X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/7f350a377e0c65a656b9b5437e27d037fd742901..59194959326dbf114a5c894e4279c04844b4a793:/apt-pkg/contrib/fileutl.cc diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 22730ec04..02b30dc1f 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -1,6 +1,5 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: fileutl.cc,v 1.42 2002/09/14 05:29:22 jgg Exp $ /* ###################################################################### File Utilities @@ -61,113 +60,14 @@ #ifdef HAVE_LZMA #include #endif - -#ifdef WORDS_BIGENDIAN -#include -#endif +#include +#include #include /*}}}*/ using namespace std; -class FileFdPrivate { - public: -#ifdef HAVE_ZLIB - gzFile gz; -#endif -#ifdef HAVE_BZ2 - BZFILE* bz2; -#endif -#ifdef HAVE_LZMA - struct LZMAFILE { - FILE* file; - uint8_t buffer[4096]; - lzma_stream stream; - lzma_ret err; - bool eof; - bool compressing; - - LZMAFILE() : file(NULL), eof(false), compressing(false) {} - ~LZMAFILE() { - if (compressing == true) - { - for (;;) { - stream.avail_out = sizeof(buffer)/sizeof(buffer[0]); - stream.next_out = buffer; - err = lzma_code(&stream, LZMA_FINISH); - if (err != LZMA_OK && err != LZMA_STREAM_END) - { - _error->Error("~LZMAFILE: Compress finalisation failed"); - break; - } - size_t const n = sizeof(buffer)/sizeof(buffer[0]) - stream.avail_out; - if (n && fwrite(buffer, 1, n, file) != n) - { - _error->Errno("~LZMAFILE",_("Write error")); - break; - } - if (err == LZMA_STREAM_END) - break; - } - } - lzma_end(&stream); - fclose(file); - } - }; - LZMAFILE* lzma; -#endif - int compressed_fd; - pid_t compressor_pid; - bool pipe; - APT::Configuration::Compressor compressor; - unsigned int openmode; - unsigned long long seekpos; - FileFdPrivate() : -#ifdef HAVE_ZLIB - gz(NULL), -#endif -#ifdef HAVE_BZ2 - bz2(NULL), -#endif -#ifdef HAVE_LZMA - lzma(NULL), -#endif - compressed_fd(-1), compressor_pid(-1), pipe(false), - openmode(0), seekpos(0) {}; - bool CloseDown(std::string const &FileName) - { - bool Res = true; -#ifdef HAVE_ZLIB - if (gz != NULL) { - int const e = gzclose(gz); - gz = NULL; - // gzdclose() 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 %s"), FileName.c_str()); - } -#endif -#ifdef HAVE_BZ2 - if (bz2 != NULL) { - BZ2_bzclose(bz2); - bz2 = NULL; - } -#endif -#ifdef HAVE_LZMA - if (lzma != NULL) { - delete lzma; - lzma = NULL; - } -#endif - if (compressor_pid > 0) - ExecWait(compressor_pid, "FileFdCompressor", true); - compressor_pid = -1; - - return Res; - } - ~FileFdPrivate() { CloseDown(""); } -}; - // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -201,7 +101,11 @@ bool RunScripts(const char *Cnf) { if (Opts->Value.empty() == true) continue; - + + if(_config->FindB("Debug::RunScripts", false) == true) + std::clog << "Running external script: '" + << Opts->Value << "'" << std::endl; + if (system(Opts->Value.c_str()) != 0) _exit(100+Count); } @@ -752,6 +656,22 @@ string flCombine(string Dir,string File) return Dir + '/' + File; } /*}}}*/ +// flAbsPath - Return the absolute path of the filename /*{{{*/ +// --------------------------------------------------------------------- +/* */ +string flAbsPath(string File) +{ + char *p = realpath(File.c_str(), NULL); + if (p == NULL) + { + _error->Errno("realpath", "flAbsPath failed"); + return ""; + } + std::string AbsPath(p); + free(p); + return AbsPath; +} + /*}}}*/ // SetCloseExec - Set the close on exec flag /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -932,13 +852,150 @@ bool ExecWait(pid_t Pid,const char *Name,bool Reap) } /*}}}*/ + +// StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool StartsWithGPGClearTextSignature(string const &FileName) +{ + static const char* SIGMSG = "-----BEGIN PGP SIGNED MESSAGE-----\n"; + char buffer[strlen(SIGMSG)+1]; + FILE* gpg = fopen(FileName.c_str(), "r"); + if (gpg == NULL) + return false; + + char const * const test = fgets(buffer, sizeof(buffer), gpg); + fclose(gpg); + if (test == NULL || strcmp(buffer, SIGMSG) != 0) + return false; + + return true; +} + + +class FileFdPrivate { /*{{{*/ + public: +#ifdef HAVE_ZLIB + gzFile gz; +#endif +#ifdef HAVE_BZ2 + BZFILE* bz2; +#endif +#ifdef HAVE_LZMA + struct LZMAFILE { + FILE* file; + uint8_t buffer[4096]; + lzma_stream stream; + lzma_ret err; + bool eof; + bool compressing; + + LZMAFILE() : file(NULL), eof(false), compressing(false) {} + ~LZMAFILE() { + if (compressing == true) + { + for (;;) { + stream.avail_out = sizeof(buffer)/sizeof(buffer[0]); + stream.next_out = buffer; + err = lzma_code(&stream, LZMA_FINISH); + if (err != LZMA_OK && err != LZMA_STREAM_END) + { + _error->Error("~LZMAFILE: Compress finalisation failed"); + break; + } + size_t const n = sizeof(buffer)/sizeof(buffer[0]) - stream.avail_out; + if (n && fwrite(buffer, 1, n, file) != n) + { + _error->Errno("~LZMAFILE",_("Write error")); + break; + } + if (err == LZMA_STREAM_END) + break; + } + } + lzma_end(&stream); + fclose(file); + } + }; + LZMAFILE* lzma; +#endif + int compressed_fd; + pid_t compressor_pid; + bool pipe; + APT::Configuration::Compressor compressor; + unsigned int openmode; + unsigned long long seekpos; + FileFdPrivate() : +#ifdef HAVE_ZLIB + gz(NULL), +#endif +#ifdef HAVE_BZ2 + bz2(NULL), +#endif +#ifdef HAVE_LZMA + lzma(NULL), +#endif + compressed_fd(-1), compressor_pid(-1), pipe(false), + openmode(0), seekpos(0) {}; + bool InternalClose(std::string const &FileName) + { + if (false) + /* dummy so that the rest can be 'else if's */; +#ifdef HAVE_ZLIB + else if (gz != NULL) { + int const e = gzclose(gz); + gz = NULL; + // gzdclose() on empty files always fails with "buffer error" here, ignore that + if (e != 0 && e != Z_BUF_ERROR) + return _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str()); + } +#endif +#ifdef HAVE_BZ2 + else if (bz2 != NULL) { + BZ2_bzclose(bz2); + bz2 = NULL; + } +#endif +#ifdef HAVE_LZMA + else if (lzma != NULL) { + delete lzma; + lzma = NULL; + } +#endif + return true; + } + bool CloseDown(std::string const &FileName) + { + bool const Res = InternalClose(FileName); + + if (compressor_pid > 0) + ExecWait(compressor_pid, "FileFdCompressor", true); + compressor_pid = -1; + + return Res; + } + bool InternalStream() const { + return false +#ifdef HAVE_BZ2 + || bz2 != NULL +#endif +#ifdef HAVE_LZMA + || lzma != NULL +#endif + ; + } + + + ~FileFdPrivate() { CloseDown(""); } +}; + /*}}}*/ // FileFd::Open - Open a file /*{{{*/ // --------------------------------------------------------------------- /* The most commonly used open mode combinations are given with Mode */ -bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const Perms) +bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const AccessMode) { if (Mode == ReadOnlyGzip) - return Open(FileName, ReadOnly, Gzip, Perms); + return Open(FileName, ReadOnly, Gzip, AccessMode); if (Compress == Auto && (Mode & WriteOnly) == WriteOnly) return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str()); @@ -1005,9 +1062,9 @@ bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, if (compressor == compressors.end()) return FileFdError("Can't find a match for specified compressor mode for file %s", FileName.c_str()); - return Open(FileName, Mode, *compressor, Perms); + return Open(FileName, Mode, *compressor, AccessMode); } -bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const Perms) +bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const AccessMode) { Close(); Flags = AutoClose; @@ -1057,11 +1114,18 @@ bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Co TemporaryFileName = string(name); free(name); - if(Perms != 600 && fchmod(iFd, Perms) == -1) + // umask() will always set the umask and return the previous value, so + // we first set the umask and then reset it to the old value + mode_t const CurrentUmask = umask(0); + umask(CurrentUmask); + // calculate the actual file permissions (just like open/creat) + mode_t const FilePermissions = (AccessMode & ~CurrentUmask); + + if(fchmod(iFd, FilePermissions) == -1) return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName.c_str()); } else - iFd = open(FileName.c_str(), fileflags, Perms); + iFd = open(FileName.c_str(), fileflags, AccessMode); this->FileName = FileName; if (iFd == -1 || OpenInternDescriptor(Mode, compressor) == false) @@ -1147,28 +1211,21 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C void* (*compress_open)(int, const char *) = NULL; if (false) /* dummy so that the rest can be 'else if's */; -#define APT_COMPRESS_INIT(NAME,OPEN,CLOSE,STRUCT) \ +#define APT_COMPRESS_INIT(NAME,OPEN) \ else if (compressor.Name == NAME) \ { \ compress_open = (void*(*)(int, const char *)) OPEN; \ - if (d != NULL && STRUCT != NULL) { CLOSE(STRUCT); STRUCT = NULL; } \ + if (d != NULL) d->InternalClose(FileName); \ } #ifdef HAVE_ZLIB - APT_COMPRESS_INIT("gzip", gzdopen, gzclose, d->gz) + APT_COMPRESS_INIT("gzip", gzdopen) #endif #ifdef HAVE_BZ2 - APT_COMPRESS_INIT("bzip2", BZ2_bzdopen, BZ2_bzclose, d->bz2) + APT_COMPRESS_INIT("bzip2", BZ2_bzdopen) #endif #ifdef HAVE_LZMA - else if (compressor.Name == "xz" || compressor.Name == "lzma") - { - compress_open = (void*(*)(int, const char*)) fdopen; - if (d != NULL && d->lzma != NULL) - { - delete d->lzma; - d->lzma = NULL; - } - } + APT_COMPRESS_INIT("xz", fdopen) + APT_COMPRESS_INIT("lzma", fdopen) #endif #undef APT_COMPRESS_INIT #endif @@ -1179,7 +1236,7 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C d->openmode = Mode; d->compressor = compressor; #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA - if (AutoClose == false && compress_open != NULL) + if ((Flags & AutoClose) != AutoClose && compress_open != NULL) { // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well int const internFd = dup(iFd); @@ -1337,7 +1394,10 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C Args.push_back(a->c_str()); if (Comp == false && FileName.empty() == false) { - Args.push_back("--stdout"); + // commands not needing arguments, do not need to be told about using standard output + // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this + if (compressor.CompressArgs.empty() == false && compressor.UncompressArgs.empty() == false) + Args.push_back("--stdout"); if (TemporaryFileName.empty() == false) Args.push_back(TemporaryFileName.c_str()); else @@ -1418,7 +1478,15 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual) errno = 0; } else + { Res = Size - d->lzma->stream.avail_out; + if (Res == 0) + { + // lzma run was okay, but produced no output… + Res = -1; + errno = EINTR; + } + } } #endif else @@ -1427,7 +1495,12 @@ bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual) if (Res < 0) { if (errno == EINTR) + { + // trick the while-loop into running again + Res = 1; + errno = 0; continue; + } if (false) /* dummy so that the rest can be 'else if's */; #ifdef HAVE_ZLIB @@ -1617,14 +1690,9 @@ bool FileFd::Write(int Fd, const void *From, unsigned long long Size) /* */ bool FileFd::Seek(unsigned long long To) { - if (d != NULL && (d->pipe == true -#ifdef HAVE_BZ2 - || d->bz2 != NULL -#endif -#ifdef HAVE_LZMA - || d->lzma != NULL -#endif - )) + Flags &= ~HitEof; + + if (d != NULL && (d->pipe == true || d->InternalStream() == true)) { // Our poor man seeking in pipes is costly, so try to avoid it unsigned long long seekpos = Tell(); @@ -1635,22 +1703,7 @@ bool FileFd::Seek(unsigned long long To) if ((d->openmode & ReadOnly) != ReadOnly) return FileFdError("Reopen is only implemented for read-only files!"); - if (false) - /* dummy so that the rest can be 'else if's */; -#ifdef HAVE_BZ2 - else if (d->bz2 != NULL) - { - BZ2_bzclose(d->bz2); - d->bz2 = NULL; - } -#endif -#ifdef HAVE_LZMA - else if (d->lzma != NULL) - { - delete d->lzma; - d->lzma = NULL; - } -#endif + d->InternalClose(FileName); if (iFd != -1) close(iFd); iFd = -1; @@ -1696,16 +1749,8 @@ bool FileFd::Seek(unsigned long long To) /* */ bool FileFd::Skip(unsigned long long Over) { - if (d != NULL && (d->pipe == true -#ifdef HAVE_BZ2 - || d->bz2 != NULL -#endif -#ifdef HAVE_LZMA - || d->lzma != NULL -#endif - )) + if (d != NULL && (d->pipe == true || d->InternalStream() == true)) { - d->seekpos += Over; char buffer[1024]; while (Over != 0) { @@ -1741,17 +1786,11 @@ bool FileFd::Truncate(unsigned long long To) if (To == 0 && FileName == "/dev/null") return true; #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA - if (d != NULL && ( + if (d != NULL && (d->InternalStream() == true #ifdef HAVE_ZLIB - d->gz != NULL || + || d->gz != NULL #endif -#ifdef HAVE_BZ2 - d->bz2 != NULL || -#endif -#ifdef HAVE_LZMA - d->lzma != NULL || -#endif - false)) + )) return FileFdError("Truncating compressed files is not implemented (%s)", FileName.c_str()); #endif if (ftruncate(iFd,To) != 0) @@ -1769,14 +1808,7 @@ unsigned long long FileFd::Tell() // seeking around, but not all users of FileFd use always Seek() and co // so d->seekpos isn't always true and we can just use it as a hint if // we have nothing else, but not always as an authority… - if (d != NULL && (d->pipe == true -#ifdef HAVE_BZ2 - || d->bz2 != NULL -#endif -#ifdef HAVE_LZMA - || d->lzma != NULL -#endif - )) + if (d != NULL && (d->pipe == true || d->InternalStream() == true)) return d->seekpos; off_t Res; @@ -1851,14 +1883,7 @@ unsigned long long FileFd::Size() // for compressor pipes st_size is undefined and at 'best' zero, // so we 'read' the content and 'seek' back - see there - if (d != NULL && (d->pipe == true -#ifdef HAVE_BZ2 - || (d->bz2 && size > 0) -#endif -#ifdef HAVE_LZMA - || (d->lzma && size > 0) -#endif - )) + if (d != NULL && (d->pipe == true || (d->InternalStream() == true && size > 0))) { unsigned long long const oldSeek = Tell(); char ignore[1000]; @@ -1889,19 +1914,13 @@ unsigned long long FileFd::Size() FileFdErrno("lseek","Unable to seek to end of gzipped file"); return 0; } - size = 0; + uint32_t size = 0; if (read(iFd, &size, 4) != 4) { FileFdErrno("read","Unable to read original size of gzipped file"); return 0; } - -#ifdef WORDS_BIGENDIAN - uint32_t tmp_size = size; - uint8_t const * const p = (uint8_t const * const) &tmp_size; - tmp_size = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; - size = tmp_size; -#endif + size = le32toh(size); if (lseek(iFd, oldPos, SEEK_SET) < 0) { @@ -1929,7 +1948,6 @@ bool FileFd::Close() { if ((Flags & Compressed) != Compressed && iFd > 0 && close(iFd) != 0) Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str()); - if (d != NULL) { Res &= d->CloseDown(FileName); @@ -2055,3 +2073,94 @@ std::string GetTempDir() return string(tmpdir); } + +FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink) +{ + char fn[512]; + FileFd *Fd = new FileFd(); + + std::string tempdir = GetTempDir(); + snprintf(fn, sizeof(fn), "%s/%s.XXXXXX", + tempdir.c_str(), Prefix.c_str()); + int fd = mkstemp(fn); + if(ImmediateUnlink) + unlink(fn); + if (fd < 0) + { + _error->Errno("GetTempFile",_("Unable to mkstemp %s"), fn); + return NULL; + } + if (!Fd->OpenDescriptor(fd, FileFd::WriteOnly, FileFd::None, true)) + { + _error->Errno("GetTempFile",_("Unable to write to %s"),fn); + return NULL; + } + + return Fd; +} + +bool Rename(std::string From, std::string To) +{ + if (rename(From.c_str(),To.c_str()) != 0) + { + _error->Error(_("rename failed, %s (%s -> %s)."),strerror(errno), + From.c_str(),To.c_str()); + return false; + } + return true; +} + +bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode) +{ + int fd; + if (Mode != FileFd::ReadOnly && Mode != FileFd::WriteOnly) + return _error->Error("Popen supports ReadOnly (x)or WriteOnly mode only"); + + int Pipe[2] = {-1, -1}; + if(pipe(Pipe) != 0) + { + return _error->Errno("pipe", _("Failed to create subprocess IPC")); + return NULL; + } + std::set keep_fds; + keep_fds.insert(Pipe[0]); + keep_fds.insert(Pipe[1]); + Child = ExecFork(keep_fds); + if(Child < 0) + return _error->Errno("fork", "Failed to fork"); + if(Child == 0) + { + if(Mode == FileFd::ReadOnly) + { + close(Pipe[0]); + fd = Pipe[1]; + } + else if(Mode == FileFd::WriteOnly) + { + close(Pipe[1]); + fd = Pipe[0]; + } + + if(Mode == FileFd::ReadOnly) + { + dup2(fd, 1); + dup2(fd, 2); + } else if(Mode == FileFd::WriteOnly) + dup2(fd, 0); + + execv(Args[0], (char**)Args); + _exit(100); + } + if(Mode == FileFd::ReadOnly) + { + close(Pipe[1]); + fd = Pipe[0]; + } else if(Mode == FileFd::WriteOnly) + { + close(Pipe[0]); + fd = Pipe[1]; + } + Fd.OpenDescriptor(fd, Mode, FileFd::None, true); + + return true; +}