3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the Cdfs in-memory data structure manipulation
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_STRUCSUP)
31 // CdAllocateFcbData (
32 // _In_ PIRP_CONTEXT IrpContext
36 // CdDeallocateFcbData (
37 // _In_ PIRP_CONTEXT IrpContext,
42 // CdAllocateFcbIndex (
43 // _In_ PIRP_CONTEXT IrpContext
47 // CdDeallocateFcbIndex (
48 // _In_ PIRP_CONTEXT IrpContext,
53 // CdAllocateFcbNonpaged (
54 // _In_ PIRP_CONTEXT IrpContext
58 // CdDeallocateFcbNonpaged (
59 // _In_ PIRP_CONTEXT IrpContext,
60 // _Inout_ PFCB_NONPAGED FcbNonpaged
65 // _In_ PIRP_CONTEXT IrpContext
70 // _In_ PIRP_CONTEXT IrpContext,
75 #define CdAllocateFcbData(IC) \
76 FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_DATA, TAG_FCB_DATA )
78 #define CdDeallocateFcbData(IC,F) \
81 #define CdAllocateFcbIndex(IC) \
82 FsRtlAllocatePoolWithTag( CdPagedPool, SIZEOF_FCB_INDEX, TAG_FCB_INDEX )
84 #define CdDeallocateFcbIndex(IC,F) \
87 #define CdAllocateFcbNonpaged(IC) \
88 ExAllocatePoolWithTag( CdNonPagedPool, sizeof( FCB_NONPAGED ), TAG_FCB_NONPAGED )
90 #define CdDeallocateFcbNonpaged(IC,FNP) \
93 #define CdAllocateCcb(IC) \
94 FsRtlAllocatePoolWithTag( CdPagedPool, sizeof( CCB ), TAG_CCB )
96 #define CdDeallocateCcb(IC,C) \
103 typedef struct _FCB_TABLE_ELEMENT
{
108 } FCB_TABLE_ELEMENT
, *PFCB_TABLE_ELEMENT
;
116 // CdInsertFcbTable (
117 // _In_ PIRP_CONTEXT IrpContext,
122 // CdDeleteFcbTable (
123 // _In_ PIRP_CONTEXT IrpContext,
129 #define CdInsertFcbTable(IC,F) { \
130 FCB_TABLE_ELEMENT _Key; \
132 _Key.FileId = (F)->FileId; \
133 RtlInsertElementGenericTable( &(F)->Vcb->FcbTable, \
135 sizeof( FCB_TABLE_ELEMENT ), \
139 #define CdDeleteFcbTable(IC,F) { \
140 FCB_TABLE_ELEMENT _Key; \
141 _Key.FileId = (F)->FileId; \
142 RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key ); \
146 // Local support routines
151 _In_ PIRP_CONTEXT IrpContext
,
156 CdCreateFcbNonpaged (
157 _In_ PIRP_CONTEXT IrpContext
161 CdDeleteFcbNonpaged (
162 _In_ PIRP_CONTEXT IrpContext
,
163 _In_ PFCB_NONPAGED FcbNonpaged
166 // Inform prefast that this is a compare routine.
167 RTL_GENERIC_COMPARE_ROUTINE CdFcbTableCompare
;
169 RTL_GENERIC_COMPARE_RESULTS
170 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
172 _In_ PRTL_GENERIC_TABLE FcbTable
,
177 // Inform prefast that this is an alloc reoutine.
178 RTL_GENERIC_ALLOCATE_ROUTINE CdAllocateFcbTable
;
181 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
183 _In_ PRTL_GENERIC_TABLE FcbTable
,
187 // Inform prefast that this is a free reoutine.
188 RTL_GENERIC_FREE_ROUTINE CdDeallocateFcbTable
;
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
199 _In_ PIRP_CONTEXT IrpContext
,
200 _In_ PCDROM_TOC_LARGE CdromToc
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)
231 // Some static names for volume streams
234 UNICODE_STRING CdInternalStreamNames
[] = {
235 { 24, 24, L
"$PATH_TABLE$"},
242 _In_ PIRP_CONTEXT IrpContext
,
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
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.
264 Vcb - Supplies the address of the Vcb record being initialized.
266 TargetDeviceObject - Supplies the address of the target device object to
267 associate with the Vcb record.
269 Vpb - Supplies the address of the Vpb to associate with the Vcb record.
271 CdromToc - Buffer to hold table of contents. NULL if TOC command not
274 TocLength - Byte count length of TOC. We use this as the TOC length to
275 return on a user query.
277 TocTrackCount - Count of tracks in TOC. Used to create pseudo files for
280 TocDiskFlags - Flag field to indicate the type of tracks on the disk.
282 BlockFactor - Used to decode any multi-session information.
284 MediaChangeCount - Initial media change count of the target device
295 UNREFERENCED_PARAMETER( IrpContext
);
298 // We start by first zeroing out all of the VCB, this will guarantee
299 // that any stale data is wiped clean.
302 RtlZeroMemory( Vcb
, sizeof( VCB
));
305 // Set the proper node type code and node byte size.
308 Vcb
->NodeTypeCode
= CDFS_NTC_VCB
;
309 Vcb
->NodeByteSize
= sizeof( VCB
);
312 // Initialize the DirNotify structs. FsRtlNotifyInitializeSync can raise.
315 InitializeListHead( &Vcb
->DirNotifyList
);
316 FsRtlNotifyInitializeSync( &Vcb
->NotifySync
);
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.
326 Vcb
->SwapVpb
= FsRtlAllocatePoolWithTag( CdNonPagedPool
,
332 if (_SEH2_AbnormalTermination()) {
334 FsRtlNotifyUninitializeSync( &Vcb
->NotifySync
);
339 // Nothing beyond this point should raise.
342 RtlZeroMemory( Vcb
->SwapVpb
, sizeof( VPB
) );
345 // Initialize the resource variable for the Vcb and files.
348 ExInitializeResourceLite( &Vcb
->VcbResource
);
349 ExInitializeResourceLite( &Vcb
->FileResource
);
350 ExInitializeFastMutex( &Vcb
->VcbMutex
);
353 // Insert this Vcb record on the CdData.VcbQueue.
356 InsertHeadList( &CdData
.VcbQueue
, &Vcb
->VcbLinks
);
359 // Set the Target Device Object and Vpb fields, referencing the
360 // Target device for the mount.
363 ObReferenceObject( TargetDeviceObject
);
364 Vcb
->TargetDeviceObject
= TargetDeviceObject
;
368 // Set the removable media flag based on the real device's
372 if (FlagOn( Vpb
->RealDevice
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
374 SetFlag( Vcb
->VcbState
, VCB_STATE_REMOVABLE_MEDIA
);
378 // Initialize the generic Fcb Table.
381 RtlInitializeGenericTable( &Vcb
->FcbTable
,
382 (PRTL_GENERIC_COMPARE_ROUTINE
) CdFcbTableCompare
,
383 (PRTL_GENERIC_ALLOCATE_ROUTINE
) CdAllocateFcbTable
,
384 (PRTL_GENERIC_FREE_ROUTINE
) CdDeallocateFcbTable
,
388 // Show that we have a mount in progress.
391 CdUpdateVcbCondition( Vcb
, VcbMountInProgress
);
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.
401 Vcb
->VcbReference
= 1 + CDFS_RESIDUAL_REFERENCE
;
404 // Update the TOC information in the Vcb.
407 Vcb
->CdromToc
= CdromToc
;
408 Vcb
->TocLength
= TocLength
;
409 Vcb
->TrackCount
= TocTrackCount
;
410 Vcb
->DiskFlags
= TocDiskFlags
;
413 // If this disk contains audio tracks only then set the audio flag.
416 if (TocDiskFlags
== CDROM_DISK_AUDIO_TRACK
) {
418 SetFlag( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
| VCB_STATE_CDXA
);
422 // Set the block factor.
425 Vcb
->BlockFactor
= BlockFactor
;
428 // Set the media change count on the device
431 CdUpdateMediaChangeCount( Vcb
, MediaChangeCount
);
436 CdUpdateVcbFromVolDescriptor (
437 _In_ PIRP_CONTEXT IrpContext
,
439 _In_reads_bytes_opt_(SECTOR_SIZE
) PCHAR RawIsoVd
446 This routine is called to perform the final initialization of a Vcb from the
447 volume descriptor on the disk.
451 Vcb - Vcb for the volume being mounted. We have already set the flags for the
454 RawIsoVd - If specified this is the volume descriptor to use to mount the
455 volume. Not specified for a raw disk.
469 PRAW_DIRENT RawDirent
;
470 PATH_ENTRY PathEntry
;
471 PCD_MCB_ENTRY McbEntry
;
473 BOOLEAN UnlockVcb
= FALSE
;
478 // Use a try-finally to facilitate cleanup.
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.
489 // This must always be set.
492 Vcb
->BlockSize
= ( ARGUMENT_PRESENT( RawIsoVd
) ?
493 CdRvdBlkSz( RawIsoVd
, Vcb
->VcbState
) :
497 // We no longer accept media where blocksize != sector size.
500 if (Vcb
->BlockSize
!= SECTOR_SIZE
) {
502 CdRaiseStatus( IrpContext
, STATUS_DISK_CORRUPT_ERROR
);
505 Vcb
->BlocksPerSector
= SECTOR_SIZE
/ Vcb
->BlockSize
;
506 Vcb
->BlockMask
= Vcb
->BlockSize
- 1;
507 Vcb
->BlockInverseMask
= ~Vcb
->BlockMask
;
509 Vcb
->BlockToSectorShift
= 0;
510 Vcb
->BlockToByteShift
= SECTOR_SHIFT
;
513 // If there is a volume descriptor then do the internal Fcb's and
517 if (ARGUMENT_PRESENT( RawIsoVd
)) {
520 // Create the path table Fcb and refererence it and the Vcb.
523 CdLockVcb( IrpContext
, Vcb
);
526 Vcb
->PathTableFcb
= CdCreateFcb( IrpContext
,
527 *((PFILE_ID
) &FileId
),
528 CDFS_NTC_FCB_PATH_TABLE
,
531 CdIncrementReferenceCounts( IrpContext
, Vcb
->PathTableFcb
, 1, 1 );
532 CdUnlockVcb( IrpContext
, Vcb
);
536 // Compute the stream offset and size of this path table.
539 StartingBlock
= CdRvdPtLoc( RawIsoVd
, Vcb
->VcbState
);
541 ByteCount
= CdRvdPtSz( RawIsoVd
, Vcb
->VcbState
);
543 Vcb
->PathTableFcb
->StreamOffset
= BytesFromBlocks( Vcb
,
544 SectorBlockOffset( Vcb
, StartingBlock
));
546 Vcb
->PathTableFcb
->FileSize
.QuadPart
= (LONGLONG
) (Vcb
->PathTableFcb
->StreamOffset
+
549 Vcb
->PathTableFcb
->ValidDataLength
.QuadPart
= Vcb
->PathTableFcb
->FileSize
.QuadPart
;
551 Vcb
->PathTableFcb
->AllocationSize
.QuadPart
= LlSectorAlign( Vcb
->PathTableFcb
->FileSize
.QuadPart
);
554 // Now add the mapping information.
557 CdLockFcb( IrpContext
, Vcb
->PathTableFcb
);
559 CdAddInitialAllocation( IrpContext
,
562 Vcb
->PathTableFcb
->AllocationSize
.QuadPart
);
564 CdUnlockFcb( IrpContext
, Vcb
->PathTableFcb
);
567 // Point to the file resource.
570 Vcb
->PathTableFcb
->Resource
= &Vcb
->FileResource
;
573 // Mark the Fcb as initialized and create the stream file for this.
576 SetFlag( Vcb
->PathTableFcb
->FcbState
, FCB_STATE_INITIALIZED
);
578 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->PathTableFcb
, &CdInternalStreamNames
[0]);
581 // Create the root index and reference it in the Vcb.
584 CdLockVcb( IrpContext
, Vcb
);
586 Vcb
->RootIndexFcb
= CdCreateFcb( IrpContext
,
587 *((PFILE_ID
) &FileId
),
591 CdIncrementReferenceCounts( IrpContext
, Vcb
->RootIndexFcb
, 1, 1 );
592 CdUnlockVcb( IrpContext
, Vcb
);
596 // Create the File id by hand for this Fcb.
599 CdSetFidPathTableOffset( Vcb
->RootIndexFcb
->FileId
, Vcb
->PathTableFcb
->StreamOffset
);
600 CdFidSetDirectory( Vcb
->RootIndexFcb
->FileId
);
603 // Create a pseudo path table entry so we can call the initialization
604 // routine for the directory.
607 RawDirent
= (PRAW_DIRENT
) CdRvdDirent( RawIsoVd
, Vcb
->VcbState
);
609 CopyUchar4( &PathEntry
.DiskOffset
, RawDirent
->FileLoc
);
611 PathEntry
.DiskOffset
+= RawDirent
->XarLen
;
612 PathEntry
.Ordinal
= 1;
613 PathEntry
.PathTableOffset
= Vcb
->PathTableFcb
->StreamOffset
;
615 CdInitializeFcbFromPathEntry( IrpContext
,
621 // Create the stream file for the root directory.
624 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->RootIndexFcb
, &CdInternalStreamNames
[1] );
627 // Now do the volume dasd Fcb. Create this and reference it in the
631 CdLockVcb( IrpContext
, Vcb
);
634 Vcb
->VolumeDasdFcb
= CdCreateFcb( IrpContext
,
635 *((PFILE_ID
) &FileId
),
639 CdIncrementReferenceCounts( IrpContext
, Vcb
->VolumeDasdFcb
, 1, 1 );
640 CdUnlockVcb( IrpContext
, Vcb
);
644 // The file size is the full disk.
647 StartingBlock
= CdRvdVolSz( RawIsoVd
, Vcb
->VcbState
);
649 Vcb
->VolumeDasdFcb
->FileSize
.QuadPart
= LlBytesFromBlocks( Vcb
, StartingBlock
);
651 Vcb
->VolumeDasdFcb
->AllocationSize
.QuadPart
=
652 Vcb
->VolumeDasdFcb
->ValidDataLength
.QuadPart
= Vcb
->VolumeDasdFcb
->FileSize
.QuadPart
;
655 // Now add the extent representing the volume 'by hand'.
658 CdLockFcb( IrpContext
, Vcb
->VolumeDasdFcb
);
660 McbEntry
= Vcb
->VolumeDasdFcb
->Mcb
.McbArray
;
662 McbEntry
->FileOffset
=
663 McbEntry
->DiskOffset
= 0;
665 McbEntry
->ByteCount
= Vcb
->VolumeDasdFcb
->AllocationSize
.QuadPart
;
667 McbEntry
->DataBlockByteCount
=
668 McbEntry
->TotalBlockByteCount
= McbEntry
->ByteCount
;
670 Vcb
->VolumeDasdFcb
->Mcb
.CurrentEntryCount
= 1;
672 CdUnlockFcb( IrpContext
, Vcb
->VolumeDasdFcb
);
675 // Point to the file resource.
678 Vcb
->VolumeDasdFcb
->Resource
= &Vcb
->FileResource
;
680 Vcb
->VolumeDasdFcb
->FileAttributes
= FILE_ATTRIBUTE_READONLY
;
683 // Mark the Fcb as initialized.
686 SetFlag( Vcb
->VolumeDasdFcb
->FcbState
, FCB_STATE_INITIALIZED
);
689 // Check and see if this is an XA disk.
692 if (FlagOn( Vcb
->VcbState
, VCB_STATE_ISO
| VCB_STATE_JOLIET
)
693 && RtlEqualMemory( CdXaId
,
694 Add2Ptr( RawIsoVd
, 0x400, PCHAR
),
697 SetFlag( Vcb
->VcbState
, VCB_STATE_CDXA
);
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
706 } else if (FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
708 ULONG RootDirectorySize
;
711 // Create the path table Fcb and refererence it and the Vcb.
714 CdLockVcb( IrpContext
, Vcb
);
717 Vcb
->PathTableFcb
= CdCreateFcb( IrpContext
,
718 *((PFILE_ID
) &FileId
),
719 CDFS_NTC_FCB_PATH_TABLE
,
722 CdIncrementReferenceCounts( IrpContext
, Vcb
->PathTableFcb
, 1, 1 );
723 CdUnlockVcb( IrpContext
, Vcb
);
727 // We only create a pseudo entry for the root.
730 Vcb
->PathTableFcb
->FileSize
.QuadPart
= (LONGLONG
) (FIELD_OFFSET( RAW_PATH_ISO
, DirId
) + 2);
732 Vcb
->PathTableFcb
->ValidDataLength
.QuadPart
= Vcb
->PathTableFcb
->FileSize
.QuadPart
;
734 Vcb
->PathTableFcb
->AllocationSize
.QuadPart
= LlSectorAlign( Vcb
->PathTableFcb
->FileSize
.QuadPart
);
737 // Point to the file resource.
740 Vcb
->PathTableFcb
->Resource
= &Vcb
->FileResource
;
743 // Mark the Fcb as initialized and create the stream file for this.
746 SetFlag( Vcb
->PathTableFcb
->FcbState
, FCB_STATE_INITIALIZED
);
748 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->PathTableFcb
, &CdInternalStreamNames
[0]);
751 // Create the root index and reference it in the Vcb.
754 CdLockVcb( IrpContext
, Vcb
);
756 Vcb
->RootIndexFcb
= CdCreateFcb( IrpContext
,
757 *((PFILE_ID
) &FileId
),
761 CdIncrementReferenceCounts( IrpContext
, Vcb
->RootIndexFcb
, 1, 1 );
762 CdUnlockVcb( IrpContext
, Vcb
);
766 // Create the File id by hand for this Fcb.
769 CdSetFidPathTableOffset( Vcb
->RootIndexFcb
->FileId
, Vcb
->PathTableFcb
->StreamOffset
);
770 CdFidSetDirectory( Vcb
->RootIndexFcb
->FileId
);
773 // Create a pseudo path table entry so we can call the initialization
774 // routine for the directory.
777 RtlZeroMemory( &PathEntry
, sizeof( PATH_ENTRY
));
780 PathEntry
.Ordinal
= 1;
781 PathEntry
.PathTableOffset
= Vcb
->PathTableFcb
->StreamOffset
;
783 CdInitializeFcbFromPathEntry( IrpContext
,
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.
793 RootDirectorySize
= (Vcb
->TrackCount
+ 2) * CdAudioDirentSize
;
794 RootDirectorySize
= SectorAlign( RootDirectorySize
);
796 Vcb
->RootIndexFcb
->AllocationSize
.QuadPart
=
797 Vcb
->RootIndexFcb
->ValidDataLength
.QuadPart
=
798 Vcb
->RootIndexFcb
->FileSize
.QuadPart
= RootDirectorySize
;
800 SetFlag( Vcb
->RootIndexFcb
->FcbState
, FCB_STATE_INITIALIZED
);
803 // Create the stream file for the root directory.
806 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->RootIndexFcb
, &CdInternalStreamNames
[1] );
809 // Now do the volume dasd Fcb. Create this and reference it in the
813 CdLockVcb( IrpContext
, Vcb
);
816 Vcb
->VolumeDasdFcb
= CdCreateFcb( IrpContext
,
817 *((PFILE_ID
) &FileId
),
821 CdIncrementReferenceCounts( IrpContext
, Vcb
->VolumeDasdFcb
, 1, 1 );
822 CdUnlockVcb( IrpContext
, Vcb
);
826 // We won't allow raw reads on this Fcb so leave the size at
831 // Point to the file resource.
834 Vcb
->VolumeDasdFcb
->Resource
= &Vcb
->FileResource
;
836 Vcb
->VolumeDasdFcb
->FileAttributes
= FILE_ATTRIBUTE_READONLY
;
839 // Mark the Fcb as initialized.
842 SetFlag( Vcb
->VolumeDasdFcb
->FcbState
, FCB_STATE_INITIALIZED
);
845 // We will store a hard-coded name in the Vpb and use the toc as
846 // the serial number.
849 Vcb
->Vpb
->VolumeLabelLength
= CdAudioLabelLength
;
851 RtlCopyMemory( Vcb
->Vpb
->VolumeLabel
,
853 CdAudioLabelLength
);
856 // Find the serial number for the audio disk.
859 Vcb
->Vpb
->SerialNumber
= CdTocSerial( IrpContext
, Vcb
->CdromToc
);
862 // Set the ISO bit so we know how to treat the names.
865 SetFlag( Vcb
->VcbState
, VCB_STATE_ISO
);
870 if (UnlockVcb
) { CdUnlockVcb( IrpContext
, Vcb
); }
877 _In_ PIRP_CONTEXT IrpContext
,
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.
902 ASSERT_EXCLUSIVE_CDDATA
;
903 ASSERT_EXCLUSIVE_VCB( Vcb
);
905 UNREFERENCED_PARAMETER( IrpContext
);
908 // Chuck the backpocket Vpb we kept just in case.
911 CdFreePool( &Vcb
->SwapVpb
);
914 // If there is a Vpb then we must delete it ourselves.
917 CdFreePool( &Vcb
->Vpb
);
920 // Dereference our target if we haven't already done so.
923 if (Vcb
->TargetDeviceObject
!= NULL
) {
925 ObDereferenceObject( Vcb
->TargetDeviceObject
);
929 // Delete the XA Sector and sector cache buffer if allocated.
932 CdFreePool( &Vcb
->XASector
);
933 CdFreePool( &Vcb
->SectorCacheBuffer
);
935 if (Vcb
->SectorCacheIrp
!= NULL
) {
937 IoFreeIrp( Vcb
->SectorCacheIrp
);
938 Vcb
->SectorCacheIrp
= NULL
;
940 ExDeleteResourceLite( &Vcb
->SectorCacheResource
);
944 // Remove this entry from the global queue.
947 RemoveEntryList( &Vcb
->VcbLinks
);
950 // Delete the Vcb and File resources.
953 ExDeleteResourceLite( &Vcb
->VcbResource
);
954 ExDeleteResourceLite( &Vcb
->FileResource
);
957 // Delete the TOC if present.
960 CdFreePool( &Vcb
->CdromToc
);
963 // Uninitialize the notify structures.
966 if (Vcb
->NotifySync
!= NULL
) {
968 FsRtlNotifyUninitializeSync( &Vcb
->NotifySync
);
972 // Now delete the volume device object.
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." )
977 IoDeleteDevice( (PDEVICE_OBJECT
) CONTAINING_RECORD( Vcb
,
978 VOLUME_DEVICE_OBJECT
,
987 _In_ PIRP_CONTEXT IrpContext
,
989 _In_ NODE_TYPE_CODE NodeTypeCode
,
990 _Out_opt_ PBOOLEAN FcbExisted
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
1002 This routine is called while the Vcb is locked.
1006 FileId - This is the Id for the target Fcb.
1008 NodeTypeCode - Node type for this Fcb if we need to create.
1010 FcbExisted - If specified, we store whether the Fcb existed.
1014 PFCB - The Fcb found in the table or created if needed.
1020 BOOLEAN LocalFcbExisted
;
1025 // Use the local boolean if one was not passed in.
1028 if (!ARGUMENT_PRESENT( FcbExisted
)) {
1030 FcbExisted
= &LocalFcbExisted
;
1034 // Maybe this is already in the table.
1037 NewFcb
= CdLookupFcbTable( IrpContext
, IrpContext
->Vcb
, FileId
);
1040 // If not then create the Fcb is requested by our caller.
1043 if (NewFcb
== NULL
) {
1046 // Allocate and initialize the structure depending on the
1050 switch (NodeTypeCode
) {
1052 case CDFS_NTC_FCB_PATH_TABLE
:
1053 case CDFS_NTC_FCB_INDEX
:
1055 NewFcb
= CdAllocateFcbIndex( IrpContext
);
1057 RtlZeroMemory( NewFcb
, SIZEOF_FCB_INDEX
);
1059 NewFcb
->NodeByteSize
= SIZEOF_FCB_INDEX
;
1061 InitializeListHead( &NewFcb
->FcbQueue
);
1065 case CDFS_NTC_FCB_DATA
:
1067 NewFcb
= CdAllocateFcbData( IrpContext
);
1069 RtlZeroMemory( NewFcb
, SIZEOF_FCB_DATA
);
1071 NewFcb
->NodeByteSize
= SIZEOF_FCB_DATA
;
1078 #pragma prefast( suppress: __WARNING_USE_OTHER_FUNCTION, "This is a bug." )
1080 CdBugCheck( 0, 0, 0 );
1084 // Now do the common initialization.
1087 NewFcb
->NodeTypeCode
= NodeTypeCode
;
1089 NewFcb
->Vcb
= IrpContext
->Vcb
;
1090 NewFcb
->FileId
= FileId
;
1092 CdInitializeMcb( IrpContext
, NewFcb
);
1095 // Now create the non-paged section object.
1098 NewFcb
->FcbNonpaged
= CdCreateFcbNonpaged( IrpContext
);
1101 // Deallocate the Fcb and raise if the allocation failed.
1104 if (NewFcb
->FcbNonpaged
== NULL
) {
1106 CdFreePool( &NewFcb
);
1108 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1111 *FcbExisted
= FALSE
;
1114 // Initialize Advanced FCB Header fields
1117 ExInitializeFastMutex( &NewFcb
->FcbNonpaged
->AdvancedFcbHeaderMutex
);
1118 FsRtlSetupAdvancedHeader( &NewFcb
->Header
,
1119 &NewFcb
->FcbNonpaged
->AdvancedFcbHeaderMutex
);
1121 if (NodeTypeCode
== CDFS_NTC_FCB_DATA
) {
1123 FsRtlInitializeOplock( CdGetFcbOplock(NewFcb
) );
1136 CdInitializeFcbFromPathEntry (
1137 _In_ PIRP_CONTEXT IrpContext
,
1139 _In_opt_ PFCB ParentFcb
,
1140 _In_ PPATH_ENTRY PathEntry
1145 Routine Description:
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.
1151 The general initialization is performed in CdCreateFcb.
1155 Fcb - Newly created Fcb for this stream.
1157 ParentFcb - Parent Fcb for this stream. It may not be present.
1159 PathEntry - PathEntry for this Fcb in the Path Table.
1171 // Fill in the Index specific fields of the Fcb.
1174 Fcb
->StreamOffset
= BytesFromBlocks( Fcb
->Vcb
,
1175 SectorBlockOffset( Fcb
->Vcb
, PathEntry
->DiskOffset
));
1177 Fcb
->Ordinal
= PathEntry
->Ordinal
;
1180 // Initialize the common header in the Fcb. The node type is already
1184 Fcb
->Resource
= &Fcb
->Vcb
->FileResource
;
1187 // Always set the sizes to one sector until we read the self-entry.
1190 Fcb
->AllocationSize
.QuadPart
=
1191 Fcb
->FileSize
.QuadPart
=
1192 Fcb
->ValidDataLength
.QuadPart
= SECTOR_SIZE
;
1194 CdAddInitialAllocation( IrpContext
,
1196 PathEntry
->DiskOffset
,
1199 // State flags for this Fcb.
1202 SetFlag( Fcb
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
);
1205 // Link into the other in-memory structures and into the Fcb table.
1208 if (ParentFcb
!= NULL
) {
1210 Fcb
->ParentFcb
= ParentFcb
;
1212 InsertTailList( &ParentFcb
->FcbQueue
, &Fcb
->FcbLinks
);
1214 CdIncrementReferenceCounts( IrpContext
, ParentFcb
, 1, 1 );
1217 CdInsertFcbTable( IrpContext
, Fcb
);
1218 SetFlag( Fcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
);
1225 CdInitializeFcbFromFileContext (
1226 _In_ PIRP_CONTEXT IrpContext
,
1228 _In_ PFCB ParentFcb
,
1229 _In_ PFILE_ENUM_CONTEXT FileContext
1234 Routine Description:
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.
1241 The general initialization is performed in CdCreateFcb.
1245 Fcb - Newly created Fcb for this stream.
1247 ParentFcb - Parent Fcb for this stream.
1249 FileContext - FileContext for the file.
1258 PDIRENT ThisDirent
= &FileContext
->InitialDirent
->Dirent
;
1259 PCOMPOUND_DIRENT CurrentCompoundDirent
;
1261 LONGLONG CurrentFileOffset
;
1262 ULONG CurrentMcbEntryOffset
;
1267 // Use a try-finally to facilitate cleanup.
1270 CdLockFcb( IrpContext
, Fcb
);
1275 // Initialize the common header in the Fcb. The node type is already
1279 Fcb
->Resource
= &IrpContext
->Vcb
->FileResource
;
1282 // Allocation occurs in block-sized units.
1285 Fcb
->FileSize
.QuadPart
=
1286 Fcb
->ValidDataLength
.QuadPart
= FileContext
->FileSize
;
1288 Fcb
->AllocationSize
.QuadPart
= LlBlockAlign( Fcb
->Vcb
, FileContext
->FileSize
);
1291 // Set the flags from the dirent. We always start with the read-only bit.
1294 SetFlag( Fcb
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
1295 if (FlagOn( ThisDirent
->DirentFlags
, CD_ATTRIBUTE_HIDDEN
)) {
1297 SetFlag( Fcb
->FileAttributes
, FILE_ATTRIBUTE_HIDDEN
);
1301 // Convert the time to NT time.
1304 CdConvertCdTimeToNtTime( IrpContext
,
1306 (PLARGE_INTEGER
) &Fcb
->CreationTime
);
1309 // Set the flag indicating the type of extent.
1312 if (ThisDirent
->ExtentType
!= Form1Data
) {
1314 if (ThisDirent
->ExtentType
== Mode2Form2Data
) {
1316 SetFlag( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
);
1320 SetFlag( Fcb
->FcbState
, FCB_STATE_DA_FILE
);
1323 Fcb
->XAAttributes
= ThisDirent
->XAAttributes
;
1324 Fcb
->XAFileNumber
= ThisDirent
->XAFileNumber
;
1328 // Read through all of the dirents for the file until we find the last
1329 // and add the allocation into the Mcb.
1332 CurrentCompoundDirent
= FileContext
->InitialDirent
;
1333 CurrentFileOffset
= 0;
1334 CurrentMcbEntryOffset
= 0;
1338 CdAddAllocationFromDirent( IrpContext
,
1340 CurrentMcbEntryOffset
,
1342 &CurrentCompoundDirent
->Dirent
);
1345 // Break out if we are at the last dirent.
1348 if (!FlagOn( CurrentCompoundDirent
->Dirent
.DirentFlags
, CD_ATTRIBUTE_MULTI
)) {
1353 CurrentFileOffset
+= CurrentCompoundDirent
->Dirent
.DataLength
;
1354 CurrentMcbEntryOffset
+= 1;
1357 // We better be able to find the next dirent.
1360 if (!CdLookupNextDirent( IrpContext
,
1362 &CurrentCompoundDirent
->DirContext
,
1363 &FileContext
->CurrentDirent
->DirContext
)) {
1365 CdRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
1368 CurrentCompoundDirent
= FileContext
->CurrentDirent
;
1370 CdUpdateDirentFromRawDirent( IrpContext
,
1372 &CurrentCompoundDirent
->DirContext
,
1373 &CurrentCompoundDirent
->Dirent
);
1377 // Show that the Fcb is initialized.
1380 SetFlag( Fcb
->FcbState
, FCB_STATE_INITIALIZED
);
1383 // Link into the other in-memory structures and into the Fcb table.
1386 Fcb
->ParentFcb
= ParentFcb
;
1388 InsertTailList( &ParentFcb
->FcbQueue
, &Fcb
->FcbLinks
);
1390 CdIncrementReferenceCounts( IrpContext
, ParentFcb
, 1, 1 );
1392 CdInsertFcbTable( IrpContext
, Fcb
);
1393 SetFlag( Fcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
);
1397 CdUnlockFcb( IrpContext
, Fcb
);
1406 _In_ PIRP_CONTEXT IrpContext
,
1413 Routine Description:
1415 This routine is called to allocate and initialize the Ccb structure.
1419 Fcb - This is the Fcb for the file being opened.
1421 Flags - User flags to set in this Ccb.
1425 PCCB - Pointer to the created Ccb.
1433 UNREFERENCED_PARAMETER( IrpContext
);
1436 // Allocate and initialize the structure.
1439 NewCcb
= CdAllocateCcb( IrpContext
);
1441 RtlZeroMemory( NewCcb
, sizeof( CCB
));
1444 // Set the proper node type code and node byte size
1447 NewCcb
->NodeTypeCode
= CDFS_NTC_CCB
;
1448 NewCcb
->NodeByteSize
= sizeof( CCB
);
1451 // Set the initial value for the flags and Fcb
1454 NewCcb
->Flags
= Flags
;
1463 _In_ PIRP_CONTEXT IrpContext
,
1464 _In_
__drv_freesMem( Pool
) PCCB Ccb
1468 Routine Description:
1470 This routine is called to cleanup and deallocate a Ccb structure.
1474 Ccb - This is the Ccb to delete.
1485 UNREFERENCED_PARAMETER( IrpContext
);
1487 if (Ccb
->SearchExpression
.FileName
.Buffer
!= NULL
) {
1489 CdFreePool( &Ccb
->SearchExpression
.FileName
.Buffer
);
1492 CdDeallocateCcb( IrpContext
, Ccb
);
1497 _When_(RaiseOnError
|| return, _At_(Fcb
->FileLock
, _Post_notnull_
))
1498 _When_(RaiseOnError
, _At_(IrpContext
, _Pre_notnull_
))
1501 _In_opt_ PIRP_CONTEXT IrpContext
,
1503 _In_ BOOLEAN RaiseOnError
1508 Routine Description:
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.
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.
1518 Fcb - This is the Fcb to create the file lock for.
1520 RaiseOnError - If TRUE, we will raise on an allocation failure. Otherwise we
1521 return FALSE on an allocation failure.
1525 BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise.
1530 BOOLEAN Result
= TRUE
;
1531 PFILE_LOCK FileLock
;
1536 // Lock the Fcb and check if there is really any work to do.
1539 CdLockFcb( IrpContext
, Fcb
);
1541 if (Fcb
->FileLock
!= NULL
) {
1543 CdUnlockFcb( IrpContext
, Fcb
);
1547 Fcb
->FileLock
= FileLock
=
1548 FsRtlAllocateFileLock( NULL
, NULL
);
1550 CdUnlockFcb( IrpContext
, Fcb
);
1553 // Return or raise as appropriate.
1556 if (FileLock
== NULL
) {
1560 NT_ASSERT( ARGUMENT_PRESENT( IrpContext
));
1562 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1572 _Ret_valid_ PIRP_CONTEXT
1573 CdCreateIrpContext (
1580 Routine Description:
1582 This routine is called to initialize an IrpContext for the current
1583 CDFS request. We allocate the structure and then initialize it from
1588 Irp - Irp for this request.
1590 Wait - TRUE if this request is synchronous, FALSE otherwise.
1594 PIRP_CONTEXT - Allocated IrpContext.
1599 PIRP_CONTEXT NewIrpContext
= NULL
;
1600 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
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).
1611 if (IrpSp
->DeviceObject
== CdData
.FileSystemDeviceObject
) {
1613 if (IrpSp
->DeviceObject
== CdData
.FileSystemDeviceObject
||
1614 IrpSp
->DeviceObject
== CdData
.HddFileSystemDeviceObject
) {
1617 if (IrpSp
->FileObject
!= NULL
&&
1618 IrpSp
->MajorFunction
!= IRP_MJ_CREATE
&&
1619 IrpSp
->MajorFunction
!= IRP_MJ_CLEANUP
&&
1620 IrpSp
->MajorFunction
!= IRP_MJ_CLOSE
) {
1622 ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST
);
1625 NT_ASSERT( IrpSp
->FileObject
!= NULL
||
1627 (IrpSp
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
&&
1628 IrpSp
->MinorFunction
== IRP_MN_USER_FS_REQUEST
&&
1629 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_INVALIDATE_VOLUMES
) ||
1631 (IrpSp
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
&&
1632 IrpSp
->MinorFunction
== IRP_MN_MOUNT_VOLUME
) ||
1634 IrpSp
->MajorFunction
== IRP_MJ_SHUTDOWN
);
1638 // Look in our lookaside list for an IrpContext.
1641 if (CdData
.IrpContextDepth
) {
1644 NewIrpContext
= (PIRP_CONTEXT
) PopEntryList( &CdData
.IrpContextList
);
1645 if (NewIrpContext
!= NULL
) {
1647 CdData
.IrpContextDepth
--;
1653 if (NewIrpContext
== NULL
) {
1656 // We didn't get it from our private list so allocate it from pool.
1659 NewIrpContext
= FsRtlAllocatePoolWithTag( CdNonPagedPool
, sizeof( IRP_CONTEXT
), TAG_IRP_CONTEXT
);
1662 RtlZeroMemory( NewIrpContext
, sizeof( IRP_CONTEXT
));
1665 // Set the proper node type code and node byte size
1668 NewIrpContext
->NodeTypeCode
= CDFS_NTC_IRP_CONTEXT
;
1669 NewIrpContext
->NodeByteSize
= sizeof( IRP_CONTEXT
);
1672 // Set the originating Irp field
1675 NewIrpContext
->Irp
= Irp
;
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.
1682 if (IrpSp
->FileObject
!= NULL
) {
1684 NewIrpContext
->RealDevice
= IrpSp
->FileObject
->DeviceObject
;
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
1694 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
) {
1696 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
&&
1697 IrpSp
->DeviceObject
!= CdData
.HddFileSystemDeviceObject
) {
1700 NewIrpContext
->Vcb
= &((PVOLUME_DEVICE_OBJECT
) IrpSp
->DeviceObject
)->Vcb
;
1705 // Major/Minor Function codes
1708 NewIrpContext
->MajorFunction
= IrpSp
->MajorFunction
;
1709 NewIrpContext
->MinorFunction
= IrpSp
->MinorFunction
;
1712 // Set the wait parameter
1717 SetFlag( NewIrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1721 SetFlag( NewIrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
1725 // return and tell the caller
1728 return NewIrpContext
;
1733 CdCleanupIrpContext (
1734 _In_ PIRP_CONTEXT IrpContext
,
1740 Routine Description:
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.
1748 Post - TRUE if we are posting this request, FALSE if we are deleting
1749 or retrying this in the current thread.
1761 // If we aren't doing more processing then deallocate this as appropriate.
1764 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_MORE_PROCESSING
)) {
1767 // If this context is the top level CDFS context then we need to
1768 // restore the top level thread context.
1771 if (IrpContext
->ThreadContext
!= NULL
) {
1773 CdRestoreThreadContext( IrpContext
);
1777 // Deallocate the Io context if allocated.
1780 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
)) {
1782 CdFreeIoContext( IrpContext
->IoContext
);
1786 // Deallocate the IrpContext if not from the stack.
1789 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ON_STACK
)) {
1791 if (CdData
.IrpContextDepth
< CdData
.IrpContextMaxDepth
) {
1795 PushEntryList( &CdData
.IrpContextList
, (PSINGLE_LIST_ENTRY
) IrpContext
);
1796 CdData
.IrpContextDepth
++;
1803 // We couldn't add this to our lookaside list so free it to
1807 CdFreePool( &IrpContext
);
1812 // Clear the appropriate flags.
1818 // If this context is the top level CDFS context then we need to
1819 // restore the top level thread context.
1822 if (IrpContext
->ThreadContext
!= NULL
) {
1824 CdRestoreThreadContext( IrpContext
);
1827 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAGS_CLEAR_ON_POST
);
1831 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY
);
1839 CdInitializeStackIrpContext (
1840 _Out_ PIRP_CONTEXT IrpContext
,
1841 _In_ PIRP_CONTEXT_LITE IrpContextLite
1846 Routine Description:
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.
1854 IrpContext - IrpContext to initialize.
1856 IrpContextLite - Structure containing the details of this request.
1868 // Zero and then initialize the structure.
1871 RtlZeroMemory( IrpContext
, sizeof( IRP_CONTEXT
));
1874 // Set the proper node type code and node byte size
1877 IrpContext
->NodeTypeCode
= CDFS_NTC_IRP_CONTEXT
;
1878 IrpContext
->NodeByteSize
= sizeof( IRP_CONTEXT
);
1881 // Note that this is from the stack.
1884 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ON_STACK
);
1887 // Copy RealDevice for workque algorithms.
1890 IrpContext
->RealDevice
= IrpContextLite
->RealDevice
;
1893 // The Vcb is found in the Fcb.
1896 IrpContext
->Vcb
= IrpContextLite
->Fcb
->Vcb
;
1899 // Major/Minor Function codes
1902 IrpContext
->MajorFunction
= IRP_MJ_CLOSE
;
1905 // Set the wait parameter
1908 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1915 _Requires_lock_held_(_Global_critical_region_
)
1917 CdTeardownStructures (
1918 _In_ PIRP_CONTEXT IrpContext
,
1919 _Inout_ PFCB StartingFcb
,
1920 _Out_ PBOOLEAN RemovedStartingFcb
1925 Routine Description:
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.
1931 We look at the following fields in the Fcb to determine whether we can
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.
1938 We return immediately if we are recursively entering this routine.
1942 StartingFcb - This is the Fcb node in the tree to begin with. This Fcb
1943 must currently be acquired exclusively.
1945 RemovedStartingFcb - Address to store whether we removed the starting Fcb.
1954 PVCB Vcb
= StartingFcb
->Vcb
;
1955 PFCB CurrentFcb
= StartingFcb
;
1956 BOOLEAN AcquiredCurrentFcb
= FALSE
;
1961 *RemovedStartingFcb
= FALSE
;
1964 // If this is a recursive call to TearDownStructures we return immediately
1965 // doing no operation.
1968 if (FlagOn( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
)) {
1973 SetFlag( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
);
1976 // Use a try-finally to safely clear the top-level field.
1982 // Loop until we find an Fcb we can't remove.
1988 // See if there is an internal stream we should delete.
1989 // Only do this if it is the last reference on the Fcb.
1992 if ((SafeNodeType( CurrentFcb
) != CDFS_NTC_FCB_DATA
) &&
1993 (CurrentFcb
->FcbUserReference
== 0) &&
1994 (CurrentFcb
->FileObject
!= NULL
)) {
1997 // Go ahead and delete the stream file object.
2000 CdDeleteInternalStream( IrpContext
, CurrentFcb
);
2004 // If the reference count is non-zero then break.
2007 if (CurrentFcb
->FcbReference
!= 0) {
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.
2018 ParentFcb
= CurrentFcb
->ParentFcb
;
2020 if (ParentFcb
!= NULL
) {
2022 CdAcquireFcbExclusive( IrpContext
, ParentFcb
, FALSE
);
2026 // Now lock the vcb.
2029 CdLockVcb( IrpContext
, Vcb
);
2032 // Final check to see if the reference count is still zero.
2035 if (CurrentFcb
->FcbReference
!= 0) {
2037 CdUnlockVcb( IrpContext
, Vcb
);
2039 if (ParentFcb
!= NULL
) {
2041 CdReleaseFcb( IrpContext
, ParentFcb
);
2048 // If there is a parent then do the necessary cleanup for the parent.
2051 if (ParentFcb
!= NULL
) {
2053 CdRemovePrefix( IrpContext
, CurrentFcb
);
2054 RemoveEntryList( &CurrentFcb
->FcbLinks
);
2056 CdDecrementReferenceCounts( IrpContext
, ParentFcb
, 1, 1 );
2059 if (FlagOn( CurrentFcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
)) {
2061 CdDeleteFcbTable( IrpContext
, CurrentFcb
);
2062 ClearFlag( CurrentFcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
);
2067 // Unlock the Vcb but hold the parent in order to walk up
2071 CdUnlockVcb( IrpContext
, Vcb
);
2072 CdDeleteFcb( IrpContext
, CurrentFcb
);
2075 // Move to the parent Fcb.
2078 CurrentFcb
= ParentFcb
;
2079 AcquiredCurrentFcb
= TRUE
;
2081 } while (CurrentFcb
!= NULL
);
2086 // Release the current Fcb if we have acquired it.
2089 if (AcquiredCurrentFcb
&& (CurrentFcb
!= NULL
)) {
2091 CdReleaseFcb( IrpContext
, CurrentFcb
);
2095 // Clear the teardown flag.
2098 ClearFlag( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
);
2101 *RemovedStartingFcb
= (CurrentFcb
!= StartingFcb
);
2108 _In_ PIRP_CONTEXT IrpContext
,
2115 Routine Description:
2117 This routine will look through the Fcb table looking for a matching
2122 Vcb - Vcb for this volume.
2124 FileId - This is the key value to use for the search.
2128 PFCB - A pointer to the matching entry or NULL otherwise.
2133 FCB_TABLE_ELEMENT Key
;
2134 PFCB_TABLE_ELEMENT Hit
;
2135 PFCB ReturnFcb
= NULL
;
2139 Key
.FileId
= FileId
;
2141 Hit
= (PFCB_TABLE_ELEMENT
) RtlLookupElementGenericTable( &Vcb
->FcbTable
, &Key
);
2145 ReturnFcb
= Hit
->Fcb
;
2150 UNREFERENCED_PARAMETER( IrpContext
);
2156 _In_ PIRP_CONTEXT IrpContext
,
2158 _In_ PVOID
*RestartKey
2163 Routine Description:
2165 This routine will enumerate through all of the Fcb's in the Fcb table.
2169 Vcb - Vcb for this volume.
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.
2177 PFCB - A pointer to the next fcb or NULL if the enumeration is
2187 UNREFERENCED_PARAMETER( IrpContext
);
2189 Fcb
= (PFCB
) RtlEnumerateGenericTableWithoutSplaying( &Vcb
->FcbTable
, RestartKey
);
2193 Fcb
= ((PFCB_TABLE_ELEMENT
)(Fcb
))->Fcb
;
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
2212 Routine Description:
2214 This routine is called to verify and process the TOC for this disk.
2215 We hide a data track for a CD+ volume.
2219 TargetDeviceObject - Device object to send TOC request to.
2221 CdromToc - Pointer to TOC structure.
2223 Length - On input this is the length of the TOC. On return is the TOC
2224 length we will show to the user.
2226 TrackCount - This is the count of tracks for the TOC. We use this
2227 when creating a pseudo directory for a music disk.
2229 DiskFlags - We return flags indicating what we know about this disk.
2233 NTSTATUS - The result of trying to read the TOC.
2239 IO_STATUS_BLOCK Iosb
;
2240 CDROM_READ_TOC_EX Command
;
2243 ULONG LocalTrackCount
;
2244 ULONG LocalTocLength
;
2246 BOOLEAN UseReadToc
= FALSE
;
2260 // Zero the command block. This conveniently corresponds to an
2261 // LBA mode READ_TOC request.
2264 RtlZeroMemory( &Command
, sizeof( Command
));
2269 // Go ahead and read the table of contents
2272 Status
= CdPerformDevIoCtrlEx( IrpContext
,
2273 UseReadToc
? IOCTL_CDROM_READ_TOC
: IOCTL_CDROM_READ_TOC_EX
,
2278 sizeof( CDROM_TOC_LARGE
),
2284 // Nothing to process if this request fails.
2287 if (!NT_SUCCESS( Status
)) {
2290 // If the underlying device does not support READ_TOC_EX, try the old method.
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
))) {
2306 // Get the number of tracks and stated size of this structure.
2310 LocalTrackCount
= CdromToc
->LastTrack
- CdromToc
->FirstTrack
+ 1;
2311 LocalTocLength
= PtrOffset( CdromToc
, &CdromToc
->TrackData
[LocalTrackCount
+ 1] );
2314 // Get out if there is an immediate problem with the TOC.
2317 if ((LocalTocLength
> Iosb
.Information
) ||
2318 (CdromToc
->FirstTrack
> CdromToc
->LastTrack
)) {
2320 Status
= STATUS_DISK_CORRUPT_ERROR
;
2325 // Walk through the individual tracks. Stop at the first data track after
2326 // any lead-in audio tracks.
2332 // Get the next track.
2335 Track
= &CdromToc
->TrackData
[CurrentTrack
];
2338 // If this is a data track then check if we have only seen audio tracks
2342 if (FlagOn( Track
->Control
, TOC_DATA_TRACK
)) {
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
2351 if (FlagOn( *DiskFlags
, CDROM_DISK_AUDIO_TRACK
) &&
2352 !FlagOn( *DiskFlags
, CDROM_DISK_DATA_TRACK
)) {
2355 // Remove one track from the TOC.
2358 CdromToc
->LastTrack
-= 1;
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).
2365 SwapCopyUchar4( &Address
, &Track
->Address
);
2367 SwapCopyUchar4( &Track
->Address
, &Address
);
2369 Track
->TrackNumber
= TOC_LAST_TRACK
;
2372 // Set the disk type to mixed data/audio.
2375 SetFlag( *DiskFlags
, CDROM_DISK_DATA_TRACK
);
2381 // Set the flag to indicate data tracks present.
2384 SetFlag( *DiskFlags
, CDROM_DISK_DATA_TRACK
);
2387 // If this is a audio track then set the flag indicating audio
2393 SetFlag( *DiskFlags
, CDROM_DISK_AUDIO_TRACK
);
2397 // Set our index for the next track.
2402 } while (CurrentTrack
< LocalTrackCount
);
2405 // Set the length to point just past the last track we looked at.
2408 *TrackCount
= CurrentTrack
;
2409 *Length
= PtrOffset( CdromToc
, &CdromToc
->TrackData
[CurrentTrack
+ 1] );
2410 BiasedTocLength
.Length
= (USHORT
) *Length
- 2;
2412 CdromToc
->Length
[0] = BiasedTocLength
.BigEndian
[1];
2413 CdromToc
->Length
[1] = BiasedTocLength
.BigEndian
[0];
2420 // Local support routine
2425 _In_ PIRP_CONTEXT IrpContext
,
2431 Routine Description:
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.
2439 Fcb - This is the Fcb to deallcoate.
2452 // Sanity check the counts.
2455 NT_ASSERT( Fcb
->FcbCleanup
== 0 );
2456 NT_ASSERT( Fcb
->FcbReference
== 0 );
2459 // Release any Filter Context structures associated with this FCB
2462 FsRtlTeardownPerStreamContexts( &Fcb
->Header
);
2465 // Start with the common structures.
2468 CdUninitializeMcb( IrpContext
, Fcb
);
2470 CdDeleteFcbNonpaged( IrpContext
, Fcb
->FcbNonpaged
);
2473 // Check if we need to deallocate the prefix name buffer.
2476 if ((Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
!= (PWCHAR
) Fcb
->FileNamePrefix
.FileNameBuffer
) &&
2477 (Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
!= NULL
)) {
2479 CdFreePool( &Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
);
2483 // Now look at the short name prefix.
2486 if (Fcb
->ShortNamePrefix
!= NULL
) {
2488 CdFreePool( &Fcb
->ShortNamePrefix
);
2492 // Now do the type specific structures.
2495 switch (Fcb
->NodeTypeCode
) {
2497 case CDFS_NTC_FCB_PATH_TABLE
:
2498 case CDFS_NTC_FCB_INDEX
:
2500 NT_ASSERT( Fcb
->FileObject
== NULL
);
2501 NT_ASSERT( IsListEmpty( &Fcb
->FcbQueue
));
2503 if (Fcb
== Fcb
->Vcb
->RootIndexFcb
) {
2506 Vcb
->RootIndexFcb
= NULL
;
2508 } else if (Fcb
== Fcb
->Vcb
->PathTableFcb
) {
2511 Vcb
->PathTableFcb
= NULL
;
2514 CdDeallocateFcbIndex( IrpContext
, *(PVOID
*)&Fcb
);/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */
2517 case CDFS_NTC_FCB_DATA
:
2519 if (Fcb
->FileLock
!= NULL
) {
2521 FsRtlFreeFileLock( Fcb
->FileLock
);
2524 FsRtlUninitializeOplock( CdGetFcbOplock(Fcb
) );
2526 if (Fcb
== Fcb
->Vcb
->VolumeDasdFcb
) {
2529 Vcb
->VolumeDasdFcb
= NULL
;
2532 CdDeallocateFcbData( IrpContext
, *(PVOID
*)&Fcb
);/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */
2536 // Decrement the Vcb reference count if this is a system
2542 InterlockedDecrement( (LONG
*)&Vcb
->VcbReference
);
2543 InterlockedDecrement( (LONG
*)&Vcb
->VcbUserReference
);
2551 // Local support routine
2555 CdCreateFcbNonpaged (
2556 _In_ PIRP_CONTEXT IrpContext
2561 Routine Description:
2563 This routine is called to create and initialize the non-paged portion
2570 PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created.
2575 PFCB_NONPAGED FcbNonpaged
;
2579 UNREFERENCED_PARAMETER( IrpContext
);
2582 // Allocate the non-paged pool and initialize the various
2583 // synchronization objects.
2586 FcbNonpaged
= CdAllocateFcbNonpaged( IrpContext
);
2588 if (FcbNonpaged
!= NULL
) {
2590 RtlZeroMemory( FcbNonpaged
, sizeof( FCB_NONPAGED
));
2592 FcbNonpaged
->NodeTypeCode
= CDFS_NTC_FCB_NONPAGED
;
2593 FcbNonpaged
->NodeByteSize
= sizeof( FCB_NONPAGED
);
2595 ExInitializeResourceLite( &FcbNonpaged
->FcbResource
);
2596 ExInitializeFastMutex( &FcbNonpaged
->FcbMutex
);
2604 // Local support routine
2608 CdDeleteFcbNonpaged (
2609 _In_ PIRP_CONTEXT IrpContext
,
2610 _In_ PFCB_NONPAGED FcbNonpaged
2615 Routine Description:
2617 This routine is called to cleanup the non-paged portion of an Fcb.
2621 FcbNonpaged - Structure to clean up.
2632 UNREFERENCED_PARAMETER( IrpContext
);
2634 ExDeleteResourceLite( &FcbNonpaged
->FcbResource
);
2636 CdDeallocateFcbNonpaged( IrpContext
, *(PVOID
*)&FcbNonpaged
);/* ReactOS Change: GCC "passing argument 1 from incompatible pointer type" */
2643 // Local support routine
2646 RTL_GENERIC_COMPARE_RESULTS
2647 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
2649 _In_ PRTL_GENERIC_TABLE FcbTable
,
2656 Routine Description:
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.
2663 FcbTable - This is the table being searched.
2665 Fid1 - First key value.
2667 Fid2 - Second key value.
2671 RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
2680 Id1
= *((FILE_ID UNALIGNED
*) Fid1
);
2681 Id2
= *((FILE_ID UNALIGNED
*) Fid2
);
2683 if (Id1
.QuadPart
< Id2
.QuadPart
) {
2685 return GenericLessThan
;
2687 } else if (Id1
.QuadPart
> Id2
.QuadPart
) {
2689 return GenericGreaterThan
;
2693 return GenericEqual
;
2696 UNREFERENCED_PARAMETER( FcbTable
);
2701 // Local support routine
2705 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
2706 CdAllocateFcbTable (
2707 _In_ PRTL_GENERIC_TABLE FcbTable
,
2713 Routine Description:
2715 This is a generic table support routine to allocate memory
2719 FcbTable - Supplies the generic table being used
2721 ByteSize - Supplies the number of bytes to allocate
2725 PVOID - Returns a pointer to the allocated data
2732 UNREFERENCED_PARAMETER( FcbTable
);
2734 return( FsRtlAllocatePoolWithTag( CdPagedPool
, ByteSize
, TAG_FCB_TABLE
));
2739 // Local support routine
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
2749 Routine Description:
2751 This is a generic table support routine that deallocates memory
2755 FcbTable - Supplies the generic table being used
2757 Buffer - Supplies the buffer being deallocated
2768 CdFreePool( &Buffer
);
2770 UNREFERENCED_PARAMETER( FcbTable
);
2775 // Local support routine
2780 _In_ PIRP_CONTEXT IrpContext
,
2781 _In_ PCDROM_TOC_LARGE CdromToc
2786 Routine Description:
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.
2792 If the number of tracks is <= 2 then initialize the serial number to the
2793 leadout block number.
2795 Then add the starting address of each track (use 0x00mmssff format).
2799 CdromToc - Valid table of contents to use for track information.
2803 ULONG - 32 bit serial number based on TOC.
2808 ULONG SerialNumber
= 0;
2809 PTRACK_DATA ThisTrack
;
2810 PTRACK_DATA LastTrack
;
2812 ULONG MsfAddress
= 0; // satisfy PREFIX
2816 UNREFERENCED_PARAMETER( IrpContext
);
2819 // Check if there are two tracks or fewer.
2822 LastTrack
= &CdromToc
->TrackData
[ CdromToc
->LastTrack
- CdromToc
->FirstTrack
+ 1];
2823 ThisTrack
= &CdromToc
->TrackData
[0];
2825 if (CdromToc
->LastTrack
- CdromToc
->FirstTrack
<= 1) {
2827 SwapCopyUchar4( &Address
, LastTrack
->Address
);
2828 CdLbnToMmSsFf( Address
, (PUCHAR
)&SerialNumber
);
2833 // Add the starting offset of each track and add to the serial number.
2836 while (ThisTrack
!= LastTrack
) {
2838 SwapCopyUchar4( &Address
, ThisTrack
->Address
);
2839 CdLbnToMmSsFf( Address
, (PUCHAR
)&MsfAddress
);
2841 SerialNumber
+= MsfAddress
;
2846 return SerialNumber
;