490 lines
13 KiB
C
490 lines
13 KiB
C
//+-------------------------------------------------------------------------
|
||
//
|
||
// Copyright (C) 1992, Microsoft Corporation.
|
||
//
|
||
// File: FILEINFO.C
|
||
//
|
||
// Contents: This module implements the File Information routines for
|
||
// Dfs called by the dispatch driver.
|
||
//
|
||
// Functions: DfsFsdSetInformation - FSD entry point for NtSetInformationFile
|
||
// DfsFspSetInformation - FSP entry point for NtSetInformationFile
|
||
// DfsCommonSetInformation - Implement SetInformationFile for DFS
|
||
// DfsSetRenameInfo - Takes care of rename restrictions.
|
||
// DfsSetDispositionInfo - Enforces Deletion of StgId restrictions.
|
||
//
|
||
// Notes: No query information routines are presently used.
|
||
// These requests are passed directly through to a redirected
|
||
// file (if one exists).
|
||
//
|
||
// History: 30 Jun 1992 AlanW Created from FastFAT source.
|
||
// 09 Feb 1994 SudK Added Rename/Delete restrictions.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
|
||
#include "dfsprocs.h"
|
||
#include "dnr.h"
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_FILEINFO)
|
||
|
||
//
|
||
// Local procedure prototypes
|
||
//
|
||
|
||
NTSTATUS
|
||
DfsCommonSetInformation (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
DfsSetDispositionInfo (
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
DfsSetRenameInfo (
|
||
IN PIRP Irp,
|
||
IN PDFS_VCB Vcb,
|
||
IN PDFS_FCB Fcb
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text ( PAGE, DfsFsdQueryInformation )
|
||
#pragma alloc_text ( PAGE, DfsFsdSetInformation )
|
||
#pragma alloc_text ( PAGE, DfsFspSetInformation )
|
||
#pragma alloc_text ( PAGE, DfsCommonSetInformation )
|
||
#pragma alloc_text ( PAGE, DfsSetDispositionInfo )
|
||
#pragma alloc_text ( PAGE, DfsSetRenameInfo )
|
||
#endif // ALLOC_PRAGMA
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFsdQueryInformation, public
|
||
//
|
||
// Synopsis: This routine implements the FSD part of the
|
||
// NtQueryInformationFile API call
|
||
//
|
||
// Arguments: [DeviceObject] -- Supplies the volume device object where
|
||
// the file being queried exists.
|
||
// [Irp] -- Supplies the Irp being processed
|
||
//
|
||
// Returns: NTSTATUS - The FSD status for the Irp.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsFsdQueryInformation (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp)
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
FILE_INFORMATION_CLASS FileInformationClass;
|
||
PFILE_NAME_INFORMATION FileNameInfo;
|
||
UNICODE_STRING FileNameToUse;
|
||
ULONG BufferLength;
|
||
PFILE_OBJECT FileObject;
|
||
TYPE_OF_OPEN TypeOfOpen;
|
||
PDFS_VCB Vcb;
|
||
PDFS_FCB Fcb;
|
||
BOOLEAN completeIrp;
|
||
|
||
|
||
ASSERT(ARGUMENT_PRESENT(DeviceObject));
|
||
ASSERT(ARGUMENT_PRESENT(Irp));
|
||
|
||
DfsDbgTrace(+1, Dbg, "DfsFsdQueryInformation - Entered\n", 0);
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
|
||
|
||
DfsDbgTrace(0, Dbg, "InfoLevel = %d\n", FileInformationClass);
|
||
|
||
if (DeviceObject->DeviceType == FILE_DEVICE_MULTI_UNC_PROVIDER ||
|
||
DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM) {
|
||
|
||
DfsCompleteRequest( NULL, Irp, STATUS_INVALID_DEVICE_REQUEST );
|
||
|
||
DfsDbgTrace(-1, Dbg, "DfsFsdQueryInformation - Mup/File System\n", 0);
|
||
|
||
return( STATUS_INVALID_DEVICE_REQUEST );
|
||
|
||
}
|
||
|
||
ASSERT( DeviceObject->DeviceType == FILE_DEVICE_DFS );
|
||
|
||
if (FileInformationClass != FileNameInformation &&
|
||
FileInformationClass != FileAlternateNameInformation) {
|
||
|
||
Status = DfsVolumePassThrough(DeviceObject, Irp);
|
||
|
||
DfsDbgTrace(-1, Dbg,
|
||
"DfsFsdQueryInformation: Exit -> %08lx\n", Status );
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
FileObject = IrpSp->FileObject;
|
||
|
||
//
|
||
// Decode the file object. Remember that there need not be an Fcb always.
|
||
//
|
||
|
||
TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb);
|
||
|
||
if (Fcb != NULL) {
|
||
|
||
completeIrp = TRUE;
|
||
|
||
switch (TypeOfOpen) {
|
||
|
||
case LogicalRootDeviceOpen:
|
||
case FilesystemDeviceOpen:
|
||
|
||
//
|
||
// We cannot get info on a device open
|
||
//
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
break;
|
||
|
||
case RedirectedFileOpen:
|
||
case UnknownOpen:
|
||
|
||
FileNameInfo = (PFILE_NAME_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
BufferLength = IrpSp->Parameters.QueryFile.Length;
|
||
|
||
if (FileInformationClass == FileAlternateNameInformation)
|
||
FileNameToUse = Fcb->AlternateFileName;
|
||
else
|
||
FileNameToUse = Fcb->FullFileName;
|
||
|
||
|
||
if (BufferLength < sizeof(FILE_NAME_INFORMATION)) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
if (FileNameToUse.Length == 0) {
|
||
|
||
ASSERT(FileInformationClass == FileAlternateNameInformation);
|
||
|
||
Status = DfsVolumePassThrough(DeviceObject, Irp);
|
||
|
||
completeIrp = FALSE;
|
||
|
||
} else if (BufferLength <
|
||
(sizeof(FILE_NAME_INFORMATION) +
|
||
FileNameToUse.Length)) {
|
||
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
FileNameInfo->FileNameLength = FileNameToUse.Length;
|
||
|
||
RtlCopyMemory(
|
||
(PVOID) &FileNameInfo->FileName,
|
||
(PVOID) FileNameToUse.Buffer,
|
||
FileNameToUse.Length);
|
||
|
||
Irp->IoStatus.Information =
|
||
sizeof(FILE_NAME_INFORMATION) + FileNameToUse.Length;
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
BugCheck( "DfsCommonQueryInformation, Illegal TypeOfOpen" );
|
||
}
|
||
|
||
if (completeIrp)
|
||
DfsCompleteRequest( NULL, Irp, Status );
|
||
|
||
} else {
|
||
|
||
//
|
||
// How can this be? We don't have an FCB for a file we opened...
|
||
//
|
||
|
||
BugCheck( "DfsCommonQueryInformation, No FCB" );
|
||
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DfsDbgTrace(-1, Dbg, "DfsFsdQueryInformation -> %08lx\n", Status);
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFsdSetInformation, public
|
||
//
|
||
// Synopsis: This routine implements the FSD part of the
|
||
// NtSetInformationFile API call.
|
||
//
|
||
// Arguments: [DeviceObject] -- Supplies the volume device object where
|
||
// the file being set exists.
|
||
// [Irp] -- Supplies the Irp being processed.
|
||
//
|
||
// Returns: NTSTATUS - The FSD status for the Irp.
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsFsdSetInformation (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
) {
|
||
NTSTATUS Status;
|
||
PIRP_CONTEXT IrpContext = NULL;
|
||
ASSERT(ARGUMENT_PRESENT(DeviceObject));
|
||
ASSERT(ARGUMENT_PRESENT(Irp));
|
||
|
||
DfsDbgTrace(+1, Dbg, "DfsFsdSetInformation\n", 0);
|
||
|
||
//
|
||
// Call the common set routine, with blocking allowed if synchronous
|
||
//
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
try {
|
||
|
||
IrpContext = DfsCreateIrpContext( Irp, CanFsdWait( Irp ) );
|
||
|
||
Status = DfsCommonSetInformation( IrpContext, Irp );
|
||
|
||
} except(DfsExceptionFilter( IrpContext, GetExceptionCode(), GetExceptionInformation() )) {
|
||
|
||
//
|
||
// We had some trouble trying to perform the requested
|
||
// operation, so we'll abort the I/O request with
|
||
// the error status that we get back from the
|
||
// execption code
|
||
//
|
||
|
||
Status = DfsProcessException( IrpContext, Irp, GetExceptionCode() );
|
||
}
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DfsDbgTrace(-1, Dbg, "DfsFsdSetInformation -> %08lx\n", Status);
|
||
|
||
UNREFERENCED_PARAMETER( DeviceObject );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFspSetInformation, public
|
||
//
|
||
// Synopsis: This routine implements the FSP part of the
|
||
// NtSetInformationFile API call.
|
||
//
|
||
// Arguments: [IrpContext] -- The IRP_CONTEXT record for the operation
|
||
// [Irp] -- Supplies the Irp being processed.
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
VOID
|
||
DfsFspSetInformation (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp
|
||
) {
|
||
DfsDbgTrace(+1, Dbg, "DfsFspSetInformation\n", 0);
|
||
|
||
//
|
||
// Call the common set routine. The Fsp is always allowed to block
|
||
//
|
||
|
||
(VOID)DfsCommonSetInformation( IrpContext, Irp );
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DfsDbgTrace(-1, Dbg, "DfsFspSetInformation -> VOID\n", 0);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------
|
||
//
|
||
// Function: DfsCommonSetInformation, private
|
||
//
|
||
// Synopsis: This is the common routine for setting file information called
|
||
// by both the FSD and FSP threads.
|
||
//
|
||
// Arguments: [Irp] -- Supplies the Irp being processed
|
||
//
|
||
// Returns: NTSTATUS - The return status for the operation
|
||
//
|
||
//--------------------------------------------------------------------
|
||
//
|
||
|
||
NTSTATUS
|
||
DfsCommonSetInformation (
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PIRP Irp
|
||
) {
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PIO_STACK_LOCATION NextIrpSp;
|
||
|
||
PFILE_OBJECT FileObject;
|
||
FILE_INFORMATION_CLASS FileInformationClass;
|
||
PDEVICE_OBJECT Vdo, DeviceObject;
|
||
|
||
TYPE_OF_OPEN TypeOfOpen;
|
||
PDFS_VCB Vcb;
|
||
PDFS_FCB Fcb;
|
||
|
||
//
|
||
// Get the current stack location
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
DfsDbgTrace(+1, Dbg, "DfsCommonSetInformation...\n", 0);
|
||
DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp);
|
||
DfsDbgTrace( 0, Dbg, "->Length = %08lx\n", IrpSp->Parameters.SetFile.Length);
|
||
DfsDbgTrace( 0, Dbg, "->FileInformationClass = %08lx\n", IrpSp->Parameters.SetFile.FileInformationClass);
|
||
DfsDbgTrace( 0, Dbg, "->ReplaceFileObject = %08lx\n", IrpSp->Parameters.SetFile.FileObject);
|
||
DfsDbgTrace( 0, Dbg, "->ReplaceIfExists = %08lx\n", IrpSp->Parameters.SetFile.ReplaceIfExists);
|
||
DfsDbgTrace( 0, Dbg, "->Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
|
||
|
||
//
|
||
// Reference our input parameters to make things easier
|
||
//
|
||
|
||
FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
|
||
FileObject = IrpSp->FileObject;
|
||
DeviceObject = IrpSp->DeviceObject;
|
||
|
||
if (DeviceObject->DeviceType == FILE_DEVICE_MULTI_UNC_PROVIDER) {
|
||
DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
|
||
DfsDbgTrace(-1, Dbg, "DfsCommonSetInformation - Mup file\n", 0);
|
||
return( STATUS_INVALID_DEVICE_REQUEST );
|
||
}
|
||
|
||
//
|
||
// Decode the file object. Remember that there need not be an Fcb always.
|
||
//
|
||
|
||
TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb);
|
||
|
||
//
|
||
// Set this handle as having modified the file
|
||
//
|
||
|
||
FileObject->Flags |= FO_FILE_MODIFIED;
|
||
|
||
try {
|
||
|
||
//
|
||
// Case on the type of open we're dealing with
|
||
//
|
||
|
||
switch (TypeOfOpen) {
|
||
|
||
case LogicalRootDeviceOpen:
|
||
case FilesystemDeviceOpen:
|
||
|
||
//
|
||
// We cannot set info on a device open
|
||
//
|
||
|
||
try_return( Status = STATUS_INVALID_PARAMETER );
|
||
|
||
case RedirectedFileOpen:
|
||
case UnknownOpen:
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
BugCheck( "DfsCommonSetInformation, Illegal TypeOfOpen" );
|
||
}
|
||
|
||
//
|
||
// Copy the stack from one to the next...
|
||
//
|
||
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
||
(*NextIrpSp) = (*IrpSp);
|
||
|
||
IoSetCompletionRoutine( Irp,
|
||
NULL,
|
||
NULL,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE);
|
||
|
||
//
|
||
// Call the next device in the chain. Remember that there need
|
||
// not be an Fcb always at this point.
|
||
//
|
||
ASSERT(Fcb != NULL);
|
||
|
||
Status = IoCallDriver( Fcb->TargetDevice, Irp );
|
||
|
||
//
|
||
// The IRP will be completed by the called driver. We have
|
||
// no need for the IrpContext in the completion routine.
|
||
//
|
||
|
||
DfsDeleteIrpContext(IrpContext);
|
||
|
||
IrpContext = NULL;
|
||
|
||
Irp = NULL;
|
||
|
||
try_exit: NOTHING;
|
||
|
||
} finally {
|
||
|
||
DebugUnwind( DfsCommonSetInformation );
|
||
|
||
if (!AbnormalTermination()) {
|
||
|
||
DfsCompleteRequest( IrpContext, Irp, Status );
|
||
|
||
}
|
||
|
||
DfsDbgTrace(-1, Dbg, "DfsCommonSetInformation -> %08lx\n", Status);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|