diff options
Diffstat (limited to 'apt-pkg/contrib')
-rw-r--r-- | apt-pkg/contrib/arfile.cc | 160 | ||||
-rw-r--r-- | apt-pkg/contrib/arfile.h | 69 | ||||
-rw-r--r-- | apt-pkg/contrib/extracttar.cc | 306 | ||||
-rw-r--r-- | apt-pkg/contrib/extracttar.h | 60 | ||||
-rw-r--r-- | apt-pkg/contrib/hashsum_template.h | 15 | ||||
-rw-r--r-- | apt-pkg/contrib/macros.h | 4 | ||||
-rw-r--r-- | apt-pkg/contrib/string_view.h | 6 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 5 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.h | 7 |
9 files changed, 604 insertions, 28 deletions
diff --git a/apt-pkg/contrib/arfile.cc b/apt-pkg/contrib/arfile.cc new file mode 100644 index 000000000..3fc3afedb --- /dev/null +++ b/apt-pkg/contrib/arfile.cc @@ -0,0 +1,160 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + AR File - Handle an 'AR' archive + + AR Archives have plain text headers at the start of each file + section. The headers are aligned on a 2 byte boundary. + + Information about the structure of AR files can be found in ar(5) + on a BSD system, or in the binutils source. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include <config.h> + +#include <apt-pkg/arfile.h> +#include <apt-pkg/error.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/strutl.h> + +#include <string> +#include <string.h> +#include <sys/types.h> + +#include <apti18n.h> + /*}}}*/ + +struct ARArchive::MemberHeader +{ + char Name[16]; + char MTime[12]; + char UID[6]; + char GID[6]; + char Mode[8]; + char Size[10]; + char Magic[2]; +}; + +// ARArchive::ARArchive - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +ARArchive::ARArchive(FileFd &File) : List(0), File(File) +{ + LoadHeaders(); +} + /*}}}*/ +// ARArchive::~ARArchive - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +ARArchive::~ARArchive() +{ + while (List != 0) + { + Member *Tmp = List; + List = List->Next; + delete Tmp; + } +} + /*}}}*/ +// ARArchive::LoadHeaders - Load the headers from each file /*{{{*/ +// --------------------------------------------------------------------- +/* AR files are structured with a 8 byte magic string followed by a 60 + byte plain text header then the file data, another header, data, etc */ +bool ARArchive::LoadHeaders() +{ + off_t Left = File.Size(); + + // Check the magic byte + char Magic[8]; + if (File.Read(Magic,sizeof(Magic)) == false) + return false; + if (memcmp(Magic,"!<arch>\012",sizeof(Magic)) != 0) + return _error->Error(_("Invalid archive signature")); + Left -= sizeof(Magic); + + // Read the member list + while (Left > 0) + { + MemberHeader Head; + if (File.Read(&Head,sizeof(Head)) == false) + return _error->Error(_("Error reading archive member header")); + Left -= sizeof(Head); + + // Convert all of the integer members + Member *Memb = new Member(); + if (StrToNum(Head.MTime,Memb->MTime,sizeof(Head.MTime)) == false || + StrToNum(Head.UID,Memb->UID,sizeof(Head.UID)) == false || + StrToNum(Head.GID,Memb->GID,sizeof(Head.GID)) == false || + StrToNum(Head.Mode,Memb->Mode,sizeof(Head.Mode),8) == false || + StrToNum(Head.Size,Memb->Size,sizeof(Head.Size)) == false) + { + delete Memb; + return _error->Error(_("Invalid archive member header %s"), Head.Name); + } + + // Check for an extra long name string + if (memcmp(Head.Name,"#1/",3) == 0) + { + char S[300]; + unsigned long Len; + if (StrToNum(Head.Name+3,Len,sizeof(Head.Size)-3) == false || + Len >= sizeof(S)) + { + delete Memb; + return _error->Error(_("Invalid archive member header")); + } + if (File.Read(S,Len) == false) + { + delete Memb; + return false; + } + S[Len] = 0; + Memb->Name = S; + Memb->Size -= Len; + Left -= Len; + } + else + { + unsigned int I = sizeof(Head.Name) - 1; + for (; Head.Name[I] == ' ' || Head.Name[I] == '/'; I--); + Memb->Name = std::string(Head.Name,I+1); + } + + // Account for the AR header alignment + off_t Skip = Memb->Size % 2; + + // Add it to the list + Memb->Next = List; + List = Memb; + Memb->Start = File.Tell(); + if (File.Skip(Memb->Size + Skip) == false) + return false; + if (Left < (off_t)(Memb->Size + Skip)) + return _error->Error(_("Archive is too short")); + Left -= Memb->Size + Skip; + } + if (Left != 0) + return _error->Error(_("Failed to read the archive headers")); + + return true; +} + /*}}}*/ +// ARArchive::FindMember - Find a name in the member list /*{{{*/ +// --------------------------------------------------------------------- +/* Find a member with the given name */ +const ARArchive::Member *ARArchive::FindMember(const char *Name) const +{ + const Member *Res = List; + while (Res != 0) + { + if (Res->Name == Name) + return Res; + Res = Res->Next; + } + + return 0; +} + /*}}}*/ diff --git a/apt-pkg/contrib/arfile.h b/apt-pkg/contrib/arfile.h new file mode 100644 index 000000000..cf454941e --- /dev/null +++ b/apt-pkg/contrib/arfile.h @@ -0,0 +1,69 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + AR File - Handle an 'AR' archive + + This is a reader for the usual 4.4 BSD AR format. It allows raw + stream access to a single member at a time. Basically all this class + provides is header parsing and verification. It is up to the client + to correctly make use of the stream start/stop points. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_ARFILE_H +#define PKGLIB_ARFILE_H + +#include <apt-pkg/macros.h> +#include <string> +#ifndef APT_8_CLEANER_HEADERS +#include <apt-pkg/fileutl.h> +#endif + +class FileFd; + +class ARArchive +{ + struct MemberHeader; + public: + struct Member; + + protected: + + // Linked list of members + Member *List; + + bool LoadHeaders(); + + public: + + // The stream file + FileFd &File; + + // Locate a member by name + const Member *FindMember(const char *Name) const; + inline Member *Members() { return List; } + + explicit ARArchive(FileFd &File); + ~ARArchive(); +}; + +// A member of the archive +struct ARArchive::Member +{ + // Fields from the header + std::string Name; + unsigned long MTime; + unsigned long UID; + unsigned long GID; + unsigned long Mode; + unsigned long long Size; + + // Location of the data. + unsigned long long Start; + Member *Next; + + Member() : Start(0), Next(0) {}; +}; + +#endif diff --git a/apt-pkg/contrib/extracttar.cc b/apt-pkg/contrib/extracttar.cc new file mode 100644 index 000000000..9bb0a55c0 --- /dev/null +++ b/apt-pkg/contrib/extracttar.cc @@ -0,0 +1,306 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Extract a Tar - Tar Extractor + + Some performance measurements showed that zlib performed quite poorly + in comparison to a forked gzip process. This tar extractor makes use + of the fact that dup'd file descriptors have the same seek pointer + and that gzip will not read past the end of a compressed stream, + even if there is more data. We use the dup property to track extraction + progress and the gzip feature to just feed gzip a fd in the middle + of an AR file. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include <config.h> + +#include <apt-pkg/configuration.h> +#include <apt-pkg/dirstream.h> +#include <apt-pkg/error.h> +#include <apt-pkg/extracttar.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/strutl.h> + +#include <algorithm> +#include <iostream> +#include <string> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> + +#include <apti18n.h> + /*}}}*/ + +using namespace std; + +// The on disk header for a tar file. +struct ExtractTar::TarHeader +{ + char Name[100]; + char Mode[8]; + char UserID[8]; + char GroupID[8]; + char Size[12]; + char MTime[12]; + char Checksum[8]; + char LinkFlag; + char LinkName[100]; + char MagicNumber[8]; + char UserName[32]; + char GroupName[32]; + char Major[8]; + char Minor[8]; +}; + +// ExtractTar::ExtractTar - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +ExtractTar::ExtractTar(FileFd &Fd,unsigned long long Max,string DecompressionProgram) + : File(Fd), MaxInSize(Max), DecompressProg(DecompressionProgram) +{ + GZPid = -1; + Eof = false; +} + /*}}}*/ +// ExtractTar::ExtractTar - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +ExtractTar::~ExtractTar() +{ + // Error close + Done(); +} + /*}}}*/ +// ExtractTar::Done - Reap the gzip sub process /*{{{*/ +bool ExtractTar::Done() +{ + return InFd.Close(); +} + /*}}}*/ +// ExtractTar::StartGzip - Startup gzip /*{{{*/ +// --------------------------------------------------------------------- +/* This creates a gzip sub process that has its input as the file itself. + If this tar file is embedded into something like an ar file then + gzip will efficiently ignore the extra bits. */ +bool ExtractTar::StartGzip() +{ + if (DecompressProg.empty()) + { + InFd.OpenDescriptor(File.Fd(), FileFd::ReadOnly, FileFd::None, false); + return true; + } + + 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 == DecompressProg) { + return InFd.OpenDescriptor(File.Fd(), FileFd::ReadOnly, *compressor, false); + } + } + + return _error->Error(_("Cannot find a configured compressor for '%s'"), + DecompressProg.c_str()); + +} + /*}}}*/ +// ExtractTar::Go - Perform extraction /*{{{*/ +// --------------------------------------------------------------------- +/* This reads each 512 byte block from the archive and extracts the header + information into the Item structure. Then it resolves the UID/GID and + invokes the correct processing function. */ +bool ExtractTar::Go(pkgDirStream &Stream) +{ + if (StartGzip() == false) + return false; + + // Loop over all blocks + string LastLongLink, ItemLink; + string LastLongName, ItemName; + while (1) + { + bool BadRecord = false; + unsigned char Block[512]; + if (InFd.Read(Block,sizeof(Block),true) == false) + return false; + + if (InFd.Eof() == true) + break; + + // Get the checksum + TarHeader *Tar = (TarHeader *)Block; + unsigned long CheckSum; + if (StrToNum(Tar->Checksum,CheckSum,sizeof(Tar->Checksum),8) == false) + return _error->Error(_("Corrupted archive")); + + /* Compute the checksum field. The actual checksum is blanked out + with spaces so it is not included in the computation */ + unsigned long NewSum = 0; + memset(Tar->Checksum,' ',sizeof(Tar->Checksum)); + for (int I = 0; I != sizeof(Block); I++) + NewSum += Block[I]; + + /* Check for a block of nulls - in this case we kill gzip, GNU tar + does this.. */ + if (NewSum == ' '*sizeof(Tar->Checksum)) + return Done(); + + if (NewSum != CheckSum) + return _error->Error(_("Tar checksum failed, archive corrupted")); + + // Decode all of the fields + pkgDirStream::Item Itm; + if (StrToNum(Tar->Mode,Itm.Mode,sizeof(Tar->Mode),8) == false || + (Base256ToNum(Tar->UserID,Itm.UID,8) == false && + StrToNum(Tar->UserID,Itm.UID,sizeof(Tar->UserID),8) == false) || + (Base256ToNum(Tar->GroupID,Itm.GID,8) == false && + StrToNum(Tar->GroupID,Itm.GID,sizeof(Tar->GroupID),8) == false) || + (Base256ToNum(Tar->Size,Itm.Size,12) == false && + StrToNum(Tar->Size,Itm.Size,sizeof(Tar->Size),8) == false) || + (Base256ToNum(Tar->MTime,Itm.MTime,12) == false && + StrToNum(Tar->MTime,Itm.MTime,sizeof(Tar->MTime),8) == false) || + StrToNum(Tar->Major,Itm.Major,sizeof(Tar->Major),8) == false || + StrToNum(Tar->Minor,Itm.Minor,sizeof(Tar->Minor),8) == false) + return _error->Error(_("Corrupted archive")); + + // Grab the filename and link target: use last long name if one was + // set, otherwise use the header value as-is, but remember that it may + // fill the entire 100-byte block and needs to be zero-terminated. + // See Debian Bug #689582. + if (LastLongName.empty() == false) + Itm.Name = (char *)LastLongName.c_str(); + else + Itm.Name = (char *)ItemName.assign(Tar->Name, sizeof(Tar->Name)).c_str(); + if (Itm.Name[0] == '.' && Itm.Name[1] == '/' && Itm.Name[2] != 0) + Itm.Name += 2; + + if (LastLongLink.empty() == false) + Itm.LinkTarget = (char *)LastLongLink.c_str(); + else + Itm.LinkTarget = (char *)ItemLink.assign(Tar->LinkName, sizeof(Tar->LinkName)).c_str(); + + // Convert the type over + switch (Tar->LinkFlag) + { + case NormalFile0: + case NormalFile: + Itm.Type = pkgDirStream::Item::File; + break; + + case HardLink: + Itm.Type = pkgDirStream::Item::HardLink; + break; + + case SymbolicLink: + Itm.Type = pkgDirStream::Item::SymbolicLink; + break; + + case CharacterDevice: + Itm.Type = pkgDirStream::Item::CharDevice; + break; + + case BlockDevice: + Itm.Type = pkgDirStream::Item::BlockDevice; + break; + + case Directory: + Itm.Type = pkgDirStream::Item::Directory; + break; + + case FIFO: + Itm.Type = pkgDirStream::Item::FIFO; + break; + + case GNU_LongLink: + { + unsigned long long Length = Itm.Size; + unsigned char Block[512]; + while (Length > 0) + { + if (InFd.Read(Block,sizeof(Block),true) == false) + return false; + if (Length <= sizeof(Block)) + { + LastLongLink.append(Block,Block+sizeof(Block)); + break; + } + LastLongLink.append(Block,Block+sizeof(Block)); + Length -= sizeof(Block); + } + continue; + } + + case GNU_LongName: + { + unsigned long long Length = Itm.Size; + unsigned char Block[512]; + while (Length > 0) + { + if (InFd.Read(Block,sizeof(Block),true) == false) + return false; + if (Length < sizeof(Block)) + { + LastLongName.append(Block,Block+sizeof(Block)); + break; + } + LastLongName.append(Block,Block+sizeof(Block)); + Length -= sizeof(Block); + } + continue; + } + + default: + BadRecord = true; + _error->Warning(_("Unknown TAR header type %u, member %s"),(unsigned)Tar->LinkFlag,Tar->Name); + break; + } + + int Fd = -1; + if (BadRecord == false) + if (Stream.DoItem(Itm,Fd) == false) + return false; + + // Copy the file over the FD + unsigned long long Size = Itm.Size; + while (Size != 0) + { + unsigned char Junk[32*1024]; + unsigned long Read = min(Size, (unsigned long long)sizeof(Junk)); + if (InFd.Read(Junk,((Read+511)/512)*512) == false) + return false; + + if (BadRecord == false) + { + if (Fd > 0) + { + if (write(Fd,Junk,Read) != (signed)Read) + return Stream.Fail(Itm,Fd); + } + else + { + /* An Fd of -2 means to send to a special processing + function */ + if (Fd == -2) + if (Stream.Process(Itm,Junk,Read,Itm.Size - Size) == false) + return Stream.Fail(Itm,Fd); + } + } + + Size -= Read; + } + + // And finish up + if (BadRecord == false) + if (Stream.FinishedFile(Itm,Fd) == false) + return false; + + LastLongName.erase(); + LastLongLink.erase(); + } + + return Done(); +} + /*}}}*/ diff --git a/apt-pkg/contrib/extracttar.h b/apt-pkg/contrib/extracttar.h new file mode 100644 index 000000000..adde21352 --- /dev/null +++ b/apt-pkg/contrib/extracttar.h @@ -0,0 +1,60 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Extract a Tar - Tar Extractor + + The tar extractor takes an ordinary gzip compressed tar stream from + the given file and explodes it, passing the individual items to the + given Directory Stream for processing. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_EXTRACTTAR_H +#define PKGLIB_EXTRACTTAR_H + +#include <apt-pkg/fileutl.h> +#include <apt-pkg/macros.h> + +#include <string> + +#ifndef APT_8_CLEANER_HEADERS +#include <apt-pkg/dirstream.h> +#include <algorithm> +using std::min; +#endif + +class pkgDirStream; + +class ExtractTar +{ + protected: + + struct TarHeader; + + // The varios types items can be + enum ItemType {NormalFile0 = '\0',NormalFile = '0',HardLink = '1', + SymbolicLink = '2',CharacterDevice = '3', + BlockDevice = '4',Directory = '5',FIFO = '6', + GNU_LongLink = 'K',GNU_LongName = 'L'}; + + FileFd &File; + unsigned long long MaxInSize; + int GZPid; + FileFd InFd; + bool Eof; + std::string DecompressProg; + + // Fork and reap gzip + bool StartGzip(); + bool Done(); + + public: + + bool Go(pkgDirStream &Stream); + + ExtractTar(FileFd &Fd,unsigned long long Max,std::string DecompressionProgram); + virtual ~ExtractTar(); +}; + +#endif diff --git a/apt-pkg/contrib/hashsum_template.h b/apt-pkg/contrib/hashsum_template.h index f11fc2f1c..52b2cbab3 100644 --- a/apt-pkg/contrib/hashsum_template.h +++ b/apt-pkg/contrib/hashsum_template.h @@ -11,9 +11,7 @@ #include <cstring> #include <string> -#ifdef APT_PKG_EXPOSE_STRING_VIEW #include <apt-pkg/string_view.h> -#endif #include <apt-pkg/strutl.h> @@ -77,17 +75,10 @@ class HashSumValue return Value(); } -#ifdef APT_PKG_EXPOSE_STRING_VIEW - APT_HIDDEN bool Set(APT::StringView Str) - { - return Hex2Num(Str,Sum,sizeof(Sum)); - } -#else - bool Set(std::string Str) + bool Set(APT::StringView Str) { return Hex2Num(Str,Sum,sizeof(Sum)); } -#endif inline void Set(unsigned char S[N/8]) { for (int I = 0; I != sizeof(Sum); ++I) @@ -99,8 +90,7 @@ class HashSumValue memset(Sum,0,sizeof(Sum)); Set(Str); } -#ifdef APT_PKG_EXPOSE_STRING_VIEW - APT_HIDDEN explicit HashSumValue(APT::StringView const &Str) + explicit HashSumValue(APT::StringView const &Str) { memset(Sum,0,sizeof(Sum)); Set(Str); @@ -110,7 +100,6 @@ class HashSumValue memset(Sum,0,sizeof(Sum)); Set(Str); } -#endif HashSumValue() { memset(Sum,0,sizeof(Sum)); diff --git a/apt-pkg/contrib/macros.h b/apt-pkg/contrib/macros.h index f15625a4c..3648390ce 100644 --- a/apt-pkg/contrib/macros.h +++ b/apt-pkg/contrib/macros.h @@ -165,8 +165,8 @@ // reverse-dependencies of libapt-pkg against the new SONAME. // Non-ABI-Breaks should only increase RELEASE number. // See also buildlib/libversion.mak -#define APT_PKG_MAJOR 6 -#define APT_PKG_MINOR 0 +#define APT_PKG_MAJOR 5 +#define APT_PKG_MINOR 90 #define APT_PKG_RELEASE 0 #define APT_PKG_ABI ((APT_PKG_MAJOR * 100) + APT_PKG_MINOR) diff --git a/apt-pkg/contrib/string_view.h b/apt-pkg/contrib/string_view.h index 536744e32..f4f0c645f 100644 --- a/apt-pkg/contrib/string_view.h +++ b/apt-pkg/contrib/string_view.h @@ -9,7 +9,7 @@ * (at your option) any later version. */ -#if !defined(APT_STRINGVIEW_H) && defined(APT_PKG_EXPOSE_STRING_VIEW) +#if !defined(APT_STRINGVIEW_H) #define APT_STRINGVIEW_H #include <apt-pkg/macros.h> #include <string> @@ -24,7 +24,7 @@ namespace APT { * used by APT. It is not meant to be used in programs, only inside the * library for performance critical paths. */ -class APT_HIDDEN StringView { +class StringView { const char *data_; size_t size_; @@ -128,5 +128,7 @@ static inline int StringViewCompareFast(StringView a, StringView b) { inline bool operator ==(const char *other, APT::StringView that); inline bool operator ==(const char *other, APT::StringView that) { return that.operator==(other); } +inline bool operator ==(std::string const &other, APT::StringView that); +inline bool operator ==(std::string const &other, APT::StringView that) { return that.operator==(other); } #endif diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index e854c5bf1..c00bce5d5 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -1202,11 +1202,6 @@ static int HexDigit(int c) // Hex2Num - Convert a long hex number into a buffer /*{{{*/ // --------------------------------------------------------------------- /* The length of the buffer must be exactly 1/2 the length of the string. */ -bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length) -{ - return Hex2Num(APT::StringView(Str), Num, Length); -} - bool Hex2Num(const APT::StringView Str,unsigned char *Num,unsigned int Length) { if (Str.length() != Length*2) diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index ae0aaedf9..3853d5ba6 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -20,9 +20,7 @@ #include <limits> #include <string> #include <vector> -#ifdef APT_PKG_EXPOSE_STRING_VIEW #include <apt-pkg/string_view.h> -#endif #include <stddef.h> #include <time.h> @@ -100,10 +98,7 @@ bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0) bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base = 0); bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len); bool Base256ToNum(const char *Str,unsigned long long &Res,unsigned int Len); -bool Hex2Num(const std::string &Str,unsigned char *Num,unsigned int Length); -#ifdef APT_PKG_EXPOSE_STRING_VIEW -APT_HIDDEN bool Hex2Num(const APT::StringView Str,unsigned char *Num,unsigned int Length); -#endif +bool Hex2Num(const APT::StringView Str,unsigned char *Num,unsigned int Length); // input changing string split bool TokSplitString(char Tok,char *Input,char **List, unsigned long ListMax); |