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