/*++ Copyright (c) 1989 Microsoft Corporation Module Name: fscontrl.c Abstract: This module implements the file file system control routines for MSFS called by the dispatch driver. Author: Manny Weiser (mannyw) 25-Jan-1991 Revision History: --*/ #include "mailslot.h" // // The debug trace level // #define Dbg (DEBUG_TRACE_FSCONTROL) // // local procedure prototypes // NTSTATUS MsCommonFsControl ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ); NTSTATUS MsPeek ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ); #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, MsCommonFsControl ) #pragma alloc_text( PAGE, MsFsdFsControl ) #pragma alloc_text( PAGE, MsPeek ) #endif NTSTATUS MsFsdFsControl ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of the NtFsControlFile API calls. Arguments: MsfsDeviceObject - Supplies the device object to use. Irp - Supplies the Irp being processed Return Value: NTSTATUS - The Fsd status for the Irp --*/ { NTSTATUS status; PAGED_CODE(); DebugTrace(+1, Dbg, "MsFsdFsControl\n", 0); // // Call the common file system control function. // try { status = MsCommonFsControl( MsfsDeviceObject, Irp ); } except(MsExceptionFilter( GetExceptionCode() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code. // status = MsProcessException( MsfsDeviceObject, Irp, GetExceptionCode() ); } // // Return to the caller. // DebugTrace(-1, Dbg, "MsFsdFsControl -> %08lx\n", status ); return status; } NTSTATUS MsCommonFsControl ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the common routine for handling a file system control call. Arguments: MsfsDeviceObject - A pointer to the mailslot file system device object. Irp - Supplies the Irp to process Return Value: NTSTATUS - the return status for the operation --*/ { NTSTATUS status; PIO_STACK_LOCATION irpSp; PAGED_CODE(); // // Reference our input parameters to make things easier // irpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "MsCommonFileSystemControl\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp); DebugTrace( 0, Dbg, "OutputBufferLength = %08lx\n", irpSp->Parameters.FileSystemControl.OutputBufferLength); DebugTrace( 0, Dbg, "InputBufferLength = %08lx\n", irpSp->Parameters.FileSystemControl.InputBufferLength); DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", irpSp->Parameters.FileSystemControl.FsControlCode); // // Decide how to handle this IRP. Call the appropriate worker function. // switch (irpSp->Parameters.FileSystemControl.FsControlCode) { case FSCTL_MAILSLOT_PEEK: status = MsPeek( MsfsDeviceObject, Irp ); break; default: MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); status = STATUS_INVALID_PARAMETER; } // // Return to the caller. // DebugTrace(-1, Dbg, "MsCommonFsControl -> %08lx\n", status); return status; } NTSTATUS MsPeek ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ) /*++ Routine Description: This function handles a mailslot peek call. Arguments: MsfsDeviceObject - A pointer to the mailslot file system device object. Irp - Supplies the Irp to process Return Value: NTSTATUS - the return status for the operation --*/ { NTSTATUS status; PIO_STACK_LOCATION irpSp; NODE_TYPE_CODE nodeTypeCode; PFCB fcb; PVOID fsContext2; PFILE_MAILSLOT_PEEK_BUFFER peekParamBuffer; ULONG peekParamLength; PVOID peekDataBuffer; ULONG peekDataLength; PDATA_QUEUE dataQueue; PAGED_CODE(); irpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "MsPeek\n", 0); // // Make local copies of the input parameters to make things easier. // peekParamBuffer = irpSp->Parameters.FileSystemControl.Type3InputBuffer; peekParamLength = irpSp->Parameters.FileSystemControl.InputBufferLength; peekDataBuffer = Irp->UserBuffer; peekDataLength = irpSp->Parameters.FileSystemControl.OutputBufferLength; // // Ensure that the supplied buffer is large enough for the peek // parameters. // if (peekParamLength < sizeof( FILE_MAILSLOT_PEEK_BUFFER ) ) { DebugTrace(0, Dbg, "Output buffer is too small\n", 0); MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); status = STATUS_INVALID_PARAMETER; DebugTrace(-1, Dbg, "MsPeek -> %08lx\n", status ); return status; } // // If the requestor mode is user mode we need to probe the buffers. // We do not need to have an exception handler here because our top // level caller already has one that will complete the Irp with // the appropriate status if we access violate. // if (Irp->RequestorMode != KernelMode) { try { ProbeForWrite( peekParamBuffer, peekParamLength, sizeof(UCHAR) ); ProbeForWrite( peekDataBuffer, peekDataLength, sizeof(UCHAR) ); } except(EXCEPTION_EXECUTE_HANDLER) { ExRaiseStatus( STATUS_INVALID_USER_BUFFER ); } } // // Decode the fil1e object. If it returns NTC_UNDEFINED, then the // node is closing. Otherwise we obtain a referenced pointer to // an FCB. // if ((nodeTypeCode = MsDecodeFileObject( irpSp->FileObject, (PVOID *)&fcb, &fsContext2 )) == NTC_UNDEFINED) { DebugTrace(0, Dbg, "Mailslot is disconnected from us\n", 0); MsCompleteRequest( Irp, STATUS_FILE_FORCED_CLOSED ); status = STATUS_FILE_FORCED_CLOSED; DebugTrace(-1, Dbg, "MsPeek -> %08lx\n", status ); return status; } // // Allow a peek operation only if this is a server side handle to // a mailslot file (i.e. the node type is FCB). // if (nodeTypeCode != MSFS_NTC_FCB) { DebugTrace(0, Dbg, "FileObject is not the correct type\n", 0); MsDereferenceNode( (PNODE_HEADER)fcb ); MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER ); status = STATUS_INVALID_PARAMETER; DebugTrace(-1, Dbg, "MsPeek -> %08lx\n", status ); return status; } // // Acquire exclusive access to the FCB. // MsAcquireExclusiveFcb( fcb ); try { // // Ensure that this FCB still belongs to an active open mailslot. // MsVerifyFcb( fcb ); // // Look for write data in the mailslot. // dataQueue = &fcb->DataQueue; if (!MsIsDataQueueWriters( dataQueue )) { // // There are no outstanding writes. // peekParamBuffer->ReadDataAvailable = 0; peekParamBuffer->NumberOfMessages = 0; peekParamBuffer->MessageLength = 0; status = STATUS_SUCCESS; } else { // // There is write data for the peek. Fill in the peek output // buffer. // peekParamBuffer->ReadDataAvailable = dataQueue->BytesInQueue; peekParamBuffer->NumberOfMessages = dataQueue->EntriesInQueue; Irp->IoStatus = MsReadDataQueue( dataQueue, Peek, peekDataBuffer, peekDataLength, &peekParamBuffer->MessageLength ); status = Irp->IoStatus.Status; } // // Finish up the fs control IRP. // MsCompleteRequest( Irp, status ); } finally { MsReleaseFcb( fcb ); // // Release the reference to the FCB. // MsDereferenceFcb( fcb ); DebugTrace(-1, Dbg, "MsPeek -> %08lx\n", status); } return status; }