xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Common/UpdateCallback.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // UpdateCallback.cpp
2 
3 #include "StdAfx.h"
4 
5 // #include <stdio.h>
6 
7 #ifndef _WIN32
8 // #include <grp.h>
9 // #include <pwd.h>
10 // for major()/minor():
11 #if defined(__APPLE__) || defined(__DragonFly__) || \
12     defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
13 #include <sys/types.h>
14 #else
15 #include <sys/sysmacros.h>
16 #endif
17 
18 #endif // _WIN32
19 
20 #ifndef Z7_ST
21 #include "../../../Windows/Synchronization.h"
22 #endif
23 
24 #include "../../../Common/ComTry.h"
25 #include "../../../Common/IntToString.h"
26 #include "../../../Common/StringConvert.h"
27 #include "../../../Common/Wildcard.h"
28 #include "../../../Common/UTFConvert.h"
29 
30 #include "../../../Windows/FileDir.h"
31 #include "../../../Windows/FileName.h"
32 #include "../../../Windows/PropVariant.h"
33 
34 #include "../../Common/StreamObjects.h"
35 
36 #include "UpdateCallback.h"
37 
38 #if defined(_WIN32) && !defined(UNDER_CE)
39 #define Z7_USE_SECURITY_CODE
40 #include "../../../Windows/SecurityUtils.h"
41 #endif
42 
43 using namespace NWindows;
44 using namespace NFile;
45 
46 #ifndef Z7_ST
47 static NSynchronization::CCriticalSection g_CriticalSection;
48 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
49 #else
50 #define MT_LOCK
51 #endif
52 
53 
54 #ifdef Z7_USE_SECURITY_CODE
55 bool InitLocalPrivileges();
56 #endif
57 
CArchiveUpdateCallback()58 CArchiveUpdateCallback::CArchiveUpdateCallback():
59     PreserveATime(false),
60     ShareForWrite(false),
61     StopAfterOpenError(false),
62     StdInMode(false),
63 
64     KeepOriginalItemNames(false),
65     StoreNtSecurity(false),
66     StoreHardLinks(false),
67     StoreSymLinks(false),
68 
69    #ifndef _WIN32
70     StoreOwnerId(false),
71     StoreOwnerName(false),
72    #endif
73 
74     /*
75     , Need_ArcMTime_Report(false),
76     , ArcMTime_WasReported(false),
77     */
78     Need_LatestMTime(false),
79     LatestMTime_Defined(false),
80 
81     Callback(NULL),
82 
83     DirItems(NULL),
84     ParentDirItem(NULL),
85 
86     Arc(NULL),
87     ArcItems(NULL),
88     UpdatePairs(NULL),
89     NewNames(NULL),
90     Comment(NULL),
91     CommentIndex(-1),
92 
93     ProcessedItemsStatuses(NULL),
94     _hardIndex_From((UInt32)(Int32)-1)
95 {
96   #ifdef Z7_USE_SECURITY_CODE
97   _saclEnabled = InitLocalPrivileges();
98   #endif
99 }
100 
101 
Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal (UInt64 size))102 Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 size))
103 {
104   COM_TRY_BEGIN
105   return Callback->SetTotal(size);
106   COM_TRY_END
107 }
108 
Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted (const UInt64 * completeValue))109 Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue))
110 {
111   COM_TRY_BEGIN
112   return Callback->SetCompleted(completeValue);
113   COM_TRY_END
114 }
115 
Z7_COM7F_IMF(CArchiveUpdateCallback::SetRatioInfo (const UInt64 * inSize,const UInt64 * outSize))116 Z7_COM7F_IMF(CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
117 {
118   COM_TRY_BEGIN
119   return Callback->SetRatioInfo(inSize, outSize);
120   COM_TRY_END
121 }
122 
123 
124 /*
125 static const CStatProp kProps[] =
126 {
127   { NULL, kpidPath, VT_BSTR},
128   { NULL, kpidIsDir, VT_BOOL},
129   { NULL, kpidSize, VT_UI8},
130   { NULL, kpidCTime, VT_FILETIME},
131   { NULL, kpidATime, VT_FILETIME},
132   { NULL, kpidMTime, VT_FILETIME},
133   { NULL, kpidAttrib, VT_UI4},
134   { NULL, kpidIsAnti, VT_BOOL}
135 };
136 
137 Z7_COM7F_IMF(CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
138 {
139   return CStatPropEnumerator::CreateEnumerator(kProps, Z7_ARRAY_SIZE(kProps), enumerator);
140 }
141 */
142 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo (UInt32 index,Int32 * newData,Int32 * newProps,UInt32 * indexInArchive))143 Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
144       Int32 *newData, Int32 *newProps, UInt32 *indexInArchive))
145 {
146   COM_TRY_BEGIN
147   RINOK(Callback->CheckBreak())
148   const CUpdatePair2 &up = (*UpdatePairs)[index];
149   if (newData) *newData = BoolToInt(up.NewData);
150   if (newProps) *newProps = BoolToInt(up.NewProps);
151   if (indexInArchive)
152   {
153     *indexInArchive = (UInt32)(Int32)-1;
154     if (up.ExistInArchive())
155       *indexInArchive = ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex;
156   }
157   return S_OK;
158   COM_TRY_END
159 }
160 
161 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootProp (PROPID propID,PROPVARIANT * value))162 Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value))
163 {
164   NCOM::CPropVariant prop;
165   switch (propID)
166   {
167     case kpidIsDir:  prop = true; break;
168     case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->GetWinAttrib(); break;
169     case kpidCTime:  if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->CTime); break;
170     case kpidATime:  if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->ATime); break;
171     case kpidMTime:  if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->MTime); break;
172     case kpidArcFileName:  if (!ArcFileName.IsEmpty()) prop = ArcFileName; break;
173     default: break;
174   }
175   prop.Detach(value);
176   return S_OK;
177 }
178 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetParent (UInt32,UInt32 * parent,UInt32 * parentType))179 Z7_COM7F_IMF(CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType))
180 {
181   *parentType = NParentType::kDir;
182   *parent = (UInt32)(Int32)-1;
183   return S_OK;
184 }
185 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetNumRawProps (UInt32 * numProps))186 Z7_COM7F_IMF(CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps))
187 {
188   *numProps = 0;
189   if (StoreNtSecurity)
190     *numProps = 1;
191   return S_OK;
192 }
193 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawPropInfo (UInt32,BSTR * name,PROPID * propID))194 Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
195 {
196   *name = NULL;
197   *propID = kpidNtSecure;
198   return S_OK;
199 }
200 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootRawProp (PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType))201 Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootRawProp(PROPID
202     propID
203     , const void **data, UInt32 *dataSize, UInt32 *propType))
204 {
205   #ifndef Z7_USE_SECURITY_CODE
206   UNUSED_VAR(propID)
207   #endif
208 
209   *data = NULL;
210   *dataSize = 0;
211   *propType = 0;
212   if (!StoreNtSecurity)
213     return S_OK;
214   #ifdef Z7_USE_SECURITY_CODE
215   if (propID == kpidNtSecure)
216   {
217     if (StdInMode)
218       return S_OK;
219 
220     if (ParentDirItem)
221     {
222       if (ParentDirItem->SecureIndex < 0)
223         return S_OK;
224       const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)ParentDirItem->SecureIndex];
225       *data = buf;
226       *dataSize = (UInt32)buf.Size();
227       *propType = NPropDataType::kRaw;
228       return S_OK;
229     }
230 
231     if (Arc && Arc->GetRootProps)
232       return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType);
233   }
234   #endif
235   return S_OK;
236 }
237 
238 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp (UInt32 index,PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType))239 Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
240 {
241   *data = NULL;
242   *dataSize = 0;
243   *propType = 0;
244 
245   if (propID == kpidNtSecure ||
246       propID == kpidNtReparse)
247   {
248     if (StdInMode)
249       return S_OK;
250 
251     const CUpdatePair2 &up = (*UpdatePairs)[index];
252     if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps)
253       return Arc->GetRawProps->GetRawProp(
254           ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex,
255           propID, data, dataSize, propType);
256     {
257       /*
258       if (!up.NewData)
259         return E_FAIL;
260       */
261       if (up.IsAnti)
262         return S_OK;
263 
264       #if defined(_WIN32) && !defined(UNDER_CE)
265       const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
266       #endif
267 
268       #ifdef Z7_USE_SECURITY_CODE
269       if (propID == kpidNtSecure)
270       {
271         if (!StoreNtSecurity)
272           return S_OK;
273         if (di.SecureIndex < 0)
274           return S_OK;
275         const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)di.SecureIndex];
276         *data = buf;
277         *dataSize = (UInt32)buf.Size();
278         *propType = NPropDataType::kRaw;
279       }
280       else
281       #endif
282       if (propID == kpidNtReparse)
283       {
284         if (!StoreSymLinks)
285           return S_OK;
286         #if defined(_WIN32) && !defined(UNDER_CE)
287         // we use ReparseData2 instead of ReparseData for WIM format
288         const CByteBuffer *buf = &di.ReparseData2;
289         if (buf->Size() == 0)
290           buf = &di.ReparseData;
291         if (buf->Size() != 0)
292         {
293           *data = *buf;
294           *dataSize = (UInt32)buf->Size();
295           *propType = NPropDataType::kRaw;
296         }
297         #endif
298       }
299 
300       return S_OK;
301     }
302   }
303 
304   return S_OK;
305 }
306 
307 #if defined(_WIN32) && !defined(UNDER_CE)
308 
GetRelativePath(const UString & to,const UString & from)309 static UString GetRelativePath(const UString &to, const UString &from)
310 {
311   UStringVector partsTo, partsFrom;
312   SplitPathToParts(to, partsTo);
313   SplitPathToParts(from, partsFrom);
314 
315   unsigned i;
316   for (i = 0;; i++)
317   {
318     if (i + 1 >= partsFrom.Size() ||
319         i + 1 >= partsTo.Size())
320       break;
321     if (CompareFileNames(partsFrom[i], partsTo[i]) != 0)
322       break;
323   }
324 
325   if (i == 0)
326   {
327     #ifdef _WIN32
328     if (NName::IsDrivePath(to) ||
329         NName::IsDrivePath(from))
330       return to;
331     #endif
332   }
333 
334   UString s;
335   unsigned k;
336 
337   for (k = i + 1; k < partsFrom.Size(); k++)
338     s += ".." STRING_PATH_SEPARATOR;
339 
340   for (k = i; k < partsTo.Size(); k++)
341   {
342     if (k != i)
343       s.Add_PathSepar();
344     s += partsTo[k];
345   }
346 
347   return s;
348 }
349 
350 #endif
351 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))352 Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
353 {
354   COM_TRY_BEGIN
355   const CUpdatePair2 &up = (*UpdatePairs)[index];
356   NCOM::CPropVariant prop;
357 
358   if (up.NewData)
359   {
360     /*
361     if (propID == kpidIsHardLink)
362     {
363       prop = _isHardLink;
364       prop.Detach(value);
365       return S_OK;
366     }
367     */
368     if (propID == kpidSymLink)
369     {
370       if (index == _hardIndex_From)
371       {
372         prop.Detach(value);
373         return S_OK;
374       }
375 
376       #if !defined(UNDER_CE)
377 
378       if (up.DirIndex >= 0)
379       {
380         const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
381 
382         #ifdef _WIN32
383         // if (di.IsDir())
384         {
385           CReparseAttr attr;
386           if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
387           {
388             const UString simpleName = attr.GetPath();
389             if (!attr.IsSymLink_WSL() && attr.IsRelative_Win())
390               prop = simpleName;
391             else
392             {
393               const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex);
394               FString fullPath;
395               if (NDir::MyGetFullPathName(phyPath, fullPath))
396               {
397                 prop = GetRelativePath(simpleName, fs2us(fullPath));
398               }
399             }
400             prop.Detach(value);
401             return S_OK;
402           }
403         }
404 
405         #else // _WIN32
406 
407         if (di.ReparseData.Size() != 0)
408         {
409           AString utf;
410           utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size());
411 
412           UString us;
413           if (ConvertUTF8ToUnicode(utf, us))
414           {
415             prop = us;
416             prop.Detach(value);
417             return S_OK;
418           }
419         }
420 
421         #endif // _WIN32
422       }
423       #endif // !defined(UNDER_CE)
424     }
425     else if (propID == kpidHardLink)
426     {
427       if (index == _hardIndex_From)
428       {
429         const CKeyKeyValPair &pair = _map[_hardIndex_To];
430         const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
431         prop = DirItems->GetLogPath((unsigned)up2.DirIndex);
432         prop.Detach(value);
433         return S_OK;
434       }
435       if (up.DirIndex >= 0)
436       {
437         prop.Detach(value);
438         return S_OK;
439       }
440     }
441   }
442 
443   if (up.IsAnti
444       && propID != kpidIsDir
445       && propID != kpidPath
446       && propID != kpidIsAltStream)
447   {
448     switch (propID)
449     {
450       case kpidSize:  prop = (UInt64)0; break;
451       case kpidIsAnti:  prop = true; break;
452       default: break;
453     }
454   }
455   else if (propID == kpidPath && up.NewNameIndex >= 0)
456     prop = (*NewNames)[(unsigned)up.NewNameIndex];
457   else if (propID == kpidComment
458       && CommentIndex >= 0
459       && (unsigned)CommentIndex == index
460       && Comment)
461     prop = *Comment;
462   else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem)
463   {
464     // we can generate new ShortName here;
465   }
466   else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream)))
467       && up.ExistInArchive() && Archive)
468     return Archive->GetProperty(ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, propID, value);
469   else if (up.ExistOnDisk())
470   {
471     const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
472     switch (propID)
473     {
474       case kpidPath:  prop = DirItems->GetLogPath((unsigned)up.DirIndex); break;
475       case kpidIsDir:  prop = di.IsDir(); break;
476       case kpidSize:  prop = (UInt64)(di.IsDir() ? (UInt64)0 : di.Size); break;
477       case kpidCTime:  PropVariant_SetFrom_FiTime(prop, di.CTime); break;
478       case kpidATime:  PropVariant_SetFrom_FiTime(prop, di.ATime); break;
479       case kpidMTime:  PropVariant_SetFrom_FiTime(prop, di.MTime); break;
480       case kpidAttrib:  /* if (di.Attrib_IsDefined) */ prop = (UInt32)di.GetWinAttrib(); break;
481       case kpidPosixAttrib: /* if (di.Attrib_IsDefined) */ prop = (UInt32)di.GetPosixAttrib(); break;
482 
483     #if defined(_WIN32)
484       case kpidIsAltStream:  prop = di.IsAltStream; break;
485       // case kpidShortName:  prop = di.ShortName; break;
486     #else
487 
488         #if defined(__APPLE__)
489         #pragma GCC diagnostic push
490         #pragma GCC diagnostic ignored "-Wsign-conversion"
491         #endif
492 
493       case kpidDeviceMajor:
494         /*
495         printf("\ndi.mode = %o\n", di.mode);
496         printf("\nst.st_rdev major = %d\n", (unsigned)major(di.rdev));
497         printf("\nst.st_rdev minor = %d\n", (unsigned)minor(di.rdev));
498         */
499         if (S_ISCHR(di.mode) || S_ISBLK(di.mode))
500           prop = (UInt32)major(di.rdev);
501         break;
502 
503       case kpidDeviceMinor:
504         if (S_ISCHR(di.mode) || S_ISBLK(di.mode))
505           prop = (UInt32)minor(di.rdev);
506         break;
507 
508         #if defined(__APPLE__)
509         #pragma GCC diagnostic pop
510         #endif
511 
512       // case kpidDevice: if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) prop = (UInt64)(di.rdev); break;
513 
514       case kpidUserId:  if (StoreOwnerId) prop = (UInt32)di.uid; break;
515       case kpidGroupId: if (StoreOwnerId) prop = (UInt32)di.gid; break;
516       case kpidUser:
517         if (di.OwnerNameIndex >= 0)
518           prop = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex];
519         break;
520       case kpidGroup:
521         if (di.OwnerGroupIndex >= 0)
522           prop = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex];
523         break;
524      #endif
525       default: break;
526     }
527   }
528   prop.Detach(value);
529   return S_OK;
530   COM_TRY_END
531 }
532 
533 #ifndef Z7_ST
534 static NSynchronization::CCriticalSection g_CS;
535 #endif
536 
UpdateProcessedItemStatus(unsigned dirIndex)537 void CArchiveUpdateCallback::UpdateProcessedItemStatus(unsigned dirIndex)
538 {
539   if (ProcessedItemsStatuses)
540   {
541     #ifndef Z7_ST
542     NSynchronization::CCriticalSectionLock lock(g_CS);
543     #endif
544     ProcessedItemsStatuses[dirIndex] = 1;
545   }
546 }
547 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream2 (UInt32 index,ISequentialInStream ** inStream,UInt32 mode))548 Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode))
549 {
550   COM_TRY_BEGIN
551   *inStream = NULL;
552   const CUpdatePair2 &up = (*UpdatePairs)[index];
553   if (!up.NewData)
554     return E_FAIL;
555 
556   RINOK(Callback->CheckBreak())
557   // RINOK(Callback->Finalize());
558 
559   bool isDir = IsDir(up);
560 
561   if (up.IsAnti)
562   {
563     UString name;
564     if (up.ArcIndex >= 0)
565       name = (*ArcItems)[(unsigned)up.ArcIndex].Name;
566     else if (up.DirIndex >= 0)
567       name = DirItems->GetLogPath((unsigned)up.DirIndex);
568     RINOK(Callback->GetStream(name, isDir, true, mode))
569 
570     /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file.
571        so we return empty stream */
572 
573     if (!isDir)
574     {
575       CBufInStream *inStreamSpec = new CBufInStream();
576       CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
577       inStreamSpec->Init(NULL, 0);
578       *inStream = inStreamLoc.Detach();
579     }
580     return S_OK;
581   }
582 
583   RINOK(Callback->GetStream(DirItems->GetLogPath((unsigned)up.DirIndex), isDir, false, mode))
584 
585   if (isDir)
586     return S_OK;
587 
588   if (StdInMode)
589   {
590     if (mode != NUpdateNotifyOp::kAdd &&
591         mode != NUpdateNotifyOp::kUpdate)
592       return S_OK;
593 
594 #if 1
595     CStdInFileStream *inStreamSpec = new CStdInFileStream;
596     CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
597 #else
598     CMyComPtr<ISequentialInStream> inStreamLoc;
599     if (!CreateStdInStream(inStreamLoc))
600       return GetLastError_noZero_HRESULT();
601 #endif
602     *inStream = inStreamLoc.Detach();
603   }
604   else
605   {
606     #if !defined(UNDER_CE)
607     const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
608     if (di.AreReparseData())
609     {
610       /*
611       // we still need DeviceIoControlOut() instead of Read
612       if (!inStreamSpec->File.OpenReparse(path))
613       {
614         return Callback->OpenFileError(path, ::GetLastError());
615       }
616       */
617       // 20.03: we use Reparse Data instead of real data
618 
619       CBufInStream *inStreamSpec = new CBufInStream();
620       CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
621       inStreamSpec->Init(di.ReparseData, di.ReparseData.Size());
622       *inStream = inStreamLoc.Detach();
623 
624       UpdateProcessedItemStatus((unsigned)up.DirIndex);
625       return S_OK;
626     }
627     #endif // !defined(UNDER_CE)
628 
629     CInFileStream *inStreamSpec = new CInFileStream;
630     CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
631 
632    /*
633    // for debug:
634    #ifdef _WIN32
635     inStreamSpec->StoreOwnerName = true;
636     inStreamSpec->OwnerName = "user_name";
637     inStreamSpec->OwnerName += di.Name;
638     inStreamSpec->OwnerName += "11111111112222222222222333333333333";
639     inStreamSpec->OwnerGroup = "gname_";
640     inStreamSpec->OwnerGroup += inStreamSpec->OwnerName;
641    #endif
642    */
643 
644    #ifndef _WIN32
645     inStreamSpec->StoreOwnerId = StoreOwnerId;
646     inStreamSpec->StoreOwnerName = StoreOwnerName;
647 
648     // if (StoreOwner)
649     {
650       inStreamSpec->_uid = di.uid;
651       inStreamSpec->_gid = di.gid;
652       if (di.OwnerNameIndex >= 0)
653         inStreamSpec->OwnerName = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex];
654       if (di.OwnerGroupIndex >= 0)
655         inStreamSpec->OwnerGroup = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex];
656     }
657    #endif
658 
659     inStreamSpec->SupportHardLinks = StoreHardLinks;
660     const bool preserveATime = (PreserveATime
661         || mode == NUpdateNotifyOp::kAnalyze);   // 22.00 : we don't change access time in Analyze pass.
662     inStreamSpec->Set_PreserveATime(preserveATime);
663 
664     const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex);
665     _openFiles_Indexes.Add(index);
666     _openFiles_Paths.Add(path);
667     // _openFiles_Streams.Add(inStreamSpec);
668 
669     /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding
670        for correct working if exception was raised in GetPhyPath */
671     inStreamSpec->Callback = this;
672     inStreamSpec->CallbackRef = index;
673 
674     if (!inStreamSpec->OpenShared(path, ShareForWrite))
675     {
676       bool isOpen = false;
677       if (preserveATime)
678       {
679         inStreamSpec->Set_PreserveATime(false);
680         isOpen = inStreamSpec->OpenShared(path, ShareForWrite);
681       }
682       if (!isOpen)
683       {
684         const DWORD error = ::GetLastError();
685         const HRESULT hres = Callback->OpenFileError(path, error);
686         if (hres == S_OK || hres == S_FALSE)
687         if (StopAfterOpenError ||
688             // v23: we check also for some critical errors:
689             #ifdef _WIN32
690               error == ERROR_NO_SYSTEM_RESOURCES
691             #else
692               error == EMFILE
693             #endif
694             )
695         {
696           if (error == 0)
697             return E_FAIL;
698           return HRESULT_FROM_WIN32(error);
699         }
700         return hres;
701       }
702     }
703 
704     /*
705     {
706       // for debug:
707       Byte b = 0;
708       UInt32 processedSize = 0;
709       if (inStreamSpec->Read(&b, 1, &processedSize) != S_OK ||
710           processedSize != 1)
711         return E_FAIL;
712     }
713     */
714 
715     if (Need_LatestMTime)
716     {
717       inStreamSpec->ReloadProps();
718     }
719 
720     // #if defined(Z7_FILE_STREAMS_USE_WIN_FILE) || !defined(_WIN32)
721     if (StoreHardLinks)
722     {
723       CStreamFileProps props;
724       if (inStreamSpec->GetProps2(&props) == S_OK)
725       {
726         if (props.NumLinks > 1)
727         {
728           CKeyKeyValPair pair;
729           pair.Key1 = props.VolID;
730           pair.Key2 = props.FileID_Low;
731           pair.Value = index;
732           const unsigned numItems = _map.Size();
733           const unsigned pairIndex = _map.AddToUniqueSorted2(pair);
734           if (numItems == _map.Size())
735           {
736             // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex];
737             _hardIndex_From = index;
738             _hardIndex_To = pairIndex;
739             // we could return NULL as stream, but it's better to return real stream
740             // return S_OK;
741           }
742         }
743       }
744     }
745     // #endif
746 
747     UpdateProcessedItemStatus((unsigned)up.DirIndex);
748     *inStream = inStreamLoc.Detach();
749   }
750 
751   return S_OK;
752   COM_TRY_END
753 }
754 
Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult (Int32 opRes))755 Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 opRes))
756 {
757   COM_TRY_BEGIN
758   return Callback->SetOperationResult(opRes);
759   COM_TRY_END
760 }
761 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream (UInt32 index,ISequentialInStream ** inStream))762 Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream))
763 {
764   COM_TRY_BEGIN
765   return GetStream2(index, inStream,
766       (*UpdatePairs)[index].ArcIndex < 0 ?
767           NUpdateNotifyOp::kAdd :
768           NUpdateNotifyOp::kUpdate);
769   COM_TRY_END
770 }
771 
Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation (UInt32 indexType,UInt32 index,UInt32 op))772 Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op))
773 {
774   COM_TRY_BEGIN
775 
776   // if (op == NUpdateNotifyOp::kOpFinished) return Callback->ReportFinished(indexType, index);
777 
778   bool isDir = false;
779 
780   if (indexType == NArchive::NEventIndexType::kOutArcIndex)
781   {
782     UString name;
783     if (index != (UInt32)(Int32)-1)
784     {
785       const CUpdatePair2 &up = (*UpdatePairs)[index];
786       if (up.ExistOnDisk())
787       {
788         name = DirItems->GetLogPath((unsigned)up.DirIndex);
789         isDir = DirItems->Items[(unsigned)up.DirIndex].IsDir();
790       }
791     }
792     return Callback->ReportUpdateOperation(op, name.IsEmpty() ? NULL : name.Ptr(), isDir);
793   }
794 
795   wchar_t temp[16];
796   UString s2;
797   const wchar_t *s = NULL;
798 
799   if (indexType == NArchive::NEventIndexType::kInArcIndex)
800   {
801     if (index != (UInt32)(Int32)-1)
802     {
803       if (ArcItems)
804       {
805         const CArcItem &ai = (*ArcItems)[index];
806         s = ai.Name;
807         isDir = ai.IsDir;
808       }
809       else if (Arc)
810       {
811         RINOK(Arc->GetItem_Path(index, s2))
812         s = s2;
813         RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir))
814       }
815     }
816   }
817   else if (indexType == NArchive::NEventIndexType::kBlockIndex)
818   {
819     temp[0] = '#';
820     ConvertUInt32ToString(index, temp + 1);
821     s = temp;
822   }
823 
824   if (!s)
825     s = L"";
826 
827   return Callback->ReportUpdateOperation(op, s, isDir);
828 
829   COM_TRY_END
830 }
831 
Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult (UInt32 indexType,UInt32 index,Int32 opRes))832 Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes))
833 {
834   COM_TRY_BEGIN
835 
836   bool isEncrypted = false;
837   wchar_t temp[16];
838   UString s2;
839   const wchar_t *s = NULL;
840 
841   if (indexType == NArchive::NEventIndexType::kOutArcIndex)
842   {
843     /*
844     UString name;
845     if (index != (UInt32)(Int32)-1)
846     {
847       const CUpdatePair2 &up = (*UpdatePairs)[index];
848       if (up.ExistOnDisk())
849       {
850         s2 = DirItems->GetLogPath(up.DirIndex);
851         s = s2;
852       }
853     }
854     */
855     return E_FAIL;
856   }
857 
858   if (indexType == NArchive::NEventIndexType::kInArcIndex)
859   {
860     if (index != (UInt32)(Int32)-1)
861     {
862       if (ArcItems)
863         s = (*ArcItems)[index].Name;
864       else if (Arc)
865       {
866         RINOK(Arc->GetItem_Path(index, s2))
867         s = s2;
868       }
869       if (Archive)
870       {
871         RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted))
872       }
873     }
874   }
875   else if (indexType == NArchive::NEventIndexType::kBlockIndex)
876   {
877     temp[0] = '#';
878     ConvertUInt32ToString(index, temp + 1);
879     s = temp;
880   }
881 
882   return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s);
883 
884   COM_TRY_END
885 }
886 
887 
888 /*
889 Z7_COM7F_IMF(CArchiveUpdateCallback::DoNeedArcProp(PROPID propID, Int32 *answer))
890 {
891   *answer = 0;
892   if (Need_ArcMTime_Report && propID == kpidComboMTime)
893     *answer = 1;
894   return S_OK;
895 }
896 
897 Z7_COM7F_IMF(CArchiveUpdateCallback::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value))
898 {
899   if (indexType == NArchive::NEventIndexType::kArcProp)
900   {
901     if (propID == kpidComboMTime)
902     {
903       ArcMTime_WasReported = true;
904       if (value->vt == VT_FILETIME)
905       {
906         Reported_ArcMTime.Set_From_Prop(*value);
907         Reported_ArcMTime.Def = true;
908       }
909       else
910       {
911         Reported_ArcMTime.Clear();
912         if (value->vt != VT_EMPTY)
913           return E_FAIL; // for debug
914       }
915     }
916   }
917   return Callback->ReportProp(indexType, index, propID, value);
918 }
919 
920 Z7_COM7F_IMF(CArchiveUpdateCallback::ReportRawProp(UInt32 indexType, UInt32 index,
921     PROPID propID, const void *data, UInt32 dataSize, UInt32 propType))
922 {
923   return Callback->ReportRawProp(indexType, index, propID, data, dataSize, propType);
924 }
925 
926 Z7_COM7F_IMF(CArchiveUpdateCallback::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes))
927 {
928   return Callback->ReportFinished(indexType, index, opRes);
929 }
930 */
931 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize (UInt32 index,UInt64 * size))932 Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size))
933 {
934   if (VolumesSizes.Size() == 0)
935     return S_FALSE;
936   if (index >= (UInt32)VolumesSizes.Size())
937     index = VolumesSizes.Size() - 1;
938   *size = VolumesSizes[index];
939   return S_OK;
940 }
941 
Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream (UInt32 index,ISequentialOutStream ** volumeStream))942 Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream))
943 {
944   COM_TRY_BEGIN
945   char temp[16];
946   ConvertUInt32ToString(index + 1, temp);
947   FString res (temp);
948   while (res.Len() < 2)
949     res.InsertAtFront(FTEXT('0'));
950   FString fileName = VolName;
951   fileName.Add_Dot();
952   fileName += res;
953   fileName += VolExt;
954   COutFileStream *streamSpec = new COutFileStream;
955   CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
956   if (!streamSpec->Create_NEW(fileName))
957     return GetLastError_noZero_HRESULT();
958   *volumeStream = streamLoc.Detach();
959   return S_OK;
960   COM_TRY_END
961 }
962 
Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2 (Int32 * passwordIsDefined,BSTR * password))963 Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
964 {
965   COM_TRY_BEGIN
966   return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
967   COM_TRY_END
968 }
969 
Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword (BSTR * password))970 Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password))
971 {
972   COM_TRY_BEGIN
973   return Callback->CryptoGetTextPassword(password);
974   COM_TRY_END
975 }
976 
InFileStream_On_Error(UINT_PTR val,DWORD error)977 HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
978 {
979   #ifdef _WIN32 // FIX IT !!!
980   // why did we check only for ERROR_LOCK_VIOLATION ?
981   // if (error == ERROR_LOCK_VIOLATION)
982   #endif
983   {
984     MT_LOCK
985     const UInt32 index = (UInt32)val;
986     FOR_VECTOR(i, _openFiles_Indexes)
987     {
988       if (_openFiles_Indexes[i] == index)
989       {
990         RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error))
991         break;
992       }
993     }
994   }
995   return HRESULT_FROM_WIN32(error);
996 }
997 
InFileStream_On_Destroy(CInFileStream * stream,UINT_PTR val)998 void CArchiveUpdateCallback::InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val)
999 {
1000   MT_LOCK
1001   if (Need_LatestMTime)
1002   {
1003     if (stream->_info_WasLoaded)
1004     {
1005       const CFiTime &ft = ST_MTIME(stream->_info);
1006       if (!LatestMTime_Defined
1007           || Compare_FiTime(&LatestMTime, &ft) < 0)
1008         LatestMTime = ft;
1009       LatestMTime_Defined = true;
1010     }
1011   }
1012   const UInt32 index = (UInt32)val;
1013   FOR_VECTOR(i, _openFiles_Indexes)
1014   {
1015     if (_openFiles_Indexes[i] == index)
1016     {
1017       _openFiles_Indexes.Delete(i);
1018       _openFiles_Paths.Delete(i);
1019       // _openFiles_Streams.Delete(i);
1020       return;
1021     }
1022   }
1023   /* 21.02 : this function can be called in destructor.
1024      And destructor can be called after some exception.
1025      If we don't want to throw exception in desctructors or after another exceptions,
1026      we must disable the code below that raises new exception.
1027   */
1028   // throw 20141125;
1029 }
1030