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