mirror of
https://github.com/reactos/reactos.git
synced 2025-06-29 02:09:43 +00:00
2056 lines
40 KiB
C
2056 lines
40 KiB
C
![]() |
/*
|
|||
|
* FFS File System Driver for Windows
|
|||
|
*
|
|||
|
* create.c
|
|||
|
*
|
|||
|
* 2004.5.6 ~
|
|||
|
*
|
|||
|
* Lee Jae-Hong, http://www.pyrasis.com
|
|||
|
*
|
|||
|
* See License.txt
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
#include "ntifs.h"
|
|||
|
#include "ffsdrv.h"
|
|||
|
|
|||
|
/* Globals */
|
|||
|
|
|||
|
extern PFFS_GLOBAL FFSGlobal;
|
|||
|
|
|||
|
/* Definitions */
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, FFSv1LookupFileName)
|
|||
|
#pragma alloc_text(PAGE, FFSv2LookupFileName)
|
|||
|
#pragma alloc_text(PAGE, FFSSearchFcbList)
|
|||
|
#pragma alloc_text(PAGE, FFSv1ScanDir)
|
|||
|
#pragma alloc_text(PAGE, FFSv2ScanDir)
|
|||
|
#pragma alloc_text(PAGE, FFSCreateFile)
|
|||
|
#pragma alloc_text(PAGE, FFSCreateVolume)
|
|||
|
#pragma alloc_text(PAGE, FFSCreate)
|
|||
|
#pragma alloc_text(PAGE, FFSCreateInode)
|
|||
|
#pragma alloc_text(PAGE, FFSSupersedeOrOverWriteFile)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FFSv1LookupFileName(
|
|||
|
IN PFFS_VCB Vcb,
|
|||
|
IN PUNICODE_STRING FullFileName,
|
|||
|
IN PFFS_MCB ParentMcb,
|
|||
|
OUT PFFS_MCB* FFSMcb,
|
|||
|
IN OUT PFFSv1_INODE dinode1)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING FileName;
|
|||
|
PFFS_MCB Mcb = 0;
|
|||
|
|
|||
|
FFS_DIR_ENTRY ffs_dir;
|
|||
|
int i = 0;
|
|||
|
BOOLEAN bRun = TRUE;
|
|||
|
BOOLEAN bParent = FALSE;
|
|||
|
FFSv1_INODE in;
|
|||
|
ULONG off = 0;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
|
|||
|
*FFSMcb = NULL;
|
|||
|
|
|||
|
if (ParentMcb)
|
|||
|
{
|
|||
|
bParent = TRUE;
|
|||
|
}
|
|||
|
else if (FullFileName->Buffer[0] == L'\\')
|
|||
|
{
|
|||
|
ParentMcb = Vcb->McbTree;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(&ffs_dir, sizeof(FFS_DIR_ENTRY));
|
|||
|
|
|||
|
if (FullFileName->Length == 0)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (FullFileName->Length == 2 && FullFileName->Buffer[0] == L'\\')
|
|||
|
{
|
|||
|
if (!FFSv1LoadInode(Vcb, ParentMcb->Inode, dinode1))
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
*FFSMcb = Vcb->McbTree;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
while (bRun && i < FullFileName->Length / 2)
|
|||
|
{
|
|||
|
int Length;
|
|||
|
ULONG FileAttr = FILE_ATTRIBUTE_NORMAL;
|
|||
|
|
|||
|
if (bParent)
|
|||
|
{
|
|||
|
bParent = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
while(i < FullFileName->Length / 2 && FullFileName->Buffer[i] == L'\\') i++;
|
|||
|
}
|
|||
|
|
|||
|
Length = i;
|
|||
|
|
|||
|
while(i < FullFileName->Length / 2 && (FullFileName->Buffer[i] != L'\\')) i++;
|
|||
|
|
|||
|
if (i - Length > 0)
|
|||
|
{
|
|||
|
FileName = *FullFileName;
|
|||
|
FileName.Buffer += Length;
|
|||
|
FileName.Length = (USHORT)((i - Length) * 2);
|
|||
|
|
|||
|
Mcb = FFSSearchMcb(Vcb, ParentMcb, &FileName);
|
|||
|
|
|||
|
if (Mcb)
|
|||
|
{
|
|||
|
ParentMcb = Mcb;
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
if (!IsFlagOn(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
|
|||
|
{
|
|||
|
if (i < FullFileName->Length / 2)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!FFSv1LoadInode(Vcb, ParentMcb->Inode, &in))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ((in.di_mode & IFMT) != IFDIR)
|
|||
|
{
|
|||
|
if (i < FullFileName->Length / 2)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Status = FFSv1ScanDir(
|
|||
|
Vcb,
|
|||
|
ParentMcb,
|
|||
|
&FileName,
|
|||
|
&off,
|
|||
|
&in,
|
|||
|
&ffs_dir);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
bRun = FALSE;
|
|||
|
/*
|
|||
|
if (i >= FullFileName->Length/2)
|
|||
|
{
|
|||
|
*FFSMcb = ParentMcb;
|
|||
|
}
|
|||
|
*/
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if 0
|
|||
|
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat,
|
|||
|
FFS_FEATURE_INCOMPAT_FILETYPE))
|
|||
|
{
|
|||
|
if (ffs_dir.d_type == FFS_FT_DIR)
|
|||
|
SetFlag(FileAttr, FILE_ATTRIBUTE_DIRECTORY);
|
|||
|
}
|
|||
|
else
|
|||
|
#endif
|
|||
|
{
|
|||
|
if (!FFSv1LoadInode(Vcb, ffs_dir.d_ino, &in))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ((in.di_mode & IFMT) == IFDIR)
|
|||
|
{
|
|||
|
SetFlag(FileAttr, FILE_ATTRIBUTE_DIRECTORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SetFlag(ParentMcb->Flags, MCB_IN_USE);
|
|||
|
Mcb = FFSAllocateMcb(Vcb, &FileName, FileAttr);
|
|||
|
ClearFlag(ParentMcb->Flags, MCB_IN_USE);
|
|||
|
|
|||
|
if (!Mcb)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Mcb->Inode = ffs_dir.d_ino;
|
|||
|
Mcb->DeOffset = off;
|
|||
|
FFSAddMcbNode(Vcb, ParentMcb, Mcb);
|
|||
|
ParentMcb = Mcb;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
*FFSMcb = Mcb;
|
|||
|
if (dinode1)
|
|||
|
{
|
|||
|
if (!FFSv1LoadInode(Vcb, Mcb->Inode, dinode1))
|
|||
|
{
|
|||
|
FFSPrint((DBG_ERROR, "FFSv1LookupFileName: error loading Inode %xh\n",
|
|||
|
Mcb->Inode));
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FFSv2LookupFileName(
|
|||
|
IN PFFS_VCB Vcb,
|
|||
|
IN PUNICODE_STRING FullFileName,
|
|||
|
IN PFFS_MCB ParentMcb,
|
|||
|
OUT PFFS_MCB* FFSMcb,
|
|||
|
IN OUT PFFSv2_INODE dinode2)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING FileName;
|
|||
|
PFFS_MCB Mcb = 0;
|
|||
|
|
|||
|
FFS_DIR_ENTRY ffs_dir;
|
|||
|
int i = 0;
|
|||
|
BOOLEAN bRun = TRUE;
|
|||
|
BOOLEAN bParent = FALSE;
|
|||
|
FFSv2_INODE in;
|
|||
|
ULONG off = 0;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
|
|||
|
*FFSMcb = NULL;
|
|||
|
|
|||
|
if (ParentMcb)
|
|||
|
{
|
|||
|
bParent = TRUE;
|
|||
|
}
|
|||
|
else if (FullFileName->Buffer[0] == L'\\')
|
|||
|
{
|
|||
|
ParentMcb = Vcb->McbTree;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(&ffs_dir, sizeof(FFS_DIR_ENTRY));
|
|||
|
|
|||
|
if (FullFileName->Length == 0)
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
if (FullFileName->Length == 2 && FullFileName->Buffer[0] == L'\\')
|
|||
|
{
|
|||
|
if (!FFSv2LoadInode(Vcb, ParentMcb->Inode, dinode2))
|
|||
|
{
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
*FFSMcb = Vcb->McbTree;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
while (bRun && i < FullFileName->Length / 2)
|
|||
|
{
|
|||
|
int Length;
|
|||
|
ULONG FileAttr = FILE_ATTRIBUTE_NORMAL;
|
|||
|
|
|||
|
if (bParent)
|
|||
|
{
|
|||
|
bParent = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
while(i < FullFileName->Length / 2 && FullFileName->Buffer[i] == L'\\') i++;
|
|||
|
}
|
|||
|
|
|||
|
Length = i;
|
|||
|
|
|||
|
while(i < FullFileName->Length / 2 && (FullFileName->Buffer[i] != L'\\')) i++;
|
|||
|
|
|||
|
if (i - Length > 0)
|
|||
|
{
|
|||
|
FileName = *FullFileName;
|
|||
|
FileName.Buffer += Length;
|
|||
|
FileName.Length = (USHORT)((i - Length) * 2);
|
|||
|
|
|||
|
Mcb = FFSSearchMcb(Vcb, ParentMcb, &FileName);
|
|||
|
|
|||
|
if (Mcb)
|
|||
|
{
|
|||
|
ParentMcb = Mcb;
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
if (!IsFlagOn(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
|
|||
|
{
|
|||
|
if (i < FullFileName->Length / 2)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!FFSv2LoadInode(Vcb, ParentMcb->Inode, &in))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ((in.di_mode & IFMT) != IFDIR)
|
|||
|
{
|
|||
|
if (i < FullFileName->Length / 2)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Status = FFSv2ScanDir(
|
|||
|
Vcb,
|
|||
|
ParentMcb,
|
|||
|
&FileName,
|
|||
|
&off,
|
|||
|
&in,
|
|||
|
&ffs_dir);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
bRun = FALSE;
|
|||
|
/*
|
|||
|
if (i >= FullFileName->Length/2)
|
|||
|
{
|
|||
|
*FFSMcb = ParentMcb;
|
|||
|
}
|
|||
|
*/
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
#if 0
|
|||
|
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat,
|
|||
|
FFS_FEATURE_INCOMPAT_FILETYPE))
|
|||
|
{
|
|||
|
if (ffs_dir.d_type == FFS_FT_DIR)
|
|||
|
SetFlag(FileAttr, FILE_ATTRIBUTE_DIRECTORY);
|
|||
|
}
|
|||
|
else
|
|||
|
#endif
|
|||
|
{
|
|||
|
if (!FFSv2LoadInode(Vcb, ffs_dir.d_ino, &in))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if ((in.di_mode & IFMT) == IFDIR)
|
|||
|
{
|
|||
|
SetFlag(FileAttr, FILE_ATTRIBUTE_DIRECTORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SetFlag(ParentMcb->Flags, MCB_IN_USE);
|
|||
|
Mcb = FFSAllocateMcb(Vcb, &FileName, FileAttr);
|
|||
|
ClearFlag(ParentMcb->Flags, MCB_IN_USE);
|
|||
|
|
|||
|
if (!Mcb)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Mcb->Inode = ffs_dir.d_ino;
|
|||
|
Mcb->DeOffset = off;
|
|||
|
FFSAddMcbNode(Vcb, ParentMcb, Mcb);
|
|||
|
ParentMcb = Mcb;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
*FFSMcb = Mcb;
|
|||
|
if (dinode2)
|
|||
|
{
|
|||
|
if (!FFSv2LoadInode(Vcb, Mcb->Inode, dinode2))
|
|||
|
{
|
|||
|
FFSPrint((DBG_ERROR, "FFSv2LookupFileName: error loading Inode %xh\n",
|
|||
|
Mcb->Inode));
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FFSv1ScanDir(
|
|||
|
IN PFFS_VCB Vcb,
|
|||
|
IN PFFS_MCB ParentMcb,
|
|||
|
IN PUNICODE_STRING FileName,
|
|||
|
IN OUT PULONG Index,
|
|||
|
IN PFFSv1_INODE dinode1,
|
|||
|
IN OUT PFFS_DIR_ENTRY ffs_dir)
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
USHORT InodeFileNameLength;
|
|||
|
UNICODE_STRING InodeFileName;
|
|||
|
|
|||
|
PFFS_DIR_ENTRY pDir = NULL;
|
|||
|
ULONG dwBytes = 0;
|
|||
|
BOOLEAN bFound = FALSE;
|
|||
|
LONGLONG Offset = 0;
|
|||
|
#ifndef __REACTOS__
|
|||
|
ULONG inode = ParentMcb->Inode;
|
|||
|
#endif
|
|||
|
ULONG dwRet;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY
|
|||
|
{
|
|||
|
|
|||
|
pDir = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
|||
|
sizeof(FFS_DIR_ENTRY), FFS_POOL_TAG);
|
|||
|
if (!pDir)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
InodeFileName.Buffer = ExAllocatePoolWithTag(
|
|||
|
PagedPool,
|
|||
|
(FFS_NAME_LEN + 1) * 2, FFS_POOL_TAG);
|
|||
|
|
|||
|
if (!InodeFileName.Buffer)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
dwBytes = 0;
|
|||
|
|
|||
|
while (!bFound && dwBytes < dinode1->di_size)
|
|||
|
{
|
|||
|
RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));
|
|||
|
|
|||
|
// Reading the DCB contents
|
|||
|
Status = FFSv1ReadInode(
|
|||
|
NULL,
|
|||
|
Vcb,
|
|||
|
dinode1,
|
|||
|
dwBytes,
|
|||
|
(PVOID)pDir,
|
|||
|
sizeof(FFS_DIR_ENTRY),
|
|||
|
&dwRet);
|
|||
|
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
FFSPrint((DBG_ERROR, "FFSv1ScanDir: Reading Directory Content error.\n"));
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (pDir->d_ino /*&& (pDir->d_ino < INODES_COUNT)*/)
|
|||
|
{
|
|||
|
OEM_STRING OemName;
|
|||
|
OemName.Buffer = pDir->d_name;
|
|||
|
OemName.Length = (pDir->d_namlen & 0xff);
|
|||
|
OemName.MaximumLength = OemName.Length;
|
|||
|
|
|||
|
InodeFileNameLength = (USHORT)
|
|||
|
RtlOemStringToCountedUnicodeSize(&OemName);
|
|||
|
|
|||
|
InodeFileName.Length = 0;
|
|||
|
InodeFileName.MaximumLength = (FFS_NAME_LEN + 1) * 2;
|
|||
|
|
|||
|
RtlZeroMemory(InodeFileName.Buffer,
|
|||
|
InodeFileNameLength + 2);
|
|||
|
|
|||
|
Status = FFSOEMToUnicode(
|
|||
|
&InodeFileName,
|
|||
|
&OemName);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (!RtlCompareUnicodeString(
|
|||
|
FileName,
|
|||
|
&InodeFileName,
|
|||
|
TRUE))
|
|||
|
{
|
|||
|
bFound = TRUE;
|
|||
|
*Index = dwBytes;
|
|||
|
RtlCopyMemory(ffs_dir, pDir, pDir->d_reclen > sizeof(FFS_DIR_ENTRY)
|
|||
|
? sizeof(FFS_DIR_ENTRY) : pDir->d_reclen);
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
FFSPrint((DBG_INFO, "FFSv1ScanDir: Found: Name=%S Inode=%xh\n", InodeFileName.Buffer, pDir->d_ino));
|
|||
|
}
|
|||
|
|
|||
|
dwBytes +=pDir->d_reclen;
|
|||
|
Offset = (LONGLONG)dwBytes;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (pDir->d_ino == 0)
|
|||
|
{
|
|||
|
if (pDir->d_reclen == 0)
|
|||
|
{
|
|||
|
FFSBreakPoint();
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dwBytes +=pDir->d_reclen;
|
|||
|
Offset = (LONGLONG)dwBytes;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!bFound)
|
|||
|
{
|
|||
|
Status = STATUS_NO_SUCH_FILE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_FINALLY
|
|||
|
{
|
|||
|
if (InodeFileName.Buffer != NULL)
|
|||
|
{
|
|||
|
ExFreePool(InodeFileName.Buffer);
|
|||
|
}
|
|||
|
|
|||
|
if (pDir)
|
|||
|
ExFreePool(pDir);
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FFSv2ScanDir(
|
|||
|
IN PFFS_VCB Vcb,
|
|||
|
IN PFFS_MCB ParentMcb,
|
|||
|
IN PUNICODE_STRING FileName,
|
|||
|
IN OUT PULONG Index,
|
|||
|
IN PFFSv2_INODE dinode2,
|
|||
|
IN OUT PFFS_DIR_ENTRY ffs_dir)
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
USHORT InodeFileNameLength;
|
|||
|
UNICODE_STRING InodeFileName;
|
|||
|
|
|||
|
PFFS_DIR_ENTRY pDir = NULL;
|
|||
|
ULONG dwBytes = 0;
|
|||
|
BOOLEAN bFound = FALSE;
|
|||
|
LONGLONG Offset = 0;
|
|||
|
#ifndef __REACTOS__
|
|||
|
ULONG inode = ParentMcb->Inode;
|
|||
|
#endif
|
|||
|
ULONG dwRet;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
_SEH2_TRY
|
|||
|
{
|
|||
|
|
|||
|
pDir = (PFFS_DIR_ENTRY)ExAllocatePoolWithTag(PagedPool,
|
|||
|
sizeof(FFS_DIR_ENTRY), FFS_POOL_TAG);
|
|||
|
if (!pDir)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
InodeFileName.Buffer = ExAllocatePoolWithTag(
|
|||
|
PagedPool,
|
|||
|
(FFS_NAME_LEN + 1) * 2, FFS_POOL_TAG);
|
|||
|
|
|||
|
if (!InodeFileName.Buffer)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
dwBytes = 0;
|
|||
|
|
|||
|
while (!bFound && dwBytes < dinode2->di_size)
|
|||
|
{
|
|||
|
RtlZeroMemory(pDir, sizeof(FFS_DIR_ENTRY));
|
|||
|
|
|||
|
// Reading the DCB contents
|
|||
|
Status = FFSv2ReadInode(
|
|||
|
NULL,
|
|||
|
Vcb,
|
|||
|
dinode2,
|
|||
|
dwBytes,
|
|||
|
(PVOID)pDir,
|
|||
|
sizeof(FFS_DIR_ENTRY),
|
|||
|
&dwRet);
|
|||
|
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
FFSPrint((DBG_ERROR, "FFSv2ScanDir: Reading Directory Content error.\n"));
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (pDir->d_ino /*&& (pDir->d_ino < INODES_COUNT)*/)
|
|||
|
{
|
|||
|
OEM_STRING OemName;
|
|||
|
OemName.Buffer = pDir->d_name;
|
|||
|
OemName.Length = (pDir->d_namlen & 0xff);
|
|||
|
OemName.MaximumLength = OemName.Length;
|
|||
|
|
|||
|
InodeFileNameLength = (USHORT)
|
|||
|
RtlOemStringToCountedUnicodeSize(&OemName);
|
|||
|
|
|||
|
InodeFileName.Length = 0;
|
|||
|
InodeFileName.MaximumLength = (FFS_NAME_LEN + 1) * 2;
|
|||
|
|
|||
|
RtlZeroMemory(InodeFileName.Buffer,
|
|||
|
InodeFileNameLength + 2);
|
|||
|
|
|||
|
Status = FFSOEMToUnicode(
|
|||
|
&InodeFileName,
|
|||
|
&OemName);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (!RtlCompareUnicodeString(
|
|||
|
FileName,
|
|||
|
&InodeFileName,
|
|||
|
TRUE))
|
|||
|
{
|
|||
|
bFound = TRUE;
|
|||
|
*Index = dwBytes;
|
|||
|
RtlCopyMemory(ffs_dir, pDir, pDir->d_reclen > sizeof(FFS_DIR_ENTRY)
|
|||
|
? sizeof(FFS_DIR_ENTRY) : pDir->d_reclen);
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
FFSPrint((DBG_VITAL, "FFSv2ScanDir: Found: Name=%S Inode=%xh\n", InodeFileName.Buffer, pDir->d_ino));
|
|||
|
}
|
|||
|
|
|||
|
dwBytes +=pDir->d_reclen;
|
|||
|
Offset = (LONGLONG)dwBytes;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (pDir->d_ino == 0)
|
|||
|
{
|
|||
|
if (pDir->d_reclen == 0)
|
|||
|
{
|
|||
|
FFSBreakPoint();
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dwBytes +=pDir->d_reclen;
|
|||
|
Offset = (LONGLONG)dwBytes;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!bFound)
|
|||
|
{
|
|||
|
Status = STATUS_NO_SUCH_FILE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_FINALLY
|
|||
|
{
|
|||
|
if (InodeFileName.Buffer != NULL)
|
|||
|
{
|
|||
|
ExFreePool(InodeFileName.Buffer);
|
|||
|
}
|
|||
|
|
|||
|
if (pDir)
|
|||
|
ExFreePool(pDir);
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
PFFS_FCB
|
|||
|
FFSSearchFcbList(
|
|||
|
IN PFFS_VCB Vcb,
|
|||
|
IN ULONG inode)
|
|||
|
{
|
|||
|
BOOLEAN bFound = FALSE;
|
|||
|
PLIST_ENTRY Link;
|
|||
|
PFFS_FCB TmpFcb;
|
|||
|
|
|||
|
Link = Vcb->FcbList.Flink;
|
|||
|
|
|||
|
while (!bFound && Link != &Vcb->FcbList)
|
|||
|
{
|
|||
|
TmpFcb = CONTAINING_RECORD(Link, FFS_FCB, Next);
|
|||
|
|
|||
|
if (TmpFcb && TmpFcb->Identifier.Type == FCB)
|
|||
|
{
|
|||
|
#if DBG
|
|||
|
FFSPrint((DBG_INFO, "FFSSearchFcbList: [%s,%xh]\n",
|
|||
|
TmpFcb->AnsiFileName.Buffer, TmpFcb->Inode));
|
|||
|
#endif
|
|||
|
if (TmpFcb->Inode == inode)
|
|||
|
{
|
|||
|
FFSPrint((DBG_INFO, "FFSSearchMcb: Found FCB for %xh.\n", inode));
|
|||
|
bFound = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
Link = Link->Flink;
|
|||
|
}
|
|||
|
|
|||
|
if (bFound)
|
|||
|
return TmpFcb;
|
|||
|
else
|
|||
|
return NULL;
|
|||
|
|
|||
|
}
|
|||
|
*/
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
FFSCreateFile(
|
|||
|
PFFS_IRP_CONTEXT IrpContext,
|
|||
|
PFFS_VCB Vcb)
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PFFS_FCB Fcb = NULL;
|
|||
|
PFFS_MCB FFSMcb = NULL;
|
|||
|
|
|||
|
PFFS_FCB ParentFcb = NULL;
|
|||
|
PFFS_MCB ParentMcb = NULL;
|
|||
|
|
|||
|
BOOLEAN bParentFcbCreated = FALSE;
|
|||
|
|
|||
|
PFFS_CCB Ccb = NULL;
|
|||
|
PFFSv1_INODE dinode1 = 0;
|
|||
|
PFFSv2_INODE dinode2 = 0;
|
|||
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|||
|
#ifndef __REACTOS__
|
|||
|
BOOLEAN bDir = FALSE;
|
|||
|
#endif
|
|||
|
BOOLEAN bFcbAllocated = FALSE;
|
|||
|
BOOLEAN bCreated = FALSE;
|
|||
|
UNICODE_STRING FileName;
|
|||
|
PIRP Irp;
|
|||
|
|
|||
|
ULONG Options;
|
|||
|
ULONG CreateDisposition;
|
|||
|
|
|||
|
BOOLEAN OpenDirectory;
|
|||
|
BOOLEAN OpenTargetDirectory;
|
|||
|
BOOLEAN CreateDirectory;
|
|||
|
BOOLEAN SequentialOnly;
|
|||
|
BOOLEAN NoIntermediateBuffering;
|
|||
|
BOOLEAN IsPagingFile;
|
|||
|
BOOLEAN DirectoryFile;
|
|||
|
BOOLEAN NonDirectoryFile;
|
|||
|
BOOLEAN NoEaKnowledge;
|
|||
|
BOOLEAN DeleteOnClose;
|
|||
|
BOOLEAN TemporaryFile;
|
|||
|
BOOLEAN CaseSensitive;
|
|||
|
|
|||
|
ACCESS_MASK DesiredAccess;
|
|||
|
ULONG ShareAccess;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
Irp = IrpContext->Irp;
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
Options = IrpSp->Parameters.Create.Options;
|
|||
|
|
|||
|
DirectoryFile = IsFlagOn(Options, FILE_DIRECTORY_FILE);
|
|||
|
OpenTargetDirectory = IsFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY);
|
|||
|
|
|||
|
NonDirectoryFile = IsFlagOn(Options, FILE_NON_DIRECTORY_FILE);
|
|||
|
SequentialOnly = IsFlagOn(Options, FILE_SEQUENTIAL_ONLY);
|
|||
|
NoIntermediateBuffering = IsFlagOn(Options, FILE_NO_INTERMEDIATE_BUFFERING);
|
|||
|
NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
|
|||
|
DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
|
|||
|
|
|||
|
CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
|
|||
|
|
|||
|
TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
|
|||
|
FILE_ATTRIBUTE_TEMPORARY);
|
|||
|
|
|||
|
CreateDisposition = (Options >> 24) & 0x000000ff;
|
|||
|
|
|||
|
IsPagingFile = IsFlagOn(IrpSp->Flags, SL_OPEN_PAGING_FILE);
|
|||
|
|
|||
|
CreateDirectory = (BOOLEAN)(DirectoryFile &&
|
|||
|
((CreateDisposition == FILE_CREATE) ||
|
|||
|
(CreateDisposition == FILE_OPEN_IF)));
|
|||
|
|
|||
|
OpenDirectory = (BOOLEAN)(DirectoryFile &&
|
|||
|
((CreateDisposition == FILE_OPEN) ||
|
|||
|
(CreateDisposition == FILE_OPEN_IF)));
|
|||
|
|
|||
|
DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
|
|||
|
ShareAccess = IrpSp->Parameters.Create.ShareAccess;
|
|||
|
|
|||
|
FileName.Buffer = NULL;
|
|||
|
|
|||
|
_SEH2_TRY
|
|||
|
{
|
|||
|
ExAcquireResourceExclusiveLite(
|
|||
|
&Vcb->MainResource, TRUE);
|
|||
|
|
|||
|
VcbResourceAcquired = TRUE;
|
|||
|
|
|||
|
if (Irp->Overlay.AllocationSize.HighPart)
|
|||
|
{
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
if (!(dinode1 = ExAllocatePoolWithTag(
|
|||
|
PagedPool, DINODE1_SIZE, 'EInd')))
|
|||
|
{
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(dinode1, sizeof(DINODE1_SIZE));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!(dinode2 = ExAllocatePoolWithTag(
|
|||
|
PagedPool, DINODE2_SIZE, 'EInd')))
|
|||
|
{
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(dinode2, sizeof(DINODE2_SIZE));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
FileName.MaximumLength = IrpSp->FileObject->FileName.MaximumLength;
|
|||
|
FileName.Length = IrpSp->FileObject->FileName.Length;
|
|||
|
|
|||
|
FileName.Buffer = ExAllocatePoolWithTag(PagedPool, FileName.MaximumLength, FFS_POOL_TAG);
|
|||
|
if (!FileName.Buffer)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(FileName.Buffer, FileName.MaximumLength);
|
|||
|
RtlCopyMemory(FileName.Buffer, IrpSp->FileObject->FileName.Buffer, FileName.Length);
|
|||
|
|
|||
|
if (IrpSp->FileObject->RelatedFileObject)
|
|||
|
{
|
|||
|
ParentFcb = (PFFS_FCB)(IrpSp->FileObject->RelatedFileObject->FsContext);
|
|||
|
}
|
|||
|
|
|||
|
if ((FileName.Length > sizeof(WCHAR)) &&
|
|||
|
(FileName.Buffer[1] == L'\\') &&
|
|||
|
(FileName.Buffer[0] == L'\\')) {
|
|||
|
|
|||
|
FileName.Length -= sizeof(WCHAR);
|
|||
|
|
|||
|
RtlMoveMemory(&FileName.Buffer[0],
|
|||
|
&FileName.Buffer[1],
|
|||
|
FileName.Length);
|
|||
|
|
|||
|
//
|
|||
|
// Bad Name if there are still beginning backslashes.
|
|||
|
//
|
|||
|
|
|||
|
if ((FileName.Length > sizeof(WCHAR)) &&
|
|||
|
(FileName.Buffer[1] == L'\\') &&
|
|||
|
(FileName.Buffer[0] == L'\\'))
|
|||
|
{
|
|||
|
|
|||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|||
|
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (IsFlagOn(Options, FILE_OPEN_BY_FILE_ID))
|
|||
|
{
|
|||
|
Status = STATUS_NOT_IMPLEMENTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
FFSPrint((DBG_INFO, "FFSCreateFile: %S (NameLen=%xh) Paging=%xh Option: %xh.\n",
|
|||
|
FileName.Buffer, FileName.Length, IsPagingFile, IrpSp->Parameters.Create.Options));
|
|||
|
|
|||
|
if (ParentFcb)
|
|||
|
{
|
|||
|
ParentMcb = ParentFcb->FFSMcb;
|
|||
|
}
|
|||
|
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
Status = FFSv1LookupFileName(
|
|||
|
Vcb,
|
|||
|
&FileName,
|
|||
|
ParentMcb,
|
|||
|
&FFSMcb,
|
|||
|
dinode1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = FFSv2LookupFileName(
|
|||
|
Vcb,
|
|||
|
&FileName,
|
|||
|
ParentMcb,
|
|||
|
&FFSMcb,
|
|||
|
dinode2);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
UNICODE_STRING PathName;
|
|||
|
UNICODE_STRING RealName;
|
|||
|
UNICODE_STRING RemainName;
|
|||
|
#ifndef __REACTOS__
|
|||
|
LONG i = 0;
|
|||
|
#endif
|
|||
|
|
|||
|
PathName = FileName;
|
|||
|
|
|||
|
FFSPrint((DBG_INFO, "FFSCreateFile: File %S will be created.\n", PathName.Buffer));
|
|||
|
|
|||
|
FFSMcb = NULL;
|
|||
|
|
|||
|
if (PathName.Buffer[PathName.Length / 2 - 1] == L'\\')
|
|||
|
{
|
|||
|
if (DirectoryFile)
|
|||
|
{
|
|||
|
PathName.Length -= 2;
|
|||
|
PathName.Buffer[PathName.Length / 2] = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = STATUS_NOT_A_DIRECTORY;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!ParentMcb)
|
|||
|
{
|
|||
|
if (PathName.Buffer[0] != L'\\')
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ParentMcb = Vcb->McbTree;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Dissecting:
|
|||
|
|
|||
|
FsRtlDissectName(PathName, &RealName, &RemainName);
|
|||
|
|
|||
|
if (((RemainName.Length != 0) && (RemainName.Buffer[0] == L'\\')) ||
|
|||
|
(RealName.Length >= 256 * sizeof(WCHAR)))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (RemainName.Length != 0)
|
|||
|
{
|
|||
|
PFFS_MCB RetMcb;
|
|||
|
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
Status = FFSv1LookupFileName(
|
|||
|
Vcb,
|
|||
|
&RealName,
|
|||
|
ParentMcb,
|
|||
|
&RetMcb,
|
|||
|
dinode1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = FFSv2LookupFileName(
|
|||
|
Vcb,
|
|||
|
&RealName,
|
|||
|
ParentMcb,
|
|||
|
&RetMcb,
|
|||
|
dinode2);
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
ParentMcb = RetMcb;
|
|||
|
PathName = RemainName;
|
|||
|
|
|||
|
goto Dissecting;
|
|||
|
}
|
|||
|
|
|||
|
if (FsRtlDoesNameContainWildCards(&RealName))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
ParentFcb = ParentMcb->FFSFcb;
|
|||
|
|
|||
|
if (!ParentFcb)
|
|||
|
{
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
PFFSv1_INODE pTmpInode = ExAllocatePoolWithTag(PagedPool,
|
|||
|
DINODE1_SIZE, FFS_POOL_TAG);
|
|||
|
if (!pTmpInode)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if(!FFSv1LoadInode(Vcb, ParentMcb->Inode, pTmpInode))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
ParentFcb = FFSv1AllocateFcb(Vcb, ParentMcb, pTmpInode);
|
|||
|
|
|||
|
if (!ParentFcb)
|
|||
|
{
|
|||
|
ExFreePool(pTmpInode);
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PFFSv2_INODE pTmpInode = ExAllocatePoolWithTag(PagedPool,
|
|||
|
DINODE2_SIZE, FFS_POOL_TAG);
|
|||
|
if (!pTmpInode)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if(!FFSv2LoadInode(Vcb, ParentMcb->Inode, pTmpInode))
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
ParentFcb = FFSv2AllocateFcb(Vcb, ParentMcb, pTmpInode);
|
|||
|
|
|||
|
if (!ParentFcb)
|
|||
|
{
|
|||
|
ExFreePool(pTmpInode);
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bParentFcbCreated = TRUE;
|
|||
|
ParentFcb->ReferenceCount++;
|
|||
|
}
|
|||
|
|
|||
|
// We need to create a new one ?
|
|||
|
if ((CreateDisposition == FILE_CREATE) ||
|
|||
|
(CreateDisposition == FILE_OPEN_IF) ||
|
|||
|
(CreateDisposition == FILE_OVERWRITE_IF))
|
|||
|
{
|
|||
|
#if FFS_READ_ONLY
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
#else // !FFS_READ_ONLY
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
|
|||
|
{
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED))
|
|||
|
{
|
|||
|
IoSetHardErrorOrVerifyDevice(IrpContext->Irp,
|
|||
|
Vcb->Vpb->RealDevice);
|
|||
|
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
|
|||
|
|
|||
|
FFSRaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
|
|||
|
}
|
|||
|
|
|||
|
if (DirectoryFile)
|
|||
|
{
|
|||
|
if (TemporaryFile)
|
|||
|
{
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!ParentFcb)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (DirectoryFile)
|
|||
|
{
|
|||
|
if (ParentFcb->FFSMcb->Inode == FFS_ROOT_INO)
|
|||
|
{
|
|||
|
if ((RealName.Length == 0x10) &&
|
|||
|
memcmp(RealName.Buffer, L"Recycled\0", 0x10) == 0)
|
|||
|
{
|
|||
|
SetFlag(IrpSp->Parameters.Create.FileAttributes,
|
|||
|
FILE_ATTRIBUTE_READONLY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Status = FFSCreateInode(
|
|||
|
IrpContext,
|
|||
|
Vcb,
|
|||
|
ParentFcb,
|
|||
|
DT_DIR,
|
|||
|
IrpSp->Parameters.Create.FileAttributes,
|
|||
|
&RealName);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = FFSCreateInode(
|
|||
|
IrpContext,
|
|||
|
Vcb,
|
|||
|
ParentFcb,
|
|||
|
DT_REG,
|
|||
|
IrpSp->Parameters.Create.FileAttributes,
|
|||
|
&RealName);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
bCreated = TRUE;
|
|||
|
|
|||
|
Irp->IoStatus.Information = FILE_CREATED;
|
|||
|
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
Status = FFSv1LookupFileName(
|
|||
|
Vcb,
|
|||
|
&RealName,
|
|||
|
ParentMcb,
|
|||
|
&FFSMcb,
|
|||
|
dinode1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = FFSv2LookupFileName(
|
|||
|
Vcb,
|
|||
|
&RealName,
|
|||
|
ParentMcb,
|
|||
|
&FFSMcb,
|
|||
|
dinode2);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
if (DirectoryFile)
|
|||
|
{
|
|||
|
FFSNotifyReportChange(
|
|||
|
IrpContext,
|
|||
|
Vcb,
|
|||
|
ParentFcb,
|
|||
|
FILE_NOTIFY_CHANGE_DIR_NAME,
|
|||
|
FILE_ACTION_ADDED);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FFSNotifyReportChange(
|
|||
|
IrpContext,
|
|||
|
Vcb,
|
|||
|
ParentFcb,
|
|||
|
FILE_NOTIFY_CHANGE_FILE_NAME,
|
|||
|
FILE_ACTION_ADDED);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FFSBreakPoint();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FFSBreakPoint();
|
|||
|
}
|
|||
|
#endif // !FFS_READ_ONLY
|
|||
|
}
|
|||
|
else if (OpenTargetDirectory)
|
|||
|
{
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
|
|||
|
{
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (!ParentFcb)
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory(IrpSp->FileObject->FileName.Buffer,
|
|||
|
IrpSp->FileObject->FileName.MaximumLength);
|
|||
|
IrpSp->FileObject->FileName.Length = RealName.Length;
|
|||
|
|
|||
|
RtlCopyMemory(IrpSp->FileObject->FileName.Buffer,
|
|||
|
RealName.Buffer,
|
|||
|
RealName.Length);
|
|||
|
|
|||
|
Fcb = ParentFcb;
|
|||
|
|
|||
|
Irp->IoStatus.Information = FILE_DOES_NOT_EXIST;
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
else // File / Dir already exists.
|
|||
|
{
|
|||
|
if (OpenTargetDirectory)
|
|||
|
{
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
|
|||
|
{
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Information = FILE_EXISTS;
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
RtlZeroMemory(IrpSp->FileObject->FileName.Buffer,
|
|||
|
IrpSp->FileObject->FileName.MaximumLength);
|
|||
|
IrpSp->FileObject->FileName.Length = FFSMcb->ShortName.Length;
|
|||
|
|
|||
|
RtlCopyMemory(IrpSp->FileObject->FileName.Buffer,
|
|||
|
FFSMcb->ShortName.Buffer,
|
|||
|
FFSMcb->ShortName.Length);
|
|||
|
|
|||
|
//Let Mcb pointer to it's parent
|
|||
|
FFSMcb = FFSMcb->Parent;
|
|||
|
|
|||
|
goto Openit;
|
|||
|
}
|
|||
|
|
|||
|
// We can not create if one exists
|
|||
|
if (CreateDisposition == FILE_CREATE)
|
|||
|
{
|
|||
|
Irp->IoStatus.Information = FILE_EXISTS;
|
|||
|
Status = STATUS_OBJECT_NAME_COLLISION;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if(IsFlagOn(FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
|
|||
|
{
|
|||
|
if ((CreateDisposition != FILE_OPEN) &&
|
|||
|
(CreateDisposition != FILE_OPEN_IF))
|
|||
|
{
|
|||
|
|
|||
|
Status = STATUS_OBJECT_NAME_COLLISION;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (NonDirectoryFile)
|
|||
|
{
|
|||
|
Status = STATUS_FILE_IS_A_DIRECTORY;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (FFSMcb->Inode == FFS_ROOT_INO)
|
|||
|
{
|
|||
|
if (DeleteOnClose)
|
|||
|
{
|
|||
|
Status = STATUS_CANNOT_DELETE;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (OpenTargetDirectory)
|
|||
|
{
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Information = FILE_OPENED;
|
|||
|
}
|
|||
|
|
|||
|
Openit:
|
|||
|
|
|||
|
if (FFSMcb)
|
|||
|
{
|
|||
|
Fcb = FFSMcb->FFSFcb;
|
|||
|
|
|||
|
if (!Fcb)
|
|||
|
{
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
Fcb = FFSv1AllocateFcb(Vcb, FFSMcb, dinode1);
|
|||
|
bFcbAllocated = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Fcb = FFSv2AllocateFcb(Vcb, FFSMcb, dinode2);
|
|||
|
bFcbAllocated = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Fcb)
|
|||
|
{
|
|||
|
if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED))
|
|||
|
{
|
|||
|
Status = STATUS_FILE_DELETED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING))
|
|||
|
{
|
|||
|
Status = STATUS_DELETE_PENDING;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (bCreated)
|
|||
|
{
|
|||
|
#if !FFS_READ_ONLY
|
|||
|
//
|
|||
|
// This file is just created.
|
|||
|
//
|
|||
|
|
|||
|
if (DirectoryFile)
|
|||
|
{
|
|||
|
UNICODE_STRING EntryName;
|
|||
|
USHORT NameBuf[6];
|
|||
|
|
|||
|
RtlZeroMemory(&NameBuf, 6 * sizeof(USHORT));
|
|||
|
|
|||
|
EntryName.Length = EntryName.MaximumLength = 2;
|
|||
|
EntryName.Buffer = &NameBuf[0];
|
|||
|
NameBuf[0] = (USHORT)'.';
|
|||
|
|
|||
|
FFSAddEntry(IrpContext, Vcb, Fcb,
|
|||
|
DT_DIR,
|
|||
|
Fcb->FFSMcb->Inode,
|
|||
|
&EntryName);
|
|||
|
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
FFSv1SaveInode(IrpContext, Vcb,
|
|||
|
Fcb->FFSMcb->Inode,
|
|||
|
Fcb->dinode1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FFSv2SaveInode(IrpContext, Vcb,
|
|||
|
Fcb->FFSMcb->Inode,
|
|||
|
Fcb->dinode2);
|
|||
|
}
|
|||
|
|
|||
|
EntryName.Length = EntryName.MaximumLength = 4;
|
|||
|
EntryName.Buffer = &NameBuf[0];
|
|||
|
NameBuf[0] = NameBuf[1] = (USHORT)'.';
|
|||
|
|
|||
|
FFSAddEntry(IrpContext, Vcb, Fcb,
|
|||
|
DT_DIR,
|
|||
|
Fcb->FFSMcb->Parent->Inode,
|
|||
|
&EntryName);
|
|||
|
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
FFSv1SaveInode(IrpContext, Vcb,
|
|||
|
Fcb->FFSMcb->Inode,
|
|||
|
Fcb->dinode1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FFSv2SaveInode(IrpContext, Vcb,
|
|||
|
Fcb->FFSMcb->Inode,
|
|||
|
Fcb->dinode2);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!FFSExpandFile(
|
|||
|
IrpContext, Vcb, Fcb,
|
|||
|
&(Irp->Overlay.AllocationSize)))
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // !FFS_READ_ONLY
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// This file alreayd exists.
|
|||
|
//
|
|||
|
|
|||
|
if (DeleteOnClose)
|
|||
|
{
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
|
|||
|
{
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED))
|
|||
|
{
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
|
|||
|
IoSetHardErrorOrVerifyDevice(IrpContext->Irp,
|
|||
|
Vcb->Vpb->RealDevice);
|
|||
|
|
|||
|
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
|
|||
|
|
|||
|
FFSRaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
|
|||
|
}
|
|||
|
|
|||
|
SetFlag(Fcb->Flags, FCB_DELETE_ON_CLOSE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// Just to Open file (Open/OverWrite ...)
|
|||
|
//
|
|||
|
|
|||
|
if ((!IsDirectory(Fcb)) && (IsFlagOn(IrpSp->FileObject->Flags,
|
|||
|
FO_NO_INTERMEDIATE_BUFFERING)))
|
|||
|
{
|
|||
|
Fcb->Header.IsFastIoPossible = FastIoIsPossible;
|
|||
|
|
|||
|
if (IsFlagOn(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED) &&
|
|||
|
(Fcb->SectionObject.DataSectionObject != NULL))
|
|||
|
{
|
|||
|
if (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount)
|
|||
|
{
|
|||
|
/* IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) */
|
|||
|
|
|||
|
if(!IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
|
|||
|
{
|
|||
|
CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
|
|||
|
ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
|||
|
}
|
|||
|
|
|||
|
CcPurgeCacheSection(&Fcb->SectionObject,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!IsDirectory(Fcb))
|
|||
|
{
|
|||
|
if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
|
|||
|
{
|
|||
|
if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile)
|
|||
|
{
|
|||
|
DesiredAccess |= DELETE;
|
|||
|
}
|
|||
|
else if (((CreateDisposition == FILE_OVERWRITE) ||
|
|||
|
(CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile)
|
|||
|
{
|
|||
|
DesiredAccess |= (FILE_WRITE_DATA | FILE_WRITE_EA |
|
|||
|
FILE_WRITE_ATTRIBUTES);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Fcb->OpenHandleCount > 0)
|
|||
|
{
|
|||
|
Status = IoCheckShareAccess(DesiredAccess,
|
|||
|
ShareAccess,
|
|||
|
IrpSp->FileObject,
|
|||
|
&(Fcb->ShareAccess),
|
|||
|
TRUE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IoSetShareAccess(DesiredAccess,
|
|||
|
ShareAccess,
|
|||
|
IrpSp->FileObject,
|
|||
|
&(Fcb->ShareAccess));
|
|||
|
}
|
|||
|
|
|||
|
Ccb = FFSAllocateCcb();
|
|||
|
|
|||
|
Fcb->OpenHandleCount++;
|
|||
|
Fcb->ReferenceCount++;
|
|||
|
|
|||
|
if (IsFlagOn(IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
|
|||
|
{
|
|||
|
Fcb->NonCachedOpenCount++;
|
|||
|
}
|
|||
|
|
|||
|
Vcb->OpenFileHandleCount++;
|
|||
|
Vcb->ReferenceCount++;
|
|||
|
|
|||
|
IrpSp->FileObject->FsContext = (void*)Fcb;
|
|||
|
IrpSp->FileObject->FsContext2 = (void*) Ccb;
|
|||
|
IrpSp->FileObject->PrivateCacheMap = NULL;
|
|||
|
IrpSp->FileObject->SectionObjectPointer = &(Fcb->SectionObject);
|
|||
|
IrpSp->FileObject->Vpb = Vcb->Vpb;
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
FFSPrint((DBG_INFO, "FFSCreateFile: %s OpenCount: %u ReferCount: %u\n",
|
|||
|
Fcb->AnsiFileName.Buffer, Fcb->OpenHandleCount, Fcb->ReferenceCount));
|
|||
|
|
|||
|
if (!IsDirectory(Fcb) && !NoIntermediateBuffering)
|
|||
|
{
|
|||
|
IrpSp->FileObject->Flags |= FO_CACHE_SUPPORTED;
|
|||
|
}
|
|||
|
|
|||
|
if (!bCreated && !IsDirectory(Fcb))
|
|||
|
{
|
|||
|
if (DeleteOnClose ||
|
|||
|
IsFlagOn(DesiredAccess, FILE_WRITE_DATA) ||
|
|||
|
(CreateDisposition == FILE_OVERWRITE) ||
|
|||
|
(CreateDisposition == FILE_OVERWRITE_IF))
|
|||
|
{
|
|||
|
if (!MmFlushImageSection(&Fcb->SectionObject,
|
|||
|
MmFlushForWrite))
|
|||
|
{
|
|||
|
|
|||
|
Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
|
|||
|
STATUS_SHARING_VIOLATION;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((CreateDisposition == FILE_SUPERSEDE) ||
|
|||
|
(CreateDisposition == FILE_OVERWRITE) ||
|
|||
|
(CreateDisposition == FILE_OVERWRITE_IF))
|
|||
|
{
|
|||
|
#if FFS_READ_ONLY
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
#else // !FFS_READ_ONLY
|
|||
|
BOOLEAN bRet;
|
|||
|
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY))
|
|||
|
{
|
|||
|
Status = STATUS_MEDIA_WRITE_PROTECTED;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED))
|
|||
|
{
|
|||
|
IoSetHardErrorOrVerifyDevice(IrpContext->Irp,
|
|||
|
Vcb->Vpb->RealDevice);
|
|||
|
SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
|
|||
|
|
|||
|
FFSRaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
|
|||
|
}
|
|||
|
|
|||
|
Status = FFSSupersedeOrOverWriteFile(IrpContext,
|
|||
|
Vcb,
|
|||
|
Fcb,
|
|||
|
CreateDisposition);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
bRet = FFSExpandFile(IrpContext,
|
|||
|
Vcb,
|
|||
|
Fcb,
|
|||
|
&(Irp->Overlay.AllocationSize));
|
|||
|
|
|||
|
if (!bRet)
|
|||
|
{
|
|||
|
Status = STATUS_DISK_FULL;
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
FFSNotifyReportChange(
|
|||
|
IrpContext,
|
|||
|
Vcb,
|
|||
|
Fcb,
|
|||
|
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
|||
|
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
|||
|
FILE_NOTIFY_CHANGE_SIZE,
|
|||
|
FILE_ACTION_MODIFIED);
|
|||
|
|
|||
|
|
|||
|
if (CreateDisposition == FILE_SUPERSEDE)
|
|||
|
{
|
|||
|
Irp->IoStatus.Information = FILE_SUPERSEDED;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Irp->IoStatus.Information = FILE_OVERWRITTEN;
|
|||
|
}
|
|||
|
#endif // !FFS_READ_ONLY
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_FINALLY
|
|||
|
{
|
|||
|
if (FileName.Buffer)
|
|||
|
ExFreePool(FileName.Buffer);
|
|||
|
|
|||
|
if (bParentFcbCreated)
|
|||
|
{
|
|||
|
ParentFcb->ReferenceCount--;
|
|||
|
}
|
|||
|
|
|||
|
if (VcbResourceAcquired)
|
|||
|
{
|
|||
|
ExReleaseResourceForThreadLite(
|
|||
|
&Vcb->MainResource,
|
|||
|
ExGetCurrentResourceThread());
|
|||
|
}
|
|||
|
|
|||
|
if (!bFcbAllocated)
|
|||
|
{
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
if (dinode1)
|
|||
|
ExFreePool(dinode1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (dinode2)
|
|||
|
ExFreePool(dinode2);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (FS_VERSION == 1)
|
|||
|
{
|
|||
|
if (!Fcb && dinode1)
|
|||
|
ExFreePool(dinode1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!Fcb && dinode2)
|
|||
|
ExFreePool(dinode2);
|
|||
|
}
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
FFSCreateVolume(
|
|||
|
PFFS_IRP_CONTEXT IrpContext,
|
|||
|
PFFS_VCB Vcb)
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PIRP Irp;
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
ACCESS_MASK DesiredAccess;
|
|||
|
ULONG ShareAccess;
|
|||
|
|
|||
|
ULONG Options;
|
|||
|
BOOLEAN DirectoryFile;
|
|||
|
BOOLEAN OpenTargetDirectory;
|
|||
|
|
|||
|
ULONG CreateDisposition;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
Irp = IrpContext->Irp;
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
Options = IrpSp->Parameters.Create.Options;
|
|||
|
|
|||
|
DirectoryFile = IsFlagOn(Options, FILE_DIRECTORY_FILE);
|
|||
|
OpenTargetDirectory = IsFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY);
|
|||
|
|
|||
|
CreateDisposition = (Options >> 24) & 0x000000ff;
|
|||
|
|
|||
|
DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
|
|||
|
ShareAccess = IrpSp->Parameters.Create.ShareAccess;
|
|||
|
|
|||
|
if (DirectoryFile)
|
|||
|
{
|
|||
|
return STATUS_NOT_A_DIRECTORY;
|
|||
|
}
|
|||
|
|
|||
|
if (OpenTargetDirectory)
|
|||
|
{
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
if ((CreateDisposition != FILE_OPEN) &&
|
|||
|
(CreateDisposition != FILE_OPEN_IF))
|
|||
|
{
|
|||
|
return STATUS_ACCESS_DENIED;
|
|||
|
}
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
if (Vcb->OpenHandleCount > 0)
|
|||
|
{
|
|||
|
Status = IoCheckShareAccess(DesiredAccess, ShareAccess,
|
|||
|
IrpSp->FileObject,
|
|||
|
&(Vcb->ShareAccess), TRUE);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
goto errorout;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IoSetShareAccess(DesiredAccess, ShareAccess,
|
|||
|
IrpSp->FileObject,
|
|||
|
&(Vcb->ShareAccess));
|
|||
|
}
|
|||
|
|
|||
|
if (FlagOn(DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA))
|
|||
|
{
|
|||
|
ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
|
|||
|
FFSFlushFiles(Vcb, FALSE);
|
|||
|
FFSFlushVolume(Vcb, FALSE);
|
|||
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|||
|
}
|
|||
|
|
|||
|
{
|
|||
|
PFFS_CCB Ccb = FFSAllocateCcb();
|
|||
|
|
|||
|
if (Ccb == NULL)
|
|||
|
{
|
|||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto errorout;
|
|||
|
}
|
|||
|
|
|||
|
IrpSp->FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
|
|||
|
IrpSp->FileObject->FsContext = Vcb;
|
|||
|
IrpSp->FileObject->FsContext2 = Ccb;
|
|||
|
|
|||
|
Vcb->ReferenceCount++;
|
|||
|
Vcb->OpenHandleCount++;
|
|||
|
|
|||
|
Irp->IoStatus.Information = FILE_OPENED;
|
|||
|
}
|
|||
|
|
|||
|
errorout:
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
FFSCreate(
|
|||
|
IN PFFS_IRP_CONTEXT IrpContext)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PIRP Irp;
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PFFS_VCB Vcb = 0;
|
|||
|
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
|||
|
PFFS_FCBVCB Xcb = NULL;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DeviceObject = IrpContext->DeviceObject;
|
|||
|
|
|||
|
Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
#if 0
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD>̹<EFBFBD><CCB9><EFBFBD> <20>ε<EFBFBD> <20>Ǿ<EFBFBD><C7BE><EFBFBD><EFBFBD><EFBFBD> <20>˻<EFBFBD><CBBB><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20>Ǿ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|||
|
<EFBFBD><EFBFBD><EFBFBD>쵵 <EFBFBD>ֱ<EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD>߸<EFBFBD> <EFBFBD>ȵ<EFBFBD>. */
|
|||
|
ASSERT(IsMounted(Vcb));
|
|||
|
#endif
|
|||
|
|
|||
|
Irp = IrpContext->Irp;
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
Xcb = (PFFS_FCBVCB)(IrpSp->FileObject->FsContext);
|
|||
|
|
|||
|
if (DeviceObject == FFSGlobal->DeviceObject)
|
|||
|
{
|
|||
|
FFSPrint((DBG_INFO, "FFSCreate: Create on main device object.\n"));
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
Irp->IoStatus.Information = FILE_OPENED;
|
|||
|
|
|||
|
FFSUnpinRepinnedBcbs(IrpContext);
|
|||
|
|
|||
|
FFSCompleteIrpContext(IrpContext, Status);
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_TRY
|
|||
|
{
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED))
|
|||
|
{
|
|||
|
Status = STATUS_ACCESS_DENIED;
|
|||
|
|
|||
|
if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING))
|
|||
|
{
|
|||
|
Status = STATUS_VOLUME_DISMOUNTED;
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_LEAVE;
|
|||
|
}
|
|||
|
|
|||
|
if (((IrpSp->FileObject->FileName.Length == 0) &&
|
|||
|
(IrpSp->FileObject->RelatedFileObject == NULL)) ||
|
|||
|
(Xcb && Xcb->Identifier.Type == FFSVCB))
|
|||
|
{
|
|||
|
Status = FFSCreateVolume(IrpContext, Vcb);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Status = FFSCreateFile(IrpContext, Vcb);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_FINALLY
|
|||
|
{
|
|||
|
|
|||
|
if (!IrpContext->ExceptionInProgress)
|
|||
|
{
|
|||
|
FFSUnpinRepinnedBcbs(IrpContext);
|
|||
|
|
|||
|
FFSCompleteIrpContext(IrpContext, Status);
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
#if !FFS_READ_ONLY
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
FFSCreateInode(
|
|||
|
PFFS_IRP_CONTEXT IrpContext,
|
|||
|
PFFS_VCB Vcb,
|
|||
|
PFFS_FCB ParentFcb,
|
|||
|
ULONG Type,
|
|||
|
ULONG FileAttr,
|
|||
|
PUNICODE_STRING FileName)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG Inode;
|
|||
|
ULONG Group;
|
|||
|
|
|||
|
FFSv1_INODE dinode1;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
RtlZeroMemory(&dinode1, DINODE1_SIZE);
|
|||
|
|
|||
|
Group = (ParentFcb->FFSMcb->Inode - 1) / BLOCKS_PER_GROUP;
|
|||
|
|
|||
|
FFSPrint((DBG_INFO,
|
|||
|
"FFSCreateInode: %S in %S(Inode=%xh)\n",
|
|||
|
FileName->Buffer,
|
|||
|
ParentFcb->FFSMcb->ShortName.Buffer,
|
|||
|
ParentFcb->FFSMcb->Inode));
|
|||
|
|
|||
|
Status = FFSNewInode(IrpContext, Vcb, Group,Type, &Inode);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
goto errorout;
|
|||
|
}
|
|||
|
|
|||
|
Status = FFSAddEntry(IrpContext, Vcb, ParentFcb, Type, Inode, FileName);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status))
|
|||
|
{
|
|||
|
FFSBreakPoint();
|
|||
|
FFSFreeInode(IrpContext, Vcb, Inode, Type);
|
|||
|
|
|||
|
goto errorout;
|
|||
|
}
|
|||
|
|
|||
|
FFSv1SaveInode(IrpContext, Vcb, ParentFcb->FFSMcb->Inode, ParentFcb->dinode1);
|
|||
|
|
|||
|
dinode1.di_ctime = ParentFcb->dinode1->di_mtime;
|
|||
|
dinode1.di_mode = 0x1FF;
|
|||
|
|
|||
|
if (IsFlagOn(FileAttr, FILE_ATTRIBUTE_READONLY))
|
|||
|
{
|
|||
|
FFSSetReadOnly(dinode1.di_mode);
|
|||
|
}
|
|||
|
|
|||
|
if (Type == DT_DIR)
|
|||
|
{
|
|||
|
SetFlag(dinode1.di_mode, IFDIR);
|
|||
|
|
|||
|
dinode1.di_nlink = 2;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dinode1.di_nlink = 1;
|
|||
|
SetFlag(dinode1.di_mode, IFLNK);
|
|||
|
}
|
|||
|
|
|||
|
FFSv1SaveInode(IrpContext, Vcb, Inode, &dinode1);
|
|||
|
|
|||
|
FFSPrint((DBG_INFO, "FFSCreateInode: New Inode = %xh (Type=%xh)\n", Inode, Type));
|
|||
|
|
|||
|
errorout:
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
__drv_mustHoldCriticalRegion
|
|||
|
NTSTATUS
|
|||
|
FFSSupersedeOrOverWriteFile(
|
|||
|
IN PFFS_IRP_CONTEXT IrpContext,
|
|||
|
IN PFFS_VCB Vcb,
|
|||
|
IN PFFS_FCB Fcb,
|
|||
|
IN ULONG Disposition)
|
|||
|
{
|
|||
|
LARGE_INTEGER CurrentTime;
|
|||
|
LARGE_INTEGER AllocationSize;
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
BOOLEAN bRet = FALSE;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
KeQuerySystemTime(&CurrentTime);
|
|||
|
|
|||
|
AllocationSize.QuadPart = (LONGLONG)0;
|
|||
|
|
|||
|
if (!MmCanFileBeTruncated(&(Fcb->SectionObject), &(AllocationSize)))
|
|||
|
{
|
|||
|
Status = STATUS_USER_MAPPED_FILE;
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
bRet = FFSTruncateFile(IrpContext, Vcb, Fcb, &AllocationSize);
|
|||
|
|
|||
|
if (bRet)
|
|||
|
{
|
|||
|
Fcb->Header.AllocationSize.QuadPart =
|
|||
|
Fcb->Header.FileSize.QuadPart = (LONGLONG)0;
|
|||
|
|
|||
|
Fcb->dinode1->di_size = 0;
|
|||
|
|
|||
|
if (Disposition == FILE_SUPERSEDE)
|
|||
|
Fcb->dinode1->di_ctime = FFSInodeTime(CurrentTime);
|
|||
|
|
|||
|
Fcb->dinode1->di_atime =
|
|||
|
Fcb->dinode1->di_mtime = FFSInodeTime(CurrentTime);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (Fcb->dinode1->di_size > Fcb->Header.AllocationSize.LowPart)
|
|||
|
Fcb->dinode1->di_size = Fcb->Header.AllocationSize.LowPart;
|
|||
|
|
|||
|
Fcb->Header.FileSize.QuadPart = (LONGLONG)Fcb->dinode1->di_size;
|
|||
|
|
|||
|
Status = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1);
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
#endif // !FFS_READ_ONLY
|