]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-item.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.27 1999/04/07 05:30:17 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()));
102 ErrorText
= string();
103 Owner
->Dequeue(this);
106 // Acquire::Item::Rename - Rename a file /*{{{*/
107 // ---------------------------------------------------------------------
108 /* This helper function is used by alot of item methods as thier final
110 void pkgAcquire::Item::Rename(string From
,string To
)
112 if (rename(From
.c_str(),To
.c_str()) != 0)
115 sprintf(S
,"rename failed, %s (%s -> %s).",strerror(errno
),
116 From
.c_str(),To
.c_str());
123 // AcqIndex::AcqIndex - Constructor /*{{{*/
124 // ---------------------------------------------------------------------
125 /* The package file is added to the queue and a second class is
126 instantiated to fetch the revision file */
127 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,const pkgSourceList::Item
*Location
) :
128 Item(Owner
), Location(Location
)
130 Decompression
= false;
133 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
134 DestFile
+= URItoFileName(Location
->PackagesURI());
137 Desc
.URI
= Location
->PackagesURI() + ".gz";
138 Desc
.Description
= Location
->PackagesInfo();
141 // Set the short description to the archive component
142 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
143 Desc
.ShortDesc
= Location
->Dist
;
145 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
149 // Create the Release fetch class
150 new pkgAcqIndexRel(Owner
,Location
);
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(Location
->PackagesURI());
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
)
177 Item::Done(Message
,Size
,MD5
);
179 if (Decompression
== true)
181 // Done, move it into position
182 string FinalFile
= _config
->FindDir("Dir::State::lists");
183 FinalFile
+= URItoFileName(Location
->PackagesURI());
184 Rename(DestFile
,FinalFile
);
186 /* We restore the original name to DestFile so that the clean operation
188 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
189 DestFile
+= URItoFileName(Location
->PackagesURI());
191 // Remove the compressed version.
193 unlink(DestFile
.c_str());
200 // Handle the unzipd case
201 string FileName
= LookupTag(Message
,"Alt-Filename");
202 if (FileName
.empty() == false)
204 // The files timestamp matches
205 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
208 Decompression
= true;
210 DestFile
+= ".decomp";
211 Desc
.URI
= "copy:" + FileName
;
217 FileName
= LookupTag(Message
,"Filename");
218 if (FileName
.empty() == true)
221 ErrorText
= "Method gave a blank filename";
224 // The files timestamp matches
225 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
228 if (FileName
== DestFile
)
233 Decompression
= true;
234 DestFile
+= ".decomp";
235 Desc
.URI
= "gzip:" + FileName
,Location
->PackagesInfo();
241 // AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
242 // ---------------------------------------------------------------------
243 /* The Release file is added to the queue */
244 pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire
*Owner
,
245 const pkgSourceList::Item
*Location
) :
246 Item(Owner
), Location(Location
)
248 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
249 DestFile
+= URItoFileName(Location
->ReleaseURI());
252 Desc
.URI
= Location
->ReleaseURI();
253 Desc
.Description
= Location
->ReleaseInfo();
256 // Set the short description to the archive component
257 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
258 Desc
.ShortDesc
= Location
->Dist
;
260 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
265 // AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
266 // ---------------------------------------------------------------------
267 /* The only header we use is the last-modified header. */
268 string
pkgAcqIndexRel::Custom600Headers()
270 string Final
= _config
->FindDir("Dir::State::lists");
271 Final
+= URItoFileName(Location
->ReleaseURI());
274 if (stat(Final
.c_str(),&Buf
) != 0)
275 return "\nIndex-File: true";
277 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
280 // AcqIndexRel::Done - Item downloaded OK /*{{{*/
281 // ---------------------------------------------------------------------
282 /* The release file was not placed into the download directory then
283 a copy URI is generated and it is copied there otherwise the file
284 in the partial directory is moved into .. and the URI is finished. */
285 void pkgAcqIndexRel::Done(string Message
,unsigned long Size
,string MD5
)
287 Item::Done(Message
,Size
,MD5
);
289 string FileName
= LookupTag(Message
,"Filename");
290 if (FileName
.empty() == true)
293 ErrorText
= "Method gave a blank filename";
299 // The files timestamp matches
300 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
303 // We have to copy it into place
304 if (FileName
!= DestFile
)
307 Desc
.URI
= "copy:" + FileName
;
312 // Done, move it into position
313 string FinalFile
= _config
->FindDir("Dir::State::lists");
314 FinalFile
+= URItoFileName(Location
->ReleaseURI());
315 Rename(DestFile
,FinalFile
);
318 // AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
319 // ---------------------------------------------------------------------
321 void pkgAcqIndexRel::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
323 // This is the retry counter
324 if (Cnf
->LocalOnly
== true ||
325 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
334 Item::Failed(Message
,Cnf
);
338 // AcqArchive::AcqArchive - Constructor /*{{{*/
339 // ---------------------------------------------------------------------
340 /* This just sets up the initial fetch environment and queues the first
342 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
343 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
344 string
&StoreFilename
) :
345 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
346 StoreFilename(StoreFilename
), Vf(Version
.FileList())
348 Retries
= _config
->FindI("Acquire::Retries",0);
350 // Generate the final file name as: package_version_arch.deb
351 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
352 QuoteString(Version
.VerStr(),"_:") + '_' +
353 QuoteString(Version
.Arch(),"_:.") + ".deb";
356 if (QueueNext() == false && _error
->PendingError() == false)
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.",
359 Version
.ParentPkg().Name());
362 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
363 // ---------------------------------------------------------------------
364 /* This queues the next available file version for download. It checks if
365 the archive is already available in the cache and stashs the MD5 for
367 bool pkgAcqArchive::QueueNext()
369 for (; Vf
.end() == false; Vf
++)
371 // Ignore not source sources
372 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
375 // Try to cross match against the source list
376 string PkgFile
= flNotDir(Vf
.File().FileName());
377 pkgSourceList::const_iterator Location
;
378 for (Location
= Sources
->begin(); Location
!= Sources
->end(); Location
++)
379 if (PkgFile
== URItoFileName(Location
->PackagesURI()))
382 if (Location
== Sources
->end())
385 // Grab the text package record
386 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
387 if (_error
->PendingError() == true)
390 PkgFile
= Parse
.FileName();
391 MD5
= Parse
.MD5Hash();
392 if (PkgFile
.empty() == true)
393 return _error
->Error("The package index files are corrupted. No Filename: "
394 "field for package %s."
395 ,Version
.ParentPkg().Name());
397 // See if we already have the file. (Legacy filenames)
398 FileSize
= Version
->Size
;
399 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
401 if (stat(FinalFile
.c_str(),&Buf
) == 0)
403 // Make sure the size matches
404 if ((unsigned)Buf
.st_size
== Version
->Size
)
409 StoreFilename
= DestFile
= FinalFile
;
413 /* Hmm, we have a file and its size does not match, this means it is
414 an old style mismatched arch */
415 unlink(FinalFile
.c_str());
418 // Check it again using the new style output filenames
419 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
420 if (stat(FinalFile
.c_str(),&Buf
) == 0)
422 // Make sure the size matches
423 if ((unsigned)Buf
.st_size
== Version
->Size
)
428 StoreFilename
= DestFile
= FinalFile
;
432 /* Hmm, we have a file and its size does not match, this shouldnt
434 unlink(FinalFile
.c_str());
437 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
439 // Check the destination file
440 if (stat(DestFile
.c_str(),&Buf
) == 0)
442 // Hmm, the partial file is too big, erase it
443 if ((unsigned)Buf
.st_size
> Version
->Size
)
444 unlink(DestFile
.c_str());
446 PartialSize
= Buf
.st_size
;
450 Desc
.URI
= Location
->ArchiveURI(PkgFile
);
451 Desc
.Description
= Location
->ArchiveInfo(Version
);
453 Desc
.ShortDesc
= Version
.ParentPkg().Name();
462 // AcqArchive::Done - Finished fetching /*{{{*/
463 // ---------------------------------------------------------------------
465 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
)
467 Item::Done(Message
,Size
,Md5Hash
);
470 if (Size
!= Version
->Size
)
472 _error
->Error("Size mismatch for package %s",Version
.ParentPkg().Name());
477 if (Md5Hash
.empty() == false && MD5
.empty() == false)
481 _error
->Error("MD5Sum mismatch for package %s",Version
.ParentPkg().Name());
486 // Grab the output filename
487 string FileName
= LookupTag(Message
,"Filename");
488 if (FileName
.empty() == true)
491 ErrorText
= "Method gave a blank filename";
497 // Reference filename
498 if (FileName
!= DestFile
)
500 StoreFilename
= DestFile
= FileName
;
505 // Done, move it into position
506 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
507 FinalFile
+= flNotDir(StoreFilename
);
508 Rename(DestFile
,FinalFile
);
510 StoreFilename
= DestFile
= FinalFile
;
514 // AcqArchive::Failed - Failure handler /*{{{*/
515 // ---------------------------------------------------------------------
516 /* Here we try other sources */
517 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
519 ErrorText
= LookupTag(Message
,"Message");
520 if (QueueNext() == false)
522 // This is the retry counter
524 Cnf
->LocalOnly
== false &&
525 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
528 Vf
= Version
.FileList();
529 if (QueueNext() == true)
533 StoreFilename
= string();
534 Item::Failed(Message
,Cnf
);
539 // AcqFile::pkgAcqFile - Constructor /*{{{*/
540 // ---------------------------------------------------------------------
541 /* The file is added to the queue */
542 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string MD5
,
543 unsigned long Size
,string Dsc
,string ShortDesc
) :
544 Item(Owner
), MD5(MD5
)
546 DestFile
= flNotDir(URI
);
550 Desc
.Description
= Dsc
;
553 // Set the short description to the archive component
554 Desc
.ShortDesc
= ShortDesc
;
556 // Get the transfer sizes
559 if (stat(DestFile
.c_str(),&Buf
) == 0)
561 // Hmm, the partial file is too big, erase it
562 if ((unsigned)Buf
.st_size
> Size
)
563 unlink(DestFile
.c_str());
565 PartialSize
= Buf
.st_size
;
571 // AcqFile::Done - Item downloaded OK /*{{{*/
572 // ---------------------------------------------------------------------
574 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
)
576 Item::Done(Message
,Size
,MD5
);
578 string FileName
= LookupTag(Message
,"Filename");
579 if (FileName
.empty() == true)
582 ErrorText
= "Method gave a blank filename";
588 // The files timestamp matches
589 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
592 // We have to copy it into place
593 if (FileName
!= DestFile
)
596 Desc
.URI
= "copy:" + FileName
;