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