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.

2312 lines
64 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. Create.c
  5. Abstract:
  6. This module implements the File Create routine for Udfs called by the
  7. Fsd/Fsp dispatch routines.
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Dan Lovinger [DanLo] 9-October-1996
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "UdfProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (UDFS_BUG_CHECK_CREATE)
  19. //
  20. // The local debug trace level
  21. //
  22. #define Dbg (UDFS_DEBUG_LEVEL_CREATE)
  23. //
  24. // Local support routines
  25. //
  26. NTSTATUS
  27. UdfNormalizeFileNames (
  28. IN PIRP_CONTEXT IrpContext,
  29. IN PVCB Vcb,
  30. IN BOOLEAN OpenByFileId,
  31. IN BOOLEAN IgnoreCase,
  32. IN TYPE_OF_OPEN RelatedTypeOfOpen,
  33. IN PCCB RelatedCcb OPTIONAL,
  34. IN PUNICODE_STRING RelatedFileName OPTIONAL,
  35. IN OUT PUNICODE_STRING FileName,
  36. IN OUT PUNICODE_STRING RemainingName
  37. );
  38. NTSTATUS
  39. UdfOpenExistingFcb (
  40. IN PIRP_CONTEXT IrpContext,
  41. IN PIO_STACK_LOCATION IrpSp,
  42. IN OUT PFCB *CurrentFcb,
  43. IN PLCB OpenLcb,
  44. IN TYPE_OF_OPEN TypeOfOpen,
  45. IN BOOLEAN IgnoreCase,
  46. IN PCCB RelatedCcb OPTIONAL
  47. );
  48. NTSTATUS
  49. UdfOpenObjectByFileId (
  50. IN PIRP_CONTEXT IrpContext,
  51. IN PIO_STACK_LOCATION IrpSp,
  52. IN PVCB Vcb,
  53. IN OUT PFCB *CurrentFcb
  54. );
  55. NTSTATUS
  56. UdfOpenObjectFromDirContext (
  57. IN PIRP_CONTEXT IrpContext,
  58. IN PIO_STACK_LOCATION IrpSp,
  59. IN PVCB Vcb,
  60. IN OUT PFCB *CurrentFcb,
  61. IN BOOLEAN ShortNameMatch,
  62. IN BOOLEAN IgnoreCase,
  63. IN PDIR_ENUM_CONTEXT DirContext,
  64. IN BOOLEAN PerformUserOpen,
  65. IN PCCB RelatedCcb OPTIONAL
  66. );
  67. NTSTATUS
  68. UdfCompleteFcbOpen (
  69. IN PIRP_CONTEXT IrpContext,
  70. PIO_STACK_LOCATION IrpSp,
  71. IN PVCB Vcb,
  72. IN OUT PFCB *CurrentFcb,
  73. IN PLCB OpenLcb,
  74. IN TYPE_OF_OPEN TypeOfOpen,
  75. IN ULONG UserCcbFlags,
  76. IN ACCESS_MASK DesiredAccess
  77. );
  78. #ifdef ALLOC_PRAGMA
  79. #pragma alloc_text(PAGE, UdfCommonCreate)
  80. #pragma alloc_text(PAGE, UdfCompleteFcbOpen)
  81. #pragma alloc_text(PAGE, UdfNormalizeFileNames)
  82. #pragma alloc_text(PAGE, UdfOpenObjectByFileId)
  83. #pragma alloc_text(PAGE, UdfOpenExistingFcb)
  84. #pragma alloc_text(PAGE, UdfOpenObjectFromDirContext)
  85. #endif
  86. NTSTATUS
  87. UdfCommonCreate (
  88. IN PIRP_CONTEXT IrpContext,
  89. IN PIRP Irp
  90. )
  91. /*++
  92. Routine Description:
  93. This is the common routine for opening a file called by both the
  94. Fsp and Fsd threads.
  95. The file can be opened either by name or by file Id either with or without
  96. a relative name. The file name field in the file object passed to this routine
  97. contains either a unicode string or a 64 bit value which is the file Id.
  98. If there is a related file object with a name then we will already have converted
  99. that name to Oem.
  100. We will store the full name for the file in the file object on a successful
  101. open. We will allocate a larger buffer if necessary and combine the
  102. related and file object names. The only exception is the relative open
  103. when the related file object is for an OpenByFileId file. If we need to
  104. allocate a buffer for a case insensitive name then we allocate it at
  105. the tail of the buffer we will store into the file object. The upcased
  106. portion will begin immediately after the name defined by the FileName
  107. in the file object.
  108. Once we have the full name in the file object we don't want to split the
  109. name in the event of a retry. We use a flag in the IrpContext to indicate
  110. that the name has been split.
  111. Arguments:
  112. Irp - Supplies the Irp to process
  113. Return Value:
  114. NTSTATUS - This is the status from this open operation.
  115. --*/
  116. {
  117. NTSTATUS Status = STATUS_SUCCESS;
  118. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  119. PFILE_OBJECT FileObject;
  120. DIR_ENUM_CONTEXT DirContext;
  121. BOOLEAN CleanupDirContext = FALSE;
  122. BOOLEAN FoundEntry;
  123. PVCB Vcb;
  124. BOOLEAN OpenByFileId;
  125. BOOLEAN IgnoreCase;
  126. ULONG CreateDisposition;
  127. BOOLEAN ShortNameMatch;
  128. BOOLEAN VolumeOpen = FALSE;
  129. //
  130. // We will be acquiring and releasing file Fcb's as we move down the
  131. // directory tree during opens. At any time we need to know the deepest
  132. // point we have traversed down in the tree in case we need to cleanup
  133. // any structures created here.
  134. //
  135. // CurrentFcb - represents this point. If non-null it means we have
  136. // acquired it and need to release it in finally clause.
  137. //
  138. // NextFcb - represents the NextFcb to walk to but haven't acquired yet.
  139. //
  140. // CurrentLcb - represents the name of the CurrentFcb.
  141. //
  142. TYPE_OF_OPEN RelatedTypeOfOpen = UnopenedFileObject;
  143. PFILE_OBJECT RelatedFileObject;
  144. PCCB RelatedCcb = NULL;
  145. PFCB NextFcb;
  146. PFCB CurrentFcb = NULL;
  147. PLCB CurrentLcb = NULL;
  148. //
  149. // During the open we need to combine the related file object name
  150. // with the remaining name. We also may need to upcase the file name
  151. // in order to do a case-insensitive name comparison. We also need
  152. // to restore the name in the file object in the event that we retry
  153. // the request. We use the following string variables to manage the
  154. // name. We will can put these strings into either Unicode or Ansi
  155. // form.
  156. //
  157. // FileName - Pointer to name as currently stored in the file
  158. // object. We store the full name into the file object early in
  159. // the open operation.
  160. //
  161. // RelatedFileName - Pointer to the name in the related file object.
  162. //
  163. // RemainingName - String containing remaining name to parse.
  164. //
  165. PUNICODE_STRING FileName;
  166. PUNICODE_STRING RelatedFileName;
  167. UNICODE_STRING RemainingName;
  168. UNICODE_STRING FinalName;
  169. PAGED_CODE();
  170. //
  171. // If we were called with our file system device object instead of a
  172. // volume device object, just complete this request with STATUS_SUCCESS.
  173. //
  174. if (IrpContext->Vcb == NULL) {
  175. UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
  176. return STATUS_SUCCESS;
  177. }
  178. //
  179. // Get create parameters from the Irp.
  180. //
  181. OpenByFileId = BooleanFlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID );
  182. IgnoreCase = !BooleanFlagOn( IrpSp->Flags, SL_CASE_SENSITIVE );
  183. CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
  184. //
  185. // Do some preliminary checks to make sure the operation is supported.
  186. // We fail in the following cases immediately.
  187. //
  188. // - Open a paging file.
  189. // - Open a target directory.
  190. // - Open a file with Eas.
  191. // - Create a file.
  192. //
  193. if (FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE | SL_OPEN_TARGET_DIRECTORY) ||
  194. (IrpSp->Parameters.Create.EaLength != 0) ||
  195. (CreateDisposition == FILE_CREATE)) {
  196. UdfCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
  197. return STATUS_ACCESS_DENIED;
  198. }
  199. //
  200. // Copy the Vcb to a local. Assume the starting directory is the root.
  201. //
  202. Vcb = IrpContext->Vcb;
  203. NextFcb = Vcb->RootIndexFcb;
  204. //
  205. // Reference our input parameters to make things easier
  206. //
  207. FileObject = IrpSp->FileObject;
  208. RelatedFileObject = NULL;
  209. FileName = &FileObject->FileName;
  210. //
  211. // Set up the file object's Vpb pointer in case anything happens.
  212. // This will allow us to get a reasonable pop-up.
  213. //
  214. if ((FileObject->RelatedFileObject != NULL) && !OpenByFileId) {
  215. RelatedFileObject = FileObject->RelatedFileObject;
  216. FileObject->Vpb = RelatedFileObject->Vpb;
  217. RelatedTypeOfOpen = UdfDecodeFileObject( RelatedFileObject, &NextFcb, &RelatedCcb );
  218. //
  219. // Fail the request if this is not a user file object.
  220. //
  221. if (RelatedTypeOfOpen < UserVolumeOpen) {
  222. UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  223. return STATUS_INVALID_PARAMETER;
  224. }
  225. //
  226. // Remember the name in the related file object.
  227. //
  228. RelatedFileName = &RelatedFileObject->FileName;
  229. }
  230. //
  231. // If we haven't initialized the names then make sure the strings are valid.
  232. // If this an OpenByFileId then verify the file id buffer.
  233. //
  234. // After this routine returns we know that the full name is in the
  235. // FileName buffer and the buffer will hold the upcased portion
  236. // of the name yet to parse immediately after the full name in the
  237. // buffer. Any trailing backslash has been removed and the flag
  238. // in the IrpContext will indicate whether we removed the
  239. // backslash.
  240. //
  241. Status = UdfNormalizeFileNames( IrpContext,
  242. Vcb,
  243. OpenByFileId,
  244. IgnoreCase,
  245. RelatedTypeOfOpen,
  246. RelatedCcb,
  247. RelatedFileName,
  248. FileName,
  249. &RemainingName );
  250. //
  251. // Return the error code if not successful.
  252. //
  253. if (!NT_SUCCESS( Status )) {
  254. UdfCompleteRequest( IrpContext, Irp, Status );
  255. return Status;
  256. }
  257. //
  258. // We want to acquire the Vcb. Exclusively for a volume open, shared otherwise.
  259. // The file name is empty for a volume open.
  260. //
  261. if ((FileName->Length == 0) &&
  262. (RelatedTypeOfOpen <= UserVolumeOpen) &&
  263. !OpenByFileId) {
  264. VolumeOpen = TRUE;
  265. UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
  266. } else {
  267. UdfAcquireVcbShared( IrpContext, Vcb, FALSE );
  268. }
  269. //
  270. // Use a try-finally to facilitate cleanup.
  271. //
  272. try {
  273. //
  274. // Verify that the Vcb is not in an unusable condition. This routine
  275. // will raise if not usable.
  276. //
  277. UdfVerifyVcb( IrpContext, Vcb );
  278. //
  279. // If the Vcb is locked then we cannot open another file
  280. //
  281. if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
  282. try_leave( Status = STATUS_ACCESS_DENIED );
  283. }
  284. //
  285. // If we are opening this file by FileId then process this immediately
  286. // and exit.
  287. //
  288. if (OpenByFileId) {
  289. //
  290. // The only create disposition we allow is OPEN.
  291. //
  292. if ((CreateDisposition != FILE_OPEN) &&
  293. (CreateDisposition != FILE_OPEN_IF)) {
  294. try_leave( Status = STATUS_ACCESS_DENIED );
  295. }
  296. try_leave( Status = UdfOpenObjectByFileId( IrpContext,
  297. IrpSp,
  298. Vcb,
  299. &CurrentFcb ));
  300. }
  301. //
  302. // If we are opening this volume Dasd then process this immediately
  303. // and exit.
  304. //
  305. if (VolumeOpen) {
  306. //
  307. // The only create disposition we allow is OPEN.
  308. //
  309. if ((CreateDisposition != FILE_OPEN) &&
  310. (CreateDisposition != FILE_OPEN_IF)) {
  311. try_leave( Status = STATUS_ACCESS_DENIED );
  312. }
  313. //
  314. // If they wanted to open a directory, surprise.
  315. //
  316. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
  317. try_leave( Status = STATUS_NOT_A_DIRECTORY );
  318. }
  319. //
  320. // Acquire the Fcb first.
  321. //
  322. CurrentFcb = Vcb->VolumeDasdFcb;
  323. UdfAcquireFcbExclusive( IrpContext, CurrentFcb, FALSE );
  324. try_leave( Status = UdfOpenExistingFcb( IrpContext,
  325. IrpSp,
  326. &CurrentFcb,
  327. NULL,
  328. UserVolumeOpen,
  329. FALSE,
  330. NULL ));
  331. }
  332. //
  333. // Acquire the Fcb at the beginning of our search to keep it from being
  334. // deleted beneath us.
  335. //
  336. UdfAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
  337. CurrentFcb = NextFcb;
  338. //
  339. // Do a prefix search if there is more of the name to parse.
  340. //
  341. if (RemainingName.Length != 0) {
  342. //
  343. // Do the prefix search to find the longest matching name.
  344. //
  345. CurrentLcb = UdfFindPrefix( IrpContext,
  346. &CurrentFcb,
  347. &RemainingName,
  348. IgnoreCase );
  349. }
  350. //
  351. // At this point CurrentFcb points at the lowest Fcb in the tree for this
  352. // file name, CurrentLcb is that name, and RemainingName is the rest of the
  353. // name we have to do any directory traversals for.
  354. //
  355. //
  356. // If the remaining name length is zero then we have found our
  357. // target.
  358. //
  359. if (RemainingName.Length == 0) {
  360. //
  361. // If this is a file so verify the user didn't want to open
  362. // a directory.
  363. //
  364. if (SafeNodeType( CurrentFcb ) == UDFS_NTC_FCB_DATA) {
  365. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
  366. FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
  367. try_leave( Status = STATUS_NOT_A_DIRECTORY );
  368. }
  369. //
  370. // The only create disposition we allow is OPEN.
  371. //
  372. if ((CreateDisposition != FILE_OPEN) &&
  373. (CreateDisposition != FILE_OPEN_IF)) {
  374. try_leave( Status = STATUS_ACCESS_DENIED );
  375. }
  376. try_leave( Status = UdfOpenExistingFcb( IrpContext,
  377. IrpSp,
  378. &CurrentFcb,
  379. CurrentLcb,
  380. UserFileOpen,
  381. IgnoreCase,
  382. RelatedCcb ));
  383. //
  384. // This is a directory. Verify the user didn't want to open
  385. // as a file.
  386. //
  387. } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
  388. try_leave( Status = STATUS_FILE_IS_A_DIRECTORY );
  389. //
  390. // Open the file as a directory.
  391. //
  392. } else {
  393. //
  394. // The only create disposition we allow is OPEN.
  395. //
  396. if ((CreateDisposition != FILE_OPEN) &&
  397. (CreateDisposition != FILE_OPEN_IF)) {
  398. try_leave( Status = STATUS_ACCESS_DENIED );
  399. }
  400. try_leave( Status = UdfOpenExistingFcb( IrpContext,
  401. IrpSp,
  402. &CurrentFcb,
  403. CurrentLcb,
  404. UserDirectoryOpen,
  405. IgnoreCase,
  406. RelatedCcb ));
  407. }
  408. }
  409. //
  410. // We have more work to do. We have a starting Fcb which we own shared.
  411. // We also have the remaining name to parse. Walk through the name
  412. // component by component looking for the full name.
  413. //
  414. //
  415. // Our starting Fcb better be a directory.
  416. //
  417. if (!FlagOn( CurrentFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
  418. try_leave( Status = STATUS_OBJECT_PATH_NOT_FOUND );
  419. }
  420. //
  421. // If we can't wait then post this request.
  422. //
  423. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  424. UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  425. }
  426. //
  427. // Prepare the enumeration context for use.
  428. //
  429. UdfInitializeDirContext( IrpContext, &DirContext );
  430. CleanupDirContext = TRUE;
  431. while (TRUE) {
  432. ShortNameMatch = FALSE;
  433. //
  434. // Split off the next component from the name.
  435. //
  436. UdfDissectName( IrpContext,
  437. &RemainingName,
  438. &FinalName );
  439. //
  440. // Go ahead and look this entry up in the directory.
  441. //
  442. FoundEntry = UdfFindDirEntry( IrpContext,
  443. CurrentFcb,
  444. &FinalName,
  445. IgnoreCase,
  446. FALSE,
  447. &DirContext );
  448. //
  449. // If we didn't find the entry then check if the current name
  450. // is a possible short name.
  451. //
  452. if (!FoundEntry && UdfCandidateShortName( IrpContext, &FinalName)) {
  453. //
  454. // If the name looks like it could be a short name, try to find
  455. // a matching real directory entry.
  456. //
  457. ShortNameMatch =
  458. FoundEntry = UdfFindDirEntry( IrpContext,
  459. CurrentFcb,
  460. &FinalName,
  461. IgnoreCase,
  462. TRUE,
  463. &DirContext );
  464. }
  465. //
  466. // If we didn't find a match then check what the caller was trying to do to
  467. // determine which error code to return.
  468. //
  469. if (!FoundEntry) {
  470. if ((CreateDisposition == FILE_OPEN) ||
  471. (CreateDisposition == FILE_OVERWRITE)) {
  472. try_leave( Status = STATUS_OBJECT_NAME_NOT_FOUND );
  473. }
  474. //
  475. // Any other operation return STATUS_ACCESS_DENIED.
  476. //
  477. try_leave( Status = STATUS_ACCESS_DENIED );
  478. }
  479. //
  480. // If this is an ignore case open then copy the exact case
  481. // in the file object name.
  482. //
  483. if (IgnoreCase && !ShortNameMatch) {
  484. ASSERT( FinalName.Length == DirContext.ObjectName.Length );
  485. RtlCopyMemory( FinalName.Buffer,
  486. DirContext.ObjectName.Buffer,
  487. DirContext.ObjectName.Length );
  488. }
  489. //
  490. // If we have found the last component then break out to open for the caller.
  491. //
  492. if (RemainingName.Length == 0) {
  493. break;
  494. }
  495. //
  496. // The object we just found must be a directory.
  497. //
  498. if (!FlagOn( DirContext.Fid->Flags, NSR_FID_F_DIRECTORY )) {
  499. try_leave( Status = STATUS_OBJECT_PATH_NOT_FOUND );
  500. }
  501. //
  502. // Now open an Fcb for this intermediate index Fcb.
  503. //
  504. UdfOpenObjectFromDirContext( IrpContext,
  505. IrpSp,
  506. Vcb,
  507. &CurrentFcb,
  508. ShortNameMatch,
  509. IgnoreCase,
  510. &DirContext,
  511. FALSE,
  512. NULL );
  513. }
  514. //
  515. // Make sure our opener is about to get what they expect.
  516. //
  517. if ((FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
  518. FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) &&
  519. !FlagOn( DirContext.Fid->Flags, NSR_FID_F_DIRECTORY )) {
  520. try_leave( Status = STATUS_NOT_A_DIRECTORY );
  521. }
  522. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE ) &&
  523. FlagOn( DirContext.Fid->Flags, NSR_FID_F_DIRECTORY )) {
  524. try_leave( Status = STATUS_FILE_IS_A_DIRECTORY );
  525. }
  526. //
  527. // The only create disposition we allow is OPEN.
  528. //
  529. if ((CreateDisposition != FILE_OPEN) &&
  530. (CreateDisposition != FILE_OPEN_IF)) {
  531. try_leave( Status = STATUS_ACCESS_DENIED );
  532. }
  533. //
  534. // Open the object for the caller.
  535. //
  536. try_leave( Status = UdfOpenObjectFromDirContext( IrpContext,
  537. IrpSp,
  538. Vcb,
  539. &CurrentFcb,
  540. ShortNameMatch,
  541. IgnoreCase,
  542. &DirContext,
  543. TRUE,
  544. RelatedCcb ));
  545. } finally {
  546. //
  547. // Cleanup the enumeration context if initialized.
  548. //
  549. if (CleanupDirContext) {
  550. UdfCleanupDirContext( IrpContext, &DirContext );
  551. }
  552. //
  553. // The result of this open could be success, pending or some error
  554. // condition.
  555. //
  556. if (AbnormalTermination()) {
  557. //
  558. // In the error path we start by calling our teardown routine if we
  559. // have a CurrentFcb.
  560. //
  561. if (CurrentFcb != NULL) {
  562. BOOLEAN RemovedFcb;
  563. UdfTeardownStructures( IrpContext, CurrentFcb, FALSE, &RemovedFcb );
  564. if (RemovedFcb) {
  565. CurrentFcb = NULL;
  566. }
  567. }
  568. //
  569. // No need to complete the request.
  570. //
  571. IrpContext = NULL;
  572. Irp = NULL;
  573. //
  574. // If we posted this request through the oplock package we need
  575. // to show that there is no reason to complete the request.
  576. //
  577. } else if (Status == STATUS_PENDING) {
  578. IrpContext = NULL;
  579. Irp = NULL;
  580. }
  581. //
  582. // Release the Current Fcb if still acquired.
  583. //
  584. if (CurrentFcb != NULL) {
  585. UdfReleaseFcb( IrpContext, CurrentFcb );
  586. }
  587. //
  588. // Release the Vcb.
  589. //
  590. UdfReleaseVcb( IrpContext, Vcb );
  591. //
  592. // Call our completion routine. It will handle the case where either
  593. // the Irp and/or IrpContext are gone.
  594. //
  595. UdfCompleteRequest( IrpContext, Irp, Status );
  596. }
  597. return Status;
  598. }
  599. //
  600. // Local support routine
  601. //
  602. NTSTATUS
  603. UdfNormalizeFileNames (
  604. IN PIRP_CONTEXT IrpContext,
  605. IN PVCB Vcb,
  606. IN BOOLEAN OpenByFileId,
  607. IN BOOLEAN IgnoreCase,
  608. IN TYPE_OF_OPEN RelatedTypeOfOpen,
  609. IN PCCB RelatedCcb OPTIONAL,
  610. IN PUNICODE_STRING RelatedFileName OPTIONAL,
  611. IN OUT PUNICODE_STRING FileName,
  612. IN OUT PUNICODE_STRING RemainingName
  613. )
  614. /*++
  615. Routine Description:
  616. This routine is called to store the full name and upcased name into the
  617. filename buffer. We only upcase the portion yet to parse. We also
  618. check for a trailing backslash and lead-in double backslashes. This
  619. routine also verifies the mode of the related open against the name
  620. currently in the filename.
  621. Arguments:
  622. Vcb - Vcb for this volume.
  623. OpenByFileId - Indicates if the filename should be a 64 bit FileId.
  624. IgnoreCase - Indicates if this open is a case-insensitive operation.
  625. RelatedTypeOfOpen - Indicates the type of the related file object.
  626. RelatedCcb - Ccb for the related open. Ignored if no relative open.
  627. RelatedFileName - FileName buffer for related open. Ignored if no
  628. relative open.
  629. FileName - FileName to update in this routine. The name should
  630. either be a 64-bit FileId or a Unicode string.
  631. RemainingName - Name with the remaining portion of the name. This
  632. will begin after the related name and any separator. For a
  633. non-relative open we also step over the initial separator.
  634. Return Value:
  635. NTSTATUS - STATUS_SUCCESS if the names are OK, appropriate error code
  636. otherwise.
  637. --*/
  638. {
  639. ULONG RemainingNameLength;
  640. ULONG RelatedNameLength = 0;
  641. ULONG SeparatorLength = 0;
  642. ULONG BufferLength;
  643. UNICODE_STRING NewFileName;
  644. PAGED_CODE();
  645. //
  646. // If this is the first pass then we need to build the full name and
  647. // check for name compatibility.
  648. //
  649. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME )) {
  650. //
  651. // Deal with the regular file name case first.
  652. //
  653. if (!OpenByFileId) {
  654. //
  655. // This is here because the Win32 layer can't avoid sending me double
  656. // beginning backslashes.
  657. //
  658. if ((FileName->Length > sizeof( WCHAR )) &&
  659. (FileName->Buffer[1] == L'\\') &&
  660. (FileName->Buffer[0] == L'\\')) {
  661. //
  662. // If there are still two beginning backslashes, the name is bogus.
  663. //
  664. if ((FileName->Length > 2 * sizeof( WCHAR )) &&
  665. (FileName->Buffer[2] == L'\\')) {
  666. return STATUS_OBJECT_NAME_INVALID;
  667. }
  668. //
  669. // Slide the name down in the buffer.
  670. //
  671. FileName->Length -= sizeof( WCHAR );
  672. RtlMoveMemory( FileName->Buffer,
  673. FileName->Buffer + 1,
  674. FileName->Length );
  675. }
  676. //
  677. // Check for a trailing backslash. Don't strip off if only character
  678. // in the full name or for relative opens where this is illegal.
  679. //
  680. if (((FileName->Length > sizeof( WCHAR)) ||
  681. ((FileName->Length == sizeof( WCHAR )) && (RelatedTypeOfOpen == UserDirectoryOpen))) &&
  682. (FileName->Buffer[ (FileName->Length/2) - 1 ] == L'\\')) {
  683. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH );
  684. FileName->Length -= sizeof( WCHAR );
  685. }
  686. //
  687. // Remember the length we need for this portion of the name.
  688. //
  689. RemainingNameLength = FileName->Length;
  690. //
  691. // If this is a related file object then we verify the compatibility
  692. // of the name in the file object with the relative file object.
  693. //
  694. if (RelatedTypeOfOpen != UnopenedFileObject) {
  695. //
  696. // If the filename length was zero then it must be legal.
  697. // If there are characters then check with the related
  698. // type of open.
  699. //
  700. if (FileName->Length != 0) {
  701. //
  702. // The name length must always be zero for a volume open.
  703. //
  704. if (RelatedTypeOfOpen <= UserVolumeOpen) {
  705. return STATUS_INVALID_PARAMETER;
  706. //
  707. // The remaining name cannot begin with a backslash.
  708. //
  709. } else if (FileName->Buffer[0] == L'\\' ) {
  710. return STATUS_INVALID_PARAMETER;
  711. //
  712. // If the related file is a user file then there
  713. // is no file with this path.
  714. //
  715. } else if (RelatedTypeOfOpen == UserFileOpen) {
  716. return STATUS_OBJECT_PATH_NOT_FOUND;
  717. }
  718. }
  719. //
  720. // Remember the length of the related name when building
  721. // the full name. We leave the RelatedNameLength and
  722. // SeparatorLength at zero if the relative file is opened
  723. // by Id.
  724. //
  725. if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
  726. //
  727. // Add a separator if the name length is non-zero
  728. // unless the relative Fcb is at the root.
  729. //
  730. if ((FileName->Length != 0) &&
  731. (RelatedCcb->Fcb != Vcb->RootIndexFcb)) {
  732. SeparatorLength = sizeof( WCHAR );
  733. }
  734. RelatedNameLength = RelatedFileName->Length;
  735. }
  736. //
  737. // The full name is already in the filename. It must either
  738. // be length 0 or begin with a backslash.
  739. //
  740. } else if (FileName->Length != 0) {
  741. if (FileName->Buffer[0] != L'\\') {
  742. return STATUS_INVALID_PARAMETER;
  743. }
  744. //
  745. // We will want to trim the leading backslash from the
  746. // remaining name we return.
  747. //
  748. RemainingNameLength -= sizeof( WCHAR );
  749. SeparatorLength = sizeof( WCHAR );
  750. }
  751. //
  752. // Now see if the buffer is large enough to hold the full name.
  753. //
  754. BufferLength = RelatedNameLength + SeparatorLength + RemainingNameLength;
  755. //
  756. // Check for an overflow of the maximum filename size.
  757. //
  758. if (BufferLength > MAXUSHORT) {
  759. return STATUS_INVALID_PARAMETER;
  760. }
  761. //
  762. // Now see if we need to allocate a new buffer.
  763. //
  764. if (FileName->MaximumLength < BufferLength) {
  765. NewFileName.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
  766. BufferLength,
  767. TAG_FILE_NAME );
  768. NewFileName.MaximumLength = (USHORT) BufferLength;
  769. } else {
  770. NewFileName.Buffer = FileName->Buffer;
  771. NewFileName.MaximumLength = FileName->MaximumLength;
  772. }
  773. //
  774. // If there is a related name then we need to slide the remaining bytes up and
  775. // insert the related name. Otherwise the name is in the correct position
  776. // already.
  777. //
  778. if (RelatedNameLength != 0) {
  779. //
  780. // Store the remaining name in its correct position.
  781. //
  782. if (RemainingNameLength != 0) {
  783. RtlMoveMemory( Add2Ptr( NewFileName.Buffer, RelatedNameLength + SeparatorLength, PVOID ),
  784. FileName->Buffer,
  785. RemainingNameLength );
  786. }
  787. RtlCopyMemory( NewFileName.Buffer,
  788. RelatedFileName->Buffer,
  789. RelatedNameLength );
  790. //
  791. // Add the separator if needed.
  792. //
  793. if (SeparatorLength != 0) {
  794. *(Add2Ptr( NewFileName.Buffer, RelatedNameLength, PWCHAR )) = L'\\';
  795. }
  796. //
  797. // Update the filename value we got from the user.
  798. //
  799. if (NewFileName.Buffer != FileName->Buffer) {
  800. if (FileName->Buffer != NULL) {
  801. ExFreePool( FileName->Buffer );
  802. }
  803. FileName->Buffer = NewFileName.Buffer;
  804. FileName->MaximumLength = NewFileName.MaximumLength;
  805. }
  806. //
  807. // Copy the name length to the user's filename.
  808. //
  809. FileName->Length = (USHORT) (RelatedNameLength + SeparatorLength + RemainingNameLength);
  810. }
  811. //
  812. // Now update the remaining name to parse.
  813. //
  814. RemainingName->MaximumLength =
  815. RemainingName->Length = (USHORT) RemainingNameLength;
  816. RemainingName->Buffer = Add2Ptr( FileName->Buffer,
  817. RelatedNameLength + SeparatorLength,
  818. PWCHAR );
  819. //
  820. // Upcase the name if necessary.
  821. //
  822. if (IgnoreCase && (RemainingNameLength != 0)) {
  823. UdfUpcaseName( IrpContext,
  824. RemainingName,
  825. RemainingName );
  826. }
  827. //
  828. // Do a quick check to make sure there are no wildcards.
  829. //
  830. if (FsRtlDoesNameContainWildCards( RemainingName )) {
  831. return STATUS_OBJECT_NAME_INVALID;
  832. }
  833. //
  834. // For the open by file Id case we verify the name really contains
  835. // a 64 bit value.
  836. //
  837. } else {
  838. //
  839. // Check for validity of the buffer.
  840. //
  841. if (FileName->Length != sizeof( FILE_ID )) {
  842. return STATUS_INVALID_PARAMETER;
  843. }
  844. }
  845. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME );
  846. //
  847. // If we are in the retry path then the full name is already in the
  848. // file object name. If this is a case-sensitive operation then
  849. // we need to upcase the name from the end of any related file name already stored
  850. // there.
  851. //
  852. } else {
  853. //
  854. // Assume there is no relative name.
  855. //
  856. *RemainingName = *FileName;
  857. //
  858. // Nothing to do if the name length is zero.
  859. //
  860. if (RemainingName->Length != 0) {
  861. //
  862. // If there is a relative name then we need to walk past it.
  863. //
  864. if (RelatedTypeOfOpen != UnopenedFileObject) {
  865. //
  866. // Nothing to walk past if the RelatedCcb is opened by FileId.
  867. //
  868. if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
  869. //
  870. // Related file name is a proper prefix of the full name.
  871. // We step over the related name and if we are then
  872. // pointing at a separator character we step over that.
  873. //
  874. RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
  875. RelatedFileName->Length,
  876. PWCHAR );
  877. RemainingName->Length -= RelatedFileName->Length;
  878. }
  879. }
  880. //
  881. // If we are pointing at a separator character then step past that.
  882. //
  883. if (RemainingName->Length != 0) {
  884. if (*(RemainingName->Buffer) == L'\\') {
  885. RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
  886. sizeof( WCHAR ),
  887. PWCHAR );
  888. RemainingName->Length -= sizeof( WCHAR );
  889. }
  890. }
  891. }
  892. //
  893. // Upcase the name if necessary.
  894. //
  895. if (IgnoreCase && (RemainingName->Length != 0)) {
  896. UdfUpcaseName( IrpContext,
  897. RemainingName,
  898. RemainingName );
  899. }
  900. }
  901. return STATUS_SUCCESS;
  902. }
  903. //
  904. // Local support routine
  905. //
  906. NTSTATUS
  907. UdfOpenObjectByFileId (
  908. IN PIRP_CONTEXT IrpContext,
  909. IN PIO_STACK_LOCATION IrpSp,
  910. IN PVCB Vcb,
  911. IN OUT PFCB *CurrentFcb
  912. )
  913. /*++
  914. Routine Description:
  915. This routine is called to open a file by the FileId. The file Id is in
  916. the FileObject name buffer and has been verified to be 64 bits.
  917. We extract the Id number and then check to see whether we are opening a
  918. file or directory and compare that with the create options. If this
  919. generates no error then optimistically look up the Fcb in the Fcb Table.
  920. If we don't find the Fcb then we take what is effectively a wild-a** guess.
  921. Since we would need more than 64bits to contain the root extent length along
  922. with the partition, lbn and dir/file flag we have to speculate that the
  923. opener knows what they are doing and try to crack an ICB hierarchy at the
  924. specified location. This can fail for any number of reasons, which then have
  925. to be mapped to an open failure.
  926. If found then build the Fcb from this entry and store the new Fcb in the
  927. tree.
  928. Finally we call our worker routine to complete the open on this Fcb.
  929. Arguments:
  930. IrpSp - Stack location within the create Irp.
  931. Vcb - Vcb for this volume.
  932. CurrentFcb - Address to store the Fcb for this open. We only store the
  933. CurrentFcb here when we have acquired it so our caller knows to
  934. free or deallocate it.
  935. Return Value:
  936. NTSTATUS - Status indicating the result of the operation.
  937. --*/
  938. {
  939. NTSTATUS Status = STATUS_ACCESS_DENIED;
  940. BOOLEAN UnlockVcb = FALSE;
  941. BOOLEAN Found;
  942. BOOLEAN FcbExisted;
  943. ICB_SEARCH_CONTEXT IcbContext;
  944. BOOLEAN CleanupIcbContext = FALSE;
  945. NODE_TYPE_CODE NodeTypeCode;
  946. TYPE_OF_OPEN TypeOfOpen;
  947. FILE_ID FileId;
  948. PFCB NextFcb = NULL;
  949. PAGED_CODE();
  950. //
  951. // Check inputs.
  952. //
  953. ASSERT_IRP_CONTEXT( IrpContext );
  954. ASSERT_VCB( Vcb );
  955. //
  956. // Extract the FileId from the FileObject.
  957. //
  958. RtlCopyMemory( &FileId, IrpSp->FileObject->FileName.Buffer, sizeof( FILE_ID ));
  959. //
  960. // Now do a quick check that the reserved, unused chunk of the fileid is
  961. // unused in this specimen.
  962. //
  963. if (UdfGetFidReservedZero( FileId )) {
  964. return STATUS_INVALID_PARAMETER;
  965. }
  966. //
  967. // Go ahead and figure out the TypeOfOpen and NodeType. We can
  968. // get these from the input FileId.
  969. //
  970. if (UdfIsFidDirectory( FileId )) {
  971. TypeOfOpen = UserDirectoryOpen;
  972. NodeTypeCode = UDFS_NTC_FCB_INDEX;
  973. } else {
  974. TypeOfOpen = UserFileOpen;
  975. NodeTypeCode = UDFS_NTC_FCB_DATA;
  976. }
  977. //
  978. // Use a try-finally to facilitate cleanup.
  979. //
  980. try {
  981. //
  982. // Acquire the Vcb and check if there is already an Fcb.
  983. // If not we will need to carefully hunt for the on-disc
  984. // structures.
  985. //
  986. // We will post the request if we don't find the Fcb and this
  987. // request can't wait.
  988. //
  989. UdfLockVcb( IrpContext, Vcb );
  990. UnlockVcb = TRUE;
  991. NextFcb = UdfCreateFcb( IrpContext, FileId, NodeTypeCode, &FcbExisted );
  992. //
  993. // Now, if the Fcb was not already here we have some work to do.
  994. //
  995. if (!FcbExisted) {
  996. //
  997. // If we can't wait then post this request.
  998. //
  999. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  1000. UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  1001. }
  1002. //
  1003. // Use a try-finally to transform errors we get as a result of going
  1004. // off on a wild goose chase into a simple open failure.
  1005. //
  1006. try {
  1007. NextFcb->FileId = FileId;
  1008. UdfInitializeIcbContextFromFcb( IrpContext, &IcbContext, NextFcb );
  1009. CleanupIcbContext = TRUE;
  1010. UdfLookupActiveIcb( IrpContext,
  1011. &IcbContext,
  1012. NextFcb->RootExtentLength);
  1013. UdfInitializeFcbFromIcbContext( IrpContext,
  1014. NextFcb,
  1015. &IcbContext,
  1016. NULL);
  1017. UdfCleanupIcbContext( IrpContext, &IcbContext );
  1018. CleanupIcbContext = FALSE;
  1019. } except( UdfExceptionFilter( IrpContext, GetExceptionInformation() )) {
  1020. //
  1021. // Any error we receive is an indication that the given fileid is
  1022. // not valid.
  1023. //
  1024. Status = STATUS_INVALID_PARAMETER;
  1025. }
  1026. //
  1027. // Do a little dance to leave the exception handler if we had problems.
  1028. //
  1029. if (Status == STATUS_INVALID_PARAMETER) {
  1030. try_leave( NOTHING );
  1031. }
  1032. }
  1033. //
  1034. // We have the Fcb. Check that the type of the file is compatible with
  1035. // the desired type of file to open.
  1036. //
  1037. if (FlagOn( NextFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
  1038. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
  1039. try_leave( Status = STATUS_FILE_IS_A_DIRECTORY );
  1040. }
  1041. } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
  1042. try_leave( Status = STATUS_NOT_A_DIRECTORY );
  1043. }
  1044. //
  1045. // We now know the Fcb and currently hold the Vcb lock.
  1046. // Try to acquire this Fcb without waiting. Otherwise we
  1047. // need to reference it, drop the Vcb, acquire the Fcb, the
  1048. // Vcb and then dereference the Fcb.
  1049. //
  1050. if (!UdfAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
  1051. NextFcb->FcbReference += 1;
  1052. UdfUnlockVcb( IrpContext, Vcb );
  1053. UdfAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
  1054. UdfLockVcb( IrpContext, Vcb );
  1055. NextFcb->FcbReference -= 1;
  1056. }
  1057. UdfUnlockVcb( IrpContext, Vcb );
  1058. UnlockVcb = FALSE;
  1059. //
  1060. // Move to this Fcb.
  1061. //
  1062. *CurrentFcb = NextFcb;
  1063. //
  1064. // Check the requested access on this Fcb.
  1065. //
  1066. if (!UdfIllegalFcbAccess( IrpContext,
  1067. TypeOfOpen,
  1068. IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
  1069. //
  1070. // Call our worker routine to complete the open.
  1071. //
  1072. Status = UdfCompleteFcbOpen( IrpContext,
  1073. IrpSp,
  1074. Vcb,
  1075. CurrentFcb,
  1076. NULL,
  1077. TypeOfOpen,
  1078. CCB_FLAG_OPEN_BY_ID,
  1079. IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
  1080. }
  1081. } finally {
  1082. if (UnlockVcb) {
  1083. UdfUnlockVcb( IrpContext, Vcb );
  1084. }
  1085. if (CleanupIcbContext) {
  1086. UdfCleanupIcbContext( IrpContext, &IcbContext );
  1087. }
  1088. //
  1089. // Destroy the new Fcb if it was not fully initialized.
  1090. //
  1091. if (NextFcb && !FlagOn( NextFcb->FcbState, FCB_STATE_INITIALIZED )) {
  1092. UdfDeleteFcb( IrpContext, NextFcb );
  1093. }
  1094. }
  1095. return Status;
  1096. }
  1097. //
  1098. // Local support routine
  1099. //
  1100. NTSTATUS
  1101. UdfOpenExistingFcb (
  1102. IN PIRP_CONTEXT IrpContext,
  1103. IN PIO_STACK_LOCATION IrpSp,
  1104. IN OUT PFCB *CurrentFcb,
  1105. IN PLCB OpenLcb,
  1106. IN TYPE_OF_OPEN TypeOfOpen,
  1107. IN BOOLEAN IgnoreCase,
  1108. IN PCCB RelatedCcb OPTIONAL
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. This routine is called to open an Fcb which is already in the Fcb table.
  1113. We will verify the access to the file and then call our worker routine
  1114. to perform the final operations.
  1115. Arguments:
  1116. IrpSp - Pointer to the stack location for this open.
  1117. CurrentFcb - Address of Fcb to open. We will clear this if the Fcb
  1118. is released here.
  1119. OpenLcb - Lcb used to find this Fcb.
  1120. TypeOfOpen - Indicates whether we are opening a file, directory or volume.
  1121. IgnoreCase - Indicates if this open is case-insensitive.
  1122. RelatedCcb - Ccb for related file object if relative open. We use
  1123. this when setting the Ccb flags for this open. It will tell
  1124. us whether the name currently in the file object is relative or
  1125. absolute.
  1126. Return Value:
  1127. NTSTATUS - Status indicating the result of the operation.
  1128. --*/
  1129. {
  1130. ULONG CcbFlags = 0;
  1131. NTSTATUS Status = STATUS_ACCESS_DENIED;
  1132. PAGED_CODE();
  1133. //
  1134. // Check inputs.
  1135. //
  1136. ASSERT_IRP_CONTEXT( IrpContext );
  1137. ASSERT_EXCLUSIVE_FCB( *CurrentFcb );
  1138. ASSERT_OPTIONAL_CCB( RelatedCcb );
  1139. //
  1140. // Check that the desired access is legal.
  1141. //
  1142. if (!UdfIllegalFcbAccess( IrpContext,
  1143. TypeOfOpen,
  1144. IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
  1145. //
  1146. // Set the Ignore case.
  1147. //
  1148. if (IgnoreCase) {
  1149. SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
  1150. }
  1151. //
  1152. // Check the related Ccb to see if this was an OpenByFileId and
  1153. // whether there was a version.
  1154. //
  1155. if (ARGUMENT_PRESENT( RelatedCcb )) {
  1156. if (FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
  1157. SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
  1158. }
  1159. }
  1160. //
  1161. // Call our worker routine to complete the open.
  1162. //
  1163. Status = UdfCompleteFcbOpen( IrpContext,
  1164. IrpSp,
  1165. (*CurrentFcb)->Vcb,
  1166. CurrentFcb,
  1167. OpenLcb,
  1168. TypeOfOpen,
  1169. CcbFlags,
  1170. IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
  1171. }
  1172. return Status;
  1173. }
  1174. //
  1175. // Local support routine
  1176. //
  1177. NTSTATUS
  1178. UdfOpenObjectFromDirContext (
  1179. IN PIRP_CONTEXT IrpContext,
  1180. IN PIO_STACK_LOCATION IrpSp,
  1181. IN PVCB Vcb,
  1182. IN OUT PFCB *CurrentFcb,
  1183. IN BOOLEAN ShortNameMatch,
  1184. IN BOOLEAN IgnoreCase,
  1185. IN PDIR_ENUM_CONTEXT DirContext,
  1186. IN BOOLEAN PerformUserOpen,
  1187. IN PCCB RelatedCcb OPTIONAL
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. This routine is called to open an object found in a directory scan. This
  1192. can be a directory or a file as indicated in the scan's results.
  1193. We first check that the desired access is legal for this file. Then we
  1194. construct the FileId for this and do a check to see if it is the Fcb
  1195. Table. It is always possible that either it was created since or simply
  1196. wasn't in the prefix table at the time of the prefix table search.
  1197. Lookup the active ICB, initialize the Fcb and store into the FcbTable
  1198. if not present.
  1199. Next we will add this to the prefix table of our parent if needed.
  1200. Once we know that the new Fcb has been initialized then we move our pointer
  1201. in the tree down to this position.
  1202. This routine does not own the Vcb lock on entry. We must be sure to release
  1203. it on exit.
  1204. Arguments:
  1205. IrpSp - Stack location for this request.
  1206. Vcb - Vcb for the current volume.
  1207. CurrentFcb - On input this is the parent of the Fcb to open. On output we
  1208. store the Fcb for the file being opened.
  1209. ShortNameMatch - Indicates whether this object was opened by the shortname.
  1210. IgnoreCase - Indicates the case sensitivity of the caller.
  1211. DirContext - This is the context used to find the object.
  1212. PerformUserOpen - Indicates if we are at the object the user wants to finally open.
  1213. RelatedCcb - RelatedCcb for relative file object used to make this open.
  1214. Return Value:
  1215. NTSTATUS - Status indicating the result of the operation.
  1216. --*/
  1217. {
  1218. ULONG CcbFlags = 0;
  1219. FILE_ID FileId;
  1220. BOOLEAN UnlockVcb = FALSE;
  1221. BOOLEAN FcbExisted;
  1222. PFCB NextFcb = NULL;
  1223. PFCB ParentFcb = NULL;
  1224. TYPE_OF_OPEN TypeOfOpen;
  1225. NODE_TYPE_CODE NodeTypeCode;
  1226. ICB_SEARCH_CONTEXT IcbContext;
  1227. BOOLEAN CleanupIcbContext = FALSE;
  1228. PLCB OpenLcb;
  1229. NTSTATUS Status;
  1230. PAGED_CODE();
  1231. //
  1232. // Figure out what kind of open we will be performing here. The caller has already insured
  1233. // that the user is expecting us to do this.
  1234. //
  1235. if (FlagOn( DirContext->Fid->Flags, NSR_FID_F_DIRECTORY )) {
  1236. TypeOfOpen = UserDirectoryOpen;
  1237. NodeTypeCode = UDFS_NTC_FCB_INDEX;
  1238. } else {
  1239. TypeOfOpen = UserFileOpen;
  1240. NodeTypeCode = UDFS_NTC_FCB_DATA;
  1241. }
  1242. //
  1243. // Check for illegal access to this file.
  1244. //
  1245. if (PerformUserOpen &&
  1246. UdfIllegalFcbAccess( IrpContext,
  1247. TypeOfOpen,
  1248. IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
  1249. return STATUS_ACCESS_DENIED;
  1250. }
  1251. //
  1252. // Use a try-finally to facilitate cleanup.
  1253. //
  1254. try {
  1255. //
  1256. // Check the related Ccb to see if this was an OpenByFileId.
  1257. //
  1258. if (ARGUMENT_PRESENT( RelatedCcb ) &&
  1259. FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
  1260. SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
  1261. }
  1262. if (IgnoreCase) {
  1263. SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
  1264. }
  1265. //
  1266. // Build the file Id for this object.
  1267. //
  1268. UdfSetFidFromLbAddr( FileId, DirContext->Fid->Icb.Start );
  1269. if (TypeOfOpen == UserDirectoryOpen) {
  1270. UdfSetFidDirectory( FileId );
  1271. }
  1272. //
  1273. // Lock the Vcb so we can examine the Fcb Table.
  1274. //
  1275. UdfLockVcb( IrpContext, Vcb );
  1276. UnlockVcb = TRUE;
  1277. //
  1278. // Get the Fcb for this file.
  1279. //
  1280. NextFcb = UdfCreateFcb( IrpContext, FileId, NodeTypeCode, &FcbExisted );
  1281. //
  1282. // If the Fcb was created here then initialize from the values in the
  1283. // dirent. We have optimistically assumed that there isn't any corrupt
  1284. // information to this point - we're about to discover it if there is.
  1285. //
  1286. if (!FcbExisted) {
  1287. //
  1288. // Set the root extent length and go get the active ICB, initialize.
  1289. //
  1290. NextFcb->RootExtentLength = DirContext->Fid->Icb.Length.Length;
  1291. UdfInitializeIcbContextFromFcb( IrpContext, &IcbContext, NextFcb );
  1292. CleanupIcbContext = TRUE;
  1293. UdfLookupActiveIcb( IrpContext,
  1294. &IcbContext,
  1295. NextFcb->RootExtentLength );
  1296. UdfInitializeFcbFromIcbContext( IrpContext,
  1297. NextFcb,
  1298. &IcbContext,
  1299. *CurrentFcb);
  1300. UdfCleanupIcbContext( IrpContext, &IcbContext );
  1301. CleanupIcbContext = FALSE;
  1302. }
  1303. //
  1304. // Now try to acquire the new Fcb without waiting. We will reference
  1305. // the Fcb and retry with wait if unsuccessful.
  1306. //
  1307. if (!UdfAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
  1308. NextFcb->FcbReference += 1;
  1309. UdfUnlockVcb( IrpContext, Vcb );
  1310. UdfReleaseFcb( IrpContext, *CurrentFcb );
  1311. UdfAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
  1312. UdfAcquireFcbExclusive( IrpContext, *CurrentFcb, FALSE );
  1313. UdfLockVcb( IrpContext, Vcb );
  1314. NextFcb->FcbReference -= 1;
  1315. }
  1316. //
  1317. // Move down to this new Fcb. Remember that we still own the parent however.
  1318. //
  1319. ParentFcb = *CurrentFcb;
  1320. *CurrentFcb = NextFcb;
  1321. //
  1322. // Store this name into the prefix table for the parent.
  1323. //
  1324. OpenLcb = UdfInsertPrefix( IrpContext,
  1325. NextFcb,
  1326. ( ShortNameMatch?
  1327. &DirContext->ShortObjectName :
  1328. &DirContext->CaseObjectName ),
  1329. ShortNameMatch,
  1330. IgnoreCase,
  1331. ParentFcb );
  1332. //
  1333. // Now increment the reference counts for the parent and drop the Vcb.
  1334. //
  1335. DebugTrace(( +1, Dbg,
  1336. "UdfOpenObjectFromDirContext, PFcb %08x Vcb %d/%d Fcb %d/%d\n", ParentFcb,
  1337. Vcb->VcbReference,
  1338. Vcb->VcbUserReference,
  1339. ParentFcb->FcbReference,
  1340. ParentFcb->FcbUserReference ));
  1341. UdfIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
  1342. DebugTrace(( -1, Dbg,
  1343. "UdfOpenObjectFromDirContext, Vcb %d/%d Fcb %d/%d\n",
  1344. Vcb->VcbReference,
  1345. Vcb->VcbUserReference,
  1346. ParentFcb->FcbReference,
  1347. ParentFcb->FcbUserReference ));
  1348. UdfUnlockVcb( IrpContext, Vcb );
  1349. UnlockVcb = FALSE;
  1350. //
  1351. // Perform initialization associated with the directory context.
  1352. //
  1353. UdfInitializeLcbFromDirContext( IrpContext,
  1354. OpenLcb,
  1355. DirContext );
  1356. //
  1357. // If we just opened VIDEO_TS directory, on a UDF1.02 file system,
  1358. // then mark the Fcb to allow the >=1Gb single AD workaround
  1359. // to be used on it's children (works around some corrupt DVD-Videos)
  1360. //
  1361. if ((NextFcb->NodeTypeCode == UDFS_NTC_FCB_INDEX) &&
  1362. (ParentFcb == Vcb->RootIndexFcb) &&
  1363. (Vcb->UdfRevision == UDF_VERSION_102) &&
  1364. (OpenLcb->FileName.Length == 16) &&
  1365. (!_wcsnicmp( OpenLcb->FileName.Buffer, L"VIDEO_TS", 8))) {
  1366. DebugTrace(( 0, Dbg, "Enabled >= 1gig AD workaround\n"));
  1367. SetFlag( NextFcb->FcbState, FCB_STATE_ALLOW_ONEGIG_WORKAROUND);
  1368. }
  1369. //
  1370. // Release the parent Fcb at this point.
  1371. //
  1372. UdfReleaseFcb( IrpContext, ParentFcb );
  1373. ParentFcb = NULL;
  1374. //
  1375. // Call our worker routine to complete the open.
  1376. //
  1377. if (PerformUserOpen) {
  1378. Status = UdfCompleteFcbOpen( IrpContext,
  1379. IrpSp,
  1380. Vcb,
  1381. CurrentFcb,
  1382. OpenLcb,
  1383. TypeOfOpen,
  1384. CcbFlags,
  1385. IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
  1386. }
  1387. } finally {
  1388. //
  1389. // Unlock the Vcb if held.
  1390. //
  1391. if (UnlockVcb) {
  1392. UdfUnlockVcb( IrpContext, Vcb );
  1393. }
  1394. //
  1395. // Release the parent if held.
  1396. //
  1397. if (ParentFcb != NULL) {
  1398. UdfReleaseFcb( IrpContext, ParentFcb );
  1399. }
  1400. //
  1401. // Destroy the new Fcb if it was not fully initialized.
  1402. //
  1403. if (NextFcb && !FlagOn( NextFcb->FcbState, FCB_STATE_INITIALIZED )) {
  1404. UdfDeleteFcb( IrpContext, NextFcb );
  1405. }
  1406. //
  1407. // Clean up the Icb context if used.
  1408. //
  1409. if (CleanupIcbContext) {
  1410. UdfCleanupIcbContext( IrpContext, &IcbContext );
  1411. }
  1412. }
  1413. return Status;
  1414. }
  1415. //
  1416. // Local support routine
  1417. //
  1418. NTSTATUS
  1419. UdfCompleteFcbOpen (
  1420. IN PIRP_CONTEXT IrpContext,
  1421. PIO_STACK_LOCATION IrpSp,
  1422. IN PVCB Vcb,
  1423. IN OUT PFCB *CurrentFcb,
  1424. IN PLCB OpenLcb OPTIONAL,
  1425. IN TYPE_OF_OPEN TypeOfOpen,
  1426. IN ULONG UserCcbFlags,
  1427. IN ACCESS_MASK DesiredAccess
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. This is the worker routine which takes an existing Fcb and completes
  1432. the open. We will do any necessary oplock checks and sharing checks.
  1433. Finally we will create the Ccb and update the file object and any
  1434. file object flags.
  1435. Arguments:
  1436. IrpSp - Stack location for the current request.
  1437. Vcb - Vcb for the current volume.
  1438. CurrentFcb - Address of pointer to Fcb to open. We clear this field if
  1439. we release the resource for this file.
  1440. OpenLcb - Lcb this Fcb is being opened by
  1441. TypeOfOpen - Type of open for this request.
  1442. UserCcbFlags - Flags to OR into the Ccb flags.
  1443. DesiredAccess - Desired access for this open.
  1444. Return Value:
  1445. NTSTATUS - STATUS_SUCCESS if we complete this request, STATUS_PENDING if
  1446. the oplock package takes the Irp or SHARING_VIOLATION if there is a
  1447. sharing check conflict.
  1448. --*/
  1449. {
  1450. NTSTATUS Status;
  1451. NTSTATUS OplockStatus = STATUS_SUCCESS;
  1452. ULONG Information = FILE_OPENED;
  1453. BOOLEAN LockVolume = FALSE;
  1454. PFCB Fcb = *CurrentFcb;
  1455. PCCB Ccb;
  1456. PAGED_CODE();
  1457. //
  1458. // Expand maximum allowed to something sensible for share access checking
  1459. //
  1460. if (MAXIMUM_ALLOWED == DesiredAccess) {
  1461. DesiredAccess = FILE_ALL_ACCESS & ~((TypeOfOpen != UserVolumeOpen ?
  1462. (FILE_WRITE_ATTRIBUTES |
  1463. FILE_WRITE_DATA |
  1464. FILE_WRITE_EA |
  1465. FILE_ADD_FILE |
  1466. FILE_ADD_SUBDIRECTORY |
  1467. FILE_APPEND_DATA) : 0) |
  1468. FILE_DELETE_CHILD |
  1469. DELETE |
  1470. WRITE_DAC );
  1471. }
  1472. //
  1473. // If this a volume open and the user wants to lock the volume then
  1474. // purge and lock the volume.
  1475. //
  1476. if ((TypeOfOpen <= UserVolumeOpen) &&
  1477. !FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ )) {
  1478. //
  1479. // If there are open handles then fail this immediately.
  1480. //
  1481. if (Vcb->VcbCleanup != 0) {
  1482. return STATUS_SHARING_VIOLATION;
  1483. }
  1484. //
  1485. // If we can't wait then force this to be posted.
  1486. //
  1487. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  1488. UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  1489. }
  1490. LockVolume = TRUE;
  1491. //
  1492. // Purge the volume and make sure all of the user references
  1493. // are gone.
  1494. //
  1495. Status = UdfPurgeVolume( IrpContext, Vcb, FALSE );
  1496. if (Status != STATUS_SUCCESS) {
  1497. return Status;
  1498. }
  1499. //
  1500. // Now force all of the delayed close operations to go away.
  1501. //
  1502. UdfFspClose( Vcb );
  1503. if (Vcb->VcbUserReference > Vcb->VcbResidualUserReference) {
  1504. return STATUS_SHARING_VIOLATION;
  1505. }
  1506. }
  1507. //
  1508. // If the Fcb already existed then we need to check the oplocks and
  1509. // the share access.
  1510. //
  1511. if (Fcb->FcbCleanup != 0) {
  1512. //
  1513. // If this is a user file open then check whether there are any
  1514. // batch oplock.
  1515. //
  1516. if (TypeOfOpen == UserFileOpen) {
  1517. //
  1518. // Store the address of the Fcb for a possible teardown into
  1519. // the IrpContext. We will release this in the call to
  1520. // prepost the Irp.
  1521. //
  1522. IrpContext->TeardownFcb = CurrentFcb;
  1523. if (FsRtlCurrentBatchOplock( &Fcb->Oplock )) {
  1524. //
  1525. // We remember if a batch oplock break is underway for the
  1526. // case where the sharing check fails.
  1527. //
  1528. Information = FILE_OPBATCH_BREAK_UNDERWAY;
  1529. OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
  1530. IrpContext->Irp,
  1531. IrpContext,
  1532. UdfOplockComplete,
  1533. UdfPrePostIrp );
  1534. if (OplockStatus == STATUS_PENDING) {
  1535. return STATUS_PENDING;
  1536. }
  1537. }
  1538. //
  1539. // Check the share access before breaking any exclusive oplocks.
  1540. //
  1541. Status = IoCheckShareAccess( DesiredAccess,
  1542. IrpSp->Parameters.Create.ShareAccess,
  1543. IrpSp->FileObject,
  1544. &Fcb->ShareAccess,
  1545. FALSE );
  1546. if (!NT_SUCCESS( Status )) {
  1547. return Status;
  1548. }
  1549. //
  1550. // Now check that we can continue based on the oplock state of the
  1551. // file.
  1552. //
  1553. OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
  1554. IrpContext->Irp,
  1555. IrpContext,
  1556. UdfOplockComplete,
  1557. UdfPrePostIrp );
  1558. if (OplockStatus == STATUS_PENDING) {
  1559. return STATUS_PENDING;
  1560. }
  1561. IrpContext->TeardownFcb = NULL;
  1562. //
  1563. // Otherwise just do the sharing check.
  1564. //
  1565. } else {
  1566. Status = IoCheckShareAccess( DesiredAccess,
  1567. IrpSp->Parameters.Create.ShareAccess,
  1568. IrpSp->FileObject,
  1569. &Fcb->ShareAccess,
  1570. FALSE );
  1571. if (!NT_SUCCESS( Status )) {
  1572. return Status;
  1573. }
  1574. }
  1575. }
  1576. //
  1577. // Create the Ccb now.
  1578. //
  1579. Ccb = UdfCreateCcb( IrpContext, Fcb, OpenLcb, UserCcbFlags );
  1580. //
  1581. // Update the share access.
  1582. //
  1583. if (Fcb->FcbCleanup == 0) {
  1584. IoSetShareAccess( DesiredAccess,
  1585. IrpSp->Parameters.Create.ShareAccess,
  1586. IrpSp->FileObject,
  1587. &Fcb->ShareAccess );
  1588. } else {
  1589. IoUpdateShareAccess( IrpSp->FileObject, &Fcb->ShareAccess );
  1590. }
  1591. //
  1592. // Set the file object type.
  1593. //
  1594. UdfSetFileObject( IrpContext, IrpSp->FileObject, TypeOfOpen, Fcb, Ccb );
  1595. //
  1596. // Set the appropriate cache flags for a user file object.
  1597. //
  1598. if (TypeOfOpen == UserFileOpen) {
  1599. if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING )) {
  1600. SetFlag( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
  1601. } else {
  1602. SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
  1603. }
  1604. }
  1605. else if (TypeOfOpen == UserVolumeOpen) {
  1606. //
  1607. // DASD access is always noncached
  1608. //
  1609. SetFlag( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
  1610. }
  1611. //
  1612. // Update the open and cleanup counts. Check the fast io state here.
  1613. //
  1614. UdfLockVcb( IrpContext, Vcb );
  1615. UdfIncrementCleanupCounts( IrpContext, Fcb );
  1616. DebugTrace(( +1, Dbg,
  1617. "UdfCompleteFcbOpen, Fcb %08x Vcb %d/%d Fcb %d/%d\n", Fcb,
  1618. Vcb->VcbReference,
  1619. Vcb->VcbUserReference,
  1620. Fcb->FcbReference,
  1621. Fcb->FcbUserReference ));
  1622. UdfIncrementReferenceCounts( IrpContext, Fcb, 1, 1 );
  1623. DebugTrace(( -1, Dbg,
  1624. "UdfCompleteFcbOpen, Vcb %d/%d Fcb %d/%d\n",
  1625. Vcb->VcbReference,
  1626. Vcb->VcbUserReference,
  1627. Fcb->FcbReference,
  1628. Fcb->FcbUserReference ));
  1629. if (LockVolume) {
  1630. Vcb->VolumeLockFileObject = IrpSp->FileObject;
  1631. SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
  1632. }
  1633. UdfUnlockVcb( IrpContext, Vcb );
  1634. UdfLockFcb( IrpContext, Fcb );
  1635. if (TypeOfOpen == UserFileOpen) {
  1636. Fcb->IsFastIoPossible = UdfIsFastIoPossible( Fcb );
  1637. } else {
  1638. Fcb->IsFastIoPossible = FastIoIsNotPossible;
  1639. }
  1640. UdfUnlockFcb( IrpContext, Fcb );
  1641. //
  1642. // Show that we opened the file.
  1643. //
  1644. IrpContext->Irp->IoStatus.Information = Information;
  1645. //
  1646. // Point to the section object pointer in the non-paged Fcb.
  1647. //
  1648. IrpSp->FileObject->SectionObjectPointer = &Fcb->FcbNonpaged->SegmentObject;
  1649. return OplockStatus;
  1650. }