[USB-BRINGUP-TRUNK]
[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, NULL, MAKE_CSR_API(GET_TEMP_FILE, CSR_NATIVE), sizeof(CSR_API_MESSAGE));
162 if (ApiMessage.Data.GetTempFile.UniqueID == 0)
163 {
164 Num++;
165 continue;
166 }
167
168 ID = ApiMessage.Data.GetTempFile.UniqueID;
169 }
170 else
171 {
172 ID = uUnique;
173 }
174
175 /* Convert that ID to wchar */
176 RtlIntegerToChar(ID, 0x10, sizeof(IDString), IDString);
177 Let = IDString;
178 do
179 {
180 *(TempFileName++) = RtlAnsiCharToUnicodeChar(&Let);
181 } while (*Let != 0);
182
183 /* Append extension & UNICODE_NULL */
184 memmove(TempFileName, Ext, sizeof(Ext));
185
186 /* If user provided its ID, just return */
187 if (uUnique)
188 {
189 return uUnique;
190 }
191
192 /* Then, try to create file */
193 if (!RtlIsDosDeviceName_U(lpTempFileName))
194 {
195 TempFile = CreateFileW(lpTempFileName,
196 GENERIC_READ,
197 0,
198 NULL,
199 CREATE_NEW,
200 FILE_ATTRIBUTE_NORMAL,
201 0);
202 if (TempFile != INVALID_HANDLE_VALUE)
203 {
204 NtClose(TempFile);
205 DPRINT("Temp file: %S\n", lpTempFileName);
206 return ID;
207 }
208
209 LastError = GetLastError();
210 /* There is no need to recover from those errors, they would hit next step */
211 if (LastError == ERROR_INVALID_PARAMETER || LastError == ERROR_CANNOT_MAKE ||
212 LastError == ERROR_WRITE_PROTECT || LastError == ERROR_NETWORK_ACCESS_DENIED ||
213 LastError == ERROR_DISK_FULL || LastError == ERROR_INVALID_NAME ||
214 LastError == ERROR_BAD_PATHNAME || LastError == ERROR_NO_INHERITANCE ||
215 LastError == ERROR_DISK_CORRUPT ||
216 (LastError == ERROR_ACCESS_DENIED && NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY))
217 {
218 break;
219 }
220 }
221 Num++;
222 } while (Num & 0xFFFF);
223
224 return 0;
225 }
226
227 /*
228 * @implemented
229 */
230 BOOL
231 WINAPI
232 SetFileShortNameW(
233 HANDLE hFile,
234 LPCWSTR lpShortName)
235 {
236 NTSTATUS Status;
237 ULONG NeededSize;
238 UNICODE_STRING ShortName;
239 IO_STATUS_BLOCK IoStatusBlock;
240 PFILE_NAME_INFORMATION FileNameInfo;
241
242 if(IsConsoleHandle(hFile))
243 {
244 SetLastError(ERROR_INVALID_HANDLE);
245 return FALSE;
246 }
247
248 if(!lpShortName)
249 {
250 SetLastError(ERROR_INVALID_PARAMETER);
251 return FALSE;
252 }
253
254 RtlInitUnicodeString(&ShortName, lpShortName);
255
256 NeededSize = sizeof(FILE_NAME_INFORMATION) + ShortName.Length + sizeof(WCHAR);
257 if(!(FileNameInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize)))
258 {
259 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
260 return FALSE;
261 }
262
263 FileNameInfo->FileNameLength = ShortName.Length;
264 RtlCopyMemory(FileNameInfo->FileName, ShortName.Buffer, ShortName.Length);
265
266 Status = NtSetInformationFile(hFile,
267 &IoStatusBlock, //out
268 FileNameInfo,
269 NeededSize,
270 FileShortNameInformation);
271
272 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameInfo);
273 if(!NT_SUCCESS(Status))
274 {
275 BaseSetLastNTError(Status);
276 return FALSE;
277 }
278
279 return TRUE;
280 }
281
282
283 /*
284 * @implemented
285 */
286 BOOL
287 WINAPI
288 SetFileShortNameA(
289 HANDLE hFile,
290 LPCSTR lpShortName
291 )
292 {
293 PWCHAR ShortNameW;
294
295 if(IsConsoleHandle(hFile))
296 {
297 SetLastError(ERROR_INVALID_HANDLE);
298 return FALSE;
299 }
300
301 if(!lpShortName)
302 {
303 SetLastError(ERROR_INVALID_PARAMETER);
304 return FALSE;
305 }
306
307 if (!(ShortNameW = FilenameA2W(lpShortName, FALSE)))
308 return FALSE;
309
310 return SetFileShortNameW(hFile, ShortNameW);
311 }
312
313
314 /*
315 * @implemented
316 */
317 BOOL
318 WINAPI
319 CheckNameLegalDOS8Dot3W(
320 LPCWSTR lpName,
321 LPSTR lpOemName OPTIONAL,
322 DWORD OemNameSize OPTIONAL,
323 PBOOL pbNameContainsSpaces OPTIONAL,
324 PBOOL pbNameLegal
325 )
326 {
327 UNICODE_STRING Name;
328 ANSI_STRING AnsiName;
329
330 if(lpName == NULL ||
331 (lpOemName == NULL && OemNameSize != 0) ||
332 pbNameLegal == NULL)
333 {
334 SetLastError(ERROR_INVALID_PARAMETER);
335 return FALSE;
336 }
337
338 if(lpOemName != NULL)
339 {
340 AnsiName.Buffer = lpOemName;
341 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
342 AnsiName.Length = 0;
343 }
344
345 RtlInitUnicodeString(&Name, lpName);
346
347 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
348 (lpOemName ? &AnsiName : NULL),
349 (BOOLEAN*)pbNameContainsSpaces);
350
351 return TRUE;
352 }
353
354
355 /*
356 * @implemented
357 */
358 BOOL
359 WINAPI
360 CheckNameLegalDOS8Dot3A(
361 LPCSTR lpName,
362 LPSTR lpOemName OPTIONAL,
363 DWORD OemNameSize OPTIONAL,
364 PBOOL pbNameContainsSpaces OPTIONAL,
365 PBOOL pbNameLegal
366 )
367 {
368 UNICODE_STRING Name;
369 ANSI_STRING AnsiName, AnsiInputName;
370 NTSTATUS Status;
371
372 if(lpName == NULL ||
373 (lpOemName == NULL && OemNameSize != 0) ||
374 pbNameLegal == NULL)
375 {
376 SetLastError(ERROR_INVALID_PARAMETER);
377 return FALSE;
378 }
379
380 if(lpOemName != NULL)
381 {
382 AnsiName.Buffer = lpOemName;
383 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
384 AnsiName.Length = 0;
385 }
386
387 RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
388 if(bIsFileApiAnsi)
389 Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
390 else
391 Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
392
393 if(!NT_SUCCESS(Status))
394 {
395 BaseSetLastNTError(Status);
396 return FALSE;
397 }
398
399 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
400 (lpOemName ? &AnsiName : NULL),
401 (BOOLEAN*)pbNameContainsSpaces);
402
403 RtlFreeUnicodeString(&Name);
404
405 return TRUE;
406 }