- initial import of revision 374 from cnc
[apt.git] / cmdline / rpmindexcopy.cc
1
2 #include <apt-pkg/error.h>
3 #include <apt-pkg/progress.h>
4 #include <apt-pkg/strutl.h>
5 #include <apt-pkg/fileutl.h>
6 #include <apt-pkg/configuration.h>
7 #include <apt-pkg/tagfile.h>
8
9 #include <iostream>
10 #include <map>
11 #include <unistd.h>
12 #include <sys/stat.h>
13 #include <stdio.h>
14
15
16 #include "rpmindexcopy.h"
17
18 using namespace std;
19
20 string RPMIndexCopy::RipComponent(string Path)
21 {
22    const char *begin;
23    const char *end;
24    
25    end = strrchr(Path.c_str(), '.');
26    begin = strchr(strrchr(Path.c_str(), '/'), '.') + 1;
27    if (begin < strrchr(end, '/'))
28        return string(end + 1);
29    
30    return string(begin, end);
31 }
32
33
34 string RPMIndexCopy::RipDistro(string Path)
35 {
36    return string(Path, 0, Path.find("base")-1);
37 }
38
39
40 string RPMIndexCopy::RipDirectory(string Path)
41 {
42    return string(Path, 0, Path.rfind('/'));
43 }
44
45 bool RPMIndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List)
46 {   
47    OpTextProgress Progress;
48    
49    if (List.size() == 0)
50       return true;
51    
52    // Prepare the progress indicator
53    unsigned long TotalSize = 0;
54    for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
55    {
56       struct stat Buf;
57       if (stat((*I).c_str(),&Buf) != 0)
58          return _error->Errno("stat","Stat failed for %s",
59                               (*I).c_str());
60       TotalSize += Buf.st_size;
61    }
62    
63    unsigned long CurrentSize = 0;
64
65    // Keep track of global release processing
66    map<string,bool> GlobalReleases;
67
68    for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
69    {      
70       string OrigPath = string(*I,CDROM.length());
71       unsigned long FileSize = 0;
72       
73       // Open the package file
74       FileFd Pkg;
75       string File = *I;
76       
77       if (strcmp(File.c_str()+File.length()-4, ".bz2") == 0)
78          File = string(File, 0, File.length()-4);
79       
80       if (FileExists(File) == true)
81       {
82          Pkg.Open(File,FileFd::ReadOnly);
83          FileSize = Pkg.Size();
84       }      
85       else
86       {
87          FileFd From(*I, FileFd::ReadOnly);
88          if (_error->PendingError() == true)
89             return false;
90          FileSize = From.Size();
91          
92          // Get a temp file
93          FILE *tmp = tmpfile();
94          if (tmp == 0)
95             return _error->Errno("tmpfile","Unable to create a tmp file");
96          Pkg.Fd(dup(fileno(tmp)));
97          fclose(tmp);
98          
99          // Fork bzip2
100          int Process = fork();
101          if (Process < 0)
102             return _error->Errno("fork","Couldn't fork bzip2");
103          
104          // The child
105          if (Process == 0)
106          {          
107             dup2(From.Fd(),STDIN_FILENO);
108             dup2(Pkg.Fd(),STDOUT_FILENO);
109             SetCloseExec(STDIN_FILENO,false);
110             SetCloseExec(STDOUT_FILENO,false);
111             
112             const char *Args[3];
113             Args[0] = _config->Find("Dir::Bin::bzip2","bzip2").c_str();
114             Args[1] = "-d";
115             Args[2] = 0;
116             execvp(Args[0],(char **)Args);
117             exit(100);
118          }
119          
120          // Wait for gzip to finish
121          if (ExecWait(Process,_config->Find("Dir::Bin::bzip2","bzip2").c_str(),false) == false)
122             return _error->Error("bzip2 failed, perhaps the disk is full.");
123          
124          Pkg.Seek(0);
125       }
126       if (_error->PendingError() == true)
127          return false;
128       
129       // Open the output file
130       char S[400];
131       sprintf(S,"cdrom:[%s]/%s",Name.c_str(),
132               File.c_str() + CDROM.length());
133       string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
134       TargetF += URItoFileName(S);
135       if (_config->FindB("APT::CDROM::NoAct",false) == true)
136          TargetF = "/dev/null";
137       FileFd Target(TargetF,FileFd::WriteEmpty);      
138       if (_error->PendingError() == true)
139          return false;
140       
141       // Setup the progress meter
142       Progress.OverallProgress(CurrentSize,TotalSize,FileSize,
143                                string("Reading Indexes"));
144
145       // Parse
146       Progress.SubProgress(Pkg.Size());
147
148       if (!CopyFile(Pkg, Target))
149           return false;
150          
151       if (_config->FindB("APT::CDROM::NoAct",false) == false)
152       {
153          // Move out of the partial directory
154          Target.Close();
155          string FinalF = _config->FindDir("Dir::State::lists");
156          FinalF += URItoFileName(S);
157          if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
158             return _error->Errno("rename","Failed to rename");
159
160          // Two release steps, one for global, one for component
161          string release = "release";
162          for (int Step = 0; Step != 2; Step++)
163          {
164             if (Step == 0)
165             {
166                if (GlobalReleases.find(*I) != GlobalReleases.end())
167                   continue;
168                GlobalReleases[*I] = true;
169             }
170             else
171                release += "." + RipComponent(*I);
172             
173             // Copy the component release file
174             sprintf(S,"cdrom:[%s]/%s/%s",Name.c_str(),
175                     RipDirectory(*I).c_str() + CDROM.length(),
176                      release.c_str());
177             string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
178             TargetF += URItoFileName(S);
179             if (FileExists(RipDirectory(*I) + release) == true)
180             {
181                FileFd Target(TargetF,FileFd::WriteEmpty);
182                FileFd Rel(RipDirectory(*I) + release,FileFd::ReadOnly);
183                if (_error->PendingError() == true)
184                   return false;
185                
186                if (CopyFile(Rel,Target) == false)
187                   return false;
188             }
189             else
190             {
191                // Empty release file
192                FileFd Target(TargetF,FileFd::WriteEmpty);           
193             }
194
195             // Rename the release file
196             FinalF = _config->FindDir("Dir::State::lists");
197             FinalF += URItoFileName(S);
198             if (rename(TargetF.c_str(),FinalF.c_str()) != 0)
199                return _error->Errno("rename","Failed to rename");
200          }
201       }
202       
203       string Prefix = "";
204       /* Mangle the source to be in the proper notation with
205          prefix dist [component] */ 
206 //      *I = string(*I,Prefix.length());
207       ConvertToSourceList(CDROM,*I);
208       *I = Prefix + ' ' + *I;
209       
210       CurrentSize += FileSize;
211    }   
212    Progress.Done();
213
214    return true;
215 }
216
217
218
219
220 void RPMIndexCopy::ConvertToSourceList(string CD, string &Path)
221 {   
222    Path = string(Path, CD.length());
223
224    Path = RipDistro(Path) + " " + RipComponent(Path);
225 }
226
227 // vim:sts=3:sw=3