⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 update.cpp

📁 7-Zip 3.11的源码
💻 CPP
字号:
// Update.cpp

#include "StdAfx.h"

#include "Update.h"

#include "Common/StdOutStream.h"
#include "Common/StringConvert.h"
#include "Common/MyCom.h"

#include "Windows/Defs.h"
#include "Windows/Error.h"
#include "Windows/FileDir.h"
#include "Windows/FileFind.h"
#include "Windows/FileName.h"
#include "Windows/PropVariant.h"
#include "Windows/PropVariantConversions.h"
#include "Windows/Error.h"

#include "../../Common/FileStreams.h"
#include "../../Compress/Copy/CopyCoder.h"

#include "../Common/DirItem.h"
#include "../Common/EnumDirItems.h"
#include "../Common/UpdateProduce.h"

#include "TempFiles.h"
#include "ConsoleClose.h"
#include "UpdateCallback.h"

#ifdef FORMAT_7Z
#include "../../Archive/7z/7zHandler.h"
#endif

#ifdef FORMAT_BZIP2
#include "../../Archive/BZip2/BZip2Handler.h"
#endif

#ifdef FORMAT_GZIP
#include "../../Archive/GZip/GZipHandler.h"
#endif

#ifdef FORMAT_TAR
#include "../../Archive/Tar/TarHandler.h"
#endif

#ifdef FORMAT_ZIP
#include "../../Archive/Zip/ZipHandler.h"
#endif

#ifndef EXCLUDE_COM
#include "../Common/HandlerLoader.h"
#endif

static const char *kCreatingArchiveMessage = "Creating archive ";
static const char *kUpdatingArchiveMessage = "Updating archive ";
static const char *kScanningMessage = "Scanning";
static const char *kNoFilesScannedMessage = "No files scanned";
static const char *kTotalFilesAddedMessage = "Total files added to archive: ";

using namespace NWindows;
using namespace NCOM;
using namespace NFile;
using namespace NName;

static wchar_t *kTempArchiveFilePrefixString = L"7zi";
static const char *kEverythingIsOk = "Everything is Ok";

static const char *kIllegalFileNameMessage = "Illegal file name for temp archive";

using namespace NUpdateArchive;

static bool ParseNumberString(const UString &srcString, UINT32 &number)
{
  wchar_t *anEndPtr;
  number = wcstoul(srcString, &anEndPtr, 10);
  return (anEndPtr - srcString == srcString.Length());
}


static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream)
{
  CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
  return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
}

HRESULT Compress(
    const CActionSet &actionSet, 
    IInArchive *archive,
    const CCompressionMethodMode &compressionMethod,
    const UString &archiveName, 
    const CObjectVector<CArchiveItem> &archiveItems,
    const CObjectVector<CDirItem> &dirItems,
    bool enablePercents,
    bool sfxMode,
    const UString &sfxModule)
{
  #ifndef EXCLUDE_COM
  CHandlerLoader loader;
  #endif

  CMyComPtr<IOutArchive> outArchive;
  if(archive != NULL)
  {
    CMyComPtr<IInArchive> archive2 = archive;
    HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
    if(result != S_OK)
    {
      throw "update operations are not supported for this archive";
    }
  }
  else
  {
    #ifndef EXCLUDE_COM

    HRESULT result = loader.CreateHandler(compressionMethod.FilePath, 
        compressionMethod.ClassID1, (void **)&outArchive, true);

    if (result != S_OK)
    {
      throw "update operations are not supported for this archive";
      return E_FAIL;
    }
    #endif

    #ifdef FORMAT_7Z
    if (compressionMethod.Name.CompareNoCase(L"7z") == 0)
      outArchive = new NArchive::N7z::CHandler;
    #endif

    #ifdef FORMAT_BZIP2
    if (compressionMethod.Name.CompareNoCase(L"BZip2") == 0)
      outArchive = new NArchive::NBZip2::CHandler;
    #endif

    #ifdef FORMAT_GZIP
    if (compressionMethod.Name.CompareNoCase(L"GZip") == 0)
      outArchive = new NArchive::NGZip::CHandler;
    #endif

    #ifdef FORMAT_TAR
    if (compressionMethod.Name.CompareNoCase(L"Tar") == 0)
      outArchive = new NArchive::NTar::CHandler;
    #endif
    
    #ifdef FORMAT_ZIP
    if (compressionMethod.Name.CompareNoCase(L"Zip") == 0)
      outArchive = new NArchive::NZip::CHandler;
    #endif


    if (outArchive == 0)
    {
      throw "update operations are not supported for this archive";
      return E_FAIL;
    }
  }
  
  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;
  GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs); // must be done only once!!!
  
  CObjectVector<CUpdatePair2> operationChain;
  UpdateProduce(dirItems, archiveItems, updatePairs, actionSet,
      operationChain);
  
  CUpdateCallbackImp *updateCallbackSpec = new CUpdateCallbackImp;
  CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
  
  updateCallbackSpec->Init(&dirItems, &archiveItems, &operationChain, enablePercents,
      compressionMethod.PasswordIsDefined, compressionMethod.Password, 
      compressionMethod.AskPassword);
  
  COutFileStream *outStreamSpec = new COutFileStream;
  CMyComPtr<IOutStream> outStream(outStreamSpec);

  {
    UString resultPath;
    int pos;
    if(! NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
      throw 141716;
    NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
  }
  if (!outStreamSpec->Open(archiveName))
  {
    UString message;
    NError::MyFormatMessage(::GetLastError(), message);
    g_StdOut << message << endl;
    return E_FAIL;
  }

  CMyComPtr<ISetProperties> setProperties;
  if (outArchive.QueryInterface(IID_ISetProperties, &setProperties) == S_OK)
  {
    CObjectVector<CMyComBSTR> realNames;
    std::vector<CPropVariant> values;
	  int i;
    for(i = 0; i < compressionMethod.Properties.Size(); i++)
    {
      const CProperty &property = compressionMethod.Properties[i];
      NCOM::CPropVariant propVariant;
      UINT32 number;
      if (!property.Value.IsEmpty())
      {
        if (ParseNumberString(property.Value, number))
          propVariant = number;
        else
          propVariant = property.Value;
      }
      CMyComBSTR comBSTR(property.Name);
      realNames.Add(comBSTR);
      values.push_back(propVariant);
    }
    std::vector<BSTR> names;
    for(i = 0; i < realNames.Size(); i++)
      names.push_back(realNames[i]);
 
    RINOK(setProperties->SetProperties(&names.front(), 
       &values.front(), names.size()));
  }

  if (sfxMode)
  {
    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, operationChain.Size(),
     updateCallback);
}

static void EnumerateDirItems(const NWildcard::CCensorNode &curNode, 
    const UString &directory, 
    const UString &prefix, 
    bool checkNameFull,
    CObjectVector<CDirItem> &dirItems, 
    bool enterToSubFolders)
{
  NConsoleClose::CheckCtrlBreak();

  NFind::CEnumeratorW enumerator(directory + wchar_t(kAnyStringWildcard));
  NFind::CFileInfoW fileInfo;
  while (enumerator.Next(fileInfo))
  {
    NConsoleClose::CheckCtrlBreak();
    UString unicodeName = fileInfo.Name;
    if (checkNameFull)
    {
      if (curNode.CheckNameFull(unicodeName))
        AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, 
            dirItems);
    }
    else
    {
      if (curNode.CheckNameRecursive(unicodeName))
        AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, 
            dirItems);
    }
    if (enterToSubFolders && fileInfo.IsDirectory())
    {
      const NWildcard::CCensorNode *nextNode = &curNode;
      if (checkNameFull)
      {
        nextNode = ((NWildcard::CCensorNode *)&curNode)->FindSubNode(unicodeName);
        if (nextNode == NULL)
          nextNode = &curNode;
      }
      EnumerateDirItems(*nextNode,   
          directory + fileInfo.Name + wchar_t(kDirDelimiter), 
          prefix + unicodeName + wchar_t(kDirDelimiter), 
          nextNode != (&curNode), dirItems, true);
    }
  }
}

static void EnumerateItems(const NWildcard::CCensorNode &curNode, 
    const UString &directory, 
    const UString &prefix,
    CObjectVector<CDirItem> &dirItems)
{
  NConsoleClose::CheckCtrlBreak();
  if (!curNode.GetAllowedRecursedNamesVector(false).IsEmpty() || 
      !curNode.GetAllowedRecursedNamesVector(true).IsEmpty()) 
  {
    EnumerateDirItems(curNode, directory, prefix, true, dirItems, 
        true);
    return;
  }
  if (!curNode.GetAllowedNamesVector(false, true).IsEmpty())
  {
    EnumerateDirItems(curNode, directory, prefix, true, dirItems, 
        false);
  }
  else
  {
    const UStringVector &directNames = curNode.GetAllowedNamesVector(false, false);
    for (int i = 0; i < directNames.Size(); i++)
    {
      const UString &nameSpec = directNames[i];
      if (curNode.CheckName(nameSpec, false, false))
        continue;

      NFind::CFileInfoW fileInfo;
      if (!NFind::FindFile(directory + nameSpec, fileInfo))
        continue;
    
      AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems);
    }
  }
  for (int i = 0; i < curNode.SubNodes.Size(); i++)
  {
    const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
    EnumerateItems(nextNode, 
        directory + nextNode.Name + wchar_t(kDirDelimiter), 
        prefix + nextNode.Name + wchar_t(kDirDelimiter),
        dirItems);
  }
}

HRESULT GetFileTime(IInArchive *archive, UINT32 index, 
    FILETIME &fileTime, const FILETIME &defaultFileTime)
{
  CPropVariant property;
  RINOK(archive->GetProperty(index, kpidLastWriteTime, &property));
  if (property.vt == VT_FILETIME)
    fileTime = property.filetime;
  else if (property.vt == VT_EMPTY)
    fileTime = defaultFileTime;
  else
    throw 4190407;
  return S_OK;
}

HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
    IInArchive *archive,
    const UString &defaultItemName,
    const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
    CObjectVector<CArchiveItem> &archiveItems)
{
  archiveItems.Clear();
  UINT32 numItems;
  RINOK(archive->GetNumberOfItems(&numItems));
  archiveItems.Reserve(numItems);
  for(UINT32 i = 0; i < numItems; i++)
  {
    CArchiveItem archiveItem;
    NCOM::CPropVariant propVariantPath;
    RINOK(archive->GetProperty(i, kpidPath, &propVariantPath));
    UString filePath;
    if(propVariantPath.vt == VT_EMPTY)
      archiveItem.Name = defaultItemName;
    else
    {
      if(propVariantPath.vt != VT_BSTR)
        return E_FAIL;
      archiveItem.Name = propVariantPath.bstrVal;
    }
    archiveItem.Censored = censor.CheckName(archiveItem.Name);

    RINOK(GetFileTime(archive, i, archiveItem.LastWriteTime, 
        archiveFileInfo.LastWriteTime));

    CPropVariant propertySize;
    RINOK(archive->GetProperty(i, kpidSize, &propertySize));
    if (archiveItem.SizeIsDefined = (propertySize.vt != VT_EMPTY))
      archiveItem.Size = ConvertPropVariantToUINT64(propertySize);

    CPropVariant propertyIsFolder;
    RINOK(archive->GetProperty(i, kpidIsFolder, &propertyIsFolder));
    if(propertyIsFolder.vt != VT_BOOL)
      return E_FAIL;
    archiveItem.IsDirectory = VARIANT_BOOLToBool(propertyIsFolder.boolVal);

    archiveItem.IndexInServer = i;
    archiveItems.Add(archiveItem);
  }
  return S_OK;
}


static HRESULT UpdateWithItemLists(
    const CUpdateArchiveOptions &options,
    IInArchive *archive, 
    const CObjectVector<CArchiveItem> &archiveItems,
    const CObjectVector<CDirItem> &dirItems,
    bool enablePercents)
{
  for(int i = 0; i < options.Commands.Size(); i++)
  {
    const CUpdateArchiveCommand &command = options.Commands[i];
    const UString &realArchivePath = command.ArchivePath;
    if (i == 0 && options.UpdateArchiveItself)
    {
      if(archive != 0)
        g_StdOut << kUpdatingArchiveMessage;
      else
        g_StdOut << kCreatingArchiveMessage; 
      g_StdOut << options.ArchivePath;
    }
    else
      g_StdOut << kCreatingArchiveMessage << realArchivePath;

    g_StdOut << endl << endl;

    RINOK(Compress(command.ActionSet, archive,
        options.MethodMode, realArchivePath, 
        archiveItems, dirItems, enablePercents,
        options.SfxMode, options.SfxModule));

    g_StdOut << endl;
  }
  return S_OK;
}

HRESULT UpdateArchiveStdMain(const NWildcard::CCensor &censor, 
    CUpdateArchiveOptions  &options, const UString &workingDir, 
    IInArchive *archive,
    const UString *defaultItemName,
    const NWindows::NFile::NFind::CFileInfoW *archiveFileInfo,
    bool enablePercents)
{
  CObjectVector<CDirItem> dirItems;
  g_StdOut << kScanningMessage;
  EnumerateItems(censor._head, L"", L"", dirItems);
  g_StdOut << endl;

  CFileVectorBundle fileVectorBundle;
  if(options.UpdateArchiveItself)
  {
    if (!NDirectory::MyGetTempFileName(workingDir, kTempArchiveFilePrefixString, 
        options.Commands[0].ArchivePath))
      throw "create temp file error";
  }

  int i;
  for(i = 0; i < options.Commands.Size(); i++)
  {
    fileVectorBundle.Add(options.Commands[i].ArchivePath, 
        i > 0 || !options.UpdateArchiveItself);
    // SetBanOnFile(censor,currentDir, options.Commands[i].ArchivePath);
  }
  g_StdOut << endl;

  CObjectVector<CArchiveItem> archiveItems;
  if (archive != NULL)
  {
    RINOK(EnumerateInArchiveItems(censor, 
        archive, *defaultItemName, *archiveFileInfo, archiveItems));
  }

  RINOK(UpdateWithItemLists(options, archive, archiveItems, dirItems, enablePercents));

  if (archive != NULL)
  {
    RINOK(archive->Close());
  }

  int firstNotTempArchiveIndex = options.UpdateArchiveItself ? 1 : 0;
  for(i = options.Commands.Size() - 1; i >= firstNotTempArchiveIndex; i--)
    fileVectorBundle.DisableDeleting(i);
  if(options.UpdateArchiveItself)
  {
    try
    {
      if (archive != NULL)
        if (!NDirectory::DeleteFileAlways(options.ArchivePath))
          throw "delete file error";
        
        if (!NDirectory::MyMoveFile(options.Commands[0].ArchivePath, options.ArchivePath))
        {
          g_StdOut << endl << "Error: ";
          g_StdOut << NError::MyFormatMessage(::GetLastError()) << endl;
          g_StdOut << options.Commands[0].ArchivePath << endl;
          g_StdOut << options.ArchivePath << endl;
          throw "move file error";
        }
    }
    catch(...)
    {
      fileVectorBundle.DisableDeleting(0);
      throw;
    }
  }
  g_StdOut << kEverythingIsOk << endl;
  return S_OK;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -