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