windows-nt/Source/XPSP1/NT/ds/nw/rdr/volinfo.c
2020-09-26 16:20:57 +08:00

1287 lines
29 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}