msix-packaging/MsixCore/msixmgr/Extractor.cpp

200 строки
6.6 KiB
C++

#include <windows.h>
#include <iostream>
#include <experimental/filesystem> // C++-standard header file name
#include <filesystem> // Microsoft-specific implementation header file name
#include "Extractor.hpp"
#include "GeneralUtil.hpp"
#include "FootprintFiles.hpp"
#include "FilePaths.hpp"
#include "Constants.hpp"
#include "RegistryDevirtualizer.hpp"
#include <TraceLoggingProvider.h>
#include "MsixTraceLoggingProvider.hpp"
using namespace MsixCoreLib;
const PCWSTR Extractor::HandlerName = L"Extractor";
HRESULT Extractor::GetOutputStream(LPCWSTR path, LPCWSTR fileName, IStream** stream)
{
std::wstring fullFileName = path + std::wstring(L"\\") + fileName;
std::wstring longFileName = std::wstring(L"\\\\?\\") + fullFileName;
RETURN_IF_FAILED(HRESULT_FROM_WIN32(mkdirp(longFileName)));
RETURN_IF_FAILED(CreateStreamOnFileUTF16(longFileName.c_str(), false, stream));
return S_OK;
}
HRESULT Extractor::ExtractFile(IAppxFile* file)
{
Text<WCHAR> fileName;
RETURN_IF_FAILED(file->GetName(&fileName));
UINT64 fileSize = 0;
RETURN_IF_FAILED(file->GetSize(&fileSize));
ULARGE_INTEGER fileSizeLargeInteger = { 0 };
fileSizeLargeInteger.QuadPart = fileSize;
TraceLoggingWrite(g_MsixTraceLoggingProvider,
"ExtractFile",
TraceLoggingValue(fileName.Get(), "FileName"),
TraceLoggingValue(fileSize, "FileSize"));
ComPtr<IStream> fileStream;
RETURN_IF_FAILED(file->GetStream(&fileStream));
ComPtr<IStream> outputStream;
auto packageDirectoryPath = m_msixRequest->GetPackageDirectoryPath();
RETURN_IF_FAILED(GetOutputStream(packageDirectoryPath.c_str(), fileName.Get(), &outputStream));
RETURN_IF_FAILED(fileStream->CopyTo(outputStream.Get(), fileSizeLargeInteger, nullptr, nullptr));
return S_OK;
}
HRESULT Extractor::ExtractFootprintFiles()
{
TraceLoggingWrite(g_MsixTraceLoggingProvider,
"Extracting footprint files from the package");
auto packageToInstall = std::dynamic_pointer_cast<Package>(m_msixRequest->GetPackageInfo());
for (int i = 0; i < FootprintFilesCount; i++)
{
if (m_msixRequest->GetMsixResponse()->GetIsInstallCancelled())
{
m_msixRequest->GetMsixResponse()->SetErrorStatus(HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT), L"User cancelled installation.");
return HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
}
if (packageToInstall != nullptr)
{
ComPtr<IAppxFile> footprintFile;
HRESULT hr = packageToInstall->GetPackageReader()->GetFootprintFile(g_footprintFilesType[i].fileType, &footprintFile);
if (SUCCEEDED(hr) && footprintFile.Get())
{
RETURN_IF_FAILED(ExtractFile(footprintFile.Get()));
}
else if (g_footprintFilesType[i].isRequired)
{
TraceLoggingWrite(g_MsixTraceLoggingProvider,
"Missing required Footprintfile",
TraceLoggingValue(g_footprintFilesType[i].description, "File Description"));
return hr;
}
}
}
return S_OK;
}
HRESULT Extractor::ExtractPayloadFiles()
{
ComPtr<IAppxFilesEnumerator> files;
TraceLoggingWrite(g_MsixTraceLoggingProvider,
"Extracting payload files from the package");
auto packageToInstall = std::dynamic_pointer_cast<Package>(m_msixRequest->GetPackageInfo());
if (packageToInstall == nullptr)
{
return E_FAIL;
}
RETURN_IF_FAILED(packageToInstall->GetPackageReader()->GetPayloadFiles(&files));
BOOL hasCurrent = FALSE;
RETURN_IF_FAILED(files->GetHasCurrent(&hasCurrent));
unsigned int totalNumberFiles = m_msixRequest->GetPackageInfo()->GetNumberOfPayloadFiles();
unsigned int nbrFilesExtracted = 0;
while (hasCurrent)
{
if (m_msixRequest->GetMsixResponse()->GetIsInstallCancelled())
{
m_msixRequest->GetMsixResponse()->SetErrorStatus(HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT), L"User cancelled installation.");
return HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
}
ComPtr<IAppxFile> file;
RETURN_IF_FAILED(files->GetCurrent(&file));
RETURN_IF_FAILED(ExtractFile(file.Get()));
RETURN_IF_FAILED(files->MoveNext(&hasCurrent));
++nbrFilesExtracted;
float progress = 100.0f * nbrFilesExtracted / totalNumberFiles;
m_msixRequest->GetMsixResponse()->Update(InstallationStep::InstallationStepExtraction, progress);
}
return S_OK;
}
HRESULT Extractor::CreatePackageRoot()
{
std::wstring packagePath = FilePathMappings::GetInstance().GetMsixCoreDirectory();
if (!CreateDirectory(packagePath.c_str(), nullptr))
{
DWORD lastError = GetLastError();
if (lastError != ERROR_ALREADY_EXISTS)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(lastError));
}
}
if (!CreateDirectory((FilePathMappings::GetInstance().GetMsixCoreDirectory() + m_msixRequest->GetPackageInfo()->GetPackageFullName()).c_str(), nullptr))
{
DWORD lastError = GetLastError();
if (lastError != ERROR_ALREADY_EXISTS)
{
RETURN_IF_FAILED(HRESULT_FROM_WIN32(lastError));
}
}
return S_OK;
}
HRESULT Extractor::ExecuteForAddRequest()
{
RETURN_IF_FAILED(CreatePackageRoot());
RETURN_IF_FAILED(ExtractPackage());
return S_OK;
}
HRESULT Extractor::ExecuteForRemoveRequest()
{
// First release manifest so we can delete the file.
m_msixRequest->GetPackageInfo()->ReleaseManifest();
std::error_code error;
auto packageDirectoryPath = m_msixRequest->GetPackageDirectoryPath();
uintmax_t numRemoved = std::experimental::filesystem::remove_all(packageDirectoryPath, error);
TraceLoggingWrite(g_MsixTraceLoggingProvider,
"Removed directory",
TraceLoggingValue(packageDirectoryPath.c_str(), "PackageDirectoryPath"),
TraceLoggingValue(error.value(), "Error"),
TraceLoggingValue(numRemoved, "NumRemoved"));
return S_OK;
}
HRESULT Extractor::CreateHandler(MsixRequest * msixRequest, IPackageHandler ** instance)
{
std::unique_ptr<Extractor> localInstance(new Extractor(msixRequest));
if (localInstance == nullptr)
{
return E_OUTOFMEMORY;
}
*instance = localInstance.release();
return S_OK;
}
HRESULT Extractor::ExtractPackage()
{
RETURN_IF_FAILED(ExtractFootprintFiles());
RETURN_IF_FAILED(ExtractPayloadFiles());
return S_OK;
}