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