Source code of Windows XP (NT5)
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.

1326 lines
40 KiB

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