Sample Code

windows driver samples/ cdfs file system driver/ C++/ namesup.c/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
/*++
 
Copyright (c) 1991-2000 Microsoft Corporation
 
Module Name:
 
    NameSup.c
 
Abstract:
 
    This module implements the Cdfs Name support routines
 
 
--*/
 
#include "CdProcs.h"
 
//
//  The Bug check file id for this module
//
 
#define BugCheckFileId                   (CDFS_BUG_CHECK_NAMESUP)
 
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CdConvertBigToLittleEndian)
#pragma alloc_text(PAGE, CdConvertNameToCdName)
#pragma alloc_text(PAGE, CdDissectName)
#pragma alloc_text(PAGE, CdGenerate8dot3Name)
#pragma alloc_text(PAGE, CdFullCompareNames)
#pragma alloc_text(PAGE, CdIsLegalName)
#pragma alloc_text(PAGE, CdIs8dot3Name)
#pragma alloc_text(PAGE, CdIsNameInExpression)
#pragma alloc_text(PAGE, CdShortNameDirentOffset)
#pragma alloc_text(PAGE, CdUpcaseName)
#endif
 
_Post_satisfies_(_Old_(CdName->FileName.Length) >=
                 CdName->FileName.Length + CdName->VersionString.Length)
VOID
CdConvertNameToCdName (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PCD_NAME CdName
    )
 
/*++
 
Routine Description:
 
    This routine is called to convert a string of bytes into a CdName.
 
    The full name is already in the CdName structure in the FileName field.
    We split this into the filename and version strings.
 
Arguments:
 
    CdName - Pointer to CdName structure to update.
 
Return Value:
 
    None.
 
--*/
 
{
    ULONG NameLength = 0;
    PWCHAR CurrentCharacter = CdName->FileName.Buffer;
 
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
 
    //
    //  Look for a separator character.
    //
 
    while ((NameLength < CdName->FileName.Length) &&
           (*CurrentCharacter != L';')) {
 
        CurrentCharacter += 1;
        NameLength += 2;
    }
 
    //
    //  If there is at least one more character after a possible separator then it
    //  and all following characters are part of the version string.
    //
 
    CdName->VersionString.Length = 0;
    if (NameLength + sizeof( WCHAR ) < CdName->FileName.Length) {
 
        CdName->VersionString.MaximumLength =
        CdName->VersionString.Length = (USHORT) (CdName->FileName.Length - NameLength - sizeof( WCHAR ));
        CdName->VersionString.Buffer = Add2Ptr( CdName->FileName.Buffer,
                                                NameLength + sizeof( WCHAR ),
                                                PWCHAR );
    }
 
    //
    //  Now update the filename portion of the name.
    //
 
    CdName->FileName.Length = (USHORT) NameLength;
 
    return;
}
 
VOID
CdConvertBigToLittleEndian (
    _In_ PIRP_CONTEXT IrpContext,
    _In_reads_bytes_(ByteCount) PCHAR BigEndian,
    _In_ ULONG ByteCount,
    _Out_writes_bytes_(ByteCount) PCHAR LittleEndian
    )
 
/*++
 
Routine Description:
 
    This routine is called to convert a unicode string in big endian to
    little endian.  We start by copying all of the source bytes except
    the first.  This will put the low order bytes in the correct position.
    We then copy each high order byte in its correct position.
 
Arguments:
 
    BigEndian - Pointer to the string of big endian characters.
 
    ByteCount - Number of unicode characters in this string.
 
    LittleEndian - Pointer to array to store the little endian characters.
 
Return Value:
 
    None.
 
--*/
 
{
    ULONG RemainingByteCount = ByteCount;
 
    PCHAR Source = BigEndian;
    PCHAR Destination = LittleEndian;
 
    PAGED_CODE();
 
    //
    //  If the byte count isn't an even number then the disk is corrupt.
    //
 
    if (FlagOn( ByteCount, 1 )) {
 
        CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
    }
 
    //
    //  Start by copy the low-order bytes into the correct position.  Do
    //  this by skipping the first byte in the BigEndian string.
    //
 
    RtlCopyMemory( Destination,
                   Source + 1,
                   RemainingByteCount - 1 );
 
    //
    //  Now move the high-order bytes into position.
    //
 
    Destination += 1;
 
    while (RemainingByteCount != 0) {
 
#pragma prefast(push)
#pragma prefast(suppress:26014, "RemainingByteCount is even")
        *Destination = *Source;
#pragma prefast(pop)
 
        Source += 2;
        Destination += 2;
 
        RemainingByteCount -= 2;
    }
 
    return;
}
 
VOID
CdUpcaseName (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PCD_NAME Name,
    _Inout_ PCD_NAME UpcaseName
    )
 
/*++
 
Routine Description:
 
    This routine is called to upcase a CdName structure.  We will do both
    the filename and version strings.
 
Arguments:
 
    Name - This is the mixed case version of the name.
 
    UpcaseName - This is the destination for the upcase operation.
 
Return Value:
 
    None.  This routine will raise all errors.
 
--*/
 
{
    NTSTATUS Status;
 
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
     
    //
    //  If the name structures are different then initialize the different components.
    //
 
    if (Name != UpcaseName) {
 
        //
        //  Initialize the version string portion of the name.
        //
 
        UpcaseName->VersionString.Length = 0;
 
        if (Name->VersionString.Length != 0) {
 
            UpcaseName->VersionString.MaximumLength =
            UpcaseName->VersionString.Length = Name->VersionString.Length;
 
            //
            //  Initially set the buffer to point to where we need to insert
            //  the separator.
            //
 
            UpcaseName->VersionString.Buffer = Add2Ptr( UpcaseName->FileName.Buffer,
                                                        Name->FileName.Length,
                                                        PWCHAR );
 
            //
            //  We are currently pointing to the location to store the separator.
            //  Store the ';' and then move to the next character to
            //  copy the data.
            //
 
#pragma prefast( suppress:26015, "CD_NAME structures have two UNICODE_STRING structures pointing to the same allocation. there is no way to tell prefast this is the case and that the allocation is always big enough.");
            *(UpcaseName->VersionString.Buffer) = L';';
 
            UpcaseName->VersionString.Buffer += 1;
        }
    }
 
    //
    //  Upcase the string using the correct upcase routine.
    //
 
    Status = RtlUpcaseUnicodeString( &UpcaseName->FileName,
                                     &Name->FileName,
                                     FALSE );
 
    //
    //  This should never fail.
    //
 
    NT_ASSERT( Status == STATUS_SUCCESS );
    __analysis_assert( Status == STATUS_SUCCESS );
                 
    if (Name->VersionString.Length != 0) {
 
#pragma prefast( suppress:26015, "CD_NAME structures have two UNICODE_STRING structures pointing to the same allocation. there is no way to tell prefast this is the case and that the allocation is always big enough.");
        Status = RtlUpcaseUnicodeString( &UpcaseName->VersionString,
                                         &Name->VersionString,
                                         FALSE );
 
        //
        //  This should never fail.
        //
 
        NT_ASSERT( Status == STATUS_SUCCESS );
        __analysis_assert( Status == STATUS_SUCCESS );       
    }
 
    return;
}
 
VOID
CdDissectName (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PUNICODE_STRING RemainingName,
    _Out_ PUNICODE_STRING FinalName
    )
 
/*++
 
Routine Description:
 
    This routine is called to strip off leading components of the name strings.  We search
    for either the end of the string or separating characters.  The input remaining
    name strings should have neither a trailing or leading backslash.
 
Arguments:
 
    RemainingName - Remaining name.
 
    FinalName - Location to store next component of name.
 
Return Value:
 
    None.
 
--*/
 
{
    ULONG NameLength;
    PWCHAR NextWchar;
 
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
     
    //
    //  Find the offset of the next component separators.
    //
 
    for (NameLength = 0, NextWchar = RemainingName->Buffer;
         (NameLength < RemainingName->Length) && (*NextWchar != L'\\');
         NameLength += sizeof( WCHAR) , NextWchar += 1);
 
    //
    //  Adjust all the strings by this amount.
    //
 
    FinalName->Buffer = RemainingName->Buffer;
 
    FinalName->MaximumLength = FinalName->Length = (USHORT) NameLength;
 
    //
    //  If this is the last component then set the RemainingName lengths to zero.
    //
 
    if (NameLength == RemainingName->Length) {
 
        RemainingName->Length = 0;
 
    //
    //  Otherwise we adjust the string by this amount plus the separating character.
    //
 
    } else {
 
        RemainingName->MaximumLength -= (USHORT) (NameLength + sizeof( WCHAR ));
        RemainingName->Length -= (USHORT) (NameLength + sizeof( WCHAR ));
        RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
                                         NameLength + sizeof( WCHAR ),
                                         PWCHAR );
    }
 
    return;
}
 
BOOLEAN
CdIsLegalName (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PUNICODE_STRING FileName
    )
 
/*++
 
Routine Description:
 
    This routine checks if the name is a legal ISO 9660 name.
 
Arguments:
 
    FileName - String of bytes containing the name.
 
Return Value:
 
    BOOLEAN - TRUE if this name is a legal, FALSE otherwise.
 
--*/
 
{
    PWCHAR Wchar;
 
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
 
    //
    //  Check if name corresponds to a legal file name.
    //
 
    for (Wchar = FileName->Buffer;
         Wchar < Add2Ptr( FileName->Buffer, FileName->Length, PWCHAR );
         Wchar++) {
 
        if ((*Wchar < 0xff) &&
            !FsRtlIsAnsiCharacterLegalHpfs( *Wchar, FALSE ) &&
            (*Wchar != L'"') &&
            (*Wchar != L'<') &&
            (*Wchar != L'>') &&
            (*Wchar != L'|')) {
 
            return FALSE;
        }
    }
 
    return TRUE;
}
 
BOOLEAN
CdIs8dot3Name (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ UNICODE_STRING FileName
    )
 
/*++
 
Routine Description:
 
    This routine checks if the name follows the 8.3 name conventions.  We check for
    the name length and whether the characters are valid.
 
Arguments:
 
    FileName - String of bytes containing the name.
 
Return Value:
 
    BOOLEAN - TRUE if this name is a legal 8.3 name, FALSE otherwise.
 
--*/
 
{
    CHAR DbcsNameBuffer[ BYTE_COUNT_8_DOT_3 ];
    STRING DbcsName = {0};
 
    PWCHAR NextWchar;
    ULONG Count;
 
    ULONG DotCount = 0;
    BOOLEAN LastCharDot = FALSE;
 
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
     
    //
    //  The length must be less than 24 bytes.
    //
 
    NT_ASSERT( FileName.Length != 0 );
    if (FileName.Length > BYTE_COUNT_8_DOT_3) {
 
        return FALSE;
    }
 
    //
    //  Walk though and check for a space character.
    //
 
    NextWchar = FileName.Buffer;
    Count = 0;
 
    do {
 
        //
        //  No spaces allowed.
        //
 
        if (*NextWchar == L' ') { return FALSE; }
 
        if (*NextWchar == L'.') {
 
            //
            //  Not an 8.3 name if more than 1 dot or more than 8 characters
            //  remaining.  (It is legal for the dot to be in the ninth
            //  position)
            //
 
            if ((DotCount > 0) ||
                (Count > 8 * sizeof( WCHAR ))) {
 
                return FALSE;
            }
 
            DotCount += 1;
            LastCharDot = TRUE;
 
        } else {
 
            LastCharDot = FALSE;
        }
 
        Count += 2;
        NextWchar += 1;
 
    } while (Count < FileName.Length);
 
    //
    //  Go ahead and truncate the dot if at the end.
    //
 
    if (LastCharDot) {
 
        FileName.Length -= sizeof( WCHAR );
    }
 
    //
    //  Create an Oem name to use to check for a valid short name.
    //
 
    DbcsName.MaximumLength = BYTE_COUNT_8_DOT_3;
    DbcsName.Buffer = DbcsNameBuffer;
 
    if (!NT_SUCCESS( RtlUnicodeStringToCountedOemString( &DbcsName,
                                                         &FileName,
                                                         FALSE ))) {
 
        return FALSE;
    }
 
    //
    //  We have now initialized the Oem string.  Call the FsRtl package to check for a
    //  valid FAT name.
    //
 
    return FsRtlIsFatDbcsLegal( DbcsName, FALSE, FALSE, FALSE );
}
 
VOID
CdGenerate8dot3Name (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PUNICODE_STRING FileName,
    _In_ ULONG DirentOffset,
    _Out_writes_bytes_to_(BYTE_COUNT_8_DOT_3, *ShortByteCount) PWCHAR ShortFileName,
    _Out_ PUSHORT ShortByteCount
    )
 
/*++
 
Routine Description:
 
    This routine is called to generate a short name from the given long name.  We will
    generate a short name from the given long name.
 
    We go through the following steps to make this conversion.
 
        1 - Generate the generic short name.  This will also be in unicode format.
 
        2 - Build the string representation of the dirent offset.
 
        3 - Build the biased short name string by combining the generic short name with
            the dirent offset string.
 
        4 - Copy the final unicode string back to our caller's buffer.
 
Arguments:
 
    FileName - String of bytes containing the name.
 
    DirentOffset - Offset in the directory for this filename.  We incorporate the offset into
        the short name by dividing this by 32 and prepending a tilde character to the
        digit character.  We then append this to the base of the generated short name.
 
    ShortFileName - Pointer to the buffer to store the short name into.
 
    ShortByteCount - Address to store the number of bytes in the short name.
 
Return Value:
 
    None.
 
--*/
 
{  
    NTSTATUS Status;
     
    UNICODE_STRING ShortName;
    UNICODE_STRING BiasedShortName;
    WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ] = {0};
    WCHAR BiasedShortNameBuffer[ BYTE_COUNT_8_DOT_3 / sizeof( WCHAR ) ];
 
    GENERATE_NAME_CONTEXT NameContext;
 
    ULONG BiasedDirentOffset;
 
    ULONG MaximumBaseBytes;
    ULONG BaseNameOffset;
 
    PWCHAR NextWchar;
    WCHAR ThisWchar;
    USHORT Length;
 
    BOOLEAN FoundTilde = FALSE;
 
    OEM_STRING OemName = {0};
    USHORT OemNameOffset = 0;
    BOOLEAN OverflowBuffer = FALSE;
 
    PAGED_CODE();
 
    //
    //  Initialize the short string to use the input buffer.
    //
 
    ShortName.Buffer = ShortNameBuffer;
    ShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
 
    //
    //  Initialize the name context.
    //
 
    RtlZeroMemory( &NameContext, sizeof( GENERATE_NAME_CONTEXT ));
 
    //
    //  We now have the unicode name for the input string.  Go ahead and generate
    //  the short name.
    //
 
    RtlGenerate8dot3Name( FileName, TRUE, &NameContext, &ShortName );
 
    //
    //  We now have the generic short name.  We want incorporate the dirent offset
    //  into the name in order to reduce the chance of name conflicts.  We will use
    //  a tilde character followed by a character representation of the dirent offset.
    //  This will be the hexadecimal representation of the dirent offset in the directory.
    //  It is actuall this offset divided by 32 since we don't need the full
    //  granularity.
    //
 
    BiasedDirentOffset = DirentOffset >> SHORT_NAME_SHIFT;
 
    //
    //  Point to a local buffer to store the offset string.  We start
    //  at the end of the buffer and work backwards.
    //
 
    NextWchar = Add2Ptr( BiasedShortNameBuffer,
                         BYTE_COUNT_8_DOT_3,
                         PWCHAR );
 
    BiasedShortName.MaximumLength = BYTE_COUNT_8_DOT_3;
 
    //
    //  Generate an OEM version of the string so that we can check for double
    //  byte characters.
    //
     
    Status = RtlUnicodeStringToOemString(&OemName, &ShortName, TRUE);
 
    //
    //  If this failed, bail out. Don't expect any problems other than no mem.
    //
     
    if (!NT_SUCCESS( Status)) {
 
        NT_ASSERT( STATUS_INSUFFICIENT_RESOURCES == Status);
        CdRaiseStatus( IrpContext, Status);
    }
     
    Length = 0;
 
    //
    //  Now add the characters for the dirent offset.  We need to start
    //  from the least significant digit and work backwards.
    //
 
    do {
 
        NextWchar -= 1;
 
        ThisWchar = (WCHAR) (BiasedDirentOffset & 0x0000000f);
 
        //
        //  Store in the next character.  Bias against either '0' or 'A'
        //
 
        if (ThisWchar <= 9) {
 
            *NextWchar = ThisWchar + L'0';
 
        } else {
 
            *NextWchar = ThisWchar + L'A' - 0xA;
        }
 
        Length += sizeof( WCHAR );
 
        //
        //  Shift out the low 4 bits of the offset.
        //
 
        BiasedDirentOffset >>= 4;
 
    } while (BiasedDirentOffset != 0);
 
    //
    //  Now store in the tilde character.
    //
 
    NextWchar -= 1;
    *NextWchar = L'~';
    Length += sizeof( WCHAR );
 
    //
    //  Set the length of this string.
    //
 
    BiasedShortName.Length = Length;
    BiasedShortName.Buffer = NextWchar;
 
    //
    //  Figure out the maximum number of characters we can copy of the base
    //  name.  We subract the number of characters in the dirent string from 8.
    //  We will copy this many characters or stop when we reach a '.' character
    //  or a '~' character in the name.
    //
 
    MaximumBaseBytes = 16 - Length;
 
    BaseNameOffset = 0;
 
    //
    //  Keep copying from the base name until we hit a '.', '~'  or the end of
    //  the short name.
    //
 
    NextWchar = ShortFileName;
    Length = 0;
 
    while ((BaseNameOffset < ShortName.Length) &&
           (ShortName.Buffer[BaseNameOffset / 2] != L'.')) {
 
        //
        //  Remember if we found a tilde character in the short name,
        //  so we don't copy it or anything following it.
        //
 
        if (ShortName.Buffer[BaseNameOffset / 2] == L'~') {
 
            FoundTilde = TRUE;
        }
 
        //
        // We need to consider the DBCS code page,  because Unicode characters
        // may use 2 bytes as DBCS characters.
        //
 
#pragma prefast(push)
#pragma prefast(suppress:26014, "OemNameOffset <= BaseNameOffset throughout this loop; OemName buffer previously allocated based on ShortName's length.")
        if (FsRtlIsLeadDbcsCharacter(OemName.Buffer[OemNameOffset])) {
#pragma prefast(pop)
 
            OemNameOffset += 2;
 
            if ((OemNameOffset + (BiasedShortName.Length / sizeof(WCHAR))) > 8)  {
             
                OverflowBuffer = TRUE;
            }
        }
        else  {
         
            OemNameOffset++;
        }
 
        //
        //  Only copy the bytes if we still have space for the dirent string.
        //
 
        if (!FoundTilde && !OverflowBuffer && (BaseNameOffset < MaximumBaseBytes)) {
 
            *NextWchar = ShortName.Buffer[BaseNameOffset / 2];
            Length += sizeof( WCHAR );
            NextWchar += 1;
        }
 
        BaseNameOffset += 2;
    }
 
    RtlFreeOemString(&OemName);
 
    //
    //  Now copy the dirent string into the biased name buffer.
    //
 
#pragma prefast(push)
#pragma prefast(suppress:26015, "The loop that the analyzer is concerned about will run fewer than 9 times")
    RtlCopyMemory( NextWchar,
                   BiasedShortName.Buffer,
                   BiasedShortName.Length );
#pragma prefast(pop)
 
    Length += BiasedShortName.Length;
    NextWchar += (BiasedShortName.Length / sizeof( WCHAR ));
 
    //
    //  Now copy any remaining bytes over to the biased short name.
    //
 
    if (BaseNameOffset != ShortName.Length) {
 
        RtlCopyMemory( NextWchar,
                       &ShortName.Buffer[BaseNameOffset / 2],
                       ShortName.Length - BaseNameOffset );
 
        Length += (ShortName.Length - (USHORT) BaseNameOffset);
    }
 
    //
    //  The final short name is stored in the user's buffer.
    //
 
    *ShortByteCount = Length;
}
 
BOOLEAN
CdIsNameInExpression (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PCD_NAME CurrentName,
    _In_ PCD_NAME SearchExpression,
    _In_ ULONG  WildcardFlags,
    _In_ BOOLEAN CheckVersion
    )
 
/*++
 
Routine Description:
 
    This routine will compare two CdName strings.  We assume that if this
    is to be a case-insensitive search then they are already upcased.
 
    We compare the filename portions of the name and if they match we
    compare the version strings if requested.
 
Arguments:
 
    CurrentName - Filename from the disk.
 
    SearchExpression - Filename expression to use for match.
 
    WildcardFlags - Flags field which indicates which parts of the
        search expression might have wildcards.  These flags are the
        same as in the Ccb flags field.
 
    CheckVersion - Indicates whether we should check both the name and the
        version strings or just the name.
 
Return Value:
 
    BOOLEAN - TRUE if the expressions match, FALSE otherwise.
 
--*/
 
{
    BOOLEAN Match = TRUE;
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
     
    //
    //  If there are wildcards in the expression then we call the
    //  appropriate FsRtlRoutine.
    //
 
    if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_NAME_EXP_HAS_WILD )) {
 
        Match = FsRtlIsNameInExpression( &SearchExpression->FileName,
                                         &CurrentName->FileName,
                                         FALSE,
                                         NULL );
 
    //
    //  Otherwise do a direct memory comparison for the name string.
    //
 
    } else {
 
        if ((CurrentName->FileName.Length != SearchExpression->FileName.Length) ||
            (!RtlEqualMemory( CurrentName->FileName.Buffer,
                              SearchExpression->FileName.Buffer,
                              CurrentName->FileName.Length ))) {
 
            Match = FALSE;
        }
    }
 
    //
    //  Check the version numbers if requested by the user and we have a
    //  match on the name and the version number is present.
    //
 
    if (Match && CheckVersion && SearchExpression->VersionString.Length &&
        !FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_MATCH_ALL )) {
 
        //
        //  If there are wildcards in the expression then call the
        //  appropriate search expression.
        //
 
        if (FlagOn( WildcardFlags, CCB_FLAG_ENUM_VERSION_EXP_HAS_WILD )) {
 
            Match = FsRtlIsNameInExpression( &SearchExpression->VersionString,
                                             &CurrentName->VersionString,
                                             FALSE,
                                             NULL );
 
        //
        //  Otherwise do a direct memory comparison for the name string.
        //
 
        } else {
 
            if ((CurrentName->VersionString.Length != SearchExpression->VersionString.Length) ||
                (!RtlEqualMemory( CurrentName->VersionString.Buffer,
                                  SearchExpression->VersionString.Buffer,
                                  CurrentName->VersionString.Length ))) {
 
                Match = FALSE;
            }
        }
    }
 
    return Match;
}
 
ULONG
CdShortNameDirentOffset (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PUNICODE_STRING Name
    )
 
/*++
 
Routine Description:
 
    This routine is called to examine a name to see if the dirent offset string is contained.
    This consists of a tilde character followed by the offset represented as a hexadecimal
    characters.  We don't do any other checks to see if this is a short name.  We
    catch that later outside this routine.
 
Arguments:
 
    Name - This is the CdName to examine.
 
Return Value:
 
    ULONG - MAXULONG if there is no valid dirent offset string embedded, otherwise the
        convert the value to numeric form.
 
--*/
 
{
    ULONG ResultOffset = MAXULONG;
    ULONG RemainingByteCount = Name->Length;
 
    BOOLEAN FoundTilde = FALSE;
 
    PWCHAR NextWchar;
 
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
     
    //
    //  Walk through the name until we either reach the end of the name
    //  or find a tilde character.
    //
 
    for (NextWchar = Name->Buffer;
         RemainingByteCount != 0;
         NextWchar += 1, RemainingByteCount -= sizeof( WCHAR )) {
 
        //
        //  Check if this is a dot.  Stop constructing any string if
        //  we found a dot.
        //
 
        if (*NextWchar == L'.') {
 
            break;
        }
 
        //
        //  If we already found a tilde then check this character as a
        //  valid character.  It must be a digit or A to F.
        //
 
        if (FoundTilde) {
 
            if ((*NextWchar < L'0') ||
                (*NextWchar > L'F') ||
                ((*NextWchar > L'9') && (*NextWchar < 'A'))) {
 
                ResultOffset = MAXULONG;
                break;
            }
 
            //
            //  Shift the result by 4 bits and add in this new character.
            //
 
            ResultOffset <<= 4;
 
            if (*NextWchar < L'A') {
 
                ResultOffset += *NextWchar - L'0';
 
            } else {
 
                ResultOffset += (*NextWchar - L'A') + 10;
            }
 
            continue;
        }
 
        //
        //  If this is a tilde then start building the dirent string.
        //
 
        if (*NextWchar == L'~') {
 
            FoundTilde = TRUE;
            ResultOffset = 0;
        }
    }
 
    return ResultOffset;
}
 
//
//  Local support routine
//
 
FSRTL_COMPARISON_RESULT
CdFullCompareNames (
    _In_ PIRP_CONTEXT IrpContext,
    _In_ PUNICODE_STRING NameA,
    _In_ PUNICODE_STRING NameB
    )
 
/*++
 
Routine Description:
 
    This function compares two names as fast as possible.  Note that since
    this comparison is case sensitive we can do a direct memory comparison.
 
Arguments:
 
    NameA & NameB - The names to compare.
 
Return Value:
 
    COMPARISON - returns
 
        LessThan    if NameA < NameB lexicalgraphically,
        GreaterThan if NameA > NameB lexicalgraphically,
        EqualTo     if NameA is equal to NameB
 
--*/
 
{
    SIZE_T i;
    ULONG MinLength = NameA->Length;
    FSRTL_COMPARISON_RESULT Result = LessThan;
 
    PAGED_CODE();
 
    UNREFERENCED_PARAMETER( IrpContext );
     
    //
    //  Figure out the minimum of the two lengths
    //
 
    if (NameA->Length > NameB->Length) {
 
        MinLength = NameB->Length;
        Result = GreaterThan;
 
    } else if (NameA->Length == NameB->Length) {
 
        Result = EqualTo;
    }
 
    //
    //  Loop through looking at all of the characters in both strings
    //  testing for equalilty, less than, and greater than
    //
 
    i = RtlCompareMemory( NameA->Buffer, NameB->Buffer, MinLength );
 
    if (i < MinLength) {
 
        //
        //  We know the offset of the first character which is different.
        //
 
        return ((NameA->Buffer[ i / 2 ] < NameB->Buffer[ i / 2 ]) ?
                 LessThan :
                 GreaterThan);
    }
 
    //
    //  The names match up to the length of the shorter string.
    //  The shorter string lexically appears first.
    //
 
    return Result;
}

Our Services

  • What our customers say about us?

© 2011-2025 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS