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.

4964 lines
130 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. StrucSup.c
  5. Abstract:
  6. This module implements the Udfs in-memory data structure manipulation
  7. routines
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Dan Lovinger [DanLo] 19-Jun-1996
  11. Tom Jolly [TomJolly] 24-Jan-2000
  12. Revision History:
  13. Tom Jolly [TomJolly] 1-March-2000 UDF 2.01 support
  14. // @@END_DDKSPLIT
  15. --*/
  16. #include "UdfProcs.h"
  17. //
  18. // The Bug check file id for this module
  19. //
  20. #define BugCheckFileId (UDFS_BUG_CHECK_STRUCSUP)
  21. //
  22. // The local debug trace level
  23. //
  24. #define Dbg (UDFS_DEBUG_LEVEL_STRUCSUP)
  25. //
  26. // Define this to change the VAT search strategy to keep looking until
  27. // we get a read fail/invalid block, and use the highest found. Default
  28. // (undef) is to stop searching at the first valid VAT we find.
  29. //
  30. //#define SEARCH_FOR_HIGHEST_VALID_VAT
  31. //
  32. // Local structures
  33. //
  34. typedef struct _FCB_TABLE_ELEMENT {
  35. FILE_ID FileId;
  36. PFCB Fcb;
  37. } FCB_TABLE_ELEMENT, *PFCB_TABLE_ELEMENT;
  38. //
  39. // Local macros
  40. //
  41. //
  42. // PFCB
  43. // UdfAllocateFcbData (
  44. // IN PIRP_CONTEXT IrpContext
  45. // );
  46. //
  47. // VOID
  48. // UdfDeallocateFcbData (
  49. // IN PIRP_CONTEXT IrpContext,
  50. // IN PFCB Fcb
  51. // );
  52. //
  53. // PFCB
  54. // UdfAllocateFcbIndex (
  55. // IN PIRP_CONTEXT IrpContext
  56. // );
  57. //
  58. // VOID
  59. // UdfDeallocateFcbIndex (
  60. // IN PIRP_CONTEXT IrpContext,
  61. // IN PFCB Fcb
  62. // );
  63. //
  64. // PFCB_NONPAGED
  65. // UdfAllocateFcbNonpaged (
  66. // IN PIRP_CONTEXT IrpContext
  67. // );
  68. //
  69. // VOID
  70. // UdfDeallocateFcbNonpaged (
  71. // IN PIRP_CONTEXT IrpContext,
  72. // IN PFCB_NONPAGED FcbNonpaged
  73. // );
  74. //
  75. // PCCB
  76. // UdfAllocateCcb (
  77. // IN PIRP_CONTEXT IrpContext
  78. // );
  79. //
  80. // VOID
  81. // UdfDeallocateCcb (
  82. // IN PIRP_CONTEXT IrpContext,
  83. // IN PCCB Ccb
  84. // );
  85. //
  86. #define UdfAllocateFcbData(IC) \
  87. ExAllocateFromPagedLookasideList( &UdfFcbDataLookasideList );
  88. #define UdfDeallocateFcbData(IC,F) \
  89. ExFreeToPagedLookasideList( &UdfFcbDataLookasideList, F );
  90. #define UdfAllocateFcbIndex(IC) \
  91. ExAllocateFromPagedLookasideList( &UdfFcbIndexLookasideList );
  92. #define UdfDeallocateFcbIndex(IC,F) \
  93. ExFreeToPagedLookasideList( &UdfFcbIndexLookasideList, F );
  94. #define UdfAllocateFcbNonpaged(IC) \
  95. ExAllocateFromNPagedLookasideList( &UdfFcbNonPagedLookasideList );
  96. #define UdfDeallocateFcbNonpaged(IC,FNP) \
  97. ExFreeToNPagedLookasideList( &UdfFcbNonPagedLookasideList, FNP );
  98. #define UdfAllocateCcb(IC) \
  99. ExAllocateFromPagedLookasideList( &UdfCcbLookasideList );
  100. #define UdfDeallocateCcb(IC,C) \
  101. ExFreeToPagedLookasideList( &UdfCcbLookasideList, C );
  102. //
  103. // VOID
  104. // UdfInsertFcbTable (
  105. // IN PIRP_CONTEXT IrpContext,
  106. // IN PFCB Fcb
  107. // );
  108. //
  109. // VOID
  110. // UdfDeleteFcbTable (
  111. // IN PIRP_CONTEXT IrpContext,
  112. // IN PFCB Fcb
  113. // );
  114. //
  115. #define UdfInsertFcbTable(IC,F) { \
  116. FCB_TABLE_ELEMENT _Key; \
  117. _Key.Fcb = (F); \
  118. _Key.FileId = (F)->FileId; \
  119. RtlInsertElementGenericTable( &(F)->Vcb->FcbTable, \
  120. &_Key, \
  121. sizeof( FCB_TABLE_ELEMENT ), \
  122. NULL ); \
  123. }
  124. #define UdfDeleteFcbTable(IC,F) { \
  125. FCB_TABLE_ELEMENT _Key; \
  126. _Key.FileId = (F)->FileId; \
  127. RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key ); \
  128. }
  129. //
  130. // Discovers the partition the current allocation descriptor's referred extent
  131. // is on, either explicitly throuigh the descriptor or implicitly through the
  132. // mapped view.
  133. //
  134. INLINE
  135. USHORT
  136. UdfGetPartitionOfCurrentAllocation (
  137. IN PALLOC_ENUM_CONTEXT AllocContext
  138. )
  139. {
  140. if (AllocContext->AllocType == ICBTAG_F_ALLOC_LONG) {
  141. return ((PLONGAD) AllocContext->Alloc)->Start.Partition;
  142. } else {
  143. return AllocContext->IcbContext->Active.Partition;
  144. }
  145. }
  146. //
  147. // Builds the Mcb in an Fcb. Use this after knowing that an Mcb is required
  148. // for mapping information.
  149. //
  150. INLINE
  151. VOID
  152. UdfInitializeFcbMcb (
  153. IN PFCB Fcb
  154. )
  155. {
  156. //
  157. // In certain rare situations, we may get called more than once.
  158. // Just reset the allocations.
  159. //
  160. if (FlagOn( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED )) {
  161. FsRtlResetLargeMcb( &Fcb->Mcb, TRUE );
  162. } else {
  163. FsRtlInitializeLargeMcb( &Fcb->Mcb, UdfPagedPool );
  164. SetFlag( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED );
  165. }
  166. }
  167. //
  168. // Teardown an Fcb's Mcb as required.
  169. //
  170. INLINE
  171. VOID
  172. UdfUninitializeFcbMcb (
  173. IN PFCB Fcb
  174. )
  175. {
  176. if (FlagOn( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED )) {
  177. FsRtlUninitializeLargeMcb( &Fcb->Mcb );
  178. ClearFlag( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED );
  179. }
  180. }
  181. //
  182. // Local support routines
  183. //
  184. PVOID
  185. UdfAllocateTable (
  186. IN PRTL_GENERIC_TABLE Table,
  187. IN CLONG ByteSize
  188. );
  189. PFCB_NONPAGED
  190. UdfCreateFcbNonPaged (
  191. IN PIRP_CONTEXT IrpContext
  192. );
  193. VOID
  194. UdfDeleteFcbNonpaged (
  195. IN PIRP_CONTEXT IrpContext,
  196. IN PFCB_NONPAGED FcbNonpaged
  197. );
  198. VOID
  199. UdfDeallocateTable (
  200. IN PRTL_GENERIC_TABLE Table,
  201. IN PVOID Buffer
  202. );
  203. RTL_GENERIC_COMPARE_RESULTS
  204. UdfFcbTableCompare (
  205. IN PRTL_GENERIC_TABLE Table,
  206. IN PVOID id1,
  207. IN PVOID id2
  208. );
  209. VOID
  210. UdfInitializeAllocationContext (
  211. IN PIRP_CONTEXT IrpContext,
  212. IN PALLOC_ENUM_CONTEXT AllocContext,
  213. IN PICB_SEARCH_CONTEXT IcbContext,
  214. IN BOOLEAN AllowSingleZeroLengthExtent
  215. );
  216. BOOLEAN
  217. UdfGetNextAllocation (
  218. IN PIRP_CONTEXT IrpContext,
  219. IN PALLOC_ENUM_CONTEXT AllocContext
  220. );
  221. BOOLEAN
  222. UdfGetNextAllocationPostProcessing (
  223. IN PIRP_CONTEXT IrpContext,
  224. IN PALLOC_ENUM_CONTEXT AllocContext
  225. );
  226. VOID
  227. UdfLookupActiveIcbInExtent (
  228. IN PIRP_CONTEXT IrpContext,
  229. IN PICB_SEARCH_CONTEXT IcbContext,
  230. IN ULONG Recurse,
  231. IN ULONG Length
  232. );
  233. VOID
  234. UdfInitializeEaContext (
  235. IN PIRP_CONTEXT IrpContext,
  236. IN PEA_SEARCH_CONTEXT EaContext,
  237. IN PICB_SEARCH_CONTEXT IcbContext,
  238. IN ULONG EAType,
  239. IN UCHAR EASubType
  240. );
  241. BOOLEAN
  242. UdfLookupEa (
  243. IN PIRP_CONTEXT IrpContext,
  244. IN PEA_SEARCH_CONTEXT EaContext
  245. );
  246. #ifdef ALLOC_PRAGMA
  247. #pragma alloc_text(PAGE, UdfAllocateTable)
  248. #pragma alloc_text(PAGE, UdfCleanupIcbContext)
  249. #pragma alloc_text(PAGE, UdfCleanupIrpContext)
  250. #pragma alloc_text(PAGE, UdfCreateCcb)
  251. #pragma alloc_text(PAGE, UdfCreateFcb)
  252. #pragma alloc_text(PAGE, UdfCreateFcbNonPaged)
  253. #pragma alloc_text(PAGE, UdfCreateIrpContext)
  254. #pragma alloc_text(PAGE, UdfDeallocateTable)
  255. #pragma alloc_text(PAGE, UdfDeleteCcb)
  256. #pragma alloc_text(PAGE, UdfDeleteFcb)
  257. #pragma alloc_text(PAGE, UdfDeleteFcbNonpaged)
  258. #pragma alloc_text(PAGE, UdfDeleteVcb)
  259. #pragma alloc_text(PAGE, UdfFcbTableCompare)
  260. #pragma alloc_text(PAGE, UdfFindInParseTable)
  261. #pragma alloc_text(PAGE, UdfGetNextAllocation)
  262. #pragma alloc_text(PAGE, UdfGetNextAllocationPostProcessing)
  263. #pragma alloc_text(PAGE, UdfGetNextFcb)
  264. #pragma alloc_text(PAGE, UdfInitializeAllocationContext)
  265. #pragma alloc_text(PAGE, UdfInitializeAllocations)
  266. #pragma alloc_text(PAGE, UdfInitializeEaContext)
  267. #pragma alloc_text(PAGE, UdfInitializeFcbFromIcbContext)
  268. #pragma alloc_text(PAGE, UdfInitializeIcbContext)
  269. #pragma alloc_text(PAGE, UdfInitializeStackIrpContext)
  270. #pragma alloc_text(PAGE, UdfInitializeVcb)
  271. #pragma alloc_text(PAGE, UdfLookupActiveIcb)
  272. #pragma alloc_text(PAGE, UdfLookupActiveIcbInExtent)
  273. #pragma alloc_text(PAGE, UdfLookupEa)
  274. #pragma alloc_text(PAGE, UdfLookupFcbTable)
  275. #pragma alloc_text(PAGE, UdfTeardownStructures)
  276. #pragma alloc_text(PAGE, UdfUpdateTimestampsFromIcbContext)
  277. #pragma alloc_text(PAGE, UdfUpdateVcbPhase0)
  278. #pragma alloc_text(PAGE, UdfUpdateVcbPhase1)
  279. #pragma alloc_text(PAGE, UdfVerifyDescriptor)
  280. #endif ALLOC_PRAGMA
  281. BOOLEAN
  282. UdfInitializeVcb (
  283. IN PIRP_CONTEXT IrpContext,
  284. IN OUT PVCB Vcb,
  285. IN PDEVICE_OBJECT TargetDeviceObject,
  286. IN PVPB Vpb,
  287. IN PDISK_GEOMETRY DiskGeometry,
  288. IN ULONG MediaChangeCount
  289. )
  290. /*++
  291. Routine Description:
  292. This routine initializes and inserts a new Vcb record into the in-memory
  293. data structure. The Vcb record "hangs" off the end of the Volume device
  294. object and must be allocated by our caller.
  295. Arguments:
  296. Vcb - Supplies the address of the Vcb record being initialized.
  297. TargetDeviceObject - Supplies the address of the target device object to
  298. associate with the Vcb record.
  299. Vpb - Supplies the address of the Vpb to associate with the Vcb record.
  300. MediaChangeCount - Initial media change count of the target device
  301. Return Value:
  302. Boolean TRUE if the volume looks reasonable to continue mounting, FALSE
  303. otherwise. This routine can raise on allocation failure.
  304. --*/
  305. {
  306. PAGED_CODE();
  307. //
  308. // We start by first zeroing out all of the VCB, this will guarantee
  309. // that any stale data is wiped clean.
  310. //
  311. RtlZeroMemory( Vcb, sizeof( VCB ));
  312. //
  313. // Set the proper node type code and node byte size.
  314. //
  315. Vcb->NodeTypeCode = UDFS_NTC_VCB;
  316. Vcb->NodeByteSize = sizeof( VCB );
  317. //
  318. // Initialize the DirNotify structs. FsRtlNotifyInitializeSync can raise.
  319. //
  320. InitializeListHead( &Vcb->DirNotifyList );
  321. FsRtlNotifyInitializeSync( &Vcb->NotifySync );
  322. //
  323. // Pick up a VPB right now so we know we can pull this filesystem stack
  324. // off of the storage stack on demand. This can raise - if it does,
  325. // uninitialize the notify structures before returning.
  326. //
  327. try {
  328. Vcb->SwapVpb = FsRtlAllocatePoolWithTag( NonPagedPool,
  329. sizeof( VPB ),
  330. TAG_VPB );
  331. }
  332. finally {
  333. if (AbnormalTermination()) {
  334. FsRtlNotifyUninitializeSync( &Vcb->NotifySync);
  335. }
  336. }
  337. //
  338. // Nothing beyond this point should raise.
  339. //
  340. RtlZeroMemory( Vcb->SwapVpb, sizeof( VPB ) );
  341. //
  342. // Initialize the resource variable for the Vcb and files.
  343. //
  344. ExInitializeResourceLite( &Vcb->VcbResource );
  345. ExInitializeResourceLite( &Vcb->FileResource );
  346. ExInitializeResourceLite( &Vcb->VmcbMappingResource );
  347. ExInitializeFastMutex( &Vcb->VcbMutex );
  348. //
  349. // Insert this Vcb record on the UdfData.VcbQueue.
  350. //
  351. InsertHeadList( &UdfData.VcbQueue, &Vcb->VcbLinks );
  352. //
  353. // Set the Target Device Object and Vpb fields, referencing the
  354. // target device.
  355. //
  356. ObReferenceObject( TargetDeviceObject );
  357. Vcb->TargetDeviceObject = TargetDeviceObject;
  358. Vcb->Vpb = Vpb;
  359. //
  360. // Set the removable media flag based on the real device's
  361. // characteristics
  362. //
  363. if (FlagOn( Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA )) {
  364. SetFlag( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA );
  365. }
  366. //
  367. // Initialize the generic Fcb Table.
  368. //
  369. RtlInitializeGenericTable( &Vcb->FcbTable,
  370. (PRTL_GENERIC_COMPARE_ROUTINE) UdfFcbTableCompare,
  371. (PRTL_GENERIC_ALLOCATE_ROUTINE) UdfAllocateTable,
  372. (PRTL_GENERIC_FREE_ROUTINE) UdfDeallocateTable,
  373. NULL );
  374. //
  375. // Show that we have a mount in progress.
  376. //
  377. UdfSetVcbCondition( Vcb, VcbMountInProgress);
  378. //
  379. // Refererence the Vcb for two reasons. The first is a reference
  380. // that prevents the Vcb from going away on the last close unless
  381. // dismount has already occurred. The second is to make sure
  382. // we don't go into the dismount path on any error during mount
  383. // until we get to the Mount cleanup.
  384. //
  385. Vcb->VcbResidualReference = UDFS_BASE_RESIDUAL_REFERENCE;
  386. Vcb->VcbResidualUserReference = UDFS_BASE_RESIDUAL_USER_REFERENCE;
  387. Vcb->VcbReference = 1 + Vcb->VcbResidualReference;
  388. //
  389. // Set the sector size.
  390. //
  391. Vcb->SectorSize = DiskGeometry->BytesPerSector;
  392. //
  393. // Set the sector shift amount.
  394. //
  395. Vcb->SectorShift = UdfHighBit( DiskGeometry->BytesPerSector );
  396. //
  397. // Set the media change count on the device
  398. //
  399. UdfSetMediaChangeCount( Vcb, MediaChangeCount);
  400. return TRUE;
  401. }
  402. VOID
  403. UdfCreateOrResetVatAndVmcbStreams(
  404. IN PIRP_CONTEXT IrpContext,
  405. IN PVCB Vcb,
  406. IN ULONG Lbn,
  407. IN PICBFILE VatIcb,
  408. IN USHORT Reference
  409. )
  410. /*++
  411. Routine Description:
  412. This is pretty ugly, but we have to cobble this maybe-Icb into the metadata stream
  413. so that initialization/use is possible (embedded data!). Normally regular Icb searches
  414. would have done this for us, but since we have to go through such an amusing search
  415. procedure that isn't possible. So, add it as a single sector mapping.
  416. Since this lives in a partition, we can just do the "lookup" in the metadata stream.
  417. If we did not have this guarantee, we'd need to do a bit more of this by hand.
  418. As this is at mount time, we are very sure we are the only person messing with the
  419. metadata stream.
  420. Arguments:
  421. VatIcb - pointer to memory containing VAT FE that we wish to set up VAT/Vmcb streams for.
  422. Reference - partition ref of virtual partition.
  423. Return Value:
  424. None. Raise on error.
  425. --*/
  426. {
  427. LONGLONG FileId = 0;
  428. ICB_SEARCH_CONTEXT IcbContext;
  429. ULONG Vsn;
  430. if (NULL != Vcb->VatFcb) {
  431. UdfResetVmcb( &Vcb->Vmcb );
  432. CcPurgeCacheSection( Vcb->MetadataFcb->FileObject->SectionObjectPointer,
  433. NULL,
  434. 0,
  435. FALSE );
  436. CcPurgeCacheSection( Vcb->VatFcb->FileObject->SectionObjectPointer,
  437. NULL,
  438. 0,
  439. FALSE );
  440. }
  441. else {
  442. //
  443. // This is the first pass. Stamp out the VAT stream Fcb.
  444. //
  445. UdfLockVcb( IrpContext, Vcb );
  446. try {
  447. Vcb->VatFcb = UdfCreateFcb( IrpContext,
  448. *((PFILE_ID) &FileId),
  449. UDFS_NTC_FCB_INDEX,
  450. NULL );
  451. UdfIncrementReferenceCounts( IrpContext, Vcb->VatFcb, 1, 1 );
  452. }
  453. finally {
  454. UdfUnlockVcb( IrpContext, Vcb );
  455. }
  456. //
  457. // Point to the file resource and set the flag that will cause mappings
  458. // to go through the Vmcb
  459. //
  460. Vcb->VatFcb->Resource = &Vcb->FileResource;
  461. }
  462. //
  463. // Establish a mapping for the candidate Vat Icb in the metadata stream
  464. // (we're currently looking at a local buffer filled by readsectors). Note
  465. // that this operation uses the presence of Vcb->VatFcb to switch of rounding
  466. // of extents to page sizes - a bad thing (tm) for packet written media.
  467. //
  468. Vsn = UdfLookupMetaVsnOfExtent( IrpContext,
  469. Vcb,
  470. Reference,
  471. Lbn,
  472. BlockSize( Vcb ),
  473. TRUE );
  474. //
  475. // Now size and try to pick up all of the allocation descriptors for this guy.
  476. // We're going to need to conjure an IcbContext for this.
  477. //
  478. Vcb->VatFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb, VatIcb->InfoLength );
  479. Vcb->VatFcb->FileSize.QuadPart =
  480. Vcb->VatFcb->ValidDataLength.QuadPart = VatIcb->InfoLength;
  481. //
  482. // Now construct the ICB search context we would have had
  483. // made in the process of normal ICB discovery. Since we
  484. // were unable to do that, gotta do it by hand. NOTE that
  485. // View / VatIcb is NOT a CcMapping, but a pointer to buffer
  486. // we allocated & filled with ReadSectors, above.
  487. //
  488. RtlZeroMemory( &IcbContext, sizeof( ICB_SEARCH_CONTEXT ));
  489. IcbContext.Active.View = (PVOID) VatIcb;
  490. IcbContext.Active.Partition = Reference;
  491. IcbContext.Active.Lbn = Lbn;
  492. IcbContext.Active.Length = UdfRawReadSize( Vcb, BlockSize( Vcb ));
  493. IcbContext.Active.Vsn = Vsn;
  494. try {
  495. UdfInitializeAllocations( IrpContext,
  496. Vcb->VatFcb,
  497. &IcbContext,
  498. FALSE);
  499. }
  500. finally {
  501. UdfCleanupIcbContext( IrpContext, &IcbContext );
  502. }
  503. //
  504. // Create or resize the stream file for the VAT as appropriate.
  505. //
  506. if (!FlagOn( Vcb->VatFcb->FcbState, FCB_STATE_INITIALIZED )) {
  507. UdfCreateInternalStream( IrpContext, Vcb, Vcb->VatFcb );
  508. SetFlag( Vcb->VatFcb->FcbState, FCB_STATE_INITIALIZED );
  509. } else {
  510. CcSetFileSizes( Vcb->VatFcb->FileObject, (PCC_FILE_SIZES) &Vcb->VatFcb->AllocationSize );
  511. }
  512. }
  513. VOID
  514. UdfUpdateVcbPhase0 (
  515. IN PIRP_CONTEXT IrpContext,
  516. IN OUT PVCB Vcb
  517. )
  518. /*++
  519. Routine Description:
  520. This routine is called to perform the initial spinup of the volume so that
  521. we can do reads into it. Primarily, this is required since virtual partitions
  522. make us lift the remapping table, and the final sets of descriptors from the volume
  523. can be off in these virtual partitions.
  524. So, we need to get everything set up to read.
  525. Arguments:
  526. Vcb - Vcb for the volume being mounted. We have already set up and completed
  527. the Pcb.
  528. Return Value:
  529. None
  530. --*/
  531. {
  532. LONGLONG FileId = 0;
  533. PICBFILE VatIcb = NULL;
  534. PREGID RegId;
  535. ULONG ThisPass;
  536. ULONG Psn;
  537. ULONG Lbn;
  538. ULONG SectorCount;
  539. USHORT Reference;
  540. #ifdef SEARCH_FOR_HIGHEST_VALID_VAT
  541. ULONG LastValidVatLbn = 0;
  542. ULONG LastValidVatOffset;
  543. ULONG LastValidVatCount;
  544. #endif
  545. BOOLEAN UnlockVcb = FALSE;
  546. PBCB Bcb = NULL;
  547. LARGE_INTEGER Offset;
  548. PVAT_HEADER VatHeader = NULL;
  549. PAGED_CODE();
  550. //
  551. // Check input.
  552. //
  553. ASSERT_IRP_CONTEXT( IrpContext );
  554. ASSERT_VCB( Vcb );
  555. DebugTrace(( +1, Dbg, "UdfUpdateVcbPhase0, Vcb %08x\n", Vcb ));
  556. try {
  557. //////////////////
  558. //
  559. // Create the Metadata Fcb and refererence it and the Vcb.
  560. //
  561. //////////////////
  562. UdfLockVcb( IrpContext, Vcb );
  563. UnlockVcb = TRUE;
  564. Vcb->MetadataFcb = UdfCreateFcb( IrpContext,
  565. *((PFILE_ID) &FileId),
  566. UDFS_NTC_FCB_INDEX,
  567. NULL );
  568. UdfIncrementReferenceCounts( IrpContext, Vcb->MetadataFcb, 1, 1 );
  569. UdfUnlockVcb( IrpContext, Vcb );
  570. UnlockVcb = FALSE;
  571. //
  572. // The metadata stream is grown lazily as we reference disk structures.
  573. //
  574. Vcb->MetadataFcb->FileSize.QuadPart =
  575. Vcb->MetadataFcb->ValidDataLength.QuadPart =
  576. Vcb->MetadataFcb->AllocationSize.QuadPart = 0;
  577. //
  578. // Initialize the volume Vmcb
  579. //
  580. UdfLockFcb( IrpContext, Vcb->MetadataFcb );
  581. UdfInitializeVmcb( &Vcb->Vmcb,
  582. UdfPagedPool,
  583. MAXULONG,
  584. SectorSize(Vcb) );
  585. SetFlag( Vcb->VcbState, VCB_STATE_VMCB_INIT);
  586. UdfUnlockFcb( IrpContext, Vcb->MetadataFcb );
  587. //
  588. // Point to the file resource and set the flag that will cause mappings
  589. // to go through the Vmcb
  590. //
  591. Vcb->MetadataFcb->Resource = &Vcb->FileResource;
  592. SetFlag( Vcb->MetadataFcb->FcbState, FCB_STATE_VMCB_MAPPING | FCB_STATE_INITIALIZED );
  593. //
  594. // Create the stream file for this.
  595. //
  596. UdfCreateInternalStream( IrpContext, Vcb, Vcb->MetadataFcb );
  597. //////////////////
  598. //
  599. // If this is a volume containing a virtual partition, set up the
  600. // Virtual Allocation Table Fcb and adjust the residual reference
  601. // counts comensurately.
  602. //
  603. //////////////////
  604. if (FlagOn( Vcb->Pcb->Flags, PCB_FLAG_VIRTUAL_PARTITION )) {
  605. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, handling VAT setup\n" ));
  606. //
  607. // Now if some dummy has stuck us in the situation of not giving us
  608. // the tools to figure out where the end of the media is, tough luck.
  609. //
  610. if (!Vcb->BoundN || Vcb->BoundN < ANCHOR_SECTOR) {
  611. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, no end bound was discoverable!\n" ));
  612. UdfRaiseStatus( IrpContext, STATUS_UNRECOGNIZED_VOLUME );
  613. }
  614. //
  615. // We take care of this first since the residuals must be in place
  616. // if we raise while finding the VAT, else we will get horribly
  617. // confused when the in-progress references are seen. We will think
  618. // that the extra real referenes are indications that the volume can't
  619. // be dismounted.
  620. //
  621. Vcb->VcbResidualReference += UDFS_CDUDF_RESIDUAL_REFERENCE;
  622. Vcb->VcbResidualUserReference += UDFS_CDUDF_RESIDUAL_USER_REFERENCE;
  623. Vcb->VcbReference += UDFS_CDUDF_RESIDUAL_REFERENCE;
  624. //
  625. // Now, we need to hunt about for the VAT ICB. This is defined, on
  626. // closed media (meaning that the sessions have been finalized for use
  627. // in CDROM drives), to be in the very last information sector on the
  628. // media. Complicating this simple picture is that CDROMs tell us the
  629. // "last sector" by telling us where the start of the leadout area is,
  630. // not where the end of the informational sectors are. This is an
  631. // important distinction because any combination of the following can
  632. // be used in closing a CDROM session: 2 runout sectors, and/or 150
  633. // sectors (2 seconds) of postgap, or nothing. Immediately after these
  634. // "closing" writes is where the leadout begins.
  635. //
  636. // Runout is usually found on CD-E media and corresponds to the time it
  637. // will take to turn the writing laser off. Postgap is what is used to
  638. // generate audio pauses. It is easy to see that the kind of media and
  639. // kind of mastering tool/system used will affect us here. There is no
  640. // way to know either ahead of time.
  641. //
  642. // So, finally, these are the offsets from our previously discovered
  643. // bounding information where we might find the last information sector:
  644. //
  645. // -152 runout + postgap
  646. // -150 postgap
  647. // -2 runout
  648. // 0 nothing
  649. //
  650. // We must search these from low to high since it is extrememly expensive
  651. // to guess wrong - CDROMs will sit there for tens of seconds trying to
  652. // read unwritten/unreadable sectors. Hopefully we will find the VAT
  653. // ICB beforehand.
  654. //
  655. // This should all be highly disturbing.
  656. //
  657. VatIcb = FsRtlAllocatePoolWithTag( UdfPagedPool,
  658. UdfRawBufferSize( Vcb, BlockSize( Vcb )),
  659. TAG_NSR_VDSD);
  660. for (ThisPass = 0; ThisPass < 4; ThisPass++) {
  661. //
  662. // Lift the appropriate sector. The discerning reader will be confused that
  663. // this is done in sector terms, not block. So is the implementor.
  664. //
  665. Psn = Vcb->BoundN - ( ThisPass == 0? 152 :
  666. ( ThisPass == 1? 150 :
  667. ( ThisPass == 2? 2 : 0 )));
  668. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, looking at Psn 0x%08x\n", Psn ));
  669. //
  670. // Now, try to figure out what physical partition this sector lives in so
  671. // that we can eventually establish workable metadata mappings to it and
  672. // dereference short allocation descriptors it may use.
  673. //
  674. for (Reference = 0;
  675. Reference < Vcb->Pcb->Partitions;
  676. Reference++) {
  677. if (Vcb->Pcb->Partition[Reference].Type == Physical &&
  678. Vcb->Pcb->Partition[Reference].Physical.Start <= Psn &&
  679. Vcb->Pcb->Partition[Reference].Physical.Start +
  680. Vcb->Pcb->Partition[Reference].Physical.Length > Psn) {
  681. break;
  682. }
  683. }
  684. //
  685. // If this sector is not contained in a partition, we do not
  686. // need to look at it.
  687. //
  688. if (Reference == Vcb->Pcb->Partitions) {
  689. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but it isn't in a partition.\n" ));
  690. continue;
  691. }
  692. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... in partition Ref %u.\n", Reference ));
  693. //
  694. // We must locate the Lbn of this Psn by figuring out the offset of it
  695. // in the partition we already know that it is recorded in.
  696. //
  697. Lbn = BlocksFromSectors( Vcb, Psn - Vcb->Pcb->Partition[Reference].Physical.Start );
  698. if (!NT_SUCCESS( UdfReadSectors( IrpContext,
  699. LlBytesFromSectors( Vcb, Psn ),
  700. UdfRawReadSize( Vcb, BlockSize( Vcb )),
  701. TRUE,
  702. VatIcb,
  703. Vcb->TargetDeviceObject ))) {
  704. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but couldn't read it.\n" ));
  705. continue;
  706. }
  707. //
  708. // First make sure this looks vaguely like a file entry.
  709. //
  710. if (!( (((PDESTAG) VatIcb)->Ident == DESTAG_ID_NSR_FILE) ||
  711. (((PDESTAG) VatIcb)->Ident == DESTAG_ID_NSR_EXT_FILE))
  712. ||
  713. !UdfVerifyDescriptor( IrpContext,
  714. (PDESTAG) VatIcb,
  715. ((PDESTAG) VatIcb)->Ident,
  716. BlockSize( Vcb ),
  717. Lbn,
  718. TRUE )) {
  719. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but it didn't verify.\n" ));
  720. continue;
  721. }
  722. //
  723. // Make sure this has filetype of NOTSPEC(1.50) or VAT(2.0x). We can also presume
  724. // that a VAT isn't linked into any directory, so it would be surprising if the link
  725. // count was nonzero.
  726. //
  727. // 4.13.01 - Relaxed the linkcount check. If it's the right type, and it passed
  728. // CRC/Checksum in verify above, that's good enough.
  729. //
  730. if (UdfVATIcbFileTypeExpected( Vcb) != VatIcb->Icbtag.FileType) {
  731. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but the type 0x%x is wrong.\n", VatIcb->Icbtag.FileType));
  732. continue;
  733. }
  734. #ifdef UDF_SANITY
  735. if (0 != VatIcb->LinkCount) {
  736. DebugTrace(( 0, Dbg, "WARNING: VAT linkcount (%d) unexpectedly non-zero\n", VatIcb->LinkCount ));
  737. }
  738. #endif
  739. //
  740. // The VAT must be at least large enough to contain the required information and
  741. // be a multiple of 4byte elements in length. We also have defined a sanity upper
  742. // bound beyond which we never expect to see a VAT go.
  743. //
  744. ASSERT( !LongOffset( UdfMinLegalVATSize( Vcb) ));
  745. if (VatIcb->InfoLength < UdfMinLegalVATSize( Vcb) ||
  746. VatIcb->InfoLength > UDF_CDUDF_MAXIMUM_VAT_SIZE ||
  747. LongOffset( VatIcb->InfoLength )) {
  748. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... but the size (0x%X) looks pretty bogus.\n", VatIcb->InfoLength ));
  749. continue;
  750. }
  751. //
  752. // At this point we have to take a wild guess that this will be the guy. Since the only
  753. // way to be sure is to look at the very end of the file an look for the regid (1.50), or
  754. // the beginning for the VAT header record (2.0x), go map this thing.
  755. //
  756. //
  757. // Zap any previous mapping and invalidate the metadata and VAT stream content.
  758. //
  759. UdfUnpinData( IrpContext, &Bcb );
  760. UdfCreateOrResetVatAndVmcbStreams( IrpContext,
  761. Vcb,
  762. Lbn,
  763. VatIcb,
  764. Reference);
  765. //
  766. // To complete VAT discovery, we now look for the regid at the end of the stream
  767. // (1.50) or a header at the beginning (2.0x) that will definitively tell us that
  768. // this is really a VAT. We already know the stream is big enough by virtue of our
  769. // preliminary sanity checks.
  770. //
  771. if (UdfVATHasHeaderRecord( Vcb)) {
  772. //
  773. // UDF 2.0x style VAT. Map the header record, and ensure the size looks
  774. // sensible. Store total header size (incl imp. use) in the Vcb so we know
  775. // the offset to the first VAT mapping entry.
  776. //
  777. Offset.QuadPart = 0;
  778. CcMapData( Vcb->VatFcb->FileObject,
  779. &Offset,
  780. sizeof(VAT_HEADER),
  781. TRUE,
  782. &Bcb,
  783. &VatHeader );
  784. if ( ( (sizeof( VAT_HEADER) + VatHeader->ImpUseLength) != VatHeader->Length) ||
  785. ( VatHeader->ImpUseLength && ((VatHeader->ImpUseLength < 32) || ( VatHeader->ImpUseLength & 0x03)))
  786. ) {
  787. //
  788. // Header is wrong size, or impl. use length is not dword aligned or is < 32 bytes
  789. // Oh well, this isn't it....
  790. //
  791. DebugTrace((0, Dbg, "UdfUpdateVcbPhase0() Invalid VAT header L 0x%X, IUL 0x%X\n", VatHeader->Length, VatHeader->ImpUseLength));
  792. continue;
  793. }
  794. Vcb->OffsetToFirstVATEntry = VatHeader->Length;
  795. Vcb->VATEntryCount = (Vcb->VatFcb->FileSize.LowPart - Vcb->OffsetToFirstVATEntry) / sizeof(ULONG);
  796. DebugTrace((0, Dbg, "UdfUpdateVcbPhase0() Successfully set up a 2.0x style VAT\n"));
  797. }
  798. else {
  799. //
  800. // UDF 1.5 style VAT. Bias from the back by the previous VAT pointer and the
  801. // regid itself.
  802. //
  803. Offset.QuadPart = Vcb->VatFcb->FileSize.QuadPart - UDF_CDUDF_TRAILING_DATA_SIZE;
  804. CcMapData( Vcb->VatFcb->FileObject,
  805. &Offset,
  806. sizeof(REGID),
  807. TRUE,
  808. &Bcb,
  809. &RegId );
  810. if (!UdfUdfIdentifierContained( RegId,
  811. &UdfVatTableIdentifier,
  812. UDF_VERSION_150,
  813. UDF_VERSION_150,
  814. OSCLASS_INVALID,
  815. OSIDENTIFIER_INVALID )) {
  816. //
  817. // Oh well, no go here.
  818. //
  819. DebugTrace((0, Dbg, "UdfUpdateVcbPhase0() VAT Regid didn't verify\n"));
  820. continue;
  821. }
  822. Vcb->OffsetToFirstVATEntry = 0;
  823. Vcb->VATEntryCount = (Vcb->VatFcb->FileSize.LowPart - UDF_CDUDF_TRAILING_DATA_SIZE) / sizeof(ULONG);
  824. DebugTrace((0, Dbg, "UdfUpdateVcbPhase0() Successfully set up a 1.50 style VAT\n"));
  825. }
  826. //
  827. // Found a valid one.
  828. //
  829. #ifdef SEARCH_FOR_HIGHEST_VALID_VAT
  830. //
  831. // But we must continue until a read fails, and use the highest block
  832. // containig a valid VAT that we find. Otherwise we may pick up an old
  833. // VAT by mistake.
  834. //
  835. LastValidVatLbn = Lbn;
  836. LastValidVatOffset = Vcb->OffsetToFirstVATEntry;
  837. LastValidVatCount = Vcb->VATEntryCount;
  838. #else
  839. break;
  840. #endif
  841. }
  842. //
  843. // If we didn't find anything ...
  844. //
  845. #ifdef SEARCH_FOR_HIGHEST_VALID_VAT
  846. if ((ThisPass == 4) || (0 == LastValidVatLbn)) {
  847. #else
  848. if (ThisPass == 4) {
  849. #endif
  850. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... and so we didn't find a VAT!\n" ));
  851. UdfRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
  852. }
  853. #ifdef SEARCH_FOR_HIGHEST_VALID_VAT
  854. //
  855. // Switch back to the last valid VAT, if we tried blocks following it.
  856. //
  857. if (Lbn != LastValidVatLbn) {
  858. DebugTrace(( 0, Dbg,"Reverting to last valid VAT @ PSN 0x%x\n", LastValidVatLbn));
  859. Offset.QuadPart = LlBytesFromSectors( Vcb, LastValidVatLbn + Vcb->Pcb->Partition[Reference].Physical.Start);
  860. if (!NT_SUCCESS( UdfReadSectors( IrpContext,
  861. Offset.QuadPart,
  862. UdfRawReadSize( Vcb, BlockSize( Vcb )),
  863. TRUE,
  864. VatIcb,
  865. Vcb->TargetDeviceObject ))) {
  866. DebugTrace(( 0, Dbg, "Failed to re-read previous valid VAT sector\n" ));
  867. UdfRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
  868. }
  869. UdfUnpinData( IrpContext, &Bcb );
  870. UdfCreateOrResetVatAndVmcbStreams( IrpContext,
  871. Vcb,
  872. LastValidVatLbn,
  873. VatIcb,
  874. Reference);
  875. Vcb->OffsetToFirstVATEntry = LastValidVatOffset;
  876. Vcb->VATEntryCount = LastValidVatCount;
  877. }
  878. #endif
  879. //
  880. // Go find the virtual reference so we can further update the Pcb
  881. // with information from the VAT.
  882. //
  883. for (Reference = 0;
  884. Reference < Vcb->Pcb->Partitions;
  885. Reference++) {
  886. if (Vcb->Pcb->Partition[Reference].Type == Virtual) {
  887. break;
  888. }
  889. }
  890. ASSERT( Reference < Vcb->Pcb->Partitions );
  891. //
  892. // We note the length so we can easily do bounds checking for
  893. // virtual mappings.
  894. //
  895. Offset.QuadPart = (Vcb->VatFcb->FileSize.QuadPart -
  896. UDF_CDUDF_TRAILING_DATA_SIZE) / sizeof(ULONG);
  897. ASSERT( Offset.HighPart == 0 );
  898. Vcb->Pcb->Partition[Reference].Virtual.Length = Offset.LowPart;
  899. DebugTrace(( 0, Dbg, "UdfUpdateVcbPhase0, ... got it!\n" ));
  900. }
  901. }
  902. finally {
  903. DebugUnwind( "UdfUpdateVcbPhase0" );
  904. UdfUnpinData( IrpContext, &Bcb );
  905. if (UnlockVcb) { UdfUnlockVcb( IrpContext, Vcb ); }
  906. if (VatIcb) { ExFreePool( VatIcb ); }
  907. }
  908. DebugTrace(( -1, Dbg, "UdfUpdateVcbPhase0 -> VOID\n" ));
  909. }
  910. VOID
  911. UdfUpdateVcbPhase1 (
  912. IN PIRP_CONTEXT IrpContext,
  913. IN OUT PVCB Vcb,
  914. IN PNSR_FSD Fsd
  915. )
  916. /*++
  917. Routine Description:
  918. This routine is called to perform the final initialization of a Vcb and Vpb
  919. from the volume descriptors on the disk.
  920. Arguments:
  921. Vcb - Vcb for the volume being mounted. We have already done phase 0.
  922. Fsd - The fileset descriptor for this volume.
  923. Return Value:
  924. None
  925. --*/
  926. {
  927. ICB_SEARCH_CONTEXT IcbContext;
  928. LONGLONG FileId = 0;
  929. PFCB Fcb;
  930. BOOLEAN UnlockVcb = FALSE;
  931. BOOLEAN UnlockFcb = FALSE;
  932. BOOLEAN CleanupIcbContext = FALSE;
  933. ULONG Reference;
  934. ULONG BoundSector = 0;
  935. PAGED_CODE();
  936. //
  937. // Check input.
  938. //
  939. ASSERT_IRP_CONTEXT( IrpContext );
  940. ASSERT_VCB( Vcb );
  941. DebugTrace(( +1, Dbg, "UdfUpdateVcbPhase1, Vcb %08x Fsd %08x\n", Vcb, Fsd ));
  942. //
  943. // Use a try-finally to facilitate cleanup.
  944. //
  945. try {
  946. //
  947. // Do the final internal Fcb's and other Vcb fields.
  948. //
  949. //////////////////
  950. //
  951. // Create the root index and reference it in the Vcb.
  952. //
  953. //////////////////
  954. UdfLockVcb( IrpContext, Vcb );
  955. UnlockVcb = TRUE;
  956. Vcb->RootIndexFcb = UdfCreateFcb( IrpContext,
  957. *((PFILE_ID) &FileId),
  958. UDFS_NTC_FCB_INDEX,
  959. NULL );
  960. UdfIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 );
  961. UdfUnlockVcb( IrpContext, Vcb );
  962. UnlockVcb = FALSE;
  963. //
  964. // Create the File id by hand for this Fcb.
  965. //
  966. UdfSetFidFromLbAddr( Vcb->RootIndexFcb->FileId, Fsd->IcbRoot.Start );
  967. UdfSetFidDirectory( Vcb->RootIndexFcb->FileId );
  968. Vcb->RootIndexFcb->RootExtentLength = Fsd->IcbRoot.Length.Length;
  969. //
  970. // Get the direct entry for the root directory and initialize
  971. // the Fcb from it.
  972. //
  973. UdfInitializeIcbContextFromFcb( IrpContext,
  974. &IcbContext,
  975. Vcb->RootIndexFcb );
  976. CleanupIcbContext = TRUE;
  977. UdfLookupActiveIcb( IrpContext,
  978. &IcbContext,
  979. Vcb->RootIndexFcb->RootExtentLength );
  980. //
  981. // Note: the vcb lock here is just to satisfy sanity checks in function.
  982. //
  983. UdfLockVcb( IrpContext, Vcb );
  984. UnlockVcb = TRUE;
  985. UdfInitializeFcbFromIcbContext( IrpContext,
  986. Vcb->RootIndexFcb,
  987. &IcbContext,
  988. NULL);
  989. UdfUnlockVcb( IrpContext, Vcb );
  990. UnlockVcb = FALSE;
  991. UdfCleanupIcbContext( IrpContext, &IcbContext );
  992. CleanupIcbContext = FALSE;
  993. //
  994. // Create the stream file for the root directory.
  995. //
  996. UdfCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb );
  997. //////////////////
  998. //
  999. // Now do the volume dasd Fcb. Create this and reference it in the
  1000. // Vcb.
  1001. //
  1002. //////////////////
  1003. UdfLockVcb( IrpContext, Vcb );
  1004. UnlockVcb = TRUE;
  1005. Vcb->VolumeDasdFcb = UdfCreateFcb( IrpContext,
  1006. *((PFILE_ID) &FileId),
  1007. UDFS_NTC_FCB_DATA,
  1008. NULL );
  1009. UdfIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 );
  1010. UdfUnlockVcb( IrpContext, Vcb );
  1011. UnlockVcb = FALSE;
  1012. Fcb = Vcb->VolumeDasdFcb;
  1013. UdfLockFcb( IrpContext, Fcb );
  1014. UnlockFcb = TRUE;
  1015. //
  1016. // If we were unable to determine a last sector on the media, walk the Pcb and guess
  1017. // that it is probably OK to think of the last sector of the last partition as The
  1018. // Last Sector. Note that we couldn't do this before since the notion of a last
  1019. // sector has significance at mount time, if it had been possible to find one.
  1020. //
  1021. for ( Reference = 0;
  1022. Reference < Vcb->Pcb->Partitions;
  1023. Reference++ ) {
  1024. if (Vcb->Pcb->Partition[Reference].Type == Physical &&
  1025. Vcb->Pcb->Partition[Reference].Physical.Start +
  1026. Vcb->Pcb->Partition[Reference].Physical.Length > BoundSector) {
  1027. BoundSector = Vcb->Pcb->Partition[Reference].Physical.Start +
  1028. Vcb->Pcb->Partition[Reference].Physical.Length;
  1029. }
  1030. }
  1031. //
  1032. // Note that we cannot restrict the bound by the "physical" bound discovered
  1033. // eariler. This is because the MSF format of the TOC request we send is only
  1034. // capable of representing about 2.3gb, and a lot of media we will be on that
  1035. // responds to TOCs will be quite a bit larger - ex: DVD.
  1036. //
  1037. // This, of course, barring proper means of discovering media bounding, prohibits
  1038. // the possibility of having UDF virtual partitions on DVD-R.
  1039. //
  1040. //
  1041. // Build the mapping from [0, Bound). We have to initialize the Mcb by hand since
  1042. // this is usually left to when we lift retrieval information from an Icb in
  1043. // UdfInitializeAllocations.
  1044. //
  1045. UdfInitializeFcbMcb( Fcb );
  1046. FsRtlAddLargeMcbEntry( &Fcb->Mcb,
  1047. (LONGLONG) 0,
  1048. (LONGLONG) 0,
  1049. (LONGLONG) BoundSector );
  1050. Fcb->FileSize.QuadPart += LlBytesFromSectors( Vcb, BoundSector );
  1051. Fcb->AllocationSize.QuadPart =
  1052. Fcb->ValidDataLength.QuadPart = Fcb->FileSize.QuadPart;
  1053. UdfUnlockFcb( IrpContext, Fcb );
  1054. UnlockFcb = FALSE;
  1055. SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED );
  1056. //
  1057. // Point to the file resource.
  1058. //
  1059. Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource;
  1060. Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY;
  1061. } finally {
  1062. DebugUnwind( "UdfUpdateVcbPhase1" );
  1063. if (CleanupIcbContext) { UdfCleanupIcbContext( IrpContext, &IcbContext ); }
  1064. if (UnlockFcb) { UdfUnlockFcb( IrpContext, Fcb ); }
  1065. if (UnlockVcb) { UdfUnlockVcb( IrpContext, Vcb ); }
  1066. }
  1067. DebugTrace(( -1, Dbg, "UdfUpdateVcbPhase1 -> VOID\n" ));
  1068. return;
  1069. }
  1070. VOID
  1071. UdfDeleteVcb (
  1072. IN PIRP_CONTEXT IrpContext,
  1073. IN OUT PVCB Vcb
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. This routine is called to delete a Vcb which failed mount or has been
  1078. dismounted. The dismount code should have already removed all of the
  1079. open Fcb's. We do nothing here but clean up other auxilary structures.
  1080. Arguments:
  1081. Vcb - Vcb to delete.
  1082. Return Value:
  1083. None
  1084. --*/
  1085. {
  1086. PAGED_CODE();
  1087. ASSERT_EXCLUSIVE_UDFDATA;
  1088. ASSERT_EXCLUSIVE_VCB( Vcb );
  1089. //
  1090. // Chuck the backpocket Vpb we kept just in case.
  1091. //
  1092. if (Vcb->SwapVpb) {
  1093. ExFreePool( Vcb->SwapVpb );
  1094. }
  1095. //
  1096. // If there is a Vpb then we must delete it ourselves.
  1097. //
  1098. if (Vcb->Vpb != NULL) {
  1099. UdfFreePool( &Vcb->Vpb );
  1100. }
  1101. //
  1102. // Drop the Pcb.
  1103. //
  1104. if (Vcb->Pcb != NULL) {
  1105. UdfDeletePcb( Vcb->Pcb );
  1106. }
  1107. //
  1108. // Dereference our target if we haven't already done so.
  1109. //
  1110. if (Vcb->TargetDeviceObject != NULL) {
  1111. ObDereferenceObject( Vcb->TargetDeviceObject );
  1112. }
  1113. //
  1114. // Remove this entry from the global queue.
  1115. //
  1116. RemoveEntryList( &Vcb->VcbLinks );
  1117. //
  1118. // Delete resources.
  1119. //
  1120. ExDeleteResourceLite( &Vcb->VcbResource );
  1121. ExDeleteResourceLite( &Vcb->FileResource );
  1122. ExDeleteResourceLite( &Vcb->VmcbMappingResource);
  1123. //
  1124. // Uninitialize the notify structures.
  1125. //
  1126. if (Vcb->NotifySync != NULL) {
  1127. FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
  1128. }
  1129. //
  1130. // Now delete the volume device object.
  1131. //
  1132. IoDeleteDevice( (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb,
  1133. VOLUME_DEVICE_OBJECT,
  1134. Vcb ));
  1135. return;
  1136. }
  1137. PIRP_CONTEXT
  1138. UdfCreateIrpContext (
  1139. IN PIRP Irp,
  1140. IN BOOLEAN Wait
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. This routine is called to initialize an IrpContext for the current
  1145. UDFS request. We allocate the structure and then initialize it from
  1146. the given Irp.
  1147. Arguments:
  1148. Irp - Irp for this request.
  1149. Wait - TRUE if this request is synchronous, FALSE otherwise.
  1150. Return Value:
  1151. PIRP_CONTEXT - Allocated IrpContext.
  1152. --*/
  1153. {
  1154. PIRP_CONTEXT NewIrpContext = NULL;
  1155. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1156. BOOLEAN IsFsDo = FALSE;
  1157. PAGED_CODE();
  1158. IsFsDo = UdfDeviceIsFsDo( IrpSp->DeviceObject);
  1159. //
  1160. // The only operations a filesystem device object should ever receive
  1161. // are create/teardown of fsdo handles and operations which do not
  1162. // occur in the context of fileobjects (i.e., mount).
  1163. //
  1164. if (IsFsDo) {
  1165. if (IrpSp->FileObject != NULL &&
  1166. IrpSp->MajorFunction != IRP_MJ_CREATE &&
  1167. IrpSp->MajorFunction != IRP_MJ_CLEANUP &&
  1168. IrpSp->MajorFunction != IRP_MJ_CLOSE) {
  1169. ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
  1170. }
  1171. ASSERT( IrpSp->FileObject != NULL ||
  1172. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  1173. IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
  1174. IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) ||
  1175. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  1176. IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ||
  1177. IrpSp->MajorFunction == IRP_MJ_SHUTDOWN );
  1178. }
  1179. NewIrpContext = ExAllocateFromNPagedLookasideList( &UdfIrpContextLookasideList );
  1180. RtlZeroMemory( NewIrpContext, sizeof( IRP_CONTEXT ));
  1181. //
  1182. // Set the proper node type code and node byte size
  1183. //
  1184. NewIrpContext->NodeTypeCode = UDFS_NTC_IRP_CONTEXT;
  1185. NewIrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
  1186. //
  1187. // Set the originating Irp field
  1188. //
  1189. NewIrpContext->Irp = Irp;
  1190. //
  1191. // Copy RealDevice for workque algorithms. We will update this in the Mount or
  1192. // Verify since they have no file objects to use here.
  1193. //
  1194. if (IrpSp->FileObject != NULL) {
  1195. NewIrpContext->RealDevice = IrpSp->FileObject->DeviceObject;
  1196. }
  1197. //
  1198. // This may be one of our filesystem device objects. In that case don't
  1199. // initialize the Vcb field.
  1200. //
  1201. if (!IsFsDo) {
  1202. NewIrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
  1203. }
  1204. //
  1205. // Major/Minor Function codes
  1206. //
  1207. NewIrpContext->MajorFunction = IrpSp->MajorFunction;
  1208. NewIrpContext->MinorFunction = IrpSp->MinorFunction;
  1209. //
  1210. // Set the wait parameter
  1211. //
  1212. if (Wait) {
  1213. SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1214. } else {
  1215. SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  1216. }
  1217. //
  1218. // return and tell the caller
  1219. //
  1220. return NewIrpContext;
  1221. }
  1222. VOID
  1223. UdfCleanupIrpContext (
  1224. IN PIRP_CONTEXT IrpContext,
  1225. IN BOOLEAN Post
  1226. )
  1227. /*++
  1228. Routine Description:
  1229. This routine is called to cleanup and possibly deallocate the Irp Context.
  1230. If the request is being posted or this Irp Context is possibly on the
  1231. stack then we only cleanup any auxilary structures.
  1232. Arguments:
  1233. Post - TRUE if we are posting this request, FALSE if we are deleting
  1234. or retrying this in the current thread.
  1235. Return Value:
  1236. None.
  1237. --*/
  1238. {
  1239. PAGED_CODE();
  1240. ASSERT_IRP_CONTEXT( IrpContext );
  1241. //
  1242. // If we aren't doing more processing then deallocate this as appropriate.
  1243. //
  1244. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING)) {
  1245. //
  1246. // If this context is the top level UDFS context then we need to
  1247. // restore the top level thread context.
  1248. //
  1249. if (IrpContext->ThreadContext != NULL) {
  1250. UdfRestoreThreadContext( IrpContext );
  1251. }
  1252. //
  1253. // Deallocate the Io context if allocated.
  1254. //
  1255. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
  1256. UdfFreeIoContext( IrpContext->IoContext );
  1257. }
  1258. //
  1259. // Deallocate the IrpContext if not from the stack.
  1260. //
  1261. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK )) {
  1262. ExFreeToNPagedLookasideList( &UdfIrpContextLookasideList, IrpContext );
  1263. }
  1264. //
  1265. // Clear the appropriate flags.
  1266. //
  1267. } else if (Post) {
  1268. //
  1269. // If this context is the top level UDFS context then we need to
  1270. // restore the top level thread context.
  1271. //
  1272. if (IrpContext->ThreadContext != NULL) {
  1273. UdfRestoreThreadContext( IrpContext );
  1274. }
  1275. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST );
  1276. } else {
  1277. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY );
  1278. }
  1279. return;
  1280. }
  1281. VOID
  1282. UdfInitializeStackIrpContext (
  1283. OUT PIRP_CONTEXT IrpContext,
  1284. IN PIRP_CONTEXT_LITE IrpContextLite
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This routine is called to initialize an IrpContext for the current
  1289. UDFS request. The IrpContext is on the stack and we need to initialize
  1290. it for the current request. The request is a close operation.
  1291. Arguments:
  1292. IrpContext - IrpContext to initialize.
  1293. IrpContextLite - Structure containing the details of this request.
  1294. Return Value:
  1295. None
  1296. --*/
  1297. {
  1298. PAGED_CODE();
  1299. ASSERT_IRP_CONTEXT_LITE( IrpContextLite );
  1300. //
  1301. // Zero and then initialize the structure.
  1302. //
  1303. RtlZeroMemory( IrpContext, sizeof( IRP_CONTEXT ));
  1304. //
  1305. // Set the proper node type code and node byte size
  1306. //
  1307. IrpContext->NodeTypeCode = UDFS_NTC_IRP_CONTEXT;
  1308. IrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
  1309. //
  1310. // Note that this is from the stack.
  1311. //
  1312. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK );
  1313. //
  1314. // Copy RealDevice for workque algorithms.
  1315. //
  1316. IrpContext->RealDevice = IrpContextLite->RealDevice;
  1317. //
  1318. // The Vcb is found in the Fcb.
  1319. //
  1320. IrpContext->Vcb = IrpContextLite->Fcb->Vcb;
  1321. //
  1322. // Major/Minor Function codes
  1323. //
  1324. IrpContext->MajorFunction = IRP_MJ_CLOSE;
  1325. //
  1326. // Set the wait parameter
  1327. //
  1328. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1329. return;
  1330. }
  1331. VOID
  1332. UdfTeardownStructures (
  1333. IN PIRP_CONTEXT IrpContext,
  1334. IN PFCB StartingFcb,
  1335. IN BOOLEAN Recursive,
  1336. OUT PBOOLEAN RemovedStartingFcb
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. This routine is used to walk from some starting point in the Fcb tree towards
  1341. the root. It will remove the Fcb and continue walking up the tree until
  1342. it finds a point where we can't remove an Fcb.
  1343. We look at the following fields in the Fcb to determine whether we can
  1344. remove this.
  1345. 1 - Handle count must be zero.
  1346. 2 - If directory then only the only reference can be for a stream file.
  1347. 3 - Reference count must either be zero or go to zero here.
  1348. We return immediately if we are recursively entering this routine.
  1349. Arguments:
  1350. StartingFcb - This is the Fcb node in the tree to begin with. This Fcb
  1351. must currently be acquired exclusively.
  1352. Recursive - Indicates if this call is an intentional recursion.
  1353. RemovedStartingFcb - Address to store whether we removed the starting Fcb.
  1354. Return Value:
  1355. None
  1356. --*/
  1357. {
  1358. PVCB Vcb = StartingFcb->Vcb;
  1359. PFCB CurrentFcb = StartingFcb;
  1360. BOOLEAN AcquiredCurrentFcb = FALSE;
  1361. PFCB ParentFcb = NULL;
  1362. PLCB Lcb;
  1363. PLIST_ENTRY ListLinks;
  1364. BOOLEAN Abort = FALSE;
  1365. BOOLEAN Removed;
  1366. PAGED_CODE();
  1367. //
  1368. // Check input.
  1369. //
  1370. ASSERT_IRP_CONTEXT( IrpContext );
  1371. ASSERT_FCB( StartingFcb );
  1372. *RemovedStartingFcb = FALSE;
  1373. //
  1374. // If this is not an intentionally recursive call we need to check if this
  1375. // is a layered close and we're already in another instance of teardown.
  1376. //
  1377. DebugTrace(( +1, Dbg,
  1378. "UdfTeardownStructures, StartingFcb %08x %s\n",
  1379. StartingFcb,
  1380. ( Recursive? "Recursive" : "Flat" )));
  1381. if (!Recursive) {
  1382. //
  1383. // If this is a recursive call to TearDownStructures we return immediately
  1384. // doing no operation.
  1385. //
  1386. if (FlagOn( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN )) {
  1387. return;
  1388. }
  1389. SetFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
  1390. }
  1391. //
  1392. // Use a try-finally to safely clear the top-level field.
  1393. //
  1394. try {
  1395. //
  1396. // Loop until we find an Fcb we can't remove.
  1397. //
  1398. do {
  1399. //
  1400. // See if there is an internal stream we should delete.
  1401. // Only do this if it is the last reference on the Fcb.
  1402. //
  1403. if ((SafeNodeType( CurrentFcb ) != UDFS_NTC_FCB_DATA) &&
  1404. (CurrentFcb->FcbUserReference == 0) &&
  1405. (CurrentFcb->FileObject != NULL)) {
  1406. //
  1407. // Go ahead and delete the stream file object.
  1408. //
  1409. UdfDeleteInternalStream( IrpContext, CurrentFcb );
  1410. }
  1411. //
  1412. // If the reference count is non-zero then break.
  1413. //
  1414. if (CurrentFcb->FcbReference != 0) {
  1415. break;
  1416. }
  1417. //
  1418. // It looks like we have a candidate for removal here. We
  1419. // will need to walk the list of prefixes and delete them
  1420. // from their parents. If it turns out that we have multiple
  1421. // parents of this Fcb, we are going to recursively teardown
  1422. // on each of these.
  1423. //
  1424. for ( ListLinks = CurrentFcb->ParentLcbQueue.Flink;
  1425. ListLinks != &CurrentFcb->ParentLcbQueue; ) {
  1426. Lcb = CONTAINING_RECORD( ListLinks, LCB, ChildFcbLinks );
  1427. ASSERT_LCB( Lcb );
  1428. //
  1429. // We advance the pointer now because we will be toasting this guy,
  1430. // invalidating whatever is here.
  1431. //
  1432. ListLinks = ListLinks->Flink;
  1433. //
  1434. // We may have multiple parents through hard links. If the previous parent we
  1435. // dealt with is not the parent of this new Lcb, lets do some work.
  1436. //
  1437. if (ParentFcb != Lcb->ParentFcb) {
  1438. //
  1439. // We need to deal with the previous parent. It may now be the case that
  1440. // we deleted the last child reference and it wants to go away at this point.
  1441. //
  1442. if (ParentFcb) {
  1443. //
  1444. // It should never be the case that we have to recurse more than one level on
  1445. // any teardown since no cross-linkage of directories is possible.
  1446. //
  1447. ASSERT( !Recursive );
  1448. UdfTeardownStructures( IrpContext, ParentFcb, TRUE, &Removed );
  1449. if (!Removed) {
  1450. UdfReleaseFcb( IrpContext, ParentFcb );
  1451. }
  1452. }
  1453. //
  1454. // Get this new parent Fcb to work on.
  1455. //
  1456. ParentFcb = Lcb->ParentFcb;
  1457. UdfAcquireFcbExclusive( IrpContext, ParentFcb, FALSE );
  1458. }
  1459. //
  1460. // Lock the Vcb so we can look at references.
  1461. //
  1462. UdfLockVcb( IrpContext, Vcb );
  1463. //
  1464. // Now check that the reference counts on the Lcb are zero.
  1465. //
  1466. if ( Lcb->Reference != 0 ) {
  1467. //
  1468. // A create is interested in getting in here, so we should
  1469. // stop right now.
  1470. //
  1471. UdfUnlockVcb( IrpContext, Vcb );
  1472. UdfReleaseFcb( IrpContext, ParentFcb );
  1473. Abort = TRUE;
  1474. break;
  1475. }
  1476. //
  1477. // Now remove this prefix and drop the references to the parent.
  1478. //
  1479. ASSERT( Lcb->ChildFcb == CurrentFcb );
  1480. ASSERT( Lcb->ParentFcb == ParentFcb );
  1481. DebugTrace(( +0, Dbg,
  1482. "UdfTeardownStructures, Lcb %08x P %08x <-> C %08x Vcb %d/%d PFcb %d/%d CFcb %d/%d\n",
  1483. Lcb,
  1484. ParentFcb,
  1485. CurrentFcb,
  1486. Vcb->VcbReference,
  1487. Vcb->VcbUserReference,
  1488. ParentFcb->FcbReference,
  1489. ParentFcb->FcbUserReference,
  1490. CurrentFcb->FcbReference,
  1491. CurrentFcb->FcbUserReference ));
  1492. UdfRemovePrefix( IrpContext, Lcb );
  1493. UdfDecrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
  1494. DebugTrace(( +0, Dbg,
  1495. "UdfTeardownStructures, Vcb %d/%d PFcb %d/%d\n",
  1496. Vcb->VcbReference,
  1497. Vcb->VcbUserReference,
  1498. ParentFcb->FcbReference,
  1499. ParentFcb->FcbUserReference ));
  1500. UdfUnlockVcb( IrpContext, Vcb );
  1501. }
  1502. //
  1503. // Now really leave if we have to.
  1504. //
  1505. if (Abort) {
  1506. break;
  1507. }
  1508. //
  1509. // Now that we have removed all of the prefixes of this Fcb we can make the final check.
  1510. // Lock the Vcb again so we can inspect the child's references.
  1511. //
  1512. UdfLockVcb( IrpContext, Vcb );
  1513. if (CurrentFcb->FcbReference != 0) {
  1514. DebugTrace(( +0, Dbg,
  1515. "UdfTeardownStructures, saving Fcb %08x %d/%d\n",
  1516. CurrentFcb,
  1517. CurrentFcb->FcbReference,
  1518. CurrentFcb->FcbUserReference ));
  1519. //
  1520. // Nope, nothing more to do. Stop right now.
  1521. //
  1522. UdfUnlockVcb( IrpContext, Vcb );
  1523. if (ParentFcb != NULL) {
  1524. UdfReleaseFcb( IrpContext, ParentFcb );
  1525. }
  1526. break;
  1527. }
  1528. //
  1529. // This Fcb is toast. Remove it from the Fcb Table as appropriate and delete.
  1530. //
  1531. if (FlagOn( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE )) {
  1532. UdfDeleteFcbTable( IrpContext, CurrentFcb );
  1533. ClearFlag( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE );
  1534. }
  1535. //
  1536. // Unlock the Vcb but hold the parent in order to walk up
  1537. // the tree.
  1538. //
  1539. DebugTrace(( +0, Dbg,
  1540. "UdfTeardownStructures, toasting Fcb %08x %d/%d\n",
  1541. CurrentFcb,
  1542. CurrentFcb->FcbReference,
  1543. CurrentFcb->FcbUserReference ));
  1544. UdfUnlockVcb( IrpContext, Vcb );
  1545. UdfDeleteFcb( IrpContext, CurrentFcb );
  1546. //
  1547. // Move to the parent Fcb.
  1548. //
  1549. CurrentFcb = ParentFcb;
  1550. ParentFcb = NULL;
  1551. AcquiredCurrentFcb = TRUE;
  1552. } while (CurrentFcb != NULL);
  1553. } finally {
  1554. //
  1555. // Release the current Fcb if we have acquired it.
  1556. //
  1557. if (AcquiredCurrentFcb && (CurrentFcb != NULL)) {
  1558. UdfReleaseFcb( IrpContext, CurrentFcb );
  1559. }
  1560. //
  1561. // Clear the teardown flag.
  1562. //
  1563. if (!Recursive) {
  1564. ClearFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
  1565. }
  1566. }
  1567. *RemovedStartingFcb = (CurrentFcb != StartingFcb);
  1568. DebugTrace(( -1, Dbg,
  1569. "UdfTeardownStructures, RemovedStartingFcb -> %c\n",
  1570. ( *RemovedStartingFcb? 'T' : 'F' )));
  1571. return;
  1572. }
  1573. PFCB
  1574. UdfLookupFcbTable (
  1575. IN PIRP_CONTEXT IrpContext,
  1576. IN PVCB Vcb,
  1577. IN FILE_ID FileId
  1578. )
  1579. /*++
  1580. Routine Description:
  1581. This routine will look through the Fcb table looking for a matching
  1582. entry.
  1583. Arguments:
  1584. Vcb - Vcb for this volume.
  1585. FileId - This is the key value to use for the search.
  1586. Return Value:
  1587. PFCB - A pointer to the matching entry or NULL otherwise.
  1588. --*/
  1589. {
  1590. FCB_TABLE_ELEMENT Key;
  1591. PFCB_TABLE_ELEMENT Hit;
  1592. PFCB ReturnFcb = NULL;
  1593. PAGED_CODE();
  1594. Key.FileId = FileId;
  1595. Hit = (PFCB_TABLE_ELEMENT) RtlLookupElementGenericTable( &Vcb->FcbTable, &Key );
  1596. if (Hit != NULL) {
  1597. ReturnFcb = Hit->Fcb;
  1598. }
  1599. return ReturnFcb;
  1600. UNREFERENCED_PARAMETER( IrpContext );
  1601. }
  1602. PFCB
  1603. UdfGetNextFcb (
  1604. IN PIRP_CONTEXT IrpContext,
  1605. IN PVCB Vcb,
  1606. IN PVOID *RestartKey
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. This routine will enumerate through all of the Fcb's in the Fcb table.
  1611. Arguments:
  1612. Vcb - Vcb for this volume.
  1613. RestartKey - This value is used by the table package to maintain
  1614. its position in the enumeration. It is initialized to NULL
  1615. for the first search.
  1616. Return Value:
  1617. PFCB - A pointer to the next fcb or NULL if the enumeration is
  1618. completed
  1619. --*/
  1620. {
  1621. PFCB Fcb;
  1622. PAGED_CODE();
  1623. Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey );
  1624. if (Fcb != NULL) {
  1625. Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb;
  1626. }
  1627. return Fcb;
  1628. }
  1629. PFCB
  1630. UdfCreateFcb (
  1631. IN PIRP_CONTEXT IrpContext,
  1632. IN FILE_ID FileId,
  1633. IN NODE_TYPE_CODE NodeTypeCode,
  1634. OUT PBOOLEAN FcbExisted OPTIONAL
  1635. )
  1636. /*++
  1637. Routine Description:
  1638. This routine is called to find the Fcb for the given FileId. We will
  1639. look this up first in the Fcb table and if not found we will create
  1640. an Fcb. We don't initialize it or insert it into the FcbTable in this
  1641. routine.
  1642. This routine is called while the Vcb is locked.
  1643. Arguments:
  1644. FileId - This is the Id for the target Fcb.
  1645. NodeTypeCode - Node type for this Fcb if we need to create.
  1646. FcbExisted - If specified, we store whether the Fcb existed.
  1647. Return Value:
  1648. PFCB - The Fcb found in the table or created if needed.
  1649. --*/
  1650. {
  1651. PFCB NewFcb;
  1652. BOOLEAN LocalFcbExisted;
  1653. PAGED_CODE();
  1654. //
  1655. // Use the local boolean if one was not passed in.
  1656. //
  1657. if (!ARGUMENT_PRESENT( FcbExisted )) {
  1658. FcbExisted = &LocalFcbExisted;
  1659. }
  1660. //
  1661. // Maybe this is already in the table.
  1662. //
  1663. NewFcb = UdfLookupFcbTable( IrpContext, IrpContext->Vcb, FileId );
  1664. //
  1665. // If not then create the Fcb is requested by our caller.
  1666. //
  1667. if (NewFcb == NULL) {
  1668. //
  1669. // Use a try-finally for cleanup
  1670. //
  1671. try {
  1672. //
  1673. // Allocate and initialize the structure depending on the
  1674. // type code.
  1675. //
  1676. switch (NodeTypeCode) {
  1677. case UDFS_NTC_FCB_INDEX:
  1678. NewFcb = UdfAllocateFcbIndex( IrpContext );
  1679. RtlZeroMemory( NewFcb, SIZEOF_FCB_INDEX );
  1680. NewFcb->NodeByteSize = SIZEOF_FCB_INDEX;
  1681. break;
  1682. case UDFS_NTC_FCB_DATA :
  1683. NewFcb = UdfAllocateFcbData( IrpContext );
  1684. RtlZeroMemory( NewFcb, SIZEOF_FCB_DATA );
  1685. NewFcb->NodeByteSize = SIZEOF_FCB_DATA;
  1686. break;
  1687. default:
  1688. UdfBugCheck( 0, 0, 0 );
  1689. }
  1690. //
  1691. // Now do the common initialization.
  1692. //
  1693. NewFcb->NodeTypeCode = NodeTypeCode;
  1694. NewFcb->Vcb = IrpContext->Vcb;
  1695. NewFcb->FileId = FileId;
  1696. InitializeListHead( &NewFcb->ParentLcbQueue );
  1697. InitializeListHead( &NewFcb->ChildLcbQueue );
  1698. //
  1699. // Now create the non-paged section object.
  1700. //
  1701. NewFcb->FcbNonpaged = UdfCreateFcbNonPaged( IrpContext );
  1702. //
  1703. // Initialize Advanced FCB Header fields
  1704. //
  1705. ExInitializeFastMutex( &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
  1706. FsRtlSetupAdvancedHeader( &NewFcb->Header,
  1707. &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
  1708. *FcbExisted = FALSE;
  1709. } finally {
  1710. DebugUnwind( "UdfCreateFcb" );
  1711. if (AbnormalTermination()) {
  1712. UdfFreePool( &NewFcb );
  1713. }
  1714. }
  1715. } else {
  1716. *FcbExisted = TRUE;
  1717. }
  1718. return NewFcb;
  1719. }
  1720. VOID
  1721. UdfDeleteFcb (
  1722. IN PIRP_CONTEXT IrpContext,
  1723. IN PFCB Fcb
  1724. )
  1725. /*++
  1726. Routine Description:
  1727. This routine is called to cleanup and deallocate an Fcb. We know there
  1728. are no references remaining. We cleanup any auxilary structures and
  1729. deallocate this Fcb.
  1730. Arguments:
  1731. Fcb - This is the Fcb to deallcoate.
  1732. Return Value:
  1733. None
  1734. --*/
  1735. {
  1736. PVCB Vcb = NULL;
  1737. PAGED_CODE();
  1738. //
  1739. // Check inputs.
  1740. //
  1741. ASSERT_IRP_CONTEXT( IrpContext );
  1742. ASSERT_FCB( Fcb );
  1743. //
  1744. // Sanity check the counts and Lcb lists.
  1745. //
  1746. ASSERT( Fcb->FcbCleanup == 0 );
  1747. ASSERT( Fcb->FcbReference == 0 );
  1748. ASSERT( IsListEmpty( &Fcb->ChildLcbQueue ));
  1749. ASSERT( IsListEmpty( &Fcb->ParentLcbQueue ));
  1750. //
  1751. // Release any Filter Context structures associated with this FCB
  1752. //
  1753. FsRtlTeardownPerStreamContexts( &Fcb->Header );
  1754. //
  1755. // Start with the common structures.
  1756. //
  1757. UdfUninitializeFcbMcb( Fcb );
  1758. UdfDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged );
  1759. //
  1760. // Now do the type specific structures.
  1761. //
  1762. switch (Fcb->NodeTypeCode) {
  1763. case UDFS_NTC_FCB_INDEX:
  1764. ASSERT( Fcb->FileObject == NULL );
  1765. if (Fcb == Fcb->Vcb->RootIndexFcb) {
  1766. Vcb = Fcb->Vcb;
  1767. Vcb->RootIndexFcb = NULL;
  1768. } else if (Fcb == Fcb->Vcb->MetadataFcb) {
  1769. Vcb = Fcb->Vcb;
  1770. Vcb->MetadataFcb = NULL;
  1771. if (FlagOn( Vcb->VcbState, VCB_STATE_VMCB_INIT)) {
  1772. UdfUninitializeVmcb( &Vcb->Vmcb );
  1773. }
  1774. } else if (Fcb == Fcb->Vcb->VatFcb) {
  1775. Vcb = Fcb->Vcb;
  1776. Vcb->VatFcb = NULL;
  1777. }
  1778. UdfDeallocateFcbIndex( IrpContext, Fcb );
  1779. break;
  1780. case UDFS_NTC_FCB_DATA :
  1781. if (Fcb->FileLock != NULL) {
  1782. FsRtlFreeFileLock( Fcb->FileLock );
  1783. }
  1784. FsRtlUninitializeOplock( &Fcb->Oplock );
  1785. if (Fcb == Fcb->Vcb->VolumeDasdFcb) {
  1786. Vcb = Fcb->Vcb;
  1787. Vcb->VolumeDasdFcb = NULL;
  1788. }
  1789. UdfDeallocateFcbData( IrpContext, Fcb );
  1790. break;
  1791. }
  1792. //
  1793. // Decrement the Vcb reference count if this is a system
  1794. // Fcb.
  1795. //
  1796. if (Vcb != NULL) {
  1797. InterlockedDecrement( &Vcb->VcbReference );
  1798. InterlockedDecrement( &Vcb->VcbUserReference );
  1799. }
  1800. return;
  1801. }
  1802. VOID
  1803. UdfInitializeFcbFromIcbContext (
  1804. IN PIRP_CONTEXT IrpContext,
  1805. IN PFCB Fcb,
  1806. IN PICB_SEARCH_CONTEXT IcbContext,
  1807. IN PFCB ParentFcb OPTIONAL
  1808. )
  1809. /*++
  1810. Routine Description:
  1811. This routine is called to initialize an Fcb from a direct ICB. It should
  1812. only be called once in the lifetime of an Fcb and will fill in the Mcb
  1813. from the chained allocation descriptors of the ICB.
  1814. Arguments:
  1815. Fcb - The Fcb being initialized
  1816. IcbOontext - An search context containing the active direct ICB for the object
  1817. Return Value:
  1818. None.
  1819. --*/
  1820. {
  1821. EA_SEARCH_CONTEXT EaContext;
  1822. PICBFILE Icb;
  1823. PVCB Vcb;
  1824. PAGED_CODE();
  1825. //
  1826. // Check inputs
  1827. //
  1828. ASSERT_IRP_CONTEXT( IrpContext );
  1829. ASSERT_FCB( Fcb );
  1830. ASSERT( IcbContext->Active.View);
  1831. //
  1832. // Vcb should be locked, since we insert into the fcb table. Note we
  1833. // manipulate fcb fields with no lock here, since it's during the init. path.
  1834. //
  1835. ASSERT_LOCKED_VCB( Fcb->Vcb);
  1836. //
  1837. // Directly reference for convenience
  1838. //
  1839. Icb = IcbContext->Active.View;
  1840. Vcb = Fcb->Vcb;
  1841. ASSERT(IcbContext->IcbType == DESTAG_ID_NSR_FILE);
  1842. ASSERT((Icb->Destag.Ident == DESTAG_ID_NSR_FILE) || ((Icb->Destag.Ident == DESTAG_ID_NSR_EXT_FILE) && UdfExtendedFEAllowed( IrpContext->Vcb)));
  1843. //
  1844. // Check that the full indicated size of the direct entry is sane and
  1845. // that the length of the EA segment is correctly aligned. A direct
  1846. // entry is less than a single logical block in size.
  1847. //
  1848. if (LongOffset( FeEALength( Icb)) ||
  1849. ((FeEAsFieldOffset( Icb) + FeEALength( Icb) + FeAllocLength( Icb)) > BlockSize( IcbContext->Vcb ))
  1850. ) {
  1851. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  1852. }
  1853. //
  1854. // Verify that the types mesh and set state flags.
  1855. //
  1856. if (Fcb->NodeTypeCode == UDFS_NTC_FCB_INDEX && Icb->Icbtag.FileType == ICBTAG_FILE_T_DIRECTORY) {
  1857. SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY );
  1858. } else if (!( Fcb->NodeTypeCode == UDFS_NTC_FCB_DATA &&
  1859. ((ICBTAG_FILE_T_FILE == Icb->Icbtag.FileType) || (ICBTAG_FILE_T_REALTIME == Icb->Icbtag.FileType)))
  1860. ) {
  1861. //
  1862. // We don't allow access to anything except files or directores (no symlinks, devices...)
  1863. // Currently we treat realtime files as normal files.
  1864. //
  1865. UdfRaiseStatus( IrpContext, STATUS_ACCESS_DENIED );
  1866. }
  1867. SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_READONLY );
  1868. //
  1869. // Store away the on disc UDF file type, this may be useful later for symlinks etc.
  1870. //
  1871. Fcb->UdfIcbFileType = Icb->Icbtag.FileType;
  1872. //
  1873. // Initialize the common header in the Fcb.
  1874. //
  1875. Fcb->Resource = &Fcb->Vcb->FileResource;
  1876. //
  1877. // Size and lookup all allocations for this object.
  1878. //
  1879. Fcb->AllocationSize.QuadPart = LlBlockAlign( Vcb, Icb->InfoLength );
  1880. Fcb->FileSize.QuadPart =
  1881. Fcb->ValidDataLength.QuadPart = Icb->InfoLength;
  1882. UdfInitializeAllocations( IrpContext,
  1883. Fcb,
  1884. IcbContext,
  1885. (ParentFcb && FlagOn( ParentFcb->FcbState, FCB_STATE_ALLOW_ONEGIG_WORKAROUND))
  1886. ? TRUE : FALSE);
  1887. //
  1888. // Re-reference (may have been unmapped/remapped)
  1889. //
  1890. Icb = IcbContext->Active.View;
  1891. //
  1892. // Lift all of the timestamps for this guy.
  1893. //
  1894. try {
  1895. UdfUpdateTimestampsFromIcbContext( IrpContext,
  1896. IcbContext,
  1897. &Fcb->Timestamps );
  1898. }
  1899. except (UdfQueryDirExceptionFilter( GetExceptionInformation())) {
  1900. //
  1901. // In the interest of allowing users maximum data access on dodgy media,
  1902. // we will ignore corruption within the Eas, and just use a dummy
  1903. // timestamp for the create time. This may change if we being using
  1904. // Eas for anything critical.
  1905. //
  1906. IrpContext->ExceptionStatus = STATUS_SUCCESS;
  1907. Fcb->Timestamps.CreationTime = UdfCorruptFileTime;
  1908. }
  1909. //
  1910. // Pick up the link count.
  1911. //
  1912. Fcb->LinkCount = Icb->LinkCount;
  1913. //
  1914. // Link into the Fcb table. Someone else is responsible for the name linkage, which is
  1915. // all that remains. We also note that the Fcb is fully initialized at this point.
  1916. //
  1917. UdfInsertFcbTable( IrpContext, Fcb );
  1918. SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE | FCB_STATE_INITIALIZED );
  1919. }
  1920. PCCB
  1921. UdfCreateCcb (
  1922. IN PIRP_CONTEXT IrpContext,
  1923. IN PFCB Fcb,
  1924. IN PLCB Lcb OPTIONAL,
  1925. IN ULONG Flags
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. This routine is called to allocate and initialize the Ccb structure.
  1930. Arguments:
  1931. Fcb - This is the Fcb for the file being opened.
  1932. Lcb - This is the Lcb the Fcb is opened by.
  1933. Flags - User flags to set in this Ccb.
  1934. Return Value:
  1935. PCCB - Pointer to the created Ccb.
  1936. --*/
  1937. {
  1938. PCCB NewCcb;
  1939. PAGED_CODE();
  1940. //
  1941. // Check inputs.
  1942. //
  1943. ASSERT_IRP_CONTEXT( IrpContext );
  1944. ASSERT_FCB( Fcb );
  1945. ASSERT_OPTIONAL_LCB( Lcb );
  1946. //
  1947. // Allocate and initialize the structure.
  1948. //
  1949. NewCcb = UdfAllocateCcb( IrpContext );
  1950. //
  1951. // Set the proper node type code and node byte size
  1952. //
  1953. NewCcb->NodeTypeCode = UDFS_NTC_CCB;
  1954. NewCcb->NodeByteSize = sizeof( CCB );
  1955. //
  1956. // Set the initial value for the flags and Fcb/Lcb
  1957. //
  1958. NewCcb->Flags = Flags;
  1959. NewCcb->Fcb = Fcb;
  1960. NewCcb->Lcb = Lcb;
  1961. //
  1962. // Initialize the directory enumeration context
  1963. //
  1964. NewCcb->CurrentFileIndex = 0;
  1965. NewCcb->HighestReturnableFileIndex = 0;
  1966. NewCcb->SearchExpression.Length =
  1967. NewCcb->SearchExpression.MaximumLength = 0;
  1968. NewCcb->SearchExpression.Buffer = NULL;
  1969. return NewCcb;
  1970. }
  1971. VOID
  1972. UdfDeleteCcb (
  1973. IN PIRP_CONTEXT IrpContext,
  1974. IN PCCB Ccb
  1975. )
  1976. /*++
  1977. Routine Description:
  1978. This routine is called to cleanup and deallocate a Ccb structure.
  1979. Arguments:
  1980. Ccb - This is the Ccb to delete.
  1981. Return Value:
  1982. None
  1983. --*/
  1984. {
  1985. PAGED_CODE();
  1986. //
  1987. // Check inputs.
  1988. //
  1989. ASSERT_IRP_CONTEXT( IrpContext );
  1990. ASSERT_CCB( Ccb );
  1991. if (Ccb->SearchExpression.Buffer != NULL) {
  1992. UdfFreePool( &Ccb->SearchExpression.Buffer );
  1993. }
  1994. UdfDeallocateCcb( IrpContext, Ccb );
  1995. return;
  1996. }
  1997. ULONG
  1998. UdfFindInParseTable (
  1999. IN PPARSE_KEYVALUE ParseTable,
  2000. IN PCHAR Id,
  2001. IN ULONG MaxIdLen
  2002. )
  2003. /*++
  2004. Routine Description:
  2005. This routine walks a table of string key/value information for a match of the
  2006. input Id. MaxIdLen can be set to get a prefix match.
  2007. Arguments:
  2008. Table - This is the table being searched.
  2009. Id - Key value.
  2010. MaxIdLen - Maximum possible length of Id.
  2011. Return Value:
  2012. Value of matching entry, or the terminating (NULL) entry's value.
  2013. --*/
  2014. {
  2015. PAGED_CODE();
  2016. while (ParseTable->Key != NULL) {
  2017. if (RtlEqualMemory(ParseTable->Key, Id, MaxIdLen)) {
  2018. break;
  2019. }
  2020. ParseTable++;
  2021. }
  2022. return ParseTable->Value;
  2023. }
  2024. #ifdef UDF_SANITY
  2025. //
  2026. // Enumerate the reasons why a descriptor might be bad.
  2027. //
  2028. typedef enum _VERIFY_FAILURE {
  2029. Nothing,
  2030. BadLbn,
  2031. BadTag,
  2032. BadChecksum,
  2033. BadCrcLength,
  2034. BadCrc,
  2035. BadDestagVersion
  2036. } VERIFY_FAILURE;
  2037. #endif
  2038. BOOLEAN
  2039. UdfVerifyDescriptor (
  2040. IN PIRP_CONTEXT IrpContext,
  2041. IN PDESTAG Descriptor,
  2042. IN USHORT Tag,
  2043. IN ULONG Size,
  2044. IN ULONG Lbn,
  2045. IN BOOLEAN ReturnError
  2046. )
  2047. /*++
  2048. Routine Description:
  2049. This routine verifies that a descriptor using a Descriptor tag (3/7.2) is
  2050. consistent with itself and the descriptor data.
  2051. Arguments:
  2052. Descriptor - This is the pointer to the descriptor tag, which is always
  2053. at the front of a descriptor
  2054. Tag - The Tag Identifier this descriptor should have
  2055. Size - Size of this descriptor
  2056. Lbn - The logical block number this descriptor should claim it is recorded at
  2057. ReturnError - Whether this routine should return an error or raise
  2058. Return Value:
  2059. Boolean TRUE if the descriptor is consistent, FALSE or a raised status of
  2060. STATUS_DISK_CORRUPT_ERROR otherwise.
  2061. --*/
  2062. {
  2063. UCHAR Checksum = 0;
  2064. PCHAR CheckPtr;
  2065. USHORT Crc;
  2066. #ifdef UDF_SANITY
  2067. VERIFY_FAILURE FailReason = Nothing;
  2068. #endif
  2069. //
  2070. // Check our inputs
  2071. //
  2072. ASSERT_IRP_CONTEXT( IrpContext );
  2073. PAGED_CODE();
  2074. #ifdef UDF_SANITY
  2075. if (UdfNoisyVerifyDescriptor) {
  2076. goto BeNoisy;
  2077. }
  2078. RegularEntry:
  2079. #endif
  2080. //
  2081. // The version of the Descriptor Tag specified in ISO 13346 and used in
  2082. // UDF is a particular value; presumeably, previous versions were used
  2083. // in some older revision of the standard.
  2084. //
  2085. if ( (DESTAG_VER_NSR02 == Descriptor->Version) ||
  2086. ((DESTAG_VER_NSR03 == Descriptor->Version) && UdfExtendedFEAllowed(IrpContext->Vcb))
  2087. ) {
  2088. //
  2089. // A descriptor is stamped in four ways. First, the Lbn of the sector
  2090. // containing the descriptor is written here. (3/7.2.8)
  2091. //
  2092. if (Descriptor->Lbn == Lbn) {
  2093. //
  2094. // Next, the descriptor tag itself has an identifier which should match
  2095. // the type we expect to find here (3/7.2.1)
  2096. //
  2097. if (Descriptor->Ident == Tag) {
  2098. //
  2099. // Next, the descriptor tag itself is checksumed, minus the byte
  2100. // used to store the checksum. (3/7.2.3)
  2101. //
  2102. for (CheckPtr = (PCHAR) Descriptor;
  2103. CheckPtr < (PCHAR) Descriptor + FIELD_OFFSET( DESTAG, Checksum );
  2104. CheckPtr++) {
  2105. Checksum += *CheckPtr;
  2106. }
  2107. for (CheckPtr = (PCHAR) Descriptor + FIELD_OFFSET( DESTAG, Checksum ) + sizeof(UCHAR);
  2108. CheckPtr < (PCHAR) Descriptor + sizeof(DESTAG);
  2109. CheckPtr++) {
  2110. Checksum += *CheckPtr;
  2111. }
  2112. if (Descriptor->Checksum == Checksum) {
  2113. //
  2114. // Now we check that the CRC in the Descriptor tag is sized sanely
  2115. // and matches the Descriptor data. (3/7.2.6)
  2116. //
  2117. if (Descriptor->CRCLen &&
  2118. Descriptor->CRCLen <= Size - sizeof(DESTAG)) {
  2119. Crc = UdfComputeCrc16( (PCHAR) Descriptor + sizeof(DESTAG),
  2120. Descriptor->CRCLen );
  2121. if (Descriptor->CRC == Crc) {
  2122. //
  2123. // This descriptor checks out.
  2124. //
  2125. #ifdef UDF_SANITY
  2126. if (UdfNoisyVerifyDescriptor) {
  2127. DebugTrace(( -1, Dbg, "UdfVerifyDescriptor -> TRUE\n" ));
  2128. }
  2129. #endif
  2130. return TRUE;
  2131. } else {
  2132. #ifdef UDF_SANITY
  2133. FailReason = BadCrc;
  2134. goto ReportFailure;
  2135. #endif
  2136. }
  2137. } else {
  2138. #ifdef UDF_SANITY
  2139. FailReason = BadCrcLength;
  2140. goto ReportFailure;
  2141. #endif
  2142. }
  2143. } else {
  2144. #ifdef UDF_SANITY
  2145. FailReason = BadChecksum;
  2146. goto ReportFailure;
  2147. #endif
  2148. }
  2149. } else {
  2150. #ifdef UDF_SANITY
  2151. FailReason = BadTag;
  2152. goto ReportFailure;
  2153. #endif
  2154. }
  2155. } else {
  2156. #ifdef UDF_SANITY
  2157. FailReason = BadLbn;
  2158. goto ReportFailure;
  2159. #endif
  2160. }
  2161. } else {
  2162. #ifdef UDF_SANITY
  2163. FailReason = BadDestagVersion;
  2164. goto ReportFailure;
  2165. #endif
  2166. }
  2167. #ifdef UDF_SANITY
  2168. BeNoisy:
  2169. DebugTrace(( +1, Dbg,
  2170. "UdfVerifyDescriptor, Destag %08x, Tag %x, Size %x, Lbn %x\n",
  2171. Descriptor,
  2172. Tag,
  2173. Size,
  2174. Lbn ));
  2175. if (FailReason == Nothing) {
  2176. goto RegularEntry;
  2177. } else if (!UdfNoisyVerifyDescriptor) {
  2178. goto ReallyReportFailure;
  2179. }
  2180. ReportFailure:
  2181. if (!UdfNoisyVerifyDescriptor) {
  2182. goto BeNoisy;
  2183. }
  2184. ReallyReportFailure:
  2185. switch (FailReason) {
  2186. case BadLbn:
  2187. DebugTrace(( 0, Dbg,
  2188. "Lbn mismatch - Lbn %x != expected %x\n",
  2189. Descriptor->Lbn,
  2190. Lbn ));
  2191. break;
  2192. case BadTag:
  2193. DebugTrace(( 0, Dbg,
  2194. "Tag mismatch - Ident %x != expected %x\n",
  2195. Descriptor->Ident,
  2196. Tag ));
  2197. break;
  2198. case BadChecksum:
  2199. DebugTrace(( 0, Dbg,
  2200. "Checksum mismatch - Checksum %x != descriptor's %x\n",
  2201. Checksum,
  2202. Descriptor->Checksum ));
  2203. break;
  2204. case BadCrcLength:
  2205. DebugTrace(( 0, Dbg,
  2206. "CRC'd size bad - CrcLen %x is 0 or > max %x\n",
  2207. Descriptor->CRCLen,
  2208. Size - sizeof(DESTAG) ));
  2209. break;
  2210. case BadCrc:
  2211. DebugTrace(( 0, Dbg,
  2212. "CRC mismatch - Crc %x != descriptor's %x\n",
  2213. Crc,
  2214. Descriptor->CRC ));
  2215. break;
  2216. case BadDestagVersion:
  2217. DebugTrace(( 0, Dbg,
  2218. "Bad Destag Verion %x - (Vcb->NsrVersion => max of %x)\n", Descriptor->Version, UdfExtendedFEAllowed( IrpContext->Vcb) ? 3 : 2));
  2219. break;
  2220. default:
  2221. ASSERT( FALSE );
  2222. }
  2223. DebugTrace(( -1, Dbg, "UdfVerifyDescriptor -> FALSE\n" ));
  2224. #endif
  2225. if (!ReturnError) {
  2226. UdfRaiseStatus( IrpContext, STATUS_CRC_ERROR );
  2227. }
  2228. return FALSE;
  2229. }
  2230. VOID
  2231. UdfInitializeIcbContextFromFcb (
  2232. IN PIRP_CONTEXT IrpContext,
  2233. IN PICB_SEARCH_CONTEXT IcbContext,
  2234. IN PFCB Fcb
  2235. )
  2236. /*++
  2237. Routine Description:
  2238. This routine is called to initialize a context to search the Icb hierarchy
  2239. associated with an Fcb.
  2240. Arguments:
  2241. Fcb - Fcb associated with the hierarchy to search.
  2242. Return Value:
  2243. None.
  2244. --*/
  2245. {
  2246. PAGED_CODE();
  2247. //
  2248. // Check input parameters.
  2249. //
  2250. ASSERT_IRP_CONTEXT( IrpContext );
  2251. ASSERT_FCB( Fcb );
  2252. ASSERT( IrpContext->Vcb);
  2253. RtlZeroMemory( IcbContext, sizeof( ICB_SEARCH_CONTEXT ));
  2254. IcbContext->Vcb = Fcb->Vcb;
  2255. IcbContext->IcbType = DESTAG_ID_NSR_FILE;
  2256. //
  2257. // Map the first extent into the current slot.
  2258. //
  2259. UdfMapMetadataView( IrpContext,
  2260. &IcbContext->Current,
  2261. IcbContext->Vcb,
  2262. UdfGetFidPartition( Fcb->FileId ),
  2263. UdfGetFidLbn( Fcb->FileId ),
  2264. BlockSize( IcbContext->Vcb ),
  2265. METAMAPOP_INIT_AND_MAP);
  2266. //
  2267. // It is possible that we don't have an idea what the length of the root extent is.
  2268. // This will commonly happen in the OpenById case.
  2269. //
  2270. if (Fcb->RootExtentLength == 0) {
  2271. PICBFILE Icb = IcbContext->Current.View;
  2272. //
  2273. // We can only accomplish the guess if we have a descriptor which contains an ICB
  2274. // Tag, which contains a field that can tell us what we need to know.
  2275. //
  2276. if (Icb->Destag.Ident == DESTAG_ID_NSR_ICBIND ||
  2277. Icb->Destag.Ident == DESTAG_ID_NSR_ICBTRM ||
  2278. Icb->Destag.Ident == DESTAG_ID_NSR_FILE ||
  2279. (UdfExtendedFEAllowed( IrpContext->Vcb) && (Icb->Destag.Ident == DESTAG_ID_NSR_EXT_FILE)) ||
  2280. Icb->Destag.Ident == DESTAG_ID_NSR_UASE ||
  2281. Icb->Destag.Ident == DESTAG_ID_NSR_PINTEG
  2282. ) {
  2283. UdfVerifyDescriptor( IrpContext,
  2284. &Icb->Destag,
  2285. Icb->Destag.Ident,
  2286. BlockSize( IcbContext->Vcb ),
  2287. UdfGetFidLbn( Fcb->FileId ),
  2288. FALSE );
  2289. } else {
  2290. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2291. }
  2292. //
  2293. // Now the MaxEntries (4/14.6.4) field of the Icb Tag should tell us how big the extent
  2294. // should be. The tail of this could be unrecorded. We could even have landed in the middle
  2295. // of an extent. This is only a guess. For whatever reason we are having to guess this
  2296. // information, any results are expected to be coming with few guarantees.
  2297. //
  2298. Fcb->RootExtentLength = Icb->Icbtag.MaxEntries * BlockSize( IcbContext->Vcb );
  2299. }
  2300. }
  2301. VOID
  2302. UdfInitializeIcbContext (
  2303. IN PIRP_CONTEXT IrpContext,
  2304. IN PICB_SEARCH_CONTEXT IcbContext,
  2305. IN PVCB Vcb,
  2306. IN USHORT IcbType,
  2307. IN USHORT Partition,
  2308. IN ULONG Lbn,
  2309. IN ULONG Length
  2310. )
  2311. /*++
  2312. Routine Description:
  2313. This routine is called to initialize a context to search an Icb hierarchy.
  2314. Arguments:
  2315. Vcb - Vcb for the volume.
  2316. IcbType - Type of direct entry we expect to find (DESTAG_ID...)
  2317. Partition - partition of the hierarchy.
  2318. Lbn - lbn of the hierarchy.
  2319. Length - length of the root extent of the hierarchy.
  2320. Return Value:
  2321. None.
  2322. --*/
  2323. {
  2324. PAGED_CODE();
  2325. //
  2326. // Check input parameters.
  2327. //
  2328. ASSERT_IRP_CONTEXT( IrpContext );
  2329. RtlZeroMemory( IcbContext, sizeof( ICB_SEARCH_CONTEXT ));
  2330. IcbContext->Vcb = Vcb;
  2331. IcbContext->IcbType = IcbType;
  2332. IcbContext->Active.Vsn = IcbContext->Current.Vsn = UDF_INVALID_VSN;
  2333. //
  2334. // Map the first extent into the current slot.
  2335. //
  2336. UdfMapMetadataView( IrpContext,
  2337. &IcbContext->Current,
  2338. Vcb,
  2339. Partition,
  2340. Lbn,
  2341. Length,
  2342. METAMAPOP_INIT_AND_MAP);
  2343. return;
  2344. }
  2345. VOID
  2346. UdfLookupActiveIcb (
  2347. IN PIRP_CONTEXT IrpContext,
  2348. IN PICB_SEARCH_CONTEXT IcbContext,
  2349. IN ULONG IcbExtentLength
  2350. )
  2351. /*++
  2352. Routine Description:
  2353. This routine is called to cause the active Icb for an Icb hierarchy to be mapped.
  2354. A context initialized by UdfInitializeIcbContext() is required.
  2355. Arguments:
  2356. IcbContext - Context which has been initialized to point into an Icb hierarchy
  2357. (i.e. first block of current extent mapped in the Current entry).
  2358. Return Value:
  2359. None.
  2360. Raised status if the Icb hierarchy is invalid.
  2361. --*/
  2362. {
  2363. PAGED_CODE();
  2364. //
  2365. // Check input parameters.
  2366. //
  2367. ASSERT_IRP_CONTEXT( IrpContext );
  2368. //
  2369. // Travel the Icb hierarchy. Due to the design of ISO 13346, it is convenient to
  2370. // recursively descend the hierarchy. Place a limit on this recursion which will
  2371. // allow traversal of most reasonable hierarchies (this will tail recurse off of
  2372. // the end of extents).
  2373. //
  2374. UdfLookupActiveIcbInExtent( IrpContext,
  2375. IcbContext,
  2376. UDF_ICB_RECURSION_LIMIT,
  2377. IcbExtentLength);
  2378. //
  2379. // We must have found an active ICB. We don't need to unmap/remap
  2380. // if the currently mapped Icb is the active one, as it will be 99.99%
  2381. // of the time. Other case should only occur on WORM.
  2382. //
  2383. if ((IcbContext->Current.Lbn == IcbContext->Active.Lbn) &&
  2384. (NULL != IcbContext->Current.View)) {
  2385. //
  2386. // Just copy the mapping information over from current to active.
  2387. //
  2388. RtlCopyMemory( &IcbContext->Active,
  2389. &IcbContext->Current,
  2390. sizeof( MAPPED_PVIEW));
  2391. RtlZeroMemory( &IcbContext->Current,
  2392. sizeof( MAPPED_PVIEW));
  2393. IcbContext->Current.Vsn = UDF_INVALID_VSN;
  2394. }
  2395. else {
  2396. //
  2397. // Drop the last mapped part of the enumeration at this point, and release
  2398. // the vmcb mapping resource before attempting to map the active icb.
  2399. //
  2400. UdfUnpinView( IrpContext, &IcbContext->Current );
  2401. //
  2402. // Actually map in the active ICB. ...LookupActiveIcb..() will have already
  2403. // initialised the view record with the Icb location so we specify 'remap'.
  2404. //
  2405. UdfMapMetadataView( IrpContext,
  2406. &IcbContext->Active,
  2407. IrpContext->Vcb,
  2408. 0,
  2409. 0,
  2410. BlockSize( IrpContext->Vcb ),
  2411. METAMAPOP_REMAP_VIEW);
  2412. }
  2413. if (IcbContext->Active.View == NULL) {
  2414. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2415. }
  2416. }
  2417. VOID
  2418. UdfCleanupIcbContext (
  2419. IN PIRP_CONTEXT IrpContext,
  2420. IN PICB_SEARCH_CONTEXT IcbContext
  2421. )
  2422. /*++
  2423. Routine Description:
  2424. This routine cleans an Icb search context for reuse/deletion.
  2425. Arguments:
  2426. IcbContext - context to clean
  2427. Return Value:
  2428. None.
  2429. --*/
  2430. {
  2431. PAGED_CODE();
  2432. //
  2433. // Check inputs
  2434. //
  2435. ASSERT_IRP_CONTEXT( IrpContext );
  2436. //
  2437. // Check we didn't map both active and current simultaneously (...vmcb purge
  2438. // limitations).
  2439. //
  2440. ASSERT( (NULL == IcbContext->Active.Bcb) || (NULL == IcbContext->Current.Bcb));
  2441. UdfUnpinView( IrpContext, &IcbContext->Active );
  2442. UdfUnpinView( IrpContext, &IcbContext->Current );
  2443. ASSERT_NOT_HELD_VMCB( IrpContext->Vcb);
  2444. RtlZeroMemory( IcbContext, sizeof( ICB_SEARCH_CONTEXT ));
  2445. }
  2446. VOID
  2447. UdfInitializeEaContext (
  2448. IN PIRP_CONTEXT IrpContext,
  2449. IN PEA_SEARCH_CONTEXT EaContext,
  2450. IN PICB_SEARCH_CONTEXT IcbContext,
  2451. IN ULONG EAType,
  2452. IN UCHAR EASubType
  2453. )
  2454. /*++
  2455. Routine Description:
  2456. This routine initializes a walk through the EA space of an Icb which has been
  2457. previously discovered.
  2458. Note: only the embedded EA space is supported now.
  2459. Arguments:
  2460. EaContext - EA context to fill in
  2461. IcbContext - Elaborated ICB search structure
  2462. Return Value:
  2463. --*/
  2464. {
  2465. PICBFILE Icb;
  2466. PAGED_CODE();
  2467. //
  2468. // Check inputs
  2469. //
  2470. ASSERT_IRP_CONTEXT( IrpContext );
  2471. ASSERT( IcbContext->Active.Bcb && IcbContext->Active.View );
  2472. Icb = IcbContext->Active.View;
  2473. EaContext->IcbContext = IcbContext;
  2474. //
  2475. // Initialize to point at the first EA to return.
  2476. //
  2477. EaContext->Ea = FeEAs( Icb);
  2478. EaContext->Remaining = FeEALength( Icb);
  2479. EaContext->EAType = EAType;
  2480. EaContext->EASubType = EASubType;
  2481. }
  2482. BOOLEAN
  2483. UdfLookupEa (
  2484. IN PIRP_CONTEXT IrpContext,
  2485. IN PEA_SEARCH_CONTEXT EaContext
  2486. )
  2487. /*++
  2488. Routine Description:
  2489. This routine finds an EA in the EA space of an ICB.
  2490. Arguments:
  2491. EaContext - an initialized EA search context containing an elaborated
  2492. ICB search context and a description of the EA to find.
  2493. Return Value:
  2494. BOOLEAN True if such an EA was found and returned, False otherwise.
  2495. --*/
  2496. {
  2497. PICBFILE Icb;
  2498. PNSR_EA_GENERIC GenericEa;
  2499. PAGED_CODE();
  2500. //
  2501. // Check inputs
  2502. //
  2503. ASSERT_IRP_CONTEXT( IrpContext );
  2504. //
  2505. // Quickly terminate if the EA space is empty or not capable of containing
  2506. // the header descriptor. A null EA space is perfectly legal.
  2507. //
  2508. if (EaContext->Remaining == 0) {
  2509. return FALSE;
  2510. } else if (EaContext->Remaining < sizeof( NSR_EAH )) {
  2511. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2512. }
  2513. //
  2514. // Verify the integrity of the EA header. This has a side effect of making
  2515. // very sure that we really have an EA sequence underneath us.
  2516. //
  2517. Icb = EaContext->IcbContext->Active.View;
  2518. UdfVerifyDescriptor( IrpContext,
  2519. &((PNSR_EAH) EaContext->Ea)->Destag,
  2520. DESTAG_ID_NSR_EA,
  2521. sizeof( NSR_EAH ),
  2522. Icb->Destag.Lbn,
  2523. FALSE );
  2524. //
  2525. // Push forward the start of the EA space and loop while we have more EAs to inspect.
  2526. // Since we only scan for ISO EA's right now, we don't need to open the EA header to
  2527. // jump forward to the Implementation Use or Application Use segments.
  2528. //
  2529. EaContext->Ea = Add2Ptr( EaContext->Ea, sizeof( NSR_EAH ), PVOID );
  2530. EaContext->Remaining -= sizeof( NSR_EAH );
  2531. while (EaContext->Remaining) {
  2532. GenericEa = EaContext->Ea;
  2533. //
  2534. // The EAs must appear on 4byte aligned boundaries, there must be room to find
  2535. // the generic EA preamble and the claimed length of the EA must fit in the
  2536. // remaining space.
  2537. //
  2538. if (LongOffsetPtr( EaContext->Ea ) ||
  2539. EaContext->Remaining < FIELD_OFFSET( NSR_EA_GENERIC, EAData ) ||
  2540. EaContext->Remaining < GenericEa->EALength ) {
  2541. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2542. }
  2543. if (GenericEa->EAType == EaContext->EAType && GenericEa->EASubType == EaContext->EASubType) {
  2544. return TRUE;
  2545. }
  2546. EaContext->Ea = Add2Ptr( EaContext->Ea, GenericEa->EALength, PVOID );
  2547. EaContext->Remaining -= GenericEa->EALength;
  2548. }
  2549. //
  2550. // If we failed to find the EA, we should have stopped at the precise end of the EA space.
  2551. //
  2552. if (EaContext->Remaining) {
  2553. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2554. }
  2555. return FALSE;
  2556. }
  2557. VOID
  2558. UdfInitializeAllocations (
  2559. IN PIRP_CONTEXT IrpContext,
  2560. IN PFCB Fcb,
  2561. IN PICB_SEARCH_CONTEXT IcbContext,
  2562. IN BOOLEAN AllowOneGigWorkaround
  2563. )
  2564. /*++
  2565. Routine Description:
  2566. This routine fills in the data retrieval information for an Fcb.
  2567. Arguments:
  2568. Fcb - Fcb to add retrieval information to.
  2569. IcbContext - Elaborated ICB search context corresponding to this Fcb.
  2570. Return Value:
  2571. None.
  2572. --*/
  2573. {
  2574. PICBFILE Icb = IcbContext->Active.View;
  2575. PAD_GENERIC GenericAd;
  2576. ALLOC_ENUM_CONTEXT AllocContext;
  2577. LONGLONG RunningOffset;
  2578. ULONG Psn;
  2579. PVCB Vcb = Fcb->Vcb;
  2580. BOOLEAN Result;
  2581. PAGED_CODE();
  2582. //
  2583. // Check inputs
  2584. //
  2585. ASSERT_IRP_CONTEXT( IrpContext );
  2586. ASSERT_FCB( Fcb );
  2587. //
  2588. // Immediately return for objects with zero information space. Note that
  2589. // passing this test does not indicate that the file has any recorded space.
  2590. //
  2591. if (Fcb->FileSize.QuadPart == 0) {
  2592. return;
  2593. }
  2594. //
  2595. // Init the allocation search context. Note that in the non-immediate
  2596. // data case this can cause the active view (icb) to be unmapped
  2597. //
  2598. UdfInitializeAllocationContext( IrpContext,
  2599. &AllocContext,
  2600. IcbContext,
  2601. AllowOneGigWorkaround);
  2602. //
  2603. // Handle the case of embedded data.
  2604. //
  2605. if (AllocContext.AllocType == ICBTAG_F_ALLOC_IMMEDIATE) {
  2606. //
  2607. // Teardown any existing mcb.
  2608. //
  2609. UdfUninitializeFcbMcb( Fcb );
  2610. //
  2611. // Establish a single block mapping to the Icb itself and mark the Fcb as
  2612. // having embedded data. Mapping will occur through the Metadata stream.
  2613. // Note that by virtue of having an Icb here we know it has already had
  2614. // a mapping established in the Metadata stream, so just retrieve that
  2615. //
  2616. SetFlag( Fcb->FcbState, FCB_STATE_EMBEDDED_DATA );
  2617. Fcb->EmbeddedVsn = IcbContext->Active.Vsn;
  2618. ASSERT( UDF_INVALID_VSN != Fcb->EmbeddedVsn );
  2619. //
  2620. // Note the offset of the data in the Icb.
  2621. //
  2622. Fcb->EmbeddedOffset = FeEAsFieldOffset( Icb) + FeEALength( Icb);
  2623. //
  2624. // Check that the information length agrees.
  2625. //
  2626. if (FeAllocLength(Icb) != Fcb->FileSize.LowPart) {
  2627. DebugTrace(( 0, Dbg, "UdfInitializeAllocations, embedded alloc %08x != filesize %08x\n",
  2628. FeAllocLength( Icb),
  2629. Fcb->FileSize.LowPart ));
  2630. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2631. }
  2632. return;
  2633. }
  2634. //
  2635. // Now initialize the mapping structure for this Fcb.
  2636. //
  2637. UdfInitializeFcbMcb( Fcb );
  2638. //
  2639. // Now walk the chain of allocation descriptors for the object, adding them into the
  2640. // mapping.
  2641. //
  2642. RunningOffset = 0;
  2643. do {
  2644. //
  2645. // Check to see if we've read all of the extents for the file body yet.
  2646. // We could do file tail consistency checking (4/12.1), however as a read only
  2647. // implementation we don't care about the file tail, and since there is no easy way
  2648. // of detecting loops in the tail, we'll just ignore it for the sake of simplicity.
  2649. //
  2650. if (RunningOffset >= Fcb->FileSize.QuadPart) {
  2651. break;
  2652. }
  2653. //
  2654. // It is impermissible for an interior body extent of an object to not be
  2655. // an integral multiple of a logical block in size (note that the last
  2656. // will tend not to be). Also check that the body didn't overshoot the
  2657. // information length (this check will also catch looped AD extents)
  2658. //
  2659. GenericAd = AllocContext.Alloc;
  2660. if (BlockOffset( Vcb, RunningOffset ) || (Fcb->FileSize.QuadPart < RunningOffset)) {
  2661. DebugTrace(( 0, Dbg, "UdfInitializeAllocations, bad alloc\n"));
  2662. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2663. }
  2664. //
  2665. // Based on the descriptor type, pull it apart and add the mapping.
  2666. //
  2667. if (GenericAd->Length.Type == NSRLENGTH_TYPE_RECORDED) {
  2668. //
  2669. // Grab the Psn this extent starts at and add the allocation.
  2670. //
  2671. Psn = UdfLookupPsnOfExtent( IrpContext,
  2672. Vcb,
  2673. UdfGetPartitionOfCurrentAllocation( &AllocContext ),
  2674. GenericAd->Start,
  2675. GenericAd->Length.Length );
  2676. Result = FsRtlAddLargeMcbEntry( &Fcb->Mcb,
  2677. LlSectorsFromBytes( Vcb, RunningOffset ),
  2678. Psn,
  2679. SectorsFromBytes( Vcb, SectorAlign( Vcb, GenericAd->Length.Length ) ));
  2680. ASSERT( Result );
  2681. }
  2682. RunningOffset += GenericAd->Length.Length;
  2683. }
  2684. while ( UdfGetNextAllocation( IrpContext, &AllocContext ));
  2685. //
  2686. // If the running offset doesn't match the expected file size, then
  2687. // see if this file is a candidate for the ">1Gb in single AD mastering
  2688. // error" workaround. Sigh...
  2689. //
  2690. if ((Fcb->FileSize.QuadPart != RunningOffset) &&
  2691. (Fcb->Header.NodeTypeCode == UDFS_NTC_FCB_DATA) &&
  2692. AllowOneGigWorkaround &&
  2693. ((Fcb->FileSize.QuadPart & 0x3fffffff) == RunningOffset) &&
  2694. (NULL != AllocContext.IcbContext->Active.View)) {
  2695. PICBFILE Icb = AllocContext.IcbContext->Active.View;
  2696. PSHORTAD Ad = Add2Ptr( FeEAs( Icb), FeEALength( Icb), PVOID );
  2697. //
  2698. // Plausable. So now verify that there is only a single AD and it contains
  2699. // precisely the expected (wrong) value. We've already checked that the
  2700. // original FE is still mapped.
  2701. //
  2702. if (((Icb->Icbtag.Flags & ICBTAG_F_ALLOC_MASK) == ICBTAG_F_ALLOC_SHORT) &&
  2703. (FeAllocLength(Icb) == sizeof( SHORTAD)) &&
  2704. (*((PULONG)(&Ad->Length)) == Fcb->FileSize.QuadPart)) {
  2705. //
  2706. // Lookup the PSN for this extent. This will also validate that our
  2707. // guestimated extent fits within partition bounds.
  2708. //
  2709. Psn = UdfLookupPsnOfExtent( IrpContext,
  2710. Vcb,
  2711. UdfGetPartitionOfCurrentAllocation( &AllocContext ),
  2712. Ad->Start,
  2713. Fcb->FileSize.LowPart );
  2714. //
  2715. // So fix up the Mcb to represent this estimated extent
  2716. //
  2717. FsRtlTruncateLargeMcb( &Fcb->Mcb, 0);
  2718. (void)FsRtlAddLargeMcbEntry( &Fcb->Mcb,
  2719. 0,
  2720. Psn,
  2721. SectorsFromBytes( Vcb, SectorAlign( Vcb, Fcb->FileSize.LowPart ) ));
  2722. RunningOffset = Fcb->FileSize.QuadPart;
  2723. DebugTrace(( 0, Dbg, "UdfInitializeAllocations -> 1 GIG AD workaround performed on Fcb 0x%p\n", Fcb));
  2724. }
  2725. }
  2726. //
  2727. // Restore the ICB mapping if we unmapped it to traverse non embedded
  2728. // extent blocks. Note that we key on Active->View here (rather than Bcb),
  2729. // because during UdfInit...VcbPhase0 we are called with a phoney IcbContext
  2730. // where View is a pointer to a buffer, hence there was no bcb, and
  2731. // we don't want to create a mapping now. Because the unmap operations
  2732. // only act if NULL!=Bcb, (not true in this case) view will still be
  2733. // non-null here even after walking more allocation extents, and we do nothing.
  2734. //
  2735. UdfUnpinView( IrpContext, &IcbContext->Current);
  2736. if ( NULL == IcbContext->Active.View) {
  2737. UdfMapMetadataView( IrpContext,
  2738. &IcbContext->Active,
  2739. IrpContext->Vcb,
  2740. 0, 0, 0,
  2741. METAMAPOP_REMAP_VIEW);
  2742. }
  2743. //
  2744. // We must have had body allocation descriptors for exactly the entire file
  2745. // information length.
  2746. //
  2747. if (Fcb->FileSize.QuadPart != RunningOffset) {
  2748. DebugTrace(( 0, Dbg, "UdfInitializeAllocations, total descriptors != filesize\n" ));
  2749. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2750. }
  2751. }
  2752. VOID
  2753. UdfUpdateTimestampsFromIcbContext (
  2754. IN PIRP_CONTEXT IrpContext,
  2755. IN PICB_SEARCH_CONTEXT IcbContext,
  2756. IN PTIMESTAMP_BUNDLE Timestamps
  2757. )
  2758. /*++
  2759. Routine Description:
  2760. This routine converts the set of timestamps associated with a given ICB into
  2761. an NT native form.
  2762. Arguments:
  2763. IcbOontext - An search context containing the active direct ICB for the object
  2764. Timestamps - the bundle of timestamps to receive the converted times.
  2765. Return Value:
  2766. None.
  2767. --*/
  2768. {
  2769. EA_SEARCH_CONTEXT EaContext;
  2770. PICBFILE Icb = IcbContext->Active.View;
  2771. PAGED_CODE();
  2772. //
  2773. // Check inputs
  2774. //
  2775. ASSERT_IRP_CONTEXT( IrpContext );
  2776. // *TEJ - following should probably be a permanent runtime check? (ext fe + nsr03)?
  2777. ASSERT( (Icb->Destag.Ident == DESTAG_ID_NSR_FILE) || ((Icb->Destag.Ident == DESTAG_ID_NSR_EXT_FILE) && UdfExtendedFEAllowed( IrpContext->Vcb)));
  2778. //
  2779. // Initialize the timestamps for this object. Due to ISO 13346,
  2780. // we must gather EAs and figure out which of several timestamps is most valid.
  2781. // Pull the access & modification times from the ICB
  2782. //
  2783. UdfConvertUdfTimeToNtTime( IrpContext,
  2784. PFeModifyTime( Icb),
  2785. (PLARGE_INTEGER) &Timestamps->ModificationTime );
  2786. UdfConvertUdfTimeToNtTime( IrpContext,
  2787. PFeAccessTime( Icb),
  2788. (PLARGE_INTEGER) &Timestamps->AccessTime );
  2789. if (UdfFEIsExtended( Icb)) {
  2790. //
  2791. // Creation time field is new in Extended FEs
  2792. //
  2793. UdfConvertUdfTimeToNtTime( IrpContext,
  2794. PFeCreationTime( Icb),
  2795. (PLARGE_INTEGER) &Timestamps->CreationTime );
  2796. }
  2797. else {
  2798. //
  2799. // For a basic FileEntry, look and see if a FileTimes EA has been recorded
  2800. // which contains a creation time.
  2801. //
  2802. UdfInitializeEaContext( IrpContext,
  2803. &EaContext,
  2804. IcbContext,
  2805. EA_TYPE_FILETIMES,
  2806. EA_SUBTYPE_BASE );
  2807. if (UdfLookupEa( IrpContext, &EaContext )) {
  2808. PNSR_EA_FILETIMES FileTimes = EaContext.Ea;
  2809. if (FlagOn(FileTimes->Existence, EA_FILETIMES_E_CREATION)) {
  2810. UdfConvertUdfTimeToNtTime( IrpContext,
  2811. &FileTimes->Stamps[0],
  2812. (PLARGE_INTEGER) &Timestamps->CreationTime );
  2813. }
  2814. }
  2815. else {
  2816. //
  2817. // No Timestamps EA recorded. So we'll just use last mod time as creation
  2818. //
  2819. Timestamps->CreationTime = Timestamps->ModificationTime;
  2820. }
  2821. }
  2822. }
  2823. BOOLEAN
  2824. UdfCreateFileLock (
  2825. IN PIRP_CONTEXT IrpContext OPTIONAL,
  2826. IN PFCB Fcb,
  2827. IN BOOLEAN RaiseOnError
  2828. )
  2829. /*++
  2830. Routine Description:
  2831. This routine is called when we want to attach a file lock structure to the
  2832. given Fcb. It is possible the file lock is already attached.
  2833. This routine is sometimes called from the fast path and sometimes in the
  2834. Irp-based path. We don't want to raise in the fast path, just return FALSE.
  2835. Arguments:
  2836. Fcb - This is the Fcb to create the file lock for.
  2837. RaiseOnError - If TRUE, we will raise on an allocation failure. Otherwise we
  2838. return FALSE on an allocation failure.
  2839. Return Value:
  2840. BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise.
  2841. --*/
  2842. {
  2843. BOOLEAN Result = TRUE;
  2844. PFILE_LOCK FileLock;
  2845. PAGED_CODE();
  2846. //
  2847. // Lock the Fcb and check if there is really any work to do.
  2848. //
  2849. UdfLockFcb( IrpContext, Fcb );
  2850. if (Fcb->FileLock != NULL) {
  2851. UdfUnlockFcb( IrpContext, Fcb );
  2852. return TRUE;
  2853. }
  2854. Fcb->FileLock = FileLock =
  2855. FsRtlAllocateFileLock( NULL, NULL );
  2856. UdfUnlockFcb( IrpContext, Fcb );
  2857. //
  2858. // Return or raise as appropriate.
  2859. //
  2860. if (FileLock == NULL) {
  2861. if (RaiseOnError) {
  2862. ASSERT( ARGUMENT_PRESENT( IrpContext ));
  2863. UdfRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  2864. }
  2865. Result = FALSE;
  2866. }
  2867. return Result;
  2868. }
  2869. //
  2870. // Local support routine
  2871. //
  2872. VOID
  2873. UdfLookupActiveIcbInExtent (
  2874. IN PIRP_CONTEXT IrpContext,
  2875. IN PICB_SEARCH_CONTEXT IcbContext,
  2876. IN ULONG Recurse,
  2877. IN ULONG Length
  2878. )
  2879. /*++
  2880. Routine Description:
  2881. This routine is called to traverse a single Icb hierarchy extent to discover
  2882. an active Icb. This is a recursive operation on indirect Icbs that may be
  2883. found in the sequence.
  2884. Arguments:
  2885. IcbContext - Context which has been initialized to point into an Icb hierarchy.
  2886. Recurse - Recursion limit.
  2887. Length - Length of the extent currently described in IcbContext->Current (since
  2888. we only map a block at a time the length in there will be 1 block...)
  2889. Return Value:
  2890. None.
  2891. Raised status if the Icb hierarchy is invalid.
  2892. --*/
  2893. {
  2894. PVCB Vcb = IcbContext->Vcb;
  2895. PFCB Fcb = Vcb->MetadataFcb;
  2896. ULONG Lbn;
  2897. USHORT Partition;
  2898. ULONG Vsn;
  2899. PICBIND Icb;
  2900. PAGED_CODE();
  2901. //
  2902. // Should only ever have a single view mapped. We're using Current, so...
  2903. //
  2904. ASSERT( NULL == IcbContext->Active.Bcb );
  2905. ASSERT( NULL != IcbContext->Current.View );
  2906. //
  2907. // Don't expect to see extended FE as search type (we just use basic FE and
  2908. // treat as potentially either).
  2909. //
  2910. ASSERT( DESTAG_ID_NSR_EXT_FILE != IcbContext->IcbType);
  2911. //
  2912. // Decrement our recursion allowance.
  2913. //
  2914. Recurse--;
  2915. //
  2916. // Grab our starting point
  2917. //
  2918. Partition = IcbContext->Current.Partition;
  2919. Lbn = IcbContext->Current.Lbn;
  2920. Icb = IcbContext->Current.View;
  2921. //
  2922. // Walk across the extent
  2923. //
  2924. do {
  2925. switch (Icb->Destag.Ident) {
  2926. case DESTAG_ID_NSR_ICBIND:
  2927. UdfVerifyDescriptor( IrpContext,
  2928. &Icb->Destag,
  2929. DESTAG_ID_NSR_ICBIND,
  2930. sizeof( ICBIND ),
  2931. Lbn,
  2932. FALSE );
  2933. //
  2934. // Go to the next extent if this indirect Icb actually points to something.
  2935. //
  2936. if (Icb->Icb.Length.Type == NSRLENGTH_TYPE_RECORDED) {
  2937. //
  2938. // If we are in the last entry of the Icb extent, we may tail recurse. This
  2939. // is very important for strategy 4096, which is a linked list of extents
  2940. // of depth equal to the number of times the direct Icb had to be re-recorded.
  2941. //
  2942. /*
  2943. //
  2944. // THIS IS STRAT.4 SUPPORT CODE. SINCE WE HAVE NO TEST MEDIA/PLAN
  2945. // FOR THIS, AND UDF ONLY ALLOWS STAT.4096 IN ANY CASE, I AM
  2946. // DISABLING IT FOR NOW.
  2947. //
  2948. UdfMapMetadataView( IrpContext,
  2949. &IcbContext->Current,
  2950. Vcb,
  2951. Icb->Icb.Start.Partition,
  2952. Icb->Icb.Start.Lbn,
  2953. BlockSize( Vcb),
  2954. METAMAPOP_INIT_AND_MAP);
  2955. if (Length != BlockSize( Vcb )) {
  2956. //
  2957. // We have to give up on this if we're going too deep.
  2958. //
  2959. if (Recurse == 0) {
  2960. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2961. }
  2962. UdfLookupActiveIcbInExtent( IrpContext,
  2963. IcbContext,
  2964. Recurse,
  2965. Icb->Icb.Length.Length);
  2966. //
  2967. // Need to remap the extent we were working on.
  2968. //
  2969. UdfMapMetadataView( IrpContext,
  2970. &IcbContext->Current,
  2971. Vcb,
  2972. Partition,
  2973. Lbn,
  2974. BlockSize( Vcb),
  2975. METAMAPOP_INIT_AND_MAP);
  2976. //
  2977. // May have been remapped at different address
  2978. //
  2979. Icb = IcbContext->Current.View;
  2980. } else {
  2981. //
  2982. // Tail recursion was possible so adjust our pointers and restart the scan.
  2983. //
  2984. Partition = IcbContext->Current.Partition;
  2985. Lbn = IcbContext->Current.Lbn;
  2986. Length = IcbContext->Current.Length;
  2987. Icb = IcbContext->Current.View;
  2988. continue;
  2989. }
  2990. */
  2991. //
  2992. // We only expect to see an indirect block at the end of an Icb
  2993. // extent (4096), so this should be the last block in the current
  2994. // extent. Anything else is corruption as far as we're concerned.
  2995. //
  2996. if ((Length != BlockSize( Vcb)) ||
  2997. (Partition != Icb->Icb.Start.Partition)) {
  2998. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  2999. }
  3000. //
  3001. // Update our pointers. The next extent will be mapped further down
  3002. // before the next pass of the loop.
  3003. //
  3004. Lbn = Icb->Icb.Start.Lbn - 1,
  3005. Length = Icb->Icb.Length.Length + BlockSize( Vcb);
  3006. }
  3007. break;
  3008. case DESTAG_ID_NSR_ICBTRM:
  3009. UdfVerifyDescriptor( IrpContext,
  3010. &Icb->Destag,
  3011. DESTAG_ID_NSR_ICBTRM,
  3012. sizeof( ICBTRM ),
  3013. Lbn,
  3014. FALSE );
  3015. //
  3016. // Terminate the current extent.
  3017. //
  3018. return;
  3019. break;
  3020. case DESTAG_ID_NOTSPEC:
  3021. //
  3022. // Perhaps this is an unrecorded sector. Treat this as terminating
  3023. // the current extent.
  3024. //
  3025. return;
  3026. break;
  3027. default:
  3028. //
  3029. // This is a data-full Icb. It must be of the expected type. We will
  3030. // accept EXT FEs here iff the search type was FE and the volume conforms to
  3031. // NSR03.
  3032. //
  3033. if ( (Icb->Destag.Ident != IcbContext->IcbType) &&
  3034. ( (DESTAG_ID_NSR_FILE != IcbContext->IcbType) ||
  3035. (!UdfExtendedFEAllowed( IrpContext->Vcb)) ||
  3036. (DESTAG_ID_NSR_EXT_FILE != Icb->Destag.Ident)
  3037. )
  3038. ) {
  3039. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  3040. }
  3041. //
  3042. // Since direct entries are of variable size, we must allow up to
  3043. // a block's worth of data.
  3044. //
  3045. UdfVerifyDescriptor( IrpContext,
  3046. &Icb->Destag,
  3047. Icb->Destag.Ident,
  3048. BlockSize( Vcb ),
  3049. Lbn,
  3050. FALSE );
  3051. //
  3052. // We perform an in-order traversal of the hierarchy. This is important since
  3053. // it means no tricks are neccesary to figure out the rightmost direct Icb -
  3054. // always stash the last one we see.
  3055. //
  3056. // Map this logical block into the active slot. We know that a direct entry
  3057. // must fit in a single logical block.
  3058. //
  3059. // Note that we don't actually do the mapping operation here, just store
  3060. // the Icb location (we don't want two active mappings in the same thread
  3061. // because it complicates the vmcb purge synchronisation logic).
  3062. // Also more effecient.
  3063. //
  3064. UdfMapMetadataView( IrpContext,
  3065. &IcbContext->Active,
  3066. Vcb,
  3067. Partition,
  3068. Lbn,
  3069. BlockSize( Vcb ),
  3070. METAMAPOP_INIT_VIEW_ONLY );
  3071. }
  3072. //
  3073. // Advance our pointer set.
  3074. //
  3075. Lbn++;
  3076. Length -= BlockSize( Vcb );
  3077. //
  3078. // If neccessary, map the next block in this extent (strat 4096).
  3079. //
  3080. if (0 != Length) {
  3081. UdfMapMetadataView( IrpContext,
  3082. &IcbContext->Current,
  3083. Vcb,
  3084. Partition,
  3085. Lbn,
  3086. BlockSize( Vcb),
  3087. METAMAPOP_INIT_AND_MAP);
  3088. Icb = IcbContext->Current.View;
  3089. }
  3090. }
  3091. while (Length);
  3092. }
  3093. //
  3094. // Local support routine
  3095. //
  3096. VOID
  3097. UdfInitializeAllocationContext (
  3098. IN PIRP_CONTEXT IrpContext,
  3099. IN PALLOC_ENUM_CONTEXT AllocContext,
  3100. IN PICB_SEARCH_CONTEXT IcbContext,
  3101. IN BOOLEAN AllowSingleZeroLengthExtent
  3102. )
  3103. /*++
  3104. Routine Description:
  3105. Initializes a walk of the allocation descriptors for an ICB which has already
  3106. been found. The first allocation descriptor will be avaliable after the call.
  3107. Can potentially exit with the AllocContext->IcbContext->Active view unmapped if
  3108. there are no descriptors embedded in the Icb (so current will now be mapped to the
  3109. next block of extents), or the data is immediate.
  3110. Arguments:
  3111. AllocContext - Allocation enumeration context to use
  3112. IcbContext - Elaborated ICB search context for the ICB to enumerate
  3113. Return Value:
  3114. None.
  3115. --*/
  3116. {
  3117. PICBFILE Icb;
  3118. PAGED_CODE();
  3119. //
  3120. // Check inputs
  3121. //
  3122. ASSERT_IRP_CONTEXT( IrpContext );
  3123. ASSERT( IcbContext->Active.View );
  3124. AllocContext->IcbContext = IcbContext;
  3125. //
  3126. // Figure out what kind of descriptors will be here.
  3127. //
  3128. Icb = IcbContext->Active.View;
  3129. AllocContext->AllocType = FlagOn( Icb->Icbtag.Flags, ICBTAG_F_ALLOC_MASK );
  3130. //
  3131. // We are done if this is actually immediate data.
  3132. //
  3133. if (AllocContext->AllocType == ICBTAG_F_ALLOC_IMMEDIATE) {
  3134. return;
  3135. }
  3136. //
  3137. // The initial chunk of allocation descriptors is inline with the ICB and
  3138. // does not contain an Allocation Extent Descriptor.
  3139. //
  3140. AllocContext->Alloc = Add2Ptr( FeEAs( Icb), FeEALength( Icb), PVOID );
  3141. AllocContext->Remaining = FeAllocLength( Icb);
  3142. ASSERT( LongOffsetPtr( AllocContext->Alloc ) == 0 );
  3143. //
  3144. // Check that the specified amount of ADs/embedded data can actually fit
  3145. // within the block.
  3146. //
  3147. if (AllocContext->Remaining >
  3148. (BlockSize( IrpContext->Vcb) - (FeEAsFieldOffset( Icb) + FeEALength( Icb)))) {
  3149. DebugTrace(( 0, Dbg, "UdfInitializeAllocationContext(), AD_Len 0x%x for Icb > (Blocksize - (FE+EAs))\n",
  3150. AllocContext->Remaining));
  3151. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  3152. }
  3153. //
  3154. // Check that an integral number of the appropriate allocation descriptors fit in
  3155. // this extent and that the extent is not composed of extended allocation descriptors,
  3156. // which are illegal on UDF.
  3157. //
  3158. // If the common post-processing fails, we probably did not find any allocation
  3159. // descriptors (case of nothing but continuation). This is likewise bad.
  3160. //
  3161. if (AllocContext->Remaining == 0 ||
  3162. AllocContext->Remaining % ISOAllocationDescriptorSize( AllocContext->AllocType ) ||
  3163. AllocContext->AllocType == ICBTAG_F_ALLOC_EXTENDED ||
  3164. !UdfGetNextAllocationPostProcessing( IrpContext, AllocContext )) {
  3165. //
  3166. // Do some final verification/traversal of continuation extents. We need to
  3167. // allow zero length extents here if we're allowing the 1Gb corrupt AD workaround,
  3168. // since a 1Gb extent will be encoded as type 1, length 0... Note that if someone
  3169. // has managed to record a 4Gb-1block extent, the postprocess function above
  3170. // will raise (will see a continuation extent > 1 block). We'll just hope that
  3171. // noone's been that stupid.
  3172. //
  3173. // This case is deliberately extremely specific.
  3174. //
  3175. if (!(AllowSingleZeroLengthExtent &&
  3176. (AllocContext->AllocType == ICBTAG_F_ALLOC_SHORT) &&
  3177. (AllocContext->Remaining == sizeof( SHORTAD)) &&
  3178. (((PSHORTAD)AllocContext->Alloc)->Length.Length == 0) &&
  3179. (((PSHORTAD)AllocContext->Alloc)->Length.Type != 0))) {
  3180. DebugTrace(( 0, Dbg, "UdfInitializeAllocationContext: Failing - Rem %x Rem%%size %x Type %x\n",
  3181. AllocContext->Remaining,
  3182. AllocContext->Remaining % ISOAllocationDescriptorSize( AllocContext->AllocType ),
  3183. AllocContext->AllocType));
  3184. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  3185. }
  3186. else {
  3187. DebugTrace(( 0, Dbg, "UdfInitializeAllocationContext: Ignoring zero length initial AD due to 1Gb workaround\n"));
  3188. }
  3189. }
  3190. }
  3191. //
  3192. // Local support routine
  3193. //
  3194. BOOLEAN
  3195. UdfGetNextAllocation (
  3196. IN PIRP_CONTEXT IrpContext,
  3197. IN PALLOC_ENUM_CONTEXT AllocContext
  3198. )
  3199. /*++
  3200. Routine Description:
  3201. This routine retrieves the next logical allocation descriptor given an enumeration
  3202. context.
  3203. Any ACTIVE view in the AllocContext->IcbContext will be unmapped.
  3204. Arguments:
  3205. AllocContext - Context to advance to the next descriptor
  3206. Return Value:
  3207. BOOLEAN - TRUE if one is found, FALSE if the enumeration is complete.
  3208. This routine will raise if malformation is discovered.
  3209. --*/
  3210. {
  3211. PAGED_CODE();
  3212. //
  3213. // Check inputs
  3214. //
  3215. ASSERT_IRP_CONTEXT( IrpContext );
  3216. AllocContext->Remaining -= ISOAllocationDescriptorSize( AllocContext->AllocType );
  3217. AllocContext->Alloc = Add2Ptr( AllocContext->Alloc, ISOAllocationDescriptorSize( AllocContext->AllocType ), PVOID );
  3218. return UdfGetNextAllocationPostProcessing( IrpContext, AllocContext );
  3219. }
  3220. BOOLEAN
  3221. UdfGetNextAllocationPostProcessing (
  3222. IN PIRP_CONTEXT IrpContext,
  3223. IN PALLOC_ENUM_CONTEXT AllocContext
  3224. )
  3225. /*++
  3226. Routine Description:
  3227. This routine retrieves the next logical allocation descriptor given an enumeration
  3228. context.
  3229. Arguments:
  3230. AllocContext - Context to advance to the next descriptor
  3231. Return Value:
  3232. BOOLEAN - TRUE if one is found, FALSE if the enumeration is complete.
  3233. This routine will raise if malformation is discovered.
  3234. --*/
  3235. {
  3236. PAD_GENERIC GenericAd;
  3237. PNSR_ALLOC AllocDesc;
  3238. ULONG Start;
  3239. USHORT Partition;
  3240. PVCB Vcb = AllocContext->IcbContext->Vcb;
  3241. //
  3242. // There are three ways to reach the end of the current block of allocation
  3243. // descriptors, per ISO 13346 4/12:
  3244. //
  3245. // reach the end of the field (kept track of in the Remaining bytes)
  3246. // reach an allocation descriptor with an extent length of zero
  3247. // reach a continuation extent descriptor
  3248. //
  3249. //
  3250. // We are done in the first two cases.
  3251. //
  3252. if (AllocContext->Remaining < ISOAllocationDescriptorSize( AllocContext->AllocType )) {
  3253. return FALSE;
  3254. }
  3255. while (TRUE) {
  3256. GenericAd = AllocContext->Alloc;
  3257. if (GenericAd->Length.Length == 0) {
  3258. return FALSE;
  3259. }
  3260. //
  3261. // Check if this descriptor is a pointer to another extent of descriptors.
  3262. //
  3263. if (GenericAd->Length.Type != NSRLENGTH_TYPE_CONTINUATION) {
  3264. break;
  3265. }
  3266. //
  3267. // UDF allocation extents are restricted to a single logical block.
  3268. //
  3269. if (GenericAd->Length.Length > BlockSize( Vcb )) {
  3270. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  3271. }
  3272. //
  3273. // Extract required values from the current block of extents, which
  3274. // may be the active ICB mapping which we're about to throw away...
  3275. //
  3276. Start = GenericAd->Start;
  3277. Partition = UdfGetPartitionOfCurrentAllocation( AllocContext );
  3278. //
  3279. // Ensure that any active view is unmapped at this point, and destroy
  3280. // pointers into it
  3281. //
  3282. UdfUnpinView( IrpContext, &AllocContext->IcbContext->Active);
  3283. GenericAd = NULL;
  3284. //
  3285. // Map the next block of extents
  3286. //
  3287. UdfMapMetadataView( IrpContext,
  3288. &AllocContext->IcbContext->Current,
  3289. Vcb,
  3290. Partition,
  3291. Start,
  3292. BlockSize( Vcb ),
  3293. METAMAPOP_INIT_AND_MAP);
  3294. //
  3295. // Now check that the allocation descriptor is valid.
  3296. //
  3297. AllocDesc = (PNSR_ALLOC) AllocContext->IcbContext->Current.View;
  3298. UdfVerifyDescriptor( IrpContext,
  3299. &AllocDesc->Destag,
  3300. DESTAG_ID_NSR_ALLOC,
  3301. BlockSize( Vcb ),
  3302. AllocContext->IcbContext->Current.Lbn,
  3303. FALSE );
  3304. //
  3305. // Note that a full logical block is mapped, but only the claimed number of
  3306. // bytes are valid.
  3307. //
  3308. AllocContext->Remaining = AllocDesc->AllocLen;
  3309. AllocContext->Alloc = Add2Ptr( AllocContext->IcbContext->Current.View, sizeof( NSR_ALLOC ), PVOID );
  3310. //
  3311. // Check that the size is sane and that an integral number of the appropriate
  3312. // allocation descriptors fit in this extent.
  3313. //
  3314. if (AllocContext->Remaining == 0 ||
  3315. AllocContext->Remaining > BlockSize( Vcb ) - sizeof( NSR_ALLOC ) ||
  3316. AllocContext->Remaining % ISOAllocationDescriptorSize( AllocContext->AllocType )) {
  3317. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  3318. }
  3319. }
  3320. return TRUE;
  3321. }
  3322. //
  3323. // Local support routine
  3324. //
  3325. PFCB_NONPAGED
  3326. UdfCreateFcbNonPaged (
  3327. IN PIRP_CONTEXT IrpContext
  3328. )
  3329. /*++
  3330. Routine Description:
  3331. This routine is called to create and initialize the non-paged portion
  3332. of an Fcb.
  3333. Arguments:
  3334. Return Value:
  3335. PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created.
  3336. --*/
  3337. {
  3338. PFCB_NONPAGED FcbNonpaged;
  3339. PAGED_CODE();
  3340. //
  3341. // Allocate the non-paged pool and initialize the various
  3342. // synchronization objects.
  3343. //
  3344. FcbNonpaged = UdfAllocateFcbNonpaged( IrpContext );
  3345. RtlZeroMemory( FcbNonpaged, sizeof( FCB_NONPAGED ));
  3346. FcbNonpaged->NodeTypeCode = UDFS_NTC_FCB_NONPAGED;
  3347. FcbNonpaged->NodeByteSize = sizeof( FCB_NONPAGED );
  3348. ExInitializeResourceLite( &FcbNonpaged->FcbResource );
  3349. ExInitializeFastMutex( &FcbNonpaged->FcbMutex );
  3350. return FcbNonpaged;
  3351. }
  3352. //
  3353. // Local support routine
  3354. //
  3355. VOID
  3356. UdfDeleteFcbNonpaged (
  3357. IN PIRP_CONTEXT IrpContext,
  3358. IN PFCB_NONPAGED FcbNonpaged
  3359. )
  3360. /*++
  3361. Routine Description:
  3362. This routine is called to cleanup the non-paged portion of an Fcb.
  3363. Arguments:
  3364. FcbNonpaged - Structure to clean up.
  3365. Return Value:
  3366. None
  3367. --*/
  3368. {
  3369. PAGED_CODE();
  3370. ExDeleteResourceLite( &FcbNonpaged->FcbResource );
  3371. UdfDeallocateFcbNonpaged( IrpContext, FcbNonpaged );
  3372. return;
  3373. }
  3374. //
  3375. // Local support routine
  3376. //
  3377. RTL_GENERIC_COMPARE_RESULTS
  3378. UdfFcbTableCompare (
  3379. IN PRTL_GENERIC_TABLE Table,
  3380. IN PVOID id1,
  3381. IN PVOID id2
  3382. )
  3383. /*++
  3384. Routine Description:
  3385. This routine is the Udfs compare routine called by the generic table package.
  3386. If will compare the two File Id values and return a comparison result.
  3387. Arguments:
  3388. Table - This is the table being searched.
  3389. id1 - First key value.
  3390. id2 - Second key value.
  3391. Return Value:
  3392. RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
  3393. input structures
  3394. --*/
  3395. {
  3396. FILE_ID Id1, Id2;
  3397. PAGED_CODE();
  3398. Id1 = *((FILE_ID UNALIGNED *) id1);
  3399. Id2 = *((FILE_ID UNALIGNED *) id2);
  3400. if (Id1.QuadPart < Id2.QuadPart) {
  3401. return GenericLessThan;
  3402. } else if (Id1.QuadPart > Id2.QuadPart) {
  3403. return GenericGreaterThan;
  3404. } else {
  3405. return GenericEqual;
  3406. }
  3407. UNREFERENCED_PARAMETER( Table );
  3408. }
  3409. //
  3410. // Local support routine
  3411. //
  3412. PVOID
  3413. UdfAllocateTable (
  3414. IN PRTL_GENERIC_TABLE Table,
  3415. IN CLONG ByteSize
  3416. )
  3417. /*++
  3418. Routine Description:
  3419. This is a generic table support routine to allocate memory
  3420. Arguments:
  3421. Table - Supplies the generic table being used
  3422. ByteSize - Supplies the number of bytes to allocate
  3423. Return Value:
  3424. PVOID - Returns a pointer to the allocated data
  3425. --*/
  3426. {
  3427. PAGED_CODE();
  3428. return( FsRtlAllocatePoolWithTag( UdfPagedPool, ByteSize, TAG_GENERIC_TABLE ));
  3429. }
  3430. //
  3431. // Local support routine
  3432. //
  3433. VOID
  3434. UdfDeallocateTable (
  3435. IN PRTL_GENERIC_TABLE Table,
  3436. IN PVOID Buffer
  3437. )
  3438. /*++
  3439. Routine Description:
  3440. This is a generic table support routine that deallocates memory
  3441. Arguments:
  3442. Table - Supplies the generic table being used
  3443. Buffer - Supplies the buffer being deallocated
  3444. Return Value:
  3445. None.
  3446. --*/
  3447. {
  3448. PAGED_CODE();
  3449. ExFreePool( Buffer );
  3450. return;
  3451. UNREFERENCED_PARAMETER( Table );
  3452. }
  3453. BOOLEAN
  3454. UdfDomainIdentifierContained (
  3455. IN PREGID RegID,
  3456. IN PSTRING Domain,
  3457. IN USHORT RevisionMin,
  3458. IN USHORT RevisionMax
  3459. )
  3460. /*++
  3461. Routine Description:
  3462. A Domain Identifier RegID is considered to be contained if the
  3463. text string identifier matches and the revision is less than or
  3464. equal. This is the convenient way to check that a Domain ID
  3465. indicates a set of structures will be intelligible to a given
  3466. implementation level.
  3467. Arguments:
  3468. RegID - Registered ID structure to verify
  3469. Domain - Domain to look for
  3470. RevisionMin, RevisionMax - Revision range to accept.
  3471. Return Value:
  3472. None.
  3473. --*/
  3474. {
  3475. PUDF_SUFFIX_DOMAIN DomainSuffix = (PUDF_SUFFIX_DOMAIN) RegID->Suffix;
  3476. BOOLEAN Contained;
  3477. Contained = ((DomainSuffix->UdfRevision <= RevisionMax && DomainSuffix->UdfRevision >= RevisionMin) &&
  3478. UdfEqualEntityId( RegID, Domain, NULL ));
  3479. #ifdef UDF_SANITY
  3480. if (!Contained) {
  3481. UCHAR Want[24], Got[24];
  3482. strncpy( Want, Domain->Buffer, Domain->Length);
  3483. Want[Domain->Length] = '\0';
  3484. strncpy( Got, RegID->Identifier, Domain->Length);
  3485. Got[Domain->Length] = '\0';
  3486. DebugTrace((0, Dbg, "UdfDomainIdentifierContained() FAILED - Expected %X<>%X '%s', Found %X '%s'\n", RevisionMin, RevisionMax, Want, DomainSuffix->UdfRevision, Got));
  3487. }
  3488. #endif
  3489. return Contained;
  3490. }