1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7 Module:
8 Namesup.cpp
9
10 Abstract: FileName support routines
11 */
12
13 #include "udffs.h"
14
15 // '\dfdf\aaa\ffg' --> '\aaa\ffg'
16 // '\aaa\ffg' --> '\ffg'
17 PWCHAR
18 __fastcall
UDFDissectName(IN PWCHAR Buffer,OUT PUSHORT Length)19 UDFDissectName(
20 IN PWCHAR Buffer,
21 OUT PUSHORT Length
22 )
23 {
24
25 USHORT i;
26
27 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
28
29 PWCHAR retval;
30
31 __asm push ebx
32 __asm push ecx
33
34 __asm mov ebx,Buffer
35 __asm xor ecx,ecx
36 Remove_leading_slash:
37 __asm cmp [word ptr ebx],L'\\'
38 __asm jne No_IncPointer
39 __asm add ebx,2
40 __asm jmp Remove_leading_slash
41 No_IncPointer:
42 __asm cmp [word ptr ebx],L':'
43 __asm jne Scan_1
44 __asm add ebx,2
45 __asm inc ecx
46 __asm jmp EO_Dissect
47 Scan_1:
48 __asm mov ax,[word ptr ebx]
49 __asm cmp ax,L'\\'
50 __asm je EO_Dissect
51 __asm or ax,ax
52 __asm jz EO_Dissect
53 __asm cmp ax,L':'
54 __asm jne Cont_scan
55 __asm or ecx,ecx
56 __asm jnz EO_Dissect
57 Cont_scan:
58 __asm inc ecx
59 __asm add ebx,2
60 __asm jmp Scan_1
61 EO_Dissect:
62 __asm mov retval,ebx
63 __asm mov i,cx
64
65 __asm pop ecx
66 __asm pop ebx
67
68 *Length = i;
69 return retval;
70
71 #else // NO X86 optimization , use generic C/C++
72
73 while (Buffer[0] == L'\\') {
74 Buffer++;
75 }
76 if (Buffer[0] == L':') {
77 *Length = 1;
78 return &(Buffer[1]);
79 }
80 for(i = 0; ( Buffer[i] != L'\\' &&
81 ((Buffer[i] != L':') || !i) &&
82 Buffer[i]); i++);
83 *Length = i;
84 return &(Buffer[i]);
85
86 #endif // _X86_
87
88 } // end UDFDissectName()
89
90 BOOLEAN
91 __fastcall
UDFIsNameValid(IN PUNICODE_STRING SearchPattern,OUT BOOLEAN * StreamOpen,OUT ULONG * SNameIndex)92 UDFIsNameValid(
93 IN PUNICODE_STRING SearchPattern,
94 OUT BOOLEAN* StreamOpen,
95 OUT ULONG* SNameIndex
96 ) {
97 LONG Index, l;
98 BOOLEAN _StreamOpen = FALSE;
99 PWCHAR Buffer;
100 WCHAR c, c0;
101
102 if(StreamOpen) (*StreamOpen) = FALSE;
103 // We can't create nameless file or too long path
104 if(!(l = SearchPattern->Length/sizeof(WCHAR)) ||
105 (l>UDF_X_PATH_LEN)) return FALSE;
106 Buffer = SearchPattern->Buffer;
107 for(Index = 0; Index<l; Index++, Buffer++) {
108 // Check for disallowed characters
109 c = (*Buffer);
110 if((c == L'*') ||
111 (c == L'>') ||
112 (c == L'\"') ||
113 (c == L'/') ||
114 (c == L'<') ||
115 (c == L'|') ||
116 ((c >= 0x0000) && (c <= 0x001f)) ||
117 (c == L'?')) return FALSE;
118 // check if this a Stream path (& validate it)
119 if(!(_StreamOpen) && // sub-streams are not allowed
120 (Index<(l-1)) && // stream name must be specified
121 ((_StreamOpen) = (c == L':'))) {
122 if(StreamOpen) (*StreamOpen) = TRUE;
123 if(SNameIndex) (*SNameIndex) = Index;
124 }
125 // According to NT IFS documentation neither SPACE nor DOT can be
126 // a trailing character
127 if(Index && (c == L'\\') ) {
128 if((c0 == L' ') ||
129 (_StreamOpen) || // stream is not a directory
130 (c0 == L'.')) return FALSE;
131 }
132 c0 = c;
133 }
134 // According to NT IFS documentation neither SPACE nor DOT can be
135 // a trailing character
136 if((c0 == L' ') ||
137 (c0 == L'.')) return FALSE;
138 return TRUE;
139 } // end UDFIsNameValid()
140
141
142 #ifndef _CONSOLE
143 /*
144
145 Routine Description:
146
147 This routine will compare two Unicode strings.
148 PtrSearchPattern may contain wildcards
149
150 Return Value:
151
152 BOOLEAN - TRUE if the expressions match, FALSE otherwise.
153
154 */
155 BOOLEAN
UDFIsNameInExpression(IN PVCB Vcb,IN PUNICODE_STRING FileName,IN PUNICODE_STRING PtrSearchPattern,OUT PBOOLEAN DosOpen,IN BOOLEAN IgnoreCase,IN BOOLEAN ContainsWC,IN BOOLEAN CanBe8dot3,IN BOOLEAN KeepIntact)156 UDFIsNameInExpression(
157 IN PVCB Vcb,
158 IN PUNICODE_STRING FileName,
159 IN PUNICODE_STRING PtrSearchPattern,
160 OUT PBOOLEAN DosOpen,
161 IN BOOLEAN IgnoreCase,
162 IN BOOLEAN ContainsWC,
163 IN BOOLEAN CanBe8dot3,
164 IN BOOLEAN KeepIntact // passed to UDFDOSName
165 )
166 {
167 BOOLEAN Match = TRUE;
168 UNICODE_STRING ShortName;
169 WCHAR Buffer[13];
170
171 if(!PtrSearchPattern) return TRUE;
172 // we try to open file by LFN by default
173 if(DosOpen) (*DosOpen) = FALSE;
174 // If there are wildcards in the expression then we call the
175 // appropriate FsRtlRoutine.
176 if(ContainsWC) {
177 Match = FsRtlIsNameInExpression( PtrSearchPattern, FileName, IgnoreCase, NULL );
178 // Otherwise do a direct memory comparison for the name string.
179 } else if (RtlCompareUnicodeString(FileName, PtrSearchPattern, IgnoreCase)) {
180 Match = FALSE;
181 }
182
183 if(Match) return TRUE;
184
185 // check if SFN can match this pattern
186 if(!CanBe8dot3)
187 return FALSE;
188
189 // try to open by SFN
190 ShortName.Buffer = (PWCHAR)(&Buffer);
191 ShortName.MaximumLength = 13*sizeof(WCHAR);
192 UDFDOSName(Vcb, &ShortName, FileName, KeepIntact);
193
194 // PtrSearchPattern is upcased if we are called with IgnoreCase=TRUE
195 // DOSName is always upcased
196 // thus, we can use case-sensetive compare here to improve performance
197 if(ContainsWC) {
198 Match = FsRtlIsNameInExpression( PtrSearchPattern, &ShortName, FALSE, NULL );
199 // Otherwise do a direct memory comparison for the name string.
200 } else if (!RtlCompareUnicodeString(&ShortName, PtrSearchPattern, FALSE)) {
201 Match = TRUE;
202 }
203 if(DosOpen && Match) {
204 // remember that we've opened file by SFN
205 (*DosOpen) = TRUE;
206 }
207 return Match;
208 } // end UDFIsNameInExpression()
209
210 #endif
211
212 BOOLEAN
213 __fastcall
UDFIsMatchAllMask(IN PUNICODE_STRING Name,OUT BOOLEAN * DosOpen)214 UDFIsMatchAllMask(
215 IN PUNICODE_STRING Name,
216 OUT BOOLEAN* DosOpen
217 )
218 {
219 USHORT i;
220 PWCHAR Buffer;
221
222 if(DosOpen)
223 *DosOpen = FALSE;
224 Buffer = Name->Buffer;
225 if(Name->Length == sizeof(WCHAR)) {
226 // Win32-style wildcard
227 if((*Buffer) != L'*')
228 return FALSE;
229 return TRUE;
230 } else
231 if(Name->Length == sizeof(WCHAR)*(8+1+3)) {
232 // DOS-style wildcard
233 for(i=0;i<8;i++,Buffer++) {
234 if((*Buffer) != DOS_QM)
235 return FALSE;
236 }
237 if((*Buffer) != DOS_DOT)
238 return FALSE;
239 Buffer++;
240 for(i=9;i<12;i++,Buffer++) {
241 if((*Buffer) != DOS_QM)
242 return FALSE;
243 }
244 if(DosOpen)
245 *DosOpen = TRUE;
246 return TRUE;
247 } else
248 if(Name->Length == sizeof(WCHAR)*(3)) {
249 // DOS-style wildcard
250 if(Buffer[0] != DOS_STAR)
251 return FALSE;
252 if(Buffer[1] != DOS_DOT)
253 return FALSE;
254 if(Buffer[2] != DOS_STAR)
255 return FALSE;
256 if(DosOpen)
257 *DosOpen = TRUE;
258 return TRUE;
259 } else {
260 return FALSE;
261 }
262 } // end UDFIsMatchAllMask()
263
264 BOOLEAN
265 __fastcall
UDFCanNameBeA8dot3(IN PUNICODE_STRING Name)266 UDFCanNameBeA8dot3(
267 IN PUNICODE_STRING Name
268 )
269 {
270 if(Name->Length >= 13 * sizeof(WCHAR))
271 return FALSE;
272
273 ULONG i,l;
274 ULONG dot_pos=0;
275 ULONG ext_len=0;
276 PWCHAR buff = Name->Buffer;
277
278 l = Name->Length / sizeof(WCHAR);
279
280 for(i=0; i<l; i++, buff++) {
281 if( ((*buff) == L'.') ||
282 ((*buff) == DOS_DOT) ) {
283 if(dot_pos)
284 return FALSE;
285 dot_pos = i+1;
286 } else
287 if(dot_pos) {
288 ext_len++;
289 if(ext_len > 3)
290 return FALSE;
291 } else
292 if(i >= 8) {
293 return FALSE;
294 }
295 }
296 return TRUE;
297 } // end UDFCanNameBeA8dot3()
298