522 lines
15 KiB
C
522 lines
15 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
|
|||
|
// 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 "attach.h"
|
|||
|
#include "localvol.h"
|
|||
|
#include "dfswml.h"
|
|||
|
|
|||
|
//
|
|||
|
// The local debug trace level
|
|||
|
//
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_FILEINFO)
|
|||
|
|
|||
|
//
|
|||
|
// Local procedure prototypes
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsCommonSetInformation (
|
|||
|
IN PIRP Irp,
|
|||
|
BOOLEAN DfsEnable
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsSetDispositionInfo (
|
|||
|
IN PIRP Irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsSetRenameInfo (
|
|||
|
IN PIRP Irp);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text ( PAGE, DfsFsdSetInformation )
|
|||
|
#pragma alloc_text ( PAGE, DfsCommonSetInformation )
|
|||
|
#pragma alloc_text ( PAGE, DfsSetDispositionInfo )
|
|||
|
#pragma alloc_text ( PAGE, DfsSetRenameInfo )
|
|||
|
#endif // ALLOC_PRAGMA
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------
|
|||
|
//
|
|||
|
// 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;
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
PFILE_OBJECT FileObject = irpSp->FileObject;
|
|||
|
ASSERT(ARGUMENT_PRESENT(DeviceObject));
|
|||
|
ASSERT(ARGUMENT_PRESENT(Irp));
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsFsdSetInformation\n", 0);
|
|||
|
DFS_TRACE_LOW(TRACE_IRP, DfsFsdSetInformation_Entry,
|
|||
|
LOGPTR(FileObject)
|
|||
|
LOGPTR(Irp));
|
|||
|
|
|||
|
|
|||
|
if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
|
|||
|
//
|
|||
|
// For local paths, we need to protect exit points and
|
|||
|
// local storage IDs against rename and delete. Otherwise,
|
|||
|
// pass the request along to the local file system driver.
|
|||
|
//
|
|||
|
|
|||
|
Status = DfsCommonSetInformation(
|
|||
|
Irp,
|
|||
|
((PDFS_VOLUME_OBJECT)DeviceObject)->DfsEnable);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = DfsVolumePassThrough( DeviceObject, Irp );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsFsdSetInformation: Exit -> %08lx\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
DFS_TRACE_LOW(TRACE_IRP, DfsFsdSetInformation_Exit,
|
|||
|
LOGSTATUS(Status)
|
|||
|
LOGPTR(FileObject)
|
|||
|
LOGPTR(Irp));
|
|||
|
|
|||
|
return( Status );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------
|
|||
|
//
|
|||
|
// 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 Irp,
|
|||
|
IN BOOLEAN DfsEnabled
|
|||
|
) {
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PIO_STACK_LOCATION NextIrpSp;
|
|||
|
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
FILE_INFORMATION_CLASS FileInformationClass;
|
|||
|
PDEVICE_OBJECT Vdo, DeviceObject;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Get the current stack location
|
|||
|
//
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
DFS_TRACE_LOW(TRACE_IRP, DfsCommonSetInformation_Entry,
|
|||
|
LOGPTR(Irp)
|
|||
|
LOGPTR(IrpSp->FileObject)
|
|||
|
LOGBOOLEAN(DfsEnabled));
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsCommonSetInformation...\n", 0);
|
|||
|
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
|
|||
|
DebugTrace( 0, Dbg, "->Length = %08lx\n", ULongToPtr( IrpSp->Parameters.SetFile.Length ));
|
|||
|
DebugTrace( 0, Dbg, "->FileInformationClass = %08lx\n", IrpSp->Parameters.SetFile.FileInformationClass);
|
|||
|
DebugTrace( 0, Dbg, "->ReplaceFileObject = %08lx\n", IrpSp->Parameters.SetFile.FileObject);
|
|||
|
DebugTrace( 0, Dbg, "->ReplaceIfExists = %08lx\n", IrpSp->Parameters.SetFile.ReplaceIfExists);
|
|||
|
DebugTrace( 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;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
//
|
|||
|
// Based on the information class we'll do different
|
|||
|
// actions. Each of the procedures that we're calling will either
|
|||
|
// complete the request of send the request off to the fsp
|
|||
|
// to do the work.
|
|||
|
//
|
|||
|
|
|||
|
switch (FileInformationClass) {
|
|||
|
|
|||
|
case FileRenameInformation:
|
|||
|
case FileDispositionInformation:
|
|||
|
|
|||
|
if (DfsEnabled) {
|
|||
|
if (FileInformationClass == FileRenameInformation) {
|
|||
|
Status = DfsSetRenameInfo( Irp );
|
|||
|
}
|
|||
|
else {
|
|||
|
Status = DfsSetDispositionInfo( Irp );
|
|||
|
}
|
|||
|
|
|||
|
if (Status != STATUS_MORE_PROCESSING_REQUIRED)
|
|||
|
break;
|
|||
|
}
|
|||
|
// NOTE: Fall through
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
//
|
|||
|
// Copy the stack from one to the next...
|
|||
|
//
|
|||
|
|
|||
|
NextIrpSp = IoGetNextIrpStackLocation(Irp);
|
|||
|
(*NextIrpSp) = (*IrpSp);
|
|||
|
|
|||
|
IoSetCompletionRoutine( Irp,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
FALSE,
|
|||
|
FALSE,
|
|||
|
FALSE);
|
|||
|
|
|||
|
Vdo = ((PDFS_VOLUME_OBJECT)DeviceObject)->Provider.DeviceObject;
|
|||
|
|
|||
|
Status = IoCallDriver( Vdo, Irp);
|
|||
|
DFS_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCommonDetInformation_Error_IoCallDriver,
|
|||
|
LOGPTR(Irp)
|
|||
|
LOGPTR(FileObject)
|
|||
|
LOGSTATUS(Status));
|
|||
|
|
|||
|
//
|
|||
|
// The IRP will be completed by the called driver.
|
|||
|
//
|
|||
|
|
|||
|
Irp = NULL;
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} finally {
|
|||
|
|
|||
|
if (!AbnormalTermination()) {
|
|||
|
|
|||
|
DfsCompleteRequest( Irp, Status );
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsCommonSetInformation -> %08lx\n", ULongToPtr( Status ));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DFS_TRACE_LOW(TRACE_IRP, DfsCommonSetInformation_Exit,
|
|||
|
LOGSTATUS(Status)
|
|||
|
LOGPTR(FileObject)
|
|||
|
LOGPTR(Irp));
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsSetDispositionInfo, private
|
|||
|
//
|
|||
|
// Synopsis: This routine performs the set name information for DFS. In
|
|||
|
// many cases, this is simply done by sending it along to the
|
|||
|
// redirected or attached file object. If, however, this is a
|
|||
|
// local volume and the storageId is about to be deleted the
|
|||
|
// the operation will be refused.
|
|||
|
//
|
|||
|
// Arguments: [Irp] -- Supplies the IRP being processed
|
|||
|
//
|
|||
|
// Returns: NTSTATUS - The result of this operation if it completes
|
|||
|
// without an exception. STATUS_MORE_PROCESSING_REQUIRED
|
|||
|
// is returned if the request should just be passed on
|
|||
|
// to the attached-to device.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
DfsSetDispositionInfo (
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PDFS_PKT Pkt;
|
|||
|
PDFS_LOCAL_VOL_ENTRY lv;
|
|||
|
|
|||
|
//
|
|||
|
// The following variables are for abnormal termination
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN LockedPkt = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Get the current stack location
|
|||
|
//
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
DeviceObject = IrpSp->DeviceObject;
|
|||
|
FileObject = IrpSp->FileObject;
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsSetDispositionInfo...\n", 0);
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
PDFS_FCB fcb;
|
|||
|
|
|||
|
fcb = DfsLookupFcb( FileObject );
|
|||
|
|
|||
|
if (fcb != NULL) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "File Delete on %wZ attempted\n",
|
|||
|
&fcb->FullFileName);
|
|||
|
|
|||
|
//
|
|||
|
// Now we have the full file name of file we are trying to delete
|
|||
|
//
|
|||
|
|
|||
|
Pkt = _GetPkt();
|
|||
|
|
|||
|
PktAcquireShared(Pkt, TRUE);
|
|||
|
|
|||
|
LockedPkt = TRUE;
|
|||
|
|
|||
|
if (DfsFileOnExitPath( Pkt, &fcb->FullFileName )) {
|
|||
|
try_return( Status = STATUS_ACCESS_DENIED );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
|
|||
|
try_exit: NOTHING;
|
|||
|
|
|||
|
} finally {
|
|||
|
|
|||
|
//
|
|||
|
// Release the PKT if locked. FreeMemory if allocated.
|
|||
|
//
|
|||
|
|
|||
|
if (LockedPkt)
|
|||
|
PktRelease(&DfsData.Pkt);
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsSetDispositionInfo -> %08lx\n", ULongToPtr( Status ));
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfspRenameAllowed()
|
|||
|
{
|
|||
|
return( STATUS_SUCCESS );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+--------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsSetRenameInfo, private
|
|||
|
//
|
|||
|
// Synopsis: This routine performs the set name information for DFS. In
|
|||
|
// many cases, this is simply done by sending it along to the
|
|||
|
// redirected or attached file object. If, however, this is a
|
|||
|
// local volume and there are volume exit points below a
|
|||
|
// directory being renamed, DFS knowledge is being changed, and
|
|||
|
// the operation will be refused unless this is being done as
|
|||
|
// part of the rename DFS path administrative operation.
|
|||
|
//
|
|||
|
// Arguments: [Irp] -- Supplies the IRP being processed
|
|||
|
//
|
|||
|
// Returns: [STATUS_MORE_PROCESSING_REQUIRED] -- Caller should continue
|
|||
|
// processing of the Irp by forwarding it to the
|
|||
|
// underlying file system driver.
|
|||
|
//
|
|||
|
// [STATUS_NOT_SAME_DEVICE] -- Indicates the source file object
|
|||
|
// and the target file object are not on the same device.
|
|||
|
//
|
|||
|
// [STATUS_INVALID_PARAMETER] -- Operation is invalid for the
|
|||
|
// type of file object or target file object.
|
|||
|
//
|
|||
|
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate memory
|
|||
|
// for the operation.
|
|||
|
//
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsSetRenameInfo (
|
|||
|
IN PIRP Irp)
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
|
|||
|
PIO_STACK_LOCATION IrpSp;
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PDFS_VOLUME_OBJECT dfsVdo;
|
|||
|
PFILE_OBJECT FileObject;
|
|||
|
PFILE_OBJECT TargetFileObject;
|
|||
|
PDFS_PKT Pkt;
|
|||
|
PUNICODE_PREFIX_TABLE_ENTRY lvpfx;
|
|||
|
PDFS_LOCAL_VOL_ENTRY lv;
|
|||
|
PDFS_FCB fcb;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The following variables are for abnormal termination
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN LockedPkt = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Get the current stack location
|
|||
|
//
|
|||
|
|
|||
|
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
DeviceObject = IrpSp->DeviceObject;
|
|||
|
dfsVdo = (PDFS_VOLUME_OBJECT) DeviceObject;
|
|||
|
TargetFileObject = IrpSp->Parameters.SetFile.FileObject;
|
|||
|
FileObject = IrpSp->FileObject;
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "DfsSetRenameInfo...\n", 0);
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
|
|||
|
|
|||
|
//
|
|||
|
// This is the hard case. We have to do a lookup of the local
|
|||
|
// name and look for conflicts.
|
|||
|
//
|
|||
|
|
|||
|
fcb = DfsLookupFcb(FileObject);
|
|||
|
|
|||
|
if (fcb != NULL) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg,
|
|||
|
"File Rename on %wZ attempted\n", &fcb->FullFileName);
|
|||
|
|
|||
|
//
|
|||
|
// Now we have the full file name of file we are trying to rename.
|
|||
|
//
|
|||
|
|
|||
|
Pkt = _GetPkt();
|
|||
|
|
|||
|
PktAcquireShared(Pkt, TRUE);
|
|||
|
|
|||
|
LockedPkt = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// First we make sure that we are not renaming any storageId.
|
|||
|
//
|
|||
|
lvpfx = DfsNextUnicodePrefix(&Pkt->LocalVolTable, TRUE);
|
|||
|
|
|||
|
while (lvpfx != NULL) {
|
|||
|
|
|||
|
lv = CONTAINING_RECORD(
|
|||
|
lvpfx,
|
|||
|
DFS_LOCAL_VOL_ENTRY,
|
|||
|
PrefixTableEntry);
|
|||
|
|
|||
|
if (DfsRtlPrefixPath(&fcb->FullFileName, &lv->LocalPath, TRUE)) {
|
|||
|
|
|||
|
try_return(Status = STATUS_ACCESS_DENIED);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
lvpfx = DfsNextUnicodePrefix(&Pkt->LocalVolTable, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now we only need to make sure that we are not renaming an
|
|||
|
// exit path.
|
|||
|
//
|
|||
|
|
|||
|
if (DfsFileOnExitPath(Pkt, &fcb->FullFileName)) {
|
|||
|
|
|||
|
//
|
|||
|
// If this is a namespace reorg then if caller is DfsManager
|
|||
|
// allow the access else fail the call.
|
|||
|
//
|
|||
|
|
|||
|
if (DfspRenameAllowed()) {
|
|||
|
|
|||
|
try_return(Status = STATUS_MORE_PROCESSING_REQUIRED);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
try_return(Status = STATUS_ACCESS_DENIED);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
try_exit: NOTHING;
|
|||
|
|
|||
|
} finally {
|
|||
|
|
|||
|
//
|
|||
|
// Release the PKT if locked. FreeMemory if allocated.
|
|||
|
//
|
|||
|
|
|||
|
if (LockedPkt)
|
|||
|
PktRelease(&DfsData.Pkt);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "DfsSetRenameInfo -> %08lx\n", ULongToPtr( Status ));
|
|||
|
|
|||
|
return(Status);
|
|||
|
|
|||
|
}
|
|||
|
|