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 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 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 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 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 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