Revert tree-restructure attempt: r66583, r66582, r66581, r66578, sauf ntdll changes...
[reactos.git] / reactos / dll / win32 / kernel32 / client / file / filename.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/file.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 CHAR * Let;
90 HANDLE TempFile;
91 UINT ID, Num = 0;
92 CHAR 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(BASE_GET_TEMP_FILE));
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), 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
332 if(lpName == NULL ||
333 (lpOemName == NULL && OemNameSize != 0) ||
334 pbNameLegal == NULL)
335 {
336 SetLastError(ERROR_INVALID_PARAMETER);
337 return FALSE;
338 }
339
340 if(lpOemName != NULL)
341 {
342 AnsiName.Buffer = lpOemName;
343 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
344 AnsiName.Length = 0;
345 }
346
347 RtlInitUnicodeString(&Name, lpName);
348
349 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
350 (lpOemName ? &AnsiName : NULL),
351 (BOOLEAN*)pbNameContainsSpaces);
352
353 return TRUE;
354 }
355
356
357 /*
358 * @implemented
359 */
360 BOOL
361 WINAPI
362 CheckNameLegalDOS8Dot3A(
363 LPCSTR lpName,
364 LPSTR lpOemName OPTIONAL,
365 DWORD OemNameSize OPTIONAL,
366 PBOOL pbNameContainsSpaces OPTIONAL,
367 PBOOL pbNameLegal
368 )
369 {
370 UNICODE_STRING Name;
371 ANSI_STRING AnsiName, AnsiInputName;
372 NTSTATUS Status;
373
374 if(lpName == NULL ||
375 (lpOemName == NULL && OemNameSize != 0) ||
376 pbNameLegal == NULL)
377 {
378 SetLastError(ERROR_INVALID_PARAMETER);
379 return FALSE;
380 }
381
382 if(lpOemName != NULL)
383 {
384 AnsiName.Buffer = lpOemName;
385 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
386 AnsiName.Length = 0;
387 }
388
389 RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
390 if(bIsFileApiAnsi)
391 Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
392 else
393 Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
394
395 if(!NT_SUCCESS(Status))
396 {
397 BaseSetLastNTError(Status);
398 return FALSE;
399 }
400
401 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
402 (lpOemName ? &AnsiName : NULL),
403 (BOOLEAN*)pbNameContainsSpaces);
404
405 RtlFreeUnicodeString(&Name);
406
407 return TRUE;
408 }