]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-item.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.37 1999/09/01 07:01:14 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
)
93 // We just downloaded something..
94 string FileName
= LookupTag(Message
,"Filename");
95 if (Complete
== false && FileName
== DestFile
)
98 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
105 ErrorText
= string();
106 Owner
->Dequeue(this);
109 // Acquire::Item::Rename - Rename a file /*{{{*/
110 // ---------------------------------------------------------------------
111 /* This helper function is used by alot of item methods as thier final
113 void pkgAcquire::Item::Rename(string From
,string To
)
115 if (rename(From
.c_str(),To
.c_str()) != 0)
118 sprintf(S
,"rename failed, %s (%s -> %s).",strerror(errno
),
119 From
.c_str(),To
.c_str());
126 // AcqIndex::AcqIndex - Constructor /*{{{*/
127 // ---------------------------------------------------------------------
128 /* The package file is added to the queue and a second class is
129 instantiated to fetch the revision file */
130 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,const pkgSourceList::Item
*Location
) :
131 Item(Owner
), Location(Location
)
133 Decompression
= false;
136 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
137 DestFile
+= URItoFileName(Location
->PackagesURI());
140 Desc
.URI
= Location
->PackagesURI() + ".gz";
141 Desc
.Description
= Location
->PackagesInfo();
144 // Set the short description to the archive component
145 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
146 Desc
.ShortDesc
= Location
->Dist
;
148 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
152 // Create the Release fetch class
153 new pkgAcqIndexRel(Owner
,Location
);
156 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
157 // ---------------------------------------------------------------------
158 /* The only header we use is the last-modified header. */
159 string
pkgAcqIndex::Custom600Headers()
161 string Final
= _config
->FindDir("Dir::State::lists");
162 Final
+= URItoFileName(Location
->PackagesURI());
165 if (stat(Final
.c_str(),&Buf
) != 0)
166 return "\nIndex-File: true";
168 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
171 // AcqIndex::Done - Finished a fetch /*{{{*/
172 // ---------------------------------------------------------------------
173 /* This goes through a number of states.. On the initial fetch the
174 method could possibly return an alternate filename which points
175 to the uncompressed version of the file. If this is so the file
176 is copied into the partial directory. In all other cases the file
177 is decompressed with a gzip uri. */
178 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
)
180 Item::Done(Message
,Size
,MD5
);
182 if (Decompression
== true)
184 // Done, move it into position
185 string FinalFile
= _config
->FindDir("Dir::State::lists");
186 FinalFile
+= URItoFileName(Location
->PackagesURI());
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(Location
->PackagesURI());
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
,Location
->PackagesInfo();
244 // AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
245 // ---------------------------------------------------------------------
246 /* The Release file is added to the queue */
247 pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire
*Owner
,
248 const pkgSourceList::Item
*Location
) :
249 Item(Owner
), Location(Location
)
251 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
252 DestFile
+= URItoFileName(Location
->ReleaseURI());
255 Desc
.URI
= Location
->ReleaseURI();
256 Desc
.Description
= Location
->ReleaseInfo();
259 // Set the short description to the archive component
260 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
261 Desc
.ShortDesc
= Location
->Dist
;
263 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
268 // AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
269 // ---------------------------------------------------------------------
270 /* The only header we use is the last-modified header. */
271 string
pkgAcqIndexRel::Custom600Headers()
273 string Final
= _config
->FindDir("Dir::State::lists");
274 Final
+= URItoFileName(Location
->ReleaseURI());
277 if (stat(Final
.c_str(),&Buf
) != 0)
278 return "\nIndex-File: true";
280 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
283 // AcqIndexRel::Done - Item downloaded OK /*{{{*/
284 // ---------------------------------------------------------------------
285 /* The release file was not placed into the download directory then
286 a copy URI is generated and it is copied there otherwise the file
287 in the partial directory is moved into .. and the URI is finished. */
288 void pkgAcqIndexRel::Done(string Message
,unsigned long Size
,string MD5
)
290 Item::Done(Message
,Size
,MD5
);
292 string FileName
= LookupTag(Message
,"Filename");
293 if (FileName
.empty() == true)
296 ErrorText
= "Method gave a blank filename";
302 // The files timestamp matches
303 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
306 // We have to copy it into place
307 if (FileName
!= DestFile
)
310 Desc
.URI
= "copy:" + FileName
;
315 // Done, move it into position
316 string FinalFile
= _config
->FindDir("Dir::State::lists");
317 FinalFile
+= URItoFileName(Location
->ReleaseURI());
318 Rename(DestFile
,FinalFile
);
321 // AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
322 // ---------------------------------------------------------------------
324 void pkgAcqIndexRel::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
326 if (Cnf
->LocalOnly
== true ||
327 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
336 Item::Failed(Message
,Cnf
);
340 // AcqArchive::AcqArchive - Constructor /*{{{*/
341 // ---------------------------------------------------------------------
342 /* This just sets up the initial fetch environment and queues the first
344 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
345 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
346 string
&StoreFilename
) :
347 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
348 StoreFilename(StoreFilename
), Vf(Version
.FileList())
350 Retries
= _config
->FindI("Acquire::Retries",0);
352 if (Version
.Arch() == 0)
354 _error
->Error("I wasn't able to locate file for the %s package. "
355 "This might mean you need to manually fix this package. (due to missing arch)",
356 Version
.ParentPkg().Name());
360 // Generate the final file name as: package_version_arch.deb
361 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
362 QuoteString(Version
.VerStr(),"_:") + '_' +
363 QuoteString(Version
.Arch(),"_:.") + ".deb";
366 if (QueueNext() == false && _error
->PendingError() == false)
367 _error
->Error("I wasn't able to locate file for the %s package. "
368 "This might mean you need to manually fix this package.",
369 Version
.ParentPkg().Name());
372 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
373 // ---------------------------------------------------------------------
374 /* This queues the next available file version for download. It checks if
375 the archive is already available in the cache and stashs the MD5 for
377 bool pkgAcqArchive::QueueNext()
379 for (; Vf
.end() == false; Vf
++)
381 // Ignore not source sources
382 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
385 // Try to cross match against the source list
386 string PkgFile
= flNotDir(Vf
.File().FileName());
387 pkgSourceList::const_iterator Location
;
388 for (Location
= Sources
->begin(); Location
!= Sources
->end(); Location
++)
389 if (PkgFile
== URItoFileName(Location
->PackagesURI()))
392 if (Location
== Sources
->end())
395 // Grab the text package record
396 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
397 if (_error
->PendingError() == true)
400 PkgFile
= Parse
.FileName();
401 MD5
= Parse
.MD5Hash();
402 if (PkgFile
.empty() == true)
403 return _error
->Error("The package index files are corrupted. No Filename: "
404 "field for package %s."
405 ,Version
.ParentPkg().Name());
407 // See if we already have the file. (Legacy filenames)
408 FileSize
= Version
->Size
;
409 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
411 if (stat(FinalFile
.c_str(),&Buf
) == 0)
413 // Make sure the size matches
414 if ((unsigned)Buf
.st_size
== Version
->Size
)
419 StoreFilename
= DestFile
= FinalFile
;
423 /* Hmm, we have a file and its size does not match, this means it is
424 an old style mismatched arch */
425 unlink(FinalFile
.c_str());
428 // Check it again using the new style output filenames
429 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
430 if (stat(FinalFile
.c_str(),&Buf
) == 0)
432 // Make sure the size matches
433 if ((unsigned)Buf
.st_size
== Version
->Size
)
438 StoreFilename
= DestFile
= FinalFile
;
442 /* Hmm, we have a file and its size does not match, this shouldnt
444 unlink(FinalFile
.c_str());
447 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
449 // Check the destination file
450 if (stat(DestFile
.c_str(),&Buf
) == 0)
452 // Hmm, the partial file is too big, erase it
453 if ((unsigned)Buf
.st_size
> Version
->Size
)
454 unlink(DestFile
.c_str());
456 PartialSize
= Buf
.st_size
;
460 Desc
.URI
= Location
->ArchiveURI(PkgFile
);
461 Desc
.Description
= Location
->ArchiveInfo(Version
);
463 Desc
.ShortDesc
= Version
.ParentPkg().Name();
472 // AcqArchive::Done - Finished fetching /*{{{*/
473 // ---------------------------------------------------------------------
475 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
)
477 Item::Done(Message
,Size
,Md5Hash
);
480 if (Size
!= Version
->Size
)
483 ErrorText
= "Size mismatch";
488 if (Md5Hash
.empty() == false && MD5
.empty() == false)
493 ErrorText
= "MD5Sum mismatch";
494 Rename(DestFile
,DestFile
+ ".FAILED");
499 // Grab the output filename
500 string FileName
= LookupTag(Message
,"Filename");
501 if (FileName
.empty() == true)
504 ErrorText
= "Method gave a blank filename";
510 // Reference filename
511 if (FileName
!= DestFile
)
513 StoreFilename
= DestFile
= FileName
;
518 // Done, move it into position
519 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
520 FinalFile
+= flNotDir(StoreFilename
);
521 Rename(DestFile
,FinalFile
);
523 StoreFilename
= DestFile
= FinalFile
;
527 // AcqArchive::Failed - Failure handler /*{{{*/
528 // ---------------------------------------------------------------------
529 /* Here we try other sources */
530 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
532 ErrorText
= LookupTag(Message
,"Message");
533 if (QueueNext() == false)
535 // This is the retry counter
537 Cnf
->LocalOnly
== false &&
538 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
541 Vf
= Version
.FileList();
542 if (QueueNext() == true)
546 StoreFilename
= string();
547 Item::Failed(Message
,Cnf
);
551 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
552 // ---------------------------------------------------------------------
554 void pkgAcqArchive::Finished()
556 if (Status
== pkgAcquire::Item::StatDone
&&
559 StoreFilename
= string();
563 // AcqFile::pkgAcqFile - Constructor /*{{{*/
564 // ---------------------------------------------------------------------
565 /* The file is added to the queue */
566 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string MD5
,
567 unsigned long Size
,string Dsc
,string ShortDesc
) :
568 Item(Owner
), Md5Hash(MD5
)
570 DestFile
= flNotDir(URI
);
574 Desc
.Description
= Dsc
;
577 // Set the short description to the archive component
578 Desc
.ShortDesc
= ShortDesc
;
580 // Get the transfer sizes
583 if (stat(DestFile
.c_str(),&Buf
) == 0)
585 // Hmm, the partial file is too big, erase it
586 if ((unsigned)Buf
.st_size
> Size
)
587 unlink(DestFile
.c_str());
589 PartialSize
= Buf
.st_size
;
595 // AcqFile::Done - Item downloaded OK /*{{{*/
596 // ---------------------------------------------------------------------
598 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
)
601 if (Md5Hash
.empty() == false && MD5
.empty() == false)
606 ErrorText
= "MD5Sum mismatch";
607 Rename(DestFile
,DestFile
+ ".FAILED");
612 Item::Done(Message
,Size
,MD5
);
614 string FileName
= LookupTag(Message
,"Filename");
615 if (FileName
.empty() == true)
618 ErrorText
= "Method gave a blank filename";
624 // The files timestamp matches
625 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
628 // We have to copy it into place
629 if (FileName
!= DestFile
)
632 if (_config
->FindB("Acquire::Source-Symlinks",true) == false)
634 Desc
.URI
= "copy:" + FileName
;
639 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
641 ErrorText
= "Link to " + DestFile
+ "failure ";