|
|
/*++
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); }
|