mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48:38 -05:00 
			
		
		
		
	sys: IRP_MJ_WRITE: implementation
This commit is contained in:
		| @@ -61,6 +61,10 @@ VOID FspAcquireFileForNtCreateSection( | ||||
| { | ||||
|     FSP_ENTER_VOID(PAGED_CODE()); | ||||
|  | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|  | ||||
|     FspFileNodeAcquireExclusive(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE_VOID("FileObject=%p", FileObject); | ||||
| } | ||||
|  | ||||
| @@ -69,6 +73,10 @@ VOID FspReleaseFileForNtCreateSection( | ||||
| { | ||||
|     FSP_ENTER_VOID(PAGED_CODE()); | ||||
|  | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|  | ||||
|     FspFileNodeRelease(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE_VOID("FileObject=%p", FileObject); | ||||
| } | ||||
|  | ||||
| @@ -80,7 +88,10 @@ NTSTATUS FspAcquireForModWrite( | ||||
| { | ||||
|     FSP_ENTER(PAGED_CODE()); | ||||
|  | ||||
|     Result = STATUS_NOT_IMPLEMENTED; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|  | ||||
|     FspFileNodeAcquireExclusive(FileNode, Full); | ||||
|     *ResourceToRelease = 0; | ||||
|  | ||||
|     FSP_LEAVE("FileObject=%p", FileObject); | ||||
| } | ||||
| @@ -92,7 +103,9 @@ NTSTATUS FspReleaseForModWrite( | ||||
| { | ||||
|     FSP_ENTER(PAGED_CODE()); | ||||
|  | ||||
|     Result = STATUS_NOT_IMPLEMENTED; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|  | ||||
|     FspFileNodeRelease(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE("FileObject=%p", FileObject); | ||||
| } | ||||
| @@ -103,7 +116,9 @@ NTSTATUS FspAcquireForCcFlush( | ||||
| { | ||||
|     FSP_ENTER(PAGED_CODE()); | ||||
|  | ||||
|     Result = STATUS_NOT_IMPLEMENTED; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|  | ||||
|     FspFileNodeAcquireExclusive(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE("FileObject=%p", FileObject); | ||||
| } | ||||
| @@ -114,7 +129,9 @@ NTSTATUS FspReleaseForCcFlush( | ||||
| { | ||||
|     FSP_ENTER(PAGED_CODE()); | ||||
|  | ||||
|     Result = STATUS_NOT_IMPLEMENTED; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|  | ||||
|     FspFileNodeRelease(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE("FileObject=%p", FileObject); | ||||
| } | ||||
| @@ -125,7 +142,9 @@ BOOLEAN FspAcquireForLazyWrite( | ||||
| { | ||||
|     FSP_ENTER_BOOL(PAGED_CODE()); | ||||
|  | ||||
|     Result = FALSE; | ||||
|     FSP_FILE_NODE *FileNode = Context; | ||||
|  | ||||
|     FspFileNodeAcquireExclusive(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE_BOOL("Context=%p, Wait=%d", Context, Wait); | ||||
| } | ||||
| @@ -135,6 +154,10 @@ VOID FspReleaseFromLazyWrite( | ||||
| { | ||||
|     FSP_ENTER_VOID(PAGED_CODE()); | ||||
|  | ||||
|     FSP_FILE_NODE *FileNode = Context; | ||||
|  | ||||
|     FspFileNodeRelease(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE_VOID("Context=%p", Context); | ||||
| } | ||||
|  | ||||
| @@ -144,7 +167,9 @@ BOOLEAN FspAcquireForReadAhead( | ||||
| { | ||||
|     FSP_ENTER_BOOL(PAGED_CODE()); | ||||
|  | ||||
|     Result = FALSE; | ||||
|     FSP_FILE_NODE *FileNode = Context; | ||||
|  | ||||
|     FspFileNodeAcquireShared(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE_BOOL("Context=%p, Wait=%d", Context, Wait); | ||||
| } | ||||
| @@ -154,5 +179,9 @@ VOID FspReleaseFromReadAhead( | ||||
| { | ||||
|     FSP_ENTER_VOID(PAGED_CODE()); | ||||
|  | ||||
|     FSP_FILE_NODE *FileNode = Context; | ||||
|  | ||||
|     FspFileNodeRelease(FileNode, Full); | ||||
|  | ||||
|     FSP_LEAVE_VOID("Context=%p", Context); | ||||
| } | ||||
|   | ||||
| @@ -61,7 +61,9 @@ static NTSTATUS FspFsvolCleanup( | ||||
|  | ||||
|     ASSERT(FileNode == FileDesc->FileNode); | ||||
|  | ||||
|     /* !!!: REVISIT! */ | ||||
|     FspFileNodeClose(FileNode, FileObject, &DeletePending); | ||||
|     CcUninitializeCacheMap(FileObject, 0, 0); | ||||
|  | ||||
|     /* | ||||
|      * If DeletePending is TRUE, the FileNode is no longer in the Context table, | ||||
|   | ||||
| @@ -583,6 +583,10 @@ NTSTATUS FspFsvolCreateComplete( | ||||
|         FileObject->PrivateCacheMap = 0; | ||||
|         FileObject->FsContext = FileNode; | ||||
|         FileObject->FsContext2 = FileDesc; | ||||
|         if (FspTimeoutInfinity32 == FsvolDeviceExtension->VolumeParams.FileInfoTimeout && | ||||
|             !FlagOn(IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING)) | ||||
|             /* enable caching! */ | ||||
|             SetFlag(FileObject->Flags, FO_CACHE_SUPPORTED); | ||||
|  | ||||
|         if (FILE_SUPERSEDED != Response->IoStatus.Information && | ||||
|             FILE_OVERWRITTEN != Response->IoStatus.Information) | ||||
|   | ||||
| @@ -93,8 +93,8 @@ NTSTATUS DriverEntry( | ||||
|     /* setup fast I/O and resource acquisition */ | ||||
|     FspFastIoDispatch.SizeOfFastIoDispatch = sizeof FspFastIoDispatch; | ||||
|     FspFastIoDispatch.FastIoCheckIfPossible = FspFastIoCheckIfPossible; | ||||
|     FspFastIoDispatch.FastIoRead = FsRtlCopyRead; | ||||
|     FspFastIoDispatch.FastIoWrite = FsRtlCopyWrite; | ||||
|     //FspFastIoDispatch.FastIoRead = 0; | ||||
|     //FspFastIoDispatch.FastIoWrite = 0; | ||||
|     //FspFastIoDispatch.FastIoQueryBasicInfo = 0; | ||||
|     //FspFastIoDispatch.FastIoQueryStandardInfo = 0; | ||||
|     //FspFastIoDispatch.FastIoLock = 0; | ||||
| @@ -107,10 +107,10 @@ NTSTATUS DriverEntry( | ||||
|     //FspFastIoDispatch.FastIoDetachDevice = 0; | ||||
|     //FspFastIoDispatch.FastIoQueryNetworkOpenInfo = 0; | ||||
|     FspFastIoDispatch.AcquireForModWrite = FspAcquireForModWrite; | ||||
|     FspFastIoDispatch.MdlRead = FsRtlMdlReadDev; | ||||
|     FspFastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev; | ||||
|     FspFastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev; | ||||
|     FspFastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev; | ||||
|     //FspFastIoDispatch.MdlRead = 0; | ||||
|     //FspFastIoDispatch.MdlReadComplete = 0; | ||||
|     //FspFastIoDispatch.PrepareMdlWrite = 0; | ||||
|     //FspFastIoDispatch.MdlWriteComplete = 0; | ||||
|     //FspFastIoDispatch.FastIoReadCompressed = 0; | ||||
|     //FspFastIoDispatch.FastIoWriteCompressed = 0; | ||||
|     //FspFastIoDispatch.MdlReadCompleteCompressed = 0; | ||||
|   | ||||
| @@ -273,6 +273,7 @@ FSP_IOPREP_DISPATCH FspFsvolSetSecurityPrepare; | ||||
| FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete; | ||||
| FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete; | ||||
| FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete; | ||||
| FSP_IOPREP_DISPATCH FspFsvolWritePrepare; | ||||
| FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; | ||||
|  | ||||
| /* fast I/O and resource acquisition callbacks */ | ||||
| @@ -378,13 +379,18 @@ VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE | ||||
| NTSTATUS FspCreateGuid(GUID *Guid); | ||||
| NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, | ||||
|     KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl); | ||||
| NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress); | ||||
| NTSTATUS FspCcInitializeCacheMap(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes, | ||||
|     BOOLEAN PinAccess, PCACHE_MANAGER_CALLBACKS Callbacks, PVOID CallbackContext); | ||||
| NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes); | ||||
| NTSTATUS FspCcCopyWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, | ||||
|     BOOLEAN Wait, PVOID Buffer); | ||||
| NTSTATUS FspCcPrepareMdlWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, | ||||
|     PMDL *PMdlChain, PIO_STATUS_BLOCK IoStatus); | ||||
| NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain); | ||||
| NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, | ||||
|     PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, | ||||
|     PSECURITY_DESCRIPTOR ObjectsSecurityDescriptor); | ||||
| #define FspSetTopLevelIrp(Irp)          (IoGetTopLevelIrp() ? FALSE : (IoSetTopLevelIrp(Irp), TRUE)) | ||||
| #define FspResetTopLevelIrp(TopLevel)   ((TopLevel) ? IoSetTopLevelIrp(0) : (void)0) | ||||
|  | ||||
| /* utility: synchronous work queue */ | ||||
| typedef struct | ||||
| @@ -409,6 +415,19 @@ VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, | ||||
|     PWORKER_THREAD_ROUTINE Routine, PVOID Context); | ||||
| VOID FspQueueDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, LARGE_INTEGER Delay); | ||||
|  | ||||
| /* utility: safe MDL */ | ||||
| typedef struct | ||||
| { | ||||
|     PMDL Mdl; | ||||
|     PVOID Buffer; | ||||
|     PMDL UserMdl; | ||||
|     LOCK_OPERATION Operation; | ||||
| } FSP_SAFE_MDL; | ||||
| BOOLEAN FspSafeMdlCheck(PMDL Mdl); | ||||
| NTSTATUS FspSafeMdlCreate(PMDL UserMdl, LOCK_OPERATION Operation, FSP_SAFE_MDL **PSafeMdl); | ||||
| VOID FspSafeMdlCopyBack(FSP_SAFE_MDL *SafeMdl); | ||||
| VOID FspSafeMdlDelete(FSP_SAFE_MDL *SafeMdl); | ||||
|  | ||||
| /* IRP context */ | ||||
| #define FspIrpTimestampInfinity         ((ULONG)-1L) | ||||
| #define FspIrpTimestamp(Irp)            \ | ||||
|   | ||||
							
								
								
									
										316
									
								
								src/sys/util.c
									
									
									
									
									
								
							
							
						
						
									
										316
									
								
								src/sys/util.c
									
									
									
									
									
								
							| @@ -11,7 +11,14 @@ VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE | ||||
| NTSTATUS FspCreateGuid(GUID *Guid); | ||||
| NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, | ||||
|     KPROCESSOR_MODE RequestorMode, LOCK_OPERATION Operation, PMDL *PMdl); | ||||
| NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress); | ||||
| NTSTATUS FspCcInitializeCacheMap(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes, | ||||
|     BOOLEAN PinAccess, PCACHE_MANAGER_CALLBACKS Callbacks, PVOID CallbackContext); | ||||
| NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes); | ||||
| NTSTATUS FspCcCopyWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, | ||||
|     BOOLEAN Wait, PVOID Buffer); | ||||
| NTSTATUS FspCcPrepareMdlWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, | ||||
|     PMDL *PMdlChain, PIO_STATUS_BLOCK IoStatus); | ||||
| NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain); | ||||
| NTSTATUS FspQuerySecurityDescriptorInfo(SECURITY_INFORMATION SecurityInformation, | ||||
|     PSECURITY_DESCRIPTOR SecurityDescriptor, PULONG PLength, | ||||
| @@ -24,13 +31,21 @@ VOID FspInitializeDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, | ||||
|     PWORKER_THREAD_ROUTINE Routine, PVOID Context); | ||||
| VOID FspQueueDelayedWorkItem(FSP_DELAYED_WORK_ITEM *DelayedWorkItem, LARGE_INTEGER Delay); | ||||
| static KDEFERRED_ROUTINE FspQueueDelayedWorkItemDPC; | ||||
| BOOLEAN FspSafeMdlCheck(PMDL Mdl); | ||||
| NTSTATUS FspSafeMdlCreate(PMDL UserMdl, LOCK_OPERATION Operation, FSP_SAFE_MDL **PSafeMdl); | ||||
| VOID FspSafeMdlCopyBack(FSP_SAFE_MDL *SafeMdl); | ||||
| VOID FspSafeMdlDelete(FSP_SAFE_MDL *SafeMdl); | ||||
|  | ||||
| #ifdef ALLOC_PRAGMA | ||||
| #pragma alloc_text(PAGE, FspUnicodePathIsValid) | ||||
| #pragma alloc_text(PAGE, FspUnicodePathSuffix) | ||||
| #pragma alloc_text(PAGE, FspCreateGuid) | ||||
| #pragma alloc_text(PAGE, FspLockUserBuffer) | ||||
| #pragma alloc_text(PAGE, FspMapLockedPagesInUserMode) | ||||
| #pragma alloc_text(PAGE, FspCcInitializeCacheMap) | ||||
| #pragma alloc_text(PAGE, FspCcSetFileSizes) | ||||
| #pragma alloc_text(PAGE, FspCcCopyWrite) | ||||
| #pragma alloc_text(PAGE, FspCcPrepareMdlWrite) | ||||
| #pragma alloc_text(PAGE, FspCcMdlWriteComplete) | ||||
| #pragma alloc_text(PAGE, FspQuerySecurityDescriptorInfo) | ||||
| #pragma alloc_text(PAGE, FspInitializeSynchronousWorkItem) | ||||
| @@ -38,6 +53,10 @@ static KDEFERRED_ROUTINE FspQueueDelayedWorkItemDPC; | ||||
| #pragma alloc_text(PAGE, FspExecuteSynchronousWorkItemRoutine) | ||||
| #pragma alloc_text(PAGE, FspInitializeDelayedWorkItem) | ||||
| #pragma alloc_text(PAGE, FspQueueDelayedWorkItem) | ||||
| #pragma alloc_text(PAGE, FspSafeMdlCheck) | ||||
| #pragma alloc_text(PAGE, FspSafeMdlCreate) | ||||
| #pragma alloc_text(PAGE, FspSafeMdlCopyBack) | ||||
| #pragma alloc_text(PAGE, FspSafeMdlDelete) | ||||
| #endif | ||||
|  | ||||
| static const LONG Delays[] = | ||||
| @@ -183,6 +202,38 @@ NTSTATUS FspLockUserBuffer(PVOID UserBuffer, ULONG Length, | ||||
|     return STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| NTSTATUS FspMapLockedPagesInUserMode(PMDL Mdl, PVOID *PAddress) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     try | ||||
|     { | ||||
|         *PAddress = MmMapLockedPagesSpecifyCache(Mdl, UserMode, MmCached, 0, FALSE, NormalPagePriority); | ||||
|         return 0 != *PAddress ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; | ||||
|     } | ||||
|     except (EXCEPTION_EXECUTE_HANDLER) | ||||
|     { | ||||
|         *PAddress = 0; | ||||
|         return GetExceptionCode(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| NTSTATUS FspCcInitializeCacheMap(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes, | ||||
|     BOOLEAN PinAccess, PCACHE_MANAGER_CALLBACKS Callbacks, PVOID CallbackContext) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     try | ||||
|     { | ||||
|         CcInitializeCacheMap(FileObject, FileSizes, PinAccess, Callbacks, CallbackContext); | ||||
|         return STATUS_SUCCESS; | ||||
|     } | ||||
|     except (EXCEPTION_EXECUTE_HANDLER) | ||||
|     { | ||||
|         return GetExceptionCode(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
| @@ -198,6 +249,56 @@ NTSTATUS FspCcSetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes) | ||||
|     } | ||||
| } | ||||
|  | ||||
| NTSTATUS FspCcCopyWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, | ||||
|     BOOLEAN Wait, PVOID Buffer) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     try | ||||
|     { | ||||
|         BOOLEAN Success = CcCopyWrite(FileObject, FileOffset, Length, Wait, Buffer); | ||||
|         return Success ? STATUS_SUCCESS : STATUS_PENDING; | ||||
|     } | ||||
|     except (EXCEPTION_EXECUTE_HANDLER) | ||||
|     { | ||||
|         return GetExceptionCode(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| NTSTATUS FspCcPrepareMdlWrite(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, | ||||
|     PMDL *PMdlChain, PIO_STATUS_BLOCK IoStatus) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|  | ||||
|     *PMdlChain = 0; | ||||
|  | ||||
|     try | ||||
|     { | ||||
|         CcPrepareMdlWrite(FileObject, FileOffset, Length, PMdlChain, IoStatus); | ||||
|         Result = IoStatus->Status; | ||||
|     } | ||||
|     except(EXCEPTION_EXECUTE_HANDLER) | ||||
|     { | ||||
|         Result = GetExceptionCode(); | ||||
|     } | ||||
|  | ||||
|     if (!NT_SUCCESS(Result)) | ||||
|     { | ||||
|         if (0 != *PMdlChain) | ||||
|         { | ||||
|             CcMdlWriteAbort(FileObject, *PMdlChain); | ||||
|             *PMdlChain = 0; | ||||
|         } | ||||
|  | ||||
|         IoStatus->Information = 0; | ||||
|         IoStatus->Status = Result; | ||||
|     } | ||||
|  | ||||
|     return Result; | ||||
| } | ||||
|  | ||||
| NTSTATUS FspCcMdlWriteComplete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
| @@ -293,3 +394,218 @@ static VOID FspQueueDelayedWorkItemDPC(PKDPC Dpc, | ||||
|  | ||||
|     ExQueueWorkItem(&DelayedWorkItem->WorkQueueItem, DelayedWorkQueue); | ||||
| } | ||||
|  | ||||
| BOOLEAN FspSafeMdlCheck(PMDL Mdl) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     PVOID VirtualAddress = MmGetMdlVirtualAddress(Mdl); | ||||
|     ULONG ByteCount = MmGetMdlByteCount(Mdl); | ||||
|  | ||||
|     return 0 == BYTE_OFFSET(VirtualAddress) && 0 == BYTE_OFFSET(ByteCount); | ||||
| } | ||||
|  | ||||
| NTSTATUS FspSafeMdlCreate(PMDL UserMdl, LOCK_OPERATION Operation, FSP_SAFE_MDL **PSafeMdl) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     PVOID VirtualAddress = MmGetMdlVirtualAddress(UserMdl); | ||||
|     ULONG ByteCount = MmGetMdlByteCount(UserMdl); | ||||
|     ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, ByteCount); | ||||
|     FSP_SAFE_MDL *SafeMdl; | ||||
|     PMDL TempMdl; | ||||
|     PPFN_NUMBER UserPfnArray, SafePfnArray, TempPfnArray; | ||||
|     ULONG ByteOffsetBgn0, ByteOffsetEnd0, ByteOffsetEnd1; | ||||
|     BOOLEAN Buffer0, Buffer1; | ||||
|     ULONG BufferPageCount; | ||||
|  | ||||
|     ASSERT(0 != PageCount); | ||||
|  | ||||
|     *PSafeMdl = 0; | ||||
|  | ||||
|     SafeMdl = FspAllocNonPaged(sizeof *SafeMdl); | ||||
|     if (0 == SafeMdl) | ||||
|     { | ||||
|         Result = STATUS_INSUFFICIENT_RESOURCES; | ||||
|         goto exit; | ||||
|     } | ||||
|     RtlZeroMemory(SafeMdl, sizeof *SafeMdl); | ||||
|  | ||||
|     SafeMdl->Mdl = IoAllocateMdl(VirtualAddress, ByteCount, FALSE, FALSE, 0); | ||||
|     if (0 == SafeMdl->Mdl) | ||||
|     { | ||||
|         Result = STATUS_INSUFFICIENT_RESOURCES; | ||||
|         goto exit; | ||||
|     } | ||||
|     UserPfnArray = MmGetMdlPfnArray(UserMdl); | ||||
|     SafePfnArray = MmGetMdlPfnArray(SafeMdl->Mdl); | ||||
|     RtlCopyMemory(SafePfnArray, UserPfnArray, PageCount * sizeof(PFN_NUMBER)); | ||||
|  | ||||
|     /* | ||||
|      * Possible cases: | ||||
|      * | ||||
|      * ----+---------+---------+---- | ||||
|      * | ||||
|      *     *---------*         + | ||||
|      *     +    *----*         + | ||||
|      *     *----*    +         + | ||||
|      *     +  *---*  +         + | ||||
|      *     *--------...--------* | ||||
|      *     +    *---...--------* | ||||
|      *     *--------...---*    + | ||||
|      *     +    *---...---*    + | ||||
|      */ | ||||
|     if (1 == PageCount) | ||||
|     { | ||||
|         ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress); | ||||
|         ByteOffsetEnd0 = BYTE_OFFSET(ByteCount + (PAGE_SIZE - 1)); | ||||
|         ByteOffsetEnd1 = 0; | ||||
|         Buffer0 = 0 != ByteOffsetBgn0 || PAGE_SIZE != ByteOffsetEnd0; | ||||
|         Buffer1 = FALSE; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress); | ||||
|         ByteOffsetEnd0 = PAGE_SIZE; | ||||
|         ByteOffsetEnd1 = BYTE_OFFSET((PUINT8)VirtualAddress + ByteCount + (PAGE_SIZE - 1)); | ||||
|         Buffer0 = 0 != ByteOffsetBgn0; | ||||
|         Buffer1 = PAGE_SIZE != ByteOffsetEnd1; | ||||
|     } | ||||
|     BufferPageCount = Buffer0 + Buffer1; | ||||
|  | ||||
|     if (0 < BufferPageCount) | ||||
|     { | ||||
|         SafeMdl->Buffer = FspAllocNonPaged(PAGE_SIZE * BufferPageCount); | ||||
|         if (0 == SafeMdl->Buffer) | ||||
|         { | ||||
|             Result = STATUS_INSUFFICIENT_RESOURCES; | ||||
|             goto exit; | ||||
|         } | ||||
|  | ||||
|         TempMdl = IoAllocateMdl(SafeMdl->Buffer, PAGE_SIZE * BufferPageCount, FALSE, FALSE, 0); | ||||
|         if (0 == TempMdl) | ||||
|         { | ||||
|             Result = STATUS_INSUFFICIENT_RESOURCES; | ||||
|             goto exit; | ||||
|         } | ||||
|  | ||||
|         MmBuildMdlForNonPagedPool(TempMdl); | ||||
|  | ||||
|         TempPfnArray = MmGetMdlPfnArray(SafeMdl); | ||||
|         if (IoReadAccess == Operation) | ||||
|         { | ||||
|             if (Buffer0) | ||||
|             { | ||||
|                 RtlZeroMemory((PUINT8)SafeMdl->Buffer, ByteOffsetBgn0); | ||||
|                 RtlCopyMemory((PUINT8)SafeMdl->Buffer + ByteOffsetBgn0, | ||||
|                     (PUINT8)VirtualAddress + ByteOffsetBgn0, ByteOffsetEnd0 - ByteOffsetBgn0); | ||||
|                 RtlZeroMemory((PUINT8)SafeMdl->Buffer + ByteOffsetEnd0, PAGE_SIZE - ByteOffsetEnd0); | ||||
|                 UserPfnArray[0] = TempPfnArray[0]; | ||||
|             } | ||||
|             if (Buffer1) | ||||
|             { | ||||
|                 RtlCopyMemory((PUINT8)SafeMdl->Buffer + (BufferPageCount - 1) * PAGE_SIZE, | ||||
|                     (PUINT8)VirtualAddress + (PageCount - 1) * PAGE_SIZE, ByteOffsetEnd1); | ||||
|                 RtlZeroMemory((PUINT8)SafeMdl->Buffer + (BufferPageCount - 1) * PAGE_SIZE + ByteOffsetEnd1, | ||||
|                     PAGE_SIZE - ByteOffsetEnd1); | ||||
|                 UserPfnArray[PageCount - 1] = TempPfnArray[BufferPageCount - 1]; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             RtlZeroMemory((PUINT8)SafeMdl->Buffer, PAGE_SIZE * BufferPageCount); | ||||
|             if (Buffer0) | ||||
|                 UserPfnArray[0] = TempPfnArray[0]; | ||||
|             if (Buffer1) | ||||
|                 UserPfnArray[PageCount - 1] = TempPfnArray[BufferPageCount - 1]; | ||||
|         } | ||||
|  | ||||
|         IoFreeMdl(TempMdl); | ||||
|     } | ||||
|  | ||||
|     SafeMdl->UserMdl = UserMdl; | ||||
|     *PSafeMdl = SafeMdl; | ||||
|  | ||||
|     Result = STATUS_SUCCESS; | ||||
|  | ||||
| exit: | ||||
|     if (!NT_SUCCESS(Result) && 0 != SafeMdl) | ||||
|     { | ||||
|         if (0 != SafeMdl->Buffer) | ||||
|             FspFree(SafeMdl->Buffer); | ||||
|         if (0 != SafeMdl->Mdl) | ||||
|             IoFreeMdl(SafeMdl->Mdl); | ||||
|         FspFree(SafeMdl); | ||||
|     } | ||||
|  | ||||
|     return Result; | ||||
| } | ||||
|  | ||||
| VOID FspSafeMdlCopyBack(FSP_SAFE_MDL *SafeMdl) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     if (IoReadAccess == SafeMdl->Operation) | ||||
|         return; | ||||
|  | ||||
|     PVOID VirtualAddress = MmGetMdlVirtualAddress(SafeMdl->UserMdl); | ||||
|     ULONG ByteCount = MmGetMdlByteCount(SafeMdl->UserMdl); | ||||
|     ULONG PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, ByteCount); | ||||
|     ULONG ByteOffsetBgn0, ByteOffsetEnd0, ByteOffsetEnd1; | ||||
|     BOOLEAN Buffer0, Buffer1; | ||||
|     ULONG BufferPageCount; | ||||
|  | ||||
|     /* | ||||
|      * Possible cases: | ||||
|      * | ||||
|      * ----+---------+---------+---- | ||||
|      * | ||||
|      *     *---------*         + | ||||
|      *     +    *----*         + | ||||
|      *     *----*    +         + | ||||
|      *     +  *---*  +         + | ||||
|      *     *--------...--------* | ||||
|      *     +    *---...--------* | ||||
|      *     *--------...---*    + | ||||
|      *     +    *---...---*    + | ||||
|      */ | ||||
|     if (1 == PageCount) | ||||
|     { | ||||
|         ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress); | ||||
|         ByteOffsetEnd0 = BYTE_OFFSET(ByteCount + (PAGE_SIZE - 1)); | ||||
|         ByteOffsetEnd1 = 0; | ||||
|         Buffer0 = 0 != ByteOffsetBgn0 || PAGE_SIZE != ByteOffsetEnd0; | ||||
|         Buffer1 = FALSE; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ByteOffsetBgn0 = BYTE_OFFSET(VirtualAddress); | ||||
|         ByteOffsetEnd0 = PAGE_SIZE; | ||||
|         ByteOffsetEnd1 = BYTE_OFFSET((PUINT8)VirtualAddress + ByteCount + (PAGE_SIZE - 1)); | ||||
|         Buffer0 = 0 != ByteOffsetBgn0; | ||||
|         Buffer1 = PAGE_SIZE != ByteOffsetEnd1; | ||||
|     } | ||||
|     BufferPageCount = Buffer0 + Buffer1; | ||||
|  | ||||
|     if (0 < BufferPageCount) | ||||
|     { | ||||
|         if (Buffer0) | ||||
|             RtlCopyMemory((PUINT8)VirtualAddress + ByteOffsetBgn0, | ||||
|                 (PUINT8)SafeMdl->Buffer + ByteOffsetBgn0, ByteOffsetEnd0 - ByteOffsetBgn0); | ||||
|         if (Buffer1) | ||||
|             RtlCopyMemory((PUINT8)VirtualAddress + (PageCount - 1) * PAGE_SIZE, | ||||
|                 (PUINT8)SafeMdl->Buffer + (BufferPageCount - 1) * PAGE_SIZE, ByteOffsetEnd1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| VOID FspSafeMdlDelete(FSP_SAFE_MDL *SafeMdl) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     if (0 != SafeMdl->Buffer) | ||||
|         FspFree(SafeMdl->Buffer); | ||||
|     if (0 != SafeMdl->Mdl) | ||||
|         IoFreeMdl(SafeMdl->Mdl); | ||||
|     FspFree(SafeMdl); | ||||
| } | ||||
|   | ||||
							
								
								
									
										391
									
								
								src/sys/write.c
									
									
									
									
									
								
							
							
						
						
									
										391
									
								
								src/sys/write.c
									
									
									
									
									
								
							| @@ -14,7 +14,9 @@ static NTSTATUS FspFsvolWriteCached( | ||||
| static VOID FspFsvolWriteCachedDeferred(PVOID Context1, PVOID Context2); | ||||
| static NTSTATUS FspFsvolWriteNonCached( | ||||
|     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); | ||||
| FSP_IOPREP_DISPATCH FspFsvolWritePrepare; | ||||
| FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; | ||||
| static FSP_IOP_REQUEST_FINI FspFsvolWriteNonCachedRequestFini; | ||||
| FSP_DRIVER_DISPATCH FspWrite; | ||||
|  | ||||
| #ifdef ALLOC_PRAGMA | ||||
| @@ -22,10 +24,21 @@ FSP_DRIVER_DISPATCH FspWrite; | ||||
| #pragma alloc_text(PAGE, FspFsvolWriteCached) | ||||
| #pragma alloc_text(PAGE, FspFsvolWriteCachedDeferred) | ||||
| #pragma alloc_text(PAGE, FspFsvolWriteNonCached) | ||||
| #pragma alloc_text(PAGE, FspFsvolWritePrepare) | ||||
| #pragma alloc_text(PAGE, FspFsvolWriteComplete) | ||||
| #pragma alloc_text(PAGE, FspFsvolWriteNonCachedRequestFini) | ||||
| #pragma alloc_text(PAGE, FspWrite) | ||||
| #endif | ||||
|  | ||||
| enum | ||||
| { | ||||
|     /* WriteNonCached */ | ||||
|     RequestIrp                          = 0, | ||||
|     RequestSafeMdl                      = 1, | ||||
|     RequestAddress                      = 2, | ||||
|     RequestProcess                      = 3, | ||||
| }; | ||||
|  | ||||
| static NTSTATUS FspFsvolWrite( | ||||
|     PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) | ||||
| { | ||||
| @@ -36,49 +49,36 @@ static NTSTATUS FspFsvolWrite( | ||||
|         return STATUS_INVALID_DEVICE_REQUEST; | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     BOOLEAN TopLevel = FspSetTopLevelIrp(Irp); | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|  | ||||
|     /* is this an MDL complete request? */ | ||||
|     if (FlagOn(IrpSp->MinorFunction, IRP_MN_COMPLETE)) | ||||
|     { | ||||
|         Result = FspCcMdlWriteComplete(IrpSp->FileObject, | ||||
|         Result = FspCcMdlWriteComplete(FileObject, | ||||
|             &IrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress); | ||||
|         Irp->MdlAddress = 0; | ||||
|         goto exit; | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     /* only regular files can be written */ | ||||
|     if (((FSP_FILE_NODE *)IrpSp->FileObject->FsContext)->IsDirectory) | ||||
|     { | ||||
|         Result = STATUS_INVALID_PARAMETER; | ||||
|         goto exit; | ||||
|     } | ||||
|     if (FileNode->IsDirectory) | ||||
|         return STATUS_INVALID_PARAMETER; | ||||
|  | ||||
|     /* do we have anything to write? */ | ||||
|     if (0 == IrpSp->Parameters.Write.Length) | ||||
|     { | ||||
|         Irp->IoStatus.Information = 0; | ||||
|         Result = STATUS_SUCCESS; | ||||
|         goto exit; | ||||
|         return STATUS_SUCCESS; | ||||
|     } | ||||
|  | ||||
|     /* probe and lock the user buffer */ | ||||
|     if (0 == Irp->MdlAddress) | ||||
|     { | ||||
|         Result = FspLockUserBuffer(Irp->UserBuffer, IrpSp->Parameters.Write.Length, | ||||
|             Irp->RequestorMode, IoReadAccess, &Irp->MdlAddress); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|             goto exit; | ||||
|     } | ||||
|  | ||||
|     if (!FlagOn(Irp->Flags, IRP_PAGING_IO | IRP_NOCACHE)) | ||||
|     /* are we doing cached or non-cached I/O? */ | ||||
|     if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && | ||||
|         !FlagOn(Irp->Flags, IRP_PAGING_IO | IRP_NOCACHE)) | ||||
|         Result = FspFsvolWriteCached(FsvolDeviceObject, Irp, IrpSp, IoIsOperationSynchronous(Irp)); | ||||
|     else | ||||
|         Result = FspFsvolWriteNonCached(FsvolDeviceObject, Irp, IrpSp); | ||||
|  | ||||
| exit: | ||||
|     FspResetTopLevelIrp(TopLevel); | ||||
|  | ||||
|     return Result; | ||||
| } | ||||
|  | ||||
| @@ -89,32 +89,36 @@ static NTSTATUS FspFsvolWriteCached( | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     FSP_FSCTL_TRANSACT_REQ *RequestWorkItem = FspIrpRequest(Irp); | ||||
|     BOOLEAN Retrying = 0 != FspIrpRequest(Irp); | ||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     FSP_FILE_DESC *FileDesc = FileObject->FsContext2; | ||||
| #if 0 | ||||
|     ULONG WriteKey = IrpSp->Parameters.Write.Key; | ||||
|     LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset; | ||||
| #endif | ||||
|     ULONG WriteLength = IrpSp->Parameters.Write.Length; | ||||
| #if 0 | ||||
|     BOOLEAN WriteToEof = | ||||
|         FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; | ||||
|     /* !!!: lock support! */ | ||||
|     ULONG WriteKey = IrpSp->Parameters.Write.Key; | ||||
| #endif | ||||
|     BOOLEAN WriteToEndOfFile = | ||||
|         FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; | ||||
|     BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); | ||||
|     FSP_FSCTL_FILE_INFO FileInfo; | ||||
|     CC_FILE_SIZES FileSizes; | ||||
|     UINT64 WriteEndOffset; | ||||
|     BOOLEAN Success; | ||||
|  | ||||
|     ASSERT(FileNode == FileDesc->FileNode); | ||||
|  | ||||
|     /* should we defer the write? */ | ||||
|     if (DEBUGRANDTEST(10, TRUE) || | ||||
|         !CcCanIWrite(FileObject, WriteLength, CanWait, 0 != RequestWorkItem)) | ||||
|     Success = DEBUGRANDTEST(90, TRUE) && CcCanIWrite(FileObject, WriteLength, CanWait, Retrying); | ||||
|     if (!Success) | ||||
|     { | ||||
|         Result = FspWqCreateIrpWorkItem(Irp, FspFsvolWriteCached, 0); | ||||
|         if (NT_SUCCESS(Result)) | ||||
|         { | ||||
|             IoMarkIrpPending(Irp); | ||||
|             CcDeferWrite(FileObject, FspFsvolWriteCachedDeferred, Irp, 0, WriteLength, | ||||
|                 0 != RequestWorkItem); | ||||
|             CcDeferWrite(FileObject, FspFsvolWriteCachedDeferred, Irp, 0, WriteLength, Retrying); | ||||
|  | ||||
|             return STATUS_PENDING; | ||||
|         } | ||||
| @@ -122,7 +126,97 @@ static NTSTATUS FspFsvolWriteCached( | ||||
|         /* if we are unable to defer we will go ahead and (try to) service the IRP now! */ | ||||
|     } | ||||
|  | ||||
|     return STATUS_INVALID_DEVICE_REQUEST; | ||||
|     /* try to acquire the FileNode Main exclusive */ | ||||
|     Success = DEBUGRANDTEST(90, TRUE) && | ||||
|         FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireMain, CanWait); | ||||
|     if (!Success) | ||||
|         return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0); | ||||
|  | ||||
|     /* compute new file size and allocation size */ | ||||
|     ASSERT(FspTimeoutInfinity32 == FsvolDeviceExtension->VolumeParams.FileInfoTimeout); | ||||
|     FspFileNodeGetFileInfo(FileNode, &FileInfo); | ||||
|     FileSizes.AllocationSize.QuadPart = FileInfo.AllocationSize; | ||||
|     FileSizes.FileSize.QuadPart = FileInfo.FileSize; | ||||
|     FileSizes.ValidDataLength.QuadPart = MAXLONGLONG; | ||||
|     WriteEndOffset = WriteToEndOfFile ? | ||||
|         FileInfo.FileSize + WriteLength : WriteOffset.QuadPart + WriteLength; | ||||
|     if (FileInfo.FileSize < WriteEndOffset) | ||||
|     { | ||||
|         /* file is being extended */ | ||||
|         FileSizes.FileSize.QuadPart = WriteEndOffset; | ||||
|         if (FileSizes.FileSize.QuadPart > FileSizes.AllocationSize.QuadPart) | ||||
|         { | ||||
|             UINT64 AllocationUnit = FsvolDeviceExtension->VolumeParams.SectorSize * | ||||
|                 FsvolDeviceExtension->VolumeParams.SectorsPerAllocationUnit; | ||||
|             FileSizes.AllocationSize.QuadPart = (FileSizes.FileSize.QuadPart + AllocationUnit - 1) | ||||
|                 / AllocationUnit * AllocationUnit; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* initialize cache if not already initialized! */ | ||||
|     if (0 == FileObject->PrivateCacheMap) | ||||
|     { | ||||
|         Result = FspCcInitializeCacheMap(FileObject, &FileSizes, FALSE, | ||||
|             &FspCacheManagerCallbacks, FileNode); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|         { | ||||
|             FspFileNodeRelease(FileNode, Main); | ||||
|             return Result; | ||||
|         } | ||||
|     } | ||||
|     else if (FileInfo.FileSize < WriteEndOffset) | ||||
|     { | ||||
|         /* file is being extended */ | ||||
|         Result = FspCcSetFileSizes(FileObject, &FileSizes); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|         { | ||||
|             FspFileNodeRelease(FileNode, Main); | ||||
|             return Result; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* are we using the copy or MDL interface? */ | ||||
|     if (!FlagOn(IrpSp->MinorFunction, IRP_MN_MDL)) | ||||
|     { | ||||
|         PVOID Buffer; | ||||
|  | ||||
|         Buffer = 0 == Irp->MdlAddress ? | ||||
|             Irp->UserBuffer : MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); | ||||
|         if (0 == Buffer) | ||||
|         { | ||||
|             FspFileNodeRelease(FileNode, Main); | ||||
|             return STATUS_INSUFFICIENT_RESOURCES; | ||||
|         } | ||||
|  | ||||
|         Result = FspCcCopyWrite(FileObject, &WriteOffset, WriteLength, CanWait || Retrying, Buffer); | ||||
|         if (STATUS_PENDING == Result) | ||||
|         { | ||||
|             FspFileNodeRelease(FileNode, Main); | ||||
|             return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0); | ||||
|         } | ||||
|  | ||||
|         Irp->IoStatus.Information = WriteLength; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ASSERT(0 == Irp->MdlAddress); | ||||
|  | ||||
|         Result = FspCcPrepareMdlWrite(FileObject, &WriteOffset, WriteLength, | ||||
|             &Irp->MdlAddress, &Irp->IoStatus); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|         { | ||||
|             FspFileNodeRelease(FileNode, Main); | ||||
|             return Result; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* update the current file offset if synchronous I/O */ | ||||
|     if (SynchronousIo) | ||||
|         FileObject->CurrentByteOffset.QuadPart = WriteEndOffset; | ||||
|  | ||||
|     FspFileNodeRelease(FileNode, Main); | ||||
|  | ||||
|     return STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| static VOID FspFsvolWriteCachedDeferred(PVOID Context1, PVOID Context2) | ||||
| @@ -135,7 +229,166 @@ static NTSTATUS FspFsvolWriteNonCached( | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     return STATUS_INVALID_DEVICE_REQUEST; | ||||
|     NTSTATUS Result; | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     FSP_FILE_DESC *FileDesc = FileObject->FsContext2; | ||||
|     LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset; | ||||
|     ULONG WriteLength = IrpSp->Parameters.Write.Length; | ||||
|     ULONG WriteKey = IrpSp->Parameters.Write.Key; | ||||
|     BOOLEAN WriteToEndOfFile = | ||||
|         FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; | ||||
|     BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); | ||||
|     FSP_FSCTL_TRANSACT_REQ *Request; | ||||
|  | ||||
|     ASSERT(FileNode == FileDesc->FileNode); | ||||
|  | ||||
|     /* no MDL requests on the non-cached path */ | ||||
|     if (FlagOn(IrpSp->MinorFunction, IRP_MN_MDL)) | ||||
|         return STATUS_INVALID_PARAMETER; | ||||
|  | ||||
|     /* paging I/O cannot change the file size */ | ||||
|     if (PagingIo && WriteToEndOfFile) | ||||
|         return STATUS_INVALID_PARAMETER; | ||||
|  | ||||
|     /* if non-cached I/O check the offset/length alignment */ | ||||
|     /* | ||||
|      * We are going to avoid doing this test, because we don't really need to restrict | ||||
|      * ourselves for non-cached I/O, but also because we do not always know the correct | ||||
|      * file size for our alignment test. The file size is needed, because the alignment | ||||
|      * test is: | ||||
|      * | ||||
|      *     if WriteOffset is sector aligned | ||||
|      *     and (WriteLength is sector aligned or WriteOffset + WriteLength >= FileSize) | ||||
|      * | ||||
|      * This means that the user-mode file system must be able to deal with variable size | ||||
|      * I/O, but this was the case anyway because of the following part of the test: | ||||
|      * | ||||
|      *     WriteOffset + WriteLength >= FileSize | ||||
|      * | ||||
|      * In any case the user-mode file system can enforce this rule if it wants! | ||||
|      */ | ||||
| #if 0 | ||||
|     if (!PagingIo) | ||||
|     { | ||||
|         FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = | ||||
|             FspFsvolDeviceExtension(FsvolDeviceObject); | ||||
|         if (0 != WriteOffset.QuadPart % FsvolDeviceExtension->VolumeParams.SectorSize || | ||||
|             0 != WriteLength % FsvolDeviceExtension->VolumeParams.SectorSize) | ||||
|             return STATUS_NOT_IMPLEMENTED; /* FastFat does this! */ | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     /* probe and lock the user buffer */ | ||||
|     if (0 == Irp->MdlAddress) | ||||
|     { | ||||
|         Result = FspLockUserBuffer(Irp->UserBuffer, IrpSp->Parameters.Write.Length, | ||||
|             Irp->RequestorMode, IoReadAccess, &Irp->MdlAddress); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|             return Result; | ||||
|     } | ||||
|  | ||||
|     /* create request */ | ||||
|     Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolWriteNonCachedRequestFini, &Request); | ||||
|     if (!NT_SUCCESS(Result)) | ||||
|         return Result; | ||||
|  | ||||
|     Request->Kind = FspFsctlTransactWriteKind; | ||||
|     Request->Req.Write.UserContext = FileNode->UserContext; | ||||
|     Request->Req.Write.UserContext2 = FileDesc->UserContext2; | ||||
|     Request->Req.Write.Offset = WriteOffset.QuadPart; | ||||
|     Request->Req.Write.Length = WriteLength; | ||||
|     Request->Req.Write.Key = WriteKey; | ||||
|     Request->Req.Write.Append = WriteToEndOfFile; | ||||
|     Request->Req.Write.PagingIo = PagingIo; | ||||
|  | ||||
|     return FSP_STATUS_IOQ_POST; | ||||
| } | ||||
|  | ||||
| NTSTATUS FspFsvolWritePrepare( | ||||
|     PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     NTSTATUS Result; | ||||
|     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); | ||||
|     FSP_SAFE_MDL *SafeMdl = 0; | ||||
|     PVOID Address; | ||||
|     PEPROCESS Process; | ||||
|     BOOLEAN Success; | ||||
|  | ||||
|     Success = DEBUGRANDTEST(90, TRUE) && FspFileNodeTryAcquireExclusive(FileNode, Full); | ||||
|     if (!Success) | ||||
|     { | ||||
|         FspIopRetryPrepareIrp(Irp, &Result); | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     /* if this is a non-cached transfer on a cached file then flush and purge the file */ | ||||
|     if (!PagingIo && 0 != FileObject->SectionObjectPointer->DataSectionObject) | ||||
|     { | ||||
|         LARGE_INTEGER FlushOffset = IrpSp->Parameters.Write.ByteOffset; | ||||
|         PLARGE_INTEGER PFlushOffset = &FlushOffset; | ||||
|         ULONG FlushLength = IrpSp->Parameters.Write.Length; | ||||
|         FSP_FSCTL_FILE_INFO FileInfo; | ||||
|         IO_STATUS_BLOCK IoStatus = { 0 }; | ||||
|  | ||||
|         if (FILE_WRITE_TO_END_OF_FILE == FlushOffset.LowPart && -1L == FlushOffset.HighPart) | ||||
|         { | ||||
|             if (FspFileNodeTryGetFileInfo(FileNode, &FileInfo)) | ||||
|                 FlushOffset.QuadPart = FileInfo.FileSize; | ||||
|             else | ||||
|                 PFlushOffset = 0; /* we don't know how big the file is, so flush it all! */ | ||||
|         } | ||||
|  | ||||
|         CcFlushCache(FileObject->SectionObjectPointer, PFlushOffset, FlushLength, &IoStatus); | ||||
|         if (!NT_SUCCESS(IoStatus.Status)) | ||||
|         { | ||||
|             FspFileNodeRelease(FileNode, Full); | ||||
|             return IoStatus.Status; | ||||
|         } | ||||
|  | ||||
|         CcPurgeCacheSection(FileObject->SectionObjectPointer, PFlushOffset, FlushLength, FALSE); | ||||
|     } | ||||
|  | ||||
|     /* create a "safe" MDL if necessary */ | ||||
|     if (!FspSafeMdlCheck(Irp->MdlAddress)) | ||||
|     { | ||||
|         Result = FspSafeMdlCreate(Irp->MdlAddress, IoReadAccess, &SafeMdl); | ||||
|         if (!NT_SUCCESS(Result)) | ||||
|         { | ||||
|             FspFileNodeRelease(FileNode, Full); | ||||
|             return STATUS_INSUFFICIENT_RESOURCES; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* map the MDL into user-mode */ | ||||
|     Result = FspMapLockedPagesInUserMode(0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress, &Address); | ||||
|     if (!NT_SUCCESS(Result)) | ||||
|     { | ||||
|         if (0 != SafeMdl) | ||||
|             FspSafeMdlDelete(SafeMdl); | ||||
|  | ||||
|         FspFileNodeRelease(FileNode, Full); | ||||
|         return Result; | ||||
|     } | ||||
|  | ||||
|     /* get a pointer to the current process so that we can unmap the address later */ | ||||
|     Process = PsGetCurrentProcess(); | ||||
|     ObReferenceObject(Process); | ||||
|  | ||||
|     Request->Req.Write.Address = (UINT64)(UINT_PTR)Address; | ||||
|  | ||||
|     FspFileNodeSetOwner(FileNode, Pgio, Request); | ||||
|     FspIopRequestContext(Request, RequestIrp) = Irp; | ||||
|     FspIopRequestContext(Request, RequestSafeMdl) = SafeMdl; | ||||
|     FspIopRequestContext(Request, RequestAddress) = Address; | ||||
|     FspIopRequestContext(Request, RequestProcess) = Process; | ||||
|  | ||||
|     return STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| NTSTATUS FspFsvolWriteComplete( | ||||
| @@ -143,6 +396,36 @@ NTSTATUS FspFsvolWriteComplete( | ||||
| { | ||||
|     FSP_ENTER_IOC(PAGED_CODE()); | ||||
|  | ||||
|     PFILE_OBJECT FileObject = IrpSp->FileObject; | ||||
|     FSP_FILE_NODE *FileNode = FileObject->FsContext; | ||||
|     LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset; | ||||
|     BOOLEAN WriteToEndOfFile = | ||||
|         FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart; | ||||
|     BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO); | ||||
|     BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO); | ||||
|  | ||||
|     if (!NT_SUCCESS(Response->IoStatus.Status)) | ||||
|     { | ||||
|         Irp->IoStatus.Information = 0; | ||||
|         Result = Response->IoStatus.Status; | ||||
|         FSP_RETURN(); | ||||
|     } | ||||
|  | ||||
|     if (!PagingIo) | ||||
|     { | ||||
|         /* update file info */ | ||||
|         FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.Write.FileInfo); | ||||
|  | ||||
|         /* update the current file offset if synchronous I/O (and not paging I/O) */ | ||||
|         if (SynchronousIo) | ||||
|             FileObject->CurrentByteOffset.QuadPart = WriteToEndOfFile ? | ||||
|                 Response->Rsp.Write.FileInfo.FileSize : | ||||
|                 WriteOffset.QuadPart + Response->IoStatus.Information; | ||||
|     } | ||||
|  | ||||
|     Irp->IoStatus.Information = Response->IoStatus.Information; | ||||
|     Result = STATUS_SUCCESS; | ||||
|  | ||||
|     FSP_LEAVE_IOC( | ||||
|         "FileObject=%p, UserBuffer=%p, MdlAddress=%p, " | ||||
|         "Key=%#lx, ByteOffset=%#lx:%#lx, Length=%ld", | ||||
| @@ -152,6 +435,44 @@ NTSTATUS FspFsvolWriteComplete( | ||||
|         IrpSp->Parameters.Write.Length); | ||||
| } | ||||
|  | ||||
| static VOID FspFsvolWriteNonCachedRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4]) | ||||
| { | ||||
|     PAGED_CODE(); | ||||
|  | ||||
|     PIRP Irp = Context[RequestIrp]; | ||||
|     FSP_SAFE_MDL *SafeMdl = Context[RequestSafeMdl]; | ||||
|     PVOID Address = Context[RequestAddress]; | ||||
|     PEPROCESS Process = Context[RequestProcess]; | ||||
|  | ||||
|     if (0 != Address) | ||||
|     { | ||||
|         KAPC_STATE ApcState; | ||||
|         BOOLEAN Attach; | ||||
|  | ||||
|         ASSERT(0 != Process); | ||||
|         Attach = Process != PsGetCurrentProcess(); | ||||
|  | ||||
|         if (Attach) | ||||
|             KeStackAttachProcess(Process, &ApcState); | ||||
|         MmUnmapLockedPages(Address, 0 != SafeMdl ? SafeMdl->Mdl : Irp->MdlAddress); | ||||
|         if (Attach) | ||||
|             KeUnstackDetachProcess(&ApcState); | ||||
|  | ||||
|         ObDereferenceObject(Process); | ||||
|     } | ||||
|  | ||||
|     if (0 != SafeMdl) | ||||
|         FspSafeMdlDelete(SafeMdl); | ||||
|  | ||||
|     if (0 != Irp) | ||||
|     { | ||||
|         PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); | ||||
|         FSP_FILE_NODE *FileNode = IrpSp->FileObject->FsContext; | ||||
|  | ||||
|         FspFileNodeReleaseOwner(FileNode, Full, Request); | ||||
|     } | ||||
| } | ||||
|  | ||||
| NTSTATUS FspWrite( | ||||
|     PDEVICE_OBJECT DeviceObject, PIRP Irp) | ||||
| { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user