diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index a418bfaa..ff5fa5a4 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -348,7 +348,8 @@ typedef struct UINT64 UserContext2; } QueryStreamInformation; } Req; - FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */ + FSP_FSCTL_TRANSACT_BUF FileName; + /* Create,Cleanup,SetInformation{Disposition,Rename},FileSystemControl{ReparsePoint} */ FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[]; } FSP_FSCTL_TRANSACT_REQ; typedef struct diff --git a/src/sys/driver.h b/src/sys/driver.h index 4d05055f..5e3af46f 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -514,13 +514,13 @@ NTSTATUS FspNotifyFullReportChange( #define FspNotifyCleanupAll(NS, NL)\ FsRtlNotifyCleanupAll(NS, NL) #define FspNotifyChangeDirectory(NS, NL, FC, FN, WT, CF, I)\ - FspNotifyFullChangeDirectory(NS, NL, FC, (PSTRING)FN, WT, FALSE, CF, I, 0, 0) + FspNotifyFullChangeDirectory(NS, NL, FC, (PSTRING)(FN), WT, FALSE, CF, I, 0, 0) #define FspNotifyCleanup(NS, NL, FC)\ FsRtlNotifyCleanup(NS, NL, FC) #define FspNotifyDeletePending(NS, NL, FC)\ FspNotifyFullChangeDirectory(NS, NL, FC, 0, 0, FALSE, 0, 0, 0, 0) -#define FspNotifyReportChange(NS, NL, FN, FO, SN, F, A)\ - FspNotifyFullReportChange(NS, NL, (PSTRING)FN, FO, (PSTRING)SN, 0, F, A, 0) +#define FspNotifyReportChange(NS, NL, FN, FO, NP, F, A)\ + FspNotifyFullReportChange(NS, NL, (PSTRING)(FN), FO, 0, (PSTRING)(NP), F, A, 0) /* utility: synchronous work queue */ typedef struct @@ -1026,6 +1026,27 @@ VOID FspFileNodeConvertExclusiveToSharedF(FSP_FILE_NODE *FileNode, ULONG Flags); VOID FspFileNodeSetOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner); VOID FspFileNodeReleaseF(FSP_FILE_NODE *FileNode, ULONG Flags); VOID FspFileNodeReleaseOwnerF(FSP_FILE_NODE *FileNode, ULONG Flags, PVOID Owner); +static inline +VOID FspFileNodeAcquireSharedForeign(FSP_FILE_NODE *FileNode) +{ + if (0 != FileNode->MainFileNode) + FileNode = FileNode->MainFileNode; + ExAcquireResourceSharedLite(FileNode->Header.Resource, TRUE); +} +static inline +VOID FspFileNodeAcquireExclusiveForeign(FSP_FILE_NODE *FileNode) +{ + if (0 != FileNode->MainFileNode) + FileNode = FileNode->MainFileNode; + ExAcquireResourceExclusiveLite(FileNode->Header.Resource, TRUE); +} +static inline +VOID FspFileNodeReleaseForeign(FSP_FILE_NODE *FileNode) +{ + if (0 != FileNode->MainFileNode) + FileNode = FileNode->MainFileNode; + ExReleaseResourceLite(FileNode->Header.Resource); +} FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult); VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, diff --git a/src/sys/file.c b/src/sys/file.c index 3bf0b4b7..aa2775c9 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -803,6 +803,25 @@ NTSTATUS FspFileNodeFlushAndPurgeCache(FSP_FILE_NODE *FileNode, VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) { + /* + * FspFileNodeRename may block, because it attempts to acquire the Main + * resource of descendant file nodes. FspFileNodeRename is called at the + * completion path of IRP_MJ_SET_INFORMATION[Rename] and an IRP completion + * path should not block, with the notable exception of Rename. + * + * The original reason that Rename completion is allowed to block was that + * it was observed that IoCompleteRequest of a Rename could sometimes + * trigger a recursive call into the FSD (likely due to a filter). WinFsp + * was modified to accommodate this by allowing this recursive call to + * proceed on a different thread. + * + * Since WinFsp can already accommodate blocking on Rename completions, + * it is safe to acquire the Main resource of descendant file nodes. + * + * Note also that there can only be one rename at a time because of the + * device's FileRenameResource. + */ + PAGED_CODE(); PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; @@ -862,6 +881,9 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) DescendantFileNode = DescendantFileNodes[DescendantFileNodeIndex]; ASSERT(DescendantFileNode->FileName.Length >= FileNameLength); + if (0 != DescendantFileNodeIndex) + FspFileNodeAcquireExclusiveForeign(DescendantFileNode); + FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, &Deleted); ASSERT(Deleted); @@ -888,6 +910,9 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) FspFsvolDeviceInsertContextByName(FsvolDeviceObject, &DescendantFileNode->FileName, DescendantFileNode, &DescendantFileNode->ContextByNameElementStorage, &Inserted); ASSERT(Inserted); + + if (0 != DescendantFileNodeIndex) + FspFileNodeReleaseForeign(DescendantFileNode); } FspFsvolDeviceUnlockContextTable(FsvolDeviceObject);