]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
Open 0.5.31
[apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
0fcd01de 3// $Id: acquire-item.cc,v 1.46 2003/02/02 22:19:17 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>
b2e465d6 21#include <apt-pkg/sourcelist.h>
03e39e59 22#include <apt-pkg/error.h>
cdcc6d34 23#include <apt-pkg/strutl.h>
36375005 24#include <apt-pkg/fileutl.h>
0a8a80e5 25
b2e465d6
AL
26#include <apti18n.h>
27
0a8a80e5
AL
28#include <sys/stat.h>
29#include <unistd.h>
c88edf1d 30#include <errno.h>
5819a761 31#include <string>
c88edf1d 32#include <stdio.h>
0118833a
AL
33 /*}}}*/
34
5819a761
AL
35using std::string;
36
0118833a
AL
37// Acquire::Item::Item - Constructor /*{{{*/
38// ---------------------------------------------------------------------
39/* */
8267fe24 40pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
6b1ff003
AL
41 PartialSize(0), Mode(0), ID(0), Complete(false),
42 Local(false), QueueCounter(0)
0118833a
AL
43{
44 Owner->Add(this);
c88edf1d 45 Status = StatIdle;
0118833a
AL
46}
47 /*}}}*/
48// Acquire::Item::~Item - Destructor /*{{{*/
49// ---------------------------------------------------------------------
50/* */
51pkgAcquire::Item::~Item()
52{
53 Owner->Remove(this);
54}
55 /*}}}*/
c88edf1d
AL
56// Acquire::Item::Failed - Item failed to download /*{{{*/
57// ---------------------------------------------------------------------
93bf083d
AL
58/* We return to an idle state if there are still other queues that could
59 fetch this object */
7d8afa39 60void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
c88edf1d 61{
93bf083d 62 Status = StatIdle;
db890fdb 63 ErrorText = LookupTag(Message,"Message");
c88edf1d 64 if (QueueCounter <= 1)
93bf083d 65 {
a72ace20 66 /* This indicates that the file is not available right now but might
7d8afa39 67 be sometime later. If we do a retry cycle then this should be
17caf1b1 68 retried [CDROMs] */
7d8afa39
AL
69 if (Cnf->LocalOnly == true &&
70 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
a72ace20
AL
71 {
72 Status = StatIdle;
681d76d0 73 Dequeue();
a72ace20
AL
74 return;
75 }
76
93bf083d 77 Status = StatError;
681d76d0 78 Dequeue();
93bf083d 79 }
c88edf1d
AL
80}
81 /*}}}*/
8267fe24
AL
82// Acquire::Item::Start - Item has begun to download /*{{{*/
83// ---------------------------------------------------------------------
17caf1b1
AL
84/* Stash status and the file size. Note that setting Complete means
85 sub-phases of the acquire process such as decompresion are operating */
727f18af 86void pkgAcquire::Item::Start(string /*Message*/,unsigned long Size)
8267fe24
AL
87{
88 Status = StatFetching;
89 if (FileSize == 0 && Complete == false)
90 FileSize = Size;
91}
92 /*}}}*/
c88edf1d
AL
93// Acquire::Item::Done - Item downloaded OK /*{{{*/
94// ---------------------------------------------------------------------
95/* */
459681d3
AL
96void pkgAcquire::Item::Done(string Message,unsigned long Size,string,
97 pkgAcquire::MethodConfig *Cnf)
c88edf1d 98{
b98f2859
AL
99 // We just downloaded something..
100 string FileName = LookupTag(Message,"Filename");
101 if (Complete == false && FileName == DestFile)
102 {
103 if (Owner->Log != 0)
104 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
105 }
aa0e1101
AL
106
107 if (FileSize == 0)
108 FileSize= Size;
b98f2859 109
c88edf1d
AL
110 Status = StatDone;
111 ErrorText = string();
112 Owner->Dequeue(this);
113}
114 /*}}}*/
8b89e57f
AL
115// Acquire::Item::Rename - Rename a file /*{{{*/
116// ---------------------------------------------------------------------
117/* This helper function is used by alot of item methods as thier final
118 step */
119void pkgAcquire::Item::Rename(string From,string To)
120{
121 if (rename(From.c_str(),To.c_str()) != 0)
122 {
123 char S[300];
0fcd01de 124 snprintf(S,sizeof(S),_("rename failed, %s (%s -> %s)."),strerror(errno),
8b89e57f
AL
125 From.c_str(),To.c_str());
126 Status = StatError;
127 ErrorText = S;
7a3c2ab0 128 }
8b89e57f
AL
129}
130 /*}}}*/
0118833a
AL
131
132// AcqIndex::AcqIndex - Constructor /*{{{*/
133// ---------------------------------------------------------------------
134/* The package file is added to the queue and a second class is
b2e465d6
AL
135 instantiated to fetch the revision file */
136pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,
137 string URI,string URIDesc,string ShortDesc) :
138 Item(Owner), RealURI(URI)
0118833a 139{
8b89e57f 140 Decompression = false;
bfd22fc0 141 Erase = false;
8b89e57f 142
0a8a80e5 143 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 144 DestFile += URItoFileName(URI);
8267fe24 145
54cf15cb 146 // Create the item
debc84b2 147 Desc.URI = URI + ".bz2";
b2e465d6 148 Desc.Description = URIDesc;
8267fe24 149 Desc.Owner = this;
b2e465d6 150 Desc.ShortDesc = ShortDesc;
8267fe24
AL
151
152 QueueURI(Desc);
0118833a
AL
153}
154 /*}}}*/
0a8a80e5 155// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 156// ---------------------------------------------------------------------
0a8a80e5
AL
157/* The only header we use is the last-modified header. */
158string pkgAcqIndex::Custom600Headers()
0118833a 159{
0a8a80e5 160 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 161 Final += URItoFileName(RealURI);
0a8a80e5
AL
162
163 struct stat Buf;
164 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 165 return "\nIndex-File: true";
0118833a 166
a72ace20 167 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
168}
169 /*}}}*/
debc84b2
MZ
170
171void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
172{
173 // no .bz2 found, retry with .gz
174 if(Desc.URI.substr(Desc.URI.size()-3,Desc.URI.size()-1) == "bz2") {
175 Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz";
176 QueueURI(Desc);
177 return;
178 }
179
180
181 Item::Failed(Message,Cnf);
182}
183
184
8b89e57f
AL
185// AcqIndex::Done - Finished a fetch /*{{{*/
186// ---------------------------------------------------------------------
187/* This goes through a number of states.. On the initial fetch the
188 method could possibly return an alternate filename which points
189 to the uncompressed version of the file. If this is so the file
190 is copied into the partial directory. In all other cases the file
191 is decompressed with a gzip uri. */
459681d3
AL
192void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
193 pkgAcquire::MethodConfig *Cfg)
8b89e57f 194{
459681d3 195 Item::Done(Message,Size,MD5,Cfg);
8b89e57f
AL
196
197 if (Decompression == true)
198 {
199 // Done, move it into position
200 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 201 FinalFile += URItoFileName(RealURI);
8b89e57f 202 Rename(DestFile,FinalFile);
7a3c2ab0 203 chmod(FinalFile.c_str(),0644);
bfd22fc0 204
7a7fa5f0
AL
205 /* We restore the original name to DestFile so that the clean operation
206 will work OK */
207 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 208 DestFile += URItoFileName(RealURI);
7a7fa5f0 209
bfd22fc0
AL
210 // Remove the compressed version.
211 if (Erase == true)
bfd22fc0 212 unlink(DestFile.c_str());
8b89e57f
AL
213 return;
214 }
bfd22fc0
AL
215
216 Erase = false;
8267fe24 217 Complete = true;
bfd22fc0 218
8b89e57f
AL
219 // Handle the unzipd case
220 string FileName = LookupTag(Message,"Alt-Filename");
221 if (FileName.empty() == false)
222 {
223 // The files timestamp matches
224 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
225 return;
226
227 Decompression = true;
a6568219 228 Local = true;
8b89e57f 229 DestFile += ".decomp";
8267fe24
AL
230 Desc.URI = "copy:" + FileName;
231 QueueURI(Desc);
b98f2859 232 Mode = "copy";
8b89e57f
AL
233 return;
234 }
235
236 FileName = LookupTag(Message,"Filename");
237 if (FileName.empty() == true)
238 {
239 Status = StatError;
240 ErrorText = "Method gave a blank filename";
241 }
242
243 // The files timestamp matches
244 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
245 return;
bfd22fc0
AL
246
247 if (FileName == DestFile)
248 Erase = true;
8267fe24 249 else
a6568219 250 Local = true;
8b89e57f 251
debc84b2
MZ
252 string compExt = Desc.URI.substr(Desc.URI.size()-3,Desc.URI.size()-1);
253 char *decompProg;
254 if(compExt == "bz2")
255 decompProg = "bzip2";
256 else if(compExt == ".gz")
257 decompProg = "gzip";
258 else {
259 _error->Error("Unsupported extension: %s", compExt.c_str());
260 return;
261 }
262
8b89e57f
AL
263 Decompression = true;
264 DestFile += ".decomp";
debc84b2 265 Desc.URI = string(decompProg) + ":" + FileName;
8267fe24 266 QueueURI(Desc);
debc84b2 267 Mode = decompProg;
8b89e57f
AL
268}
269 /*}}}*/
270
0118833a
AL
271// AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
272// ---------------------------------------------------------------------
273/* The Release file is added to the queue */
274pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
b2e465d6
AL
275 string URI,string URIDesc,string ShortDesc) :
276 Item(Owner), RealURI(URI)
0118833a 277{
0a8a80e5 278 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 279 DestFile += URItoFileName(URI);
0a8a80e5 280
8267fe24 281 // Create the item
b2e465d6
AL
282 Desc.URI = URI;
283 Desc.Description = URIDesc;
284 Desc.ShortDesc = ShortDesc;
8267fe24
AL
285 Desc.Owner = this;
286
8267fe24 287 QueueURI(Desc);
0118833a
AL
288}
289 /*}}}*/
0a8a80e5 290// AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 291// ---------------------------------------------------------------------
0a8a80e5
AL
292/* The only header we use is the last-modified header. */
293string pkgAcqIndexRel::Custom600Headers()
0118833a 294{
0a8a80e5 295 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 296 Final += URItoFileName(RealURI);
0a8a80e5
AL
297
298 struct stat Buf;
299 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 300 return "\nIndex-File: true";
0118833a 301
a72ace20 302 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
303}
304 /*}}}*/
c88edf1d
AL
305// AcqIndexRel::Done - Item downloaded OK /*{{{*/
306// ---------------------------------------------------------------------
307/* The release file was not placed into the download directory then
308 a copy URI is generated and it is copied there otherwise the file
309 in the partial directory is moved into .. and the URI is finished. */
459681d3
AL
310void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5,
311 pkgAcquire::MethodConfig *Cfg)
c88edf1d 312{
459681d3 313 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
314
315 string FileName = LookupTag(Message,"Filename");
316 if (FileName.empty() == true)
317 {
318 Status = StatError;
319 ErrorText = "Method gave a blank filename";
8b89e57f 320 return;
c88edf1d 321 }
8b89e57f 322
8267fe24
AL
323 Complete = true;
324
8b89e57f
AL
325 // The files timestamp matches
326 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
327 return;
c88edf1d
AL
328
329 // We have to copy it into place
330 if (FileName != DestFile)
331 {
a6568219 332 Local = true;
8267fe24
AL
333 Desc.URI = "copy:" + FileName;
334 QueueURI(Desc);
c88edf1d
AL
335 return;
336 }
337
338 // Done, move it into position
339 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 340 FinalFile += URItoFileName(RealURI);
8b89e57f 341 Rename(DestFile,FinalFile);
7a3c2ab0
AL
342
343 chmod(FinalFile.c_str(),0644);
c88edf1d
AL
344}
345 /*}}}*/
681d76d0
AL
346// AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
347// ---------------------------------------------------------------------
348/* */
349void pkgAcqIndexRel::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
350{
681d76d0
AL
351 if (Cnf->LocalOnly == true ||
352 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
353 {
2b154e53
AL
354 // Ignore this
355 Status = StatDone;
356 Complete = false;
681d76d0
AL
357 Dequeue();
358 return;
359 }
360
361 Item::Failed(Message,Cnf);
362}
363 /*}}}*/
03e39e59
AL
364
365// AcqArchive::AcqArchive - Constructor /*{{{*/
366// ---------------------------------------------------------------------
17caf1b1
AL
367/* This just sets up the initial fetch environment and queues the first
368 possibilitiy */
03e39e59 369pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
370 pkgRecords *Recs,pkgCache::VerIterator const &Version,
371 string &StoreFilename) :
372 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b185acc2 373 StoreFilename(StoreFilename), Vf(Version.FileList())
03e39e59 374{
7d8afa39 375 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
376
377 if (Version.Arch() == 0)
bdae53f1 378 {
d1f1f6a8 379 _error->Error(_("I wasn't able to locate a file for the %s package. "
7a3c2ab0
AL
380 "This might mean you need to manually fix this package. "
381 "(due to missing arch)"),
813c8eea 382 Version.ParentPkg().Name());
bdae53f1
AL
383 return;
384 }
813c8eea 385
b2e465d6
AL
386 /* We need to find a filename to determine the extension. We make the
387 assumption here that all the available sources for this version share
388 the same extension.. */
389 // Skip not source sources, they do not have file fields.
390 for (; Vf.end() == false; Vf++)
391 {
392 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
393 continue;
394 break;
395 }
396
397 // Does not really matter here.. we are going to fail out below
398 if (Vf.end() != true)
399 {
400 // If this fails to get a file name we will bomb out below.
401 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
402 if (_error->PendingError() == true)
403 return;
404
405 // Generate the final file name as: package_version_arch.foo
406 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
407 QuoteString(Version.VerStr(),"_:") + '_' +
408 QuoteString(Version.Arch(),"_:.") +
409 "." + flExtension(Parse.FileName());
410 }
411
03e39e59 412 // Select a source
b185acc2 413 if (QueueNext() == false && _error->PendingError() == false)
b2e465d6
AL
414 _error->Error(_("I wasn't able to locate file for the %s package. "
415 "This might mean you need to manually fix this package."),
b185acc2
AL
416 Version.ParentPkg().Name());
417}
418 /*}}}*/
419// AcqArchive::QueueNext - Queue the next file source /*{{{*/
420// ---------------------------------------------------------------------
17caf1b1
AL
421/* This queues the next available file version for download. It checks if
422 the archive is already available in the cache and stashs the MD5 for
423 checking later. */
b185acc2 424bool pkgAcqArchive::QueueNext()
b2e465d6 425{
03e39e59
AL
426 for (; Vf.end() == false; Vf++)
427 {
428 // Ignore not source sources
429 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
430 continue;
431
432 // Try to cross match against the source list
b2e465d6
AL
433 pkgIndexFile *Index;
434 if (Sources->FindIndex(Vf.File(),Index) == false)
435 continue;
03e39e59
AL
436
437 // Grab the text package record
438 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
439 if (_error->PendingError() == true)
b185acc2 440 return false;
03e39e59 441
b2e465d6 442 string PkgFile = Parse.FileName();
03e39e59
AL
443 MD5 = Parse.MD5Hash();
444 if (PkgFile.empty() == true)
b2e465d6
AL
445 return _error->Error(_("The package index files are corrupted. No Filename: "
446 "field for package %s."),
447 Version.ParentPkg().Name());
a6568219 448
17caf1b1 449 // See if we already have the file. (Legacy filenames)
a6568219
AL
450 FileSize = Version->Size;
451 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
452 struct stat Buf;
453 if (stat(FinalFile.c_str(),&Buf) == 0)
454 {
455 // Make sure the size matches
456 if ((unsigned)Buf.st_size == Version->Size)
457 {
458 Complete = true;
459 Local = true;
460 Status = StatDone;
30e1eab5 461 StoreFilename = DestFile = FinalFile;
b185acc2 462 return true;
a6568219
AL
463 }
464
6b1ff003
AL
465 /* Hmm, we have a file and its size does not match, this means it is
466 an old style mismatched arch */
a6568219
AL
467 unlink(FinalFile.c_str());
468 }
17caf1b1
AL
469
470 // Check it again using the new style output filenames
471 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
472 if (stat(FinalFile.c_str(),&Buf) == 0)
473 {
474 // Make sure the size matches
475 if ((unsigned)Buf.st_size == Version->Size)
476 {
477 Complete = true;
478 Local = true;
479 Status = StatDone;
480 StoreFilename = DestFile = FinalFile;
481 return true;
482 }
483
484 /* Hmm, we have a file and its size does not match, this shouldnt
485 happen.. */
486 unlink(FinalFile.c_str());
487 }
488
489 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
490
491 // Check the destination file
492 if (stat(DestFile.c_str(),&Buf) == 0)
493 {
494 // Hmm, the partial file is too big, erase it
495 if ((unsigned)Buf.st_size > Version->Size)
496 unlink(DestFile.c_str());
497 else
498 PartialSize = Buf.st_size;
499 }
500
03e39e59 501 // Create the item
b2e465d6
AL
502 Local = false;
503 Desc.URI = Index->ArchiveURI(PkgFile);
504 Desc.Description = Index->ArchiveInfo(Version);
03e39e59
AL
505 Desc.Owner = this;
506 Desc.ShortDesc = Version.ParentPkg().Name();
507 QueueURI(Desc);
b185acc2
AL
508
509 Vf++;
510 return true;
03e39e59 511 }
b185acc2
AL
512 return false;
513}
03e39e59
AL
514 /*}}}*/
515// AcqArchive::Done - Finished fetching /*{{{*/
516// ---------------------------------------------------------------------
517/* */
459681d3
AL
518void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
519 pkgAcquire::MethodConfig *Cfg)
03e39e59 520{
459681d3 521 Item::Done(Message,Size,Md5Hash,Cfg);
03e39e59
AL
522
523 // Check the size
524 if (Size != Version->Size)
525 {
bdae53f1 526 Status = StatError;
b2e465d6 527 ErrorText = _("Size mismatch");
03e39e59
AL
528 return;
529 }
530
531 // Check the md5
532 if (Md5Hash.empty() == false && MD5.empty() == false)
533 {
534 if (Md5Hash != MD5)
535 {
bdae53f1 536 Status = StatError;
b2e465d6 537 ErrorText = _("MD5Sum mismatch");
9978c7b0 538 Rename(DestFile,DestFile + ".FAILED");
03e39e59
AL
539 return;
540 }
541 }
a6568219
AL
542
543 // Grab the output filename
03e39e59
AL
544 string FileName = LookupTag(Message,"Filename");
545 if (FileName.empty() == true)
546 {
547 Status = StatError;
548 ErrorText = "Method gave a blank filename";
549 return;
550 }
a6568219
AL
551
552 Complete = true;
30e1eab5
AL
553
554 // Reference filename
a6568219
AL
555 if (FileName != DestFile)
556 {
30e1eab5 557 StoreFilename = DestFile = FileName;
a6568219
AL
558 Local = true;
559 return;
560 }
561
562 // Done, move it into position
563 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 564 FinalFile += flNotDir(StoreFilename);
a6568219 565 Rename(DestFile,FinalFile);
03e39e59 566
30e1eab5 567 StoreFilename = DestFile = FinalFile;
03e39e59
AL
568 Complete = true;
569}
570 /*}}}*/
db890fdb
AL
571// AcqArchive::Failed - Failure handler /*{{{*/
572// ---------------------------------------------------------------------
573/* Here we try other sources */
7d8afa39 574void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
575{
576 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
577
578 /* We don't really want to retry on failed media swaps, this prevents
579 that. An interesting observation is that permanent failures are not
580 recorded. */
581 if (Cnf->Removable == true &&
582 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
583 {
584 // Vf = Version.FileList();
585 while (Vf.end() == false) Vf++;
586 StoreFilename = string();
587 Item::Failed(Message,Cnf);
588 return;
589 }
590
db890fdb 591 if (QueueNext() == false)
7d8afa39
AL
592 {
593 // This is the retry counter
594 if (Retries != 0 &&
595 Cnf->LocalOnly == false &&
596 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
597 {
598 Retries--;
599 Vf = Version.FileList();
600 if (QueueNext() == true)
601 return;
602 }
603
9dbb421f 604 StoreFilename = string();
7d8afa39
AL
605 Item::Failed(Message,Cnf);
606 }
db890fdb
AL
607}
608 /*}}}*/
ab559b35
AL
609// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
610// ---------------------------------------------------------------------
611/* */
612void pkgAcqArchive::Finished()
613{
614 if (Status == pkgAcquire::Item::StatDone &&
615 Complete == true)
616 return;
617 StoreFilename = string();
618}
619 /*}}}*/
36375005
AL
620
621// AcqFile::pkgAcqFile - Constructor /*{{{*/
622// ---------------------------------------------------------------------
623/* The file is added to the queue */
624pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
625 unsigned long Size,string Dsc,string ShortDesc) :
b3c39978 626 Item(Owner), Md5Hash(MD5)
36375005 627{
08cfc005
AL
628 Retries = _config->FindI("Acquire::Retries",0);
629
36375005
AL
630 DestFile = flNotDir(URI);
631
632 // Create the item
633 Desc.URI = URI;
634 Desc.Description = Dsc;
635 Desc.Owner = this;
636
637 // Set the short description to the archive component
638 Desc.ShortDesc = ShortDesc;
639
640 // Get the transfer sizes
641 FileSize = Size;
642 struct stat Buf;
643 if (stat(DestFile.c_str(),&Buf) == 0)
644 {
645 // Hmm, the partial file is too big, erase it
646 if ((unsigned)Buf.st_size > Size)
647 unlink(DestFile.c_str());
648 else
649 PartialSize = Buf.st_size;
650 }
651
652 QueueURI(Desc);
653}
654 /*}}}*/
655// AcqFile::Done - Item downloaded OK /*{{{*/
656// ---------------------------------------------------------------------
657/* */
459681d3
AL
658void pkgAcqFile::Done(string Message,unsigned long Size,string MD5,
659 pkgAcquire::MethodConfig *Cnf)
36375005 660{
b3c39978
AL
661 // Check the md5
662 if (Md5Hash.empty() == false && MD5.empty() == false)
663 {
664 if (Md5Hash != MD5)
665 {
666 Status = StatError;
667 ErrorText = "MD5Sum mismatch";
668 Rename(DestFile,DestFile + ".FAILED");
669 return;
670 }
671 }
672
459681d3 673 Item::Done(Message,Size,MD5,Cnf);
36375005
AL
674
675 string FileName = LookupTag(Message,"Filename");
676 if (FileName.empty() == true)
677 {
678 Status = StatError;
679 ErrorText = "Method gave a blank filename";
680 return;
681 }
682
683 Complete = true;
684
685 // The files timestamp matches
686 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
687 return;
688
689 // We have to copy it into place
690 if (FileName != DestFile)
691 {
692 Local = true;
459681d3
AL
693 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
694 Cnf->Removable == true)
917ae805
AL
695 {
696 Desc.URI = "copy:" + FileName;
697 QueueURI(Desc);
698 return;
699 }
700
83ab33fc
AL
701 // Erase the file if it is a symlink so we can overwrite it
702 struct stat St;
703 if (lstat(DestFile.c_str(),&St) == 0)
704 {
705 if (S_ISLNK(St.st_mode) != 0)
706 unlink(DestFile.c_str());
707 }
708
709 // Symlink the file
917ae805
AL
710 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
711 {
83ab33fc 712 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
713 Status = StatError;
714 Complete = false;
715 }
36375005
AL
716 }
717}
718 /*}}}*/
08cfc005
AL
719// AcqFile::Failed - Failure handler /*{{{*/
720// ---------------------------------------------------------------------
721/* Here we try other sources */
722void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
723{
724 ErrorText = LookupTag(Message,"Message");
725
726 // This is the retry counter
727 if (Retries != 0 &&
728 Cnf->LocalOnly == false &&
729 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
730 {
731 Retries--;
732 QueueURI(Desc);
733 return;
734 }
735
736 Item::Failed(Message,Cnf);
737}
738 /*}}}*/