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 // IN 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 RTL_GENERIC_COMPARE_RESULTS
168 IN PRTL_GENERIC_TABLE FcbTable
,
175 IN PRTL_GENERIC_TABLE FcbTable
,
180 CdDeallocateFcbTable (
181 IN PRTL_GENERIC_TABLE FcbTable
,
187 IN PIRP_CONTEXT IrpContext
,
188 IN PCDROM_TOC CdromToc
192 #pragma alloc_text(PAGE, CdAllocateFcbTable)
193 #pragma alloc_text(PAGE, CdCleanupIrpContext)
194 #pragma alloc_text(PAGE, CdCreateCcb)
195 #pragma alloc_text(PAGE, CdCreateFcb)
196 #pragma alloc_text(PAGE, CdCreateFcbNonpaged)
197 #pragma alloc_text(PAGE, CdCreateFileLock)
198 #pragma alloc_text(PAGE, CdCreateIrpContext)
199 #pragma alloc_text(PAGE, CdDeallocateFcbTable)
200 #pragma alloc_text(PAGE, CdDeleteCcb)
201 #pragma alloc_text(PAGE, CdDeleteFcb)
202 #pragma alloc_text(PAGE, CdDeleteFcbNonpaged)
203 #pragma alloc_text(PAGE, CdDeleteFileLock)
204 #pragma alloc_text(PAGE, CdDeleteVcb)
205 #pragma alloc_text(PAGE, CdFcbTableCompare)
206 #pragma alloc_text(PAGE, CdGetNextFcb)
207 #pragma alloc_text(PAGE, CdInitializeFcbFromFileContext)
208 #pragma alloc_text(PAGE, CdInitializeFcbFromPathEntry)
209 #pragma alloc_text(PAGE, CdInitializeStackIrpContext)
210 #pragma alloc_text(PAGE, CdInitializeVcb)
211 #pragma alloc_text(PAGE, CdLookupFcbTable)
212 #pragma alloc_text(PAGE, CdProcessToc)
213 #pragma alloc_text(PAGE, CdTeardownStructures)
214 #pragma alloc_text(PAGE, CdTocSerial)
215 #pragma alloc_text(PAGE, CdUpdateVcbFromVolDescriptor)
221 IN PIRP_CONTEXT IrpContext
,
223 IN PDEVICE_OBJECT TargetDeviceObject
,
225 IN PCDROM_TOC CdromToc
,
227 IN ULONG TocTrackCount
,
228 IN ULONG TocDiskFlags
,
229 IN ULONG BlockFactor
,
230 IN ULONG MediaChangeCount
237 This routine initializes and inserts a new Vcb record into the in-memory
238 data structure. The Vcb record "hangs" off the end of the Volume device
239 object and must be allocated by our caller.
243 Vcb - Supplies the address of the Vcb record being initialized.
245 TargetDeviceObject - Supplies the address of the target device object to
246 associate with the Vcb record.
248 Vpb - Supplies the address of the Vpb to associate with the Vcb record.
250 CdromToc - Buffer to hold table of contents. NULL if TOC command not
253 TocLength - Byte count length of TOC. We use this as the TOC length to
254 return on a user query.
256 TocTrackCount - Count of tracks in TOC. Used to create pseudo files for
259 TocDiskFlags - Flag field to indicate the type of tracks on the disk.
261 BlockFactor - Used to decode any multi-session information.
263 MediaChangeCount - Initial media change count of the target device
275 // We start by first zeroing out all of the VCB, this will guarantee
276 // that any stale data is wiped clean.
279 RtlZeroMemory( Vcb
, sizeof( VCB
));
282 // Set the proper node type code and node byte size.
285 Vcb
->NodeTypeCode
= CDFS_NTC_VCB
;
286 Vcb
->NodeByteSize
= sizeof( VCB
);
289 // Initialize the DirNotify structs. FsRtlNotifyInitializeSync can raise.
292 InitializeListHead( &Vcb
->DirNotifyList
);
293 FsRtlNotifyInitializeSync( &Vcb
->NotifySync
);
296 // Pick up a VPB right now so we know we can pull this filesystem stack
297 // off of the storage stack on demand. This can raise - if it does,
298 // uninitialize the notify structures before returning.
303 Vcb
->SwapVpb
= FsRtlAllocatePoolWithTag( NonPagedPool
,
309 if (AbnormalTermination()) {
311 FsRtlNotifyUninitializeSync( &Vcb
->NotifySync
);
316 // Nothing beyond this point should raise.
319 RtlZeroMemory( Vcb
->SwapVpb
, sizeof( VPB
) );
322 // Initialize the resource variable for the Vcb and files.
325 ExInitializeResourceLite( &Vcb
->VcbResource
);
326 ExInitializeResourceLite( &Vcb
->FileResource
);
327 ExInitializeFastMutex( &Vcb
->VcbMutex
);
330 // Insert this Vcb record on the CdData.VcbQueue.
333 InsertHeadList( &CdData
.VcbQueue
, &Vcb
->VcbLinks
);
336 // Set the Target Device Object and Vpb fields, referencing the
337 // Target device for the mount.
340 ObReferenceObject( TargetDeviceObject
);
341 Vcb
->TargetDeviceObject
= TargetDeviceObject
;
345 // Set the removable media flag based on the real device's
349 if (FlagOn( Vpb
->RealDevice
->Characteristics
, FILE_REMOVABLE_MEDIA
)) {
351 SetFlag( Vcb
->VcbState
, VCB_STATE_REMOVABLE_MEDIA
);
355 // Initialize the generic Fcb Table.
358 RtlInitializeGenericTable( &Vcb
->FcbTable
,
359 (PRTL_GENERIC_COMPARE_ROUTINE
) CdFcbTableCompare
,
360 (PRTL_GENERIC_ALLOCATE_ROUTINE
) CdAllocateFcbTable
,
361 (PRTL_GENERIC_FREE_ROUTINE
) CdDeallocateFcbTable
,
365 // Show that we have a mount in progress.
368 CdUpdateVcbCondition( Vcb
, VcbMountInProgress
);
371 // Reference the Vcb for two reasons. The first is a reference
372 // that prevents the Vcb from going away on the last close unless
373 // dismount has already occurred. The second is to make sure
374 // we don't go into the dismount path on any error during mount
375 // until we get to the Mount cleanup.
378 Vcb
->VcbReference
= 1 + CDFS_RESIDUAL_REFERENCE
;
381 // Update the TOC information in the Vcb.
384 Vcb
->CdromToc
= CdromToc
;
385 Vcb
->TocLength
= TocLength
;
386 Vcb
->TrackCount
= TocTrackCount
;
387 Vcb
->DiskFlags
= TocDiskFlags
;
390 // If this disk contains audio tracks only then set the audio flag.
393 if (TocDiskFlags
== CDROM_DISK_AUDIO_TRACK
) {
395 SetFlag( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
| VCB_STATE_CDXA
);
399 // Set the block factor.
402 Vcb
->BlockFactor
= BlockFactor
;
405 // Set the media change count on the device
408 CdUpdateMediaChangeCount( Vcb
, MediaChangeCount
);
413 CdUpdateVcbFromVolDescriptor (
414 IN PIRP_CONTEXT IrpContext
,
416 IN PCHAR RawIsoVd OPTIONAL
423 This routine is called to perform the final initialization of a Vcb from the
424 volume descriptor on the disk.
428 Vcb - Vcb for the volume being mounted. We have already set the flags for the
431 RawIsoVd - If specified this is the volume descriptor to use to mount the
432 volume. Not specified for a raw disk.
441 //ULONG Shift; /* ReactOS Change: GCC Unused variable */
447 PRAW_DIRENT RawDirent
;
448 PATH_ENTRY PathEntry
;
449 PCD_MCB_ENTRY McbEntry
;
451 BOOLEAN UnlockVcb
= FALSE
;
456 // Use a try-finally to facilitate cleanup.
462 // Copy the block size and compute the various block masks.
463 // Block size must not be larger than the sector size. We will
464 // use a default of the CD physical sector size if we are not
465 // on a data-full disc.
467 // This must always be set.
470 Vcb
->BlockSize
= ( ARGUMENT_PRESENT( RawIsoVd
) ?
471 CdRvdBlkSz( RawIsoVd
, Vcb
->VcbState
) :
475 // We no longer accept media where blocksize != sector size.
478 if (Vcb
->BlockSize
!= SECTOR_SIZE
) {
480 CdRaiseStatus( IrpContext
, STATUS_DISK_CORRUPT_ERROR
);
483 Vcb
->BlocksPerSector
= SECTOR_SIZE
/ Vcb
->BlockSize
;
484 Vcb
->BlockMask
= Vcb
->BlockSize
- 1;
485 Vcb
->BlockInverseMask
= ~Vcb
->BlockMask
;
487 Vcb
->BlockToSectorShift
= 0;
488 Vcb
->BlockToByteShift
= SECTOR_SHIFT
;
491 // If there is a volume descriptor then do the internal Fcb's and
495 if (ARGUMENT_PRESENT( RawIsoVd
)) {
498 // Create the path table Fcb and reference it and the Vcb.
501 CdLockVcb( IrpContext
, Vcb
);
504 Vcb
->PathTableFcb
= CdCreateFcb( IrpContext
,
505 *((PFILE_ID
) &FileId
),
506 CDFS_NTC_FCB_PATH_TABLE
,
509 CdIncrementReferenceCounts( IrpContext
, Vcb
->PathTableFcb
, 1, 1 );
510 CdUnlockVcb( IrpContext
, Vcb
);
514 // Compute the stream offset and size of this path table.
517 StartingBlock
= CdRvdPtLoc( RawIsoVd
, Vcb
->VcbState
);
519 ByteCount
= CdRvdPtSz( RawIsoVd
, Vcb
->VcbState
);
521 Vcb
->PathTableFcb
->StreamOffset
= BytesFromBlocks( Vcb
,
522 SectorBlockOffset( Vcb
, StartingBlock
));
524 Vcb
->PathTableFcb
->FileSize
.QuadPart
= (LONGLONG
) (Vcb
->PathTableFcb
->StreamOffset
+
527 Vcb
->PathTableFcb
->ValidDataLength
.QuadPart
= Vcb
->PathTableFcb
->FileSize
.QuadPart
;
529 Vcb
->PathTableFcb
->AllocationSize
.QuadPart
= LlSectorAlign( Vcb
->PathTableFcb
->FileSize
.QuadPart
);
532 // Now add the mapping information.
535 CdLockFcb( IrpContext
, Vcb
->PathTableFcb
);
537 CdAddInitialAllocation( IrpContext
,
540 Vcb
->PathTableFcb
->AllocationSize
.QuadPart
);
542 CdUnlockFcb( IrpContext
, Vcb
->PathTableFcb
);
545 // Point to the file resource.
548 Vcb
->PathTableFcb
->Resource
= &Vcb
->FileResource
;
551 // Mark the Fcb as initialized and create the stream file for this.
554 SetFlag( Vcb
->PathTableFcb
->FcbState
, FCB_STATE_INITIALIZED
);
556 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->PathTableFcb
);
559 // Create the root index and reference it in the Vcb.
562 CdLockVcb( IrpContext
, Vcb
);
564 Vcb
->RootIndexFcb
= CdCreateFcb( IrpContext
,
565 *((PFILE_ID
) &FileId
),
569 CdIncrementReferenceCounts( IrpContext
, Vcb
->RootIndexFcb
, 1, 1 );
570 CdUnlockVcb( IrpContext
, Vcb
);
574 // Create the File id by hand for this Fcb.
577 CdSetFidPathTableOffset( Vcb
->RootIndexFcb
->FileId
, Vcb
->PathTableFcb
->StreamOffset
);
578 CdFidSetDirectory( Vcb
->RootIndexFcb
->FileId
);
581 // Create a pseudo path table entry so we can call the initialization
582 // routine for the directory.
585 RawDirent
= (PRAW_DIRENT
) CdRvdDirent( RawIsoVd
, Vcb
->VcbState
);
587 CopyUchar4( &PathEntry
.DiskOffset
, RawDirent
->FileLoc
);
589 PathEntry
.DiskOffset
+= RawDirent
->XarLen
;
590 PathEntry
.Ordinal
= 1;
591 PathEntry
.PathTableOffset
= Vcb
->PathTableFcb
->StreamOffset
;
593 CdInitializeFcbFromPathEntry( IrpContext
,
599 // Create the stream file for the root directory.
602 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->RootIndexFcb
);
605 // Now do the volume dasd Fcb. Create this and reference it in the
609 CdLockVcb( IrpContext
, Vcb
);
612 Vcb
->VolumeDasdFcb
= CdCreateFcb( IrpContext
,
613 *((PFILE_ID
) &FileId
),
617 CdIncrementReferenceCounts( IrpContext
, Vcb
->VolumeDasdFcb
, 1, 1 );
618 CdUnlockVcb( IrpContext
, Vcb
);
622 // The file size is the full disk.
625 StartingBlock
= CdRvdVolSz( RawIsoVd
, Vcb
->VcbState
);
627 Vcb
->VolumeDasdFcb
->FileSize
.QuadPart
= LlBytesFromBlocks( Vcb
, StartingBlock
);
629 Vcb
->VolumeDasdFcb
->AllocationSize
.QuadPart
=
630 Vcb
->VolumeDasdFcb
->ValidDataLength
.QuadPart
= Vcb
->VolumeDasdFcb
->FileSize
.QuadPart
;
633 // Now add the extent representing the volume 'by hand'.
636 CdLockFcb( IrpContext
, Vcb
->VolumeDasdFcb
);
638 McbEntry
= Vcb
->VolumeDasdFcb
->Mcb
.McbArray
;
640 McbEntry
->FileOffset
=
641 McbEntry
->DiskOffset
= 0;
643 McbEntry
->ByteCount
= Vcb
->VolumeDasdFcb
->AllocationSize
.QuadPart
;
645 McbEntry
->DataBlockByteCount
=
646 McbEntry
->TotalBlockByteCount
= McbEntry
->ByteCount
;
648 Vcb
->VolumeDasdFcb
->Mcb
.CurrentEntryCount
= 1;
650 CdUnlockFcb( IrpContext
, Vcb
->VolumeDasdFcb
);
653 // Point to the file resource.
656 Vcb
->VolumeDasdFcb
->Resource
= &Vcb
->FileResource
;
658 Vcb
->VolumeDasdFcb
->FileAttributes
= FILE_ATTRIBUTE_READONLY
;
661 // Mark the Fcb as initialized.
664 SetFlag( Vcb
->VolumeDasdFcb
->FcbState
, FCB_STATE_INITIALIZED
);
667 // Check and see if this is an XA disk.
670 if (FlagOn( Vcb
->VcbState
, VCB_STATE_ISO
| VCB_STATE_JOLIET
)
671 && RtlEqualMemory( CdXaId
,
672 Add2Ptr( RawIsoVd
, 0x400, PCHAR
),
675 SetFlag( Vcb
->VcbState
, VCB_STATE_CDXA
);
679 // If this is a music disk then we want to mock this disk to make it
680 // look like ISO disk. We will create a pseudo root directory in
684 } else if (FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
686 ULONG RootDirectorySize
;
689 // Create the path table Fcb and reference it and the Vcb.
692 CdLockVcb( IrpContext
, Vcb
);
695 Vcb
->PathTableFcb
= CdCreateFcb( IrpContext
,
696 *((PFILE_ID
) &FileId
),
697 CDFS_NTC_FCB_PATH_TABLE
,
700 CdIncrementReferenceCounts( IrpContext
, Vcb
->PathTableFcb
, 1, 1 );
701 CdUnlockVcb( IrpContext
, Vcb
);
705 // We only create a pseudo entry for the root.
708 Vcb
->PathTableFcb
->FileSize
.QuadPart
= (LONGLONG
) (FIELD_OFFSET( RAW_PATH_ISO
, DirId
) + 2);
710 Vcb
->PathTableFcb
->ValidDataLength
.QuadPart
= Vcb
->PathTableFcb
->FileSize
.QuadPart
;
712 Vcb
->PathTableFcb
->AllocationSize
.QuadPart
= LlSectorAlign( Vcb
->PathTableFcb
->FileSize
.QuadPart
);
715 // Point to the file resource.
718 Vcb
->PathTableFcb
->Resource
= &Vcb
->FileResource
;
721 // Mark the Fcb as initialized and create the stream file for this.
724 SetFlag( Vcb
->PathTableFcb
->FcbState
, FCB_STATE_INITIALIZED
);
726 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->PathTableFcb
);
729 // Create the root index and reference it in the Vcb.
732 CdLockVcb( IrpContext
, Vcb
);
734 Vcb
->RootIndexFcb
= CdCreateFcb( IrpContext
,
735 *((PFILE_ID
) &FileId
),
739 CdIncrementReferenceCounts( IrpContext
, Vcb
->RootIndexFcb
, 1, 1 );
740 CdUnlockVcb( IrpContext
, Vcb
);
744 // Create the File id by hand for this Fcb.
747 CdSetFidPathTableOffset( Vcb
->RootIndexFcb
->FileId
, Vcb
->PathTableFcb
->StreamOffset
);
748 CdFidSetDirectory( Vcb
->RootIndexFcb
->FileId
);
751 // Create a pseudo path table entry so we can call the initialization
752 // routine for the directory.
755 RtlZeroMemory( &PathEntry
, sizeof( PATH_ENTRY
));
758 PathEntry
.Ordinal
= 1;
759 PathEntry
.PathTableOffset
= Vcb
->PathTableFcb
->StreamOffset
;
761 CdInitializeFcbFromPathEntry( IrpContext
,
767 // Set the sizes by hand for this Fcb. It should have an entry for each track plus an
768 // entry for the root and parent.
771 RootDirectorySize
= (Vcb
->TrackCount
+ 2) * CdAudioDirentSize
;
772 RootDirectorySize
= SectorAlign( RootDirectorySize
);
774 Vcb
->RootIndexFcb
->AllocationSize
.QuadPart
=
775 Vcb
->RootIndexFcb
->ValidDataLength
.QuadPart
=
776 Vcb
->RootIndexFcb
->FileSize
.QuadPart
= RootDirectorySize
;
778 SetFlag( Vcb
->RootIndexFcb
->FcbState
, FCB_STATE_INITIALIZED
);
781 // Create the stream file for the root directory.
784 CdCreateInternalStream( IrpContext
, Vcb
, Vcb
->RootIndexFcb
);
787 // Now do the volume dasd Fcb. Create this and reference it in the
791 CdLockVcb( IrpContext
, Vcb
);
794 Vcb
->VolumeDasdFcb
= CdCreateFcb( IrpContext
,
795 *((PFILE_ID
) &FileId
),
799 CdIncrementReferenceCounts( IrpContext
, Vcb
->VolumeDasdFcb
, 1, 1 );
800 CdUnlockVcb( IrpContext
, Vcb
);
804 // We won't allow raw reads on this Fcb so leave the size at
809 // Point to the file resource.
812 Vcb
->VolumeDasdFcb
->Resource
= &Vcb
->FileResource
;
814 Vcb
->VolumeDasdFcb
->FileAttributes
= FILE_ATTRIBUTE_READONLY
;
817 // Mark the Fcb as initialized.
820 SetFlag( Vcb
->VolumeDasdFcb
->FcbState
, FCB_STATE_INITIALIZED
);
823 // We will store a hard-coded name in the Vpb and use the toc as
824 // the serial number.
827 Vcb
->Vpb
->VolumeLabelLength
= CdAudioLabelLength
;
829 RtlCopyMemory( Vcb
->Vpb
->VolumeLabel
,
831 CdAudioLabelLength
);
834 // Find the serial number for the audio disk.
837 Vcb
->Vpb
->SerialNumber
= CdTocSerial( IrpContext
, Vcb
->CdromToc
);
840 // Set the ISO bit so we know how to treat the names.
843 SetFlag( Vcb
->VcbState
, VCB_STATE_ISO
);
848 if (UnlockVcb
) { CdUnlockVcb( IrpContext
, Vcb
); }
855 IN PIRP_CONTEXT IrpContext
,
863 This routine is called to delete a Vcb which failed mount or has been
864 dismounted. The dismount code should have already removed all of the
865 open Fcb's. We do nothing here but clean up other auxiliary structures.
880 ASSERT_EXCLUSIVE_CDDATA
;
881 ASSERT_EXCLUSIVE_VCB( Vcb
);
884 // Chuck the backpocket Vpb we kept just in case.
889 CdFreePool( &Vcb
->SwapVpb
);
893 // If there is a Vpb then we must delete it ourselves.
896 if (Vcb
->Vpb
!= NULL
) {
898 CdFreePool( &Vcb
->Vpb
);
902 // Dereference our target if we haven't already done so.
905 if (Vcb
->TargetDeviceObject
!= NULL
) {
907 ObDereferenceObject( Vcb
->TargetDeviceObject
);
911 // Delete the XA Sector if allocated.
914 if (Vcb
->XASector
!= NULL
) {
916 CdFreePool( &Vcb
->XASector
);
920 // Remove this entry from the global queue.
923 RemoveEntryList( &Vcb
->VcbLinks
);
926 // Delete the Vcb and File resources.
929 ExDeleteResourceLite( &Vcb
->VcbResource
);
930 ExDeleteResourceLite( &Vcb
->FileResource
);
933 // Delete the TOC if present.
936 if (Vcb
->CdromToc
!= NULL
) {
938 CdFreePool( &Vcb
->CdromToc
);
942 // Uninitialize the notify structures.
945 if (Vcb
->NotifySync
!= NULL
) {
947 FsRtlNotifyUninitializeSync( &Vcb
->NotifySync
);
951 // Now delete the volume device object.
954 IoDeleteDevice( (PDEVICE_OBJECT
) CONTAINING_RECORD( Vcb
,
955 VOLUME_DEVICE_OBJECT
,
964 IN PIRP_CONTEXT IrpContext
,
966 IN NODE_TYPE_CODE NodeTypeCode
,
967 OUT PBOOLEAN FcbExisted OPTIONAL
974 This routine is called to find the Fcb for the given FileId. We will
975 look this up first in the Fcb table and if not found we will create
976 an Fcb. We don't initialize it or insert it into the FcbTable in this
979 This routine is called while the Vcb is locked.
983 FileId - This is the Id for the target Fcb.
985 NodeTypeCode - Node type for this Fcb if we need to create.
987 FcbExisted - If specified, we store whether the Fcb existed.
991 PFCB - The Fcb found in the table or created if needed.
997 BOOLEAN LocalFcbExisted
;
1002 // Use the local boolean if one was not passed in.
1005 if (!ARGUMENT_PRESENT( FcbExisted
)) {
1007 FcbExisted
= &LocalFcbExisted
;
1011 // Maybe this is already in the table.
1014 NewFcb
= CdLookupFcbTable( IrpContext
, IrpContext
->Vcb
, FileId
);
1017 // If not then create the Fcb is requested by our caller.
1020 if (NewFcb
== NULL
) {
1023 // Allocate and initialize the structure depending on the
1027 switch (NodeTypeCode
) {
1029 case CDFS_NTC_FCB_PATH_TABLE
:
1030 case CDFS_NTC_FCB_INDEX
:
1032 NewFcb
= CdAllocateFcbIndex( IrpContext
);
1034 RtlZeroMemory( NewFcb
, SIZEOF_FCB_INDEX
);
1036 NewFcb
->NodeByteSize
= SIZEOF_FCB_INDEX
;
1038 InitializeListHead( &NewFcb
->FcbQueue
);
1042 case CDFS_NTC_FCB_DATA
:
1044 NewFcb
= CdAllocateFcbData( IrpContext
);
1046 RtlZeroMemory( NewFcb
, SIZEOF_FCB_DATA
);
1048 NewFcb
->NodeByteSize
= SIZEOF_FCB_DATA
;
1054 CdBugCheck( 0, 0, 0 );
1058 // Now do the common initialization.
1061 NewFcb
->NodeTypeCode
= NodeTypeCode
;
1063 NewFcb
->Vcb
= IrpContext
->Vcb
;
1064 NewFcb
->FileId
= FileId
;
1066 CdInitializeMcb( IrpContext
, NewFcb
);
1069 // Now create the non-paged section object.
1072 NewFcb
->FcbNonpaged
= CdCreateFcbNonpaged( IrpContext
);
1075 // Deallocate the Fcb and raise if the allocation failed.
1078 if (NewFcb
->FcbNonpaged
== NULL
) {
1080 CdFreePool( &NewFcb
);
1082 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1085 *FcbExisted
= FALSE
;
1088 // Initialize Advanced FCB Header fields
1091 ExInitializeFastMutex( &NewFcb
->FcbNonpaged
->AdvancedFcbHeaderMutex
);
1092 FsRtlSetupAdvancedHeader( &NewFcb
->Header
,
1093 &NewFcb
->FcbNonpaged
->AdvancedFcbHeaderMutex
);
1104 CdInitializeFcbFromPathEntry (
1105 IN PIRP_CONTEXT IrpContext
,
1107 IN PFCB ParentFcb OPTIONAL
,
1108 IN PPATH_ENTRY PathEntry
1113 Routine Description:
1115 This routine is called to initialize an Fcb for a directory from
1116 the path entry. Since we only have a starting point for the directory,
1117 not the length, we can only speculate on the sizes.
1119 The general initialization is performed in CdCreateFcb.
1123 Fcb - Newly created Fcb for this stream.
1125 ParentFcb - Parent Fcb for this stream. It may not be present.
1127 PathEntry - PathEntry for this Fcb in the Path Table.
1139 // Fill in the Index specific fields of the Fcb.
1142 Fcb
->StreamOffset
= BytesFromBlocks( Fcb
->Vcb
,
1143 SectorBlockOffset( Fcb
->Vcb
, PathEntry
->DiskOffset
));
1145 Fcb
->Ordinal
= PathEntry
->Ordinal
;
1148 // Initialize the common header in the Fcb. The node type is already
1152 Fcb
->Resource
= &Fcb
->Vcb
->FileResource
;
1155 // Always set the sizes to one sector until we read the self-entry.
1158 Fcb
->AllocationSize
.QuadPart
=
1159 Fcb
->FileSize
.QuadPart
=
1160 Fcb
->ValidDataLength
.QuadPart
= SECTOR_SIZE
;
1162 CdAddInitialAllocation( IrpContext
,
1164 PathEntry
->DiskOffset
,
1167 // State flags for this Fcb.
1170 SetFlag( Fcb
->FileAttributes
,
1171 FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
);
1174 // Link into the other in-memory structures and into the Fcb table.
1177 if (ParentFcb
!= NULL
) {
1179 Fcb
->ParentFcb
= ParentFcb
;
1181 InsertTailList( &ParentFcb
->FcbQueue
, &Fcb
->FcbLinks
);
1183 CdIncrementReferenceCounts( IrpContext
, ParentFcb
, 1, 1 );
1186 CdInsertFcbTable( IrpContext
, Fcb
);
1187 SetFlag( Fcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
);
1194 CdInitializeFcbFromFileContext (
1195 IN PIRP_CONTEXT IrpContext
,
1198 IN PFILE_ENUM_CONTEXT FileContext
1203 Routine Description:
1205 This routine is called to initialize an Fcb for a file from
1206 the file context. We have looked up all of the dirents for this
1207 stream and have the full file size. We will load the all of the allocation
1208 for the file into the Mcb now.
1210 The general initialization is performed in CdCreateFcb.
1214 Fcb - Newly created Fcb for this stream.
1216 ParentFcb - Parent Fcb for this stream.
1218 FileContext - FileContext for the file.
1227 PDIRENT ThisDirent
= &FileContext
->InitialDirent
->Dirent
;
1228 PCOMPOUND_DIRENT CurrentCompoundDirent
;
1230 LONGLONG CurrentFileOffset
;
1231 ULONG CurrentMcbEntryOffset
;
1236 // Use a try-finally to facilitate cleanup.
1239 CdLockFcb( IrpContext
, Fcb
);
1244 // Initialize the common header in the Fcb. The node type is already
1248 Fcb
->Resource
= &IrpContext
->Vcb
->FileResource
;
1251 // Allocation occurs in block-sized units.
1254 Fcb
->FileSize
.QuadPart
=
1255 Fcb
->ValidDataLength
.QuadPart
= FileContext
->FileSize
;
1257 Fcb
->AllocationSize
.QuadPart
= LlBlockAlign( Fcb
->Vcb
, FileContext
->FileSize
);
1260 // Set the flags from the dirent. We always start with the read-only bit.
1263 SetFlag( Fcb
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
1264 if (FlagOn( ThisDirent
->DirentFlags
, CD_ATTRIBUTE_HIDDEN
)) {
1266 SetFlag( Fcb
->FileAttributes
, FILE_ATTRIBUTE_HIDDEN
);
1270 // Convert the time to NT time.
1273 CdConvertCdTimeToNtTime( IrpContext
,
1275 (PLARGE_INTEGER
) &Fcb
->CreationTime
);
1278 // Set the flag indicating the type of extent.
1281 if (ThisDirent
->ExtentType
!= Form1Data
) {
1283 if (ThisDirent
->ExtentType
== Mode2Form2Data
) {
1285 SetFlag( Fcb
->FcbState
, FCB_STATE_MODE2FORM2_FILE
);
1289 SetFlag( Fcb
->FcbState
, FCB_STATE_DA_FILE
);
1292 Fcb
->XAAttributes
= ThisDirent
->XAAttributes
;
1293 Fcb
->XAFileNumber
= ThisDirent
->XAFileNumber
;
1297 // Read through all of the dirents for the file until we find the last
1298 // and add the allocation into the Mcb.
1301 CurrentCompoundDirent
= FileContext
->InitialDirent
;
1302 CurrentFileOffset
= 0;
1303 CurrentMcbEntryOffset
= 0;
1307 CdAddAllocationFromDirent( IrpContext
,
1309 CurrentMcbEntryOffset
,
1311 &CurrentCompoundDirent
->Dirent
);
1314 // Break out if we are at the last dirent.
1317 if (!FlagOn( CurrentCompoundDirent
->Dirent
.DirentFlags
, CD_ATTRIBUTE_MULTI
)) {
1322 CurrentFileOffset
+= CurrentCompoundDirent
->Dirent
.DataLength
;
1323 CurrentMcbEntryOffset
+= 1;
1326 // We better be able to find the next dirent.
1329 if (!CdLookupNextDirent( IrpContext
,
1331 &CurrentCompoundDirent
->DirContext
,
1332 &FileContext
->CurrentDirent
->DirContext
)) {
1334 CdRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
1337 CurrentCompoundDirent
= FileContext
->CurrentDirent
;
1339 CdUpdateDirentFromRawDirent( IrpContext
,
1341 &CurrentCompoundDirent
->DirContext
,
1342 &CurrentCompoundDirent
->Dirent
);
1346 // Show that the Fcb is initialized.
1349 SetFlag( Fcb
->FcbState
, FCB_STATE_INITIALIZED
);
1352 // Link into the other in-memory structures and into the Fcb table.
1355 Fcb
->ParentFcb
= ParentFcb
;
1357 InsertTailList( &ParentFcb
->FcbQueue
, &Fcb
->FcbLinks
);
1359 CdIncrementReferenceCounts( IrpContext
, ParentFcb
, 1, 1 );
1361 CdInsertFcbTable( IrpContext
, Fcb
);
1362 SetFlag( Fcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
);
1366 CdUnlockFcb( IrpContext
, Fcb
);
1375 IN PIRP_CONTEXT IrpContext
,
1382 Routine Description:
1384 This routine is called to allocate and initialize the Ccb structure.
1388 Fcb - This is the Fcb for the file being opened.
1390 Flags - User flags to set in this Ccb.
1394 PCCB - Pointer to the created Ccb.
1403 // Allocate and initialize the structure.
1406 NewCcb
= CdAllocateCcb( IrpContext
);
1408 RtlZeroMemory( NewCcb
, sizeof( CCB
));
1411 // Set the proper node type code and node byte size
1414 NewCcb
->NodeTypeCode
= CDFS_NTC_CCB
;
1415 NewCcb
->NodeByteSize
= sizeof( CCB
);
1418 // Set the initial value for the flags and Fcb
1421 NewCcb
->Flags
= Flags
;
1430 IN PIRP_CONTEXT IrpContext
,
1435 Routine Description:
1437 This routine is called to cleanup and deallocate a Ccb structure.
1441 Ccb - This is the Ccb to delete.
1452 if (Ccb
->SearchExpression
.FileName
.Buffer
!= NULL
) {
1454 CdFreePool( &Ccb
->SearchExpression
.FileName
.Buffer
);
1457 CdDeallocateCcb( IrpContext
, Ccb
);
1464 IN PIRP_CONTEXT IrpContext OPTIONAL
,
1466 IN BOOLEAN RaiseOnError
1471 Routine Description:
1473 This routine is called when we want to attach a file lock structure to the
1474 given Fcb. It is possible the file lock is already attached.
1476 This routine is sometimes called from the fast path and sometimes in the
1477 Irp-based path. We don't want to raise in the fast path, just return FALSE.
1481 Fcb - This is the Fcb to create the file lock for.
1483 RaiseOnError - If TRUE, we will raise on an allocation failure. Otherwise we
1484 return FALSE on an allocation failure.
1488 BOOLEAN - TRUE if the Fcb has a filelock, FALSE otherwise.
1493 BOOLEAN Result
= TRUE
;
1494 PFILE_LOCK FileLock
;
1499 // Lock the Fcb and check if there is really any work to do.
1502 CdLockFcb( IrpContext
, Fcb
);
1504 if (Fcb
->FileLock
!= NULL
) {
1506 CdUnlockFcb( IrpContext
, Fcb
);
1510 Fcb
->FileLock
= FileLock
=
1511 FsRtlAllocateFileLock( NULL
, NULL
);
1513 CdUnlockFcb( IrpContext
, Fcb
);
1516 // Return or raise as appropriate.
1519 if (FileLock
== NULL
) {
1523 ASSERT( ARGUMENT_PRESENT( IrpContext
));
1525 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
1536 CdCreateIrpContext (
1543 Routine Description:
1545 This routine is called to initialize an IrpContext for the current
1546 CDFS request. We allocate the structure and then initialize it from
1551 Irp - Irp for this request.
1553 Wait - TRUE if this request is synchronous, FALSE otherwise.
1557 PIRP_CONTEXT - Allocated IrpContext.
1562 PIRP_CONTEXT NewIrpContext
= NULL
;
1563 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
1568 // The only operations a filesystem device object should ever receive
1569 // are create/teardown of fsdo handles and operations which do not
1570 // occur in the context of fileobjects (i.e., mount).
1574 if (IrpSp
->DeviceObject
== CdData
.FileSystemDeviceObject
) {
1576 if (IrpSp
->DeviceObject
== CdData
.FileSystemDeviceObject
||
1577 IrpSp
->DeviceObject
== CdData
.HddFileSystemDeviceObject
) {
1580 if (IrpSp
->FileObject
!= NULL
&&
1581 IrpSp
->MajorFunction
!= IRP_MJ_CREATE
&&
1582 IrpSp
->MajorFunction
!= IRP_MJ_CLEANUP
&&
1583 IrpSp
->MajorFunction
!= IRP_MJ_CLOSE
) {
1585 ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST
);
1588 ASSERT( IrpSp
->FileObject
!= NULL
||
1590 (IrpSp
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
&&
1591 IrpSp
->MinorFunction
== IRP_MN_USER_FS_REQUEST
&&
1592 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_INVALIDATE_VOLUMES
) ||
1594 (IrpSp
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
&&
1595 IrpSp
->MinorFunction
== IRP_MN_MOUNT_VOLUME
) ||
1597 IrpSp
->MajorFunction
== IRP_MJ_SHUTDOWN
);
1601 // Look in our lookaside list for an IrpContext.
1604 if (CdData
.IrpContextDepth
) {
1607 NewIrpContext
= (PIRP_CONTEXT
) PopEntryList( &CdData
.IrpContextList
);
1608 if (NewIrpContext
!= NULL
) {
1610 CdData
.IrpContextDepth
--;
1616 if (NewIrpContext
== NULL
) {
1619 // We didn't get it from our private list so allocate it from pool.
1622 NewIrpContext
= FsRtlAllocatePoolWithTag( NonPagedPool
, sizeof( IRP_CONTEXT
), TAG_IRP_CONTEXT
);
1625 RtlZeroMemory( NewIrpContext
, sizeof( IRP_CONTEXT
));
1628 // Set the proper node type code and node byte size
1631 NewIrpContext
->NodeTypeCode
= CDFS_NTC_IRP_CONTEXT
;
1632 NewIrpContext
->NodeByteSize
= sizeof( IRP_CONTEXT
);
1635 // Set the originating Irp field
1638 NewIrpContext
->Irp
= Irp
;
1641 // Copy RealDevice for workque algorithms. We will update this in the Mount or
1642 // Verify since they have no file objects to use here.
1645 if (IrpSp
->FileObject
!= NULL
) {
1647 NewIrpContext
->RealDevice
= IrpSp
->FileObject
->DeviceObject
;
1651 // Locate the volume device object and Vcb that we are trying to access.
1652 // This may be our filesystem device object. In that case don't initialize
1657 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
) {
1659 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
&&
1660 IrpSp
->DeviceObject
!= CdData
.HddFileSystemDeviceObject
) {
1663 NewIrpContext
->Vcb
= &((PVOLUME_DEVICE_OBJECT
) IrpSp
->DeviceObject
)->Vcb
;
1668 // Major/Minor Function codes
1671 NewIrpContext
->MajorFunction
= IrpSp
->MajorFunction
;
1672 NewIrpContext
->MinorFunction
= IrpSp
->MinorFunction
;
1675 // Set the wait parameter
1680 SetFlag( NewIrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1684 SetFlag( NewIrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
1688 // return and tell the caller
1691 return NewIrpContext
;
1696 CdCleanupIrpContext (
1697 IN PIRP_CONTEXT IrpContext
,
1703 Routine Description:
1705 This routine is called to cleanup and possibly deallocate the Irp Context.
1706 If the request is being posted or this Irp Context is possibly on the
1707 stack then we only cleanup any auxiliary structures.
1711 Post - TRUE if we are posting this request, FALSE if we are deleting
1712 or retrying this in the current thread.
1724 // If we aren't doing more processing then deallocate this as appropriate.
1727 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_MORE_PROCESSING
)) {
1730 // If this context is the top level CDFS context then we need to
1731 // restore the top level thread context.
1734 if (IrpContext
->ThreadContext
!= NULL
) {
1736 CdRestoreThreadContext( IrpContext
);
1740 // Deallocate the Io context if allocated.
1743 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
)) {
1745 CdFreeIoContext( IrpContext
->IoContext
);
1749 // Deallocate the IrpContext if not from the stack.
1752 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ON_STACK
)) {
1754 if (CdData
.IrpContextDepth
< CdData
.IrpContextMaxDepth
) {
1758 PushEntryList( &CdData
.IrpContextList
, (PSINGLE_LIST_ENTRY
) IrpContext
);
1759 CdData
.IrpContextDepth
++;
1766 // We couldn't add this to our lookaside list so free it to
1770 CdFreePool( &IrpContext
);
1775 // Clear the appropriate flags.
1781 // If this context is the top level CDFS context then we need to
1782 // restore the top level thread context.
1785 if (IrpContext
->ThreadContext
!= NULL
) {
1787 CdRestoreThreadContext( IrpContext
);
1790 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAGS_CLEAR_ON_POST
);
1794 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY
);
1802 CdInitializeStackIrpContext (
1803 OUT PIRP_CONTEXT IrpContext
,
1804 IN PIRP_CONTEXT_LITE IrpContextLite
1809 Routine Description:
1811 This routine is called to initialize an IrpContext for the current
1812 CDFS request. The IrpContext is on the stack and we need to initialize
1813 it for the current request. The request is a close operation.
1817 IrpContext - IrpContext to initialize.
1819 IrpContextLite - Structure containing the details of this request.
1831 // Zero and then initialize the structure.
1834 RtlZeroMemory( IrpContext
, sizeof( IRP_CONTEXT
));
1837 // Set the proper node type code and node byte size
1840 IrpContext
->NodeTypeCode
= CDFS_NTC_IRP_CONTEXT
;
1841 IrpContext
->NodeByteSize
= sizeof( IRP_CONTEXT
);
1844 // Note that this is from the stack.
1847 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ON_STACK
);
1850 // Copy RealDevice for workque algorithms.
1853 IrpContext
->RealDevice
= IrpContextLite
->RealDevice
;
1856 // The Vcb is found in the Fcb.
1859 IrpContext
->Vcb
= IrpContextLite
->Fcb
->Vcb
;
1862 // Major/Minor Function codes
1865 IrpContext
->MajorFunction
= IRP_MJ_CLOSE
;
1868 // Set the wait parameter
1871 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1878 CdTeardownStructures (
1879 IN PIRP_CONTEXT IrpContext
,
1880 IN PFCB StartingFcb
,
1881 OUT PBOOLEAN RemovedStartingFcb
1886 Routine Description:
1888 This routine is used to walk from some starting point in the Fcb tree towards
1889 the root. It will remove the Fcb and continue walking up the tree until
1890 it finds a point where we can't remove an Fcb.
1892 We look at the following fields in the Fcb to determine whether we can
1895 1 - Handle count must be zero.
1896 2 - If directory then only the only reference can be for a stream file.
1897 3 - Reference count must either be zero or go to zero here.
1899 We return immediately if we are recursively entering this routine.
1903 StartingFcb - This is the Fcb node in the tree to begin with. This Fcb
1904 must currently be acquired exclusively.
1906 RemovedStartingFcb - Address to store whether we removed the starting Fcb.
1915 PVCB Vcb
= StartingFcb
->Vcb
;
1916 PFCB CurrentFcb
= StartingFcb
;
1917 BOOLEAN AcquiredCurrentFcb
= FALSE
;
1922 *RemovedStartingFcb
= FALSE
;
1925 // If this is a recursive call to TearDownStructures we return immediately
1926 // doing no operation.
1929 if (FlagOn( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
)) {
1934 SetFlag( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
);
1937 // Use a try-finally to safely clear the top-level field.
1943 // Loop until we find an Fcb we can't remove.
1949 // See if there is an internal stream we should delete.
1950 // Only do this if it is the last reference on the Fcb.
1953 if ((SafeNodeType( CurrentFcb
) != CDFS_NTC_FCB_DATA
) &&
1954 (CurrentFcb
->FcbUserReference
== 0) &&
1955 (CurrentFcb
->FileObject
!= NULL
)) {
1958 // Go ahead and delete the stream file object.
1961 CdDeleteInternalStream( IrpContext
, CurrentFcb
);
1965 // If the reference count is non-zero then break.
1968 if (CurrentFcb
->FcbReference
!= 0) {
1974 // It looks like we have a candidate for removal here. We
1975 // will need to acquire the parent, if present, in order to
1976 // remove this from the parent prefix table.
1979 ParentFcb
= CurrentFcb
->ParentFcb
;
1981 if (ParentFcb
!= NULL
) {
1983 CdAcquireFcbExclusive( IrpContext
, ParentFcb
, FALSE
);
1987 // Now lock the vcb.
1990 CdLockVcb( IrpContext
, Vcb
);
1993 // Final check to see if the reference count is still zero.
1996 if (CurrentFcb
->FcbReference
!= 0) {
1998 CdUnlockVcb( IrpContext
, Vcb
);
2000 if (ParentFcb
!= NULL
) {
2002 CdReleaseFcb( IrpContext
, ParentFcb
);
2009 // If there is a parent then do the necessary cleanup for the parent.
2012 if (ParentFcb
!= NULL
) {
2014 CdRemovePrefix( IrpContext
, CurrentFcb
);
2015 RemoveEntryList( &CurrentFcb
->FcbLinks
);
2017 CdDecrementReferenceCounts( IrpContext
, ParentFcb
, 1, 1 );
2020 if (FlagOn( CurrentFcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
)) {
2022 CdDeleteFcbTable( IrpContext
, CurrentFcb
);
2023 ClearFlag( CurrentFcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
);
2028 // Unlock the Vcb but hold the parent in order to walk up
2032 CdUnlockVcb( IrpContext
, Vcb
);
2033 CdDeleteFcb( IrpContext
, CurrentFcb
);
2036 // Move to the parent Fcb.
2039 CurrentFcb
= ParentFcb
;
2040 AcquiredCurrentFcb
= TRUE
;
2042 } while (CurrentFcb
!= NULL
);
2047 // Release the current Fcb if we have acquired it.
2050 if (AcquiredCurrentFcb
&& (CurrentFcb
!= NULL
)) {
2052 CdReleaseFcb( IrpContext
, CurrentFcb
);
2056 // Clear the teardown flag.
2059 ClearFlag( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
);
2062 *RemovedStartingFcb
= (CurrentFcb
!= StartingFcb
);
2069 IN PIRP_CONTEXT IrpContext
,
2076 Routine Description:
2078 This routine will look through the Fcb table looking for a matching
2083 Vcb - Vcb for this volume.
2085 FileId - This is the key value to use for the search.
2089 PFCB - A pointer to the matching entry or NULL otherwise.
2094 FCB_TABLE_ELEMENT Key
;
2095 PFCB_TABLE_ELEMENT Hit
;
2096 PFCB ReturnFcb
= NULL
;
2100 Key
.FileId
= FileId
;
2102 Hit
= (PFCB_TABLE_ELEMENT
) RtlLookupElementGenericTable( &Vcb
->FcbTable
, &Key
);
2106 ReturnFcb
= Hit
->Fcb
;
2111 UNREFERENCED_PARAMETER( IrpContext
);
2117 IN PIRP_CONTEXT IrpContext
,
2119 IN PVOID
*RestartKey
2124 Routine Description:
2126 This routine will enumerate through all of the Fcb's in the Fcb table.
2130 Vcb - Vcb for this volume.
2132 RestartKey - This value is used by the table package to maintain
2133 its position in the enumeration. It is initialized to NULL
2134 for the first search.
2138 PFCB - A pointer to the next fcb or NULL if the enumeration is
2148 Fcb
= (PFCB
) RtlEnumerateGenericTableWithoutSplaying( &Vcb
->FcbTable
, RestartKey
);
2152 Fcb
= ((PFCB_TABLE_ELEMENT
)(Fcb
))->Fcb
;
2161 IN PIRP_CONTEXT IrpContext
,
2162 IN PDEVICE_OBJECT TargetDeviceObject
,
2163 IN PCDROM_TOC CdromToc
,
2164 IN OUT PULONG Length
,
2165 OUT PULONG TrackCount
,
2166 OUT PULONG DiskFlags
2171 Routine Description:
2173 This routine is called to verify and process the TOC for this disk.
2174 We hide a data track for a CD+ volume.
2178 TargetDeviceObject - Device object to send TOC request to.
2180 CdromToc - Pointer to TOC structure.
2182 Length - On input this is the length of the TOC. On return is the TOC
2183 length we will show to the user.
2185 TrackCount - This is the count of tracks for the TOC. We use this
2186 when creating a pseudo directory for a music disk.
2188 DiskFlags - We return flags indicating what we know about this disk.
2192 NTSTATUS - The result of trying to read the TOC.
2198 IO_STATUS_BLOCK Iosb
;
2201 ULONG LocalTrackCount
;
2202 ULONG LocalTocLength
;
2216 // Go ahead and read the table of contents
2219 Status
= CdPerformDevIoCtrl( IrpContext
,
2220 IOCTL_CDROM_READ_TOC
,
2223 sizeof( CDROM_TOC
),
2229 // Nothing to process if this request fails.
2232 if (Status
!= STATUS_SUCCESS
) {
2238 // Get the number of tracks and stated size of this structure.
2242 LocalTrackCount
= CdromToc
->LastTrack
- CdromToc
->FirstTrack
+ 1;
2243 LocalTocLength
= PtrOffset( CdromToc
, &CdromToc
->TrackData
[LocalTrackCount
+ 1] );
2246 // Get out if there is an immediate problem with the TOC.
2249 if ((LocalTocLength
> Iosb
.Information
) ||
2250 (CdromToc
->FirstTrack
> CdromToc
->LastTrack
)) {
2252 Status
= STATUS_DISK_CORRUPT_ERROR
;
2257 // Walk through the individual tracks. Stop at the first data track after
2258 // any lead-in audio tracks.
2264 // Get the next track.
2267 Track
= &CdromToc
->TrackData
[CurrentTrack
];
2270 // If this is a data track then check if we have only seen audio tracks
2274 if (FlagOn( Track
->Control
, TOC_DATA_TRACK
)) {
2277 // If we have only seen audio tracks then assume this is a
2278 // CD+ disk. Hide the current data track and only return
2279 // the previous audio tracks. Set the disk type to be mixed
2283 if (FlagOn( *DiskFlags
, CDROM_DISK_AUDIO_TRACK
) &&
2284 !FlagOn( *DiskFlags
, CDROM_DISK_DATA_TRACK
)) {
2287 // Remove one track from the TOC.
2290 CdromToc
->LastTrack
-= 1;
2293 // Knock 2.5 minutes off the current track to
2294 // hide the final leadin.
2297 Track
->Address
[1] -= 2;
2298 Track
->Address
[2] += 30;
2300 if (Track
->Address
[2] < 60) {
2302 Track
->Address
[1] -= 1;
2306 Track
->Address
[2] -= 60;
2309 Track
->TrackNumber
= TOC_LAST_TRACK
;
2312 // Set the disk type to mixed data/audio.
2315 SetFlag( *DiskFlags
, CDROM_DISK_DATA_TRACK
);
2321 // Set the flag to indicate data tracks present.
2324 SetFlag( *DiskFlags
, CDROM_DISK_DATA_TRACK
);
2327 // If this is a audio track then set the flag indicating audio
2333 SetFlag( *DiskFlags
, CDROM_DISK_AUDIO_TRACK
);
2337 // Set our index for the next track.
2342 } while (CurrentTrack
< LocalTrackCount
);
2345 // Set the length to point just past the last track we looked at.
2348 *TrackCount
= CurrentTrack
;
2349 *Length
= PtrOffset( CdromToc
, &CdromToc
->TrackData
[CurrentTrack
+ 1] );
2350 BiasedTocLength
.Length
= (USHORT
) *Length
- 2;
2352 CdromToc
->Length
[0] = BiasedTocLength
.BigEndian
[1];
2353 CdromToc
->Length
[1] = BiasedTocLength
.BigEndian
[0];
2360 // Local support routine
2365 IN PIRP_CONTEXT IrpContext
,
2371 Routine Description:
2373 This routine is called to cleanup and deallocate an Fcb. We know there
2374 are no references remaining. We cleanup any auxiliary structures and
2375 deallocate this Fcb.
2379 Fcb - This is the Fcb to deallocate.
2392 // Sanity check the counts.
2395 ASSERT( Fcb
->FcbCleanup
== 0 );
2396 ASSERT( Fcb
->FcbReference
== 0 );
2399 // Release any Filter Context structures associated with this FCB
2402 FsRtlTeardownPerStreamContexts( &Fcb
->Header
);
2405 // Start with the common structures.
2408 CdUninitializeMcb( IrpContext
, Fcb
);
2410 CdDeleteFcbNonpaged( IrpContext
, Fcb
->FcbNonpaged
);
2413 // Check if we need to deallocate the prefix name buffer.
2416 if ((Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
!= (PWCHAR
) Fcb
->FileNamePrefix
.FileNameBuffer
) &&
2417 (Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
!= NULL
)) {
2419 CdFreePool( &Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
);
2423 // Now look at the short name prefix.
2426 if (Fcb
->ShortNamePrefix
!= NULL
) {
2428 CdFreePool( &Fcb
->ShortNamePrefix
);
2432 // Now do the type specific structures.
2435 switch (Fcb
->NodeTypeCode
) {
2437 case CDFS_NTC_FCB_PATH_TABLE
:
2438 case CDFS_NTC_FCB_INDEX
:
2440 ASSERT( Fcb
->FileObject
== NULL
);
2441 ASSERT( IsListEmpty( &Fcb
->FcbQueue
));
2443 if (Fcb
== Fcb
->Vcb
->RootIndexFcb
) {
2446 Vcb
->RootIndexFcb
= NULL
;
2448 } else if (Fcb
== Fcb
->Vcb
->PathTableFcb
) {
2451 Vcb
->PathTableFcb
= NULL
;
2454 CdDeallocateFcbIndex( IrpContext
, Fcb
);
2457 case CDFS_NTC_FCB_DATA
:
2459 if (Fcb
->FileLock
!= NULL
) {
2461 FsRtlFreeFileLock( Fcb
->FileLock
);
2464 FsRtlUninitializeOplock( &Fcb
->Oplock
);
2466 if (Fcb
== Fcb
->Vcb
->VolumeDasdFcb
) {
2469 Vcb
->VolumeDasdFcb
= NULL
;
2472 CdDeallocateFcbData( IrpContext
, Fcb
);
2476 // Decrement the Vcb reference count if this is a system
2482 InterlockedDecrement( &Vcb
->VcbReference
);
2483 InterlockedDecrement( &Vcb
->VcbUserReference
);
2491 // Local support routine
2495 CdCreateFcbNonpaged (
2496 IN PIRP_CONTEXT IrpContext
2501 Routine Description:
2503 This routine is called to create and initialize the non-paged portion
2510 PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created.
2515 PFCB_NONPAGED FcbNonpaged
;
2520 // Allocate the non-paged pool and initialize the various
2521 // synchronization objects.
2524 FcbNonpaged
= CdAllocateFcbNonpaged( IrpContext
);
2526 if (FcbNonpaged
!= NULL
) {
2528 RtlZeroMemory( FcbNonpaged
, sizeof( FCB_NONPAGED
));
2530 FcbNonpaged
->NodeTypeCode
= CDFS_NTC_FCB_NONPAGED
;
2531 FcbNonpaged
->NodeByteSize
= sizeof( FCB_NONPAGED
);
2533 ExInitializeResourceLite( &FcbNonpaged
->FcbResource
);
2534 ExInitializeFastMutex( &FcbNonpaged
->FcbMutex
);
2542 // Local support routine
2546 CdDeleteFcbNonpaged (
2547 IN PIRP_CONTEXT IrpContext
,
2548 IN PFCB_NONPAGED FcbNonpaged
2553 Routine Description:
2555 This routine is called to cleanup the non-paged portion of an Fcb.
2559 FcbNonpaged - Structure to clean up.
2570 ExDeleteResourceLite( &FcbNonpaged
->FcbResource
);
2572 CdDeallocateFcbNonpaged( IrpContext
, FcbNonpaged
);
2579 // Local support routine
2582 RTL_GENERIC_COMPARE_RESULTS
2584 IN PRTL_GENERIC_TABLE FcbTable
,
2591 Routine Description:
2593 This routine is the Cdfs compare routine called by the generic table package.
2594 If will compare the two File Id values and return a comparison result.
2598 FcbTable - This is the table being searched.
2600 Fid1 - First key value.
2602 Fid2 - Second key value.
2606 RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
2615 Id1
= *((FILE_ID UNALIGNED
*) Fid1
);
2616 Id2
= *((FILE_ID UNALIGNED
*) Fid2
);
2618 if (Id1
.QuadPart
< Id2
.QuadPart
) {
2620 return GenericLessThan
;
2622 } else if (Id1
.QuadPart
> Id2
.QuadPart
) {
2624 return GenericGreaterThan
;
2628 return GenericEqual
;
2631 UNREFERENCED_PARAMETER( FcbTable
);
2636 // Local support routine
2640 CdAllocateFcbTable (
2641 IN PRTL_GENERIC_TABLE FcbTable
,
2647 Routine Description:
2649 This is a generic table support routine to allocate memory
2653 FcbTable - Supplies the generic table being used
2655 ByteSize - Supplies the number of bytes to allocate
2659 PVOID - Returns a pointer to the allocated data
2666 return( FsRtlAllocatePoolWithTag( CdPagedPool
, ByteSize
, TAG_FCB_TABLE
));
2671 // Local support routine
2675 CdDeallocateFcbTable (
2676 IN PRTL_GENERIC_TABLE FcbTable
,
2682 Routine Description:
2684 This is a generic table support routine that deallocates memory
2688 FcbTable - Supplies the generic table being used
2690 Buffer - Supplies the buffer being deallocated
2701 CdFreePool( &Buffer
);
2703 UNREFERENCED_PARAMETER( FcbTable
);
2708 // Local support routine
2713 IN PIRP_CONTEXT IrpContext
,
2714 IN PCDROM_TOC CdromToc
2719 Routine Description:
2721 This routine is called to generate a serial number for an audio disk.
2722 The number is based on the starting positions of the tracks.
2723 The following algorithm is used.
2725 If the number of tracks is <= 2 then initialize the serial number to the
2726 leadout block number.
2728 Then add the starting address of each track (use 0x00mmssff format).
2732 CdromToc - Valid table of contents to use for track information.
2736 ULONG - 32 bit serial number based on TOC.
2741 ULONG SerialNumber
= 0;
2742 PTRACK_DATA ThisTrack
;
2743 PTRACK_DATA LastTrack
;
2748 // Check if there are two tracks or fewer.
2751 LastTrack
= &CdromToc
->TrackData
[ CdromToc
->LastTrack
- CdromToc
->FirstTrack
+ 1];
2752 ThisTrack
= &CdromToc
->TrackData
[0];
2754 if (CdromToc
->LastTrack
- CdromToc
->FirstTrack
<= 1) {
2756 SerialNumber
= (((LastTrack
->Address
[1] * 60) + LastTrack
->Address
[2]) * 75) + LastTrack
->Address
[3];
2758 SerialNumber
-= (((ThisTrack
->Address
[1] * 60) + ThisTrack
->Address
[2]) * 75) + ThisTrack
->Address
[3];
2762 // Now find the starting offset of each track and add to the serial number.
2765 while (ThisTrack
!= LastTrack
) {
2767 SerialNumber
+= (ThisTrack
->Address
[1] << 16);
2768 SerialNumber
+= (ThisTrack
->Address
[2] << 8);
2769 SerialNumber
+= ThisTrack
->Address
[3];
2773 return SerialNumber
;