aboutsummaryrefslogtreecommitdiff
path: root/CPP/Windows/FileIO.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/Windows/FileIO.cpp')
-rw-r--r--CPP/Windows/FileIO.cpp248
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
20typedef LONG NTSTATUS;
21typedef 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()
33extern bool g_IsNT; 56extern 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
63typedef LONG Z7_WIN_NTSTATUS;
64typedef 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
75typedef 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
82typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status);
83
84Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
85static Func_NtSetInformationFile g_NtSetInformationFile;
86static Func_RtlNtStatusToDosError g_RtlNtStatusToDosError;
87static 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
36using namespace NWindows; 101using namespace NWindows;
37using namespace NFile; 102using namespace NFile;
38using namespace NName; 103using 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)
539bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes) 604bool 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
607DWORD 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
635bool 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
542bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() 671bool 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
760extern
761bool FiTime_To_timespec(const CFiTime *ft, timespec &ts);
762
631namespace NWindows { 763namespace NWindows {
632namespace NFile { 764namespace NFile {
633 765
634namespace NDir { 766namespace NDir {
767
768extern C_umask g_umask;
769
635bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); 770bool 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
741bool CInFile::Open(const char *name) 904bool 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
746bool CInFile::OpenShared(const char *name, bool) 909bool 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
906bool COutFile::Close() 1072bool 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
1161bool 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
945bool COutFile::SetMTime(const CFiTime *mTime) throw() 1179bool 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;