mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48:38 -05:00 
			
		
		
		
	sys: IRP_MJ_QUERY_INFORMATION: FileStreamInformation
This commit is contained in:
		| @@ -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