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