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

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

first import

Line 
1/* rsource.cc - access the sources.list file
2 *
3 * Copyright (c) 1999 Patrick Cole <z@amused.net>
4 *           (c) 2002 Synaptic development team         
5 *
6 * Author: Patrick Cole <z@amused.net>
7 *         Michael Vogt <mvo@debian.org>
8 *         Gustavo Niemeyer <niemeyer@conectiva.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 */
25
26#include <sys/stat.h>
27#include <dirent.h>
28
29#include "rsources.h"
30#include <apt-pkg/configuration.h>
31#include <apt-pkg/fileutl.h>
32#include <apt-pkg/sourcelist.h>
33#include <apt-pkg/strutl.h>
34#include <apt-pkg/error.h>
35#include <algorithm>
36#include <fstream>
37#include "config.h"
38#include "i18n.h"
39
40SourcesList::~SourcesList()
41{
42   for (list<SourceRecord *>::iterator it = SourceRecords.begin();
43        it != SourceRecords.end(); it++)
44      delete *it;
45   for (list<VendorRecord *>::iterator it = VendorRecords.begin();
46        it != VendorRecords.end(); it++)
47      delete *it;
48}
49
50SourcesList::SourceRecord *SourcesList::AddSourceNode(SourceRecord &rec)
51{
52   SourceRecord *newrec = new SourceRecord;
53   *newrec = rec;
54   SourceRecords.push_back(newrec);
55
56   return newrec;
57}
58
59bool SourcesList::ReadSourcePart(string listpath)
60{
61   //cout << "SourcesList::ReadSourcePart() "<< listpath  << endl;
62   char buf[512];
63   const char *p;
64   ifstream ifs(listpath.c_str(), ios::in);
65   bool record_ok = true;
66
67   // cannot open file
68   if (!ifs != 0)
69      return _error->Error(_("Can't read %s"), listpath.c_str());
70
71   while (ifs.eof() == false) {
72      p = buf;
73      SourceRecord rec;
74      string Type;
75      string Section;
76      string VURI;
77
78      ifs.getline(buf, sizeof(buf));
79
80      rec.SourceFile = listpath;
81      while (isspace(*p))
82         p++;
83      if (*p == '#') {
84         rec.Type = Disabled;
85         p++;
86         while (isspace(*p))
87            p++;
88      }
89
90      if (*p == '\r' || *p == '\n' || *p == 0) {
91         rec.Type = Comment;
92         rec.Comment = p;
93
94         AddSourceNode(rec);
95         continue;
96      }
97
98      bool Failed = true;
99      if (ParseQuoteWord(p, Type) == true &&
100          rec.SetType(Type) == true && ParseQuoteWord(p, VURI) == true) {
101         if (VURI[0] == '[') {
102            rec.VendorID = VURI.substr(1, VURI.length() - 2);
103            if (ParseQuoteWord(p, VURI) == true && rec.SetURI(VURI) == true)
104               Failed = false;
105         } else if (rec.SetURI(VURI) == true) {
106            Failed = false;
107         }
108         if (Failed == false && ParseQuoteWord(p, rec.Dist) == false)
109            Failed = true;
110      }
111
112      if (Failed == true) {
113         if (rec.Type == Disabled) {
114            // treat as a comment field
115            rec.Type = Comment;
116            rec.Comment = buf;
117         } else {
118            // syntax error on line
119            rec.Type = Comment;
120            string s = "#" + string(buf);
121            rec.Comment = s;
122            record_ok = false;
123            //return _error->Error(_("Syntax error in line %s"), buf);
124         }
125      }
126#ifndef HAVE_RPM
127      // check for absolute dist
128      if (rec.Dist.empty() == false && rec.Dist[rec.Dist.size() - 1] == '/') {
129         // make sure there's no section
130         if (ParseQuoteWord(p, Section) == true)
131            return _error->Error(_("Syntax error in line %s"), buf);
132
133         rec.Dist = SubstVar(rec.Dist, "$(ARCH)",
134                             _config->Find("APT::Architecture"));
135
136         AddSourceNode(rec);
137         continue;
138      }
139#endif
140
141      const char *tmp = p;
142      rec.NumSections = 0;
143      while (ParseQuoteWord(p, Section) == true)
144         rec.NumSections++;
145      if (rec.NumSections > 0) {
146         p = tmp;
147         rec.Sections = new string[rec.NumSections];
148         rec.NumSections = 0;
149         while (ParseQuoteWord(p, Section) == true) {
150            // comments inside the record are preserved
151            if (Section[0] == '#') {
152               SourceRecord rec;
153               string s = Section + string(p);
154               rec.Type = Comment;
155               rec.Comment = s;
156               rec.SourceFile = listpath;
157               AddSourceNode(rec);
158               break;
159            } else {
160               rec.Sections[rec.NumSections++] = Section;
161            }
162         }
163      }
164      AddSourceNode(rec);
165   }
166
167   ifs.close();
168   return record_ok;
169}
170
171bool SourcesList::ReadSourceDir(string Dir)
172{
173   //cout << "SourcesList::ReadSourceDir() " << Dir  << endl;
174
175   DIR *D = opendir(Dir.c_str());
176   if (D == 0)
177      return _error->Errno("opendir", _("Unable to read %s"), Dir.c_str());
178
179   vector<string> List;
180   for (struct dirent * Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
181      if (Ent->d_name[0] == '.')
182         continue;
183
184      // Skip bad file names ala run-parts
185      const char *C = Ent->d_name;
186      for (; *C != 0; C++)
187         if (isalpha(*C) == 0 && isdigit(*C) == 0
188             && *C != '_' && *C != '-' && *C != '.')
189            break;
190      if (*C != 0)
191         continue;
192
193      // Only look at files ending in .list to skip .rpmnew etc files
194      if (strcmp(Ent->d_name + strlen(Ent->d_name) - 5, ".list") != 0)
195         continue;
196
197      // Make sure it is a file and not something else
198      string File = flCombine(Dir, Ent->d_name);
199      struct stat St;
200      if (stat(File.c_str(), &St) != 0 || S_ISREG(St.st_mode) == 0)
201         continue;
202      List.push_back(File);
203
204   }
205   closedir(D);
206
207   sort(List.begin(), List.end());
208
209   // Read the files
210   for (vector<string>::const_iterator I = List.begin(); I != List.end();
211        I++)
212      if (ReadSourcePart(*I) == false)
213         return false;
214   return true;
215}
216
217
218bool SourcesList::ReadSources()
219{
220   //cout << "SourcesList::ReadSources() " << endl;
221
222   bool Res = true;
223
224   string Parts = _config->FindDir("Dir::Etc::sourceparts");
225   if (FileExists(Parts) == true)
226      Res &= ReadSourceDir(Parts);
227   string Main = _config->FindFile("Dir::Etc::sourcelist");
228   if (FileExists(Main) == true)
229      Res &= ReadSourcePart(Main);
230
231   return Res;
232}
233
234SourcesList::SourceRecord *SourcesList::AddEmptySource()
235{
236   SourceRecord rec;
237#ifdef HAVE_RPM
238   rec.Type = Rpm;
239#else
240   rec.Type = Deb;
241#endif
242   rec.VendorID = "";
243   rec.SourceFile = _config->FindFile("Dir::Etc::sourcelist");
244   rec.Dist = "";
245   rec.NumSections = 0;
246   return AddSourceNode(rec);
247}
248
249SourcesList::SourceRecord *SourcesList::AddSource(RecType Type,
250                                                   string VendorID, string URI,
251                                                   string Dist,
252                                                   string *Sections,
253                                                   unsigned short count,
254                                                   string SourceFile)
255{
256   SourceRecord rec;
257   rec.Type = Type;
258   rec.VendorID = VendorID;
259   rec.SourceFile = SourceFile;
260
261   if (rec.SetURI(URI) == false) {
262      return NULL;
263   }
264   rec.Dist = Dist;
265   rec.NumSections = count;
266   rec.Sections = new string[count];
267   for (unsigned int i = 0; i < count; i++)
268      rec.Sections[i] = Sections[i];
269
270   return AddSourceNode(rec);
271}
272
273void SourcesList::RemoveSource(SourceRecord *&rec)
274{
275   SourceRecords.remove(rec);
276   delete rec;
277   rec = 0;
278}
279
280void SourcesList::SwapSources( SourceRecord *&rec_one, SourceRecord *&rec_two )
281{
282  list<SourceRecord *>::iterator rec_p;
283  list<SourceRecord *>::iterator rec_n;
284
285  rec_p = find( SourceRecords.begin(), SourceRecords.end(), rec_one );
286  rec_n = find( SourceRecords.begin(), SourceRecords.end(), rec_two );
287 
288  SourceRecords.insert( rec_p, rec_two );
289  SourceRecords.erase( rec_n );
290}
291
292bool SourcesList::UpdateSources()
293{
294   list<string> filenames;
295   for (list<SourceRecord *>::iterator it = SourceRecords.begin();
296        it != SourceRecords.end(); it++) {
297      if ((*it)->SourceFile == "")
298         continue;
299      filenames.push_front((*it)->SourceFile);
300   }
301   filenames.sort();
302   filenames.unique();
303
304   for (list<string>::iterator fi = filenames.begin();
305        fi != filenames.end(); fi++) {
306      ofstream ofs((*fi).c_str(), ios::out);
307      if (!ofs != 0)
308         return false;
309
310      for (list<SourceRecord *>::iterator it = SourceRecords.begin();
311           it != SourceRecords.end(); it++) {
312         if ((*fi) != (*it)->SourceFile)
313            continue;
314         string S;
315         if (((*it)->Type & Comment) != 0) {
316            S = (*it)->Comment;
317         } else if ((*it)->URI.empty() || (*it)->Dist.empty()) {
318            continue;
319         } else {
320            if (((*it)->Type & Disabled) != 0)
321               S = "# ";
322
323            S += (*it)->GetType() + " ";
324
325            if ((*it)->VendorID.empty() == false)
326               S += "[" + (*it)->VendorID + "] ";
327
328            S += (*it)->URI + " ";
329            S += (*it)->Dist + " ";
330
331            for (unsigned int J = 0; J < (*it)->NumSections; J++)
332               S += (*it)->Sections[J] + " ";
333         }
334         ofs << S << endl;
335      }
336      ofs.close();
337   }
338   return true;
339}
340
341bool SourcesList::SourceRecord::SetType(string S)
342{
343   if (S == "deb")
344      Type |= Deb;
345   else if (S == "deb-src")
346      Type |= DebSrc;
347   else if (S == "rpm")
348      Type |= Rpm;
349   else if (S == "rpm-src")
350      Type |= RpmSrc;
351   else if (S == "rpm-dir")
352      Type |= RpmDir;
353   else if (S == "rpm-src-dir")
354      Type |= RpmSrcDir;
355   else if (S == "repomd")
356      Type |= Repomd;
357   else if (S == "repomd-src")
358      Type |= RepomdSrc;
359   else
360      return false;
361   cout << S << " settype " << (Type | Repomd) << endl;
362   return true;
363}
364
365string SourcesList::SourceRecord::GetType()
366{
367   if ((Type & Deb) != 0)
368      return "deb";
369   else if ((Type & DebSrc) != 0)
370      return "deb-src";
371   else if ((Type & Rpm) != 0)
372      return "rpm";
373   else if ((Type & RpmSrc) != 0)
374      return "rpm-src";
375   else if ((Type & RpmDir) != 0)
376      return "rpm-dir";
377   else if ((Type & RpmSrcDir) != 0)
378      return "rpm-src-dir";
379   else if ((Type & Repomd) != 0)
380      return "repomd";
381   else if ((Type & RepomdSrc) != 0)
382      return "repomd-src";
383   cout << "type " << (Type & Repomd) << endl;
384   return "unknown";
385}
386
387bool SourcesList::SourceRecord::SetURI(string S)
388{
389   if (S.empty() == true)
390      return false;
391   if (S.find(':') == string::npos)
392      return false;
393
394   S = SubstVar(S, "$(ARCH)", _config->Find("APT::Architecture"));
395   S = SubstVar(S, "$(VERSION)", _config->Find("APT::DistroVersion"));
396   URI = S;
397
398   // append a / to the end if one is not already there
399   if (URI[URI.size() - 1] != '/')
400      URI += '/';
401
402   return true;
403}
404
405SourcesList::SourceRecord &SourcesList::SourceRecord::
406operator=(const SourceRecord &rhs)
407{
408   // Needed for a proper deep copy of the record; uses the string operator= to properly copy the strings
409   Type = rhs.Type;
410   VendorID = rhs.VendorID;
411   URI = rhs.URI;
412   Dist = rhs.Dist;
413   Sections = new string[rhs.NumSections];
414   for (unsigned int I = 0; I < rhs.NumSections; I++)
415      Sections[I] = rhs.Sections[I];
416   NumSections = rhs.NumSections;
417   Comment = rhs.Comment;
418   SourceFile = rhs.SourceFile;
419
420   return *this;
421}
422
423SourcesList::VendorRecord *SourcesList::AddVendorNode(VendorRecord &rec)
424{
425   VendorRecord *newrec = new VendorRecord;
426   *newrec = rec;
427   VendorRecords.push_back(newrec);
428
429   return newrec;
430}
431
432bool SourcesList::ReadVendors()
433{
434   Configuration Cnf;
435
436   string CnfFile = _config->FindFile("Dir::Etc::vendorlist");
437   if (FileExists(CnfFile) == true)
438      if (ReadConfigFile(Cnf, CnfFile, true) == false)
439         return false;
440
441   for (list<VendorRecord *>::const_iterator I = VendorRecords.begin();
442        I != VendorRecords.end(); I++)
443      delete *I;
444   VendorRecords.clear();
445
446   // Process 'simple-key' type sections
447   const Configuration::Item *Top = Cnf.Tree("simple-key");
448   for (Top = (Top == 0 ? 0 : Top->Child); Top != 0; Top = Top->Next) {
449      Configuration Block(Top);
450      VendorRecord Vendor;
451
452      Vendor.VendorID = Top->Tag;
453      Vendor.FingerPrint = Block.Find("Fingerprint");
454      Vendor.Description = Block.Find("Name");
455
456      char *buffer = new char[Vendor.FingerPrint.length() + 1];
457      char *p = buffer;;
458      for (string::const_iterator I = Vendor.FingerPrint.begin();
459           I != Vendor.FingerPrint.end(); I++) {
460         if (*I != ' ' && *I != '\t')
461            *p++ = *I;
462      }
463      *p = 0;
464      Vendor.FingerPrint = buffer;
465      delete[]buffer;
466
467      if (Vendor.FingerPrint.empty() == true ||
468          Vendor.Description.empty() == true) {
469         _error->Error(_("Vendor block %s is invalid"),
470                       Vendor.VendorID.c_str());
471         continue;
472      }
473
474      AddVendorNode(Vendor);
475   }
476
477   return !_error->PendingError();
478}
479
480SourcesList::VendorRecord *SourcesList::AddVendor(string VendorID,
481                                                  string FingerPrint,
482                                                  string Description)
483{
484   VendorRecord rec;
485   rec.VendorID = VendorID;
486   rec.FingerPrint = FingerPrint;
487   rec.Description = Description;
488   return AddVendorNode(rec);
489}
490
491bool SourcesList::UpdateVendors()
492{
493   ofstream ofs(_config->FindFile("Dir::Etc::vendorlist").c_str(), ios::out);
494   if (!ofs != 0)
495      return false;
496
497   for (list<VendorRecord *>::iterator it = VendorRecords.begin();
498        it != VendorRecords.end(); it++) {
499      ofs << "simple-key \"" << (*it)->VendorID << "\" {" << endl;
500      ofs << "\tFingerPrint \"" << (*it)->FingerPrint << "\";" << endl;
501      ofs << "\tName \"" << (*it)->Description << "\";" << endl;
502      ofs << "}" << endl;
503   }
504
505   ofs.close();
506   return true;
507}
508
509
510void SourcesList::RemoveVendor(VendorRecord *&rec)
511{
512   VendorRecords.remove(rec);
513   delete rec;
514   rec = 0;
515}
516
517ostream &operator<<(ostream &os, const SourcesList::SourceRecord &rec)
518{
519   os << "Type: ";
520   if ((rec.Type & SourcesList::Comment) != 0)
521      os << "Comment ";
522   if ((rec.Type & SourcesList::Disabled) != 0)
523      os << "Disabled ";
524   if ((rec.Type & SourcesList::Deb) != 0)
525      os << "Deb";
526   if ((rec.Type & SourcesList::DebSrc) != 0)
527      os << "DebSrc";
528   if ((rec.Type & SourcesList::Rpm) != 0)
529      os << "Rpm";
530   if ((rec.Type & SourcesList::RpmSrc) != 0)
531      os << "RpmSrc";
532   if ((rec.Type & SourcesList::RpmDir) != 0)
533      os << "RpmDir";
534   if ((rec.Type & SourcesList::RpmSrcDir) != 0)
535      os << "RpmSrcDir";
536   if ((rec.Type & SourcesList::Repomd) != 0)
537      os << "Repomd";
538   if ((rec.Type & SourcesList::RepomdSrc) != 0)
539      os << "RepomdSrc";
540   os << endl;
541   os << "SourceFile: " << rec.SourceFile << endl;
542   os << "VendorID: " << rec.VendorID << endl;
543   os << "URI: " << rec.URI << endl;
544   os << "Dist: " << rec.Dist << endl;
545   os << "Section(s):" << endl;
546   for (unsigned int J = 0; J < rec.NumSections; J++) {
547      cout << "\t" << rec.Sections[J] << endl;
548   }
549   os << endl;
550   return os;
551}
552
553ostream &operator<<(ostream &os, const SourcesList::VendorRecord &rec)
554{
555   os << "VendorID: " << rec.VendorID << endl;
556   os << "FingerPrint: " << rec.FingerPrint << endl;
557   os << "Description: " << rec.Description << endl;
558   return os;
559}
560
561// vim:sts=4:sw=4
Note: See TracBrowser for help on using the repository browser.