sys: rename: oplock refactoring

This commit is contained in:
Bill Zissimopoulos 2016-11-22 14:18:10 -08:00
parent 8f10ba4fc9
commit ba78fbb956
3 changed files with 214 additions and 138 deletions

View File

@ -1123,8 +1123,9 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
FSP_FILE_NODE *FileNode, FSP_FILE_NODE *FileNode,
ULONG AcquireFlags, ULONG AcquireFlags,
PUNICODE_STRING StreamFileName); PUNICODE_STRING StreamFileName);
BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName); FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);

161
src/sys/file.c Normal file → Executable file
View File

@ -48,8 +48,9 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
FSP_FILE_NODE *FileNode, FSP_FILE_NODE *FileNode,
ULONG AcquireFlags, ULONG AcquireFlags,
PUNICODE_STRING StreamFileName); PUNICODE_STRING StreamFileName);
BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName); FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
PUNICODE_STRING FileName, BOOLEAN CheckingOldName);
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName);
VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo);
@ -851,7 +852,7 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
return IoStatus.Status; return IoStatus.Status;
} }
#define GATHER_DESCENDANTS(FILENAME, SUBPATHONLY, REFERENCE, ...)\ #define GATHER_DESCENDANTS(FILENAME, REFERENCE, ...)\
FSP_FILE_NODE *DescendantFileNode;\ FSP_FILE_NODE *DescendantFileNode;\
FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\ FSP_FILE_NODE *DescendantFileNodeArray[16], **DescendantFileNodes;\
ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\ ULONG DescendantFileNodeCount, DescendantFileNodeIndex;\
@ -862,7 +863,7 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
for (;;) \ for (;;) \
{ \ { \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\ DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, SUBPATHONLY, &RestartKey);\ FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode) \ if (0 == DescendantFileNode) \
break; \ break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\ ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
@ -882,7 +883,7 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode,
for (;;) \ for (;;) \
{ \ { \
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\ DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,\
FILENAME, SUBPATHONLY, &RestartKey);\ FILENAME, FALSE, &RestartKey);\
if (0 == DescendantFileNode)\ if (0 == DescendantFileNode)\
break; \ break; \
ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\ ASSERT(0 == ((UINT_PTR)DescendantFileNode & 7));\
@ -934,7 +935,7 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
GATHER_DESCENDANTS(&FileNode->FileName, FALSE, TRUE, GATHER_DESCENDANTS(&FileNode->FileName, TRUE,
if (DescendantFileNode->FileName.Length > FileNameLength && if (DescendantFileNode->FileName.Length > FileNameLength &&
L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)]) L'\\' == DescendantFileNode->FileName.Buffer[FileNameLength / sizeof(WCHAR)])
break; break;
@ -1028,42 +1029,36 @@ NTSTATUS FspFileNodeCheckBatchOplocksOnAllStreams(
return Result; return Result;
} }
BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp, NTSTATUS FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
FSP_FILE_NODE *FileNode, PUNICODE_STRING FileName) FSP_FILE_NODE *FileNode, ULONG AcquireFlags,
PUNICODE_STRING FileName, BOOLEAN CheckingOldName)
{ {
PAGED_CODE(); PAGED_CODE();
BOOLEAN CheckingOldName = 0 != FileNode; NTSTATUS Result;
BOOLEAN HasOpenHandles; ULONG HasHandles, IsBatchOplock, IsHandleOplock;
BOOLEAN Success = TRUE;
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
/* if we are checking the existing file name, do a quick check here */ if (CheckingOldName && !FileNode->IsDirectory && 1 == FileNode->HandleCount)
if (CheckingOldName)
{ {
/* if file has single open handle (also means no streams open) and not a directory, exit now */ /* quick exit */
if (1 == FileNode->HandleCount && !FileNode->IsDirectory) FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
{ return STATUS_SUCCESS;
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
return TRUE;
}
/* Note: when CheckingOldName==TRUE, the old FileNode is not included in enumerations below */
} }
GATHER_DESCENDANTS(FileName, CheckingOldName, TRUE, GATHER_DESCENDANTS(FileName, TRUE,
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode | DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode |
(0 < DescendantFileNode->HandleCount))); (0 < DescendantFileNode->HandleCount)));
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
if (0 == DescendantFileNodeCount) if (0 == DescendantFileNodeCount)
{ {
ASSERT(Success); Result = STATUS_SUCCESS;
goto unlock_exit; goto exit;
} }
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
/* /*
* At this point all descendant FileNode's are enumerated and referenced. * At this point all descendant FileNode's are enumerated and referenced.
* There can be no new FileNode's because Rename has acquired the device's * There can be no new FileNode's because Rename has acquired the device's
@ -1079,29 +1074,103 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
DescendantFileNodeIndex++) DescendantFileNodeIndex++)
{ {
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1); DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
Success = MmFlushImageSection(&DescendantFileNode->NonPaged->SectionObjectPointers, if (!MmFlushImageSection(&DescendantFileNode->NonPaged->SectionObjectPointers,
MmFlushForDelete); MmFlushForDelete))
if (!Success) {
goto unlock_exit; /* release the FileNode in case of failure! */
FspFileNodeReleaseF(FileNode, AcquireFlags);
Result = STATUS_ACCESS_DENIED;
goto exit;
}
} }
} }
/* break any Batch or Handle oplocks on descendants */ /* break any Batch or Handle oplocks on descendants */
Result = STATUS_SUCCESS;
for ( for (
DescendantFileNodeIndex = 0; DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex; DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++) DescendantFileNodeIndex++)
{ {
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
HasOpenHandles = (UINT_PTR)DescendantFileNode & 1; HasHandles = (UINT_PTR)DescendantFileNode & 1;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1); DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (HasOpenHandles) if (!HasHandles)
if (FspFileNodeOplockIsBatch(DescendantFileNode) || continue;
FspFileNodeOplockIsHandle(DescendantFileNode))
FspFileNodeOplockCheck(DescendantFileNode, OplockIrp); if (FspFileNodeOplockIsBatch(DescendantFileNode))
{
NTSTATUS Result0 = FspFileNodeOplockCheckEx(DescendantFileNode, OplockIrp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_SUCCESS == Result0)
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
else
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
{
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | 2);
}
else
Result = STATUS_ACCESS_DENIED;
}
else
if (FspFileNodeOplockIsHandle(DescendantFileNode))
{
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_SUCCESS == Result0)
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
else
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result0)
{
Result = NT_SUCCESS(Result) ? STATUS_OPLOCK_BREAK_IN_PROGRESS : Result;
DescendantFileNodes[DescendantFileNodeIndex] =
(PVOID)((UINT_PTR)DescendantFileNode | 2);
}
else
Result = STATUS_ACCESS_DENIED;
}
}
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result || !NT_SUCCESS(Result))
{
/* release the FileNode so that we can safely wait without deadlocks */
FspFileNodeReleaseF(FileNode, AcquireFlags);
/* wait for oplock breaks to finish */
for (
DescendantFileNodeIndex = 0;
DescendantFileNodeCount > DescendantFileNodeIndex;
DescendantFileNodeIndex++)
{
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
IsBatchOplock = (UINT_PTR)DescendantFileNode & 2;
IsHandleOplock = (UINT_PTR)DescendantFileNode & 4;
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~7);
if (IsBatchOplock)
{
NTSTATUS Result0 = FspFileNodeOplockCheck(DescendantFileNode, OplockIrp);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
if (STATUS_SUCCESS != Result0)
Result = STATUS_ACCESS_DENIED;
}
else
if (IsHandleOplock)
{
NTSTATUS Result0 = FspFileNodeOplockBreakHandle(DescendantFileNode, OplockIrp, 0);
ASSERT(STATUS_OPLOCK_BREAK_IN_PROGRESS != Result0);
if (STATUS_SUCCESS != Result0)
Result = STATUS_ACCESS_DENIED;
}
}
goto exit;
} }
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
@ -1111,23 +1180,27 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP OplockIrp,
for (;;) for (;;)
{ {
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
FileName, CheckingOldName, &RestartKey); FileName, FALSE, &RestartKey);
if (0 == DescendantFileNode) if (0 == DescendantFileNode)
break; break;
if (0 < DescendantFileNode->HandleCount) /* if this is the FileNode being renamed then HandleCount must be 1, else 0 */
if ((DescendantFileNode == FileNode) < DescendantFileNode->HandleCount)
{ {
Success = FALSE; /* release the FileNode in case of failure! */
goto unlock_exit; FspFileNodeReleaseF(FileNode, AcquireFlags);
Result = STATUS_ACCESS_DENIED;
break;
} }
} }
unlock_exit:
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
exit:
SCATTER_DESCENDANTS(TRUE); SCATTER_DESCENDANTS(TRUE);
return Success; return Result;
} }
VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
@ -1160,7 +1233,7 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName)
FspFsvolDeviceLockContextTable(FsvolDeviceObject); FspFsvolDeviceLockContextTable(FsvolDeviceObject);
GATHER_DESCENDANTS(&FileNode->FileName, FALSE, FALSE, {}); GATHER_DESCENDANTS(&FileNode->FileName, FALSE, {});
FileNameLength = FileNode->FileName.Length; FileNameLength = FileNode->FileName.Length;
for ( for (

View File

@ -1159,7 +1159,7 @@ static NTSTATUS FspFsvolSetRenameInformation(
FSP_FILE_DESC *FileDesc = FileObject->FsContext2; FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ? FSP_FILE_NODE *TargetFileNode = 0 != TargetFileObject ?
TargetFileObject->FsContext : 0; TargetFileObject->FsContext : 0;
FSP_FSCTL_TRANSACT_REQ *Request; FSP_FSCTL_TRANSACT_REQ *Request = 0;
UNICODE_STRING Remain, Suffix; UNICODE_STRING Remain, Suffix;
UNICODE_STRING NewFileName; UNICODE_STRING NewFileName;
PUINT8 NewFileNameBuffer; PUINT8 NewFileNameBuffer;
@ -1186,91 +1186,62 @@ static NTSTATUS FspFsvolSetRenameInformation(
ASSERT(TargetFileNode->IsDirectory); ASSERT(TargetFileNode->IsDirectory);
} }
retry:
FspFsvolDeviceFileRenameAcquireExclusive(FsvolDeviceObject); FspFsvolDeviceFileRenameAcquireExclusive(FsvolDeviceObject);
retry:
FspFileNodeAcquireExclusive(FileNode, Full); FspFileNodeAcquireExclusive(FileNode, Full);
/* if (0 == Request)
* Perform oplock check.
*
* It is ok to block our thread during receipt of the SetInformation IRP.
* However we cannot acquire the FileNode exclusive and wait for oplock
* breaks to complete, because oplock break processing acquires the FileNode
* shared.
*
* Instead we initiate the oplock breaks and then check if any are in progress.
* If that is the case we release the FileNode and wait for the oplock breaks
* to complete. Once they are complete we retry the whole thing.
*/
Result = FspFileNodeOplockCheckEx(FileNode, Irp,
OPLOCK_FLAG_COMPLETE_IF_OPLOCKED);
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result ||
DEBUGTEST_EX(NT_SUCCESS(Result), 10, FALSE))
{ {
FspFileNodeRelease(FileNode, Full); if (0 != TargetFileNode)
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject); Remain = TargetFileNode->FileName;
Result = FspFileNodeOplockCheck(FileNode, Irp); else
if (!NT_SUCCESS(Result)) FspFileNameSuffix(&FileNode->FileName, &Remain, &Suffix);
return Result;
goto retry;
}
if (!NT_SUCCESS(Result))
goto unlock_exit;
if (0 != TargetFileNode) Suffix.Length = (USHORT)Info->FileNameLength;
Remain = TargetFileNode->FileName; Suffix.Buffer = Info->FileName;
else /* if there is a backslash anywhere in the NewFileName get its suffix */
FspFileNameSuffix(&FileNode->FileName, &Remain, &Suffix); for (PWSTR P = Suffix.Buffer, EndP = P + Suffix.Length / sizeof(WCHAR); EndP > P; P++)
if (L'\\' == *P)
{
Suffix.Length = (USHORT)((EndP - P - 1) * sizeof(WCHAR));
Suffix.Buffer = P + 1;
}
Suffix.MaximumLength = Suffix.Length;
Suffix.Length = (USHORT)Info->FileNameLength; if (!FspFileNameIsValid(&Remain, 0, 0) || !FspFileNameIsValid(&Suffix, 0, 0))
Suffix.Buffer = Info->FileName;
/* if there is a backslash anywhere in the NewFileName get its suffix */
for (PWSTR P = Suffix.Buffer, EndP = P + Suffix.Length / sizeof(WCHAR); EndP > P; P++)
if (L'\\' == *P)
{ {
Suffix.Length = (USHORT)((EndP - P - 1) * sizeof(WCHAR)); /* cannot rename streams (WinFsp limitation) */
Suffix.Buffer = P + 1; Result = STATUS_INVALID_PARAMETER;
goto unlock_exit;
} }
Suffix.MaximumLength = Suffix.Length;
if (!FspFileNameIsValid(&Remain, 0, 0) || !FspFileNameIsValid(&Suffix, 0, 0)) AppendBackslash = sizeof(WCHAR) < Remain.Length;
{ NewFileName.Length = NewFileName.MaximumLength =
/* cannot rename streams (WinFsp limitation) */ Remain.Length + AppendBackslash * sizeof(WCHAR) + Suffix.Length;
Result = STATUS_INVALID_PARAMETER;
goto unlock_exit; Result = FspIopCreateRequestEx(Irp, &FileNode->FileName,
NewFileName.Length + sizeof(WCHAR),
FspFsvolSetInformationRequestFini, &Request);
if (!NT_SUCCESS(Result))
goto unlock_exit;
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);
} }
AppendBackslash = sizeof(WCHAR) < Remain.Length;
NewFileName.Length = NewFileName.MaximumLength =
Remain.Length + AppendBackslash * sizeof(WCHAR) + Suffix.Length;
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName,
NewFileName.Length + sizeof(WCHAR),
FspFsvolSetInformationRequestFini, &Request);
if (!NT_SUCCESS(Result))
goto unlock_exit;
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);
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
/* /*
* Special rules for renaming open files: * Special rules for renaming open files:
* - A file cannot be renamed if it has any open handles, * - A file cannot be renamed if it has any open handles,
@ -1281,29 +1252,60 @@ retry:
* - A directory cannot be renamed if it or any of its subdirectories contains a file * - A directory cannot be renamed if it or any of its subdirectories contains a file
* that has open handles (except in the batch-oplock case described earlier). * that has open handles (except in the batch-oplock case described earlier).
*/ */
Result = STATUS_SUCCESS;
if (!FspFileNodeRenameCheck(FsvolDeviceObject, Irp, FileNode, &FileNode->FileName) ||
(0 != FspFileNameCompare(&FileNode->FileName, &NewFileName, !FileDesc->CaseSensitive, 0) &&
!FspFileNodeRenameCheck(FsvolDeviceObject, Irp, 0, &NewFileName)))
Result = STATUS_ACCESS_DENIED;
if (!NT_SUCCESS(Result))
return Result;
/* Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
* If the new file name is *exactly* the same (including case) as the old one, FileNode, FspFileNodeAcquireFull,
* there is no need to go to the user mode file system. Just return STATUS_SUCCESS. &FileNode->FileName, TRUE);
* Our RequestFini will do any cleanup necessary. /* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */
* if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
* This check needs to be done *after* the open handle test above. This is what FASTFAT goto retry;
* and NTFS do. if (!NT_SUCCESS(Result))
*/ {
if (0 == FspFileNameCompare(&FileNode->FileName, &NewFileName, FALSE, 0)) Result = STATUS_ACCESS_DENIED;
return STATUS_SUCCESS; goto rename_unlock_exit;
}
if (0 != FspFileNameCompare(&FileNode->FileName, &NewFileName, !FileDesc->CaseSensitive, 0))
{
Result = FspFileNodeRenameCheck(FsvolDeviceObject, Irp,
FileNode, FspFileNodeAcquireFull,
&NewFileName, FALSE);
/* FspFileNodeRenameCheck releases FileNode with STATUS_OPLOCK_BREAK_IN_PROGRESS or failure */
if (STATUS_OPLOCK_BREAK_IN_PROGRESS == Result)
goto retry;
if (!NT_SUCCESS(Result))
{
Result = STATUS_ACCESS_DENIED;
goto rename_unlock_exit;
}
}
else
{
/*
* If the new file name is *exactly* the same (including case) as the old one,
* there is no need to go to the user mode file system. Just return STATUS_SUCCESS.
* Our RequestFini will do any cleanup necessary.
*
* This check needs to be done *after* the open handle test above. This is what FASTFAT
* and NTFS do.
*/
if (0 == FspFileNameCompare(&FileNode->FileName, &NewFileName, FALSE, 0))
{
Result = STATUS_SUCCESS;
goto unlock_exit;
}
}
FspFsvolDeviceFileRenameSetOwner(FsvolDeviceObject, Request);
FspFileNodeSetOwner(FileNode, Full, Request);
FspIopRequestContext(Request, RequestFileNode) = FileNode;
FspIopRequestContext(Request, RequestDeviceObject) = FsvolDeviceObject;
return FSP_STATUS_IOQ_POST; return FSP_STATUS_IOQ_POST;
unlock_exit: unlock_exit:
FspFileNodeRelease(FileNode, Full); FspFileNodeRelease(FileNode, Full);
rename_unlock_exit:
FspFsvolDeviceFileRenameRelease(FsvolDeviceObject); FspFsvolDeviceFileRenameRelease(FsvolDeviceObject);
return Result; return Result;