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