1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: dll/win32/kernel32/client/file/create.c 5 * PURPOSE: Directory functions 6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) 7 * UPDATE HISTORY: 8 * Created 01/11/98 9 * Removed use of SearchPath (not used by Windows) 10 * 18/08/2002: CreateFileW mess cleaned up (KJK::Hyperion) 11 * 24/08/2002: removed superfluous DPRINTs (KJK::Hyperion) 12 */ 13 14 /* INCLUDES *****************************************************************/ 15 16 #include <k32.h> 17 #define NDEBUG 18 #include <debug.h> 19 20 #if DBG 21 DEBUG_CHANNEL(kernel32file); 22 #endif 23 24 /* FUNCTIONS ****************************************************************/ 25 26 /* 27 * @implemented 28 */ 29 HANDLE WINAPI CreateFileA (LPCSTR lpFileName, 30 DWORD dwDesiredAccess, 31 DWORD dwShareMode, 32 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 33 DWORD dwCreationDisposition, 34 DWORD dwFlagsAndAttributes, 35 HANDLE hTemplateFile) 36 { 37 PWCHAR FileNameW; 38 HANDLE FileHandle; 39 40 TRACE("CreateFileA(lpFileName %s)\n",lpFileName); 41 42 if (!(FileNameW = FilenameA2W(lpFileName, FALSE))) 43 return INVALID_HANDLE_VALUE; 44 45 FileHandle = CreateFileW (FileNameW, 46 dwDesiredAccess, 47 dwShareMode, 48 lpSecurityAttributes, 49 dwCreationDisposition, 50 dwFlagsAndAttributes, 51 hTemplateFile); 52 53 return FileHandle; 54 } 55 56 57 /* 58 * @implemented 59 */ 60 HANDLE WINAPI CreateFileW (LPCWSTR lpFileName, 61 DWORD dwDesiredAccess, 62 DWORD dwShareMode, 63 LPSECURITY_ATTRIBUTES lpSecurityAttributes, 64 DWORD dwCreationDisposition, 65 DWORD dwFlagsAndAttributes, 66 HANDLE hTemplateFile) 67 { 68 OBJECT_ATTRIBUTES ObjectAttributes; 69 IO_STATUS_BLOCK IoStatusBlock; 70 UNICODE_STRING NtPathU; 71 LPCWSTR pszConsoleFileName; 72 HANDLE FileHandle; 73 NTSTATUS Status; 74 ULONG FileAttributes, Flags = 0; 75 PVOID EaBuffer = NULL; 76 ULONG EaLength = 0; 77 BOOLEAN TrailingBackslash; 78 79 if (!lpFileName || !lpFileName[0]) 80 { 81 SetLastError( ERROR_PATH_NOT_FOUND ); 82 return INVALID_HANDLE_VALUE; 83 } 84 85 TRACE("CreateFileW(lpFileName %S)\n",lpFileName); 86 87 /* validate & translate the creation disposition */ 88 switch (dwCreationDisposition) 89 { 90 case CREATE_NEW: 91 dwCreationDisposition = FILE_CREATE; 92 break; 93 94 case CREATE_ALWAYS: 95 dwCreationDisposition = FILE_OVERWRITE_IF; 96 break; 97 98 case OPEN_EXISTING: 99 dwCreationDisposition = FILE_OPEN; 100 break; 101 102 case OPEN_ALWAYS: 103 dwCreationDisposition = FILE_OPEN_IF; 104 break; 105 106 case TRUNCATE_EXISTING: 107 dwCreationDisposition = FILE_OVERWRITE; 108 break; 109 110 default: 111 SetLastError(ERROR_INVALID_PARAMETER); 112 return (INVALID_HANDLE_VALUE); 113 } 114 115 /* check for console input/output */ 116 pszConsoleFileName = IntCheckForConsoleFileName(lpFileName, dwDesiredAccess); 117 if (pszConsoleFileName) 118 { 119 return OpenConsoleW(pszConsoleFileName, 120 dwDesiredAccess, 121 lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE, 122 FILE_SHARE_READ | FILE_SHARE_WRITE); 123 } 124 125 /* validate & translate the flags */ 126 127 /* translate the flags that need no validation */ 128 if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED)) 129 { 130 /* yes, nonalert is correct! apc's are not delivered 131 while waiting for file io to complete */ 132 Flags |= FILE_SYNCHRONOUS_IO_NONALERT; 133 } 134 135 if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH) 136 Flags |= FILE_WRITE_THROUGH; 137 138 if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING) 139 Flags |= FILE_NO_INTERMEDIATE_BUFFERING; 140 141 if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS) 142 Flags |= FILE_RANDOM_ACCESS; 143 144 if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN) 145 Flags |= FILE_SEQUENTIAL_ONLY; 146 147 if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE) 148 { 149 Flags |= FILE_DELETE_ON_CLOSE; 150 dwDesiredAccess |= DELETE; 151 } 152 153 if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS) 154 { 155 if(dwDesiredAccess & GENERIC_ALL) 156 Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REMOTE_INSTANCE; 157 else 158 { 159 if(dwDesiredAccess & GENERIC_READ) 160 Flags |= FILE_OPEN_FOR_BACKUP_INTENT; 161 162 if(dwDesiredAccess & GENERIC_WRITE) 163 Flags |= FILE_OPEN_REMOTE_INSTANCE; 164 } 165 } 166 else 167 Flags |= FILE_NON_DIRECTORY_FILE; 168 169 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT) 170 Flags |= FILE_OPEN_REPARSE_POINT; 171 172 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL) 173 Flags |= FILE_OPEN_NO_RECALL; 174 175 FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY)); 176 177 /* handle may always be waited on and querying attributes are always allowed */ 178 dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES; 179 180 /* FILE_FLAG_POSIX_SEMANTICS is handled later */ 181 182 /* validate & translate the filename */ 183 if (!RtlDosPathNameToNtPathName_U (lpFileName, 184 &NtPathU, 185 NULL, 186 NULL)) 187 { 188 WARN("Invalid path\n"); 189 SetLastError(ERROR_FILE_NOT_FOUND); 190 return INVALID_HANDLE_VALUE; 191 } 192 193 TRACE("NtPathU \'%wZ\'\n", &NtPathU); 194 195 TrailingBackslash = FALSE; 196 if (NtPathU.Length >= sizeof(WCHAR) && 197 NtPathU.Buffer[NtPathU.Length / sizeof(WCHAR) - 1]) 198 { 199 TrailingBackslash = TRUE; 200 } 201 202 if (hTemplateFile != NULL) 203 { 204 FILE_EA_INFORMATION EaInformation; 205 206 for (;;) 207 { 208 /* try to get the size of the extended attributes, if we fail just continue 209 creating the file without copying the attributes! */ 210 Status = NtQueryInformationFile(hTemplateFile, 211 &IoStatusBlock, 212 &EaInformation, 213 sizeof(FILE_EA_INFORMATION), 214 FileEaInformation); 215 if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0)) 216 { 217 /* there's extended attributes to read, let's give it a try */ 218 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 219 0, 220 EaInformation.EaSize); 221 if (EaBuffer == NULL) 222 { 223 RtlFreeHeap(RtlGetProcessHeap(), 224 0, 225 NtPathU.Buffer); 226 227 /* the template file handle is valid and has extended attributes, 228 however we seem to lack some memory here. We should fail here! */ 229 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 230 return INVALID_HANDLE_VALUE; 231 } 232 233 Status = NtQueryEaFile(hTemplateFile, 234 &IoStatusBlock, 235 EaBuffer, 236 EaInformation.EaSize, 237 FALSE, 238 NULL, 239 0, 240 NULL, 241 TRUE); 242 243 if (NT_SUCCESS(Status)) 244 { 245 /* we successfully read the extended attributes, break the loop 246 and continue */ 247 EaLength = EaInformation.EaSize; 248 break; 249 } 250 else 251 { 252 RtlFreeHeap(RtlGetProcessHeap(), 253 0, 254 EaBuffer); 255 EaBuffer = NULL; 256 257 if (Status != STATUS_BUFFER_TOO_SMALL) 258 { 259 /* unless we just allocated not enough memory, break the loop 260 and just continue without copying extended attributes */ 261 break; 262 } 263 } 264 } 265 else 266 { 267 /* we either failed to get the size of the extended attributes or 268 they're empty, just continue as there's no need to copy 269 attributes */ 270 break; 271 } 272 } 273 } 274 275 /* build the object attributes */ 276 InitializeObjectAttributes(&ObjectAttributes, 277 &NtPathU, 278 0, 279 NULL, 280 NULL); 281 282 if (lpSecurityAttributes) 283 { 284 if(lpSecurityAttributes->bInheritHandle) 285 ObjectAttributes.Attributes |= OBJ_INHERIT; 286 287 ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor; 288 } 289 290 if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS)) 291 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; 292 293 /* perform the call */ 294 Status = NtCreateFile (&FileHandle, 295 dwDesiredAccess, 296 &ObjectAttributes, 297 &IoStatusBlock, 298 NULL, 299 FileAttributes, 300 dwShareMode, 301 dwCreationDisposition, 302 Flags, 303 EaBuffer, 304 EaLength); 305 306 RtlFreeHeap(RtlGetProcessHeap(), 307 0, 308 NtPathU.Buffer); 309 310 /* free the extended attributes buffer if allocated */ 311 if (EaBuffer != NULL) 312 { 313 RtlFreeHeap(RtlGetProcessHeap(), 314 0, 315 EaBuffer); 316 } 317 318 /* error */ 319 if (!NT_SUCCESS(Status)) 320 { 321 /* In the case file creation was rejected due to CREATE_NEW flag 322 * was specified and file with that name already exists, correct 323 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS. 324 * Note: RtlNtStatusToDosError is not the subject to blame here. 325 */ 326 if (Status == STATUS_OBJECT_NAME_COLLISION && 327 dwCreationDisposition == FILE_CREATE) 328 { 329 SetLastError( ERROR_FILE_EXISTS ); 330 } 331 else if (Status == STATUS_FILE_IS_A_DIRECTORY && 332 TrailingBackslash) 333 { 334 SetLastError(ERROR_PATH_NOT_FOUND); 335 } 336 else 337 { 338 BaseSetLastNTError (Status); 339 } 340 341 return INVALID_HANDLE_VALUE; 342 } 343 344 /* 345 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED 346 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED 347 */ 348 if (dwCreationDisposition == FILE_OPEN_IF) 349 { 350 SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS); 351 } 352 else if (dwCreationDisposition == FILE_OVERWRITE_IF) 353 { 354 SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS); 355 } 356 else 357 { 358 SetLastError(ERROR_SUCCESS); 359 } 360 361 return FileHandle; 362 } 363 364 /* 365 * @implemented 366 */ 367 HFILE WINAPI 368 OpenFile(LPCSTR lpFileName, 369 LPOFSTRUCT lpReOpenBuff, 370 UINT uStyle) 371 { 372 OBJECT_ATTRIBUTES ObjectAttributes; 373 IO_STATUS_BLOCK IoStatusBlock; 374 UNICODE_STRING FileNameString; 375 UNICODE_STRING FileNameU; 376 ANSI_STRING FileName; 377 WCHAR PathNameW[MAX_PATH]; 378 HANDLE FileHandle = NULL; 379 NTSTATUS errCode; 380 PWCHAR FilePart; 381 ULONG Len; 382 383 TRACE("OpenFile('%s', lpReOpenBuff %p, uStyle %x)\n", lpFileName, lpReOpenBuff, uStyle); 384 385 if (lpReOpenBuff == NULL) 386 { 387 return HFILE_ERROR; 388 } 389 390 lpReOpenBuff->nErrCode = 0; 391 392 if (uStyle & OF_REOPEN) lpFileName = lpReOpenBuff->szPathName; 393 394 if (!lpFileName) 395 { 396 return HFILE_ERROR; 397 } 398 399 if (!GetFullPathNameA(lpFileName, 400 sizeof(lpReOpenBuff->szPathName), 401 lpReOpenBuff->szPathName, 402 NULL)) 403 { 404 lpReOpenBuff->nErrCode = (WORD)GetLastError(); 405 return HFILE_ERROR; 406 } 407 408 if (uStyle & OF_PARSE) 409 { 410 lpReOpenBuff->fFixedDisk = (GetDriveTypeA(lpReOpenBuff->szPathName) != DRIVE_REMOVABLE); 411 TRACE("(%s): OF_PARSE, res = '%s'\n", lpFileName, lpReOpenBuff->szPathName); 412 return 0; 413 } 414 415 if ((uStyle & OF_EXIST) && !(uStyle & OF_CREATE)) 416 { 417 DWORD dwAttributes = GetFileAttributesA(lpReOpenBuff->szPathName); 418 419 switch (dwAttributes) 420 { 421 case INVALID_FILE_ATTRIBUTES: /* File does not exist */ 422 SetLastError(ERROR_FILE_NOT_FOUND); 423 lpReOpenBuff->nErrCode = (WORD) ERROR_FILE_NOT_FOUND; 424 return -1; 425 426 case FILE_ATTRIBUTE_DIRECTORY: 427 SetLastError(ERROR_ACCESS_DENIED); 428 lpReOpenBuff->nErrCode = (WORD) ERROR_ACCESS_DENIED; 429 return -1; 430 431 default: 432 lpReOpenBuff->cBytes = sizeof(OFSTRUCT); 433 return 1; 434 } 435 } 436 lpReOpenBuff->cBytes = sizeof(OFSTRUCT); 437 if ((uStyle & OF_CREATE) == OF_CREATE) 438 { 439 DWORD Sharing; 440 switch (uStyle & 0x70) 441 { 442 case OF_SHARE_EXCLUSIVE: Sharing = 0; break; 443 case OF_SHARE_DENY_WRITE: Sharing = FILE_SHARE_READ; break; 444 case OF_SHARE_DENY_READ: Sharing = FILE_SHARE_WRITE; break; 445 case OF_SHARE_DENY_NONE: 446 case OF_SHARE_COMPAT: 447 default: 448 Sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; 449 } 450 return (HFILE)(ULONG_PTR) CreateFileA (lpFileName, 451 GENERIC_READ | GENERIC_WRITE, 452 Sharing, 453 NULL, 454 CREATE_ALWAYS, 455 FILE_ATTRIBUTE_NORMAL, 456 0); 457 } 458 459 RtlInitAnsiString (&FileName, (LPSTR)lpFileName); 460 461 /* convert ansi (or oem) string to unicode */ 462 if (bIsFileApiAnsi) 463 RtlAnsiStringToUnicodeString (&FileNameU, &FileName, TRUE); 464 else 465 RtlOemStringToUnicodeString (&FileNameU, &FileName, TRUE); 466 467 Len = SearchPathW (NULL, 468 FileNameU.Buffer, 469 NULL, 470 OFS_MAXPATHNAME, 471 PathNameW, 472 &FilePart); 473 474 RtlFreeUnicodeString(&FileNameU); 475 476 if (Len == 0 || Len > OFS_MAXPATHNAME) 477 { 478 lpReOpenBuff->nErrCode = (WORD)GetLastError(); 479 return HFILE_ERROR; 480 } 481 482 if (uStyle & OF_DELETE) 483 { 484 if (!DeleteFileW(PathNameW)) 485 { 486 lpReOpenBuff->nErrCode = (WORD)GetLastError(); 487 return HFILE_ERROR; 488 } 489 TRACE("(%s): OF_DELETE return = OK\n", lpFileName); 490 return TRUE; 491 } 492 493 FileName.Buffer = lpReOpenBuff->szPathName; 494 FileName.Length = 0; 495 FileName.MaximumLength = OFS_MAXPATHNAME; 496 497 RtlInitUnicodeString(&FileNameU, PathNameW); 498 499 /* convert unicode string to ansi (or oem) */ 500 if (bIsFileApiAnsi) 501 RtlUnicodeStringToAnsiString (&FileName, &FileNameU, FALSE); 502 else 503 RtlUnicodeStringToOemString (&FileName, &FileNameU, FALSE); 504 505 if (!RtlDosPathNameToNtPathName_U (PathNameW, 506 &FileNameString, 507 NULL, 508 NULL)) 509 { 510 return HFILE_ERROR; 511 } 512 513 // FILE_SHARE_READ 514 // FILE_NO_INTERMEDIATE_BUFFERING 515 516 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); 517 ObjectAttributes.RootDirectory = NULL; 518 ObjectAttributes.ObjectName = &FileNameString; 519 ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE| OBJ_INHERIT; 520 ObjectAttributes.SecurityDescriptor = NULL; 521 ObjectAttributes.SecurityQualityOfService = NULL; 522 523 errCode = NtOpenFile (&FileHandle, 524 GENERIC_READ | SYNCHRONIZE, 525 &ObjectAttributes, 526 &IoStatusBlock, 527 FILE_SHARE_READ, 528 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 529 530 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameString.Buffer); 531 532 lpReOpenBuff->nErrCode = (WORD)RtlNtStatusToDosError(errCode); 533 534 if (!NT_SUCCESS(errCode)) 535 { 536 BaseSetLastNTError (errCode); 537 return HFILE_ERROR; 538 } 539 540 if (uStyle & OF_EXIST) 541 { 542 NtClose(FileHandle); 543 return (HFILE)1; 544 } 545 546 return (HFILE)(ULONG_PTR)FileHandle; 547 } 548 549 /* 550 * @unimplemented 551 */ 552 BOOL 553 WINAPI 554 OpenDataFile(HANDLE hFile, DWORD dwUnused) 555 { 556 STUB; 557 return FALSE; 558 } 559 560 /* 561 * @unimplemented 562 */ 563 HANDLE 564 WINAPI 565 ReOpenFile(IN HANDLE hOriginalFile, 566 IN DWORD dwDesiredAccess, 567 IN DWORD dwShareMode, 568 IN DWORD dwFlags) 569 { 570 STUB; 571 return INVALID_HANDLE_VALUE; 572 } 573 574 /* EOF */ 575