windows-nt/Source/XPSP1/NT/base/fs/dfs/driver/fileinfo.c

522 lines
15 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// 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);
}