reactos/drivers/filesystems/ffs/src/create.c

2056 lines
40 KiB
C
Raw Normal View History

/*
* 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