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