Browse Source

Base revisions

Author: jgg
Date: 1998-07-02 02:58:12 GMT
Base revisions
debian/1.8.y
Arch Librarian 18 years ago
commit
578bfd0aed
  1. 281
      apt-pkg/cacheiterators.h
  2. 139
      apt-pkg/contrib/error.cc
  3. 84
      apt-pkg/contrib/error.h
  4. 214
      apt-pkg/contrib/fileutl.cc
  5. 63
      apt-pkg/contrib/fileutl.h
  6. 227
      apt-pkg/contrib/mmap.cc
  7. 92
      apt-pkg/contrib/mmap.h
  8. 57
      apt-pkg/contrib/system.h
  9. 360
      apt-pkg/pkgcache.cc
  10. 280
      apt-pkg/pkgcache.h
  11. 184
      apt-pkg/pkgcachegen.cc
  12. 69
      apt-pkg/pkgcachegen.h
  13. 195
      apt-pkg/tagfile.cc
  14. 64
      apt-pkg/tagfile.h
  15. 249
      apt-pkg/version.cc
  16. 45
      apt-pkg/version.h
  17. 199
      doc/apt-cache.8
  18. 250
      doc/apt-get.8
  19. 50
      doc/apt.8
  20. 761
      doc/cache.sgml
  21. 411
      doc/design.sgml
  22. 509
      doc/dpkg-tech.sgml
  23. 491
      doc/files.sgml
  24. 93
      doc/ftp.conf.5
  25. 548
      doc/guide.sgml
  26. 177
      doc/sources.list.5

281
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

139
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 <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <pkglib/error.h>
/*}}}*/
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;
}
}
/*}}}*/

84
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 <string>
#include <vector.h>
class GlobalError
{
struct Item
{
string Text;
bool Error;
};
vector<Item> 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

214
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 <fileutl.h>
#include <pkglib/error.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/types.h>
/*}}}*/
// 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;
}
/*}}}*/

63
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 <string>
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

227
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 <pkglib/mmap.h>
#include <pkglib/error.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/user.h>
#include <unistd.h>
#include <fcntl.h>
/*}}}*/
// 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;
}
/*}}}*/

92
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 <string>
#include <pkglib/fileutl.h>
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

57
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 <coolio>
#if defined(__GNUG__)
#define MIN(A,B) ((A) <? (B))
#define MAX(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

360
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 <pkglib/pkgcache.h>
#include <pkglib/version.h>
#include <pkglib/error.h>
#include <system.h>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
/*}}}*/
// 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;
}
/*}}}*/

280
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 <string>
#include <time.h>
#include <pkglib/mmap.h>