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