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.

2787 lines
63 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. StrucSup.c
  5. Abstract:
  6. This module implements the Cdfs in-memory data structure manipulation
  7. routines
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Brian Andrew [BrianAn] 01-July-1995
  11. Revision History:
  12. // @@END_DDKSPLIT
  13. --*/
  14. #include "CdProcs.h"
  15. //
  16. // The Bug check file id for this module
  17. //
  18. #define BugCheckFileId (CDFS_BUG_CHECK_STRUCSUP)
  19. //
  20. // Local macros
  21. //
  22. //
  23. // PFCB
  24. // CdAllocateFcbData (
  25. // IN PIRP_CONTEXT IrpContext
  26. // );
  27. //
  28. // VOID
  29. // CdDeallocateFcbData (
  30. // IN PIRP_CONTEXT IrpContext,
  31. // IN PFCB Fcb
  32. // );
  33. //
  34. // PFCB
  35. // CdAllocateFcbIndex (
  36. // IN PIRP_CONTEXT IrpContext
  37. // );
  38. //
  39. // VOID
  40. // CdDeallocateFcbIndex (
  41. // IN PIRP_CONTEXT IrpContext,
  42. // IN PFCB Fcb
  43. // );
  44. //
  45. // PFCB_NONPAGED
  46. // CdAllocateFcbNonpaged (
  47. // IN PIRP_CONTEXT IrpContext
  48. // );
  49. //
  50. // VOID
  51. // CdDeallocateFcbNonpaged (
  52. // IN PIRP_CONTEXT IrpContext,
  53. // IN PFCB_NONPAGED FcbNonpaged
  54. // );
  55. //
  56. // PCCB
  57. // CdAllocateCcb (
  58. // IN PIRP_CONTEXT IrpContext
  59. // );
  60. //
  61. // VOID
  62. // CdDeallocateCcb (
  63. // IN PIRP_CONTEXT IrpContext,
  64. // IN PCCB Ccb
  65. // );
  66. //
  67. #define CdAllocateFcbData(IC) \
  68. FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_DATA, TAG_FCB_DATA )
  69. #define CdDeallocateFcbData(IC,F) \
  70. ExFreePool( F )
  71. #define CdAllocateFcbIndex(IC) \
  72. FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_INDEX, TAG_FCB_INDEX )
  73. #define CdDeallocateFcbIndex(IC,F) \
  74. ExFreePool( F )
  75. #define CdAllocateFcbNonpaged(IC) \
  76. ExAllocatePoolWithTag( CdNonPagedPool, sizeof( FCB_NONPAGED ), TAG_FCB_NONPAGED )
  77. #define CdDeallocateFcbNonpaged(IC,FNP) \
  78. ExFreePool( FNP )
  79. #define CdAllocateCcb(IC) \
  80. FsRtlAllocatePoolWithTag( CdPagedPool, sizeof( CCB ), TAG_CCB )
  81. #define CdDeallocateCcb(IC,C) \
  82. ExFreePool( C )
  83. //
  84. // Local structures
  85. //
  86. typedef struct _FCB_TABLE_ELEMENT {
  87. FILE_ID FileId;
  88. PFCB Fcb;
  89. } FCB_TABLE_ELEMENT, *PFCB_TABLE_ELEMENT;
  90. //
  91. // Local macros
  92. //
  93. //
  94. // VOID
  95. // CdInsertFcbTable (
  96. // IN PIRP_CONTEXT IrpContext,
  97. // IN PFCB Fcb
  98. // );
  99. //
  100. // VOID
  101. // CdDeleteFcbTable (
  102. // IN PIRP_CONTEXT IrpContext,
  103. // IN PFCB Fcb
  104. // );
  105. //
  106. #define CdInsertFcbTable(IC,F) { \
  107. FCB_TABLE_ELEMENT _Key; \
  108. _Key.Fcb = (F); \
  109. _Key.FileId = (F)->FileId; \
  110. RtlInsertElementGenericTable( &(F)->Vcb->FcbTable, \
  111. &_Key, \
  112. sizeof( FCB_TABLE_ELEMENT ), \
  113. NULL ); \
  114. }
  115. #define CdDeleteFcbTable(IC,F) { \
  116. FCB_TABLE_ELEMENT _Key; \
  117. _Key.FileId = (F)->FileId; \
  118. RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key ); \
  119. }
  120. //
  121. // Local support routines
  122. //
  123. VOID
  124. CdDeleteFcb (
  125. IN PIRP_CONTEXT IrpContext,
  126. IN PFCB Fcb
  127. );
  128. PFCB_NONPAGED
  129. CdCreateFcbNonpaged (
  130. IN PIRP_CONTEXT IrpContext
  131. );
  132. VOID
  133. CdDeleteFcbNonpaged (
  134. IN PIRP_CONTEXT IrpContext,
  135. IN PFCB_NONPAGED FcbNonpaged
  136. );
  137. RTL_GENERIC_COMPARE_RESULTS
  138. CdFcbTableCompare (
  139. IN PRTL_GENERIC_TABLE FcbTable,
  140. IN PVOID Fid1,
  141. IN PVOID Fid2
  142. );
  143. PVOID
  144. CdAllocateFcbTable (
  145. IN PRTL_GENERIC_TABLE FcbTable,
  146. IN CLONG ByteSize
  147. );
  148. VOID
  149. CdDeallocateFcbTable (
  150. IN PRTL_GENERIC_TABLE FcbTable,
  151. IN PVOID Buffer
  152. );
  153. ULONG
  154. CdTocSerial (
  155. IN PIRP_CONTEXT IrpContext,
  156. IN PCDROM_TOC CdromToc
  157. );
  158. #ifdef ALLOC_PRAGMA
  159. #pragma alloc_text(PAGE, CdAllocateFcbTable)
  160. #pragma alloc_text(PAGE, CdCleanupIrpContext)
  161. #pragma alloc_text(PAGE, CdCreateCcb)
  162. #pragma alloc_text(PAGE, CdCreateFcb)
  163. #pragma alloc_text(PAGE, CdCreateFcbNonpaged)
  164. #pragma alloc_text(PAGE, CdCreateFileLock)
  165. #pragma alloc_text(PAGE, CdCreateIrpContext)
  166. #pragma alloc_text(PAGE, CdDeallocateFcbTable)
  167. #pragma alloc_text(PAGE, CdDeleteCcb)
  168. #pragma alloc_text(PAGE, CdDeleteFcb)
  169. #pragma alloc_text(PAGE, CdDeleteFcbNonpaged)
  170. #pragma alloc_text(PAGE, CdDeleteFileLock)
  171. #pragma alloc_text(PAGE, CdDeleteVcb)
  172. #pragma alloc_text(PAGE, CdFcbTableCompare)
  173. #pragma alloc_text(PAGE, CdGetNextFcb)
  174. #pragma alloc_text(PAGE, CdInitializeFcbFromFileContext)
  175. #pragma alloc_text(PAGE, CdInitializeFcbFromPathEntry)
  176. #pragma alloc_text(PAGE, CdInitializeStackIrpContext)
  177. #pragma alloc_text(PAGE, CdInitializeVcb)
  178. #pragma alloc_text(PAGE, CdLookupFcbTable)
  179. #pragma alloc_text(PAGE, CdProcessToc)
  180. #pragma alloc_text(PAGE, CdTeardownStructures)
  181. #pragma alloc_text(PAGE, CdTocSerial)
  182. #pragma alloc_text(PAGE, CdUpdateVcbFromVolDescriptor)
  183. #endif
  184. VOID
  185. CdInitializeVcb (
  186. IN PIRP_CONTEXT IrpContext,
  187. IN OUT PVCB Vcb,
  188. IN PDEVICE_OBJECT TargetDeviceObject,
  189. IN PVPB Vpb,
  190. IN PCDROM_TOC CdromToc,
  191. IN ULONG TocLength,
  192. IN ULONG TocTrackCount,
  193. IN ULONG TocDiskFlags,
  194. IN ULONG BlockFactor,
  195. IN ULONG MediaChangeCount
  196. )
  197. /*++
  198. Routine Description:
  199. This routine initializes and inserts a new Vcb record into the in-memory
  200. data structure. The Vcb record "hangs" off the end of the Volume device
  201. object and must be allocated by our caller.
  202. Arguments:
  203. Vcb - Supplies the address of the Vcb record being initialized.
  204. TargetDeviceObject - Supplies the address of the target device object to
  205. associate with the Vcb record.
  206. Vpb - Supplies the address of the Vpb to associate with the Vcb record.
  207. CdromToc - Buffer to hold table of contents. NULL if TOC command not
  208. supported.
  209. TocLength - Byte count length of TOC. We use this as the TOC length to
  210. return on a user query.
  211. TocTrackCount - Count of tracks in TOC. Used to create pseudo files for
  212. audio disks.
  213. TocDiskFlags - Flag field to indicate the type of tracks on the disk.
  214. BlockFactor - Used to decode any multi-session information.
  215. MediaChangeCount - Initial media change count of the target device
  216. Return Value:
  217. None.
  218. --*/
  219. {
  220. PAGED_CODE();
  221. //
  222. // We start by first zeroing out all of the VCB, this will guarantee
  223. // that any stale data is wiped clean.
  224. //
  225. RtlZeroMemory( Vcb, sizeof( VCB ));
  226. //
  227. // Set the proper node type code and node byte size.
  228. //
  229. Vcb->NodeTypeCode = CDFS_NTC_VCB;
  230. Vcb->NodeByteSize = sizeof( VCB );
  231. //
  232. // Initialize the DirNotify structs. FsRtlNotifyInitializeSync can raise.
  233. //
  234. InitializeListHead( &Vcb->DirNotifyList );
  235. FsRtlNotifyInitializeSync( &Vcb->NotifySync );
  236. //
  237. // Pick up a VPB right now so we know we can pull this filesystem stack
  238. // off of the storage stack on demand. This can raise - if it does,
  239. // uninitialize the notify structures before returning.
  240. //
  241. try {
  242. Vcb->SwapVpb = FsRtlAllocatePoolWithTag( NonPagedPool,
  243. sizeof( VPB ),
  244. TAG_VPB );
  245. }
  246. finally {
  247. if (AbnormalTermination()) {
  248. FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
  249. }
  250. }
  251. //
  252. // Nothing beyond this point should raise.
  253. //
  254. RtlZeroMemory( Vcb->SwapVpb, sizeof( VPB ) );
  255. //
  256. // Initialize the resource variable for the Vcb and files.
  257. //
  258. ExInitializeResourceLite( &Vcb->VcbResource );
  259. ExInitializeResourceLite( &Vcb->FileResource );
  260. ExInitializeFastMutex( &Vcb->VcbMutex );
  261. //
  262. // Insert this Vcb record on the CdData.VcbQueue.
  263. //
  264. InsertHeadList( &CdData.VcbQueue, &Vcb->VcbLinks );
  265. //
  266. // Set the Target Device Object and Vpb fields, referencing the
  267. // Target device for the mount.
  268. //
  269. ObReferenceObject( TargetDeviceObject );
  270. Vcb->TargetDeviceObject = TargetDeviceObject;
  271. Vcb->Vpb = Vpb;
  272. //
  273. // Set the removable media flag based on the real device's
  274. // characteristics
  275. //
  276. if (FlagOn( Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA )) {
  277. SetFlag( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA );
  278. }
  279. //
  280. // Initialize the generic Fcb Table.
  281. //
  282. RtlInitializeGenericTable( &Vcb->FcbTable,
  283. (PRTL_GENERIC_COMPARE_ROUTINE) CdFcbTableCompare,
  284. (PRTL_GENERIC_ALLOCATE_ROUTINE) CdAllocateFcbTable,
  285. (PRTL_GENERIC_FREE_ROUTINE) CdDeallocateFcbTable,
  286. NULL );
  287. //
  288. // Show that we have a mount in progress.
  289. //
  290. CdUpdateVcbCondition( Vcb, VcbMountInProgress);
  291. //
  292. // Refererence the Vcb for two reasons. The first is a reference
  293. // that prevents the Vcb from going away on the last close unless
  294. // dismount has already occurred. The second is to make sure
  295. // we don't go into the dismount path on any error during mount
  296. // until we get to the Mount cleanup.
  297. //
  298. Vcb->VcbReference = 1 + CDFS_RESIDUAL_REFERENCE;
  299. //
  300. // Update the TOC information in the Vcb.
  301. //
  302. Vcb->CdromToc = CdromToc;
  303. Vcb->TocLength = TocLength;
  304. Vcb->TrackCount = TocTrackCount;
  305. Vcb->DiskFlags = TocDiskFlags;
  306. //
  307. // If this disk contains audio tracks only then set the audio flag.
  308. //
  309. if (TocDiskFlags == CDROM_DISK_AUDIO_TRACK) {
  310. SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA );
  311. }
  312. //
  313. // Set the block factor.
  314. //
  315. Vcb->BlockFactor = BlockFactor;
  316. //
  317. // Set the media change count on the device
  318. //
  319. CdUpdateMediaChangeCount( Vcb, MediaChangeCount);
  320. }
  321. VOID
  322. CdUpdateVcbFromVolDescriptor (
  323. IN PIRP_CONTEXT IrpContext,
  324. IN OUT PVCB Vcb,
  325. IN PCHAR RawIsoVd OPTIONAL
  326. )
  327. /*++
  328. Routine Description:
  329. This routine is called to perform the final initialization of a Vcb from the
  330. volume descriptor on the disk.
  331. Arguments:
  332. Vcb - Vcb for the volume being mounted. We have already set the flags for the
  333. type of descriptor.
  334. RawIsoVd - If specified this is the volume descriptor to use to mount the
  335. volume. Not specified for a raw disk.
  336. Return Value:
  337. None
  338. --*/
  339. {
  340. ULONG Shift;
  341. ULONG StartingBlock;
  342. ULONG ByteCount;
  343. LONGLONG FileId = 0;
  344. PRAW_DIRENT RawDirent;
  345. PATH_ENTRY PathEntry;
  346. PCD_MCB_ENTRY McbEntry;
  347. BOOLEAN UnlockVcb = FALSE;
  348. PAGED_CODE();
  349. //
  350. // Use a try-finally to facilitate cleanup.
  351. //
  352. try {
  353. //
  354. // Copy the block size and compute the various block masks.
  355. // Block size must not be larger than the sector size. We will
  356. // use a default of the CD physical sector size if we are not
  357. // on a data-full disc.
  358. //
  359. // This must always be set.
  360. //
  361. Vcb->BlockSize = ( ARGUMENT_PRESENT( RawIsoVd ) ?
  362. CdRvdBlkSz( RawIsoVd, Vcb->VcbState ) :
  363. SECTOR_SIZE );
  364. if ((Vcb->BlockSize > SECTOR_SIZE) || (0 == Vcb->BlockSize)) {
  365. CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
  366. }
  367. Vcb->BlocksPerSector = SECTOR_SIZE / Vcb->BlockSize;
  368. Vcb->BlockMask = Vcb->BlockSize - 1;
  369. Vcb->BlockInverseMask = ~Vcb->BlockMask;
  370. //
  371. // Initialize the BlockToSectorShift and BlockToByte by assuming
  372. // the block size is the same as the sector size. Shift the
  373. // blocks per sectors until it goes to zero.
  374. //
  375. Vcb->BlockToSectorShift = 0;
  376. Vcb->BlockToByteShift = SECTOR_SHIFT;
  377. Shift = Vcb->BlocksPerSector - 1;
  378. while (Shift != 0) {
  379. Vcb->BlockToSectorShift += 1;
  380. Vcb->BlockToByteShift -= 1;
  381. Shift >>= 1;
  382. }
  383. //
  384. // If there is a volume descriptor then do the internal Fcb's and
  385. // other Vcb fields.
  386. //
  387. if (ARGUMENT_PRESENT( RawIsoVd )) {
  388. //
  389. // Create the path table Fcb and refererence it and the Vcb.
  390. //
  391. CdLockVcb( IrpContext, Vcb );
  392. UnlockVcb = TRUE;
  393. Vcb->PathTableFcb = CdCreateFcb( IrpContext,
  394. *((PFILE_ID) &FileId),
  395. CDFS_NTC_FCB_PATH_TABLE,
  396. NULL );
  397. CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 );
  398. CdUnlockVcb( IrpContext, Vcb );
  399. UnlockVcb = FALSE;
  400. //
  401. // Compute the stream offset and size of this path table.
  402. //
  403. StartingBlock = CdRvdPtLoc( RawIsoVd, Vcb->VcbState );
  404. ByteCount = CdRvdPtSz( RawIsoVd, Vcb->VcbState );
  405. Vcb->PathTableFcb->StreamOffset = BytesFromBlocks( Vcb,
  406. SectorBlockOffset( Vcb, StartingBlock ));
  407. Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (Vcb->PathTableFcb->StreamOffset +
  408. ByteCount);
  409. Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart;
  410. Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart );
  411. //
  412. // Now add the mapping information.
  413. //
  414. CdLockFcb( IrpContext, Vcb->PathTableFcb );
  415. CdAddInitialAllocation( IrpContext,
  416. Vcb->PathTableFcb,
  417. StartingBlock,
  418. Vcb->PathTableFcb->AllocationSize.QuadPart );
  419. CdUnlockFcb( IrpContext, Vcb->PathTableFcb );
  420. //
  421. // Point to the file resource.
  422. //
  423. Vcb->PathTableFcb->Resource = &Vcb->FileResource;
  424. //
  425. // Mark the Fcb as initialized and create the stream file for this.
  426. //
  427. SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED );
  428. CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb );
  429. //
  430. // Create the root index and reference it in the Vcb.
  431. //
  432. CdLockVcb( IrpContext, Vcb );
  433. UnlockVcb = TRUE;
  434. Vcb->RootIndexFcb = CdCreateFcb( IrpContext,
  435. *((PFILE_ID) &FileId),
  436. CDFS_NTC_FCB_INDEX,
  437. NULL );
  438. CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 );
  439. CdUnlockVcb( IrpContext, Vcb );
  440. UnlockVcb = FALSE;
  441. //
  442. // Create the File id by hand for this Fcb.
  443. //
  444. CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset );
  445. CdFidSetDirectory( Vcb->RootIndexFcb->FileId );
  446. //
  447. // Create a pseudo path table entry so we can call the initialization
  448. // routine for the directory.
  449. //
  450. RawDirent = (PRAW_DIRENT) CdRvdDirent( RawIsoVd, Vcb->VcbState );
  451. CopyUchar4( &PathEntry.DiskOffset, RawDirent->FileLoc );
  452. PathEntry.DiskOffset += RawDirent->XarLen;
  453. PathEntry.Ordinal = 1;
  454. PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset;
  455. CdInitializeFcbFromPathEntry( IrpContext,
  456. Vcb->RootIndexFcb,
  457. NULL,
  458. &PathEntry );
  459. //
  460. // Create the stream file for the root directory.
  461. //
  462. CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb );
  463. //
  464. // Now do the volume dasd Fcb. Create this and reference it in the
  465. // Vcb.
  466. //
  467. CdLockVcb( IrpContext, Vcb );
  468. UnlockVcb = TRUE;
  469. Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext,
  470. *((PFILE_ID) &FileId),
  471. CDFS_NTC_FCB_DATA,
  472. NULL );
  473. CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 );
  474. CdUnlockVcb( IrpContext, Vcb );
  475. UnlockVcb = FALSE;
  476. //
  477. // The file size is the full disk.
  478. //
  479. StartingBlock = CdRvdVolSz( RawIsoVd, Vcb->VcbState );
  480. Vcb->VolumeDasdFcb->FileSize.QuadPart = LlBytesFromBlocks( Vcb, StartingBlock );
  481. Vcb->VolumeDasdFcb->AllocationSize.QuadPart =
  482. Vcb->VolumeDasdFcb->ValidDataLength.QuadPart = Vcb->VolumeDasdFcb->FileSize.QuadPart;
  483. //
  484. // Now add the extent representing the volume 'by hand'.
  485. //
  486. CdLockFcb( IrpContext, Vcb->VolumeDasdFcb );
  487. McbEntry = Vcb->VolumeDasdFcb->Mcb.McbArray;
  488. McbEntry->FileOffset =
  489. McbEntry->DiskOffset = 0;
  490. McbEntry->ByteCount = Vcb->VolumeDasdFcb->AllocationSize.QuadPart;
  491. McbEntry->DataBlockByteCount =
  492. McbEntry->TotalBlockByteCount = McbEntry->ByteCount;
  493. Vcb->VolumeDasdFcb->Mcb.CurrentEntryCount = 1;
  494. CdUnlockFcb( IrpContext, Vcb->VolumeDasdFcb );
  495. //
  496. // Point to the file resource.
  497. //
  498. Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource;
  499. Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY;
  500. //
  501. // Mark the Fcb as initialized.
  502. //
  503. SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED );
  504. //
  505. // Check and see if this is an XA disk.
  506. //
  507. if (FlagOn( Vcb->VcbState, VCB_STATE_ISO | VCB_STATE_JOLIET)
  508. && RtlEqualMemory( CdXaId,
  509. Add2Ptr( RawIsoVd, 0x400, PCHAR ),
  510. 8 )) {
  511. SetFlag( Vcb->VcbState, VCB_STATE_CDXA );
  512. }
  513. //
  514. // If this is a music disk then we want to mock this disk to make it
  515. // look like ISO disk. We will create a pseudo root directory in
  516. // that case.
  517. //
  518. } else if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
  519. ULONG RootDirectorySize;
  520. //
  521. // Create the path table Fcb and refererence it and the Vcb.
  522. //
  523. CdLockVcb( IrpContext, Vcb );
  524. UnlockVcb = TRUE;
  525. Vcb->PathTableFcb = CdCreateFcb( IrpContext,
  526. *((PFILE_ID) &FileId),
  527. CDFS_NTC_FCB_PATH_TABLE,
  528. NULL );
  529. CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 );
  530. CdUnlockVcb( IrpContext, Vcb );
  531. UnlockVcb = FALSE;
  532. //
  533. // We only create a pseudo entry for the root.
  534. //
  535. Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2);
  536. Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart;
  537. Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart );
  538. //
  539. // Point to the file resource.
  540. //
  541. Vcb->PathTableFcb->Resource = &Vcb->FileResource;
  542. //
  543. // Mark the Fcb as initialized and create the stream file for this.
  544. //
  545. SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED );
  546. CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb );
  547. //
  548. // Create the root index and reference it in the Vcb.
  549. //
  550. CdLockVcb( IrpContext, Vcb );
  551. UnlockVcb = TRUE;
  552. Vcb->RootIndexFcb = CdCreateFcb( IrpContext,
  553. *((PFILE_ID) &FileId),
  554. CDFS_NTC_FCB_INDEX,
  555. NULL );
  556. CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 );
  557. CdUnlockVcb( IrpContext, Vcb );
  558. UnlockVcb = FALSE;
  559. //
  560. // Create the File id by hand for this Fcb.
  561. //
  562. CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset );
  563. CdFidSetDirectory( Vcb->RootIndexFcb->FileId );
  564. //
  565. // Create a pseudo path table entry so we can call the initialization
  566. // routine for the directory.
  567. //
  568. RtlZeroMemory( &PathEntry, sizeof( PATH_ENTRY ));
  569. PathEntry.Ordinal = 1;
  570. PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset;
  571. CdInitializeFcbFromPathEntry( IrpContext,
  572. Vcb->RootIndexFcb,
  573. NULL,
  574. &PathEntry );
  575. //
  576. // Set the sizes by hand for this Fcb. It should have an entry for each track plus an
  577. // entry for the root and parent.
  578. //
  579. RootDirectorySize = (Vcb->TrackCount + 2) * CdAudioDirentSize;
  580. RootDirectorySize = SectorAlign( RootDirectorySize );
  581. Vcb->RootIndexFcb->AllocationSize.QuadPart =
  582. Vcb->RootIndexFcb->ValidDataLength.QuadPart =
  583. Vcb->RootIndexFcb->FileSize.QuadPart = RootDirectorySize;
  584. SetFlag( Vcb->RootIndexFcb->FcbState, FCB_STATE_INITIALIZED );
  585. //
  586. // Create the stream file for the root directory.
  587. //
  588. CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb );
  589. //
  590. // Now do the volume dasd Fcb. Create this and reference it in the
  591. // Vcb.
  592. //
  593. CdLockVcb( IrpContext, Vcb );
  594. UnlockVcb = TRUE;
  595. Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext,
  596. *((PFILE_ID) &FileId),
  597. CDFS_NTC_FCB_DATA,
  598. NULL );
  599. CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 );
  600. CdUnlockVcb( IrpContext, Vcb );
  601. UnlockVcb = FALSE;
  602. //
  603. // We won't allow raw reads on this Fcb so leave the size at
  604. // zero.
  605. //
  606. //
  607. // Point to the file resource.
  608. //
  609. Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource;
  610. Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY;
  611. //
  612. // Mark the Fcb as initialized.
  613. //
  614. SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED );
  615. //
  616. // We will store a hard-coded name in the Vpb and use the toc as
  617. // the serial number.
  618. //
  619. Vcb->Vpb->VolumeLabelLength = CdAudioLabelLength;
  620. RtlCopyMemory( Vcb->Vpb->VolumeLabel,
  621. CdAudioLabel,
  622. CdAudioLabelLength );
  623. //
  624. // Find the serial number for the audio disk.
  625. //
  626. Vcb->Vpb->SerialNumber = CdTocSerial( IrpContext, Vcb->CdromToc );
  627. //
  628. // Set the ISO bit so we know how to treat the names.
  629. //
  630. SetFlag( Vcb->VcbState, VCB_STATE_ISO );
  631. }
  632. } finally {
  633. if (UnlockVcb) { CdUnlockVcb( IrpContext, Vcb ); }
  634. }
  635. }
  636. VOID
  637. CdDeleteVcb (
  638. IN PIRP_CONTEXT IrpContext,
  639. IN OUT PVCB Vcb
  640. )
  641. /*++
  642. Routine Description:
  643. This routine is called to delete a Vcb which failed mount or has been
  644. dismounted. The dismount code should have already removed all of the
  645. open Fcb's. We do nothing here but clean up other auxilary structures.
  646. Arguments:
  647. Vcb - Vcb to delete.
  648. Return Value:
  649. None
  650. --*/
  651. {
  652. PAGED_CODE();
  653. ASSERT_EXCLUSIVE_CDDATA;
  654. ASSERT_EXCLUSIVE_VCB( Vcb );
  655. //
  656. // Chuck the backpocket Vpb we kept just in case.
  657. //
  658. if (Vcb->SwapVpb) {
  659. ExFreePool( Vcb->SwapVpb );
  660. }
  661. //
  662. // If there is a Vpb then we must delete it ourselves.
  663. //
  664. if (Vcb->Vpb != NULL) {
  665. ExFreePool( Vcb->Vpb );
  666. }
  667. //
  668. // Dereference our target if we haven't already done so.
  669. //
  670. if (Vcb->TargetDeviceObject != NULL) {
  671. ObDereferenceObject( Vcb->TargetDeviceObject );
  672. }
  673. //
  674. // Delete the XA Sector if allocated.
  675. //
  676. if (Vcb->XASector != NULL) {
  677. ExFreePool( Vcb->XASector );
  678. }
  679. //
  680. // Remove this entry from the global queue.
  681. //
  682. RemoveEntryList( &Vcb->VcbLinks );
  683. //
  684. // Delete the Vcb and File resources.
  685. //
  686. ExDeleteResourceLite( &Vcb->VcbResource );
  687. ExDeleteResourceLite( &Vcb->FileResource );
  688. //
  689. // Delete the TOC if present.
  690. //
  691. if (Vcb->CdromToc != NULL) {
  692. ExFreePool( Vcb->CdromToc );
  693. }
  694. //
  695. // Uninitialize the notify structures.
  696. //
  697. if (Vcb->NotifySync != NULL) {
  698. FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
  699. }
  700. //
  701. // Now delete the volume device object.
  702. //
  703. IoDeleteDevice( (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb,
  704. VOLUME_DEVICE_OBJECT,
  705. Vcb ));
  706. return;
  707. }
  708. PFCB
  709. CdCreateFcb (
  710. IN PIRP_CONTEXT IrpContext,
  711. IN FILE_ID FileId,
  712. IN NODE_TYPE_CODE NodeTypeCode,
  713. OUT PBOOLEAN FcbExisted OPTIONAL
  714. )
  715. /*++
  716. Routine Description:
  717. This routine is called to find the Fcb for the given FileId. We will
  718. look this up first in the Fcb table and if not found we will create
  719. an Fcb. We don't initialize it or insert it into the FcbTable in this
  720. routine.
  721. This routine is called while the Vcb is locked.
  722. Arguments:
  723. FileId - This is the Id for the target Fcb.
  724. NodeTypeCode - Node type for this Fcb if we need to create.
  725. FcbExisted - If specified, we store whether the Fcb existed.
  726. Return Value:
  727. PFCB - The Fcb found in the table or created if needed.
  728. --*/
  729. {
  730. PFCB NewFcb;
  731. BOOLEAN LocalFcbExisted;
  732. PAGED_CODE();
  733. //
  734. // Use the local boolean if one was not passed in.
  735. //
  736. if (!ARGUMENT_PRESENT( FcbExisted )) {
  737. FcbExisted = &LocalFcbExisted;
  738. }
  739. //
  740. // Maybe this is already in the table.
  741. //
  742. NewFcb = CdLookupFcbTable( IrpContext, IrpContext->Vcb, FileId );
  743. //
  744. // If not then create the Fcb is requested by our caller.
  745. //
  746. if (NewFcb == NULL) {
  747. //
  748. // Allocate and initialize the structure depending on the
  749. // type code.
  750. //
  751. switch (NodeTypeCode) {
  752. case CDFS_NTC_FCB_PATH_TABLE:
  753. case CDFS_NTC_FCB_INDEX:
  754. NewFcb = CdAllocateFcbIndex( IrpContext );
  755. RtlZeroMemory( NewFcb, SIZEOF_FCB_INDEX );
  756. NewFcb->NodeByteSize = SIZEOF_FCB_INDEX;
  757. InitializeListHead( &NewFcb->FcbQueue );
  758. break;
  759. case CDFS_NTC_FCB_DATA :
  760. NewFcb = CdAllocateFcbData( IrpContext );
  761. RtlZeroMemory( NewFcb, SIZEOF_FCB_DATA );
  762. NewFcb->NodeByteSize = SIZEOF_FCB_DATA;
  763. break;
  764. default:
  765. CdBugCheck( 0, 0, 0 );
  766. }
  767. //
  768. // Now do the common initialization.
  769. //
  770. NewFcb->NodeTypeCode = NodeTypeCode;
  771. NewFcb->Vcb = IrpContext->Vcb;
  772. NewFcb->FileId = FileId;
  773. CdInitializeMcb( IrpContext, NewFcb );
  774. //
  775. // Now create the non-paged section object.
  776. //
  777. NewFcb->FcbNonpaged = CdCreateFcbNonpaged( IrpContext );
  778. //
  779. // Deallocate the Fcb and raise if the allocation failed.
  780. //
  781. if (NewFcb->FcbNonpaged == NULL) {
  782. ExFreePool( NewFcb );
  783. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  784. }
  785. *FcbExisted = FALSE;
  786. //
  787. // Initialize Advanced FCB Header fields
  788. //
  789. ExInitializeFastMutex( &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
  790. FsRtlSetupAdvancedHeader( &NewFcb->Header,
  791. &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
  792. } else {
  793. *FcbExisted = TRUE;
  794. }
  795. return NewFcb;
  796. }
  797. VOID
  798. CdInitializeFcbFromPathEntry (
  799. IN PIRP_CONTEXT IrpContext,
  800. IN PFCB Fcb,
  801. IN PFCB ParentFcb OPTIONAL,
  802. IN PPATH_ENTRY PathEntry
  803. )
  804. /*++
  805. Routine Description:
  806. This routine is called to initialize an Fcb for a directory from
  807. the path entry. Since we only have a starting point for the directory,
  808. not the length, we can only speculate on the sizes.
  809. The general initialization is performed in CdCreateFcb.
  810. Arguments:
  811. Fcb - Newly created Fcb for this stream.
  812. ParentFcb - Parent Fcb for this stream. It may not be present.
  813. PathEntry - PathEntry for this Fcb in the Path Table.
  814. Return Value:
  815. None
  816. --*/
  817. {
  818. PAGED_CODE();
  819. //
  820. // Fill in the Index specific fields of the Fcb.
  821. //
  822. Fcb->StreamOffset = BytesFromBlocks( Fcb->Vcb,
  823. SectorBlockOffset( Fcb->Vcb, PathEntry->DiskOffset ));
  824. Fcb->Ordinal = PathEntry->Ordinal;
  825. //
  826. // Initialize the common header in the Fcb. The node type is already
  827. // present.
  828. //
  829. Fcb->Resource = &Fcb->Vcb->FileResource;
  830. //
  831. // Always set the sizes to one sector until we read the self-entry.
  832. //
  833. Fcb->AllocationSize.QuadPart =
  834. Fcb->FileSize.QuadPart =
  835. Fcb->ValidDataLength.QuadPart = SECTOR_SIZE;
  836. CdAddInitialAllocation( IrpContext,
  837. Fcb,
  838. PathEntry->DiskOffset,
  839. SECTOR_SIZE );
  840. //
  841. // State flags for this Fcb.
  842. //
  843. SetFlag( Fcb->FileAttributes,
  844. FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY );
  845. //
  846. // Link into the other in-memory structures and into the Fcb table.
  847. //
  848. if (ParentFcb != NULL) {
  849. Fcb->ParentFcb = ParentFcb;
  850. InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks );
  851. CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
  852. }
  853. CdInsertFcbTable( IrpContext, Fcb );
  854. SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
  855. return;
  856. }
  857. VOID
  858. CdInitializeFcbFromFileContext (
  859. IN PIRP_CONTEXT IrpContext,
  860. IN PFCB Fcb,
  861. IN PFCB ParentFcb,
  862. IN PFILE_ENUM_CONTEXT FileContext
  863. )
  864. /*++
  865. Routine Description:
  866. This routine is called to initialize an Fcb for a file from
  867. the file context. We have looked up all of the dirents for this
  868. stream and have the full file size. We will load the all of the allocation
  869. for the file into the Mcb now.
  870. The general initialization is performed in CdCreateFcb.
  871. Arguments:
  872. Fcb - Newly created Fcb for this stream.
  873. ParentFcb - Parent Fcb for this stream.
  874. FileContext - FileContext for the file.
  875. Return Value:
  876. None
  877. --*/
  878. {
  879. PDIRENT ThisDirent = &FileContext->InitialDirent->Dirent;
  880. PCOMPOUND_DIRENT CurrentCompoundDirent;
  881. LONGLONG CurrentFileOffset;
  882. ULONG CurrentMcbEntryOffset;
  883. PAGED_CODE();
  884. //
  885. // Use a try-finally to facilitate cleanup.
  886. //
  887. CdLockFcb( IrpContext, Fcb );
  888. try {
  889. //
  890. // Initialize the common header in the Fcb. The node type is already
  891. // present.
  892. //
  893. Fcb->Resource = &IrpContext->Vcb->FileResource;
  894. //
  895. // Allocation occurs in block-sized units.
  896. //
  897. Fcb->FileSize.QuadPart =
  898. Fcb->ValidDataLength.QuadPart = FileContext->FileSize;
  899. Fcb->AllocationSize.QuadPart = LlBlockAlign( Fcb->Vcb, FileContext->FileSize );
  900. //
  901. // Set the flags from the dirent. We always start with the read-only bit.
  902. //
  903. SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_READONLY );
  904. if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_HIDDEN )) {
  905. SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
  906. }
  907. //
  908. // Convert the time to NT time.
  909. //
  910. CdConvertCdTimeToNtTime( IrpContext,
  911. ThisDirent->CdTime,
  912. (PLARGE_INTEGER) &Fcb->CreationTime );
  913. //
  914. // Set the flag indicating the type of extent.
  915. //
  916. if (ThisDirent->ExtentType != Form1Data) {
  917. if (ThisDirent->ExtentType == Mode2Form2Data) {
  918. SetFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE );
  919. } else {
  920. SetFlag( Fcb->FcbState, FCB_STATE_DA_FILE );
  921. }
  922. Fcb->XAAttributes = ThisDirent->XAAttributes;
  923. Fcb->XAFileNumber = ThisDirent->XAFileNumber;
  924. }
  925. //
  926. // Read through all of the dirents for the file until we find the last
  927. // and add the allocation into the Mcb.
  928. //
  929. CurrentCompoundDirent = FileContext->InitialDirent;
  930. CurrentFileOffset = 0;
  931. CurrentMcbEntryOffset = 0;
  932. while (TRUE) {
  933. CdAddAllocationFromDirent( IrpContext,
  934. Fcb,
  935. CurrentMcbEntryOffset,
  936. CurrentFileOffset,
  937. &CurrentCompoundDirent->Dirent );
  938. //
  939. // Break out if we are at the last dirent.
  940. //
  941. if (!FlagOn( CurrentCompoundDirent->Dirent.DirentFlags, CD_ATTRIBUTE_MULTI )) {
  942. break;
  943. }
  944. CurrentFileOffset += CurrentCompoundDirent->Dirent.DataLength;
  945. CurrentMcbEntryOffset += 1;
  946. //
  947. // We better be able to find the next dirent.
  948. //
  949. if (!CdLookupNextDirent( IrpContext,
  950. ParentFcb,
  951. &CurrentCompoundDirent->DirContext,
  952. &FileContext->CurrentDirent->DirContext )) {
  953. CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
  954. }
  955. CurrentCompoundDirent = FileContext->CurrentDirent;
  956. CdUpdateDirentFromRawDirent( IrpContext,
  957. ParentFcb,
  958. &CurrentCompoundDirent->DirContext,
  959. &CurrentCompoundDirent->Dirent );
  960. }
  961. //
  962. // Show that the Fcb is initialized.
  963. //
  964. SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED );
  965. //
  966. // Link into the other in-memory structures and into the Fcb table.
  967. //
  968. Fcb->ParentFcb = ParentFcb;
  969. InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks );
  970. CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
  971. CdInsertFcbTable( IrpContext, Fcb );
  972. SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
  973. } finally {
  974. CdUnlockFcb( IrpContext, Fcb );
  975. }
  976. return;
  977. }
  978. PCCB
  979. CdCreateCcb (
  980. IN PIRP_CONTEXT IrpContext,
  981. IN PFCB Fcb,
  982. IN ULONG Flags
  983. )
  984. /*++
  985. Routine Description:
  986. This routine is called to allocate and initialize the Ccb structure.
  987. Arguments:
  988. Fcb - This is the Fcb for the file being opened.
  989. Flags - User flags to set in this Ccb.
  990. Return Value:
  991. PCCB - Pointer to the created Ccb.
  992. --*/
  993. {
  994. PCCB NewCcb;
  995. PAGED_CODE();
  996. //
  997. // Allocate and initialize the structure.
  998. //
  999. NewCcb = CdAllocateCcb( IrpContext );
  1000. RtlZeroMemory( NewCcb, sizeof( CCB ));
  1001. //
  1002. // Set the proper node type code and node byte size
  1003. //
  1004. NewCcb->NodeTypeCode = CDFS_NTC_CCB;
  1005. NewCcb->NodeByteSize = sizeof( CCB );
  1006. //
  1007. // Set the initial value for the flags and Fcb
  1008. //
  1009. NewCcb->Flags = Flags;
  1010. NewCcb->Fcb = Fcb;
  1011. return NewCcb;
  1012. }
  1013. VOID
  1014. CdDeleteCcb (
  1015. IN PIRP_CONTEXT IrpContext,
  1016. IN PCCB Ccb
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. This routine is called to cleanup and deallocate a Ccb structure.
  1021. Arguments:
  1022. Ccb - This is the Ccb to delete.
  1023. Return Value:
  1024. None
  1025. --*/
  1026. {
  1027. PAGED_CODE();
  1028. if (Ccb->SearchExpression.FileName.Buffer != NULL) {
  1029. ExFreePool( Ccb->SearchExpression.FileName.Buffer );
  1030. }
  1031. CdDeallocateCcb( IrpContext, Ccb );
  1032. return;
  1033. }
  1034. BOOLEAN
  1035. CdCreateFileLock (
  1036. IN PIRP_CONTEXT IrpContext OPTIONAL,
  1037. IN PFCB Fcb,
  1038. IN BOOLEAN RaiseOnError
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. This routine is called when we want to attach a file lock structure to the
  1043. given Fcb. It is possible the file lock is already attached.
  1044. This routine is sometimes called from the fast path and sometimes in the
  1045. Irp-based path. We don't want to raise in the fast path, just return FALSE.
  1046. Arguments:
  1047. Fcb - This is the Fcb to create the file lock for.
  1048. RaiseOnError - If TRUE, we will raise on an allocation failure. Otherwise we
  1049. return FALSE on an allocation failure.
  1050. Return Value:
  1051. BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise.
  1052. --*/
  1053. {
  1054. BOOLEAN Result = TRUE;
  1055. PFILE_LOCK FileLock;
  1056. PAGED_CODE();
  1057. //
  1058. // Lock the Fcb and check if there is really any work to do.
  1059. //
  1060. CdLockFcb( IrpContext, Fcb );
  1061. if (Fcb->FileLock != NULL) {
  1062. CdUnlockFcb( IrpContext, Fcb );
  1063. return TRUE;
  1064. }
  1065. Fcb->FileLock = FileLock =
  1066. FsRtlAllocateFileLock( NULL, NULL );
  1067. CdUnlockFcb( IrpContext, Fcb );
  1068. //
  1069. // Return or raise as appropriate.
  1070. //
  1071. if (FileLock == NULL) {
  1072. if (RaiseOnError) {
  1073. ASSERT( ARGUMENT_PRESENT( IrpContext ));
  1074. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1075. }
  1076. Result = FALSE;
  1077. }
  1078. return Result;
  1079. }
  1080. PIRP_CONTEXT
  1081. CdCreateIrpContext (
  1082. IN PIRP Irp,
  1083. IN BOOLEAN Wait
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. This routine is called to initialize an IrpContext for the current
  1088. CDFS request. We allocate the structure and then initialize it from
  1089. the given Irp.
  1090. Arguments:
  1091. Irp - Irp for this request.
  1092. Wait - TRUE if this request is synchronous, FALSE otherwise.
  1093. Return Value:
  1094. PIRP_CONTEXT - Allocated IrpContext.
  1095. --*/
  1096. {
  1097. PIRP_CONTEXT NewIrpContext = NULL;
  1098. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1099. PAGED_CODE();
  1100. //
  1101. // The only operations a filesystem device object should ever receive
  1102. // are create/teardown of fsdo handles and operations which do not
  1103. // occur in the context of fileobjects (i.e., mount).
  1104. //
  1105. if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject) {
  1106. if (IrpSp->FileObject != NULL &&
  1107. IrpSp->MajorFunction != IRP_MJ_CREATE &&
  1108. IrpSp->MajorFunction != IRP_MJ_CLEANUP &&
  1109. IrpSp->MajorFunction != IRP_MJ_CLOSE) {
  1110. ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
  1111. }
  1112. ASSERT( IrpSp->FileObject != NULL ||
  1113. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  1114. IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
  1115. IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) ||
  1116. (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  1117. IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ||
  1118. IrpSp->MajorFunction == IRP_MJ_SHUTDOWN );
  1119. }
  1120. //
  1121. // Look in our lookaside list for an IrpContext.
  1122. //
  1123. if (CdData.IrpContextDepth) {
  1124. CdLockCdData();
  1125. NewIrpContext = (PIRP_CONTEXT) PopEntryList( &CdData.IrpContextList );
  1126. if (NewIrpContext != NULL) {
  1127. CdData.IrpContextDepth--;
  1128. }
  1129. CdUnlockCdData();
  1130. }
  1131. if (NewIrpContext == NULL) {
  1132. //
  1133. // We didn't get it from our private list so allocate it from pool.
  1134. //
  1135. NewIrpContext = FsRtlAllocatePoolWithTag( NonPagedPool, sizeof( IRP_CONTEXT ), TAG_IRP_CONTEXT );
  1136. }
  1137. RtlZeroMemory( NewIrpContext, sizeof( IRP_CONTEXT ));
  1138. //
  1139. // Set the proper node type code and node byte size
  1140. //
  1141. NewIrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
  1142. NewIrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
  1143. //
  1144. // Set the originating Irp field
  1145. //
  1146. NewIrpContext->Irp = Irp;
  1147. //
  1148. // Copy RealDevice for workque algorithms. We will update this in the Mount or
  1149. // Verify since they have no file objects to use here.
  1150. //
  1151. if (IrpSp->FileObject != NULL) {
  1152. NewIrpContext->RealDevice = IrpSp->FileObject->DeviceObject;
  1153. }
  1154. //
  1155. // Locate the volume device object and Vcb that we are trying to access.
  1156. // This may be our filesystem device object. In that case don't initialize
  1157. // the Vcb field.
  1158. //
  1159. if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject) {
  1160. NewIrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
  1161. }
  1162. //
  1163. // Major/Minor Function codes
  1164. //
  1165. NewIrpContext->MajorFunction = IrpSp->MajorFunction;
  1166. NewIrpContext->MinorFunction = IrpSp->MinorFunction;
  1167. //
  1168. // Set the wait parameter
  1169. //
  1170. if (Wait) {
  1171. SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1172. } else {
  1173. SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
  1174. }
  1175. //
  1176. // return and tell the caller
  1177. //
  1178. return NewIrpContext;
  1179. }
  1180. VOID
  1181. CdCleanupIrpContext (
  1182. IN PIRP_CONTEXT IrpContext,
  1183. IN BOOLEAN Post
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. This routine is called to cleanup and possibly deallocate the Irp Context.
  1188. If the request is being posted or this Irp Context is possibly on the
  1189. stack then we only cleanup any auxilary structures.
  1190. Arguments:
  1191. Post - TRUE if we are posting this request, FALSE if we are deleting
  1192. or retrying this in the current thread.
  1193. Return Value:
  1194. None.
  1195. --*/
  1196. {
  1197. PAGED_CODE();
  1198. //
  1199. // If we aren't doing more processing then deallocate this as appropriate.
  1200. //
  1201. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING)) {
  1202. //
  1203. // If this context is the top level CDFS context then we need to
  1204. // restore the top level thread context.
  1205. //
  1206. if (IrpContext->ThreadContext != NULL) {
  1207. CdRestoreThreadContext( IrpContext );
  1208. }
  1209. //
  1210. // Deallocate the Io context if allocated.
  1211. //
  1212. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
  1213. CdFreeIoContext( IrpContext->IoContext );
  1214. }
  1215. //
  1216. // Deallocate the IrpContext if not from the stack.
  1217. //
  1218. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK )) {
  1219. if (CdData.IrpContextDepth < CdData.IrpContextMaxDepth) {
  1220. CdLockCdData();
  1221. PushEntryList( &CdData.IrpContextList, (PSINGLE_LIST_ENTRY) IrpContext );
  1222. CdData.IrpContextDepth++;
  1223. CdUnlockCdData();
  1224. } else {
  1225. //
  1226. // We couldn't add this to our lookaside list so free it to
  1227. // pool.
  1228. //
  1229. ExFreePool( IrpContext );
  1230. }
  1231. }
  1232. //
  1233. // Clear the appropriate flags.
  1234. //
  1235. } else if (Post) {
  1236. //
  1237. // If this context is the top level CDFS context then we need to
  1238. // restore the top level thread context.
  1239. //
  1240. if (IrpContext->ThreadContext != NULL) {
  1241. CdRestoreThreadContext( IrpContext );
  1242. }
  1243. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST );
  1244. } else {
  1245. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY );
  1246. }
  1247. return;
  1248. }
  1249. VOID
  1250. CdInitializeStackIrpContext (
  1251. OUT PIRP_CONTEXT IrpContext,
  1252. IN PIRP_CONTEXT_LITE IrpContextLite
  1253. )
  1254. /*++
  1255. Routine Description:
  1256. This routine is called to initialize an IrpContext for the current
  1257. CDFS request. The IrpContext is on the stack and we need to initialize
  1258. it for the current request. The request is a close operation.
  1259. Arguments:
  1260. IrpContext - IrpContext to initialize.
  1261. IrpContextLite - Structure containing the details of this request.
  1262. Return Value:
  1263. None
  1264. --*/
  1265. {
  1266. PAGED_CODE();
  1267. //
  1268. // Zero and then initialize the structure.
  1269. //
  1270. RtlZeroMemory( IrpContext, sizeof( IRP_CONTEXT ));
  1271. //
  1272. // Set the proper node type code and node byte size
  1273. //
  1274. IrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
  1275. IrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
  1276. //
  1277. // Note that this is from the stack.
  1278. //
  1279. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK );
  1280. //
  1281. // Copy RealDevice for workque algorithms.
  1282. //
  1283. IrpContext->RealDevice = IrpContextLite->RealDevice;
  1284. //
  1285. // The Vcb is found in the Fcb.
  1286. //
  1287. IrpContext->Vcb = IrpContextLite->Fcb->Vcb;
  1288. //
  1289. // Major/Minor Function codes
  1290. //
  1291. IrpContext->MajorFunction = IRP_MJ_CLOSE;
  1292. //
  1293. // Set the wait parameter
  1294. //
  1295. SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
  1296. return;
  1297. }
  1298. VOID
  1299. CdTeardownStructures (
  1300. IN PIRP_CONTEXT IrpContext,
  1301. IN PFCB StartingFcb,
  1302. OUT PBOOLEAN RemovedStartingFcb
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. This routine is used to walk from some starting point in the Fcb tree towards
  1307. the root. It will remove the Fcb and continue walking up the tree until
  1308. it finds a point where we can't remove an Fcb.
  1309. We look at the following fields in the Fcb to determine whether we can
  1310. remove this.
  1311. 1 - Handle count must be zero.
  1312. 2 - If directory then only the only reference can be for a stream file.
  1313. 3 - Reference count must either be zero or go to zero here.
  1314. We return immediately if we are recursively entering this routine.
  1315. Arguments:
  1316. StartingFcb - This is the Fcb node in the tree to begin with. This Fcb
  1317. must currently be acquired exclusively.
  1318. RemovedStartingFcb - Address to store whether we removed the starting Fcb.
  1319. Return Value:
  1320. None
  1321. --*/
  1322. {
  1323. PVCB Vcb = StartingFcb->Vcb;
  1324. PFCB CurrentFcb = StartingFcb;
  1325. BOOLEAN AcquiredCurrentFcb = FALSE;
  1326. PFCB ParentFcb;
  1327. PAGED_CODE();
  1328. *RemovedStartingFcb = FALSE;
  1329. //
  1330. // If this is a recursive call to TearDownStructures we return immediately
  1331. // doing no operation.
  1332. //
  1333. if (FlagOn( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN )) {
  1334. return;
  1335. }
  1336. SetFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
  1337. //
  1338. // Use a try-finally to safely clear the top-level field.
  1339. //
  1340. try {
  1341. //
  1342. // Loop until we find an Fcb we can't remove.
  1343. //
  1344. do {
  1345. //
  1346. // See if there is an internal stream we should delete.
  1347. // Only do this if it is the last reference on the Fcb.
  1348. //
  1349. if ((SafeNodeType( CurrentFcb ) != CDFS_NTC_FCB_DATA) &&
  1350. (CurrentFcb->FcbUserReference == 0) &&
  1351. (CurrentFcb->FileObject != NULL)) {
  1352. //
  1353. // Go ahead and delete the stream file object.
  1354. //
  1355. CdDeleteInternalStream( IrpContext, CurrentFcb );
  1356. }
  1357. //
  1358. // If the reference count is non-zero then break.
  1359. //
  1360. if (CurrentFcb->FcbReference != 0) {
  1361. break;
  1362. }
  1363. //
  1364. // It looks like we have a candidate for removal here. We
  1365. // will need to acquire the parent, if present, in order to
  1366. // remove this from the parent prefix table.
  1367. //
  1368. ParentFcb = CurrentFcb->ParentFcb;
  1369. if (ParentFcb != NULL) {
  1370. CdAcquireFcbExclusive( IrpContext, ParentFcb, FALSE );
  1371. }
  1372. //
  1373. // Now lock the vcb.
  1374. //
  1375. CdLockVcb( IrpContext, Vcb );
  1376. //
  1377. // Final check to see if the reference count is still zero.
  1378. //
  1379. if (CurrentFcb->FcbReference != 0) {
  1380. CdUnlockVcb( IrpContext, Vcb );
  1381. if (ParentFcb != NULL) {
  1382. CdReleaseFcb( IrpContext, ParentFcb );
  1383. }
  1384. break;
  1385. }
  1386. //
  1387. // If there is a parent then do the necessary cleanup for the parent.
  1388. //
  1389. if (ParentFcb != NULL) {
  1390. CdRemovePrefix( IrpContext, CurrentFcb );
  1391. RemoveEntryList( &CurrentFcb->FcbLinks );
  1392. CdDecrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
  1393. }
  1394. if (FlagOn( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE )) {
  1395. CdDeleteFcbTable( IrpContext, CurrentFcb );
  1396. ClearFlag( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE );
  1397. }
  1398. //
  1399. // Unlock the Vcb but hold the parent in order to walk up
  1400. // the tree.
  1401. //
  1402. CdUnlockVcb( IrpContext, Vcb );
  1403. CdDeleteFcb( IrpContext, CurrentFcb );
  1404. //
  1405. // Move to the parent Fcb.
  1406. //
  1407. CurrentFcb = ParentFcb;
  1408. AcquiredCurrentFcb = TRUE;
  1409. } while (CurrentFcb != NULL);
  1410. } finally {
  1411. //
  1412. // Release the current Fcb if we have acquired it.
  1413. //
  1414. if (AcquiredCurrentFcb && (CurrentFcb != NULL)) {
  1415. CdReleaseFcb( IrpContext, CurrentFcb );
  1416. }
  1417. //
  1418. // Clear the teardown flag.
  1419. //
  1420. ClearFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
  1421. }
  1422. *RemovedStartingFcb = (CurrentFcb != StartingFcb);
  1423. return;
  1424. }
  1425. PFCB
  1426. CdLookupFcbTable (
  1427. IN PIRP_CONTEXT IrpContext,
  1428. IN PVCB Vcb,
  1429. IN FILE_ID FileId
  1430. )
  1431. /*++
  1432. Routine Description:
  1433. This routine will look through the Fcb table looking for a matching
  1434. entry.
  1435. Arguments:
  1436. Vcb - Vcb for this volume.
  1437. FileId - This is the key value to use for the search.
  1438. Return Value:
  1439. PFCB - A pointer to the matching entry or NULL otherwise.
  1440. --*/
  1441. {
  1442. FCB_TABLE_ELEMENT Key;
  1443. PFCB_TABLE_ELEMENT Hit;
  1444. PFCB ReturnFcb = NULL;
  1445. PAGED_CODE();
  1446. Key.FileId = FileId;
  1447. Hit = (PFCB_TABLE_ELEMENT) RtlLookupElementGenericTable( &Vcb->FcbTable, &Key );
  1448. if (Hit != NULL) {
  1449. ReturnFcb = Hit->Fcb;
  1450. }
  1451. return ReturnFcb;
  1452. UNREFERENCED_PARAMETER( IrpContext );
  1453. }
  1454. PFCB
  1455. CdGetNextFcb (
  1456. IN PIRP_CONTEXT IrpContext,
  1457. IN PVCB Vcb,
  1458. IN PVOID *RestartKey
  1459. )
  1460. /*++
  1461. Routine Description:
  1462. This routine will enumerate through all of the Fcb's in the Fcb table.
  1463. Arguments:
  1464. Vcb - Vcb for this volume.
  1465. RestartKey - This value is used by the table package to maintain
  1466. its position in the enumeration. It is initialized to NULL
  1467. for the first search.
  1468. Return Value:
  1469. PFCB - A pointer to the next fcb or NULL if the enumeration is
  1470. completed
  1471. --*/
  1472. {
  1473. PFCB Fcb;
  1474. PAGED_CODE();
  1475. Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey );
  1476. if (Fcb != NULL) {
  1477. Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb;
  1478. }
  1479. return Fcb;
  1480. }
  1481. NTSTATUS
  1482. CdProcessToc (
  1483. IN PIRP_CONTEXT IrpContext,
  1484. IN PDEVICE_OBJECT TargetDeviceObject,
  1485. IN PCDROM_TOC CdromToc,
  1486. IN OUT PULONG Length,
  1487. OUT PULONG TrackCount,
  1488. OUT PULONG DiskFlags
  1489. )
  1490. /*++
  1491. Routine Description:
  1492. This routine is called to verify and process the TOC for this disk.
  1493. We hide a data track for a CD+ volume.
  1494. Arguments:
  1495. TargetDeviceObject - Device object to send TOC request to.
  1496. CdromToc - Pointer to TOC structure.
  1497. Length - On input this is the length of the TOC. On return is the TOC
  1498. length we will show to the user.
  1499. TrackCount - This is the count of tracks for the TOC. We use this
  1500. when creating a pseudo directory for a music disk.
  1501. DiskFlags - We return flags indicating what we know about this disk.
  1502. Return Value:
  1503. NTSTATUS - The result of trying to read the TOC.
  1504. --*/
  1505. {
  1506. NTSTATUS Status;
  1507. IO_STATUS_BLOCK Iosb;
  1508. ULONG CurrentTrack;
  1509. ULONG LocalTrackCount;
  1510. ULONG LocalTocLength;
  1511. union {
  1512. UCHAR BigEndian[2];
  1513. USHORT Length;
  1514. } BiasedTocLength;
  1515. PTRACK_DATA Track;
  1516. PAGED_CODE();
  1517. //
  1518. // Go ahead and read the table of contents
  1519. //
  1520. Status = CdPerformDevIoCtrl( IrpContext,
  1521. IOCTL_CDROM_READ_TOC,
  1522. TargetDeviceObject,
  1523. CdromToc,
  1524. sizeof( CDROM_TOC ),
  1525. FALSE,
  1526. TRUE,
  1527. &Iosb );
  1528. //
  1529. // Nothing to process if this request fails.
  1530. //
  1531. if (Status != STATUS_SUCCESS) {
  1532. return Status;
  1533. }
  1534. //
  1535. // Get the number of tracks and stated size of this structure.
  1536. //
  1537. CurrentTrack = 0;
  1538. LocalTrackCount = CdromToc->LastTrack - CdromToc->FirstTrack + 1;
  1539. LocalTocLength = PtrOffset( CdromToc, &CdromToc->TrackData[LocalTrackCount + 1] );
  1540. //
  1541. // Get out if there is an immediate problem with the TOC.
  1542. //
  1543. if ((LocalTocLength > Iosb.Information) ||
  1544. (CdromToc->FirstTrack > CdromToc->LastTrack)) {
  1545. Status = STATUS_DISK_CORRUPT_ERROR;
  1546. return Status;
  1547. }
  1548. //
  1549. // Walk through the individual tracks. Stop at the first data track after
  1550. // any lead-in audio tracks.
  1551. //
  1552. do {
  1553. //
  1554. // Get the next track.
  1555. //
  1556. Track = &CdromToc->TrackData[CurrentTrack];
  1557. //
  1558. // If this is a data track then check if we have only seen audio tracks
  1559. // to this point.
  1560. //
  1561. if (FlagOn( Track->Control, TOC_DATA_TRACK )) {
  1562. //
  1563. // If we have only seen audio tracks then assume this is a
  1564. // CD+ disk. Hide the current data track and only return
  1565. // the previous audio tracks. Set the disk type to be mixed
  1566. // data/audio.
  1567. //
  1568. if (FlagOn( *DiskFlags, CDROM_DISK_AUDIO_TRACK ) &&
  1569. !FlagOn( *DiskFlags, CDROM_DISK_DATA_TRACK )) {
  1570. //
  1571. // Remove one track from the TOC.
  1572. //
  1573. CdromToc->LastTrack -= 1;
  1574. //
  1575. // Knock 2.5 minutes off the current track to
  1576. // hide the final leadin.
  1577. //
  1578. Track->Address[1] -= 2;
  1579. Track->Address[2] += 30;
  1580. if (Track->Address[2] < 60) {
  1581. Track->Address[1] -= 1;
  1582. } else {
  1583. Track->Address[2] -= 60;
  1584. }
  1585. Track->TrackNumber = TOC_LAST_TRACK;
  1586. //
  1587. // Set the disk type to mixed data/audio.
  1588. //
  1589. SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
  1590. break;
  1591. }
  1592. //
  1593. // Set the flag to indicate data tracks present.
  1594. //
  1595. SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
  1596. //
  1597. // If this is a audio track then set the flag indicating audio
  1598. // tracks.
  1599. //
  1600. } else {
  1601. SetFlag( *DiskFlags, CDROM_DISK_AUDIO_TRACK );
  1602. }
  1603. //
  1604. // Set our index for the next track.
  1605. //
  1606. CurrentTrack += 1;
  1607. } while (CurrentTrack < LocalTrackCount);
  1608. //
  1609. // Set the length to point just past the last track we looked at.
  1610. //
  1611. *TrackCount = CurrentTrack;
  1612. *Length = PtrOffset( CdromToc, &CdromToc->TrackData[CurrentTrack + 1] );
  1613. BiasedTocLength.Length = (USHORT) *Length - 2;
  1614. CdromToc->Length[0] = BiasedTocLength.BigEndian[1];
  1615. CdromToc->Length[1] = BiasedTocLength.BigEndian[0];
  1616. return Status;
  1617. }
  1618. //
  1619. // Local support routine
  1620. //
  1621. VOID
  1622. CdDeleteFcb (
  1623. IN PIRP_CONTEXT IrpContext,
  1624. IN PFCB Fcb
  1625. )
  1626. /*++
  1627. Routine Description:
  1628. This routine is called to cleanup and deallocate an Fcb. We know there
  1629. are no references remaining. We cleanup any auxilary structures and
  1630. deallocate this Fcb.
  1631. Arguments:
  1632. Fcb - This is the Fcb to deallcoate.
  1633. Return Value:
  1634. None
  1635. --*/
  1636. {
  1637. PVCB Vcb = NULL;
  1638. PAGED_CODE();
  1639. //
  1640. // Sanity check the counts.
  1641. //
  1642. ASSERT( Fcb->FcbCleanup == 0 );
  1643. ASSERT( Fcb->FcbReference == 0 );
  1644. //
  1645. // Release any Filter Context structures associated with this FCB
  1646. //
  1647. FsRtlTeardownPerStreamContexts( &Fcb->Header );
  1648. //
  1649. // Start with the common structures.
  1650. //
  1651. CdUninitializeMcb( IrpContext, Fcb );
  1652. CdDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged );
  1653. //
  1654. // Check if we need to deallocate the prefix name buffer.
  1655. //
  1656. if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) Fcb->FileNamePrefix.FileNameBuffer) &&
  1657. (Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) {
  1658. ExFreePool( Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer );
  1659. }
  1660. //
  1661. // Now look at the short name prefix.
  1662. //
  1663. if (Fcb->ShortNamePrefix != NULL) {
  1664. ExFreePool( Fcb->ShortNamePrefix );
  1665. }
  1666. //
  1667. // Now do the type specific structures.
  1668. //
  1669. switch (Fcb->NodeTypeCode) {
  1670. case CDFS_NTC_FCB_PATH_TABLE:
  1671. case CDFS_NTC_FCB_INDEX:
  1672. ASSERT( Fcb->FileObject == NULL );
  1673. ASSERT( IsListEmpty( &Fcb->FcbQueue ));
  1674. if (Fcb == Fcb->Vcb->RootIndexFcb) {
  1675. Vcb = Fcb->Vcb;
  1676. Vcb->RootIndexFcb = NULL;
  1677. } else if (Fcb == Fcb->Vcb->PathTableFcb) {
  1678. Vcb = Fcb->Vcb;
  1679. Vcb->PathTableFcb = NULL;
  1680. }
  1681. CdDeallocateFcbIndex( IrpContext, Fcb );
  1682. break;
  1683. case CDFS_NTC_FCB_DATA :
  1684. if (Fcb->FileLock != NULL) {
  1685. FsRtlFreeFileLock( Fcb->FileLock );
  1686. }
  1687. FsRtlUninitializeOplock( &Fcb->Oplock );
  1688. if (Fcb == Fcb->Vcb->VolumeDasdFcb) {
  1689. Vcb = Fcb->Vcb;
  1690. Vcb->VolumeDasdFcb = NULL;
  1691. }
  1692. CdDeallocateFcbData( IrpContext, Fcb );
  1693. }
  1694. //
  1695. // Decrement the Vcb reference count if this is a system
  1696. // Fcb.
  1697. //
  1698. if (Vcb != NULL) {
  1699. InterlockedDecrement( &Vcb->VcbReference );
  1700. InterlockedDecrement( &Vcb->VcbUserReference );
  1701. }
  1702. return;
  1703. }
  1704. //
  1705. // Local support routine
  1706. //
  1707. PFCB_NONPAGED
  1708. CdCreateFcbNonpaged (
  1709. IN PIRP_CONTEXT IrpContext
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. This routine is called to create and initialize the non-paged portion
  1714. of an Fcb.
  1715. Arguments:
  1716. Return Value:
  1717. PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created.
  1718. --*/
  1719. {
  1720. PFCB_NONPAGED FcbNonpaged;
  1721. PAGED_CODE();
  1722. //
  1723. // Allocate the non-paged pool and initialize the various
  1724. // synchronization objects.
  1725. //
  1726. FcbNonpaged = CdAllocateFcbNonpaged( IrpContext );
  1727. if (FcbNonpaged != NULL) {
  1728. RtlZeroMemory( FcbNonpaged, sizeof( FCB_NONPAGED ));
  1729. FcbNonpaged->NodeTypeCode = CDFS_NTC_FCB_NONPAGED;
  1730. FcbNonpaged->NodeByteSize = sizeof( FCB_NONPAGED );
  1731. ExInitializeResourceLite( &FcbNonpaged->FcbResource );
  1732. ExInitializeFastMutex( &FcbNonpaged->FcbMutex );
  1733. }
  1734. return FcbNonpaged;
  1735. }
  1736. //
  1737. // Local support routine
  1738. //
  1739. VOID
  1740. CdDeleteFcbNonpaged (
  1741. IN PIRP_CONTEXT IrpContext,
  1742. IN PFCB_NONPAGED FcbNonpaged
  1743. )
  1744. /*++
  1745. Routine Description:
  1746. This routine is called to cleanup the non-paged portion of an Fcb.
  1747. Arguments:
  1748. FcbNonpaged - Structure to clean up.
  1749. Return Value:
  1750. None
  1751. --*/
  1752. {
  1753. PAGED_CODE();
  1754. ExDeleteResourceLite( &FcbNonpaged->FcbResource );
  1755. CdDeallocateFcbNonpaged( IrpContext, FcbNonpaged );
  1756. return;
  1757. }
  1758. //
  1759. // Local support routine
  1760. //
  1761. RTL_GENERIC_COMPARE_RESULTS
  1762. CdFcbTableCompare (
  1763. IN PRTL_GENERIC_TABLE FcbTable,
  1764. IN PVOID Fid1,
  1765. IN PVOID Fid2
  1766. )
  1767. /*++
  1768. Routine Description:
  1769. This routine is the Cdfs compare routine called by the generic table package.
  1770. If will compare the two File Id values and return a comparison result.
  1771. Arguments:
  1772. FcbTable - This is the table being searched.
  1773. Fid1 - First key value.
  1774. Fid2 - Second key value.
  1775. Return Value:
  1776. RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
  1777. input structures
  1778. --*/
  1779. {
  1780. FILE_ID Id1, Id2;
  1781. PAGED_CODE();
  1782. Id1 = *((FILE_ID UNALIGNED *) Fid1);
  1783. Id2 = *((FILE_ID UNALIGNED *) Fid2);
  1784. if (Id1.QuadPart < Id2.QuadPart) {
  1785. return GenericLessThan;
  1786. } else if (Id1.QuadPart > Id2.QuadPart) {
  1787. return GenericGreaterThan;
  1788. } else {
  1789. return GenericEqual;
  1790. }
  1791. UNREFERENCED_PARAMETER( FcbTable );
  1792. }
  1793. //
  1794. // Local support routine
  1795. //
  1796. PVOID
  1797. CdAllocateFcbTable (
  1798. IN PRTL_GENERIC_TABLE FcbTable,
  1799. IN CLONG ByteSize
  1800. )
  1801. /*++
  1802. Routine Description:
  1803. This is a generic table support routine to allocate memory
  1804. Arguments:
  1805. FcbTable - Supplies the generic table being used
  1806. ByteSize - Supplies the number of bytes to allocate
  1807. Return Value:
  1808. PVOID - Returns a pointer to the allocated data
  1809. --*/
  1810. {
  1811. PAGED_CODE();
  1812. return( FsRtlAllocatePoolWithTag( CdPagedPool, ByteSize, TAG_FCB_TABLE ));
  1813. }
  1814. //
  1815. // Local support routine
  1816. //
  1817. VOID
  1818. CdDeallocateFcbTable (
  1819. IN PRTL_GENERIC_TABLE FcbTable,
  1820. IN PVOID Buffer
  1821. )
  1822. /*++
  1823. Routine Description:
  1824. This is a generic table support routine that deallocates memory
  1825. Arguments:
  1826. FcbTable - Supplies the generic table being used
  1827. Buffer - Supplies the buffer being deallocated
  1828. Return Value:
  1829. None.
  1830. --*/
  1831. {
  1832. PAGED_CODE();
  1833. ExFreePool( Buffer );
  1834. return;
  1835. UNREFERENCED_PARAMETER( FcbTable );
  1836. }
  1837. //
  1838. // Local support routine
  1839. //
  1840. ULONG
  1841. CdTocSerial (
  1842. IN PIRP_CONTEXT IrpContext,
  1843. IN PCDROM_TOC CdromToc
  1844. )
  1845. /*++
  1846. Routine Description:
  1847. This routine is called to generate a serial number for an audio disk.
  1848. The number is based on the starting positions of the tracks.
  1849. The following algorithm is used.
  1850. If the number of tracks is <= 2 then initialize the serial number to the
  1851. leadout block number.
  1852. Then add the starting address of each track (use 0x00mmssff format).
  1853. Arguments:
  1854. CdromToc - Valid table of contents to use for track information.
  1855. Return Value:
  1856. ULONG - 32 bit serial number based on TOC.
  1857. --*/
  1858. {
  1859. ULONG SerialNumber = 0;
  1860. PTRACK_DATA ThisTrack;
  1861. PTRACK_DATA LastTrack;
  1862. PAGED_CODE();
  1863. //
  1864. // Check if there are two tracks or fewer.
  1865. //
  1866. LastTrack = &CdromToc->TrackData[ CdromToc->LastTrack - CdromToc->FirstTrack + 1];
  1867. ThisTrack = &CdromToc->TrackData[0];
  1868. if (CdromToc->LastTrack - CdromToc->FirstTrack <= 1) {
  1869. SerialNumber = (((LastTrack->Address[1] * 60) + LastTrack->Address[2]) * 75) + LastTrack->Address[3];
  1870. SerialNumber -= (((ThisTrack->Address[1] * 60) + ThisTrack->Address[2]) * 75) + ThisTrack->Address[3];
  1871. }
  1872. //
  1873. // Now find the starting offset of each track and add to the serial number.
  1874. //
  1875. while (ThisTrack != LastTrack) {
  1876. SerialNumber += (ThisTrack->Address[1] << 16);
  1877. SerialNumber += (ThisTrack->Address[2] << 8);
  1878. SerialNumber += ThisTrack->Address[3];
  1879. ThisTrack += 1;
  1880. }
  1881. return SerialNumber;
  1882. }