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