diff options
Diffstat (limited to 'CPP/7zip/UI/Agent/ArchiveFolderOut.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/UI/Agent/ArchiveFolderOut.cpp | 197 |
1 files changed, 142 insertions, 55 deletions
diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp index 656602cb..003f6d98 100755..100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp @@ -2,79 +2,157 @@ #include "StdAfx.h" -#include "Common/ComTry.h" +#include "../../../Common/ComTry.h" -#include "Windows/FileDir.h" +#include "../../../Windows/FileDir.h" #include "../../Common/FileStreams.h" +#include "../../Common/LimitedStreams.h" + +#include "../../Compress/CopyCoder.h" + #include "../Common/WorkDir.h" #include "Agent.h" using namespace NWindows; using namespace NFile; -using namespace NDirectory; +using namespace NDir; void CAgentFolder::GetPathParts(UStringVector &pathParts) { - _proxyFolderItem->GetPathParts(pathParts); + if (_proxyArchive2) + _proxyArchive2->GetPathParts(_proxyFolderItem, pathParts); + else + _proxyArchive->GetPathParts(_proxyFolderItem, pathParts); +} + +static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) +{ + NFind::CFileInfo fileInfo; + FString pathPrefix = path + FCHAR_PATH_SEPARATOR; + { + NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK); + while (enumerator.Next(fileInfo)) + { + if (fileInfo.IsDir()) + if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name)) + return false; + } + } + /* + // we don't need clear readonly for folders + if (!SetFileAttrib(path, 0)) + return false; + */ + return RemoveDir(path); } + HRESULT CAgentFolder::CommonUpdateOperation( AGENT_OP operation, + bool moveMode, const wchar_t *newItemName, const NUpdateArchive::CActionSet *actionSet, - const UINT32 *indices, UINT32 numItems, + const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback100) { - CWorkDirTempFile tempFile; - RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath))); + if (!_agentSpec->CanUpdate()) + return E_NOTIMPL; - /* - if (SetOutProperties(anOutArchive, aCompressionInfo.Method) != S_OK) - return NFileOperationReturnCode::kError; - */ - //////////////////////////// // Save FolderItem; UStringVector pathParts; GetPathParts(pathParts); - HRESULT result; - switch (operation) + FStringVector requestedPaths; + FStringVector processedPaths; + + CWorkDirTempFile tempFile; + RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath))); { - case AGENT_OP_Delete: - result = _agentSpec->DeleteItems(tempFile.OutStream, indices, numItems, updateCallback100); - break; - case AGENT_OP_CreateFolder: - result = _agentSpec->CreateFolder(tempFile.OutStream, newItemName, updateCallback100); - break; - case AGENT_OP_Rename: - result = _agentSpec->RenameItem(tempFile.OutStream, indices, numItems, newItemName, updateCallback100); - break; - case AGENT_OP_CopyFromFile: - result = _agentSpec->UpdateOneFile(tempFile.OutStream, indices, numItems, newItemName, updateCallback100); - break; - case AGENT_OP_Uni: + CMyComPtr<IOutStream> tailStream; + const CArc &arc = *_agentSpec->_archiveLink.GetArc(); + + if (arc.ArcStreamOffset == 0) + tailStream = tempFile.OutStream; + else { - Byte actionSetByte[NUpdateArchive::NPairState::kNumValues]; - for (int i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) - actionSetByte[i] = (Byte)actionSet->StateActions[i]; - result = _agentSpec->DoOperation2(tempFile.OutStream, actionSetByte, NULL, updateCallback100); - break; + if (arc.Offset < 0) + return E_NOTIMPL; + RINOK(arc.InStream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(NCompress::CopyStream_ExactSize(arc.InStream, tempFile.OutStream, arc.ArcStreamOffset, NULL)); + CTailOutStream *tailStreamSpec = new CTailOutStream; + tailStream = tailStreamSpec; + tailStreamSpec->Stream = tempFile.OutStream; + tailStreamSpec->Offset = arc.ArcStreamOffset; + tailStreamSpec->Init(); } - default: - return E_FAIL; + + HRESULT result; + + switch (operation) + { + case AGENT_OP_Delete: + result = _agentSpec->DeleteItems(tailStream, indices, numItems, updateCallback100); + break; + case AGENT_OP_CreateFolder: + result = _agentSpec->CreateFolder(tailStream, newItemName, updateCallback100); + break; + case AGENT_OP_Rename: + result = _agentSpec->RenameItem(tailStream, indices, numItems, newItemName, updateCallback100); + break; + case AGENT_OP_CopyFromFile: + result = _agentSpec->UpdateOneFile(tailStream, indices, numItems, newItemName, updateCallback100); + break; + case AGENT_OP_Uni: + { + Byte actionSetByte[NUpdateArchive::NPairState::kNumValues]; + for (int i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) + actionSetByte[i] = (Byte)actionSet->StateActions[i]; + result = _agentSpec->DoOperation2( + moveMode ? &requestedPaths : NULL, + moveMode ? &processedPaths : NULL, + tailStream, actionSetByte, NULL, updateCallback100); + break; + } + default: + return E_FAIL; + } + + RINOK(result); } - - RINOK(result); + _agentSpec->KeepModeForNextOpen(); _agentSpec->Close(); + // before 9.26: if there was error for MoveToOriginal archive was closed. + // now: we reopen archive after close + // m_FolderItem = NULL; - RINOK(tempFile.MoveToOriginal(true)); + HRESULT res = tempFile.MoveToOriginal(true); + + // RINOK(res); + if (res == S_OK) + { + if (moveMode) + { + unsigned i; + for (i = 0; i < processedPaths.Size(); i++) + { + DeleteFileAlways(processedPaths[i]); + } + for (i = 0; i < requestedPaths.Size(); i++) + { + const FString &fs = requestedPaths[i]; + if (NFind::DoesDirExist(fs)) + DeleteEmptyFolderAndEmptySubFolders(fs); + } + } + } + { CMyComPtr<IArchiveOpenCallback> openCallback; @@ -85,12 +163,11 @@ HRESULT CAgentFolder::CommonUpdateOperation( RINOK(_agentSpec->ReOpen(openCallback)); } - //////////////////////////// // Restore FolderItem; CMyComPtr<IFolderFolder> archiveFolder; RINOK(_agentSpec->BindToRootFolder(&archiveFolder)); - for (int i = 0; i < pathParts.Size(); i++) + FOR_VECTOR (i, pathParts) { CMyComPtr<IFolderFolder> newFolder; archiveFolder->BindToFolder(pathParts[i], &newFolder); @@ -105,15 +182,16 @@ HRESULT CAgentFolder::CommonUpdateOperation( RINOK(archiveFolderInternal->GetAgentFolder(&agentFolder)); _proxyFolderItem = agentFolder->_proxyFolderItem; _proxyArchive = agentFolder->_proxyArchive; + _proxyArchive2 = agentFolder->_proxyArchive2; _parentFolder = agentFolder->_parentFolder; - return S_OK; + return res; } -STDMETHODIMP CAgentFolder::CopyFrom( +STDMETHODIMP CAgentFolder::CopyFrom(Int32 moveMode, const wchar_t *fromFolderPath, // test it const wchar_t **itemsPaths, - UINT32 numItems, + UInt32 numItems, IProgress *progress) { COM_TRY_BEGIN @@ -126,8 +204,9 @@ STDMETHODIMP CAgentFolder::CopyFrom( { RINOK(_agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems)); RINOK(_agentSpec->SetFolder(this)); - return CommonUpdateOperation(AGENT_OP_Uni, NULL, - &NUpdateArchive::kAddActionSet, 0, 0, updateCallback100); + return CommonUpdateOperation(AGENT_OP_Uni, (moveMode != 0), NULL, + &NUpdateArchive::k_ActionSet_Add, + 0, 0, updateCallback100); } catch(const UString &s) { @@ -150,8 +229,8 @@ STDMETHODIMP CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPat try { RINOK(_agentSpec->SetFolder(this)); - return CommonUpdateOperation(AGENT_OP_CopyFromFile, itemPath, - &NUpdateArchive::kAddActionSet, + return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath, + &NUpdateArchive::k_ActionSet_Add, &indices.Front(), indices.Size(), updateCallback100); } catch(const UString &s) @@ -162,7 +241,7 @@ STDMETHODIMP CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPat COM_TRY_END } -STDMETHODIMP CAgentFolder::Delete(const UINT32 *indices, UINT32 numItems, IProgress *progress) +STDMETHODIMP CAgentFolder::Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress) { COM_TRY_BEGIN RINOK(_agentSpec->SetFolder(this)); @@ -173,16 +252,24 @@ STDMETHODIMP CAgentFolder::Delete(const UINT32 *indices, UINT32 numItems, IProgr RINOK(progressWrapper.QueryInterface( IID_IFolderArchiveUpdateCallback, &updateCallback100)); } - return CommonUpdateOperation(AGENT_OP_Delete, NULL, - &NUpdateArchive::kDeleteActionSet, indices, numItems, updateCallback100); + return CommonUpdateOperation(AGENT_OP_Delete, false, NULL, + &NUpdateArchive::k_ActionSet_Delete, indices, numItems, updateCallback100); COM_TRY_END } STDMETHODIMP CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress) { COM_TRY_BEGIN - if (_proxyFolderItem->FindDirSubItemIndex(name) >= 0) - return ERROR_ALREADY_EXISTS; + if (_proxyArchive2) + { + if (_proxyArchive2->IsThere_SubDir(_proxyFolderItem, name)) + return ERROR_ALREADY_EXISTS; + } + else + { + if (_proxyArchive->FindDirSubItemIndex(_proxyFolderItem, name) >= 0) + return ERROR_ALREADY_EXISTS; + } RINOK(_agentSpec->SetFolder(this)); CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100; if (progress) @@ -190,11 +277,11 @@ STDMETHODIMP CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress CMyComPtr<IProgress> progressWrapper = progress; RINOK(progressWrapper.QueryInterface(IID_IFolderArchiveUpdateCallback, &updateCallback100)); } - return CommonUpdateOperation(AGENT_OP_CreateFolder, name, NULL, NULL, 0, updateCallback100); + return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, updateCallback100); COM_TRY_END } -STDMETHODIMP CAgentFolder::Rename(UINT32 index, const wchar_t *newName, IProgress *progress) +STDMETHODIMP CAgentFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress) { COM_TRY_BEGIN CUIntVector indices; @@ -206,7 +293,7 @@ STDMETHODIMP CAgentFolder::Rename(UINT32 index, const wchar_t *newName, IProgres CMyComPtr<IProgress> progressWrapper = progress; RINOK(progressWrapper.QueryInterface(IID_IFolderArchiveUpdateCallback, &updateCallback100)); } - return CommonUpdateOperation(AGENT_OP_Rename, newName, NULL, &indices.Front(), + return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL, &indices.Front(), indices.Size(), updateCallback100); COM_TRY_END } @@ -216,7 +303,7 @@ STDMETHODIMP CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* return E_NOTIMPL; } -STDMETHODIMP CAgentFolder::SetProperty(UINT32 /* index */, PROPID /* propID */, +STDMETHODIMP CAgentFolder::SetProperty(UInt32 /* index */, PROPID /* propID */, const PROPVARIANT * /* value */, IProgress * /* progress */) { return E_NOTIMPL; |