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