]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-item.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.41 2000/01/17 07:11:49 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/error.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/fileutl.h>
32 // Acquire::Item::Item - Constructor /*{{{*/
33 // ---------------------------------------------------------------------
35 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
36 PartialSize(0), Mode(0), ID(0), Complete(false),
37 Local(false), QueueCounter(0)
43 // Acquire::Item::~Item - Destructor /*{{{*/
44 // ---------------------------------------------------------------------
46 pkgAcquire::Item::~Item()
51 // Acquire::Item::Failed - Item failed to download /*{{{*/
52 // ---------------------------------------------------------------------
53 /* We return to an idle state if there are still other queues that could
55 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
58 ErrorText
= LookupTag(Message
,"Message");
59 if (QueueCounter
<= 1)
61 /* This indicates that the file is not available right now but might
62 be sometime later. If we do a retry cycle then this should be
64 if (Cnf
->LocalOnly
== true &&
65 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
77 // Acquire::Item::Start - Item has begun to download /*{{{*/
78 // ---------------------------------------------------------------------
79 /* Stash status and the file size. Note that setting Complete means
80 sub-phases of the acquire process such as decompresion are operating */
81 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long Size
)
83 Status
= StatFetching
;
84 if (FileSize
== 0 && Complete
== false)
88 // Acquire::Item::Done - Item downloaded OK /*{{{*/
89 // ---------------------------------------------------------------------
91 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string
,
92 pkgAcquire::MethodConfig
*Cnf
)
94 // We just downloaded something..
95 string FileName
= LookupTag(Message
,"Filename");
96 if (Complete
== false && FileName
== DestFile
)
99 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
106 ErrorText
= string();
107 Owner
->Dequeue(this);
110 // Acquire::Item::Rename - Rename a file /*{{{*/
111 // ---------------------------------------------------------------------
112 /* This helper function is used by alot of item methods as thier final
114 void pkgAcquire::Item::Rename(string From
,string To
)
116 if (rename(From
.c_str(),To
.c_str()) != 0)
119 sprintf(S
,"rename failed, %s (%s -> %s).",strerror(errno
),
120 From
.c_str(),To
.c_str());
127 // AcqIndex::AcqIndex - Constructor /*{{{*/
128 // ---------------------------------------------------------------------
129 /* The package file is added to the queue and a second class is
130 instantiated to fetch the revision file */
131 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,const pkgSourceList::Item
*Location
) :
132 Item(Owner
), Location(Location
)
134 Decompression
= false;
137 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
138 DestFile
+= URItoFileName(Location
->PackagesURI());
141 Desc
.URI
= Location
->PackagesURI() + ".gz";
142 Desc
.Description
= Location
->PackagesInfo();
145 // Set the short description to the archive component
146 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
147 Desc
.ShortDesc
= Location
->Dist
;
149 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
153 // Create the Release fetch class
154 new pkgAcqIndexRel(Owner
,Location
);
157 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
158 // ---------------------------------------------------------------------
159 /* The only header we use is the last-modified header. */
160 string
pkgAcqIndex::Custom600Headers()
162 string Final
= _config
->FindDir("Dir::State::lists");
163 Final
+= URItoFileName(Location
->PackagesURI());
166 if (stat(Final
.c_str(),&Buf
) != 0)
167 return "\nIndex-File: true";
169 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
172 // AcqIndex::Done - Finished a fetch /*{{{*/
173 // ---------------------------------------------------------------------
174 /* This goes through a number of states.. On the initial fetch the
175 method could possibly return an alternate filename which points
176 to the uncompressed version of the file. If this is so the file
177 is copied into the partial directory. In all other cases the file
178 is decompressed with a gzip uri. */
179 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
,
180 pkgAcquire::MethodConfig
*Cfg
)
182 Item::Done(Message
,Size
,MD5
,Cfg
);
184 if (Decompression
== true)
186 // Done, move it into position
187 string FinalFile
= _config
->FindDir("Dir::State::lists");
188 FinalFile
+= URItoFileName(Location
->PackagesURI());
189 Rename(DestFile
,FinalFile
);
191 /* We restore the original name to DestFile so that the clean operation
193 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
194 DestFile
+= URItoFileName(Location
->PackagesURI());
196 // Remove the compressed version.
198 unlink(DestFile
.c_str());
205 // Handle the unzipd case
206 string FileName
= LookupTag(Message
,"Alt-Filename");
207 if (FileName
.empty() == false)
209 // The files timestamp matches
210 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
213 Decompression
= true;
215 DestFile
+= ".decomp";
216 Desc
.URI
= "copy:" + FileName
;
222 FileName
= LookupTag(Message
,"Filename");
223 if (FileName
.empty() == true)
226 ErrorText
= "Method gave a blank filename";
229 // The files timestamp matches
230 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
233 if (FileName
== DestFile
)
238 Decompression
= true;
239 DestFile
+= ".decomp";
240 Desc
.URI
= "gzip:" + FileName
,Location
->PackagesInfo();
246 // AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
247 // ---------------------------------------------------------------------
248 /* The Release file is added to the queue */
249 pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire
*Owner
,
250 const pkgSourceList::Item
*Location
) :
251 Item(Owner
), Location(Location
)
253 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
254 DestFile
+= URItoFileName(Location
->ReleaseURI());
257 Desc
.URI
= Location
->ReleaseURI();
258 Desc
.Description
= Location
->ReleaseInfo();
261 // Set the short description to the archive component
262 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
263 Desc
.ShortDesc
= Location
->Dist
;
265 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
270 // AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
271 // ---------------------------------------------------------------------
272 /* The only header we use is the last-modified header. */
273 string
pkgAcqIndexRel::Custom600Headers()
275 string Final
= _config
->FindDir("Dir::State::lists");
276 Final
+= URItoFileName(Location
->ReleaseURI());
279 if (stat(Final
.c_str(),&Buf
) != 0)
280 return "\nIndex-File: true";
282 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
285 // AcqIndexRel::Done - Item downloaded OK /*{{{*/
286 // ---------------------------------------------------------------------
287 /* The release file was not placed into the download directory then
288 a copy URI is generated and it is copied there otherwise the file
289 in the partial directory is moved into .. and the URI is finished. */
290 void pkgAcqIndexRel::Done(string Message
,unsigned long Size
,string MD5
,
291 pkgAcquire::MethodConfig
*Cfg
)
293 Item::Done(Message
,Size
,MD5
,Cfg
);
295 string FileName
= LookupTag(Message
,"Filename");
296 if (FileName
.empty() == true)
299 ErrorText
= "Method gave a blank filename";
305 // The files timestamp matches
306 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
309 // We have to copy it into place
310 if (FileName
!= DestFile
)
313 Desc
.URI
= "copy:" + FileName
;
318 // Done, move it into position
319 string FinalFile
= _config
->FindDir("Dir::State::lists");
320 FinalFile
+= URItoFileName(Location
->ReleaseURI());
321 Rename(DestFile
,FinalFile
);
324 // AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
325 // ---------------------------------------------------------------------
327 void pkgAcqIndexRel::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
329 if (Cnf
->LocalOnly
== true ||
330 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
339 Item::Failed(Message
,Cnf
);
343 // AcqArchive::AcqArchive - Constructor /*{{{*/
344 // ---------------------------------------------------------------------
345 /* This just sets up the initial fetch environment and queues the first
347 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
348 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
349 string
&StoreFilename
) :
350 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
351 StoreFilename(StoreFilename
), Vf(Version
.FileList())
353 Retries
= _config
->FindI("Acquire::Retries",0);
355 if (Version
.Arch() == 0)
357 _error
->Error("I wasn't able to locate file for the %s package. "
358 "This might mean you need to manually fix this package. (due to missing arch)",
359 Version
.ParentPkg().Name());
363 // Generate the final file name as: package_version_arch.deb
364 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
365 QuoteString(Version
.VerStr(),"_:") + '_' +
366 QuoteString(Version
.Arch(),"_:.") + ".deb";
369 if (QueueNext() == false && _error
->PendingError() == false)
370 _error
->Error("I wasn't able to locate file for the %s package. "
371 "This might mean you need to manually fix this package.",
372 Version
.ParentPkg().Name());
375 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
376 // ---------------------------------------------------------------------
377 /* This queues the next available file version for download. It checks if
378 the archive is already available in the cache and stashs the MD5 for
380 bool pkgAcqArchive::QueueNext()
382 for (; Vf
.end() == false; Vf
++)
384 // Ignore not source sources
385 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
388 // Try to cross match against the source list
389 string PkgFile
= flNotDir(Vf
.File().FileName());
390 pkgSourceList::const_iterator Location
;
391 for (Location
= Sources
->begin(); Location
!= Sources
->end(); Location
++)
392 if (PkgFile
== URItoFileName(Location
->PackagesURI()))
395 if (Location
== Sources
->end())
398 // Grab the text package record
399 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
400 if (_error
->PendingError() == true)
403 PkgFile
= Parse
.FileName();
404 MD5
= Parse
.MD5Hash();
405 if (PkgFile
.empty() == true)
406 return _error
->Error("The package index files are corrupted. No Filename: "
407 "field for package %s."
408 ,Version
.ParentPkg().Name());
410 // See if we already have the file. (Legacy filenames)
411 FileSize
= Version
->Size
;
412 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
414 if (stat(FinalFile
.c_str(),&Buf
) == 0)
416 // Make sure the size matches
417 if ((unsigned)Buf
.st_size
== Version
->Size
)
422 StoreFilename
= DestFile
= FinalFile
;
426 /* Hmm, we have a file and its size does not match, this means it is
427 an old style mismatched arch */
428 unlink(FinalFile
.c_str());
431 // Check it again using the new style output filenames
432 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
433 if (stat(FinalFile
.c_str(),&Buf
) == 0)
435 // Make sure the size matches
436 if ((unsigned)Buf
.st_size
== Version
->Size
)
441 StoreFilename
= DestFile
= FinalFile
;
445 /* Hmm, we have a file and its size does not match, this shouldnt
447 unlink(FinalFile
.c_str());
450 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
452 // Check the destination file
453 if (stat(DestFile
.c_str(),&Buf
) == 0)
455 // Hmm, the partial file is too big, erase it
456 if ((unsigned)Buf
.st_size
> Version
->Size
)
457 unlink(DestFile
.c_str());
459 PartialSize
= Buf
.st_size
;
463 Desc
.URI
= Location
->ArchiveURI(PkgFile
);
464 Desc
.Description
= Location
->ArchiveInfo(Version
);
466 Desc
.ShortDesc
= Version
.ParentPkg().Name();
475 // AcqArchive::Done - Finished fetching /*{{{*/
476 // ---------------------------------------------------------------------
478 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
,
479 pkgAcquire::MethodConfig
*Cfg
)
481 Item::Done(Message
,Size
,Md5Hash
,Cfg
);
484 if (Size
!= Version
->Size
)
487 ErrorText
= "Size mismatch";
492 if (Md5Hash
.empty() == false && MD5
.empty() == false)
497 ErrorText
= "MD5Sum mismatch";
498 Rename(DestFile
,DestFile
+ ".FAILED");
503 // Grab the output filename
504 string FileName
= LookupTag(Message
,"Filename");
505 if (FileName
.empty() == true)
508 ErrorText
= "Method gave a blank filename";
514 // Reference filename
515 if (FileName
!= DestFile
)
517 StoreFilename
= DestFile
= FileName
;
522 // Done, move it into position
523 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
524 FinalFile
+= flNotDir(StoreFilename
);
525 Rename(DestFile
,FinalFile
);
527 StoreFilename
= DestFile
= FinalFile
;
531 // AcqArchive::Failed - Failure handler /*{{{*/
532 // ---------------------------------------------------------------------
533 /* Here we try other sources */
534 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
536 ErrorText
= LookupTag(Message
,"Message");
537 if (QueueNext() == false)
539 // This is the retry counter
541 Cnf
->LocalOnly
== false &&
542 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
545 Vf
= Version
.FileList();
546 if (QueueNext() == true)
550 StoreFilename
= string();
551 Item::Failed(Message
,Cnf
);
555 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
556 // ---------------------------------------------------------------------
558 void pkgAcqArchive::Finished()
560 if (Status
== pkgAcquire::Item::StatDone
&&
563 StoreFilename
= string();
567 // AcqFile::pkgAcqFile - Constructor /*{{{*/
568 // ---------------------------------------------------------------------
569 /* The file is added to the queue */
570 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string MD5
,
571 unsigned long Size
,string Dsc
,string ShortDesc
) :
572 Item(Owner
), Md5Hash(MD5
)
574 Retries
= _config
->FindI("Acquire::Retries",0);
576 DestFile
= flNotDir(URI
);
580 Desc
.Description
= Dsc
;
583 // Set the short description to the archive component
584 Desc
.ShortDesc
= ShortDesc
;
586 // Get the transfer sizes
589 if (stat(DestFile
.c_str(),&Buf
) == 0)
591 // Hmm, the partial file is too big, erase it
592 if ((unsigned)Buf
.st_size
> Size
)
593 unlink(DestFile
.c_str());
595 PartialSize
= Buf
.st_size
;
601 // AcqFile::Done - Item downloaded OK /*{{{*/
602 // ---------------------------------------------------------------------
604 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
,
605 pkgAcquire::MethodConfig
*Cnf
)
608 if (Md5Hash
.empty() == false && MD5
.empty() == false)
613 ErrorText
= "MD5Sum mismatch";
614 Rename(DestFile
,DestFile
+ ".FAILED");
619 Item::Done(Message
,Size
,MD5
,Cnf
);
621 string FileName
= LookupTag(Message
,"Filename");
622 if (FileName
.empty() == true)
625 ErrorText
= "Method gave a blank filename";
631 // The files timestamp matches
632 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
635 // We have to copy it into place
636 if (FileName
!= DestFile
)
639 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
640 Cnf
->Removable
== true)
642 Desc
.URI
= "copy:" + FileName
;
647 // Erase the file if it is a symlink so we can overwrite it
649 if (lstat(DestFile
.c_str(),&St
) == 0)
651 if (S_ISLNK(St
.st_mode
) != 0)
652 unlink(DestFile
.c_str());
656 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
658 ErrorText
= "Link to " + DestFile
+ " failure ";
665 // AcqFile::Failed - Failure handler /*{{{*/
666 // ---------------------------------------------------------------------
667 /* Here we try other sources */
668 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
670 ErrorText
= LookupTag(Message
,"Message");
672 // This is the retry counter
674 Cnf
->LocalOnly
== false &&
675 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
682 Item::Failed(Message
,Cnf
);