From 56a5ebef8187e7d266a4a4eef70a2be0f08814ef Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Mon, 28 Apr 2014 19:40:26 +0000 Subject: [PATCH] [FASTFAT] Implement part 2/3 (first part was in ntoskrnl, remember ;-)) of renaming support in ReactOS. Here, we implement support for SL_OPEN_TARGET_DIRECTORY for IRP_MJ_CREATE in fastfat. The code is not the best ever, but we can't do miracles with fastfat. This fixes a few tests in KmTests:IoCreateFile and also shows failures I still don't get and that will require deeper attention. Last part will be to effectively bring support of FileRenameInformation in IRP_MJ_SET_INFORMATION. But this is yet another story. svn path=/trunk/; revision=63034 --- reactos/drivers/filesystems/fastfat/create.c | 104 ++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/reactos/drivers/filesystems/fastfat/create.c b/reactos/drivers/filesystems/fastfat/create.c index 76967dd6d73..8ce7ca0399f 100644 --- a/reactos/drivers/filesystems/fastfat/create.c +++ b/reactos/drivers/filesystems/fastfat/create.c @@ -352,6 +352,7 @@ VfatOpenFile( PUNICODE_STRING PathNameU, PFILE_OBJECT FileObject, ULONG RequestedDisposition, + BOOLEAN OpenTargetDir, PVFATFCB *ParentFcb) { PVFATFCB Fcb; @@ -402,6 +403,14 @@ VfatOpenFile( DPRINT ("Could not make a new FCB, status: %x\n", Status); return Status; } + + /* In case we're to open target, just check whether file exist, but don't open it */ + if (OpenTargetDir) + { + vfatReleaseFCB(DeviceExt, Fcb); + return STATUS_OBJECT_NAME_COLLISION; + } + if (Fcb->Flags & FCB_DELETE_PENDING) { vfatReleaseFCB(DeviceExt, Fcb); @@ -443,6 +452,7 @@ VfatCreateFile( PWCHAR c, last; BOOLEAN PagingFileCreate = FALSE; BOOLEAN Dots; + BOOLEAN OpenTargetDir = FALSE; UNICODE_STRING FileNameU; UNICODE_STRING PathNameU; ULONG Attributes; @@ -452,6 +462,7 @@ VfatCreateFile( RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff); RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE; + OpenTargetDir = (Stack->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE; FileObject = Stack->FileObject; DeviceExt = DeviceObject->DeviceExtension; @@ -485,6 +496,11 @@ VfatCreateFile( } #endif + if (OpenTargetDir) + { + return STATUS_INVALID_PARAMETER; + } + pFcb = DeviceExt->VolumeFcb; vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject); pFcb->RefCount++; @@ -520,6 +536,13 @@ VfatCreateFile( } } + /* Check if we try to open target directory of root dir */ + if (OpenTargetDir && FileObject->RelatedFileObject == NULL && PathNameU.Length == sizeof(WCHAR) && + PathNameU.Buffer[0] == L'\\') + { + return STATUS_INVALID_PARAMETER; + } + if (FileObject->RelatedFileObject && PathNameU.Length >= sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\') { return STATUS_OBJECT_NAME_INVALID; @@ -531,7 +554,86 @@ VfatCreateFile( } /* Try opening the file. */ - Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, &ParentFcb); + Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, OpenTargetDir, &ParentFcb); + + if (OpenTargetDir) + { + LONG idx, FileNameLen; + + if (Status == STATUS_OBJECT_NAME_COLLISION) + { + Irp->IoStatus.Information = FILE_EXISTS; + } + else + { + Irp->IoStatus.Information = FILE_DOES_NOT_EXIST; + } + + idx = FileObject->FileName.Length / sizeof(WCHAR) - 1; + + /* Skip tailing \ - if any */ + if (PathNameU.Buffer[idx] == L'\\') + { + --idx; + PathNameU.Length -= sizeof(WCHAR); + } + + /* Get file name */ + while (idx >= 0 && PathNameU.Buffer[idx] != L'\\') + { + --idx; + } + + if (idx > 0) + { + /* We don't want to include / in the name */ + FileNameLen = PathNameU.Length - ((idx + 1) * sizeof(WCHAR)); + + /* Try to open parent */ + PathNameU.Length -= (PathNameU.Length - idx * sizeof(WCHAR)); + Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, FALSE, &ParentFcb); + + /* Update FO just to keep file name */ + /* Skip first slash */ + ++idx; + PathNameU.Length = FileNameLen; + RtlMoveMemory(&PathNameU.Buffer[0], &PathNameU.Buffer[idx], PathNameU.Length); + } + else + { + /* This is a relative open and we have only the filename, so open the parent directory + * It is in RelatedFileObject + */ + BOOLEAN Chomp = FALSE; + PFILE_OBJECT RelatedFileObject = FileObject->RelatedFileObject; + + DPRINT("%wZ\n", &PathNameU); + + ASSERT(RelatedFileObject != NULL); + + DPRINT("Relative opening\n"); + DPRINT("FileObject->RelatedFileObject->FileName: %wZ\n", &RelatedFileObject->FileName); + + /* VfatOpenFile() doesn't like our name ends with \, so chomp it if there's one */ + if (RelatedFileObject->FileName.Buffer[RelatedFileObject->FileName.Length / sizeof(WCHAR) - 1] == L'\\') + { + Chomp = FALSE; + RelatedFileObject->FileName.Length -= sizeof(WCHAR); + } + + /* Tricky part - fake our FO. It's NOT relative, we want to open the complete file path */ + FileObject->RelatedFileObject = NULL; + Status = VfatOpenFile(DeviceExt, &RelatedFileObject->FileName, FileObject, RequestedDisposition, FALSE, &ParentFcb); + + /* We're done opening, restore what we broke */ + FileObject->RelatedFileObject = RelatedFileObject; + if (Chomp) RelatedFileObject->FileName.Length += sizeof(WCHAR); + + /* No need to modify the FO, it already has the name */ + } + + return Status; + } /* * If the directory containing the file to open doesn't exist then