]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
Added --print-uris
[apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
cdcc6d34 3// $Id: acquire-item.cc,v 1.19 1999/01/27 02:48:52 jgg Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire Item - Item to acquire
7
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.
b185acc2 12
0118833a
AL
13 ##################################################################### */
14 /*}}}*/
15// Include Files /*{{{*/
16#ifdef __GNUG__
17#pragma implementation "apt-pkg/acquire-item.h"
18#endif
19#include <apt-pkg/acquire-item.h>
20#include <apt-pkg/configuration.h>
03e39e59 21#include <apt-pkg/error.h>
cdcc6d34 22#include <apt-pkg/strutl.h>
0a8a80e5
AL
23
24#include <sys/stat.h>
25#include <unistd.h>
c88edf1d
AL
26#include <errno.h>
27#include <string.h>
28#include <stdio.h>
0118833a
AL
29 /*}}}*/
30
31// Acquire::Item::Item - Constructor /*{{{*/
32// ---------------------------------------------------------------------
33/* */
8267fe24 34pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
a6568219
AL
35 Mode(0), ID(0), Complete(false), Local(false),
36 QueueCounter(0)
0118833a
AL
37{
38 Owner->Add(this);
c88edf1d 39 Status = StatIdle;
0118833a
AL
40}
41 /*}}}*/
42// Acquire::Item::~Item - Destructor /*{{{*/
43// ---------------------------------------------------------------------
44/* */
45pkgAcquire::Item::~Item()
46{
47 Owner->Remove(this);
48}
49 /*}}}*/
c88edf1d
AL
50// Acquire::Item::Failed - Item failed to download /*{{{*/
51// ---------------------------------------------------------------------
93bf083d
AL
52/* We return to an idle state if there are still other queues that could
53 fetch this object */
c88edf1d
AL
54void pkgAcquire::Item::Failed(string Message)
55{
93bf083d 56 Status = StatIdle;
db890fdb 57 ErrorText = LookupTag(Message,"Message");
c88edf1d 58 if (QueueCounter <= 1)
93bf083d 59 {
a72ace20
AL
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
62 retried */
63 if (StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
64 {
65 Status = StatIdle;
66 Owner->Dequeue(this);
67 return;
68 }
69
93bf083d 70 Status = StatError;
c88edf1d 71 Owner->Dequeue(this);
93bf083d 72 }
c88edf1d
AL
73}
74 /*}}}*/
8267fe24
AL
75// Acquire::Item::Start - Item has begun to download /*{{{*/
76// ---------------------------------------------------------------------
77/* */
78void pkgAcquire::Item::Start(string Message,unsigned long Size)
79{
80 Status = StatFetching;
81 if (FileSize == 0 && Complete == false)
82 FileSize = Size;
83}
84 /*}}}*/
c88edf1d
AL
85// Acquire::Item::Done - Item downloaded OK /*{{{*/
86// ---------------------------------------------------------------------
87/* */
b98f2859 88void pkgAcquire::Item::Done(string Message,unsigned long Size,string)
c88edf1d 89{
b98f2859
AL
90 // We just downloaded something..
91 string FileName = LookupTag(Message,"Filename");
92 if (Complete == false && FileName == DestFile)
93 {
94 if (Owner->Log != 0)
95 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
96 }
97
c88edf1d
AL
98 Status = StatDone;
99 ErrorText = string();
100 Owner->Dequeue(this);
101}
102 /*}}}*/
8b89e57f
AL
103// Acquire::Item::Rename - Rename a file /*{{{*/
104// ---------------------------------------------------------------------
105/* This helper function is used by alot of item methods as thier final
106 step */
107void pkgAcquire::Item::Rename(string From,string To)
108{
109 if (rename(From.c_str(),To.c_str()) != 0)
110 {
111 char S[300];
112 sprintf(S,"rename failed, %s (%s -> %s).",strerror(errno),
113 From.c_str(),To.c_str());
114 Status = StatError;
115 ErrorText = S;
116 }
117}
118 /*}}}*/
0118833a
AL
119
120// AcqIndex::AcqIndex - Constructor /*{{{*/
121// ---------------------------------------------------------------------
122/* The package file is added to the queue and a second class is
123 instantiated to fetch the revision file */
124pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location) :
125 Item(Owner), Location(Location)
126{
8b89e57f 127 Decompression = false;
bfd22fc0 128 Erase = false;
8b89e57f 129
0a8a80e5
AL
130 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
131 DestFile += URItoFileName(Location->PackagesURI());
8267fe24
AL
132
133 // Create the item
134 Desc.URI = Location->PackagesURI() + ".gz";
135 Desc.Description = Location->PackagesInfo();
136 Desc.Owner = this;
137
138 // Set the short description to the archive component
139 if (Location->Dist[Location->Dist.size() - 1] == '/')
140 Desc.ShortDesc = Location->Dist;
141 else
142 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
143
144 QueueURI(Desc);
0118833a 145
0a8a80e5 146 // Create the Release fetch class
0118833a
AL
147 new pkgAcqIndexRel(Owner,Location);
148}
149 /*}}}*/
0a8a80e5 150// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 151// ---------------------------------------------------------------------
0a8a80e5
AL
152/* The only header we use is the last-modified header. */
153string pkgAcqIndex::Custom600Headers()
0118833a 154{
0a8a80e5
AL
155 string Final = _config->FindDir("Dir::State::lists");
156 Final += URItoFileName(Location->PackagesURI());
157
158 struct stat Buf;
159 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 160 return "\nIndex-File: true";
0118833a 161
a72ace20 162 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
163}
164 /*}}}*/
8b89e57f
AL
165// AcqIndex::Done - Finished a fetch /*{{{*/
166// ---------------------------------------------------------------------
167/* This goes through a number of states.. On the initial fetch the
168 method could possibly return an alternate filename which points
169 to the uncompressed version of the file. If this is so the file
170 is copied into the partial directory. In all other cases the file
171 is decompressed with a gzip uri. */
172void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5)
173{
174 Item::Done(Message,Size,MD5);
175
176 if (Decompression == true)
177 {
178 // Done, move it into position
179 string FinalFile = _config->FindDir("Dir::State::lists");
180 FinalFile += URItoFileName(Location->PackagesURI());
181 Rename(DestFile,FinalFile);
bfd22fc0 182
7a7fa5f0
AL
183 /* We restore the original name to DestFile so that the clean operation
184 will work OK */
185 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
186 DestFile += URItoFileName(Location->PackagesURI());
187
bfd22fc0
AL
188 // Remove the compressed version.
189 if (Erase == true)
bfd22fc0 190 unlink(DestFile.c_str());
8b89e57f
AL
191 return;
192 }
bfd22fc0
AL
193
194 Erase = false;
8267fe24 195 Complete = true;
bfd22fc0 196
8b89e57f
AL
197 // Handle the unzipd case
198 string FileName = LookupTag(Message,"Alt-Filename");
199 if (FileName.empty() == false)
200 {
201 // The files timestamp matches
202 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
203 return;
204
205 Decompression = true;
a6568219 206 Local = true;
8b89e57f 207 DestFile += ".decomp";
8267fe24
AL
208 Desc.URI = "copy:" + FileName;
209 QueueURI(Desc);
b98f2859 210 Mode = "copy";
8b89e57f
AL
211 return;
212 }
213
214 FileName = LookupTag(Message,"Filename");
215 if (FileName.empty() == true)
216 {
217 Status = StatError;
218 ErrorText = "Method gave a blank filename";
219 }
220
221 // The files timestamp matches
222 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
223 return;
bfd22fc0
AL
224
225 if (FileName == DestFile)
226 Erase = true;
8267fe24 227 else
a6568219 228 Local = true;
8b89e57f
AL
229
230 Decompression = true;
231 DestFile += ".decomp";
8267fe24
AL
232 Desc.URI = "gzip:" + FileName,Location->PackagesInfo();
233 QueueURI(Desc);
b98f2859 234 Mode = "gzip";
8b89e57f
AL
235}
236 /*}}}*/
30e1eab5
AL
237// AcqIndex::Describe - Describe the Item /*{{{*/
238// ---------------------------------------------------------------------
239/* */
240string pkgAcqIndex::Describe()
241{
242 return Location->PackagesURI();
243}
244 /*}}}*/
8b89e57f 245
0118833a
AL
246// AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
247// ---------------------------------------------------------------------
248/* The Release file is added to the queue */
249pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
250 const pkgSourceList::Item *Location) :
251 Item(Owner), Location(Location)
252{
0a8a80e5
AL
253 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
254 DestFile += URItoFileName(Location->ReleaseURI());
255
8267fe24
AL
256 // Create the item
257 Desc.URI = Location->ReleaseURI();
258 Desc.Description = Location->ReleaseInfo();
259 Desc.Owner = this;
260
261 // Set the short description to the archive component
262 if (Location->Dist[Location->Dist.size() - 1] == '/')
263 Desc.ShortDesc = Location->Dist;
264 else
265 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
266
267 QueueURI(Desc);
0118833a
AL
268}
269 /*}}}*/
0a8a80e5 270// AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 271// ---------------------------------------------------------------------
0a8a80e5
AL
272/* The only header we use is the last-modified header. */
273string pkgAcqIndexRel::Custom600Headers()
0118833a 274{
0a8a80e5
AL
275 string Final = _config->FindDir("Dir::State::lists");
276 Final += URItoFileName(Location->ReleaseURI());
277
278 struct stat Buf;
279 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 280 return "\nIndex-File: true";
0118833a 281
a72ace20 282 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
283}
284 /*}}}*/
c88edf1d
AL
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. */
290void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5)
291{
292 Item::Done(Message,Size,MD5);
293
294 string FileName = LookupTag(Message,"Filename");
295 if (FileName.empty() == true)
296 {
297 Status = StatError;
298 ErrorText = "Method gave a blank filename";
8b89e57f 299 return;
c88edf1d 300 }
8b89e57f 301
8267fe24
AL
302 Complete = true;
303
8b89e57f
AL
304 // The files timestamp matches
305 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
306 return;
c88edf1d
AL
307
308 // We have to copy it into place
309 if (FileName != DestFile)
310 {
a6568219 311 Local = true;
8267fe24
AL
312 Desc.URI = "copy:" + FileName;
313 QueueURI(Desc);
c88edf1d
AL
314 return;
315 }
316
317 // Done, move it into position
318 string FinalFile = _config->FindDir("Dir::State::lists");
319 FinalFile += URItoFileName(Location->ReleaseURI());
8b89e57f 320 Rename(DestFile,FinalFile);
c88edf1d
AL
321}
322 /*}}}*/
30e1eab5
AL
323// AcqIndexRel::Describe - Describe the Item /*{{{*/
324// ---------------------------------------------------------------------
325/* */
326string pkgAcqIndexRel::Describe()
327{
328 return Location->ReleaseURI();
329}
330 /*}}}*/
03e39e59
AL
331
332// AcqArchive::AcqArchive - Constructor /*{{{*/
333// ---------------------------------------------------------------------
334/* */
335pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
336 pkgRecords *Recs,pkgCache::VerIterator const &Version,
337 string &StoreFilename) :
338 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b185acc2 339 StoreFilename(StoreFilename), Vf(Version.FileList())
03e39e59
AL
340{
341 // Select a source
b185acc2
AL
342 if (QueueNext() == false && _error->PendingError() == false)
343 _error->Error("I wasn't able to locate file for the %s package. "
344 "This might mean you need to manually fix this package.",
345 Version.ParentPkg().Name());
346}
347 /*}}}*/
348// AcqArchive::QueueNext - Queue the next file source /*{{{*/
349// ---------------------------------------------------------------------
350/* This queues the next available file version for download. */
351bool pkgAcqArchive::QueueNext()
352{
03e39e59
AL
353 for (; Vf.end() == false; Vf++)
354 {
355 // Ignore not source sources
356 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
357 continue;
358
359 // Try to cross match against the source list
360 string PkgFile = flNotDir(Vf.File().FileName());
361 pkgSourceList::const_iterator Location;
362 for (Location = Sources->begin(); Location != Sources->end(); Location++)
363 if (PkgFile == URItoFileName(Location->PackagesURI()))
364 break;
365
366 if (Location == Sources->end())
367 continue;
368
369 // Grab the text package record
370 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
371 if (_error->PendingError() == true)
b185acc2 372 return false;
03e39e59
AL
373
374 PkgFile = Parse.FileName();
375 MD5 = Parse.MD5Hash();
376 if (PkgFile.empty() == true)
b185acc2
AL
377 return _error->Error("The package index files are corrupted. No Filename: "
378 "field for package %s."
379 ,Version.ParentPkg().Name());
a6568219
AL
380
381 // See if we already have the file.
382 FileSize = Version->Size;
383 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
384 struct stat Buf;
385 if (stat(FinalFile.c_str(),&Buf) == 0)
386 {
387 // Make sure the size matches
388 if ((unsigned)Buf.st_size == Version->Size)
389 {
390 Complete = true;
391 Local = true;
392 Status = StatDone;
30e1eab5 393 StoreFilename = DestFile = FinalFile;
b185acc2 394 return true;
a6568219
AL
395 }
396
397 /* Hmm, we have a file and its size does not match, this shouldnt
398 happen.. */
399 unlink(FinalFile.c_str());
400 }
401
402 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(PkgFile);
03e39e59
AL
403
404 // Create the item
405 Desc.URI = Location->ArchiveURI(PkgFile);
406 Desc.Description = Location->ArchiveInfo(Version);
407 Desc.Owner = this;
408 Desc.ShortDesc = Version.ParentPkg().Name();
409 QueueURI(Desc);
b185acc2
AL
410
411 Vf++;
412 return true;
03e39e59 413 }
b185acc2
AL
414 return false;
415}
03e39e59
AL
416 /*}}}*/
417// AcqArchive::Done - Finished fetching /*{{{*/
418// ---------------------------------------------------------------------
419/* */
420void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash)
421{
fd9bd3dc 422 Item::Done(Message,Size,Md5Hash);
03e39e59
AL
423
424 // Check the size
425 if (Size != Version->Size)
426 {
427 _error->Error("Size mismatch for package %s",Version.ParentPkg().Name());
428 return;
429 }
430
431 // Check the md5
432 if (Md5Hash.empty() == false && MD5.empty() == false)
433 {
434 if (Md5Hash != MD5)
435 {
436 _error->Error("MD5Sum mismatch for package %s",Version.ParentPkg().Name());
437 return;
438 }
439 }
a6568219
AL
440
441 // Grab the output filename
03e39e59
AL
442 string FileName = LookupTag(Message,"Filename");
443 if (FileName.empty() == true)
444 {
445 Status = StatError;
446 ErrorText = "Method gave a blank filename";
447 return;
448 }
a6568219
AL
449
450 Complete = true;
30e1eab5
AL
451
452 // Reference filename
a6568219
AL
453 if (FileName != DestFile)
454 {
30e1eab5 455 StoreFilename = DestFile = FileName;
a6568219
AL
456 Local = true;
457 return;
458 }
459
460 // Done, move it into position
461 string FinalFile = _config->FindDir("Dir::Cache::Archives");
462 FinalFile += flNotDir(DestFile);
463 Rename(DestFile,FinalFile);
03e39e59 464
30e1eab5 465 StoreFilename = DestFile = FinalFile;
03e39e59
AL
466 Complete = true;
467}
468 /*}}}*/
30e1eab5
AL
469// AcqArchive::Describe - Describe the Item /*{{{*/
470// ---------------------------------------------------------------------
471/* */
472string pkgAcqArchive::Describe()
473{
474 return Desc.URI;
475}
476 /*}}}*/
db890fdb
AL
477// AcqArchive::Failed - Failure handler /*{{{*/
478// ---------------------------------------------------------------------
479/* Here we try other sources */
480void pkgAcqArchive::Failed(string Message)
481{
482 ErrorText = LookupTag(Message,"Message");
483 if (QueueNext() == false)
484 Item::Failed(Message);
485}
486 /*}}}*/