• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ArchiveFolderOut.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/ComTry.h"
6 
7 #include "../../../Windows/FileDir.h"
8 
9 #include "../../Common/FileStreams.h"
10 #include "../../Common/LimitedStreams.h"
11 
12 #include "../../Compress/CopyCoder.h"
13 
14 #include "../Common/WorkDir.h"
15 
16 #include "Agent.h"
17 
18 using namespace NWindows;
19 using namespace NFile;
20 using namespace NDir;
21 
GetPathParts(UStringVector & pathParts,bool & isAltStreamFolder)22 void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder)
23 {
24   if (_proxy2)
25     _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
26   else
27     _proxy->GetDirPathParts(_proxyDirIndex, pathParts);
28 }
29 
Delete_EmptyFolder_And_EmptySubFolders(const FString & path)30 static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path)
31 {
32   {
33     const FString pathPrefix = path + FCHAR_PATH_SEPARATOR;
34     CObjectVector<FString> names;
35     {
36       NFind::CDirEntry fileInfo;
37       NFind::CEnumerator enumerator;
38       enumerator.SetDirPrefix(pathPrefix);
39       for (;;)
40       {
41         bool found;
42         if (!enumerator.Next(fileInfo, found))
43           return false;
44         if (!found)
45           break;
46         if (fileInfo.IsDir())
47           names.Add(fileInfo.Name);
48       }
49     }
50     bool res = true;
51     FOR_VECTOR (i, names)
52     {
53       if (!Delete_EmptyFolder_And_EmptySubFolders(pathPrefix + names[i]))
54         res = false;
55     }
56     if (!res)
57       return false;
58   }
59   // we clear read-only attrib to remove read-only dir
60   if (!SetFileAttrib(path, 0))
61     return false;
62   return RemoveDir(path);
63 }
64 
CommonUpdateOperation(AGENT_OP operation,bool moveMode,const wchar_t * newItemName,const NUpdateArchive::CActionSet * actionSet,const UInt32 * indices,UInt32 numItems,IProgress * progress)65 HRESULT CAgentFolder::CommonUpdateOperation(
66     AGENT_OP operation,
67     bool moveMode,
68     const wchar_t *newItemName,
69     const NUpdateArchive::CActionSet *actionSet,
70     const UInt32 *indices, UInt32 numItems,
71     IProgress *progress)
72 {
73   if (moveMode && _agentSpec->_isHashHandler)
74     return E_NOTIMPL;
75 
76   if (!_agentSpec->CanUpdate())
77     return E_NOTIMPL;
78 
79   CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100;
80   if (progress)
81     progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&updateCallback100);
82 
83   try
84   {
85 
86   RINOK(_agentSpec->SetFolder(this))
87 
88   // ---------- Save FolderItem ----------
89 
90   UStringVector pathParts;
91   bool isAltStreamFolder = false;
92   GetPathParts(pathParts, isAltStreamFolder);
93 
94   FStringVector requestedPaths;
95   FStringVector processedPaths;
96 
97   CWorkDirTempFile tempFile;
98   RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath)))
99   {
100     CMyComPtr<IOutStream> tailStream;
101     const CArc &arc = *_agentSpec->_archiveLink.GetArc();
102 
103     if (arc.ArcStreamOffset == 0)
104       tailStream = tempFile.OutStream;
105     else
106     {
107       if (arc.Offset < 0)
108         return E_NOTIMPL;
109       RINOK(arc.InStream->Seek(0, STREAM_SEEK_SET, NULL))
110       RINOK(NCompress::CopyStream_ExactSize(arc.InStream, tempFile.OutStream, arc.ArcStreamOffset, NULL))
111       CTailOutStream *tailStreamSpec = new CTailOutStream;
112       tailStream = tailStreamSpec;
113       tailStreamSpec->Stream = tempFile.OutStream;
114       tailStreamSpec->Offset = arc.ArcStreamOffset;
115       tailStreamSpec->Init();
116     }
117 
118     HRESULT result;
119 
120     switch ((int)operation)
121     {
122       case AGENT_OP_Delete:
123         result = _agentSpec->DeleteItems(tailStream, indices, numItems, updateCallback100);
124         break;
125       case AGENT_OP_CreateFolder:
126         result = _agentSpec->CreateFolder(tailStream, newItemName, updateCallback100);
127         break;
128       case AGENT_OP_Rename:
129         result = _agentSpec->RenameItem(tailStream, indices, numItems, newItemName, updateCallback100);
130         break;
131       case AGENT_OP_Comment:
132         result = _agentSpec->CommentItem(tailStream, indices, numItems, newItemName, updateCallback100);
133         break;
134       case AGENT_OP_CopyFromFile:
135         result = _agentSpec->UpdateOneFile(tailStream, indices, numItems, newItemName, updateCallback100);
136         break;
137       case AGENT_OP_Uni:
138         {
139           Byte actionSetByte[NUpdateArchive::NPairState::kNumValues];
140           for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
141             actionSetByte[i] = (Byte)actionSet->StateActions[i];
142           result = _agentSpec->DoOperation2(
143               moveMode ? &requestedPaths : NULL,
144               moveMode ? &processedPaths : NULL,
145               tailStream, actionSetByte, NULL, updateCallback100);
146           break;
147         }
148       default:
149         return E_FAIL;
150     }
151 
152     RINOK(result)
153   }
154 
155   _agentSpec->KeepModeForNextOpen();
156   _agent->Close();
157 
158   // before 9.26: if there was error for MoveToOriginal archive was closed.
159   // now: we reopen archive after close
160 
161   // m_FolderItem = NULL;
162 
163   const HRESULT res = tempFile.MoveToOriginal(true);
164 
165   // RINOK(res);
166   if (res == S_OK)
167   {
168     if (moveMode)
169     {
170       unsigned i;
171       for (i = 0; i < processedPaths.Size(); i++)
172       {
173         DeleteFileAlways(processedPaths[i]);
174       }
175       for (i = 0; i < requestedPaths.Size(); i++)
176       {
177         const FString &fs = requestedPaths[i];
178         if (NFind::DoesDirExist(fs))
179           Delete_EmptyFolder_And_EmptySubFolders(fs);
180       }
181     }
182   }
183 
184   {
185     CMyComPtr<IArchiveOpenCallback> openCallback;
186     if (updateCallback100)
187       updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback);
188     RINOK(_agent->ReOpen(openCallback))
189   }
190 
191   // CAgent::ReOpen() deletes _proxy and _proxy2
192   _items.Clear();
193   _proxy = NULL;
194   _proxy2 = NULL;
195   _proxyDirIndex = k_Proxy_RootDirIndex;
196   _isAltStreamFolder = false;
197 
198 
199   // ---------- Restore FolderItem ----------
200 
201   CMyComPtr<IFolderFolder> archiveFolder;
202   RINOK(_agent->BindToRootFolder(&archiveFolder))
203 
204   // CAgent::BindToRootFolder() changes _proxy and _proxy2
205   _proxy = _agentSpec->_proxy;
206   _proxy2 = _agentSpec->_proxy2;
207 
208   if (_proxy)
209   {
210     FOR_VECTOR (i, pathParts)
211     {
212       const int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]);
213       if (next == -1)
214         break;
215       _proxyDirIndex = (unsigned)next;
216     }
217   }
218 
219   if (_proxy2)
220   {
221     if (pathParts.IsEmpty() && isAltStreamFolder)
222     {
223       _proxyDirIndex = k_Proxy2_AltRootDirIndex;
224     }
225     else FOR_VECTOR (i, pathParts)
226     {
227       const bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder);
228       const int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly);
229       if (index == -1)
230         break;
231 
232       const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]];
233 
234       if (dirOnly)
235         _proxyDirIndex = (unsigned)file.DirIndex;
236       else
237       {
238         if (file.AltDirIndex != -1)
239           _proxyDirIndex = (unsigned)file.AltDirIndex;
240         break;
241       }
242     }
243   }
244 
245   /*
246   if (pathParts.IsEmpty() && isAltStreamFolder)
247   {
248     CMyComPtr<IFolderAltStreams> folderAltStreams;
249     archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams);
250     if (folderAltStreams)
251     {
252       CMyComPtr<IFolderFolder> newFolder;
253       folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder);
254       if (newFolder)
255         archiveFolder = newFolder;
256     }
257   }
258 
259   FOR_VECTOR (i, pathParts)
260   {
261     CMyComPtr<IFolderFolder> newFolder;
262 
263     if (isAltStreamFolder && i == pathParts.Size() - 1)
264     {
265       CMyComPtr<IFolderAltStreams> folderAltStreams;
266       archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams);
267       if (folderAltStreams)
268         folderAltStreams->BindToAltStreams(pathParts[i], &newFolder);
269     }
270     else
271       archiveFolder->BindToFolder(pathParts[i], &newFolder);
272 
273     if (!newFolder)
274       break;
275     archiveFolder = newFolder;
276   }
277 
278   CMyComPtr<IArchiveFolderInternal> archiveFolderInternal;
279   RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal));
280   CAgentFolder *agentFolder;
281   RINOK(archiveFolderInternal->GetAgentFolder(&agentFolder));
282   _proxyDirIndex = agentFolder->_proxyDirIndex;
283   // _parentFolder = agentFolder->_parentFolder;
284   */
285 
286   if (_proxy2)
287     _isAltStreamFolder = _proxy2->IsAltDir(_proxyDirIndex);
288 
289   return res;
290 
291   }
292   catch(const UString &s)
293   {
294     if (updateCallback100)
295     {
296       UString s2 ("Error: ");
297       s2 += s;
298       RINOK(updateCallback100->UpdateErrorMessage(s2))
299       return E_FAIL;
300     }
301     throw;
302   }
303 }
304 
305 
Z7_COM7F_IMF(CAgentFolder::CopyFrom (Int32 moveMode,const wchar_t * fromFolderPath,const wchar_t * const * itemsPaths,UInt32 numItems,IProgress * progress))306 Z7_COM7F_IMF(CAgentFolder::CopyFrom(Int32 moveMode,
307     const wchar_t *fromFolderPath, /* test it */
308     const wchar_t * const *itemsPaths,
309     UInt32 numItems,
310     IProgress *progress))
311 {
312   COM_TRY_BEGIN
313   {
314     RINOK(_agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems))
315     return CommonUpdateOperation(AGENT_OP_Uni, (moveMode != 0), NULL,
316         &NUpdateArchive::k_ActionSet_Add,
317         NULL, 0, progress);
318   }
319   COM_TRY_END
320 }
321 
Z7_COM7F_IMF(CAgentFolder::CopyFromFile (UInt32 destIndex,const wchar_t * itemPath,IProgress * progress))322 Z7_COM7F_IMF(CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPath, IProgress *progress))
323 {
324   COM_TRY_BEGIN
325   return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath,
326       &NUpdateArchive::k_ActionSet_Add,
327       &destIndex, 1, progress);
328   COM_TRY_END
329 }
330 
Z7_COM7F_IMF(CAgentFolder::Delete (const UInt32 * indices,UInt32 numItems,IProgress * progress))331 Z7_COM7F_IMF(CAgentFolder::Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress))
332 {
333   COM_TRY_BEGIN
334   return CommonUpdateOperation(AGENT_OP_Delete, false, NULL,
335       &NUpdateArchive::k_ActionSet_Delete, indices, numItems, progress);
336   COM_TRY_END
337 }
338 
Z7_COM7F_IMF(CAgentFolder::CreateFolder (const wchar_t * name,IProgress * progress))339 Z7_COM7F_IMF(CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress))
340 {
341   COM_TRY_BEGIN
342 
343   if (_isAltStreamFolder)
344     return E_NOTIMPL;
345 
346   if (_proxy2)
347   {
348     if (_proxy2->IsThere_SubDir(_proxyDirIndex, name))
349       return ERROR_ALREADY_EXISTS;
350   }
351   else
352   {
353     if (_proxy->FindSubDir(_proxyDirIndex, name) != -1)
354       return ERROR_ALREADY_EXISTS;
355   }
356 
357   return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress);
358   COM_TRY_END
359 }
360 
Z7_COM7F_IMF(CAgentFolder::Rename (UInt32 index,const wchar_t * newName,IProgress * progress))361 Z7_COM7F_IMF(CAgentFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress))
362 {
363   COM_TRY_BEGIN
364   return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL,
365       &index, 1, progress);
366   COM_TRY_END
367 }
368 
Z7_COM7F_IMF(CAgentFolder::CreateFile (const wchar_t *,IProgress *))369 Z7_COM7F_IMF(CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */))
370 {
371   return E_NOTIMPL;
372 }
373 
Z7_COM7F_IMF(CAgentFolder::SetProperty (UInt32 index,PROPID propID,const PROPVARIANT * value,IProgress * progress))374 Z7_COM7F_IMF(CAgentFolder::SetProperty(UInt32 index, PROPID propID,
375     const PROPVARIANT *value, IProgress *progress))
376 {
377   COM_TRY_BEGIN
378   if (propID != kpidComment || value->vt != VT_BSTR)
379     return E_NOTIMPL;
380   if (!_agentSpec || !_agentSpec->GetTypeOfArc(_agentSpec->GetArc()).IsEqualTo_Ascii_NoCase("zip"))
381     return E_NOTIMPL;
382 
383   return CommonUpdateOperation(AGENT_OP_Comment, false, value->bstrVal, NULL,
384       &index, 1, progress);
385   COM_TRY_END
386 }
387