You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1286 lines
30 KiB
1286 lines
30 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|