|
|
//+----------------------------------------------------------------------------
//
// File: create.c
//
// Contents:
//
// This module implements the File Create routine for Dfs called by the
// dispatch driver. Unlike traditional disk-based FSDs, there is only
// one entry point, DfsFsdCreate. The request is assumed to be
// synchronous (whether the user thread requests it or not).
// Of course, since we will typically be calling out to some other
// FSD, that FSD may post the request and return to us with a
// STATUS_PENDING.
//
// Functions: DfsFsdCreate - FSD entry point for NtCreateFile/NtOpenFile
// DfsCommonCreate, local
// DfsPassThroughRelativeOpen, local
// DfsCompleteRelativeOpen, local
// DfsPostProcessRelativeOpen, local
// DfsRestartRelativeOpen, local
// DfsComposeFullName, local
// DfsAreFilesOnSameLocalVolume, local
//
// History: 27 Jan 1992 AlanW Created.
//
//-----------------------------------------------------------------------------
#include "dfsprocs.h"
#include "dnr.h"
#include "fcbsup.h"
#include "mupwml.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_CREATE)
//
// Local procedure prototypes
//
NTSTATUS DfsCommonCreate ( OPTIONAL IN PIRP_CONTEXT IrpContext, PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
IO_STATUS_BLOCK DfsOpenDevice ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject, IN ACCESS_MASK DesiredAccess, IN USHORT ShareAccess, IN ULONG CreateOptions);
NTSTATUS DfsPassThroughRelativeOpen( IN PIRP Irp, IN PIRP_CONTEXT IrpContext, IN PDFS_FCB ParentFcb);
NTSTATUS DfsCompleteRelativeOpen( IN PDEVICE_OBJECT pDevice, IN PIRP Irp, IN PVOID Context);
NTSTATUS DfsPostProcessRelativeOpen( IN PIRP Irp, IN PIRP_CONTEXT IrpContext, IN PDFS_FCB ParentFcb);
VOID DfsRestartRelativeOpen( IN PIRP_CONTEXT IrpContext);
NTSTATUS DfsComposeFullName( IN PUNICODE_STRING ParentName, IN PUNICODE_STRING RelativeName, OUT PUNICODE_STRING FullName);
NTSTATUS DfsAreFilesOnSameLocalVolume( IN PUNICODE_STRING ParentName, IN PUNICODE_STRING FileName);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, DfsFsdCreate )
#pragma alloc_text( PAGE, DfsCommonCreate )
#pragma alloc_text( PAGE, DfsOpenDevice )
#pragma alloc_text( PAGE, DfsPassThroughRelativeOpen )
#pragma alloc_text( PAGE, DfsPostProcessRelativeOpen )
#pragma alloc_text( PAGE, DfsRestartRelativeOpen )
#pragma alloc_text( PAGE, DfsComposeFullName )
#pragma alloc_text( PAGE, DfsAreFilesOnSameLocalVolume )
//
// The following are not pageable since they can be called at DPC level
//
// DfsCompleteRelativeOpen
//
#endif // ALLOC_PRAGMA
//+-------------------------------------------------------------------
//
// Function: DfsFsdCreate, public
//
// Synopsis: This routine implements the FSD part of the NtCreateFile
// and NtOpenFile API calls.
//
// Arguments: [DeviceObject] -- Supplies the device object where
// the file/directory exists that we are trying
// to open/create exists
// [Irp] - Supplies the Irp being processed
//
// Returns: NTSTATUS - The Fsd status for the Irp
//
//--------------------------------------------------------------------
NTSTATUS DfsFsdCreate ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS Status; PIRP_CONTEXT IrpContext = NULL; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PFILE_OBJECT FileObject = IrpSp->FileObject; PDFS_FCB pFcb = NULL;
DfsDbgTrace(+1, Dbg, "DfsFsdCreate: Entered\n", 0);
MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCreate_Entry, LOGPTR(DeviceObject) LOGPTR(FileObject) LOGUSTR(FileObject->FileName) LOGPTR(Irp));
ASSERT(IoIsOperationSynchronous(Irp) == TRUE);
//
// Call the common create routine, with block allowed if the operation
// is synchronous.
//
try {
IrpContext = DfsCreateIrpContext( Irp, CanFsdWait( Irp ) ); if (IrpContext == NULL) ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); Status = DfsCommonCreate( IrpContext, DeviceObject, 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() );
}
//
// And return to our caller
//
DfsDbgTrace(-1, Dbg, "DfsFsdCreate: Exit -> %08lx\n", ULongToPtr(Status) ); MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCreate_Exit, LOGSTATUS(Status) LOGPTR(DeviceObject) LOGPTR(FileObject) LOGPTR(Irp)); return Status; }
//+-------------------------------------------------------------------
// Function: DfsCommonCreate, private
//
// Synopsis: This is the common routine for creating/opening a file
// called by both the FSD and FSP threads.
//
// Arguments: [DeviceObject] - The device object associated with
// the request.
// [Irp] -- Supplies the Irp to process
//
// Returns: NTSTATUS - the return status for the operation
//
//--------------------------------------------------------------------
NTSTATUS DfsCommonCreate ( OPTIONAL IN PIRP_CONTEXT IrpContext, IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) {
IO_STATUS_BLOCK Iosb; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PDFS_VCB Vcb = NULL; PDFS_FCB Fcb = NULL;
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT RelatedFileObject; UNICODE_STRING FileName; ACCESS_MASK DesiredAccess; ULONG CreateOptions; USHORT ShareAccess; NTSTATUS Status; LARGE_INTEGER StartTime; LARGE_INTEGER EndTime;
DfsDbgTrace(+1, Dbg, "DfsCommonCreate\n", 0 ); DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp ); DfsDbgTrace( 0, Dbg, "->Flags = %08lx\n", ULongToPtr(Irp->Flags) ); DfsDbgTrace( 0, Dbg, "->FileObject = %08lx\n", FileObject ); DfsDbgTrace( 0, Dbg, " ->RelatedFileObject = %08lx\n", FileObject->RelatedFileObject ); DfsDbgTrace( 0, Dbg, " ->FileName = %wZ\n", &FileObject->FileName ); DfsDbgTrace( 0, Dbg, "->DesiredAccess = %08lx\n", ULongToPtr(IrpSp->Parameters.Create.SecurityContext->DesiredAccess) ); DfsDbgTrace( 0, Dbg, "->CreateOptions = %08lx\n", ULongToPtr(IrpSp->Parameters.Create.Options) ); DfsDbgTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes ); DfsDbgTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess ); DfsDbgTrace( 0, Dbg, "->EaLength = %08lx\n", ULongToPtr(IrpSp->Parameters.Create.EaLength) );
KeQuerySystemTime(&StartTime); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] DfsCommonCreate(%wZ)\n", (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)), &FileObject->FileName); } #endif
//
// Reference our input parameters to make things easier
//
RelatedFileObject = IrpSp->FileObject->RelatedFileObject; FileName = *((PUNICODE_STRING) &IrpSp->FileObject->FileName); DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; CreateOptions = IrpSp->Parameters.Create.Options; ShareAccess = IrpSp->Parameters.Create.ShareAccess;
Iosb.Status = STATUS_SUCCESS;
//
// Short circuit known invalid opens.
//
if ((IrpSp->Flags & SL_OPEN_PAGING_FILE) != 0) {
DfsDbgTrace(0, Dbg, "DfsCommonCreate: Paging file not allowed on Dfs\n", 0);
Iosb.Status = STATUS_INVALID_PARAMETER;
MUP_TRACE_HIGH(ERROR, DfsCommonCreate_Error_PagingFileNotAllowed, LOGSTATUS(Iosb.Status) LOGPTR(DeviceObject) LOGPTR(FileObject) LOGPTR(Irp));
DfsCompleteRequest( IrpContext, Irp, Iosb.Status );
DfsDbgTrace(-1, Dbg, "DfsCommonCreate: Exit -> %08lx\n", ULongToPtr(Iosb.Status));
return Iosb.Status;
}
//
// There are several cases we need to handle here.
//
// 1. FileName is 0 length
//
// If the filename length is 0, then someone really wants to open the
// device object itself.
//
// 2. This is a Relative open and the parent is on the same volume,
// either local or remote.
//
// We pass through the relative open to the driver that opened the
// parent.
//
// 3. This is a relative open and the parent is on a different volume.
//
// Form the full name of the file by concatenating the parent's
// name with the relative file name. Stick this name in the FileObject
// and do DNR on the full name.
//
// 4. This is a relative open and the parent is a device object (ie,
// the parent was opened via case 1)
//
// Assume the parent name is \, so concatenate \ with the relative
// file name. Stick this name in the FileObject and do DNR on the
// the full name.
//
// 5. This is an absolute open, (or a case 3/4 converted to an absolute
// open), and the SL_OPEN_TARGET_DIRECTORY bis *is* set.
//
// a. If the file's immediate parent directory is on the same local
// volume as the file, then do a regular DNR, and let the
// underlying FS handle the SL_OPEN_TARGET_DIRECTORY.
//
// b. If the file's immediate parent directory is on a local volume
// and the file is not on the same local volume, then immediately
// return STATUS_NOT_SAME_DEVICE.
//
// c. If the file's immediate parent directory is on a remote volume,
// then do a full DNR. This will pass through the
// SL_OPEN_TARGET_DIRECTORY to the remote Dfs driver, which will
// handle it as case 5a. or 5b.
//
// 6. This is an absolute open, (or a case 3/4 converted to an absolute
// open), and the SL_OPEN_TARGET_DIRECTORY bit is *not* set.
//
// Do a DNR on the FileObject's name.
//
try {
//
// Check to see if we are opening a device object. If so, and the
// file is being opened on the File system device object, it will
// only permit FsCtl and Close operations to be performed.
//
if ( (FileName.Length == 0 && RelatedFileObject == NULL) || (DeviceObject != NULL && DeviceObject->DeviceType != FILE_DEVICE_DFS && RelatedFileObject == NULL) ) {
//
// This is case 1.
//
// In this case there had better be a DeviceObject
//
ASSERT(ARGUMENT_PRESENT(DeviceObject));
DfsDbgTrace(0, Dbg, "DfsCommonCreate: Opening the device, DevObj = %08lx\n", DeviceObject);
Iosb = DfsOpenDevice( IrpContext, FileObject, DeviceObject, DesiredAccess, ShareAccess, CreateOptions);
Irp->IoStatus.Information = Iosb.Information;
DfsCompleteRequest( IrpContext, Irp, Iosb.Status );
try_return( Iosb.Status );
}
if (DeviceObject != NULL && DeviceObject->DeviceType == FILE_DEVICE_DFS) { Vcb = &(((PLOGICAL_ROOT_DEVICE_OBJECT)DeviceObject)->Vcb); }
//
// If there is a related file object, then this is a relative open.
//
if (RelatedFileObject != NULL) {
//
// This is case 2, 3, or 4.
//
PDFS_VCB TempVcb; TYPE_OF_OPEN OpenType; UNICODE_STRING NewFileName;
OpenType = DfsDecodeFileObject( RelatedFileObject, &TempVcb, &Fcb);
if (OpenType == RedirectedFileOpen) {
DfsDbgTrace(0, Dbg, "Relative file open: DFS_FCB = %08x\n", Fcb); DfsDbgTrace(0, Dbg, " Directory: %wZ\n", &Fcb->FullFileName); DfsDbgTrace(0, Dbg, " Relative file: %wZ\n", &FileName);
//
// This is case 2.
//
DfsDbgTrace(0, Dbg, "Trying pass through of relative open\n", 0);
Iosb.Status = DfsPassThroughRelativeOpen( Irp, IrpContext, Fcb );
try_return( Iosb.Status );
} else if (OpenType == LogicalRootDeviceOpen) {
//
// This is case 4.
//
// If the open is relative to a logical root open, then we
// are forced to convert it to an absolute open, since there
// is no underlying FS backing up the logical root to pass
// the relative open to first.
//
DfsDbgTrace( 0, Dbg, "DfsCommonCreate: Open relative to Logical Root\n", 0);
ASSERT (TempVcb == Vcb);
NewFileName.MaximumLength = sizeof (WCHAR) + FileName.Length;
NewFileName.Buffer = (PWCHAR) ExAllocatePoolWithTag( NonPagedPool, NewFileName.MaximumLength, ' puM');
if (NewFileName.Buffer == NULL) {
Iosb.Status = STATUS_INSUFFICIENT_RESOURCES;
DfsCompleteRequest( IrpContext, Irp, Iosb.Status );
try_return( Iosb.Status );
}
NewFileName.Buffer[0] = L'\\';
NewFileName.Length = sizeof (WCHAR);
} else {
Iosb.Status = STATUS_INVALID_HANDLE;
DfsCompleteRequest( IrpContext, Irp, Iosb.Status );
DfsDbgTrace(0, Dbg, "DfsCommonCreate: Invalid related file object\n", 0);
try_return( Iosb.Status );
}
(void) DnrConcatenateFilePath ( &NewFileName, FileName.Buffer, FileName.Length);
if (IrpSp->FileObject->FileName.Buffer) ExFreePool( IrpSp->FileObject->FileName.Buffer );
FileName = IrpSp->FileObject->FileName = NewFileName;
}
ASSERT(FileName.Length != 0);
//
// This is case 5b, 5c, or 6 - Do a full DNR.
//
if (Vcb == NULL) {
DfsDbgTrace(0, Dbg, "DfsCommonCreate: Null Vcb!\n", 0);
Iosb.Status = STATUS_INVALID_PARAMETER; MUP_TRACE_HIGH(ERROR, DfsCommonCreate_Error_NullVcb, LOGSTATUS(Iosb.Status) LOGPTR(DeviceObject) LOGPTR(FileObject) LOGPTR(Irp)); DfsCompleteRequest(IrpContext, Irp, Iosb.Status);
try_return(Iosb.Status);
}
Iosb.Status = DnrStartNameResolution(IrpContext, Irp, Vcb);
try_exit: NOTHING; } finally {
DfsDbgTrace(-1, Dbg, "DfsCommonCreate: Exit -> %08lx\n", ULongToPtr(Iosb.Status)); #if DBG
if (MupVerbose) { KeQuerySystemTime(&EndTime); DbgPrint("[%d] DfsCommonCreate exit 0x%x\n", (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)), Iosb.Status); } #endif
}
return Iosb.Status; }
//+-------------------------------------------------------------------
//
// Function: DfsOpenDevice, local
//
// Synopsis: This routine opens the specified device for direct
// access.
//
// Arguments: [FileObject] - Supplies the File object
// [DeviceObject] - Supplies the object denoting the device
// being opened
// [DesiredAccess] - Supplies the desired access of the caller
// [ShareAccess] - Supplies the share access of the caller
// [CreateOptions] - Supplies the create options for
// this operation
//
// Returns: [IO_STATUS_BLOCK] - Returns the completion status for
// the operation
//
//--------------------------------------------------------------------
IO_STATUS_BLOCK DfsOpenDevice ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject, IN ACCESS_MASK DesiredAccess, IN USHORT ShareAccess, IN ULONG CreateOptions ) { IO_STATUS_BLOCK Iosb; PDFS_VCB Vcb = NULL;
//
// The following variables are for abnormal termination
//
BOOLEAN UnwindShareAccess = FALSE; BOOLEAN UnwindVolumeLock = FALSE;
DfsDbgTrace( +1, Dbg, "DfsOpenDevice: Entered\n", 0 );
try {
//
// Check to see which type of device is being opened.
// We don't permit all open modes on the file system
// device object.
//
if (DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM ) { ULONG CreateDisposition = (CreateOptions >> 24) & 0x000000ff;
//
// Check for proper desired access and rights
//
if (CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OPEN_IF ) {
Iosb.Status = STATUS_ACCESS_DENIED; MUP_TRACE_HIGH(ERROR, DfsOpenDevice_Error_BadDisposition, LOGSTATUS(Iosb.Status) LOGPTR(DeviceObject) LOGPTR(FileObject)); try_return( Iosb ); }
//
// Check if we were to open a directory
//
if (CreateOptions & FILE_DIRECTORY_FILE) { DfsDbgTrace(0, Dbg, "DfsOpenDevice: Cannot open device as a directory\n", 0);
Iosb.Status = STATUS_NOT_A_DIRECTORY; MUP_TRACE_HIGH(ERROR, DfsOpenDevice_Error_CannotOpenAsDirectory, LOGSTATUS(Iosb.Status) LOGPTR(DeviceObject) LOGPTR(FileObject)); try_return( Iosb ); }
DfsSetFileObject( FileObject, FilesystemDeviceOpen, DeviceObject );
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED; try_return( Iosb ); }
ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE); Vcb = & (((PLOGICAL_ROOT_DEVICE_OBJECT)DeviceObject)->Vcb);
//
// If the user does not want to share anything then we will try and
// take out a lock on the volume. We check if the volume is already
// in use, and if it is then we deny the open
//
if ((ShareAccess & ( FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)) == 0 ) {
if (Vcb->OpenFileCount != 0) {
ExReleaseResourceLite( &DfsData.Resource ); Iosb.Status = STATUS_ACCESS_DENIED; MUP_TRACE_HIGH(ERROR, DfsOpenDevice_Error_FileInUse, LOGSTATUS(Iosb.Status) LOGPTR(DeviceObject) LOGPTR(FileObject));
try_return( Iosb ); }
//
// Lock the volume
//
Vcb->VcbState |= VCB_STATE_FLAG_LOCKED; Vcb->FileObjectWithVcbLocked = FileObject; UnwindVolumeLock = TRUE; }
//
// If the volume is already opened by someone then we need to check
// the share access
//
if (Vcb->DirectAccessOpenCount > 0) {
if ( !NT_SUCCESS( Iosb.Status = IoCheckShareAccess( DesiredAccess, ShareAccess, FileObject, &Vcb->ShareAccess, TRUE ))) { ExReleaseResourceLite( &DfsData.Resource );
MUP_TRACE_ERROR_HIGH(Iosb.Status, ALL_ERROR, DfsOpenDevice_Error_IoCheckShareAccess, LOGSTATUS(Iosb.Status) LOGPTR(DeviceObject) LOGPTR(FileObject));
try_return( Iosb ); }
} else {
IoSetShareAccess( DesiredAccess, ShareAccess, FileObject, &Vcb->ShareAccess ); }
UnwindShareAccess = TRUE;
//
// Bug: 425017. Update the counters with lock held to avoid race between multiple processors.
//
InterlockedIncrement(&Vcb->DirectAccessOpenCount); InterlockedIncrement(&Vcb->OpenFileCount);
ExReleaseResourceLite( &DfsData.Resource ); //
// Setup the context pointers, and update
// our reference counts
//
DfsSetFileObject( FileObject, LogicalRootDeviceOpen, Vcb );
//
// And set our status to success
//
Iosb.Status = STATUS_SUCCESS; Iosb.Information = FILE_OPENED;
try_exit: NOTHING; } finally {
//
// If this is an abnormal termination then undo our work
//
if (AbnormalTermination() && (Vcb != NULL)) {
if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Vcb->ShareAccess ); }
if (UnwindVolumeLock) { Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; Vcb->FileObjectWithVcbLocked = NULL; }
}
DfsDbgTrace(-1, Dbg, "DfsOpenDevice: Exit -> Iosb.Status = %08lx\n", ULongToPtr(Iosb.Status)); }
return Iosb; }
//+----------------------------------------------------------------------------
//
// Function: DfsPassThroughRelativeOpen
//
// Synopsis: Passes through a relative open call to the device handling
// the parent. This is required for structured storages on OFS
// to work, for replication's Do-not-cross-JP sematics to work,
// and as an optimization.
//
// Arguments: [Irp] -- The open Irp, which we will pass through.
// [IrpContext] -- Associated with the above Irp.
// [ParentFcb] -- Fcb of related file object.
//
// Returns: Status returned by the underlying FS, or by DNR if
// the underlying FS complained about STATUS_DFS_EXIT_PATH_FOUND.
//
//-----------------------------------------------------------------------------
NTSTATUS DfsPassThroughRelativeOpen( IN PIRP Irp, IN PIRP_CONTEXT IrpContext, IN PDFS_FCB ParentFcb) {
NTSTATUS Status; PIO_STACK_LOCATION IrpSp, NextIrpSp; PFILE_OBJECT FileObject; PDFS_FCB NewFcb; UNICODE_STRING NewFileName;
DfsDbgTrace(+1, Dbg, "DfsPassThroughRelativeOpen: Entered\n", 0);
IrpSp = IoGetCurrentIrpStackLocation(Irp); FileObject = IrpSp->FileObject;
//
// Prepare to pass the request to the device handling the parent open.
//
//
// First, we preallocate an DFS_FCB, assuming that the relative open will
// succeed. We need to do this at this point in time because the
// FileObject->FileName is still intact; after we pass through, the
// underlying can do as it wishes with the FileName field, and we will
// be unable to construct the full file name for the DFS_FCB.
//
Status = DfsComposeFullName( &ParentFcb->FullFileName, &IrpSp->FileObject->FileName, &NewFileName);
if (!NT_SUCCESS(Status)) { DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Unable to create full Name %08lx\n", ULongToPtr(Status) ); DfsCompleteRequest( IrpContext, Irp, Status ); return( Status ); }
NewFcb = DfsCreateFcb( NULL, ParentFcb->Vcb, &NewFileName );
if (NewFcb == NULL) {
if (NewFileName.Buffer != NULL) ExFreePool(NewFileName.Buffer); Status = STATUS_INSUFFICIENT_RESOURCES; DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Exited %08lx\n", ULongToPtr(Status));
DfsCompleteRequest( IrpContext, Irp, Status ); return( Status );
}
// Changes for 426540. Do all the right logic for CSC.
// since DFS does not "failover" for relative names, allow CSC to go
// offline if necessary to serve the name. This does mean that the DFS
// namespace will be served by the CSC even when one of the DFS alternates
// exists.
NewFcb->DfsNameContext.Flags = DFS_FLAG_LAST_ALTERNATE;
if (NewFcb->Vcb != NULL) { if (NewFcb->Vcb->VcbState & VCB_STATE_CSCAGENT_VOLUME) { NewFcb->DfsNameContext.NameContextType = DFS_CSCAGENT_NAME_CONTEXT; } else { NewFcb->DfsNameContext.NameContextType = DFS_USER_NAME_CONTEXT; } }
NewFcb->TargetDevice = ParentFcb->TargetDevice; NewFcb->ProviderId = ParentFcb->ProviderId; NewFcb->DfsMachineEntry = ParentFcb->DfsMachineEntry; NewFcb->FileObject = IrpSp->FileObject;
DfsSetFileObject(IrpSp->FileObject, RedirectedFileOpen, NewFcb );
IrpSp->FileObject->FsContext = &(NewFcb->DfsNameContext); if (ParentFcb->ProviderId == PROV_ID_DFS_RDR) { IrpSp->FileObject->FsContext2 = UIntToPtr(DFS_OPEN_CONTEXT); }
if (NewFileName.Buffer != NULL) ExFreePool( NewFileName.Buffer );
//
// Next, setup the IRP stack location
//
NextIrpSp = IoGetNextIrpStackLocation(Irp); (*NextIrpSp) = (*IrpSp);
//
// Put the parent DFS_FCB pointer in the IrpContext.
//
IrpContext->Context = (PVOID) NewFcb;
IoSetCompletionRoutine( Irp, DfsCompleteRelativeOpen, IrpContext, TRUE, TRUE, TRUE);
Status = IoCallDriver( ParentFcb->TargetDevice, Irp ); MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsPassThroughRelativeOpen_Error_IoCallDriver, LOGSTATUS(Status) LOGPTR(FileObject) LOGPTR(Irp));
DfsDbgTrace(0, Dbg, "IoCallDriver returned %08lx\n", ULongToPtr(Status));
if (Status != STATUS_PENDING) {
Status = DfsPostProcessRelativeOpen( Irp, IrpContext, NewFcb);
}
DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Exited %08lx\n", ULongToPtr(Status));
return( Status );
}
//+----------------------------------------------------------------------------
//
// Function: DfsCompleteRelativeOpen
//
// Synopsis: Completion routine for DfsPassThroughRelativeOpen. It is
// interesting only in case where STATUS_PENDING was originally
// returned from IoCallDriver. If so, then this routine simply
// queues DfsRestartRelativeOpen to a work queue. Note that it
// must queue an item at this stage instead of doing the work
// itself because this routine is executed at DPC level.
//
// Arguments: [pDevice] -- Our device object.
// [Irp] -- The Irp being completed.
// [IrpContext] -- Context associated with Irp.
//
// Returns: STATUS_MORE_PROCESSING_REQUIRED. Either the posted routine
// or DfsPassThroughRelativeOpen must complete the IRP for real.
//
//-----------------------------------------------------------------------------
NTSTATUS DfsCompleteRelativeOpen( IN PDEVICE_OBJECT pDevice, IN PIRP Irp, IN PIRP_CONTEXT IrpContext) {
DfsDbgTrace( +1, Dbg, "DfsCompleteRelativeOpen: Entered\n", 0);
//
// We are only interested in the case when the pass through of relative
// opens returned STATUS_PENDING. In that case, the original thread has
// popped all the way back to the caller of NtCreateFile, and we need
// to finish the open in an asynchronous manner.
//
if (Irp->PendingReturned) {
DfsDbgTrace(0, Dbg, "Pending returned : Queuing DfsRestartRelativeOpen\n", 0);
//
// We need to call IpMarkIrpPending so the IoSubsystem will realize
// that our FSD routine returned STATUS_PENDING. We can't call this
// from the FSD routine itself because the FSD routine doesn't have
// access to the stack location when the underlying guy returns
// STATUS_PENDING
//
IoMarkIrpPending( Irp );
ExInitializeWorkItem( &(IrpContext->WorkQueueItem), DfsRestartRelativeOpen, (PVOID) IrpContext );
ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
}
//
// We MUST return STATUS_MORE_PROCESSING_REQUIRED to halt the completion
// of the Irp. Either DfsRestartRelativeOpen that we queued above or
// DfsPassThroughRelativeOpen will complete the IRP after it is done.
//
DfsDbgTrace(-1, Dbg, "DfsCompleteRelativeOpen: Exited\n", 0);
return( STATUS_MORE_PROCESSING_REQUIRED );
}
//+----------------------------------------------------------------------------
//
// Function: DfsPostProcessRelativeOpen
//
// Synopsis: Continues a relative open after it has already been passed
// to the device of the parent. One of three things could have
// happened -
//
// a) The device of the parent successfully handled the open.
// We create an fcb and return.
// b) The device of the parent could not do the open for some
// reason other than STATUS_DFS_EXIT_PATH_FOUND. We return
// the error to the caller.
// c) The device of the parent returned STATUS_DFS_EXIT_PATH
// found. In that case, we convert the relative open to an
// absolute open and do a full Dnr.
//
// Arguments: [Irp] -- Pointer to Irp
// [IrpContext] -- Pointer to IrpContext associated with Irp
// [Fcb] -- Preallocated Fcb of this file.
//
// Returns:
//
//-----------------------------------------------------------------------------
NTSTATUS DfsPostProcessRelativeOpen( IN PIRP Irp, IN PIRP_CONTEXT IrpContext, IN PDFS_FCB Fcb) { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; UNICODE_STRING NewFileName; BOOLEAN fCompleteRequest = TRUE;
DfsDbgTrace(+1, Dbg, "DfsPostProcessRelativeOpen: Entered\n", 0);
ASSERT( ARGUMENT_PRESENT( Irp ) ); ASSERT( ARGUMENT_PRESENT( IrpContext ) ); ASSERT( ARGUMENT_PRESENT( Fcb ) );
IrpSp = IoGetCurrentIrpStackLocation( Irp );
FileObject = IrpSp->FileObject;
ASSERT( Fcb->Vcb != NULL ); ASSERT( NodeType(Fcb->Vcb) == DSFS_NTC_VCB );
Status = Irp->IoStatus.Status;
if (Status == STATUS_SUCCESS) {
//
// Just set the DFS_FCB for the FileObject.
//
DfsDbgTrace( 0, Dbg, "Relative Open pass through succeeded\n", 0 );
DfsDbgTrace(0, Dbg, "Fcb = %08lx\n", Fcb);
InterlockedIncrement(&Fcb->DfsMachineEntry->UseCount);
//
// Now that a File Open has succeeded, we need to bump up OpenCnt
// on the DFS_VCB.
//
InterlockedIncrement(&Fcb->Vcb->OpenFileCount);
} else if ( Status == STATUS_DFS_EXIT_PATH_FOUND || Status == STATUS_PATH_NOT_COVERED ) {
PDFS_VCB Vcb;
//
// Exit path was found. We'll have to convert this relative open to
// an absolute open, and do a normal dnr on it.
//
DfsDbgTrace(0, Dbg, "Exit point found! Trying absolute open\n", 0);
Vcb = Fcb->Vcb;
NewFileName.Buffer = ExAllocatePoolWithTag( NonPagedPool, Fcb->FullFileName.MaximumLength, ' puM');
if (NewFileName.Buffer != NULL) {
NewFileName.Length = Fcb->FullFileName.Length; NewFileName.MaximumLength = Fcb->FullFileName.MaximumLength;
RtlMoveMemory( (PVOID) NewFileName.Buffer, (PVOID) Fcb->FullFileName.Buffer, Fcb->FullFileName.Length );
DfsDetachFcb( FileObject, Fcb );
DfsDeleteFcb( IrpContext, Fcb );
if (FileObject->FileName.Buffer) {
ExFreePool( FileObject->FileName.Buffer );
}
FileObject->FileName = NewFileName;
// OFS apparently sets the FileObject->Vpb even though it failed
// the open. Reset it to NULL.
//
if (FileObject->Vpb != NULL) { FileObject->Vpb = NULL; }
DfsDbgTrace(0, Dbg, "Absolute path == %wZ\n", &NewFileName);
fCompleteRequest = FALSE;
ASSERT( Vcb != NULL );
Status = DnrStartNameResolution( IrpContext, Irp, Vcb );
} else {
DfsDetachFcb( FileObject, Fcb );
DfsDeleteFcb( IrpContext, Fcb );
Status = STATUS_INSUFFICIENT_RESOURCES;
DfsDbgTrace(0, Dbg, "Unable to allocate full name!\n", 0);
}
} else {
DfsDetachFcb( FileObject, Fcb ); DfsDeleteFcb( IrpContext, Fcb );
}
if (fCompleteRequest) {
DfsCompleteRequest( IrpContext, Irp, Status );
}
DfsDbgTrace(-1, Dbg, "DfsPostProcessRelativeOpen: Exited %08lx\n", ULongToPtr(Status));
return(Status);
}
//+----------------------------------------------------------------------------
//
// Function: DfsRestartRelativeOpen
//
// Synopsis: This function is intended to be queued to complete processing
// of a relative open IRP that was passed through and originally
// came back with STATUS_PENDING.
//
// Arguments: [IrpContext]
//
// Returns: Nothing
//
//-----------------------------------------------------------------------------
VOID DfsRestartRelativeOpen( IN PIRP_CONTEXT IrpContext) { NTSTATUS Status;
DfsDbgTrace(+1, Dbg, "DfsRestartRelativeOpen: Entered IrpContext == %08lx\n", IrpContext);
Status = DfsPostProcessRelativeOpen( IrpContext->OriginatingIrp, IrpContext, (PDFS_FCB) IrpContext->Context);
DfsDbgTrace(-1, Dbg, "DfsRestartRelativeOpen: Exited\n", 0);
}
//+----------------------------------------------------------------------------
//
// Function: DfsComposeFullName
//
// Synopsis: Given a fully qualified name and a relative name, this
// function allocates room for the concatenation of the two, and
// fills up the buffer with the concatenated name.
//
// Arguments: [ParentName] -- Pointer to fully qualified parent name.
// [RelativeName] -- Pointer to name relative to parent.
// [FullName] -- Pointer to UNICODE_STRING structure that will
// get filled up with the full name.
//
// Returns: STATUS_INSUFFICIENT_RESOURCES if memory allocation fails.
// STAUS_SUCCESS otherwise.
//
// Notes: This routine uses an appropriate allocator so that the
// returned FullName can be put into a FILE_OBJECT.
//
//-----------------------------------------------------------------------------
NTSTATUS DfsComposeFullName( IN PUNICODE_STRING ParentName, IN PUNICODE_STRING RelativeName, OUT PUNICODE_STRING FullName) { ULONG nameLen; NTSTATUS status;
nameLen = ParentName->Length + sizeof (WCHAR) + // For backslash
RelativeName->Length;
if (nameLen > MAXUSHORT) { status = STATUS_NAME_TOO_LONG; MUP_TRACE_HIGH(ERROR, DfsComposeFullName_Error1, LOGUSTR(*ParentName) LOGSTATUS(status)); return status; }
FullName->Buffer = (PWCHAR) ExAllocatePoolWithTag( NonPagedPool, nameLen, ' puM');
if (FullName->Buffer == NULL) { return (STATUS_INSUFFICIENT_RESOURCES); }
FullName->Length = ParentName->Length; FullName->MaximumLength = (USHORT)nameLen; RtlMoveMemory (FullName->Buffer, ParentName->Buffer, ParentName->Length);
if (RelativeName->Length > 0) { (void) DnrConcatenateFilePath( FullName, RelativeName->Buffer, RelativeName->Length); }
return( STATUS_SUCCESS ); }
//+----------------------------------------------------------------------------
//
// Function: DfsAreFilesOnSameLocalVolume
//
// Synopsis: Given a file name and a name relative to it, this routine
// will determine if both files live on the same local volume.
//
// Arguments: [ParentName] -- The name of the parent file.
// [FileName] -- Name relative to parent of the other file.
//
// Returns: [STATUS_SUCCESS] -- The two files should indeed be on the
// same local volume.
//
// [STATUS_NOT_SAME_DEVICE] -- The two files are not on the
// same local volume.
//
// [STATUS_OBJECT_TYPE_MISMATCH] -- ustrParentName is not on
// a local volume.
//
//-----------------------------------------------------------------------------
NTSTATUS DfsAreFilesOnSameLocalVolume( IN PUNICODE_STRING ParentName, IN PUNICODE_STRING FileName) { NTSTATUS status = STATUS_SUCCESS; PDFS_PKT pkt; PDFS_PKT_ENTRY pktEntryParent; PDFS_PKT_ENTRY pktEntryFile; UNICODE_STRING remPath; BOOLEAN pktLocked;
DfsDbgTrace(+1, Dbg, "DfsAreFilesOnSameLocalVolume entered\n", 0);
DfsDbgTrace(0, Dbg, "Parent = [%wZ]\n", ParentName); DfsDbgTrace(0, Dbg, "File = [%wZ]\n", FileName);
pkt = _GetPkt();
PktAcquireShared( TRUE, &pktLocked );
//
// First, see if the parent is on a local volume at all.
//
pktEntryParent = PktLookupEntryByPrefix( pkt, ParentName, &remPath );
DfsDbgTrace(0, Dbg, "Parent Entry @%08lx\n", pktEntryParent);
if (pktEntryParent == NULL || !(pktEntryParent->Type & PKT_ENTRY_TYPE_LOCAL)) {
status = STATUS_OBJECT_TYPE_MISMATCH;
}
if (NT_SUCCESS(status)) {
USHORT parentLen;
//
// Parent is local, verify that the relative file does not cross a
// junction point. We'll iterate through the list of exit points on
// the parent's local volume pkt entry, comparing the remaing path
// of the exit point with the FileName argument
//
ASSERT(pktEntryParent != NULL);
parentLen = pktEntryParent->Id.Prefix.Length + sizeof(UNICODE_PATH_SEP);
for (pktEntryFile = PktEntryFirstSubordinate(pktEntryParent); pktEntryFile != NULL && NT_SUCCESS(status); pktEntryFile = PktEntryNextSubordinate( pktEntryParent, pktEntryFile)) {
remPath = pktEntryFile->Id.Prefix; remPath.Length -= parentLen; remPath.Buffer += (parentLen/sizeof(WCHAR));
if (DfsRtlPrefixPath( &remPath, FileName, FALSE)) {
DfsDbgTrace(0, Dbg, "Found entry %08lx for File\n", pktEntryFile);
//
// FileName is on another volume.
//
status = STATUS_NOT_SAME_DEVICE;
}
}
}
PktRelease();
DfsDbgTrace(-1, Dbg, "DfsAreFilesOnSameLocalVolume exit %08lx\n", ULongToPtr(status));
return( status ); }
|