NT4/private/ntos/rdr/volinfo.c
2020-09-30 17:12:29 +02:00

1709 lines
49 KiB
C
Raw Blame History

This file contains invisible Unicode characters

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

/*++
Copyright (c) 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( &currentTime );
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( &currentTime );
//
// 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_