1e94be315a2c16c6f0064bd6fcaabddc463c107f
[reactos.git] / dll / win32 / kernel32 / client / file / filename.c
1 /* $Id: file.c 54310 2011-11-06 04:13:21Z ion $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/file.c
6 * PURPOSE: Directory functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <k32.h>
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS ******************************************************************/
20
21 /* FUNCTIONS ****************************************************************/
22
23 /***********************************************************************
24 * GetTempFileNameA (KERNEL32.@)
25 */
26 UINT WINAPI
27 GetTempFileNameA(IN LPCSTR lpPathName,
28 IN LPCSTR lpPrefixString,
29 IN UINT uUnique,
30 OUT LPSTR lpTempFileName)
31 {
32 UINT ID;
33 NTSTATUS Status;
34 LPWSTR lpTempFileNameW;
35 PUNICODE_STRING lpPathNameW;
36 ANSI_STRING TempFileNameStringA;
37 UNICODE_STRING lpPrefixStringW, TempFileNameStringW;
38
39 /* Convert strings */
40 lpPathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
41 if (!lpPathNameW)
42 {
43 return 0;
44 }
45
46 if (!Basep8BitStringToDynamicUnicodeString(&lpPrefixStringW, lpPrefixString))
47 {
48 return 0;
49 }
50
51 lpTempFileNameW = RtlAllocateHeap(RtlGetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
52 if (!lpTempFileNameW)
53 {
54 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
55 RtlFreeUnicodeString(&lpPrefixStringW);
56 return 0;
57 }
58
59 /* Call Unicode */
60 ID = GetTempFileNameW(lpPathNameW->Buffer, lpPrefixStringW.Buffer, uUnique, lpTempFileNameW);
61 if (ID)
62 {
63 RtlInitUnicodeString(&TempFileNameStringW, lpTempFileNameW);
64 TempFileNameStringA.Buffer = lpTempFileName;
65 TempFileNameStringA.MaximumLength = MAX_PATH;
66
67 Status = BasepUnicodeStringTo8BitString(&TempFileNameStringA, &TempFileNameStringW, FALSE);
68 if (!NT_SUCCESS(Status))
69 {
70 BaseSetLastNTError(Status);
71 ID = 0;
72 }
73 }
74
75 /* Cleanup */
76 RtlFreeUnicodeString(&lpPrefixStringW);
77 RtlFreeHeap(RtlGetProcessHeap(), 0, lpTempFileNameW);
78 return ID;
79 }
80
81 /***********************************************************************
82 * GetTempFileNameW (KERNEL32.@)
83 */
84 UINT WINAPI
85 GetTempFileNameW(IN LPCWSTR lpPathName,
86 IN LPCWSTR lpPrefixString,
87 IN UINT uUnique,
88 OUT LPWSTR lpTempFileName)
89 {
90 CHAR * Let;
91 HANDLE TempFile;
92 UINT ID, Num = 0;
93 CHAR IDString[5];
94 WCHAR * TempFileName;
95 CSR_API_MESSAGE ApiMessage;
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(&ApiMessage,
162 NULL,
163 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetTempFile),
164 sizeof(CSR_API_MESSAGE));
165 if (ApiMessage.Data.GetTempFile.UniqueID == 0)
166 {
167 Num++;
168 continue;
169 }
170
171 ID = ApiMessage.Data.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 }