From a3a03f5d7436c870edac9c0eb92e85e1fcaf6bca Mon Sep 17 00:00:00 2001 From: "martin@piware.de" <> Date: Wed, 9 Jun 2010 14:08:20 +0200 Subject: * apt-pkg/contrib/fileutl.{h,cc}: - Add support for transparent reading of gzipped files. - Link against zlib (in apt-pkg/makefile) and add zlib build dependency. --- apt-pkg/contrib/fileutl.cc | 47 ++++++++++++++++++++++++++++++++++++++++------ apt-pkg/contrib/fileutl.h | 9 ++++++--- 2 files changed, 47 insertions(+), 9 deletions(-) (limited to 'apt-pkg/contrib') diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index da32983f1..11a9e7f7b 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -11,6 +11,7 @@ Most of this source is placed in the Public Domain, do with it what you will It was originally written by Jason Gunthorpe . + FileFd gzip support added by Martin Pitt The exception is RunScripts() it is under the GPLv2 @@ -603,6 +604,13 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms) { case ReadOnly: iFd = open(FileName.c_str(),O_RDONLY); + if (iFd > 0 && FileName.compare(FileName.size()-3, 3, ".gz") == 0) { + gz = gzdopen (iFd, "r"); + if (gz == NULL) { + close (iFd); + iFd = -1; + } + } break; case WriteEmpty: @@ -658,7 +666,10 @@ bool FileFd::Read(void *To,unsigned long Size,unsigned long *Actual) do { - Res = read(iFd,To,Size); + if (gz != NULL) + Res = gzread(gz,To,Size); + else + Res = read(iFd,To,Size); if (Res < 0 && errno == EINTR) continue; if (Res < 0) @@ -697,7 +708,10 @@ bool FileFd::Write(const void *From,unsigned long Size) errno = 0; do { - Res = write(iFd,From,Size); + if (gz != NULL) + Res = gzwrite(gz,From,Size); + else + Res = write(iFd,From,Size); if (Res < 0 && errno == EINTR) continue; if (Res < 0) @@ -723,7 +737,12 @@ bool FileFd::Write(const void *From,unsigned long Size) /* */ bool FileFd::Seek(unsigned long To) { - if (lseek(iFd,To,SEEK_SET) != (signed)To) + int res; + if (gz) + res = gzseek(gz,To,SEEK_SET); + else + res = lseek(iFd,To,SEEK_SET); + if (res != (signed)To) { Flags |= Fail; return _error->Error("Unable to seek to %lu",To); @@ -737,7 +756,12 @@ bool FileFd::Seek(unsigned long To) /* */ bool FileFd::Skip(unsigned long Over) { - if (lseek(iFd,Over,SEEK_CUR) < 0) + int res; + if (gz) + res = gzseek(gz,Over,SEEK_CUR); + else + res = lseek(iFd,Over,SEEK_CUR); + if (res < 0) { Flags |= Fail; return _error->Error("Unable to seek ahead %lu",Over); @@ -751,6 +775,11 @@ bool FileFd::Skip(unsigned long Over) /* */ bool FileFd::Truncate(unsigned long To) { + if (gz) + { + Flags |= Fail; + return _error->Error("Truncating gzipped files is not implemented (%s)", FileName.c_str()); + } if (ftruncate(iFd,To) != 0) { Flags |= Fail; @@ -765,7 +794,11 @@ bool FileFd::Truncate(unsigned long To) /* */ unsigned long FileFd::Tell() { - off_t Res = lseek(iFd,0,SEEK_CUR); + off_t Res; + if (gz) + Res = gztell(gz); + else + Res = lseek(iFd,0,SEEK_CUR); if (Res == (off_t)-1) _error->Errno("lseek","Failed to determine the current file position"); return Res; @@ -776,6 +809,7 @@ unsigned long FileFd::Tell() /* */ unsigned long FileFd::Size() { + //TODO: For gz, do we need the actual file size here or the uncompressed length? struct stat Buf; if (fstat(iFd,&Buf) != 0) return _error->Errno("fstat","Unable to determine the file size"); @@ -789,9 +823,10 @@ bool FileFd::Close() { bool Res = true; if ((Flags & AutoClose) == AutoClose) - if (iFd >= 0 && close(iFd) != 0) + if ((gz != NULL && gzclose(gz) != 0) || (gz == NULL && iFd > 0 && close(iFd) != 0)) Res &= _error->Errno("close",_("Problem closing the file")); iFd = -1; + gz = NULL; if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail && FileName.empty() == false) diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 85a94898c..9925bbed4 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -25,6 +25,8 @@ #include #include +#include + using std::string; class FileFd @@ -36,6 +38,7 @@ class FileFd HitEof = (1<<3)}; unsigned long Flags; string FileName; + gzFile gz; public: enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,WriteTemp}; @@ -69,12 +72,12 @@ class FileFd inline string &Name() {return FileName;}; FileFd(string FileName,OpenMode Mode,unsigned long Perms = 0666) : iFd(-1), - Flags(0) + Flags(0), gz(NULL) { Open(FileName,Mode,Perms); }; - FileFd(int Fd = -1) : iFd(Fd), Flags(AutoClose) {}; - FileFd(int Fd,bool) : iFd(Fd), Flags(0) {}; + FileFd(int Fd = -1) : iFd(Fd), Flags(AutoClose), gz(NULL) {}; + FileFd(int Fd,bool) : iFd(Fd), Flags(0), gz(NULL) {}; virtual ~FileFd(); }; -- cgit v1.2.3 From c4fc2fd7fa0fc63fd8cd6bc9b73492e6baf0222a Mon Sep 17 00:00:00 2001 From: "martin@piware.de" <> Date: Thu, 24 Jun 2010 21:27:27 +0200 Subject: Switch FileFd to not transparently gunzip, since that breaks code which expects the compressed contents to stay (such as the copy backend, or when using file:// repositories. Instead, introduce a new ReadOnlyGzip mode and use that where needed --- apt-pkg/contrib/fileutl.cc | 14 +++++++++----- apt-pkg/contrib/fileutl.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'apt-pkg/contrib') diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 11a9e7f7b..2b91a46f7 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -604,12 +604,16 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms) { case ReadOnly: iFd = open(FileName.c_str(),O_RDONLY); + break; + + case ReadOnlyGzip: + iFd = open(FileName.c_str(),O_RDONLY); if (iFd > 0 && FileName.compare(FileName.size()-3, 3, ".gz") == 0) { - gz = gzdopen (iFd, "r"); - if (gz == NULL) { - close (iFd); - iFd = -1; - } + gz = gzdopen (iFd, "r"); + if (gz == NULL) { + close (iFd); + iFd = -1; + } } break; diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 9925bbed4..c4b282126 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -41,7 +41,7 @@ class FileFd gzFile gz; public: - enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,WriteTemp}; + enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,WriteTemp,ReadOnlyGzip}; inline bool Read(void *To,unsigned long Size,bool AllowEof) { -- cgit v1.2.3 From d13c2d3f7b10e558301a05948e91ac4a60160793 Mon Sep 17 00:00:00 2001 From: "martin@piware.de" <> Date: Tue, 6 Jul 2010 12:48:06 +0200 Subject: FileFd(): Drop file name extension check in ReadOnlyGzip mode Drop the ".gz" extension check in FileFd::Open() in ReadOnlyGzip mode, to not depend on a particular file extension. This allows rewriting the gzip method using internal decompression (on ".decomp" files). This requires a zlib bug workaround in FileFd::Close(): When opening an empty file with gzdopen(), gzclose() fails with Z_BUF_ERROR. Do not count this as a failure. --- apt-pkg/contrib/fileutl.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'apt-pkg/contrib') diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 2b91a46f7..0d2d3f356 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -608,7 +608,7 @@ bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms) case ReadOnlyGzip: iFd = open(FileName.c_str(),O_RDONLY); - if (iFd > 0 && FileName.compare(FileName.size()-3, 3, ".gz") == 0) { + if (iFd > 0) { gz = gzdopen (iFd, "r"); if (gz == NULL) { close (iFd); @@ -827,8 +827,16 @@ bool FileFd::Close() { bool Res = true; if ((Flags & AutoClose) == AutoClose) - if ((gz != NULL && gzclose(gz) != 0) || (gz == NULL && iFd > 0 && close(iFd) != 0)) - Res &= _error->Errno("close",_("Problem closing the file")); + { + if (gz != NULL) { + int e = gzclose(gz); + // gzdopen() on empty files always fails with "buffer error" here, ignore that + if (e != 0 && e != Z_BUF_ERROR) + Res &= _error->Errno("close",_("Problem closing the gzip file")); + } else + if (iFd > 0 && close(iFd) != 0) + Res &= _error->Errno("close",_("Problem closing the file")); + } iFd = -1; gz = NULL; -- cgit v1.2.3