Files
easy7zip/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
Igor Pavlov f08f4dcc3c 9.34
2016-05-28 00:16:51 +01:00

311 lines
8.7 KiB
C++

// FolderOut.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.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 NDir;
void CAgentFolder::GetPathParts(UStringVector &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,
IFolderArchiveUpdateCallback *updateCallback100)
{
if (!_agentSpec->CanUpdate())
return E_NOTIMPL;
////////////////////////////
// Save FolderItem;
UStringVector pathParts;
GetPathParts(pathParts);
FStringVector requestedPaths;
FStringVector processedPaths;
CWorkDirTempFile tempFile;
RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath)));
{
CMyComPtr<IOutStream> tailStream;
const CArc &arc = *_agentSpec->_archiveLink.GetArc();
if (arc.ArcStreamOffset == 0)
tailStream = tempFile.OutStream;
else
{
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();
}
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);
}
_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;
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;
if (updateCallback100)
{
RINOK(updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback));
}
RINOK(_agentSpec->ReOpen(openCallback));
}
// Restore FolderItem;
CMyComPtr<IFolderFolder> archiveFolder;
RINOK(_agentSpec->BindToRootFolder(&archiveFolder));
FOR_VECTOR (i, pathParts)
{
CMyComPtr<IFolderFolder> newFolder;
archiveFolder->BindToFolder(pathParts[i], &newFolder);
if(!newFolder)
break;
archiveFolder = newFolder;
}
CMyComPtr<IArchiveFolderInternal> archiveFolderInternal;
RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal));
CAgentFolder *agentFolder;
RINOK(archiveFolderInternal->GetAgentFolder(&agentFolder));
_proxyFolderItem = agentFolder->_proxyFolderItem;
_proxyArchive = agentFolder->_proxyArchive;
_proxyArchive2 = agentFolder->_proxyArchive2;
_parentFolder = agentFolder->_parentFolder;
return res;
}
STDMETHODIMP CAgentFolder::CopyFrom(Int32 moveMode,
const wchar_t *fromFolderPath, // test it
const wchar_t **itemsPaths,
UInt32 numItems,
IProgress *progress)
{
COM_TRY_BEGIN
CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100;
if (progress)
{
RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&updateCallback100));
}
try
{
RINOK(_agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems));
RINOK(_agentSpec->SetFolder(this));
return CommonUpdateOperation(AGENT_OP_Uni, (moveMode != 0), NULL,
&NUpdateArchive::k_ActionSet_Add,
0, 0, updateCallback100);
}
catch(const UString &s)
{
RINOK(updateCallback100->UpdateErrorMessage(UString(L"Error: ") + s));
return E_FAIL;
}
COM_TRY_END
}
STDMETHODIMP CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPath, IProgress * progress)
{
COM_TRY_BEGIN
CUIntVector indices;
indices.Add(destIndex);
CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100;
if (progress)
{
RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&updateCallback100));
}
try
{
RINOK(_agentSpec->SetFolder(this));
return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath,
&NUpdateArchive::k_ActionSet_Add,
&indices.Front(), indices.Size(), updateCallback100);
}
catch(const UString &s)
{
RINOK(updateCallback100->UpdateErrorMessage(UString(L"Error: ") + s));
return E_FAIL;
}
COM_TRY_END
}
STDMETHODIMP CAgentFolder::Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress)
{
COM_TRY_BEGIN
RINOK(_agentSpec->SetFolder(this));
CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100;
if (progress)
{
CMyComPtr<IProgress> progressWrapper = progress;
RINOK(progressWrapper.QueryInterface(
IID_IFolderArchiveUpdateCallback, &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 (_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)
{
CMyComPtr<IProgress> progressWrapper = progress;
RINOK(progressWrapper.QueryInterface(IID_IFolderArchiveUpdateCallback, &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)
{
COM_TRY_BEGIN
CUIntVector indices;
indices.Add(index);
RINOK(_agentSpec->SetFolder(this));
CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100;
if (progress)
{
CMyComPtr<IProgress> progressWrapper = progress;
RINOK(progressWrapper.QueryInterface(IID_IFolderArchiveUpdateCallback, &updateCallback100));
}
return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL, &indices.Front(),
indices.Size(), updateCallback100);
COM_TRY_END
}
STDMETHODIMP CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CAgentFolder::SetProperty(UInt32 /* index */, PROPID /* propID */,
const PROPVARIANT * /* value */, IProgress * /* progress */)
{
return E_NOTIMPL;
}