1 // AgentOut.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/Wildcard.h"
6
7 #include "../../../Windows/FileDir.h"
8 #include "../../../Windows/FileName.h"
9 #include "../../../Windows/TimeUtils.h"
10
11 #include "../../Compress/CopyCoder.h"
12
13 #include "../../Common/FileStreams.h"
14
15 #include "Agent.h"
16 #include "UpdateCallbackAgent.h"
17
18 using namespace NWindows;
19 using namespace NCOM;
20
SetFolder(IFolderFolder * folder)21 STDMETHODIMP CAgent::SetFolder(IFolderFolder *folder)
22 {
23 _updatePathPrefix.Empty();
24 _updatePathPrefix_is_AltFolder = false;
25 _agentFolder = NULL;
26
27 if (!folder)
28 return S_OK;
29
30 {
31 CMyComPtr<IArchiveFolderInternal> afi;
32 RINOK(folder->QueryInterface(IID_IArchiveFolderInternal, (void **)&afi));
33 if (afi)
34 {
35 RINOK(afi->GetAgentFolder(&_agentFolder));
36 }
37 if (!_agentFolder)
38 return E_FAIL;
39 }
40
41 if (_proxy2)
42 _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, _updatePathPrefix_is_AltFolder);
43 else
44 _updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
45 return S_OK;
46 }
47
SetFiles(const wchar_t * folderPrefix,const wchar_t * const * names,UInt32 numNames)48 STDMETHODIMP CAgent::SetFiles(const wchar_t *folderPrefix,
49 const wchar_t * const *names, UInt32 numNames)
50 {
51 _folderPrefix = us2fs(folderPrefix);
52 _names.ClearAndReserve(numNames);
53 for (UInt32 i = 0; i < numNames; i++)
54 _names.AddInReserved(us2fs(names[i]));
55 return S_OK;
56 }
57
EnumerateArchiveItems(CAgent * agent,const CProxyDir & item,const UString & prefix,CObjectVector<CArcItem> & arcItems)58 static HRESULT EnumerateArchiveItems(CAgent *agent,
59 const CProxyDir &item,
60 const UString &prefix,
61 CObjectVector<CArcItem> &arcItems)
62 {
63 unsigned i;
64
65 for (i = 0; i < item.SubFiles.Size(); i++)
66 {
67 unsigned arcIndex = item.SubFiles[i];
68 const CProxyFile &fileItem = agent->_proxy->Files[arcIndex];
69 CArcItem ai;
70 RINOK(agent->GetArc().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined));
71 RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined));
72 ai.IsDir = false;
73 ai.Name = prefix + fileItem.Name;
74 ai.Censored = true; // test it
75 ai.IndexInServer = arcIndex;
76 arcItems.Add(ai);
77 }
78
79 for (i = 0; i < item.SubDirs.Size(); i++)
80 {
81 const CProxyDir &dirItem = agent->_proxy->Dirs[item.SubDirs[i]];
82 UString fullName = prefix + dirItem.Name;
83 if (dirItem.IsLeaf())
84 {
85 CArcItem ai;
86 RINOK(agent->GetArc().GetItemMTime(dirItem.ArcIndex, ai.MTime, ai.MTimeDefined));
87 ai.IsDir = true;
88 ai.SizeDefined = false;
89 ai.Name = fullName;
90 ai.Censored = true; // test it
91 ai.IndexInServer = dirItem.ArcIndex;
92 arcItems.Add(ai);
93 }
94 RINOK(EnumerateArchiveItems(agent, dirItem, fullName + WCHAR_PATH_SEPARATOR, arcItems));
95 }
96
97 return S_OK;
98 }
99
EnumerateArchiveItems2(const CAgent * agent,unsigned dirIndex,const UString & prefix,CObjectVector<CArcItem> & arcItems)100 static HRESULT EnumerateArchiveItems2(const CAgent *agent,
101 unsigned dirIndex,
102 const UString &prefix,
103 CObjectVector<CArcItem> &arcItems)
104 {
105 const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex];
106 FOR_VECTOR (i, dir.Items)
107 {
108 unsigned arcIndex = dir.Items[i];
109 const CProxyFile2 &file = agent->_proxy2->Files[arcIndex];
110 CArcItem ai;
111 ai.IndexInServer = arcIndex;
112 ai.Name = prefix + file.Name;
113 ai.Censored = true; // test it
114 RINOK(agent->GetArc().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined));
115 ai.IsDir = file.IsDir();
116 ai.SizeDefined = false;
117 ai.IsAltStream = file.IsAltStream;
118 if (!ai.IsDir)
119 {
120 RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined));
121 ai.IsDir = false;
122 }
123 arcItems.Add(ai);
124
125 if (file.AltDirIndex >= 0)
126 {
127 RINOK(EnumerateArchiveItems2(agent, file.AltDirIndex, ai.Name + L':', arcItems));
128 }
129
130 if (ai.IsDir)
131 {
132 RINOK(EnumerateArchiveItems2(agent, file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems));
133 }
134 }
135 return S_OK;
136 }
137
138 struct CAgUpCallbackImp: public IUpdateProduceCallback
139 {
140 const CObjectVector<CArcItem> *_arcItems;
141 IFolderArchiveUpdateCallback *_callback;
142
CAgUpCallbackImpCAgUpCallbackImp143 CAgUpCallbackImp(const CObjectVector<CArcItem> *a,
144 IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {}
145 HRESULT ShowDeleteFile(unsigned arcIndex);
146 };
147
ShowDeleteFile(unsigned arcIndex)148 HRESULT CAgUpCallbackImp::ShowDeleteFile(unsigned arcIndex)
149 {
150 return _callback->DeleteOperation((*_arcItems)[arcIndex].Name);
151 }
152
153
SetInArchiveInterfaces(CAgent * agent,CArchiveUpdateCallback * upd)154 static void SetInArchiveInterfaces(CAgent *agent, CArchiveUpdateCallback *upd)
155 {
156 if (agent->_archiveLink.Arcs.IsEmpty())
157 return;
158 const CArc &arc = agent->GetArc();
159 upd->Arc = &arc;
160 upd->Archive = arc.Archive;
161
162 upd->ArcFileName = ExtractFileNameFromPath(arc.Path);
163 }
164
165 struct CDirItemsCallback_AgentOut: public IDirItemsCallback
166 {
167 CMyComPtr<IFolderScanProgress> FolderScanProgress;
168 IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback;
169 HRESULT ErrorCode;
170
CDirItemsCallback_AgentOutCDirItemsCallback_AgentOut171 CDirItemsCallback_AgentOut(): FolderArchiveUpdateCallback(NULL), ErrorCode(S_OK) {}
172
ScanErrorCDirItemsCallback_AgentOut173 HRESULT ScanError(const FString &name, DWORD systemError)
174 {
175 HRESULT hres = HRESULT_FROM_WIN32(systemError);
176 if (FolderArchiveUpdateCallback)
177 return FolderScanProgress->ScanError(fs2us(name), hres);
178 ErrorCode = hres;
179 return ErrorCode;
180 }
181
ScanProgressCDirItemsCallback_AgentOut182 HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir)
183 {
184 if (FolderScanProgress)
185 return FolderScanProgress->ScanProgress(st.NumDirs, st.NumFiles + st.NumAltStreams,
186 st.GetTotalBytes(), fs2us(path), BoolToInt(isDir));
187
188 if (FolderArchiveUpdateCallback)
189 return FolderArchiveUpdateCallback->SetNumFiles(st.NumFiles);
190
191 return S_OK;
192 }
193 };
194
195
DoOperation(FStringVector * requestedPaths,FStringVector * processedPaths,CCodecs * codecs,int formatIndex,ISequentialOutStream * outArchiveStream,const Byte * stateActions,const wchar_t * sfxModule,IFolderArchiveUpdateCallback * updateCallback100)196 STDMETHODIMP CAgent::DoOperation(
197 FStringVector *requestedPaths,
198 FStringVector *processedPaths,
199 CCodecs *codecs,
200 int formatIndex,
201 ISequentialOutStream *outArchiveStream,
202 const Byte *stateActions,
203 const wchar_t *sfxModule,
204 IFolderArchiveUpdateCallback *updateCallback100)
205 {
206 if (!CanUpdate())
207 return E_NOTIMPL;
208
209 NUpdateArchive::CActionSet actionSet;
210 {
211 for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
212 actionSet.StateActions[i] = (NUpdateArchive::NPairAction::EEnum)stateActions[i];
213 }
214
215 CDirItemsCallback_AgentOut enumCallback;
216 if (updateCallback100)
217 {
218 enumCallback.FolderArchiveUpdateCallback = updateCallback100;
219 updateCallback100->QueryInterface(IID_IFolderScanProgress, (void **)&enumCallback.FolderScanProgress);
220 }
221
222 CDirItems dirItems;
223 dirItems.Callback = &enumCallback;
224
225 {
226 FString folderPrefix = _folderPrefix;
227 NFile::NName::NormalizeDirPathPrefix(folderPrefix);
228
229 RINOK(dirItems.EnumerateItems2(folderPrefix, _updatePathPrefix, _names, requestedPaths));
230
231 if (_updatePathPrefix_is_AltFolder)
232 {
233 FOR_VECTOR(i, dirItems.Items)
234 {
235 CDirItem &item = dirItems.Items[i];
236 if (item.IsDir())
237 return E_NOTIMPL;
238 item.IsAltStream = true;
239 }
240 }
241 }
242
243 CMyComPtr<IOutArchive> outArchive;
244
245 if (GetArchive())
246 {
247 RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive));
248 }
249 else
250 {
251 if (formatIndex < 0)
252 return E_FAIL;
253 RINOK(codecs->CreateOutArchive(formatIndex, outArchive));
254
255 #ifdef EXTERNAL_CODECS
256 {
257 CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
258 outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
259 if (setCompressCodecsInfo)
260 {
261 RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
262 }
263 }
264 #endif
265 }
266
267 NFileTimeType::EEnum fileTimeType;
268 UInt32 value;
269 RINOK(outArchive->GetFileTimeType(&value));
270
271 switch (value)
272 {
273 case NFileTimeType::kWindows:
274 case NFileTimeType::kDOS:
275 case NFileTimeType::kUnix:
276 fileTimeType = NFileTimeType::EEnum(value);
277 break;
278 default:
279 return E_FAIL;
280 }
281
282
283 CObjectVector<CArcItem> arcItems;
284 if (GetArchive())
285 {
286 RINOK(ReadItems());
287 if (_proxy2)
288 {
289 RINOK(EnumerateArchiveItems2(this, k_Proxy2_RootDirIndex, L"", arcItems));
290 RINOK(EnumerateArchiveItems2(this, k_Proxy2_AltRootDirIndex, L":", arcItems));
291 }
292 else
293 {
294 RINOK(EnumerateArchiveItems(this, _proxy->Dirs[0], L"", arcItems));
295 }
296 }
297
298 CRecordVector<CUpdatePair2> updatePairs2;
299
300 {
301 CRecordVector<CUpdatePair> updatePairs;
302 GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs);
303 CAgUpCallbackImp upCallback(&arcItems, updateCallback100);
304 UpdateProduce(updatePairs, actionSet, updatePairs2, &upCallback);
305 }
306
307 UInt32 numFiles = 0;
308 {
309 FOR_VECTOR (i, updatePairs2)
310 if (updatePairs2[i].NewData)
311 numFiles++;
312 }
313
314 if (updateCallback100)
315 {
316 RINOK(updateCallback100->SetNumFiles(numFiles));
317 }
318
319 CUpdateCallbackAgent updateCallbackAgent;
320 updateCallbackAgent.SetCallback(updateCallback100);
321 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
322 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
323
324 updateCallbackSpec->DirItems = &dirItems;
325 updateCallbackSpec->ArcItems = &arcItems;
326 updateCallbackSpec->UpdatePairs = &updatePairs2;
327
328 SetInArchiveInterfaces(this, updateCallbackSpec);
329
330 updateCallbackSpec->Callback = &updateCallbackAgent;
331
332 CByteBuffer processedItems;
333 if (processedPaths)
334 {
335 unsigned num = dirItems.Items.Size();
336 processedItems.Alloc(num);
337 for (unsigned i = 0; i < num; i++)
338 processedItems[i] = 0;
339 updateCallbackSpec->ProcessedItemsStatuses = processedItems;
340 }
341
342 CMyComPtr<ISetProperties> setProperties;
343 if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK)
344 {
345 if (m_PropNames.Size() == 0)
346 {
347 RINOK(setProperties->SetProperties(0, 0, 0));
348 }
349 else
350 {
351 CRecordVector<const wchar_t *> names;
352 FOR_VECTOR (i, m_PropNames)
353 names.Add((const wchar_t *)m_PropNames[i]);
354
355 CPropVariant *propValues = new CPropVariant[m_PropValues.Size()];
356 try
357 {
358 FOR_VECTOR (i, m_PropValues)
359 propValues[i] = m_PropValues[i];
360 RINOK(setProperties->SetProperties(&names.Front(), propValues, names.Size()));
361 }
362 catch(...)
363 {
364 delete []propValues;
365 return E_FAIL;
366 }
367 delete []propValues;
368 }
369 }
370 m_PropNames.Clear();
371 m_PropValues.Clear();
372
373 if (sfxModule != NULL)
374 {
375 CInFileStream *sfxStreamSpec = new CInFileStream;
376 CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
377 if (!sfxStreamSpec->Open(us2fs(sfxModule)))
378 return E_FAIL;
379 // throw "Can't open sfx module";
380 RINOK(NCompress::CopyStream(sfxStream, outArchiveStream, NULL));
381 }
382
383 HRESULT res = outArchive->UpdateItems(outArchiveStream, updatePairs2.Size(), updateCallback);
384 if (res == S_OK && processedPaths)
385 {
386 {
387 /* OutHandler for 7z archives doesn't report compression operation for empty files.
388 So we must include these files manually */
389 FOR_VECTOR(i, updatePairs2)
390 {
391 const CUpdatePair2 &up = updatePairs2[i];
392 if (up.DirIndex >= 0 && up.NewData)
393 {
394 const CDirItem &di = dirItems.Items[up.DirIndex];
395 if (!di.IsDir() && di.Size == 0)
396 processedItems[up.DirIndex] = 1;
397 }
398 }
399 }
400
401 FOR_VECTOR (i, dirItems.Items)
402 if (processedItems[i] != 0)
403 processedPaths->Add(dirItems.GetPhyPath(i));
404 }
405 return res;
406 }
407
DoOperation2(FStringVector * requestedPaths,FStringVector * processedPaths,ISequentialOutStream * outArchiveStream,const Byte * stateActions,const wchar_t * sfxModule,IFolderArchiveUpdateCallback * updateCallback100)408 STDMETHODIMP CAgent::DoOperation2(
409 FStringVector *requestedPaths,
410 FStringVector *processedPaths,
411 ISequentialOutStream *outArchiveStream,
412 const Byte *stateActions, const wchar_t *sfxModule, IFolderArchiveUpdateCallback *updateCallback100)
413 {
414 return DoOperation(requestedPaths, processedPaths, g_CodecsObj, -1, outArchiveStream, stateActions, sfxModule, updateCallback100);
415 }
416
CommonUpdate(ISequentialOutStream * outArchiveStream,unsigned numUpdateItems,IArchiveUpdateCallback * updateCallback)417 HRESULT CAgent::CommonUpdate(ISequentialOutStream *outArchiveStream,
418 unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback)
419 {
420 if (!CanUpdate())
421 return E_NOTIMPL;
422 CMyComPtr<IOutArchive> outArchive;
423 RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive));
424 return outArchive->UpdateItems(outArchiveStream, numUpdateItems, updateCallback);
425 }
426
DeleteItems(ISequentialOutStream * outArchiveStream,const UInt32 * indices,UInt32 numItems,IFolderArchiveUpdateCallback * updateCallback100)427 STDMETHODIMP CAgent::DeleteItems(ISequentialOutStream *outArchiveStream,
428 const UInt32 *indices, UInt32 numItems,
429 IFolderArchiveUpdateCallback *updateCallback100)
430 {
431 if (!CanUpdate())
432 return E_NOTIMPL;
433 CRecordVector<CUpdatePair2> updatePairs;
434 CUpdateCallbackAgent updateCallbackAgent;
435 updateCallbackAgent.SetCallback(updateCallback100);
436 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
437 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
438
439 CUIntVector realIndices;
440 _agentFolder->GetRealIndices(indices, numItems,
441 true, // includeAltStreams
442 false, // includeFolderSubItemsInFlatMode, we don't want to delete subItems in Flat Mode
443 realIndices);
444 unsigned curIndex = 0;
445 UInt32 numItemsInArchive;
446 RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
447
448 UString deletePath;
449
450 for (UInt32 i = 0; i < numItemsInArchive; i++)
451 {
452 if (curIndex < realIndices.Size())
453 if (realIndices[curIndex] == i)
454 {
455 RINOK(GetArc().GetItemPath2(i, deletePath));
456 RINOK(updateCallback100->DeleteOperation(deletePath));
457
458 curIndex++;
459 continue;
460 }
461 CUpdatePair2 up2;
462 up2.SetAs_NoChangeArcItem(i);
463 updatePairs.Add(up2);
464 }
465 updateCallbackSpec->UpdatePairs = &updatePairs;
466
467 SetInArchiveInterfaces(this, updateCallbackSpec);
468
469 updateCallbackSpec->Callback = &updateCallbackAgent;
470 return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
471 }
472
CreateFolder(ISequentialOutStream * outArchiveStream,const wchar_t * folderName,IFolderArchiveUpdateCallback * updateCallback100)473 HRESULT CAgent::CreateFolder(ISequentialOutStream *outArchiveStream,
474 const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100)
475 {
476 if (!CanUpdate())
477 return E_NOTIMPL;
478 CRecordVector<CUpdatePair2> updatePairs;
479 CDirItems dirItems;
480 CUpdateCallbackAgent updateCallbackAgent;
481 updateCallbackAgent.SetCallback(updateCallback100);
482 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
483 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
484
485 UInt32 numItemsInArchive;
486 RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
487 for (UInt32 i = 0; i < numItemsInArchive; i++)
488 {
489 CUpdatePair2 up2;
490 up2.SetAs_NoChangeArcItem(i);
491 updatePairs.Add(up2);
492 }
493 CUpdatePair2 up2;
494 up2.NewData = up2.NewProps = true;
495 up2.UseArcProps = false;
496 up2.DirIndex = 0;
497
498 updatePairs.Add(up2);
499
500 updatePairs.ReserveDown();
501
502 CDirItem di;
503
504 di.Attrib = FILE_ATTRIBUTE_DIRECTORY;
505 di.Size = 0;
506 bool isAltStreamFolder = false;
507 if (_proxy2)
508 di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, isAltStreamFolder);
509 else
510 di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
511 di.Name += folderName;
512
513 FILETIME ft;
514 NTime::GetCurUtcFileTime(ft);
515 di.CTime = di.ATime = di.MTime = ft;
516
517 dirItems.Items.Add(di);
518
519 updateCallbackSpec->Callback = &updateCallbackAgent;
520 updateCallbackSpec->DirItems = &dirItems;
521 updateCallbackSpec->UpdatePairs = &updatePairs;
522
523 SetInArchiveInterfaces(this, updateCallbackSpec);
524
525 return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
526 }
527
528
RenameItem(ISequentialOutStream * outArchiveStream,const UInt32 * indices,UInt32 numItems,const wchar_t * newItemName,IFolderArchiveUpdateCallback * updateCallback100)529 HRESULT CAgent::RenameItem(ISequentialOutStream *outArchiveStream,
530 const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
531 IFolderArchiveUpdateCallback *updateCallback100)
532 {
533 if (!CanUpdate())
534 return E_NOTIMPL;
535 if (numItems != 1)
536 return E_INVALIDARG;
537 if (!_archiveLink.IsOpen)
538 return E_FAIL;
539 CRecordVector<CUpdatePair2> updatePairs;
540 CUpdateCallbackAgent updateCallbackAgent;
541 updateCallbackAgent.SetCallback(updateCallback100);
542 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
543 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
544
545 CUIntVector realIndices;
546 _agentFolder->GetRealIndices(indices, numItems,
547 true, // includeAltStreams
548 true, // includeFolderSubItemsInFlatMode
549 realIndices);
550
551 int mainRealIndex = _agentFolder->GetRealIndex(indices[0]);
552
553 UString fullPrefix = _agentFolder->GetFullPrefix(indices[0]);
554 UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]);
555 UString newItemPath = fullPrefix + newItemName;
556
557 UStringVector newNames;
558
559 unsigned curIndex = 0;
560 UInt32 numItemsInArchive;
561 RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
562
563 for (UInt32 i = 0; i < numItemsInArchive; i++)
564 {
565 CUpdatePair2 up2;
566 up2.SetAs_NoChangeArcItem(i);
567 if (curIndex < realIndices.Size())
568 if (realIndices[curIndex] == i)
569 {
570 up2.NewProps = true;
571 RINOK(GetArc().IsItemAnti(i, up2.IsAnti)); // it must work without that line too.
572
573 UString oldFullPath;
574 RINOK(GetArc().GetItemPath2(i, oldFullPath));
575
576 if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath))
577 return E_INVALIDARG;
578
579 up2.NewNameIndex = newNames.Add(newItemPath + oldFullPath.Ptr(oldItemPath.Len()));
580 up2.IsMainRenameItem = (mainRealIndex == (int)i);
581 curIndex++;
582 }
583 updatePairs.Add(up2);
584 }
585
586 updateCallbackSpec->Callback = &updateCallbackAgent;
587 updateCallbackSpec->UpdatePairs = &updatePairs;
588 updateCallbackSpec->NewNames = &newNames;
589
590 SetInArchiveInterfaces(this, updateCallbackSpec);
591
592 return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
593 }
594
595
CommentItem(ISequentialOutStream * outArchiveStream,const UInt32 * indices,UInt32 numItems,const wchar_t * newItemName,IFolderArchiveUpdateCallback * updateCallback100)596 HRESULT CAgent::CommentItem(ISequentialOutStream *outArchiveStream,
597 const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
598 IFolderArchiveUpdateCallback *updateCallback100)
599 {
600 if (!CanUpdate())
601 return E_NOTIMPL;
602 if (numItems != 1)
603 return E_INVALIDARG;
604 if (!_archiveLink.IsOpen)
605 return E_FAIL;
606
607 CRecordVector<CUpdatePair2> updatePairs;
608 CUpdateCallbackAgent updateCallbackAgent;
609 updateCallbackAgent.SetCallback(updateCallback100);
610 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
611 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
612
613 const int mainRealIndex = _agentFolder->GetRealIndex(indices[0]);
614
615 if (mainRealIndex < 0)
616 return E_NOTIMPL;
617
618 UInt32 numItemsInArchive;
619 RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
620
621 UString newName = newItemName;
622
623 for (UInt32 i = 0; i < numItemsInArchive; i++)
624 {
625 CUpdatePair2 up2;
626 up2.SetAs_NoChangeArcItem(i);
627 if ((int)i == mainRealIndex)
628 up2.NewProps = true;
629 updatePairs.Add(up2);
630 }
631
632 updateCallbackSpec->Callback = &updateCallbackAgent;
633 updateCallbackSpec->UpdatePairs = &updatePairs;
634 updateCallbackSpec->CommentIndex = mainRealIndex;
635 updateCallbackSpec->Comment = &newName;
636
637 SetInArchiveInterfaces(this, updateCallbackSpec);
638
639 return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
640 }
641
642
643
UpdateOneFile(ISequentialOutStream * outArchiveStream,const UInt32 * indices,UInt32 numItems,const wchar_t * diskFilePath,IFolderArchiveUpdateCallback * updateCallback100)644 HRESULT CAgent::UpdateOneFile(ISequentialOutStream *outArchiveStream,
645 const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath,
646 IFolderArchiveUpdateCallback *updateCallback100)
647 {
648 if (!CanUpdate())
649 return E_NOTIMPL;
650 CRecordVector<CUpdatePair2> updatePairs;
651 CDirItems dirItems;
652 CUpdateCallbackAgent updateCallbackAgent;
653 updateCallbackAgent.SetCallback(updateCallback100);
654 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
655 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
656
657 UInt32 realIndex;
658 {
659 CUIntVector realIndices;
660 _agentFolder->GetRealIndices(indices, numItems,
661 false, // includeAltStreams // we update only main stream of file
662 false, // includeFolderSubItemsInFlatMode
663 realIndices);
664 if (realIndices.Size() != 1)
665 return E_FAIL;
666 realIndex = realIndices[0];
667 }
668
669 {
670 FStringVector filePaths;
671 filePaths.Add(us2fs(diskFilePath));
672 dirItems.EnumerateItems2(FString(), UString(), filePaths, NULL);
673 if (dirItems.Items.Size() != 1)
674 return E_FAIL;
675 }
676
677 UInt32 numItemsInArchive;
678 RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
679 for (UInt32 i = 0; i < numItemsInArchive; i++)
680 {
681 CUpdatePair2 up2;
682 up2.SetAs_NoChangeArcItem(i);
683 if (realIndex == i)
684 {
685 up2.DirIndex = 0;
686 up2.NewData = true;
687 up2.NewProps = true;
688 up2.UseArcProps = false;
689 }
690 updatePairs.Add(up2);
691 }
692 updateCallbackSpec->DirItems = &dirItems;
693 updateCallbackSpec->Callback = &updateCallbackAgent;
694 updateCallbackSpec->UpdatePairs = &updatePairs;
695
696 SetInArchiveInterfaces(this, updateCallbackSpec);
697
698 updateCallbackSpec->KeepOriginalItemNames = true;
699 return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
700 }
701
SetProperties(const wchar_t * const * names,const PROPVARIANT * values,UInt32 numProps)702 STDMETHODIMP CAgent::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
703 {
704 m_PropNames.Clear();
705 m_PropValues.Clear();
706 for (UInt32 i = 0; i < numProps; i++)
707 {
708 m_PropNames.Add(names[i]);
709 m_PropValues.Add(values[i]);
710 }
711 return S_OK;
712 }
713