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