diff options
Diffstat (limited to 'CPP/Windows/FileIO.cpp')
| -rw-r--r-- | CPP/Windows/FileIO.cpp | 248 |
1 files changed, 241 insertions, 7 deletions
diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp index dc4de14..8be06fc 100644 --- a/CPP/Windows/FileIO.cpp +++ b/CPP/Windows/FileIO.cpp | |||
| @@ -6,6 +6,29 @@ | |||
| 6 | #include "../../C/Alloc.h" | 6 | #include "../../C/Alloc.h" |
| 7 | #endif | 7 | #endif |
| 8 | 8 | ||
| 9 | #ifdef _WIN32 | ||
| 10 | #ifdef __MINGW32_VERSION | ||
| 11 | // #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10) | ||
| 12 | // for old mingw | ||
| 13 | #include <ddk/ntddk.h> | ||
| 14 | #else | ||
| 15 | #ifndef Z7_OLD_WIN_SDK | ||
| 16 | #if !defined(_M_IA64) | ||
| 17 | #include <winternl.h> | ||
| 18 | #endif | ||
| 19 | #else | ||
| 20 | typedef LONG NTSTATUS; | ||
| 21 | typedef struct _IO_STATUS_BLOCK { | ||
| 22 | union { | ||
| 23 | NTSTATUS Status; | ||
| 24 | PVOID Pointer; | ||
| 25 | }; | ||
| 26 | ULONG_PTR Information; | ||
| 27 | } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; | ||
| 28 | #endif | ||
| 29 | #endif | ||
| 30 | #endif // _WIN32 | ||
| 31 | |||
| 9 | // #include <stdio.h> | 32 | // #include <stdio.h> |
| 10 | 33 | ||
| 11 | /* | 34 | /* |
| @@ -33,6 +56,48 @@ HRESULT GetLastError_noZero_HRESULT() | |||
| 33 | extern bool g_IsNT; | 56 | extern bool g_IsNT; |
| 34 | #endif | 57 | #endif |
| 35 | 58 | ||
| 59 | #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) | ||
| 60 | #define Z7_WIN_NTSTATUS NTSTATUS | ||
| 61 | #define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK | ||
| 62 | #else | ||
| 63 | typedef LONG Z7_WIN_NTSTATUS; | ||
| 64 | typedef struct | ||
| 65 | { | ||
| 66 | union | ||
| 67 | { | ||
| 68 | Z7_WIN_NTSTATUS Status; | ||
| 69 | PVOID Pointer; | ||
| 70 | } DUMMYUNIONNAME; | ||
| 71 | ULONG_PTR Information; | ||
| 72 | } Z7_WIN_IO_STATUS_BLOCK; | ||
| 73 | #endif | ||
| 74 | |||
| 75 | typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)( | ||
| 76 | HANDLE FileHandle, | ||
| 77 | Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock, | ||
| 78 | PVOID FileInformation, | ||
| 79 | ULONG Length, | ||
| 80 | Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass); | ||
| 81 | // NTAPI | ||
| 82 | typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status); | ||
| 83 | |||
| 84 | Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION | ||
| 85 | static Func_NtSetInformationFile g_NtSetInformationFile; | ||
| 86 | static Func_RtlNtStatusToDosError g_RtlNtStatusToDosError; | ||
| 87 | static struct C_Init_NtSetInformationFile | ||
| 88 | { | ||
| 89 | C_Init_NtSetInformationFile() | ||
| 90 | { | ||
| 91 | const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); | ||
| 92 | g_NtSetInformationFile = Z7_GET_PROC_ADDRESS( | ||
| 93 | Func_NtSetInformationFile, ntdll, | ||
| 94 | "NtSetInformationFile"); | ||
| 95 | g_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS( | ||
| 96 | Func_RtlNtStatusToDosError, ntdll, | ||
| 97 | "RtlNtStatusToDosError"); | ||
| 98 | } | ||
| 99 | } g_C_Init_NtSetInformationFile; | ||
| 100 | |||
| 36 | using namespace NWindows; | 101 | using namespace NWindows; |
| 37 | using namespace NFile; | 102 | using namespace NFile; |
| 38 | using namespace NName; | 103 | using namespace NName; |
| @@ -353,7 +418,7 @@ void CInFile::CalcDeviceSize(CFSTR s) | |||
| 353 | WinXP 64-bit: | 418 | WinXP 64-bit: |
| 354 | 419 | ||
| 355 | HDD \\.\PhysicalDrive0 (MBR): | 420 | HDD \\.\PhysicalDrive0 (MBR): |
| 356 | GetPartitionInfo == GeometryEx : corrrect size? (includes tail) | 421 | GetPartitionInfo == GeometryEx : correct size? (includes tail) |
| 357 | Geometry : smaller than GeometryEx (no tail, maybe correct too?) | 422 | Geometry : smaller than GeometryEx (no tail, maybe correct too?) |
| 358 | MyGetDiskFreeSpace : FAIL | 423 | MyGetDiskFreeSpace : FAIL |
| 359 | Size correction is slow and block size (kClusterSize) must be small? | 424 | Size correction is slow and block size (kClusterSize) must be small? |
| @@ -365,8 +430,8 @@ void CInFile::CalcDeviceSize(CFSTR s) | |||
| 365 | 430 | ||
| 366 | CD-ROM drive (ISO): | 431 | CD-ROM drive (ISO): |
| 367 | MyGetDiskFreeSpace : correct size. Same size can be calculated after correction | 432 | MyGetDiskFreeSpace : correct size. Same size can be calculated after correction |
| 368 | Geometry == CdRomGeometry : smaller than corrrect size | 433 | Geometry == CdRomGeometry : smaller than correct size |
| 369 | GetPartitionInfo == GeometryEx : larger than corrrect size | 434 | GetPartitionInfo == GeometryEx : larger than correct size |
| 370 | 435 | ||
| 371 | Floppy \\.\a: (FAT): | 436 | Floppy \\.\a: (FAT): |
| 372 | Geometry : correct size. | 437 | Geometry : correct size. |
| @@ -539,6 +604,70 @@ bool COutFile::Open_Disposition(CFSTR fileName, DWORD creationDisposition) | |||
| 539 | bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes) | 604 | bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes) |
| 540 | { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); } | 605 | { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); } |
| 541 | 606 | ||
| 607 | DWORD CFileBase::Call_NtSetInformationFile_return_WinError( | ||
| 608 | void *data, ULONG len, Z7_WIN_FILE_INFORMATION_CLASS fileInformationClass) const | ||
| 609 | { | ||
| 610 | if (!g_NtSetInformationFile) | ||
| 611 | return ERROR_PROC_NOT_FOUND; | ||
| 612 | Z7_WIN_IO_STATUS_BLOCK ioStatus; | ||
| 613 | Z7_memset_0_VAR(ioStatus); // optional | ||
| 614 | const Z7_WIN_NTSTATUS status = g_NtSetInformationFile(_handle, | ||
| 615 | &ioStatus, data, len, fileInformationClass); | ||
| 616 | if (status == 0) // MY_STATUS_SUCCESS | ||
| 617 | return 0; | ||
| 618 | if (g_RtlNtStatusToDosError) | ||
| 619 | { | ||
| 620 | const ULONG res = g_RtlNtStatusToDosError(status); | ||
| 621 | if (res != ERROR_MR_MID_NOT_FOUND) | ||
| 622 | return res; | ||
| 623 | } | ||
| 624 | return 1; | ||
| 625 | } | ||
| 626 | |||
| 627 | |||
| 628 | #define SET_TIME_FIELD_IF_DEFINED(dest, src) \ | ||
| 629 | { if (src) { \ | ||
| 630 | dest.LowPart = (src)->dwLowDateTime; \ | ||
| 631 | dest.HighPart = (LONG)(src)->dwHighDateTime; \ | ||
| 632 | } \ | ||
| 633 | } | ||
| 634 | |||
| 635 | bool COutFile::Set_Time_and_WinAttrib(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime, DWORD attrib) throw() | ||
| 636 | { | ||
| 637 | #ifdef _WIN32 | ||
| 638 | // similar to GetAttrib_PosixHighDetect(attrib) | ||
| 639 | if (attrib & 0xF0000000) | ||
| 640 | attrib &= 0x3FFF; | ||
| 641 | #endif | ||
| 642 | |||
| 643 | Z7_WIN_FILE_BASIC_INFORMATION fbi; | ||
| 644 | Z7_memset_0_VAR(fbi); | ||
| 645 | SET_TIME_FIELD_IF_DEFINED (fbi.CreationTime, cTime) | ||
| 646 | SET_TIME_FIELD_IF_DEFINED (fbi.LastAccessTime, aTime) | ||
| 647 | SET_TIME_FIELD_IF_DEFINED (fbi.LastWriteTime, mTime) | ||
| 648 | // fbi.ChangeTime.QuadPart = 0; | ||
| 649 | /* | ||
| 650 | if (attrib == 0) | ||
| 651 | { win10: NtSetInformationFile() doesn't change file attribute | ||
| 652 | if (attrib & FILE_ATTRIBUTE_DIRECTORY) | ||
| 653 | { win10: NtSetInformationFile() returns (STATUS_INVALID_PARAMETER) } | ||
| 654 | we provide similar attribute processing as | ||
| 655 | SetFileAttributes(): | ||
| 656 | - we ignore (FILE_ATTRIBUTE_DIRECTORY) | ||
| 657 | - we write (FILE_ATTRIBUTE_NORMAL) instead of (0) | ||
| 658 | */ | ||
| 659 | attrib &= ~(DWORD)FILE_ATTRIBUTE_DIRECTORY; | ||
| 660 | if (attrib == 0) | ||
| 661 | attrib = FILE_ATTRIBUTE_NORMAL; | ||
| 662 | fbi.FileAttributes = attrib; | ||
| 663 | const DWORD wres = Call_NtSetInformationFile_return_WinError( | ||
| 664 | &fbi, sizeof(fbi), Z7_WIN_FileBasicInformation); | ||
| 665 | if (wres == 0) | ||
| 666 | return true; | ||
| 667 | SetLastError(wres); | ||
| 668 | return false; | ||
| 669 | } | ||
| 670 | |||
| 542 | bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() | 671 | bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() |
| 543 | { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } | 672 | { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } |
| 544 | 673 | ||
| @@ -628,10 +757,16 @@ bool COutFile::SetLength_KeepPosition(UInt64 length) throw() | |||
| 628 | #include <fcntl.h> | 757 | #include <fcntl.h> |
| 629 | #include <unistd.h> | 758 | #include <unistd.h> |
| 630 | 759 | ||
| 760 | extern | ||
| 761 | bool FiTime_To_timespec(const CFiTime *ft, timespec &ts); | ||
| 762 | |||
| 631 | namespace NWindows { | 763 | namespace NWindows { |
| 632 | namespace NFile { | 764 | namespace NFile { |
| 633 | 765 | ||
| 634 | namespace NDir { | 766 | namespace NDir { |
| 767 | |||
| 768 | extern C_umask g_umask; | ||
| 769 | |||
| 635 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); | 770 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); |
| 636 | } | 771 | } |
| 637 | 772 | ||
| @@ -644,6 +779,34 @@ bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode) | |||
| 644 | #endif | 779 | #endif |
| 645 | 780 | ||
| 646 | Close(); | 781 | Close(); |
| 782 | /* | ||
| 783 | The mode argument specifies the file mode bits to be | ||
| 784 | applied when a new file is created. If neither O_CREAT nor | ||
| 785 | O_TMPFILE is specified in flags, then mode is ignored (and | ||
| 786 | can thus be specified as 0, or simply omitted). | ||
| 787 | |||
| 788 | The effective mode is modified by the process's umask in | ||
| 789 | the usual way: in the absence of a default ACL, the mode of | ||
| 790 | the created file is (mode & ~umask). | ||
| 791 | |||
| 792 | Note that mode applies only to future accesses of the newly | ||
| 793 | created file; the open() call that creates a read-only file | ||
| 794 | may well return a read/write file descriptor. | ||
| 795 | |||
| 796 | POSIX: if other bits (~0777) are set in mode : the effect is unspecified | ||
| 797 | Linux: | ||
| 798 | S_ISUID 04000 set-user-ID bit | ||
| 799 | S_ISGID 02000 set-group-ID bit | ||
| 800 | S_ISVTX 01000 sticky bit | ||
| 801 | |||
| 802 | S_ISVTX can be set, but it's useless for file in modern linux. | ||
| 803 | by security reasons: | ||
| 804 | open() ignores S_ISUID | ||
| 805 | open() ignores S_ISGID, if S_IXGRP is set. | ||
| 806 | */ | ||
| 807 | // mode |= S_ISUID | S_ISGID | S_ISVTX; // for debug | ||
| 808 | // printf("\n open() mode=%o\n", (unsigned)(mode)); | ||
| 809 | |||
| 647 | _handle = ::open(name, flags, mode); | 810 | _handle = ::open(name, flags, mode); |
| 648 | return _handle != -1; | 811 | return _handle != -1; |
| 649 | 812 | ||
| @@ -740,7 +903,7 @@ bool CFileBase::SeekToBegin() const throw() | |||
| 740 | 903 | ||
| 741 | bool CInFile::Open(const char *name) | 904 | bool CInFile::Open(const char *name) |
| 742 | { | 905 | { |
| 743 | return CFileBase::OpenBinary(name, O_RDONLY); | 906 | return CFileBase::OpenBinary(name, O_RDONLY, k_OutFile_mode_default); |
| 744 | } | 907 | } |
| 745 | 908 | ||
| 746 | bool CInFile::OpenShared(const char *name, bool) | 909 | bool CInFile::OpenShared(const char *name, bool) |
| @@ -903,11 +1066,64 @@ bool COutFile::SetLength(UInt64 length) throw() | |||
| 903 | return (iret == 0); | 1066 | return (iret == 0); |
| 904 | } | 1067 | } |
| 905 | 1068 | ||
| 1069 | // #define PRF(x) x | ||
| 1070 | #define PRF(x) | ||
| 1071 | |||
| 906 | bool COutFile::Close() | 1072 | bool COutFile::Close() |
| 907 | { | 1073 | { |
| 908 | const bool res = CFileBase::Close(); | 1074 | bool res = true; |
| 909 | if (!res) | 1075 | if (_handle == -1) |
| 910 | return res; | 1076 | return true; |
| 1077 | { | ||
| 1078 | // bool res2 = true; | ||
| 1079 | if (mode_for_Close_defined) | ||
| 1080 | { | ||
| 1081 | PRF(printf("\n COutFile::Close() mode=%o\n", (unsigned)(mode_for_Close));) | ||
| 1082 | // fchmod() function ignores the file creation mask set by umask() | ||
| 1083 | // so we can restore any of (07777) mode bits | ||
| 1084 | // mode_for_Close |= (0xffff << 12); // for debug | ||
| 1085 | if (fchmod(_handle, mode_for_Close) == 0) | ||
| 1086 | { | ||
| 1087 | mode_for_Close_defined = false; | ||
| 1088 | PRF(printf("\n COutFile::Close() fchmod() == 0\n");) | ||
| 1089 | } | ||
| 1090 | // else res2 = false; | ||
| 1091 | } | ||
| 1092 | { | ||
| 1093 | if (MTime_defined || ATime_defined) | ||
| 1094 | { | ||
| 1095 | struct timespec times[2]; | ||
| 1096 | FiTime_To_timespec(ATime_defined ? &ATime : NULL, times[0]); | ||
| 1097 | FiTime_To_timespec(MTime_defined ? &MTime : NULL, times[1]); | ||
| 1098 | // futimens : POSIX.1-2008 | ||
| 1099 | if (futimens(_handle, times) == 0) | ||
| 1100 | { | ||
| 1101 | PRF(printf("\n futimens() OK \n");) | ||
| 1102 | ATime_defined = false; | ||
| 1103 | MTime_defined = false; | ||
| 1104 | } | ||
| 1105 | else | ||
| 1106 | { | ||
| 1107 | PRF(printf("\n futimens() ERROR: %d=%s\n", errno, strerror(errno));) | ||
| 1108 | } | ||
| 1109 | } | ||
| 1110 | } | ||
| 1111 | res = CFileBase::Close(); | ||
| 1112 | if (!res) | ||
| 1113 | return res; | ||
| 1114 | // res = res2; | ||
| 1115 | } | ||
| 1116 | if (mode_for_Close_defined) | ||
| 1117 | { | ||
| 1118 | // chmod() ignores the file creation mask set by umask() | ||
| 1119 | // so we can restore any of (07777) mode bits | ||
| 1120 | // const int res_chmod = | ||
| 1121 | chmod(Path, mode_for_Close); | ||
| 1122 | mode_for_Close_defined = false; | ||
| 1123 | // if (res_chmod != 0 && res == true) res = false; | ||
| 1124 | // PRF(printf("\n COutFile::Close() chmod res=%d\n", (int)res_chmod);) | ||
| 1125 | } | ||
| 1126 | |||
| 911 | if (CTime_defined || ATime_defined || MTime_defined) | 1127 | if (CTime_defined || ATime_defined || MTime_defined) |
| 912 | { | 1128 | { |
| 913 | /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, | 1129 | /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, |
| @@ -942,6 +1158,24 @@ bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime | |||
| 942 | */ | 1158 | */ |
| 943 | } | 1159 | } |
| 944 | 1160 | ||
| 1161 | bool COutFile::Set_Time_and_WinAttrib( | ||
| 1162 | const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD attrib) throw() | ||
| 1163 | { | ||
| 1164 | PRF(printf("\n Set_Time_and_WinAttrib() mode=%o\n", (unsigned)(attrib >> 16));) | ||
| 1165 | SetTime(cTime, aTime, mTime); | ||
| 1166 | // we will use fchmod() or chmod() later in Close() fucntion. | ||
| 1167 | // fchmod() or chmod() are not limited by system umask. | ||
| 1168 | // but for security reasons we use the system mask (g_umask.mask) derived from umask(). | ||
| 1169 | mode_t mode = k_OutFile_mode_default; // 0666 | ||
| 1170 | if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) | ||
| 1171 | mode = (attrib >> 16); | ||
| 1172 | else if (attrib & FILE_ATTRIBUTE_READONLY) | ||
| 1173 | mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions | ||
| 1174 | mode_for_Close = mode & NDir::g_umask.mask; | ||
| 1175 | mode_for_Close_defined = true; | ||
| 1176 | return true; | ||
| 1177 | } | ||
| 1178 | |||
| 945 | bool COutFile::SetMTime(const CFiTime *mTime) throw() | 1179 | bool COutFile::SetMTime(const CFiTime *mTime) throw() |
| 946 | { | 1180 | { |
| 947 | if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; | 1181 | if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; |
