317 lines
7.7 KiB
C
317 lines
7.7 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
Write.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements the File Write routine for Write called by the
|
||
|
Fsd/Fsp dispatch drivers.
|
||
|
|
||
|
// @@BEGIN_DDKSPLIT
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Tom Jolly [tomjolly] 8-Aug-2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
// @@END_DDKSPLIT
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "UdfProcs.h"
|
||
|
|
||
|
//
|
||
|
// The Bug check file id for this module
|
||
|
//
|
||
|
|
||
|
#define BugCheckFileId (UDFS_BUG_CHECK_WRITE)
|
||
|
|
||
|
//
|
||
|
// The local debug trace level
|
||
|
//
|
||
|
|
||
|
#define Dbg (UDFS_DEBUG_LEVEL_WRITE)
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
UdfCommonWrite (
|
||
|
IN PIRP_CONTEXT IrpContext,
|
||
|
IN PIRP Irp
|
||
|
)
|
||
|
{
|
||
|
PIO_STACK_LOCATION IrpSp;
|
||
|
PFILE_OBJECT FileObject;
|
||
|
|
||
|
TYPE_OF_OPEN TypeOfOpen;
|
||
|
PFCB Fcb;
|
||
|
PCCB Ccb;
|
||
|
|
||
|
BOOLEAN Wait;
|
||
|
BOOLEAN PagingIo;
|
||
|
BOOLEAN SynchronousIo;
|
||
|
BOOLEAN WriteToEof;
|
||
|
|
||
|
LONGLONG StartingOffset;
|
||
|
LONGLONG ByteCount;
|
||
|
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
|
||
|
UDF_IO_CONTEXT LocalIoContext;
|
||
|
|
||
|
//
|
||
|
// Get current Irp stack location and file object
|
||
|
//
|
||
|
|
||
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
FileObject = IrpSp->FileObject;
|
||
|
|
||
|
DebugTrace((+1, Dbg, "UdfCommonWrite\n"));
|
||
|
DebugTrace(( 0, Dbg, "Irp = %8lx\n", Irp));
|
||
|
DebugTrace(( 0, Dbg, "ByteCount = %8lx\n", IrpSp->Parameters.Write.Length));
|
||
|
DebugTrace(( 0, Dbg, "ByteOffset.LowPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.LowPart));
|
||
|
DebugTrace(( 0, Dbg, "ByteOffset.HighPart = %8lx\n", IrpSp->Parameters.Write.ByteOffset.HighPart));
|
||
|
|
||
|
//
|
||
|
// Extract the nature of the write from the file object, and case on it
|
||
|
//
|
||
|
|
||
|
TypeOfOpen = UdfDecodeFileObject( FileObject, &Fcb, &Ccb);
|
||
|
|
||
|
//
|
||
|
// We only support write to the volume file
|
||
|
//
|
||
|
|
||
|
if (TypeOfOpen != UserVolumeOpen) {
|
||
|
|
||
|
Irp->IoStatus.Information = 0;
|
||
|
UdfCompleteRequest( IrpContext, Irp, STATUS_NOT_IMPLEMENTED );
|
||
|
return STATUS_NOT_IMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
ASSERT( Fcb == IrpContext->Vcb->VolumeDasdFcb);
|
||
|
|
||
|
//
|
||
|
// Initialize the appropriate local variables.
|
||
|
//
|
||
|
|
||
|
Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
|
||
|
PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
|
||
|
SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
|
||
|
|
||
|
//
|
||
|
// Extract the bytecount and starting offset
|
||
|
//
|
||
|
|
||
|
ByteCount = IrpSp->Parameters.Write.Length;
|
||
|
StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart;
|
||
|
WriteToEof = (StartingOffset == -1);
|
||
|
|
||
|
Irp->IoStatus.Information = 0;
|
||
|
|
||
|
//
|
||
|
// If there is nothing to write, return immediately
|
||
|
//
|
||
|
|
||
|
if (ByteCount == 0) {
|
||
|
|
||
|
UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Watch for overflow
|
||
|
//
|
||
|
|
||
|
if ((MAXLONGLONG - StartingOffset) < ByteCount) {
|
||
|
|
||
|
UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
|
||
|
return STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Not sure what we're synchronising against, but....
|
||
|
//
|
||
|
|
||
|
UdfAcquireFileShared( IrpContext, Fcb );
|
||
|
|
||
|
try {
|
||
|
|
||
|
//
|
||
|
// Verify the Fcb. Allow writes if this handle is dismounting
|
||
|
// the volume.
|
||
|
//
|
||
|
|
||
|
if ((NULL == Ccb) || !FlagOn( Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) {
|
||
|
|
||
|
UdfVerifyFcbOperation( IrpContext, Fcb );
|
||
|
}
|
||
|
|
||
|
if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
|
||
|
|
||
|
//
|
||
|
// Clamp to volume size
|
||
|
//
|
||
|
|
||
|
if ( StartingOffset >= Fcb->FileSize.QuadPart) {
|
||
|
|
||
|
try_leave( NOTHING);
|
||
|
}
|
||
|
|
||
|
if ( ByteCount > (Fcb->FileSize.QuadPart - StartingOffset)) {
|
||
|
|
||
|
ByteCount = Fcb->FileSize.QuadPart - StartingOffset;
|
||
|
|
||
|
if (0 == ByteCount) {
|
||
|
|
||
|
try_leave( NOTHING);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// This has a peculiar interpretation, but just adjust the starting
|
||
|
// byte to the end of the visible volume.
|
||
|
//
|
||
|
|
||
|
if (WriteToEof) {
|
||
|
|
||
|
StartingOffset = Fcb->FileSize.QuadPart;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize the IoContext for the write.
|
||
|
// If there is a context pointer, we need to make sure it was
|
||
|
// allocated and not a stale stack pointer.
|
||
|
//
|
||
|
|
||
|
if (IrpContext->IoContext == NULL ||
|
||
|
!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
|
||
|
|
||
|
//
|
||
|
// If we can wait, use the context on the stack. Otherwise
|
||
|
// we need to allocate one.
|
||
|
//
|
||
|
|
||
|
if (Wait) {
|
||
|
|
||
|
IrpContext->IoContext = &LocalIoContext;
|
||
|
ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
IrpContext->IoContext = UdfAllocateIoContext();
|
||
|
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory( IrpContext->IoContext, sizeof( UDF_IO_CONTEXT ));
|
||
|
|
||
|
//
|
||
|
// Store whether we allocated this context structure in the structure
|
||
|
// itself.
|
||
|
//
|
||
|
|
||
|
IrpContext->IoContext->AllocatedContext =
|
||
|
BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
|
||
|
|
||
|
if (Wait) {
|
||
|
|
||
|
KeInitializeEvent( &IrpContext->IoContext->SyncEvent,
|
||
|
NotificationEvent,
|
||
|
FALSE );
|
||
|
|
||
|
} else {
|
||
|
|
||
|
IrpContext->IoContext->ResourceThreadId = ExGetCurrentResourceThread();
|
||
|
IrpContext->IoContext->Resource = Fcb->Resource;
|
||
|
IrpContext->IoContext->RequestedByteCount = (ULONG)ByteCount;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// For DASD we have to probe and lock the user's buffer
|
||
|
//
|
||
|
|
||
|
UdfLockUserBuffer( IrpContext, (ULONG)ByteCount, IoReadAccess );
|
||
|
|
||
|
//
|
||
|
// Set the FO_MODIFIED flag here to trigger a verify when this
|
||
|
// handle is closed. Note that we can err on the conservative
|
||
|
// side with no problem, i.e. if we accidently do an extra
|
||
|
// verify there is no problem.
|
||
|
//
|
||
|
|
||
|
SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
|
||
|
|
||
|
//
|
||
|
// Write the data and wait for the results
|
||
|
//
|
||
|
|
||
|
Irp->IoStatus.Information = (ULONG)ByteCount;
|
||
|
|
||
|
UdfSingleAsync( IrpContext,
|
||
|
StartingOffset,
|
||
|
(ULONG)ByteCount);
|
||
|
|
||
|
if (!Wait) {
|
||
|
|
||
|
//
|
||
|
// We, nor anybody else, need the IrpContext any more.
|
||
|
//
|
||
|
|
||
|
ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO);
|
||
|
|
||
|
UdfCleanupIrpContext( IrpContext, TRUE);
|
||
|
|
||
|
DebugTrace((-1, Dbg, "UdfCommonWrite -> STATUS_PENDING\n"));
|
||
|
|
||
|
try_leave( Status = STATUS_PENDING);
|
||
|
}
|
||
|
|
||
|
UdfWaitSync( IrpContext );
|
||
|
|
||
|
//
|
||
|
// If the call didn't succeed, raise the error status
|
||
|
//
|
||
|
|
||
|
Status = Irp->IoStatus.Status;
|
||
|
|
||
|
if (!NT_SUCCESS( Status)) {
|
||
|
|
||
|
UdfNormalizeAndRaiseStatus( IrpContext, Status );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update the current file position. We assume that
|
||
|
// open/create zeros out the CurrentByteOffset field.
|
||
|
//
|
||
|
|
||
|
if (SynchronousIo && !PagingIo) {
|
||
|
FileObject->CurrentByteOffset.QuadPart =
|
||
|
StartingOffset + Irp->IoStatus.Information;
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
|
||
|
UdfReleaseFile( IrpContext, Fcb);
|
||
|
|
||
|
DebugTrace((-1, Dbg, "UdfCommonWrite -> %08lx\n", Status ));
|
||
|
}
|
||
|
|
||
|
if (STATUS_PENDING != Status) {
|
||
|
|
||
|
UdfCompleteRequest( IrpContext, Irp, Status );
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
|