diff options
Diffstat (limited to 'apt-inst/deb/debfile.cc')
-rw-r--r-- | apt-inst/deb/debfile.cc | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/apt-inst/deb/debfile.cc b/apt-inst/deb/debfile.cc new file mode 100644 index 000000000..c93ba88a8 --- /dev/null +++ b/apt-inst/deb/debfile.cc @@ -0,0 +1,262 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debfile.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Debian Archive File (.deb) + + .DEB archives are AR files containing two tars and an empty marker + member called 'debian-binary'. The two tars contain the meta data and + the actual archive contents. Thus this class is a very simple wrapper + around ar/tar to simply extract the right tar files. + + It also uses the deb package list parser to parse the control file + into the cache. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/debfile.h" +#endif + +#include <apt-pkg/debfile.h> +#include <apt-pkg/extracttar.h> +#include <apt-pkg/error.h> +#include <apt-pkg/deblistparser.h> + +#include <sys/stat.h> +#include <unistd.h> + /*}}}*/ + +// DebFile::debDebFile - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* Open the AR file and check for consistency */ +debDebFile::debDebFile(FileFd &File) : File(File), AR(File) +{ + if (_error->PendingError() == true) + return; + + // Check the members for validity + if (CheckMember("debian-binary") == false || + CheckMember("control.tar.gz") == false || + CheckMember("data.tar.gz") == false) + return; +} + /*}}}*/ +// DebFile::CheckMember - Check if a named member is in the archive /*{{{*/ +// --------------------------------------------------------------------- +/* This is used to check for a correct deb and to give nicer error messages + for people playing around. */ +bool debDebFile::CheckMember(const char *Name) +{ + if (AR.FindMember(Name) == 0) + return _error->Error("This is not a valid DEB archive, missing '%s' member",Name); + return true; +} + /*}}}*/ +// DebFile::GotoMember - Jump to a Member /*{{{*/ +// --------------------------------------------------------------------- +/* Jump in the file to the start of a named member and return the information + about that member. The caller can then read from the file up to the + returned size. Note, since this relies on the file position this is + a destructive operation, it also changes the last returned Member + structure - so don't nest them! */ +const ARArchive::Member *debDebFile::GotoMember(const char *Name) +{ + // Get the archive member and positition the file + const ARArchive::Member *Member = AR.FindMember(Name); + if (Member == 0) + { + _error->Error("Internal Error, could not locate member %s",Name); + return 0; + } + if (File.Seek(Member->Start) == false) + return 0; + + return Member; +} + /*}}}*/ +// DebFile::ExtractControl - Extract Control information /*{{{*/ +// --------------------------------------------------------------------- +/* Extract the control information into the Database's temporary + directory. */ +bool debDebFile::ExtractControl(pkgDataBase &DB) +{ + // Get the archive member and positition the file + const ARArchive::Member *Member = GotoMember("control.tar.gz"); + if (Member == 0) + return false; + + // Prepare Tar + ControlExtract Extract; + ExtractTar Tar(File,Member->Size); + if (_error->PendingError() == true) + return false; + + // Get into the temporary directory + string Cwd = SafeGetCWD(); + string Tmp; + if (DB.GetMetaTmp(Tmp) == false) + return false; + if (chdir(Tmp.c_str()) != 0) + return _error->Errno("chdir","Couldn't change to %s",Tmp.c_str()); + + // Do extraction + if (Tar.Go(Extract) == false) + return false; + + // Switch out of the tmp directory. + if (chdir(Cwd.c_str()) != 0) + chdir("/"); + + return true; +} + /*}}}*/ +// DebFile::ExtractArchive - Extract the archive data itself /*{{{*/ +// --------------------------------------------------------------------- +/* Simple wrapper around tar.. */ +bool debDebFile::ExtractArchive(pkgDirStream &Stream) +{ + // Get the archive member and positition the file + const ARArchive::Member *Member = AR.FindMember("data.tar.gz"); + if (Member == 0) + return _error->Error("Internal Error, could not locate member"); + if (File.Seek(Member->Start) == false) + return false; + + // Prepare Tar + ExtractTar Tar(File,Member->Size); + if (_error->PendingError() == true) + return false; + return Tar.Go(Stream); +} + /*}}}*/ +// DebFile::MergeControl - Merge the control information /*{{{*/ +// --------------------------------------------------------------------- +/* This reads the extracted control file into the cache and returns the + version that was parsed. All this really does is select the correct + parser and correct file to parse. */ +pkgCache::VerIterator debDebFile::MergeControl(pkgDataBase &DB) +{ + // Open the control file + string Tmp; + if (DB.GetMetaTmp(Tmp) == false) + return pkgCache::VerIterator(DB.GetCache()); + FileFd Fd(Tmp + "control",FileFd::ReadOnly); + if (_error->PendingError() == true) + return pkgCache::VerIterator(DB.GetCache()); + + // Parse it + debListParser Parse(&Fd); + pkgCache::VerIterator Ver(DB.GetCache()); + if (DB.GetGenerator().MergeList(Parse,&Ver) == false) + return pkgCache::VerIterator(DB.GetCache()); + + if (Ver.end() == true) + _error->Error("Failed to locate a valid control file"); + return Ver; +} + /*}}}*/ + +// DebFile::ControlExtract::DoItem - Control Tar Extraction /*{{{*/ +// --------------------------------------------------------------------- +/* This directory stream handler for the control tar handles extracting + it into the temporary meta directory. It only extracts files, it does + not create directories, links or anything else. */ +bool debDebFile::ControlExtract::DoItem(Item &Itm,int &Fd) +{ + if (Itm.Type != Item::File) + return true; + + /* Cleanse the file name, prevent people from trying to unpack into + absolute paths, .., etc */ + for (char *I = Itm.Name; *I != 0; I++) + if (*I == '/') + *I = '_'; + + /* Force the ownership to be root and ensure correct permissions, + go-w, the rest are left untouched */ + Itm.UID = 0; + Itm.GID = 0; + Itm.Mode &= ~(S_IWGRP | S_IWOTH); + + return pkgDirStream::DoItem(Itm,Fd); +} + /*}}}*/ + +// MemControlExtract::DoItem - Check if it is the control file /*{{{*/ +// --------------------------------------------------------------------- +/* This sets up to extract the control block member file into a memory + block of just the right size. All other files go into the bit bucket. */ +bool debDebFile::MemControlExtract::DoItem(Item &Itm,int &Fd) +{ + // At the control file, allocate buffer memory. + if (Member == Itm.Name) + { + delete [] Control; + Control = new char[Itm.Size+2]; + IsControl = true; + Fd = -2; // Signal to pass to Process + Length = Itm.Size; + } + else + IsControl = false; + + return true; +} + /*}}}*/ +// MemControlExtract::Process - Process extracting the control file /*{{{*/ +// --------------------------------------------------------------------- +/* Just memcopy the block from the tar extractor and put it in the right + place in the pre-allocated memory block. */ +bool debDebFile::MemControlExtract::Process(Item &Itm,const unsigned char *Data, + unsigned long Size,unsigned long Pos) +{ + memcpy(Control + Pos, Data,Size); + return true; +} + /*}}}*/ +// MemControlExtract::Read - Read the control information from the deb /*{{{*/ +// --------------------------------------------------------------------- +/* This uses the internal tar extractor to fetch the control file, and then + it parses it into a tag section parser. */ +bool debDebFile::MemControlExtract::Read(debDebFile &Deb) +{ + // Get the archive member and positition the file + const ARArchive::Member *Member = Deb.GotoMember("control.tar.gz"); + if (Member == 0) + return false; + + // Extract it. + ExtractTar Tar(Deb.GetFile(),Member->Size); + if (Tar.Go(*this) == false) + return false; + + if (Control == 0) + return true; + + Control[Length] = '\n'; + Control[Length+1] = '\n'; + if (Section.Scan(Control,Length+2) == false) + return _error->Error("Unparsible control file"); + return true; +} + /*}}}*/ +// MemControlExtract::TakeControl - Parse a memory block /*{{{*/ +// --------------------------------------------------------------------- +/* The given memory block is loaded into the parser and parsed as a control + record. */ +bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long Size) +{ + delete [] Control; + Control = new char[Size+2]; + Length = Size; + memcpy(Control,Data,Size); + + Control[Length] = '\n'; + Control[Length+1] = '\n'; + return Section.Scan(Control,Length+2); +} + /*}}}*/ + |