From b2e465d6d32d2dc884f58b94acb7e35f671a87fe Mon Sep 17 00:00:00 2001 From: Arch Librarian Date: Mon, 20 Sep 2004 16:56:32 +0000 Subject: Join with aliencode Author: jgg Date: 2001-02-20 07:03:16 GMT Join with aliencode --- apt-inst/deb/debfile.cc | 262 ++++++++++++++++++++++++++ apt-inst/deb/debfile.h | 92 +++++++++ apt-inst/deb/dpkgdb.cc | 490 ++++++++++++++++++++++++++++++++++++++++++++++++ apt-inst/deb/dpkgdb.h | 53 ++++++ 4 files changed, 897 insertions(+) create mode 100644 apt-inst/deb/debfile.cc create mode 100644 apt-inst/deb/debfile.h create mode 100644 apt-inst/deb/dpkgdb.cc create mode 100644 apt-inst/deb/dpkgdb.h (limited to 'apt-inst/deb') 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 +#include +#include +#include + +#include +#include + /*}}}*/ + +// 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); +} + /*}}}*/ + diff --git a/apt-inst/deb/debfile.h b/apt-inst/deb/debfile.h new file mode 100644 index 000000000..d89b85268 --- /dev/null +++ b/apt-inst/deb/debfile.h @@ -0,0 +1,92 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: debfile.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + Debian Archive File (.deb) + + This Class handles all the operations performed directly on .deb + files. It makes use of the AR and TAR classes to give the necessary + external interface. + + There are only two things that can be done with a raw package, + extract it's control information and extract the contents itself. + + This should probably subclass an as-yet unwritten super class to + produce a generic archive mechanism. + + The memory control file extractor is useful to extract a single file + into memory from the control.tar.gz + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_DEBFILE_H +#define PKGLIB_DEBFILE_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/debfile.h" +#endif + +#include +#include +#include +#include + +class debDebFile +{ + protected: + + FileFd &File; + ARArchive AR; + + bool CheckMember(const char *Name); + + public: + + class ControlExtract; + class MemControlExtract; + + bool ExtractControl(pkgDataBase &DB); + bool ExtractArchive(pkgDirStream &Stream); + pkgCache::VerIterator MergeControl(pkgDataBase &DB); + const ARArchive::Member *GotoMember(const char *Name); + inline FileFd &GetFile() {return File;}; + + debDebFile(FileFd &File); +}; + +class debDebFile::ControlExtract : public pkgDirStream +{ + public: + + virtual bool DoItem(Item &Itm,int &Fd); +}; + +class debDebFile::MemControlExtract : public pkgDirStream +{ + bool IsControl; + + public: + + char *Control; + pkgTagSection Section; + unsigned long Length; + string Member; + + // Members from DirStream + virtual bool DoItem(Item &Itm,int &Fd); + virtual bool Process(Item &Itm,const unsigned char *Data, + unsigned long Size,unsigned long Pos); + + + // Helpers + bool Read(debDebFile &Deb); + bool TakeControl(const void *Data,unsigned long Size); + + MemControlExtract() : IsControl(false), Control(0), Length(0), Member("control") {}; + MemControlExtract(string Member) : IsControl(false), Control(0), Length(0), Member(Member) {}; + ~MemControlExtract() {delete [] Control;}; +}; + /*}}}*/ + +#endif diff --git a/apt-inst/deb/dpkgdb.cc b/apt-inst/deb/dpkgdb.cc new file mode 100644 index 000000000..85fec1ccd --- /dev/null +++ b/apt-inst/deb/dpkgdb.cc @@ -0,0 +1,490 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: dpkgdb.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + DPKGv1 Database Implemenation + + This class provides parsers and other implementations for the DPKGv1 + database. It reads the diversion file, the list files and the status + file to build both the list of currently installed files and the + currently installed package list. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#ifdef __GNUG__ +#pragma implementation "apt-pkg/dpkgdb.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + /*}}}*/ + +// EraseDir - Erase A Directory /*{{{*/ +// --------------------------------------------------------------------- +/* This is necessary to create a new empty sub directory. The caller should + invoke mkdir after this with the proper permissions and check for + error. Maybe stick this in fileutils */ +static bool EraseDir(const char *Dir) +{ + // First we try a simple RM + if (rmdir(Dir) == 0 || + errno == ENOENT) + return true; + + // A file? Easy enough.. + if (errno == ENOTDIR) + { + if (unlink(Dir) != 0) + return _error->Errno("unlink","Failed to remove %s",Dir); + return true; + } + + // Should not happen + if (errno != ENOTEMPTY) + return _error->Errno("rmdir","Failed to remove %s",Dir); + + // Purge it using rm + int Pid = ExecFork(); + + // Spawn the subprocess + if (Pid == 0) + { + execlp(_config->Find("Dir::Bin::rm","/bin/rm").c_str(), + "rm","-rf","--",Dir,0); + _exit(100); + } + return ExecWait(Pid,_config->Find("dir::bin::rm","/bin/rm").c_str()); +} + /*}}}*/ +// DpkgDB::debDpkgDB - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +debDpkgDB::debDpkgDB() : CacheMap(0), FileMap(0) +{ + AdminDir = flNotFile(_config->Find("Dir::State::status")); + DiverInode = 0; + DiverTime = 0; +} + /*}}}*/ +// DpkgDB::~debDpkgDB - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +debDpkgDB::~debDpkgDB() +{ + delete Cache; + Cache = 0; + delete CacheMap; + CacheMap = 0; + + delete FList; + FList = 0; + delete FileMap; + FileMap = 0; +} + /*}}}*/ +// DpkgDB::InitMetaTmp - Get the temp dir for meta information /*{{{*/ +// --------------------------------------------------------------------- +/* This creats+empties the meta temporary directory /var/lib/dpkg/tmp.ci + Only one package at a time can be using the returned meta directory. */ +bool debDpkgDB::InitMetaTmp(string &Dir) +{ + string Tmp = AdminDir + "tmp.ci/"; + if (EraseDir(Tmp.c_str()) == false) + return _error->Error("Unable to create %s",Tmp.c_str()); + if (mkdir(Tmp.c_str(),0755) != 0) + return _error->Errno("mkdir","Unable to create %s",Tmp.c_str()); + + // Verify it is on the same filesystem as the main info directory + dev_t Dev; + struct stat St; + if (stat((AdminDir + "info").c_str(),&St) != 0) + return _error->Errno("stat","Failed to stat %sinfo",AdminDir.c_str()); + Dev = St.st_dev; + if (stat(Tmp.c_str(),&St) != 0) + return _error->Errno("stat","Failed to stat %s",Tmp.c_str()); + if (Dev != St.st_dev) + return _error->Error("The info and temp directories need to be on the same filesystem"); + + // Done + Dir = Tmp; + return true; +} + /*}}}*/ +// DpkgDB::ReadyPkgCache - Prepare the cache with the current status /*{{{*/ +// --------------------------------------------------------------------- +/* This reads in the status file into an empty cache. This really needs + to be somehow unified with the high level APT notion of the Database + directory, but there is no clear way on how to do that yet. */ +bool debDpkgDB::ReadyPkgCache(OpProgress &Progress) +{ + if (Cache != 0) + { + Progress.OverallProgress(1,1,1,"Reading Package Lists"); + return true; + } + + if (CacheMap != 0) + { + delete CacheMap; + CacheMap = 0; + } + + if (pkgMakeOnlyStatusCache(Progress,&CacheMap) == false) + return false; + Cache->DropProgress(); + + return true; +} + /*}}}*/ +// DpkgDB::ReadFList - Read the File Listings in /*{{{*/ +// --------------------------------------------------------------------- +/* This reads the file listing in from the state directory. This is a + performance critical routine, as it needs to parse about 50k lines of + text spread over a hundred or more files. For an initial cold start + most of the time is spent in reading file inodes and so on, not + actually parsing. */ +bool debDpkgDB::ReadFList(OpProgress &Progress) +{ + // Count the number of packages we need to read information for + unsigned long Total = 0; + pkgCache &Cache = this->Cache->GetCache(); + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++) + { + // Only not installed packages have no files. + if (I->CurrentState == pkgCache::State::NotInstalled) + continue; + Total++; + } + + /* Switch into the admin dir, this prevents useless lookups for the + path components */ + string Cwd = SafeGetCWD(); + if (chdir((AdminDir + "info/").c_str()) != 0) + return _error->Errno("chdir","Failed to change to the admin dir %sinfo",AdminDir.c_str()); + + // Allocate a buffer. Anything larger than this buffer will be mmaped + unsigned long BufSize = 32*1024; + char *Buffer = new char[BufSize]; + + // Begin Loading them + unsigned long Count = 0; + char Name[300]; + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++) + { + /* Only not installed packages have no files. ConfFile packages have + file lists but we don't want to read them in */ + if (I->CurrentState == pkgCache::State::NotInstalled || + I->CurrentState == pkgCache::State::ConfigFiles) + continue; + + // Fetch a package handle to associate with the file + pkgFLCache::PkgIterator FlPkg = FList->GetPkg(I.Name(),0,true); + if (FlPkg.end() == true) + { + _error->Error("Internal Error getting a Package Name"); + break; + } + + Progress.OverallProgress(Count,Total,1,"Reading File Listing"); + + // Open the list file + snprintf(Name,sizeof(Name),"%s.list",I.Name()); + int Fd = open(Name,O_RDONLY); + + /* Okay this is very strange and bad.. Best thing is to bail and + instruct the user to look into it. */ + struct stat Stat; + if (Fd == -1 || fstat(Fd,&Stat) != 0) + { + _error->Errno("open","Failed to open the list file '%sinfo/%s'. If you " + "cannot restore this file then make it empty " + "and immediately re-install the same version of the package!", + AdminDir.c_str(),Name); + break; + } + + // Set File to be a memory buffer containing the whole file + char *File; + if ((unsigned)Stat.st_size < BufSize) + { + if (read(Fd,Buffer,Stat.st_size) != Stat.st_size) + { + _error->Errno("read","Failed reading the list file %sinfo/%s", + AdminDir.c_str(),Name); + close(Fd); + break; + } + File = Buffer; + } + else + { + // Use mmap + File = (char *)mmap(0,Stat.st_size,PROT_READ,MAP_PRIVATE,Fd,0); + if (File == (char *)(-1)) + { + _error->Errno("mmap","Failed reading the list file %sinfo/%s", + AdminDir.c_str(),Name); + close(Fd); + break; + } + } + + // Parse it + const char *Start = File; + const char *End = File; + const char *Finish = File + Stat.st_size; + for (; End < Finish; End++) + { + // Not an end of line + if (*End != '\n' && End + 1 < Finish) + continue; + + // Skip blank lines + if (End - Start > 1) + { + pkgFLCache::NodeIterator Node = FList->GetNode(Start,End, + FlPkg.Offset(),true,false); + if (Node.end() == true) + { + _error->Error("Internal Error getting a Node"); + break; + } + } + + // Skip past the end of line + for (; *End == '\n' && End < Finish; End++); + Start = End; + } + + close(Fd); + if ((unsigned)Stat.st_size >= BufSize) + munmap((caddr_t)File,Stat.st_size); + + // Failed + if (End < Finish) + break; + + Count++; + } + + delete [] Buffer; + if (chdir(Cwd.c_str()) != 0) + chdir("/"); + + return !_error->PendingError(); +} + /*}}}*/ +// DpkgDB::ReadDiversions - Load the diversions file /*{{{*/ +// --------------------------------------------------------------------- +/* Read the diversion file in from disk. This is usually invoked by + LoadChanges before performing an operation that uses the FLCache. */ +bool debDpkgDB::ReadDiversions() +{ + struct stat Stat; + if (stat((AdminDir + "diversions").c_str(),&Stat) != 0) + return true; + + if (_error->PendingError() == true) + return false; + + FILE *Fd = fopen((AdminDir + "diversions").c_str(),"r"); + if (Fd == 0) + return _error->Errno("fopen","Failed to open the diversions file %sdiversions",AdminDir.c_str()); + + FList->BeginDiverLoad(); + while (1) + { + char From[300]; + char To[300]; + char Package[100]; + + // Read the three lines in + if (fgets(From,sizeof(From),Fd) == 0) + break; + if (fgets(To,sizeof(To),Fd) == 0 || + fgets(Package,sizeof(Package),Fd) == 0) + { + _error->Error("The diversion file is corrupted"); + break; + } + + // Strip the \ns + unsigned long Len = strlen(From); + if (Len < 2 || From[Len-1] != '\n') + _error->Error("Invalid line in the diversion file: %s",From); + else + From[Len-1] = 0; + Len = strlen(To); + if (Len < 2 || To[Len-1] != '\n') + _error->Error("Invalid line in the diversion file: %s",To); + else + To[Len-1] = 0; + Len = strlen(Package); + if (Len < 2 || Package[Len-1] != '\n') + _error->Error("Invalid line in the diversion file: %s",Package); + else + Package[Len-1] = 0; + + // Make sure the lines were parsed OK + if (_error->PendingError() == true) + break; + + // Fetch a package + if (strcmp(Package,":") == 0) + Package[0] = 0; + pkgFLCache::PkgIterator FlPkg = FList->GetPkg(Package,0,true); + if (FlPkg.end() == true) + { + _error->Error("Internal Error getting a Package Name"); + break; + } + + // Install the diversion + if (FList->AddDiversion(FlPkg,From,To) == false) + { + _error->Error("Internal Error adding a diversion"); + break; + } + } + if (_error->PendingError() == false) + FList->FinishDiverLoad(); + + DiverInode = Stat.st_ino; + DiverTime = Stat.st_mtime; + + fclose(Fd); + return !_error->PendingError(); +} + /*}}}*/ +// DpkgDB::ReadFileList - Read the file listing /*{{{*/ +// --------------------------------------------------------------------- +/* Read in the file listing. The file listing is created from three + sources, *.list, Conffile sections and the Diversion table. */ +bool debDpkgDB::ReadyFileList(OpProgress &Progress) +{ + if (Cache == 0) + return _error->Error("The pkg cache must be initialize first"); + if (FList != 0) + { + Progress.OverallProgress(1,1,1,"Reading File List"); + return true; + } + + // Create the cache and read in the file listing + FileMap = new DynamicMMap(MMap::Public); + FList = new pkgFLCache(*FileMap); + if (_error->PendingError() == true || + ReadFList(Progress) == false || + ReadConfFiles() == false || + ReadDiversions() == false) + { + delete FList; + delete FileMap; + FileMap = 0; + FList = 0; + return false; + } + + cout << "Node: " << FList->HeaderP->NodeCount << ',' << FList->HeaderP->UniqNodes << endl; + cout << "Dir: " << FList->HeaderP->DirCount << endl; + cout << "Package: " << FList->HeaderP->PackageCount << endl; + cout << "HashSize: " << FList->HeaderP->HashSize << endl; + cout << "Size: " << FileMap->Size() << endl; + cout << endl; + + return true; +} + /*}}}*/ +// DpkgDB::ReadConfFiles - Read the conf file sections from the s-file /*{{{*/ +// --------------------------------------------------------------------- +/* Reading the conf files is done by reparsing the status file. This is + actually rather fast so it is no big deal. */ +bool debDpkgDB::ReadConfFiles() +{ + FileFd File(_config->FindFile("Dir::State::status"),FileFd::ReadOnly); + pkgTagFile Tags(&File); + if (_error->PendingError() == true) + return false; + + pkgTagSection Section; + while (1) + { + // Skip to the next section + unsigned long Offset = Tags.Offset(); + if (Tags.Step(Section) == false) + break; + + // Parse the line + const char *Start; + const char *Stop; + if (Section.Find("Conffiles",Start,Stop) == false) + continue; + + const char *PkgStart; + const char *PkgEnd; + if (Section.Find("Package",PkgStart,PkgEnd) == false) + return _error->Error("Failed to find a Package: Header, offset %lu",Offset); + + // Snag a package record for it + pkgFLCache::PkgIterator FlPkg = FList->GetPkg(PkgStart,PkgEnd,true); + if (FlPkg.end() == true) + return _error->Error("Internal Error getting a Package Name"); + + // Parse the conf file lines + while (1) + { + for (; isspace(*Start) != 0 && Start < Stop; Start++); + if (Start == Stop) + break; + + // Split it into words + const char *End = Start; + for (; isspace(*End) == 0 && End < Stop; End++); + const char *StartMd5 = End; + for (; isspace(*StartMd5) != 0 && StartMd5 < Stop; StartMd5++); + const char *EndMd5 = StartMd5; + for (; isspace(*EndMd5) == 0 && EndMd5 < Stop; EndMd5++); + if (StartMd5 == EndMd5 || Start == End) + return _error->Error("Bad ConfFile section in the status file. Offset %lu",Offset); + + // Insert a new entry + unsigned char MD5[16]; + if (Hex2Num(StartMd5,EndMd5,MD5,16) == false) + return _error->Error("Error parsing MD5. Offset %lu",Offset); + + if (FList->AddConfFile(Start,End,FlPkg,MD5) == false) + return false; + Start = EndMd5; + } + } + + return true; +} + /*}}}*/ +// DpkgDB::LoadChanges - Read in any changed state files /*{{{*/ +// --------------------------------------------------------------------- +/* The only file in the dpkg system that can change while packages are + unpacking is the diversions file. */ +bool debDpkgDB::LoadChanges() +{ + struct stat Stat; + if (stat((AdminDir + "diversions").c_str(),&Stat) != 0) + return true; + if (DiverInode == Stat.st_ino && DiverTime == Stat.st_mtime) + return true; + return ReadDiversions(); +} + /*}}}*/ diff --git a/apt-inst/deb/dpkgdb.h b/apt-inst/deb/dpkgdb.h new file mode 100644 index 000000000..ddbb6d6f2 --- /dev/null +++ b/apt-inst/deb/dpkgdb.h @@ -0,0 +1,53 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: dpkgdb.h,v 1.2 2001/02/20 07:03:17 jgg Exp $ +/* ###################################################################### + + DPKGv1 Data Base Implemenation + + The DPKGv1 database is typically stored in /var/lib/dpkg/. For + DPKGv1 the 'meta' information is the contents of the .deb control.tar.gz + member prepended by the package name. The meta information is unpacked + in its temporary directory and then migrated into the main list dir + at a checkpoint. + + Journaling is providing by syncronized file writes to the updates sub + directory. + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_DPKGDB_H +#define PKGLIB_DPKGDB_H + +#ifdef __GNUG__ +#pragma interface "apt-pkg/dpkgdb.h" +#endif + +#include + +class debDpkgDB : public pkgDataBase +{ + protected: + + string AdminDir; + DynamicMMap *CacheMap; + DynamicMMap *FileMap; + unsigned long DiverInode; + signed long DiverTime; + + virtual bool InitMetaTmp(string &Dir); + bool ReadFList(OpProgress &Progress); + bool ReadDiversions(); + bool ReadConfFiles(); + + public: + + virtual bool ReadyFileList(OpProgress &Progress); + virtual bool ReadyPkgCache(OpProgress &Progress); + virtual bool LoadChanges(); + + debDpkgDB(); + virtual ~debDpkgDB(); +}; + +#endif -- cgit v1.2.3