mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4442 lines
129 KiB
4442 lines
129 KiB
/*++
|
|
|
|
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);
|
|
}
|