aboutsummaryrefslogtreecommitdiff
path: root/CPP/Windows
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/Windows')
-rw-r--r--CPP/Windows/FileDir.cpp29
-rw-r--r--CPP/Windows/FileDir.h5
-rw-r--r--CPP/Windows/FileFind.cpp9
-rw-r--r--CPP/Windows/FileIO.h43
-rw-r--r--CPP/Windows/FileLink.cpp244
-rw-r--r--CPP/Windows/FileName.cpp71
-rw-r--r--CPP/Windows/FileName.h13
-rw-r--r--CPP/Windows/System.cpp128
-rw-r--r--CPP/Windows/System.h61
-rw-r--r--CPP/Windows/Thread.h8
-rw-r--r--CPP/Windows/TimeUtils.cpp3
11 files changed, 464 insertions, 150 deletions
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp
index 2cb83b2..10c4e98 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
@@ -651,6 +651,35 @@ bool RemoveDirWithSubItems(const FString &path)
651 return RemoveDir(path); 651 return RemoveDir(path);
652} 652}
653 653
654bool RemoveDirAlways_if_Empty(const FString &path)
655{
656 const DWORD attrib = NFind::GetFileAttrib(path);
657 if (attrib != INVALID_FILE_ATTRIBUTES
658 && (attrib & FILE_ATTRIBUTE_READONLY))
659 {
660 bool need_ClearAttrib = true;
661 if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
662 {
663 FString s (path);
664 s.Add_PathSepar();
665 NFind::CEnumerator enumerator;
666 enumerator.SetDirPrefix(s);
667 NFind::CDirEntry fi;
668 if (enumerator.Next(fi))
669 {
670 // we don't want to change attributes, if there are files
671 // in directory, because RemoveDir(path) will fail.
672 need_ClearAttrib = false;
673 // SetLastError(ERROR_DIR_NOT_EMPTY);
674 // return false;
675 }
676 }
677 if (need_ClearAttrib)
678 SetFileAttrib(path, 0); // we clear read-only attrib to remove read-only dir
679 }
680 return RemoveDir(path);
681}
682
654#endif // _WIN32 683#endif // _WIN32
655 684
656#ifdef UNDER_CE 685#ifdef UNDER_CE
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h
index 74675ee..65e6368 100644
--- a/CPP/Windows/FileDir.h
+++ b/CPP/Windows/FileDir.h
@@ -78,6 +78,11 @@ bool CreateComplexDir(CFSTR path);
78 78
79bool DeleteFileAlways(CFSTR name); 79bool DeleteFileAlways(CFSTR name);
80bool RemoveDirWithSubItems(const FString &path); 80bool RemoveDirWithSubItems(const FString &path);
81#ifdef _WIN32
82bool RemoveDirAlways_if_Empty(const FString &path);
83#else
84#define RemoveDirAlways_if_Empty RemoveDir
85#endif
81 86
82bool MyGetFullPathName(CFSTR path, FString &resFullPath); 87bool MyGetFullPathName(CFSTR path, FString &resFullPath);
83bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); 88bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName);
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp
index ca387f6..64075ab 100644
--- a/CPP/Windows/FileFind.cpp
+++ b/CPP/Windows/FileFind.cpp
@@ -731,7 +731,7 @@ bool CFileInfo::Find(CFSTR path, bool followLink)
731 bool isOK = false; 731 bool isOK = false;
732 if (finder.FindFirst(s, *this)) 732 if (finder.FindFirst(s, *this))
733 { 733 {
734 if (Name == FTEXT(".")) 734 if (Name.IsEqualTo("."))
735 { 735 {
736 Name = path + prefixSize; 736 Name = path + prefixSize;
737 return true; 737 return true;
@@ -769,6 +769,13 @@ bool CFileInfo::Find(CFSTR path, bool followLink)
769 769
770 // return FollowReparse(path, IsDir()); 770 // return FollowReparse(path, IsDir());
771 return Fill_From_ByHandleFileInfo(path); 771 return Fill_From_ByHandleFileInfo(path);
772/*
773 // Fill_From_ByHandleFileInfo returns false (with Access Denied error),
774 // if there is reparse link file (not directory reparse item).
775 if (Fill_From_ByHandleFileInfo(path))
776 return true;
777 return HasReparsePoint();
778*/
772} 779}
773 780
774bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) 781bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path)
diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h
index 6ba40eb..26edef4 100644
--- a/CPP/Windows/FileIO.h
+++ b/CPP/Windows/FileIO.h
@@ -11,8 +11,7 @@
11 11
12#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1 12#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1
13 13
14// what the meaning of that FLAG or field (2)? 14#define Z7_WIN_LX_SYMLINK_VERSION_2 2
15#define Z7_WIN_LX_SYMLINK_FLAG 2
16 15
17#ifdef _WIN32 16#ifdef _WIN32
18 17
@@ -44,7 +43,33 @@ namespace NWindows {
44namespace NFile { 43namespace NFile {
45 44
46#if defined(_WIN32) && !defined(UNDER_CE) 45#if defined(_WIN32) && !defined(UNDER_CE)
47bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); 46/*
47 in: (CByteBuffer &dest) is empty
48 in: (path) uses Windows path separator (\).
49 out: (path) uses Linux path separator (/).
50 if (isAbsPath == true), then "c:\\" prefix is replaced to "/mnt/c/" prefix
51*/
52void Convert_WinPath_to_WslLinuxPath(FString &path, bool convertDrivePath);
53// (path) must use Linux path separator (/).
54void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path);
55
56/*
57 in: (CByteBuffer &dest) is empty
58 if (isSymLink == false) : MOUNT_POINT : (path) must be absolute.
59 if (isSymLink == true) : SYMLINK : Windows
60 (path) must use Windows path separator (\).
61 (path) must be without link "\\??\\" prefix.
62 link "\\??\\" prefix will be added inside FillLinkData(), if path is absolute.
63*/
64void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink);
65// in: (CByteBuffer &dest) is empty
66inline void FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
67{
68 if (isWSL)
69 FillLinkData_WslLink(dest, path);
70 else
71 FillLinkData_WinLink(dest, path, isSymLink);
72}
48#endif 73#endif
49 74
50struct CReparseShortInfo 75struct CReparseShortInfo
@@ -61,7 +86,6 @@ struct CReparseAttr
61 UInt32 Flags; 86 UInt32 Flags;
62 UString SubsName; 87 UString SubsName;
63 UString PrintName; 88 UString PrintName;
64
65 AString WslName; 89 AString WslName;
66 90
67 bool HeaderError; 91 bool HeaderError;
@@ -71,8 +95,7 @@ struct CReparseAttr
71 95
72 CReparseAttr(): Tag(0), Flags(0) {} 96 CReparseAttr(): Tag(0), Flags(0) {}
73 97
74 // Parse() 98 // returns (true) and (ErrorCode = 0), if (it's correct known link)
75 // returns (true) and (ErrorCode = 0), if (it'a correct known link)
76 // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag 99 // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag
77 bool Parse(const Byte *p, size_t size); 100 bool Parse(const Byte *p, size_t size);
78 101
@@ -80,18 +103,14 @@ struct CReparseAttr
80 bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } 103 bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; }
81 bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } 104 bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; }
82 105
106 // note: "/dir1/path" is marked as relative.
83 bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } 107 bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; }
84 108
85 bool IsRelative_WSL() const 109 bool IsRelative_WSL() const
86 { 110 {
87 if (WslName.IsEmpty()) 111 return WslName[0] != '/'; // WSL uses unix path separator
88 return true;
89 char c = WslName[0];
90 return !IS_PATH_SEPAR(c);
91 } 112 }
92 113
93 // bool IsVolume() const;
94
95 bool IsOkNamePair() const; 114 bool IsOkNamePair() const;
96 UString GetPath() const; 115 UString GetPath() const;
97}; 116};
diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp
index bb380ec..2883c82 100644
--- a/CPP/Windows/FileLink.cpp
+++ b/CPP/Windows/FileLink.cpp
@@ -39,12 +39,24 @@ namespace NFile {
39using namespace NName; 39using namespace NName;
40 40
41/* 41/*
42Win10 Junctions/SymLinks:
43 - (/) slash doesn't work as path separator
44 - Win10 preinstalled junctions don't use tail backslash, but tail backslashes also work.
45 - double backslash works only after drive prefix "c:\\dir1\dir2\",
46 and doesn't work in another places.
47 - absolute path without \??\ prefix doesn't work
48 - absolute path "c:" doesn't work
49*/
50
51/*
42 Reparse Points (Junctions and Symbolic Links): 52 Reparse Points (Junctions and Symbolic Links):
43 struct 53 struct
44 { 54 {
45 UInt32 Tag; 55 UInt32 Tag;
46 UInt16 Size; // not including starting 8 bytes 56 UInt16 Size; // not including starting 8 bytes
47 UInt16 Reserved; // = 0 57 UInt16 Reserved; // = 0, DOCs: // Length, in bytes, of the unparsed portion of
58 // the file name pointed to by the FileName member of the associated file object.
59 // This member is only valid for create operations when the I/O fails with STATUS_REPARSE.
48 60
49 UInt16 SubstituteOffset; // offset in bytes from start of namesChars 61 UInt16 SubstituteOffset; // offset in bytes from start of namesChars
50 UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL 62 UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL
@@ -68,6 +80,16 @@ using namespace NName;
68 2) Default Order in table: 80 2) Default Order in table:
69 Print Path 81 Print Path
70 Substitute Path 82 Substitute Path
83
84DOCS:
85 The print name SHOULD be an informative pathname, suitable for display
86 to a user, that also identifies the target of the mount point.
87 Neither of these pathnames can contain dot directory names.
88
89reparse tags, with the exception of IO_REPARSE_TAG_SYMLINK,
90are processed on the server and are not processed by a client
91after transmission over the wire.
92Clients SHOULD treat associated reparse data as opaque data.
71*/ 93*/
72 94
73/* 95/*
@@ -93,7 +115,8 @@ static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31);
93#define Get16(p) GetUi16(p) 115#define Get16(p) GetUi16(p)
94#define Get32(p) GetUi32(p) 116#define Get32(p) GetUi32(p)
95 117
96static const wchar_t * const k_LinkPrefix = L"\\??\\"; 118static const char * const k_LinkPrefix = "\\??\\";
119static const char * const k_LinkPrefix_UNC = "\\??\\UNC\\";
97static const unsigned k_LinkPrefix_Size = 4; 120static const unsigned k_LinkPrefix_Size = 4;
98 121
99static bool IsLinkPrefix(const wchar_t *s) 122static bool IsLinkPrefix(const wchar_t *s)
@@ -102,7 +125,7 @@ static bool IsLinkPrefix(const wchar_t *s)
102} 125}
103 126
104/* 127/*
105static const wchar_t * const k_VolumePrefix = L"Volume{"; 128static const char * const k_VolumePrefix = "Volume{";
106static const bool IsVolumeName(const wchar_t *s) 129static const bool IsVolumeName(const wchar_t *s)
107{ 130{
108 return IsString1PrefixedByString2(s, k_VolumePrefix); 131 return IsString1PrefixedByString2(s, k_VolumePrefix);
@@ -118,7 +141,7 @@ static void WriteString(Byte *dest, const wchar_t *path)
118{ 141{
119 for (;;) 142 for (;;)
120 { 143 {
121 wchar_t c = *path++; 144 const wchar_t c = *path++;
122 if (c == 0) 145 if (c == 0)
123 return; 146 return;
124 Set16(dest, (UInt16)c) 147 Set16(dest, (UInt16)c)
@@ -126,62 +149,103 @@ static void WriteString(Byte *dest, const wchar_t *path)
126 } 149 }
127} 150}
128 151
129bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) 152#ifdef _WIN32
153void Convert_WinPath_to_WslLinuxPath(FString &s, bool convertDrivePath)
130{ 154{
131 bool isAbs = IsAbsolutePath(path); 155 if (convertDrivePath && IsDrivePath(s))
132 if (!isAbs && !isSymLink)
133 return false;
134
135 if (isWSL)
136 { 156 {
137 // unsupported characters probably use Replacement Character UTF-16 0xFFFD 157 FChar c = s[0];
138 AString utf; 158 c = MyCharLower_Ascii(c);
139 ConvertUnicodeToUTF8(path, utf); 159 s.DeleteFrontal(2);
140 const size_t size = 4 + utf.Len(); 160 s.InsertAtFront(c);
141 if (size != (UInt16)size) 161 s.Insert(0, FTEXT("/mnt/"));
142 return false;
143 dest.Alloc(8 + size);
144 Byte *p = dest;
145 Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
146 Set16(p + 4, (UInt16)(size))
147 Set16(p + 6, 0)
148 Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG)
149 memcpy(p + 12, utf.Ptr(), utf.Len());
150 return true;
151 } 162 }
163 s.Replace(FCHAR_PATH_SEPARATOR, FTEXT('/'));
164}
165#endif
152 166
153 // usual symbolic LINK (NOT WSL)
154 167
155 bool needPrintName = true; 168static const unsigned k_Link_Size_Limit = 1u << 16; // 16-bit field is used for size.
169
170void FillLinkData_WslLink(CByteBuffer &dest, const wchar_t *path)
171{
172 // dest.Free(); // it's empty already
173 // WSL probably uses Replacement Character UTF-16 0xFFFD for unsupported characters?
174 AString utf;
175 ConvertUnicodeToUTF8(path, utf);
176 const unsigned size = 4 + utf.Len();
177 if (size >= k_Link_Size_Limit)
178 return;
179 dest.Alloc(8 + size);
180 Byte *p = dest;
181 Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
182 // Set32(p + 4, (UInt32)size)
183 Set16(p + 4, (UInt16)size)
184 Set16(p + 6, 0)
185 Set32(p + 8, Z7_WIN_LX_SYMLINK_VERSION_2)
186 memcpy(p + 12, utf.Ptr(), utf.Len());
187}
188
156 189
157 if (IsSuperPath(path)) 190void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
191{
192 // dest.Free(); // it's empty already
193 bool isAbs = false;
194 if (IS_PATH_SEPAR(path[0]))
158 { 195 {
159 path += kSuperPathPrefixSize; 196 // root paths "\dir1\path" are marked as relative
160 if (!IsDrivePath(path)) 197 if (IS_PATH_SEPAR(path[1]))
161 needPrintName = false; 198 isAbs = true;
199 }
200 else
201 isAbs = IsAbsolutePath(path);
202 if (!isAbs && !isSymLink)
203 {
204 // Win10 allows us to create relative MOUNT_POINT.
205 // But relative MOUNT_POINT will not work when accessing it.
206 // So we prevent useless creation of a relative MOUNT_POINT.
207 return;
162 } 208 }
163 209
164 const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; 210 bool needPrintName = true;
165 211 UString subs (path);
212 if (isAbs)
213 {
214 const bool isSuperPath = IsSuperPath(path);
215 if (!isSuperPath && NName::IsNetworkPath(us2fs(path)))
216 {
217 subs = k_LinkPrefix_UNC;
218 subs += (path + 2);
219 }
220 else
221 {
222 if (isSuperPath)
223 {
224 // we remove super prefix:
225 path += kSuperPathPrefixSize;
226 // we want to get correct abolute path in PrintName still.
227 if (!IsDrivePath(path))
228 needPrintName = false; // we need "\\server\path" for print name.
229 }
230 subs = k_LinkPrefix;
231 subs += path;
232 }
233 }
234 const size_t len1 = subs.Len() * 2;
166 size_t len2 = (size_t)MyStringLen(path) * 2; 235 size_t len2 = (size_t)MyStringLen(path) * 2;
167 const size_t len1 = len2 + add_Prefix_Len * 2;
168 if (!needPrintName) 236 if (!needPrintName)
169 len2 = 0; 237 len2 = 0;
170 238 size_t totalNamesSize = len1 + len2;
171 size_t totalNamesSize = (len1 + len2);
172
173 /* some WIM imagex software uses old scheme for symbolic links. 239 /* some WIM imagex software uses old scheme for symbolic links.
174 so we can old scheme for byte to byte compatibility */ 240 so we can use old scheme for byte to byte compatibility */
175 241 const bool newOrderScheme = isSymLink;
176 bool newOrderScheme = isSymLink;
177 // newOrderScheme = false; 242 // newOrderScheme = false;
178
179 if (!newOrderScheme) 243 if (!newOrderScheme)
180 totalNamesSize += 2 * 2; 244 totalNamesSize += 2 * 2; // we use NULL terminators in old scheme.
181 245
182 const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; 246 const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
183 if (size != (UInt16)size) 247 if (size >= k_Link_Size_Limit)
184 return false; 248 return;
185 dest.Alloc(size); 249 dest.Alloc(size);
186 memset(dest, 0, size); 250 memset(dest, 0, size);
187 const UInt32 tag = isSymLink ? 251 const UInt32 tag = isSymLink ?
@@ -189,6 +253,7 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool i
189 Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; 253 Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT;
190 Byte *p = dest; 254 Byte *p = dest;
191 Set32(p, tag) 255 Set32(p, tag)
256 // Set32(p + 4, (UInt32)(size - 8))
192 Set16(p + 4, (UInt16)(size - 8)) 257 Set16(p + 4, (UInt16)(size - 8))
193 Set16(p + 6, 0) 258 Set16(p + 6, 0)
194 p += 8; 259 p += 8;
@@ -204,21 +269,16 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool i
204 Set16(p + 2, (UInt16)len1) 269 Set16(p + 2, (UInt16)len1)
205 Set16(p + 4, (UInt16)printOffs) 270 Set16(p + 4, (UInt16)printOffs)
206 Set16(p + 6, (UInt16)len2) 271 Set16(p + 6, (UInt16)len2)
207
208 p += 8; 272 p += 8;
209 if (isSymLink) 273 if (isSymLink)
210 { 274 {
211 UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE; 275 const UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
212 Set32(p, flags) 276 Set32(p, flags)
213 p += 4; 277 p += 4;
214 } 278 }
215 279 WriteString(p + subOffs, subs);
216 if (add_Prefix_Len != 0)
217 WriteString(p + subOffs, k_LinkPrefix);
218 WriteString(p + subOffs + add_Prefix_Len * 2, path);
219 if (needPrintName) 280 if (needPrintName)
220 WriteString(p + printOffs, path); 281 WriteString(p + printOffs, path);
221 return true;
222} 282}
223 283
224#endif // defined(_WIN32) && !defined(UNDER_CE) 284#endif // defined(_WIN32) && !defined(UNDER_CE)
@@ -230,7 +290,7 @@ static void GetString(const Byte *p, unsigned len, UString &res)
230 unsigned i; 290 unsigned i;
231 for (i = 0; i < len; i++) 291 for (i = 0; i < len; i++)
232 { 292 {
233 wchar_t c = Get16(p + i * 2); 293 const wchar_t c = Get16(p + (size_t)i * 2);
234 if (c == 0) 294 if (c == 0)
235 break; 295 break;
236 s[i] = c; 296 s[i] = c;
@@ -239,6 +299,7 @@ static void GetString(const Byte *p, unsigned len, UString &res)
239 res.ReleaseBuf_SetLen(i); 299 res.ReleaseBuf_SetLen(i);
240} 300}
241 301
302
242bool CReparseAttr::Parse(const Byte *p, size_t size) 303bool CReparseAttr::Parse(const Byte *p, size_t size)
243{ 304{
244 ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; 305 ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA;
@@ -250,7 +311,12 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
250 return false; 311 return false;
251 Tag = Get32(p); 312 Tag = Get32(p);
252 if (Get16(p + 6) != 0) // padding 313 if (Get16(p + 6) != 0) // padding
253 return false; 314 {
315 // DOCs: Reserved : the field SHOULD be set to 0
316 // and MUST be ignored (by parser).
317 // Win10 ignores it.
318 MinorError = true; // optional
319 }
254 unsigned len = Get16(p + 4); 320 unsigned len = Get16(p + 4);
255 p += 8; 321 p += 8;
256 size -= 8; 322 size -= 8;
@@ -262,8 +328,6 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
262 (type & kReparseFlags_Microsoft) == 0 || 328 (type & kReparseFlags_Microsoft) == 0 ||
263 (type & 0xFFFF) != 3) 329 (type & 0xFFFF) != 3)
264 */ 330 */
265
266
267 HeaderError = false; 331 HeaderError = false;
268 332
269 if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT 333 if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT
@@ -282,8 +346,7 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
282 { 346 {
283 if (len < 4) 347 if (len < 4)
284 return false; 348 return false;
285 Flags = Get32(p); // maybe it's not Flags 349 if (Get32(p) != Z7_WIN_LX_SYMLINK_VERSION_2)
286 if (Flags != Z7_WIN_LX_SYMLINK_FLAG)
287 return false; 350 return false;
288 len -= 4; 351 len -= 4;
289 p += 4; 352 p += 4;
@@ -291,12 +354,13 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
291 unsigned i; 354 unsigned i;
292 for (i = 0; i < len; i++) 355 for (i = 0; i < len; i++)
293 { 356 {
294 char c = (char)p[i]; 357 const char c = (char)p[i];
295 s[i] = c; 358 s[i] = c;
296 if (c == 0) 359 if (c == 0)
297 break; 360 break;
298 } 361 }
299 WslName.ReleaseBuf_SetEnd(i); 362 s[i] = 0;
363 WslName.ReleaseBuf_SetLen(i);
300 MinorError = (i != len); 364 MinorError = (i != len);
301 ErrorCode = 0; 365 ErrorCode = 0;
302 return true; 366 return true;
@@ -304,10 +368,10 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
304 368
305 if (len < 8) 369 if (len < 8)
306 return false; 370 return false;
307 unsigned subOffs = Get16(p); 371 const unsigned subOffs = Get16(p);
308 unsigned subLen = Get16(p + 2); 372 const unsigned subLen = Get16(p + 2);
309 unsigned printOffs = Get16(p + 4); 373 const unsigned printOffs = Get16(p + 4);
310 unsigned printLen = Get16(p + 6); 374 const unsigned printLen = Get16(p + 6);
311 len -= 8; 375 len -= 8;
312 p += 8; 376 p += 8;
313 377
@@ -335,15 +399,17 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
335 399
336bool CReparseShortInfo::Parse(const Byte *p, size_t size) 400bool CReparseShortInfo::Parse(const Byte *p, size_t size)
337{ 401{
338 const Byte *start = p; 402 const Byte * const start = p;
339 Offset= 0; 403 Offset = 0;
340 Size = 0; 404 Size = 0;
341 if (size < 8) 405 if (size < 8)
342 return false; 406 return false;
343 UInt32 Tag = Get32(p); 407 const UInt32 Tag = Get32(p);
344 UInt32 len = Get16(p + 4); 408 UInt32 len = Get16(p + 4);
409 /*
345 if (len + 8 > size) 410 if (len + 8 > size)
346 return false; 411 return false;
412 */
347 /* 413 /*
348 if ((type & kReparseFlags_Alias) == 0 || 414 if ((type & kReparseFlags_Alias) == 0 ||
349 (type & kReparseFlags_Microsoft) == 0 || 415 (type & kReparseFlags_Microsoft) == 0 ||
@@ -353,16 +419,14 @@ bool CReparseShortInfo::Parse(const Byte *p, size_t size)
353 Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK) 419 Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK)
354 // return true; 420 // return true;
355 return false; 421 return false;
356 422 /*
357 if (Get16(p + 6) != 0) // padding 423 if (Get16(p + 6) != 0) // padding
358 return false; 424 return false;
359 425 */
360 p += 8; 426 p += 8;
361 size -= 8; 427 size -= 8;
362
363 if (len != size) // do we need that check? 428 if (len != size) // do we need that check?
364 return false; 429 return false;
365
366 if (len < 8) 430 if (len < 8)
367 return false; 431 return false;
368 unsigned subOffs = Get16(p); 432 unsigned subOffs = Get16(p);
@@ -396,10 +460,14 @@ bool CReparseAttr::IsOkNamePair() const
396{ 460{
397 if (IsLinkPrefix(SubsName)) 461 if (IsLinkPrefix(SubsName))
398 { 462 {
463 if (PrintName == GetPath())
464 return true;
465/*
399 if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) 466 if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size)))
400 return PrintName.IsEmpty(); 467 return PrintName.IsEmpty();
401 if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) 468 if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0)
402 return true; 469 return true;
470*/
403 } 471 }
404 return wcscmp(SubsName, PrintName) == 0; 472 return wcscmp(SubsName, PrintName) == 0;
405} 473}
@@ -415,21 +483,26 @@ bool CReparseAttr::IsVolume() const
415 483
416UString CReparseAttr::GetPath() const 484UString CReparseAttr::GetPath() const
417{ 485{
486 UString s (SubsName);
418 if (IsSymLink_WSL()) 487 if (IsSymLink_WSL())
419 { 488 {
420 UString u;
421 // if (CheckUTF8(attr.WslName) 489 // if (CheckUTF8(attr.WslName)
422 if (!ConvertUTF8ToUnicode(WslName, u)) 490 if (!ConvertUTF8ToUnicode(WslName, s))
423 MultiByteToUnicodeString2(u, WslName); 491 MultiByteToUnicodeString2(s, WslName);
424 return u;
425 } 492 }
426 493 else if (IsLinkPrefix(s))
427 UString s (SubsName);
428 if (IsLinkPrefix(s))
429 { 494 {
430 s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" 495 if (IsString1PrefixedByString2_NoCase_Ascii(s.Ptr(), k_LinkPrefix_UNC))
431 if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) 496 {
432 s.DeleteFrontal(k_LinkPrefix_Size); 497 s.DeleteFrontal(6);
498 s.ReplaceOneCharAtPos(0, '\\');
499 }
500 else
501 {
502 s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
503 if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
504 s.DeleteFrontal(k_LinkPrefix_Size);
505 }
433 } 506 }
434 return s; 507 return s;
435} 508}
@@ -468,7 +541,7 @@ bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMA
468static bool CreatePrefixDirOfFile(CFSTR path) 541static bool CreatePrefixDirOfFile(CFSTR path)
469{ 542{
470 FString path2 (path); 543 FString path2 (path);
471 int pos = path2.ReverseFind_PathSepar(); 544 const int pos = path2.ReverseFind_PathSepar();
472 if (pos < 0) 545 if (pos < 0)
473 return true; 546 return true;
474 #ifdef _WIN32 547 #ifdef _WIN32
@@ -494,6 +567,8 @@ static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD si
494} 567}
495 568
496 569
570// MOUNT_POINT (Junction Point) and LX_SYMLINK (WSL) can be written without administrator rights.
571// SYMLINK requires administrator rights.
497// If there is Reparse data already, it still writes new Reparse data 572// If there is Reparse data already, it still writes new Reparse data
498bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) 573bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
499{ 574{
@@ -540,10 +615,11 @@ bool DeleteReparseData(CFSTR path)
540 SetLastError(ERROR_INVALID_REPARSE_DATA); 615 SetLastError(ERROR_INVALID_REPARSE_DATA);
541 return false; 616 return false;
542 } 617 }
543 BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; 618 // BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
544 memset(buf, 0, sizeof(buf)); 619 // memset(buf, 0, sizeof(buf));
545 memcpy(buf, reparseData, 4); // tag 620 // memcpy(buf, reparseData, 4); // tag
546 return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); 621 memset(reparseData + 4, 0, my_REPARSE_DATA_BUFFER_HEADER_SIZE - 4);
622 return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, reparseData, my_REPARSE_DATA_BUFFER_HEADER_SIZE);
547} 623}
548 624
549} 625}
diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp
index 1f4a6da..eb62567 100644
--- a/CPP/Windows/FileName.cpp
+++ b/CPP/Windows/FileName.cpp
@@ -65,8 +65,15 @@ void NormalizeDirPathPrefix(UString &dirPath)
65 dirPath.Add_PathSepar(); 65 dirPath.Add_PathSepar();
66} 66}
67 67
68
69#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
70bool IsDrivePath (const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
71// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
72
68#ifdef _WIN32 73#ifdef _WIN32
69 74
75bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
76
70#ifndef USE_UNICODE_FSTRING 77#ifndef USE_UNICODE_FSTRING
71#ifdef Z7_LONG_PATH 78#ifdef Z7_LONG_PATH
72static void NormalizeDirSeparators(UString &s) 79static void NormalizeDirSeparators(UString &s)
@@ -87,13 +94,6 @@ void NormalizeDirSeparators(FString &s)
87 s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); 94 s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR);
88} 95}
89 96
90#endif
91
92
93#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
94
95bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
96
97bool IsAltPathPrefix(CFSTR s) throw() 97bool IsAltPathPrefix(CFSTR s) throw()
98{ 98{
99 unsigned len = MyStringLen(s); 99 unsigned len = MyStringLen(s);
@@ -117,16 +117,23 @@ bool IsAltPathPrefix(CFSTR s) throw()
117 return true; 117 return true;
118} 118}
119 119
120#if defined(_WIN32) && !defined(UNDER_CE) 120#endif // _WIN32
121
121 122
122const char * const kSuperPathPrefix = "\\\\?\\"; 123const char * const kSuperPathPrefix =
124 STRING_PATH_SEPARATOR
125 STRING_PATH_SEPARATOR "?"
126 STRING_PATH_SEPARATOR;
123#ifdef Z7_LONG_PATH 127#ifdef Z7_LONG_PATH
124static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; 128static const char * const kSuperUncPrefix =
129 STRING_PATH_SEPARATOR
130 STRING_PATH_SEPARATOR "?"
131 STRING_PATH_SEPARATOR "UNC"
132 STRING_PATH_SEPARATOR;
125#endif 133#endif
126 134
127#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) 135#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3]))
128#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) 136#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3]))
129#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
130 137
131#define IS_UNC_WITH_SLASH(s) ( \ 138#define IS_UNC_WITH_SLASH(s) ( \
132 ((s)[0] == 'U' || (s)[0] == 'u') \ 139 ((s)[0] == 'U' || (s)[0] == 'u') \
@@ -134,6 +141,16 @@ static const char * const kSuperUncPrefix = "\\\\?\\UNC\\";
134 && ((s)[2] == 'C' || (s)[2] == 'c') \ 141 && ((s)[2] == 'C' || (s)[2] == 'c') \
135 && IS_SEPAR((s)[3])) 142 && IS_SEPAR((s)[3]))
136 143
144static const unsigned kDrivePrefixSize = 3; /* c:\ */
145
146bool IsSuperPath(const wchar_t *s) throw();
147bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
148// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
149
150#if defined(_WIN32) && !defined(UNDER_CE)
151
152#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
153bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
137bool IsDevicePath(CFSTR s) throw() 154bool IsDevicePath(CFSTR s) throw()
138{ 155{
139 #ifdef UNDER_CE 156 #ifdef UNDER_CE
@@ -154,7 +171,7 @@ bool IsDevicePath(CFSTR s) throw()
154 171
155 if (!IS_DEVICE_PATH(s)) 172 if (!IS_DEVICE_PATH(s))
156 return false; 173 return false;
157 unsigned len = MyStringLen(s); 174 const unsigned len = MyStringLen(s);
158 if (len == 6 && s[5] == ':') 175 if (len == 6 && s[5] == ':')
159 return true; 176 return true;
160 if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) 177 if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive"))
@@ -174,7 +191,7 @@ bool IsNetworkPath(CFSTR s) throw()
174 return false; 191 return false;
175 if (IsSuperUncPath(s)) 192 if (IsSuperUncPath(s))
176 return true; 193 return true;
177 FChar c = s[2]; 194 const FChar c = s[2];
178 return (c != '.' && c != '?'); 195 return (c != '.' && c != '?');
179} 196}
180 197
@@ -187,7 +204,7 @@ unsigned GetNetworkServerPrefixSize(CFSTR s) throw()
187 prefixSize = kSuperUncPathPrefixSize; 204 prefixSize = kSuperUncPathPrefixSize;
188 else 205 else
189 { 206 {
190 FChar c = s[2]; 207 const FChar c = s[2];
191 if (c == '.' || c == '?') 208 if (c == '.' || c == '?')
192 return 0; 209 return 0;
193 } 210 }
@@ -209,14 +226,6 @@ bool IsNetworkShareRootPath(CFSTR s) throw()
209 return s[(unsigned)pos + 1] == 0; 226 return s[(unsigned)pos + 1] == 0;
210} 227}
211 228
212static const unsigned kDrivePrefixSize = 3; /* c:\ */
213
214bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
215// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
216bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
217bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
218// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
219
220bool IsAltStreamPrefixWithColon(const UString &s) throw() 229bool IsAltStreamPrefixWithColon(const UString &s) throw()
221{ 230{
222 if (s.IsEmpty()) 231 if (s.IsEmpty())
@@ -349,14 +358,16 @@ unsigned GetRootPrefixSize(CFSTR s) throw()
349} 358}
350 359
351#endif // USE_UNICODE_FSTRING 360#endif // USE_UNICODE_FSTRING
361#endif // _WIN32
362
352 363
353static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() 364static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw()
354{ 365{
355 // Network path: we look "server\path\" as root prefix 366 // Network path: we look "server\path\" as root prefix
356 int pos = FindSepar(s); 367 const int pos = FindSepar(s);
357 if (pos < 0) 368 if (pos < 0)
358 return 0; 369 return 0;
359 int pos2 = FindSepar(s + (unsigned)pos + 1); 370 const int pos2 = FindSepar(s + (unsigned)pos + 1);
360 if (pos2 < 0) 371 if (pos2 < 0)
361 return 0; 372 return 0;
362 return (unsigned)(pos + pos2 + 2); 373 return (unsigned)(pos + pos2 + 2);
@@ -370,7 +381,7 @@ static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw()
370 return 0; 381 return 0;
371 if (s[1] == 0 || !IS_SEPAR(s[1])) 382 if (s[1] == 0 || !IS_SEPAR(s[1]))
372 return 1; 383 return 1;
373 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 384 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
374 return (size == 0) ? 0 : 2 + size; 385 return (size == 0) ? 0 : 2 + size;
375} 386}
376 387
@@ -378,17 +389,21 @@ static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw()
378{ 389{
379 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 390 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
380 { 391 {
381 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 392 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
382 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 393 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
383 } 394 }
384 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 395 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
385 int pos = FindSepar(s + kSuperPathPrefixSize); 396 const int pos = FindSepar(s + kSuperPathPrefixSize);
386 if (pos < 0) 397 if (pos < 0)
387 return 0; 398 return 0;
388 return kSuperPathPrefixSize + (unsigned)(pos + 1); 399 return kSuperPathPrefixSize + (unsigned)(pos + 1);
389} 400}
390 401
402#ifdef _WIN32
391unsigned GetRootPrefixSize(const wchar_t *s) throw() 403unsigned GetRootPrefixSize(const wchar_t *s) throw()
404#else
405unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw()
406#endif
392{ 407{
393 if (IS_DEVICE_PATH(s)) 408 if (IS_DEVICE_PATH(s))
394 return kDevicePathPrefixSize; 409 return kDevicePathPrefixSize;
@@ -397,7 +412,7 @@ unsigned GetRootPrefixSize(const wchar_t *s) throw()
397 return GetRootPrefixSize_Of_SimplePath(s); 412 return GetRootPrefixSize_Of_SimplePath(s);
398} 413}
399 414
400#else // _WIN32 415#ifndef _WIN32
401 416
402bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } 417bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); }
403 418
diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h
index 219b656..ce26e78 100644
--- a/CPP/Windows/FileName.h
+++ b/CPP/Windows/FileName.h
@@ -25,13 +25,13 @@ bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars li
25 25
26bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ 26bool IsAltPathPrefix(CFSTR s) throw(); /* name: */
27 27
28#if defined(_WIN32) && !defined(UNDER_CE)
29
30extern const char * const kSuperPathPrefix; /* \\?\ */ 28extern const char * const kSuperPathPrefix; /* \\?\ */
31const unsigned kDevicePathPrefixSize = 4; 29const unsigned kDevicePathPrefixSize = 4;
32const unsigned kSuperPathPrefixSize = 4; 30const unsigned kSuperPathPrefixSize = 4;
33const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; 31const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4;
34 32
33#if defined(_WIN32) && !defined(UNDER_CE)
34
35bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ 35bool IsDevicePath(CFSTR s) throw(); /* \\.\ */
36bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ 36bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */
37bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ 37bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */
@@ -86,6 +86,15 @@ int FindAltStreamColon(CFSTR path) throw();
86bool IsAbsolutePath(const wchar_t *s) throw(); 86bool IsAbsolutePath(const wchar_t *s) throw();
87unsigned GetRootPrefixSize(const wchar_t *s) throw(); 87unsigned GetRootPrefixSize(const wchar_t *s) throw();
88 88
89#ifndef _WIN32
90/* GetRootPrefixSize_WINDOWS() is called in linux, but it parses path by windows rules.
91 It supports only paths system (linux) slash separators (STRING_PATH_SEPARATOR),
92 It doesn't parses paths with backslash (windows) separators.
93 "c:/dir/file" is supported.
94*/
95unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw();
96#endif
97
89#ifdef Z7_LONG_PATH 98#ifdef Z7_LONG_PATH
90 99
91const int kSuperPathType_UseOnlyMain = 0; 100const int kSuperPathType_UseOnlyMain = 0;
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp
index 5fa87f3..4745785 100644
--- a/CPP/Windows/System.cpp
+++ b/CPP/Windows/System.cpp
@@ -25,6 +25,69 @@ namespace NSystem {
25 25
26#ifdef _WIN32 26#ifdef _WIN32
27 27
28/*
29note: returned value in 32-bit version can be limited by value 32.
30 while 64-bit version returns full value.
31GetMaximumProcessorCount(groupNumber) can return higher value than
32GetActiveProcessorCount(groupNumber) in some cases, because CPUs can be added.
33*/
34// typedef DWORD (WINAPI *Func_GetMaximumProcessorCount)(WORD GroupNumber);
35typedef DWORD (WINAPI *Func_GetActiveProcessorCount)(WORD GroupNumber);
36typedef WORD (WINAPI *Func_GetActiveProcessorGroupCount)(VOID);
37/*
38#if 0 && defined(ALL_PROCESSOR_GROUPS)
39#define MY_ALL_PROCESSOR_GROUPS ALL_PROCESSOR_GROUPS
40#else
41#define MY_ALL_PROCESSOR_GROUPS 0xffff
42#endif
43*/
44
45Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
46
47bool CCpuGroups::Load()
48{
49 NumThreadsTotal = 0;
50 GroupSizes.Clear();
51 const HMODULE hmodule = ::GetModuleHandleA("kernel32.dll");
52 // Is_Win11_Groups = GetProcAddress(hmodule, "SetThreadSelectedCpuSetMasks") != NULL;
53 const
54 Func_GetActiveProcessorGroupCount
55 fn_GetActiveProcessorGroupCount = Z7_GET_PROC_ADDRESS(
56 Func_GetActiveProcessorGroupCount, hmodule,
57 "GetActiveProcessorGroupCount");
58 const
59 Func_GetActiveProcessorCount
60 fn_GetActiveProcessorCount = Z7_GET_PROC_ADDRESS(
61 Func_GetActiveProcessorCount, hmodule,
62 "GetActiveProcessorCount");
63 if (!fn_GetActiveProcessorGroupCount ||
64 !fn_GetActiveProcessorCount)
65 return false;
66
67 const unsigned numGroups = fn_GetActiveProcessorGroupCount();
68 if (numGroups == 0)
69 return false;
70 UInt32 sum = 0;
71 for (unsigned i = 0; i < numGroups; i++)
72 {
73 const UInt32 num = fn_GetActiveProcessorCount((WORD)i);
74 /*
75 if (num == 0)
76 {
77 // it means error
78 // but is it possible that some group is empty by some reason?
79 // GroupSizes.Clear();
80 // return false;
81 }
82 */
83 sum += num;
84 GroupSizes.Add(num);
85 }
86 NumThreadsTotal = sum;
87 // NumThreadsTotal = fn_GetActiveProcessorCount(MY_ALL_PROCESSOR_GROUPS);
88 return true;
89}
90
28UInt32 CountAffinity(DWORD_PTR mask) 91UInt32 CountAffinity(DWORD_PTR mask)
29{ 92{
30 UInt32 num = 0; 93 UInt32 num = 0;
@@ -38,31 +101,62 @@ UInt32 CountAffinity(DWORD_PTR mask)
38 101
39BOOL CProcessAffinity::Get() 102BOOL CProcessAffinity::Get()
40{ 103{
41 #ifndef UNDER_CE 104 IsGroupMode = false;
42 return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); 105 Groups.Load();
43 #else 106 // SetThreadAffinityMask(GetCurrentThread(), 1);
44 return FALSE; 107 // SetProcessAffinityMask(GetCurrentProcess(), 1);
45 #endif 108 BOOL res = GetProcessAffinityMask(GetCurrentProcess(),
109 &processAffinityMask, &systemAffinityMask);
110 /* DOCs: On a system with more than 64 processors, if the threads
111 of the calling process are in a single processor group, the
112 function sets the variables pointed to by lpProcessAffinityMask
113 and lpSystemAffinityMask to the process affinity mask and the
114 processor mask of active logical processors for that group.
115 If the calling process contains threads in multiple groups,
116 the function returns zero for both affinity masks
117
118 note: tested in Win10: GetProcessAffinityMask() doesn't return 0
119 in (processAffinityMask) and (systemAffinityMask) masks.
120 We need to test it in Win11: how to get mask==0 from GetProcessAffinityMask()?
121 */
122 if (!res)
123 {
124 processAffinityMask = 0;
125 systemAffinityMask = 0;
126 }
127 if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
128 if (// !res ||
129 processAffinityMask == 0 || // to support case described in DOCs and for (!res) case
130 processAffinityMask == systemAffinityMask) // for default nonchanged affinity
131 {
132 // we set IsGroupMode only if processAffinity is default (not changed).
133 res = TRUE;
134 IsGroupMode = true;
135 }
136 return res;
46} 137}
47 138
48 139
140UInt32 CProcessAffinity::Load_and_GetNumberOfThreads()
141{
142 if (Get())
143 {
144 const UInt32 numProcessors = GetNumProcessThreads();
145 if (numProcessors)
146 return numProcessors;
147 }
148 SYSTEM_INFO systemInfo;
149 GetSystemInfo(&systemInfo);
150 // the number of logical processors in the current group
151 return systemInfo.dwNumberOfProcessors;
152}
153
49UInt32 GetNumberOfProcessors() 154UInt32 GetNumberOfProcessors()
50{ 155{
51 // We need to know how many threads we can use. 156 // We need to know how many threads we can use.
52 // By default the process is assigned to one group. 157 // By default the process is assigned to one group.
53 // So we get the number of logical processors (threads)
54 // assigned to current process in the current group.
55 // Group size can be smaller than total number logical processors, for exammple, 2x36
56
57 CProcessAffinity pa; 158 CProcessAffinity pa;
58 159 return pa.Load_and_GetNumberOfThreads();
59 if (pa.Get() && pa.processAffinityMask != 0)
60 return pa.GetNumProcessThreads();
61
62 SYSTEM_INFO systemInfo;
63 GetSystemInfo(&systemInfo);
64 // the number of logical processors in the current group
65 return (UInt32)systemInfo.dwNumberOfProcessors;
66} 160}
67 161
68#else 162#else
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h
index 9951b8b..0c80373 100644
--- a/CPP/Windows/System.h
+++ b/CPP/Windows/System.h
@@ -9,6 +9,7 @@
9#endif 9#endif
10 10
11#include "../Common/MyTypes.h" 11#include "../Common/MyTypes.h"
12#include "../Common/MyVector.h"
12#include "../Common/MyWindows.h" 13#include "../Common/MyWindows.h"
13 14
14namespace NWindows { 15namespace NWindows {
@@ -16,6 +17,34 @@ namespace NSystem {
16 17
17#ifdef _WIN32 18#ifdef _WIN32
18 19
20struct CCpuGroups
21{
22 CRecordVector<UInt32> GroupSizes;
23 UInt32 NumThreadsTotal; // sum of threads in all groups
24 // bool Is_Win11_Groups; // useless
25
26 void Get_GroupSize_Min_Max(UInt32 &minSize, UInt32 &maxSize) const
27 {
28 unsigned num = GroupSizes.Size();
29 UInt32 minSize2 = 0, maxSize2 = 0;
30 if (num)
31 {
32 minSize2 = (UInt32)0 - 1;
33 do
34 {
35 const UInt32 v = GroupSizes[--num];
36 if (minSize2 > v) minSize2 = v;
37 if (maxSize2 < v) maxSize2 = v;
38 }
39 while (num);
40 }
41 minSize = minSize2;
42 maxSize = maxSize2;
43 }
44 bool Load();
45 CCpuGroups(): NumThreadsTotal(0) {}
46};
47
19UInt32 CountAffinity(DWORD_PTR mask); 48UInt32 CountAffinity(DWORD_PTR mask);
20 49
21struct CProcessAffinity 50struct CProcessAffinity
@@ -25,14 +54,28 @@ struct CProcessAffinity
25 DWORD_PTR processAffinityMask; 54 DWORD_PTR processAffinityMask;
26 DWORD_PTR systemAffinityMask; 55 DWORD_PTR systemAffinityMask;
27 56
57 CCpuGroups Groups;
58 bool IsGroupMode;
59 /*
60 IsGroupMode == true, if
61 Groups.GroupSizes.Size() > 1) && { dafalt affinity was not changed }
62 IsGroupMode == false, if single group or affinity was changed
63 */
64
65 UInt32 Load_and_GetNumberOfThreads();
66
28 void InitST() 67 void InitST()
29 { 68 {
30 // numProcessThreads = 1; 69 // numProcessThreads = 1;
31 // numSysThreads = 1; 70 // numSysThreads = 1;
32 processAffinityMask = 1; 71 processAffinityMask = 1;
33 systemAffinityMask = 1; 72 systemAffinityMask = 1;
73 IsGroupMode = false;
74 // Groups.NumThreadsTotal = 0;
75 // Groups.Is_Win11_Groups = false;
34 } 76 }
35 77
78/*
36 void CpuZero() 79 void CpuZero()
37 { 80 {
38 processAffinityMask = 0; 81 processAffinityMask = 0;
@@ -42,9 +85,23 @@ struct CProcessAffinity
42 { 85 {
43 processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); 86 processAffinityMask |= ((DWORD_PTR)1 << cpuIndex);
44 } 87 }
88*/
45 89
46 UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); } 90 UInt32 GetNumProcessThreads() const
47 UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); } 91 {
92 if (IsGroupMode)
93 return Groups.NumThreadsTotal;
94 // IsGroupMode == false
95 // so we don't want to use groups
96 // we return number of threads in default primary group:
97 return CountAffinity(processAffinityMask);
98 }
99 UInt32 GetNumSystemThreads() const
100 {
101 if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal)
102 return Groups.NumThreadsTotal;
103 return CountAffinity(systemAffinityMask);
104 }
48 105
49 BOOL Get(); 106 BOOL Get();
50 107
diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h
index d72f64c..75c1616 100644
--- a/CPP/Windows/Thread.h
+++ b/CPP/Windows/Thread.h
@@ -26,8 +26,10 @@ public:
26 { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } 26 { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); }
27 WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet) 27 WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet)
28 { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } 28 { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); }
29 29
30 #ifdef _WIN32 30#ifdef _WIN32
31 WRes Create_With_Group(THREAD_FUNC_TYPE startAddress, LPVOID param, unsigned group, CAffinityMask affinity = 0)
32 { return Thread_Create_With_Group(&thread, startAddress, param, group, affinity); }
31 operator HANDLE() { return thread; } 33 operator HANDLE() { return thread; }
32 void Attach(HANDLE handle) { thread = handle; } 34 void Attach(HANDLE handle) { thread = handle; }
33 HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; } 35 HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
@@ -36,7 +38,7 @@ public:
36 bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); } 38 bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
37 int GetPriority() { return ::GetThreadPriority(thread); } 39 int GetPriority() { return ::GetThreadPriority(thread); }
38 bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); } 40 bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
39 #endif 41#endif
40}; 42};
41 43
42} 44}
diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp
index bbd79ba..4e3bc59 100644
--- a/CPP/Windows/TimeUtils.cpp
+++ b/CPP/Windows/TimeUtils.cpp
@@ -258,8 +258,9 @@ bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
258 FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0, 258 FreeBSD 11.0, NetBSD 7.1, OpenBSD 6.0,
259 Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, 259 Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3,
260 Cygwin 2.9, mingw, MSVC 14, Android 9.0. 260 Cygwin 2.9, mingw, MSVC 14, Android 9.0.
261 Android NDK defines TIME_UTC but doesn't have the timespec_get().
261*/ 262*/
262#if defined(TIME_UTC) 263#if defined(TIME_UTC) && !defined(__ANDROID__)
263#define ZIP7_USE_timespec_get 264#define ZIP7_USE_timespec_get
264// #pragma message("ZIP7_USE_timespec_get") 265// #pragma message("ZIP7_USE_timespec_get")
265#elif defined(CLOCK_REALTIME) 266#elif defined(CLOCK_REALTIME)