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