1174 lines
35 KiB
C
1174 lines
35 KiB
C
|
//+----------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// 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 );
|
|||
|
}
|
|||
|
|