]>
git.saurik.com Git - apt.git/blob - apt-pkg/acquire-item.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.23 1999/02/01 08:11:57 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>
31 // Acquire::Item::Item - Constructor /*{{{*/
32 // ---------------------------------------------------------------------
34 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
35 Mode(0), ID(0), Complete(false), Local(false),
42 // Acquire::Item::~Item - Destructor /*{{{*/
43 // ---------------------------------------------------------------------
45 pkgAcquire::Item::~Item()
50 // Acquire::Item::Failed - Item failed to download /*{{{*/
51 // ---------------------------------------------------------------------
52 /* We return to an idle state if there are still other queues that could
54 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
57 ErrorText
= LookupTag(Message
,"Message");
58 if (QueueCounter
<= 1)
60 /* This indicates that the file is not available right now but might
61 be sometime later. If we do a retry cycle then this should be
63 if (Cnf
->LocalOnly
== true &&
64 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
76 // Acquire::Item::Start - Item has begun to download /*{{{*/
77 // ---------------------------------------------------------------------
78 /* Stash status and the file size. Note that setting Complete means
79 sub-phases of the acquire process such as decompresion are operating */
80 void pkgAcquire::Item::Start(string Message
,unsigned long Size
)
82 Status
= StatFetching
;
83 if (FileSize
== 0 && Complete
== false)
87 // Acquire::Item::Done - Item downloaded OK /*{{{*/
88 // ---------------------------------------------------------------------
90 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string
)
92 // We just downloaded something..
93 string FileName
= LookupTag(Message
,"Filename");
94 if (Complete
== false && FileName
== DestFile
)
97 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
101 ErrorText
= string();
102 Owner
->Dequeue(this);
105 // Acquire::Item::Rename - Rename a file /*{{{*/
106 // ---------------------------------------------------------------------
107 /* This helper function is used by alot of item methods as thier final
109 void pkgAcquire::Item::Rename(string From
,string To
)
111 if (rename(From
.c_str(),To
.c_str()) != 0)
114 sprintf(S
,"rename failed, %s (%s -> %s).",strerror(errno
),
115 From
.c_str(),To
.c_str());
122 // AcqIndex::AcqIndex - Constructor /*{{{*/
123 // ---------------------------------------------------------------------
124 /* The package file is added to the queue and a second class is
125 instantiated to fetch the revision file */
126 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,const pkgSourceList::Item
*Location
) :
127 Item(Owner
), Location(Location
)
129 Decompression
= false;
132 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
133 DestFile
+= URItoFileName(Location
->PackagesURI());
136 Desc
.URI
= Location
->PackagesURI() + ".gz";
137 Desc
.Description
= Location
->PackagesInfo();
140 // Set the short description to the archive component
141 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
142 Desc
.ShortDesc
= Location
->Dist
;
144 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
148 // Create the Release fetch class
149 new pkgAcqIndexRel(Owner
,Location
);
152 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
153 // ---------------------------------------------------------------------
154 /* The only header we use is the last-modified header. */
155 string
pkgAcqIndex::Custom600Headers()
157 string Final
= _config
->FindDir("Dir::State::lists");
158 Final
+= URItoFileName(Location
->PackagesURI());
161 if (stat(Final
.c_str(),&Buf
) != 0)
162 return "\nIndex-File: true";
164 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
167 // AcqIndex::Done - Finished a fetch /*{{{*/
168 // ---------------------------------------------------------------------
169 /* This goes through a number of states.. On the initial fetch the
170 method could possibly return an alternate filename which points
171 to the uncompressed version of the file. If this is so the file
172 is copied into the partial directory. In all other cases the file
173 is decompressed with a gzip uri. */
174 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
)
176 Item::Done(Message
,Size
,MD5
);
178 if (Decompression
== true)
180 // Done, move it into position
181 string FinalFile
= _config
->FindDir("Dir::State::lists");
182 FinalFile
+= URItoFileName(Location
->PackagesURI());
183 Rename(DestFile
,FinalFile
);
185 /* We restore the original name to DestFile so that the clean operation
187 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
188 DestFile
+= URItoFileName(Location
->PackagesURI());
190 // Remove the compressed version.
192 unlink(DestFile
.c_str());
199 // Handle the unzipd case
200 string FileName
= LookupTag(Message
,"Alt-Filename");
201 if (FileName
.empty() == false)
203 // The files timestamp matches
204 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
207 Decompression
= true;
209 DestFile
+= ".decomp";
210 Desc
.URI
= "copy:" + FileName
;
216 FileName
= LookupTag(Message
,"Filename");
217 if (FileName
.empty() == true)
220 ErrorText
= "Method gave a blank filename";
223 // The files timestamp matches
224 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
227 if (FileName
== DestFile
)
232 Decompression
= true;
233 DestFile
+= ".decomp";
234 Desc
.URI
= "gzip:" + FileName
,Location
->PackagesInfo();
239 // AcqIndex::Describe - Describe the Item /*{{{*/
240 // ---------------------------------------------------------------------
242 string
pkgAcqIndex::Describe()
244 return Location
->PackagesURI();
248 // AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
249 // ---------------------------------------------------------------------
250 /* The Release file is added to the queue */
251 pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire
*Owner
,
252 const pkgSourceList::Item
*Location
) :
253 Item(Owner
), Location(Location
)
255 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
256 DestFile
+= URItoFileName(Location
->ReleaseURI());
259 Desc
.URI
= Location
->ReleaseURI();
260 Desc
.Description
= Location
->ReleaseInfo();
263 // Set the short description to the archive component
264 if (Location
->Dist
[Location
->Dist
.size() - 1] == '/')
265 Desc
.ShortDesc
= Location
->Dist
;
267 Desc
.ShortDesc
= Location
->Dist
+ '/' + Location
->Section
;
272 // AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
273 // ---------------------------------------------------------------------
274 /* The only header we use is the last-modified header. */
275 string
pkgAcqIndexRel::Custom600Headers()
277 string Final
= _config
->FindDir("Dir::State::lists");
278 Final
+= URItoFileName(Location
->ReleaseURI());
281 if (stat(Final
.c_str(),&Buf
) != 0)
282 return "\nIndex-File: true";
284 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
287 // AcqIndexRel::Done - Item downloaded OK /*{{{*/
288 // ---------------------------------------------------------------------
289 /* The release file was not placed into the download directory then
290 a copy URI is generated and it is copied there otherwise the file
291 in the partial directory is moved into .. and the URI is finished. */
292 void pkgAcqIndexRel::Done(string Message
,unsigned long Size
,string MD5
)
294 Item::Done(Message
,Size
,MD5
);
296 string FileName
= LookupTag(Message
,"Filename");
297 if (FileName
.empty() == true)
300 ErrorText
= "Method gave a blank filename";
306 // The files timestamp matches
307 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
310 // We have to copy it into place
311 if (FileName
!= DestFile
)
314 Desc
.URI
= "copy:" + FileName
;
319 // Done, move it into position
320 string FinalFile
= _config
->FindDir("Dir::State::lists");
321 FinalFile
+= URItoFileName(Location
->ReleaseURI());
322 Rename(DestFile
,FinalFile
);
325 // AcqIndexRel::Describe - Describe the Item /*{{{*/
326 // ---------------------------------------------------------------------
328 string
pkgAcqIndexRel::Describe()
330 return Location
->ReleaseURI();
333 // AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
334 // ---------------------------------------------------------------------
336 void pkgAcqIndexRel::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
338 // This is the retry counter
339 if (Cnf
->LocalOnly
== true ||
340 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
347 Item::Failed(Message
,Cnf
);
351 // AcqArchive::AcqArchive - Constructor /*{{{*/
352 // ---------------------------------------------------------------------
353 /* This just sets up the initial fetch environment and queues the first
355 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
356 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
357 string
&StoreFilename
) :
358 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
359 StoreFilename(StoreFilename
), Vf(Version
.FileList())
361 Retries
= _config
->FindI("Acquire::Retries",0);
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 shouldnt
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
);
453 Desc
.URI
= Location
->ArchiveURI(PkgFile
);
454 Desc
.Description
= Location
->ArchiveInfo(Version
);
456 Desc
.ShortDesc
= Version
.ParentPkg().Name();
465 // AcqArchive::Done - Finished fetching /*{{{*/
466 // ---------------------------------------------------------------------
468 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
)
470 Item::Done(Message
,Size
,Md5Hash
);
473 if (Size
!= Version
->Size
)
475 _error
->Error("Size mismatch for package %s",Version
.ParentPkg().Name());
480 if (Md5Hash
.empty() == false && MD5
.empty() == false)
484 _error
->Error("MD5Sum mismatch for package %s",Version
.ParentPkg().Name());
489 // Grab the output filename
490 string FileName
= LookupTag(Message
,"Filename");
491 if (FileName
.empty() == true)
494 ErrorText
= "Method gave a blank filename";
500 // Reference filename
501 if (FileName
!= DestFile
)
503 StoreFilename
= DestFile
= FileName
;
508 // Done, move it into position
509 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
510 FinalFile
+= flNotDir(StoreFilename
);
511 Rename(DestFile
,FinalFile
);
513 StoreFilename
= DestFile
= FinalFile
;
517 // AcqArchive::Describe - Describe the Item /*{{{*/
518 // ---------------------------------------------------------------------
520 string
pkgAcqArchive::Describe()
525 // AcqArchive::Failed - Failure handler /*{{{*/
526 // ---------------------------------------------------------------------
527 /* Here we try other sources */
528 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
530 ErrorText
= LookupTag(Message
,"Message");
531 if (QueueNext() == false)
533 // This is the retry counter
535 Cnf
->LocalOnly
== false &&
536 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
539 Vf
= Version
.FileList();
540 if (QueueNext() == true)
544 Item::Failed(Message
,Cnf
);