]>
git.saurik.com Git - apt.git/blob - cmdline/indexcopy.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: indexcopy.cc,v 1.2 1999/09/03 05:46:48 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 /*{{{*/
13 #include "indexcopy.h"
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/configuration.h>
20 #include <apt-pkg/tagfile.h>
29 // IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/
30 // ---------------------------------------------------------------------
32 bool IndexCopy::CopyPackages(string CDROM
,string Name
,vector
<string
> &List
)
37 OpTextProgress Progress
;
39 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
40 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
42 // Prepare the progress indicator
43 unsigned long TotalSize
= 0;
44 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
47 if (stat(string(*I
+ GetFileName()).c_str(),&Buf
) != 0 &&
48 stat(string(*I
+ GetFileName() + ".gz").c_str(),&Buf
) != 0)
49 return _error
->Errno("stat","Stat failed for %s",
50 string(*I
+ GetFileName()).c_str());
51 TotalSize
+= Buf
.st_size
;
54 unsigned long CurrentSize
= 0;
55 unsigned int NotFound
= 0;
56 unsigned int WrongSize
= 0;
57 unsigned int Packages
= 0;
58 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
60 string OrigPath
= string(*I
,CDROM
.length());
61 unsigned long FileSize
= 0;
63 // Open the package file
65 if (FileExists(*I
+ GetFileName()) == true)
67 Pkg
.Open(*I
+ GetFileName(),FileFd::ReadOnly
);
68 FileSize
= Pkg
.Size();
72 FileFd
From(*I
+ GetFileName() + ".gz",FileFd::ReadOnly
);
73 if (_error
->PendingError() == true)
75 FileSize
= From
.Size();
78 FILE *tmp
= tmpfile();
80 return _error
->Errno("tmpfile","Unable to create a tmp file");
81 Pkg
.Fd(dup(fileno(tmp
)));
87 return _error
->Errno("fork","Couldn't fork gzip");
92 dup2(From
.Fd(),STDIN_FILENO
);
93 dup2(Pkg
.Fd(),STDOUT_FILENO
);
94 SetCloseExec(STDIN_FILENO
,false);
95 SetCloseExec(STDOUT_FILENO
,false);
98 Args
[0] = _config
->Find("Dir::bin::gzip","gzip").c_str();
101 execvp(Args
[0],(char **)Args
);
105 // Wait for gzip to finish
107 if (waitpid(Process
,&Status
,0) != Process
)
108 return _error
->Errno("wait","Waiting for gzip failed");
109 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
110 return _error
->Error("gzip failed, perhaps the disk is full.");
113 pkgTagFile
Parser(Pkg
);
114 if (_error
->PendingError() == true)
117 // Open the output file
119 sprintf(S
,"cdrom:%s/%s%s",Name
.c_str(),(*I
).c_str() + CDROM
.length(),
121 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
122 TargetF
+= URItoFileName(S
);
123 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
124 TargetF
= "/dev/null";
125 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
126 if (_error
->PendingError() == true)
129 // Setup the progress meter
130 Progress
.OverallProgress(CurrentSize
,TotalSize
,FileSize
,
131 string("Reading ") + Type() + " Indexes");
134 Progress
.SubProgress(Pkg
.Size());
135 pkgTagSection Section
;
136 this->Section
= &Section
;
138 unsigned long Hits
= 0;
139 unsigned long Chop
= 0;
140 while (Parser
.Step(Section
) == true)
142 Progress
.Progress(Parser
.Offset());
145 if (GetFile(File
,Size
) == false)
149 File
= OrigPath
+ ChopDirs(File
,Chop
);
151 // See if the file exists
152 bool Mangled
= false;
153 if (NoStat
== false || Hits
< 10)
155 // Attempt to fix broken structure
158 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
159 ReconstructChop(Chop
,*I
,File
) == false)
162 clog
<< "Missed: " << File
<< endl
;
167 File
= OrigPath
+ ChopDirs(File
,Chop
);
172 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0 ||
175 // Attempt to fix busted symlink support for one instance
176 string OrigFile
= File
;
177 string::size_type Start
= File
.find("binary-");
178 string::size_type End
= File
.find("/",Start
+3);
179 if (Start
!= string::npos
&& End
!= string::npos
)
181 File
.replace(Start
,End
-Start
,"binary-all");
185 if (Mangled
== false ||
186 stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
189 clog
<< "Missed(2): " << OrigFile
<< endl
;
196 if ((unsigned)Buf
.st_size
!= Size
)
199 clog
<< "Wrong Size: " << File
<< endl
;
208 // Copy it to the target package file
209 if (Chop
!= 0 || Mangled
== true)
211 if (RewriteEntry(Target
,File
) == false)
218 Section
.GetSection(Start
,Stop
);
219 if (Target
.Write(Start
,Stop
-Start
) == false)
225 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
227 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
229 // Move out of the partial directory
231 string FinalF
= _config
->FindDir("Dir::State::lists");
232 FinalF
+= URItoFileName(S
);
233 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
234 return _error
->Errno("rename","Failed to rename");
236 // Copy the release file
237 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
238 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
239 TargetF
+= URItoFileName(S
);
240 if (FileExists(*I
+ "Release") == true)
242 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
243 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
244 if (_error
->PendingError() == true)
247 if (CopyFile(Rel
,Target
) == false)
252 // Empty release file
253 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
256 // Rename the release file
257 FinalF
= _config
->FindDir("Dir::State::lists");
258 FinalF
+= URItoFileName(S
);
259 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
260 return _error
->Errno("rename","Failed to rename");
263 /* Mangle the source to be in the proper notation with
264 prefix dist [component] */
265 *I
= string(*I
,Prefix
.length());
266 ConvertToSourceList(CDROM
,*I
);
267 *I
= Prefix
+ ' ' + *I
;
269 CurrentSize
+= FileSize
;
274 cout
<< "Wrote " << Packages
<< " records" ;
276 cout
<< " with " << NotFound
<< " missing files";
277 if (NotFound
!= 0 && WrongSize
!= 0)
280 cout
<< " with " << WrongSize
<< " mismatched files";
284 return _error
->Warning("No valid records were found.");
286 if (NotFound
+ WrongSize
> 10)
287 cout
<< "Alot of entries were discarded, something may be wrong." << endl
;
292 // IndexCopy::ChopDirs - Chop off the leading directory components /*{{{*/
293 // ---------------------------------------------------------------------
295 string
IndexCopy::ChopDirs(string Path
,unsigned int Depth
)
297 string::size_type I
= 0;
300 I
= Path
.find('/',I
+1);
303 while (I
!= string::npos
&& Depth
!= 0);
305 if (I
== string::npos
)
308 return string(Path
,I
+1);
311 // IndexCopy::ReconstructPrefix - Fix strange prefixing /*{{{*/
312 // ---------------------------------------------------------------------
313 /* This prepends dir components from the path to the package files to
314 the path to the deb until it is found */
315 bool IndexCopy::ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
318 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
319 unsigned int Depth
= 1;
320 string MyPrefix
= Prefix
;
324 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
327 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
328 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
342 // IndexCopy::ReconstructChop - Fixes bad source paths /*{{{*/
343 // ---------------------------------------------------------------------
344 /* This removes path components from the filename and prepends the location
345 of the package files until a file is found */
346 bool IndexCopy::ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
348 // Attempt to reconstruct the filename
349 unsigned long Depth
= 0;
353 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
355 File
= ChopDirs(File
,1);
357 if (File
.empty() == false)
370 // IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist /*{{{*/
371 // ---------------------------------------------------------------------
372 /* We look for things in dists/ notation and convert them to
373 <dist> <component> form otherwise it is left alone. This also strips
375 void IndexCopy::ConvertToSourceList(string CD
,string
&Path
)
378 sprintf(S
,"binary-%s",_config
->Find("Apt::Architecture").c_str());
380 // Strip the cdrom base path
381 Path
= string(Path
,CD
.length());
382 if (Path
.empty() == true)
385 // Too short to be a dists/ type
386 if (Path
.length() < strlen("dists/"))
390 if (stringcmp(Path
.begin(),Path
.begin()+strlen("dists/"),"dists/") != 0)
394 string::size_type Slash
= strlen("dists/");
395 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
396 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
398 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
400 // Isolate the component
401 Slash
= Path
.find('/',Slash2
+1);
402 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
404 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
406 // Verify the trailing binar - bit
407 Slash2
= Path
.find('/',Slash
+ 1);
408 if (Slash
== string::npos
)
410 string Binary
= string(Path
,Slash
+1,Slash2
- Slash
-1);
412 if (Binary
!= S
&& Binary
!= "source")
415 Path
= Dist
+ ' ' + Comp
;
418 // IndexCopy::GrabFirst - Return the first Depth path components /*{{{*/
419 // ---------------------------------------------------------------------
421 bool IndexCopy::GrabFirst(string Path
,string
&To
,unsigned int Depth
)
423 string::size_type I
= 0;
426 I
= Path
.find('/',I
+1);
429 while (I
!= string::npos
&& Depth
!= 0);
431 if (I
== string::npos
)
434 To
= string(Path
,0,I
+1);
438 // IndexCopy::CopyWithReplace - Copy a section and replace text /*{{{*/
439 // ---------------------------------------------------------------------
441 bool IndexCopy::CopyWithReplace(FileFd
&Target
,const char *Tag
,string New
)
443 // Mangle the output filename
446 const char *Filename
;
447 Section
->Find(Tag
,Filename
,Stop
);
449 /* We need to rewrite the filename field so we emit
450 all fields except the filename file and rewrite that one */
451 for (unsigned int I
= 0; I
!= Section
->Count(); I
++)
453 Section
->Get(Start
,Stop
,I
);
454 if (Start
<= Filename
&& Stop
> Filename
)
457 sprintf(S
,"%s: %s\n",Tag
,New
.c_str());
458 if (I
+ 1 == Section
->Count())
460 if (Target
.Write(S
,strlen(S
)) == false)
465 if (Target
.Write(Start
,Stop
-Start
) == false)
467 if (Stop
[-1] != '\n')
468 if (Target
.Write("\n",1) == false)
472 if (Target
.Write("\n",1) == false)
476 // PackageCopy::GetFile - Get the file information from the section /*{{{*/
477 // ---------------------------------------------------------------------
479 bool PackageCopy::GetFile(string
&File
,unsigned long &Size
)
481 File
= Section
->FindS("Filename");
482 Size
= Section
->FindI("Size");
483 if (File
.empty() || Size
== 0)
484 return _error
->Error("Cannot find filename or size tag");
488 // PackageCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
489 // ---------------------------------------------------------------------
491 bool PackageCopy::RewriteEntry(FileFd
&Target
,string File
)
493 return CopyWithReplace(Target
,"Filename",File
);
496 // SourceCopy::GetFile - Get the file information from the section /*{{{*/
497 // ---------------------------------------------------------------------
499 bool SourceCopy::GetFile(string
&File
,unsigned long &Size
)
501 string Files
= Section
->FindS("Files");
502 if (Files
.empty() == true)
505 // Stash the / terminated directory prefix
506 string Base
= Section
->FindS("Directory");
507 if (Base
.empty() == false && Base
[Base
.length()-1] != '/')
510 // Iterate over the entire list grabbing each triplet
511 const char *C
= Files
.c_str();
515 // Parse each of the elements
516 if (ParseQuoteWord(C
,MD5Hash
) == false ||
517 ParseQuoteWord(C
,sSize
) == false ||
518 ParseQuoteWord(C
,File
) == false)
519 return _error
->Error("Error parsing file record");
521 // Parse the size and append the directory
522 Size
= atoi(sSize
.c_str());
527 // SourceCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/
528 // ---------------------------------------------------------------------
530 bool SourceCopy::RewriteEntry(FileFd
&Target
,string File
)
532 return CopyWithReplace(Target
,"Directory",
533 string(File
,0,File
.rfind('/')));