1287 lines
29 KiB
C
1287 lines
29 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|