diff options
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 | } |