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