1709 lines
49 KiB
C
1709 lines
49 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
volinfo.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the NtQueryVolumeInformationFile NT API
|
||
functionality.
|
||
|
||
Author:
|
||
|
||
Colin Watson (Colinw) 24-Aug-1990
|
||
|
||
Revision History:
|
||
|
||
24-Aug-1990 Colinw
|
||
|
||
Created
|
||
|
||
--*/
|
||
#define INCLUDE_SMB_MISC
|
||
#define INCLUDE_SMB_TRANSACTION
|
||
|
||
#ifdef _CAIRO_
|
||
#define INCLUDE_SMB_QUERY_SET
|
||
#endif // _CAIRO_
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
typedef struct _CORELABELCONTEXT {
|
||
TRANCEIVE_HEADER Header; // Standard NetTranceive context header
|
||
SMB_DIRECTORY_INFORMATION Result;
|
||
} CORELABELCONTEXT, *PCORELABELCONTEXT;
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryVolumeInfo(
|
||
IN PIRP Irp OPTIONAL,
|
||
PICB Icb,
|
||
PFILE_FS_VOLUME_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QuerySizeInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_FS_SIZE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryDeviceInfo(
|
||
PICB Icb,
|
||
PFILE_FS_DEVICE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryAAttributeInfo(
|
||
PICB Icb,
|
||
PFILE_FS_ATTRIBUTE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryAttributeInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_FS_ATTRIBUTE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
NTSTATUS
|
||
ReadCoreLabel(
|
||
IN PIRP Irp OPTIONAL,
|
||
IN PICB Icb,
|
||
OUT PSMB_DIRECTORY_INFORMATION UsersBuffer
|
||
);
|
||
|
||
DBGSTATIC
|
||
STANDARD_CALLBACK_HEADER (
|
||
CoreLabelCallBack
|
||
);
|
||
|
||
#ifdef _CAIRO_
|
||
|
||
#ifdef _CAIRO_QUOTAS_
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryQuotaInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_QUOTA_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryControlInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_FS_CONTROL_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
#endif // _CAIRO_QUOTAS_
|
||
#endif // _CAIRO_
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, RdrFsdQueryVolumeInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFspQueryVolumeInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFscQueryVolumeInformationFile)
|
||
#pragma alloc_text(PAGE, QueryVolumeInfo)
|
||
#pragma alloc_text(PAGE, QueryDeviceInfo)
|
||
#pragma alloc_text(PAGE, QueryAttributeInfo)
|
||
#pragma alloc_text(PAGE, QuerySizeInfo)
|
||
#ifdef _CAIRO_
|
||
#ifdef _CAIRO_QUOTAS_
|
||
#pragma alloc_text(PAGE, QueryQuotaInfo)
|
||
#pragma alloc_text(PAGE, QueryControlInfo)
|
||
#endif // _CAIRO_QUOTAS_
|
||
#endif // _CAIRO_
|
||
#pragma alloc_text(PAGE, RdrQueryDiskQuota)
|
||
#pragma alloc_text(PAGE, RdrQueryDiskControl)
|
||
#pragma alloc_text(PAGE, ReadCoreLabel)
|
||
#pragma alloc_text(PAGE3FILE, CoreLabelCallBack)
|
||
#endif
|
||
|
||
NTSTATUS
|
||
RdrFsdQueryVolumeInformationFile (
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSD version of the NtQueryInformationFile API.
|
||
|
||
Arguments:
|
||
|
||
IN PFS_DEVICE_OBJECT DeviceObject, - Supplies the device object for this
|
||
request
|
||
IN PIRP Irp - Supplies the IRP that describes the request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
PFCB Fcb = FCB_OF(IrpSp);
|
||
|
||
PAGED_CODE();
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
dprintf(DPRT_VOLINFO|DPRT_DISPATCH, ("RdrFsdQueryVolumeInformationFile: Device: %08lx Irp:%08lx\n", DeviceObject, Irp));
|
||
|
||
Status = RdrFscQueryVolumeInformationFile(CanFsdWait(Irp), DeviceObject, Irp);
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RdrFspQueryVolumeInformationFile (
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSP version of the NtQueryVolumeInformationFile
|
||
API.
|
||
|
||
Arguments:
|
||
|
||
IN PFS_DEVICE_OBJECT DeviceObject, - Supplies the device object for this
|
||
request
|
||
IN PIRP Irp - Supplies the IRP that describes the request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
dprintf(DPRT_VOLINFO, ("RdrFspQueryVolumeInformationFile: Device: %08lx Irp:%08lx\n", DeviceObject, Irp));
|
||
|
||
return RdrFscQueryVolumeInformationFile(TRUE, DeviceObject, Irp);
|
||
}
|
||
|
||
NTSTATUS
|
||
RdrFscQueryVolumeInformationFile (
|
||
IN BOOLEAN Wait,
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the common version of the
|
||
NtQueryVolumeInformationFile API.
|
||
|
||
Arguments:
|
||
|
||
IN BOOLEAN Wait - True if routine can block waiting for the request
|
||
to complete.
|
||
|
||
IN PFS_DEVICE_OBJECT DeviceObject, - Supplies the device object for this
|
||
request
|
||
IN PIRP Irp - Supplies the IRP that describes the request
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation
|
||
|
||
Note:
|
||
|
||
This code assumes that this is a buffered I/O operation. If it is ever
|
||
implemented as a non buffered operation, then we have to put code to map
|
||
in the users buffer here.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
|
||
PVOID UsersBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||
ULONG BufferSize = IrpSp->Parameters.QueryVolume.Length;
|
||
PICB Icb = ICB_OF(IrpSp);
|
||
BOOLEAN QueueToFsp = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT (Icb->Signature == STRUCTURE_SIGNATURE_ICB);
|
||
ASSERT (Irp->Flags & IRP_BUFFERED_IO);
|
||
|
||
dprintf(DPRT_VOLINFO, ("NtQueryVolumeInformationFile File Class %ld Buffer %lx, Length %lx\n", IrpSp->Parameters.QueryVolume.FsInformationClass, UsersBuffer, BufferSize));
|
||
|
||
if (!RdrAcquireFcbLock(Icb->Fcb, SharedLock, Wait)) {
|
||
RdrFsdPostToFsp(DeviceObject, Irp);
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
try {
|
||
//
|
||
// Now make sure that the file that we are dealing with is of an
|
||
// appropriate type for us to perform this operation.
|
||
//
|
||
// We can perform these operation on any file that has an instantiation
|
||
// on the remote server, so ignore any that have either purely local
|
||
// semantics, or on tree connections.
|
||
//
|
||
|
||
Status = RdrIsOperationValid(ICB_OF(IrpSp), IRP_MJ_QUERY_VOLUME_INFORMATION, IrpSp->FileObject);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
try_return(Status);
|
||
}
|
||
|
||
switch (IrpSp->Parameters.QueryVolume.FsInformationClass) {
|
||
|
||
case FileFsVolumeInformation:
|
||
|
||
QueueToFsp = QueryVolumeInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FileFsSizeInformation:
|
||
|
||
QueueToFsp = QuerySizeInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
case FileFsDeviceInformation:
|
||
|
||
QueueToFsp = QueryDeviceInfo(Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FileFsAttributeInformation:
|
||
|
||
QueueToFsp = QueryAttributeInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
#ifdef _CAIRO_
|
||
#ifdef _CAIRO_QUOTAS_
|
||
case FileFsQuotaQueryInformation:
|
||
QueueToFsp = QueryQuotaInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FileFsControlQueryInformation:
|
||
QueueToFsp = QueryControlInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
#endif // _CAIRO_QUOTAS_
|
||
#endif // _CAIRO_
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
|
||
};
|
||
try_exit:NOTHING;
|
||
} finally {
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
}
|
||
|
||
if (QueueToFsp) {
|
||
RdrFsdPostToFsp(DeviceObject, Irp);
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
if (!NT_ERROR(Status)) {
|
||
Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length -
|
||
BufferSize;
|
||
}
|
||
|
||
dprintf(DPRT_VOLINFO, ("Returning status: %X\n", Status));
|
||
|
||
//
|
||
// Complete the I/O request with the specified status.
|
||
//
|
||
|
||
RdrCompleteRequest(Irp, Status);
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryVolumeInfo (
|
||
IN PIRP Irp OPTIONAL,
|
||
IN PICB Icb,
|
||
OUT PFILE_FS_VOLUME_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
OUT PNTSTATUS FinalStatus,
|
||
IN BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileFsVolumeInformation value of the
|
||
NtQueryVolumeInformationFile api.
|
||
|
||
It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the Icb associated with this request.
|
||
|
||
OUT PFILE_FS_VOLUME_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN OUT PULONG BufferSize - Supplies the size of the buffer, and is updated
|
||
with the amount used.
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PAGED_CODE();
|
||
|
||
if (Icb->Fcb->Connection->Server->Capabilities & DF_LANMAN20) {
|
||
|
||
//
|
||
// Use TRANSACT2_QFSINFO to get the Label and serial number
|
||
// The other information is not available.
|
||
|
||
USHORT Setup[] = {TRANS2_QUERY_FS_INFORMATION};
|
||
|
||
REQ_QUERY_FS_INFORMATION Parameters;
|
||
|
||
UCHAR Buffer[MAX(sizeof(QFSINFO), sizeof(FILE_FS_VOLUME_INFORMATION) + MAXIMUM_FILENAME_LENGTH)];
|
||
|
||
PQFSINFO FsInfo = (PQFSINFO)Buffer;
|
||
|
||
CLONG OutParameterCount = sizeof(REQ_QUERY_FS_INFORMATION);
|
||
|
||
CLONG OutDataCount = sizeof(Buffer);
|
||
|
||
CLONG OutSetupCount = 0;
|
||
|
||
if (!Wait) {
|
||
return TRUE; // FSP must process this request- we always hit the
|
||
// network and must therefore block.
|
||
}
|
||
|
||
if (Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) {
|
||
|
||
SmbPutAlignedUshort(&Parameters.InformationLevel, SMB_QUERY_FS_VOLUME_INFO);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Build and initialize the Parameters
|
||
//
|
||
|
||
SmbPutAlignedUshort(&Parameters.InformationLevel, SMB_INFO_VOLUME);
|
||
|
||
}
|
||
|
||
*FinalStatus = RdrTransact(Irp, // Irp,
|
||
Icb->Fcb->Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&Parameters,
|
||
sizeof(Parameters), // InParameterCount,
|
||
&OutParameterCount,
|
||
NULL, // InData,
|
||
0, // InDataCount,
|
||
Buffer, // OutData,
|
||
&OutDataCount,
|
||
NULL, // Fid
|
||
0, // Timeout
|
||
(USHORT) (FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? SMB_TRANSACTION_DFSFILE : 0),
|
||
0,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
if (Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) {
|
||
PFILE_FS_VOLUME_INFORMATION VolInfo = (PFILE_FS_VOLUME_INFORMATION)Buffer;
|
||
|
||
if (Icb->Fcb->Connection->Server->Capabilities & DF_UNICODE) {
|
||
|
||
if (*BufferSize < sizeof(FILE_FS_VOLUME_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Put as much as is possible into the users buffer, either
|
||
// the full information returned or the users buffer.
|
||
//
|
||
|
||
RtlCopyMemory(UsersBuffer, VolInfo, MIN(*BufferSize, OutDataCount));
|
||
|
||
//
|
||
// If the entire buffer wouldn't fit, then return an
|
||
// error.
|
||
//
|
||
|
||
if (OutDataCount > *BufferSize) {
|
||
|
||
//
|
||
// There's no more user buffer remaining.
|
||
//
|
||
|
||
*BufferSize = 0;
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Account for this buffer in the request.
|
||
//
|
||
|
||
*BufferSize -= OutDataCount;
|
||
|
||
} else {
|
||
UNICODE_STRING UnicodeString;
|
||
OEM_STRING OemString;
|
||
|
||
if (*BufferSize < OutDataCount) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Copy over the fixed portion of the buffer.
|
||
//
|
||
|
||
RtlCopyMemory(UsersBuffer, VolInfo, FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel));
|
||
|
||
OemString.Buffer = (PUCHAR)VolInfo->VolumeLabel;
|
||
OemString.Length = (USHORT)VolInfo->VolumeLabelLength;
|
||
OemString.MaximumLength = (USHORT)VolInfo->VolumeLabelLength;
|
||
|
||
UnicodeString.Buffer = UsersBuffer->VolumeLabel;
|
||
UnicodeString.MaximumLength = (USHORT)(*BufferSize - FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel));
|
||
|
||
*FinalStatus = RtlOemStringToUnicodeString(&UnicodeString, &OemString, FALSE);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
//
|
||
// Account for this buffer in the request.
|
||
//
|
||
|
||
UsersBuffer->VolumeLabelLength = UnicodeString.Length;
|
||
|
||
*BufferSize -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION,
|
||
VolumeLabel)+UsersBuffer->VolumeLabelLength;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
} else {
|
||
if (*BufferSize < sizeof(FILE_FS_VOLUME_INFORMATION)+FsInfo->cch*sizeof(WCHAR)) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
|
||
UsersBuffer->VolumeCreationTime.LowPart = 0;
|
||
UsersBuffer->VolumeCreationTime.HighPart = 0;
|
||
UsersBuffer->VolumeSerialNumber = FsInfo->ulVSN;
|
||
UsersBuffer->SupportsObjects = FALSE;
|
||
|
||
if (Icb->Fcb->Connection->Server->Capabilities & DF_UNICODE) {
|
||
PWSTR label = ALIGN_SMB_WSTR(FsInfo->szVolLabel);
|
||
wcsncpy(UsersBuffer->VolumeLabel, label, FsInfo->cch/2);
|
||
|
||
*BufferSize -= (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel)+FsInfo->cch);
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
} else {
|
||
UNICODE_STRING VolumeLabelU;
|
||
OEM_STRING VolumeLabelA;
|
||
ULONG BytesToCopy;
|
||
|
||
|
||
VolumeLabelA.Length = FsInfo->cch;
|
||
VolumeLabelA.MaximumLength = FsInfo->cch;
|
||
VolumeLabelA.Buffer = FsInfo->szVolLabel;
|
||
|
||
*FinalStatus = RtlOemStringToUnicodeString(&VolumeLabelU, &VolumeLabelA, TRUE);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
BytesToCopy = MIN((ULONG)VolumeLabelU.Length, (*BufferSize-sizeof(FILE_FS_VOLUME_INFORMATION)));
|
||
|
||
RtlCopyMemory(UsersBuffer->VolumeLabel, VolumeLabelU.Buffer, BytesToCopy);
|
||
|
||
RtlFreeUnicodeString(&VolumeLabelU);
|
||
|
||
UsersBuffer->VolumeLabelLength = VolumeLabelU.Length;
|
||
|
||
*BufferSize -= (sizeof(FILE_FS_VOLUME_INFORMATION)-1+BytesToCopy);
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// This is a < LANMAN 2.0 Server
|
||
//
|
||
|
||
UNICODE_STRING VolumeLabelU;
|
||
OEM_STRING VolumeLabelA;
|
||
SMB_DIRECTORY_INFORMATION Buffer;
|
||
ULONG NameLength;
|
||
ULONG BytesToCopy = 0;
|
||
|
||
if (!Wait) {
|
||
return TRUE; // FSP must process this request- we always hit the
|
||
// network and must therefore block.
|
||
}
|
||
|
||
*FinalStatus = ReadCoreLabel(Irp, Icb, &Buffer);
|
||
|
||
UsersBuffer->SupportsObjects = FALSE;
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
UsersBuffer->VolumeCreationTime.LowPart = 0;
|
||
UsersBuffer->VolumeCreationTime.HighPart = 0;
|
||
UsersBuffer->VolumeSerialNumber =
|
||
(((SmbGetUshort(&Buffer.LastWriteTime.Ushort)) << 16) |
|
||
(SmbGetUshort(&Buffer.LastWriteDate.Ushort)));
|
||
|
||
NAME_LENGTH(NameLength, Buffer.FileName, MAXIMUM_COMPONENT_CORE);
|
||
|
||
VolumeLabelA.Length = (USHORT )NameLength;
|
||
VolumeLabelA.MaximumLength = (USHORT )NameLength;
|
||
VolumeLabelA.Buffer = Buffer.FileName;
|
||
|
||
*FinalStatus = RtlOemStringToUnicodeString(&VolumeLabelU, &VolumeLabelA, TRUE);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
BytesToCopy = MIN((ULONG)VolumeLabelU.Length, (*BufferSize-sizeof(FILE_FS_VOLUME_INFORMATION)));
|
||
|
||
RtlCopyMemory(UsersBuffer->VolumeLabel,
|
||
VolumeLabelU.Buffer,
|
||
BytesToCopy);
|
||
|
||
if (( BytesToCopy >= (9 * sizeof(WCHAR)) ) &&
|
||
( VolumeLabelU.Buffer[8] == L'.' )) {
|
||
|
||
//
|
||
// Some downlevel servers insert a dot in the 11 byte
|
||
// volume label. Remove it.
|
||
//
|
||
|
||
|
||
if ( BytesToCopy > (9 * sizeof(WCHAR)) ) {
|
||
|
||
//
|
||
// Copy characters after dot. Use VolumeLabelU
|
||
// to get the characters to avoid using RtlMoveMemory
|
||
// instead of RtlCopyMemory.
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
&UsersBuffer->VolumeLabel[8],
|
||
&VolumeLabelU.Buffer[9],
|
||
BytesToCopy - (9 * sizeof(WCHAR)));
|
||
|
||
} // else last character was the dot
|
||
|
||
VolumeLabelU.Length -= sizeof(L'.');
|
||
|
||
BytesToCopy -= sizeof(WCHAR);
|
||
|
||
}
|
||
|
||
|
||
RtlFreeUnicodeString(&VolumeLabelU);
|
||
|
||
UsersBuffer->VolumeLabelLength = VolumeLabelU.Length;
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// If we got no such file, this means that there's no volume label
|
||
// the remote volume. Return success with no data.
|
||
//
|
||
if (*FinalStatus == STATUS_NO_SUCH_FILE) {
|
||
|
||
UsersBuffer->VolumeCreationTime.LowPart = 0;
|
||
UsersBuffer->VolumeCreationTime.HighPart = 0;
|
||
UsersBuffer->VolumeSerialNumber = 0;
|
||
UsersBuffer->VolumeLabelLength = 0;
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
|
||
VolumeLabelU.Length = 0;
|
||
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
*BufferSize -= (sizeof(FILE_FS_VOLUME_INFORMATION)-1+BytesToCopy);
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryDeviceInfo(
|
||
PICB Icb,
|
||
PFILE_FS_DEVICE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileFsSizeInformation value of the
|
||
NtQueryVolumeInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the Icb associated with this request.
|
||
|
||
OUT PFILE_FS_DEVICE_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN OUT PULONG BufferSize - Supplies the size of the buffer, and is updated
|
||
with the amount used.
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
|
||
if (*BufferSize < sizeof(FILE_FS_DEVICE_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
|
||
UsersBuffer->Characteristics = FILE_REMOTE_DEVICE;
|
||
switch (Icb->Type) {
|
||
case DiskFile:
|
||
case Directory:
|
||
case FileOrDirectory:
|
||
case NetRoot:
|
||
case ServerRoot:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_DISK;
|
||
break;
|
||
|
||
case TreeConnect:
|
||
|
||
//
|
||
// On a tree connection, we determine the type of device from
|
||
// the connection type.
|
||
//
|
||
|
||
switch (Icb->Fcb->Connection->Type) {
|
||
case CONNECT_DISK:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_DISK;
|
||
break;
|
||
case CONNECT_PRINT:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_PRINTER;
|
||
break;
|
||
case CONNECT_COMM:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_SERIAL_PORT;
|
||
break;
|
||
case CONNECT_IPC:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_NAMED_PIPE;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case Redirector:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
|
||
break;
|
||
case PrinterFile:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_PRINTER;
|
||
break;
|
||
case NamedPipe:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_NAMED_PIPE;
|
||
break;
|
||
case Com:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_SERIAL_PORT;
|
||
break;
|
||
case Mailslot:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_MAILSLOT;
|
||
break;
|
||
default:
|
||
UsersBuffer->DeviceType = FILE_DEVICE_UNKNOWN;
|
||
InternalError(("Unknown file type %lx passed to QueryDeviceInfo\n", Icb->Type));
|
||
break;
|
||
}
|
||
*BufferSize -= (sizeof(FILE_FS_DEVICE_INFORMATION));
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
return FALSE;
|
||
|
||
if (Icb||Wait);
|
||
|
||
}
|
||
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryAttributeInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_FS_ATTRIBUTE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileFsAttributeInformation value of the
|
||
NtQueryVolumeInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the Icb associated with this request.
|
||
|
||
OUT PFILE_FS_ATTRIBUTE_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN OUT PULONG BufferSize - Supplies the size of the buffer, and is updated
|
||
with the amount used.
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (*BufferSize < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
if (Icb->Fcb->Connection->Server->Capabilities & DF_NT_FIND) {
|
||
|
||
if (Icb->Fcb->Connection->MaximumComponentLength == 0) {
|
||
|
||
//
|
||
// Use TRANSACT2_QFSINFO to get the Label and serial number
|
||
// The serial number is not used.
|
||
|
||
USHORT Setup[] = {TRANS2_QUERY_FS_INFORMATION};
|
||
|
||
REQ_QUERY_FS_INFORMATION Parameters;
|
||
|
||
UCHAR Buffer[MAX(sizeof(QFSINFO), sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAXIMUM_FILENAME_LENGTH)];
|
||
|
||
PQFSINFO FsInfo = (PQFSINFO)Buffer;
|
||
|
||
CLONG OutParameterCount = sizeof(REQ_QUERY_FS_INFORMATION);
|
||
|
||
CLONG OutDataCount = sizeof(Buffer);
|
||
|
||
CLONG OutSetupCount = 0;
|
||
|
||
if (!Wait) {
|
||
return TRUE; // FSP must process this request- we always hit the
|
||
// network and must therefore block.
|
||
}
|
||
|
||
SmbPutAlignedUshort(&Parameters.InformationLevel, SMB_QUERY_FS_ATTRIBUTE_INFO);
|
||
|
||
//
|
||
// Build and initialize the Parameters
|
||
//
|
||
|
||
*FinalStatus = RdrTransact(Irp, // Irp,
|
||
Icb->Fcb->Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&Parameters,
|
||
sizeof(Parameters), // InParameterCount,
|
||
&OutParameterCount,
|
||
NULL, // InData,
|
||
0, // InDataCount,
|
||
Buffer, // OutData,
|
||
&OutDataCount,
|
||
NULL, // Fid
|
||
0, // Timeout
|
||
(USHORT) (FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? SMB_TRANSACTION_DFSFILE : 0),
|
||
0,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
PFILE_FS_ATTRIBUTE_INFORMATION AttribInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
|
||
|
||
if (*BufferSize < OutDataCount) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
RtlCopyMemory(UsersBuffer, AttribInfo, OutDataCount);
|
||
|
||
if (Icb->Fcb->Connection->MaximumComponentLength == 0) {
|
||
Icb->Fcb->Connection->MaximumComponentLength = AttribInfo->MaximumComponentNameLength;
|
||
Icb->Fcb->Connection->FileSystemAttributes = AttribInfo->FileSystemAttributes;
|
||
} else {
|
||
ASSERT(Icb->Fcb->Connection->MaximumComponentLength == AttribInfo->MaximumComponentNameLength);
|
||
ASSERT(Icb->Fcb->Connection->FileSystemAttributes == AttribInfo->FileSystemAttributes);
|
||
}
|
||
|
||
RtlCopyMemory(
|
||
Icb->Fcb->Connection->FileSystemType,
|
||
AttribInfo->FileSystemName,
|
||
MIN(AttribInfo->FileSystemNameLength, LM20_DEVLEN*sizeof(WCHAR))
|
||
);
|
||
Icb->Fcb->Connection->FileSystemTypeLength =
|
||
(USHORT)MIN(AttribInfo->FileSystemNameLength, LM20_DEVLEN*sizeof(WCHAR));
|
||
}
|
||
}
|
||
} else {
|
||
|
||
if (*BufferSize <= (ULONG)(FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName)+Icb->Fcb->Connection->FileSystemTypeLength)) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
|
||
UsersBuffer->MaximumComponentNameLength = Icb->Fcb->Connection->MaximumComponentLength;
|
||
UsersBuffer->FileSystemAttributes = Icb->Fcb->Connection->FileSystemAttributes;
|
||
|
||
RtlCopyMemory(UsersBuffer->FileSystemName, Icb->Fcb->Connection->FileSystemType, Icb->Fcb->Connection->FileSystemTypeLength);
|
||
UsersBuffer->FileSystemNameLength = Icb->Fcb->Connection->FileSystemTypeLength;
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
} else if (Icb->Fcb->Connection->Server->Capabilities & DF_LANMAN21) {
|
||
|
||
if (*BufferSize < (ULONG)(FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName)+Icb->Fcb->Connection->FileSystemTypeLength)) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
if (Icb->Fcb->Connection->FileSystemTypeLength == 0) {
|
||
|
||
//
|
||
// We don't know what type of file system this is, so
|
||
// assume the redirector defaults.
|
||
//
|
||
// wcsncmp will return 0 if the length is 0.
|
||
//
|
||
|
||
UsersBuffer->MaximumComponentNameLength = 255;
|
||
UsersBuffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES;
|
||
|
||
} else if (wcsncmp(Icb->Fcb->Connection->FileSystemType, L"FAT", Icb->Fcb->Connection->FileSystemTypeLength) == 0) {
|
||
|
||
//
|
||
// We know that this is a FAT file system.
|
||
//
|
||
|
||
UsersBuffer->MaximumComponentNameLength = 12;
|
||
UsersBuffer->FileSystemAttributes = 0;
|
||
|
||
} else if (wcsncmp(Icb->Fcb->Connection->FileSystemType, L"HPFS", Icb->Fcb->Connection->FileSystemTypeLength) == 0) {
|
||
|
||
//
|
||
// We know that this is HPFS, so we can assume it's HPFS size.
|
||
//
|
||
|
||
UsersBuffer->MaximumComponentNameLength = 254;
|
||
UsersBuffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES;
|
||
|
||
} else if (wcsncmp(Icb->Fcb->Connection->FileSystemType, L"HPFS386", Icb->Fcb->Connection->FileSystemTypeLength) == 0) {
|
||
|
||
//
|
||
// We know that this is HPFS, so we can assume it's HPFS size.
|
||
//
|
||
|
||
UsersBuffer->MaximumComponentNameLength = 254;
|
||
UsersBuffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If we could determine the type of file system on the remote
|
||
// media, we could make a better guess at this, but until we
|
||
// have this capability (LM 2.1), we have to guess.
|
||
//
|
||
|
||
UsersBuffer->MaximumComponentNameLength = 255;
|
||
UsersBuffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES;
|
||
}
|
||
|
||
RtlCopyMemory(UsersBuffer->FileSystemName, Icb->Fcb->Connection->FileSystemType, Icb->Fcb->Connection->FileSystemTypeLength);
|
||
UsersBuffer->FileSystemNameLength = Icb->Fcb->Connection->FileSystemTypeLength;
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
|
||
} else if (Icb->Fcb->Connection->Server->Capabilities & DF_LANMAN20) {
|
||
if (*BufferSize < FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName)+sizeof(DD_NFS_FILESYS_NAME_U)) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
//
|
||
// If we could determine the type of file system on the remote
|
||
// media, we could make a better guess at this, but until we
|
||
// have this capability (LM 2.1), we have to guess.
|
||
//
|
||
|
||
UsersBuffer->MaximumComponentNameLength = 255;
|
||
UsersBuffer->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES;
|
||
|
||
RtlCopyMemory(UsersBuffer->FileSystemName, DD_NFS_FILESYS_NAME_U, sizeof(DD_NFS_FILESYS_NAME_U) - sizeof(WCHAR));
|
||
UsersBuffer->FileSystemNameLength = sizeof(DD_NFS_FILESYS_NAME_U) - sizeof(WCHAR);
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
} else {
|
||
if (*BufferSize < FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName)+sizeof(L"FAT")) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
|
||
//
|
||
// We know that all non lanman 2.0 servers must have FAT
|
||
// filesystems, so we should use FAT naming conventions.
|
||
//
|
||
|
||
UsersBuffer->MaximumComponentNameLength = 12;
|
||
UsersBuffer->FileSystemAttributes = 0;
|
||
|
||
RtlCopyMemory(UsersBuffer->FileSystemName, L"FAT", sizeof(L"FAT") - sizeof(WCHAR));
|
||
UsersBuffer->FileSystemNameLength = sizeof(L"FAT") - sizeof(WCHAR);
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
*BufferSize -= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + UsersBuffer->FileSystemNameLength);
|
||
}
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
if (Icb||Wait);
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QuerySizeInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_FS_SIZE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileFsSizeInformation value of the
|
||
NtQueryVolumeInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
IN PIRP Irp - Supplies an Irp to use for this request.
|
||
|
||
IN PICB Icb - Supplies the Icb associated with this request.
|
||
|
||
OUT PFILE_FS_SIZE_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN OUT PULONG BufferSize - Supplies the size of the buffer, and is updated
|
||
with the amount used.
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
CONNECTLISTENTRY *connection = Icb->Fcb->Connection;
|
||
LARGE_INTEGER currentTime;
|
||
|
||
PAGED_CODE();
|
||
|
||
KeQuerySystemTime( ¤tTime );
|
||
|
||
if (*BufferSize < sizeof(FILE_FS_SIZE_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else if( currentTime.QuadPart <= connection->FsSizeInformationExpiration.QuadPart ) {
|
||
//
|
||
// We have the information in our cache... use it!
|
||
//
|
||
RtlCopyMemory( UsersBuffer,
|
||
&connection->FsSizeInformation,
|
||
sizeof( FILE_FS_SIZE_INFORMATION ) );
|
||
|
||
*BufferSize -= sizeof(FILE_FS_SIZE_INFORMATION);
|
||
|
||
} else {
|
||
//
|
||
// We can not use our cached information -- need to hit the server
|
||
//
|
||
|
||
if (!Wait) {
|
||
return TRUE;
|
||
}
|
||
|
||
*FinalStatus = RdrQueryDiskAttributes(Irp, Icb,
|
||
&UsersBuffer->TotalAllocationUnits,
|
||
&UsersBuffer->AvailableAllocationUnits,
|
||
&UsersBuffer->SectorsPerAllocationUnit,
|
||
&UsersBuffer->BytesPerSector);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
connection->FileSystemGranularity =
|
||
UsersBuffer->SectorsPerAllocationUnit *
|
||
UsersBuffer->BytesPerSector;
|
||
|
||
connection->FileSystemSize.QuadPart =
|
||
UsersBuffer->TotalAllocationUnits.QuadPart *
|
||
UsersBuffer->SectorsPerAllocationUnit * UsersBuffer->BytesPerSector;
|
||
|
||
*BufferSize -= sizeof(FILE_FS_SIZE_INFORMATION);
|
||
|
||
connection->FsSizeInformation.TotalAllocationUnits =
|
||
UsersBuffer->TotalAllocationUnits;
|
||
connection->FsSizeInformation.AvailableAllocationUnits =
|
||
UsersBuffer->AvailableAllocationUnits;
|
||
connection->FsSizeInformation.SectorsPerAllocationUnit =
|
||
UsersBuffer->SectorsPerAllocationUnit;
|
||
connection->FsSizeInformation.BytesPerSector =
|
||
UsersBuffer->BytesPerSector;
|
||
|
||
KeQuerySystemTime( ¤tTime );
|
||
//
|
||
// Expires in 2 seconds
|
||
//
|
||
connection->FsSizeInformationExpiration.QuadPart = currentTime.QuadPart + 2*10*1000*1000;
|
||
}
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
DBGSTATIC
|
||
NTSTATUS
|
||
ReadCoreLabel(
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PSMB_DIRECTORY_INFORMATION UsersBuffer
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine uses the search SMB to read a disk volume label and serial
|
||
number. It is used for all servers negotiating Core or Lanman 1.0.
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB with the associated SearchControlBlock
|
||
|
||
OUT PSMB_DIRECTORY_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the requested data.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation
|
||
|
||
--*/
|
||
{
|
||
|
||
PSMB_BUFFER SmbBuffer;
|
||
PSMB_HEADER Smb;
|
||
PUCHAR TrailingBytes;
|
||
NTSTATUS Status;
|
||
PREQ_SEARCH Search;
|
||
PCORELABELCONTEXT Context = NULL;
|
||
|
||
PAGED_CODE();
|
||
|
||
Context = ALLOCATE_POOL(NonPagedPool, sizeof(CORELABELCONTEXT), POOL_CORELABELCONTEXT);
|
||
|
||
if (Context == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
if ((SmbBuffer = RdrAllocateSMBBuffer()) == NULL) {
|
||
FREE_POOL(Context);
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
Smb = (PSMB_HEADER )SmbBuffer->Buffer;
|
||
Search = (PREQ_SEARCH)(Smb+1);
|
||
|
||
Smb->Command = SMB_COM_SEARCH;
|
||
Search->WordCount = 2;
|
||
SmbPutUshort(&Search->MaxCount, 1);
|
||
|
||
SmbPutUshort(&Search->SearchAttributes, SMB_FILE_ATTRIBUTE_VOLUME);
|
||
|
||
// Calculate the addresses of the various buffers.
|
||
|
||
TrailingBytes = ((PUCHAR)Search)+sizeof(REQ_SEARCH)-1;
|
||
|
||
//TrailingBytes now points to where the 0x04 of FileName is to go.
|
||
|
||
*TrailingBytes++ = SMB_FORMAT_ASCII;
|
||
|
||
Status = RdrCopyUnicodeStringToAscii( &TrailingBytes, &RdrAll8dot3Files, TRUE, MAXIMUM_FILENAME_LENGTH);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
RdrFreeSMBBuffer(SmbBuffer);
|
||
|
||
FREE_POOL(Context);
|
||
|
||
return Status;
|
||
}
|
||
|
||
*TrailingBytes++ = '\0';
|
||
|
||
*TrailingBytes++ = SMB_FORMAT_VARIABLE;
|
||
*TrailingBytes++ = 0; //smb_keylen must be zero
|
||
*TrailingBytes = 0; //smb_keylen must be zero
|
||
|
||
SmbPutUshort(&Search->ByteCount,(
|
||
(USHORT)(TrailingBytes-(PUCHAR)Search-sizeof(REQ_SEARCH)+2)
|
||
// the plus 2 is for the last smb_keylen and REQ_SEARCH.Buffer[1]
|
||
));
|
||
|
||
SmbBuffer->Mdl->ByteCount = (ULONG)(TrailingBytes - (PUCHAR)(Smb)+1);
|
||
|
||
Context->Header.Type = CONTEXT_CORE_LABEL;
|
||
Context->Header.TransferSize =
|
||
SmbBuffer->Mdl->ByteCount +
|
||
sizeof(RESP_SEARCH) +
|
||
sizeof(SMB_DIRECTORY_INFORMATION);
|
||
|
||
Status = RdrNetTranceiveWithCallback(NT_NORMAL, Irp,
|
||
Icb->Fcb->Connection,
|
||
SmbBuffer->Mdl,
|
||
Context,
|
||
CoreLabelCallBack,
|
||
Icb->Se,
|
||
NULL);
|
||
|
||
RdrFreeSMBBuffer(SmbBuffer);
|
||
|
||
if ( Status == STATUS_NO_MORE_FILES ) {
|
||
FREE_POOL(Context);
|
||
|
||
return STATUS_NO_SUCH_FILE;
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
RtlCopyMemory( UsersBuffer,
|
||
&Context->Result,
|
||
sizeof(SMB_DIRECTORY_INFORMATION));
|
||
|
||
}
|
||
|
||
FREE_POOL(Context);
|
||
|
||
return Status;
|
||
}
|
||
|
||
DBGSTATIC
|
||
STANDARD_CALLBACK_HEADER (
|
||
CoreLabelCallBack
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the callback routine for the processing of a Search SMB.
|
||
|
||
It copies the resulting information from the SMB into the context block.
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
IN PSMB_HEADER Smb - SMB response from server.
|
||
IN PMPX_ENTRY MpxTable - MPX table entry for request.
|
||
IN PCORELABELCONTEXT Context - Context from caller.
|
||
IN BOOLEAN ErrorIndicator - TRUE if error indication
|
||
IN NTSTATUS NetworkErrorCode OPTIONAL - Network error if error indication.
|
||
IN OUT PIRP *Irp - IRP from TDI
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of the request
|
||
|
||
--*/
|
||
|
||
{
|
||
PRESP_SEARCH SearchResponse;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PCORELABELCONTEXT Context = Ctx;
|
||
|
||
DISCARDABLE_CODE(RdrFileDiscardableSection);
|
||
|
||
ASSERT(Context->Header.Type == CONTEXT_CORE_LABEL);
|
||
|
||
dprintf(DPRT_DIRECTORY, ("CoreLabelComplete\n"));
|
||
|
||
Context->Header.ErrorType = NoError; // Assume no error at first.
|
||
|
||
//
|
||
// If we are called because the VC dropped, indicate it in the response
|
||
//
|
||
|
||
if (ErrorIndicator) {
|
||
Context->Header.ErrorType = NetError;
|
||
Context->Header.ErrorCode = RdrMapNetworkError(NetworkErrorCode);
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
if (!NT_SUCCESS(Status = RdrMapSmbError(Smb, Server))) {
|
||
Context->Header.ErrorType = SMBError;
|
||
Context->Header.ErrorCode = Status;
|
||
goto ReturnStatus;
|
||
}
|
||
|
||
SearchResponse = (PRESP_SEARCH )(Smb+1);
|
||
ASSERT(SearchResponse->WordCount == 1);
|
||
|
||
if (SmbGetUshort(&SearchResponse->Count) != 1) {
|
||
// If theres nothing there then on core servers count-returned == 0
|
||
Context->Header.ErrorType = SMBError;
|
||
Context->Header.ErrorCode = STATUS_NO_MORE_FILES;
|
||
goto ReturnStatus;
|
||
} else {
|
||
RtlCopyMemory(&Context->Result,
|
||
&SearchResponse->Buffer[0]+3,
|
||
sizeof(SMB_DIRECTORY_INFORMATION));
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
Context->Header.ErrorType = SMBError;
|
||
Context->Header.ErrorCode = Status;
|
||
}
|
||
|
||
// Set the event that allows CoreLabel to continue
|
||
ReturnStatus:
|
||
KeSetEvent(&Context->Header.KernelEvent, IO_NETWORK_INCREMENT, FALSE);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
if (SmbLength || MpxEntry || Irp || Server);
|
||
}
|
||
|
||
|
||
#ifdef _CAIRO_
|
||
#ifdef _CAIRO_QUOTAS_
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryQuotaInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_QUOTA_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileFsQuotaQueryInformation value of the
|
||
NtQueryVolumeInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies an Irp to use for this request.
|
||
|
||
IN PICB Icb - Supplies the Icb associated with this request.
|
||
|
||
OUT PFILE_QUOTA_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN OUT PULONG BufferSize - Supplies the size of the buffer, and is updated
|
||
with the amount used.
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (*BufferSize < sizeof(FILE_QUOTA_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
|
||
if (!Wait) {
|
||
return(TRUE);
|
||
}
|
||
|
||
*FinalStatus = RdrQueryDiskQuota(Irp, Icb, UsersBuffer, BufferSize);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
//*BufferSize -= sizeof(FILE_QUOTA_INFORMATION);
|
||
}
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryControlInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_FS_CONTROL_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileFsControlQueryInformation value of the
|
||
NtQueryVolumeInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies an Irp to use for this request.
|
||
|
||
IN PICB Icb - Supplies the Icb associated with this request.
|
||
|
||
OUT PFILE_FS_CONTROL_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN OUT PULONG BufferSize - Supplies the size of the buffer, and is updated
|
||
with the amount used.
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (*BufferSize < sizeof(FILE_FS_CONTROL_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
|
||
if (!Wait) {
|
||
return(TRUE);
|
||
}
|
||
|
||
*FinalStatus = RdrQueryDiskControl(Irp, Icb, UsersBuffer);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
*BufferSize -= sizeof(FILE_FS_CONTROL_INFORMATION);
|
||
}
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RdrQueryDiskQuota(
|
||
IN PIRP Irp OPTIONAL,
|
||
IN PICB Icb,
|
||
PFILE_QUOTA_INFORMATION UsersBuffer,
|
||
PULONG BufferSize)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns information about the file system backing a share
|
||
on the specified remote server.
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies an optional I/O Request packet to use for the
|
||
SMBdskattr request.
|
||
IN PICB Icb - Supplies an ICB associated with the file to check.
|
||
|
||
OUT PFILE_QUOTA_INFORMATION UsersBuffer - Returns the quota info
|
||
|
||
IN OUT PULONG BufferSize - Adjusted by the size returned
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
USHORT Setup[1];
|
||
REQ_QUERY_FS_INFORMATION_FID ParameterBuf;
|
||
CLONG OutParameterCount;
|
||
CLONG OutSetupCount = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
if ((Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) == 0) {
|
||
return(STATUS_INVALID_DEVICE_REQUEST);
|
||
}
|
||
|
||
//
|
||
// Use TRANSACT2_QFSINFO to get the volume size information
|
||
//
|
||
|
||
BuildTrans2QueryRequest(
|
||
Icb,
|
||
SMB_QUERY_QUOTA_INFO,
|
||
0,
|
||
Setup,
|
||
(UCHAR *) &ParameterBuf,
|
||
&OutParameterCount);
|
||
|
||
Status = RdrTransact(
|
||
Irp, // Irp,PICB
|
||
Icb->Fcb->Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&ParameterBuf,
|
||
OutParameterCount, // InParameterCount,
|
||
&OutParameterCount,
|
||
NULL, // InData,
|
||
0, // InDataCount,
|
||
UsersBuffer, // OutData,
|
||
BufferSize,
|
||
NULL, // Fid
|
||
0, // Timeout
|
||
FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? (USHORT) SMB_TRANSACTION_DFSFILE : 0,
|
||
0,
|
||
NULL,
|
||
NULL);
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RdrQueryDiskControl(
|
||
IN PIRP Irp OPTIONAL,
|
||
IN PICB Icb,
|
||
PFILE_FS_CONTROL_INFORMATION UsersBuffer)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns information about the file system backing a share
|
||
on the specified remote server.
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies an optional I/O Request packet to use for the
|
||
SMBdskattr request.
|
||
IN PICB Icb - Supplies an ICB associated with the file to check.
|
||
|
||
OUT PFILE_FS_CONTROL_INFORMATION UsersBuffer - Returns the quota info
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation performed.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
USHORT Setup[1];
|
||
REQ_QUERY_FS_INFORMATION_FID ParameterBuf;
|
||
CLONG OutParameterCount;
|
||
CLONG OutDataCount = sizeof(*UsersBuffer);
|
||
CLONG OutSetupCount = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
if ((Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) == 0) {
|
||
return(STATUS_INVALID_DEVICE_REQUEST);
|
||
}
|
||
|
||
//
|
||
// Use TRANSACT2_QFSINFO to get the volume size information
|
||
//
|
||
|
||
BuildTrans2QueryRequest(
|
||
Icb,
|
||
SMB_QUERY_FS_CONTROL_INFO,
|
||
0,
|
||
Setup,
|
||
(UCHAR *) &ParameterBuf,
|
||
&OutParameterCount);
|
||
|
||
Status = RdrTransact(
|
||
Irp, // Irp,PICB
|
||
Icb->Fcb->Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&ParameterBuf,
|
||
OutParameterCount, // InParameterCount,
|
||
&OutParameterCount,
|
||
NULL, // InData,
|
||
0, // InDataCount,
|
||
UsersBuffer, // OutData,
|
||
&OutDataCount,
|
||
NULL, // Fid
|
||
0, // Timeout
|
||
FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? (USHORT) SMB_TRANSACTION_DFSFILE : 0,
|
||
0,
|
||
NULL,
|
||
NULL);
|
||
return(Status);
|
||
}
|
||
#endif // _CAIRO_QUOTAS_
|
||
#endif // _CAIRO_
|