489 lines
13 KiB
C
489 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"
|
|||
|
#include "mupwml.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, BytesToCopy;
|
|||
|
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", ULongToPtr(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) {
|
|||
|
|
|||
|
default:
|
|||
|
//
|
|||
|
// 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 {
|
|||
|
BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
|
|||
|
|
|||
|
if (BufferLength < FileNameToUse.Length) {
|
|||
|
BytesToCopy = BufferLength;
|
|||
|
Status = STATUS_BUFFER_OVERFLOW;
|
|||
|
BufferLength = 0;
|
|||
|
}
|
|||
|
else {
|
|||
|
BytesToCopy = FileNameToUse.Length;
|
|||
|
BufferLength -= BytesToCopy;
|
|||
|
}
|
|||
|
FileNameInfo->FileNameLength = FileNameToUse.Length;
|
|||
|
|
|||
|
if (BytesToCopy > 0) {
|
|||
|
RtlCopyMemory(
|
|||
|
(PVOID) &FileNameInfo->FileName,
|
|||
|
(PVOID) FileNameToUse.Buffer,
|
|||
|
BytesToCopy);
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Information =
|
|||
|
IrpSp->Parameters.QueryFile.Length - BufferLength;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (completeIrp)
|
|||
|
DfsCompleteRequest( NULL, Irp, Status );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
DfsCompleteRequest( NULL, Irp, Status );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// And return to our caller
|
|||
|
//
|
|||
|
|
|||
|
DfsDbgTrace(-1, Dbg, "DfsFsdQueryInformation -> %08lx\n", ULongToPtr(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 ) );
|
|||
|
if (IrpContext == NULL)
|
|||
|
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
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", ULongToPtr(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", ULongToPtr(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) {
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
//
|
|||
|
// We cannot set info on a device open
|
|||
|
//
|
|||
|
|
|||
|
try_return( Status = STATUS_INVALID_PARAMETER );
|
|||
|
|
|||
|
case RedirectedFileOpen:
|
|||
|
case UnknownOpen:
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (Fcb == NULL)
|
|||
|
try_return( Status = STATUS_INVALID_PARAMETER );
|
|||
|
|
|||
|
//
|
|||
|
// 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.
|
|||
|
//
|
|||
|
|
|||
|
Status = IoCallDriver( Fcb->TargetDevice, Irp );
|
|||
|
MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCommonSetInformation_Error_IoCallDriver,
|
|||
|
LOGSTATUS(Status)
|
|||
|
LOGPTR(Irp)
|
|||
|
LOGPTR(FileObject));
|
|||
|
|
|||
|
//
|
|||
|
// 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", ULongToPtr(Status) );
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|