[CDFS_NEW] Fix headers inclusion so that it can work on a *nix platform
[reactos.git] / drivers / filesystems / cdfs_new / dirsup.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 DirSup.c
8
9 Abstract:
10
11 This module implements the dirent support routines for Cdfs.
12
13 Directories on a CD consist of a number of contiguous sectors on
14 the disk. File descriptors consist of one or more directory entries
15 (dirents) within a directory. Files may contain version numbers. If
16 present all like-named files will be ordered contiguously in the
17 directory by decreasing version numbers. We will only return the
18 first of these on a directory query unless the user explicitly
19 asks for version numbers. Finally dirents will not span sector
20 boundaries. Unused bytes at the end of a sector will be zero
21 filled.
22
23 Directory sector: Offset
24 2048
25 +---------------------------------------------------------------+
26 | | | | | | |
27 | foo;4 | foo;4 | foo;3 | hat | zebra | Zero|
28 | | | | | | Fill|
29 | | final | single | | | |
30 | | extent | extent | | | |
31 +---------------------------------------------------------------+
32
33 Dirent operations:
34
35 - Position scan at known offset in directory. Dirent at this
36 offset must exist and is valid. Used when scanning a directory
37 from the beginning when the self entry is known to be valid.
38 Used when positioning at the first dirent for an open
39 file to scan the allocation information. Used when resuming
40 a directory enumeration from a valid directory entry.
41
42 - Position scan at known offset in directory. Dirent is known to
43 start at this position but must be checked for validity.
44 Used to read the self-directory entry.
45
46 - Move to the next dirent within a directory.
47
48 - Given a known starting dirent, collect all the dirents for
49 that file. Scan will finish positioned at the last dirent
50 for the file. We will accumulate the extent lengths to
51 find the size of the file.
52
53 - Given a known starting dirent, position the scan for the first
54 dirent of the following file. Used when not interested in
55 all of the details for the current file and are looking for
56 the next file.
57
58 - Update a common dirent structure with the details of the on-disk
59 structure. This is used to smooth out the differences
60
61 - Build the filename (name and version strings) out of the stream
62 of bytes in the file name on disk. For Joliet disks we will have
63 to convert to little endian.
64
65
66 --*/
67
68 #include "cdprocs.h"
69
70 //
71 // The Bug check file id for this module
72 //
73
74 #define BugCheckFileId (CDFS_BUG_CHECK_DIRSUP)
75
76 //
77 // Local macros
78 //
79
80 //
81 // PRAW_DIRENT
82 // CdRawDirent (
83 // IN PIRP_CONTEXT IrpContext,
84 // IN PDIR_ENUM_CONTEXT DirContext
85 // );
86 //
87
88 #define CdRawDirent(IC,DC) \
89 Add2Ptr( (DC)->Sector, (DC)->SectorOffset, PRAW_DIRENT )
90
91 //
92 // Local support routines
93 //
94
95 ULONG
96 CdCheckRawDirentBounds (
97 IN PIRP_CONTEXT IrpContext,
98 IN PDIRENT_ENUM_CONTEXT DirContext
99 );
100
101 XA_EXTENT_TYPE
102 CdCheckForXAExtent (
103 IN PIRP_CONTEXT IrpContext,
104 IN PRAW_DIRENT RawDirent,
105 IN OUT PDIRENT Dirent
106 );
107
108 #ifdef ALLOC_PRAGMA
109 #pragma alloc_text(PAGE, CdCheckForXAExtent)
110 #pragma alloc_text(PAGE, CdCheckRawDirentBounds)
111 #pragma alloc_text(PAGE, CdCleanupFileContext)
112 #pragma alloc_text(PAGE, CdFindFile)
113 #pragma alloc_text(PAGE, CdFindDirectory)
114 #pragma alloc_text(PAGE, CdFindFileByShortName)
115 #pragma alloc_text(PAGE, CdLookupDirent)
116 #pragma alloc_text(PAGE, CdLookupLastFileDirent)
117 #pragma alloc_text(PAGE, CdLookupNextDirent)
118 #pragma alloc_text(PAGE, CdLookupNextInitialFileDirent)
119 #pragma alloc_text(PAGE, CdUpdateDirentFromRawDirent)
120 #pragma alloc_text(PAGE, CdUpdateDirentName)
121 #endif
122
123 \f
124 VOID
125 CdLookupDirent (
126 IN PIRP_CONTEXT IrpContext,
127 IN PFCB Fcb,
128 IN ULONG DirentOffset,
129 OUT PDIRENT_ENUM_CONTEXT DirContext
130 )
131
132 /*++
133
134 Routine Description:
135
136 This routine is called to initiate a walk through a directory. We will
137 position ourselves in the directory at offset DirentOffset. We know that
138 a dirent begins at this boundary but may have to verify the dirent bounds.
139 We will call this routine when looking up the first entry of a known
140 file or verifying the self entry of a directory.
141
142 Arguments:
143
144 Fcb - Fcb for the directory being traversed.
145
146 DirentOffset - This is our target point in the directory. We will map the
147 page containing this entry and possibly verify the dirent bounds at
148 this location.
149
150 DirContext - This is the dirent context for this scan. We update it with
151 the location of the dirent we found. This structure has been initialized
152 outside of this call.
153
154 Return Value:
155
156 None.
157
158 --*/
159
160 {
161 LONGLONG BaseOffset;
162
163 PAGED_CODE();
164
165 //
166 // Initialize the offset of the first dirent we want to map.
167 //
168
169 DirContext->BaseOffset = SectorTruncate( DirentOffset );
170 BaseOffset = DirContext->BaseOffset;
171
172 DirContext->DataLength = SECTOR_SIZE;
173
174 DirContext->SectorOffset = SectorOffset( DirentOffset );
175
176 //
177 // Truncate the data length if we are at the end of the file.
178 //
179
180 if (DirContext->DataLength > (Fcb->FileSize.QuadPart - BaseOffset)) {
181
182 DirContext->DataLength = (ULONG) (Fcb->FileSize.QuadPart - BaseOffset);
183 }
184
185 //
186 // Now map the data at this offset.
187 //
188
189 CcMapData( Fcb->FileObject,
190 (PLARGE_INTEGER) &BaseOffset,
191 DirContext->DataLength,
192 TRUE,
193 &DirContext->Bcb,
194 &DirContext->Sector );
195
196 //
197 // Verify the dirent bounds.
198 //
199
200 DirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
201 DirContext );
202
203 return;
204 }
205
206 \f
207 BOOLEAN
208 CdLookupNextDirent (
209 IN PIRP_CONTEXT IrpContext,
210 IN PFCB Fcb,
211 IN PDIRENT_ENUM_CONTEXT CurrentDirContext,
212 OUT PDIRENT_ENUM_CONTEXT NextDirContext
213 )
214
215 /*++
216
217 Routine Description:
218
219 This routine is called to find the next dirent in the directory. The
220 current position is given and we look for the next. We leave the context
221 for the starting position untouched and update the context for the
222 dirent we found. The target context may already be initialized so we
223 may already have the sector in memory.
224
225 This routine will position the enumeration context for the next dirent and
226 verify the dirent bounds.
227
228 NOTE - This routine can be called with CurrentDirContext and NextDirContext
229 pointing to the same enumeration context.
230
231 Arguments:
232
233 Fcb - Fcb for the directory being traversed.
234
235 CurrentDirContext - This is the dirent context for this scan. We update
236 it with the location of the dirent we found. This is currently
237 pointing to a dirent location. The dirent bounds at this location
238 have already been verified.
239
240 NextDirContext - This is the dirent context to update with the dirent we
241 find. This may already point to a dirent so we need to check if
242 we are in the same sector and unmap any buffer as necessary.
243
244 This dirent is left in an indeterminate state if we don't find a dirent.
245
246 Return Value:
247
248 BOOLEAN - TRUE if we find a location for the next dirent, FALSE otherwise.
249 This routine can cause a raise if the directory is corrupt.
250
251 --*/
252
253 {
254 LONGLONG CurrentBaseOffset = CurrentDirContext->BaseOffset;
255 ULONG TempUlong;
256
257 BOOLEAN FoundDirent = FALSE;
258
259 PAGED_CODE();
260
261 //
262 // Check if a different sector is mapped. If so then move our target
263 // enumeration context to the same sector.
264 //
265
266 if ((CurrentDirContext->BaseOffset != NextDirContext->BaseOffset) ||
267 (NextDirContext->Bcb == NULL)) {
268
269 //
270 // Unpin the current target Bcb and map the next sector.
271 //
272
273 CdUnpinData( IrpContext, &NextDirContext->Bcb );
274
275 CcMapData( Fcb->FileObject,
276 (PLARGE_INTEGER) &CurrentBaseOffset,
277 CurrentDirContext->DataLength,
278 TRUE,
279 &NextDirContext->Bcb,
280 &NextDirContext->Sector );
281
282 //
283 // Copy the data length and sector offset.
284 //
285
286 NextDirContext->DataLength = CurrentDirContext->DataLength;
287 NextDirContext->BaseOffset = CurrentDirContext->BaseOffset;
288 }
289
290 //
291 // Now move to the same offset in the sector.
292 //
293
294 NextDirContext->SectorOffset = CurrentDirContext->SectorOffset;
295
296 //
297 // If the value is zero then unmap the current sector and set up
298 // the base offset to the beginning of the next sector.
299 //
300
301 if (CurrentDirContext->NextDirentOffset == 0) {
302
303 CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;
304
305 //
306 // Unmap the current sector. We test the value of the Bcb in the
307 // loop below to see if we need to read in another sector.
308 //
309
310 CdUnpinData( IrpContext, &NextDirContext->Bcb );
311
312 //
313 // There is another possible dirent in the current sector. Update the
314 // enumeration context to reflect this.
315 //
316
317 } else {
318
319 NextDirContext->SectorOffset += CurrentDirContext->NextDirentOffset;
320 }
321
322 //
323 // Now loop until we find the next possible dirent or walk off the directory.
324 //
325
326 while (TRUE) {
327
328 //
329 // If we don't currently have a sector mapped then map the
330 // directory at the current offset.
331 //
332
333 if (NextDirContext->Bcb == NULL) {
334
335 TempUlong = SECTOR_SIZE;
336
337 if (TempUlong > (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset)) {
338
339 TempUlong = (ULONG) (Fcb->FileSize.QuadPart - CurrentBaseOffset);
340
341 //
342 // If the length is zero then there is no dirent.
343 //
344
345 if (TempUlong == 0) {
346
347 break;
348 }
349 }
350
351 CcMapData( Fcb->FileObject,
352 (PLARGE_INTEGER) &CurrentBaseOffset,
353 TempUlong,
354 TRUE,
355 &NextDirContext->Bcb,
356 &NextDirContext->Sector );
357
358 NextDirContext->BaseOffset = (ULONG) CurrentBaseOffset;
359 NextDirContext->SectorOffset = 0;
360 NextDirContext->DataLength = TempUlong;
361 }
362
363 //
364 // The CDFS spec allows for sectors in a directory to contain all zeroes.
365 // In this case we need to move to the next sector. So look at the
366 // current potential dirent for a zero length. Move to the next
367 // dirent if length is zero.
368 //
369
370 if (*((PCHAR) CdRawDirent( IrpContext, NextDirContext )) != 0) {
371
372 FoundDirent = TRUE;
373 break;
374 }
375
376 CurrentBaseOffset = NextDirContext->BaseOffset + NextDirContext->DataLength;
377 CdUnpinData( IrpContext, &NextDirContext->Bcb );
378 }
379
380 //
381 // Check the dirent bounds if we found a dirent.
382 //
383
384 if (FoundDirent) {
385
386 NextDirContext->NextDirentOffset = CdCheckRawDirentBounds( IrpContext,
387 NextDirContext );
388 }
389
390 return FoundDirent;
391 }
392
393 \f
394 VOID
395 CdUpdateDirentFromRawDirent (
396 IN PIRP_CONTEXT IrpContext,
397 IN PFCB Fcb,
398 IN PDIRENT_ENUM_CONTEXT DirContext,
399 IN OUT PDIRENT Dirent
400 )
401
402 /*++
403
404 Routine Description:
405
406 This routine is called to safely copy the data from the dirent on disk
407 to the in-memory dirent. The fields on disk are unaligned so we
408 need to safely copy them to our structure.
409
410 Arguments:
411
412 Fcb - Fcb for the directory being scanned.
413
414 DirContext - Enumeration context for the raw disk dirent.
415
416 Dirent - In-memory dirent to update.
417
418 Return Value:
419
420 None.
421
422 --*/
423
424 {
425 PRAW_DIRENT RawDirent = CdRawDirent( IrpContext, DirContext );
426
427 PAGED_CODE();
428
429 //
430 // Clear all of the current state flags except the flag indicating that
431 // we allocated a name string.
432 //
433
434 ClearFlag( Dirent->Flags, DIRENT_FLAG_NOT_PERSISTENT );
435
436 //
437 // The dirent offset is the sum of the start of the sector and the
438 // sector offset.
439 //
440
441 Dirent->DirentOffset = DirContext->BaseOffset + DirContext->SectorOffset;
442
443 //
444 // Copy the dirent length from the raw dirent.
445 //
446
447 Dirent->DirentLength = RawDirent->DirLen;
448
449 //
450 // The starting offset on disk is computed by finding the starting
451 // logical block and stepping over the Xar block.
452 //
453
454 CopyUchar4( &Dirent->StartingOffset, RawDirent->FileLoc );
455
456 Dirent->StartingOffset += RawDirent->XarLen;
457
458 //
459 // Do a safe copy to get the data length.
460 //
461
462 CopyUchar4( &Dirent->DataLength, RawDirent->DataLen );
463
464 //
465 // Save a pointer to the time stamps.
466 //
467
468 Dirent->CdTime = (PCHAR)RawDirent->RecordTime; /* ReactOS change: GCC "pointer targets in assignment differ in signedness" */
469
470 //
471 // Copy the dirent flags.
472 //
473
474 Dirent->DirentFlags = CdRawDirentFlags( IrpContext, RawDirent );
475
476 //
477 // For both the file unit and interleave skip we want to take the
478 // logical block count.
479 //
480
481 Dirent->FileUnitSize =
482 Dirent->InterleaveGapSize = 0;
483
484 if (RawDirent->IntLeaveSize != 0) {
485
486 Dirent->FileUnitSize = RawDirent->IntLeaveSize;
487 Dirent->InterleaveGapSize = RawDirent->IntLeaveSkip;
488 }
489
490 //
491 // Get the name length and remember a pointer to the start of the
492 // name string. We don't do any processing on the name at this
493 // point.
494 //
495 // Check that the name length is non-zero.
496 //
497
498 if (RawDirent->FileIdLen == 0) {
499
500 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
501 }
502
503 Dirent->FileNameLen = RawDirent->FileIdLen;
504 Dirent->FileName = (PCHAR)RawDirent->FileId; /* ReactOS change: GCC "pointer targets in assignment differ in signedness" */
505
506 //
507 // If there are any remaining bytes at the end of the dirent then
508 // there may be a system use area. We protect ourselves from
509 // disks which don't pad the dirent entries correctly by using
510 // a fudge factor of one. All system use areas must have a length
511 // greater than one. Don't bother with the system use area
512 // if this is a directory.
513 //
514
515 Dirent->XAAttributes = 0;
516 Dirent->XAFileNumber = 0;
517 Dirent->ExtentType = Form1Data;
518 Dirent->SystemUseOffset = 0;
519
520 if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY ) &&
521 (Dirent->DirentLength > ((FIELD_OFFSET( RAW_DIRENT, FileId ) + Dirent->FileNameLen) + 1))) {
522
523 Dirent->SystemUseOffset = WordAlign( FIELD_OFFSET( RAW_DIRENT, FileId ) + Dirent->FileNameLen );
524 }
525
526 return;
527 }
528
529 \f
530 VOID
531 CdUpdateDirentName (
532 IN PIRP_CONTEXT IrpContext,
533 IN OUT PDIRENT Dirent,
534 IN ULONG IgnoreCase
535 )
536
537 /*++
538
539 Routine Description:
540
541 This routine is called to update the name in the dirent with the name
542 from the disk. We will look for the special case of the self and
543 parent entries and also construct the Unicode name for the Joliet disk
544 in order to work around the BigEndian on-disk structure.
545
546 Arguments:
547
548 Dirent - Pointer to the in-memory dirent structure.
549
550 IgnoreCase - TRUE if we should build the upcased version. Otherwise we
551 use the exact case name.
552
553 Return Value:
554
555 None.
556
557 --*/
558
559 {
560 UCHAR DirectoryValue;
561 ULONG Length;
562
563 NTSTATUS Status;
564
565 PAGED_CODE();
566
567 //
568 // Check if this is a self or parent entry. There is no version number
569 // in these cases. We use a fixed string for these.
570 //
571 // Self-Entry - Length is 1, value is 0.
572 // Parent-Entry - Length is 1, value is 1.
573 //
574
575 if ((Dirent->FileNameLen == 1) &&
576 FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
577
578 DirectoryValue = *((PCHAR) Dirent->FileName);
579
580 if ((DirectoryValue == 0) || (DirectoryValue == 1)) {
581
582 //
583 // We should not have allocated a name by the time we see these cases.
584 // If we have, this means that the image is in violation of ISO 9660 7.6.2,
585 // which states that the ./.. entries must be the first two in the directory.
586 //
587
588 if (FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {
589
590 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
591 }
592
593 //
594 // Now use one of the hard coded directory names.
595 //
596
597 Dirent->CdFileName.FileName = CdUnicodeDirectoryNames[DirectoryValue];
598
599 //
600 // Show that there is no version number.
601 //
602
603 Dirent->CdFileName.VersionString.Length = 0;
604
605 //
606 // The case name is the same as the exact name.
607 //
608
609 Dirent->CdCaseFileName = Dirent->CdFileName;
610
611 //
612 // Mark this as a constant value entry.
613 //
614
615 SetFlag( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY );
616
617 //
618 // Return now.
619 //
620
621 return;
622 }
623 }
624
625 //
626 // Mark this as a non-constant value entry.
627 //
628
629 ClearFlag( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY );
630
631 //
632 // Compute how large a buffer we will need. If this is an ignore
633 // case operation then we will want a double size buffer. If the disk is not
634 // a Joliet disk then we might need two bytes for each byte in the name.
635 //
636
637 Length = Dirent->FileNameLen;
638
639 if (IgnoreCase) {
640
641 Length *= 2;
642 }
643
644 if (!FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
645
646 Length *= sizeof( WCHAR );
647 }
648
649 //
650 // Now decide if we need to allocate a new buffer. We will if
651 // this name won't fit in the embedded name buffer and it is
652 // larger than the current allocated buffer. We always use the
653 // allocated buffer if present.
654 //
655 // If we haven't allocated a buffer then use the embedded buffer if the data
656 // will fit. This is the typical case.
657 //
658
659 if (!FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER ) &&
660 (Length <= sizeof( Dirent->NameBuffer ))) {
661
662 Dirent->CdFileName.FileName.MaximumLength = sizeof( Dirent->NameBuffer );
663 Dirent->CdFileName.FileName.Buffer = Dirent->NameBuffer;
664
665 } else {
666
667 //
668 // We need to use an allocated buffer. Check if the current buffer
669 // is large enough.
670 //
671
672 if (Length > Dirent->CdFileName.FileName.MaximumLength) {
673
674 //
675 // Free any allocated buffer.
676 //
677
678 if (FlagOn( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER )) {
679
680 CdFreePool( &Dirent->CdFileName.FileName.Buffer );
681 ClearFlag( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER );
682 }
683
684 Dirent->CdFileName.FileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
685 Length,
686 TAG_DIRENT_NAME );
687
688 SetFlag( Dirent->Flags, DIRENT_FLAG_ALLOC_BUFFER );
689
690 Dirent->CdFileName.FileName.MaximumLength = (USHORT) Length;
691 }
692 }
693
694 //
695 // We now have a buffer for the name. We need to either convert the on-disk bigendian
696 // to little endian or covert the name to Unicode.
697 //
698
699 if (!FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
700
701 Status = RtlOemToUnicodeN( Dirent->CdFileName.FileName.Buffer,
702 Dirent->CdFileName.FileName.MaximumLength,
703 &Length,
704 Dirent->FileName,
705 Dirent->FileNameLen );
706
707 ASSERT( Status == STATUS_SUCCESS );
708 Dirent->CdFileName.FileName.Length = (USHORT) Length;
709
710 } else {
711
712 //
713 // Convert this string to little endian.
714 //
715
716 CdConvertBigToLittleEndian( IrpContext,
717 Dirent->FileName,
718 Dirent->FileNameLen,
719 (PCHAR) Dirent->CdFileName.FileName.Buffer );
720
721 Dirent->CdFileName.FileName.Length = (USHORT) Dirent->FileNameLen;
722 }
723
724 //
725 // Split the name into name and version strings.
726 //
727
728 CdConvertNameToCdName( IrpContext,
729 &Dirent->CdFileName );
730
731 //
732 // The name length better be non-zero.
733 //
734
735 if (Dirent->CdFileName.FileName.Length == 0) {
736
737 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
738 }
739
740 //
741 // If the filename ends with a period then back up one character.
742 //
743
744 if (Dirent->CdFileName.FileName.Buffer[(Dirent->CdFileName.FileName.Length - sizeof( WCHAR )) / 2] == L'.') {
745
746 //
747 // Slide the version string down.
748 //
749
750 if (Dirent->CdFileName.VersionString.Length != 0) {
751
752 PWCHAR NewVersion;
753
754 //
755 // Start from the position currently containing the separator.
756 //
757
758 NewVersion = Add2Ptr( Dirent->CdFileName.FileName.Buffer,
759 Dirent->CdFileName.FileName.Length,
760 PWCHAR );
761
762 //
763 // Now overwrite the period.
764 //
765
766 RtlMoveMemory( NewVersion - 1,
767 NewVersion,
768 Dirent->CdFileName.VersionString.Length + sizeof( WCHAR ));
769
770 //
771 // Now point to the new version string.
772 //
773
774 Dirent->CdFileName.VersionString.Buffer = NewVersion;
775 }
776
777 //
778 // Shrink the filename length.
779 //
780
781 Dirent->CdFileName.FileName.Length -= sizeof( WCHAR );
782 }
783
784 //
785 // If this an exact case operation then use the filename exactly.
786 //
787
788 if (!IgnoreCase) {
789
790 Dirent->CdCaseFileName = Dirent->CdFileName;
791
792 //
793 // Otherwise perform our upcase operation. We already have guaranteed the buffers are
794 // there.
795 //
796
797 } else {
798
799 Dirent->CdCaseFileName.FileName.Buffer = Add2Ptr( Dirent->CdFileName.FileName.Buffer,
800 Dirent->CdFileName.FileName.MaximumLength / 2,
801 PWCHAR);
802
803 Dirent->CdCaseFileName.FileName.MaximumLength = Dirent->CdFileName.FileName.MaximumLength / 2;
804
805 CdUpcaseName( IrpContext,
806 &Dirent->CdFileName,
807 &Dirent->CdCaseFileName );
808 }
809
810 return;
811 }
812
813 \f
814 BOOLEAN
815 CdFindFile (
816 IN PIRP_CONTEXT IrpContext,
817 IN PFCB Fcb,
818 IN PCD_NAME Name,
819 IN BOOLEAN IgnoreCase,
820 IN OUT PFILE_ENUM_CONTEXT FileContext,
821 OUT PCD_NAME *MatchingName
822 )
823
824 /*++
825
826 Routine Description:
827
828 This routine is called to search a directory for a file matching the input
829 name. This name has been upcased at this point if this a case-insensitive
830 search. The name has been separated into separate name and version strings.
831 We look for an exact match in the name and only consider the version if
832 there is a version specified in the search name.
833
834 Arguments:
835
836 Fcb - Fcb for the directory being scanned.
837
838 Name - Name to search for.
839
840 IgnoreCase - Indicates the case of the search.
841
842 FileContext - File context to use for the search. This has already been
843 initialized.
844
845 MatchingName - Pointer to buffer containing matching name. We need this
846 in case we don't match the name in the directory but match the
847 short name instead.
848
849 Return Value:
850
851 BOOLEAN - TRUE if matching entry is found, FALSE otherwise.
852
853 --*/
854
855 {
856 PDIRENT Dirent;
857 ULONG ShortNameDirentOffset;
858
859 BOOLEAN Found = FALSE;
860
861 PAGED_CODE();
862
863 //
864 // Make sure there is a stream file for this Fcb.
865 //
866
867 if (Fcb->FileObject == NULL) {
868
869 CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
870 }
871
872 //
873 // Check to see whether we need to check for a possible short name.
874 //
875
876 ShortNameDirentOffset = CdShortNameDirentOffset( IrpContext, &Name->FileName );
877
878 //
879 // Position ourselves at the first entry.
880 //
881
882 CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, Fcb->StreamOffset );
883
884 //
885 // Loop while there are more entries in this directory.
886 //
887
888 do {
889
890 Dirent = &FileContext->InitialDirent->Dirent;
891
892 //
893 // We only consider files which don't have the associated bit set.
894 // We also only look for files. All directories would already
895 // have been found.
896 //
897
898 if (!FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_ASSOC | CD_ATTRIBUTE_DIRECTORY )) {
899
900 //
901 // Update the name in the current dirent.
902 //
903
904 CdUpdateDirentName( IrpContext, Dirent, IgnoreCase );
905
906 //
907 // Don't bother with constant entries.
908 //
909
910 if (FlagOn( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
911
912 continue;
913 }
914
915 //
916 // Now check whether we have a name match.
917 // We exit the loop if we have a match.
918 //
919
920 if (CdIsNameInExpression( IrpContext,
921 &Dirent->CdCaseFileName,
922 Name,
923 0,
924 TRUE )) {
925
926 *MatchingName = &Dirent->CdCaseFileName;
927 Found = TRUE;
928 break;
929 }
930
931 //
932 // The names didn't match. If the input name is a possible short
933 // name and we are at the correct offset in the directory then
934 // check if the short names match.
935 //
936
937 if (((Dirent->DirentOffset >> SHORT_NAME_SHIFT) == ShortNameDirentOffset) &&
938 (Name->VersionString.Length == 0) &&
939 !CdIs8dot3Name( IrpContext,
940 Dirent->CdFileName.FileName )) {
941
942 //
943 // Create the short name and check for a match.
944 //
945
946 CdGenerate8dot3Name( IrpContext,
947 &Dirent->CdCaseFileName.FileName,
948 Dirent->DirentOffset,
949 FileContext->ShortName.FileName.Buffer,
950 &FileContext->ShortName.FileName.Length );
951
952 //
953 // Now check whether we have a name match.
954 // We exit the loop if we have a match.
955 //
956
957 if (CdIsNameInExpression( IrpContext,
958 &FileContext->ShortName,
959 Name,
960 0,
961 FALSE )) {
962
963 *MatchingName = &FileContext->ShortName,
964 Found = TRUE;
965 break;
966 }
967 }
968 }
969
970 //
971 // Go to the next initial dirent for a file.
972 //
973
974 } while (CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext ));
975
976 //
977 // If we find the file then collect all of the dirents.
978 //
979
980 if (Found) {
981
982 CdLookupLastFileDirent( IrpContext, Fcb, FileContext );
983
984 }
985
986 return Found;
987 }
988
989 \f
990 BOOLEAN
991 CdFindDirectory (
992 IN PIRP_CONTEXT IrpContext,
993 IN PFCB Fcb,
994 IN PCD_NAME Name,
995 IN BOOLEAN IgnoreCase,
996 IN OUT PFILE_ENUM_CONTEXT FileContext
997 )
998
999 /*++
1000
1001 Routine Description:
1002
1003 This routine is called to search a directory for a directory matching the input
1004 name. This name has been upcased at this point if this a case-insensitive
1005 search. We look for an exact match in the name and do not look for shortname
1006 equivalents.
1007
1008 Arguments:
1009
1010 Fcb - Fcb for the directory being scanned.
1011
1012 Name - Name to search for.
1013
1014 IgnoreCase - Indicates the case of the search.
1015
1016 FileContext - File context to use for the search. This has already been
1017 initialized.
1018
1019 Return Value:
1020
1021 BOOLEAN - TRUE if matching entry is found, FALSE otherwise.
1022
1023 --*/
1024
1025 {
1026 PDIRENT Dirent;
1027
1028 BOOLEAN Found = FALSE;
1029
1030 PAGED_CODE();
1031
1032 //
1033 // Make sure there is a stream file for this Fcb.
1034 //
1035
1036 if (Fcb->FileObject == NULL) {
1037
1038 CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
1039 }
1040
1041 //
1042 // Position ourselves at the first entry.
1043 //
1044
1045 CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, Fcb->StreamOffset );
1046
1047 //
1048 // Loop while there are more entries in this directory.
1049 //
1050
1051 do {
1052
1053 Dirent = &FileContext->InitialDirent->Dirent;
1054
1055 //
1056 // We only look for directories. Directories cannot have the
1057 // associated bit set.
1058 //
1059
1060 if (FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_DIRECTORY )) {
1061
1062 //
1063 // Update the name in the current dirent.
1064 //
1065
1066 CdUpdateDirentName( IrpContext, Dirent, IgnoreCase );
1067
1068 //
1069 // Don't bother with constant entries.
1070 //
1071
1072 if (FlagOn( Dirent->Flags, DIRENT_FLAG_CONSTANT_ENTRY )) {
1073
1074 continue;
1075 }
1076
1077 //
1078 // Now check whether we have a name match.
1079 // We exit the loop if we have a match.
1080 //
1081
1082 if (CdIsNameInExpression( IrpContext,
1083 &Dirent->CdCaseFileName,
1084 Name,
1085 0,
1086 TRUE )) {
1087
1088 Found = TRUE;
1089 break;
1090 }
1091 }
1092
1093 //
1094 // Go to the next initial dirent.
1095 //
1096
1097 } while (CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext ));
1098
1099 return Found;
1100 }
1101
1102 \f
1103 BOOLEAN
1104 CdFindFileByShortName (
1105 IN PIRP_CONTEXT IrpContext,
1106 IN PFCB Fcb,
1107 IN PCD_NAME Name,
1108 IN BOOLEAN IgnoreCase,
1109 IN ULONG ShortNameDirentOffset,
1110 IN OUT PFILE_ENUM_CONTEXT FileContext
1111 )
1112
1113 /*++
1114
1115 Routine Description:
1116
1117 This routine is called to find the file name entry whose short name
1118 is defined by the input DirentOffset. The dirent offset here is
1119 multiplied by 32 and we look for the dirent begins in this 32 byte offset in
1120 directory. The minimum dirent length is 34 so we are guaranteed that only
1121 one dirent can begin in each 32 byte block in the directory.
1122
1123 Arguments:
1124
1125 Fcb - Fcb for the directory being scanned.
1126
1127 Name - Name we are trying to match. We know this contains the tilde
1128 character followed by decimal characters.
1129
1130 IgnoreCase - Indicates whether we need to upcase the long name and
1131 generated short name.
1132
1133 ShortNameDirentOffset - This is the shifted value for the offset of the
1134 name in the directory.
1135
1136 FileContext - This is the initialized file context to use for the search.
1137
1138 Return Value:
1139
1140 BOOLEAN - TRUE if a matching name was found, FALSE otherwise.
1141
1142 --*/
1143
1144 {
1145 BOOLEAN Found = FALSE;
1146 PDIRENT Dirent;
1147
1148 ULONG ThisShortNameDirentOffset;
1149
1150 PAGED_CODE();
1151
1152 //
1153 // Make sure there is a stream file for this Fcb.
1154 //
1155
1156 if (Fcb->FileObject == NULL) {
1157
1158 CdCreateInternalStream( IrpContext, Fcb->Vcb, Fcb );
1159 }
1160
1161 //
1162 // Position ourselves at the start of the directory and update
1163 //
1164 //
1165
1166 CdLookupInitialFileDirent( IrpContext, Fcb, FileContext, Fcb->StreamOffset );
1167
1168 //
1169 // Loop until we have found the entry or are beyond this dirent.
1170 //
1171
1172 do {
1173
1174 //
1175 // Compute the short name dirent offset for the current dirent.
1176 //
1177
1178 Dirent = &FileContext->InitialDirent->Dirent;
1179 ThisShortNameDirentOffset = Dirent->DirentOffset >> SHORT_NAME_SHIFT;
1180
1181 //
1182 // If beyond the target then exit.
1183 //
1184
1185 if (ThisShortNameDirentOffset > ShortNameDirentOffset) {
1186
1187 break;
1188 }
1189
1190 //
1191 // If equal to the target then check if we have a name match.
1192 // We will either match or fail here.
1193 //
1194
1195 if (ThisShortNameDirentOffset == ShortNameDirentOffset) {
1196
1197 //
1198 // If this is an associated file then get out.
1199 //
1200
1201 if (FlagOn( Dirent->DirentFlags, CD_ATTRIBUTE_ASSOC )) {
1202
1203 break;
1204 }
1205
1206 //
1207 // Update the name in the dirent and check if it is not
1208 // an 8.3 name.
1209 //
1210
1211 CdUpdateDirentName( IrpContext, Dirent, IgnoreCase );
1212
1213 if (CdIs8dot3Name( IrpContext,
1214 Dirent->CdFileName.FileName )) {
1215
1216 break;
1217 }
1218
1219 //
1220 // Generate the 8.3 name see if it matches our input name.
1221 //
1222
1223 CdGenerate8dot3Name( IrpContext,
1224 &Dirent->CdCaseFileName.FileName,
1225 Dirent->DirentOffset,
1226 FileContext->ShortName.FileName.Buffer,
1227 &FileContext->ShortName.FileName.Length );
1228
1229 //
1230 // Check if this name matches.
1231 //
1232
1233 if (CdIsNameInExpression( IrpContext,
1234 Name,
1235 &FileContext->ShortName,
1236 0,
1237 FALSE )) {
1238
1239 //
1240 // Let our caller know we found an entry.
1241 //
1242
1243 Found = TRUE;
1244 }
1245
1246 //
1247 // Break out of the loop.
1248 //
1249
1250 break;
1251 }
1252
1253 //
1254 // Continue until there are no more entries.
1255 //
1256
1257 } while (CdLookupNextInitialFileDirent( IrpContext, Fcb, FileContext ));
1258
1259 //
1260 // If we find the file then collect all of the dirents.
1261 //
1262
1263 if (Found) {
1264
1265 CdLookupLastFileDirent( IrpContext, Fcb, FileContext );
1266
1267 }
1268
1269 return Found;
1270 }
1271
1272 \f
1273 BOOLEAN
1274 CdLookupNextInitialFileDirent (
1275 IN PIRP_CONTEXT IrpContext,
1276 IN PFCB Fcb,
1277 IN OUT PFILE_ENUM_CONTEXT FileContext
1278 )
1279
1280 /*++
1281
1282 Routine Description:
1283
1284 This routine is called to walk through the directory until we find the
1285 first possible dirent for file. We are positioned at some point described
1286 by the FileContext. We will walk through any remaining dirents for the
1287 current file until we find the first dirent for some subsequent file.
1288
1289 We can be called when we have found just one dirent for a file or all
1290 of them. We first check the CurrentDirContext. In the typical
1291 single-extent case this is unused. Then we look to the InitialDirContext
1292 which must be initialized.
1293
1294 This routine will save the initial DirContext to the PriorDirContext and
1295 clean up any existing DirContext for the Prior or Current positions in
1296 the enumeration context.
1297
1298 Arguments:
1299
1300 Fcb - This is the directory to scan.
1301
1302 FileContext - This is the file enumeration context. It is currently pointing
1303 at some file in the directory.
1304
1305 Return Value:
1306
1307 --*/
1308
1309 {
1310 PRAW_DIRENT RawDirent;
1311
1312 PDIRENT_ENUM_CONTEXT CurrentDirContext;
1313 PDIRENT_ENUM_CONTEXT TargetDirContext;
1314 PCOMPOUND_DIRENT TempDirent;
1315
1316 BOOLEAN FoundDirent = FALSE;
1317 BOOLEAN FoundLastDirent;
1318
1319 PAGED_CODE();
1320
1321 //
1322 // Start by saving the initial dirent of the current file as the
1323 // previous file.
1324 //
1325
1326 TempDirent = FileContext->PriorDirent;
1327 FileContext->PriorDirent = FileContext->InitialDirent;
1328 FileContext->InitialDirent = TempDirent;
1329
1330 //
1331 // We will use the initial dirent of the prior file unless the
1332 // previous search returned multiple extents.
1333 //
1334
1335 CurrentDirContext = &FileContext->PriorDirent->DirContext;
1336
1337 if (FlagOn( FileContext->Flags, FILE_CONTEXT_MULTIPLE_DIRENTS )) {
1338
1339 CurrentDirContext = &FileContext->CurrentDirent->DirContext;
1340 }
1341
1342 //
1343 // Clear all of the flags and file size for the next file.
1344 //
1345
1346 FileContext->Flags = 0;
1347 FileContext->FileSize = 0;
1348
1349 FileContext->ShortName.FileName.Length = 0;
1350
1351 //
1352 // We always want to store the result into the updated initial dirent
1353 // context.
1354 //
1355
1356 TargetDirContext = &FileContext->InitialDirent->DirContext;
1357
1358 //
1359 // Loop until we find the first dirent after the last dirent of the
1360 // current file. We may not be at the last dirent for the current file yet
1361 // so we may walk forward looking for the last and then find the
1362 // initial dirent for the next file after that.
1363 //
1364
1365 while (TRUE) {
1366
1367 //
1368 // Remember if the last dirent we visited was the last dirent for
1369 // a file.
1370 //
1371
1372 RawDirent = CdRawDirent( IrpContext, CurrentDirContext );
1373
1374 FoundLastDirent = !FlagOn( CdRawDirentFlags( IrpContext, RawDirent ), CD_ATTRIBUTE_MULTI );
1375
1376 //
1377 // Try to find another dirent.
1378 //
1379
1380 FoundDirent = CdLookupNextDirent( IrpContext,
1381 Fcb,
1382 CurrentDirContext,
1383 TargetDirContext );
1384
1385 //
1386 // Exit the loop if no entry found.
1387 //
1388
1389 if (!FoundDirent) {
1390
1391 break;
1392
1393 }
1394
1395 //
1396 // Update the in-memory dirent.
1397 //
1398
1399 CdUpdateDirentFromRawDirent( IrpContext,
1400 Fcb,
1401 TargetDirContext,
1402 &FileContext->InitialDirent->Dirent );
1403
1404 //
1405 // Exit the loop if we had the end for the previous file.
1406 //
1407
1408 if (FoundLastDirent) {
1409
1410 break;
1411 }
1412
1413 //
1414 // Always use a single dirent from this point on.
1415 //
1416
1417 CurrentDirContext = TargetDirContext;
1418 }
1419
1420 return FoundDirent;
1421 }
1422
1423 \f
1424 VOID
1425 CdLookupLastFileDirent (
1426 IN PIRP_CONTEXT IrpContext,
1427 IN PFCB Fcb,
1428 IN PFILE_ENUM_CONTEXT FileContext
1429 )
1430
1431 /*++
1432
1433 Routine Description:
1434
1435 This routine is called when we've found the matching initial dirent for
1436 a file. Now we want to find all of the dirents for a file as well as
1437 compute the running total for the file size.
1438
1439 We also go out to the system use area and check whether this is an
1440 XA sector. In that case we will compute the real file size.
1441
1442 The dirent in the initial compound dirent has been updated from the
1443 raw dirent when this routine is called.
1444
1445 Arguments:
1446
1447 Fcb - Directory containing the entries for the file.
1448
1449 FileContext - Enumeration context for this search. It currently points
1450 to the first dirent of the file and the in-memory dirent has been
1451 updated.
1452
1453 Return Value:
1454
1455 None. This routine may raise STATUS_FILE_CORRUPT.
1456
1457 --*/
1458
1459 {
1460 XA_EXTENT_TYPE ExtentType = 0; /* ReactOS Change: GCC Uninit var */
1461 PCOMPOUND_DIRENT CurrentCompoundDirent;
1462 PDIRENT CurrentDirent;
1463
1464 BOOLEAN FirstPass = TRUE;
1465 BOOLEAN FoundDirent;
1466
1467 PAGED_CODE();
1468
1469 //
1470 // The current dirent to look at is the initial dirent for the file.
1471 //
1472
1473 CurrentCompoundDirent = FileContext->InitialDirent;
1474
1475 //
1476 // Loop until we reach the last dirent for the file.
1477 //
1478
1479 while (TRUE) {
1480
1481 CurrentDirent = &CurrentCompoundDirent->Dirent;
1482
1483 //
1484 // Check if this extent has XA sectors.
1485 //
1486
1487 if ((CurrentDirent->SystemUseOffset != 0) &&
1488 FlagOn( Fcb->Vcb->VcbState, VCB_STATE_CDXA ) &&
1489 CdCheckForXAExtent( IrpContext,
1490 CdRawDirent( IrpContext, &CurrentCompoundDirent->DirContext ),
1491 CurrentDirent )) {
1492
1493 //
1494 // Any previous dirent must describe XA sectors as well.
1495 //
1496
1497 if (!FirstPass && (ExtentType != CurrentDirent->ExtentType)) {
1498
1499 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1500 }
1501
1502 //
1503 // If there are XA sectors then the data on the disk must
1504 // be correctly aligned on sectors and be an integral number of
1505 // sectors. Only an issue if the logical block size is not
1506 // 2048.
1507 //
1508
1509 if (Fcb->Vcb->BlockSize != SECTOR_SIZE) {
1510
1511 //
1512 // We will do the following checks.
1513 //
1514 // Data must start on a sector boundary.
1515 // Data length must be integral number of sectors.
1516 //
1517
1518 if ((SectorBlockOffset( Fcb->Vcb, CurrentDirent->StartingOffset ) != 0) ||
1519 (SectorBlockOffset( Fcb->Vcb, CurrentDirent->DataLength ) != 0)) {
1520
1521 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1522 }
1523
1524 //
1525 // If interleaved then both the file unit and interleave
1526 // gap must be integral number of sectors.
1527 //
1528
1529 if ((CurrentDirent->FileUnitSize != 0) &&
1530 ((SectorBlockOffset( Fcb->Vcb, CurrentDirent->FileUnitSize ) != 0) ||
1531 (SectorBlockOffset( Fcb->Vcb, CurrentDirent->InterleaveGapSize ) != 0))) {
1532
1533 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1534 }
1535 }
1536
1537 //
1538 // If this is the first dirent then add the bytes for the RIFF
1539 // header.
1540 //
1541
1542 if (FirstPass) {
1543
1544 FileContext->FileSize = sizeof( RIFF_HEADER );
1545 }
1546
1547 //
1548 // Add the size of the mode2-form2 sector for each sector
1549 // we have here.
1550 //
1551
1552 FileContext->FileSize += Int32x32To64( CurrentDirent->DataLength >> SECTOR_SHIFT,
1553 XA_SECTOR_SIZE);
1554
1555 } else {
1556
1557 //
1558 // This extent does not have XA sectors. Any previous dirent
1559 // better not have XA sectors.
1560 //
1561
1562 if (!FirstPass && (ExtentType != CurrentDirent->ExtentType)) {
1563
1564 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1565 }
1566
1567 //
1568 // Add these bytes to the file size.
1569 //
1570
1571 FileContext->FileSize += CurrentDirent->DataLength;
1572 }
1573
1574 //
1575 // If we are at the last dirent then exit.
1576 //
1577
1578 if (!FlagOn( CurrentDirent->DirentFlags, CD_ATTRIBUTE_MULTI )) {
1579
1580 break;
1581 }
1582
1583 //
1584 // Remember the extent type of the current extent.
1585 //
1586
1587 ExtentType = CurrentDirent->ExtentType;
1588
1589 //
1590 // Look for the next dirent of the file.
1591 //
1592
1593 FoundDirent = CdLookupNextDirent( IrpContext,
1594 Fcb,
1595 &CurrentCompoundDirent->DirContext,
1596 &FileContext->CurrentDirent->DirContext );
1597
1598 //
1599 // If we didn't find the entry then this is a corrupt directory.
1600 //
1601
1602 if (!FoundDirent) {
1603
1604 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1605 }
1606
1607 //
1608 // Remember the dirent we just found.
1609 //
1610
1611 CurrentCompoundDirent = FileContext->CurrentDirent;
1612 FirstPass = FALSE;
1613
1614 //
1615 // Look up all of the dirent information for the given dirent.
1616 //
1617
1618 CdUpdateDirentFromRawDirent( IrpContext,
1619 Fcb,
1620 &CurrentCompoundDirent->DirContext,
1621 &CurrentCompoundDirent->Dirent );
1622
1623 //
1624 // Set flag to show there were multiple extents.
1625 //
1626
1627 SetFlag( FileContext->Flags, FILE_CONTEXT_MULTIPLE_DIRENTS );
1628 }
1629
1630 return;
1631 }
1632
1633 \f
1634 VOID
1635 CdCleanupFileContext (
1636 IN PIRP_CONTEXT IrpContext,
1637 IN PFILE_ENUM_CONTEXT FileContext
1638 )
1639
1640 /*++
1641
1642 Routine Description:
1643
1644 This routine is called to cleanup the enumeration context for a file
1645 search in a directory. We will unpin any remaining Bcbs and free
1646 any allocated buffers.
1647
1648 Arguments:
1649
1650 FileContext - Enumeration context for the file search.
1651
1652 Return Value:
1653
1654 None.
1655
1656 --*/
1657
1658 {
1659 PCOMPOUND_DIRENT CurrentCompoundDirent;
1660 ULONG Count = 2;
1661
1662 PAGED_CODE();
1663
1664 //
1665 // Cleanup the individual compound dirents.
1666 //
1667
1668 do {
1669
1670 CurrentCompoundDirent = &FileContext->Dirents[ Count ];
1671 CdCleanupDirContext( IrpContext, &CurrentCompoundDirent->DirContext );
1672 CdCleanupDirent( IrpContext, &CurrentCompoundDirent->Dirent );
1673
1674 } while (Count--);
1675
1676 return;
1677 }
1678
1679 \f
1680 //
1681 // Local support routine
1682 //
1683
1684 ULONG
1685 CdCheckRawDirentBounds (
1686 IN PIRP_CONTEXT IrpContext,
1687 IN PDIRENT_ENUM_CONTEXT DirContext
1688 )
1689
1690 /*++
1691
1692 Routine Description:
1693
1694 This routine takes a Dirent enumeration context and computes the offset
1695 to the next dirent. A non-zero value indicates the offset within this
1696 sector. A zero value indicates to move to the next sector. If the
1697 current dirent does not fit within the sector then we will raise
1698 STATUS_CORRUPT.
1699
1700 Arguments:
1701
1702 DirContext - Enumeration context indicating the current position in
1703 the sector.
1704
1705 Return Value:
1706
1707 ULONG - Offset to the next dirent in this sector or zero if the
1708 next dirent is in the next sector.
1709
1710 This routine will raise on a dirent which does not fit into the
1711 described data buffer.
1712
1713 --*/
1714
1715 {
1716 ULONG NextDirentOffset;
1717 PRAW_DIRENT RawDirent;
1718
1719 PAGED_CODE();
1720
1721 //
1722 // We should always have at least a byte still available in the
1723 // current buffer.
1724 //
1725
1726 ASSERT( (DirContext->DataLength - DirContext->SectorOffset) >= 1 );
1727
1728 //
1729 // Get a pointer to the current dirent.
1730 //
1731
1732 RawDirent = CdRawDirent( IrpContext, DirContext );
1733
1734 //
1735 // If the dirent length is non-zero then look at the current dirent.
1736 //
1737
1738 if (RawDirent->DirLen != 0) {
1739
1740 //
1741 // Check the following bound for the dirent length.
1742 //
1743 // - Fits in the available bytes in the sector.
1744 // - Is at least the minimal dirent size.
1745 // - Is large enough to hold the file name.
1746 //
1747
1748 if ((RawDirent->DirLen > (DirContext->DataLength - DirContext->SectorOffset)) ||
1749 (RawDirent->DirLen < MIN_RAW_DIRENT_LEN) ||
1750 (RawDirent->DirLen < (MIN_RAW_DIRENT_LEN - 1 + RawDirent->FileIdLen))) {
1751
1752 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
1753 }
1754
1755 //
1756 // Copy the dirent length field.
1757 //
1758
1759 NextDirentOffset = RawDirent->DirLen;
1760
1761 //
1762 // If we are exactly at the next sector then tell our caller by
1763 // returning zero.
1764 //
1765
1766 if (NextDirentOffset == (DirContext->DataLength - DirContext->SectorOffset)) {
1767
1768 NextDirentOffset = 0;
1769 }
1770
1771 } else {
1772
1773 NextDirentOffset = 0;
1774 }
1775
1776 return NextDirentOffset;
1777 }
1778
1779 \f
1780 //
1781 // Local support routine
1782 //
1783
1784 XA_EXTENT_TYPE
1785 CdCheckForXAExtent (
1786 IN PIRP_CONTEXT IrpContext,
1787 IN PRAW_DIRENT RawDirent,
1788 IN OUT PDIRENT Dirent
1789 )
1790
1791 /*++
1792
1793 Routine Description:
1794
1795 This routine is called to scan through the system use area to test if
1796 the current dirent has the XA bit set. The bit in the in-memory
1797 dirent will be set as appropriate.
1798
1799 Arguments:
1800
1801 RawDirent - Pointer to the on-disk dirent.
1802
1803 Dirent - Pointer to the in-memory dirent. We will update this with the
1804 appropriate XA flag.
1805
1806 Return Value:
1807
1808 XA_EXTENT_TYPE - Type of physical extent for this on disk dirent.
1809
1810 --*/
1811
1812 {
1813 XA_EXTENT_TYPE ExtentType = Form1Data;
1814 PSYSTEM_USE_XA SystemUseArea;
1815
1816 PAGED_CODE();
1817
1818 //
1819 // Check if there is enough space for the XA system use area.
1820 //
1821
1822 if (Dirent->DirentLength - Dirent->SystemUseOffset >= sizeof( SYSTEM_USE_XA )) {
1823
1824 SystemUseArea = Add2Ptr( RawDirent, Dirent->SystemUseOffset, PSYSTEM_USE_XA );
1825
1826 //
1827 // Check for a valid signature.
1828 //
1829
1830 if (SystemUseArea->Signature == SYSTEM_XA_SIGNATURE) {
1831
1832 //
1833 // Check for an audio track.
1834 //
1835
1836 if (FlagOn( SystemUseArea->Attributes, SYSTEM_USE_XA_DA )) {
1837
1838 ExtentType = CDAudio;
1839
1840 } else if (FlagOn( SystemUseArea->Attributes, SYSTEM_USE_XA_FORM2 )) {
1841
1842 //
1843 // Check for XA data. Note that a number of discs (video CDs)
1844 // have files marked as type XA Mode 2 Form 1 (2048 bytes of
1845 // user data), but actually record these sectors as Mode2 Form 2
1846 // (2352). We will fail to read these files, since for M2F1,
1847 // a normal read CD command is issued (as per SCSI specs).
1848 //
1849
1850 ExtentType = Mode2Form2Data;
1851 }
1852
1853 Dirent->XAAttributes = SystemUseArea->Attributes;
1854 Dirent->XAFileNumber = SystemUseArea->FileNumber;
1855 }
1856 }
1857
1858 Dirent->ExtentType = ExtentType;
1859 return ExtentType;
1860 }
1861
1862
1863