|
|
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
fileinfo.c
Abstract:
This module implements the get / set volume information routines for netware redirector.
Setting volume information is currently unimplemented.
Author:
Manny Weiser (mannyw) 4-Mar-1993
Revision History:
--*/
#include "procs.h"
#define NW_FS_NAME L"NWCompat"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_VOLINFO)
//
// Local procedure prototypes.
//
NTSTATUS NwCommonQueryVolumeInformation ( IN PIRP_CONTEXT pIrpContext );
NTSTATUS NwQueryAttributeInfo ( IN PVCB Vcb, IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, IN ULONG Length, OUT PULONG BytesWritten );
NTSTATUS NwQueryVolumeInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN ULONG Length, OUT PULONG BytesWritten );
NTSTATUS NwQueryLabelInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_LABEL_INFORMATION Buffer, IN ULONG Length, OUT PULONG BytesWritten );
NTSTATUS NwQuerySizeInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN ULONG Length );
NTSTATUS QueryFsSizeInfoCallback( IN PIRP_CONTEXT pIrpContext, IN ULONG BytesAvailable, IN PUCHAR Response );
NTSTATUS QueryFsSizeInfoCallback2( IN PIRP_CONTEXT pIrpContext, IN ULONG BytesAvailable, IN PUCHAR Response );
NTSTATUS NwQueryDeviceInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_DEVICE_INFORMATION Buffer, IN ULONG Length );
NTSTATUS NwCommonSetVolumeInformation ( IN PIRP_CONTEXT pIrpContext );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, NwFsdQueryVolumeInformation )
#pragma alloc_text( PAGE, NwCommonQueryVolumeInformation )
#pragma alloc_text( PAGE, NwQueryAttributeInfo )
#pragma alloc_text( PAGE, NwQueryVolumeInfo )
#pragma alloc_text( PAGE, NwQueryLabelInfo )
#pragma alloc_text( PAGE, NwQuerySizeInfo )
#pragma alloc_text( PAGE, NwQueryDeviceInfo )
#pragma alloc_text( PAGE, NwFsdSetVolumeInformation )
#pragma alloc_text( PAGE, NwCommonSetVolumeInformation )
#ifndef QFE_BUILD
#pragma alloc_text( PAGE1, QueryFsSizeInfoCallback )
#pragma alloc_text( PAGE1, QueryFsSizeInfoCallback2 )
#endif
#endif
#if 0 // Not pageable
// see ifndef QFE_BUILD above
#endif
NTSTATUS NwFsdQueryVolumeInformation ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine implements the FSD part of the NtQueryVolumeInformationFile API calls.
Arguments:
NwfsDeviceObject - 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; PIRP_CONTEXT pIrpContext = NULL; BOOLEAN TopLevel;
PAGED_CODE();
DebugTrace(+1, Dbg, "NwFsdQueryVolumeInformation\n", 0);
//
// Call the common query volume information routine.
//
FsRtlEnterFileSystem(); TopLevel = NwIsIrpTopLevel( Irp );
try {
pIrpContext = AllocateIrpContext( Irp ); status = NwCommonQueryVolumeInformation( pIrpContext );
} except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
if ( pIrpContext == NULL ) {
//
// If we couldn't allocate an irp context, just complete
// irp without any fanfare.
//
status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
} else {
//
// 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 = NwProcessException( pIrpContext, GetExceptionCode() ); }
}
if ( pIrpContext ) {
if ( status != STATUS_PENDING ) { NwDequeueIrpContext( pIrpContext, FALSE ); }
NwCompleteRequest( pIrpContext, status ); }
if ( TopLevel ) { NwSetTopLevelIrp( NULL ); } FsRtlExitFileSystem();
//
// Return to the caller.
//
DebugTrace(-1, Dbg, "NwFsdQueryVolumeInformation -> %08lx\n", status );
return status; }
NTSTATUS NwCommonQueryVolumeInformation ( IN PIRP_CONTEXT pIrpContext )
/*++
Routine Description:
This is the common routine for querying volume information.
Arguments:
IrpContext - Supplies the Irp to process
Return Value:
NTSTATUS - the return status for the operation.
--*/
{ PIRP Irp; PIO_STACK_LOCATION irpSp; NTSTATUS status;
ULONG length; ULONG bytesWritten = 0; FS_INFORMATION_CLASS fsInformationClass; PVOID buffer;
NODE_TYPE_CODE nodeTypeCode;
PVOID fsContext, fsContext2; PICB icb = NULL; PVCB vcb = NULL;
PAGED_CODE();
//
// Get the current stack location.
//
Irp = pIrpContext->pOriginalIrp; irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NwCommonQueryInformation...\n", 0); DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG_PTR)Irp); DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.QueryFile.Length); DebugTrace( 0, Dbg, " ->FsInformationClass = %08lx\n", irpSp->Parameters.QueryVolume.FsInformationClass); DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer);
//
// Find out who are.
//
if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject, &fsContext, &fsContext2 )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Handle is closing\n", 0);
NwCompleteRequest( pIrpContext, STATUS_INVALID_HANDLE ); status = STATUS_INVALID_HANDLE;
DebugTrace(-1, Dbg, "NwCommonQueryVolumeInformation -> %08lx\n", status ); return status; }
//
// Decide how to handle this request. A user can query information
// on a VCB only.
//
switch (nodeTypeCode) {
case NW_NTC_RCB: break;
case NW_NTC_ICB: icb = (PICB)fsContext2;
//
// Make sure that this ICB is still active.
//
NwVerifyIcb( icb );
vcb = icb->SuperType.Fcb->Vcb;
pIrpContext->pNpScb = icb->SuperType.Fcb->Scb->pNpScb;
break;
default: // This is not a nodetype
DebugTrace(0, Dbg, "Node type code is not incorrect\n", 0); DebugTrace(-1, Dbg, "NwCommonQueryVolumeInformation -> STATUS_INVALID_PARAMETER\n", 0);
return STATUS_INVALID_PARAMETER; }
//
// Make local copies of the input parameters.
//
length = irpSp->Parameters.QueryVolume.Length; fsInformationClass = irpSp->Parameters.QueryVolume.FsInformationClass; buffer = Irp->AssociatedIrp.SystemBuffer;
//
// It is ok to attempt a reconnect if this request fails with a
// connection error.
//
SetFlag( pIrpContext->Flags, IRP_FLAG_RECONNECTABLE );
try {
//
// Decide how to handle the request.
//
switch (fsInformationClass) {
case FileFsVolumeInformation:
status = NwQueryVolumeInfo( pIrpContext, vcb, buffer, length, &bytesWritten ); break;
case FileFsLabelInformation: status = NwQueryLabelInfo( pIrpContext, vcb, buffer, length, &bytesWritten ); break;
case FileFsSizeInformation: if ( vcb != NULL ) { status = NwQuerySizeInfo( pIrpContext, vcb, buffer, length ); } else { status = STATUS_INVALID_PARAMETER; } break;
case FileFsDeviceInformation: status = NwQueryDeviceInfo( pIrpContext, vcb, buffer, length ); bytesWritten = sizeof( FILE_FS_DEVICE_INFORMATION ); break;
case FileFsAttributeInformation:
if ( vcb != NULL ) { status = NwQueryAttributeInfo( vcb, buffer, length, &bytesWritten ); } else { status = STATUS_INVALID_PARAMETER; }
break;
default:
status = STATUS_INVALID_PARAMETER; DebugTrace(0, Dbg, "Unhandled query volume level %d\n", fsInformationClass ); break; }
//
// Set the information field to the number of bytes actually
// filled in and then complete the request.
//
// If the worker function returned status pending, it's
// callback routine will fill the information field.
//
if ( status != STATUS_PENDING ) { Irp->IoStatus.Information = bytesWritten; }
} finally {
DebugTrace(-1, Dbg, "NwCommonQueryVolumeInformation -> %08lx\n", status ); }
return status; }
NTSTATUS NwQueryAttributeInfo ( IN PVCB Vcb, IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, IN ULONG Length, OUT PULONG BytesWritten )
/*++
Routine Description:
This routine performs the query fs attribute information operation.
Arguments:
Vcb - Supplies the VCB to query.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Length - Supplies the length of the buffer in bytes.
BytesWritten - Returns the number of bytes written to the buffer.
Return Value:
NTSTATUS - The result of this query.
--*/
{ NTSTATUS status; ULONG bytesToCopy;
PAGED_CODE();
DebugTrace(0, Dbg, "QueryFsAttributeInfo...\n", 0);
//
// See how many bytes of the file system name we can copy.
//
Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0] );
*BytesWritten = FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0] );
if ( Length >= sizeof(NW_FS_NAME) - 2 ) {
status = STATUS_SUCCESS; *BytesWritten += sizeof(NW_FS_NAME - 2); bytesToCopy = sizeof( NW_FS_NAME - 2 );
} else {
status = STATUS_BUFFER_OVERFLOW; *BytesWritten += Length; bytesToCopy = Length; }
//
// Fill in the attribute information.
//
Buffer->FileSystemAttributes = 0;
if ( Vcb->Specific.Disk.LongNameSpace == LFN_NO_OS2_NAME_SPACE ) { Buffer->MaximumComponentNameLength = 12; } else { Buffer->MaximumComponentNameLength = NW_MAX_FILENAME_LENGTH; }
//
// And copy over the file name and its length.
//
RtlMoveMemory( &Buffer->FileSystemName[0], NW_FS_NAME, bytesToCopy );
Buffer->FileSystemNameLength = bytesToCopy;
return status; }
NTSTATUS NwQueryVolumeInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN ULONG Length, OUT PULONG BytesWritten )
/*++
Routine Description:
This routine performs the query fs volume information operation.
Arguments:
Vcb - The VCB to query.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Length - Supplies the length of the buffer in bytes.
Return Value:
NTSTATUS - The result of this query.
--*/
{ NTSTATUS status; UNICODE_STRING VolumeName;
PAGED_CODE();
DebugTrace(0, Dbg, "QueryVolumeInfo...\n", 0);
//
// Do the volume request synchronously.
//
if (!Vcb) { return STATUS_INVALID_PARAMETER; }
status = ExchangeWithWait( pIrpContext, SynchronousResponseCallback, "Sb", NCP_DIR_FUNCTION, NCP_GET_VOLUME_STATS, Vcb->Specific.Disk.Handle );
if ( !NT_SUCCESS( status ) ) { return status; }
//
// Get the data from the response.
//
VolumeName.MaximumLength = (USHORT)(MIN( MAX_VOLUME_NAME_LENGTH * sizeof( WCHAR ), Length - FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel) ) ); VolumeName.Buffer = Buffer->VolumeLabel;
status = ParseResponse( pIrpContext, pIrpContext->rsp, pIrpContext->ResponseLength, "N=====R", &VolumeName, MAX_VOLUME_NAME_LENGTH );
//
// Fill in the volume information.
//
Buffer->VolumeCreationTime.HighPart = 0; Buffer->VolumeCreationTime.LowPart = 0; Buffer->VolumeSerialNumber = 0; Buffer->VolumeLabelLength = VolumeName.Length; Buffer->SupportsObjects = FALSE;
pIrpContext->pOriginalIrp->IoStatus.Information = FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] ) + VolumeName.Length; *BytesWritten = (ULONG) pIrpContext->pOriginalIrp->IoStatus.Information;
pIrpContext->pOriginalIrp->IoStatus.Status = status;
//
// If the volume has been unmounted and remounted then we will
// fail this dir but the next one will be fine.
//
if (status == STATUS_UNSUCCESSFUL) { NwReopenVcbHandle( pIrpContext, Vcb); }
return status; }
NTSTATUS NwQueryLabelInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_LABEL_INFORMATION Buffer, IN ULONG Length, OUT PULONG BytesWritten )
/*++
Routine Description:
This routine performs the query fs label information operation.
Arguments:
Vcb - The VCB to query.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Length - Supplies the length of the buffer in bytes.
Return Value:
NTSTATUS - The result of this query.
--*/
{ NTSTATUS status; UNICODE_STRING VolumeName;
PAGED_CODE();
DebugTrace(0, Dbg, "QueryLabelInfo...\n", 0);
//
// Do the volume query synchronously.
//
status = ExchangeWithWait( pIrpContext, SynchronousResponseCallback, "Sb", NCP_DIR_FUNCTION, NCP_GET_VOLUME_STATS, Vcb->Specific.Disk.Handle );
if ( !NT_SUCCESS( status ) ) { return status; }
VolumeName.MaximumLength = (USHORT)(MIN( MAX_VOLUME_NAME_LENGTH * sizeof( WCHAR ), Length - FIELD_OFFSET(FILE_FS_LABEL_INFORMATION, VolumeLabel) ) ); VolumeName.Buffer = Buffer->VolumeLabel;
status = ParseResponse( pIrpContext, pIrpContext->rsp, pIrpContext->ResponseLength, "N=====R", &VolumeName, 12 );
//
// Fill in the label information.
//
Buffer->VolumeLabelLength = VolumeName.Length;
pIrpContext->pOriginalIrp->IoStatus.Information = FIELD_OFFSET( FILE_FS_LABEL_INFORMATION, VolumeLabel[0] ) + VolumeName.Length; *BytesWritten = (ULONG) pIrpContext->pOriginalIrp->IoStatus.Information;
pIrpContext->pOriginalIrp->IoStatus.Status = status;
return status;
}
NTSTATUS NwQuerySizeInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN ULONG Length )
/*++
Routine Description:
This routine performs the query fs size information operation.
Arguments:
Vcb - The VCB to query.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Length - Supplies the length of the buffer in bytes.
Return Value:
NTSTATUS - The result of this query.
--*/
{ NTSTATUS status;
PAGED_CODE();
DebugTrace(0, Dbg, "QueryFsSizeInfo...\n", 0);
//
// Remember where the response goes.
//
pIrpContext->Specific.QueryVolumeInformation.Buffer = Buffer; pIrpContext->Specific.QueryVolumeInformation.Length = Length; pIrpContext->Specific.QueryVolumeInformation.VolumeNumber = Vcb->Specific.Disk.VolumeNumber;
//
// Start a Get Size Information NCP
//
status = Exchange( pIrpContext, QueryFsSizeInfoCallback, "Sb", NCP_DIR_FUNCTION, NCP_GET_VOLUME_STATS, Vcb->Specific.Disk.Handle );
return( status ); }
NTSTATUS QueryFsSizeInfoCallback( IN PIRP_CONTEXT pIrpContext, IN ULONG BytesAvailable, IN PUCHAR Response ) /*++
Routine Description:
This routine receives the query volume size response and generates a Query Standard Information response.
Arguments:
Return Value:
VOID
--*/ { PFILE_FS_SIZE_INFORMATION Buffer; NTSTATUS Status;
DebugTrace(0, Dbg, "QueryFsSizeInfoCallback...\n", 0);
if ( BytesAvailable == 0) {
//
// We're done with this request. Dequeue the IRP context from
// SCB and complete the request.
//
NwDequeueIrpContext( pIrpContext, FALSE ); NwCompleteRequest( pIrpContext, STATUS_REMOTE_NOT_LISTENING );
//
// No response from server. Status is in pIrpContext->
// ResponseParameters.Error
//
DebugTrace( 0, Dbg, "Timeout\n", 0); return STATUS_REMOTE_NOT_LISTENING; }
//
// Get the data from the response.
//
Buffer = pIrpContext->Specific.QueryVolumeInformation.Buffer; RtlZeroMemory( Buffer, sizeof( FILE_FS_SIZE_INFORMATION ) );
Status = ParseResponse( pIrpContext, Response, BytesAvailable, "Nwww", &Buffer->SectorsPerAllocationUnit, &Buffer->TotalAllocationUnits.LowPart, &Buffer->AvailableAllocationUnits.LowPart );
if ( NT_SUCCESS( Status ) ) {
if (Buffer->TotalAllocationUnits.LowPart == 0xffff) {
//
// The next callback will fill in all the appropriate size info.
//
Status = Exchange( pIrpContext, QueryFsSizeInfoCallback2, "Sb", NCP_DIR_FUNCTION, NCP_GET_VOLUME_INFO, pIrpContext->Specific.QueryVolumeInformation.VolumeNumber );
if (Status == STATUS_PENDING) { return( STATUS_SUCCESS ); }
} else {
//
// Fill in the remaining size information.
//
Buffer->BytesPerSector = 512;
pIrpContext->pOriginalIrp->IoStatus.Information = sizeof( FILE_FS_SIZE_INFORMATION ); } }
//
// We're done with this request. Dequeue the IRP context from
// SCB and complete the request.
//
NwDequeueIrpContext( pIrpContext, FALSE ); NwCompleteRequest( pIrpContext, Status );
return STATUS_SUCCESS; }
NTSTATUS QueryFsSizeInfoCallback2( IN PIRP_CONTEXT pIrpContext, IN ULONG BytesAvailable, IN PUCHAR Response ) /*++
Routine Description:
This routine receives the query volume size response and generates a Query Standard Information response.
Arguments:
Return Value:
VOID
--*/ { PFILE_FS_SIZE_INFORMATION Buffer; NTSTATUS Status; ULONG PurgeableAllocationUnits; ULONG OriginalFreeSpace, OriginalSectorsPerAllocUnit, OriginalTotalSpace; ULONG ScaleSectorsPerUnit;
DebugTrace(0, Dbg, "QueryFsSizeInfoCallback2...\n", 0);
if ( BytesAvailable == 0) {
//
// We're done with this request. Dequeue the IRP context from
// SCB and complete the request.
//
NwDequeueIrpContext( pIrpContext, FALSE ); NwCompleteRequest( pIrpContext, STATUS_REMOTE_NOT_LISTENING );
//
// No response from server. Status is in pIrpContext->
// ResponseParameters.Error
//
DebugTrace( 0, Dbg, "Timeout\n", 0); return STATUS_REMOTE_NOT_LISTENING; }
//
// Get the data from the response. Save off the data from
// the GET_VOLUME_STATS call to compute the correct sizes.
//
Buffer = pIrpContext->Specific.QueryVolumeInformation.Buffer;
OriginalTotalSpace = Buffer->TotalAllocationUnits.LowPart; OriginalFreeSpace = Buffer->AvailableAllocationUnits.LowPart; OriginalSectorsPerAllocUnit = Buffer->SectorsPerAllocationUnit;
RtlZeroMemory( Buffer, sizeof( FILE_FS_SIZE_INFORMATION ) );
Status = ParseResponse( pIrpContext, Response, BytesAvailable, "Neee_b", &Buffer->TotalAllocationUnits.LowPart, &Buffer->AvailableAllocationUnits.LowPart, &PurgeableAllocationUnits, 16, &Buffer->SectorsPerAllocationUnit);
if ( NT_SUCCESS( Status ) ) {
//
// If the original free space was maxed out, just add the
// additionally indicated units. Otherwise, return the
// original free space (which is the correct limit) and
// adjust the sectors per allocation units if necessary.
//
if ( OriginalFreeSpace != 0xffff ) {
Buffer->AvailableAllocationUnits.LowPart = OriginalFreeSpace;
if ( ( Buffer->SectorsPerAllocationUnit != 0 ) && ( OriginalSectorsPerAllocUnit != 0 ) ) {
//
// ScaleSectorsPerUnit should always be a whole number.
// There's no floating point here!!
//
if ( (ULONG) Buffer->SectorsPerAllocationUnit <= OriginalSectorsPerAllocUnit ) {
ScaleSectorsPerUnit = OriginalSectorsPerAllocUnit / Buffer->SectorsPerAllocationUnit; Buffer->TotalAllocationUnits.LowPart /= ScaleSectorsPerUnit;
} else {
ScaleSectorsPerUnit = Buffer->SectorsPerAllocationUnit / OriginalSectorsPerAllocUnit; Buffer->TotalAllocationUnits.LowPart *= ScaleSectorsPerUnit; }
Buffer->SectorsPerAllocationUnit = OriginalSectorsPerAllocUnit; }
} else {
Buffer->AvailableAllocationUnits.QuadPart += PurgeableAllocationUnits; }
} else {
//
// If we didn't succeed the second packet, restore the original values.
//
Buffer->TotalAllocationUnits.LowPart = OriginalTotalSpace; Buffer->AvailableAllocationUnits.LowPart = OriginalFreeSpace; Buffer->SectorsPerAllocationUnit = OriginalSectorsPerAllocUnit;
}
//
// Fill in the remaining size information.
//
Buffer->BytesPerSector = 512;
pIrpContext->pOriginalIrp->IoStatus.Information = sizeof( FILE_FS_SIZE_INFORMATION );
//
// We're done with this request. Dequeue the IRP context from
// SCB and complete the request.
//
NwDequeueIrpContext( pIrpContext, FALSE ); NwCompleteRequest( pIrpContext, Status );
return STATUS_SUCCESS; }
NTSTATUS NwQueryDeviceInfo ( IN PIRP_CONTEXT pIrpContext, IN PVCB Vcb, IN PFILE_FS_DEVICE_INFORMATION Buffer, IN ULONG Length )
/*++
Routine Description:
This routine performs the query fs size information operation.
Arguments:
Vcb - The VCB to query.
Buffer - Supplies a pointer to the buffer where the information is to be returned.
Length - Supplies the length of the buffer in bytes.
Return Value:
NTSTATUS - The result of this query.
--*/
{ PAGED_CODE();
DebugTrace(0, Dbg, "QueryFsDeviceInfo...\n", 0);
//- Multi-user code merge --
// Citrix bug fix.
//
if (Vcb && FlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE)) { Buffer->DeviceType = FILE_DEVICE_PRINTER; } else { Buffer->DeviceType = FILE_DEVICE_DISK; }
Buffer->Characteristics = FILE_REMOTE_DEVICE;
return( STATUS_SUCCESS ); }
NTSTATUS NwFsdSetVolumeInformation ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++
Routine Description:
This routine implements the FSD part of the NtSetVolumeInformationFile API calls.
Arguments:
NwfsDeviceObject - 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; PIRP_CONTEXT pIrpContext = NULL; BOOLEAN TopLevel;
PAGED_CODE();
DebugTrace(+1, Dbg, "NwFsdSetVolumeInformation\n", 0);
//
// Call the common query volume information routine.
//
FsRtlEnterFileSystem(); TopLevel = NwIsIrpTopLevel( Irp );
try {
pIrpContext = AllocateIrpContext( Irp ); status = NwCommonSetVolumeInformation( pIrpContext );
} except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
if ( pIrpContext == NULL ) {
//
// If we couldn't allocate an irp context, just complete
// irp without any fanfare.
//
status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
} else {
//
// 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 = NwProcessException( pIrpContext, GetExceptionCode() ); } }
if ( pIrpContext ) {
if ( status != STATUS_PENDING ) { NwDequeueIrpContext( pIrpContext, FALSE ); }
NwCompleteRequest( pIrpContext, status ); }
if ( TopLevel ) { NwSetTopLevelIrp( NULL ); } FsRtlExitFileSystem();
//
// Return to the caller.
//
DebugTrace(-1, Dbg, "NwFsdSetVolumeInformation -> %08lx\n", status );
return status; }
NTSTATUS NwCommonSetVolumeInformation ( IN PIRP_CONTEXT pIrpContext ) /*++
Routine Description:
This is the common routine for setting volume information.
Arguments:
IrpContext - Supplies the Irp context to process
Return Value:
NTSTATUS - the return status for the operation.
--*/
{ PIRP Irp; PIO_STACK_LOCATION irpSp; NTSTATUS status;
FS_INFORMATION_CLASS fsInformationClass;
NODE_TYPE_CODE nodeTypeCode;
PVOID fsContext, fsContext2; PICB icb = NULL; PVCB vcb = NULL;
PAGED_CODE();
//
// Get the current stack location.
//
Irp = pIrpContext->pOriginalIrp; irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "NwCommonSetVolumeInformation...\n", 0); DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG_PTR)Irp); DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.QueryFile.Length); DebugTrace( 0, Dbg, " ->FsInformationClass = %08lx\n", irpSp->Parameters.QueryVolume.FsInformationClass); DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer);
//
// Find out who are.
//
if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject, &fsContext, &fsContext2 )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Handle is closing\n", 0);
NwCompleteRequest( pIrpContext, STATUS_INVALID_HANDLE ); status = STATUS_INVALID_HANDLE;
DebugTrace(-1, Dbg, "NwCommonSetVolumeInformation -> %08lx\n", status ); return status; }
//
// Decide how to handle this request. A user can set information
// on a VCB only.
//
switch (nodeTypeCode) {
case NW_NTC_RCB: break;
case NW_NTC_ICB: icb = (PICB)fsContext2;
//
// Make sure that this ICB is still active.
//
NwVerifyIcb( icb );
vcb = icb->SuperType.Fcb->Vcb;
pIrpContext->pNpScb = icb->SuperType.Fcb->Scb->pNpScb;
break;
default: // This is not a nodetype
DebugTrace(0, Dbg, "Node type code is not incorrect\n", 0); DebugTrace(-1, Dbg, "NwCommonSetVolumeInformation -> STATUS_INVALID_PARAMETER\n", 0);
return STATUS_INVALID_PARAMETER; }
fsInformationClass = irpSp->Parameters.SetVolume.FsInformationClass;
try {
//
// Decide how to handle the request.
//
switch (fsInformationClass) {
case FileFsLabelInformation:
//
// We're not allowed to set the label on a Netware volume.
//
status = STATUS_ACCESS_DENIED; break;
default:
status = STATUS_INVALID_PARAMETER; DebugTrace(0, Dbg, "Unhandled set volume level %d\n", fsInformationClass ); break; }
//
// Set the information field to the number of bytes actually
// filled in and then complete the request.
//
// If the worker function returned status pending, it's
// callback routine will fill the information field.
//
if ( status != STATUS_PENDING ) { Irp->IoStatus.Information = 0; }
} finally {
DebugTrace(-1, Dbg, "NwCommonSetVolumeInformation -> %08lx\n", status ); }
return status; }
|