xref: /reactos/drivers/filesystems/cdfs/strucsup.c (revision cc439606)
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     StrucSup.c
8 
9 Abstract:
10 
11     This module implements the Cdfs in-memory data structure manipulation
12     routines
13 
14 
15 --*/
16 
17 #include "cdprocs.h"
18 
19 //
20 //  The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId                   (CDFS_BUG_CHECK_STRUCSUP)
24 
25 //
26 //  Local macros
27 //
28 
29 //
30 //  PFCB
31 //  CdAllocateFcbData (
32 //      _In_ PIRP_CONTEXT IrpContext
33 //      );
34 //
35 //  VOID
36 //  CdDeallocateFcbData (
37 //      _In_ PIRP_CONTEXT IrpContext,
38 //      _Inout_ PFCB Fcb
39 //      );
40 //
41 //  PFCB
42 //  CdAllocateFcbIndex (
43 //      _In_ PIRP_CONTEXT IrpContext
44 //      );
45 //
46 //  VOID
47 //  CdDeallocateFcbIndex (
48 //      _In_ PIRP_CONTEXT IrpContext,
49 //      _Inout_ PFCB Fcb
50 //      );
51 //
52 //  PFCB_NONPAGED
53 //  CdAllocateFcbNonpaged (
54 //      _In_ PIRP_CONTEXT IrpContext
55 //      );
56 //
57 //  VOID
58 //  CdDeallocateFcbNonpaged (
59 //      _In_ PIRP_CONTEXT IrpContext,
60 //      _Inout_ PFCB_NONPAGED FcbNonpaged
61 //      );
62 //
63 //  PCCB
64 //  CdAllocateCcb (
65 //      _In_ PIRP_CONTEXT IrpContext
66 //      );
67 //
68 //  VOID
69 //  CdDeallocateCcb (
70 //      _In_ PIRP_CONTEXT IrpContext,
71 //      _Inout_ PCCB Ccb
72 //      );
73 //
74 
75 #define CdAllocateFcbData(IC) \
76     FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_DATA, TAG_FCB_DATA )
77 
78 #define CdDeallocateFcbData(IC,F) \
79     CdFreePool( &(F) )
80 
81 #define CdAllocateFcbIndex(IC) \
82     FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_INDEX, TAG_FCB_INDEX )
83 
84 #define CdDeallocateFcbIndex(IC,F) \
85     CdFreePool( &(F) )
86 
87 #define CdAllocateFcbNonpaged(IC) \
88     ExAllocatePoolWithTag( CdNonPagedPool, sizeof( FCB_NONPAGED ), TAG_FCB_NONPAGED )
89 
90 #define CdDeallocateFcbNonpaged(IC,FNP) \
91     CdFreePool( &(FNP) )
92 
93 #define CdAllocateCcb(IC) \
94     FsRtlAllocatePoolWithTag( CdPagedPool, sizeof( CCB ), TAG_CCB )
95 
96 #define CdDeallocateCcb(IC,C) \
97     CdFreePool( &(C) )
98 
99 //
100 //  Local structures
101 //
102 
103 typedef struct _FCB_TABLE_ELEMENT {
104 
105     FILE_ID FileId;
106     PFCB Fcb;
107 
108 } FCB_TABLE_ELEMENT, *PFCB_TABLE_ELEMENT;
109 
110 //
111 //  Local macros
112 //
113 
114 //
115 //  VOID
116 //  CdInsertFcbTable (
117 //      _In_ PIRP_CONTEXT IrpContext,
118 //      _In_ PFCB Fcb
119 //      );
120 //
121 //  VOID
122 //  CdDeleteFcbTable (
123 //      _In_ PIRP_CONTEXT IrpContext,
124 //      _In_ PFCB Fcb
125 //      );
126 //
127 
128 
129 #define CdInsertFcbTable(IC,F) {                                    \
130     FCB_TABLE_ELEMENT _Key;                                         \
131     _Key.Fcb = (F);                                                 \
132     _Key.FileId = (F)->FileId;                                      \
133     RtlInsertElementGenericTable( &(F)->Vcb->FcbTable,              \
134                                   &_Key,                            \
135                                   sizeof( FCB_TABLE_ELEMENT ),      \
136                                   NULL );                           \
137 }
138 
139 #define CdDeleteFcbTable(IC,F) {                                    \
140     FCB_TABLE_ELEMENT _Key;                                         \
141     _Key.FileId = (F)->FileId;                                      \
142     RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key );     \
143 }
144 
145 //
146 //  Local support routines
147 //
148 
149 VOID
150 CdDeleteFcb (
151     _In_ PIRP_CONTEXT IrpContext,
152     _In_ PFCB Fcb
153     );
154 
155 PFCB_NONPAGED
156 CdCreateFcbNonpaged (
157     _In_ PIRP_CONTEXT IrpContext
158     );
159 
160 VOID
161 CdDeleteFcbNonpaged (
162     _In_ PIRP_CONTEXT IrpContext,
163     _In_ PFCB_NONPAGED FcbNonpaged
164     );
165 
166 //  Inform prefast that this is a compare routine.
167 RTL_GENERIC_COMPARE_ROUTINE CdFcbTableCompare;
168 
169 RTL_GENERIC_COMPARE_RESULTS
170 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
171 CdFcbTableCompare (
172     _In_ PRTL_GENERIC_TABLE FcbTable,
173     _In_ PVOID Fid1,
174     _In_ PVOID Fid2
175     );
176 
177 //  Inform prefast that this is an alloc reoutine.
178 RTL_GENERIC_ALLOCATE_ROUTINE CdAllocateFcbTable;
179 
180 PVOID
181 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
182 CdAllocateFcbTable (
183     _In_ PRTL_GENERIC_TABLE FcbTable,
184     _In_ CLONG ByteSize
185     );
186 
187 //  Inform prefast that this is a free reoutine.
188 RTL_GENERIC_FREE_ROUTINE CdDeallocateFcbTable;
189 
190 VOID
191 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
192 CdDeallocateFcbTable (
193     _In_ PRTL_GENERIC_TABLE FcbTable,
194     _In_ __drv_freesMem(Mem) _Post_invalid_ PVOID Buffer
195     );
196 
197 ULONG
198 CdTocSerial (
199     _In_ PIRP_CONTEXT IrpContext,
200     _In_ PCDROM_TOC_LARGE CdromToc
201     );
202 
203 #ifdef ALLOC_PRAGMA
204 #pragma alloc_text(PAGE, CdAllocateFcbTable)
205 #pragma alloc_text(PAGE, CdCleanupIrpContext)
206 #pragma alloc_text(PAGE, CdCreateCcb)
207 #pragma alloc_text(PAGE, CdCreateFcb)
208 #pragma alloc_text(PAGE, CdCreateFcbNonpaged)
209 #pragma alloc_text(PAGE, CdCreateFileLock)
210 #pragma alloc_text(PAGE, CdCreateIrpContext)
211 #pragma alloc_text(PAGE, CdDeallocateFcbTable)
212 #pragma alloc_text(PAGE, CdDeleteCcb)
213 #pragma alloc_text(PAGE, CdDeleteFcb)
214 #pragma alloc_text(PAGE, CdDeleteFcbNonpaged)
215 #pragma alloc_text(PAGE, CdDeleteFileLock)
216 #pragma alloc_text(PAGE, CdDeleteVcb)
217 #pragma alloc_text(PAGE, CdFcbTableCompare)
218 #pragma alloc_text(PAGE, CdGetNextFcb)
219 #pragma alloc_text(PAGE, CdInitializeFcbFromFileContext)
220 #pragma alloc_text(PAGE, CdInitializeFcbFromPathEntry)
221 #pragma alloc_text(PAGE, CdInitializeStackIrpContext)
222 #pragma alloc_text(PAGE, CdInitializeVcb)
223 #pragma alloc_text(PAGE, CdLookupFcbTable)
224 #pragma alloc_text(PAGE, CdProcessToc)
225 #pragma alloc_text(PAGE, CdTeardownStructures)
226 #pragma alloc_text(PAGE, CdTocSerial)
227 #pragma alloc_text(PAGE, CdUpdateVcbFromVolDescriptor)
228 #endif
229 
230 //
231 //  Some static names for volume streams
232 //
233 
234 UNICODE_STRING CdInternalStreamNames[] = {
235         { 24, 24, L"$PATH_TABLE$"},
236         { 2,  2,  L"\\"}
237 };
238 
239 
240 VOID
241 CdInitializeVcb (
242     _In_ PIRP_CONTEXT IrpContext,
243     _Inout_ PVCB Vcb,
244     _In_ __drv_aliasesMem  PDEVICE_OBJECT TargetDeviceObject,
245     _In_ __drv_aliasesMem PVPB Vpb,
246     _In_ __drv_aliasesMem PCDROM_TOC_LARGE CdromToc,
247     _In_ ULONG TocLength,
248     _In_ ULONG TocTrackCount,
249     _In_ ULONG TocDiskFlags,
250     _In_ ULONG BlockFactor,
251     _In_ ULONG MediaChangeCount
252     )
253 
254 /*++
255 
256 Routine Description:
257 
258     This routine initializes and inserts a new Vcb record into the in-memory
259     data structure.  The Vcb record "hangs" off the end of the Volume device
260     object and must be allocated by our caller.
261 
262 Arguments:
263 
264     Vcb - Supplies the address of the Vcb record being initialized.
265 
266     TargetDeviceObject - Supplies the address of the target device object to
267         associate with the Vcb record.
268 
269     Vpb - Supplies the address of the Vpb to associate with the Vcb record.
270 
271     CdromToc - Buffer to hold table of contents.  NULL if TOC command not
272         supported.
273 
274     TocLength - Byte count length of TOC.  We use this as the TOC length to
275         return on a user query.
276 
277     TocTrackCount - Count of tracks in TOC.  Used to create pseudo files for
278         audio disks.
279 
280     TocDiskFlags - Flag field to indicate the type of tracks on the disk.
281 
282     BlockFactor - Used to decode any multi-session information.
283 
284     MediaChangeCount - Initial media change count of the target device
285 
286 Return Value:
287 
288     None.
289 
290 --*/
291 
292 {
293     PAGED_CODE();
294 
295     UNREFERENCED_PARAMETER( IrpContext );
296 
297     //
298     //  We start by first zeroing out all of the VCB, this will guarantee
299     //  that any stale data is wiped clean.
300     //
301 
302     RtlZeroMemory( Vcb, sizeof( VCB ));
303 
304     //
305     //  Set the proper node type code and node byte size.
306     //
307 
308     Vcb->NodeTypeCode = CDFS_NTC_VCB;
309     Vcb->NodeByteSize = sizeof( VCB );
310 
311     //
312     //  Initialize the DirNotify structs.  FsRtlNotifyInitializeSync can raise.
313     //
314 
315     InitializeListHead( &Vcb->DirNotifyList );
316     FsRtlNotifyInitializeSync( &Vcb->NotifySync );
317 
318     //
319     //  Pick up a VPB right now so we know we can pull this filesystem stack
320     //  off of the storage stack on demand.  This can raise - if it does,
321     //  uninitialize the notify structures before returning.
322     //
323 
324     _SEH2_TRY  {
325 
326         Vcb->SwapVpb = FsRtlAllocatePoolWithTag( CdNonPagedPool,
327                                                  sizeof( VPB ),
328                                                  TAG_VPB );
329     }
330     _SEH2_FINALLY {
331 
332         if (_SEH2_AbnormalTermination())  {
333 
334             FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
335         }
336     } _SEH2_END;
337 
338     //
339     //  Nothing beyond this point should raise.
340     //
341 
342     RtlZeroMemory( Vcb->SwapVpb, sizeof( VPB ) );
343 
344     //
345     //  Initialize the resource variable for the Vcb and files.
346     //
347 
348     ExInitializeResourceLite( &Vcb->VcbResource );
349     ExInitializeResourceLite( &Vcb->FileResource );
350     ExInitializeFastMutex( &Vcb->VcbMutex );
351 
352     //
353     //  Insert this Vcb record on the CdData.VcbQueue.
354     //
355 
356     InsertHeadList( &CdData.VcbQueue, &Vcb->VcbLinks );
357 
358     //
359     //  Set the Target Device Object and Vpb fields, referencing the
360     //  Target device for the mount.
361     //
362 
363     ObReferenceObject( TargetDeviceObject );
364     Vcb->TargetDeviceObject = TargetDeviceObject;
365     Vcb->Vpb = Vpb;
366 
367     //
368     //  Set the removable media flag based on the real device's
369     //  characteristics
370     //
371 
372     if (FlagOn( Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA )) {
373 
374         SetFlag( Vcb->VcbState, VCB_STATE_REMOVABLE_MEDIA );
375     }
376 
377     //
378     //  Initialize the generic Fcb Table.
379     //
380 
381     RtlInitializeGenericTable( &Vcb->FcbTable,
382                                (PRTL_GENERIC_COMPARE_ROUTINE) CdFcbTableCompare,
383                                (PRTL_GENERIC_ALLOCATE_ROUTINE) CdAllocateFcbTable,
384                                (PRTL_GENERIC_FREE_ROUTINE) CdDeallocateFcbTable,
385                                NULL );
386 
387     //
388     //  Show that we have a mount in progress.
389     //
390 
391     CdUpdateVcbCondition( Vcb, VcbMountInProgress);
392 
393     //
394     //  Refererence the Vcb for two reasons.  The first is a reference
395     //  that prevents the Vcb from going away on the last close unless
396     //  dismount has already occurred.  The second is to make sure
397     //  we don't go into the dismount path on any error during mount
398     //  until we get to the Mount cleanup.
399     //
400 
401     Vcb->VcbReference = 1 + CDFS_RESIDUAL_REFERENCE;
402 
403     //
404     //  Update the TOC information in the Vcb.
405     //
406 
407     Vcb->CdromToc = CdromToc;
408     Vcb->TocLength = TocLength;
409     Vcb->TrackCount = TocTrackCount;
410     Vcb->DiskFlags = TocDiskFlags;
411 
412     //
413     //  If this disk contains audio tracks only then set the audio flag.
414     //
415 
416     if (TocDiskFlags == CDROM_DISK_AUDIO_TRACK) {
417 
418         SetFlag( Vcb->VcbState, VCB_STATE_AUDIO_DISK | VCB_STATE_CDXA );
419     }
420 
421     //
422     //  Set the block factor.
423     //
424 
425     Vcb->BlockFactor = BlockFactor;
426 
427     //
428     //  Set the media change count on the device
429     //
430 
431     CdUpdateMediaChangeCount( Vcb, MediaChangeCount);
432 }
433 
434 
435 VOID
436 CdUpdateVcbFromVolDescriptor (
437     _In_ PIRP_CONTEXT IrpContext,
438     _Inout_ PVCB Vcb,
439     _In_reads_bytes_opt_(SECTOR_SIZE) PCHAR RawIsoVd
440     )
441 
442 /*++
443 
444 Routine Description:
445 
446     This routine is called to perform the final initialization of a Vcb from the
447     volume descriptor on the disk.
448 
449 Arguments:
450 
451     Vcb - Vcb for the volume being mounted.  We have already set the flags for the
452         type of descriptor.
453 
454     RawIsoVd - If specified this is the volume descriptor to use to mount the
455         volume.  Not specified for a raw disk.
456 
457 Return Value:
458 
459     None
460 
461 --*/
462 
463 {
464     ULONG StartingBlock;
465     ULONG ByteCount;
466 
467     LONGLONG FileId = 0;
468 
469     PRAW_DIRENT RawDirent;
470     PATH_ENTRY PathEntry;
471     PCD_MCB_ENTRY McbEntry;
472 
473     BOOLEAN UnlockVcb = FALSE;
474 
475     PAGED_CODE();
476 
477     //
478     //  Use a try-finally to facilitate cleanup.
479     //
480 
481     _SEH2_TRY {
482 
483         //
484         //  Copy the block size and compute the various block masks.
485         //  Block size must not be larger than the sector size.  We will
486         //  use a default of the CD physical sector size if we are not
487         //  on a data-full disc.
488         //
489         //  This must always be set.
490         //
491 
492         Vcb->BlockSize = ( ARGUMENT_PRESENT( RawIsoVd ) ?
493                             CdRvdBlkSz( RawIsoVd, Vcb->VcbState ) :
494                             SECTOR_SIZE );
495 
496         //
497         //  We no longer accept media where blocksize != sector size.
498         //
499 
500         if (Vcb->BlockSize != SECTOR_SIZE)  {
501 
502             CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
503         }
504 
505         Vcb->BlocksPerSector = SECTOR_SIZE / Vcb->BlockSize;
506         Vcb->BlockMask = Vcb->BlockSize - 1;
507         Vcb->BlockInverseMask = ~Vcb->BlockMask;
508 
509         Vcb->BlockToSectorShift = 0;
510         Vcb->BlockToByteShift = SECTOR_SHIFT;
511 
512         //
513         //  If there is a volume descriptor then do the internal Fcb's and
514         //  other Vcb fields.
515         //
516 
517         if (ARGUMENT_PRESENT( RawIsoVd )) {
518 
519             //
520             //  Create the path table Fcb and refererence it and the Vcb.
521             //
522 
523             CdLockVcb( IrpContext, Vcb );
524             UnlockVcb = TRUE;
525 
526             Vcb->PathTableFcb = CdCreateFcb( IrpContext,
527                                              *((PFILE_ID) &FileId),
528                                              CDFS_NTC_FCB_PATH_TABLE,
529                                              NULL );
530 
531             CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 );
532             CdUnlockVcb( IrpContext, Vcb );
533             UnlockVcb = FALSE;
534 
535             //
536             //  Compute the stream offset and size of this path table.
537             //
538 
539             StartingBlock = CdRvdPtLoc( RawIsoVd, Vcb->VcbState );
540 
541             ByteCount = CdRvdPtSz( RawIsoVd, Vcb->VcbState );
542 
543             Vcb->PathTableFcb->StreamOffset = BytesFromBlocks( Vcb,
544                                                                SectorBlockOffset( Vcb, StartingBlock ));
545 
546             Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (Vcb->PathTableFcb->StreamOffset +
547                                                                ByteCount);
548 
549             Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart;
550 
551             Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart );
552 
553             //
554             //  Now add the mapping information.
555             //
556 
557             CdLockFcb( IrpContext, Vcb->PathTableFcb );
558 
559             CdAddInitialAllocation( IrpContext,
560                                     Vcb->PathTableFcb,
561                                     StartingBlock,
562                                     Vcb->PathTableFcb->AllocationSize.QuadPart );
563 
564             CdUnlockFcb( IrpContext, Vcb->PathTableFcb );
565 
566             //
567             //  Point to the file resource.
568             //
569 
570             Vcb->PathTableFcb->Resource = &Vcb->FileResource;
571 
572             //
573             //  Mark the Fcb as initialized and create the stream file for this.
574             //
575 
576             SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED );
577 
578             CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb, &CdInternalStreamNames[0]);
579 
580             //
581             //  Create the root index and reference it in the Vcb.
582             //
583 
584             CdLockVcb( IrpContext, Vcb );
585             UnlockVcb = TRUE;
586             Vcb->RootIndexFcb = CdCreateFcb( IrpContext,
587                                              *((PFILE_ID) &FileId),
588                                              CDFS_NTC_FCB_INDEX,
589                                              NULL );
590 
591             CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 );
592             CdUnlockVcb( IrpContext, Vcb );
593             UnlockVcb = FALSE;
594 
595             //
596             //  Create the File id by hand for this Fcb.
597             //
598 
599             CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset );
600             CdFidSetDirectory( Vcb->RootIndexFcb->FileId );
601 
602             //
603             //  Create a pseudo path table entry so we can call the initialization
604             //  routine for the directory.
605             //
606 
607             RawDirent = (PRAW_DIRENT) CdRvdDirent( RawIsoVd, Vcb->VcbState );
608 
609             CopyUchar4( &PathEntry.DiskOffset, RawDirent->FileLoc );
610 
611             PathEntry.DiskOffset += RawDirent->XarLen;
612             PathEntry.Ordinal = 1;
613             PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset;
614 
615             CdInitializeFcbFromPathEntry( IrpContext,
616                                           Vcb->RootIndexFcb,
617                                           NULL,
618                                           &PathEntry );
619 
620             //
621             //  Create the stream file for the root directory.
622             //
623 
624             CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb, &CdInternalStreamNames[1] );
625 
626             //
627             //  Now do the volume dasd Fcb.  Create this and reference it in the
628             //  Vcb.
629             //
630 
631             CdLockVcb( IrpContext, Vcb );
632             UnlockVcb = TRUE;
633 
634             Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext,
635                                               *((PFILE_ID) &FileId),
636                                               CDFS_NTC_FCB_DATA,
637                                               NULL );
638 
639             CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 );
640             CdUnlockVcb( IrpContext, Vcb );
641             UnlockVcb = FALSE;
642 
643             //
644             //  The file size is the full disk.
645             //
646 
647             StartingBlock = CdRvdVolSz( RawIsoVd, Vcb->VcbState );
648 
649             Vcb->VolumeDasdFcb->FileSize.QuadPart = LlBytesFromBlocks( Vcb, StartingBlock );
650 
651             Vcb->VolumeDasdFcb->AllocationSize.QuadPart =
652             Vcb->VolumeDasdFcb->ValidDataLength.QuadPart = Vcb->VolumeDasdFcb->FileSize.QuadPart;
653 
654             //
655             //  Now add the extent representing the volume 'by hand'.
656             //
657 
658             CdLockFcb( IrpContext, Vcb->VolumeDasdFcb );
659 
660             McbEntry = Vcb->VolumeDasdFcb->Mcb.McbArray;
661 
662             McbEntry->FileOffset =
663             McbEntry->DiskOffset = 0;
664 
665             McbEntry->ByteCount = Vcb->VolumeDasdFcb->AllocationSize.QuadPart;
666 
667             McbEntry->DataBlockByteCount =
668             McbEntry->TotalBlockByteCount = McbEntry->ByteCount;
669 
670             Vcb->VolumeDasdFcb->Mcb.CurrentEntryCount = 1;
671 
672             CdUnlockFcb( IrpContext, Vcb->VolumeDasdFcb );
673 
674             //
675             //  Point to the file resource.
676             //
677 
678             Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource;
679 
680             Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY;
681 
682             //
683             //  Mark the Fcb as initialized.
684             //
685 
686             SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED );
687 
688             //
689             //  Check and see if this is an XA disk.
690             //
691 
692             if (FlagOn( Vcb->VcbState, VCB_STATE_ISO | VCB_STATE_JOLIET)
693                 && RtlEqualMemory( CdXaId,
694                                    Add2Ptr( RawIsoVd, 0x400, PCHAR ),
695                                    8 )) {
696 
697                 SetFlag( Vcb->VcbState, VCB_STATE_CDXA );
698             }
699 
700         //
701         //  If this is a music disk then we want to mock this disk to make it
702         //  look like ISO disk.  We will create a pseudo root directory in
703         //  that case.
704         //
705 
706         } else if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
707 
708             ULONG RootDirectorySize;
709 
710             //
711             //  Create the path table Fcb and refererence it and the Vcb.
712             //
713 
714             CdLockVcb( IrpContext, Vcb );
715             UnlockVcb = TRUE;
716 
717             Vcb->PathTableFcb = CdCreateFcb( IrpContext,
718                                              *((PFILE_ID) &FileId),
719                                              CDFS_NTC_FCB_PATH_TABLE,
720                                              NULL );
721 
722             CdIncrementReferenceCounts( IrpContext, Vcb->PathTableFcb, 1, 1 );
723             CdUnlockVcb( IrpContext, Vcb );
724             UnlockVcb = FALSE;
725 
726             //
727             //  We only create a pseudo entry for the root.
728             //
729 
730             Vcb->PathTableFcb->FileSize.QuadPart = (LONGLONG) (FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2);
731 
732             Vcb->PathTableFcb->ValidDataLength.QuadPart = Vcb->PathTableFcb->FileSize.QuadPart;
733 
734             Vcb->PathTableFcb->AllocationSize.QuadPart = LlSectorAlign( Vcb->PathTableFcb->FileSize.QuadPart );
735 
736             //
737             //  Point to the file resource.
738             //
739 
740             Vcb->PathTableFcb->Resource = &Vcb->FileResource;
741 
742             //
743             //  Mark the Fcb as initialized and create the stream file for this.
744             //
745 
746             SetFlag( Vcb->PathTableFcb->FcbState, FCB_STATE_INITIALIZED );
747 
748             CdCreateInternalStream( IrpContext, Vcb, Vcb->PathTableFcb, &CdInternalStreamNames[0]);
749 
750             //
751             //  Create the root index and reference it in the Vcb.
752             //
753 
754             CdLockVcb( IrpContext, Vcb );
755             UnlockVcb = TRUE;
756             Vcb->RootIndexFcb = CdCreateFcb( IrpContext,
757                                              *((PFILE_ID) &FileId),
758                                              CDFS_NTC_FCB_INDEX,
759                                              NULL );
760 
761             CdIncrementReferenceCounts( IrpContext, Vcb->RootIndexFcb, 1, 1 );
762             CdUnlockVcb( IrpContext, Vcb );
763             UnlockVcb = FALSE;
764 
765             //
766             //  Create the File id by hand for this Fcb.
767             //
768 
769             CdSetFidPathTableOffset( Vcb->RootIndexFcb->FileId, Vcb->PathTableFcb->StreamOffset );
770             CdFidSetDirectory( Vcb->RootIndexFcb->FileId );
771 
772             //
773             //  Create a pseudo path table entry so we can call the initialization
774             //  routine for the directory.
775             //
776 
777             RtlZeroMemory( &PathEntry, sizeof( PATH_ENTRY ));
778 
779 
780             PathEntry.Ordinal = 1;
781             PathEntry.PathTableOffset = Vcb->PathTableFcb->StreamOffset;
782 
783             CdInitializeFcbFromPathEntry( IrpContext,
784                                           Vcb->RootIndexFcb,
785                                           NULL,
786                                           &PathEntry );
787 
788             //
789             //  Set the sizes by hand for this Fcb.  It should have an entry for each track plus an
790             //  entry for the root and parent.
791             //
792 
793             RootDirectorySize = (Vcb->TrackCount + 2) * CdAudioDirentSize;
794             RootDirectorySize = SectorAlign( RootDirectorySize );
795 
796             Vcb->RootIndexFcb->AllocationSize.QuadPart =
797             Vcb->RootIndexFcb->ValidDataLength.QuadPart =
798             Vcb->RootIndexFcb->FileSize.QuadPart = RootDirectorySize;
799 
800             SetFlag( Vcb->RootIndexFcb->FcbState, FCB_STATE_INITIALIZED );
801 
802             //
803             //  Create the stream file for the root directory.
804             //
805 
806             CdCreateInternalStream( IrpContext, Vcb, Vcb->RootIndexFcb, &CdInternalStreamNames[1] );
807 
808             //
809             //  Now do the volume dasd Fcb.  Create this and reference it in the
810             //  Vcb.
811             //
812 
813             CdLockVcb( IrpContext, Vcb );
814             UnlockVcb = TRUE;
815 
816             Vcb->VolumeDasdFcb = CdCreateFcb( IrpContext,
817                                               *((PFILE_ID) &FileId),
818                                               CDFS_NTC_FCB_DATA,
819                                               NULL );
820 
821             CdIncrementReferenceCounts( IrpContext, Vcb->VolumeDasdFcb, 1, 1 );
822             CdUnlockVcb( IrpContext, Vcb );
823             UnlockVcb = FALSE;
824 
825             //
826             //  We won't allow raw reads on this Fcb so leave the size at
827             //  zero.
828             //
829 
830             //
831             //  Point to the file resource.
832             //
833 
834             Vcb->VolumeDasdFcb->Resource = &Vcb->FileResource;
835 
836             Vcb->VolumeDasdFcb->FileAttributes = FILE_ATTRIBUTE_READONLY;
837 
838             //
839             //  Mark the Fcb as initialized.
840             //
841 
842             SetFlag( Vcb->VolumeDasdFcb->FcbState, FCB_STATE_INITIALIZED );
843 
844             //
845             //  We will store a hard-coded name in the Vpb and use the toc as
846             //  the serial number.
847             //
848 
849             Vcb->Vpb->VolumeLabelLength = CdAudioLabelLength;
850 
851             RtlCopyMemory( Vcb->Vpb->VolumeLabel,
852                            CdAudioLabel,
853                            CdAudioLabelLength );
854 
855             //
856             //  Find the serial number for the audio disk.
857             //
858 
859             Vcb->Vpb->SerialNumber = CdTocSerial( IrpContext, Vcb->CdromToc );
860 
861             //
862             //  Set the ISO bit so we know how to treat the names.
863             //
864 
865             SetFlag( Vcb->VcbState, VCB_STATE_ISO );
866         }
867 
868     } _SEH2_FINALLY {
869 
870         if (UnlockVcb) { CdUnlockVcb( IrpContext, Vcb ); }
871     } _SEH2_END;
872 }
873 
874 
875 VOID
876 CdDeleteVcb (
877     _In_ PIRP_CONTEXT IrpContext,
878     _Inout_ PVCB Vcb
879     )
880 
881 /*++
882 
883 Routine Description:
884 
885     This routine is called to delete a Vcb which failed mount or has been
886     dismounted.  The dismount code should have already removed all of the
887     open Fcb's.  We do nothing here but clean up other auxilary structures.
888 
889 Arguments:
890 
891     Vcb - Vcb to delete.
892 
893 Return Value:
894 
895     None
896 
897 --*/
898 
899 {
900     PAGED_CODE();
901 
902     ASSERT_EXCLUSIVE_CDDATA;
903     ASSERT_EXCLUSIVE_VCB( Vcb );
904 
905     UNREFERENCED_PARAMETER( IrpContext );
906 
907     //
908     //  Chuck the backpocket Vpb we kept just in case.
909     //
910 
911     CdFreePool( &Vcb->SwapVpb );
912 
913     //
914     //  If there is a Vpb then we must delete it ourselves.
915     //
916 
917     CdFreePool( &Vcb->Vpb );
918 
919     //
920     //  Dereference our target if we haven't already done so.
921     //
922 
923     if (Vcb->TargetDeviceObject != NULL) {
924 
925         ObDereferenceObject( Vcb->TargetDeviceObject );
926     }
927 
928     //
929     //  Delete the XA Sector and sector cache buffer if allocated.
930     //
931 
932     CdFreePool( &Vcb->XASector );
933     CdFreePool( &Vcb->SectorCacheBuffer);
934 
935     if (Vcb->SectorCacheIrp != NULL) {
936 
937         IoFreeIrp( Vcb->SectorCacheIrp);
938         Vcb->SectorCacheIrp = NULL;
939 
940         ExDeleteResourceLite( &Vcb->SectorCacheResource);
941     }
942 
943     //
944     //  Remove this entry from the global queue.
945     //
946 
947     RemoveEntryList( &Vcb->VcbLinks );
948 
949     //
950     //  Delete the Vcb and File resources.
951     //
952 
953     ExDeleteResourceLite( &Vcb->VcbResource );
954     ExDeleteResourceLite( &Vcb->FileResource );
955 
956     //
957     //  Delete the TOC if present.
958     //
959 
960     CdFreePool( &Vcb->CdromToc );
961 
962     //
963     //  Uninitialize the notify structures.
964     //
965 
966     if (Vcb->NotifySync != NULL) {
967 
968         FsRtlNotifyUninitializeSync( &Vcb->NotifySync );
969     }
970 
971     //
972     //  Now delete the volume device object.
973     //
974 #ifdef _MSC_VER
975 #pragma prefast( suppress: __WARNING_BUFFER_UNDERFLOW, "This is ok, the Vcb is embedded in our volume device object, and that is what we are really deleting." )
976 #endif
977     IoDeleteDevice( (PDEVICE_OBJECT) CONTAINING_RECORD( Vcb,
978                                                         VOLUME_DEVICE_OBJECT,
979                                                         Vcb ));
980 
981     return;
982 }
983 
984 
985 PFCB
986 CdCreateFcb (
987     _In_ PIRP_CONTEXT IrpContext,
988     _In_ FILE_ID FileId,
989     _In_ NODE_TYPE_CODE NodeTypeCode,
990     _Out_opt_ PBOOLEAN FcbExisted
991     )
992 
993 /*++
994 
995 Routine Description:
996 
997     This routine is called to find the Fcb for the given FileId.  We will
998     look this up first in the Fcb table and if not found we will create
999     an Fcb.  We don't initialize it or insert it into the FcbTable in this
1000     routine.
1001 
1002     This routine is called while the Vcb is locked.
1003 
1004 Arguments:
1005 
1006     FileId - This is the Id for the target Fcb.
1007 
1008     NodeTypeCode - Node type for this Fcb if we need to create.
1009 
1010     FcbExisted - If specified, we store whether the Fcb existed.
1011 
1012 Return Value:
1013 
1014     PFCB - The Fcb found in the table or created if needed.
1015 
1016 --*/
1017 
1018 {
1019     PFCB NewFcb;
1020     BOOLEAN LocalFcbExisted;
1021 
1022     PAGED_CODE();
1023 
1024     //
1025     //  Use the local boolean if one was not passed in.
1026     //
1027 
1028     if (!ARGUMENT_PRESENT( FcbExisted )) {
1029 
1030         FcbExisted = &LocalFcbExisted;
1031     }
1032 
1033     //
1034     //  Maybe this is already in the table.
1035     //
1036 
1037     NewFcb = CdLookupFcbTable( IrpContext, IrpContext->Vcb, FileId );
1038 
1039     //
1040     //  If not then create the Fcb is requested by our caller.
1041     //
1042 
1043     if (NewFcb == NULL) {
1044 
1045         //
1046         //  Allocate and initialize the structure depending on the
1047         //  type code.
1048         //
1049 
1050         switch (NodeTypeCode) {
1051 
1052         case CDFS_NTC_FCB_PATH_TABLE:
1053         case CDFS_NTC_FCB_INDEX:
1054 
1055             NewFcb = CdAllocateFcbIndex( IrpContext );
1056 
1057             RtlZeroMemory( NewFcb, SIZEOF_FCB_INDEX );
1058 
1059             NewFcb->NodeByteSize = SIZEOF_FCB_INDEX;
1060 
1061             InitializeListHead( &NewFcb->FcbQueue );
1062 
1063             break;
1064 
1065         case CDFS_NTC_FCB_DATA :
1066 
1067             NewFcb = CdAllocateFcbData( IrpContext );
1068 
1069             RtlZeroMemory( NewFcb, SIZEOF_FCB_DATA );
1070 
1071             NewFcb->NodeByteSize = SIZEOF_FCB_DATA;
1072 
1073             break;
1074 
1075         default:
1076 
1077 #ifdef _MSC_VER
1078 #pragma prefast( suppress: __WARNING_USE_OTHER_FUNCTION, "This is a bug." )
1079 #endif
1080             CdBugCheck( 0, 0, 0 );
1081         }
1082 
1083         //
1084         //  Now do the common initialization.
1085         //
1086 
1087         NewFcb->NodeTypeCode = NodeTypeCode;
1088 
1089         NewFcb->Vcb = IrpContext->Vcb;
1090         NewFcb->FileId = FileId;
1091 
1092         CdInitializeMcb( IrpContext, NewFcb );
1093 
1094         //
1095         //  Now create the non-paged section object.
1096         //
1097 
1098         NewFcb->FcbNonpaged = CdCreateFcbNonpaged( IrpContext );
1099 
1100         //
1101         //  Deallocate the Fcb and raise if the allocation failed.
1102         //
1103 
1104         if (NewFcb->FcbNonpaged == NULL) {
1105 
1106             CdFreePool( &NewFcb );
1107 
1108             CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
1109         }
1110 
1111         *FcbExisted = FALSE;
1112 
1113         //
1114         //  Initialize Advanced FCB Header fields
1115         //
1116 
1117         ExInitializeFastMutex( &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
1118         FsRtlSetupAdvancedHeader( &NewFcb->Header,
1119                                   &NewFcb->FcbNonpaged->AdvancedFcbHeaderMutex );
1120 
1121         if (NodeTypeCode == CDFS_NTC_FCB_DATA) {
1122 
1123             FsRtlInitializeOplock( CdGetFcbOplock(NewFcb) );
1124         }
1125 
1126     } else {
1127 
1128         *FcbExisted = TRUE;
1129     }
1130 
1131     return NewFcb;
1132 }
1133 
1134 
1135 VOID
1136 CdInitializeFcbFromPathEntry (
1137     _In_ PIRP_CONTEXT IrpContext,
1138     _Inout_ PFCB Fcb,
1139     _In_opt_ PFCB ParentFcb,
1140     _In_ PPATH_ENTRY PathEntry
1141     )
1142 
1143 /*++
1144 
1145 Routine Description:
1146 
1147     This routine is called to initialize an Fcb for a directory from
1148     the path entry.  Since we only have a starting point for the directory,
1149     not the length, we can only speculate on the sizes.
1150 
1151     The general initialization is performed in CdCreateFcb.
1152 
1153 Arguments:
1154 
1155     Fcb - Newly created Fcb for this stream.
1156 
1157     ParentFcb - Parent Fcb for this stream.  It may not be present.
1158 
1159     PathEntry - PathEntry for this Fcb in the Path Table.
1160 
1161 Return Value:
1162 
1163     None
1164 
1165 --*/
1166 
1167 {
1168     PAGED_CODE();
1169 
1170     //
1171     //  Fill in the Index specific fields of the Fcb.
1172     //
1173 
1174     Fcb->StreamOffset = BytesFromBlocks( Fcb->Vcb,
1175                                          SectorBlockOffset( Fcb->Vcb, PathEntry->DiskOffset ));
1176 
1177     Fcb->Ordinal = PathEntry->Ordinal;
1178 
1179     //
1180     //  Initialize the common header in the Fcb.  The node type is already
1181     //  present.
1182     //
1183 
1184     Fcb->Resource = &Fcb->Vcb->FileResource;
1185 
1186     //
1187     //  Always set the sizes to one sector until we read the self-entry.
1188     //
1189 
1190     Fcb->AllocationSize.QuadPart =
1191     Fcb->FileSize.QuadPart =
1192     Fcb->ValidDataLength.QuadPart = SECTOR_SIZE;
1193 
1194     CdAddInitialAllocation( IrpContext,
1195                             Fcb,
1196                             PathEntry->DiskOffset,
1197                             SECTOR_SIZE );
1198     //
1199     //  State flags for this Fcb.
1200     //
1201 
1202     SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY );
1203 
1204     //
1205     //  Link into the other in-memory structures and into the Fcb table.
1206     //
1207 
1208     if (ParentFcb != NULL) {
1209 
1210         Fcb->ParentFcb = ParentFcb;
1211 
1212         InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks );
1213 
1214         CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
1215     }
1216 
1217     CdInsertFcbTable( IrpContext, Fcb );
1218     SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
1219 
1220     return;
1221 }
1222 
1223 
1224 VOID
1225 CdInitializeFcbFromFileContext (
1226     _In_ PIRP_CONTEXT IrpContext,
1227     _Inout_ PFCB Fcb,
1228     _In_ PFCB ParentFcb,
1229     _In_ PFILE_ENUM_CONTEXT FileContext
1230     )
1231 
1232 /*++
1233 
1234 Routine Description:
1235 
1236     This routine is called to initialize an Fcb for a file from
1237     the file context.  We have looked up all of the dirents for this
1238     stream and have the full file size.  We will load the all of the allocation
1239     for the file into the Mcb now.
1240 
1241     The general initialization is performed in CdCreateFcb.
1242 
1243 Arguments:
1244 
1245     Fcb - Newly created Fcb for this stream.
1246 
1247     ParentFcb - Parent Fcb for this stream.
1248 
1249     FileContext - FileContext for the file.
1250 
1251 Return Value:
1252 
1253     None
1254 
1255 --*/
1256 
1257 {
1258     PDIRENT ThisDirent = &FileContext->InitialDirent->Dirent;
1259     PCOMPOUND_DIRENT CurrentCompoundDirent;
1260 
1261     LONGLONG CurrentFileOffset;
1262     ULONG CurrentMcbEntryOffset;
1263 
1264     PAGED_CODE();
1265 
1266     //
1267     //  Use a try-finally to facilitate cleanup.
1268     //
1269 
1270     CdLockFcb( IrpContext, Fcb );
1271 
1272     _SEH2_TRY {
1273 
1274         //
1275         //  Initialize the common header in the Fcb.  The node type is already
1276         //  present.
1277         //
1278 
1279         Fcb->Resource = &IrpContext->Vcb->FileResource;
1280 
1281         //
1282         //  Allocation occurs in block-sized units.
1283         //
1284 
1285         Fcb->FileSize.QuadPart =
1286         Fcb->ValidDataLength.QuadPart = FileContext->FileSize;
1287 
1288         Fcb->AllocationSize.QuadPart = LlBlockAlign( Fcb->Vcb, FileContext->FileSize );
1289 
1290         //
1291         //  Set the flags from the dirent.  We always start with the read-only bit.
1292         //
1293 
1294         SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_READONLY );
1295         if (FlagOn( ThisDirent->DirentFlags, CD_ATTRIBUTE_HIDDEN )) {
1296 
1297             SetFlag( Fcb->FileAttributes, FILE_ATTRIBUTE_HIDDEN );
1298         }
1299 
1300         //
1301         //  Convert the time to NT time.
1302         //
1303 
1304         CdConvertCdTimeToNtTime( IrpContext,
1305                                  ThisDirent->CdTime,
1306                                  (PLARGE_INTEGER) &Fcb->CreationTime );
1307 
1308         //
1309         //  Set the flag indicating the type of extent.
1310         //
1311 
1312         if (ThisDirent->ExtentType != Form1Data) {
1313 
1314             if (ThisDirent->ExtentType == Mode2Form2Data) {
1315 
1316                 SetFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE );
1317 
1318             } else {
1319 
1320                 SetFlag( Fcb->FcbState, FCB_STATE_DA_FILE );
1321             }
1322 
1323             Fcb->XAAttributes = ThisDirent->XAAttributes;
1324             Fcb->XAFileNumber = ThisDirent->XAFileNumber;
1325         }
1326 
1327         //
1328         //  Read through all of the dirents for the file until we find the last
1329         //  and add the allocation into the Mcb.
1330         //
1331 
1332         CurrentCompoundDirent = FileContext->InitialDirent;
1333         CurrentFileOffset = 0;
1334         CurrentMcbEntryOffset = 0;
1335 
1336         while (TRUE) {
1337 
1338             CdAddAllocationFromDirent( IrpContext,
1339                                        Fcb,
1340                                        CurrentMcbEntryOffset,
1341                                        CurrentFileOffset,
1342                                        &CurrentCompoundDirent->Dirent );
1343 
1344             //
1345             //  Break out if we are at the last dirent.
1346             //
1347 
1348             if (!FlagOn( CurrentCompoundDirent->Dirent.DirentFlags, CD_ATTRIBUTE_MULTI )) {
1349 
1350                 break;
1351             }
1352 
1353             CurrentFileOffset += CurrentCompoundDirent->Dirent.DataLength;
1354             CurrentMcbEntryOffset += 1;
1355 
1356             //
1357             //  We better be able to find the next dirent.
1358             //
1359 
1360             if (!CdLookupNextDirent( IrpContext,
1361                                      ParentFcb,
1362                                      &CurrentCompoundDirent->DirContext,
1363                                      &FileContext->CurrentDirent->DirContext )) {
1364 
1365                 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1366             }
1367 
1368             CurrentCompoundDirent = FileContext->CurrentDirent;
1369 
1370             CdUpdateDirentFromRawDirent( IrpContext,
1371                                          ParentFcb,
1372                                          &CurrentCompoundDirent->DirContext,
1373                                          &CurrentCompoundDirent->Dirent );
1374         }
1375 
1376         //
1377         //  Show that the Fcb is initialized.
1378         //
1379 
1380         SetFlag( Fcb->FcbState, FCB_STATE_INITIALIZED );
1381 
1382         //
1383         //  Link into the other in-memory structures and into the Fcb table.
1384         //
1385 
1386         Fcb->ParentFcb = ParentFcb;
1387 
1388         InsertTailList( &ParentFcb->FcbQueue, &Fcb->FcbLinks );
1389 
1390         CdIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
1391 
1392         CdInsertFcbTable( IrpContext, Fcb );
1393         SetFlag( Fcb->FcbState, FCB_STATE_IN_FCB_TABLE );
1394 
1395     } _SEH2_FINALLY {
1396 
1397         CdUnlockFcb( IrpContext, Fcb );
1398     } _SEH2_END;
1399 
1400     return;
1401 }
1402 
1403 
1404 PCCB
1405 CdCreateCcb (
1406     _In_ PIRP_CONTEXT IrpContext,
1407     _In_ PFCB Fcb,
1408     _In_ ULONG Flags
1409     )
1410 
1411 /*++
1412 
1413 Routine Description:
1414 
1415     This routine is called to allocate and initialize the Ccb structure.
1416 
1417 Arguments:
1418 
1419     Fcb - This is the Fcb for the file being opened.
1420 
1421     Flags - User flags to set in this Ccb.
1422 
1423 Return Value:
1424 
1425     PCCB - Pointer to the created Ccb.
1426 
1427 --*/
1428 
1429 {
1430     PCCB NewCcb;
1431     PAGED_CODE();
1432 
1433     UNREFERENCED_PARAMETER( IrpContext );
1434 
1435     //
1436     //  Allocate and initialize the structure.
1437     //
1438 
1439     NewCcb = CdAllocateCcb( IrpContext );
1440 
1441     RtlZeroMemory( NewCcb, sizeof( CCB ));
1442 
1443     //
1444     //  Set the proper node type code and node byte size
1445     //
1446 
1447     NewCcb->NodeTypeCode = CDFS_NTC_CCB;
1448     NewCcb->NodeByteSize = sizeof( CCB );
1449 
1450     //
1451     //  Set the initial value for the flags and Fcb
1452     //
1453 
1454     NewCcb->Flags = Flags;
1455     NewCcb->Fcb = Fcb;
1456 
1457     return NewCcb;
1458 }
1459 
1460 
1461 VOID
1462 CdDeleteCcb (
1463     _In_ PIRP_CONTEXT IrpContext,
1464     _In_ __drv_freesMem( Pool ) PCCB Ccb
1465     )
1466 /*++
1467 
1468 Routine Description:
1469 
1470     This routine is called to cleanup and deallocate a Ccb structure.
1471 
1472 Arguments:
1473 
1474     Ccb - This is the Ccb to delete.
1475 
1476 Return Value:
1477 
1478     None
1479 
1480 --*/
1481 
1482 {
1483     PAGED_CODE();
1484 
1485     UNREFERENCED_PARAMETER( IrpContext );
1486 
1487     if (Ccb->SearchExpression.FileName.Buffer != NULL) {
1488 
1489         CdFreePool( &Ccb->SearchExpression.FileName.Buffer );
1490     }
1491 
1492     CdDeallocateCcb( IrpContext, Ccb );
1493     return;
1494 }
1495 
1496 
1497 _When_(RaiseOnError || return, _At_(Fcb->FileLock, _Post_notnull_))
1498 _When_(RaiseOnError, _At_(IrpContext, _Pre_notnull_))
1499 BOOLEAN
1500 CdCreateFileLock (
1501     _In_opt_ PIRP_CONTEXT IrpContext,
1502     _Inout_ PFCB Fcb,
1503     _In_ BOOLEAN RaiseOnError
1504     )
1505 
1506 /*++
1507 
1508 Routine Description:
1509 
1510     This routine is called when we want to attach a file lock structure to the
1511     given Fcb.  It is possible the file lock is already attached.
1512 
1513     This routine is sometimes called from the fast path and sometimes in the
1514     Irp-based path.  We don't want to raise in the fast path, just return FALSE.
1515 
1516 Arguments:
1517 
1518     Fcb - This is the Fcb to create the file lock for.
1519 
1520     RaiseOnError - If TRUE, we will raise on an allocation failure.  Otherwise we
1521         return FALSE on an allocation failure.
1522 
1523 Return Value:
1524 
1525     BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise.
1526 
1527 --*/
1528 
1529 {
1530     BOOLEAN Result = TRUE;
1531     PFILE_LOCK FileLock;
1532 
1533     PAGED_CODE();
1534 
1535     //
1536     //  Lock the Fcb and check if there is really any work to do.
1537     //
1538 
1539     CdLockFcb( IrpContext, Fcb );
1540 
1541     if (Fcb->FileLock != NULL) {
1542 
1543         CdUnlockFcb( IrpContext, Fcb );
1544         return TRUE;
1545     }
1546 
1547     Fcb->FileLock = FileLock =
1548         FsRtlAllocateFileLock( NULL, NULL );
1549 
1550     CdUnlockFcb( IrpContext, Fcb );
1551 
1552     //
1553     //  Return or raise as appropriate.
1554     //
1555 
1556     if (FileLock == NULL) {
1557 
1558         if (RaiseOnError) {
1559 
1560             NT_ASSERT( ARGUMENT_PRESENT( IrpContext ));
1561 
1562             CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
1563         }
1564 
1565         Result = FALSE;
1566     }
1567 
1568     return Result;
1569 }
1570 
1571 
1572 _Ret_valid_ PIRP_CONTEXT
1573 CdCreateIrpContext (
1574     _In_ PIRP Irp,
1575     _In_ BOOLEAN Wait
1576     )
1577 
1578 /*++
1579 
1580 Routine Description:
1581 
1582     This routine is called to initialize an IrpContext for the current
1583     CDFS request.  We allocate the structure and then initialize it from
1584     the given Irp.
1585 
1586 Arguments:
1587 
1588     Irp - Irp for this request.
1589 
1590     Wait - TRUE if this request is synchronous, FALSE otherwise.
1591 
1592 Return Value:
1593 
1594     PIRP_CONTEXT - Allocated IrpContext.
1595 
1596 --*/
1597 
1598 {
1599     PIRP_CONTEXT NewIrpContext = NULL;
1600     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
1601 
1602     PAGED_CODE();
1603 
1604     //
1605     //  The only operations a filesystem device object should ever receive
1606     //  are create/teardown of fsdo handles and operations which do not
1607     //  occur in the context of fileobjects (i.e., mount).
1608     //
1609 
1610 #ifndef __REACTOS__
1611     if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject) {
1612 #else
1613     if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject ||
1614         IrpSp->DeviceObject == CdData.HddFileSystemDeviceObject) {
1615 #endif
1616 
1617         if (IrpSp->FileObject != NULL &&
1618             IrpSp->MajorFunction != IRP_MJ_CREATE &&
1619             IrpSp->MajorFunction != IRP_MJ_CLEANUP &&
1620             IrpSp->MajorFunction != IRP_MJ_CLOSE) {
1621 
1622             ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
1623         }
1624 
1625         NT_ASSERT( IrpSp->FileObject != NULL ||
1626 
1627                 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
1628                  IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
1629                  IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) ||
1630 
1631                 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
1632                  IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ||
1633 
1634                 IrpSp->MajorFunction == IRP_MJ_SHUTDOWN );
1635     }
1636 
1637     //
1638     //  Look in our lookaside list for an IrpContext.
1639     //
1640 
1641     if (CdData.IrpContextDepth) {
1642 
1643         CdLockCdData();
1644         NewIrpContext = (PIRP_CONTEXT) PopEntryList( &CdData.IrpContextList );
1645         if (NewIrpContext != NULL) {
1646 
1647             CdData.IrpContextDepth--;
1648         }
1649 
1650         CdUnlockCdData();
1651     }
1652 
1653     if (NewIrpContext == NULL) {
1654 
1655         //
1656         //  We didn't get it from our private list so allocate it from pool.
1657         //
1658 
1659         NewIrpContext = FsRtlAllocatePoolWithTag( CdNonPagedPool, sizeof( IRP_CONTEXT ), TAG_IRP_CONTEXT );
1660     }
1661 
1662     RtlZeroMemory( NewIrpContext, sizeof( IRP_CONTEXT ));
1663 
1664     //
1665     //  Set the proper node type code and node byte size
1666     //
1667 
1668     NewIrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
1669     NewIrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
1670 
1671     //
1672     //  Set the originating Irp field
1673     //
1674 
1675     NewIrpContext->Irp = Irp;
1676 
1677     //
1678     //  Copy RealDevice for workque algorithms.  We will update this in the Mount or
1679     //  Verify since they have no file objects to use here.
1680     //
1681 
1682     if (IrpSp->FileObject != NULL) {
1683 
1684         NewIrpContext->RealDevice = IrpSp->FileObject->DeviceObject;
1685     }
1686 
1687     //
1688     //  Locate the volume device object and Vcb that we are trying to access.
1689     //  This may be our filesystem device object.  In that case don't initialize
1690     //  the Vcb field.
1691     //
1692 
1693 #ifndef __REACTOS__
1694     if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject) {
1695 #else
1696     if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject &&
1697         IrpSp->DeviceObject != CdData.HddFileSystemDeviceObject) {
1698 #endif
1699 
1700         NewIrpContext->Vcb =  &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
1701 
1702     }
1703 
1704     //
1705     //  Major/Minor Function codes
1706     //
1707 
1708     NewIrpContext->MajorFunction = IrpSp->MajorFunction;
1709     NewIrpContext->MinorFunction = IrpSp->MinorFunction;
1710 
1711     //
1712     //  Set the wait parameter
1713     //
1714 
1715     if (Wait) {
1716 
1717         SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
1718 
1719     } else {
1720 
1721         SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
1722     }
1723 
1724     //
1725     //  return and tell the caller
1726     //
1727 
1728     return NewIrpContext;
1729 }
1730 
1731 
1732 VOID
1733 CdCleanupIrpContext (
1734     _In_ PIRP_CONTEXT IrpContext,
1735     _In_ BOOLEAN Post
1736     )
1737 
1738 /*++
1739 
1740 Routine Description:
1741 
1742     This routine is called to cleanup and possibly deallocate the Irp Context.
1743     If the request is being posted or this Irp Context is possibly on the
1744     stack then we only cleanup any auxilary structures.
1745 
1746 Arguments:
1747 
1748     Post - TRUE if we are posting this request, FALSE if we are deleting
1749         or retrying this in the current thread.
1750 
1751 Return Value:
1752 
1753     None.
1754 
1755 --*/
1756 
1757 {
1758     PAGED_CODE();
1759 
1760     //
1761     //  If we aren't doing more processing then deallocate this as appropriate.
1762     //
1763 
1764     if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING)) {
1765 
1766         //
1767         //  If this context is the top level CDFS context then we need to
1768         //  restore the top level thread context.
1769         //
1770 
1771         if (IrpContext->ThreadContext != NULL) {
1772 
1773             CdRestoreThreadContext( IrpContext );
1774         }
1775 
1776         //
1777         //  Deallocate the Io context if allocated.
1778         //
1779 
1780         if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
1781 
1782             CdFreeIoContext( IrpContext->IoContext );
1783         }
1784 
1785         //
1786         //  Deallocate the IrpContext if not from the stack.
1787         //
1788 
1789         if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK )) {
1790 
1791             if (CdData.IrpContextDepth < CdData.IrpContextMaxDepth) {
1792 
1793                 CdLockCdData();
1794 
1795                 PushEntryList( &CdData.IrpContextList, (PSINGLE_LIST_ENTRY) IrpContext );
1796                 CdData.IrpContextDepth++;
1797 
1798                 CdUnlockCdData();
1799 
1800             } else {
1801 
1802                 //
1803                 //  We couldn't add this to our lookaside list so free it to
1804                 //  pool.
1805                 //
1806 
1807                 CdFreePool( &IrpContext );
1808             }
1809         }
1810 
1811     //
1812     //  Clear the appropriate flags.
1813     //
1814 
1815     } else if (Post) {
1816 
1817         //
1818         //  If this context is the top level CDFS context then we need to
1819         //  restore the top level thread context.
1820         //
1821 
1822         if (IrpContext->ThreadContext != NULL) {
1823 
1824             CdRestoreThreadContext( IrpContext );
1825         }
1826 
1827         ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST );
1828 
1829     } else {
1830 
1831         ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY );
1832     }
1833 
1834     return;
1835 }
1836 
1837 
1838 VOID
1839 CdInitializeStackIrpContext (
1840     _Out_ PIRP_CONTEXT IrpContext,
1841     _In_ PIRP_CONTEXT_LITE IrpContextLite
1842     )
1843 
1844 /*++
1845 
1846 Routine Description:
1847 
1848     This routine is called to initialize an IrpContext for the current
1849     CDFS request.  The IrpContext is on the stack and we need to initialize
1850     it for the current request.  The request is a close operation.
1851 
1852 Arguments:
1853 
1854     IrpContext - IrpContext to initialize.
1855 
1856     IrpContextLite - Structure containing the details of this request.
1857 
1858 Return Value:
1859 
1860     None
1861 
1862 --*/
1863 
1864 {
1865     PAGED_CODE();
1866 
1867     //
1868     //  Zero and then initialize the structure.
1869     //
1870 
1871     RtlZeroMemory( IrpContext, sizeof( IRP_CONTEXT ));
1872 
1873     //
1874     //  Set the proper node type code and node byte size
1875     //
1876 
1877     IrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
1878     IrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
1879 
1880     //
1881     //  Note that this is from the stack.
1882     //
1883 
1884     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK );
1885 
1886     //
1887     //  Copy RealDevice for workque algorithms.
1888     //
1889 
1890     IrpContext->RealDevice = IrpContextLite->RealDevice;
1891 
1892     //
1893     //  The Vcb is found in the Fcb.
1894     //
1895 
1896     IrpContext->Vcb = IrpContextLite->Fcb->Vcb;
1897 
1898     //
1899     //  Major/Minor Function codes
1900     //
1901 
1902     IrpContext->MajorFunction = IRP_MJ_CLOSE;
1903 
1904     //
1905     //  Set the wait parameter
1906     //
1907 
1908     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
1909 
1910     return;
1911 }
1912 
1913 
1914 
1915 _Requires_lock_held_(_Global_critical_region_)
1916 VOID
1917 CdTeardownStructures (
1918     _In_ PIRP_CONTEXT IrpContext,
1919     _Inout_ PFCB StartingFcb,
1920     _Out_ PBOOLEAN RemovedStartingFcb
1921     )
1922 
1923 /*++
1924 
1925 Routine Description:
1926 
1927     This routine is used to walk from some starting point in the Fcb tree towards
1928     the root.  It will remove the Fcb and continue walking up the tree until
1929     it finds a point where we can't remove an Fcb.
1930 
1931     We look at the following fields in the Fcb to determine whether we can
1932     remove this.
1933 
1934         1 - Handle count must be zero.
1935         2 - If directory then only the only reference can be for a stream file.
1936         3 - Reference count must either be zero or go to zero here.
1937 
1938     We return immediately if we are recursively entering this routine.
1939 
1940 Arguments:
1941 
1942     StartingFcb - This is the Fcb node in the tree to begin with.  This Fcb
1943         must currently be acquired exclusively.
1944 
1945     RemovedStartingFcb - Address to store whether we removed the starting Fcb.
1946 
1947 Return Value:
1948 
1949     None
1950 
1951 --*/
1952 
1953 {
1954     PVCB Vcb = StartingFcb->Vcb;
1955     PFCB CurrentFcb = StartingFcb;
1956     BOOLEAN AcquiredCurrentFcb = FALSE;
1957     PFCB ParentFcb;
1958 
1959     PAGED_CODE();
1960 
1961     *RemovedStartingFcb = FALSE;
1962 
1963     //
1964     //  If this is a recursive call to TearDownStructures we return immediately
1965     //  doing no operation.
1966     //
1967 
1968     if (FlagOn( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN )) {
1969 
1970         return;
1971     }
1972 
1973     SetFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
1974 
1975     //
1976     //  Use a try-finally to safely clear the top-level field.
1977     //
1978 
1979     _SEH2_TRY {
1980 
1981         //
1982         //  Loop until we find an Fcb we can't remove.
1983         //
1984 
1985         do {
1986 
1987             //
1988             //  See if there is an internal stream we should delete.
1989             //  Only do this if it is the last reference on the Fcb.
1990             //
1991 
1992             if ((SafeNodeType( CurrentFcb ) != CDFS_NTC_FCB_DATA) &&
1993                 (CurrentFcb->FcbUserReference == 0) &&
1994                 (CurrentFcb->FileObject != NULL)) {
1995 
1996                 //
1997                 //  Go ahead and delete the stream file object.
1998                 //
1999 
2000                 CdDeleteInternalStream( IrpContext, CurrentFcb );
2001             }
2002 
2003             //
2004             //  If the reference count is non-zero then break.
2005             //
2006 
2007             if (CurrentFcb->FcbReference != 0) {
2008 
2009                 break;
2010             }
2011 
2012             //
2013             //  It looks like we have a candidate for removal here.  We
2014             //  will need to acquire the parent, if present, in order to
2015             //  remove this from the parent prefix table.
2016             //
2017 
2018             ParentFcb = CurrentFcb->ParentFcb;
2019 
2020             if (ParentFcb != NULL) {
2021 
2022                 CdAcquireFcbExclusive( IrpContext, ParentFcb, FALSE );
2023             }
2024 
2025             //
2026             //  Now lock the vcb.
2027             //
2028 
2029             CdLockVcb( IrpContext, Vcb );
2030 
2031             //
2032             //  Final check to see if the reference count is still zero.
2033             //
2034 
2035             if (CurrentFcb->FcbReference != 0) {
2036 
2037                 CdUnlockVcb( IrpContext, Vcb );
2038 
2039                 if (ParentFcb != NULL) {
2040 
2041                     CdReleaseFcb( IrpContext, ParentFcb );
2042                 }
2043 
2044                 break;
2045             }
2046 
2047             //
2048             //  If there is a parent then do the necessary cleanup for the parent.
2049             //
2050 
2051             if (ParentFcb != NULL) {
2052 
2053                 CdRemovePrefix( IrpContext, CurrentFcb );
2054                 RemoveEntryList( &CurrentFcb->FcbLinks );
2055 
2056                 CdDecrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
2057             }
2058 
2059             if (FlagOn( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE )) {
2060 
2061                 CdDeleteFcbTable( IrpContext, CurrentFcb );
2062                 ClearFlag( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE );
2063 
2064             }
2065 
2066             //
2067             //  Unlock the Vcb but hold the parent in order to walk up
2068             //  the tree.
2069             //
2070 
2071             CdUnlockVcb( IrpContext, Vcb );
2072             CdDeleteFcb( IrpContext, CurrentFcb );
2073 
2074             //
2075             //  Move to the parent Fcb.
2076             //
2077 
2078             CurrentFcb = ParentFcb;
2079             AcquiredCurrentFcb = TRUE;
2080 
2081         } while (CurrentFcb != NULL);
2082 
2083     } _SEH2_FINALLY {
2084 
2085         //
2086         //  Release the current Fcb if we have acquired it.
2087         //
2088 
2089         if (AcquiredCurrentFcb && (CurrentFcb != NULL)) {
2090 
2091             CdReleaseFcb( IrpContext, CurrentFcb );
2092         }
2093 
2094         //
2095         //  Clear the teardown flag.
2096         //
2097 
2098         ClearFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
2099     } _SEH2_END;
2100 
2101     *RemovedStartingFcb = (CurrentFcb != StartingFcb);
2102     return;
2103 }
2104 
2105 
2106 PFCB
2107 CdLookupFcbTable (
2108     _In_ PIRP_CONTEXT IrpContext,
2109     _In_ PVCB Vcb,
2110     _In_ FILE_ID FileId
2111     )
2112 
2113 /*++
2114 
2115 Routine Description:
2116 
2117     This routine will look through the Fcb table looking for a matching
2118     entry.
2119 
2120 Arguments:
2121 
2122     Vcb - Vcb for this volume.
2123 
2124     FileId - This is the key value to use for the search.
2125 
2126 Return Value:
2127 
2128     PFCB - A pointer to the matching entry or NULL otherwise.
2129 
2130 --*/
2131 
2132 {
2133     FCB_TABLE_ELEMENT Key;
2134     PFCB_TABLE_ELEMENT Hit;
2135     PFCB ReturnFcb = NULL;
2136 
2137     PAGED_CODE();
2138 
2139     Key.FileId = FileId;
2140 
2141     Hit = (PFCB_TABLE_ELEMENT) RtlLookupElementGenericTable( &Vcb->FcbTable, &Key );
2142 
2143     if (Hit != NULL) {
2144 
2145         ReturnFcb = Hit->Fcb;
2146     }
2147 
2148     return ReturnFcb;
2149 
2150     UNREFERENCED_PARAMETER( IrpContext );
2151 }
2152 
2153 
2154 PFCB
2155 CdGetNextFcb (
2156     _In_ PIRP_CONTEXT IrpContext,
2157     _In_ PVCB Vcb,
2158     _In_ PVOID *RestartKey
2159     )
2160 
2161 /*++
2162 
2163 Routine Description:
2164 
2165     This routine will enumerate through all of the Fcb's in the Fcb table.
2166 
2167 Arguments:
2168 
2169     Vcb - Vcb for this volume.
2170 
2171     RestartKey - This value is used by the table package to maintain
2172         its position in the enumeration.  It is initialized to NULL
2173         for the first search.
2174 
2175 Return Value:
2176 
2177     PFCB - A pointer to the next fcb or NULL if the enumeration is
2178         completed
2179 
2180 --*/
2181 
2182 {
2183     PFCB Fcb;
2184 
2185     PAGED_CODE();
2186 
2187     UNREFERENCED_PARAMETER( IrpContext );
2188 
2189     Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey );
2190 
2191     if (Fcb != NULL) {
2192 
2193         Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb;
2194     }
2195 
2196     return Fcb;
2197 }
2198 
2199 
2200 NTSTATUS
2201 CdProcessToc (
2202     _In_ PIRP_CONTEXT IrpContext,
2203     _In_ PDEVICE_OBJECT TargetDeviceObject,
2204     _In_ PCDROM_TOC_LARGE CdromToc,
2205     _Inout_ PULONG Length,
2206     _Out_ PULONG TrackCount,
2207     _Inout_ PULONG DiskFlags
2208     )
2209 
2210 /*++
2211 
2212 Routine Description:
2213 
2214     This routine is called to verify and process the TOC for this disk.
2215     We hide a data track for a CD+ volume.
2216 
2217 Arguments:
2218 
2219     TargetDeviceObject - Device object to send TOC request to.
2220 
2221     CdromToc - Pointer to TOC structure.
2222 
2223     Length - On input this is the length of the TOC.  On return is the TOC
2224         length we will show to the user.
2225 
2226     TrackCount - This is the count of tracks for the TOC.  We use this
2227         when creating a pseudo directory for a music disk.
2228 
2229     DiskFlags - We return flags indicating what we know about this disk.
2230 
2231 Return Value:
2232 
2233     NTSTATUS - The result of trying to read the TOC.
2234 
2235 --*/
2236 
2237 {
2238     NTSTATUS Status;
2239     IO_STATUS_BLOCK Iosb;
2240     CDROM_READ_TOC_EX Command;
2241 
2242     ULONG CurrentTrack;
2243     ULONG LocalTrackCount;
2244     ULONG LocalTocLength;
2245     ULONG Address = 0;
2246     BOOLEAN UseReadToc = FALSE;
2247 
2248     union {
2249 
2250         UCHAR BigEndian[2];
2251         USHORT Length;
2252 
2253     } BiasedTocLength;
2254 
2255     PTRACK_DATA Track;
2256 
2257     PAGED_CODE();
2258 
2259     //
2260     //  Zero the command block.  This conveniently corresponds to an
2261     //  LBA mode READ_TOC request.
2262     //
2263 
2264     RtlZeroMemory( &Command, sizeof( Command));
2265 
2266 RetryReadToc:
2267 
2268     //
2269     //  Go ahead and read the table of contents
2270     //
2271 
2272     Status = CdPerformDevIoCtrlEx( IrpContext,
2273                                    UseReadToc ? IOCTL_CDROM_READ_TOC : IOCTL_CDROM_READ_TOC_EX,
2274                                    TargetDeviceObject,
2275                                    &Command,
2276                                    sizeof( Command ),
2277                                    CdromToc,
2278                                    sizeof( CDROM_TOC_LARGE ),
2279                                    FALSE,
2280                                    TRUE,
2281                                    &Iosb );
2282 
2283     //
2284     //  Nothing to process if this request fails.
2285     //
2286 
2287     if (!NT_SUCCESS( Status )) {
2288 
2289         //
2290         //  If the underlying device does not support READ_TOC_EX, try the old method.
2291         //
2292 
2293         if (!UseReadToc &&
2294             ((Status == STATUS_INVALID_DEVICE_REQUEST) ||
2295              (Status == STATUS_NOT_IMPLEMENTED) || /* ReactOS Change: we return STATUS_NOT_IMPLEMENTED for IOCTL_CDROM_READ_TOC_EX */
2296              (Status == STATUS_INVALID_PARAMETER))) {
2297 
2298             UseReadToc = TRUE;
2299             goto RetryReadToc;
2300         }
2301 
2302         return Status;
2303     }
2304 
2305     //
2306     //  Get the number of tracks and stated size of this structure.
2307     //
2308 
2309     CurrentTrack = 0;
2310     LocalTrackCount = CdromToc->LastTrack - CdromToc->FirstTrack + 1;
2311     LocalTocLength = PtrOffset( CdromToc, &CdromToc->TrackData[LocalTrackCount + 1] );
2312 
2313     //
2314     //  Get out if there is an immediate problem with the TOC.
2315     //
2316 
2317     if ((LocalTocLength > Iosb.Information) ||
2318         (CdromToc->FirstTrack > CdromToc->LastTrack)) {
2319 
2320         Status = STATUS_DISK_CORRUPT_ERROR;
2321         return Status;
2322     }
2323 
2324     //
2325     //  Walk through the individual tracks.  Stop at the first data track after
2326     //  any lead-in audio tracks.
2327     //
2328 
2329     do {
2330 
2331         //
2332         //  Get the next track.
2333         //
2334 
2335         Track = &CdromToc->TrackData[CurrentTrack];
2336 
2337         //
2338         //  If this is a data track then check if we have only seen audio tracks
2339         //  to this point.
2340         //
2341 
2342         if (FlagOn( Track->Control, TOC_DATA_TRACK )) {
2343 
2344             //
2345             //  If we have only seen audio tracks then assume this is a
2346             //  CD+ disk.  Hide the current data track and only return
2347             //  the previous audio tracks.  Set the disk type to be mixed
2348             //  data/audio.
2349             //
2350 
2351             if (FlagOn( *DiskFlags, CDROM_DISK_AUDIO_TRACK ) &&
2352                 !FlagOn( *DiskFlags, CDROM_DISK_DATA_TRACK )) {
2353 
2354                 //
2355                 //  Remove one track from the TOC.
2356                 //
2357 
2358                 CdromToc->LastTrack -= 1;
2359 
2360                 //
2361                 //  Knock 2.5 minutes off the current track to hide the final leadin.
2362                 //  2.5 min = 150 sec = (x 75) 11250 frames (sectors).
2363                 //
2364 
2365                 SwapCopyUchar4( &Address, &Track->Address);
2366                 Address -= 11250;
2367                 SwapCopyUchar4( &Track->Address, &Address);
2368 
2369                 Track->TrackNumber = TOC_LAST_TRACK;
2370 
2371                 //
2372                 //  Set the disk type to mixed data/audio.
2373                 //
2374 
2375                 SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
2376 
2377                 break;
2378             }
2379 
2380             //
2381             //  Set the flag to indicate data tracks present.
2382             //
2383 
2384             SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
2385 
2386         //
2387         //  If this is a audio track then set the flag indicating audio
2388         //  tracks.
2389         //
2390 
2391         } else {
2392 
2393             SetFlag( *DiskFlags, CDROM_DISK_AUDIO_TRACK );
2394         }
2395 
2396         //
2397         //  Set our index for the next track.
2398         //
2399 
2400         CurrentTrack += 1;
2401 
2402     } while (CurrentTrack < LocalTrackCount);
2403 
2404     //
2405     //  Set the length to point just past the last track we looked at.
2406     //
2407 
2408     *TrackCount = CurrentTrack;
2409     *Length = PtrOffset( CdromToc, &CdromToc->TrackData[CurrentTrack + 1] );
2410     BiasedTocLength.Length = (USHORT) *Length - 2;
2411 
2412     CdromToc->Length[0] = BiasedTocLength.BigEndian[1];
2413     CdromToc->Length[1] = BiasedTocLength.BigEndian[0];
2414 
2415     return Status;
2416 }
2417 
2418 
2419 //
2420 //  Local support routine
2421 //
2422 
2423 VOID
2424 CdDeleteFcb (
2425     _In_ PIRP_CONTEXT IrpContext,
2426     _In_ PFCB Fcb
2427     )
2428 
2429 /*++
2430 
2431 Routine Description:
2432 
2433     This routine is called to cleanup and deallocate an Fcb.  We know there
2434     are no references remaining.  We cleanup any auxilary structures and
2435     deallocate this Fcb.
2436 
2437 Arguments:
2438 
2439     Fcb - This is the Fcb to deallcoate.
2440 
2441 Return Value:
2442 
2443     None
2444 
2445 --*/
2446 
2447 {
2448     PVCB Vcb = NULL;
2449     PAGED_CODE();
2450 
2451     //
2452     //  Sanity check the counts.
2453     //
2454 
2455     NT_ASSERT( Fcb->FcbCleanup == 0 );
2456     NT_ASSERT( Fcb->FcbReference == 0 );
2457 
2458     //
2459     //  Release any Filter Context structures associated with this FCB
2460     //
2461 
2462     FsRtlTeardownPerStreamContexts( &Fcb->Header );
2463 
2464     //
2465     //  Start with the common structures.
2466     //
2467 
2468     CdUninitializeMcb( IrpContext, Fcb );
2469 
2470     CdDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged );
2471 
2472     //
2473     //  Check if we need to deallocate the prefix name buffer.
2474     //
2475 
2476     if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) Fcb->FileNamePrefix.FileNameBuffer) &&
2477         (Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) {
2478 
2479         CdFreePool( &Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer );
2480     }
2481 
2482     //
2483     //  Now look at the short name prefix.
2484     //
2485 
2486     if (Fcb->ShortNamePrefix != NULL) {
2487 
2488         CdFreePool( &Fcb->ShortNamePrefix );
2489     }
2490 
2491     //
2492     //  Now do the type specific structures.
2493     //
2494 
2495     switch (Fcb->NodeTypeCode) {
2496 
2497     case CDFS_NTC_FCB_PATH_TABLE:
2498     case CDFS_NTC_FCB_INDEX:
2499 
2500         NT_ASSERT( Fcb->FileObject == NULL );
2501         NT_ASSERT( IsListEmpty( &Fcb->FcbQueue ));
2502 
2503         if (Fcb == Fcb->Vcb->RootIndexFcb) {
2504 
2505             Vcb = Fcb->Vcb;
2506             Vcb->RootIndexFcb = NULL;
2507 
2508         } else if (Fcb == Fcb->Vcb->PathTableFcb) {
2509 
2510             Vcb = Fcb->Vcb;
2511             Vcb->PathTableFcb = NULL;
2512         }
2513 
2514         CdDeallocateFcbIndex( IrpContext, *(PVOID*)&Fcb );/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */
2515         break;
2516 
2517     case CDFS_NTC_FCB_DATA :
2518 
2519         if (Fcb->FileLock != NULL) {
2520 
2521             FsRtlFreeFileLock( Fcb->FileLock );
2522         }
2523 
2524         FsRtlUninitializeOplock( CdGetFcbOplock(Fcb) );
2525 
2526         if (Fcb == Fcb->Vcb->VolumeDasdFcb) {
2527 
2528             Vcb = Fcb->Vcb;
2529             Vcb->VolumeDasdFcb = NULL;
2530         }
2531 
2532         CdDeallocateFcbData( IrpContext, *(PVOID*)&Fcb );/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */
2533     }
2534 
2535     //
2536     //  Decrement the Vcb reference count if this is a system
2537     //  Fcb.
2538     //
2539 
2540     if (Vcb != NULL) {
2541 
2542         InterlockedDecrement( (LONG*)&Vcb->VcbReference );
2543         InterlockedDecrement( (LONG*)&Vcb->VcbUserReference );
2544     }
2545 
2546     return;
2547 }
2548 
2549 
2550 //
2551 //  Local support routine
2552 //
2553 
2554 PFCB_NONPAGED
2555 CdCreateFcbNonpaged (
2556     _In_ PIRP_CONTEXT IrpContext
2557     )
2558 
2559 /*++
2560 
2561 Routine Description:
2562 
2563     This routine is called to create and initialize the non-paged portion
2564     of an Fcb.
2565 
2566 Arguments:
2567 
2568 Return Value:
2569 
2570     PFCB_NONPAGED - Pointer to the created nonpaged Fcb.  NULL if not created.
2571 
2572 --*/
2573 
2574 {
2575     PFCB_NONPAGED FcbNonpaged;
2576 
2577     PAGED_CODE();
2578 
2579     UNREFERENCED_PARAMETER( IrpContext );
2580 
2581     //
2582     //  Allocate the non-paged pool and initialize the various
2583     //  synchronization objects.
2584     //
2585 
2586     FcbNonpaged = CdAllocateFcbNonpaged( IrpContext );
2587 
2588     if (FcbNonpaged != NULL) {
2589 
2590         RtlZeroMemory( FcbNonpaged, sizeof( FCB_NONPAGED ));
2591 
2592         FcbNonpaged->NodeTypeCode = CDFS_NTC_FCB_NONPAGED;
2593         FcbNonpaged->NodeByteSize = sizeof( FCB_NONPAGED );
2594 
2595         ExInitializeResourceLite( &FcbNonpaged->FcbResource );
2596         ExInitializeFastMutex( &FcbNonpaged->FcbMutex );
2597     }
2598 
2599     return FcbNonpaged;
2600 }
2601 
2602 
2603 //
2604 //  Local support routine
2605 //
2606 
2607 VOID
2608 CdDeleteFcbNonpaged (
2609     _In_ PIRP_CONTEXT IrpContext,
2610     _In_ PFCB_NONPAGED FcbNonpaged
2611     )
2612 
2613 /*++
2614 
2615 Routine Description:
2616 
2617     This routine is called to cleanup the non-paged portion of an Fcb.
2618 
2619 Arguments:
2620 
2621     FcbNonpaged - Structure to clean up.
2622 
2623 Return Value:
2624 
2625     None
2626 
2627 --*/
2628 
2629 {
2630     PAGED_CODE();
2631 
2632     UNREFERENCED_PARAMETER( IrpContext );
2633 
2634     ExDeleteResourceLite( &FcbNonpaged->FcbResource );
2635 
2636     CdDeallocateFcbNonpaged( IrpContext, *(PVOID*)&FcbNonpaged );/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */
2637 
2638     return;
2639 }
2640 
2641 
2642 //
2643 //  Local support routine
2644 //
2645 
2646 RTL_GENERIC_COMPARE_RESULTS
2647 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2648 CdFcbTableCompare (
2649     _In_ PRTL_GENERIC_TABLE FcbTable,
2650     _In_ PVOID Fid1,
2651     _In_ PVOID Fid2
2652     )
2653 
2654 /*++
2655 
2656 Routine Description:
2657 
2658     This routine is the Cdfs compare routine called by the generic table package.
2659     If will compare the two File Id values and return a comparison result.
2660 
2661 Arguments:
2662 
2663     FcbTable - This is the table being searched.
2664 
2665     Fid1 - First key value.
2666 
2667     Fid2 - Second key value.
2668 
2669 Return Value:
2670 
2671     RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
2672         input structures
2673 
2674 --*/
2675 
2676 {
2677     FILE_ID Id1, Id2;
2678     PAGED_CODE();
2679 
2680     Id1 = *((FILE_ID UNALIGNED *) Fid1);
2681     Id2 = *((FILE_ID UNALIGNED *) Fid2);
2682 
2683     if (Id1.QuadPart < Id2.QuadPart) {
2684 
2685         return GenericLessThan;
2686 
2687     } else if (Id1.QuadPart > Id2.QuadPart) {
2688 
2689         return GenericGreaterThan;
2690 
2691     } else {
2692 
2693         return GenericEqual;
2694     }
2695 
2696     UNREFERENCED_PARAMETER( FcbTable );
2697 }
2698 
2699 
2700 //
2701 //  Local support routine
2702 //
2703 
2704 PVOID
2705 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2706 CdAllocateFcbTable (
2707     _In_ PRTL_GENERIC_TABLE FcbTable,
2708     _In_ CLONG ByteSize
2709     )
2710 
2711 /*++
2712 
2713 Routine Description:
2714 
2715     This is a generic table support routine to allocate memory
2716 
2717 Arguments:
2718 
2719     FcbTable - Supplies the generic table being used
2720 
2721     ByteSize - Supplies the number of bytes to allocate
2722 
2723 Return Value:
2724 
2725     PVOID - Returns a pointer to the allocated data
2726 
2727 --*/
2728 
2729 {
2730     PAGED_CODE();
2731 
2732     UNREFERENCED_PARAMETER( FcbTable );
2733 
2734     return( FsRtlAllocatePoolWithTag( CdPagedPool, ByteSize, TAG_FCB_TABLE ));
2735 }
2736 
2737 
2738 //
2739 //  Local support routine
2740 //
2741 VOID
2742 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2743 CdDeallocateFcbTable (
2744     _In_ PRTL_GENERIC_TABLE FcbTable,
2745     _In_ __drv_freesMem(Mem) _Post_invalid_ PVOID Buffer
2746     )
2747 /*++
2748 
2749 Routine Description:
2750 
2751     This is a generic table support routine that deallocates memory
2752 
2753 Arguments:
2754 
2755     FcbTable - Supplies the generic table being used
2756 
2757     Buffer - Supplies the buffer being deallocated
2758 
2759 Return Value:
2760 
2761     None.
2762 
2763 --*/
2764 
2765 {
2766     PAGED_CODE();
2767 
2768     CdFreePool( &Buffer );
2769 
2770     UNREFERENCED_PARAMETER( FcbTable );
2771 }
2772 
2773 
2774 //
2775 //  Local support routine
2776 //
2777 
2778 ULONG
2779 CdTocSerial (
2780     _In_ PIRP_CONTEXT IrpContext,
2781     _In_ PCDROM_TOC_LARGE CdromToc
2782     )
2783 
2784 /*++
2785 
2786 Routine Description:
2787 
2788     This routine is called to generate a serial number for an audio disk.
2789     The number is based on the starting positions of the tracks.
2790     The following algorithm is used.
2791 
2792     If the number of tracks is <= 2 then initialize the serial number to the
2793     leadout block number.
2794 
2795     Then add the starting address of each track (use 0x00mmssff format).
2796 
2797 Arguments:
2798 
2799     CdromToc - Valid table of contents to use for track information.
2800 
2801 Return Value:
2802 
2803     ULONG - 32 bit serial number based on TOC.
2804 
2805 --*/
2806 
2807 {
2808     ULONG SerialNumber = 0;
2809     PTRACK_DATA ThisTrack;
2810     PTRACK_DATA LastTrack;
2811     ULONG Address;
2812     ULONG MsfAddress = 0;   // satisfy PREFIX
2813 
2814     PAGED_CODE();
2815 
2816     UNREFERENCED_PARAMETER( IrpContext );
2817 
2818     //
2819     //  Check if there are two tracks or fewer.
2820     //
2821 
2822     LastTrack = &CdromToc->TrackData[ CdromToc->LastTrack - CdromToc->FirstTrack + 1];
2823     ThisTrack = &CdromToc->TrackData[0];
2824 
2825     if (CdromToc->LastTrack - CdromToc->FirstTrack <= 1) {
2826 
2827         SwapCopyUchar4( &Address, LastTrack->Address);
2828         CdLbnToMmSsFf( Address, (PUCHAR)&SerialNumber);
2829     }
2830     else {
2831 
2832         //
2833         //  Add the starting offset of each track and add to the serial number.
2834         //
2835 
2836         while (ThisTrack != LastTrack) {
2837 
2838             SwapCopyUchar4( &Address, ThisTrack->Address);
2839             CdLbnToMmSsFf( Address, (PUCHAR)&MsfAddress);
2840 
2841             SerialNumber += MsfAddress;
2842             ThisTrack += 1;
2843         }
2844     }
2845 
2846     return SerialNumber;
2847 }
2848 
2849 
2850