mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-29 19:18:39 -05:00 
			
		
		
		
	sys: IRP_MJ_QUERY_INFORMATION: FileStreamInformation
This commit is contained in:
		| @@ -106,6 +106,7 @@ enum | ||||
|     FspFsctlTransactLockControlKind, | ||||
|     FspFsctlTransactQuerySecurityKind, | ||||
|     FspFsctlTransactSetSecurityKind, | ||||
|     FspFsctlTransactQueryStreamInformationKind, | ||||
|     FspFsctlTransactKindCount, | ||||
| }; | ||||
| enum | ||||
| @@ -142,7 +143,7 @@ typedef struct | ||||
|     UINT32 PersistentAcls:1;            /* file system preserves and enforces access control lists */ | ||||
|     UINT32 ReparsePoints:1;             /* file system supports reparse points */ | ||||
|     UINT32 ReparsePointsAccessCheck:1;  /* file system performs reparse point access checks */ | ||||
|     UINT32 NamedStreams:1;              /* file system supports named streams (!!!: unimplemented) */ | ||||
|     UINT32 NamedStreams:1;              /* file system supports named streams */ | ||||
|     UINT32 HardLinks:1;                 /* unimplemented; set to 0 */ | ||||
|     UINT32 ExtendedAttributes:1;        /* unimplemented; set to 0 */ | ||||
|     UINT32 ReadOnlyVolume:1; | ||||
| @@ -184,6 +185,13 @@ typedef struct | ||||
|     WCHAR FileNameBuf[]; | ||||
| } FSP_FSCTL_DIR_INFO; | ||||
| typedef struct | ||||
| { | ||||
|     UINT16 Size; | ||||
|     UINT64 StreamSize; | ||||
|     UINT64 StreamAllocationSize; | ||||
|     WCHAR StreamNameBuf[]; | ||||
| } FSP_FSCTL_STREAM_INFO; | ||||
| typedef struct | ||||
| { | ||||
|     UINT16 Offset; | ||||
|     UINT16 Size; | ||||
| @@ -332,6 +340,11 @@ typedef struct | ||||
|             UINT64 AccessToken;         /* request access token (HANDLE) */ | ||||
|             FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; | ||||
|         } SetSecurity; | ||||
|         struct | ||||
|         { | ||||
|             UINT64 UserContext; | ||||
|             UINT64 UserContext2; | ||||
|         } QueryStreamInformation; | ||||
|     } Req; | ||||
|     FSP_FSCTL_TRANSACT_BUF FileName;    /* {Create,Cleanup,SetInformation/{...},QueryDirectory} */ | ||||
|     FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[]; | ||||
| @@ -401,6 +414,10 @@ typedef struct | ||||
|         { | ||||
|             FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;  /* Size==0 means no security descriptor returned */ | ||||
|         } SetSecurity; | ||||
|         struct | ||||
|         { | ||||
|             FSP_FSCTL_TRANSACT_BUF Buffer; | ||||
|         } QueryStreamInformation; | ||||
|     } Rsp; | ||||
|     FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[]; | ||||
| } FSP_FSCTL_TRANSACT_RSP; | ||||
|   | ||||
| @@ -773,12 +773,36 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE | ||||
|         FSP_FSCTL_TRANSACT_REQ *Request, | ||||
|         PVOID FileNode, | ||||
|         PWSTR FileName, PVOID Buffer, SIZE_T Size); | ||||
|     /** | ||||
|      * Get named streams information. | ||||
|      * | ||||
|      * @param FileSystem | ||||
|      *     The file system on which this request is posted. | ||||
|      * @param Request | ||||
|      *     The request posted by the kernel mode FSD. | ||||
|      * @param FileNode | ||||
|      *     The file node of the file or directory to get stream information for. | ||||
|      * @param Buffer | ||||
|      *     Pointer to a buffer that will receive the stream information. | ||||
|      * @param Length | ||||
|      *     Length of buffer. | ||||
|      * @param PBytesTransferred [out] | ||||
|      *     Pointer to a memory location that will receive the actual number of bytes stored. | ||||
|      * @return | ||||
|      *     STATUS_SUCCESS or error code. | ||||
|      * @see | ||||
|      *     FspFileSystemAddStreamInfo | ||||
|      */ | ||||
|     NTSTATUS (*GetStreamInfo)(FSP_FILE_SYSTEM *FileSystem, | ||||
|         FSP_FSCTL_TRANSACT_REQ *Request, | ||||
|         PVOID FileNode, PVOID Buffer, ULONG Length, | ||||
|         PULONG PBytesTransferred); | ||||
|  | ||||
|     /* | ||||
|      * This ensures that this interface will always contain 64 function pointers. | ||||
|      * Please update when changing the interface as it is important for future compatibility. | ||||
|      */ | ||||
|     NTSTATUS (*Reserved[41])(); | ||||
|     NTSTATUS (*Reserved[40])(); | ||||
| } FSP_FILE_SYSTEM_INTERFACE; | ||||
| FSP_FSCTL_STATIC_ASSERT(sizeof(FSP_FILE_SYSTEM_INTERFACE) == 64 * sizeof(NTSTATUS (*)()), | ||||
|     "FSP_FILE_SYSTEM_INTERFACE must have 64 entries."); | ||||
| @@ -1010,6 +1034,8 @@ FSP_API NTSTATUS FspFileSystemOpQuerySecurity(FSP_FILE_SYSTEM *FileSystem, | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); | ||||
| FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem, | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); | ||||
| FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSystem, | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); | ||||
|  | ||||
| /* | ||||
|  * Helpers | ||||
| @@ -1150,6 +1176,30 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem, | ||||
| FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint( | ||||
|     PVOID CurrentReparseData, SIZE_T CurrentReparseDataSize, | ||||
|     PVOID ReplaceReparseData, SIZE_T ReplaceReparseDataSize); | ||||
| /** | ||||
|  * Add named stream information to a buffer. | ||||
|  * | ||||
|  * This is a helper for implementing the GetStreamInfo operation. | ||||
|  * | ||||
|  * @param StreamInfo | ||||
|  *     The stream information to add. A value of NULL acts as an EOF marker for a GetStreamInfo | ||||
|  *     operation. | ||||
|  * @param Buffer | ||||
|  *     Pointer to a buffer that will receive the stream information. This should contain | ||||
|  *     the same value passed to the GetStreamInfo Buffer parameter. | ||||
|  * @param Length | ||||
|  *     Length of buffer. This should contain the same value passed to the GetStreamInfo | ||||
|  *     Length parameter. | ||||
|  * @param PBytesTransferred [out] | ||||
|  *     Pointer to a memory location that will receive the actual number of bytes stored. This should | ||||
|  *     contain the same value passed to the GetStreamInfo PBytesTransferred parameter. | ||||
|  * @return | ||||
|  *     TRUE if the stream information was added, FALSE if there was not enough space to add it. | ||||
|  * @see | ||||
|  *     GetStreamInfo | ||||
|  */ | ||||
| FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo, | ||||
|     PVOID Buffer, ULONG Length, PULONG PBytesTransferred); | ||||
|  | ||||
| /* | ||||
|  * Security | ||||
|   | ||||
| @@ -99,6 +99,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, | ||||
|     FileSystem->Operations[FspFsctlTransactFileSystemControlKind] = FspFileSystemOpFileSystemControl; | ||||
|     FileSystem->Operations[FspFsctlTransactQuerySecurityKind] = FspFileSystemOpQuerySecurity; | ||||
|     FileSystem->Operations[FspFsctlTransactSetSecurityKind] = FspFileSystemOpSetSecurity; | ||||
|     FileSystem->Operations[FspFsctlTransactQueryStreamInformationKind] = FspFileSystemOpQueryStreamInformation; | ||||
|     FileSystem->Interface = Interface; | ||||
|  | ||||
|     FileSystem->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE; | ||||
|   | ||||
| @@ -976,18 +976,46 @@ FSP_API NTSTATUS FspFileSystemOpSetSecurity(FSP_FILE_SYSTEM *FileSystem, | ||||
|         (PSECURITY_DESCRIPTOR)Request->Buffer); | ||||
| } | ||||
|  | ||||
| FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo, | ||||
| FSP_API NTSTATUS FspFileSystemOpQueryStreamInformation(FSP_FILE_SYSTEM *FileSystem, | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) | ||||
| { | ||||
|     NTSTATUS Result; | ||||
|     ULONG BytesTransferred; | ||||
|  | ||||
|     if (0 == FileSystem->Interface->GetStreamInfo) | ||||
|         return STATUS_INVALID_DEVICE_REQUEST; | ||||
|  | ||||
|     BytesTransferred = 0; | ||||
|     Result = FileSystem->Interface->GetStreamInfo(FileSystem, Request, | ||||
|         (PVOID)USERCONTEXT(Request->Req.QueryStreamInformation), | ||||
|         Response->Buffer, | ||||
|         FSP_FSCTL_TRANSACT_RSP_SIZEMAX - sizeof *Response, | ||||
|         &BytesTransferred); | ||||
|     if (!NT_SUCCESS(Result)) | ||||
|         return Result; | ||||
|  | ||||
|     Response->Size = (UINT16)(sizeof *Response + BytesTransferred); | ||||
|     Response->Rsp.QueryStreamInformation.Buffer.Offset = 0; | ||||
|     Response->Rsp.QueryStreamInformation.Buffer.Size = (UINT16)BytesTransferred; | ||||
|     return STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| FSP_FSCTL_STATIC_ASSERT( | ||||
|     sizeof(UINT16) == sizeof ((FSP_FSCTL_DIR_INFO *)0)->Size && | ||||
|     sizeof(UINT16) == sizeof ((FSP_FSCTL_STREAM_INFO *)0)->Size, | ||||
|     "FSP_FSCTL_DIR_INFO::Size and FSP_FSCTL_STREAM_INFO::Size: sizeof must be 2."); | ||||
| static BOOLEAN FspFileSystemAddXxxInfo(PVOID Info, SIZE_T InfoSize, | ||||
|     PVOID Buffer, ULONG Length, PULONG PBytesTransferred) | ||||
| { | ||||
|     static UINT8 Zero[sizeof DirInfo->Size] = { 0 }; | ||||
|     static UINT8 Zero[sizeof(UINT16)] = { 0 }; | ||||
|     PVOID BufferEnd = (PUINT8)Buffer + Length; | ||||
|     PVOID SrcBuffer; | ||||
|     ULONG SrcLength, DstLength; | ||||
|  | ||||
|     if (0 != DirInfo) | ||||
|     if (0 != Info) | ||||
|     { | ||||
|         SrcBuffer = DirInfo; | ||||
|         SrcLength = DirInfo->Size; | ||||
|         SrcBuffer = Info; | ||||
|         SrcLength = *(PUINT16)Info; | ||||
|         DstLength = FSP_FSCTL_DEFAULT_ALIGN_UP(SrcLength); | ||||
|     } | ||||
|     else | ||||
| @@ -1007,6 +1035,12 @@ FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo, | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| FSP_API BOOLEAN FspFileSystemAddDirInfo(FSP_FSCTL_DIR_INFO *DirInfo, | ||||
|     PVOID Buffer, ULONG Length, PULONG PBytesTransferred) | ||||
| { | ||||
|     return FspFileSystemAddXxxInfo(DirInfo, sizeof *DirInfo, Buffer, Length, PBytesTransferred); | ||||
| } | ||||
|  | ||||
| FSP_API BOOLEAN FspFileSystemFindReparsePoint(FSP_FILE_SYSTEM *FileSystem, | ||||
|     NTSTATUS (*GetReparsePointByName)( | ||||
|         FSP_FILE_SYSTEM *FileSystem, PVOID Context, | ||||
| @@ -1267,3 +1301,9 @@ FSP_API NTSTATUS FspFileSystemCanReplaceReparsePoint( | ||||
|     else | ||||
|         return STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| FSP_API BOOLEAN FspFileSystemAddStreamInfo(FSP_FSCTL_STREAM_INFO *StreamInfo, | ||||
|     PVOID Buffer, ULONG Length, PULONG PBytesTransferred) | ||||
| { | ||||
|     return FspFileSystemAddXxxInfo(StreamInfo, sizeof *StreamInfo, Buffer, Length, PBytesTransferred); | ||||
| } | ||||
|   | ||||
| @@ -41,7 +41,6 @@ struct fsp_fuse_core_opt_data | ||||
|         rellinks; | ||||
|     int set_FileInfoTimeout; | ||||
|     int CaseInsensitiveSearch, | ||||
|         NamedStreams, | ||||
|         ReadOnlyVolume; | ||||
|     FSP_FSCTL_VOLUME_PARAMS VolumeParams; | ||||
| }; | ||||
| @@ -96,9 +95,9 @@ static struct fuse_opt fsp_fuse_core_opts[] = | ||||
|     FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1), | ||||
|     FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0), | ||||
|     FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1), | ||||
|     FSP_FUSE_CORE_OPT("NamedStreams", NamedStreams, 1), | ||||
|     FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1), | ||||
|     FUSE_OPT_KEY("ReparsePoints", FUSE_OPT_KEY_DISCARD), | ||||
|     FUSE_OPT_KEY("NamedStreams", FUSE_OPT_KEY_DISCARD), | ||||
|     FUSE_OPT_KEY("HardLinks", FUSE_OPT_KEY_DISCARD), | ||||
|     FUSE_OPT_KEY("ExtendedAttributes", FUSE_OPT_KEY_DISCARD), | ||||
|     FUSE_OPT_KEY("--UNC=", 'U'), | ||||
| @@ -457,7 +456,6 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key, | ||||
|             "    -o VolumeSerialNumber=N    32-bit wide\n" | ||||
|             "    -o FileInfoTimeout=N       FileInfo/Security/VolumeInfo timeout (millisec)\n" | ||||
|             "    -o CaseInsensitiveSearch   file system supports case-insensitive file names\n" | ||||
|             //"    -o NamedStreams            file system supports named streams\n" | ||||
|             //"    -o ReadOnlyVolume          file system is read only\n" | ||||
|             "    --UNC=U --VolumePrefix=U   UNC prefix (\\Server\\Share)\n" | ||||
|             "    --FileSystemName=FSN       Name of user mode file system\n"); | ||||
| @@ -523,7 +521,7 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, | ||||
|     opt_data.VolumeParams.PersistentAcls = TRUE; | ||||
|     opt_data.VolumeParams.ReparsePoints = TRUE; | ||||
|     opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE; | ||||
|     opt_data.VolumeParams.NamedStreams = !!opt_data.NamedStreams; | ||||
|     opt_data.VolumeParams.NamedStreams = FALSE; | ||||
|     opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume; | ||||
|     opt_data.VolumeParams.PostCleanupOnDeleteOnly = TRUE; | ||||
|     opt_data.VolumeParams.UmFileNodeIsUserContext2 = TRUE; | ||||
|   | ||||
| @@ -295,7 +295,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) | ||||
|     NTSTATUS Result; | ||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); | ||||
|     LARGE_INTEGER IrpTimeout; | ||||
|     LARGE_INTEGER SecurityTimeout, DirInfoTimeout; | ||||
|     LARGE_INTEGER SecurityTimeout, DirInfoTimeout, StreamInfoTimeout; | ||||
|  | ||||
|     /* | ||||
|      * Volume device initialization is a mess, because of the different ways of | ||||
| @@ -347,6 +347,16 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) | ||||
|         return Result; | ||||
|     FsvolDeviceExtension->InitDoneDir = 1; | ||||
|  | ||||
|     /* create our stream info meta cache */ | ||||
|     StreamInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout); | ||||
|         /* convert millis to nanos */ | ||||
|     Result = FspMetaCacheCreate( | ||||
|         FspFsvolDeviceStreamInfoCacheCapacity, FspFsvolDeviceStreamInfoCacheItemSizeMax, &StreamInfoTimeout, | ||||
|         &FsvolDeviceExtension->StreamInfoCache); | ||||
|     if (!NT_SUCCESS(Result)) | ||||
|         return Result; | ||||
|     FsvolDeviceExtension->InitDoneStrm = 1; | ||||
|  | ||||
|     /* initialize the FSRTL Notify mechanism */ | ||||
|     Result = FspNotifyInitializeSync(&FsvolDeviceExtension->NotifySync); | ||||
|     if (!NT_SUCCESS(Result)) | ||||
| @@ -406,6 +416,10 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject) | ||||
|         FspNotifyUninitializeSync(&FsvolDeviceExtension->NotifySync); | ||||
|     } | ||||
|  | ||||
|     /* delete the stream info meta cache */ | ||||
|     if (FsvolDeviceExtension->InitDoneStrm) | ||||
|         FspMetaCacheDelete(FsvolDeviceExtension->StreamInfoCache); | ||||
|  | ||||
|     /* delete the directory meta cache */ | ||||
|     if (FsvolDeviceExtension->InitDoneDir) | ||||
|         FspMetaCacheDelete(FsvolDeviceExtension->DirInfoCache); | ||||
| @@ -484,6 +498,7 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context) | ||||
|     InterruptTime = KeQueryInterruptTime(); | ||||
|     FspMetaCacheInvalidateExpired(FsvolDeviceExtension->SecurityCache, InterruptTime); | ||||
|     FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime); | ||||
|     FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime); | ||||
|     FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime); | ||||
|  | ||||
|     KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql); | ||||
|   | ||||
| @@ -722,6 +722,8 @@ enum | ||||
|     FspFsvolDeviceSecurityCacheItemSizeMax = 4096, | ||||
|     FspFsvolDeviceDirInfoCacheCapacity = 100, | ||||
|     FspFsvolDeviceDirInfoCacheItemSizeMax = FSP_FSCTL_ALIGN_UP(16384, PAGE_SIZE), | ||||
|     FspFsvolDeviceStreamInfoCacheCapacity = 100, | ||||
|     FspFsvolDeviceStreamInfoCacheItemSizeMax = 4096, | ||||
| }; | ||||
| typedef struct | ||||
| { | ||||
| @@ -748,7 +750,7 @@ typedef struct | ||||
| typedef struct | ||||
| { | ||||
|     FSP_DEVICE_EXTENSION Base; | ||||
|     UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, | ||||
|     UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1, | ||||
|         InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1; | ||||
|     PDEVICE_OBJECT FsctlDeviceObject; | ||||
|     PDEVICE_OBJECT FsvrtDeviceObject; | ||||
| @@ -760,6 +762,7 @@ typedef struct | ||||
|     FSP_IOQ *Ioq; | ||||
|     FSP_META_CACHE *SecurityCache; | ||||
|     FSP_META_CACHE *DirInfoCache; | ||||
|     FSP_META_CACHE *StreamInfoCache; | ||||
|     KSPIN_LOCK ExpirationLock; | ||||
|     WORK_QUEUE_ITEM ExpirationWorkItem; | ||||
|     BOOLEAN ExpirationInProgress; | ||||
| @@ -888,8 +891,9 @@ typedef struct | ||||
|     ERESOURCE PagingIoResource; | ||||
|     FAST_MUTEX HeaderFastMutex; | ||||
|     SECTION_OBJECT_POINTERS SectionObjectPointers; | ||||
|     KSPIN_LOCK DirInfoSpinLock; | ||||
|     UINT64 DirInfo;                     /* allows to invalidate DirInfo w/o resources acquired */ | ||||
|     KSPIN_LOCK NpInfoSpinLock;          /* allows to invalidate non-page Info w/o resources acquired */ | ||||
|     UINT64 DirInfo; | ||||
|     UINT64 StreamInfo; | ||||
| } FSP_FILE_NODE_NONPAGED; | ||||
| typedef struct | ||||
| { | ||||
| @@ -918,6 +922,7 @@ typedef struct | ||||
|     UINT64 Security; | ||||
|     ULONG SecurityChangeNumber; | ||||
|     ULONG DirInfoChangeNumber; | ||||
|     ULONG StreamInfoChangeNumber; | ||||
|     BOOLEAN TruncateOnClose; | ||||
|     FILE_LOCK FileLock; | ||||
|     struct | ||||
| @@ -1001,6 +1006,10 @@ BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PU | ||||
| VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size); | ||||
| BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, | ||||
|     ULONG DirInfoChangeNumber); | ||||
| BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize); | ||||
| VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size); | ||||
| BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, | ||||
|     ULONG StreamInfoChangeNumber); | ||||
| VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action); | ||||
| NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp); | ||||
| NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); | ||||
| @@ -1017,6 +1026,7 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, | ||||
| #define FspFileNodeReleaseOwner(N,F,P)  FspFileNodeReleaseOwnerF(N, FspFileNodeAcquire ## F, P) | ||||
| #define FspFileNodeDereferenceSecurity(P)   FspMetaCacheDereferenceItemBuffer(P) | ||||
| #define FspFileNodeDereferenceDirInfo(P)    FspMetaCacheDereferenceItemBuffer(P) | ||||
| #define FspFileNodeDereferenceStreamInfo(P) FspMetaCacheDereferenceItemBuffer(P) | ||||
| #define FspFileNodeUnlockAll(N,F,P)     FsRtlFastUnlockAll(&(N)->FileLock, F, P, N) | ||||
|  | ||||
| /* multiversion support */ | ||||
|   | ||||
| @@ -57,6 +57,11 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size); | ||||
| BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, | ||||
|     ULONG DirInfoChangeNumber); | ||||
| static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode); | ||||
| BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize); | ||||
| VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size); | ||||
| BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, | ||||
|     ULONG StreamInfoChangeNumber); | ||||
| static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode); | ||||
| VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, | ||||
|     ULONG Filter, ULONG Action); | ||||
| NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp); | ||||
| @@ -97,6 +102,10 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, | ||||
| // !#pragma alloc_text(PAGE, FspFileNodeSetDirInfo) | ||||
| // !#pragma alloc_text(PAGE, FspFileNodeTrySetDirInfo) | ||||
| // !#pragma alloc_text(PAGE, FspFileNodeInvalidateDirInfo) | ||||
| // !#pragma alloc_text(PAGE, FspFileNodeReferenceStreamInfo) | ||||
| // !#pragma alloc_text(PAGE, FspFileNodeSetStreamInfo) | ||||
| // !#pragma alloc_text(PAGE, FspFileNodeTrySetStreamInfo) | ||||
| // !#pragma alloc_text(PAGE, FspFileNodeInvalidateStreamInfo) | ||||
| #pragma alloc_text(PAGE, FspFileNodeNotifyChange) | ||||
| #pragma alloc_text(PAGE, FspFileNodeProcessLockIrp) | ||||
| #pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp) | ||||
| @@ -176,7 +185,7 @@ NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject, | ||||
|     ExInitializeResourceLite(&NonPaged->Resource); | ||||
|     ExInitializeResourceLite(&NonPaged->PagingIoResource); | ||||
|     ExInitializeFastMutex(&NonPaged->HeaderFastMutex); | ||||
|     KeInitializeSpinLock(&NonPaged->DirInfoSpinLock); | ||||
|     KeInitializeSpinLock(&NonPaged->NpInfoSpinLock); | ||||
|  | ||||
|     RtlZeroMemory(FileNode, sizeof *FileNode + ExtraSize); | ||||
|     FileNode->Header.NodeTypeCode = FspFileNodeFileKind; | ||||
| @@ -211,6 +220,7 @@ VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode) | ||||
|  | ||||
|     FsRtlTeardownPerStreamContexts(&FileNode->Header); | ||||
|  | ||||
|     FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, FileNode->NonPaged->StreamInfo); | ||||
|     FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, FileNode->NonPaged->DirInfo); | ||||
|     FspMetaCacheInvalidateItem(FsvolDeviceExtension->SecurityCache, FileNode->Security); | ||||
|  | ||||
| @@ -848,7 +858,7 @@ BOOLEAN FspFileNodeReferenceDirInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PU | ||||
|     FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged; | ||||
|     UINT64 DirInfo; | ||||
|  | ||||
|     /* no need to acquire the DirInfoSpinLock as the FileNode is acquired */ | ||||
|     /* no need to acquire the NpInfoSpinLock as the FileNode is acquired */ | ||||
|     DirInfo = NonPaged->DirInfo; | ||||
|  | ||||
|     return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->DirInfoCache, | ||||
| @@ -865,7 +875,7 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size) | ||||
|     KIRQL Irql; | ||||
|     UINT64 DirInfo; | ||||
|  | ||||
|     /* no need to acquire the DirInfoSpinLock as the FileNode is acquired */ | ||||
|     /* no need to acquire the NpInfoSpinLock as the FileNode is acquired */ | ||||
|     DirInfo = NonPaged->DirInfo; | ||||
|  | ||||
|     FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo); | ||||
| @@ -873,10 +883,10 @@ VOID FspFileNodeSetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size) | ||||
|         FspMetaCacheAddItem(FsvolDeviceExtension->DirInfoCache, Buffer, Size) : 0; | ||||
|     FileNode->DirInfoChangeNumber++; | ||||
|  | ||||
|     /* acquire the DirInfoSpinLock to protect against concurrent FspFileNodeInvalidateDirInfo */ | ||||
|     KeAcquireSpinLock(&NonPaged->DirInfoSpinLock, &Irql); | ||||
|     /* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateDirInfo */ | ||||
|     KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql); | ||||
|     NonPaged->DirInfo = DirInfo; | ||||
|     KeReleaseSpinLock(&NonPaged->DirInfoSpinLock, Irql); | ||||
|     KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql); | ||||
| } | ||||
|  | ||||
| BOOLEAN FspFileNodeTrySetDirInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, | ||||
| @@ -901,14 +911,84 @@ static VOID FspFileNodeInvalidateDirInfo(FSP_FILE_NODE *FileNode) | ||||
|     KIRQL Irql; | ||||
|     UINT64 DirInfo; | ||||
|  | ||||
|     /* acquire the DirInfoSpinLock to protect against concurrent FspFileNodeSetDirInfo */ | ||||
|     KeAcquireSpinLock(&NonPaged->DirInfoSpinLock, &Irql); | ||||
|     /* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetDirInfo */ | ||||
|     KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql); | ||||
|     DirInfo = NonPaged->DirInfo; | ||||
|     KeReleaseSpinLock(&NonPaged->DirInfoSpinLock, Irql); | ||||
|     KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql); | ||||
|  | ||||
|     FspMetaCacheInvalidateItem(FsvolDeviceExtension->DirInfoCache, DirInfo); | ||||
| } | ||||
|  | ||||
| BOOLEAN FspFileNodeReferenceStreamInfo(FSP_FILE_NODE *FileNode, PCVOID *PBuffer, PULONG PSize) | ||||
| { | ||||
|     // !PAGED_CODE(); | ||||
|  | ||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = | ||||
|         FspFsvolDeviceExtension(FileNode->FsvolDeviceObject); | ||||
|     FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged; | ||||
|     UINT64 StreamInfo; | ||||
|  | ||||
|     /* no need to acquire the NpInfoSpinLock as the FileNode is acquired */ | ||||
|     StreamInfo = NonPaged->StreamInfo; | ||||
|  | ||||
|     return FspMetaCacheReferenceItemBuffer(FsvolDeviceExtension->StreamInfoCache, | ||||
|         StreamInfo, PBuffer, PSize); | ||||
| } | ||||
|  | ||||
| VOID FspFileNodeSetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size) | ||||
| { | ||||
|     // !PAGED_CODE(); | ||||
|  | ||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = | ||||
|         FspFsvolDeviceExtension(FileNode->FsvolDeviceObject); | ||||
|     FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged; | ||||
|     KIRQL Irql; | ||||
|     UINT64 StreamInfo; | ||||
|  | ||||
|     /* no need to acquire the NpInfoSpinLock as the FileNode is acquired */ | ||||
|     StreamInfo = NonPaged->StreamInfo; | ||||
|  | ||||
|     FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo); | ||||
|     StreamInfo = 0 != Buffer ? | ||||
|         FspMetaCacheAddItem(FsvolDeviceExtension->StreamInfoCache, Buffer, Size) : 0; | ||||
|     FileNode->StreamInfoChangeNumber++; | ||||
|  | ||||
|     /* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeInvalidateStreamInfo */ | ||||
|     KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql); | ||||
|     NonPaged->StreamInfo = StreamInfo; | ||||
|     KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql); | ||||
| } | ||||
|  | ||||
| BOOLEAN FspFileNodeTrySetStreamInfo(FSP_FILE_NODE *FileNode, PCVOID Buffer, ULONG Size, | ||||
|     ULONG StreamInfoChangeNumber) | ||||
| { | ||||
|     // !PAGED_CODE(); | ||||
|  | ||||
|     if (FileNode->StreamInfoChangeNumber != StreamInfoChangeNumber) | ||||
|         return FALSE; | ||||
|  | ||||
|     FspFileNodeSetStreamInfo(FileNode, Buffer, Size); | ||||
|     return TRUE; | ||||
| } | ||||
|  | ||||
| static VOID FspFileNodeInvalidateStreamInfo(FSP_FILE_NODE *FileNode) | ||||
| { | ||||
|     // !PAGED_CODE(); | ||||
|  | ||||
|     PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; | ||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); | ||||
|     FSP_FILE_NODE_NONPAGED *NonPaged = FileNode->NonPaged; | ||||
|     KIRQL Irql; | ||||
|     UINT64 StreamInfo; | ||||
|  | ||||
|     /* acquire the NpInfoSpinLock to protect against concurrent FspFileNodeSetStreamInfo */ | ||||
|     KeAcquireSpinLock(&NonPaged->NpInfoSpinLock, &Irql); | ||||
|     StreamInfo = NonPaged->StreamInfo; | ||||
|     KeReleaseSpinLock(&NonPaged->NpInfoSpinLock, Irql); | ||||
|  | ||||
|     FspMetaCacheInvalidateItem(FsvolDeviceExtension->StreamInfoCache, StreamInfo); | ||||
| } | ||||
|  | ||||
| VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, | ||||
|     ULONG Filter, ULONG Action) | ||||
| { | ||||
|   | ||||
| @@ -38,6 +38,13 @@ static NTSTATUS FspFsvolQueryPositionInformation(PFILE_OBJECT FileObject, | ||||
| static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject, | ||||
|     PVOID *PBuffer, PVOID BufferEnd, | ||||
|     const FSP_FSCTL_FILE_INFO *FileInfo); | ||||
| static NTSTATUS FspFsvolQueryStreamInformationCopy( | ||||
|     FSP_FSCTL_STREAM_INFO *StreamInfoBuffer, ULONG StreamInfoBufferSize, | ||||
|     PVOID DestBuf, PULONG PDestLen); | ||||
| static NTSTATUS FspFsvolQueryStreamInformation( | ||||
|     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||
| static NTSTATUS FspFsvolQueryStreamInformationSuccess( | ||||
|     PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); | ||||
| static NTSTATUS FspFsvolQueryInformation( | ||||
|     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||
| FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete; | ||||
| @@ -78,6 +85,9 @@ FSP_DRIVER_DISPATCH FspSetInformation; | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryNetworkOpenInformation) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryPositionInformation) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryStandardInformation) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryStreamInformationCopy) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryStreamInformation) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryStreamInformationSuccess) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryInformation) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryInformationComplete) | ||||
| #pragma alloc_text(PAGE, FspFsvolQueryInformationRequestFini) | ||||
| @@ -349,6 +359,197 @@ static NTSTATUS FspFsvolQueryStandardInformation(PFILE_OBJECT FileObject, | ||||
|     return STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| static NTSTATUS FspFsvolQueryStreamInformationCopy( | ||||
|     FSP_FSCTL_STREAM_INFO *StreamInfo, ULONG StreamInfoSize, | ||||
|     PVOID DestBuf, PULONG PDestLen) | ||||
| { | ||||
| #define FILL_INFO()\ | ||||
|     do\ | ||||
|     {\ | ||||
|         FILE_STREAM_INFORMATION InfoStruct = { 0 }, *Info = &InfoStruct;\ | ||||
|         Info->NextEntryOffset = 0;\ | ||||
|         Info->StreamNameLength = StreamNameLength;\ | ||||
|         Info->StreamSize.QuadPart = StreamInfo->StreamSize;\ | ||||
|         Info->StreamAllocationSize.QuadPart = StreamInfo->StreamAllocationSize;\ | ||||
|         Info = DestBuf;\ | ||||
|         RtlCopyMemory(Info, &InfoStruct, FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName));\ | ||||
|         RtlCopyMemory(Info->StreamName, StreamInfo->StreamNameBuf, StreamNameLength);\ | ||||
|     } while (0,0) | ||||
|  | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     NTSTATUS Result = STATUS_SUCCESS; | ||||
|     PUINT8 StreamInfoEnd = (PUINT8)StreamInfo + StreamInfoSize; | ||||
|     PUINT8 DestBufBgn = (PUINT8)DestBuf; | ||||
|     PUINT8 DestBufEnd = (PUINT8)DestBuf + *PDestLen; | ||||
|     PVOID PrevDestBuf = 0; | ||||
|     ULONG StreamNameLength; | ||||
|     ULONG BaseInfoLen = FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamName); | ||||
|  | ||||
|     *PDestLen = 0; | ||||
|  | ||||
|     for (; | ||||
|         NT_SUCCESS(Result) && (PUINT8)StreamInfo + sizeof(StreamInfo->Size) <= StreamInfoEnd; | ||||
|         StreamInfo = (PVOID)((PUINT8)StreamInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(StreamInfoSize))) | ||||
|     { | ||||
|         StreamInfoSize = StreamInfo->Size; | ||||
|  | ||||
|         if (sizeof(FSP_FSCTL_STREAM_INFO) > StreamInfoSize) | ||||
|             break; | ||||
|  | ||||
|         if ((PUINT8)DestBuf + BaseInfoLen > DestBufEnd) | ||||
|         { | ||||
|             if (0 == *PDestLen) | ||||
|                 /* if we haven't copied anything yet, buffer is too small */ | ||||
|                 return STATUS_BUFFER_TOO_SMALL; | ||||
|             else | ||||
|                 /* *PDestLen contains bytes copied so far */ | ||||
|                 return STATUS_BUFFER_OVERFLOW; | ||||
|         } | ||||
|  | ||||
|         StreamNameLength = StreamInfoSize - sizeof(FSP_FSCTL_STREAM_INFO); | ||||
|  | ||||
|         if ((PUINT8)DestBuf + BaseInfoLen + StreamNameLength > DestBufEnd) | ||||
|         { | ||||
|             /* only copy as much of the stream name as we can and return STATUS_BUFFER_OVERFLOW */ | ||||
|             StreamNameLength = (ULONG)(DestBufEnd - ((PUINT8)DestBuf + BaseInfoLen)); | ||||
|             Result = STATUS_BUFFER_OVERFLOW; | ||||
|         } | ||||
|  | ||||
|         /* fill in NextEntryOffset */ | ||||
|         if (0 != PrevDestBuf) | ||||
|             *(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf); | ||||
|         PrevDestBuf = DestBuf; | ||||
|  | ||||
|         FILL_INFO(); | ||||
|  | ||||
|         /* bytes copied so far */ | ||||
|         *PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + StreamNameLength - DestBufBgn); | ||||
|  | ||||
|         /* advance DestBuf; make sure to align properly! */ | ||||
|         DestBuf = (PVOID)((PUINT8)DestBuf + | ||||
|             FSP_FSCTL_ALIGN_UP(BaseInfoLen + StreamNameLength, sizeof(LONGLONG))); | ||||
|     } | ||||
|  | ||||
|     return Result; | ||||
|  | ||||
| #undef FILL_INFO | ||||
| } | ||||
|  | ||||
| static NTSTATUS FspFsvolQueryStreamInformation( | ||||
|     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     FSP_FILE_DESC *FileDesc = FileObject->FsContext2; | ||||
|     PVOID Buffer = Irp->AssociatedIrp.SystemBuffer; | ||||
|     ULONG Length = IrpSp->Parameters.QueryFile.Length; | ||||
|     PVOID StreamInfoBuffer; | ||||
|     ULONG StreamInfoBufferSize; | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request; | ||||
|  | ||||
|     ASSERT(FileNode == FileDesc->FileNode); | ||||
|  | ||||
|     FspFileNodeAcquireShared(FileNode, Main); | ||||
|     if (FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize)) | ||||
|     { | ||||
|         FspFileNodeRelease(FileNode, Main); | ||||
|  | ||||
|         Result = FspFsvolQueryStreamInformationCopy( | ||||
|             StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length); | ||||
|  | ||||
|         FspFileNodeDereferenceStreamInfo(StreamInfoBuffer); | ||||
|  | ||||
|         Irp->IoStatus.Information = Length; | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     FspFileNodeAcquireShared(FileNode, Pgio); | ||||
|  | ||||
|     Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolQueryInformationRequestFini, &Request); | ||||
|     if (!NT_SUCCESS(Result)) | ||||
|     { | ||||
|         FspFileNodeRelease(FileNode, Full); | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     Request->Kind = FspFsctlTransactQueryStreamInformationKind; | ||||
|     Request->Req.QueryStreamInformation.UserContext = FileNode->UserContext; | ||||
|     Request->Req.QueryStreamInformation.UserContext2 = FileDesc->UserContext2; | ||||
|  | ||||
|     FspFileNodeSetOwner(FileNode, Full, Request); | ||||
|     FspIopRequestContext(Request, RequestFileNode) = FileNode; | ||||
|  | ||||
|     return FSP_STATUS_IOQ_POST; | ||||
| } | ||||
|  | ||||
| static NTSTATUS FspFsvolQueryStreamInformationSuccess( | ||||
|     PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     PVOID Buffer = Irp->AssociatedIrp.SystemBuffer; | ||||
|     ULONG Length = IrpSp->Parameters.QueryFile.Length; | ||||
|     PVOID StreamInfoBuffer = 0; | ||||
|     ULONG StreamInfoBufferSize = 0; | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); | ||||
|     BOOLEAN Success; | ||||
|  | ||||
|     if (0 != FspIopRequestContext(Request, RequestFileNode)) | ||||
|     { | ||||
|         /* check that the stream info we got back is valid */ | ||||
|         if (Response->Buffer + Response->Rsp.QueryStreamInformation.Buffer.Size > | ||||
|             (PUINT8)Response + Response->Size) | ||||
|         { | ||||
|             Irp->IoStatus.Information = 0; | ||||
|             return STATUS_INFO_LENGTH_MISMATCH; /* ???: what is the best code to return here? */ | ||||
|         } | ||||
|  | ||||
|         FspIopRequestContext(Request, RequestInfoChangeNumber) = (PVOID)FileNode->StreamInfoChangeNumber; | ||||
|         FspIopRequestContext(Request, RequestFileNode) = 0; | ||||
|  | ||||
|         FspFileNodeReleaseOwner(FileNode, Full, Request); | ||||
|     } | ||||
|  | ||||
|     Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Main); | ||||
|     if (!Success) | ||||
|     { | ||||
|         FspIopRetryCompleteIrp(Irp, Response, &Result); | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     Success = !FspFileNodeTrySetStreamInfo(FileNode, | ||||
|         Response->Buffer, Response->Rsp.QueryStreamInformation.Buffer.Size, | ||||
|         (ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestInfoChangeNumber)); | ||||
|     Success = Success && | ||||
|         FspFileNodeReferenceStreamInfo(FileNode, &StreamInfoBuffer, &StreamInfoBufferSize); | ||||
|     FspFileNodeRelease(FileNode, Main); | ||||
|     if (Success) | ||||
|     { | ||||
|         Result = FspFsvolQueryStreamInformationCopy( | ||||
|             StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length); | ||||
|         FspFileNodeDereferenceStreamInfo(StreamInfoBuffer); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         StreamInfoBuffer = (PVOID)Response->Buffer; | ||||
|         StreamInfoBufferSize = Response->Rsp.QueryStreamInformation.Buffer.Size; | ||||
|         Result = FspFsvolQueryStreamInformationCopy( | ||||
|             StreamInfoBuffer, StreamInfoBufferSize, Buffer, &Length); | ||||
|     } | ||||
|  | ||||
|     Irp->IoStatus.Information = Length; | ||||
|  | ||||
|     return Result; | ||||
| } | ||||
|  | ||||
| static NTSTATUS FspFsvolQueryInformation( | ||||
|     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||
| { | ||||
| @@ -358,8 +559,13 @@ static NTSTATUS FspFsvolQueryInformation( | ||||
|     if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext)) | ||||
|         return STATUS_INVALID_DEVICE_REQUEST; | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass; | ||||
|  | ||||
|     /* special case FileStreamInformation */ | ||||
|     if (FileStreamInformation == FileInformationClass) | ||||
|         return FspFsvolQueryStreamInformation(FsvolDeviceObject, Irp, IrpSp); | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     FSP_FILE_DESC *FileDesc = FileObject->FsContext2; | ||||
| @@ -415,9 +621,6 @@ static NTSTATUS FspFsvolQueryInformation( | ||||
|     case FileStandardInformation: | ||||
|         Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0); | ||||
|         break; | ||||
|     case FileStreamInformation: | ||||
|         Result = STATUS_INVALID_PARAMETER;  /* !!!: no stream support yet! */ | ||||
|         return Result; | ||||
|     default: | ||||
|         Result = STATUS_INVALID_PARAMETER; | ||||
|         return Result; | ||||
| @@ -496,6 +699,11 @@ NTSTATUS FspFsvolQueryInformationComplete( | ||||
|     } | ||||
|  | ||||
|     FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass; | ||||
|  | ||||
|     /* special case FileStreamInformation */ | ||||
|     if (FileStreamInformation == FileInformationClass) | ||||
|         FSP_RETURN(Result = FspFsvolQueryStreamInformationSuccess(Irp, Response)); | ||||
|  | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     PVOID Buffer = Irp->AssociatedIrp.SystemBuffer; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user