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