Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1173 lines
35 KiB

4 years ago
  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: create.c
  4. //
  5. // Contents:
  6. //
  7. // This module implements the File Create routine for Dfs called by the
  8. // dispatch driver. Unlike traditional disk-based FSDs, there is only
  9. // one entry point, DfsFsdCreate. The request is assumed to be
  10. // synchronous (whether the user thread requests it or not).
  11. // Of course, since we will typically be calling out to some other
  12. // FSD, that FSD may post the request and return to us with a
  13. // STATUS_PENDING.
  14. //
  15. // Functions: DfsFsdCreate - FSD entry point for NtCreateFile/NtOpenFile
  16. // DfsCommonCreate, local
  17. // DfsPassThroughRelativeOpen, local
  18. // DfsCompleteRelativeOpen, local
  19. // DfsPostProcessRelativeOpen, local
  20. // DfsRestartRelativeOpen, local
  21. // DfsComposeFullName, local
  22. // DfsAreFilesOnSameLocalVolume, local
  23. //
  24. // History: 27 Jan 1992 AlanW Created.
  25. //
  26. //-----------------------------------------------------------------------------
  27. #include "dfsprocs.h"
  28. #include "dnr.h"
  29. #include "fcbsup.h"
  30. //
  31. // The debug trace level
  32. //
  33. #define Dbg (DEBUG_TRACE_CREATE)
  34. //
  35. // Local procedure prototypes
  36. //
  37. static NTSTATUS
  38. DfsCommonCreate (
  39. OPTIONAL IN PIRP_CONTEXT IrpContext,
  40. PDEVICE_OBJECT DeviceObject,
  41. IN PIRP Irp);
  42. IO_STATUS_BLOCK
  43. DfsOpenDevice (
  44. IN PIRP_CONTEXT IrpContext,
  45. IN PFILE_OBJECT FileObject,
  46. IN PDEVICE_OBJECT DeviceObject,
  47. IN ACCESS_MASK DesiredAccess,
  48. IN USHORT ShareAccess,
  49. IN ULONG CreateOptions);
  50. NTSTATUS
  51. DfsPassThroughRelativeOpen(
  52. IN PIRP Irp,
  53. IN PIRP_CONTEXT IrpContext,
  54. IN PDFS_FCB ParentFcb);
  55. NTSTATUS
  56. DfsCompleteRelativeOpen(
  57. IN PDEVICE_OBJECT pDevice,
  58. IN PIRP Irp,
  59. IN PVOID Context);
  60. NTSTATUS
  61. DfsPostProcessRelativeOpen(
  62. IN PIRP Irp,
  63. IN PIRP_CONTEXT IrpContext,
  64. IN PDFS_FCB ParentFcb);
  65. VOID
  66. DfsRestartRelativeOpen(
  67. IN PIRP_CONTEXT IrpContext);
  68. NTSTATUS
  69. DfsComposeFullName(
  70. IN PUNICODE_STRING ParentName,
  71. IN PUNICODE_STRING RelativeName,
  72. OUT PUNICODE_STRING FullName);
  73. NTSTATUS
  74. DfsAreFilesOnSameLocalVolume(
  75. IN PUNICODE_STRING ParentName,
  76. IN PUNICODE_STRING FileName);
  77. #ifdef ALLOC_PRAGMA
  78. #pragma alloc_text( PAGE, DfsFsdCreate )
  79. #pragma alloc_text( PAGE, DfsCommonCreate )
  80. #pragma alloc_text( PAGE, DfsOpenDevice )
  81. #pragma alloc_text( PAGE, DfsPassThroughRelativeOpen )
  82. #pragma alloc_text( PAGE, DfsPostProcessRelativeOpen )
  83. #pragma alloc_text( PAGE, DfsRestartRelativeOpen )
  84. #pragma alloc_text( PAGE, DfsComposeFullName )
  85. #pragma alloc_text( PAGE, DfsAreFilesOnSameLocalVolume )
  86. //
  87. // The following are not pageable since they can be called at DPC level
  88. //
  89. // DfsCompleteRelativeOpen
  90. //
  91. #endif // ALLOC_PRAGMA
  92. //+-------------------------------------------------------------------
  93. //
  94. // Function: DfsFsdCreate, public
  95. //
  96. // Synopsis: This routine implements the FSD part of the NtCreateFile
  97. // and NtOpenFile API calls.
  98. //
  99. // Arguments: [DeviceObject] -- Supplies the device object where
  100. // the file/directory exists that we are trying
  101. // to open/create exists
  102. // [Irp] - Supplies the Irp being processed
  103. //
  104. // Returns: NTSTATUS - The Fsd status for the Irp
  105. //
  106. //--------------------------------------------------------------------
  107. NTSTATUS
  108. DfsFsdCreate (
  109. IN PDEVICE_OBJECT DeviceObject,
  110. IN PIRP Irp
  111. )
  112. {
  113. NTSTATUS Status;
  114. PIRP_CONTEXT IrpContext = NULL;
  115. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  116. PDFS_FCB pFcb = NULL;
  117. DfsDbgTrace(+1, Dbg, "DfsFsdCreate: Entered\n", 0);
  118. ASSERT(IoIsOperationSynchronous(Irp) == TRUE);
  119. //
  120. // Call the common create routine, with block allowed if the operation
  121. // is synchronous.
  122. //
  123. try {
  124. IrpContext = DfsCreateIrpContext( Irp, CanFsdWait( Irp ) );
  125. Status = DfsCommonCreate( IrpContext, DeviceObject, Irp );
  126. } except( DfsExceptionFilter( IrpContext, GetExceptionCode(), GetExceptionInformation() )) {
  127. //
  128. // We had some trouble trying to perform the requested
  129. // operation, so we'll abort the I/O request with
  130. // the error status that we get back from the
  131. // execption code
  132. //
  133. Status = DfsProcessException( IrpContext, Irp, GetExceptionCode() );
  134. }
  135. //
  136. // And return to our caller
  137. //
  138. DfsDbgTrace(-1, Dbg, "DfsFsdCreate: Exit -> %08lx\n", Status );
  139. return Status;
  140. }
  141. //+-------------------------------------------------------------------
  142. // Function: DfsCommonCreate, private
  143. //
  144. // Synopsis: This is the common routine for creating/opening a file
  145. // called by both the FSD and FSP threads.
  146. //
  147. // Arguments: [DeviceObject] - The device object associated with
  148. // the request.
  149. // [Irp] -- Supplies the Irp to process
  150. //
  151. // Returns: NTSTATUS - the return status for the operation
  152. //
  153. //--------------------------------------------------------------------
  154. NTSTATUS
  155. DfsCommonCreate (
  156. OPTIONAL IN PIRP_CONTEXT IrpContext,
  157. IN PDEVICE_OBJECT DeviceObject,
  158. IN PIRP Irp
  159. )
  160. {
  161. IO_STATUS_BLOCK Iosb;
  162. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  163. PDFS_VCB Vcb = NULL;
  164. PDFS_FCB Fcb;
  165. PFILE_OBJECT FileObject = IrpSp->FileObject;
  166. PFILE_OBJECT RelatedFileObject;
  167. UNICODE_STRING FileName;
  168. ACCESS_MASK DesiredAccess;
  169. ULONG CreateOptions;
  170. USHORT ShareAccess;
  171. NTSTATUS Status;
  172. DfsDbgTrace(+1, Dbg, "DfsCommonCreate\n", 0 );
  173. DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp );
  174. DfsDbgTrace( 0, Dbg, "->Flags = %08lx\n", Irp->Flags );
  175. DfsDbgTrace( 0, Dbg, "->FileObject = %08lx\n", FileObject );
  176. DfsDbgTrace( 0, Dbg, " ->RelatedFileObject = %08lx\n", FileObject->RelatedFileObject );
  177. DfsDbgTrace( 0, Dbg, " ->FileName = %wZ\n", &FileObject->FileName );
  178. DfsDbgTrace( 0, Dbg, "->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
  179. DfsDbgTrace( 0, Dbg, "->CreateOptions = %08lx\n", IrpSp->Parameters.Create.Options );
  180. DfsDbgTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes );
  181. DfsDbgTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess );
  182. DfsDbgTrace( 0, Dbg, "->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength );
  183. //
  184. // Reference our input parameters to make things easier
  185. //
  186. RelatedFileObject = IrpSp->FileObject->RelatedFileObject;
  187. FileName = *((PUNICODE_STRING) &IrpSp->FileObject->FileName);
  188. DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
  189. CreateOptions = IrpSp->Parameters.Create.Options;
  190. ShareAccess = IrpSp->Parameters.Create.ShareAccess;
  191. Iosb.Status = STATUS_SUCCESS;
  192. //
  193. // Short circuit known invalid opens.
  194. //
  195. if ((IrpSp->Flags & SL_OPEN_PAGING_FILE) != 0) {
  196. DfsDbgTrace(0, Dbg,
  197. "DfsCommonCreate: Paging file not allowed on Dfs\n", 0);
  198. Iosb.Status = STATUS_INVALID_PARAMETER;
  199. DfsCompleteRequest( IrpContext, Irp, Iosb.Status );
  200. DfsDbgTrace(-1, Dbg, "DfsCommonCreate: Exit -> %08lx\n", Iosb.Status);
  201. return Iosb.Status;
  202. }
  203. //
  204. // There are several cases we need to handle here.
  205. //
  206. // 1. FileName is 0 length
  207. //
  208. // If the filename length is 0, then someone really wants to open the
  209. // device object itself.
  210. //
  211. // 2. This is a Relative open and the parent is on the same volume,
  212. // either local or remote.
  213. //
  214. // We pass through the relative open to the driver that opened the
  215. // parent.
  216. //
  217. // 3. This is a relative open and the parent is on a different volume.
  218. //
  219. // Form the full name of the file by concatenating the parent's
  220. // name with the relative file name. Stick this name in the FileObject
  221. // and do DNR on the full name.
  222. //
  223. // 4. This is a relative open and the parent is a device object (ie,
  224. // the parent was opened via case 1)
  225. //
  226. // Assume the parent name is \, so concatenate \ with the relative
  227. // file name. Stick this name in the FileObject and do DNR on the
  228. // the full name.
  229. //
  230. // 5. This is an absolute open, (or a case 3/4 converted to an absolute
  231. // open), and the SL_OPEN_TARGET_DIRECTORY bis *is* set.
  232. //
  233. // a. If the file's immediate parent directory is on the same local
  234. // volume as the file, then do a regular DNR, and let the
  235. // underlying FS handle the SL_OPEN_TARGET_DIRECTORY.
  236. //
  237. // b. If the file's immediate parent directory is on a local volume
  238. // and the file is not on the same local volume, then immediately
  239. // return STATUS_NOT_SAME_DEVICE.
  240. //
  241. // c. If the file's immediate parent directory is on a remote volume,
  242. // then do a full DNR. This will pass through the
  243. // SL_OPEN_TARGET_DIRECTORY to the remote Dfs driver, which will
  244. // handle it as case 5a. or 5b.
  245. //
  246. // 6. This is an absolute open, (or a case 3/4 converted to an absolute
  247. // open), and the SL_OPEN_TARGET_DIRECTORY bit is *not* set.
  248. //
  249. // Do a DNR on the FileObject's name.
  250. //
  251. try {
  252. //
  253. // Check to see if we are opening a device object. If so, and the
  254. // file is being opened on the File system device object, it will
  255. // only permit FsCtl and Close operations to be performed.
  256. //
  257. if (FileName.Length == 0 && RelatedFileObject == NULL) {
  258. //
  259. // This is case 1.
  260. //
  261. // In this case there had better be a DeviceObject
  262. //
  263. ASSERT(ARGUMENT_PRESENT(DeviceObject));
  264. DfsDbgTrace(0, Dbg,
  265. "DfsCommonCreate: Opening the device, DevObj = %08lx\n",
  266. DeviceObject);
  267. Iosb = DfsOpenDevice( IrpContext,
  268. FileObject,
  269. DeviceObject,
  270. DesiredAccess,
  271. ShareAccess,
  272. CreateOptions);
  273. Irp->IoStatus.Information = Iosb.Information;
  274. DfsCompleteRequest( IrpContext, Irp, Iosb.Status );
  275. try_return( Iosb.Status );
  276. }
  277. if (DeviceObject != NULL && DeviceObject->DeviceType == FILE_DEVICE_DFS) {
  278. Vcb = &(((PLOGICAL_ROOT_DEVICE_OBJECT)DeviceObject)->Vcb);
  279. }
  280. //
  281. // If there is a related file object, then this is a relative open.
  282. //
  283. if (RelatedFileObject != NULL) {
  284. //
  285. // This is case 2, 3, or 4.
  286. //
  287. PDFS_VCB TempVcb;
  288. TYPE_OF_OPEN OpenType;
  289. UNICODE_STRING NewFileName;
  290. OpenType = DfsDecodeFileObject( RelatedFileObject,
  291. &TempVcb,
  292. &Fcb);
  293. if (OpenType == RedirectedFileOpen) {
  294. DfsDbgTrace(0, Dbg, "Relative file open: DFS_FCB = %08x\n", Fcb);
  295. DfsDbgTrace(0, Dbg, " Directory: %wZ\n", &Fcb->FullFileName);
  296. DfsDbgTrace(0, Dbg, " Relative file: %wZ\n", &FileName);
  297. //
  298. // This is case 2.
  299. //
  300. DfsDbgTrace(0, Dbg,
  301. "Trying pass through of relative open\n", 0);
  302. Iosb.Status = DfsPassThroughRelativeOpen(
  303. Irp,
  304. IrpContext,
  305. Fcb
  306. );
  307. try_return( Iosb.Status );
  308. } else if (OpenType == LogicalRootDeviceOpen) {
  309. //
  310. // This is case 4.
  311. //
  312. // If the open is relative to a logical root open, then we
  313. // are forced to convert it to an absolute open, since there
  314. // is no underlying FS backing up the logical root to pass
  315. // the relative open to first.
  316. //
  317. DfsDbgTrace( 0, Dbg, "DfsCommonCreate: Open relative to Logical Root\n", 0);
  318. ASSERT (TempVcb == Vcb);
  319. NewFileName.MaximumLength = sizeof (WCHAR) +
  320. FileName.Length;
  321. NewFileName.Buffer = (PWCHAR) ExAllocatePool(
  322. NonPagedPool,
  323. NewFileName.MaximumLength);
  324. if (NewFileName.Buffer == NULL) {
  325. Iosb.Status = STATUS_INSUFFICIENT_RESOURCES;
  326. DfsCompleteRequest( IrpContext, Irp, Iosb.Status );
  327. try_return( Iosb.Status );
  328. }
  329. NewFileName.Buffer[0] = L'\\';
  330. NewFileName.Length = sizeof (WCHAR);
  331. } else {
  332. DfsDbgTrace(0, Dbg, "DfsCommonCreate: Invalid related file object\n", 0);
  333. try_return( Iosb.Status = STATUS_INVALID_HANDLE );
  334. }
  335. (void) DnrConcatenateFilePath (
  336. &NewFileName,
  337. FileName.Buffer,
  338. FileName.Length);
  339. if (IrpSp->FileObject->FileName.Buffer)
  340. ExFreePool( IrpSp->FileObject->FileName.Buffer );
  341. FileName = IrpSp->FileObject->FileName = NewFileName;
  342. }
  343. ASSERT(FileName.Length != 0);
  344. //
  345. // This is case 5b, 5c, or 6 - Do a full DNR.
  346. //
  347. Iosb.Status = DnrStartNameResolution(IrpContext, Irp, Vcb);
  348. try_exit: NOTHING;
  349. } finally {
  350. DfsDbgTrace(-1, Dbg, "DfsCommonCreate: Exit -> %08lx\n", Iosb.Status);
  351. }
  352. return Iosb.Status;
  353. }
  354. //+-------------------------------------------------------------------
  355. //
  356. // Function: DfsOpenDevice, local
  357. //
  358. // Synopsis: This routine opens the specified device for direct
  359. // access.
  360. //
  361. // Arguments: [FileObject] - Supplies the File object
  362. // [DeviceObject] - Supplies the object denoting the device
  363. // being opened
  364. // [DesiredAccess] - Supplies the desired access of the caller
  365. // [ShareAccess] - Supplies the share access of the caller
  366. // [CreateOptions] - Supplies the create options for
  367. // this operation
  368. //
  369. // Returns: [IO_STATUS_BLOCK] - Returns the completion status for
  370. // the operation
  371. //
  372. //--------------------------------------------------------------------
  373. IO_STATUS_BLOCK
  374. DfsOpenDevice (
  375. IN PIRP_CONTEXT IrpContext,
  376. IN PFILE_OBJECT FileObject,
  377. IN PDEVICE_OBJECT DeviceObject,
  378. IN ACCESS_MASK DesiredAccess,
  379. IN USHORT ShareAccess,
  380. IN ULONG CreateOptions
  381. ) {
  382. IO_STATUS_BLOCK Iosb;
  383. PDFS_VCB Vcb = NULL;
  384. //
  385. // The following variables are for abnormal termination
  386. //
  387. BOOLEAN UnwindShareAccess = FALSE;
  388. BOOLEAN UnwindVolumeLock = FALSE;
  389. DfsDbgTrace( +1, Dbg, "DfsOpenDevice: Entered\n", 0 );
  390. try {
  391. //
  392. // Check to see which type of device is being opened.
  393. // We don't permit all open modes on the file system
  394. // device object.
  395. //
  396. if (DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM ) {
  397. ULONG CreateDisposition = (CreateOptions >> 24) & 0x000000ff;
  398. //
  399. // Check for proper desired access and rights
  400. //
  401. if (CreateDisposition != FILE_OPEN
  402. && CreateDisposition != FILE_OPEN_IF ) {
  403. Iosb.Status = STATUS_ACCESS_DENIED;
  404. try_return( Iosb );
  405. }
  406. //
  407. // Check if we were to open a directory
  408. //
  409. if (CreateOptions & FILE_DIRECTORY_FILE) {
  410. DfsDbgTrace(0, Dbg, "DfsOpenDevice: Cannot open device as a directory\n", 0);
  411. Iosb.Status = STATUS_NOT_A_DIRECTORY;
  412. try_return( Iosb );
  413. }
  414. DfsSetFileObject( FileObject,
  415. FilesystemDeviceOpen,
  416. DeviceObject
  417. );
  418. Iosb.Status = STATUS_SUCCESS;
  419. Iosb.Information = FILE_OPENED;
  420. try_return( Iosb );
  421. }
  422. Vcb = & (((PLOGICAL_ROOT_DEVICE_OBJECT)DeviceObject)->Vcb);
  423. //
  424. // If the user does not want to share anything then we will try and
  425. // take out a lock on the volume. We check if the volume is already
  426. // in use, and if it is then we deny the open
  427. //
  428. if ((ShareAccess & (
  429. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)) == 0 ) {
  430. if (Vcb->OpenFileCount != 0) {
  431. Iosb.Status = STATUS_ACCESS_DENIED;
  432. try_return( Iosb );
  433. }
  434. //
  435. // Lock the volume
  436. //
  437. Vcb->VcbState |= VCB_STATE_FLAG_LOCKED;
  438. Vcb->FileObjectWithVcbLocked = FileObject;
  439. UnwindVolumeLock = TRUE;
  440. }
  441. //
  442. // If the volume is already opened by someone then we need to check
  443. // the share access
  444. //
  445. if (Vcb->DirectAccessOpenCount > 0) {
  446. if ( !NT_SUCCESS( Iosb.Status
  447. = IoCheckShareAccess( DesiredAccess,
  448. ShareAccess,
  449. FileObject,
  450. &Vcb->ShareAccess,
  451. TRUE ))) {
  452. try_return( Iosb );
  453. }
  454. } else {
  455. IoSetShareAccess( DesiredAccess,
  456. ShareAccess,
  457. FileObject,
  458. &Vcb->ShareAccess );
  459. }
  460. UnwindShareAccess = TRUE;
  461. //
  462. // Setup the context pointers, and update
  463. // our reference counts
  464. //
  465. DfsSetFileObject( FileObject,
  466. LogicalRootDeviceOpen,
  467. Vcb
  468. );
  469. ExInterlockedIncrementLong(&Vcb->DirectAccessOpenCount, &DfsData.DfsLock);
  470. ExInterlockedIncrementLong(&Vcb->OpenFileCount, &DfsData.DfsLock);
  471. //
  472. // And set our status to success
  473. //
  474. Iosb.Status = STATUS_SUCCESS;
  475. Iosb.Information = FILE_OPENED;
  476. try_exit: NOTHING;
  477. } finally {
  478. //
  479. // If this is an abnormal termination then undo our work
  480. //
  481. if (AbnormalTermination()) {
  482. if (UnwindShareAccess) {
  483. IoRemoveShareAccess( FileObject, &Vcb->ShareAccess );
  484. }
  485. if (UnwindVolumeLock) {
  486. Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
  487. Vcb->FileObjectWithVcbLocked = NULL;
  488. }
  489. }
  490. DfsDbgTrace(-1, Dbg, "DfsOpenDevice: Exit -> Iosb.Status = %08lx\n", Iosb.Status);
  491. }
  492. return Iosb;
  493. }
  494. //+----------------------------------------------------------------------------
  495. //
  496. // Function: DfsPassThroughRelativeOpen
  497. //
  498. // Synopsis: Passes through a relative open call to the device handling
  499. // the parent. This is required for structured storages on OFS
  500. // to work, for replication's Do-not-cross-JP sematics to work,
  501. // and as an optimization.
  502. //
  503. // Arguments: [Irp] -- The open Irp, which we will pass through.
  504. // [IrpContext] -- Associated with the above Irp.
  505. // [ParentFcb] -- Fcb of related file object.
  506. //
  507. // Returns: Status returned by the underlying FS, or by DNR if
  508. // the underlying FS complained about STATUS_DFS_EXIT_PATH_FOUND.
  509. //
  510. //-----------------------------------------------------------------------------
  511. NTSTATUS
  512. DfsPassThroughRelativeOpen(
  513. IN PIRP Irp,
  514. IN PIRP_CONTEXT IrpContext,
  515. IN PDFS_FCB ParentFcb)
  516. {
  517. NTSTATUS Status;
  518. PIO_STACK_LOCATION IrpSp, NextIrpSp;
  519. PDFS_FCB NewFcb;
  520. UNICODE_STRING NewFileName;
  521. DfsDbgTrace(+1, Dbg, "DfsPassThroughRelativeOpen: Entered\n", 0);
  522. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  523. //
  524. // Prepare to pass the request to the device handling the parent open.
  525. //
  526. //
  527. // First, we preallocate an DFS_FCB, assuming that the relative open will
  528. // succeed. We need to do this at this point in time because the
  529. // FileObject->FileName is still intact; after we pass through, the
  530. // underlying can do as it wishes with the FileName field, and we will
  531. // be unable to construct the full file name for the DFS_FCB.
  532. //
  533. Status = DfsComposeFullName(
  534. &ParentFcb->FullFileName,
  535. &IrpSp->FileObject->FileName,
  536. &NewFileName);
  537. if (!NT_SUCCESS(Status)) {
  538. DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Unable to create full Name %08lx\n", Status );
  539. DfsCompleteRequest( IrpContext, Irp, Status );
  540. return( Status );
  541. }
  542. NewFcb = DfsCreateFcb( NULL, ParentFcb->Vcb, &NewFileName );
  543. NewFcb->TargetDevice = ParentFcb->TargetDevice;
  544. NewFcb->ProviderId = ParentFcb->ProviderId;
  545. NewFcb->DfsMachineEntry = ParentFcb->DfsMachineEntry;
  546. NewFcb->FileObject = IrpSp->FileObject;
  547. if (ParentFcb->ProviderId == PROV_ID_DFS_RDR) {
  548. IrpSp->FileObject->FsContext2 = (PVOID) DFS_OPEN_CONTEXT;
  549. }
  550. ExFreePool( NewFileName.Buffer );
  551. if (NewFcb == NULL) {
  552. DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Unable to create DFS_FCB\n", 0);
  553. DfsCompleteRequest( IrpContext, Irp, STATUS_INSUFFICIENT_RESOURCES );
  554. return( STATUS_INSUFFICIENT_RESOURCES );
  555. }
  556. //
  557. // Next, setup the IRP stack location
  558. //
  559. NextIrpSp = IoGetNextIrpStackLocation(Irp);
  560. (*NextIrpSp) = (*IrpSp);
  561. //
  562. // Put the parent DFS_FCB pointer in the IrpContext.
  563. //
  564. IrpContext->Context = (PVOID) NewFcb;
  565. IoSetCompletionRoutine(
  566. Irp,
  567. DfsCompleteRelativeOpen,
  568. IrpContext,
  569. TRUE,
  570. TRUE,
  571. TRUE);
  572. Status = IoCallDriver( ParentFcb->TargetDevice, Irp );
  573. DfsDbgTrace(0, Dbg, "IoCallDriver returned %08lx\n", Status);
  574. if (Status != STATUS_PENDING) {
  575. Status = DfsPostProcessRelativeOpen(
  576. Irp,
  577. IrpContext,
  578. NewFcb);
  579. }
  580. DfsDbgTrace(-1, Dbg, "DfsPassThroughRelativeOpen: Exited %08lx\n", Status);
  581. return( Status );
  582. }
  583. //+----------------------------------------------------------------------------
  584. //
  585. // Function: DfsCompleteRelativeOpen
  586. //
  587. // Synopsis: Completion routine for DfsPassThroughRelativeOpen. It is
  588. // interesting only in case where STATUS_PENDING was originally
  589. // returned from IoCallDriver. If so, then this routine simply
  590. // queues DfsRestartRelativeOpen to a work queue. Note that it
  591. // must queue an item at this stage instead of doing the work
  592. // itself because this routine is executed at DPC level.
  593. //
  594. // Arguments: [pDevice] -- Our device object.
  595. // [Irp] -- The Irp being completed.
  596. // [IrpContext] -- Context associated with Irp.
  597. //
  598. // Returns: STATUS_MORE_PROCESSING_REQUIRED. Either the posted routine
  599. // or DfsPassThroughRelativeOpen must complete the IRP for real.
  600. //
  601. //-----------------------------------------------------------------------------
  602. NTSTATUS
  603. DfsCompleteRelativeOpen(
  604. IN PDEVICE_OBJECT pDevice,
  605. IN PIRP Irp,
  606. IN PIRP_CONTEXT IrpContext)
  607. {
  608. DfsDbgTrace( +1, Dbg, "DfsCompleteRelativeOpen: Entered\n", 0);
  609. //
  610. // We are only interested in the case when the pass through of relative
  611. // opens returned STATUS_PENDING. In that case, the original thread has
  612. // popped all the way back to the caller of NtCreateFile, and we need
  613. // to finish the open in an asynchronous manner.
  614. //
  615. if (Irp->PendingReturned) {
  616. DfsDbgTrace(0, Dbg, "Pending returned : Queuing DfsRestartRelativeOpen\n", 0);
  617. //
  618. // We need to call IpMarkIrpPending so the IoSubsystem will realize
  619. // that our FSD routine returned STATUS_PENDING. We can't call this
  620. // from the FSD routine itself because the FSD routine doesn't have
  621. // access to the stack location when the underlying guy returns
  622. // STATUS_PENDING
  623. //
  624. IoMarkIrpPending( Irp );
  625. ExInitializeWorkItem( &(IrpContext->WorkQueueItem),
  626. DfsRestartRelativeOpen,
  627. (PVOID) IrpContext );
  628. ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
  629. }
  630. //
  631. // We MUST return STATUS_MORE_PROCESSING_REQUIRED to halt the completion
  632. // of the Irp. Either DfsRestartRelativeOpen that we queued above or
  633. // DfsPassThroughRelativeOpen will complete the IRP after it is done.
  634. //
  635. DfsDbgTrace(-1, Dbg, "DfsCompleteRelativeOpen: Exited\n", 0);
  636. return( STATUS_MORE_PROCESSING_REQUIRED );
  637. }
  638. //+----------------------------------------------------------------------------
  639. //
  640. // Function: DfsPostProcessRelativeOpen
  641. //
  642. // Synopsis: Continues a relative open after it has already been passed
  643. // to the device of the parent. One of three things could have
  644. // happened -
  645. //
  646. // a) The device of the parent successfully handled the open.
  647. // We create an fcb and return.
  648. // b) The device of the parent could not do the open for some
  649. // reason other than STATUS_DFS_EXIT_PATH_FOUND. We return
  650. // the error to the caller.
  651. // c) The device of the parent returned STATUS_DFS_EXIT_PATH
  652. // found. In that case, we convert the relative open to an
  653. // absolute open and do a full Dnr.
  654. //
  655. // Arguments: [Irp] -- Pointer to Irp
  656. // [IrpContext] -- Pointer to IrpContext associated with Irp
  657. // [Fcb] -- Preallocated Fcb of this file.
  658. //
  659. // Returns:
  660. //
  661. //-----------------------------------------------------------------------------
  662. NTSTATUS
  663. DfsPostProcessRelativeOpen(
  664. IN PIRP Irp,
  665. IN PIRP_CONTEXT IrpContext,
  666. IN PDFS_FCB Fcb)
  667. {
  668. NTSTATUS Status;
  669. PIO_STACK_LOCATION IrpSp;
  670. PFILE_OBJECT FileObject;
  671. UNICODE_STRING NewFileName;
  672. BOOLEAN fCompleteRequest = TRUE;
  673. DfsDbgTrace(+1, Dbg, "DfsPostProcessRelativeOpen: Entered\n", 0);
  674. ASSERT( ARGUMENT_PRESENT( Irp ) );
  675. ASSERT( ARGUMENT_PRESENT( IrpContext ) );
  676. ASSERT( ARGUMENT_PRESENT( Fcb ) );
  677. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  678. FileObject = IrpSp->FileObject;
  679. ASSERT( Fcb->Vcb != NULL );
  680. ASSERT( NodeType(Fcb->Vcb) == DSFS_NTC_VCB );
  681. Status = Irp->IoStatus.Status;
  682. if (NT_SUCCESS( Status )) {
  683. //
  684. // Just set the DFS_FCB for the FileObject.
  685. //
  686. DfsDbgTrace( 0, Dbg, "Relative Open pass through succeeded\n", 0 );
  687. DfsDbgTrace(0, Dbg, "Fcb = %08lx\n", Fcb);
  688. DfsSetFileObject(FileObject,
  689. RedirectedFileOpen,
  690. Fcb
  691. );
  692. ExInterlockedIncrementLong(&Fcb->DfsMachineEntry->UseCount, &DfsData.Pkt.UseCountLock);
  693. //
  694. // Now that a File Open has succeeded, we need to bump up OpenCnt
  695. // on the DFS_VCB.
  696. //
  697. ExInterlockedIncrementLong(&Fcb->Vcb->OpenFileCount, &DfsData.DfsLock);
  698. } else if ( Status == STATUS_DFS_EXIT_PATH_FOUND ||
  699. Status == STATUS_PATH_NOT_COVERED ) {
  700. PDFS_VCB Vcb;
  701. //
  702. // Exit path was found. We'll have to convert this relative open to
  703. // an absolute open, and do a normal dnr on it.
  704. //
  705. DfsDbgTrace(0, Dbg, "Exit point found! Trying absolute open\n", 0);
  706. Vcb = Fcb->Vcb;
  707. NewFileName.Buffer = ExAllocatePool( NonPagedPool, Fcb->FullFileName.MaximumLength );
  708. if (NewFileName.Buffer != NULL) {
  709. NewFileName.Length = Fcb->FullFileName.Length;
  710. NewFileName.MaximumLength = Fcb->FullFileName.MaximumLength;
  711. RtlMoveMemory(
  712. (PVOID) NewFileName.Buffer,
  713. (PVOID) Fcb->FullFileName.Buffer,
  714. Fcb->FullFileName.Length );
  715. DfsDeleteFcb( IrpContext, Fcb );
  716. if (FileObject->FileName.Buffer) {
  717. ExFreePool( FileObject->FileName.Buffer );
  718. }
  719. FileObject->FileName = NewFileName;
  720. //
  721. // Bugbug: OFS sets the FileObject->Vpb even though it failed
  722. // the open. Reset it to NULL.
  723. //
  724. if (FileObject->Vpb == NULL) {
  725. DfsDbgTrace(0, Dbg, "Dfs: Ofs set Vpb to NULL! Remove Dfs workaround!\n", 0);
  726. } else {
  727. FileObject->Vpb = NULL;
  728. }
  729. DfsDbgTrace(0, Dbg, "Absolute path == %wZ\n", &NewFileName);
  730. fCompleteRequest = FALSE;
  731. ASSERT( Vcb != NULL );
  732. Status = DnrStartNameResolution( IrpContext, Irp, Vcb );
  733. } else {
  734. DfsDeleteFcb( IrpContext, Fcb );
  735. Status = STATUS_INSUFFICIENT_RESOURCES;
  736. DfsDbgTrace(0, Dbg, "Unable to allocate full name!\n", 0);
  737. }
  738. }
  739. if (fCompleteRequest) {
  740. DfsCompleteRequest( IrpContext, Irp, Status );
  741. }
  742. DfsDbgTrace(-1, Dbg, "DfsPostProcessRelativeOpen: Exited %08lx\n", Status);
  743. return(Status);
  744. }
  745. //+----------------------------------------------------------------------------
  746. //
  747. // Function: DfsRestartRelativeOpen
  748. //
  749. // Synopsis: This function is intended to be queued to complete processing
  750. // of a relative open IRP that was passed through and originally
  751. // came back with STATUS_PENDING.
  752. //
  753. // Arguments: [IrpContext]
  754. //
  755. // Returns: Nothing
  756. //
  757. //-----------------------------------------------------------------------------
  758. VOID
  759. DfsRestartRelativeOpen(
  760. IN PIRP_CONTEXT IrpContext)
  761. {
  762. NTSTATUS Status;
  763. DfsDbgTrace(+1, Dbg, "DfsRestartRelativeOpen: Entered IrpContext == %08lx\n", IrpContext);
  764. Status = DfsPostProcessRelativeOpen(
  765. IrpContext->OriginatingIrp,
  766. IrpContext,
  767. (PDFS_FCB) IrpContext->Context);
  768. DfsDbgTrace(-1, Dbg, "DfsRestartRelativeOpen: Exited\n", 0);
  769. }
  770. //+----------------------------------------------------------------------------
  771. //
  772. // Function: DfsComposeFullName
  773. //
  774. // Synopsis: Given a fully qualified name and a relative name, this
  775. // function allocates room for the concatenation of the two, and
  776. // fills up the buffer with the concatenated name.
  777. //
  778. // Arguments: [ParentName] -- Pointer to fully qualified parent name.
  779. // [RelativeName] -- Pointer to name relative to parent.
  780. // [FullName] -- Pointer to UNICODE_STRING structure that will
  781. // get filled up with the full name.
  782. //
  783. // Returns: STATUS_INSUFFICIENT_RESOURCES if memory allocation fails.
  784. // STAUS_SUCCESS otherwise.
  785. //
  786. // Notes: This routine uses an appropriate allocator so that the
  787. // returned FullName can be put into a FILE_OBJECT.
  788. //
  789. //-----------------------------------------------------------------------------
  790. NTSTATUS
  791. DfsComposeFullName(
  792. IN PUNICODE_STRING ParentName,
  793. IN PUNICODE_STRING RelativeName,
  794. OUT PUNICODE_STRING FullName)
  795. {
  796. FullName->MaximumLength = ParentName->Length +
  797. sizeof (WCHAR) + // For backslash
  798. RelativeName->Length;
  799. FullName->Buffer = (PWCHAR) ExAllocatePool(NonPagedPool,
  800. FullName->MaximumLength);
  801. if (FullName->Buffer == NULL) {
  802. return (STATUS_INSUFFICIENT_RESOURCES);
  803. }
  804. RtlMoveMemory (FullName->Buffer, ParentName->Buffer, ParentName->Length);
  805. FullName->Length = ParentName->Length;
  806. (void) DnrConcatenateFilePath (FullName,
  807. RelativeName->Buffer,
  808. RelativeName->Length);
  809. return( STATUS_SUCCESS );
  810. }
  811. //+----------------------------------------------------------------------------
  812. //
  813. // Function: DfsAreFilesOnSameLocalVolume
  814. //
  815. // Synopsis: Given a file name and a name relative to it, this routine
  816. // will determine if both files live on the same local volume.
  817. //
  818. // Arguments: [ParentName] -- The name of the parent file.
  819. // [FileName] -- Name relative to parent of the other file.
  820. //
  821. // Returns: [STATUS_SUCCESS] -- The two files should indeed be on the
  822. // same local volume.
  823. //
  824. // [STATUS_NOT_SAME_DEVICE] -- The two files are not on the
  825. // same local volume.
  826. //
  827. // [STATUS_OBJECT_TYPE_MISMATCH] -- ustrParentName is not on
  828. // a local volume.
  829. //
  830. //-----------------------------------------------------------------------------
  831. NTSTATUS
  832. DfsAreFilesOnSameLocalVolume(
  833. IN PUNICODE_STRING ParentName,
  834. IN PUNICODE_STRING FileName)
  835. {
  836. NTSTATUS status = STATUS_SUCCESS;
  837. PDFS_PKT pkt;
  838. PDFS_PKT_ENTRY pktEntryParent;
  839. PDFS_PKT_ENTRY pktEntryFile;
  840. UNICODE_STRING remPath;
  841. BOOLEAN pktLocked;
  842. DfsDbgTrace(+1, Dbg, "DfsAreFilesOnSameLocalVolume entered\n", 0);
  843. DfsDbgTrace(0, Dbg, "Parent = [%wZ]\n", ParentName);
  844. DfsDbgTrace(0, Dbg, "File = [%wZ]\n", FileName);
  845. pkt = _GetPkt();
  846. PktAcquireShared( TRUE, &pktLocked );
  847. //
  848. // First, see if the parent is on a local volume at all.
  849. //
  850. pktEntryParent = PktLookupEntryByPrefix( pkt, ParentName, &remPath );
  851. DfsDbgTrace(0, Dbg, "Parent Entry @%08lx\n", pktEntryParent);
  852. if (pktEntryParent == NULL ||
  853. !(pktEntryParent->Type & PKT_ENTRY_TYPE_LOCAL)) {
  854. status = STATUS_OBJECT_TYPE_MISMATCH;
  855. }
  856. if (NT_SUCCESS(status)) {
  857. USHORT parentLen;
  858. //
  859. // Parent is local, verify that the relative file does not cross a
  860. // junction point. We'll iterate through the list of exit points on
  861. // the parent's local volume pkt entry, comparing the remaing path
  862. // of the exit point with the FileName argument
  863. //
  864. ASSERT(pktEntryParent != NULL);
  865. parentLen = pktEntryParent->Id.Prefix.Length +
  866. sizeof(UNICODE_PATH_SEP);
  867. for (pktEntryFile = PktEntryFirstSubordinate(pktEntryParent);
  868. pktEntryFile != NULL && NT_SUCCESS(status);
  869. pktEntryFile = PktEntryNextSubordinate(
  870. pktEntryParent, pktEntryFile)) {
  871. remPath = pktEntryFile->Id.Prefix;
  872. remPath.Length -= parentLen;
  873. remPath.Buffer += (parentLen/sizeof(WCHAR));
  874. if (DfsRtlPrefixPath( &remPath, FileName, FALSE)) {
  875. DfsDbgTrace(0, Dbg,
  876. "Found entry %08lx for File\n", pktEntryFile);
  877. //
  878. // FileName is on another volume.
  879. //
  880. status = STATUS_NOT_SAME_DEVICE;
  881. }
  882. }
  883. }
  884. PktRelease();
  885. DfsDbgTrace(-1, Dbg, "DfsAreFilesOnSameLocalVolume exit %08lx\n", status);
  886. return( status );
  887. }