diff --git a/src/sys/file.c b/src/sys/file.c index 0e0955c3..4e7ed407 100755 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -1230,6 +1230,7 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; BOOLEAN Deleted, Inserted, AcquireForeign; + FSP_FILE_NODE *InsertedFileNode; USHORT FileNameLength; PWSTR ExternalFileName; @@ -1274,9 +1275,33 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) if (0 != ExternalFileName) FspFree(ExternalFileName); - FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode, + InsertedFileNode = FspFsvolDeviceInsertContextByName( + FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode, &DescendantFileNode->ContextByNameElementStorage, &Inserted); - ASSERT(Inserted); + if (!Inserted) + { + /* + * Handle files that have been Cleanup'ed but not Close'd. + * For example, this can happen when the user has mapped and closed a file + * or immediately after breaking a Batch oplock. + */ + + ASSERT(FspFileNodeIsValid(InsertedFileNode)); + ASSERT(DescendantFileNode != InsertedFileNode); + ASSERT(0 == InsertedFileNode->HandleCount); + ASSERT(0 != InsertedFileNode->OpenCount); + + InsertedFileNode->OpenCount = 0; + FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &InsertedFileNode->FileName, &Deleted); + ASSERT(Deleted); + + FspFileNodeDereference(InsertedFileNode); + + FspFsvolDeviceInsertContextByName( + FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode, + &DescendantFileNode->ContextByNameElementStorage, &Inserted); + ASSERT(Inserted); + } if (AcquireForeign) FspFileNodeReleaseForeign(DescendantFileNode); diff --git a/tst/winfsp-tests/hooks.c b/tst/winfsp-tests/hooks.c index 743aec54..fc999e25 100644 --- a/tst/winfsp-tests/hooks.c +++ b/tst/winfsp-tests/hooks.c @@ -300,6 +300,9 @@ BOOL WINAPI HookMoveFileExW( PrepareFileName(lpExistingFileName, OldFileNameBuf); PrepareFileName(lpNewFileName, NewFileNameBuf); + MaybeRequestOplock(lpExistingFileName); + MaybeRequestOplock(lpNewFileName); + MaybeAdjustTraversePrivilege(FALSE); Success = MoveFileExW(OldFileNameBuf, NewFileNameBuf, dwFlags); MaybeAdjustTraversePrivilege(TRUE);