1 // Client7z.cpp
2
3 #include "StdAfx.h"
4
5 #include <stdio.h>
6
7 #include "../../../Common/MyWindows.h"
8 #include "../../../Common/MyInitGuid.h"
9
10 #include "../../../Common/Defs.h"
11 #include "../../../Common/IntToString.h"
12 #include "../../../Common/StringConvert.h"
13
14 #include "../../../Windows/DLL.h"
15 #include "../../../Windows/FileDir.h"
16 #include "../../../Windows/FileFind.h"
17 #include "../../../Windows/FileName.h"
18 #include "../../../Windows/NtCheck.h"
19 #include "../../../Windows/PropVariant.h"
20 #include "../../../Windows/PropVariantConv.h"
21
22 #include "../../Common/FileStreams.h"
23
24 #include "../../Archive/IArchive.h"
25
26 #if 0
27 // for password request functions:
28 #include "../../UI/Console/UserInputUtils.h"
29 #endif
30
31 #include "../../IPassword.h"
32 #include "../../../../C/7zVersion.h"
33
34 #ifdef _WIN32
35 extern
36 HINSTANCE g_hInstance;
37 HINSTANCE g_hInstance = NULL;
38 #endif
39
40 Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
41
42 // You can find full list of all GUIDs supported by 7-Zip in Guid.txt file.
43 // 7z format GUID: {23170F69-40C1-278A-1000-000110070000}
44
45 #define DEFINE_GUID_ARC(name, id) Z7_DEFINE_GUID(name, \
46 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00);
47
48 enum
49 {
50 kId_Zip = 1,
51 kId_BZip2 = 2,
52 kId_7z = 7,
53 kId_Xz = 0xC,
54 kId_Tar = 0xEE,
55 kId_GZip = 0xEF
56 };
57
58 // use another id, if you want to support other formats (zip, Xz, ...).
59 // DEFINE_GUID_ARC (CLSID_Format, kId_Zip)
60 // DEFINE_GUID_ARC (CLSID_Format, kId_BZip2)
61 // DEFINE_GUID_ARC (CLSID_Format, kId_Xz)
62 // DEFINE_GUID_ARC (CLSID_Format, kId_Tar)
63 // DEFINE_GUID_ARC (CLSID_Format, kId_GZip)
64 DEFINE_GUID_ARC (CLSID_Format, kId_7z)
65
66 using namespace NWindows;
67 using namespace NFile;
68 using namespace NDir;
69
70 #ifdef _WIN32
71 #define kDllName "7z.dll"
72 #else
73 #define kDllName "7z.so"
74 #endif
75
76 static const char * const kCopyrightString =
77 "\n"
78 "7-Zip"
79 " (" kDllName " client)"
80 " " MY_VERSION
81 " : " MY_COPYRIGHT_DATE
82 "\n";
83
84 static const char * const kHelpString =
85 "Usage: 7zcl.exe [a | l | x] archive.7z [fileName ...]\n"
86 "Examples:\n"
87 " 7zcl.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n"
88 " 7zcl.exe l archive.7z : List contents of archive.7z\n"
89 " 7zcl.exe x archive.7z : eXtract files from archive.7z\n";
90
91
Convert_UString_to_AString(const UString & s,AString & temp)92 static void Convert_UString_to_AString(const UString &s, AString &temp)
93 {
94 int codePage = CP_OEMCP;
95 /*
96 int g_CodePage = -1;
97 int codePage = g_CodePage;
98 if (codePage == -1)
99 codePage = CP_OEMCP;
100 if (codePage == CP_UTF8)
101 ConvertUnicodeToUTF8(s, temp);
102 else
103 */
104 UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
105 }
106
CmdStringToFString(const char * s)107 static FString CmdStringToFString(const char *s)
108 {
109 return us2fs(GetUnicodeString(s));
110 }
111
Print(const char * s)112 static void Print(const char *s)
113 {
114 fputs(s, stdout);
115 }
116
Print(const AString & s)117 static void Print(const AString &s)
118 {
119 Print(s.Ptr());
120 }
121
Print(const UString & s)122 static void Print(const UString &s)
123 {
124 AString as;
125 Convert_UString_to_AString(s, as);
126 Print(as);
127 }
128
Print(const wchar_t * s)129 static void Print(const wchar_t *s)
130 {
131 Print(UString(s));
132 }
133
PrintNewLine()134 static void PrintNewLine()
135 {
136 Print("\n");
137 }
138
PrintStringLn(const char * s)139 static void PrintStringLn(const char *s)
140 {
141 Print(s);
142 PrintNewLine();
143 }
144
PrintError(const char * message)145 static void PrintError(const char *message)
146 {
147 Print("Error: ");
148 PrintNewLine();
149 Print(message);
150 PrintNewLine();
151 }
152
PrintError(const char * message,const FString & name)153 static void PrintError(const char *message, const FString &name)
154 {
155 PrintError(message);
156 Print(name);
157 }
158
159
IsArchiveItemProp(IInArchive * archive,UInt32 index,PROPID propID,bool & result)160 static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
161 {
162 NCOM::CPropVariant prop;
163 RINOK(archive->GetProperty(index, propID, &prop))
164 if (prop.vt == VT_BOOL)
165 result = VARIANT_BOOLToBool(prop.boolVal);
166 else if (prop.vt == VT_EMPTY)
167 result = false;
168 else
169 return E_FAIL;
170 return S_OK;
171 }
172
IsArchiveItemFolder(IInArchive * archive,UInt32 index,bool & result)173 static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
174 {
175 return IsArchiveItemProp(archive, index, kpidIsDir, result);
176 }
177
178
179 static const wchar_t * const kEmptyFileAlias = L"[Content]";
180
181
182 //////////////////////////////////////////////////////////////
183 // Archive Open callback class
184
185
186 class CArchiveOpenCallback Z7_final:
187 public IArchiveOpenCallback,
188 public ICryptoGetTextPassword,
189 public CMyUnknownImp
190 {
191 Z7_IFACES_IMP_UNK_2(IArchiveOpenCallback, ICryptoGetTextPassword)
192 public:
193
194 bool PasswordIsDefined;
195 UString Password;
196
CArchiveOpenCallback()197 CArchiveOpenCallback() : PasswordIsDefined(false) {}
198 };
199
Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal (const UInt64 *,const UInt64 *))200 Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */))
201 {
202 return S_OK;
203 }
204
Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted (const UInt64 *,const UInt64 *))205 Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */))
206 {
207 return S_OK;
208 }
209
Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword (BSTR * password))210 Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password))
211 {
212 if (!PasswordIsDefined)
213 {
214 // You can ask real password here from user
215 #if 0
216 RINOK(GetPassword_HRESULT(&g_StdOut, Password))
217 PasswordIsDefined = true;
218 #else
219 PrintError("Password is not defined");
220 return E_ABORT;
221 #endif
222 }
223 return StringToBstr(Password, password);
224 }
225
226
227
228 static const char * const kIncorrectCommand = "incorrect command";
229
230 //////////////////////////////////////////////////////////////
231 // Archive Extracting callback class
232
233 static const char * const kTestingString = "Testing ";
234 static const char * const kExtractingString = "Extracting ";
235 static const char * const kSkippingString = "Skipping ";
236 static const char * const kReadingString = "Reading ";
237
238 static const char * const kUnsupportedMethod = "Unsupported Method";
239 static const char * const kCRCFailed = "CRC Failed";
240 static const char * const kDataError = "Data Error";
241 static const char * const kUnavailableData = "Unavailable data";
242 static const char * const kUnexpectedEnd = "Unexpected end of data";
243 static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
244 static const char * const kIsNotArc = "Is not archive";
245 static const char * const kHeadersError = "Headers Error";
246
247
248 struct CArcTime
249 {
250 FILETIME FT;
251 UInt16 Prec;
252 Byte Ns100;
253 bool Def;
254
CArcTimeCArcTime255 CArcTime()
256 {
257 Clear();
258 }
259
ClearCArcTime260 void Clear()
261 {
262 FT.dwHighDateTime = FT.dwLowDateTime = 0;
263 Prec = 0;
264 Ns100 = 0;
265 Def = false;
266 }
267
IsZeroCArcTime268 bool IsZero() const
269 {
270 return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
271 }
272
GetNumDigitsCArcTime273 int GetNumDigits() const
274 {
275 if (Prec == k_PropVar_TimePrec_Unix ||
276 Prec == k_PropVar_TimePrec_DOS)
277 return 0;
278 if (Prec == k_PropVar_TimePrec_HighPrec)
279 return 9;
280 if (Prec == k_PropVar_TimePrec_0)
281 return 7;
282 int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
283 if (digits < 0)
284 digits = 0;
285 return digits;
286 }
287
Write_To_FiTimeCArcTime288 void Write_To_FiTime(CFiTime &dest) const
289 {
290 #ifdef _WIN32
291 dest = FT;
292 #else
293 if (FILETIME_To_timespec(FT, dest))
294 if ((Prec == k_PropVar_TimePrec_Base + 8 ||
295 Prec == k_PropVar_TimePrec_Base + 9)
296 && Ns100 != 0)
297 {
298 dest.tv_nsec += Ns100;
299 }
300 #endif
301 }
302
Set_From_PropCArcTime303 void Set_From_Prop(const PROPVARIANT &prop)
304 {
305 FT = prop.filetime;
306 unsigned prec = 0;
307 unsigned ns100 = 0;
308 const unsigned prec_Temp = prop.wReserved1;
309 if (prec_Temp != 0
310 && prec_Temp <= k_PropVar_TimePrec_1ns
311 && prop.wReserved3 == 0)
312 {
313 const unsigned ns100_Temp = prop.wReserved2;
314 if (ns100_Temp < 100)
315 {
316 ns100 = ns100_Temp;
317 prec = prec_Temp;
318 }
319 }
320 Prec = (UInt16)prec;
321 Ns100 = (Byte)ns100;
322 Def = true;
323 }
324 };
325
326
327
328 class CArchiveExtractCallback Z7_final:
329 public IArchiveExtractCallback,
330 public ICryptoGetTextPassword,
331 public CMyUnknownImp
332 {
333 Z7_IFACES_IMP_UNK_2(IArchiveExtractCallback, ICryptoGetTextPassword)
334 Z7_IFACE_COM7_IMP(IProgress)
335
336 CMyComPtr<IInArchive> _archiveHandler;
337 FString _directoryPath; // Output directory
338 UString _filePath; // name inside arcvhive
339 FString _diskFilePath; // full path to file on disk
340 bool _extractMode;
341 struct CProcessedFileInfo
342 {
343 CArcTime MTime;
344 UInt32 Attrib;
345 bool isDir;
346 bool Attrib_Defined;
347 } _processedFileInfo;
348
349 COutFileStream *_outFileStreamSpec;
350 CMyComPtr<ISequentialOutStream> _outFileStream;
351
352 public:
353 void Init(IInArchive *archiveHandler, const FString &directoryPath);
354
355 UInt64 NumErrors;
356 bool PasswordIsDefined;
357 UString Password;
358
CArchiveExtractCallback()359 CArchiveExtractCallback() : PasswordIsDefined(false) {}
360 };
361
Init(IInArchive * archiveHandler,const FString & directoryPath)362 void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath)
363 {
364 NumErrors = 0;
365 _archiveHandler = archiveHandler;
366 _directoryPath = directoryPath;
367 NName::NormalizeDirPathPrefix(_directoryPath);
368 }
369
Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal (UInt64))370 Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 /* size */))
371 {
372 return S_OK;
373 }
374
Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted (const UInt64 *))375 Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */))
376 {
377 return S_OK;
378 }
379
Z7_COM7F_IMF(CArchiveExtractCallback::GetStream (UInt32 index,ISequentialOutStream ** outStream,Int32 askExtractMode))380 Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index,
381 ISequentialOutStream **outStream, Int32 askExtractMode))
382 {
383 *outStream = NULL;
384 _outFileStream.Release();
385
386 {
387 // Get Name
388 NCOM::CPropVariant prop;
389 RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop))
390
391 UString fullPath;
392 if (prop.vt == VT_EMPTY)
393 fullPath = kEmptyFileAlias;
394 else
395 {
396 if (prop.vt != VT_BSTR)
397 return E_FAIL;
398 fullPath = prop.bstrVal;
399 }
400 _filePath = fullPath;
401 }
402
403 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
404 return S_OK;
405
406 {
407 // Get Attrib
408 NCOM::CPropVariant prop;
409 RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop))
410 if (prop.vt == VT_EMPTY)
411 {
412 _processedFileInfo.Attrib = 0;
413 _processedFileInfo.Attrib_Defined = false;
414 }
415 else
416 {
417 if (prop.vt != VT_UI4)
418 return E_FAIL;
419 _processedFileInfo.Attrib = prop.ulVal;
420 _processedFileInfo.Attrib_Defined = true;
421 }
422 }
423
424 RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir))
425
426 {
427 _processedFileInfo.MTime.Clear();
428 // Get Modified Time
429 NCOM::CPropVariant prop;
430 RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop))
431 switch (prop.vt)
432 {
433 case VT_EMPTY:
434 // _processedFileInfo.MTime = _utcMTimeDefault;
435 break;
436 case VT_FILETIME:
437 _processedFileInfo.MTime.Set_From_Prop(prop);
438 break;
439 default:
440 return E_FAIL;
441 }
442
443 }
444 {
445 // Get Size
446 NCOM::CPropVariant prop;
447 RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop))
448 UInt64 newFileSize;
449 /* bool newFileSizeDefined = */ ConvertPropVariantToUInt64(prop, newFileSize);
450 }
451
452
453 {
454 // Create folders for file
455 int slashPos = _filePath.ReverseFind_PathSepar();
456 if (slashPos >= 0)
457 CreateComplexDir(_directoryPath + us2fs(_filePath.Left(slashPos)));
458 }
459
460 FString fullProcessedPath = _directoryPath + us2fs(_filePath);
461 _diskFilePath = fullProcessedPath;
462
463 if (_processedFileInfo.isDir)
464 {
465 CreateComplexDir(fullProcessedPath);
466 }
467 else
468 {
469 NFind::CFileInfo fi;
470 if (fi.Find(fullProcessedPath))
471 {
472 if (!DeleteFileAlways(fullProcessedPath))
473 {
474 PrintError("Cannot delete output file", fullProcessedPath);
475 return E_ABORT;
476 }
477 }
478
479 _outFileStreamSpec = new COutFileStream;
480 CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
481 if (!_outFileStreamSpec->Create_ALWAYS(fullProcessedPath))
482 {
483 PrintError("Cannot open output file", fullProcessedPath);
484 return E_ABORT;
485 }
486 _outFileStream = outStreamLoc;
487 *outStream = outStreamLoc.Detach();
488 }
489 return S_OK;
490 }
491
Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation (Int32 askExtractMode))492 Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode))
493 {
494 _extractMode = false;
495 switch (askExtractMode)
496 {
497 case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break;
498 }
499 switch (askExtractMode)
500 {
501 case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break;
502 case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break;
503 case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break;
504 case NArchive::NExtract::NAskMode::kReadExternal: Print(kReadingString); break;
505 default:
506 Print("??? "); break;
507 }
508 Print(_filePath);
509 return S_OK;
510 }
511
Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult (Int32 operationResult))512 Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 operationResult))
513 {
514 switch (operationResult)
515 {
516 case NArchive::NExtract::NOperationResult::kOK:
517 break;
518 default:
519 {
520 NumErrors++;
521 Print(" : ");
522 const char *s = NULL;
523 switch (operationResult)
524 {
525 case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
526 s = kUnsupportedMethod;
527 break;
528 case NArchive::NExtract::NOperationResult::kCRCError:
529 s = kCRCFailed;
530 break;
531 case NArchive::NExtract::NOperationResult::kDataError:
532 s = kDataError;
533 break;
534 case NArchive::NExtract::NOperationResult::kUnavailable:
535 s = kUnavailableData;
536 break;
537 case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
538 s = kUnexpectedEnd;
539 break;
540 case NArchive::NExtract::NOperationResult::kDataAfterEnd:
541 s = kDataAfterEnd;
542 break;
543 case NArchive::NExtract::NOperationResult::kIsNotArc:
544 s = kIsNotArc;
545 break;
546 case NArchive::NExtract::NOperationResult::kHeadersError:
547 s = kHeadersError;
548 break;
549 }
550 if (s)
551 {
552 Print("Error : ");
553 Print(s);
554 }
555 else
556 {
557 char temp[16];
558 ConvertUInt32ToString((UInt32)operationResult, temp);
559 Print("Error #");
560 Print(temp);
561 }
562 }
563 }
564
565 if (_outFileStream)
566 {
567 if (_processedFileInfo.MTime.Def)
568 {
569 CFiTime ft;
570 _processedFileInfo.MTime.Write_To_FiTime(ft);
571 _outFileStreamSpec->SetMTime(&ft);
572 }
573 RINOK(_outFileStreamSpec->Close())
574 }
575 _outFileStream.Release();
576 if (_extractMode && _processedFileInfo.Attrib_Defined)
577 SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib);
578 PrintNewLine();
579 return S_OK;
580 }
581
582
Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword (BSTR * password))583 Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password))
584 {
585 if (!PasswordIsDefined)
586 {
587 #if 0
588 // You can ask real password here from user
589 RINOK(GetPassword_HRESULT(&g_StdOut, Password))
590 PasswordIsDefined = true;
591 #else
592 PrintError("Password is not defined");
593 return E_ABORT;
594 #endif
595 }
596 return StringToBstr(Password, password);
597 }
598
599
600
601 //////////////////////////////////////////////////////////////
602 // Archive Creating callback class
603
604 struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
605 {
606 UString Path_For_Handler;
607 FString FullPath; // for filesystem
608
CDirItemCDirItem609 CDirItem(const NWindows::NFile::NFind::CFileInfo &fi):
610 CFileInfoBase(fi)
611 {}
612 };
613
614 class CArchiveUpdateCallback Z7_final:
615 public IArchiveUpdateCallback2,
616 public ICryptoGetTextPassword2,
617 public CMyUnknownImp
618 {
619 Z7_IFACES_IMP_UNK_2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)
620 Z7_IFACE_COM7_IMP(IProgress)
621 Z7_IFACE_COM7_IMP(IArchiveUpdateCallback)
622
623 public:
624 CRecordVector<UInt64> VolumesSizes;
625 UString VolName;
626 UString VolExt;
627
628 FString DirPrefix;
629 const CObjectVector<CDirItem> *DirItems;
630
631 bool PasswordIsDefined;
632 UString Password;
633 bool AskPassword;
634
635 bool m_NeedBeClosed;
636
637 FStringVector FailedFiles;
638 CRecordVector<HRESULT> FailedCodes;
639
CArchiveUpdateCallback()640 CArchiveUpdateCallback():
641 DirItems(NULL),
642 PasswordIsDefined(false),
643 AskPassword(false)
644 {}
645
~CArchiveUpdateCallback()646 ~CArchiveUpdateCallback() { Finilize(); }
647 HRESULT Finilize();
648
Init(const CObjectVector<CDirItem> * dirItems)649 void Init(const CObjectVector<CDirItem> *dirItems)
650 {
651 DirItems = dirItems;
652 m_NeedBeClosed = false;
653 FailedFiles.Clear();
654 FailedCodes.Clear();
655 }
656 };
657
Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal (UInt64))658 Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 /* size */))
659 {
660 return S_OK;
661 }
662
Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted (const UInt64 *))663 Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */))
664 {
665 return S_OK;
666 }
667
Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo (UInt32,Int32 * newData,Int32 * newProperties,UInt32 * indexInArchive))668 Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */,
669 Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive))
670 {
671 if (newData)
672 *newData = BoolToInt(true);
673 if (newProperties)
674 *newProperties = BoolToInt(true);
675 if (indexInArchive)
676 *indexInArchive = (UInt32)(Int32)-1;
677 return S_OK;
678 }
679
Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))680 Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
681 {
682 NCOM::CPropVariant prop;
683
684 if (propID == kpidIsAnti)
685 {
686 prop = false;
687 prop.Detach(value);
688 return S_OK;
689 }
690
691 {
692 const CDirItem &di = (*DirItems)[index];
693 switch (propID)
694 {
695 case kpidPath: prop = di.Path_For_Handler; break;
696 case kpidIsDir: prop = di.IsDir(); break;
697 case kpidSize: prop = di.Size; break;
698 case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break;
699 case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break;
700 case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break;
701 case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break;
702 case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break;
703 }
704 }
705 prop.Detach(value);
706 return S_OK;
707 }
708
Finilize()709 HRESULT CArchiveUpdateCallback::Finilize()
710 {
711 if (m_NeedBeClosed)
712 {
713 PrintNewLine();
714 m_NeedBeClosed = false;
715 }
716 return S_OK;
717 }
718
GetStream2(const wchar_t * name)719 static void GetStream2(const wchar_t *name)
720 {
721 Print("Compressing ");
722 if (name[0] == 0)
723 name = kEmptyFileAlias;
724 Print(name);
725 }
726
Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream (UInt32 index,ISequentialInStream ** inStream))727 Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream))
728 {
729 RINOK(Finilize())
730
731 const CDirItem &dirItem = (*DirItems)[index];
732 GetStream2(dirItem.Path_For_Handler);
733
734 if (dirItem.IsDir())
735 return S_OK;
736
737 {
738 CInFileStream *inStreamSpec = new CInFileStream;
739 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
740 FString path = DirPrefix + dirItem.FullPath;
741 if (!inStreamSpec->Open(path))
742 {
743 const DWORD sysError = ::GetLastError();
744 FailedCodes.Add(HRESULT_FROM_WIN32(sysError));
745 FailedFiles.Add(path);
746 // if (systemError == ERROR_SHARING_VIOLATION)
747 {
748 PrintNewLine();
749 PrintError("WARNING: can't open file");
750 // Print(NError::MyFormatMessageW(systemError));
751 return S_FALSE;
752 }
753 // return sysError;
754 }
755 *inStream = inStreamLoc.Detach();
756 }
757 return S_OK;
758 }
759
Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult (Int32))760 Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */))
761 {
762 m_NeedBeClosed = true;
763 return S_OK;
764 }
765
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize (UInt32 index,UInt64 * size))766 Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size))
767 {
768 if (VolumesSizes.Size() == 0)
769 return S_FALSE;
770 if (index >= (UInt32)VolumesSizes.Size())
771 index = VolumesSizes.Size() - 1;
772 *size = VolumesSizes[index];
773 return S_OK;
774 }
775
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream (UInt32 index,ISequentialOutStream ** volumeStream))776 Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream))
777 {
778 wchar_t temp[16];
779 ConvertUInt32ToString(index + 1, temp);
780 UString res = temp;
781 while (res.Len() < 2)
782 res.InsertAtFront(L'0');
783 UString fileName = VolName;
784 fileName.Add_Dot();
785 fileName += res;
786 fileName += VolExt;
787 COutFileStream *streamSpec = new COutFileStream;
788 CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
789 if (!streamSpec->Create_NEW(us2fs(fileName)))
790 return GetLastError_noZero_HRESULT();
791 *volumeStream = streamLoc.Detach();
792 return S_OK;
793 }
794
Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2 (Int32 * passwordIsDefined,BSTR * password))795 Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
796 {
797 if (!PasswordIsDefined)
798 {
799 if (AskPassword)
800 {
801 #if 0
802 RINOK(GetPassword_HRESULT(&g_StdOut, Password))
803 PasswordIsDefined = true;
804 #else
805 PrintError("Password is not defined");
806 return E_ABORT;
807 #endif
808 }
809 }
810 *passwordIsDefined = BoolToInt(PasswordIsDefined);
811 return StringToBstr(Password, password);
812 }
813
814
815 // Main function
816
817 #if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
818 #define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
819 #endif
820
main(int numArgs,const char * args[])821 int Z7_CDECL main(int numArgs, const char *args[])
822 {
823 NT_CHECK
824
825 #ifdef ENV_HAVE_LOCALE
826 MY_SetLocale();
827 #endif
828
829 PrintStringLn(kCopyrightString);
830
831 if (numArgs < 2)
832 {
833 PrintStringLn(kHelpString);
834 return 0;
835 }
836
837 FString dllPrefix;
838
839 #ifdef _WIN32
840 dllPrefix = NDLL::GetModuleDirPrefix();
841 #else
842 {
843 AString s (args[0]);
844 int sep = s.ReverseFind_PathSepar();
845 s.DeleteFrom(sep + 1);
846 dllPrefix = s;
847 }
848 #endif
849
850 NDLL::CLibrary lib;
851 if (!lib.Load(dllPrefix + FTEXT(kDllName)))
852 {
853 PrintError("Cannot load 7-zip library");
854 return 1;
855 }
856
857 #if defined(__clang__)
858 #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
859 #endif
860
861 #ifdef _WIN32
862 Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION
863 #endif
864
865 Func_CreateObject
866 f_CreateObject = Z7_GET_PROC_ADDRESS(
867 Func_CreateObject, lib.Get_HMODULE(),
868 "CreateObject");
869 if (!f_CreateObject)
870 {
871 PrintError("Cannot get CreateObject");
872 return 1;
873 }
874
875 char c = 0;
876 UString password;
877 bool passwordIsDefined = false;
878 CObjectVector<FString> params;
879
880 for (int curCmd = 1; curCmd < numArgs; curCmd++)
881 {
882 AString a(args[curCmd]);
883
884 if (!a.IsEmpty())
885 {
886 if (a[0] == '-')
887 {
888 if (!passwordIsDefined && a[1] == 'p')
889 {
890 password = GetUnicodeString(a.Ptr(2));
891 passwordIsDefined = true;
892 continue;
893 }
894 }
895 else
896 {
897 if (c)
898 {
899 params.Add(CmdStringToFString(a));
900 continue;
901 }
902 if (a.Len() == 1)
903 {
904 c = (char)MyCharLower_Ascii(a[0]);
905 continue;
906 }
907 }
908 }
909 {
910 PrintError(kIncorrectCommand);
911 return 1;
912 }
913 }
914
915 if (!c || params.Size() < 1)
916 {
917 PrintError(kIncorrectCommand);
918 return 1;
919 }
920
921 const FString &archiveName = params[0];
922
923 if (c == 'a')
924 {
925 // create archive command
926 if (params.Size() < 2)
927 {
928 PrintError(kIncorrectCommand);
929 return 1;
930 }
931 CObjectVector<CDirItem> dirItems;
932 {
933 unsigned i;
934 for (i = 1; i < params.Size(); i++)
935 {
936 const FString &name = params[i];
937
938 NFind::CFileInfo fi;
939 if (!fi.Find(name))
940 {
941 PrintError("Can't find file", name);
942 return 1;
943 }
944
945 CDirItem di(fi);
946
947 di.Path_For_Handler = fs2us(name);
948 di.FullPath = name;
949 dirItems.Add(di);
950 }
951 }
952
953 COutFileStream *outFileStreamSpec = new COutFileStream;
954 CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
955 if (!outFileStreamSpec->Create_NEW(archiveName))
956 {
957 PrintError("can't create archive file");
958 return 1;
959 }
960
961 CMyComPtr<IOutArchive> outArchive;
962 if (f_CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK)
963 {
964 PrintError("Cannot get class object");
965 return 1;
966 }
967
968 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
969 CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
970 updateCallbackSpec->Init(&dirItems);
971 updateCallbackSpec->PasswordIsDefined = passwordIsDefined;
972 updateCallbackSpec->Password = password;
973
974 /*
975 {
976 const wchar_t *names[] =
977 {
978 L"m",
979 L"s",
980 L"x"
981 };
982 const unsigned kNumProps = Z7_ARRAY_SIZE(names);
983 NCOM::CPropVariant values[kNumProps] =
984 {
985 L"lzma",
986 false, // solid mode OFF
987 (UInt32)9 // compression level = 9 - ultra
988 };
989 CMyComPtr<ISetProperties> setProperties;
990 outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
991 if (!setProperties)
992 {
993 PrintError("ISetProperties unsupported");
994 return 1;
995 }
996 if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
997 {
998 PrintError("SetProperties() error");
999 return 1;
1000 }
1001 }
1002 */
1003
1004 HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback);
1005
1006 updateCallbackSpec->Finilize();
1007
1008 if (result != S_OK)
1009 {
1010 PrintError("Update Error");
1011 return 1;
1012 }
1013
1014 FOR_VECTOR (i, updateCallbackSpec->FailedFiles)
1015 {
1016 PrintNewLine();
1017 PrintError("Error for file", updateCallbackSpec->FailedFiles[i]);
1018 }
1019
1020 if (updateCallbackSpec->FailedFiles.Size() != 0)
1021 return 1;
1022 }
1023 else
1024 {
1025 if (params.Size() != 1)
1026 {
1027 PrintError(kIncorrectCommand);
1028 return 1;
1029 }
1030
1031 bool listCommand;
1032
1033 if (c == 'l')
1034 listCommand = true;
1035 else if (c == 'x')
1036 listCommand = false;
1037 else
1038 {
1039 PrintError(kIncorrectCommand);
1040 return 1;
1041 }
1042
1043 CMyComPtr<IInArchive> archive;
1044 if (f_CreateObject(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK)
1045 {
1046 PrintError("Cannot get class object");
1047 return 1;
1048 }
1049
1050 CInFileStream *fileSpec = new CInFileStream;
1051 CMyComPtr<IInStream> file = fileSpec;
1052
1053 if (!fileSpec->Open(archiveName))
1054 {
1055 PrintError("Cannot open archive file", archiveName);
1056 return 1;
1057 }
1058
1059 {
1060 CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
1061 CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
1062 openCallbackSpec->PasswordIsDefined = passwordIsDefined;
1063 openCallbackSpec->Password = password;
1064
1065 const UInt64 scanSize = 1 << 23;
1066 if (archive->Open(file, &scanSize, openCallback) != S_OK)
1067 {
1068 PrintError("Cannot open file as archive", archiveName);
1069 return 1;
1070 }
1071 }
1072
1073 if (listCommand)
1074 {
1075 // List command
1076 UInt32 numItems = 0;
1077 archive->GetNumberOfItems(&numItems);
1078 for (UInt32 i = 0; i < numItems; i++)
1079 {
1080 {
1081 // Get uncompressed size of file
1082 NCOM::CPropVariant prop;
1083 archive->GetProperty(i, kpidSize, &prop);
1084 char s[64];
1085 ConvertPropVariantToShortString(prop, s);
1086 Print(s);
1087 Print(" ");
1088 }
1089 {
1090 // Get name of file
1091 NCOM::CPropVariant prop;
1092 archive->GetProperty(i, kpidPath, &prop);
1093 if (prop.vt == VT_BSTR)
1094 Print(prop.bstrVal);
1095 else if (prop.vt != VT_EMPTY)
1096 Print("ERROR!");
1097 }
1098 PrintNewLine();
1099 }
1100 }
1101 else
1102 {
1103 // Extract command
1104 CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
1105 CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
1106 extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path
1107 extractCallbackSpec->PasswordIsDefined = passwordIsDefined;
1108 extractCallbackSpec->Password = password;
1109
1110 /*
1111 const wchar_t *names[] =
1112 {
1113 L"mt",
1114 L"mtf"
1115 };
1116 const unsigned kNumProps = sizeof(names) / sizeof(names[0]);
1117 NCOM::CPropVariant values[kNumProps] =
1118 {
1119 (UInt32)1,
1120 false
1121 };
1122 CMyComPtr<ISetProperties> setProperties;
1123 archive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
1124 if (setProperties)
1125 {
1126 if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
1127 {
1128 PrintError("SetProperties() error");
1129 return 1;
1130 }
1131 }
1132 */
1133
1134 HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
1135
1136 if (result != S_OK)
1137 {
1138 PrintError("Extract Error");
1139 return 1;
1140 }
1141 }
1142 }
1143
1144 return 0;
1145 }
1146