|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
fileinfo.c
Abstract:
This module implements the get / set file information routines for MSFS called by the dispatch driver.
Author:
Manny Weiser (mannyw) 31-Jan-1991
Revision History:
--*/
#include "mailslot.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_FILEINFO)
//
// local procedure prototypes
//
NTSTATUS MsCommonQueryInformation ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp );
NTSTATUS MsCommonSetInformation ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp );
VOID MsQueryBasicInfo ( IN PFCB Fcb, IN PFILE_BASIC_INFORMATION Buffer );
VOID MsQueryStandardInfo ( IN PFCB Fcb, IN PFILE_STANDARD_INFORMATION Buffer );
VOID MsQueryInternalInfo ( IN PFCB Fcb, IN PFILE_INTERNAL_INFORMATION Buffer );
VOID MsQueryEaInfo ( IN PFILE_EA_INFORMATION Buffer );
NTSTATUS MsQueryNameInfo ( IN PFCB Fcb, IN PFILE_NAME_INFORMATION Buffer, IN OUT PULONG Length );
VOID MsQueryPositionInfo ( IN PFCB Fcb, IN PFILE_POSITION_INFORMATION Buffer );
VOID MsQueryMailslotInfo ( IN PFCB Fcb, IN PFILE_MAILSLOT_QUERY_INFORMATION Buffer );
NTSTATUS MsSetBasicInfo ( IN PFCB Fcb, IN PFILE_BASIC_INFORMATION Buffer );
NTSTATUS MsSetMailslotInfo ( IN PIRP Irp, IN PFCB Fcb, IN PFILE_MAILSLOT_SET_INFORMATION Buffer );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, MsCommonQueryInformation )
#pragma alloc_text( PAGE, MsCommonSetInformation )
#pragma alloc_text( PAGE, MsFsdQueryInformation )
#pragma alloc_text( PAGE, MsFsdSetInformation )
#pragma alloc_text( PAGE, MsQueryBasicInfo )
#pragma alloc_text( PAGE, MsQueryEaInfo )
#pragma alloc_text( PAGE, MsQueryInternalInfo )
#pragma alloc_text( PAGE, MsQueryMailslotInfo )
#pragma alloc_text( PAGE, MsQueryNameInfo )
#pragma alloc_text( PAGE, MsQueryPositionInfo )
#pragma alloc_text( PAGE, MsQueryStandardInfo )
#pragma alloc_text( PAGE, MsSetBasicInfo )
#pragma alloc_text( PAGE, MsSetMailslotInfo )
#endif
NTSTATUS MsFsdQueryInformation ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine implements the FSD part of the NtQueryInformationFile API calls.
Arguments:
MsfsDeviceObject - Supplies a pointer to the device object to use.
Irp - Supplies a pointer to the Irp to process.
Return Value:
NTSTATUS - The Fsd status for the Irp
--*/
{ NTSTATUS status;
PAGED_CODE(); DebugTrace(+1, Dbg, "MsFsdQueryInformation\n", 0);
//
// Call the common query information routine.
//
FsRtlEnterFileSystem();
status = MsCommonQueryInformation( MsfsDeviceObject, Irp );
FsRtlExitFileSystem();
//
// Return to the caller.
//
DebugTrace(-1, Dbg, "MsFsdQueryInformation -> %08lx\n", status );
return status; }
NTSTATUS MsFsdSetInformation ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine implements the FSD part of the NtSetInformationFile 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, "MsFsdSetInformation\n", 0);
//
// Call the common Set Information routine.
//
FsRtlEnterFileSystem();
status = MsCommonSetInformation( MsfsDeviceObject, Irp );
FsRtlExitFileSystem();
//
// Return to the caller.
//
DebugTrace(-1, Dbg, "MsFsdSetInformation -> %08lx\n", status );
return status; }
NTSTATUS MsCommonQueryInformation ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This is the common routine for querying information on a file.
Arguments:
MsfsDeviceObject - The device object to use.
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - the return status for the operation.
--*/
{ PIO_STACK_LOCATION irpSp; NTSTATUS status;
ULONG length; FILE_INFORMATION_CLASS fileInformationClass; PVOID buffer;
NODE_TYPE_CODE nodeTypeCode; PFCB fcb;
PVOID fsContext, fsContext2;
PFILE_ALL_INFORMATION AllInfo;
PAGED_CODE();
//
// Get the current stack location.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "MsCommonQueryInformation...\n", 0); DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG)Irp); DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.QueryFile.Length); DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", irpSp->Parameters.QueryFile.FileInformationClass); DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG)Irp->AssociatedIrp.SystemBuffer);
//
// Find out who are.
//
if ((nodeTypeCode = MsDecodeFileObject( irpSp->FileObject, &fsContext, &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, "MsCommonQueryInformation -> %08lx\n", status ); return status; }
//
// Decide how to handle this request. A user can query information
// on a DCB, ROOT_DCB, FCB, or CCB only.
//
switch (nodeTypeCode) {
case MSFS_NTC_FCB: // This is a server side handle to a mailslot file
case MSFS_NTC_ROOT_DCB: // This is the MSFS root directory
fcb = (PFCB)fsContext; break;
default: // This is an illegal file object to query
DebugTrace(0, Dbg, "Node type code is not incorrect\n", 0);
MsDereferenceNode( (PNODE_HEADER)fsContext );
MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
DebugTrace(-1, Dbg, "MsCommonQueryInformation -> STATUS_INVALID_PARAMETER\n", 0); return STATUS_INVALID_PARAMETER; }
//
// Make local copies of the input parameters.
//
length = irpSp->Parameters.QueryFile.Length; fileInformationClass = irpSp->Parameters.QueryFile.FileInformationClass; buffer = Irp->AssociatedIrp.SystemBuffer;
//
// Now acquire shared access to the FCB
//
MsAcquireSharedFcb( fcb );
try {
//
// Based on the information class we'll do different actions. Each
// of the procedure that we're calling fill up as much of the
// buffer as possible and return the remaining length, and status
// This is done so that we can use them to build up the
// FileAllInformation request. These procedures do not complete the
// IRP, instead this procedure must complete the IRP.
//
status = STATUS_SUCCESS;
switch (fileInformationClass) {
case FileAllInformation:
AllInfo = buffer;
MsQueryBasicInfo( fcb, &AllInfo->BasicInformation ); MsQueryStandardInfo( fcb, &AllInfo->StandardInformation ); MsQueryInternalInfo( fcb, &AllInfo->InternalInformation ); MsQueryEaInfo( &AllInfo->EaInformation ); MsQueryPositionInfo( fcb, &AllInfo->PositionInformation );
length -= FIELD_OFFSET( FILE_ALL_INFORMATION, NameInformation );
status = MsQueryNameInfo( fcb, &AllInfo->NameInformation, &length );
break;
case FileBasicInformation:
MsQueryBasicInfo( fcb, buffer );
length -= sizeof( FILE_BASIC_INFORMATION ); break;
case FileStandardInformation:
MsQueryStandardInfo( fcb, buffer );
length -= sizeof( FILE_STANDARD_INFORMATION ); break;
case FileInternalInformation:
MsQueryInternalInfo( fcb, buffer );
length -= sizeof( FILE_INTERNAL_INFORMATION ); break;
case FileEaInformation:
MsQueryEaInfo( buffer );
length -= sizeof( FILE_EA_INFORMATION ); break;
case FilePositionInformation:
MsQueryPositionInfo( fcb, buffer );
length -= sizeof( FILE_POSITION_INFORMATION );
break;
case FileNameInformation:
status = MsQueryNameInfo( fcb, buffer, &length ); break;
case FileMailslotQueryInformation:
if( nodeTypeCode == MSFS_NTC_FCB ) {
MsQueryMailslotInfo( fcb, buffer ); length -= sizeof( FILE_MAILSLOT_QUERY_INFORMATION );
} else { status = STATUS_INVALID_PARAMETER; }
break;
default:
status = STATUS_INVALID_PARAMETER; break; }
} finally {
MsReleaseFcb( fcb ); MsDereferenceFcb( fcb );
//
// Set the information field to the number of bytes actually
// filled in and then complete the request.
//
Irp->IoStatus.Information = irpSp->Parameters.QueryFile.Length - length;
MsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "MsCommonQueryInformation -> %08lx\n", status ); }
return status; }
NTSTATUS MsCommonSetInformation ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp )
/*++
Routine Description:
This is the common routine for setting information on a mailslot file.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - the return status for the operation
--*/
{ PIO_STACK_LOCATION irpSp; NTSTATUS status;
ULONG length; FILE_INFORMATION_CLASS fileInformationClass; PVOID buffer;
NODE_TYPE_CODE nodeTypeCode; PFCB fcb; PVOID fsContext2;
PAGED_CODE();
//
// Get the current Irp stack location.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "MsCommonSetInformation...\n", 0); DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG)Irp); DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.SetFile.Length); DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", irpSp->Parameters.SetFile.FileInformationClass); DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG)Irp->AssociatedIrp.SystemBuffer);
//
// Get a pointer to the FCB and ensure that this is a server side
// handler to a mailslot file.
//
if ((nodeTypeCode = MsDecodeFileObject( irpSp->FileObject, (PVOID *)&fcb, &fsContext2 )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "The mailslot is disconnected from us\n", 0);
MsCompleteRequest( Irp, STATUS_FILE_FORCED_CLOSED ); status = STATUS_FILE_FORCED_CLOSED;
DebugTrace(-1, Dbg, "MsCommonSetInformation -> %08lx\n", status ); return status; }
//
// Case on the type of the context, We can only set information
// on an FCB.
//
if (nodeTypeCode != MSFS_NTC_FCB) {
MsDereferenceNode( &fcb->Header ); MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
DebugTrace(-1, Dbg, "MsCommonQueryInformation -> STATUS_INVALID_PARAMETER\n", 0); return STATUS_INVALID_PARAMETER; }
//
// Make local copies of the input parameters.
//
length = irpSp->Parameters.SetFile.Length; fileInformationClass = irpSp->Parameters.SetFile.FileInformationClass; buffer = Irp->AssociatedIrp.SystemBuffer;
//
// Acquire exclusive access to the FCB.
//
MsAcquireExclusiveFcb( fcb );
try {
//
// Based on the information class we'll do different actions. Each
// procedure that we're calling will complete the request.
//
switch (fileInformationClass) {
case FileBasicInformation:
status = MsSetBasicInfo( fcb, buffer ); break;
case FileMailslotSetInformation:
status = MsSetMailslotInfo( Irp, fcb, buffer ); break;
default:
status = STATUS_INVALID_PARAMETER; break; }
//
// Directory information has changed. Complete any notify change
// directory requests.
//
MsCheckForNotify( fcb->ParentDcb, FALSE, STATUS_SUCCESS );
} finally {
MsReleaseFcb( fcb ); MsDereferenceFcb( fcb ); //
// Complete the request.
//
MsCompleteRequest( Irp, status );
DebugTrace(-1, Dbg, "MsCommonSetInformation -> %08lx\n", status); }
return status; }
VOID MsQueryBasicInfo ( IN PFCB Fcb, IN PFILE_BASIC_INFORMATION Buffer )
/*++
Routine Description:
This routine performs the query basic information operation.
Arguments:
Fcb - Supplies a pointer the FCB of mailslot being queried.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Return Value:
VOID
--*/
{ PAGED_CODE(); DebugTrace(0, Dbg, "QueryBasicInfo...\n", 0);
//
// Zero out the buffer.
//
RtlZeroMemory( Buffer, sizeof(FILE_BASIC_INFORMATION) );
//
// Set the various fields in the record. These times are not maintained for the root DCB0
//
if( Fcb->Header.NodeTypeCode == MSFS_NTC_FCB ) { Buffer->CreationTime = Fcb->Specific.Fcb.CreationTime; Buffer->LastAccessTime = Fcb->Specific.Fcb.LastAccessTime; Buffer->LastWriteTime = Fcb->Specific.Fcb.LastModificationTime; Buffer->ChangeTime = Fcb->Specific.Fcb.LastChangeTime; }
Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
return; }
VOID MsQueryStandardInfo ( IN PFCB Fcb, IN PFILE_STANDARD_INFORMATION Buffer )
/*++
Routine Description:
This routine performs the query standard information operation.
Arguments:
Fcb - Supplies the FCB of the mailslot being queried
Buffer - Supplies a pointer to the buffer where the information is to be returned
Return Value:
VOID
--*/
{ PDATA_QUEUE dataQueue;
PAGED_CODE(); DebugTrace(0, Dbg, "MsQueryStandardInfo...\n", 0);
//
// Zero out the buffer.
//
RtlZeroMemory( Buffer, sizeof(FILE_STANDARD_INFORMATION) );
//
// The allocation size is the amount of quota we've charged the mailslot
// creator.
//
if( Fcb->Header.NodeTypeCode == MSFS_NTC_FCB ) { dataQueue = &Fcb->DataQueue; Buffer->AllocationSize.QuadPart = dataQueue->Quota;
//
// The EOF is the number of written bytes ready to be read from the
// mailslot.
//
Buffer->EndOfFile.QuadPart = dataQueue->BytesInQueue;
Buffer->Directory = FALSE; } else { Buffer->Directory = TRUE; } Buffer->NumberOfLinks = 1; Buffer->DeletePending = TRUE;
return; }
VOID MsQueryInternalInfo ( IN PFCB Fcb, IN PFILE_INTERNAL_INFORMATION Buffer )
/*++
Routine Description:
This routine performs the query internal information operation.
Arguments:
Fcb - Supplies the FCB of the mailslot being queried.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Return Value:
VOID
--*/
{ PAGED_CODE(); DebugTrace(0, Dbg, "QueryInternalInfo...\n", 0);
//
// Zero out the buffer.
//
RtlZeroMemory( Buffer, sizeof(FILE_INTERNAL_INFORMATION) );
//
// Set the internal index number to be the address of the FCB.
//
Buffer->IndexNumber.QuadPart = (ULONG_PTR)Fcb;
return; }
VOID MsQueryEaInfo ( IN PFILE_EA_INFORMATION Buffer )
/*++
Routine Description:
This routine performs the query Ea information operation.
Arguments:
Buffer - Supplies a pointer to the buffer where the information is to be returned
Return Value:
VOID - The result of this query
--*/
{ PAGED_CODE(); DebugTrace(0, Dbg, "QueryEaInfo...\n", 0);
//
// Zero out the buffer.
//
RtlZeroMemory(Buffer, sizeof(FILE_EA_INFORMATION));
return; }
NTSTATUS MsQueryNameInfo ( IN PFCB Fcb, IN PFILE_NAME_INFORMATION Buffer, IN PULONG Length )
/*++
Routine Description:
This routine performs the query name information operation.
Arguments:
Fcb - Supplies the FCB of the mailslot to query.
Buffer - Supplies a pointer to the buffer where the information is to be returned
Length - Supplies and receives the length of the buffer in bytes.
Return Value:
NTSTATUS - The result of this query.
--*/
{ ULONG bytesToCopy; ULONG fileNameSize;
NTSTATUS status;
PAGED_CODE(); DebugTrace(0, Dbg, "QueryNameInfo...\n", 0);
//
// See if the buffer is large enough, and decide how many bytes to copy.
//
*Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName[0] );
fileNameSize = Fcb->FullFileName.Length;
if ( *Length >= fileNameSize ) {
status = STATUS_SUCCESS;
bytesToCopy = fileNameSize;
} else {
status = STATUS_BUFFER_OVERFLOW;
bytesToCopy = *Length; }
//
// Copy over the file name and its length.
//
RtlCopyMemory (Buffer->FileName, Fcb->FullFileName.Buffer, bytesToCopy);
Buffer->FileNameLength = bytesToCopy;
*Length -= bytesToCopy;
return status; }
VOID MsQueryPositionInfo ( IN PFCB Fcb, IN PFILE_POSITION_INFORMATION Buffer )
/*++
Routine Description:
This routine performs the query position information operation.
Arguments:
Fcb - Supplies the FCB of the mailslot being queried.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Return Value:
VOID
--*/
{ PDATA_QUEUE dataQueue;
PAGED_CODE(); DebugTrace(0, Dbg, "QueryPositionInfo...\n", 0);
//
// The current byte offset is the number of bytes available to read
// in the mailslot buffer.
//
if( Fcb->Header.NodeTypeCode == MSFS_NTC_FCB ) { dataQueue = &Fcb->DataQueue;
Buffer->CurrentByteOffset.QuadPart = dataQueue->BytesInQueue; } else { Buffer->CurrentByteOffset.QuadPart = 0; }
return; }
VOID MsQueryMailslotInfo ( IN PFCB Fcb, IN PFILE_MAILSLOT_QUERY_INFORMATION Buffer )
/*++
Routine Description:
This routine performs the query mailslot information operation.
Arguments:
Fcb - Supplies the Fcb of the mailslot to query.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Return Value:
VOID
--*/
{ PDATA_QUEUE dataQueue; PDATA_ENTRY dataEntry;
PAGED_CODE(); DebugTrace(0, Dbg, "QueryMailslotInfo...\n", 0);
//
// Set the fields in the record.
//
dataQueue = &Fcb->DataQueue;
Buffer->MaximumMessageSize = dataQueue->MaximumMessageSize; Buffer->MailslotQuota = dataQueue->Quota; Buffer->MessagesAvailable = dataQueue->EntriesInQueue;
Buffer->ReadTimeout = Fcb->Specific.Fcb.ReadTimeout;
if ( dataQueue->EntriesInQueue == 0 ) { Buffer->NextMessageSize = MAILSLOT_NO_MESSAGE; } else { dataEntry = CONTAINING_RECORD( dataQueue->DataEntryList.Flink, DATA_ENTRY, ListEntry );
Buffer->NextMessageSize = dataEntry->DataSize; }
return; }
NTSTATUS MsSetBasicInfo ( IN PFCB Fcb, IN PFILE_BASIC_INFORMATION Buffer )
/*++
Routine Description:
This routine sets the basic information for a mailslot.
Arguments:
Fcb - Supplies the FCB for the mailslot being modified.
Buffer - Supplies the buffer containing the data being set.
Return Value:
NTSTATUS - Returns our completion status.
--*/
{ PAGED_CODE(); DebugTrace(0, Dbg, "SetBasicInfo...\n", 0);
if (((PLARGE_INTEGER)&Buffer->CreationTime)->QuadPart != 0) {
//
// Modify the creation time
//
Fcb->Specific.Fcb.CreationTime = Buffer->CreationTime; }
if (((PLARGE_INTEGER)&Buffer->LastAccessTime)->QuadPart != 0) {
//
// Modify the last access time
//
Fcb->Specific.Fcb.LastAccessTime = Buffer->LastAccessTime; }
if (((PLARGE_INTEGER)&Buffer->LastWriteTime)->QuadPart != 0) {
//
// Modify the last write time
//
Fcb->Specific.Fcb.LastModificationTime = Buffer->LastWriteTime; }
if (((PLARGE_INTEGER)&Buffer->ChangeTime)->QuadPart != 0) {
//
// Modify the change time
//
Fcb->Specific.Fcb.LastChangeTime = Buffer->ChangeTime; }
//
// And return to our caller
//
return STATUS_SUCCESS; }
NTSTATUS MsSetMailslotInfo ( IN PIRP Irp, IN PFCB Fcb, IN PFILE_MAILSLOT_SET_INFORMATION Buffer )
/*++
Routine Description:
This routine sets the mailslot information for a mailslot.
Arguments:
Irp - Pointer to an irp that contains the requestor's mode.
Fcb - Supplies the FCB for the mailslot being modified.
Buffer - Supplies the buffer containing the data being set.
Return Value:
NTSTATUS - Returns our completion status.
--*/
{ BOOLEAN fileUpdated;
PAGED_CODE(); DebugTrace(0, Dbg, "SetMaislotInfo...\n", 0);
fileUpdated = FALSE;
//
// Check whether or not the DefaultTimeout parameter was specified. If
// so, then set it in the FCB.
//
if (ARGUMENT_PRESENT( Buffer->ReadTimeout )) {
//
// A read timeout parameter was specified. Check to see whether
// the caller's mode is kernel and if not capture the parameter inside
// of a try...except clause.
//
if (Irp->RequestorMode != KernelMode) { try { ProbeForRead( Buffer->ReadTimeout, sizeof( LARGE_INTEGER ), sizeof( ULONG ) );
Fcb->Specific.Fcb.ReadTimeout = *(Buffer->ReadTimeout);
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// Something went awry attempting to access the parameter.
// Get the reason for the error and return it as the status
// value from this service.
//
return GetExceptionCode(); } } else {
//
// The caller's mode was kernel so simply store the parameter.
//
Fcb->Specific.Fcb.ReadTimeout = *(Buffer->ReadTimeout); }
fileUpdated = TRUE; }
//
// Update the last change time, if necessary
//
if ( fileUpdated ) { KeQuerySystemTime( &Fcb->Specific.Fcb.LastChangeTime); }
//
// And return to our caller
//
return STATUS_SUCCESS; }
|