Author: ion Date: Mon Jul 3 05:17:14 2006 New Revision: 22790
URL: http://svn.reactos.org/svn/reactos?rev=22790&view=rev Log: - NtWriteFile: - Allow async i/o access on mailslots, without a byte offset. - Fix sync semantics just like for the other functions until now. - Fix a potential object leak in a failure case. - Don't call IoBuildSyncronousFsdRequest since we want to build the IRP ourselves. - Use deferred I/O as an optimization.
Modified: trunk/reactos/ntoskrnl/io/iomgr/iofunc.c
Modified: trunk/reactos/ntoskrnl/io/iomgr/iofunc.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/iofunc.c?... ============================================================================== --- trunk/reactos/ntoskrnl/io/iomgr/iofunc.c (original) +++ trunk/reactos/ntoskrnl/io/iomgr/iofunc.c Mon Jul 3 05:17:14 2006 @@ -26,9 +26,9 @@ // TODO: // - Lock/Unlock <= DONE // - Query/Set Volume Info <= DONE -// - Read/Write file -// - QuerySet/ File Info -// - NtQueryDirectoryFile +// - Read/Write file <= DONE +// - Query/Set File Info +// - QueryDirectoryFile // ///
@@ -2450,20 +2450,19 @@ IN PLARGE_INTEGER ByteOffset OPTIONAL, IN PULONG Key OPTIONAL) { - OBJECT_HANDLE_INFORMATION ObjectHandleInfo; NTSTATUS Status = STATUS_SUCCESS; PFILE_OBJECT FileObject; - PIRP Irp = NULL; + PIRP Irp; PDEVICE_OBJECT DeviceObject; PIO_STACK_LOCATION StackPtr; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); - BOOLEAN Synchronous = FALSE; PKEVENT EventObject = NULL; LARGE_INTEGER CapturedByteOffset; ULONG CapturedKey = 0; - ACCESS_MASK DesiredAccess = FILE_WRITE_DATA; + BOOLEAN Synchronous = FALSE; + PMDL Mdl; + OBJECT_HANDLE_INFORMATION ObjectHandleInfo; PAGED_CODE(); - CapturedByteOffset.QuadPart = 0;
/* Get File Object */ @@ -2475,79 +2474,71 @@ &ObjectHandleInfo); if (!NT_SUCCESS(Status)) return Status;
- /* If this is a named pipe, make sure we don't ask for FILE_APPEND_DATA as it - overlaps with the FILE_CREATE_PIPE_INSTANCE access right! */ - if (!(FileObject->Flags & FO_NAMED_PIPE)) - DesiredAccess |= FILE_APPEND_DATA; - /* Validate User-Mode Buffers */ - if (PreviousMode != KernelMode) - { - /* check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was - granted. */ - if (!RtlAreAnyAccessesGranted(ObjectHandleInfo.GrantedAccess, - DesiredAccess)) - { - ObDereferenceObject(FileObject); - return STATUS_ACCESS_DENIED; - } - + if(PreviousMode != KernelMode) + { _SEH_TRY { + /* + * Check if the handle has either FILE_WRITE_DATA or + * FILE_APPEND_DATA granted. However, if this is a named pipe, + * make sure we don't ask for FILE_APPEND_DATA as it interferes + * with the FILE_CREATE_PIPE_INSTANCE access right! + */ + if (!(ObjectHandleInfo.GrantedAccess & + ((!(FileObject->Flags & FO_NAMED_PIPE) ? + FILE_APPEND_DATA : 0) | FILE_WRITE_DATA))) + { + /* We failed */ + ObDereferenceObject(FileObject); + return STATUS_ACCESS_DENIED; + } + + /* Probe the status block */ ProbeForWrite(IoStatusBlock, sizeof(IO_STATUS_BLOCK), sizeof(ULONG)); + + /* Probe the read buffer */ ProbeForRead(Buffer, Length, 1);
+ /* Check if we got a byte offset */ if (ByteOffset) { + /* Capture and probe it */ CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); }
+ /* Capture and probe the key */ if (Key) CapturedKey = ProbeForReadUlong(Key); } _SEH_HANDLE { + /* Get the exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END;
- if(!NT_SUCCESS(Status)) return Status; + /* Check for probe failure */ + if (!NT_SUCCESS(Status)) return Status; } else { + /* Kernel mode: capture directly */ if (ByteOffset) CapturedByteOffset = *ByteOffset; if (Key) CapturedKey = *Key; }
- /* check if this is an append operation */ - if ((ObjectHandleInfo.GrantedAccess & DesiredAccess) == FILE_APPEND_DATA) + /* Check if this is an append operation */ + if ((ObjectHandleInfo.GrantedAccess & + (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA) { /* Give the drivers something to understand */ CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE; CapturedByteOffset.u.HighPart = -1; }
- /* Check if we should use Sync IO or not */ - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - if (ByteOffset == NULL || - (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION && - CapturedByteOffset.u.HighPart == -1)) - { - /* Use the Current Byte OFfset */ - CapturedByteOffset = FileObject->CurrentByteOffset; - } - - Synchronous = TRUE; - } - else if (ByteOffset == NULL && !(FileObject->Flags & FO_NAMED_PIPE)) - { - ObDereferenceObject(FileObject); - return STATUS_INVALID_PARAMETER; - } - - /* Check if we got an event */ + /* Check for event */ if (Event) { /* Reference it */ @@ -2559,89 +2550,133 @@ NULL); if (!NT_SUCCESS(Status)) { + /* Fail */ ObDereferenceObject(FileObject); return Status; } + + /* Otherwise reset the event */ KeClearEvent(EventObject); }
- /* Check if this is a direct open or not */ - if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) - { - DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); - } - else - { - DeviceObject = IoGetRelatedDeviceObject(FileObject); - } - + /* Check if we should use Sync IO or not */ + if (FileObject->Flags & FO_SYNCHRONOUS_IO) + { + /* Lock the file object */ + IopLockFileObject(FileObject); + + /* Check if we don't have a byte offset avilable */ + if (!(ByteOffset) || + ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && + (CapturedByteOffset.u.HighPart == -1))) + { + /* Use the Current Byte Offset instead */ + CapturedByteOffset = FileObject->CurrentByteOffset; + } + + /* Rememer we are sync */ + Synchronous = TRUE; + } + else if (!(ByteOffset) && + !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) + { + /* Otherwise, this was async I/O without a byte offset, so fail */ + if (EventObject) ObDereferenceObject(EventObject); + ObDereferenceObject(FileObject); + return STATUS_INVALID_PARAMETER; + } + + /* Get the device object */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + /* Clear the File Object's event */ KeClearEvent(&FileObject->Event);
- /* Build the IRP */ - _SEH_TRY - { - Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, - DeviceObject, - Buffer, - Length, - &CapturedByteOffset, - EventObject, - IoStatusBlock); - if (Irp == NULL) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - /* Cleanup on failure */ - if (!NT_SUCCESS(Status)) - { - if (Event) ObDereferenceObject(&EventObject); - ObDereferenceObject(FileObject); - return Status; - } - - /* Set up IRP Data */ + /* Allocate the IRP */ + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) return IopCleanupFailedIrp(FileObject, NULL); + + /* Set the IRP */ Irp->Tail.Overlay.OriginalFileObject = FileObject; - Irp->RequestorMode = PreviousMode; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->RequestorMode = KernelMode; Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; - Irp->Flags |= IRP_WRITE_OPERATION; -#if 0 - /* FIXME: - * Vfat doesn't handle non cached files correctly. - */ + Irp->UserIosb = IoStatusBlock; + Irp->UserEvent = EventObject; + Irp->PendingReturned = FALSE; + Irp->Cancel = FALSE; + Irp->CancelRoutine = NULL; + Irp->AssociatedIrp.SystemBuffer = NULL; + Irp->MdlAddress = NULL; + + /* Set the Stack Data */ + StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->MajorFunction = IRP_MJ_WRITE; + StackPtr->FileObject = FileObject; + StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ? + SL_WRITE_THROUGH : 0; + StackPtr->Parameters.Write.Key = CapturedKey; + StackPtr->Parameters.Write.Length = Length; + StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset; + + /* Check if this is buffered I/O */ + if (DeviceObject->Flags & DO_BUFFERED_IO) + { + /* Check if we have a buffer length */ + if (Length) + { + /* Allocate a buffer */ + Irp->AssociatedIrp.SystemBuffer = + ExAllocatePoolWithTag(NonPagedPool, + Length, + TAG_SYSB); + + /* Copy the buffer and set flags */ + RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length); + Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER); + } + else + { + /* Not writing anything */ + Irp->Flags = IRP_BUFFERED_IO; + } + } + else if (DeviceObject->Flags & DO_DIRECT_IO) + { + /* Check if we have a buffer length */ + if (Length) + { + /* Allocate an MDL */ + Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); + MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess); + } + + /* No allocation flags */ + Irp->Flags = 0; + } + else + { + /* No allocation flags, and use the buffer directly */ + Irp->Flags = 0; + Irp->UserBuffer = Buffer; + } + + /* Now set the deferred read flags */ + Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION); +#if 0 + /* FIXME: VFAT SUCKS */ if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; -#endif - - /* Setup Stack Data */ - StackPtr = IoGetNextIrpStackLocation(Irp); - StackPtr->FileObject = FileObject; - StackPtr->Parameters.Write.Key = CapturedKey; - if (FileObject->Flags & FO_WRITE_THROUGH) StackPtr->Flags = SL_WRITE_THROUGH; - - /* Call the Driver */ - Status = IoCallDriver(DeviceObject, Irp); - if (Status == STATUS_PENDING) - { - if (Synchronous) - { - KeWaitForSingleObject(&FileObject->Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); - Status = FileObject->FinalStatus; - } - } - - /* Return the Status */ - return Status; +#endif + + /* Perform the call */ + return IopPerformSynchronousRequest(DeviceObject, + Irp, + FileObject, + TRUE, + PreviousMode, + Synchronous, + IopWriteTransfer); }
NTSTATUS