diff options
| author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2025-07-05 00:00:00 +0000 |
|---|---|---|
| committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2025-07-05 19:27:33 +0500 |
| commit | 395149956d696e6e3099d8b76d797437f94a6942 (patch) | |
| tree | 6ed5013a637078ae2dfdc4acf1ad93bf29cea356 /CPP/Windows/FileLink.cpp | |
| parent | e5431fa6f5505e385c6f9367260717e9c47dc2ee (diff) | |
| download | 7zip-25.00.tar.gz 7zip-25.00.tar.bz2 7zip-25.00.zip | |
25.0025.00
Diffstat (limited to 'CPP/Windows/FileLink.cpp')
| -rw-r--r-- | CPP/Windows/FileLink.cpp | 244 |
1 files changed, 160 insertions, 84 deletions
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 | } |
