/*++ 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); ASSERT( Ccb != NULL); // // 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 ((NULL == Ccb) || !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; }