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