1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
/* ######################################################################
Store method - Takes a file URI and stores its content (for which it will
calculate the hashes) in the given destination. The input file will be
extracted based on its file extension (or with the given compressor if
called with one of the compatible symlinks) and potentially recompressed
based on the file extension of the destination filename.
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#include <config.h>
#include "aptmethod.h"
#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/hashes.h>
#include <apt-pkg/strutl.h>
#include <array>
#include <cstring>
#include <string>
#include <vector>
#include <sys/stat.h>
#include <sys/time.h>
#include <apti18n.h>
/*}}}*/
class StoreMethod final : public aptMethod
{
bool Fetch(FetchItem *Itm) override;
public:
explicit StoreMethod(std::string pProg) : aptMethod(std::move(pProg),"1.2",SingleInstance | SendConfig | SendURIEncoded)
{
SeccompFlags = aptMethod::BASE;
if (Binary != "store")
methodNames.insert(methodNames.begin(), "store");
}
};
static bool OpenFileWithCompressorByName(FileFd &fileFd, std::string const &Filename, unsigned int const Mode, std::string const &Name)
{
if (Name == "store")
return fileFd.Open(Filename, Mode, FileFd::Extension);
std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
for (; compressor != compressors.end(); ++compressor)
if (compressor->Name == Name)
break;
if (compressor == compressors.end())
return _error->Error("Extraction of file %s requires unknown compressor %s", Filename.c_str(), Name.c_str());
return fileFd.Open(Filename, Mode, *compressor);
}
/*}}}*/
bool StoreMethod::Fetch(FetchItem *Itm) /*{{{*/
{
URI Get(Itm->Uri);
std::string Path = DecodeSendURI(Get.Host + Get.Path); // To account for relative paths
FetchResult Res;
Res.Filename = Itm->DestFile;
URIStart(Res);
// Open the source and destination files
FileFd From;
if (_config->FindB("Method::Compress", false) == false)
{
if (OpenFileWithCompressorByName(From, Path, FileFd::ReadOnly, Binary) == false)
return false;
if(From.IsCompressed() && From.FileSize() == 0)
return _error->Error(_("Empty files can't be valid archives"));
}
else
From.Open(Path, FileFd::ReadOnly, FileFd::Extension);
if (From.IsOpen() == false || From.Failed() == true)
return false;
FileFd To;
if (Itm->DestFile != "/dev/null" && Itm->DestFile != Path)
{
if (_config->FindB("Method::Compress", false) == false)
To.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Atomic, FileFd::Extension);
else if (OpenFileWithCompressorByName(To, Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty, Binary) == false)
return false;
if (To.IsOpen() == false || To.Failed() == true)
return false;
To.EraseOnFailure();
}
// Read data from source, generate checksums and write
Hashes Hash(Itm->ExpectedHashes);
bool Failed = false;
Res.Size = 0;
while (1)
{
std::array<unsigned char, APT_BUFFER_SIZE> Buffer;
unsigned long long Count = 0;
if (!From.Read(Buffer.data(),Buffer.size(),&Count))
{
if (To.IsOpen())
To.OpFail();
return false;
}
if (Count == 0)
break;
Res.Size += Count;
Hash.Add(Buffer.data(),Count);
if (To.IsOpen() && To.Write(Buffer.data(),Count) == false)
{
Failed = true;
break;
}
}
From.Close();
To.Close();
if (Failed == true)
return false;
if (TransferModificationTimes(Path.c_str(), Itm->DestFile.c_str(), Res.LastModified) == false)
return false;
// Return a Done response
Res.TakeHashes(Hash);
URIDone(Res);
return true;
}
/*}}}*/
int main(int, char *argv[])
{
return StoreMethod(std::string{flNotDir(argv[0])}).Run();
}
|