1 // ArchiveExtractCallback.h
2 
3 #ifndef __ARCHIVE_EXTRACT_CALLBACK_H
4 #define __ARCHIVE_EXTRACT_CALLBACK_H
5 
6 #include "../../../Common/MyCom.h"
7 #include "../../../Common/MyLinux.h"
8 #include "../../../Common/Wildcard.h"
9 
10 #include "../../IPassword.h"
11 
12 #include "../../Common/FileStreams.h"
13 #include "../../Common/ProgressUtils.h"
14 #include "../../Common/StreamObjects.h"
15 
16 #include "../../Archive/IArchive.h"
17 
18 #include "ExtractMode.h"
19 #include "IFileExtractCallback.h"
20 #include "OpenArchive.h"
21 
22 #include "HashCalc.h"
23 
24 #ifndef _SFX
25 
26 class COutStreamWithHash:
27   public ISequentialOutStream,
28   public CMyUnknownImp
29 {
30   CMyComPtr<ISequentialOutStream> _stream;
31   UInt64 _size;
32   bool _calculate;
33 public:
34   IHashCalc *_hash;
35 
36   MY_UNKNOWN_IMP
37   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
SetStream(ISequentialOutStream * stream)38   void SetStream(ISequentialOutStream *stream) { _stream = stream; }
ReleaseStream()39   void ReleaseStream() { _stream.Release(); }
40   void Init(bool calculate = true)
41   {
42     InitCRC();
43     _size = 0;
44     _calculate = calculate;
45   }
EnableCalc(bool calculate)46   void EnableCalc(bool calculate) { _calculate = calculate; }
InitCRC()47   void InitCRC() { _hash->InitForNewFile(); }
GetSize()48   UInt64 GetSize() const { return _size; }
49 };
50 
51 #endif
52 
53 struct CExtractNtOptions
54 {
55   CBoolPair NtSecurity;
56   CBoolPair SymLinks;
57   CBoolPair SymLinks_AllowDangerous;
58   CBoolPair HardLinks;
59   CBoolPair AltStreams;
60   bool ReplaceColonForAltStream;
61   bool WriteToAltStreamIfColon;
62 
63   bool PreAllocateOutFile;
64 
65   // used for hash arcs only, when we open external files
66   bool PreserveATime;
67   bool OpenShareForWrite;
68 
CExtractNtOptionsCExtractNtOptions69   CExtractNtOptions():
70       ReplaceColonForAltStream(false),
71       WriteToAltStreamIfColon(false),
72       PreserveATime(false),
73       OpenShareForWrite(false)
74   {
75     SymLinks.Val = true;
76     SymLinks_AllowDangerous.Val = false;
77     HardLinks.Val = true;
78     AltStreams.Val = true;
79 
80     PreAllocateOutFile =
81       #ifdef _WIN32
82         true;
83       #else
84         false;
85       #endif
86   }
87 };
88 
89 #ifndef _SFX
90 
91 class CGetProp:
92   public IGetProp,
93   public CMyUnknownImp
94 {
95 public:
96   const CArc *Arc;
97   UInt32 IndexInArc;
98   // UString Name; // relative path
99 
100   MY_UNKNOWN_IMP1(IGetProp)
101   INTERFACE_IGetProp(;)
102 };
103 
104 #endif
105 
106 #ifndef _SFX
107 #ifndef UNDER_CE
108 
109 #define SUPPORT_LINKS
110 
111 #endif
112 #endif
113 
114 
115 #ifdef SUPPORT_LINKS
116 
117 struct CHardLinkNode
118 {
119   UInt64 StreamId;
120   UInt64 INode;
121 
122   int Compare(const CHardLinkNode &a) const;
123 };
124 
125 class CHardLinks
126 {
127 public:
128   CRecordVector<CHardLinkNode> IDs;
129   CObjectVector<FString> Links;
130 
Clear()131   void Clear()
132   {
133     IDs.Clear();
134     Links.Clear();
135   }
136 
PrepareLinks()137   void PrepareLinks()
138   {
139     while (Links.Size() < IDs.Size())
140       Links.AddNew();
141   }
142 };
143 
144 #endif
145 
146 #ifdef SUPPORT_ALT_STREAMS
147 
148 struct CIndexToPathPair
149 {
150   UInt32 Index;
151   FString Path;
152 
CIndexToPathPairCIndexToPathPair153   CIndexToPathPair(UInt32 index): Index(index) {}
CIndexToPathPairCIndexToPathPair154   CIndexToPathPair(UInt32 index, const FString &path): Index(index), Path(path) {}
155 
CompareCIndexToPathPair156   int Compare(const CIndexToPathPair &pair) const
157   {
158     return MyCompare(Index, pair.Index);
159   }
160 };
161 
162 #endif
163 
164 
165 
166 struct CDirPathTime
167 {
168   FILETIME CTime;
169   FILETIME ATime;
170   FILETIME MTime;
171 
172   bool CTimeDefined;
173   bool ATimeDefined;
174   bool MTimeDefined;
175 
176   FString Path;
177 
178   bool SetDirTime() const;
179 };
180 
181 
182 #ifdef SUPPORT_LINKS
183 
184 struct CLinkInfo
185 {
186   // bool isCopyLink;
187   bool isHardLink;
188   bool isJunction;
189   bool isRelative;
190   bool isWSL;
191   UString linkPath;
192 
IsSymLinkCLinkInfo193   bool IsSymLink() const { return !isHardLink; }
194 
CLinkInfoCLinkInfo195   CLinkInfo():
196     // IsCopyLink(false),
197     isHardLink(false),
198     isJunction(false),
199     isRelative(false),
200     isWSL(false)
201     {}
202 
ClearCLinkInfo203   void Clear()
204   {
205     // IsCopyLink = false;
206     isHardLink = false;
207     isJunction = false;
208     isRelative = false;
209     isWSL = false;
210     linkPath.Empty();
211   }
212 
213   bool Parse(const Byte *data, size_t dataSize, bool isLinuxData);
214 };
215 
216 #endif // SUPPORT_LINKS
217 
218 
219 class CArchiveExtractCallback:
220   public IArchiveExtractCallback,
221   public IArchiveExtractCallbackMessage,
222   public ICryptoGetTextPassword,
223   public ICompressProgressInfo,
224   public IArchiveUpdateCallbackFile,
225   public IArchiveGetDiskProperty,
226   public CMyUnknownImp
227 {
228   const CArc *_arc;
229   CExtractNtOptions _ntOptions;
230 
231   const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
232   CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
233   CMyComPtr<ICompressProgressInfo> _compressProgress;
234   CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
235   CMyComPtr<IArchiveExtractCallbackMessage> _callbackMessage;
236   CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
237 
238   FString _dirPathPrefix;
239   FString _dirPathPrefix_Full;
240   NExtract::NPathMode::EEnum _pathMode;
241   NExtract::NOverwriteMode::EEnum _overwriteMode;
242   bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
243 
244   #ifndef _SFX
245 
246   CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
247   CGetProp *GetProp_Spec;
248   CMyComPtr<IGetProp> GetProp;
249 
250   #endif
251 
252   CReadArcItem _item;
253   FString _diskFilePath;
254   UInt64 _position;
255   bool _isSplit;
256 
257   bool _extractMode;
258 
259   bool WriteCTime;
260   bool WriteATime;
261   bool WriteMTime;
262 
263   bool _encrypted;
264 
265   struct CProcessedFileInfo
266   {
267     FILETIME CTime;
268     FILETIME ATime;
269     FILETIME MTime;
270     UInt32 Attrib;
271 
272     bool CTimeDefined;
273     bool ATimeDefined;
274     bool MTimeDefined;
275     bool AttribDefined;
276 
IsReparseCProcessedFileInfo277     bool IsReparse() const
278     {
279       return (AttribDefined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
280     }
281 
IsLinuxSymLinkCProcessedFileInfo282     bool IsLinuxSymLink() const
283     {
284       return (AttribDefined && MY_LIN_S_ISLNK(Attrib >> 16));
285     }
286 
SetFromPosixAttribCProcessedFileInfo287     void SetFromPosixAttrib(UInt32 a)
288     {
289       // here we set only part of combined attribute required by SetFileAttrib() call
290       #ifdef _WIN32
291       // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute.
292       Attrib = MY_LIN_S_ISDIR(a) ?
293           FILE_ATTRIBUTE_DIRECTORY :
294           FILE_ATTRIBUTE_ARCHIVE;
295       if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
296         Attrib |= FILE_ATTRIBUTE_READONLY;
297       #else
298       Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
299       #endif
300       AttribDefined = true;
301     }
302   } _fi;
303 
304   // bool _is_SymLink_in_Data;
305   bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX
306 
307   bool _needSetAttrib;
308   bool _isSymLinkCreated;
309   bool _itemFailure;
310 
311   UInt32 _index;
312   UInt64 _curSize;
313   bool _curSizeDefined;
314   bool _fileLengthWasSet;
315   UInt64 _fileLength_that_WasSet;
316 
317   COutFileStream *_outFileStreamSpec;
318   CMyComPtr<ISequentialOutStream> _outFileStream;
319 
320   CByteBuffer _outMemBuf;
321   CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec;
322   CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream;
323 
324 
325   #ifndef _SFX
326 
327   COutStreamWithHash *_hashStreamSpec;
328   CMyComPtr<ISequentialOutStream> _hashStream;
329   bool _hashStreamWasUsed;
330 
331   #endif
332 
333   bool _removePartsForAltStreams;
334   UStringVector _removePathParts;
335 
336   #ifndef _SFX
337   bool _use_baseParentFolder_mode;
338   UInt32 _baseParentFolder;
339   #endif
340 
341   bool _stdOutMode;
342   bool _testMode;
343   bool _multiArchives;
344 
345   CMyComPtr<ICompressProgressInfo> _localProgress;
346   UInt64 _packTotal;
347 
348   UInt64 _progressTotal;
349   bool _progressTotal_Defined;
350 
351   CObjectVector<CDirPathTime> _extractedFolders;
352 
353   #ifndef _WIN32
354   // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks;
355   #endif
356 
357   #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
358   bool _saclEnabled;
359   #endif
360 
361   void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
362   HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
363   HRESULT GetUnpackSize();
364 
365   FString Hash_GetFullFilePath();
366 
367   void SetAttrib();
368 
369 public:
370   HRESULT SendMessageError(const char *message, const FString &path);
371   HRESULT SendMessageError_with_LastError(const char *message, const FString &path);
372   HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2);
373 
374 public:
375 
376   CLocalProgress *LocalProgressSpec;
377 
378   UInt64 NumFolders;
379   UInt64 NumFiles;
380   UInt64 NumAltStreams;
381   UInt64 UnpackSize;
382   UInt64 AltStreams_UnpackSize;
383 
384   FString DirPathPrefix_for_HashFiles;
385 
386   MY_UNKNOWN_IMP5(
387       IArchiveExtractCallbackMessage,
388       ICryptoGetTextPassword,
389       ICompressProgressInfo,
390       IArchiveUpdateCallbackFile,
391       IArchiveGetDiskProperty
392       )
393 
394   INTERFACE_IArchiveExtractCallback(;)
395   INTERFACE_IArchiveExtractCallbackMessage(;)
396   INTERFACE_IArchiveUpdateCallbackFile(;)
397   INTERFACE_IArchiveGetDiskProperty(;)
398 
399   STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
400 
401   STDMETHOD(CryptoGetTextPassword)(BSTR *password);
402 
403   CArchiveExtractCallback();
404 
InitForMulti(bool multiArchives,NExtract::NPathMode::EEnum pathMode,NExtract::NOverwriteMode::EEnum overwriteMode,bool keepAndReplaceEmptyDirPrefixes)405   void InitForMulti(bool multiArchives,
406       NExtract::NPathMode::EEnum pathMode,
407       NExtract::NOverwriteMode::EEnum overwriteMode,
408       bool keepAndReplaceEmptyDirPrefixes)
409   {
410     _multiArchives = multiArchives;
411     _pathMode = pathMode;
412     _overwriteMode = overwriteMode;
413     _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;
414     NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
415   }
416 
417   #ifndef _SFX
418 
SetHashMethods(IHashCalc * hash)419   void SetHashMethods(IHashCalc *hash)
420   {
421     if (!hash)
422       return;
423     _hashStreamSpec = new COutStreamWithHash;
424     _hashStream = _hashStreamSpec;
425     _hashStreamSpec->_hash = hash;
426   }
427 
428   #endif
429 
430   void Init(
431       const CExtractNtOptions &ntOptions,
432       const NWildcard::CCensorNode *wildcardCensor,
433       const CArc *arc,
434       IFolderArchiveExtractCallback *extractCallback2,
435       bool stdOutMode, bool testMode,
436       const FString &directoryPath,
437       const UStringVector &removePathParts, bool removePartsForAltStreams,
438       UInt64 packSize);
439 
440 
441   #ifdef SUPPORT_LINKS
442 
443 private:
444   CHardLinks _hardLinks;
445   CLinkInfo _link;
446 
447   // FString _CopyFile_Path;
448   // HRESULT MyCopyFile(ISequentialOutStream *outStream);
449   HRESULT Link(const FString &fullProcessedPath);
450   HRESULT ReadLink();
451 
452 public:
453   // call PrepareHardLinks() after Init()
454   HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices);  // NULL means all items
455 
456   #endif
457 
458 
459   #ifdef SUPPORT_ALT_STREAMS
460   CObjectVector<CIndexToPathPair> _renamedFiles;
461   #endif
462 
463   // call it after Init()
464 
465   #ifndef _SFX
SetBaseParentFolderIndex(UInt32 indexInArc)466   void SetBaseParentFolderIndex(UInt32 indexInArc)
467   {
468     _baseParentFolder = indexInArc;
469     _use_baseParentFolder_mode = true;
470   }
471   #endif
472 
473   HRESULT CloseArc();
474 
475 private:
ClearExtractedDirsInfo()476   void ClearExtractedDirsInfo()
477   {
478     _extractedFolders.Clear();
479     #ifndef _WIN32
480     // _delayedSymLinks.Clear();
481     #endif
482   }
483 
484   HRESULT Read_fi_Props();
485   void CorrectPathParts();
486   void CreateFolders();
487 
488   bool _isRenamed;
489   HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit);
490   HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit);
491   HRESULT GetItem(UInt32 index);
492 
493   HRESULT CloseFile();
494   HRESULT CloseReparseAndFile();
495   HRESULT CloseReparseAndFile2();
496   HRESULT SetDirsTimes();
497 
498   const void *NtReparse_Data;
499   UInt32 NtReparse_Size;
500 
501   #ifdef SUPPORT_LINKS
502   HRESULT SetFromLinkPath(
503       const FString &fullProcessedPath,
504       const CLinkInfo &linkInfo,
505       bool &linkWasSet);
506   #endif
507 };
508 
509 
510 struct CArchiveExtractCallback_Closer
511 {
512   CArchiveExtractCallback *_ref;
513 
CArchiveExtractCallback_CloserCArchiveExtractCallback_Closer514   CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {}
515 
CloseCArchiveExtractCallback_Closer516   HRESULT Close()
517   {
518     HRESULT res = S_OK;
519     if (_ref)
520     {
521       res = _ref->CloseArc();
522       _ref = NULL;
523     }
524     return res;
525   }
526 
~CArchiveExtractCallback_CloserCArchiveExtractCallback_Closer527   ~CArchiveExtractCallback_Closer()
528   {
529     Close();
530   }
531 };
532 
533 
534 bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
535 
536 #endif
537