Restored my pretty comment
[ntk/apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
54cf15cb 3// $Id: acquire-item.cc,v 1.38 1999/10/17 07:30:23 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/* */
b98f2859 91void pkgAcquire::Item::Done(string Message,unsigned long Size,string)
c88edf1d 92{
b98f2859
AL
93 // We just downloaded something..
94 string FileName = LookupTag(Message,"Filename");
95 if (Complete == false && FileName == DestFile)
96 {
97 if (Owner->Log != 0)
98 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
99 }
aa0e1101
AL
100
101 if (FileSize == 0)
102 FileSize= Size;
b98f2859 103
c88edf1d
AL
104 Status = StatDone;
105 ErrorText = string();
106 Owner->Dequeue(this);
107}
108 /*}}}*/
8b89e57f
AL
109// Acquire::Item::Rename - Rename a file /*{{{*/
110// ---------------------------------------------------------------------
111/* This helper function is used by alot of item methods as thier final
112 step */
113void pkgAcquire::Item::Rename(string From,string To)
114{
115 if (rename(From.c_str(),To.c_str()) != 0)
116 {
117 char S[300];
118 sprintf(S,"rename failed, %s (%s -> %s).",strerror(errno),
119 From.c_str(),To.c_str());
120 Status = StatError;
121 ErrorText = S;
122 }
123}
124 /*}}}*/
0118833a
AL
125
126// AcqIndex::AcqIndex - Constructor /*{{{*/
127// ---------------------------------------------------------------------
128/* The package file is added to the queue and a second class is
129 instantiated to fetch the revision file */
130pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location) :
131 Item(Owner), Location(Location)
132{
8b89e57f 133 Decompression = false;
bfd22fc0 134 Erase = false;
8b89e57f 135
0a8a80e5
AL
136 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
137 DestFile += URItoFileName(Location->PackagesURI());
8267fe24 138
54cf15cb 139 // Create the item
8267fe24
AL
140 Desc.URI = Location->PackagesURI() + ".gz";
141 Desc.Description = Location->PackagesInfo();
142 Desc.Owner = this;
143
144 // Set the short description to the archive component
145 if (Location->Dist[Location->Dist.size() - 1] == '/')
146 Desc.ShortDesc = Location->Dist;
147 else
148 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
149
150 QueueURI(Desc);
0118833a 151
0a8a80e5 152 // Create the Release fetch class
0118833a
AL
153 new pkgAcqIndexRel(Owner,Location);
154}
155 /*}}}*/
0a8a80e5 156// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 157// ---------------------------------------------------------------------
0a8a80e5
AL
158/* The only header we use is the last-modified header. */
159string pkgAcqIndex::Custom600Headers()
0118833a 160{
0a8a80e5
AL
161 string Final = _config->FindDir("Dir::State::lists");
162 Final += URItoFileName(Location->PackagesURI());
163
164 struct stat Buf;
165 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 166 return "\nIndex-File: true";
0118833a 167
a72ace20 168 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
169}
170 /*}}}*/
8b89e57f
AL
171// AcqIndex::Done - Finished a fetch /*{{{*/
172// ---------------------------------------------------------------------
173/* This goes through a number of states.. On the initial fetch the
174 method could possibly return an alternate filename which points
175 to the uncompressed version of the file. If this is so the file
176 is copied into the partial directory. In all other cases the file
177 is decompressed with a gzip uri. */
178void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5)
179{
180 Item::Done(Message,Size,MD5);
181
182 if (Decompression == true)
183 {
184 // Done, move it into position
185 string FinalFile = _config->FindDir("Dir::State::lists");
186 FinalFile += URItoFileName(Location->PackagesURI());
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/";
192 DestFile += URItoFileName(Location->PackagesURI());
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";
8267fe24
AL
238 Desc.URI = "gzip:" + FileName,Location->PackagesInfo();
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,
248 const pkgSourceList::Item *Location) :
249 Item(Owner), Location(Location)
250{
0a8a80e5
AL
251 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
252 DestFile += URItoFileName(Location->ReleaseURI());
253
8267fe24
AL
254 // Create the item
255 Desc.URI = Location->ReleaseURI();
256 Desc.Description = Location->ReleaseInfo();
257 Desc.Owner = this;
258
259 // Set the short description to the archive component
260 if (Location->Dist[Location->Dist.size() - 1] == '/')
261 Desc.ShortDesc = Location->Dist;
262 else
263 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
264
265 QueueURI(Desc);
0118833a
AL
266}
267 /*}}}*/
0a8a80e5 268// AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 269// ---------------------------------------------------------------------
0a8a80e5
AL
270/* The only header we use is the last-modified header. */
271string pkgAcqIndexRel::Custom600Headers()
0118833a 272{
0a8a80e5
AL
273 string Final = _config->FindDir("Dir::State::lists");
274 Final += URItoFileName(Location->ReleaseURI());
275
276 struct stat Buf;
277 if (stat(Final.c_str(),&Buf) != 0)
a72ace20 278 return "\nIndex-File: true";
0118833a 279
a72ace20 280 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
281}
282 /*}}}*/
c88edf1d
AL
283// AcqIndexRel::Done - Item downloaded OK /*{{{*/
284// ---------------------------------------------------------------------
285/* The release file was not placed into the download directory then
286 a copy URI is generated and it is copied there otherwise the file
287 in the partial directory is moved into .. and the URI is finished. */
288void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5)
289{
290 Item::Done(Message,Size,MD5);
291
292 string FileName = LookupTag(Message,"Filename");
293 if (FileName.empty() == true)
294 {
295 Status = StatError;
296 ErrorText = "Method gave a blank filename";
8b89e57f 297 return;
c88edf1d 298 }
8b89e57f 299
8267fe24
AL
300 Complete = true;
301
8b89e57f
AL
302 // The files timestamp matches
303 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
304 return;
c88edf1d
AL
305
306 // We have to copy it into place
307 if (FileName != DestFile)
308 {
a6568219 309 Local = true;
8267fe24
AL
310 Desc.URI = "copy:" + FileName;
311 QueueURI(Desc);
c88edf1d
AL
312 return;
313 }
314
315 // Done, move it into position
316 string FinalFile = _config->FindDir("Dir::State::lists");
317 FinalFile += URItoFileName(Location->ReleaseURI());
8b89e57f 318 Rename(DestFile,FinalFile);
c88edf1d
AL
319}
320 /*}}}*/
681d76d0
AL
321// AcqIndexRel::Failed - Silence failure messages for missing rel files /*{{{*/
322// ---------------------------------------------------------------------
323/* */
324void pkgAcqIndexRel::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
325{
681d76d0
AL
326 if (Cnf->LocalOnly == true ||
327 StringToBool(LookupTag(Message,"Transient-Failure"),false) == false)
328 {
2b154e53
AL
329 // Ignore this
330 Status = StatDone;
331 Complete = false;
681d76d0
AL
332 Dequeue();
333 return;
334 }
335
336 Item::Failed(Message,Cnf);
337}
338 /*}}}*/
03e39e59
AL
339
340// AcqArchive::AcqArchive - Constructor /*{{{*/
341// ---------------------------------------------------------------------
17caf1b1
AL
342/* This just sets up the initial fetch environment and queues the first
343 possibilitiy */
03e39e59 344pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
345 pkgRecords *Recs,pkgCache::VerIterator const &Version,
346 string &StoreFilename) :
347 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
b185acc2 348 StoreFilename(StoreFilename), Vf(Version.FileList())
03e39e59 349{
7d8afa39 350 Retries = _config->FindI("Acquire::Retries",0);
813c8eea
AL
351
352 if (Version.Arch() == 0)
bdae53f1 353 {
813c8eea
AL
354 _error->Error("I wasn't able to locate file for the %s package. "
355 "This might mean you need to manually fix this package. (due to missing arch)",
356 Version.ParentPkg().Name());
bdae53f1
AL
357 return;
358 }
813c8eea 359
17caf1b1
AL
360 // Generate the final file name as: package_version_arch.deb
361 StoreFilename = QuoteString(Version.ParentPkg().Name(),"_:") + '_' +
362 QuoteString(Version.VerStr(),"_:") + '_' +
1bc849af 363 QuoteString(Version.Arch(),"_:.") + ".deb";
bdae53f1 364
03e39e59 365 // Select a source
b185acc2
AL
366 if (QueueNext() == false && _error->PendingError() == false)
367 _error->Error("I wasn't able to locate file for the %s package. "
368 "This might mean you need to manually fix this package.",
369 Version.ParentPkg().Name());
370}
371 /*}}}*/
372// AcqArchive::QueueNext - Queue the next file source /*{{{*/
373// ---------------------------------------------------------------------
17caf1b1
AL
374/* This queues the next available file version for download. It checks if
375 the archive is already available in the cache and stashs the MD5 for
376 checking later. */
b185acc2
AL
377bool pkgAcqArchive::QueueNext()
378{
03e39e59
AL
379 for (; Vf.end() == false; Vf++)
380 {
381 // Ignore not source sources
382 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
383 continue;
384
385 // Try to cross match against the source list
386 string PkgFile = flNotDir(Vf.File().FileName());
387 pkgSourceList::const_iterator Location;
388 for (Location = Sources->begin(); Location != Sources->end(); Location++)
389 if (PkgFile == URItoFileName(Location->PackagesURI()))
390 break;
391
392 if (Location == Sources->end())
393 continue;
394
395 // Grab the text package record
396 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
397 if (_error->PendingError() == true)
b185acc2 398 return false;
03e39e59
AL
399
400 PkgFile = Parse.FileName();
401 MD5 = Parse.MD5Hash();
402 if (PkgFile.empty() == true)
b185acc2
AL
403 return _error->Error("The package index files are corrupted. No Filename: "
404 "field for package %s."
405 ,Version.ParentPkg().Name());
a6568219 406
17caf1b1 407 // See if we already have the file. (Legacy filenames)
a6568219
AL
408 FileSize = Version->Size;
409 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
410 struct stat Buf;
411 if (stat(FinalFile.c_str(),&Buf) == 0)
412 {
413 // Make sure the size matches
414 if ((unsigned)Buf.st_size == Version->Size)
415 {
416 Complete = true;
417 Local = true;
418 Status = StatDone;
30e1eab5 419 StoreFilename = DestFile = FinalFile;
b185acc2 420 return true;
a6568219
AL
421 }
422
6b1ff003
AL
423 /* Hmm, we have a file and its size does not match, this means it is
424 an old style mismatched arch */
a6568219
AL
425 unlink(FinalFile.c_str());
426 }
17caf1b1
AL
427
428 // Check it again using the new style output filenames
429 FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename);
430 if (stat(FinalFile.c_str(),&Buf) == 0)
431 {
432 // Make sure the size matches
433 if ((unsigned)Buf.st_size == Version->Size)
434 {
435 Complete = true;
436 Local = true;
437 Status = StatDone;
438 StoreFilename = DestFile = FinalFile;
439 return true;
440 }
441
442 /* Hmm, we have a file and its size does not match, this shouldnt
443 happen.. */
444 unlink(FinalFile.c_str());
445 }
446
447 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
6b1ff003
AL
448
449 // Check the destination file
450 if (stat(DestFile.c_str(),&Buf) == 0)
451 {
452 // Hmm, the partial file is too big, erase it
453 if ((unsigned)Buf.st_size > Version->Size)
454 unlink(DestFile.c_str());
455 else
456 PartialSize = Buf.st_size;
457 }
458
03e39e59
AL
459 // Create the item
460 Desc.URI = Location->ArchiveURI(PkgFile);
461 Desc.Description = Location->ArchiveInfo(Version);
462 Desc.Owner = this;
463 Desc.ShortDesc = Version.ParentPkg().Name();
464 QueueURI(Desc);
b185acc2
AL
465
466 Vf++;
467 return true;
03e39e59 468 }
b185acc2
AL
469 return false;
470}
03e39e59
AL
471 /*}}}*/
472// AcqArchive::Done - Finished fetching /*{{{*/
473// ---------------------------------------------------------------------
474/* */
475void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash)
476{
fd9bd3dc 477 Item::Done(Message,Size,Md5Hash);
03e39e59
AL
478
479 // Check the size
480 if (Size != Version->Size)
481 {
bdae53f1
AL
482 Status = StatError;
483 ErrorText = "Size mismatch";
03e39e59
AL
484 return;
485 }
486
487 // Check the md5
488 if (Md5Hash.empty() == false && MD5.empty() == false)
489 {
490 if (Md5Hash != MD5)
491 {
bdae53f1
AL
492 Status = StatError;
493 ErrorText = "MD5Sum mismatch";
9978c7b0 494 Rename(DestFile,DestFile + ".FAILED");
03e39e59
AL
495 return;
496 }
497 }
a6568219
AL
498
499 // Grab the output filename
03e39e59
AL
500 string FileName = LookupTag(Message,"Filename");
501 if (FileName.empty() == true)
502 {
503 Status = StatError;
504 ErrorText = "Method gave a blank filename";
505 return;
506 }
a6568219
AL
507
508 Complete = true;
30e1eab5
AL
509
510 // Reference filename
a6568219
AL
511 if (FileName != DestFile)
512 {
30e1eab5 513 StoreFilename = DestFile = FileName;
a6568219
AL
514 Local = true;
515 return;
516 }
517
518 // Done, move it into position
519 string FinalFile = _config->FindDir("Dir::Cache::Archives");
17caf1b1 520 FinalFile += flNotDir(StoreFilename);
a6568219 521 Rename(DestFile,FinalFile);
03e39e59 522
30e1eab5 523 StoreFilename = DestFile = FinalFile;
03e39e59
AL
524 Complete = true;
525}
526 /*}}}*/
db890fdb
AL
527// AcqArchive::Failed - Failure handler /*{{{*/
528// ---------------------------------------------------------------------
529/* Here we try other sources */
7d8afa39 530void pkgAcqArchive::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
db890fdb
AL
531{
532 ErrorText = LookupTag(Message,"Message");
533 if (QueueNext() == false)
7d8afa39
AL
534 {
535 // This is the retry counter
536 if (Retries != 0 &&
537 Cnf->LocalOnly == false &&
538 StringToBool(LookupTag(Message,"Transient-Failure"),false) == true)
539 {
540 Retries--;
541 Vf = Version.FileList();
542 if (QueueNext() == true)
543 return;
544 }
545
9dbb421f 546 StoreFilename = string();
7d8afa39
AL
547 Item::Failed(Message,Cnf);
548 }
db890fdb
AL
549}
550 /*}}}*/
ab559b35
AL
551// AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
552// ---------------------------------------------------------------------
553/* */
554void pkgAcqArchive::Finished()
555{
556 if (Status == pkgAcquire::Item::StatDone &&
557 Complete == true)
558 return;
559 StoreFilename = string();
560}
561 /*}}}*/
36375005
AL
562
563// AcqFile::pkgAcqFile - Constructor /*{{{*/
564// ---------------------------------------------------------------------
565/* The file is added to the queue */
566pkgAcqFile::pkgAcqFile(pkgAcquire *Owner,string URI,string MD5,
567 unsigned long Size,string Dsc,string ShortDesc) :
b3c39978 568 Item(Owner), Md5Hash(MD5)
36375005
AL
569{
570 DestFile = flNotDir(URI);
571
572 // Create the item
573 Desc.URI = URI;
574 Desc.Description = Dsc;
575 Desc.Owner = this;
576
577 // Set the short description to the archive component
578 Desc.ShortDesc = ShortDesc;
579
580 // Get the transfer sizes
581 FileSize = Size;
582 struct stat Buf;
583 if (stat(DestFile.c_str(),&Buf) == 0)
584 {
585 // Hmm, the partial file is too big, erase it
586 if ((unsigned)Buf.st_size > Size)
587 unlink(DestFile.c_str());
588 else
589 PartialSize = Buf.st_size;
590 }
591
592 QueueURI(Desc);
593}
594 /*}}}*/
595// AcqFile::Done - Item downloaded OK /*{{{*/
596// ---------------------------------------------------------------------
597/* */
598void pkgAcqFile::Done(string Message,unsigned long Size,string MD5)
599{
b3c39978
AL
600 // Check the md5
601 if (Md5Hash.empty() == false && MD5.empty() == false)
602 {
603 if (Md5Hash != MD5)
604 {
605 Status = StatError;
606 ErrorText = "MD5Sum mismatch";
607 Rename(DestFile,DestFile + ".FAILED");
608 return;
609 }
610 }
611
36375005
AL
612 Item::Done(Message,Size,MD5);
613
614 string FileName = LookupTag(Message,"Filename");
615 if (FileName.empty() == true)
616 {
617 Status = StatError;
618 ErrorText = "Method gave a blank filename";
619 return;
620 }
621
622 Complete = true;
623
624 // The files timestamp matches
625 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
626 return;
627
628 // We have to copy it into place
629 if (FileName != DestFile)
630 {
631 Local = true;
917ae805
AL
632 if (_config->FindB("Acquire::Source-Symlinks",true) == false)
633 {
634 Desc.URI = "copy:" + FileName;
635 QueueURI(Desc);
636 return;
637 }
638
639 if (symlink(FileName.c_str(),DestFile.c_str()) != 0)
640 {
641 ErrorText = "Link to " + DestFile + "failure ";
642 Status = StatError;
643 Complete = false;
644 }
36375005
AL
645 }
646}
647 /*}}}*/