]>
git.saurik.com Git - apt.git/blob - apt-pkg/indexcopy.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: indexcopy.cc,v 1.10 2002/03/26 07:38:58 jgg Exp $
4 /* ######################################################################
6 Index Copying - Aid for copying and verifying the index files
8 This class helps apt-cache reconstruct a damaged index files.
10 ##################################################################### */
12 // Include Files /*{{{*/
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/progress.h>
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/fileutl.h>
19 #include <apt-pkg/aptconfiguration.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/tagfile.h>
22 #include <apt-pkg/indexrecords.h>
23 #include <apt-pkg/md5.h>
24 #include <apt-pkg/cdrom.h>
30 #include <sys/types.h>
35 #include "indexcopy.h"
41 // IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/
42 // ---------------------------------------------------------------------
44 bool IndexCopy::CopyPackages(string CDROM
,string Name
,vector
<string
> &List
,
47 OpProgress
*Progress
= NULL
;
48 if (List
.empty() == true)
52 Progress
= log
->GetOpProgress();
54 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
55 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
57 // Prepare the progress indicator
59 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
60 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
64 std::string file
= std::string(*I
).append(GetFileName());
65 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
66 c
!= compressor
.end(); ++c
)
68 if (stat(std::string(file
+ c
->Extension
).c_str(), &Buf
) != 0)
75 return _error
->Errno("stat", "Stat failed for %s", file
.c_str());
76 TotalSize
+= Buf
.st_size
;
79 off_t CurrentSize
= 0;
80 unsigned int NotFound
= 0;
81 unsigned int WrongSize
= 0;
82 unsigned int Packages
= 0;
83 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
85 string OrigPath
= string(*I
,CDROM
.length());
87 // Open the package file
88 FileFd
Pkg(*I
+ GetFileName(), FileFd::ReadOnly
, FileFd::Auto
);
89 off_t
const FileSize
= Pkg
.Size();
91 pkgTagFile
Parser(&Pkg
);
92 if (_error
->PendingError() == true)
95 // Open the output file
97 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",Name
.c_str(),
98 (*I
).c_str() + CDROM
.length(),GetFileName());
99 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
100 TargetF
+= URItoFileName(S
);
102 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
104 TargetF
= "/dev/null";
105 Target
.Open(TargetF
,FileFd::WriteExists
);
107 Target
.Open(TargetF
,FileFd::WriteAtomic
);
109 FILE *TargetFl
= fdopen(dup(Target
.Fd()),"w");
110 if (_error
->PendingError() == true)
113 return _error
->Errno("fdopen","Failed to reopen fd");
115 // Setup the progress meter
117 Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
,
118 string("Reading ") + Type() + " Indexes");
122 Progress
->SubProgress(Pkg
.Size());
123 pkgTagSection Section
;
124 this->Section
= &Section
;
126 unsigned long Hits
= 0;
127 unsigned long Chop
= 0;
128 while (Parser
.Step(Section
) == true)
131 Progress
->Progress(Parser
.Offset());
133 unsigned long long Size
;
134 if (GetFile(File
,Size
) == false)
141 File
= OrigPath
+ ChopDirs(File
,Chop
);
143 // See if the file exists
144 if (NoStat
== false || Hits
< 10)
146 // Attempt to fix broken structure
149 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
150 ReconstructChop(Chop
,*I
,File
) == false)
153 clog
<< "Missed: " << File
<< endl
;
158 File
= OrigPath
+ ChopDirs(File
,Chop
);
163 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0 ||
166 bool Mangled
= false;
167 // Attempt to fix busted symlink support for one instance
168 string OrigFile
= File
;
169 string::size_type Start
= File
.find("binary-");
170 string::size_type End
= File
.find("/",Start
+3);
171 if (Start
!= string::npos
&& End
!= string::npos
)
173 File
.replace(Start
,End
-Start
,"binary-all");
177 if (Mangled
== false ||
178 stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
181 clog
<< "Missed(2): " << OrigFile
<< endl
;
188 if ((unsigned long long)Buf
.st_size
!= Size
)
191 clog
<< "Wrong Size: " << File
<< endl
;
200 if (RewriteEntry(TargetFl
,File
) == false)
209 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
211 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
213 // Move out of the partial directory
215 string FinalF
= _config
->FindDir("Dir::State::lists");
216 FinalF
+= URItoFileName(S
);
217 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
218 return _error
->Errno("rename","Failed to rename");
221 /* Mangle the source to be in the proper notation with
222 prefix dist [component] */
223 *I
= string(*I
,Prefix
.length());
224 ConvertToSourceList(CDROM
,*I
);
225 *I
= Prefix
+ ' ' + *I
;
227 CurrentSize
+= FileSize
;
235 if(NotFound
== 0 && WrongSize
== 0)
236 ioprintf(msg
, _("Wrote %i records.\n"), Packages
);
237 else if (NotFound
!= 0 && WrongSize
== 0)
238 ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),
240 else if (NotFound
== 0 && WrongSize
!= 0)
241 ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),
242 Packages
, WrongSize
);
243 if (NotFound
!= 0 && WrongSize
!= 0)
244 ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
);
248 _error
->Warning("No valid records were found.");
250 if (NotFound
+ WrongSize
> 10)
251 _error
->Warning("A lot of entries were discarded, something may be wrong.\n");
257 // IndexCopy::ChopDirs - Chop off the leading directory components /*{{{*/
258 // ---------------------------------------------------------------------
260 string
IndexCopy::ChopDirs(string Path
,unsigned int Depth
)
262 string::size_type I
= 0;
265 I
= Path
.find('/',I
+1);
268 while (I
!= string::npos
&& Depth
!= 0);
270 if (I
== string::npos
)
273 return string(Path
,I
+1);
276 // IndexCopy::ReconstructPrefix - Fix strange prefixing /*{{{*/
277 // ---------------------------------------------------------------------
278 /* This prepends dir components from the path to the package files to
279 the path to the deb until it is found */
280 bool IndexCopy::ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
283 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
284 unsigned int Depth
= 1;
285 string MyPrefix
= Prefix
;
289 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
292 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
293 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
307 // IndexCopy::ReconstructChop - Fixes bad source paths /*{{{*/
308 // ---------------------------------------------------------------------
309 /* This removes path components from the filename and prepends the location
310 of the package files until a file is found */
311 bool IndexCopy::ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
313 // Attempt to reconstruct the filename
314 unsigned long Depth
= 0;
318 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
320 File
= ChopDirs(File
,1);
322 if (File
.empty() == false)
335 // IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist /*{{{*/
336 // ---------------------------------------------------------------------
337 /* We look for things in dists/ notation and convert them to
338 <dist> <component> form otherwise it is left alone. This also strips
341 This implements a regex sort of like:
342 (.*)/dists/([^/]*)/(.*)/binary-*
344 | |-------- Distribution
345 |------------------- Path
347 It was deciced to use only a single word for dist (rather than say
348 unstable/non-us) to increase the chance that each CD gets a single
349 line in sources.list.
351 void IndexCopy::ConvertToSourceList(string CD
,string
&Path
)
353 // Strip the cdrom base path
354 Path
= string(Path
,CD
.length());
355 if (Path
.empty() == true)
358 // Too short to be a dists/ type
359 if (Path
.length() < strlen("dists/"))
363 if (stringcmp(Path
.c_str(),Path
.c_str()+strlen("dists/"),"dists/") != 0)
367 string::size_type Slash
= strlen("dists/");
368 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
369 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
371 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
373 // Isolate the component
375 for (unsigned I
= 0; I
!= 10; I
++)
377 Slash
= Path
.find('/',Slash
+1);
378 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
380 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
382 // Verify the trailing binary- bit
383 string::size_type BinSlash
= Path
.find('/',Slash
+ 1);
384 if (Slash
== string::npos
)
386 string Binary
= string(Path
,Slash
+1,BinSlash
- Slash
-1);
388 if (strncmp(Binary
.c_str(), "binary-", strlen("binary-")) == 0)
390 Binary
.erase(0, strlen("binary-"));
391 if (APT::Configuration::checkArchitecture(Binary
) == false)
394 else if (Binary
!= "source")
397 Path
= Dist
+ ' ' + Comp
;
402 // IndexCopy::GrabFirst - Return the first Depth path components /*{{{*/
403 // ---------------------------------------------------------------------
405 bool IndexCopy::GrabFirst(string Path
,string
&To
,unsigned int Depth
)
407 string::size_type I
= 0;
410 I
= Path
.find('/',I
+1);
413 while (I
!= string::npos
&& Depth
!= 0);
415 if (I
== string::npos
)
418 To
= string(Path
,0,I
+1);
422 // PackageCopy::GetFile - Get the file information from the section /*{{{*/
423 // ---------------------------------------------------------------------
425 bool PackageCopy::GetFile(string
&File
,unsigned long long &Size
)
427 File
= Section
->FindS("Filename");
428 Size
= Section
->FindI("Size");
429 if (File
.empty() || Size
== 0)
430 return _error
->Error("Cannot find filename or size tag");
434 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
435 // ---------------------------------------------------------------------
437 bool PackageCopy::RewriteEntry(FILE *Target
,string File
)
439 TFRewriteData Changes
[] = {{"Filename",File
.c_str()},
442 if (TFRewrite(Target
,*Section
,TFRewritePackageOrder
,Changes
) == false)
448 // SourceCopy::GetFile - Get the file information from the section /*{{{*/
449 // ---------------------------------------------------------------------
451 bool SourceCopy::GetFile(string
&File
,unsigned long long &Size
)
453 string Files
= Section
->FindS("Files");
454 if (Files
.empty() == true)
457 // Stash the / terminated directory prefix
458 string Base
= Section
->FindS("Directory");
459 if (Base
.empty() == false && Base
[Base
.length()-1] != '/')
462 // Read the first file triplet
463 const char *C
= Files
.c_str();
467 // Parse each of the elements
468 if (ParseQuoteWord(C
,MD5Hash
) == false ||
469 ParseQuoteWord(C
,sSize
) == false ||
470 ParseQuoteWord(C
,File
) == false)
471 return _error
->Error("Error parsing file record");
473 // Parse the size and append the directory
474 Size
= strtoull(sSize
.c_str(), NULL
, 10);
479 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
480 // ---------------------------------------------------------------------
482 bool SourceCopy::RewriteEntry(FILE *Target
,string File
)
484 string
Dir(File
,0,File
.rfind('/'));
485 TFRewriteData Changes
[] = {{"Directory",Dir
.c_str()},
488 if (TFRewrite(Target
,*Section
,TFRewriteSourceOrder
,Changes
) == false)
494 // SigVerify::Verify - Verify a files md5sum against its metaindex /*{{{*/
495 // ---------------------------------------------------------------------
497 bool SigVerify::Verify(string prefix
, string file
, indexRecords
*MetaIndex
)
499 const indexRecords::checkSum
*Record
= MetaIndex
->Lookup(file
);
500 bool const Debug
= _config
->FindB("Debug::aptcdrom",false);
502 // we skip non-existing files in the verifcation of the Release file
503 // as non-existing files do not harm, but a warning scares people and
504 // makes it hard to strip unneeded files from an ISO like uncompressed
505 // indexes as it is done on the mirrors (see also LP: #255545 )
506 if(!RealFileExists(prefix
+file
))
509 cout
<< "Skipping nonexistent in " << prefix
<< " file " << file
<< std::endl
;
515 _error
->Warning(_("Can't find authentication record for: %s"), file
.c_str());
519 if (!Record
->Hash
.VerifyFile(prefix
+file
))
521 _error
->Warning(_("Hash mismatch for: %s"),file
.c_str());
527 cout
<< "File: " << prefix
+file
<< endl
;
528 cout
<< "Expected Hash " << Record
->Hash
.toStr() << endl
;
534 bool SigVerify::CopyMetaIndex(string CDROM
, string CDName
, /*{{{*/
535 string prefix
, string file
)
538 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s%s",CDName
.c_str(),
539 (prefix
).c_str() + CDROM
.length(),file
.c_str());
540 string TargetF
= _config
->FindDir("Dir::State::lists");
541 TargetF
+= URItoFileName(S
);
545 Target
.Open(TargetF
,FileFd::WriteAtomic
);
546 Rel
.Open(prefix
+ file
,FileFd::ReadOnly
);
547 if (_error
->PendingError() == true)
549 if (CopyFile(Rel
,Target
) == false)
555 bool SigVerify::CopyAndVerify(string CDROM
,string Name
,vector
<string
> &SigList
, /*{{{*/
556 vector
<string
> PkgList
,vector
<string
> SrcList
)
558 if (SigList
.empty() == true)
561 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
563 // Read all Release files
564 for (vector
<string
>::iterator I
= SigList
.begin(); I
!= SigList
.end(); ++I
)
567 cout
<< "Signature verify for: " << *I
<< endl
;
569 indexRecords
*MetaIndex
= new indexRecords
;
572 string
const releasegpg
= *I
+"Release.gpg";
573 string
const release
= *I
+"Release";
574 string
const inrelease
= *I
+"InRelease";
575 bool useInRelease
= true;
577 // a Release.gpg without a Release should never happen
578 if (RealFileExists(inrelease
) == true)
580 else if(RealFileExists(release
) == false || RealFileExists(releasegpg
) == false)
586 useInRelease
= false;
588 pid_t pid
= ExecFork();
590 _error
->Error("Fork failed");
595 if (useInRelease
== true)
596 RunGPGV(inrelease
, inrelease
);
598 RunGPGV(release
, releasegpg
);
601 if(!ExecWait(pid
, "gpgv")) {
602 _error
->Warning("Signature verification failed for: %s",
603 (useInRelease
? inrelease
.c_str() : releasegpg
.c_str()));
604 // something went wrong, don't copy the Release.gpg
605 // FIXME: delete any existing gpg file?
609 // Open the Release file and add it to the MetaIndex
610 if(!MetaIndex
->Load(release
))
612 _error
->Error("%s",MetaIndex
->ErrorText
.c_str());
616 // go over the Indexfiles and see if they verify
617 // if so, remove them from our copy of the lists
618 vector
<string
> keys
= MetaIndex
->MetaKeys();
619 for (vector
<string
>::iterator I
= keys
.begin(); I
!= keys
.end(); ++I
)
621 if(!Verify(prefix
,*I
, MetaIndex
)) {
622 // something went wrong, don't copy the Release.gpg
623 // FIXME: delete any existing gpg file?
629 // we need a fresh one for the Release.gpg
632 // everything was fine, copy the Release and Release.gpg file
633 if (useInRelease
== true)
634 CopyMetaIndex(CDROM
, Name
, prefix
, "InRelease");
637 CopyMetaIndex(CDROM
, Name
, prefix
, "Release");
638 CopyMetaIndex(CDROM
, Name
, prefix
, "Release.gpg");
645 // SigVerify::RunGPGV - returns the command needed for verify /*{{{*/
646 // ---------------------------------------------------------------------
647 /* Generating the commandline for calling gpgv is somehow complicated as
648 we need to add multiple keyrings and user supplied options. Also, as
649 the cdrom code currently can not use the gpgv method we have two places
650 these need to be done - so the place for this method is wrong but better
651 than code duplication… */
652 bool SigVerify::RunGPGV(std::string
const &File
, std::string
const &FileGPG
,
653 int const &statusfd
, int fd
[2])
657 #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n"
658 char buffer
[sizeof(SIGMSG
)];
659 FILE* gpg
= fopen(File
.c_str(), "r");
661 return _error
->Errno("RunGPGV", _("Could not open file %s"), File
.c_str());
662 char const * const test
= fgets(buffer
, sizeof(buffer
), gpg
);
664 if (test
== NULL
|| strcmp(buffer
, SIGMSG
) != 0)
665 return _error
->Error(_("File %s doesn't start with a clearsigned message"), File
.c_str());
670 string
const gpgvpath
= _config
->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
671 // FIXME: remove support for deprecated APT::GPGV setting
672 string
const trustedFile
= _config
->Find("APT::GPGV::TrustedKeyring", _config
->FindFile("Dir::Etc::Trusted"));
673 string
const trustedPath
= _config
->FindDir("Dir::Etc::TrustedParts");
675 bool const Debug
= _config
->FindB("Debug::Acquire::gpgv", false);
679 std::clog
<< "gpgv path: " << gpgvpath
<< std::endl
;
680 std::clog
<< "Keyring file: " << trustedFile
<< std::endl
;
681 std::clog
<< "Keyring path: " << trustedPath
<< std::endl
;
684 std::vector
<string
> keyrings
;
685 if (DirectoryExists(trustedPath
))
686 keyrings
= GetListOfFilesInDir(trustedPath
, "gpg", false, true);
687 if (RealFileExists(trustedFile
) == true)
688 keyrings
.push_back(trustedFile
);
690 std::vector
<const char *> Args
;
693 if (keyrings
.empty() == true)
695 // TRANSLATOR: %s is the trusted keyring parts directory
696 return _error
->Error(_("No keyring installed in %s."),
697 _config
->FindDir("Dir::Etc::TrustedParts").c_str());
700 Args
.push_back(gpgvpath
.c_str());
701 Args
.push_back("--ignore-time-conflict");
705 Args
.push_back("--status-fd");
707 snprintf(fd
, sizeof(fd
), "%i", statusfd
);
711 for (vector
<string
>::const_iterator K
= keyrings
.begin();
712 K
!= keyrings
.end(); ++K
)
714 Args
.push_back("--keyring");
715 Args
.push_back(K
->c_str());
718 Configuration::Item
const *Opts
;
719 Opts
= _config
->Tree("Acquire::gpgv::Options");
723 for (; Opts
!= 0; Opts
= Opts
->Next
)
725 if (Opts
->Value
.empty() == true)
727 Args
.push_back(Opts
->Value
.c_str());
731 Args
.push_back(FileGPG
.c_str());
733 Args
.push_back(File
.c_str());
734 Args
.push_back(NULL
);
738 std::clog
<< "Preparing to exec: " << gpgvpath
;
739 for (std::vector
<const char *>::const_iterator a
= Args
.begin(); *a
!= NULL
; ++a
)
740 std::clog
<< " " << *a
;
741 std::clog
<< std::endl
;
746 int const nullfd
= open("/dev/null", O_RDONLY
);
748 // Redirect output to /dev/null; we read from the status fd
749 dup2(nullfd
, STDOUT_FILENO
);
750 dup2(nullfd
, STDERR_FILENO
);
751 // Redirect the pipe to the status fd (3)
752 dup2(fd
[1], statusfd
);
754 putenv((char *)"LANG=");
755 putenv((char *)"LC_ALL=");
756 putenv((char *)"LC_MESSAGES=");
759 execvp(gpgvpath
.c_str(), (char **) &Args
[0]);
763 bool TranslationsCopy::CopyTranslations(string CDROM
,string Name
, /*{{{*/
764 vector
<string
> &List
, pkgCdromStatus
*log
)
766 OpProgress
*Progress
= NULL
;
767 if (List
.empty() == true)
771 Progress
= log
->GetOpProgress();
773 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
775 // Prepare the progress indicator
777 std::vector
<APT::Configuration::Compressor
> const compressor
= APT::Configuration::getCompressors();
778 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
782 std::string file
= *I
;
783 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressor
.begin();
784 c
!= compressor
.end(); ++c
)
786 if (stat(std::string(file
+ c
->Extension
).c_str(), &Buf
) != 0)
793 return _error
->Errno("stat", "Stat failed for %s", file
.c_str());
794 TotalSize
+= Buf
.st_size
;
797 off_t CurrentSize
= 0;
798 unsigned int NotFound
= 0;
799 unsigned int WrongSize
= 0;
800 unsigned int Packages
= 0;
801 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); ++I
)
803 // Open the package file
804 FileFd
Pkg(*I
, FileFd::ReadOnly
, FileFd::Auto
);
805 off_t
const FileSize
= Pkg
.Size();
807 pkgTagFile
Parser(&Pkg
);
808 if (_error
->PendingError() == true)
811 // Open the output file
813 snprintf(S
,sizeof(S
),"cdrom:[%s]/%s",Name
.c_str(),
814 (*I
).c_str() + CDROM
.length());
815 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
816 TargetF
+= URItoFileName(S
);
818 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
820 TargetF
= "/dev/null";
821 Target
.Open(TargetF
,FileFd::WriteExists
);
823 Target
.Open(TargetF
,FileFd::WriteAtomic
);
825 FILE *TargetFl
= fdopen(dup(Target
.Fd()),"w");
826 if (_error
->PendingError() == true)
829 return _error
->Errno("fdopen","Failed to reopen fd");
831 // Setup the progress meter
833 Progress
->OverallProgress(CurrentSize
,TotalSize
,FileSize
,
834 string("Reading Translation Indexes"));
838 Progress
->SubProgress(Pkg
.Size());
839 pkgTagSection Section
;
840 this->Section
= &Section
;
842 unsigned long Hits
= 0;
843 while (Parser
.Step(Section
) == true)
846 Progress
->Progress(Parser
.Offset());
850 Section
.GetSection(Start
,Stop
);
851 fwrite(Start
,Stop
-Start
, 1, TargetFl
);
852 fputc('\n',TargetFl
);
860 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << endl
;
862 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
864 // Move out of the partial directory
866 string FinalF
= _config
->FindDir("Dir::State::lists");
867 FinalF
+= URItoFileName(S
);
868 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
869 return _error
->Errno("rename","Failed to rename");
873 CurrentSize
+= FileSize
;
881 if(NotFound
== 0 && WrongSize
== 0)
882 ioprintf(msg
, _("Wrote %i records.\n"), Packages
);
883 else if (NotFound
!= 0 && WrongSize
== 0)
884 ioprintf(msg
, _("Wrote %i records with %i missing files.\n"),
886 else if (NotFound
== 0 && WrongSize
!= 0)
887 ioprintf(msg
, _("Wrote %i records with %i mismatched files\n"),
888 Packages
, WrongSize
);
889 if (NotFound
!= 0 && WrongSize
!= 0)
890 ioprintf(msg
, _("Wrote %i records with %i missing files and %i mismatched files\n"), Packages
, NotFound
, WrongSize
);
894 _error
->Warning("No valid records were found.");
896 if (NotFound
+ WrongSize
> 10)
897 _error
->Warning("A lot of entries were discarded, something may be wrong.\n");