1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
4 /* ######################################################################
6 Acquire Item - Item to acquire
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.
13 ##################################################################### */
15 // Include Files /*{{{*/
18 #include <apt-pkg/acquire-item.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/aptconfiguration.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/sha1.h>
26 #include <apt-pkg/tagfile.h>
27 #include <apt-pkg/indexrecords.h>
28 #include <apt-pkg/acquire.h>
29 #include <apt-pkg/hashes.h>
30 #include <apt-pkg/indexfile.h>
31 #include <apt-pkg/pkgcache.h>
32 #include <apt-pkg/cacheiterators.h>
33 #include <apt-pkg/pkgrecords.h>
53 // Acquire::Item::Item - Constructor /*{{{*/
54 // ---------------------------------------------------------------------
56 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
57 PartialSize(0), Mode(0), ID(0), Complete(false),
58 Local(false), QueueCounter(0),
59 ExpectedAdditionalItems(0)
65 // Acquire::Item::~Item - Destructor /*{{{*/
66 // ---------------------------------------------------------------------
68 pkgAcquire::Item::~Item()
73 // Acquire::Item::Failed - Item failed to download /*{{{*/
74 // ---------------------------------------------------------------------
75 /* We return to an idle state if there are still other queues that could
77 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
80 ErrorText
= LookupTag(Message
,"Message");
81 UsedMirror
= LookupTag(Message
,"UsedMirror");
82 if (QueueCounter
<= 1)
84 /* This indicates that the file is not available right now but might
85 be sometime later. If we do a retry cycle then this should be
87 if (Cnf
->LocalOnly
== true &&
88 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
99 // report mirror failure back to LP if we actually use a mirror
100 string FailReason
= LookupTag(Message
, "FailReason");
101 if(FailReason
.size() != 0)
102 ReportMirrorFailure(FailReason
);
104 ReportMirrorFailure(ErrorText
);
107 // Acquire::Item::Start - Item has begun to download /*{{{*/
108 // ---------------------------------------------------------------------
109 /* Stash status and the file size. Note that setting Complete means
110 sub-phases of the acquire process such as decompresion are operating */
111 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
113 Status
= StatFetching
;
114 if (FileSize
== 0 && Complete
== false)
118 // Acquire::Item::Done - Item downloaded OK /*{{{*/
119 // ---------------------------------------------------------------------
121 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,string
/*Hash*/,
122 pkgAcquire::MethodConfig
* /*Cnf*/)
124 // We just downloaded something..
125 string FileName
= LookupTag(Message
,"Filename");
126 UsedMirror
= LookupTag(Message
,"UsedMirror");
127 if (Complete
== false && !Local
&& FileName
== DestFile
)
130 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
136 ErrorText
= string();
137 Owner
->Dequeue(this);
140 // Acquire::Item::Rename - Rename a file /*{{{*/
141 // ---------------------------------------------------------------------
142 /* This helper function is used by a lot of item methods as their final
144 void pkgAcquire::Item::Rename(string From
,string To
)
146 if (rename(From
.c_str(),To
.c_str()) != 0)
149 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
150 From
.c_str(),To
.c_str());
156 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
158 if(FileExists(DestFile
))
159 Rename(DestFile
, DestFile
+ ".FAILED");
163 case HashSumMismatch
:
164 ErrorText
= _("Hash Sum mismatch");
165 Status
= StatAuthError
;
166 ReportMirrorFailure("HashChecksumFailure");
169 ErrorText
= _("Size mismatch");
170 Status
= StatAuthError
;
171 ReportMirrorFailure("SizeFailure");
174 ErrorText
= _("Invalid file format");
176 // do not report as usually its not the mirrors fault, but Portal/Proxy
182 // Acquire::Item::ReportMirrorFailure /*{{{*/
183 // ---------------------------------------------------------------------
184 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
186 // we only act if a mirror was used at all
187 if(UsedMirror
.empty())
190 std::cerr
<< "\nReportMirrorFailure: "
192 << " Uri: " << DescURI()
194 << FailCode
<< std::endl
;
196 const char *Args
[40];
198 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
199 "/usr/lib/apt/apt-report-mirror-failure");
200 if(!FileExists(report
))
202 Args
[i
++] = report
.c_str();
203 Args
[i
++] = UsedMirror
.c_str();
204 Args
[i
++] = DescURI().c_str();
205 Args
[i
++] = FailCode
.c_str();
207 pid_t pid
= ExecFork();
210 _error
->Error("ReportMirrorFailure Fork failed");
215 execvp(Args
[0], (char**)Args
);
216 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
219 if(!ExecWait(pid
, "report-mirror-failure"))
221 _error
->Warning("Couldn't report problem to '%s'",
222 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
226 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
227 // ---------------------------------------------------------------------
228 /* Get a sub-index file based on checksums from a 'master' file and
229 possibly query additional files */
230 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
231 string
const &URIDesc
, string
const &ShortDesc
,
232 HashString
const &ExpectedHash
)
233 : Item(Owner
), ExpectedHash(ExpectedHash
)
235 /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
236 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
238 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
239 DestFile
+= URItoFileName(URI
);
242 Desc
.Description
= URIDesc
;
244 Desc
.ShortDesc
= ShortDesc
;
249 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
252 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
253 // ---------------------------------------------------------------------
254 /* The only header we use is the last-modified header. */
255 string
pkgAcqSubIndex::Custom600Headers()
257 string Final
= _config
->FindDir("Dir::State::lists");
258 Final
+= URItoFileName(Desc
.URI
);
261 if (stat(Final
.c_str(),&Buf
) != 0)
262 return "\nIndex-File: true\nFail-Ignore: true\n";
263 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
266 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
269 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
275 // No good Index is provided
278 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
279 pkgAcquire::MethodConfig
*Cnf
)
282 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
284 string FileName
= LookupTag(Message
,"Filename");
285 if (FileName
.empty() == true)
288 ErrorText
= "Method gave a blank filename";
292 if (FileName
!= DestFile
)
295 Desc
.URI
= "copy:" + FileName
;
300 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
302 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
304 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
305 indexRecords SubIndexParser
;
306 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
308 ErrorText
= SubIndexParser
.ErrorText
;
312 // success in downloading the index
315 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
316 Rename(DestFile
,FinalFile
);
317 chmod(FinalFile
.c_str(),0644);
318 DestFile
= FinalFile
;
320 if(ParseIndex(DestFile
) == false)
321 return Failed("", NULL
);
329 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
331 indexRecords SubIndexParser
;
332 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
334 // so something with the downloaded index
338 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
339 // ---------------------------------------------------------------------
340 /* Get the DiffIndex file first and see if there are patches available
341 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
342 * patches. If anything goes wrong in that process, it will fall back to
343 * the original packages file
345 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
346 string URI
,string URIDesc
,string ShortDesc
,
347 HashString ExpectedHash
)
348 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
352 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
354 Desc
.Description
= URIDesc
+ "/DiffIndex";
356 Desc
.ShortDesc
= ShortDesc
;
357 Desc
.URI
= URI
+ ".diff/Index";
359 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
360 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
363 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
365 // look for the current package file
366 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
367 CurrentPackagesFile
+= URItoFileName(RealURI
);
369 // FIXME: this file:/ check is a hack to prevent fetching
370 // from local sources. this is really silly, and
371 // should be fixed cleanly as soon as possible
372 if(!FileExists(CurrentPackagesFile
) ||
373 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
375 // we don't have a pkg file or we don't want to queue
377 std::clog
<< "No index file, local or canceld by user" << std::endl
;
383 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
384 << CurrentPackagesFile
<< std::endl
;
390 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
391 // ---------------------------------------------------------------------
392 /* The only header we use is the last-modified header. */
393 string
pkgAcqDiffIndex::Custom600Headers()
395 string Final
= _config
->FindDir("Dir::State::lists");
396 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
399 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
402 if (stat(Final
.c_str(),&Buf
) != 0)
403 return "\nIndex-File: true";
405 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
408 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
411 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
416 vector
<DiffInfo
> available_patches
;
418 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
420 if (_error
->PendingError() == true)
423 if(TF
.Step(Tags
) == true)
429 string
const tmp
= Tags
.FindS("SHA1-Current");
430 std::stringstream
ss(tmp
);
431 ss
>> ServerSha1
>> size
;
432 unsigned long const ServerSize
= atol(size
.c_str());
434 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
437 string
const local_sha1
= SHA1
.Result();
439 if(local_sha1
== ServerSha1
)
441 // we have the same sha1 as the server so we are done here
443 std::clog
<< "Package file is up-to-date" << std::endl
;
444 // list cleanup needs to know that this file as well as the already
445 // present index is ours, so we create an empty diff to save it for us
446 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
447 ExpectedHash
, ServerSha1
, available_patches
);
453 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
455 // check the historie and see what patches we need
456 string
const history
= Tags
.FindS("SHA1-History");
457 std::stringstream
hist(history
);
458 while(hist
>> d
.sha1
>> size
>> d
.file
)
460 // read until the first match is found
461 // from that point on, we probably need all diffs
462 if(d
.sha1
== local_sha1
)
464 else if (found
== false)
468 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
469 available_patches
.push_back(d
);
472 if (available_patches
.empty() == false)
474 // patching with too many files is rather slow compared to a fast download
475 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
476 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
479 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
480 << ") so fallback to complete download" << std::endl
;
484 // see if the patches are too big
485 found
= false; // it was true and it will be true again at the end
486 d
= *available_patches
.begin();
487 string
const firstPatch
= d
.file
;
488 unsigned long patchesSize
= 0;
489 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
490 while(patches
>> d
.sha1
>> size
>> d
.file
)
492 if (firstPatch
== d
.file
)
494 else if (found
== false)
497 patchesSize
+= atol(size
.c_str());
499 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
500 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
503 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
504 << ") so fallback to complete download" << std::endl
;
510 // we have something, queue the next diff
514 string::size_type
const last_space
= Description
.rfind(" ");
515 if(last_space
!= string::npos
)
516 Description
.erase(last_space
, Description
.size()-last_space
);
518 /* decide if we should download patches one by one or in one go:
519 The first is good if the server merges patches, but many don't so client
520 based merging can be attempt in which case the second is better.
521 "bad things" will happen if patches are merged on the server,
522 but client side merging is attempt as well */
523 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
524 if (pdiff_merge
== true)
526 // reprepro adds this flag if it has merged patches on the server
527 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
528 pdiff_merge
= (precedence
!= "merged");
531 if (pdiff_merge
== false)
532 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
533 ExpectedHash
, ServerSha1
, available_patches
);
536 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
537 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
538 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
, ExpectedHash
,
539 available_patches
[i
], diffs
);
549 // Nothing found, report and return false
550 // Failing here is ok, if we return false later, the full
551 // IndexFile is queued
553 std::clog
<< "Can't find a patch in the index file" << std::endl
;
557 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
560 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
561 << "Falling back to normal index file acquire" << std::endl
;
563 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
571 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
572 pkgAcquire::MethodConfig
*Cnf
)
575 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
577 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
580 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
582 // success in downloading the index
584 FinalFile
+= string(".IndexDiff");
586 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
588 Rename(DestFile
,FinalFile
);
589 chmod(FinalFile
.c_str(),0644);
590 DestFile
= FinalFile
;
592 if(!ParseDiffIndex(DestFile
))
593 return Failed("", NULL
);
601 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
602 // ---------------------------------------------------------------------
603 /* The package diff is added to the queue. one object is constructed
604 * for each diff and the index
606 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
607 string URI
,string URIDesc
,string ShortDesc
,
608 HashString ExpectedHash
,
610 vector
<DiffInfo
> diffs
)
611 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
612 available_patches(diffs
), ServerSha1(ServerSha1
)
615 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
616 DestFile
+= URItoFileName(URI
);
618 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
620 Description
= URIDesc
;
622 Desc
.ShortDesc
= ShortDesc
;
624 if(available_patches
.empty() == true)
626 // we are done (yeah!)
632 State
= StateFetchDiff
;
637 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
640 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
641 << "Falling back to normal index file acquire" << std::endl
;
642 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
647 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
648 void pkgAcqIndexDiffs::Finish(bool allDone
)
650 // we restore the original name, this is required, otherwise
651 // the file will be cleaned
654 DestFile
= _config
->FindDir("Dir::State::lists");
655 DestFile
+= URItoFileName(RealURI
);
657 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
659 RenameOnError(HashSumMismatch
);
664 // this is for the "real" finish
669 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
674 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
681 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
684 // calc sha1 of the just patched file
685 string FinalFile
= _config
->FindDir("Dir::State::lists");
686 FinalFile
+= URItoFileName(RealURI
);
688 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
691 string local_sha1
= string(SHA1
.Result());
693 std::clog
<< "QueueNextDiff: "
694 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
696 // final file reached before all patches are applied
697 if(local_sha1
== ServerSha1
)
703 // remove all patches until the next matching patch is found
704 // this requires the Index file to be ordered
705 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
706 available_patches
.empty() == false &&
707 I
!= available_patches
.end() &&
708 I
->sha1
!= local_sha1
;
711 available_patches
.erase(I
);
714 // error checking and falling back if no patch was found
715 if(available_patches
.empty() == true)
721 // queue the right diff
722 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
723 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
724 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
725 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
728 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
735 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
736 pkgAcquire::MethodConfig
*Cnf
)
739 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
741 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
744 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
746 // success in downloading a diff, enter ApplyDiff state
747 if(State
== StateFetchDiff
)
750 // rred excepts the patch as $FinalFile.ed
751 Rename(DestFile
,FinalFile
+".ed");
754 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
756 State
= StateApplyDiff
;
758 Desc
.URI
= "rred:" + FinalFile
;
765 // success in download/apply a diff, queue next (if needed)
766 if(State
== StateApplyDiff
)
768 // remove the just applied patch
769 available_patches
.erase(available_patches
.begin());
770 unlink((FinalFile
+ ".ed").c_str());
775 std::clog
<< "Moving patched file in place: " << std::endl
776 << DestFile
<< " -> " << FinalFile
<< std::endl
;
778 Rename(DestFile
,FinalFile
);
779 chmod(FinalFile
.c_str(),0644);
781 // see if there is more to download
782 if(available_patches
.empty() == false) {
783 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
784 ExpectedHash
, ServerSha1
, available_patches
);
791 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
792 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
793 string
const &URI
, string
const &URIDesc
,
794 string
const &ShortDesc
, HashString
const &ExpectedHash
,
795 DiffInfo
const &patch
,
796 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
797 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
798 patch(patch
),allPatches(allPatches
), State(StateFetchDiff
)
801 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
802 DestFile
+= URItoFileName(URI
);
804 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
806 Description
= URIDesc
;
808 Desc
.ShortDesc
= ShortDesc
;
810 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
811 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
812 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
813 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
816 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
821 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
824 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
829 // check if we are the first to fail, otherwise we are done here
830 State
= StateDoneDiff
;
831 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
832 I
!= allPatches
->end(); ++I
)
833 if ((*I
)->State
== StateErrorDiff
)
836 // first failure means we should fallback
837 State
= StateErrorDiff
;
838 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
839 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
843 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
844 pkgAcquire::MethodConfig
*Cnf
)
847 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
849 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
851 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
853 if (State
== StateFetchDiff
)
855 // rred expects the patch as $FinalFile.ed.$patchname.gz
856 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
858 // check if this is the last completed diff
859 State
= StateDoneDiff
;
860 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
861 I
!= allPatches
->end(); ++I
)
862 if ((*I
)->State
!= StateDoneDiff
)
865 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
869 // this is the last completed diff, so we are ready to apply now
870 State
= StateApplyDiff
;
873 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
876 Desc
.URI
= "rred:" + FinalFile
;
881 // success in download/apply all diffs, clean up
882 else if (State
== StateApplyDiff
)
884 // see if we really got the expected file
885 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
887 RenameOnError(HashSumMismatch
);
891 // move the result into place
893 std::clog
<< "Moving patched file in place: " << std::endl
894 << DestFile
<< " -> " << FinalFile
<< std::endl
;
895 Rename(DestFile
, FinalFile
);
896 chmod(FinalFile
.c_str(), 0644);
898 // otherwise lists cleanup will eat the file
899 DestFile
= FinalFile
;
901 // ensure the ed's are gone regardless of list-cleanup
902 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
903 I
!= allPatches
->end(); ++I
)
905 std::string patch
= FinalFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
906 unlink(patch
.c_str());
912 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
916 // AcqIndex::AcqIndex - Constructor /*{{{*/
917 // ---------------------------------------------------------------------
918 /* The package file is added to the queue and a second class is
919 instantiated to fetch the revision file */
920 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
921 string URI
,string URIDesc
,string ShortDesc
,
922 HashString ExpectedHash
, string comprExt
)
923 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
925 if(comprExt
.empty() == true)
927 // autoselect the compression method
928 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
929 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
930 comprExt
.append(*t
).append(" ");
931 if (comprExt
.empty() == false)
932 comprExt
.erase(comprExt
.end()-1);
934 CompressionExtension
= comprExt
;
936 Init(URI
, URIDesc
, ShortDesc
);
938 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
939 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
940 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
942 // autoselect the compression method
943 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
944 CompressionExtension
= "";
945 if (ExpectedHash
.empty() == false)
947 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
948 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
949 CompressionExtension
.append(*t
).append(" ");
953 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
954 CompressionExtension
.append(*t
).append(" ");
956 if (CompressionExtension
.empty() == false)
957 CompressionExtension
.erase(CompressionExtension
.end()-1);
959 // only verify non-optional targets, see acquire-item.h for a FIXME
960 // to make this more flexible
961 if (Target
->IsOptional())
966 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
969 // AcqIndex::Init - defered Constructor /*{{{*/
970 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
971 Decompression
= false;
974 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
975 DestFile
+= URItoFileName(URI
);
977 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
978 if (comprExt
== "uncompressed")
981 Desc
.URI
= URI
+ '.' + comprExt
;
983 Desc
.Description
= URIDesc
;
985 Desc
.ShortDesc
= ShortDesc
;
990 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
991 // ---------------------------------------------------------------------
992 /* The only header we use is the last-modified header. */
993 string
pkgAcqIndex::Custom600Headers()
995 string Final
= _config
->FindDir("Dir::State::lists");
996 Final
+= URItoFileName(RealURI
);
997 if (_config
->FindB("Acquire::GzipIndexes",false))
1000 string msg
= "\nIndex-File: true";
1001 // FIXME: this really should use "IndexTarget::IsOptional()" but that
1002 // seems to be difficult without breaking ABI
1003 if (ShortDesc().find("Translation") != 0)
1004 msg
+= "\nFail-Ignore: true";
1006 if (stat(Final
.c_str(),&Buf
) == 0)
1007 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1012 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1014 size_t const nextExt
= CompressionExtension
.find(' ');
1015 if (nextExt
!= std::string::npos
)
1017 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1018 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1022 // on decompression failure, remove bad versions in partial/
1023 if (Decompression
&& Erase
) {
1024 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1025 s
.append(URItoFileName(RealURI
));
1029 Item::Failed(Message
,Cnf
);
1032 // AcqIndex::Done - Finished a fetch /*{{{*/
1033 // ---------------------------------------------------------------------
1034 /* This goes through a number of states.. On the initial fetch the
1035 method could possibly return an alternate filename which points
1036 to the uncompressed version of the file. If this is so the file
1037 is copied into the partial directory. In all other cases the file
1038 is decompressed with a gzip uri. */
1039 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
1040 pkgAcquire::MethodConfig
*Cfg
)
1042 Item::Done(Message
,Size
,Hash
,Cfg
);
1044 if (Decompression
== true)
1046 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1048 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
1049 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
1052 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
1054 RenameOnError(HashSumMismatch
);
1058 /* Verify the index file for correctness (all indexes must
1059 * have a Package field) (LP: #346386) (Closes: #627642) */
1062 FileFd
fd(DestFile
, FileFd::ReadOnly
);
1063 // Only test for correctness if the file is not empty (empty is ok)
1064 if (fd
.FileSize() > 0)
1067 pkgTagFile
tag(&fd
);
1069 // all our current indexes have a field 'Package' in each section
1070 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1072 RenameOnError(InvalidFormat
);
1078 // Done, move it into position
1079 string FinalFile
= _config
->FindDir("Dir::State::lists");
1080 FinalFile
+= URItoFileName(RealURI
);
1081 Rename(DestFile
,FinalFile
);
1082 chmod(FinalFile
.c_str(),0644);
1084 /* We restore the original name to DestFile so that the clean operation
1086 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1087 DestFile
+= URItoFileName(RealURI
);
1089 // Remove the compressed version.
1091 unlink(DestFile
.c_str());
1098 // Handle the unzipd case
1099 string FileName
= LookupTag(Message
,"Alt-Filename");
1100 if (FileName
.empty() == false)
1102 // The files timestamp matches
1103 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
1105 Decompression
= true;
1107 DestFile
+= ".decomp";
1108 Desc
.URI
= "copy:" + FileName
;
1114 FileName
= LookupTag(Message
,"Filename");
1115 if (FileName
.empty() == true)
1118 ErrorText
= "Method gave a blank filename";
1121 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1123 // The files timestamp matches
1124 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
1125 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1126 // Update DestFile for .gz suffix so that the clean operation keeps it
1131 if (FileName
== DestFile
)
1138 // If we enable compressed indexes and already have gzip, keep it
1139 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
1140 string FinalFile
= _config
->FindDir("Dir::State::lists");
1141 FinalFile
+= URItoFileName(RealURI
) + ".gz";
1142 Rename(DestFile
,FinalFile
);
1143 chmod(FinalFile
.c_str(),0644);
1145 // Update DestFile for .gz suffix so that the clean operation keeps it
1146 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1147 DestFile
+= URItoFileName(RealURI
) + ".gz";
1151 // get the binary name for your used compression type
1152 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1153 if(decompProg
.empty() == false);
1154 else if(compExt
== "uncompressed")
1155 decompProg
= "copy";
1157 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1161 Decompression
= true;
1162 DestFile
+= ".decomp";
1163 Desc
.URI
= decompProg
+ ":" + FileName
;
1166 // FIXME: this points to a c++ string that goes out of scope
1167 Mode
= decompProg
.c_str();
1170 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1171 // ---------------------------------------------------------------------
1172 /* The Translation file is added to the queue */
1173 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1174 string URI
,string URIDesc
,string ShortDesc
)
1175 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1178 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1179 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1180 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1184 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1185 // ---------------------------------------------------------------------
1186 string
pkgAcqIndexTrans::Custom600Headers()
1188 string Final
= _config
->FindDir("Dir::State::lists");
1189 Final
+= URItoFileName(RealURI
);
1192 if (stat(Final
.c_str(),&Buf
) != 0)
1193 return "\nFail-Ignore: true\nIndex-File: true";
1194 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1197 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1198 // ---------------------------------------------------------------------
1200 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1202 size_t const nextExt
= CompressionExtension
.find(' ');
1203 if (nextExt
!= std::string::npos
)
1205 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1206 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1211 if (Cnf
->LocalOnly
== true ||
1212 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1221 Item::Failed(Message
,Cnf
);
1224 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1225 string URI
,string URIDesc
,string ShortDesc
,
1226 string MetaIndexURI
, string MetaIndexURIDesc
,
1227 string MetaIndexShortDesc
,
1228 const vector
<IndexTarget
*>* IndexTargets
,
1229 indexRecords
* MetaIndexParser
) :
1230 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1231 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1232 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1234 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1235 DestFile
+= URItoFileName(URI
);
1237 // remove any partial downloaded sig-file in partial/.
1238 // it may confuse proxies and is too small to warrant a
1239 // partial download anyway
1240 unlink(DestFile
.c_str());
1243 Desc
.Description
= URIDesc
;
1245 Desc
.ShortDesc
= ShortDesc
;
1248 string Final
= _config
->FindDir("Dir::State::lists");
1249 Final
+= URItoFileName(RealURI
);
1250 if (RealFileExists(Final
) == true)
1252 // File was already in place. It needs to be re-downloaded/verified
1253 // because Release might have changed, we do give it a different
1254 // name than DestFile because otherwise the http method will
1255 // send If-Range requests and there are too many broken servers
1256 // out there that do not understand them
1257 LastGoodSig
= DestFile
+".reverify";
1258 Rename(Final
,LastGoodSig
);
1261 // we expect the indextargets + one additional Release file
1262 ExpectedAdditionalItems
= IndexTargets
->size() + 1;
1267 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1269 // if the file was never queued undo file-changes done in the constructor
1270 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1271 LastGoodSig
.empty() == false)
1273 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1274 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1275 Rename(LastGoodSig
, Final
);
1280 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1281 // ---------------------------------------------------------------------
1282 /* The only header we use is the last-modified header. */
1283 string
pkgAcqMetaSig::Custom600Headers()
1286 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1287 return "\nIndex-File: true";
1289 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1292 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1293 pkgAcquire::MethodConfig
*Cfg
)
1295 Item::Done(Message
,Size
,MD5
,Cfg
);
1297 string FileName
= LookupTag(Message
,"Filename");
1298 if (FileName
.empty() == true)
1301 ErrorText
= "Method gave a blank filename";
1305 if (FileName
!= DestFile
)
1307 // We have to copy it into place
1309 Desc
.URI
= "copy:" + FileName
;
1316 // at this point pkgAcqMetaIndex takes over
1317 ExpectedAdditionalItems
= 0;
1319 // put the last known good file back on i-m-s hit (it will
1320 // be re-verified again)
1321 // Else do nothing, we have the new file in DestFile then
1322 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1323 Rename(LastGoodSig
, DestFile
);
1325 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1326 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1327 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1332 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1334 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1336 // at this point pkgAcqMetaIndex takes over
1337 ExpectedAdditionalItems
= 0;
1339 // if we get a network error we fail gracefully
1340 if(Status
== StatTransientNetworkError
)
1342 Item::Failed(Message
,Cnf
);
1343 // move the sigfile back on transient network failures
1344 if(FileExists(LastGoodSig
))
1345 Rename(LastGoodSig
,Final
);
1347 // set the status back to , Item::Failed likes to reset it
1348 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1352 // Delete any existing sigfile when the acquire failed
1353 unlink(Final
.c_str());
1355 // queue a pkgAcqMetaIndex with no sigfile
1356 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1357 "", IndexTargets
, MetaIndexParser
);
1359 if (Cnf
->LocalOnly
== true ||
1360 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1369 Item::Failed(Message
,Cnf
);
1372 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1373 string URI
,string URIDesc
,string ShortDesc
,
1375 const vector
<struct IndexTarget
*>* IndexTargets
,
1376 indexRecords
* MetaIndexParser
) :
1377 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1378 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1380 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1381 DestFile
+= URItoFileName(URI
);
1384 Desc
.Description
= URIDesc
;
1386 Desc
.ShortDesc
= ShortDesc
;
1389 // we expect more item
1390 ExpectedAdditionalItems
= IndexTargets
->size();
1395 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1396 // ---------------------------------------------------------------------
1397 /* The only header we use is the last-modified header. */
1398 string
pkgAcqMetaIndex::Custom600Headers()
1400 string Final
= _config
->FindDir("Dir::State::lists");
1401 Final
+= URItoFileName(RealURI
);
1404 if (stat(Final
.c_str(),&Buf
) != 0)
1405 return "\nIndex-File: true";
1407 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1410 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1411 pkgAcquire::MethodConfig
*Cfg
)
1413 Item::Done(Message
,Size
,Hash
,Cfg
);
1415 // MetaIndexes are done in two passes: one to download the
1416 // metaindex with an appropriate method, and a second to verify it
1417 // with the gpgv method
1419 if (AuthPass
== true)
1423 // all cool, move Release file into place
1428 RetrievalDone(Message
);
1430 // Still more retrieving to do
1435 // There was no signature file, so we are finished. Download
1436 // the indexes and do only hashsum verification if possible
1437 MetaIndexParser
->Load(DestFile
);
1438 QueueIndexes(false);
1442 // There was a signature file, so pass it to gpgv for
1445 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1446 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1447 << SigFile
<< "," << DestFile
<< ")\n";
1449 Desc
.URI
= "gpgv:" + SigFile
;
1456 if (Complete
== true)
1458 string FinalFile
= _config
->FindDir("Dir::State::lists");
1459 FinalFile
+= URItoFileName(RealURI
);
1460 if (SigFile
== DestFile
)
1461 SigFile
= FinalFile
;
1462 Rename(DestFile
,FinalFile
);
1463 chmod(FinalFile
.c_str(),0644);
1464 DestFile
= FinalFile
;
1468 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1470 // We have just finished downloading a Release file (it is not
1473 string FileName
= LookupTag(Message
,"Filename");
1474 if (FileName
.empty() == true)
1477 ErrorText
= "Method gave a blank filename";
1481 if (FileName
!= DestFile
)
1484 Desc
.URI
= "copy:" + FileName
;
1489 // make sure to verify against the right file on I-M-S hit
1490 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1493 string FinalFile
= _config
->FindDir("Dir::State::lists");
1494 FinalFile
+= URItoFileName(RealURI
);
1495 if (SigFile
== DestFile
)
1497 SigFile
= FinalFile
;
1498 // constructor of pkgAcqMetaClearSig moved it out of the way,
1499 // now move it back in on IMS hit for the 'old' file
1500 string
const OldClearSig
= DestFile
+ ".reverify";
1501 if (RealFileExists(OldClearSig
) == true)
1502 Rename(OldClearSig
, FinalFile
);
1504 DestFile
= FinalFile
;
1509 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1511 // At this point, the gpgv method has succeeded, so there is a
1512 // valid signature from a key in the trusted keyring. We
1513 // perform additional verification of its contents, and use them
1514 // to verify the indexes we are about to download
1516 if (!MetaIndexParser
->Load(DestFile
))
1518 Status
= StatAuthError
;
1519 ErrorText
= MetaIndexParser
->ErrorText
;
1523 if (!VerifyVendor(Message
))
1528 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1529 std::cerr
<< "Signature verification succeeded: "
1530 << DestFile
<< std::endl
;
1532 // Download further indexes with verification
1535 // is it a clearsigned MetaIndex file?
1536 if (DestFile
== SigFile
)
1539 // Done, move signature file into position
1540 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1541 URItoFileName(RealURI
) + ".gpg";
1542 Rename(SigFile
,VerifiedSigFile
);
1543 chmod(VerifiedSigFile
.c_str(),0644);
1546 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1549 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1550 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1551 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1554 ErrorText
= MetaIndexParser
->ErrorText
;
1558 bool transInRelease
= false;
1560 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1561 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1562 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1563 if (k
->find("Translation-") != std::string::npos
)
1565 transInRelease
= true;
1570 // at this point the real Items are loaded in the fetcher
1571 ExpectedAdditionalItems
= 0;
1573 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1574 Target
!= IndexTargets
->end();
1577 HashString ExpectedIndexHash
;
1578 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1579 bool compressedAvailable
= false;
1582 if ((*Target
)->IsOptional() == true)
1584 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1585 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1586 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1588 compressedAvailable
= true;
1592 else if (verify
== true)
1594 Status
= StatAuthError
;
1595 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1601 ExpectedIndexHash
= Record
->Hash
;
1602 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1604 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1605 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1606 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1608 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1610 Status
= StatAuthError
;
1611 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1616 if ((*Target
)->IsOptional() == true)
1618 if ((*Target
)->IsSubIndex() == true)
1619 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1620 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1621 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1623 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1624 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1625 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1626 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1628 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1633 /* Queue Packages file (either diff or full packages files, depending
1634 on the users option) - we also check if the PDiff Index file is listed
1635 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1636 instead, but passing the required info to it is to much hassle */
1637 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1638 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1639 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1640 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1642 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1646 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1648 string::size_type pos
;
1650 // check for missing sigs (that where not fatal because otherwise we had
1653 string msg
= _("There is no public key available for the "
1654 "following key IDs:\n");
1655 pos
= Message
.find("NO_PUBKEY ");
1656 if (pos
!= std::string::npos
)
1658 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1659 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1660 missingkeys
+= (Fingerprint
);
1662 if(!missingkeys
.empty())
1663 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1665 string Transformed
= MetaIndexParser
->GetExpectedDist();
1667 if (Transformed
== "../project/experimental")
1669 Transformed
= "experimental";
1672 pos
= Transformed
.rfind('/');
1673 if (pos
!= string::npos
)
1675 Transformed
= Transformed
.substr(0, pos
);
1678 if (Transformed
== ".")
1683 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1684 MetaIndexParser
->GetValidUntil() > 0) {
1685 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1686 if (invalid_since
> 0)
1687 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1688 // the time since then the file is invalid - formated in the same way as in
1689 // the download progress display (e.g. 7d 3h 42min 1s)
1690 return _error
->Error(
1691 _("Release file for %s is expired (invalid since %s). "
1692 "Updates for this repository will not be applied."),
1693 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1696 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1698 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1699 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1700 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1703 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1705 // This might become fatal one day
1706 // Status = StatAuthError;
1707 // ErrorText = "Conflicting distribution; expected "
1708 // + MetaIndexParser->GetExpectedDist() + " but got "
1709 // + MetaIndexParser->GetDist();
1711 if (!Transformed
.empty())
1713 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1714 Desc
.Description
.c_str(),
1715 Transformed
.c_str(),
1716 MetaIndexParser
->GetDist().c_str());
1723 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1724 // ---------------------------------------------------------------------
1726 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)
1728 if (AuthPass
== true)
1730 // gpgv method failed, if we have a good signature
1731 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1732 if (DestFile
!= SigFile
)
1733 LastGoodSigFile
.append(".gpg");
1734 LastGoodSigFile
.append(".reverify");
1736 if(FileExists(LastGoodSigFile
))
1738 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1739 if (DestFile
!= SigFile
)
1740 VerifiedSigFile
.append(".gpg");
1741 Rename(LastGoodSigFile
, VerifiedSigFile
);
1742 Status
= StatTransientNetworkError
;
1743 _error
->Warning(_("An error occurred during the signature "
1744 "verification. The repository is not updated "
1745 "and the previous index files will be used. "
1746 "GPG error: %s: %s\n"),
1747 Desc
.Description
.c_str(),
1748 LookupTag(Message
,"Message").c_str());
1749 RunScripts("APT::Update::Auth-Failure");
1751 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1752 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1753 _error
->Error(_("GPG error: %s: %s"),
1754 Desc
.Description
.c_str(),
1755 LookupTag(Message
,"Message").c_str());
1758 _error
->Warning(_("GPG error: %s: %s"),
1759 Desc
.Description
.c_str(),
1760 LookupTag(Message
,"Message").c_str());
1762 // gpgv method failed
1763 ReportMirrorFailure("GPGFailure");
1766 /* Always move the meta index, even if gpgv failed. This ensures
1767 * that PackageFile objects are correctly filled in */
1768 if (FileExists(DestFile
)) {
1769 string FinalFile
= _config
->FindDir("Dir::State::lists");
1770 FinalFile
+= URItoFileName(RealURI
);
1771 /* InRelease files become Release files, otherwise
1772 * they would be considered as trusted later on */
1773 if (SigFile
== DestFile
) {
1774 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1776 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1778 SigFile
= FinalFile
;
1780 Rename(DestFile
,FinalFile
);
1781 chmod(FinalFile
.c_str(),0644);
1783 DestFile
= FinalFile
;
1786 // No Release file was present, or verification failed, so fall
1787 // back to queueing Packages files without verification
1788 QueueIndexes(false);
1791 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1792 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1793 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1794 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1795 const vector
<struct IndexTarget
*>* IndexTargets
,
1796 indexRecords
* MetaIndexParser
) :
1797 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1798 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1799 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1803 // index targets + (worst case:) Release/Release.gpg
1804 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
1807 // keep the old InRelease around in case of transistent network errors
1808 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1809 if (RealFileExists(Final
) == true)
1811 string
const LastGoodSig
= DestFile
+ ".reverify";
1812 Rename(Final
,LastGoodSig
);
1816 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1818 // if the file was never queued undo file-changes done in the constructor
1819 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1821 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1822 string
const LastGoodSig
= DestFile
+ ".reverify";
1823 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1824 Rename(LastGoodSig
, Final
);
1828 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1829 // ---------------------------------------------------------------------
1830 // FIXME: this can go away once the InRelease file is used widely
1831 string
pkgAcqMetaClearSig::Custom600Headers()
1833 string Final
= _config
->FindDir("Dir::State::lists");
1834 Final
+= URItoFileName(RealURI
);
1837 if (stat(Final
.c_str(),&Buf
) != 0)
1839 Final
= DestFile
+ ".reverify";
1840 if (stat(Final
.c_str(),&Buf
) != 0)
1841 return "\nIndex-File: true\nFail-Ignore: true\n";
1844 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1847 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1849 // we failed, we will not get additional items from this method
1850 ExpectedAdditionalItems
= 0;
1852 if (AuthPass
== false)
1854 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1855 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1856 string FinalFile
= _config
->FindDir("Dir::State::lists");
1857 FinalFile
.append(URItoFileName(RealURI
));
1858 if (FileExists(FinalFile
))
1859 unlink(FinalFile
.c_str());
1861 new pkgAcqMetaSig(Owner
,
1862 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1863 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1864 IndexTargets
, MetaIndexParser
);
1865 if (Cnf
->LocalOnly
== true ||
1866 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1870 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1873 // AcqArchive::AcqArchive - Constructor /*{{{*/
1874 // ---------------------------------------------------------------------
1875 /* This just sets up the initial fetch environment and queues the first
1877 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1878 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1879 string
&StoreFilename
) :
1880 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1881 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1884 Retries
= _config
->FindI("Acquire::Retries",0);
1886 if (Version
.Arch() == 0)
1888 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1889 "This might mean you need to manually fix this package. "
1890 "(due to missing arch)"),
1891 Version
.ParentPkg().FullName().c_str());
1895 /* We need to find a filename to determine the extension. We make the
1896 assumption here that all the available sources for this version share
1897 the same extension.. */
1898 // Skip not source sources, they do not have file fields.
1899 for (; Vf
.end() == false; ++Vf
)
1901 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1906 // Does not really matter here.. we are going to fail out below
1907 if (Vf
.end() != true)
1909 // If this fails to get a file name we will bomb out below.
1910 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1911 if (_error
->PendingError() == true)
1914 // Generate the final file name as: package_version_arch.foo
1915 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1916 QuoteString(Version
.VerStr(),"_:") + '_' +
1917 QuoteString(Version
.Arch(),"_:.") +
1918 "." + flExtension(Parse
.FileName());
1921 // check if we have one trusted source for the package. if so, switch
1922 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1923 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
1924 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
1925 bool seenUntrusted
= false;
1926 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1928 pkgIndexFile
*Index
;
1929 if (Sources
->FindIndex(i
.File(),Index
) == false)
1932 if (debugAuth
== true)
1933 std::cerr
<< "Checking index: " << Index
->Describe()
1934 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
1936 if (Index
->IsTrusted() == true)
1939 if (allowUnauth
== false)
1943 seenUntrusted
= true;
1946 // "allow-unauthenticated" restores apts old fetching behaviour
1947 // that means that e.g. unauthenticated file:// uris are higher
1948 // priority than authenticated http:// uris
1949 if (allowUnauth
== true && seenUntrusted
== true)
1953 if (QueueNext() == false && _error
->PendingError() == false)
1954 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
1955 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
1958 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1959 // ---------------------------------------------------------------------
1960 /* This queues the next available file version for download. It checks if
1961 the archive is already available in the cache and stashs the MD5 for
1963 bool pkgAcqArchive::QueueNext()
1965 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1966 for (; Vf
.end() == false; ++Vf
)
1968 // Ignore not source sources
1969 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1972 // Try to cross match against the source list
1973 pkgIndexFile
*Index
;
1974 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1977 // only try to get a trusted package from another source if that source
1979 if(Trusted
&& !Index
->IsTrusted())
1982 // Grab the text package record
1983 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1984 if (_error
->PendingError() == true)
1987 string PkgFile
= Parse
.FileName();
1988 if (ForceHash
.empty() == false)
1990 if(stringcasecmp(ForceHash
, "sha512") == 0)
1991 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
1992 else if(stringcasecmp(ForceHash
, "sha256") == 0)
1993 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1994 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1995 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1997 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
2002 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
2003 ExpectedHash
= HashString("SHA512", Hash
);
2004 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
2005 ExpectedHash
= HashString("SHA256", Hash
);
2006 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
2007 ExpectedHash
= HashString("SHA1", Hash
);
2009 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
2011 if (PkgFile
.empty() == true)
2012 return _error
->Error(_("The package index files are corrupted. No Filename: "
2013 "field for package %s."),
2014 Version
.ParentPkg().Name());
2016 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2017 Desc
.Description
= Index
->ArchiveInfo(Version
);
2019 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2021 // See if we already have the file. (Legacy filenames)
2022 FileSize
= Version
->Size
;
2023 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2025 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2027 // Make sure the size matches
2028 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2033 StoreFilename
= DestFile
= FinalFile
;
2037 /* Hmm, we have a file and its size does not match, this means it is
2038 an old style mismatched arch */
2039 unlink(FinalFile
.c_str());
2042 // Check it again using the new style output filenames
2043 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2044 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2046 // Make sure the size matches
2047 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2052 StoreFilename
= DestFile
= FinalFile
;
2056 /* Hmm, we have a file and its size does not match, this shouldn't
2058 unlink(FinalFile
.c_str());
2061 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2063 // Check the destination file
2064 if (stat(DestFile
.c_str(),&Buf
) == 0)
2066 // Hmm, the partial file is too big, erase it
2067 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2068 unlink(DestFile
.c_str());
2070 PartialSize
= Buf
.st_size
;
2073 // Disables download of archives - useful if no real installation follows,
2074 // e.g. if we are just interested in proposed installation order
2075 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2080 StoreFilename
= DestFile
= FinalFile
;
2094 // AcqArchive::Done - Finished fetching /*{{{*/
2095 // ---------------------------------------------------------------------
2097 void pkgAcqArchive::Done(string Message
,unsigned long long Size
,string CalcHash
,
2098 pkgAcquire::MethodConfig
*Cfg
)
2100 Item::Done(Message
,Size
,CalcHash
,Cfg
);
2103 if (Size
!= Version
->Size
)
2105 RenameOnError(SizeMismatch
);
2110 if(ExpectedHash
.toStr() != CalcHash
)
2112 RenameOnError(HashSumMismatch
);
2116 // Grab the output filename
2117 string FileName
= LookupTag(Message
,"Filename");
2118 if (FileName
.empty() == true)
2121 ErrorText
= "Method gave a blank filename";
2127 // Reference filename
2128 if (FileName
!= DestFile
)
2130 StoreFilename
= DestFile
= FileName
;
2135 // Done, move it into position
2136 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2137 FinalFile
+= flNotDir(StoreFilename
);
2138 Rename(DestFile
,FinalFile
);
2140 StoreFilename
= DestFile
= FinalFile
;
2144 // AcqArchive::Failed - Failure handler /*{{{*/
2145 // ---------------------------------------------------------------------
2146 /* Here we try other sources */
2147 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2149 ErrorText
= LookupTag(Message
,"Message");
2151 /* We don't really want to retry on failed media swaps, this prevents
2152 that. An interesting observation is that permanent failures are not
2154 if (Cnf
->Removable
== true &&
2155 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2157 // Vf = Version.FileList();
2158 while (Vf
.end() == false) ++Vf
;
2159 StoreFilename
= string();
2160 Item::Failed(Message
,Cnf
);
2164 if (QueueNext() == false)
2166 // This is the retry counter
2168 Cnf
->LocalOnly
== false &&
2169 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2172 Vf
= Version
.FileList();
2173 if (QueueNext() == true)
2177 StoreFilename
= string();
2178 Item::Failed(Message
,Cnf
);
2182 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2183 // ---------------------------------------------------------------------
2184 APT_PURE
bool pkgAcqArchive::IsTrusted()
2189 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2190 // ---------------------------------------------------------------------
2192 void pkgAcqArchive::Finished()
2194 if (Status
== pkgAcquire::Item::StatDone
&&
2197 StoreFilename
= string();
2200 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2201 // ---------------------------------------------------------------------
2202 /* The file is added to the queue */
2203 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
2204 unsigned long long Size
,string Dsc
,string ShortDesc
,
2205 const string
&DestDir
, const string
&DestFilename
,
2207 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
2209 Retries
= _config
->FindI("Acquire::Retries",0);
2211 if(!DestFilename
.empty())
2212 DestFile
= DestFilename
;
2213 else if(!DestDir
.empty())
2214 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2216 DestFile
= flNotDir(URI
);
2220 Desc
.Description
= Dsc
;
2223 // Set the short description to the archive component
2224 Desc
.ShortDesc
= ShortDesc
;
2226 // Get the transfer sizes
2229 if (stat(DestFile
.c_str(),&Buf
) == 0)
2231 // Hmm, the partial file is too big, erase it
2232 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2233 unlink(DestFile
.c_str());
2235 PartialSize
= Buf
.st_size
;
2241 // AcqFile::Done - Item downloaded OK /*{{{*/
2242 // ---------------------------------------------------------------------
2244 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
2245 pkgAcquire::MethodConfig
*Cnf
)
2247 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2250 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2252 RenameOnError(HashSumMismatch
);
2256 string FileName
= LookupTag(Message
,"Filename");
2257 if (FileName
.empty() == true)
2260 ErrorText
= "Method gave a blank filename";
2266 // The files timestamp matches
2267 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2270 // We have to copy it into place
2271 if (FileName
!= DestFile
)
2274 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2275 Cnf
->Removable
== true)
2277 Desc
.URI
= "copy:" + FileName
;
2282 // Erase the file if it is a symlink so we can overwrite it
2284 if (lstat(DestFile
.c_str(),&St
) == 0)
2286 if (S_ISLNK(St
.st_mode
) != 0)
2287 unlink(DestFile
.c_str());
2291 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2293 ErrorText
= "Link to " + DestFile
+ " failure ";
2300 // AcqFile::Failed - Failure handler /*{{{*/
2301 // ---------------------------------------------------------------------
2302 /* Here we try other sources */
2303 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2305 ErrorText
= LookupTag(Message
,"Message");
2307 // This is the retry counter
2309 Cnf
->LocalOnly
== false &&
2310 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2317 Item::Failed(Message
,Cnf
);
2320 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2321 // ---------------------------------------------------------------------
2322 /* The only header we use is the last-modified header. */
2323 string
pkgAcqFile::Custom600Headers()
2326 return "\nIndex-File: true";