0.3.19cnc55-alt3
- Added librpm-4.0.4 build support. - Built with librpm-4.0.4, updated buildrequires.
This commit is contained in:
commit
e3ad0ef694
4
.gear-rules
Normal file
4
.gear-rules
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
copy: *.conf
|
||||||
|
copy: *.patch
|
||||||
|
tar.bz2: apt
|
||||||
|
copy: rpmpriorities
|
21
apt-0.3.19cnc32-alt-distro.patch
Normal file
21
apt-0.3.19cnc32-alt-distro.patch
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
diff -k.orig -urN apt-0.3.19cnc32/cmdline/apt-cdrom.cc.orig apt-0.3.19cnc32/cmdline/apt-cdrom.cc
|
||||||
|
--- apt-0.3.19cnc32/cmdline/apt-cdrom.cc.orig Thu Jan 4 23:26:14 2001
|
||||||
|
+++ apt-0.3.19cnc32/cmdline/apt-cdrom.cc Mon Jan 22 17:22:32 2001
|
||||||
|
@@ -723,7 +723,7 @@
|
||||||
|
if (0)
|
||||||
|
return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc"));
|
||||||
|
else
|
||||||
|
- return _error->Error(_("Unable to locate any package files, perhaps this is not a Conectiva Disc"));
|
||||||
|
+ return _error->Error(_("Unable to locate any package files, perhaps this is not a ALT Linux Disc"));
|
||||||
|
}
|
||||||
|
// Check if the CD is in the database
|
||||||
|
string Name;
|
||||||
|
@@ -748,7 +748,7 @@
|
||||||
|
if (_config->FindB("APT::CDROM::Rename",false) == true ||
|
||||||
|
Name.empty() == true)
|
||||||
|
{
|
||||||
|
- cout << _("Please provide a name for this Disc, such as 'MyDistro 6.0 Disk 1'");
|
||||||
|
+ cout << _("Please provide a name for this Disc, such as 'Spring 2001 Disk 1'");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
11
apt-0.3.19cnc52-alt-INLINEDEPFLAG.patch
Normal file
11
apt-0.3.19cnc52-alt-INLINEDEPFLAG.patch
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
--- apt-0.3.19cnc52/buildlib/environment.mak.in.orig Thu Aug 2 01:31:58 2001
|
||||||
|
+++ apt-0.3.19cnc52/buildlib/environment.mak.in Sun Aug 5 13:49:41 2001
|
||||||
|
@@ -22,7 +22,7 @@
|
||||||
|
|
||||||
|
# Dep generation - this only works for gnu stuff
|
||||||
|
GCC3DEP = @GCC3DEP@
|
||||||
|
-INLINEDEPFLAG = -MD
|
||||||
|
+#INLINEDEPFLAG = -MD
|
||||||
|
|
||||||
|
# Debian doc stuff
|
||||||
|
DEBIANDOC_HTML = @DEBIANDOC_HTML@
|
63
apt-0.3.19cnc53-alt-configure-build.patch
Normal file
63
apt-0.3.19cnc53-alt-configure-build.patch
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
diff -ur apt-0.3.19cnc55~/configure.in apt-0.3.19cnc55/configure.in
|
||||||
|
--- apt-0.3.19cnc55~/configure.in Wed Mar 6 20:17:10 2002
|
||||||
|
+++ apt-0.3.19cnc55/configure.in Tue Mar 26 21:14:21 2002
|
||||||
|
@@ -64,20 +64,12 @@
|
||||||
|
dnl AC_MSG_ERROR(failed: I need posix threads, pthread)
|
||||||
|
dnl fi
|
||||||
|
|
||||||
|
-dnl Check for DB2
|
||||||
|
-AC_CHECK_HEADER(db2/db.h,
|
||||||
|
- [AC_CHECK_LIB(db2,db_open,
|
||||||
|
- [AC_DEFINE(HAVE_DB2) DB2LIB="-ldb2"])])
|
||||||
|
-AC_SUBST(DB2LIB)
|
||||||
|
-
|
||||||
|
-
|
||||||
|
dnl Check for rpm version --akk
|
||||||
|
rpm_version="none"
|
||||||
|
SAVE_LIBS="$LIBS"
|
||||||
|
SAVE_CPPFLAGS="$CPPFLAGS"
|
||||||
|
|
||||||
|
CPPFLAGS="$SAVE_CPPFLAGS -I/usr/include/rpm"
|
||||||
|
-AC_CHECK_HEADERS(db1/db.h)
|
||||||
|
AC_CHECK_HEADER(rpm/rpmlib.h, rpm_header_ok=1, rpm_header_ok=0)
|
||||||
|
|
||||||
|
if test $rpm_header_ok = 1; then
|
||||||
|
@@ -85,7 +77,7 @@
|
||||||
|
LIBS="$SAVE_LIBS -lrpm -lrpmio -lz -lbz2 -lpopt"
|
||||||
|
AC_CHECK_LIB(rpmdb,rpmdbOpen,
|
||||||
|
[RPMDBLIBS="-lrpmdb"],
|
||||||
|
- [RPMDBLIBS="-ldb-3.1"])
|
||||||
|
+ [RPMDBLIBS="-ldb"])
|
||||||
|
|
||||||
|
LIBS="$SAVE_LIBS $RPMDBLIBS -lrpmio -lz -lbz2 -lpopt"
|
||||||
|
AC_CHECK_LIB(rpm,rpmdbGetIteratorOffset,
|
||||||
|
@@ -100,6 +92,7 @@
|
||||||
|
[AC_DEFINE_UNQUOTED(HAVE_RPM, 1)
|
||||||
|
RPMLIBS="-lrpm -ldb1 -lz -lbz2 -lpopt"
|
||||||
|
SAVE_CPPFLAGS="$SAVE_CPPFLAGS -I/usr/include/rpm"
|
||||||
|
+ AC_CHECK_HEADERS(db1/db.h)
|
||||||
|
rpm_version="3"])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
diff -ur apt-0.3.19cnc55~/tools/cached_md5.cc apt-0.3.19cnc55/tools/cached_md5.cc
|
||||||
|
--- apt-0.3.19cnc55~/tools/cached_md5.cc Sun Feb 17 01:46:11 2002
|
||||||
|
+++ apt-0.3.19cnc55/tools/cached_md5.cc Sun Feb 17 01:46:25 2002
|
||||||
|
@@ -39,6 +39,7 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <rpm/rpmlib.h>
|
||||||
|
+#include <rpm/misc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
diff -ur apt-0.3.19cnc55~/tools/hdlist2pkglist.cc apt-0.3.19cnc55/tools/hdlist2pkglist.cc
|
||||||
|
--- apt-0.3.19cnc55~/tools/hdlist2pkglist.cc Sun Feb 17 01:46:11 2002
|
||||||
|
+++ apt-0.3.19cnc55/tools/hdlist2pkglist.cc Sun Feb 17 01:46:46 2002
|
||||||
|
@@ -37,6 +37,7 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <rpmlib.h>
|
||||||
|
+#include <rpm/misc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
11
apt-0.3.19cnc53-alt-strsignal.patch
Normal file
11
apt-0.3.19cnc53-alt-strsignal.patch
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
--- apt-0.3.19cnc53/apt-pkg/rpm/rpmpm.cc~ Tue Nov 13 20:32:08 2001
|
||||||
|
+++ apt-0.3.19cnc53/apt-pkg/rpm/rpmpm.cc Fri Nov 16 19:10:19 2001
|
||||||
|
@@ -402,7 +402,7 @@
|
||||||
|
if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
|
||||||
|
{
|
||||||
|
if (WIFSIGNALED(Status) != 0)
|
||||||
|
- return _error->Error(_("Sub-process %s terminated by signal (%i)") ,Args[0], WTERMSIG(Status) );
|
||||||
|
+ return _error->Error(_("Sub-process %s terminated by signal (%s)") ,Args[0], strsignal(WTERMSIG(Status)) );
|
||||||
|
|
||||||
|
if (WIFEXITED(Status) != 0)
|
||||||
|
return _error->Error(_("Sub-process %s returned an error code (%u)"),Args[0],
|
47
apt-0.3.19cnc53-stelian-apt-pkg-algorithms-scores.patch
Normal file
47
apt-0.3.19cnc53-stelian-apt-pkg-algorithms-scores.patch
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
On Tue, Nov 20, 2001 at 02:28:53PM +0200, Matilainen Panu wrote:
|
||||||
|
|
||||||
|
> > I think this is the same bug (if it's a bug of course).
|
||||||
|
[...]
|
||||||
|
> The sane-split? I got it working by changing sane-frontends to have
|
||||||
|
> Provides: sane = %{version}
|
||||||
|
> and sane-backends
|
||||||
|
> Conflicts: sane < %{version}
|
||||||
|
>
|
||||||
|
> With the additional version information it manages to sort this out
|
||||||
|
> correctly.
|
||||||
|
|
||||||
|
I managed to find a hack permitting this to work without any
|
||||||
|
package modifications: when package scores are calculated
|
||||||
|
(based on package priorities and Depends:), I've added some
|
||||||
|
additionnal code to increment the priority of a package which
|
||||||
|
obsoletes another. This additionnal 'point' score makes the
|
||||||
|
right package to be selected for installation.
|
||||||
|
|
||||||
|
It works for me in simple cases, but it definately needs more
|
||||||
|
testing.
|
||||||
|
|
||||||
|
Comments ?
|
||||||
|
|
||||||
|
Stelian.
|
||||||
|
|
||||||
|
|
||||||
|
--- apt-0.3.19cnc53/apt-pkg/algorithms.cc.orig Wed Nov 21 17:45:34 2001
|
||||||
|
+++ apt-0.3.19cnc53/apt-pkg/algorithms.cc Wed Nov 21 17:46:12 2001
|
||||||
|
@@ -454,6 +454,8 @@
|
||||||
|
{
|
||||||
|
if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
Scores[D.TargetPkg()->ID]++;
|
||||||
|
+ if (D->Type == pkgCache::Dep::Obsoletes)
|
||||||
|
+ Scores[I->ID]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
Stelian Pop <stelian.pop@fr.alcove.com>
|
||||||
|
|---------------- Free Software Engineer -----------------|
|
||||||
|
| Alcôve - http://www.alcove.com - Tel: +33 1 49 22 68 00 |
|
||||||
|
|------------- Alcôve, liberating software ---------------|
|
||||||
|
_______________________________________________
|
||||||
|
Apt-rpm mailing list
|
||||||
|
Apt-rpm@distro.conectiva.com.br
|
||||||
|
http://distro.conectiva.com.br/mailman/listinfo/apt-rpm
|
18
apt-0.3.19cnc55-alt-AllowedDupPkgs-HoldPkgs.patch
Normal file
18
apt-0.3.19cnc55-alt-AllowedDupPkgs-HoldPkgs.patch
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
diff -ur apt-0.3.19cnc55~/apt-pkg/init.cc apt-0.3.19cnc55/apt-pkg/init.cc
|
||||||
|
--- apt-0.3.19cnc55~/apt-pkg/init.cc Thu Aug 2 01:35:12 2001
|
||||||
|
+++ apt-0.3.19cnc55/apt-pkg/init.cc Thu Mar 21 18:47:24 2002
|
||||||
|
@@ -38,12 +38,9 @@
|
||||||
|
Cnf.Set("Dir::State::status","/var/lib/dpkg/status");
|
||||||
|
} else {
|
||||||
|
Cnf.Set("Acquire::cdrom::mount", "/mnt/cdrom");
|
||||||
|
- Cnf.Set("RPM::AllowedDupPkgs::","^kernel$");
|
||||||
|
- Cnf.Set("RPM::AllowedDupPkgs::", "kernel-smp");
|
||||||
|
- Cnf.Set("RPM::AllowedDupPkgs::", "kernel-enterprise");
|
||||||
|
+ Cnf.Set("RPM::AllowedDupPkgs::", "^(NVIDIA_)?(kernel|alsa)[0-9]*($|-up|-smp|-secure|-custom|-enterprise|-BOOT|-tape|-aureal)");
|
||||||
|
|
||||||
|
- Cnf.Set("RPM::HoldPkgs::", "kernel-source");
|
||||||
|
- Cnf.Set("RPM::HoldPkgs::", "kernel-headers");
|
||||||
|
+ Cnf.Set("RPM::HoldPkgs::", "^(kernel|alsa)[0-9]*-source");
|
||||||
|
|
||||||
|
Cnf.Set("Dir::State::status","/var/lib/rpm/status");
|
||||||
|
}
|
56
apt-0.3.19cnc55-alt-apt-pkg-rpmpm-execute_rpm.patch
Normal file
56
apt-0.3.19cnc55-alt-apt-pkg-rpmpm-execute_rpm.patch
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
--- apt-0.3.19cnc55~/apt-pkg/rpm/rpmpm.cc Wed Mar 6 20:17:13 2002
|
||||||
|
+++ apt-0.3.19cnc55/apt-pkg/rpm/rpmpm.cc Thu Mar 21 22:35:05 2002
|
||||||
|
@@ -287,14 +287,16 @@
|
||||||
|
case OInstall:
|
||||||
|
options = "-i";
|
||||||
|
|
||||||
|
- Args[n++] = "-i";
|
||||||
|
+ Args[n++] = "-iv";
|
||||||
|
|
||||||
|
Args[n++] = "--replacepkgs";
|
||||||
|
|
||||||
|
if (noninteractive)
|
||||||
|
Args[n++] = "--percent";
|
||||||
|
- else
|
||||||
|
+ else {
|
||||||
|
Args[n++] = "-h";
|
||||||
|
+ Args[n++] = "--fancypercent";
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (_config->FindB("RPM::Force", false) == true)
|
||||||
|
Args[n++] = "--force";
|
||||||
|
@@ -309,8 +311,10 @@
|
||||||
|
|
||||||
|
if (noninteractive)
|
||||||
|
Args[n++] = "--percent";
|
||||||
|
- else
|
||||||
|
+ else {
|
||||||
|
Args[n++] = "-h";
|
||||||
|
+ Args[n++] = "--fancypercent";
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (_config->FindB("RPM::Force", false) == true)
|
||||||
|
Args[n++] = "--force";
|
||||||
|
@@ -330,6 +334,13 @@
|
||||||
|
if (nodeps)
|
||||||
|
Args[n++] = "--nodeps";
|
||||||
|
|
||||||
|
+ string cmd;
|
||||||
|
+ for (unsigned i = 0; i < n; ++i)
|
||||||
|
+ {
|
||||||
|
+ if (cmd.length())
|
||||||
|
+ cmd += ' ';
|
||||||
|
+ cmd += Args[i];
|
||||||
|
+ }
|
||||||
|
|
||||||
|
for (slist<char*>::iterator i = files->begin();
|
||||||
|
i != files->end() && n < sizeof(Args);
|
||||||
|
@@ -349,7 +360,7 @@
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- cout << _("Executing RPM (")<<options<<")..." << endl;
|
||||||
|
+ cout << _("Executing RPM (") << cmd << ")..." << endl;
|
||||||
|
|
||||||
|
cout << flush;
|
||||||
|
clog << flush;
|
95
apt-0.3.19cnc55-alt-enable-rsh-method.patch
Normal file
95
apt-0.3.19cnc55-alt-enable-rsh-method.patch
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
diff -ur apt-0.3.19cnc55/methods/makefile apt-0.3.19cnc53/methods/makefile
|
||||||
|
--- apt-0.3.19cnc55/methods/makefile Fri Aug 10 18:03:50 2001
|
||||||
|
+++ apt-0.3.19cnc53/methods/makefile Thu Mar 21 19:36:03 2002
|
||||||
|
@@ -58,8 +58,8 @@
|
||||||
|
include $(PROGRAM_H)
|
||||||
|
|
||||||
|
# The rsh method
|
||||||
|
-#PROGRAM=rsh
|
||||||
|
-#SLIBS = -lapt-pkg $(SOCKETLIBS) $(RPMLIBS)
|
||||||
|
-#LIB_MAKES = apt-pkg/makefile
|
||||||
|
-#SOURCE = rsh.cc
|
||||||
|
-#include $(PROGRAM_H)
|
||||||
|
+PROGRAM=rsh
|
||||||
|
+SLIBS = -lapt-pkg $(SOCKETLIBS) $(RPMLIBS)
|
||||||
|
+LIB_MAKES = apt-pkg/makefile
|
||||||
|
+SOURCE = rsh.cc
|
||||||
|
+include $(PROGRAM_H)
|
||||||
|
diff -ur apt-0.3.19cnc55/methods/rsh.cc apt-0.3.19cnc53/methods/rsh.cc
|
||||||
|
--- apt-0.3.19cnc55/methods/rsh.cc Fri Nov 30 23:34:13 2001
|
||||||
|
+++ apt-0.3.19cnc53/methods/rsh.cc Thu Mar 21 20:05:08 2002
|
||||||
|
@@ -271,7 +271,7 @@
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool RSHConn::Get(const char *Path,FileFd &To,unsigned long Resume,
|
||||||
|
- Hashes &Hash,bool &Missing, unsigned long Size)
|
||||||
|
+ MD5Summation &MD5,bool &Missing, unsigned long Size)
|
||||||
|
{
|
||||||
|
Missing = false;
|
||||||
|
|
||||||
|
@@ -284,7 +284,7 @@
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Resume != 0) {
|
||||||
|
- if (Hash.AddFD(To.Fd(),Resume) == false) {
|
||||||
|
+ if (MD5.AddFD(To.Fd(),Resume) == false) {
|
||||||
|
_error->Errno("read","Problem hashing file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -323,7 +323,7 @@
|
||||||
|
}
|
||||||
|
MyLen += Res;
|
||||||
|
|
||||||
|
- Hash.Add(Buffer,Res);
|
||||||
|
+ MD5.Add(Buffer,Res);
|
||||||
|
if (To.Write(Buffer,Res) == false)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
@@ -428,7 +428,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the file
|
||||||
|
- Hashes Hash;
|
||||||
|
+ MD5Summation MD5;
|
||||||
|
{
|
||||||
|
FileFd Fd(Itm->DestFile,FileFd::WriteAny);
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
@@ -441,7 +441,7 @@
|
||||||
|
FailFd = Fd.Fd();
|
||||||
|
|
||||||
|
bool Missing;
|
||||||
|
- if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing,Res.Size) == false)
|
||||||
|
+ if (Server->Get(File,Fd,Res.ResumePoint,MD5,Missing,Res.Size) == false)
|
||||||
|
{
|
||||||
|
Fd.Close();
|
||||||
|
|
||||||
|
@@ -462,7 +462,7 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
Res.LastModified = FailTime;
|
||||||
|
- Res.TakeHashes(Hash);
|
||||||
|
+ Res.MD5Sum = MD5.Result();
|
||||||
|
|
||||||
|
// Timestamp
|
||||||
|
struct utimbuf UBuf;
|
||||||
|
diff -ur apt-0.3.19cnc55/methods/rsh.h apt-0.3.19cnc53/methods/rsh.h
|
||||||
|
--- apt-0.3.19cnc55/methods/rsh.h Fri Nov 30 23:34:13 2001
|
||||||
|
+++ apt-0.3.19cnc53/methods/rsh.h Thu Mar 21 20:05:08 2002
|
||||||
|
@@ -12,7 +12,7 @@
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
-#include <apt-pkg/hashes.h>
|
||||||
|
+#include <apt-pkg/md5.h>
|
||||||
|
#include <apt-pkg/acquire-method.h>
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@
|
||||||
|
bool Size(const char *Path,unsigned long &Size);
|
||||||
|
bool ModTime(const char *Path, time_t &Time);
|
||||||
|
bool Get(const char *Path,FileFd &To,unsigned long Resume,
|
||||||
|
- Hashes &Hash,bool &Missing, unsigned long Size);
|
||||||
|
+ MD5Summation &MD5,bool &Missing, unsigned long Size);
|
||||||
|
|
||||||
|
RSHConn(URI Srv);
|
||||||
|
~RSHConn();
|
489
apt-0.3.19cnc55-alt-genbasedir.patch
Normal file
489
apt-0.3.19cnc55-alt-genbasedir.patch
Normal file
@ -0,0 +1,489 @@
|
|||||||
|
--- apt-0.3.19cnc55~/tools/genbasedir Wed Mar 6 20:17:13 2002
|
||||||
|
+++ apt-0.3.19cnc55/tools/genbasedir Thu Mar 21 22:15:32 2002
|
||||||
|
@@ -69,99 +69,103 @@
|
||||||
|
# Language setting to generate a consistent pkglist.
|
||||||
|
#
|
||||||
|
|
||||||
|
-usage="\
|
||||||
|
-Usage: genbasedir [<options>] <distribution> <comp1> [<comp2> ... <compN>]\n\
|
||||||
|
-Options:\n\
|
||||||
|
- -s, --sign Generate and sign hashfile\n\
|
||||||
|
- --hashonly Do hashfile stuff only\n\
|
||||||
|
- --listonly Generate pkglists/srclists and quit\n\
|
||||||
|
- --bz2only Generate only compressed lists\n\
|
||||||
|
- --topdir=dir Top directory of repository\n\
|
||||||
|
- --progress Show progress bars for genpkglist/gensrclist\n\
|
||||||
|
- --updateinfo=file Update information file\n"
|
||||||
|
+PROG="${0##*/}"
|
||||||
|
|
||||||
|
basedir=.
|
||||||
|
signature=0
|
||||||
|
listonly=0
|
||||||
|
hashonly=0
|
||||||
|
-updateinfo=""
|
||||||
|
-mapi=0
|
||||||
|
-bz2only=0
|
||||||
|
+updateinfo=
|
||||||
|
+mapi=
|
||||||
|
+gpguid=
|
||||||
|
+topdir=
|
||||||
|
+bz2only=k
|
||||||
|
progress=
|
||||||
|
|
||||||
|
# bloat is necessary for non-Conectiva distros, at least RH,
|
||||||
|
# because they use file dependencies with a non-predictable
|
||||||
|
# heuristic. So we can't strip-off paths that will probably
|
||||||
|
# never appear in dependencies.
|
||||||
|
-bloat=""
|
||||||
|
-
|
||||||
|
+bloat=
|
||||||
|
|
||||||
|
# flat is for repositories where RPMS and SRPMS are kept in the
|
||||||
|
# same directory level.
|
||||||
|
flat=""
|
||||||
|
|
||||||
|
-while test $# -gt 0 ; do
|
||||||
|
- case "${1}" in
|
||||||
|
- -h | --help)
|
||||||
|
- echo -e "${usage}"
|
||||||
|
- exit 0
|
||||||
|
- ;;
|
||||||
|
- --mapi)
|
||||||
|
- # hee hee hee..
|
||||||
|
- mapi=1
|
||||||
|
- ;;
|
||||||
|
- --listonly)
|
||||||
|
- listonly=1
|
||||||
|
- ;;
|
||||||
|
- --hashonly)
|
||||||
|
- hashonly=1
|
||||||
|
- ;;
|
||||||
|
- --bz2only)
|
||||||
|
- bz2only=1
|
||||||
|
- ;;
|
||||||
|
- --updateinfo=*)
|
||||||
|
- updateinfo=${1}
|
||||||
|
- ;;
|
||||||
|
- --bloat)
|
||||||
|
- bloat="--bloat"
|
||||||
|
- ;;
|
||||||
|
- --flat)
|
||||||
|
- flat="--flat"
|
||||||
|
- ;;
|
||||||
|
- --topdir=*)
|
||||||
|
- topdir="`echo \"${1}\" | sed -e 's/^[^=]*=//'`"
|
||||||
|
- if [ ! -d $topdir ]; then
|
||||||
|
- echo "Invalid top directory for distribution ${topdir}" 1>&2
|
||||||
|
- exit 1
|
||||||
|
- fi
|
||||||
|
- ;;
|
||||||
|
- --progress)
|
||||||
|
- progress="--progress"
|
||||||
|
- ;;
|
||||||
|
- -s | --sign)
|
||||||
|
- signature=1;
|
||||||
|
- ;;
|
||||||
|
- -*)
|
||||||
|
- echo -e "${usage}" 1>&2
|
||||||
|
- exit 1
|
||||||
|
- ;;
|
||||||
|
- *)
|
||||||
|
- break
|
||||||
|
- ;;
|
||||||
|
- esac
|
||||||
|
- shift
|
||||||
|
+USAGE()
|
||||||
|
+{
|
||||||
|
+ cat >&2 <<EOF
|
||||||
|
+Usage: genbasedir [<options>] <distribution> <comp1> [<comp2> ... <compN>]
|
||||||
|
+Options:
|
||||||
|
+ -s, --sign Generate and sign hashfile
|
||||||
|
+ --hashonly Do hashfile stuff only
|
||||||
|
+ --listonly Generate pkglists/srclists and quit
|
||||||
|
+ --bz2only Generate only compressed lists
|
||||||
|
+ --topdir=dir Top directory of repository
|
||||||
|
+ --updateinfo=file Update information file
|
||||||
|
+ --bloat Do not strip the package file list. Needed for some
|
||||||
|
+ distributions that use non-automatically generated file dependencies
|
||||||
|
+ --uid=uid Pass different GPG user ID for signing
|
||||||
|
+ --progress Show progress bars for genpkglist/gensrclist
|
||||||
|
+EOF
|
||||||
|
+ [ -n "$1" ] && exit "$1" || exit
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+TEMP=`getopt -n $PROG -o hs -l help,mapi,listonly,bz2only,hashonly,updateinfo:,bloat,topdir:,sign,uid:,progress -- "$@"` || USAGE
|
||||||
|
+eval set -- "$TEMP"
|
||||||
|
+
|
||||||
|
+while :; do
|
||||||
|
+ case "$1" in
|
||||||
|
+ --listonly) shift; listonly=1
|
||||||
|
+ ;;
|
||||||
|
+ --bz2only) shift; bz2only=
|
||||||
|
+ ;;
|
||||||
|
+ --hashonly) shift; hashonly=1
|
||||||
|
+ ;;
|
||||||
|
+ -s|--sign) shift; signature=1
|
||||||
|
+ ;;
|
||||||
|
+ --bloat) shift; bloat="--bloat"
|
||||||
|
+ ;;
|
||||||
|
+ --mapi) shift; mapi="--mapi"
|
||||||
|
+ ;;
|
||||||
|
+ --updateinfo) shift; updateinfo="$1"; shift
|
||||||
|
+ ;;
|
||||||
|
+ --uid) shift; gpguid="$1"; shift
|
||||||
|
+ ;;
|
||||||
|
+ --topdir) shift; topdir="$1"; shift
|
||||||
|
+ ;;
|
||||||
|
+ --flat) shift; float="--float"
|
||||||
|
+ ;;
|
||||||
|
+ --progress) shift; progress="--progress"
|
||||||
|
+ ;;
|
||||||
|
+ -h|--help) USAGE 0
|
||||||
|
+ ;;
|
||||||
|
+ --) shift; break
|
||||||
|
+ ;;
|
||||||
|
+ *) echo "$PROG: unrecognized option: $1" >&2; exit 1
|
||||||
|
+ ;;
|
||||||
|
+ esac
|
||||||
|
done
|
||||||
|
|
||||||
|
-distro=${1}
|
||||||
|
-shift
|
||||||
|
+topdir="$(echo "$topdir" |sed '
|
||||||
|
+s:/\(\./\)\+:/:g
|
||||||
|
+s:/\+:/:g
|
||||||
|
+s:/$::
|
||||||
|
+')"
|
||||||
|
|
||||||
|
-components=$*
|
||||||
|
+[ -n "$topdir" ] || USAGE 1
|
||||||
|
|
||||||
|
-if [ -z "$components" ]; then
|
||||||
|
- echo -e "${usage}"
|
||||||
|
- exit 0
|
||||||
|
+if [ ! -d "$topdir" ]; then
|
||||||
|
+ echo "Invalid top directory for distribution: $topdir" >&2
|
||||||
|
+ exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
+distro=${1}
|
||||||
|
+shift
|
||||||
|
+
|
||||||
|
+components="$*"
|
||||||
|
+
|
||||||
|
+[ -n "$components" ] || USAGE 1
|
||||||
|
|
||||||
|
getsize() {
|
||||||
|
tmp=`wc -c $1`
|
||||||
|
@@ -186,75 +190,88 @@
|
||||||
|
basedir_=`echo ${distro}/base|tr -s /`
|
||||||
|
basedir=${topdir}/$basedir_
|
||||||
|
|
||||||
|
+WORKDIR=
|
||||||
|
+
|
||||||
|
+Exit()
|
||||||
|
+{
|
||||||
|
+ RETVAL=$?
|
||||||
|
+ trap '' EXIT
|
||||||
|
+ [ -z "$WORKDIR" ] || rm -rf "$WORKDIR"
|
||||||
|
+ exit $RETVAL
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+trap 'Exit ' SIGHUP SIGPIPE SIGINT SIGQUIT SIGTERM EXIT
|
||||||
|
+
|
||||||
|
+WORKDIR="$(mktemp -dt "$PROG.XXXXXXXXXX")"
|
||||||
|
+
|
||||||
|
+SRCIDX_COMP="$WORKDIR/comp"
|
||||||
|
+SRCIDX="$WORKDIR/total"
|
||||||
|
+
|
||||||
|
+saved_list=
|
||||||
|
+
|
||||||
|
+save_file()
|
||||||
|
+{
|
||||||
|
+ saved_list="$1"
|
||||||
|
+
|
||||||
|
+ if [ -f "$saved_list" ]; then
|
||||||
|
+ mv -f "$saved_list" "$saved_list.old"
|
||||||
|
+ else
|
||||||
|
+ saved_list=
|
||||||
|
+ fi
|
||||||
|
+}
|
||||||
|
|
||||||
|
-# release file
|
||||||
|
-# ------------
|
||||||
|
+compare_file()
|
||||||
|
+{
|
||||||
|
+ if [ -n "$saved_list" -a -f "$saved_list.old" ]; then
|
||||||
|
+ if cmp -s "$saved_list.old" "$saved_list"; then
|
||||||
|
+ mv -f "$saved_list.old" "$saved_list"
|
||||||
|
+ else
|
||||||
|
+ rm -f "$saved_list.old"
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+}
|
||||||
|
|
||||||
|
-#for comp in ${components}; do
|
||||||
|
-# true > ${basedir}/release.$comp
|
||||||
|
-#
|
||||||
|
-#done
|
||||||
|
+for comp in ${components}; do
|
||||||
|
+ [ -f "$basedir/release.$comp" ] || touch "$basedir/release.$comp"
|
||||||
|
+done
|
||||||
|
|
||||||
|
|
||||||
|
-if [ $hashonly -ne 1 ]; then
|
||||||
|
+if [ "$hashonly" -ne 1 ]; then
|
||||||
|
# package lists
|
||||||
|
# -------------
|
||||||
|
|
||||||
|
-true > /tmp/srcidx.$$
|
||||||
|
-
|
||||||
|
for comp in ${components}; do
|
||||||
|
echo -n "${comp}: "
|
||||||
|
|
||||||
|
echo -n "pkglist "
|
||||||
|
|
||||||
|
+ newlist="$basedir/pkglist.$comp"
|
||||||
|
+
|
||||||
|
# Save older pkglist
|
||||||
|
- if [ -f $basedir/pkglist.$comp ]; then
|
||||||
|
- mv -f $basedir/pkglist.$comp $basedir/pkglist.$comp.old
|
||||||
|
- fi
|
||||||
|
+ save_file "$newlist"
|
||||||
|
|
||||||
|
- if test x$updateinfo = x; then
|
||||||
|
- (cd $basedir; genpkglist $progress $bloat --index /tmp/srcidx.$comp.$$ $topdir/${distro} $comp)
|
||||||
|
+ :>"$SRCIDX_COMP"
|
||||||
|
+ if [ -z "$updateinfo" ]; then
|
||||||
|
+ (cd "$basedir"; genpkglist $progress $bloat --index "$SRCIDX_COMP" "$topdir/$distro" "$comp")
|
||||||
|
else
|
||||||
|
- (cd $basedir; genpkglist $progress $bloat --index /tmp/srcidx.$comp.$$ --info $updateinfo $topdir/${distro} $comp)
|
||||||
|
+ (cd "$basedir"; genpkglist $progress $bloat --index "$SRCIDX_COMP" --info "$updateinfo" "$topdir/$distro" "$comp")
|
||||||
|
fi
|
||||||
|
+
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "Error executing genpkglist."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- if [ -f $basedir/pkglist.$comp ]; then
|
||||||
|
-
|
||||||
|
- # Compare with older pkglist.
|
||||||
|
- if [ -f $basedir/pkglist.$comp.old ]; then
|
||||||
|
- if cmp -s $basedir/pkglist.$comp.old $basedir/pkglist.$comp; then
|
||||||
|
- mv -f $basedir/pkglist.$comp.old $basedir/pkglist.$comp
|
||||||
|
- fi
|
||||||
|
- fi
|
||||||
|
-
|
||||||
|
- # Save older compressed pkglist
|
||||||
|
- if [ -f $basedir/pkglist.$comp.bz2 ]; then
|
||||||
|
- mv -f $basedir/pkglist.$comp.bz2 $basedir/pkglist.$comp.bz2.old
|
||||||
|
- fi
|
||||||
|
-
|
||||||
|
- bzip2 -c $basedir/pkglist.$comp > $basedir/pkglist.$comp.bz2
|
||||||
|
-
|
||||||
|
- # Compare with older compressed pkglist.
|
||||||
|
- if [ -f $basedir/pkglist.$comp.bz2.old ]; then
|
||||||
|
- if cmp -s $basedir/pkglist.$comp.bz2.old $basedir/pkglist.$comp.bz2; then
|
||||||
|
- mv -f $basedir/pkglist.$comp.bz2.old $basedir/pkglist.$comp.bz2
|
||||||
|
- fi
|
||||||
|
- fi
|
||||||
|
-
|
||||||
|
- if [ $bz2only -eq 1 ]; then
|
||||||
|
- rm -f $basedir/pkglist.$comp
|
||||||
|
- fi
|
||||||
|
+ # Compare with older pkglist.
|
||||||
|
+ compare_file
|
||||||
|
|
||||||
|
- rm -f $basedir/pkglist.$comp.old
|
||||||
|
- rm -f $basedir/pkglist.$comp.bz2.old
|
||||||
|
+ if [ -f "$newlist" ]; then
|
||||||
|
+ rm -f "$newlist.bz2"
|
||||||
|
+ bzip2 -9$bz2only "$newlist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- cat /tmp/srcidx.$comp.$$ >> /tmp/srcidx.$$
|
||||||
|
+ cat "$SRCIDX_COMP" >> "$SRCIDX"
|
||||||
|
|
||||||
|
echo "done"
|
||||||
|
done
|
||||||
|
@@ -264,77 +281,38 @@
|
||||||
|
|
||||||
|
echo -n "srclist "
|
||||||
|
|
||||||
|
- # Save older srclist
|
||||||
|
- if [ -f $basedir/srclist.$comp ]; then
|
||||||
|
- mv -f $basedir/srclist.$comp $basedir/srclist.$comp.old
|
||||||
|
- fi
|
||||||
|
+ newlist="$basedir/srclist.$comp"
|
||||||
|
|
||||||
|
+ # Save older srclist
|
||||||
|
+ save_file "$newlist"
|
||||||
|
|
||||||
|
- sfix="/.."
|
||||||
|
- if test x$flat != x; then
|
||||||
|
- sfix=""
|
||||||
|
- fi
|
||||||
|
+ :>"$SRCIDX_COMP"
|
||||||
|
+ (cd "$basedir"; gensrclist $progress $flat $mapi "$topdir/$distro/.." "$comp" "$SRCIDX_COMP")
|
||||||
|
|
||||||
|
- if [ $mapi -ne 0 ]; then
|
||||||
|
- (cd $basedir; gensrclist $progress $flat --mapi $topdir/${distro}${sfix} $comp /tmp/srcidx.$comp.$$)
|
||||||
|
- else
|
||||||
|
- (cd $basedir; gensrclist $progress $flat $topdir/${distro}${sfix} $comp /tmp/srcidx.$$)
|
||||||
|
- fi
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "Error executing gensrclist."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
+ # Compare with older srclist.
|
||||||
|
+ compare_file
|
||||||
|
|
||||||
|
-
|
||||||
|
- if [ -f $basedir/srclist.$comp ]; then
|
||||||
|
-
|
||||||
|
- # Compare with older srclist.
|
||||||
|
- if [ -f $basedir/srclist.$comp.old ]; then
|
||||||
|
- if cmp -s $basedir/srclist.$comp.old $basedir/srclist.$comp; then
|
||||||
|
- mv -f $basedir/srclist.$comp.old $basedir/srclist.$comp
|
||||||
|
- fi
|
||||||
|
- fi
|
||||||
|
-
|
||||||
|
- # Save older compressed srclist
|
||||||
|
- if [ -f $basedir/srclist.$comp.bz2 ]; then
|
||||||
|
- mv -f $basedir/srclist.$comp.bz2 $basedir/srclist.$comp.bz2.old
|
||||||
|
- fi
|
||||||
|
-
|
||||||
|
- bzip2 -c $basedir/srclist.$comp > $basedir/srclist.$comp.bz2
|
||||||
|
-
|
||||||
|
- # Compare with older compressed srclist.
|
||||||
|
- if [ -f $basedir/srclist.$comp.bz2.old ]; then
|
||||||
|
- if cmp -s $basedir/srclist.$comp.bz2.old $basedir/srclist.$comp.bz2; then
|
||||||
|
- mv -f $basedir/srclist.$comp.bz2.old $basedir/srclist.$comp.bz2
|
||||||
|
- fi
|
||||||
|
- fi
|
||||||
|
-
|
||||||
|
- if [ $bz2only -eq 1 ]; then
|
||||||
|
- rm -f $basedir/srclist.$comp
|
||||||
|
- fi
|
||||||
|
-
|
||||||
|
- rm -f $basedir/srclist.$comp.old
|
||||||
|
- rm -f $basedir/srclist.$comp.bz2.old
|
||||||
|
+ if [ -f "$newlist" ]; then
|
||||||
|
+ rm -f "$newlist.bz2"
|
||||||
|
+ bzip2 -9$bz2only "$newlist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- rm -f /tmp/srcidx.$comp.$$
|
||||||
|
-
|
||||||
|
echo "done"
|
||||||
|
done
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
-rm -f /tmp/srcidx.$$
|
||||||
|
-
|
||||||
|
-if [ $listonly -eq 0 ]; then
|
||||||
|
+if [ "$listonly" -eq 0 ]; then
|
||||||
|
# Save older hashfile
|
||||||
|
- if [ -f $basedir/hashfile ]; then
|
||||||
|
- mv -f $basedir/hashfile $basedir/hashfile.old
|
||||||
|
- fi
|
||||||
|
+ save_file "$basedir/hashfile"
|
||||||
|
hf=${basedir}/hashfile
|
||||||
|
- true > $hf
|
||||||
|
+ : > $hf
|
||||||
|
else
|
||||||
|
hf=/dev/null
|
||||||
|
fi
|
||||||
|
@@ -348,27 +326,21 @@
|
||||||
|
srclist=${basedir}/srclist
|
||||||
|
release=${basedir}/release
|
||||||
|
|
||||||
|
-for comp in ${components}; do
|
||||||
|
- echo -n "${comp}: "
|
||||||
|
-
|
||||||
|
- echo -n "hashfile "
|
||||||
|
- if [ -f ${pkglist}.$comp ]; then
|
||||||
|
- phashstuff ${pkglist}.$comp ${pkglist_}.$comp >> $hf
|
||||||
|
- fi
|
||||||
|
- if [ -f ${srclist}.$comp ]; then
|
||||||
|
- phashstuff ${srclist}.$comp ${srclist_}.$comp >> $hf
|
||||||
|
- fi
|
||||||
|
+phash()
|
||||||
|
+{
|
||||||
|
+ if [ -f "$1" ]; then
|
||||||
|
+ phashstuff "$1" "$2" >> "$3"
|
||||||
|
+ fi
|
||||||
|
+}
|
||||||
|
|
||||||
|
- if [ -f ${pkglist}.$comp.bz2 ]; then
|
||||||
|
- phashstuff ${pkglist}.$comp.bz2 ${pkglist_}.$comp.bz2 >> $hf
|
||||||
|
- fi
|
||||||
|
- if [ -f ${srclist}.$comp.bz2 ]; then
|
||||||
|
- phashstuff ${srclist}.$comp.bz2 ${srclist_}.$comp.bz2 >> $hf
|
||||||
|
- fi
|
||||||
|
+for comp in ${components}; do
|
||||||
|
+ echo -n "$comp: hashfile "
|
||||||
|
|
||||||
|
- if [ -f ${release}.$comp ]; then
|
||||||
|
- phashstuff ${release}.$comp ${release_}.$comp >> $hf
|
||||||
|
- fi
|
||||||
|
+ phash "$pkglist.$comp" "$pkglist_.$comp" "$hf"
|
||||||
|
+ phash "$srclist.$comp" "$srclist_.$comp" "$hf"
|
||||||
|
+ phash "$pkglist.$comp.bz2" "$pkglist_.$comp.bz2" "$hf"
|
||||||
|
+ phash "$srclist.$comp.bz2" "$srclist_.$comp.bz2" "$hf"
|
||||||
|
+ phash "$release.$comp" "$release_.$comp" "$hf"
|
||||||
|
|
||||||
|
echo "done"
|
||||||
|
done
|
||||||
|
@@ -377,34 +349,26 @@
|
||||||
|
|
||||||
|
if [ $listonly -eq 0 ]; then
|
||||||
|
# Compare with older hashfile.
|
||||||
|
- if [ -f $basedir/hashfile.old ]; then
|
||||||
|
- if cmp -s $basedir/hashfile.old $basedir/hashfile; then
|
||||||
|
- mv -f $basedir/hashfile.old $basedir/hashfile
|
||||||
|
- fi
|
||||||
|
- fi
|
||||||
|
+ compare_file
|
||||||
|
fi
|
||||||
|
|
||||||
|
-if [ $signature -ne 0 -a $listonly -eq 0 ]; then
|
||||||
|
+if [ "$signature" -ne 0 -a "$listonly" -eq 0 ]; then
|
||||||
|
+ if [ -n "$gpguid" ]; then
|
||||||
|
+ DEFAULTKEY="--default-key $gpguid"
|
||||||
|
+ else
|
||||||
|
+ DEFAULTKEY=
|
||||||
|
+ fi
|
||||||
|
|
||||||
|
# Save older hashfile.gpg
|
||||||
|
- if [ -f $basedir/hashfile.gpg ]; then
|
||||||
|
- mv -f $basedir/hashfile.gpg $basedir/hashfile.gpg.old
|
||||||
|
- fi
|
||||||
|
+ save_file "$basedir/hashfile.gpg"
|
||||||
|
|
||||||
|
- gpg -armour -qs --yes $basedir/hashfile
|
||||||
|
- mv -f $basedir/hashfile.asc $basedir/hashfile.gpg
|
||||||
|
- rm -f $basedir/hashfile
|
||||||
|
+ gpg -armour $DEFAULTKEY -qs --yes $basedir/hashfile
|
||||||
|
+ mv -f "$basedir/hashfile.asc" "$basedir/hashfile.gpg"
|
||||||
|
+ rm -f "$basedir/hashfile"
|
||||||
|
|
||||||
|
# Compare with older hashfile.gpg
|
||||||
|
- if [ -f $basedir/hashfile.gpg.old ]; then
|
||||||
|
- if cmp -s $basedir/hashfile.gpg.old $basedir/hashfile.gpg; then
|
||||||
|
- mv -f $basedir/hashfile.gpg.old $basedir/hashfile.gpg
|
||||||
|
- fi
|
||||||
|
- fi
|
||||||
|
+ compare_file
|
||||||
|
fi
|
||||||
|
-
|
||||||
|
-rm -f $basedir/hashfile.old
|
||||||
|
-rm -f $basedir/hashfile.gpg.old
|
||||||
|
|
||||||
|
echo "All your base are belong to us !!"
|
||||||
|
|
36
apt.conf
Normal file
36
apt.conf
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
Dir
|
||||||
|
{
|
||||||
|
Bin
|
||||||
|
{
|
||||||
|
Methods "/usr/lib/apt";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
APT
|
||||||
|
{
|
||||||
|
Get
|
||||||
|
{
|
||||||
|
Show-Upgraded "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
GPG
|
||||||
|
{
|
||||||
|
PubringPath "/usr/lib/rpm/gnupg";
|
||||||
|
}
|
||||||
|
|
||||||
|
Architecture "i586";
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug
|
||||||
|
{
|
||||||
|
pkgRPMPM "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
Acquire::CDROM::Copy "true";
|
||||||
|
|
||||||
|
RPM
|
||||||
|
{
|
||||||
|
Options "-vv";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
600
apt.spec
Normal file
600
apt.spec
Normal file
@ -0,0 +1,600 @@
|
|||||||
|
# hey Emacs, its -*- rpm-spec -*-
|
||||||
|
# $Id: apt,v 1.5 2002/03/13 19:01:26 ab Exp $
|
||||||
|
|
||||||
|
Name: apt
|
||||||
|
Version: 0.3.19cnc55
|
||||||
|
Release: alt3
|
||||||
|
|
||||||
|
Summary: Debian's Advanced Packaging Tool with RPM support
|
||||||
|
Summary(ru_RU.CP1251): Debian APT - Óñîâåðøåíñòâîâàííîå ñðåäñòâî óïðàâëåíèÿ ïàêåòàìè ñ ïîääåðæêîé RPM
|
||||||
|
License: GPL
|
||||||
|
Group: System/Configuration/Packaging
|
||||||
|
Packager: APT Development Team <apt@alt-linux.org>
|
||||||
|
|
||||||
|
Source0: %name-%version.tar.bz2
|
||||||
|
Source1: %name.conf
|
||||||
|
Source2: rpmpriorities
|
||||||
|
|
||||||
|
Patch1: %name-0.3.19cnc32-alt-distro.patch
|
||||||
|
Patch2: %name-0.3.19cnc55-alt-AllowedDupPkgs-HoldPkgs.patch
|
||||||
|
Patch3: %name-0.3.19cnc52-alt-INLINEDEPFLAG.patch
|
||||||
|
Patch4: %name-0.3.19cnc53-alt-configure-build.patch
|
||||||
|
Patch5: %name-0.3.19cnc53-alt-strsignal.patch
|
||||||
|
Patch6: %name-0.3.19cnc55-alt-genbasedir.patch
|
||||||
|
Patch7: %name-0.3.19cnc55-alt-apt-pkg-rpmpm-execute_rpm.patch
|
||||||
|
Patch8: %name-0.3.19cnc53-stelian-apt-pkg-algorithms-scores.patch
|
||||||
|
Patch9: %name-0.3.19cnc55-alt-enable-rsh-method.patch
|
||||||
|
|
||||||
|
Requires: lib%name = %version-%release, mktemp >= 1:1.3.1, getopt
|
||||||
|
Requires: %{get_dep rpm}, gnupg, apt-conf
|
||||||
|
|
||||||
|
BuildPreReq: librpm-devel >= 4.0.4, rpm-build >= 4.0.4
|
||||||
|
|
||||||
|
# Automatically added by buildreq on Tue Mar 26 2002
|
||||||
|
BuildRequires: bison bzlib-devel gcc-c++ libbeecrypt libdb4 libpopt-devel librpm-devel libstdc++-devel openjade perl-SGMLSpm zlib-devel
|
||||||
|
|
||||||
|
%description
|
||||||
|
A port of Debian's APT tools for RPM based distributions,
|
||||||
|
or at least for Conectiva. It provides the %name-get utility that
|
||||||
|
provides a simpler, safer way to install and upgrade packages.
|
||||||
|
APT features complete installation ordering, multiple source
|
||||||
|
capability and several other unique features.
|
||||||
|
|
||||||
|
This package is still under development.
|
||||||
|
|
||||||
|
%define risk_usage Äàííûé ïàêåò ïîêà åùå íàõîäèòñÿ â ñòàäèè ðàçðàáîòêè.
|
||||||
|
|
||||||
|
%description -l ru_RU.CP1251
|
||||||
|
Ïåðåíåñåííûå èç Debian ñðåäñòâà óïðàâëåíèÿ ïàêåòàìè APT, âêëþ÷àþùèå
|
||||||
|
â ñåáÿ ïîääåðæêó RPM, âûïîëíåííóþ êîìïàíèåé Conectiva (Áðàçèëèÿ).
|
||||||
|
Ýòîò ïàêåò ñîäåðæèò óòèëèòó %name-get äëÿ ïðîñòîé è íàäåæíîé óñòàíîâêè
|
||||||
|
è îáíîâëåíèÿ ïàêåòîâ. APT óìååò àâòîìàòè÷åñêè ðàçðåøàòü çàâèñèìîñòè
|
||||||
|
ïðè óñòàíîâêå, îáåñïå÷èâàåò óñòàíîâêó èç íåñêîëüêèõ èñòî÷íèêîâ è
|
||||||
|
öåëûé ðÿä äðóãèõ óíèêàëüíûõ âîçìîæíîñòåé.
|
||||||
|
|
||||||
|
%risk_usage
|
||||||
|
|
||||||
|
%package -n lib%name
|
||||||
|
Summary: APT's lib%name-pkg
|
||||||
|
Group: System/Libraries
|
||||||
|
Conflicts: %name < %version-%release
|
||||||
|
|
||||||
|
%package -n lib%name-devel
|
||||||
|
Summary: Development files and documentation for APT's lib%name-pkg
|
||||||
|
Summary(ru_RU.CP1251): Ôàéëû è äîêóìåíòàöèÿ äëÿ ðàçðàáîò÷èêîâ, èñïîëüçóþùèõ lib%name-pkg
|
||||||
|
Group: Development/C
|
||||||
|
Requires: lib%name = %version-%release
|
||||||
|
Provides: %name-devel = %version
|
||||||
|
Obsoletes: %name-devel lib%name-pkg-devel lib%name-pkg-doc
|
||||||
|
|
||||||
|
%package -n lib%name-devel-static
|
||||||
|
Summary: Development static library for APT's lib%name-pkg
|
||||||
|
Summary(ru_RU.CP1251): Ñòàòè÷åñêàÿ áèáëèîòåêà APT äëÿ ðàçðàáîò÷èêîâ, èñïîëüçóþùèõ lib%name-pkg
|
||||||
|
Group: Development/C
|
||||||
|
Requires: lib%name-devel = %version-%release
|
||||||
|
Provides: %name-devel-static = %version
|
||||||
|
Obsoletes: %name-devel-static
|
||||||
|
|
||||||
|
%description -n lib%name
|
||||||
|
This package contains APT's lib%name-pkg package manipulation library,
|
||||||
|
modified for RPM.
|
||||||
|
|
||||||
|
This package is still under development.
|
||||||
|
|
||||||
|
%description -n lib%name-devel
|
||||||
|
This package contains the header files and libraries for developing with
|
||||||
|
APT's lib%name-pkg package manipulation library, modified for RPM.
|
||||||
|
|
||||||
|
This package is still under development.
|
||||||
|
|
||||||
|
%description -n lib%name-devel-static
|
||||||
|
This package contains static libraries for developing with APT's
|
||||||
|
lib%name-pkg package manipulation library, modified for RPM.
|
||||||
|
|
||||||
|
This package is still under development.
|
||||||
|
|
||||||
|
%description -n lib%name -l ru_RU.CP1251
|
||||||
|
 ýòîì ïàêåòå íàõîäèòñÿ lib%name-pkg -- áèáëèîòåêà óïðàâëåíèÿ ïàêåòàìè
|
||||||
|
èç êîìïëåêòà APT.  îòëè÷èå îò îðèãèíàëüíîé âåðñèè äëÿ Debian, ýòîò
|
||||||
|
ïàêåò ñîäåðæèò ïîääåðæêó äëÿ ôîðìàòà RPM.
|
||||||
|
|
||||||
|
%risk_usage
|
||||||
|
|
||||||
|
%description -n lib%name-devel -l ru_RU.CP1251
|
||||||
|
 ýòîì ïàêåòå íàõîäÿòñÿ çàãîëîâî÷íûå ôàéëû è áèáëèîòåêè äëÿ ðàçðàáîòêè
|
||||||
|
ïðîãðàìì, èñïîëüçóþùèõ lib%name-pkg -- áèáëèîòåêó óïðàâëåíèÿ ïàêåòàìè
|
||||||
|
èç êîìïëåêòà APT.  îòëè÷èå îò îðèãèíàëüíîé âåðñèè äëÿ Debian, ýòîò
|
||||||
|
ïàêåò ñîäåðæèò ïîääåðæêó äëÿ ôîðìàòà RPM.
|
||||||
|
|
||||||
|
%risk_usage
|
||||||
|
|
||||||
|
%description -n lib%name-devel-static -l ru_RU.CP1251
|
||||||
|
 ýòîì ïàêåòå íàõîäÿòñÿ ñòàòè÷åñêèå áèáëèîòåêè äëÿ ðàçðàáîòêè ïðîãðàìì,
|
||||||
|
èñïîëüçóþùèõ lib%name-pkg -- áèáëèîòåêó óïðàâëåíèÿ ïàêåòàìè èç
|
||||||
|
êîìïëåêòà APT.  îòëè÷èå îò îðèãèíàëüíîé âåðñèè äëÿ Debian, ýòîò ïàêåò
|
||||||
|
ñîäåðæèò ïîääåðæêó äëÿ ôîðìàòà RPM.
|
||||||
|
|
||||||
|
%risk_usage
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q
|
||||||
|
%patch1 -p1
|
||||||
|
%patch2 -p1
|
||||||
|
%patch3 -p1
|
||||||
|
%patch4 -p1
|
||||||
|
%patch5 -p1
|
||||||
|
%patch6 -p1
|
||||||
|
%patch7 -p1
|
||||||
|
%patch8 -p1
|
||||||
|
%patch9 -p1
|
||||||
|
|
||||||
|
#install -p -m644 %SOURCE3 po/ru.po
|
||||||
|
|
||||||
|
%build
|
||||||
|
%add_optflags -fno-exceptions -D_GNU_SOURCE
|
||||||
|
|
||||||
|
libtoolize --copy --force
|
||||||
|
aclocal -I buildlib
|
||||||
|
autoconf
|
||||||
|
|
||||||
|
# BEGIN HACK: fix broken files.
|
||||||
|
%configure --with-proc-multiply=1 --with-procs=%__nprocs
|
||||||
|
for n in LOCALEDIR `sed -ne 's/.*}\(ENABLE\|HAVE\|NEED\)\(_[A-Z_0-9]*\)\$.*/\1\2/pg' config.status |LC_COLLATE=C sort -u`; do
|
||||||
|
%__grep -Fqs "$n" buildlib/config.h.in || echo "#undef $n"
|
||||||
|
done >config.h.add
|
||||||
|
cat config.h.add >>buildlib/config.h.in
|
||||||
|
# END HACK
|
||||||
|
|
||||||
|
%configure --with-proc-multiply=1 --with-procs=%__nprocs
|
||||||
|
|
||||||
|
find -type f -print0 |
|
||||||
|
xargs -r0 %__grep -EZl '/var(/lib)?/state/%name' |
|
||||||
|
xargs -r0 %__perl -pi -e 's,/var(/lib)?/state/%name,%_localstatedir/%name,g'
|
||||||
|
for f in `find -type f -name '*.[58]'`; do
|
||||||
|
[ -f "$f.yo" ] || touch -r "$f" "$f.yo"
|
||||||
|
done
|
||||||
|
%make clean
|
||||||
|
|
||||||
|
%make_build STATICLIBS=1 NOISY=1
|
||||||
|
tar xzf docs.tar.gz
|
||||||
|
bzip2 -9 docs/*.text
|
||||||
|
|
||||||
|
%install
|
||||||
|
mkdir -p $RPM_BUILD_ROOT{%_bindir,%_libdir/%name,%_mandir/man{5,8},%_includedir/%name-pkg,%_sysconfdir/%name}
|
||||||
|
mkdir -p $RPM_BUILD_ROOT%_localstatedir/%name/lists/partial
|
||||||
|
mkdir -p $RPM_BUILD_ROOT/var/cache/%name/{archives/partial,genpkglist,gensrclist}
|
||||||
|
|
||||||
|
cp -a bin/lib*.so* $RPM_BUILD_ROOT%_libdir
|
||||||
|
cp -a bin/lib*.a* $RPM_BUILD_ROOT%_libdir
|
||||||
|
|
||||||
|
install -p -m755 bin/methods/* $RPM_BUILD_ROOT%_libdir/%name
|
||||||
|
install -p -m755 bin/{%name-*,*list} tools/genbasedir $RPM_BUILD_ROOT%_bindir
|
||||||
|
|
||||||
|
install -p -m644 %name-pkg/{,*/}*.h $RPM_BUILD_ROOT%_includedir/%name-pkg
|
||||||
|
|
||||||
|
install -p -m644 doc/*.5 $RPM_BUILD_ROOT%_man5dir/
|
||||||
|
install -p -m644 doc/*.8 $RPM_BUILD_ROOT%_man8dir/
|
||||||
|
|
||||||
|
install -p -m644 %SOURCE1 %SOURCE2 $RPM_BUILD_ROOT%_sysconfdir/%name
|
||||||
|
|
||||||
|
# Make possible SSH method via RSH one.
|
||||||
|
%__ln_s rsh $RPM_BUILD_ROOT%_libdir/%name/ssh
|
||||||
|
|
||||||
|
%make_install install -C po DESTDIR=$RPM_BUILD_ROOT
|
||||||
|
%find_lang %name
|
||||||
|
|
||||||
|
%post -n lib%name -p /sbin/ldconfig
|
||||||
|
%postun -n lib%name -p /sbin/ldconfig
|
||||||
|
|
||||||
|
%files -f %name.lang
|
||||||
|
%_bindir/*
|
||||||
|
%_libdir/%name
|
||||||
|
%dir %_sysconfdir/%name
|
||||||
|
%config(noreplace) %_sysconfdir/%name/%name.conf
|
||||||
|
%config(noreplace) %_sysconfdir/%name/rpmpriorities
|
||||||
|
%_mandir/man?/*
|
||||||
|
%doc README* TODO docs/examples REPOSITORIO-APT-HOWTO
|
||||||
|
|
||||||
|
%defattr(2770,root,rpm,2770)
|
||||||
|
%_localstatedir/%name
|
||||||
|
%_cachedir/%name
|
||||||
|
|
||||||
|
%files -n lib%name
|
||||||
|
%_libdir/*.so.*
|
||||||
|
|
||||||
|
%files -n lib%name-devel
|
||||||
|
%_libdir/*.so
|
||||||
|
%_includedir/*
|
||||||
|
%doc docs/*.{text.*,html}
|
||||||
|
|
||||||
|
%files -n lib%name-devel-static
|
||||||
|
%_libdir/*.a
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Tue Mar 26 2002 Dmitry V. Levin <ldv@alt-linux.org> 0.3.19cnc55-alt3
|
||||||
|
- Added librpm-4.0.4 build support.
|
||||||
|
- Built with librpm-4.0.4, updated buildrequires.
|
||||||
|
|
||||||
|
* Thu Mar 21 2002 Dmitry V. Levin <ldv@alt-linux.org> 0.3.19cnc55-alt2
|
||||||
|
- Added kernel-aureal and NVIDIA_kernel to default AllowedDupPkgs.
|
||||||
|
- Updated patch for pkgRPMPM::ExecRPM.
|
||||||
|
- Reenabled rsh method.
|
||||||
|
- Updated rpmpriorities.
|
||||||
|
- fixed genbasedir patch.
|
||||||
|
- Set explicit Packager tag.
|
||||||
|
- Dropped obsolete trigger.
|
||||||
|
- lib%name: Conflicts: %name < %%version-%%release.
|
||||||
|
- Renamed patches.
|
||||||
|
|
||||||
|
* Wed Mar 13 2002 Alexander Bokovoy <ab@altlinux.ru> 0.3.19cnc55-alt1
|
||||||
|
- apt-0.3.19cnc55 integrated
|
||||||
|
- Fixed:
|
||||||
|
+ rpmpm-exec_rpm patch
|
||||||
|
+ genbasedir
|
||||||
|
- Removed:
|
||||||
|
+ rpmpm-nodeps patch (already upstream)
|
||||||
|
+ rsh method (already upstream)
|
||||||
|
|
||||||
|
* Mon Dec 10 2001 Dmitry V. Levin <ldv@alt-linux.org> 0.3.19cnc53-alt6
|
||||||
|
- Fixed rpm --nodeps option usage in pkgRPMPM::ExecRPM (#0000215).
|
||||||
|
|
||||||
|
* Fri Nov 23 2001 Dmitry V. Levin <ldv@alt-linux.org> 0.3.19cnc53-alt5
|
||||||
|
- Applied scoring algorithm patch (Stelian Pop <stelian.pop@fr.alcove.com>)
|
||||||
|
- Updated package requires.
|
||||||
|
|
||||||
|
* Mon Nov 19 2001 Dmitry V. Levin <ldv@alt-linux.org> 0.3.19cnc53-alt4
|
||||||
|
- Dropped outdated pofile (already upstream).
|
||||||
|
- Corrected "Executing RPM" message generation.
|
||||||
|
|
||||||
|
* Fri Nov 16 2001 Dmitry V. Levin <ldv@alt-linux.org> 0.3.19cnc53-alt3
|
||||||
|
- Updated patches: genbasedir, configure-db3, i18n.
|
||||||
|
|
||||||
|
* Wed Nov 15 2001 Alexander Bokovoy <ab@altlinux.ru> 0.3.19cnc53-alt2
|
||||||
|
+ apt-0.3.19cnc53-2cl integrated. Most of our patches moved to upstream
|
||||||
|
- Fixed (from Conectiva's changelog):
|
||||||
|
+ fixed bug in mirror patch
|
||||||
|
+ cleaned up gen{pkg,src}list (Alexander Bokovoy <ab@altlinux.ru
|
||||||
|
+ fixed crash bug in genpkglist
|
||||||
|
+ configure.in patch to detect rpmdb (Stelian Pop <stelian.pop@fr.alcove.com>)
|
||||||
|
+ * Skips correctly over empty package directories
|
||||||
|
+ * Adds the --bz2only argument which makes genbasedir
|
||||||
|
+ to generate only the .bz2 compressed versions of pkglist
|
||||||
|
+ and srclist (space gain...)
|
||||||
|
+ * Doesn't change the timestamps on pkglists/srclists if
|
||||||
|
+ the contents are not modified (making possible for example
|
||||||
|
+ to make several consecutive runs of genbasedir without
|
||||||
|
+ having the apt clients download the indexes again and again).
|
||||||
|
+ * Some minor cleanups (remove the temporary files in /tmp
|
||||||
|
+ at the end of the script etc).
|
||||||
|
+ (Stelian Pop <stelian.pop@fr.alcove.com>)
|
||||||
|
+ cleanup patch for gensrclist (Stelian Pop <stelian.pop@fr.alcove.com>)
|
||||||
|
+ fixed multi-arch pkg handling (Stelian Pop <stelian.pop@fr.alcove.com>)
|
||||||
|
+ updated russian translation (Alexander Bokovoy <ab@altlinux.ru>
|
||||||
|
+ updated i18n (Dmitry Levin <ldv@alt-linux.org>)
|
||||||
|
+ replaced Apt::GPG::Pubring with Apt::GPG::PubringPath
|
||||||
|
also uses --homedir instead of --keyring in gpg
|
||||||
|
(Alexander Bokovoy <ab@altlinux.ru>)
|
||||||
|
+ patch to detect replaced (instead of just removed) packages
|
||||||
|
Dmitry Levin <ldv@alt-linux.org>
|
||||||
|
+ updated mirrors patch
|
||||||
|
+ Fixed mirrors infinite loop bug (closes: #4420).
|
||||||
|
+ Fixed error handling.
|
||||||
|
- Added:
|
||||||
|
+ added kernel-tape to default AllowedDupPkgs
|
||||||
|
+ added patch to fix bug in genbasedir with empty dirs
|
||||||
|
(Stelian Pop <stelian.pop@fr.alcove.com>)
|
||||||
|
+ added -K (RPM::Check-Signatures) option to verify rpm sigs
|
||||||
|
+ Added mirrors patch.
|
||||||
|
|
||||||
|
* Fri Nov 02 2001 Dmitry V. Levin <ldv@alt-linux.org> 0.3.19cnc52-alt6
|
||||||
|
- Initial build with rpm4.
|
||||||
|
|
||||||
|
* Thu Oct 04 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc52-alt5
|
||||||
|
- Fixed i18n support and probably smth else
|
||||||
|
(configure.in, config.h.in and i18n.h were broken, kojima sux).
|
||||||
|
- Implemented 18n for apt-pkg/rpm, updated POTFILES.in and russian translation.
|
||||||
|
|
||||||
|
* Mon Oct 01 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc52-alt4
|
||||||
|
- Removed "^(kernel|alsa)[0-9]*-headers" from RPM::HoldPkgs list.
|
||||||
|
- Added (experimental) replaced packages support.
|
||||||
|
|
||||||
|
* Fri Sep 07 2001 Ivan Zakharyaschev <imz@altlinux.ru> 0.3.19cnc52-alt3.1
|
||||||
|
- apt-cdrom fix (patch 6) reworked: apt-cdrom used to not detect a second
|
||||||
|
list file (srclist) if both (pkglist and srclist) were present in one
|
||||||
|
directory on the disk (in non-thorough mode); hopefully now it works how
|
||||||
|
we expect it to do.
|
||||||
|
|
||||||
|
* Thu Aug 09 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc52-alt3
|
||||||
|
- Libification.
|
||||||
|
- Reworked compilation options again: we add only '-fno-exceptions' now.
|
||||||
|
|
||||||
|
* Tue Aug 07 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc52-alt2
|
||||||
|
- More code cleanup in tools/gen{pkg,src}list.cc.
|
||||||
|
- Added %%optflags_nocpp to compilation options.
|
||||||
|
|
||||||
|
* Mon Aug 06 2001 Alexander Bokovoy <ab@altlinux.ru> 0.3.19cnc52-alt1
|
||||||
|
- cnc52, gcc 3 and Solaris fixes
|
||||||
|
- RPM4 check is disabled for the moment
|
||||||
|
- File method fix has been integrated into mainstream
|
||||||
|
- RPM::RemoveOptions, RPM::UpdateOptions have been added
|
||||||
|
- Generation of Package list fixed
|
||||||
|
|
||||||
|
* Thu Aug 02 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc51-alt4
|
||||||
|
- Added trigger for better apt-conf-* migration.
|
||||||
|
|
||||||
|
* Tue Jul 31 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc51-alt3
|
||||||
|
- Updated:
|
||||||
|
+ rpmpriorities,
|
||||||
|
+ AllowedDupPkgs,
|
||||||
|
+ HoldPkgs.
|
||||||
|
- Moved *.list to apt-conf-* packages.
|
||||||
|
|
||||||
|
* Fri Jul 20 2001 Alexander Bokovoy <ab@altlinux.ru> 0.3.19cnc51-alt2
|
||||||
|
- Fixed:
|
||||||
|
+ Bug in file method which prevented authentication from working correctly
|
||||||
|
|
||||||
|
* Fri Jul 20 2001 Alexander Bokovoy <ab@altlinux.ru> 0.3.19cnc51-alt1
|
||||||
|
- cnc51
|
||||||
|
|
||||||
|
* Wed Jun 27 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc46-alt2
|
||||||
|
- cnc46
|
||||||
|
- kernel(|24)-{headers,source} added to HoldPkgs
|
||||||
|
- REPOSITORIO-APT-HOWTO added (Portugal)
|
||||||
|
- AllowedDupPackages -> AllowedDupPkgs
|
||||||
|
|
||||||
|
* Thu Jun 07 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc38-alt4
|
||||||
|
- Various fixes in %_bindir/genbasedir.
|
||||||
|
|
||||||
|
* Thu May 17 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc38-alt3
|
||||||
|
- Fixed build.
|
||||||
|
- Updated rpmpriorities.
|
||||||
|
|
||||||
|
* Mon Apr 16 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc38-alt2
|
||||||
|
- More duplicate packages from kernel series allowed.
|
||||||
|
|
||||||
|
* Sun Apr 15 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc38-alt1
|
||||||
|
- cnc38
|
||||||
|
- Updated:
|
||||||
|
+ apt-cdrom now works correctly
|
||||||
|
+ default architecture has been changed to i586
|
||||||
|
+ ssh method as wrapper to rsh one
|
||||||
|
|
||||||
|
* Mon Mar 19 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc37-ipl3mdk
|
||||||
|
- Updated:
|
||||||
|
+ New patch for genbasedir to allow pass default key to GnuPG
|
||||||
|
|
||||||
|
* Sun Mar 18 2001 Dmitry V. Levin <ldv@altlinux.ru> 0.3.19cnc37-ipl2mdk
|
||||||
|
- Fixed:
|
||||||
|
+ Build/installation of manpages without yodl sources;
|
||||||
|
+ Uncompressed small patches.
|
||||||
|
- Updated:
|
||||||
|
+ AllowedDupPackages list according to new kernel naming scheme;
|
||||||
|
+ URLs to use new domain name.
|
||||||
|
|
||||||
|
* Sat Mar 17 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc37-ipl1mdk
|
||||||
|
- Fixed:
|
||||||
|
+ APT::GPG::Pubring renamed to APT::GPG::PubringPath
|
||||||
|
+ Pubring support patch changed to use --homedir instead of --keyring
|
||||||
|
- Updated:
|
||||||
|
+ APT cnc37
|
||||||
|
+ Fingerprint and repository sources changed to reflect ALT Linux
|
||||||
|
new public key ring
|
||||||
|
|
||||||
|
* Mon Feb 19 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc36-ipl4mdk
|
||||||
|
- Sisyphus source repository added to sources.list
|
||||||
|
|
||||||
|
* Mon Feb 19 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc36-ipl3mdk
|
||||||
|
- New version
|
||||||
|
|
||||||
|
* Fri Feb 16 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc35-ipl2mdk
|
||||||
|
- Static library compilation added
|
||||||
|
- Static library goes to apt-devel-static due sizes of library
|
||||||
|
|
||||||
|
* Thu Feb 15 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc35-ipl1mdk
|
||||||
|
- New version
|
||||||
|
- Rsh method from upstream apt-get ported
|
||||||
|
- Spec file follows libification of rpm now
|
||||||
|
|
||||||
|
* Mon Jan 22 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc32-ipl4mdk
|
||||||
|
- New upstream version
|
||||||
|
- Russian translation updated
|
||||||
|
- Rebuild with new RPM library
|
||||||
|
|
||||||
|
* Mon Jan 22 2001 Alexander Bokovoy <ab@avilink.net> 0.3.19cnc28-ipl1mdk
|
||||||
|
- New upstream version
|
||||||
|
- cnc28 still lacks correct GNUPG checking code, our patch is neccessary.
|
||||||
|
- Genbasedir slightly patched again.
|
||||||
|
|
||||||
|
* Sun Jan 21 2001 Alexander Bokovoy <ab@avilink.net> ipl11mdk
|
||||||
|
- Typo in methods/gpg.cc fixed.
|
||||||
|
|
||||||
|
* Sun Jan 21 2001 Alexander Bokovoy <ab@avilink.net> ipl10mdk
|
||||||
|
- APT::GPG::Pubring option to specify default gnupg public ring added to check
|
||||||
|
distributors' signs automatically via default pubring in RPM package
|
||||||
|
- ftp user password changed to IPL one.
|
||||||
|
|
||||||
|
* Tue Jan 09 2001 Dmitry V. Levin <ldv@fandra.org> 0.3.19cnc27-ipl7mdk
|
||||||
|
- Specfile cleanup.
|
||||||
|
|
||||||
|
* Mon Jan 08 2001 Alexander Bokovoy <ab@avilink.net> ipl5mdk
|
||||||
|
- genbasedir help message fixed
|
||||||
|
|
||||||
|
* Mon Jan 08 2001 Alexander Bokovoy <ab@avilink.net> ipl4mdk
|
||||||
|
- Integration with main IPL package:
|
||||||
|
- Russian translation for command line messages added
|
||||||
|
- Russian translation of package summary/description
|
||||||
|
|
||||||
|
* Thu Jan 04 2001 AEN <aen@logic.ru>
|
||||||
|
- Real Sisyphus URL & IPLabs Fingerptint added
|
||||||
|
- changed rpmpriorities
|
||||||
|
|
||||||
|
* Thu Jan 04 2001 AEN <aen@logic.ru>
|
||||||
|
- build for RE
|
||||||
|
|
||||||
|
* Tue Dec 12 2000 Frederic Lepied <flepied@mandrakesoft.com> 0.3.19cnc27-1mdk
|
||||||
|
- first mandrake version.
|
||||||
|
|
||||||
|
* Thu Dec 07 2000 Andreas Hasenack <andreas@conectiva.com>
|
||||||
|
- damn! Wrong URL in sources.list, atualizacoes.conectiva.com
|
||||||
|
doesn't exist, of course...
|
||||||
|
|
||||||
|
* Thu Dec 07 2000 Andreas Hasenack <andreas@conectiva.com>
|
||||||
|
- updated sources.list with new mirrors and new download tree
|
||||||
|
- removed (noreplace) for the sources.list file for this
|
||||||
|
upgrade. It will be easier for the user. The (noreplace)
|
||||||
|
should be back in place after this update as we expect no
|
||||||
|
further big modifications for that file, only new mirrors.
|
||||||
|
|
||||||
|
* Wed Dec 06 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- fixed prob in vendors.list
|
||||||
|
|
||||||
|
* Tue Dec 05 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc27
|
||||||
|
|
||||||
|
* Wed Nov 08 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc26
|
||||||
|
|
||||||
|
* Mon Nov 06 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc25
|
||||||
|
|
||||||
|
* Thu Nov 02 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc24
|
||||||
|
|
||||||
|
* Thu Nov 02 2000 Rud<E1> Moura <ruda@conectiva.com>
|
||||||
|
- updated source.list (again)
|
||||||
|
|
||||||
|
* Thu Nov 02 2000 Rud<E1> Moura <ruda@conectiva.com>
|
||||||
|
- updated source.list
|
||||||
|
|
||||||
|
* Wed Nov 01 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc23
|
||||||
|
- added cache directories for gen{pkg,src}list
|
||||||
|
- pt_BR manpages
|
||||||
|
|
||||||
|
* Tue Oct 31 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc22
|
||||||
|
- Requires -> PreReq in apt-devel
|
||||||
|
|
||||||
|
* Mon Oct 30 2000 Alfredo Kojima <kojima@conectiva.com>
|
||||||
|
- collapsed libapt-pkg-devel and -doc to apt-devel
|
||||||
|
|
||||||
|
* Mon Oct 30 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc21
|
||||||
|
|
||||||
|
* Sun Oct 29 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc20
|
||||||
|
|
||||||
|
* Sun Oct 29 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc19
|
||||||
|
- added gensrclist
|
||||||
|
- support for apt-get source
|
||||||
|
|
||||||
|
* Fri Oct 27 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc18
|
||||||
|
|
||||||
|
* Thu Oct 26 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc17
|
||||||
|
- new manpages
|
||||||
|
|
||||||
|
* Wed Oct 25 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc16
|
||||||
|
|
||||||
|
* Sun Oct 22 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc15
|
||||||
|
|
||||||
|
* Sat Oct 21 2000 Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
- released version 0.3.19cnc14
|
||||||
|
|
||||||
|
* Thu Oct 19 2000 Claudio Matsuoka <claudio@conectiva.com>
|
||||||
|
- new upstream release: 0.3.9cnc13
|
||||||
|
|
||||||
|
* Tue Oct 17 2000 Eliphas Levy Theodoro <eliphas@conectiva.com>
|
||||||
|
- added rpmpriorities to filelist and install
|
||||||
|
|
||||||
|
* Tue Oct 17 2000 Claudio Matsuoka <claudio@conectiva.com>
|
||||||
|
- updated to 0.3.19cnc12
|
||||||
|
- fresh CVS snapshot including: support to Acquire::ComprExtension,
|
||||||
|
debug messages removed, fixed apt-cdrom, RPM DB path, rpmlib call
|
||||||
|
in pkgRpmLock::Close(), package priority kludge removed, i18n
|
||||||
|
improvements, and genbasedir/genpkglist updates.
|
||||||
|
- handling language setting in genpkglist to make aptitude happy
|
||||||
|
|
||||||
|
* Wed Oct 11 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc11
|
||||||
|
- fixed problem with shard lib symlinks
|
||||||
|
|
||||||
|
* Tue Oct 10 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc10
|
||||||
|
|
||||||
|
* Mon Oct 2 2000 Claudio Matsuoka <claudio@conectiva.com>
|
||||||
|
- fixed brown paper bag bug with method permissions
|
||||||
|
- added parameter --sign to genbasedir
|
||||||
|
- added html/text doc files
|
||||||
|
|
||||||
|
* Sat Sep 30 2000 Claudio Matsuoka <claudio@conectiva.com>
|
||||||
|
- bumped to 0.3.19cnc9
|
||||||
|
- added vendors.list
|
||||||
|
- added gpg method
|
||||||
|
- fixed minor stuff to make Aptitude work
|
||||||
|
- added missing manpages
|
||||||
|
- fixed shared libs
|
||||||
|
- split in apt, libapt-pkg, libapt-pkg-devel, libapt-pkg-doc
|
||||||
|
- rewrote genbasedir in shell script (original was in TCL)
|
||||||
|
- misc cosmetic changes
|
||||||
|
|
||||||
|
* Tue Sep 26 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc8
|
||||||
|
|
||||||
|
* Wed Sep 20 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc7
|
||||||
|
|
||||||
|
* Mon Sep 18 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc6
|
||||||
|
|
||||||
|
* Sat Sep 16 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc5
|
||||||
|
|
||||||
|
* Fri Sep 15 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc4
|
||||||
|
|
||||||
|
* Mon Sep 12 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- released version 0.3.19cnc3
|
||||||
|
|
||||||
|
* Mon Sep 5 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- renamed package to apt, with version 0.3.19cncV
|
||||||
|
|
||||||
|
* Mon Sep 5 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- 0.10
|
||||||
|
- added genpkglist and rapt-config
|
||||||
|
- program names changed back to apt-*
|
||||||
|
|
||||||
|
* Mon Sep 4 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- 0.9
|
||||||
|
|
||||||
|
* Mon Sep 4 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- 0.8
|
||||||
|
|
||||||
|
* Mon Sep 4 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- 0.7
|
||||||
|
|
||||||
|
* Fri Sep 1 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- fixed typo in sources.list
|
||||||
|
|
||||||
|
* Tue Aug 31 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- version 0.6
|
||||||
|
|
||||||
|
* Tue Aug 31 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- version 0.5
|
||||||
|
|
||||||
|
* Tue Aug 31 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- version 0.4
|
||||||
|
|
||||||
|
* Wed Aug 30 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- version 0.3
|
||||||
|
|
||||||
|
* Thu Aug 28 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- second try. new release with direct hdlist handling
|
||||||
|
|
||||||
|
* Thu Aug 10 2000 Alfredo K. Kojima <kojima@conectiva.com>
|
||||||
|
- initial package creation. Yeah, it's totally broken for sure.
|
||||||
|
|
28
apt/AUTHORS
Normal file
28
apt/AUTHORS
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
The project hierachy stands at:
|
||||||
|
|
||||||
|
CVS:jgg Jason Gunthorpe <jgg@debian.org>
|
||||||
|
- Project leader
|
||||||
|
|
||||||
|
CVS:srivasta Manoj Srivastava <srivasta@datasync.com>
|
||||||
|
- Dependency Expert
|
||||||
|
|
||||||
|
CVS:che Ben Gertzfield <che@debian.org>
|
||||||
|
- Packaging and Releases
|
||||||
|
|
||||||
|
CVS:branden Branden Robinson <branden@purdue.edu>
|
||||||
|
- Man Page Documentation
|
||||||
|
|
||||||
|
CVS:doogie Adam Heath <doogie@debian.org>
|
||||||
|
- FTP method author
|
||||||
|
|
||||||
|
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
|
||||||
|
Many other bug reports through the Debian Bug system
|
||||||
|
|
||||||
|
NOTE: The ChangeLog generator will parse for names and email addresses. The
|
||||||
|
'CVS:<name>' tag should indicate who this pair refers to.
|
||||||
|
|
15
apt/AUTHORS.RPM
Normal file
15
apt/AUTHORS.RPM
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
RPM port brought to you by
|
||||||
|
Alfredo K. Kojima <kojima@conectiva.com.br>
|
||||||
|
with consulting help from:
|
||||||
|
Packaging: Ruda Moura <ruda@conectiva.com.br>
|
||||||
|
Security: Andreas Hasenack <andreas@conectiva.com.br>
|
||||||
|
Misc.: Claudio Matsuoka <claudio@conectiva.com.br>
|
||||||
|
|
||||||
|
|
||||||
|
added user specified public keyring option for gpg, fixed a bug
|
||||||
|
in the file method with authentication
|
||||||
|
Alexander Bokovoy <ab@avilink.net>
|
||||||
|
|
||||||
|
solaris portability fixes
|
||||||
|
AUSTIN MURPHY <amurphy@nbcs.rutgers.edu>
|
71
apt/COMPILING
Normal file
71
apt/COMPILING
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
General Information
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
To compile this you need a couple things
|
||||||
|
- A working POSIX system with working POSIX gcc, g++, make (GNU),
|
||||||
|
ar, sh, awk and sed in the path
|
||||||
|
- GNU Make 3.74 or so, -- normal UNIX make will NOT work
|
||||||
|
* Note 3.77 is broken.
|
||||||
|
- A working ANSI C++ compiler, this is not g++ 2.7.*
|
||||||
|
g++ 2.8 works OK and newer egcs work well also. Nobody has tried it
|
||||||
|
on other compilers :< You will need a properly working STL as well.
|
||||||
|
- A C library with the usual POSIX functions and a BSD socket layer.
|
||||||
|
If you OS conforms to the Single User Spec then you are fine:
|
||||||
|
http://www.opengroup.org/onlinepubs/7908799/index.html
|
||||||
|
|
||||||
|
Guidelines
|
||||||
|
~~~~~~~~~~
|
||||||
|
I am not interested in making 'ultra portable code'. I will accept patches
|
||||||
|
to make the code that already exists conform more to SUS or POSIX, but
|
||||||
|
I don't really care if your not-SUS OS doesn't work. It is simply too
|
||||||
|
much work to maintain patches for dysfunctional OSs. I highly suggest you
|
||||||
|
contact your vendor and express intrest in a conforming C library.
|
||||||
|
|
||||||
|
That said, there are lots of finniky problems that must be delt with even
|
||||||
|
between the supported OS's. Primarily the path I choose to take is to put
|
||||||
|
a shim header file in build/include that transparently adds the required
|
||||||
|
functionality. Patches to make autoconf detect these cases and generate the
|
||||||
|
required shims are OK.
|
||||||
|
|
||||||
|
Current shims:
|
||||||
|
* C9x integer types 'inttypes.h'
|
||||||
|
* sys/statvfs.h to convert from BSD/Linux statfs to SUS statvfs
|
||||||
|
* rfc2553 hostname resolution (methods/rfc*), shims to normal gethostbyname.
|
||||||
|
The more adventerous could steal the KAME IPv6 enabled resolvers for those
|
||||||
|
OS's with IPv6 support but no rfc2553 (why?)
|
||||||
|
* define _XOPEN_EXTENDES_SOURCE to bring in h_errno on HP-UX
|
||||||
|
* socklen_t shim in netdb.h if the OS does not have socklen_t
|
||||||
|
|
||||||
|
The only completely non-shimed OS is Linux with glibc2.1, glibc2.0 requires
|
||||||
|
the first three shims.
|
||||||
|
|
||||||
|
Platform Notes
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
Debian GNU Linux 2.1 'slink'
|
||||||
|
Debian GNU Linux 'potato'
|
||||||
|
* All Archs
|
||||||
|
- Works flawlessly
|
||||||
|
- You will want to have debiandoc-sgml and yodl installed to get
|
||||||
|
best results.
|
||||||
|
- No IPv6 Support in glibc's < 2.1.
|
||||||
|
|
||||||
|
Sun Solaris
|
||||||
|
SunOS cab101 5.7 Generic_106541-04 sun4u sparc
|
||||||
|
- Works fine
|
||||||
|
- Note, no IPv6 Support, OS lacks RFC 2553 hostname resolution
|
||||||
|
|
||||||
|
OpenBSD
|
||||||
|
OpenBSD gsb086 2.5 CMPUT#0 i386 unknown
|
||||||
|
- Works fine
|
||||||
|
- OS needs 'ranlib' to generate the symbol table after 'ar'.. (not using
|
||||||
|
GNU ar with the gnu tool chain :<)
|
||||||
|
- Note, no IPv6 Support, OS lacks RFC 2553 hostname resolution
|
||||||
|
|
||||||
|
HP-UX
|
||||||
|
HP-UX nyquist B.10.20 C 9000/780 2016574337 32-user license
|
||||||
|
- Evil OS, does not conform very well to SUS
|
||||||
|
1) snprintf exists but is not prototyped, ignore spurios warnings
|
||||||
|
2) No socklen_t
|
||||||
|
3) Requires -D_XOPEN_SOURCE_EXTENDED for h_errno
|
||||||
|
configure should fix the last two (see above)
|
||||||
|
- Note, no IPv6 Support, OS lacks RFC 2553 hostname resolution
|
||||||
|
|
142
apt/COPYING
Normal file
142
apt/COPYING
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
Apt is copyright 1997, 1998, 1999 Jason Gunthorpe and others.
|
||||||
|
|
||||||
|
Apt is licened under the terms of the GNU General Public License (GPL),
|
||||||
|
version 2.0 or later, as published by the Free Software Foundation. See
|
||||||
|
the file COPYING.GPL [included], /usr/share/common-licenses/GPL, or
|
||||||
|
<http://www.gnu.org/copyleft/gpl.txt> for the terms of the latest version
|
||||||
|
of the GNU General Public License.
|
||||||
|
|
||||||
|
In addition, prior to November 15th, 2000, apt may be distributed under
|
||||||
|
terms identical to the above with the following addition:
|
||||||
|
|
||||||
|
Works using apt may link against the GUI library "libqt", copyright by
|
||||||
|
Troll Tech AS, Norway, provided that:
|
||||||
|
|
||||||
|
1. The version of "libqt" is licensed under the terms of the "Qt Free Edition
|
||||||
|
License" published by Troll Tech AS. The license terms identified as
|
||||||
|
the Qt Free Edition License below are the only such terms under which
|
||||||
|
distribution of works derived from both apt and "libqt" are permitted;
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
2. The source code of the version of "libqt" used is
|
||||||
|
|
||||||
|
a) Distributed with the binary version;
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
b) Downloadable by anyone, without fee, using a publicly-announced
|
||||||
|
URL on the Internet, for a duration of at least three years
|
||||||
|
starting with distribution of the binary version.
|
||||||
|
|
||||||
|
On and after November 15th, 2000, the above additional terms lose all
|
||||||
|
force, and apt will be licensed only under the terms of the GNU General
|
||||||
|
Public License, version 2.0 or later.
|
||||||
|
|
||||||
|
_______________________________________________________________
|
||||||
|
|
||||||
|
The following text, up to the text of the Qt Free Edition License, is
|
||||||
|
informational and not part of the license terms on apt.
|
||||||
|
|
||||||
|
Modifications to apt in either source or compiled form must be licensed
|
||||||
|
under the terms of the GNU General Public License, version 2.0 (or later),
|
||||||
|
but need not include the above clause permitting usage of the "libqt"
|
||||||
|
library under the Qt Free Edition License. Note that removal of this
|
||||||
|
clause will result in software which is not licensed for binary
|
||||||
|
redistribution linked against software governed by the Qt Free Edition
|
||||||
|
License. In the event that a version of "libqt" is released that is
|
||||||
|
licensed under terms that do not conflict with the GPL, the additional
|
||||||
|
clause above is not required to grant permission for distribution of works
|
||||||
|
that are derived from both apt and "libqt".
|
||||||
|
|
||||||
|
No part of apt is licensed under the Qt Free Edition License. The terms
|
||||||
|
below are provided to help identify the circumstances under which the
|
||||||
|
"libqt" library may be used with apt (or a work derived from both). The
|
||||||
|
terms below are copied from the LICENSE file of the qt-1.44 distribution,
|
||||||
|
as of November 10th, 1999.
|
||||||
|
|
||||||
|
_______________________________________________________________
|
||||||
|
|
||||||
|
QT FREE EDITION LICENSE
|
||||||
|
|
||||||
|
Copyright (C) 1992-1999 Troll Tech AS. All rights reserved.
|
||||||
|
|
||||||
|
This is the license for Qt Free Edition version 1.44; it covers private use,
|
||||||
|
use of third-party application programs based on Qt, and development of
|
||||||
|
free software for the free software community.
|
||||||
|
|
||||||
|
|
||||||
|
COPYRIGHT AND RESTRICTIONS
|
||||||
|
|
||||||
|
The Qt toolkit is a product of Troll Tech AS. The Qt Free Edition is limited
|
||||||
|
to use with the X Window System.
|
||||||
|
|
||||||
|
You may copy this version of the Qt Free Edition provided that the entire
|
||||||
|
archive is distributed unchanged and as a whole, including this notice.
|
||||||
|
|
||||||
|
You may use this version of the Qt Free Edition to compile, link and run
|
||||||
|
application programs legally developed by third parties.
|
||||||
|
|
||||||
|
You may use the Qt Free Edition to create application programs
|
||||||
|
provided that:
|
||||||
|
|
||||||
|
You accept this license.
|
||||||
|
Your software does not require modifications to Qt Free Edition.
|
||||||
|
You satisfy ONE of the following three requirements
|
||||||
|
EITHER
|
||||||
|
Users of your software can freely obtain source code for the
|
||||||
|
software, freely modify the source code (possibly with
|
||||||
|
restrictions on copyright notices, attributions and legal
|
||||||
|
responsibility), and freely redistribute original or modified
|
||||||
|
versions of the software.
|
||||||
|
OR
|
||||||
|
Your software is distributed under the GNU GENERAL
|
||||||
|
PUBLIC LICENSE, version 2 or later, as defined by the
|
||||||
|
Free Software Foundation.
|
||||||
|
OR
|
||||||
|
Your software is distributed under the GNU LIBRARY
|
||||||
|
GENERAL PUBLIC LICENSE, version 2 or later, as
|
||||||
|
defined by the Free Software Foundation.
|
||||||
|
|
||||||
|
If you are paid to develop something with Qt Free Edition or it is a part of
|
||||||
|
your job the following conditions also apply:
|
||||||
|
|
||||||
|
Your software must not require libraries, programs, data or
|
||||||
|
documentation that are not available outside your organization in
|
||||||
|
order to compile or use.
|
||||||
|
If and when your organization starts using the software, you must
|
||||||
|
notify Troll Tech AS of the following:
|
||||||
|
Your organization's name and purpose.
|
||||||
|
The software's name and purpose.
|
||||||
|
The software's license.
|
||||||
|
That your organization considers the software to be free
|
||||||
|
software.
|
||||||
|
|
||||||
|
You may also use the Qt Free Edition to create reusable components
|
||||||
|
(such as libraries) provided that you accept the terms above, and in
|
||||||
|
addition that:
|
||||||
|
|
||||||
|
Your components' license includes the following text:
|
||||||
|
|
||||||
|
[Your package] requires the Qt library, which is
|
||||||
|
copyright Troll Tech AS. Freely distributable
|
||||||
|
programs may generally use Qt Free Edition free of
|
||||||
|
charge, see [README.QT] for details.
|
||||||
|
|
||||||
|
README.QT is distributed along with your components.
|
||||||
|
Qt Free Edition is not distributed as an integral part of your
|
||||||
|
components.
|
||||||
|
|
||||||
|
LIMITATIONS OF LIABILITY
|
||||||
|
|
||||||
|
Troll Tech AS makes no obligation under this license to support or
|
||||||
|
upgrade Qt Free Edition, or assist in the use of Qt Free Edition.
|
||||||
|
|
||||||
|
In no event shall Troll Tech AS be liable for any lost revenue or profits or
|
||||||
|
other direct, indirect, special, incidental or consequential damages, even
|
||||||
|
if Troll Tech has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
QT FREE EDITION IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND,
|
||||||
|
INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE.
|
||||||
|
_______________________________________________________________
|
340
apt/COPYING.GPL
Normal file
340
apt/COPYING.GPL
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) 19yy <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
30
apt/CVS/Entries
Normal file
30
apt/CVS/Entries
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/AUTHORS.RPM/1.4/Wed Aug 1 21:35:12 2001//
|
||||||
|
/Makefile/1.4/Wed Aug 1 22:05:11 2001//
|
||||||
|
D/apt-pkg////
|
||||||
|
D/buildlib////
|
||||||
|
D/cmdline////
|
||||||
|
D/debian////
|
||||||
|
D/deity////
|
||||||
|
D/doc////
|
||||||
|
D/dselect////
|
||||||
|
D/gui////
|
||||||
|
D/intl////
|
||||||
|
D/methods////
|
||||||
|
D/po////
|
||||||
|
D/test////
|
||||||
|
D/tools////
|
||||||
|
/AUTHORS/1.1.1.1/Fri Aug 10 13:57:00 2001//
|
||||||
|
/COMPILING/1.1.1.1/Fri Aug 10 13:57:00 2001//
|
||||||
|
/COPYING/1.1.1.1/Fri Aug 10 13:57:01 2001//
|
||||||
|
/COPYING.GPL/1.1.1.1/Fri Aug 10 13:57:02 2001//
|
||||||
|
/ChangeLog/1.2/Fri Aug 10 13:57:23 2001//
|
||||||
|
/README.RPM/1.12/Fri Aug 10 13:57:23 2001//
|
||||||
|
/README.make/1.1.1.1/Fri Aug 10 13:57:24 2001//
|
||||||
|
/REPOSITORIO-APT-HOWTO/1.2/Fri Aug 10 13:57:24 2001//
|
||||||
|
/TODO/1.2/Fri Aug 10 13:57:24 2001//
|
||||||
|
/apt.dia/1.3/Fri Aug 10 13:57:26 2001//
|
||||||
|
/docs.tar.gz/1.1/Fri Aug 10 13:58:18 2001//
|
||||||
|
/mkinstalldirs/1.1/Fri Aug 10 13:58:18 2001//
|
||||||
|
/rpmpriorities/1.2/Fri Aug 10 13:58:19 2001//
|
||||||
|
/configure.in/1.75/Wed Mar 6 17:17:10 2002//
|
||||||
|
/release/1.73/Wed Mar 6 17:17:10 2002//
|
1
apt/CVS/Repository
Normal file
1
apt/CVS/Repository
Normal file
@ -0,0 +1 @@
|
|||||||
|
rapt
|
1
apt/CVS/Root
Normal file
1
apt/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@cvs.conectiva.com.br:/home/cvs
|
1780
apt/ChangeLog
Normal file
1780
apt/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
28
apt/Makefile
Normal file
28
apt/Makefile
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# -*- make -*-
|
||||||
|
|
||||||
|
# This is the top level make file for APT, it recurses to each lower
|
||||||
|
# level make file and runs it with the proper target
|
||||||
|
ifndef NOISY
|
||||||
|
.SILENT:
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: headers library clean veryclean all binary program doc
|
||||||
|
all headers library clean veryclean binary program doc dirs:
|
||||||
|
$(MAKE) -C apt-pkg $@
|
||||||
|
$(MAKE) -C methods $@
|
||||||
|
$(MAKE) -C cmdline $@
|
||||||
|
$(MAKE) -C dselect $@
|
||||||
|
$(MAKE) -C tools $@
|
||||||
|
$(MAKE) -C doc $@
|
||||||
|
|
||||||
|
# Some very common aliases
|
||||||
|
.PHONY: maintainer-clean dist-clean distclean pristine sanity
|
||||||
|
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
|
||||||
|
include buildlib/configure.mak
|
||||||
|
$(BUILDDIR)/include/config.h: buildlib/config.h.in
|
||||||
|
$(BUILDDIR)/environment.mak: buildlib/environment.mak.in
|
||||||
|
$(BUILDDIR)/makefile: buildlib/makefile.in
|
41
apt/README.RPM
Normal file
41
apt/README.RPM
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
|
||||||
|
RPM enabled APT
|
||||||
|
|
||||||
|
WARNING
|
||||||
|
=======
|
||||||
|
This is an EARLY DEVELOPMENT release of apt-get. It might
|
||||||
|
F*&# UP YOUR SYSTEM BEYOND REPAIR. So use at your own
|
||||||
|
risk etc etc bla bla.
|
||||||
|
|
||||||
|
DO NOT TRY TO COMPILE THIS ON A DEBIAN SYSTEM.
|
||||||
|
THIS IS A WORK IN PROGRESS AND WILL NOT WORK ON DEBIAN
|
||||||
|
RIGHT NOW.
|
||||||
|
|
||||||
|
If you find a problem, contact kojima@conectiva.com.br,
|
||||||
|
not the original developers.
|
||||||
|
|
||||||
|
|
||||||
|
WTF is this??
|
||||||
|
=============
|
||||||
|
|
||||||
|
This is a port of debian's apt tools to RPM based
|
||||||
|
distro (at least Conectiva). apt-get is an advanced
|
||||||
|
package management utility frontend (dpkg in debian,
|
||||||
|
rpm in Conectiva and similars), which allows you to easily
|
||||||
|
perform package installation, upgrading and removal.
|
||||||
|
Dependencies are automatically handled, so if you
|
||||||
|
try to install a package that needs others to be installed,
|
||||||
|
it will download all needed packages and install them.
|
||||||
|
|
||||||
|
|
||||||
|
How to Use It
|
||||||
|
=============
|
||||||
|
|
||||||
|
The manpages are properly updated, but if you
|
||||||
|
want simpler/friendlier documentation, you can
|
||||||
|
get the APT+RPM HOWTO at:
|
||||||
|
http://bazar.conectiva.com.br/~godoy/apt-howto/
|
||||||
|
|
||||||
|
|
||||||
|
|
114
apt/README.make
Normal file
114
apt/README.make
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
The Make System
|
||||||
|
~~~ ~~~~ ~~~~~~
|
||||||
|
To compile this program you require GNU Make. In fact you probably need
|
||||||
|
GNU Make 3.76.1 or newer. The makefiles contained make use of many
|
||||||
|
GNU Make specific features and will not run on other makes.
|
||||||
|
|
||||||
|
The make system has a number of interesting properties that are not found
|
||||||
|
in other systems such as automake or the GNU makefile standards. In
|
||||||
|
general some semblance of expectedness is kept so as not to be too
|
||||||
|
surprising. Basically the following will work as expected:
|
||||||
|
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
or
|
||||||
|
cd build
|
||||||
|
../configure
|
||||||
|
make
|
||||||
|
|
||||||
|
There are a number of other things that are possible that may make software
|
||||||
|
development and software packaging simpler. The first of these is the
|
||||||
|
environment.mak file. When configure is run it creates an environment.mak
|
||||||
|
file in the build directory. This contains -all- configurable parameters
|
||||||
|
for all of the make files in all of the subdirectories. Changing one
|
||||||
|
of these parameters will have an immediate effect. The use of makefile.in
|
||||||
|
and configure substitutions across build makefiles is not used at all.
|
||||||
|
|
||||||
|
Furthermore, the make system runs with a current directory equal to the
|
||||||
|
source directory irregardless of the destination directory. This means
|
||||||
|
#include "" and #include <> work as epected and more importantly
|
||||||
|
running 'make' in the source directory will work as expected. The
|
||||||
|
environment variable or make parameter 'BUILD' set the build directory.
|
||||||
|
It may be an absolute path or a path relative to the top level directory.
|
||||||
|
By default build/ will be used with a fall back to ./ This means
|
||||||
|
you can get all the advantages of a build directory without having to
|
||||||
|
cd into it to edit your source code!
|
||||||
|
|
||||||
|
The make system also performs dependency generation on the fly as the
|
||||||
|
compiler runs. This is extremely fast and accurate. There is however
|
||||||
|
one failure condition that occures when a header file is erased. In
|
||||||
|
this case you should run make clean to purge the .o and .d files to
|
||||||
|
rebuild.
|
||||||
|
|
||||||
|
The final significant deviation from normal make practicies is
|
||||||
|
in how the build directory is managed. It is not mearly a mirror of
|
||||||
|
the source directory but is logically divided in the following manner
|
||||||
|
bin/
|
||||||
|
methods/
|
||||||
|
doc/
|
||||||
|
examples/
|
||||||
|
include/
|
||||||
|
apt-pkg/
|
||||||
|
deity/
|
||||||
|
obj/
|
||||||
|
apt-pkg/
|
||||||
|
deity/
|
||||||
|
cmndline/
|
||||||
|
[...]
|
||||||
|
Only .o and .d files are placed in the obj/ subdirectory. The final compiled
|
||||||
|
binaries are placed in bin, published headers for inter-component linking
|
||||||
|
are placed in include/ and documentation is generated into doc/. This means
|
||||||
|
all runnable programs are within the bin/ directory, a huge benifit for
|
||||||
|
debugging inter-program relationships. The .so files are also placed in
|
||||||
|
bin/ for simplicity.
|
||||||
|
|
||||||
|
By default make is put into silent mode. During operation there should be
|
||||||
|
no shell or compiler messages only status messages from the makefiles,
|
||||||
|
if any pop up that indicates there may be a problem with your environment.
|
||||||
|
For debugging you can disable this by setting NOISY=1, ala
|
||||||
|
make NOISY=1
|
||||||
|
|
||||||
|
Using the makefiles
|
||||||
|
~~~~~ ~~~ ~~~~~~~~~
|
||||||
|
The makefiles for the components are really simple. The complexity is hidden
|
||||||
|
within the buildlib/ directory. Each makefile defines a set of make variables
|
||||||
|
for the bit it is going to make then includes a makefile fragment from
|
||||||
|
the buildlib/. This fragment generates the necessary rules based on the
|
||||||
|
originally defined variables. This process can be repeated as many times as
|
||||||
|
necessary for as many programs or libraries as are in the directory.
|
||||||
|
|
||||||
|
Many of the make fragments have some useful properties involving sub
|
||||||
|
directories and other interesting features. They are more completely
|
||||||
|
described in the fragment code in buildlib. Some tips on writing fragments
|
||||||
|
are included in buildlib/defaults.mak
|
||||||
|
|
||||||
|
The fragments are NEVER processed by configure, so if you make changes to
|
||||||
|
them they will have an immediate effect.
|
||||||
|
|
||||||
|
Autoconf
|
||||||
|
~~~~~~~~
|
||||||
|
Straight out of CVS you have to initialize autoconf. This requires
|
||||||
|
automake (I really don't know why) and autoconf and requires doing
|
||||||
|
aclocal -I buidlib
|
||||||
|
autoconf
|
||||||
|
[Altertatively you can run make startup in the top level build dir]
|
||||||
|
|
||||||
|
Autoconf is configured to do some basic system probes for optional and
|
||||||
|
required functionality and generate an environment.mak and include/config.h
|
||||||
|
from it's findings. It will then write a 'makefile' and run make dirs to
|
||||||
|
create the output directory tree.
|
||||||
|
|
||||||
|
It is not my belief that autoconf should be used to generate substantial
|
||||||
|
source code markup to escape OS problems. If an OS problem does crop up
|
||||||
|
it can likely be corrected by installing the correct files into the
|
||||||
|
build include/ dir and perhaps writing some replacement code and
|
||||||
|
linking it in. To the fullest extent possible the source code should conform
|
||||||
|
to standards and not cater to broken systems.
|
||||||
|
|
||||||
|
Autoconf will also wite a makefile into the top level of the build dir,
|
||||||
|
this simply acts as a wrapper to the main top level make in the source tree.
|
||||||
|
There is one big warning, you can't use both this make file and the
|
||||||
|
ones in the top level tree. Make is not able to resolve rules that
|
||||||
|
go to the same file through different paths and this will confuse the
|
||||||
|
depends mechanism. I recommend always using the makefiles in the
|
||||||
|
source directory and exporting BUILD.
|
117
apt/REPOSITORIO-APT-HOWTO
Normal file
117
apt/REPOSITORIO-APT-HOWTO
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Repositório de APT HOWTO
|
||||||
|
|
||||||
|
|
||||||
|
** Ingredientes
|
||||||
|
|
||||||
|
- 1 máquina com acesso rápido à rede e bastante largura de banda
|
||||||
|
- 1 servidor de ftp (anônimo) ou http rodando
|
||||||
|
|
||||||
|
** Modo de Preparo
|
||||||
|
|
||||||
|
1) Vá ao diretório raiz do servidor de ftp/http
|
||||||
|
2) Crie a seguinte estrutura de diretórios nele:
|
||||||
|
|
||||||
|
<versao>/SRPMS/
|
||||||
|
<versao>/conectiva/RPMS.<comp1>/
|
||||||
|
<versao>/conectiva/RPMS.<comp2>/
|
||||||
|
...
|
||||||
|
<versao>/conectiva/RPMS.<compn>/
|
||||||
|
<versao>/conectiva/base/
|
||||||
|
|
||||||
|
Você pode substituir <versao> pela versão da distribuição
|
||||||
|
que será disponibilizada ou se você estiver disponibilizando
|
||||||
|
algum outro software, a versão da distribuição a que se destinam
|
||||||
|
os pacotes.
|
||||||
|
|
||||||
|
<comp1>...<compn> são os diretórios dos componentes da distribuição
|
||||||
|
e podem ser qualquer string.
|
||||||
|
|
||||||
|
No diretório SRPMS devem estar contidos os srpms dos pacotes
|
||||||
|
do repositório.
|
||||||
|
|
||||||
|
3) Crie os arquivos de índice do apt (os pkglists) no diretório base.
|
||||||
|
Para isso, vá ao diretório base e execute o seguinte comando para
|
||||||
|
cada componente:
|
||||||
|
|
||||||
|
genpkglist <path>/<versao> <comp>
|
||||||
|
|
||||||
|
Onde:
|
||||||
|
|
||||||
|
<path>/<versao> é o caminho completo até o topo do diretório onde
|
||||||
|
está o repositório
|
||||||
|
|
||||||
|
<comp> é o nome do componente.
|
||||||
|
|
||||||
|
Repita a operação para cada um dos componentes que você criou.
|
||||||
|
|
||||||
|
4) Comprima os arquivos de índice com gzip.
|
||||||
|
|
||||||
|
5) Distribua a linha do sources.list para o seu repositório. Ela
|
||||||
|
tem o seguinte formato:
|
||||||
|
|
||||||
|
rpm URL/<path> <versao>/conectiva <comp1> <comp2> ... <compn>
|
||||||
|
^ ^ ^ ^ ^ ^ ^
|
||||||
|
| | | +------+------+-----+- Nomes dos
|
||||||
|
| | | componentes
|
||||||
|
| | |
|
||||||
|
| | versao da distribuição e nome da distribuição
|
||||||
|
| |
|
||||||
|
| URL para o diretório raiz do repositório
|
||||||
|
|
|
||||||
|
Tipo de distribuição. No caso, rpm
|
||||||
|
|
||||||
|
** Exemplos:
|
||||||
|
|
||||||
|
## Quer se fazer um repositório de pacotes para o Conectiva 6.0, na máquina
|
||||||
|
repo.conectiva.com.br, usando http:
|
||||||
|
|
||||||
|
cd /home/httpd
|
||||||
|
mkdir -p coisas/6.0
|
||||||
|
cd coisas/6.0
|
||||||
|
mkdir SRPMS
|
||||||
|
mkdir -p conectiva/RPMS.bla
|
||||||
|
mkdir -p conectiva/base
|
||||||
|
cp /meus/pacotes/*src.rpm SRPMS
|
||||||
|
cp /meus/pacotes/*i386.rpm conectiva/RPMS.bla
|
||||||
|
cd conectiva/base
|
||||||
|
genpkglist /home/httpd/coisas/6.0/conectiva bla
|
||||||
|
gzip pkglist.bla
|
||||||
|
|
||||||
|
Em sources.list deve se adicionar:
|
||||||
|
|
||||||
|
rpm http://repo.conectiva.com.br/coisas 6.0/conectiva bla
|
||||||
|
|
||||||
|
|
||||||
|
## Quer se fazer um repositório de pacotes para a distribuição RedRat 20.0,
|
||||||
|
em bla.redrat.com, usando ftp:
|
||||||
|
|
||||||
|
cd /home/ftp/pub
|
||||||
|
mkdir -p stuff/20.0
|
||||||
|
cd stuff/20.0
|
||||||
|
mkdir SRPMS
|
||||||
|
mkdir -p redrat/RPMS.1
|
||||||
|
mkdir -p redrat/RPMS.2
|
||||||
|
mkdir -p redrat/base
|
||||||
|
cp /tmp/pacotes*src.rpm SRPMS
|
||||||
|
cp <bla bla bla> redrat/RPMS.1
|
||||||
|
cp <bla bla bla> redrat/RPMS.2
|
||||||
|
cd redrat/base
|
||||||
|
genpkglist /home/ftp/stuff/20.0/redrat 1
|
||||||
|
genpkglist /home/ftp/stuff/20.0/redrat 2
|
||||||
|
gzip pkglist.1
|
||||||
|
gzip pkglist.2
|
||||||
|
|
||||||
|
Em sources.list deve se adicionar:
|
||||||
|
|
||||||
|
rpm ftp://bla.redrat.com/pub/stuff 20.0/redrat 1 2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
6
apt/TODO
Normal file
6
apt/TODO
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
- check support for installation of packages scattered across multiple CDs
|
||||||
|
- port the authentication stuff to the aliencode branch of APT
|
||||||
|
- port the RPM support to the aliencode branch of APT
|
||||||
|
- rewrite rpm repository maintenance tools
|
||||||
|
- package "hold"ing
|
||||||
|
- package ignoring (exclude from apt-get check)
|
43
apt/apt-pkg/CVS/Entries
Normal file
43
apt/apt-pkg/CVS/Entries
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/init.cc/1.16/Wed Aug 1 21:35:12 2001//
|
||||||
|
D/cnc////
|
||||||
|
D/contrib////
|
||||||
|
D/deb////
|
||||||
|
D/rpm////
|
||||||
|
/acquire-method.cc/1.4/Fri Aug 10 13:58:21 2001//
|
||||||
|
/acquire-method.h/1.2/Fri Aug 10 13:58:24 2001//
|
||||||
|
/acquire-worker.cc/1.2/Fri Aug 10 13:58:24 2001//
|
||||||
|
/acquire-worker.h/1.1.1.1/Fri Aug 10 13:58:24 2001//
|
||||||
|
/acquire.cc/1.3/Fri Aug 10 13:58:24 2001//
|
||||||
|
/acquire.h/1.2/Fri Aug 10 13:58:26 2001//
|
||||||
|
/algorithms.h/1.1.1.1/Fri Aug 10 13:58:29 2001//
|
||||||
|
/cachefile.cc/1.8/Fri Aug 10 13:58:29 2001//
|
||||||
|
/cachefile.h/1.4/Fri Aug 10 13:58:29 2001//
|
||||||
|
/cacheiterators.h/1.2/Fri Aug 10 13:58:31 2001//
|
||||||
|
/clean.cc/1.2/Fri Aug 10 13:58:31 2001//
|
||||||
|
/clean.h/1.1.1.1/Fri Aug 10 13:58:31 2001//
|
||||||
|
/init.h/1.1.1.1/Fri Aug 10 13:58:33 2001//
|
||||||
|
/makefile/1.12/Fri Aug 10 13:58:33 2001//
|
||||||
|
/orderlist.cc/1.4/Fri Aug 10 13:58:34 2001//
|
||||||
|
/orderlist.h/1.1.1.1/Fri Aug 10 13:58:34 2001//
|
||||||
|
/packagemanager.h/1.2/Fri Aug 10 13:59:57 2001//
|
||||||
|
/pkgcache.cc/1.11/Fri Aug 10 14:00:19 2001//
|
||||||
|
/pkgcache.h/1.2/Fri Aug 10 14:00:19 2001//
|
||||||
|
/pkgcachegen.h/1.5/Fri Aug 10 14:00:20 2001//
|
||||||
|
/pkgrecords.cc/1.5/Fri Aug 10 14:00:20 2001//
|
||||||
|
/pkgrecords.h/1.3/Fri Aug 10 14:00:20 2001//
|
||||||
|
/srcrecords.cc/1.4/Fri Aug 10 14:00:21 2001//
|
||||||
|
/srcrecords.h/1.2/Fri Aug 10 14:00:21 2001//
|
||||||
|
/systemfactory.cc/1.8/Fri Aug 10 14:00:23 2001//
|
||||||
|
/systemfactory.h/1.5/Fri Aug 10 14:00:23 2001//
|
||||||
|
/tagfile.cc/1.2/Fri Aug 10 14:00:23 2001//
|
||||||
|
/tagfile.h/1.1.1.1/Fri Aug 10 14:00:23 2001//
|
||||||
|
/version.cc/1.4/Fri Aug 10 14:00:23 2001//
|
||||||
|
/acquire-item.cc/1.20/Tue Nov 13 14:24:16 2001//
|
||||||
|
/acquire-item.h/1.6/Tue Nov 13 14:24:16 2001//
|
||||||
|
/sourcelist.cc/1.25/Tue Nov 13 14:24:16 2001//
|
||||||
|
/sourcelist.h/1.9/Tue Nov 13 14:24:16 2001//
|
||||||
|
/algorithms.cc/1.11/Fri Nov 16 01:13:06 2001//
|
||||||
|
/depcache.cc/1.20/Fri Nov 16 01:13:06 2001//
|
||||||
|
/depcache.h/1.3/Fri Nov 16 01:13:06 2001//
|
||||||
|
/packagemanager.cc/1.15/Fri Nov 16 01:13:06 2001//
|
||||||
|
/pkgcachegen.cc/1.24/Wed Mar 6 17:17:10 2002//
|
1
apt/apt-pkg/CVS/Repository
Normal file
1
apt/apt-pkg/CVS/Repository
Normal file
@ -0,0 +1 @@
|
|||||||
|
rapt/apt-pkg
|
1
apt/apt-pkg/CVS/Root
Normal file
1
apt/apt-pkg/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@cvs.conectiva.com.br:/home/cvs
|
1016
apt/apt-pkg/acquire-item.cc
Normal file
1016
apt/apt-pkg/acquire-item.cc
Normal file
File diff suppressed because it is too large
Load Diff
200
apt/apt-pkg/acquire-item.h
Normal file
200
apt/apt-pkg/acquire-item.h
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: acquire-item.h,v 1.6 2001/11/12 16:34:00 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Acquire Item - Item to acquire
|
||||||
|
|
||||||
|
When an item is instantiated it will add it self to the local list in
|
||||||
|
the Owner Acquire class. Derived classes will then call QueueURI to
|
||||||
|
register all the URI's they wish to fetch at the initial moment.
|
||||||
|
|
||||||
|
Two item classes are provided to provide functionality for downloading
|
||||||
|
of Index files and downloading of Packages.
|
||||||
|
|
||||||
|
A Archive class is provided for downloading .deb files. It does Md5
|
||||||
|
checking and source location as well as a retry algorithm.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_ACQUIRE_ITEM_H
|
||||||
|
#define PKGLIB_ACQUIRE_ITEM_H
|
||||||
|
|
||||||
|
#include <apt-pkg/acquire.h>
|
||||||
|
#include <apt-pkg/sourcelist.h>
|
||||||
|
#include <apt-pkg/pkgrecords.h>
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/acquire-item.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Item to acquire
|
||||||
|
class pkgAcquire::Item
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
bool RecheckFile(string path, string MD5, unsigned long Size);
|
||||||
|
|
||||||
|
// Some private helper methods for registering URIs
|
||||||
|
pkgAcquire *Owner;
|
||||||
|
inline void QueueURI(ItemDesc &Item)
|
||||||
|
{Owner->Enqueue(Item);};
|
||||||
|
inline void Dequeue() {Owner->Dequeue(this);};
|
||||||
|
|
||||||
|
// Safe rename function with timestamp preservation
|
||||||
|
void Rename(string From,string To);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// State of the item
|
||||||
|
enum {StatIdle, StatFetching, StatDone, StatError, StatAuthError} Status;
|
||||||
|
string ErrorText;
|
||||||
|
unsigned long FileSize;
|
||||||
|
unsigned long PartialSize;
|
||||||
|
char *Mode;
|
||||||
|
unsigned long ID;
|
||||||
|
bool Complete;
|
||||||
|
bool Local;
|
||||||
|
|
||||||
|
// Number of queues we are inserted into
|
||||||
|
unsigned int QueueCounter;
|
||||||
|
|
||||||
|
// File to write the fetch into
|
||||||
|
string DestFile;
|
||||||
|
|
||||||
|
// Action members invoked by the worker
|
||||||
|
virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual void Done(string Message,unsigned long Size,string Md5Hash,
|
||||||
|
pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual void Start(string Message,unsigned long Size);
|
||||||
|
virtual string Custom600Headers() {return string();};
|
||||||
|
virtual string DescURI() = 0;
|
||||||
|
virtual void Finished() {};
|
||||||
|
|
||||||
|
// Inquire functions
|
||||||
|
virtual string MD5Sum() {return string();};
|
||||||
|
pkgAcquire *GetOwner() {return Owner;};
|
||||||
|
|
||||||
|
Item(pkgAcquire *Owner);
|
||||||
|
virtual ~Item();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Item class for index files
|
||||||
|
class pkgAcqIndex : public pkgAcquire::Item
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
const pkgSourceList::Item *Location;
|
||||||
|
bool Decompression;
|
||||||
|
bool Erase;
|
||||||
|
pkgAcquire::ItemDesc Desc;
|
||||||
|
unsigned int Retries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Specialized action members
|
||||||
|
virtual void Done(string Message,unsigned long Size,string Md5Hash,
|
||||||
|
pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual string Custom600Headers();
|
||||||
|
virtual string DescURI() {return Location->PackagesURI();};
|
||||||
|
|
||||||
|
pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Item class for index files
|
||||||
|
class pkgAcqIndexRel : public pkgAcquire::Item
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
const pkgSourceList::Item *Location;
|
||||||
|
pkgAcquire::ItemDesc Desc;
|
||||||
|
unsigned int Retries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Specialized action members
|
||||||
|
virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual void Done(string Message,unsigned long Size,string Md5Hash,
|
||||||
|
pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual string Custom600Headers();
|
||||||
|
virtual string DescURI() {return Location->ReleaseURI();};
|
||||||
|
|
||||||
|
pkgAcqIndexRel(pkgAcquire *Owner,const pkgSourceList::Item *Location);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Item class for archive files
|
||||||
|
class pkgAcqArchive : public pkgAcquire::Item
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// State information for the retry mechanism
|
||||||
|
pkgCache::VerIterator Version;
|
||||||
|
pkgAcquire::ItemDesc Desc;
|
||||||
|
pkgSourceList *Sources;
|
||||||
|
pkgRecords *Recs;
|
||||||
|
string MD5;
|
||||||
|
string &StoreFilename;
|
||||||
|
pkgCache::VerFileIterator Vf;
|
||||||
|
unsigned int Retries;
|
||||||
|
|
||||||
|
// Queue the next available file for download.
|
||||||
|
bool QueueNext();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Specialized action members
|
||||||
|
virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual void Done(string Message,unsigned long Size,string Md5Hash,
|
||||||
|
pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual string MD5Sum() {return MD5;};
|
||||||
|
virtual string DescURI() {return Desc.URI;};
|
||||||
|
virtual void Finished();
|
||||||
|
|
||||||
|
pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
|
||||||
|
pkgRecords *Recs,pkgCache::VerIterator const &Version,
|
||||||
|
string &StoreFilename);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Item class for index files
|
||||||
|
class pkgAcqHashes : public pkgAcquire::Item
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool Authentication;
|
||||||
|
pkgSourceList::RepositoryItem *Location;
|
||||||
|
pkgAcquire::ItemDesc Desc;
|
||||||
|
unsigned int Retries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Specialized action members
|
||||||
|
virtual void Done(string Message,unsigned long Size,string Md5Hash,
|
||||||
|
pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual string DescURI() {return Location->HashesURI();};
|
||||||
|
virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
|
||||||
|
|
||||||
|
pkgAcqHashes(pkgAcquire *Owner,
|
||||||
|
pkgSourceList::RepositoryItem *Location);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch a generic file to the current directory
|
||||||
|
class pkgAcqFile : public pkgAcquire::Item
|
||||||
|
{
|
||||||
|
pkgAcquire::ItemDesc Desc;
|
||||||
|
string Md5Hash;
|
||||||
|
unsigned int Retries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Specialized action members
|
||||||
|
virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual void Done(string Message,unsigned long Size,string Md5Hash,
|
||||||
|
pkgAcquire::MethodConfig *Cnf);
|
||||||
|
virtual string MD5Sum() {return Md5Hash;};
|
||||||
|
virtual string DescURI() {return Desc.URI;};
|
||||||
|
|
||||||
|
pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,unsigned long Size,
|
||||||
|
string Desc,string ShortDesc);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
442
apt/apt-pkg/acquire-method.cc
Normal file
442
apt/apt-pkg/acquire-method.cc
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: acquire-method.cc,v 1.4 2001/06/16 01:50:22 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Acquire Method
|
||||||
|
|
||||||
|
This is a skeleton class that implements most of the functionality
|
||||||
|
of a method and some usefull functions to make method implementation
|
||||||
|
simpler. The methods all derive this and specialize it. The most
|
||||||
|
complex implementation is the http method which needs to provide
|
||||||
|
pipelining, it runs the message engine at the same time it is
|
||||||
|
downloading files..
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/acquire-method.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/acquire-method.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// AcqMethod::pkgAcqMethod - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This constructs the initialization text */
|
||||||
|
pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
|
||||||
|
{
|
||||||
|
char S[300] = "";
|
||||||
|
char *End = S;
|
||||||
|
strcat(End,"100 Capabilities\n");
|
||||||
|
snprintf(End+strlen(End),sizeof(S),"Version: %s\n",Ver);
|
||||||
|
|
||||||
|
if ((Flags & SingleInstance) == SingleInstance)
|
||||||
|
strcat(End,"Single-Instance: true\n");
|
||||||
|
|
||||||
|
if ((Flags & Pipeline) == Pipeline)
|
||||||
|
strcat(End,"Pipeline: true\n");
|
||||||
|
|
||||||
|
if ((Flags & SendConfig) == SendConfig)
|
||||||
|
strcat(End,"Send-Config: true\n");
|
||||||
|
|
||||||
|
if ((Flags & LocalOnly) == LocalOnly)
|
||||||
|
strcat(End,"Local-Only: true\n");
|
||||||
|
|
||||||
|
if ((Flags & NeedsCleanup) == NeedsCleanup)
|
||||||
|
strcat(End,"Needs-Cleanup: true\n");
|
||||||
|
|
||||||
|
if ((Flags & Removable) == Removable)
|
||||||
|
strcat(End,"Removable: true\n");
|
||||||
|
strcat(End,"\n");
|
||||||
|
|
||||||
|
if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
|
||||||
|
exit(100);
|
||||||
|
|
||||||
|
SetNonBlock(STDIN_FILENO,true);
|
||||||
|
|
||||||
|
Queue = 0;
|
||||||
|
QueueBack = 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::Fail - A fetch has failed /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcqMethod::Fail(bool Transient)
|
||||||
|
{
|
||||||
|
string Err = "Undetermined Error";
|
||||||
|
if (_error->empty() == false)
|
||||||
|
_error->PopMessage(Err);
|
||||||
|
_error->Discard();
|
||||||
|
Fail(Err,Transient);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::Fail - A fetch has failed /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcqMethod::Fail(string Err,bool Transient)
|
||||||
|
{
|
||||||
|
// Strip out junk from the error messages
|
||||||
|
for (char *I = Err.begin(); I != Err.end(); I++)
|
||||||
|
{
|
||||||
|
if (*I == '\r')
|
||||||
|
*I = ' ';
|
||||||
|
if (*I == '\n')
|
||||||
|
*I = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
char S[1024];
|
||||||
|
if (Queue != 0)
|
||||||
|
{
|
||||||
|
snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n"
|
||||||
|
"Message: %s\n",Queue->Uri.c_str(),Err.c_str());
|
||||||
|
|
||||||
|
// Dequeue
|
||||||
|
FetchItem *Tmp = Queue;
|
||||||
|
Queue = Queue->Next;
|
||||||
|
delete Tmp;
|
||||||
|
if (Tmp == QueueBack)
|
||||||
|
QueueBack = Queue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
|
||||||
|
"Message: %s\n",Err.c_str());
|
||||||
|
|
||||||
|
// Set the transient flag
|
||||||
|
if (Transient == true)
|
||||||
|
strcat(S,"Transient-Failure: true\n\n");
|
||||||
|
else
|
||||||
|
strcat(S,"\n");
|
||||||
|
|
||||||
|
if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcqMethod::URIStart(FetchResult &Res)
|
||||||
|
{
|
||||||
|
if (Queue == 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
char S[1024] = "";
|
||||||
|
char *End = S;
|
||||||
|
|
||||||
|
End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
|
||||||
|
if (Res.Size != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
|
||||||
|
|
||||||
|
if (Res.LastModified != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
|
||||||
|
TimeRFC1123(Res.LastModified).c_str());
|
||||||
|
|
||||||
|
if (Res.ResumePoint != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
|
||||||
|
Res.ResumePoint);
|
||||||
|
|
||||||
|
strcat(End,"\n");
|
||||||
|
if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::URIDone - A URI is finished /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
|
||||||
|
{
|
||||||
|
if (Queue == 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
char S[1024] = "";
|
||||||
|
char *End = S;
|
||||||
|
|
||||||
|
End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
|
||||||
|
|
||||||
|
if (Res.Filename.empty() == false)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
|
||||||
|
|
||||||
|
if (Res.Size != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
|
||||||
|
|
||||||
|
if (Res.LastModified != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
|
||||||
|
TimeRFC1123(Res.LastModified).c_str());
|
||||||
|
|
||||||
|
if (Res.MD5Sum.empty() == false)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
|
||||||
|
|
||||||
|
if (Res.SignatureKeyID.empty() == false)
|
||||||
|
End += snprintf(End,sizeof(S)-80 - (End - S),"Signature-Key: %s\n",
|
||||||
|
Res.SignatureKeyID.c_str());
|
||||||
|
|
||||||
|
if (Res.ResumePoint != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
|
||||||
|
Res.ResumePoint);
|
||||||
|
|
||||||
|
if (Res.IMSHit == true)
|
||||||
|
strcat(End,"IMS-Hit: true\n");
|
||||||
|
End = S + strlen(S);
|
||||||
|
|
||||||
|
if (Alt != 0)
|
||||||
|
{
|
||||||
|
if (Alt->Filename.empty() == false)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
|
||||||
|
|
||||||
|
if (Alt->Size != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
|
||||||
|
|
||||||
|
if (Alt->LastModified != 0)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
|
||||||
|
TimeRFC1123(Alt->LastModified).c_str());
|
||||||
|
|
||||||
|
if (Alt->MD5Sum.empty() == false)
|
||||||
|
End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
|
||||||
|
Alt->MD5Sum.c_str());
|
||||||
|
|
||||||
|
if (Alt->SignatureKeyID.empty() == false)
|
||||||
|
End += snprintf(End,sizeof(S)-80 - (End - S),"Alt-Signature-Key: %s\n",
|
||||||
|
Alt->SignatureKeyID.c_str());
|
||||||
|
|
||||||
|
if (Alt->IMSHit == true)
|
||||||
|
strcat(End,"Alt-IMS-Hit: true\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(End,"\n");
|
||||||
|
if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
|
||||||
|
exit(100);
|
||||||
|
|
||||||
|
// Dequeue
|
||||||
|
FetchItem *Tmp = Queue;
|
||||||
|
Queue = Queue->Next;
|
||||||
|
delete Tmp;
|
||||||
|
if (Tmp == QueueBack)
|
||||||
|
QueueBack = Queue;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::MediaFail - Syncronous request for new media /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This sends a 403 Media Failure message to the APT and waits for it
|
||||||
|
to be ackd */
|
||||||
|
bool pkgAcqMethod::MediaFail(string Required,string Drive)
|
||||||
|
{
|
||||||
|
char S[1024];
|
||||||
|
snprintf(S,sizeof(S),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
|
||||||
|
Required.c_str(),Drive.c_str());
|
||||||
|
|
||||||
|
if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
|
||||||
|
exit(100);
|
||||||
|
|
||||||
|
vector<string> MyMessages;
|
||||||
|
|
||||||
|
/* Here we read messages until we find a 603, each non 603 message is
|
||||||
|
appended to the main message list for later processing */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (WaitFd(STDIN_FILENO) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ReadMessages(STDIN_FILENO,MyMessages) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string Message = MyMessages.front();
|
||||||
|
MyMessages.erase(MyMessages.begin());
|
||||||
|
|
||||||
|
// Fetch the message number
|
||||||
|
char *End;
|
||||||
|
int Number = strtol(Message.c_str(),&End,10);
|
||||||
|
if (End == Message.c_str())
|
||||||
|
{
|
||||||
|
cerr << "Malformed message!" << endl;
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change ack
|
||||||
|
if (Number == 603)
|
||||||
|
{
|
||||||
|
while (MyMessages.empty() == false)
|
||||||
|
{
|
||||||
|
Messages.push_back(MyMessages.front());
|
||||||
|
MyMessages.erase(MyMessages.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
return !StringToBool(LookupTag(Message,"Failed"),false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages.push_back(Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::Configuration - Handle the configuration message /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This parses each configuration entry and puts it into the _config
|
||||||
|
Configuration class. */
|
||||||
|
bool pkgAcqMethod::Configuration(string Message)
|
||||||
|
{
|
||||||
|
::Configuration &Cnf = *_config;
|
||||||
|
|
||||||
|
const char *I = Message.begin();
|
||||||
|
|
||||||
|
unsigned int Length = strlen("Config-Item");
|
||||||
|
for (; I + Length < Message.end(); I++)
|
||||||
|
{
|
||||||
|
// Not a config item
|
||||||
|
if (I[Length] != ':' || stringcasecmp(I,I+Length,"Config-Item") != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
I += Length + 1;
|
||||||
|
|
||||||
|
for (; I < Message.end() && *I == ' '; I++);
|
||||||
|
const char *Equals = I;
|
||||||
|
for (; Equals < Message.end() && *Equals != '='; Equals++);
|
||||||
|
const char *End = Equals;
|
||||||
|
for (; End < Message.end() && *End != '\n'; End++);
|
||||||
|
if (End == Equals)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Cnf.Set(DeQuoteString(string(I,Equals-I)),
|
||||||
|
DeQuoteString(string(Equals+1,End-Equals-1)));
|
||||||
|
I = End;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::Run - Run the message engine /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Fetch any messages and execute them. In single mode it returns 1 if
|
||||||
|
there are no more available messages - any other result is a
|
||||||
|
fatal failure code! */
|
||||||
|
int pkgAcqMethod::Run(bool Single)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// Block if the message queue is empty
|
||||||
|
if (Messages.empty() == true)
|
||||||
|
{
|
||||||
|
if (Single == false)
|
||||||
|
if (WaitFd(STDIN_FILENO) == false)
|
||||||
|
break;
|
||||||
|
if (ReadMessages(STDIN_FILENO,Messages) == false)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single mode exits if the message queue is empty
|
||||||
|
if (Single == true && Messages.empty() == true)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
string Message = Messages.front();
|
||||||
|
Messages.erase(Messages.begin());
|
||||||
|
|
||||||
|
// Fetch the message number
|
||||||
|
char *End;
|
||||||
|
int Number = strtol(Message.c_str(),&End,10);
|
||||||
|
if (End == Message.c_str())
|
||||||
|
{
|
||||||
|
cerr << "Malformed message!" << endl;
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Number)
|
||||||
|
{
|
||||||
|
case 601:
|
||||||
|
if (Configuration(Message) == false)
|
||||||
|
return 100;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 600:
|
||||||
|
{
|
||||||
|
FetchItem *Tmp = new FetchItem;
|
||||||
|
|
||||||
|
Tmp->Uri = LookupTag(Message,"URI");
|
||||||
|
Tmp->DestFile = LookupTag(Message,"FileName");
|
||||||
|
if (StrToTime(LookupTag(Message,"Last-Modified"),Tmp->LastModified) == false)
|
||||||
|
Tmp->LastModified = 0;
|
||||||
|
Tmp->IndexFile = StringToBool(LookupTag(Message,"Index-File"),false);
|
||||||
|
Tmp->Next = 0;
|
||||||
|
|
||||||
|
// Append it to the list
|
||||||
|
FetchItem **I = &Queue;
|
||||||
|
for (; *I != 0; I = &(*I)->Next);
|
||||||
|
*I = Tmp;
|
||||||
|
if (QueueBack == 0)
|
||||||
|
QueueBack = Tmp;
|
||||||
|
|
||||||
|
// Notify that this item is to be fetched.
|
||||||
|
if (Fetch(Tmp) == false)
|
||||||
|
Fail();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::Log - Send a log message /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcqMethod::Log(const char *Format,...)
|
||||||
|
{
|
||||||
|
string CurrentURI = "<UNKNOWN>";
|
||||||
|
if (Queue != 0)
|
||||||
|
CurrentURI = Queue->Uri;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args,Format);
|
||||||
|
|
||||||
|
// sprintf the description
|
||||||
|
char S[1024];
|
||||||
|
unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\nURI: %s\n"
|
||||||
|
"Message: ",CurrentURI.c_str());
|
||||||
|
|
||||||
|
vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
|
||||||
|
strcat(S,"\n\n");
|
||||||
|
|
||||||
|
if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcqMethod::Status - Send a status message /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcqMethod::Status(const char *Format,...)
|
||||||
|
{
|
||||||
|
string CurrentURI = "<UNKNOWN>";
|
||||||
|
if (Queue != 0)
|
||||||
|
CurrentURI = Queue->Uri;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args,Format);
|
||||||
|
|
||||||
|
// sprintf the description
|
||||||
|
char S[1024];
|
||||||
|
unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
|
||||||
|
"Message: ",CurrentURI.c_str());
|
||||||
|
|
||||||
|
vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
|
||||||
|
strcat(S,"\n\n");
|
||||||
|
|
||||||
|
if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcqMethod::FetchResult::FetchResult() : LastModified(0),
|
||||||
|
IMSHit(false), Size(0), ResumePoint(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*}}}*/
|
83
apt/apt-pkg/acquire-method.h
Normal file
83
apt/apt-pkg/acquire-method.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: acquire-method.h,v 1.2 2000/09/26 14:22:14 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Acquire Method - Method helper class + functions
|
||||||
|
|
||||||
|
These functions are designed to be used within the method task to
|
||||||
|
ease communication with APT.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_ACQUIRE_METHOD_H
|
||||||
|
#define PKGLIB_ACQUIRE_METHOD_H
|
||||||
|
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/acquire-method.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class pkgAcqMethod
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct FetchItem
|
||||||
|
{
|
||||||
|
FetchItem *Next;
|
||||||
|
|
||||||
|
string Uri;
|
||||||
|
string DestFile;
|
||||||
|
time_t LastModified;
|
||||||
|
bool IndexFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FetchResult
|
||||||
|
{
|
||||||
|
string MD5Sum;
|
||||||
|
string SignatureKeyID;
|
||||||
|
time_t LastModified;
|
||||||
|
bool IMSHit;
|
||||||
|
string Filename;
|
||||||
|
unsigned long Size;
|
||||||
|
unsigned long ResumePoint;
|
||||||
|
FetchResult();
|
||||||
|
};
|
||||||
|
|
||||||
|
// State
|
||||||
|
vector<string> Messages;
|
||||||
|
FetchItem *Queue;
|
||||||
|
FetchItem *QueueBack;
|
||||||
|
|
||||||
|
// Handlers for messages
|
||||||
|
virtual bool Configuration(string Message);
|
||||||
|
virtual bool Fetch(FetchItem * /*Item*/) {return true;};
|
||||||
|
|
||||||
|
// Outgoing messages
|
||||||
|
void Fail(bool Transient = false);
|
||||||
|
inline void Fail(const char *Why, bool Transient = false) {Fail(string(Why),Transient);};
|
||||||
|
void Fail(string Why, bool Transient = false);
|
||||||
|
void URIStart(FetchResult &Res);
|
||||||
|
void URIDone(FetchResult &Res,FetchResult *Alt = 0);
|
||||||
|
bool MediaFail(string Required,string Drive);
|
||||||
|
virtual void Exit() {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum CnfFlags {SingleInstance = (1<<0),
|
||||||
|
Pipeline = (1<<1), SendConfig = (1<<2),
|
||||||
|
LocalOnly = (1<<3), NeedsCleanup = (1<<4),
|
||||||
|
Removable = (1<<5)};
|
||||||
|
|
||||||
|
void Log(const char *Format,...);
|
||||||
|
void Status(const char *Format,...);
|
||||||
|
|
||||||
|
int Run(bool Single = false);
|
||||||
|
|
||||||
|
pkgAcqMethod(const char *Ver,unsigned long Flags = 0);
|
||||||
|
virtual ~pkgAcqMethod() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
547
apt/apt-pkg/acquire-worker.cc
Normal file
547
apt/apt-pkg/acquire-worker.cc
Normal file
@ -0,0 +1,547 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: acquire-worker.cc,v 1.2 2001/01/11 02:03:26 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Acquire Worker
|
||||||
|
|
||||||
|
The worker process can startup either as a Configuration prober
|
||||||
|
or as a queue runner. As a configuration prober it only reads the
|
||||||
|
configuration message and
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/acquire-worker.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/acquire-worker.h>
|
||||||
|
#include <apt-pkg/acquire-item.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// Worker::Worker - Constructor for Queue startup /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::Worker::Worker(Queue *Q,MethodConfig *Cnf,
|
||||||
|
pkgAcquireStatus *Log) : Log(Log)
|
||||||
|
{
|
||||||
|
OwnerQ = Q;
|
||||||
|
Config = Cnf;
|
||||||
|
Access = Cnf->Access;
|
||||||
|
CurrentItem = 0;
|
||||||
|
TotalSize = 0;
|
||||||
|
CurrentSize = 0;
|
||||||
|
|
||||||
|
Construct();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::Worker - Constructor for method config startup /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::Worker::Worker(MethodConfig *Cnf)
|
||||||
|
{
|
||||||
|
OwnerQ = 0;
|
||||||
|
Config = Cnf;
|
||||||
|
Access = Cnf->Access;
|
||||||
|
CurrentItem = 0;
|
||||||
|
TotalSize = 0;
|
||||||
|
CurrentSize = 0;
|
||||||
|
|
||||||
|
Construct();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::Construct - Constructor helper /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcquire::Worker::Construct()
|
||||||
|
{
|
||||||
|
NextQueue = 0;
|
||||||
|
NextAcquire = 0;
|
||||||
|
Process = -1;
|
||||||
|
InFd = -1;
|
||||||
|
OutFd = -1;
|
||||||
|
OutReady = false;
|
||||||
|
InReady = false;
|
||||||
|
Debug = _config->FindB("Debug::pkgAcquire::Worker",false);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::~Worker - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::Worker::~Worker()
|
||||||
|
{
|
||||||
|
close(InFd);
|
||||||
|
close(OutFd);
|
||||||
|
|
||||||
|
if (Process > 0)
|
||||||
|
{
|
||||||
|
/* Closing of stdin is the signal to exit and die when the process
|
||||||
|
indicates it needs cleanup */
|
||||||
|
if (Config->NeedsCleanup == false)
|
||||||
|
kill(Process,SIGINT);
|
||||||
|
ExecWait(Process,Access.c_str(),true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::Start - Start the worker process /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This forks the method and inits the communication channel */
|
||||||
|
bool pkgAcquire::Worker::Start()
|
||||||
|
{
|
||||||
|
// Get the method path
|
||||||
|
string Method = _config->FindDir("Dir::Bin::Methods") + Access;
|
||||||
|
if (FileExists(Method) == false)
|
||||||
|
return _error->Error(_("The method driver %s could not be found."),Method.c_str());
|
||||||
|
|
||||||
|
if (Debug == true)
|
||||||
|
clog << "Starting method '" << Method << '\'' << endl;
|
||||||
|
|
||||||
|
// Create the pipes
|
||||||
|
int Pipes[4] = {-1,-1,-1,-1};
|
||||||
|
if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0)
|
||||||
|
{
|
||||||
|
_error->Errno("pipe",_("Failed to create IPC pipe to subprocess"));
|
||||||
|
for (int I = 0; I != 4; I++)
|
||||||
|
close(Pipes[I]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int I = 0; I != 4; I++)
|
||||||
|
SetCloseExec(Pipes[I],true);
|
||||||
|
|
||||||
|
// Fork off the process
|
||||||
|
Process = ExecFork();
|
||||||
|
|
||||||
|
// Spawn the subprocess
|
||||||
|
if (Process == 0)
|
||||||
|
{
|
||||||
|
// Setup the FDs
|
||||||
|
dup2(Pipes[1],STDOUT_FILENO);
|
||||||
|
dup2(Pipes[2],STDIN_FILENO);
|
||||||
|
dup2(((filebuf *)clog.rdbuf())->fd(),STDERR_FILENO);
|
||||||
|
SetCloseExec(STDOUT_FILENO,false);
|
||||||
|
SetCloseExec(STDIN_FILENO,false);
|
||||||
|
SetCloseExec(STDERR_FILENO,false);
|
||||||
|
|
||||||
|
const char *Args[2];
|
||||||
|
Args[0] = Method.c_str();
|
||||||
|
Args[1] = 0;
|
||||||
|
execv(Args[0],(char **)Args);
|
||||||
|
cerr << "Failed to exec method " << Args[0] << endl;
|
||||||
|
_exit(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix up our FDs
|
||||||
|
InFd = Pipes[0];
|
||||||
|
OutFd = Pipes[3];
|
||||||
|
SetNonBlock(Pipes[0],true);
|
||||||
|
SetNonBlock(Pipes[3],true);
|
||||||
|
close(Pipes[1]);
|
||||||
|
close(Pipes[2]);
|
||||||
|
OutReady = false;
|
||||||
|
InReady = true;
|
||||||
|
|
||||||
|
// Read the configuration data
|
||||||
|
if (WaitFd(InFd) == false ||
|
||||||
|
ReadMessages() == false)
|
||||||
|
return _error->Error(_("Method %s did not start correctly"),Method.c_str());
|
||||||
|
|
||||||
|
RunMessages();
|
||||||
|
if (OwnerQ != 0)
|
||||||
|
SendConfiguration();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::ReadMessages - Read all pending messages into the list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgAcquire::Worker::ReadMessages()
|
||||||
|
{
|
||||||
|
if (::ReadMessages(InFd,MessageQueue) == false)
|
||||||
|
return MethodFailure();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::RunMessage - Empty the message queue /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This takes the messages from the message queue and runs them through
|
||||||
|
the parsers in order. */
|
||||||
|
bool pkgAcquire::Worker::RunMessages()
|
||||||
|
{
|
||||||
|
while (MessageQueue.empty() == false)
|
||||||
|
{
|
||||||
|
string Message = MessageQueue.front();
|
||||||
|
MessageQueue.erase(MessageQueue.begin());
|
||||||
|
|
||||||
|
if (Debug == true)
|
||||||
|
clog << " <- " << Access << ':' << QuoteString(Message,"\n") << endl;
|
||||||
|
|
||||||
|
// Fetch the message number
|
||||||
|
char *End;
|
||||||
|
int Number = strtol(Message.c_str(),&End,10);
|
||||||
|
if (End == Message.c_str())
|
||||||
|
return _error->Error(_("Invalid message from method %s: %s"),Access.c_str(),Message.c_str());
|
||||||
|
|
||||||
|
string URI = LookupTag(Message,"URI");
|
||||||
|
pkgAcquire::Queue::QItem *Itm = 0;
|
||||||
|
if (URI.empty() == false)
|
||||||
|
Itm = OwnerQ->FindItem(URI,this);
|
||||||
|
|
||||||
|
// Determine the message number and dispatch
|
||||||
|
switch (Number)
|
||||||
|
{
|
||||||
|
// 100 Capabilities
|
||||||
|
case 100:
|
||||||
|
if (Capabilities(Message) == false)
|
||||||
|
return _error->Error(_("Unable to process Capabilities message from %s"),Access.c_str());
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 101 Log
|
||||||
|
case 101:
|
||||||
|
if (Debug == true)
|
||||||
|
clog << " <- (log) " << LookupTag(Message,"Message") << endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 102 Status
|
||||||
|
case 102:
|
||||||
|
Status = LookupTag(Message,"Message");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 200 URI Start
|
||||||
|
case 200:
|
||||||
|
{
|
||||||
|
if (Itm == 0)
|
||||||
|
{
|
||||||
|
_error->Error(_("Method gave invalid 200 URI Start message"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentItem = Itm;
|
||||||
|
CurrentSize = 0;
|
||||||
|
TotalSize = atoi(LookupTag(Message,"Size","0").c_str());
|
||||||
|
ResumePoint = atoi(LookupTag(Message,"Resume-Point","0").c_str());
|
||||||
|
Itm->Owner->Start(Message,atoi(LookupTag(Message,"Size","0").c_str()));
|
||||||
|
|
||||||
|
// Display update before completion
|
||||||
|
if (Log != 0 && Log->MorePulses == true)
|
||||||
|
Log->Pulse(Itm->Owner->GetOwner());
|
||||||
|
|
||||||
|
if (Log != 0)
|
||||||
|
Log->Fetch(*Itm);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 201 URI Done
|
||||||
|
case 201:
|
||||||
|
{
|
||||||
|
if (Itm == 0)
|
||||||
|
{
|
||||||
|
_error->Error("Method gave invalid 201 URI Done message");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgAcquire::Item *Owner = Itm->Owner;
|
||||||
|
pkgAcquire::ItemDesc Desc = *Itm;
|
||||||
|
|
||||||
|
// Display update before completion
|
||||||
|
if (Log != 0 && Log->MorePulses == true)
|
||||||
|
Log->Pulse(Owner->GetOwner());
|
||||||
|
|
||||||
|
OwnerQ->ItemDone(Itm);
|
||||||
|
if (TotalSize != 0 &&
|
||||||
|
(unsigned)atoi(LookupTag(Message,"Size","0").c_str()) != TotalSize)
|
||||||
|
_error->Warning(_("Bizzar Error - File size is not what the server reported %s %u"),
|
||||||
|
LookupTag(Message,"Size","0").c_str(),TotalSize);
|
||||||
|
|
||||||
|
Owner->Done(Message,atoi(LookupTag(Message,"Size","0").c_str()),
|
||||||
|
LookupTag(Message,"MD5-Hash"),Config);
|
||||||
|
ItemDone();
|
||||||
|
|
||||||
|
// Log that we are done
|
||||||
|
if (Log != 0)
|
||||||
|
{
|
||||||
|
if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true ||
|
||||||
|
StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
|
||||||
|
{
|
||||||
|
/* Hide 'hits' for local only sources - we also manage to
|
||||||
|
hide gets */
|
||||||
|
if (Config->LocalOnly == false)
|
||||||
|
Log->IMSHit(Desc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Log->Done(Desc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 400 URI Failure
|
||||||
|
case 400:
|
||||||
|
{
|
||||||
|
if (Itm == 0)
|
||||||
|
{
|
||||||
|
_error->Error(_("Method gave invalid 400 URI Failure message"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display update before completion
|
||||||
|
if (Log != 0 && Log->MorePulses == true)
|
||||||
|
Log->Pulse(Itm->Owner->GetOwner());
|
||||||
|
|
||||||
|
pkgAcquire::Item *Owner = Itm->Owner;
|
||||||
|
pkgAcquire::ItemDesc Desc = *Itm;
|
||||||
|
OwnerQ->ItemDone(Itm);
|
||||||
|
Owner->Failed(Message,Config);
|
||||||
|
ItemDone();
|
||||||
|
|
||||||
|
if (Log != 0)
|
||||||
|
Log->Fail(Desc);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 401 General Failure
|
||||||
|
case 401:
|
||||||
|
_error->Error(_("Method %s General failure: %s"),LookupTag(Message,"Message").c_str());
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 403 Media Change
|
||||||
|
case 403:
|
||||||
|
MediaChange(Message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::Capabilities - 100 Capabilities handler /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This parses the capabilities message and dumps it into the configuration
|
||||||
|
structure. */
|
||||||
|
bool pkgAcquire::Worker::Capabilities(string Message)
|
||||||
|
{
|
||||||
|
if (Config == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Config->Version = LookupTag(Message,"Version");
|
||||||
|
Config->SingleInstance = StringToBool(LookupTag(Message,"Single-Instance"),false);
|
||||||
|
Config->Pipeline = StringToBool(LookupTag(Message,"Pipeline"),false);
|
||||||
|
Config->SendConfig = StringToBool(LookupTag(Message,"Send-Config"),false);
|
||||||
|
Config->LocalOnly = StringToBool(LookupTag(Message,"Local-Only"),false);
|
||||||
|
Config->NeedsCleanup = StringToBool(LookupTag(Message,"Needs-Cleanup"),false);
|
||||||
|
Config->Removable = StringToBool(LookupTag(Message,"Removable"),false);
|
||||||
|
|
||||||
|
// Some debug text
|
||||||
|
if (Debug == true)
|
||||||
|
{
|
||||||
|
clog << "Configured access method " << Config->Access << endl;
|
||||||
|
clog << "Version:" << Config->Version <<
|
||||||
|
" SingleInstance:" << Config->SingleInstance <<
|
||||||
|
" Pipeline:" << Config->Pipeline <<
|
||||||
|
" SendConfig:" << Config->SendConfig <<
|
||||||
|
" LocalOnly: " << Config->LocalOnly <<
|
||||||
|
" NeedsCleanup: " << Config->NeedsCleanup <<
|
||||||
|
" Removable: " << Config->Removable << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::MediaChange - Request a media change /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgAcquire::Worker::MediaChange(string Message)
|
||||||
|
{
|
||||||
|
if (Log == 0 || Log->MediaChange(LookupTag(Message,"Media"),
|
||||||
|
LookupTag(Message,"Drive")) == false)
|
||||||
|
{
|
||||||
|
char S[300];
|
||||||
|
sprintf(S,"603 Media Changed\nFailed: true\n\n");
|
||||||
|
if (Debug == true)
|
||||||
|
clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
|
||||||
|
OutQueue += S;
|
||||||
|
OutReady = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char S[300];
|
||||||
|
sprintf(S,"603 Media Changed\n\n");
|
||||||
|
if (Debug == true)
|
||||||
|
clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
|
||||||
|
OutQueue += S;
|
||||||
|
OutReady = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::SendConfiguration - Send the config to the method /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgAcquire::Worker::SendConfiguration()
|
||||||
|
{
|
||||||
|
if (Config->SendConfig == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (OutFd == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string Message = "601 Configuration\n";
|
||||||
|
Message.reserve(2000);
|
||||||
|
|
||||||
|
/* Write out all of the configuration directives by walking the
|
||||||
|
configuration tree */
|
||||||
|
const Configuration::Item *Top = _config->Tree(0);
|
||||||
|
for (; Top != 0;)
|
||||||
|
{
|
||||||
|
if (Top->Value.empty() == false)
|
||||||
|
{
|
||||||
|
string Line = "Config-Item: " + Top->FullTag() + "=";
|
||||||
|
Line += QuoteString(Top->Value,"\n") + '\n';
|
||||||
|
Message += Line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Top->Child != 0)
|
||||||
|
{
|
||||||
|
Top = Top->Child;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Top != 0 && Top->Next == 0)
|
||||||
|
Top = Top->Parent;
|
||||||
|
if (Top != 0)
|
||||||
|
Top = Top->Next;
|
||||||
|
}
|
||||||
|
Message += '\n';
|
||||||
|
|
||||||
|
if (Debug == true)
|
||||||
|
clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
|
||||||
|
OutQueue += Message;
|
||||||
|
OutReady = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::QueueItem - Add an item to the outbound queue /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Send a URI Acquire message to the method */
|
||||||
|
bool pkgAcquire::Worker::QueueItem(pkgAcquire::Queue::QItem *Item)
|
||||||
|
{
|
||||||
|
if (OutFd == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string Message = "600 URI Acquire\n";
|
||||||
|
Message.reserve(300);
|
||||||
|
Message += "URI: " + Item->URI;
|
||||||
|
Message += "\nFilename: " + Item->Owner->DestFile;
|
||||||
|
Message += Item->Owner->Custom600Headers();
|
||||||
|
Message += "\n\n";
|
||||||
|
|
||||||
|
if (Debug == true)
|
||||||
|
clog << " -> " << Access << ':' << QuoteString(Message,"\n") << endl;
|
||||||
|
OutQueue += Message;
|
||||||
|
OutReady = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::OutFdRead - Out bound FD is ready /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgAcquire::Worker::OutFdReady()
|
||||||
|
{
|
||||||
|
int Res;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Res = write(OutFd,OutQueue.begin(),OutQueue.length());
|
||||||
|
}
|
||||||
|
while (Res < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (Res <= 0)
|
||||||
|
return MethodFailure();
|
||||||
|
|
||||||
|
// Hmm.. this should never happen.
|
||||||
|
if (Res < 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
OutQueue.erase(0,Res);
|
||||||
|
if (OutQueue.empty() == true)
|
||||||
|
OutReady = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::InFdRead - In bound FD is ready /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgAcquire::Worker::InFdReady()
|
||||||
|
{
|
||||||
|
if (ReadMessages() == false)
|
||||||
|
return false;
|
||||||
|
RunMessages();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::MethodFailure - Called when the method fails /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called when the method is belived to have failed, probably because
|
||||||
|
read returned -1. */
|
||||||
|
bool pkgAcquire::Worker::MethodFailure()
|
||||||
|
{
|
||||||
|
_error->Error(_("Method %s has died unexpectedly!"),Access.c_str());
|
||||||
|
|
||||||
|
ExecWait(Process,Access.c_str(),true);
|
||||||
|
Process = -1;
|
||||||
|
close(InFd);
|
||||||
|
close(OutFd);
|
||||||
|
InFd = -1;
|
||||||
|
OutFd = -1;
|
||||||
|
OutReady = false;
|
||||||
|
InReady = false;
|
||||||
|
OutQueue = string();
|
||||||
|
MessageQueue.erase(MessageQueue.begin(),MessageQueue.end());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::Pulse - Called periodically /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcquire::Worker::Pulse()
|
||||||
|
{
|
||||||
|
if (CurrentItem == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct stat Buf;
|
||||||
|
if (stat(CurrentItem->Owner->DestFile.c_str(),&Buf) != 0)
|
||||||
|
return;
|
||||||
|
CurrentSize = Buf.st_size;
|
||||||
|
|
||||||
|
// Hmm? Should not happen...
|
||||||
|
if (CurrentSize > TotalSize && TotalSize != 0)
|
||||||
|
TotalSize = CurrentSize;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Worker::ItemDone - Called when the current item is finished /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcquire::Worker::ItemDone()
|
||||||
|
{
|
||||||
|
CurrentItem = 0;
|
||||||
|
CurrentSize = 0;
|
||||||
|
TotalSize = 0;
|
||||||
|
Status = string();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
89
apt/apt-pkg/acquire-worker.h
Normal file
89
apt/apt-pkg/acquire-worker.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: acquire-worker.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Acquire Worker - Worker process manager
|
||||||
|
|
||||||
|
Each worker class is associated with exaclty one subprocess.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_ACQUIRE_WORKER_H
|
||||||
|
#define PKGLIB_ACQUIRE_WORKER_H
|
||||||
|
|
||||||
|
#include <apt-pkg/acquire.h>
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/acquire-worker.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Interfacing to the method process
|
||||||
|
class pkgAcquire::Worker
|
||||||
|
{
|
||||||
|
friend pkgAcquire;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend Queue;
|
||||||
|
|
||||||
|
/* Linked list starting at a Queue and a linked list starting
|
||||||
|
at Acquire */
|
||||||
|
Worker *NextQueue;
|
||||||
|
Worker *NextAcquire;
|
||||||
|
|
||||||
|
// The access association
|
||||||
|
Queue *OwnerQ;
|
||||||
|
pkgAcquireStatus *Log;
|
||||||
|
MethodConfig *Config;
|
||||||
|
string Access;
|
||||||
|
|
||||||
|
// This is the subprocess IPC setup
|
||||||
|
pid_t Process;
|
||||||
|
int InFd;
|
||||||
|
int OutFd;
|
||||||
|
bool InReady;
|
||||||
|
bool OutReady;
|
||||||
|
|
||||||
|
// Various internal things
|
||||||
|
bool Debug;
|
||||||
|
vector<string> MessageQueue;
|
||||||
|
string OutQueue;
|
||||||
|
|
||||||
|
// Private constructor helper
|
||||||
|
void Construct();
|
||||||
|
|
||||||
|
// Message handling things
|
||||||
|
bool ReadMessages();
|
||||||
|
bool RunMessages();
|
||||||
|
bool InFdReady();
|
||||||
|
bool OutFdReady();
|
||||||
|
|
||||||
|
// The message handlers
|
||||||
|
bool Capabilities(string Message);
|
||||||
|
bool SendConfiguration();
|
||||||
|
bool MediaChange(string Message);
|
||||||
|
|
||||||
|
bool MethodFailure();
|
||||||
|
void ItemDone();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// The curent method state
|
||||||
|
pkgAcquire::Queue::QItem *CurrentItem;
|
||||||
|
string Status;
|
||||||
|
unsigned long CurrentSize;
|
||||||
|
unsigned long TotalSize;
|
||||||
|
unsigned long ResumePoint;
|
||||||
|
|
||||||
|
// Load the method and do the startup
|
||||||
|
bool QueueItem(pkgAcquire::Queue::QItem *Item);
|
||||||
|
bool Start();
|
||||||
|
void Pulse();
|
||||||
|
inline const MethodConfig *GetConf() const {return Config;};
|
||||||
|
|
||||||
|
Worker(Queue *OwnerQ,MethodConfig *Config,pkgAcquireStatus *Log);
|
||||||
|
Worker(MethodConfig *Config);
|
||||||
|
~Worker();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
842
apt/apt-pkg/acquire.cc
Normal file
842
apt/apt-pkg/acquire.cc
Normal file
@ -0,0 +1,842 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: acquire.cc,v 1.3 2001/06/16 01:50:22 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Acquire - File Acquiration
|
||||||
|
|
||||||
|
The core element for the schedual system is the concept of a named
|
||||||
|
queue. Each queue is unique and each queue has a name derived from the
|
||||||
|
URI. The degree of paralization can be controled by how the queue
|
||||||
|
name is derived from the URI.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/acquire.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/acquire.h>
|
||||||
|
#include <apt-pkg/acquire-item.h>
|
||||||
|
#include <apt-pkg/acquire-worker.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// Acquire::pkgAcquire - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We grab some runtime state from the configuration space */
|
||||||
|
pkgAcquire::pkgAcquire(pkgAcquireStatus *Log) : Log(Log)
|
||||||
|
{
|
||||||
|
Queues = 0;
|
||||||
|
Configs = 0;
|
||||||
|
Workers = 0;
|
||||||
|
ToFetch = 0;
|
||||||
|
Running = false;
|
||||||
|
|
||||||
|
string Mode = _config->Find("Acquire::Queue-Mode","host");
|
||||||
|
if (strcasecmp(Mode.c_str(),"host") == 0)
|
||||||
|
QueueMode = QueueHost;
|
||||||
|
if (strcasecmp(Mode.c_str(),"access") == 0)
|
||||||
|
QueueMode = QueueAccess;
|
||||||
|
|
||||||
|
Debug = _config->FindB("Debug::pkgAcquire",false);
|
||||||
|
|
||||||
|
// This is really a stupid place for this
|
||||||
|
struct stat St;
|
||||||
|
if (stat((_config->FindDir("Dir::State::lists") + "partial/").c_str(),&St) != 0 ||
|
||||||
|
S_ISDIR(St.st_mode) == 0)
|
||||||
|
_error->Error(_("Lists directory %spartial is missing."),
|
||||||
|
_config->FindDir("Dir::State::lists").c_str());
|
||||||
|
if (stat((_config->FindDir("Dir::Cache::Archives") + "partial/").c_str(),&St) != 0 ||
|
||||||
|
S_ISDIR(St.st_mode) == 0)
|
||||||
|
_error->Error(_("Archive directory %spartial is missing."),
|
||||||
|
_config->FindDir("Dir::Cache::Archives").c_str());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::~pkgAcquire - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Free our memory, clean up the queues (destroy the workers) */
|
||||||
|
pkgAcquire::~pkgAcquire()
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
|
||||||
|
while (Configs != 0)
|
||||||
|
{
|
||||||
|
MethodConfig *Jnk = Configs;
|
||||||
|
Configs = Configs->Next;
|
||||||
|
delete Jnk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Shutdown - Clean out the acquire object /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcquire::Shutdown()
|
||||||
|
{
|
||||||
|
while (Items.size() != 0)
|
||||||
|
delete Items[0];
|
||||||
|
|
||||||
|
while (Queues != 0)
|
||||||
|
{
|
||||||
|
Queue *Jnk = Queues;
|
||||||
|
Queues = Queues->Next;
|
||||||
|
delete Jnk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Add - Add a new item /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This puts an item on the acquire list. This list is mainly for tracking
|
||||||
|
item status */
|
||||||
|
void pkgAcquire::Add(Item *Itm)
|
||||||
|
{
|
||||||
|
Items.push_back(Itm);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Remove - Remove a item /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Remove an item from the acquire list. This is usually not used.. */
|
||||||
|
void pkgAcquire::Remove(Item *Itm)
|
||||||
|
{
|
||||||
|
Dequeue(Itm);
|
||||||
|
|
||||||
|
for (vector<Item *>::iterator I = Items.begin(); I < Items.end(); I++)
|
||||||
|
{
|
||||||
|
if (*I == Itm)
|
||||||
|
Items.erase(I);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Add - Add a worker /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* A list of workers is kept so that the select loop can direct their FD
|
||||||
|
usage. */
|
||||||
|
void pkgAcquire::Add(Worker *Work)
|
||||||
|
{
|
||||||
|
Work->NextAcquire = Workers;
|
||||||
|
Workers = Work;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Remove - Remove a worker /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* A worker has died. This can not be done while the select loop is running
|
||||||
|
as it would require that RunFds could handling a changing list state and
|
||||||
|
it cant.. */
|
||||||
|
void pkgAcquire::Remove(Worker *Work)
|
||||||
|
{
|
||||||
|
if (Running == true)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
Worker **I = &Workers;
|
||||||
|
for (; *I != 0;)
|
||||||
|
{
|
||||||
|
if (*I == Work)
|
||||||
|
*I = (*I)->NextAcquire;
|
||||||
|
else
|
||||||
|
I = &(*I)->NextAcquire;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Enqueue - Queue an URI for fetching /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is the entry point for an item. An item calls this function when
|
||||||
|
it is constructed which creates a queue (based on the current queue
|
||||||
|
mode) and puts the item in that queue. If the system is running then
|
||||||
|
the queue might be started. */
|
||||||
|
void pkgAcquire::Enqueue(ItemDesc &Item)
|
||||||
|
{
|
||||||
|
// Determine which queue to put the item in
|
||||||
|
const MethodConfig *Config;
|
||||||
|
string Name = QueueName(Item.URI,Config);
|
||||||
|
if (Name.empty() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Find the queue structure
|
||||||
|
Queue *I = Queues;
|
||||||
|
for (; I != 0 && I->Name != Name; I = I->Next);
|
||||||
|
if (I == 0)
|
||||||
|
{
|
||||||
|
I = new Queue(Name,this);
|
||||||
|
I->Next = Queues;
|
||||||
|
Queues = I;
|
||||||
|
|
||||||
|
if (Running == true)
|
||||||
|
I->Startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if this is a local only URI
|
||||||
|
if (Config->LocalOnly == true && Item.Owner->Complete == false)
|
||||||
|
Item.Owner->Local = true;
|
||||||
|
Item.Owner->Status = Item::StatIdle;
|
||||||
|
|
||||||
|
// Queue it into the named queue
|
||||||
|
I->Enqueue(Item);
|
||||||
|
ToFetch++;
|
||||||
|
|
||||||
|
// Some trace stuff
|
||||||
|
if (Debug == true)
|
||||||
|
{
|
||||||
|
clog << "Fetching " << Item.URI << endl;
|
||||||
|
clog << " to " << Item.Owner->DestFile << endl;
|
||||||
|
clog << " Queue is: " << Name << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Dequeue - Remove an item from all queues /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called when an item is finished being fetched. It removes it
|
||||||
|
from all the queues */
|
||||||
|
void pkgAcquire::Dequeue(Item *Itm)
|
||||||
|
{
|
||||||
|
Queue *I = Queues;
|
||||||
|
bool Res = false;
|
||||||
|
for (; I != 0; I = I->Next)
|
||||||
|
Res |= I->Dequeue(Itm);
|
||||||
|
|
||||||
|
if (Debug == true)
|
||||||
|
clog << "Dequeuing " << Itm->DestFile << endl;
|
||||||
|
if (Res == true)
|
||||||
|
ToFetch--;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::QueueName - Return the name of the queue for this URI /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The string returned depends on the configuration settings and the
|
||||||
|
method parameters. Given something like http://foo.org/bar it can
|
||||||
|
return http://foo.org or http */
|
||||||
|
string pkgAcquire::QueueName(string Uri,MethodConfig const *&Config)
|
||||||
|
{
|
||||||
|
URI U(Uri);
|
||||||
|
|
||||||
|
Config = GetConfig(U.Access);
|
||||||
|
if (Config == 0)
|
||||||
|
return string();
|
||||||
|
|
||||||
|
/* Single-Instance methods get exactly one queue per URI. This is
|
||||||
|
also used for the Access queue method */
|
||||||
|
if (Config->SingleInstance == true || QueueMode == QueueAccess)
|
||||||
|
return U.Access;
|
||||||
|
|
||||||
|
return U.Access + ':' + U.Host;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::GetConfig - Fetch the configuration information /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This locates the configuration structure for an access method. If
|
||||||
|
a config structure cannot be found a Worker will be created to
|
||||||
|
retrieve it */
|
||||||
|
pkgAcquire::MethodConfig *pkgAcquire::GetConfig(string Access)
|
||||||
|
{
|
||||||
|
// Search for an existing config
|
||||||
|
MethodConfig *Conf;
|
||||||
|
for (Conf = Configs; Conf != 0; Conf = Conf->Next)
|
||||||
|
if (Conf->Access == Access)
|
||||||
|
return Conf;
|
||||||
|
|
||||||
|
// Create the new config class
|
||||||
|
Conf = new MethodConfig;
|
||||||
|
Conf->Access = Access;
|
||||||
|
Conf->Next = Configs;
|
||||||
|
Configs = Conf;
|
||||||
|
|
||||||
|
// Create the worker to fetch the configuration
|
||||||
|
Worker Work(Conf);
|
||||||
|
if (Work.Start() == false)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Conf;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::SetFds - Deal with readable FDs /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Collect FDs that have activity monitors into the fd sets */
|
||||||
|
void pkgAcquire::SetFds(int &Fd,fd_set *RSet,fd_set *WSet)
|
||||||
|
{
|
||||||
|
for (Worker *I = Workers; I != 0; I = I->NextAcquire)
|
||||||
|
{
|
||||||
|
if (I->InReady == true && I->InFd >= 0)
|
||||||
|
{
|
||||||
|
if (Fd < I->InFd)
|
||||||
|
Fd = I->InFd;
|
||||||
|
FD_SET(I->InFd,RSet);
|
||||||
|
}
|
||||||
|
if (I->OutReady == true && I->OutFd >= 0)
|
||||||
|
{
|
||||||
|
if (Fd < I->OutFd)
|
||||||
|
Fd = I->OutFd;
|
||||||
|
FD_SET(I->OutFd,WSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::RunFds - Deal with active FDs /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Dispatch active FDs over to the proper workers. It is very important
|
||||||
|
that a worker never be erased while this is running! The queue class
|
||||||
|
should never erase a worker except during shutdown processing. */
|
||||||
|
void pkgAcquire::RunFds(fd_set *RSet,fd_set *WSet)
|
||||||
|
{
|
||||||
|
for (Worker *I = Workers; I != 0; I = I->NextAcquire)
|
||||||
|
{
|
||||||
|
if (I->InFd >= 0 && FD_ISSET(I->InFd,RSet) != 0)
|
||||||
|
I->InFdReady();
|
||||||
|
if (I->OutFd >= 0 && FD_ISSET(I->OutFd,WSet) != 0)
|
||||||
|
I->OutFdReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Run - Run the fetch sequence /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This runs the queues. It manages a select loop for all of the
|
||||||
|
Worker tasks. The workers interact with the queues and items to
|
||||||
|
manage the actual fetch. */
|
||||||
|
pkgAcquire::RunResult pkgAcquire::Run()
|
||||||
|
{
|
||||||
|
Running = true;
|
||||||
|
|
||||||
|
for (Queue *I = Queues; I != 0; I = I->Next)
|
||||||
|
I->Startup();
|
||||||
|
|
||||||
|
if (Log != 0)
|
||||||
|
Log->Start();
|
||||||
|
|
||||||
|
bool WasCancelled = false;
|
||||||
|
|
||||||
|
// Run till all things have been acquired
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 500000;
|
||||||
|
while (ToFetch > 0)
|
||||||
|
{
|
||||||
|
fd_set RFds;
|
||||||
|
fd_set WFds;
|
||||||
|
int Highest = 0;
|
||||||
|
FD_ZERO(&RFds);
|
||||||
|
FD_ZERO(&WFds);
|
||||||
|
SetFds(Highest,&RFds,&WFds);
|
||||||
|
|
||||||
|
int Res;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Res = select(Highest+1,&RFds,&WFds,0,&tv);
|
||||||
|
}
|
||||||
|
while (Res < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (Res < 0)
|
||||||
|
{
|
||||||
|
_error->Errno("select","Select has failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunFds(&RFds,&WFds);
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Timeout, notify the log class
|
||||||
|
if (Res == 0 || (Log != 0 && Log->Update == true))
|
||||||
|
{
|
||||||
|
tv.tv_usec = 500000;
|
||||||
|
for (Worker *I = Workers; I != 0; I = I->NextAcquire)
|
||||||
|
I->Pulse();
|
||||||
|
if (Log != 0 && Log->Pulse(this) == false)
|
||||||
|
{
|
||||||
|
WasCancelled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Log != 0)
|
||||||
|
Log->Stop();
|
||||||
|
|
||||||
|
// Shut down the acquire bits
|
||||||
|
Running = false;
|
||||||
|
for (Queue *I = Queues; I != 0; I = I->Next)
|
||||||
|
I->Shutdown(false);
|
||||||
|
|
||||||
|
// Shut down the items
|
||||||
|
for (Item **I = Items.begin(); I != Items.end(); I++)
|
||||||
|
(*I)->Finished();
|
||||||
|
|
||||||
|
if (_error->PendingError())
|
||||||
|
return Failed;
|
||||||
|
if (WasCancelled)
|
||||||
|
return Cancelled;
|
||||||
|
return Continue;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Bump - Called when an item is dequeued /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This routine bumps idle queues in hopes that they will be able to fetch
|
||||||
|
the dequeued item */
|
||||||
|
void pkgAcquire::Bump()
|
||||||
|
{
|
||||||
|
for (Queue *I = Queues; I != 0; I = I->Next)
|
||||||
|
I->Bump();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::WorkerStep - Step to the next worker /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Not inlined to advoid including acquire-worker.h */
|
||||||
|
pkgAcquire::Worker *pkgAcquire::WorkerStep(Worker *I)
|
||||||
|
{
|
||||||
|
return I->NextAcquire;
|
||||||
|
};
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::Clean - Cleans a directory /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is a bit simplistic, it looks at every file in the dir and sees
|
||||||
|
if it is part of the download set. */
|
||||||
|
bool pkgAcquire::Clean(string Dir)
|
||||||
|
{
|
||||||
|
DIR *D = opendir(Dir.c_str());
|
||||||
|
if (D == 0)
|
||||||
|
return _error->Errno("opendir","Unable to read %s",Dir.c_str());
|
||||||
|
|
||||||
|
string StartDir = SafeGetCWD();
|
||||||
|
if (chdir(Dir.c_str()) != 0)
|
||||||
|
{
|
||||||
|
closedir(D);
|
||||||
|
return _error->Errno("chdir","Unable to change to ",Dir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
|
||||||
|
{
|
||||||
|
// Skip some files..
|
||||||
|
if (strcmp(Dir->d_name,"lock") == 0 ||
|
||||||
|
strcmp(Dir->d_name,"partial") == 0 ||
|
||||||
|
strcmp(Dir->d_name,".") == 0 ||
|
||||||
|
strcmp(Dir->d_name,"..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Look in the get list
|
||||||
|
vector<Item *>::iterator I = Items.begin();
|
||||||
|
for (; I != Items.end(); I++)
|
||||||
|
if (flNotDir((*I)->DestFile) == Dir->d_name)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Nothing found, nuke it
|
||||||
|
if (I == Items.end())
|
||||||
|
unlink(Dir->d_name);
|
||||||
|
};
|
||||||
|
|
||||||
|
chdir(StartDir.c_str());
|
||||||
|
closedir(D);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::TotalNeeded - Number of bytes to fetch /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is the total number of bytes needed */
|
||||||
|
unsigned long pkgAcquire::TotalNeeded()
|
||||||
|
{
|
||||||
|
unsigned long Total = 0;
|
||||||
|
for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
|
||||||
|
Total += (*I)->FileSize;
|
||||||
|
return Total;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::FetchNeeded - Number of bytes needed to get /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is the number of bytes that is not local */
|
||||||
|
unsigned long pkgAcquire::FetchNeeded()
|
||||||
|
{
|
||||||
|
unsigned long Total = 0;
|
||||||
|
for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
|
||||||
|
if ((*I)->Local == false)
|
||||||
|
Total += (*I)->FileSize;
|
||||||
|
return Total;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::PartialPresent - Number of partial bytes we already have /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is the number of bytes that is not local */
|
||||||
|
unsigned long pkgAcquire::PartialPresent()
|
||||||
|
{
|
||||||
|
unsigned long Total = 0;
|
||||||
|
for (pkgAcquire::Item **I = ItemsBegin(); I != ItemsEnd(); I++)
|
||||||
|
if ((*I)->Local == false)
|
||||||
|
Total += (*I)->PartialSize;
|
||||||
|
return Total;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::UriBegin - Start iterator for the uri list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::UriIterator pkgAcquire::UriBegin()
|
||||||
|
{
|
||||||
|
return UriIterator(Queues);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Acquire::UriEnd - End iterator for the uri list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::UriIterator pkgAcquire::UriEnd()
|
||||||
|
{
|
||||||
|
return UriIterator(0);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// Acquire::MethodConfig::MethodConfig - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::MethodConfig::MethodConfig()
|
||||||
|
{
|
||||||
|
SingleInstance = false;
|
||||||
|
Pipeline = false;
|
||||||
|
SendConfig = false;
|
||||||
|
LocalOnly = false;
|
||||||
|
Removable = false;
|
||||||
|
Next = 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// Queue::Queue - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::Queue::Queue(string Name,pkgAcquire *Owner) : Name(Name),
|
||||||
|
Owner(Owner)
|
||||||
|
{
|
||||||
|
Items = 0;
|
||||||
|
Next = 0;
|
||||||
|
Workers = 0;
|
||||||
|
MaxPipeDepth = 1;
|
||||||
|
PipeDepth = 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::~Queue - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::Queue::~Queue()
|
||||||
|
{
|
||||||
|
Shutdown(true);
|
||||||
|
|
||||||
|
while (Items != 0)
|
||||||
|
{
|
||||||
|
QItem *Jnk = Items;
|
||||||
|
Items = Items->Next;
|
||||||
|
delete Jnk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::Enqueue - Queue an item to the queue /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgAcquire::Queue::Enqueue(ItemDesc &Item)
|
||||||
|
{
|
||||||
|
QItem **I = &Items;
|
||||||
|
for (; *I != 0; I = &(*I)->Next);
|
||||||
|
|
||||||
|
// Create a new item
|
||||||
|
QItem *Itm = new QItem;
|
||||||
|
*Itm = Item;
|
||||||
|
Itm->Next = 0;
|
||||||
|
*I = Itm;
|
||||||
|
|
||||||
|
Item.Owner->QueueCounter++;
|
||||||
|
if (Items->Next == 0)
|
||||||
|
Cycle();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::Dequeue - Remove an item from the queue /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We return true if we hit something */
|
||||||
|
bool pkgAcquire::Queue::Dequeue(Item *Owner)
|
||||||
|
{
|
||||||
|
if (Owner->Status == pkgAcquire::Item::StatFetching)
|
||||||
|
return _error->Error("Tried to dequeue a fetching object");
|
||||||
|
|
||||||
|
bool Res = false;
|
||||||
|
|
||||||
|
QItem **I = &Items;
|
||||||
|
for (; *I != 0;)
|
||||||
|
{
|
||||||
|
if ((*I)->Owner == Owner)
|
||||||
|
{
|
||||||
|
QItem *Jnk= *I;
|
||||||
|
*I = (*I)->Next;
|
||||||
|
Owner->QueueCounter--;
|
||||||
|
delete Jnk;
|
||||||
|
Res = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
I = &(*I)->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::Startup - Start the worker processes /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* It is possible for this to be called with a pre-existing set of
|
||||||
|
workers. */
|
||||||
|
bool pkgAcquire::Queue::Startup()
|
||||||
|
{
|
||||||
|
if (Workers == 0)
|
||||||
|
{
|
||||||
|
URI U(Name);
|
||||||
|
pkgAcquire::MethodConfig *Cnf = Owner->GetConfig(U.Access);
|
||||||
|
if (Cnf == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Workers = new Worker(this,Cnf,Owner->Log);
|
||||||
|
Owner->Add(Workers);
|
||||||
|
if (Workers->Start() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* When pipelining we commit 10 items. This needs to change when we
|
||||||
|
added other source retry to have cycle maintain a pipeline depth
|
||||||
|
on its own. */
|
||||||
|
if (Cnf->Pipeline == true)
|
||||||
|
MaxPipeDepth = 10;
|
||||||
|
else
|
||||||
|
MaxPipeDepth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cycle();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::Shutdown - Shutdown the worker processes /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* If final is true then all workers are eliminated, otherwise only workers
|
||||||
|
that do not need cleanup are removed */
|
||||||
|
bool pkgAcquire::Queue::Shutdown(bool Final)
|
||||||
|
{
|
||||||
|
// Delete all of the workers
|
||||||
|
pkgAcquire::Worker **Cur = &Workers;
|
||||||
|
while (*Cur != 0)
|
||||||
|
{
|
||||||
|
pkgAcquire::Worker *Jnk = *Cur;
|
||||||
|
if (Final == true || Jnk->GetConf()->NeedsCleanup == false)
|
||||||
|
{
|
||||||
|
*Cur = Jnk->NextQueue;
|
||||||
|
Owner->Remove(Jnk);
|
||||||
|
delete Jnk;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Cur = &(*Cur)->NextQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::FindItem - Find a URI in the item list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquire::Queue::QItem *pkgAcquire::Queue::FindItem(string URI,pkgAcquire::Worker *Owner)
|
||||||
|
{
|
||||||
|
for (QItem *I = Items; I != 0; I = I->Next)
|
||||||
|
if (I->URI == URI && I->Worker == Owner)
|
||||||
|
return I;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::ItemDone - Item has been completed /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The worker signals this which causes the item to be removed from the
|
||||||
|
queue. If this is the last queue instance then it is removed from the
|
||||||
|
main queue too.*/
|
||||||
|
bool pkgAcquire::Queue::ItemDone(QItem *Itm)
|
||||||
|
{
|
||||||
|
PipeDepth--;
|
||||||
|
if (Itm->Owner->Status == pkgAcquire::Item::StatFetching)
|
||||||
|
Itm->Owner->Status = pkgAcquire::Item::StatDone;
|
||||||
|
|
||||||
|
if (Itm->Owner->QueueCounter <= 1)
|
||||||
|
Owner->Dequeue(Itm->Owner);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Dequeue(Itm->Owner);
|
||||||
|
Owner->Bump();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cycle();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::Cycle - Queue new items into the method /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This locates a new idle item and sends it to the worker. If pipelining
|
||||||
|
is enabled then it keeps the pipe full. */
|
||||||
|
bool pkgAcquire::Queue::Cycle()
|
||||||
|
{
|
||||||
|
if (Items == 0 || Workers == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (PipeDepth < 0)
|
||||||
|
return _error->Error("Pipedepth failure");
|
||||||
|
|
||||||
|
// Look for a queable item
|
||||||
|
QItem *I = Items;
|
||||||
|
while (PipeDepth < (signed)MaxPipeDepth)
|
||||||
|
{
|
||||||
|
for (; I != 0; I = I->Next)
|
||||||
|
if (I->Owner->Status == pkgAcquire::Item::StatIdle)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Nothing to do, queue is idle.
|
||||||
|
if (I == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
I->Worker = Workers;
|
||||||
|
I->Owner->Status = pkgAcquire::Item::StatFetching;
|
||||||
|
PipeDepth++;
|
||||||
|
if (Workers->QueueItem(I) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Queue::Bump - Fetch any pending objects if we are idle /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called when an item in multiple queues is dequeued */
|
||||||
|
void pkgAcquire::Queue::Bump()
|
||||||
|
{
|
||||||
|
Cycle();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// AcquireStatus::pkgAcquireStatus - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgAcquireStatus::pkgAcquireStatus() : Update(true), MorePulses(false)
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcquireStatus::Pulse - Called periodically /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This computes some internal state variables for the derived classes to
|
||||||
|
use. It generates the current downloaded bytes and total bytes to download
|
||||||
|
as well as the current CPS estimate. */
|
||||||
|
bool pkgAcquireStatus::Pulse(pkgAcquire *Owner)
|
||||||
|
{
|
||||||
|
TotalBytes = 0;
|
||||||
|
CurrentBytes = 0;
|
||||||
|
TotalItems = 0;
|
||||||
|
CurrentItems = 0;
|
||||||
|
|
||||||
|
// Compute the total number of bytes to fetch
|
||||||
|
unsigned int Unknown = 0;
|
||||||
|
unsigned int Count = 0;
|
||||||
|
for (pkgAcquire::Item **I = Owner->ItemsBegin(); I != Owner->ItemsEnd();
|
||||||
|
I++, Count++)
|
||||||
|
{
|
||||||
|
TotalItems++;
|
||||||
|
if ((*I)->Status == pkgAcquire::Item::StatDone)
|
||||||
|
CurrentItems++;
|
||||||
|
|
||||||
|
// Totally ignore local items
|
||||||
|
if ((*I)->Local == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TotalBytes += (*I)->FileSize;
|
||||||
|
if ((*I)->Complete == true)
|
||||||
|
CurrentBytes += (*I)->FileSize;
|
||||||
|
if ((*I)->FileSize == 0 && (*I)->Complete == false)
|
||||||
|
Unknown++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the current completion
|
||||||
|
unsigned long ResumeSize = 0;
|
||||||
|
for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
|
||||||
|
I = Owner->WorkerStep(I))
|
||||||
|
if (I->CurrentItem != 0 && I->CurrentItem->Owner->Complete == false)
|
||||||
|
{
|
||||||
|
CurrentBytes += I->CurrentSize;
|
||||||
|
ResumeSize += I->ResumePoint;
|
||||||
|
|
||||||
|
// Files with unknown size always have 100% completion
|
||||||
|
if (I->CurrentItem->Owner->FileSize == 0 &&
|
||||||
|
I->CurrentItem->Owner->Complete == false)
|
||||||
|
TotalBytes += I->CurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize the figures and account for unknown size downloads
|
||||||
|
if (TotalBytes <= 0)
|
||||||
|
TotalBytes = 1;
|
||||||
|
if (Unknown == Count)
|
||||||
|
TotalBytes = Unknown;
|
||||||
|
|
||||||
|
// Wha?! Is not supposed to happen.
|
||||||
|
if (CurrentBytes > TotalBytes)
|
||||||
|
CurrentBytes = TotalBytes;
|
||||||
|
|
||||||
|
// Compute the CPS
|
||||||
|
struct timeval NewTime;
|
||||||
|
gettimeofday(&NewTime,0);
|
||||||
|
if (NewTime.tv_sec - Time.tv_sec == 6 && NewTime.tv_usec > Time.tv_usec ||
|
||||||
|
NewTime.tv_sec - Time.tv_sec > 6)
|
||||||
|
{
|
||||||
|
double Delta = NewTime.tv_sec - Time.tv_sec +
|
||||||
|
(NewTime.tv_usec - Time.tv_usec)/1000000.0;
|
||||||
|
|
||||||
|
// Compute the CPS value
|
||||||
|
if (Delta < 0.01)
|
||||||
|
CurrentCPS = 0;
|
||||||
|
else
|
||||||
|
CurrentCPS = ((CurrentBytes - ResumeSize) - LastBytes)/Delta;
|
||||||
|
LastBytes = CurrentBytes - ResumeSize;
|
||||||
|
ElapsedTime = (unsigned long)Delta;
|
||||||
|
Time = NewTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcquireStatus::Start - Called when the download is started /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We just reset the counters */
|
||||||
|
void pkgAcquireStatus::Start()
|
||||||
|
{
|
||||||
|
gettimeofday(&Time,0);
|
||||||
|
gettimeofday(&StartTime,0);
|
||||||
|
LastBytes = 0;
|
||||||
|
CurrentCPS = 0;
|
||||||
|
CurrentBytes = 0;
|
||||||
|
TotalBytes = 0;
|
||||||
|
FetchedBytes = 0;
|
||||||
|
ElapsedTime = 0;
|
||||||
|
TotalItems = 0;
|
||||||
|
CurrentItems = 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcquireStatus::Stop - Finished downloading /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This accurately computes the elapsed time and the total overall CPS. */
|
||||||
|
void pkgAcquireStatus::Stop()
|
||||||
|
{
|
||||||
|
// Compute the CPS and elapsed time
|
||||||
|
struct timeval NewTime;
|
||||||
|
gettimeofday(&NewTime,0);
|
||||||
|
|
||||||
|
double Delta = NewTime.tv_sec - StartTime.tv_sec +
|
||||||
|
(NewTime.tv_usec - StartTime.tv_usec)/1000000.0;
|
||||||
|
|
||||||
|
// Compute the CPS value
|
||||||
|
if (Delta < 0.01)
|
||||||
|
CurrentCPS = 0;
|
||||||
|
else
|
||||||
|
CurrentCPS = FetchedBytes/Delta;
|
||||||
|
LastBytes = CurrentBytes;
|
||||||
|
ElapsedTime = (unsigned int)Delta;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AcquireStatus::Fetched - Called when a byte set has been fetched /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is used to get accurate final transfer rate reporting. */
|
||||||
|
void pkgAcquireStatus::Fetched(unsigned long Size,unsigned long Resume)
|
||||||
|
{
|
||||||
|
FetchedBytes += Size - Resume;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
276
apt/apt-pkg/acquire.h
Normal file
276
apt/apt-pkg/acquire.h
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: acquire.h,v 1.2 2000/11/06 12:53:49 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Acquire - File Acquiration
|
||||||
|
|
||||||
|
This module contians the Acquire system. It is responsible for bringing
|
||||||
|
files into the local pathname space. It deals with URIs for files and
|
||||||
|
URI handlers responsible for downloading or finding the URIs.
|
||||||
|
|
||||||
|
Each file to download is represented by an Acquire::Item class subclassed
|
||||||
|
into a specialization. The Item class can add itself to several URI
|
||||||
|
acquire queues each prioritized by the download scheduler. When the
|
||||||
|
system is run the proper URI handlers are spawned and the the acquire
|
||||||
|
queues are fed into the handlers by the schedular until the queues are
|
||||||
|
empty. This allows for an Item to be downloaded from an alternate source
|
||||||
|
if the first try turns out to fail. It also alows concurrent downloading
|
||||||
|
of multiple items from multiple sources as well as dynamic balancing
|
||||||
|
of load between the sources.
|
||||||
|
|
||||||
|
Schedualing of downloads is done on a first ask first get basis. This
|
||||||
|
preserves the order of the download as much as possible. And means the
|
||||||
|
fastest source will tend to process the largest number of files.
|
||||||
|
|
||||||
|
Internal methods and queues for performing gzip decompression,
|
||||||
|
md5sum hashing and file copying are provided to allow items to apply
|
||||||
|
a number of transformations to the data files they are working with.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_ACQUIRE_H
|
||||||
|
#define PKGLIB_ACQUIRE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/acquire.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
class pkgAcquireStatus;
|
||||||
|
class pkgAcquire
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
class Item;
|
||||||
|
class Queue;
|
||||||
|
class Worker;
|
||||||
|
struct MethodConfig;
|
||||||
|
struct ItemDesc;
|
||||||
|
friend Item;
|
||||||
|
friend Queue;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// List of items to fetch
|
||||||
|
vector<Item *> Items;
|
||||||
|
|
||||||
|
// List of active queues and fetched method configuration parameters
|
||||||
|
Queue *Queues;
|
||||||
|
Worker *Workers;
|
||||||
|
MethodConfig *Configs;
|
||||||
|
pkgAcquireStatus *Log;
|
||||||
|
unsigned long ToFetch;
|
||||||
|
|
||||||
|
// Configurable parameters for the schedular
|
||||||
|
enum {QueueHost,QueueAccess} QueueMode;
|
||||||
|
bool Debug;
|
||||||
|
bool Running;
|
||||||
|
|
||||||
|
void Add(Item *Item);
|
||||||
|
void Remove(Item *Item);
|
||||||
|
void Add(Worker *Work);
|
||||||
|
void Remove(Worker *Work);
|
||||||
|
|
||||||
|
void Enqueue(ItemDesc &Item);
|
||||||
|
void Dequeue(Item *Item);
|
||||||
|
string QueueName(string URI,MethodConfig const *&Config);
|
||||||
|
|
||||||
|
// FDSET managers for derived classes
|
||||||
|
virtual void SetFds(int &Fd,fd_set *RSet,fd_set *WSet);
|
||||||
|
virtual void RunFds(fd_set *RSet,fd_set *WSet);
|
||||||
|
|
||||||
|
// A queue calls this when it dequeues an item
|
||||||
|
void Bump();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MethodConfig *GetConfig(string Access);
|
||||||
|
|
||||||
|
enum RunResult {Continue,Failed,Cancelled};
|
||||||
|
|
||||||
|
RunResult Run();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
// Simple iteration mechanism
|
||||||
|
inline Worker *WorkersBegin() {return Workers;};
|
||||||
|
Worker *WorkerStep(Worker *I);
|
||||||
|
inline Item **ItemsBegin() {return Items.begin();};
|
||||||
|
inline Item **ItemsEnd() {return Items.end();};
|
||||||
|
|
||||||
|
// Iterate over queued Item URIs
|
||||||
|
class UriIterator;
|
||||||
|
UriIterator UriBegin();
|
||||||
|
UriIterator UriEnd();
|
||||||
|
|
||||||
|
// Cleans out the download dir
|
||||||
|
bool Clean(string Dir);
|
||||||
|
|
||||||
|
// Returns the size of the total download set
|
||||||
|
unsigned long TotalNeeded();
|
||||||
|
unsigned long FetchNeeded();
|
||||||
|
unsigned long PartialPresent();
|
||||||
|
|
||||||
|
pkgAcquire(pkgAcquireStatus *Log = 0);
|
||||||
|
virtual ~pkgAcquire();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Description of an Item+URI
|
||||||
|
struct pkgAcquire::ItemDesc
|
||||||
|
{
|
||||||
|
string URI;
|
||||||
|
string Description;
|
||||||
|
string ShortDesc;
|
||||||
|
Item *Owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
// List of possible items queued for download.
|
||||||
|
class pkgAcquire::Queue
|
||||||
|
{
|
||||||
|
friend pkgAcquire;
|
||||||
|
friend pkgAcquire::UriIterator;
|
||||||
|
Queue *Next;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Queued item
|
||||||
|
struct QItem : pkgAcquire::ItemDesc
|
||||||
|
{
|
||||||
|
QItem *Next;
|
||||||
|
pkgAcquire::Worker *Worker;
|
||||||
|
|
||||||
|
void operator =(pkgAcquire::ItemDesc const &I)
|
||||||
|
{
|
||||||
|
URI = I.URI;
|
||||||
|
Description = I.Description;
|
||||||
|
ShortDesc = I.ShortDesc;
|
||||||
|
Owner = I.Owner;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
// Name of the queue
|
||||||
|
string Name;
|
||||||
|
|
||||||
|
// Items queued into this queue
|
||||||
|
QItem *Items;
|
||||||
|
pkgAcquire::Worker *Workers;
|
||||||
|
pkgAcquire *Owner;
|
||||||
|
signed long PipeDepth;
|
||||||
|
unsigned long MaxPipeDepth;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Put an item into this queue
|
||||||
|
void Enqueue(ItemDesc &Item);
|
||||||
|
bool Dequeue(Item *Owner);
|
||||||
|
|
||||||
|
// Find a Queued item
|
||||||
|
QItem *FindItem(string URI,pkgAcquire::Worker *Owner);
|
||||||
|
bool ItemStart(QItem *Itm,unsigned long Size);
|
||||||
|
bool ItemDone(QItem *Itm);
|
||||||
|
|
||||||
|
bool Startup();
|
||||||
|
bool Shutdown(bool Final);
|
||||||
|
bool Cycle();
|
||||||
|
void Bump();
|
||||||
|
|
||||||
|
Queue(string Name,pkgAcquire *Owner);
|
||||||
|
~Queue();
|
||||||
|
};
|
||||||
|
|
||||||
|
class pkgAcquire::UriIterator
|
||||||
|
{
|
||||||
|
pkgAcquire::Queue *CurQ;
|
||||||
|
pkgAcquire::Queue::QItem *CurItem;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Advance to the next item
|
||||||
|
inline void operator ++() {operator ++();};
|
||||||
|
void operator ++(int)
|
||||||
|
{
|
||||||
|
CurItem = CurItem->Next;
|
||||||
|
while (CurItem == 0 && CurQ != 0)
|
||||||
|
{
|
||||||
|
CurItem = CurQ->Items;
|
||||||
|
CurQ = CurQ->Next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline pkgAcquire::ItemDesc const *operator ->() const {return CurItem;};
|
||||||
|
inline bool operator !=(UriIterator const &rhs) const {return rhs.CurQ != CurQ || rhs.CurItem != CurItem;};
|
||||||
|
inline bool operator ==(UriIterator const &rhs) const {return rhs.CurQ == CurQ && rhs.CurItem == CurItem;};
|
||||||
|
|
||||||
|
UriIterator(pkgAcquire::Queue *Q) : CurQ(Q), CurItem(0)
|
||||||
|
{
|
||||||
|
while (CurItem == 0 && CurQ != 0)
|
||||||
|
{
|
||||||
|
CurItem = CurQ->Items;
|
||||||
|
CurQ = CurQ->Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configuration information from each method
|
||||||
|
struct pkgAcquire::MethodConfig
|
||||||
|
{
|
||||||
|
MethodConfig *Next;
|
||||||
|
|
||||||
|
string Access;
|
||||||
|
|
||||||
|
string Version;
|
||||||
|
bool SingleInstance;
|
||||||
|
bool Pipeline;
|
||||||
|
bool SendConfig;
|
||||||
|
bool LocalOnly;
|
||||||
|
bool NeedsCleanup;
|
||||||
|
bool Removable;
|
||||||
|
|
||||||
|
MethodConfig();
|
||||||
|
};
|
||||||
|
|
||||||
|
class pkgAcquireStatus
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct timeval Time;
|
||||||
|
struct timeval StartTime;
|
||||||
|
unsigned long LastBytes;
|
||||||
|
double CurrentCPS;
|
||||||
|
unsigned long CurrentBytes;
|
||||||
|
unsigned long TotalBytes;
|
||||||
|
unsigned long FetchedBytes;
|
||||||
|
unsigned long ElapsedTime;
|
||||||
|
unsigned long TotalItems;
|
||||||
|
unsigned long CurrentItems;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool Update;
|
||||||
|
bool MorePulses;
|
||||||
|
|
||||||
|
// Called by items when they have finished a real download
|
||||||
|
virtual void Fetched(unsigned long Size,unsigned long ResumePoint);
|
||||||
|
|
||||||
|
// Called to change media
|
||||||
|
virtual bool MediaChange(string Media,string Drive) = 0;
|
||||||
|
|
||||||
|
// Each of these is called by the workers when an event occures
|
||||||
|
virtual void IMSHit(pkgAcquire::ItemDesc &/*Itm*/) {};
|
||||||
|
virtual void Fetch(pkgAcquire::ItemDesc &/*Itm*/) {};
|
||||||
|
virtual void Done(pkgAcquire::ItemDesc &/*Itm*/) {};
|
||||||
|
virtual void Fail(pkgAcquire::ItemDesc &/*Itm*/) {};
|
||||||
|
virtual bool Pulse(pkgAcquire *Owner); // returns false on user cancel
|
||||||
|
virtual void Start();
|
||||||
|
virtual void Stop();
|
||||||
|
|
||||||
|
pkgAcquireStatus();
|
||||||
|
virtual ~pkgAcquireStatus() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1177
apt/apt-pkg/algorithms.cc
Normal file
1177
apt/apt-pkg/algorithms.cc
Normal file
File diff suppressed because it is too large
Load Diff
113
apt/apt-pkg/algorithms.h
Normal file
113
apt/apt-pkg/algorithms.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: algorithms.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Algorithms - A set of misc algorithms
|
||||||
|
|
||||||
|
This simulate class displays what the ordering code has done and
|
||||||
|
analyses it with a fresh new dependency cache. In this way we can
|
||||||
|
see all of the effects of an upgrade run.
|
||||||
|
|
||||||
|
pkgDistUpgrade computes an upgrade that causes as many packages as
|
||||||
|
possible to move to the newest verison.
|
||||||
|
|
||||||
|
pkgApplyStatus sets the target state based on the content of the status
|
||||||
|
field in the status file. It is important to get proper crash recovery.
|
||||||
|
|
||||||
|
pkgFixBroken corrects a broken system so that it is in a sane state.
|
||||||
|
|
||||||
|
pkgAllUpgrade attempts to upgade as many packages as possible but
|
||||||
|
without installing new packages.
|
||||||
|
|
||||||
|
The problem resolver class contains a number of complex algorithms
|
||||||
|
to try to best-guess an upgrade state. It solves the problem of
|
||||||
|
maximizing the number of install state packages while having no broken
|
||||||
|
packages.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_ALGORITHMS_H
|
||||||
|
#define PKGLIB_ALGORITHMS_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/algorithms.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/packagemanager.h>
|
||||||
|
#include <apt-pkg/depcache.h>
|
||||||
|
|
||||||
|
class pkgSimulate : public pkgPackageManager
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
unsigned char *Flags;
|
||||||
|
|
||||||
|
pkgDepCache Sim;
|
||||||
|
|
||||||
|
// The Actuall installation implementation
|
||||||
|
virtual bool Install(PkgIterator Pkg,string File);
|
||||||
|
virtual bool Configure(PkgIterator Pkg);
|
||||||
|
virtual bool Remove(PkgIterator Pkg,bool Purge);
|
||||||
|
void ShortBreaks();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
pkgSimulate(pkgDepCache &Cache);
|
||||||
|
};
|
||||||
|
|
||||||
|
class pkgProblemResolver
|
||||||
|
{
|
||||||
|
pkgDepCache &Cache;
|
||||||
|
typedef pkgCache::PkgIterator PkgIterator;
|
||||||
|
typedef pkgCache::VerIterator VerIterator;
|
||||||
|
typedef pkgCache::DepIterator DepIterator;
|
||||||
|
typedef pkgCache::PrvIterator PrvIterator;
|
||||||
|
typedef pkgCache::Version Version;
|
||||||
|
typedef pkgCache::Package Package;
|
||||||
|
|
||||||
|
enum Flags {Protected = (1 << 0), PreInstalled = (1 << 1),
|
||||||
|
Upgradable = (1 << 2), ReInstateTried = (1 << 3),
|
||||||
|
ToRemove = (1 << 4)};
|
||||||
|
signed short *Scores;
|
||||||
|
unsigned char *Flags;
|
||||||
|
bool Debug;
|
||||||
|
|
||||||
|
// Sort stuff
|
||||||
|
static pkgProblemResolver *This;
|
||||||
|
static int ScoreSort(const void *a,const void *b);
|
||||||
|
|
||||||
|
struct PackageKill
|
||||||
|
{
|
||||||
|
PkgIterator Pkg;
|
||||||
|
DepIterator Dep;
|
||||||
|
};
|
||||||
|
|
||||||
|
void MakeScores();
|
||||||
|
bool DoUpgrade(pkgCache::PkgIterator Pkg);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline void Protect(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= Protected;};
|
||||||
|
inline void Remove(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= ToRemove;};
|
||||||
|
inline void Clear(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] &= ~(Protected | ToRemove);};
|
||||||
|
|
||||||
|
// Try to intelligently resolve problems by installing and removing packages
|
||||||
|
bool Resolve(bool BrokenFix = false);
|
||||||
|
|
||||||
|
// Try to resolve problems only by using keep
|
||||||
|
bool ResolveByKeep();
|
||||||
|
|
||||||
|
void InstallProtect();
|
||||||
|
|
||||||
|
pkgProblemResolver(pkgDepCache &Cache);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool pkgDistUpgrade(pkgDepCache &Cache);
|
||||||
|
bool pkgApplyStatus(pkgDepCache &Cache);
|
||||||
|
bool pkgFixBroken(pkgDepCache &Cache);
|
||||||
|
bool pkgAllUpgrade(pkgDepCache &Cache);
|
||||||
|
bool pkgMinimizeUpgrade(pkgDepCache &Cache);
|
||||||
|
|
||||||
|
#endif
|
123
apt/apt-pkg/cachefile.cc
Normal file
123
apt/apt-pkg/cachefile.cc
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: cachefile.cc,v 1.8 2001/07/12 21:47:32 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
CacheFile - Simple wrapper class for opening, generating and whatnot
|
||||||
|
|
||||||
|
This class implements a simple 2 line mechanism to open various sorts
|
||||||
|
of caches. It can operate as root, as not root, show progress and so on,
|
||||||
|
it transparently handles everything necessary.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/cachefile.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <apt-pkg/cachefile.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/sourcelist.h>
|
||||||
|
#include <apt-pkg/pkgcachegen.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/systemfactory.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// CacheFile::CacheFile - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgCacheFile::pkgCacheFile() : Map(0), Cache(0),
|
||||||
|
#if 0//akk
|
||||||
|
Lock(0),
|
||||||
|
#endif
|
||||||
|
RPM(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheFile::~CacheFile - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgCacheFile::~pkgCacheFile()
|
||||||
|
{
|
||||||
|
delete Cache;
|
||||||
|
delete Map;
|
||||||
|
#if 0//akk
|
||||||
|
if (Lock)
|
||||||
|
delete Lock;
|
||||||
|
#endif
|
||||||
|
if (RPM)
|
||||||
|
delete RPM;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheFile::Open - Open the cache files, creating if necessary /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgCacheFile::Open(OpProgress &Progress,bool WithLock)
|
||||||
|
{
|
||||||
|
if (WithLock == true)
|
||||||
|
{
|
||||||
|
#if 0 //akk
|
||||||
|
if (0)//akk
|
||||||
|
{
|
||||||
|
Lock = new pkgDpkgLock;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (1) {
|
||||||
|
RPM = new pkgRpmLock(WithLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Read the source list
|
||||||
|
pkgSourceList List;
|
||||||
|
if (List.ReadMainList() == false)
|
||||||
|
return _error->Error(_("The list of sources could not be read."));
|
||||||
|
|
||||||
|
/* Build all of the caches, using the cache files if we are locking
|
||||||
|
(ie as root) */
|
||||||
|
if (WithLock == true)
|
||||||
|
{
|
||||||
|
_system->makeStatusCache(List, Progress);
|
||||||
|
|
||||||
|
Progress.Done();
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return _error->Error(_("The package lists or status file could not be parsed or opened."));
|
||||||
|
if (_error->empty() == false)
|
||||||
|
_error->Warning(_("You may want to run apt-get update to correct these missing files"));
|
||||||
|
|
||||||
|
// Open the cache file
|
||||||
|
FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Map = new MMap(File,MMap::Public | MMap::ReadOnly);
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Map = _system->makeStatusCacheMem(List,Progress);
|
||||||
|
Progress.Done();
|
||||||
|
if (Map == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the dependency cache
|
||||||
|
Cache = new pkgDepCache(*Map,Progress);
|
||||||
|
Progress.Done();
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
63
apt/apt-pkg/cachefile.h
Normal file
63
apt/apt-pkg/cachefile.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: cachefile.h,v 1.4 2001/07/12 21:47:32 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
CacheFile - Simple wrapper class for opening, generating and whatnot
|
||||||
|
|
||||||
|
This class implements a simple 2 line mechanism to open various sorts
|
||||||
|
of caches. It can operate as root, as not root, show progress and so on,
|
||||||
|
it transparently handles everything necessary.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_CACHEFILE_H
|
||||||
|
#define PKGLIB_CACHEFILE_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/cachefile.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <apt-pkg/depcache.h>
|
||||||
|
#include <apt-pkg/dpkginit.h>
|
||||||
|
#include <apt-pkg/rpminit.h>
|
||||||
|
|
||||||
|
class pkgCacheFile
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
MMap *Map;
|
||||||
|
pkgDepCache *Cache;
|
||||||
|
#if 0//akk
|
||||||
|
pkgDpkgLock *Lock;
|
||||||
|
#endif
|
||||||
|
pkgRpmLock *RPM;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// We look pretty much exactly like a pointer to a dep cache
|
||||||
|
inline operator pkgDepCache &() {return *Cache;};
|
||||||
|
inline operator pkgDepCache *() {return Cache;};
|
||||||
|
inline pkgDepCache *operator ->() {return Cache;};
|
||||||
|
inline pkgDepCache &operator *() {return *Cache;};
|
||||||
|
inline pkgDepCache::StateCache &operator [](pkgCache::PkgIterator const &I) {return (*Cache)[I];};
|
||||||
|
inline unsigned char &operator [](pkgCache::DepIterator const &I) {return (*Cache)[I];};
|
||||||
|
|
||||||
|
// Release the dpkg status lock
|
||||||
|
inline void ReleaseLock() {
|
||||||
|
#if 0//akk
|
||||||
|
if (0)
|
||||||
|
Lock->Close();
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
RPM->Close();
|
||||||
|
};//akk
|
||||||
|
|
||||||
|
bool Open(OpProgress &Progress,bool WithLock = true);
|
||||||
|
|
||||||
|
pkgCacheFile();
|
||||||
|
~pkgCacheFile();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
350
apt/apt-pkg/cacheiterators.h
Normal file
350
apt/apt-pkg/cacheiterators.h
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: cacheiterators.h,v 1.2 2000/09/20 15:20:06 kojima 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. The provide iterator has the
|
||||||
|
same system.
|
||||||
|
|
||||||
|
This header is not user includable, please use apt-pkg/pkgcache.h
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_CACHEITERATORS_H
|
||||||
|
#define PKGLIB_CACHEITERATORS_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/cacheiterators.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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 bool Purge() const {return Pkg->CurrentState == pkgCache::State::Purge ||
|
||||||
|
(Pkg->CurrentVer == 0 && Pkg->CurrentState == pkgCache::State::NotInstalled);};
|
||||||
|
inline VerIterator VersionList() const;
|
||||||
|
inline VerIterator TargetVer() const;
|
||||||
|
inline VerIterator CurrentVer() const;
|
||||||
|
inline DepIterator RevDependsList() const;
|
||||||
|
inline PrvIterator ProvidesList() const;
|
||||||
|
inline unsigned long Index() const {return Pkg - Owner->PkgP;};
|
||||||
|
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; Owner = B.Owner;};
|
||||||
|
|
||||||
|
// 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 const char *Arch() const {return Ver->Arch == 0?0:Owner->StrP + Ver->Arch;};
|
||||||
|
inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Ver->ParentPkg);};
|
||||||
|
inline DepIterator DependsList() const;
|
||||||
|
inline PrvIterator ProvidesList() const;
|
||||||
|
inline VerFileIterator FileList() const;
|
||||||
|
inline unsigned long Index() const {return Ver - Owner->VerP;};
|
||||||
|
bool Downloadable() const;
|
||||||
|
const char *PriorityType();
|
||||||
|
|
||||||
|
bool Automatic() const;
|
||||||
|
VerFileIterator NewestFile() const;
|
||||||
|
|
||||||
|
inline VerIterator() : Ver(0), Owner(0) {};
|
||||||
|
inline VerIterator(pkgCache &Owner,Version *Trg = 0) : 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);};
|
||||||
|
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);};
|
||||||
|
inline bool Reverse() {return Type == DepRev;};
|
||||||
|
inline unsigned long Index() const {return Dep - Owner->DepP;};
|
||||||
|
bool IsCritical();
|
||||||
|
void GlobOr(DepIterator &Start,DepIterator &End);
|
||||||
|
Version **AllTargets();
|
||||||
|
bool SmartTargetPkg(PkgIterator &Result);
|
||||||
|
const char *CompType();
|
||||||
|
const char *DepType();
|
||||||
|
|
||||||
|
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 unsigned long Index() const {return Prv - Owner->ProvideP;};
|
||||||
|
|
||||||
|
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 *Archive() const {return File->Archive == 0?0:Owner->StrP + File->Archive;};
|
||||||
|
inline const char *Component() const {return File->Component == 0?0:Owner->StrP + File->Component;};
|
||||||
|
inline const char *Version() const {return File->Version == 0?0:Owner->StrP + File->Version;};
|
||||||
|
inline const char *Origin() const {return File->Origin == 0?0:Owner->StrP + File->Origin;};
|
||||||
|
inline const char *Label() const {return File->Origin == 0?0:Owner->StrP + File->Label;};
|
||||||
|
inline const char *Architecture() const {return File->Origin == 0?0:Owner->StrP + File->Architecture;};
|
||||||
|
|
||||||
|
inline unsigned long Index() const {return File - Owner->PkgFileP;};
|
||||||
|
|
||||||
|
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) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Version File
|
||||||
|
class pkgCache::VerFileIterator
|
||||||
|
{
|
||||||
|
pkgCache *Owner;
|
||||||
|
VerFile *FileP;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Iteration
|
||||||
|
void operator ++(int) {if (FileP != Owner->VerFileP) FileP = Owner->VerFileP + FileP->NextFile;};
|
||||||
|
inline void operator ++() {operator ++(0);};
|
||||||
|
inline bool end() const {return FileP == Owner->VerFileP?true:false;};
|
||||||
|
|
||||||
|
// Comparison
|
||||||
|
inline bool operator ==(const VerFileIterator &B) const {return FileP == B.FileP;};
|
||||||
|
inline bool operator !=(const VerFileIterator &B) const {return FileP != B.FileP;};
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline VerFile *operator ->() {return FileP;};
|
||||||
|
inline VerFile const *operator ->() const {return FileP;};
|
||||||
|
inline VerFile const &operator *() const {return *FileP;};
|
||||||
|
inline operator VerFile *() {return FileP == Owner->VerFileP?0:FileP;};
|
||||||
|
inline operator VerFile const *() const {return FileP == Owner->VerFileP?0:FileP;};
|
||||||
|
|
||||||
|
inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
|
||||||
|
inline unsigned long Index() const {return FileP - Owner->VerFileP;};
|
||||||
|
|
||||||
|
inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(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::VerFileIterator pkgCache::VerIterator::FileList() const
|
||||||
|
{return VerFileIterator(*Owner,Owner->VerFileP + Ver->FileList);};
|
||||||
|
|
||||||
|
#endif
|
117
apt/apt-pkg/clean.cc
Normal file
117
apt/apt-pkg/clean.cc
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: clean.cc,v 1.2 2001/01/11 02:03:26 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Clean - Clean out downloaded directories
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Includes /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/clean.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/clean.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// ArchiveCleaner::Go - Perform smart cleanup of the archive /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Scan the directory for files to erase, we check the version information
|
||||||
|
against our database to see if it is interesting */
|
||||||
|
bool pkgArchiveCleaner::Go(string Dir,pkgCache &Cache)
|
||||||
|
{
|
||||||
|
bool CleanInstalled = _config->FindB("APT::Clean-Installed",true);
|
||||||
|
|
||||||
|
DIR *D = opendir(Dir.c_str());
|
||||||
|
if (D == 0)
|
||||||
|
return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
|
||||||
|
|
||||||
|
string StartDir = SafeGetCWD();
|
||||||
|
if (chdir(Dir.c_str()) != 0)
|
||||||
|
{
|
||||||
|
closedir(D);
|
||||||
|
return _error->Errno("chdir",_("Unable to change to "),Dir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
|
||||||
|
{
|
||||||
|
// Skip some files..
|
||||||
|
if (strcmp(Dir->d_name,"lock") == 0 ||
|
||||||
|
strcmp(Dir->d_name,"partial") == 0 ||
|
||||||
|
strcmp(Dir->d_name,".") == 0 ||
|
||||||
|
strcmp(Dir->d_name,"..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct stat St;
|
||||||
|
if (stat(Dir->d_name,&St) != 0)
|
||||||
|
return _error->Errno("stat",_("Unable to stat %s."),Dir->d_name);
|
||||||
|
|
||||||
|
// Grab the package name
|
||||||
|
const char *I = Dir->d_name;
|
||||||
|
for (; *I != 0 && *I != '_';I++);
|
||||||
|
if (*I != '_')
|
||||||
|
continue;
|
||||||
|
string Pkg = DeQuoteString(string(Dir->d_name,I-Dir->d_name));
|
||||||
|
|
||||||
|
// Grab the version
|
||||||
|
const char *Start = I + 1;
|
||||||
|
for (I = Start; *I != 0 && *I != '_';I++);
|
||||||
|
if (*I != '_')
|
||||||
|
continue;
|
||||||
|
string Ver = DeQuoteString(string(Start,I-Start));
|
||||||
|
|
||||||
|
// Grab the arch
|
||||||
|
Start = I + 1;
|
||||||
|
for (I = Start; *I != 0 && *I != '.' ;I++);
|
||||||
|
if (*I != '.')
|
||||||
|
continue;
|
||||||
|
string Arch = DeQuoteString(string(Start,I-Start));
|
||||||
|
|
||||||
|
// Lookup the package
|
||||||
|
pkgCache::PkgIterator P = Cache.FindPkg(Pkg);
|
||||||
|
if (P.end() != true)
|
||||||
|
{
|
||||||
|
pkgCache::VerIterator V = P.VersionList();
|
||||||
|
for (; V.end() == false; V++)
|
||||||
|
{
|
||||||
|
// See if we can fetch this version at all
|
||||||
|
bool IsFetchable = false;
|
||||||
|
for (pkgCache::VerFileIterator J = V.FileList();
|
||||||
|
J.end() == false; J++)
|
||||||
|
{
|
||||||
|
if (CleanInstalled == true &&
|
||||||
|
(J.File()->Flags & pkgCache::Flag::NotSource) != 0)
|
||||||
|
continue;
|
||||||
|
IsFetchable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if this verison matches the file
|
||||||
|
if (IsFetchable == true && Ver == V.VerStr())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found a match, keep the file
|
||||||
|
if (V.end() == false)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Erase(Dir->d_name,Pkg,Ver,St);
|
||||||
|
};
|
||||||
|
|
||||||
|
chdir(StartDir.c_str());
|
||||||
|
closedir(D);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
30
apt/apt-pkg/clean.h
Normal file
30
apt/apt-pkg/clean.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: clean.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Clean - Clean out downloaded directories
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef APTPKG_CLEAN_H
|
||||||
|
#define APTPKG_CLEAN_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/clean.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/pkgcache.h>
|
||||||
|
|
||||||
|
class pkgArchiveCleaner
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void Erase(const char * /*File*/,string /*Pkg*/,string /*Ver*/,struct stat & /*St*/) {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool Go(string Dir,pkgCache &Cache);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1
apt/apt-pkg/cnc/CVS/Entries
Normal file
1
apt/apt-pkg/cnc/CVS/Entries
Normal file
@ -0,0 +1 @@
|
|||||||
|
D
|
1
apt/apt-pkg/cnc/CVS/Repository
Normal file
1
apt/apt-pkg/cnc/CVS/Repository
Normal file
@ -0,0 +1 @@
|
|||||||
|
rapt/apt-pkg/cnc
|
1
apt/apt-pkg/cnc/CVS/Root
Normal file
1
apt/apt-pkg/cnc/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@cvs.conectiva.com.br:/home/cvs
|
24
apt/apt-pkg/contrib/CVS/Entries
Normal file
24
apt/apt-pkg/contrib/CVS/Entries
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/cdromutl.cc/1.1.1.1/Fri Aug 10 14:00:24 2001//
|
||||||
|
/cdromutl.h/1.1.1.1/Fri Aug 10 14:00:24 2001//
|
||||||
|
/cmndline.cc/1.1.1.1/Fri Aug 10 14:00:24 2001//
|
||||||
|
/cmndline.h/1.1.1.1/Fri Aug 10 14:00:28 2001//
|
||||||
|
/configuration.cc/1.2/Fri Aug 10 14:00:30 2001//
|
||||||
|
/configuration.h/1.2/Fri Aug 10 14:00:30 2001//
|
||||||
|
/crc-16.cc/1.1.1.1/Fri Aug 10 14:00:30 2001//
|
||||||
|
/crc-16.h/1.1.1.1/Fri Aug 10 14:00:30 2001//
|
||||||
|
/error.h/1.1.1.1/Fri Aug 10 14:00:30 2001//
|
||||||
|
/fileutl.cc/1.3/Fri Aug 10 14:00:30 2001//
|
||||||
|
/fileutl.h/1.2/Fri Aug 10 14:00:30 2001//
|
||||||
|
/md5.cc/1.1.1.1/Fri Aug 10 14:00:32 2001//
|
||||||
|
/md5.h/1.1.1.1/Fri Aug 10 14:00:32 2001//
|
||||||
|
/mmap.cc/1.1.1.1/Fri Aug 10 14:00:32 2001//
|
||||||
|
/mmap.h/1.1.1.1/Fri Aug 10 14:00:32 2001//
|
||||||
|
/progress.h/1.1.1.1/Fri Aug 10 14:00:32 2001//
|
||||||
|
/sptr.h/1.1/Fri Aug 10 14:00:34 2001//
|
||||||
|
/strutl.cc/1.3/Fri Aug 10 14:00:34 2001//
|
||||||
|
/strutl.h/1.3/Fri Aug 10 14:00:34 2001//
|
||||||
|
/system.h/1.1.1.1/Fri Aug 10 14:00:34 2001//
|
||||||
|
/error.cc/1.4/Tue Nov 13 14:24:16 2001//
|
||||||
|
/i18n.h/1.2/Fri Nov 16 01:13:06 2001//
|
||||||
|
/progress.cc/1.3/Fri Nov 16 01:13:06 2001//
|
||||||
|
D
|
1
apt/apt-pkg/contrib/CVS/Repository
Normal file
1
apt/apt-pkg/contrib/CVS/Repository
Normal file
@ -0,0 +1 @@
|
|||||||
|
rapt/apt-pkg/contrib
|
1
apt/apt-pkg/contrib/CVS/Root
Normal file
1
apt/apt-pkg/contrib/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@cvs.conectiva.com.br:/home/cvs
|
202
apt/apt-pkg/contrib/cdromutl.cc
Normal file
202
apt/apt-pkg/contrib/cdromutl.cc
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: cdromutl.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
CDROM Utilities - Some functions to manipulate CDROM mounts.
|
||||||
|
|
||||||
|
These are here for the cdrom method and apt-cdrom.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/cdromutl.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/cdromutl.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/md5.h>
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// IsMounted - Returns true if the mount point is mounted /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is a simple algorithm that should always work, we stat the mount point
|
||||||
|
and the '..' file in the mount point and see if they are on the same device.
|
||||||
|
By definition if they are the same then it is not mounted. This should
|
||||||
|
account for symlinked mount points as well. */
|
||||||
|
bool IsMounted(string &Path)
|
||||||
|
{
|
||||||
|
if (Path.empty() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Need that trailing slash for directories
|
||||||
|
if (Path[Path.length() - 1] != '/')
|
||||||
|
Path += '/';
|
||||||
|
|
||||||
|
/* First we check if the path is actualy mounted, we do this by
|
||||||
|
stating the path and the previous directory (carefull of links!)
|
||||||
|
and comparing their device fields. */
|
||||||
|
struct stat Buf,Buf2;
|
||||||
|
if (stat(Path.c_str(),&Buf) != 0 ||
|
||||||
|
stat((Path + "../").c_str(),&Buf2) != 0)
|
||||||
|
return _error->Errno("stat","Unable to stat the mount point %s",Path.c_str());
|
||||||
|
|
||||||
|
if (Buf.st_dev == Buf2.st_dev)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// UnmountCdrom - Unmount a cdrom /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Forking umount works much better than the umount syscall which can
|
||||||
|
leave /etc/mtab inconsitant. We drop all messages this produces. */
|
||||||
|
bool UnmountCdrom(string Path)
|
||||||
|
{
|
||||||
|
if (IsMounted(Path) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int Child = ExecFork();
|
||||||
|
|
||||||
|
// The child
|
||||||
|
if (Child == 0)
|
||||||
|
{
|
||||||
|
// Make all the fds /dev/null
|
||||||
|
for (int I = 0; I != 3; I++)
|
||||||
|
dup2(open("/dev/null",O_RDWR),I);
|
||||||
|
|
||||||
|
if (_config->Exists("Acquire::cdrom::"+Path+"::UMount") == true)
|
||||||
|
{
|
||||||
|
if (system(_config->Find("Acquire::cdrom::"+Path+"::UMount").c_str()) != 0)
|
||||||
|
_exit(100);
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *Args[10];
|
||||||
|
Args[0] = "umount";
|
||||||
|
Args[1] = Path.c_str();
|
||||||
|
Args[2] = 0;
|
||||||
|
execvp(Args[0],(char **)Args);
|
||||||
|
_exit(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for mount
|
||||||
|
return ExecWait(Child,"mount",true);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MountCdrom - Mount a cdrom /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We fork mount and drop all messages */
|
||||||
|
bool MountCdrom(string Path)
|
||||||
|
{
|
||||||
|
if (IsMounted(Path) == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int Child = ExecFork();
|
||||||
|
|
||||||
|
// The child
|
||||||
|
if (Child == 0)
|
||||||
|
{
|
||||||
|
// Make all the fds /dev/null
|
||||||
|
for (int I = 0; I != 3; I++)
|
||||||
|
dup2(open("/dev/null",O_RDWR),I);
|
||||||
|
|
||||||
|
if (_config->Exists("Acquire::cdrom::"+Path+"::Mount") == true)
|
||||||
|
{
|
||||||
|
if (system(_config->Find("Acquire::cdrom::"+Path+"::Mount").c_str()) != 0)
|
||||||
|
_exit(100);
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *Args[10];
|
||||||
|
Args[0] = "mount";
|
||||||
|
Args[1] = Path.c_str();
|
||||||
|
Args[2] = 0;
|
||||||
|
execvp(Args[0],(char **)Args);
|
||||||
|
_exit(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for mount
|
||||||
|
return ExecWait(Child,"mount",true);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// IdentCdrom - Generate a unique string for this CD /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We convert everything we hash into a string, this prevents byte size/order
|
||||||
|
from effecting the outcome. */
|
||||||
|
bool IdentCdrom(string CD,string &Res,unsigned int Version)
|
||||||
|
{
|
||||||
|
MD5Summation Hash;
|
||||||
|
|
||||||
|
string StartDir = SafeGetCWD();
|
||||||
|
if (chdir(CD.c_str()) != 0)
|
||||||
|
return _error->Errno("chdir","Unable to change to %s",CD.c_str());
|
||||||
|
|
||||||
|
DIR *D = opendir(".");
|
||||||
|
if (D == 0)
|
||||||
|
return _error->Errno("opendir","Unable to read %s",CD.c_str());
|
||||||
|
|
||||||
|
/* Run over the directory, we assume that the reader order will never
|
||||||
|
change as the media is read-only. In theory if the kernel did
|
||||||
|
some sort of wacked caching this might not be true.. */
|
||||||
|
char S[300];
|
||||||
|
for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
|
||||||
|
{
|
||||||
|
// Skip some files..
|
||||||
|
if (strcmp(Dir->d_name,".") == 0 ||
|
||||||
|
strcmp(Dir->d_name,"..") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Version <= 1)
|
||||||
|
{
|
||||||
|
sprintf(S,"%lu",(unsigned long)Dir->d_ino);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct stat Buf;
|
||||||
|
if (stat(Dir->d_name,&Buf) != 0)
|
||||||
|
continue;
|
||||||
|
sprintf(S,"%lu",(unsigned long)Buf.st_mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
Hash.Add(S);
|
||||||
|
Hash.Add(Dir->d_name);
|
||||||
|
};
|
||||||
|
|
||||||
|
chdir(StartDir.c_str());
|
||||||
|
closedir(D);
|
||||||
|
|
||||||
|
// Some stats from the fsys
|
||||||
|
if (_config->FindB("Debug::identcdrom",false) == false)
|
||||||
|
{
|
||||||
|
struct statvfs Buf;
|
||||||
|
if (statvfs(CD.c_str(),&Buf) != 0)
|
||||||
|
return _error->Errno("statfs","Failed to stat the cdrom");
|
||||||
|
|
||||||
|
// We use a kilobyte block size to advoid overflow
|
||||||
|
sprintf(S,"%lu %lu",(long)(Buf.f_blocks*(Buf.f_bsize/1024)),
|
||||||
|
(long)(Buf.f_bfree*(Buf.f_bsize/1024)));
|
||||||
|
Hash.Add(S);
|
||||||
|
sprintf(S,"-%u",Version);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sprintf(S,"-%u.debug",Version);
|
||||||
|
|
||||||
|
Res = Hash.Result().Value() + S;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
23
apt/apt-pkg/contrib/cdromutl.h
Normal file
23
apt/apt-pkg/contrib/cdromutl.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: cdromutl.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
CDROM Utilities - Some functions to manipulate CDROM mounts.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_CDROMUTL_H
|
||||||
|
#define PKGLIB_ACQUIRE_METHOD_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/cdromutl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool MountCdrom(string Path);
|
||||||
|
bool UnmountCdrom(string Path);
|
||||||
|
bool IdentCdrom(string CD,string &Res,unsigned int Version = 2);
|
||||||
|
|
||||||
|
#endif
|
347
apt/apt-pkg/contrib/cmndline.cc
Normal file
347
apt/apt-pkg/contrib/cmndline.cc
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: cmndline.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Command Line Class - Sophisticated command line parser
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/cmndline.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/cmndline.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// CommandLine::CommandLine - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
CommandLine::CommandLine(Args *AList,Configuration *Conf) : ArgList(AList),
|
||||||
|
Conf(Conf), FileList(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CommandLine::~CommandLine - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
CommandLine::~CommandLine()
|
||||||
|
{
|
||||||
|
delete [] FileList;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CommandLine::Parse - Main action member /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool CommandLine::Parse(int argc,const char **argv)
|
||||||
|
{
|
||||||
|
delete [] FileList;
|
||||||
|
FileList = new const char *[argc];
|
||||||
|
const char **Files = FileList;
|
||||||
|
int I;
|
||||||
|
for (I = 1; I != argc; I++)
|
||||||
|
{
|
||||||
|
const char *Opt = argv[I];
|
||||||
|
|
||||||
|
// It is not an option
|
||||||
|
if (*Opt != '-')
|
||||||
|
{
|
||||||
|
*Files++ = Opt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Opt++;
|
||||||
|
|
||||||
|
// Double dash signifies the end of option processing
|
||||||
|
if (*Opt == '-' && Opt[1] == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Single dash is a short option
|
||||||
|
if (*Opt != '-')
|
||||||
|
{
|
||||||
|
// Iterate over each letter
|
||||||
|
while (*Opt != 0)
|
||||||
|
{
|
||||||
|
// Search for the option
|
||||||
|
Args *A;
|
||||||
|
for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
|
||||||
|
if (A->end() == true)
|
||||||
|
return _error->Error("Command line option '%c' [from %s] is not known.",*Opt,argv[I]);
|
||||||
|
|
||||||
|
if (HandleOpt(I,argc,argv,Opt,A) == false)
|
||||||
|
return false;
|
||||||
|
if (*Opt != 0)
|
||||||
|
Opt++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Opt++;
|
||||||
|
|
||||||
|
// Match up to a = against the list
|
||||||
|
const char *OptEnd = Opt;
|
||||||
|
Args *A;
|
||||||
|
for (; *OptEnd != 0 && *OptEnd != '='; OptEnd++);
|
||||||
|
for (A = ArgList; A->end() == false &&
|
||||||
|
stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++);
|
||||||
|
|
||||||
|
// Failed, look for a word after the first - (no-foo)
|
||||||
|
bool PreceedMatch = false;
|
||||||
|
if (A->end() == true)
|
||||||
|
{
|
||||||
|
for (; Opt != OptEnd && *Opt != '-'; Opt++);
|
||||||
|
|
||||||
|
if (Opt == OptEnd)
|
||||||
|
return _error->Error("Command line option %s is not understood",argv[I]);
|
||||||
|
Opt++;
|
||||||
|
|
||||||
|
for (A = ArgList; A->end() == false &&
|
||||||
|
stringcasecmp(Opt,OptEnd,A->LongOpt) != 0; A++);
|
||||||
|
|
||||||
|
// Failed again..
|
||||||
|
if (A->end() == true && OptEnd - Opt != 1)
|
||||||
|
return _error->Error("Command line option %s is not understood",argv[I]);
|
||||||
|
|
||||||
|
// The option could be a single letter option prefixed by a no-..
|
||||||
|
if (A->end() == true)
|
||||||
|
{
|
||||||
|
for (A = ArgList; A->end() == false && A->ShortOpt != *Opt; A++);
|
||||||
|
|
||||||
|
if (A->end() == true)
|
||||||
|
return _error->Error("Command line option %s is not understood",argv[I]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The option is not boolean
|
||||||
|
if (A->IsBoolean() == false)
|
||||||
|
return _error->Error("Command line option %s is not boolean",argv[I]);
|
||||||
|
PreceedMatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with it.
|
||||||
|
OptEnd--;
|
||||||
|
if (HandleOpt(I,argc,argv,OptEnd,A,PreceedMatch) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy any remaining file names over
|
||||||
|
for (; I != argc; I++)
|
||||||
|
*Files++ = argv[I];
|
||||||
|
*Files = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CommandLine::HandleOpt - Handle a single option including all flags /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is a helper function for parser, it looks at a given argument
|
||||||
|
and looks for specific patterns in the string, it gets tokanized
|
||||||
|
-ruffly- like -*[yes|true|enable]-(o|longopt)[=][ ][argument] */
|
||||||
|
bool CommandLine::HandleOpt(int &I,int argc,const char *argv[],
|
||||||
|
const char *&Opt,Args *A,bool PreceedMatch)
|
||||||
|
{
|
||||||
|
const char *Argument = 0;
|
||||||
|
bool CertainArg = false;
|
||||||
|
int IncI = 0;
|
||||||
|
|
||||||
|
/* Determine the possible location of an option or 0 if their is
|
||||||
|
no option */
|
||||||
|
if (Opt[1] == 0 || (Opt[1] == '=' && Opt[2] == 0))
|
||||||
|
{
|
||||||
|
if (I + 1 < argc && argv[I+1][0] != '-')
|
||||||
|
Argument = argv[I+1];
|
||||||
|
|
||||||
|
// Equals was specified but we fell off the end!
|
||||||
|
if (Opt[1] == '=' && Argument == 0)
|
||||||
|
return _error->Error("Option %s requires an argument.",argv[I]);
|
||||||
|
if (Opt[1] == '=')
|
||||||
|
CertainArg = true;
|
||||||
|
|
||||||
|
IncI = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Opt[1] == '=')
|
||||||
|
{
|
||||||
|
CertainArg = true;
|
||||||
|
Argument = Opt + 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Argument = Opt + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option is an argument set
|
||||||
|
if ((A->Flags & HasArg) == HasArg)
|
||||||
|
{
|
||||||
|
if (Argument == 0)
|
||||||
|
return _error->Error("Option %s requires an argument.",argv[I]);
|
||||||
|
Opt += strlen(Opt);
|
||||||
|
I += IncI;
|
||||||
|
|
||||||
|
// Parse a configuration file
|
||||||
|
if ((A->Flags & ConfigFile) == ConfigFile)
|
||||||
|
return ReadConfigFile(*Conf,Argument);
|
||||||
|
|
||||||
|
// Arbitary item specification
|
||||||
|
if ((A->Flags & ArbItem) == ArbItem)
|
||||||
|
{
|
||||||
|
const char *J;
|
||||||
|
for (J = Argument; *J != 0 && *J != '='; J++);
|
||||||
|
if (*J == 0)
|
||||||
|
return _error->Error("Option %s: Configuration item sepecification must have an =<val>.",argv[I]);
|
||||||
|
|
||||||
|
// = is trailing
|
||||||
|
if (J[1] == 0)
|
||||||
|
{
|
||||||
|
if (I+1 >= argc)
|
||||||
|
return _error->Error("Option %s: Configuration item sepecification must have an =<val>.",argv[I]);
|
||||||
|
Conf->Set(string(Argument,J-Argument),string(argv[I++ +1]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Conf->Set(string(Argument,J-Argument),string(J+1));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *I = A->ConfName;
|
||||||
|
for (; *I != 0 && *I != ' '; I++);
|
||||||
|
if (*I == ' ')
|
||||||
|
Conf->Set(string(A->ConfName,0,I-A->ConfName),string(I+1) + Argument);
|
||||||
|
else
|
||||||
|
Conf->Set(A->ConfName,string(I) + Argument);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option is an integer level
|
||||||
|
if ((A->Flags & IntLevel) == IntLevel)
|
||||||
|
{
|
||||||
|
// There might be an argument
|
||||||
|
if (Argument != 0)
|
||||||
|
{
|
||||||
|
char *EndPtr;
|
||||||
|
unsigned long Value = strtol(Argument,&EndPtr,10);
|
||||||
|
|
||||||
|
// Conversion failed and the argument was specified with an =s
|
||||||
|
if (EndPtr == Argument && CertainArg == true)
|
||||||
|
return _error->Error("Option %s requires an integer argument, not '%s'",argv[I],Argument);
|
||||||
|
|
||||||
|
// Conversion was ok, set the value and return
|
||||||
|
if (EndPtr != 0 && EndPtr != Argument && *EndPtr == 0)
|
||||||
|
{
|
||||||
|
Conf->Set(A->ConfName,Value);
|
||||||
|
Opt += strlen(Opt);
|
||||||
|
I += IncI;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase the level
|
||||||
|
Conf->Set(A->ConfName,Conf->FindI(A->ConfName)+1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option is a boolean
|
||||||
|
int Sense = -1; // -1 is unspecified, 0 is yes 1 is no
|
||||||
|
|
||||||
|
// Look for an argument.
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// Look at preceeding text
|
||||||
|
char Buffer[300];
|
||||||
|
if (Argument == 0)
|
||||||
|
{
|
||||||
|
if (PreceedMatch == false)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (strlen(argv[I]) >= sizeof(Buffer))
|
||||||
|
return _error->Error("Option '%s' is too long",argv[I]);
|
||||||
|
|
||||||
|
// Skip the leading dash
|
||||||
|
const char *J = argv[I];
|
||||||
|
for (; *J != 0 && *J == '-'; J++);
|
||||||
|
|
||||||
|
const char *JEnd = J;
|
||||||
|
for (; *JEnd != 0 && *JEnd != '-'; JEnd++);
|
||||||
|
if (*JEnd != 0)
|
||||||
|
{
|
||||||
|
strncpy(Buffer,J,JEnd - J);
|
||||||
|
Buffer[JEnd - J] = 0;
|
||||||
|
Argument = Buffer;
|
||||||
|
CertainArg = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for boolean
|
||||||
|
Sense = StringToBool(Argument);
|
||||||
|
if (Sense >= 0)
|
||||||
|
{
|
||||||
|
// Eat the argument
|
||||||
|
if (Argument != Buffer)
|
||||||
|
{
|
||||||
|
Opt += strlen(Opt);
|
||||||
|
I += IncI;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CertainArg == true)
|
||||||
|
return _error->Error("Sense %s is not understood, try true or false.",Argument);
|
||||||
|
|
||||||
|
Argument = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indeterminate sense depends on the flag
|
||||||
|
if (Sense == -1)
|
||||||
|
{
|
||||||
|
if ((A->Flags & InvBoolean) == InvBoolean)
|
||||||
|
Sense = 0;
|
||||||
|
else
|
||||||
|
Sense = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Conf->Set(A->ConfName,Sense);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CommandLine::FileSize - Count the number of filenames /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
unsigned int CommandLine::FileSize() const
|
||||||
|
{
|
||||||
|
unsigned int Count = 0;
|
||||||
|
for (const char **I = FileList; I != 0 && *I != 0; I++)
|
||||||
|
Count++;
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CommandLine::DispatchArg - Do something with the first arg /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool CommandLine::DispatchArg(Dispatch *Map,bool NoMatch)
|
||||||
|
{
|
||||||
|
int I;
|
||||||
|
for (I = 0; Map[I].Match != 0; I++)
|
||||||
|
{
|
||||||
|
if (strcmp(FileList[0],Map[I].Match) == 0)
|
||||||
|
{
|
||||||
|
bool Res = Map[I].Handler(*this);
|
||||||
|
if (Res == false && _error->PendingError() == false)
|
||||||
|
_error->Error("Handler silently failed");
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matching name
|
||||||
|
if (Map[I].Match == 0)
|
||||||
|
{
|
||||||
|
if (NoMatch == true)
|
||||||
|
_error->Error("Invalid operation %s",FileList[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
106
apt/apt-pkg/contrib/cmndline.h
Normal file
106
apt/apt-pkg/contrib/cmndline.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: cmndline.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Command Line Class - Sophisticated command line parser
|
||||||
|
|
||||||
|
This class provides a unified command line parser/option handliner/
|
||||||
|
configuration mechanism. It allows the caller to specify the option
|
||||||
|
set and map the option set into the configuration class or other
|
||||||
|
special functioning.
|
||||||
|
|
||||||
|
Filenames are stripped from the option stream and put into their
|
||||||
|
own array.
|
||||||
|
|
||||||
|
The argument descriptor array can be initialized as:
|
||||||
|
|
||||||
|
CommandLine::Args Args[] =
|
||||||
|
{{'q',"quiet","apt::get::quiet",CommandLine::IntLevel},
|
||||||
|
{0,0,0,0}};
|
||||||
|
|
||||||
|
The flags mean,
|
||||||
|
HasArg - Means the argument has a value
|
||||||
|
IntLevel - Means the argument is an integer level indication, the
|
||||||
|
following -qqqq (+3) -q5 (=5) -q=5 (=5) are valid
|
||||||
|
Boolean - Means it is true/false or yes/no.
|
||||||
|
-d (true) --no-d (false) --yes-d (true)
|
||||||
|
--long (true) --no-long (false) --yes-long (true)
|
||||||
|
-d=yes (true) -d=no (false) Words like enable, disable,
|
||||||
|
true false, yes no and on off are recognized in logical
|
||||||
|
places.
|
||||||
|
InvBoolean - Same as boolean but the case with no specified sense
|
||||||
|
(first case) is set to false.
|
||||||
|
ConfigFile - Means this flag should be interprited as the name of
|
||||||
|
a config file to read in at this point in option processing.
|
||||||
|
Implies HasArg.
|
||||||
|
ArbItem - Means the item is an arbitary configuration string of
|
||||||
|
the form item=value, where item is passed directly
|
||||||
|
to the configuration class.
|
||||||
|
The default, if the flags are 0 is to use Boolean
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_CMNDLINE_H
|
||||||
|
#define PKGLIB_CMNDLINE_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/cmndline.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
|
||||||
|
class CommandLine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Args;
|
||||||
|
struct Dispatch;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Args *ArgList;
|
||||||
|
Configuration *Conf;
|
||||||
|
bool HandleOpt(int &I,int argc,const char *argv[],
|
||||||
|
const char *&Opt,Args *A,bool PreceedeMatch = false);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum AFlags
|
||||||
|
{
|
||||||
|
HasArg = (1 << 0),
|
||||||
|
IntLevel = (1 << 1),
|
||||||
|
Boolean = (1 << 2),
|
||||||
|
InvBoolean = (1 << 3),
|
||||||
|
ConfigFile = (1 << 4) | HasArg,
|
||||||
|
ArbItem = (1 << 5) | HasArg
|
||||||
|
};
|
||||||
|
|
||||||
|
const char **FileList;
|
||||||
|
|
||||||
|
bool Parse(int argc,const char **argv);
|
||||||
|
void ShowHelp();
|
||||||
|
unsigned int FileSize() const;
|
||||||
|
bool DispatchArg(Dispatch *List,bool NoMatch = true);
|
||||||
|
|
||||||
|
CommandLine(Args *AList,Configuration *Conf);
|
||||||
|
~CommandLine();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommandLine::Args
|
||||||
|
{
|
||||||
|
char ShortOpt;
|
||||||
|
const char *LongOpt;
|
||||||
|
const char *ConfName;
|
||||||
|
unsigned long Flags;
|
||||||
|
|
||||||
|
inline bool end() {return ShortOpt == 0 && LongOpt == 0;};
|
||||||
|
inline bool IsBoolean() {return Flags == 0 || (Flags & (Boolean|InvBoolean)) != 0;};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CommandLine::Dispatch
|
||||||
|
{
|
||||||
|
const char *Match;
|
||||||
|
bool (*Handler)(CommandLine &);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
665
apt/apt-pkg/contrib/configuration.cc
Normal file
665
apt/apt-pkg/contrib/configuration.cc
Normal file
@ -0,0 +1,665 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: configuration.cc,v 1.2 2000/10/30 18:49:49 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Configuration Class
|
||||||
|
|
||||||
|
This class provides a configuration file and command line parser
|
||||||
|
for a tree-oriented configuration environment. All runtime configuration
|
||||||
|
is stored in here.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/configuration.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fstream.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
Configuration *_config = new Configuration;
|
||||||
|
|
||||||
|
// Configuration::Configuration - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
Configuration::Configuration() : ToFree(true)
|
||||||
|
{
|
||||||
|
Root = new Item;
|
||||||
|
}
|
||||||
|
Configuration::Configuration(const Item *Root) : Root((Item *)Root), ToFree(false)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::~Configuration - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
Configuration::~Configuration()
|
||||||
|
{
|
||||||
|
if (ToFree == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Item *Top = Root;
|
||||||
|
for (; Top != 0;)
|
||||||
|
{
|
||||||
|
if (Top->Child != 0)
|
||||||
|
{
|
||||||
|
Top = Top->Child;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Top != 0 && Top->Next == 0)
|
||||||
|
{
|
||||||
|
Item *Parent = Top->Parent;
|
||||||
|
delete Top;
|
||||||
|
Top = Parent;
|
||||||
|
}
|
||||||
|
if (Top != 0)
|
||||||
|
{
|
||||||
|
Item *Next = Top->Next;
|
||||||
|
delete Top;
|
||||||
|
Top = Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Lookup - Lookup a single item /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This will lookup a single item by name below another item. It is a
|
||||||
|
helper function for the main lookup function */
|
||||||
|
Configuration::Item *Configuration::Lookup(Item *Head,const char *S,
|
||||||
|
unsigned long Len,bool Create)
|
||||||
|
{
|
||||||
|
int Res = 1;
|
||||||
|
Item *I = Head->Child;
|
||||||
|
Item **Last = &Head->Child;
|
||||||
|
|
||||||
|
// Empty strings match nothing. They are used for lists.
|
||||||
|
if (Len != 0)
|
||||||
|
{
|
||||||
|
for (; I != 0; Last = &I->Next, I = I->Next)
|
||||||
|
if ((Res = stringcasecmp(I->Tag.begin(),I->Tag.end(),S,S + Len)) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (; I != 0; Last = &I->Next, I = I->Next);
|
||||||
|
|
||||||
|
if (Res == 0)
|
||||||
|
return I;
|
||||||
|
if (Create == false)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
I = new Item;
|
||||||
|
I->Tag = string(S,Len);
|
||||||
|
I->Next = *Last;
|
||||||
|
I->Parent = Head;
|
||||||
|
*Last = I;
|
||||||
|
return I;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Lookup - Lookup a fully scoped item /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This performs a fully scoped lookup of a given name, possibly creating
|
||||||
|
new items */
|
||||||
|
Configuration::Item *Configuration::Lookup(const char *Name,bool Create)
|
||||||
|
{
|
||||||
|
if (Name == 0)
|
||||||
|
return Root->Child;
|
||||||
|
|
||||||
|
const char *Start = Name;
|
||||||
|
const char *End = Start + strlen(Name);
|
||||||
|
const char *TagEnd = Name;
|
||||||
|
Item *Itm = Root;
|
||||||
|
for (; End - TagEnd >= 2; TagEnd++)
|
||||||
|
{
|
||||||
|
if (TagEnd[0] == ':' && TagEnd[1] == ':')
|
||||||
|
{
|
||||||
|
Itm = Lookup(Itm,Start,TagEnd - Start,Create);
|
||||||
|
if (Itm == 0)
|
||||||
|
return 0;
|
||||||
|
TagEnd = Start = TagEnd + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This must be a trailing ::, we create unique items in a list
|
||||||
|
if (End - Start == 0)
|
||||||
|
{
|
||||||
|
if (Create == false)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Itm = Lookup(Itm,Start,End - Start,Create);
|
||||||
|
return Itm;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Find - Find a value /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string Configuration::Find(const char *Name,const char *Default) const
|
||||||
|
{
|
||||||
|
const Item *Itm = Lookup(Name);
|
||||||
|
if (Itm == 0 || Itm->Value.empty() == true)
|
||||||
|
{
|
||||||
|
if (Default == 0)
|
||||||
|
return string();
|
||||||
|
else
|
||||||
|
return Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Itm->Value;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::FindFile - Find a Filename /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Directories are stored as the base dir in the Parent node and the
|
||||||
|
sub directory in sub nodes with the final node being the end filename
|
||||||
|
*/
|
||||||
|
string Configuration::FindFile(const char *Name,const char *Default) const
|
||||||
|
{
|
||||||
|
const Item *Itm = Lookup(Name);
|
||||||
|
if (Itm == 0 || Itm->Value.empty() == true)
|
||||||
|
{
|
||||||
|
if (Default == 0)
|
||||||
|
return string();
|
||||||
|
else
|
||||||
|
return Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
string val = Itm->Value;
|
||||||
|
while (Itm->Parent != 0 && Itm->Parent->Value.empty() == false)
|
||||||
|
{
|
||||||
|
// Absolute
|
||||||
|
if (val[0] == '/')
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ~/foo or ./foo
|
||||||
|
if ((val[0] == '~' || val[0] == '.') && val[1] == '/')
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ../foo
|
||||||
|
if (val[0] == '.' && val[1] == '.' && val[2] == '/')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (Itm->Parent->Value.end()[-1] != '/')
|
||||||
|
val.insert(0, "/");
|
||||||
|
|
||||||
|
val.insert(0, Itm->Parent->Value);
|
||||||
|
Itm = Itm->Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::FindDir - Find a directory name /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is like findfile execept the result is terminated in a / */
|
||||||
|
string Configuration::FindDir(const char *Name,const char *Default) const
|
||||||
|
{
|
||||||
|
string Res = FindFile(Name,Default);
|
||||||
|
if (Res.end()[-1] != '/')
|
||||||
|
return Res + '/';
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::FindI - Find an integer value /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
int Configuration::FindI(const char *Name,int Default) const
|
||||||
|
{
|
||||||
|
const Item *Itm = Lookup(Name);
|
||||||
|
if (Itm == 0 || Itm->Value.empty() == true)
|
||||||
|
return Default;
|
||||||
|
|
||||||
|
char *End;
|
||||||
|
int Res = strtol(Itm->Value.c_str(),&End,0);
|
||||||
|
if (End == Itm->Value.c_str())
|
||||||
|
return Default;
|
||||||
|
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::FindB - Find a boolean type /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool Configuration::FindB(const char *Name,bool Default) const
|
||||||
|
{
|
||||||
|
const Item *Itm = Lookup(Name);
|
||||||
|
if (Itm == 0 || Itm->Value.empty() == true)
|
||||||
|
return Default;
|
||||||
|
|
||||||
|
return StringToBool(Itm->Value,Default);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::FindAny - Find an arbitrary type /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* a key suffix of /f, /d, /b or /i calls Find{File,Dir,B,I} */
|
||||||
|
string Configuration::FindAny(const char *Name,const char *Default) const
|
||||||
|
{
|
||||||
|
string key = Name;
|
||||||
|
char type = 0;
|
||||||
|
|
||||||
|
if (key.size() > 2 && key.end()[-2] == '/')
|
||||||
|
{
|
||||||
|
type = key.end()[-1];
|
||||||
|
key.resize(key.size() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
// file
|
||||||
|
case 'f':
|
||||||
|
return FindFile(key.c_str(), Default);
|
||||||
|
|
||||||
|
// directory
|
||||||
|
case 'd':
|
||||||
|
return FindDir(key.c_str(), Default);
|
||||||
|
|
||||||
|
// bool
|
||||||
|
case 'b':
|
||||||
|
return FindB(key, Default) ? "true" : "false";
|
||||||
|
|
||||||
|
// int
|
||||||
|
case 'i':
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
snprintf(buf, sizeof(buf)-1, "%d", FindI(key, Default));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
return Find(Name, Default);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::CndSet - Conditinal Set a value /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This will not overwrite */
|
||||||
|
void Configuration::CndSet(const char *Name,string Value)
|
||||||
|
{
|
||||||
|
Item *Itm = Lookup(Name,true);
|
||||||
|
if (Itm == 0)
|
||||||
|
return;
|
||||||
|
if (Itm->Value.empty() == true)
|
||||||
|
Itm->Value = Value;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Set - Set a value /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void Configuration::Set(const char *Name,string Value)
|
||||||
|
{
|
||||||
|
Item *Itm = Lookup(Name,true);
|
||||||
|
if (Itm == 0)
|
||||||
|
return;
|
||||||
|
Itm->Value = Value;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Set - Set an integer value /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void Configuration::Set(const char *Name,int Value)
|
||||||
|
{
|
||||||
|
Item *Itm = Lookup(Name,true);
|
||||||
|
if (Itm == 0)
|
||||||
|
return;
|
||||||
|
char S[300];
|
||||||
|
snprintf(S,sizeof(S),"%i",Value);
|
||||||
|
Itm->Value = S;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Clear - Clear an entire tree /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void Configuration::Clear(string Name)
|
||||||
|
{
|
||||||
|
Item *Top = Lookup(Name.c_str(),false);
|
||||||
|
if (Top == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Top->Value = string();
|
||||||
|
Item *Stop = Top;
|
||||||
|
Top = Top->Child;
|
||||||
|
Stop->Child = 0;
|
||||||
|
for (; Top != 0;)
|
||||||
|
{
|
||||||
|
if (Top->Child != 0)
|
||||||
|
{
|
||||||
|
Top = Top->Child;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Top != 0 && Top->Next == 0)
|
||||||
|
{
|
||||||
|
if (Top == Stop)
|
||||||
|
return;
|
||||||
|
Item *Tmp = Top;
|
||||||
|
Top = Top->Parent;
|
||||||
|
delete Tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item *Tmp = Top;
|
||||||
|
if (Top != 0)
|
||||||
|
Top = Top->Next;
|
||||||
|
delete Tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Exists - Returns true if the Name exists /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool Configuration::Exists(const char *Name) const
|
||||||
|
{
|
||||||
|
const Item *Itm = Lookup(Name);
|
||||||
|
if (Itm == 0)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::ExistsAny - Returns true if the Name, possibly /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* qualified by /[fdbi] exists */
|
||||||
|
bool Configuration::ExistsAny(const char *Name) const
|
||||||
|
{
|
||||||
|
string key = Name;
|
||||||
|
|
||||||
|
if (key.size() > 2 && key.end()[-2] == '/' &&
|
||||||
|
key.find_first_of("fdbi",key.size()-1) < key.size())
|
||||||
|
{
|
||||||
|
key.resize(key.size() - 2);
|
||||||
|
if (Exists(key.c_str()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Exists(Name);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Configuration::Dump - Dump the config /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Dump the entire configuration space */
|
||||||
|
void Configuration::Dump()
|
||||||
|
{
|
||||||
|
/* Write out all of the configuration directives by walking the
|
||||||
|
configuration tree */
|
||||||
|
const Configuration::Item *Top = Tree(0);
|
||||||
|
for (; Top != 0;)
|
||||||
|
{
|
||||||
|
clog << Top->FullTag() << " \"" << Top->Value << "\";" << endl;
|
||||||
|
|
||||||
|
if (Top->Child != 0)
|
||||||
|
{
|
||||||
|
Top = Top->Child;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Top != 0 && Top->Next == 0)
|
||||||
|
Top = Top->Parent;
|
||||||
|
if (Top != 0)
|
||||||
|
Top = Top->Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// Configuration::Item::FullTag - Return the fully scoped tag /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Stop sets an optional max recursion depth if this item is being viewed as
|
||||||
|
part of a sub tree. */
|
||||||
|
string Configuration::Item::FullTag(const Item *Stop) const
|
||||||
|
{
|
||||||
|
if (Parent == 0 || Parent->Parent == 0 || Parent == Stop)
|
||||||
|
return Tag;
|
||||||
|
return Parent->FullTag(Stop) + "::" + Tag;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// ReadConfigFile - Read a configuration file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The configuration format is very much like the named.conf format
|
||||||
|
used in bind8, in fact this routine can parse most named.conf files.
|
||||||
|
Sectional config files are like bind's named.conf where there are
|
||||||
|
sections like 'zone "foo.org" { .. };' This causes each section to be
|
||||||
|
added in with a tag like "zone::foo.org" instead of being split
|
||||||
|
tag/value. */
|
||||||
|
bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional,
|
||||||
|
unsigned Depth)
|
||||||
|
{
|
||||||
|
// Open the stream for reading
|
||||||
|
ifstream F(FName.c_str(),ios::in | ios::nocreate);
|
||||||
|
if (!F != 0)
|
||||||
|
return _error->Errno("ifstream::ifstream","Opening configuration file %s",FName.c_str());
|
||||||
|
|
||||||
|
char Buffer[300];
|
||||||
|
string LineBuffer;
|
||||||
|
string Stack[100];
|
||||||
|
unsigned int StackPos = 0;
|
||||||
|
|
||||||
|
// Parser state
|
||||||
|
string ParentTag;
|
||||||
|
|
||||||
|
int CurLine = 0;
|
||||||
|
bool InComment = false;
|
||||||
|
while (F.eof() == false)
|
||||||
|
{
|
||||||
|
F.getline(Buffer,sizeof(Buffer));
|
||||||
|
CurLine++;
|
||||||
|
_strtabexpand(Buffer,sizeof(Buffer));
|
||||||
|
_strstrip(Buffer);
|
||||||
|
|
||||||
|
// Multi line comment
|
||||||
|
if (InComment == true)
|
||||||
|
{
|
||||||
|
for (const char *I = Buffer; *I != 0; I++)
|
||||||
|
{
|
||||||
|
if (*I == '*' && I[1] == '/')
|
||||||
|
{
|
||||||
|
memmove(Buffer,I+2,strlen(I+2) + 1);
|
||||||
|
InComment = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (InComment == true)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discard single line comments
|
||||||
|
bool InQuote = false;
|
||||||
|
for (char *I = Buffer; *I != 0; I++)
|
||||||
|
{
|
||||||
|
if (*I == '"')
|
||||||
|
InQuote = !InQuote;
|
||||||
|
if (InQuote == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (*I == '/' && I[1] == '/')
|
||||||
|
{
|
||||||
|
*I = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for multi line comments
|
||||||
|
InQuote = false;
|
||||||
|
for (char *I = Buffer; *I != 0; I++)
|
||||||
|
{
|
||||||
|
if (*I == '"')
|
||||||
|
InQuote = !InQuote;
|
||||||
|
if (InQuote == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (*I == '/' && I[1] == '*')
|
||||||
|
{
|
||||||
|
InComment = true;
|
||||||
|
for (char *J = Buffer; *J != 0; J++)
|
||||||
|
{
|
||||||
|
if (*J == '*' && J[1] == '/')
|
||||||
|
{
|
||||||
|
memmove(I,J+2,strlen(J+2) + 1);
|
||||||
|
InComment = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InComment == true)
|
||||||
|
{
|
||||||
|
*I = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blank
|
||||||
|
if (Buffer[0] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We now have a valid line fragment
|
||||||
|
InQuote = false;
|
||||||
|
for (char *I = Buffer; *I != 0;)
|
||||||
|
{
|
||||||
|
if (*I == '"')
|
||||||
|
InQuote = !InQuote;
|
||||||
|
|
||||||
|
if (InQuote == false && (*I == '{' || *I == ';' || *I == '}'))
|
||||||
|
{
|
||||||
|
// Put the last fragment into the buffer
|
||||||
|
char *Start = Buffer;
|
||||||
|
char *Stop = I;
|
||||||
|
for (; Start != I && isspace(*Start) != 0; Start++);
|
||||||
|
for (; Stop != Start && isspace(Stop[-1]) != 0; Stop--);
|
||||||
|
if (LineBuffer.empty() == false && Stop - Start != 0)
|
||||||
|
LineBuffer += ' ';
|
||||||
|
LineBuffer += string(Start,Stop - Start);
|
||||||
|
|
||||||
|
// Remove the fragment
|
||||||
|
char TermChar = *I;
|
||||||
|
memmove(Buffer,I + 1,strlen(I + 1) + 1);
|
||||||
|
I = Buffer;
|
||||||
|
|
||||||
|
// Syntax Error
|
||||||
|
if (TermChar == '{' && LineBuffer.empty() == true)
|
||||||
|
return _error->Error("Syntax error %s:%u: Block starts with no name.",FName.c_str(),CurLine);
|
||||||
|
|
||||||
|
// No string on this line
|
||||||
|
if (LineBuffer.empty() == true)
|
||||||
|
{
|
||||||
|
if (TermChar == '}')
|
||||||
|
{
|
||||||
|
if (StackPos == 0)
|
||||||
|
ParentTag = string();
|
||||||
|
else
|
||||||
|
ParentTag = Stack[--StackPos];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse off the tag
|
||||||
|
string Tag;
|
||||||
|
const char *Pos = LineBuffer.c_str();
|
||||||
|
if (ParseQuoteWord(Pos,Tag) == false)
|
||||||
|
return _error->Error("Syntax error %s:%u: Malformed Tag",FName.c_str(),CurLine);
|
||||||
|
|
||||||
|
// Parse off the word
|
||||||
|
string Word;
|
||||||
|
if (ParseCWord(Pos,Word) == false &&
|
||||||
|
ParseQuoteWord(Pos,Word) == false)
|
||||||
|
{
|
||||||
|
if (TermChar != '{')
|
||||||
|
{
|
||||||
|
Word = Tag;
|
||||||
|
Tag = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strlen(Pos) != 0)
|
||||||
|
return _error->Error("Syntax error %s:%u: Extra junk after value",FName.c_str(),CurLine);
|
||||||
|
|
||||||
|
// Go down a level
|
||||||
|
if (TermChar == '{')
|
||||||
|
{
|
||||||
|
if (StackPos <= 100)
|
||||||
|
Stack[StackPos++] = ParentTag;
|
||||||
|
|
||||||
|
/* Make sectional tags incorperate the section into the
|
||||||
|
tag string */
|
||||||
|
if (AsSectional == true && Word.empty() == false)
|
||||||
|
{
|
||||||
|
Tag += "::" ;
|
||||||
|
Tag += Word;
|
||||||
|
Word = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ParentTag.empty() == true)
|
||||||
|
ParentTag = Tag;
|
||||||
|
else
|
||||||
|
ParentTag += string("::") + Tag;
|
||||||
|
Tag = string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the item name
|
||||||
|
string Item;
|
||||||
|
if (ParentTag.empty() == true)
|
||||||
|
Item = Tag;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (TermChar != '{' || Tag.empty() == false)
|
||||||
|
Item = ParentTag + "::" + Tag;
|
||||||
|
else
|
||||||
|
Item = ParentTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specials
|
||||||
|
if (Tag[0] == '#')
|
||||||
|
{
|
||||||
|
if (ParentTag.empty() == false)
|
||||||
|
return _error->Error("Syntax error %s:%u: Directives can only be done at the top level",FName.c_str(),CurLine);
|
||||||
|
Tag.erase(Tag.begin());
|
||||||
|
if (Tag == "clear")
|
||||||
|
Conf.Clear(Word);
|
||||||
|
else if (Tag == "include")
|
||||||
|
{
|
||||||
|
if (Depth > 10)
|
||||||
|
return _error->Error("Syntax error %s:%u: Too many nested includes",FName.c_str(),CurLine);
|
||||||
|
if (ReadConfigFile(Conf,Word,AsSectional,Depth+1) == false)
|
||||||
|
return _error->Error("Syntax error %s:%u: Included from here",FName.c_str(),CurLine);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return _error->Error("Syntax error %s:%u: Unsupported directive '%s'",FName.c_str(),CurLine,Tag.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set the item in the configuration class
|
||||||
|
Conf.Set(Item,Word);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty the buffer
|
||||||
|
LineBuffer = string();
|
||||||
|
|
||||||
|
// Move up a tag, but only if there is no bit to parse
|
||||||
|
if (TermChar == '}')
|
||||||
|
{
|
||||||
|
if (StackPos == 0)
|
||||||
|
ParentTag = string();
|
||||||
|
else
|
||||||
|
ParentTag = Stack[--StackPos];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
I++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the fragment
|
||||||
|
const char *Stripd = _strstrip(Buffer);
|
||||||
|
if (*Stripd != 0 && LineBuffer.empty() == false)
|
||||||
|
LineBuffer += " ";
|
||||||
|
LineBuffer += Stripd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LineBuffer.empty() == false)
|
||||||
|
return _error->Error("Syntax error %s:%u: Extra junk at end of file",FName.c_str(),CurLine);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
103
apt/apt-pkg/contrib/configuration.h
Normal file
103
apt/apt-pkg/contrib/configuration.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: configuration.h,v 1.2 2000/10/30 18:49:49 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Configuration Class
|
||||||
|
|
||||||
|
This class provides a configuration file and command line parser
|
||||||
|
for a tree-oriented configuration environment. All runtime configuration
|
||||||
|
is stored in here.
|
||||||
|
|
||||||
|
Each configuration name is given as a fully scoped string such as
|
||||||
|
Foo::Bar
|
||||||
|
And has associated with it a text string. The Configuration class only
|
||||||
|
provides storage and lookup for this tree, other classes provide
|
||||||
|
configuration file formats (and parsers/emitters if needed).
|
||||||
|
|
||||||
|
Most things can get by quite happily with,
|
||||||
|
cout << _config->Find("Foo::Bar") << endl;
|
||||||
|
|
||||||
|
A special extension, support for ordered lists is provided by using the
|
||||||
|
special syntax, "block::list::" the trailing :: designates the
|
||||||
|
item as a list. To access the list you must use the tree function on
|
||||||
|
"block::list".
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_CONFIGURATION_H
|
||||||
|
#define PKGLIB_CONFIGURATION_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/configuration.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Configuration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
string Value;
|
||||||
|
string Tag;
|
||||||
|
Item *Parent;
|
||||||
|
Item *Child;
|
||||||
|
Item *Next;
|
||||||
|
|
||||||
|
string FullTag(const Item *Stop = 0) const;
|
||||||
|
|
||||||
|
Item() : Parent(0), Child(0), Next(0) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Item *Root;
|
||||||
|
bool ToFree;
|
||||||
|
|
||||||
|
Item *Lookup(Item *Head,const char *S,unsigned long Len,bool Create);
|
||||||
|
Item *Lookup(const char *Name,bool Create);
|
||||||
|
inline const Item *Lookup(const char *Name) const
|
||||||
|
{
|
||||||
|
return ((Configuration *)this)->Lookup(Name,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
string Find(const char *Name,const char *Default = 0) const;
|
||||||
|
string Find(string Name,const char *Default = 0) const {return Find(Name.c_str(),Default);};
|
||||||
|
string FindFile(const char *Name,const char *Default = 0) const;
|
||||||
|
string FindDir(const char *Name,const char *Default = 0) const;
|
||||||
|
int FindI(const char *Name,int Default = 0) const;
|
||||||
|
int FindI(string Name,bool Default = 0) const {return FindI(Name.c_str(),Default);};
|
||||||
|
bool FindB(const char *Name,bool Default = false) const;
|
||||||
|
bool FindB(string Name,bool Default = false) const {return FindB(Name.c_str(),Default);};
|
||||||
|
string FindAny(const char *Name,const char *Default = 0) const;
|
||||||
|
|
||||||
|
inline void Set(string Name,string Value) {Set(Name.c_str(),Value);};
|
||||||
|
void CndSet(const char *Name,string Value);
|
||||||
|
void Set(const char *Name,string Value);
|
||||||
|
void Set(const char *Name,int Value);
|
||||||
|
|
||||||
|
inline bool Exists(string Name) const {return Exists(Name.c_str());};
|
||||||
|
bool Exists(const char *Name) const;
|
||||||
|
bool ExistsAny(const char *Name) const;
|
||||||
|
|
||||||
|
void Clear(string Name);
|
||||||
|
|
||||||
|
inline const Item *Tree(const char *Name) const {return Lookup(Name);};
|
||||||
|
|
||||||
|
void Dump();
|
||||||
|
|
||||||
|
Configuration(const Item *Root);
|
||||||
|
Configuration();
|
||||||
|
~Configuration();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Configuration *_config;
|
||||||
|
|
||||||
|
bool ReadConfigFile(Configuration &Conf,string FName,bool AsSectional = false,
|
||||||
|
unsigned Depth = 0);
|
||||||
|
|
||||||
|
#endif
|
76
apt/apt-pkg/contrib/crc-16.cc
Normal file
76
apt/apt-pkg/contrib/crc-16.cc
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: crc-16.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
CRC16 - Compute a 16bit crc very quickly
|
||||||
|
|
||||||
|
This was ripped out of the linux 2.2 kernel source (irda/crc.c) and
|
||||||
|
is credited to ppp.c by Michael Callahan <callahan@maths.ox.ac.uk> and
|
||||||
|
Al Longyear <longyear@netcom.com>
|
||||||
|
|
||||||
|
Modified by Jason Gunthorpe <jgg@debian.org> to fit the local coding
|
||||||
|
style, this code is belived to be in the Public Domain.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/crc-16.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/crc-16.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This mysterious table is just the CRC of each possible byte. It can be
|
||||||
|
* computed using the standard bit-at-a-time methods. The polynomial can
|
||||||
|
* be seen in entry 128, 0x8408. This corresponds to x^0 + x^5 + x^12.
|
||||||
|
* Add the implicit x^16, and you have the standard CRC-CCITT.
|
||||||
|
*/
|
||||||
|
static unsigned short const crc16_table[256] =
|
||||||
|
{
|
||||||
|
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
|
||||||
|
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
|
||||||
|
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
|
||||||
|
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
|
||||||
|
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
|
||||||
|
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
|
||||||
|
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
|
||||||
|
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
|
||||||
|
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
|
||||||
|
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
|
||||||
|
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
|
||||||
|
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
|
||||||
|
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
|
||||||
|
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
|
||||||
|
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
|
||||||
|
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
|
||||||
|
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
|
||||||
|
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
|
||||||
|
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
|
||||||
|
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
|
||||||
|
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
|
||||||
|
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
|
||||||
|
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
|
||||||
|
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
|
||||||
|
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
|
||||||
|
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
|
||||||
|
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
|
||||||
|
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
|
||||||
|
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
|
||||||
|
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
|
||||||
|
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
|
||||||
|
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Recompute the FCS with one more character appended. */
|
||||||
|
#define CalcFCS(fcs, c) (((fcs) >> 8) ^ crc16_table[((fcs) ^ (c)) & 0xff])
|
||||||
|
unsigned short AddCRC16(unsigned short fcs, void const *Buf,
|
||||||
|
unsigned long len)
|
||||||
|
{
|
||||||
|
unsigned char const *buf = (unsigned char const *)Buf;
|
||||||
|
while (len--)
|
||||||
|
fcs = CalcFCS(fcs, *buf++);
|
||||||
|
return fcs;
|
||||||
|
}
|
21
apt/apt-pkg/contrib/crc-16.h
Normal file
21
apt/apt-pkg/contrib/crc-16.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: crc-16.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
CRC16 - Compute a 16bit crc very quickly
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef APTPKG_CRC16_H
|
||||||
|
#define APTPKG_CRC16_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/crc-16.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INIT_FCS 0xffff
|
||||||
|
unsigned short AddCRC16(unsigned short fcs, void const *buf,
|
||||||
|
unsigned long len);
|
||||||
|
|
||||||
|
#endif
|
239
apt/apt-pkg/contrib/error.cc
Normal file
239
apt/apt-pkg/contrib/error.cc
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: error.cc,v 1.4 2001/11/12 16:04:37 kojima 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 /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/error.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// Global Error Object /*{{{*/
|
||||||
|
/* If the implementation supports posix threads then the accessor function
|
||||||
|
is compiled to be thread safe otherwise a non-safe version is used. A
|
||||||
|
Per-Thread error object is maintained in much the same manner as libc
|
||||||
|
manages errno */
|
||||||
|
#if _POSIX_THREADS == 1 && defined(HAVE_PTHREAD)
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
static pthread_key_t ErrorKey;
|
||||||
|
static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
|
||||||
|
static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
|
||||||
|
|
||||||
|
GlobalError *_GetErrorObj()
|
||||||
|
{
|
||||||
|
static pthread_once_t Once = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once(&Once,KeyAlloc);
|
||||||
|
|
||||||
|
void *Res = pthread_getspecific(ErrorKey);
|
||||||
|
if (Res == 0)
|
||||||
|
pthread_setspecific(ErrorKey,Res = new GlobalError);
|
||||||
|
return (GlobalError *)Res;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
GlobalError *_GetErrorObj()
|
||||||
|
{
|
||||||
|
static GlobalError *Obj = new GlobalError;
|
||||||
|
return Obj;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// GlobalError::GlobalError - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
GlobalError::GlobalError() : List(0), 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];
|
||||||
|
vsnprintf(S,sizeof(S),Description,args);
|
||||||
|
snprintf(S + strlen(S),sizeof(S) - strlen(S),
|
||||||
|
" - %s (%i %s)",Function,errno,strerror(errno));
|
||||||
|
|
||||||
|
// Put it on the list
|
||||||
|
Item *Itm = new Item;
|
||||||
|
Itm->Text = S;
|
||||||
|
Itm->Error = true;
|
||||||
|
Insert(Itm);
|
||||||
|
|
||||||
|
PendingFlag = true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// GlobalError::WarningE - Get part of the warn 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::WarningE(const char *Function,const char *Description,...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args,Description);
|
||||||
|
|
||||||
|
// sprintf the description
|
||||||
|
char S[400];
|
||||||
|
vsnprintf(S,sizeof(S),Description,args);
|
||||||
|
snprintf(S + strlen(S),sizeof(S) - strlen(S)," - %s (%i %s)",Function,errno,strerror(errno));
|
||||||
|
|
||||||
|
// Put it on the list
|
||||||
|
Item *Itm = new Item;
|
||||||
|
Itm->Text = S;
|
||||||
|
Itm->Error = false;
|
||||||
|
Insert(Itm);
|
||||||
|
|
||||||
|
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];
|
||||||
|
vsnprintf(S,sizeof(S),Description,args);
|
||||||
|
|
||||||
|
// Put it on the list
|
||||||
|
Item *Itm = new Item;
|
||||||
|
Itm->Text = S;
|
||||||
|
Itm->Error = true;
|
||||||
|
Insert(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];
|
||||||
|
vsnprintf(S,sizeof(S),Description,args);
|
||||||
|
|
||||||
|
// Put it on the list
|
||||||
|
Item *Itm = new Item;
|
||||||
|
Itm->Text = S;
|
||||||
|
Itm->Error = false;
|
||||||
|
Insert(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)
|
||||||
|
{
|
||||||
|
if (List == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool Ret = List->Error;
|
||||||
|
Text = List->Text;
|
||||||
|
Item *Old = List;
|
||||||
|
List = List->Next;
|
||||||
|
delete Old;
|
||||||
|
|
||||||
|
// This really should check the list to see if only warnings are left..
|
||||||
|
if (List == 0)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// GlobalError::Discard - Discard /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void GlobalError::Discard()
|
||||||
|
{
|
||||||
|
while (List != 0)
|
||||||
|
{
|
||||||
|
Item *Old = List;
|
||||||
|
List = List->Next;
|
||||||
|
delete Old;
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingFlag = false;
|
||||||
|
};
|
||||||
|
/*}}}*/
|
||||||
|
// GlobalError::Insert - Insert a new item at the end /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void GlobalError::Insert(Item *Itm)
|
||||||
|
{
|
||||||
|
if (0) {//akk don't leave this here or it will have evil side effects
|
||||||
|
// on acquire methods
|
||||||
|
cerr << Itm->Text.c_str() << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Item **End = &List;
|
||||||
|
for (Item *I = List; I != 0; I = I->Next)
|
||||||
|
End = &I->Next;
|
||||||
|
Itm->Next = *End;
|
||||||
|
*End = Itm;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
89
apt/apt-pkg/contrib/error.h
Normal file
89
apt/apt-pkg/contrib/error.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: error.h,v 1.1.1.1 2000/08/10 12:42:39 kojima 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.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_ERROR_H
|
||||||
|
#define PKGLIB_ERROR_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/error.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class GlobalError
|
||||||
|
{
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
string Text;
|
||||||
|
bool Error;
|
||||||
|
Item *Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
Item *List;
|
||||||
|
bool PendingFlag;
|
||||||
|
void Insert(Item *I);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Call to generate an error from a library call.
|
||||||
|
bool Errno(const char *Function,const char *Description,...);
|
||||||
|
bool WarningE(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 == 0;};
|
||||||
|
bool PopMessage(string &Text);
|
||||||
|
void Discard();
|
||||||
|
|
||||||
|
// Usefull routine to dump to cerr
|
||||||
|
void DumpErrors();
|
||||||
|
|
||||||
|
GlobalError();
|
||||||
|
};
|
||||||
|
|
||||||
|
// The 'extra-ansi' syntax is used to help with collisions.
|
||||||
|
GlobalError *_GetErrorObj();
|
||||||
|
#define _error _GetErrorObj()
|
||||||
|
|
||||||
|
#endif
|
569
apt/apt-pkg/contrib/fileutl.cc
Normal file
569
apt/apt-pkg/contrib/fileutl.cc
Normal file
@ -0,0 +1,569 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: fileutl.cc,v 1.3 2000/09/26 14:22:14 kojima 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 /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/fileutl.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// CopyFile - Buffered copy of a file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The caller is expected to set things so that failure causes erasure */
|
||||||
|
bool CopyFile(FileFd &From,FileFd &To)
|
||||||
|
{
|
||||||
|
if (From.IsOpen() == false || To.IsOpen() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Buffered copy between fds
|
||||||
|
unsigned char *Buf = new unsigned char[64000];
|
||||||
|
unsigned long Size = From.Size();
|
||||||
|
while (Size != 0)
|
||||||
|
{
|
||||||
|
unsigned long ToRead = Size;
|
||||||
|
if (Size > 64000)
|
||||||
|
ToRead = 64000;
|
||||||
|
|
||||||
|
if (From.Read(Buf,ToRead) == false ||
|
||||||
|
To.Write(Buf,ToRead) == false)
|
||||||
|
{
|
||||||
|
delete [] Buf;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size -= ToRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// Read only .. cant have locking problems there.
|
||||||
|
if (errno == EROFS)
|
||||||
|
{
|
||||||
|
_error->Warning("Not using locking for read only lock file %s",File.c_str());
|
||||||
|
return dup(0); // Need something for the caller to close
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Errors == true)
|
||||||
|
_error->Errno("open","Could not open lock file %s",File.c_str());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
SetCloseExec(FD,true);
|
||||||
|
|
||||||
|
// Aquire a write lock
|
||||||
|
struct flock fl;
|
||||||
|
fl.l_type = F_WRLCK;
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = 0;
|
||||||
|
fl.l_len = 0;
|
||||||
|
if (fcntl(FD,F_SETLK,&fl) == -1)
|
||||||
|
{
|
||||||
|
if (errno == ENOLCK)
|
||||||
|
{
|
||||||
|
_error->Warning("Not using locking for nfs mounted lock file %s",File.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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)-2) == 0)
|
||||||
|
return "/";
|
||||||
|
unsigned int Len = strlen(S);
|
||||||
|
S[Len] = '/';
|
||||||
|
S[Len+1] = 0;
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// flNotDir - Strip the directory from the filename /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string flNotDir(string File)
|
||||||
|
{
|
||||||
|
string::size_type Res = File.rfind('/');
|
||||||
|
if (Res == string::npos)
|
||||||
|
return File;
|
||||||
|
Res++;
|
||||||
|
return string(File,Res,Res - File.length());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// flNotFile - Strip the file from the directory name /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string flNotFile(string File)
|
||||||
|
{
|
||||||
|
string::size_type Res = File.rfind('/');
|
||||||
|
if (Res == string::npos)
|
||||||
|
return File;
|
||||||
|
Res++;
|
||||||
|
return string(File,0,Res);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// flExtension - Return the extension for the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string flExtension(string File)
|
||||||
|
{
|
||||||
|
string::size_type Res = File.rfind('.');
|
||||||
|
if (Res == string::npos)
|
||||||
|
return File;
|
||||||
|
Res++;
|
||||||
|
return string(File,Res,Res - File.length());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// flNoLink - If file is a symlink then deref it /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* If the name is not a link then the returned path is the input. */
|
||||||
|
string flNoLink(string File)
|
||||||
|
{
|
||||||
|
struct stat St;
|
||||||
|
if (lstat(File.c_str(),&St) != 0 || S_ISLNK(St.st_mode) == 0)
|
||||||
|
return File;
|
||||||
|
if (stat(File.c_str(),&St) != 0)
|
||||||
|
return File;
|
||||||
|
|
||||||
|
/* Loop resolving the link. There is no need to limit the number of
|
||||||
|
loops because the stat call above ensures that the symlink is not
|
||||||
|
circular */
|
||||||
|
char Buffer[1024];
|
||||||
|
string NFile = File;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// Read the link
|
||||||
|
int Res;
|
||||||
|
if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 ||
|
||||||
|
(unsigned)Res >= sizeof(Buffer))
|
||||||
|
return File;
|
||||||
|
|
||||||
|
// Append or replace the previous path
|
||||||
|
Buffer[Res] = 0;
|
||||||
|
if (Buffer[0] == '/')
|
||||||
|
NFile = Buffer;
|
||||||
|
else
|
||||||
|
NFile = flNotFile(NFile) + Buffer;
|
||||||
|
|
||||||
|
// See if we are done
|
||||||
|
if (lstat(NFile.c_str(),&St) != 0)
|
||||||
|
return File;
|
||||||
|
if (S_ISLNK(St.st_mode) == 0)
|
||||||
|
return NFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// flCombine - Combine a file and a directory /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* If the file is an absolute path then it is just returned, otherwise
|
||||||
|
the directory is pre-pended to it. */
|
||||||
|
string flCombine(string Dir,string File)
|
||||||
|
{
|
||||||
|
if (File.empty() == true)
|
||||||
|
return string();
|
||||||
|
|
||||||
|
if (File[0] == '/' || Dir.empty() == true)
|
||||||
|
return File;
|
||||||
|
if (File.length() >= 2 && File[0] == '.' && File[1] == '/')
|
||||||
|
return File;
|
||||||
|
if (Dir[Dir.length()-1] == '/')
|
||||||
|
return Dir + File;
|
||||||
|
return Dir + '/' + File;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// SetCloseExec - Set the close on exec flag /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void SetCloseExec(int Fd,bool Close)
|
||||||
|
{
|
||||||
|
if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
|
||||||
|
{
|
||||||
|
cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// SetNonBlock - Set the nonblocking flag /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void SetNonBlock(int Fd,bool Block)
|
||||||
|
{
|
||||||
|
int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
|
||||||
|
if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
|
||||||
|
{
|
||||||
|
cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// WaitFd - Wait for a FD to become readable /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This waits for a FD to become readable using select. It is useful for
|
||||||
|
applications making use of non-blocking sockets. The timeout is
|
||||||
|
in seconds. */
|
||||||
|
bool WaitFd(int Fd,bool write,unsigned long timeout)
|
||||||
|
{
|
||||||
|
fd_set Set;
|
||||||
|
struct timeval tv;
|
||||||
|
FD_ZERO(&Set);
|
||||||
|
FD_SET(Fd,&Set);
|
||||||
|
tv.tv_sec = timeout;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
if (write == true)
|
||||||
|
{
|
||||||
|
int Res;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Res = select(Fd+1,0,&Set,0,(timeout != 0?&tv:0));
|
||||||
|
}
|
||||||
|
while (Res < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (Res <= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int Res;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Res = select(Fd+1,&Set,0,0,(timeout != 0?&tv:0));
|
||||||
|
}
|
||||||
|
while (Res < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (Res <= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is used if you want to cleanse the environment for the forked
|
||||||
|
child, it fixes up the important signals and nukes all of the fds,
|
||||||
|
otherwise acts like normal fork. */
|
||||||
|
int ExecFork()
|
||||||
|
{
|
||||||
|
// Fork off the process
|
||||||
|
pid_t Process = fork();
|
||||||
|
if (Process < 0)
|
||||||
|
{
|
||||||
|
cerr << "FATAL -> Failed to fork." << endl;
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn the subprocess
|
||||||
|
if (Process == 0)
|
||||||
|
{
|
||||||
|
// Setup the signals
|
||||||
|
signal(SIGPIPE,SIG_DFL);
|
||||||
|
signal(SIGQUIT,SIG_DFL);
|
||||||
|
signal(SIGINT,SIG_DFL);
|
||||||
|
signal(SIGWINCH,SIG_DFL);
|
||||||
|
signal(SIGCONT,SIG_DFL);
|
||||||
|
signal(SIGTSTP,SIG_DFL);
|
||||||
|
|
||||||
|
// Close all of our FDs - just in case
|
||||||
|
for (int K = 3; K != 40; K++)
|
||||||
|
fcntl(K,F_SETFD,FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Process;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ExecWait - Fancy waitpid /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Waits for the given sub process. If Reap is set the no errors are
|
||||||
|
generated. Otherwise a failed subprocess will generate a proper descriptive
|
||||||
|
message */
|
||||||
|
bool ExecWait(int Pid,const char *Name,bool Reap)
|
||||||
|
{
|
||||||
|
if (Pid <= 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Wait and collect the error code
|
||||||
|
int Status;
|
||||||
|
while (waitpid(Pid,&Status,0) != Pid)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Reap == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _error->Error("Waited, for %s but it wasn't there",Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check for an error code.
|
||||||
|
if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
|
||||||
|
{
|
||||||
|
if (Reap == true)
|
||||||
|
return false;
|
||||||
|
if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
|
||||||
|
return _error->Error("Sub-process %s recieved a segmentation fault.",Name);
|
||||||
|
|
||||||
|
if (WIFEXITED(Status) != 0)
|
||||||
|
return _error->Error("Sub-process %s returned an error code (%u)",Name,WEXITSTATUS(Status));
|
||||||
|
|
||||||
|
return _error->Error("Sub-process %s exited unexpectedly",Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// FileFd::Open - Open a file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The most commonly used open mode combinations are given with Mode */
|
||||||
|
bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
Flags = AutoClose;
|
||||||
|
switch (Mode)
|
||||||
|
{
|
||||||
|
case ReadOnly:
|
||||||
|
iFd = open(FileName.c_str(),O_RDONLY);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WriteEmpty:
|
||||||
|
{
|
||||||
|
struct stat Buf;
|
||||||
|
if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
|
||||||
|
unlink(FileName.c_str());
|
||||||
|
iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case WriteExists:
|
||||||
|
iFd = open(FileName.c_str(),O_RDWR);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WriteAny:
|
||||||
|
iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iFd < 0)
|
||||||
|
return _error->Errno("open","Could not open file %s",FileName.c_str());
|
||||||
|
|
||||||
|
this->FileName = FileName;
|
||||||
|
SetCloseExec(iFd,true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::~File - Closes the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* If the proper modes are selected then we close the Fd and possibly
|
||||||
|
unlink the file on error. */
|
||||||
|
FileFd::~FileFd()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Read - Read a bit of the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We are carefull to handle interruption by a signal while reading
|
||||||
|
gracefully. */
|
||||||
|
bool FileFd::Read(void *To,unsigned long Size,bool AllowEof)
|
||||||
|
{
|
||||||
|
int Res;
|
||||||
|
errno = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Res = read(iFd,To,Size);
|
||||||
|
if (Res < 0 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (Res < 0)
|
||||||
|
{
|
||||||
|
Flags |= Fail;
|
||||||
|
return _error->Errno("read","Read error");
|
||||||
|
}
|
||||||
|
|
||||||
|
To = (char *)To + Res;
|
||||||
|
Size -= Res;
|
||||||
|
}
|
||||||
|
while (Res > 0 && Size > 0);
|
||||||
|
|
||||||
|
if (Size == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Eof handling
|
||||||
|
if (AllowEof == true)
|
||||||
|
{
|
||||||
|
Flags |= HitEof;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flags |= Fail;
|
||||||
|
return _error->Error("read, still have %u to read but none left",Size);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Write - Write to the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool FileFd::Write(const void *From,unsigned long Size)
|
||||||
|
{
|
||||||
|
int Res;
|
||||||
|
errno = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Res = write(iFd,From,Size);
|
||||||
|
if (Res < 0 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (Res < 0)
|
||||||
|
{
|
||||||
|
Flags |= Fail;
|
||||||
|
return _error->Errno("write","Write error");
|
||||||
|
}
|
||||||
|
|
||||||
|
From = (char *)From + Res;
|
||||||
|
Size -= Res;
|
||||||
|
}
|
||||||
|
while (Res > 0 && Size > 0);
|
||||||
|
|
||||||
|
if (Size == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Flags |= Fail;
|
||||||
|
return _error->Error("write, still have %u to write but couldn't",Size);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Seek - Seek in the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool FileFd::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;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Skip - Seek in the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool FileFd::Skip(unsigned long Over)
|
||||||
|
{
|
||||||
|
if (lseek(iFd,Over,SEEK_CUR) < 0)
|
||||||
|
{
|
||||||
|
Flags |= Fail;
|
||||||
|
return _error->Error("Unable to seek ahead %u",Over);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Truncate - Truncate the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool FileFd::Truncate(unsigned long To)
|
||||||
|
{
|
||||||
|
if (ftruncate(iFd,To) != 0)
|
||||||
|
{
|
||||||
|
Flags |= Fail;
|
||||||
|
return _error->Error("Unable to truncate to %u",To);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Tell - Current seek position /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
unsigned long FileFd::Tell()
|
||||||
|
{
|
||||||
|
off_t Res = lseek(iFd,0,SEEK_CUR);
|
||||||
|
if (Res == (off_t)-1)
|
||||||
|
_error->Errno("lseek","Failed to determine the current file position");
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Size - Return the size of the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
unsigned long FileFd::Size()
|
||||||
|
{
|
||||||
|
struct stat Buf;
|
||||||
|
if (fstat(iFd,&Buf) != 0)
|
||||||
|
return _error->Errno("fstat","Unable to determine the file size");
|
||||||
|
return Buf.st_size;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// FileFd::Close - Close the file if the close flag is set /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool FileFd::Close()
|
||||||
|
{
|
||||||
|
bool Res = true;
|
||||||
|
if ((Flags & AutoClose) == AutoClose)
|
||||||
|
if (iFd >= 0 && close(iFd) != 0)
|
||||||
|
Res &= _error->Errno("close","Problem closing the file");
|
||||||
|
iFd = -1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
90
apt/apt-pkg/contrib/fileutl.h
Normal file
90
apt/apt-pkg/contrib/fileutl.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: fileutl.h,v 1.2 2000/09/26 14:22:14 kojima 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.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_FILEUTL_H
|
||||||
|
#define PKGLIB_FILEUTL_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/fileutl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class FileFd
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int iFd;
|
||||||
|
|
||||||
|
enum LocalFlags {AutoClose = (1<<0),Fail = (1<<1),DelOnFail = (1<<2),
|
||||||
|
HitEof = (1<<3)};
|
||||||
|
unsigned long Flags;
|
||||||
|
string FileName;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny};
|
||||||
|
|
||||||
|
bool Read(void *To,unsigned long Size,bool AllowEof = false);
|
||||||
|
bool Write(const void *From,unsigned long Size);
|
||||||
|
bool Seek(unsigned long To);
|
||||||
|
bool Skip(unsigned long To);
|
||||||
|
bool Truncate(unsigned long To);
|
||||||
|
unsigned long Tell();
|
||||||
|
unsigned long Size();
|
||||||
|
bool Open(string FileName,OpenMode Mode,unsigned long Perms = 0666);
|
||||||
|
bool Close();
|
||||||
|
|
||||||
|
// Simple manipulators
|
||||||
|
inline int Fd() {return iFd;};
|
||||||
|
inline void Fd(int fd) {iFd = fd;};
|
||||||
|
inline bool IsOpen() {return iFd >= 0;};
|
||||||
|
inline bool Failed() {return (Flags & Fail) == Fail;};
|
||||||
|
inline void EraseOnFailure() {Flags |= DelOnFail;};
|
||||||
|
inline void OpFail() {Flags |= Fail;};
|
||||||
|
inline bool Eof() {return (Flags & HitEof) == HitEof;};
|
||||||
|
inline string &Name() {return FileName;};
|
||||||
|
|
||||||
|
FileFd(string FileName,OpenMode Mode,unsigned long Perms = 0666) : iFd(-1),
|
||||||
|
Flags(0)
|
||||||
|
{
|
||||||
|
Open(FileName,Mode,Perms);
|
||||||
|
};
|
||||||
|
FileFd(int Fd = -1) : iFd(Fd), Flags(AutoClose) {};
|
||||||
|
FileFd(int Fd,bool) : iFd(Fd), Flags(0) {};
|
||||||
|
virtual ~FileFd();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CopyFile(FileFd &From,FileFd &To);
|
||||||
|
int GetLock(string File,bool Errors = true);
|
||||||
|
bool FileExists(string File);
|
||||||
|
string SafeGetCWD();
|
||||||
|
void SetCloseExec(int Fd,bool Close);
|
||||||
|
void SetNonBlock(int Fd,bool Block);
|
||||||
|
bool WaitFd(int Fd,bool write = false,unsigned long timeout = 0);
|
||||||
|
int ExecFork();
|
||||||
|
bool ExecWait(int Pid,const char *Name,bool Reap = false);
|
||||||
|
|
||||||
|
// File string manipulators
|
||||||
|
string flNotDir(string File);
|
||||||
|
string flNotFile(string File);
|
||||||
|
string flNoLink(string File);
|
||||||
|
string flExtension(string File);
|
||||||
|
string flCombine(string Dir,string File);
|
||||||
|
|
||||||
|
#endif
|
54
apt/apt-pkg/contrib/i18n.h
Normal file
54
apt/apt-pkg/contrib/i18n.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/* i18n.h -- Internationalization stuff (ripped from bash)
|
||||||
|
|
||||||
|
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GNU Bash, the Bourne Again SHell.
|
||||||
|
|
||||||
|
Modified 9/2000 by Alfredo K. Kojima for apt
|
||||||
|
|
||||||
|
Bash is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free
|
||||||
|
Software Foundation; either version 2, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with Bash; see the file COPYING. If not, write to the Free Software
|
||||||
|
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||||
|
|
||||||
|
#if !defined (_I18N_H_)
|
||||||
|
#define _I18N_H_
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBINTL_H)
|
||||||
|
# include <libintl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (HAVE_LOCALE_H)
|
||||||
|
# include <locale.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (HAVE_SETLOCALE) && !defined (LC_ALL)
|
||||||
|
# undef HAVE_SETLOCALE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_NLS
|
||||||
|
# define _(a) (const char*)gettext(a)
|
||||||
|
#else
|
||||||
|
# undef bindtextdomain
|
||||||
|
# define bindtextdomain(Domain, Directory) /* empty */
|
||||||
|
# undef textdomain
|
||||||
|
# define textdomain(Domain) /* empty */
|
||||||
|
# undef setlocale
|
||||||
|
# define setlocale(cat, log)
|
||||||
|
# define _(a) a
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !_I18N_H_ */
|
358
apt/apt-pkg/contrib/md5.cc
Normal file
358
apt/apt-pkg/contrib/md5.cc
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: md5.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
MD5Sum - MD5 Message Digest Algorithm.
|
||||||
|
|
||||||
|
This code implements the MD5 message-digest algorithm. The algorithm is
|
||||||
|
due to Ron Rivest. This code was written by Colin Plumb in 1993, no
|
||||||
|
copyright is claimed. This code is in the public domain; do with it what
|
||||||
|
you wish.
|
||||||
|
|
||||||
|
Equivalent code is available from RSA Data Security, Inc. This code has
|
||||||
|
been tested against that, and is equivalent, except that you don't need to
|
||||||
|
include two pages of legalese with every copy.
|
||||||
|
|
||||||
|
To compute the message digest of a chunk of bytes, instantiate the class,
|
||||||
|
and repeatedly call one of the Add() members. When finished the Result
|
||||||
|
method will return the Hash and finalize the value.
|
||||||
|
|
||||||
|
Changed so as no longer to depend on Colin Plumb's `usual.h' header
|
||||||
|
definitions; now uses stuff from dpkg's config.h.
|
||||||
|
- Ian Jackson <ijackson@nyx.cs.du.edu>.
|
||||||
|
|
||||||
|
Changed into a C++ interface and made work with APT's config.h.
|
||||||
|
- Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
|
||||||
|
|
||||||
|
Still in the public domain.
|
||||||
|
|
||||||
|
The classes use arrays of char that are a specific size. We cast those
|
||||||
|
arrays to uint8_t's and go from there. This allows us to advoid using
|
||||||
|
the uncommon inttypes.h in a public header or internally newing memory.
|
||||||
|
In theory if C9x becomes nicely accepted
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/md5.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/md5.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h> // For htonl
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <system.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// byteSwap - Swap bytes in a buffer /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Swap n 32 bit longs in given buffer */
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
static void byteSwap(uint32_t *buf, unsigned words)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)buf;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
*buf++ = (uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 |
|
||||||
|
((unsigned)p[1] << 8 | p[0]);
|
||||||
|
p += 4;
|
||||||
|
} while (--words);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define byteSwap(buf,words)
|
||||||
|
#endif
|
||||||
|
/*}}}*/
|
||||||
|
// MD5Transform - Alters an existing MD5 hash /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||||
|
reflect the addition of 16 longwords of new data. Add blocks
|
||||||
|
the data and converts bytes into longwords for this routine. */
|
||||||
|
|
||||||
|
// The four core functions - F1 is optimized somewhat
|
||||||
|
// #define F1(x, y, z) (x & y | ~x & z)
|
||||||
|
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||||
|
#define F2(x, y, z) F1(z, x, y)
|
||||||
|
#define F3(x, y, z) (x ^ y ^ z)
|
||||||
|
#define F4(x, y, z) (y ^ (x | ~z))
|
||||||
|
|
||||||
|
// This is the central step in the MD5 algorithm.
|
||||||
|
#define MD5STEP(f,w,x,y,z,in,s) \
|
||||||
|
(w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
|
||||||
|
|
||||||
|
static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
|
||||||
|
{
|
||||||
|
register uint32_t a, b, c, d;
|
||||||
|
|
||||||
|
a = buf[0];
|
||||||
|
b = buf[1];
|
||||||
|
c = buf[2];
|
||||||
|
d = buf[3];
|
||||||
|
|
||||||
|
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||||
|
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||||
|
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||||
|
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||||
|
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||||
|
|
||||||
|
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||||
|
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||||
|
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||||
|
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||||
|
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||||
|
|
||||||
|
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||||
|
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||||
|
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||||
|
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||||
|
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||||
|
|
||||||
|
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||||
|
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||||
|
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||||
|
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||||
|
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||||
|
|
||||||
|
buf[0] += a;
|
||||||
|
buf[1] += b;
|
||||||
|
buf[2] += c;
|
||||||
|
buf[3] += d;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5SumValue::MD5SumValue - Constructs the summation from a string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The string form of a MD5 is a 32 character hex number */
|
||||||
|
MD5SumValue::MD5SumValue(string Str)
|
||||||
|
{
|
||||||
|
memset(Sum,0,sizeof(Sum));
|
||||||
|
Set(Str);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5SumValue::MD5SumValue - Default constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Sets the value to 0 */
|
||||||
|
MD5SumValue::MD5SumValue()
|
||||||
|
{
|
||||||
|
memset(Sum,0,sizeof(Sum));
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5SumValue::Set - Set the sum from a string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Converts the hex string into a set of chars */
|
||||||
|
bool MD5SumValue::Set(string Str)
|
||||||
|
{
|
||||||
|
return Hex2Num(Str.begin(),Str.end(),Sum,sizeof(Sum));
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5SumValue::Value - Convert the number into a string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Converts the set of chars into a hex string in lower case */
|
||||||
|
string MD5SumValue::Value() const
|
||||||
|
{
|
||||||
|
char Conv[16] = {'0','1','2','3','4','5','6','7','8','9','a','b',
|
||||||
|
'c','d','e','f'};
|
||||||
|
char Result[33];
|
||||||
|
Result[32] = 0;
|
||||||
|
|
||||||
|
// Convert each char into two letters
|
||||||
|
int J = 0;
|
||||||
|
int I = 0;
|
||||||
|
for (; I != 32; J++, I += 2)
|
||||||
|
{
|
||||||
|
Result[I] = Conv[Sum[J] >> 4];
|
||||||
|
Result[I + 1] = Conv[Sum[J] & 0xF];
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(Result);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5SumValue::operator == - Comparitor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Call memcmp on the buffer */
|
||||||
|
bool MD5SumValue::operator ==(const MD5SumValue &rhs) const
|
||||||
|
{
|
||||||
|
return memcmp(Sum,rhs.Sum,sizeof(Sum)) == 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5Summation::MD5Summation - Initialize the summer /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This assigns the deep magic initial values */
|
||||||
|
MD5Summation::MD5Summation()
|
||||||
|
{
|
||||||
|
uint32_t *buf = (uint32_t *)Buf;
|
||||||
|
uint32_t *bytes = (uint32_t *)Bytes;
|
||||||
|
|
||||||
|
buf[0] = 0x67452301;
|
||||||
|
buf[1] = 0xefcdab89;
|
||||||
|
buf[2] = 0x98badcfe;
|
||||||
|
buf[3] = 0x10325476;
|
||||||
|
|
||||||
|
bytes[0] = 0;
|
||||||
|
bytes[1] = 0;
|
||||||
|
Done = false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5Summation::Add - 'Add' a data set to the hash /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool MD5Summation::Add(const unsigned char *data,unsigned long len)
|
||||||
|
{
|
||||||
|
if (Done == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t *buf = (uint32_t *)Buf;
|
||||||
|
uint32_t *bytes = (uint32_t *)Bytes;
|
||||||
|
uint32_t *in = (uint32_t *)In;
|
||||||
|
|
||||||
|
// Update byte count and carry (this could be done with a long long?)
|
||||||
|
uint32_t t = bytes[0];
|
||||||
|
if ((bytes[0] = t + len) < t)
|
||||||
|
bytes[1]++;
|
||||||
|
|
||||||
|
// Space available (at least 1)
|
||||||
|
t = 64 - (t & 0x3f);
|
||||||
|
if (t > len)
|
||||||
|
{
|
||||||
|
memcpy((unsigned char *)in + 64 - t,data,len);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First chunk is an odd size
|
||||||
|
memcpy((unsigned char *)in + 64 - t,data,t);
|
||||||
|
byteSwap(in, 16);
|
||||||
|
MD5Transform(buf,in);
|
||||||
|
data += t;
|
||||||
|
len -= t;
|
||||||
|
|
||||||
|
// Process data in 64-byte chunks
|
||||||
|
while (len >= 64)
|
||||||
|
{
|
||||||
|
memcpy(in,data,64);
|
||||||
|
byteSwap(in,16);
|
||||||
|
MD5Transform(buf,in);
|
||||||
|
data += 64;
|
||||||
|
len -= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle any remaining bytes of data.
|
||||||
|
memcpy(in,data,len);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5Summation::AddFD - Add the contents of a FD to the hash /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool MD5Summation::AddFD(int Fd,unsigned long Size)
|
||||||
|
{
|
||||||
|
unsigned char Buf[64*64];
|
||||||
|
int Res = 0;
|
||||||
|
while (Size != 0)
|
||||||
|
{
|
||||||
|
Res = read(Fd,Buf,MIN(Size,sizeof(Buf)));
|
||||||
|
if (Res < 0 || (unsigned)Res != MIN(Size,sizeof(Buf)))
|
||||||
|
return false;
|
||||||
|
Size -= Res;
|
||||||
|
Add(Buf,Res);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MD5Summation::Result - Returns the value of the sum /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Because this must add in the last bytes of the series it prevents anyone
|
||||||
|
from calling add after. */
|
||||||
|
MD5SumValue MD5Summation::Result()
|
||||||
|
{
|
||||||
|
uint32_t *buf = (uint32_t *)Buf;
|
||||||
|
uint32_t *bytes = (uint32_t *)Bytes;
|
||||||
|
uint32_t *in = (uint32_t *)In;
|
||||||
|
|
||||||
|
if (Done == false)
|
||||||
|
{
|
||||||
|
// Number of bytes in In
|
||||||
|
int count = bytes[0] & 0x3f;
|
||||||
|
unsigned char *p = (unsigned char *)in + count;
|
||||||
|
|
||||||
|
// Set the first char of padding to 0x80. There is always room.
|
||||||
|
*p++ = 0x80;
|
||||||
|
|
||||||
|
// Bytes of padding needed to make 56 bytes (-8..55)
|
||||||
|
count = 56 - 1 - count;
|
||||||
|
|
||||||
|
// Padding forces an extra block
|
||||||
|
if (count < 0)
|
||||||
|
{
|
||||||
|
memset(p,0,count + 8);
|
||||||
|
byteSwap(in, 16);
|
||||||
|
MD5Transform(buf,in);
|
||||||
|
p = (unsigned char *)in;
|
||||||
|
count = 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(p, 0, count);
|
||||||
|
byteSwap(in, 14);
|
||||||
|
|
||||||
|
// Append length in bits and transform
|
||||||
|
in[14] = bytes[0] << 3;
|
||||||
|
in[15] = bytes[1] << 3 | bytes[0] >> 29;
|
||||||
|
MD5Transform(buf,in);
|
||||||
|
byteSwap(buf,4);
|
||||||
|
Done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MD5SumValue V;
|
||||||
|
memcpy(V.Sum,buf,16);
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
74
apt/apt-pkg/contrib/md5.h
Normal file
74
apt/apt-pkg/contrib/md5.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: md5.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
MD5SumValue - Storage for a MD5Sum
|
||||||
|
MD5Summation - MD5 Message Digest Algorithm.
|
||||||
|
|
||||||
|
This is a C++ interface to a set of MD5Sum functions. The class can
|
||||||
|
store a MD5Sum in 16 bytes of memory.
|
||||||
|
|
||||||
|
A MD5Sum is used to generate a (hopefully) unique 16 byte number for a
|
||||||
|
block of data. This can be used to gaurd against corruption of a file.
|
||||||
|
MD5 should not be used for tamper protection, use SHA or something more
|
||||||
|
secure.
|
||||||
|
|
||||||
|
There are two classes because computing a MD5 is not a continual
|
||||||
|
operation unless 64 byte blocks are used. Also the summation requires an
|
||||||
|
extra 18*4 bytes to operate.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef APTPKG_MD5_H
|
||||||
|
#define APTPKG_MD5_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/md5.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class MD5Summation;
|
||||||
|
|
||||||
|
class MD5SumValue
|
||||||
|
{
|
||||||
|
friend MD5Summation;
|
||||||
|
unsigned char Sum[4*4];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
bool operator ==(const MD5SumValue &rhs) const;
|
||||||
|
string Value() const;
|
||||||
|
inline void Value(unsigned char S[16])
|
||||||
|
{for (int I = 0; I != sizeof(Sum); I++) S[I] = Sum[I];};
|
||||||
|
inline operator string() const {return Value();};
|
||||||
|
bool Set(string Str);
|
||||||
|
inline void Set(unsigned char S[16])
|
||||||
|
{for (int I = 0; I != sizeof(Sum); I++) Sum[I] = S[I];};
|
||||||
|
|
||||||
|
MD5SumValue(string Str);
|
||||||
|
MD5SumValue();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MD5Summation
|
||||||
|
{
|
||||||
|
unsigned char Buf[4*4];
|
||||||
|
unsigned char Bytes[2*4];
|
||||||
|
unsigned char In[16*4];
|
||||||
|
bool Done;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool Add(const unsigned char *Data,unsigned long Size);
|
||||||
|
inline bool Add(const char *Data) {return Add((unsigned char *)Data,strlen(Data));};
|
||||||
|
bool AddFD(int Fd,unsigned long Size);
|
||||||
|
inline bool Add(const unsigned char *Beg,const unsigned char *End)
|
||||||
|
{return Add(Beg,End-Beg);};
|
||||||
|
MD5SumValue Result();
|
||||||
|
|
||||||
|
MD5Summation();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
279
apt/apt-pkg/contrib/mmap.cc
Normal file
279
apt/apt-pkg/contrib/mmap.cc
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: mmap.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima 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 /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/mmap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _BSD_SOURCE
|
||||||
|
#include <apt-pkg/mmap.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// MMap::MMap - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
|
||||||
|
Base(0)
|
||||||
|
{
|
||||||
|
if ((Flags & NoImmMap) != NoImmMap)
|
||||||
|
Map(F);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MMap::MMap - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
|
||||||
|
Base(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MMap::~MMap - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
MMap::~MMap()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MMap::Map - Perform the mapping /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool MMap::Map(FileFd &Fd)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (iSize == 0)
|
||||||
|
return _error->Error("Can't mmap an empty file");
|
||||||
|
|
||||||
|
// 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 DoSync)
|
||||||
|
{
|
||||||
|
if ((Flags & UnMapped) == UnMapped || Base == 0 || iSize == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (DoSync == true)
|
||||||
|
Sync();
|
||||||
|
|
||||||
|
if (munmap((char *)Base,iSize) != 0)
|
||||||
|
_error->Warning("Unable to munmap");
|
||||||
|
|
||||||
|
iSize = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MMap::Sync - Syncronize the map with the disk /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is done in syncronous mode - the docs indicate that this will
|
||||||
|
not return till all IO is complete */
|
||||||
|
bool MMap::Sync()
|
||||||
|
{
|
||||||
|
if ((Flags & UnMapped) == UnMapped)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#ifdef _POSIX_SYNCHRONIZED_IO
|
||||||
|
if ((Flags & ReadOnly) != ReadOnly)
|
||||||
|
if (msync((char *)Base,iSize,MS_SYNC) != 0)
|
||||||
|
return _error->Errno("msync","Unable to write mmap");
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MMap::Sync - Syncronize a section of the file to disk /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool MMap::Sync(unsigned long Start,unsigned long Stop)
|
||||||
|
{
|
||||||
|
if ((Flags & UnMapped) == UnMapped)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#ifdef _POSIX_SYNCHRONIZED_IO
|
||||||
|
unsigned long PSize = sysconf(_SC_PAGESIZE);
|
||||||
|
if ((Flags & ReadOnly) != ReadOnly)
|
||||||
|
if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) != 0)
|
||||||
|
return _error->Errno("msync","Unable to write mmap");
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// DynamicMMap::DynamicMMap - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) :
|
||||||
|
MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(WorkSpace)
|
||||||
|
{
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned long EndOfFile = Fd->Size();
|
||||||
|
Fd->Seek(WorkSpace);
|
||||||
|
char C = 0;
|
||||||
|
Fd->Write(&C,sizeof(C));
|
||||||
|
Map(F);
|
||||||
|
iSize = EndOfFile;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DynamicMMap::DynamicMMap - Constructor for a non-file backed map /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is just a fancy malloc really.. */
|
||||||
|
DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long WorkSpace) :
|
||||||
|
MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace)
|
||||||
|
{
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Base = new unsigned char[WorkSpace];
|
||||||
|
iSize = 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DynamicMMap::~DynamicMMap - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We truncate the file to the size of the memory data set */
|
||||||
|
DynamicMMap::~DynamicMMap()
|
||||||
|
{
|
||||||
|
if (Fd == 0)
|
||||||
|
{
|
||||||
|
delete [] (unsigned char *)Base;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long EndOfFile = iSize;
|
||||||
|
Sync();
|
||||||
|
iSize = WorkSpace;
|
||||||
|
Close(false);
|
||||||
|
ftruncate(Fd->Fd(),EndOfFile);
|
||||||
|
Fd->Close();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This allocates a block of memory aligned to the given size */
|
||||||
|
unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
|
||||||
|
{
|
||||||
|
unsigned long Result = iSize;
|
||||||
|
if (Aln != 0)
|
||||||
|
Result += Aln - (iSize%Aln);
|
||||||
|
|
||||||
|
iSize = Result + Size;
|
||||||
|
|
||||||
|
// Just in case error check
|
||||||
|
if (Result + Size > 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,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 + Len > WorkSpace)
|
||||||
|
{
|
||||||
|
_error->Error("Dynamic MMap ran out of room");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Len == (unsigned long)-1)
|
||||||
|
Len = strlen(String);
|
||||||
|
iSize += Len + 1;
|
||||||
|
memcpy((char *)Base + Result,String,Len);
|
||||||
|
((char *)Base)[Result + Len] = 0;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
103
apt/apt-pkg/contrib/mmap.h
Normal file
103
apt/apt-pkg/contrib/mmap.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: mmap.h,v 1.1.1.1 2000/08/10 12:42:39 kojima 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.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_MMAP_H
|
||||||
|
#define PKGLIB_MMAP_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/mmap.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
|
||||||
|
/* This should be a 32 bit type, larger tyes use too much ram and smaller
|
||||||
|
types are too small. Where ever possible 'unsigned long' should be used
|
||||||
|
instead of this internal type */
|
||||||
|
typedef unsigned int map_ptrloc;
|
||||||
|
|
||||||
|
class MMap
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
unsigned long Flags;
|
||||||
|
unsigned long iSize;
|
||||||
|
void *Base;
|
||||||
|
|
||||||
|
bool Map(FileFd &Fd);
|
||||||
|
bool Close(bool DoSync = true);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum OpenFlags {NoImmMap = (1<<0),Public = (1<<1),ReadOnly = (1<<2),
|
||||||
|
UnMapped = (1<<3)};
|
||||||
|
|
||||||
|
// 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(FileFd &F,unsigned long Flags);
|
||||||
|
MMap(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:
|
||||||
|
|
||||||
|
FileFd *Fd;
|
||||||
|
unsigned long WorkSpace;
|
||||||
|
Pool *Pools;
|
||||||
|
unsigned int PoolCount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Allocation
|
||||||
|
unsigned long RawAllocate(unsigned long Size,unsigned long Aln = 0);
|
||||||
|
unsigned long Allocate(unsigned long ItemSize);
|
||||||
|
unsigned long WriteString(const char *String,unsigned long Len = (unsigned long)-1);
|
||||||
|
inline unsigned long WriteString(string S) {return WriteString(S.begin(),S.size());};
|
||||||
|
void UsePools(Pool &P,unsigned int Count) {Pools = &P; PoolCount = Count;};
|
||||||
|
|
||||||
|
DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace = 2*1024*1024);
|
||||||
|
DynamicMMap(unsigned long Flags,unsigned long WorkSpace = 2*1024*1024);
|
||||||
|
virtual ~DynamicMMap();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
200
apt/apt-pkg/contrib/progress.cc
Normal file
200
apt/apt-pkg/contrib/progress.cc
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: progress.cc,v 1.3 2001/11/13 17:32:08 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
OpProgress - Operation Progress
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/progress.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/progress.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
/*}}}*/
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
// OpProgress::OpProgress - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
OpProgress::OpProgress() : Current(0), Total(0), Size(0), SubTotal(1),
|
||||||
|
LastPercent(0), Percent(0)
|
||||||
|
{
|
||||||
|
memset(&LastTime,0,sizeof(LastTime));
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpProgress::Progress - Sub progress with no state change /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Current is the Base Overall progress in units of Total. Cur is the sub
|
||||||
|
progress in units of SubTotal. Size is a scaling factor that says what
|
||||||
|
percent of Total SubTotal is. */
|
||||||
|
void OpProgress::Progress(unsigned long Cur)
|
||||||
|
{
|
||||||
|
Percent = (Current + Cur/((float)SubTotal)*Size)*100.0/Total;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpProgress::OverallProgress - Set the overall progress /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void OpProgress::OverallProgress(unsigned long Current, unsigned long Total,
|
||||||
|
unsigned long Size,string Op)
|
||||||
|
{
|
||||||
|
this->Current = Current;
|
||||||
|
this->Total = Total;
|
||||||
|
this->Size = Size;
|
||||||
|
this->Op = Op;
|
||||||
|
SubOp = string();
|
||||||
|
Percent = Current*100.0/Total;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpProgress::SubProgress - Set the sub progress state /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void OpProgress::SubProgress(unsigned long SubTotal,string Op)
|
||||||
|
{
|
||||||
|
this->SubTotal = SubTotal;
|
||||||
|
SubOp = Op;
|
||||||
|
Percent = Current*100.0/Total;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpProgress::SubProgress - Set the sub progress state /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void OpProgress::SubProgress(unsigned long SubTotal)
|
||||||
|
{
|
||||||
|
this->SubTotal = SubTotal;
|
||||||
|
Percent = Current*100.0/Total;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpProgress::CheckChange - See if the display should be updated /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Progress calls are made so frequently that if every one resulted in
|
||||||
|
an update the display would be swamped and the system much slower.
|
||||||
|
This provides an upper bound on the update rate. */
|
||||||
|
bool OpProgress::CheckChange(float Interval)
|
||||||
|
{
|
||||||
|
// New major progress indication
|
||||||
|
if (Op != LastOp)
|
||||||
|
{
|
||||||
|
MajorChange = true;
|
||||||
|
LastOp = Op;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
MajorChange = false;
|
||||||
|
|
||||||
|
if (SubOp != LastSubOp)
|
||||||
|
{
|
||||||
|
LastSubOp = SubOp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)LastPercent == (int)Percent)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check time delta
|
||||||
|
struct timeval Now;
|
||||||
|
gettimeofday(&Now,0);
|
||||||
|
double Diff = Now.tv_sec - LastTime.tv_sec + (Now.tv_usec - LastTime.tv_usec)/1000000.0;
|
||||||
|
if (Diff < Interval)
|
||||||
|
return false;
|
||||||
|
LastTime = Now;
|
||||||
|
LastPercent = Percent;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpTextProgress::OpTextProgress - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
OpTextProgress::OpTextProgress(Configuration &Config) :
|
||||||
|
NoUpdate(false), NoDisplay(false), LastLen(0)
|
||||||
|
{
|
||||||
|
if (Config.FindI("quiet",0) >= 1)
|
||||||
|
NoUpdate = true;
|
||||||
|
if (Config.FindI("quiet",0) >= 2)
|
||||||
|
NoDisplay = true;
|
||||||
|
};
|
||||||
|
/*}}}*/
|
||||||
|
// OpTextProgress::Done - Clean up the display /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void OpTextProgress::Done()
|
||||||
|
{
|
||||||
|
if (NoUpdate == false && OldOp.empty() == false)
|
||||||
|
{
|
||||||
|
char S[300];
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
snprintf(S,sizeof(S),"\r%s... %s",OldOp.c_str(),_("Error!"));
|
||||||
|
else
|
||||||
|
snprintf(S,sizeof(S),"\r%s... %s",OldOp.c_str(),_("Done"));
|
||||||
|
Write(S);
|
||||||
|
cout << endl;
|
||||||
|
OldOp = string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NoUpdate == true && NoDisplay == false && OldOp.empty() == false)
|
||||||
|
{
|
||||||
|
OldOp = string();
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpTextProgress::Update - Simple text spinner /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void OpTextProgress::Update()
|
||||||
|
{
|
||||||
|
if (CheckChange(0.1) == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// No percent spinner
|
||||||
|
if (NoUpdate == true)
|
||||||
|
{
|
||||||
|
if (MajorChange == false)
|
||||||
|
return;
|
||||||
|
if (NoDisplay == false)
|
||||||
|
{
|
||||||
|
if (OldOp.empty() == false)
|
||||||
|
cout << endl;
|
||||||
|
OldOp = "a";
|
||||||
|
cout << Op << "..." << flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase the old text and 'log' the event
|
||||||
|
char S[300];
|
||||||
|
if (MajorChange == true && OldOp.empty() == false)
|
||||||
|
{
|
||||||
|
snprintf(S,sizeof(S),"\r%s",OldOp.c_str());
|
||||||
|
Write(S);
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the spinner
|
||||||
|
snprintf(S,sizeof(S),"\r%s... %u%%",Op.c_str(),(unsigned int)Percent);
|
||||||
|
Write(S);
|
||||||
|
|
||||||
|
OldOp = Op;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OpTextProgress::Write - Write the progress string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This space fills the end to overwrite the previous text */
|
||||||
|
void OpTextProgress::Write(const char *S)
|
||||||
|
{
|
||||||
|
cout << S;
|
||||||
|
for (unsigned int I = strlen(S); I < LastLen; I++)
|
||||||
|
cout << ' ';
|
||||||
|
cout << '\r' << flush;
|
||||||
|
LastLen = strlen(S);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
90
apt/apt-pkg/contrib/progress.h
Normal file
90
apt/apt-pkg/contrib/progress.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: progress.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
OpProgress - Operation Progress
|
||||||
|
|
||||||
|
This class allows lengthy operations to communicate their progress
|
||||||
|
to the GUI. The progress model is simple and is not designed to handle
|
||||||
|
the complex case of the multi-activity aquire class.
|
||||||
|
|
||||||
|
The model is based on the concept of an overall operation consisting
|
||||||
|
of a series of small sub operations. Each sub operation has it's own
|
||||||
|
completion status and the overall operation has it's completion status.
|
||||||
|
The units of the two are not mixed and are completely independent.
|
||||||
|
|
||||||
|
The UI is expected to subclass this to provide the visuals to the user.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_PROGRESS_H
|
||||||
|
#define PKGLIB_PROGRESS_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/progress.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
class Configuration;
|
||||||
|
class OpProgress
|
||||||
|
{
|
||||||
|
unsigned long Current;
|
||||||
|
unsigned long Total;
|
||||||
|
unsigned long Size;
|
||||||
|
unsigned long SubTotal;
|
||||||
|
float LastPercent;
|
||||||
|
|
||||||
|
// Change reduction code
|
||||||
|
struct timeval LastTime;
|
||||||
|
string LastOp;
|
||||||
|
string LastSubOp;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
string Op;
|
||||||
|
string SubOp;
|
||||||
|
float Percent;
|
||||||
|
|
||||||
|
bool MajorChange;
|
||||||
|
|
||||||
|
bool CheckChange(float Interval = 0.7);
|
||||||
|
virtual void Update() {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void Progress(unsigned long Current);
|
||||||
|
void SubProgress(unsigned long SubTotal);
|
||||||
|
void SubProgress(unsigned long SubTotal,string Op);
|
||||||
|
void OverallProgress(unsigned long Current,unsigned long Total,
|
||||||
|
unsigned long Size,string Op);
|
||||||
|
virtual void Done() {};
|
||||||
|
|
||||||
|
OpProgress();
|
||||||
|
virtual ~OpProgress() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpTextProgress : public OpProgress
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
string OldOp;
|
||||||
|
bool NoUpdate;
|
||||||
|
bool NoDisplay;
|
||||||
|
unsigned long LastLen;
|
||||||
|
virtual void Update();
|
||||||
|
void Write(const char *S);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void Done();
|
||||||
|
|
||||||
|
OpTextProgress(bool NoUpdate = false) : NoUpdate(NoUpdate),
|
||||||
|
NoDisplay(false), LastLen(0) {};
|
||||||
|
OpTextProgress(Configuration &Config);
|
||||||
|
virtual ~OpTextProgress() {Done();};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
66
apt/apt-pkg/contrib/sptr.h
Normal file
66
apt/apt-pkg/contrib/sptr.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: sptr.h,v 1.1 2001/03/27 21:18:18 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Trivial non-ref counted 'smart pointer'
|
||||||
|
|
||||||
|
This is really only good to eliminate
|
||||||
|
{
|
||||||
|
delete Foo;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Blocks from functions.
|
||||||
|
|
||||||
|
I think G++ has become good enough that doing this won't have much
|
||||||
|
code size implications.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef SMART_POINTER_H
|
||||||
|
#define SMART_POINTER_H
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class SPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
T *Ptr;
|
||||||
|
|
||||||
|
inline T *operator ->() {return Ptr;};
|
||||||
|
inline T &operator *() {return *Ptr;};
|
||||||
|
inline operator T *() {return Ptr;};
|
||||||
|
inline operator void *() {return Ptr;};
|
||||||
|
inline T *UnGuard() {T *Tmp = Ptr; Ptr = 0; return Tmp;};
|
||||||
|
inline void operator =(T *N) {Ptr = N;};
|
||||||
|
inline bool operator ==(T *lhs) const {return Ptr == lhs;};
|
||||||
|
inline bool operator !=(T *lhs) const {return Ptr != lhs;};
|
||||||
|
inline T*Get() {return Ptr;};
|
||||||
|
|
||||||
|
inline SPtr(T *Ptr) : Ptr(Ptr) {};
|
||||||
|
inline SPtr() : Ptr(0) {};
|
||||||
|
inline ~SPtr() {delete Ptr;};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class SPtrArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
T *Ptr;
|
||||||
|
|
||||||
|
//inline T &operator *() {return *Ptr;};
|
||||||
|
inline operator T *() {return Ptr;};
|
||||||
|
inline operator void *() {return Ptr;};
|
||||||
|
inline T *UnGuard() {T *Tmp = Ptr; Ptr = 0; return Tmp;};
|
||||||
|
//inline T &operator [](signed long I) {return Ptr[I];};
|
||||||
|
inline void operator =(T *N) {Ptr = N;};
|
||||||
|
inline bool operator ==(T *lhs) const {return Ptr == lhs;};
|
||||||
|
inline bool operator !=(T *lhs) const {return Ptr != lhs;};
|
||||||
|
inline T *Get() {return Ptr;};
|
||||||
|
|
||||||
|
inline SPtrArray(T *Ptr) : Ptr(Ptr) {};
|
||||||
|
inline SPtrArray() : Ptr(0) {};
|
||||||
|
inline ~SPtrArray() {delete [] Ptr;};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1039
apt/apt-pkg/contrib/strutl.cc
Normal file
1039
apt/apt-pkg/contrib/strutl.cc
Normal file
File diff suppressed because it is too large
Load Diff
96
apt/apt-pkg/contrib/strutl.h
Normal file
96
apt/apt-pkg/contrib/strutl.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: strutl.h,v 1.3 2000/10/30 18:49:49 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
String Util - These are some useful string functions
|
||||||
|
|
||||||
|
_strstrip is a function to remove whitespace from the front and end
|
||||||
|
of a string.
|
||||||
|
|
||||||
|
This source is placed in the Public Domain, do with it what you will
|
||||||
|
It was originally written by Jason Gunthorpe <jgg@gpu.srv.ualberta.ca>
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef STRUTL_H
|
||||||
|
#define STRUTL_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/strutl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
char *_strstrip(char *String);
|
||||||
|
char *_strtabexpand(char *String,size_t Len);
|
||||||
|
bool ParseQuoteWord(const char *&String,string &Res);
|
||||||
|
bool ParseCWord(const char *&String,string &Res);
|
||||||
|
string QuoteString(string Str,const char *Bad);
|
||||||
|
string DeQuoteString(string Str);
|
||||||
|
string SizeToStr(double Bytes);
|
||||||
|
string TimeToStr(unsigned long Sec);
|
||||||
|
string Base64Encode(string Str);
|
||||||
|
string URItoFileName(string URI);
|
||||||
|
string TimeRFC1123(time_t Date);
|
||||||
|
bool StrToTime(string Val,time_t &Result);
|
||||||
|
string LookupTag(string Message,const char *Tag,const char *Default = 0);
|
||||||
|
int StringToBool(string Text,int Default = -1);
|
||||||
|
bool ReadMessages(int Fd, vector<string> &List);
|
||||||
|
bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0);
|
||||||
|
bool Hex2Num(const char *Start,const char *End,unsigned char *Num,
|
||||||
|
unsigned int Length);
|
||||||
|
bool TokSplitString(char Tok,char *Input,char **List,
|
||||||
|
unsigned long ListMax);
|
||||||
|
|
||||||
|
int stringcmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
|
||||||
|
inline int stringcmp(const char *A,const char *AEnd,const char *B) {return stringcmp(A,AEnd,B,B+strlen(B));};
|
||||||
|
inline int stringcmp(string A,const char *B) {return stringcmp(A.begin(),A.end(),B,B+strlen(B));};
|
||||||
|
int stringcasecmp(const char *A,const char *AEnd,const char *B,const char *BEnd);
|
||||||
|
inline int stringcasecmp(const char *A,const char *AEnd,const char *B) {return stringcasecmp(A,AEnd,B,B+strlen(B));};
|
||||||
|
inline int stringcasecmp(string A,const char *B) {return stringcasecmp(A.begin(),A.end(),B,B+strlen(B));};
|
||||||
|
inline int stringcasecmp(string A,string B) {return stringcasecmp(A.begin(),A.end(),B.begin(),B.end());};
|
||||||
|
|
||||||
|
class URI
|
||||||
|
{
|
||||||
|
void CopyFrom(string From);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
string Access;
|
||||||
|
string User;
|
||||||
|
string Password;
|
||||||
|
string Host;
|
||||||
|
string Path;
|
||||||
|
unsigned int Port;
|
||||||
|
|
||||||
|
operator string();
|
||||||
|
inline void operator =(string From) {CopyFrom(From);};
|
||||||
|
inline bool empty() {return Access.empty();};
|
||||||
|
static string SiteOnly(string URI);
|
||||||
|
|
||||||
|
URI(string Path) {CopyFrom(Path);};
|
||||||
|
URI() : Port(0) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SubstVar
|
||||||
|
{
|
||||||
|
const char *Subst;
|
||||||
|
const string *Contents;
|
||||||
|
};
|
||||||
|
string SubstVar(string Str,const struct SubstVar *Vars);
|
||||||
|
string SubstVar(string Str,string Subst,string Contents);
|
||||||
|
|
||||||
|
struct RxChoiceList
|
||||||
|
{
|
||||||
|
void *UserData;
|
||||||
|
const char *Str;
|
||||||
|
bool Hit;
|
||||||
|
};
|
||||||
|
unsigned long RegexChoice(RxChoiceList *Rxs,const char **ListBegin,
|
||||||
|
const char **ListEnd);
|
||||||
|
|
||||||
|
#endif
|
58
apt/apt-pkg/contrib/system.h
Normal file
58
apt/apt-pkg/contrib/system.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: system.h,v 1.1.1.1 2000/08/10 12:42:39 kojima 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
|
||||||
|
#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(MIN)
|
||||||
|
#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
|
||||||
|
#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
|
13
apt/apt-pkg/deb/CVS/Entries
Normal file
13
apt/apt-pkg/deb/CVS/Entries
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/debfactory.cc/1.6/Fri Aug 10 14:00:34 2001//
|
||||||
|
/debfactory.h/1.6/Fri Aug 10 14:00:34 2001//
|
||||||
|
/deblistparser.cc/1.1.1.1/Fri Aug 10 14:00:36 2001//
|
||||||
|
/deblistparser.h/1.1.1.1/Fri Aug 10 14:00:36 2001//
|
||||||
|
/debrecords.cc/1.1.1.1/Fri Aug 10 14:00:36 2001//
|
||||||
|
/debrecords.h/1.1.1.1/Fri Aug 10 14:00:37 2001//
|
||||||
|
/debsrcrecords.cc/1.2/Fri Aug 10 14:00:37 2001//
|
||||||
|
/debsrcrecords.h/1.1.1.1/Fri Aug 10 14:00:37 2001//
|
||||||
|
/dpkginit.cc/1.1.1.1/Fri Aug 10 14:00:37 2001//
|
||||||
|
/dpkginit.h/1.1.1.1/Fri Aug 10 14:00:37 2001//
|
||||||
|
/dpkgpm.cc/1.1.1.1/Fri Aug 10 14:00:37 2001//
|
||||||
|
/dpkgpm.h/1.1.1.1/Fri Aug 10 14:00:37 2001//
|
||||||
|
D
|
1
apt/apt-pkg/deb/CVS/Repository
Normal file
1
apt/apt-pkg/deb/CVS/Repository
Normal file
@ -0,0 +1 @@
|
|||||||
|
rapt/apt-pkg/deb
|
1
apt/apt-pkg/deb/CVS/Root
Normal file
1
apt/apt-pkg/deb/CVS/Root
Normal file
@ -0,0 +1 @@
|
|||||||
|
:pserver:anonymous@cvs.conectiva.com.br:/home/cvs
|
197
apt/apt-pkg/deb/debfactory.cc
Normal file
197
apt/apt-pkg/deb/debfactory.cc
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/deblistparser.h>
|
||||||
|
#include <apt-pkg/dpkgpm.h>
|
||||||
|
#include <apt-pkg/debfactory.h>
|
||||||
|
#include <apt-pkg/sourcelist.h>
|
||||||
|
#include <apt-pkg/progress.h>
|
||||||
|
#include <apt-pkg/debrecords.h>
|
||||||
|
#include <apt-pkg/debsrcrecords.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <system.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pkgPackageManager *DebianFactory::CreatePackageManager(pkgDepCache &Cache)
|
||||||
|
{
|
||||||
|
return new pkgDPkgPM(Cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pkgRecords::Parser *DebianFactory::CreateRecordParser(string File, pkgCache &Cache)
|
||||||
|
{
|
||||||
|
FileFd f;
|
||||||
|
|
||||||
|
f = FileFd(File, FileFd::ReadOnly);
|
||||||
|
if (_error->PendingError())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return new debRecordParser(f, Cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pkgSrcRecords::Parser *DebianFactory::CreateSrcRecordParser(string File,
|
||||||
|
pkgSourceList::const_iterator SrcItem)
|
||||||
|
{
|
||||||
|
FileFd *f;
|
||||||
|
|
||||||
|
f = new FileFd(File, FileFd::ReadOnly);
|
||||||
|
if (_error->PendingError()) {
|
||||||
|
delete f;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new debSrcRecordParser(f, SrcItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DebianFactory::checkSourceType(int type, bool binary)
|
||||||
|
{
|
||||||
|
if (binary)
|
||||||
|
return (type == pkgSourceList::Deb);
|
||||||
|
else
|
||||||
|
return (type == pkgSourceList::DebSrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pkgCacheGenerator::ListParser *DebianFactory::CreateListParser(FileFd &File)
|
||||||
|
{
|
||||||
|
return new debListParser(File);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
// PkgCacheCheck - Check if the package cache is uptodate /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This does a simple check of all files used to compose the cache */
|
||||||
|
bool DebianFactory::packageCacheCheck(string CacheFile)
|
||||||
|
{
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Open the source package cache
|
||||||
|
if (FileExists(CacheFile) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FileFd CacheF(CacheFile,FileFd::ReadOnly);
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
{
|
||||||
|
_error->Discard();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
|
||||||
|
if (_error->PendingError() == true || Map.Size() == 0)
|
||||||
|
{
|
||||||
|
_error->Discard();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgCache Cache(Map);
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
{
|
||||||
|
_error->Discard();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status files that must be in the cache
|
||||||
|
string Status[3];
|
||||||
|
Status[0] = _config->FindFile("Dir::State::xstatus");
|
||||||
|
Status[1]= _config->FindFile("Dir::State::userstatus");
|
||||||
|
Status[2] = _config->FindFile("Dir::State::status");
|
||||||
|
|
||||||
|
// Cheack each file
|
||||||
|
for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
|
||||||
|
{
|
||||||
|
if (F.IsOk() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// See if this is one of the status files
|
||||||
|
for (int I = 0; I != 3; I++)
|
||||||
|
if (F.FileName() == Status[I])
|
||||||
|
Status[I] = string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure all the status files are loaded.
|
||||||
|
for (int I = 0; I != 3; I++)
|
||||||
|
{
|
||||||
|
if (Status[I].empty() == false && FileExists(Status[I]) == true)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// AddStatusSize - Add the size of the status files /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This adds the size of all the status files to the size counter */
|
||||||
|
bool DebianFactory::addStatusSize(unsigned long &TotalSize)
|
||||||
|
{
|
||||||
|
// Grab the file names
|
||||||
|
string xstatus = _config->FindFile("Dir::State::xstatus");
|
||||||
|
string userstatus = _config->FindFile("Dir::State::userstatus");
|
||||||
|
string status = _config->FindFile("Dir::State::status");
|
||||||
|
|
||||||
|
// Grab the sizes
|
||||||
|
struct stat Buf;
|
||||||
|
if (stat(xstatus.c_str(),&Buf) == 0)
|
||||||
|
TotalSize += Buf.st_size;
|
||||||
|
if (stat(userstatus.c_str(),&Buf) == 0)
|
||||||
|
TotalSize += Buf.st_size;
|
||||||
|
if (stat(status.c_str(),&Buf) != 0)
|
||||||
|
return _error->Errno("stat","Couldn't stat the status file %s",status.c_str());
|
||||||
|
TotalSize += Buf.st_size;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// MergeInstalledPackages (was MergeStatus) - Add the status files to the cache /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This adds the status files to the map */
|
||||||
|
bool DebianFactory::mergeInstalledPackages(OpProgress &Progress,
|
||||||
|
pkgCacheGenerator &Gen,
|
||||||
|
unsigned long &CurrentSize,
|
||||||
|
unsigned long TotalSize)
|
||||||
|
{
|
||||||
|
// Grab the file names
|
||||||
|
string Status[3];
|
||||||
|
Status[0] = _config->FindFile("Dir::State::xstatus");
|
||||||
|
Status[1]= _config->FindFile("Dir::State::userstatus");
|
||||||
|
Status[2] = _config->FindFile("Dir::State::status");
|
||||||
|
|
||||||
|
for (int I = 0; I != 3; I++)
|
||||||
|
{
|
||||||
|
pkgCacheGenerator::ListParser *Parser;
|
||||||
|
|
||||||
|
// Check if the file exists and it is not the primary status file.
|
||||||
|
string File = Status[I];
|
||||||
|
if (I != 2 && FileExists(File) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FileFd Pkg(File,FileFd::ReadOnly);
|
||||||
|
Parser = new debListParser(Pkg);
|
||||||
|
|
||||||
|
Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists");
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return _error->Error("Problem opening %s",File.c_str());
|
||||||
|
CurrentSize += Pkg.Size();
|
||||||
|
|
||||||
|
Progress.SubProgress(0,"Local Package State - " + flNotDir(File));
|
||||||
|
if (Gen.SelectFile(File,pkgCache::Flag::NotSource) == false)
|
||||||
|
return _error->Error("Problem with SelectFile %s",File.c_str());
|
||||||
|
|
||||||
|
if (Gen.MergeList(*Parser) == false)
|
||||||
|
return _error->Error("Problem with MergeList %s",File.c_str());
|
||||||
|
Progress.Progress(Pkg.Size());
|
||||||
|
|
||||||
|
delete Parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
31
apt/apt-pkg/deb/debfactory.h
Normal file
31
apt/apt-pkg/deb/debfactory.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
#ifndef _DEBIANFACTORY_H_
|
||||||
|
#define _DEBIANFACTORY_H_
|
||||||
|
|
||||||
|
#include <apt-pkg/systemfactory.h>
|
||||||
|
|
||||||
|
|
||||||
|
class DebianFactory : public SystemFactory
|
||||||
|
{
|
||||||
|
// for cache generation
|
||||||
|
protected:
|
||||||
|
bool addStatusSize(unsigned long &TotalSize);
|
||||||
|
|
||||||
|
bool mergeInstalledPackages(OpProgress &Progress,pkgCacheGenerator &Gen,
|
||||||
|
unsigned long &CurrentSize,
|
||||||
|
unsigned long TotalSize);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool packageCacheCheck(string CacheFile);
|
||||||
|
|
||||||
|
bool checkSourceType(int type, bool binary=true);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// other stuffs
|
||||||
|
pkgCacheGenerator::ListParser *CreateListParser(FileFd &File);
|
||||||
|
pkgRecords::Parser *CreateRecordParser(string File, pkgCache &Cache);
|
||||||
|
pkgSrcRecords::Parser *CreateSrcRecordParser(string File, pkgSourceList::const_iterator SrcItem);
|
||||||
|
pkgPackageManager *CreatePackageManager(pkgDepCache &Cache);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
529
apt/apt-pkg/deb/deblistparser.cc
Normal file
529
apt/apt-pkg/deb/deblistparser.cc
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: deblistparser.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Package Cache Generator - Generator for the cache structure.
|
||||||
|
|
||||||
|
This builds the cache structure from the abstract package list parser.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#include <apt-pkg/deblistparser.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
#include <apt-pkg/crc-16.h>
|
||||||
|
|
||||||
|
#include <system.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// ListParser::debListParser - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
debListParser::debListParser(FileFd &File) : Tags(File)
|
||||||
|
{
|
||||||
|
Arch = _config->Find("APT::architecture");
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
unsigned long debListParser::UniqFindTagWrite(const char *Tag)
|
||||||
|
{
|
||||||
|
const char *Start;
|
||||||
|
const char *Stop;
|
||||||
|
if (Section.Find(Tag,Start,Stop) == false)
|
||||||
|
return 0;
|
||||||
|
return WriteUniqString(Start,Stop - Start);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::Package - Return the package name /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is to return the name of the package this section describes */
|
||||||
|
string debListParser::Package()
|
||||||
|
{
|
||||||
|
string Result = Section.FindS("Package");
|
||||||
|
if (Result.empty() == true)
|
||||||
|
_error->Error("Encountered a section with no Package: header");
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::Version - Return the version string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is to return the string describing the version in debian form,
|
||||||
|
epoch:upstream-release. If this returns the blank string then the
|
||||||
|
entry is assumed to only describe package properties */
|
||||||
|
string debListParser::Version()
|
||||||
|
{
|
||||||
|
return Section.FindS("Version");
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::NewVersion - Fill in the version structure /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool debListParser::NewVersion(pkgCache::VerIterator Ver)
|
||||||
|
{
|
||||||
|
// Parse the section
|
||||||
|
Ver->Section = UniqFindTagWrite("Section");
|
||||||
|
Ver->Arch = UniqFindTagWrite("Architecture");
|
||||||
|
|
||||||
|
// Archive Size
|
||||||
|
Ver->Size = (unsigned)Section.FindI("Size");
|
||||||
|
|
||||||
|
// Unpacked Size (in K)
|
||||||
|
Ver->InstalledSize = (unsigned)Section.FindI("Installed-Size");
|
||||||
|
Ver->InstalledSize *= 1024;
|
||||||
|
|
||||||
|
// Priority
|
||||||
|
const char *Start;
|
||||||
|
const char *Stop;
|
||||||
|
if (Section.Find("Priority",Start,Stop) == true)
|
||||||
|
{
|
||||||
|
WordList PrioList[] = {{"important",pkgCache::State::Important},
|
||||||
|
{"required",pkgCache::State::Required},
|
||||||
|
{"standard",pkgCache::State::Standard},
|
||||||
|
{"optional",pkgCache::State::Optional},
|
||||||
|
{"extra",pkgCache::State::Extra}};
|
||||||
|
if (GrabWord(string(Start,Stop-Start),PrioList,
|
||||||
|
_count(PrioList),Ver->Priority) == false)
|
||||||
|
Ver->Priority = pkgCache::State::Extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
|
||||||
|
return false;
|
||||||
|
if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
|
||||||
|
return false;
|
||||||
|
if (ParseDepends(Ver,"Suggests",pkgCache::Dep::Suggests) == false)
|
||||||
|
return false;
|
||||||
|
if (ParseDepends(Ver,"Recommends",pkgCache::Dep::Recommends) == false)
|
||||||
|
return false;
|
||||||
|
if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
|
||||||
|
return false;
|
||||||
|
if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ParseProvides(Ver) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::UsePackage - Update a package structure /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called to update the package with any new information
|
||||||
|
that might be found in the section */
|
||||||
|
bool debListParser::UsePackage(pkgCache::PkgIterator Pkg,
|
||||||
|
pkgCache::VerIterator Ver)
|
||||||
|
{
|
||||||
|
if (Pkg->Section == 0)
|
||||||
|
Pkg->Section = UniqFindTagWrite("Section");
|
||||||
|
if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
|
||||||
|
return false;
|
||||||
|
if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (strcmp(Pkg.Name(),"apt") == 0)
|
||||||
|
Pkg->Flags |= pkgCache::Flag::Important;
|
||||||
|
|
||||||
|
if (ParseStatus(Pkg,Ver) == false)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::VersionHash - Compute a unique hash for this version /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
unsigned short debListParser::VersionHash()
|
||||||
|
{
|
||||||
|
const char *Sections[] ={"Installed-Size",
|
||||||
|
"Depends",
|
||||||
|
"Pre-Depends",
|
||||||
|
// "Suggests",
|
||||||
|
// "Recommends",
|
||||||
|
"Conflicts",
|
||||||
|
"Replaces",0};
|
||||||
|
unsigned long Result = INIT_FCS;
|
||||||
|
char S[300];
|
||||||
|
for (const char **I = Sections; *I != 0; I++)
|
||||||
|
{
|
||||||
|
const char *Start;
|
||||||
|
const char *End;
|
||||||
|
if (Section.Find(*I,Start,End) == false || End - Start >= (signed)sizeof(S))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Strip out any spaces from the text, this undoes dpkgs reformatting
|
||||||
|
of certain fields. dpkg also has the rather interesting notion of
|
||||||
|
reformatting depends operators < -> <= */
|
||||||
|
char *I = S;
|
||||||
|
for (; Start != End; Start++)
|
||||||
|
{
|
||||||
|
if (isspace(*Start) == 0)
|
||||||
|
*I++ = tolower(*Start);
|
||||||
|
if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
|
||||||
|
*I++ = '=';
|
||||||
|
if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
|
||||||
|
*I++ = '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = AddCRC16(Result,S,I - S);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::ParseStatus - Parse the status field /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Status lines are of the form,
|
||||||
|
Status: want flag status
|
||||||
|
want = unknown, install, hold, deinstall, purge
|
||||||
|
flag = ok, reinstreq, hold, hold-reinstreq
|
||||||
|
status = not-installed, unpacked, half-configured,
|
||||||
|
half-installed, config-files, post-inst-failed,
|
||||||
|
removal-failed, installed
|
||||||
|
|
||||||
|
Some of the above are obsolete (I think?) flag = hold-* and
|
||||||
|
status = post-inst-failed, removal-failed at least.
|
||||||
|
*/
|
||||||
|
bool debListParser::ParseStatus(pkgCache::PkgIterator Pkg,
|
||||||
|
pkgCache::VerIterator Ver)
|
||||||
|
{
|
||||||
|
const char *Start;
|
||||||
|
const char *Stop;
|
||||||
|
if (Section.Find("Status",Start,Stop) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Isolate the first word
|
||||||
|
const char *I = Start;
|
||||||
|
for(; I < Stop && *I != ' '; I++);
|
||||||
|
if (I >= Stop || *I != ' ')
|
||||||
|
return _error->Error("Malformed Status line");
|
||||||
|
|
||||||
|
// Process the want field
|
||||||
|
WordList WantList[] = {{"unknown",pkgCache::State::Unknown},
|
||||||
|
{"install",pkgCache::State::Install},
|
||||||
|
{"hold",pkgCache::State::Hold},
|
||||||
|
{"deinstall",pkgCache::State::DeInstall},
|
||||||
|
{"purge",pkgCache::State::Purge}};
|
||||||
|
if (GrabWord(string(Start,I-Start),WantList,
|
||||||
|
_count(WantList),Pkg->SelectedState) == false)
|
||||||
|
return _error->Error("Malformed 1st word in the Status line");
|
||||||
|
|
||||||
|
// Isloate the next word
|
||||||
|
I++;
|
||||||
|
Start = I;
|
||||||
|
for(; I < Stop && *I != ' '; I++);
|
||||||
|
if (I >= Stop || *I != ' ')
|
||||||
|
return _error->Error("Malformed status line, no 2nd word");
|
||||||
|
|
||||||
|
// Process the flag field
|
||||||
|
WordList FlagList[] = {{"ok",pkgCache::State::Ok},
|
||||||
|
{"reinstreq",pkgCache::State::ReInstReq},
|
||||||
|
{"hold",pkgCache::State::HoldInst},
|
||||||
|
{"hold-reinstreq",pkgCache::State::HoldReInstReq}};
|
||||||
|
if (GrabWord(string(Start,I-Start),FlagList,
|
||||||
|
_count(FlagList),Pkg->InstState) == false)
|
||||||
|
return _error->Error("Malformed 2nd word in the Status line");
|
||||||
|
|
||||||
|
// Isloate the last word
|
||||||
|
I++;
|
||||||
|
Start = I;
|
||||||
|
for(; I < Stop && *I != ' '; I++);
|
||||||
|
if (I != Stop)
|
||||||
|
return _error->Error("Malformed Status line, no 3rd word");
|
||||||
|
|
||||||
|
// Process the flag field
|
||||||
|
WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled},
|
||||||
|
{"unpacked",pkgCache::State::UnPacked},
|
||||||
|
{"half-configured",pkgCache::State::HalfConfigured},
|
||||||
|
{"installed",pkgCache::State::Installed},
|
||||||
|
{"half-installed",pkgCache::State::HalfInstalled},
|
||||||
|
{"config-files",pkgCache::State::ConfigFiles},
|
||||||
|
{"post-inst-failed",pkgCache::State::HalfConfigured},
|
||||||
|
{"removal-failed",pkgCache::State::HalfInstalled}};
|
||||||
|
if (GrabWord(string(Start,I-Start),StatusList,
|
||||||
|
_count(StatusList),Pkg->CurrentState) == false)
|
||||||
|
return _error->Error("Malformed 3rd word in the Status line");
|
||||||
|
|
||||||
|
/* A Status line marks the package as indicating the current
|
||||||
|
version as well. Only if it is actually installed.. Otherwise
|
||||||
|
the interesting dpkg handling of the status file creates bogus
|
||||||
|
entries. */
|
||||||
|
if (!(Pkg->CurrentState == pkgCache::State::NotInstalled ||
|
||||||
|
Pkg->CurrentState == pkgCache::State::ConfigFiles))
|
||||||
|
{
|
||||||
|
if (Ver.end() == true)
|
||||||
|
_error->Warning("Encountered status field in a non-version description");
|
||||||
|
else
|
||||||
|
Pkg->CurrentVer = Ver.Index();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::ParseDepends - Parse a dependency element /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This parses the dependency elements out of a standard string in place,
|
||||||
|
bit by bit. */
|
||||||
|
const char *debListParser::ParseDepends(const char *Start,const char *Stop,
|
||||||
|
string &Package,string &Ver,
|
||||||
|
unsigned int &Op)
|
||||||
|
{
|
||||||
|
// Strip off leading space
|
||||||
|
for (;Start != Stop && isspace(*Start) != 0; Start++);
|
||||||
|
|
||||||
|
// Parse off the package name
|
||||||
|
const char *I = Start;
|
||||||
|
for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
|
||||||
|
*I != ',' && *I != '|'; I++);
|
||||||
|
|
||||||
|
// Malformed, no '('
|
||||||
|
if (I != Stop && *I == ')')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (I == Start)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Stash the package name
|
||||||
|
Package.assign(Start,I - Start);
|
||||||
|
|
||||||
|
// Skip white space to the '('
|
||||||
|
for (;I != Stop && isspace(*I) != 0 ; I++);
|
||||||
|
|
||||||
|
// Parse a version
|
||||||
|
if (I != Stop && *I == '(')
|
||||||
|
{
|
||||||
|
// Skip the '('
|
||||||
|
for (I++; I != Stop && isspace(*I) != 0 ; I++);
|
||||||
|
if (I + 3 >= Stop)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Determine the operator
|
||||||
|
switch (*I)
|
||||||
|
{
|
||||||
|
case '<':
|
||||||
|
I++;
|
||||||
|
if (*I == '=')
|
||||||
|
{
|
||||||
|
I++;
|
||||||
|
Op = pkgCache::Dep::LessEq;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*I == '<')
|
||||||
|
{
|
||||||
|
I++;
|
||||||
|
Op = pkgCache::Dep::Less;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// < is the same as <= and << is really Cs < for some reason
|
||||||
|
Op = pkgCache::Dep::LessEq;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
I++;
|
||||||
|
if (*I == '=')
|
||||||
|
{
|
||||||
|
I++;
|
||||||
|
Op = pkgCache::Dep::GreaterEq;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*I == '>')
|
||||||
|
{
|
||||||
|
I++;
|
||||||
|
Op = pkgCache::Dep::Greater;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// > is the same as >= and >> is really Cs > for some reason
|
||||||
|
Op = pkgCache::Dep::GreaterEq;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '=':
|
||||||
|
Op = pkgCache::Dep::Equals;
|
||||||
|
I++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// HACK around bad package definitions
|
||||||
|
default:
|
||||||
|
Op = pkgCache::Dep::Equals;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
for (;I != Stop && isspace(*I) != 0; I++);
|
||||||
|
Start = I;
|
||||||
|
for (;I != Stop && *I != ')'; I++);
|
||||||
|
if (I == Stop || Start == I)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Skip trailing whitespace
|
||||||
|
const char *End = I;
|
||||||
|
for (; End > Start && isspace(End[-1]); End--);
|
||||||
|
|
||||||
|
Ver = string(Start,End-Start);
|
||||||
|
I++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ver = string();
|
||||||
|
Op = pkgCache::Dep::NoOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
for (;I != Stop && isspace(*I) != 0; I++);
|
||||||
|
if (I != Stop && *I == '|')
|
||||||
|
Op |= pkgCache::Dep::Or;
|
||||||
|
|
||||||
|
if (I == Stop || *I == ',' || *I == '|')
|
||||||
|
{
|
||||||
|
if (I != Stop)
|
||||||
|
for (I++; I != Stop && isspace(*I) != 0; I++);
|
||||||
|
return I;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::ParseDepends - Parse a dependency list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is the higher level depends parser. It takes a tag and generates
|
||||||
|
a complete depends tree for the given version. */
|
||||||
|
bool debListParser::ParseDepends(pkgCache::VerIterator Ver,
|
||||||
|
const char *Tag,unsigned int Type)
|
||||||
|
{
|
||||||
|
const char *Start;
|
||||||
|
const char *Stop;
|
||||||
|
if (Section.Find(Tag,Start,Stop) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
string Package;
|
||||||
|
string Version;
|
||||||
|
unsigned int Op;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
Start = ParseDepends(Start,Stop,Package,Version,Op);
|
||||||
|
if (Start == 0)
|
||||||
|
return _error->Error("Problem parsing dependency %s",Tag);
|
||||||
|
|
||||||
|
if (NewDepends(Ver,Package,Version,Op,Type) == false)
|
||||||
|
return false;
|
||||||
|
if (Start == Stop)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::ParseProvides - Parse the provides list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool debListParser::ParseProvides(pkgCache::VerIterator Ver)
|
||||||
|
{
|
||||||
|
const char *Start;
|
||||||
|
const char *Stop;
|
||||||
|
if (Section.Find("Provides",Start,Stop) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
string Package;
|
||||||
|
string Version;
|
||||||
|
unsigned int Op;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
Start = ParseDepends(Start,Stop,Package,Version,Op);
|
||||||
|
if (Start == 0)
|
||||||
|
return _error->Error("Problem parsing Provides line");
|
||||||
|
if (Op != pkgCache::Dep::NoOp)
|
||||||
|
return _error->Error("Malformed provides line");
|
||||||
|
|
||||||
|
if (NewProvides(Ver,Package,Version) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Start == Stop)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::GrabWord - Matches a word and returns /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Looks for a word in a list of words - for ParseStatus */
|
||||||
|
bool debListParser::GrabWord(string Word,WordList *List,int Count,
|
||||||
|
unsigned char &Out)
|
||||||
|
{
|
||||||
|
for (int C = 0; C != Count; C++)
|
||||||
|
{
|
||||||
|
if (strcasecmp(Word.c_str(),List[C].Str) == 0)
|
||||||
|
{
|
||||||
|
Out = List[C].Val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::Step - Move to the next section in the file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This has to be carefull to only process the correct architecture */
|
||||||
|
bool debListParser::Step()
|
||||||
|
{
|
||||||
|
iOffset = Tags.Offset();
|
||||||
|
while (Tags.Step(Section) == true)
|
||||||
|
{
|
||||||
|
/* See if this is the correct Architecture, if it isn't then we
|
||||||
|
drop the whole section. A missing arch tag only happens (in theory)
|
||||||
|
inside the Status file, so that is a positive return */
|
||||||
|
const char *Start;
|
||||||
|
const char *Stop;
|
||||||
|
if (Section.Find("Architecture",Start,Stop) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (stringcmp(Start,Stop,Arch.begin(),Arch.end()) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (stringcmp(Start,Stop,"all") == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
iOffset = Tags.Offset();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::LoadReleaseInfo - Load the release information /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator FileI,
|
||||||
|
FileFd &File)
|
||||||
|
{
|
||||||
|
pkgTagFile Tags(File);
|
||||||
|
pkgTagSection Section;
|
||||||
|
if (Tags.Step(Section) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char *Start;
|
||||||
|
const char *Stop;
|
||||||
|
if (Section.Find("Archive",Start,Stop) == true)
|
||||||
|
FileI->Archive = WriteUniqString(Start,Stop - Start);
|
||||||
|
if (Section.Find("Component",Start,Stop) == true)
|
||||||
|
FileI->Component = WriteUniqString(Start,Stop - Start);
|
||||||
|
if (Section.Find("Version",Start,Stop) == true)
|
||||||
|
FileI->Version = WriteUniqString(Start,Stop - Start);
|
||||||
|
if (Section.Find("Origin",Start,Stop) == true)
|
||||||
|
FileI->Origin = WriteUniqString(Start,Stop - Start);
|
||||||
|
if (Section.Find("Label",Start,Stop) == true)
|
||||||
|
FileI->Label = WriteUniqString(Start,Stop - Start);
|
||||||
|
if (Section.Find("Architecture",Start,Stop) == true)
|
||||||
|
FileI->Architecture = WriteUniqString(Start,Stop - Start);
|
||||||
|
|
||||||
|
if (Section.FindFlag("NotAutomatic",FileI->Flags,
|
||||||
|
pkgCache::Flag::NotAutomatic) == false)
|
||||||
|
_error->Warning("Bad NotAutomatic flag");
|
||||||
|
|
||||||
|
return !_error->PendingError();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
60
apt/apt-pkg/deb/deblistparser.h
Normal file
60
apt/apt-pkg/deb/deblistparser.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: deblistparser.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Debian Package List Parser - This implements the abstract parser
|
||||||
|
interface for Debian package files
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_DEBLISTPARSER_H
|
||||||
|
#define PKGLIB_DEBLISTPARSER_H
|
||||||
|
|
||||||
|
#include <apt-pkg/pkgcachegen.h>
|
||||||
|
#include <apt-pkg/tagfile.h>
|
||||||
|
|
||||||
|
class debListParser : public pkgCacheGenerator::ListParser
|
||||||
|
{
|
||||||
|
pkgTagFile Tags;
|
||||||
|
pkgTagSection Section;
|
||||||
|
unsigned long iOffset;
|
||||||
|
string Arch;
|
||||||
|
|
||||||
|
// Parser Helper
|
||||||
|
struct WordList
|
||||||
|
{
|
||||||
|
char *Str;
|
||||||
|
unsigned char Val;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long UniqFindTagWrite(const char *Tag);
|
||||||
|
bool ParseStatus(pkgCache::PkgIterator Pkg,pkgCache::VerIterator Ver);
|
||||||
|
const char *ParseDepends(const char *Start,const char *Stop,
|
||||||
|
string &Package,string &Ver,unsigned int &Op);
|
||||||
|
bool ParseDepends(pkgCache::VerIterator Ver,const char *Tag,
|
||||||
|
unsigned int Type);
|
||||||
|
bool ParseProvides(pkgCache::VerIterator Ver);
|
||||||
|
bool GrabWord(string Word,WordList *List,int Count,unsigned char &Out);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// These all operate against the current section
|
||||||
|
virtual string Package();
|
||||||
|
virtual string Version();
|
||||||
|
virtual bool NewVersion(pkgCache::VerIterator Ver);
|
||||||
|
virtual unsigned short VersionHash();
|
||||||
|
virtual bool UsePackage(pkgCache::PkgIterator Pkg,
|
||||||
|
pkgCache::VerIterator Ver);
|
||||||
|
virtual unsigned long Offset() {return iOffset;};
|
||||||
|
virtual unsigned long Size() {return Section.size();};
|
||||||
|
|
||||||
|
virtual bool Step();
|
||||||
|
|
||||||
|
bool LoadReleaseInfo(pkgCache::PkgFileIterator FileI,FileFd &File);
|
||||||
|
|
||||||
|
debListParser(FileFd &File);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
89
apt/apt-pkg/deb/debrecords.cc
Normal file
89
apt/apt-pkg/deb/debrecords.cc
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: debrecords.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Debian Package Records - Parser for debian package records
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/debrecords.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/debrecords.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// RecordParser::debRecordParser - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
debRecordParser::debRecordParser(FileFd &File,pkgCache &Cache) :
|
||||||
|
Tags(File,Cache.Head().MaxVerFileSize + 20)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// RecordParser::Jump - Jump to a specific record /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool debRecordParser::Jump(pkgCache::VerFileIterator const &Ver)
|
||||||
|
{
|
||||||
|
return Tags.Jump(Section,Ver->Offset);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// RecordParser::FileName - Return the archive filename on the site /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string debRecordParser::FileName()
|
||||||
|
{
|
||||||
|
return Section.FindS("Filename");
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// RecordParser::MD5Hash - Return the archive hash /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string debRecordParser::MD5Hash()
|
||||||
|
{
|
||||||
|
return Section.FindS("MD5sum");
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// RecordParser::Maintainer - Return the maintainer email /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string debRecordParser::Maintainer()
|
||||||
|
{
|
||||||
|
return Section.FindS("Maintainer");
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// RecordParser::ShortDesc - Return a 1 line description /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string debRecordParser::ShortDesc()
|
||||||
|
{
|
||||||
|
string Res = Section.FindS("Description");
|
||||||
|
string::size_type Pos = Res.find('\n');
|
||||||
|
if (Pos == string::npos)
|
||||||
|
return Res;
|
||||||
|
return string(Res,0,Pos);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// RecordParser::LongDesc - Return a longer description /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string debRecordParser::LongDesc()
|
||||||
|
{
|
||||||
|
return Section.FindS("Description");
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// RecordParser::SourcePkg - Return the source package name if any /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
string debRecordParser::SourcePkg()
|
||||||
|
{
|
||||||
|
string Res = Section.FindS("Source");
|
||||||
|
string::size_type Pos = Res.find(' ');
|
||||||
|
if (Pos == string::npos)
|
||||||
|
return Res;
|
||||||
|
return string(Res,0,Pos);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
50
apt/apt-pkg/deb/debrecords.h
Normal file
50
apt/apt-pkg/deb/debrecords.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: debrecords.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Debian Package Records - Parser for debian package records
|
||||||
|
|
||||||
|
This provides display-type parsing for the Packages file. This is
|
||||||
|
different than the the list parser which provides cache generation
|
||||||
|
services. There should be no overlap between these two.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_DEBRECORDS_H
|
||||||
|
#define PKGLIB_DEBRECORDS_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/debrecords.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/pkgrecords.h>
|
||||||
|
#include <apt-pkg/tagfile.h>
|
||||||
|
|
||||||
|
class debRecordParser : public pkgRecords::Parser
|
||||||
|
{
|
||||||
|
pkgTagFile Tags;
|
||||||
|
pkgTagSection Section;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual bool Jump(pkgCache::VerFileIterator const &Ver);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// These refer to the archive file for the Version
|
||||||
|
virtual string FileName();
|
||||||
|
virtual string MD5Hash();
|
||||||
|
virtual string SourcePkg();
|
||||||
|
|
||||||
|
// These are some general stats about the package
|
||||||
|
virtual string Maintainer();
|
||||||
|
virtual string ShortDesc();
|
||||||
|
virtual string LongDesc();
|
||||||
|
|
||||||
|
debRecordParser(FileFd &File,pkgCache &Cache);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
103
apt/apt-pkg/deb/debsrcrecords.cc
Normal file
103
apt/apt-pkg/deb/debsrcrecords.cc
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: debsrcrecords.cc,v 1.2 2000/10/29 20:25:10 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Debian Source Package Records - Parser implementation for Debian style
|
||||||
|
source indexes
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/debsrcrecords.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/debsrcrecords.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// SrcRecordParser::Binaries - Return the binaries field /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This member parses the binaries field into a pair of class arrays and
|
||||||
|
returns a list of strings representing all of the components of the
|
||||||
|
binaries field. The returned array need not be freed and will be
|
||||||
|
reused by the next Binaries function call. */
|
||||||
|
const char **debSrcRecordParser::Binaries()
|
||||||
|
{
|
||||||
|
string Bins = Sect.FindS("Binary");
|
||||||
|
char *Buf = Buffer;
|
||||||
|
unsigned int Bin = 0;
|
||||||
|
if (Bins.empty() == true)
|
||||||
|
return 0;
|
||||||
|
// XXX no bounds check: exploitable?
|
||||||
|
// Strip any leading spaces
|
||||||
|
string::const_iterator Start = Bins.begin();
|
||||||
|
for (; Start != Bins.end() && isspace(*Start) != 0; Start++);
|
||||||
|
|
||||||
|
string::const_iterator Pos = Start;
|
||||||
|
while (Pos != Bins.end())
|
||||||
|
{
|
||||||
|
// Skip to the next ','
|
||||||
|
for (; Pos != Bins.end() && *Pos != ','; Pos++);
|
||||||
|
|
||||||
|
// Back remove spaces
|
||||||
|
string::const_iterator End = Pos;
|
||||||
|
for (; End > Start && (End[-1] == ',' || isspace(End[-1]) != 0); End--);
|
||||||
|
|
||||||
|
// Stash the string
|
||||||
|
memcpy(Buf,Start,End-Start);
|
||||||
|
StaticBinList[Bin] = Buf;
|
||||||
|
Bin++;
|
||||||
|
Buf += End-Start;
|
||||||
|
*Buf++ = 0;
|
||||||
|
|
||||||
|
// Advance pos
|
||||||
|
for (; Pos != Bins.end() && (*Pos == ',' || isspace(*Pos) != 0); Pos++);
|
||||||
|
Start = Pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticBinList[Bin] = 0;
|
||||||
|
return StaticBinList;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// SrcRecordParser::Files - Return a list of files for this source /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This parses the list of files and returns it, each file is required to have
|
||||||
|
a complete source package */
|
||||||
|
bool debSrcRecordParser::Files(vector<pkgSrcRecords::File> &List)
|
||||||
|
{
|
||||||
|
List.erase(List.begin(),List.end());
|
||||||
|
|
||||||
|
string Files = Sect.FindS("Files");
|
||||||
|
if (Files.empty() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Stash the / terminated directory prefix
|
||||||
|
string Base = Sect.FindS("Directory");
|
||||||
|
if (Base.empty() == false && Base[Base.length()-1] != '/')
|
||||||
|
Base += '/';
|
||||||
|
|
||||||
|
// Iterate over the entire list grabbing each triplet
|
||||||
|
const char *C = Files.c_str();
|
||||||
|
while (*C != 0)
|
||||||
|
{
|
||||||
|
pkgSrcRecords::File F;
|
||||||
|
string Size;
|
||||||
|
|
||||||
|
// Parse each of the elements
|
||||||
|
if (ParseQuoteWord(C,F.MD5Hash) == false ||
|
||||||
|
ParseQuoteWord(C,Size) == false ||
|
||||||
|
ParseQuoteWord(C,F.Path) == false)
|
||||||
|
return _error->Error("Error parsing file record");
|
||||||
|
|
||||||
|
// Parse the size and append the directory
|
||||||
|
F.Size = atoi(Size.c_str());
|
||||||
|
F.Path = Base + F.Path;
|
||||||
|
List.push_back(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
54
apt/apt-pkg/deb/debsrcrecords.h
Normal file
54
apt/apt-pkg/deb/debsrcrecords.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: debsrcrecords.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Debian Source Package Records - Parser implementation for Debian style
|
||||||
|
source indexes
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_DEBSRCRECORDS_H
|
||||||
|
#define PKGLIB_DEBSRCRECORDS_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/debsrcrecords.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/srcrecords.h>
|
||||||
|
#include <apt-pkg/tagfile.h>
|
||||||
|
|
||||||
|
class debSrcRecordParser : public pkgSrcRecords::Parser
|
||||||
|
{
|
||||||
|
pkgTagFile Tags;
|
||||||
|
pkgTagSection Sect;
|
||||||
|
char Buffer[10000];
|
||||||
|
const char *StaticBinList[400];
|
||||||
|
unsigned long iOffset;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual bool Restart() {return Tags.Jump(Sect,0);};
|
||||||
|
virtual bool Step() {iOffset = Tags.Offset(); return Tags.Step(Sect);};
|
||||||
|
virtual bool Jump(unsigned long Off) {iOffset = Off; return Tags.Jump(Sect,Off);};
|
||||||
|
|
||||||
|
virtual string Package() {return Sect.FindS("Package");};
|
||||||
|
virtual string Version() {return Sect.FindS("Version");};
|
||||||
|
virtual string Maintainer() {return Sect.FindS("Maintainer");};
|
||||||
|
virtual string Section() {return Sect.FindS("Section");};
|
||||||
|
virtual const char **Binaries();
|
||||||
|
virtual unsigned long Offset() {return iOffset;};
|
||||||
|
virtual string AsStr()
|
||||||
|
{
|
||||||
|
const char *Start=0,*Stop=0;
|
||||||
|
Sect.GetSection(Start,Stop);
|
||||||
|
return string(Start,Stop);
|
||||||
|
};
|
||||||
|
virtual bool Files(vector<pkgSrcRecords::File> &F);
|
||||||
|
|
||||||
|
debSrcRecordParser(FileFd *File,pkgSourceList::const_iterator SrcItem) :
|
||||||
|
Parser(File,SrcItem),
|
||||||
|
Tags(*File,sizeof(Buffer)) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
119
apt/apt-pkg/deb/dpkginit.cc
Normal file
119
apt/apt-pkg/deb/dpkginit.cc
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: dpkginit.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
DPKG init - Initialize the dpkg stuff
|
||||||
|
|
||||||
|
This class provides the locking mechanism used by dpkg for its
|
||||||
|
database area. It does the proper consistency checks and acquires the
|
||||||
|
correct kind of lock.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Includes /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/dpkginit.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/dpkginit.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// DpkgLock::pkgDpkgLock - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgDpkgLock::pkgDpkgLock(bool WithUpdates)
|
||||||
|
{
|
||||||
|
LockFD = -1;
|
||||||
|
GetLock(WithUpdates);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DpkgLock::~pkgDpkgLock - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgDpkgLock::~pkgDpkgLock()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DpkgLock::GetLock - Get the lock /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This mirrors the operations dpkg does when it starts up. Note the
|
||||||
|
checking of the updates directory. */
|
||||||
|
bool pkgDpkgLock::GetLock(bool WithUpdates)
|
||||||
|
{
|
||||||
|
// Disable file locking
|
||||||
|
if (_config->FindB("Debug::NoLocking",false) == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Close();
|
||||||
|
|
||||||
|
// Create the lockfile
|
||||||
|
string AdminDir = flNotFile(_config->Find("Dir::State::status"));
|
||||||
|
LockFD = ::GetLock(AdminDir + "lock");
|
||||||
|
if (LockFD == -1)
|
||||||
|
return _error->Error("Unable to lock the administration directory, "
|
||||||
|
"are you root?");
|
||||||
|
|
||||||
|
// See if we need to abort with a dirty journal
|
||||||
|
if (WithUpdates == true && CheckUpdates() == true)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
return _error->Error("dpkg was interrupted, you must manually "
|
||||||
|
"run 'dpkg --configure -a' to correct the problem. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DpkgLock::Close - Close the lock /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgDpkgLock::Close()
|
||||||
|
{
|
||||||
|
close(LockFD);
|
||||||
|
LockFD = -1;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DpkgLock::CheckUpdates - Check if the updates dir is dirty /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This does a check of the updates directory to see if it has any entries
|
||||||
|
in it. */
|
||||||
|
bool pkgDpkgLock::CheckUpdates()
|
||||||
|
{
|
||||||
|
// Check for updates.. (dirty)
|
||||||
|
string File = flNotFile(_config->Find("Dir::State::status")) + "updates/";
|
||||||
|
DIR *DirP = opendir(File.c_str());
|
||||||
|
if (DirP == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* We ignore any files that are not all digits, this skips .,.. and
|
||||||
|
some tmp files dpkg will leave behind.. */
|
||||||
|
bool Damaged = false;
|
||||||
|
for (struct dirent *Ent = readdir(DirP); Ent != 0; Ent = readdir(DirP))
|
||||||
|
{
|
||||||
|
Damaged = true;
|
||||||
|
for (unsigned int I = 0; Ent->d_name[I] != 0; I++)
|
||||||
|
{
|
||||||
|
// Check if its not a digit..
|
||||||
|
if (isdigit(Ent->d_name[I]) == 0)
|
||||||
|
{
|
||||||
|
Damaged = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Damaged == true)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
closedir(DirP);
|
||||||
|
|
||||||
|
return Damaged;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
34
apt/apt-pkg/deb/dpkginit.h
Normal file
34
apt/apt-pkg/deb/dpkginit.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: dpkginit.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
DPKG init - Initialize the dpkg stuff
|
||||||
|
|
||||||
|
This basically gets a lock in /var/lib/dpkg and checks the updates
|
||||||
|
directory
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_DPKGINIT_H
|
||||||
|
#define PKGLIB_DPKGINIT_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/dpkginit.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class pkgDpkgLock
|
||||||
|
{
|
||||||
|
int LockFD;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool CheckUpdates();
|
||||||
|
bool GetLock(bool WithUpdates);
|
||||||
|
void Close();
|
||||||
|
|
||||||
|
pkgDpkgLock(bool WithUpdates = true);
|
||||||
|
~pkgDpkgLock();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
408
apt/apt-pkg/deb/dpkgpm.cc
Normal file
408
apt/apt-pkg/deb/dpkgpm.cc
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: dpkgpm.cc,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
DPKG Package Manager - Provide an interface to dpkg
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Includes /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/dpkgpm.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/dpkgpm.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// DPkgPM::pkgDPkgPM - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgDPkgPM::pkgDPkgPM(pkgDepCache &Cache) : pkgPackageManager(Cache)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DPkgPM::pkgDPkgPM - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgDPkgPM::~pkgDPkgPM()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DPkgPM::Install - Install a package /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Add an install operation to the sequence list */
|
||||||
|
bool pkgDPkgPM::Install(PkgIterator Pkg,string File)
|
||||||
|
{
|
||||||
|
if (File.empty() == true || Pkg.end() == true)
|
||||||
|
return _error->Error("Internal Error, No file name for %s",Pkg.Name());
|
||||||
|
|
||||||
|
List.push_back(Item(Item::Install,Pkg,File));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DPkgPM::Configure - Configure a package /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Add a configure operation to the sequence list */
|
||||||
|
bool pkgDPkgPM::Configure(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
if (Pkg.end() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
List.push_back(Item(Item::Configure,Pkg));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DPkgPM::Remove - Remove a package /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Add a remove operation to the sequence list */
|
||||||
|
bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
|
||||||
|
{
|
||||||
|
if (Pkg.end() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Purge == true)
|
||||||
|
List.push_back(Item(Item::Purge,Pkg));
|
||||||
|
else
|
||||||
|
List.push_back(Item(Item::Remove,Pkg));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DPkgPM::RunScripts - Run a set of scripts /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This looks for a list of script sto run from the configuration file,
|
||||||
|
each one is run with system from a forked child. */
|
||||||
|
bool pkgDPkgPM::RunScripts(const char *Cnf)
|
||||||
|
{
|
||||||
|
Configuration::Item const *Opts = _config->Tree(Cnf);
|
||||||
|
if (Opts == 0 || Opts->Child == 0)
|
||||||
|
return true;
|
||||||
|
Opts = Opts->Child;
|
||||||
|
|
||||||
|
// Fork for running the system calls
|
||||||
|
pid_t Child = ExecFork();
|
||||||
|
|
||||||
|
// This is the child
|
||||||
|
if (Child == 0)
|
||||||
|
{
|
||||||
|
if (chdir("/tmp/") != 0)
|
||||||
|
_exit(100);
|
||||||
|
|
||||||
|
unsigned int Count = 1;
|
||||||
|
for (; Opts != 0; Opts = Opts->Next, Count++)
|
||||||
|
{
|
||||||
|
if (Opts->Value.empty() == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (system(Opts->Value.c_str()) != 0)
|
||||||
|
_exit(100+Count);
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the child
|
||||||
|
int Status = 0;
|
||||||
|
while (waitpid(Child,&Status,0) != Child)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
return _error->Errno("waitpid","Couldn't wait for subprocess");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore sig int/quit
|
||||||
|
signal(SIGQUIT,SIG_DFL);
|
||||||
|
signal(SIGINT,SIG_DFL);
|
||||||
|
|
||||||
|
// Check for an error code.
|
||||||
|
if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
|
||||||
|
{
|
||||||
|
unsigned int Count = WEXITSTATUS(Status);
|
||||||
|
if (Count > 100)
|
||||||
|
{
|
||||||
|
Count -= 100;
|
||||||
|
for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
|
||||||
|
_error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return _error->Error("Sub-process returned an error code");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
// DPkgPM::RunScriptsWithPkgs - Run scripts with package names on stdin /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This looks for a list of scripts to run from the configuration file
|
||||||
|
each one is run and is fed on standard input a list of all .deb files
|
||||||
|
that are due to be installed. */
|
||||||
|
bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
|
||||||
|
{
|
||||||
|
Configuration::Item const *Opts = _config->Tree(Cnf);
|
||||||
|
if (Opts == 0 || Opts->Child == 0)
|
||||||
|
return true;
|
||||||
|
Opts = Opts->Child;
|
||||||
|
|
||||||
|
unsigned int Count = 1;
|
||||||
|
for (; Opts != 0; Opts = Opts->Next, Count++)
|
||||||
|
{
|
||||||
|
if (Opts->Value.empty() == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Create the pipes
|
||||||
|
int Pipes[2];
|
||||||
|
if (pipe(Pipes) != 0)
|
||||||
|
return _error->Errno("pipe","Failed to create IPC pipe to subprocess");
|
||||||
|
SetCloseExec(Pipes[0],true);
|
||||||
|
SetCloseExec(Pipes[1],true);
|
||||||
|
|
||||||
|
// Purified Fork for running the script
|
||||||
|
pid_t Process = ExecFork();
|
||||||
|
if (Process == 0)
|
||||||
|
{
|
||||||
|
// Setup the FDs
|
||||||
|
dup2(Pipes[0],STDIN_FILENO);
|
||||||
|
SetCloseExec(STDOUT_FILENO,false);
|
||||||
|
SetCloseExec(STDIN_FILENO,false);
|
||||||
|
SetCloseExec(STDERR_FILENO,false);
|
||||||
|
|
||||||
|
const char *Args[4];
|
||||||
|
Args[0] = "/bin/sh";
|
||||||
|
Args[1] = "-c";
|
||||||
|
Args[2] = Opts->Value.c_str();
|
||||||
|
Args[3] = 0;
|
||||||
|
execv(Args[0],(char **)Args);
|
||||||
|
_exit(100);
|
||||||
|
}
|
||||||
|
close(Pipes[0]);
|
||||||
|
FileFd Fd(Pipes[1]);
|
||||||
|
|
||||||
|
// Feed it the filenames.
|
||||||
|
for (vector<Item>::iterator I = List.begin(); I != List.end(); I++)
|
||||||
|
{
|
||||||
|
// Only deal with packages to be installed from .deb
|
||||||
|
if (I->Op != Item::Install)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// No errors here..
|
||||||
|
if (I->File[0] != '/')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Feed the filename of each package that is pending install
|
||||||
|
into the pipe. */
|
||||||
|
if (Fd.Write(I->File.begin(),I->File.length()) == false ||
|
||||||
|
Fd.Write("\n",1) == false)
|
||||||
|
{
|
||||||
|
kill(Process,SIGINT);
|
||||||
|
Fd.Close();
|
||||||
|
ExecWait(Process,Opts->Value.c_str(),true);
|
||||||
|
return _error->Error("Failure running script %s",Opts->Value.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fd.Close();
|
||||||
|
|
||||||
|
// Clean up the sub process
|
||||||
|
if (ExecWait(Process,Opts->Value.c_str()) == false)
|
||||||
|
return _error->Error("Failure running script %s",Opts->Value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
// DPkgPM::Go - Run the sequence /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This globs the operations and calls dpkg */
|
||||||
|
bool pkgDPkgPM::Go()
|
||||||
|
{
|
||||||
|
if (RunScripts("DPkg::Pre-Invoke") == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (vector<Item>::iterator I = List.begin(); I != List.end();)
|
||||||
|
{
|
||||||
|
vector<Item>::iterator J = I;
|
||||||
|
for (; J != List.end() && J->Op == I->Op; J++);
|
||||||
|
|
||||||
|
// Generate the argument list
|
||||||
|
const char *Args[400];
|
||||||
|
if (J - I > 350)
|
||||||
|
J = I + 350;
|
||||||
|
|
||||||
|
unsigned int n = 0;
|
||||||
|
unsigned long Size = 0;
|
||||||
|
Args[n++] = _config->Find("Dir::Bin::dpkg","dpkg").c_str();
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
|
||||||
|
// Stick in any custom dpkg options
|
||||||
|
Configuration::Item const *Opts = _config->Tree("DPkg::Options");
|
||||||
|
if (Opts != 0)
|
||||||
|
{
|
||||||
|
Opts = Opts->Child;
|
||||||
|
for (; Opts != 0; Opts = Opts->Next)
|
||||||
|
{
|
||||||
|
if (Opts->Value.empty() == true)
|
||||||
|
continue;
|
||||||
|
Args[n++] = Opts->Value.c_str();
|
||||||
|
Size += Opts->Value.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (I->Op)
|
||||||
|
{
|
||||||
|
case Item::Remove:
|
||||||
|
Args[n++] = "--force-depends";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
Args[n++] = "--force-remove-essential";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
Args[n++] = "--remove";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Item::Purge:
|
||||||
|
Args[n++] = "--force-depends";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
Args[n++] = "--force-remove-essential";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
Args[n++] = "--purge";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Item::Configure:
|
||||||
|
Args[n++] = "--configure";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Item::Install:
|
||||||
|
Args[n++] = "--unpack";
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write in the file or package names
|
||||||
|
if (I->Op == Item::Install)
|
||||||
|
{
|
||||||
|
for (;I != J && Size < 1024; I++)
|
||||||
|
{
|
||||||
|
if (I->File[0] != '/')
|
||||||
|
return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
|
||||||
|
Args[n++] = I->File.c_str();
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (;I != J && Size < 1024; I++)
|
||||||
|
{
|
||||||
|
Args[n++] = I->Pkg.Name();
|
||||||
|
Size += strlen(Args[n-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Args[n] = 0;
|
||||||
|
J = I;
|
||||||
|
|
||||||
|
if (_config->FindB("Debug::pkgDPkgPM",false) == true)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k != n; k++)
|
||||||
|
clog << Args[k] << ' ';
|
||||||
|
clog << endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << flush;
|
||||||
|
clog << flush;
|
||||||
|
cerr << flush;
|
||||||
|
|
||||||
|
/* Mask off sig int/quit. We do this because dpkg also does when
|
||||||
|
it forks scripts. What happens is that when you hit ctrl-c it sends
|
||||||
|
it to all processes in the group. Since dpkg ignores the signal
|
||||||
|
it doesn't die but we do! So we must also ignore it */
|
||||||
|
signal(SIGQUIT,SIG_IGN);
|
||||||
|
signal(SIGINT,SIG_IGN);
|
||||||
|
|
||||||
|
// Fork dpkg
|
||||||
|
pid_t Child = ExecFork();
|
||||||
|
|
||||||
|
// This is the child
|
||||||
|
if (Child == 0)
|
||||||
|
{
|
||||||
|
if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
|
||||||
|
_exit(100);
|
||||||
|
|
||||||
|
if (_config->FindB("DPkg::FlushSTDIN",true) == true)
|
||||||
|
{
|
||||||
|
int Flags,dummy;
|
||||||
|
if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
|
||||||
|
_exit(100);
|
||||||
|
|
||||||
|
// Discard everything in stdin before forking dpkg
|
||||||
|
if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
|
||||||
|
_exit(100);
|
||||||
|
|
||||||
|
while (read(STDIN_FILENO,&dummy,1) == 1);
|
||||||
|
|
||||||
|
if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
|
||||||
|
_exit(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No Job Control Stop Env is a magic dpkg var that prevents it
|
||||||
|
from using sigstop */
|
||||||
|
putenv("DPKG_NO_TSTP=yes");
|
||||||
|
execvp(Args[0],(char **)Args);
|
||||||
|
cerr << "Could not exec dpkg!" << endl;
|
||||||
|
_exit(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for dpkg
|
||||||
|
int Status = 0;
|
||||||
|
while (waitpid(Child,&Status,0) != Child)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
RunScripts("DPkg::Post-Invoke");
|
||||||
|
return _error->Errno("waitpid","Couldn't wait for subprocess");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore sig int/quit
|
||||||
|
signal(SIGQUIT,SIG_DFL);
|
||||||
|
signal(SIGINT,SIG_DFL);
|
||||||
|
|
||||||
|
// Check for an error code.
|
||||||
|
if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
|
||||||
|
{
|
||||||
|
RunScripts("DPkg::Post-Invoke");
|
||||||
|
if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
|
||||||
|
return _error->Error("Sub-process %s recieved a segmentation fault.",Args[0]);
|
||||||
|
|
||||||
|
if (WIFEXITED(Status) != 0)
|
||||||
|
return _error->Error("Sub-process %s returned an error code (%u)",Args[0],WEXITSTATUS(Status));
|
||||||
|
|
||||||
|
return _error->Error("Sub-process %s exited unexpectedly",Args[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RunScripts("DPkg::Post-Invoke") == false)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// pkgDpkgPM::Reset - Dump the contents of the command list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgDPkgPM::Reset()
|
||||||
|
{
|
||||||
|
List.erase(List.begin(),List.end());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
53
apt/apt-pkg/deb/dpkgpm.h
Normal file
53
apt/apt-pkg/deb/dpkgpm.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: dpkgpm.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
DPKG Package Manager - Provide an interface to dpkg
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
#ifndef PKGLIB_DPKGPM_H
|
||||||
|
#define PKGLIB_DPKGPM_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/dpkgpm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/packagemanager.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class pkgDPkgPM : public pkgPackageManager
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct Item
|
||||||
|
{
|
||||||
|
enum Ops {Install, Configure, Remove, Purge} Op;
|
||||||
|
string File;
|
||||||
|
PkgIterator Pkg;
|
||||||
|
Item(Ops Op,PkgIterator Pkg,string File = "") : Op(Op),
|
||||||
|
File(File), Pkg(Pkg) {};
|
||||||
|
Item() {};
|
||||||
|
|
||||||
|
};
|
||||||
|
vector<Item> List;
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
bool RunScripts(const char *Cnf);
|
||||||
|
bool RunScriptsWithPkgs(const char *Cnf);
|
||||||
|
|
||||||
|
// The Actuall installation implementation
|
||||||
|
virtual bool Install(PkgIterator Pkg,string File);
|
||||||
|
virtual bool Configure(PkgIterator Pkg);
|
||||||
|
virtual bool Remove(PkgIterator Pkg,bool Purge = false);
|
||||||
|
virtual bool Go();
|
||||||
|
virtual void Reset();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
pkgDPkgPM(pkgDepCache &Cache);
|
||||||
|
virtual ~pkgDPkgPM();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
941
apt/apt-pkg/depcache.cc
Normal file
941
apt/apt-pkg/depcache.cc
Normal file
@ -0,0 +1,941 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: depcache.cc,v 1.20 2001/11/13 17:32:07 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Dependency Cache - Caches Dependency information.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/depcache.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/depcache.h>
|
||||||
|
#include <apt-pkg/systemfactory.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/sptr.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// DepCache::pkgDepCache - Constructors /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgDepCache::pkgDepCache(MMap &Map,OpProgress &Prog) :
|
||||||
|
pkgCache(Map), PkgState(0), DepState(0)
|
||||||
|
{
|
||||||
|
if (_error->PendingError() == false)
|
||||||
|
Init(&Prog);
|
||||||
|
}
|
||||||
|
pkgDepCache::pkgDepCache(MMap &Map) :
|
||||||
|
pkgCache(Map), PkgState(0), DepState(0)
|
||||||
|
{
|
||||||
|
if (_error->PendingError() == false)
|
||||||
|
Init(0);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::~pkgDepCache - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgDepCache::~pkgDepCache()
|
||||||
|
{
|
||||||
|
delete [] PkgState;
|
||||||
|
delete [] DepState;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::Init - Generate the initial extra structures. /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This allocats the extension buffers and initializes them. */
|
||||||
|
bool pkgDepCache::Init(OpProgress *Prog)
|
||||||
|
{
|
||||||
|
delete [] PkgState;
|
||||||
|
delete [] DepState;
|
||||||
|
PkgState = new StateCache[Head().PackageCount];
|
||||||
|
DepState = new unsigned char[Head().DependsCount];
|
||||||
|
memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
|
||||||
|
memset(DepState,0,sizeof(*DepState)*Head().DependsCount);
|
||||||
|
|
||||||
|
if (Prog != 0)
|
||||||
|
{
|
||||||
|
Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount,
|
||||||
|
_("Building Dependency Tree"));
|
||||||
|
Prog->SubProgress(Head().PackageCount,_("Candidate Versions"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the current state of everything. In this state all of the
|
||||||
|
packages are kept exactly as is. See AllUpgrade */
|
||||||
|
int Done = 0;
|
||||||
|
for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
|
||||||
|
{
|
||||||
|
if (Prog != 0)
|
||||||
|
Prog->Progress(Done);
|
||||||
|
|
||||||
|
// Find the proper cache slot
|
||||||
|
StateCache &State = PkgState[I->ID];
|
||||||
|
State.iFlags = 0;
|
||||||
|
|
||||||
|
// Figure out the install version
|
||||||
|
State.CandidateVer = GetCandidateVer(I);
|
||||||
|
State.InstallVer = I.CurrentVer();
|
||||||
|
State.Mode = ModeKeep;
|
||||||
|
|
||||||
|
State.Update(I,*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Prog != 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
|
||||||
|
Head().PackageCount,
|
||||||
|
_("Building Dependency Tree"));
|
||||||
|
Prog->SubProgress(Head().PackageCount,_("Dependency Generation"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Update(Prog);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::GetCandidateVer - Returns the Candidate install version /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The default just returns the target version if it exists or the
|
||||||
|
highest version. */
|
||||||
|
pkgDepCache::VerIterator pkgDepCache::GetCandidateVer(PkgIterator Pkg,
|
||||||
|
bool AllowCurrent)
|
||||||
|
{
|
||||||
|
// Try to use an explicit target
|
||||||
|
if (Pkg->TargetVer == 0 ||
|
||||||
|
(AllowCurrent == false && Pkg.TargetVer() == Pkg.CurrentVer()))
|
||||||
|
return pkgCache::GetCandidateVer(Pkg,AllowCurrent);
|
||||||
|
else
|
||||||
|
return Pkg.TargetVer();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::IsImportantDep - True if the dependency is important /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgDepCache::IsImportantDep(DepIterator Dep)
|
||||||
|
{
|
||||||
|
return Dep.IsCritical();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// DepCache::CheckDep - Checks a single dependency /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This first checks the dependency against the main target package and
|
||||||
|
then walks along the package provides list and checks if each provides
|
||||||
|
will be installed then checks the provides against the dep. Res will be
|
||||||
|
set to the package which was used to satisfy the dep. */
|
||||||
|
bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
|
||||||
|
{
|
||||||
|
Res = Dep.TargetPkg();
|
||||||
|
|
||||||
|
/* Check simple depends. A depends -should- never self match but
|
||||||
|
we allow it anyhow because dpkg does. Technically it is a packaging
|
||||||
|
bug. Conflicts may never self match */
|
||||||
|
if (Dep.TargetPkg() != Dep.ParentPkg()
|
||||||
|
|| (Dep->Type != Dep::Conflicts
|
||||||
|
&& Dep->Type != Dep::Obsoletes))
|
||||||
|
{
|
||||||
|
PkgIterator Pkg = Dep.TargetPkg();
|
||||||
|
|
||||||
|
// Check the base package
|
||||||
|
if (Type == NowVersion && Pkg->CurrentVer != 0)
|
||||||
|
if (_system->checkDep(Dep.TargetVer(),
|
||||||
|
Pkg.CurrentVer().VerStr(),Dep->CompareOp) == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0)
|
||||||
|
if (_system->checkDep(Dep.TargetVer(),
|
||||||
|
PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
|
||||||
|
Dep->CompareOp) == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0)
|
||||||
|
if (_system->checkDep(Dep.TargetVer(),
|
||||||
|
PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
|
||||||
|
Dep->CompareOp) == true)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Dep->Type == Dep::Obsoletes)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check the providing packages
|
||||||
|
PrvIterator P = Dep.TargetPkg().ProvidesList();
|
||||||
|
PkgIterator Pkg = Dep.ParentPkg();
|
||||||
|
|
||||||
|
for (; P.end() != true; P++)
|
||||||
|
{
|
||||||
|
/* Provides may never be applied against the same package if it is
|
||||||
|
a conflicts. See the comment above. */
|
||||||
|
if (P.OwnerPkg() == Pkg && Dep->Type == Dep::Conflicts)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if the provides is a hit
|
||||||
|
if (Type == NowVersion)
|
||||||
|
{
|
||||||
|
if (P.OwnerPkg().CurrentVer() != P.OwnerVer())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Type == InstallVersion)
|
||||||
|
{
|
||||||
|
StateCache &State = PkgState[P.OwnerPkg()->ID];
|
||||||
|
if (State.InstallVer != (Version *)P.OwnerVer())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Type == CandidateVersion)
|
||||||
|
{
|
||||||
|
StateCache &State = PkgState[P.OwnerPkg()->ID];
|
||||||
|
if (State.CandidateVer != (Version *)P.OwnerVer())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the versions.
|
||||||
|
if (_system->checkDep(Dep.TargetVer(),P.ProvideVersion(),Dep->CompareOp) == true)
|
||||||
|
{
|
||||||
|
Res = P.OwnerPkg();
|
||||||
|
/*
|
||||||
|
if (Dep->Type == Dep::Conflicts)
|
||||||
|
cout << "MATCH: " << Res.Name() << "::"<<P.ProvideVersion()
|
||||||
|
<<"::"<<P.OwnerVer().VerStr()<<endl;
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Call with Mult = -1 to preform the inverse opration */
|
||||||
|
void pkgDepCache::AddSizes(const PkgIterator &Pkg,long Mult)
|
||||||
|
{
|
||||||
|
StateCache &P = PkgState[Pkg->ID];
|
||||||
|
|
||||||
|
if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
|
||||||
|
P.Keep() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Compute the size data
|
||||||
|
if (P.NewInstall() == true)
|
||||||
|
{
|
||||||
|
iUsrSize += Mult*P.InstVerIter(*this)->InstalledSize;
|
||||||
|
iDownloadSize += Mult*P.InstVerIter(*this)->Size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrading
|
||||||
|
if (Pkg->CurrentVer != 0 &&
|
||||||
|
(P.InstallVer != (Version *)Pkg.CurrentVer() ||
|
||||||
|
(P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
|
||||||
|
{
|
||||||
|
iUsrSize += Mult*((signed)P.InstVerIter(*this)->InstalledSize -
|
||||||
|
(signed)Pkg.CurrentVer()->InstalledSize);
|
||||||
|
iDownloadSize += Mult*P.InstVerIter(*this)->Size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinstall
|
||||||
|
if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
|
||||||
|
P.Delete() == false)
|
||||||
|
{
|
||||||
|
iDownloadSize += Mult*P.InstVerIter(*this)->Size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removing
|
||||||
|
if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
|
||||||
|
{
|
||||||
|
iUsrSize -= Mult*Pkg.CurrentVer()->InstalledSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::AddStates - Add the package to the state counter /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This routine is tricky to use, you must make sure that it is never
|
||||||
|
called twice for the same package. This means the Remove/Add section
|
||||||
|
should be as short as possible and not encompass any code that will
|
||||||
|
calld Remove/Add itself. Remember, dependencies can be circular so
|
||||||
|
while processing a dep for Pkg it is possible that Add/Remove
|
||||||
|
will be called on Pkg */
|
||||||
|
void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add)
|
||||||
|
{
|
||||||
|
StateCache &State = PkgState[Pkg->ID];
|
||||||
|
|
||||||
|
// The Package is broken
|
||||||
|
if ((State.DepState & DepInstMin) != DepInstMin)
|
||||||
|
iBrokenCount += Add;
|
||||||
|
|
||||||
|
// Bad state
|
||||||
|
if (Pkg.State() != PkgIterator::NeedsNothing)
|
||||||
|
iBadCount += Add;
|
||||||
|
|
||||||
|
// Not installed
|
||||||
|
if (Pkg->CurrentVer == 0)
|
||||||
|
{
|
||||||
|
if (State.Mode == ModeDelete &&
|
||||||
|
(State.iFlags | Purge) == Purge && Pkg.Purge() == false)
|
||||||
|
iDelCount += Add;
|
||||||
|
|
||||||
|
if (State.Mode == ModeInstall)
|
||||||
|
iInstCount += Add;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Installed, no upgrade
|
||||||
|
if (State.Upgradable() == false)
|
||||||
|
{
|
||||||
|
if (State.Mode == ModeDelete)
|
||||||
|
iDelCount += Add;
|
||||||
|
else
|
||||||
|
if ((State.iFlags & ReInstall) == ReInstall)
|
||||||
|
iInstCount += Add;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alll 3 are possible
|
||||||
|
if (State.Mode == ModeDelete)
|
||||||
|
iDelCount += Add;
|
||||||
|
if (State.Mode == ModeKeep)
|
||||||
|
iKeepCount += Add;
|
||||||
|
if (State.Mode == ModeInstall)
|
||||||
|
iInstCount += Add;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::BuildGroupOrs - Generate the Or group dep data /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The or group results are stored in the last item of the or group. This
|
||||||
|
allows easy detection of the state of a whole or'd group. */
|
||||||
|
void pkgDepCache::BuildGroupOrs(VerIterator const &V)
|
||||||
|
{
|
||||||
|
unsigned char Group = 0;
|
||||||
|
|
||||||
|
for (DepIterator D = V.DependsList(); D.end() != true; D++)
|
||||||
|
{
|
||||||
|
// Build the dependency state.
|
||||||
|
unsigned char &State = DepState[D->ID];
|
||||||
|
|
||||||
|
/* Invert for Conflicts. We have to do this twice to get the
|
||||||
|
right sense for a conflicts group */
|
||||||
|
if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
|
||||||
|
State = ~State;
|
||||||
|
|
||||||
|
// Add to the group if we are within an or..
|
||||||
|
State &= 0x7;
|
||||||
|
Group |= State;
|
||||||
|
State |= Group << 3;
|
||||||
|
if ((D->CompareOp & Dep::Or) != Dep::Or)
|
||||||
|
Group = 0;
|
||||||
|
|
||||||
|
// Invert for Conflicts
|
||||||
|
if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
|
||||||
|
State = ~State;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::VersionState - Perform a pass over a dependency list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is used to run over a dependency list and determine the dep
|
||||||
|
state of the list, filtering it through both a Min check and a Policy
|
||||||
|
check. The return result will have SetMin/SetPolicy low if a check
|
||||||
|
fails. It uses the DepState cache for it's computations. */
|
||||||
|
unsigned char pkgDepCache::VersionState(DepIterator D,unsigned char Check,
|
||||||
|
unsigned char SetMin,
|
||||||
|
unsigned char SetPolicy)
|
||||||
|
{
|
||||||
|
unsigned char Dep = 0xFF;
|
||||||
|
|
||||||
|
while (D.end() != true)
|
||||||
|
{
|
||||||
|
// Compute a single dependency element (glob or)
|
||||||
|
DepIterator Start = D;
|
||||||
|
unsigned char State = 0;
|
||||||
|
for (bool LastOR = true; D.end() == false && LastOR == true; D++)
|
||||||
|
{
|
||||||
|
State |= DepState[D->ID];
|
||||||
|
LastOR = (D->CompareOp & Dep::Or) == Dep::Or;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimum deps that must be satisfied to have a working package
|
||||||
|
if (Start.IsCritical() == true)
|
||||||
|
if ((State & Check) != Check)
|
||||||
|
Dep &= ~SetMin;
|
||||||
|
|
||||||
|
// Policy deps that must be satisfied to install the package
|
||||||
|
if (IsImportantDep(Start) == true &&
|
||||||
|
(State & Check) != Check)
|
||||||
|
Dep &= ~SetPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Dep;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::DependencyState - Compute the 3 results for a dep /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is the main dependency computation bit. It computes the 3 main
|
||||||
|
results for a dependencys, Now, Install and Candidate. Callers must
|
||||||
|
invert the result if dealing with conflicts. */
|
||||||
|
unsigned char pkgDepCache::DependencyState(DepIterator &D)
|
||||||
|
{
|
||||||
|
unsigned char State = 0;
|
||||||
|
|
||||||
|
if (CheckDep(D,NowVersion) == true)
|
||||||
|
State |= DepNow;
|
||||||
|
if (CheckDep(D,InstallVersion) == true)
|
||||||
|
State |= DepInstall;
|
||||||
|
if (CheckDep(D,CandidateVersion) == true)
|
||||||
|
State |= DepCVer;
|
||||||
|
|
||||||
|
return State;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::UpdateVerState - Compute the Dep member of the state /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This determines the combined dependency representation of a package
|
||||||
|
for its two states now and install. This is done by using the pre-generated
|
||||||
|
dependency information. */
|
||||||
|
void pkgDepCache::UpdateVerState(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
// Empty deps are always true
|
||||||
|
StateCache &State = PkgState[Pkg->ID];
|
||||||
|
State.DepState = 0xFF;
|
||||||
|
|
||||||
|
// Check the Current state
|
||||||
|
if (Pkg->CurrentVer != 0)
|
||||||
|
{
|
||||||
|
DepIterator D = Pkg.CurrentVer().DependsList();
|
||||||
|
State.DepState &= VersionState(D,DepNow,DepNowMin,DepNowPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the candidate state. We do not compare against the whole as
|
||||||
|
a candidate state but check the candidate version against the
|
||||||
|
install states */
|
||||||
|
if (State.CandidateVer != 0)
|
||||||
|
{
|
||||||
|
DepIterator D = State.CandidateVerIter(*this).DependsList();
|
||||||
|
State.DepState &= VersionState(D,DepInstall,DepCandMin,DepCandPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check target state which can only be current or installed
|
||||||
|
if (State.InstallVer != 0)
|
||||||
|
{
|
||||||
|
DepIterator D = State.InstVerIter(*this).DependsList();
|
||||||
|
State.DepState &= VersionState(D,DepInstall,DepInstMin,DepInstPolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::Update - Figure out all the state information /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This will figure out the state of all the packages and all the
|
||||||
|
dependencies based on the current policy. */
|
||||||
|
void pkgDepCache::Update(OpProgress *Prog)
|
||||||
|
{
|
||||||
|
iUsrSize = 0;
|
||||||
|
iDownloadSize = 0;
|
||||||
|
iDelCount = 0;
|
||||||
|
iInstCount = 0;
|
||||||
|
iKeepCount = 0;
|
||||||
|
iBrokenCount = 0;
|
||||||
|
iBadCount = 0;
|
||||||
|
|
||||||
|
// Perform the depends pass
|
||||||
|
int Done = 0;
|
||||||
|
for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
|
||||||
|
{
|
||||||
|
if (Prog != 0 && Done%20 == 0)
|
||||||
|
Prog->Progress(Done);
|
||||||
|
for (VerIterator V = I.VersionList(); V.end() != true; V++)
|
||||||
|
{
|
||||||
|
unsigned char Group = 0;
|
||||||
|
|
||||||
|
for (DepIterator D = V.DependsList(); D.end() != true; D++)
|
||||||
|
{
|
||||||
|
// Build the dependency state.
|
||||||
|
unsigned char &State = DepState[D->ID];
|
||||||
|
State = DependencyState(D);;
|
||||||
|
|
||||||
|
// Add to the group if we are within an or..
|
||||||
|
Group |= State;
|
||||||
|
State |= Group << 3;
|
||||||
|
if ((D->CompareOp & Dep::Or) != Dep::Or)
|
||||||
|
Group = 0;
|
||||||
|
|
||||||
|
// Invert for Conflicts
|
||||||
|
if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
|
||||||
|
State = ~State;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the pacakge dependency state and size additions
|
||||||
|
AddSizes(I);
|
||||||
|
UpdateVerState(I);
|
||||||
|
AddStates(I);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Prog != 0)
|
||||||
|
Prog->Progress(Done);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::Update - Update the deps list of a package /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is a helper for update that only does the dep portion of the scan.
|
||||||
|
It is mainly ment to scan reverse dependencies. */
|
||||||
|
void pkgDepCache::Update(DepIterator D)
|
||||||
|
{
|
||||||
|
// Update the reverse deps
|
||||||
|
for (;D.end() != true; D++)
|
||||||
|
{
|
||||||
|
unsigned char &State = DepState[D->ID];
|
||||||
|
State = DependencyState(D);
|
||||||
|
|
||||||
|
// Invert for Conflicts
|
||||||
|
if (D->Type == Dep::Conflicts || D->Type == Dep::Obsoletes)
|
||||||
|
State = ~State;
|
||||||
|
|
||||||
|
RemoveStates(D.ParentPkg());
|
||||||
|
BuildGroupOrs(D.ParentVer());
|
||||||
|
UpdateVerState(D.ParentPkg());
|
||||||
|
AddStates(D.ParentPkg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::Update - Update the related deps of a package /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called whenever the state of a package changes. It updates
|
||||||
|
all cached dependencies related to this package. */
|
||||||
|
void pkgDepCache::Update(PkgIterator const &Pkg)
|
||||||
|
{
|
||||||
|
// Recompute the dep of the package
|
||||||
|
RemoveStates(Pkg);
|
||||||
|
UpdateVerState(Pkg);
|
||||||
|
AddStates(Pkg);
|
||||||
|
|
||||||
|
// Update the reverse deps
|
||||||
|
Update(Pkg.RevDependsList());
|
||||||
|
|
||||||
|
// Update the provides map for the current ver
|
||||||
|
if (Pkg->CurrentVer != 0)
|
||||||
|
for (PrvIterator P = Pkg.CurrentVer().ProvidesList();
|
||||||
|
P.end() != true; P++)
|
||||||
|
Update(P.ParentPkg().RevDependsList());
|
||||||
|
|
||||||
|
// Update the provides map for the candidate ver
|
||||||
|
if (PkgState[Pkg->ID].CandidateVer != 0)
|
||||||
|
for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList();
|
||||||
|
P.end() != true; P++)
|
||||||
|
Update(P.ParentPkg().RevDependsList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// DepCache::MarkKeep - Put the package in the keep state /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgDepCache::MarkKeep(PkgIterator const &Pkg,bool Soft)
|
||||||
|
{
|
||||||
|
// Simplifies other routines.
|
||||||
|
if (Pkg.end() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Reject an attempt to keep a non-source broken installed package, those
|
||||||
|
must be upgraded */
|
||||||
|
if (Pkg.State() == PkgIterator::NeedsUnpack &&
|
||||||
|
Pkg.CurrentVer().Downloadable() == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* We changed the soft state all the time so the UI is a bit nicer
|
||||||
|
to use */
|
||||||
|
StateCache &P = PkgState[Pkg->ID];
|
||||||
|
if (Soft == true)
|
||||||
|
P.iFlags |= AutoKept;
|
||||||
|
else
|
||||||
|
P.iFlags &= ~AutoKept;
|
||||||
|
|
||||||
|
// Check that it is not already kept
|
||||||
|
if (P.Mode == ModeKeep)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We dont even try to keep virtual packages..
|
||||||
|
if (Pkg->VersionList == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
P.Flags &= ~Flag::Auto;
|
||||||
|
RemoveSizes(Pkg);
|
||||||
|
RemoveStates(Pkg);
|
||||||
|
|
||||||
|
P.Mode = ModeKeep;
|
||||||
|
if (Pkg->CurrentVer == 0)
|
||||||
|
P.InstallVer = 0;
|
||||||
|
else
|
||||||
|
P.InstallVer = Pkg.CurrentVer();
|
||||||
|
|
||||||
|
AddStates(Pkg);
|
||||||
|
|
||||||
|
Update(Pkg);
|
||||||
|
|
||||||
|
AddSizes(Pkg);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepCache::MarkDelete - Put the package in the delete state /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool fReplace, bool rPurge)
|
||||||
|
{
|
||||||
|
// Simplifies other routines.
|
||||||
|
if (Pkg.end() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check that it is not already marked for delete
|
||||||
|
StateCache &P = PkgState[Pkg->ID];
|
||||||
|
P.iFlags &= ~(AutoKept | Purge);
|
||||||
|
if ( fReplace ) P.iFlags |= Replaced;
|
||||||
|
if (rPurge == true)
|
||||||
|
P.iFlags |= Purge;
|
||||||
|
|
||||||
|
if ((P.Mode == ModeDelete || P.InstallVer == 0) &&
|
||||||
|
(Pkg.Purge() == true || rPurge == false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We dont even try to delete virtual packages..
|
||||||
|
if (Pkg->VersionList == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RemoveSizes(Pkg);
|
||||||
|
RemoveStates(Pkg);
|
||||||
|
|
||||||
|
if (Pkg->CurrentVer == 0 && (Pkg.Purge() == true || rPurge == false))
|
||||||
|
P.Mode = ModeKeep;
|
||||||
|
else
|
||||||
|
P.Mode = ModeDelete;
|
||||||
|
P.InstallVer = 0;
|
||||||
|
P.Flags &= Flag::Auto;
|
||||||
|
|
||||||
|
AddStates(Pkg);
|
||||||
|
Update(Pkg);
|
||||||
|
AddSizes(Pkg);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
#if 1
|
||||||
|
// DepCache::MarkInstall - Put the package in the install state /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst)
|
||||||
|
{
|
||||||
|
// Simplifies other routines.
|
||||||
|
if (Pkg.end() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Check that it is not already marked for install and that it can be
|
||||||
|
installed */
|
||||||
|
StateCache &P = PkgState[Pkg->ID];
|
||||||
|
P.iFlags &= ~AutoKept;
|
||||||
|
if (P.InstBroken() == false && (P.Mode == ModeInstall ||
|
||||||
|
P.CandidateVer == (Version *)Pkg.CurrentVer()))
|
||||||
|
{
|
||||||
|
if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
|
||||||
|
MarkKeep(Pkg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We dont even try to install virtual packages..
|
||||||
|
if (Pkg->VersionList == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Target the candidate version and remove the autoflag. We reset the
|
||||||
|
autoflag below if this was called recursively. Otherwise the user
|
||||||
|
should have the ability to de-auto a package by changing its state */
|
||||||
|
RemoveSizes(Pkg);
|
||||||
|
RemoveStates(Pkg);
|
||||||
|
|
||||||
|
P.Mode = ModeInstall;
|
||||||
|
P.InstallVer = P.CandidateVer;
|
||||||
|
P.Flags &= ~Flag::Auto;
|
||||||
|
if (P.CandidateVer == (Version *)Pkg.CurrentVer())
|
||||||
|
P.Mode = ModeKeep;
|
||||||
|
|
||||||
|
AddStates(Pkg);
|
||||||
|
Update(Pkg);
|
||||||
|
AddSizes(Pkg);
|
||||||
|
|
||||||
|
|
||||||
|
if (AutoInst == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DepIterator Dep = P.InstVerIter(*this).DependsList();
|
||||||
|
for (; Dep.end() != true;)
|
||||||
|
{
|
||||||
|
// Grok or groups
|
||||||
|
DepIterator Start = Dep;
|
||||||
|
bool Result = true;
|
||||||
|
for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++)
|
||||||
|
{
|
||||||
|
LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
|
||||||
|
|
||||||
|
if ((DepState[Dep->ID] & DepInstall) == DepInstall)
|
||||||
|
Result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dep is satisfied okay.
|
||||||
|
if (Result == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this dep should be consider for install. If it is a user
|
||||||
|
defined important dep and we are installed a new package then
|
||||||
|
it will be installed. Otherwise we only worry about critical deps */
|
||||||
|
if (IsImportantDep(Start) == false)
|
||||||
|
continue;
|
||||||
|
if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Now we have to take action...
|
||||||
|
PkgIterator P = Start.SmartTargetPkg();
|
||||||
|
if ((DepState[Start->ID] & DepCVer) == DepCVer)
|
||||||
|
{
|
||||||
|
MarkInstall(P,true);
|
||||||
|
|
||||||
|
// Set the autoflag, after MarkInstall because MarkInstall unsets it
|
||||||
|
if (P->CurrentVer == 0)
|
||||||
|
PkgState[P->ID].Flags |= Flag::Auto;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For conflicts we just de-install the package and mark as auto
|
||||||
|
if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes)
|
||||||
|
{
|
||||||
|
Version **List = Start.AllTargets();
|
||||||
|
for (Version **I = List; *I != 0; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(*this,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
MarkDelete(Pkg, Start->Type == Dep::Obsoletes);
|
||||||
|
PkgState[Pkg->ID].Flags |= Flag::Auto;
|
||||||
|
}
|
||||||
|
delete [] List;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
#else
|
||||||
|
// DepCache::MarkInstall - Put the package in the install state /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
|
||||||
|
unsigned long Depth)
|
||||||
|
{
|
||||||
|
if (Depth > 100)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Simplifies other routines.
|
||||||
|
if (Pkg.end() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Check that it is not already marked for install and that it can be
|
||||||
|
installed */
|
||||||
|
StateCache &P = PkgState[Pkg->ID];
|
||||||
|
P.iFlags &= ~AutoKept;
|
||||||
|
if (P.InstBroken() == false && (P.Mode == ModeInstall ||
|
||||||
|
P.CandidateVer == (Version *)Pkg.CurrentVer()))
|
||||||
|
{
|
||||||
|
if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
|
||||||
|
MarkKeep(Pkg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if there is even any possible instalation candidate
|
||||||
|
if (P.CandidateVer == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We dont even try to install virtual packages..
|
||||||
|
if (Pkg->VersionList == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Target the candidate version and remove the autoflag. We reset the
|
||||||
|
autoflag below if this was called recursively. Otherwise the user
|
||||||
|
should have the ability to de-auto a package by changing its state */
|
||||||
|
RemoveSizes(Pkg);
|
||||||
|
RemoveStates(Pkg);
|
||||||
|
|
||||||
|
P.Mode = ModeInstall;
|
||||||
|
P.InstallVer = P.CandidateVer;
|
||||||
|
P.Flags &= ~Flag::Auto;
|
||||||
|
if (P.CandidateVer == (Version *)Pkg.CurrentVer())
|
||||||
|
P.Mode = ModeKeep;
|
||||||
|
|
||||||
|
AddStates(Pkg);
|
||||||
|
Update(Pkg);
|
||||||
|
AddSizes(Pkg);
|
||||||
|
|
||||||
|
if (AutoInst == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DepIterator Dep = P.InstVerIter(*this).DependsList();
|
||||||
|
for (; Dep.end() != true;)
|
||||||
|
{
|
||||||
|
// Grok or groups
|
||||||
|
DepIterator Start = Dep;
|
||||||
|
bool Result = true;
|
||||||
|
unsigned Ors = 0;
|
||||||
|
for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++,Ors++)
|
||||||
|
{
|
||||||
|
LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
|
||||||
|
|
||||||
|
if ((DepState[Dep->ID] & DepInstall) == DepInstall)
|
||||||
|
Result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dep is satisfied okay.
|
||||||
|
if (Result == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check if this dep should be consider for install. If it is a user
|
||||||
|
defined important dep and we are installed a new package then
|
||||||
|
it will be installed. Otherwise we only worry about critical deps */
|
||||||
|
if (IsImportantDep(Start) == false)
|
||||||
|
continue;
|
||||||
|
if (Pkg->CurrentVer != 0 && Start.IsCritical() == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If we are in an or group locate the first or that can
|
||||||
|
succeed. We have already cached this.. */
|
||||||
|
for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--)
|
||||||
|
Start++;
|
||||||
|
|
||||||
|
/* This bit is for processing the possibilty of an install/upgrade
|
||||||
|
fixing the problem */
|
||||||
|
SPtrArray<Version *> List = Start.AllTargets();
|
||||||
|
if ((DepState[Start->ID] & DepCVer) == DepCVer)
|
||||||
|
{
|
||||||
|
// Right, find the best version to install..
|
||||||
|
Version **Cur = List;
|
||||||
|
PkgIterator P = Start.TargetPkg();
|
||||||
|
PkgIterator InstPkg(*Cache,0);
|
||||||
|
|
||||||
|
// See if there are direct matches (at the start of the list)
|
||||||
|
for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++)
|
||||||
|
{
|
||||||
|
PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
|
||||||
|
if (PkgState[Pkg->ID].CandidateVer != *Cur)
|
||||||
|
continue;
|
||||||
|
InstPkg = Pkg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the highest priority providing package
|
||||||
|
if (InstPkg.end() == false)
|
||||||
|
{
|
||||||
|
pkgPrioSortList(*Cache,Cur);
|
||||||
|
for (; *Cur != 0; Cur++)
|
||||||
|
{
|
||||||
|
PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
|
||||||
|
if (PkgState[Pkg->ID].CandidateVer != *Cur)
|
||||||
|
continue;
|
||||||
|
InstPkg = Pkg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InstPkg.end() == false)
|
||||||
|
{
|
||||||
|
MarkInstall(InstPkg,true,Depth + 1);
|
||||||
|
|
||||||
|
// Set the autoflag, after MarkInstall because MarkInstall unsets it
|
||||||
|
if (P->CurrentVer == 0)
|
||||||
|
PkgState[InstPkg->ID].Flags |= Flag::Auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For conflicts we just de-install the package and mark as auto,
|
||||||
|
Conflicts may not have or groups */
|
||||||
|
if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes)
|
||||||
|
{
|
||||||
|
for (Version **I = List; *I != 0; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(*this,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
MarkDelete(Pkg, Start->Type == Dep::Obsoletes);
|
||||||
|
PkgState[Pkg->ID].Flags |= Flag::Auto;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
#endif
|
||||||
|
// DepCache::SetReInstall - Set the reinstallation flag /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
|
||||||
|
{
|
||||||
|
RemoveSizes(Pkg);
|
||||||
|
RemoveStates(Pkg);
|
||||||
|
|
||||||
|
StateCache &P = PkgState[Pkg->ID];
|
||||||
|
if (To == true)
|
||||||
|
P.iFlags |= ReInstall;
|
||||||
|
else
|
||||||
|
P.iFlags &= ~ReInstall;
|
||||||
|
|
||||||
|
AddStates(Pkg);
|
||||||
|
AddSizes(Pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateCache::Update - Compute the various static display things /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called whenever the Candidate version changes. */
|
||||||
|
void pkgDepCache::StateCache::Update(PkgIterator Pkg,pkgCache &Cache)
|
||||||
|
{
|
||||||
|
// Some info
|
||||||
|
VerIterator Ver = CandidateVerIter(Cache);
|
||||||
|
|
||||||
|
// Use a null string or the version string
|
||||||
|
if (Ver.end() == true)
|
||||||
|
CandVersion = "";
|
||||||
|
else
|
||||||
|
CandVersion = Ver.VerStr();
|
||||||
|
|
||||||
|
// Find the current version
|
||||||
|
CurVersion = "";
|
||||||
|
if (Pkg->CurrentVer != 0)
|
||||||
|
CurVersion = Pkg.CurrentVer().VerStr();
|
||||||
|
|
||||||
|
// Strip off the epochs for display
|
||||||
|
CurVersion = StripEpoch(CurVersion);
|
||||||
|
CandVersion = StripEpoch(CandVersion);
|
||||||
|
|
||||||
|
// Figure out if its up or down or equal
|
||||||
|
Status = Ver.CompareVer(Pkg.CurrentVer());
|
||||||
|
|
||||||
|
if (Pkg->CurrentVer == 0 || Pkg->VersionList == 0 || CandidateVer == 0) {
|
||||||
|
Status = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// StateCache::StripEpoch - Remove the epoch specifier from the version /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
|
||||||
|
{
|
||||||
|
if (Ver == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Strip any epoch
|
||||||
|
for (const char *I = Ver; *I != 0; I++)
|
||||||
|
if (*I == ':')
|
||||||
|
return I + 1;
|
||||||
|
return Ver;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
187
apt/apt-pkg/depcache.h
Normal file
187
apt/apt-pkg/depcache.h
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: depcache.h,v 1.3 2001/11/13 17:32:07 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
DepCache - Dependency Extension data for the cache
|
||||||
|
|
||||||
|
This class stores the cache data and a set of extension structures for
|
||||||
|
monitoring the current state of all the packages. It also generates and
|
||||||
|
caches the 'install' state of many things. This refers to the state of the
|
||||||
|
package after an install has been run.
|
||||||
|
|
||||||
|
The StateCache::State field can be -1,0,1,2 which is <,=,>,no current.
|
||||||
|
StateCache::Mode is which of the 3 fields is active.
|
||||||
|
|
||||||
|
This structure is important to support the readonly status of the cache
|
||||||
|
file. When the data is saved the cache will be refereshed from our
|
||||||
|
internal rep and written to disk. Then the actual persistant data
|
||||||
|
files will be put on the disk.
|
||||||
|
|
||||||
|
Each dependency is compared against 3 target versions to produce to
|
||||||
|
3 dependency results.
|
||||||
|
Now - Compared using the Currently install version
|
||||||
|
Install - Compared using the install version (final state)
|
||||||
|
CVer - (Candidate Verion) Compared using the Candidate Version
|
||||||
|
The candidate and now results are used to decide wheather a package
|
||||||
|
should be automatically installed or if it should be left alone.
|
||||||
|
|
||||||
|
Remember, the Candidate Version is selected based on the distribution
|
||||||
|
settings for the Package. The Install Version is selected based on the
|
||||||
|
state (Delete, Keep, Install) field and can be either the Current Version
|
||||||
|
or the Candidate version.
|
||||||
|
|
||||||
|
The Candidate version is what is shown the 'Install Version' field.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_DEPCACHE_H
|
||||||
|
#define PKGLIB_DEPCACHE_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/depcache.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/pkgcache.h>
|
||||||
|
#include <apt-pkg/progress.h>
|
||||||
|
|
||||||
|
class pkgDepCache : public pkgCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// These flags are used in DepState
|
||||||
|
enum DepFlags {DepNow = (1 << 0),DepInstall = (1 << 1),DepCVer = (1 << 2),
|
||||||
|
DepGNow = (1 << 3),DepGInstall = (1 << 4),DepGCVer = (1 << 5)};
|
||||||
|
|
||||||
|
// These flags are used in StateCache::DepState
|
||||||
|
enum DepStateFlags {DepNowPolicy = (1 << 0), DepNowMin = (1 << 1),
|
||||||
|
DepInstPolicy = (1 << 2), DepInstMin = (1 << 3),
|
||||||
|
DepCandPolicy = (1 << 4), DepCandMin = (1 << 5)};
|
||||||
|
|
||||||
|
// These flags are used in StateCache::iFlags
|
||||||
|
enum InternalFlags {AutoKept = (1 << 0), Purge = (1 << 1), ReInstall = (1 << 2), Replaced = (1 << 3)};
|
||||||
|
|
||||||
|
enum VersionTypes {NowVersion, InstallVersion, CandidateVersion};
|
||||||
|
enum ModeList {ModeDelete = 0, ModeKeep, ModeInstall};
|
||||||
|
struct StateCache
|
||||||
|
{
|
||||||
|
// Epoch stripped text versions of the two version fields
|
||||||
|
const char *CandVersion;
|
||||||
|
const char *CurVersion;
|
||||||
|
|
||||||
|
// Pointer to the candidate install version.
|
||||||
|
Version *CandidateVer;
|
||||||
|
|
||||||
|
// Pointer to the install version.
|
||||||
|
Version *InstallVer;
|
||||||
|
|
||||||
|
// Various tree indicators
|
||||||
|
signed char Status; // -1,0,1,2
|
||||||
|
unsigned char Mode; // ModeList
|
||||||
|
unsigned char DepState; // DepState Flags
|
||||||
|
|
||||||
|
// Copy of Package::Flags
|
||||||
|
unsigned short Flags;
|
||||||
|
unsigned short iFlags; // Internal flags
|
||||||
|
|
||||||
|
// Update of candidate version
|
||||||
|
const char *StripEpoch(const char *Ver);
|
||||||
|
void Update(PkgIterator Pkg,pkgCache &Cache);
|
||||||
|
|
||||||
|
// Various test members for the current status of the package
|
||||||
|
inline bool NewInstall() const {return Status == 2 && Mode == ModeInstall;};
|
||||||
|
inline bool Delete() const {return Mode == ModeDelete;};
|
||||||
|
inline bool Replaced() const {return iFlags & pkgDepCache::Replaced;};
|
||||||
|
inline bool Keep() const {return Mode == ModeKeep;};
|
||||||
|
inline bool Upgrade() const {return Status > 0 && Mode == ModeInstall;};
|
||||||
|
inline bool Upgradable() const {return Status >= 1;};
|
||||||
|
inline bool Downgrade() const {return Status < 0;};
|
||||||
|
inline bool Held() const {return Status != 0 && Keep();};
|
||||||
|
inline bool NowBroken() const {return (DepState & DepNowMin) != DepNowMin;};
|
||||||
|
inline bool InstBroken() const {return (DepState & DepInstMin) != DepInstMin;};
|
||||||
|
inline bool Install() const {return Mode == ModeInstall;};
|
||||||
|
inline VerIterator InstVerIter(pkgCache &Cache)
|
||||||
|
{return VerIterator(Cache,InstallVer);};
|
||||||
|
inline VerIterator CandidateVerIter(pkgCache &Cache)
|
||||||
|
{return VerIterator(Cache,CandidateVer);};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
void BuildGroupOrs(VerIterator const &V);
|
||||||
|
void UpdateVerState(PkgIterator Pkg);
|
||||||
|
|
||||||
|
bool Init(OpProgress *Prog);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// State information
|
||||||
|
StateCache *PkgState;
|
||||||
|
unsigned char *DepState;
|
||||||
|
|
||||||
|
signed long iUsrSize;
|
||||||
|
unsigned long iDownloadSize;
|
||||||
|
unsigned long iInstCount;
|
||||||
|
unsigned long iDelCount;
|
||||||
|
unsigned long iKeepCount;
|
||||||
|
unsigned long iBrokenCount;
|
||||||
|
unsigned long iBadCount;
|
||||||
|
|
||||||
|
// Check for a matching provides
|
||||||
|
bool CheckDep(DepIterator Dep,int Type,PkgIterator &Res);
|
||||||
|
inline bool CheckDep(DepIterator Dep,int Type)
|
||||||
|
{
|
||||||
|
PkgIterator Res(*this);
|
||||||
|
return CheckDep(Dep,Type,Res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes state information for deps and versions (w/o storing)
|
||||||
|
unsigned char DependencyState(DepIterator &D);
|
||||||
|
unsigned char VersionState(DepIterator D,unsigned char Check,
|
||||||
|
unsigned char SetMin,
|
||||||
|
unsigned char SetPolicy);
|
||||||
|
|
||||||
|
// Recalculates various portions of the cache, call after changing something
|
||||||
|
void Update(DepIterator Dep); // Mostly internal
|
||||||
|
void Update(PkgIterator const &P);
|
||||||
|
|
||||||
|
// Count manipulators
|
||||||
|
void AddSizes(const PkgIterator &Pkg,long Mult = 1);
|
||||||
|
inline void RemoveSizes(const PkgIterator &Pkg) {AddSizes(Pkg,-1);};
|
||||||
|
void AddStates(const PkgIterator &Pkg,int Add = 1);
|
||||||
|
inline void RemoveStates(const PkgIterator &Pkg) {AddStates(Pkg,-1);};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Policy implementation
|
||||||
|
virtual VerIterator GetCandidateVer(PkgIterator Pkg,bool AllowCurrent = true);
|
||||||
|
virtual bool IsImportantDep(DepIterator Dep);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline StateCache &operator [](PkgIterator const &I) {return PkgState[I->ID];};
|
||||||
|
inline unsigned char &operator [](DepIterator const &I) {return DepState[I->ID];};
|
||||||
|
|
||||||
|
// Manipulators
|
||||||
|
void MarkKeep(PkgIterator const &Pkg,bool Soft = false);
|
||||||
|
void MarkDelete(PkgIterator const &Pkg, bool fReplace = false, bool Purge = false);
|
||||||
|
void MarkInstall(PkgIterator const &Pkg,bool AutoInst = true);
|
||||||
|
void SetReInstall(PkgIterator const &Pkg,bool To);
|
||||||
|
|
||||||
|
// This is for debuging
|
||||||
|
void Update(OpProgress *Prog = 0);
|
||||||
|
|
||||||
|
// Size queries
|
||||||
|
inline signed long UsrSize() {return iUsrSize;};
|
||||||
|
inline unsigned long DebSize() {return iDownloadSize;};
|
||||||
|
inline unsigned long DelCount() {return iDelCount;};
|
||||||
|
inline unsigned long KeepCount() {return iKeepCount;};
|
||||||
|
inline unsigned long InstCount() {return iInstCount;};
|
||||||
|
inline unsigned long BrokenCount() {return iBrokenCount;};
|
||||||
|
inline unsigned long BadCount() {return iBadCount;};
|
||||||
|
|
||||||
|
pkgDepCache(MMap &Map,OpProgress &Prog);
|
||||||
|
pkgDepCache(MMap &Map);
|
||||||
|
virtual ~pkgDepCache();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
94
apt/apt-pkg/init.cc
Normal file
94
apt/apt-pkg/init.cc
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: init.cc,v 1.16 2001/08/01 21:35:12 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Init - Initialize the package library
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include files /*{{{*/
|
||||||
|
#include <apt-pkg/init.h>
|
||||||
|
#include <apt-pkg/fileutl.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <config.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
|
||||||
|
// pkgInitialize - Initialize the configuration class /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Directories are specified in such a way that the FindDir function will
|
||||||
|
understand them. That is, if they don't start with a / then their parent
|
||||||
|
is prepended, this allows a fair degree of flexability. */
|
||||||
|
bool pkgInitialize(Configuration &Cnf)
|
||||||
|
{
|
||||||
|
// General APT things
|
||||||
|
Cnf.Set("APT::Architecture",COMMON_CPU);
|
||||||
|
|
||||||
|
// State
|
||||||
|
Cnf.Set("Dir::State","/var/state/apt/");
|
||||||
|
Cnf.Set("Dir::State::lists","lists/");
|
||||||
|
|
||||||
|
/* These really should be jammed into a generic 'Local Database' engine
|
||||||
|
which is yet to be determined. The functions in pkgcachegen should
|
||||||
|
be the only users of these */
|
||||||
|
Cnf.Set("Dir::State::xstatus","xstatus");
|
||||||
|
Cnf.Set("Dir::State::userstatus","status.user");
|
||||||
|
if (0) {//akk
|
||||||
|
Cnf.Set("Dir::State::status","/var/lib/dpkg/status");
|
||||||
|
} else {
|
||||||
|
Cnf.Set("Acquire::cdrom::mount", "/mnt/cdrom");
|
||||||
|
Cnf.Set("RPM::AllowedDupPkgs::","^kernel$");
|
||||||
|
Cnf.Set("RPM::AllowedDupPkgs::", "kernel-smp");
|
||||||
|
Cnf.Set("RPM::AllowedDupPkgs::", "kernel-enterprise");
|
||||||
|
|
||||||
|
Cnf.Set("RPM::HoldPkgs::", "kernel-source");
|
||||||
|
Cnf.Set("RPM::HoldPkgs::", "kernel-headers");
|
||||||
|
|
||||||
|
Cnf.Set("Dir::State::status","/var/lib/rpm/status");
|
||||||
|
}
|
||||||
|
Cnf.Set("Dir::State::cdroms","cdroms.list");
|
||||||
|
|
||||||
|
// Cache
|
||||||
|
Cnf.Set("Dir::Cache","/var/cache/apt/");
|
||||||
|
Cnf.Set("Dir::Cache::archives","archives/");
|
||||||
|
Cnf.Set("Dir::Cache::srcpkgcache","srcpkgcache.bin");
|
||||||
|
Cnf.Set("Dir::Cache::pkgcache","pkgcache.bin");
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
Cnf.Set("Dir::Etc","/etc/apt/");
|
||||||
|
Cnf.Set("Dir::Etc::sourcelist","sources.list");
|
||||||
|
Cnf.Set("Dir::Etc::vendorlist","vendors.list");
|
||||||
|
Cnf.Set("Dir::Etc::main","apt.conf");
|
||||||
|
Cnf.Set("Dir::Bin::gpg","/usr/bin/gpg");
|
||||||
|
Cnf.Set("Dir::Bin::methods","/usr/lib/apt/methods");
|
||||||
|
if (0) {//akk
|
||||||
|
Cnf.Set("Dir::Bin::dpkg","/usr/bin/dpkg");
|
||||||
|
Cnf.Set("Acquire::ComprExtension", ".gz");
|
||||||
|
} else {
|
||||||
|
Cnf.Set("Dir::Etc::RpmPriorities", "rpmpriorities");
|
||||||
|
Cnf.Set("Dir::bin::gzip","/usr/bin/bzip2");
|
||||||
|
Cnf.Set("Dir::Bin::rpm","/bin/rpm");
|
||||||
|
Cnf.Set("Acquire::ComprExtension", ".bz2");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the main config file
|
||||||
|
string FName = Cnf.FindFile("Dir::Etc::main");
|
||||||
|
bool Res = true;
|
||||||
|
if (FileExists(FName) == true)
|
||||||
|
Res &= ReadConfigFile(Cnf,FName);
|
||||||
|
|
||||||
|
// Read an alternate config file
|
||||||
|
const char *Cfg = getenv("APT_CONFIG");
|
||||||
|
if (Cfg != 0 && FileExists(Cfg) == true)
|
||||||
|
Res &= ReadConfigFile(Cnf,Cfg);
|
||||||
|
|
||||||
|
if (Res == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Cnf.FindB("Debug::pkgInitialize",false) == true)
|
||||||
|
Cnf.Dump();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
21
apt/apt-pkg/init.h
Normal file
21
apt/apt-pkg/init.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: init.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Init - Initialize the package library
|
||||||
|
|
||||||
|
This function must be called to configure the config class before
|
||||||
|
calling many APT library functions.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_INIT_H
|
||||||
|
#define PKGLIB_INIT_H
|
||||||
|
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
|
||||||
|
bool pkgInitialize(Configuration &Cnf);
|
||||||
|
|
||||||
|
#endif
|
61
apt/apt-pkg/makefile
Normal file
61
apt/apt-pkg/makefile
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# -*- make -*-
|
||||||
|
BASE=..
|
||||||
|
SUBDIR=apt-pkg
|
||||||
|
|
||||||
|
# Header location
|
||||||
|
SUBDIRS = rpm deb contrib
|
||||||
|
HEADER_TARGETDIRS = apt-pkg
|
||||||
|
|
||||||
|
# Bring in the default rules
|
||||||
|
include ../buildlib/defaults.mak
|
||||||
|
|
||||||
|
# The library name
|
||||||
|
LIBRARY=apt-pkg
|
||||||
|
MAJOR=3.1
|
||||||
|
MINOR=0
|
||||||
|
SLIBS=$(PTHREADLIB)
|
||||||
|
|
||||||
|
# Source code for the contributed non-core things
|
||||||
|
SOURCE = contrib/mmap.cc contrib/error.cc contrib/strutl.cc \
|
||||||
|
contrib/configuration.cc contrib/progress.cc contrib/cmndline.cc \
|
||||||
|
contrib/md5.cc contrib/cdromutl.cc contrib/crc-16.cc
|
||||||
|
|
||||||
|
# Source code for the main library
|
||||||
|
SOURCE+= pkgcache.cc version.cc fileutl.cc pkgcachegen.cc depcache.cc \
|
||||||
|
orderlist.cc tagfile.cc sourcelist.cc packagemanager.cc \
|
||||||
|
pkgrecords.cc algorithms.cc acquire.cc acquire-item.cc \
|
||||||
|
acquire-worker.cc acquire-method.cc init.cc clean.cc \
|
||||||
|
srcrecords.cc cachefile.cc systemfactory.cc
|
||||||
|
|
||||||
|
# Source code for the debian specific components
|
||||||
|
SOURCE+= deb/deblistparser.cc deb/debrecords.cc deb/dpkgpm.cc deb/dpkginit.cc \
|
||||||
|
deb/debsrcrecords.cc \
|
||||||
|
deb/debfactory.cc
|
||||||
|
|
||||||
|
# Source code for the rpm specific components
|
||||||
|
SOURCE+= rpm/rpminit.cc rpm/rpmlistparser.cc rpm/rpmpm.cc\
|
||||||
|
rpm/rpmrecords.cc rpm/rpmsrcrecords.cc
|
||||||
|
|
||||||
|
SOURCE+= rpm/rpmfactory.cc rpm/rpmversion.cc rpm/rpmpackagedata.cc
|
||||||
|
|
||||||
|
# Public apt-pkg header files
|
||||||
|
HEADERS = algorithms.h depcache.h mmap.h pkgcachegen.h cacheiterators.h \
|
||||||
|
error.h orderlist.h sourcelist.h configuration.h fileutl.h \
|
||||||
|
packagemanager.h tagfile.h deblistparser.h init.h pkgcache.h \
|
||||||
|
progress.h pkgrecords.h debrecords.h cmndline.h \
|
||||||
|
acquire.h acquire-worker.h acquire-item.h acquire-method.h md5.h \
|
||||||
|
dpkgpm.h dpkginit.h cdromutl.h strutl.h clean.h srcrecords.h \
|
||||||
|
debsrcrecords.h cachefile.h crc-16.h systemfactory.h sptr.h
|
||||||
|
|
||||||
|
HEADERS+= rpmfactory.h debfactory.h
|
||||||
|
|
||||||
|
HEADERS+= rpminit.h rpmlistparser.h rpmpm.h rpmrecords.h rpmpackagedata.h\
|
||||||
|
rpmsrcrecords.h
|
||||||
|
|
||||||
|
|
||||||
|
HEADERS := $(addprefix apt-pkg/,$(HEADERS))
|
||||||
|
|
||||||
|
# Private header files
|
||||||
|
HEADERS+= system.h i18n.h
|
||||||
|
|
||||||
|
include $(LIBRARY_H)
|
960
apt/apt-pkg/orderlist.cc
Normal file
960
apt/apt-pkg/orderlist.cc
Normal file
@ -0,0 +1,960 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: orderlist.cc,v 1.4 2000/10/26 21:15:21 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Order List - Represents and Manipulates an ordered list of packages.
|
||||||
|
|
||||||
|
A list of packages can be ordered by a number of conflicting criteria
|
||||||
|
each given a specific priority. Each package also has a set of flags
|
||||||
|
indicating some usefull things about it that are derived in the
|
||||||
|
course of sorting. The pkgPackageManager class uses this class for
|
||||||
|
all of it's installation ordering needs.
|
||||||
|
|
||||||
|
This is a modified version of Manoj's Routine B. It consists of four
|
||||||
|
independent ordering algorithms that can be applied at for different
|
||||||
|
points in the ordering. By appling progressivly fewer ordering
|
||||||
|
operations it is possible to give each consideration it's own
|
||||||
|
priority and create an order that satisfies the lowest applicable
|
||||||
|
consideration.
|
||||||
|
|
||||||
|
The rules for unpacking ordering are:
|
||||||
|
1) Unpacking ignores Depends: on all packages
|
||||||
|
2) Unpacking requires Conflicts: on -ALL- packages to be satisfied
|
||||||
|
3) Unpacking requires PreDepends: on this package only to be satisfied
|
||||||
|
4) Removing requires that no packages depend on the package to be
|
||||||
|
removed.
|
||||||
|
|
||||||
|
And the rule for configuration ordering is:
|
||||||
|
1) Configuring requires that the Depends: of the package be satisfied
|
||||||
|
Conflicts+PreDepends are ignored because unpacking says they are
|
||||||
|
already correct [exageration, it does check but we need not be
|
||||||
|
concerned]
|
||||||
|
|
||||||
|
And some features that are valuable for unpacking ordering.
|
||||||
|
f1) Unpacking a new package should advoid breaking dependencies of
|
||||||
|
configured packages
|
||||||
|
f2) Removal should not require a force, corrolory of f1
|
||||||
|
f3) Unpacking should order by depends rather than fall back to random
|
||||||
|
ordering.
|
||||||
|
|
||||||
|
Each of the features can be enabled in the sorting routine at an
|
||||||
|
arbitary priority to give quite abit of control over the final unpacking
|
||||||
|
order.
|
||||||
|
|
||||||
|
The rules listed above may never be violated and are called Critical.
|
||||||
|
When a critical rule is violated then a loop condition is recorded
|
||||||
|
and will have to be delt with in the caller.
|
||||||
|
|
||||||
|
The ordering keeps two lists, the main list and the 'After List'. The
|
||||||
|
purpose of the after list is to allow packages to be delayed. This is done
|
||||||
|
by setting the after flag on the package. Any package which requires this
|
||||||
|
package to be ordered before will inherit the after flag and so on. This
|
||||||
|
is used for CD swap ordering where all packages on a second CD have the
|
||||||
|
after flag set. This forces them and all their dependents to be ordered
|
||||||
|
toward the end.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/orderlist.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/orderlist.h>
|
||||||
|
#include <apt-pkg/depcache.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
pkgOrderList *pkgOrderList::Me = 0;
|
||||||
|
|
||||||
|
// OrderList::pkgOrderList - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgOrderList::pkgOrderList(pkgDepCache &Cache) : Cache(Cache)
|
||||||
|
{
|
||||||
|
FileList = 0;
|
||||||
|
Primary = 0;
|
||||||
|
Secondary = 0;
|
||||||
|
RevDepends = 0;
|
||||||
|
Remove = 0;
|
||||||
|
LoopCount = -1;
|
||||||
|
|
||||||
|
/* Construct the arrays, egcs 1.0.1 bug requires the package count
|
||||||
|
hack */
|
||||||
|
unsigned long Size = Cache.HeaderP->PackageCount;
|
||||||
|
Flags = new unsigned short[Size];
|
||||||
|
End = List = new Package *[Size];
|
||||||
|
memset(Flags,0,sizeof(*Flags)*Size);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::~pkgOrderList - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgOrderList::~pkgOrderList()
|
||||||
|
{
|
||||||
|
delete [] List;
|
||||||
|
delete [] Flags;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::IsMissing - Check if a file is missing /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgOrderList::IsMissing(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
// Skip packages to erase
|
||||||
|
if (Cache[Pkg].Delete() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Skip Packages that need configure only.
|
||||||
|
if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
|
||||||
|
Cache[Pkg].Keep() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (FileList != 0 && FileList[Pkg->ID].empty() == false)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// OrderList::DoRun - Does an order run /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The caller is expeted to have setup the desired probe state */
|
||||||
|
bool pkgOrderList::DoRun()
|
||||||
|
{
|
||||||
|
// Temp list
|
||||||
|
unsigned long Size = Cache.HeaderP->PackageCount;
|
||||||
|
Package **NList = new Package *[Size];
|
||||||
|
AfterList = new Package *[Size];
|
||||||
|
AfterEnd = AfterList;
|
||||||
|
|
||||||
|
Depth = 0;
|
||||||
|
WipeFlags(Added | AddPending | Loop | InList);
|
||||||
|
|
||||||
|
for (iterator I = List; I != End; I++)
|
||||||
|
Flag(*I,InList);
|
||||||
|
|
||||||
|
// Rebuild the main list into the temp list.
|
||||||
|
iterator OldEnd = End;
|
||||||
|
End = NList;
|
||||||
|
for (iterator I = List; I != OldEnd; I++)
|
||||||
|
if (VisitNode(PkgIterator(Cache,*I)) == false)
|
||||||
|
{
|
||||||
|
End = OldEnd;
|
||||||
|
delete [] NList;
|
||||||
|
delete [] AfterList;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the after list to the end of the main list
|
||||||
|
for (Package **I = AfterList; I != AfterEnd; I++)
|
||||||
|
*End++ = *I;
|
||||||
|
|
||||||
|
// Swap the main list to the new list
|
||||||
|
delete [] List;
|
||||||
|
delete [] AfterList;
|
||||||
|
List = NList;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::OrderCritical - Perform critical unpacking ordering /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This performs predepends and immediate configuration ordering only.
|
||||||
|
This is termed critical unpacking ordering. Any loops that form are
|
||||||
|
fatal and indicate that the packages cannot be installed. */
|
||||||
|
bool pkgOrderList::OrderCritical()
|
||||||
|
{
|
||||||
|
FileList = 0;
|
||||||
|
|
||||||
|
Primary = &pkgOrderList::DepUnPackPre;
|
||||||
|
Secondary = 0;
|
||||||
|
RevDepends = 0;
|
||||||
|
Remove = 0;
|
||||||
|
LoopCount = 0;
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
Me = this;
|
||||||
|
qsort(List,End - List,sizeof(*List),&OrderCompareB);
|
||||||
|
|
||||||
|
if (DoRun() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (LoopCount != 0)
|
||||||
|
return _error->Error("Fatal, predepends looping detected");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::OrderUnpack - Perform complete unpacking ordering /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This performs complete unpacking ordering and creates an order that is
|
||||||
|
suitable for unpacking */
|
||||||
|
bool pkgOrderList::OrderUnpack(string *FileList)
|
||||||
|
{
|
||||||
|
this->FileList = FileList;
|
||||||
|
|
||||||
|
// Setup the after flags
|
||||||
|
if (FileList != 0)
|
||||||
|
{
|
||||||
|
WipeFlags(After);
|
||||||
|
|
||||||
|
// Set the inlist flag
|
||||||
|
for (iterator I = List; I != End; I++)
|
||||||
|
{
|
||||||
|
PkgIterator P(Cache,*I);
|
||||||
|
if (IsMissing(P) == true && IsNow(P) == true)
|
||||||
|
Flag(*I,After);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Primary = &pkgOrderList::DepUnPackCrit;
|
||||||
|
Secondary = &pkgOrderList::DepConfigure;
|
||||||
|
RevDepends = &pkgOrderList::DepUnPackDep;
|
||||||
|
Remove = &pkgOrderList::DepRemove;
|
||||||
|
LoopCount = -1;
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
Me = this;
|
||||||
|
qsort(List,End - List,sizeof(*List),&OrderCompareA);
|
||||||
|
|
||||||
|
if (DoRun() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Secondary = 0;
|
||||||
|
if (DoRun() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LoopCount = 0;
|
||||||
|
RevDepends = 0;
|
||||||
|
Remove = 0; // Otherwise the libreadline remove problem occures
|
||||||
|
if (DoRun() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LoopCount = 0;
|
||||||
|
Primary = &pkgOrderList::DepUnPackPre;
|
||||||
|
if (DoRun() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* cout << "----------END" << endl;
|
||||||
|
|
||||||
|
for (iterator I = List; I != End; I++)
|
||||||
|
{
|
||||||
|
PkgIterator P(Cache,*I);
|
||||||
|
if (IsNow(P) == true)
|
||||||
|
cout << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::OrderConfigure - Perform configuration ordering /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This orders by depends only and produces an order which is suitable
|
||||||
|
for configuration */
|
||||||
|
bool pkgOrderList::OrderConfigure()
|
||||||
|
{
|
||||||
|
FileList = 0;
|
||||||
|
Primary = &pkgOrderList::DepConfigure;
|
||||||
|
Secondary = 0;
|
||||||
|
RevDepends = 0;
|
||||||
|
Remove = 0;
|
||||||
|
LoopCount = -1;
|
||||||
|
return DoRun();
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// OrderList::Score - Score the package for sorting /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Higher scores order earlier */
|
||||||
|
int pkgOrderList::Score(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
// Removal is always done first
|
||||||
|
if (Cache[Pkg].Delete() == true)
|
||||||
|
return 200;
|
||||||
|
|
||||||
|
// This should never happen..
|
||||||
|
if (Cache[Pkg].InstVerIter(Cache).end() == true)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int Score = 0;
|
||||||
|
if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
|
||||||
|
Score += 100;
|
||||||
|
|
||||||
|
if (IsFlag(Pkg,Immediate) == true)
|
||||||
|
Score += 10;
|
||||||
|
|
||||||
|
for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
|
||||||
|
D.end() == false; D++)
|
||||||
|
if (D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
{
|
||||||
|
Score += 50;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Important Required Standard Optional Extra
|
||||||
|
signed short PrioMap[] = {0,5,4,3,1,0};
|
||||||
|
if (Cache[Pkg].InstVerIter(Cache)->Priority <= 5)
|
||||||
|
Score += PrioMap[Cache[Pkg].InstVerIter(Cache)->Priority];
|
||||||
|
return Score;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::FileCmp - Compare by package file /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This compares by the package file that the install version is in. */
|
||||||
|
int pkgOrderList::FileCmp(PkgIterator A,PkgIterator B)
|
||||||
|
{
|
||||||
|
if (Cache[A].Delete() == true && Cache[B].Delete() == true)
|
||||||
|
return 0;
|
||||||
|
if (Cache[A].Delete() == true)
|
||||||
|
return -1;
|
||||||
|
if (Cache[B].Delete() == true)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (Cache[A].InstVerIter(Cache).FileList().end() == true)
|
||||||
|
return -1;
|
||||||
|
if (Cache[B].InstVerIter(Cache).FileList().end() == true)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
pkgCache::PackageFile *FA = Cache[A].InstVerIter(Cache).FileList().File();
|
||||||
|
pkgCache::PackageFile *FB = Cache[B].InstVerIter(Cache).FileList().File();
|
||||||
|
if (FA < FB)
|
||||||
|
return -1;
|
||||||
|
if (FA > FB)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// BoolCompare - Comparison function for two booleans /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
static int BoolCompare(bool A,bool B)
|
||||||
|
{
|
||||||
|
if (A == B)
|
||||||
|
return 0;
|
||||||
|
if (A == false)
|
||||||
|
return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::OrderCompareA - Order the installation by op /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This provides a first-pass sort of the list and gives a decent starting
|
||||||
|
point for further complete ordering. It is used by OrderUnpack only */
|
||||||
|
int pkgOrderList::OrderCompareA(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
PkgIterator A(Me->Cache,*(Package **)a);
|
||||||
|
PkgIterator B(Me->Cache,*(Package **)b);
|
||||||
|
|
||||||
|
// We order packages with a set state toward the front
|
||||||
|
int Res;
|
||||||
|
if ((Res = BoolCompare(Me->IsNow(A),Me->IsNow(B))) != 0)
|
||||||
|
return -1*Res;
|
||||||
|
|
||||||
|
// We order missing files to toward the end
|
||||||
|
/* if (Me->FileList != 0)
|
||||||
|
{
|
||||||
|
if ((Res = BoolCompare(Me->IsMissing(A),
|
||||||
|
Me->IsMissing(B))) != 0)
|
||||||
|
return Res;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (A.State() != pkgCache::PkgIterator::NeedsNothing &&
|
||||||
|
B.State() == pkgCache::PkgIterator::NeedsNothing)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (A.State() == pkgCache::PkgIterator::NeedsNothing &&
|
||||||
|
B.State() != pkgCache::PkgIterator::NeedsNothing)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int ScoreA = Me->Score(A);
|
||||||
|
int ScoreB = Me->Score(B);
|
||||||
|
if (ScoreA > ScoreB)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ScoreA < ScoreB)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return strcmp(A.Name(),B.Name());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::OrderCompareB - Order the installation by source /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This orders by installation source. This is usefull to handle
|
||||||
|
inter-source breaks */
|
||||||
|
int pkgOrderList::OrderCompareB(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
PkgIterator A(Me->Cache,*(Package **)a);
|
||||||
|
PkgIterator B(Me->Cache,*(Package **)b);
|
||||||
|
|
||||||
|
if (A.State() != pkgCache::PkgIterator::NeedsNothing &&
|
||||||
|
B.State() == pkgCache::PkgIterator::NeedsNothing)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (A.State() == pkgCache::PkgIterator::NeedsNothing &&
|
||||||
|
B.State() != pkgCache::PkgIterator::NeedsNothing)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
int F = Me->FileCmp(A,B);
|
||||||
|
if (F != 0)
|
||||||
|
{
|
||||||
|
if (F > 0)
|
||||||
|
return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScoreA = Me->Score(A);
|
||||||
|
int ScoreB = Me->Score(B);
|
||||||
|
if (ScoreA > ScoreB)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ScoreA < ScoreB)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return strcmp(A.Name(),B.Name());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// OrderList::VisitDeps - Visit forward install dependencies /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This calls the dependency function for the normal forwards dependencies
|
||||||
|
of the package */
|
||||||
|
bool pkgOrderList::VisitDeps(DepFunc F,PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
if (F == 0 || Pkg.end() == true || Cache[Pkg].InstallVer == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return (this->*F)(Cache[Pkg].InstVerIter(Cache).DependsList());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::VisitRDeps - Visit reverse dependencies /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This calls the dependency function for all of the normal reverse depends
|
||||||
|
of the package */
|
||||||
|
bool pkgOrderList::VisitRDeps(DepFunc F,PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
if (F == 0 || Pkg.end() == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return (this->*F)(Pkg.RevDependsList());
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::VisitRProvides - Visit provides reverse dependencies /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This calls the dependency function for all reverse dependencies
|
||||||
|
generated by the provides line on the package. */
|
||||||
|
bool pkgOrderList::VisitRProvides(DepFunc F,VerIterator Ver)
|
||||||
|
{
|
||||||
|
if (F == 0 || Ver.end() == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool Res = true;
|
||||||
|
for (PrvIterator P = Ver.ProvidesList(); P.end() == false; P++)
|
||||||
|
Res &= (this->*F)(P.ParentPkg().RevDependsList());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::VisitProvides - Visit all of the providing packages /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This routine calls visit on all providing packages. */
|
||||||
|
bool pkgOrderList::VisitProvides(DepIterator D,bool Critical)
|
||||||
|
{
|
||||||
|
Version **List = D.AllTargets();
|
||||||
|
for (Version **I = List; *I != 0; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(Cache,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::Obsoletes
|
||||||
|
&& Cache[Pkg].InstallVer != *I)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((D->Type == pkgCache::Dep::Conflicts || D->Type == pkgCache::Dep::Obsoletes)
|
||||||
|
&& (Version *)Pkg.CurrentVer() != *I)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip over missing files
|
||||||
|
if (Critical == false && IsMissing(D.ParentPkg()) == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (VisitNode(Pkg) == false)
|
||||||
|
{
|
||||||
|
delete [] List;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete [] List;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::VisitNode - Recursive ordering director /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is the core ordering routine. It calls the set dependency
|
||||||
|
consideration functions which then potentialy call this again. Finite
|
||||||
|
depth is achived through the colouring mechinism. */
|
||||||
|
bool pkgOrderList::VisitNode(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
// Looping or irrelevent.
|
||||||
|
// This should probably trancend not installed packages
|
||||||
|
if (Pkg.end() == true || IsFlag(Pkg,Added) == true ||
|
||||||
|
IsFlag(Pkg,AddPending) == true || IsFlag(Pkg,InList) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* for (int j = 0; j != Depth; j++) cout << ' ';
|
||||||
|
cout << "Visit " << Pkg.Name() << endl;*/
|
||||||
|
Depth++;
|
||||||
|
|
||||||
|
// Color grey
|
||||||
|
Flag(Pkg,AddPending);
|
||||||
|
|
||||||
|
DepFunc Old = Primary;
|
||||||
|
|
||||||
|
// Perform immedate configuration of the package if so flagged.
|
||||||
|
if (IsFlag(Pkg,Immediate) == true && Primary != &pkgOrderList::DepUnPackPre)
|
||||||
|
Primary = &pkgOrderList::DepUnPackPreD;
|
||||||
|
|
||||||
|
if (IsNow(Pkg) == true)
|
||||||
|
{
|
||||||
|
bool Res = true;
|
||||||
|
if (Cache[Pkg].Delete() == false)
|
||||||
|
{
|
||||||
|
// Primary
|
||||||
|
Res &= Res && VisitDeps(Primary,Pkg);
|
||||||
|
Res &= Res && VisitRDeps(Primary,Pkg);
|
||||||
|
Res &= Res && VisitRProvides(Primary,Pkg.CurrentVer());
|
||||||
|
Res &= Res && VisitRProvides(Primary,Cache[Pkg].InstVerIter(Cache));
|
||||||
|
|
||||||
|
// RevDep
|
||||||
|
Res &= Res && VisitRDeps(RevDepends,Pkg);
|
||||||
|
Res &= Res && VisitRProvides(RevDepends,Pkg.CurrentVer());
|
||||||
|
Res &= Res && VisitRProvides(RevDepends,Cache[Pkg].InstVerIter(Cache));
|
||||||
|
|
||||||
|
// Secondary
|
||||||
|
Res &= Res && VisitDeps(Secondary,Pkg);
|
||||||
|
Res &= Res && VisitRDeps(Secondary,Pkg);
|
||||||
|
Res &= Res && VisitRProvides(Secondary,Pkg.CurrentVer());
|
||||||
|
Res &= Res && VisitRProvides(Secondary,Cache[Pkg].InstVerIter(Cache));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// RevDep
|
||||||
|
Res &= Res && VisitRDeps(Remove,Pkg);
|
||||||
|
Res &= Res && VisitRProvides(Remove,Pkg.CurrentVer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsFlag(Pkg,Added) == false)
|
||||||
|
{
|
||||||
|
Flag(Pkg,Added,Added | AddPending);
|
||||||
|
if (IsFlag(Pkg,After) == true)
|
||||||
|
*AfterEnd++ = Pkg;
|
||||||
|
else
|
||||||
|
*End++ = Pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
Primary = Old;
|
||||||
|
Depth--;
|
||||||
|
|
||||||
|
/* for (int j = 0; j != Depth; j++) cout << ' ';
|
||||||
|
cout << "Leave " << Pkg.Name() << ' ' << IsFlag(Pkg,Added) << ',' << IsFlag(Pkg,AddPending) << endl;*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// OrderList::DepUnPackCrit - Critical UnPacking ordering /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Critical unpacking ordering strives to satisfy Conflicts: and
|
||||||
|
PreDepends: only. When a prdepends is encountered the Primary
|
||||||
|
DepFunc is changed to be DepUnPackPreD.
|
||||||
|
|
||||||
|
Loops are preprocessed and logged. */
|
||||||
|
bool pkgOrderList::DepUnPackCrit(DepIterator D)
|
||||||
|
{
|
||||||
|
for (; D.end() == false; D++)
|
||||||
|
{
|
||||||
|
if (D.Reverse() == true)
|
||||||
|
{
|
||||||
|
/* Reverse depenanices are only interested in conflicts,
|
||||||
|
predepend breakage is ignored here */
|
||||||
|
if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::Obsoletes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Duplication elimination, consider only the current version
|
||||||
|
if (D.ParentPkg().CurrentVer() != D.ParentVer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* For reverse dependencies we wish to check if the
|
||||||
|
dependency is satisifed in the install state. The
|
||||||
|
target package (caller) is going to be in the installed
|
||||||
|
state. */
|
||||||
|
if (CheckDep(D) == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (VisitNode(D.ParentPkg()) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Forward critical dependencies MUST be correct before the
|
||||||
|
package can be unpacked. */
|
||||||
|
if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::Obsoletes &&
|
||||||
|
D->Type != pkgCache::Dep::PreDepends)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* We wish to check if the dep is okay in the now state of the
|
||||||
|
target package against the install state of this package. */
|
||||||
|
if (CheckDep(D) == true)
|
||||||
|
{
|
||||||
|
/* We want to catch predepends loops with the code below.
|
||||||
|
Conflicts loops that are Dep OK are ignored */
|
||||||
|
if (IsFlag(D.TargetPkg(),AddPending) == false ||
|
||||||
|
D->Type != pkgCache::Dep::PreDepends)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the loop detection
|
||||||
|
if (IsFlag(D.TargetPkg(),Added) == true ||
|
||||||
|
IsFlag(D.TargetPkg(),AddPending) == true)
|
||||||
|
{
|
||||||
|
if (IsFlag(D.TargetPkg(),AddPending) == true)
|
||||||
|
AddLoop(D);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Predepends require a special ordering stage, they must have
|
||||||
|
all dependents installed as well */
|
||||||
|
DepFunc Old = Primary;
|
||||||
|
bool Res = false;
|
||||||
|
if (D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
Primary = &pkgOrderList::DepUnPackPreD;
|
||||||
|
Res = VisitProvides(D,true);
|
||||||
|
Primary = Old;
|
||||||
|
if (Res == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::DepUnPackPreD - Critical UnPacking ordering with depends /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Critical PreDepends (also configure immediate and essential) strives to
|
||||||
|
ensure not only that all conflicts+predepends are met but that this
|
||||||
|
package will be immediately configurable when it is unpacked.
|
||||||
|
|
||||||
|
Loops are preprocessed and logged. */
|
||||||
|
bool pkgOrderList::DepUnPackPreD(DepIterator D)
|
||||||
|
{
|
||||||
|
if (D.Reverse() == true)
|
||||||
|
return DepUnPackCrit(D);
|
||||||
|
|
||||||
|
for (; D.end() == false; D++)
|
||||||
|
{
|
||||||
|
if (D.IsCritical() == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* We wish to check if the dep is okay in the now state of the
|
||||||
|
target package against the install state of this package. */
|
||||||
|
if (CheckDep(D) == true)
|
||||||
|
{
|
||||||
|
/* We want to catch predepends loops with the code below.
|
||||||
|
Conflicts loops that are Dep OK are ignored */
|
||||||
|
if (IsFlag(D.TargetPkg(),AddPending) == false ||
|
||||||
|
D->Type != pkgCache::Dep::PreDepends)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the loop detection
|
||||||
|
if (IsFlag(D.TargetPkg(),Added) == true ||
|
||||||
|
IsFlag(D.TargetPkg(),AddPending) == true)
|
||||||
|
{
|
||||||
|
if (IsFlag(D.TargetPkg(),AddPending) == true)
|
||||||
|
AddLoop(D);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VisitProvides(D,true) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::DepUnPackPre - Critical Predepends ordering /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Critical PreDepends (also configure immediate and essential) strives to
|
||||||
|
ensure not only that all conflicts+predepends are met but that this
|
||||||
|
package will be immediately configurable when it is unpacked.
|
||||||
|
|
||||||
|
Loops are preprocessed and logged. All loops will be fatal. */
|
||||||
|
bool pkgOrderList::DepUnPackPre(DepIterator D)
|
||||||
|
{
|
||||||
|
if (D.Reverse() == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (; D.end() == false; D++)
|
||||||
|
{
|
||||||
|
/* Only consider the PreDepends or Depends. Depends are only
|
||||||
|
considered at the lowest depth or in the case of immediate
|
||||||
|
configure */
|
||||||
|
if (D->Type != pkgCache::Dep::PreDepends)
|
||||||
|
{
|
||||||
|
if (D->Type == pkgCache::Dep::Depends)
|
||||||
|
{
|
||||||
|
if (Depth == 1 && IsFlag(D.ParentPkg(),Immediate) == false)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We wish to check if the dep is okay in the now state of the
|
||||||
|
target package against the install state of this package. */
|
||||||
|
if (CheckDep(D) == true)
|
||||||
|
{
|
||||||
|
/* We want to catch predepends loops with the code below.
|
||||||
|
Conflicts loops that are Dep OK are ignored */
|
||||||
|
if (IsFlag(D.TargetPkg(),AddPending) == false)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the loop detection
|
||||||
|
if (IsFlag(D.TargetPkg(),Added) == true ||
|
||||||
|
IsFlag(D.TargetPkg(),AddPending) == true)
|
||||||
|
{
|
||||||
|
if (IsFlag(D.TargetPkg(),AddPending) == true)
|
||||||
|
AddLoop(D);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VisitProvides(D,true) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::DepUnPackDep - Reverse dependency considerations /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Reverse dependencies are considered to determine if unpacking this
|
||||||
|
package will break any existing dependencies. If so then those
|
||||||
|
packages are ordered before this one so that they are in the
|
||||||
|
UnPacked state.
|
||||||
|
|
||||||
|
The forwards depends loop is designed to bring the packages dependents
|
||||||
|
close to the package. This helps reduce deconfigure time.
|
||||||
|
|
||||||
|
Loops are irrelevent to this. */
|
||||||
|
bool pkgOrderList::DepUnPackDep(DepIterator D)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (; D.end() == false; D++)
|
||||||
|
if (D.IsCritical() == true)
|
||||||
|
{
|
||||||
|
if (D.Reverse() == true)
|
||||||
|
{
|
||||||
|
/* Duplication prevention. We consider rev deps only on
|
||||||
|
the current version, a not installed package
|
||||||
|
cannot break */
|
||||||
|
if (D.ParentPkg()->CurrentVer == 0 ||
|
||||||
|
D.ParentPkg().CurrentVer() != D.ParentVer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// The dep will not break so it is irrelevent.
|
||||||
|
if (CheckDep(D) == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip over missing files
|
||||||
|
if (IsMissing(D.ParentPkg()) == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (VisitNode(D.ParentPkg()) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (D->Type == pkgCache::Dep::Depends)
|
||||||
|
if (VisitProvides(D,false) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::DepConfigure - Configuration ordering /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Configuration only ordering orders by the Depends: line only. It
|
||||||
|
orders configuration so that when a package comes to be configured it's
|
||||||
|
dependents are configured.
|
||||||
|
|
||||||
|
Loops are ingored. Depends loop entry points are chaotic. */
|
||||||
|
bool pkgOrderList::DepConfigure(DepIterator D)
|
||||||
|
{
|
||||||
|
// Never consider reverse configuration dependencies.
|
||||||
|
if (D.Reverse() == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (; D.end() == false; D++)
|
||||||
|
if (D->Type == pkgCache::Dep::Depends)
|
||||||
|
if (VisitProvides(D,false) == false)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::DepRemove - Removal ordering /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* Removal visits all reverse depends. It considers if the dependency
|
||||||
|
of the Now state version to see if it is okay with removing this
|
||||||
|
package. This check should always fail, but is provided for symetery
|
||||||
|
with the other critical handlers.
|
||||||
|
|
||||||
|
Loops are preprocessed and logged. Removal loops can also be
|
||||||
|
detected in the critical handler. They are characterized by an
|
||||||
|
old version of A depending on B but the new version of A conflicting
|
||||||
|
with B, thus either A or B must break to install. */
|
||||||
|
bool pkgOrderList::DepRemove(DepIterator D)
|
||||||
|
{
|
||||||
|
if (D.Reverse() == false)
|
||||||
|
return true;
|
||||||
|
for (; D.end() == false; D++)
|
||||||
|
if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
{
|
||||||
|
// Duplication elimination, consider the current version only
|
||||||
|
if (D.ParentPkg().CurrentVer() != D.ParentVer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* We wish to see if the dep on the parent package is okay
|
||||||
|
in the removed (install) state of the target pkg. */
|
||||||
|
if (CheckDep(D) == true)
|
||||||
|
{
|
||||||
|
// We want to catch loops with the code below.
|
||||||
|
if (IsFlag(D.ParentPkg(),AddPending) == false)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the loop detection
|
||||||
|
if (IsFlag(D.ParentPkg(),Added) == true ||
|
||||||
|
IsFlag(D.ParentPkg(),AddPending) == true)
|
||||||
|
{
|
||||||
|
if (IsFlag(D.ParentPkg(),AddPending) == true)
|
||||||
|
AddLoop(D);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip over missing files
|
||||||
|
if (IsMissing(D.ParentPkg()) == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (VisitNode(D.ParentPkg()) == false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// OrderList::AddLoop - Add a loop to the loop list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We record the loops. This is a relic since loop breaking is done
|
||||||
|
genericaly as part of the safety routines. */
|
||||||
|
bool pkgOrderList::AddLoop(DepIterator D)
|
||||||
|
{
|
||||||
|
if (LoopCount < 0 || LoopCount >= 20)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Skip dups
|
||||||
|
if (LoopCount != 0)
|
||||||
|
{
|
||||||
|
if (Loops[LoopCount - 1].ParentPkg() == D.ParentPkg() ||
|
||||||
|
Loops[LoopCount - 1].TargetPkg() == D.ParentPkg())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loops[LoopCount++] = D;
|
||||||
|
|
||||||
|
// Mark the packages as being part of a loop.
|
||||||
|
Flag(D.TargetPkg(),Loop);
|
||||||
|
Flag(D.ParentPkg(),Loop);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::WipeFlags - Unset the given flags from all packages /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
void pkgOrderList::WipeFlags(unsigned long F)
|
||||||
|
{
|
||||||
|
unsigned long Size = Cache.HeaderP->PackageCount;
|
||||||
|
for (unsigned long I = 0; I != Size; I++)
|
||||||
|
Flags[I] &= ~F;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// OrderList::CheckDep - Check a dependency for truth /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This performs a complete analysis of the dependency wrt to the
|
||||||
|
current add list. It returns true if after all events are
|
||||||
|
performed it is still true. This sort of routine can be approximated
|
||||||
|
by examining the DepCache, however in convoluted cases of provides
|
||||||
|
this fails to produce a suitable result. */
|
||||||
|
bool pkgOrderList::CheckDep(DepIterator D)
|
||||||
|
{
|
||||||
|
Version **List = D.AllTargets();
|
||||||
|
bool Hit = false;
|
||||||
|
for (Version **I = List; *I != 0; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(Cache,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
/* The meaning of Added and AddPending is subtle. AddPending is
|
||||||
|
an indication that the package is looping. Because of the
|
||||||
|
way ordering works Added means the package will be unpacked
|
||||||
|
before this one and AddPending means after. It is therefore
|
||||||
|
correct to ignore AddPending in all cases, but that exposes
|
||||||
|
reverse-ordering loops which should be ignored. */
|
||||||
|
if (IsFlag(Pkg,Added) == true ||
|
||||||
|
(IsFlag(Pkg,AddPending) == true && D.Reverse() == true))
|
||||||
|
{
|
||||||
|
if (Cache[Pkg].InstallVer != *I)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if ((Version *)Pkg.CurrentVer() != *I ||
|
||||||
|
Pkg.State() != PkgIterator::NeedsNothing)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Conflicts requires that all versions are not present, depends
|
||||||
|
just needs one */
|
||||||
|
if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::Obsoletes)
|
||||||
|
{
|
||||||
|
/* Try to find something that does not have the after flag set
|
||||||
|
if at all possible */
|
||||||
|
if (IsFlag(Pkg,After) == true)
|
||||||
|
{
|
||||||
|
Hit = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] List;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IsFlag(Pkg,After) == true)
|
||||||
|
Flag(D.ParentPkg(),After);
|
||||||
|
|
||||||
|
delete [] List;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete [] List;
|
||||||
|
|
||||||
|
// We found a hit, but it had the after flag set
|
||||||
|
if (Hit == true && D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
{
|
||||||
|
Flag(D.ParentPkg(),After);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Conflicts requires that all versions are not present, depends
|
||||||
|
just needs one */
|
||||||
|
if (D->Type == pkgCache::Dep::Conflicts || D->Type == pkgCache::Dep::Obsoletes)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
129
apt/apt-pkg/orderlist.h
Normal file
129
apt/apt-pkg/orderlist.h
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: orderlist.h,v 1.1.1.1 2000/08/10 12:42:39 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Order List - Represents and Manipulates an ordered list of packages.
|
||||||
|
|
||||||
|
A list of packages can be ordered by a number of conflicting criteria
|
||||||
|
each given a specific priority. Each package also has a set of flags
|
||||||
|
indicating some usefull things about it that are derived in the
|
||||||
|
course of sorting. The pkgPackageManager class uses this class for
|
||||||
|
all of it's installation ordering needs.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_ORDERLIST_H
|
||||||
|
#define PKGLIB_ORDERLIST_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/orderlist.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/pkgcache.h>
|
||||||
|
|
||||||
|
class pkgDepCache;
|
||||||
|
class pkgOrderList
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
pkgDepCache &Cache;
|
||||||
|
|
||||||
|
// Bring some usefull types into the local scope
|
||||||
|
typedef pkgCache::PkgIterator PkgIterator;
|
||||||
|
typedef pkgCache::VerIterator VerIterator;
|
||||||
|
typedef pkgCache::DepIterator DepIterator;
|
||||||
|
typedef pkgCache::PrvIterator PrvIterator;
|
||||||
|
typedef pkgCache::Package Package;
|
||||||
|
typedef pkgCache::Version Version;
|
||||||
|
typedef bool (pkgOrderList::*DepFunc)(DepIterator D);
|
||||||
|
|
||||||
|
// These are the currently selected ordering functions
|
||||||
|
DepFunc Primary;
|
||||||
|
DepFunc Secondary;
|
||||||
|
DepFunc RevDepends;
|
||||||
|
DepFunc Remove;
|
||||||
|
|
||||||
|
// State
|
||||||
|
Package **End;
|
||||||
|
Package **List;
|
||||||
|
Package **AfterList;
|
||||||
|
Package **AfterEnd;
|
||||||
|
string *FileList;
|
||||||
|
DepIterator Loops[20];
|
||||||
|
int LoopCount;
|
||||||
|
int Depth;
|
||||||
|
unsigned short *Flags;
|
||||||
|
|
||||||
|
// Main visit function
|
||||||
|
bool VisitNode(PkgIterator Pkg);
|
||||||
|
bool VisitDeps(DepFunc F,PkgIterator Pkg);
|
||||||
|
bool VisitRDeps(DepFunc F,PkgIterator Pkg);
|
||||||
|
bool VisitRProvides(DepFunc F,VerIterator Ver);
|
||||||
|
bool VisitProvides(DepIterator Pkg,bool Critical);
|
||||||
|
|
||||||
|
// Dependency checking functions.
|
||||||
|
bool DepUnPackCrit(DepIterator D);
|
||||||
|
bool DepUnPackPreD(DepIterator D);
|
||||||
|
bool DepUnPackPre(DepIterator D);
|
||||||
|
bool DepUnPackDep(DepIterator D);
|
||||||
|
bool DepConfigure(DepIterator D);
|
||||||
|
bool DepRemove(DepIterator D);
|
||||||
|
|
||||||
|
// Analysis helpers
|
||||||
|
bool AddLoop(DepIterator D);
|
||||||
|
bool CheckDep(DepIterator D);
|
||||||
|
bool DoRun();
|
||||||
|
|
||||||
|
// For pre sorting
|
||||||
|
static pkgOrderList *Me;
|
||||||
|
static int OrderCompareA(const void *a, const void *b);
|
||||||
|
static int OrderCompareB(const void *a, const void *b);
|
||||||
|
int FileCmp(PkgIterator A,PkgIterator B);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef Package **iterator;
|
||||||
|
|
||||||
|
// State flags
|
||||||
|
enum Flags {Added = (1 << 0), AddPending = (1 << 1),
|
||||||
|
Immediate = (1 << 2), Loop = (1 << 3),
|
||||||
|
UnPacked = (1 << 4), Configured = (1 << 5),
|
||||||
|
Removed = (1 << 6), // Early Remove
|
||||||
|
InList = (1 << 7),
|
||||||
|
After = (1 << 8),
|
||||||
|
States = (UnPacked | Configured | Removed)};
|
||||||
|
|
||||||
|
// Flag manipulators
|
||||||
|
inline bool IsFlag(PkgIterator Pkg,unsigned long F) {return (Flags[Pkg->ID] & F) == F;};
|
||||||
|
inline bool IsFlag(Package *Pkg,unsigned long F) {return (Flags[Pkg->ID] & F) == F;};
|
||||||
|
void Flag(PkgIterator Pkg,unsigned long State, unsigned long F) {Flags[Pkg->ID] = (Flags[Pkg->ID] & (~F)) | State;};
|
||||||
|
inline void Flag(PkgIterator Pkg,unsigned long F) {Flags[Pkg->ID] |= F;};
|
||||||
|
inline void Flag(Package *Pkg,unsigned long F) {Flags[Pkg->ID] |= F;};
|
||||||
|
inline bool IsNow(PkgIterator Pkg) {return (Flags[Pkg->ID] & (States & (~Removed))) == 0;};
|
||||||
|
bool IsMissing(PkgIterator Pkg);
|
||||||
|
void WipeFlags(unsigned long F);
|
||||||
|
void SetFileList(string *FileList) {this->FileList = FileList;};
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline iterator begin() {return List;};
|
||||||
|
inline iterator end() {return End;};
|
||||||
|
inline void push_back(Package *Pkg) {*(End++) = Pkg;};
|
||||||
|
inline void push_back(PkgIterator Pkg) {*(End++) = Pkg;};
|
||||||
|
inline void pop_back() {End--;};
|
||||||
|
inline bool empty() {return End == List;};
|
||||||
|
inline unsigned int size() {return End - List;};
|
||||||
|
|
||||||
|
// Ordering modes
|
||||||
|
bool OrderCritical();
|
||||||
|
bool OrderUnpack(string *FileList = 0);
|
||||||
|
bool OrderConfigure();
|
||||||
|
|
||||||
|
int Score(PkgIterator Pkg);
|
||||||
|
|
||||||
|
pkgOrderList(pkgDepCache &Cache);
|
||||||
|
~pkgOrderList();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
671
apt/apt-pkg/packagemanager.cc
Normal file
671
apt/apt-pkg/packagemanager.cc
Normal file
@ -0,0 +1,671 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: packagemanager.cc,v 1.15 2001/11/13 17:32:07 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Package Manager - Abstacts the package manager
|
||||||
|
|
||||||
|
More work is needed in the area of transitioning provides, ie exim
|
||||||
|
replacing smail. This can cause interesing side effects.
|
||||||
|
|
||||||
|
Other cases involving conflicts+replaces should be tested.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/packagemanager.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/packagemanager.h>
|
||||||
|
#include <apt-pkg/orderlist.h>
|
||||||
|
#include <apt-pkg/depcache.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/systemfactory.h>
|
||||||
|
#include <apt-pkg/acquire-item.h>
|
||||||
|
#include <apt-pkg/algorithms.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// PM::PackageManager - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgPackageManager::pkgPackageManager(pkgDepCache &Cache) : Cache(Cache)
|
||||||
|
{
|
||||||
|
FileNames = new string[Cache.Head().PackageCount];
|
||||||
|
List = 0;
|
||||||
|
Debug = _config->FindB("Debug::pkgPackageManager",false);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::PackageManager - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgPackageManager::~pkgPackageManager()
|
||||||
|
{
|
||||||
|
delete List;
|
||||||
|
delete [] FileNames;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::GetArchives - Queue the archives for download /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
|
||||||
|
pkgRecords *Recs)
|
||||||
|
{
|
||||||
|
if (CreateOrderList() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (List->OrderUnpack() == false)
|
||||||
|
return _error->Error("Internal ordering error");
|
||||||
|
|
||||||
|
for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
|
||||||
|
{
|
||||||
|
PkgIterator Pkg(Cache,*I);
|
||||||
|
FileNames[Pkg->ID] = string();
|
||||||
|
|
||||||
|
// Skip packages to erase
|
||||||
|
if (Cache[Pkg].Delete() == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip Packages that need configure only.
|
||||||
|
if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
|
||||||
|
Cache[Pkg].Keep() == true)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip already processed packages
|
||||||
|
if (List->IsNow(Pkg) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
new pkgAcqArchive(Owner,Sources,Recs,Cache[Pkg].InstVerIter(Cache),
|
||||||
|
FileNames[Pkg->ID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::FixMissing - Keep all missing packages /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called to correct the installation when packages could not
|
||||||
|
be downloaded. */
|
||||||
|
bool pkgPackageManager::FixMissing()
|
||||||
|
{
|
||||||
|
pkgProblemResolver Resolve(Cache);
|
||||||
|
List->SetFileList(FileNames);
|
||||||
|
|
||||||
|
bool Bad = false;
|
||||||
|
for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
|
||||||
|
{
|
||||||
|
if (List->IsMissing(I) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Okay, this file is missing and we need it. Mark it for keep
|
||||||
|
Bad = true;
|
||||||
|
Cache.MarkKeep(I);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to empty the list otherwise it will not have the new changes
|
||||||
|
delete List;
|
||||||
|
List = 0;
|
||||||
|
|
||||||
|
if (Bad == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Now downgrade everything that is broken
|
||||||
|
return Resolve.ResolveByKeep() == true && Cache.BrokenCount() == 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// PM::CreateOrderList - Create the ordering class /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This populates the ordering list with all the packages that are
|
||||||
|
going to change. */
|
||||||
|
bool pkgPackageManager::CreateOrderList()
|
||||||
|
{
|
||||||
|
if (List != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
delete List;
|
||||||
|
List = new pkgOrderList(Cache);
|
||||||
|
|
||||||
|
bool NoImmConfigure = _config->FindB("APT::Immediate-Configure",false);
|
||||||
|
|
||||||
|
// Generate the list of affected packages and sort it
|
||||||
|
for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
|
||||||
|
{
|
||||||
|
// Mark the package and its dependends for immediate configuration
|
||||||
|
if (((I->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential ||
|
||||||
|
(I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) &&
|
||||||
|
NoImmConfigure == false)
|
||||||
|
{
|
||||||
|
List->Flag(I,pkgOrderList::Immediate);
|
||||||
|
|
||||||
|
// Look for other packages to make immediate configurea
|
||||||
|
if (Cache[I].InstallVer != 0)
|
||||||
|
for (DepIterator D = Cache[I].InstVerIter(Cache).DependsList();
|
||||||
|
D.end() == false; D++)
|
||||||
|
if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
List->Flag(D.TargetPkg(),pkgOrderList::Immediate);
|
||||||
|
|
||||||
|
// And again with the current version.
|
||||||
|
if (I->CurrentVer != 0)
|
||||||
|
for (DepIterator D = I.CurrentVer().DependsList();
|
||||||
|
D.end() == false; D++)
|
||||||
|
if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
List->Flag(D.TargetPkg(),pkgOrderList::Immediate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not interesting
|
||||||
|
if ((Cache[I].Keep() == true ||
|
||||||
|
Cache[I].InstVerIter(Cache) == I.CurrentVer()) &&
|
||||||
|
I.State() == pkgCache::PkgIterator::NeedsNothing &&
|
||||||
|
(Cache[I].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall &&
|
||||||
|
(I.Purge() != false || Cache[I].Mode != pkgDepCache::ModeDelete ||
|
||||||
|
(Cache[I].iFlags & pkgDepCache::Purge) != pkgDepCache::Purge))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Append it to the list
|
||||||
|
List->push_back(I);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::DepAlwaysTrue - Returns true if this dep is irrelevent /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The restriction on provides is to eliminate the case when provides
|
||||||
|
are transitioning between valid states [ie exim to smail] */
|
||||||
|
bool pkgPackageManager::DepAlwaysTrue(DepIterator D)
|
||||||
|
{
|
||||||
|
if (D.TargetPkg()->ProvidesList != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((Cache[D] & pkgDepCache::DepInstall) != 0 &&
|
||||||
|
(Cache[D] & pkgDepCache::DepNow) != 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::CheckRConflicts - Look for reverse conflicts /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This looks over the reverses for a conflicts line that needs early
|
||||||
|
removal. */
|
||||||
|
bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D,
|
||||||
|
const char *Ver)
|
||||||
|
{
|
||||||
|
for (;D.end() == false; D++)
|
||||||
|
{
|
||||||
|
if (D->Type != pkgCache::Dep::Conflicts && D->Type != pkgCache::Dep::Obsoletes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// The package hasnt been changed
|
||||||
|
if (List->IsNow(Pkg) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Ignore self conflicts, ignore conflicts from irrelevent versions
|
||||||
|
if (D.ParentPkg() == Pkg || D.ParentVer() != D.ParentPkg().CurrentVer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_system->checkDep(D.TargetVer(),Ver,D->CompareOp) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (EarlyRemove(D.ParentPkg()) == false)
|
||||||
|
return _error->Error("Reverse conflicts early remove for package '%s' failed",
|
||||||
|
Pkg.Name());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::ConfigureAll - Run the all out configuration /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This configures every package. It is assumed they are all unpacked and
|
||||||
|
that the final configuration is valid. */
|
||||||
|
bool pkgPackageManager::ConfigureAll()
|
||||||
|
{
|
||||||
|
pkgOrderList OList(Cache);
|
||||||
|
|
||||||
|
// Populate the order list
|
||||||
|
for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
|
||||||
|
if (List->IsFlag(pkgCache::PkgIterator(Cache,*I),
|
||||||
|
pkgOrderList::UnPacked) == true)
|
||||||
|
OList.push_back(*I);
|
||||||
|
|
||||||
|
if (OList.OrderConfigure() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Perform the configuring
|
||||||
|
for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
|
||||||
|
{
|
||||||
|
PkgIterator Pkg(Cache,*I);
|
||||||
|
|
||||||
|
if (Configure(Pkg) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::SmartConfigure - Perform immediate configuration of the pkg /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This routine scheduals the configuration of the given package and all
|
||||||
|
of it's dependents. */
|
||||||
|
bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
pkgOrderList OList(Cache);
|
||||||
|
|
||||||
|
if (DepAdd(OList,Pkg) == false) {
|
||||||
|
cout<<"AAA"<<endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OList.OrderConfigure() == false) {
|
||||||
|
cout<<"BBB"<<endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the configuring
|
||||||
|
for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++)
|
||||||
|
{
|
||||||
|
PkgIterator Pkg(Cache,*I);
|
||||||
|
|
||||||
|
if (Configure(Pkg) == false) {
|
||||||
|
cout<<"CCC"<<endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity Check
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::Configured) == false) {
|
||||||
|
cout<<"DDD"<<endl;
|
||||||
|
return _error->Error("Internal error, could not immediate configure %s",Pkg.Name());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::DepAdd - Add all dependents to the oder list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This recursively adds all dependents to the order list */
|
||||||
|
bool pkgPackageManager::DepAdd(pkgOrderList &OList,PkgIterator Pkg,int Depth)
|
||||||
|
{
|
||||||
|
if (OList.IsFlag(Pkg,pkgOrderList::Added) == true)
|
||||||
|
return true;
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::Configured) == true)
|
||||||
|
return true;
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
// Put the package on the list
|
||||||
|
OList.push_back(Pkg);
|
||||||
|
OList.Flag(Pkg,pkgOrderList::Added);
|
||||||
|
Depth++;
|
||||||
|
|
||||||
|
// Check the dependencies to see if they are all satisfied.
|
||||||
|
bool Bad = false;
|
||||||
|
for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;)
|
||||||
|
{
|
||||||
|
if (D->Type != pkgCache::Dep::Depends && D->Type != pkgCache::Dep::PreDepends)
|
||||||
|
{
|
||||||
|
D++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grok or groups
|
||||||
|
Bad = true;
|
||||||
|
for (bool LastOR = true; D.end() == false && LastOR == true; D++)
|
||||||
|
{
|
||||||
|
LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
|
||||||
|
|
||||||
|
if (Bad == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Version **VList = D.AllTargets();
|
||||||
|
for (Version **I = VList; *I != 0 && Bad == true; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(Cache,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
// See if the current version is ok
|
||||||
|
if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true &&
|
||||||
|
Pkg.State() == PkgIterator::NeedsNothing)
|
||||||
|
{
|
||||||
|
Bad = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not the install version
|
||||||
|
if (Cache[Pkg].InstallVer != *I ||
|
||||||
|
(Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
|
||||||
|
continue;
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == true)
|
||||||
|
Bad = !DepAdd(OList,Pkg,Depth);
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::Configured) == true)
|
||||||
|
Bad = false;
|
||||||
|
}
|
||||||
|
delete [] VList;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Bad == true)
|
||||||
|
{
|
||||||
|
OList.Flag(Pkg,0,pkgOrderList::Added);
|
||||||
|
OList.pop_back();
|
||||||
|
Depth--;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Depth--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::EarlyRemove - Perform removal of packages before their time /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is called to deal with conflicts arising from unpacking */
|
||||||
|
bool pkgPackageManager::EarlyRemove(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
if (List->IsNow(Pkg) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Already removed it
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::Removed) == true)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Woops, it will not be re-installed!
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::InList) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Essential packages get special treatment
|
||||||
|
bool IsEssential = false;
|
||||||
|
if ((Pkg->Flags & pkgCache::Flag::Essential) != 0)
|
||||||
|
IsEssential = true;
|
||||||
|
|
||||||
|
/* Check for packages that are the dependents of essential packages and
|
||||||
|
promote them too */
|
||||||
|
if (Pkg->CurrentVer != 0)
|
||||||
|
{
|
||||||
|
for (DepIterator D = Pkg.RevDependsList(); D.end() == false &&
|
||||||
|
IsEssential == false; D++)
|
||||||
|
if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends)
|
||||||
|
if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0)
|
||||||
|
IsEssential = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsEssential == true)
|
||||||
|
{
|
||||||
|
if (_config->FindB("APT::Force-LoopBreak",false) == false)
|
||||||
|
return _error->Error(_("This installation run will require temporarily "
|
||||||
|
"removing the essential package %s due to a "
|
||||||
|
"Conflicts/Pre-Depends loop. This is often bad, "
|
||||||
|
"but if you really want to do it, activate the "
|
||||||
|
"APT::Force-LoopBreak option."),Pkg.Name());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Res = SmartRemove(Pkg);
|
||||||
|
if (Cache[Pkg].Delete() == false)
|
||||||
|
List->Flag(Pkg,pkgOrderList::Removed,pkgOrderList::States);
|
||||||
|
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::SmartRemove - Removal Helper /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
if (List->IsNow(Pkg) == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
|
||||||
|
if (Cache[Pkg].Replaced())
|
||||||
|
return true;
|
||||||
|
return Remove(Pkg,(Cache[Pkg].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::SmartUnPack - Install helper /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This performs the task of handling pre-depends. */
|
||||||
|
bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
|
||||||
|
{
|
||||||
|
// Check if it is already unpacked
|
||||||
|
if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
|
||||||
|
Cache[Pkg].Keep() == true)
|
||||||
|
{
|
||||||
|
List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true) {
|
||||||
|
if (SmartConfigure(Pkg) == false)
|
||||||
|
return _error->Error("Internal Error, Could not perform immediate configuration: %s",
|
||||||
|
Pkg.Name());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if this packages install version has any predependencies
|
||||||
|
that are not met by 'now' packages. */
|
||||||
|
for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
|
||||||
|
D.end() == false; )
|
||||||
|
{
|
||||||
|
// Compute a single dependency element (glob or)
|
||||||
|
pkgCache::DepIterator Start;
|
||||||
|
pkgCache::DepIterator End;
|
||||||
|
D.GlobOr(Start,End);
|
||||||
|
|
||||||
|
while (End->Type == pkgCache::Dep::PreDepends)
|
||||||
|
{
|
||||||
|
// Look for possible ok targets.
|
||||||
|
Version **VList = Start.AllTargets();
|
||||||
|
bool Bad = true;
|
||||||
|
for (Version **I = VList; *I != 0 && Bad == true; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(Cache,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
// See if the current version is ok
|
||||||
|
if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true &&
|
||||||
|
Pkg.State() == PkgIterator::NeedsNothing)
|
||||||
|
{
|
||||||
|
Bad = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for something that could be configured.
|
||||||
|
for (Version **I = VList; *I != 0 && Bad == true; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(Cache,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
// Not the install version
|
||||||
|
if (Cache[Pkg].InstallVer != *I ||
|
||||||
|
(Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Bad = !SmartConfigure(Pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] VList;
|
||||||
|
|
||||||
|
/* If this or element did not match then continue on to the
|
||||||
|
next or element until a matching element is found*/
|
||||||
|
if (Bad == true)
|
||||||
|
{
|
||||||
|
if (Start == End)
|
||||||
|
return _error->Error("Internal Error, Couldn't configure a pre-depend: %s",
|
||||||
|
Pkg.Name());
|
||||||
|
Start++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (End->Type == pkgCache::Dep::Conflicts || End->Type == pkgCache::Dep::Obsoletes)
|
||||||
|
{
|
||||||
|
/* Look for conflicts. Two packages that are both in the install
|
||||||
|
state cannot conflict so we don't check.. */
|
||||||
|
Version **VList = End.AllTargets();
|
||||||
|
for (Version **I = VList; *I != 0; I++)
|
||||||
|
{
|
||||||
|
VerIterator Ver(Cache,*I);
|
||||||
|
PkgIterator Pkg = Ver.ParentPkg();
|
||||||
|
|
||||||
|
// See if the current version is conflicting
|
||||||
|
// and that it's not obsoleting a virtual package
|
||||||
|
if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true &&
|
||||||
|
!(Pkg->ProvidesList == 0 && End->Type == pkgCache::Dep::Obsoletes))
|
||||||
|
{
|
||||||
|
if (EarlyRemove(Pkg) == false)
|
||||||
|
return _error->Error("Internal Error, Could not early remove %s",Pkg.Name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete [] VList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for reverse conflicts.
|
||||||
|
if (CheckRConflicts(Pkg,Pkg.RevDependsList(),
|
||||||
|
Cache[Pkg].InstVerIter(Cache).VerStr()) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList();
|
||||||
|
P.end() == false; P++)
|
||||||
|
CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
|
||||||
|
|
||||||
|
if (Install(Pkg,FileNames[Pkg->ID]) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
|
||||||
|
|
||||||
|
// Perform immedate configuration of the package.
|
||||||
|
if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true) {
|
||||||
|
if (SmartConfigure(Pkg) == false)
|
||||||
|
return _error->Error("Internal Error, Could not perform immediate configuration");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::OrderInstall - Installation ordering routine /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
pkgPackageManager::OrderResult pkgPackageManager::OrderInstall()
|
||||||
|
{
|
||||||
|
for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
|
||||||
|
{
|
||||||
|
// Not interesting
|
||||||
|
if ((Cache[I].Keep() == true ||
|
||||||
|
Cache[I].InstVerIter(Cache) == I.CurrentVer()) &&
|
||||||
|
I.State() == pkgCache::PkgIterator::NeedsNothing &&
|
||||||
|
(Cache[I].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall &&
|
||||||
|
(I.Purge() != false || Cache[I].Mode != pkgDepCache::ModeDelete ||
|
||||||
|
(Cache[I].iFlags & pkgDepCache::Purge) != pkgDepCache::Purge))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Perform a delete or an install
|
||||||
|
if (Cache[I].Delete() == true)
|
||||||
|
{
|
||||||
|
if (!Cache[I].Replaced() && !Remove(I))
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (Install(I, FileNames[I->ID]) == false)
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
return Completed;
|
||||||
|
#if 0
|
||||||
|
if (CreateOrderList() == false)
|
||||||
|
return Failed;
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
if (Debug == true)
|
||||||
|
clog << "Begining to order" << endl;
|
||||||
|
|
||||||
|
if (List->OrderUnpack(FileNames) == false)
|
||||||
|
{
|
||||||
|
_error->Error("Internal ordering error");
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Debug == true)
|
||||||
|
clog << "Done ordering" << endl;
|
||||||
|
|
||||||
|
bool DoneSomething = false;
|
||||||
|
for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
|
||||||
|
{
|
||||||
|
PkgIterator Pkg(Cache,*I);
|
||||||
|
|
||||||
|
if (List->IsNow(Pkg) == false)
|
||||||
|
{
|
||||||
|
if (Debug == true)
|
||||||
|
clog << "Skipping already done " << Pkg.Name() << endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (List->IsMissing(Pkg) == true)
|
||||||
|
{
|
||||||
|
if (Debug == true)
|
||||||
|
clog << "Sequence completed at " << Pkg.Name() << endl;
|
||||||
|
if (DoneSomething == false)
|
||||||
|
{
|
||||||
|
_error->Error("Internal Error, ordering was unable to handle the media swap");
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
return Incomplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (Cache[Pkg].Keep() == true &&
|
||||||
|
Pkg.State() == pkgCache::PkgIterator::NeedsNothing &&
|
||||||
|
(Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)
|
||||||
|
{
|
||||||
|
_error->Error("Internal Error, trying to manipulate a kept package");
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a delete or an install
|
||||||
|
if (Cache[Pkg].Delete() == true)
|
||||||
|
{
|
||||||
|
if (SmartRemove(Pkg) == false)
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (SmartUnPack(Pkg) == false)
|
||||||
|
return Failed;
|
||||||
|
DoneSomething = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final run through the configure phase
|
||||||
|
if (ConfigureAll() == false)
|
||||||
|
return Failed;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++)
|
||||||
|
{
|
||||||
|
if (List->IsFlag(*I,pkgOrderList::Configured) == false)
|
||||||
|
{
|
||||||
|
_error->Error("Internal error, packages left unconfigured. %s",
|
||||||
|
PkgIterator(Cache,*I).Name());
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Completed;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// PM::DoInstall - Does the installation /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This uses the filenames in FileNames and the information in the
|
||||||
|
DepCache to perform the installation of packages.*/
|
||||||
|
pkgPackageManager::OrderResult pkgPackageManager::DoInstall()
|
||||||
|
{
|
||||||
|
OrderResult Res = OrderInstall();
|
||||||
|
if (Res != Failed)
|
||||||
|
if (Go() == false)
|
||||||
|
return Failed;
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
93
apt/apt-pkg/packagemanager.h
Normal file
93
apt/apt-pkg/packagemanager.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: packagemanager.h,v 1.2 2000/09/26 14:22:14 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Package Manager - Abstacts the package manager
|
||||||
|
|
||||||
|
Three steps are
|
||||||
|
- Aquiration of archives (stores the list of final file names)
|
||||||
|
- Sorting of operations
|
||||||
|
- Invokation of package manager
|
||||||
|
|
||||||
|
This is the final stage when the package cache entities get converted
|
||||||
|
into file names and the state stored in a DepCache is transformed
|
||||||
|
into a series of operations.
|
||||||
|
|
||||||
|
In the final scheme of things this may serve as a director class to
|
||||||
|
access the actual install methods based on the file type being
|
||||||
|
installed.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Header section: pkglib
|
||||||
|
#ifndef PKGLIB_PACKAGEMANAGER_H
|
||||||
|
#define PKGLIB_PACKAGEMANAGER_H
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/packagemanager.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <apt-pkg/pkgcache.h>
|
||||||
|
|
||||||
|
class pkgAcquire;
|
||||||
|
class pkgDepCache;
|
||||||
|
class pkgSourceList;
|
||||||
|
class pkgOrderList;
|
||||||
|
class pkgRecords;
|
||||||
|
class pkgPackageManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum OrderResult {Completed,Failed,Incomplete};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
string *FileNames;
|
||||||
|
pkgDepCache &Cache;
|
||||||
|
pkgOrderList *List;
|
||||||
|
bool Debug;
|
||||||
|
|
||||||
|
// Bring some usefull types into the local scope
|
||||||
|
typedef pkgCache::PkgIterator PkgIterator;
|
||||||
|
typedef pkgCache::VerIterator VerIterator;
|
||||||
|
typedef pkgCache::DepIterator DepIterator;
|
||||||
|
typedef pkgCache::PrvIterator PrvIterator;
|
||||||
|
typedef pkgCache::Version Version;
|
||||||
|
typedef pkgCache::Package Package;
|
||||||
|
|
||||||
|
bool DepAdd(pkgOrderList &Order,PkgIterator P,int Depth = 0);
|
||||||
|
OrderResult OrderInstall();
|
||||||
|
bool CheckRConflicts(PkgIterator Pkg,DepIterator Dep,const char *Ver);
|
||||||
|
bool CreateOrderList();
|
||||||
|
|
||||||
|
// Analysis helpers
|
||||||
|
bool DepAlwaysTrue(DepIterator D);
|
||||||
|
|
||||||
|
// Install helpers
|
||||||
|
bool ConfigureAll();
|
||||||
|
bool SmartConfigure(PkgIterator Pkg);
|
||||||
|
bool SmartUnPack(PkgIterator Pkg);
|
||||||
|
bool SmartRemove(PkgIterator Pkg);
|
||||||
|
bool EarlyRemove(PkgIterator Pkg);
|
||||||
|
|
||||||
|
// The Actuall installation implementation
|
||||||
|
virtual bool Install(PkgIterator /*Pkg*/,string /*File*/) {return false;};
|
||||||
|
virtual bool Configure(PkgIterator /*Pkg*/) {return false;};
|
||||||
|
virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;};
|
||||||
|
virtual bool Go() {return true;};
|
||||||
|
virtual void Reset() {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Main action members
|
||||||
|
bool GetArchives(pkgAcquire *Owner,pkgSourceList *Sources,
|
||||||
|
pkgRecords *Recs);
|
||||||
|
OrderResult DoInstall();
|
||||||
|
bool FixMissing();
|
||||||
|
|
||||||
|
pkgPackageManager(pkgDepCache &Cache);
|
||||||
|
virtual ~pkgPackageManager();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
545
apt/apt-pkg/pkgcache.cc
Normal file
545
apt/apt-pkg/pkgcache.cc
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: pkgcache.cc,v 1.11 2001/06/25 16:16:18 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Package Cache - Accessor code for the cache
|
||||||
|
|
||||||
|
Please see doc/apt-pkg/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 /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/pkgcache.h"
|
||||||
|
#pragma implementation "apt-pkg/cacheiterators.h"
|
||||||
|
#endif
|
||||||
|
#include <apt-pkg/pkgcache.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
#include <apt-pkg/systemfactory.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <system.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 = 3;
|
||||||
|
MinorVersion = 7;
|
||||||
|
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);
|
||||||
|
VerFileSz = sizeof(pkgCache::VerFile);
|
||||||
|
|
||||||
|
PackageCount = 0;
|
||||||
|
VersionCount = 0;
|
||||||
|
DependsCount = 0;
|
||||||
|
PackageFileCount = 0;
|
||||||
|
VerFileCount = 0;
|
||||||
|
ProvidesCount = 0;
|
||||||
|
MaxVerFileSize = 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 &&
|
||||||
|
VerFileSz == Against.VerFileSz &&
|
||||||
|
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();
|
||||||
|
VerFileP = (VerFile *)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();
|
||||||
|
|
||||||
|
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) const
|
||||||
|
{
|
||||||
|
unsigned long Hash = 0;
|
||||||
|
#if 0
|
||||||
|
for (const char *I = Str.begin(); I != Str.end(); I++)
|
||||||
|
Hash = 5*Hash + tolower(*I);
|
||||||
|
#else
|
||||||
|
for (const char *I = Str.begin(); I != Str.end(); I++)
|
||||||
|
Hash = 5*Hash + *I;
|
||||||
|
#endif
|
||||||
|
return Hash % _count(HeaderP->HashTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long pkgCache::sHash(const char *Str) const
|
||||||
|
{
|
||||||
|
unsigned long Hash = 0;
|
||||||
|
#if 0
|
||||||
|
for (const char *I = Str; *I != 0; I++)
|
||||||
|
Hash = 5*Hash + tolower(*I);
|
||||||
|
#else
|
||||||
|
for (const char *I = Str; *I != 0; I++)
|
||||||
|
Hash = 5*Hash + *I;
|
||||||
|
#endif
|
||||||
|
return Hash % _count(HeaderP->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 0
|
||||||
|
if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
|
||||||
|
stringcasecmp(Name.begin(),Name.end(),StrP + Pkg->Name) == 0)
|
||||||
|
return PkgIterator(*this,Pkg);
|
||||||
|
#else
|
||||||
|
if (Pkg->Name != 0 && StrP[Pkg->Name] == Name[0] &&
|
||||||
|
stringcmp(Name.begin(),Name.end(),StrP + Pkg->Name) == 0)
|
||||||
|
return PkgIterator(*this,Pkg);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return PkgIterator(*this,0);
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Cache::Priority - Convert a priority value to a string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
const char *pkgCache::Priority(unsigned char Prio)
|
||||||
|
{
|
||||||
|
const char *Mapping[] = {0,"important","required","standard","optional","extra"};
|
||||||
|
if (Prio < _count(Mapping))
|
||||||
|
return Mapping[Prio];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Cache::GetCandidateVer - Returns the Candidate install version /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* The default just returns the highest available version that is not
|
||||||
|
a source and automatic */
|
||||||
|
pkgCache::VerIterator pkgCache::GetCandidateVer(PkgIterator Pkg,
|
||||||
|
bool AllowCurrent)
|
||||||
|
{
|
||||||
|
/* Not source/not automatic versions cannot be a candidate version
|
||||||
|
unless they are already installed */
|
||||||
|
VerIterator Last(*this,0);
|
||||||
|
|
||||||
|
for (VerIterator I = Pkg.VersionList(); I.end() == false; I++)
|
||||||
|
{
|
||||||
|
if (Pkg.CurrentVer() == I && AllowCurrent == true)
|
||||||
|
return I;
|
||||||
|
|
||||||
|
for (VerFileIterator J = I.FileList(); J.end() == false; J++)
|
||||||
|
{
|
||||||
|
if ((J.File()->Flags & Flag::NotSource) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Stash the highest version of a not-automatic source, we use it
|
||||||
|
if there is nothing better */
|
||||||
|
if ((J.File()->Flags & Flag::NotAutomatic) != 0)
|
||||||
|
{
|
||||||
|
if (Last.end() == true)
|
||||||
|
Last = I;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return I;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Last;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
|
||||||
|
// Bases for iterator classes /*{{{*/
|
||||||
|
void pkgCache::VerIterator::_dummy() {}
|
||||||
|
void pkgCache::DepIterator::_dummy() {}
|
||||||
|
void pkgCache::PrvIterator::_dummy() {}
|
||||||
|
/*}}}*/
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/*}}}*/
|
||||||
|
// 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->InstState == pkgCache::State::ReInstReq ||
|
||||||
|
Pkg->InstState == pkgCache::State::HoldReInstReq)
|
||||||
|
return NeedsUnpack;
|
||||||
|
|
||||||
|
if (Pkg->CurrentState == pkgCache::State::UnPacked ||
|
||||||
|
Pkg->CurrentState == pkgCache::State::HalfConfigured)
|
||||||
|
return NeedsConfigure;
|
||||||
|
|
||||||
|
if (Pkg->CurrentState == pkgCache::State::HalfInstalled ||
|
||||||
|
Pkg->InstState != pkgCache::State::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 == pkgCache::Dep::Conflicts ||
|
||||||
|
Dep->Type == pkgCache::Dep::Obsoletes ||
|
||||||
|
Dep->Type == pkgCache::Dep::Depends ||
|
||||||
|
Dep->Type == pkgCache::Dep::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = PStart.OwnerPkg();
|
||||||
|
// Check for non dups
|
||||||
|
if (P.end() != true)
|
||||||
|
return true;
|
||||||
|
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. The resulting pointer
|
||||||
|
must be delete [] 'd */
|
||||||
|
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 (_system->checkDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((Dep->Type == pkgCache::Dep::Conflicts
|
||||||
|
|| Dep->Type == pkgCache::Dep::Obsoletes) &&
|
||||||
|
ParentPkg() == I.ParentPkg())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Size++;
|
||||||
|
if (Res != 0)
|
||||||
|
*End++ = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follow all provides
|
||||||
|
for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
|
||||||
|
{
|
||||||
|
if (_system->checkDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((Dep->Type == pkgCache::Dep::Conflicts
|
||||||
|
|| Dep->Type == pkgCache::Dep::Obsoletes) &&
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepIterator::CompType - Return a string describing the compare type /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This returns a string representation of the dependency compare
|
||||||
|
type */
|
||||||
|
const char *pkgCache::DepIterator::CompType()
|
||||||
|
{
|
||||||
|
const char *Ops[] = {"","<=",">=","<",">","=","!="};
|
||||||
|
if ((unsigned)(Dep->CompareOp & 0xF) < 7)
|
||||||
|
return Ops[Dep->CompareOp & 0xF];
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepIterator::DepType - Return a string describing the dep type /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
const char *pkgCache::DepIterator::DepType()
|
||||||
|
{
|
||||||
|
const char *Types[] = {"","Depends","PreDepends","Suggests",
|
||||||
|
"Recommends","Conflicts","Replaces","Obsoletes"};
|
||||||
|
if (Dep->Type < 8)
|
||||||
|
return Types[Dep->Type];
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// DepIterator::GlobOr - Compute an OR group /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This Takes an iterator, iterates past the current dependency grouping
|
||||||
|
and returns Start and End so that so End is the final element
|
||||||
|
in the group, if End == Start then D is End++ and End is the
|
||||||
|
dependency D was pointing to. Use in loops to iterate sensibly. */
|
||||||
|
void pkgCache::DepIterator::GlobOr(DepIterator &Start,DepIterator &End)
|
||||||
|
{
|
||||||
|
// Compute a single dependency element (glob or)
|
||||||
|
Start = *this;
|
||||||
|
End = *this;
|
||||||
|
for (bool LastOR = true; end() == false && LastOR == true;)
|
||||||
|
{
|
||||||
|
LastOR = (Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
|
||||||
|
(*this)++;
|
||||||
|
if (LastOR == true)
|
||||||
|
End = (*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// VerIterator::Downloadable - Checks if the version is downloadable /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgCache::VerIterator::Downloadable() const
|
||||||
|
{
|
||||||
|
VerFileIterator Files = FileList();
|
||||||
|
for (; Files.end() == false; Files++)
|
||||||
|
if ((Files.File()->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// VerIterator::PriorityType - Return a string describing the priority /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
const char *pkgCache::VerIterator::PriorityType()
|
||||||
|
{
|
||||||
|
const char *Types[] = {"","Important","Required","Standard",
|
||||||
|
"Optional","Extra"};
|
||||||
|
if (Ver->Priority < 6)
|
||||||
|
return Types[Ver->Priority];
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// VerIterator::Automatic - Check if this version is 'automatic' /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This checks to see if any of the versions files are not NotAutomatic.
|
||||||
|
True if this version is selectable for automatic installation. */
|
||||||
|
bool pkgCache::VerIterator::Automatic() const
|
||||||
|
{
|
||||||
|
VerFileIterator Files = FileList();
|
||||||
|
for (; Files.end() == false; Files++)
|
||||||
|
if ((Files.File()->Flags & pkgCache::Flag::NotAutomatic) != pkgCache::Flag::NotAutomatic)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// VerIterator::NewestFile - Return the newest file version relation /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This looks at the version numbers associated with all of the sources
|
||||||
|
this version is in and returns the highest.*/
|
||||||
|
pkgCache::VerFileIterator pkgCache::VerIterator::NewestFile() const
|
||||||
|
{
|
||||||
|
VerFileIterator Files = FileList();
|
||||||
|
VerFileIterator Highest = Files;
|
||||||
|
for (; Files.end() == false; Files++)
|
||||||
|
{
|
||||||
|
if (_system->versionCompare(Files.File().Version(),Highest.File().Version()) > 0)
|
||||||
|
Highest = Files;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Highest;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
281
apt/apt-pkg/pkgcache.h
Normal file
281
apt/apt-pkg/pkgcache.h
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: pkgcache.h,v 1.2 2000/09/18 18:34:42 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Cache - Structure definitions for the cache file
|
||||||
|
|
||||||
|
Please see doc/apt-pkg/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
|
||||||
|
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma interface "apt-pkg/pkgcache.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <time.h>
|
||||||
|
#include <apt-pkg/mmap.h>
|
||||||
|
|
||||||
|
class pkgCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Cache element predeclarations
|
||||||
|
struct Header;
|
||||||
|
struct Package;
|
||||||
|
struct PackageFile;
|
||||||
|
struct Version;
|
||||||
|
struct Provides;
|
||||||
|
struct Dependency;
|
||||||
|
struct StringItem;
|
||||||
|
struct VerFile;
|
||||||
|
|
||||||
|
// Iterators
|
||||||
|
class PkgIterator;
|
||||||
|
class VerIterator;
|
||||||
|
class DepIterator;
|
||||||
|
class PrvIterator;
|
||||||
|
class PkgFileIterator;
|
||||||
|
class VerFileIterator;
|
||||||
|
friend PkgIterator;
|
||||||
|
friend VerIterator;
|
||||||
|
friend DepIterator;
|
||||||
|
friend PrvIterator;
|
||||||
|
friend PkgFileIterator;
|
||||||
|
friend VerFileIterator;
|
||||||
|
|
||||||
|
// These are all the constants used in the cache structures
|
||||||
|
struct Dep
|
||||||
|
{
|
||||||
|
enum DepType {Depends=1,PreDepends=2,Suggests=3,Recommends=4,
|
||||||
|
Conflicts=5,Replaces=6,Obsoletes=7};
|
||||||
|
enum DepCompareOp {Or=0x10,NoOp=0,LessEq=0x1,GreaterEq=0x2,Less=0x3,
|
||||||
|
Greater=0x4,Equals=0x5,NotEquals=0x6};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
enum VerPriority {Important=1,Required=2,Standard=3,Optional=4,Extra=5};
|
||||||
|
enum PkgSelectedState {Unknown=0,Install=1,Hold=2,DeInstall=3,Purge=4};
|
||||||
|
enum PkgInstState {Ok=0,ReInstReq=1,HoldInst=2,HoldReInstReq=3};
|
||||||
|
enum PkgCurrentState {NotInstalled=0,UnPacked=1,HalfConfigured=2,
|
||||||
|
HalfInstalled=4,ConfigFiles=5,Installed=6};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Flag
|
||||||
|
{
|
||||||
|
enum PkgFlags {Auto=(1<<0),Essential=(1<<3),Important=(1<<4)};
|
||||||
|
enum PkgFFlags {NotSource=(1<<0),NotAutomatic=(1<<1)};
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Memory mapped cache file
|
||||||
|
string CacheFile;
|
||||||
|
MMap ⤅
|
||||||
|
|
||||||
|
unsigned long sHash(string S) const;
|
||||||
|
unsigned long sHash(const char *S) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Pointers to the arrays of items
|
||||||
|
Header *HeaderP;
|
||||||
|
Package *PkgP;
|
||||||
|
VerFile *VerFileP;
|
||||||
|
PackageFile *PkgFileP;
|
||||||
|
Version *VerP;
|
||||||
|
Provides *ProvideP;
|
||||||
|
Dependency *DepP;
|
||||||
|
StringItem *StringItemP;
|
||||||
|
char *StrP;
|
||||||
|
|
||||||
|
virtual bool ReMap();
|
||||||
|
inline bool Sync() {return Map.Sync();};
|
||||||
|
inline MMap &GetMap() {return Map;};
|
||||||
|
|
||||||
|
// String hashing function (512 range)
|
||||||
|
inline unsigned long Hash(string S) const {return sHash(S);};
|
||||||
|
inline unsigned long Hash(const char *S) const {return sHash(S);};
|
||||||
|
|
||||||
|
// Usefull transformation things
|
||||||
|
const char *Priority(unsigned char Priority);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
PkgIterator FindPkg(string Name);
|
||||||
|
Header &Head() {return *HeaderP;};
|
||||||
|
inline PkgIterator PkgBegin();
|
||||||
|
inline PkgIterator PkgEnd();
|
||||||
|
inline PkgFileIterator FileBegin();
|
||||||
|
inline PkgFileIterator FileEnd();
|
||||||
|
VerIterator GetCandidateVer(PkgIterator Pkg,bool AllowCurrent = true);
|
||||||
|
|
||||||
|
pkgCache(MMap &Map);
|
||||||
|
virtual ~pkgCache() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Header structure
|
||||||
|
struct pkgCache::Header
|
||||||
|
{
|
||||||
|
// Signature information
|
||||||
|
unsigned long Signature;
|
||||||
|
short MajorVersion;
|
||||||
|
short MinorVersion;
|
||||||
|
bool Dirty;
|
||||||
|
|
||||||
|
// Size of structure values
|
||||||
|
unsigned short HeaderSz;
|
||||||
|
unsigned short PackageSz;
|
||||||
|
unsigned short PackageFileSz;
|
||||||
|
unsigned short VersionSz;
|
||||||
|
unsigned short DependencySz;
|
||||||
|
unsigned short ProvidesSz;
|
||||||
|
unsigned short VerFileSz;
|
||||||
|
|
||||||
|
// Structure counts
|
||||||
|
unsigned long PackageCount;
|
||||||
|
unsigned long VersionCount;
|
||||||
|
unsigned long DependsCount;
|
||||||
|
unsigned long PackageFileCount;
|
||||||
|
unsigned long VerFileCount;
|
||||||
|
unsigned long ProvidesCount;
|
||||||
|
|
||||||
|
// Offsets
|
||||||
|
map_ptrloc FileList; // struct PackageFile
|
||||||
|
map_ptrloc StringList; // struct StringItem
|
||||||
|
unsigned long MaxVerFileSize;
|
||||||
|
|
||||||
|
/* Allocation pools, there should be one of these for each structure
|
||||||
|
excluding the header */
|
||||||
|
DynamicMMap::Pool Pools[7];
|
||||||
|
|
||||||
|
// Rapid package name lookup
|
||||||
|
map_ptrloc HashTable[2*1048];
|
||||||
|
|
||||||
|
bool CheckSizes(Header &Against) const;
|
||||||
|
Header();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pkgCache::Package
|
||||||
|
{
|
||||||
|
// Pointers
|
||||||
|
map_ptrloc Name; // Stringtable
|
||||||
|
map_ptrloc VersionList; // Version
|
||||||
|
map_ptrloc TargetVer; // Version
|
||||||
|
map_ptrloc CurrentVer; // Version
|
||||||
|
map_ptrloc TargetDist; // StringTable (StringItem)
|
||||||
|
map_ptrloc Section; // StringTable (StringItem)
|
||||||
|
|
||||||
|
// Linked list
|
||||||
|
map_ptrloc NextPackage; // Package
|
||||||
|
map_ptrloc RevDepends; // Dependency
|
||||||
|
map_ptrloc ProvidesList; // Provides
|
||||||
|
|
||||||
|
// Install/Remove/Purge etc
|
||||||
|
unsigned char SelectedState; // What
|
||||||
|
unsigned char InstState; // Flags
|
||||||
|
unsigned char CurrentState; // State
|
||||||
|
|
||||||
|
unsigned short ID;
|
||||||
|
unsigned long Flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pkgCache::PackageFile
|
||||||
|
{
|
||||||
|
// Names
|
||||||
|
map_ptrloc FileName; // Stringtable
|
||||||
|
map_ptrloc Archive; // Stringtable
|
||||||
|
map_ptrloc Component; // Stringtable
|
||||||
|
map_ptrloc Version; // Stringtable
|
||||||
|
map_ptrloc Origin; // Stringtable
|
||||||
|
map_ptrloc Label; // Stringtable
|
||||||
|
map_ptrloc Architecture; // Stringtable
|
||||||
|
unsigned long Size;
|
||||||
|
unsigned long Flags;
|
||||||
|
|
||||||
|
// Linked list
|
||||||
|
map_ptrloc NextFile; // PackageFile
|
||||||
|
unsigned short ID;
|
||||||
|
time_t mtime; // Modification time for the file
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pkgCache::VerFile
|
||||||
|
{
|
||||||
|
map_ptrloc File; // PackageFile
|
||||||
|
map_ptrloc NextFile; // PkgVerFile
|
||||||
|
map_ptrloc Offset; // File offset
|
||||||
|
unsigned short Size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pkgCache::Version
|
||||||
|
{
|
||||||
|
map_ptrloc VerStr; // Stringtable
|
||||||
|
map_ptrloc Section; // StringTable (StringItem)
|
||||||
|
map_ptrloc Arch; // StringTable
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
map_ptrloc FileList; // VerFile
|
||||||
|
map_ptrloc NextVer; // Version
|
||||||
|
map_ptrloc DependsList; // Dependency
|
||||||
|
map_ptrloc ParentPkg; // Package
|
||||||
|
map_ptrloc ProvidesList; // Provides
|
||||||
|
|
||||||
|
map_ptrloc Size; // These are the .deb size
|
||||||
|
map_ptrloc InstalledSize;
|
||||||
|
unsigned short Hash;
|
||||||
|
unsigned short ID;
|
||||||
|
unsigned char Priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pkgCache::Dependency
|
||||||
|
{
|
||||||
|
map_ptrloc Version; // Stringtable
|
||||||
|
map_ptrloc Package; // Package
|
||||||
|
map_ptrloc NextDepends; // Dependency
|
||||||
|
map_ptrloc NextRevDepends; // Dependency
|
||||||
|
map_ptrloc ParentVer; // Version
|
||||||
|
|
||||||
|
// Specific types of depends
|
||||||
|
unsigned char Type;
|
||||||
|
unsigned char CompareOp;
|
||||||
|
unsigned short ID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pkgCache::Provides
|
||||||
|
{
|
||||||
|
map_ptrloc ParentPkg; // Pacakge
|
||||||
|
map_ptrloc Version; // Version
|
||||||
|
map_ptrloc ProvideVersion; // Stringtable
|
||||||
|
map_ptrloc NextProvides; // Provides
|
||||||
|
map_ptrloc NextPkgProv; // Provides
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pkgCache::StringItem
|
||||||
|
{
|
||||||
|
map_ptrloc String; // Stringtable
|
||||||
|
map_ptrloc NextItem; // StringItem
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <apt-pkg/cacheiterators.h>
|
||||||
|
|
||||||
|
inline pkgCache::PkgIterator pkgCache::PkgBegin()
|
||||||
|
{return PkgIterator(*this);};
|
||||||
|
inline pkgCache::PkgIterator pkgCache::PkgEnd()
|
||||||
|
{return PkgIterator(*this,PkgP);};
|
||||||
|
inline pkgCache::PkgFileIterator pkgCache::FileBegin()
|
||||||
|
{return PkgFileIterator(*this);};
|
||||||
|
inline pkgCache::PkgFileIterator pkgCache::FileEnd()
|
||||||
|
{return PkgFileIterator(*this,PkgFileP);};
|
||||||
|
|
||||||
|
#endif
|
468
apt/apt-pkg/pkgcachegen.cc
Normal file
468
apt/apt-pkg/pkgcachegen.cc
Normal file
@ -0,0 +1,468 @@
|
|||||||
|
// -*- mode: cpp; mode: fold -*-
|
||||||
|
// Description /*{{{*/
|
||||||
|
// $Id: pkgcachegen.cc,v 1.24 2001/12/11 20:50:12 kojima Exp $
|
||||||
|
/* ######################################################################
|
||||||
|
|
||||||
|
Package Cache Generator - Generator for the cache structure.
|
||||||
|
|
||||||
|
This builds the cache structure from the abstract package list parser.
|
||||||
|
|
||||||
|
##################################################################### */
|
||||||
|
/*}}}*/
|
||||||
|
// Include Files /*{{{*/
|
||||||
|
#ifdef __GNUG__
|
||||||
|
#pragma implementation "apt-pkg/pkgcachegen.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <apt-pkg/pkgcachegen.h>
|
||||||
|
#include <apt-pkg/error.h>
|
||||||
|
#include <apt-pkg/progress.h>
|
||||||
|
#include <apt-pkg/sourcelist.h>
|
||||||
|
#include <apt-pkg/configuration.h>
|
||||||
|
#include <apt-pkg/strutl.h>
|
||||||
|
|
||||||
|
#include <apt-pkg/systemfactory.h>
|
||||||
|
|
||||||
|
#include <i18n.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <system.h>
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We set the diry flag and make sure that is written to the disk */
|
||||||
|
pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map,OpProgress &Prog) : Map(Map), Cache(Map), Progress(&Prog)
|
||||||
|
{
|
||||||
|
CurrentFile = 0;
|
||||||
|
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Map.Size() == 0)
|
||||||
|
{
|
||||||
|
Map.RawAllocate(sizeof(pkgCache::Header));
|
||||||
|
*Cache.HeaderP = pkgCache::Header();
|
||||||
|
}
|
||||||
|
Cache.HeaderP->Dirty = true;
|
||||||
|
Map.Sync(0,sizeof(pkgCache::Header));
|
||||||
|
Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
|
||||||
|
memset(UniqHash,0,sizeof(UniqHash));
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* We sync the data then unset the dirty flag in two steps so as to
|
||||||
|
advoid a problem during a crash */
|
||||||
|
pkgCacheGenerator::~pkgCacheGenerator()
|
||||||
|
{
|
||||||
|
if (_error->PendingError() == true)
|
||||||
|
return;
|
||||||
|
if (Map.Sync() == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Cache.HeaderP->Dirty = false;
|
||||||
|
Map.Sync(0,sizeof(pkgCache::Header));
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::MergeList - Merge the package list /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This provides the generation of the entries in the cache. Each loop
|
||||||
|
goes through a single package record from the underlying parse engine. */
|
||||||
|
bool pkgCacheGenerator::MergeList(ListParser &List,
|
||||||
|
pkgCache::VerIterator *OutVer)
|
||||||
|
{
|
||||||
|
List.Owner = this;
|
||||||
|
|
||||||
|
unsigned int Counter = 0;
|
||||||
|
while (List.Step() == true)
|
||||||
|
{
|
||||||
|
// Get a pointer to the package structure
|
||||||
|
string PackageName = List.Package();
|
||||||
|
|
||||||
|
if (PackageName.empty() == true)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pkgCache::PkgIterator Pkg;
|
||||||
|
if (NewPackage(Pkg,PackageName) == false)
|
||||||
|
return _error->Error(_("Error occured while processing %s (NewPackage)"),PackageName.c_str());
|
||||||
|
Counter++;
|
||||||
|
if (Counter % 100 == 0 && Progress != 0)
|
||||||
|
Progress->Progress(List.Offset());
|
||||||
|
|
||||||
|
/* Get a pointer to the version structure. We know the list is sorted
|
||||||
|
so we use that fact in the search. Insertion of new versions is
|
||||||
|
done with correct sorting */
|
||||||
|
string Version = List.Version();
|
||||||
|
if (Version.empty() == true)
|
||||||
|
{
|
||||||
|
if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
|
||||||
|
return _error->Error(_("Error occured while processing %s (UsePackage1)"),PackageName.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgCache::VerIterator Ver = Pkg.VersionList();
|
||||||
|
map_ptrloc *Last = &Pkg->VersionList;
|
||||||
|
int Res = 1;
|
||||||
|
for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
|
||||||
|
{
|
||||||
|
Res = _system->versionCompare(Version.begin(),Version.end(),Ver.VerStr(),
|
||||||
|
Ver.VerStr() + strlen(Ver.VerStr()));
|
||||||
|
if (Res >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We already have a version for this item, record that we saw it */
|
||||||
|
unsigned long Hash = List.VersionHash();
|
||||||
|
bool ToEnd = true;
|
||||||
|
|
||||||
|
if (Res == 0 && Ver->Hash == Hash)
|
||||||
|
{
|
||||||
|
if (List.UsePackage(Pkg,Ver) == false)
|
||||||
|
return _error->Error(_("Error occured while processing %s (UsePackage2)"),PackageName.c_str());
|
||||||
|
|
||||||
|
if (NewFileVer(Ver,List) == false)
|
||||||
|
return _error->Error(_("Error occured while processing %s (NewFileVer1)"),PackageName.c_str());
|
||||||
|
|
||||||
|
// Read only a single record and return
|
||||||
|
if (OutVer != 0)
|
||||||
|
{
|
||||||
|
*OutVer = Ver;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (Res == 0) {
|
||||||
|
cout << _("WARNING: '") << PackageName << _("' has 2 packages with same version but different dependencies. ");
|
||||||
|
cout << _("That usually means a packaging bug.") << endl;
|
||||||
|
|
||||||
|
if (Pkg.CurrentVer() == Ver) {
|
||||||
|
// if this is the currently installed version, then
|
||||||
|
// keep it as the 1st in the same version set
|
||||||
|
ToEnd = false;
|
||||||
|
} else {
|
||||||
|
// if this one is not the currently installed version,
|
||||||
|
// just ignore it. and hope that this package doesn't
|
||||||
|
// have an extra dependency that would fix some
|
||||||
|
// situation... which would be severe a packaging bug anyway
|
||||||
|
// cout << "Skipping package"<<endl;
|
||||||
|
// continue;
|
||||||
|
// apparently have some problems yet, got a case where
|
||||||
|
// an isntalled pkg was undetected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Skip to the end of the same version set
|
||||||
|
if (Res == 0 && ToEnd == true)
|
||||||
|
{
|
||||||
|
for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
|
||||||
|
{
|
||||||
|
Res = _system->versionCompare(Version.begin(),Version.end(),Ver.VerStr(),
|
||||||
|
Ver.VerStr() + strlen(Ver.VerStr()));
|
||||||
|
if (Res != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new version
|
||||||
|
*Last = NewVersion(Ver,Version,*Last);
|
||||||
|
Ver->ParentPkg = Pkg.Index();
|
||||||
|
Ver->Hash = Hash;
|
||||||
|
if (List.NewVersion(Ver) == false)
|
||||||
|
return _error->Error(_("Error occured while processing %s (NewVersion1)"),PackageName.c_str());
|
||||||
|
|
||||||
|
if (List.UsePackage(Pkg,Ver) == false)
|
||||||
|
return _error->Error(_("Error occured while processing %s (UsePackage3)"),PackageName.c_str());
|
||||||
|
|
||||||
|
if (NewFileVer(Ver,List) == false)
|
||||||
|
return _error->Error(_("Error occured while processing %s (NewVersion2)"),PackageName.c_str());
|
||||||
|
|
||||||
|
// Read only a single record and return
|
||||||
|
if (OutVer != 0)
|
||||||
|
{
|
||||||
|
*OutVer = Ver;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::NewPackage - Add a new package /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This creates a new package structure and adds it to the hash table */
|
||||||
|
bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
|
||||||
|
{
|
||||||
|
Pkg = Cache.FindPkg(Name);
|
||||||
|
if (Pkg.end() == false)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Get a structure
|
||||||
|
unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
|
||||||
|
if (Package == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
|
||||||
|
|
||||||
|
// Insert it into the hash table
|
||||||
|
unsigned long Hash = Cache.Hash(Name);
|
||||||
|
Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
|
||||||
|
Cache.HeaderP->HashTable[Hash] = Package;
|
||||||
|
|
||||||
|
// Set the name and the ID
|
||||||
|
Pkg->Name = Map.WriteString(Name);
|
||||||
|
if (Pkg->Name == 0)
|
||||||
|
return false;
|
||||||
|
Pkg->ID = Cache.HeaderP->PackageCount++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
|
||||||
|
ListParser &List)
|
||||||
|
{
|
||||||
|
if (CurrentFile == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Get a structure
|
||||||
|
unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
|
||||||
|
if (VerFile == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
|
||||||
|
VF->File = CurrentFile - Cache.PkgFileP;
|
||||||
|
|
||||||
|
// Link it to the end of the list
|
||||||
|
map_ptrloc *Last = &Ver->FileList;
|
||||||
|
for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++)
|
||||||
|
Last = &V->NextFile;
|
||||||
|
VF->NextFile = *Last;
|
||||||
|
*Last = VF.Index();
|
||||||
|
|
||||||
|
VF->Offset = List.Offset();
|
||||||
|
VF->Size = List.Size();
|
||||||
|
if (Cache.HeaderP->MaxVerFileSize < VF->Size)
|
||||||
|
Cache.HeaderP->MaxVerFileSize = VF->Size;
|
||||||
|
Cache.HeaderP->VerFileCount++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::NewVersion - Create a new Version /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This puts a version structure in the linked list */
|
||||||
|
unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
|
||||||
|
string VerStr,
|
||||||
|
unsigned long Next)
|
||||||
|
{
|
||||||
|
// Get a structure
|
||||||
|
unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
|
||||||
|
if (Version == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Fill it in
|
||||||
|
Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
|
||||||
|
Ver->NextVer = Next;
|
||||||
|
Ver->ID = Cache.HeaderP->VersionCount++;
|
||||||
|
Ver->VerStr = Map.WriteString(VerStr);
|
||||||
|
if (Ver->VerStr == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return Version;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::NewDepends - Create a dependency element /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This creates a dependency element in the tree. It is linked to the
|
||||||
|
version and to the package that it is pointing to. */
|
||||||
|
bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
|
||||||
|
string PackageName,
|
||||||
|
string Version,
|
||||||
|
unsigned int Op,
|
||||||
|
unsigned int Type)
|
||||||
|
{
|
||||||
|
pkgCache &Cache = Owner->Cache;
|
||||||
|
|
||||||
|
// Get a structure
|
||||||
|
unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
|
||||||
|
if (Dependency == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Fill it in
|
||||||
|
pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
|
||||||
|
Dep->ParentVer = Ver.Index();
|
||||||
|
Dep->Type = Type;
|
||||||
|
Dep->CompareOp = Op;
|
||||||
|
Dep->ID = Cache.HeaderP->DependsCount++;
|
||||||
|
|
||||||
|
// Locate the target package
|
||||||
|
pkgCache::PkgIterator Pkg;
|
||||||
|
if (Owner->NewPackage(Pkg,PackageName) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Probe the reverse dependency list for a version string that matches
|
||||||
|
if (Version.empty() == false)
|
||||||
|
{
|
||||||
|
/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++, Hit++)
|
||||||
|
if (I->Version != 0 && I.TargetVer() == Version)
|
||||||
|
Dep->Version = I->Version;*/
|
||||||
|
if (Dep->Version == 0)
|
||||||
|
if ((Dep->Version = WriteString(Version)) == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link it to the package
|
||||||
|
Dep->Package = Pkg.Index();
|
||||||
|
Dep->NextRevDepends = Pkg->RevDepends;
|
||||||
|
Pkg->RevDepends = Dep.Index();
|
||||||
|
|
||||||
|
/* Link it to the version (at the end of the list)
|
||||||
|
Caching the old end point speeds up generation substantially */
|
||||||
|
if (OldDepVer != Ver)
|
||||||
|
{
|
||||||
|
OldDepLast = &Ver->DependsList;
|
||||||
|
for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
|
||||||
|
OldDepLast = &D->NextDepends;
|
||||||
|
OldDepVer = Ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Dep->NextDepends = *OldDepLast;
|
||||||
|
*OldDepLast = Dep.Index();
|
||||||
|
OldDepLast = &Dep->NextDepends;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// ListParser::NewProvides - Create a Provides element /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* */
|
||||||
|
bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
|
||||||
|
string PackageName,
|
||||||
|
string Version)
|
||||||
|
{
|
||||||
|
pkgCache &Cache = Owner->Cache;
|
||||||
|
|
||||||
|
// We do not add self referencing provides
|
||||||
|
if (Ver.ParentPkg().Name() == PackageName)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Get a structure
|
||||||
|
unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
|
||||||
|
if (Provides == 0)
|
||||||
|
return false;
|
||||||
|
Cache.HeaderP->ProvidesCount++;
|
||||||
|
|
||||||
|
// Fill it in
|
||||||
|
pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
|
||||||
|
Prv->Version = Ver.Index();
|
||||||
|
Prv->NextPkgProv = Ver->ProvidesList;
|
||||||
|
Ver->ProvidesList = Prv.Index();
|
||||||
|
|
||||||
|
if (Version.empty() == false)
|
||||||
|
{
|
||||||
|
if (Prv->ProvideVersion == 0)
|
||||||
|
if ((Prv->ProvideVersion = WriteString(Version)) == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate the target package
|
||||||
|
pkgCache::PkgIterator Pkg;
|
||||||
|
if (Owner->NewPackage(Pkg,PackageName) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Link it to the package
|
||||||
|
Prv->ParentPkg = Pkg.Index();
|
||||||
|
Prv->NextProvides = Pkg->ProvidesList;
|
||||||
|
Pkg->ProvidesList = Prv.Index();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is used to select which file is to be associated with all newly
|
||||||
|
added versions. */
|
||||||
|
bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
|
||||||
|
{
|
||||||
|
struct stat Buf;
|
||||||
|
if (stat(File.c_str(),&Buf) == -1)
|
||||||
|
return _error->Errno("stat","Couldn't stat %s",File.c_str());
|
||||||
|
|
||||||
|
// Get some space for the structure
|
||||||
|
CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
|
||||||
|
if (CurrentFile == Cache.PkgFileP)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Fill it in
|
||||||
|
CurrentFile->FileName = Map.WriteString(File);
|
||||||
|
CurrentFile->Size = Buf.st_size;
|
||||||
|
CurrentFile->mtime = Buf.st_mtime;
|
||||||
|
CurrentFile->NextFile = Cache.HeaderP->FileList;
|
||||||
|
CurrentFile->Flags = Flags;
|
||||||
|
CurrentFile->ID = Cache.HeaderP->PackageFileCount;
|
||||||
|
PkgFileName = File;
|
||||||
|
Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
|
||||||
|
Cache.HeaderP->PackageFileCount++;
|
||||||
|
|
||||||
|
if (CurrentFile->FileName == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Progress != 0)
|
||||||
|
Progress->SubProgress(Buf.st_size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
/* This is used to create handles to strings. Given the same text it
|
||||||
|
always returns the same number */
|
||||||
|
unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
|
||||||
|
unsigned int Size)
|
||||||
|
{
|
||||||
|
/* We use a very small transient hash table here, this speeds up generation
|
||||||
|
by a fair amount on slower machines */
|
||||||
|
pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
|
||||||
|
if (Bucket != 0 &&
|
||||||
|
stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
|
||||||
|
return Bucket->String;
|
||||||
|
|
||||||
|
// Search for an insertion point
|
||||||
|
pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
|
||||||
|
int Res = 1;
|
||||||
|
map_ptrloc *Last = &Cache.HeaderP->StringList;
|
||||||
|
for (; I != Cache.StringItemP; Last = &I->NextItem,
|
||||||
|
I = Cache.StringItemP + I->NextItem)
|
||||||
|
{
|
||||||
|
Res = stringcmp(S,S+Size,Cache.StrP + I->String);
|
||||||
|
if (Res >= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match
|
||||||
|
if (Res == 0)
|
||||||
|
{
|
||||||
|
Bucket = I;
|
||||||
|
return I->String;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a structure
|
||||||
|
unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
|
||||||
|
if (Item == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Fill in the structure
|
||||||
|
pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
|
||||||
|
ItemP->NextItem = I - Cache.StringItemP;
|
||||||
|
*Last = Item;
|
||||||
|
ItemP->String = Map.WriteString(S,Size);
|
||||||
|
if (ItemP->String == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Bucket = ItemP;
|
||||||
|
return ItemP->String;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user