1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: dll/win32/kernel32/client/file/fileinfo.c 5 * PURPOSE: Directory functions 6 * PROGRAMMER: 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 DEBUG_CHANNEL(kernel32file); 18 19 /* FUNCTIONS ****************************************************************/ 20 21 PWCHAR 22 FilenameA2W(LPCSTR NameA, BOOL alloc) 23 { 24 ANSI_STRING str; 25 UNICODE_STRING strW; 26 PUNICODE_STRING pstrW; 27 NTSTATUS Status; 28 29 //ASSERT(NtCurrentTeb()->StaticUnicodeString.Buffer == NtCurrentTeb()->StaticUnicodeBuffer); 30 ASSERT(NtCurrentTeb()->StaticUnicodeString.MaximumLength == sizeof(NtCurrentTeb()->StaticUnicodeBuffer)); 31 32 RtlInitAnsiString(&str, NameA); 33 pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString; 34 35 if (bIsFileApiAnsi) 36 Status= RtlAnsiStringToUnicodeString( pstrW, &str, (BOOLEAN)alloc ); 37 else 38 Status= RtlOemStringToUnicodeString( pstrW, &str, (BOOLEAN)alloc ); 39 40 if (NT_SUCCESS(Status)) 41 return pstrW->Buffer; 42 43 if (Status== STATUS_BUFFER_OVERFLOW) 44 SetLastError( ERROR_FILENAME_EXCED_RANGE ); 45 else 46 BaseSetLastNTError(Status); 47 48 return NULL; 49 } 50 51 52 /* 53 No copy/conversion is done if the dest. buffer is too small. 54 55 Returns: 56 Success: number of TCHARS copied into dest. buffer NOT including nullterm 57 Fail: size of buffer in TCHARS required to hold the converted filename, including nullterm 58 */ 59 DWORD 60 FilenameU2A_FitOrFail( 61 LPSTR DestA, 62 INT destLen, /* buffer size in TCHARS incl. nullchar */ 63 PUNICODE_STRING SourceU 64 ) 65 { 66 DWORD ret; 67 68 /* destLen should never exceed MAX_PATH */ 69 if (destLen > MAX_PATH) destLen = MAX_PATH; 70 71 ret = bIsFileApiAnsi? RtlUnicodeStringToAnsiSize(SourceU) : RtlUnicodeStringToOemSize(SourceU); 72 /* ret incl. nullchar */ 73 74 if (DestA && (INT)ret <= destLen) 75 { 76 ANSI_STRING str; 77 78 str.Buffer = DestA; 79 str.MaximumLength = (USHORT)destLen; 80 81 82 if (bIsFileApiAnsi) 83 RtlUnicodeStringToAnsiString(&str, SourceU, FALSE ); 84 else 85 RtlUnicodeStringToOemString(&str, SourceU, FALSE ); 86 87 ret = str.Length; /* SUCCESS: length without terminating 0 */ 88 } 89 90 return ret; 91 } 92 93 94 /* 95 No copy/conversion is done if the dest. buffer is too small. 96 97 Returns: 98 Success: number of TCHARS copied into dest. buffer NOT including nullterm 99 Fail: size of buffer in TCHARS required to hold the converted filename, including nullterm 100 */ 101 DWORD 102 FilenameW2A_FitOrFail( 103 LPSTR DestA, 104 INT destLen, /* buffer size in TCHARS incl. nullchar */ 105 LPCWSTR SourceW, 106 INT sourceLen /* buffer size in TCHARS incl. nullchar */ 107 ) 108 { 109 UNICODE_STRING strW; 110 111 if (sourceLen < 0) sourceLen = wcslen(SourceW) + 1; 112 113 strW.Buffer = (PWCHAR)SourceW; 114 strW.MaximumLength = sourceLen * sizeof(WCHAR); 115 strW.Length = strW.MaximumLength - sizeof(WCHAR); 116 117 return FilenameU2A_FitOrFail(DestA, destLen, &strW); 118 } 119 120 121 /* 122 Return: num. TCHARS copied into dest including nullterm 123 */ 124 DWORD 125 FilenameA2W_N( 126 LPWSTR dest, 127 INT destlen, /* buffer size in TCHARS incl. nullchar */ 128 LPCSTR src, 129 INT srclen /* buffer size in TCHARS incl. nullchar */ 130 ) 131 { 132 DWORD ret; 133 134 if (srclen < 0) srclen = strlen( src ) + 1; 135 136 if (bIsFileApiAnsi) 137 RtlMultiByteToUnicodeN( dest, destlen* sizeof(WCHAR), &ret, (LPSTR)src, srclen ); 138 else 139 RtlOemToUnicodeN( dest, destlen* sizeof(WCHAR), &ret, (LPSTR)src, srclen ); 140 141 if (ret) dest[(ret/sizeof(WCHAR))-1]=0; 142 143 return ret/sizeof(WCHAR); 144 } 145 146 /* 147 Return: num. TCHARS copied into dest including nullterm 148 */ 149 DWORD 150 FilenameW2A_N( 151 LPSTR dest, 152 INT destlen, /* buffer size in TCHARS incl. nullchar */ 153 LPCWSTR src, 154 INT srclen /* buffer size in TCHARS incl. nullchar */ 155 ) 156 { 157 DWORD ret; 158 159 if (srclen < 0) srclen = wcslen( src ) + 1; 160 161 if (bIsFileApiAnsi) 162 RtlUnicodeToMultiByteN( dest, destlen, &ret, (LPWSTR) src, srclen * sizeof(WCHAR)); 163 else 164 RtlUnicodeToOemN( dest, destlen, &ret, (LPWSTR) src, srclen * sizeof(WCHAR) ); 165 166 if (ret) dest[ret-1]=0; 167 168 return ret; 169 } 170 171 /* 172 * @implemented 173 */ 174 BOOL WINAPI 175 FlushFileBuffers(IN HANDLE hFile) 176 { 177 NTSTATUS Status; 178 IO_STATUS_BLOCK IoStatusBlock; 179 180 hFile = TranslateStdHandle(hFile); 181 182 if (IsConsoleHandle(hFile)) 183 { 184 return FlushConsoleInputBuffer(hFile); 185 } 186 187 Status = NtFlushBuffersFile(hFile, 188 &IoStatusBlock); 189 if (!NT_SUCCESS(Status)) 190 { 191 BaseSetLastNTError(Status); 192 return FALSE; 193 } 194 return TRUE; 195 } 196 197 198 /* 199 * @implemented 200 */ 201 DWORD 202 WINAPI 203 DECLSPEC_HOTPATCH 204 SetFilePointer(HANDLE hFile, 205 LONG lDistanceToMove, 206 PLONG lpDistanceToMoveHigh, 207 DWORD dwMoveMethod) 208 { 209 FILE_POSITION_INFORMATION FilePosition; 210 FILE_STANDARD_INFORMATION FileStandard; 211 NTSTATUS errCode; 212 IO_STATUS_BLOCK IoStatusBlock; 213 LARGE_INTEGER Distance; 214 215 TRACE("SetFilePointer(hFile %p, lDistanceToMove %d, dwMoveMethod %lu)\n", 216 hFile,lDistanceToMove,dwMoveMethod); 217 218 if(IsConsoleHandle(hFile)) 219 { 220 SetLastError(ERROR_INVALID_HANDLE); 221 return INVALID_SET_FILE_POINTER; 222 } 223 224 if (lpDistanceToMoveHigh) 225 { 226 Distance.u.HighPart = *lpDistanceToMoveHigh; 227 Distance.u.LowPart = lDistanceToMove; 228 } 229 else 230 { 231 Distance.QuadPart = lDistanceToMove; 232 } 233 234 switch(dwMoveMethod) 235 { 236 case FILE_CURRENT: 237 errCode = NtQueryInformationFile(hFile, 238 &IoStatusBlock, 239 &FilePosition, 240 sizeof(FILE_POSITION_INFORMATION), 241 FilePositionInformation); 242 FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart; 243 if (!NT_SUCCESS(errCode)) 244 { 245 if (lpDistanceToMoveHigh != NULL) 246 *lpDistanceToMoveHigh = -1; 247 BaseSetLastNTError(errCode); 248 return INVALID_SET_FILE_POINTER; 249 } 250 break; 251 case FILE_END: 252 errCode = NtQueryInformationFile(hFile, 253 &IoStatusBlock, 254 &FileStandard, 255 sizeof(FILE_STANDARD_INFORMATION), 256 FileStandardInformation); 257 FilePosition.CurrentByteOffset.QuadPart = 258 FileStandard.EndOfFile.QuadPart + Distance.QuadPart; 259 if (!NT_SUCCESS(errCode)) 260 { 261 if (lpDistanceToMoveHigh != NULL) 262 *lpDistanceToMoveHigh = -1; 263 BaseSetLastNTError(errCode); 264 return INVALID_SET_FILE_POINTER; 265 } 266 break; 267 case FILE_BEGIN: 268 FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart; 269 break; 270 default: 271 SetLastError(ERROR_INVALID_PARAMETER); 272 return INVALID_SET_FILE_POINTER; 273 } 274 275 if(FilePosition.CurrentByteOffset.QuadPart < 0) 276 { 277 SetLastError(ERROR_NEGATIVE_SEEK); 278 return INVALID_SET_FILE_POINTER; 279 } 280 281 if (lpDistanceToMoveHigh == NULL && FilePosition.CurrentByteOffset.HighPart != 0) 282 { 283 /* If we're moving the pointer outside of the 32 bit boundaries but 284 the application only passed a 32 bit value we need to bail out! */ 285 SetLastError(ERROR_INVALID_PARAMETER); 286 return INVALID_SET_FILE_POINTER; 287 } 288 289 errCode = NtSetInformationFile(hFile, 290 &IoStatusBlock, 291 &FilePosition, 292 sizeof(FILE_POSITION_INFORMATION), 293 FilePositionInformation); 294 if (!NT_SUCCESS(errCode)) 295 { 296 if (lpDistanceToMoveHigh != NULL) 297 *lpDistanceToMoveHigh = -1; 298 299 BaseSetLastNTError(errCode); 300 return INVALID_SET_FILE_POINTER; 301 } 302 303 if (lpDistanceToMoveHigh != NULL) 304 { 305 *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart; 306 } 307 308 if (FilePosition.CurrentByteOffset.u.LowPart == MAXDWORD) 309 { 310 /* The value of -1 is valid here, especially when the new 311 file position is greater than 4 GB. Since NtSetInformationFile 312 succeeded we never set an error code and we explicitly need 313 to clear a previously set error code in this case, which 314 an application will check if INVALID_SET_FILE_POINTER is returned! */ 315 SetLastError(ERROR_SUCCESS); 316 } 317 318 return FilePosition.CurrentByteOffset.u.LowPart; 319 } 320 321 322 /* 323 * @implemented 324 */ 325 BOOL 326 WINAPI 327 SetFilePointerEx(HANDLE hFile, 328 LARGE_INTEGER liDistanceToMove, 329 PLARGE_INTEGER lpNewFilePointer, 330 DWORD dwMoveMethod) 331 { 332 NTSTATUS Status; 333 IO_STATUS_BLOCK IoStatusBlock; 334 FILE_POSITION_INFORMATION FilePosition; 335 FILE_STANDARD_INFORMATION FileStandard; 336 337 if (IsConsoleHandle(hFile)) 338 { 339 BaseSetLastNTError(STATUS_INVALID_HANDLE); 340 return FALSE; 341 } 342 343 switch (dwMoveMethod) 344 { 345 case FILE_CURRENT: 346 { 347 Status = NtQueryInformationFile(hFile, &IoStatusBlock, 348 &FilePosition, 349 sizeof(FILE_POSITION_INFORMATION), 350 FilePositionInformation); 351 if (!NT_SUCCESS(Status)) 352 { 353 BaseSetLastNTError(Status); 354 return FALSE; 355 } 356 357 FilePosition.CurrentByteOffset.QuadPart += liDistanceToMove.QuadPart; 358 break; 359 } 360 361 case FILE_END: 362 { 363 Status = NtQueryInformationFile(hFile, &IoStatusBlock, 364 &FileStandard, 365 sizeof(FILE_STANDARD_INFORMATION), 366 FileStandardInformation); 367 if (!NT_SUCCESS(Status)) 368 { 369 BaseSetLastNTError(Status); 370 return FALSE; 371 } 372 373 FilePosition.CurrentByteOffset.QuadPart = FileStandard.EndOfFile.QuadPart + 374 liDistanceToMove.QuadPart; 375 break; 376 } 377 378 case FILE_BEGIN: 379 { 380 FilePosition.CurrentByteOffset.QuadPart = liDistanceToMove.QuadPart; 381 break; 382 } 383 384 default: 385 { 386 SetLastError(ERROR_INVALID_PARAMETER); 387 return FALSE; 388 } 389 } 390 391 if (FilePosition.CurrentByteOffset.QuadPart < 0) 392 { 393 SetLastError(ERROR_NEGATIVE_SEEK); 394 return FALSE; 395 } 396 397 Status = NtSetInformationFile(hFile, &IoStatusBlock, &FilePosition, 398 sizeof(FILE_POSITION_INFORMATION), 399 FilePositionInformation); 400 if (!NT_SUCCESS(Status)) 401 { 402 BaseSetLastNTError(Status); 403 return FALSE; 404 } 405 406 if (lpNewFilePointer != NULL) 407 { 408 *lpNewFilePointer = FilePosition.CurrentByteOffset; 409 } 410 411 return TRUE; 412 } 413 414 415 /* 416 * @implemented 417 */ 418 DWORD WINAPI 419 GetFileType(HANDLE hFile) 420 { 421 FILE_FS_DEVICE_INFORMATION DeviceInfo; 422 IO_STATUS_BLOCK StatusBlock; 423 NTSTATUS Status; 424 425 /* Get real handle */ 426 hFile = TranslateStdHandle(hFile); 427 428 /* Check for console handle */ 429 if (IsConsoleHandle(hFile)) 430 { 431 if (VerifyConsoleIoHandle(hFile)) 432 return FILE_TYPE_CHAR; 433 } 434 435 Status = NtQueryVolumeInformationFile(hFile, 436 &StatusBlock, 437 &DeviceInfo, 438 sizeof(FILE_FS_DEVICE_INFORMATION), 439 FileFsDeviceInformation); 440 if (!NT_SUCCESS(Status)) 441 { 442 BaseSetLastNTError(Status); 443 return FILE_TYPE_UNKNOWN; 444 } 445 446 switch (DeviceInfo.DeviceType) 447 { 448 case FILE_DEVICE_CD_ROM: 449 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 450 case FILE_DEVICE_CONTROLLER: 451 case FILE_DEVICE_DATALINK: 452 case FILE_DEVICE_DFS: 453 case FILE_DEVICE_DISK: 454 case FILE_DEVICE_DISK_FILE_SYSTEM: 455 case FILE_DEVICE_VIRTUAL_DISK: 456 return FILE_TYPE_DISK; 457 458 case FILE_DEVICE_KEYBOARD: 459 case FILE_DEVICE_MOUSE: 460 case FILE_DEVICE_NULL: 461 case FILE_DEVICE_PARALLEL_PORT: 462 case FILE_DEVICE_PRINTER: 463 case FILE_DEVICE_SERIAL_PORT: 464 case FILE_DEVICE_SCREEN: 465 case FILE_DEVICE_SOUND: 466 case FILE_DEVICE_MODEM: 467 return FILE_TYPE_CHAR; 468 469 case FILE_DEVICE_NAMED_PIPE: 470 return FILE_TYPE_PIPE; 471 } 472 473 return FILE_TYPE_UNKNOWN; 474 } 475 476 477 /* 478 * @implemented 479 */ 480 DWORD WINAPI 481 GetFileSize(HANDLE hFile, 482 LPDWORD lpFileSizeHigh) 483 { 484 NTSTATUS errCode; 485 FILE_STANDARD_INFORMATION FileStandard; 486 IO_STATUS_BLOCK IoStatusBlock; 487 488 errCode = NtQueryInformationFile(hFile, 489 &IoStatusBlock, 490 &FileStandard, 491 sizeof(FILE_STANDARD_INFORMATION), 492 FileStandardInformation); 493 if (!NT_SUCCESS(errCode)) 494 { 495 BaseSetLastNTError(errCode); 496 if ( lpFileSizeHigh == NULL ) 497 { 498 return -1; 499 } 500 else 501 { 502 return 0; 503 } 504 } 505 if ( lpFileSizeHigh != NULL ) 506 *lpFileSizeHigh = FileStandard.EndOfFile.u.HighPart; 507 508 return FileStandard.EndOfFile.u.LowPart; 509 } 510 511 512 /* 513 * @implemented 514 */ 515 BOOL 516 WINAPI 517 GetFileSizeEx( 518 HANDLE hFile, 519 PLARGE_INTEGER lpFileSize 520 ) 521 { 522 NTSTATUS errCode; 523 FILE_STANDARD_INFORMATION FileStandard; 524 IO_STATUS_BLOCK IoStatusBlock; 525 526 errCode = NtQueryInformationFile(hFile, 527 &IoStatusBlock, 528 &FileStandard, 529 sizeof(FILE_STANDARD_INFORMATION), 530 FileStandardInformation); 531 if (!NT_SUCCESS(errCode)) 532 { 533 BaseSetLastNTError(errCode); 534 return FALSE; 535 } 536 if (lpFileSize) 537 *lpFileSize = FileStandard.EndOfFile; 538 539 return TRUE; 540 } 541 542 543 /* 544 * @implemented 545 */ 546 DWORD WINAPI 547 GetCompressedFileSizeA(LPCSTR lpFileName, 548 LPDWORD lpFileSizeHigh) 549 { 550 PWCHAR FileNameW; 551 552 if (!(FileNameW = FilenameA2W(lpFileName, FALSE))) 553 return INVALID_FILE_SIZE; 554 555 return GetCompressedFileSizeW(FileNameW, lpFileSizeHigh); 556 } 557 558 559 /* 560 * @implemented 561 */ 562 DWORD WINAPI 563 GetCompressedFileSizeW(LPCWSTR lpFileName, 564 LPDWORD lpFileSizeHigh) 565 { 566 FILE_COMPRESSION_INFORMATION FileCompression; 567 NTSTATUS errCode; 568 IO_STATUS_BLOCK IoStatusBlock; 569 HANDLE hFile; 570 571 hFile = CreateFileW(lpFileName, 572 GENERIC_READ, 573 FILE_SHARE_READ, 574 NULL, 575 OPEN_EXISTING, 576 FILE_ATTRIBUTE_NORMAL, 577 NULL); 578 579 if (hFile == INVALID_HANDLE_VALUE) 580 return INVALID_FILE_SIZE; 581 582 errCode = NtQueryInformationFile(hFile, 583 &IoStatusBlock, 584 &FileCompression, 585 sizeof(FILE_COMPRESSION_INFORMATION), 586 FileCompressionInformation); 587 588 CloseHandle(hFile); 589 590 if (!NT_SUCCESS(errCode)) 591 { 592 BaseSetLastNTError(errCode); 593 return INVALID_FILE_SIZE; 594 } 595 596 if(lpFileSizeHigh) 597 *lpFileSizeHigh = FileCompression.CompressedFileSize.u.HighPart; 598 599 SetLastError(NO_ERROR); 600 return FileCompression.CompressedFileSize.u.LowPart; 601 } 602 603 604 /* 605 * @implemented 606 */ 607 BOOL WINAPI 608 GetFileInformationByHandle(HANDLE hFile, 609 LPBY_HANDLE_FILE_INFORMATION lpFileInformation) 610 { 611 struct 612 { 613 FILE_FS_VOLUME_INFORMATION FileFsVolume; 614 WCHAR Name[255]; 615 } 616 FileFsVolume; 617 618 FILE_BASIC_INFORMATION FileBasic; 619 FILE_INTERNAL_INFORMATION FileInternal; 620 FILE_STANDARD_INFORMATION FileStandard; 621 NTSTATUS errCode; 622 IO_STATUS_BLOCK IoStatusBlock; 623 624 if(IsConsoleHandle(hFile)) 625 { 626 SetLastError(ERROR_INVALID_HANDLE); 627 return FALSE; 628 } 629 630 errCode = NtQueryInformationFile(hFile, 631 &IoStatusBlock, 632 &FileBasic, 633 sizeof(FILE_BASIC_INFORMATION), 634 FileBasicInformation); 635 if (!NT_SUCCESS(errCode)) 636 { 637 BaseSetLastNTError(errCode); 638 return FALSE; 639 } 640 641 lpFileInformation->dwFileAttributes = (DWORD)FileBasic.FileAttributes; 642 643 lpFileInformation->ftCreationTime.dwHighDateTime = FileBasic.CreationTime.u.HighPart; 644 lpFileInformation->ftCreationTime.dwLowDateTime = FileBasic.CreationTime.u.LowPart; 645 646 lpFileInformation->ftLastAccessTime.dwHighDateTime = FileBasic.LastAccessTime.u.HighPart; 647 lpFileInformation->ftLastAccessTime.dwLowDateTime = FileBasic.LastAccessTime.u.LowPart; 648 649 lpFileInformation->ftLastWriteTime.dwHighDateTime = FileBasic.LastWriteTime.u.HighPart; 650 lpFileInformation->ftLastWriteTime.dwLowDateTime = FileBasic.LastWriteTime.u.LowPart; 651 652 errCode = NtQueryInformationFile(hFile, 653 &IoStatusBlock, 654 &FileInternal, 655 sizeof(FILE_INTERNAL_INFORMATION), 656 FileInternalInformation); 657 if (!NT_SUCCESS(errCode)) 658 { 659 BaseSetLastNTError(errCode); 660 return FALSE; 661 } 662 663 lpFileInformation->nFileIndexHigh = FileInternal.IndexNumber.u.HighPart; 664 lpFileInformation->nFileIndexLow = FileInternal.IndexNumber.u.LowPart; 665 666 errCode = NtQueryVolumeInformationFile(hFile, 667 &IoStatusBlock, 668 &FileFsVolume, 669 sizeof(FileFsVolume), 670 FileFsVolumeInformation); 671 if (!NT_SUCCESS(errCode)) 672 { 673 BaseSetLastNTError(errCode); 674 return FALSE; 675 } 676 677 lpFileInformation->dwVolumeSerialNumber = FileFsVolume.FileFsVolume.VolumeSerialNumber; 678 679 errCode = NtQueryInformationFile(hFile, 680 &IoStatusBlock, 681 &FileStandard, 682 sizeof(FILE_STANDARD_INFORMATION), 683 FileStandardInformation); 684 if (!NT_SUCCESS(errCode)) 685 { 686 BaseSetLastNTError(errCode); 687 return FALSE; 688 } 689 690 lpFileInformation->nNumberOfLinks = FileStandard.NumberOfLinks; 691 lpFileInformation->nFileSizeHigh = FileStandard.EndOfFile.u.HighPart; 692 lpFileInformation->nFileSizeLow = FileStandard.EndOfFile.u.LowPart; 693 694 return TRUE; 695 } 696 697 698 /* 699 * @implemented 700 */ 701 BOOL WINAPI 702 GetFileAttributesExW(LPCWSTR lpFileName, 703 GET_FILEEX_INFO_LEVELS fInfoLevelId, 704 LPVOID lpFileInformation) 705 { 706 FILE_NETWORK_OPEN_INFORMATION FileInformation; 707 OBJECT_ATTRIBUTES ObjectAttributes; 708 UNICODE_STRING FileName; 709 NTSTATUS Status; 710 WIN32_FILE_ATTRIBUTE_DATA* FileAttributeData; 711 712 TRACE("GetFileAttributesExW(%S) called\n", lpFileName); 713 714 715 if (fInfoLevelId != GetFileExInfoStandard || lpFileInformation == NULL) 716 { 717 SetLastError(ERROR_INVALID_PARAMETER); 718 return FALSE; 719 } 720 721 /* Validate and translate the filename */ 722 if (!RtlDosPathNameToNtPathName_U (lpFileName, 723 &FileName, 724 NULL, 725 NULL)) 726 { 727 WARN ("Invalid path '%S'\n", lpFileName); 728 SetLastError (ERROR_BAD_PATHNAME); 729 return FALSE; 730 } 731 732 /* build the object attributes */ 733 InitializeObjectAttributes (&ObjectAttributes, 734 &FileName, 735 OBJ_CASE_INSENSITIVE, 736 NULL, 737 NULL); 738 739 /* Get file attributes */ 740 Status = NtQueryFullAttributesFile(&ObjectAttributes, 741 &FileInformation); 742 743 RtlFreeUnicodeString (&FileName); 744 if (!NT_SUCCESS (Status)) 745 { 746 WARN ("NtQueryFullAttributesFile() failed (Status %lx)\n", Status); 747 BaseSetLastNTError (Status); 748 return FALSE; 749 } 750 751 FileAttributeData = (WIN32_FILE_ATTRIBUTE_DATA*)lpFileInformation; 752 FileAttributeData->dwFileAttributes = FileInformation.FileAttributes; 753 FileAttributeData->ftCreationTime.dwLowDateTime = FileInformation.CreationTime.u.LowPart; 754 FileAttributeData->ftCreationTime.dwHighDateTime = FileInformation.CreationTime.u.HighPart; 755 FileAttributeData->ftLastAccessTime.dwLowDateTime = FileInformation.LastAccessTime.u.LowPart; 756 FileAttributeData->ftLastAccessTime.dwHighDateTime = FileInformation.LastAccessTime.u.HighPart; 757 FileAttributeData->ftLastWriteTime.dwLowDateTime = FileInformation.LastWriteTime.u.LowPart; 758 FileAttributeData->ftLastWriteTime.dwHighDateTime = FileInformation.LastWriteTime.u.HighPart; 759 FileAttributeData->nFileSizeLow = FileInformation.EndOfFile.u.LowPart; 760 FileAttributeData->nFileSizeHigh = FileInformation.EndOfFile.u.HighPart; 761 762 return TRUE; 763 } 764 765 /* 766 * @implemented 767 */ 768 BOOL WINAPI 769 GetFileAttributesExA(LPCSTR lpFileName, 770 GET_FILEEX_INFO_LEVELS fInfoLevelId, 771 LPVOID lpFileInformation) 772 { 773 PWCHAR FileNameW; 774 775 if (!(FileNameW = FilenameA2W(lpFileName, FALSE))) 776 return FALSE; 777 778 return GetFileAttributesExW(FileNameW, fInfoLevelId, lpFileInformation); 779 } 780 781 782 /* 783 * @implemented 784 */ 785 DWORD WINAPI 786 GetFileAttributesA(LPCSTR lpFileName) 787 { 788 PWSTR FileNameW; 789 790 if (!lpFileName || !(FileNameW = FilenameA2W(lpFileName, FALSE))) 791 return INVALID_FILE_ATTRIBUTES; 792 793 return GetFileAttributesW(FileNameW); 794 } 795 796 797 /* 798 * @implemented 799 */ 800 DWORD 801 WINAPI 802 GetFileAttributesW(LPCWSTR lpFileName) 803 { 804 NTSTATUS Status; 805 UNICODE_STRING FileName; 806 OBJECT_ATTRIBUTES ObjectAttributes; 807 FILE_BASIC_INFORMATION FileInformation; 808 809 /* Get the NT path name */ 810 if (!RtlDosPathNameToNtPathName_U(lpFileName, &FileName, NULL, NULL)) 811 { 812 SetLastError(ERROR_PATH_NOT_FOUND); 813 return INVALID_FILE_ATTRIBUTES; 814 } 815 816 /* Prepare for querying attributes */ 817 InitializeObjectAttributes(&ObjectAttributes, &FileName, 818 OBJ_CASE_INSENSITIVE, 819 NULL, NULL); 820 /* Simply query attributes */ 821 Status = NtQueryAttributesFile(&ObjectAttributes, &FileInformation); 822 if (!NT_SUCCESS(Status)) 823 { 824 /* It failed? Is it a DOS device? */ 825 if (RtlIsDosDeviceName_U(lpFileName)) 826 { 827 return FILE_ATTRIBUTE_ARCHIVE; 828 } 829 830 /* Set the error otherwise */ 831 BaseSetLastNTError(Status); 832 return INVALID_FILE_ATTRIBUTES; 833 } 834 835 /* Return the file attributes */ 836 return FileInformation.FileAttributes; 837 } 838 839 840 /* 841 * @implemented 842 */ 843 BOOL WINAPI 844 GetFileAttributesByHandle(IN HANDLE hFile, 845 OUT LPDWORD dwFileAttributes, 846 IN DWORD dwFlags) 847 { 848 FILE_BASIC_INFORMATION FileBasic; 849 IO_STATUS_BLOCK IoStatusBlock; 850 NTSTATUS Status; 851 852 UNREFERENCED_PARAMETER(dwFlags); 853 854 if (IsConsoleHandle(hFile)) 855 { 856 SetLastError(ERROR_INVALID_HANDLE); 857 return FALSE; 858 } 859 860 Status = NtQueryInformationFile(hFile, 861 &IoStatusBlock, 862 &FileBasic, 863 sizeof(FileBasic), 864 FileBasicInformation); 865 if (NT_SUCCESS(Status)) 866 { 867 *dwFileAttributes = FileBasic.FileAttributes; 868 return TRUE; 869 } 870 871 BaseSetLastNTError(Status); 872 return FALSE; 873 } 874 875 876 /* 877 * @implemented 878 */ 879 BOOL WINAPI 880 SetFileAttributesByHandle(IN HANDLE hFile, 881 IN DWORD dwFileAttributes, 882 IN DWORD dwFlags) 883 { 884 FILE_BASIC_INFORMATION FileBasic; 885 IO_STATUS_BLOCK IoStatusBlock; 886 NTSTATUS Status; 887 888 UNREFERENCED_PARAMETER(dwFlags); 889 890 if (IsConsoleHandle(hFile)) 891 { 892 SetLastError(ERROR_INVALID_HANDLE); 893 return FALSE; 894 } 895 896 Status = NtQueryInformationFile(hFile, 897 &IoStatusBlock, 898 &FileBasic, 899 sizeof(FileBasic), 900 FileBasicInformation); 901 if (NT_SUCCESS(Status)) 902 { 903 FileBasic.FileAttributes = dwFileAttributes; 904 905 Status = NtSetInformationFile(hFile, 906 &IoStatusBlock, 907 &FileBasic, 908 sizeof(FileBasic), 909 FileBasicInformation); 910 } 911 912 if (!NT_SUCCESS(Status)) 913 { 914 BaseSetLastNTError(Status); 915 return FALSE; 916 } 917 918 return TRUE; 919 } 920 921 922 /* 923 * @implemented 924 */ 925 BOOL WINAPI 926 SetFileAttributesA( 927 LPCSTR lpFileName, 928 DWORD dwFileAttributes) 929 { 930 PWCHAR FileNameW; 931 932 if (!(FileNameW = FilenameA2W(lpFileName, FALSE))) 933 return FALSE; 934 935 return SetFileAttributesW(FileNameW, dwFileAttributes); 936 } 937 938 939 /* 940 * @implemented 941 */ 942 BOOL 943 WINAPI 944 SetFileAttributesW(LPCWSTR lpFileName, 945 DWORD dwFileAttributes) 946 { 947 NTSTATUS Status; 948 PWSTR PathUBuffer; 949 HANDLE FileHandle; 950 UNICODE_STRING NtPathU; 951 IO_STATUS_BLOCK IoStatusBlock; 952 RTL_RELATIVE_NAME_U RelativeName; 953 OBJECT_ATTRIBUTES ObjectAttributes; 954 FILE_BASIC_INFORMATION FileInformation; 955 956 /* Get relative name */ 957 if (!RtlDosPathNameToRelativeNtPathName_U(lpFileName, &NtPathU, NULL, &RelativeName)) 958 { 959 SetLastError(ERROR_PATH_NOT_FOUND); 960 return FALSE; 961 } 962 963 /* Save buffer to allow later freeing */ 964 PathUBuffer = NtPathU.Buffer; 965 966 /* If we have relative name (and root dir), use them instead */ 967 if (RelativeName.RelativeName.Length != 0) 968 { 969 NtPathU.Length = RelativeName.RelativeName.Length; 970 NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength; 971 NtPathU.Buffer = RelativeName.RelativeName.Buffer; 972 } 973 else 974 { 975 RelativeName.ContainingDirectory = NULL; 976 } 977 978 /* Prepare the object attribute for opening the file */ 979 InitializeObjectAttributes(&ObjectAttributes, &NtPathU, 980 OBJ_CASE_INSENSITIVE, 981 RelativeName.ContainingDirectory, NULL); 982 983 /* Attempt to open the file, while supporting reparse point */ 984 Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, 985 &ObjectAttributes, &IoStatusBlock, 986 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 987 FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT); 988 /* If opening failed, check whether it was because of reparse point support */ 989 if (!NT_SUCCESS(Status)) 990 { 991 /* Nope, just quit */ 992 if (Status != STATUS_INVALID_PARAMETER) 993 { 994 RtlReleaseRelativeName(&RelativeName); 995 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 996 BaseSetLastNTError(Status); 997 998 return FALSE; 999 } 1000 1001 /* Yes, retry without */ 1002 Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, 1003 &ObjectAttributes, &IoStatusBlock, 1004 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1005 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT); 1006 if (!NT_SUCCESS(Status)) 1007 { 1008 RtlReleaseRelativeName(&RelativeName); 1009 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 1010 BaseSetLastNTError(Status); 1011 1012 return FALSE; 1013 } 1014 } 1015 1016 /* We don't need strings anylonger */ 1017 RtlReleaseRelativeName(&RelativeName); 1018 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer); 1019 1020 /* Zero our structure, we'll only set file attributes */ 1021 ZeroMemory(&FileInformation, sizeof(FileInformation)); 1022 /* Set the attributes, filtering only allowed attributes, and forcing normal attribute */ 1023 FileInformation.FileAttributes = (dwFileAttributes & FILE_ATTRIBUTE_VALID_SET_FLAGS) | FILE_ATTRIBUTE_NORMAL; 1024 1025 /* Finally, set the attributes */ 1026 Status = NtSetInformationFile(FileHandle, &IoStatusBlock, &FileInformation, 1027 sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); 1028 /* Close the file */ 1029 NtClose(FileHandle); 1030 1031 /* If it failed, set the error and fail */ 1032 if (!NT_SUCCESS(Status)) 1033 { 1034 BaseSetLastNTError(Status); 1035 1036 return FALSE; 1037 } 1038 1039 return TRUE; 1040 } 1041 1042 /* 1043 * @implemented 1044 */ 1045 BOOL WINAPI 1046 GetFileTime(IN HANDLE hFile, 1047 OUT LPFILETIME lpCreationTime OPTIONAL, 1048 OUT LPFILETIME lpLastAccessTime OPTIONAL, 1049 OUT LPFILETIME lpLastWriteTime OPTIONAL) 1050 { 1051 NTSTATUS Status; 1052 IO_STATUS_BLOCK IoStatusBlock; 1053 FILE_BASIC_INFORMATION FileBasic; 1054 1055 if(IsConsoleHandle(hFile)) 1056 { 1057 BaseSetLastNTError(STATUS_INVALID_HANDLE); 1058 return FALSE; 1059 } 1060 1061 Status = NtQueryInformationFile(hFile, 1062 &IoStatusBlock, 1063 &FileBasic, 1064 sizeof(FILE_BASIC_INFORMATION), 1065 FileBasicInformation); 1066 if (!NT_SUCCESS(Status)) 1067 { 1068 BaseSetLastNTError(Status); 1069 return FALSE; 1070 } 1071 1072 if (lpCreationTime) 1073 { 1074 lpCreationTime->dwLowDateTime = FileBasic.CreationTime.LowPart; 1075 lpCreationTime->dwHighDateTime = FileBasic.CreationTime.HighPart; 1076 } 1077 1078 if (lpLastAccessTime) 1079 { 1080 lpLastAccessTime->dwLowDateTime = FileBasic.LastAccessTime.LowPart; 1081 lpLastAccessTime->dwHighDateTime = FileBasic.LastAccessTime.HighPart; 1082 } 1083 1084 if (lpLastWriteTime) 1085 { 1086 lpLastWriteTime->dwLowDateTime = FileBasic.LastWriteTime.LowPart; 1087 lpLastWriteTime->dwHighDateTime = FileBasic.LastWriteTime.HighPart; 1088 } 1089 1090 return TRUE; 1091 } 1092 1093 1094 /* 1095 * @implemented 1096 */ 1097 BOOL WINAPI 1098 SetFileTime(IN HANDLE hFile, 1099 CONST FILETIME *lpCreationTime OPTIONAL, 1100 CONST FILETIME *lpLastAccessTime OPTIONAL, 1101 CONST FILETIME *lpLastWriteTime OPTIONAL) 1102 { 1103 NTSTATUS Status; 1104 IO_STATUS_BLOCK IoStatusBlock; 1105 FILE_BASIC_INFORMATION FileBasic; 1106 1107 if(IsConsoleHandle(hFile)) 1108 { 1109 BaseSetLastNTError(STATUS_INVALID_HANDLE); 1110 return FALSE; 1111 } 1112 1113 memset(&FileBasic, 0, sizeof(FILE_BASIC_INFORMATION)); 1114 1115 if (lpCreationTime) 1116 { 1117 FileBasic.CreationTime.LowPart = lpCreationTime->dwLowDateTime; 1118 FileBasic.CreationTime.HighPart = lpCreationTime->dwHighDateTime; 1119 } 1120 1121 if (lpLastAccessTime) 1122 { 1123 FileBasic.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime; 1124 FileBasic.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime; 1125 } 1126 1127 if (lpLastWriteTime) 1128 { 1129 FileBasic.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime; 1130 FileBasic.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime; 1131 } 1132 1133 Status = NtSetInformationFile(hFile, 1134 &IoStatusBlock, 1135 &FileBasic, 1136 sizeof(FILE_BASIC_INFORMATION), 1137 FileBasicInformation); 1138 if (!NT_SUCCESS(Status)) 1139 { 1140 BaseSetLastNTError(Status); 1141 return FALSE; 1142 } 1143 1144 return TRUE; 1145 } 1146 1147 1148 /* 1149 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set. 1150 * 1151 * @implemented 1152 */ 1153 BOOL WINAPI 1154 SetEndOfFile(HANDLE hFile) 1155 { 1156 IO_STATUS_BLOCK IoStatusBlock; 1157 FILE_END_OF_FILE_INFORMATION EndOfFileInfo; 1158 FILE_ALLOCATION_INFORMATION FileAllocationInfo; 1159 FILE_POSITION_INFORMATION FilePosInfo; 1160 NTSTATUS Status; 1161 1162 if(IsConsoleHandle(hFile)) 1163 { 1164 SetLastError(ERROR_INVALID_HANDLE); 1165 return FALSE; 1166 } 1167 1168 //get current position 1169 Status = NtQueryInformationFile( 1170 hFile, 1171 &IoStatusBlock, 1172 &FilePosInfo, 1173 sizeof(FILE_POSITION_INFORMATION), 1174 FilePositionInformation 1175 ); 1176 1177 if (!NT_SUCCESS(Status)){ 1178 BaseSetLastNTError(Status); 1179 return FALSE; 1180 } 1181 1182 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart; 1183 1184 /* 1185 NOTE: 1186 This call is not supposed to free up any space after the eof marker 1187 if the file gets truncated. We have to deallocate the space explicitly afterwards. 1188 But...most file systems dispatch both FileEndOfFileInformation 1189 and FileAllocationInformation as they were the same command. 1190 1191 */ 1192 Status = NtSetInformationFile( 1193 hFile, 1194 &IoStatusBlock, //out 1195 &EndOfFileInfo, 1196 sizeof(FILE_END_OF_FILE_INFORMATION), 1197 FileEndOfFileInformation 1198 ); 1199 1200 if (!NT_SUCCESS(Status)){ 1201 BaseSetLastNTError(Status); 1202 return FALSE; 1203 } 1204 1205 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart; 1206 1207 1208 Status = NtSetInformationFile( 1209 hFile, 1210 &IoStatusBlock, //out 1211 &FileAllocationInfo, 1212 sizeof(FILE_ALLOCATION_INFORMATION), 1213 FileAllocationInformation 1214 ); 1215 1216 if (!NT_SUCCESS(Status)){ 1217 BaseSetLastNTError(Status); 1218 return FALSE; 1219 } 1220 1221 return TRUE; 1222 1223 } 1224 1225 1226 /* 1227 * @implemented 1228 */ 1229 BOOL 1230 WINAPI 1231 SetFileValidData( 1232 HANDLE hFile, 1233 LONGLONG ValidDataLength 1234 ) 1235 { 1236 IO_STATUS_BLOCK IoStatusBlock; 1237 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation; 1238 NTSTATUS Status; 1239 1240 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength; 1241 1242 Status = NtSetInformationFile( 1243 hFile, 1244 &IoStatusBlock, //out 1245 &ValidDataLengthInformation, 1246 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION), 1247 FileValidDataLengthInformation 1248 ); 1249 1250 if (!NT_SUCCESS(Status)){ 1251 BaseSetLastNTError(Status); 1252 return FALSE; 1253 } 1254 1255 return TRUE; 1256 } 1257 1258 /* EOF */ 1259