diff options
Diffstat (limited to 'CPP/7zip/UI/Agent/AgentOut.cpp')
-rwxr-xr-x | CPP/7zip/UI/Agent/AgentOut.cpp | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp new file mode 100755 index 00000000..25d65bb2 --- /dev/null +++ b/CPP/7zip/UI/Agent/AgentOut.cpp @@ -0,0 +1,518 @@ +// AgentOut.cpp + +#include "StdAfx.h" + +#include "Common/StringConvert.h" +#include "Common/IntToString.h" + +#include "Windows/Defs.h" +#include "Windows/PropVariant.h" +#include "Windows/PropVariantConversions.h" +#include "Windows/FileDir.h" + +#include "../../Compress/Copy/CopyCoder.h" +#include "../../Common/FileStreams.h" + +#include "../Common/UpdatePair.h" +#include "../Common/EnumDirItems.h" +#include "../Common/HandlerLoader.h" +#include "../Common/UpdateCallback.h" +#include "../Common/OpenArchive.h" + +#include "Agent.h" +#include "UpdateCallbackAgent.h" + +using namespace NWindows; +using namespace NCOM; + +static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream) +{ + CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder; + return copyCoder->Code(inStream, outStream, NULL, NULL, NULL); +} + +STDMETHODIMP CAgent::SetFolder(IFolderFolder *folder) +{ + _archiveNamePrefix.Empty(); + if (folder == NULL) + { + _agentFolder = NULL; + return S_OK; + } + else + { + CMyComPtr<IFolderFolder> archiveFolder = folder; + CMyComPtr<IArchiveFolderInternal> archiveFolderInternal; + RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal)); + RINOK(archiveFolderInternal->GetAgentFolder(&_agentFolder)); + } + + UStringVector pathParts; + pathParts.Clear(); + CMyComPtr<IFolderFolder> folderItem = folder; + if (folderItem != NULL) + for (;;) + { + CMyComPtr<IFolderFolder> newFolder; + folderItem->BindToParentFolder(&newFolder); + if (newFolder == NULL) + break; + CMyComBSTR name; + folderItem->GetName(&name); + pathParts.Insert(0, (const wchar_t *)name); + folderItem = newFolder; + } + + for(int i = 0; i < pathParts.Size(); i++) + { + _archiveNamePrefix += pathParts[i]; + _archiveNamePrefix += L'\\'; + } + return S_OK; +} + +STDMETHODIMP CAgent::SetFiles(const wchar_t *folderPrefix, + const wchar_t **names, UINT32 numNames) +{ + _folderPrefix = folderPrefix; + _names.Clear(); + _names.Reserve(numNames); + for (UINT32 i = 0; i < numNames; i++) + _names.Add(names[i]); + return S_OK; +} + + +static HRESULT GetFileTime(CAgent *agent, UINT32 itemIndex, FILETIME &fileTime) +{ + CPropVariant property; + RINOK(agent->GetArchive()->GetProperty(itemIndex, kpidLastWriteTime, &property)); + if (property.vt == VT_FILETIME) + fileTime = property.filetime; + else if (property.vt == VT_EMPTY) + fileTime = agent->DefaultTime; + else + throw 4190407; + return S_OK; +} + +static HRESULT EnumerateArchiveItems(CAgent *agent, + const CProxyFolder &item, + const UString &prefix, + CObjectVector<CArchiveItem> &archiveItems) +{ + int i; + for(i = 0; i < item.Files.Size(); i++) + { + const CProxyFile &fileItem = item.Files[i]; + CArchiveItem archiveItem; + + RINOK(::GetFileTime(agent, fileItem.Index, archiveItem.LastWriteTime)); + + CPropVariant property; + agent->GetArchive()->GetProperty(fileItem.Index, kpidSize, &property); + archiveItem.SizeIsDefined = (property.vt != VT_EMPTY); + if (archiveItem.SizeIsDefined) + archiveItem.Size = ConvertPropVariantToUInt64(property); + archiveItem.IsDirectory = false; + archiveItem.Name = prefix + fileItem.Name; + archiveItem.Censored = true; // test it + archiveItem.IndexInServer = fileItem.Index; + archiveItems.Add(archiveItem); + } + for(i = 0; i < item.Folders.Size(); i++) + { + const CProxyFolder &dirItem = item.Folders[i]; + UString fullName = prefix + dirItem.Name; + if(dirItem.IsLeaf) + { + CArchiveItem archiveItem; + RINOK(::GetFileTime(agent, dirItem.Index, archiveItem.LastWriteTime)); + archiveItem.IsDirectory = true; + archiveItem.SizeIsDefined = false; + archiveItem.Name = fullName; + archiveItem.Censored = true; // test it + archiveItem.IndexInServer = dirItem.Index; + archiveItems.Add(archiveItem); + } + RINOK(EnumerateArchiveItems(agent, dirItem, fullName + UString(L'\\'), archiveItems)); + } + return S_OK; +} + +STDMETHODIMP CAgent::DoOperation( + const wchar_t *filePath, + const CLSID *clsID, + const wchar_t *newArchiveName, + const Byte *stateActions, + const wchar_t *sfxModule, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + NUpdateArchive::CActionSet actionSet; + int i; + for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++) + actionSet.StateActions[i] = (NUpdateArchive::NPairAction::EEnum)stateActions[i]; + + CObjectVector<CDirItem> dirItems; + + UString folderPrefix = _folderPrefix; + NFile::NName::NormalizeDirPathPrefix(folderPrefix); + UStringVector errorPaths; + CRecordVector<DWORD> errorCodes; + ::EnumerateDirItems(folderPrefix, _names, _archiveNamePrefix, dirItems, errorPaths, errorCodes); + if (errorCodes.Size() > 0) + { + return errorCodes.Front(); + } + + NWindows::NDLL::CLibrary library; + + CMyComPtr<IOutArchive> outArchive; + if (GetArchive()) + { + RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)); + } + else + { + CHandlerLoader loader; + RINOK(loader.CreateHandler(filePath, *clsID, (void **)&outArchive, true)); + library.Attach(loader.Detach()); + } + + NFileTimeType::EEnum fileTimeType; + UINT32 value; + RINOK(outArchive->GetFileTimeType(&value)); + + switch(value) + { + case NFileTimeType::kWindows: + case NFileTimeType::kDOS: + case NFileTimeType::kUnix: + fileTimeType = NFileTimeType::EEnum(value); + break; + default: + return E_FAIL; + } + + CObjectVector<CUpdatePair> updatePairs; + + CObjectVector<CArchiveItem> archiveItems; + if (GetArchive()) + { + RINOK(ReadItems()); + EnumerateArchiveItems(this, _proxyArchive->RootFolder, L"", archiveItems); + } + + GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs); + + CObjectVector<CUpdatePair2> updatePairs2; + UpdateProduce(updatePairs, actionSet, updatePairs2); + + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.Callback = updateCallback100; + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec ); + + updateCallbackSpec->DirPrefix = folderPrefix; + updateCallbackSpec->DirItems = &dirItems; + updateCallbackSpec->ArchiveItems = &archiveItems; + updateCallbackSpec->UpdatePairs = &updatePairs2; + updateCallbackSpec->Archive = GetArchive(); + updateCallbackSpec->Callback = &updateCallbackAgent; + + COutFileStream *outStreamSpec = new COutFileStream; + CMyComPtr<IOutStream> outStream(outStreamSpec); + UString archiveName = newArchiveName; + { + UString resultPath; + int pos; + if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos)) + throw 141716; + NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos)); + } + if (!outStreamSpec->Create(archiveName, true)) + { + // ShowLastErrorMessage(); + return E_FAIL; + } + + CMyComPtr<ISetProperties> setProperties; + if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK) + { + if (m_PropNames.Size() == 0) + { + RINOK(setProperties->SetProperties(0, 0, 0)); + } + else + { + CRecordVector<const wchar_t *> names; + for(i = 0; i < m_PropNames.Size(); i++) + names.Add((const wchar_t *)m_PropNames[i]); + + NWindows::NCOM::CPropVariant *propValues = new NWindows::NCOM::CPropVariant[m_PropValues.Size()]; + try + { + for (int i = 0; i < m_PropValues.Size(); i++) + propValues[i] = m_PropValues[i]; + RINOK(setProperties->SetProperties(&names.Front(), propValues, names.Size())); + } + catch(...) + { + delete []propValues; + throw; + } + delete []propValues; + } + } + m_PropNames.Clear(); + m_PropValues.Clear(); + + if (sfxModule != NULL) + { + CInFileStream *sfxStreamSpec = new CInFileStream; + CMyComPtr<IInStream> sfxStream(sfxStreamSpec); + if (!sfxStreamSpec->Open(sfxModule)) + throw "Can't open sfx module"; + RINOK(CopyBlock(sfxStream, outStream)); + } + + return outArchive->UpdateItems(outStream, updatePairs2.Size(),updateCallback); +} + + +HRESULT CAgent::CommonUpdate( + const wchar_t *newArchiveName, + int numUpdateItems, + IArchiveUpdateCallback *updateCallback) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CMyComPtr<IOutArchive> outArchive; + RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive)); + + COutFileStream *outStreamSpec = new COutFileStream; + CMyComPtr<IOutStream> outStream(outStreamSpec); + + UString archiveName = newArchiveName; + { + UString resultPath; + int pos; + if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos)) + throw 141716; + NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos)); + } + + /* + bool isOK = false; + for (int i = 0; i < (1 << 16); i++) + { + resultName = newArchiveName; + if (i > 0) + { + wchar_t s[32]; + ConvertUInt64ToString(i, s); + resultName += s; + } + if (outStreamSpec->Open(realPath)) + { + isOK = true; + break; + } + if (::GetLastError() != ERROR_FILE_EXISTS) + return ::GetLastError(); + } + if (!isOK) + return ::GetLastError(); + */ + if (!outStreamSpec->Create(archiveName, true)) + { + // ShowLastErrorMessage(); + return E_FAIL; + } + + return outArchive->UpdateItems(outStream, numUpdateItems, updateCallback); +} + + +STDMETHODIMP CAgent::DeleteItems( + const wchar_t *newArchiveName, + const UINT32 *indices, UINT32 numItems, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.Callback = updateCallback100; + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); + + CUIntVector realIndices; + _agentFolder->GetRealIndices(indices, numItems, realIndices); + CObjectVector<CUpdatePair2> updatePairs; + int curIndex = 0; + UInt32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)); + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + if (curIndex < realIndices.Size()) + if (realIndices[curIndex] == i) + { + curIndex++; + continue; + } + CUpdatePair2 updatePair; + updatePair.NewData = updatePair.NewProperties = false; + updatePair.ExistInArchive = true; + updatePair.ExistOnDisk = false; + updatePair.IsAnti = false; // check it. Maybe it can be undefined + updatePair.ArchiveItemIndex = i; + updatePairs.Add(updatePair); + } + updateCallbackSpec->UpdatePairs = &updatePairs; + updateCallbackSpec->Archive = GetArchive(); + updateCallbackSpec->Callback = &updateCallbackAgent; + return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback); +} + +HRESULT CAgent::CreateFolder( + const wchar_t *newArchiveName, + const wchar_t *folderName, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.Callback = updateCallback100; + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); + + CObjectVector<CUpdatePair2> updatePairs; + UINT32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)); + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + CUpdatePair2 updatePair; + updatePair.NewData = updatePair.NewProperties = false; + updatePair.ExistInArchive = true; + updatePair.ExistOnDisk = false; + updatePair.IsAnti = false; // check it. + updatePair.ArchiveItemIndex = i; + updatePairs.Add(updatePair); + } + CUpdatePair2 updatePair; + updatePair.NewData = updatePair.NewProperties = true; + updatePair.ExistInArchive = false; + updatePair.ExistOnDisk = true; + updatePair.IsAnti = false; + updatePair.ArchiveItemIndex = -1; + updatePair.DirItemIndex = 0; + + updatePairs.Add(updatePair); + + CObjectVector<CDirItem> dirItems; + CDirItem dirItem; + + dirItem.Attributes = FILE_ATTRIBUTE_DIRECTORY; + dirItem.Size = 0; + dirItem.Name = _agentFolder->_proxyFolderItem->GetFullPathPrefix() + folderName; + + SYSTEMTIME systemTime; + FILETIME fileTime; + ::GetSystemTime(&systemTime); + ::SystemTimeToFileTime(&systemTime, &fileTime); + dirItem.LastAccessTime = dirItem.LastWriteTime = + dirItem.CreationTime = fileTime; + + dirItems.Add(dirItem); + + updateCallbackSpec->Callback = &updateCallbackAgent; + updateCallbackSpec->DirItems = &dirItems; + updateCallbackSpec->UpdatePairs = &updatePairs; + updateCallbackSpec->Archive = GetArchive(); + return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback); +} + + +HRESULT CAgent::RenameItem( + const wchar_t *newArchiveName, + const UINT32 *indices, UINT32 numItems, + const wchar_t *newItemName, + IFolderArchiveUpdateCallback *updateCallback100) +{ + if (!CanUpdate()) + return E_NOTIMPL; + if (numItems != 1) + return E_INVALIDARG; + CUpdateCallbackAgent updateCallbackAgent; + updateCallbackAgent.Callback = updateCallback100; + CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; + CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); + + CUIntVector realIndices; + _agentFolder->GetRealIndices(indices, numItems, realIndices); + + UString fullPrefix = _agentFolder->GetFullPathPrefixPlusPrefix(indices[0]); + UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]); + UString newItemPath = fullPrefix + newItemName; + + CObjectVector<CUpdatePair2> updatePairs; + int curIndex = 0; + UINT32 numItemsInArchive; + RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive)); + for (UInt32 i = 0; i < numItemsInArchive; i++) + { + if (curIndex < realIndices.Size()) + if (realIndices[curIndex] == i) + { + CUpdatePair2 updatePair; + updatePair.NewData = false; + updatePair.NewProperties = true; + updatePair.ExistInArchive = true; + updatePair.ExistOnDisk = false; + RINOK(IsArchiveItemAnti(GetArchive(), i, updatePair.IsAnti)); + updatePair.ArchiveItemIndex = i; + updatePair.NewNameIsDefined = true; + + updatePair.NewName = newItemName; + + UString oldFullPath; + RINOK(GetArchiveItemPath(GetArchive(), i, DefaultName, oldFullPath)); + + if (oldItemPath.CompareNoCase(oldFullPath.Left(oldItemPath.Length())) != 0) + return E_INVALIDARG; + + updatePair.NewName = newItemPath + oldFullPath.Mid(oldItemPath.Length()); + updatePairs.Add(updatePair); + curIndex++; + continue; + } + CUpdatePair2 updatePair; + updatePair.NewData = updatePair.NewProperties = false; + updatePair.ExistInArchive = true; + updatePair.ExistOnDisk = false; + updatePair.IsAnti = false; + updatePair.ArchiveItemIndex = i; + updatePairs.Add(updatePair); + } + updateCallbackSpec->Callback = &updateCallbackAgent; + updateCallbackSpec->UpdatePairs = &updatePairs; + updateCallbackSpec->Archive = GetArchive(); + return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback); +} + +STDMETHODIMP CAgent::SetProperties(const wchar_t **names, + const PROPVARIANT *values, INT32 numProperties) +{ + m_PropNames.Clear(); + m_PropValues.Clear(); + for (int i = 0; i < numProperties; i++) + { + m_PropNames.Add(names[i]); + m_PropValues.Add(values[i]); + } + return S_OK; +} + + |