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