]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
* cmdline/apt-get.cc:
[apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
b3d44315 3// $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire Item - Item to acquire
7
8 Each item can download to exactly one file at a time. This means you
9 cannot create an item that fetches two uri's to two files at the same
10 time. The pkgAcqIndex class creates a second class upon instantiation
11 to fetch the other index files because of this.
b185acc2 12
0118833a
AL
13 ##################################################################### */
14 /*}}}*/
15// Include Files /*{{{*/
0118833a
AL
16#include <apt-pkg/acquire-item.h>
17#include <apt-pkg/configuration.h>
b2e465d6 18#include <apt-pkg/sourcelist.h>
b3d44315 19#include <apt-pkg/vendorlist.h>
03e39e59 20#include <apt-pkg/error.h>
cdcc6d34 21#include <apt-pkg/strutl.h>
36375005 22#include <apt-pkg/fileutl.h>
b3d44315 23#include <apt-pkg/md5.h>
ac5b205a
MV
24#include <apt-pkg/sha1.h>
25#include <apt-pkg/tagfile.h>
0a8a80e5 26
b2e465d6
AL
27#include <apti18n.h>
28
0a8a80e5
AL
29#include <sys/stat.h>
30#include <unistd.h>
c88edf1d 31#include <errno.h>
5819a761 32#include <string>
ac5b205a 33#include <sstream>
c88edf1d 34#include <stdio.h>
0118833a
AL
35 /*}}}*/
36
b3d44315 37using namespace std;
5819a761 38
0118833a
AL
39// Acquire::Item::Item - Constructor /*{{{*/
40// ---------------------------------------------------------------------
41/* */
8267fe24 42pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
6b1ff003
AL
43 PartialSize(0), Mode(0), ID(0), Complete(false),
44 Local(false), QueueCounter(0)
0118833a
AL
45{
46 Owner->Add(this);
c88edf1d 47 Status = StatIdle;
0118833a
AL
48}
49 /*}}}*/
50// Acquire::Item::~Item - Destructor /*{{{*/
51// ---------------------------------------------------------------------
52/* */
53pkgAcquire::Item::~Item()
54{
55 Owner->Remove(this);
56}
57 /*}}}*/
c88edf1d
AL
58// Acquire::Item::Failed - Item failed to download /*{{{*/
59// ---------------------------------------------------------------------
93bf083d
AL
60/* We return to an idle state if there are still other queues that could
61 fetch this object */
7d8afa39 62void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
c88edf1d 63{
93bf083d 64 Status = StatIdle;
db890fdb 65 ErrorText = LookupTag(Message,"Message");
361593e9 66 UsedMirror = LookupTag(Message,"UsedMirror");
c88edf1d 67 if (QueueCounter <= 1)
93bf083d 68 {
a72ace20 69 /* This indicates that the file is not available right now but might
7d8afa39 70 be sometime later. If we do a retry cycle then this should be
17caf1b1 71 retried [CDROMs] */
7d8afa39
AL
72 if (Cnf->LocalOnly == true &&
73 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
a72ace20
AL
74 {
75 Status = StatIdle;
681d76d0 76 Dequeue();
a72ace20
AL
77 return;
78 }
7e5f33eb 79
93bf083d 80 Status = StatError;
681d76d0 81 Dequeue();
93bf083d 82 }
36280399
MV
83
84 // report mirror failure back to LP if we actually use a mirror
f0b509cd
MV
85 string FailReason = LookupTag(Message, "FailReason");
86 if(FailReason.size() != 0)
87 ReportMirrorFailure(FailReason);
88 else
89 ReportMirrorFailure(ErrorText);
c88edf1d
AL
90}
91 /*}}}*/
8267fe24
AL
92// Acquire::Item::Start - Item has begun to download /*{{{*/
93// ---------------------------------------------------------------------
17caf1b1
AL
94/* Stash status and the file size. Note that setting Complete means
95 sub-phases of the acquire process such as decompresion are operating */
727f18af 96void pkgAcquire::Item::Start(string /*Message*/,unsigned long Size)
8267fe24
AL
97{
98 Status = StatFetching;
99 if (FileSize == 0 && Complete == false)
100 FileSize = Size;
101}
102 /*}}}*/
c88edf1d
AL
103// Acquire::Item::Done - Item downloaded OK /*{{{*/
104// ---------------------------------------------------------------------
105/* */
459681d3
AL
106void pkgAcquire::Item::Done(string Message,unsigned long Size,string,
107 pkgAcquire::MethodConfig *Cnf)
c88edf1d 108{
b98f2859
AL
109 // We just downloaded something..
110 string FileName = LookupTag(Message,"Filename");
36280399 111 UsedMirror = LookupTag(Message,"UsedMirror");
8f30ca30 112 if (Complete == false && !Local && FileName == DestFile)
b98f2859
AL
113 {
114 if (Owner->Log != 0)
115 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
116 }
aa0e1101
AL
117
118 if (FileSize == 0)
119 FileSize= Size;
c88edf1d
AL
120 Status = StatDone;
121 ErrorText = string();
122 Owner->Dequeue(this);
123}
124 /*}}}*/
8b89e57f
AL
125// Acquire::Item::Rename - Rename a file /*{{{*/
126// ---------------------------------------------------------------------
127/* This helper function is used by alot of item methods as thier final
128 step */
129void pkgAcquire::Item::Rename(string From,string To)
130{
131 if (rename(From.c_str(),To.c_str()) != 0)
132 {
133 char S[300];
0fcd01de 134 snprintf(S,sizeof(S),_("rename failed, %s (%s -> %s)."),strerror(errno),
8b89e57f
AL
135 From.c_str(),To.c_str());
136 Status = StatError;
137 ErrorText = S;
7a3c2ab0 138 }
8b89e57f
AL
139}
140 /*}}}*/
0118833a 141
36280399
MV
142void pkgAcquire::Item::ReportMirrorFailure(string FailCode)
143{
59271f62
MV
144 // we only act if a mirror was used at all
145 if(UsedMirror.empty())
146 return;
36280399
MV
147#if 0
148 std::cerr << "\nReportMirrorFailure: "
149 << UsedMirror
59271f62 150 << " Uri: " << DescURI()
36280399
MV
151 << " FailCode: "
152 << FailCode << std::endl;
153#endif
154 const char *Args[40];
155 unsigned int i = 0;
156 string report = _config->Find("Methods::Mirror::ProblemReporting",
3f599bb7 157 "/usr/lib/apt/apt-report-mirror-failure");
36280399
MV
158 if(!FileExists(report))
159 return;
160 Args[i++] = report.c_str();
161 Args[i++] = UsedMirror.c_str();
f0b509cd 162 Args[i++] = DescURI().c_str();
36280399 163 Args[i++] = FailCode.c_str();
361593e9 164 Args[i++] = NULL;
36280399
MV
165 pid_t pid = ExecFork();
166 if(pid < 0)
167 {
168 _error->Error("ReportMirrorFailure Fork failed");
169 return;
170 }
171 else if(pid == 0)
172 {
361593e9
MV
173 execvp(Args[0], (char**)Args);
174 std::cerr << "Could not exec " << Args[0] << std::endl;
175 _exit(100);
36280399
MV
176 }
177 if(!ExecWait(pid, "report-mirror-failure"))
178 {
179 _error->Warning("Couldn't report problem to '%s'",
361593e9 180 _config->Find("Methods::Mirror::ProblemReporting").c_str());
36280399
MV
181 }
182}
183
184
2237bd01
MV
185
186// AcqDiffIndex::AcqDiffIndex - Constructor
ac5b205a 187// ---------------------------------------------------------------------
2237bd01
MV
188/* Get the DiffIndex file first and see if there are patches availabe
189 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
190 * patches. If anything goes wrong in that process, it will fall back to
191 * the original packages file
ac5b205a 192 */
2237bd01
MV
193pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner,
194 string URI,string URIDesc,string ShortDesc,
195 string ExpectedMD5)
196 : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5), Description(URIDesc)
ac5b205a
MV
197{
198
ac5b205a
MV
199 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
200
2237bd01 201 Desc.Description = URIDesc + "/DiffIndex";
ac5b205a
MV
202 Desc.Owner = this;
203 Desc.ShortDesc = ShortDesc;
2237bd01
MV
204 Desc.URI = URI + ".diff/Index";
205
206 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
207 DestFile += URItoFileName(URI) + string(".DiffIndex");
208
209 if(Debug)
210 std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl;
ac5b205a 211
2237bd01 212 // look for the current package file
ac5b205a
MV
213 CurrentPackagesFile = _config->FindDir("Dir::State::lists");
214 CurrentPackagesFile += URItoFileName(RealURI);
215
b4e57d2d
MV
216 // FIXME: this file:/ check is a hack to prevent fetching
217 // from local sources. this is really silly, and
218 // should be fixed cleanly as soon as possible
ac5b205a 219 if(!FileExists(CurrentPackagesFile) ||
81fcf9e2 220 Desc.URI.substr(0,strlen("file:/")) == "file:/")
2ac3eeb6 221 {
ac5b205a
MV
222 // we don't have a pkg file or we don't want to queue
223 if(Debug)
b4e57d2d 224 std::clog << "No index file, local or canceld by user" << std::endl;
ac5b205a
MV
225 Failed("", NULL);
226 return;
227 }
228
2ac3eeb6 229 if(Debug)
2237bd01
MV
230 std::clog << "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
231 << CurrentPackagesFile << std::endl;
2ac3eeb6 232
ac5b205a 233 QueueURI(Desc);
2237bd01 234
ac5b205a
MV
235}
236
6cb30d01
MV
237// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
238// ---------------------------------------------------------------------
239/* The only header we use is the last-modified header. */
2237bd01 240string pkgAcqDiffIndex::Custom600Headers()
6cb30d01 241{
6cb30d01
MV
242 string Final = _config->FindDir("Dir::State::lists");
243 Final += URItoFileName(RealURI) + string(".IndexDiff");
244
245 if(Debug)
246 std::clog << "Custom600Header-IMS: " << Final << std::endl;
247
248 struct stat Buf;
249 if (stat(Final.c_str(),&Buf) != 0)
250 return "\nIndex-File: true";
251
252 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
253}
254
2237bd01
MV
255
256bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile)
257{
258 if(Debug)
259 std::clog << "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
260 << std::endl;
261
262 pkgTagSection Tags;
263 string ServerSha1;
264 vector<DiffInfo> available_patches;
265
266 FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
267 pkgTagFile TF(&Fd);
268 if (_error->PendingError() == true)
269 return false;
270
271 if(TF.Step(Tags) == true)
272 {
273 string local_sha1;
002d9943
MV
274 bool found = false;
275 DiffInfo d;
276 string size;
277
2237bd01
MV
278 string tmp = Tags.FindS("SHA1-Current");
279 std::stringstream ss(tmp);
280 ss >> ServerSha1;
281
282 FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
283 SHA1Summation SHA1;
284 SHA1.AddFD(fd.Fd(), fd.Size());
285 local_sha1 = string(SHA1.Result());
286
2ac3eeb6
MV
287 if(local_sha1 == ServerSha1)
288 {
289 // we have the same sha1 as the server
2237bd01
MV
290 if(Debug)
291 std::clog << "Package file is up-to-date" << std::endl;
002d9943
MV
292 // set found to true, this will queue a pkgAcqIndexDiffs with
293 // a empty availabe_patches
294 found = true;
2ac3eeb6
MV
295 }
296 else
297 {
002d9943
MV
298 if(Debug)
299 std::clog << "SHA1-Current: " << ServerSha1 << std::endl;
300
301 // check the historie and see what patches we need
302 string history = Tags.FindS("SHA1-History");
303 std::stringstream hist(history);
2ac3eeb6
MV
304 while(hist >> d.sha1 >> size >> d.file)
305 {
002d9943
MV
306 d.size = atoi(size.c_str());
307 // read until the first match is found
308 if(d.sha1 == local_sha1)
309 found=true;
310 // from that point on, we probably need all diffs
2ac3eeb6
MV
311 if(found)
312 {
002d9943
MV
313 if(Debug)
314 std::clog << "Need to get diff: " << d.file << std::endl;
315 available_patches.push_back(d);
316 }
2237bd01
MV
317 }
318 }
319
05aab406
MV
320 // we have something, queue the next diff
321 if(found)
2ac3eeb6 322 {
2237bd01 323 // queue the diffs
05aab406
MV
324 int last_space = Description.rfind(" ");
325 if(last_space != string::npos)
326 Description.erase(last_space, Description.size()-last_space);
2237bd01
MV
327 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
328 ExpectedMD5, available_patches);
329 Complete = false;
330 Status = StatDone;
331 Dequeue();
332 return true;
333 }
334 }
05aab406
MV
335
336 // Nothing found, report and return false
337 // Failing here is ok, if we return false later, the full
338 // IndexFile is queued
339 if(Debug)
340 std::clog << "Can't find a patch in the index file" << std::endl;
2237bd01
MV
341 return false;
342}
343
344void pkgAcqDiffIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
345{
346 if(Debug)
347 std::clog << "pkgAcqDiffIndex failed: " << Desc.URI << std::endl
348 << "Falling back to normal index file aquire" << std::endl;
349
002d9943 350 new pkgAcqIndex(Owner, RealURI, Description, Desc.ShortDesc,
2237bd01
MV
351 ExpectedMD5);
352
353 Complete = false;
354 Status = StatDone;
355 Dequeue();
356}
357
358void pkgAcqDiffIndex::Done(string Message,unsigned long Size,string Md5Hash,
359 pkgAcquire::MethodConfig *Cnf)
360{
361 if(Debug)
362 std::clog << "pkgAcqDiffIndex::Done(): " << Desc.URI << std::endl;
363
364 Item::Done(Message,Size,Md5Hash,Cnf);
365
366 string FinalFile;
367 FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
368
369 // sucess in downloading the index
370 // rename the index
371 FinalFile += string(".IndexDiff");
372 if(Debug)
373 std::clog << "Renaming: " << DestFile << " -> " << FinalFile
374 << std::endl;
375 Rename(DestFile,FinalFile);
376 chmod(FinalFile.c_str(),0644);
377 DestFile = FinalFile;
378
379 if(!ParseDiffIndex(DestFile))
380 return Failed("", NULL);
381
382 Complete = true;
383 Status = StatDone;
384 Dequeue();
385 return;
386}
387
388
389
390// AcqIndexDiffs::AcqIndexDiffs - Constructor
391// ---------------------------------------------------------------------
392/* The package diff is added to the queue. one object is constructed
393 * for each diff and the index
394 */
395pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire *Owner,
396 string URI,string URIDesc,string ShortDesc,
397 string ExpectedMD5, vector<DiffInfo> diffs)
398 : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5),
399 available_patches(diffs)
400{
401
402 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
403 DestFile += URItoFileName(URI);
404
405 Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
406
05aab406 407 Description = URIDesc;
2237bd01
MV
408 Desc.Owner = this;
409 Desc.ShortDesc = ShortDesc;
410
2ac3eeb6
MV
411 if(available_patches.size() == 0)
412 {
2237bd01
MV
413 // we are done (yeah!)
414 Finish(true);
2ac3eeb6
MV
415 }
416 else
417 {
2237bd01
MV
418 // get the next diff
419 State = StateFetchDiff;
420 QueueNextDiff();
421 }
422}
423
424
ac5b205a
MV
425void pkgAcqIndexDiffs::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
426{
2237bd01
MV
427 if(Debug)
428 std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << std::endl
429 << "Falling back to normal index file aquire" << std::endl;
430 new pkgAcqIndex(Owner, RealURI, Description,Desc.ShortDesc,
ac5b205a
MV
431 ExpectedMD5);
432 Finish();
433}
434
435
436// helper that cleans the item out of the fetcher queue
437void pkgAcqIndexDiffs::Finish(bool allDone)
438{
439 // we restore the original name, this is required, otherwise
440 // the file will be cleaned
2ac3eeb6
MV
441 if(allDone)
442 {
ac5b205a
MV
443 DestFile = _config->FindDir("Dir::State::lists");
444 DestFile += URItoFileName(RealURI);
2d4722e2
MV
445
446 // do the final md5sum checking
447 MD5Summation sum;
448 FileFd Fd(DestFile, FileFd::ReadOnly);
449 sum.AddFD(Fd.Fd(), Fd.Size());
450 Fd.Close();
451 string MD5 = (string)sum.Result();
452
453 if (!ExpectedMD5.empty() && MD5 != ExpectedMD5)
454 {
455 Status = StatAuthError;
456 ErrorText = _("MD5Sum mismatch");
457 Rename(DestFile,DestFile + ".FAILED");
458 Dequeue();
459 return;
460 }
461
462 // this is for the "real" finish
ac5b205a 463 Complete = true;
cffc2ddd 464 Status = StatDone;
ac5b205a
MV
465 Dequeue();
466 if(Debug)
467 std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
468 return;
ac5b205a
MV
469 }
470
471 if(Debug)
472 std::clog << "Finishing: " << Desc.URI << std::endl;
473 Complete = false;
474 Status = StatDone;
475 Dequeue();
476 return;
477}
478
479
ac5b205a
MV
480
481bool pkgAcqIndexDiffs::QueueNextDiff()
482{
3de9ff77 483
94dc9d7d
MV
484 // calc sha1 of the just patched file
485 string FinalFile = _config->FindDir("Dir::State::lists");
486 FinalFile += URItoFileName(RealURI);
487
488 FileFd fd(FinalFile, FileFd::ReadOnly);
489 SHA1Summation SHA1;
490 SHA1.AddFD(fd.Fd(), fd.Size());
491 string local_sha1 = string(SHA1.Result());
3de9ff77
MV
492 if(Debug)
493 std::clog << "QueueNextDiff: "
494 << FinalFile << " (" << local_sha1 << ")"<<std::endl;
94dc9d7d 495
26d27645
MV
496 // remove all patches until the next matching patch is found
497 // this requires the Index file to be ordered
94dc9d7d 498 for(vector<DiffInfo>::iterator I=available_patches.begin();
2ac3eeb6
MV
499 available_patches.size() > 0 &&
500 I != available_patches.end() &&
501 (*I).sha1 != local_sha1;
502 I++)
503 {
26d27645 504 available_patches.erase(I);
59a704f0 505 }
94dc9d7d
MV
506
507 // error checking and falling back if no patch was found
2ac3eeb6
MV
508 if(available_patches.size() == 0)
509 {
94dc9d7d
MV
510 Failed("", NULL);
511 return false;
512 }
6cb30d01 513
94dc9d7d 514 // queue the right diff
2237bd01 515 Desc.URI = string(RealURI) + ".diff/" + available_patches[0].file + ".gz";
05aab406 516 Desc.Description = Description + " " + available_patches[0].file + string(".pdiff");
ac5b205a 517 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
2237bd01 518 DestFile += URItoFileName(RealURI + ".diff/" + available_patches[0].file);
ac5b205a
MV
519
520 if(Debug)
521 std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
522
523 QueueURI(Desc);
524
525 return true;
526}
527
ac5b205a
MV
528
529
530void pkgAcqIndexDiffs::Done(string Message,unsigned long Size,string Md5Hash,
531 pkgAcquire::MethodConfig *Cnf)
532{
533 if(Debug)
534 std::clog << "pkgAcqIndexDiffs::Done(): " << Desc.URI << std::endl;
535
536 Item::Done(Message,Size,Md5Hash,Cnf);
537
4a0a786f
MV
538 string FinalFile;
539 FinalFile = _config->FindDir("Dir::State::lists")+URItoFileName(RealURI);
6cb30d01 540
4a0a786f
MV
541 // sucess in downloading a diff, enter ApplyDiff state
542 if(State == StateFetchDiff)
543 {
544
545 if(Debug)
546 std::clog << "Sending to gzip method: " << FinalFile << std::endl;
547
548 string FileName = LookupTag(Message,"Filename");
549 State = StateUnzipDiff;
b7347826 550 Local = true;
4a0a786f
MV
551 Desc.URI = "gzip:" + FileName;
552 DestFile += ".decomp";
553 QueueURI(Desc);
554 Mode = "gzip";
555 return;
556 }
557
558 // sucess in downloading a diff, enter ApplyDiff state
559 if(State == StateUnzipDiff)
560 {
561
562 // rred excepts the patch as $FinalFile.ed
563 Rename(DestFile,FinalFile+".ed");
564
565 if(Debug)
566 std::clog << "Sending to rred method: " << FinalFile << std::endl;
567
568 State = StateApplyDiff;
b7347826 569 Local = true;
4a0a786f
MV
570 Desc.URI = "rred:" + FinalFile;
571 QueueURI(Desc);
572 Mode = "rred";
573 return;
574 }
575
576
577 // success in download/apply a diff, queue next (if needed)
578 if(State == StateApplyDiff)
579 {
580 // remove the just applied patch
94dc9d7d 581 available_patches.erase(available_patches.begin());
ac5b205a 582
4a0a786f 583 // move into place
59a704f0
MV
584 if(Debug)
585 {
4a0a786f
MV
586 std::clog << "Moving patched file in place: " << std::endl
587 << DestFile << " -> " << FinalFile << std::endl;
59a704f0 588 }
4a0a786f 589 Rename(DestFile,FinalFile);
1790e0cf 590 chmod(FinalFile.c_str(),0644);
4a0a786f
MV
591
592 // see if there is more to download
94dc9d7d 593 if(available_patches.size() > 0) {
ac5b205a 594 new pkgAcqIndexDiffs(Owner, RealURI, Description, Desc.ShortDesc,
94dc9d7d 595 ExpectedMD5, available_patches);
4a0a786f
MV
596 return Finish();
597 } else
598 return Finish(true);
ac5b205a 599 }
ac5b205a
MV
600}
601
602
0118833a
AL
603// AcqIndex::AcqIndex - Constructor /*{{{*/
604// ---------------------------------------------------------------------
605/* The package file is added to the queue and a second class is
b2e465d6
AL
606 instantiated to fetch the revision file */
607pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
b3d44315 608 string URI,string URIDesc,string ShortDesc,
ac5b205a
MV
609 string ExpectedMD5, string comprExt)
610 : Item(Owner), RealURI(URI), ExpectedMD5(ExpectedMD5)
0118833a 611{
8b89e57f 612 Decompression = false;
bfd22fc0 613 Erase = false;
13e8426f 614
0a8a80e5 615 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 616 DestFile += URItoFileName(URI);
8267fe24 617
b3d44315
MV
618 if(comprExt.empty())
619 {
13e8426f 620 // autoselect the compression method
4577fda2 621 if(FileExists("/bin/bzip2"))
13e8426f
MV
622 CompressionExtension = ".bz2";
623 else
624 CompressionExtension = ".gz";
b3d44315 625 } else {
13e8426f 626 CompressionExtension = comprExt;
b3d44315 627 }
13e8426f 628 Desc.URI = URI + CompressionExtension;
b3d44315 629
b2e465d6 630 Desc.Description = URIDesc;
8267fe24 631 Desc.Owner = this;
b2e465d6 632 Desc.ShortDesc = ShortDesc;
8267fe24
AL
633
634 QueueURI(Desc);
0118833a
AL
635}
636 /*}}}*/
0a8a80e5 637// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 638// ---------------------------------------------------------------------
0a8a80e5
AL
639/* The only header we use is the last-modified header. */
640string pkgAcqIndex::Custom600Headers()
0118833a 641{
0a8a80e5 642 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 643 Final += URItoFileName(RealURI);
0a8a80e5
AL
644
645 struct stat Buf;
646 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 647 return "\nIndex-File: true";
a72ace20 648 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
649}
650 /*}}}*/
debc84b2
MZ
651
652void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
653{
654 // no .bz2 found, retry with .gz
46e00f9d 655 if(Desc.URI.substr(Desc.URI.size()-3) == "bz2") {
debc84b2 656 Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz";
b3d44315
MV
657
658 // retry with a gzip one
659 new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc,
660 ExpectedMD5, string(".gz"));
661 Status = StatDone;
662 Complete = false;
663 Dequeue();
debc84b2 664 return;
17ff0930
MV
665 }
666
667 // on decompression failure, remove bad versions in partial/
668 if(Decompression && Erase) {
669 string s = _config->FindDir("Dir::State::lists") + "partial/";
670 s += URItoFileName(RealURI);
671 unlink(s.c_str());
debc84b2
MZ
672 }
673
debc84b2
MZ
674 Item::Failed(Message,Cnf);
675}
676
677
8b89e57f
AL
678// AcqIndex::Done - Finished a fetch /*{{{*/
679// ---------------------------------------------------------------------
680/* This goes through a number of states.. On the initial fetch the
681 method could possibly return an alternate filename which points
682 to the uncompressed version of the file. If this is so the file
683 is copied into the partial directory. In all other cases the file
684 is decompressed with a gzip uri. */
459681d3
AL
685void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
686 pkgAcquire::MethodConfig *Cfg)
8b89e57f 687{
459681d3 688 Item::Done(Message,Size,MD5,Cfg);
8b89e57f
AL
689
690 if (Decompression == true)
691 {
b3d44315
MV
692 if (_config->FindB("Debug::pkgAcquire::Auth", false))
693 {
694 std::cerr << std::endl << RealURI << ": Computed MD5: " << MD5;
695 std::cerr << " Expected MD5: " << ExpectedMD5 << std::endl;
696 }
697
698 if (MD5.empty())
699 {
700 MD5Summation sum;
701 FileFd Fd(DestFile, FileFd::ReadOnly);
702 sum.AddFD(Fd.Fd(), Fd.Size());
703 Fd.Close();
704 MD5 = (string)sum.Result();
705 }
706
707 if (!ExpectedMD5.empty() && MD5 != ExpectedMD5)
708 {
709 Status = StatAuthError;
710 ErrorText = _("MD5Sum mismatch");
711 Rename(DestFile,DestFile + ".FAILED");
59271f62 712 ReportMirrorFailure("HashChecksumFailure");
b3d44315
MV
713 return;
714 }
8b89e57f
AL
715 // Done, move it into position
716 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 717 FinalFile += URItoFileName(RealURI);
8b89e57f 718 Rename(DestFile,FinalFile);
7a3c2ab0 719 chmod(FinalFile.c_str(),0644);
bfd22fc0 720
7a7fa5f0
AL
721 /* We restore the original name to DestFile so that the clean operation
722 will work OK */
723 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 724 DestFile += URItoFileName(RealURI);
7a7fa5f0 725
bfd22fc0
AL
726 // Remove the compressed version.
727 if (Erase == true)
bfd22fc0 728 unlink(DestFile.c_str());
8b89e57f
AL
729 return;
730 }
bfd22fc0
AL
731
732 Erase = false;
8267fe24 733 Complete = true;
bfd22fc0 734
8b89e57f
AL
735 // Handle the unzipd case
736 string FileName = LookupTag(Message,"Alt-Filename");
737 if (FileName.empty() == false)
738 {
739 // The files timestamp matches
740 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
741 return;
b3d44315 742
8b89e57f 743 Decompression = true;
a6568219 744 Local = true;
8b89e57f 745 DestFile += ".decomp";
8267fe24
AL
746 Desc.URI = "copy:" + FileName;
747 QueueURI(Desc);
b98f2859 748 Mode = "copy";
8b89e57f
AL
749 return;
750 }
751
752 FileName = LookupTag(Message,"Filename");
753 if (FileName.empty() == true)
754 {
755 Status = StatError;
756 ErrorText = "Method gave a blank filename";
757 }
758
759 // The files timestamp matches
760 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
761 return;
bfd22fc0
AL
762
763 if (FileName == DestFile)
764 Erase = true;
8267fe24 765 else
a6568219 766 Local = true;
8b89e57f 767
46e00f9d 768 string compExt = Desc.URI.substr(Desc.URI.size()-3);
debc84b2
MZ
769 char *decompProg;
770 if(compExt == "bz2")
771 decompProg = "bzip2";
772 else if(compExt == ".gz")
773 decompProg = "gzip";
774 else {
775 _error->Error("Unsupported extension: %s", compExt.c_str());
776 return;
777 }
778
8b89e57f
AL
779 Decompression = true;
780 DestFile += ".decomp";
debc84b2 781 Desc.URI = string(decompProg) + ":" + FileName;
8267fe24 782 QueueURI(Desc);
debc84b2 783 Mode = decompProg;
8b89e57f 784}
8b89e57f 785
a52f938b
OS
786// AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
787// ---------------------------------------------------------------------
788/* The Translation file is added to the queue */
789pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire *Owner,
790 string URI,string URIDesc,string ShortDesc) :
a7a5b0d9 791 pkgAcqIndex(Owner, URI, URIDesc, ShortDesc, "", "")
a52f938b
OS
792{
793}
794
795 /*}}}*/
796// AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
797// ---------------------------------------------------------------------
798/* */
799void pkgAcqIndexTrans::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
800{
801 if (Cnf->LocalOnly == true ||
802 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
803 {
804 // Ignore this
805 Status = StatDone;
806 Complete = false;
807 Dequeue();
808 return;
809 }
810
811 Item::Failed(Message,Cnf);
812}
813 /*}}}*/
814
b3d44315
MV
815pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire *Owner,
816 string URI,string URIDesc,string ShortDesc,
817 string MetaIndexURI, string MetaIndexURIDesc,
818 string MetaIndexShortDesc,
819 const vector<IndexTarget*>* IndexTargets,
820 indexRecords* MetaIndexParser) :
821 Item(Owner), RealURI(URI), MetaIndexURI(MetaIndexURI),
46e00f9d
MV
822 MetaIndexURIDesc(MetaIndexURIDesc), MetaIndexShortDesc(MetaIndexShortDesc),
823 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets)
0118833a 824{
0a8a80e5 825 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 826 DestFile += URItoFileName(URI);
b3d44315 827
47eb38f4
MV
828 // remove any partial downloaded sig-file in partial/.
829 // it may confuse proxies and is too small to warrant a
830 // partial download anyway
f6237efd
MV
831 unlink(DestFile.c_str());
832
8267fe24 833 // Create the item
b2e465d6 834 Desc.Description = URIDesc;
8267fe24 835 Desc.Owner = this;
b3d44315
MV
836 Desc.ShortDesc = ShortDesc;
837 Desc.URI = URI;
838
839
840 string Final = _config->FindDir("Dir::State::lists");
841 Final += URItoFileName(RealURI);
842 struct stat Buf;
843 if (stat(Final.c_str(),&Buf) == 0)
844 {
845 // File was already in place. It needs to be re-verified
846 // because Release might have changed, so Move it into partial
847 Rename(Final,DestFile);
848 }
8267fe24 849
8267fe24 850 QueueURI(Desc);
0118833a
AL
851}
852 /*}}}*/
b3d44315 853// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 854// ---------------------------------------------------------------------
0a8a80e5 855/* The only header we use is the last-modified header. */
b3d44315 856string pkgAcqMetaSig::Custom600Headers()
0118833a 857{
0a8a80e5 858 struct stat Buf;
2aab5956 859 if (stat(DestFile.c_str(),&Buf) != 0)
a72ace20 860 return "\nIndex-File: true";
a789b983 861
a72ace20 862 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a 863}
b3d44315
MV
864
865void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5,
866 pkgAcquire::MethodConfig *Cfg)
c88edf1d 867{
459681d3 868 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
869
870 string FileName = LookupTag(Message,"Filename");
871 if (FileName.empty() == true)
872 {
873 Status = StatError;
874 ErrorText = "Method gave a blank filename";
8b89e57f 875 return;
c88edf1d 876 }
8b89e57f 877
c88edf1d
AL
878 if (FileName != DestFile)
879 {
b3d44315 880 // We have to copy it into place
a6568219 881 Local = true;
8267fe24
AL
882 Desc.URI = "copy:" + FileName;
883 QueueURI(Desc);
c88edf1d
AL
884 return;
885 }
b3d44315
MV
886
887 Complete = true;
888
889 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
890 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
891 DestFile, IndexTargets, MetaIndexParser);
892
c88edf1d
AL
893}
894 /*}}}*/
b3d44315 895void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
681d76d0 896{
47eb38f4 897 string Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
a789b983 898
75dd8af1 899 // if we get a network error we fail gracefully
7e5f33eb
MV
900 if(Status == StatTransientNetworkError)
901 {
24057ad6 902 Item::Failed(Message,Cnf);
484dbb81 903 // move the sigfile back on transient network failures
47eb38f4
MV
904 if(FileExists(DestFile))
905 Rename(DestFile,Final);
7e5f33eb
MV
906
907 // set the status back to , Item::Failed likes to reset it
908 Status = pkgAcquire::Item::StatTransientNetworkError;
24057ad6
MV
909 return;
910 }
911
75dd8af1 912 // Delete any existing sigfile when the acquire failed
75dd8af1
MV
913 unlink(Final.c_str());
914
b3d44315
MV
915 // queue a pkgAcqMetaIndex with no sigfile
916 new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc,
917 "", IndexTargets, MetaIndexParser);
918
681d76d0
AL
919 if (Cnf->LocalOnly == true ||
920 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
921 {
2b154e53
AL
922 // Ignore this
923 Status = StatDone;
924 Complete = false;
681d76d0
AL
925 Dequeue();
926 return;
927 }
928
929 Item::Failed(Message,Cnf);
930}
b3d44315
MV
931
932pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner,
933 string URI,string URIDesc,string ShortDesc,
934 string SigFile,
935 const vector<struct IndexTarget*>* IndexTargets,
936 indexRecords* MetaIndexParser) :
46e00f9d 937 Item(Owner), RealURI(URI), SigFile(SigFile), AuthPass(false),
f381d68d 938 MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets), IMSHit(false)
b3d44315 939{
b3d44315
MV
940 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
941 DestFile += URItoFileName(URI);
942
943 // Create the item
944 Desc.Description = URIDesc;
945 Desc.Owner = this;
946 Desc.ShortDesc = ShortDesc;
947 Desc.URI = URI;
948
949 QueueURI(Desc);
950}
951
952 /*}}}*/
953// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
954// ---------------------------------------------------------------------
955/* The only header we use is the last-modified header. */
956string pkgAcqMetaIndex::Custom600Headers()
957{
958 string Final = _config->FindDir("Dir::State::lists");
959 Final += URItoFileName(RealURI);
960
961 struct stat Buf;
962 if (stat(Final.c_str(),&Buf) != 0)
963 return "\nIndex-File: true";
964
965 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
966}
967
968void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string MD5,
969 pkgAcquire::MethodConfig *Cfg)
970{
971 Item::Done(Message,Size,MD5,Cfg);
972
973 // MetaIndexes are done in two passes: one to download the
974 // metaindex with an appropriate method, and a second to verify it
975 // with the gpgv method
976
977 if (AuthPass == true)
978 {
979 AuthDone(Message);
980 }
981 else
982 {
983 RetrievalDone(Message);
984 if (!Complete)
985 // Still more retrieving to do
986 return;
987
988 if (SigFile == "")
989 {
990 // There was no signature file, so we are finished. Download
991 // the indexes without verification.
992 QueueIndexes(false);
993 }
994 else
995 {
996 // There was a signature file, so pass it to gpgv for
997 // verification
998
999 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1000 std::cerr << "Metaindex acquired, queueing gpg verification ("
1001 << SigFile << "," << DestFile << ")\n";
1002 AuthPass = true;
1003 Desc.URI = "gpgv:" + SigFile;
1004 QueueURI(Desc);
1005 Mode = "gpgv";
1006 }
1007 }
1008}
1009
1010void pkgAcqMetaIndex::RetrievalDone(string Message)
1011{
1012 // We have just finished downloading a Release file (it is not
1013 // verified yet)
1014
1015 string FileName = LookupTag(Message,"Filename");
1016 if (FileName.empty() == true)
1017 {
1018 Status = StatError;
1019 ErrorText = "Method gave a blank filename";
1020 return;
1021 }
1022
1023 if (FileName != DestFile)
1024 {
1025 Local = true;
1026 Desc.URI = "copy:" + FileName;
1027 QueueURI(Desc);
1028 return;
1029 }
1030
f381d68d
MV
1031 // see if the download was a IMSHit
1032 IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
1033
b3d44315
MV
1034 Complete = true;
1035
1036 string FinalFile = _config->FindDir("Dir::State::lists");
1037 FinalFile += URItoFileName(RealURI);
1038
1039 // The files timestamp matches
1040 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == false)
1041 {
1042 // Move it into position
1043 Rename(DestFile,FinalFile);
1044 }
1790e0cf 1045 chmod(FinalFile.c_str(),0644);
b3d44315
MV
1046 DestFile = FinalFile;
1047}
1048
1049void pkgAcqMetaIndex::AuthDone(string Message)
1050{
1051 // At this point, the gpgv method has succeeded, so there is a
1052 // valid signature from a key in the trusted keyring. We
1053 // perform additional verification of its contents, and use them
1054 // to verify the indexes we are about to download
1055
1056 if (!MetaIndexParser->Load(DestFile))
1057 {
1058 Status = StatAuthError;
1059 ErrorText = MetaIndexParser->ErrorText;
1060 return;
1061 }
1062
ce424cd4 1063 if (!VerifyVendor(Message))
b3d44315
MV
1064 {
1065 return;
1066 }
1067
1068 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1069 std::cerr << "Signature verification succeeded: "
1070 << DestFile << std::endl;
1071
1072 // Download further indexes with verification
1073 QueueIndexes(true);
1074
1075 // Done, move signature file into position
1076
1077 string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
1078 URItoFileName(RealURI) + ".gpg";
1079 Rename(SigFile,VerifiedSigFile);
1080 chmod(VerifiedSigFile.c_str(),0644);
1081}
1082
1083void pkgAcqMetaIndex::QueueIndexes(bool verify)
1084{
1085 for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
1086 Target != IndexTargets->end();
1087 Target++)
1088 {
1089 string ExpectedIndexMD5;
1090 if (verify)
1091 {
1092 const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
1093 if (!Record)
1094 {
1095 Status = StatAuthError;
1096 ErrorText = "Unable to find expected entry "
1097 + (*Target)->MetaKey + " in Meta-index file (malformed Release file?)";
1098 return;
1099 }
1100 ExpectedIndexMD5 = Record->MD5Hash;
1101 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1102 {
1103 std::cerr << "Queueing: " << (*Target)->URI << std::endl;
1104 std::cerr << "Expected MD5: " << ExpectedIndexMD5 << std::endl;
1105 }
1106 if (ExpectedIndexMD5.empty())
1107 {
1108 Status = StatAuthError;
1109 ErrorText = "Unable to find MD5 sum for "
1110 + (*Target)->MetaKey + " in Meta-index file";
1111 return;
1112 }
1113 }
1114
2ac3eeb6
MV
1115 // Queue Packages file (either diff or full packages files, depending
1116 // on the users option)
702c84fb 1117 if(_config->FindB("Acquire::PDiffs",false) == true)
2ac3eeb6
MV
1118 new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
1119 (*Target)->ShortDesc, ExpectedIndexMD5);
1120 else
81fcf9e2 1121 new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
2ac3eeb6 1122 (*Target)->ShortDesc, ExpectedIndexMD5);
b3d44315
MV
1123 }
1124}
1125
ce424cd4 1126bool pkgAcqMetaIndex::VerifyVendor(string Message)
b3d44315
MV
1127{
1128// // Maybe this should be made available from above so we don't have
1129// // to read and parse it every time?
1130// pkgVendorList List;
1131// List.ReadMainList();
1132
1133// const Vendor* Vndr = NULL;
1134// for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1135// {
1136// string::size_type pos = (*I).find("VALIDSIG ");
1137// if (_config->FindB("Debug::Vendor", false))
1138// std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1139// << std::endl;
1140// if (pos != std::string::npos)
1141// {
1142// string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1143// if (_config->FindB("Debug::Vendor", false))
1144// std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1145// std::endl;
1146// Vndr = List.FindVendor(Fingerprint) != "";
1147// if (Vndr != NULL);
1148// break;
1149// }
1150// }
ce424cd4
MV
1151 string::size_type pos;
1152
1153 // check for missing sigs (that where not fatal because otherwise we had
1154 // bombed earlier)
1155 string missingkeys;
400ad7a4 1156 string msg = _("There is no public key available for the "
ce424cd4
MV
1157 "following key IDs:\n");
1158 pos = Message.find("NO_PUBKEY ");
1159 if (pos != std::string::npos)
1160 {
1161 string::size_type start = pos+strlen("NO_PUBKEY ");
1162 string Fingerprint = Message.substr(start, Message.find("\n")-start);
1163 missingkeys += (Fingerprint);
1164 }
1165 if(!missingkeys.empty())
1166 _error->Warning("%s", string(msg+missingkeys).c_str());
b3d44315
MV
1167
1168 string Transformed = MetaIndexParser->GetExpectedDist();
1169
1170 if (Transformed == "../project/experimental")
1171 {
1172 Transformed = "experimental";
1173 }
1174
ce424cd4 1175 pos = Transformed.rfind('/');
b3d44315
MV
1176 if (pos != string::npos)
1177 {
1178 Transformed = Transformed.substr(0, pos);
1179 }
1180
1181 if (Transformed == ".")
1182 {
1183 Transformed = "";
1184 }
1185
1186 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1187 {
1188 std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
1189 std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
1190 std::cerr << "Transformed Dist: " << Transformed << std::endl;
1191 }
1192
1193 if (MetaIndexParser->CheckDist(Transformed) == false)
1194 {
1195 // This might become fatal one day
1196// Status = StatAuthError;
1197// ErrorText = "Conflicting distribution; expected "
1198// + MetaIndexParser->GetExpectedDist() + " but got "
1199// + MetaIndexParser->GetDist();
1200// return false;
1201 if (!Transformed.empty())
1202 {
1203 _error->Warning("Conflicting distribution: %s (expected %s but got %s)",
1204 Desc.Description.c_str(),
1205 Transformed.c_str(),
1206 MetaIndexParser->GetDist().c_str());
1207 }
1208 }
1209
1210 return true;
1211}
1212 /*}}}*/
1213// pkgAcqMetaIndex::Failed - no Release file present or no signature
1214// file present /*{{{*/
1215// ---------------------------------------------------------------------
1216/* */
1217void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1218{
1219 if (AuthPass == true)
1220 {
f381d68d
MV
1221 // if we fail the authentication but got the file via a IMS-Hit
1222 // this means that the file wasn't downloaded and that it might be
1223 // just stale (server problem, proxy etc). we delete what we have
1224 // queue it again without i-m-s
1225 // alternatively we could just unlink the file and let the user try again
1226 if (IMSHit)
1227 {
1228 Complete = false;
1229 Local = false;
1230 AuthPass = false;
1231 unlink(DestFile.c_str());
1232
1233 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
1234 DestFile += URItoFileName(RealURI);
1235 Desc.URI = RealURI;
1236 QueueURI(Desc);
1237 return;
1238 }
1239
1240 // gpgv method failed
59271f62 1241 ReportMirrorFailure("GPGFailure");
b3d44315
MV
1242 _error->Warning("GPG error: %s: %s",
1243 Desc.Description.c_str(),
1244 LookupTag(Message,"Message").c_str());
f381d68d 1245
b3d44315
MV
1246 }
1247
1248 // No Release file was present, or verification failed, so fall
1249 // back to queueing Packages files without verification
1250 QueueIndexes(false);
1251}
1252
681d76d0 1253 /*}}}*/
03e39e59
AL
1254
1255// AcqArchive::AcqArchive - Constructor /*{{{*/
1256// ---------------------------------------------------------------------
17caf1b1
AL
1257/* This just sets up the initial fetch environment and queues the first
1258 possibilitiy */
03e39e59 1259pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
1260 pkgRecords *Recs,pkgCache::VerIterator const &Version,
1261 string &StoreFilename) :
1262 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b3d44315
MV
1263 StoreFilename(StoreFilename), Vf(Version.FileList()),
1264 Trusted(false)
03e39e59 1265{
7d8afa39 1266 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
1267
1268 if (Version.Arch() == 0)
bdae53f1 1269 {
d1f1f6a8 1270 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
1271 "This might mean you need to manually fix this package. "
1272 "(due to missing arch)"),
813c8eea 1273 Version.ParentPkg().Name());
bdae53f1
AL
1274 return;
1275 }
813c8eea 1276
b2e465d6
AL
1277 /* We need to find a filename to determine the extension. We make the
1278 assumption here that all the available sources for this version share
1279 the same extension.. */
1280 // Skip not source sources, they do not have file fields.
1281 for (; Vf.end() == false; Vf++)
1282 {
1283 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1284 continue;
1285 break;
1286 }
1287
1288 // Does not really matter here.. we are going to fail out below
1289 if (Vf.end() != true)
1290 {
1291 // If this fails to get a file name we will bomb out below.
1292 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1293 if (_error->PendingError() == true)
1294 return;
1295
1296 // Generate the final file name as: package_version_arch.foo
1297 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
1298 QuoteString(Version.VerStr(),"_:") + '_' +
1299 QuoteString(Version.Arch(),"_:.") +
1300 "." + flExtension(Parse.FileName());
1301 }
b3d44315
MV
1302
1303 // check if we have one trusted source for the package. if so, switch
1304 // to "TrustedOnly" mode
1305 for (pkgCache::VerFileIterator i = Version.FileList(); i.end() == false; i++)
1306 {
1307 pkgIndexFile *Index;
1308 if (Sources->FindIndex(i.File(),Index) == false)
1309 continue;
1310 if (_config->FindB("Debug::pkgAcquire::Auth", false))
1311 {
1312 std::cerr << "Checking index: " << Index->Describe()
1313 << "(Trusted=" << Index->IsTrusted() << ")\n";
1314 }
1315 if (Index->IsTrusted()) {
1316 Trusted = true;
1317 break;
1318 }
1319 }
1320
a3371852
MV
1321 // "allow-unauthenticated" restores apts old fetching behaviour
1322 // that means that e.g. unauthenticated file:// uris are higher
1323 // priority than authenticated http:// uris
1324 if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true)
1325 Trusted = false;
1326
03e39e59 1327 // Select a source
b185acc2 1328 if (QueueNext() == false && _error->PendingError() == false)
b2e465d6
AL
1329 _error->Error(_("I wasn't able to locate file for the %s package. "
1330 "This might mean you need to manually fix this package."),
b185acc2
AL
1331 Version.ParentPkg().Name());
1332}
1333 /*}}}*/
1334// AcqArchive::QueueNext - Queue the next file source /*{{{*/
1335// ---------------------------------------------------------------------
17caf1b1
AL
1336/* This queues the next available file version for download. It checks if
1337 the archive is already available in the cache and stashs the MD5 for
1338 checking later. */
b185acc2 1339bool pkgAcqArchive::QueueNext()
b2e465d6 1340{
03e39e59
AL
1341 for (; Vf.end() == false; Vf++)
1342 {
1343 // Ignore not source sources
1344 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
1345 continue;
1346
1347 // Try to cross match against the source list
b2e465d6
AL
1348 pkgIndexFile *Index;
1349 if (Sources->FindIndex(Vf.File(),Index) == false)
1350 continue;
03e39e59 1351
b3d44315
MV
1352 // only try to get a trusted package from another source if that source
1353 // is also trusted
1354 if(Trusted && !Index->IsTrusted())
1355 continue;
1356
03e39e59
AL
1357 // Grab the text package record
1358 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
1359 if (_error->PendingError() == true)
b185acc2 1360 return false;
03e39e59 1361
b2e465d6 1362 string PkgFile = Parse.FileName();
03e39e59
AL
1363 MD5 = Parse.MD5Hash();
1364 if (PkgFile.empty() == true)
b2e465d6
AL
1365 return _error->Error(_("The package index files are corrupted. No Filename: "
1366 "field for package %s."),
1367 Version.ParentPkg().Name());
a6568219 1368
b3d44315
MV
1369 Desc.URI = Index->ArchiveURI(PkgFile);
1370 Desc.Description = Index->ArchiveInfo(Version);
1371 Desc.Owner = this;
1372 Desc.ShortDesc = Version.ParentPkg().Name();
1373
17caf1b1 1374 // See if we already have the file. (Legacy filenames)
a6568219
AL
1375 FileSize = Version->Size;
1376 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
1377 struct stat Buf;
1378 if (stat(FinalFile.c_str(),&Buf) == 0)
1379 {
1380 // Make sure the size matches
1381 if ((unsigned)Buf.st_size == Version->Size)
1382 {
1383 Complete = true;
1384 Local = true;
1385 Status = StatDone;
30e1eab5 1386 StoreFilename = DestFile = FinalFile;
b185acc2 1387 return true;
a6568219
AL
1388 }
1389
6b1ff003
AL
1390 /* Hmm, we have a file and its size does not match, this means it is
1391 an old style mismatched arch */
a6568219
AL
1392 unlink(FinalFile.c_str());
1393 }
17caf1b1
AL
1394
1395 // Check it again using the new style output filenames
1396 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
1397 if (stat(FinalFile.c_str(),&Buf) == 0)
1398 {
1399 // Make sure the size matches
1400 if ((unsigned)Buf.st_size == Version->Size)
1401 {
1402 Complete = true;
1403 Local = true;
1404 Status = StatDone;
1405 StoreFilename = DestFile = FinalFile;
1406 return true;
1407 }
1408
1409 /* Hmm, we have a file and its size does not match, this shouldnt
1410 happen.. */
1411 unlink(FinalFile.c_str());
1412 }
1413
1414 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
1415
1416 // Check the destination file
1417 if (stat(DestFile.c_str(),&Buf) == 0)
1418 {
1419 // Hmm, the partial file is too big, erase it
1420 if ((unsigned)Buf.st_size > Version->Size)
1421 unlink(DestFile.c_str());
1422 else
1423 PartialSize = Buf.st_size;
1424 }
1425
03e39e59 1426 // Create the item
b2e465d6
AL
1427 Local = false;
1428 Desc.URI = Index->ArchiveURI(PkgFile);
1429 Desc.Description = Index->ArchiveInfo(Version);
03e39e59
AL
1430 Desc.Owner = this;
1431 Desc.ShortDesc = Version.ParentPkg().Name();
1432 QueueURI(Desc);
b185acc2
AL
1433
1434 Vf++;
1435 return true;
03e39e59 1436 }
b185acc2
AL
1437 return false;
1438}
03e39e59
AL
1439 /*}}}*/
1440// AcqArchive::Done - Finished fetching /*{{{*/
1441// ---------------------------------------------------------------------
1442/* */
459681d3
AL
1443void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
1444 pkgAcquire::MethodConfig *Cfg)
03e39e59 1445{
459681d3 1446 Item::Done(Message,Size,Md5Hash,Cfg);
03e39e59
AL
1447
1448 // Check the size
1449 if (Size != Version->Size)
1450 {
bdae53f1 1451 Status = StatError;
b2e465d6 1452 ErrorText = _("Size mismatch");
03e39e59
AL
1453 return;
1454 }
1455
1456 // Check the md5
1457 if (Md5Hash.empty() == false && MD5.empty() == false)
1458 {
1459 if (Md5Hash != MD5)
1460 {
bdae53f1 1461 Status = StatError;
b2e465d6 1462 ErrorText = _("MD5Sum mismatch");
13e8426f
MV
1463 if(FileExists(DestFile))
1464 Rename(DestFile,DestFile + ".FAILED");
03e39e59
AL
1465 return;
1466 }
1467 }
a6568219
AL
1468
1469 // Grab the output filename
03e39e59
AL
1470 string FileName = LookupTag(Message,"Filename");
1471 if (FileName.empty() == true)
1472 {
1473 Status = StatError;
1474 ErrorText = "Method gave a blank filename";
1475 return;
1476 }
a6568219
AL
1477
1478 Complete = true;
30e1eab5
AL
1479
1480 // Reference filename
a6568219
AL
1481 if (FileName != DestFile)
1482 {
30e1eab5 1483 StoreFilename = DestFile = FileName;
a6568219
AL
1484 Local = true;
1485 return;
1486 }
1487
1488 // Done, move it into position
1489 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 1490 FinalFile += flNotDir(StoreFilename);
a6568219 1491 Rename(DestFile,FinalFile);
03e39e59 1492
30e1eab5 1493 StoreFilename = DestFile = FinalFile;
03e39e59
AL
1494 Complete = true;
1495}
1496 /*}}}*/
db890fdb
AL
1497// AcqArchive::Failed - Failure handler /*{{{*/
1498// ---------------------------------------------------------------------
1499/* Here we try other sources */
7d8afa39 1500void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
1501{
1502 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
1503
1504 /* We don't really want to retry on failed media swaps, this prevents
1505 that. An interesting observation is that permanent failures are not
1506 recorded. */
1507 if (Cnf->Removable == true &&
1508 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1509 {
1510 // Vf = Version.FileList();
1511 while (Vf.end() == false) Vf++;
1512 StoreFilename = string();
1513 Item::Failed(Message,Cnf);
1514 return;
1515 }
1516
db890fdb 1517 if (QueueNext() == false)
7d8afa39
AL
1518 {
1519 // This is the retry counter
1520 if (Retries != 0 &&
1521 Cnf->LocalOnly == false &&
1522 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1523 {
1524 Retries--;
1525 Vf = Version.FileList();
1526 if (QueueNext() == true)
1527 return;
1528 }
1529
9dbb421f 1530 StoreFilename = string();
7d8afa39
AL
1531 Item::Failed(Message,Cnf);
1532 }
db890fdb
AL
1533}
1534 /*}}}*/
b3d44315
MV
1535// AcqArchive::IsTrusted - Determine whether this archive comes from a
1536// trusted source /*{{{*/
1537// ---------------------------------------------------------------------
1538bool pkgAcqArchive::IsTrusted()
1539{
1540 return Trusted;
1541}
1542
ab559b35
AL
1543// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1544// ---------------------------------------------------------------------
1545/* */
1546void pkgAcqArchive::Finished()
1547{
1548 if (Status == pkgAcquire::Item::StatDone &&
1549 Complete == true)
1550 return;
1551 StoreFilename = string();
1552}
1553 /*}}}*/
36375005
AL
1554
1555// AcqFile::pkgAcqFile - Constructor /*{{{*/
1556// ---------------------------------------------------------------------
1557/* The file is added to the queue */
1558pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
46e00f9d
MV
1559 unsigned long Size,string Dsc,string ShortDesc,
1560 const string &DestDir, const string &DestFilename) :
b3c39978 1561 Item(Owner), Md5Hash(MD5)
36375005 1562{
08cfc005
AL
1563 Retries = _config->FindI("Acquire::Retries",0);
1564
46e00f9d
MV
1565 if(!DestFilename.empty())
1566 DestFile = DestFilename;
1567 else if(!DestDir.empty())
1568 DestFile = DestDir + "/" + flNotDir(URI);
1569 else
1570 DestFile = flNotDir(URI);
1571
36375005
AL
1572 // Create the item
1573 Desc.URI = URI;
1574 Desc.Description = Dsc;
1575 Desc.Owner = this;
1576
1577 // Set the short description to the archive component
1578 Desc.ShortDesc = ShortDesc;
1579
1580 // Get the transfer sizes
1581 FileSize = Size;
1582 struct stat Buf;
1583 if (stat(DestFile.c_str(),&Buf) == 0)
1584 {
1585 // Hmm, the partial file is too big, erase it
1586 if ((unsigned)Buf.st_size > Size)
1587 unlink(DestFile.c_str());
1588 else
1589 PartialSize = Buf.st_size;
1590 }
092ae175 1591
36375005
AL
1592 QueueURI(Desc);
1593}
1594 /*}}}*/
1595// AcqFile::Done - Item downloaded OK /*{{{*/
1596// ---------------------------------------------------------------------
1597/* */
459681d3
AL
1598void pkgAcqFile::Done(string Message,unsigned long Size,string MD5,
1599 pkgAcquire::MethodConfig *Cnf)
36375005 1600{
b3c39978
AL
1601 // Check the md5
1602 if (Md5Hash.empty() == false && MD5.empty() == false)
1603 {
1604 if (Md5Hash != MD5)
1605 {
1606 Status = StatError;
1607 ErrorText = "MD5Sum mismatch";
1608 Rename(DestFile,DestFile + ".FAILED");
1609 return;
1610 }
1611 }
1612
459681d3 1613 Item::Done(Message,Size,MD5,Cnf);
36375005
AL
1614
1615 string FileName = LookupTag(Message,"Filename");
1616 if (FileName.empty() == true)
1617 {
1618 Status = StatError;
1619 ErrorText = "Method gave a blank filename";
1620 return;
1621 }
1622
1623 Complete = true;
1624
1625 // The files timestamp matches
1626 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
1627 return;
1628
1629 // We have to copy it into place
1630 if (FileName != DestFile)
1631 {
1632 Local = true;
459681d3
AL
1633 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
1634 Cnf->Removable == true)
917ae805
AL
1635 {
1636 Desc.URI = "copy:" + FileName;
1637 QueueURI(Desc);
1638 return;
1639 }
1640
83ab33fc
AL
1641 // Erase the file if it is a symlink so we can overwrite it
1642 struct stat St;
1643 if (lstat(DestFile.c_str(),&St) == 0)
1644 {
1645 if (S_ISLNK(St.st_mode) != 0)
1646 unlink(DestFile.c_str());
1647 }
1648
1649 // Symlink the file
917ae805
AL
1650 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
1651 {
83ab33fc 1652 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
1653 Status = StatError;
1654 Complete = false;
1655 }
36375005
AL
1656 }
1657}
1658 /*}}}*/
08cfc005
AL
1659// AcqFile::Failed - Failure handler /*{{{*/
1660// ---------------------------------------------------------------------
1661/* Here we try other sources */
1662void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
1663{
1664 ErrorText = LookupTag(Message,"Message");
1665
1666 // This is the retry counter
1667 if (Retries != 0 &&
1668 Cnf->LocalOnly == false &&
1669 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
1670 {
1671 Retries--;
1672 QueueURI(Desc);
1673 return;
1674 }
1675
1676 Item::Failed(Message,Cnf);
1677}
1678 /*}}}*/