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