Leaked source code of windows server 2003
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.

1679 lines
50 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. AllocSup.c
  5. Abstract:
  6. This module implements mappings to physical blocks on UDF media. The basic
  7. structure used here is the Pcb, which contains lookup information for each
  8. partition reference in the volume.
  9. // @@BEGIN_DDKSPLIT
  10. Author:
  11. Dan Lovinger [DanLo] 5-Sep-1996
  12. Revision History:
  13. Tom Jolly [TomJolly] 21-Jan-2000 CcPurge and append at vmcb end
  14. Tom Jolly [TomJolly] 1-March-2000 UDF 2.01 support
  15. // @@END_DDKSPLIT
  16. --*/
  17. #include "UdfProcs.h"
  18. //
  19. // The Bug check file id for this module
  20. //
  21. #define BugCheckFileId (UDFS_BUG_CHECK_ALLOCSUP)
  22. //
  23. // The local debug trace level
  24. //
  25. #define Dbg (UDFS_DEBUG_LEVEL_ALLOCSUP)
  26. //
  27. // Local support routines.
  28. //
  29. PPCB
  30. UdfCreatePcb (
  31. IN ULONG NumberOfPartitions
  32. );
  33. NTSTATUS
  34. UdfLoadSparingTables(
  35. PIRP_CONTEXT IrpContext,
  36. PVCB Vcb,
  37. PPCB Pcb,
  38. ULONG Reference
  39. );
  40. #ifdef ALLOC_PRAGMA
  41. #pragma alloc_text(PAGE, UdfAddToPcb)
  42. #pragma alloc_text(PAGE, UdfCompletePcb)
  43. #pragma alloc_text(PAGE, UdfCreatePcb)
  44. #pragma alloc_text(PAGE, UdfDeletePcb)
  45. #pragma alloc_text(PAGE, UdfEquivalentPcb)
  46. #pragma alloc_text(PAGE, UdfInitializePcb)
  47. #pragma alloc_text(PAGE, UdfLookupAllocation)
  48. #pragma alloc_text(PAGE, UdfLookupMetaVsnOfExtent)
  49. #pragma alloc_text(PAGE, UdfLookupPsnOfExtent)
  50. #endif
  51. BOOLEAN
  52. UdfLookupAllocation (
  53. IN PIRP_CONTEXT IrpContext,
  54. IN PFCB Fcb,
  55. IN PCCB Ccb,
  56. IN LONGLONG FileOffset,
  57. OUT PLONGLONG DiskOffset,
  58. OUT PULONG ByteCount
  59. )
  60. /*++
  61. Routine Description:
  62. This routine looks through the mapping information for the file
  63. to find the logical diskoffset and number of bytes at that offset.
  64. This routine assumes we are looking up a valid range in the file. If
  65. a mapping does not exist,
  66. Arguments:
  67. Fcb - Fcb representing this stream.
  68. FileOffset - Lookup the allocation beginning at this point.
  69. DiskOffset - Address to store the logical disk offset.
  70. ByteCount - Address to store the number of contiguous bytes beginning
  71. at DiskOffset above.
  72. Return Value:
  73. BOOLEAN - whether the extent is unrecorded data
  74. --*/
  75. {
  76. PVCB Vcb;
  77. BOOLEAN Recorded = TRUE;
  78. BOOLEAN Result;
  79. LARGE_INTEGER LocalPsn;
  80. LARGE_INTEGER LocalSectorCount;
  81. PAGED_CODE();
  82. //
  83. // Check inputs
  84. //
  85. ASSERT_IRP_CONTEXT( IrpContext );
  86. ASSERT_FCB( Fcb );
  87. //
  88. // We will never be looking up the allocations of embedded objects.
  89. //
  90. ASSERT( !FlagOn( Fcb->FcbState, FCB_STATE_EMBEDDED_DATA ));
  91. Vcb = Fcb->Vcb;
  92. LocalPsn.QuadPart = LocalSectorCount.QuadPart = 0;
  93. //
  94. // Lookup the entry containing this file offset.
  95. //
  96. if (FlagOn( Fcb->FcbState, FCB_STATE_VMCB_MAPPING )) {
  97. //
  98. // Map this offset into the metadata stream.
  99. //
  100. ASSERT( SectorOffset( Vcb, FileOffset ) == 0 );
  101. Result = UdfVmcbVbnToLbn( &Vcb->Vmcb,
  102. SectorsFromLlBytes( Vcb, FileOffset ),
  103. &LocalPsn.LowPart,
  104. &LocalSectorCount.LowPart );
  105. } else {
  106. //
  107. // Map this offset in a regular stream.
  108. //
  109. ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED ));
  110. Result = FsRtlLookupLargeMcbEntry( &Fcb->Mcb,
  111. LlSectorsFromBytes( Vcb, FileOffset ),
  112. &LocalPsn.QuadPart,
  113. &LocalSectorCount.QuadPart,
  114. NULL,
  115. NULL,
  116. NULL );
  117. }
  118. //
  119. // If within the Mcb then we use the data out of this entry and are nearly done.
  120. //
  121. if (Result) {
  122. if ( LocalPsn.QuadPart == -1 ) {
  123. //
  124. // Regular files can have holey allocations which represent unrecorded extents. For
  125. // such extents which are sandwiched in between recorded extents of the file, the Mcb
  126. // package tells us that it found a valid mapping but that it doesn't correspond to
  127. // any extents on the media yet. In this case, simply fake the disk offset. The
  128. // returned sector count is accurate.
  129. //
  130. *DiskOffset = 0;
  131. Recorded = FALSE;
  132. } else {
  133. //
  134. // Now mimic the effects of physical sector sparing. This may shrink the size of the
  135. // returned run if sparing interrupted the extent on disc.
  136. //
  137. ASSERT( LocalPsn.HighPart == 0 );
  138. if (Vcb->Pcb->SparingMcb) {
  139. LONGLONG SparingPsn;
  140. LONGLONG SparingSectorCount;
  141. if (FsRtlLookupLargeMcbEntry( Vcb->Pcb->SparingMcb,
  142. LocalPsn.LowPart,
  143. &SparingPsn,
  144. &SparingSectorCount,
  145. NULL,
  146. NULL,
  147. NULL )) {
  148. //
  149. // Only emit noise if we will really change anything as a result
  150. // of the sparing table.
  151. //
  152. if (SparingPsn != -1 ||
  153. SparingSectorCount < LocalSectorCount.QuadPart) {
  154. DebugTrace(( 0, Dbg, "UdfLookupAllocation, spared [%x, +%x) onto [%x, +%x)\n",
  155. LocalPsn.LowPart,
  156. LocalSectorCount.LowPart,
  157. (ULONG) SparingPsn,
  158. (ULONG) SparingSectorCount ));
  159. }
  160. //
  161. // If we did not land in a hole, map the sector.
  162. //
  163. if (SparingPsn != -1) {
  164. LocalPsn.QuadPart = SparingPsn;
  165. }
  166. //
  167. // The returned sector count now reduces the previous sector count.
  168. // If we landed in a hole, this indicates that the trailing edge of
  169. // the extent is spared, if not this indicates that the leading
  170. // edge is spared.
  171. //
  172. if (SparingSectorCount < LocalSectorCount.QuadPart) {
  173. LocalSectorCount.QuadPart = SparingSectorCount;
  174. }
  175. }
  176. }
  177. *DiskOffset = LlBytesFromSectors( Vcb, LocalPsn.QuadPart ) + SectorOffset( Vcb, FileOffset );
  178. //
  179. // Now we can apply method 2 fixups, which will again interrupt the size of the extent.
  180. //
  181. if (FlagOn( Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP )) {
  182. LARGE_INTEGER SectorsToRunout;
  183. SectorsToRunout.QuadPart= UdfMethod2NextRunoutInSectors( Vcb, *DiskOffset );
  184. if (SectorsToRunout.QuadPart < LocalSectorCount.QuadPart) {
  185. LocalSectorCount.QuadPart = SectorsToRunout.QuadPart;
  186. }
  187. *DiskOffset = UdfMethod2TransformByteOffset( Vcb, *DiskOffset );
  188. }
  189. }
  190. } else {
  191. //
  192. // We know that prior to this call the system has restricted IO to points within the
  193. // the file data. Since we failed to find a mapping this is an unrecorded extent at
  194. // the end of the file, so just conjure up a proper representation.
  195. //
  196. if ((Ccb != NULL) && FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
  197. LocalSectorCount.QuadPart = LlSectorsFromBytes( Vcb, ByteCount );
  198. *DiskOffset = FileOffset;
  199. Recorded = TRUE;
  200. } else {
  201. ASSERT( FileOffset < Fcb->FileSize.QuadPart );
  202. LocalSectorCount.QuadPart = LlSectorsFromBytes( Vcb, Fcb->FileSize.QuadPart ) -
  203. LlSectorsFromBytes( Vcb, FileOffset ) +
  204. 1;
  205. *DiskOffset = 0;
  206. Recorded = FALSE;
  207. }
  208. }
  209. //
  210. // Restrict to MAXULONG bytes of allocation
  211. //
  212. if (LocalSectorCount.QuadPart > SectorsFromBytes( Vcb, MAXULONG )) {
  213. *ByteCount = MAXULONG;
  214. } else {
  215. *ByteCount = BytesFromSectors( Vcb, LocalSectorCount.LowPart );
  216. }
  217. *ByteCount -= SectorOffset( Vcb, FileOffset );
  218. return Recorded;
  219. }
  220. VOID
  221. UdfDeletePcb (
  222. IN PPCB Pcb
  223. )
  224. /*++
  225. Routine Description:
  226. This routine deallocates a Pcb and all ancilliary structures.
  227. Arguments:
  228. Pcb - Pcb being deleted
  229. Return Value:
  230. None
  231. --*/
  232. {
  233. PUDF_PARTITION Partition;
  234. if (Pcb->SparingMcb) {
  235. FsRtlUninitializeLargeMcb( Pcb->SparingMcb );
  236. UdfFreePool( &Pcb->SparingMcb );
  237. }
  238. for (Partition = Pcb->Partition;
  239. Partition < &Pcb->Partition[Pcb->Partitions];
  240. Partition++) {
  241. switch (Partition->Type) {
  242. case Physical:
  243. UdfFreePool( &Partition->Physical.PartitionDescriptor );
  244. UdfFreePool( &Partition->Physical.SparingMap );
  245. break;
  246. case Virtual:
  247. case Uninitialized:
  248. break;
  249. default:
  250. ASSERT( FALSE );
  251. break;
  252. }
  253. }
  254. ExFreePool( Pcb );
  255. }
  256. NTSTATUS
  257. UdfInitializePcb (
  258. IN PIRP_CONTEXT IrpContext,
  259. IN PVCB Vcb,
  260. IN OUT PPCB *Pcb,
  261. IN PNSR_LVOL LVD
  262. )
  263. /*++
  264. Routine Description:
  265. This routine walks through the partition map of a Logical Volume Descriptor
  266. and builds an intializing Pcb from it. The Pcb will be ready to be used
  267. in searching for the partition descriptors of a volume.
  268. Arguments:
  269. Vcb - The volume this Pcb will pertain to
  270. Pcb - Caller's pointer to the Pcb
  271. LVD - The Logical Volume Descriptor being used
  272. Return Value:
  273. STATUS_SUCCESS if the partition map is good and the Pcb is built
  274. STATUS_DISK_CORRUPT_ERROR if corrupt maps are found
  275. STATUS_UNRECOGNIZED_VOLUME if noncompliant maps are found
  276. --*/
  277. {
  278. PPARTMAP_UDF_GENERIC Map;
  279. PUDF_PARTITION Partition;
  280. BOOLEAN Found;
  281. PAGED_CODE();
  282. //
  283. // Check the input parameters
  284. //
  285. ASSERT_OPTIONAL_PCB( *Pcb );
  286. DebugTrace(( +1, Dbg,
  287. "UdfInitializePcb, Lvd %08x\n",
  288. LVD ));
  289. //
  290. // Delete a pre-existing (partially initialized from a failed
  291. // crawl of a VDS) Pcb.
  292. //
  293. if (*Pcb != NULL) {
  294. UdfDeletePcb( *Pcb );
  295. *Pcb = NULL;
  296. }
  297. *Pcb = UdfCreatePcb( LVD->MapTableCount );
  298. //
  299. // Walk the table of partition maps intializing the Pcb for the descriptor
  300. // initialization pass.
  301. //
  302. for (Map = (PPARTMAP_UDF_GENERIC) LVD->MapTable,
  303. Partition = (*Pcb)->Partition;
  304. Partition < &(*Pcb)->Partition[(*Pcb)->Partitions];
  305. Map = Add2Ptr( Map, Map->Length, PPARTMAP_UDF_GENERIC ),
  306. Partition++) {
  307. //
  308. // Now check that this LVD can actually contain this map entry. First check that
  309. // the descriptor can contain the first few fields, then check that it can hold
  310. // all of the bytes claimed by the descriptor.
  311. //
  312. if (Add2Ptr( Map, sizeof( PARTMAP_GENERIC ), PCHAR ) > Add2Ptr( LVD, ISONsrLvolSize( LVD ), PCHAR ) ||
  313. Add2Ptr( Map, Map->Length, PCHAR ) > Add2Ptr( LVD, ISONsrLvolSize( LVD ), PCHAR )) {
  314. DebugTrace(( 0, Dbg,
  315. "UdfInitializePcb, map at +%04x beyond Lvd size %04x\n",
  316. (PCHAR) Map - (PCHAR) LVD,
  317. ISONsrLvolSize( LVD )));
  318. DebugTrace(( -1, Dbg,
  319. "UdfInitializePcb -> STATUS_DISK_CORRUPT_ERROR\n" ));
  320. return STATUS_DISK_CORRUPT_ERROR;
  321. }
  322. //
  323. // Now load up this map entry.
  324. //
  325. switch (Map->Type) {
  326. case PARTMAP_TYPE_PHYSICAL:
  327. {
  328. PPARTMAP_PHYSICAL MapPhysical = (PPARTMAP_PHYSICAL) Map;
  329. //
  330. // Type 1 - Physical Partition
  331. //
  332. DebugTrace(( 0, Dbg,
  333. "UdfInitializePcb, map reference %02x is Physical (Partition # %08x)\n",
  334. (Partition - (*Pcb)->Partition)/sizeof(UDF_PARTITION),
  335. MapPhysical->Partition ));
  336. //
  337. // It must be the case that the volume the partition is on is the first
  338. // one since we only do single disc UDF. This will have already been
  339. // checked by the caller.
  340. //
  341. if (MapPhysical->VolSetSeq > 1) {
  342. DebugTrace(( 0, Dbg,
  343. "UdfInitializePcb, ... but physical partition resides on volume set volume # %08x (> 1)!\n",
  344. MapPhysical->VolSetSeq ));
  345. DebugTrace(( -1, Dbg,
  346. "UdfInitializePcb -> STATUS_DISK_CORRUPT_ERROR\n" ));
  347. return STATUS_DISK_CORRUPT_ERROR;
  348. }
  349. SetFlag( (*Pcb)->Flags, PCB_FLAG_PHYSICAL_PARTITION );
  350. Partition->Type = Physical;
  351. Partition->Physical.PartitionNumber = MapPhysical->Partition;
  352. }
  353. break;
  354. case PARTMAP_TYPE_PROXY:
  355. //
  356. // Type 2 - a Proxy Partition, something not explicitly physical.
  357. //
  358. DebugTrace(( 0, Dbg,
  359. "UdfInitializePcb, map reference %02x is a proxy\n",
  360. (Partition - (*Pcb)->Partition)/sizeof(UDF_PARTITION)));
  361. //
  362. // Handle the various types of proxy partitions we recognize
  363. //
  364. if (UdfDomainIdentifierContained( &Map->PartID,
  365. &UdfVirtualPartitionDomainIdentifier,
  366. UDF_VERSION_150,
  367. UDF_VERSION_RECOGNIZED )) {
  368. {
  369. PPARTMAP_VIRTUAL MapVirtual = (PPARTMAP_VIRTUAL) Map;
  370. //
  371. // Only one of these guys can exist, since there can be only one VAT per media surface.
  372. //
  373. if (FlagOn( (*Pcb)->Flags, PCB_FLAG_VIRTUAL_PARTITION )) {
  374. DebugTrace(( 0, Dbg,
  375. "UdfInitializePcb, ... but this is a second virtual partition!?!!\n" ));
  376. DebugTrace(( -1, Dbg,
  377. "UdfInitializePcb -> STATUS_UNCRECOGNIZED_VOLUME\n" ));
  378. return STATUS_UNRECOGNIZED_VOLUME;
  379. }
  380. DebugTrace(( 0, Dbg,
  381. "UdfInitializePcb, ... Virtual (Partition # %08x)\n",
  382. MapVirtual->Partition ));
  383. SetFlag( (*Pcb)->Flags, PCB_FLAG_VIRTUAL_PARTITION );
  384. Partition->Type = Virtual;
  385. //
  386. // We will convert the partition number to a partition reference
  387. // before returning.
  388. //
  389. Partition->Virtual.RelatedReference = MapVirtual->Partition;
  390. }
  391. } else if (UdfDomainIdentifierContained( &Map->PartID,
  392. &UdfSparablePartitionDomainIdentifier,
  393. UDF_VERSION_150,
  394. UDF_VERSION_RECOGNIZED )) {
  395. {
  396. NTSTATUS Status;
  397. PPARTMAP_SPARABLE MapSparable = (PPARTMAP_SPARABLE) Map;
  398. //
  399. // It must be the case that the volume the partition is on is the first
  400. // one since we only do single disc UDF. This will have already been
  401. // checked by the caller.
  402. //
  403. if (MapSparable->VolSetSeq > 1) {
  404. DebugTrace(( 0, Dbg,
  405. "UdfInitializePcb, ... but sparable partition resides on volume set volume # %08x (> 1)!\n",
  406. MapSparable->VolSetSeq ));
  407. DebugTrace(( -1, Dbg,
  408. "UdfInitializePcb -> STATUS_DISK_CORRUPT_ERROR\n" ));
  409. return STATUS_DISK_CORRUPT_ERROR;
  410. }
  411. DebugTrace(( 0, Dbg,
  412. "UdfInitializePcb, ... Sparable (Partition # %08x)\n",
  413. MapSparable->Partition ));
  414. //
  415. // We pretend that sparable partitions are basically the same as
  416. // physical partitions. Since we are not r/w (and will never be
  417. // on media that requires host-based sparing in any case), this
  418. // is a good simplification.
  419. //
  420. SetFlag( (*Pcb)->Flags, PCB_FLAG_SPARABLE_PARTITION );
  421. Partition->Type = Physical;
  422. Partition->Physical.PartitionNumber = MapSparable->Partition;
  423. //
  424. // Save this map for use when the partition descriptor is found.
  425. // We can't load the sparing table at this time because we have
  426. // to turn the Lbn->Psn mapping into a Psn->Psn mapping. UDF
  427. // believes that the way sparing will be used in concert with
  428. // the Lbn->Psn mapping engine (like UdfLookupPsnOfExtent).
  429. //
  430. // Unfortunately, this would be a bit painful at this time.
  431. // The users of UdfLookupPsnOfExtent would need to iterate
  432. // over a new interface (not so bad) but the Vmcb package
  433. // would need to be turned inside out so that it didn't do
  434. // the page-filling alignment of blocks in the metadata
  435. // stream - instead, UdfLookupMetaVsnOfExtent would need to
  436. // do this itself. I choose to lay the sparing engine into
  437. // the read path and raw sector read engine instead.
  438. //
  439. Partition->Physical.SparingMap = FsRtlAllocatePoolWithTag( PagedPool,
  440. sizeof(PARTMAP_SPARABLE),
  441. TAG_NSR_FSD);
  442. RtlCopyMemory( Partition->Physical.SparingMap,
  443. MapSparable,
  444. sizeof(PARTMAP_SPARABLE));
  445. }
  446. } else {
  447. DebugTrace(( 0, Dbg,
  448. "UdfInitializePcb, ... but we don't recognize this proxy!\n" ));
  449. DebugTrace(( -1, Dbg,
  450. "UdfInitializePcb -> STATUS_UNRECOGNIZED_VOLUME\n" ));
  451. return STATUS_UNRECOGNIZED_VOLUME;
  452. }
  453. break;
  454. default:
  455. DebugTrace(( 0, Dbg,
  456. "UdfInitializePcb, map reference %02x is of unknown type %02x\n",
  457. Map->Type ));
  458. DebugTrace(( -1, Dbg,
  459. "UdfInitializePcb -> STATUS_UNRECOGNIZED_VOLUME\n" ));
  460. return STATUS_UNRECOGNIZED_VOLUME;
  461. break;
  462. }
  463. }
  464. if (!FlagOn( (*Pcb)->Flags, PCB_FLAG_PHYSICAL_PARTITION | PCB_FLAG_SPARABLE_PARTITION )) {
  465. DebugTrace(( 0, Dbg,
  466. "UdfInitializePcb, no physical partition seen on this logical volume!\n" ));
  467. DebugTrace(( -1, Dbg,
  468. "UdfInitializePcb -> STATUS_UNRECOGNIZED_VOLUME\n" ));
  469. return STATUS_UNRECOGNIZED_VOLUME;
  470. }
  471. if (FlagOn( (*Pcb)->Flags, PCB_FLAG_VIRTUAL_PARTITION )) {
  472. PUDF_PARTITION Host;
  473. //
  474. // Confirm the validity of any type 2 virtual maps on this volume
  475. // and convert partition numbers to partition references that will
  476. // immediately index an element of the Pcb.
  477. //
  478. for (Partition = (*Pcb)->Partition;
  479. Partition < &(*Pcb)->Partition[(*Pcb)->Partitions];
  480. Partition++) {
  481. if (Partition->Type == Virtual) {
  482. //
  483. // Go find the partition this thing is talking about
  484. //
  485. Found = FALSE;
  486. for (Host = (*Pcb)->Partition;
  487. Host < &(*Pcb)->Partition[(*Pcb)->Partitions];
  488. Host++) {
  489. if (Host->Type == Physical &&
  490. Host->Physical.PartitionNumber ==
  491. Partition->Virtual.RelatedReference) {
  492. Partition->Virtual.RelatedReference =
  493. (USHORT)(Host - (*Pcb)->Partition)/sizeof(UDF_PARTITION);
  494. Found = TRUE;
  495. break;
  496. }
  497. }
  498. //
  499. // Failure to find a physical partition for this virtual guy
  500. // is not a good sign.
  501. //
  502. if (!Found) {
  503. return STATUS_DISK_CORRUPT_ERROR;
  504. }
  505. }
  506. }
  507. }
  508. DebugTrace(( -1, Dbg,
  509. "UdfInitializePcb -> STATUS_SUCCESS\n" ));
  510. return STATUS_SUCCESS;
  511. }
  512. VOID
  513. UdfAddToPcb (
  514. IN PPCB Pcb,
  515. IN PNSR_PART PartitionDescriptor
  516. )
  517. /*++
  518. Routine Description:
  519. This routine possibly adds a partition descriptor into a Pcb if it
  520. turns out to be of higher precendence than a descriptor already
  521. present. Used in building a Pcb already initialized in preperation
  522. for UdfCompletePcb.
  523. Arguments:
  524. Vcb - Vcb of the volume the Pcb describes
  525. Pcb - Pcb being filled in
  526. Return Value:
  527. None. An old partition descriptor may be returned in the input field.
  528. --*/
  529. {
  530. USHORT Reference;
  531. PAGED_CODE();
  532. //
  533. // Check inputs
  534. //
  535. ASSERT_PCB( Pcb );
  536. ASSERT( PartitionDescriptor );
  537. for (Reference = 0;
  538. Reference < Pcb->Partitions;
  539. Reference++) {
  540. DebugTrace(( 0, Dbg, "UdfAddToPcb, considering partition reference %d (type %d)\n", (ULONG)Reference, Pcb->Partition[Reference].Type));
  541. switch (Pcb->Partition[Reference].Type) {
  542. case Physical:
  543. //
  544. // Now possibly store this descriptor in the Pcb if it is
  545. // the partition number for this partition reference.
  546. //
  547. if (Pcb->Partition[Reference].Physical.PartitionNumber == PartitionDescriptor->Number) {
  548. //
  549. // It seems to be legal (if questionable) for multiple partition maps to reference
  550. // the same partition descriptor. So we make a copy of the descriptor for each
  551. // referencing partitionmap to make life easier when it comes to freeing it.
  552. //
  553. UdfStoreVolumeDescriptorIfPrevailing( (PNSR_VD_GENERIC *) &Pcb->Partition[Reference].Physical.PartitionDescriptor,
  554. (PNSR_VD_GENERIC) PartitionDescriptor );
  555. }
  556. break;
  557. case Virtual:
  558. break;
  559. default:
  560. ASSERT(FALSE);
  561. break;
  562. }
  563. }
  564. }
  565. NTSTATUS
  566. UdfCompletePcb (
  567. IN PIRP_CONTEXT IrpContext,
  568. IN PVCB Vcb,
  569. IN PPCB Pcb
  570. )
  571. /*++
  572. Routine Description:
  573. This routine completes initialization of a Pcb which has been filled
  574. in with partition descriptors. Initialization-time data such as the
  575. physical partition descriptors will be returned to the system.
  576. Arguments:
  577. Vcb - Vcb of the volume the Pcb describes
  578. Pcb - Pcb being completed
  579. Return Value:
  580. NTSTATUS according to whether intialization completion was succesful
  581. --*/
  582. {
  583. ULONG Reference;
  584. NTSTATUS Status;
  585. PAGED_CODE();
  586. //
  587. // Check inputs
  588. //
  589. ASSERT_IRP_CONTEXT( IrpContext );
  590. ASSERT_VCB( Vcb );
  591. ASSERT_PCB( Pcb );
  592. DebugTrace(( +1, Dbg, "UdfCompletePcb, Vcb %08x Pcb %08x\n", Vcb, Pcb ));
  593. //
  594. // Complete intialization all physical partitions
  595. //
  596. for (Reference = 0;
  597. Reference < Pcb->Partitions;
  598. Reference++) {
  599. DebugTrace(( 0, Dbg, "UdfCompletePcb, Examining Ref %u (type %u)!\n", Reference, Pcb->Partition[Reference].Type));
  600. switch (Pcb->Partition[Reference].Type) {
  601. case Physical:
  602. if (Pcb->Partition[Reference].Physical.PartitionDescriptor == NULL) {
  603. DebugTrace(( 0, Dbg,
  604. "UdfCompletePcb, ... but didn't find Partition# %u!\n",
  605. Pcb->Partition[Reference].Physical.PartitionNumber ));
  606. DebugTrace(( -1, Dbg, "UdfCompletePcb -> STATUS_DISK_CORRUPT_ERROR\n" ));
  607. return STATUS_DISK_CORRUPT_ERROR;
  608. }
  609. Pcb->Partition[Reference].Physical.Start =
  610. Pcb->Partition[Reference].Physical.PartitionDescriptor->Start;
  611. Pcb->Partition[Reference].Physical.Length =
  612. Pcb->Partition[Reference].Physical.PartitionDescriptor->Length;
  613. //
  614. // Retrieve the sparing information at this point if appropriate.
  615. // We have to do this when we can map logical -> physical blocks.
  616. //
  617. if (Pcb->Partition[Reference].Physical.SparingMap) {
  618. Status = UdfLoadSparingTables( IrpContext,
  619. Vcb,
  620. Pcb,
  621. Reference );
  622. if (!NT_SUCCESS( Status )) {
  623. DebugTrace(( -1, Dbg,
  624. "UdfCompletePcb -> %08x\n", Status ));
  625. return Status;
  626. }
  627. }
  628. DebugTrace(( 0, Dbg, "Start Psn: 0x%X, sectors: 0x%x\n",
  629. Pcb->Partition[Reference].Physical.Start,
  630. Pcb->Partition[Reference].Physical.Length));
  631. //
  632. // We will not need the descriptor or sparing map anymore, so drop them.
  633. //
  634. UdfFreePool( &Pcb->Partition[Reference].Physical.PartitionDescriptor );
  635. UdfFreePool( &Pcb->Partition[Reference].Physical.SparingMap );
  636. break;
  637. case Virtual:
  638. break;
  639. default:
  640. ASSERT(FALSE);
  641. break;
  642. }
  643. }
  644. DebugTrace(( -1, Dbg, "UdfCompletePcb -> STATUS_SUCCESS\n" ));
  645. return STATUS_SUCCESS;
  646. }
  647. BOOLEAN
  648. UdfEquivalentPcb (
  649. IN PIRP_CONTEXT IrpContext,
  650. IN PPCB Pcb1,
  651. IN PPCB Pcb2
  652. )
  653. /*++
  654. Routine Description:
  655. This routine compares two completed Pcbs to see if they appear equivalent.
  656. Arguments:
  657. Pcb1 - Pcb being compared
  658. Pcb2 - Pcb being compared
  659. Return Value:
  660. BOOLEAN according to whether they are equivalent (TRUE, else FALSE)
  661. --*/
  662. {
  663. ULONG Index;
  664. PAGED_CODE();
  665. //
  666. // Check input.
  667. //
  668. ASSERT_IRP_CONTEXT( IrpContext );
  669. if (Pcb1->Partitions != Pcb2->Partitions) {
  670. return FALSE;
  671. }
  672. for (Index = 0;
  673. Index < Pcb1->Partitions;
  674. Index++) {
  675. //
  676. // First check that the partitions are of the same type.
  677. //
  678. if (Pcb1->Partition[Index].Type != Pcb2->Partition[Index].Type) {
  679. return FALSE;
  680. }
  681. //
  682. // Now the map content must be the same ...
  683. //
  684. switch (Pcb1->Partition[Index].Type) {
  685. case Physical:
  686. if (Pcb1->Partition[Index].Physical.PartitionNumber != Pcb2->Partition[Index].Physical.PartitionNumber ||
  687. Pcb1->Partition[Index].Physical.Length != Pcb2->Partition[Index].Physical.Length ||
  688. Pcb1->Partition[Index].Physical.Start != Pcb2->Partition[Index].Physical.Start) {
  689. return FALSE;
  690. }
  691. break;
  692. case Virtual:
  693. if (Pcb1->Partition[Index].Virtual.RelatedReference != Pcb2->Partition[Index].Virtual.RelatedReference) {
  694. return FALSE;
  695. }
  696. break;
  697. default:
  698. ASSERT( FALSE);
  699. return FALSE;
  700. break;
  701. }
  702. }
  703. //
  704. // All map elements were equivalent.
  705. //
  706. return TRUE;
  707. }
  708. ULONG
  709. UdfLookupPsnOfExtent (
  710. IN PIRP_CONTEXT IrpContext,
  711. IN PVCB Vcb,
  712. IN USHORT Reference,
  713. IN ULONG Lbn,
  714. IN ULONG Len
  715. )
  716. /*++
  717. Routine Description:
  718. This routine maps the input logical block extent on a given partition to
  719. a starting physical sector. It doubles as a bounds checker - if the routine
  720. does not raise, the caller is guaranteed that the extent lies within the
  721. partition.
  722. Arguments:
  723. Vcb - Vcb of logical volume
  724. Reference - Partition reference to use in the mapping
  725. Lbn - Logical block number
  726. Len - Length of extent in bytes
  727. Return Value:
  728. ULONG physical sector number
  729. --*/
  730. {
  731. PPCB Pcb = Vcb->Pcb;
  732. ULONG Psn;
  733. PBCB Bcb;
  734. LARGE_INTEGER Offset;
  735. PULONG MappedLbn;
  736. PAGED_CODE();
  737. //
  738. // Check inputs
  739. //
  740. ASSERT_IRP_CONTEXT( IrpContext );
  741. ASSERT_VCB( Vcb );
  742. ASSERT_PCB( Pcb );
  743. DebugTrace(( +1, Dbg, "UdfLookupPsnOfExtent, [%04x/%08x, +%08x)\n", Reference, Lbn, Len ));
  744. if (Reference < Pcb->Partitions) {
  745. while (TRUE) {
  746. switch (Pcb->Partition[Reference].Type) {
  747. case Physical:
  748. //
  749. // Check that the input extent lies inside the partition. Calculate the
  750. // Lbn of the last block and see that it is interior.
  751. //
  752. if (SectorsFromBlocks( Vcb, Lbn ) + SectorsFromBytes( Vcb, Len ) >
  753. Pcb->Partition[Reference].Physical.Length) {
  754. goto NoGood;
  755. }
  756. Psn = Pcb->Partition[Reference].Physical.Start + SectorsFromBlocks( Vcb, Lbn );
  757. DebugTrace(( -1, Dbg, "UdfLookupPsnOfExtent -> %08x\n", Psn ));
  758. return Psn;
  759. case Virtual:
  760. //
  761. // Bounds check. Per UDF 2.00 2.3.10 and implied in UDF 1.50, virtual
  762. // extent lengths cannot be greater than one block in size. Lbn must also
  763. // fall within the VAT!
  764. //
  765. if ((Lbn >= Vcb->VATEntryCount) || (Len > BlockSize( Vcb ))) {
  766. DebugTrace(( 0, Dbg, "UdfLookupPsnOfExtent() - Either Lbn (0x%x) > VatLbns (0x%X), or len (0x%x) > blocksize (0x%x)\n", Lbn, Vcb->VATEntryCount, Len, BlockSize(Vcb)));
  767. goto NoGood;
  768. }
  769. try {
  770. Bcb = NULL;
  771. //
  772. // Calculate the location of the mapping element in the VAT
  773. // and retrieve. Bias by the size of the VAT header, if any.
  774. //
  775. Offset.QuadPart = Vcb->OffsetToFirstVATEntry + Lbn * sizeof(ULONG);
  776. CcMapData( Vcb->VatFcb->FileObject,
  777. &Offset,
  778. sizeof(ULONG),
  779. TRUE,
  780. &Bcb,
  781. &MappedLbn );
  782. //
  783. // Now rewrite the inputs in terms of the virtual mapping. We
  784. // will reloop to perform the logical -> physical mapping.
  785. //
  786. DebugTrace(( 0, Dbg,
  787. "UdfLookupPsnOfExtent, Mapping V %04x/%08x -> L %04x/%08x\n",
  788. Reference,
  789. Lbn,
  790. Pcb->Partition[Reference].Virtual.RelatedReference,
  791. *MappedLbn ));
  792. Lbn = *MappedLbn;
  793. Reference = Pcb->Partition[Reference].Virtual.RelatedReference;
  794. } finally {
  795. DebugUnwind( UdfLookupPsnOfExtent );
  796. UdfUnpinData( IrpContext, &Bcb );
  797. }
  798. //
  799. // An Lbn of ~0 in the VAT is defined to indicate that the sector is unused,
  800. // so we should never see such a thing.
  801. //
  802. if (Lbn == ~0) {
  803. goto NoGood;
  804. }
  805. break;
  806. default:
  807. ASSERT(FALSE);
  808. break;
  809. }
  810. }
  811. }
  812. NoGood:
  813. //
  814. // Some people have misinterpreted a partition number to equal a
  815. // partition reference, or perhaps this is just corrupt media.
  816. //
  817. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  818. }
  819. ULONG
  820. UdfLookupMetaVsnOfExtent (
  821. IN PIRP_CONTEXT IrpContext,
  822. IN PVCB Vcb,
  823. IN USHORT Reference,
  824. IN ULONG Lbn,
  825. IN ULONG Len,
  826. IN BOOLEAN ExactEnd
  827. )
  828. /*++
  829. Routine Description:
  830. This routine maps the input logical block extent on a given partition to
  831. a starting virtual block in the metadata stream. If a mapping does not
  832. exist, one will be created and the metadata stream extended.
  833. Callers must hold NO mappings into the VMCB stream when calling this
  834. function.
  835. Arguments:
  836. Vcb - Vcb of logical volume
  837. Reference - Partition reference to use in the mapping
  838. Lbn - Logical block number
  839. Len - Length of extent in bytes
  840. ExactEnd - Indicates the extension policy if these blocks are not mapped.
  841. Return Value:
  842. ULONG virtual sector number
  843. Raised status if the Lbn extent is split across multiple Vbn extents.
  844. --*/
  845. {
  846. ULONG Vsn;
  847. ULONG Psn;
  848. ULONG SectorCount;
  849. BOOLEAN Result;
  850. BOOLEAN UnwindExtension = FALSE;
  851. BOOLEAN UnwindVmcb = FALSE;
  852. LONGLONG UnwindAllocationSize;
  853. PFCB Fcb = NULL;
  854. //
  855. // Check inputs
  856. //
  857. ASSERT_IRP_CONTEXT( IrpContext );
  858. ASSERT_VCB( Vcb );
  859. //
  860. // The extent must be a multiple of blocksize
  861. //
  862. if ((0 == Len) || BlockOffset( Vcb, Len)) {
  863. UdfRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  864. }
  865. //
  866. // Get the physical mapping of the extent. The Mcb package operates on ULONG/ULONG
  867. // keys and values so we must render our 48bit address into 32. We can do this since
  868. // this is a single surface implementation, and it is guaranteed that a surface cannot
  869. // contain more than MAXULONG physical sectors.
  870. //
  871. Psn = UdfLookupPsnOfExtent( IrpContext,
  872. Vcb,
  873. Reference,
  874. Lbn,
  875. Len );
  876. //
  877. // Use try-finally for cleanup
  878. //
  879. try {
  880. //
  881. // We must safely establish a mapping and extend the metadata stream so that cached
  882. // reads can occur on this new extent. This lock was moved out here (rather than just
  883. // protecting the actual Fcb changes) to protect against mappings being made
  884. // by other threads between this thread extending the vmcb and calling CcSetFileSizes.
  885. // this would result in zeroed pages being mapped...
  886. //
  887. Fcb = Vcb->MetadataFcb;
  888. UdfLockFcb( IrpContext, Fcb );
  889. //
  890. // Add / lookup the mapping. We know that it is being added to the end of the stream.
  891. //
  892. UnwindVmcb = UdfAddVmcbMapping(IrpContext,
  893. &Vcb->Vmcb,
  894. Psn,
  895. SectorsFromBytes( Vcb, Len ),
  896. ExactEnd,
  897. &Vsn,
  898. &SectorCount );
  899. ASSERT( SectorCount >= SectorsFromBytes( Vcb, Len));
  900. //
  901. // If this was a new mapping, then we need to extend the Vmcb file size
  902. //
  903. if (UnwindVmcb) {
  904. UnwindAllocationSize = Fcb->AllocationSize.QuadPart;
  905. UnwindExtension = TRUE;
  906. Fcb->AllocationSize.QuadPart =
  907. Fcb->FileSize.QuadPart =
  908. Fcb->ValidDataLength.QuadPart = LlBytesFromSectors( Vcb, Vsn + SectorCount);
  909. CcSetFileSizes( Fcb->FileObject, (PCC_FILE_SIZES) &Fcb->AllocationSize );
  910. UnwindExtension = FALSE;
  911. }
  912. }
  913. finally {
  914. if (UnwindExtension) {
  915. ULONG FirstZappedVsn;
  916. //
  917. // Strip off the additional mappings we made.
  918. //
  919. Fcb->AllocationSize.QuadPart =
  920. Fcb->FileSize.QuadPart =
  921. Fcb->ValidDataLength.QuadPart = UnwindAllocationSize;
  922. FirstZappedVsn = SectorsFromLlBytes( Vcb, UnwindAllocationSize );
  923. if (UnwindVmcb) {
  924. UdfRemoveVmcbMapping( &Vcb->Vmcb,
  925. FirstZappedVsn,
  926. Vsn + SectorCount - FirstZappedVsn );
  927. }
  928. CcSetFileSizes( Fcb->FileObject, (PCC_FILE_SIZES) &Fcb->AllocationSize );
  929. }
  930. if (Fcb) { UdfUnlockFcb( IrpContext, Fcb ); }
  931. }
  932. return Vsn;
  933. }
  934. //
  935. // Local support routine.
  936. //
  937. PPCB
  938. UdfCreatePcb (
  939. IN ULONG NumberOfPartitions
  940. )
  941. /*++
  942. Routine Description:
  943. This routine creates a new Pcb of the indicated size.
  944. Arguments:
  945. NumberOfPartitions - Number of partitions this Pcb will describe
  946. Return Value:
  947. PPCB - the Pcb created
  948. --*/
  949. {
  950. PPCB Pcb;
  951. ULONG Size = sizeof(PCB) + sizeof(UDF_PARTITION)*NumberOfPartitions;
  952. PAGED_CODE();
  953. ASSERT( NumberOfPartitions );
  954. ASSERT( NumberOfPartitions < MAXUSHORT );
  955. Pcb = (PPCB) FsRtlAllocatePoolWithTag( UdfPagedPool,
  956. Size,
  957. TAG_PCB );
  958. RtlZeroMemory( Pcb, Size );
  959. Pcb->NodeTypeCode = UDFS_NTC_PCB;
  960. Pcb->NodeByteSize = (USHORT) Size;
  961. Pcb->Partitions = (USHORT)NumberOfPartitions;
  962. return Pcb;
  963. }
  964. //
  965. // Internal support routine
  966. //
  967. NTSTATUS
  968. UdfLoadSparingTables(
  969. PIRP_CONTEXT IrpContext,
  970. PVCB Vcb,
  971. PPCB Pcb,
  972. ULONG Reference
  973. )
  974. /*++
  975. Routine Description:
  976. This routine reads the sparing tables for a partition and fills
  977. in the sparing Mcb.
  978. Arguments:
  979. Vcb - the volume hosting the spared partition
  980. Pcb - the partion block corresponding to the volume
  981. Reference - the partition reference being pulled in
  982. Return Value:
  983. NTSTATUS according to whether the sparing tables were loaded
  984. --*/
  985. {
  986. NTSTATUS Status;
  987. ULONG SparingTable;
  988. PULONG SectorBuffer;
  989. ULONG Psn;
  990. ULONG RemainingBytes;
  991. ULONG ByteOffset;
  992. ULONG TotalBytes;
  993. BOOLEAN Complete;
  994. PSPARING_TABLE_HEADER Header;
  995. PSPARING_TABLE_ENTRY Entry;
  996. PUDF_PARTITION Partition = &Pcb->Partition[Reference];
  997. PPARTMAP_SPARABLE Map = Partition->Physical.SparingMap;
  998. ASSERT_IRP_CONTEXT( IrpContext );
  999. ASSERT_VCB( Vcb );
  1000. ASSERT( Map != NULL );
  1001. DebugTrace(( +1, Dbg, "UdfLoadSparingTables, Vcb %08x, PcbPartition %08x, Map @ %08x\n", Vcb, Partition, Map ));
  1002. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, Map sez: PacketLen %u, NTables %u, TableSize %u\n",
  1003. Map->PacketLength,
  1004. Map->NumSparingTables,
  1005. Map->TableSize));
  1006. //
  1007. // Check that the sparable map appears sane. If there are no sparing tables that
  1008. // is pretty OK, and it'll wind up looking like a regular physical partition.
  1009. //
  1010. if (Map->NumSparingTables == 0) {
  1011. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, no sparing tables claimed!\n" ));
  1012. DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_SUCCESS\n" ));
  1013. return STATUS_SUCCESS;
  1014. }
  1015. if (Map->NumSparingTables > sizeof(Map->TableLocation)/sizeof(ULONG)) {
  1016. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, too many claimed tables to fit! (max %u)\n",
  1017. sizeof(Map->TableLocation)/sizeof(ULONG)));
  1018. DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_DISK_CORRUPT_ERROR\n" ));
  1019. return STATUS_DISK_CORRUPT_ERROR;
  1020. }
  1021. if ((Map->PacketLength != UDF_SPARING_PACKET_LENGTH_CDRW) &&
  1022. (Map->PacketLength != UDF_SPARING_PACKET_LENGTH_DVDRW)) {
  1023. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, packet size is %u!\n",
  1024. Map->PacketLength));
  1025. DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_DISK_CORRUPT_ERROR\n" ));
  1026. return STATUS_DISK_CORRUPT_ERROR;
  1027. }
  1028. if (Map->TableSize < sizeof(SPARING_TABLE_HEADER) ||
  1029. (Map->TableSize - sizeof(SPARING_TABLE_HEADER)) % sizeof(SPARING_TABLE_ENTRY) != 0) {
  1030. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, sparing table size is too small or unaligned!\n" ));
  1031. DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_DISK_CORRUPT_ERROR\n" ));
  1032. return STATUS_DISK_CORRUPT_ERROR;
  1033. }
  1034. #ifdef UDF_SANITY
  1035. DebugTrace(( 0, Dbg, "UdfLoadSparingTables" ));
  1036. for (SparingTable = 0; SparingTable < Map->NumSparingTables; SparingTable++) {
  1037. DebugTrace(( 0, Dbg, ", Table %u @ %x", SparingTable, Map->TableLocation[SparingTable] ));
  1038. }
  1039. DebugTrace(( 0, Dbg, "\n" ));
  1040. #endif
  1041. //
  1042. // If a sparing mcb doesn't exist, manufacture one.
  1043. //
  1044. if (Pcb->SparingMcb == NULL) {
  1045. Pcb->SparingMcb = FsRtlAllocatePoolWithTag( PagedPool, sizeof(LARGE_MCB), TAG_SPARING_MCB );
  1046. FsRtlInitializeLargeMcb( Pcb->SparingMcb, PagedPool );
  1047. }
  1048. SectorBuffer = FsRtlAllocatePoolWithTag( PagedPool, PAGE_SIZE, TAG_NSR_FSD );
  1049. //
  1050. // Now loop across the sparing tables and pull the data in.
  1051. //
  1052. try {
  1053. for (Complete = FALSE, SparingTable = 0;
  1054. SparingTable < Map->NumSparingTables;
  1055. SparingTable++) {
  1056. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, loading sparing table %u!\n",
  1057. SparingTable ));
  1058. ByteOffset = 0;
  1059. TotalBytes = 0;
  1060. RemainingBytes = 0;
  1061. do {
  1062. if (RemainingBytes == 0) {
  1063. (VOID) UdfReadSectors( IrpContext,
  1064. BytesFromSectors( Vcb, Map->TableLocation[SparingTable] ) + ByteOffset,
  1065. SectorSize( Vcb ),
  1066. FALSE,
  1067. SectorBuffer,
  1068. Vcb->TargetDeviceObject );
  1069. //
  1070. // Verify the descriptor at the head of the sparing table. If it is not
  1071. // valid, we just break out for a chance at the next table, if any.
  1072. //
  1073. if (ByteOffset == 0) {
  1074. Header = (PSPARING_TABLE_HEADER) SectorBuffer;
  1075. if (!UdfVerifyDescriptor( IrpContext,
  1076. &Header->Destag,
  1077. 0,
  1078. SectorSize( Vcb ),
  1079. Header->Destag.Lbn,
  1080. TRUE )) {
  1081. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, sparing table %u didn't verify destag!\n",
  1082. SparingTable ));
  1083. break;
  1084. }
  1085. if (!UdfUdfIdentifierContained( &Header->RegID,
  1086. &UdfSparingTableIdentifier,
  1087. UDF_VERSION_150,
  1088. UDF_VERSION_RECOGNIZED,
  1089. OSCLASS_INVALID,
  1090. OSIDENTIFIER_INVALID)) {
  1091. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, sparing table %u didn't verify regid!\n",
  1092. SparingTable ));
  1093. break;
  1094. }
  1095. //
  1096. // Calculate the total number bytes this map spans and check it against what
  1097. // we were told the sparing table sizes are.
  1098. //
  1099. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, Sparing table %u has %u entries\n",
  1100. SparingTable,
  1101. Header->TableEntries ));
  1102. TotalBytes = sizeof(SPARING_TABLE_HEADER) + Header->TableEntries * sizeof(SPARING_TABLE_ENTRY);
  1103. if (Map->TableSize < TotalBytes) {
  1104. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, sparing table #ents %u overflows allocation!\n",
  1105. Header->TableEntries ));
  1106. break;
  1107. }
  1108. //
  1109. // So far so good, advance past the header.
  1110. //
  1111. ByteOffset = sizeof(SPARING_TABLE_HEADER);
  1112. Entry = Add2Ptr( SectorBuffer, sizeof(SPARING_TABLE_HEADER), PSPARING_TABLE_ENTRY );
  1113. } else {
  1114. //
  1115. // Pick up in the new sector.
  1116. //
  1117. Entry = (PSPARING_TABLE_ENTRY) SectorBuffer;
  1118. }
  1119. RemainingBytes = Min( SectorSize( Vcb ), TotalBytes - ByteOffset );
  1120. }
  1121. //
  1122. // Add the mapping. Since sparing tables are an Lbn->Psn mapping,
  1123. // very odd, and I want to simplify things by putting the sparing
  1124. // in right at IO dispatch, translate this to a Psn->Psn mapping.
  1125. //
  1126. if (Entry->Original != UDF_SPARING_AVALIABLE &&
  1127. Entry->Original != UDF_SPARING_DEFECTIVE) {
  1128. Psn = Partition->Physical.Start + SectorsFromBlocks( Vcb, Entry->Original );
  1129. DebugTrace(( 0, Dbg, "UdfLoadSparingTables, mapping from Psn %x (Lbn %x) -> Psn %x\n",
  1130. Psn,
  1131. Entry->Original,
  1132. Entry->Mapped ));
  1133. FsRtlAddLargeMcbEntry( Pcb->SparingMcb,
  1134. Psn,
  1135. Entry->Mapped,
  1136. Map->PacketLength);
  1137. }
  1138. //
  1139. // Advance to the next, and drop out if we've hit the end.
  1140. //
  1141. ByteOffset += sizeof(SPARING_TABLE_ENTRY);
  1142. RemainingBytes -= sizeof(SPARING_TABLE_ENTRY);
  1143. Entry++;
  1144. } while ( ByteOffset < TotalBytes );
  1145. }
  1146. } finally {
  1147. DebugUnwind( UdfLoadSparingTables );
  1148. UdfFreePool( &SectorBuffer );
  1149. }
  1150. DebugTrace(( -1, Dbg, "UdfLoadSparingTables -> STATUS_SUCCESS\n" ));
  1151. return STATUS_SUCCESS;
  1152. }