[CDFS_NEW]
[reactos.git] / 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 #ifndef __REACTOS__
1574 if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject) {
1575 #else
1576 if (IrpSp->DeviceObject == CdData.FileSystemDeviceObject ||
1577 IrpSp->DeviceObject == CdData.HddFileSystemDeviceObject) {
1578 #endif
1579
1580 if (IrpSp->FileObject != NULL &&
1581 IrpSp->MajorFunction != IRP_MJ_CREATE &&
1582 IrpSp->MajorFunction != IRP_MJ_CLEANUP &&
1583 IrpSp->MajorFunction != IRP_MJ_CLOSE) {
1584
1585 ExRaiseStatus( STATUS_INVALID_DEVICE_REQUEST );
1586 }
1587
1588 ASSERT( IrpSp->FileObject != NULL ||
1589
1590 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
1591 IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST &&
1592 IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) ||
1593
1594 (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
1595 IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME ) ||
1596
1597 IrpSp->MajorFunction == IRP_MJ_SHUTDOWN );
1598 }
1599
1600 //
1601 // Look in our lookaside list for an IrpContext.
1602 //
1603
1604 if (CdData.IrpContextDepth) {
1605
1606 CdLockCdData();
1607 NewIrpContext = (PIRP_CONTEXT) PopEntryList( &CdData.IrpContextList );
1608 if (NewIrpContext != NULL) {
1609
1610 CdData.IrpContextDepth--;
1611 }
1612
1613 CdUnlockCdData();
1614 }
1615
1616 if (NewIrpContext == NULL) {
1617
1618 //
1619 // We didn't get it from our private list so allocate it from pool.
1620 //
1621
1622 NewIrpContext = FsRtlAllocatePoolWithTag( NonPagedPool, sizeof( IRP_CONTEXT ), TAG_IRP_CONTEXT );
1623 }
1624
1625 RtlZeroMemory( NewIrpContext, sizeof( IRP_CONTEXT ));
1626
1627 //
1628 // Set the proper node type code and node byte size
1629 //
1630
1631 NewIrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
1632 NewIrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
1633
1634 //
1635 // Set the originating Irp field
1636 //
1637
1638 NewIrpContext->Irp = Irp;
1639
1640 //
1641 // Copy RealDevice for workque algorithms. We will update this in the Mount or
1642 // Verify since they have no file objects to use here.
1643 //
1644
1645 if (IrpSp->FileObject != NULL) {
1646
1647 NewIrpContext->RealDevice = IrpSp->FileObject->DeviceObject;
1648 }
1649
1650 //
1651 // Locate the volume device object and Vcb that we are trying to access.
1652 // This may be our filesystem device object. In that case don't initialize
1653 // the Vcb field.
1654 //
1655
1656 #ifndef __REACTOS__
1657 if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject) {
1658 #else
1659 if (IrpSp->DeviceObject != CdData.FileSystemDeviceObject &&
1660 IrpSp->DeviceObject != CdData.HddFileSystemDeviceObject) {
1661 #endif
1662
1663 NewIrpContext->Vcb = &((PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject)->Vcb;
1664
1665 }
1666
1667 //
1668 // Major/Minor Function codes
1669 //
1670
1671 NewIrpContext->MajorFunction = IrpSp->MajorFunction;
1672 NewIrpContext->MinorFunction = IrpSp->MinorFunction;
1673
1674 //
1675 // Set the wait parameter
1676 //
1677
1678 if (Wait) {
1679
1680 SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
1681
1682 } else {
1683
1684 SetFlag( NewIrpContext->Flags, IRP_CONTEXT_FLAG_FORCE_POST );
1685 }
1686
1687 //
1688 // return and tell the caller
1689 //
1690
1691 return NewIrpContext;
1692 }
1693
1694 \f
1695 VOID
1696 CdCleanupIrpContext (
1697 IN PIRP_CONTEXT IrpContext,
1698 IN BOOLEAN Post
1699 )
1700
1701 /*++
1702
1703 Routine Description:
1704
1705 This routine is called to cleanup and possibly deallocate the Irp Context.
1706 If the request is being posted or this Irp Context is possibly on the
1707 stack then we only cleanup any auxiliary structures.
1708
1709 Arguments:
1710
1711 Post - TRUE if we are posting this request, FALSE if we are deleting
1712 or retrying this in the current thread.
1713
1714 Return Value:
1715
1716 None.
1717
1718 --*/
1719
1720 {
1721 PAGED_CODE();
1722
1723 //
1724 // If we aren't doing more processing then deallocate this as appropriate.
1725 //
1726
1727 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING)) {
1728
1729 //
1730 // If this context is the top level CDFS context then we need to
1731 // restore the top level thread context.
1732 //
1733
1734 if (IrpContext->ThreadContext != NULL) {
1735
1736 CdRestoreThreadContext( IrpContext );
1737 }
1738
1739 //
1740 // Deallocate the Io context if allocated.
1741 //
1742
1743 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO )) {
1744
1745 CdFreeIoContext( IrpContext->IoContext );
1746 }
1747
1748 //
1749 // Deallocate the IrpContext if not from the stack.
1750 //
1751
1752 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK )) {
1753
1754 if (CdData.IrpContextDepth < CdData.IrpContextMaxDepth) {
1755
1756 CdLockCdData();
1757
1758 PushEntryList( &CdData.IrpContextList, (PSINGLE_LIST_ENTRY) IrpContext );
1759 CdData.IrpContextDepth++;
1760
1761 CdUnlockCdData();
1762
1763 } else {
1764
1765 //
1766 // We couldn't add this to our lookaside list so free it to
1767 // pool.
1768 //
1769
1770 CdFreePool( &IrpContext );
1771 }
1772 }
1773
1774 //
1775 // Clear the appropriate flags.
1776 //
1777
1778 } else if (Post) {
1779
1780 //
1781 // If this context is the top level CDFS context then we need to
1782 // restore the top level thread context.
1783 //
1784
1785 if (IrpContext->ThreadContext != NULL) {
1786
1787 CdRestoreThreadContext( IrpContext );
1788 }
1789
1790 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_POST );
1791
1792 } else {
1793
1794 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAGS_CLEAR_ON_RETRY );
1795 }
1796
1797 return;
1798 }
1799
1800 \f
1801 VOID
1802 CdInitializeStackIrpContext (
1803 OUT PIRP_CONTEXT IrpContext,
1804 IN PIRP_CONTEXT_LITE IrpContextLite
1805 )
1806
1807 /*++
1808
1809 Routine Description:
1810
1811 This routine is called to initialize an IrpContext for the current
1812 CDFS request. The IrpContext is on the stack and we need to initialize
1813 it for the current request. The request is a close operation.
1814
1815 Arguments:
1816
1817 IrpContext - IrpContext to initialize.
1818
1819 IrpContextLite - Structure containing the details of this request.
1820
1821 Return Value:
1822
1823 None
1824
1825 --*/
1826
1827 {
1828 PAGED_CODE();
1829
1830 //
1831 // Zero and then initialize the structure.
1832 //
1833
1834 RtlZeroMemory( IrpContext, sizeof( IRP_CONTEXT ));
1835
1836 //
1837 // Set the proper node type code and node byte size
1838 //
1839
1840 IrpContext->NodeTypeCode = CDFS_NTC_IRP_CONTEXT;
1841 IrpContext->NodeByteSize = sizeof( IRP_CONTEXT );
1842
1843 //
1844 // Note that this is from the stack.
1845 //
1846
1847 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ON_STACK );
1848
1849 //
1850 // Copy RealDevice for workque algorithms.
1851 //
1852
1853 IrpContext->RealDevice = IrpContextLite->RealDevice;
1854
1855 //
1856 // The Vcb is found in the Fcb.
1857 //
1858
1859 IrpContext->Vcb = IrpContextLite->Fcb->Vcb;
1860
1861 //
1862 // Major/Minor Function codes
1863 //
1864
1865 IrpContext->MajorFunction = IRP_MJ_CLOSE;
1866
1867 //
1868 // Set the wait parameter
1869 //
1870
1871 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
1872
1873 return;
1874 }
1875
1876 \f
1877 VOID
1878 CdTeardownStructures (
1879 IN PIRP_CONTEXT IrpContext,
1880 IN PFCB StartingFcb,
1881 OUT PBOOLEAN RemovedStartingFcb
1882 )
1883
1884 /*++
1885
1886 Routine Description:
1887
1888 This routine is used to walk from some starting point in the Fcb tree towards
1889 the root. It will remove the Fcb and continue walking up the tree until
1890 it finds a point where we can't remove an Fcb.
1891
1892 We look at the following fields in the Fcb to determine whether we can
1893 remove this.
1894
1895 1 - Handle count must be zero.
1896 2 - If directory then only the only reference can be for a stream file.
1897 3 - Reference count must either be zero or go to zero here.
1898
1899 We return immediately if we are recursively entering this routine.
1900
1901 Arguments:
1902
1903 StartingFcb - This is the Fcb node in the tree to begin with. This Fcb
1904 must currently be acquired exclusively.
1905
1906 RemovedStartingFcb - Address to store whether we removed the starting Fcb.
1907
1908 Return Value:
1909
1910 None
1911
1912 --*/
1913
1914 {
1915 PVCB Vcb = StartingFcb->Vcb;
1916 PFCB CurrentFcb = StartingFcb;
1917 BOOLEAN AcquiredCurrentFcb = FALSE;
1918 PFCB ParentFcb;
1919
1920 PAGED_CODE();
1921
1922 *RemovedStartingFcb = FALSE;
1923
1924 //
1925 // If this is a recursive call to TearDownStructures we return immediately
1926 // doing no operation.
1927 //
1928
1929 if (FlagOn( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN )) {
1930
1931 return;
1932 }
1933
1934 SetFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
1935
1936 //
1937 // Use a try-finally to safely clear the top-level field.
1938 //
1939
1940 try {
1941
1942 //
1943 // Loop until we find an Fcb we can't remove.
1944 //
1945
1946 do {
1947
1948 //
1949 // See if there is an internal stream we should delete.
1950 // Only do this if it is the last reference on the Fcb.
1951 //
1952
1953 if ((SafeNodeType( CurrentFcb ) != CDFS_NTC_FCB_DATA) &&
1954 (CurrentFcb->FcbUserReference == 0) &&
1955 (CurrentFcb->FileObject != NULL)) {
1956
1957 //
1958 // Go ahead and delete the stream file object.
1959 //
1960
1961 CdDeleteInternalStream( IrpContext, CurrentFcb );
1962 }
1963
1964 //
1965 // If the reference count is non-zero then break.
1966 //
1967
1968 if (CurrentFcb->FcbReference != 0) {
1969
1970 break;
1971 }
1972
1973 //
1974 // It looks like we have a candidate for removal here. We
1975 // will need to acquire the parent, if present, in order to
1976 // remove this from the parent prefix table.
1977 //
1978
1979 ParentFcb = CurrentFcb->ParentFcb;
1980
1981 if (ParentFcb != NULL) {
1982
1983 CdAcquireFcbExclusive( IrpContext, ParentFcb, FALSE );
1984 }
1985
1986 //
1987 // Now lock the vcb.
1988 //
1989
1990 CdLockVcb( IrpContext, Vcb );
1991
1992 //
1993 // Final check to see if the reference count is still zero.
1994 //
1995
1996 if (CurrentFcb->FcbReference != 0) {
1997
1998 CdUnlockVcb( IrpContext, Vcb );
1999
2000 if (ParentFcb != NULL) {
2001
2002 CdReleaseFcb( IrpContext, ParentFcb );
2003 }
2004
2005 break;
2006 }
2007
2008 //
2009 // If there is a parent then do the necessary cleanup for the parent.
2010 //
2011
2012 if (ParentFcb != NULL) {
2013
2014 CdRemovePrefix( IrpContext, CurrentFcb );
2015 RemoveEntryList( &CurrentFcb->FcbLinks );
2016
2017 CdDecrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
2018 }
2019
2020 if (FlagOn( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE )) {
2021
2022 CdDeleteFcbTable( IrpContext, CurrentFcb );
2023 ClearFlag( CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE );
2024
2025 }
2026
2027 //
2028 // Unlock the Vcb but hold the parent in order to walk up
2029 // the tree.
2030 //
2031
2032 CdUnlockVcb( IrpContext, Vcb );
2033 CdDeleteFcb( IrpContext, CurrentFcb );
2034
2035 //
2036 // Move to the parent Fcb.
2037 //
2038
2039 CurrentFcb = ParentFcb;
2040 AcquiredCurrentFcb = TRUE;
2041
2042 } while (CurrentFcb != NULL);
2043
2044 } finally {
2045
2046 //
2047 // Release the current Fcb if we have acquired it.
2048 //
2049
2050 if (AcquiredCurrentFcb && (CurrentFcb != NULL)) {
2051
2052 CdReleaseFcb( IrpContext, CurrentFcb );
2053 }
2054
2055 //
2056 // Clear the teardown flag.
2057 //
2058
2059 ClearFlag( IrpContext->TopLevel->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN );
2060 }
2061
2062 *RemovedStartingFcb = (CurrentFcb != StartingFcb);
2063 return;
2064 }
2065
2066 \f
2067 PFCB
2068 CdLookupFcbTable (
2069 IN PIRP_CONTEXT IrpContext,
2070 IN PVCB Vcb,
2071 IN FILE_ID FileId
2072 )
2073
2074 /*++
2075
2076 Routine Description:
2077
2078 This routine will look through the Fcb table looking for a matching
2079 entry.
2080
2081 Arguments:
2082
2083 Vcb - Vcb for this volume.
2084
2085 FileId - This is the key value to use for the search.
2086
2087 Return Value:
2088
2089 PFCB - A pointer to the matching entry or NULL otherwise.
2090
2091 --*/
2092
2093 {
2094 FCB_TABLE_ELEMENT Key;
2095 PFCB_TABLE_ELEMENT Hit;
2096 PFCB ReturnFcb = NULL;
2097
2098 PAGED_CODE();
2099
2100 Key.FileId = FileId;
2101
2102 Hit = (PFCB_TABLE_ELEMENT) RtlLookupElementGenericTable( &Vcb->FcbTable, &Key );
2103
2104 if (Hit != NULL) {
2105
2106 ReturnFcb = Hit->Fcb;
2107 }
2108
2109 return ReturnFcb;
2110
2111 UNREFERENCED_PARAMETER( IrpContext );
2112 }
2113
2114 \f
2115 PFCB
2116 CdGetNextFcb (
2117 IN PIRP_CONTEXT IrpContext,
2118 IN PVCB Vcb,
2119 IN PVOID *RestartKey
2120 )
2121
2122 /*++
2123
2124 Routine Description:
2125
2126 This routine will enumerate through all of the Fcb's in the Fcb table.
2127
2128 Arguments:
2129
2130 Vcb - Vcb for this volume.
2131
2132 RestartKey - This value is used by the table package to maintain
2133 its position in the enumeration. It is initialized to NULL
2134 for the first search.
2135
2136 Return Value:
2137
2138 PFCB - A pointer to the next fcb or NULL if the enumeration is
2139 completed
2140
2141 --*/
2142
2143 {
2144 PFCB Fcb;
2145
2146 PAGED_CODE();
2147
2148 Fcb = (PFCB) RtlEnumerateGenericTableWithoutSplaying( &Vcb->FcbTable, RestartKey );
2149
2150 if (Fcb != NULL) {
2151
2152 Fcb = ((PFCB_TABLE_ELEMENT)(Fcb))->Fcb;
2153 }
2154
2155 return Fcb;
2156 }
2157
2158 \f
2159 NTSTATUS
2160 CdProcessToc (
2161 IN PIRP_CONTEXT IrpContext,
2162 IN PDEVICE_OBJECT TargetDeviceObject,
2163 IN PCDROM_TOC CdromToc,
2164 IN OUT PULONG Length,
2165 OUT PULONG TrackCount,
2166 OUT PULONG DiskFlags
2167 )
2168
2169 /*++
2170
2171 Routine Description:
2172
2173 This routine is called to verify and process the TOC for this disk.
2174 We hide a data track for a CD+ volume.
2175
2176 Arguments:
2177
2178 TargetDeviceObject - Device object to send TOC request to.
2179
2180 CdromToc - Pointer to TOC structure.
2181
2182 Length - On input this is the length of the TOC. On return is the TOC
2183 length we will show to the user.
2184
2185 TrackCount - This is the count of tracks for the TOC. We use this
2186 when creating a pseudo directory for a music disk.
2187
2188 DiskFlags - We return flags indicating what we know about this disk.
2189
2190 Return Value:
2191
2192 NTSTATUS - The result of trying to read the TOC.
2193
2194 --*/
2195
2196 {
2197 NTSTATUS Status;
2198 IO_STATUS_BLOCK Iosb;
2199
2200 ULONG CurrentTrack;
2201 ULONG LocalTrackCount;
2202 ULONG LocalTocLength;
2203
2204 union {
2205
2206 UCHAR BigEndian[2];
2207 USHORT Length;
2208
2209 } BiasedTocLength;
2210
2211 PTRACK_DATA Track;
2212
2213 PAGED_CODE();
2214
2215 //
2216 // Go ahead and read the table of contents
2217 //
2218
2219 Status = CdPerformDevIoCtrl( IrpContext,
2220 IOCTL_CDROM_READ_TOC,
2221 TargetDeviceObject,
2222 CdromToc,
2223 sizeof( CDROM_TOC ),
2224 FALSE,
2225 TRUE,
2226 &Iosb );
2227
2228 //
2229 // Nothing to process if this request fails.
2230 //
2231
2232 if (Status != STATUS_SUCCESS) {
2233
2234 return Status;
2235 }
2236
2237 //
2238 // Get the number of tracks and stated size of this structure.
2239 //
2240
2241 CurrentTrack = 0;
2242 LocalTrackCount = CdromToc->LastTrack - CdromToc->FirstTrack + 1;
2243 LocalTocLength = PtrOffset( CdromToc, &CdromToc->TrackData[LocalTrackCount + 1] );
2244
2245 //
2246 // Get out if there is an immediate problem with the TOC.
2247 //
2248
2249 if ((LocalTocLength > Iosb.Information) ||
2250 (CdromToc->FirstTrack > CdromToc->LastTrack)) {
2251
2252 Status = STATUS_DISK_CORRUPT_ERROR;
2253 return Status;
2254 }
2255
2256 //
2257 // Walk through the individual tracks. Stop at the first data track after
2258 // any lead-in audio tracks.
2259 //
2260
2261 do {
2262
2263 //
2264 // Get the next track.
2265 //
2266
2267 Track = &CdromToc->TrackData[CurrentTrack];
2268
2269 //
2270 // If this is a data track then check if we have only seen audio tracks
2271 // to this point.
2272 //
2273
2274 if (FlagOn( Track->Control, TOC_DATA_TRACK )) {
2275
2276 //
2277 // If we have only seen audio tracks then assume this is a
2278 // CD+ disk. Hide the current data track and only return
2279 // the previous audio tracks. Set the disk type to be mixed
2280 // data/audio.
2281 //
2282
2283 if (FlagOn( *DiskFlags, CDROM_DISK_AUDIO_TRACK ) &&
2284 !FlagOn( *DiskFlags, CDROM_DISK_DATA_TRACK )) {
2285
2286 //
2287 // Remove one track from the TOC.
2288 //
2289
2290 CdromToc->LastTrack -= 1;
2291
2292 //
2293 // Knock 2.5 minutes off the current track to
2294 // hide the final leadin.
2295 //
2296
2297 Track->Address[1] -= 2;
2298 Track->Address[2] += 30;
2299
2300 if (Track->Address[2] < 60) {
2301
2302 Track->Address[1] -= 1;
2303
2304 } else {
2305
2306 Track->Address[2] -= 60;
2307 }
2308
2309 Track->TrackNumber = TOC_LAST_TRACK;
2310
2311 //
2312 // Set the disk type to mixed data/audio.
2313 //
2314
2315 SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
2316
2317 break;
2318 }
2319
2320 //
2321 // Set the flag to indicate data tracks present.
2322 //
2323
2324 SetFlag( *DiskFlags, CDROM_DISK_DATA_TRACK );
2325
2326 //
2327 // If this is a audio track then set the flag indicating audio
2328 // tracks.
2329 //
2330
2331 } else {
2332
2333 SetFlag( *DiskFlags, CDROM_DISK_AUDIO_TRACK );
2334 }
2335
2336 //
2337 // Set our index for the next track.
2338 //
2339
2340 CurrentTrack += 1;
2341
2342 } while (CurrentTrack < LocalTrackCount);
2343
2344 //
2345 // Set the length to point just past the last track we looked at.
2346 //
2347
2348 *TrackCount = CurrentTrack;
2349 *Length = PtrOffset( CdromToc, &CdromToc->TrackData[CurrentTrack + 1] );
2350 BiasedTocLength.Length = (USHORT) *Length - 2;
2351
2352 CdromToc->Length[0] = BiasedTocLength.BigEndian[1];
2353 CdromToc->Length[1] = BiasedTocLength.BigEndian[0];
2354
2355 return Status;
2356 }
2357
2358 \f
2359 //
2360 // Local support routine
2361 //
2362
2363 VOID
2364 CdDeleteFcb (
2365 IN PIRP_CONTEXT IrpContext,
2366 IN PFCB Fcb
2367 )
2368
2369 /*++
2370
2371 Routine Description:
2372
2373 This routine is called to cleanup and deallocate an Fcb. We know there
2374 are no references remaining. We cleanup any auxiliary structures and
2375 deallocate this Fcb.
2376
2377 Arguments:
2378
2379 Fcb - This is the Fcb to deallocate.
2380
2381 Return Value:
2382
2383 None
2384
2385 --*/
2386
2387 {
2388 PVCB Vcb = NULL;
2389 PAGED_CODE();
2390
2391 //
2392 // Sanity check the counts.
2393 //
2394
2395 ASSERT( Fcb->FcbCleanup == 0 );
2396 ASSERT( Fcb->FcbReference == 0 );
2397
2398 //
2399 // Release any Filter Context structures associated with this FCB
2400 //
2401
2402 FsRtlTeardownPerStreamContexts( &Fcb->Header );
2403
2404 //
2405 // Start with the common structures.
2406 //
2407
2408 CdUninitializeMcb( IrpContext, Fcb );
2409
2410 CdDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged );
2411
2412 //
2413 // Check if we need to deallocate the prefix name buffer.
2414 //
2415
2416 if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) Fcb->FileNamePrefix.FileNameBuffer) &&
2417 (Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) {
2418
2419 CdFreePool( &Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer );
2420 }
2421
2422 //
2423 // Now look at the short name prefix.
2424 //
2425
2426 if (Fcb->ShortNamePrefix != NULL) {
2427
2428 CdFreePool( &Fcb->ShortNamePrefix );
2429 }
2430
2431 //
2432 // Now do the type specific structures.
2433 //
2434
2435 switch (Fcb->NodeTypeCode) {
2436
2437 case CDFS_NTC_FCB_PATH_TABLE:
2438 case CDFS_NTC_FCB_INDEX:
2439
2440 ASSERT( Fcb->FileObject == NULL );
2441 ASSERT( IsListEmpty( &Fcb->FcbQueue ));
2442
2443 if (Fcb == Fcb->Vcb->RootIndexFcb) {
2444
2445 Vcb = Fcb->Vcb;
2446 Vcb->RootIndexFcb = NULL;
2447
2448 } else if (Fcb == Fcb->Vcb->PathTableFcb) {
2449
2450 Vcb = Fcb->Vcb;
2451 Vcb->PathTableFcb = NULL;
2452 }
2453
2454 CdDeallocateFcbIndex( IrpContext, Fcb );
2455 break;
2456
2457 case CDFS_NTC_FCB_DATA :
2458
2459 if (Fcb->FileLock != NULL) {
2460
2461 FsRtlFreeFileLock( Fcb->FileLock );
2462 }
2463
2464 FsRtlUninitializeOplock( &Fcb->Oplock );
2465
2466 if (Fcb == Fcb->Vcb->VolumeDasdFcb) {
2467
2468 Vcb = Fcb->Vcb;
2469 Vcb->VolumeDasdFcb = NULL;
2470 }
2471
2472 CdDeallocateFcbData( IrpContext, Fcb );
2473 }
2474
2475 //
2476 // Decrement the Vcb reference count if this is a system
2477 // Fcb.
2478 //
2479
2480 if (Vcb != NULL) {
2481
2482 InterlockedDecrement( &Vcb->VcbReference );
2483 InterlockedDecrement( &Vcb->VcbUserReference );
2484 }
2485
2486 return;
2487 }
2488
2489 \f
2490 //
2491 // Local support routine
2492 //
2493
2494 PFCB_NONPAGED
2495 CdCreateFcbNonpaged (
2496 IN PIRP_CONTEXT IrpContext
2497 )
2498
2499 /*++
2500
2501 Routine Description:
2502
2503 This routine is called to create and initialize the non-paged portion
2504 of an Fcb.
2505
2506 Arguments:
2507
2508 Return Value:
2509
2510 PFCB_NONPAGED - Pointer to the created nonpaged Fcb. NULL if not created.
2511
2512 --*/
2513
2514 {
2515 PFCB_NONPAGED FcbNonpaged;
2516
2517 PAGED_CODE();
2518
2519 //
2520 // Allocate the non-paged pool and initialize the various
2521 // synchronization objects.
2522 //
2523
2524 FcbNonpaged = CdAllocateFcbNonpaged( IrpContext );
2525
2526 if (FcbNonpaged != NULL) {
2527
2528 RtlZeroMemory( FcbNonpaged, sizeof( FCB_NONPAGED ));
2529
2530 FcbNonpaged->NodeTypeCode = CDFS_NTC_FCB_NONPAGED;
2531 FcbNonpaged->NodeByteSize = sizeof( FCB_NONPAGED );
2532
2533 ExInitializeResourceLite( &FcbNonpaged->FcbResource );
2534 ExInitializeFastMutex( &FcbNonpaged->FcbMutex );
2535 }
2536
2537 return FcbNonpaged;
2538 }
2539
2540 \f
2541 //
2542 // Local support routine
2543 //
2544
2545 VOID
2546 CdDeleteFcbNonpaged (
2547 IN PIRP_CONTEXT IrpContext,
2548 IN PFCB_NONPAGED FcbNonpaged
2549 )
2550
2551 /*++
2552
2553 Routine Description:
2554
2555 This routine is called to cleanup the non-paged portion of an Fcb.
2556
2557 Arguments:
2558
2559 FcbNonpaged - Structure to clean up.
2560
2561 Return Value:
2562
2563 None
2564
2565 --*/
2566
2567 {
2568 PAGED_CODE();
2569
2570 ExDeleteResourceLite( &FcbNonpaged->FcbResource );
2571
2572 CdDeallocateFcbNonpaged( IrpContext, FcbNonpaged );
2573
2574 return;
2575 }
2576
2577 \f
2578 //
2579 // Local support routine
2580 //
2581
2582 RTL_GENERIC_COMPARE_RESULTS
2583 CdFcbTableCompare (
2584 IN PRTL_GENERIC_TABLE FcbTable,
2585 IN PVOID Fid1,
2586 IN PVOID Fid2
2587 )
2588
2589 /*++
2590
2591 Routine Description:
2592
2593 This routine is the Cdfs compare routine called by the generic table package.
2594 If will compare the two File Id values and return a comparison result.
2595
2596 Arguments:
2597
2598 FcbTable - This is the table being searched.
2599
2600 Fid1 - First key value.
2601
2602 Fid2 - Second key value.
2603
2604 Return Value:
2605
2606 RTL_GENERIC_COMPARE_RESULTS - The results of comparing the two
2607 input structures
2608
2609 --*/
2610
2611 {
2612 FILE_ID Id1, Id2;
2613 PAGED_CODE();
2614
2615 Id1 = *((FILE_ID UNALIGNED *) Fid1);
2616 Id2 = *((FILE_ID UNALIGNED *) Fid2);
2617
2618 if (Id1.QuadPart < Id2.QuadPart) {
2619
2620 return GenericLessThan;
2621
2622 } else if (Id1.QuadPart > Id2.QuadPart) {
2623
2624 return GenericGreaterThan;
2625
2626 } else {
2627
2628 return GenericEqual;
2629 }
2630
2631 UNREFERENCED_PARAMETER( FcbTable );
2632 }
2633
2634 \f
2635 //
2636 // Local support routine
2637 //
2638
2639 PVOID
2640 CdAllocateFcbTable (
2641 IN PRTL_GENERIC_TABLE FcbTable,
2642 IN CLONG ByteSize
2643 )
2644
2645 /*++
2646
2647 Routine Description:
2648
2649 This is a generic table support routine to allocate memory
2650
2651 Arguments:
2652
2653 FcbTable - Supplies the generic table being used
2654
2655 ByteSize - Supplies the number of bytes to allocate
2656
2657 Return Value:
2658
2659 PVOID - Returns a pointer to the allocated data
2660
2661 --*/
2662
2663 {
2664 PAGED_CODE();
2665
2666 return( FsRtlAllocatePoolWithTag( CdPagedPool, ByteSize, TAG_FCB_TABLE ));
2667 }
2668
2669 \f
2670 //
2671 // Local support routine
2672 //
2673
2674 VOID
2675 CdDeallocateFcbTable (
2676 IN PRTL_GENERIC_TABLE FcbTable,
2677 IN PVOID Buffer
2678 )
2679
2680 /*++
2681
2682 Routine Description:
2683
2684 This is a generic table support routine that deallocates memory
2685
2686 Arguments:
2687
2688 FcbTable - Supplies the generic table being used
2689
2690 Buffer - Supplies the buffer being deallocated
2691
2692 Return Value:
2693
2694 None.
2695
2696 --*/
2697
2698 {
2699 PAGED_CODE();
2700
2701 CdFreePool( &Buffer );
2702
2703 UNREFERENCED_PARAMETER( FcbTable );
2704 }
2705
2706 \f
2707 //
2708 // Local support routine
2709 //
2710
2711 ULONG
2712 CdTocSerial (
2713 IN PIRP_CONTEXT IrpContext,
2714 IN PCDROM_TOC CdromToc
2715 )
2716
2717 /*++
2718
2719 Routine Description:
2720
2721 This routine is called to generate a serial number for an audio disk.
2722 The number is based on the starting positions of the tracks.
2723 The following algorithm is used.
2724
2725 If the number of tracks is <= 2 then initialize the serial number to the
2726 leadout block number.
2727
2728 Then add the starting address of each track (use 0x00mmssff format).
2729
2730 Arguments:
2731
2732 CdromToc - Valid table of contents to use for track information.
2733
2734 Return Value:
2735
2736 ULONG - 32 bit serial number based on TOC.
2737
2738 --*/
2739
2740 {
2741 ULONG SerialNumber = 0;
2742 PTRACK_DATA ThisTrack;
2743 PTRACK_DATA LastTrack;
2744
2745 PAGED_CODE();
2746
2747 //
2748 // Check if there are two tracks or fewer.
2749 //
2750
2751 LastTrack = &CdromToc->TrackData[ CdromToc->LastTrack - CdromToc->FirstTrack + 1];
2752 ThisTrack = &CdromToc->TrackData[0];
2753
2754 if (CdromToc->LastTrack - CdromToc->FirstTrack <= 1) {
2755
2756 SerialNumber = (((LastTrack->Address[1] * 60) + LastTrack->Address[2]) * 75) + LastTrack->Address[3];
2757
2758 SerialNumber -= (((ThisTrack->Address[1] * 60) + ThisTrack->Address[2]) * 75) + ThisTrack->Address[3];
2759 }
2760
2761 //
2762 // Now find the starting offset of each track and add to the serial number.
2763 //
2764
2765 while (ThisTrack != LastTrack) {
2766
2767 SerialNumber += (ThisTrack->Address[1] << 16);
2768 SerialNumber += (ThisTrack->Address[2] << 8);
2769 SerialNumber += ThisTrack->Address[3];
2770 ThisTrack += 1;
2771 }
2772
2773 return SerialNumber;
2774 }
2775
2776