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