1 // UpdateCallback.cpp
2 
3 #include "StdAfx.h"
4 
5 #ifndef _7ZIP_ST
6 #include "../../../Windows/Synchronization.h"
7 #endif
8 
9 #include "../../../Common/ComTry.h"
10 #include "../../../Common/IntToString.h"
11 #include "../../../Common/StringConvert.h"
12 #include "../../../Common/Wildcard.h"
13 
14 #include "../../../Windows/FileDir.h"
15 #include "../../../Windows/FileName.h"
16 #include "../../../Windows/PropVariant.h"
17 
18 #include "../../Common/StreamObjects.h"
19 
20 #include "UpdateCallback.h"
21 
22 #if defined(_WIN32) && !defined(UNDER_CE)
23 #define _USE_SECURITY_CODE
24 #include "../../../Windows/SecurityUtils.h"
25 #endif
26 
27 using namespace NWindows;
28 using namespace NFile;
29 
30 #ifndef _7ZIP_ST
31 static NSynchronization::CCriticalSection g_CriticalSection;
32 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
33 #else
34 #define MT_LOCK
35 #endif
36 
37 
38 #ifdef _USE_SECURITY_CODE
39 bool InitLocalPrivileges();
40 #endif
41 
CArchiveUpdateCallback()42 CArchiveUpdateCallback::CArchiveUpdateCallback():
43     _hardIndex_From((UInt32)(Int32)-1),
44 
45     Callback(NULL),
46 
47     DirItems(NULL),
48     ParentDirItem(NULL),
49 
50     Arc(NULL),
51     ArcItems(NULL),
52     UpdatePairs(NULL),
53     NewNames(NULL),
54     CommentIndex(-1),
55     Comment(NULL),
56 
57     ShareForWrite(false),
58     StopAfterOpenError(false),
59     StdInMode(false),
60 
61     KeepOriginalItemNames(false),
62     StoreNtSecurity(false),
63     StoreHardLinks(false),
64     StoreSymLinks(false),
65 
66     ProcessedItemsStatuses(NULL)
67 {
68   #ifdef _USE_SECURITY_CODE
69   _saclEnabled = InitLocalPrivileges();
70   #endif
71 }
72 
73 
SetTotal(UInt64 size)74 STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
75 {
76   COM_TRY_BEGIN
77   return Callback->SetTotal(size);
78   COM_TRY_END
79 }
80 
SetCompleted(const UInt64 * completeValue)81 STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
82 {
83   COM_TRY_BEGIN
84   return Callback->SetCompleted(completeValue);
85   COM_TRY_END
86 }
87 
SetRatioInfo(const UInt64 * inSize,const UInt64 * outSize)88 STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
89 {
90   COM_TRY_BEGIN
91   return Callback->SetRatioInfo(inSize, outSize);
92   COM_TRY_END
93 }
94 
95 
96 /*
97 static const CStatProp kProps[] =
98 {
99   { NULL, kpidPath, VT_BSTR},
100   { NULL, kpidIsDir, VT_BOOL},
101   { NULL, kpidSize, VT_UI8},
102   { NULL, kpidCTime, VT_FILETIME},
103   { NULL, kpidATime, VT_FILETIME},
104   { NULL, kpidMTime, VT_FILETIME},
105   { NULL, kpidAttrib, VT_UI4},
106   { NULL, kpidIsAnti, VT_BOOL}
107 };
108 
109 STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
110 {
111   return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator);
112 }
113 */
114 
GetUpdateItemInfo(UInt32 index,Int32 * newData,Int32 * newProps,UInt32 * indexInArchive)115 STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
116       Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)
117 {
118   COM_TRY_BEGIN
119   RINOK(Callback->CheckBreak());
120   const CUpdatePair2 &up = (*UpdatePairs)[index];
121   if (newData) *newData = BoolToInt(up.NewData);
122   if (newProps) *newProps = BoolToInt(up.NewProps);
123   if (indexInArchive)
124   {
125     *indexInArchive = (UInt32)(Int32)-1;
126     if (up.ExistInArchive())
127       *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;
128   }
129   return S_OK;
130   COM_TRY_END
131 }
132 
GetRootProp(PROPID propID,PROPVARIANT * value)133 STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)
134 {
135   NCOM::CPropVariant prop;
136   switch (propID)
137   {
138     case kpidIsDir:  prop = true; break;
139     case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break;
140     case kpidCTime:  if (ParentDirItem) prop = ParentDirItem->CTime; break;
141     case kpidATime:  if (ParentDirItem) prop = ParentDirItem->ATime; break;
142     case kpidMTime:  if (ParentDirItem) prop = ParentDirItem->MTime; break;
143   }
144   prop.Detach(value);
145   return S_OK;
146 }
147 
GetParent(UInt32,UInt32 * parent,UInt32 * parentType)148 STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
149 {
150   *parentType = NParentType::kDir;
151   *parent = (UInt32)(Int32)-1;
152   return S_OK;
153 }
154 
GetNumRawProps(UInt32 * numProps)155 STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)
156 {
157   *numProps = 0;
158   if (StoreNtSecurity)
159     *numProps = 1;
160   return S_OK;
161 }
162 
GetRawPropInfo(UInt32,BSTR * name,PROPID * propID)163 STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
164 {
165   *name = NULL;
166   *propID = kpidNtSecure;
167   return S_OK;
168 }
169 
GetRootRawProp(PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType)170 STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID
171     #ifdef _USE_SECURITY_CODE
172     propID
173     #endif
174     , const void **data, UInt32 *dataSize, UInt32 *propType)
175 {
176   *data = 0;
177   *dataSize = 0;
178   *propType = 0;
179   if (!StoreNtSecurity)
180     return S_OK;
181   #ifdef _USE_SECURITY_CODE
182   if (propID == kpidNtSecure)
183   {
184     if (StdInMode)
185       return S_OK;
186 
187     if (ParentDirItem)
188     {
189       if (ParentDirItem->SecureIndex < 0)
190         return S_OK;
191       const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex];
192       *data = buf;
193       *dataSize = (UInt32)buf.Size();
194       *propType = NPropDataType::kRaw;
195       return S_OK;
196     }
197 
198     if (Arc && Arc->GetRootProps)
199       return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType);
200   }
201   #endif
202   return S_OK;
203 }
204 
205 //    #ifdef _USE_SECURITY_CODE
206 //    #endif
207 
GetRawProp(UInt32 index,PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType)208 STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
209 {
210   *data = 0;
211   *dataSize = 0;
212   *propType = 0;
213 
214   if (propID == kpidNtSecure ||
215       propID == kpidNtReparse)
216   {
217     if (StdInMode)
218       return S_OK;
219 
220     const CUpdatePair2 &up = (*UpdatePairs)[index];
221     if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps)
222       return Arc->GetRawProps->GetRawProp(
223           ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex,
224           propID, data, dataSize, propType);
225     {
226       /*
227       if (!up.NewData)
228         return E_FAIL;
229       */
230       if (up.IsAnti)
231         return S_OK;
232 
233       #ifndef UNDER_CE
234       const CDirItem &di = DirItems->Items[up.DirIndex];
235       #endif
236 
237       #ifdef _USE_SECURITY_CODE
238       if (propID == kpidNtSecure)
239       {
240         if (!StoreNtSecurity)
241           return S_OK;
242         if (di.SecureIndex < 0)
243           return S_OK;
244         const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex];
245         *data = buf;
246         *dataSize = (UInt32)buf.Size();
247         *propType = NPropDataType::kRaw;
248       }
249       else
250       #endif
251       {
252         // propID == kpidNtReparse
253         if (!StoreSymLinks)
254           return S_OK;
255         #ifndef UNDER_CE
256         const CByteBuffer *buf = &di.ReparseData2;
257         if (buf->Size() == 0)
258           buf = &di.ReparseData;
259         if (buf->Size() != 0)
260         {
261           *data = *buf;
262           *dataSize = (UInt32)buf->Size();
263           *propType = NPropDataType::kRaw;
264         }
265         #endif
266       }
267 
268       return S_OK;
269     }
270   }
271 
272   return S_OK;
273 }
274 
275 #ifndef UNDER_CE
276 
GetRelativePath(const UString & to,const UString & from)277 static UString GetRelativePath(const UString &to, const UString &from)
278 {
279   UStringVector partsTo, partsFrom;
280   SplitPathToParts(to, partsTo);
281   SplitPathToParts(from, partsFrom);
282 
283   unsigned i;
284   for (i = 0;; i++)
285   {
286     if (i + 1 >= partsFrom.Size() ||
287         i + 1 >= partsTo.Size())
288       break;
289     if (CompareFileNames(partsFrom[i], partsTo[i]) != 0)
290       break;
291   }
292 
293   if (i == 0)
294   {
295     #ifdef _WIN32
296     if (NName::IsDrivePath(to) ||
297         NName::IsDrivePath(from))
298       return to;
299     #endif
300   }
301 
302   UString s;
303   unsigned k;
304 
305   for (k = i + 1; k < partsFrom.Size(); k++)
306     s += ".." STRING_PATH_SEPARATOR;
307 
308   for (k = i; k < partsTo.Size(); k++)
309   {
310     if (k != i)
311       s.Add_PathSepar();
312     s += partsTo[k];
313   }
314 
315   return s;
316 }
317 
318 #endif
319 
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)320 STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
321 {
322   COM_TRY_BEGIN
323   const CUpdatePair2 &up = (*UpdatePairs)[index];
324   NCOM::CPropVariant prop;
325 
326   if (up.NewData)
327   {
328     /*
329     if (propID == kpidIsHardLink)
330     {
331       prop = _isHardLink;
332       prop.Detach(value);
333       return S_OK;
334     }
335     */
336     if (propID == kpidSymLink)
337     {
338       if (index == _hardIndex_From)
339       {
340         prop.Detach(value);
341         return S_OK;
342       }
343       if (up.DirIndex >= 0)
344       {
345         #ifndef UNDER_CE
346         const CDirItem &di = DirItems->Items[up.DirIndex];
347         // if (di.IsDir())
348         {
349           CReparseAttr attr;
350           DWORD errorCode = 0;
351           if (attr.Parse(di.ReparseData, di.ReparseData.Size(), errorCode))
352           {
353             UString simpleName = attr.GetPath();
354             if (attr.IsRelative())
355               prop = simpleName;
356             else
357             {
358               const FString phyPath = DirItems->GetPhyPath(up.DirIndex);
359               FString fullPath;
360               if (NDir::MyGetFullPathName(phyPath, fullPath))
361               {
362                 prop = GetRelativePath(simpleName, fs2us(fullPath));
363               }
364             }
365             prop.Detach(value);
366             return S_OK;
367           }
368         }
369         #endif
370       }
371     }
372     else if (propID == kpidHardLink)
373     {
374       if (index == _hardIndex_From)
375       {
376         const CKeyKeyValPair &pair = _map[_hardIndex_To];
377         const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
378         prop = DirItems->GetLogPath(up2.DirIndex);
379         prop.Detach(value);
380         return S_OK;
381       }
382       if (up.DirIndex >= 0)
383       {
384         prop.Detach(value);
385         return S_OK;
386       }
387     }
388   }
389 
390   if (up.IsAnti
391       && propID != kpidIsDir
392       && propID != kpidPath
393       && propID != kpidIsAltStream)
394   {
395     switch (propID)
396     {
397       case kpidSize:  prop = (UInt64)0; break;
398       case kpidIsAnti:  prop = true; break;
399     }
400   }
401   else if (propID == kpidPath && up.NewNameIndex >= 0)
402     prop = (*NewNames)[up.NewNameIndex];
403   else if (propID == kpidComment
404       && CommentIndex >= 0
405       && (unsigned)CommentIndex == index
406       && Comment)
407     prop = *Comment;
408   else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem)
409   {
410     // we can generate new ShortName here;
411   }
412   else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream)))
413       && up.ExistInArchive() && Archive)
414     return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value);
415   else if (up.ExistOnDisk())
416   {
417     const CDirItem &di = DirItems->Items[up.DirIndex];
418     switch (propID)
419     {
420       case kpidPath:  prop = DirItems->GetLogPath(up.DirIndex); break;
421       case kpidIsDir:  prop = di.IsDir(); break;
422       case kpidSize:  prop = di.IsDir() ? (UInt64)0 : di.Size; break;
423       case kpidAttrib:  prop = di.Attrib; break;
424       case kpidCTime:  prop = di.CTime; break;
425       case kpidATime:  prop = di.ATime; break;
426       case kpidMTime:  prop = di.MTime; break;
427       case kpidIsAltStream:  prop = di.IsAltStream; break;
428       #if defined(_WIN32) && !defined(UNDER_CE)
429       // case kpidShortName:  prop = di.ShortName; break;
430       #endif
431     }
432   }
433   prop.Detach(value);
434   return S_OK;
435   COM_TRY_END
436 }
437 
438 #ifndef _7ZIP_ST
439 static NSynchronization::CCriticalSection CS;
440 #endif
441 
GetStream2(UInt32 index,ISequentialInStream ** inStream,UInt32 mode)442 STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)
443 {
444   COM_TRY_BEGIN
445   *inStream = NULL;
446   const CUpdatePair2 &up = (*UpdatePairs)[index];
447   if (!up.NewData)
448     return E_FAIL;
449 
450   RINOK(Callback->CheckBreak());
451   // RINOK(Callback->Finalize());
452 
453   bool isDir = IsDir(up);
454 
455   if (up.IsAnti)
456   {
457     UString name;
458     if (up.ArcIndex >= 0)
459       name = (*ArcItems)[up.ArcIndex].Name;
460     else if (up.DirIndex >= 0)
461       name = DirItems->GetLogPath(up.DirIndex);
462     RINOK(Callback->GetStream(name, isDir, true, mode));
463 
464     /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file.
465        so we return empty stream */
466 
467     if (!isDir)
468     {
469       CBufInStream *inStreamSpec = new CBufInStream();
470       CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
471       inStreamSpec->Init(NULL, 0);
472       *inStream = inStreamLoc.Detach();
473     }
474     return S_OK;
475   }
476 
477   RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), isDir, false, mode));
478 
479   if (isDir)
480     return S_OK;
481 
482   if (StdInMode)
483   {
484     if (mode != NUpdateNotifyOp::kAdd &&
485         mode != NUpdateNotifyOp::kUpdate)
486       return S_OK;
487 
488     CStdInFileStream *inStreamSpec = new CStdInFileStream;
489     CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
490     *inStream = inStreamLoc.Detach();
491   }
492   else
493   {
494     CInFileStream *inStreamSpec = new CInFileStream;
495     CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
496 
497     inStreamSpec->SupportHardLinks = StoreHardLinks;
498     inStreamSpec->Callback = this;
499     inStreamSpec->CallbackRef = index;
500 
501     const FString path = DirItems->GetPhyPath(up.DirIndex);
502     _openFiles_Indexes.Add(index);
503     _openFiles_Paths.Add(path);
504 
505     #if defined(_WIN32) && !defined(UNDER_CE)
506     if (DirItems->Items[up.DirIndex].AreReparseData())
507     {
508       if (!inStreamSpec->File.OpenReparse(path))
509       {
510         return Callback->OpenFileError(path, ::GetLastError());
511       }
512     }
513     else
514     #endif
515     if (!inStreamSpec->OpenShared(path, ShareForWrite))
516     {
517       DWORD error = ::GetLastError();
518       HRESULT hres = Callback->OpenFileError(path, error);
519       if (StopAfterOpenError)
520         if (hres == S_OK || hres == S_FALSE)
521           return HRESULT_FROM_WIN32(error);
522       return hres;
523     }
524 
525     if (StoreHardLinks)
526     {
527       CStreamFileProps props;
528       if (inStreamSpec->GetProps2(&props) == S_OK)
529       {
530         if (props.NumLinks > 1)
531         {
532           CKeyKeyValPair pair;
533           pair.Key1 = props.VolID;
534           pair.Key2 = props.FileID_Low;
535           pair.Value = index;
536           unsigned numItems = _map.Size();
537           unsigned pairIndex = _map.AddToUniqueSorted2(pair);
538           if (numItems == _map.Size())
539           {
540             // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex];
541             _hardIndex_From = index;
542             _hardIndex_To = pairIndex;
543             // we could return NULL as stream, but it's better to return real stream
544             // return S_OK;
545           }
546         }
547       }
548     }
549 
550     if (ProcessedItemsStatuses)
551     {
552       #ifndef _7ZIP_ST
553       NSynchronization::CCriticalSectionLock lock(CS);
554       #endif
555       ProcessedItemsStatuses[(unsigned)up.DirIndex] = 1;
556     }
557     *inStream = inStreamLoc.Detach();
558   }
559 
560   return S_OK;
561   COM_TRY_END
562 }
563 
SetOperationResult(Int32 opRes)564 STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 opRes)
565 {
566   COM_TRY_BEGIN
567   return Callback->SetOperationResult(opRes);
568   COM_TRY_END
569 }
570 
GetStream(UInt32 index,ISequentialInStream ** inStream)571 STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
572 {
573   COM_TRY_BEGIN
574   return GetStream2(index, inStream,
575       (*UpdatePairs)[index].ArcIndex < 0 ?
576           NUpdateNotifyOp::kAdd :
577           NUpdateNotifyOp::kUpdate);
578   COM_TRY_END
579 }
580 
ReportOperation(UInt32 indexType,UInt32 index,UInt32 op)581 STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)
582 {
583   COM_TRY_BEGIN
584 
585   bool isDir = false;
586 
587   if (indexType == NArchive::NEventIndexType::kOutArcIndex)
588   {
589     UString name;
590     if (index != (UInt32)(Int32)-1)
591     {
592       const CUpdatePair2 &up = (*UpdatePairs)[index];
593       if (up.ExistOnDisk())
594       {
595         name = DirItems->GetLogPath(up.DirIndex);
596         isDir = DirItems->Items[up.DirIndex].IsDir();
597       }
598     }
599     return Callback->ReportUpdateOpeartion(op, name.IsEmpty() ? NULL : name.Ptr(), isDir);
600   }
601 
602   wchar_t temp[16];
603   UString s2;
604   const wchar_t *s = NULL;
605 
606   if (indexType == NArchive::NEventIndexType::kInArcIndex)
607   {
608     if (index != (UInt32)(Int32)-1)
609     {
610       if (ArcItems)
611       {
612         const CArcItem &ai = (*ArcItems)[index];
613         s = ai.Name;
614         isDir = ai.IsDir;
615       }
616       else if (Arc)
617       {
618         RINOK(Arc->GetItemPath(index, s2));
619         s = s2;
620         RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir));
621       }
622     }
623   }
624   else if (indexType == NArchive::NEventIndexType::kBlockIndex)
625   {
626     temp[0] = '#';
627     ConvertUInt32ToString(index, temp + 1);
628     s = temp;
629   }
630 
631   if (!s)
632     s = L"";
633 
634   return Callback->ReportUpdateOpeartion(op, s, isDir);
635 
636   COM_TRY_END
637 }
638 
ReportExtractResult(UInt32 indexType,UInt32 index,Int32 opRes)639 STDMETHODIMP CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)
640 {
641   COM_TRY_BEGIN
642 
643   bool isEncrypted = false;
644   wchar_t temp[16];
645   UString s2;
646   const wchar_t *s = NULL;
647 
648   if (indexType == NArchive::NEventIndexType::kOutArcIndex)
649   {
650     /*
651     UString name;
652     if (index != (UInt32)(Int32)-1)
653     {
654       const CUpdatePair2 &up = (*UpdatePairs)[index];
655       if (up.ExistOnDisk())
656       {
657         s2 = DirItems->GetLogPath(up.DirIndex);
658         s = s2;
659       }
660     }
661     */
662     return E_FAIL;
663   }
664 
665   if (indexType == NArchive::NEventIndexType::kInArcIndex)
666   {
667     if (index != (UInt32)(Int32)-1)
668     {
669       if (ArcItems)
670         s = (*ArcItems)[index].Name;
671       else if (Arc)
672       {
673         RINOK(Arc->GetItemPath(index, s2));
674         s = s2;
675       }
676       if (Archive)
677       {
678         RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted));
679       }
680     }
681   }
682   else if (indexType == NArchive::NEventIndexType::kBlockIndex)
683   {
684     temp[0] = '#';
685     ConvertUInt32ToString(index, temp + 1);
686     s = temp;
687   }
688 
689   return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s);
690 
691   COM_TRY_END
692 }
693 
GetVolumeSize(UInt32 index,UInt64 * size)694 STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
695 {
696   if (VolumesSizes.Size() == 0)
697     return S_FALSE;
698   if (index >= (UInt32)VolumesSizes.Size())
699     index = VolumesSizes.Size() - 1;
700   *size = VolumesSizes[index];
701   return S_OK;
702 }
703 
GetVolumeStream(UInt32 index,ISequentialOutStream ** volumeStream)704 STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
705 {
706   COM_TRY_BEGIN
707   char temp[16];
708   ConvertUInt32ToString(index + 1, temp);
709   FString res (temp);
710   while (res.Len() < 2)
711     res.InsertAtFront(FTEXT('0'));
712   FString fileName = VolName;
713   fileName += '.';
714   fileName += res;
715   fileName += VolExt;
716   COutFileStream *streamSpec = new COutFileStream;
717   CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
718   if (!streamSpec->Create(fileName, false))
719     return ::GetLastError();
720   *volumeStream = streamLoc.Detach();
721   return S_OK;
722   COM_TRY_END
723 }
724 
CryptoGetTextPassword2(Int32 * passwordIsDefined,BSTR * password)725 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
726 {
727   COM_TRY_BEGIN
728   return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
729   COM_TRY_END
730 }
731 
CryptoGetTextPassword(BSTR * password)732 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)
733 {
734   COM_TRY_BEGIN
735   return Callback->CryptoGetTextPassword(password);
736   COM_TRY_END
737 }
738 
InFileStream_On_Error(UINT_PTR val,DWORD error)739 HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
740 {
741   if (error == ERROR_LOCK_VIOLATION)
742   {
743     MT_LOCK
744     UInt32 index = (UInt32)val;
745     FOR_VECTOR(i, _openFiles_Indexes)
746     {
747       if (_openFiles_Indexes[i] == index)
748       {
749         RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error));
750         break;
751       }
752     }
753   }
754   return HRESULT_FROM_WIN32(error);
755 }
756 
InFileStream_On_Destroy(UINT_PTR val)757 void CArchiveUpdateCallback::InFileStream_On_Destroy(UINT_PTR val)
758 {
759   MT_LOCK
760   UInt32 index = (UInt32)val;
761   FOR_VECTOR(i, _openFiles_Indexes)
762   {
763     if (_openFiles_Indexes[i] == index)
764     {
765       _openFiles_Indexes.Delete(i);
766       _openFiles_Paths.Delete(i);
767       return;
768     }
769   }
770   throw 20141125;
771 }
772