1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            dll/win32/kernel32/client/file/filename.c
5  * PURPOSE:         Directory functions
6  * PROGRAMMERS:     Ariadne (ariadne@xs4all.nl)
7  *                  Pierre Schweitzer (pierre.schweitzer@reactos.org)
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  */
11 
12 /* INCLUDES *****************************************************************/
13 
14 #include <k32.h>
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* GLOBALS ******************************************************************/
19 
20 /* FUNCTIONS ****************************************************************/
21 
22 /***********************************************************************
23  *           GetTempFileNameA   (KERNEL32.@)
24  */
25 UINT WINAPI
GetTempFileNameA(IN LPCSTR lpPathName,IN LPCSTR lpPrefixString,IN UINT uUnique,OUT LPSTR lpTempFileName)26 GetTempFileNameA(IN LPCSTR lpPathName,
27                  IN LPCSTR lpPrefixString,
28                  IN UINT uUnique,
29                  OUT LPSTR lpTempFileName)
30 {
31     UINT ID;
32     NTSTATUS Status;
33     LPWSTR lpTempFileNameW;
34     PUNICODE_STRING lpPathNameW;
35     ANSI_STRING TempFileNameStringA;
36     UNICODE_STRING lpPrefixStringW, TempFileNameStringW;
37 
38     /* Convert strings */
39     lpPathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
40     if (!lpPathNameW)
41     {
42         return 0;
43     }
44 
45     if (!Basep8BitStringToDynamicUnicodeString(&lpPrefixStringW, lpPrefixString))
46     {
47         return 0;
48     }
49 
50     lpTempFileNameW = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
51     if (!lpTempFileNameW)
52     {
53         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
54         RtlFreeUnicodeString(&lpPrefixStringW);
55         return 0;
56     }
57 
58     /* Call Unicode */
59     ID = GetTempFileNameW(lpPathNameW->Buffer, lpPrefixStringW.Buffer, uUnique, lpTempFileNameW);
60     if (ID)
61     {
62         RtlInitUnicodeString(&TempFileNameStringW, lpTempFileNameW);
63         TempFileNameStringA.Buffer = lpTempFileName;
64         TempFileNameStringA.MaximumLength = MAX_PATH;
65 
66         Status = BasepUnicodeStringTo8BitString(&TempFileNameStringA, &TempFileNameStringW, FALSE);
67         if (!NT_SUCCESS(Status))
68         {
69             BaseSetLastNTError(Status);
70             ID = 0;
71         }
72     }
73 
74     /* Cleanup */
75     RtlFreeUnicodeString(&lpPrefixStringW);
76     RtlFreeHeap(RtlGetProcessHeap(), 0, lpTempFileNameW);
77     return ID;
78  }
79 
80  /***********************************************************************
81   *           GetTempFileNameW   (KERNEL32.@)
82   */
83 UINT WINAPI
GetTempFileNameW(IN LPCWSTR lpPathName,IN LPCWSTR lpPrefixString,IN UINT uUnique,OUT LPWSTR lpTempFileName)84 GetTempFileNameW(IN LPCWSTR lpPathName,
85                  IN LPCWSTR lpPrefixString,
86                  IN UINT uUnique,
87                  OUT LPWSTR lpTempFileName)
88 {
89     PUCHAR Let;
90     HANDLE TempFile;
91     UINT ID, Num = 0;
92     UCHAR IDString[5];
93     WCHAR * TempFileName;
94     BASE_API_MESSAGE ApiMessage;
95     PBASE_GET_TEMP_FILE GetTempFile = &ApiMessage.Data.GetTempFileRequest;
96     DWORD FileAttributes, LastError;
97     UNICODE_STRING PathNameString, PrefixString;
98     static const WCHAR Ext[] = { L'.', 't', 'm', 'p', UNICODE_NULL };
99 
100     RtlInitUnicodeString(&PathNameString, lpPathName);
101     if (PathNameString.Length == 0 || PathNameString.Buffer[(PathNameString.Length / sizeof(WCHAR)) - 1] != L'\\')
102     {
103         PathNameString.Length += sizeof(WCHAR);
104     }
105 
106     /* lpTempFileName must be able to contain: PathName, Prefix (3), number(4), .tmp(4) & \0(1)
107      * See: http://msdn.microsoft.com/en-us/library/aa364991%28v=vs.85%29.aspx
108      */
109     if (PathNameString.Length > (MAX_PATH - 3 - 4 - 4 - 1) * sizeof(WCHAR))
110     {
111         SetLastError(ERROR_BUFFER_OVERFLOW);
112         return 0;
113     }
114 
115     /* If PathName and TempFileName aren't the same buffer, move PathName to TempFileName */
116     if (lpPathName != lpTempFileName)
117     {
118         memmove(lpTempFileName, PathNameString.Buffer, PathNameString.Length);
119     }
120 
121     /* PathName MUST BE a path. Check it */
122     lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = UNICODE_NULL;
123     FileAttributes = GetFileAttributesW(lpTempFileName);
124     if (FileAttributes == INVALID_FILE_ATTRIBUTES)
125     {
126         /* Append a '\' if necessary */
127         lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
128         lpTempFileName[PathNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
129         FileAttributes = GetFileAttributesW(lpTempFileName);
130         if (FileAttributes == INVALID_FILE_ATTRIBUTES)
131         {
132             SetLastError(ERROR_DIRECTORY);
133             return 0;
134         }
135     }
136     if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
137     {
138         SetLastError(ERROR_DIRECTORY);
139         return 0;
140     }
141 
142     /* Make sure not to mix path & prefix */
143     lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
144     RtlInitUnicodeString(&PrefixString, lpPrefixString);
145     if (PrefixString.Length > 3 * sizeof(WCHAR))
146     {
147         PrefixString.Length = 3 * sizeof(WCHAR);
148     }
149 
150     /* Append prefix to path */
151     TempFileName = lpTempFileName + PathNameString.Length / sizeof(WCHAR);
152     memmove(TempFileName, PrefixString.Buffer, PrefixString.Length);
153     TempFileName += PrefixString.Length / sizeof(WCHAR);
154 
155     /* Then, generate filename */
156     do
157     {
158         /* If user didn't gave any ID, ask Csrss to give one */
159         if (!uUnique)
160         {
161             CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
162                                 NULL,
163                                 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetTempFile),
164                                 sizeof(*GetTempFile));
165             if (GetTempFile->UniqueID == 0)
166             {
167                 Num++;
168                 continue;
169             }
170 
171             ID = GetTempFile->UniqueID;
172         }
173         else
174         {
175             ID = uUnique;
176         }
177 
178         /* Convert that ID to wchar */
179         RtlIntegerToChar(ID, 0x10, sizeof(IDString), (PCHAR)IDString);
180         Let = IDString;
181         do
182         {
183             *(TempFileName++) = RtlAnsiCharToUnicodeChar(&Let);
184         } while (*Let != 0);
185 
186         /* Append extension & UNICODE_NULL */
187         memmove(TempFileName, Ext, sizeof(Ext));
188 
189         /* If user provided its ID, just return */
190         if (uUnique)
191         {
192             return uUnique;
193         }
194 
195         /* Then, try to create file */
196         if (!RtlIsDosDeviceName_U(lpTempFileName))
197         {
198             TempFile = CreateFileW(lpTempFileName,
199                                    GENERIC_READ,
200                                    0,
201                                    NULL,
202                                    CREATE_NEW,
203                                    FILE_ATTRIBUTE_NORMAL,
204                                    0);
205             if (TempFile != INVALID_HANDLE_VALUE)
206             {
207                 NtClose(TempFile);
208                 DPRINT("Temp file: %S\n", lpTempFileName);
209                 return ID;
210             }
211 
212             LastError = GetLastError();
213             /* There is no need to recover from those errors, they would hit next step */
214             if (LastError == ERROR_INVALID_PARAMETER || LastError == ERROR_CANNOT_MAKE ||
215                 LastError == ERROR_WRITE_PROTECT || LastError == ERROR_NETWORK_ACCESS_DENIED ||
216                 LastError == ERROR_DISK_FULL || LastError == ERROR_INVALID_NAME ||
217                 LastError == ERROR_BAD_PATHNAME || LastError == ERROR_NO_INHERITANCE ||
218                 LastError == ERROR_DISK_CORRUPT ||
219                 (LastError == ERROR_ACCESS_DENIED && NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY))
220             {
221                 break;
222             }
223         }
224         Num++;
225     } while (Num & 0xFFFF);
226 
227     return 0;
228 }
229 
230 /*
231  * @implemented
232  */
233 BOOL
234 WINAPI
SetFileShortNameW(HANDLE hFile,LPCWSTR lpShortName)235 SetFileShortNameW(
236     HANDLE hFile,
237     LPCWSTR lpShortName)
238 {
239     NTSTATUS Status;
240     ULONG NeededSize;
241     UNICODE_STRING ShortName;
242     IO_STATUS_BLOCK IoStatusBlock;
243     PFILE_NAME_INFORMATION FileNameInfo;
244 
245     if(IsConsoleHandle(hFile))
246     {
247         SetLastError(ERROR_INVALID_HANDLE);
248         return FALSE;
249     }
250 
251     if(!lpShortName)
252     {
253         SetLastError(ERROR_INVALID_PARAMETER);
254         return FALSE;
255     }
256 
257     RtlInitUnicodeString(&ShortName, lpShortName);
258 
259     NeededSize = sizeof(FILE_NAME_INFORMATION) + ShortName.Length + sizeof(WCHAR);
260     if(!(FileNameInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize)))
261     {
262         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
263         return FALSE;
264     }
265 
266     FileNameInfo->FileNameLength = ShortName.Length;
267     RtlCopyMemory(FileNameInfo->FileName, ShortName.Buffer, ShortName.Length);
268 
269     Status = NtSetInformationFile(hFile,
270                                   &IoStatusBlock, //out
271                                   FileNameInfo,
272                                   NeededSize,
273                                   FileShortNameInformation);
274 
275     RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameInfo);
276     if(!NT_SUCCESS(Status))
277     {
278         BaseSetLastNTError(Status);
279         return FALSE;
280     }
281 
282     return TRUE;
283 }
284 
285 
286 /*
287  * @implemented
288  */
289 BOOL
290 WINAPI
SetFileShortNameA(HANDLE hFile,LPCSTR lpShortName)291 SetFileShortNameA(
292     HANDLE hFile,
293     LPCSTR lpShortName)
294 {
295     PWCHAR ShortNameW;
296 
297     if(IsConsoleHandle(hFile))
298     {
299         SetLastError(ERROR_INVALID_HANDLE);
300         return FALSE;
301     }
302 
303     if(!lpShortName)
304     {
305         SetLastError(ERROR_INVALID_PARAMETER);
306         return FALSE;
307     }
308 
309     if (!(ShortNameW = FilenameA2W(lpShortName, FALSE)))
310         return FALSE;
311 
312     return SetFileShortNameW(hFile, ShortNameW);
313 }
314 
315 
316 /*
317  * @implemented
318  */
319 BOOL
320 WINAPI
CheckNameLegalDOS8Dot3W(LPCWSTR lpName,LPSTR lpOemName OPTIONAL,DWORD OemNameSize OPTIONAL,PBOOL pbNameContainsSpaces OPTIONAL,PBOOL pbNameLegal)321 CheckNameLegalDOS8Dot3W(
322     LPCWSTR lpName,
323     LPSTR lpOemName OPTIONAL,
324     DWORD OemNameSize OPTIONAL,
325     PBOOL pbNameContainsSpaces OPTIONAL,
326     PBOOL pbNameLegal
327     )
328 {
329     UNICODE_STRING Name;
330     ANSI_STRING AnsiName;
331     BOOLEAN NameContainsSpaces;
332 
333     if(lpName == NULL ||
334        (lpOemName == NULL && OemNameSize != 0) ||
335        pbNameLegal == NULL)
336     {
337       SetLastError(ERROR_INVALID_PARAMETER);
338       return FALSE;
339     }
340 
341     if(lpOemName != NULL)
342     {
343       AnsiName.Buffer = lpOemName;
344       AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
345       AnsiName.Length = 0;
346     }
347 
348     RtlInitUnicodeString(&Name, lpName);
349 
350     *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
351                                           (lpOemName ? &AnsiName : NULL),
352                                           &NameContainsSpaces);
353     if (*pbNameLegal && pbNameContainsSpaces)
354         *pbNameContainsSpaces = NameContainsSpaces;
355 
356     return TRUE;
357 }
358 
359 
360 /*
361  * @implemented
362  */
363 BOOL
364 WINAPI
CheckNameLegalDOS8Dot3A(LPCSTR lpName,LPSTR lpOemName OPTIONAL,DWORD OemNameSize OPTIONAL,PBOOL pbNameContainsSpaces OPTIONAL,PBOOL pbNameLegal)365 CheckNameLegalDOS8Dot3A(
366     LPCSTR lpName,
367     LPSTR lpOemName OPTIONAL,
368     DWORD OemNameSize OPTIONAL,
369     PBOOL pbNameContainsSpaces OPTIONAL,
370     PBOOL pbNameLegal
371     )
372 {
373     UNICODE_STRING Name;
374     ANSI_STRING AnsiName, AnsiInputName;
375     NTSTATUS Status;
376     BOOLEAN NameContainsSpaces;
377 
378     if(lpName == NULL ||
379        (lpOemName == NULL && OemNameSize != 0) ||
380        pbNameLegal == NULL)
381     {
382       SetLastError(ERROR_INVALID_PARAMETER);
383       return FALSE;
384     }
385 
386     if(lpOemName != NULL)
387     {
388       AnsiName.Buffer = lpOemName;
389       AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
390       AnsiName.Length = 0;
391     }
392 
393     RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
394     if(bIsFileApiAnsi)
395       Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
396     else
397       Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
398 
399     if(!NT_SUCCESS(Status))
400     {
401       BaseSetLastNTError(Status);
402       return FALSE;
403     }
404 
405     *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
406                                           (lpOemName ? &AnsiName : NULL),
407                                           &NameContainsSpaces);
408     if (*pbNameLegal && pbNameContainsSpaces)
409         *pbNameContainsSpaces = NameContainsSpaces;
410 
411     RtlFreeUnicodeString(&Name);
412 
413     return TRUE;
414 }
415