// 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 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 openCallback; if (updateCallback100) { RINOK(updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback)); } RINOK(_agentSpec->ReOpen(openCallback)); } // Restore FolderItem; CMyComPtr archiveFolder; RINOK(_agentSpec->BindToRootFolder(&archiveFolder)); FOR_VECTOR (i, pathParts) { CMyComPtr newFolder; archiveFolder->BindToFolder(pathParts[i], &newFolder); if(!newFolder) break; archiveFolder = newFolder; } CMyComPtr 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 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 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 updateCallback100; if (progress) { CMyComPtr 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 updateCallback100; if (progress) { CMyComPtr 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 updateCallback100; if (progress) { CMyComPtr 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; }