diff options
author | Michael Vogt <mvo@debian.org> | 2005-10-17 14:56:57 +0000 |
---|---|---|
committer | Michael Vogt <mvo@debian.org> | 2005-10-17 14:56:57 +0000 |
commit | 5e9d46df79517125d0fd72e7671f5e0995746677 (patch) | |
tree | 8736bb81b19535094fd77fb90b8218af5e55f004 /methods | |
parent | c511502fcec38680fff2f27aec75908e348e5905 (diff) | |
parent | cec6091772ae3463cb04c417e3f598f9b6814516 (diff) | |
download | apt-5e9d46df79517125d0fd72e7671f5e0995746677.tar.gz |
* merged pdiff support
Patches applied:
* michael.vogt@canonical.com--2004/apt--bwlimit--0--base-0
tag of apt@packages.debian.org/apt--main--0--patch-47
* michael.vogt@canonical.com--2004/apt--bwlimit--0--patch-1
* fist attempt for bwlimit
* michael.vogt@canonical.com--2004/apt--bwlimit--0--patch-2
* add a nanosleep, making it less cpu intensive
* michael.vogt@canonical.com--2004/apt--bwlimit--0--patch-3
* use SingleInstance when DlLimit is activated
* michael.vogt@canonical.com--2004/apt--bwlimit--0--patch-4
* cleanups, no code changes
* michael.vogt@ubuntu.com--2005/apt--bwlimit--0--base-0
tag of apt@packages.debian.org/apt--main--0--patch-76
* michael.vogt@ubuntu.com--2005/apt--bwlimit--0--patch-1
* merged the apt--main with the 2004 bwlimit tree
* michael.vogt@ubuntu.com--2005/apt--local-install--0--base-0
tag of michael.vogt@ubuntu.com--2005/apt--bwlimit--0--patch-1
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--base-0
tag of michael.vogt@ubuntu.com--2005/apt--local-install--0--base-0
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-1
* first rewrite of the apt pdiff support patch finished
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-2
* use "red" now, print meaningfull pdiff names, use IMS for the IndexDiff
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-3
* merge with matt, search for the right patch next instead of applying them in order
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-4
* fix a bug QueueNextDiff
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-5
* another bug in QueueNextDiff fixed
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-6
* merged with apt--main and apt--fixes
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-7
* added methods/rred.cc (thanks to robertle)
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-8
* use the new cool rred method for the patchting
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-9
* merged with mainline
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-10
* rred.cc: use the d'tor of FileFd to close the file-fd; acquuire-item.cc: make the QueueNextDiff() code more robust
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-11
* bugfix/updates in the rred.cc code (big thanks for helping Robert!)
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-12
* method/rred.cc cleanup (thanks to robertle)
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-13
* debug support (Debug::pkgAcquire::RRed) for rred method added
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-14
* split the diff acquire code in a bit that gets the index file and one that gets the patches. that make the code cleaner and the list-cleaner happy
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-15
* fixed apt-pkg/acquire-item.h (looks like the last commit didn't include it?)
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-16
* fix a missing StatDone if nothing needs to be fetched
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-17
* be less verbose and call the Url-Remap: APT::URL-Remap
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-18
* dont bump the soname, it doesn't break the abi!
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-19
* merged with michael.vogt@ubuntu.com--2005/apt--mvo--0 to be in sync with debian
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-20
* don't forget the final md5sum checking!
* michael.vogt@ubuntu.com--2005/apt--pdiff--0--patch-21
* removed the URL-Reamp hack (we have pdiff support in the main archive now), removed bw-limit support (NO idea how that got into this archive in the first place)
Diffstat (limited to 'methods')
-rw-r--r-- | methods/http.cc | 3 | ||||
-rw-r--r-- | methods/makefile | 9 | ||||
-rw-r--r-- | methods/rred.cc | 262 |
3 files changed, 272 insertions, 2 deletions
diff --git a/methods/http.cc b/methods/http.cc index ba86aa6b..e2337a9b 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -58,6 +58,7 @@ unsigned long PipelineDepth = 10; unsigned long TimeOut = 120; bool Debug = false; + // CircleBuf::CircleBuf - Circular input buffer /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -95,7 +96,7 @@ bool CircleBuf::Read(int Fd) // Woops, buffer is full if (InP - OutP == Size) return true; - + // Write the buffer segment int Res; Res = read(Fd,Buf + (InP%Size),LeftRead()); diff --git a/methods/makefile b/methods/makefile index 06fd2a6f..d0b5a28c 100644 --- a/methods/makefile +++ b/methods/makefile @@ -7,7 +7,7 @@ include ../buildlib/defaults.mak BIN := $(BIN)/methods # FIXME.. -LIB_APT_PKG_MAJOR = 3.10 +LIB_APT_PKG_MAJOR = 3.11 APT_DOMAIN := libapt-pkg$(LIB_APT_PKG_MAJOR) # The file method @@ -59,6 +59,13 @@ LIB_MAKES = apt-pkg/makefile SOURCE = ftp.cc rfc2553emu.cc connect.cc include $(PROGRAM_H) +# The rred method +PROGRAM=rred +SLIBS = -lapt-pkg $(SOCKETLIBS) +LIB_MAKES = apt-pkg/makefile +SOURCE = rred.cc +include $(PROGRAM_H) + # The rsh method PROGRAM=rsh SLIBS = -lapt-pkg diff --git a/methods/rred.cc b/methods/rred.cc new file mode 100644 index 00000000..6fa57f3a --- /dev/null +++ b/methods/rred.cc @@ -0,0 +1,262 @@ +#include <apt-pkg/fileutl.h> +#include <apt-pkg/error.h> +#include <apt-pkg/acquire-method.h> +#include <apt-pkg/strutl.h> +#include <apt-pkg/hashes.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <utime.h> +#include <stdio.h> +#include <errno.h> +#include <apti18n.h> + +/* this method implements a patch functionality similar to "patch --ed" that is + * used by the "tiffany" incremental packages download stuff. it differs from + * "ed" insofar that it is way more restricted (and therefore secure). in the + * moment only the "c", "a" and "d" commands of ed are implemented (diff + * doesn't output any other). additionally the records must be reverse sorted + * by line number and may not overlap (diff *seems* to produce this kind of + * output). + * */ + +const char *Prog; + +class RredMethod : public pkgAcqMethod +{ + bool Debug; + // the size of this doesn't really matter (except for performance) + const static int BUF_SIZE = 1024; + // the ed commands + enum Mode {MODE_CHANGED, MODE_DELETED, MODE_ADDED}; + // return values + enum State {ED_OK, ED_ORDERING, ED_PARSER, ED_FAILURE}; + // this applies a single hunk, it uses a tail recursion to + // reverse the hunks in the file + int ed_rec(FILE *ed_cmds, FILE *in_file, FILE *out_file, int line, + char *buffer, unsigned int bufsize, Hashes *hash); + // apply a patch file + int ed_file(FILE *ed_cmds, FILE *in_file, FILE *out_file, Hashes *hash); + // the methods main method + virtual bool Fetch(FetchItem *Itm); + + public: + + RredMethod() : pkgAcqMethod("1.1",SingleInstance | SendConfig) {}; +}; + +int RredMethod::ed_rec(FILE *ed_cmds, FILE *in_file, FILE *out_file, int line, + char *buffer, unsigned int bufsize, Hashes *hash) { + int pos; + int startline; + int stopline; + int mode; + int written; + char *idx; + + /* get the current command and parse it*/ + if (fgets(buffer, bufsize, ed_cmds) == NULL) { + return line; + } + startline = strtol(buffer, &idx, 10); + if (startline < line) { + return ED_ORDERING; + } + if (*idx == ',') { + idx++; + stopline = strtol(idx, &idx, 10); + } + else { + stopline = startline; + } + if (*idx == 'c') { + mode = MODE_CHANGED; + if (Debug == true) { + std::clog << "changing from line " << startline + << " to " << stopline << std::endl; + } + } + else if (*idx == 'a') { + mode = MODE_ADDED; + if (Debug == true) { + std::clog << "adding after line " << startline << std::endl; + } + } + else if (*idx == 'd') { + mode = MODE_DELETED; + if (Debug == true) { + std::clog << "deleting from line " << startline + << " to " << stopline << std::endl; + } + } + else { + return ED_PARSER; + } + /* get the current position */ + pos = ftell(ed_cmds); + /* if this is add or change then go to the next full stop */ + if ((mode == MODE_CHANGED) || (mode == MODE_ADDED)) { + do { + fgets(buffer, bufsize, ed_cmds); + while ((strlen(buffer) == (bufsize - 1)) + && (buffer[bufsize - 2] != '\n')) { + fgets(buffer, bufsize, ed_cmds); + buffer[0] = ' '; + } + } while (strncmp(buffer, ".", 1) != 0); + } + /* do the recursive call */ + line = ed_rec(ed_cmds, in_file, out_file, line, buffer, bufsize, + hash); + /* pass on errors */ + if (line < 0) { + return line; + } + /* apply our hunk */ + fseek(ed_cmds, pos, SEEK_SET); + /* first wind to the current position */ + if (mode != MODE_ADDED) { + startline -= 1; + } + while (line < startline) { + fgets(buffer, bufsize, in_file); + written = fwrite(buffer, 1, strlen(buffer), out_file); + hash->Add((unsigned char*)buffer, written); + while ((strlen(buffer) == (bufsize - 1)) + && (buffer[bufsize - 2] != '\n')) { + fgets(buffer, bufsize, in_file); + written = fwrite(buffer, 1, strlen(buffer), out_file); + hash->Add((unsigned char*)buffer, written); + } + line++; + } + /* include from ed script */ + if ((mode == MODE_ADDED) || (mode == MODE_CHANGED)) { + do { + fgets(buffer, bufsize, ed_cmds); + if (strncmp(buffer, ".", 1) != 0) { + written = fwrite(buffer, 1, strlen(buffer), out_file); + hash->Add((unsigned char*)buffer, written); + while ((strlen(buffer) == (bufsize - 1)) + && (buffer[bufsize - 2] != '\n')) { + fgets(buffer, bufsize, ed_cmds); + written = fwrite(buffer, 1, strlen(buffer), out_file); + hash->Add((unsigned char*)buffer, written); + } + } + else { + break; + } + } while (1); + } + /* ignore the corresponding number of lines from input */ + if ((mode == MODE_DELETED) || (mode == MODE_CHANGED)) { + while (line < stopline) { + fgets(buffer, bufsize, in_file); + while ((strlen(buffer) == (bufsize - 1)) + && (buffer[bufsize - 2] != '\n')) { + fgets(buffer, bufsize, in_file); + } + line++; + } + } + return line; +} + +int RredMethod::ed_file(FILE *ed_cmds, FILE *in_file, FILE *out_file, + Hashes *hash) { + char buffer[BUF_SIZE]; + int result; + int written; + + /* we do a tail recursion to read the commands in the right order */ + result = ed_rec(ed_cmds, in_file, out_file, 0, buffer, BUF_SIZE, + hash); + + /* read the rest from infile */ + if (result > 0) { + while (fgets(buffer, BUF_SIZE, in_file) != NULL) { + written = fwrite(buffer, 1, strlen(buffer), out_file); + hash->Add((unsigned char*)buffer, written); + } + } + else { + return ED_FAILURE; + } + return ED_OK; +} + + +bool RredMethod::Fetch(FetchItem *Itm) +{ + Debug = _config->FindB("Debug::pkgAcquire::RRed",false); + URI Get = Itm->Uri; + string Path = Get.Host + Get.Path; // To account for relative paths + // Path contains the filename to patch + FetchResult Res; + Res.Filename = Itm->DestFile; + URIStart(Res); + // Res.Filename the destination filename + + if (Debug == true) + std::clog << "Patching " << Path << " with " << Path + << ".ed and putting result into " << Itm->DestFile << std::endl; + // Open the source and destination files (the d'tor of FileFd will do + // the cleanup/closing of the fds) + FileFd From(Path,FileFd::ReadOnly); + FileFd Patch(Path+".ed",FileFd::ReadOnly); + FileFd To(Itm->DestFile,FileFd::WriteEmpty); + To.EraseOnFailure(); + if (_error->PendingError() == true) + return false; + + Hashes Hash; + FILE* fFrom = fdopen(From.Fd(), "r"); + FILE* fPatch = fdopen(Patch.Fd(), "r"); + FILE* fTo = fdopen(To.Fd(), "w"); + // now do the actual patching + if (ed_file(fPatch, fFrom, fTo, &Hash) != ED_OK) { + _error->Errno("rred", _("Could not patch file")); + return false; + } + + // write out the result + fflush(fFrom); + fflush(fPatch); + fflush(fTo); + From.Close(); + Patch.Close(); + To.Close(); + + // Transfer the modification times + struct stat Buf; + if (stat(Path.c_str(),&Buf) != 0) + return _error->Errno("stat",_("Failed to stat")); + + struct utimbuf TimeBuf; + TimeBuf.actime = Buf.st_atime; + TimeBuf.modtime = Buf.st_mtime; + if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0) + return _error->Errno("utime",_("Failed to set modification time")); + + if (stat(Itm->DestFile.c_str(),&Buf) != 0) + return _error->Errno("stat",_("Failed to stat")); + + // return done + Res.LastModified = Buf.st_mtime; + Res.Size = Buf.st_size; + Res.TakeHashes(Hash); + URIDone(Res); + + return true; +} + +int main(int argc, char *argv[]) +{ + RredMethod Mth; + + Prog = strrchr(argv[0],'/'); + Prog++; + + return Mth.Run(); +} |