*/
pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
string URI,string URIDesc,string ShortDesc,
- string ExpectedMD5, vector<string> diffs)
- : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5), needed_files(diffs)
+ string ExpectedMD5, vector<DiffInfo> diffs)
+ : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5),
+ available_patches(diffs)
{
DestFile = _config->FindDir("Dir::State::lists") + "partial/";
return;
}
- if(needed_files.size() == 0)
+ if(available_patches.size() == 0) {
+ State = StateFetchIndex;
QueueDiffIndex(URI);
- else
+ } else {
+ State = StateFetchDiff;
QueueNextDiff();
+ }
}
void pkgAcqIndexDiffs::QueueDiffIndex(string URI)
QueueURI(Desc);
}
-void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
+// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
+// ---------------------------------------------------------------------
+/* The only header we use is the last-modified header. */
+string pkgAcqIndexDiffs::Custom600Headers()
{
+ // we only care for the IndexDiff file
+ if(State != StateFetchIndex)
+ return string("");
+
+ string Final = _config->FindDir("Dir::State::lists");
+ Final += URItoFileName(RealURI) + string(".IndexDiff");
+
if(Debug)
- std::clog << "Failed(): " << Desc.URI << std::endl
- << "Falling back to big package file" << std::endl;
+ 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);
+}
+
+void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
+{
+ std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << std::endl
+ << "Falling back to normal index file aquire" << std::endl;
new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc,
ExpectedMD5);
Finish();
}
-// this needs to be rewriten to not depend on the external ed
-bool pkgAcqIndexDiffs::ApplyDiff(string PatchFile)
+
+bool pkgAcqIndexDiffs::QueueNextDiff()
{
- char *error;
- int res=0;
+ // calc sha1 of the just patched file
string FinalFile = _config->FindDir("Dir::State::lists");
FinalFile += URItoFileName(RealURI);
- int Process = ExecFork();
- if (Process == 0)
- {
- chdir(_config->FindDir("Dir::State::lists").c_str());
- string cmd = "(zcat " + PatchFile + "; echo \"wq\" ) | ed " + FinalFile + " >/dev/null 2>/dev/null";
- if(Debug)
- std::clog << "Runing: " << cmd << std::endl;
- res = system(cmd.c_str());
- _exit(WEXITSTATUS(res));
+ 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);
}
- if(!ExecWait(Process, error, true)) {
- //_error->Error("Patch failed: %s ", error);
+
+ // error checking and falling back if no patch was found
+ if(available_patches.size() == 0) {
+ Failed("", NULL);
return false;
}
- return true;
-}
-
-bool pkgAcqIndexDiffs::QueueNextDiff()
-{
- // queue diff
- Desc.URI = string(RealURI) + string(".diff/") + needed_files[0] + string(".gz");
- Desc.Description = Description + string("-diff");
+ // queue the right diff
+ Desc.URI = string(RealURI) + string(".diff/") + available_patches[0].file + string(".gz");
+ Desc.Description = available_patches[0].file + string(".pdiff");
DestFile = _config->FindDir("Dir::State::lists") + "partial/";
- DestFile += URItoFileName(RealURI + string(".diff/") + needed_files[0]);
+ DestFile += URItoFileName(RealURI + string(".diff/") + available_patches[0].file);
if(Debug)
std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
// check the historie and see what patches we need
string history = Tags.FindS("SHA1-History");
std::stringstream hist(history);
- string sha1, size, file;
+ DiffInfo d;
+ string size;
bool found = false;
- while(hist >> sha1 >> size >> file) {
- if(sha1 == local_sha1)
+ 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: " << file << std::endl;
- needed_files.push_back(file);
+ 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)
} else {
// queue the diffs
new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
- ExpectedMD5, needed_files);
+ ExpectedMD5, available_patches);
Finish();
return true;
}
Item::Done(Message,Size,Md5Hash,Cnf);
- int len = Desc.URI.size();
+ string FinalFile;
+ FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
+
// sucess in downloading the index
- if(Desc.URI.substr(len-strlen("Index"),len-1) == "Index") {
+ if(State == StateFetchIndex)
+ {
+ // 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(!ParseIndexDiff(DestFile))
return Failed("", NULL);
- else
+ else
return Finish();
}
- // sucess in downloading a diff
- if(Desc.URI.find(".diff") != string::npos) {
- ApplyDiff(DestFile);
- needed_files.erase(needed_files.begin());
+ // sucess in downloading a diff, enter ApplyDiff state
+ if(State == StateFetchDiff)
+ {
- if(needed_files.size() > 0) {
- new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
- ExpectedMD5, needed_files);
- } else {
- Finish(true);
- return;
+ 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);
- Finish();
+ // 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);
+ }
}
// File was already in place. It needs to be re-verified
// because Release might have changed, so Move it into partial
Rename(Final,DestFile);
+ // unlink the file and do not try to use I-M-S and Last-Modified
+ // if the users proxy is broken
+ if(_config->FindB("Acquire::BrokenProxy", false) == true) {
+ std::cerr << "forcing re-get of the signature file as requested" << std::endl;
+ unlink(DestFile.c_str());
+ }
}
QueueURI(Desc);