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).
1573 if (IrpSp
->DeviceObject
== CdData
.FileSystemDeviceObject
) {
1575 if (IrpSp
->FileObject
!= NULL
&&
1576 IrpSp
->MajorFunction
!= IRP_MJ_CREATE
&&
1577 IrpSp
->MajorFunction
!= IRP_MJ_CLEANUP
&&
1578 IrpSp
->MajorFunction
!= IRP_MJ_CLOSE
) {
1580 ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST
);
1583 ASSERT( IrpSp
->FileObject
!= NULL
||
1585 (IrpSp
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
&&
1586 IrpSp
->MinorFunction
== IRP_MN_USER_FS_REQUEST
&&
1587 IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_INVALIDATE_VOLUMES
) ||
1589 (IrpSp
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
&&
1590 IrpSp
->MinorFunction
== IRP_MN_MOUNT_VOLUME
) ||
1592 IrpSp
->MajorFunction
== IRP_MJ_SHUTDOWN
);
1596 // Look in our lookaside list for an IrpContext.
1599 if (CdData
.IrpContextDepth
) {
1602 NewIrpContext
= (PIRP_CONTEXT
) PopEntryList( &CdData
.IrpContextList
);
1603 if (NewIrpContext
!= NULL
) {
1605 CdData
.IrpContextDepth
--;
1611 if (NewIrpContext
== NULL
) {
1614 // We didn't get it from our private list so allocate it from pool.
1617 NewIrpContext
= FsRtlAllocatePoolWithTag( NonPagedPool
, sizeof( IRP_CONTEXT
), TAG_IRP_CONTEXT
);
1620 RtlZeroMemory( NewIrpContext
, sizeof( IRP_CONTEXT
));
1623 // Set the proper node type code and node byte size
1626 NewIrpContext
->NodeTypeCode
= CDFS_NTC_IRP_CONTEXT
;
1627 NewIrpContext
->NodeByteSize
= sizeof( IRP_CONTEXT
);
1630 // Set the originating Irp field
1633 NewIrpContext
->Irp
= Irp
;
1636 // Copy RealDevice for workque algorithms. We will update this in the Mount or
1637 // Verify since they have no file objects to use here.
1640 if (IrpSp
->FileObject
!= NULL
) {
1642 NewIrpContext
->RealDevice
= IrpSp
->FileObject
->DeviceObject
;
1646 // Locate the volume device object and Vcb that we are trying to access.
1647 // This may be our filesystem device object. In that case don't initialize
1651 if (IrpSp
->DeviceObject
!= CdData
.FileSystemDeviceObject
) {
1653 NewIrpContext
->Vcb
= &((PVOLUME_DEVICE_OBJECT
) IrpSp
->DeviceObject
)->Vcb
;
1658 // Major/Minor Function codes
1661 NewIrpContext
->MajorFunction
= IrpSp
->MajorFunction
;
1662 NewIrpContext
->MinorFunction
= IrpSp
->MinorFunction
;
1665 // Set the wait parameter
1670 SetFlag( NewIrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1674 SetFlag( NewIrpContext
->Flags
, IRP_CONTEXT_FLAG_FORCE_POST
);
1678 // return and tell the caller
1681 return NewIrpContext
;
1686 CdCleanupIrpContext (
1687 IN PIRP_CONTEXT IrpContext
,
1693 Routine Description:
1695 This routine is called to cleanup and possibly deallocate the Irp Context.
1696 If the request is being posted or this Irp Context is possibly on the
1697 stack then we only cleanup any auxiliary structures.
1701 Post - TRUE if we are posting this request, FALSE if we are deleting
1702 or retrying this in the current thread.
1714 // If we aren't doing more processing then deallocate this as appropriate.
1717 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_MORE_PROCESSING
)) {
1720 // If this context is the top level CDFS context then we need to
1721 // restore the top level thread context.
1724 if (IrpContext
->ThreadContext
!= NULL
) {
1726 CdRestoreThreadContext( IrpContext
);
1730 // Deallocate the Io context if allocated.
1733 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ALLOC_IO
)) {
1735 CdFreeIoContext( IrpContext
->IoContext
);
1739 // Deallocate the IrpContext if not from the stack.
1742 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ON_STACK
)) {
1744 if (CdData
.IrpContextDepth
< CdData
.IrpContextMaxDepth
) {
1748 PushEntryList( &CdData
.IrpContextList
, (PSINGLE_LIST_ENTRY
) IrpContext
);
1749 CdData
.IrpContextDepth
++;
1756 // We couldn't add this to our lookaside list so free it to
1760 CdFreePool( &IrpContext
);
1765 // Clear the appropriate flags.
1771 // If this context is the top level CDFS context then we need to
1772 // restore the top level thread context.
1775 if (IrpContext
->ThreadContext
!= NULL
) {
1777 CdRestoreThreadContext( IrpContext
);
1780 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAGS_CLEAR_ON_POST
);
1784 ClearFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY
);
1792 CdInitializeStackIrpContext (
1793 OUT PIRP_CONTEXT IrpContext
,
1794 IN PIRP_CONTEXT_LITE IrpContextLite
1799 Routine Description:
1801 This routine is called to initialize an IrpContext for the current
1802 CDFS request. The IrpContext is on the stack and we need to initialize
1803 it for the current request. The request is a close operation.
1807 IrpContext - IrpContext to initialize.
1809 IrpContextLite - Structure containing the details of this request.
1821 // Zero and then initialize the structure.
1824 RtlZeroMemory( IrpContext
, sizeof( IRP_CONTEXT
));
1827 // Set the proper node type code and node byte size
1830 IrpContext
->NodeTypeCode
= CDFS_NTC_IRP_CONTEXT
;
1831 IrpContext
->NodeByteSize
= sizeof( IRP_CONTEXT
);
1834 // Note that this is from the stack.
1837 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_ON_STACK
);
1840 // Copy RealDevice for workque algorithms.
1843 IrpContext
->RealDevice
= IrpContextLite
->RealDevice
;
1846 // The Vcb is found in the Fcb.
1849 IrpContext
->Vcb
= IrpContextLite
->Fcb
->Vcb
;
1852 // Major/Minor Function codes
1855 IrpContext
->MajorFunction
= IRP_MJ_CLOSE
;
1858 // Set the wait parameter
1861 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1868 CdTeardownStructures (
1869 IN PIRP_CONTEXT IrpContext
,
1870 IN PFCB StartingFcb
,
1871 OUT PBOOLEAN RemovedStartingFcb
1876 Routine Description:
1878 This routine is used to walk from some starting point in the Fcb tree towards
1879 the root. It will remove the Fcb and continue walking up the tree until
1880 it finds a point where we can't remove an Fcb.
1882 We look at the following fields in the Fcb to determine whether we can
1885 1 - Handle count must be zero.
1886 2 - If directory then only the only reference can be for a stream file.
1887 3 - Reference count must either be zero or go to zero here.
1889 We return immediately if we are recursively entering this routine.
1893 StartingFcb - This is the Fcb node in the tree to begin with. This Fcb
1894 must currently be acquired exclusively.
1896 RemovedStartingFcb - Address to store whether we removed the starting Fcb.
1905 PVCB Vcb
= StartingFcb
->Vcb
;
1906 PFCB CurrentFcb
= StartingFcb
;
1907 BOOLEAN AcquiredCurrentFcb
= FALSE
;
1912 *RemovedStartingFcb
= FALSE
;
1915 // If this is a recursive call to TearDownStructures we return immediately
1916 // doing no operation.
1919 if (FlagOn( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
)) {
1924 SetFlag( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
);
1927 // Use a try-finally to safely clear the top-level field.
1933 // Loop until we find an Fcb we can't remove.
1939 // See if there is an internal stream we should delete.
1940 // Only do this if it is the last reference on the Fcb.
1943 if ((SafeNodeType( CurrentFcb
) != CDFS_NTC_FCB_DATA
) &&
1944 (CurrentFcb
->FcbUserReference
== 0) &&
1945 (CurrentFcb
->FileObject
!= NULL
)) {
1948 // Go ahead and delete the stream file object.
1951 CdDeleteInternalStream( IrpContext
, CurrentFcb
);
1955 // If the reference count is non-zero then break.
1958 if (CurrentFcb
->FcbReference
!= 0) {
1964 // It looks like we have a candidate for removal here. We
1965 // will need to acquire the parent, if present, in order to
1966 // remove this from the parent prefix table.
1969 ParentFcb
= CurrentFcb
->ParentFcb
;
1971 if (ParentFcb
!= NULL
) {
1973 CdAcquireFcbExclusive( IrpContext
, ParentFcb
, FALSE
);
1977 // Now lock the vcb.
1980 CdLockVcb( IrpContext
, Vcb
);
1983 // Final check to see if the reference count is still zero.
1986 if (CurrentFcb
->FcbReference
!= 0) {
1988 CdUnlockVcb( IrpContext
, Vcb
);
1990 if (ParentFcb
!= NULL
) {
1992 CdReleaseFcb( IrpContext
, ParentFcb
);
1999 // If there is a parent then do the necessary cleanup for the parent.
2002 if (ParentFcb
!= NULL
) {
2004 CdRemovePrefix( IrpContext
, CurrentFcb
);
2005 RemoveEntryList( &CurrentFcb
->FcbLinks
);
2007 CdDecrementReferenceCounts( IrpContext
, ParentFcb
, 1, 1 );
2010 if (FlagOn( CurrentFcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
)) {
2012 CdDeleteFcbTable( IrpContext
, CurrentFcb
);
2013 ClearFlag( CurrentFcb
->FcbState
, FCB_STATE_IN_FCB_TABLE
);
2018 // Unlock the Vcb but hold the parent in order to walk up
2022 CdUnlockVcb( IrpContext
, Vcb
);
2023 CdDeleteFcb( IrpContext
, CurrentFcb
);
2026 // Move to the parent Fcb.
2029 CurrentFcb
= ParentFcb
;
2030 AcquiredCurrentFcb
= TRUE
;
2032 } while (CurrentFcb
!= NULL
);
2037 // Release the current Fcb if we have acquired it.
2040 if (AcquiredCurrentFcb
&& (CurrentFcb
!= NULL
)) {
2042 CdReleaseFcb( IrpContext
, CurrentFcb
);
2046 // Clear the teardown flag.
2049 ClearFlag( IrpContext
->TopLevel
->Flags
, IRP_CONTEXT_FLAG_IN_TEARDOWN
);
2052 *RemovedStartingFcb
= (CurrentFcb
!= StartingFcb
);
2059 IN PIRP_CONTEXT IrpContext
,
2066 Routine Description:
2068 This routine will look through the Fcb table looking for a matching
2073 Vcb - Vcb for this volume.
2075 FileId - This is the key value to use for the search.
2079 PFCB - A pointer to the matching entry or NULL otherwise.
2084 FCB_TABLE_ELEMENT Key
;
2085 PFCB_TABLE_ELEMENT Hit
;
2086 PFCB ReturnFcb
= NULL
;
2090 Key
.FileId
= FileId
;
2092 Hit
= (PFCB_TABLE_ELEMENT
) RtlLookupElementGenericTable( &Vcb
->FcbTable
, &Key
);
2096 ReturnFcb
= Hit
->Fcb
;
2101 UNREFERENCED_PARAMETER( IrpContext
);
2107 IN PIRP_CONTEXT IrpContext
,
2109 IN PVOID
*RestartKey
2114 Routine Description:
2116 This routine will enumerate through all of the Fcb's in the Fcb table.
2120 Vcb - Vcb for this volume.
2122 RestartKey - This value is used by the table package to maintain
2123 its position in the enumeration. It is initialized to NULL
2124 for the first search.
2128 PFCB - A pointer to the next fcb or NULL if the enumeration is
2138 Fcb
= (PFCB
) RtlEnumerateGenericTableWithoutSplaying( &Vcb
->FcbTable
, RestartKey
);
2142 Fcb
= ((PFCB_TABLE_ELEMENT
)(Fcb
))->Fcb
;
2151 IN PIRP_CONTEXT IrpContext
,
2152 IN PDEVICE_OBJECT TargetDeviceObject
,
2153 IN PCDROM_TOC CdromToc
,
2154 IN OUT PULONG Length
,
2155 OUT PULONG TrackCount
,
2156 OUT PULONG DiskFlags
2161 Routine Description:
2163 This routine is called to verify and process the TOC for this disk.
2164 We hide a data track for a CD+ volume.
2168 TargetDeviceObject - Device object to send TOC request to.
2170 CdromToc - Pointer to TOC structure.
2172 Length - On input this is the length of the TOC. On return is the TOC
2173 length we will show to the user.
2175 TrackCount - This is the count of tracks for the TOC. We use this
2176 when creating a pseudo directory for a music disk.
2178 DiskFlags - We return flags indicating what we know about this disk.
2182 NTSTATUS - The result of trying to read the TOC.
2188 IO_STATUS_BLOCK Iosb
;
2191 ULONG LocalTrackCount
;
2192 ULONG LocalTocLength
;
2206 // Go ahead and read the table of contents
2209 Status
= CdPerformDevIoCtrl( IrpContext
,
2210 IOCTL_CDROM_READ_TOC
,
2213 sizeof( CDROM_TOC
),
2219 // Nothing to process if this request fails.
2222 if (Status
!= STATUS_SUCCESS
) {
2228 // Get the number of tracks and stated size of this structure.
2232 LocalTrackCount
= CdromToc
->LastTrack
- CdromToc
->FirstTrack
+ 1;
2233 LocalTocLength
= PtrOffset( CdromToc
, &CdromToc
->TrackData
[LocalTrackCount
+ 1] );
2236 // Get out if there is an immediate problem with the TOC.
2239 if ((LocalTocLength
> Iosb
.Information
) ||
2240 (CdromToc
->FirstTrack
> CdromToc
->LastTrack
)) {
2242 Status
= STATUS_DISK_CORRUPT_ERROR
;
2247 // Walk through the individual tracks. Stop at the first data track after
2248 // any lead-in audio tracks.
2254 // Get the next track.
2257 Track
= &CdromToc
->TrackData
[CurrentTrack
];
2260 // If this is a data track then check if we have only seen audio tracks
2264 if (FlagOn( Track
->Control
, TOC_DATA_TRACK
)) {
2267 // If we have only seen audio tracks then assume this is a
2268 // CD+ disk. Hide the current data track and only return
2269 // the previous audio tracks. Set the disk type to be mixed
2273 if (FlagOn( *DiskFlags
, CDROM_DISK_AUDIO_TRACK
) &&
2274 !FlagOn( *DiskFlags
, CDROM_DISK_DATA_TRACK
)) {
2277 // Remove one track from the TOC.
2280 CdromToc
->LastTrack
-= 1;
2283 // Knock 2.5 minutes off the current track to
2284 // hide the final leadin.
2287 Track
->Address
[1] -= 2;
2288 Track
->Address
[2] += 30;
2290 if (Track
->Address
[2] < 60) {
2292 Track
->Address
[1] -= 1;
2296 Track
->Address
[2] -= 60;
2299 Track
->TrackNumber
= TOC_LAST_TRACK
;
2302 // Set the disk type to mixed data/audio.
2305 SetFlag( *DiskFlags
, CDROM_DISK_DATA_TRACK
);
2311 // Set the flag to indicate data tracks present.
2314 SetFlag( *DiskFlags
, CDROM_DISK_DATA_TRACK
);
2317 // If this is a audio track then set the flag indicating audio
2323 SetFlag( *DiskFlags
, CDROM_DISK_AUDIO_TRACK
);
2327 // Set our index for the next track.
2332 } while (CurrentTrack
< LocalTrackCount
);
2335 // Set the length to point just past the last track we looked at.
2338 *TrackCount
= CurrentTrack
;
2339 *Length
= PtrOffset( CdromToc
, &CdromToc
->TrackData
[CurrentTrack
+ 1] );
2340 BiasedTocLength
.Length
= (USHORT
) *Length
- 2;
2342 CdromToc
->Length
[0] = BiasedTocLength
.BigEndian
[1];
2343 CdromToc
->Length
[1] = BiasedTocLength
.BigEndian
[0];
2350 // Local support routine
2355 IN PIRP_CONTEXT IrpContext
,
2361 Routine Description:
2363 This routine is called to cleanup and deallocate an Fcb. We know there
2364 are no references remaining. We cleanup any auxiliary structures and
2365 deallocate this Fcb.
2369 Fcb - This is the Fcb to deallocate.
2382 // Sanity check the counts.
2385 ASSERT( Fcb
->FcbCleanup
== 0 );
2386 ASSERT( Fcb
->FcbReference
== 0 );
2389 // Release any Filter Context structures associated with this FCB
2392 FsRtlTeardownPerStreamContexts( &Fcb
->Header
);
2395 // Start with the common structures.
2398 CdUninitializeMcb( IrpContext
, Fcb
);
2400 CdDeleteFcbNonpaged( IrpContext
, Fcb
->FcbNonpaged
);
2403 // Check if we need to deallocate the prefix name buffer.
2406 if ((Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
!= (PWCHAR
) Fcb
->FileNamePrefix
.FileNameBuffer
) &&
2407 (Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
!= NULL
)) {
2409 CdFreePool( &Fcb
->FileNamePrefix
.ExactCaseName
.FileName
.Buffer
);
2413 // Now look at the short name prefix.
2416 if (Fcb
->ShortNamePrefix
!= NULL
) {
2418 CdFreePool( &Fcb
->ShortNamePrefix
);
2422 // Now do the type specific structures.
2425 switch (Fcb
->NodeTypeCode
) {
2427 case CDFS_NTC_FCB_PATH_TABLE
:
2428 case CDFS_NTC_FCB_INDEX
:
2430 ASSERT( Fcb
->FileObject
== NULL
);
2431 ASSERT( IsListEmpty( &Fcb
->FcbQueue
));
2433 if (Fcb
== Fcb
->Vcb
->RootIndexFcb
) {
2436 Vcb
->RootIndexFcb
= NULL
;
2438 } else if (Fcb
== Fcb
->Vcb
->PathTableFcb
) {
2441 Vcb
->PathTableFcb
= NULL
;
2444 CdDeallocateFcbIndex( IrpContext
, Fcb
);
2447 case CDFS_NTC_FCB_DATA
:
2449 if (Fcb
->FileLock
!= NULL
) {
2451 FsRtlFreeFileLock( Fcb
->FileLock
);
2454 FsRtlUninitializeOplock( &Fcb
->Oplock
);
2456 if (Fcb
== Fcb
->Vcb
->VolumeDasdFcb
) {
2459 Vcb
->VolumeDasdFcb
= NULL
;
2462 CdDeallocateFcbData( IrpContext
, Fcb
);
2466 // Decrement the Vcb reference count if this is a system
2472 InterlockedDecrement( &Vcb
->VcbReference
);
2473 InterlockedDecrement( &Vcb
->VcbUserReference
);
2481 // Local support routine
2485 CdCreateFcbNonpaged (
2486 IN PIRP_CONTEXT IrpContext
2491 Routine Description:
2493 This routine is called to create and initialize the non-paged portion
2500 PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created.
2505 PFCB_NONPAGED FcbNonpaged
;
2510 // Allocate the non-paged pool and initialize the various
2511 // synchronization objects.
2514 FcbNonpaged
= CdAllocateFcbNonpaged( IrpContext
);
2516 if (FcbNonpaged
!= NULL
) {
2518 RtlZeroMemory( FcbNonpaged
, sizeof( FCB_NONPAGED
));
2520 FcbNonpaged
->NodeTypeCode
= CDFS_NTC_FCB_NONPAGED
;
2521 FcbNonpaged
->NodeByteSize
= sizeof( FCB_NONPAGED
);
2523 ExInitializeResourceLite( &FcbNonpaged
->FcbResource
);
2524 ExInitializeFastMutex( &FcbNonpaged
->FcbMutex
);
2532 // Local support routine
2536 CdDeleteFcbNonpaged (
2537 IN PIRP_CONTEXT IrpContext
,
2538 IN PFCB_NONPAGED FcbNonpaged
2543 Routine Description:
2545 This routine is called to cleanup the non-paged portion of an Fcb.
2549 FcbNonpaged - Structure to clean up.
2560 ExDeleteResourceLite( &FcbNonpaged
->FcbResource
);
2562 CdDeallocateFcbNonpaged( IrpContext
, FcbNonpaged
);
2569 // Local support routine
2572 RTL_GENERIC_COMPARE_RESULTS
2574 IN PRTL_GENERIC_TABLE FcbTable
,
2581 Routine Description:
2583 This routine is the Cdfs compare routine called by the generic table package.
2584 If will compare the two File Id values and return a comparison result.
2588 FcbTable - This is the table being searched.
2590 Fid1 - First key value.
2592 Fid2 - Second key value.
2596 RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
2605 Id1
= *((FILE_ID UNALIGNED
*) Fid1
);
2606 Id2
= *((FILE_ID UNALIGNED
*) Fid2
);
2608 if (Id1
.QuadPart
< Id2
.QuadPart
) {
2610 return GenericLessThan
;
2612 } else if (Id1
.QuadPart
> Id2
.QuadPart
) {
2614 return GenericGreaterThan
;
2618 return GenericEqual
;
2621 UNREFERENCED_PARAMETER( FcbTable
);
2626 // Local support routine
2630 CdAllocateFcbTable (
2631 IN PRTL_GENERIC_TABLE FcbTable
,
2637 Routine Description:
2639 This is a generic table support routine to allocate memory
2643 FcbTable - Supplies the generic table being used
2645 ByteSize - Supplies the number of bytes to allocate
2649 PVOID - Returns a pointer to the allocated data
2656 return( FsRtlAllocatePoolWithTag( CdPagedPool
, ByteSize
, TAG_FCB_TABLE
));
2661 // Local support routine
2665 CdDeallocateFcbTable (
2666 IN PRTL_GENERIC_TABLE FcbTable
,
2672 Routine Description:
2674 This is a generic table support routine that deallocates memory
2678 FcbTable - Supplies the generic table being used
2680 Buffer - Supplies the buffer being deallocated
2691 CdFreePool( &Buffer
);
2693 UNREFERENCED_PARAMETER( FcbTable
);
2698 // Local support routine
2703 IN PIRP_CONTEXT IrpContext
,
2704 IN PCDROM_TOC CdromToc
2709 Routine Description:
2711 This routine is called to generate a serial number for an audio disk.
2712 The number is based on the starting positions of the tracks.
2713 The following algorithm is used.
2715 If the number of tracks is <= 2 then initialize the serial number to the
2716 leadout block number.
2718 Then add the starting address of each track (use 0x00mmssff format).
2722 CdromToc - Valid table of contents to use for track information.
2726 ULONG - 32 bit serial number based on TOC.
2731 ULONG SerialNumber
= 0;
2732 PTRACK_DATA ThisTrack
;
2733 PTRACK_DATA LastTrack
;
2738 // Check if there are two tracks or fewer.
2741 LastTrack
= &CdromToc
->TrackData
[ CdromToc
->LastTrack
- CdromToc
->FirstTrack
+ 1];
2742 ThisTrack
= &CdromToc
->TrackData
[0];
2744 if (CdromToc
->LastTrack
- CdromToc
->FirstTrack
<= 1) {
2746 SerialNumber
= (((LastTrack
->Address
[1] * 60) + LastTrack
->Address
[2]) * 75) + LastTrack
->Address
[3];
2748 SerialNumber
-= (((ThisTrack
->Address
[1] * 60) + ThisTrack
->Address
[2]) * 75) + ThisTrack
->Address
[3];
2752 // Now find the starting offset of each track and add to the serial number.
2755 while (ThisTrack
!= LastTrack
) {
2757 SerialNumber
+= (ThisTrack
->Address
[1] << 16);
2758 SerialNumber
+= (ThisTrack
->Address
[2] << 8);
2759 SerialNumber
+= ThisTrack
->Address
[3];
2763 return SerialNumber
;