summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS8
-rw-r--r--README.ddtp74
-rw-r--r--apt-pkg/acquire-item.cc436
-rw-r--r--apt-pkg/acquire-item.h78
-rw-r--r--apt-pkg/cacheiterators.h83
-rw-r--r--apt-pkg/cdrom.cc47
-rw-r--r--apt-pkg/cdrom.h7
-rw-r--r--apt-pkg/contrib/strutl.cc45
-rw-r--r--apt-pkg/contrib/strutl.h3
-rw-r--r--apt-pkg/deb/debindexfile.cc174
-rw-r--r--apt-pkg/deb/debindexfile.h30
-rw-r--r--apt-pkg/deb/deblistparser.cc43
-rw-r--r--apt-pkg/deb/deblistparser.h4
-rw-r--r--apt-pkg/deb/debmetaindex.cc15
-rw-r--r--apt-pkg/deb/debrecords.cc23
-rw-r--r--apt-pkg/deb/debrecords.h2
-rw-r--r--apt-pkg/indexcopy.cc183
-rw-r--r--apt-pkg/indexcopy.h13
-rw-r--r--apt-pkg/indexfile.cc60
-rw-r--r--apt-pkg/indexfile.h7
-rw-r--r--apt-pkg/init.cc3
-rw-r--r--apt-pkg/init.h2
-rw-r--r--apt-pkg/pkgcache.cc13
-rw-r--r--apt-pkg/pkgcache.h44
-rw-r--r--apt-pkg/pkgcachegen.cc117
-rw-r--r--apt-pkg/pkgcachegen.h6
-rw-r--r--apt-pkg/pkgrecords.cc9
-rw-r--r--apt-pkg/pkgrecords.h2
-rw-r--r--cmdline/apt-cache.cc106
-rw-r--r--debian/changelog1
-rw-r--r--methods/http.cc3
-rw-r--r--methods/makefile9
-rw-r--r--methods/rred.cc262
33 files changed, 1850 insertions, 62 deletions
diff --git a/BUGS b/BUGS
new file mode 100644
index 000000000..6bbc6f839
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,8 @@
+
+DDTP problems:
+--------------
+- apt-get update clean the /var/lib/apt/lists dir
+ from all Translation-$index that are not in the current
+ enviroment or Translations apt variable
+- there needs to be a list of locales (pt, sv, en) that need
+ both language and country code to get the right file
diff --git a/README.ddtp b/README.ddtp
new file mode 100644
index 000000000..98f6109aa
--- /dev/null
+++ b/README.ddtp
@@ -0,0 +1,74 @@
+TODO:
+- URL-Remap for the translation files (to hack around the problem that
+ they are not on any ftp server yet but only on http://ddtp.debian.org/)
+
+Here is the original announcement of the ddtp support:
+
+* To: debian-devel-announce@lists.debian.org
+* Subject: Translate files
+* From: Michael Bramer <grisu@debian.org>
+* Date: Sun, 6 Oct 2002 21:56:06 +0200
+* Mail-followup-to: debian-devel@lists.debian.org
+* Message-id: <20021006195605.GA30516@home.debsupport.de>
+* Old-return-path: <michael@home.debsupport.de>
+* User-agent: Mutt/1.3.28i
+
+Hello all
+
+After some discussion between Anthony Towns (a ftpmaster), Jason
+Gunthorpe (APT Developer) and some DDTP Coordinators we find a way to
+transfer the translated package descriptions from the archive to the
+user.
+
+The translated descriptions need to be downloadable befor any
+installation process, like the other package meta information. We
+choose a new file per languages with all translated package
+descriptions. The package system can download one or more of this
+files at 'apt-get update' time and know the translations.
+
+The new files are names 'Translate-$lang' and the file have this
+rfc822-format:
+ Package: &lt;package-name&gt;
+ Description-md5: &lt;the md5 checksum of the english description&gt;
+ Description-$lang.$encoding: &lt;translated headline&gt;
+ &lt;translated section&gt;
+
+The encoding of the Description is 'UTF-8' in all languages normal.
+The files will be located at 'debian/dists/sid/main/i18n/' on the ftp
+server (for all architecture). In addition of the plain
+'Translate-$lang' file, there will be a 'gz' and a 'bz2' version and
+in future also the new incremental format version.
+
+The &lt;the md5 checksum of the english description&gt; is the md5 checksum
+of the full english description, without the 'Description: '-tag and
+with all spaces and newlines. Look at this example:
+ Description: XXX
+ YYY
+ .
+ ZZZ
+is md5(&quot;XXX\n YYY\n .\n ZZZ\n&quot;) (perl-syntax).
+
+
+A future APT version will download one or some 'Translate-$lang'
+file(s) at 'update'-time. After this download it show a translated
+description instead of the english form, if it found a translated
+description of the package with the right md5 chechsum. The enviroment
+of the user will controlled this process (LANG, LANGUAGE, LC_MESSAGES,
+etc). With this the package system will never show a outdated
+translation.
+
+The translations come all from the DDTP. A daily process on
+ddtp.debian.org make new 'Translated-$lang' files and a script on
+ftp-master request this files and move this to the debian archive.
+Now the first files are accessable at
+ <a href="http://ddtp.debian.org/pdesc/translatefiles/">http://ddtp.debian.org/pdesc/translatefiles/</a>
+
+If you found wrong translations, please read the guides on
+ddtp.debian.org, make a better translation and send this per mail to
+the DDTP server. Don't bug the package maintainer!
+
+Thanks
+Grisu
+--
+Michael Bramer - a Debian Linux Developer <a href="http://www.debsupport.de">http://www.debsupport.de</a>
+PGP: finger grisu@db.debian.org -- Linux Sysadmin -- Use Debian Linux
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc
index dea68f3ee..75a7faa2a 100644
--- a/apt-pkg/acquire-item.cc
+++ b/apt-pkg/acquire-item.cc
@@ -24,6 +24,8 @@
#include <apt-pkg/strutl.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/md5.h>
+#include <apt-pkg/sha1.h>
+#include <apt-pkg/tagfile.h>
#include <apti18n.h>
@@ -31,6 +33,7 @@
#include <unistd.h>
#include <errno.h>
#include <string>
+#include <sstream>
#include <stdio.h>
/*}}}*/
@@ -131,14 +134,410 @@ void pkgAcquire::Item::Rename(string From,string To)
}
/*}}}*/
+
+// AcqDiffIndex::AcqDiffIndex - Constructor
+// ---------------------------------------------------------------------
+/* Get the DiffIndex file first and see if there are patches availabe
+ * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
+ * patches. If anything goes wrong in that process, it will fall back to
+ * the original packages file
+ */
+pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
+ string URI,string URIDesc,string ShortDesc,
+ string ExpectedMD5)
+ : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5), Description(URIDesc)
+{
+
+ Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
+
+ Desc.Description = URIDesc + "/DiffIndex";
+ Desc.Owner = this;
+ Desc.ShortDesc = ShortDesc;
+ Desc.URI = URI + ".diff/Index";
+
+ DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+ DestFile += URItoFileName(URI) + string(".DiffIndex");
+
+ if(Debug)
+ std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
+
+ // look for the current package file
+ CurrentPackagesFile = _config->FindDir("Dir::State::lists");
+ CurrentPackagesFile += URItoFileName(RealURI);
+
+ if(!FileExists(CurrentPackagesFile) ||
+ !_config->FindB("Acquire::Diffs",true)) {
+ // we don't have a pkg file or we don't want to queue
+ if(Debug)
+ std::clog << "No index file or canceld by user" << std::endl;
+ Failed("", NULL);
+ return;
+ }
+
+ if(Debug) {
+ std::clog << "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
+ << CurrentPackagesFile << std::endl;
+ }
+
+ QueueURI(Desc);
+
+}
+
+// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
+// ---------------------------------------------------------------------
+/* The only header we use is the last-modified header. */
+string pkgAcqDiffIndex::Custom600Headers()
+{
+ string Final = _config->FindDir("Dir::State::lists");
+ Final += URItoFileName(RealURI) + string(".IndexDiff");
+
+ if(Debug)
+ std::clog << "Custom600Header-IMS: " << Final << std::endl;
+
+ struct stat Buf;
+ if (stat(Final.c_str(),&Buf) != 0)
+ return "\nIndex-File: true";
+
+ return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
+}
+
+
+bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile)
+{
+ if(Debug)
+ std::clog << "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
+ << std::endl;
+
+ pkgTagSection Tags;
+ string ServerSha1;
+ vector<DiffInfo> available_patches;
+
+ FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
+ pkgTagFile TF(&Fd);
+ if (_error->PendingError() == true)
+ return false;
+
+ if(TF.Step(Tags) == true)
+ {
+ string local_sha1;
+ bool found = false;
+ DiffInfo d;
+ string size;
+
+ string tmp = Tags.FindS("SHA1-Current");
+ std::stringstream ss(tmp);
+ ss >> ServerSha1;
+
+ FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
+ SHA1Summation SHA1;
+ SHA1.AddFD(fd.Fd(), fd.Size());
+ local_sha1 = string(SHA1.Result());
+
+ if(local_sha1 == ServerSha1) {
+ if(Debug)
+ std::clog << "Package file is up-to-date" << std::endl;
+ // set found to true, this will queue a pkgAcqIndexDiffs with
+ // a empty availabe_patches
+ found = true;
+ } else {
+ if(Debug)
+ std::clog << "SHA1-Current: " << ServerSha1 << std::endl;
+
+ // check the historie and see what patches we need
+ string history = Tags.FindS("SHA1-History");
+ std::stringstream hist(history);
+ while(hist >> d.sha1 >> size >> d.file) {
+ d.size = atoi(size.c_str());
+ // read until the first match is found
+ if(d.sha1 == local_sha1)
+ found=true;
+ // from that point on, we probably need all diffs
+ if(found) {
+ if(Debug)
+ std::clog << "Need to get diff: " << d.file << std::endl;
+ available_patches.push_back(d);
+ }
+ }
+ }
+
+ // no information how to get the patches, bail out
+ if(!found) {
+ if(Debug)
+ std::clog << "Can't find a patch in the index file" << std::endl;
+ // Failed will queue a big package file
+ Failed("", NULL);
+ } else {
+ // queue the diffs
+ new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
+ ExpectedMD5, available_patches);
+ Complete = false;
+ Status = StatDone;
+ Dequeue();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
+{
+ if(Debug)
+ std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << std::endl
+ << "Falling back to normal index file aquire" << std::endl;
+
+ new pkgAcqIndex(Owner, RealURI, Description, Desc.ShortDesc,
+ ExpectedMD5);
+
+ Complete = false;
+ Status = StatDone;
+ Dequeue();
+}
+
+void pkgAcqDiffIndex::Done(string Message,unsigned long Size,string Md5Hash,
+ pkgAcquire::MethodConfig *Cnf)
+{
+ if(Debug)
+ std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
+
+ Item::Done(Message,Size,Md5Hash,Cnf);
+
+ string FinalFile;
+ FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
+
+ // sucess in downloading the index
+ // rename the index
+ FinalFile += string(".IndexDiff");
+ if(Debug)
+ std::clog << "Renaming: " << DestFile << " -> " << FinalFile
+ << std::endl;
+ Rename(DestFile,FinalFile);
+ chmod(FinalFile.c_str(),0644);
+ DestFile = FinalFile;
+
+ if(!ParseDiffIndex(DestFile))
+ return Failed("", NULL);
+
+ Complete = true;
+ Status = StatDone;
+ Dequeue();
+ return;
+}
+
+
+
+// AcqIndexDiffs::AcqIndexDiffs - Constructor
+// ---------------------------------------------------------------------
+/* The package diff is added to the queue. one object is constructed
+ * for each diff and the index
+ */
+pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
+ string URI,string URIDesc,string ShortDesc,
+ string ExpectedMD5, vector<DiffInfo> diffs)
+ : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5),
+ available_patches(diffs)
+{
+
+ DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+ DestFile += URItoFileName(URI);
+
+ Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
+
+ Desc.Description = URIDesc;
+ Desc.Owner = this;
+ Desc.ShortDesc = ShortDesc;
+
+ if(available_patches.size() == 0) {
+ // we are done (yeah!)
+ Finish(true);
+ } else {
+ // get the next diff
+ State = StateFetchDiff;
+ QueueNextDiff();
+ }
+}
+
+
+void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
+{
+ if(Debug)
+ std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << std::endl
+ << "Falling back to normal index file aquire" << std::endl;
+ new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc,
+ ExpectedMD5);
+ Finish();
+}
+
+
+// helper that cleans the item out of the fetcher queue
+void pkgAcqIndexDiffs::Finish(bool allDone)
+{
+ // we restore the original name, this is required, otherwise
+ // the file will be cleaned
+ if(allDone) {
+ DestFile = _config->FindDir("Dir::State::lists");
+ DestFile += URItoFileName(RealURI);
+
+ // do the final md5sum checking
+ MD5Summation sum;
+ FileFd Fd(DestFile, FileFd::ReadOnly);
+ sum.AddFD(Fd.Fd(), Fd.Size());
+ Fd.Close();
+ string MD5 = (string)sum.Result();
+
+ if (!ExpectedMD5.empty() && MD5 != ExpectedMD5)
+ {
+ Status = StatAuthError;
+ ErrorText = _("MD5Sum mismatch");
+ Rename(DestFile,DestFile + ".FAILED");
+ Dequeue();
+ return;
+ }
+
+ // this is for the "real" finish
+ Complete = true;
+ Status = StatDone;
+ Dequeue();
+ if(Debug)
+ std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
+ return;
+ }
+
+ if(Debug)
+ std::clog << "Finishing: " << Desc.URI << std::endl;
+ Complete = false;
+ Status = StatDone;
+ Dequeue();
+ return;
+}
+
+
+
+bool pkgAcqIndexDiffs::QueueNextDiff()
+{
+
+ // calc sha1 of the just patched file
+ string FinalFile = _config->FindDir("Dir::State::lists");
+ FinalFile += URItoFileName(RealURI);
+
+ FileFd fd(FinalFile, FileFd::ReadOnly);
+ SHA1Summation SHA1;
+ SHA1.AddFD(fd.Fd(), fd.Size());
+ string local_sha1 = string(SHA1.Result());
+ if(Debug)
+ std::clog << "QueueNextDiff: "
+ << FinalFile << " (" << local_sha1 << ")"<<std::endl;
+
+ // remove all patches until the next matching patch is found
+ // this requires the Index file to be ordered
+ for(vector<DiffInfo>::iterator I=available_patches.begin();
+ available_patches.size() > 0 && I != available_patches.end()
+ && (*I).sha1 != local_sha1;
+ I++) {
+ available_patches.erase(I);
+ }
+
+ // error checking and falling back if no patch was found
+ if(available_patches.size() == 0) {
+ Failed("", NULL);
+ return false;
+ }
+
+ // queue the right diff
+ Desc.URI = string(RealURI) + ".diff/" + available_patches[0].file + ".gz";
+ Desc.Description = available_patches[0].file + string(".pdiff");
+
+ DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+ DestFile += URItoFileName(RealURI + ".diff/" + available_patches[0].file);
+
+ if(Debug)
+ std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
+
+ QueueURI(Desc);
+
+ return true;
+}
+
+
+
+void pkgAcqIndexDiffs::Done(string Message,unsigned long Size,string Md5Hash,
+ pkgAcquire::MethodConfig *Cnf)
+{
+ if(Debug)
+ std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
+
+ Item::Done(Message,Size,Md5Hash,Cnf);
+
+ string FinalFile;
+ FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
+
+ // sucess in downloading a diff, enter ApplyDiff state
+ if(State == StateFetchDiff)
+ {
+
+ if(Debug)
+ std::clog << "Sending to gzip method: " << FinalFile << std::endl;
+
+ string FileName = LookupTag(Message,"Filename");
+ State = StateUnzipDiff;
+ Desc.URI = "gzip:" + FileName;
+ DestFile += ".decomp";
+ QueueURI(Desc);
+ Mode = "gzip";
+ return;
+ }
+
+ // sucess in downloading a diff, enter ApplyDiff state
+ if(State == StateUnzipDiff)
+ {
+
+ // rred excepts the patch as $FinalFile.ed
+ Rename(DestFile,FinalFile+".ed");
+
+ if(Debug)
+ std::clog << "Sending to rred method: " << FinalFile << std::endl;
+
+ State = StateApplyDiff;
+ Desc.URI = "rred:" + FinalFile;
+ QueueURI(Desc);
+ Mode = "rred";
+ return;
+ }
+
+
+ // success in download/apply a diff, queue next (if needed)
+ if(State == StateApplyDiff)
+ {
+ // remove the just applied patch
+ available_patches.erase(available_patches.begin());
+
+ // move into place
+ if(Debug)
+ {
+ std::clog << "Moving patched file in place: " << std::endl
+ << DestFile << " -> " << FinalFile << std::endl;
+ }
+ Rename(DestFile,FinalFile);
+
+ // see if there is more to download
+ if(available_patches.size() > 0) {
+ new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
+ ExpectedMD5, available_patches);
+ return Finish();
+ } else
+ return Finish(true);
+ }
+}
+
+
// AcqIndex::AcqIndex - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* The package file is added to the queue and a second class is
instantiated to fetch the revision file */
pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
string URI,string URIDesc,string ShortDesc,
- string ExpectedMD5, string comprExt) :
- Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5)
+ string ExpectedMD5, string comprExt)
+ : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5)
{
Decompression = false;
Erase = false;
@@ -308,6 +707,35 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
Mode = decompProg;
}
+// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
+// ---------------------------------------------------------------------
+/* The Translation file is added to the queue */
+pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
+ string URI,string URIDesc,string ShortDesc) :
+ pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, "", "")
+{
+}
+
+ /*}}}*/
+// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
+{
+ if (Cnf->LocalOnly == true ||
+ StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
+ {
+ // Ignore this
+ Status = StatDone;
+ Complete = false;
+ Dequeue();
+ return;
+ }
+
+ Item::Failed(Message,Cnf);
+}
+ /*}}}*/
+
pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
string URI,string URIDesc,string ShortDesc,
string MetaIndexURI, string MetaIndexURIDesc,
@@ -607,8 +1035,8 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify)
}
// Queue Packages file
- new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
- (*Target)->ShortDesc, ExpectedIndexMD5);
+ new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
+ (*Target)->ShortDesc, ExpectedIndexMD5);
}
}
diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h
index 90f80368b..34fcc2a76 100644
--- a/apt-pkg/acquire-item.h
+++ b/apt-pkg/acquire-item.h
@@ -9,8 +9,8 @@
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.
+ Three item classes are provided to provide functionality for
+ downloading of Index, Translation and Packages files.
A Archive class is provided for downloading .deb files. It does Md5
checking and source location as well as a retry algorithm.
@@ -82,6 +82,70 @@ class pkgAcquire::Item
virtual ~Item();
};
+// item for index diffs
+
+struct DiffInfo {
+ string file;
+ string sha1;
+ unsigned long size;
+};
+
+class pkgAcqDiffIndex : public pkgAcquire::Item
+{
+ protected:
+ bool Debug;
+ pkgAcquire::ItemDesc Desc;
+ string RealURI;
+ string ExpectedMD5;
+ string CurrentPackagesFile;
+ string Description;
+
+ 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 DescURI() {return RealURI + "Index";};
+ virtual string Custom600Headers();
+
+ // helpers
+ bool ParseDiffIndex(string IndexDiffFile);
+
+ pkgAcqDiffIndex(pkgAcquire *Owner,string URI,string URIDesc,
+ string ShortDesct, string ExpectedMD5);
+};
+
+class pkgAcqIndexDiffs : public pkgAcquire::Item
+{
+ protected:
+ bool Debug;
+ pkgAcquire::ItemDesc Desc;
+ string RealURI;
+ string ExpectedMD5;
+
+ // this is the SHA-1 sum we expect after the patching
+ string Description;
+ vector<DiffInfo> available_patches;
+ enum {StateFetchIndex,StateFetchDiff,StateUnzipDiff,StateApplyDiff} State;
+
+ 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 DescURI() {return RealURI + "Index";};
+
+ // various helpers
+ bool QueueNextDiff();
+ bool ApplyDiff(string PatchFile);
+ void Finish(bool allDone=false);
+
+ pkgAcqIndexDiffs(pkgAcquire *Owner,string URI,string URIDesc,
+ string ShortDesct, string ExpectedMD5,
+ vector<DiffInfo> diffs=vector<DiffInfo>());
+};
+
// Item class for index files
class pkgAcqIndex : public pkgAcquire::Item
{
@@ -107,6 +171,16 @@ class pkgAcqIndex : public pkgAcquire::Item
string ShortDesct, string ExpectedMD5, string compressExt="");
};
+// Item class for translated package index files
+class pkgAcqIndexTrans : public pkgAcqIndex
+{
+ public:
+
+ virtual void Failed(string Message,pkgAcquire::MethodConfig *Cnf);
+ pkgAcqIndexTrans(pkgAcquire *Owner,string URI,string URIDesc,
+ string ShortDesct);
+};
+
struct IndexTarget
{
string URI;
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index c3a0d0a5a..f0aafb52d 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -99,7 +99,7 @@ class pkgCache::VerIterator
{
Version *Ver;
pkgCache *Owner;
-
+
void _dummy();
public:
@@ -128,6 +128,7 @@ class pkgCache::VerIterator
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 DescIterator DescriptionList() const;
inline DepIterator DependsList() const;
inline PrvIterator ProvidesList() const;
inline VerFileIterator FileList() const;
@@ -148,6 +149,50 @@ class pkgCache::VerIterator
};
};
+// Description Iterator
+class pkgCache::DescIterator
+{
+ Description *Desc;
+ pkgCache *Owner;
+
+ void _dummy();
+
+ public:
+
+ // Iteration
+ void operator ++(int) {if (Desc != Owner->DescP) Desc = Owner->DescP + Desc->NextDesc;};
+ inline void operator ++() {operator ++(0);};
+ inline bool end() const {return Desc == Owner->DescP?true:false;};
+ inline void operator =(const DescIterator &B) {Desc = B.Desc; Owner = B.Owner;};
+
+ // Comparison
+ inline bool operator ==(const DescIterator &B) const {return Desc == B.Desc;};
+ inline bool operator !=(const DescIterator &B) const {return Desc != B.Desc;};
+ int CompareDesc(const DescIterator &B) const;
+
+ // Accessors
+ inline Description *operator ->() {return Desc;};
+ inline Description const *operator ->() const {return Desc;};
+ inline Description &operator *() {return *Desc;};
+ inline Description const &operator *() const {return *Desc;};
+ inline operator Description *() {return Desc == Owner->DescP?0:Desc;};
+ inline operator Description const *() const {return Desc == Owner->DescP?0:Desc;};
+ inline pkgCache *Cache() {return Owner;};
+
+ inline const char *LanguageCode() const {return Owner->StrP + Desc->language_code;};
+ inline const char *md5() const {return Owner->StrP + Desc->md5sum;};
+ inline DescFileIterator FileList() const;
+ inline unsigned long Index() const {return Desc - Owner->DescP;};
+
+ inline DescIterator() : Desc(0), Owner(0) {};
+ inline DescIterator(pkgCache &Owner,Description *Trg = 0) : Desc(Trg),
+ Owner(&Owner)
+ {
+ if (Desc == 0)
+ Desc = Owner.DescP;
+ };
+};
+
// Dependency iterator
class pkgCache::DepIterator
{
@@ -338,6 +383,38 @@ class pkgCache::VerFileIterator
inline VerFileIterator(pkgCache &Owner,VerFile *Trg) : Owner(&Owner), FileP(Trg) {};
};
+// Description File
+class pkgCache::DescFileIterator
+{
+ pkgCache *Owner;
+ DescFile *FileP;
+
+ public:
+
+ // Iteration
+ void operator ++(int) {if (FileP != Owner->DescFileP) FileP = Owner->DescFileP + FileP->NextFile;};
+ inline void operator ++() {operator ++(0);};
+ inline bool end() const {return FileP == Owner->DescFileP?true:false;};
+
+ // Comparison
+ inline bool operator ==(const DescFileIterator &B) const {return FileP == B.FileP;};
+ inline bool operator !=(const DescFileIterator &B) const {return FileP != B.FileP;};
+
+ // Accessors
+ inline DescFile *operator ->() {return FileP;};
+ inline DescFile const *operator ->() const {return FileP;};
+ inline DescFile const &operator *() const {return *FileP;};
+ inline operator DescFile *() {return FileP == Owner->DescFileP?0:FileP;};
+ inline operator DescFile const *() const {return FileP == Owner->DescFileP?0:FileP;};
+ inline pkgCache *Cache() {return Owner;};
+
+ inline PkgFileIterator File() const {return PkgFileIterator(*Owner,FileP->File + Owner->PkgFileP);};
+ inline unsigned long Index() const {return FileP - Owner->DescFileP;};
+
+ inline DescFileIterator() : Owner(0), FileP(0) {};
+ inline DescFileIterator(pkgCache &Owner,DescFile *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);};
@@ -347,11 +424,15 @@ 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::DescIterator pkgCache::VerIterator::DescriptionList() const
+ {return DescIterator(*Owner,Owner->DescP + Ver->DescriptionList);};
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);};
+inline pkgCache::DescFileIterator pkgCache::DescIterator::FileList() const
+ {return DescFileIterator(*Owner,Owner->DescFileP + Desc->FileList);};
#endif
diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc
index ce1beb39b..b42c82dd0 100644
--- a/apt-pkg/cdrom.cc
+++ b/apt-pkg/cdrom.cc
@@ -30,12 +30,16 @@ using namespace std;
search that short circuits when it his a package file in the dir.
This speeds it up greatly as the majority of the size is in the
binary-* sub dirs. */
-bool pkgCdrom::FindPackages(string CD,vector<string> &List,
- vector<string> &SList, vector<string> &SigList,
+bool pkgCdrom::FindPackages(string CD,
+ vector<string> &List,
+ vector<string> &SList,
+ vector<string> &SigList,
+ vector<string> &TransList,
string &InfoDir, pkgCdromStatus *log,
unsigned int Depth)
{
static ino_t Inodes[9];
+ DIR *D;
// if we have a look we "pulse" now
if(log)
@@ -90,8 +94,28 @@ bool pkgCdrom::FindPackages(string CD,vector<string> &List,
if (_config->FindB("APT::CDROM::Thorough",false) == false)
return true;
}
+
+ // see if we find translatin indexes
+ if (stat("i18n",&Buf) == 0)
+ {
+ D = opendir("i18n");
+ for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
+ {
+ if(strstr(Dir->d_name,"Translation") != NULL)
+ {
+ if (_config->FindB("Debug::aptcdrom",false) == true)
+ std::clog << "found translations: " << Dir->d_name << "\n";
+ string file = Dir->d_name;
+ if(file.substr(file.size()-3,file.size()) == ".gz")
+ file = file.substr(0,file.size()-3);
+ TransList.push_back(CD+"i18n/"+ file);
+ }
+ }
+ closedir(D);
+ }
+
- DIR *D = opendir(".");
+ D = opendir(".");
if (D == 0)
return _error->Errno("opendir","Unable to read %s",CD.c_str());
@@ -127,7 +151,7 @@ bool pkgCdrom::FindPackages(string CD,vector<string> &List,
Inodes[Depth] = Buf.st_ino;
// Descend
- if (FindPackages(CD + Dir->d_name,List,SList,SigList,InfoDir,log,Depth+1) == false)
+ if (FindPackages(CD + Dir->d_name,List,SList,SigList,TransList,InfoDir,log,Depth+1) == false)
break;
if (chdir(CD.c_str()) != 0)
@@ -612,9 +636,10 @@ bool pkgCdrom::Add(pkgCdromStatus *log)
vector<string> List;
vector<string> SourceList;
vector<string> SigList;
+ vector<string> TransList;
string StartDir = SafeGetCWD();
string InfoDir;
- if (FindPackages(CDROM,List,SourceList, SigList,InfoDir,log) == false)
+ if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
{
log->Update("\n");
return false;
@@ -642,11 +667,13 @@ bool pkgCdrom::Add(pkgCdromStatus *log)
DropRepeats(List,"Packages");
DropRepeats(SourceList,"Sources");
DropRepeats(SigList,"Release.gpg");
+ DropRepeats(TransList,"");
if(log) {
msg.str("");
- ioprintf(msg, _("Found %i package indexes, %i source indexes and "
- "%i signatures\n"),
- List.size(), SourceList.size(), SigList.size());
+ ioprintf(msg, _("Found %i package indexes, %i source indexes, "
+ "%i translation indexes and %i signatures\n"),
+ List.size(), SourceList.size(), TransList.size(),
+ SigList.size());
log->Update(msg.str(), STEP_SCAN);
}
@@ -736,8 +763,10 @@ bool pkgCdrom::Add(pkgCdromStatus *log)
// Copy the package files to the state directory
PackageCopy Copy;
SourceCopy SrcCopy;
+ TranslationsCopy TransCopy;
if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
- SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false)
+ SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
+ TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
return false;
// reduce the List so that it takes less space in sources.list
diff --git a/apt-pkg/cdrom.h b/apt-pkg/cdrom.h
index 085eb64e2..e18aaff3e 100644
--- a/apt-pkg/cdrom.h
+++ b/apt-pkg/cdrom.h
@@ -50,8 +50,11 @@ class pkgCdrom
};
- bool FindPackages(string CD,vector<string> &List,
- vector<string> &SList, vector<string> &SigList,
+ bool FindPackages(string CD,
+ vector<string> &List,
+ vector<string> &SList,
+ vector<string> &SigList,
+ vector<string> &TransList,
string &InfoDir, pkgCdromStatus *log,
unsigned int Depth = 0);
bool DropBinaryArch(vector<string> &List);
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index a75fbdf92..303cb27db 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -32,12 +32,55 @@
#include <regex.h>
#include <errno.h>
#include <stdarg.h>
+#include <iconv.h>
#include "config.h"
using namespace std;
/*}}}*/
+// UTF8ToCodeset - Convert some UTF-8 string for some codeset /*{{{*/
+// ---------------------------------------------------------------------
+/* This is handy to use before display some information for enduser */
+bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest)
+{
+ iconv_t cd;
+ const char *inbuf;
+ char *inptr, *outbuf, *outptr;
+ size_t insize, outsize;
+
+ cd = iconv_open(codeset, "UTF-8");
+ if (cd == (iconv_t)(-1)) {
+ // Something went wrong
+ if (errno == EINVAL)
+ _error->Error("conversion from 'UTF-8' to '%s' not available",
+ codeset);
+ else
+ perror("iconv_open");
+
+ // Clean the destination string
+ *dest = "";
+
+ return false;
+ }
+
+ insize = outsize = orig.size();
+ inbuf = orig.data();
+ inptr = (char *)inbuf;
+ outbuf = new char[insize+1];
+ outptr = outbuf;
+
+ iconv(cd, &inptr, &insize, &outptr, &outsize);
+ *outptr = '\0';
+
+ *dest = outbuf;
+ delete[] outbuf;
+
+ iconv_close(cd);
+
+ return true;
+}
+ /*}}}*/
// strstrip - Remove white space from the front and back of a string /*{{{*/
// ---------------------------------------------------------------------
/* This is handy to use when parsing a file. It also removes \n's left
@@ -357,7 +400,7 @@ string URItoFileName(string URI)
U.Access = "";
// "\x00-\x20{}|\\\\^\\[\\]<>\"\x7F-\xFF";
- URI = QuoteString(U,"\\|{}[]<>\"^~_=!@#$%^&*");
+ URI = QuoteString(U,"\\|{}[]<>\"^~=!@#$%^&*");
string::iterator J = URI.begin();
for (; J != URI.end(); J++)
if (*J == '/')
diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h
index 353e78ac9..72fc34d6d 100644
--- a/apt-pkg/contrib/strutl.h
+++ b/apt-pkg/contrib/strutl.h
@@ -38,7 +38,8 @@ using std::ostream;
#define APT_FORMAT2
#define APT_FORMAT3
#endif
-
+
+bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest);
char *_strstrip(char *String);
char *_strtabexpand(char *String,size_t Len);
bool ParseQuoteWord(const char *&String,string &Res);
diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc
index ff8bce85d..38ecdd16a 100644
--- a/apt-pkg/deb/debindexfile.cc
+++ b/apt-pkg/deb/debindexfile.cc
@@ -320,6 +320,170 @@ pkgCache::PkgFileIterator debPackagesIndex::FindInCache(pkgCache &Cache) const
}
/*}}}*/
+// TranslationsIndex::debTranslationsIndex - Contructor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section) :
+ pkgIndexFile(true), URI(URI), Dist(Dist), Section(Section)
+{
+}
+ /*}}}*/
+// TranslationIndex::Trans* - Return the URI to the translation files /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+inline string debTranslationsIndex::IndexFile(const char *Type) const
+{
+ return _config->FindDir("Dir::State::lists") + URItoFileName(IndexURI(Type));
+}
+string debTranslationsIndex::IndexURI(const char *Type) const
+{
+ string Res;
+ if (Dist[Dist.size() - 1] == '/')
+ {
+ if (Dist != "/")
+ Res = URI + Dist;
+ else
+ Res = URI;
+ }
+ else
+ Res = URI + "dists/" + Dist + '/' + Section +
+ "/i18n/Translation-";
+
+ Res += Type;
+ return Res;
+}
+ /*}}}*/
+// TranslationsIndex::GetIndexes - Fetch the index files /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debTranslationsIndex::GetIndexes(pkgAcquire *Owner) const
+{
+ if (TranslationsAvailable()) {
+ string TranslationFile = "Translation-" + LanguageCode();
+ new pkgAcqIndexTrans(Owner, IndexURI(LanguageCode().c_str()),
+ Info(TranslationFile.c_str()),
+ TranslationFile);
+ }
+
+ return true;
+}
+ /*}}}*/
+// TranslationsIndex::Describe - Give a descriptive path to the index /*{{{*/
+// ---------------------------------------------------------------------
+/* This should help the user find the index in the sources.list and
+ in the filesystem for problem solving */
+string debTranslationsIndex::Describe(bool Short) const
+{
+ char S[300];
+ if (Short == true)
+ snprintf(S,sizeof(S),"%s",Info(TranslationFile().c_str()).c_str());
+ else
+ snprintf(S,sizeof(S),"%s (%s)",Info(TranslationFile().c_str()).c_str(),
+ IndexFile(LanguageCode().c_str()).c_str());
+ return S;
+}
+ /*}}}*/
+// TranslationsIndex::Info - One liner describing the index URI /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+string debTranslationsIndex::Info(const char *Type) const
+{
+ string Info = ::URI::SiteOnly(URI) + ' ';
+ if (Dist[Dist.size() - 1] == '/')
+ {
+ if (Dist != "/")
+ Info += Dist;
+ }
+ else
+ Info += Dist + '/' + Section;
+ Info += " ";
+ Info += Type;
+ return Info;
+}
+ /*}}}*/
+bool debTranslationsIndex::HasPackages() const
+{
+ if(!TranslationsAvailable())
+ return false;
+
+ return FileExists(IndexFile(LanguageCode().c_str()));
+}
+
+// TranslationsIndex::Exists - Check if the index is available /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debTranslationsIndex::Exists() const
+{
+ return FileExists(IndexFile(LanguageCode().c_str()));
+}
+ /*}}}*/
+// TranslationsIndex::Size - Return the size of the index /*{{{*/
+// ---------------------------------------------------------------------
+/* This is really only used for progress reporting. */
+unsigned long debTranslationsIndex::Size() const
+{
+ struct stat S;
+ if (stat(IndexFile(LanguageCode().c_str()).c_str(),&S) != 0)
+ return 0;
+ return S.st_size;
+}
+ /*}}}*/
+// TranslationsIndex::Merge - Load the index file into a cache /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
+{
+ // Check the translation file, if in use
+ string TranslationFile = IndexFile(LanguageCode().c_str());
+ if (TranslationsAvailable() && FileExists(TranslationFile))
+ {
+ FileFd Trans(TranslationFile,FileFd::ReadOnly);
+ debListParser TransParser(&Trans);
+ if (_error->PendingError() == true)
+ return false;
+
+ Prog.SubProgress(0, Info(TranslationFile.c_str()));
+ if (Gen.SelectFile(TranslationFile,string(),*this) == false)
+ return _error->Error("Problem with SelectFile %s",TranslationFile.c_str());
+
+ // Store the IMS information
+ pkgCache::PkgFileIterator TransFile = Gen.GetCurFile();
+ struct stat TransSt;
+ if (fstat(Trans.Fd(),&TransSt) != 0)
+ return _error->Errno("fstat","Failed to stat");
+ TransFile->Size = TransSt.st_size;
+ TransFile->mtime = TransSt.st_mtime;
+
+ if (Gen.MergeList(TransParser) == false)
+ return _error->Error("Problem with MergeList %s",TranslationFile.c_str());
+ }
+
+ return true;
+}
+ /*}}}*/
+// TranslationsIndex::FindInCache - Find this index /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgCache::PkgFileIterator debTranslationsIndex::FindInCache(pkgCache &Cache) const
+{
+ string FileName = IndexFile(LanguageCode().c_str());
+
+ pkgCache::PkgFileIterator File = Cache.FileBegin();
+ for (; File.end() == false; File++)
+ {
+ if (FileName != File.FileName())
+ continue;
+
+ struct stat St;
+ if (stat(File.FileName(),&St) != 0)
+ return pkgCache::PkgFileIterator(Cache);
+ if ((unsigned)St.st_size != File->Size || St.st_mtime != File->mtime)
+ return pkgCache::PkgFileIterator(Cache);
+ return File;
+ }
+ return File;
+}
+ /*}}}*/
// StatusIndex::debStatusIndex - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -416,6 +580,11 @@ class debIFTypePkg : public pkgIndexFile::Type
};
debIFTypePkg() {Label = "Debian Package Index";};
};
+class debIFTypeTrans : public debIFTypePkg
+{
+ public:
+ debIFTypeTrans() {Label = "Debian Translation Index";};
+};
class debIFTypeStatus : public pkgIndexFile::Type
{
public:
@@ -428,6 +597,7 @@ class debIFTypeStatus : public pkgIndexFile::Type
};
static debIFTypeSrc _apt_Src;
static debIFTypePkg _apt_Pkg;
+static debIFTypeTrans _apt_Trans;
static debIFTypeStatus _apt_Status;
const pkgIndexFile::Type *debSourcesIndex::GetType() const
@@ -438,6 +608,10 @@ const pkgIndexFile::Type *debPackagesIndex::GetType() const
{
return &_apt_Pkg;
}
+const pkgIndexFile::Type *debTranslationsIndex::GetType() const
+{
+ return &_apt_Trans;
+}
const pkgIndexFile::Type *debStatusIndex::GetType() const
{
return &_apt_Status;
diff --git a/apt-pkg/deb/debindexfile.h b/apt-pkg/deb/debindexfile.h
index a1b9583a4..57005222f 100644
--- a/apt-pkg/deb/debindexfile.h
+++ b/apt-pkg/deb/debindexfile.h
@@ -74,6 +74,36 @@ class debPackagesIndex : public pkgIndexFile
debPackagesIndex(string URI,string Dist,string Section,bool Trusted);
};
+class debTranslationsIndex : public pkgIndexFile
+{
+ string URI;
+ string Dist;
+ string Section;
+
+ string Info(const char *Type) const;
+ string IndexFile(const char *Type) const;
+ string IndexURI(const char *Type) const;
+
+ inline string TranslationFile() const {return "Translation-" + LanguageCode();};
+
+ public:
+
+ virtual const Type *GetType() const;
+
+ // Interface for acquire
+ virtual string Describe(bool Short) const;
+ virtual bool GetIndexes(pkgAcquire *Owner) const;
+
+ // Interface for the Cache Generator
+ virtual bool Exists() const;
+ virtual bool HasPackages() const;
+ virtual unsigned long Size() const;
+ virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
+ virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
+
+ debTranslationsIndex(string URI,string Dist,string Section);
+};
+
class debSourcesIndex : public pkgIndexFile
{
string URI;
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 25b533773..97553ab82 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -15,6 +15,7 @@
#include <apt-pkg/configuration.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/crc-16.h>
+#include <apt-pkg/md5.h>
#include <ctype.h>
@@ -117,6 +118,48 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
return true;
}
/*}}}*/
+// ListParser::Description - Return the description string /*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the string describing the package in debian
+ form. If this returns the blank string then the entry is assumed to
+ only describe package properties */
+string debListParser::Description()
+{
+ if (DescriptionLanguage().empty())
+ return Section.FindS("Description");
+ else
+ return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
+}
+ /*}}}*/
+// ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the string describing the language of
+ description. If this returns the blank string then the entry is
+ assumed to describe original description. */
+string debListParser::DescriptionLanguage()
+{
+ return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
+}
+ /*}}}*/
+// ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the md5 string to allow the check if it is the right
+ description. If no Description-md5 is found in the section it will be
+ calculated.
+ */
+MD5SumValue debListParser::Description_md5()
+{
+ string value = Section.FindS("Description-md5");
+
+ if (value.empty())
+ {
+ MD5Summation md5;
+ md5.Add((Description() + "\n").c_str());
+ return md5.Result();
+ } else
+ return MD5SumValue(value);
+}
+ /*}}}*/
// ListParser::UsePackage - Update a package structure /*{{{*/
// ---------------------------------------------------------------------
/* This is called to update the package with any new information
diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h
index 3a0e0421b..34bb29c72 100644
--- a/apt-pkg/deb/deblistparser.h
+++ b/apt-pkg/deb/deblistparser.h
@@ -12,6 +12,7 @@
#define PKGLIB_DEBLISTPARSER_H
#include <apt-pkg/pkgcachegen.h>
+#include <apt-pkg/indexfile.h>
#include <apt-pkg/tagfile.h>
class debListParser : public pkgCacheGenerator::ListParser
@@ -47,6 +48,9 @@ class debListParser : public pkgCacheGenerator::ListParser
virtual string Package();
virtual string Version();
virtual bool NewVersion(pkgCache::VerIterator Ver);
+ virtual string Description();
+ virtual string DescriptionLanguage();
+ virtual MD5SumValue Description_md5();
virtual unsigned short VersionHash();
virtual bool UsePackage(pkgCache::PkgIterator Pkg,
pkgCache::VerIterator Ver);
diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc
index 526c8c0b2..8dfbf7aff 100644
--- a/apt-pkg/deb/debmetaindex.cc
+++ b/apt-pkg/deb/debmetaindex.cc
@@ -157,6 +157,14 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
ComputeIndexTargets(),
new indexRecords (Dist));
+ // Queue the translations
+ for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
+ I != SectionEntries.end(); I++) {
+
+ debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section);
+ i.GetIndexes(Owner);
+ }
+
return true;
}
@@ -177,11 +185,16 @@ vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
Indexes = new vector <pkgIndexFile*>;
for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin();
- I != SectionEntries.end(); I++)
+ I != SectionEntries.end(); I++) {
if ((*I)->IsSrc)
Indexes->push_back(new debSourcesIndex (URI, Dist, (*I)->Section, IsTrusted()));
else
+ {
Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted()));
+ Indexes->push_back(new debTranslationsIndex(URI, Dist, (*I)->Section));
+ }
+ }
+
return Indexes;
}
diff --git a/apt-pkg/deb/debrecords.cc b/apt-pkg/deb/debrecords.cc
index 6652a6ad9..518988bb6 100644
--- a/apt-pkg/deb/debrecords.cc
+++ b/apt-pkg/deb/debrecords.cc
@@ -12,7 +12,9 @@
#pragma implementation "apt-pkg/debrecords.h"
#endif
#include <apt-pkg/debrecords.h>
+#include <apt-pkg/strutl.h>
#include <apt-pkg/error.h>
+#include <langinfo.h>
/*}}}*/
// RecordParser::debRecordParser - Constructor /*{{{*/
@@ -31,6 +33,10 @@ bool debRecordParser::Jump(pkgCache::VerFileIterator const &Ver)
{
return Tags.Jump(Section,Ver->Offset);
}
+bool debRecordParser::Jump(pkgCache::DescFileIterator const &Desc)
+{
+ return Tags.Jump(Section,Desc->Offset);
+}
/*}}}*/
// RecordParser::FileName - Return the archive filename on the site /*{{{*/
// ---------------------------------------------------------------------
@@ -77,7 +83,7 @@ string debRecordParser::Maintainer()
/* */
string debRecordParser::ShortDesc()
{
- string Res = Section.FindS("Description");
+ string Res = LongDesc();
string::size_type Pos = Res.find('\n');
if (Pos == string::npos)
return Res;
@@ -89,7 +95,20 @@ string debRecordParser::ShortDesc()
/* */
string debRecordParser::LongDesc()
{
- return Section.FindS("Description");
+ string orig, dest;
+ char *codeset = nl_langinfo(CODESET);
+
+ if (!Section.FindS("Description").empty())
+ orig = Section.FindS("Description").c_str();
+ else
+ orig = Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str()).c_str();
+
+ if (strcmp(codeset,"UTF-8") != 0) {
+ UTF8ToCodeset(codeset, orig, &dest);
+ orig = dest;
+ }
+
+ return orig;
}
/*}}}*/
// RecordParser::SourcePkg - Return the source package name if any /*{{{*/
diff --git a/apt-pkg/deb/debrecords.h b/apt-pkg/deb/debrecords.h
index efef2e588..24e5aab88 100644
--- a/apt-pkg/deb/debrecords.h
+++ b/apt-pkg/deb/debrecords.h
@@ -19,6 +19,7 @@
#endif
#include <apt-pkg/pkgrecords.h>
+#include <apt-pkg/indexfile.h>
#include <apt-pkg/tagfile.h>
class debRecordParser : public pkgRecords::Parser
@@ -30,6 +31,7 @@ class debRecordParser : public pkgRecords::Parser
protected:
virtual bool Jump(pkgCache::VerFileIterator const &Ver);
+ virtual bool Jump(pkgCache::DescFileIterator const &Desc);
public:
diff --git a/apt-pkg/indexcopy.cc b/apt-pkg/indexcopy.cc
index 1f65062f7..c9dded134 100644
--- a/apt-pkg/indexcopy.cc
+++ b/apt-pkg/indexcopy.cc
@@ -32,6 +32,8 @@
using namespace std;
+
+
// IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -512,10 +514,10 @@ bool SourceCopy::RewriteEntry(FILE *Target,string File)
fputc('\n',Target);
return true;
}
-
-
/*}}}*/
-
+// SigVerify::Verify - Verify a files md5sum against its metaindex /*{{{*/
+// ---------------------------------------------------------------------
+/* */
bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
{
const indexRecords::checkSum *Record = MetaIndex->Lookup(file);
@@ -670,3 +672,178 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
return true;
}
+
+
+bool TranslationsCopy::CopyTranslations(string CDROM,string Name,vector<string> &List,
+ pkgCdromStatus *log)
+{
+ OpProgress *Progress = NULL;
+ if (List.size() == 0)
+ return true;
+
+ if(log)
+ Progress = log->GetOpProgress();
+
+ bool Debug = _config->FindB("Debug::aptcdrom",false);
+
+ // Prepare the progress indicator
+ unsigned long TotalSize = 0;
+ for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+ {
+ struct stat Buf;
+ if (stat(string(*I).c_str(),&Buf) != 0 &&
+ stat(string(*I + ".gz").c_str(),&Buf) != 0)
+ return _error->Errno("stat","Stat failed for %s",
+ string(*I).c_str());
+ TotalSize += Buf.st_size;
+ }
+
+ unsigned long CurrentSize = 0;
+ unsigned int NotFound = 0;
+ unsigned int WrongSize = 0;
+ unsigned int Packages = 0;
+ for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
+ {
+ string OrigPath = string(*I,CDROM.length());
+ unsigned long FileSize = 0;
+
+ // Open the package file
+ FileFd Pkg;
+ if (FileExists(*I) == true)
+ {
+ Pkg.Open(*I,FileFd::ReadOnly);
+ FileSize = Pkg.Size();
+ }
+ else
+ {
+ FileFd From(*I + ".gz",FileFd::ReadOnly);
+ if (_error->PendingError() == true)
+ return false;
+ FileSize = From.Size();
+
+ // Get a temp file
+ FILE *tmp = tmpfile();
+ if (tmp == 0)
+ return _error->Errno("tmpfile","Unable to create a tmp file");
+ Pkg.Fd(dup(fileno(tmp)));
+ fclose(tmp);
+
+ // Fork gzip
+ pid_t Process = fork();
+ if (Process < 0)
+ return _error->Errno("fork","Couldn't fork gzip");
+
+ // The child
+ if (Process == 0)
+ {
+ dup2(From.Fd(),STDIN_FILENO);
+ dup2(Pkg.Fd(),STDOUT_FILENO);
+ SetCloseExec(STDIN_FILENO,false);
+ SetCloseExec(STDOUT_FILENO,false);
+
+ const char *Args[3];
+ string Tmp = _config->Find("Dir::bin::gzip","gzip");
+ Args[0] = Tmp.c_str();
+ Args[1] = "-d";
+ Args[2] = 0;
+ execvp(Args[0],(char **)Args);
+ exit(100);
+ }
+
+ // Wait for gzip to finish
+ if (ExecWait(Process,_config->Find("Dir::bin::gzip","gzip").c_str(),false) == false)
+ return _error->Error("gzip failed, perhaps the disk is full.");
+
+ Pkg.Seek(0);
+ }
+ pkgTagFile Parser(&Pkg);
+ if (_error->PendingError() == true)
+ return false;
+
+ // Open the output file
+ char S[400];
+ snprintf(S,sizeof(S),"cdrom:[%s]/%s",Name.c_str(),
+ (*I).c_str() + CDROM.length());
+ string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
+ TargetF += URItoFileName(S);
+ if (_config->FindB("APT::CDROM::NoAct",false) == true)
+ TargetF = "/dev/null";
+ FileFd Target(TargetF,FileFd::WriteEmpty);
+ FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
+ if (_error->PendingError() == true)
+ return false;
+ if (TargetFl == 0)
+ return _error->Errno("fdopen","Failed to reopen fd");
+
+ // Setup the progress meter
+ if(Progress)
+ Progress->OverallProgress(CurrentSize,TotalSize,FileSize,
+ string("Reading Translation Indexes"));
+
+ // Parse
+ if(Progress)
+ Progress->SubProgress(Pkg.Size());
+ pkgTagSection Section;
+ this->Section = &Section;
+ string Prefix;
+ unsigned long Hits = 0;
+ unsigned long Chop = 0;
+ while (Parser.Step(Section) == true)
+ {
+ if(Progress)
+ Progress->Progress(Parser.Offset());
+
+ const char *Start;
+ const char *Stop;
+ Section.GetSection(Start,Stop);
+ fwrite(Start,Stop-Start, 1, TargetFl);
+ fputc('\n',TargetFl);
+
+ Packages++;
+ Hits++;
+ }
+ fclose(TargetFl);
+
+ if (Debug == true)
+ cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl;
+
+ if (_config->FindB("APT::CDROM::NoAct",false) == false)
+ {
+ // Move out of the partial directory
+ Target.Close();
+ string FinalF = _config->FindDir("Dir::State::lists");
+ FinalF += URItoFileName(S);
+ if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
+ return _error->Errno("rename","Failed to rename");
+ }
+
+
+ CurrentSize += FileSize;
+ }
+ if(Progress)
+ Progress->Done();
+
+ // Some stats
+ if(log) {
+ stringstream msg;
+ if(NotFound == 0 && WrongSize == 0)
+ ioprintf(msg, _("Wrote %i records.\n"), Packages);
+ else if (NotFound != 0 && WrongSize == 0)
+ ioprintf(msg, _("Wrote %i records with %i missing files.\n"),
+ Packages, NotFound);
+ else if (NotFound == 0 && WrongSize != 0)
+ ioprintf(msg, _("Wrote %i records with %i mismatched files\n"),
+ Packages, WrongSize);
+ if (NotFound != 0 && WrongSize != 0)
+ ioprintf(msg, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages, NotFound, WrongSize);
+ }
+
+ if (Packages == 0)
+ _error->Warning("No valid records were found.");
+
+ if (NotFound + WrongSize > 10)
+ _error->Warning("Alot of entries were discarded, something may be wrong.\n");
+
+
+ return true;
+}
diff --git a/apt-pkg/indexcopy.h b/apt-pkg/indexcopy.h
index 4dcb2b46d..7778ae595 100644
--- a/apt-pkg/indexcopy.h
+++ b/apt-pkg/indexcopy.h
@@ -70,6 +70,17 @@ class SourceCopy : public IndexCopy
public:
};
+class TranslationsCopy
+{
+ protected:
+ pkgTagSection *Section;
+
+ public:
+ bool CopyTranslations(string CDROM,string Name,vector<string> &List,
+ pkgCdromStatus *log);
+};
+
+
class SigVerify
{
bool Verify(string prefix,string file, indexRecords *records);
@@ -81,4 +92,6 @@ class SigVerify
vector<string> PkgList,vector<string> SrcList);
};
+
+
#endif
diff --git a/apt-pkg/indexfile.cc b/apt-pkg/indexfile.cc
index 49665161d..496e68b8b 100644
--- a/apt-pkg/indexfile.cc
+++ b/apt-pkg/indexfile.cc
@@ -12,8 +12,11 @@
#pragma implementation "apt-pkg/indexfile.h"
#endif
+#include <apt-pkg/configuration.h>
#include <apt-pkg/indexfile.h>
#include <apt-pkg/error.h>
+
+#include <clocale>
/*}}}*/
// Global list of Item supported
@@ -67,3 +70,60 @@ string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &Record,
return string();
}
/*}}}*/
+// IndexFile::TranslationsAvailable - Check if will use Translation /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgIndexFile::TranslationsAvailable()
+{
+ const string Translation = _config->Find("APT::Acquire::Translation");
+
+ if (Translation.compare("none") != 0)
+ return CheckLanguageCode(LanguageCode().c_str());
+ else
+ return false;
+}
+ /*}}}*/
+// IndexFile::CheckLanguageCode - Check the Language Code /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+/* common cases: de_DE, de_DE@euro, de_DE.UTF-8, de_DE.UTF-8@euro,
+ de_DE.ISO8859-1, tig_ER
+ more in /etc/gdm/locale.conf
+*/
+
+bool pkgIndexFile::CheckLanguageCode(const char *Lang)
+{
+ if (strlen(Lang) == 2 || (strlen(Lang) == 5 && Lang[2] == '_'))
+ return true;
+
+ if (strcmp(Lang,"C") != 0)
+ _error->Warning("Wrong language code %s", Lang);
+
+ return false;
+}
+ /*}}}*/
+// IndexFile::LanguageCode - Return the Language Code /*{{{*/
+// ---------------------------------------------------------------------
+/* return the language code */
+string pkgIndexFile::LanguageCode()
+{
+ const string Translation = _config->Find("APT::Acquire::Translation");
+
+ if (Translation.compare("environment") == 0)
+ {
+ string lang = std::setlocale(LC_MESSAGES,NULL);
+
+ // FIXME: this needs to be added
+ // we have a mapping of the language codes that contains all the language
+ // codes that need the country code as well
+ // (like pt_BR, pt_PT, sv_SE, zh_*, en_*)
+
+ if(lang.size() > 2)
+ return lang.substr(0,2);
+ else
+ return lang;
+ }
+ else
+ return Translation;
+}
+ /*}}}*/
diff --git a/apt-pkg/indexfile.h b/apt-pkg/indexfile.h
index 61049f4bd..d5d1cf57a 100644
--- a/apt-pkg/indexfile.h
+++ b/apt-pkg/indexfile.h
@@ -5,10 +5,11 @@
Index File - Abstraction for an index of archive/source file.
- There are 3 primary sorts of index files, all represented by this
+ There are 4 primary sorts of index files, all represented by this
class:
Binary index files
+ Binary translation files
Bianry index files decribing the local system
Source index files
@@ -80,6 +81,10 @@ class pkgIndexFile
virtual bool MergeFileProvides(pkgCacheGenerator &/*Gen*/,OpProgress &/*Prog*/) const {return true;};
virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
+ static bool TranslationsAvailable();
+ static bool CheckLanguageCode(const char *Lang);
+ static string LanguageCode();
+
bool IsTrusted() const { return Trusted; };
pkgIndexFile(bool Trusted): Trusted(Trusted) {};
diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc
index f4b816c0b..6118845e8 100644
--- a/apt-pkg/init.cc
+++ b/apt-pkg/init.cc
@@ -101,6 +101,9 @@ bool pkgInitConfig(Configuration &Cnf)
bindtextdomain(textdomain(0),Cnf.FindDir("Dir::Locale").c_str());
}
#endif
+
+ // Translation
+ Cnf.Set("APT::Acquire::Translation", "environment");
return true;
}
diff --git a/apt-pkg/init.h b/apt-pkg/init.h
index e21351797..8255b406a 100644
--- a/apt-pkg/init.h
+++ b/apt-pkg/init.h
@@ -18,7 +18,7 @@
// See the makefile
#define APT_PKG_MAJOR 3
-#define APT_PKG_MINOR 10
+#define APT_PKG_MINOR 11
#define APT_PKG_RELEASE 0
extern const char *pkgVersion;
diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc
index 6ef7cafb0..f76afb935 100644
--- a/apt-pkg/pkgcache.cc
+++ b/apt-pkg/pkgcache.cc
@@ -52,7 +52,7 @@ pkgCache::Header::Header()
/* Whenever the structures change the major version should be bumped,
whenever the generator changes the minor version should be bumped. */
- MajorVersion = 4;
+ MajorVersion = 5;
MinorVersion = 0;
Dirty = false;
@@ -60,17 +60,22 @@ pkgCache::Header::Header()
PackageSz = sizeof(pkgCache::Package);
PackageFileSz = sizeof(pkgCache::PackageFile);
VersionSz = sizeof(pkgCache::Version);
+ DescriptionSz = sizeof(pkgCache::Description);
DependencySz = sizeof(pkgCache::Dependency);
ProvidesSz = sizeof(pkgCache::Provides);
VerFileSz = sizeof(pkgCache::VerFile);
+ DescFileSz = sizeof(pkgCache::DescFile);
PackageCount = 0;
VersionCount = 0;
+ DescriptionCount = 0;
DependsCount = 0;
PackageFileCount = 0;
VerFileCount = 0;
+ DescFileCount = 0;
ProvidesCount = 0;
MaxVerFileSize = 0;
+ MaxDescFileSize = 0;
FileList = 0;
StringList = 0;
@@ -89,8 +94,10 @@ bool pkgCache::Header::CheckSizes(Header &Against) const
PackageSz == Against.PackageSz &&
PackageFileSz == Against.PackageFileSz &&
VersionSz == Against.VersionSz &&
+ DescriptionSz == Against.DescriptionSz &&
DependencySz == Against.DependencySz &&
VerFileSz == Against.VerFileSz &&
+ DescFileSz == Against.DescFileSz &&
ProvidesSz == Against.ProvidesSz)
return true;
return false;
@@ -115,8 +122,10 @@ bool pkgCache::ReMap()
HeaderP = (Header *)Map.Data();
PkgP = (Package *)Map.Data();
VerFileP = (VerFile *)Map.Data();
+ DescFileP = (DescFile *)Map.Data();
PkgFileP = (PackageFile *)Map.Data();
VerP = (Version *)Map.Data();
+ DescP = (Description *)Map.Data();
ProvideP = (Provides *)Map.Data();
DepP = (Dependency *)Map.Data();
StringItemP = (StringItem *)Map.Data();
@@ -235,11 +244,11 @@ const char *pkgCache::Priority(unsigned char Prio)
return 0;
}
/*}}}*/
-
// Bases for iterator classes /*{{{*/
void pkgCache::VerIterator::_dummy() {}
void pkgCache::DepIterator::_dummy() {}
void pkgCache::PrvIterator::_dummy() {}
+void pkgCache::DescIterator::_dummy() {}
/*}}}*/
// PkgIterator::operator ++ - Postfix incr /*{{{*/
// ---------------------------------------------------------------------
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
index b07951dfb..6a54ad5ba 100644
--- a/apt-pkg/pkgcache.h
+++ b/apt-pkg/pkgcache.h
@@ -38,24 +38,30 @@ class pkgCache
struct Package;
struct PackageFile;
struct Version;
+ struct Description;
struct Provides;
struct Dependency;
struct StringItem;
struct VerFile;
+ struct DescFile;
// Iterators
class PkgIterator;
class VerIterator;
+ class DescIterator;
class DepIterator;
class PrvIterator;
class PkgFileIterator;
class VerFileIterator;
+ class DescFileIterator;
friend class PkgIterator;
friend class VerIterator;
+ friend class DescInterator;
friend class DepIterator;
friend class PrvIterator;
friend class PkgFileIterator;
friend class VerFileIterator;
+ friend class DescFileIterator;
class Namespace;
@@ -98,8 +104,10 @@ class pkgCache
Header *HeaderP;
Package *PkgP;
VerFile *VerFileP;
+ DescFile *DescFileP;
PackageFile *PkgFileP;
Version *VerP;
+ Description *DescP;
Provides *ProvideP;
Dependency *DepP;
StringItem *StringItemP;
@@ -151,16 +159,20 @@ struct pkgCache::Header
unsigned short PackageSz;
unsigned short PackageFileSz;
unsigned short VersionSz;
+ unsigned short DescriptionSz;
unsigned short DependencySz;
unsigned short ProvidesSz;
unsigned short VerFileSz;
+ unsigned short DescFileSz;
// Structure counts
unsigned long PackageCount;
unsigned long VersionCount;
+ unsigned long DescriptionCount;
unsigned long DependsCount;
unsigned long PackageFileCount;
unsigned long VerFileCount;
+ unsigned long DescFileCount;
unsigned long ProvidesCount;
// Offsets
@@ -169,10 +181,11 @@ struct pkgCache::Header
map_ptrloc VerSysName; // StringTable
map_ptrloc Architecture; // StringTable
unsigned long MaxVerFileSize;
+ unsigned long MaxDescFileSize;
/* Allocation pools, there should be one of these for each structure
excluding the header */
- DynamicMMap::Pool Pools[7];
+ DynamicMMap::Pool Pools[8];
// Rapid package name lookup
map_ptrloc HashTable[2*1048];
@@ -193,7 +206,7 @@ struct pkgCache::Package
map_ptrloc NextPackage; // Package
map_ptrloc RevDepends; // Dependency
map_ptrloc ProvidesList; // Provides
-
+
// Install/Remove/Purge etc
unsigned char SelectedState; // What
unsigned char InstState; // Flags
@@ -232,6 +245,14 @@ struct pkgCache::VerFile
unsigned short Size;
};
+struct pkgCache::DescFile
+{
+ map_ptrloc File; // PackageFile
+ map_ptrloc NextFile; // PkgVerFile
+ map_ptrloc Offset; // File offset
+ unsigned short Size;
+};
+
struct pkgCache::Version
{
map_ptrloc VerStr; // Stringtable
@@ -241,6 +262,7 @@ struct pkgCache::Version
// Lists
map_ptrloc FileList; // VerFile
map_ptrloc NextVer; // Version
+ map_ptrloc DescriptionList; // Description
map_ptrloc DependsList; // Dependency
map_ptrloc ParentPkg; // Package
map_ptrloc ProvidesList; // Provides
@@ -252,6 +274,22 @@ struct pkgCache::Version
unsigned char Priority;
};
+struct pkgCache::Description
+{
+ // Language Code store the description translation language code. If
+ // the value has a 0 lenght then this is readed using the Package
+ // file else the Translation-CODE are used.
+ map_ptrloc language_code; // StringTable
+ map_ptrloc md5sum; // StringTable
+
+ // Linked list
+ map_ptrloc FileList; // DescFile
+ map_ptrloc NextDesc; // Description
+ map_ptrloc ParentPkg; // Package
+
+ unsigned short ID;
+};
+
struct pkgCache::Dependency
{
map_ptrloc Version; // Stringtable
@@ -299,11 +337,13 @@ class pkgCache::Namespace
typedef pkgCache::PkgIterator PkgIterator;
typedef pkgCache::VerIterator VerIterator;
+ typedef pkgCache::DescIterator DescIterator;
typedef pkgCache::DepIterator DepIterator;
typedef pkgCache::PrvIterator PrvIterator;
typedef pkgCache::PkgFileIterator PkgFileIterator;
typedef pkgCache::VerFileIterator VerFileIterator;
typedef pkgCache::Version Version;
+ typedef pkgCache::Description Description;
typedef pkgCache::Package Package;
typedef pkgCache::Header Header;
typedef pkgCache::Dep Dep;
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index 2340f97fd..1ba791b45 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -125,16 +125,46 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
string Version = List.Version();
if (Version.empty() == true)
{
+ // we first process the package, then the descriptions
+ // (this has the bonus that we get MMap error when we run out
+ // of MMap space)
if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
return _error->Error(_("Error occurred while processing %s (UsePackage1)"),
PackageName.c_str());
+
+ // Find the right version to write the description
+ MD5SumValue CurMd5 = List.Description_md5();
+ pkgCache::VerIterator Ver = Pkg.VersionList();
+ map_ptrloc *LastVer = &Pkg->VersionList;
+
+ for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
+ {
+ pkgCache::DescIterator Desc = Ver.DescriptionList();
+ map_ptrloc *LastDesc = &Ver->DescriptionList;
+
+ for (; Desc.end() == false; LastDesc = &Desc->NextDesc, Desc++)
+ {
+
+ if (MD5SumValue(Desc.md5()) == CurMd5)
+ {
+ // Add new description
+ *LastDesc = NewDescription(Desc, List.DescriptionLanguage(), CurMd5, *LastDesc);
+ Desc->ParentPkg = Pkg.Index();
+
+ if (NewFileDesc(Desc,List) == false)
+ return _error->Error(_("Error occured while processing %s (NewFileDesc1)"),PackageName.c_str());
+ break;
+ }
+ }
+ }
+
continue;
}
pkgCache::VerIterator Ver = Pkg.VersionList();
- map_ptrloc *Last = &Pkg->VersionList;
+ map_ptrloc *LastVer = &Pkg->VersionList;
int Res = 1;
- for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
+ for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
{
Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
if (Res >= 0)
@@ -168,7 +198,7 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
// Skip to the end of the same version set.
if (Res == 0)
{
- for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
+ for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
{
Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
if (Res != 0)
@@ -177,9 +207,10 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
}
// Add a new version
- *Last = NewVersion(Ver,Version,*Last);
+ *LastVer = NewVersion(Ver,Version,*LastVer);
Ver->ParentPkg = Pkg.Index();
Ver->Hash = Hash;
+
if (List.NewVersion(Ver) == false)
return _error->Error(_("Error occurred while processing %s (NewVersion1)"),
PackageName.c_str());
@@ -199,6 +230,21 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
FoundFileDeps |= List.HasFileDeps();
return true;
}
+
+ /* Record the Description data. Description data always exist in
+ Packages and Translation-* files. */
+ pkgCache::DescIterator Desc = Ver.DescriptionList();
+ map_ptrloc *LastDesc = &Ver->DescriptionList;
+
+ // Skip to the end of description set
+ for (; Desc.end() == false; LastDesc = &Desc->NextDesc, Desc++);
+
+ // Add new description
+ *LastDesc = NewDescription(Desc, List.DescriptionLanguage(), List.Description_md5(), *LastDesc);
+ Desc->ParentPkg = Pkg.Index();
+
+ if (NewFileDesc(Desc,List) == false)
+ return _error->Error(_("Error occured while processing %s (NewFileDesc2)"),PackageName.c_str());
}
FoundFileDeps |= List.HasFileDeps();
@@ -209,6 +255,9 @@ bool pkgCacheGenerator::MergeList(ListParser &List,
if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
return _error->Error(_("Wow, you exceeded the number of versions "
"this APT is capable of."));
+ if (Cache.HeaderP->DescriptionCount >= (1ULL<<(sizeof(Cache.DescP->ID)*8))-1)
+ return _error->Error(_("Wow, you exceeded the number of descriptions "
+ "this APT is capable of."));
if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
return _error->Error(_("Wow, you exceeded the number of dependencies "
"this APT is capable of."));
@@ -271,7 +320,7 @@ 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)
@@ -349,6 +398,62 @@ unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
return Version;
}
/*}}}*/
+// CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
+ ListParser &List)
+{
+ if (CurrentFile == 0)
+ return true;
+
+ // Get a structure
+ unsigned long DescFile = Map.Allocate(sizeof(pkgCache::DescFile));
+ if (DescFile == 0)
+ return 0;
+
+ pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
+ DF->File = CurrentFile - Cache.PkgFileP;
+
+ // Link it to the end of the list
+ map_ptrloc *Last = &Desc->FileList;
+ for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; D++)
+ Last = &D->NextFile;
+
+ DF->NextFile = *Last;
+ *Last = DF.Index();
+
+ DF->Offset = List.Offset();
+ DF->Size = List.Size();
+ if (Cache.HeaderP->MaxDescFileSize < DF->Size)
+ Cache.HeaderP->MaxDescFileSize = DF->Size;
+ Cache.HeaderP->DescFileCount++;
+
+ return true;
+}
+ /*}}}*/
+// CacheGenerator::NewDescription - Create a new Description /*{{{*/
+// ---------------------------------------------------------------------
+/* This puts a description structure in the linked list */
+map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
+ const string &Lang, const MD5SumValue &md5sum,
+ map_ptrloc Next)
+{
+ // Get a structure
+ map_ptrloc Description = Map.Allocate(sizeof(pkgCache::Description));
+ if (Description == 0)
+ return 0;
+
+ // Fill it in
+ Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
+ Desc->NextDesc = Next;
+ Desc->ID = Cache.HeaderP->DescriptionCount++;
+ Desc->language_code = Map.WriteString(Lang);
+ Desc->md5sum = Map.WriteString(md5sum.Value());
+
+ return Description;
+}
+ /*}}}*/
// ListParser::NewDepends - Create a dependency element /*{{{*/
// ---------------------------------------------------------------------
/* This creates a dependency element in the tree. It is linked to the
@@ -580,7 +685,7 @@ static bool CheckValidity(string CacheFile, FileIterator Start,
pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
if (File.end() == true)
return false;
-
+
Visited[File->ID] = true;
}
diff --git a/apt-pkg/pkgcachegen.h b/apt-pkg/pkgcachegen.h
index 7d0920629..6ab8594d9 100644
--- a/apt-pkg/pkgcachegen.h
+++ b/apt-pkg/pkgcachegen.h
@@ -24,6 +24,7 @@
#endif
#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/md5.h>
class pkgSourceList;
class OpProgress;
@@ -55,7 +56,9 @@ class pkgCacheGenerator
bool NewPackage(pkgCache::PkgIterator &Pkg,string Pkg);
bool NewFileVer(pkgCache::VerIterator &Ver,ListParser &List);
+ bool NewFileDesc(pkgCache::DescIterator &Desc,ListParser &List);
unsigned long NewVersion(pkgCache::VerIterator &Ver,string VerStr,unsigned long Next);
+ map_ptrloc NewDescription(pkgCache::DescIterator &Desc,const string &Lang,const MD5SumValue &md5sum,map_ptrloc Next);
public:
@@ -107,6 +110,9 @@ class pkgCacheGenerator::ListParser
virtual string Package() = 0;
virtual string Version() = 0;
virtual bool NewVersion(pkgCache::VerIterator Ver) = 0;
+ virtual string Description() = 0;
+ virtual string DescriptionLanguage() = 0;
+ virtual MD5SumValue Description_md5() = 0;
virtual unsigned short VersionHash() = 0;
virtual bool UsePackage(pkgCache::PkgIterator Pkg,
pkgCache::VerIterator Ver) = 0;
diff --git a/apt-pkg/pkgrecords.cc b/apt-pkg/pkgrecords.cc
index 1d71d3e2f..f62f945b5 100644
--- a/apt-pkg/pkgrecords.cc
+++ b/apt-pkg/pkgrecords.cc
@@ -66,3 +66,12 @@ pkgRecords::Parser &pkgRecords::Lookup(pkgCache::VerFileIterator const &Ver)
return *Files[Ver.File()->ID];
}
/*}}}*/
+// Records::Lookup - Get a parser for the package description file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+pkgRecords::Parser &pkgRecords::Lookup(pkgCache::DescFileIterator const &Desc)
+{
+ Files[Desc.File()->ID]->Jump(Desc);
+ return *Files[Desc.File()->ID];
+}
+ /*}}}*/
diff --git a/apt-pkg/pkgrecords.h b/apt-pkg/pkgrecords.h
index f31e83afe..ece91680e 100644
--- a/apt-pkg/pkgrecords.h
+++ b/apt-pkg/pkgrecords.h
@@ -39,6 +39,7 @@ class pkgRecords
// Lookup function
Parser &Lookup(pkgCache::VerFileIterator const &Ver);
+ Parser &Lookup(pkgCache::DescFileIterator const &Desc);
// Construct destruct
pkgRecords(pkgCache &Cache);
@@ -50,6 +51,7 @@ class pkgRecords::Parser
protected:
virtual bool Jump(pkgCache::VerFileIterator const &Ver) = 0;
+ virtual bool Jump(pkgCache::DescFileIterator const &Desc) = 0;
public:
friend class pkgRecords;
diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc
index 0014563b8..94cfab14f 100644
--- a/cmdline/apt-cache.cc
+++ b/cmdline/apt-cache.cc
@@ -71,6 +71,12 @@ void LocalitySort(pkgCache::VerFile **begin,
{
qsort(begin,Count,Size,LocalityCompare);
}
+
+void LocalitySort(pkgCache::DescFile **begin,
+ unsigned long Count,size_t Size)
+{
+ qsort(begin,Count,Size,LocalityCompare);
+}
/*}}}*/
// UnMet - Show unmet dependencies /*{{{*/
// ---------------------------------------------------------------------
@@ -182,7 +188,14 @@ bool DumpPackage(CommandLine &CmdL)
{
cout << Cur.VerStr();
for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
- cout << "(" << Vf.File().FileName() << ")";
+ cout << " (" << Vf.File().FileName() << ")";
+ cout << endl;
+ for (pkgCache::DescIterator D = Cur.DescriptionList(); D.end() == false; D++)
+ {
+ cout << " Description Language: " << D.LanguageCode() << endl
+ << " File: " << D.FileList().File().FileName() << endl
+ << " MD5: " << D.md5() << endl;
+ }
cout << endl;
}
@@ -277,11 +290,15 @@ bool Stats(CommandLine &Cmd)
cout << _("Total distinct versions: ") << Cache.Head().VersionCount << " (" <<
SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
+ cout << _("Total Distinct Descriptions: ") << Cache.Head().DescriptionCount << " (" <<
+ SizeToStr(Cache.Head().DescriptionCount*Cache.Head().DescriptionSz) << ')' << endl;
cout << _("Total dependencies: ") << Cache.Head().DependsCount << " (" <<
SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
cout << _("Total ver/file relations: ") << Cache.Head().VerFileCount << " (" <<
SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
+ cout << _("Total Desc/File relations: ") << Cache.Head().DescFileCount << " (" <<
+ SizeToStr(Cache.Head().DescFileCount*Cache.Head().DescFileSz) << ')' << endl;
cout << _("Total Provides mappings: ") << Cache.Head().ProvidesCount << " (" <<
SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
@@ -344,6 +361,12 @@ bool Dump(CommandLine &Cmd)
for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
cout << " Depends: " << D.TargetPkg().Name() << ' ' <<
DeNull(D.TargetVer()) << endl;
+ for (pkgCache::DescIterator D = V.DescriptionList(); D.end() == false; D++)
+ {
+ cout << " Description Language: " << D.LanguageCode() << endl
+ << " File: " << D.FileList().File().FileName() << endl
+ << " MD5: " << D.md5() << endl;
+ }
}
}
@@ -1192,17 +1215,56 @@ bool DisplayRecord(pkgCache::VerIterator V)
if (_error->PendingError() == true)
return false;
- // Read the record and then write it out again.
+ // Read the record
unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize+1];
Buffer[V.FileList()->Size] = '\n';
if (PkgF.Seek(V.FileList()->Offset) == false ||
- PkgF.Read(Buffer,V.FileList()->Size) == false ||
- fwrite(Buffer,1,V.FileList()->Size+1,stdout) < (size_t)(V.FileList()->Size+1))
+ PkgF.Read(Buffer,V.FileList()->Size) == false)
{
delete [] Buffer;
return false;
}
-
+
+ // Get a pointer to start of Description field
+ const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "Description:");
+
+ // Write all but Description
+ if (fwrite(Buffer,1,DescP - Buffer-1,stdout) < (size_t)(DescP - Buffer-1))
+ {
+ delete [] Buffer;
+ return false;
+ }
+
+ // Show the right description
+ pkgRecords Recs(*GCache);
+ pkgCache::DescIterator DescDefault = V.DescriptionList();
+ pkgCache::DescIterator Desc = DescDefault;
+ for (; Desc.end() == false; Desc++)
+ if (pkgIndexFile::LanguageCode() == Desc.LanguageCode())
+ break;
+ if (Desc.end() == true) Desc = DescDefault;
+
+ pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
+ cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc();
+
+ // Find the first field after the description (if there is any)
+ for(DescP++;DescP != &Buffer[V.FileList()->Size];DescP++)
+ {
+ if(*DescP == '\n' && *(DescP+1) != ' ')
+ {
+ // write the rest of the buffer
+ const unsigned char *end=&Buffer[V.FileList()->Size];
+ if (fwrite(DescP,1,end-DescP,stdout) < (size_t)(end-DescP))
+ {
+ delete [] Buffer;
+ return false;
+ }
+
+ break;
+ }
+ }
+ // write a final newline (after the description)
+ cout<<endl;
delete [] Buffer;
return true;
@@ -1211,9 +1273,9 @@ bool DisplayRecord(pkgCache::VerIterator V)
// Search - Perform a search /*{{{*/
// ---------------------------------------------------------------------
/* This searches the package names and pacakge descriptions for a pattern */
-struct ExVerFile
+struct ExDescFile
{
- pkgCache::VerFile *Vf;
+ pkgCache::DescFile *Df;
bool NameMatch;
};
@@ -1253,35 +1315,35 @@ bool Search(CommandLine &CmdL)
return false;
}
- ExVerFile *VFList = new ExVerFile[Cache.HeaderP->PackageCount+1];
- memset(VFList,0,sizeof(*VFList)*Cache.HeaderP->PackageCount+1);
+ ExDescFile *DFList = new ExDescFile[Cache.HeaderP->PackageCount+1];
+ memset(DFList,0,sizeof(*DFList)*Cache.HeaderP->PackageCount+1);
// Map versions that we want to write out onto the VerList array.
for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
{
- VFList[P->ID].NameMatch = NumPatterns != 0;
+ DFList[P->ID].NameMatch = NumPatterns != 0;
for (unsigned I = 0; I != NumPatterns; I++)
{
if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
- VFList[P->ID].NameMatch &= true;
+ DFList[P->ID].NameMatch &= true;
else
- VFList[P->ID].NameMatch = false;
+ DFList[P->ID].NameMatch = false;
}
// Doing names only, drop any that dont match..
- if (NamesOnly == true && VFList[P->ID].NameMatch == false)
+ if (NamesOnly == true && DFList[P->ID].NameMatch == false)
continue;
// Find the proper version to use.
pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
if (V.end() == false)
- VFList[P->ID].Vf = V.FileList();
+ DFList[P->ID].Df = V.DescriptionList().FileList();
}
// Include all the packages that provide matching names too
for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
{
- if (VFList[P->ID].NameMatch == false)
+ if (DFList[P->ID].NameMatch == false)
continue;
for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; Prv++)
@@ -1289,18 +1351,18 @@ bool Search(CommandLine &CmdL)
pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
if (V.end() == false)
{
- VFList[Prv.OwnerPkg()->ID].Vf = V.FileList();
- VFList[Prv.OwnerPkg()->ID].NameMatch = true;
+ DFList[Prv.OwnerPkg()->ID].Df = V.DescriptionList().FileList();
+ DFList[Prv.OwnerPkg()->ID].NameMatch = true;
}
}
}
-
- LocalitySort(&VFList->Vf,Cache.HeaderP->PackageCount,sizeof(*VFList));
+
+ LocalitySort(&DFList->Df,Cache.HeaderP->PackageCount,sizeof(*DFList));
// Iterate over all the version records and check them
- for (ExVerFile *J = VFList; J->Vf != 0; J++)
+ for (ExDescFile *J = DFList; J->Df != 0; J++)
{
- pkgRecords::Parser &P = Recs.Lookup(pkgCache::VerFileIterator(Cache,J->Vf));
+ pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(Cache,J->Df));
bool Match = true;
if (J->NameMatch == false)
@@ -1331,7 +1393,7 @@ bool Search(CommandLine &CmdL)
}
}
- delete [] VFList;
+ delete [] DFList;
for (unsigned I = 0; I != NumPatterns; I++)
regfree(&Patterns[I]);
if (ferror(stdout))
diff --git a/debian/changelog b/debian/changelog
index 28152fa0a..064d240b5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -101,6 +101,7 @@ apt (0.6.38) unstable; urgency=low
-- Matt Zimmerman <mdz@debian.org> Sat, 25 Jun 2005 09:51:00 -0700
+>>>>>>> MERGE-SOURCE
apt (0.6.37) breezy; urgency=low
* Merge bubulle@debian.org--2005/apt--main--0 up to patch-81
diff --git a/methods/http.cc b/methods/http.cc
index ba86aa6b6..e2337a9ba 100644
--- a/methods/http.cc
+++ b/methods/http.cc
@@ -58,6 +58,7 @@ unsigned long PipelineDepth = 10;
unsigned long TimeOut = 120;
bool Debug = false;
+
// CircleBuf::CircleBuf - Circular input buffer /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -95,7 +96,7 @@ bool CircleBuf::Read(int Fd)
// Woops, buffer is full
if (InP - OutP == Size)
return true;
-
+
// Write the buffer segment
int Res;
Res = read(Fd,Buf + (InP%Size),LeftRead());
diff --git a/methods/makefile b/methods/makefile
index 06fd2a6fc..d0b5a28c0 100644
--- a/methods/makefile
+++ b/methods/makefile
@@ -7,7 +7,7 @@ include ../buildlib/defaults.mak
BIN := $(BIN)/methods
# FIXME..
-LIB_APT_PKG_MAJOR = 3.10
+LIB_APT_PKG_MAJOR = 3.11
APT_DOMAIN := libapt-pkg$(LIB_APT_PKG_MAJOR)
# The file method
@@ -59,6 +59,13 @@ LIB_MAKES = apt-pkg/makefile
SOURCE = ftp.cc rfc2553emu.cc connect.cc
include $(PROGRAM_H)
+# The rred method
+PROGRAM=rred
+SLIBS = -lapt-pkg $(SOCKETLIBS)
+LIB_MAKES = apt-pkg/makefile
+SOURCE = rred.cc
+include $(PROGRAM_H)
+
# The rsh method
PROGRAM=rsh
SLIBS = -lapt-pkg
diff --git a/methods/rred.cc b/methods/rred.cc
new file mode 100644
index 000000000..6fa57f3a6
--- /dev/null
+++ b/methods/rred.cc
@@ -0,0 +1,262 @@
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/error.h>
+#include <apt-pkg/acquire-method.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/hashes.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <utime.h>
+#include <stdio.h>
+#include <errno.h>
+#include <apti18n.h>
+
+/* this method implements a patch functionality similar to "patch --ed" that is
+ * used by the "tiffany" incremental packages download stuff. it differs from
+ * "ed" insofar that it is way more restricted (and therefore secure). in the
+ * moment only the "c", "a" and "d" commands of ed are implemented (diff
+ * doesn't output any other). additionally the records must be reverse sorted
+ * by line number and may not overlap (diff *seems* to produce this kind of
+ * output).
+ * */
+
+const char *Prog;
+
+class RredMethod : public pkgAcqMethod
+{
+ bool Debug;
+ // the size of this doesn't really matter (except for performance)
+ const static int BUF_SIZE = 1024;
+ // the ed commands
+ enum Mode {MODE_CHANGED, MODE_DELETED, MODE_ADDED};
+ // return values
+ enum State {ED_OK, ED_ORDERING, ED_PARSER, ED_FAILURE};
+ // this applies a single hunk, it uses a tail recursion to
+ // reverse the hunks in the file
+ int ed_rec(FILE *ed_cmds, FILE *in_file, FILE *out_file, int line,
+ char *buffer, unsigned int bufsize, Hashes *hash);
+ // apply a patch file
+ int ed_file(FILE *ed_cmds, FILE *in_file, FILE *out_file, Hashes *hash);
+ // the methods main method
+ virtual bool Fetch(FetchItem *Itm);
+
+ public:
+
+ RredMethod() : pkgAcqMethod("1.1",SingleInstance | SendConfig) {};
+};
+
+int RredMethod::ed_rec(FILE *ed_cmds, FILE *in_file, FILE *out_file, int line,
+ char *buffer, unsigned int bufsize, Hashes *hash) {
+ int pos;
+ int startline;
+ int stopline;
+ int mode;
+ int written;
+ char *idx;
+
+ /* get the current command and parse it*/
+ if (fgets(buffer, bufsize, ed_cmds) == NULL) {
+ return line;
+ }
+ startline = strtol(buffer, &idx, 10);
+ if (startline < line) {
+ return ED_ORDERING;
+ }
+ if (*idx == ',') {
+ idx++;
+ stopline = strtol(idx, &idx, 10);
+ }
+ else {
+ stopline = startline;
+ }
+ if (*idx == 'c') {
+ mode = MODE_CHANGED;
+ if (Debug == true) {
+ std::clog << "changing from line " << startline
+ << " to " << stopline << std::endl;
+ }
+ }
+ else if (*idx == 'a') {
+ mode = MODE_ADDED;
+ if (Debug == true) {
+ std::clog << "adding after line " << startline << std::endl;
+ }
+ }
+ else if (*idx == 'd') {
+ mode = MODE_DELETED;
+ if (Debug == true) {
+ std::clog << "deleting from line " << startline
+ << " to " << stopline << std::endl;
+ }
+ }
+ else {
+ return ED_PARSER;
+ }
+ /* get the current position */
+ pos = ftell(ed_cmds);
+ /* if this is add or change then go to the next full stop */
+ if ((mode == MODE_CHANGED) || (mode == MODE_ADDED)) {
+ do {
+ fgets(buffer, bufsize, ed_cmds);
+ while ((strlen(buffer) == (bufsize - 1))
+ && (buffer[bufsize - 2] != '\n')) {
+ fgets(buffer, bufsize, ed_cmds);
+ buffer[0] = ' ';
+ }
+ } while (strncmp(buffer, ".", 1) != 0);
+ }
+ /* do the recursive call */
+ line = ed_rec(ed_cmds, in_file, out_file, line, buffer, bufsize,
+ hash);
+ /* pass on errors */
+ if (line < 0) {
+ return line;
+ }
+ /* apply our hunk */
+ fseek(ed_cmds, pos, SEEK_SET);
+ /* first wind to the current position */
+ if (mode != MODE_ADDED) {
+ startline -= 1;
+ }
+ while (line < startline) {
+ fgets(buffer, bufsize, in_file);
+ written = fwrite(buffer, 1, strlen(buffer), out_file);
+ hash->Add((unsigned char*)buffer, written);
+ while ((strlen(buffer) == (bufsize - 1))
+ && (buffer[bufsize - 2] != '\n')) {
+ fgets(buffer, bufsize, in_file);
+ written = fwrite(buffer, 1, strlen(buffer), out_file);
+ hash->Add((unsigned char*)buffer, written);
+ }
+ line++;
+ }
+ /* include from ed script */
+ if ((mode == MODE_ADDED) || (mode == MODE_CHANGED)) {
+ do {
+ fgets(buffer, bufsize, ed_cmds);
+ if (strncmp(buffer, ".", 1) != 0) {
+ written = fwrite(buffer, 1, strlen(buffer), out_file);
+ hash->Add((unsigned char*)buffer, written);
+ while ((strlen(buffer) == (bufsize - 1))
+ && (buffer[bufsize - 2] != '\n')) {
+ fgets(buffer, bufsize, ed_cmds);
+ written = fwrite(buffer, 1, strlen(buffer), out_file);
+ hash->Add((unsigned char*)buffer, written);
+ }
+ }
+ else {
+ break;
+ }
+ } while (1);
+ }
+ /* ignore the corresponding number of lines from input */
+ if ((mode == MODE_DELETED) || (mode == MODE_CHANGED)) {
+ while (line < stopline) {
+ fgets(buffer, bufsize, in_file);
+ while ((strlen(buffer) == (bufsize - 1))
+ && (buffer[bufsize - 2] != '\n')) {
+ fgets(buffer, bufsize, in_file);
+ }
+ line++;
+ }
+ }
+ return line;
+}
+
+int RredMethod::ed_file(FILE *ed_cmds, FILE *in_file, FILE *out_file,
+ Hashes *hash) {
+ char buffer[BUF_SIZE];
+ int result;
+ int written;
+
+ /* we do a tail recursion to read the commands in the right order */
+ result = ed_rec(ed_cmds, in_file, out_file, 0, buffer, BUF_SIZE,
+ hash);
+
+ /* read the rest from infile */
+ if (result > 0) {
+ while (fgets(buffer, BUF_SIZE, in_file) != NULL) {
+ written = fwrite(buffer, 1, strlen(buffer), out_file);
+ hash->Add((unsigned char*)buffer, written);
+ }
+ }
+ else {
+ return ED_FAILURE;
+ }
+ return ED_OK;
+}
+
+
+bool RredMethod::Fetch(FetchItem *Itm)
+{
+ Debug = _config->FindB("Debug::pkgAcquire::RRed",false);
+ URI Get = Itm->Uri;
+ string Path = Get.Host + Get.Path; // To account for relative paths
+ // Path contains the filename to patch
+ FetchResult Res;
+ Res.Filename = Itm->DestFile;
+ URIStart(Res);
+ // Res.Filename the destination filename
+
+ if (Debug == true)
+ std::clog << "Patching " << Path << " with " << Path
+ << ".ed and putting result into " << Itm->DestFile << std::endl;
+ // Open the source and destination files (the d'tor of FileFd will do
+ // the cleanup/closing of the fds)
+ FileFd From(Path,FileFd::ReadOnly);
+ FileFd Patch(Path+".ed",FileFd::ReadOnly);
+ FileFd To(Itm->DestFile,FileFd::WriteEmpty);
+ To.EraseOnFailure();
+ if (_error->PendingError() == true)
+ return false;
+
+ Hashes Hash;
+ FILE* fFrom = fdopen(From.Fd(), "r");
+ FILE* fPatch = fdopen(Patch.Fd(), "r");
+ FILE* fTo = fdopen(To.Fd(), "w");
+ // now do the actual patching
+ if (ed_file(fPatch, fFrom, fTo, &Hash) != ED_OK) {
+ _error->Errno("rred", _("Could not patch file"));
+ return false;
+ }
+
+ // write out the result
+ fflush(fFrom);
+ fflush(fPatch);
+ fflush(fTo);
+ From.Close();
+ Patch.Close();
+ To.Close();
+
+ // Transfer the modification times
+ struct stat Buf;
+ if (stat(Path.c_str(),&Buf) != 0)
+ return _error->Errno("stat",_("Failed to stat"));
+
+ struct utimbuf TimeBuf;
+ TimeBuf.actime = Buf.st_atime;
+ TimeBuf.modtime = Buf.st_mtime;
+ if (utime(Itm->DestFile.c_str(),&TimeBuf) != 0)
+ return _error->Errno("utime",_("Failed to set modification time"));
+
+ if (stat(Itm->DestFile.c_str(),&Buf) != 0)
+ return _error->Errno("stat",_("Failed to stat"));
+
+ // return done
+ Res.LastModified = Buf.st_mtime;
+ Res.Size = Buf.st_size;
+ Res.TakeHashes(Hash);
+ URIDone(Res);
+
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ RredMethod Mth;
+
+ Prog = strrchr(argv[0],'/');
+ Prog++;
+
+ return Mth.Run();
+}