diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h index 99a19e92..8c8fc04c 100644 --- a/inc/winfsp/winfsp.h +++ b/inc/winfsp/winfsp.h @@ -81,7 +81,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE NTSTATUS (*Rename)(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, PVOID FileNode, - PWSTR ExistingFileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists); + PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists); } FSP_FILE_SYSTEM_INTERFACE; typedef struct _FSP_FILE_SYSTEM { diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index 78d4acf9..f98a7b3b 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -795,7 +795,10 @@ static NTSTATUS FspFsvolSetRenameInformation( FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ? TargetFileObject->FsContext : 0; FSP_FSCTL_TRANSACT_REQ *Request; + UNICODE_STRING Remain, Suffix; UNICODE_STRING NewFileName; + PUINT8 NewFileNameBuffer; + BOOLEAN AppendBackslash; ASSERT(FileNode == FileDesc->FileNode); @@ -818,49 +821,41 @@ static NTSTATUS FspFsvolSetRenameInformation( FspFsvolDeviceFileRenameAcquireExclusive(FsvolDeviceObject); FspFileNodeAcquireExclusive(FileNode, Full); - if (L'\\' == Info->FileName[0]) - { - Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, - Info->FileNameLength + sizeof(WCHAR), - FspFsvolSetInformationRequestFini, &Request); - if (!NT_SUCCESS(Result)) - goto unlock_exit; - - Request->Req.SetInformation.Info.Rename.NewFileName.Size = - (UINT16)(Info->FileNameLength + sizeof(WCHAR)); - - RtlCopyMemory(Request->Buffer + Request->FileName.Size, - Info->FileName, Info->FileNameLength); - } + if (0 != TargetFileNode) + Remain = TargetFileNode->FileName; else - { - UNICODE_STRING Remain, Suffix; - FspUnicodePathSuffix(&FileNode->FileName, &Remain, &Suffix); - Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, - Remain.Length + sizeof(WCHAR) + Info->FileNameLength + sizeof(WCHAR), - FspFsvolSetInformationRequestFini, &Request); - if (!NT_SUCCESS(Result)) - goto unlock_exit; + Suffix.Length = Suffix.MaximumLength = (USHORT)Info->FileNameLength; + Suffix.Buffer = Info->FileName; + if (L'\\' == Suffix.Buffer[0]) + FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix); - Request->Req.SetInformation.Info.Rename.NewFileName.Size = - (UINT16)(Remain.Length + sizeof(WCHAR) + Info->FileNameLength + sizeof(WCHAR)); + AppendBackslash = sizeof(WCHAR) < Remain.Length; + NewFileName.Length = NewFileName.MaximumLength = + Remain.Length + AppendBackslash * sizeof(WCHAR) + Suffix.Length; - RtlCopyMemory(Request->Buffer + Request->FileName.Size, - Remain.Buffer, Remain.Length); - *(PWSTR)(Request->Buffer + Request->FileName.Size + Remain.Length) = L'\\'; - RtlCopyMemory(Request->Buffer + Request->FileName.Size + Remain.Length + sizeof(WCHAR), - Info->FileName, Info->FileNameLength); - } + Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, + NewFileName.Length + sizeof(WCHAR), + FspFsvolSetInformationRequestFini, &Request); + if (!NT_SUCCESS(Result)) + goto unlock_exit; - *(PWSTR)(Request->Buffer + Request->Req.SetInformation.Info.Rename.NewFileName.Size) = L'\0'; + NewFileNameBuffer = Request->Buffer + Request->FileName.Size; + NewFileName.Buffer = (PVOID)NewFileNameBuffer; + + RtlCopyMemory(NewFileNameBuffer, Remain.Buffer, Remain.Length); + *(PWSTR)(NewFileNameBuffer + Remain.Length) = L'\\'; + RtlCopyMemory(NewFileNameBuffer + Remain.Length + AppendBackslash * sizeof(WCHAR), + Suffix.Buffer, Suffix.Length); + *(PWSTR)(NewFileNameBuffer + NewFileName.Length) = L'\0'; Request->Kind = FspFsctlTransactSetInformationKind; Request->Req.SetInformation.UserContext = FileNode->UserContext; Request->Req.SetInformation.UserContext2 = FileDesc->UserContext2; Request->Req.SetInformation.FileInformationClass = FileRenameInformation; Request->Req.SetInformation.Info.Rename.NewFileName.Offset = Request->FileName.Size; + Request->Req.SetInformation.Info.Rename.NewFileName.Size = NewFileName.Length + sizeof(WCHAR); Request->Req.SetInformation.Info.Rename.ReplaceIfExists = ReplaceIfExists; FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request); @@ -879,10 +874,6 @@ static NTSTATUS FspFsvolSetRenameInformation( * that has open handles (except in the batch-oplock case described earlier). */ - NewFileName.Length = NewFileName.MaximumLength = - Request->Req.SetInformation.Info.Rename.NewFileName.Size - sizeof(WCHAR); - NewFileName.Buffer = (PVOID)(Request->Buffer + Request->FileName.Size); - Result = STATUS_SUCCESS; FspFsvolDeviceLockContextTable(FsvolDeviceObject); if (FileNode->IsDirectory) diff --git a/src/sys/util.c b/src/sys/util.c index ae84c722..ee95dede 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -95,6 +95,8 @@ VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE Remain->Length = Remain->MaximumLength = (USHORT)((PUINT8)RemainEnd - (PUINT8)PathBgn); Remain->Buffer = PathBgn; + if (0 == Remain->Length && PathBgn < PathEnd && L'\\' == *PathBgn) + Remain->Length = Remain->MaximumLength = sizeof(WCHAR); Suffix->Length = Suffix->MaximumLength = (USHORT)((PUINT8)PathEnd - (PUINT8)SuffixBgn); Suffix->Buffer = SuffixBgn; } diff --git a/tst/winfsp-tests/memfs.cpp b/tst/winfsp-tests/memfs.cpp index 2d70b9fc..c317b5d9 100644 --- a/tst/winfsp-tests/memfs.cpp +++ b/tst/winfsp-tests/memfs.cpp @@ -502,10 +502,45 @@ NTSTATUS CanDelete(FSP_FILE_SYSTEM *FileSystem, NTSTATUS Rename(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, - PVOID FileNode, - PWSTR ExistingFileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists) + PVOID FileNode0, + PWSTR FileName, PWSTR NewFileName, BOOLEAN ReplaceIfExists) { - return STATUS_INVALID_DEVICE_REQUEST; + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; + MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0; + MEMFS_FILE_NODE *NewFileNode; + BOOLEAN Inserted; + NTSTATUS Result; + + assert(0 == FileName || 0 == wcscmp(FileNode->FileName, FileName)); + + if (MAX_PATH <= wcslen(NewFileName)) + return STATUS_OBJECT_NAME_INVALID; + + NewFileNode = MemfsFileNodeMapGet(Memfs->FileNodeMap, NewFileName); + if (0 != NewFileNode) + { + if (NewFileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return STATUS_ACCESS_DENIED; + + if (ReplaceIfExists) + return STATUS_OBJECT_NAME_COLLISION; + + NewFileNode->RefCount++; + MemfsFileNodeMapRemove(Memfs->FileNodeMap, NewFileNode); + if (0 == --NewFileNode->RefCount) + MemfsFileNodeDelete(NewFileNode); + } + + MemfsFileNodeMapRemove(Memfs->FileNodeMap, FileNode); + wcscpy_s(FileNode->FileName, sizeof FileNode->FileName / sizeof(WCHAR), NewFileName); + Result = MemfsFileNodeMapInsert(Memfs->FileNodeMap, FileNode, &Inserted); + if (!NT_SUCCESS(Result)) + { + FspDebugLog(__FUNCTION__ ": cannot insert into FileNodeMap; aborting\n"); + abort(); + } + + return STATUS_SUCCESS; } static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =