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