]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-item.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.43 2001/02/27 04:24:41 jgg 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 /*{{{*/
17 #pragma implementation "apt-pkg/acquire-item.h"
19 #include <apt-pkg/acquire-item.h>
20 #include <apt-pkg/configuration.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>
35 // Acquire::Item::Item - Constructor /*{{{*/
36 // ---------------------------------------------------------------------
38 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
39 PartialSize(0), Mode(0), ID(0), Complete(false),
40 Local(false), QueueCounter(0)
46 // Acquire::Item::~Item - Destructor /*{{{*/
47 // ---------------------------------------------------------------------
49 pkgAcquire::Item::~Item()
54 // Acquire::Item::Failed - Item failed to download /*{{{*/
55 // ---------------------------------------------------------------------
56 /* We return to an idle state if there are still other queues that could
58 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
61 ErrorText
= LookupTag(Message
,"Message");
62 if (QueueCounter
<= 1)
64 /* This indicates that the file is not available right now but might
65 be sometime later. If we do a retry cycle then this should be
67 if (Cnf
->LocalOnly
== true &&
68 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
80 // Acquire::Item::Start - Item has begun to download /*{{{*/
81 // ---------------------------------------------------------------------
82 /* Stash status and the file size. Note that setting Complete means
83 sub-phases of the acquire process such as decompresion are operating */
84 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long Size
)
86 Status
= StatFetching
;
87 if (FileSize
== 0 && Complete
== false)
91 // Acquire::Item::Done - Item downloaded OK /*{{{*/
92 // ---------------------------------------------------------------------
94 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string
,
95 pkgAcquire::MethodConfig
*Cnf
)
97 // We just downloaded something..
98 string FileName
= LookupTag(Message
,"Filename");
99 if (Complete
== false && FileName
== DestFile
)
102 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
109 ErrorText
= string();
110 Owner
->Dequeue(this);
113 // Acquire::Item::Rename - Rename a file /*{{{*/
114 // ---------------------------------------------------------------------
115 /* This helper function is used by alot of item methods as thier final
117 void pkgAcquire::Item::Rename(string From
,string To
)
119 if (rename(From
.c_str(),To
.c_str()) != 0)
122 sprintf(S
,_("rename failed, %s (%s -> %s)."),strerror(errno
),
123 From
.c_str(),To
.c_str());
130 // AcqIndex::AcqIndex - Constructor /*{{{*/
131 // ---------------------------------------------------------------------
132 /* The package file is added to the queue and a second class is
133 instantiated to fetch the revision file */
134 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
135 string URI
,string URIDesc
,string ShortDesc
) :
136 Item(Owner
), RealURI(URI
)
138 Decompression
= false;
141 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
142 DestFile
+= URItoFileName(URI
);
145 Desc
.URI
= URI
+ ".gz";
146 Desc
.Description
= URIDesc
;
148 Desc
.ShortDesc
= ShortDesc
;
153 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
154 // ---------------------------------------------------------------------
155 /* The only header we use is the last-modified header. */
156 string
pkgAcqIndex::Custom600Headers()
158 string Final
= _config
->FindDir("Dir::State::lists");
159 Final
+= URItoFileName(RealURI
);
162 if (stat(Final
.c_str(),&Buf
) != 0)
163 return "\nIndex-File: true";
165 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
168 // AcqIndex::Done - Finished a fetch /*{{{*/
169 // ---------------------------------------------------------------------
170 /* This goes through a number of states.. On the initial fetch the
171 method could possibly return an alternate filename which points
172 to the uncompressed version of the file. If this is so the file
173 is copied into the partial directory. In all other cases the file
174 is decompressed with a gzip uri. */
175 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
,
176 pkgAcquire::MethodConfig
*Cfg
)
178 Item::Done(Message
,Size
,MD5
,Cfg
);
180 if (Decompression
== true)
182 // Done, move it into position
183 string FinalFile
= _config
->FindDir("Dir::State::lists");
184 FinalFile
+= URItoFileName(RealURI
);
185 Rename(DestFile
,FinalFile
);
187 /* We restore the original name to DestFile so that the clean operation
189 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
190 DestFile
+= URItoFileName(RealURI
);
192 // Remove the compressed version.
194 unlink(DestFile
.c_str());
201 // Handle the unzipd case
202 string FileName
= LookupTag(Message
,"Alt-Filename");
203 if (FileName
.empty() == false)
205 // The files timestamp matches
206 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
209 Decompression
= true;
211 DestFile
+= ".decomp";
212 Desc
.URI
= "copy:" + FileName
;
218 FileName
= LookupTag(Message
,"Filename");
219 if (FileName
.empty() == true)
222 ErrorText
= "Method gave a blank filename";
225 // The files timestamp matches
226 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
229 if (FileName
== DestFile
)
234 Decompression
= true;
235 DestFile
+= ".decomp";
236 Desc
.URI
= "gzip:" + FileName
;
242 // AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
243 // ---------------------------------------------------------------------
244 /* The Release file is added to the queue */
245 pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire
*Owner
,
246 string URI
,string URIDesc
,string ShortDesc
) :
247 Item(Owner
), RealURI(URI
)
249 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
250 DestFile
+= URItoFileName(URI
);
254 Desc
.Description
= URIDesc
;
255 Desc
.ShortDesc
= ShortDesc
;
261 // AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
262 // ---------------------------------------------------------------------
263 /* The only header we use is the last-modified header. */
264 string
pkgAcqIndexRel::Custom600Headers()
266 string Final
= _config
->FindDir("Dir::State::lists");
267 Final
+= URItoFileName(RealURI
);
270 if (stat(Final
.c_str(),&Buf
) != 0)
271 return "\nIndex-File: true";
273 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
276 // AcqIndexRel::Done - Item downloaded OK /*{{{*/
277 // ---------------------------------------------------------------------
278 /* The release file was not placed into the download directory then
279 a copy URI is generated and it is copied there otherwise the file
280 in the partial directory is moved into .. and the URI is finished. */
281 void pkgAcqIndexRel::Done(string Message
,unsigned long Size
,string MD5
,
282 pkgAcquire::MethodConfig
*Cfg
)
284 Item::Done(Message
,Size
,MD5
,Cfg
);
286 string FileName
= LookupTag(Message
,"Filename");
287 if (FileName
.empty() == true)
290 ErrorText
= "Method gave a blank filename";
296 // The files timestamp matches
297 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
300 // We have to copy it into place
301 if (FileName
!= DestFile
)
304 Desc
.URI
= "copy:" + FileName
;
309 // Done, move it into position
310 string FinalFile
= _config
->FindDir("Dir::State::lists");
311 FinalFile
+= URItoFileName(RealURI
);
312 Rename(DestFile
,FinalFile
);
315 // AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
316 // ---------------------------------------------------------------------
318 void pkgAcqIndexRel::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
320 if (Cnf
->LocalOnly
== true ||
321 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
330 Item::Failed(Message
,Cnf
);
334 // AcqArchive::AcqArchive - Constructor /*{{{*/
335 // ---------------------------------------------------------------------
336 /* This just sets up the initial fetch environment and queues the first
338 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
339 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
340 string
&StoreFilename
) :
341 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
342 StoreFilename(StoreFilename
), Vf(Version
.FileList())
344 Retries
= _config
->FindI("Acquire::Retries",0);
346 if (Version
.Arch() == 0)
348 _error
->Error(_("I wasn't able to locate a file for the %s package. "
349 "This might mean you need to manually fix this package. (due to missing arch)"),
350 Version
.ParentPkg().Name());
354 /* We need to find a filename to determine the extension. We make the
355 assumption here that all the available sources for this version share
356 the same extension.. */
357 // Skip not source sources, they do not have file fields.
358 for (; Vf
.end() == false; Vf
++)
360 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
365 // Does not really matter here.. we are going to fail out below
366 if (Vf
.end() != true)
368 // If this fails to get a file name we will bomb out below.
369 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
370 if (_error
->PendingError() == true)
373 // Generate the final file name as: package_version_arch.foo
374 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
375 QuoteString(Version
.VerStr(),"_:") + '_' +
376 QuoteString(Version
.Arch(),"_:.") +
377 "." + flExtension(Parse
.FileName());
381 if (QueueNext() == false && _error
->PendingError() == false)
382 _error
->Error(_("I wasn't able to locate file for the %s package. "
383 "This might mean you need to manually fix this package."),
384 Version
.ParentPkg().Name());
387 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
388 // ---------------------------------------------------------------------
389 /* This queues the next available file version for download. It checks if
390 the archive is already available in the cache and stashs the MD5 for
392 bool pkgAcqArchive::QueueNext()
394 for (; Vf
.end() == false; Vf
++)
396 // Ignore not source sources
397 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
400 // Try to cross match against the source list
402 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
405 // Grab the text package record
406 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
407 if (_error
->PendingError() == true)
410 string PkgFile
= Parse
.FileName();
411 MD5
= Parse
.MD5Hash();
412 if (PkgFile
.empty() == true)
413 return _error
->Error(_("The package index files are corrupted. No Filename: "
414 "field for package %s."),
415 Version
.ParentPkg().Name());
417 // See if we already have the file. (Legacy filenames)
418 FileSize
= Version
->Size
;
419 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
421 if (stat(FinalFile
.c_str(),&Buf
) == 0)
423 // Make sure the size matches
424 if ((unsigned)Buf
.st_size
== Version
->Size
)
429 StoreFilename
= DestFile
= FinalFile
;
433 /* Hmm, we have a file and its size does not match, this means it is
434 an old style mismatched arch */
435 unlink(FinalFile
.c_str());
438 // Check it again using the new style output filenames
439 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
440 if (stat(FinalFile
.c_str(),&Buf
) == 0)
442 // Make sure the size matches
443 if ((unsigned)Buf
.st_size
== Version
->Size
)
448 StoreFilename
= DestFile
= FinalFile
;
452 /* Hmm, we have a file and its size does not match, this shouldnt
454 unlink(FinalFile
.c_str());
457 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
459 // Check the destination file
460 if (stat(DestFile
.c_str(),&Buf
) == 0)
462 // Hmm, the partial file is too big, erase it
463 if ((unsigned)Buf
.st_size
> Version
->Size
)
464 unlink(DestFile
.c_str());
466 PartialSize
= Buf
.st_size
;
471 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
472 Desc
.Description
= Index
->ArchiveInfo(Version
);
474 Desc
.ShortDesc
= Version
.ParentPkg().Name();
483 // AcqArchive::Done - Finished fetching /*{{{*/
484 // ---------------------------------------------------------------------
486 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
,
487 pkgAcquire::MethodConfig
*Cfg
)
489 Item::Done(Message
,Size
,Md5Hash
,Cfg
);
492 if (Size
!= Version
->Size
)
495 ErrorText
= _("Size mismatch");
500 if (Md5Hash
.empty() == false && MD5
.empty() == false)
505 ErrorText
= _("MD5Sum mismatch");
506 Rename(DestFile
,DestFile
+ ".FAILED");
511 // Grab the output filename
512 string FileName
= LookupTag(Message
,"Filename");
513 if (FileName
.empty() == true)
516 ErrorText
= "Method gave a blank filename";
522 // Reference filename
523 if (FileName
!= DestFile
)
525 StoreFilename
= DestFile
= FileName
;
530 // Done, move it into position
531 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
532 FinalFile
+= flNotDir(StoreFilename
);
533 Rename(DestFile
,FinalFile
);
535 StoreFilename
= DestFile
= FinalFile
;
539 // AcqArchive::Failed - Failure handler /*{{{*/
540 // ---------------------------------------------------------------------
541 /* Here we try other sources */
542 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
544 ErrorText
= LookupTag(Message
,"Message");
546 /* We don't really want to retry on failed media swaps, this prevents
547 that. An interesting observation is that permanent failures are not
549 if (Cnf
->Removable
== true &&
550 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
552 // Vf = Version.FileList();
553 while (Vf
.end() == false) Vf
++;
554 StoreFilename
= string();
555 Item::Failed(Message
,Cnf
);
559 if (QueueNext() == false)
561 // This is the retry counter
563 Cnf
->LocalOnly
== false &&
564 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
567 Vf
= Version
.FileList();
568 if (QueueNext() == true)
572 StoreFilename
= string();
573 Item::Failed(Message
,Cnf
);
577 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
578 // ---------------------------------------------------------------------
580 void pkgAcqArchive::Finished()
582 if (Status
== pkgAcquire::Item::StatDone
&&
585 StoreFilename
= string();
589 // AcqFile::pkgAcqFile - Constructor /*{{{*/
590 // ---------------------------------------------------------------------
591 /* The file is added to the queue */
592 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string MD5
,
593 unsigned long Size
,string Dsc
,string ShortDesc
) :
594 Item(Owner
), Md5Hash(MD5
)
596 Retries
= _config
->FindI("Acquire::Retries",0);
598 DestFile
= flNotDir(URI
);
602 Desc
.Description
= Dsc
;
605 // Set the short description to the archive component
606 Desc
.ShortDesc
= ShortDesc
;
608 // Get the transfer sizes
611 if (stat(DestFile
.c_str(),&Buf
) == 0)
613 // Hmm, the partial file is too big, erase it
614 if ((unsigned)Buf
.st_size
> Size
)
615 unlink(DestFile
.c_str());
617 PartialSize
= Buf
.st_size
;
623 // AcqFile::Done - Item downloaded OK /*{{{*/
624 // ---------------------------------------------------------------------
626 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
,
627 pkgAcquire::MethodConfig
*Cnf
)
630 if (Md5Hash
.empty() == false && MD5
.empty() == false)
635 ErrorText
= "MD5Sum mismatch";
636 Rename(DestFile
,DestFile
+ ".FAILED");
641 Item::Done(Message
,Size
,MD5
,Cnf
);
643 string FileName
= LookupTag(Message
,"Filename");
644 if (FileName
.empty() == true)
647 ErrorText
= "Method gave a blank filename";
653 // The files timestamp matches
654 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
657 // We have to copy it into place
658 if (FileName
!= DestFile
)
661 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
662 Cnf
->Removable
== true)
664 Desc
.URI
= "copy:" + FileName
;
669 // Erase the file if it is a symlink so we can overwrite it
671 if (lstat(DestFile
.c_str(),&St
) == 0)
673 if (S_ISLNK(St
.st_mode
) != 0)
674 unlink(DestFile
.c_str());
678 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
680 ErrorText
= "Link to " + DestFile
+ " failure ";
687 // AcqFile::Failed - Failure handler /*{{{*/
688 // ---------------------------------------------------------------------
689 /* Here we try other sources */
690 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
692 ErrorText
= LookupTag(Message
,"Message");
694 // This is the retry counter
696 Cnf
->LocalOnly
== false &&
697 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
704 Item::Failed(Message
,Cnf
);