]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-item.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: acquire-item.cc,v 1.44 2001/05/07 05:49:43 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> 
  37 // Acquire::Item::Item - Constructor                                    /*{{{*/ 
  38 // --------------------------------------------------------------------- 
  40 pkgAcquire::Item::Item(pkgAcquire 
*Owner
) : Owner(Owner
), FileSize(0), 
  41                        PartialSize(0), Mode(0), ID(0), Complete(false),  
  42                        Local(false), QueueCounter(0) 
  48 // Acquire::Item::~Item - Destructor                                    /*{{{*/ 
  49 // --------------------------------------------------------------------- 
  51 pkgAcquire::Item::~Item() 
  56 // Acquire::Item::Failed - Item failed to download                      /*{{{*/ 
  57 // --------------------------------------------------------------------- 
  58 /* We return to an idle state if there are still other queues that could 
  60 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig 
*Cnf
) 
  63    ErrorText 
= LookupTag(Message
,"Message"); 
  64    if (QueueCounter 
<= 1) 
  66       /* This indicates that the file is not available right now but might 
  67          be sometime later. If we do a retry cycle then this should be 
  69       if (Cnf
->LocalOnly 
== true && 
  70           StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true) 
  82 // Acquire::Item::Start - Item has begun to download                    /*{{{*/ 
  83 // --------------------------------------------------------------------- 
  84 /* Stash status and the file size. Note that setting Complete means  
  85    sub-phases of the acquire process such as decompresion are operating */ 
  86 void pkgAcquire::Item::Start(string 
/*Message*/,unsigned long Size
) 
  88    Status 
= StatFetching
; 
  89    if (FileSize 
== 0 && Complete 
== false) 
  93 // Acquire::Item::Done - Item downloaded OK                             /*{{{*/ 
  94 // --------------------------------------------------------------------- 
  96 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string
, 
  97                             pkgAcquire::MethodConfig 
*Cnf
) 
  99    // We just downloaded something.. 
 100    string FileName 
= LookupTag(Message
,"Filename"); 
 101    if (Complete 
== false && FileName 
== DestFile
) 
 104          Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str())); 
 111    ErrorText 
= string(); 
 112    Owner
->Dequeue(this); 
 115 // Acquire::Item::Rename - Rename a file                                /*{{{*/ 
 116 // --------------------------------------------------------------------- 
 117 /* This helper function is used by alot of item methods as thier final 
 119 void pkgAcquire::Item::Rename(string From
,string To
) 
 121    if (rename(From
.c_str(),To
.c_str()) != 0) 
 124       sprintf(S
,_("rename failed, %s (%s -> %s)."),strerror(errno
), 
 125               From
.c_str(),To
.c_str()); 
 132 // AcqIndex::AcqIndex - Constructor                                     /*{{{*/ 
 133 // --------------------------------------------------------------------- 
 134 /* The package file is added to the queue and a second class is  
 135    instantiated to fetch the revision file */    
 136 pkgAcqIndex::pkgAcqIndex(pkgAcquire 
*Owner
, 
 137                          string URI
,string URIDesc
,string ShortDesc
) : 
 138                       Item(Owner
), RealURI(URI
) 
 140    Decompression 
= false; 
 143    DestFile 
= _config
->FindDir("Dir::State::lists") + "partial/"; 
 144    DestFile 
+= URItoFileName(URI
); 
 147    Desc
.URI 
= URI 
+ ".gz"; 
 148    Desc
.Description 
= URIDesc
; 
 150    Desc
.ShortDesc 
= ShortDesc
; 
 155 // AcqIndex::Custom600Headers - Insert custom request headers           /*{{{*/ 
 156 // --------------------------------------------------------------------- 
 157 /* The only header we use is the last-modified header. */ 
 158 string 
pkgAcqIndex::Custom600Headers() 
 160    string Final 
= _config
->FindDir("Dir::State::lists"); 
 161    Final 
+= URItoFileName(RealURI
); 
 164    if (stat(Final
.c_str(),&Buf
) != 0) 
 165       return "\nIndex-File: true"; 
 167    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
); 
 170 // AcqIndex::Done - Finished a fetch                                    /*{{{*/ 
 171 // --------------------------------------------------------------------- 
 172 /* This goes through a number of states.. On the initial fetch the 
 173    method could possibly return an alternate filename which points 
 174    to the uncompressed version of the file. If this is so the file 
 175    is copied into the partial directory. In all other cases the file 
 176    is decompressed with a gzip uri. */ 
 177 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
, 
 178                        pkgAcquire::MethodConfig 
*Cfg
) 
 180    Item::Done(Message
,Size
,MD5
,Cfg
); 
 182    if (Decompression 
== true) 
 184       // Done, move it into position 
 185       string FinalFile 
= _config
->FindDir("Dir::State::lists"); 
 186       FinalFile 
+= URItoFileName(RealURI
); 
 187       Rename(DestFile
,FinalFile
); 
 189       /* We restore the original name to DestFile so that the clean operation 
 191       DestFile 
= _config
->FindDir("Dir::State::lists") + "partial/"; 
 192       DestFile 
+= URItoFileName(RealURI
); 
 194       // Remove the compressed version. 
 196          unlink(DestFile
.c_str()); 
 203    // Handle the unzipd case 
 204    string FileName 
= LookupTag(Message
,"Alt-Filename"); 
 205    if (FileName
.empty() == false) 
 207       // The files timestamp matches 
 208       if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true) 
 211       Decompression 
= true; 
 213       DestFile 
+= ".decomp"; 
 214       Desc
.URI 
= "copy:" + FileName
; 
 220    FileName 
= LookupTag(Message
,"Filename"); 
 221    if (FileName
.empty() == true) 
 224       ErrorText 
= "Method gave a blank filename"; 
 227    // The files timestamp matches 
 228    if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) 
 231    if (FileName 
== DestFile
) 
 236    Decompression 
= true; 
 237    DestFile 
+= ".decomp"; 
 238    Desc
.URI 
= "gzip:" + FileName
; 
 244 // AcqIndexRel::pkgAcqIndexRel - Constructor                            /*{{{*/ 
 245 // --------------------------------------------------------------------- 
 246 /* The Release file is added to the queue */ 
 247 pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire 
*Owner
, 
 248                             string URI
,string URIDesc
,string ShortDesc
) : 
 249                       Item(Owner
), RealURI(URI
) 
 251    DestFile 
= _config
->FindDir("Dir::State::lists") + "partial/"; 
 252    DestFile 
+= URItoFileName(URI
); 
 256    Desc
.Description 
= URIDesc
; 
 257    Desc
.ShortDesc 
= ShortDesc
; 
 263 // AcqIndexRel::Custom600Headers - Insert custom request headers        /*{{{*/ 
 264 // --------------------------------------------------------------------- 
 265 /* The only header we use is the last-modified header. */ 
 266 string 
pkgAcqIndexRel::Custom600Headers() 
 268    string Final 
= _config
->FindDir("Dir::State::lists"); 
 269    Final 
+= URItoFileName(RealURI
); 
 272    if (stat(Final
.c_str(),&Buf
) != 0) 
 273       return "\nIndex-File: true"; 
 275    return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
); 
 278 // AcqIndexRel::Done - Item downloaded OK                               /*{{{*/ 
 279 // --------------------------------------------------------------------- 
 280 /* The release file was not placed into the download directory then 
 281    a copy URI is generated and it is copied there otherwise the file 
 282    in the partial directory is moved into .. and the URI is finished. */ 
 283 void pkgAcqIndexRel::Done(string Message
,unsigned long Size
,string MD5
, 
 284                           pkgAcquire::MethodConfig 
*Cfg
) 
 286    Item::Done(Message
,Size
,MD5
,Cfg
); 
 288    string FileName 
= LookupTag(Message
,"Filename"); 
 289    if (FileName
.empty() == true) 
 292       ErrorText 
= "Method gave a blank filename"; 
 298    // The files timestamp matches 
 299    if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) 
 302    // We have to copy it into place 
 303    if (FileName 
!= DestFile
) 
 306       Desc
.URI 
= "copy:" + FileName
; 
 311    // Done, move it into position 
 312    string FinalFile 
= _config
->FindDir("Dir::State::lists"); 
 313    FinalFile 
+= URItoFileName(RealURI
); 
 314    Rename(DestFile
,FinalFile
); 
 317 // AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/ 
 318 // --------------------------------------------------------------------- 
 320 void pkgAcqIndexRel::Failed(string Message
,pkgAcquire::MethodConfig 
*Cnf
) 
 322    if (Cnf
->LocalOnly 
== true ||  
 323        StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false) 
 332    Item::Failed(Message
,Cnf
); 
 336 // AcqArchive::AcqArchive - Constructor                                 /*{{{*/ 
 337 // --------------------------------------------------------------------- 
 338 /* This just sets up the initial fetch environment and queues the first 
 340 pkgAcqArchive::pkgAcqArchive(pkgAcquire 
*Owner
,pkgSourceList 
*Sources
, 
 341                              pkgRecords 
*Recs
,pkgCache::VerIterator 
const &Version
, 
 342                              string 
&StoreFilename
) : 
 343                Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),  
 344                StoreFilename(StoreFilename
), Vf(Version
.FileList()) 
 346    Retries 
= _config
->FindI("Acquire::Retries",0); 
 348    if (Version
.Arch() == 0) 
 350       _error
->Error(_("I wasn't able to locate a file for the %s package. " 
 351                     "This might mean you need to manually fix this package. (due to missing arch)"), 
 352                     Version
.ParentPkg().Name()); 
 356    /* We need to find a filename to determine the extension. We make the 
 357       assumption here that all the available sources for this version share 
 358       the same extension.. */ 
 359    // Skip not source sources, they do not have file fields. 
 360    for (; Vf
.end() == false; Vf
++) 
 362       if ((Vf
.File()->Flags 
& pkgCache::Flag::NotSource
) != 0) 
 367    // Does not really matter here.. we are going to fail out below 
 368    if (Vf
.end() != true) 
 370       // If this fails to get a file name we will bomb out below. 
 371       pkgRecords::Parser 
&Parse 
= Recs
->Lookup(Vf
); 
 372       if (_error
->PendingError() == true) 
 375       // Generate the final file name as: package_version_arch.foo 
 376       StoreFilename 
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' + 
 377                       QuoteString(Version
.VerStr(),"_:") + '_' + 
 378                       QuoteString(Version
.Arch(),"_:.") +  
 379                       "." + flExtension(Parse
.FileName()); 
 383    if (QueueNext() == false && _error
->PendingError() == false) 
 384       _error
->Error(_("I wasn't able to locate file for the %s package. " 
 385                     "This might mean you need to manually fix this package."), 
 386                     Version
.ParentPkg().Name()); 
 389 // AcqArchive::QueueNext - Queue the next file source                   /*{{{*/ 
 390 // --------------------------------------------------------------------- 
 391 /* This queues the next available file version for download. It checks if 
 392    the archive is already available in the cache and stashs the MD5 for 
 394 bool pkgAcqArchive::QueueNext() 
 396    for (; Vf
.end() == false; Vf
++) 
 398       // Ignore not source sources 
 399       if ((Vf
.File()->Flags 
& pkgCache::Flag::NotSource
) != 0) 
 402       // Try to cross match against the source list 
 404       if (Sources
->FindIndex(Vf
.File(),Index
) == false) 
 407       // Grab the text package record 
 408       pkgRecords::Parser 
&Parse 
= Recs
->Lookup(Vf
); 
 409       if (_error
->PendingError() == true) 
 412       string PkgFile 
= Parse
.FileName(); 
 413       MD5 
= Parse
.MD5Hash(); 
 414       if (PkgFile
.empty() == true) 
 415          return _error
->Error(_("The package index files are corrupted. No Filename: " 
 416                               "field for package %s."), 
 417                               Version
.ParentPkg().Name()); 
 419       // See if we already have the file. (Legacy filenames) 
 420       FileSize 
= Version
->Size
; 
 421       string FinalFile 
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
); 
 423       if (stat(FinalFile
.c_str(),&Buf
) == 0) 
 425          // Make sure the size matches 
 426          if ((unsigned)Buf
.st_size 
== Version
->Size
) 
 431             StoreFilename 
= DestFile 
= FinalFile
; 
 435          /* Hmm, we have a file and its size does not match, this means it is 
 436             an old style mismatched arch */ 
 437          unlink(FinalFile
.c_str()); 
 440       // Check it again using the new style output filenames 
 441       FinalFile 
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
); 
 442       if (stat(FinalFile
.c_str(),&Buf
) == 0) 
 444          // Make sure the size matches 
 445          if ((unsigned)Buf
.st_size 
== Version
->Size
) 
 450             StoreFilename 
= DestFile 
= FinalFile
; 
 454          /* Hmm, we have a file and its size does not match, this shouldnt 
 456          unlink(FinalFile
.c_str()); 
 459       DestFile 
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
); 
 461       // Check the destination file 
 462       if (stat(DestFile
.c_str(),&Buf
) == 0) 
 464          // Hmm, the partial file is too big, erase it 
 465          if ((unsigned)Buf
.st_size 
> Version
->Size
) 
 466             unlink(DestFile
.c_str()); 
 468             PartialSize 
= Buf
.st_size
; 
 473       Desc
.URI 
= Index
->ArchiveURI(PkgFile
); 
 474       Desc
.Description 
= Index
->ArchiveInfo(Version
); 
 476       Desc
.ShortDesc 
= Version
.ParentPkg().Name(); 
 485 // AcqArchive::Done - Finished fetching                                 /*{{{*/ 
 486 // --------------------------------------------------------------------- 
 488 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
, 
 489                          pkgAcquire::MethodConfig 
*Cfg
) 
 491    Item::Done(Message
,Size
,Md5Hash
,Cfg
); 
 494    if (Size 
!= Version
->Size
) 
 497       ErrorText 
= _("Size mismatch"); 
 502    if (Md5Hash
.empty() == false && MD5
.empty() == false) 
 507          ErrorText 
= _("MD5Sum mismatch"); 
 508          Rename(DestFile
,DestFile 
+ ".FAILED"); 
 513    // Grab the output filename 
 514    string FileName 
= LookupTag(Message
,"Filename"); 
 515    if (FileName
.empty() == true) 
 518       ErrorText 
= "Method gave a blank filename"; 
 524    // Reference filename 
 525    if (FileName 
!= DestFile
) 
 527       StoreFilename 
= DestFile 
= FileName
; 
 532    // Done, move it into position 
 533    string FinalFile 
= _config
->FindDir("Dir::Cache::Archives"); 
 534    FinalFile 
+= flNotDir(StoreFilename
); 
 535    Rename(DestFile
,FinalFile
); 
 537    StoreFilename 
= DestFile 
= FinalFile
; 
 541 // AcqArchive::Failed - Failure handler                                 /*{{{*/ 
 542 // --------------------------------------------------------------------- 
 543 /* Here we try other sources */ 
 544 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig 
*Cnf
) 
 546    ErrorText 
= LookupTag(Message
,"Message"); 
 548    /* We don't really want to retry on failed media swaps, this prevents  
 549       that. An interesting observation is that permanent failures are not 
 551    if (Cnf
->Removable 
== true &&  
 552        StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true) 
 554       // Vf = Version.FileList(); 
 555       while (Vf
.end() == false) Vf
++; 
 556       StoreFilename 
= string(); 
 557       Item::Failed(Message
,Cnf
); 
 561    if (QueueNext() == false) 
 563       // This is the retry counter 
 565           Cnf
->LocalOnly 
== false && 
 566           StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true) 
 569          Vf 
= Version
.FileList(); 
 570          if (QueueNext() == true) 
 574       StoreFilename 
= string(); 
 575       Item::Failed(Message
,Cnf
); 
 579 // AcqArchive::Finished - Fetching has finished, tidy up                /*{{{*/ 
 580 // --------------------------------------------------------------------- 
 582 void pkgAcqArchive::Finished() 
 584    if (Status 
== pkgAcquire::Item::StatDone 
&& 
 587    StoreFilename 
= string(); 
 591 // AcqFile::pkgAcqFile - Constructor                                    /*{{{*/ 
 592 // --------------------------------------------------------------------- 
 593 /* The file is added to the queue */ 
 594 pkgAcqFile::pkgAcqFile(pkgAcquire 
*Owner
,string URI
,string MD5
, 
 595                        unsigned long Size
,string Dsc
,string ShortDesc
) : 
 596                        Item(Owner
), Md5Hash(MD5
) 
 598    Retries 
= _config
->FindI("Acquire::Retries",0); 
 600    DestFile 
= flNotDir(URI
); 
 604    Desc
.Description 
= Dsc
; 
 607    // Set the short description to the archive component 
 608    Desc
.ShortDesc 
= ShortDesc
; 
 610    // Get the transfer sizes 
 613    if (stat(DestFile
.c_str(),&Buf
) == 0) 
 615       // Hmm, the partial file is too big, erase it 
 616       if ((unsigned)Buf
.st_size 
> Size
) 
 617          unlink(DestFile
.c_str()); 
 619          PartialSize 
= Buf
.st_size
; 
 625 // AcqFile::Done - Item downloaded OK                                   /*{{{*/ 
 626 // --------------------------------------------------------------------- 
 628 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
, 
 629                       pkgAcquire::MethodConfig 
*Cnf
) 
 632    if (Md5Hash
.empty() == false && MD5
.empty() == false) 
 637          ErrorText 
= "MD5Sum mismatch"; 
 638          Rename(DestFile
,DestFile 
+ ".FAILED"); 
 643    Item::Done(Message
,Size
,MD5
,Cnf
); 
 645    string FileName 
= LookupTag(Message
,"Filename"); 
 646    if (FileName
.empty() == true) 
 649       ErrorText 
= "Method gave a blank filename"; 
 655    // The files timestamp matches 
 656    if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) 
 659    // We have to copy it into place 
 660    if (FileName 
!= DestFile
) 
 663       if (_config
->FindB("Acquire::Source-Symlinks",true) == false || 
 664           Cnf
->Removable 
== true) 
 666          Desc
.URI 
= "copy:" + FileName
; 
 671       // Erase the file if it is a symlink so we can overwrite it 
 673       if (lstat(DestFile
.c_str(),&St
) == 0) 
 675          if (S_ISLNK(St
.st_mode
) != 0) 
 676             unlink(DestFile
.c_str()); 
 680       if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0) 
 682          ErrorText 
= "Link to " + DestFile 
+ " failure "; 
 689 // AcqFile::Failed - Failure handler                                    /*{{{*/ 
 690 // --------------------------------------------------------------------- 
 691 /* Here we try other sources */ 
 692 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig 
*Cnf
) 
 694    ErrorText 
= LookupTag(Message
,"Message"); 
 696    // This is the retry counter 
 698        Cnf
->LocalOnly 
== false && 
 699        StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true) 
 706    Item::Failed(Message
,Cnf
);