mirror of
https://github.com/reactos/reactos.git
synced 2025-04-21 20:50:29 +00:00
Fix NtWriteFile: Get right Deviceobject, Use FileObject->FinalStatus, use FileObject-.CurrentByteOffset if ByteOffset == FILE_USER_FILE_POINTER_POSITION, add SEH, use right event requested access, set IRP_WRITE_OPERATION flag, add support for IRP_NOCACHE and add support for SL_WRITE_THROUGH if FO_WRITE_THROUGH is enabled.
svn path=/trunk/; revision=15175
This commit is contained in:
parent
71b6d3cb0f
commit
02a4600eb8
1 changed files with 370 additions and 328 deletions
|
@ -2957,152 +2957,194 @@ NtWriteFile (IN HANDLE FileHandle,
|
|||
IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */
|
||||
IN PULONG Key OPTIONAL)
|
||||
{
|
||||
OBJECT_HANDLE_INFORMATION HandleInformation;
|
||||
NTSTATUS Status;
|
||||
PFILE_OBJECT FileObject;
|
||||
PIRP Irp = NULL;
|
||||
PIO_STACK_LOCATION StackPtr;
|
||||
KPROCESSOR_MODE PreviousMode;
|
||||
PKEVENT EventObject = NULL;
|
||||
LARGE_INTEGER Offset;
|
||||
OBJECT_HANDLE_INFORMATION HandleInformation;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PFILE_OBJECT FileObject;
|
||||
PIRP Irp = NULL;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PIO_STACK_LOCATION StackPtr;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
BOOLEAN LocalEvent = FALSE;
|
||||
PKEVENT EventObject = NULL;
|
||||
|
||||
DPRINT("NtWriteFile(FileHandle %x Buffer %x Length %x ByteOffset %x, "
|
||||
"IoStatusBlock %x)\n", FileHandle, Buffer, Length, ByteOffset,
|
||||
IoStatusBlock);
|
||||
|
||||
if (IoStatusBlock == NULL)
|
||||
return STATUS_ACCESS_VIOLATION;
|
||||
|
||||
PreviousMode = ExGetPreviousMode();
|
||||
|
||||
Status = ObReferenceObjectByHandle(FileHandle,
|
||||
0,
|
||||
IoFileObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&FileObject,
|
||||
&HandleInformation);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Must have FILE_WRITE_DATA | FILE_APPEND_DATA access */
|
||||
if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
|
||||
{
|
||||
DPRINT1("Invalid access rights\n");
|
||||
ObDereferenceObject(FileObject);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (HandleInformation.GrantedAccess & FILE_WRITE_DATA)
|
||||
{
|
||||
if (ByteOffset == NULL)
|
||||
{
|
||||
/* a valid ByteOffset is required if asynch. op. */
|
||||
if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
|
||||
{
|
||||
DPRINT1("NtWriteFile: missing ByteOffset for asynch. op\n");
|
||||
ObDereferenceObject(FileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
ByteOffset = &FileObject->CurrentByteOffset;
|
||||
}
|
||||
}
|
||||
else if (HandleInformation.GrantedAccess & FILE_APPEND_DATA)
|
||||
{
|
||||
/* a valid ByteOffset is required if asynch. op. */
|
||||
if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
|
||||
{
|
||||
DPRINT1("NtWriteFile: missing ByteOffset for asynch. op\n");
|
||||
ObDereferenceObject(FileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Offset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;
|
||||
Offset.u.HighPart = 0xffffffff;
|
||||
ByteOffset = &Offset;
|
||||
}
|
||||
|
||||
if (Event != NULL)
|
||||
{
|
||||
Status = ObReferenceObjectByHandle(Event,
|
||||
SYNCHRONIZE,
|
||||
ExEventObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&EventObject,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ObDereferenceObject(FileObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
KeClearEvent(EventObject);
|
||||
}
|
||||
|
||||
_SEH_TRY
|
||||
{
|
||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
|
||||
FileObject->DeviceObject,
|
||||
Buffer,
|
||||
Length,
|
||||
ByteOffset,
|
||||
EventObject,
|
||||
DPRINT("NtWriteFile(FileHandle %x Buffer %x Length %x ByteOffset %x, "
|
||||
"IoStatusBlock %x)\n", FileHandle, Buffer, Length, ByteOffset,
|
||||
IoStatusBlock);
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if (!NT_SUCCESS(Status) || Irp == NULL)
|
||||
{
|
||||
if (Event)
|
||||
{
|
||||
ObDereferenceObject(&EventObject);
|
||||
}
|
||||
ObDereferenceObject(FileObject);
|
||||
if (Irp)
|
||||
{
|
||||
IoFreeIrp(Irp);
|
||||
}
|
||||
return NT_SUCCESS(Status) ? STATUS_INSUFFICIENT_RESOURCES : Status;
|
||||
}
|
||||
|
||||
KeClearEvent(&FileObject->Event);
|
||||
|
||||
/* Trigger FileObject/Event dereferencing */
|
||||
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
||||
|
||||
Irp->RequestorMode = PreviousMode;
|
||||
|
||||
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
|
||||
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
|
||||
|
||||
StackPtr = IoGetNextIrpStackLocation(Irp);
|
||||
StackPtr->FileObject = FileObject;
|
||||
StackPtr->Parameters.Write.Key = Key ? *Key : 0;
|
||||
|
||||
Status = IoCallDriver(FileObject->DeviceObject, Irp);
|
||||
if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
|
||||
{
|
||||
Status = KeWaitForSingleObject(&FileObject->Event,
|
||||
Executive,
|
||||
PreviousMode,
|
||||
FileObject->Flags & FO_ALERTABLE_IO,
|
||||
NULL);
|
||||
if (Status != STATUS_WAIT_0)
|
||||
/* Validate User-Mode Buffers */
|
||||
if(PreviousMode != KernelMode)
|
||||
{
|
||||
/* Wait failed. */
|
||||
return Status;
|
||||
_SEH_TRY
|
||||
{
|
||||
ProbeForWrite(IoStatusBlock,
|
||||
sizeof(IO_STATUS_BLOCK),
|
||||
sizeof(ULONG));
|
||||
#if 0
|
||||
ProbeForRead(Buffer,
|
||||
Length,
|
||||
sizeof(ULONG));
|
||||
#endif
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
Status = IoStatusBlock->Status;
|
||||
}
|
||||
/* Get File Object */
|
||||
Status = ObReferenceObjectByHandle(FileHandle,
|
||||
0,
|
||||
IoFileObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&FileObject,
|
||||
&HandleInformation);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
return Status;
|
||||
/* Must have FILE_WRITE_DATA | FILE_APPEND_DATA access */
|
||||
if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
|
||||
{
|
||||
DPRINT1("Invalid access rights\n");
|
||||
ObDereferenceObject(FileObject);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
/* Check if we got write Access */
|
||||
if (HandleInformation.GrantedAccess & FILE_WRITE_DATA)
|
||||
{
|
||||
/* Check the Byte Offset */
|
||||
if (!ByteOffset ||
|
||||
(ByteOffset->u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
|
||||
ByteOffset->u.HighPart == 0xffffffff))
|
||||
{
|
||||
/* a valid ByteOffset is required if asynch. op. */
|
||||
if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
|
||||
{
|
||||
DPRINT1("NtReadFile: missing ByteOffset for asynch. op\n");
|
||||
ObDereferenceObject(FileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Use the Current Byte OFfset */
|
||||
ByteOffset = &FileObject->CurrentByteOffset;
|
||||
}
|
||||
}
|
||||
else if (HandleInformation.GrantedAccess & FILE_APPEND_DATA)
|
||||
{
|
||||
/* a valid ByteOffset is required if asynch. op. */
|
||||
if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
|
||||
{
|
||||
DPRINT1("NtWriteFile: missing ByteOffset for asynch. op\n");
|
||||
ObDereferenceObject(FileObject);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Give the drivers somethign to understand */
|
||||
ByteOffset->u.LowPart = FILE_WRITE_TO_END_OF_FILE;
|
||||
ByteOffset->u.HighPart = 0xffffffff;
|
||||
}
|
||||
|
||||
/* Check if we got an event */
|
||||
if (Event)
|
||||
{
|
||||
/* Reference it */
|
||||
Status = ObReferenceObjectByHandle(Event,
|
||||
EVENT_MODIFY_STATE,
|
||||
ExEventObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&EventObject,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ObDereferenceObject(FileObject);
|
||||
return Status;
|
||||
}
|
||||
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)
|
||||
{
|
||||
/* Use File Object event */
|
||||
KeClearEvent(&FileObject->Event);
|
||||
}
|
||||
else
|
||||
{
|
||||
LocalEvent = TRUE;
|
||||
}
|
||||
|
||||
/* Build the IRP */
|
||||
_SEH_TRY
|
||||
{
|
||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
|
||||
FileObject->DeviceObject,
|
||||
Buffer,
|
||||
Length,
|
||||
ByteOffset,
|
||||
EventObject,
|
||||
IoStatusBlock);
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
/* Cleanup on failure */
|
||||
if (!NT_SUCCESS(Status) || !Irp)
|
||||
{
|
||||
if (Event)
|
||||
{
|
||||
ObDereferenceObject(&EventObject);
|
||||
}
|
||||
ObDereferenceObject(FileObject);
|
||||
if (Irp) IoFreeIrp(Irp);
|
||||
return NT_SUCCESS(Status) ? STATUS_INSUFFICIENT_RESOURCES : Status;
|
||||
}
|
||||
|
||||
/* Set up IRP Data */
|
||||
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
||||
Irp->RequestorMode = PreviousMode;
|
||||
Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
|
||||
Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
|
||||
Irp->Flags |= IRP_WRITE_OPERATION;
|
||||
if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
|
||||
|
||||
/* Setup Stack Data */
|
||||
StackPtr = IoGetNextIrpStackLocation(Irp);
|
||||
StackPtr->FileObject = FileObject;
|
||||
StackPtr->Parameters.Write.Key = Key ? *Key : 0;
|
||||
if (FileObject->Flags & FO_WRITE_THROUGH) StackPtr->Flags = SL_WRITE_THROUGH;
|
||||
|
||||
/* Call the Driver */
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
if (!LocalEvent)
|
||||
{
|
||||
KeWaitForSingleObject(&FileObject->Event,
|
||||
Executive,
|
||||
PreviousMode,
|
||||
FileObject->Flags & FO_ALERTABLE_IO,
|
||||
NULL);
|
||||
Status = FileObject->FinalStatus;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the Status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue