aboutsummaryrefslogtreecommitdiff
path: root/CPP/7zip/UI/Common
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.cpp80
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.cpp1260
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.h328
-rw-r--r--CPP/7zip/UI/Common/Bench.cpp135
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.cpp59
-rw-r--r--CPP/7zip/UI/Common/Extract.cpp2
-rw-r--r--CPP/7zip/UI/Common/ExtractingFilePath.cpp2
-rw-r--r--CPP/7zip/UI/Common/HashCalc.cpp325
-rw-r--r--CPP/7zip/UI/Common/HashCalc.h21
-rw-r--r--CPP/7zip/UI/Common/LoadCodecs.cpp6
-rw-r--r--CPP/7zip/UI/Common/TempFiles.cpp3
-rw-r--r--CPP/7zip/UI/Common/TempFiles.h3
-rw-r--r--CPP/7zip/UI/Common/Update.cpp72
-rw-r--r--CPP/7zip/UI/Common/Update.h7
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.cpp110
-rw-r--r--CPP/7zip/UI/Common/WorkDir.cpp16
-rw-r--r--CPP/7zip/UI/Common/WorkDir.h8
-rw-r--r--CPP/7zip/UI/Common/ZipRegistry.cpp37
18 files changed, 1617 insertions, 857 deletions
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
index 556b25a..7fe18fb 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -63,17 +63,46 @@ EXTERN_C_END
63 63
64#else 64#else
65 65
66// #define MY_isatty_fileno(x) (isatty(fileno(x))) 66static bool MY_IS_TERMINAL(FILE *x)
67// #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
68static inline bool MY_IS_TERMINAL(FILE *x)
69{ 67{
70 return ( 68#ifdef _WIN32
71 #if defined(_MSC_VER) && (_MSC_VER >= 1400) 69 /*
72 _isatty(_fileno(x)) 70crt/stdio.h:
73 #else 71typedef struct _iobuf FILE;
74 isatty(fileno(x)) 72#define stdin (&_iob[0])
75 #endif 73#define stdout (&_iob[1])
76 != 0); 74#define stderr (&_iob[2])
75*/
76 // fprintf(stderr, "\nMY_IS_TERMINAL = %p", x);
77 const int fd = _fileno(x);
78 /* (fd) is 0, 1 or 2 in console program.
79 docs: If stdout or stderr is not associated with
80 an output stream (for example, in a Windows application
81 without a console window), the file descriptor returned is -2.
82 In previous versions, the file descriptor returned was -1.
83 */
84 if (fd < 0) // is not associated with an output stream application (without a console window)
85 return false;
86 // fprintf(stderr, "\n\nstderr _fileno(%p) = %d", x, fd);
87 if (!_isatty(fd))
88 return false;
89 // fprintf(stderr, "\nisatty_val = true");
90 const HANDLE h = (HANDLE)_get_osfhandle(fd);
91 /* _get_osfhandle() returns intptr_t in new SDK, or long in MSVC6.
92 Also it can return (INVALID_HANDLE_VALUE).
93 docs: _get_osfhandle also returns the special value -2 when
94 the file descriptor is not associated with a stream
95 in old msvcrt.dll: it returns (-1) for incorrect value
96 */
97 // fprintf(stderr, "\n_get_osfhandle() = %p", (void *)h);
98 if (h == NULL || h == INVALID_HANDLE_VALUE)
99 return false;
100 DWORD st;
101 // fprintf(stderr, "\nGetConsoleMode() = %u", (unsigned)GetConsoleMode(h, &st));
102 return GetConsoleMode(h, &st) != 0;
103#else
104 return isatty(fileno(x)) != 0;
105#endif
77} 106}
78 107
79#endif 108#endif
@@ -312,7 +341,7 @@ static const CSwitchForm kSwitchForms[] =
312 { "spf", SWFRM_STRING_SINGL(0) }, 341 { "spf", SWFRM_STRING_SINGL(0) },
313 342
314 { "snh", SWFRM_MINUS }, 343 { "snh", SWFRM_MINUS },
315 { "snld", SWFRM_MINUS }, 344 { "snld", SWFRM_STRING },
316 { "snl", SWFRM_MINUS }, 345 { "snl", SWFRM_MINUS },
317 { "sni", SWFRM_SIMPLE }, 346 { "sni", SWFRM_SIMPLE },
318 347
@@ -1088,7 +1117,7 @@ void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
1088 const UString &s = parser[NKey::kLargePages].PostStrings[0]; 1117 const UString &s = parser[NKey::kLargePages].PostStrings[0];
1089 if (s.IsEmpty()) 1118 if (s.IsEmpty())
1090 slp = 1; 1119 slp = 1;
1091 else if (s != L"-") 1120 else if (!s.IsEqualTo("-"))
1092 { 1121 {
1093 if (!StringToUInt32(s, slp)) 1122 if (!StringToUInt32(s, slp))
1094 throw CArcCmdLineException("Unsupported switch postfix for -slp", s); 1123 throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
@@ -1338,7 +1367,7 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1338 const UString &s = parser[NKey::kFullPathMode].PostStrings[0]; 1367 const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
1339 if (!s.IsEmpty()) 1368 if (!s.IsEmpty())
1340 { 1369 {
1341 if (s == L"2") 1370 if (s.IsEqualTo("2"))
1342 censorPathMode = NWildcard::k_FullPath; 1371 censorPathMode = NWildcard::k_FullPath;
1343 else 1372 else
1344 throw CArcCmdLineException("Unsupported -spf:", s); 1373 throw CArcCmdLineException("Unsupported -spf:", s);
@@ -1400,6 +1429,7 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1400 const bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); 1429 const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
1401 const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList; 1430 const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
1402 const bool isRename = options.Command.CommandType == NCommandType::kRename; 1431 const bool isRename = options.Command.CommandType == NCommandType::kRename;
1432 options.UpdateOptions.RenameMode = isRename;
1403 1433
1404 if ((isExtractOrList || isRename) && options.StdInMode) 1434 if ((isExtractOrList || isRename) && options.StdInMode)
1405 thereIsArchiveName = false; 1435 thereIsArchiveName = false;
@@ -1449,14 +1479,8 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1449 1479
1450 SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); 1480 SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId);
1451 SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); 1481 SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName);
1452
1453 CBoolPair symLinks_AllowDangerous;
1454 SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
1455
1456
1457 /* 1482 /*
1458 bool supportSymLink = options.SymLinks.Val; 1483 bool supportSymLink = options.SymLinks.Val;
1459
1460 if (!options.SymLinks.Def) 1484 if (!options.SymLinks.Def)
1461 { 1485 {
1462 if (isExtractOrList) 1486 if (isExtractOrList)
@@ -1464,7 +1488,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1464 else 1488 else
1465 supportSymLink = false; 1489 supportSymLink = false;
1466 } 1490 }
1467
1468 #ifdef ENV_HAVE_LSTAT 1491 #ifdef ENV_HAVE_LSTAT
1469 if (supportSymLink) 1492 if (supportSymLink)
1470 global_use_lstat = 1; 1493 global_use_lstat = 1;
@@ -1473,7 +1496,6 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1473 #endif 1496 #endif
1474 */ 1497 */
1475 1498
1476
1477 if (isExtractOrList) 1499 if (isExtractOrList)
1478 { 1500 {
1479 CExtractOptionsBase &eo = options.ExtractOptions; 1501 CExtractOptionsBase &eo = options.ExtractOptions;
@@ -1497,7 +1519,15 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1497 if (!options.SymLinks.Def) 1519 if (!options.SymLinks.Def)
1498 nt.SymLinks.Val = true; 1520 nt.SymLinks.Val = true;
1499 1521
1500 nt.SymLinks_AllowDangerous = symLinks_AllowDangerous; 1522 if (parser[NKey::kSymLinks_AllowDangerous].ThereIs)
1523 {
1524 const UString &s = parser[NKey::kSymLinks_AllowDangerous].PostStrings[0];
1525 UInt32 v = 9; // default value for "-snld" instead of default = 5 without "-snld".
1526 if (!s.IsEmpty())
1527 if (!StringToUInt32(s, v))
1528 throw CArcCmdLineException("Unsupported switch postfix -snld", s);
1529 nt.SymLinks_DangerousLevel = (unsigned)v;
1530 }
1501 1531
1502 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; 1532 nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
1503 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; 1533 nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
@@ -1516,9 +1546,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1516 const UString &s = parser[NKey::kZoneFile].PostStrings[0]; 1546 const UString &s = parser[NKey::kZoneFile].PostStrings[0];
1517 if (!s.IsEmpty()) 1547 if (!s.IsEmpty())
1518 { 1548 {
1519 if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone; 1549 if (s.IsEqualTo("0")) eo.ZoneMode = NExtract::NZoneIdMode::kNone;
1520 else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll; 1550 else if (s.IsEqualTo("1")) eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1521 else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice; 1551 else if (s.IsEqualTo("2")) eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
1522 else 1552 else
1523 throw CArcCmdLineException("Unsupported -snz:", s); 1553 throw CArcCmdLineException("Unsupported -snz:", s);
1524 } 1554 }
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
index 2d32694..6631629 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -6,12 +6,10 @@
6#undef printf 6#undef printf
7 7
8// #include <stdio.h> 8// #include <stdio.h>
9// #include "../../../../C/CpuTicks.h"
10 9
11#include "../../../../C/Alloc.h" 10#include "../../../../C/Alloc.h"
12#include "../../../../C/CpuArch.h" 11#include "../../../../C/CpuArch.h"
13 12
14
15#include "../../../Common/ComTry.h" 13#include "../../../Common/ComTry.h"
16#include "../../../Common/IntToString.h" 14#include "../../../Common/IntToString.h"
17#include "../../../Common/StringConvert.h" 15#include "../../../Common/StringConvert.h"
@@ -33,6 +31,8 @@
33#include "../../Common/FilePathAutoRename.h" 31#include "../../Common/FilePathAutoRename.h"
34#include "../../Common/StreamUtils.h" 32#include "../../Common/StreamUtils.h"
35 33
34#include "../../Archive/Common/ItemNameUtils.h"
35
36#include "../Common/ExtractingFilePath.h" 36#include "../Common/ExtractingFilePath.h"
37#include "../Common/PropIDUtils.h" 37#include "../Common/PropIDUtils.h"
38 38
@@ -54,6 +54,23 @@ static const char * const kCantSetFileLen = "Cannot set length for output file";
54#ifdef SUPPORT_LINKS 54#ifdef SUPPORT_LINKS
55static const char * const kCantCreateHardLink = "Cannot create hard link"; 55static const char * const kCantCreateHardLink = "Cannot create hard link";
56static const char * const kCantCreateSymLink = "Cannot create symbolic link"; 56static const char * const kCantCreateSymLink = "Cannot create symbolic link";
57static const char * const k_HardLink_to_SymLink_Ignored = "Hard link to symbolic link was ignored";
58static const char * const k_CantDelete_File_for_SymLink = "Cannot delete file for symbolic link creation";
59static const char * const k_CantDelete_Dir_for_SymLink = "Cannot delete directory for symbolic link creation";
60#endif
61
62static const unsigned k_LinkDataSize_LIMIT = 1 << 12;
63
64#ifdef SUPPORT_LINKS
65#if WCHAR_PATH_SEPARATOR != L'/'
66 // we convert linux slashes to windows slashes for further processing.
67 // also we convert linux backslashes to BackslashReplacement character.
68 #define REPLACE_SLASHES_from_Linux_to_Sys(s) \
69 { NArchive::NItemName::ReplaceToWinSlashes(s, true); } // useBackslashReplacement
70 // { s.Replace(L'/', WCHAR_PATH_SEPARATOR); }
71#else
72 #define REPLACE_SLASHES_from_Linux_to_Sys(s)
73#endif
57#endif 74#endif
58 75
59#ifndef Z7_SFX 76#ifndef Z7_SFX
@@ -140,21 +157,25 @@ static bool FindExt2(const char *p, const UString &name)
140} 157}
141 158
142 159
143static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); 160static const char * const k_ZoneId_StreamName_With_Colon_Prefix = ":Zone.Identifier";
144 161
145void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf) 162bool Is_ZoneId_StreamName(const wchar_t *s)
146{ 163{
147 FString fileName (fileName2); 164 return StringsAreEqualNoCase_Ascii(s, k_ZoneId_StreamName_With_Colon_Prefix + 1);
148 fileName += k_ZoneId_StreamName; 165}
149 166
167void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf)
168{
150 buf.Free(); 169 buf.Free();
170 FString path (fileName);
171 path += k_ZoneId_StreamName_With_Colon_Prefix;
151 NIO::CInFile file; 172 NIO::CInFile file;
152 if (!file.Open(fileName)) 173 if (!file.Open(path))
153 return; 174 return;
154 UInt64 fileSize; 175 UInt64 fileSize;
155 if (!file.GetLength(fileSize)) 176 if (!file.GetLength(fileSize))
156 return; 177 return;
157 if (fileSize == 0 || fileSize >= ((UInt32)1 << 16)) 178 if (fileSize == 0 || fileSize >= (1u << 15))
158 return; 179 return;
159 buf.Alloc((size_t)fileSize); 180 buf.Alloc((size_t)fileSize);
160 size_t processed; 181 size_t processed;
@@ -166,7 +187,7 @@ void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf)
166bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf) 187bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf)
167{ 188{
168 FString path (fileName); 189 FString path (fileName);
169 path += k_ZoneId_StreamName; 190 path += k_ZoneId_StreamName_With_Colon_Prefix;
170 NIO::COutFile file; 191 NIO::COutFile file;
171 if (!file.Create_ALWAYS(path)) 192 if (!file.Create_ALWAYS(path))
172 return false; 193 return false;
@@ -213,7 +234,7 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
213 if (!_arc->Ask_INode) 234 if (!_arc->Ask_INode)
214 return S_OK; 235 return S_OK;
215 236
216 IInArchive *archive = _arc->Archive; 237 IInArchive * const archive = _arc->Archive;
217 CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs; 238 CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs;
218 239
219 { 240 {
@@ -275,16 +296,13 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
275 296
276 297
277CArchiveExtractCallback::CArchiveExtractCallback(): 298CArchiveExtractCallback::CArchiveExtractCallback():
278 _arc(NULL), 299 // Write_CTime(true),
279 Write_CTime(true), 300 // Write_ATime(true),
280 Write_ATime(true), 301 // Write_MTime(true),
281 Write_MTime(true),
282 Is_elimPrefix_Mode(false), 302 Is_elimPrefix_Mode(false),
303 _arc(NULL),
283 _multiArchives(false) 304 _multiArchives(false)
284{ 305{
285 LocalProgressSpec = new CLocalProgress();
286 _localProgress = LocalProgressSpec;
287
288 #ifdef Z7_USE_SECURITY_CODE 306 #ifdef Z7_USE_SECURITY_CODE
289 _saclEnabled = InitLocalPrivileges(); 307 _saclEnabled = InitLocalPrivileges();
290 #endif 308 #endif
@@ -293,9 +311,9 @@ CArchiveExtractCallback::CArchiveExtractCallback():
293 311
294void CArchiveExtractCallback::InitBeforeNewArchive() 312void CArchiveExtractCallback::InitBeforeNewArchive()
295{ 313{
296 #if defined(_WIN32) && !defined(UNDER_CE) 314#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
297 ZoneBuf.Free(); 315 ZoneBuf.Free();
298 #endif 316#endif
299} 317}
300 318
301void CArchiveExtractCallback::Init( 319void CArchiveExtractCallback::Init(
@@ -312,37 +330,31 @@ void CArchiveExtractCallback::Init(
312 _outFileStream.Release(); 330 _outFileStream.Release();
313 _bufPtrSeqOutStream.Release(); 331 _bufPtrSeqOutStream.Release();
314 332
315 #ifdef SUPPORT_LINKS 333#ifdef SUPPORT_LINKS
316 _hardLinks.Clear(); 334 _hardLinks.Clear();
317 #endif 335 _postLinks.Clear();
336#endif
318 337
319 #ifdef SUPPORT_ALT_STREAMS 338#ifdef SUPPORT_ALT_STREAMS
320 _renamedFiles.Clear(); 339 _renamedFiles.Clear();
321 #endif 340#endif
322 341
323 _ntOptions = ntOptions; 342 _ntOptions = ntOptions;
324 _wildcardCensor = wildcardCensor; 343 _wildcardCensor = wildcardCensor;
325
326 _stdOutMode = stdOutMode; 344 _stdOutMode = stdOutMode;
327 _testMode = testMode; 345 _testMode = testMode;
328
329 // _progressTotal = 0;
330 // _progressTotal_Defined = false;
331
332 _packTotal = packSize; 346 _packTotal = packSize;
333 _progressTotal = packSize; 347 _progressTotal = packSize;
334 _progressTotal_Defined = true; 348 // _progressTotal = 0;
335 349 // _progressTotal_Defined = false;
350 // _progressTotal_Defined = true;
336 _extractCallback2 = extractCallback2; 351 _extractCallback2 = extractCallback2;
337
338 /* 352 /*
339 _compressProgress.Release(); 353 _compressProgress.Release();
340 _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); 354 _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
341
342 _callbackMessage.Release(); 355 _callbackMessage.Release();
343 _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage); 356 _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage);
344 */ 357 */
345
346 _folderArchiveExtractCallback2.Release(); 358 _folderArchiveExtractCallback2.Release();
347 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); 359 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);
348 360
@@ -390,7 +402,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 size))
390{ 402{
391 COM_TRY_BEGIN 403 COM_TRY_BEGIN
392 _progressTotal = size; 404 _progressTotal = size;
393 _progressTotal_Defined = true; 405 // _progressTotal_Defined = true;
394 if (!_multiArchives && _extractCallback2) 406 if (!_multiArchives && _extractCallback2)
395 return _extractCallback2->SetTotal(size); 407 return _extractCallback2->SetTotal(size);
396 return S_OK; 408 return S_OK;
@@ -430,7 +442,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
430 if (_multiArchives) 442 if (_multiArchives)
431 { 443 {
432 packCur = LocalProgressSpec->InSize; 444 packCur = LocalProgressSpec->InSize;
433 if (completeValue && _progressTotal_Defined) 445 if (completeValue /* && _progressTotal_Defined */)
434 packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal); 446 packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal);
435 completeValue = &packCur; 447 completeValue = &packCur;
436 } 448 }
@@ -443,12 +455,13 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
443Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) 455Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
444{ 456{
445 COM_TRY_BEGIN 457 COM_TRY_BEGIN
446 return _localProgress->SetRatioInfo(inSize, outSize); 458 return LocalProgressSpec.Interface()->SetRatioInfo(inSize, outSize);
447 COM_TRY_END 459 COM_TRY_END
448} 460}
449 461
450 462
451void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) 463void CArchiveExtractCallback::CreateComplexDirectory(
464 const UStringVector &dirPathParts, bool isFinal, FString &fullPath)
452{ 465{
453 // we use (_item.IsDir) in this function 466 // we use (_item.IsDir) in this function
454 467
@@ -480,7 +493,7 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat
480 const UString &s = dirPathParts[i]; 493 const UString &s = dirPathParts[i];
481 fullPath += us2fs(s); 494 fullPath += us2fs(s);
482 495
483 const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir); 496 const bool isFinalDir = (i == dirPathParts.Size() - 1 && isFinal && _item.IsDir);
484 497
485 if (fullPath.IsEmpty()) 498 if (fullPath.IsEmpty())
486 { 499 {
@@ -541,7 +554,7 @@ static void AddPathToMessage(UString &s, const FString &path)
541 s += fs2us(path); 554 s += fs2us(path);
542} 555}
543 556
544HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) 557HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) const
545{ 558{
546 UString s (message); 559 UString s (message);
547 AddPathToMessage(s, path); 560 AddPathToMessage(s, path);
@@ -549,7 +562,7 @@ HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FSt
549} 562}
550 563
551 564
552HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) 565HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const
553{ 566{
554 UString s (message); 567 UString s (message);
555 if (errorCode != S_OK) 568 if (errorCode != S_OK)
@@ -561,13 +574,13 @@ HRESULT CArchiveExtractCallback::SendMessageError_with_Error(HRESULT errorCode,
561 return _extractCallback2->MessageError(s); 574 return _extractCallback2->MessageError(s);
562} 575}
563 576
564HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) 577HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) const
565{ 578{
566 const HRESULT errorCode = GetLastError_noZero_HRESULT(); 579 const HRESULT errorCode = GetLastError_noZero_HRESULT();
567 return SendMessageError_with_Error(errorCode, message, path); 580 return SendMessageError_with_Error(errorCode, message, path);
568} 581}
569 582
570HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) 583HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const
571{ 584{
572 UString s (message); 585 UString s (message);
573 if (errorCode != 0) 586 if (errorCode != 0)
@@ -580,15 +593,32 @@ HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char
580 return _extractCallback2->MessageError(s); 593 return _extractCallback2->MessageError(s);
581} 594}
582 595
596HRESULT CArchiveExtractCallback::SendMessageError2_with_LastError(
597 const char *message, const FString &path1, const FString &path2) const
598{
599 const HRESULT errorCode = GetLastError_noZero_HRESULT();
600 return SendMessageError2(errorCode, message, path1, path2);
601}
602
583#ifndef Z7_SFX 603#ifndef Z7_SFX
584 604
605Z7_CLASS_IMP_COM_1(
606 CGetProp
607 , IGetProp
608)
609public:
610 UInt32 IndexInArc;
611 const CArc *Arc;
612 // UString BaseName; // relative path
613};
614
585Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value)) 615Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
586{ 616{
587 /* 617 /*
588 if (propID == kpidName) 618 if (propID == kpidBaseName)
589 { 619 {
590 COM_TRY_BEGIN 620 COM_TRY_BEGIN
591 NCOM::CPropVariant prop = Name; 621 NCOM::CPropVariant prop = BaseName;
592 prop.Detach(value); 622 prop.Detach(value);
593 return S_OK; 623 return S_OK;
594 COM_TRY_END 624 COM_TRY_END
@@ -600,38 +630,25 @@ Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
600#endif // Z7_SFX 630#endif // Z7_SFX
601 631
602 632
603#ifdef SUPPORT_LINKS
604
605static UString GetDirPrefixOf(const UString &src)
606{
607 UString s (src);
608 if (!s.IsEmpty())
609 {
610 if (IsPathSepar(s.Back()))
611 s.DeleteBack();
612 int pos = s.ReverseFind_PathSepar();
613 s.DeleteFrom((unsigned)(pos + 1));
614 }
615 return s;
616}
617
618#endif // SUPPORT_LINKS
619
620struct CLinkLevelsInfo 633struct CLinkLevelsInfo
621{ 634{
622 bool IsAbsolute; 635 bool IsAbsolute;
636 bool ParentDirDots_after_NonParent;
623 int LowLevel; 637 int LowLevel;
624 int FinalLevel; 638 int FinalLevel;
625 639
626 void Parse(const UString &path); 640 void Parse(const UString &path, bool isWSL);
627}; 641};
628 642
629void CLinkLevelsInfo::Parse(const UString &path) 643void CLinkLevelsInfo::Parse(const UString &path, bool isWSL)
630{ 644{
631 IsAbsolute = NName::IsAbsolutePath(path); 645 IsAbsolute = isWSL ?
632 646 IS_PATH_SEPAR(path[0]) :
647 NName::IsAbsolutePath(path);
633 LowLevel = 0; 648 LowLevel = 0;
634 FinalLevel = 0; 649 FinalLevel = 0;
650 ParentDirDots_after_NonParent = false;
651 bool nonParentDir = false;
635 652
636 UStringVector parts; 653 UStringVector parts;
637 SplitPathToParts(path, parts); 654 SplitPathToParts(path, parts);
@@ -646,32 +663,41 @@ void CLinkLevelsInfo::Parse(const UString &path)
646 IsAbsolute = true; 663 IsAbsolute = true;
647 continue; 664 continue;
648 } 665 }
649 if (s == L".") 666 if (s.IsEqualTo("."))
650 continue; 667 continue;
651 if (s == L"..") 668 if (s.IsEqualTo(".."))
652 { 669 {
670 if (IsAbsolute || nonParentDir)
671 ParentDirDots_after_NonParent = true;
653 level--; 672 level--;
654 if (LowLevel > level) 673 if (LowLevel > level)
655 LowLevel = level; 674 LowLevel = level;
656 } 675 }
657 else 676 else
677 {
678 nonParentDir = true;
658 level++; 679 level++;
680 }
659 } 681 }
660 682
661 FinalLevel = level; 683 FinalLevel = level;
662} 684}
663 685
664 686
665bool IsSafePath(const UString &path); 687static bool IsSafePath(const UString &path, bool isWSL)
666bool IsSafePath(const UString &path)
667{ 688{
668 CLinkLevelsInfo levelsInfo; 689 CLinkLevelsInfo levelsInfo;
669 levelsInfo.Parse(path); 690 levelsInfo.Parse(path, isWSL);
670 return !levelsInfo.IsAbsolute 691 return !levelsInfo.IsAbsolute
671 && levelsInfo.LowLevel >= 0 692 && levelsInfo.LowLevel >= 0
672 && levelsInfo.FinalLevel > 0; 693 && levelsInfo.FinalLevel > 0;
673} 694}
674 695
696bool IsSafePath(const UString &path);
697bool IsSafePath(const UString &path)
698{
699 return IsSafePath(path, false); // isWSL
700}
675 701
676bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); 702bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
677bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) 703bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)
@@ -787,159 +813,113 @@ HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)
787 813
788HRESULT CArchiveExtractCallback::ReadLink() 814HRESULT CArchiveExtractCallback::ReadLink()
789{ 815{
790 IInArchive *archive = _arc->Archive; 816 IInArchive * const archive = _arc->Archive;
791 const UInt32 index = _index; 817 const UInt32 index = _index;
792 _link.Clear(); 818 // _link.Clear(); // _link.Clear() was called already.
793
794 { 819 {
795 NCOM::CPropVariant prop; 820 NCOM::CPropVariant prop;
796 RINOK(archive->GetProperty(index, kpidHardLink, &prop)) 821 RINOK(archive->GetProperty(index, kpidHardLink, &prop))
797 if (prop.vt == VT_BSTR) 822 if (prop.vt == VT_BSTR)
798 { 823 {
799 _link.isHardLink = true; 824 _link.LinkType = k_LinkType_HardLink;
800 // _link.isCopyLink = false;
801 _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive 825 _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive
802 _link.linkPath.SetFromBstr(prop.bstrVal); 826 _link.LinkPath.SetFromBstr(prop.bstrVal);
827 // 7-Zip 24-: tar handler returned original path (with linux slash in most case)
828 // 7-Zip 24-: rar5 handler returned path with system slash.
829 // 7-Zip 25+: tar/rar5 handlers return linux path in most cases.
803 } 830 }
804 else if (prop.vt != VT_EMPTY) 831 else if (prop.vt != VT_EMPTY)
805 return E_FAIL; 832 return E_FAIL;
806 } 833 }
807
808 /* 834 /*
809 { 835 {
810 NCOM::CPropVariant prop; 836 NCOM::CPropVariant prop;
811 RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); 837 RINOK(archive->GetProperty(index, kpidCopyLink, &prop));
812 if (prop.vt == VT_BSTR) 838 if (prop.vt == VT_BSTR)
813 { 839 {
814 _link.isHardLink = false; 840 _link.LinkType = k_LinkType_CopyLink;
815 _link.isCopyLink = true;
816 _link.isRelative = false; // RAR5: copy links are from root folder of archive 841 _link.isRelative = false; // RAR5: copy links are from root folder of archive
817 _link.linkPath.SetFromBstr(prop.bstrVal); 842 _link.LinkPath.SetFromBstr(prop.bstrVal);
818 } 843 }
819 else if (prop.vt != VT_EMPTY) 844 else if (prop.vt != VT_EMPTY)
820 return E_FAIL; 845 return E_FAIL;
821 } 846 }
822 */ 847 */
823
824 { 848 {
825 NCOM::CPropVariant prop; 849 NCOM::CPropVariant prop;
826 RINOK(archive->GetProperty(index, kpidSymLink, &prop)) 850 RINOK(archive->GetProperty(index, kpidSymLink, &prop))
827 if (prop.vt == VT_BSTR) 851 if (prop.vt == VT_BSTR)
828 { 852 {
829 _link.isHardLink = false; 853 _link.LinkType = k_LinkType_PureSymLink;
830 // _link.isCopyLink = false; 854 _link.isRelative = true; // RAR5, TAR: symbolic links are relative by default
831 _link.isRelative = true; // RAR5, TAR: symbolic links can be relative 855 _link.LinkPath.SetFromBstr(prop.bstrVal);
832 _link.linkPath.SetFromBstr(prop.bstrVal); 856 // 7-Zip 24-: (tar, cpio, xar, ext, iso) handlers returned returned original path (with linux slash in most case)
857 // 7-Zip 24-: rar5 handler returned path with system slash.
858 // 7-Zip 25+: all handlers return linux path in most cases.
833 } 859 }
834 else if (prop.vt != VT_EMPTY) 860 else if (prop.vt != VT_EMPTY)
835 return E_FAIL; 861 return E_FAIL;
836 } 862 }
837 863
838 NtReparse_Data = NULL; 864 // linux path separator in (_link.LinkPath) is expected for most cases,
839 NtReparse_Size = 0; 865 // if new handler code is used, and if data in archive is correct.
840 866 // NtReparse_Data = NULL;
841 if (_link.linkPath.IsEmpty() && _arc->GetRawProps) 867 // NtReparse_Size = 0;
868 if (!_link.LinkPath.IsEmpty())
869 {
870 REPLACE_SLASHES_from_Linux_to_Sys(_link.LinkPath)
871 }
872 else if (_arc->GetRawProps)
842 { 873 {
843 const void *data; 874 const void *data;
844 UInt32 dataSize; 875 UInt32 dataSize, propType;
845 UInt32 propType; 876 if (_arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType) == S_OK
846 877 // && dataSize == 1234567 // for debug: unpacking without reparse
847 _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); 878 && dataSize)
848
849 // if (dataSize == 1234567) // for debug: unpacking without reparse
850 if (dataSize != 0)
851 { 879 {
852 if (propType != NPropDataType::kRaw) 880 if (propType != NPropDataType::kRaw)
853 return E_FAIL; 881 return E_FAIL;
854
855 // 21.06: we need kpidNtReparse in linux for wim archives created in Windows 882 // 21.06: we need kpidNtReparse in linux for wim archives created in Windows
856 // #ifdef _WIN32 883 // NtReparse_Data = data;
857 884 // NtReparse_Size = dataSize;
858 NtReparse_Data = data; 885 // we ignore error code here, if there is failure of parsing:
859 NtReparse_Size = dataSize; 886 _link.Parse_from_WindowsReparseData((const Byte *)data, dataSize);
860
861 CReparseAttr reparse;
862 bool isOkReparse = reparse.Parse((const Byte *)data, dataSize);
863 if (isOkReparse)
864 {
865 _link.isHardLink = false;
866 // _link.isCopyLink = false;
867 _link.linkPath = reparse.GetPath();
868 _link.isJunction = reparse.IsMountPoint();
869
870 if (reparse.IsSymLink_WSL())
871 {
872 _link.isWSL = true;
873 _link.isRelative = reparse.IsRelative_WSL();
874 }
875 else
876 _link.isRelative = reparse.IsRelative_Win();
877
878 // const AString s = GetAnsiString(_link.linkPath);
879 // printf("\n_link.linkPath: %s\n", s.Ptr());
880
881 #ifndef _WIN32
882 _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
883 #endif
884 }
885 // #endif
886 } 887 }
887 } 888 }
888 889
889 if (_link.linkPath.IsEmpty()) 890 if (_link.LinkPath.IsEmpty())
890 return S_OK; 891 return S_OK;
891 892 // (_link.LinkPath) uses system path separator.
893 // windows: (_link.LinkPath) doesn't contain linux separator (slash).
892 { 894 {
893 #ifdef _WIN32 895 // _link.LinkPath = "\\??\\r:\\1\\2"; // for debug
894 _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR); 896 // rar5+ returns kpidSymLink absolute link path with "\??\" prefix.
895 #endif 897 // we normalize such prefix:
896 898 if (_link.LinkPath.IsPrefixedBy(STRING_PATH_SEPARATOR "??" STRING_PATH_SEPARATOR))
897 // rar5 uses "\??\" prefix for absolute links
898 if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
899 {
900 _link.isRelative = false;
901 _link.linkPath.DeleteFrontal(4);
902 }
903
904 for (;;)
905 // while (NName::IsAbsolutePath(linkPath))
906 { 899 {
907 unsigned n = NName::GetRootPrefixSize(_link.linkPath);
908 if (n == 0)
909 break;
910 _link.isRelative = false; 900 _link.isRelative = false;
911 _link.linkPath.DeleteFrontal(n); 901 // we normalize prefix from "\??\" to "\\?\":
912 } 902 _link.LinkPath.ReplaceOneCharAtPos(1, WCHAR_PATH_SEPARATOR);
913 } 903 _link.isWindowsPath = true;
914 904 if (_link.LinkPath.IsPrefixedBy_Ascii_NoCase(
915 if (_link.linkPath.IsEmpty()) 905 STRING_PATH_SEPARATOR
916 return S_OK; 906 STRING_PATH_SEPARATOR "?"
917 907 STRING_PATH_SEPARATOR "UNC"
918 if (!_link.isRelative && _removePathParts.Size() != 0) 908 STRING_PATH_SEPARATOR))
919 {
920 UStringVector pathParts;
921 SplitPathToParts(_link.linkPath, pathParts);
922 bool badPrefix = false;
923 FOR_VECTOR (i, _removePathParts)
924 {
925 if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
926 { 909 {
927 badPrefix = true; 910 // we normalize prefix from "\\?\UNC\path" to "\\path":
928 break; 911 _link.LinkPath.DeleteFrontal(6);
912 _link.LinkPath.ReplaceOneCharAtPos(0, WCHAR_PATH_SEPARATOR);
913 }
914 else
915 {
916 const unsigned k_prefix_Size = 4;
917 if (NName::IsDrivePath(_link.LinkPath.Ptr(k_prefix_Size)))
918 _link.LinkPath.DeleteFrontal(k_prefix_Size);
929 } 919 }
930 } 920 }
931 if (!badPrefix)
932 pathParts.DeleteFrontal(_removePathParts.Size());
933 _link.linkPath = MakePathFromParts(pathParts);
934 }
935
936 /*
937 if (!_link.linkPath.IsEmpty())
938 {
939 printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr());
940 } 921 }
941 */ 922 _link.Normalize_to_RelativeSafe(_removePathParts);
942
943 return S_OK; 923 return S_OK;
944} 924}
945 925
@@ -949,7 +929,7 @@ HRESULT CArchiveExtractCallback::ReadLink()
949#ifndef _WIN32 929#ifndef _WIN32
950 930
951static HRESULT GetOwner(IInArchive *archive, 931static HRESULT GetOwner(IInArchive *archive,
952 UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res) 932 UInt32 index, UInt32 pidName, UInt32 pidId, CProcessedFileInfo::COwnerInfo &res)
953{ 933{
954 { 934 {
955 NWindows::NCOM::CPropVariant prop; 935 NWindows::NCOM::CPropVariant prop;
@@ -957,7 +937,7 @@ static HRESULT GetOwner(IInArchive *archive,
957 if (prop.vt == VT_UI4) 937 if (prop.vt == VT_UI4)
958 { 938 {
959 res.Id_Defined = true; 939 res.Id_Defined = true;
960 res.Id = prop.ulVal; // for debug 940 res.Id = prop.ulVal;
961 // res.Id++; // for debug 941 // res.Id++; // for debug
962 // if (pidId == kpidGroupId) res.Id += 7; // for debug 942 // if (pidId == kpidGroupId) res.Id += 7; // for debug
963 // res.Id = 0; // for debug 943 // res.Id = 0; // for debug
@@ -989,7 +969,7 @@ static HRESULT GetOwner(IInArchive *archive,
989 969
990HRESULT CArchiveExtractCallback::Read_fi_Props() 970HRESULT CArchiveExtractCallback::Read_fi_Props()
991{ 971{
992 IInArchive *archive = _arc->Archive; 972 IInArchive * const archive = _arc->Archive;
993 const UInt32 index = _index; 973 const UInt32 index = _index;
994 974
995 _fi.Attrib_Defined = false; 975 _fi.Attrib_Defined = false;
@@ -1081,35 +1061,35 @@ void CArchiveExtractCallback::CorrectPathParts()
1081} 1061}
1082 1062
1083 1063
1084void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) 1064static void GetFiTimesCAM(const CProcessedFileInfo &fi, CFiTimesCAM &pt, const CArc &arc)
1085{ 1065{
1086 pt.CTime_Defined = false; 1066 pt.CTime_Defined = false;
1087 pt.ATime_Defined = false; 1067 pt.ATime_Defined = false;
1088 pt.MTime_Defined = false; 1068 pt.MTime_Defined = false;
1089 1069
1090 if (Write_MTime) 1070 // if (Write_MTime)
1091 { 1071 {
1092 if (_fi.MTime.Def) 1072 if (fi.MTime.Def)
1093 { 1073 {
1094 _fi.MTime.Write_To_FiTime(pt.MTime); 1074 fi.MTime.Write_To_FiTime(pt.MTime);
1095 pt.MTime_Defined = true; 1075 pt.MTime_Defined = true;
1096 } 1076 }
1097 else if (_arc->MTime.Def) 1077 else if (arc.MTime.Def)
1098 { 1078 {
1099 _arc->MTime.Write_To_FiTime(pt.MTime); 1079 arc.MTime.Write_To_FiTime(pt.MTime);
1100 pt.MTime_Defined = true; 1080 pt.MTime_Defined = true;
1101 } 1081 }
1102 } 1082 }
1103 1083
1104 if (Write_CTime && _fi.CTime.Def) 1084 if (/* Write_CTime && */ fi.CTime.Def)
1105 { 1085 {
1106 _fi.CTime.Write_To_FiTime(pt.CTime); 1086 fi.CTime.Write_To_FiTime(pt.CTime);
1107 pt.CTime_Defined = true; 1087 pt.CTime_Defined = true;
1108 } 1088 }
1109 1089
1110 if (Write_ATime && _fi.ATime.Def) 1090 if (/* Write_ATime && */ fi.ATime.Def)
1111 { 1091 {
1112 _fi.ATime.Write_To_FiTime(pt.ATime); 1092 fi.ATime.Write_To_FiTime(pt.ATime);
1113 pt.ATime_Defined = true; 1093 pt.ATime_Defined = true;
1114 } 1094 }
1115} 1095}
@@ -1120,6 +1100,7 @@ void CArchiveExtractCallback::CreateFolders()
1120 // 21.04 : we don't change original (_item.PathParts) here 1100 // 21.04 : we don't change original (_item.PathParts) here
1121 UStringVector pathParts = _item.PathParts; 1101 UStringVector pathParts = _item.PathParts;
1122 1102
1103 bool isFinal = true;
1123 // bool is_DirOp = false; 1104 // bool is_DirOp = false;
1124 if (!pathParts.IsEmpty()) 1105 if (!pathParts.IsEmpty())
1125 { 1106 {
@@ -1129,12 +1110,15 @@ void CArchiveExtractCallback::CreateFolders()
1129 but if we create dir item here, it's not problem. */ 1110 but if we create dir item here, it's not problem. */
1130 if (!_item.IsDir 1111 if (!_item.IsDir
1131 #ifdef SUPPORT_LINKS 1112 #ifdef SUPPORT_LINKS
1132 #ifndef WIN32 1113 // #ifndef WIN32
1133 || !_link.linkPath.IsEmpty() 1114 || !_link.LinkPath.IsEmpty()
1134 #endif 1115 // #endif
1135 #endif 1116 #endif
1136 ) 1117 )
1118 {
1137 pathParts.DeleteBack(); 1119 pathParts.DeleteBack();
1120 isFinal = false; // last path part was excluded
1121 }
1138 // else is_DirOp = true; 1122 // else is_DirOp = true;
1139 } 1123 }
1140 1124
@@ -1158,7 +1142,7 @@ void CArchiveExtractCallback::CreateFolders()
1158 */ 1142 */
1159 1143
1160 FString fullPathNew; 1144 FString fullPathNew;
1161 CreateComplexDirectory(pathParts, fullPathNew); 1145 CreateComplexDirectory(pathParts, isFinal, fullPathNew);
1162 1146
1163 /* 1147 /*
1164 if (is_DirOp) 1148 if (is_DirOp)
@@ -1179,12 +1163,12 @@ void CArchiveExtractCallback::CreateFolders()
1179 return; 1163 return;
1180 1164
1181 CDirPathTime pt; 1165 CDirPathTime pt;
1182 GetFiTimesCAM(pt); 1166 GetFiTimesCAM(_fi, pt, *_arc);
1183 1167
1184 if (pt.IsSomeTimeDefined()) 1168 if (pt.IsSomeTimeDefined())
1185 { 1169 {
1186 pt.Path = fullPathNew; 1170 pt.Path = fullPathNew;
1187 pt.SetDirTime(); 1171 pt.SetDirTime_to_FS_2();
1188 _extractedFolders.Add(pt); 1172 _extractedFolders.Add(pt);
1189 } 1173 }
1190} 1174}
@@ -1269,8 +1253,7 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1269 // MyMoveFile can rename folders. So it's OK to use it for folders too 1253 // MyMoveFile can rename folders. So it's OK to use it for folders too
1270 if (!MyMoveFile(fullProcessedPath, existPath)) 1254 if (!MyMoveFile(fullProcessedPath, existPath))
1271 { 1255 {
1272 HRESULT errorCode = GetLastError_noZero_HRESULT(); 1256 RINOK(SendMessageError2_with_LastError(kCantRenameFile, existPath, fullProcessedPath))
1273 RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath))
1274 return E_FAIL; 1257 return E_FAIL;
1275 } 1258 }
1276 } 1259 }
@@ -1302,7 +1285,7 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1302 { 1285 {
1303 #if defined(_WIN32) && !defined(UNDER_CE) 1286 #if defined(_WIN32) && !defined(UNDER_CE)
1304 // we need to clear READ-ONLY of parent before creating alt stream 1287 // we need to clear READ-ONLY of parent before creating alt stream
1305 int colonPos = NName::FindAltStreamColon(fullProcessedPath); 1288 const int colonPos = NName::FindAltStreamColon(fullProcessedPath);
1306 if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0) 1289 if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0)
1307 { 1290 {
1308 FString parentFsPath (fullProcessedPath); 1291 FString parentFsPath (fullProcessedPath);
@@ -1311,7 +1294,11 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1311 if (parentFi.Find(parentFsPath)) 1294 if (parentFi.Find(parentFsPath))
1312 { 1295 {
1313 if (parentFi.IsReadOnly()) 1296 if (parentFi.IsReadOnly())
1297 {
1298 _altStream_NeedRestore_Attrib_for_parentFsPath = parentFsPath;
1299 _altStream_NeedRestore_AttribVal = parentFi.Attrib;
1314 SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY); 1300 SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY);
1301 }
1315 } 1302 }
1316 } 1303 }
1317 #endif // defined(_WIN32) && !defined(UNDER_CE) 1304 #endif // defined(_WIN32) && !defined(UNDER_CE)
@@ -1323,9 +1310,11 @@ HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool
1323 1310
1324 1311
1325 1312
1326 1313/*
1327 1314return:
1328 1315 needExit = false: caller will use (outStreamLoc) and _hashStreamSpec
1316 needExit = true : caller will not use (outStreamLoc) and _hashStreamSpec.
1317*/
1329HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit) 1318HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit)
1330{ 1319{
1331 needExit = true; 1320 needExit = true;
@@ -1333,7 +1322,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1333 RINOK(Read_fi_Props()) 1322 RINOK(Read_fi_Props())
1334 1323
1335 #ifdef SUPPORT_LINKS 1324 #ifdef SUPPORT_LINKS
1336 IInArchive *archive = _arc->Archive; 1325 IInArchive * const archive = _arc->Archive;
1337 #endif 1326 #endif
1338 1327
1339 const UInt32 index = _index; 1328 const UInt32 index = _index;
@@ -1379,7 +1368,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1379 if (isAnti) 1368 if (isAnti)
1380 RemoveDir(_diskFilePath); 1369 RemoveDir(_diskFilePath);
1381 #ifdef SUPPORT_LINKS 1370 #ifdef SUPPORT_LINKS
1382 if (_link.linkPath.IsEmpty()) 1371 if (_link.LinkPath.IsEmpty())
1383 #endif 1372 #endif
1384 { 1373 {
1385 if (!isAnti) 1374 if (!isAnti)
@@ -1408,18 +1397,21 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1408 1397
1409 #ifdef SUPPORT_LINKS 1398 #ifdef SUPPORT_LINKS
1410 1399
1411 if (!_link.linkPath.IsEmpty()) 1400 if (!_link.LinkPath.IsEmpty())
1412 { 1401 {
1413 #ifndef UNDER_CE 1402 #ifndef UNDER_CE
1414 { 1403 {
1415 bool linkWasSet = false; 1404 bool linkWasSet = false;
1416 RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet)) 1405 RINOK(SetLink(fullProcessedPath, _link, linkWasSet))
1406/*
1407 // we don't set attributes for placeholder.
1417 if (linkWasSet) 1408 if (linkWasSet)
1418 { 1409 {
1419 _isSymLinkCreated = _link.IsSymLink(); 1410 _isSymLinkCreated = _link.Is_AnySymLink();
1420 SetAttrib(); 1411 SetAttrib();
1421 // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath)); 1412 // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath));
1422 } 1413 }
1414*/
1423 } 1415 }
1424 #endif // UNDER_CE 1416 #endif // UNDER_CE
1425 1417
@@ -1445,16 +1437,17 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1445 hl = fullProcessedPath; 1437 hl = fullProcessedPath;
1446 else 1438 else
1447 { 1439 {
1448 if (!MyCreateHardLink(fullProcessedPath, hl)) 1440 bool link_was_Created = false;
1449 { 1441 RINOK(CreateHardLink2(fullProcessedPath, hl, link_was_Created))
1450 const HRESULT errorCode = GetLastError_noZero_HRESULT(); 1442 if (!link_was_Created)
1451 RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl))
1452 return S_OK; 1443 return S_OK;
1453 }
1454
1455 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath)); 1444 // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath));
1456 // _needSetAttrib = true; // do we need to set attribute ? 1445 // _needSetAttrib = true; // do we need to set attribute ?
1457 SetAttrib(); 1446 SetAttrib();
1447 /* if we set (needExit = false) here, _hashStreamSpec will be used,
1448 and hash will be calulated for all hard links files (it's slower).
1449 But "Test" operation also calculates hashes.
1450 */
1458 needExit = false; 1451 needExit = false;
1459 return S_OK; 1452 return S_OK;
1460 } 1453 }
@@ -1483,7 +1476,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1483 1476
1484 bool is_SymLink_in_Data = false; 1477 bool is_SymLink_in_Data = false;
1485 1478
1486 if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12)) 1479 if (_curSize_Defined && _curSize && _curSize < k_LinkDataSize_LIMIT)
1487 { 1480 {
1488 if (_fi.IsLinuxSymLink()) 1481 if (_fi.IsLinuxSymLink())
1489 { 1482 {
@@ -1505,7 +1498,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1505 _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size()); 1498 _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size());
1506 outStreamLoc = _bufPtrSeqOutStream; 1499 outStreamLoc = _bufPtrSeqOutStream;
1507 } 1500 }
1508 else // not reprase 1501 else // not reparse
1509 { 1502 {
1510 if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12)) 1503 if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12))
1511 { 1504 {
@@ -1560,7 +1553,7 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream
1560 RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL)) 1553 RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL))
1561 } 1554 }
1562 outStreamLoc = outFileStream_Loc; 1555 outStreamLoc = outFileStream_Loc;
1563 } // if not reprase 1556 } // if not reparse
1564 1557
1565 _outFileStream = outFileStream_Loc; 1558 _outFileStream = outFileStream_Loc;
1566 1559
@@ -1607,37 +1600,36 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1607 _bufPtrSeqOutStream.Release(); 1600 _bufPtrSeqOutStream.Release();
1608 1601
1609 _encrypted = false; 1602 _encrypted = false;
1610 _position = 0;
1611 _isSplit = false; 1603 _isSplit = false;
1612
1613 _curSize = 0;
1614 _curSize_Defined = false; 1604 _curSize_Defined = false;
1615 _fileLength_WasSet = false; 1605 _fileLength_WasSet = false;
1616 _fileLength_that_WasSet = 0;
1617 _index = index;
1618
1619 _diskFilePath.Empty();
1620
1621 _isRenamed = false; 1606 _isRenamed = false;
1622
1623 // _fi.Clear(); 1607 // _fi.Clear();
1624 1608 _extractMode = false;
1625 // _is_SymLink_in_Data = false;
1626 _is_SymLink_in_Data_Linux = false; 1609 _is_SymLink_in_Data_Linux = false;
1627
1628 _needSetAttrib = false; 1610 _needSetAttrib = false;
1629 _isSymLinkCreated = false; 1611 _isSymLinkCreated = false;
1630 _itemFailure = false; 1612 _itemFailure = false;
1631
1632 _some_pathParts_wereRemoved = false; 1613 _some_pathParts_wereRemoved = false;
1633 // _op_WasReported = false; 1614 // _op_WasReported = false;
1634 1615
1616 _position = 0;
1617 _curSize = 0;
1618 _fileLength_that_WasSet = 0;
1619 _index = index;
1620
1621#if defined(_WIN32) && !defined(UNDER_CE)
1622 _altStream_NeedRestore_AttribVal = 0;
1623 _altStream_NeedRestore_Attrib_for_parentFsPath.Empty();
1624#endif
1625
1626 _diskFilePath.Empty();
1627
1635 #ifdef SUPPORT_LINKS 1628 #ifdef SUPPORT_LINKS
1636 // _copyFile_Path.Empty(); 1629 // _copyFile_Path.Empty();
1637 _link.Clear(); 1630 _link.Clear();
1638 #endif 1631 #endif
1639 1632
1640 _extractMode = false;
1641 1633
1642 switch (askExtractMode) 1634 switch (askExtractMode)
1643 { 1635 {
@@ -1653,7 +1645,7 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1653 } 1645 }
1654 1646
1655 1647
1656 IInArchive *archive = _arc->Archive; 1648 IInArchive * const archive = _arc->Archive;
1657 1649
1658 RINOK(GetItem(index)) 1650 RINOK(GetItem(index))
1659 1651
@@ -1669,10 +1661,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1669 } 1661 }
1670 } 1662 }
1671 1663
1672 #ifdef SUPPORT_LINKS 1664#ifdef SUPPORT_LINKS
1673 RINOK(ReadLink()) 1665 RINOK(ReadLink())
1674 #endif // SUPPORT_LINKS 1666#endif
1675
1676 1667
1677 RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)) 1668 RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted))
1678 1669
@@ -1692,6 +1683,19 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1692 return S_OK; 1683 return S_OK;
1693 } 1684 }
1694 1685
1686#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
1687 if (askExtractMode == NArchive::NExtract::NAskMode::kExtract
1688 && !_testMode
1689 && _item.IsAltStream
1690 && ZoneBuf.Size() != 0
1691 && Is_ZoneId_StreamName(_item.AltStreamName))
1692 if (ZoneMode != NExtract::NZoneIdMode::kOffice
1693 || _item.PathParts.IsEmpty()
1694 || FindExt2(kOfficeExtensions, _item.PathParts.Back()))
1695 return S_OK;
1696#endif
1697
1698
1695 #ifndef Z7_SFX 1699 #ifndef Z7_SFX
1696 if (_use_baseParentFolder_mode) 1700 if (_use_baseParentFolder_mode)
1697 { 1701 {
@@ -1810,15 +1814,11 @@ Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
1810 1814
1811 if (ExtractToStreamCallback) 1815 if (ExtractToStreamCallback)
1812 { 1816 {
1813 if (!GetProp) 1817 CMyComPtr2_Create<IGetProp, CGetProp> GetProp;
1814 { 1818 GetProp->Arc = _arc;
1815 GetProp_Spec = new CGetProp; 1819 GetProp->IndexInArc = index;
1816 GetProp = GetProp_Spec;
1817 }
1818 GetProp_Spec->Arc = _arc;
1819 GetProp_Spec->IndexInArc = index;
1820 UString name (MakePathFromParts(pathParts)); 1820 UString name (MakePathFromParts(pathParts));
1821 1821 // GetProp->BaseName = name;
1822 #ifdef SUPPORT_ALT_STREAMS 1822 #ifdef SUPPORT_ALT_STREAMS
1823 if (_item.IsAltStream) 1823 if (_item.IsAltStream)
1824 { 1824 {
@@ -1972,7 +1972,7 @@ HRESULT CArchiveExtractCallback::CloseFile()
1972 #endif 1972 #endif
1973 1973
1974 CFiTimesCAM t; 1974 CFiTimesCAM t;
1975 GetFiTimesCAM(t); 1975 GetFiTimesCAM(_fi, t, *_arc);
1976 1976
1977 // #ifdef _WIN32 1977 // #ifdef _WIN32
1978 if (t.IsSomeTimeDefined()) 1978 if (t.IsSomeTimeDefined())
@@ -1984,94 +1984,290 @@ HRESULT CArchiveExtractCallback::CloseFile()
1984 1984
1985 RINOK(_outFileStreamSpec->Close()) 1985 RINOK(_outFileStreamSpec->Close())
1986 _outFileStream.Release(); 1986 _outFileStream.Release();
1987
1988#if defined(_WIN32) && !defined(UNDER_CE)
1989 if (!_altStream_NeedRestore_Attrib_for_parentFsPath.IsEmpty())
1990 {
1991 SetFileAttrib(_altStream_NeedRestore_Attrib_for_parentFsPath, _altStream_NeedRestore_AttribVal);
1992 _altStream_NeedRestore_Attrib_for_parentFsPath.Empty();
1993 }
1994#endif
1995
1987 return hres; 1996 return hres;
1988} 1997}
1989 1998
1990 1999
1991#ifdef SUPPORT_LINKS 2000#ifdef SUPPORT_LINKS
1992 2001
2002static bool CheckLinkPath_in_FS_for_pathParts(const FString &path, const UStringVector &v)
2003{
2004 FString path2 = path;
2005 FOR_VECTOR (i, v)
2006 {
2007 // if (i == v.Size() - 1) path = path2; // we don't need last part in returned path
2008 path2 += us2fs(v[i]);
2009 NFind::CFileInfo fi;
2010 // printf("\nCheckLinkPath_in_FS_for_pathParts(): %s\n", GetOemString(path2).Ptr());
2011 if (fi.Find(path2) && fi.IsOsSymLink())
2012 return false;
2013 path2.Add_PathSepar();
2014 }
2015 return true;
2016}
2017
2018/*
2019link.isRelative / relative_item_PathPrefix
2020 false / empty
2021 true / item path without last part
2022*/
2023static bool CheckLinkPath_in_FS(
2024 const FString &pathPrefix_in_FS,
2025 const CPostLink &postLink,
2026 const UString &relative_item_PathPrefix)
2027{
2028 const CLinkInfo &link = postLink.LinkInfo;
2029 if (postLink.item_PathParts.IsEmpty() || link.LinkPath.IsEmpty())
2030 return false;
2031 FString path;
2032 {
2033 const UString &s = postLink.item_PathParts[0];
2034 if (!s.IsEmpty() && !NName::IsAbsolutePath(s))
2035 path = pathPrefix_in_FS; // item_PathParts is relative. So we use absolutre prefix
2036 }
2037 if (!CheckLinkPath_in_FS_for_pathParts(path, postLink.item_PathParts))
2038 return false;
2039 path += us2fs(relative_item_PathPrefix);
2040 UStringVector v;
2041 SplitPathToParts(link.LinkPath, v);
2042 // we check target paths:
2043 return CheckLinkPath_in_FS_for_pathParts(path, v);
2044}
1993 2045
1994HRESULT CArchiveExtractCallback::SetFromLinkPath( 2046static const unsigned k_DangLevel_MAX_for_Link_over_Link = 9;
1995 const FString &fullProcessedPath, 2047
1996 const CLinkInfo &linkInfo, 2048HRESULT CArchiveExtractCallback::CreateHardLink2(
1997 bool &linkWasSet) 2049 const FString &newFilePath, const FString &existFilePath, bool &link_was_Created) const
2050{
2051 link_was_Created = false;
2052 if (_ntOptions.SymLinks_DangerousLevel <= k_DangLevel_MAX_for_Link_over_Link)
2053 {
2054 NFind::CFileInfo fi;
2055 if (fi.Find(existFilePath) && fi.IsOsSymLink())
2056 return SendMessageError2(0, k_HardLink_to_SymLink_Ignored, newFilePath, existFilePath);
2057 }
2058 if (!MyCreateHardLink(newFilePath, existFilePath))
2059 return SendMessageError2_with_LastError(kCantCreateHardLink, newFilePath, existFilePath);
2060 link_was_Created = true;
2061 return S_OK;
2062}
2063
2064
2065
2066HRESULT CArchiveExtractCallback::SetLink(
2067 const FString &fullProcessedPath_from,
2068 const CLinkInfo &link,
2069 bool &linkWasSet) // placeholder was created
1998{ 2070{
1999 linkWasSet = false; 2071 linkWasSet = false;
2000 if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink) 2072 if (link.LinkPath.IsEmpty())
2073 return S_OK;
2074 if (!_ntOptions.SymLinks.Val && link.Is_AnySymLink())
2001 return S_OK; 2075 return S_OK;
2076 CPostLink postLink;
2077 postLink.Index_in_Arc = _index;
2078 postLink.item_IsDir = _item.IsDir;
2079 postLink.item_Path = _item.Path;
2080 postLink.item_PathParts = _item.PathParts;
2081 postLink.item_FileInfo = _fi;
2082 postLink.fullProcessedPath_from = fullProcessedPath_from;
2083 postLink.LinkInfo = link;
2084 _postLinks.Add(postLink);
2085
2086 // file doesn't exist in most cases. So we don't check for error.
2087 DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, false); // checkThatFileIsEmpty = false
2002 2088
2003 UString relatPath; 2089 NIO::COutFile outFile;
2090 if (!outFile.Create_NEW(fullProcessedPath_from))
2091 return SendMessageError("Cannot create temporary link file", fullProcessedPath_from);
2092#if 0 // 1 for debug
2093 // here we can write link path to temporary link file placeholder,
2094 // but empty placeholder is better, because we don't want to get any non-eampty data instead of link file.
2095 AString s;
2096 ConvertUnicodeToUTF8(link.LinkPath, s);
2097 outFile.WriteFull(s, s.Len());
2098#endif
2099 linkWasSet = true;
2100 return S_OK;
2101}
2004 2102
2005 /* if (linkInfo.isRelative) 2103
2006 linkInfo.linkPath is final link path that must be stored to file link field 2104// if file/dir is symbolic link it will remove only link itself
2007 else 2105HRESULT CArchiveExtractCallback::DeleteLinkFileAlways_or_RemoveEmptyDir(
2008 linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath. 2106 const FString &path, bool checkThatFileIsEmpty) const
2009 */ 2107{
2010 2108 NFile::NFind::CFileInfo fi;
2011 if (linkInfo.isRelative) 2109 if (fi.Find(path)) // followLink = false
2012 relatPath = GetDirPrefixOf(_item.Path);
2013 relatPath += linkInfo.linkPath;
2014
2015 if (!IsSafePath(relatPath))
2016 { 2110 {
2017 return SendMessageError2( 2111 if (fi.IsDir())
2018 0, // errorCode 2112 {
2019 "Dangerous link path was ignored", 2113 if (RemoveDirAlways_if_Empty(path))
2020 us2fs(_item.Path), 2114 return S_OK;
2021 us2fs(linkInfo.linkPath)); // us2fs(relatPath) 2115 }
2116 else
2117 {
2118 // link file placeholder must be empty
2119 if (checkThatFileIsEmpty && !fi.IsOsSymLink() && fi.Size != 0)
2120 return SendMessageError("Temporary link file is not empty", path);
2121 if (DeleteFileAlways(path))
2122 return S_OK;
2123 }
2124 if (GetLastError() != ERROR_FILE_NOT_FOUND)
2125 return SendMessageError_with_LastError(
2126 fi.IsDir() ?
2127 k_CantDelete_Dir_for_SymLink:
2128 k_CantDelete_File_for_SymLink,
2129 path);
2022 } 2130 }
2131 return S_OK;
2132}
2133
2134
2135/*
2136in:
2137 link.LinkPath : must be relative (non-absolute) path in any case !!!
2138 link.isRelative / target path that must stored as created link:
2139 == false / _dirPathPrefix_Full + link.LinkPath
2140 == true / link.LinkPath
2141*/
2142static HRESULT SetLink2(const CArchiveExtractCallback &callback,
2143 const CPostLink &postLink, bool &linkWasSet)
2144{
2145 const CLinkInfo &link = postLink.LinkInfo;
2146 const FString &fullProcessedPath_from = postLink.fullProcessedPath_from; // full file path in FS (fullProcessedPath_from)
2023 2147
2024 FString existPath; 2148 const unsigned level = callback._ntOptions.SymLinks_DangerousLevel;
2025 if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative) 2149 if (level < 20)
2026 { 2150 {
2027 if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath)) 2151 /*
2152 We want to use additional check for links that can link to directory.
2153 - linux: all symbolic links are files.
2154 - windows: we can have file/directory symbolic link,
2155 but file symbolic link works like directory link in windows.
2156 So we use additional check for all relative links.
2157
2158 We don't allow decreasing of final level of link.
2159 So if some another extracted file will use this link,
2160 then number of real path parts (after link redirection) cannot be
2161 smaller than number of requested path parts from archive records.
2162
2163 here we check only (link.LinkPath) without (_item.PathParts).
2164 */
2165 CLinkLevelsInfo li;
2166 li.Parse(link.LinkPath, link.Is_WSL());
2167 bool isDang;
2168 UString relativePathPrefix;
2169 if (li.IsAbsolute // unexpected
2170 || li.ParentDirDots_after_NonParent
2171 || (level <= 5 && link.isRelative && li.FinalLevel < 1) // final level lower
2172 || (level <= 5 && link.isRelative && li.LowLevel < 0) // negative temporary levels
2173 )
2174 isDang = true;
2175 else // if (!isDang)
2028 { 2176 {
2029 RINOK(SendMessageError("Incorrect path", us2fs(relatPath))) 2177 UString path;
2030 } 2178 if (link.isRelative)
2179 {
2180 // item_PathParts : parts that will be created in output folder.
2181 // we want to get directory prefix of link item.
2182 // so we remove file name (last non-empty part) from PathParts:
2183 UStringVector v = postLink.item_PathParts;
2184 while (!v.IsEmpty())
2185 {
2186 const unsigned len = v.Back().Len();
2187 v.DeleteBack();
2188 if (len)
2189 break;
2190 }
2191 path = MakePathFromParts(v);
2192 NName::NormalizeDirPathPrefix(path);
2193 relativePathPrefix = path;
2194 }
2195 path += link.LinkPath;
2196 /*
2197 path is calculated virtual target path of link
2198 path is relative to root folder of extracted items
2199 if (!link.isRelative), then (path == link.LinkPath)
2200 */
2201 isDang = false;
2202 if (!IsSafePath(path, link.Is_WSL()))
2203 isDang = true;
2204 }
2205 const char *message = NULL;
2206 if (isDang)
2207 message = "Dangerous link path was ignored";
2208 else if (level <= k_DangLevel_MAX_for_Link_over_Link
2209 && !CheckLinkPath_in_FS(callback._dirPathPrefix_Full,
2210 postLink, relativePathPrefix))
2211 message = "Dangerous link via another link was ignored";
2212 if (message)
2213 return callback.SendMessageError2(0, // errorCode
2214 message, us2fs(postLink.item_Path), us2fs(link.LinkPath));
2215 }
2216
2217 FString target; // target path that will be stored to link field
2218 if (link.Is_HardLink() /* || link.IsCopyLink */ || !link.isRelative)
2219 {
2220 // isRelative == false
2221 // all hard links and absolute symbolic links
2222 // relatPath == link.LinkPath
2223 // we get absolute link path for target:
2224 if (!NName::GetFullPath(callback._dirPathPrefix_Full, us2fs(link.LinkPath), target))
2225 return callback.SendMessageError("Incorrect link path", us2fs(link.LinkPath));
2226 // (target) is (_dirPathPrefix_Full + relatPath)
2031 } 2227 }
2032 else 2228 else
2033 { 2229 {
2034 existPath = us2fs(linkInfo.linkPath); 2230 // link.isRelative == true
2035 // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr()); 2231 // relative symbolic links only
2232 target = us2fs(link.LinkPath);
2036 } 2233 }
2037 2234 if (target.IsEmpty())
2038 if (existPath.IsEmpty()) 2235 return callback.SendMessageError("Empty link", fullProcessedPath_from);
2039 return SendMessageError("Empty link", fullProcessedPath);
2040 2236
2041 if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */) 2237 if (link.Is_HardLink() /* || link.IsCopyLink */)
2042 { 2238 {
2043 // if (linkInfo.isHardLink) 2239 // if (link.isHardLink)
2044 { 2240 {
2045 if (!MyCreateHardLink(fullProcessedPath, existPath)) 2241 RINOK(callback.DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, true)) // checkThatFileIsEmpty
2046 { 2242 {
2047 const HRESULT errorCode = GetLastError_noZero_HRESULT(); 2243 // RINOK(SendMessageError_with_LastError(k_Cant_DeleteTempLinkFile, fullProcessedPath_from))
2048 RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath))
2049 } 2244 }
2245 return callback.CreateHardLink2(fullProcessedPath_from, target, linkWasSet);
2050 /* 2246 /*
2051 RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract)) 2247 RINOK(PrepareOperation(NArchive::NExtract::NAskMode::kExtract))
2052 _op_WasReported = true; 2248 _op_WasReported = true;
2053 RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK)) 2249 RINOK(SetOperationResult(NArchive::NExtract::NOperationResult::kOK))
2054 */
2055 linkWasSet = true; 2250 linkWasSet = true;
2056 return S_OK; 2251 return S_OK;
2252 */
2057 } 2253 }
2058 /* 2254 /*
2059 // IsCopyLink 2255 // IsCopyLink
2060 { 2256 {
2061 NFind::CFileInfo fi; 2257 NFind::CFileInfo fi;
2062 if (!fi.Find(existPath)) 2258 if (!fi.Find(target))
2063 { 2259 {
2064 RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath)); 2260 RINOK(SendMessageError2("Cannot find the file for copying", target, fullProcessedPath));
2065 } 2261 }
2066 else 2262 else
2067 { 2263 {
2068 if (_curSize_Defined && _curSize == fi.Size) 2264 if (_curSize_Defined && _curSize == fi.Size)
2069 _copyFile_Path = existPath; 2265 _copyFile_Path = target;
2070 else 2266 else
2071 { 2267 {
2072 RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath)); 2268 RINOK(SendMessageError2("File size collision for file copying", target, fullProcessedPath));
2073 } 2269 }
2074 // RINOK(MyCopyFile(existPath, fullProcessedPath)); 2270 // RINOK(MyCopyFile(target, fullProcessedPath));
2075 } 2271 }
2076 } 2272 }
2077 */ 2273 */
@@ -2085,127 +2281,227 @@ HRESULT CArchiveExtractCallback::SetFromLinkPath(
2085 // Windows before Vista doesn't support symbolic links. 2281 // Windows before Vista doesn't support symbolic links.
2086 // we could convert such symbolic links to Junction Points 2282 // we could convert such symbolic links to Junction Points
2087 // isJunction = true; 2283 // isJunction = true;
2088 // convertToAbs = true;
2089 } 2284 }
2090 */ 2285 */
2091 2286
2092 if (!_ntOptions.SymLinks_AllowDangerous.Val) 2287#ifdef _WIN32
2093 { 2288 const bool isDir = (postLink.item_IsDir || link.LinkType == k_LinkType_Junction);
2094 #ifdef _WIN32 2289#endif
2095 if (_item.IsDir)
2096 #endif
2097 if (linkInfo.isRelative)
2098 {
2099 CLinkLevelsInfo levelsInfo;
2100 levelsInfo.Parse(linkInfo.linkPath);
2101 if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute)
2102 {
2103 return SendMessageError2(
2104 0, // errorCode
2105 "Dangerous symbolic link path was ignored",
2106 us2fs(_item.Path),
2107 us2fs(linkInfo.linkPath));
2108 }
2109 }
2110 }
2111 2290
2112 2291
2113 #ifdef _WIN32 2292#ifdef _WIN32
2114
2115 CByteBuffer data; 2293 CByteBuffer data;
2116 // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr()); 2294 // printf("\nFillLinkData(): %s\n", GetOemString(target).Ptr());
2117 if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL)) 2295 if (link.Is_WSL())
2118 return SendMessageError("Cannot fill link data", us2fs(_item.Path));
2119
2120 /*
2121 if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
2122 { 2296 {
2123 SendMessageError("reconstructed Reparse is different", fs2us(existPath)); 2297 Convert_WinPath_to_WslLinuxPath(target, !link.isRelative);
2298 FillLinkData_WslLink(data, fs2us(target));
2124 } 2299 }
2300 else
2301 FillLinkData_WinLink(data, fs2us(target), link.LinkType != k_LinkType_Junction);
2302 if (data.Size() == 0)
2303 return callback.SendMessageError("Cannot fill link data", us2fs(postLink.item_Path));
2304 /*
2305 if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
2306 SendMessageError("reconstructed Reparse is different", fs2us(target));
2125 */ 2307 */
2126
2127 CReparseAttr attr;
2128 if (!attr.Parse(data, data.Size()))
2129 { 2308 {
2130 RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))) 2309 // we check that reparse data is correct, but we ignore attr.MinorError.
2131 return S_OK; 2310 CReparseAttr attr;
2132 } 2311 if (!attr.Parse(data, data.Size()))
2133 if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size())) 2312 return callback.SendMessageError("Internal error for symbolic link file", us2fs(postLink.item_Path));
2134 {
2135 RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
2136 return S_OK;
2137 } 2313 }
2138 linkWasSet = true; 2314#endif
2139
2140 return S_OK;
2141
2142
2143 #else // ! _WIN32
2144 2315
2145 if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath)) 2316 RINOK(callback.DeleteLinkFileAlways_or_RemoveEmptyDir(fullProcessedPath_from, true)) // checkThatFileIsEmpty
2317#ifdef _WIN32
2318 if (!NFile::NIO::SetReparseData(fullProcessedPath_from, isDir, data, (DWORD)data.Size()))
2319#else // ! _WIN32
2320 if (!NFile::NIO::SetSymLink(fullProcessedPath_from, target))
2321#endif // ! _WIN32
2146 { 2322 {
2147 RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath)) 2323 return callback.SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath_from);
2148 return S_OK;
2149 } 2324 }
2150 linkWasSet = true; 2325 linkWasSet = true;
2151
2152 return S_OK; 2326 return S_OK;
2153
2154 #endif // ! _WIN32
2155} 2327}
2156 2328
2157 2329
2158bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData)
2159{
2160 Clear();
2161 // this->isLinux = isLinuxData;
2162
2163 if (isLinuxData)
2164 {
2165 isJunction = false;
2166 isHardLink = false;
2167 AString utf;
2168 if (dataSize >= (1 << 12))
2169 return false;
2170 utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
2171 UString u;
2172 if (!ConvertUTF8ToUnicode(utf, u))
2173 return false;
2174 linkPath = u;
2175
2176 // in linux symbolic data: we expect that linux separator '/' is used
2177 // if windows link was created, then we also must use linux separator
2178 if (u.IsEmpty())
2179 return false;
2180 const wchar_t c = u[0];
2181 isRelative = !IS_PATH_SEPAR(c);
2182 return true;
2183 }
2184 2330
2331bool CLinkInfo::Parse_from_WindowsReparseData(const Byte *data, size_t dataSize)
2332{
2185 CReparseAttr reparse; 2333 CReparseAttr reparse;
2186 if (!reparse.Parse(data, dataSize)) 2334 if (!reparse.Parse(data, dataSize))
2187 return false; 2335 return false;
2188 isHardLink = false; 2336 // const AString s = GetAnsiString(LinkPath);
2189 // isCopyLink = false; 2337 // printf("\nlinkPath: %s\n", s.Ptr());
2190 linkPath = reparse.GetPath(); 2338 LinkPath = reparse.GetPath();
2191 isJunction = reparse.IsMountPoint();
2192
2193 if (reparse.IsSymLink_WSL()) 2339 if (reparse.IsSymLink_WSL())
2194 { 2340 {
2195 isWSL = true; 2341 LinkType = k_LinkType_WSL;
2196 isRelative = reparse.IsRelative_WSL(); 2342 isRelative = reparse.IsRelative_WSL(); // detected from LinkPath[0]
2343 // LinkPath is original raw name converted to UString from AString
2344 // Linux separator '/' is expected here.
2345 REPLACE_SLASHES_from_Linux_to_Sys(LinkPath)
2197 } 2346 }
2198 else 2347 else
2199 isRelative = reparse.IsRelative_Win(); 2348 {
2200 2349 LinkType = reparse.IsMountPoint() ? k_LinkType_Junction : k_LinkType_PureSymLink;
2201 // FIXME !!! 2350 isRelative = reparse.IsRelative_Win(); // detected by (Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE)
2202 #ifndef _WIN32 2351 isWindowsPath = true;
2203 linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); 2352 // LinkPath is original windows link path from raparse data with \??\ prefix removed.
2204 #endif 2353 // windows '\\' separator is expected here.
2205 2354 // linux '/' separator is not expected here.
2355 // we translate both types of separators to system separator.
2356 LinkPath.Replace(
2357#if WCHAR_PATH_SEPARATOR == L'\\'
2358 L'/'
2359#else
2360 L'\\'
2361#endif
2362 , WCHAR_PATH_SEPARATOR);
2363 }
2364 // (LinkPath) uses system path separator.
2365 // windows: (LinkPath) doesn't contain linux separator (slash).
2366 return true;
2367}
2368
2369
2370bool CLinkInfo::Parse_from_LinuxData(const Byte *data, size_t dataSize)
2371{
2372 // Clear(); // *this object was cleared by constructor already.
2373 LinkType = k_LinkType_PureSymLink;
2374 AString utf;
2375 if (dataSize >= k_LinkDataSize_LIMIT)
2376 return false;
2377 utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
2378 UString u;
2379 if (!ConvertUTF8ToUnicode(utf, u))
2380 return false;
2381 if (u.IsEmpty())
2382 return false;
2383 const wchar_t c = u[0];
2384 isRelative = (c != L'/');
2385 // linux path separator is expected
2386 REPLACE_SLASHES_from_Linux_to_Sys(u)
2387 LinkPath = u;
2388 // (LinkPath) uses system path separator.
2389 // windows: (LinkPath) doesn't contain linux separator (slash).
2206 return true; 2390 return true;
2207} 2391}
2208 2392
2393
2394// in/out: (LinkPath) uses system path separator
2395// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
2396// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
2397// out: isRelative changed to false, if any prefix was removed.
2398// note: absolute windows links "c:\" to root will be reduced to empty string:
2399void CLinkInfo::Remove_AbsPathPrefixes()
2400{
2401 while (!LinkPath.IsEmpty())
2402 {
2403 unsigned n = 0;
2404 if (!Is_WSL())
2405 {
2406 n =
2407#ifndef _WIN32
2408 isWindowsPath ?
2409 NName::GetRootPrefixSize_WINDOWS(LinkPath) :
2410#endif
2411 NName::GetRootPrefixSize(LinkPath);
2412/*
2413 // "c:path" will be ignored later as "Dangerous absolute path"
2414 // so check is not required
2415 if (n == 0
2416#ifndef _WIN32
2417 && isWindowsPath
2418#endif
2419 && NName::IsDrivePath2(LinkPath))
2420 n = 2;
2421*/
2422 }
2423 if (n == 0)
2424 {
2425 if (!IS_PATH_SEPAR(LinkPath[0]))
2426 break;
2427 n = 1;
2428 }
2429 isRelative = false; // (LinkPath) will be treated as relative to root folder of archive
2430 LinkPath.DeleteFrontal(n);
2431 }
2432}
2433
2434
2435/*
2436 it removes redundant separators, if there are double separators,
2437 but it keeps double separators at start of string //name/.
2438 in/out: system path separator is used
2439 windows: slash character (linux separator) is not treated as separator
2440 windows: (path) doesn't contain linux separator (slash).
2441*/
2442static void RemoveRedundantPathSeparators(UString &path)
2443{
2444 wchar_t *dest = path.GetBuf();
2445 const wchar_t * const start = dest;
2446 const wchar_t *src = dest;
2447 for (;;)
2448 {
2449 wchar_t c = *src++;
2450 if (c == 0)
2451 break;
2452 // if (IS_PATH_SEPAR(c)) // for Windows: we can change (/) to (\).
2453 if (c == WCHAR_PATH_SEPARATOR)
2454 {
2455 if (dest - start >= 2 && dest[-1] == WCHAR_PATH_SEPARATOR)
2456 continue;
2457 // c = WCHAR_PATH_SEPARATOR; // for Windows: we can change (/) to (\).
2458 }
2459 *dest++ = c;
2460 }
2461 *dest = 0;
2462 path.ReleaseBuf_SetLen((unsigned)(dest - path.Ptr()));
2463}
2464
2465
2466// in/out: (LinkPath) uses system path separator
2467// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
2468// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
2469void CLinkInfo::Normalize_to_RelativeSafe(UStringVector &removePathParts)
2470{
2471 // We WILL NOT WRITE original absolute link path from archive to filesystem.
2472 // So here we remove all root prefixes from (LinkPath).
2473 // If we see any absolute root prefix, then we suppose that this prefix is virtual prefix
2474 // that shows that link is relative to root folder of archive
2475 RemoveRedundantPathSeparators(LinkPath);
2476 // LinkPath = "\\\\?\\r:test\\test2"; // for debug
2477 Remove_AbsPathPrefixes();
2478 // (LinkPath) now is relative:
2479 // if (isRelative == false), then (LinkPath) is relative to root folder of archive
2480 // if (isRelative == true ), then (LinkPath) is relative to current item
2481 if (LinkPath.IsEmpty() || isRelative || removePathParts.Size() == 0)
2482 return;
2483
2484 // if LinkPath is prefixed by _removePathParts, we remove these paths
2485 UStringVector pathParts;
2486 SplitPathToParts(LinkPath, pathParts);
2487 bool badPrefix = false;
2488 {
2489 FOR_VECTOR (i, removePathParts)
2490 {
2491 if (i >= pathParts.Size()
2492 || CompareFileNames(removePathParts[i], pathParts[i]) != 0)
2493 {
2494 badPrefix = true;
2495 break;
2496 }
2497 }
2498 }
2499 if (!badPrefix)
2500 pathParts.DeleteFrontal(removePathParts.Size());
2501 LinkPath = MakePathFromParts(pathParts);
2502 Remove_AbsPathPrefixes();
2503}
2504
2209#endif // SUPPORT_LINKS 2505#endif // SUPPORT_LINKS
2210 2506
2211 2507
@@ -2213,12 +2509,12 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2213{ 2509{
2214 HRESULT res = S_OK; 2510 HRESULT res = S_OK;
2215 2511
2216 #ifdef SUPPORT_LINKS 2512#ifdef SUPPORT_LINKS
2217 2513
2218 size_t reparseSize = 0; 2514 size_t reparseSize = 0;
2219 bool repraseMode = false; 2515 bool repraseMode = false;
2220 bool needSetReparse = false; 2516 bool needSetReparse = false;
2221 CLinkInfo linkInfo; 2517 CLinkInfo link;
2222 2518
2223 if (_bufPtrSeqOutStream) 2519 if (_bufPtrSeqOutStream)
2224 { 2520 {
@@ -2232,15 +2528,19 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2232 needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode); 2528 needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode);
2233 if (needSetReparse) 2529 if (needSetReparse)
2234 { 2530 {
2235 UString linkPath = reparse.GetPath(); 2531 UString LinkPath = reparse.GetPath();
2236 #ifndef _WIN32 2532 #ifndef _WIN32
2237 linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); 2533 LinkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
2238 #endif 2534 #endif
2239 } 2535 }
2240 */ 2536 */
2241 needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux); 2537 needSetReparse = _is_SymLink_in_Data_Linux ?
2538 link.Parse_from_LinuxData(_outMemBuf, reparseSize) :
2539 link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize);
2242 if (!needSetReparse) 2540 if (!needSetReparse)
2243 res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); 2541 res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path));
2542 // (link.LinkPath) uses system path separator.
2543 // windows: (link.LinkPath) doesn't contain linux separator (slash).
2244 } 2544 }
2245 else 2545 else
2246 { 2546 {
@@ -2255,25 +2555,21 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2255 _bufPtrSeqOutStream.Release(); 2555 _bufPtrSeqOutStream.Release();
2256 } 2556 }
2257 2557
2258 #endif // SUPPORT_LINKS 2558#endif // SUPPORT_LINKS
2259
2260 2559
2261 const HRESULT res2 = CloseFile(); 2560 const HRESULT res2 = CloseFile();
2262
2263 if (res == S_OK) 2561 if (res == S_OK)
2264 res = res2; 2562 res = res2;
2265
2266 RINOK(res) 2563 RINOK(res)
2267 2564
2268 #ifdef SUPPORT_LINKS 2565#ifdef SUPPORT_LINKS
2269 if (repraseMode) 2566 if (repraseMode)
2270 { 2567 {
2271 _curSize = reparseSize; 2568 _curSize = reparseSize;
2272 _curSize_Defined = true; 2569 _curSize_Defined = true;
2273
2274 #ifdef SUPPORT_LINKS
2275 if (needSetReparse) 2570 if (needSetReparse)
2276 { 2571 {
2572 // empty file was created so we must delete it.
2277 // in Linux : we must delete empty file before symbolic link creation 2573 // in Linux : we must delete empty file before symbolic link creation
2278 // in Windows : we can create symbolic link even without file deleting 2574 // in Windows : we can create symbolic link even without file deleting
2279 if (!DeleteFileAlways(_diskFilePath)) 2575 if (!DeleteFileAlways(_diskFilePath))
@@ -2281,42 +2577,57 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile()
2281 RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath)) 2577 RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath))
2282 } 2578 }
2283 { 2579 {
2284 /*
2285 // for DEBUG ONLY: we can extract sym links as WSL links
2286 // to eliminate (non-admin) errors for sym links.
2287 #ifdef _WIN32
2288 if (!linkInfo.isHardLink && !linkInfo.isJunction)
2289 linkInfo.isWSL = true;
2290 #endif
2291 */
2292 bool linkWasSet = false; 2580 bool linkWasSet = false;
2293 RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet)) 2581 // link.LinkPath = "r:\\1\\2"; // for debug
2582 // link.isJunction = true; // for debug
2583 link.Normalize_to_RelativeSafe(_removePathParts);
2584 RINOK(SetLink(_diskFilePath, link, linkWasSet))
2585/*
2586 // we don't set attributes for placeholder.
2294 if (linkWasSet) 2587 if (linkWasSet)
2295 _isSymLinkCreated = linkInfo.IsSymLink(); 2588 _isSymLinkCreated = true; // link.IsSymLink();
2296 else 2589 else
2590*/
2297 _needSetAttrib = false; 2591 _needSetAttrib = false;
2298 } 2592 }
2299 /*
2300 if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, ))
2301 {
2302 res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath);
2303 }
2304 */
2305 } 2593 }
2306 #endif
2307 } 2594 }
2308 #endif 2595#endif // SUPPORT_LINKS
2309 return res; 2596 return res;
2310} 2597}
2311 2598
2312 2599
2313void CArchiveExtractCallback::SetAttrib() 2600static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi,
2601 const CArchiveExtractCallback &callback)
2314{ 2602{
2315 #ifndef _WIN32 2603#ifndef _WIN32
2604 if (fi.Owner.Id_Defined &&
2605 fi.Group.Id_Defined)
2606 {
2607 if (my_chown(path, fi.Owner.Id, fi.Group.Id) != 0)
2608 callback.SendMessageError_with_LastError("Cannot set owner", path);
2609 }
2610#endif
2611
2612 if (fi.Attrib_Defined)
2613 {
2614 // const AString s = GetAnsiString(_diskFilePath);
2615 // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib);
2616 if (!SetFileAttrib_PosixHighDetect(path, fi.Attrib))
2617 {
2618 // do we need error message here in Windows and in posix?
2619 callback.SendMessageError_with_LastError("Cannot set file attribute", path);
2620 }
2621 }
2622}
2623
2624void CArchiveExtractCallback::SetAttrib() const
2625{
2626#ifndef _WIN32
2316 // Linux now doesn't support permissions for symlinks 2627 // Linux now doesn't support permissions for symlinks
2317 if (_isSymLinkCreated) 2628 if (_isSymLinkCreated)
2318 return; 2629 return;
2319 #endif 2630#endif
2320 2631
2321 if (_itemFailure 2632 if (_itemFailure
2322 || _diskFilePath.IsEmpty() 2633 || _diskFilePath.IsEmpty()
@@ -2324,29 +2635,39 @@ void CArchiveExtractCallback::SetAttrib()
2324 || !_extractMode) 2635 || !_extractMode)
2325 return; 2636 return;
2326 2637
2327 #ifndef _WIN32 2638 SetAttrib_Base(_diskFilePath, _fi, *this);
2328 if (_fi.Owner.Id_Defined && 2639}
2329 _fi.Group.Id_Defined)
2330 {
2331 if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0)
2332 {
2333 SendMessageError_with_LastError("Cannot set owner", _diskFilePath);
2334 }
2335 }
2336 #endif
2337 2640
2338 if (_fi.Attrib_Defined) 2641
2642#ifdef Z7_USE_SECURITY_CODE
2643HRESULT CArchiveExtractCallback::SetSecurityInfo(UInt32 indexInArc, const FString &path) const
2644{
2645 if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps)
2339 { 2646 {
2340 // const AString s = GetAnsiString(_diskFilePath); 2647 const void *data;
2341 // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); 2648 UInt32 dataSize;
2342 bool res = SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib); 2649 UInt32 propType;
2343 if (!res) 2650 _arc->GetRawProps->GetRawProp(indexInArc, kpidNtSecure, &data, &dataSize, &propType);
2651 if (dataSize != 0)
2344 { 2652 {
2345 // do we need error message here in Windows and in posix? 2653 if (propType != NPropDataType::kRaw)
2346 SendMessageError_with_LastError("Cannot set file attribute", _diskFilePath); 2654 return E_FAIL;
2655 if (CheckNtSecure((const Byte *)data, dataSize))
2656 {
2657 SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION;
2658 if (_saclEnabled)
2659 securInfo |= SACL_SECURITY_INFORMATION;
2660 // if (!
2661 ::SetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data));
2662 {
2663 // RINOK(SendMessageError_with_LastError("SetFileSecurity FAILS", path))
2664 }
2665 }
2347 } 2666 }
2348 } 2667 }
2668 return S_OK;
2349} 2669}
2670#endif // Z7_USE_SECURITY_CODE
2350 2671
2351 2672
2352Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) 2673Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
@@ -2384,27 +2705,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
2384 2705
2385 RINOK(CloseReparseAndFile()) 2706 RINOK(CloseReparseAndFile())
2386 2707
2387 #ifdef Z7_USE_SECURITY_CODE 2708#ifdef Z7_USE_SECURITY_CODE
2388 if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) 2709 RINOK(SetSecurityInfo(_index, _diskFilePath))
2389 { 2710#endif
2390 const void *data;
2391 UInt32 dataSize;
2392 UInt32 propType;
2393 _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType);
2394 if (dataSize != 0)
2395 {
2396 if (propType != NPropDataType::kRaw)
2397 return E_FAIL;
2398 if (CheckNtSecure((const Byte *)data, dataSize))
2399 {
2400 SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION;
2401 if (_saclEnabled)
2402 securInfo |= SACL_SECURITY_INFORMATION;
2403 ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data));
2404 }
2405 }
2406 }
2407 #endif // Z7_USE_SECURITY_CODE
2408 2711
2409 if (!_curSize_Defined) 2712 if (!_curSize_Defined)
2410 GetUnpackSize(); 2713 GetUnpackSize();
@@ -2648,15 +2951,58 @@ void CDirPathSortPair::SetNumSlashes(const FChar *s)
2648} 2951}
2649 2952
2650 2953
2651bool CDirPathTime::SetDirTime() const 2954bool CFiTimesCAM::SetDirTime_to_FS(CFSTR path) const
2652{ 2955{
2653 return NDir::SetDirTime(Path, 2956 // it's same function for dir and for file
2957 return NDir::SetDirTime(path,
2654 CTime_Defined ? &CTime : NULL, 2958 CTime_Defined ? &CTime : NULL,
2655 ATime_Defined ? &ATime : NULL, 2959 ATime_Defined ? &ATime : NULL,
2656 MTime_Defined ? &MTime : NULL); 2960 MTime_Defined ? &MTime : NULL);
2657} 2961}
2658 2962
2659 2963
2964#ifdef SUPPORT_LINKS
2965
2966bool CFiTimesCAM::SetLinkFileTime_to_FS(CFSTR path) const
2967{
2968 // it's same function for dir and for file
2969 return NDir::SetLinkFileTime(path,
2970 CTime_Defined ? &CTime : NULL,
2971 ATime_Defined ? &ATime : NULL,
2972 MTime_Defined ? &MTime : NULL);
2973}
2974
2975HRESULT CArchiveExtractCallback::SetPostLinks() const
2976{
2977 FOR_VECTOR (i, _postLinks)
2978 {
2979 const CPostLink &link = _postLinks[i];
2980 bool linkWasSet = false;
2981 RINOK(SetLink2(*this, link, linkWasSet))
2982 if (linkWasSet)
2983 {
2984#ifdef _WIN32
2985 // Linux now doesn't support permissions for symlinks
2986 SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this);
2987#endif
2988
2989 CFiTimesCAM pt;
2990 GetFiTimesCAM(link.item_FileInfo, pt, *_arc);
2991 if (pt.IsSomeTimeDefined())
2992 pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from);
2993
2994#ifdef Z7_USE_SECURITY_CODE
2995 // we set security information after timestamps setting
2996 RINOK(SetSecurityInfo(link.Index_in_Arc, link.fullProcessedPath_from))
2997#endif
2998 }
2999 }
3000 return S_OK;
3001}
3002
3003#endif
3004
3005
2660HRESULT CArchiveExtractCallback::SetDirsTimes() 3006HRESULT CArchiveExtractCallback::SetDirsTimes()
2661{ 3007{
2662 if (!_arc) 3008 if (!_arc)
@@ -2680,7 +3026,7 @@ HRESULT CArchiveExtractCallback::SetDirsTimes()
2680 for (i = 0; i < pairs.Size(); i++) 3026 for (i = 0; i < pairs.Size(); i++)
2681 { 3027 {
2682 const CDirPathTime &dpt = _extractedFolders[pairs[i].Index]; 3028 const CDirPathTime &dpt = _extractedFolders[pairs[i].Index];
2683 if (!dpt.SetDirTime()) 3029 if (!dpt.SetDirTime_to_FS_2())
2684 { 3030 {
2685 // result = E_FAIL; 3031 // result = E_FAIL;
2686 // do we need error message here in Windows and in posix? 3032 // do we need error message here in Windows and in posix?
@@ -2712,10 +3058,20 @@ HRESULT CArchiveExtractCallback::SetDirsTimes()
2712 3058
2713HRESULT CArchiveExtractCallback::CloseArc() 3059HRESULT CArchiveExtractCallback::CloseArc()
2714{ 3060{
3061 // we call CloseReparseAndFile() here because we can have non-closed file in some cases?
2715 HRESULT res = CloseReparseAndFile(); 3062 HRESULT res = CloseReparseAndFile();
2716 const HRESULT res2 = SetDirsTimes(); 3063#ifdef SUPPORT_LINKS
2717 if (res == S_OK) 3064 {
2718 res = res2; 3065 const HRESULT res2 = SetPostLinks();
3066 if (res == S_OK)
3067 res = res2;
3068 }
3069#endif
3070 {
3071 const HRESULT res2 = SetDirsTimes();
3072 if (res == S_OK)
3073 res = res2;
3074 }
2719 _arc = NULL; 3075 _arc = NULL;
2720 return res; 3076 return res;
2721} 3077}
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
index 7eb2f67..3c62763 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -52,7 +52,6 @@ struct CExtractNtOptions
52{ 52{
53 CBoolPair NtSecurity; 53 CBoolPair NtSecurity;
54 CBoolPair SymLinks; 54 CBoolPair SymLinks;
55 CBoolPair SymLinks_AllowDangerous;
56 CBoolPair HardLinks; 55 CBoolPair HardLinks;
57 CBoolPair AltStreams; 56 CBoolPair AltStreams;
58 bool ReplaceColonForAltStream; 57 bool ReplaceColonForAltStream;
@@ -66,6 +65,8 @@ struct CExtractNtOptions
66 bool PreserveATime; 65 bool PreserveATime;
67 bool OpenShareForWrite; 66 bool OpenShareForWrite;
68 67
68 unsigned SymLinks_DangerousLevel;
69
69 UInt64 MemLimit; 70 UInt64 MemLimit;
70 71
71 CExtractNtOptions(): 72 CExtractNtOptions():
@@ -74,10 +75,10 @@ struct CExtractNtOptions
74 ExtractOwner(false), 75 ExtractOwner(false),
75 PreserveATime(false), 76 PreserveATime(false),
76 OpenShareForWrite(false), 77 OpenShareForWrite(false),
78 SymLinks_DangerousLevel(5),
77 MemLimit((UInt64)(Int64)-1) 79 MemLimit((UInt64)(Int64)-1)
78 { 80 {
79 SymLinks.Val = true; 81 SymLinks.Val = true;
80 SymLinks_AllowDangerous.Val = false;
81 HardLinks.Val = true; 82 HardLinks.Val = true;
82 AltStreams.Val = true; 83 AltStreams.Val = true;
83 84
@@ -90,25 +91,10 @@ struct CExtractNtOptions
90 } 91 }
91}; 92};
92 93
93#ifndef Z7_SFX
94
95Z7_CLASS_IMP_COM_1(
96 CGetProp
97 , IGetProp
98)
99public:
100 UInt32 IndexInArc;
101 const CArc *Arc;
102 // UString Name; // relative path
103};
104
105#endif
106 94
107#ifndef Z7_SFX 95#ifndef Z7_SFX
108#ifndef UNDER_CE 96#ifndef UNDER_CE
109
110#define SUPPORT_LINKS 97#define SUPPORT_LINKS
111
112#endif 98#endif
113#endif 99#endif
114 100
@@ -181,53 +167,79 @@ struct CFiTimesCAM
181 ATime_Defined | 167 ATime_Defined |
182 MTime_Defined; 168 MTime_Defined;
183 } 169 }
170 bool SetDirTime_to_FS(CFSTR path) const;
171#ifdef SUPPORT_LINKS
172 bool SetLinkFileTime_to_FS(CFSTR path) const;
173#endif
184}; 174};
185 175
186struct CDirPathTime: public CFiTimesCAM 176struct CDirPathTime: public CFiTimesCAM
187{ 177{
188 FString Path; 178 FString Path;
189 179
190 bool SetDirTime() const; 180 bool SetDirTime_to_FS_2() const { return SetDirTime_to_FS(Path); }
191}; 181};
192 182
193 183
194#ifdef SUPPORT_LINKS 184#ifdef SUPPORT_LINKS
195 185
186enum ELinkType
187{
188 k_LinkType_HardLink,
189 k_LinkType_PureSymLink,
190 k_LinkType_Junction,
191 k_LinkType_WSL
192 // , k_LinkType_CopyLink;
193};
194
195
196struct CLinkInfo 196struct CLinkInfo
197{ 197{
198 // bool isCopyLink; 198 ELinkType LinkType;
199 bool isHardLink;
200 bool isJunction;
201 bool isRelative; 199 bool isRelative;
202 bool isWSL; 200 // if (isRelative == false), then (LinkPath) is relative to root folder of archive
203 UString linkPath; 201 // if (isRelative == true ), then (LinkPath) is relative to current item
202 bool isWindowsPath;
203 UString LinkPath;
204
205 bool Is_HardLink() const { return LinkType == k_LinkType_HardLink; }
206 bool Is_AnySymLink() const { return LinkType != k_LinkType_HardLink; }
204 207
205 bool IsSymLink() const { return !isHardLink; } 208 bool Is_WSL() const { return LinkType == k_LinkType_WSL; }
206 209
207 CLinkInfo(): 210 CLinkInfo():
208 // IsCopyLink(false), 211 LinkType(k_LinkType_PureSymLink),
209 isHardLink(false),
210 isJunction(false),
211 isRelative(false), 212 isRelative(false),
212 isWSL(false) 213 isWindowsPath(false)
213 {} 214 {}
214 215
215 void Clear() 216 void Clear()
216 { 217 {
217 // IsCopyLink = false; 218 LinkType = k_LinkType_PureSymLink;
218 isHardLink = false;
219 isJunction = false;
220 isRelative = false; 219 isRelative = false;
221 isWSL = false; 220 isWindowsPath = false;
222 linkPath.Empty(); 221 LinkPath.Empty();
223 } 222 }
224 223
225 bool Parse(const Byte *data, size_t dataSize, bool isLinuxData); 224 bool Parse_from_WindowsReparseData(const Byte *data, size_t dataSize);
225 bool Parse_from_LinuxData(const Byte *data, size_t dataSize);
226 void Normalize_to_RelativeSafe(UStringVector &removePathParts);
227private:
228 void Remove_AbsPathPrefixes();
226}; 229};
227 230
228#endif // SUPPORT_LINKS 231#endif // SUPPORT_LINKS
229 232
230 233
234
235struct CProcessedFileInfo
236{
237 CArcTime CTime;
238 CArcTime ATime;
239 CArcTime MTime;
240 UInt32 Attrib;
241 bool Attrib_Defined;
242
231#ifndef _WIN32 243#ifndef _WIN32
232 244
233struct COwnerInfo 245struct COwnerInfo
@@ -244,7 +256,75 @@ struct COwnerInfo
244 } 256 }
245}; 257};
246 258
259 COwnerInfo Owner;
260 COwnerInfo Group;
261#endif
262
263 void Clear()
264 {
265#ifndef _WIN32
266 Attrib_Defined = false;
267 Owner.Clear();
247#endif 268#endif
269 }
270
271 bool IsReparse() const
272 {
273 return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
274 }
275
276 bool IsLinuxSymLink() const
277 {
278 return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16));
279 }
280
281 void SetFromPosixAttrib(UInt32 a)
282 {
283 // here we set only part of combined attribute required by SetFileAttrib() call
284 #ifdef _WIN32
285 // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute.
286 Attrib = MY_LIN_S_ISDIR(a) ?
287 FILE_ATTRIBUTE_DIRECTORY :
288 FILE_ATTRIBUTE_ARCHIVE;
289 if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
290 Attrib |= FILE_ATTRIBUTE_READONLY;
291 // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink()
292 a &= MY_LIN_S_IFMT;
293 if (a == MY_LIN_S_IFLNK)
294 Attrib |= (a << 16);
295 #else
296 Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
297 #endif
298 Attrib_Defined = true;
299 }
300};
301
302
303#ifdef SUPPORT_LINKS
304
305struct CPostLink
306{
307 UInt32 Index_in_Arc;
308 bool item_IsDir; // _item.IsDir
309 UString item_Path; // _item.Path;
310 UStringVector item_PathParts; // _item.PathParts;
311 CProcessedFileInfo item_FileInfo; // _fi
312 FString fullProcessedPath_from; // full file path in FS
313 CLinkInfo LinkInfo;
314};
315
316/*
317struct CPostLinks
318{
319 void Clear()
320 {
321 Links.Clear();
322 }
323};
324*/
325
326#endif // SUPPORT_LINKS
327
248 328
249 329
250class CArchiveExtractCallback Z7_final: 330class CArchiveExtractCallback Z7_final:
@@ -282,114 +362,78 @@ class CArchiveExtractCallback Z7_final:
282 Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback) 362 Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback)
283#endif 363#endif
284 364
365 // bool Write_CTime;
366 // bool Write_ATime;
367 // bool Write_MTime;
368 bool _stdOutMode;
369 bool _testMode;
370 bool _removePartsForAltStreams;
371public:
372 bool Is_elimPrefix_Mode;
373private:
374
285 const CArc *_arc; 375 const CArc *_arc;
376public:
286 CExtractNtOptions _ntOptions; 377 CExtractNtOptions _ntOptions;
287 378private:
379 bool _encrypted;
288 bool _isSplit; 380 bool _isSplit;
381 bool _curSize_Defined;
382 bool _fileLength_WasSet;
289 383
384 bool _isRenamed;
290 bool _extractMode; 385 bool _extractMode;
291 386 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX.
292 bool Write_CTime; 387 // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file.
293 bool Write_ATime;
294 bool Write_MTime;
295 bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
296
297 bool _encrypted;
298
299 // bool _is_SymLink_in_Data;
300 bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX
301
302 bool _needSetAttrib; 388 bool _needSetAttrib;
303 bool _isSymLinkCreated; 389 bool _isSymLinkCreated;
304 bool _itemFailure; 390 bool _itemFailure;
305
306 bool _some_pathParts_wereRemoved; 391 bool _some_pathParts_wereRemoved;
307public:
308 bool Is_elimPrefix_Mode;
309
310private:
311 bool _curSize_Defined;
312 bool _fileLength_WasSet;
313 392
314 bool _removePartsForAltStreams;
315
316 bool _stdOutMode;
317 bool _testMode;
318 bool _multiArchives; 393 bool _multiArchives;
394 bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
395#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
396 bool _saclEnabled;
397#endif
319 398
320 NExtract::NPathMode::EEnum _pathMode; 399 NExtract::NPathMode::EEnum _pathMode;
321 NExtract::NOverwriteMode::EEnum _overwriteMode; 400 NExtract::NOverwriteMode::EEnum _overwriteMode;
322 401
323 const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
324 CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2; 402 CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
403 const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
325 // CMyComPtr<ICompressProgressInfo> _compressProgress; 404 // CMyComPtr<ICompressProgressInfo> _compressProgress;
326 // CMyComPtr<IArchiveExtractCallbackMessage2> _callbackMessage; 405 // CMyComPtr<IArchiveExtractCallbackMessage2> _callbackMessage;
327 CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2; 406 CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
328 CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword; 407 CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
329 408
330 FString _dirPathPrefix; 409 FString _dirPathPrefix;
410public:
331 FString _dirPathPrefix_Full; 411 FString _dirPathPrefix_Full;
412private:
332 413
333 #ifndef Z7_SFX 414 #ifndef Z7_SFX
334 415
335 CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback; 416 CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
336 CGetProp *GetProp_Spec;
337 CMyComPtr<IGetProp> GetProp;
338 CMyComPtr<IArchiveRequestMemoryUseCallback> _requestMemoryUseCallback; 417 CMyComPtr<IArchiveRequestMemoryUseCallback> _requestMemoryUseCallback;
339 418
340 #endif 419 #endif
341 420
342 CReadArcItem _item; 421 CReadArcItem _item;
343 FString _diskFilePath; 422 FString _diskFilePath;
344 UInt64 _position;
345
346 struct CProcessedFileInfo
347 {
348 CArcTime CTime;
349 CArcTime ATime;
350 CArcTime MTime;
351 UInt32 Attrib;
352 bool Attrib_Defined;
353 423
354 #ifndef _WIN32 424 CProcessedFileInfo _fi;
355 COwnerInfo Owner;
356 COwnerInfo Group;
357 #endif
358
359 bool IsReparse() const
360 {
361 return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
362 }
363
364 bool IsLinuxSymLink() const
365 {
366 return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16));
367 }
368 425
369 void SetFromPosixAttrib(UInt32 a) 426 UInt64 _position;
370 {
371 // here we set only part of combined attribute required by SetFileAttrib() call
372 #ifdef _WIN32
373 // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute.
374 Attrib = MY_LIN_S_ISDIR(a) ?
375 FILE_ATTRIBUTE_DIRECTORY :
376 FILE_ATTRIBUTE_ARCHIVE;
377 if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
378 Attrib |= FILE_ATTRIBUTE_READONLY;
379 // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink()
380 a &= MY_LIN_S_IFMT;
381 if (a == MY_LIN_S_IFLNK)
382 Attrib |= (a << 16);
383 #else
384 Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
385 #endif
386 Attrib_Defined = true;
387 }
388 } _fi;
389
390 UInt32 _index;
391 UInt64 _curSize; 427 UInt64 _curSize;
392 UInt64 _fileLength_that_WasSet; 428 UInt64 _fileLength_that_WasSet;
429 UInt32 _index;
430
431// #ifdef SUPPORT_ALT_STREAMS
432#if defined(_WIN32) && !defined(UNDER_CE)
433 DWORD _altStream_NeedRestore_AttribVal;
434 FString _altStream_NeedRestore_Attrib_for_parentFsPath;
435#endif
436// #endif
393 437
394 COutFileStream *_outFileStreamSpec; 438 COutFileStream *_outFileStreamSpec;
395 CMyComPtr<ISequentialOutStream> _outFileStream; 439 CMyComPtr<ISequentialOutStream> _outFileStream;
@@ -398,9 +442,7 @@ private:
398 CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec; 442 CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec;
399 CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream; 443 CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream;
400 444
401
402 #ifndef Z7_SFX 445 #ifndef Z7_SFX
403
404 COutStreamWithHash *_hashStreamSpec; 446 COutStreamWithHash *_hashStreamSpec;
405 CMyComPtr<ISequentialOutStream> _hashStream; 447 CMyComPtr<ISequentialOutStream> _hashStream;
406 bool _hashStreamWasUsed; 448 bool _hashStreamWasUsed;
@@ -411,11 +453,9 @@ private:
411 453
412 UStringVector _removePathParts; 454 UStringVector _removePathParts;
413 455
414 CMyComPtr<ICompressProgressInfo> _localProgress;
415 UInt64 _packTotal; 456 UInt64 _packTotal;
416
417 UInt64 _progressTotal; 457 UInt64 _progressTotal;
418 bool _progressTotal_Defined; 458 // bool _progressTotal_Defined;
419 459
420 CObjectVector<CDirPathTime> _extractedFolders; 460 CObjectVector<CDirPathTime> _extractedFolders;
421 461
@@ -423,31 +463,28 @@ private:
423 // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks; 463 // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks;
424 #endif 464 #endif
425 465
426 #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) 466 void CreateComplexDirectory(
427 bool _saclEnabled; 467 const UStringVector &dirPathParts, bool isFinal, FString &fullPath);
428 #endif
429
430 void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
431 HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); 468 HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft);
432 HRESULT GetUnpackSize(); 469 HRESULT GetUnpackSize();
433 470
434 FString Hash_GetFullFilePath(); 471 FString Hash_GetFullFilePath();
435 472
436 void SetAttrib(); 473 void SetAttrib() const;
437 474
438public: 475public:
439 HRESULT SendMessageError(const char *message, const FString &path); 476 HRESULT SendMessageError(const char *message, const FString &path) const;
440 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path); 477 HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const;
441 HRESULT SendMessageError_with_LastError(const char *message, const FString &path); 478 HRESULT SendMessageError_with_LastError(const char *message, const FString &path) const;
442 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); 479 HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const;
480 HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2) const;
443 481
444public: 482#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
445 #if defined(_WIN32) && !defined(UNDER_CE)
446 NExtract::NZoneIdMode::EEnum ZoneMode; 483 NExtract::NZoneIdMode::EEnum ZoneMode;
447 CByteBuffer ZoneBuf; 484 CByteBuffer ZoneBuf;
448 #endif 485#endif
449 486
450 CLocalProgress *LocalProgressSpec; 487 CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> LocalProgressSpec;
451 488
452 UInt64 NumFolders; 489 UInt64 NumFolders;
453 UInt64 NumFiles; 490 UInt64 NumFiles;
@@ -468,11 +505,11 @@ public:
468 _multiArchives = multiArchives; 505 _multiArchives = multiArchives;
469 _pathMode = pathMode; 506 _pathMode = pathMode;
470 _overwriteMode = overwriteMode; 507 _overwriteMode = overwriteMode;
471 #if defined(_WIN32) && !defined(UNDER_CE) 508#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
472 ZoneMode = zoneMode; 509 ZoneMode = zoneMode;
473 #else 510#else
474 UNUSED_VAR(zoneMode) 511 UNUSED_VAR(zoneMode)
475 #endif 512#endif
476 _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes; 513 _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;
477 NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; 514 NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
478 } 515 }
@@ -503,23 +540,32 @@ public:
503 UInt64 packSize); 540 UInt64 packSize);
504 541
505 542
506 #ifdef SUPPORT_LINKS 543#ifdef SUPPORT_LINKS
507 544
508private: 545private:
509 CHardLinks _hardLinks; 546 CHardLinks _hardLinks;
547 CObjectVector<CPostLink> _postLinks;
510 CLinkInfo _link; 548 CLinkInfo _link;
549 // const void *NtReparse_Data;
550 // UInt32 NtReparse_Size;
511 551
512 // FString _copyFile_Path; 552 // FString _copyFile_Path;
513 // HRESULT MyCopyFile(ISequentialOutStream *outStream); 553 // HRESULT MyCopyFile(ISequentialOutStream *outStream);
514 HRESULT Link(const FString &fullProcessedPath);
515 HRESULT ReadLink(); 554 HRESULT ReadLink();
555 HRESULT SetLink(
556 const FString &fullProcessedPath_from,
557 const CLinkInfo &linkInfo,
558 bool &linkWasSet);
559 HRESULT SetPostLinks() const;
516 560
517public: 561public:
518 // call PrepareHardLinks() after Init() 562 HRESULT CreateHardLink2(const FString &newFilePath,
563 const FString &existFilePath, bool &link_was_Created) const;
564 HRESULT DeleteLinkFileAlways_or_RemoveEmptyDir(const FString &path, bool checkThatFileIsEmpty) const;
519 HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items 565 HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items
566#endif
520 567
521 #endif 568private:
522
523 569
524 #ifdef SUPPORT_ALT_STREAMS 570 #ifdef SUPPORT_ALT_STREAMS
525 CObjectVector<CIndexToPathPair> _renamedFiles; 571 CObjectVector<CIndexToPathPair> _renamedFiles;
@@ -527,6 +573,7 @@ public:
527 573
528 // call it after Init() 574 // call it after Init()
529 575
576public:
530 #ifndef Z7_SFX 577 #ifndef Z7_SFX
531 void SetBaseParentFolderIndex(UInt32 indexInArc) 578 void SetBaseParentFolderIndex(UInt32 indexInArc)
532 { 579 {
@@ -548,28 +595,16 @@ private:
548 595
549 HRESULT Read_fi_Props(); 596 HRESULT Read_fi_Props();
550 void CorrectPathParts(); 597 void CorrectPathParts();
551 void GetFiTimesCAM(CFiTimesCAM &pt);
552 void CreateFolders(); 598 void CreateFolders();
553 599
554 bool _isRenamed;
555 HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit); 600 HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit);
556 HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit); 601 HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit);
557 HRESULT GetItem(UInt32 index); 602 HRESULT GetItem(UInt32 index);
558 603
559 HRESULT CloseFile(); 604 HRESULT CloseFile();
560 HRESULT CloseReparseAndFile(); 605 HRESULT CloseReparseAndFile();
561 HRESULT CloseReparseAndFile2();
562 HRESULT SetDirsTimes(); 606 HRESULT SetDirsTimes();
563 607 HRESULT SetSecurityInfo(UInt32 indexInArc, const FString &path) const;
564 const void *NtReparse_Data;
565 UInt32 NtReparse_Size;
566
567 #ifdef SUPPORT_LINKS
568 HRESULT SetFromLinkPath(
569 const FString &fullProcessedPath,
570 const CLinkInfo &linkInfo,
571 bool &linkWasSet);
572 #endif
573}; 608};
574 609
575 610
@@ -599,7 +634,8 @@ struct CArchiveExtractCallback_Closer
599 634
600bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); 635bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
601 636
602void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf); 637bool Is_ZoneId_StreamName(const wchar_t *s);
638void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf);
603bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf); 639bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf);
604 640
605#endif 641#endif
diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp
index e1ca846..eb24e7f 100644
--- a/CPP/7zip/UI/Common/Bench.cpp
+++ b/CPP/7zip/UI/Common/Bench.cpp
@@ -871,14 +871,27 @@ struct CAffinityMode
871 unsigned NumCoreThreads; 871 unsigned NumCoreThreads;
872 unsigned NumCores; 872 unsigned NumCores;
873 // unsigned DivideNum; 873 // unsigned DivideNum;
874
875#ifdef _WIN32
876 unsigned NumGroups;
877#endif
878
874 UInt32 Sizes[NUM_CPU_LEVELS_MAX]; 879 UInt32 Sizes[NUM_CPU_LEVELS_MAX];
875 880
876 void SetLevels(unsigned numCores, unsigned numCoreThreads); 881 void SetLevels(unsigned numCores, unsigned numCoreThreads);
877 DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; 882 DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const;
878 bool NeedAffinity() const { return NumBundleThreads != 0; } 883 bool NeedAffinity() const { return NumBundleThreads != 0; }
879 884
885#ifdef _WIN32
886 bool NeedGroupsMode() const { return NumGroups > 1; }
887#endif
888
880 WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const 889 WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const
881 { 890 {
891#ifdef _WIN32
892 if (NeedGroupsMode()) // we need fix for bundleIndex usage
893 return thread.Create_With_Group(startAddress, parameter, bundleIndex % NumGroups);
894#endif
882 if (NeedAffinity()) 895 if (NeedAffinity())
883 { 896 {
884 CCpuSet cpuSet; 897 CCpuSet cpuSet;
@@ -892,6 +905,9 @@ struct CAffinityMode
892 NumBundleThreads(0), 905 NumBundleThreads(0),
893 NumLevels(0), 906 NumLevels(0),
894 NumCoreThreads(1) 907 NumCoreThreads(1)
908#ifdef _WIN32
909 , NumGroups(0)
910#endif
895 // DivideNum(1) 911 // DivideNum(1)
896 {} 912 {}
897}; 913};
@@ -1288,22 +1304,28 @@ HRESULT CEncoderInfo::Generate()
1288 if (scp) 1304 if (scp)
1289 { 1305 {
1290 const UInt64 reduceSize = kBufferSize; 1306 const UInt64 reduceSize = kBufferSize;
1291 1307 /* in posix : new thread uses same affinity as parent thread,
1292 /* in posix new thread uses same affinity as parent thread,
1293 so we don't need to send affinity to coder in posix */ 1308 so we don't need to send affinity to coder in posix */
1294 UInt64 affMask; 1309 UInt64 affMask = 0;
1295 #if !defined(Z7_ST) && defined(_WIN32) 1310 UInt32 affinityGroup = (UInt32)(Int32)-1;
1311 // UInt64 affinityInGroup = 0;
1312#if !defined(Z7_ST) && defined(_WIN32)
1296 { 1313 {
1297 CCpuSet cpuSet; 1314 CCpuSet cpuSet;
1298 affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet); 1315 if (AffinityMode.NeedGroupsMode()) // we need fix for affinityInGroup also
1316 affinityGroup = EncoderIndex % AffinityMode.NumGroups;
1317 else
1318 affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet);
1299 } 1319 }
1300 #else 1320#endif
1301 affMask = 0; 1321 // affMask <<= 3; // debug line: to test no affinity in coder
1302 #endif 1322 // affMask = 0; // for debug
1303 // affMask <<= 3; // debug line: to test no affinity in coder; 1323 // affinityGroup = 0; // for debug
1304 // affMask = 0; 1324 // affinityInGroup = 1; // for debug
1305 1325 RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize,
1306 RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL))) 1326 affMask != 0 ? &affMask : NULL,
1327 affinityGroup != (UInt32)(Int32)-1 ? &affinityGroup : NULL,
1328 /* affinityInGroup != 0 ? &affinityInGroup : */ NULL))
1307 } 1329 }
1308 else 1330 else
1309 { 1331 {
@@ -2298,6 +2320,28 @@ HRESULT CCrcInfo_Base::Generate(const Byte *data, size_t size)
2298} 2320}
2299 2321
2300 2322
2323#if 1
2324#define HashUpdate(hf, data, size) hf->Update(data, size)
2325#else
2326// for debug:
2327static void HashUpdate(IHasher *hf, const void *data, UInt32 size)
2328{
2329 for (;;)
2330 {
2331 if (size == 0)
2332 return;
2333 UInt32 size2 = (size * 0x85EBCA87) % size / 8;
2334 // UInt32 size2 = size / 2;
2335 if (size2 == 0)
2336 size2 = 1;
2337 hf->Update(data, size2);
2338 data = (const void *)((const Byte *)data + size2);
2339 size -= size2;
2340 }
2341}
2342#endif
2343
2344
2301HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations, 2345HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations,
2302 const UInt32 *checkSum, IHasher *hf, 2346 const UInt32 *checkSum, IHasher *hf,
2303 IBenchPrintCallback *callback) 2347 IBenchPrintCallback *callback)
@@ -2328,7 +2372,7 @@ HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations,
2328 const size_t rem = size - pos; 2372 const size_t rem = size - pos;
2329 const UInt32 kStep = ((UInt32)1 << 31); 2373 const UInt32 kStep = ((UInt32)1 << 31);
2330 const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep; 2374 const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep;
2331 hf->Update(buf + pos, curSize); 2375 HashUpdate(hf, buf + pos, curSize);
2332 pos += curSize; 2376 pos += curSize;
2333 } 2377 }
2334 while (pos != size); 2378 while (pos != size);
@@ -2742,14 +2786,20 @@ static const CBenchHash g_Hash[] =
2742 { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" }, 2786 { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" },
2743 { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" }, 2787 { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" },
2744 { 10, 256, 0x41b901d1, "CRC64" }, 2788 { 10, 256, 0x41b901d1, "CRC64" },
2745 { 10, 64, 0x43eac94f, "XXH64" }, 2789 { 5, 64, 0x43eac94f, "XXH64" },
2746 2790 { 2, 2340, 0x3398a904, "MD5" },
2747 { 10, 5100, 0x7913ba03, "SHA256:1" }, 2791 { 10, 2340, 0xff769021, "SHA1:1" },
2748 { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" },
2749
2750 { 10, 2340, 0xff769021, "SHA1:1" },
2751 { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" }, 2792 { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" },
2752 2793 { 10, 5100, 0x7913ba03, "SHA256:1" },
2794 { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" },
2795 { 5, 3200, 0xe7aeb394, "SHA512:1" },
2796 { 2, CMPLX((40 * 4 + 1) * 4 + 4), 0xe7aeb394, "SHA512:2" },
2797 // { 10, 3428, 0x1cc99b18, "SHAKE128" },
2798 // { 10, 4235, 0x74eaddc3, "SHAKE256" },
2799 // { 10, 4000, 0xdf3e6863, "SHA3-224" },
2800 { 5, 4200, 0xcecac10d, "SHA3-256" },
2801 // { 10, 5538, 0x4e5d9163, "SHA3-384" },
2802 // { 10, 8000, 0x96a58289, "SHA3-512" },
2753 { 2, 4096, 0x85189d02, "BLAKE2sp:1" }, 2803 { 2, 4096, 0x85189d02, "BLAKE2sp:1" },
2754 { 2, 1024, 0x85189d02, "BLAKE2sp:2" }, // sse2-way4-fast 2804 { 2, 1024, 0x85189d02, "BLAKE2sp:2" }, // sse2-way4-fast
2755 { 2, 512, 0x85189d02, "BLAKE2sp:3" } // avx2-way8-fast 2805 { 2, 512, 0x85189d02, "BLAKE2sp:3" } // avx2-way8-fast
@@ -2934,7 +2984,7 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
2934{ 2984{
2935 AString s; 2985 AString s;
2936 // s.Add_UInt32(ti.numProcessThreads); 2986 // s.Add_UInt32(ti.numProcessThreads);
2937 unsigned numSysThreads = ti.GetNumSystemThreads(); 2987 const unsigned numSysThreads = ti.GetNumSystemThreads();
2938 if (ti.GetNumProcessThreads() != numSysThreads) 2988 if (ti.GetNumProcessThreads() != numSysThreads)
2939 { 2989 {
2940 // if (ti.numProcessThreads != ti.numSysThreads) 2990 // if (ti.numProcessThreads != ti.numSysThreads)
@@ -2964,6 +3014,35 @@ AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
2964 } 3014 }
2965 #endif 3015 #endif
2966 } 3016 }
3017#ifdef _WIN32
3018 if (ti.Groups.GroupSizes.Size() > 1 ||
3019 (ti.Groups.GroupSizes.Size() == 1
3020 && ti.Groups.NumThreadsTotal != numSysThreads))
3021 {
3022 s += " : ";
3023 s.Add_UInt32(ti.Groups.GroupSizes.Size());
3024 s += " groups : ";
3025 if (ti.Groups.NumThreadsTotal == numSysThreads)
3026 {
3027 s.Add_UInt32(ti.Groups.NumThreadsTotal);
3028 s += " c : ";
3029 }
3030 UInt32 minSize, maxSize;
3031 ti.Groups.Get_GroupSize_Min_Max(minSize, maxSize);
3032 if (minSize == maxSize)
3033 {
3034 s.Add_UInt32(ti.Groups.GroupSizes[0]);
3035 s += " c/g";
3036 }
3037 else
3038 FOR_VECTOR (i, ti.Groups.GroupSizes)
3039 {
3040 if (i != 0)
3041 s.Add_Char(' ');
3042 s.Add_UInt32(ti.Groups.GroupSizes[i]);
3043 }
3044 }
3045#endif
2967 return s; 3046 return s;
2968} 3047}
2969 3048
@@ -3687,7 +3766,7 @@ HRESULT Bench(
3687 return E_FAIL; 3766 return E_FAIL;
3688 3767
3689 UInt32 numCPUs = 1; 3768 UInt32 numCPUs = 1;
3690 UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29; 3769 size_t ramSize = (size_t)sizeof(size_t) << 29;
3691 3770
3692 NSystem::CProcessAffinity threadsInfo; 3771 NSystem::CProcessAffinity threadsInfo;
3693 threadsInfo.InitST(); 3772 threadsInfo.InitST();
@@ -3725,9 +3804,13 @@ HRESULT Bench(
3725 UInt64 complexInCommands = kComplexInCommands; 3804 UInt64 complexInCommands = kComplexInCommands;
3726 UInt32 numThreads_Start = 1; 3805 UInt32 numThreads_Start = 1;
3727 3806
3728 #ifndef Z7_ST 3807#ifndef Z7_ST
3729 CAffinityMode affinityMode; 3808 CAffinityMode affinityMode;
3730 #endif 3809#ifdef _WIN32
3810 if (threadsInfo.IsGroupMode && threadsInfo.Groups.GroupSizes.Size() > 1)
3811 affinityMode.NumGroups = threadsInfo.Groups.GroupSizes.Size();
3812#endif
3813#endif
3731 3814
3732 3815
3733 COneMethodInfo method; 3816 COneMethodInfo method;
@@ -4580,6 +4663,8 @@ HRESULT Bench(
4580 4663
4581 if (!dictIsDefined && !onlyHashBench) 4664 if (!dictIsDefined && !onlyHashBench)
4582 { 4665 {
4666 // we use dicSizeLog and dicSizeLog_Main for data size.
4667 // also we use it to reduce dictionary size of LZMA encoder via NCoderPropID::kReduceSize.
4583 const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25); 4668 const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25);
4584 unsigned dicSizeLog = dicSizeLog_Main; 4669 unsigned dicSizeLog = dicSizeLog_Main;
4585 4670
@@ -4831,7 +4916,7 @@ HRESULT Bench(
4831 if (AreSameMethodNames(benchMethod, methodName)) 4916 if (AreSameMethodNames(benchMethod, methodName))
4832 { 4917 {
4833 if (benchProps.IsEmpty() 4918 if (benchProps.IsEmpty()
4834 || (benchProps == "x5" && method.PropsString.IsEmpty()) 4919 || (benchProps.IsEqualTo("x5") && method.PropsString.IsEmpty())
4835 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) 4920 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
4836 { 4921 {
4837 callback.BenchProps.EncComplex = h.EncComplex; 4922 callback.BenchProps.EncComplex = h.EncComplex;
diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp
index 0758547..cada2e6 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -671,7 +671,7 @@ static HRESULT EnumerateForItem(
671 } 671 }
672 672
673 #if defined(_WIN32) 673 #if defined(_WIN32)
674 if (needAltStreams && dirItems.ScanAltStreams) 674 if (needAltStreams && dirItems.ScanAltStreams && !fi.IsAltStream)
675 { 675 {
676 RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, 676 RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
677 phyPrefix + fi.Name, // with (fi.Name) 677 phyPrefix + fi.Name, // with (fi.Name)
@@ -929,7 +929,7 @@ static HRESULT EnumerateDirItems(
929 } 929 }
930 930
931 #if defined(_WIN32) 931 #if defined(_WIN32)
932 if (needAltStreams && dirItems.ScanAltStreams) 932 if (needAltStreams && dirItems.ScanAltStreams && !fi.IsAltStream)
933 { 933 {
934 UStringVector pathParts; 934 UStringVector pathParts;
935 pathParts.Add(fs2us(fi.Name)); 935 pathParts.Add(fs2us(fi.Name));
@@ -1213,11 +1213,13 @@ HRESULT CDirItems::FillFixedReparse()
1213 // continue; // for debug 1213 // continue; // for debug
1214 if (!item.Has_Attrib_ReparsePoint()) 1214 if (!item.Has_Attrib_ReparsePoint())
1215 continue; 1215 continue;
1216 1216 /*
1217 We want to get properties of target file instead of properies of symbolic link.
1218 Probably this code is unused, because
1219 CFileInfo::Find(with followLink = true) called Fill_From_ByHandleFileInfo() already.
1220 */
1217 // if (item.IsDir()) continue; 1221 // if (item.IsDir()) continue;
1218
1219 const FString phyPath = GetPhyPath(i); 1222 const FString phyPath = GetPhyPath(i);
1220
1221 NFind::CFileInfo fi; 1223 NFind::CFileInfo fi;
1222 if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir() 1224 if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir()
1223 { 1225 {
@@ -1228,38 +1230,13 @@ HRESULT CDirItems::FillFixedReparse()
1228 item.Attrib = fi.Attrib; 1230 item.Attrib = fi.Attrib;
1229 continue; 1231 continue;
1230 } 1232 }
1231
1232 /*
1233 // we request properties of target file instead of properies of symbolic link
1234 // here we also can manually parse unsupported links (like WSL links)
1235 NIO::CInFile inFile;
1236 if (inFile.Open(phyPath))
1237 {
1238 BY_HANDLE_FILE_INFORMATION info;
1239 if (inFile.GetFileInformation(&info))
1240 {
1241 // Stat.FilesSize doesn't contain item.Size already
1242 // Stat.FilesSize -= item.Size;
1243 item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
1244 Stat.FilesSize += item.Size;
1245 item.CTime = info.ftCreationTime;
1246 item.ATime = info.ftLastAccessTime;
1247 item.MTime = info.ftLastWriteTime;
1248 item.Attrib = info.dwFileAttributes;
1249 continue;
1250 }
1251 }
1252 */
1253
1254 RINOK(AddError(phyPath)) 1233 RINOK(AddError(phyPath))
1255 continue; 1234 continue;
1256 } 1235 }
1257 1236
1258 // (SymLinks == true) here 1237 // (SymLinks == true)
1259
1260 if (item.ReparseData.Size() == 0) 1238 if (item.ReparseData.Size() == 0)
1261 continue; 1239 continue;
1262
1263 // if (item.Size == 0) 1240 // if (item.Size == 0)
1264 { 1241 {
1265 // 20.03: we use Reparse Data instead of real data 1242 // 20.03: we use Reparse Data instead of real data
@@ -1277,7 +1254,7 @@ HRESULT CDirItems::FillFixedReparse()
1277 /* imagex/WIM reduces absolute paths in links (raparse data), 1254 /* imagex/WIM reduces absolute paths in links (raparse data),
1278 if we archive non root folder. We do same thing here */ 1255 if we archive non root folder. We do same thing here */
1279 1256
1280 bool isWSL = false; 1257 // bool isWSL = false;
1281 if (attr.IsSymLink_WSL()) 1258 if (attr.IsSymLink_WSL())
1282 { 1259 {
1283 // isWSL = true; 1260 // isWSL = true;
@@ -1314,21 +1291,27 @@ HRESULT CDirItems::FillFixedReparse()
1314 continue; 1291 continue;
1315 if (rootPrefixSize == prefix.Len()) 1292 if (rootPrefixSize == prefix.Len())
1316 continue; // simple case: paths are from root 1293 continue; // simple case: paths are from root
1317
1318 if (link.Len() <= prefix.Len()) 1294 if (link.Len() <= prefix.Len())
1319 continue; 1295 continue;
1320
1321 if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0) 1296 if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)
1322 continue; 1297 continue;
1323 1298
1324 UString newLink = prefix.Left(rootPrefixSize); 1299 UString newLink = prefix.Left(rootPrefixSize);
1325 newLink += link.Ptr(prefix.Len()); 1300 newLink += link.Ptr(prefix.Len());
1326 1301
1327 CByteBuffer data; 1302 CByteBuffer &data = item.ReparseData2;
1328 bool isSymLink = !attr.IsMountPoint(); 1303/*
1329 if (!FillLinkData(data, newLink, isSymLink, isWSL)) 1304 if (isWSL)
1305 {
1306 Convert_WinPath_to_WslLinuxPath(newLink, true); // is absolute : change it
1307 FillLinkData_WslLink(data, newLink);
1308 }
1309 else
1310*/
1311 FillLinkData_WinLink(data, newLink, !attr.IsMountPoint());
1312 if (data.Size() == 0)
1330 continue; 1313 continue;
1331 item.ReparseData2 = data; 1314 // item.ReparseData2 = data;
1332 } 1315 }
1333 return S_OK; 1316 return S_OK;
1334} 1317}
diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp
index 010b01c..0301976 100644
--- a/CPP/7zip/UI/Common/Extract.cpp
+++ b/CPP/7zip/UI/Common/Extract.cpp
@@ -389,7 +389,7 @@ HRESULT Extract(
389 { 389 {
390 UString s = arcPath.Ptr(pos + 1); 390 UString s = arcPath.Ptr(pos + 1);
391 int index = codecs->FindFormatForExtension(s); 391 int index = codecs->FindFormatForExtension(s);
392 if (index >= 0 && s == L"001") 392 if (index >= 0 && s.IsEqualTo("001"))
393 { 393 {
394 s = arcPath.Left(pos); 394 s = arcPath.Left(pos);
395 pos = s.ReverseFind(L'.'); 395 pos = s.ReverseFind(L'.');
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
index 88da4ad..5ca5e66 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -208,7 +208,7 @@ void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UString
208 if (parts.Size() > 1 && parts[1].IsEmpty()) 208 if (parts.Size() > 1 && parts[1].IsEmpty())
209 { 209 {
210 i = 2; 210 i = 2;
211 if (parts.Size() > 2 && parts[2] == L"?") 211 if (parts.Size() > 2 && parts[2].IsEqualTo("?"))
212 { 212 {
213 i = 3; 213 i = 3;
214 if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3])) 214 if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp
index f3d65ef..f026f80 100644
--- a/CPP/7zip/UI/Common/HashCalc.cpp
+++ b/CPP/7zip/UI/Common/HashCalc.cpp
@@ -62,7 +62,7 @@ HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVecto
62 if (m.MethodName.IsEmpty()) 62 if (m.MethodName.IsEmpty())
63 m.MethodName = k_DefaultHashMethod; 63 m.MethodName = k_DefaultHashMethod;
64 64
65 if (m.MethodName == "*") 65 if (m.MethodName.IsEqualTo("*"))
66 { 66 {
67 CRecordVector<CMethodId> tempMethods; 67 CRecordVector<CMethodId> tempMethods;
68 GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods); 68 GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
@@ -431,6 +431,19 @@ static void WriteLine(CDynLimBuf &hashFileString,
431} 431}
432 432
433 433
434static void Convert_TagName_to_MethodName(AString &method)
435{
436 // we need to convert at least SHA512/256 to SHA512-256, and SHA512/224 to SHA512-224
437 // but we convert any '/' to '-'.
438 method.Replace('/', '-');
439}
440
441static void Convert_MethodName_to_TagName(AString &method)
442{
443 if (method.IsPrefixedBy_Ascii_NoCase("SHA512-2"))
444 method.ReplaceOneCharAtPos(6, '/');
445}
446
434 447
435static void WriteLine(CDynLimBuf &hashFileString, 448static void WriteLine(CDynLimBuf &hashFileString,
436 const CHashOptionsLocal &options, 449 const CHashOptionsLocal &options,
@@ -440,8 +453,10 @@ static void WriteLine(CDynLimBuf &hashFileString,
440{ 453{
441 AString methodName; 454 AString methodName;
442 if (!hb.Hashers.IsEmpty()) 455 if (!hb.Hashers.IsEmpty())
456 {
443 methodName = hb.Hashers[0].Name; 457 methodName = hb.Hashers[0].Name;
444 458 Convert_MethodName_to_TagName(methodName);
459 }
445 AString hashesString; 460 AString hashesString;
446 AddHashResultLine(hashesString, hb.Hashers); 461 AddHashResultLine(hashesString, hb.Hashers);
447 WriteLine(hashFileString, options, path, isDir, methodName, hashesString); 462 WriteLine(hashFileString, options, path, isDir, methodName, hashesString);
@@ -752,7 +767,7 @@ bool CHashPair::ParseCksum(const char *s)
752 Name = end; 767 Name = end;
753 768
754 Hash.Alloc(4); 769 Hash.Alloc(4);
755 SetBe32(Hash, crc) 770 SetBe32a(Hash, crc)
756 771
757 Size_from_Arc = size; 772 Size_from_Arc = size;
758 Size_from_Arc_Defined = true; 773 Size_from_Arc_Defined = true;
@@ -773,48 +788,87 @@ static const char * const k_CsumMethodNames[] =
773{ 788{
774 "sha256" 789 "sha256"
775 , "sha224" 790 , "sha224"
776// , "sha512/224" 791 , "sha512-224"
777// , "sha512/256" 792 , "sha512-256"
778 , "sha512"
779 , "sha384" 793 , "sha384"
794 , "sha512"
795 , "sha3-224"
796 , "sha3-256"
797 , "sha3-384"
798 , "sha3-512"
799// , "shake128"
800// , "shake256"
780 , "sha1" 801 , "sha1"
802 , "sha2"
803 , "sha3"
804 , "sha"
781 , "md5" 805 , "md5"
806 , "blake2s"
782 , "blake2b" 807 , "blake2b"
783 , "crc64" 808 , "blake2sp"
809 , "xxh64"
784 , "crc32" 810 , "crc32"
811 , "crc64"
785 , "cksum" 812 , "cksum"
786}; 813};
787 814
788static UString GetMethod_from_FileName(const UString &name) 815
816// returns true, if (method) is known hash method or hash method group name.
817static bool GetMethod_from_FileName(const UString &name, AString &method)
789{ 818{
819 method.Empty();
790 AString s; 820 AString s;
791 ConvertUnicodeToUTF8(name, s); 821 ConvertUnicodeToUTF8(name, s);
792 const int dotPos = s.ReverseFind_Dot(); 822 const int dotPos = s.ReverseFind_Dot();
793 const char *src = s.Ptr();
794 bool isExtension = false;
795 if (dotPos >= 0) 823 if (dotPos >= 0)
796 { 824 {
797 isExtension = true; 825 method = s.Ptr(dotPos + 1);
798 src = s.Ptr(dotPos + 1); 826 if (method.IsEqualTo_Ascii_NoCase("txt") ||
827 method.IsEqualTo_Ascii_NoCase("asc"))
828 {
829 method.Empty();
830 const int dotPos2 = s.Find('.');
831 if (dotPos2 >= 0)
832 s.DeleteFrom(dotPos2);
833 }
799 } 834 }
800 const char *m = ""; 835 if (method.IsEmpty())
836 {
837 // we support file names with "sum" and "sums" postfixes: "sha256sum", "sha256sums"
838 unsigned size;
839 if (s.Len() > 4 && StringsAreEqualNoCase_Ascii(s.RightPtr(4), "sums"))
840 size = 4;
841 else if (s.Len() > 3 && StringsAreEqualNoCase_Ascii(s.RightPtr(3), "sum"))
842 size = 3;
843 else
844 return false;
845 method = s;
846 method.DeleteFrom(s.Len() - size);
847 }
848
801 unsigned i; 849 unsigned i;
802 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++) 850 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
803 { 851 {
804 m = k_CsumMethodNames[i]; 852 const char *m = k_CsumMethodNames[i];
805 if (isExtension) 853 if (method.IsEqualTo_Ascii_NoCase(m))
806 { 854 {
807 if (StringsAreEqual_Ascii(src, m)) 855 // method = m; // we can get lowcase
808 break; 856 return true;
809 } 857 }
810 else if (IsString1PrefixedByString2_NoCase_Ascii(src, m))
811 if (StringsAreEqual_Ascii(src + strlen(m), "sums"))
812 break;
813 } 858 }
814 UString res; 859
815 if (i != Z7_ARRAY_SIZE(k_CsumMethodNames)) 860/*
816 res = m; 861 for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
817 return res; 862 {
863 const char *m = k_CsumMethodNames[i];
864 if (method.IsPrefixedBy_Ascii_NoCase(m))
865 {
866 method = m; // we get lowcase
867 return true;
868 }
869 }
870*/
871 return false;
818} 872}
819 873
820 874
@@ -1039,7 +1093,7 @@ Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data
1039 if (propID == kpidChecksum) 1093 if (propID == kpidChecksum)
1040 { 1094 {
1041 const CHashPair &hp = HashPairs[index]; 1095 const CHashPair &hp = HashPairs[index];
1042 if (hp.Hash.Size() > 0) 1096 if (hp.Hash.Size() != 0)
1043 { 1097 {
1044 *data = hp.Hash; 1098 *data = hp.Hash;
1045 *dataSize = (UInt32)hp.Hash.Size(); 1099 *dataSize = (UInt32)hp.Hash.Size();
@@ -1092,11 +1146,6 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1092 s.Add_UInt32(_hashSize * 8); 1146 s.Add_UInt32(_hashSize * 8);
1093 s += "-bit"; 1147 s += "-bit";
1094 } 1148 }
1095 if (!_nameExtenstion.IsEmpty())
1096 {
1097 s.Add_Space_if_NotEmpty();
1098 s += _nameExtenstion;
1099 }
1100 if (_is_PgpMethod) 1149 if (_is_PgpMethod)
1101 { 1150 {
1102 Add_OptSpace_String(s, "PGP"); 1151 Add_OptSpace_String(s, "PGP");
@@ -1112,6 +1161,18 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
1112 Add_OptSpace_String(s, "TAG"); 1161 Add_OptSpace_String(s, "TAG");
1113 if (_are_there_Dirs) 1162 if (_are_there_Dirs)
1114 Add_OptSpace_String(s, "DIRS"); 1163 Add_OptSpace_String(s, "DIRS");
1164 if (!_method_from_FileName.IsEmpty())
1165 {
1166 Add_OptSpace_String(s, "filename_method:");
1167 s += _method_from_FileName;
1168 if (!_is_KnownMethod_in_FileName)
1169 s += ":UNKNOWN";
1170 }
1171 if (!_methods.IsEmpty())
1172 {
1173 Add_OptSpace_String(s, "cmd_method:");
1174 s += _methods[0];
1175 }
1115 prop = s; 1176 prop = s;
1116 break; 1177 break;
1117 } 1178 }
@@ -1220,6 +1281,15 @@ static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOp
1220} 1281}
1221 1282
1222 1283
1284static bool isThere_Zero_Byte(const Byte *data, size_t size)
1285{
1286 for (size_t i = 0; i < size; i++)
1287 if (data[i] == 0)
1288 return true;
1289 return false;
1290}
1291
1292
1223Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback)) 1293Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
1224{ 1294{
1225 COM_TRY_BEGIN 1295 COM_TRY_BEGIN
@@ -1231,17 +1301,9 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
1231 1301
1232 CObjectVector<CHashPair> &pairs = HashPairs; 1302 CObjectVector<CHashPair> &pairs = HashPairs;
1233 1303
1234 bool zeroMode = false; 1304 const bool zeroMode = isThere_Zero_Byte(buf, buf.Size());
1235 bool cr_lf_Mode = false;
1236 {
1237 for (size_t i = 0; i < buf.Size(); i++)
1238 if (buf.ConstData()[i] == 0)
1239 {
1240 zeroMode = true;
1241 break;
1242 }
1243 }
1244 _is_ZeroMode = zeroMode; 1305 _is_ZeroMode = zeroMode;
1306 bool cr_lf_Mode = false;
1245 if (!zeroMode) 1307 if (!zeroMode)
1246 cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size()); 1308 cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size());
1247 1309
@@ -1255,13 +1317,21 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb
1255 NCOM::CPropVariant prop; 1317 NCOM::CPropVariant prop;
1256 RINOK(openVolumeCallback->GetProperty(kpidName, &prop)) 1318 RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
1257 if (prop.vt == VT_BSTR) 1319 if (prop.vt == VT_BSTR)
1258 _nameExtenstion = GetMethod_from_FileName(prop.bstrVal); 1320 _is_KnownMethod_in_FileName = GetMethod_from_FileName(prop.bstrVal, _method_from_FileName);
1259 } 1321 }
1260 } 1322 }
1261 1323
1262 bool cksumMode = false; 1324 if (!_methods.IsEmpty())
1263 if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum")) 1325 {
1264 cksumMode = true; 1326 ConvertUnicodeToUTF8(_methods[0], _method_for_Extraction);
1327 }
1328 if (_method_for_Extraction.IsEmpty())
1329 {
1330 // if (_is_KnownMethod_in_FileName)
1331 _method_for_Extraction = _method_from_FileName;
1332 }
1333
1334 const bool cksumMode = _method_for_Extraction.IsEqualTo_Ascii_NoCase("cksum");
1265 _is_CksumMode = cksumMode; 1335 _is_CksumMode = cksumMode;
1266 1336
1267 size_t pos = 0; 1337 size_t pos = 0;
@@ -1358,6 +1428,7 @@ void CHandler::ClearVars()
1358 _is_ZeroMode = false; 1428 _is_ZeroMode = false;
1359 _are_there_Tags = false; 1429 _are_there_Tags = false;
1360 _are_there_Dirs = false; 1430 _are_there_Dirs = false;
1431 _is_KnownMethod_in_FileName = false;
1361 _hashSize_Defined = false; 1432 _hashSize_Defined = false;
1362 _hashSize = 0; 1433 _hashSize = 0;
1363} 1434}
@@ -1366,7 +1437,8 @@ void CHandler::ClearVars()
1366Z7_COM7F_IMF(CHandler::Close()) 1437Z7_COM7F_IMF(CHandler::Close())
1367{ 1438{
1368 ClearVars(); 1439 ClearVars();
1369 _nameExtenstion.Empty(); 1440 _method_from_FileName.Empty();
1441 _method_for_Extraction.Empty();
1370 _pgpMethod.Empty(); 1442 _pgpMethod.Empty();
1371 HashPairs.Clear(); 1443 HashPairs.Clear();
1372 return S_OK; 1444 return S_OK;
@@ -1393,19 +1465,73 @@ static bool CheckDigests(const Byte *a, const Byte *b, size_t size)
1393} 1465}
1394 1466
1395 1467
1396static void AddDefaultMethod(UStringVector &methods, unsigned size) 1468static void AddDefaultMethod(UStringVector &methods,
1469 const char *name, unsigned size)
1397{ 1470{
1471 int shaVersion = -1;
1472 if (name)
1473 {
1474 if (StringsAreEqualNoCase_Ascii(name, "sha"))
1475 {
1476 shaVersion = 0;
1477 if (size == 0)
1478 size = 32;
1479 }
1480 else if (StringsAreEqualNoCase_Ascii(name, "sha1"))
1481 {
1482 shaVersion = 1;
1483 if (size == 0)
1484 size = 20;
1485 }
1486 else if (StringsAreEqualNoCase_Ascii(name, "sha2"))
1487 {
1488 shaVersion = 2;
1489 if (size == 0)
1490 size = 32;
1491 }
1492 else if (StringsAreEqualNoCase_Ascii(name, "sha3"))
1493 {
1494 if (size == 0 ||
1495 size == 32) name = "sha3-256";
1496 else if (size == 28) name = "sha3-224";
1497 else if (size == 48) name = "sha3-384";
1498 else if (size == 64) name = "sha3-512";
1499 }
1500 else if (StringsAreEqualNoCase_Ascii(name, "sha512"))
1501 {
1502 // we allow any sha512 derived hash inside .sha512 file:
1503 if (size == 48) name = "sha384";
1504 else if (size == 32) name = "sha512-256";
1505 else if (size == 28) name = "sha512-224";
1506 }
1507 if (shaVersion >= 0)
1508 name = NULL;
1509 }
1510
1398 const char *m = NULL; 1511 const char *m = NULL;
1399 if (size == 32) m = "sha256"; 1512 if (name)
1400 else if (size == 20) m = "sha1"; 1513 m = name;
1401 else if (size == 16) m = "md5";
1402 else if (size == 8) m = "crc64";
1403 else if (size == 4) m = "crc32";
1404 else 1514 else
1515 {
1516 if (size == 64) m = "sha512";
1517 else if (size == 48) m = "sha384";
1518 else if (size == 32) m = "sha256";
1519 else if (size == 28) m = "sha224";
1520 else if (size == 20) m = "sha1";
1521 else if (shaVersion < 0)
1522 {
1523 if (size == 16) m = "md5";
1524 else if (size == 8) m = "crc64";
1525 else if (size == 4) m = "crc32";
1526 }
1527 }
1528
1529 if (!m)
1405 return; 1530 return;
1406 #ifdef Z7_EXTERNAL_CODECS 1531
1532#ifdef Z7_EXTERNAL_CODECS
1407 const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr; 1533 const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
1408 #endif 1534#endif
1409 CMethodId id; 1535 CMethodId id;
1410 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS 1536 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS
1411 AString(m), id)) 1537 AString(m), id))
@@ -1436,15 +1562,15 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1436 CHashBundle hb_Glob; 1562 CHashBundle hb_Glob;
1437 // UStringVector methods = options.Methods; 1563 // UStringVector methods = options.Methods;
1438 UStringVector methods; 1564 UStringVector methods;
1439 1565
1440 if (methods.IsEmpty() && !_nameExtenstion.IsEmpty()) 1566/*
1567 if (methods.IsEmpty() && !utf_nameExtenstion.IsEmpty() && !_hashSize_Defined)
1441 { 1568 {
1442 AString utf;
1443 ConvertUnicodeToUTF8(_nameExtenstion, utf);
1444 CMethodId id; 1569 CMethodId id;
1445 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id)) 1570 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf_nameExtenstion, id))
1446 methods.Add(_nameExtenstion); 1571 methods.Add(_nameExtenstion);
1447 } 1572 }
1573*/
1448 1574
1449 if (methods.IsEmpty() && !_pgpMethod.IsEmpty()) 1575 if (methods.IsEmpty() && !_pgpMethod.IsEmpty())
1450 { 1576 {
@@ -1453,12 +1579,21 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1453 methods.Add(UString(_pgpMethod)); 1579 methods.Add(UString(_pgpMethod));
1454 } 1580 }
1455 1581
1582/*
1456 if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined) 1583 if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined)
1457 AddDefaultMethod(methods, _hashSize); 1584 {
1585 AddDefaultMethod(methods,
1586 utf_nameExtenstion.IsEmpty() ? NULL : utf_nameExtenstion.Ptr(),
1587 _hashSize);
1588 }
1589*/
1458 1590
1459 RINOK(hb_Glob.SetMethods( 1591 if (!methods.IsEmpty())
1592 {
1593 RINOK(hb_Glob.SetMethods(
1460 EXTERNAL_CODECS_LOC_VARS 1594 EXTERNAL_CODECS_LOC_VARS
1461 methods)) 1595 methods))
1596 }
1462 1597
1463 Z7_DECL_CMyComPtr_QI_FROM( 1598 Z7_DECL_CMyComPtr_QI_FROM(
1464 IArchiveUpdateCallbackFile, 1599 IArchiveUpdateCallbackFile,
@@ -1553,9 +1688,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1553 { 1688 {
1554 hb_Use = &hb_Loc; 1689 hb_Use = &hb_Loc;
1555 CMethodId id; 1690 CMethodId id;
1556 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id)) 1691 AString methodName = hp.Method;
1692 Convert_TagName_to_MethodName(methodName);
1693 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, id))
1557 { 1694 {
1558 methods_loc.Add(UString(hp.Method)); 1695 methods_loc.Add(UString(methodName));
1559 RINOK(hb_Loc.SetMethods( 1696 RINOK(hb_Loc.SetMethods(
1560 EXTERNAL_CODECS_LOC_VARS 1697 EXTERNAL_CODECS_LOC_VARS
1561 methods_loc)) 1698 methods_loc))
@@ -1565,7 +1702,10 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1565 } 1702 }
1566 else if (methods.IsEmpty()) 1703 else if (methods.IsEmpty())
1567 { 1704 {
1568 AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size()); 1705 AddDefaultMethod(methods_loc,
1706 _method_for_Extraction.IsEmpty() ? NULL :
1707 _method_for_Extraction.Ptr(),
1708 (unsigned)hp.Hash.Size());
1569 if (!methods_loc.IsEmpty()) 1709 if (!methods_loc.IsEmpty())
1570 { 1710 {
1571 hb_Use = &hb_Loc; 1711 hb_Use = &hb_Loc;
@@ -1613,7 +1753,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
1613 Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod; 1753 Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod;
1614 if (isSupportedMode 1754 if (isSupportedMode
1615 && res_SetMethods != E_NOTIMPL 1755 && res_SetMethods != E_NOTIMPL
1616 && hb_Use->Hashers.Size() > 0 1756 && !hb_Use->Hashers.IsEmpty()
1617 ) 1757 )
1618 { 1758 {
1619 const CHasherState &hs = hb_Use->Hashers[0]; 1759 const CHasherState &hs = hb_Use->Hashers[0];
@@ -1766,10 +1906,6 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1766 methods.Add(_methods[k]); 1906 methods.Add(_methods[k]);
1767 } 1907 }
1768 } 1908 }
1769 else if (_crcSize_WasSet)
1770 {
1771 AddDefaultMethod(methods, _crcSize);
1772 }
1773 else 1909 else
1774 { 1910 {
1775 Z7_DECL_CMyComPtr_QI_FROM( 1911 Z7_DECL_CMyComPtr_QI_FROM(
@@ -1781,12 +1917,23 @@ Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
1781 RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop)) 1917 RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop))
1782 if (prop.vt == VT_BSTR) 1918 if (prop.vt == VT_BSTR)
1783 { 1919 {
1784 const UString method = GetMethod_from_FileName(prop.bstrVal); 1920 AString method;
1921 /* const bool isKnownMethod = */ GetMethod_from_FileName(prop.bstrVal, method);
1785 if (!method.IsEmpty()) 1922 if (!method.IsEmpty())
1786 methods.Add(method); 1923 {
1924 AddDefaultMethod(methods, method, _crcSize_WasSet ? _crcSize : 0);
1925 if (methods.IsEmpty())
1926 return E_NOTIMPL;
1927 }
1787 } 1928 }
1788 } 1929 }
1789 } 1930 }
1931 if (methods.IsEmpty() && _crcSize_WasSet)
1932 {
1933 AddDefaultMethod(methods,
1934 NULL, // name
1935 _crcSize);
1936 }
1790 1937
1791 RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods)) 1938 RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods))
1792 1939
@@ -2030,6 +2177,15 @@ HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
2030} 2177}
2031 2178
2032 2179
2180void CHandler::InitProps()
2181{
2182 _supportWindowsBackslash = true;
2183 _crcSize_WasSet = false;
2184 _crcSize = 4;
2185 _methods.Clear();
2186 _options.Init_HashOptionsLocal();
2187}
2188
2033Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) 2189Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
2034{ 2190{
2035 COM_TRY_BEGIN 2191 COM_TRY_BEGIN
@@ -2076,11 +2232,32 @@ void Codecs_AddHashArcHandler(CCodecs *codecs)
2076 2232
2077 // ubuntu uses "SHA256SUMS" file 2233 // ubuntu uses "SHA256SUMS" file
2078 item.AddExts(UString ( 2234 item.AddExts(UString (
2079 "sha256 sha512 sha224 sha384 sha1 sha md5" 2235 "sha256"
2080 // "b2sum" 2236 " sha512"
2081 " crc32 crc64" 2237 " sha384"
2082 " asc" 2238 " sha224"
2239 " sha512-224"
2240 " sha512-256"
2241 " sha3-224"
2242 " sha3-256"
2243 " sha3-384"
2244 " sha3-512"
2245 // " shake128"
2246 // " shake256"
2247 " sha1"
2248 " sha2"
2249 " sha3"
2250 " sha"
2251 " md5"
2252 " blake2s"
2253 " blake2b"
2254 " blake2sp"
2255 " xxh64"
2256 " crc32"
2257 " crc64"
2083 " cksum" 2258 " cksum"
2259 " asc"
2260 // " b2sum"
2084 ), 2261 ),
2085 UString()); 2262 UString());
2086 2263
diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h
index 1e9dbf4..b8f867f 100644
--- a/CPP/7zip/UI/Common/HashCalc.h
+++ b/CPP/7zip/UI/Common/HashCalc.h
@@ -279,32 +279,25 @@ Z7_CLASS_IMP_CHandler_IInArchive_3(
279 bool _isArc; 279 bool _isArc;
280 bool _supportWindowsBackslash; 280 bool _supportWindowsBackslash;
281 bool _crcSize_WasSet; 281 bool _crcSize_WasSet;
282 UInt64 _phySize;
283 CObjectVector<CHashPair> HashPairs;
284 UString _nameExtenstion;
285 // UString _method_fromName;
286 AString _pgpMethod;
287 bool _is_CksumMode; 282 bool _is_CksumMode;
288 bool _is_PgpMethod; 283 bool _is_PgpMethod;
289 bool _is_ZeroMode; 284 bool _is_ZeroMode;
290 bool _are_there_Tags; 285 bool _are_there_Tags;
291 bool _are_there_Dirs; 286 bool _are_there_Dirs;
287 bool _is_KnownMethod_in_FileName;
292 bool _hashSize_Defined; 288 bool _hashSize_Defined;
293 unsigned _hashSize; 289 unsigned _hashSize;
294 UInt32 _crcSize; 290 UInt32 _crcSize;
291 UInt64 _phySize;
292 CObjectVector<CHashPair> HashPairs;
295 UStringVector _methods; 293 UStringVector _methods;
294 AString _method_from_FileName;
295 AString _pgpMethod;
296 AString _method_for_Extraction;
296 CHashOptionsLocal _options; 297 CHashOptionsLocal _options;
297 298
298 void ClearVars(); 299 void ClearVars();
299 300 void InitProps();
300 void InitProps()
301 {
302 _supportWindowsBackslash = true;
303 _crcSize_WasSet = false;
304 _crcSize = 4;
305 _methods.Clear();
306 _options.Init_HashOptionsLocal();
307 }
308 301
309 bool CanUpdate() const 302 bool CanUpdate() const
310 { 303 {
diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp
index 6bf53ea..943435a 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.cpp
+++ b/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -170,7 +170,7 @@ void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
170 if (i < addExts.Size()) 170 if (i < addExts.Size())
171 { 171 {
172 extInfo.AddExt = addExts[i]; 172 extInfo.AddExt = addExts[i];
173 if (extInfo.AddExt == L"*") 173 if (extInfo.AddExt.IsEqualTo("*"))
174 extInfo.AddExt.Empty(); 174 extInfo.AddExt.Empty();
175 } 175 }
176 Exts.Add(extInfo); 176 Exts.Add(extInfo);
@@ -931,8 +931,8 @@ bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &forma
931 const UString name = arcType.Mid(pos, (unsigned)pos2 - pos); 931 const UString name = arcType.Mid(pos, (unsigned)pos2 - pos);
932 if (name.IsEmpty()) 932 if (name.IsEmpty())
933 return false; 933 return false;
934 int index = FindFormatForArchiveType(name); 934 const int index = FindFormatForArchiveType(name);
935 if (index < 0 && name != L"*") 935 if (index < 0 && !name.IsEqualTo("*"))
936 { 936 {
937 formatIndices.Clear(); 937 formatIndices.Clear();
938 return false; 938 return false;
diff --git a/CPP/7zip/UI/Common/TempFiles.cpp b/CPP/7zip/UI/Common/TempFiles.cpp
index 2f86838..ad16e36 100644
--- a/CPP/7zip/UI/Common/TempFiles.cpp
+++ b/CPP/7zip/UI/Common/TempFiles.cpp
@@ -13,7 +13,8 @@ void CTempFiles::Clear()
13{ 13{
14 while (!Paths.IsEmpty()) 14 while (!Paths.IsEmpty())
15 { 15 {
16 NDir::DeleteFileAlways(Paths.Back()); 16 if (NeedDeleteFiles)
17 NDir::DeleteFileAlways(Paths.Back());
17 Paths.DeleteBack(); 18 Paths.DeleteBack();
18 } 19 }
19} 20}
diff --git a/CPP/7zip/UI/Common/TempFiles.h b/CPP/7zip/UI/Common/TempFiles.h
index dd4ac20..83c741f 100644
--- a/CPP/7zip/UI/Common/TempFiles.h
+++ b/CPP/7zip/UI/Common/TempFiles.h
@@ -10,6 +10,9 @@ class CTempFiles
10 void Clear(); 10 void Clear();
11public: 11public:
12 FStringVector Paths; 12 FStringVector Paths;
13 bool NeedDeleteFiles;
14
15 CTempFiles(): NeedDeleteFiles(true) {}
13 ~CTempFiles() { Clear(); } 16 ~CTempFiles() { Clear(); }
14}; 17};
15 18
diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp
index ed48605..1c2754e 100644
--- a/CPP/7zip/UI/Common/Update.cpp
+++ b/CPP/7zip/UI/Common/Update.cpp
@@ -474,7 +474,7 @@ static HRESULT Compress(
474 474
475 CArcToDoStat stat2; 475 CArcToDoStat stat2;
476 476
477 if (options.RenamePairs.Size() != 0) 477 if (options.RenameMode || options.RenamePairs.Size() != 0)
478 { 478 {
479 FOR_VECTOR (i, arcItems) 479 FOR_VECTOR (i, arcItems)
480 { 480 {
@@ -1096,6 +1096,30 @@ typedef Z7_WIN_MAPISENDMAILW FAR *Z7_WIN_LPMAPISENDMAILW;
1096#endif // _WIN32 1096#endif // _WIN32
1097 1097
1098 1098
1099struct C_CopyFileProgress_to_IUpdateCallbackUI2 Z7_final:
1100 public ICopyFileProgress
1101{
1102 IUpdateCallbackUI2 *Callback;
1103 HRESULT CallbackResult;
1104 // bool Disable_Break;
1105
1106 virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) Z7_override
1107 {
1108 const HRESULT res = Callback->MoveArc_Progress(total, current);
1109 CallbackResult = res;
1110 // if (Disable_Break && res == E_ABORT) res = S_OK;
1111 return res == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL;
1112 }
1113
1114 C_CopyFileProgress_to_IUpdateCallbackUI2(
1115 IUpdateCallbackUI2 *callback) :
1116 Callback(callback),
1117 CallbackResult(S_OK)
1118 // , Disable_Break(false)
1119 {}
1120};
1121
1122
1099HRESULT UpdateArchive( 1123HRESULT UpdateArchive(
1100 CCodecs *codecs, 1124 CCodecs *codecs,
1101 const CObjectVector<COpenType> &types, 1125 const CObjectVector<COpenType> &types,
@@ -1311,7 +1335,7 @@ HRESULT UpdateArchive(
1311 return E_NOTIMPL; 1335 return E_NOTIMPL;
1312 } 1336 }
1313 1337
1314 bool thereIsInArchive = arcLink.IsOpen; 1338 const bool thereIsInArchive = arcLink.IsOpen;
1315 if (!thereIsInArchive && renameMode) 1339 if (!thereIsInArchive && renameMode)
1316 return E_FAIL; 1340 return E_FAIL;
1317 1341
@@ -1588,7 +1612,14 @@ HRESULT UpdateArchive(
1588 multiStreams.DisableDeletion(); 1612 multiStreams.DisableDeletion();
1589 RINOK(multiStreams.Destruct()) 1613 RINOK(multiStreams.Destruct())
1590 1614
1591 tempFiles.Paths.Clear(); 1615 // here we disable deleting of temp archives.
1616 // note: archive moving can fail, or it can be interrupted,
1617 // if we move new temp update from another volume.
1618 // And we still want to keep temp archive in that case,
1619 // because we will have deleted original archive.
1620 tempFiles.NeedDeleteFiles = false;
1621 // tempFiles.Paths.Clear();
1622
1592 if (createTempFile) 1623 if (createTempFile)
1593 { 1624 {
1594 try 1625 try
@@ -1603,16 +1634,29 @@ HRESULT UpdateArchive(
1603 if (!DeleteFileAlways(us2fs(arcPath))) 1634 if (!DeleteFileAlways(us2fs(arcPath)))
1604 return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath)); 1635 return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath));
1605 } 1636 }
1606 1637
1607 if (!MyMoveFile(tempPath, us2fs(arcPath))) 1638 UInt64 totalArcSize = 0;
1639 {
1640 NFind::CFileInfo fi;
1641 if (fi.Find(tempPath))
1642 totalArcSize = fi.Size;
1643 }
1644 RINOK(callback->MoveArc_Start(fs2us(tempPath), arcPath,
1645 totalArcSize, BoolToInt(thereIsInArchive)))
1646
1647 C_CopyFileProgress_to_IUpdateCallbackUI2 prox(callback);
1648 // if we update archive, we have removed original archive.
1649 // So if we break archive moving, we will have only temporary archive.
1650 // We can disable breaking here:
1651 // prox.Disable_Break = thereIsInArchive;
1652
1653 if (!MyMoveFile_with_Progress(tempPath, us2fs(arcPath), &prox))
1608 { 1654 {
1609 errorInfo.SystemError = ::GetLastError(); 1655 errorInfo.SystemError = ::GetLastError();
1610 errorInfo.Message = "cannot move the file"; 1656 errorInfo.Message = "cannot move the file";
1611 if (errorInfo.SystemError == ERROR_INVALID_PARAMETER) 1657 if (errorInfo.SystemError == ERROR_INVALID_PARAMETER)
1612 { 1658 {
1613 NFind::CFileInfo fi; 1659 if (totalArcSize > (UInt32)(Int32)-1)
1614 if (fi.Find(tempPath) &&
1615 fi.Size > (UInt32)(Int32)-1)
1616 { 1660 {
1617 // bool isFsDetected = false; 1661 // bool isFsDetected = false;
1618 // if (NSystem::Is_File_LimitedBy_4GB(us2fs(arcPath), isFsDetected) || !isFsDetected) 1662 // if (NSystem::Is_File_LimitedBy_4GB(us2fs(arcPath), isFsDetected) || !isFsDetected)
@@ -1622,10 +1666,20 @@ HRESULT UpdateArchive(
1622 } 1666 }
1623 } 1667 }
1624 } 1668 }
1669 // if there was no input archive, and we have operation breaking.
1670 // then we can remove temporary archive, because we still have original uncompressed files.
1671 if (!thereIsInArchive
1672 && prox.CallbackResult == E_ABORT)
1673 tempFiles.NeedDeleteFiles = true;
1625 errorInfo.FileNames.Add(tempPath); 1674 errorInfo.FileNames.Add(tempPath);
1626 errorInfo.FileNames.Add(us2fs(arcPath)); 1675 errorInfo.FileNames.Add(us2fs(arcPath));
1676 RINOK(prox.CallbackResult)
1627 return errorInfo.Get_HRESULT_Error(); 1677 return errorInfo.Get_HRESULT_Error();
1628 } 1678 }
1679
1680 // MoveArc_Finish() can return delayed user break (E_ABORT) status,
1681 // if callback callee ignored interruption to finish archive creation operation.
1682 RINOK(callback->MoveArc_Finish())
1629 1683
1630 /* 1684 /*
1631 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) 1685 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
@@ -1866,7 +1920,7 @@ Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
1866 if (NFind::DoesDirExist(phyPath)) 1920 if (NFind::DoesDirExist(phyPath))
1867 { 1921 {
1868 RINOK(callback->DeletingAfterArchiving(phyPath, true)) 1922 RINOK(callback->DeletingAfterArchiving(phyPath, true))
1869 RemoveDir(phyPath); 1923 RemoveDirAlways_if_Empty(phyPath);
1870 } 1924 }
1871 } 1925 }
1872 1926
diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h
index a9459ff..ae141e5 100644
--- a/CPP/7zip/UI/Common/Update.h
+++ b/CPP/7zip/UI/Common/Update.h
@@ -12,8 +12,6 @@
12#include "UpdateAction.h" 12#include "UpdateAction.h"
13#include "UpdateCallback.h" 13#include "UpdateCallback.h"
14 14
15#include "DirItem.h"
16
17enum EArcNameMode 15enum EArcNameMode
18{ 16{
19 k_ArcNameMode_Smart, 17 k_ArcNameMode_Smart,
@@ -96,6 +94,7 @@ struct CUpdateOptions
96 94
97 bool DeleteAfterCompressing; 95 bool DeleteAfterCompressing;
98 bool SetArcMTime; 96 bool SetArcMTime;
97 bool RenameMode;
99 98
100 CBoolPair NtSecurity; 99 CBoolPair NtSecurity;
101 CBoolPair AltStreams; 100 CBoolPair AltStreams;
@@ -141,6 +140,7 @@ struct CUpdateOptions
141 140
142 DeleteAfterCompressing(false), 141 DeleteAfterCompressing(false),
143 SetArcMTime(false), 142 SetArcMTime(false),
143 RenameMode(false),
144 144
145 ArcNameMode(k_ArcNameMode_Smart), 145 ArcNameMode(k_ArcNameMode_Smart),
146 PathMode(NWildcard::k_RelatPath) 146 PathMode(NWildcard::k_RelatPath)
@@ -195,6 +195,9 @@ Z7_PURE_INTERFACES_BEGIN
195 virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \ 195 virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \
196 virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \ 196 virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \
197 virtual HRESULT FinishDeletingAfterArchiving() x \ 197 virtual HRESULT FinishDeletingAfterArchiving() x \
198 virtual HRESULT MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode) x \
199 virtual HRESULT MoveArc_Progress(UInt64 total, UInt64 current) x \
200 virtual HRESULT MoveArc_Finish() x \
198 201
199DECLARE_INTERFACE(IUpdateCallbackUI2): 202DECLARE_INTERFACE(IUpdateCallbackUI2):
200 public IUpdateCallbackUI, 203 public IUpdateCallbackUI,
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp
index d3ee639..e2f1866 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.cpp
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -32,6 +32,7 @@
32#include "../../../Windows/PropVariant.h" 32#include "../../../Windows/PropVariant.h"
33 33
34#include "../../Common/StreamObjects.h" 34#include "../../Common/StreamObjects.h"
35#include "../../Archive/Common/ItemNameUtils.h"
35 36
36#include "UpdateCallback.h" 37#include "UpdateCallback.h"
37 38
@@ -306,7 +307,7 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, con
306 307
307#if defined(_WIN32) && !defined(UNDER_CE) 308#if defined(_WIN32) && !defined(UNDER_CE)
308 309
309static UString GetRelativePath(const UString &to, const UString &from) 310static UString GetRelativePath(const UString &to, const UString &from, bool isWSL)
310{ 311{
311 UStringVector partsTo, partsFrom; 312 UStringVector partsTo, partsFrom;
312 SplitPathToParts(to, partsTo); 313 SplitPathToParts(to, partsTo);
@@ -324,11 +325,12 @@ static UString GetRelativePath(const UString &to, const UString &from)
324 325
325 if (i == 0) 326 if (i == 0)
326 { 327 {
327 #ifdef _WIN32 328#ifdef _WIN32
328 if (NName::IsDrivePath(to) || 329 if (isWSL ||
329 NName::IsDrivePath(from)) 330 (NName::IsDrivePath(to) ||
331 NName::IsDrivePath(from)))
330 return to; 332 return to;
331 #endif 333#endif
332 } 334 }
333 335
334 UString s; 336 UString s;
@@ -373,54 +375,87 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
373 return S_OK; 375 return S_OK;
374 } 376 }
375 377
376 #if !defined(UNDER_CE) 378#if !defined(UNDER_CE)
377
378 if (up.DirIndex >= 0) 379 if (up.DirIndex >= 0)
379 { 380 {
380 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; 381 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
381 382 if (di.ReparseData.Size())
382 #ifdef _WIN32
383 // if (di.IsDir())
384 { 383 {
384#ifdef _WIN32
385 CReparseAttr attr; 385 CReparseAttr attr;
386 if (attr.Parse(di.ReparseData, di.ReparseData.Size())) 386 if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
387 { 387 {
388 const UString simpleName = attr.GetPath(); 388 UString path = attr.GetPath();
389 if (!attr.IsSymLink_WSL() && attr.IsRelative_Win()) 389 if (!path.IsEmpty())
390 prop = simpleName;
391 else
392 { 390 {
393 const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex); 391 bool isWSL = attr.IsSymLink_WSL();
394 FString fullPath; 392 if (isWSL)
395 if (NDir::MyGetFullPathName(phyPath, fullPath)) 393 NArchive::NItemName::ReplaceToWinSlashes(path, true); // useBackslashReplacement
394 // it's expected that (path) now uses windows slashes.
395 // CReparseAttr::IsRelative_Win() returns true if FLAG_RELATIVE is set
396 // CReparseAttr::IsRelative_Win() returns true for "\dir1\path"
397 // but we want to store real relative paths without "\" root prefix.
398 // so we parse path instead of IsRelative_Win() calling.
399 if (// attr.IsRelative_Win() ||
400 (isWSL ?
401 IS_PATH_SEPAR(path[0]) :
402 NName::IsAbsolutePath(path)))
396 { 403 {
397 prop = GetRelativePath(simpleName, fs2us(fullPath)); 404 // (path) is abolute path or relative to root: "\path"
405 // we try to convert (path) to relative path for writing to archive.
406 const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex);
407 FString fullPath;
408 if (NDir::MyGetFullPathName(phyPath, fullPath))
409 {
410 if (IS_PATH_SEPAR(path[0]) &&
411 !IS_PATH_SEPAR(path[1]))
412 {
413 // path is relative to root of (fullPath): "\path"
414 const unsigned prefixSize = NName::GetRootPrefixSize(fullPath);
415 if (prefixSize)
416 {
417 path.DeleteFrontal(1);
418 path.Insert(0, fs2us(fullPath.Left(prefixSize)));
419 // we have changed "\" prefix to drive prefix "c:\" in (path).
420 // (path) is Windows path now.
421 isWSL = false;
422 }
423 }
424 }
425 path = GetRelativePath(path, fs2us(fullPath), isWSL);
398 } 426 }
427#if WCHAR_PATH_SEPARATOR != L'/'
428 // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes.
429 // so we can return any slashes to TAR handler.
430 // or we can convert to linux slashes here,
431 // because input IInArchive handler uses linux slashes for kpidSymLink.
432 // path.Replace(WCHAR_PATH_SEPARATOR, L'/');
433#endif
434 if (!path.IsEmpty())
435 prop = path;
399 } 436 }
400 prop.Detach(value);
401 return S_OK;
402 } 437 }
403 } 438#else // ! _WIN32
404
405 #else // _WIN32
406
407 if (di.ReparseData.Size() != 0)
408 {
409 AString utf; 439 AString utf;
410 utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size()); 440 utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size());
411 441 #if 0 // 0 - for debug
442 // it's expected that link data uses system codepage.
443 // fs2us() ignores conversion errors. But we want correct path
444 UString us (fs2us(utf));
445 #else
412 UString us; 446 UString us;
413 if (ConvertUTF8ToUnicode(utf, us)) 447 if (ConvertUTF8ToUnicode(utf, us))
448 #endif
414 { 449 {
415 prop = us; 450 if (!us.IsEmpty())
416 prop.Detach(value); 451 prop = us;
417 return S_OK;
418 } 452 }
453#endif // ! _WIN32
419 } 454 }
420 455 prop.Detach(value);
421 #endif // _WIN32 456 return S_OK;
422 } 457 }
423 #endif // !defined(UNDER_CE) 458#endif // !defined(UNDER_CE)
424 } 459 }
425 else if (propID == kpidHardLink) 460 else if (propID == kpidHardLink)
426 { 461 {
@@ -428,7 +463,12 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
428 { 463 {
429 const CKeyKeyValPair &pair = _map[_hardIndex_To]; 464 const CKeyKeyValPair &pair = _map[_hardIndex_To];
430 const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; 465 const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
431 prop = DirItems->GetLogPath((unsigned)up2.DirIndex); 466 const UString path = DirItems->GetLogPath((unsigned)up2.DirIndex);
467#if WCHAR_PATH_SEPARATOR != L'/'
468 // 7-Zip's TAR handler in Windows replaces windows slashes to linux slashes.
469 // path.Replace(WCHAR_PATH_SEPARATOR, L'/');
470#endif
471 prop = path;
432 prop.Detach(value); 472 prop.Detach(value);
433 return S_OK; 473 return S_OK;
434 } 474 }
@@ -438,7 +478,7 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR
438 return S_OK; 478 return S_OK;
439 } 479 }
440 } 480 }
441 } 481 } // if (up.NewData)
442 482
443 if (up.IsAnti 483 if (up.IsAnti
444 && propID != kpidIsDir 484 && propID != kpidIsDir
diff --git a/CPP/7zip/UI/Common/WorkDir.cpp b/CPP/7zip/UI/Common/WorkDir.cpp
index cfec635..a492967 100644
--- a/CPP/7zip/UI/Common/WorkDir.cpp
+++ b/CPP/7zip/UI/Common/WorkDir.cpp
@@ -63,24 +63,22 @@ HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath)
63 NWorkDir::CInfo workDirInfo; 63 NWorkDir::CInfo workDirInfo;
64 workDirInfo.Load(); 64 workDirInfo.Load();
65 FString namePart; 65 FString namePart;
66 const FString workDir = GetWorkDir(workDirInfo, originalPath, namePart); 66 FString path = GetWorkDir(workDirInfo, originalPath, namePart);
67 CreateComplexDir(workDir); 67 CreateComplexDir(path);
68 path += namePart;
68 _outStreamSpec = new COutFileStream; 69 _outStreamSpec = new COutFileStream;
69 OutStream = _outStreamSpec; 70 OutStream = _outStreamSpec;
70 if (!_tempFile.Create(workDir + namePart, &_outStreamSpec->File)) 71 if (!_tempFile.Create(path, &_outStreamSpec->File))
71 {
72 return GetLastError_noZero_HRESULT(); 72 return GetLastError_noZero_HRESULT();
73 }
74 _originalPath = originalPath; 73 _originalPath = originalPath;
75 return S_OK; 74 return S_OK;
76} 75}
77 76
78HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal) 77HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal,
78 NWindows::NFile::NDir::ICopyFileProgress *progress)
79{ 79{
80 OutStream.Release(); 80 OutStream.Release();
81 if (!_tempFile.MoveTo(_originalPath, deleteOriginal)) 81 if (!_tempFile.MoveTo(_originalPath, deleteOriginal, progress))
82 {
83 return GetLastError_noZero_HRESULT(); 82 return GetLastError_noZero_HRESULT();
84 }
85 return S_OK; 83 return S_OK;
86} 84}
diff --git a/CPP/7zip/UI/Common/WorkDir.h b/CPP/7zip/UI/Common/WorkDir.h
index d32ab9d..fed8c4a 100644
--- a/CPP/7zip/UI/Common/WorkDir.h
+++ b/CPP/7zip/UI/Common/WorkDir.h
@@ -11,7 +11,7 @@
11 11
12FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName); 12FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName);
13 13
14class CWorkDirTempFile 14class CWorkDirTempFile MY_UNCOPYABLE
15{ 15{
16 FString _originalPath; 16 FString _originalPath;
17 NWindows::NFile::NDir::CTempFile _tempFile; 17 NWindows::NFile::NDir::CTempFile _tempFile;
@@ -19,8 +19,12 @@ class CWorkDirTempFile
19public: 19public:
20 CMyComPtr<IOutStream> OutStream; 20 CMyComPtr<IOutStream> OutStream;
21 21
22 const FString &Get_OriginalFilePath() const { return _originalPath; }
23 const FString &Get_TempFilePath() const { return _tempFile.GetPath(); }
24
22 HRESULT CreateTempFile(const FString &originalPath); 25 HRESULT CreateTempFile(const FString &originalPath);
23 HRESULT MoveToOriginal(bool deleteOriginal); 26 HRESULT MoveToOriginal(bool deleteOriginal,
27 NWindows::NFile::NDir::ICopyFileProgress *progress = NULL);
24}; 28};
25 29
26#endif 30#endif
diff --git a/CPP/7zip/UI/Common/ZipRegistry.cpp b/CPP/7zip/UI/Common/ZipRegistry.cpp
index 73c56cf..936b888 100644
--- a/CPP/7zip/UI/Common/ZipRegistry.cpp
+++ b/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -45,8 +45,8 @@ static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value)
45 45
46static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value) 46static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value)
47{ 47{
48 if (key.QueryValue(name, value) != ERROR_SUCCESS) 48 value = (UInt32)(Int32)-1;
49 value = (UInt32)(Int32)-1; 49 key.GetValue_UInt32_IfOk(name, value);
50} 50}
51 51
52 52
@@ -59,7 +59,7 @@ static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b)
59static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val) 59static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val)
60{ 60{
61 bool oldVal = false; 61 bool oldVal = false;
62 if (key.GetValue_IfOk(name, oldVal) == ERROR_SUCCESS) 62 if (key.GetValue_bool_IfOk(name, oldVal) == ERROR_SUCCESS)
63 if (val == oldVal) 63 if (val == oldVal)
64 return; 64 return;
65 key.SetValue(name, val); 65 key.SetValue(name, val);
@@ -76,13 +76,13 @@ static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoo
76static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b) 76static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b)
77{ 77{
78 b.Val = false; 78 b.Val = false;
79 b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS); 79 b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS);
80} 80}
81 81
82static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b) 82static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b)
83{ 83{
84 b.Val = true; 84 b.Val = true;
85 b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS); 85 b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS);
86} 86}
87 87
88namespace NExtract 88namespace NExtract
@@ -155,12 +155,12 @@ void CInfo::Load()
155 155
156 key.GetValue_Strings(kPathHistory, Paths); 156 key.GetValue_Strings(kPathHistory, Paths);
157 UInt32 v; 157 UInt32 v;
158 if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths) 158 if (key.GetValue_UInt32_IfOk(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths)
159 { 159 {
160 PathMode = (NPathMode::EEnum)v; 160 PathMode = (NPathMode::EEnum)v;
161 PathMode_Force = true; 161 PathMode_Force = true;
162 } 162 }
163 if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting) 163 if (key.GetValue_UInt32_IfOk(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting)
164 { 164 {
165 OverwriteMode = (NOverwriteMode::EEnum)v; 165 OverwriteMode = (NOverwriteMode::EEnum)v;
166 OverwriteMode_Force = true; 166 OverwriteMode_Force = true;
@@ -181,7 +181,7 @@ bool Read_ShowPassword()
181 bool showPassword = false; 181 bool showPassword = false;
182 if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS) 182 if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
183 return showPassword; 183 return showPassword;
184 key.GetValue_IfOk(kShowPassword, showPassword); 184 key.GetValue_bool_IfOk(kShowPassword, showPassword);
185 return showPassword; 185 return showPassword;
186} 186}
187 187
@@ -189,13 +189,10 @@ UInt32 Read_LimitGB()
189{ 189{
190 CS_LOCK 190 CS_LOCK
191 CKey key; 191 CKey key;
192 UInt32 v = (UInt32)(Int32)-1;
192 if (OpenMainKey(key, kKeyName) == ERROR_SUCCESS) 193 if (OpenMainKey(key, kKeyName) == ERROR_SUCCESS)
193 { 194 key.GetValue_UInt32_IfOk(kMemLimit, v);
194 UInt32 v; 195 return v;
195 if (key.QueryValue(kMemLimit, v) == ERROR_SUCCESS)
196 return v;
197 }
198 return (UInt32)(Int32)-1;
199} 196}
200 197
201} 198}
@@ -371,9 +368,9 @@ void CInfo::Load()
371 UString a; 368 UString a;
372 if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS) 369 if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS)
373 ArcType = a; 370 ArcType = a;
374 key.GetValue_IfOk(kLevel, Level); 371 key.GetValue_UInt32_IfOk(kLevel, Level);
375 key.GetValue_IfOk(kShowPassword, ShowPassword); 372 key.GetValue_bool_IfOk(kShowPassword, ShowPassword);
376 key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders); 373 key.GetValue_bool_IfOk(kEncryptHeaders, EncryptHeaders);
377} 374}
378 375
379 376
@@ -517,7 +514,7 @@ void CInfo::Load()
517 return; 514 return;
518 515
519 UInt32 dirType; 516 UInt32 dirType;
520 if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS) 517 if (key.GetValue_UInt32_IfOk(kWorkDirType, dirType) != ERROR_SUCCESS)
521 return; 518 return;
522 switch (dirType) 519 switch (dirType)
523 { 520 {
@@ -535,7 +532,7 @@ void CInfo::Load()
535 if (Mode == NMode::kSpecified) 532 if (Mode == NMode::kSpecified)
536 Mode = NMode::kSystem; 533 Mode = NMode::kSystem;
537 } 534 }
538 key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly); 535 key.GetValue_bool_IfOk(kTempRemovableOnly, ForRemovableOnly);
539} 536}
540 537
541} 538}
@@ -598,5 +595,5 @@ void CContextMenuInfo::Load()
598 595
599 Key_Get_UInt32(key, kWriteZoneId, WriteZone); 596 Key_Get_UInt32(key, kWriteZoneId, WriteZone);
600 597
601 Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS); 598 Flags_Def = (key.GetValue_UInt32_IfOk(kContextMenu, Flags) == ERROR_SUCCESS);
602} 599}