Browse Source

Join with aliencode

Author: jgg
Date: 2001-02-20 07:03:16 GMT
Join with aliencode
debian/1.8.y
Arch Librarian 19 years ago
parent
commit
b2e465d6d3
  1. 6
      AUTHORS
  2. 15
      Makefile
  3. 154
      apt-inst/contrib/arfile.cc
  4. 68
      apt-inst/contrib/arfile.h
  5. 342
      apt-inst/contrib/extracttar.cc
  6. 54
      apt-inst/contrib/extracttar.h
  7. 30
      apt-inst/database.cc
  8. 56
      apt-inst/database.h
  9. 262
      apt-inst/deb/debfile.cc
  10. 92
      apt-inst/deb/debfile.h
  11. 490
      apt-inst/deb/dpkgdb.cc
  12. 53
      apt-inst/deb/dpkgdb.h
  13. 103
      apt-inst/dirstream.cc
  14. 61
      apt-inst/dirstream.h
  15. 5
      apt-inst/dpkg-diffs.txt
  16. 509
      apt-inst/extract.cc
  17. 52
      apt-inst/extract.h
  18. 588
      apt-inst/filelist.cc
  19. 314
      apt-inst/filelist.h
  20. 30
      apt-inst/makefile
  21. 142
      apt-pkg/acquire-item.cc
  22. 20
      apt-pkg/acquire-item.h
  23. 10
      apt-pkg/acquire-method.cc
  24. 6
      apt-pkg/acquire-method.h
  25. 16
      apt-pkg/acquire-worker.cc
  26. 6
      apt-pkg/acquire-worker.h
  27. 26
      apt-pkg/acquire.cc
  28. 25
      apt-pkg/acquire.h
  29. 223
      apt-pkg/algorithms.cc
  30. 25
      apt-pkg/algorithms.h
  31. 90
      apt-pkg/cachefile.cc
  32. 31
      apt-pkg/cachefile.h
  33. 50
      apt-pkg/cacheiterators.h
  34. 28
      apt-pkg/clean.cc
  35. 14
      apt-pkg/contrib/cdromutl.cc
  36. 30
      apt-pkg/contrib/cmndline.cc
  37. 406
      apt-pkg/contrib/configuration.cc
  38. 57
      apt-pkg/contrib/configuration.h
  39. 4
      apt-pkg/contrib/error.cc
  40. 22
      apt-pkg/contrib/error.h
  41. 107
      apt-pkg/contrib/fileutl.cc
  42. 7
      apt-pkg/contrib/fileutl.h
  43. 4
      apt-pkg/contrib/md5.h
  44. 23
      apt-pkg/contrib/mmap.cc
  45. 14
      apt-pkg/contrib/progress.cc
  46. 66
      apt-pkg/contrib/sptr.h
  47. 163
      apt-pkg/contrib/strutl.cc
  48. 38
      apt-pkg/contrib/strutl.h
  49. 506
      apt-pkg/deb/debindexfile.cc
  50. 112
      apt-pkg/deb/debindexfile.h
  51. 221
      apt-pkg/deb/deblistparser.cc
  52. 36
      apt-pkg/deb/deblistparser.h
  53. 23
      apt-pkg/deb/debrecords.cc
  54. 12
      apt-pkg/deb/debrecords.h
  55. 97
      apt-pkg/deb/debsrcrecords.cc
  56. 24
      apt-pkg/deb/debsrcrecords.h
  57. 197
      apt-pkg/deb/debsystem.cc
  58. 41
      apt-pkg/deb/debsystem.h
  59. 266
      apt-pkg/deb/debversion.cc
  60. 72
      apt-pkg/deb/debversion.h
  61. 119
      apt-pkg/deb/dpkginit.cc
  62. 34
      apt-pkg/deb/dpkginit.h
  63. 162
      apt-pkg/deb/dpkgpm.cc
  64. 8
      apt-pkg/deb/dpkgpm.h
  65. 255
      apt-pkg/depcache.cc
  66. 72
      apt-pkg/depcache.h
  67. 77
      apt-pkg/indexfile.cc
  68. 80
      apt-pkg/indexfile.h
  69. 105
      apt-pkg/init.cc
  70. 28
      apt-pkg/init.h
  71. 43
      apt-pkg/makefile
  72. 119
      apt-pkg/orderlist.cc
  73. 21
      apt-pkg/orderlist.h
  74. 56
      apt-pkg/packagemanager.cc
  75. 25
      apt-pkg/packagemanager.h
  76. 245
      apt-pkg/pkgcache.cc
  77. 64
      apt-pkg/pkgcache.h
  78. 688
      apt-pkg/pkgcachegen.cc
  79. 41
      apt-pkg/pkgcachegen.h
  80. 45
      apt-pkg/pkgrecords.cc
  81. 27
      apt-pkg/pkgrecords.h
  82. 45
      apt-pkg/pkgsystem.cc
  83. 95
      apt-pkg/pkgsystem.h
  84. 275
      apt-pkg/policy.cc
  85. 83
      apt-pkg/policy.h
  86. 424
      apt-pkg/sourcelist.cc
  87. 61
      apt-pkg/sourcelist.h
  88. 68
      apt-pkg/srcrecords.cc
  89. 47
      apt-pkg/srcrecords.h
  90. 282
      apt-pkg/tagfile.cc
  91. 49
      apt-pkg/tagfile.h
  92. 261
      apt-pkg/version.cc
  93. 69
      apt-pkg/version.h
  94. 210
      apt-pkg/versionmatch.cc
  95. 69
      apt-pkg/versionmatch.h
  96. 1
      buildlib/apti18n.h.in
  97. 54
      buildlib/archtable
  98. 439
      buildlib/config.guess
  99. 16
      buildlib/config.h.in
  100. 200
      buildlib/config.sub

6
AUTHORS

@ -6,16 +6,20 @@ CVS:jgg Jason Gunthorpe <jgg@debian.org>
CVS:che Ben Gertzfield <che@debian.org>
- Packaging and Releases
CVS:bod Brendan O'Dea <bod@debian.org>
- Perl Bindings
Past Contributures:
Brian White <bcwhite@verisim.com> - Project originator
Tom Lees <tom@lpsg.demon.co.uk> - DPKG documentation and ideas
Behan Webster <behanw@verisim.com> - Original GUI design
Scott Ellis <storm@gate.net> - Original packaging and beta releases
Branden Branden Robinson <branden@purdue.edu> - Man Page Documentation
Branden Robinson <branden@purdue.edu> - Man Page Documentation
Manoj Srivastava <srivasta@datasync.com> - 1st Generation FTP method and
dselect setup script
Adam Heath <doogie@debian.org> - 2nd Generation FTP method author
Ben Collins <bcollins@debian.org> - Initial RSH method
Many other bug reports through the Debian Bug system
NOTE: The ChangeLog generator will parse for names and email addresses. The

15
Makefile

@ -6,17 +6,17 @@ ifndef NOISY
.SILENT:
endif
.PHONY: default
default: startup all
.PHONY: headers library clean veryclean all binary program doc
all headers library clean veryclean binary program doc:
all headers library clean veryclean binary program doc dirs:
$(MAKE) -C apt-pkg $@
$(MAKE) -C apt-inst $@
$(MAKE) -C methods $@
# $(MAKE) -C methods/ftp $@
$(MAKE) -C cmdline $@
$(MAKE) -C ftparchive $@
$(MAKE) -C dselect $@
ifdef GUI
$(MAKE) -C deity $@
$(MAKE) -C gui $@
endif
$(MAKE) -C doc $@
# Some very common aliases
@ -25,8 +25,9 @@ maintainer-clean dist-clean distclean pristine sanity: veryclean
# The startup target builds the necessary configure scripts. It should
# be used after a CVS checkout.
CONVERTED=environment.mak include/config.h makefile
CONVERTED=environment.mak include/config.h include/apti18n.h makefile
include buildlib/configure.mak
$(BUILDDIR)/include/config.h: buildlib/config.h.in
$(BUILDDIR)/include/apti18n.h: buildlib/apti18n.h.in
$(BUILDDIR)/environment.mak: buildlib/environment.mak.in
$(BUILDDIR)/makefile: buildlib/makefile.in

154
apt-inst/contrib/arfile.cc

@ -0,0 +1,154 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: arfile.cc,v 1.2 2001/02/20 07:03:16 jgg Exp $
/* ######################################################################
AR File - Handle an 'AR' archive
AR Archives have plain text headers at the start of each file
section. The headers are aligned on a 2 byte boundry.
Information about the structure of AR files can be found in ar(5)
on a BSD system, or in the binutils source.
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#ifdef __GNUG__
#pragma implementation "apt-pkg/arfile.h"
#endif
#include <apt-pkg/arfile.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/error.h>
#include <stdlib.h>
/*}}}*/
struct ARArchive::MemberHeader
{
char Name[16];
char MTime[12];
char UID[6];
char GID[6];
char Mode[8];
char Size[10];
char Magic[2];
};
// ARArchive::ARArchive - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
ARArchive::ARArchive(FileFd &File) : List(0), File(File)
{
LoadHeaders();
}
/*}}}*/
// ARArchive::~ARArchive - Destructor /*{{{*/
// ---------------------------------------------------------------------
/* */
ARArchive::~ARArchive()
{
while (List != 0)
{
Member *Tmp = List;
List = List->Next;
delete Tmp;
}
}
/*}}}*/
// ARArchive::LoadHeaders - Load the headers from each file /*{{{*/
// ---------------------------------------------------------------------
/* AR files are structured with a 8 byte magic string followed by a 60
byte plain text header then the file data, another header, data, etc */
bool ARArchive::LoadHeaders()
{
signed long Left = File.Size();
// Check the magic byte
char Magic[8];
if (File.Read(Magic,sizeof(Magic)) == false)
return false;
if (memcmp(Magic,"!<arch>\012",sizeof(Magic)) != 0)
return _error->Error("Invalid archive signature");
Left -= sizeof(Magic);
// Read the member list
while (Left > 0)
{
MemberHeader Head;
if (File.Read(&Head,sizeof(Head)) == false)
return _error->Error("Error reading archive member header");
Left -= sizeof(Head);
// Convert all of the integer members
Member *Memb = new Member();
if (StrToNum(Head.MTime,Memb->MTime,sizeof(Head.MTime)) == false ||
StrToNum(Head.UID,Memb->UID,sizeof(Head.UID)) == false ||
StrToNum(Head.GID,Memb->GID,sizeof(Head.GID)) == false ||
StrToNum(Head.Mode,Memb->Mode,sizeof(Head.Mode),8) == false ||
StrToNum(Head.Size,Memb->Size,sizeof(Head.Size)) == false)
{
delete Memb;
return _error->Error("Invalid archive member header");
}
// Check for an extra long name string
if (memcmp(Head.Name,"#1/",3) == 0)
{
char S[300];
unsigned long Len;
if (StrToNum(Head.Name+3,Len,sizeof(Head.Size)-3) == false ||
Len >= strlen(S))
{
delete Memb;
return _error->Error("Invalid archive member header");
}
if (File.Read(S,Len) == false)
return false;
S[Len] = 0;
Memb->Name = S;
Memb->Size -= Len;
Left -= Len;
}
else
{
unsigned int I = sizeof(Head.Name) - 1;
for (; Head.Name[I] == ' '; I--);
Memb->Name = string(Head.Name,0,I+1);
}
// Account for the AR header alignment
unsigned Skip = Memb->Size % 2;
// Add it to the list
Memb->Next = List;
List = Memb;
Memb->Start = File.Tell();
if (File.Skip(Memb->Size + Skip) == false)
return false;
if (Left < (signed)(Memb->Size + Skip))
return _error->Error("Archive is too short");
Left -= Memb->Size + Skip;
}
if (Left != 0)
return _error->Error("Failed to read the archive headers");
return true;
}
/*}}}*/
// ARArchive::FindMember - Find a name in the member list /*{{{*/
// ---------------------------------------------------------------------
/* Find a member with the given name */
const ARArchive::Member *ARArchive::FindMember(const char *Name) const
{
const Member *Res = List;
while (Res != 0)
{
if (Res->Name == Name)
return Res;
Res = Res->Next;
}
return 0;
}
/*}}}*/

68
apt-inst/contrib/arfile.h

@ -0,0 +1,68 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: arfile.h,v 1.2 2001/02/20 07:03:16 jgg Exp $
/* ######################################################################
AR File - Handle an 'AR' archive
This is a reader for the usual 4.4 BSD AR format. It allows raw
stream access to a single member at a time. Basically all this class
provides is header parsing and verification. It is up to the client
to correctly make use of the stream start/stop points.
##################################################################### */
/*}}}*/
#ifndef PKGLIB_ARFILE_H
#define PKGLIB_ARFILE_H
#ifdef __GNUG__
#pragma interface "apt-pkg/arfile.h"
#endif
#include <string>
#include <apt-pkg/fileutl.h>
class ARArchive
{
struct MemberHeader;
public:
struct Member;
protected:
// Linked list of members
Member *List;
bool LoadHeaders();
public:
// The stream file
FileFd &File;
// Locate a member by name
const Member *FindMember(const char *Name) const;
ARArchive(FileFd &File);
~ARArchive();
};
// A member of the archive
struct ARArchive::Member
{
// Fields from the header
string Name;
unsigned long MTime;
unsigned long UID;
unsigned long GID;
unsigned long Mode;
unsigned long Size;
// Location of the data.
unsigned long Start;
Member *Next;
Member() : Start(0), Next(0) {};
};
#endif

342
apt-inst/contrib/extracttar.cc

@ -0,0 +1,342 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: extracttar.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
/* ######################################################################
Extract a Tar - Tar Extractor
Some performance measurements showed that zlib performed quite poorly
in comparision to a forked gzip process. This tar extractor makes use
of the fact that dup'd file descriptors have the same seek pointer
and that gzip will not read past the end of a compressed stream,
even if there is more data. We use the dup property to track extraction
progress and the gzip feature to just feed gzip a fd in the middle
of an AR file.
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#ifdef __GNUG__
#pragma implementation "apt-pkg/extracttar.h"
#endif
#include <apt-pkg/extracttar.h>
#include <apt-pkg/error.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/configuration.h>
#include <system.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
/*}}}*/
// The on disk header for a tar file.
struct ExtractTar::TarHeader
{
char Name[100];
char Mode[8];
char UserID[8];
char GroupID[8];
char Size[12];
char MTime[12];
char Checksum[8];
char LinkFlag;
char LinkName[100];
char MagicNumber[8];
char UserName[32];
char GroupName[32];
char Major[8];
char Minor[8];
};
// ExtractTar::ExtractTar - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
ExtractTar::ExtractTar(FileFd &Fd,unsigned long Max) : File(Fd),
MaxInSize(Max)
{
GZPid = -1;
InFd = -1;
Eof = false;
}
/*}}}*/
// ExtractTar::ExtractTar - Destructor /*{{{*/
// ---------------------------------------------------------------------
/* */
ExtractTar::~ExtractTar()
{
Done(false);
}
/*}}}*/
// ExtractTar::Done - Reap the gzip sub process /*{{{*/
// ---------------------------------------------------------------------
/* If the force flag is given then error messages are suppressed - this
means we hit the end of the tar file but there was still gzip data. */
bool ExtractTar::Done(bool Force)
{
InFd.Close();
if (GZPid <= 0)
return true;
/* If there is a pending error then we are cleaning up gzip and are
not interested in it's failures */
if (_error->PendingError() == true)
Force = true;
// Make sure we clean it up!
kill(GZPid,SIGINT);
if (ExecWait(GZPid,_config->Find("dir::bin::gzip","/bin/gzip").c_str(),
Force) == false)
{
GZPid = -1;
return Force;
}
GZPid = -1;
return true;
}
/*}}}*/
// ExtractTar::StartGzip - Startup gzip /*{{{*/
// ---------------------------------------------------------------------
/* This creates a gzip sub process that has its input as the file itself.
If this tar file is embedded into something like an ar file then
gzip will efficiently ignore the extra bits. */
bool ExtractTar::StartGzip()
{
int Pipes[2];
if (pipe(Pipes) != 0)
return _error->Errno("pipe","Failed to create pipes");
// Fork off the process
GZPid = ExecFork();
// Spawn the subprocess
if (GZPid == 0)
{
// Setup the FDs
dup2(Pipes[1],STDOUT_FILENO);
dup2(File.Fd(),STDIN_FILENO);
int Fd = open("/dev/null",O_RDWR);
if (Fd == -1)
_exit(101);
dup2(Fd,STDERR_FILENO);
close(Fd);
SetCloseExec(STDOUT_FILENO,false);
SetCloseExec(STDIN_FILENO,false);
SetCloseExec(STDERR_FILENO,false);
const char *Args[3];
Args[0] = _config->Find("dir::bin::gzip","/bin/gzip").c_str();
Args[1] = "-d";
Args[2] = 0;
execv(Args[0],(char **)Args);
cerr << "Failed to exec gzip " << Args[0] << endl;
_exit(100);
}
// Fix up our FDs
InFd.Fd(Pipes[0]);
close(Pipes[1]);
return true;
}
/*}}}*/
// ExtractTar::Go - Perform extraction /*{{{*/
// ---------------------------------------------------------------------
/* This reads each 512 byte block from the archive and extracts the header
information into the Item structure. Then it resolves the UID/GID and
invokes the correct processing function. */
bool ExtractTar::Go(pkgDirStream &Stream)
{
if (StartGzip() == false)
return false;
// Loop over all blocks
string LastLongLink;
string LastLongName;
while (1)
{
bool BadRecord = false;
unsigned char Block[512];
if (InFd.Read(Block,sizeof(Block),true) == false)
return false;
if (InFd.Eof() == true)
break;
// Get the checksum
TarHeader *Tar = (TarHeader *)Block;
unsigned long CheckSum;
if (StrToNum(Tar->Checksum,CheckSum,sizeof(Tar->Checksum),8) == false)
return _error->Error("Corrupted archive");
/* Compute the checksum field. The actual checksum is blanked out
with spaces so it is not included in the computation */
unsigned long NewSum = 0;
memset(Tar->Checksum,' ',sizeof(Tar->Checksum));
for (int I = 0; I != sizeof(Block); I++)
NewSum += Block[I];
/* Check for a block of nulls - in this case we kill gzip, GNU tar
does this.. */
if (NewSum == ' '*sizeof(Tar->Checksum))
return Done(true);
if (NewSum != CheckSum)
return _error->Error("Tar Checksum failed, archive corrupted");
// Decode all of the fields
pkgDirStream::Item Itm;
unsigned long UID;
unsigned long GID;
if (StrToNum(Tar->Mode,Itm.Mode,sizeof(Tar->Mode),8) == false ||
StrToNum(Tar->UserID,UID,sizeof(Tar->UserID),8) == false ||
StrToNum(Tar->GroupID,GID,sizeof(Tar->GroupID),8) == false ||
StrToNum(Tar->Size,Itm.Size,sizeof(Tar->Size),8) == false ||
StrToNum(Tar->MTime,Itm.MTime,sizeof(Tar->MTime),8) == false ||
StrToNum(Tar->Major,Itm.Major,sizeof(Tar->Major),8) == false ||
StrToNum(Tar->Minor,Itm.Minor,sizeof(Tar->Minor),8) == false)
return _error->Error("Corrupted archive");
// Grab the filename
if (LastLongName.empty() == false)
Itm.Name = (char *)LastLongName.c_str();
else
{
Tar->Name[sizeof(Tar->Name)] = 0;
Itm.Name = Tar->Name;
}
if (Itm.Name[0] == '.' && Itm.Name[1] == '/' && Itm.Name[2] != 0)
Itm.Name += 2;
// Grab the link target
Tar->Name[sizeof(Tar->LinkName)] = 0;
Itm.LinkTarget = Tar->LinkName;
if (LastLongLink.empty() == false)
Itm.LinkTarget = (char *)LastLongLink.c_str();
// Convert the type over
switch (Tar->LinkFlag)
{
case NormalFile0:
case NormalFile:
Itm.Type = pkgDirStream::Item::File;
break;
case HardLink:
Itm.Type = pkgDirStream::Item::HardLink;
break;
case SymbolicLink:
Itm.Type = pkgDirStream::Item::SymbolicLink;
break;
case CharacterDevice:
Itm.Type = pkgDirStream::Item::CharDevice;
break;
case BlockDevice:
Itm.Type = pkgDirStream::Item::BlockDevice;
break;
case Directory:
Itm.Type = pkgDirStream::Item::Directory;
break;
case FIFO:
Itm.Type = pkgDirStream::Item::FIFO;
break;
case GNU_LongLink:
{
unsigned long Length = Itm.Size;
unsigned char Block[512];
while (Length > 0)
{
if (InFd.Read(Block,sizeof(Block),true) == false)
return false;
if (Length <= sizeof(Block))
{
LastLongLink.append(Block,Block+sizeof(Block));
break;
}
LastLongLink.append(Block,Block+sizeof(Block));
Length -= sizeof(Block);
}
continue;
}
case GNU_LongName:
{
unsigned long Length = Itm.Size;
unsigned char Block[512];
while (Length > 0)
{
if (InFd.Read(Block,sizeof(Block),true) == false)
return false;
if (Length < sizeof(Block))
{
LastLongName.append(Block,Block+sizeof(Block));
break;
}
LastLongName.append(Block,Block+sizeof(Block));
Length -= sizeof(Block);
}
continue;
}
default:
BadRecord = true;
_error->Warning("Unkown TAR header type %u, member %s",(unsigned)Tar->LinkFlag,Tar->Name);
break;
}
int Fd = -1;
if (BadRecord == false)
if (Stream.DoItem(Itm,Fd) == false)
return false;
// Copy the file over the FD
unsigned long Size = Itm.Size;
while (Size != 0)
{
unsigned char Junk[32*1024];
unsigned long Read = MIN(Size,sizeof(Junk));
if (InFd.Read(Junk,((Read+511)/512)*512) == false)
return false;
if (BadRecord == false)
{
if (Fd > 0)
{
if (write(Fd,Junk,Read) != (signed)Read)
return Stream.Fail(Itm,Fd);
}
else
{
/* An Fd of -2 means to send to a special processing
function */
if (Fd == -2)
if (Stream.Process(Itm,Junk,Read,Itm.Size - Size) == false)
return Stream.Fail(Itm,Fd);
}
}
Size -= Read;
}
// And finish up
if (Itm.Size != 0 && BadRecord == false)
if (Stream.FinishedFile(Itm,Fd) == false)
return false;
LastLongName.erase();
LastLongLink.erase();
}
return Done(false);
}
/*}}}*/

54
apt-inst/contrib/extracttar.h

@ -0,0 +1,54 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: extracttar.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
/* ######################################################################
Extract a Tar - Tar Extractor
The tar extractor takes an ordinary gzip compressed tar stream from
the given file and explodes it, passing the individual items to the
given Directory Stream for processing.
##################################################################### */
/*}}}*/
#ifndef PKGLIB_EXTRACTTAR_H
#define PKGLIB_EXTRACTTAR_H
#ifdef __GNUG__
#pragma interface "apt-pkg/extracttar.h"
#endif
#include <apt-pkg/fileutl.h>
#include <apt-pkg/dirstream.h>
class ExtractTar
{
protected:
struct TarHeader;
// The varios types items can be
enum ItemType {NormalFile0 = '\0',NormalFile = '0',HardLink = '1',
SymbolicLink = '2',CharacterDevice = '3',
BlockDevice = '4',Directory = '5',FIFO = '6',
GNU_LongLink = 'K',GNU_LongName = 'L'};
FileFd &File;
unsigned long MaxInSize;
int GZPid;
FileFd InFd;
bool Eof;
// Fork and reap gzip
bool StartGzip();
bool Done(bool Force);
public:
bool Go(pkgDirStream &Stream);
ExtractTar(FileFd &Fd,unsigned long Max);
virtual ~ExtractTar();
};
#endif

30
apt-inst/database.cc

@ -0,0 +1,30 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: database.cc,v 1.2 2001/02/20 07:03:16 jgg Exp $
/* ######################################################################
Data Base Abstraction
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#ifdef __GNUG__
#pragma implementation "apt-pkg/database.h"
#endif
#include <apt-pkg/database.h>
/*}}}*/
// DataBase::GetMetaTmp - Get the temp dir /*{{{*/
// ---------------------------------------------------------------------
/* This re-initializes the meta temporary directory if it hasn't yet
been inited for this cycle. The flag is the emptyness of MetaDir */
bool pkgDataBase::GetMetaTmp(string &Dir)
{
if (MetaDir.empty() == true)
if (InitMetaTmp(MetaDir) == false)
return false;
Dir = MetaDir;
return true;
}
/*}}}*/

56
apt-inst/database.h

@ -0,0 +1,56 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: database.h,v 1.2 2001/02/20 07:03:16 jgg Exp $
/* ######################################################################
Data Base Abstraction
This class provides a simple interface to an abstract notion of a
database directory for storing state information about the system.
The 'Meta' information for a package is the control information and
setup scripts stored inside the archive. GetMetaTmp returns the name of
a directory that is used to store named files containing the control
information.
The File Listing is the database of installed files. It is loaded
into the memory/persistent cache structure by the ReadFileList method.
##################################################################### */
/*}}}*/
#ifndef PKGLIB_DATABASE_H
#define PKGLIB_DATABASE_H
#ifdef __GNUG__
#pragma interface "apt-pkg/database.h"
#endif
#include <apt-pkg/filelist.h>
#include <apt-pkg/pkgcachegen.h>
class pkgDataBase
{
protected:
pkgCacheGenerator *Cache;
pkgFLCache *FList;
string MetaDir;
virtual bool InitMetaTmp(string &Dir) = 0;
public:
// Some manipulators for the cache and generator
inline pkgCache &GetCache() {return Cache->GetCache();};
inline pkgFLCache &GetFLCache() {return *FList;};
inline pkgCacheGenerator &GetGenerator() {return *Cache;};
bool GetMetaTmp(string &Dir);
virtual bool ReadyFileList(OpProgress &Progress) = 0;
virtual bool ReadyPkgCache(OpProgress &Progress) = 0;
virtual bool LoadChanges() = 0;
pkgDataBase() : Cache(0), FList(0) {};
virtual ~pkgDataBase() {delete Cache; delete FList;};
};
#endif

262
apt-inst/deb/debfile.cc

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

92
apt-inst/deb/debfile.h

@ -0,0 +1,92 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: debfile.h,v 1.2 2001/02/20 07:03:17 jgg Exp $
/* ######################################################################
Debian Archive File (.deb)
This Class handles all the operations performed directly on .deb
files. It makes use of the AR and TAR classes to give the necessary
external interface.
There are only two things that can be done with a raw package,
extract it's control information and extract the contents itself.
This should probably subclass an as-yet unwritten super class to
produce a generic archive mechanism.
The memory control file extractor is useful to extract a single file
into memory from the control.tar.gz
##################################################################### */
/*}}}*/
#ifndef PKGLIB_DEBFILE_H
#define PKGLIB_DEBFILE_H
#ifdef __GNUG__
#pragma interface "apt-pkg/debfile.h"
#endif
#include <apt-pkg/arfile.h>
#include <apt-pkg/database.h>
#include <apt-pkg/dirstream.h>
#include <apt-pkg/tagfile.h>
class debDebFile
{
protected:
FileFd &File;
ARArchive AR;
bool CheckMember(const char *Name);
public:
class ControlExtract;
class MemControlExtract;
bool ExtractControl(pkgDataBase &DB);
bool ExtractArchive(pkgDirStream &Stream);
pkgCache::VerIterator MergeControl(pkgDataBase &DB);
const ARArchive::Member *GotoMember(const char *Name);
inline FileFd &GetFile() {return File;};
debDebFile(FileFd &File);
};
class debDebFile::ControlExtract : public pkgDirStream
{
public:
virtual bool DoItem(Item &Itm,int &Fd);
};
class debDebFile::MemControlExtract : public pkgDirStream
{
bool IsControl;
public:
char *Control;
pkgTagSection Section;
unsigned long Length;
string Member;
// Members from DirStream
virtual bool DoItem(Item &Itm,int &Fd);
virtual bool Process(Item &Itm,const unsigned char *Data,
unsigned long Size,unsigned long Pos);
// Helpers
bool Read(debDebFile &Deb);
bool TakeControl(const void *Data,unsigned long Size);
MemControlExtract() : IsControl(false), Control(0), Length(0), Member("control") {};
MemControlExtract(string Member) : IsControl(false), Control(0), Length(0), Member(Member) {};
~MemControlExtract() {delete [] Control;};
};
/*}}}*/
#endif

490
apt-inst/deb/dpkgdb.cc

@ -0,0 +1,490 @@
// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
// $Id: dpkgdb.cc,v 1.2 2001/02/20 07:03:17 jgg Exp $
/* ######################################################################
DPKGv1 Database Implemenation
This class provides parsers and other implementations for the DPKGv1
database. It reads the diversion file, the list files and the status
file to build both the list of currently installed files and the
currently installed package list.
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#ifdef __GNUG__
#pragma implementation "apt-pkg/dpkgdb.h"
#endif
#include <apt-pkg/dpkgdb.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
#include <apt-pkg/progress.h>
#include <apt-pkg/tagfile.h>
#include <apt-pkg/strutl.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
/*}}}*/
// EraseDir - Erase A Directory /*{{{*/
// ---------------------------------------------------------------------
/* This is necessary to create a new empty sub directory. The caller should
invoke mkdir after this with the proper permissions and check for
error. Maybe stick this in fileutils */
static bool EraseDir(const char *Dir)
{
// First we try a simple RM
if (rmdir(Dir) == 0 ||
errno == ENOENT)
return true;
// A file? Easy enough..
if (errno == ENOTDIR)
{
if (unlink(Dir) != 0)
return _error->Errno("unlink","Failed to remove %s",Dir);
return true;
}
// Should not happen
if (errno != ENOTEMPTY)
return _error->Errno("rmdir","Failed to remove %s",Dir);
// Purge it using rm
int Pid = ExecFork();
// Spawn the subprocess
if (Pid == 0)
{
execlp(_config->Find("Dir::Bin::rm","/bin/rm").c_str(),
"rm","-rf","--",Dir,0);
_exit(100);
}
return ExecWait(Pid,_config->Find("dir::bin::rm","/bin/rm").c_str());
}
/*}}}*/
// DpkgDB::debDpkgDB - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
debDpkgDB::debDpkgDB() : CacheMap(0), FileMap(0)
{
AdminDir = flNotFile(_config->Find("Dir::State::status"));
DiverInode = 0;
DiverTime = 0;
}
/*}}}*/
// DpkgDB::~debDpkgDB - Destructor /*{{{*/
// ---------------------------------------------------------------------
/* */
debDpkgDB::~debDpkgDB()
{
delete Cache;
Cache = 0;
delete CacheMap;
CacheMap = 0;
delete FList;
FList = 0;
delete FileMap;
FileMap = 0;
}
/*}}}*/
// DpkgDB::InitMetaTmp - Get the temp dir for meta information /*{{{*/
// ---------------------------------------------------------------------
/* This creats+empties the meta temporary directory /var/lib/dpkg/tmp.ci
Only one package at a time can be using the returned meta directory. */
bool debDpkgDB::InitMetaTmp(string &Dir)
{
string Tmp = AdminDir + "tmp.ci/";
if (EraseDir(Tmp.c_str()) == false)
return _error->Error("Unable to create %s",Tmp.c_str());
if (mkdir(Tmp.c_str(),0755) != 0)
return _error->Errno("mkdir","Unable to create %s",Tmp.c_str());
// Verify it is on the same filesystem as the main info directory
dev_t Dev;
struct stat St;
if (stat((AdminDir + "info").c_str(),&St) != 0)
return _error->Errno("stat","Failed to stat %sinfo",AdminDir.c_str());
Dev = St.st_dev;
if (stat(Tmp.c_str(),&St) != 0)
return _error->Errno("stat","Failed to stat %s",Tmp.c_str());
if (Dev != St.st_dev)
return _error->Error("The info and temp directories need to be on the same filesystem");
// Done
Dir = Tmp;
return true;
}
/*}}}*/
// DpkgDB::ReadyPkgCache - Prepare the cache with the current status /*{{{*/
// ---------------------------------------------------------------------
/* This reads in the status file into an empty cache. This really needs
to be somehow unified with the high level APT notion of the Database
directory, but there is no clear way on how to do that yet. */
bool debDpkgDB::ReadyPkgCache(OpProgress &Progress)
{
if (Cache != 0)
{
Progress.OverallProgress(1,1,1,"Reading Package Lists");
return true;
}
if (CacheMap != 0)
{
delete CacheMap;
CacheMap = 0;
}
if (pkgMakeOnlyStatusCache(Progress,&CacheMap) == false)
return false;
Cache->DropProgress();
return true;
}
/*}}}*/
// DpkgDB::ReadFList - Read the File Listings in /*{{{*/
// ---------------------------------------------------------------------
/* This reads the file listing in from the state directory. This is a
performance critical routine, as it needs to parse about 50k lines of
text spread over a hundred or more files. For an initial cold start
most of the time is spent in reading file inodes and so on, not
actually parsing. */
bool debDpkgDB::ReadFList(OpProgress &Progress)
{
// Count the number of packages we need to read information for
unsigned long Total = 0;
pkgCache &Cache = this->Cache->GetCache();
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
// Only not installed packages have no files.
if (I->CurrentState == pkgCache::State::NotInstalled)
continue;
Total++;
}
/* Switch into the admin dir, this prevents useless lookups for the
path components */
string Cwd = SafeGetCWD();
if (chdir((AdminDir + "info/").c_str()) != 0)
return _error->Errno("chdir","Failed to change to the admin dir %sinfo",AdminDir.c_str());
// Allocate a buffer. Anything larger than this buffer will be mmaped
unsigned long BufSize = 32*1024;
char *Buffer = new char[BufSize];
// Begin Loading them
unsigned long Count = 0;
char Name[300];
for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
{
/* Only not installed packages have no files. ConfFile packages have
file lists but we don't want to read them in */
if (I->CurrentState == pkgCache::State::NotInstalled ||
I->CurrentState == pkgCache::State::ConfigFiles)
continue;
// Fetch a package handle to associate with the file
pkgFLCache::PkgIterator FlPkg = FList->GetPkg(I.Name(),0,true);
if (FlPkg.end() == true)
{
_error->Error("Internal Error getting a Package Name");
break;
}
Progress.OverallProgress(Count,Total,1,"Reading File Listing");
// Open the list file
snprintf(Name,sizeof(Name),"%s.list",I.Name());
int Fd = open(Name,O_RDONLY);
/* Okay this is very strange and bad.. Best thing is to bail and
instruct the user to look into it. */
struct stat Stat;
if (Fd == -1 || fstat(Fd,&Stat) != 0)
{
_error->Errno("open","Failed to open the list file '%sinfo/%s'. If you "
"cannot restore this file then make it empty "
"and immediately re-install the same version of the package!",
AdminDir.c_str(),Name);
break;
}
// Set File to be a memory buffer containing the whole file
char *File;
if ((unsigned)Stat.st_size < BufSize)
{
if (read(Fd,Buffer,Stat.st_size) != Stat.st_size)
{
_error->Errno("read","Failed reading the list file %sinfo/%s",
AdminDir.c_str(),Name);
close(Fd);
break;
}
File = Buffer;
}
else
{
// Use mmap
File = (char *)mmap(0,Stat.st_size,PROT_READ,MAP_PRIVATE,Fd,0);
if (File == (char *)(-1))
{
_error->Errno("mmap","Failed reading the list file %sinfo/%s",
AdminDir.c_str(),Name);
close(Fd);
break;
}
}
// Parse it
const char *Start = File;
const char *End = File;
const char *Finish = File + Stat.st_size;
for (; End < Finish; End++)
{
// Not an end of line
if (*End != '\n' && End + 1 < Finish)
continue;
// Skip blank lines
if (End - Start > 1)
{
pkgFLCache::NodeIterator Node = FList->GetNode(Start,End,
FlPkg.Offset(),true,false);
if (Node.end() == true)
{
_error->Error("Internal Error getting a Node");
break;
}
}
// Skip past the end of line
for (; *End == '\n' && End < Finish; End++);
Start = End;
}
close(Fd);
if ((unsigned)Stat.st_size >= BufSize)
munmap((caddr_t)File,Stat.st_size);
// Failed
if (End < Finish)
break;
Count++;
}
delete [] Buffer;
if (chdir(Cwd.c_str()) != 0)
chdir("/");
return !_error->PendingError();
}
/*}}}*/
// DpkgDB::ReadDiversions - Load the diversions file /*{{{*/
// ---------------------------------------------------------------------
/* Read the diversion file in from disk. This is usually invoked by
LoadChanges before performing an operation that uses the FLCache. */
bool debDpkgDB::ReadDiversions()
{
struct stat Stat;
if (stat((AdminDir + "diversions").c_str(),&Stat) != 0)
return true;
if (_error->PendingError() == true)
return false;
FILE *Fd = fopen((AdminDir + "diversions").c_str(),"r");
if (Fd == 0)
return _error->Errno("fopen","Failed to open the diversions file %sdiversions",AdminDir.c_str());
FList->BeginDiverLoad();
while (1)
{
char From[300];
char To[300];
char Package[100];
// Read the three lines in
if (fgets(From,sizeof(From),Fd) == 0)
break;
if (fgets(To,sizeof(To),Fd) == 0 ||
fgets(Package,sizeof(Package),Fd) == 0)
{
_error->Error("The diversion file is corrupted");
break;
}
// Strip the \ns
unsigned long Len = strlen(From);
if (Len < 2 || From[Len-1] != '\n')
_error->Error("Invalid line in the diversion file: %s",From);
else
From[Len-1] = 0;
Len = strlen(To);
if (Len < 2 || To[Len-1] != '\n')
_error->Error("Invalid line in the diversion file: %s",To);
else
To[Len-1] = 0;
Len = strlen(Package);
if (Len < 2 || Package[Len-1] != '\n')
_error->Error("Invalid line in the diversion file: %s",Package);
else
Package[Len-1] = 0;
// Make sure the lines were parsed OK
if (_error->PendingError() == true)
break;
// Fetch a package
if (strcmp(Package,":") == 0)
Package[0] = 0;
pkgFLCache::PkgIterator FlPkg = FList->GetPkg(Package,0,true);
if (FlPkg.end() == true)
{
_error->Error("Internal Error getting a Package Name");
break;
}
// Install the diversion
if (FList->AddDiversion(FlPkg,From,To) == false)
{
_error->Error("Internal Error adding a diversion");
break;
}
}
if (_error->PendingError() == false)
FList->FinishDiverLoad();
DiverInode = Stat.st_ino;
DiverTime = Stat.st_mtime;
fclose(Fd);
return !_error->PendingError();
}
/*}}}*/
// DpkgDB::ReadFileList - Read the file listing /*{{{*/
// ---------------------------------------------------------------------
/* Read in the file listing. The file listing is created from three
sources, *.list, Conffile sections and the Diversion table. */
bool debDpkgDB::ReadyFileList(OpProgress &Progress)
{
if (Cache == 0)
return _error->Error("The pkg cache must be initialize first");
if (FList != 0)
{
Progress.OverallProgress(1,1,1,"Reading File List");
return true;
}
// Create the cache and read in the file listing
FileMap = new DynamicMMap(MMap::Public);
FList = new pkgFLCache(*FileMap);
if (_error->PendingError() == true ||
ReadFList(Progress) == false ||
ReadConfFiles() == false ||
ReadDiversions() == false)
{
delete FList;
delete FileMap;
FileMap = 0;
FList = 0;