diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/mup/dfscreat.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/mup/dfscreat.c')
-rw-r--r-- | private/ntos/mup/dfscreat.c | 1173 |
1 files changed, 1173 insertions, 0 deletions
diff --git a/private/ntos/mup/dfscreat.c b/private/ntos/mup/dfscreat.c new file mode 100644 index 000000000..8c453bd35 --- /dev/null +++ b/private/ntos/mup/dfscreat.c @@ -0,0 +1,1173 @@ +//+---------------------------------------------------------------------------- +// +// 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" + +// +// The debug trace level +// + +#define Dbg (DEBUG_TRACE_CREATE) + +// +// Local procedure prototypes +// + +static 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); + PDFS_FCB pFcb = NULL; + + DfsDbgTrace(+1, Dbg, "DfsFsdCreate: Entered\n", 0); + + ASSERT(IoIsOperationSynchronous(Irp) == TRUE); + + // + // Call the common create routine, with block allowed if the operation + // is synchronous. + // + + try { + + IrpContext = DfsCreateIrpContext( Irp, CanFsdWait( Irp ) ); + + 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", Status ); + 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; + + PFILE_OBJECT FileObject = IrpSp->FileObject; + PFILE_OBJECT RelatedFileObject; + UNICODE_STRING FileName; + ACCESS_MASK DesiredAccess; + ULONG CreateOptions; + USHORT ShareAccess; + NTSTATUS Status; + + DfsDbgTrace(+1, Dbg, "DfsCommonCreate\n", 0 ); + DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp ); + DfsDbgTrace( 0, Dbg, "->Flags = %08lx\n", 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", IrpSp->Parameters.Create.SecurityContext->DesiredAccess ); + DfsDbgTrace( 0, Dbg, "->CreateOptions = %08lx\n", 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", IrpSp->Parameters.Create.EaLength ); + + // + // 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; + + DfsCompleteRequest( IrpContext, Irp, Iosb.Status ); + + DfsDbgTrace(-1, Dbg, "DfsCommonCreate: Exit -> %08lx\n", 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) { + + // + // 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) ExAllocatePool( + NonPagedPool, + NewFileName.MaximumLength); + + 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 { + + DfsDbgTrace(0, Dbg, "DfsCommonCreate: Invalid related file object\n", 0); + + try_return( Iosb.Status = STATUS_INVALID_HANDLE ); + + } + + (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. + // + + Iosb.Status = DnrStartNameResolution(IrpContext, Irp, Vcb); + + try_exit: NOTHING; + } finally { + + DfsDbgTrace(-1, Dbg, "DfsCommonCreate: Exit -> %08lx\n", Iosb.Status); + } + + 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; + 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; + try_return( Iosb ); + } + + DfsSetFileObject( FileObject, + FilesystemDeviceOpen, + DeviceObject + ); + + Iosb.Status = STATUS_SUCCESS; + Iosb.Information = FILE_OPENED; + try_return( Iosb ); + } + + 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) { + + Iosb.Status = STATUS_ACCESS_DENIED; + 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 ))) { + + try_return( Iosb ); + } + + } else { + + IoSetShareAccess( DesiredAccess, + ShareAccess, + FileObject, + &Vcb->ShareAccess ); + } + + UnwindShareAccess = TRUE; + + // + // Setup the context pointers, and update + // our reference counts + // + + DfsSetFileObject( FileObject, + LogicalRootDeviceOpen, + Vcb + ); + + ExInterlockedIncrementLong(&Vcb->DirectAccessOpenCount, &DfsData.DfsLock); + ExInterlockedIncrementLong(&Vcb->OpenFileCount, &DfsData.DfsLock); + + // + // 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()) { + + 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", 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; + PDFS_FCB NewFcb; + UNICODE_STRING NewFileName; + + DfsDbgTrace(+1, Dbg, "DfsPassThroughRelativeOpen: Entered\n", 0); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // 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", Status ); + DfsCompleteRequest( IrpContext, Irp, Status ); + return( Status ); + } + + + NewFcb = DfsCreateFcb( NULL, ParentFcb->Vcb, &NewFileName ); + + NewFcb->TargetDevice = ParentFcb->TargetDevice; + + NewFcb->ProviderId = ParentFcb->ProviderId; + + NewFcb->DfsMachineEntry = ParentFcb->DfsMachineEntry; + + NewFcb->FileObject = IrpSp->FileObject; + + if (ParentFcb->ProviderId == PROV_ID_DFS_RDR) { + IrpSp->FileObject->FsContext2 = (PVOID) DFS_OPEN_CONTEXT; + } + + ExFreePool( NewFileName.Buffer ); + + if (NewFcb == NULL) { + DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Unable to create DFS_FCB\n", 0); + DfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES ); + return( STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // 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 ); + + DfsDbgTrace(0, Dbg, "IoCallDriver returned %08lx\n", Status); + + if (Status != STATUS_PENDING) { + + Status = DfsPostProcessRelativeOpen( + Irp, + IrpContext, + NewFcb); + + } + + DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Exited %08lx\n", 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 (NT_SUCCESS( Status )) { + + // + // 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); + + DfsSetFileObject(FileObject, + RedirectedFileOpen, + Fcb + ); + + ExInterlockedIncrementLong(&Fcb->DfsMachineEntry->UseCount, &DfsData.Pkt.UseCountLock); + + // + // Now that a File Open has succeeded, we need to bump up OpenCnt + // on the DFS_VCB. + // + + ExInterlockedIncrementLong(&Fcb->Vcb->OpenFileCount, &DfsData.DfsLock); + + } 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 = ExAllocatePool( NonPagedPool, Fcb->FullFileName.MaximumLength ); + + 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 ); + + DfsDeleteFcb( IrpContext, Fcb ); + + if (FileObject->FileName.Buffer) { + + ExFreePool( FileObject->FileName.Buffer ); + + } + + FileObject->FileName = NewFileName; + + // + // Bugbug: OFS sets the FileObject->Vpb even though it failed + // the open. Reset it to NULL. + // + + if (FileObject->Vpb == NULL) { + DfsDbgTrace(0, Dbg, "Dfs: Ofs set Vpb to NULL! Remove Dfs workaround!\n", 0); + } else { + FileObject->Vpb = NULL; + } + + DfsDbgTrace(0, Dbg, "Absolute path == %wZ\n", &NewFileName); + + fCompleteRequest = FALSE; + + ASSERT( Vcb != NULL ); + + Status = DnrStartNameResolution( IrpContext, Irp, Vcb ); + + } else { + + DfsDeleteFcb( IrpContext, Fcb ); + + Status = STATUS_INSUFFICIENT_RESOURCES; + + DfsDbgTrace(0, Dbg, "Unable to allocate full name!\n", 0); + + } + + } + + if (fCompleteRequest) { + + DfsCompleteRequest( IrpContext, Irp, Status ); + + } + + DfsDbgTrace(-1, Dbg, "DfsPostProcessRelativeOpen: Exited %08lx\n", 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) +{ + + FullName->MaximumLength = ParentName->Length + + sizeof (WCHAR) + // For backslash + RelativeName->Length; + + FullName->Buffer = (PWCHAR) ExAllocatePool(NonPagedPool, + FullName->MaximumLength); + + if (FullName->Buffer == NULL) { + return (STATUS_INSUFFICIENT_RESOURCES); + } + + RtlMoveMemory (FullName->Buffer, ParentName->Buffer, ParentName->Length); + + FullName->Length = ParentName->Length; + + (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", status); + + return( status ); +} + |