mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-23 00:43:00 -05:00
sys: FspFileNodeRenameCheck
This commit is contained in:
parent
cb6b10385b
commit
53e2f13e38
138
src/sys/file.c
138
src/sys/file.c
@ -838,55 +838,64 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp,
|
|||||||
{
|
{
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special rules for renaming open files:
|
||||||
|
* - A file cannot be renamed if it has any open handles,
|
||||||
|
* unless it is only open because of a batch opportunistic lock (oplock)
|
||||||
|
* and the batch oplock can be broken immediately.
|
||||||
|
* - A file cannot be renamed if a file with the same name exists
|
||||||
|
* and has open handles (except in the batch-oplock case described earlier).
|
||||||
|
* - 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).
|
||||||
|
*/
|
||||||
|
|
||||||
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;
|
||||||
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
|
FSP_DEVICE_CONTEXT_BY_NAME_TABLE_RESTART_KEY RestartKey;
|
||||||
BOOLEAN SubpathOnly = 0 != FileNode;
|
BOOLEAN CheckingOldName = 0 != FileNode;
|
||||||
|
BOOLEAN HasOpenHandles;
|
||||||
BOOLEAN Success = TRUE;
|
BOOLEAN Success = TRUE;
|
||||||
|
|
||||||
|
DescendantFileNodes = DescendantFileNodeArray;
|
||||||
|
DescendantFileNodeCount = 0;
|
||||||
|
|
||||||
|
/* if we are checking the existing file name, do a quick check here */
|
||||||
|
if (CheckingOldName)
|
||||||
|
{
|
||||||
|
/* if file has single open handle (also means no streams open) and not a directory, exit now */
|
||||||
|
if (1 == FileNode->HandleCount && !FileNode->IsDirectory)
|
||||||
|
{
|
||||||
|
ASSERT(Success);
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: when CheckingOldName==TRUE, the old FileNode is not included in enumerations below */
|
||||||
|
}
|
||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
DescendantFileNodes = DescendantFileNodeArray;
|
/* count descendant file nodes and try to gather them in a local array if possible */
|
||||||
|
|
||||||
if (0 != FileNode)
|
|
||||||
{
|
|
||||||
if (1 < FileNode->HandleCount)
|
|
||||||
{
|
|
||||||
Success = FALSE;
|
|
||||||
goto unlock_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FileNode->IsDirectory)
|
|
||||||
goto unlock_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
DescendantFileNodeCount = 0;
|
|
||||||
memset(&RestartKey, 0, sizeof RestartKey);
|
memset(&RestartKey, 0, sizeof RestartKey);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
||||||
FileName, SubpathOnly, &RestartKey);
|
FileName, CheckingOldName, &RestartKey);
|
||||||
if (0 == DescendantFileNode)
|
if (0 == DescendantFileNode)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (0 < DescendantFileNode->HandleCount)
|
/* keep a reference to the FileNode in case it goes away in later processing */
|
||||||
{
|
FspFileNodeReference(DescendantFileNode);
|
||||||
if (FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(DescendantFileNode)) ||
|
|
||||||
FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(DescendantFileNode)))
|
HasOpenHandles = 0 < DescendantFileNode->HandleCount;
|
||||||
{
|
|
||||||
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
|
if (ARRAYSIZE(DescendantFileNodeArray) > DescendantFileNodeCount)
|
||||||
DescendantFileNodes[DescendantFileNodeCount] = DescendantFileNode;
|
DescendantFileNodes[DescendantFileNodeCount] =
|
||||||
|
(PVOID)((UINT_PTR)DescendantFileNode | HasOpenHandles);
|
||||||
DescendantFileNodeCount++;
|
DescendantFileNodeCount++;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Success = FALSE;
|
|
||||||
goto unlock_exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* if the local array is out of space, gather descendant file nodes in the pool */
|
||||||
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
|
if (ARRAYSIZE(DescendantFileNodeArray) < DescendantFileNodeCount)
|
||||||
{
|
{
|
||||||
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
|
DescendantFileNodes = FspAllocMustSucceed(DescendantFileNodeCount * sizeof(FSP_FILE_NODE *));
|
||||||
@ -895,49 +904,69 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp,
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
||||||
FileName, SubpathOnly, &RestartKey);
|
FileName, CheckingOldName, &RestartKey);
|
||||||
if (0 == DescendantFileNode)
|
if (0 == DescendantFileNode)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (0 < DescendantFileNode->HandleCount)
|
HasOpenHandles = 0 < DescendantFileNode->HandleCount;
|
||||||
{
|
|
||||||
if (FsRtlCurrentBatchOplock(FspFileNodeAddrOfOplock(DescendantFileNode)) ||
|
DescendantFileNodes[DescendantFileNodeIndex] =
|
||||||
FsRtlCurrentOplockH(FspFileNodeAddrOfOplock(DescendantFileNode)))
|
(PVOID)((UINT_PTR)DescendantFileNode | HasOpenHandles);
|
||||||
{
|
|
||||||
DescendantFileNodes[DescendantFileNodeIndex] = DescendantFileNode;
|
|
||||||
DescendantFileNodeIndex++;
|
DescendantFileNodeIndex++;
|
||||||
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
|
ASSERT(DescendantFileNodeCount >= DescendantFileNodeIndex);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Success = FALSE;
|
|
||||||
goto unlock_exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
|
ASSERT(DescendantFileNodeCount == DescendantFileNodeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* "rename" resource exclusively, which disallows new Opens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!CheckingOldName)
|
||||||
|
{
|
||||||
|
/* make sure no processes are mapping any descendants as an image */
|
||||||
for (
|
for (
|
||||||
DescendantFileNodeIndex = 0;
|
DescendantFileNodeIndex = 0;
|
||||||
DescendantFileNodeCount > DescendantFileNodeIndex;
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
DescendantFileNodeIndex++)
|
DescendantFileNodeIndex++)
|
||||||
{
|
{
|
||||||
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1);
|
||||||
|
|
||||||
|
Success = MmFlushImageSection(&DescendantFileNode->NonPaged->SectionObjectPointers,
|
||||||
|
MmFlushForDelete);
|
||||||
|
if (!Success)
|
||||||
|
goto unlock_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* break any batch oplocks on descendants */
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
HasOpenHandles = (UINT_PTR)DescendantFileNode & 1;
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1);
|
||||||
|
|
||||||
|
if (HasOpenHandles)
|
||||||
FspCheckOplock(FspFileNodeAddrOfOplock(DescendantFileNode), Irp, 0, 0, 0);
|
FspCheckOplock(FspFileNodeAddrOfOplock(DescendantFileNode), Irp, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceLockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/* recheck whether there are still files with open handles */
|
||||||
memset(&RestartKey, 0, sizeof RestartKey);
|
memset(&RestartKey, 0, sizeof RestartKey);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
DescendantFileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject,
|
||||||
FileName, SubpathOnly, &RestartKey);
|
FileName, CheckingOldName, &RestartKey);
|
||||||
if (0 == DescendantFileNode)
|
if (0 == DescendantFileNode)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -948,16 +977,21 @@ BOOLEAN FspFileNodeRenameCheck(PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
|
||||||
|
|
||||||
if (DescendantFileNodeArray != DescendantFileNodes)
|
|
||||||
FspFree(DescendantFileNodes);
|
|
||||||
|
|
||||||
return Success;
|
|
||||||
|
|
||||||
unlock_exit:
|
unlock_exit:
|
||||||
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);
|
||||||
|
|
||||||
|
/* dereference all FileNode's referenced during initial enumeration */
|
||||||
|
for (
|
||||||
|
DescendantFileNodeIndex = 0;
|
||||||
|
DescendantFileNodeCount > DescendantFileNodeIndex;
|
||||||
|
DescendantFileNodeIndex++)
|
||||||
|
{
|
||||||
|
DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex];
|
||||||
|
DescendantFileNode = (PVOID)((UINT_PTR)DescendantFileNode & ~1);
|
||||||
|
|
||||||
|
FspFileNodeDereference(DescendantFileNode);
|
||||||
|
}
|
||||||
|
|
||||||
if (DescendantFileNodeArray != DescendantFileNodes)
|
if (DescendantFileNodeArray != DescendantFileNodes)
|
||||||
FspFree(DescendantFileNodes);
|
FspFree(DescendantFileNodes);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user