diff options
| author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
|---|---|---|
| committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
| commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
| tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/Windows/FileLink.cpp | |
| parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
| download | 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.gz 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.bz2 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.zip | |
'21.07'21.07
Diffstat (limited to 'CPP/Windows/FileLink.cpp')
| -rw-r--r-- | CPP/Windows/FileLink.cpp | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp new file mode 100644 index 0000000..8ce634f --- /dev/null +++ b/CPP/Windows/FileLink.cpp | |||
| @@ -0,0 +1,613 @@ | |||
| 1 | // Windows/FileLink.cpp | ||
| 2 | |||
| 3 | #include "StdAfx.h" | ||
| 4 | |||
| 5 | #include "../../C/CpuArch.h" | ||
| 6 | |||
| 7 | #ifndef _WIN32 | ||
| 8 | #include <unistd.h> | ||
| 9 | #endif | ||
| 10 | |||
| 11 | #ifdef SUPPORT_DEVICE_FILE | ||
| 12 | #include "../../C/Alloc.h" | ||
| 13 | #endif | ||
| 14 | |||
| 15 | #include "../Common/UTFConvert.h" | ||
| 16 | #include "../Common/StringConvert.h" | ||
| 17 | |||
| 18 | #include "FileDir.h" | ||
| 19 | #include "FileFind.h" | ||
| 20 | #include "FileIO.h" | ||
| 21 | #include "FileName.h" | ||
| 22 | |||
| 23 | #ifndef _UNICODE | ||
| 24 | extern bool g_IsNT; | ||
| 25 | #endif | ||
| 26 | |||
| 27 | namespace NWindows { | ||
| 28 | namespace NFile { | ||
| 29 | |||
| 30 | using namespace NName; | ||
| 31 | |||
| 32 | /* | ||
| 33 | Reparse Points (Junctions and Symbolic Links): | ||
| 34 | struct | ||
| 35 | { | ||
| 36 | UInt32 Tag; | ||
| 37 | UInt16 Size; // not including starting 8 bytes | ||
| 38 | UInt16 Reserved; // = 0 | ||
| 39 | |||
| 40 | UInt16 SubstituteOffset; // offset in bytes from start of namesChars | ||
| 41 | UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL | ||
| 42 | UInt16 PrintOffset; // offset in bytes from start of namesChars | ||
| 43 | UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL | ||
| 44 | |||
| 45 | [UInt32] Flags; // for Symbolic Links only. | ||
| 46 | |||
| 47 | UInt16 namesChars[] | ||
| 48 | } | ||
| 49 | |||
| 50 | MOUNT_POINT (Junction point): | ||
| 51 | 1) there is NUL wchar after path | ||
| 52 | 2) Default Order in table: | ||
| 53 | Substitute Path | ||
| 54 | Print Path | ||
| 55 | 3) pathnames can not contain dot directory names | ||
| 56 | |||
| 57 | SYMLINK: | ||
| 58 | 1) there is no NUL wchar after path | ||
| 59 | 2) Default Order in table: | ||
| 60 | Print Path | ||
| 61 | Substitute Path | ||
| 62 | */ | ||
| 63 | |||
| 64 | /* | ||
| 65 | Win10 WSL2: | ||
| 66 | admin rights + sudo: it creates normal windows symbolic link. | ||
| 67 | in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point. | ||
| 68 | */ | ||
| 69 | |||
| 70 | /* | ||
| 71 | static const UInt32 kReparseFlags_Alias = (1 << 29); | ||
| 72 | static const UInt32 kReparseFlags_HighLatency = (1 << 30); | ||
| 73 | static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); | ||
| 74 | |||
| 75 | #define _my_IO_REPARSE_TAG_HSM (0xC0000004L) | ||
| 76 | #define _my_IO_REPARSE_TAG_HSM2 (0x80000006L) | ||
| 77 | #define _my_IO_REPARSE_TAG_SIS (0x80000007L) | ||
| 78 | #define _my_IO_REPARSE_TAG_WIM (0x80000008L) | ||
| 79 | #define _my_IO_REPARSE_TAG_CSV (0x80000009L) | ||
| 80 | #define _my_IO_REPARSE_TAG_DFS (0x8000000AL) | ||
| 81 | #define _my_IO_REPARSE_TAG_DFSR (0x80000012L) | ||
| 82 | */ | ||
| 83 | |||
| 84 | #define Get16(p) GetUi16(p) | ||
| 85 | #define Get32(p) GetUi32(p) | ||
| 86 | |||
| 87 | static const wchar_t * const k_LinkPrefix = L"\\??\\"; | ||
| 88 | static const unsigned k_LinkPrefix_Size = 4; | ||
| 89 | |||
| 90 | static bool IsLinkPrefix(const wchar_t *s) | ||
| 91 | { | ||
| 92 | return IsString1PrefixedByString2(s, k_LinkPrefix); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* | ||
| 96 | static const wchar_t * const k_VolumePrefix = L"Volume{"; | ||
| 97 | static const bool IsVolumeName(const wchar_t *s) | ||
| 98 | { | ||
| 99 | return IsString1PrefixedByString2(s, k_VolumePrefix); | ||
| 100 | } | ||
| 101 | */ | ||
| 102 | |||
| 103 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 104 | |||
| 105 | #define Set16(p, v) SetUi16(p, v) | ||
| 106 | #define Set32(p, v) SetUi32(p, v) | ||
| 107 | |||
| 108 | static void WriteString(Byte *dest, const wchar_t *path) | ||
| 109 | { | ||
| 110 | for (;;) | ||
| 111 | { | ||
| 112 | wchar_t c = *path++; | ||
| 113 | if (c == 0) | ||
| 114 | return; | ||
| 115 | Set16(dest, (UInt16)c); | ||
| 116 | dest += 2; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) | ||
| 121 | { | ||
| 122 | bool isAbs = IsAbsolutePath(path); | ||
| 123 | if (!isAbs && !isSymLink) | ||
| 124 | return false; | ||
| 125 | |||
| 126 | if (isWSL) | ||
| 127 | { | ||
| 128 | // unsupported characters probably use Replacement Character UTF-16 0xFFFD | ||
| 129 | AString utf; | ||
| 130 | ConvertUnicodeToUTF8(path, utf); | ||
| 131 | const size_t size = 4 + utf.Len(); | ||
| 132 | if (size != (UInt16)size) | ||
| 133 | return false; | ||
| 134 | dest.Alloc(8 + size); | ||
| 135 | Byte *p = dest; | ||
| 136 | Set32(p, _my_IO_REPARSE_TAG_LX_SYMLINK); | ||
| 137 | Set16(p + 4, (UInt16)(size)); | ||
| 138 | Set16(p + 6, 0); | ||
| 139 | Set32(p + 8, _my_LX_SYMLINK_FLAG); | ||
| 140 | memcpy(p + 12, utf.Ptr(), utf.Len()); | ||
| 141 | return true; | ||
| 142 | } | ||
| 143 | |||
| 144 | // usual symbolic LINK (NOT WSL) | ||
| 145 | |||
| 146 | bool needPrintName = true; | ||
| 147 | |||
| 148 | if (IsSuperPath(path)) | ||
| 149 | { | ||
| 150 | path += kSuperPathPrefixSize; | ||
| 151 | if (!IsDrivePath(path)) | ||
| 152 | needPrintName = false; | ||
| 153 | } | ||
| 154 | |||
| 155 | const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; | ||
| 156 | |||
| 157 | size_t len2 = (size_t)MyStringLen(path) * 2; | ||
| 158 | const size_t len1 = len2 + add_Prefix_Len * 2; | ||
| 159 | if (!needPrintName) | ||
| 160 | len2 = 0; | ||
| 161 | |||
| 162 | size_t totalNamesSize = (len1 + len2); | ||
| 163 | |||
| 164 | /* some WIM imagex software uses old scheme for symbolic links. | ||
| 165 | so we can old scheme for byte to byte compatibility */ | ||
| 166 | |||
| 167 | bool newOrderScheme = isSymLink; | ||
| 168 | // newOrderScheme = false; | ||
| 169 | |||
| 170 | if (!newOrderScheme) | ||
| 171 | totalNamesSize += 2 * 2; | ||
| 172 | |||
| 173 | const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; | ||
| 174 | if (size != (UInt16)size) | ||
| 175 | return false; | ||
| 176 | dest.Alloc(size); | ||
| 177 | memset(dest, 0, size); | ||
| 178 | const UInt32 tag = isSymLink ? | ||
| 179 | _my_IO_REPARSE_TAG_SYMLINK : | ||
| 180 | _my_IO_REPARSE_TAG_MOUNT_POINT; | ||
| 181 | Byte *p = dest; | ||
| 182 | Set32(p, tag); | ||
| 183 | Set16(p + 4, (UInt16)(size - 8)); | ||
| 184 | Set16(p + 6, 0); | ||
| 185 | p += 8; | ||
| 186 | |||
| 187 | unsigned subOffs = 0; | ||
| 188 | unsigned printOffs = 0; | ||
| 189 | if (newOrderScheme) | ||
| 190 | subOffs = (unsigned)len2; | ||
| 191 | else | ||
| 192 | printOffs = (unsigned)len1 + 2; | ||
| 193 | |||
| 194 | Set16(p + 0, (UInt16)subOffs); | ||
| 195 | Set16(p + 2, (UInt16)len1); | ||
| 196 | Set16(p + 4, (UInt16)printOffs); | ||
| 197 | Set16(p + 6, (UInt16)len2); | ||
| 198 | |||
| 199 | p += 8; | ||
| 200 | if (isSymLink) | ||
| 201 | { | ||
| 202 | UInt32 flags = isAbs ? 0 : _my_SYMLINK_FLAG_RELATIVE; | ||
| 203 | Set32(p, flags); | ||
| 204 | p += 4; | ||
| 205 | } | ||
| 206 | |||
| 207 | if (add_Prefix_Len != 0) | ||
| 208 | WriteString(p + subOffs, k_LinkPrefix); | ||
| 209 | WriteString(p + subOffs + add_Prefix_Len * 2, path); | ||
| 210 | if (needPrintName) | ||
| 211 | WriteString(p + printOffs, path); | ||
| 212 | return true; | ||
| 213 | } | ||
| 214 | |||
| 215 | #endif // defined(_WIN32) && !defined(UNDER_CE) | ||
| 216 | |||
| 217 | |||
| 218 | static void GetString(const Byte *p, unsigned len, UString &res) | ||
| 219 | { | ||
| 220 | wchar_t *s = res.GetBuf(len); | ||
| 221 | unsigned i; | ||
| 222 | for (i = 0; i < len; i++) | ||
| 223 | { | ||
| 224 | wchar_t c = Get16(p + i * 2); | ||
| 225 | if (c == 0) | ||
| 226 | break; | ||
| 227 | s[i] = c; | ||
| 228 | } | ||
| 229 | s[i] = 0; | ||
| 230 | res.ReleaseBuf_SetLen(i); | ||
| 231 | } | ||
| 232 | |||
| 233 | bool CReparseAttr::Parse(const Byte *p, size_t size) | ||
| 234 | { | ||
| 235 | ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; | ||
| 236 | HeaderError = true; | ||
| 237 | TagIsUnknown = true; | ||
| 238 | MinorError = false; | ||
| 239 | |||
| 240 | if (size < 8) | ||
| 241 | return false; | ||
| 242 | Tag = Get32(p); | ||
| 243 | UInt32 len = Get16(p + 4); | ||
| 244 | if (len + 8 != size) | ||
| 245 | // if (len + 8 > size) | ||
| 246 | return false; | ||
| 247 | /* | ||
| 248 | if ((type & kReparseFlags_Alias) == 0 || | ||
| 249 | (type & kReparseFlags_Microsoft) == 0 || | ||
| 250 | (type & 0xFFFF) != 3) | ||
| 251 | */ | ||
| 252 | |||
| 253 | if (Get16(p + 6) != 0) // padding | ||
| 254 | return false; | ||
| 255 | |||
| 256 | HeaderError = false; | ||
| 257 | |||
| 258 | if ( Tag != _my_IO_REPARSE_TAG_MOUNT_POINT | ||
| 259 | && Tag != _my_IO_REPARSE_TAG_SYMLINK | ||
| 260 | && Tag != _my_IO_REPARSE_TAG_LX_SYMLINK) | ||
| 261 | { | ||
| 262 | // for unsupported reparse points | ||
| 263 | ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH | ||
| 264 | // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID | ||
| 265 | return false; | ||
| 266 | } | ||
| 267 | |||
| 268 | TagIsUnknown = false; | ||
| 269 | |||
| 270 | p += 8; | ||
| 271 | size -= 8; | ||
| 272 | |||
| 273 | if (Tag == _my_IO_REPARSE_TAG_LX_SYMLINK) | ||
| 274 | { | ||
| 275 | if (len < 4) | ||
| 276 | return false; | ||
| 277 | Flags = Get32(p); // maybe it's not Flags | ||
| 278 | if (Flags != _my_LX_SYMLINK_FLAG) | ||
| 279 | return false; | ||
| 280 | len -= 4; | ||
| 281 | p += 4; | ||
| 282 | char *s = WslName.GetBuf(len); | ||
| 283 | unsigned i; | ||
| 284 | for (i = 0; i < len; i++) | ||
| 285 | { | ||
| 286 | char c = (char)p[i]; | ||
| 287 | s[i] = c; | ||
| 288 | if (c == 0) | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | WslName.ReleaseBuf_SetEnd(i); | ||
| 292 | MinorError = (i != len); | ||
| 293 | ErrorCode = 0; | ||
| 294 | return true; | ||
| 295 | } | ||
| 296 | |||
| 297 | if (len < 8) | ||
| 298 | return false; | ||
| 299 | unsigned subOffs = Get16(p); | ||
| 300 | unsigned subLen = Get16(p + 2); | ||
| 301 | unsigned printOffs = Get16(p + 4); | ||
| 302 | unsigned printLen = Get16(p + 6); | ||
| 303 | len -= 8; | ||
| 304 | p += 8; | ||
| 305 | |||
| 306 | Flags = 0; | ||
| 307 | if (Tag == _my_IO_REPARSE_TAG_SYMLINK) | ||
| 308 | { | ||
| 309 | if (len < 4) | ||
| 310 | return false; | ||
| 311 | Flags = Get32(p); | ||
| 312 | len -= 4; | ||
| 313 | p += 4; | ||
| 314 | } | ||
| 315 | |||
| 316 | if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) | ||
| 317 | return false; | ||
| 318 | if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) | ||
| 319 | return false; | ||
| 320 | GetString(p + subOffs, subLen >> 1, SubsName); | ||
| 321 | GetString(p + printOffs, printLen >> 1, PrintName); | ||
| 322 | |||
| 323 | ErrorCode = 0; | ||
| 324 | return true; | ||
| 325 | } | ||
| 326 | |||
| 327 | |||
| 328 | bool CReparseShortInfo::Parse(const Byte *p, size_t size) | ||
| 329 | { | ||
| 330 | const Byte *start = p; | ||
| 331 | Offset= 0; | ||
| 332 | Size = 0; | ||
| 333 | if (size < 8) | ||
| 334 | return false; | ||
| 335 | UInt32 Tag = Get32(p); | ||
| 336 | UInt32 len = Get16(p + 4); | ||
| 337 | if (len + 8 > size) | ||
| 338 | return false; | ||
| 339 | /* | ||
| 340 | if ((type & kReparseFlags_Alias) == 0 || | ||
| 341 | (type & kReparseFlags_Microsoft) == 0 || | ||
| 342 | (type & 0xFFFF) != 3) | ||
| 343 | */ | ||
| 344 | if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && | ||
| 345 | Tag != _my_IO_REPARSE_TAG_SYMLINK) | ||
| 346 | // return true; | ||
| 347 | return false; | ||
| 348 | |||
| 349 | if (Get16(p + 6) != 0) // padding | ||
| 350 | return false; | ||
| 351 | |||
| 352 | p += 8; | ||
| 353 | size -= 8; | ||
| 354 | |||
| 355 | if (len != size) // do we need that check? | ||
| 356 | return false; | ||
| 357 | |||
| 358 | if (len < 8) | ||
| 359 | return false; | ||
| 360 | unsigned subOffs = Get16(p); | ||
| 361 | unsigned subLen = Get16(p + 2); | ||
| 362 | unsigned printOffs = Get16(p + 4); | ||
| 363 | unsigned printLen = Get16(p + 6); | ||
| 364 | len -= 8; | ||
| 365 | p += 8; | ||
| 366 | |||
| 367 | // UInt32 Flags = 0; | ||
| 368 | if (Tag == _my_IO_REPARSE_TAG_SYMLINK) | ||
| 369 | { | ||
| 370 | if (len < 4) | ||
| 371 | return false; | ||
| 372 | // Flags = Get32(p); | ||
| 373 | len -= 4; | ||
| 374 | p += 4; | ||
| 375 | } | ||
| 376 | |||
| 377 | if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen) | ||
| 378 | return false; | ||
| 379 | if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen) | ||
| 380 | return false; | ||
| 381 | |||
| 382 | Offset = (unsigned)(p - start) + subOffs; | ||
| 383 | Size = subLen; | ||
| 384 | return true; | ||
| 385 | } | ||
| 386 | |||
| 387 | bool CReparseAttr::IsOkNamePair() const | ||
| 388 | { | ||
| 389 | if (IsLinkPrefix(SubsName)) | ||
| 390 | { | ||
| 391 | if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size))) | ||
| 392 | return PrintName.IsEmpty(); | ||
| 393 | if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0) | ||
| 394 | return true; | ||
| 395 | } | ||
| 396 | return wcscmp(SubsName, PrintName) == 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* | ||
| 400 | bool CReparseAttr::IsVolume() const | ||
| 401 | { | ||
| 402 | if (!IsLinkPrefix(SubsName)) | ||
| 403 | return false; | ||
| 404 | return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size)); | ||
| 405 | } | ||
| 406 | */ | ||
| 407 | |||
| 408 | UString CReparseAttr::GetPath() const | ||
| 409 | { | ||
| 410 | if (IsSymLink_WSL()) | ||
| 411 | { | ||
| 412 | UString u; | ||
| 413 | // if (CheckUTF8(attr.WslName) | ||
| 414 | if (!ConvertUTF8ToUnicode(WslName, u)) | ||
| 415 | MultiByteToUnicodeString2(u, WslName); | ||
| 416 | return u; | ||
| 417 | } | ||
| 418 | |||
| 419 | UString s (SubsName); | ||
| 420 | if (IsLinkPrefix(s)) | ||
| 421 | { | ||
| 422 | s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" | ||
| 423 | if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) | ||
| 424 | s.DeleteFrontal(k_LinkPrefix_Size); | ||
| 425 | } | ||
| 426 | return s; | ||
| 427 | } | ||
| 428 | |||
| 429 | #ifdef SUPPORT_DEVICE_FILE | ||
| 430 | |||
| 431 | namespace NSystem | ||
| 432 | { | ||
| 433 | bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); | ||
| 434 | } | ||
| 435 | #endif // SUPPORT_DEVICE_FILE | ||
| 436 | |||
| 437 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
| 438 | |||
| 439 | namespace NIO { | ||
| 440 | |||
| 441 | bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo) | ||
| 442 | { | ||
| 443 | reparseData.Free(); | ||
| 444 | CInFile file; | ||
| 445 | if (!file.OpenReparse(path)) | ||
| 446 | return false; | ||
| 447 | |||
| 448 | if (fileInfo) | ||
| 449 | file.GetFileInformation(fileInfo); | ||
| 450 | |||
| 451 | const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; | ||
| 452 | CByteArr buf(kBufSize); | ||
| 453 | DWORD returnedSize; | ||
| 454 | if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize)) | ||
| 455 | return false; | ||
| 456 | reparseData.CopyFrom(buf, returnedSize); | ||
| 457 | return true; | ||
| 458 | } | ||
| 459 | |||
| 460 | static bool CreatePrefixDirOfFile(CFSTR path) | ||
| 461 | { | ||
| 462 | FString path2 (path); | ||
| 463 | int pos = path2.ReverseFind_PathSepar(); | ||
| 464 | if (pos < 0) | ||
| 465 | return true; | ||
| 466 | #ifdef _WIN32 | ||
| 467 | if (pos == 2 && path2[1] == L':') | ||
| 468 | return true; // we don't create Disk folder; | ||
| 469 | #endif | ||
| 470 | path2.DeleteFrom((unsigned)pos); | ||
| 471 | return NDir::CreateComplexDir(path2); | ||
| 472 | } | ||
| 473 | |||
| 474 | |||
| 475 | static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size) | ||
| 476 | { | ||
| 477 | COutFile file; | ||
| 478 | if (!file.Open(path, | ||
| 479 | FILE_SHARE_WRITE, | ||
| 480 | OPEN_EXISTING, | ||
| 481 | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) | ||
| 482 | return false; | ||
| 483 | |||
| 484 | DWORD returnedSize; | ||
| 485 | return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize); | ||
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | // If there is Reparse data already, it still writes new Reparse data | ||
| 490 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) | ||
| 491 | { | ||
| 492 | NFile::NFind::CFileInfo fi; | ||
| 493 | if (fi.Find(path)) | ||
| 494 | { | ||
| 495 | if (fi.IsDir() != isDir) | ||
| 496 | { | ||
| 497 | ::SetLastError(ERROR_DIRECTORY); | ||
| 498 | return false; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | else | ||
| 502 | { | ||
| 503 | if (isDir) | ||
| 504 | { | ||
| 505 | if (!NDir::CreateComplexDir(path)) | ||
| 506 | return false; | ||
| 507 | } | ||
| 508 | else | ||
| 509 | { | ||
| 510 | CreatePrefixDirOfFile(path); | ||
| 511 | COutFile file; | ||
| 512 | if (!file.Create(path, CREATE_NEW)) | ||
| 513 | return false; | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size); | ||
| 518 | } | ||
| 519 | |||
| 520 | |||
| 521 | bool DeleteReparseData(CFSTR path) | ||
| 522 | { | ||
| 523 | CByteBuffer reparseData; | ||
| 524 | if (!GetReparseData(path, reparseData, NULL)) | ||
| 525 | return false; | ||
| 526 | /* MSDN: The tag specified in the ReparseTag member of this structure | ||
| 527 | must match the tag of the reparse point to be deleted, | ||
| 528 | and the ReparseDataLength member must be zero */ | ||
| 529 | #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8 | ||
| 530 | if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE) | ||
| 531 | { | ||
| 532 | SetLastError(ERROR_INVALID_REPARSE_DATA); | ||
| 533 | return false; | ||
| 534 | } | ||
| 535 | BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; | ||
| 536 | memset(buf, 0, sizeof(buf)); | ||
| 537 | memcpy(buf, reparseData, 4); // tag | ||
| 538 | return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); | ||
| 539 | } | ||
| 540 | |||
| 541 | } | ||
| 542 | |||
| 543 | #endif // defined(_WIN32) && !defined(UNDER_CE) | ||
| 544 | |||
| 545 | |||
| 546 | #ifndef _WIN32 | ||
| 547 | |||
| 548 | namespace NIO { | ||
| 549 | |||
| 550 | bool GetReparseData(CFSTR path, CByteBuffer &reparseData) | ||
| 551 | { | ||
| 552 | reparseData.Free(); | ||
| 553 | |||
| 554 | #define MAX_PATHNAME_LEN 1024 | ||
| 555 | char buf[MAX_PATHNAME_LEN + 2]; | ||
| 556 | const size_t request = sizeof(buf) - 1; | ||
| 557 | |||
| 558 | // printf("\nreadlink() path = %s \n", path); | ||
| 559 | const ssize_t size = readlink(path, buf, request); | ||
| 560 | // there is no tail zero | ||
| 561 | |||
| 562 | if (size < 0) | ||
| 563 | return false; | ||
| 564 | if ((size_t)size >= request) | ||
| 565 | { | ||
| 566 | SetLastError(EINVAL); // check it: ENAMETOOLONG | ||
| 567 | return false; | ||
| 568 | } | ||
| 569 | |||
| 570 | // printf("\nreadlink() res = %s size = %d \n", buf, (int)size); | ||
| 571 | reparseData.CopyFrom((const Byte *)buf, (size_t)size); | ||
| 572 | return true; | ||
| 573 | } | ||
| 574 | |||
| 575 | |||
| 576 | /* | ||
| 577 | // If there is Reparse data already, it still writes new Reparse data | ||
| 578 | bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) | ||
| 579 | { | ||
| 580 | // AString s; | ||
| 581 | // s.SetFrom_CalcLen(data, size); | ||
| 582 | // return (symlink(s, path) == 0); | ||
| 583 | UNUSED_VAR(path) | ||
| 584 | UNUSED_VAR(isDir) | ||
| 585 | UNUSED_VAR(data) | ||
| 586 | UNUSED_VAR(size) | ||
| 587 | SetLastError(ENOSYS); | ||
| 588 | return false; | ||
| 589 | } | ||
| 590 | */ | ||
| 591 | |||
| 592 | bool SetSymLink(CFSTR from, CFSTR to) | ||
| 593 | { | ||
| 594 | // printf("\nsymlink() %s -> %s\n", from, to); | ||
| 595 | int ir; | ||
| 596 | // ir = unlink(path); | ||
| 597 | // if (ir == 0) | ||
| 598 | ir = symlink(to, from); | ||
| 599 | return (ir == 0); | ||
| 600 | } | ||
| 601 | |||
| 602 | bool SetSymLink_UString(CFSTR from, const UString &to) | ||
| 603 | { | ||
| 604 | AString utf; | ||
| 605 | ConvertUnicodeToUTF8(to, utf); | ||
| 606 | return SetSymLink(from, utf); | ||
| 607 | } | ||
| 608 | |||
| 609 | } | ||
| 610 | |||
| 611 | #endif // !_WIN32 | ||
| 612 | |||
| 613 | }} | ||
