From 578bfd0aed2ec993f4ad85fa6a7094a852261422 Mon Sep 17 00:00:00 2001 From: Arch Librarian Date: Mon, 20 Sep 2004 16:50:36 +0000 Subject: Base revisions Author: jgg Date: 1998-07-02 02:58:12 GMT Base revisions --- apt-pkg/cacheiterators.h | 281 +++++++++++++++++++++++++++++++++++ apt-pkg/contrib/error.cc | 139 +++++++++++++++++ apt-pkg/contrib/error.h | 84 +++++++++++ apt-pkg/contrib/fileutl.cc | 214 +++++++++++++++++++++++++++ apt-pkg/contrib/fileutl.h | 63 ++++++++ apt-pkg/contrib/mmap.cc | 227 ++++++++++++++++++++++++++++ apt-pkg/contrib/mmap.h | 92 ++++++++++++ apt-pkg/contrib/system.h | 57 +++++++ apt-pkg/pkgcache.cc | 360 +++++++++++++++++++++++++++++++++++++++++++++ apt-pkg/pkgcache.h | 280 +++++++++++++++++++++++++++++++++++ apt-pkg/pkgcachegen.cc | 184 +++++++++++++++++++++++ apt-pkg/pkgcachegen.h | 69 +++++++++ apt-pkg/tagfile.cc | 195 ++++++++++++++++++++++++ apt-pkg/tagfile.h | 64 ++++++++ apt-pkg/version.cc | 249 +++++++++++++++++++++++++++++++ apt-pkg/version.h | 45 ++++++ 16 files changed, 2603 insertions(+) create mode 100644 apt-pkg/cacheiterators.h create mode 100644 apt-pkg/contrib/error.cc create mode 100644 apt-pkg/contrib/error.h create mode 100644 apt-pkg/contrib/fileutl.cc create mode 100644 apt-pkg/contrib/fileutl.h create mode 100644 apt-pkg/contrib/mmap.cc create mode 100644 apt-pkg/contrib/mmap.h create mode 100644 apt-pkg/contrib/system.h create mode 100644 apt-pkg/pkgcache.cc create mode 100644 apt-pkg/pkgcache.h create mode 100644 apt-pkg/pkgcachegen.cc create mode 100644 apt-pkg/pkgcachegen.h create mode 100644 apt-pkg/tagfile.cc create mode 100644 apt-pkg/tagfile.h create mode 100644 apt-pkg/version.cc create mode 100644 apt-pkg/version.h (limited to 'apt-pkg') diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h new file mode 100644 index 000000000..539444c33 --- /dev/null +++ b/apt-pkg/cacheiterators.h @@ -0,0 +1,281 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: cacheiterators.h,v 1.1 1998/07/02 02:58:12 jgg Exp $ +/* ###################################################################### + + Cache Iterators - Iterators for navigating the cache structure + + The iterators all provides ++,==,!=,->,* and end for their type. + The end function can be used to tell if the list has been fully + traversed. + + Unlike STL iterators these contain helper functions to access the data + that is being iterated over. This is because the data structures can't + be formed in a manner that is intuitive to use and also mmapable. + + For each variable in the target structure that would need a translation + to be accessed correctly a translating function of the same name is + present in the iterator. If applicable the translating function will + return an iterator. + + The DepIterator can iterate over two lists, a list of 'version depends' + or a list of 'package reverse depends'. The type is determined by the + structure passed to the constructor, which should be the structure + that has the depends pointer as a member. + + This header is not user includable, please use pkglib/pkgcache.h + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_CACHEITERATORS_H +#define PKGLIB_CACHEITERATORS_H + +// Package Iterator +class pkgCache::PkgIterator +{ + Package *Pkg; + pkgCache *Owner; + long HashIndex; + + public: + + enum OkState {NeedsNothing,NeedsUnpack,NeedsConfigure}; + + // Iteration + void operator ++(int); + inline void operator ++() {operator ++(0);}; + inline bool end() const {return Owner == 0 || Pkg == Owner->PkgP?true:false;}; + + // Comparison + inline bool operator ==(const PkgIterator &B) const {return Pkg == B.Pkg;}; + inline bool operator !=(const PkgIterator &B) const {return Pkg != B.Pkg;}; + + // Accessors + inline Package *operator ->() {return Pkg;}; + inline Package const *operator ->() const {return Pkg;}; + inline Package const &operator *() const {return *Pkg;}; + inline operator Package *() {return Pkg == Owner->PkgP?0:Pkg;}; + inline operator Package const *() const {return Pkg == Owner->PkgP?0:Pkg;}; + inline const char *Name() const {return Pkg->Name == 0?0:Owner->StrP + Pkg->Name;}; + inline const char *Section() const {return Pkg->Section == 0?0:Owner->StrP + Pkg->Section;}; + inline const char *TargetDist() const {return Pkg->TargetDist == 0?0:Owner->StrP + Pkg->TargetDist;}; + inline VerIterator VersionList() const; + inline VerIterator TargetVer() const; + inline VerIterator CurrentVer() const; + inline DepIterator RevDependsList() const; + inline PrvIterator ProvidesList() const; + OkState State() const; + + // Constructors + inline PkgIterator(pkgCache &Owner) : Owner(&Owner), HashIndex(-1) + { + Pkg = Owner.PkgP; + operator ++(0); + }; + inline PkgIterator(pkgCache &Owner,Package *Trg) : Pkg(Trg), Owner(&Owner), + HashIndex(0) + { + if (Pkg == 0) + Pkg = Owner.PkgP; + }; + inline PkgIterator() : Pkg(0), Owner(0), HashIndex(0) {}; +}; + +// Version Iterator +class pkgCache::VerIterator +{ + Version *Ver; + pkgCache &Owner; + + void _dummy(); + + public: + + // Iteration + void operator ++(int) {if (Ver != Owner.VerP) Ver = Owner.VerP + Ver->NextVer;}; + inline void operator ++() {operator ++(0);}; + inline bool end() const {return Ver == Owner.VerP?true:false;}; + inline void operator =(const VerIterator &B) {Ver = B.Ver;}; + + // Comparison + inline bool operator ==(const VerIterator &B) const {return Ver == B.Ver;}; + inline bool operator !=(const VerIterator &B) const {return Ver != B.Ver;}; + int CompareVer(const VerIterator &B) const; + + // Accessors + inline Version *operator ->() {return Ver;}; + inline Version const *operator ->() const {return Ver;}; + inline Version &operator *() {return *Ver;}; + inline Version const &operator *() const {return *Ver;}; + inline operator Version *() {return Ver == Owner.VerP?0:Ver;}; + inline operator Version const *() const {return Ver == Owner.VerP?0:Ver;}; + inline const char *VerStr() const {return Ver->VerStr == 0?0:Owner.StrP + Ver->VerStr;}; + inline const char *Section() const {return Ver->Section == 0?0:Owner.StrP + Ver->Section;}; + inline PkgFileIterator File() const; + inline PkgIterator ParentPkg() const {return PkgIterator(Owner,Owner.PkgP + Ver->ParentPkg);}; + inline DepIterator DependsList() const; + inline PrvIterator ProvidesList() const; + + inline VerIterator(pkgCache &Owner,Version *Trg) : Ver(Trg), Owner(Owner) + { + if (Ver == 0) + Ver = Owner.VerP; + }; +}; + +// Dependency iterator +class pkgCache::DepIterator +{ + Dependency *Dep; + enum {DepVer, DepRev} Type; + pkgCache *Owner; + + void _dummy(); + + public: + + // Iteration + void operator ++(int) {if (Dep != Owner->DepP) Dep = Owner->DepP + + (Type == DepVer?Dep->NextDepends:Dep->NextRevDepends);}; + inline void operator ++() {operator ++(0);}; + inline bool end() const {return Owner == 0 || Dep == Owner->DepP?true:false;}; + + // Comparison + inline bool operator ==(const DepIterator &B) const {return Dep == B.Dep;}; + inline bool operator !=(const DepIterator &B) const {return Dep != B.Dep;}; + + // Accessors + inline Dependency *operator ->() {return Dep;}; + inline Dependency const *operator ->() const {return Dep;}; + inline Dependency &operator *() {return *Dep;}; + inline Dependency const &operator *() const {return *Dep;}; + inline operator Dependency *() {return Dep == Owner->DepP?0:Dep;}; + inline operator Dependency const *() const {return Dep == Owner->DepP?0:Dep;}; + inline const char *TargetVer() const {return Dep->Version == 0?0:Owner->StrP + Dep->Version;}; + inline PkgIterator TargetPkg() {return PkgIterator(*Owner,Owner->PkgP + Dep->Package);}; + Version **AllTargets(); + bool SmartTargetPkg(PkgIterator &Result); + inline PkgIterator SmartTargetPkg() {PkgIterator R(*Owner);SmartTargetPkg(R);return R;}; + inline VerIterator ParentVer() {return VerIterator(*Owner,Owner->VerP + Dep->ParentVer);}; + inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Dep->ParentVer].ParentPkg);}; + bool IsCritical(); + inline bool Reverse() {return Type == DepRev;}; + + inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) : + Dep(Trg), Type(DepVer), Owner(&Owner) + { + if (Dep == 0) + Dep = Owner.DepP; + }; + inline DepIterator(pkgCache &Owner,Dependency *Trg,Package *) : + Dep(Trg), Type(DepRev), Owner(&Owner) + { + if (Dep == 0) + Dep = Owner.DepP; + }; + inline DepIterator() : Dep(0), Type(DepVer), Owner(0) {}; +}; + +// Provides iterator +class pkgCache::PrvIterator +{ + Provides *Prv; + enum {PrvVer, PrvPkg} Type; + pkgCache *Owner; + + void _dummy(); + + public: + + // Iteration + void operator ++(int) {if (Prv != Owner->ProvideP) Prv = Owner->ProvideP + + (Type == PrvVer?Prv->NextPkgProv:Prv->NextProvides);}; + inline void operator ++() {operator ++(0);}; + inline bool end() const {return Prv == Owner->ProvideP?true:false;}; + + // Comparison + inline bool operator ==(const PrvIterator &B) const {return Prv == B.Prv;}; + inline bool operator !=(const PrvIterator &B) const {return Prv != B.Prv;}; + + // Accessors + inline Provides *operator ->() {return Prv;}; + inline Provides const *operator ->() const {return Prv;}; + inline Provides &operator *() {return *Prv;}; + inline Provides const &operator *() const {return *Prv;}; + inline operator Provides *() {return Prv == Owner->ProvideP?0:Prv;}; + inline operator Provides const *() const {return Prv == Owner->ProvideP?0:Prv;}; + inline const char *Name() const {return Owner->StrP + Owner->PkgP[Prv->ParentPkg].Name;}; + inline const char *ProvideVersion() const {return Prv->ProvideVersion == 0?0:Owner->StrP + Prv->ProvideVersion;}; + inline PkgIterator ParentPkg() {return PkgIterator(*Owner,Owner->PkgP + Prv->ParentPkg);}; + inline VerIterator OwnerVer() {return VerIterator(*Owner,Owner->VerP + Prv->Version);}; + inline PkgIterator OwnerPkg() {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[Prv->Version].ParentPkg);}; + + inline PrvIterator(pkgCache &Owner,Provides *Trg,Version *) : + Prv(Trg), Type(PrvVer), Owner(&Owner) + { + if (Prv == 0) + Prv = Owner.ProvideP; + }; + inline PrvIterator(pkgCache &Owner,Provides *Trg,Package *) : + Prv(Trg), Type(PrvPkg), Owner(&Owner) + { + if (Prv == 0) + Prv = Owner.ProvideP; + }; +}; + +// Package file +class pkgCache::PkgFileIterator +{ + pkgCache *Owner; + PackageFile *File; + + public: + + // Iteration + void operator ++(int) {if (File!= Owner->PkgFileP) File = Owner->PkgFileP + File->NextFile;}; + inline void operator ++() {operator ++(0);}; + inline bool end() const {return File == Owner->PkgFileP?true:false;}; + + // Comparison + inline bool operator ==(const PkgFileIterator &B) const {return File == B.File;}; + inline bool operator !=(const PkgFileIterator &B) const {return File != B.File;}; + + // Accessors + inline PackageFile *operator ->() {return File;}; + inline PackageFile const *operator ->() const {return File;}; + inline PackageFile const &operator *() const {return *File;}; + inline operator PackageFile *() {return File == Owner->PkgFileP?0:File;}; + inline operator PackageFile const *() const {return File == Owner->PkgFileP?0:File;}; + + inline const char *FileName() const {return File->FileName == 0?0:Owner->StrP + File->FileName;}; + inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;}; + inline const char *Distribution() const {return File->Distribution == 0?0:Owner->StrP + File->Distribution;}; + + bool IsOk(); + + // Constructors + inline PkgFileIterator(pkgCache &Owner) : Owner(&Owner), File(Owner.PkgFileP + Owner.Head().FileList) {}; + inline PkgFileIterator(pkgCache &Owner,PackageFile *Trg) : Owner(&Owner), File(Trg) {}; +}; + +// Inlined Begin functions cant be in the class because of order problems +inline pkgCache::VerIterator pkgCache::PkgIterator::VersionList() const + {return VerIterator(*Owner,Owner->VerP + Pkg->VersionList);}; +inline pkgCache::VerIterator pkgCache::PkgIterator::CurrentVer() const + {return VerIterator(*Owner,Owner->VerP + Pkg->CurrentVer);}; +inline pkgCache::VerIterator pkgCache::PkgIterator::TargetVer() const + {return VerIterator(*Owner,Owner->VerP + Pkg->TargetVer);}; +inline pkgCache::DepIterator pkgCache::PkgIterator::RevDependsList() const + {return DepIterator(*Owner,Owner->DepP + Pkg->RevDepends,Pkg);}; +inline pkgCache::PrvIterator pkgCache::PkgIterator::ProvidesList() const + {return PrvIterator(*Owner,Owner->ProvideP + Pkg->ProvidesList,Pkg);}; +inline pkgCache::PrvIterator pkgCache::VerIterator::ProvidesList() const + {return PrvIterator(Owner,Owner.ProvideP + Ver->ProvidesList,Ver);}; +inline pkgCache::DepIterator pkgCache::VerIterator::DependsList() const + {return DepIterator(Owner,Owner.DepP + Ver->DependsList,Ver);}; +inline pkgCache::PkgFileIterator pkgCache::VerIterator::File() const + {return PkgFileIterator(Owner,Owner.PkgFileP + Ver->File);}; + +#endif diff --git a/apt-pkg/contrib/error.cc b/apt-pkg/contrib/error.cc new file mode 100644 index 000000000..59d2b8c8b --- /dev/null +++ b/apt-pkg/contrib/error.cc @@ -0,0 +1,139 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: error.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + Global Erorr Class - Global error mechanism + + We use a simple STL vector to store each error record. A PendingFlag + is kept which indicates when the vector contains a Sever error. + + This source is placed in the Public Domain, do with it what you will + It was originally written by Jason Gunthorpe. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include +#include +#include +#include + +#include + /*}}}*/ + +GlobalError *_error = new GlobalError; + +// GlobalError::GlobalError - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +GlobalError::GlobalError() : PendingFlag(false) +{ +} + /*}}}*/ +// GlobalError::Errno - Get part of the error string from errno /*{{{*/ +// --------------------------------------------------------------------- +/* Function indicates the stdlib function that failed and Description is + a user string that leads the text. Form is: + Description - Function (errno: strerror) + Carefull of the buffer overrun, sprintf. + */ +bool GlobalError::Errno(const char *Function,const char *Description,...) +{ + va_list args; + va_start(args,Description); + + // sprintf the description + char S[400]; + vsprintf(S,Description,args); + sprintf(S + strlen(S)," - %s (%i %s)",Function,errno,strerror(errno)); + + // Put it on the list + Item Itm; + Itm.Text = S; + Itm.Error = true; + List.push_back(Itm); + + PendingFlag = true; + + return false; +} + /*}}}*/ +// GlobalError::Error - Add an error to the list /*{{{*/ +// --------------------------------------------------------------------- +/* Just vsprintfs and pushes */ +bool GlobalError::Error(const char *Description,...) +{ + va_list args; + va_start(args,Description); + + // sprintf the description + char S[400]; + vsprintf(S,Description,args); + + // Put it on the list + Item Itm; + Itm.Text = S; + Itm.Error = true; + List.push_back(Itm); + + PendingFlag = true; + + return false; +} + /*}}}*/ +// GlobalError::Warning - Add a warning to the list /*{{{*/ +// --------------------------------------------------------------------- +/* This doesn't set the pending error flag */ +bool GlobalError::Warning(const char *Description,...) +{ + va_list args; + va_start(args,Description); + + // sprintf the description + char S[400]; + vsprintf(S,Description,args); + + // Put it on the list + Item Itm; + Itm.Text = S; + Itm.Error = false; + List.push_back(Itm); + + return false; +} + /*}}}*/ +// GlobalError::PopMessage - Pulls a single message out /*{{{*/ +// --------------------------------------------------------------------- +/* This should be used in a loop checking empty() each cycle. It returns + true if the message is an error. */ +bool GlobalError::PopMessage(string &Text) +{ + bool Ret = List.front().Error; + Text = List.front().Text; + List.erase(List.begin()); + + // This really should check the list to see if only warnings are left.. + if (empty()) + PendingFlag = false; + + return Ret; +} + /*}}}*/ +// GlobalError::DumpErrors - Dump all of the errors/warns to cerr /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void GlobalError::DumpErrors() +{ + // Print any errors or warnings found + string Err; + while (empty() == false) + { + bool Type = PopMessage(Err); + if (Type == true) + cerr << "E: " << Err << endl; + else + cerr << "W: " << Err << endl; + } +} + /*}}}*/ diff --git a/apt-pkg/contrib/error.h b/apt-pkg/contrib/error.h new file mode 100644 index 000000000..06b998e5e --- /dev/null +++ b/apt-pkg/contrib/error.h @@ -0,0 +1,84 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: error.h,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + Global Erorr Class - Global error mechanism + + This class has a single global instance. When a function needs to + generate an error condition, such as a read error, it calls a member + in this class to add the error to a stack of errors. + + By using a stack the problem with a scheme like errno is removed and + it allows a very detailed account of what went wrong to be transmitted + to the UI for display. (Errno has problems because each function sets + errno to 0 if it didn't have an error thus eraseing erno in the process + of cleanup) + + Several predefined error generators are provided to handle common + things like errno. The general idea is that all methods return a bool. + If the bool is true then things are OK, if it is false then things + should start being undone and the stack should unwind under program + control. + + A Warning should not force the return of false. Things did not fail, but + they might have had unexpected problems. Errors are stored in a FIFO + so Pop will return the first item.. + + I have some thoughts about extending this into a more general UI<-> + Engine interface, ie allowing the Engine to say 'The disk is full' in + a dialog that says 'Panic' and 'Retry'.. The error generator functions + like errno, Warning and Error return false always so this is normal: + if (open(..)) + return _error->Errno(..); + + This source is placed in the Public Domain, do with it what you will + It was originally written by Jason Gunthorpe. + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_ERROR_H +#define PKGLIB_ERROR_H + +#include +#include + +class GlobalError +{ + struct Item + { + string Text; + bool Error; + }; + + vector List; + bool PendingFlag; + + public: + + // Call to generate an error from a library call. + bool Errno(const char *Function,const char *Description,...); + + /* A warning should be considered less severe than an error, and may be + ignored by the client. */ + bool Error(const char *Description,...); + bool Warning(const char *Description,...); + + // Simple accessors + inline bool PendingError() {return PendingFlag;}; + inline bool empty() {return List.empty();}; + bool PopMessage(string &Text); + void Discard() {List.erase(List.begin(),List.end()); PendingFlag = false;}; + + // Usefull routine to dump to cerr + void DumpErrors(); + + GlobalError(); +}; + +/* The 'extra-ansi' syntax is used to help with collisions. This is the + single global instance of this class. */ +extern GlobalError *_error; + +#endif diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc new file mode 100644 index 000000000..6048ff0bb --- /dev/null +++ b/apt-pkg/contrib/fileutl.cc @@ -0,0 +1,214 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: fileutl.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + File Utilities + + CopyFile - Buffered copy of a single file + GetLock - dpkg compatible lock file manipulation (fcntl) + + This source is placed in the Public Domain, do with it what you will + It was originally written by Jason Gunthorpe. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include +#include + +#include +#include +#include +#include + /*}}}*/ + +// CopyFile - Buffered copy of a file /*{{{*/ +// --------------------------------------------------------------------- +/* The caller is expected to set things so that failure causes erasure */ +bool CopyFile(File From,File To) +{ + if (From.IsOpen() == false || To.IsOpen() == false) + return false; + + // Buffered copy between fds + unsigned char *Buf = new unsigned char[64000]; + long Size; + while ((Size = read(From.Fd(),Buf,64000)) > 0) + { + if (To.Write(Buf,Size) == false) + { + delete [] Buf; + return false; + } + } + + delete [] Buf; + return true; +} + /*}}}*/ +// GetLock - Gets a lock file /*{{{*/ +// --------------------------------------------------------------------- +/* This will create an empty file of the given name and lock it. Once this + is done all other calls to GetLock in any other process will fail with + -1. The return result is the fd of the file, the call should call + close at some time. */ +int GetLock(string File,bool Errors) +{ + int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640); + if (FD < 0) + { + if (Errors == true) + _error->Errno("open","Could not open lock file %s",File.c_str()); + return -1; + } + + // Aquire a write lock + struct flock fl; + fl.l_type= F_WRLCK; + fl.l_whence= SEEK_SET; + fl.l_start= 0; + fl.l_len= 1; + if (fcntl(FD,F_SETLK,&fl) == -1) + { + if (Errors == true) + _error->Errno("open","Could not get lock %s",File.c_str()); + close(FD); + return -1; + } + + return FD; +} + /*}}}*/ +// FileExists - Check if a file exists /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool FileExists(string File) +{ + struct stat Buf; + if (stat(File.c_str(),&Buf) != 0) + return false; + return true; +} + /*}}}*/ +// SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/ +// --------------------------------------------------------------------- +/* We return / on failure. */ +string SafeGetCWD() +{ + // Stash the current dir. + char S[300]; + S[0] = 0; + if (getcwd(S,sizeof(S)) == 0) + return "/"; + return S; +} + /*}}}*/ + +// File::File - Open a file /*{{{*/ +// --------------------------------------------------------------------- +/* The most commonly used open mode combinations are given with Mode */ +File::File(string FileName,OpenMode Mode, unsigned long Perms) +{ + Flags = 0; + switch (Mode) + { + case ReadOnly: + iFd = open(FileName.c_str(),O_RDONLY); + break; + + case WriteEmpty: + unlink(FileName.c_str()); + iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms); + break; + + case WriteExists: + iFd = open(FileName.c_str(),O_RDWR); + break; + } + + if (iFd < 0) + _error->Errno("open","Could not open file %s",FileName.c_str()); + else + this->FileName = FileName; +} + /*}}}*/ +// File::~File - Closes the file /*{{{*/ +// --------------------------------------------------------------------- +/* If the proper modes are selected then we close the Fd and possibly + unlink the file on error. */ +File::~File() +{ + Close(); +} + /*}}}*/ +// File::Read - Read a bit of the file /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool File::Read(void *To,unsigned long Size) +{ + if (read(iFd,To,Size) != (signed)Size) + { + Flags |= Fail; + return _error->Errno("read","Read error"); + } + + return true; +} + /*}}}*/ +// File::Write - Write to the file /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool File::Write(void *From,unsigned long Size) +{ + if (write(iFd,From,Size) != (signed)Size) + { + Flags |= Fail; + return _error->Errno("write","Write error"); + } + + return true; +} + /*}}}*/ +// File::Seek - Seek in the file /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool File::Seek(unsigned long To) +{ + if (lseek(iFd,To,SEEK_SET) != (signed)To) + { + Flags |= Fail; + return _error->Error("Unable to seek to %u",To); + } + + return true; +} + /*}}}*/ +// File::Size - Return the size of the file /*{{{*/ +// --------------------------------------------------------------------- +/* */ +unsigned long File::Size() +{ + struct stat Buf; + if (fstat(iFd,&Buf) != 0) + return _error->Errno("fstat","Unable to determine the file size"); + return Buf.st_size; +} + /*}}}*/ +// File::Close - Close the file if the close flag is set /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool File::Close() +{ + bool Res = true; + if ((Flags & AutoClose) == AutoClose) + if (close(iFd) != 0) + Res &= _error->Errno("close","Problem closing the file"); + + if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail && + FileName.empty() == false) + if (unlink(FileName.c_str()) != 0) + Res &= _error->Warning("unlnk","Problem unlinking the file"); + return Res; +} + /*}}}*/ diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h new file mode 100644 index 000000000..1b6666843 --- /dev/null +++ b/apt-pkg/contrib/fileutl.h @@ -0,0 +1,63 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: fileutl.h,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + File Utilities + + CopyFile - Buffered copy of a single file + GetLock - dpkg compatible lock file manipulation (fcntl) + FileExists - Returns true if the file exists + SafeGetCWD - Returns the CWD in a string with overrun protection + + The file class is a handy abstraction for various functions+classes + that need to accept filenames. + + This source is placed in the Public Domain, do with it what you will + It was originally written by Jason Gunthorpe. + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_FILEUTL_H +#define PKGLIB_FILEUTL_H + +#include + +class File +{ + protected: + int iFd; + + enum LocalFlags {AutoClose = (1<<0),Fail = (1<<1),DelOnFail = (1<<2)}; + unsigned long Flags; + string FileName; + + public: + enum OpenMode {ReadOnly,WriteEmpty,WriteExists}; + + bool Read(void *To,unsigned long Size); + bool Write(void *From,unsigned long Size); + bool Seek(unsigned long To); + unsigned long Size(); + bool Close(); + + // Simple manipulators + inline int Fd() {return iFd;}; + inline bool IsOpen() {return iFd >= 0;}; + inline bool Failed() {return (Flags & Fail) == Fail;}; + inline void EraseOnFailure() {Flags |= DelOnFail;}; + inline void OpFail() {Flags |= Fail;}; + + File(string FileName,OpenMode Mode,unsigned long Perms = 0666); + File(int Fd) : iFd(Fd), Flags(AutoClose) {}; + File(int Fd,bool) : iFd(Fd), Flags(0) {}; + virtual ~File(); +}; + +bool CopyFile(string From,string To); +int GetLock(string File,bool Errors = true); +bool FileExists(string File); +string SafeGetCWD(); + +#endif diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc new file mode 100644 index 000000000..85cac1cca --- /dev/null +++ b/apt-pkg/contrib/mmap.cc @@ -0,0 +1,227 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: mmap.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + MMap Class - Provides 'real' mmap or a faked mmap using read(). + + MMap cover class. + + Some broken versions of glibc2 (libc6) have a broken definition + of mmap that accepts a char * -- all other systems (and libc5) use + void *. We can't safely do anything here that would be portable, so + libc6 generates warnings -- which should be errors, g++ isn't properly + strict. + + The configure test notes that some OS's have broken private mmap's + so on those OS's we can't use mmap. This means we have to use + configure to test mmap and can't rely on the POSIX + _POSIX_MAPPED_FILES test. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#define _BSD_SOURCE +#include +#include + +#include +#include +#include +#include +#include + /*}}}*/ + +// MMap::MMap - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +MMap::MMap(File &F,unsigned long Flags) : Fd(F), Flags(Flags), iSize(0), + Base(0) +{ + if ((Flags & NoImmMap) != NoImmMap) + Map(); +} + /*}}}*/ +// MMap::~MMap - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +MMap::~MMap() +{ + Close(true); +} + /*}}}*/ +// MMap::Map - Perform the mapping /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool MMap::Map() +{ + iSize = Fd.Size(); + + // Set the permissions. + int Prot = PROT_READ; + int Map = MAP_SHARED; + if ((Flags & ReadOnly) != ReadOnly) + Prot |= PROT_WRITE; + if ((Flags & Public) != Public) + Map = MAP_PRIVATE; + + // Map it. + Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0); + if (Base == (void *)-1) + return _error->Errno("mmap","Couldn't make mmap of %u bytes",iSize); + + return true; +} + /*}}}*/ +// MMap::Close - Close the map /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool MMap::Close(bool DoClose) +{ + if (Fd.IsOpen() == false) + return true; + + Sync(); + + if (munmap((char *)Base,iSize) != 0) + _error->Warning("Unable to munmap"); + + iSize = 0; + if (DoClose == true) + Fd.Close(); + return true; +} + /*}}}*/ +// MMap::Sync - Syncronize the map with the disk /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool MMap::Sync() +{ + if ((Flags & ReadOnly) == ReadOnly) + if (msync((char *)Base,iSize,MS_SYNC) != 0) + return _error->Error("msync","Unable to write mmap"); + return true; +} + /*}}}*/ +// MMap::Sync - Syncronize a section of the file to disk /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool MMap::Sync(unsigned long Start,unsigned long Stop) +{ + if ((Flags & ReadOnly) == ReadOnly) + if (msync((char *)Base+(int)(Start/PAGE_SIZE)*PAGE_SIZE,Stop - Start,MS_SYNC) != 0) + return _error->Error("msync","Unable to write mmap"); + return true; +} + /*}}}*/ + +// DynamicMMap::DynamicMMap - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +DynamicMMap::DynamicMMap(File &F,unsigned long Flags,unsigned long WorkSpace) : + MMap(F,Flags | NoImmMap), WorkSpace(WorkSpace) +{ + unsigned long EndOfFile = Fd.Size(); + Fd.Seek(WorkSpace); + char C = 0; + Fd.Write(&C,sizeof(C)); + Map(); + iSize = EndOfFile; +} + /*}}}*/ +// DynamicMMap::~DynamicMMap - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* We truncate the file to the size of the memory data set */ +DynamicMMap::~DynamicMMap() +{ + unsigned long EndOfFile = iSize; + Close(false); + ftruncate(Fd.Fd(),EndOfFile); + Fd.Close(); +} + /*}}}*/ +// DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/ +// --------------------------------------------------------------------- +/* */ +unsigned long DynamicMMap::RawAllocate(unsigned long Size) +{ + unsigned long Result = iSize; + iSize += Size; + + // Just in case error check + if (Result > WorkSpace) + { + _error->Error("Dynamic MMap ran out of room"); + return 0; + } + + return Result; +} + /*}}}*/ +// DynamicMMap::Allocate - Pooled aligned allocation /*{{{*/ +// --------------------------------------------------------------------- +/* This allocates an Item of size ItemSize so that it is aligned to its + size in the file. */ +unsigned long DynamicMMap::Allocate(unsigned long ItemSize) +{ + // Look for a matching pool entry + Pool *I; + Pool *Empty = 0; + for (I = Pools; I != Pools + PoolCount; I++) + { + if (I->ItemSize == 0) + Empty = I; + if (I->ItemSize == ItemSize) + break; + } + + // No pool is allocated, use an unallocated one + if (I == Pools + PoolCount) + { + // Woops, we ran out, the calling code should allocate more. + if (Empty == 0) + { + _error->Error("Ran out of allocation pools"); + return 0; + } + + I = Empty; + I->ItemSize = ItemSize; + I->Count = 0; + } + + // Out of space, allocate some more + if (I->Count == 0) + { + I->Count = 20*1024/ItemSize; + I->Start = RawAllocate(I->Count*ItemSize); + } + + I->Count--; + unsigned long Result = I->Start; + I->Start += ItemSize; + return Result/ItemSize; +} + /*}}}*/ +// DynamicMMap::WriteString - Write a string to the file /*{{{*/ +// --------------------------------------------------------------------- +/* Strings are not aligned to anything */ +unsigned long DynamicMMap::WriteString(const char *String, + unsigned long Len) +{ + unsigned long Result = iSize; + // Just in case error check + if (Result > WorkSpace) + { + _error->Error("Dynamic MMap ran out of room"); + return 0; + } + + if (Len == 0) + Len = strlen(String); + iSize += Len + 1; + memcpy((char *)Base + Result,String,Len); + ((char *)Base)[Result + Len] = 0; + return Result; +} + /*}}}*/ diff --git a/apt-pkg/contrib/mmap.h b/apt-pkg/contrib/mmap.h new file mode 100644 index 000000000..096304177 --- /dev/null +++ b/apt-pkg/contrib/mmap.h @@ -0,0 +1,92 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: mmap.h,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + MMap Class - Provides 'real' mmap or a faked mmap using read(). + + The purpose of this code is to provide a generic way for clients to + access the mmap function. In enviroments that do not support mmap + from file fd's this function will use read and normal allocated + memory. + + Writing to a public mmap will always fully comit all changes when the + class is deleted. Ie it will rewrite the file, unless it is readonly + + The DynamicMMap class is used to help the on-disk data structure + generators. It provides a large allocated workspace and members + to allocate space from the workspace in an effecient fashion. + + This source is placed in the Public Domain, do with it what you will + It was originally written by Jason Gunthorpe. + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_MMAP_H +#define PKGLIB_MMAP_H + +#include +#include + +class MMap +{ + protected: + + File &Fd; + unsigned long Flags; + unsigned long iSize; + void *Base; + + bool Map(); + bool Close(bool DoClose = true); + + public: + + enum OpenFlags {NoImmMap = (1<<0),Public = (1<<1),ReadOnly = (1<<2)}; + + // Simple accessors + inline operator void *() {return Base;}; + inline void *Data() {return Base;}; + inline unsigned long Size() {return iSize;}; + + // File manipulators + bool Sync(); + bool Sync(unsigned long Start,unsigned long Stop); + + MMap(File &F,unsigned long Flags); + virtual ~MMap(); +}; + +class DynamicMMap : public MMap +{ + public: + + // This is the allocation pool structure + struct Pool + { + unsigned long ItemSize; + unsigned long Start; + unsigned long Count; + }; + + protected: + + unsigned long WorkSpace; + Pool *Pools; + unsigned int PoolCount; + + public: + + // Allocation + unsigned long RawAllocate(unsigned long Size); + unsigned long Allocate(unsigned long ItemSize); + unsigned long WriteString(const char *String,unsigned long Len = 0); + inline unsigned long WriteString(string S) {return WriteString(S.begin(),S.size());}; + void UsePools(Pool &P,unsigned int Count) {Pools = &P; PoolCount = Count;}; + + DynamicMMap(File &F,unsigned long Flags,unsigned long WorkSpace = 1024*1024); + virtual ~DynamicMMap(); +}; + +#endif diff --git a/apt-pkg/contrib/system.h b/apt-pkg/contrib/system.h new file mode 100644 index 000000000..e652348b0 --- /dev/null +++ b/apt-pkg/contrib/system.h @@ -0,0 +1,57 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: system.h,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + System Header - Usefull private definitions + + This source is placed in the Public Domain, do with it what you will + It was originally written by Brian C. White. + + ##################################################################### */ + /*}}}*/ +// Private header +// Header section: / +#ifndef SYSTEM_H +#define SYSTEM_H + +// MIN_VAL(SINT16) will return -0x8000 and MAX_VAL(SINT16) = 0x7FFF +#define MIN_VAL(t) (((t)(-1) > 0) ? (t)( 0) : (t)(((1L<<(sizeof(t)*8-1)) ))) +#define MAX_VAL(t) (((t)(-1) > 0) ? (t)(-1) : (t)(((1L<<(sizeof(t)*8-1))-1))) + +// Min/Max functions +#if defined(__HIGHC__) +#define MIN(x,y) _min(x,y) +#define MAX(x,y) _max(x,y) +#endif + +// GNU C++ has a min/max operator +#if defined(__GNUG__) +#define MIN(A,B) ((A) ? (B)) +#endif + +/* Templates tend to mess up existing code that uses min/max because of the + strict matching requirements */ +#if !defined(MIN) +#define MIN(A,B) ((A) < (B)?(A):(B)) +#define MAX(A,B) ((A) > (B)?(A):(B)) +#endif + +/* Bound functions, bound will return the value b within the limits a-c + bounv will change b so that it is within the limits of a-c. */ +#define _bound(a,b,c) MIN(c,MAX(b,a)) +#define _boundv(a,b,c) b = _bound(a,b,c) +#define ABS(a) (((a) < (0)) ?-(a) : (a)) + +/* Usefull count macro, use on an array of things and it will return the + number of items in the array */ +#define _count(a) (sizeof(a)/sizeof(a[0])) + +// Flag Macros +#define FLAG(f) (1L << (f)) +#define SETFLAG(v,f) ((v) |= FLAG(f)) +#define CLRFLAG(v,f) ((v) &=~FLAG(f)) +#define CHKFLAG(v,f) ((v) & FLAG(f) ? true : false) + +#endif diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc new file mode 100644 index 000000000..b75fe6d94 --- /dev/null +++ b/apt-pkg/pkgcache.cc @@ -0,0 +1,360 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgcache.cc,v 1.1 1998/07/02 02:58:12 jgg Exp $ +/* ###################################################################### + + Package Cache - Accessor code for the cache + + Please see doc/pkglib/cache.sgml for a more detailed description of + this format. Also be sure to keep that file up-to-date!! + + This is the general utility functions for cache managment. They provide + a complete set of accessor functions for the cache. The cacheiterators + header contains the STL-like iterators that can be used to easially + navigate the cache as well as seemlessly dereference the mmap'd + indexes. Use these always. + + The main class provides for ways to get package indexes and some + general lookup functions to start the iterators. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include +#include +#include +#include + +#include +#include +#include + /*}}}*/ + +// Cache::Header::Header - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* Simply initialize the header */ +pkgCache::Header::Header() +{ + Signature = 0x98FE76DC; + + /* Whenever the structures change the major version should be bumped, + whenever the generator changes the minor version should be bumped. */ + MajorVersion = 2; + MinorVersion = 0; + Dirty = true; + + HeaderSz = sizeof(pkgCache::Header); + PackageSz = sizeof(pkgCache::Package); + PackageFileSz = sizeof(pkgCache::PackageFile); + VersionSz = sizeof(pkgCache::Version); + DependencySz = sizeof(pkgCache::Dependency); + ProvidesSz = sizeof(pkgCache::Provides); + + PackageCount = 0; + VersionCount = 0; + DependsCount = 0; + PackageFileCount = 0; + + FileList = 0; + StringList = 0; + memset(HashTable,0,sizeof(HashTable)); + memset(Pools,0,sizeof(Pools)); +} + /*}}}*/ +// Cache::Header::CheckSizes - Check if the two headers have same *sz /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgCache::Header::CheckSizes(Header &Against) const +{ + if (HeaderSz == Against.HeaderSz && + PackageSz == Against.PackageSz && + PackageFileSz == Against.PackageFileSz && + VersionSz == Against.VersionSz && + DependencySz == Against.DependencySz && + ProvidesSz == Against.ProvidesSz) + return true; + return false; +} + /*}}}*/ + +// Cache::pkgCache - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgCache::pkgCache(MMap &Map) : Map(Map) +{ + ReMap(); +} + /*}}}*/ +// Cache::ReMap - Reopen the cache file /*{{{*/ +// --------------------------------------------------------------------- +/* If the file is already closed then this will open it open it. */ +bool pkgCache::ReMap() +{ + // Apply the typecasts. + HeaderP = (Header *)Map.Data(); + PkgP = (Package *)Map.Data(); + PkgFileP = (PackageFile *)Map.Data(); + VerP = (Version *)Map.Data(); + ProvideP = (Provides *)Map.Data(); + DepP = (Dependency *)Map.Data(); + StringItemP = (StringItem *)Map.Data(); + StrP = (char *)Map.Data(); + + cout << "Size is " << Map.Size() << endl; + if (Map.Size() == 0) + return false; + + // Check the header + Header DefHeader; + if (HeaderP->Signature != DefHeader.Signature || + HeaderP->Dirty == true) + return _error->Error("The package cache file is corrupted"); + + if (HeaderP->MajorVersion != DefHeader.MajorVersion || + HeaderP->MinorVersion != DefHeader.MinorVersion || + HeaderP->CheckSizes(DefHeader) == false) + return _error->Error("The package cache file is an incompatible version"); + + return true; +} + /*}}}*/ +// Cache::Hash - Hash a string /*{{{*/ +// --------------------------------------------------------------------- +/* This is used to generate the hash entries for the HashTable. With my + package list from bo this function gets 94% table usage on a 512 item + table (480 used items) */ +unsigned long pkgCache::sHash(string Str) +{ + unsigned long Hash = 0; + for (const char *I = Str.begin(); I != Str.end(); I++) + Hash += *I * ((Str.end() - I + 1)); + Header H; + return Hash % _count(H.HashTable); +} + +unsigned long pkgCache::sHash(const char *Str) +{ + unsigned long Hash = 0; + const char *End = Str + strlen(Str); + for (const char *I = Str; I != End; I++) + Hash += *I * ((End - I + 1)); + Header H; + return Hash % _count(H.HashTable); +} + + /*}}}*/ +// Cache::FindPkg - Locate a package by name /*{{{*/ +// --------------------------------------------------------------------- +/* Returns 0 on error, pointer to the package otherwise */ +pkgCache::PkgIterator pkgCache::FindPkg(string Name) +{ + // Look at the hash bucket + Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)]; + for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage) + { + if (Pkg->Name != 0 && StrP + Pkg->Name == Name) + return PkgIterator(*this,Pkg); + } + return PkgIterator(*this,0); +} + /*}}}*/ + +// Cache::PkgIterator - operator ++ - Postfix incr /*{{{*/ +// --------------------------------------------------------------------- +/* This will advance to the next logical package in the hash table. */ +void pkgCache::PkgIterator::operator ++(int) +{ + // Follow the current links + if (Pkg != Owner->PkgP) + Pkg = Owner->PkgP + Pkg->NextPackage; + + // Follow the hash table + while (Pkg == Owner->PkgP && HashIndex < (signed)_count(Owner->HeaderP->HashTable)) + { + HashIndex++; + Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex]; + } +}; + /*}}}*/ +// Bases for iterator classes /*{{{*/ +void pkgCache::VerIterator::_dummy() {} +void pkgCache::DepIterator::_dummy() {} +void pkgCache::PrvIterator::_dummy() {} + /*}}}*/ +// PkgIterator::State - Check the State of the package /*{{{*/ +// --------------------------------------------------------------------- +/* By this we mean if it is either cleanly installed or cleanly removed. */ +pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const +{ + if (Pkg->CurrentState == pkgSTATE_UnPacked || + Pkg->CurrentState == pkgSTATE_HalfConfigured) + return NeedsConfigure; + + if (Pkg->CurrentState == pkgSTATE_UnInstalled || + Pkg->CurrentState == pkgSTATE_HalfInstalled || + Pkg->InstState != pkgSTATE_Ok) + return NeedsUnpack; + + return NeedsNothing; +} + /*}}}*/ +// DepIterator::IsCritical - Returns true if the dep is important /*{{{*/ +// --------------------------------------------------------------------- +/* Currently critical deps are defined as depends, predepends and + conflicts. */ +bool pkgCache::DepIterator::IsCritical() +{ + if (Dep->Type == pkgDEP_Conflicts || Dep->Type == pkgDEP_Depends || + Dep->Type == pkgDEP_PreDepends) + return true; + return false; +} + /*}}}*/ +// DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides /*{{{*/ +// --------------------------------------------------------------------- +/* This intellegently looks at dep target packages and tries to figure + out which package should be used. This is needed to nicely handle + provide mapping. If the target package has no other providing packages + then it returned. Otherwise the providing list is looked at to + see if there is one one unique providing package if so it is returned. + Otherwise true is returned and the target package is set. The return + result indicates whether the node should be expandable */ +bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result) +{ + Result = TargetPkg(); + + // No provides at all + if (Result->ProvidesList == 0) + return false; + + // There is the Base package and the providing ones which is at least 2 + if (Result->VersionList != 0) + return true; + + /* We have to skip over indirect provisions of the package that + owns the dependency. For instance, if libc5-dev depends on the + virtual package libc-dev which is provided by libc5-dev and libc6-dev + we must ignore libc5-dev when considering the provides list. */ + PrvIterator PStart = Result.ProvidesList(); + for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); PStart++); + + // Nothing but indirect self provides + if (PStart.end() == true) + return false; + + // Check for single packages in the provides list + PrvIterator P = PStart; + for (; P.end() != true; P++) + { + // Skip over self provides + if (P.OwnerPkg() == ParentPkg()) + continue; + if (PStart.OwnerPkg() != P.OwnerPkg()) + break; + } + + // Check for non dups + if (P.end() != true) + return true; + Result = PStart.OwnerPkg(); + return false; +} + /*}}}*/ +// DepIterator::AllTargets - Returns the set of all possible targets /*{{{*/ +// --------------------------------------------------------------------- +/* This is a more usefull version of TargetPkg() that follows versioned + provides. It includes every possible package-version that could satisfy + the dependency. The last item in the list has a 0. */ +pkgCache::Version **pkgCache::DepIterator::AllTargets() +{ + Version **Res = 0; + unsigned long Size =0; + while (1) + { + Version **End = Res; + PkgIterator DPkg = TargetPkg(); + + // Walk along the actual package providing versions + for (VerIterator I = DPkg.VersionList(); I.end() == false; I++) + { + if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false) + continue; + + if (Dep->Type == pkgDEP_Conflicts && ParentPkg() == I.ParentPkg()) + continue; + + Size++; + if (Res != 0) + *End++ = I; + } + + // Follow all provides + for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++) + { + if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false) + continue; + + if (Dep->Type == pkgDEP_Conflicts && ParentPkg() == I.OwnerPkg()) + continue; + + Size++; + if (Res != 0) + *End++ = I.OwnerVer(); + } + + // Do it again and write it into the array + if (Res == 0) + { + Res = new Version *[Size+1]; + Size = 0; + } + else + { + *End = 0; + break; + } + } + + return Res; +} + /*}}}*/ +// VerIterator::CompareVer - Fast version compare for same pkgs /*{{{*/ +// --------------------------------------------------------------------- +/* This just looks over the version list to see if B is listed before A. In + most cases this will return in under 4 checks, ver lists are short. */ +int pkgCache::VerIterator::CompareVer(const VerIterator &B) const +{ + // Check if they are equal + if (*this == B) + return 0; + if (end() == true) + return -1; + if (B.end() == true) + return 1; + + /* Start at A and look for B. If B is found then A > B otherwise + B was before A so A < B */ + VerIterator I = *this; + for (;I.end() == false; I++) + if (I == B) + return 1; + return -1; +} + /*}}}*/ +// PkgFileIterator::IsOk - Checks if the cache is in sync with the file /*{{{*/ +// --------------------------------------------------------------------- +/* This stats the file and compares its stats with the ones that were + stored during generation. Date checks should probably also be + included here. */ +bool pkgCache::PkgFileIterator::IsOk() +{ + struct stat Buf; + if (stat(FileName(),&Buf) != 0) + return false; + + if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime) + return false; + + return true; +} + /*}}}*/ diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h new file mode 100644 index 000000000..0dc939a51 --- /dev/null +++ b/apt-pkg/pkgcache.h @@ -0,0 +1,280 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgcache.h,v 1.1 1998/07/02 02:58:12 jgg Exp $ +/* ###################################################################### + + Cache - Structure definitions for the cache file + + Please see doc/pkglib/cache.sgml for a more detailed description of + this format. Also be sure to keep that file up-to-date!! + + Clients should always use the CacheIterators classes for access to the + cache. They provide a simple STL-like method for traversing the links + of the datastructure. + + See pkgcachegen.h for information about generating cache structures. + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_PKGCACHE_H +#define PKGLIB_PKGCACHE_H + +#include +#include +#include + +// Definitions for Depends::Type +#define pkgDEP_Depends 1 +#define pkgDEP_PreDepends 2 +#define pkgDEP_Suggests 3 +#define pkgDEP_Recommends 4 +#define pkgDEP_Conflicts 5 +#define pkgDEP_Replaces 6 + +// Definitions for Version::Priority +#define pkgPRIO_Important 1 +#define pkgPRIO_Required 2 +#define pkgPRIO_Standard 3 +#define pkgPRIO_Optional 4 +#define pkgPRIO_Extra 5 + +// Definitions for Package::SelectedState +#define pkgSTATE_Unkown 0 +#define pkgSTATE_Install 1 +#define pkgSTATE_Hold 2 +#define pkgSTATE_DeInstall 3 +#define pkgSTATE_Purge 4 + +// Definitions for Package::Flags +#define pkgFLAG_Auto (1 << 0) +#define pkgFLAG_New (1 << 1) +#define pkgFLAG_Obsolete (1 << 2) +#define pkgFLAG_Essential (1 << 3) +#define pkgFLAG_ImmediateConf (1 << 4) + +// Definitions for Package::InstState +#define pkgSTATE_Ok 0 +#define pkgSTATE_ReInstReq 1 +#define pkgSTATE_Hold 2 +#define pkgSTATE_HoldReInstReq 3 + +// Definitions for Package::CurrentState +#define pkgSTATE_NotInstalled 0 +#define pkgSTATE_UnPacked 1 +#define pkgSTATE_HalfConfigured 2 +#define pkgSTATE_UnInstalled 3 +#define pkgSTATE_HalfInstalled 4 +#define pkgSTATE_ConfigFiles 5 +#define pkgSTATE_Installed 6 + +// Definitions for PackageFile::Flags +#define pkgFLAG_NotSource (1 << 0) + +// Definitions for Dependency::CompareOp +#define pkgOP_OR 0x10 +#define pkgOP_LESSEQ 0x1 +#define pkgOP_GREATEREQ 0x2 +#define pkgOP_LESS 0x3 +#define pkgOP_GREATER 0x4 +#define pkgOP_EQUALS 0x5 +#define pkgOP_NOTEQUALS 0x6 + +class pkgCache +{ + public: + // Cache element predeclarations + struct Header; + struct Package; + struct PackageFile; + struct Version; + struct Provides; + struct Dependency; + struct StringItem; + + // Iterators + class PkgIterator; + class VerIterator; + class DepIterator; + class PrvIterator; + class PkgFileIterator; + friend PkgIterator; + friend VerIterator; + friend DepIterator; + friend PrvIterator; + friend PkgFileIterator; + + protected: + + // Memory mapped cache file + string CacheFile; + MMap ⤅ + + bool Public; + bool ReadOnly; + + static unsigned long sHash(string S); + static unsigned long sHash(const char *S); + + public: + + // Pointers to the arrays of items + Header *HeaderP; + Package *PkgP; + PackageFile *PkgFileP; + Version *VerP; + Provides *ProvideP; + Dependency *DepP; + StringItem *StringItemP; + char *StrP; + + virtual bool ReMap(); + inline bool Sync() {return Map.Sync();}; + + // String hashing function (512 range) + inline unsigned long Hash(string S) const {return sHash(S);}; + inline unsigned long Hash(const char *S) const {return sHash(S);}; + + // Accessors + PkgIterator FindPkg(string Name); + Header &Head() {return *HeaderP;}; + inline PkgIterator PkgBegin(); + inline PkgIterator PkgEnd(); + + pkgCache(MMap &Map); + virtual ~pkgCache() {}; +}; + +// Header structure +struct pkgCache::Header +{ + // Signature information + unsigned long Signature; + short MajorVersion; + short MinorVersion; + bool Dirty; + + // Size of structure values + unsigned short HeaderSz; + unsigned short PackageSz; + unsigned short PackageFileSz; + unsigned short VersionSz; + unsigned short DependencySz; + unsigned short ProvidesSz; + + // Structure counts + unsigned long PackageCount; + unsigned long VersionCount; + unsigned long DependsCount; + unsigned long PackageFileCount; + + // Offsets + unsigned long FileList; // struct PackageFile + unsigned long StringList; // struct StringItem + + /* Allocation pools, there should be one of these for each structure + excluding the header */ + DynamicMMap::Pool Pools[6]; + + // Rapid package name lookup + unsigned long HashTable[512]; + + bool CheckSizes(Header &Against) const; + Header(); +}; + +struct pkgCache::Package +{ + // Pointers + unsigned long Name; // Stringtable + unsigned long VersionList; // Version + unsigned long TargetVer; // Version + unsigned long CurrentVer; // Version + unsigned long TargetDist; // StringTable (StringItem) + unsigned long Section; // StringTable (StringItem) + + // Linked list + unsigned long NextPackage; // Package + unsigned long RevDepends; // Dependency + unsigned long ProvidesList; // Provides + + // Install/Remove/Purge etc + unsigned char SelectedState; // What + unsigned char InstState; // Flags + unsigned char CurrentState; // State + + unsigned short ID; + unsigned short Flags; +}; + +struct pkgCache::PackageFile +{ + // Names + unsigned long FileName; // Stringtable + unsigned long Version; // Stringtable + unsigned long Distribution; // Stringtable + unsigned long Size; + + // Linked list + unsigned long NextFile; // PackageFile + unsigned short ID; + unsigned short Flags; + time_t mtime; // Modification time for the file +}; + +struct pkgCache::Version +{ + unsigned long VerStr; // Stringtable + unsigned long File; // PackageFile + unsigned long Section; // StringTable (StringItem) + + // Lists + unsigned long NextVer; // Version + unsigned long DependsList; // Dependency + unsigned long ParentPkg; // Package + unsigned long ProvidesList; // Provides + + unsigned long Offset; + unsigned long Size; + unsigned long InstalledSize; + unsigned short ID; + unsigned char Priority; +}; + +struct pkgCache::Dependency +{ + unsigned long Version; // Stringtable + unsigned long Package; // Package + unsigned long NextDepends; // Dependency + unsigned long NextRevDepends; // Dependency + unsigned long ParentVer; // Version + + // Specific types of depends + unsigned char Type; + unsigned char CompareOp; + unsigned short ID; +}; + +struct pkgCache::Provides +{ + unsigned long ParentPkg; // Pacakge + unsigned long Version; // Version + unsigned long ProvideVersion; // Stringtable + unsigned long NextProvides; // Provides + unsigned long NextPkgProv; // Provides +}; + +struct pkgCache::StringItem +{ + unsigned long String; // Stringtable + unsigned long NextItem; // StringItem +}; + +#include + +inline pkgCache::PkgIterator pkgCache::PkgBegin() + {return PkgIterator(*this);}; +inline pkgCache::PkgIterator pkgCache::PkgEnd() + {return PkgIterator(*this,PkgP);}; + +#endif diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc new file mode 100644 index 000000000..cb0fd3f74 --- /dev/null +++ b/apt-pkg/pkgcachegen.cc @@ -0,0 +1,184 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgcachegen.cc,v 1.1 1998/07/02 02:58:12 jgg Exp $ +/* ###################################################################### + + Package Cache Generator - Generator for the cache structure. + + This builds the cache structure from the abstract package list parser. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include +#include +#include + +#include +#include + /*}}}*/ + +// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* We set the diry flag and make sure that is written to the disk */ +pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map) : Map(Map), Cache(Map) +{ + if (_error->PendingError() == true) + return; + + if (Map.Size() == 0) + { + Map.RawAllocate(sizeof(pkgCache::Header)); + *Cache.HeaderP = pkgCache::Header(); + } + Cache.HeaderP->Dirty = true; + Map.Sync(0,sizeof(pkgCache::Header)); + Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0])); +} + /*}}}*/ +// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* We sync the data then unset the dirty flag in two steps so as to + advoid a problem during a crash */ +pkgCacheGenerator::~pkgCacheGenerator() +{ + if (_error->PendingError() == true) + return; + if (Map.Sync() == false) + return; + + Cache.HeaderP->Dirty = false; + Map.Sync(0,sizeof(pkgCache::Header)); +} + /*}}}*/ +// CacheGenerator::MergeList - Merge the package list /*{{{*/ +// --------------------------------------------------------------------- +/* This provides the generation of the entries in the cache. Each loop + goes through a single package record from the underlying parse engine. */ +bool pkgCacheGenerator::MergeList(ListParser &List) +{ + List.Owner = this; + + do + { + // Get a pointer to the package structure + string Package = List.Package(); + pkgCache::PkgIterator Pkg = Cache.FindPkg(Package); + if (Pkg.end() == false) + { + if (NewPackage(Pkg,Package) == false) + return false; + + if (List.NewPackage(Pkg) == false) + return false; + } + if (List.UsePackage(Pkg) == false) + return false; + + /* Get a pointer to the version structure. We know the list is sorted + so we use that fact in the search. Insertion of new versions is + done with correct sorting */ + string Version = List.Version(); + pkgCache::VerIterator Ver = Pkg.VersionList(); + unsigned long *Last = &Pkg->VersionList; + int Res; + for (; Ver.end() == false; Ver++, Last = &Ver->NextVer) + { + Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(), + Ver.VerStr() + strlen(Ver.VerStr())); + if (Res >= 0) + break; + } + + /* We already have a version for this item, record that we + saw it */ + if (Res == 0) + { + if (NewFileVer(Ver,List) == false) + return false; + + continue; + } + + // Add a new version + *Last = NewVersion(Ver,*Last); + if (List.NewVersion(Ver) == false) + return false; + + if (NewFileVer(Ver,List) == false) + return false; + } + while (List.Step() == true); + + return true; +} + /*}}}*/ +// CacheGenerator::NewPackage - Add a new package /*{{{*/ +// --------------------------------------------------------------------- +/* This creates a new package structure and adds it to the hash table */ +bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator Pkg,string Name) +{ + // Get a structure + unsigned long Package = Map.Allocate(sizeof(pkgCache::Package)); + if (Package == 0) + return false; + + Pkg = pkgCache::PkgIterator(Cache,Cache.PackageP + Package); + + // Insert it into the hash table + unsigned long Hash = Map.Hash(Name); + Pkg->NextPackage = Cache.HeaderP->HashTable[Hash]; + Cache.HeaderP->HashTable[Hash] = Package; + + // Set the name and the ID + Pkg->Name = Map.WriteString(Name); + if (Pkg->Name == 0) + return false; + Pkg->ID = Cache.HeaderP->PackageCount++; + + return true; +} + /*}}}*/ +// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator Ver, + ListParser &List) +{ +} + /*}}}*/ +// CacheGenerator::NewVersion - Create a new Version /*{{{*/ +// --------------------------------------------------------------------- +/* */ +unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver, + unsigned long Next) +{ +} + /*}}}*/ +// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/ +// --------------------------------------------------------------------- +/* This is used to select which file is to be associated with all newly + added versions. */ +bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags) +{ + struct stat Buf; + if (stat(File.c_str(),&Buf) == -1) + return _error->Errno("stat","Couldn't stat ",File.c_str()); + + // Get some space for the structure + CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile)); + if (CurrentFile == Cache.PkgFileP) + return false; + + // Fill it in + CurrentFile->FileName = Map.WriteString(File); + CurrentFile->Size = Buf.st_size; + CurrentFile->mtime = Buf.st_mtime; + CurrentFile->NextFile = Cache.HeaderP->FileList; + CurrentFile->Flags = Flags; + PkgFileName = File; + + if (CurrentFile->FileName == 0) + return false; +} + /*}}}*/ diff --git a/apt-pkg/pkgcachegen.h b/apt-pkg/pkgcachegen.h new file mode 100644 index 000000000..1385ab964 --- /dev/null +++ b/apt-pkg/pkgcachegen.h @@ -0,0 +1,69 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: pkgcachegen.h,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + Package Cache Generator - Generator for the cache structure. + + This builds the cache structure from the abstract package list parser. + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_PKGCACHEGEN_H +#define PKGLIB_PKGCACHEGEN_H + +#include + +class pkgCacheGenerator +{ + public: + + class ListParser; + + protected: + + DynamicMMap ⤅ + pkgCache Cache; + + string PkgFileName; + pkgCache::PackageFile *CurrentFile; + + bool NewPackage(pkgCache::PkgIterator Pkg,string Pkg); + bool NewFileVer(pkgCache::VerIterator Ver,ListParser &List); + unsigned long NewVersion(pkgCache::VerIterator &Ver,unsigned long Next); + + public: + + // This is the abstract package list parser class. + class ListParser + { + pkgCacheGenerator *Owner; + friend pkgCacheGenerator; + + protected: + + inline unsigned long WriteString(string S) {return Owner->Map.WriteString(S);}; + inline unsigned long WriteString(const char *S,unsigned int Size) {return Owner->Map.WriteString(S,Size);}; + + public: + + // These all operate against the current section + virtual string Package() = 0; + virtual string Version() = 0; + virtual bool NewVersion(pkgCache::VerIterator Ver) = 0; + virtual bool NewPackage(pkgCache::PkgIterator Pkg) = 0; + virtual bool UsePackage(pkgCache::PkgIterator Pkg) = 0; + + virtual bool Step() = 0; + }; + friend ListParser; + + bool SelectFile(string File,unsigned long Flags = 0); + bool MergeList(ListParser &List); + + pkgCacheGenerator(DynamicMMap &Map); + ~pkgCacheGenerator(); +}; + +#endif diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc new file mode 100644 index 000000000..106b0febe --- /dev/null +++ b/apt-pkg/tagfile.cc @@ -0,0 +1,195 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: tagfile.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + Fast scanner for RFC-822 type header information + + This uses a rotating 64K buffer to load the package information into. + The scanner runs over it and isolates and indexes a single section. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include +#include + +#include +#include + /*}}}*/ + +// TagFile::pkgTagFile - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgTagFile::pkgTagFile(File &Fd) : Fd(Fd) +{ + Buffer = new char[64*1024]; + Start = End = Buffer + 64*1024; + Left = Fd.Size(); + Fill(); +} + /*}}}*/ +// TagFile::Step - Advance to the next section /*{{{*/ +// --------------------------------------------------------------------- +/* If the Section Scanner fails we refill the buffer and try again. */ +bool pkgTagFile::Step(pkgTagSection &Tag) +{ + if (Tag.Scan(Start,End - Start) == false) + { + if (Fill() == false) + return false; + + if (Tag.Scan(Start,End - Start) == false) + return _error->Error("Unable to parse package file"); + } + Start += Tag.Length(); + return true; +} + /*}}}*/ +// TagFile::Fill - Top up the buffer /*{{{*/ +// --------------------------------------------------------------------- +/* This takes the bit at the end of the buffer and puts it at the start + then fills the rest from the file */ +bool pkgTagFile::Fill() +{ + unsigned long Size = End - Start; + + if (Left == 0) + { + if (Size <= 1) + return false; + return true; + } + + memmove(Buffer,Start,Size); + Start = Buffer; + + // See if only a bit of the file is left or if + if (Left < End - Buffer - Size) + { + if (Fd.Read(Buffer + Size,Left) == false) + return false; + End = Buffer + Size + Left; + Left = 0; + } + else + { + if (Fd.Read(Buffer + Size, End - Buffer - Size) == false) + return false; + Left -= End - Buffer - Size; + } + return true; +} + /*}}}*/ +// TagSection::Scan - Scan for the end of the header information /*{{{*/ +// --------------------------------------------------------------------- +/* This looks for the first double new line in the data stream. It also + indexes the tags in the section. */ +bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength) +{ + const char *End = Start + MaxLength; + Stop = Section = Start; + + TagCount = 0; + Indexes[TagCount++] = Stop - Section; + Stop++; + for (; Stop < End; Stop++) + { + if (Stop[-1] != '\n') + continue; + if (Stop[0] == '\n') + { + // Extra one at the end to simplify find + Indexes[TagCount] = Stop - Section; + for (; Stop[0] == '\n' && Stop < End; Stop++); + return true; + break; + } + + if (isspace(Stop[0]) == 0) + Indexes[TagCount++] = Stop - Section; + + // Just in case. + if (TagCount > sizeof(Indexes)/sizeof(Indexes[0])) + TagCount = sizeof(Indexes)/sizeof(Indexes[0]); + } + return false; +} + /*}}}*/ +// TagSection::Find - Locate a tag /*{{{*/ +// --------------------------------------------------------------------- +/* This searches the section for a tag that matches the given string. */ +bool pkgTagSection::Find(const char *Tag,const char *&Start, + const char *&End) +{ + unsigned int Length = strlen(Tag); + for (unsigned int I = 0; I != TagCount; I++) + { + if (strncasecmp(Tag,Section + Indexes[I],Length) != 0) + continue; + + // Make sure the colon is in the right place + const char *C = Section + Length + Indexes[I]; + for (; isspace(*C) != 0; C++); + if (*C != ':') + continue; + + // Strip off the gunk from the start end + Start = C; + End = Section + Indexes[I+1]; + for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++); + for (; isspace(End[-1]) != 0 && End > Start; End--); + return true; + } + Start = End = 0; + return false; +} + /*}}}*/ + +#include + +int main(int argc,char *argv[]) +{ + { + File F(argv[1],File::ReadOnly); + pkgTagFile Test(F); + File CacheF("./cache",File::WriteEmpty); + DynamicMMap Map(CacheF,MMap::Public); + pkgCacheGenerator Gen(Map); + Gen.SelectFile("tet"); + } + +#if 0 + pkgTagSection I; + while (Test.Step(I) == true) + { + const char *Start; + const char *End; + if (I.Find("Package",Start,End) == false) + { + cout << "Failed" << endl; + continue; + } + + cout << "Package: " << string(Start,End - Start) << endl; + +/* for (const char *I = Start; I < End; I++) + { + const char *Begin = I; + bool Number = true; + while (isspace(*I) == 0 && ispunct(*I) == 0 && I < End) + { + if (isalpha(*I) != 0) + Number = false; + I++; + } + if (Number == false) + cout << string(Begin,I-Begin) << endl; + while ((isspace(*I) != 0 || ispunct(*I) != 0) && I < End) + I++; + I--; + } */ + } +#endif + _error->DumpErrors(); +} diff --git a/apt-pkg/tagfile.h b/apt-pkg/tagfile.h new file mode 100644 index 000000000..a7a82dd1c --- /dev/null +++ b/apt-pkg/tagfile.h @@ -0,0 +1,64 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: tagfile.h,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + Fast scanner for RFC-822 type header information + + This parser handles Debian package files (and others). Their form is + RFC-822 type header fields in groups seperated by a blank line. + + The parser reads the and provides methods to step linearly + over it or to jump to a pre-recorded start point and read that record. + + A second class is used to perform pre-parsing of the record. It works + by indexing the start of each header field and providing lookup + functions for header fields. + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_TAGFILE_H +#define PKGLIB_TAGFILE_H + +#include + +class pkgTagSection +{ + const char *Section; + const char *Stop; + + // We have a limit of 256 tags per section. + unsigned short Indexes[256]; + unsigned int TagCount; + + public: + + inline bool operator ==(const pkgTagSection &rhs) {return Section == rhs.Section;}; + inline bool operator !=(const pkgTagSection &rhs) {return Section != rhs.Section;}; + + bool Find(const char *Tag,const char *&Start, const char *&End); + bool Scan(const char *Start,unsigned long MaxLength); + inline unsigned long Length() {return Stop - Section;}; + + pkgTagSection() : Section(0), Stop(0) {}; +}; + +class pkgTagFile +{ + File Fd; + char *Buffer; + char *Start; + char *End; + unsigned long Left; + + bool Fill(); + + public: + + bool Step(pkgTagSection &Section); + + pkgTagFile(File &F); +}; + +#endif diff --git a/apt-pkg/version.cc b/apt-pkg/version.cc new file mode 100644 index 000000000..c02ee5f87 --- /dev/null +++ b/apt-pkg/version.cc @@ -0,0 +1,249 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: version.cc,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + Version - Version string + + Version comparing is done using the == and < operators. STL's + function.h provides the remaining set of comparitors. A directly + callable non-string class version is provided for functions manipulating + the cache file (esp the sort function). + + A version is defined to be equal if a case sensitive compare returns + that the two strings are the same. For compatibility with the QSort + function this version returns -1,0,1. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include +#include + +#include + /*}}}*/ + +// Version::pkgVersion - Default Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +pkgVersion::pkgVersion() +{ +} + /*}}}*/ +// Version::operator == - Checks if two versions are equal /*{{{*/ +// --------------------------------------------------------------------- +/* We can't simply perform a string compare because of epochs. */ +bool pkgVersion::operator ==(const pkgVersion &Vrhs) const +{ + if (pkgVersionCompare(Value.begin(),Value.end(), + Vrhs.Value.begin(),Vrhs.Value.end()) == 0) + return true; + return false; +} + /*}}}*/ +// Version::operator < - Checks if this is less than another version /*{{{*/ +// --------------------------------------------------------------------- +/* All other forms of comparision can be built up from this single function. + a > b -> b < a + a <= b -> !(a > b) -> !(b < a) + a >= b -> !(a < b) + */ +bool pkgVersion::operator <(const pkgVersion &Vrhs) const +{ + if (pkgVersionCompare(Value.begin(),Value.end(), + Vrhs.Value.begin(),Vrhs.Value.end()) == -1) + return true; + return false; +} + /*}}}*/ +// StrToLong - Convert the string between two iterators to a long /*{{{*/ +// --------------------------------------------------------------------- +/* */ +static unsigned long StrToLong(const char *begin,const char *end) +{ + char S[40]; + char *I = S; + for (; begin != end && I < S + 40;) + *I++ = *begin++; + *I = 0; + return strtoul(S,0,10); +} + /*}}}*/ +// VersionCompare (op) - Greater than comparison for versions /*{{{*/ +// --------------------------------------------------------------------- +/* */ +int pkgVersionCompare(const char *A, const char *B) +{ + return pkgVersionCompare(A,A + strlen(A),B,B + strlen(B)); +} +int pkgVersionCompare(string A,string B) +{ + return pkgVersionCompare(A.begin(),A.end(),B.begin(),B.end()); +} + + /*}}}*/ +// VersionCompare - Greater than comparison for versions /*{{{*/ +// --------------------------------------------------------------------- +/* */ +int pkgVersionCompare(const char *A, const char *AEnd, const char *B, + const char *BEnd) +{ + // lhs = left hand side, rhs = right hand side + const char *lhs = A; + const char *rhs = B; + + /* Consider epochs. They need special handling because an epoch + must not be compared against the first element of the real version. + This works okay when both sides have an epoch but when only one + does it must compare the missing epoch to 0 */ + for (;lhs != AEnd && *lhs != ':'; lhs++); + for (;rhs != BEnd && *rhs != ':'; rhs++); + + // Parse the epoch out + unsigned long lhsEpoch = 0; + unsigned long rhsEpoch = 0; + if (lhs != AEnd && *lhs == ':') + lhsEpoch = StrToLong(A,lhs); + if (rhs != BEnd && *rhs == ':') + rhsEpoch = StrToLong(B,rhs); + if (lhsEpoch != rhsEpoch) + { + if (lhsEpoch > rhsEpoch) + return 1; + return -1; + } + + /* Iterate over the whole string + What this does is to spilt the whole string into groups of + numeric and non numeric portions. For instance: + a67bhgs89 + Has 4 portions 'a', '67', 'bhgs', '89'. A more normal: + 2.7.2-linux-1 + Has '2', '.', '7', '.' ,'-linux-','1' */ + lhs = A; + rhs = B; + while (lhs != AEnd && rhs != BEnd) + { + // Starting points + const char *Slhs = lhs; + const char *Srhs = rhs; + + // Compute ending points were we have passed over the portion + bool Digit = (isdigit(*lhs) > 0?true:false); + for (;lhs != AEnd && (isdigit(*lhs) > 0?true:false) == Digit; lhs++); + for (;rhs != BEnd && (isdigit(*rhs) > 0?true:false) == Digit; rhs++); + + if (Digit == true) + { + // If the lhs has a digit and the rhs does not then true + if (rhs - Srhs == 0) + return -1; + + // Generate integers from the strings. + unsigned long Ilhs = StrToLong(Slhs,lhs); + unsigned long Irhs = StrToLong(Srhs,rhs); + if (Ilhs != Irhs) + { + if (Ilhs > Irhs) + return 1; + return -1; + } + } + else + { + // They are equal length so do a straight text compare + for (;Slhs != lhs && Srhs != rhs; Slhs++, Srhs++) + { + if (*Slhs != *Srhs) + { + /* We need to compare non alpha chars as higher than alpha + chars (a < !) This is so things like 7.6p2-4 and 7.6-0 + compare higher as well as . and -. I am not sure how + the dpkg code manages to achive the != '-' test, but it + is necessary. */ + int lc = *Slhs; + int rc = *Srhs; + if (isalpha(lc) == 0 && lc != '-') lc += 256; + if (isalpha(rc) == 0 && rc != '-') rc += 256; + if (lc > rc) + return 1; + return -1; + } + } + + // If the lhs is shorter than the right it is 'less' + if (lhs - Slhs < rhs - Srhs) + return -1; + + // If the lhs is longer than the right it is 'more' + if (lhs - Slhs > rhs - Srhs) + return 1; + } + } + + // The strings must be equal + if (lhs == AEnd && rhs == BEnd) + return 0; + + // lhs is shorter + if (lhs == AEnd) + return -1; + + // rhs is shorter + if (rhs == BEnd) + return 1; + + // Shouldnt happen + return 1; +} + /*}}}*/ +// CheckDep - Check a single dependency /*{{{*/ +// --------------------------------------------------------------------- +/* This simply preforms the version comparison and switch based on + operator. */ +bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op) +{ + if (DepVer == 0) + return true; + if (PkgVer == 0) + return false; + + // Perform the actuall comparision. + int Res = pkgVersionCompare(PkgVer,DepVer); + switch (Op & 0x0F) + { + case pkgOP_LESSEQ: + if (Res <= 0) + return true; + break; + + case pkgOP_GREATEREQ: + if (Res >= 0) + return true; + break; + + case pkgOP_LESS: + if (Res < 0) + return true; + break; + + case pkgOP_GREATER: + if (Res > 0) + return true; + break; + + case pkgOP_EQUALS: + if (Res == 0) + return true; + break; + + case pkgOP_NOTEQUALS: + if (Res != 0) + return true; + break; + } + + return false; +} + /*}}}*/ + diff --git a/apt-pkg/version.h b/apt-pkg/version.h new file mode 100644 index 000000000..a30246946 --- /dev/null +++ b/apt-pkg/version.h @@ -0,0 +1,45 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: version.h,v 1.1 1998/07/02 02:58:13 jgg Exp $ +/* ###################################################################### + + Version - Version string + + This class implements storage and operators for version strings. + + The client is responsible for stripping epochs should it be desired. + + ##################################################################### */ + /*}}}*/ +// Header section: pkglib +#ifndef PKGLIB_VERSION_H +#define PKGLIB_VERSION_H + +#include + +class pkgVersion +{ + string Value; + + public: + + inline operator string () const {return Value;}; + + // Assignmnet + void operator =(string rhs) {Value = rhs;}; + + // Comparitors. STL will provide the rest + bool operator ==(const pkgVersion &rhs) const; + bool operator <(const pkgVersion &rhs) const; + + pkgVersion(); + pkgVersion(string Version) : Value(Version) {}; +}; + +int pkgVersionCompare(const char *A, const char *B); +int pkgVersionCompare(const char *A, const char *AEnd, const char *B, + const char *BEnd); +int pkgVersionCompare(string A,string B); +bool pkgCheckDep(const char *DepVer,const char *PkgVer,int Op); + +#endif -- cgit v1.2.3