
commit
578bfd0aed
26 changed files with 6092 additions and 0 deletions
@ -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 |
@ -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; |
|||
} |
|||
} |
|||
/*}}}*/ |
@ -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 |
@ -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; |
|||
} |
|||
/*}}}*/ |
@ -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 |
@ -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; |
|||
} |
|||
/*}}}*/ |
@ -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 |
@ -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 |
@ -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; |
|||
} |
|||
/*}}}*/ |
@ -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> |
|||