1// Windows/FileName.cpp 2 3#include "StdAfx.h" 4 5#ifndef _WIN32 6#include <limits.h> 7#include <unistd.h> 8#include "../Common/StringConvert.h" 9#endif 10 11#include "FileDir.h" 12#include "FileName.h" 13 14#ifndef _UNICODE 15extern bool g_IsNT; 16#endif 17 18namespace NWindows { 19namespace NFile { 20namespace NName { 21 22#define IS_SEPAR(c) IS_PATH_SEPAR(c) 23 24int FindSepar(const wchar_t *s) throw() 25{ 26 for (const wchar_t *p = s;; p++) 27 { 28 const wchar_t c = *p; 29 if (c == 0) 30 return -1; 31 if (IS_SEPAR(c)) 32 return (int)(p - s); 33 } 34} 35 36#ifndef USE_UNICODE_FSTRING 37int FindSepar(const FChar *s) throw() 38{ 39 for (const FChar *p = s;; p++) 40 { 41 const FChar c = *p; 42 if (c == 0) 43 return -1; 44 if (IS_SEPAR(c)) 45 return (int)(p - s); 46 } 47} 48#endif 49 50#ifndef USE_UNICODE_FSTRING 51void NormalizeDirPathPrefix(FString &dirPath) 52{ 53 if (dirPath.IsEmpty()) 54 return; 55 if (!IsPathSepar(dirPath.Back())) 56 dirPath.Add_PathSepar(); 57} 58#endif 59 60void NormalizeDirPathPrefix(UString &dirPath) 61{ 62 if (dirPath.IsEmpty()) 63 return; 64 if (!IsPathSepar(dirPath.Back())) 65 dirPath.Add_PathSepar(); 66} 67 68#ifdef _WIN32 69 70#ifndef USE_UNICODE_FSTRING 71#ifdef Z7_LONG_PATH 72static void NormalizeDirSeparators(UString &s) 73{ 74 const unsigned len = s.Len(); 75 for (unsigned i = 0; i < len; i++) 76 if (s[i] == '/') 77 s.ReplaceOneCharAtPos(i, WCHAR_PATH_SEPARATOR); 78} 79#endif 80#endif 81 82void NormalizeDirSeparators(FString &s) 83{ 84 const unsigned len = s.Len(); 85 for (unsigned i = 0; i < len; i++) 86 if (s[i] == '/') 87 s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); 88} 89 90#endif 91 92 93#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a'))) 94 95bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } 96 97bool IsAltPathPrefix(CFSTR s) throw() 98{ 99 unsigned len = MyStringLen(s); 100 if (len == 0) 101 return false; 102 if (s[len - 1] != ':') 103 return false; 104 105 #if defined(_WIN32) && !defined(UNDER_CE) 106 if (IsDevicePath(s)) 107 return false; 108 if (IsSuperPath(s)) 109 { 110 s += kSuperPathPrefixSize; 111 len -= kSuperPathPrefixSize; 112 } 113 if (len == 2 && IsDrivePath2(s)) 114 return false; 115 #endif 116 117 return true; 118} 119 120#if defined(_WIN32) && !defined(UNDER_CE) 121 122const char * const kSuperPathPrefix = "\\\\?\\"; 123#ifdef Z7_LONG_PATH 124static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; 125#endif 126 127#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])) 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 131#define IS_UNC_WITH_SLASH(s) ( \ 132 ((s)[0] == 'U' || (s)[0] == 'u') \ 133 && ((s)[1] == 'N' || (s)[1] == 'n') \ 134 && ((s)[2] == 'C' || (s)[2] == 'c') \ 135 && IS_SEPAR((s)[3])) 136 137bool IsDevicePath(CFSTR s) throw() 138{ 139 #ifdef UNDER_CE 140 141 s = s; 142 return false; 143 /* 144 // actually we don't know the way to open device file in WinCE. 145 unsigned len = MyStringLen(s); 146 if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK")) 147 return false; 148 if (s[4] != ':') 149 return false; 150 // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ)); 151 */ 152 153 #else 154 155 if (!IS_DEVICE_PATH(s)) 156 return false; 157 unsigned len = MyStringLen(s); 158 if (len == 6 && s[5] == ':') 159 return true; 160 if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive")) 161 return false; 162 for (unsigned i = 17; i < len; i++) 163 if (s[i] < '0' || s[i] > '9') 164 return false; 165 return true; 166 167 #endif 168} 169 170bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } 171bool IsNetworkPath(CFSTR s) throw() 172{ 173 if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) 174 return false; 175 if (IsSuperUncPath(s)) 176 return true; 177 FChar c = s[2]; 178 return (c != '.' && c != '?'); 179} 180 181unsigned GetNetworkServerPrefixSize(CFSTR s) throw() 182{ 183 if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1])) 184 return 0; 185 unsigned prefixSize = 2; 186 if (IsSuperUncPath(s)) 187 prefixSize = kSuperUncPathPrefixSize; 188 else 189 { 190 FChar c = s[2]; 191 if (c == '.' || c == '?') 192 return 0; 193 } 194 const int pos = FindSepar(s + prefixSize); 195 if (pos < 0) 196 return 0; 197 return prefixSize + (unsigned)(pos + 1); 198} 199 200bool IsNetworkShareRootPath(CFSTR s) throw() 201{ 202 const unsigned prefixSize = GetNetworkServerPrefixSize(s); 203 if (prefixSize == 0) 204 return false; 205 s += prefixSize; 206 const int pos = FindSepar(s); 207 if (pos < 0) 208 return true; 209 return s[(unsigned)pos + 1] == 0; 210} 211 212static const unsigned kDrivePrefixSize = 3; /* c:\ */ 213 214bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } 215// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } 216bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); } 217bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } 218// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); } 219 220bool IsAltStreamPrefixWithColon(const UString &s) throw() 221{ 222 if (s.IsEmpty()) 223 return false; 224 if (s.Back() != ':') 225 return false; 226 unsigned pos = 0; 227 if (IsSuperPath(s)) 228 pos = kSuperPathPrefixSize; 229 if (s.Len() - pos == 2 && IsDrivePath2(s.Ptr(pos))) 230 return false; 231 return true; 232} 233 234bool If_IsSuperPath_RemoveSuperPrefix(UString &s) 235{ 236 if (!IsSuperPath(s)) 237 return false; 238 unsigned start = 0; 239 unsigned count = kSuperPathPrefixSize; 240 const wchar_t *s2 = s.Ptr(kSuperPathPrefixSize); 241 if (IS_UNC_WITH_SLASH(s2)) 242 { 243 start = 2; 244 count = kSuperUncPathPrefixSize - 2; 245 } 246 s.Delete(start, count); 247 return true; 248} 249 250 251#ifndef USE_UNICODE_FSTRING 252bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; } 253// bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; } 254bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } 255bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); } 256bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); } 257#endif // USE_UNICODE_FSTRING 258 259bool IsDrivePath_SuperAllowed(CFSTR s) throw() 260{ 261 if (IsSuperPath(s)) 262 s += kSuperPathPrefixSize; 263 return IsDrivePath(s); 264} 265 266bool IsDriveRootPath_SuperAllowed(CFSTR s) throw() 267{ 268 if (IsSuperPath(s)) 269 s += kSuperPathPrefixSize; 270 return IsDrivePath(s) && s[kDrivePrefixSize] == 0; 271} 272 273bool IsAbsolutePath(const wchar_t *s) throw() 274{ 275 return IS_SEPAR(s[0]) || IsDrivePath2(s); 276} 277 278int FindAltStreamColon(CFSTR path) throw() 279{ 280 unsigned i = 0; 281 if (IsDrivePath2(path)) 282 i = 2; 283 int colonPos = -1; 284 for (;; i++) 285 { 286 FChar c = path[i]; 287 if (c == 0) 288 return colonPos; 289 if (c == ':') 290 { 291 if (colonPos < 0) 292 colonPos = (int)i; 293 continue; 294 } 295 if (IS_SEPAR(c)) 296 colonPos = -1; 297 } 298} 299 300#ifndef USE_UNICODE_FSTRING 301 302static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s) 303{ 304 // Network path: we look "server\path\" as root prefix 305 int pos = FindSepar(s); 306 if (pos < 0) 307 return 0; 308 int pos2 = FindSepar(s + (unsigned)pos + 1); 309 if (pos2 < 0) 310 return 0; 311 return pos + pos2 + 2; 312} 313 314static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s) 315{ 316 if (IsDrivePath(s)) 317 return kDrivePrefixSize; 318 if (!IS_SEPAR(s[0])) 319 return 0; 320 if (s[1] == 0 || !IS_SEPAR(s[1])) 321 return 1; 322 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 323 return (size == 0) ? 0 : 2 + size; 324} 325 326static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s) 327{ 328 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 329 { 330 const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 331 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 332 } 333 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 334 const int pos = FindSepar(s + kSuperPathPrefixSize); 335 if (pos < 0) 336 return 0; 337 return kSuperPathPrefixSize + pos + 1; 338} 339 340unsigned GetRootPrefixSize(CFSTR s) throw() 341{ 342 if (IS_DEVICE_PATH(s)) 343 return kDevicePathPrefixSize; 344 if (IsSuperPath(s)) 345 return GetRootPrefixSize_Of_SuperPath(s); 346 return GetRootPrefixSize_Of_SimplePath(s); 347} 348 349#endif // USE_UNICODE_FSTRING 350 351static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() 352{ 353 // Network path: we look "server\path\" as root prefix 354 int pos = FindSepar(s); 355 if (pos < 0) 356 return 0; 357 int pos2 = FindSepar(s + (unsigned)pos + 1); 358 if (pos2 < 0) 359 return 0; 360 return (unsigned)(pos + pos2 + 2); 361} 362 363static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() 364{ 365 if (IsDrivePath(s)) 366 return kDrivePrefixSize; 367 if (!IS_SEPAR(s[0])) 368 return 0; 369 if (s[1] == 0 || !IS_SEPAR(s[1])) 370 return 1; 371 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2); 372 return (size == 0) ? 0 : 2 + size; 373} 374 375static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() 376{ 377 if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)) 378 { 379 unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize); 380 return (size == 0) ? 0 : kSuperUncPathPrefixSize + size; 381 } 382 // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\" 383 int pos = FindSepar(s + kSuperPathPrefixSize); 384 if (pos < 0) 385 return 0; 386 return kSuperPathPrefixSize + (unsigned)(pos + 1); 387} 388 389unsigned GetRootPrefixSize(const wchar_t *s) throw() 390{ 391 if (IS_DEVICE_PATH(s)) 392 return kDevicePathPrefixSize; 393 if (IsSuperPath(s)) 394 return GetRootPrefixSize_Of_SuperPath(s); 395 return GetRootPrefixSize_Of_SimplePath(s); 396} 397 398#else // _WIN32 399 400bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } 401 402#ifndef USE_UNICODE_FSTRING 403unsigned GetRootPrefixSize(CFSTR s) throw(); 404unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } 405#endif 406unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } 407 408#endif // _WIN32 409 410 411#ifndef UNDER_CE 412 413 414#ifdef USE_UNICODE_FSTRING 415 416#define GetCurDir NDir::GetCurrentDir 417 418#else 419 420static bool GetCurDir(UString &path) 421{ 422 path.Empty(); 423 FString s; 424 if (!NDir::GetCurrentDir(s)) 425 return false; 426 path = fs2us(s); 427 return true; 428} 429 430#endif 431 432 433static bool ResolveDotsFolders(UString &s) 434{ 435 #ifdef _WIN32 436 // s.Replace(L'/', WCHAR_PATH_SEPARATOR); 437 #endif 438 439 for (unsigned i = 0;;) 440 { 441 const wchar_t c = s[i]; 442 if (c == 0) 443 return true; 444 if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) 445 { 446 const wchar_t c1 = s[i + 1]; 447 if (c1 == '.') 448 { 449 const wchar_t c2 = s[i + 2]; 450 if (IS_SEPAR(c2) || c2 == 0) 451 { 452 if (i == 0) 453 return false; 454 int k = (int)i - 2; 455 i += 2; 456 457 for (;; k--) 458 { 459 if (k < 0) 460 return false; 461 if (!IS_SEPAR(s[(unsigned)k])) 462 break; 463 } 464 465 do 466 k--; 467 while (k >= 0 && !IS_SEPAR(s[(unsigned)k])); 468 469 unsigned num; 470 471 if (k >= 0) 472 { 473 num = i - (unsigned)k; 474 i = (unsigned)k; 475 } 476 else 477 { 478 num = (c2 == 0 ? i : (i + 1)); 479 i = 0; 480 } 481 482 s.Delete(i, num); 483 continue; 484 } 485 } 486 else if (IS_SEPAR(c1) || c1 == 0) 487 { 488 unsigned num = 2; 489 if (i != 0) 490 i--; 491 else if (c1 == 0) 492 num = 1; 493 s.Delete(i, num); 494 continue; 495 } 496 } 497 498 i++; 499 } 500} 501 502#endif // UNDER_CE 503 504#define LONG_PATH_DOTS_FOLDERS_PARSING 505 506 507/* 508Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\ 509To solve that problem we check such path: 510 - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper 511 - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain 512*/ 513#ifdef LONG_PATH_DOTS_FOLDERS_PARSING 514#ifndef UNDER_CE 515static bool AreThereDotsFolders(CFSTR s) 516{ 517 for (unsigned i = 0;; i++) 518 { 519 FChar c = s[i]; 520 if (c == 0) 521 return false; 522 if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1]))) 523 { 524 FChar c1 = s[i + 1]; 525 if (c1 == 0 || IS_SEPAR(c1) || 526 (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2])))) 527 return true; 528 } 529 } 530} 531#endif 532#endif // LONG_PATH_DOTS_FOLDERS_PARSING 533 534#ifdef Z7_LONG_PATH 535 536/* 537Most of Windows versions have problems, if some file or dir name 538contains '.' or ' ' at the end of name (Bad Path). 539To solve that problem, we always use Super Path ("\\?\" prefix and full path) 540in such cases. Note that "." and ".." are not bad names. 541 542There are 3 cases: 543 1) If the path is already Super Path, we use that path 544 2) If the path is not Super Path : 545 2.1) Bad Path; we use only Super Path. 546 2.2) Good Path; we use Main Path. If it fails, we use Super Path. 547 548 NeedToUseOriginalPath returns: 549 kSuperPathType_UseOnlyMain : Super already 550 kSuperPathType_UseOnlySuper : not Super, Bad Path 551 kSuperPathType_UseMainAndSuper : not Super, Good Path 552*/ 553 554int GetUseSuperPathType(CFSTR s) throw() 555{ 556 if (IsSuperOrDevicePath(s)) 557 { 558 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 559 if ((s)[2] != '.') 560 if (AreThereDotsFolders(s + kSuperPathPrefixSize)) 561 return kSuperPathType_UseOnlySuper; 562 #endif 563 return kSuperPathType_UseOnlyMain; 564 } 565 566 for (unsigned i = 0;; i++) 567 { 568 FChar c = s[i]; 569 if (c == 0) 570 return kSuperPathType_UseMainAndSuper; 571 if (c == '.' || c == ' ') 572 { 573 FChar c2 = s[i + 1]; 574 if (c2 == 0 || IS_SEPAR(c2)) 575 { 576 // if it's "." or "..", it's not bad name. 577 if (c == '.') 578 { 579 if (i == 0 || IS_SEPAR(s[i - 1])) 580 continue; 581 if (s[i - 1] == '.') 582 { 583 if (i - 1 == 0 || IS_SEPAR(s[i - 2])) 584 continue; 585 } 586 } 587 return kSuperPathType_UseOnlySuper; 588 } 589 } 590 } 591} 592 593 594 595/* 596 returns false in two cases: 597 - if GetCurDir was used, and GetCurDir returned error. 598 - if we can't resolve ".." name. 599 if path is ".", "..", res is empty. 600 if it's Super Path already, res is empty. 601 for \**** , and if GetCurDir is not drive (c:\), res is empty 602 for absolute paths, returns true, res is Super path. 603*/ 604 605static bool GetSuperPathBase(CFSTR s, UString &res) 606{ 607 res.Empty(); 608 609 FChar c = s[0]; 610 if (c == 0) 611 return true; 612 if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0))) 613 return true; 614 615 if (IsSuperOrDevicePath(s)) 616 { 617 #ifdef LONG_PATH_DOTS_FOLDERS_PARSING 618 619 if ((s)[2] == '.') 620 return true; 621 622 // we will return true here, so we will try to use these problem paths. 623 624 if (!AreThereDotsFolders(s + kSuperPathPrefixSize)) 625 return true; 626 627 UString temp = fs2us(s); 628 const unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp); 629 if (fixedSize == 0) 630 return true; 631 632 UString rem = temp.Ptr(fixedSize); 633 if (!ResolveDotsFolders(rem)) 634 return true; 635 636 temp.DeleteFrom(fixedSize); 637 res += temp; 638 res += rem; 639 640 #endif 641 642 return true; 643 } 644 645 if (IS_SEPAR(c)) 646 { 647 if (IS_SEPAR(s[1])) 648 { 649 UString temp = fs2us(s + 2); 650 const unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp); 651 // we ignore that error to allow short network paths server\share? 652 /* 653 if (fixedSize == 0) 654 return false; 655 */ 656 UString rem = temp.Ptr(fixedSize); 657 if (!ResolveDotsFolders(rem)) 658 return false; 659 res += kSuperUncPrefix; 660 temp.DeleteFrom(fixedSize); 661 res += temp; 662 res += rem; 663 return true; 664 } 665 } 666 else 667 { 668 if (IsDrivePath2(s)) 669 { 670 UString temp = fs2us(s); 671 unsigned prefixSize = 2; 672 if (IsDrivePath(s)) 673 prefixSize = kDrivePrefixSize; 674 UString rem = temp.Ptr(prefixSize); 675 if (!ResolveDotsFolders(rem)) 676 return true; 677 res += kSuperPathPrefix; 678 temp.DeleteFrom(prefixSize); 679 res += temp; 680 res += rem; 681 return true; 682 } 683 } 684 685 UString curDir; 686 if (!GetCurDir(curDir)) 687 return false; 688 NormalizeDirPathPrefix(curDir); 689 690 unsigned fixedSizeStart = 0; 691 unsigned fixedSize = 0; 692 const char *superMarker = NULL; 693 if (IsSuperPath(curDir)) 694 { 695 fixedSize = GetRootPrefixSize_Of_SuperPath(curDir); 696 if (fixedSize == 0) 697 return false; 698 } 699 else 700 { 701 if (IsDrivePath(curDir)) 702 { 703 superMarker = kSuperPathPrefix; 704 fixedSize = kDrivePrefixSize; 705 } 706 else 707 { 708 if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1])) 709 return false; 710 fixedSizeStart = 2; 711 fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2)); 712 if (fixedSize == 0) 713 return false; 714 superMarker = kSuperUncPrefix; 715 } 716 } 717 718 UString temp; 719 if (IS_SEPAR(c)) 720 { 721 temp = fs2us(s + 1); 722 } 723 else 724 { 725 temp += &curDir[fixedSizeStart + fixedSize]; 726 temp += fs2us(s); 727 } 728 if (!ResolveDotsFolders(temp)) 729 return false; 730 if (superMarker) 731 res += superMarker; 732 res += curDir.Mid(fixedSizeStart, fixedSize); 733 res += temp; 734 return true; 735} 736 737 738/* 739 In that case if GetSuperPathBase doesn't return new path, we don't need 740 to use same path that was used as main path 741 742 GetSuperPathBase superPath.IsEmpty() onlyIfNew 743 false * * GetCurDir Error 744 true false * use Super path 745 true true true don't use any path, we already used mainPath 746 true true false use main path as Super Path, we don't try mainMath 747 That case is possible now if GetCurDir returns unknown 748 type of path (not drive and not network) 749 750 We can change that code if we want to try mainPath, if GetSuperPathBase returns error, 751 and we didn't try mainPath still. 752 If we want to work that way, we don't need to use GetSuperPathBase return code. 753*/ 754 755bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) 756{ 757 if (GetSuperPathBase(path, superPath)) 758 { 759 if (superPath.IsEmpty()) 760 { 761 // actually the only possible when onlyIfNew == true and superPath is empty 762 // is case when 763 764 if (onlyIfNew) 765 return false; 766 superPath = fs2us(path); 767 } 768 769 NormalizeDirSeparators(superPath); 770 return true; 771 } 772 return false; 773} 774 775bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) 776{ 777 if (!GetSuperPathBase(s1, d1) || 778 !GetSuperPathBase(s2, d2)) 779 return false; 780 781 NormalizeDirSeparators(d1); 782 NormalizeDirSeparators(d2); 783 784 if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) 785 return false; 786 if (d1.IsEmpty()) d1 = fs2us(s1); 787 if (d2.IsEmpty()) d2 = fs2us(s2); 788 return true; 789} 790 791 792/* 793// returns true, if we need additional use with New Super path. 794bool GetSuperPath(CFSTR path, UString &superPath) 795{ 796 if (GetSuperPathBase(path, superPath)) 797 return !superPath.IsEmpty(); 798 return false; 799} 800*/ 801#endif // Z7_LONG_PATH 802 803bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res) 804{ 805 res = s; 806 807 #ifdef UNDER_CE 808 809 if (!IS_SEPAR(s[0])) 810 { 811 if (!dirPrefix) 812 return false; 813 res = dirPrefix; 814 res += s; 815 } 816 817 #else 818 819 const unsigned prefixSize = GetRootPrefixSize(s); 820 if (prefixSize != 0) 821#ifdef _WIN32 822 if (prefixSize != 1) 823#endif 824 { 825 if (!AreThereDotsFolders(s + prefixSize)) 826 return true; 827 828 UString rem = fs2us(s + prefixSize); 829 if (!ResolveDotsFolders(rem)) 830 return true; // maybe false; 831 res.DeleteFrom(prefixSize); 832 res += us2fs(rem); 833 return true; 834 } 835 836 UString curDir; 837 if (dirPrefix && prefixSize == 0) 838 curDir = fs2us(dirPrefix); // we use (dirPrefix), only if (s) path is relative 839 else 840 { 841 if (!GetCurDir(curDir)) 842 return false; 843 } 844 NormalizeDirPathPrefix(curDir); 845 846 unsigned fixedSize = GetRootPrefixSize(curDir); 847 848 UString temp; 849#ifdef _WIN32 850 if (prefixSize != 0) 851 { 852 /* (s) is absolute path, but only (prefixSize == 1) is possible here. 853 So for full resolving we need root of current folder and 854 relative part of (s). */ 855 s += prefixSize; 856 // (s) is relative part now 857 if (fixedSize == 0) 858 { 859 // (curDir) is not absolute. 860 // That case is unexpected, but we support it too. 861 curDir.Empty(); 862 curDir.Add_PathSepar(); 863 fixedSize = 1; 864 // (curDir) now is just Separ character. 865 // So final (res) path later also will have Separ prefix. 866 } 867 } 868 else 869#endif // _WIN32 870 { 871 // (s) is relative path 872 temp = curDir.Ptr(fixedSize); 873 // (temp) is relative_part_of(curDir) 874 } 875 temp += fs2us(s); 876 if (!ResolveDotsFolders(temp)) 877 return false; 878 curDir.DeleteFrom(fixedSize); 879 // (curDir) now contains only absolute prefix part 880 res = us2fs(curDir); 881 res += us2fs(temp); 882 883 #endif // UNDER_CE 884 885 return true; 886} 887 888 889bool GetFullPath(CFSTR path, FString &fullPath) 890{ 891 return GetFullPath(NULL, path, fullPath); 892} 893 894}}} 895