]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
Fixed remove iteration
[apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
5819a761 3// $Id: acquire-item.cc,v 1.44 2001/05/07 05:49:43 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];
b2e465d6 124 sprintf(S,_("rename failed, %s (%s -> %s)."),strerror(errno),
8b89e57f
AL
125 From.c_str(),To.c_str());
126 Status = StatError;
127 ErrorText = S;
128 }
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
b2e465d6
AL
147 Desc.URI = URI + ".gz";
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 /*}}}*/
8b89e57f
AL
170// AcqIndex::Done - Finished a fetch /*{{{*/
171// ---------------------------------------------------------------------
172/* This goes through a number of states.. On the initial fetch the
173 method could possibly return an alternate filename which points
174 to the uncompressed version of the file. If this is so the file
175 is copied into the partial directory. In all other cases the file
176 is decompressed with a gzip uri. */
459681d3
AL
177void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5,
178 pkgAcquire::MethodConfig *Cfg)
8b89e57f 179{
459681d3 180 Item::Done(Message,Size,MD5,Cfg);
8b89e57f
AL
181
182 if (Decompression == true)
183 {
184 // Done, move it into position
185 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 186 FinalFile += URItoFileName(RealURI);
8b89e57f 187 Rename(DestFile,FinalFile);
bfd22fc0 188
7a7fa5f0
AL
189 /* We restore the original name to DestFile so that the clean operation
190 will work OK */
191 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 192 DestFile += URItoFileName(RealURI);
7a7fa5f0 193
bfd22fc0
AL
194 // Remove the compressed version.
195 if (Erase == true)
bfd22fc0 196 unlink(DestFile.c_str());
8b89e57f
AL
197 return;
198 }
bfd22fc0
AL
199
200 Erase = false;
8267fe24 201 Complete = true;
bfd22fc0 202
8b89e57f
AL
203 // Handle the unzipd case
204 string FileName = LookupTag(Message,"Alt-Filename");
205 if (FileName.empty() == false)
206 {
207 // The files timestamp matches
208 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
209 return;
210
211 Decompression = true;
a6568219 212 Local = true;
8b89e57f 213 DestFile += ".decomp";
8267fe24
AL
214 Desc.URI = "copy:" + FileName;
215 QueueURI(Desc);
b98f2859 216 Mode = "copy";
8b89e57f
AL
217 return;
218 }
219
220 FileName = LookupTag(Message,"Filename");
221 if (FileName.empty() == true)
222 {
223 Status = StatError;
224 ErrorText = "Method gave a blank filename";
225 }
226
227 // The files timestamp matches
228 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
229 return;
bfd22fc0
AL
230
231 if (FileName == DestFile)
232 Erase = true;
8267fe24 233 else
a6568219 234 Local = true;
8b89e57f
AL
235
236 Decompression = true;
237 DestFile += ".decomp";
b2e465d6 238 Desc.URI = "gzip:" + FileName;
8267fe24 239 QueueURI(Desc);
b98f2859 240 Mode = "gzip";
8b89e57f
AL
241}
242 /*}}}*/
243
0118833a
AL
244// AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
245// ---------------------------------------------------------------------
246/* The Release file is added to the queue */
247pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
b2e465d6
AL
248 string URI,string URIDesc,string ShortDesc) :
249 Item(Owner), RealURI(URI)
0118833a 250{
0a8a80e5 251 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
b2e465d6 252 DestFile += URItoFileName(URI);
0a8a80e5 253
8267fe24 254 // Create the item
b2e465d6
AL
255 Desc.URI = URI;
256 Desc.Description = URIDesc;
257 Desc.ShortDesc = ShortDesc;
8267fe24
AL
258 Desc.Owner = this;
259
8267fe24 260 QueueURI(Desc);
0118833a
AL
261}
262 /*}}}*/
0a8a80e5 263// AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 264// ---------------------------------------------------------------------
0a8a80e5
AL
265/* The only header we use is the last-modified header. */
266string pkgAcqIndexRel::Custom600Headers()
0118833a 267{
0a8a80e5 268 string Final = _config->FindDir("Dir::State::lists");
b2e465d6 269 Final += URItoFileName(RealURI);
0a8a80e5
AL
270
271 struct stat Buf;
272 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 273 return "\nIndex-File: true";
0118833a 274
a72ace20 275 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
276}
277 /*}}}*/
c88edf1d
AL
278// AcqIndexRel::Done - Item downloaded OK /*{{{*/
279// ---------------------------------------------------------------------
280/* The release file was not placed into the download directory then
281 a copy URI is generated and it is copied there otherwise the file
282 in the partial directory is moved into .. and the URI is finished. */
459681d3
AL
283void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5,
284 pkgAcquire::MethodConfig *Cfg)
c88edf1d 285{
459681d3 286 Item::Done(Message,Size,MD5,Cfg);
c88edf1d
AL
287
288 string FileName = LookupTag(Message,"Filename");
289 if (FileName.empty() == true)
290 {
291 Status = StatError;
292 ErrorText = "Method gave a blank filename";
8b89e57f 293 return;
c88edf1d 294 }
8b89e57f 295
8267fe24
AL
296 Complete = true;
297
8b89e57f
AL
298 // The files timestamp matches
299 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
300 return;
c88edf1d
AL
301
302 // We have to copy it into place
303 if (FileName != DestFile)
304 {
a6568219 305 Local = true;
8267fe24
AL
306 Desc.URI = "copy:" + FileName;
307 QueueURI(Desc);
c88edf1d
AL
308 return;
309 }
310
311 // Done, move it into position
312 string FinalFile = _config->FindDir("Dir::State::lists");
b2e465d6 313 FinalFile += URItoFileName(RealURI);
8b89e57f 314 Rename(DestFile,FinalFile);
c88edf1d
AL
315}
316 /*}}}*/
681d76d0
AL
317// AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
318// ---------------------------------------------------------------------
319/* */
320void pkgAcqIndexRel::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
321{
681d76d0
AL
322 if (Cnf->LocalOnly == true ||
323 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
324 {
2b154e53
AL
325 // Ignore this
326 Status = StatDone;
327 Complete = false;
681d76d0
AL
328 Dequeue();
329 return;
330 }
331
332 Item::Failed(Message,Cnf);
333}
334 /*}}}*/
03e39e59
AL
335
336// AcqArchive::AcqArchive - Constructor /*{{{*/
337// ---------------------------------------------------------------------
17caf1b1
AL
338/* This just sets up the initial fetch environment and queues the first
339 possibilitiy */
03e39e59 340pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
341 pkgRecords *Recs,pkgCache::VerIterator const &Version,
342 string &StoreFilename) :
343 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b185acc2 344 StoreFilename(StoreFilename), Vf(Version.FileList())
03e39e59 345{
7d8afa39 346 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
347
348 if (Version.Arch() == 0)
bdae53f1 349 {
d1f1f6a8 350 _error->Error(_("I wasn't able to locate a file for the %s package. "
b2e465d6 351 "This might mean you need to manually fix this package. (due to missing arch)"),
813c8eea 352 Version.ParentPkg().Name());
bdae53f1
AL
353 return;
354 }
813c8eea 355
b2e465d6
AL
356 /* We need to find a filename to determine the extension. We make the
357 assumption here that all the available sources for this version share
358 the same extension.. */
359 // Skip not source sources, they do not have file fields.
360 for (; Vf.end() == false; Vf++)
361 {
362 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
363 continue;
364 break;
365 }
366
367 // Does not really matter here.. we are going to fail out below
368 if (Vf.end() != true)
369 {
370 // If this fails to get a file name we will bomb out below.
371 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
372 if (_error->PendingError() == true)
373 return;
374
375 // Generate the final file name as: package_version_arch.foo
376 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
377 QuoteString(Version.VerStr(),"_:") + '_' +
378 QuoteString(Version.Arch(),"_:.") +
379 "." + flExtension(Parse.FileName());
380 }
381
03e39e59 382 // Select a source
b185acc2 383 if (QueueNext() == false && _error->PendingError() == false)
b2e465d6
AL
384 _error->Error(_("I wasn't able to locate file for the %s package. "
385 "This might mean you need to manually fix this package."),
b185acc2
AL
386 Version.ParentPkg().Name());
387}
388 /*}}}*/
389// AcqArchive::QueueNext - Queue the next file source /*{{{*/
390// ---------------------------------------------------------------------
17caf1b1
AL
391/* This queues the next available file version for download. It checks if
392 the archive is already available in the cache and stashs the MD5 for
393 checking later. */
b185acc2 394bool pkgAcqArchive::QueueNext()
b2e465d6 395{
03e39e59
AL
396 for (; Vf.end() == false; Vf++)
397 {
398 // Ignore not source sources
399 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
400 continue;
401
402 // Try to cross match against the source list
b2e465d6
AL
403 pkgIndexFile *Index;
404 if (Sources->FindIndex(Vf.File(),Index) == false)
405 continue;
03e39e59
AL
406
407 // Grab the text package record
408 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
409 if (_error->PendingError() == true)
b185acc2 410 return false;
03e39e59 411
b2e465d6 412 string PkgFile = Parse.FileName();
03e39e59
AL
413 MD5 = Parse.MD5Hash();
414 if (PkgFile.empty() == true)
b2e465d6
AL
415 return _error->Error(_("The package index files are corrupted. No Filename: "
416 "field for package %s."),
417 Version.ParentPkg().Name());
a6568219 418
17caf1b1 419 // See if we already have the file. (Legacy filenames)
a6568219
AL
420 FileSize = Version->Size;
421 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
422 struct stat Buf;
423 if (stat(FinalFile.c_str(),&Buf) == 0)
424 {
425 // Make sure the size matches
426 if ((unsigned)Buf.st_size == Version->Size)
427 {
428 Complete = true;
429 Local = true;
430 Status = StatDone;
30e1eab5 431 StoreFilename = DestFile = FinalFile;
b185acc2 432 return true;
a6568219
AL
433 }
434
6b1ff003
AL
435 /* Hmm, we have a file and its size does not match, this means it is
436 an old style mismatched arch */
a6568219
AL
437 unlink(FinalFile.c_str());
438 }
17caf1b1
AL
439
440 // Check it again using the new style output filenames
441 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
442 if (stat(FinalFile.c_str(),&Buf) == 0)
443 {
444 // Make sure the size matches
445 if ((unsigned)Buf.st_size == Version->Size)
446 {
447 Complete = true;
448 Local = true;
449 Status = StatDone;
450 StoreFilename = DestFile = FinalFile;
451 return true;
452 }
453
454 /* Hmm, we have a file and its size does not match, this shouldnt
455 happen.. */
456 unlink(FinalFile.c_str());
457 }
458
459 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
460
461 // Check the destination file
462 if (stat(DestFile.c_str(),&Buf) == 0)
463 {
464 // Hmm, the partial file is too big, erase it
465 if ((unsigned)Buf.st_size > Version->Size)
466 unlink(DestFile.c_str());
467 else
468 PartialSize = Buf.st_size;
469 }
470
03e39e59 471 // Create the item
b2e465d6
AL
472 Local = false;
473 Desc.URI = Index->ArchiveURI(PkgFile);
474 Desc.Description = Index->ArchiveInfo(Version);
03e39e59
AL
475 Desc.Owner = this;
476 Desc.ShortDesc = Version.ParentPkg().Name();
477 QueueURI(Desc);
b185acc2
AL
478
479 Vf++;
480 return true;
03e39e59 481 }
b185acc2
AL
482 return false;
483}
03e39e59
AL
484 /*}}}*/
485// AcqArchive::Done - Finished fetching /*{{{*/
486// ---------------------------------------------------------------------
487/* */
459681d3
AL
488void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash,
489 pkgAcquire::MethodConfig *Cfg)
03e39e59 490{
459681d3 491 Item::Done(Message,Size,Md5Hash,Cfg);
03e39e59
AL
492
493 // Check the size
494 if (Size != Version->Size)
495 {
bdae53f1 496 Status = StatError;
b2e465d6 497 ErrorText = _("Size mismatch");
03e39e59
AL
498 return;
499 }
500
501 // Check the md5
502 if (Md5Hash.empty() == false && MD5.empty() == false)
503 {
504 if (Md5Hash != MD5)
505 {
bdae53f1 506 Status = StatError;
b2e465d6 507 ErrorText = _("MD5Sum mismatch");
9978c7b0 508 Rename(DestFile,DestFile + ".FAILED");
03e39e59
AL
509 return;
510 }
511 }
a6568219
AL
512
513 // Grab the output filename
03e39e59
AL
514 string FileName = LookupTag(Message,"Filename");
515 if (FileName.empty() == true)
516 {
517 Status = StatError;
518 ErrorText = "Method gave a blank filename";
519 return;
520 }
a6568219
AL
521
522 Complete = true;
30e1eab5
AL
523
524 // Reference filename
a6568219
AL
525 if (FileName != DestFile)
526 {
30e1eab5 527 StoreFilename = DestFile = FileName;
a6568219
AL
528 Local = true;
529 return;
530 }
531
532 // Done, move it into position
533 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 534 FinalFile += flNotDir(StoreFilename);
a6568219 535 Rename(DestFile,FinalFile);
03e39e59 536
30e1eab5 537 StoreFilename = DestFile = FinalFile;
03e39e59
AL
538 Complete = true;
539}
540 /*}}}*/
db890fdb
AL
541// AcqArchive::Failed - Failure handler /*{{{*/
542// ---------------------------------------------------------------------
543/* Here we try other sources */
7d8afa39 544void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
545{
546 ErrorText = LookupTag(Message,"Message");
b2e465d6
AL
547
548 /* We don't really want to retry on failed media swaps, this prevents
549 that. An interesting observation is that permanent failures are not
550 recorded. */
551 if (Cnf->Removable == true &&
552 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
553 {
554 // Vf = Version.FileList();
555 while (Vf.end() == false) Vf++;
556 StoreFilename = string();
557 Item::Failed(Message,Cnf);
558 return;
559 }
560
db890fdb 561 if (QueueNext() == false)
7d8afa39
AL
562 {
563 // This is the retry counter
564 if (Retries != 0 &&
565 Cnf->LocalOnly == false &&
566 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
567 {
568 Retries--;
569 Vf = Version.FileList();
570 if (QueueNext() == true)
571 return;
572 }
573
9dbb421f 574 StoreFilename = string();
7d8afa39
AL
575 Item::Failed(Message,Cnf);
576 }
db890fdb
AL
577}
578 /*}}}*/
ab559b35
AL
579// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
580// ---------------------------------------------------------------------
581/* */
582void pkgAcqArchive::Finished()
583{
584 if (Status == pkgAcquire::Item::StatDone &&
585 Complete == true)
586 return;
587 StoreFilename = string();
588}
589 /*}}}*/
36375005
AL
590
591// AcqFile::pkgAcqFile - Constructor /*{{{*/
592// ---------------------------------------------------------------------
593/* The file is added to the queue */
594pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
595 unsigned long Size,string Dsc,string ShortDesc) :
b3c39978 596 Item(Owner), Md5Hash(MD5)
36375005 597{
08cfc005
AL
598 Retries = _config->FindI("Acquire::Retries",0);
599
36375005
AL
600 DestFile = flNotDir(URI);
601
602 // Create the item
603 Desc.URI = URI;
604 Desc.Description = Dsc;
605 Desc.Owner = this;
606
607 // Set the short description to the archive component
608 Desc.ShortDesc = ShortDesc;
609
610 // Get the transfer sizes
611 FileSize = Size;
612 struct stat Buf;
613 if (stat(DestFile.c_str(),&Buf) == 0)
614 {
615 // Hmm, the partial file is too big, erase it
616 if ((unsigned)Buf.st_size > Size)
617 unlink(DestFile.c_str());
618 else
619 PartialSize = Buf.st_size;
620 }
621
622 QueueURI(Desc);
623}
624 /*}}}*/
625// AcqFile::Done - Item downloaded OK /*{{{*/
626// ---------------------------------------------------------------------
627/* */
459681d3
AL
628void pkgAcqFile::Done(string Message,unsigned long Size,string MD5,
629 pkgAcquire::MethodConfig *Cnf)
36375005 630{
b3c39978
AL
631 // Check the md5
632 if (Md5Hash.empty() == false && MD5.empty() == false)
633 {
634 if (Md5Hash != MD5)
635 {
636 Status = StatError;
637 ErrorText = "MD5Sum mismatch";
638 Rename(DestFile,DestFile + ".FAILED");
639 return;
640 }
641 }
642
459681d3 643 Item::Done(Message,Size,MD5,Cnf);
36375005
AL
644
645 string FileName = LookupTag(Message,"Filename");
646 if (FileName.empty() == true)
647 {
648 Status = StatError;
649 ErrorText = "Method gave a blank filename";
650 return;
651 }
652
653 Complete = true;
654
655 // The files timestamp matches
656 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
657 return;
658
659 // We have to copy it into place
660 if (FileName != DestFile)
661 {
662 Local = true;
459681d3
AL
663 if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
664 Cnf->Removable == true)
917ae805
AL
665 {
666 Desc.URI = "copy:" + FileName;
667 QueueURI(Desc);
668 return;
669 }
670
83ab33fc
AL
671 // Erase the file if it is a symlink so we can overwrite it
672 struct stat St;
673 if (lstat(DestFile.c_str(),&St) == 0)
674 {
675 if (S_ISLNK(St.st_mode) != 0)
676 unlink(DestFile.c_str());
677 }
678
679 // Symlink the file
917ae805
AL
680 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
681 {
83ab33fc 682 ErrorText = "Link to " + DestFile + " failure ";
917ae805
AL
683 Status = StatError;
684 Complete = false;
685 }
36375005
AL
686 }
687}
688 /*}}}*/
08cfc005
AL
689// AcqFile::Failed - Failure handler /*{{{*/
690// ---------------------------------------------------------------------
691/* Here we try other sources */
692void pkgAcqFile::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
693{
694 ErrorText = LookupTag(Message,"Message");
695
696 // This is the retry counter
697 if (Retries != 0 &&
698 Cnf->LocalOnly == false &&
699 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
700 {
701 Retries--;
702 QueueURI(Desc);
703 return;
704 }
705
706 Item::Failed(Message,Cnf);
707}
708 /*}}}*/