source: projects/synaptic/trunk/common/rpmindexcopy.cc @ 280

Revision 280, 6.5 KB checked in by yasumichi, 15 years ago (diff)

first import

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