X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/d7a51997c30b2098bb60b3397095ec58ec825303..14e57111df6f8894ed47841b7471837c9d87c264:/methods/rred.cc diff --git a/methods/rred.cc b/methods/rred.cc index 7c2ccd98e..0c641ad82 100644 --- a/methods/rred.cc +++ b/methods/rred.cc @@ -7,12 +7,13 @@ #include +#include #include #include -#include #include #include #include +#include "aptmethod.h" #include #include @@ -38,7 +39,7 @@ class MemBlock { char *free; MemBlock *next; - MemBlock(size_t size) : size(size), next(NULL) + explicit MemBlock(size_t size) : size(size), next(NULL) { free = start = new char[size]; } @@ -117,7 +118,7 @@ struct Change { size_t add_len; /* bytes */ char *add; - Change(size_t off) + explicit Change(size_t off) { offset = off; del_cnt = add_cnt = add_len = 0; @@ -334,26 +335,30 @@ class Patch { FileChanges filechanges; MemBlock add_text; - static bool retry_fwrite(char *b, size_t l, FileFd &f, Hashes *hash) + static bool retry_fwrite(char *b, size_t l, FileFd &f, Hashes * const start_hash, Hashes * const end_hash = nullptr) { if (f.Write(b, l) == false) return false; - if (hash) - hash->Add((unsigned char*)b, l); + if (start_hash) + start_hash->Add((unsigned char*)b, l); + if (end_hash) + end_hash->Add((unsigned char*)b, l); return true; } - static void dump_rest(FileFd &o, FileFd &i, Hashes *hash) + static void dump_rest(FileFd &o, FileFd &i, + Hashes * const start_hash, Hashes * const end_hash) { char buffer[BLOCK_SIZE]; unsigned long long l = 0; while (i.Read(buffer, sizeof(buffer), &l)) { - if (l ==0 || !retry_fwrite(buffer, l, o, hash)) + if (l ==0 || !retry_fwrite(buffer, l, o, start_hash, end_hash)) break; } } - static void dump_lines(FileFd &o, FileFd &i, size_t n, Hashes *hash) + static void dump_lines(FileFd &o, FileFd &i, size_t n, + Hashes * const start_hash, Hashes * const end_hash) { char buffer[BLOCK_SIZE]; while (n > 0) { @@ -362,11 +367,11 @@ class Patch { size_t const l = strlen(buffer); if (l == 0 || buffer[l-1] == '\n') n--; - retry_fwrite(buffer, l, o, hash); + retry_fwrite(buffer, l, o, start_hash, end_hash); } } - static void skip_lines(FileFd &i, int n) + static void skip_lines(FileFd &i, int n, Hashes * const start_hash) { char buffer[BLOCK_SIZE]; while (n > 0) { @@ -375,6 +380,8 @@ class Patch { size_t const l = strlen(buffer); if (l == 0 || buffer[l-1] == '\n') n--; + if (start_hash) + start_hash->Add((unsigned char*)buffer, l); } } @@ -489,7 +496,11 @@ class Patch { for (ch = filechanges.rbegin(); ch != filechanges.rend(); ++ch) { std::list::reverse_iterator mg_i, mg_e = ch; while (ch->del_cnt == 0 && ch->offset == 0) + { ++ch; + if (unlikely(ch == filechanges.rend())) + return; + } line -= ch->del_cnt; std::string buf; if (ch->add_cnt > 0) { @@ -520,19 +531,21 @@ class Patch { } } - void apply_against_file(FileFd &out, FileFd &in, Hashes *hash = NULL) + void apply_against_file(FileFd &out, FileFd &in, + Hashes * const start_hash = nullptr, Hashes * const end_hash = nullptr) { std::list::iterator ch; for (ch = filechanges.begin(); ch != filechanges.end(); ++ch) { - dump_lines(out, in, ch->offset, hash); - skip_lines(in, ch->del_cnt); - dump_mem(out, ch->add, ch->add_len, hash); + dump_lines(out, in, ch->offset, start_hash, end_hash); + skip_lines(in, ch->del_cnt, start_hash); + dump_mem(out, ch->add, ch->add_len, end_hash); } - dump_rest(out, in, hash); + dump_rest(out, in, start_hash, end_hash); + out.Flush(); } }; -class RredMethod : public pkgAcqMethod { +class RredMethod : public aptMethod { private: bool Debug; @@ -559,7 +572,7 @@ class RredMethod : public pkgAcqMethod { protected: virtual bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE { - Debug = _config->FindB("Debug::pkgAcquire::RRed", false); + Debug = DebugEnabled(); URI Get = Itm->Uri; std::string Path = Get.Host + Get.Path; // rred:/path - no host @@ -575,6 +588,16 @@ class RredMethod : public pkgAcqMethod { std::vector patchfiles; Patch patch; + HashStringList StartHashes; + for (char const * const * type = HashString::SupportedHashes(); *type != nullptr; ++type) + { + std::string tagname; + strprintf(tagname, "Start-%s-Hash", *type); + std::string const hashsum = LookupTag(Message, tagname.c_str()); + if (hashsum.empty() == false) + StartHashes.push_back(HashString(*type, hashsum)); + } + if (FileExists(Path + ".ed") == true) { HashStringList const ExpectedHashes = ReadExpectedHashesForPatch(0, Message); @@ -621,7 +644,7 @@ class RredMethod : public pkgAcqMethod { if (p.Open(patch_name, FileFd::ReadOnly, FileFd::Gzip) == false || patch.read_diff(p, &patch_hash) == false) { - _error->DumpErrors(std::cerr); + _error->DumpErrors(std::cerr, GlobalError::DEBUG, false); return false; } p.Close(); @@ -641,18 +664,31 @@ class RredMethod : public pkgAcqMethod { std::cerr << "FAILED to open inp " << Path << std::endl; return _error->Error("Failed to open inp %s", Path.c_str()); } - if (out.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create, FileFd::Extension) == false) + if (out.Open(Itm->DestFile, FileFd::WriteOnly | FileFd::Create | FileFd::Empty | FileFd::BufferedWrite, FileFd::Extension) == false) { std::cerr << "FAILED to open out " << Itm->DestFile << std::endl; return _error->Error("Failed to open out %s", Itm->DestFile.c_str()); } - Hashes hash(Itm->ExpectedHashes); - patch.apply_against_file(out, inp, &hash); + Hashes end_hash(Itm->ExpectedHashes); + if (StartHashes.usable()) + { + Hashes start_hash(StartHashes); + patch.apply_against_file(out, inp, &start_hash, &end_hash); + if (start_hash.GetHashStringList() != StartHashes) + _error->Error("The input file hadn't the expected hash!"); + } + else + patch.apply_against_file(out, inp, nullptr, &end_hash); out.Close(); inp.Close(); + if (_error->PendingError() == true) { + std::cerr << "FAILED to read or write files" << std::endl; + return false; + } + if (Debug == true) { std::clog << "rred: finished file patching of " << Path << "." << std::endl; } @@ -660,7 +696,7 @@ class RredMethod : public pkgAcqMethod { struct stat bufbase, bufpatch; if (stat(Path.c_str(), &bufbase) != 0 || stat(patch_name.c_str(), &bufpatch) != 0) - return _error->Errno("stat", _("Failed to stat")); + return _error->Errno("stat", _("Failed to stat %s"), Path.c_str()); struct timeval times[2]; times[0].tv_sec = bufbase.st_atime; @@ -670,42 +706,39 @@ class RredMethod : public pkgAcqMethod { return _error->Errno("utimes",_("Failed to set modification time")); if (stat(Itm->DestFile.c_str(), &bufbase) != 0) - return _error->Errno("stat", _("Failed to stat")); + return _error->Errno("stat", _("Failed to stat %s"), Itm->DestFile.c_str()); Res.LastModified = bufbase.st_mtime; Res.Size = bufbase.st_size; - Res.TakeHashes(hash); + Res.TakeHashes(end_hash); URIDone(Res); return true; } - bool Configuration(std::string Message) APT_OVERRIDE - { - if (pkgAcqMethod::Configuration(Message) == false) - return false; - - DropPrivsOrDie(); - - return true; - } - public: - RredMethod() : pkgAcqMethod("2.0",SingleInstance | SendConfig), Debug(false) {} + RredMethod() : aptMethod("rred", "2.0", SendConfig), Debug(false) {} }; int main(int argc, char **argv) { int i; bool just_diff = true; + bool test = false; Patch patch; if (argc <= 1) { - RredMethod Mth; - return Mth.Run(); + return RredMethod().Run(); } - if (argc > 1 && strcmp(argv[1], "-f") == 0) { + // Usage: rred -t input output diff ... + if (argc > 1 && strcmp(argv[1], "-t") == 0) { + // Read config files so we see compressors. + pkgInitConfig(*_config); + just_diff = false; + test = true; + i = 4; + } else if (argc > 1 && strcmp(argv[1], "-f") == 0) { just_diff = false; i = 2; } else { @@ -725,15 +758,24 @@ int main(int argc, char **argv) } } - if (just_diff) { + if (test) { + FileFd out, inp; + std::cerr << "Patching " << argv[2] << " into " << argv[3] << "\n"; + inp.Open(argv[2], FileFd::ReadOnly,FileFd::Extension); + out.Open(argv[3], FileFd::WriteOnly | FileFd::Create | FileFd::Empty | FileFd::BufferedWrite, FileFd::Extension); + patch.apply_against_file(out, inp); + out.Close(); + } else if (just_diff) { FileFd out; out.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::Create); patch.write_diff(out); + out.Close(); } else { FileFd out, inp; - out.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::Create); + out.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::Create | FileFd::BufferedWrite); inp.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly); patch.apply_against_file(out, inp); + out.Close(); } return 0; }