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