4443 lines
129 KiB
C
4443 lines
129 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
fileinfo.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the NtQueryInformationFile and NtSetInformationFile
|
||
NT API functionality.
|
||
|
||
Author:
|
||
|
||
Larry Osterman (LarryO) 22-Aug-1990
|
||
|
||
Revision History:
|
||
|
||
22-Aug-1990 LarryO
|
||
|
||
Created
|
||
|
||
--*/
|
||
|
||
#define INCLUDE_SMB_TRANSACTION
|
||
#define INCLUDE_SMB_QUERY_SET
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryBasicInfo(
|
||
IN PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_BASIC_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryStandardInfo(
|
||
IN PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_STANDARD_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryInternalInfo(
|
||
PICB Icb,
|
||
PFILE_INTERNAL_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryEaInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_EA_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryNameInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_NAME_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryAlternateNameInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_NAME_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryPositionInfo(
|
||
PICB Icb,
|
||
PIO_STACK_LOCATION IrpSp,
|
||
PFILE_POSITION_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryStreamInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_STREAM_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryCompressionInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_COMPRESSION_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryOleAllMiscInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_OLE_ALL_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryOleInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_OLE_INFORMATION UsersBuffer,
|
||
PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetBasicInfo(
|
||
IN PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_BASIC_INFORMATION UsersBuffer,
|
||
ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetDispositionInfo(
|
||
IN PICB Icb,
|
||
OUT PFILE_DISPOSITION_INFORMATION UsersBuffer,
|
||
IN ULONG BufferSize,
|
||
IN PIRP Irp,
|
||
OUT PNTSTATUS FinalStatus,
|
||
IN BOOLEAN Wait
|
||
);
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetRenameInfo(
|
||
IN PIRP Irp OPTIONAL,
|
||
PICB Icb,
|
||
PFILE_RENAME_INFORMATION UsersBuffer,
|
||
ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait,
|
||
USHORT NtInformationLevel
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetPositionInfo(
|
||
PICB Icb,
|
||
PIO_STACK_LOCATION IrpSp,
|
||
PFILE_POSITION_INFORMATION UsersBuffer,
|
||
ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetAllocationInfo(
|
||
PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_ALLOCATION_INFORMATION UsersBuffer,
|
||
ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetEndOfFileInfo(
|
||
IN PIRP Irp,
|
||
PICB Icb,
|
||
PFILE_END_OF_FILE_INFORMATION UsersBuffer,
|
||
ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetGenericInfo(
|
||
IN PIRP Irp,
|
||
PICB Icb,
|
||
VOID *pvUsersBuffer,
|
||
ULONG cbBuffer,
|
||
ULONG cbMin,
|
||
USHORT NtInformationLevel,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, RdrFsdQueryInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFspQueryInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFscQueryInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFsdSetInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFspSetInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFscSetInformationFile)
|
||
#pragma alloc_text(PAGE, RdrFastQueryBasicInfo)
|
||
#pragma alloc_text(PAGE, RdrFastQueryStdInfo)
|
||
#pragma alloc_text(PAGE, RdrQueryNtFileInformation)
|
||
#pragma alloc_text(PAGE, RdrQueryNtPathInformation)
|
||
#pragma alloc_text(PAGE, QueryBasicInfo)
|
||
#pragma alloc_text(PAGE, QueryStandardInfo)
|
||
#pragma alloc_text(PAGE, QueryInternalInfo)
|
||
#pragma alloc_text(PAGE, QueryEaInfo)
|
||
#pragma alloc_text(PAGE, QueryNameInfo)
|
||
#pragma alloc_text(PAGE, QueryAlternateNameInfo)
|
||
#pragma alloc_text(PAGE, QueryPositionInfo)
|
||
#pragma alloc_text(PAGE, QueryStreamInfo)
|
||
#pragma alloc_text(PAGE, QueryCompressionInfo)
|
||
#pragma alloc_text(PAGE, QueryOleAllMiscInfo)
|
||
#pragma alloc_text(PAGE, QueryOleInfo)
|
||
#pragma alloc_text(PAGE, SetBasicInfo)
|
||
#pragma alloc_text(PAGE, SetRenameInfo)
|
||
#pragma alloc_text(PAGE, SetDispositionInfo)
|
||
#pragma alloc_text(PAGE, SetPositionInfo)
|
||
#pragma alloc_text(PAGE, SetAllocationInfo)
|
||
#pragma alloc_text(PAGE, SetEndOfFileInfo)
|
||
#pragma alloc_text(PAGE, SetGenericInfo)
|
||
#endif
|
||
|
||
|
||
|
||
NTSTATUS
|
||
RdrFsdQueryInformationFile (
|
||
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();
|
||
|
||
if (DeviceObject == (PFS_DEVICE_OBJECT)BowserDeviceObject) {
|
||
return BowserFsdQueryInformationFile(BowserDeviceObject, Irp);
|
||
}
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
// dprintf(DPRT_DISPATCH, ("RdrFsdQueryInformationFile: Class: %ld Irp:%08lx\n", IrpSp->Parameters.QueryFile.FileInformationClass, Irp));
|
||
|
||
Status = RdrFscQueryInformationFile(CanFsdWait(Irp), DeviceObject, Irp);
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RdrFspQueryInformationFile (
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSP version of the NtFsControlFile 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_FILEINFO, ("RdrFsdFsControlFile: Device: %08lx Irp:%08lx\n", DeviceObject, Irp));
|
||
|
||
return RdrFscQueryInformationFile(TRUE, DeviceObject, Irp);
|
||
}
|
||
|
||
NTSTATUS
|
||
RdrFscQueryInformationFile (
|
||
IN BOOLEAN Wait,
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSD version of the NtFsControlFile 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.QueryFile.Length;
|
||
PICB Icb = ICB_OF(IrpSp);
|
||
BOOLEAN QueueToFsp = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT (Icb->Signature == STRUCTURE_SIGNATURE_ICB);
|
||
|
||
// dprintf(DPRT_FILEINFO, ("NtQueryInformationFile File Class %ld Buffer %lx, Length %lx\n", IrpSp->Parameters.QueryFile.FileInformationClass, UsersBuffer, BufferSize));
|
||
|
||
RdrAcquireFcbLock(Icb->Fcb, SharedLock, TRUE);
|
||
|
||
//
|
||
// If the file has a delete operation pending on it, or does not have
|
||
// a remote instantiation, blow the request away.
|
||
//
|
||
|
||
Status = RdrIsOperationValid(ICB_OF(IrpSp), IRP_MJ_QUERY_INFORMATION, IrpSp->FileObject);
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
RdrCompleteRequest(Irp, Status);
|
||
return Status;
|
||
}
|
||
|
||
switch (IrpSp->Parameters.QueryFile.FileInformationClass) {
|
||
|
||
case FileBasicInformation:
|
||
QueueToFsp = QueryBasicInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FileStandardInformation:
|
||
QueueToFsp = QueryStandardInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
|
||
break;
|
||
|
||
case FileInternalInformation:
|
||
QueueToFsp = QueryInternalInfo(Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FileEaInformation:
|
||
QueueToFsp = QueryEaInfo(Irp,
|
||
Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FileNameInformation:
|
||
QueueToFsp = QueryNameInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FileAlternateNameInformation:
|
||
QueueToFsp = QueryAlternateNameInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FilePositionInformation:
|
||
QueueToFsp = QueryPositionInfo(Icb,
|
||
IrpSp,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
|
||
case FileOleAllInformation:
|
||
case FileAllInformation:
|
||
{
|
||
PFILE_ALL_INFORMATION AllInfo = UsersBuffer;
|
||
|
||
//
|
||
// We can assume that we will have to go to the net for this
|
||
// guy, queue it to the FSP.
|
||
//
|
||
|
||
if (!Wait) {
|
||
QueueToFsp = TRUE;
|
||
break;
|
||
}
|
||
|
||
BufferSize -= (sizeof(FILE_ALIGNMENT_INFORMATION) +
|
||
sizeof(FILE_ACCESS_INFORMATION) +
|
||
sizeof(FILE_MODE_INFORMATION) ) ;
|
||
QueryBasicInfo(Irp, Icb, &AllInfo->BasicInformation,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
QueryStandardInfo(Irp, Icb, &AllInfo->StandardInformation,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
QueryInternalInfo(Icb, &AllInfo->InternalInformation,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
QueryEaInfo(Irp, Icb, &AllInfo->EaInformation,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
if (Status != STATUS_EAS_NOT_SUPPORTED) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
QueryPositionInfo(Icb, IrpSp, &AllInfo->PositionInformation,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
if (!NT_SUCCESS(Status)) {
|
||
break;
|
||
}
|
||
|
||
if (IrpSp->Parameters.QueryFile.FileInformationClass ==
|
||
FileOleAllInformation) {
|
||
PFILE_OLE_ALL_INFORMATION OleAllInfo = UsersBuffer;
|
||
|
||
QueryOleAllMiscInfo(
|
||
Irp,
|
||
Icb,
|
||
OleAllInfo,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
} else {
|
||
|
||
QueryNameInfo(Irp, Icb, &AllInfo->NameInformation,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case FilePipeInformation:
|
||
QueueToFsp = RdrQueryNpInfo( Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status);
|
||
break;
|
||
|
||
case FilePipeLocalInformation:
|
||
QueueToFsp = RdrQueryNpLocalInfo( Irp,
|
||
Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
|
||
case FilePipeRemoteInformation:
|
||
QueueToFsp = RdrQueryNpRemoteInfo( Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status);
|
||
break;
|
||
|
||
case FileStreamInformation:
|
||
QueueToFsp = QueryStreamInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
|
||
break;
|
||
|
||
case FileCompressionInformation:
|
||
QueueToFsp = QueryCompressionInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
|
||
break;
|
||
|
||
case FileOleInformation:
|
||
QueueToFsp = QueryOleInfo(Irp, Icb,
|
||
UsersBuffer,
|
||
&BufferSize,
|
||
&Status,
|
||
Wait);
|
||
|
||
break;
|
||
|
||
#if RDRDBG
|
||
//
|
||
// Special case information fields handled in the I/O subsystem
|
||
//
|
||
|
||
case FileAlignmentInformation:
|
||
InternalError(("FileAlignmentInformation handled in I/O subsystem"));
|
||
break;
|
||
case FileAccessInformation:
|
||
InternalError(("FileAccessInformation handled in I/O subsystem"));
|
||
break;
|
||
case FileModeInformation:
|
||
InternalError(("FileModeInformation handled in I/O subsystem"));
|
||
break;
|
||
|
||
//
|
||
// Special case information fields that can never be passed on Qinfo.
|
||
//
|
||
|
||
case FileFullDirectoryInformation:
|
||
InternalError(("FileFullDirectory illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileBothDirectoryInformation:
|
||
InternalError(("FileBothDirectory illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileRenameInformation:
|
||
InternalError(("FileRename illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileMailslotQueryInformation:
|
||
InternalError(("FileMailslotQuery illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileMailslotSetInformation:
|
||
InternalError(("FileMailslotSet illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileCompletionInformation:
|
||
InternalError(("FileCompletion illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileLinkInformation:
|
||
InternalError(("FileLink illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileFullEaInformation:
|
||
InternalError(("FileFullEa illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileDirectoryInformation:
|
||
InternalError(("FileDirectory illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileNamesInformation:
|
||
InternalError(("FileNames illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileDispositionInformation:
|
||
InternalError(("FileDisposition illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileAllocationInformation:
|
||
InternalError(("FileAllocation illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileEndOfFileInformation:
|
||
InternalError(("FileEndOfFile illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileCopyOnWriteInformation:
|
||
InternalError(("FileCopyOnWrite illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileMoveClusterInformation:
|
||
InternalError(("FileMoveCluster illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileOleClassIdInformation:
|
||
InternalError(("FileOleClassId illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileOleStateBitsInformation:
|
||
InternalError(("FileOleStateBits illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileObjectIdInformation:
|
||
InternalError(("FileObjectId illegal for NtQueryInformationFile"));
|
||
break;
|
||
case FileOleDirectoryInformation:
|
||
InternalError(("FileOleDirectory illegal for NtQueryInformationFile"));
|
||
break;
|
||
#endif // RDRDBG
|
||
default:
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
|
||
};
|
||
|
||
if (QueueToFsp) {
|
||
RdrFsdPostToFsp(DeviceObject, Irp);
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
if (!NT_ERROR(Status)) {
|
||
|
||
Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length -
|
||
BufferSize;
|
||
}
|
||
|
||
// dprintf(DPRT_FILEINFO, ("Returning status: %X\n", Status));
|
||
|
||
//
|
||
// Complete the I/O request with the specified status.
|
||
//
|
||
|
||
RdrCompleteRequest(Irp, Status);
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
RdrFsdSetInformationFile (
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSD version of the NtSetInformationFile 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 = STATUS_SUCCESS;
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
PFCB Fcb = FCB_OF(IrpSp);
|
||
|
||
PAGED_CODE();
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
// dprintf(DPRT_FILEINFO, ("RdrFsdSetInformationFile: Device: %08lx Irp:%08lx\n", DeviceObject, Irp));
|
||
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
Status = RdrFscSetInformationFile(CanFsdWait(Irp), DeviceObject, Irp);
|
||
|
||
} else {
|
||
|
||
RdrCompleteRequest(Irp, Status);
|
||
}
|
||
|
||
FsRtlExitFileSystem();
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RdrFspSetInformationFile (
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSP version of the NtFsControlFile 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
|
||
|
||
--*/
|
||
|
||
{
|
||
// dprintf(DPRT_FILEINFO, ("RdrFsdSetInformationFile: Device: %08lx Irp:%08lx\n", DeviceObject, Irp));
|
||
|
||
return RdrFscSetInformationFile(TRUE, DeviceObject, Irp);
|
||
}
|
||
|
||
NTSTATUS
|
||
RdrFscSetInformationFile (
|
||
IN BOOLEAN Wait,
|
||
IN PFS_DEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the common version of the NtSetInformationFile 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;
|
||
PICB Icb = ICB_OF(IrpSp);
|
||
BOOLEAN QueueToFsp = FALSE;
|
||
ULONG cbMin = 0;
|
||
USHORT NtInformationLevel;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT (Icb->Signature == STRUCTURE_SIGNATURE_ICB);
|
||
|
||
// dprintf(DPRT_FILEINFO, ("NtSetInformationFile File Class %ld Buffer %lx\n", IrpSp->Parameters.QueryFile.FileInformationClass, UsersBuffer));
|
||
|
||
//
|
||
// If the file has a delete operation pending on it, blow away
|
||
// this request for the file.
|
||
//
|
||
|
||
Status = RdrIsOperationValid(ICB_OF(IrpSp), IRP_MJ_SET_INFORMATION, IrpSp->FileObject);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
RdrCompleteRequest(Irp, Status);
|
||
return Status;
|
||
}
|
||
|
||
Icb->Fcb->UpdatedFile = TRUE;
|
||
InterlockedIncrement( &RdrServerStateUpdated );
|
||
|
||
switch (Icb->NonPagedFcb->FileType) {
|
||
|
||
//
|
||
// NAMED PIPES======================================================
|
||
//
|
||
|
||
case FileTypeByteModePipe:
|
||
case FileTypeMessageModePipe:
|
||
switch (IrpSp->Parameters.SetFile.FileInformationClass) {
|
||
|
||
case FilePipeInformation:
|
||
QueueToFsp = RdrSetNpInfo( Irp, Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
&Status,
|
||
Wait);
|
||
|
||
break;
|
||
|
||
case FilePipeRemoteInformation:
|
||
QueueToFsp = RdrSetNpRemoteInfo( Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
&Status);
|
||
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
break;
|
||
//
|
||
// ALL OTHER FILE TYPES=============================================
|
||
//
|
||
|
||
default:
|
||
switch (IrpSp->Parameters.SetFile.FileInformationClass) {
|
||
case FileBasicInformation:
|
||
QueueToFsp = SetBasicInfo(Irp, Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
case FileDispositionInformation:
|
||
QueueToFsp = SetDispositionInfo(Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
Irp,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
case FileCopyOnWriteInformation:
|
||
case FileMoveClusterInformation:
|
||
case FileLinkInformation:
|
||
case FileRenameInformation:
|
||
QueueToFsp = SetRenameInfo(Irp, Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
&Status,
|
||
Wait,
|
||
(USHORT)IrpSp->Parameters.SetFile.FileInformationClass);
|
||
break;
|
||
case FilePositionInformation:
|
||
QueueToFsp = SetPositionInfo(Icb, IrpSp,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
case FileAllocationInformation:
|
||
QueueToFsp = SetAllocationInfo(Irp, Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
case FileEndOfFileInformation:
|
||
QueueToFsp = SetEndOfFileInfo(Irp, Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
&Status,
|
||
Wait);
|
||
break;
|
||
case FileOleClassIdInformation:
|
||
cbMin = sizeof(FILE_OLE_CLASSID_INFORMATION);
|
||
NtInformationLevel = SMB_SET_FILE_OLE_CLASSID_INFO;
|
||
break;
|
||
case FileOleStateBitsInformation:
|
||
cbMin = sizeof(FILE_OLE_STATE_BITS_INFORMATION);
|
||
NtInformationLevel = SMB_SET_FILE_OLE_STATE_BITS_INFO;
|
||
break;
|
||
case FileObjectIdInformation:
|
||
cbMin = sizeof(FILE_OBJECTID_INFORMATION);
|
||
NtInformationLevel = SMB_SET_FILE_OBJECTID_INFO;
|
||
break;
|
||
case FileContentIndexInformation:
|
||
cbMin = sizeof(BOOLEAN);
|
||
NtInformationLevel = SMB_SET_FILE_CONTENT_INDEX_INFO;
|
||
break;
|
||
case FileInheritContentIndexInformation:
|
||
cbMin = sizeof(BOOLEAN);
|
||
NtInformationLevel = SMB_SET_FILE_INHERIT_CONTENT_INDEX_INFO;
|
||
break;
|
||
case FileOleInformation:
|
||
cbMin = sizeof(FILE_OLE_INFORMATION);
|
||
NtInformationLevel = SMB_SET_FILE_OLE_INFO;
|
||
break;
|
||
|
||
#if RDRDBG
|
||
//
|
||
// Special case information fields handled in the I/O subsystem
|
||
//
|
||
|
||
case FileModeInformation:
|
||
InternalError(("FileModeInformation handled in I/O subsystem"));
|
||
break;
|
||
|
||
//
|
||
// Special case information fields that can never be passed on Qinfo.
|
||
//
|
||
|
||
case FileDirectoryInformation:
|
||
InternalError(("FileDirectory illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileFullDirectoryInformation:
|
||
InternalError(("FileFullDirectory illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileBothDirectoryInformation:
|
||
InternalError(("FileBothDirectory illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileStandardInformation:
|
||
InternalError(("FileStandard illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileInternalInformation:
|
||
InternalError(("FileInternal illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileEaInformation:
|
||
InternalError(("FileEa illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileAccessInformation:
|
||
InternalError(("FileAccess illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileNameInformation:
|
||
InternalError(("FileName illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileNamesInformation:
|
||
InternalError(("FileNames illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileFullEaInformation:
|
||
InternalError(("FileFullEa illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileAlignmentInformation:
|
||
InternalError(("FileAlignment illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileAllInformation:
|
||
InternalError(("FileAll illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileAlternateNameInformation:
|
||
InternalError(("FileAlternateName illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileStreamInformation:
|
||
InternalError(("FileStream illegal for NtSetInformationFile"));
|
||
break;
|
||
case FilePipeInformation:
|
||
InternalError(("FilePipe illegal for NtSetInformationFile"));
|
||
break;
|
||
case FilePipeLocalInformation:
|
||
InternalError(("FilePipeLocal illegal for NtSetInformationFile"));
|
||
break;
|
||
case FilePipeRemoteInformation:
|
||
InternalError(("FilePipeRemote illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileMailslotQueryInformation:
|
||
InternalError(("FileMailslotQuery illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileMailslotSetInformation:
|
||
InternalError(("FileMailslotSet illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileCompressionInformation:
|
||
InternalError(("FileCompression illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileCompletionInformation:
|
||
InternalError(("FileCompletion illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileOleAllInformation:
|
||
InternalError(("FileOleAll illegal for NtSetInformationFile"));
|
||
break;
|
||
case FileOleDirectoryInformation:
|
||
InternalError(("FileOleDirectory illegal for NtSetInformationFile"));
|
||
break;
|
||
#endif // RDRDBG
|
||
default:
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
if (cbMin != 0) {
|
||
QueueToFsp = SetGenericInfo(
|
||
Irp,
|
||
Icb,
|
||
Irp->AssociatedIrp.SystemBuffer,
|
||
IrpSp->Parameters.SetFile.Length,
|
||
cbMin,
|
||
NtInformationLevel,
|
||
&Status,
|
||
Wait);
|
||
}
|
||
}
|
||
|
||
if (QueueToFsp) {
|
||
RdrFsdPostToFsp(DeviceObject, Irp);
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
// dprintf(DPRT_FILEINFO, ("Returning status: %X\n", Status));
|
||
|
||
//
|
||
// Complete the I/O request with the specified status.
|
||
//
|
||
|
||
RdrCompleteRequest(Irp, Status);
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
RdrFastQueryBasicInfo (
|
||
IN PFILE_OBJECT FileObject,
|
||
IN BOOLEAN Wait,
|
||
IN OUT PFILE_BASIC_INFORMATION Buffer,
|
||
OUT PIO_STATUS_BLOCK IoStatus,
|
||
IN PDEVICE_OBJECT DeviceObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is for the fast query call for basic file information.
|
||
|
||
Arguments:
|
||
|
||
FileObject - Supplies the file object used in this operation
|
||
|
||
Wait - Indicates if we are allowed to wait for the information
|
||
|
||
Buffer - Supplies the output buffer to receive the basic information
|
||
|
||
IoStatus - Receives the final status of the operation
|
||
|
||
Return Value:
|
||
|
||
TRUE - Indicates the the operation succeeded with the specified
|
||
IoStatus.
|
||
|
||
FALSE - Indicates that the caller should take the long route
|
||
to do the query call.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN Results = FALSE;
|
||
BOOLEAN FcbAcquired = FALSE;
|
||
PFCB Fcb = FileObject->FsContext;
|
||
PICB Icb = FileObject->FsContext2;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT (Icb->Signature == STRUCTURE_SIGNATURE_ICB);
|
||
|
||
ASSERT (Fcb->Header.NodeTypeCode == STRUCTURE_SIGNATURE_FCB);
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
if (!RdrAcquireFcbLock(Fcb, SharedLock, Wait)) {
|
||
FsRtlExitFileSystem();
|
||
return Results;
|
||
}
|
||
|
||
FcbAcquired = TRUE;
|
||
|
||
try {
|
||
QSFILEATTRIB FileAttribs;
|
||
|
||
if (!Wait) {
|
||
if (!RdrCanFileBeBuffered(Icb) || Icb->Type != DiskFile) {
|
||
try_return( Results );
|
||
}
|
||
}
|
||
|
||
if (RdrCanFileBeBuffered(Icb) && Icb->Type == DiskFile) {
|
||
|
||
//
|
||
// If the file can be buffered, we don't have to hit the net
|
||
// to find this information out, we have it cached locally anyway!
|
||
//
|
||
|
||
ASSERT ((Fcb->Attribute & ~FILE_ATTRIBUTE_VALID_FLAGS) == 0);
|
||
|
||
try {
|
||
Buffer->CreationTime = Fcb->CreationTime;
|
||
Buffer->LastAccessTime = Fcb->LastAccessTime;
|
||
Buffer->LastWriteTime = Fcb->LastWriteTime;
|
||
Buffer->ChangeTime = Fcb->ChangeTime;
|
||
Buffer->FileAttributes = Fcb->Attribute;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
IoStatus->Status = GetExceptionCode();
|
||
IoStatus->Information = 0;
|
||
try_return(Results = FALSE);
|
||
}
|
||
|
||
IoStatus->Status = STATUS_SUCCESS;
|
||
|
||
IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
|
||
|
||
try_return(Results = TRUE);
|
||
}
|
||
|
||
//
|
||
// We can't determine the file information from the FCB, however we
|
||
// CAN tie up the users thread, so we can query it right now.
|
||
//
|
||
|
||
ASSERT (Wait);
|
||
|
||
//
|
||
// Query the file attributes over the net.
|
||
//
|
||
|
||
if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
|
||
FILE_BASIC_INFORMATION LocalBuffer;
|
||
|
||
IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
IoStatus->Status = RdrQueryNtFileInformation(
|
||
NULL,
|
||
Icb,
|
||
SMB_QUERY_FILE_BASIC_INFO,
|
||
&LocalBuffer,
|
||
&IoStatus->Information
|
||
);
|
||
} else {
|
||
IoStatus->Status = RdrQueryNtPathInformation(
|
||
NULL,
|
||
Icb,
|
||
SMB_QUERY_FILE_BASIC_INFO,
|
||
&LocalBuffer,
|
||
&IoStatus->Information
|
||
);
|
||
}
|
||
IoStatus->Information = sizeof(FILE_BASIC_INFORMATION) - IoStatus->Information;
|
||
|
||
if (NT_SUCCESS(IoStatus->Status)) {
|
||
|
||
try {
|
||
RtlCopyMemory( Buffer, &LocalBuffer, sizeof(FILE_BASIC_INFORMATION) );
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
IoStatus->Status = GetExceptionCode();
|
||
IoStatus->Information = 0;
|
||
try_return (Results = FALSE);
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
IoStatus->Status = RdrQueryFileAttributes(NULL, Icb, &FileAttribs);
|
||
|
||
if (NT_SUCCESS(IoStatus->Status)) {
|
||
|
||
ASSERT ((FileAttribs.Attributes & ~FILE_ATTRIBUTE_VALID_FLAGS) == 0);
|
||
|
||
try {
|
||
Buffer->CreationTime = FileAttribs.CreationTime;
|
||
Buffer->LastAccessTime = FileAttribs.LastAccessTime;
|
||
Buffer->LastWriteTime = FileAttribs.LastWriteTime;
|
||
Buffer->ChangeTime = FileAttribs.ChangeTime;
|
||
Buffer->FileAttributes = FileAttribs.Attributes;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
IoStatus->Status = GetExceptionCode();
|
||
IoStatus->Information = 0;
|
||
try_return (Results = FALSE);
|
||
}
|
||
|
||
}
|
||
|
||
IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
|
||
|
||
}
|
||
|
||
try_return(Results = TRUE);
|
||
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
if (FcbAcquired) {
|
||
RdrReleaseFcbLock( Fcb );
|
||
}
|
||
FsRtlExitFileSystem();
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return Results;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
RdrFastQueryStdInfo (
|
||
IN PFILE_OBJECT FileObject,
|
||
IN BOOLEAN Wait,
|
||
IN OUT PFILE_STANDARD_INFORMATION Buffer,
|
||
OUT PIO_STATUS_BLOCK IoStatus,
|
||
IN PDEVICE_OBJECT DeviceObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is for the fast query call for standard file information.
|
||
|
||
Arguments:
|
||
|
||
FileObject - Supplies the file object used in this operation
|
||
|
||
Wait - Indicates if we are allowed to wait for the information
|
||
|
||
Buffer - Supplies the output buffer to receive the basic information
|
||
|
||
IoStatus - Receives the final status of the operation
|
||
|
||
Return Value:
|
||
|
||
TRUE - Indicates the the operation succeeded with the specified
|
||
IoStatus.
|
||
|
||
FALSE - Indicates that the caller should take the long route
|
||
to do the query call.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN Results = FALSE;
|
||
BOOLEAN FcbAcquired = FALSE;
|
||
PFCB Fcb = FileObject->FsContext;
|
||
PICB Icb = FileObject->FsContext2;
|
||
PAGED_CODE();
|
||
|
||
ASSERT (Icb->Signature == STRUCTURE_SIGNATURE_ICB);
|
||
|
||
ASSERT (Fcb->Header.NodeTypeCode == STRUCTURE_SIGNATURE_FCB);
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
if (!RdrAcquireFcbLock(Fcb, SharedLock, Wait)) {
|
||
FsRtlExitFileSystem();
|
||
return Results;
|
||
}
|
||
|
||
FcbAcquired = TRUE;
|
||
|
||
try {
|
||
|
||
IoStatus->Status = RdrIsOperationValid(Icb, IRP_MJ_QUERY_INFORMATION, FileObject);
|
||
|
||
if (!NT_SUCCESS(IoStatus->Status)) {
|
||
IoStatus->Information = 0;
|
||
try_return(Results = TRUE);
|
||
}
|
||
|
||
if (!RdrCanFileBeBuffered(Icb)) {
|
||
try_return(Results);
|
||
}
|
||
|
||
Buffer->NumberOfLinks = 1; // Assume 1 links on the file.
|
||
Buffer->DeletePending = FileObject->DeletePending;
|
||
|
||
if (Icb->Type != DiskFile) {
|
||
Buffer->EndOfFile.QuadPart =
|
||
Buffer->AllocationSize.QuadPart = 0;
|
||
Buffer->Directory = (BOOLEAN)((Icb->Type == Directory) || (Icb->Type == TreeConnect));
|
||
|
||
} else {
|
||
|
||
IoStatus->Status = RdrDetermineFileAllocation(NULL,
|
||
Icb,
|
||
&Buffer->AllocationSize,
|
||
NULL);
|
||
|
||
if (!NT_SUCCESS(IoStatus->Status)) {
|
||
IoStatus->Information = 0;
|
||
try_return(Results = TRUE);
|
||
}
|
||
|
||
Buffer->EndOfFile = Icb->Fcb->Header.FileSize;
|
||
Buffer->Directory = FALSE;
|
||
}
|
||
|
||
IoStatus->Status = STATUS_SUCCESS;
|
||
|
||
IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
|
||
|
||
Results = TRUE;
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
if (FcbAcquired) {
|
||
RdrReleaseFcbLock( Fcb );
|
||
}
|
||
FsRtlExitFileSystem();
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return Results;
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryBasicInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_BASIC_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryBasicInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_BASIC_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.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
QSFILEATTRIB FileAttribs;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!RdrAcquireFcbLock(Icb->Fcb, SharedLock, Wait)) {
|
||
return TRUE;
|
||
}
|
||
|
||
if (Icb->Type == DiskFile &&
|
||
RdrCanFileBeBuffered(Icb)) {
|
||
|
||
//
|
||
// If the file can be buffered, we don't have to hit the net
|
||
// to find this information out, we have it cached locally anyway!
|
||
//
|
||
|
||
UsersBuffer->CreationTime = Icb->Fcb->CreationTime;
|
||
UsersBuffer->LastAccessTime = Icb->Fcb->LastAccessTime;
|
||
UsersBuffer->LastWriteTime = Icb->Fcb->LastWriteTime;
|
||
UsersBuffer->ChangeTime = Icb->Fcb->ChangeTime;
|
||
UsersBuffer->FileAttributes = Icb->Fcb->Attribute;
|
||
|
||
ASSERT ((Icb->Fcb->Attribute & ~FILE_ATTRIBUTE_VALID_FLAGS) == 0);
|
||
|
||
*BufferSize -= sizeof(FILE_BASIC_INFORMATION);
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
if (!Wait) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_BASIC_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
} else {
|
||
*FinalStatus = RdrQueryNtPathInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_BASIC_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
*FinalStatus = RdrQueryFileAttributes(Irp, Icb, &FileAttribs);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
UsersBuffer->CreationTime = FileAttribs.CreationTime;
|
||
UsersBuffer->LastAccessTime = FileAttribs.LastAccessTime;
|
||
UsersBuffer->LastWriteTime = FileAttribs.LastWriteTime;
|
||
UsersBuffer->ChangeTime = FileAttribs.ChangeTime;
|
||
UsersBuffer->FileAttributes = FileAttribs.Attributes;
|
||
|
||
ASSERT ((FileAttribs.Attributes & ~FILE_ATTRIBUTE_VALID_FLAGS) == 0);
|
||
|
||
*BufferSize -= sizeof(FILE_BASIC_INFORMATION);
|
||
}
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryStandardInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_STANDARD_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryStandardInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_STANDARD_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. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
QSFILEATTRIB FileAttribs;
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
UsersBuffer->NumberOfLinks = 1; // Assume 1 links on the file.
|
||
UsersBuffer->DeletePending = IrpSp->FileObject->DeletePending;
|
||
|
||
if (!RdrAcquireFcbLock(Icb->Fcb, SharedLock, Wait)) {
|
||
return TRUE;
|
||
}
|
||
|
||
if (Icb->Type != FileOrDirectory) {
|
||
UsersBuffer->Directory = (BOOLEAN )((Icb->Type == Directory) || (Icb->Type == TreeConnect));
|
||
|
||
//
|
||
// If this is not a disk file, then it has no size, and we should
|
||
// return 0 as the end of file and allocation size.
|
||
//
|
||
|
||
if (Icb->Type != DiskFile) {
|
||
UsersBuffer->EndOfFile.QuadPart =
|
||
UsersBuffer->AllocationSize.QuadPart = 0;
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
|
||
*BufferSize -= sizeof(FILE_STANDARD_INFORMATION);
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
if (RdrCanFileBeBuffered(Icb)) {
|
||
|
||
*FinalStatus = RdrDetermineFileAllocation(Irp, Icb, &UsersBuffer->AllocationSize, NULL);
|
||
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
return FALSE;
|
||
}
|
||
|
||
UsersBuffer->EndOfFile = Icb->Fcb->Header.FileSize;
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
|
||
*BufferSize -= sizeof(FILE_STANDARD_INFORMATION);
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
}
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
//
|
||
// We have to go to the net to find out the size of the file. If we
|
||
// cannot block the user's thread, pass the request to the FSP.
|
||
//
|
||
|
||
if (!Wait) {
|
||
return TRUE;
|
||
}
|
||
|
||
if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_STANDARD_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
} else {
|
||
*FinalStatus = RdrQueryNtPathInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_STANDARD_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
|
||
//
|
||
// Determine the file's size using a GetExpandedAttributes
|
||
// SMB.
|
||
//
|
||
|
||
*FinalStatus = RdrQueryFileAttributes(Irp, Icb, &FileAttribs);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
//
|
||
// If we don't know the type of this file, we want to
|
||
// find out whether or not it is a directory by looking at
|
||
// the attributes to see if the file is a directory.
|
||
//
|
||
|
||
if (Icb->Type == FileOrDirectory) {
|
||
UsersBuffer->Directory = (BOOLEAN)(FileAttribs.Attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||
} else {
|
||
UsersBuffer->Directory = (BOOLEAN)((Icb->Type == Directory) || (Icb->Type == TreeConnect));
|
||
}
|
||
|
||
UsersBuffer->AllocationSize.QuadPart = FileAttribs.AllocationSize;
|
||
UsersBuffer->EndOfFile.QuadPart = FileAttribs.FileSize;
|
||
*BufferSize -= sizeof(FILE_STANDARD_INFORMATION);
|
||
} else {
|
||
dprintf(DPRT_FILEINFO, ("RdrQueryFileAttributes(%wZ) failed, Status=%X\n",
|
||
&Icb->Fcb->FileName, *FinalStatus));
|
||
}
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryStreamInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_STREAM_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryBasicInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_STREAM_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 (!Wait) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_STREAM_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
} else {
|
||
*FinalStatus = RdrQueryNtPathInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_STREAM_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
*FinalStatus = STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryCompressionInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_COMPRESSION_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileCompressionInformation value of the
|
||
NtQueryInformationFile API.
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies the IRP associated with this request.
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_COMPRESSION_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:
|
||
|
||
BOOLEAN - Indicates whether the IRP should be posted.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if ( !Wait ) {
|
||
return TRUE;
|
||
}
|
||
|
||
if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_COMPRESSION_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
} else {
|
||
*FinalStatus = RdrQueryNtPathInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_COMPRESSION_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
}
|
||
|
||
} else {
|
||
|
||
*FinalStatus = STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryOleAllMiscInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_OLE_ALL_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements selected portions of FileQueryOleAllInformation
|
||
of the NtQueryInformationFile api.
|
||
It returns the following information:
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_OLE_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();
|
||
|
||
ASSERT (!ExIsResourceAcquiredExclusive(Icb->Fcb->Header.Resource));
|
||
|
||
if (!Wait) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if ((Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) &&
|
||
(Icb->Flags & ICB_HASHANDLE)) {
|
||
|
||
FILE_OLE_ALL_INFORMATION *pfoai;
|
||
|
||
//
|
||
// We are going to ask the remote server for OLE_ALL_INFORMATION.
|
||
// We do not want to perturb the contents of the user's buffer that
|
||
// have been filled in so far. So, we allocate a new
|
||
// OLE_ALL_INFORMATION struct, get the info in it, and then copy only
|
||
// a subpart to the user's buffer.
|
||
//
|
||
// We will copy everything from the LastChangeUsn field of the struct.
|
||
//
|
||
// Hence, we need to allocate *BufferSize + field offset of
|
||
// LastChangeUsn bytes.
|
||
//
|
||
|
||
ULONG cb = *BufferSize + FIELD_OFFSET(FILE_OLE_ALL_INFORMATION, LastChangeUsn);
|
||
|
||
pfoai = ALLOCATE_POOL(PagedPool, cb, POOL_OLE_ALL_BUFFER);
|
||
if (pfoai == NULL) {
|
||
|
||
*FinalStatus = STATUS_NO_MEMORY;
|
||
|
||
} else {
|
||
try {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_OLE_ALL_INFO,
|
||
pfoai,
|
||
&cb);
|
||
if (NT_SUCCESS(*FinalStatus)
|
||
||
|
||
*FinalStatus == STATUS_BUFFER_OVERFLOW) {
|
||
|
||
ULONG cbCopy;
|
||
|
||
UsersBuffer->InternalInformation.IndexNumber =
|
||
pfoai->InternalInformation.IndexNumber;
|
||
|
||
cbCopy = FIELD_OFFSET(
|
||
FILE_OLE_ALL_INFORMATION,
|
||
NameInformation.FileName[0]) +
|
||
pfoai->NameInformation.FileNameLength -
|
||
FIELD_OFFSET( FILE_OLE_ALL_INFORMATION, LastChangeUsn);
|
||
|
||
if (cbCopy > *BufferSize) {
|
||
cbCopy = *BufferSize;
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
RtlCopyMemory(&UsersBuffer->LastChangeUsn, &pfoai->LastChangeUsn, cbCopy);
|
||
*BufferSize -= cbCopy;
|
||
}
|
||
|
||
} finally {
|
||
|
||
FREE_POOL(pfoai);
|
||
}
|
||
}
|
||
} else {
|
||
|
||
*FinalStatus = STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
ASSERT (!ExIsResourceAcquiredExclusive(Icb->Fcb->Header.Resource));
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryOleInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_OLE_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryOleInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_OLE_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 (!Wait) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_OLE_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
} else {
|
||
*FinalStatus = RdrQueryNtPathInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_OLE_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
}
|
||
|
||
} else {
|
||
ULONG TransferSize = min(sizeof(*UsersBuffer), *BufferSize);
|
||
|
||
RtlZeroMemory(UsersBuffer, TransferSize);
|
||
*FinalStatus = (sizeof(*UsersBuffer) > *BufferSize)?
|
||
STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
|
||
*BufferSize -= TransferSize;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
RdrQueryNtFileInformation(
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
IN USHORT FileInformationClass,
|
||
IN OUT PVOID Buffer,
|
||
IN OUT PULONG BufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine remotes a simple NtQueryInformationFile API to the server.
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies an IRP to use for the request.
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
IN USHORT FileInformationClass - Information class to query.
|
||
OUT PVOID 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.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Use TRANSACT2_QFILEINFO to query FileInformationClass.
|
||
//
|
||
|
||
USHORT Setup[] = {TRANS2_QUERY_FILE_INFORMATION};
|
||
|
||
REQ_QUERY_FILE_INFORMATION Parameters;
|
||
|
||
CLONG OutParameterCount;
|
||
CLONG OutDataCount;
|
||
CLONG OutSetupCount;
|
||
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT( sizeof(REQ_QUERY_FILE_INFORMATION) >= sizeof(RESP_QUERY_FILE_INFORMATION) );
|
||
OutParameterCount = sizeof(RESP_QUERY_FILE_INFORMATION);
|
||
OutDataCount = *BufferSize;
|
||
OutSetupCount = 0;
|
||
|
||
SmbPutAlignedUshort(&Parameters.InformationLevel, FileInformationClass);
|
||
|
||
SmbPutAlignedUshort(&Parameters.Fid, Icb->FileId);
|
||
|
||
Status = 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,
|
||
&Icb->FileId, // Fid
|
||
0, // Timeout
|
||
(USHORT) (FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? SMB_TRANSACTION_DFSFILE : 0),
|
||
0, // NtTransactionFunction
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (Status == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
*BufferSize -= OutDataCount;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
RdrQueryNtPathInformation(
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
IN USHORT FileInformationClass,
|
||
IN OUT PVOID Buffer,
|
||
IN OUT PULONG BufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine remotes a simple NtQueryInformationFile API to the server.
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies an IRP to use for the request.
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
IN USHORT FileInformationClass - Information class to query.
|
||
OUT PVOID 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.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Use TRANSACT2_QPATHINFO to query FileInformationClass.
|
||
//
|
||
|
||
USHORT Setup[] = {TRANS2_QUERY_PATH_INFORMATION};
|
||
|
||
PREQ_QUERY_PATH_INFORMATION Parameters;
|
||
PUCHAR Path;
|
||
PCONNECTLISTENTRY Connect = Icb->Fcb->Connection;
|
||
LARGE_INTEGER currentTime;
|
||
|
||
CLONG InParameterCount;
|
||
CLONG OutParameterCount;
|
||
CLONG OutDataCount;
|
||
CLONG OutSetupCount;
|
||
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
KeQuerySystemTime( ¤tTime );
|
||
|
||
if( currentTime.QuadPart <= Connect->CachedInvalidPathExpiration.QuadPart &&
|
||
RdrStatistics.SmbsTransmitted.LowPart == Connect->CachedInvalidSmbCount &&
|
||
RtlEqualUnicodeString( &Icb->Fcb->FileName, &Connect->CachedInvalidPath, TRUE ) ) {
|
||
|
||
//
|
||
// We know that this file does not exist on the server, so return error right now
|
||
//
|
||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||
}
|
||
|
||
InParameterCount = sizeof(REQ_QUERY_FILE_INFORMATION) + Icb->Fcb->FileName.Length;
|
||
Parameters = ALLOCATE_POOL( NonPagedPool, InParameterCount, POOL_PATH_BUFFER );
|
||
if ( Parameters == NULL ) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
Path = Parameters->Buffer;
|
||
Status = RdrCopyNetworkPath(
|
||
&Path,
|
||
&Icb->Fcb->FileName,
|
||
Connect->Server,
|
||
0,
|
||
SKIP_SERVER_SHARE
|
||
);
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
FREE_POOL( Parameters );
|
||
return Status;
|
||
}
|
||
|
||
InParameterCount = (ULONG)(Path - (PUCHAR)Parameters);
|
||
ASSERT( sizeof(REQ_QUERY_PATH_INFORMATION) >= sizeof(RESP_QUERY_PATH_INFORMATION) );
|
||
OutParameterCount = sizeof(RESP_QUERY_PATH_INFORMATION);
|
||
OutDataCount = *BufferSize;
|
||
OutSetupCount = 0;
|
||
|
||
SmbPutAlignedUshort(&Parameters->InformationLevel, FileInformationClass);
|
||
SmbPutAlignedUlong(&Parameters->Reserved, 0);
|
||
|
||
Status = RdrTransact(Irp, // Irp,
|
||
Connect,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
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, // NtTransactionFunction
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
FREE_POOL( Parameters );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
*BufferSize -= OutDataCount;
|
||
|
||
} else if( Status == STATUS_OBJECT_NAME_NOT_FOUND &&
|
||
Icb->Fcb->FileName.Length <= Connect->CachedInvalidPath.MaximumLength ) {
|
||
//
|
||
// Cache the fact that this file does not exist on the server
|
||
//
|
||
RtlCopyMemory( Connect->CachedInvalidPath.Buffer,
|
||
Icb->Fcb->FileName.Buffer,
|
||
Icb->Fcb->FileName.Length );
|
||
|
||
Connect->CachedInvalidPath.Length = Icb->Fcb->FileName.Length;
|
||
|
||
Connect->CachedInvalidSmbCount = RdrStatistics.SmbsTransmitted.LowPart;
|
||
|
||
KeQuerySystemTime( ¤tTime );
|
||
Connect->CachedInvalidPathExpiration.QuadPart = currentTime.QuadPart + 2 * 10 * 1000 * 1000;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryInternalInfo (
|
||
IN PICB Icb,
|
||
OUT PFILE_INTERNAL_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryInternalInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_INTERNAL_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:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
// if ((Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) &&
|
||
// (Icb->Flags & ICB_HASHANDLE)) {
|
||
//
|
||
// *FinalStatus = RdrQueryNtFileInformation(Irp, Icb, SMB_QUERY_FILE_INTERNAL_INFO,
|
||
// UsersBuffer,
|
||
// BufferSize);
|
||
//
|
||
// } else {
|
||
//
|
||
// Note: We use the address of the FCB to determine the
|
||
// index number of the file. If we have to maintain persistance between
|
||
// file opens for this request, then we might have to do something
|
||
// like checksuming the reserved fields on a FUNIQUE SMB response.
|
||
//
|
||
|
||
UsersBuffer->IndexNumber.LowPart = (ULONG )Icb->Fcb;
|
||
UsersBuffer->IndexNumber.HighPart = 0;
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
*BufferSize -= sizeof(FILE_INTERNAL_INFORMATION);
|
||
|
||
// }
|
||
|
||
return FALSE;
|
||
|
||
UNREFERENCED_PARAMETER(Wait);
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryEaInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_EA_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryEaInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_EA_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. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (!(Icb->Fcb->Connection->Server->Capabilities & DF_SUPPORTEA)) {
|
||
|
||
//
|
||
// Make sure that there are 0 ea's on the file.
|
||
//
|
||
|
||
UsersBuffer->EaSize = 0;
|
||
|
||
*FinalStatus = STATUS_EAS_NOT_SUPPORTED;
|
||
return FALSE;
|
||
|
||
} else if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_EA_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
} else {
|
||
*FinalStatus = RdrQueryNtPathInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_EA_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
}
|
||
|
||
} else {
|
||
USHORT Setup[] = {TRANS2_QUERY_PATH_INFORMATION};
|
||
|
||
PUCHAR TempBuffer;
|
||
|
||
FILESTATUS Buffer;
|
||
|
||
CLONG OutSetupCount = 0;
|
||
|
||
CLONG OutDataCount = sizeof(Buffer);
|
||
|
||
CLONG OutParameterCount = sizeof(RESP_QUERY_PATH_INFORMATION);
|
||
|
||
//
|
||
// The same buffer is used for request and response parameters
|
||
//
|
||
|
||
union {
|
||
struct _Q {
|
||
REQ_QUERY_PATH_INFORMATION Q;
|
||
UCHAR PathName[MAXIMUM_PATHLEN_LANMAN12];
|
||
} Q;
|
||
RESP_QUERY_PATH_INFORMATION R;
|
||
} Parameters;
|
||
|
||
SmbPutAlignedUshort( &Parameters.Q.Q.InformationLevel, SMB_INFO_QUERY_EA_SIZE);
|
||
|
||
TempBuffer = Parameters.Q.Q.Buffer;
|
||
|
||
//
|
||
// Strip \Server\Share and copy just PATH
|
||
//
|
||
|
||
*FinalStatus = RdrCopyNetworkPath((PVOID *)&TempBuffer,
|
||
&Icb->Fcb->FileName,
|
||
Icb->Fcb->Connection->Server,
|
||
FALSE,
|
||
SKIP_SERVER_SHARE);
|
||
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
return FALSE;
|
||
}
|
||
|
||
*FinalStatus = RdrTransact(Irp, // Irp,
|
||
Icb->Fcb->Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&Parameters.Q,
|
||
TempBuffer-(PUCHAR)&Parameters, // InParameterCount,
|
||
&OutParameterCount,
|
||
NULL, // InData,
|
||
0,
|
||
&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)) {
|
||
return FALSE;
|
||
}
|
||
|
||
UsersBuffer->EaSize = Buffer.EaSize;
|
||
|
||
//
|
||
// Os/2 machines return 4 (sizeof(cblist)) when there are no ea's on
|
||
// a file.
|
||
//
|
||
|
||
if (UsersBuffer->EaSize == 4) {
|
||
UsersBuffer->EaSize = 0;
|
||
}
|
||
|
||
*BufferSize -= sizeof(FILE_EA_INFORMATION);
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
UNREFERENCED_PARAMETER(Wait);
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryNameInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_NAME_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryNameInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_NAME_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. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PFCB Fcb = Icb->Fcb;
|
||
PCONNECTLISTENTRY Connection = Fcb->Connection;
|
||
PSERVERLISTENTRY Server = Connection->Server;
|
||
|
||
PAGED_CODE();
|
||
|
||
RdrAcquireFcbLock(Fcb, SharedLock, TRUE);
|
||
|
||
//
|
||
// Reduce the available buffer space by the fixed part of the structure.
|
||
//
|
||
|
||
*BufferSize -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
|
||
|
||
if ((Server->Capabilities & DF_NT_SMBS) &&
|
||
(Icb->Flags & ICB_HASHANDLE)) {
|
||
|
||
WCHAR FilenameBuffer[MAXIMUM_FILENAME_LENGTH+sizeof(FILE_NAME_INFORMATION)];
|
||
|
||
PFILE_NAME_INFORMATION NameInfo = (PFILE_NAME_INFORMATION)FilenameBuffer;
|
||
|
||
|
||
//
|
||
// Use TRANSACT2_QFILEINFO to query FILE_STANDARD_INFORMATION.
|
||
//
|
||
|
||
USHORT Setup[] = {TRANS2_QUERY_FILE_INFORMATION};
|
||
|
||
REQ_QUERY_FILE_INFORMATION Parameters;
|
||
|
||
CLONG OutParameterCount = sizeof(REQ_QUERY_FILE_INFORMATION);
|
||
|
||
CLONG OutDataCount = sizeof(FilenameBuffer);
|
||
|
||
CLONG OutSetupCount = 0;
|
||
|
||
SmbPutAlignedUshort(&Parameters.InformationLevel, SMB_QUERY_FILE_NAME_INFO);
|
||
|
||
SmbPutAlignedUshort(&Parameters.Fid, Icb->FileId);
|
||
|
||
*FinalStatus = RdrTransact(Irp, // Irp,
|
||
Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&Parameters,
|
||
sizeof(Parameters), // InParameterCount,
|
||
&OutParameterCount,
|
||
NULL, // InData,
|
||
0, // InDataCount,
|
||
FilenameBuffer, // OutData,
|
||
&OutDataCount,
|
||
&Icb->FileId, // Fid
|
||
0, // Timeout
|
||
(USHORT) (FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? SMB_TRANSACTION_DFSFILE : 0),
|
||
0, // NtTransact function
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (*FinalStatus == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
|
||
if (!NT_ERROR(*FinalStatus)) {
|
||
|
||
UNICODE_STRING FileName;
|
||
UNICODE_STRING ServerFileName;
|
||
|
||
UsersBuffer->FileNameLength =
|
||
sizeof(WCHAR) + Server->Text.Length + sizeof(WCHAR) +
|
||
((Icb->Type == NamedPipe) ? RdrPipeText.Length : Connection->Text.Length) +
|
||
NameInfo->FileNameLength;
|
||
|
||
ServerFileName.Buffer = NameInfo->FileName;
|
||
ServerFileName.MaximumLength = sizeof(FilenameBuffer);
|
||
ServerFileName.Length = (USHORT)NameInfo->FileNameLength;
|
||
|
||
FileName.Buffer = UsersBuffer->FileName;
|
||
FileName.Length = 0;
|
||
FileName.MaximumLength = (USHORT)*BufferSize;
|
||
|
||
RtlAppendUnicodeToString(&FileName, L"\\");
|
||
|
||
RtlAppendUnicodeStringToString(&FileName, &Server->Text);
|
||
|
||
RtlAppendUnicodeToString(&FileName, L"\\");
|
||
|
||
if (Icb->Type == NamedPipe) {
|
||
RtlAppendUnicodeStringToString(&FileName, &RdrPipeText);
|
||
} else {
|
||
RtlAppendUnicodeStringToString(&FileName, &Connection->Text);
|
||
}
|
||
|
||
RtlAppendUnicodeStringToString(&FileName, &ServerFileName);
|
||
|
||
ASSERT(*BufferSize >= (ULONG)FileName.Length);
|
||
|
||
*BufferSize -= FileName.Length;
|
||
|
||
if (FileName.Length < UsersBuffer->FileNameLength) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
} else {
|
||
|
||
ULONG NameSizeToCopy;
|
||
|
||
if (*BufferSize < Fcb->FileName.Length ) {
|
||
*FinalStatus = STATUS_BUFFER_OVERFLOW;
|
||
NameSizeToCopy = *BufferSize;
|
||
} else {
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
NameSizeToCopy = Fcb->FileName.Length;
|
||
}
|
||
|
||
UsersBuffer->FileNameLength = Fcb->FileName.Length;
|
||
|
||
RtlCopyMemory(UsersBuffer->FileName, Fcb->FileName.Buffer, NameSizeToCopy);
|
||
|
||
*BufferSize -= NameSizeToCopy;
|
||
}
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
|
||
return FALSE;
|
||
|
||
UNREFERENCED_PARAMETER(Wait);
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryAlternateNameInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_NAME_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileAlternateNameInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_NAME_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. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if ( FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_NT_SMBS) ) {
|
||
|
||
if ( FlagOn(Icb->Flags, ICB_HASHANDLE) ) {
|
||
*FinalStatus = RdrQueryNtFileInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_ALT_NAME_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
} else {
|
||
*FinalStatus = RdrQueryNtPathInformation(
|
||
Irp,
|
||
Icb,
|
||
SMB_QUERY_FILE_ALT_NAME_INFO,
|
||
UsersBuffer,
|
||
BufferSize
|
||
);
|
||
}
|
||
|
||
} else {
|
||
*FinalStatus = STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
UNREFERENCED_PARAMETER(Wait);
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
QueryPositionInfo (
|
||
IN PICB Icb,
|
||
IN PIO_STACK_LOCATION IrpSp,
|
||
OUT PFILE_POSITION_INFORMATION UsersBuffer,
|
||
IN OUT PULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileQueryPositionInformation value of the
|
||
NtQueryInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_POSITION_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. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Snarf the position out of the file object. Please note that
|
||
// this information is totally bogus for a file that is not
|
||
// synchronous. (But you knew that anyway).
|
||
//
|
||
|
||
*BufferSize -= sizeof(FILE_POSITION_INFORMATION);
|
||
UsersBuffer->CurrentByteOffset = IrpSp->FileObject->CurrentByteOffset;
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
|
||
return FALSE;
|
||
|
||
if (Wait||Icb);
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetBasicInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
IN PFILE_BASIC_INFORMATION UsersBuffer,
|
||
IN ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileBasicInformation value of the
|
||
NtSetInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_BASIC_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN ULONG BufferSize - Supplies the size of the buffer. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSD can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
BOOLEAN FcbLocked = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (BufferSize < sizeof(FILE_BASIC_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
return FALSE;
|
||
} else {
|
||
|
||
if (UsersBuffer->FileAttributes == 0 &&
|
||
UsersBuffer->CreationTime.HighPart == 0 &&
|
||
UsersBuffer->CreationTime.LowPart == 0 &&
|
||
UsersBuffer->LastAccessTime.HighPart == 0 &&
|
||
UsersBuffer->LastAccessTime.LowPart == 0 &&
|
||
UsersBuffer->LastWriteTime.HighPart == 0 &&
|
||
UsersBuffer->LastWriteTime.LowPart == 0 &&
|
||
UsersBuffer->ChangeTime.HighPart == 0 &&
|
||
UsersBuffer->ChangeTime.LowPart == 0) {
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
return FALSE;
|
||
}
|
||
|
||
if (!Wait) {
|
||
return TRUE;
|
||
}
|
||
|
||
*FinalStatus = RdrSetFileAttributes(Irp, Icb, UsersBuffer);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
RdrAcquireFcbLock(Icb->Fcb, ExclusiveLock, TRUE);
|
||
|
||
if (UsersBuffer->FileAttributes != 0) {
|
||
|
||
Icb->Fcb->Attribute = UsersBuffer->FileAttributes;
|
||
|
||
//
|
||
// If this is a disk file, and
|
||
// the file has a handle (isn't pseudo-opened) &&
|
||
// the new file attributes indicate that the file isn't
|
||
// readonly and
|
||
// the file is currently cached, and
|
||
// we can't keep the file open for any other reason,
|
||
// then purge the cache for the file.
|
||
//
|
||
|
||
if ((Icb->Type == DiskFile) &&
|
||
(Icb->Flags & ICB_HASHANDLE)) {
|
||
|
||
if ((!(UsersBuffer->FileAttributes & FILE_ATTRIBUTE_READONLY))
|
||
&&
|
||
(CcIsFileCached(Icb->u.f.FileObject))) {
|
||
|
||
if (!(Icb->u.f.Flags & (ICBF_OPLOCKED | ICBF_OPENEDEXCLUSIVE))) {
|
||
ASSERT (RdrData.BufferReadOnlyFiles);
|
||
|
||
//RdrLog(( "rdflusha", &Icb->Fcb->FileName, 0 ));
|
||
*FinalStatus = RdrFlushCacheFile(Icb->Fcb);
|
||
|
||
if (Icb->Fcb->NonPagedFcb->OplockLevel != SMB_OPLOCK_LEVEL_II) {
|
||
*FinalStatus = RdrFlushFileLocks(Icb->Fcb);
|
||
}
|
||
|
||
//RdrLog(( "rdpurgea", &Icb->Fcb->FileName, 0 ));
|
||
*FinalStatus = RdrPurgeCacheFile(Icb->Fcb);
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the user is setting the temporary bit, and the file
|
||
// object is not marked as temporary, mark it as temporary.
|
||
//
|
||
// If the temporary bit is NOT on, and the file is
|
||
// marked as temporary, turn off the temporary bit.
|
||
//
|
||
|
||
if ((FlagOn(UsersBuffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY))) {
|
||
if (!FlagOn(IrpSp->FileObject->Flags, FO_TEMPORARY_FILE)) {
|
||
IrpSp->FileObject->Flags |= FO_TEMPORARY_FILE;
|
||
}
|
||
} else if (FlagOn(IrpSp->FileObject->Flags, FO_TEMPORARY_FILE)) {
|
||
IrpSp->FileObject->Flags &= ~FO_TEMPORARY_FILE;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Update the times in the FCB for the times that are being
|
||
// modified.
|
||
//
|
||
|
||
if (UsersBuffer->CreationTime.HighPart != 0 &&
|
||
UsersBuffer->CreationTime.LowPart != 0) {
|
||
Icb->Fcb->CreationTime = UsersBuffer->CreationTime;
|
||
Icb->Flags |= ICB_USER_SET_TIMES;
|
||
}
|
||
|
||
if (UsersBuffer->LastAccessTime.HighPart != 0 &&
|
||
UsersBuffer->LastAccessTime.LowPart != 0) {
|
||
Icb->Fcb->LastAccessTime = UsersBuffer->LastAccessTime;
|
||
Icb->Flags |= ICB_USER_SET_TIMES;
|
||
}
|
||
|
||
if (UsersBuffer->LastWriteTime.HighPart != 0 &&
|
||
UsersBuffer->LastWriteTime.LowPart != 0) {
|
||
Icb->Fcb->LastWriteTime = UsersBuffer->LastWriteTime;
|
||
Icb->Flags |= ICB_USER_SET_TIMES;
|
||
}
|
||
|
||
if (UsersBuffer->CreationTime.HighPart != 0 &&
|
||
UsersBuffer->CreationTime.LowPart != 0) {
|
||
Icb->Fcb->ChangeTime = UsersBuffer->ChangeTime;
|
||
Icb->Flags |= ICB_USER_SET_TIMES;
|
||
}
|
||
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetRenameInfo (
|
||
IN PIRP Irp OPTIONAL,
|
||
IN PICB Icb,
|
||
OUT PFILE_RENAME_INFORMATION UsersBuffer,
|
||
IN ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait,
|
||
USHORT NtInformationLevel
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileCopyOnWriteInformation,
|
||
FileMoveClusterInformation, FileLinkInformation and
|
||
FileRenameInformation info levels of the NtSetInformationFile api.
|
||
It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_RENAME_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN ULONG BufferSize - Supplies the size of the buffer. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
IN USHORT NtInformationLevel - Nt info level
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING NewFileName, RenameDestination;
|
||
PFCB Fcb = Icb->Fcb;
|
||
BOOLEAN FullyQualifiedPath = FALSE;
|
||
BOOLEAN PoolAllocatedForRenameDestination = FALSE;
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
PAGED_CODE();
|
||
|
||
NewFileName.Buffer = NULL;
|
||
|
||
//
|
||
// Force the request to be queued to the FSP right now to avoid our
|
||
// having to walk the connection database twice.
|
||
//
|
||
|
||
if (!Wait) {
|
||
return TRUE;
|
||
}
|
||
|
||
if (BufferSize < sizeof(FILE_RENAME_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
return FALSE;
|
||
}
|
||
if (NtInformationLevel != FileRenameInformation &&
|
||
!(Fcb->Connection->Server->Capabilities & DF_NT_SMBS)) {
|
||
*FinalStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Acquire the FCB lock to the source file for exclusive access to
|
||
// guarantee that no-one else is messing with the file.
|
||
//
|
||
|
||
RdrAcquireFcbLock(Fcb, ExclusiveLock, TRUE);
|
||
|
||
try {
|
||
// WARNING: Need NT support for rename functionality.
|
||
// if ( !(Fcb->Connection->Server->Capabilities & DF_NT_SMBS)
|
||
//
|
||
// ||
|
||
//
|
||
// !(Icb->Flags & ICB_HASHANDLE)
|
||
//
|
||
// ||
|
||
//
|
||
// ((IrpSp->Parameters.SetFile.FileObject != NULL) &&
|
||
// (!(((PICB)IrpSp->Parameters.SetFile.FileObject->FsContext2)->Flags & ICB_HASHANDLE) )
|
||
// )
|
||
//
|
||
// )
|
||
{
|
||
//
|
||
// Check to see whether this is a fully qualified RenameDestination or a simple
|
||
// rename within a directory.
|
||
//
|
||
|
||
if (IrpSp->Parameters.SetFile.FileObject != NULL) {
|
||
PFCB TargetFcb = NULL;
|
||
UNICODE_STRING TargetPath;
|
||
UNICODE_STRING LastComponent;
|
||
|
||
dprintf(DPRT_FILEINFO, ("SetRenameInformation: Fully qualified rename\n" ));
|
||
|
||
TargetFcb = IrpSp->Parameters.SetFile.FileObject->FsContext;
|
||
|
||
if (TargetFcb->Connection != Fcb->Connection) {
|
||
*FinalStatus = STATUS_NOT_SAME_DEVICE;
|
||
try_return(NOTHING);
|
||
}
|
||
|
||
//
|
||
// Disect the target path into two components, the file's path
|
||
// and the actual file name.
|
||
//
|
||
|
||
RdrExtractPathAndFileName(&IrpSp->Parameters.SetFile.FileObject->FileName, &TargetPath, &LastComponent);
|
||
|
||
RenameDestination.Buffer = ALLOCATE_POOL(PagedPool,
|
||
TargetFcb->FileName.MaximumLength + (USHORT )sizeof(WCHAR) + LastComponent.Length, POOL_RENAMEDEST);
|
||
|
||
if (RenameDestination.Buffer == NULL) {
|
||
try_return(*FinalStatus = STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
RenameDestination.MaximumLength = TargetFcb->FileName.MaximumLength + (USHORT )sizeof(WCHAR) + LastComponent.Length;
|
||
|
||
PoolAllocatedForRenameDestination = TRUE;
|
||
|
||
FullyQualifiedPath = TRUE;
|
||
|
||
//
|
||
// Build the rename destination name by concatinating the
|
||
// name of the FCB with the last component of the file name.
|
||
//
|
||
|
||
RtlCopyUnicodeString(&RenameDestination, &TargetFcb->FileName);
|
||
|
||
RtlAppendUnicodeToString(&RenameDestination, L"\\");
|
||
|
||
RtlAppendUnicodeStringToString(&RenameDestination, &LastComponent);
|
||
|
||
} else {
|
||
|
||
UNICODE_STRING LastComponent, FilePath;
|
||
|
||
//
|
||
// This is a relative rename operation, so treat it as such.
|
||
//
|
||
|
||
NewFileName.Length = (USHORT )UsersBuffer->FileNameLength;
|
||
NewFileName.Buffer = UsersBuffer->FileName;
|
||
|
||
if (NewFileName.Length == 0) {
|
||
*FinalStatus = STATUS_OBJECT_NAME_INVALID;
|
||
try_return(NOTHING);
|
||
}
|
||
|
||
//
|
||
// The user specified a path component. Check to make sure that
|
||
// the path component that the user specified is valid.
|
||
//
|
||
// If this is a LANMAN 2.0 server, use the NT canonicalization
|
||
// rules for determining name validity, otherwise use the
|
||
// DOS (8.3) file name rules.
|
||
//
|
||
|
||
|
||
if (!(Fcb->Connection->Server->Capabilities & DF_NT_SMBS)) {
|
||
OEM_STRING FileName;
|
||
|
||
*FinalStatus = RtlUnicodeStringToOemString(&FileName, &NewFileName, TRUE);
|
||
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
try_return(NOTHING);
|
||
}
|
||
|
||
if (Fcb->Connection->Server->Capabilities & DF_LANMAN20) {
|
||
if (!FsRtlIsHpfsDbcsLegal(FileName, FALSE, FALSE, FALSE)) {
|
||
*FinalStatus = STATUS_OBJECT_NAME_INVALID;
|
||
RtlFreeOemString(&FileName);
|
||
try_return(NOTHING);
|
||
}
|
||
|
||
} else {
|
||
if (!FsRtlIsFatDbcsLegal(FileName, FALSE, FALSE, FALSE)) {
|
||
*FinalStatus = STATUS_OBJECT_NAME_INVALID;
|
||
RtlFreeOemString(&FileName);
|
||
try_return(NOTHING);
|
||
}
|
||
}
|
||
|
||
RtlFreeOemString(&FileName);
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// The target name is valid, figure out the fully qualified path
|
||
// to the destination.
|
||
//
|
||
|
||
//
|
||
// Initialize the path component to the entire source file name
|
||
// string.
|
||
//
|
||
|
||
FilePath = Fcb->FileName;
|
||
|
||
LastComponent.Length = LastComponent.MaximumLength = 0;
|
||
|
||
//
|
||
// Disect the source path into two components, the file's path
|
||
// and the actual file name.
|
||
//
|
||
|
||
RdrExtractPathAndFileName(&Fcb->FileName, &FilePath, &LastComponent);
|
||
|
||
//
|
||
// If the new file name matches the old file name, then we
|
||
// are done. Return success.
|
||
//
|
||
|
||
if (RtlEqualUnicodeString(&LastComponent, &NewFileName, TRUE)) {
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
try_return(NOTHING);
|
||
}
|
||
|
||
RenameDestination.Buffer = ALLOCATE_POOL(PagedPool,
|
||
FilePath.Length + (USHORT )sizeof(WCHAR) + NewFileName.Length, POOL_RENAMEDEST);
|
||
|
||
RenameDestination.Length = RenameDestination.MaximumLength =
|
||
FilePath.Length + (USHORT )sizeof(WCHAR) + NewFileName.Length;
|
||
|
||
if (RenameDestination.Buffer == NULL) {
|
||
*FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
try_return(NOTHING);
|
||
}
|
||
|
||
PoolAllocatedForRenameDestination = TRUE;
|
||
|
||
RtlCopyUnicodeString(&RenameDestination, &FilePath);
|
||
|
||
RtlAppendUnicodeToString(&RenameDestination, L"\\");
|
||
|
||
RtlAppendUnicodeStringToString(&RenameDestination, &NewFileName);
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// RenameDestination contains the destination of the rename operation.
|
||
//
|
||
// Fcb->FileName contains the source of the rename operation.
|
||
//
|
||
|
||
dprintf(DPRT_FILEINFO, ("Rename %wZ to %wZ\n", &Fcb->FileName, &RenameDestination));
|
||
|
||
//
|
||
// We know we have enough quota to hold the new file name, attempt
|
||
// the rename operation.
|
||
//
|
||
|
||
//
|
||
// Purge this file from the cache, closing open instances.
|
||
//
|
||
|
||
if (Icb->Type == DiskFile) {
|
||
|
||
//
|
||
// Flush any write behind data from the cache for this file.
|
||
//
|
||
|
||
//RdrLog(( "rdflushb", &Icb->Fcb->FileName, 0 ));
|
||
*FinalStatus = RdrFlushCacheFile(Icb->Fcb);
|
||
|
||
//
|
||
// Purge the file from the cache.
|
||
//
|
||
|
||
//RdrLog(( "rdpurgeb", &Icb->Fcb->FileName, 0 ));
|
||
*FinalStatus = RdrPurgeCacheFile(Icb->Fcb);
|
||
}
|
||
|
||
//
|
||
// Force close the file.
|
||
//
|
||
// The SMB protocol sharing rules do not allow renaming open
|
||
// files, so we force close the file before renaming the
|
||
// old file to the new.
|
||
//
|
||
|
||
if (NtInformationLevel == FileRenameInformation &&
|
||
(Icb->Flags & ICB_HASHANDLE)) {
|
||
RdrCloseFile(Irp, Icb, IrpSp->FileObject, TRUE);
|
||
#if DBG
|
||
{
|
||
PLIST_ENTRY IcbEntry;
|
||
for (IcbEntry = Icb->Fcb->InstanceChain.Flink ;
|
||
IcbEntry != &Icb->Fcb->InstanceChain ;
|
||
IcbEntry = IcbEntry->Flink) {
|
||
PICB Icb2 = CONTAINING_RECORD(IcbEntry, ICB, InstanceNext);
|
||
|
||
if (Icb2->FileId == Icb->FileId) {
|
||
ASSERT (!(Icb2->Flags & ICB_HASHANDLE));
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
if (NtInformationLevel == FileRenameInformation &&
|
||
Fcb->NumberOfOpens != 1 &&
|
||
!(Fcb->Connection->Server->Capabilities & DF_NT_SMBS) ) {
|
||
|
||
*FinalStatus = STATUS_ACCESS_DENIED;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If the user wanted us to delete this file, try the delete
|
||
// operation. If it fails, we ignore the error, since
|
||
// a better error will come from the RdrRenameFile request
|
||
// later on.
|
||
//
|
||
// To ease the load on the wire, if the user wanted us to
|
||
// replace the target, and the target doesn't exist, don't
|
||
// bother with the rename operation.
|
||
//
|
||
|
||
if (NtInformationLevel != FileMoveClusterInformation &&
|
||
IrpSp->Parameters.SetFile.ReplaceIfExists &&
|
||
!(Fcb->NonPagedFcb->Flags & FCB_DOESNTEXIST)) {
|
||
|
||
|
||
//
|
||
// Try to delete the destination of the rename operation.
|
||
//
|
||
//
|
||
|
||
*FinalStatus = RdrDeleteFile(Irp, &RenameDestination,
|
||
BooleanFlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE),
|
||
Icb->Fcb->Connection, Icb->Se);
|
||
|
||
#ifdef NOTIFY
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
//
|
||
// Complete the report notify as appropriate.
|
||
//
|
||
FsRtlNotifyReportChange( Fcb->Connection->NotifySync,
|
||
&Fcb->Connection->DirNotifyList,
|
||
(PSTRING)&Icb->Fcb->FileName,
|
||
(PSTRING)&Icb->Fcb->LastFileName,
|
||
FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||
| FILE_NOTIFY_CHANGE_SIZE
|
||
| FILE_NOTIFY_CHANGE_LAST_WRITE
|
||
| FILE_NOTIFY_CHANGE_LAST_ACCESS
|
||
| FILE_NOTIFY_CHANGE_CREATION
|
||
| FILE_NOTIFY_CHANGE_EA );
|
||
|
||
}
|
||
#endif
|
||
}
|
||
|
||
*FinalStatus = RdrRenameFile(
|
||
Irp,
|
||
Icb,
|
||
&Fcb->FileName,
|
||
&RenameDestination,
|
||
NtInformationLevel,
|
||
IrpSp->Parameters.SetFile.ClusterCount
|
||
);
|
||
|
||
#ifdef NOTIFY
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
FsRtlNotifyReportChange( Fcb->Connection->NotifySync,
|
||
&Fcb->Connection->DirNotifyList,
|
||
(PSTRING)&Icb->Fcb->FileName,
|
||
(PSTRING)&Icb->Fcb->LastFileName,
|
||
NtInformationLevel == FileMoveClusterInformation?
|
||
FILE_NOTIFY_CHANGE_SIZE :
|
||
FILE_NOTIFY_CHANGE_NAME );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
}
|
||
// else {
|
||
// //
|
||
// // Use TRANSACT2_SETFILEINFO to set FILE_RENAME_INFORMATION.
|
||
// //
|
||
//
|
||
// USHORT Setup[] = {TRANS2_SET_FILE_INFORMATION};
|
||
//
|
||
// REQ_SET_FILE_INFORMATION Parameters;
|
||
//
|
||
// CLONG OutParameterCount = sizeof(REQ_SET_FILE_INFORMATION);
|
||
//
|
||
// CLONG OutDataCount = 0;
|
||
//
|
||
// CLONG OutSetupCount = 0;
|
||
//
|
||
// UCHAR RenameBuffer[sizeof(FILE_RENAME_INFORMATION)+MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)];
|
||
//
|
||
// PFILE_RENAME_INFORMATION RenameInfo = (PFILE_RENAME_INFORMATION)RenameBuffer;
|
||
//
|
||
// DbgBreakPoint();
|
||
//
|
||
// SmbPutAlignedUshort(&Parameters.InformationLevel, SMB_SET_FILE_RENAME_INFO);
|
||
//
|
||
// SmbPutAlignedUshort(&Parameters.Fid, Icb->FileId);
|
||
//
|
||
// if (BufferSize > sizeof(RenameBuffer)) {
|
||
// try_return(*FinalStatus = STATUS_INSUFFICIENT_RESOURCES);
|
||
// }
|
||
//
|
||
// RtlCopyMemory(RenameBuffer, UsersBuffer, BufferSize);
|
||
//
|
||
// if (IrpSp->Parameters.SetFile.FileObject != NULL) {
|
||
// RenameInfo->RootDirectory = (HANDLE)((PICB)IrpSp->Parameters.SetFile.FileObject->FsContext2)->FileId;
|
||
// }
|
||
//
|
||
// RenameInfo->ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
|
||
//
|
||
// *FinalStatus = RdrTransact(Irp, // Irp,
|
||
// Icb->Fcb->Connection,
|
||
// Icb->Se,
|
||
// Setup,
|
||
// (CLONG) sizeof(Setup), // InSetupCount,
|
||
// &OutSetupCount,
|
||
// NULL, // Name,
|
||
// &Parameters,
|
||
// sizeof(Parameters), // InParameterCount,
|
||
// &OutParameterCount,
|
||
// RenameInfo, // InData,
|
||
// BufferSize, // InDataCount,
|
||
// NULL, // OutData,
|
||
// &OutDataCount, // OutDataCount
|
||
// &Icb->FileId, // Fid
|
||
// 0, // Timeout
|
||
// 0, // Flags
|
||
// 0, // NtTransact function
|
||
// NULL,
|
||
// NULL
|
||
// );
|
||
// }
|
||
//
|
||
if (NT_SUCCESS(*FinalStatus) &&
|
||
NtInformationLevel == FileRenameInformation) {
|
||
|
||
//
|
||
// The rename operation succeeded.
|
||
//
|
||
//
|
||
// We don't update the file name in the FCB because no further
|
||
// operations can be performed on the file.
|
||
//
|
||
|
||
Icb->Flags |= ICB_RENAMED;
|
||
|
||
}
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
if (PoolAllocatedForRenameDestination) {
|
||
FREE_POOL(RenameDestination.Buffer);
|
||
}
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetDispositionInfo (
|
||
IN PICB Icb,
|
||
OUT PFILE_DISPOSITION_INFORMATION UsersBuffer,
|
||
IN ULONG BufferSize,
|
||
IN PIRP Irp,
|
||
OUT PNTSTATUS FinalStatus,
|
||
IN BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileSetDispositionInformation value of the
|
||
NtSetInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_DISPOSITION_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN ULONG BufferSize - Supplies the size of the buffer. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
IN PIRP Irp - Irp that generated this request.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
PFCB Fcb = Icb->Fcb;
|
||
|
||
PAGED_CODE();
|
||
|
||
dprintf(DPRT_FILEINFO, ("SetDispositionInformation, file %wZ\n", &Icb->Fcb->FileName));
|
||
|
||
if (BufferSize < sizeof(FILE_DISPOSITION_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// We can only delete files or directories.
|
||
//
|
||
|
||
if (Icb->Type == PrinterFile || Icb->Type == NamedPipe ||
|
||
Icb->Type == Com) {
|
||
*FinalStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Always process SetDisposition requests in the FSP if we can't block.
|
||
//
|
||
|
||
if (UsersBuffer->DeleteFile) {
|
||
BOOLEAN DeleteDirectory = (BOOLEAN)(Icb->Type == Directory);
|
||
|
||
if (!Wait) {
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Gain exclusive access to the FCB.
|
||
//
|
||
|
||
RdrAcquireFcbLock(Fcb, ExclusiveLock, TRUE);
|
||
|
||
//
|
||
// If this file doesn't exist, then we're done now - this is simply
|
||
// a NOP.
|
||
//
|
||
|
||
if (Fcb->NonPagedFcb->Flags & FCB_DOESNTEXIST) {
|
||
|
||
#ifdef NOTIFY
|
||
FsRtlNotifyReportChange( Fcb->Connection->NotifySync,
|
||
&Fcb->Connection->DirNotifyList,
|
||
(PSTRING)&Fcb->FileName,
|
||
(PSTRING)&Fcb->LastFileName,
|
||
FILE_NOTIFY_CHANGE_NAME );
|
||
#endif
|
||
|
||
//
|
||
// Set the bitsy pieces to indicate that this file has been
|
||
// deleted.
|
||
//
|
||
|
||
IrpSp->FileObject->DeletePending = TRUE;
|
||
|
||
Icb->Flags |= ICB_DELETE_PENDING;
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// If this is a non NT server, or there is no valid file id for this file,
|
||
// use the Lanman SMB delete for this file.
|
||
//
|
||
|
||
if (!(Fcb->Connection->Server->Capabilities & DF_NT_SMBS)
|
||
||
|
||
!(Icb->Flags & ICB_HASHANDLE)) {
|
||
|
||
if (Icb->Type == FileOrDirectory) {
|
||
ULONG FileAttributes;
|
||
BOOLEAN IsDirectory;
|
||
|
||
*FinalStatus = RdrDoesFileExist(Irp,
|
||
&Icb->Fcb->FileName,
|
||
Icb->Fcb->Connection,
|
||
Icb->Se,
|
||
BooleanFlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE),
|
||
&FileAttributes,
|
||
&IsDirectory,
|
||
NULL);
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
RdrReleaseFcbLock(Fcb);
|
||
return FALSE;
|
||
}
|
||
|
||
if (IsDirectory) {
|
||
DeleteDirectory = TRUE;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Purge this file from the cache, closing open instances.
|
||
//
|
||
|
||
if (Icb->Type == DiskFile) {
|
||
|
||
//
|
||
// Flush any write behind data from the cache for this file.
|
||
//
|
||
|
||
//RdrLog(( "rdflushc", &Icb->Fcb->FileName, 0 ));
|
||
*FinalStatus = RdrFlushCacheFile(Icb->Fcb);
|
||
|
||
//
|
||
// Purge the file from the cache.
|
||
//
|
||
|
||
//RdrLog(( "rdpurgec", &Icb->Fcb->FileName, 0 ));
|
||
*FinalStatus = RdrPurgeCacheFile(Icb->Fcb);
|
||
}
|
||
|
||
if (Icb->Flags & ICB_HASHANDLE) {
|
||
RdrCloseFile(Irp, Icb, IrpSp->FileObject, TRUE);
|
||
#if DBG
|
||
{
|
||
PLIST_ENTRY IcbEntry;
|
||
for (IcbEntry = Icb->Fcb->InstanceChain.Flink ;
|
||
IcbEntry != &Icb->Fcb->InstanceChain ;
|
||
IcbEntry = IcbEntry->Flink) {
|
||
PICB Icb2 = CONTAINING_RECORD(IcbEntry, ICB, InstanceNext);
|
||
|
||
if (Icb2->FileId == Icb->FileId) {
|
||
ASSERT (!(Icb2->Flags & ICB_HASHANDLE));
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
|
||
}
|
||
|
||
//
|
||
// If there are other openers of this file left, and it is an old server,
|
||
// deny the user's request.
|
||
//
|
||
|
||
if (Fcb->NumberOfOpens != 1 &&
|
||
!(Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) ) {
|
||
|
||
*FinalStatus = STATUS_SHARING_VIOLATION;
|
||
|
||
//
|
||
// Release the FCB lock to allow potential oplock breaks
|
||
// from coming through.
|
||
//
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
|
||
} else {
|
||
|
||
//
|
||
// If the delete succeeded, mark the file object as being
|
||
// deleted, otherwise it didn't actually get deleted.
|
||
//
|
||
|
||
IrpSp->FileObject->DeletePending = TRUE;
|
||
|
||
Icb->Flags |= ICB_DELETE_PENDING;
|
||
|
||
//
|
||
// Release the FCB lock to allow potential oplock breaks
|
||
// to come through.
|
||
//
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
|
||
|
||
//
|
||
// Issue the delete/rmdir request to the remote server and
|
||
// check the status of the response. If it was successful
|
||
// we can mark the file as being deleted.
|
||
//
|
||
|
||
if ( !DeleteDirectory ) {
|
||
|
||
//
|
||
// Try to delete the file.
|
||
//
|
||
|
||
*FinalStatus = RdrDeleteFile(Irp, &Fcb->FileName,
|
||
BooleanFlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE),
|
||
Icb->Fcb->Connection, Icb->Se);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Try to delete the directory.
|
||
//
|
||
|
||
*FinalStatus = RdrGenericPathSmb(Irp,
|
||
SMB_COM_DELETE_DIRECTORY,
|
||
BooleanFlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE),
|
||
&Fcb->FileName,
|
||
Fcb->Connection,
|
||
Icb->Se);
|
||
}
|
||
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
|
||
RdrAcquireFcbLock(Fcb, ExclusiveLock, TRUE);
|
||
|
||
IrpSp->FileObject->DeletePending = FALSE;
|
||
|
||
Icb->Flags &= ~ICB_DELETE_PENDING;
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
|
||
#ifdef NOTIFY
|
||
} else {
|
||
FsRtlNotifyReportChange( Fcb->Connection->NotifySync,
|
||
&Fcb->Connection->DirNotifyList,
|
||
(PSTRING)&Fcb->FileName,
|
||
(PSTRING)&Fcb->LastFileName,
|
||
FILE_NOTIFY_CHANGE_NAME );
|
||
#endif
|
||
|
||
}
|
||
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Use TRANSACT2_SETFILEINFO to set FILE_DISPOSITION_INFORMATION.
|
||
//
|
||
|
||
USHORT Setup[] = {TRANS2_SET_FILE_INFORMATION};
|
||
|
||
REQ_SET_FILE_INFORMATION Parameters;
|
||
|
||
CLONG OutParameterCount = sizeof(REQ_SET_FILE_INFORMATION);
|
||
|
||
CLONG OutDataCount = 0;
|
||
|
||
CLONG OutSetupCount = 0;
|
||
|
||
//
|
||
// If the delete succeeded, mark the file object as being
|
||
// deleted, otherwise it didn't actually get deleted.
|
||
//
|
||
|
||
IrpSp->FileObject->DeletePending = TRUE;
|
||
|
||
Icb->Flags |= ICB_DELETE_PENDING;
|
||
|
||
//
|
||
// Blow the file out of the cache. Don't worry about the data,
|
||
// since we're going to be deleting the file.
|
||
//
|
||
|
||
if (Icb->Type == DiskFile) {
|
||
//RdrLog(( "rdpurged", &Icb->Fcb->FileName, 0 ));
|
||
*FinalStatus = RdrPurgeCacheFile(Icb->Fcb);
|
||
}
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
|
||
SmbPutAlignedUshort(&Parameters.InformationLevel, SMB_SET_FILE_DISPOSITION_INFO);
|
||
|
||
SmbPutAlignedUshort(&Parameters.Fid, Icb->FileId);
|
||
|
||
*FinalStatus = RdrTransact(Irp, // Irp,
|
||
Fcb->Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&Parameters,
|
||
sizeof(Parameters), // InParameterCount,
|
||
&OutParameterCount,
|
||
UsersBuffer, // InData,
|
||
BufferSize, // InDataCount,
|
||
NULL, // OutData,
|
||
&OutDataCount, // OutDataCount
|
||
&Icb->FileId, // Fid
|
||
0, // Timeout
|
||
(USHORT) (FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? SMB_TRANSACTION_DFSFILE : 0),
|
||
0, // NtTransact function
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (*FinalStatus == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
#ifdef NOTIFY
|
||
FsRtlNotifyReportChange( Fcb->Connection->NotifySync,
|
||
&Fcb->Connection->DirNotifyList,
|
||
(PSTRING)&Fcb->FileName,
|
||
(PSTRING)&Fcb->LastFileName,
|
||
FILE_NOTIFY_CHANGE_NAME );
|
||
#endif
|
||
|
||
} else {
|
||
RdrAcquireFcbLock(Fcb, ExclusiveLock, TRUE);
|
||
|
||
IrpSp->FileObject->DeletePending = FALSE;
|
||
|
||
Icb->Flags &= ~ICB_DELETE_PENDING;
|
||
|
||
RdrReleaseFcbLock(Fcb);
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetPositionInfo (
|
||
IN PICB Icb,
|
||
IN PIO_STACK_LOCATION IrpSp,
|
||
OUT PFILE_POSITION_INFORMATION UsersBuffer,
|
||
IN ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileSetPositionInformation value of the
|
||
NtSetInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_POSITION_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN ULONG BufferSize - Supplies the size of the buffer. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (BufferSize < sizeof(FILE_POSITION_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
|
||
if (Icb->Flags & ICB_PSEUDOOPENED) {
|
||
*FinalStatus = STATUS_ACCESS_DENIED;
|
||
return FALSE;
|
||
}
|
||
|
||
// dprintf(DPRT_FILEINFO, ("Set current byte offset on file %lx to %lx%lx\n", IrpSp->FileObject, UsersBuffer->CurrentByteOffset.HighPart, UsersBuffer->CurrentByteOffset.LowPart));
|
||
|
||
IrpSp->FileObject->CurrentByteOffset = UsersBuffer->CurrentByteOffset;
|
||
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
UNREFERENCED_PARAMETER(Wait);
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetAllocationInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_ALLOCATION_INFORMATION UsersBuffer,
|
||
IN ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileSetAllocationInformation value of the
|
||
NtSetInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PIRP Irp - Supplies an I/O request packet for the request.
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_ALLOCATION_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN ULONG BufferSize - Supplies the size of the buffer. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN RetValue = FALSE;
|
||
BOOLEAN Truncated = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (Icb->Type != DiskFile) {
|
||
*FinalStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
} else if (BufferSize < sizeof(FILE_ALLOCATION_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
//
|
||
// Prevent other people from messing with the file.
|
||
//
|
||
|
||
RdrAcquireFcbLock(Icb->Fcb, ExclusiveLock, TRUE);
|
||
|
||
try {
|
||
if (!(Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) ||
|
||
!(Icb->Flags & ICB_HASHANDLE)) {
|
||
LARGE_INTEGER FileSize;
|
||
|
||
// dprintf(DPRT_FILEINFO, ("Set allocation info on file %lx (%wZ) to %lx%lx\n", IoGetCurrentIrpStackLocation(Irp)->FileObject, Icb->Fcb->FileName, UsersBuffer->AllocationSize.HighPart, UsersBuffer->AllocationSize.LowPart));
|
||
|
||
//
|
||
// If the file was pseudo-opened, this is an invalid operation.
|
||
//
|
||
|
||
if (Icb->Flags & ICB_PSEUDOOPENED) {
|
||
*FinalStatus = STATUS_ACCESS_DENIED;
|
||
try_return(RetValue = FALSE);
|
||
}
|
||
|
||
//
|
||
// Check to see what the user is trying to set as the new
|
||
// allocation for this size. We cannot set the file allocation
|
||
// information independently of the file size
|
||
//
|
||
// If the user is trying to extend the file, we ignore the
|
||
// request and return success, if he is trying to truncate
|
||
// the file, truncate it to the new value.
|
||
|
||
if (!Wait) {
|
||
try_return(RetValue = TRUE);
|
||
}
|
||
|
||
//
|
||
// Wait for writebehind operations to complete.
|
||
//
|
||
|
||
RdrWaitForWriteBehindOperation(Icb);
|
||
|
||
//
|
||
// First find out what the file's size is.
|
||
//
|
||
|
||
if (RdrCanFileBeBuffered(Icb)) {
|
||
//
|
||
// If the file is exclusive, we can rely on the
|
||
// file size cached in the FCB.
|
||
//
|
||
FileSize = Icb->Fcb->Header.FileSize;
|
||
|
||
} else {
|
||
*FinalStatus = RdrQueryEndOfFile(Irp, Icb, &FileSize);
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
if (*FinalStatus == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
try_return( RetValue = FALSE );
|
||
}
|
||
}
|
||
//
|
||
// Now see if the file is being extended or truncated.
|
||
//
|
||
// If the file is being extended, ignore this request,
|
||
// If the file is being truncated, truncate the file.
|
||
//
|
||
|
||
if (UsersBuffer->AllocationSize.QuadPart <
|
||
FileSize.QuadPart) {
|
||
*FinalStatus = RdrSetEndOfFile(Irp, Icb,
|
||
UsersBuffer->AllocationSize);
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
if (*FinalStatus == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
try_return ( RetValue = FALSE );
|
||
}
|
||
|
||
Icb->Fcb->Header.FileSize = UsersBuffer->AllocationSize;
|
||
|
||
if (Icb->Fcb->Header.FileSize.QuadPart >
|
||
Icb->Fcb->Header.AllocationSize.QuadPart) {
|
||
Icb->Fcb->Header.AllocationSize = Icb->Fcb->Header.FileSize;
|
||
}
|
||
|
||
Truncated = TRUE;
|
||
|
||
} else {
|
||
//
|
||
// The new allocation is larger than the file's size,
|
||
// return success always (ignore the api).
|
||
//
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Use TRANSACT2_SETFILEINFO to set FILE_ALLOCATION_INFORMATION.
|
||
//
|
||
|
||
USHORT Setup[] = {TRANS2_SET_FILE_INFORMATION};
|
||
|
||
REQ_SET_FILE_INFORMATION Parameters;
|
||
|
||
CLONG OutParameterCount = sizeof(REQ_SET_FILE_INFORMATION);
|
||
|
||
CLONG OutDataCount = 0;
|
||
|
||
CLONG OutSetupCount = 0;
|
||
|
||
if (!Wait) {
|
||
try_return(RetValue = TRUE);
|
||
}
|
||
|
||
//
|
||
// Wait for writebehind operations to complete.
|
||
//
|
||
|
||
RdrWaitForWriteBehindOperation(Icb);
|
||
|
||
SmbPutAlignedUshort(&Parameters.InformationLevel, SMB_SET_FILE_ALLOCATION_INFO);
|
||
|
||
SmbPutAlignedUshort(&Parameters.Fid, Icb->FileId);
|
||
|
||
*FinalStatus = RdrTransact(Irp, // Irp,
|
||
Icb->Fcb->Connection,
|
||
Icb->Se,
|
||
Setup,
|
||
(CLONG) sizeof(Setup), // InSetupCount,
|
||
&OutSetupCount,
|
||
NULL, // Name,
|
||
&Parameters,
|
||
sizeof(Parameters), // InParameterCount,
|
||
&OutParameterCount,
|
||
UsersBuffer, // InData,
|
||
BufferSize, // InDataCount,
|
||
NULL, // OutData,
|
||
&OutDataCount, // OutDataCount
|
||
&Icb->FileId, // Fid
|
||
0, // Timeout
|
||
(USHORT) (FlagOn(Icb->NonPagedFcb->Flags, FCB_DFSFILE) ? SMB_TRANSACTION_DFSFILE : 0),
|
||
0, // NtTransact function
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (NT_SUCCESS(*FinalStatus)) {
|
||
|
||
if (*FinalStatus == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
|
||
if (UsersBuffer->AllocationSize.QuadPart <
|
||
Icb->Fcb->Header.AllocationSize.QuadPart) {
|
||
Truncated = TRUE;
|
||
}
|
||
Icb->Fcb->Header.AllocationSize = UsersBuffer->AllocationSize;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
if ( Truncated ) {
|
||
CC_FILE_SIZES FileSizes =*((PCC_FILE_SIZES)&Icb->Fcb->Header.AllocationSize);
|
||
|
||
#ifdef NOTIFY
|
||
FsRtlNotifyReportChange( Icb->Fcb->Connection->NotifySync,
|
||
&Icb->Fcb->Connection->DirNotifyList,
|
||
(PSTRING)&Icb->Fcb->FileName,
|
||
(PSTRING)&Icb->Fcb->LastFileName,
|
||
FILE_NOTIFY_CHANGE_SIZE );
|
||
#endif
|
||
|
||
RdrTruncateLockHeadForFcb(Icb->Fcb);
|
||
RdrTruncateWriteBufferForFcb(Icb->Fcb);
|
||
|
||
CcSetFileSizes(IoGetCurrentIrpStackLocation(Irp)->FileObject,
|
||
&FileSizes);
|
||
}
|
||
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return RetValue;
|
||
|
||
}
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetEndOfFileInfo (
|
||
IN PIRP Irp,
|
||
IN PICB Icb,
|
||
OUT PFILE_END_OF_FILE_INFORMATION UsersBuffer,
|
||
IN ULONG BufferSize,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FileSetEndOfFileInformation value of the
|
||
NtSetInformationFile api. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT PFILE_END_OF_FILE_INFORMATION UsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN ULONG BufferSize - Supplies the size of the buffer. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN RetValue = FALSE;
|
||
BOOLEAN Truncated = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (Icb->Type != DiskFile) {
|
||
*FinalStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
return FALSE;
|
||
}
|
||
|
||
if (BufferSize < sizeof(FILE_END_OF_FILE_INFORMATION)) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// If IrpSp->Parameters.SetFile->AdvanceOnly is set, this is an
|
||
// indication that this is from the cache manager and should be
|
||
// used to update valid data length.
|
||
//
|
||
|
||
if (IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.AdvanceOnly) {
|
||
*FinalStatus = STATUS_SUCCESS;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// If the file was pseudo-opened, this is an invalid operation.
|
||
//
|
||
|
||
if (Icb->Flags & ICB_PSEUDOOPENED) {
|
||
*FinalStatus = STATUS_ACCESS_DENIED;
|
||
return FALSE;
|
||
}
|
||
|
||
RdrAcquireFcbLock(Icb->Fcb, ExclusiveLock, TRUE);
|
||
|
||
ExAcquireResourceExclusive(Icb->Fcb->Header.PagingIoResource, TRUE);
|
||
|
||
try {
|
||
|
||
//
|
||
// If this is not an NT server, or it doesn't have a handle...
|
||
//
|
||
|
||
// dprintf(DPRT_FILEINFO, ("Set end of file info on file %lx (%wZ) to %lx%lx\n", IoGetCurrentIrpStackLocation(Irp), Icb->Fcb->FileName, UsersBuffer->EndOfFile.HighPart, UsersBuffer->EndOfFile.LowPart));
|
||
if (!(Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) &&
|
||
(UsersBuffer->EndOfFile.HighPart != 0)) {
|
||
*FinalStatus = STATUS_INVALID_PARAMETER;
|
||
try_return(RetValue = FALSE);
|
||
}
|
||
|
||
if (!Wait) {
|
||
try_return(RetValue = TRUE);
|
||
}
|
||
|
||
//
|
||
// Wait for writebehind operations to complete.
|
||
//
|
||
|
||
RdrWaitForWriteBehindOperation(Icb);
|
||
|
||
//
|
||
// We know that the end of file is within the legal bounds
|
||
// for the SMB protocol. Set the end of file for the current
|
||
// file.
|
||
//
|
||
|
||
*FinalStatus = RdrSetEndOfFile(Irp, Icb, UsersBuffer->EndOfFile);
|
||
|
||
if (!NT_SUCCESS(*FinalStatus)) {
|
||
if (*FinalStatus == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
try_return(RetValue = FALSE);
|
||
}
|
||
|
||
Truncated = TRUE;
|
||
|
||
Icb->Fcb->Header.FileSize = UsersBuffer->EndOfFile;
|
||
|
||
if (Icb->Fcb->Header.FileSize.QuadPart > Icb->Fcb->Header.AllocationSize.QuadPart) {
|
||
Icb->Fcb->Header.AllocationSize = Icb->Fcb->Header.FileSize;
|
||
}
|
||
|
||
//
|
||
// If this is a core server, then he might have extended the file
|
||
// but returned no error due to running out of disk space. We
|
||
// want to make sure that the right thing happened.
|
||
//
|
||
|
||
if (!(Icb->Fcb->Connection->Server->Capabilities & DF_LANMAN10)) {
|
||
|
||
LARGE_INTEGER TrueFileSize;
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// If the setting of the end of file succeeded, we need
|
||
// to determine what the true end of file is. We do
|
||
// this because it is possible that the attempt to set
|
||
// the end of file might have failed to set the end of
|
||
// file to the actual amount we requested. We issue an
|
||
// LSEEK SMB to find out how large the file is.
|
||
//
|
||
|
||
Status = RdrQueryEndOfFile(Irp, Icb, &TrueFileSize);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
if (Status == STATUS_INVALID_HANDLE) {
|
||
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
|
||
}
|
||
|
||
*FinalStatus = Status;
|
||
try_return(RetValue = FALSE);
|
||
}
|
||
|
||
if (TrueFileSize.QuadPart < UsersBuffer->EndOfFile.QuadPart) {
|
||
*FinalStatus = STATUS_DISK_FULL;
|
||
try_return(RetValue = FALSE);
|
||
}
|
||
}
|
||
|
||
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
if ( Truncated ) {
|
||
CC_FILE_SIZES FileSizes =*((PCC_FILE_SIZES)&Icb->Fcb->Header.AllocationSize);
|
||
|
||
#ifdef NOTIFY
|
||
FsRtlNotifyReportChange( Icb->Fcb->Connection->NotifySync,
|
||
&Icb->Fcb->Connection->DirNotifyList,
|
||
(PSTRING)&Icb->Fcb->FileName,
|
||
(PSTRING)&Icb->Fcb->LastFileName,
|
||
FILE_NOTIFY_CHANGE_SIZE );
|
||
#endif
|
||
|
||
RdrTruncateLockHeadForFcb(Icb->Fcb);
|
||
RdrTruncateWriteBufferForFcb(Icb->Fcb);
|
||
|
||
CcSetFileSizes(IoGetCurrentIrpStackLocation(Irp)->FileObject,
|
||
&FileSizes);
|
||
}
|
||
|
||
ExReleaseResource(Icb->Fcb->Header.PagingIoResource);
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
}
|
||
|
||
return RetValue;
|
||
|
||
}
|
||
|
||
|
||
DBGSTATIC
|
||
BOOLEAN
|
||
SetGenericInfo(
|
||
IN PIRP Irp,
|
||
PICB Icb,
|
||
VOID *pvUsersBuffer,
|
||
ULONG cbBuffer,
|
||
ULONG cbMin,
|
||
USHORT NtInformationLevel,
|
||
PNTSTATUS FinalStatus,
|
||
BOOLEAN Wait)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the extended portions of the NtSetInformationFile
|
||
api for Cairo. It returns the following information:
|
||
|
||
|
||
Arguments:
|
||
|
||
IN PICB Icb - Supplies the ICB associated with this request.
|
||
|
||
OUT VOID *pvUsersBuffer - Supplies the user's buffer
|
||
that is filled in with the
|
||
requested data.
|
||
IN ULONG cbBuffer - Supplies the size of the buffer. On return,
|
||
the amount of the buffer consumed is
|
||
subtracted from the initial size.
|
||
|
||
IN ULONG cbMin - Supplies the minimum required size of the buffer.
|
||
|
||
OUT PNTSTATUS FinalStatus - Status to be returned for this operation.
|
||
|
||
IN BOOLEAN Wait - True if FSP can wait for this request.
|
||
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - True if request is to be processed in the FSP.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
if (Icb->Type != DiskFile && Icb->Type != Directory) {
|
||
*FinalStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
return(FALSE);
|
||
}
|
||
if (cbBuffer < cbMin) {
|
||
*FinalStatus = STATUS_BUFFER_TOO_SMALL;
|
||
return(FALSE);
|
||
}
|
||
if (!Wait) {
|
||
return(TRUE);
|
||
}
|
||
|
||
//
|
||
// Prevent other people from messing with the file.
|
||
//
|
||
|
||
RdrAcquireFcbLock(Icb->Fcb, ExclusiveLock, TRUE);
|
||
|
||
if ((Icb->Fcb->Connection->Server->Capabilities & DF_NT_SMBS) == 0) {
|
||
*FinalStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
} else if ((Icb->Flags & ICB_HASHANDLE) == 0) {
|
||
*FinalStatus = STATUS_INVALID_HANDLE;
|
||
} else {
|
||
*FinalStatus = RdrSetGeneric(
|
||
Irp,
|
||
Icb,
|
||
NtInformationLevel,
|
||
cbBuffer,
|
||
pvUsersBuffer);
|
||
}
|
||
RdrReleaseFcbLock(Icb->Fcb);
|
||
return(FALSE);
|
||
}
|