[KERNEL32]
[reactos.git] / 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.GetTempFile;
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 {
296 PWCHAR ShortNameW;
297
298 if(IsConsoleHandle(hFile))
299 {
300 SetLastError(ERROR_INVALID_HANDLE);
301 return FALSE;
302 }
303
304 if(!lpShortName)
305 {
306 SetLastError(ERROR_INVALID_PARAMETER);
307 return FALSE;
308 }
309
310 if (!(ShortNameW = FilenameA2W(lpShortName, FALSE)))
311 return FALSE;
312
313 return SetFileShortNameW(hFile, ShortNameW);
314 }
315
316
317 /*
318 * @implemented
319 */
320 BOOL
321 WINAPI
322 CheckNameLegalDOS8Dot3W(
323 LPCWSTR lpName,
324 LPSTR lpOemName OPTIONAL,
325 DWORD OemNameSize OPTIONAL,
326 PBOOL pbNameContainsSpaces OPTIONAL,
327 PBOOL pbNameLegal
328 )
329 {
330 UNICODE_STRING Name;
331 ANSI_STRING AnsiName;
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 (BOOLEAN*)pbNameContainsSpaces);
353
354 return TRUE;
355 }
356
357
358 /*
359 * @implemented
360 */
361 BOOL
362 WINAPI
363 CheckNameLegalDOS8Dot3A(
364 LPCSTR lpName,
365 LPSTR lpOemName OPTIONAL,
366 DWORD OemNameSize OPTIONAL,
367 PBOOL pbNameContainsSpaces OPTIONAL,
368 PBOOL pbNameLegal
369 )
370 {
371 UNICODE_STRING Name;
372 ANSI_STRING AnsiName, AnsiInputName;
373 NTSTATUS Status;
374
375 if(lpName == NULL ||
376 (lpOemName == NULL && OemNameSize != 0) ||
377 pbNameLegal == NULL)
378 {
379 SetLastError(ERROR_INVALID_PARAMETER);
380 return FALSE;
381 }
382
383 if(lpOemName != NULL)
384 {
385 AnsiName.Buffer = lpOemName;
386 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
387 AnsiName.Length = 0;
388 }
389
390 RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
391 if(bIsFileApiAnsi)
392 Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
393 else
394 Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
395
396 if(!NT_SUCCESS(Status))
397 {
398 BaseSetLastNTError(Status);
399 return FALSE;
400 }
401
402 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
403 (lpOemName ? &AnsiName : NULL),
404 (BOOLEAN*)pbNameContainsSpaces);
405
406 RtlFreeUnicodeString(&Name);
407
408 return TRUE;
409 }