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
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
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
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
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
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
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