diff options
Diffstat (limited to 'CPP/Windows')
| -rw-r--r-- | CPP/Windows/FileDir.cpp | 29 | ||||
| -rw-r--r-- | CPP/Windows/FileDir.h | 5 | ||||
| -rw-r--r-- | CPP/Windows/FileFind.cpp | 9 | ||||
| -rw-r--r-- | CPP/Windows/FileIO.h | 43 | ||||
| -rw-r--r-- | CPP/Windows/FileLink.cpp | 244 | ||||
| -rw-r--r-- | CPP/Windows/FileName.cpp | 71 | ||||
| -rw-r--r-- | CPP/Windows/FileName.h | 13 | ||||
| -rw-r--r-- | CPP/Windows/System.cpp | 128 | ||||
| -rw-r--r-- | CPP/Windows/System.h | 61 | ||||
| -rw-r--r-- | CPP/Windows/Thread.h | 8 | ||||
| -rw-r--r-- | CPP/Windows/TimeUtils.cpp | 3 |
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 | ||
| 654 | bool 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 | ||
| 79 | bool DeleteFileAlways(CFSTR name); | 79 | bool DeleteFileAlways(CFSTR name); |
| 80 | bool RemoveDirWithSubItems(const FString &path); | 80 | bool RemoveDirWithSubItems(const FString &path); |
| 81 | #ifdef _WIN32 | ||
| 82 | bool RemoveDirAlways_if_Empty(const FString &path); | ||
| 83 | #else | ||
| 84 | #define RemoveDirAlways_if_Empty RemoveDir | ||
| 85 | #endif | ||
| 81 | 86 | ||
| 82 | bool MyGetFullPathName(CFSTR path, FString &resFullPath); | 87 | bool MyGetFullPathName(CFSTR path, FString &resFullPath); |
| 83 | bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName); | 88 | bool 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 | ||
| 774 | bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) | 781 | bool 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 { | |||
| 44 | namespace NFile { | 43 | namespace NFile { |
| 45 | 44 | ||
| 46 | #if defined(_WIN32) && !defined(UNDER_CE) | 45 | #if defined(_WIN32) && !defined(UNDER_CE) |
| 47 | bool 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 | */ | ||
| 52 | void Convert_WinPath_to_WslLinuxPath(FString &path, bool convertDrivePath); | ||
| 53 | // (path) must use Linux path separator (/). | ||
| 54 | void 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 | */ | ||
| 64 | void FillLinkData_WinLink(CByteBuffer &dest, const wchar_t *path, bool isSymLink); | ||
| 65 | // in: (CByteBuffer &dest) is empty | ||
| 66 | inline 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 | ||
| 50 | struct CReparseShortInfo | 75 | struct 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 { | |||
| 39 | using namespace NName; | 39 | using namespace NName; |
| 40 | 40 | ||
| 41 | /* | 41 | /* |
| 42 | Win10 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 | |||
| 84 | DOCS: | ||
| 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 | |||
| 89 | reparse tags, with the exception of IO_REPARSE_TAG_SYMLINK, | ||
| 90 | are processed on the server and are not processed by a client | ||
| 91 | after transmission over the wire. | ||
| 92 | Clients 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 | ||
| 96 | static const wchar_t * const k_LinkPrefix = L"\\??\\"; | 118 | static const char * const k_LinkPrefix = "\\??\\"; |
| 119 | static const char * const k_LinkPrefix_UNC = "\\??\\UNC\\"; | ||
| 97 | static const unsigned k_LinkPrefix_Size = 4; | 120 | static const unsigned k_LinkPrefix_Size = 4; |
| 98 | 121 | ||
| 99 | static bool IsLinkPrefix(const wchar_t *s) | 122 | static bool IsLinkPrefix(const wchar_t *s) |
| @@ -102,7 +125,7 @@ static bool IsLinkPrefix(const wchar_t *s) | |||
| 102 | } | 125 | } |
| 103 | 126 | ||
| 104 | /* | 127 | /* |
| 105 | static const wchar_t * const k_VolumePrefix = L"Volume{"; | 128 | static const char * const k_VolumePrefix = "Volume{"; |
| 106 | static const bool IsVolumeName(const wchar_t *s) | 129 | static 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 | ||
| 129 | bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) | 152 | #ifdef _WIN32 |
| 153 | void 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; | 168 | static const unsigned k_Link_Size_Limit = 1u << 16; // 16-bit field is used for size. |
| 169 | |||
| 170 | void 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)) | 190 | void 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 | |||
| 242 | bool CReparseAttr::Parse(const Byte *p, size_t size) | 303 | bool 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 | ||
| 336 | bool CReparseShortInfo::Parse(const Byte *p, size_t size) | 400 | bool 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 | ||
| 416 | UString CReparseAttr::GetPath() const | 484 | UString 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 | |||
| 468 | static bool CreatePrefixDirOfFile(CFSTR path) | 541 | static 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 |
| 498 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) | 573 | bool 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'))) | ||
| 70 | bool 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 | ||
| 75 | bool 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 |
| 72 | static void NormalizeDirSeparators(UString &s) | 79 | static 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 | |||
| 95 | bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } | ||
| 96 | |||
| 97 | bool IsAltPathPrefix(CFSTR s) throw() | 97 | bool 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 | ||
| 122 | const char * const kSuperPathPrefix = "\\\\?\\"; | 123 | const 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 |
| 124 | static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; | 128 | static 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 | ||
| 144 | static const unsigned kDrivePrefixSize = 3; /* c:\ */ | ||
| 145 | |||
| 146 | bool IsSuperPath(const wchar_t *s) throw(); | ||
| 147 | bool 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])) | ||
| 153 | bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } | ||
| 137 | bool IsDevicePath(CFSTR s) throw() | 154 | bool 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 | ||
| 212 | static const unsigned kDrivePrefixSize = 3; /* c:\ */ | ||
| 213 | |||
| 214 | bool 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; } | ||
| 216 | bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } | ||
| 217 | bool 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 | |||
| 220 | bool IsAltStreamPrefixWithColon(const UString &s) throw() | 229 | bool 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 | ||
| 353 | static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() | 364 | static 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 | ||
| 391 | unsigned GetRootPrefixSize(const wchar_t *s) throw() | 403 | unsigned GetRootPrefixSize(const wchar_t *s) throw() |
| 404 | #else | ||
| 405 | unsigned 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 | ||
| 402 | bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } | 417 | bool 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 | ||
| 26 | bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ | 26 | bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ |
| 27 | 27 | ||
| 28 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 29 | |||
| 30 | extern const char * const kSuperPathPrefix; /* \\?\ */ | 28 | extern const char * const kSuperPathPrefix; /* \\?\ */ |
| 31 | const unsigned kDevicePathPrefixSize = 4; | 29 | const unsigned kDevicePathPrefixSize = 4; |
| 32 | const unsigned kSuperPathPrefixSize = 4; | 30 | const unsigned kSuperPathPrefixSize = 4; |
| 33 | const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; | 31 | const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4; |
| 34 | 32 | ||
| 33 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 34 | |||
| 35 | bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ | 35 | bool IsDevicePath(CFSTR s) throw(); /* \\.\ */ |
| 36 | bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ | 36 | bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */ |
| 37 | bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ | 37 | bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */ |
| @@ -86,6 +86,15 @@ int FindAltStreamColon(CFSTR path) throw(); | |||
| 86 | bool IsAbsolutePath(const wchar_t *s) throw(); | 86 | bool IsAbsolutePath(const wchar_t *s) throw(); |
| 87 | unsigned GetRootPrefixSize(const wchar_t *s) throw(); | 87 | unsigned 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 | */ | ||
| 95 | unsigned GetRootPrefixSize_WINDOWS(const wchar_t *s) throw(); | ||
| 96 | #endif | ||
| 97 | |||
| 89 | #ifdef Z7_LONG_PATH | 98 | #ifdef Z7_LONG_PATH |
| 90 | 99 | ||
| 91 | const int kSuperPathType_UseOnlyMain = 0; | 100 | const 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 | /* | ||
| 29 | note: returned value in 32-bit version can be limited by value 32. | ||
| 30 | while 64-bit version returns full value. | ||
| 31 | GetMaximumProcessorCount(groupNumber) can return higher value than | ||
| 32 | GetActiveProcessorCount(groupNumber) in some cases, because CPUs can be added. | ||
| 33 | */ | ||
| 34 | // typedef DWORD (WINAPI *Func_GetMaximumProcessorCount)(WORD GroupNumber); | ||
| 35 | typedef DWORD (WINAPI *Func_GetActiveProcessorCount)(WORD GroupNumber); | ||
| 36 | typedef 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 | |||
| 45 | Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION | ||
| 46 | |||
| 47 | bool 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 | |||
| 28 | UInt32 CountAffinity(DWORD_PTR mask) | 91 | UInt32 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 | ||
| 39 | BOOL CProcessAffinity::Get() | 102 | BOOL 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 | ||
| 140 | UInt32 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 | |||
| 49 | UInt32 GetNumberOfProcessors() | 154 | UInt32 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 | ||
| 14 | namespace NWindows { | 15 | namespace NWindows { |
| @@ -16,6 +17,34 @@ namespace NSystem { | |||
| 16 | 17 | ||
| 17 | #ifdef _WIN32 | 18 | #ifdef _WIN32 |
| 18 | 19 | ||
| 20 | struct 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 | |||
| 19 | UInt32 CountAffinity(DWORD_PTR mask); | 48 | UInt32 CountAffinity(DWORD_PTR mask); |
| 20 | 49 | ||
| 21 | struct CProcessAffinity | 50 | struct 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) |
