]> git.saurik.com Git - apt.git/blob - apt-pkg/indexfile.cc
fad3391973dc9c49474b11453e2059d409b125dd
[apt.git] / apt-pkg / indexfile.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: indexfile.cc,v 1.2.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
5
6 Index File - Abstraction for an index of archive/souce file.
7
8 ##################################################################### */
9 /*}}}*/
10 // Include Files /*{{{*/
11 #include<config.h>
12
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/indexfile.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/fileutl.h>
17 #include <apt-pkg/aptconfiguration.h>
18 #include <apt-pkg/pkgcache.h>
19 #include <apt-pkg/pkgcachegen.h>
20 #include <apt-pkg/cacheiterators.h>
21 #include <apt-pkg/srcrecords.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/progress.h>
24 #include <apt-pkg/macros.h>
25
26 #include <apt-pkg/deblistparser.h>
27
28 #include <sys/stat.h>
29
30 #include <string>
31 #include <vector>
32 #include <clocale>
33 #include <cstring>
34 #include <memory>
35 /*}}}*/
36
37 // Global list of Item supported
38 static pkgIndexFile::Type *ItmList[10];
39 pkgIndexFile::Type **pkgIndexFile::Type::GlobalList = ItmList;
40 unsigned long pkgIndexFile::Type::GlobalListLen = 0;
41
42 // Type::Type - Constructor /*{{{*/
43 // ---------------------------------------------------------------------
44 /* */
45 pkgIndexFile::Type::Type()
46 {
47 ItmList[GlobalListLen] = this;
48 GlobalListLen++;
49 Label = NULL;
50 }
51 /*}}}*/
52 // Type::GetType - Locate the type by name /*{{{*/
53 // ---------------------------------------------------------------------
54 /* */
55 pkgIndexFile::Type *pkgIndexFile::Type::GetType(const char *Type)
56 {
57 for (unsigned I = 0; I != GlobalListLen; I++)
58 if (strcmp(GlobalList[I]->Label,Type) == 0)
59 return GlobalList[I];
60 return 0;
61 }
62 /*}}}*/
63 pkgIndexFile::pkgIndexFile(bool const Trusted) : /*{{{*/
64 d(NULL), Trusted(Trusted)
65 {
66 }
67 /*}}}*/
68 // IndexFile::ArchiveInfo - Stub /*{{{*/
69 std::string pkgIndexFile::ArchiveInfo(pkgCache::VerIterator const &/*Ver*/) const
70 {
71 return std::string();
72 }
73 /*}}}*/
74 // IndexFile::FindInCache - Stub /*{{{*/
75 pkgCache::PkgFileIterator pkgIndexFile::FindInCache(pkgCache &Cache) const
76 {
77 return pkgCache::PkgFileIterator(Cache);
78 }
79 /*}}}*/
80 // IndexFile::SourceIndex - Stub /*{{{*/
81 std::string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &/*Record*/,
82 pkgSrcRecords::File const &/*File*/) const
83 {
84 return std::string();
85 }
86 /*}}}*/
87 // IndexFile::TranslationsAvailable - Check if will use Translation /*{{{*/
88 // ---------------------------------------------------------------------
89 /* */
90 bool pkgIndexFile::TranslationsAvailable() {
91 return (APT::Configuration::getLanguages().empty() != true);
92 }
93 /*}}}*/
94 // IndexFile::CheckLanguageCode - Check the Language Code /*{{{*/
95 // ---------------------------------------------------------------------
96 /* No intern need for this method anymore as the check for correctness
97 is already done in getLanguages(). Note also that this check is
98 rather bad (doesn't take three character like ast into account).
99 TODO: Remove method with next API break */
100 APT_DEPRECATED bool pkgIndexFile::CheckLanguageCode(const char * const Lang)
101 {
102 if (strlen(Lang) == 2 || (strlen(Lang) == 5 && Lang[2] == '_'))
103 return true;
104
105 if (strcmp(Lang,"C") != 0)
106 _error->Warning("Wrong language code %s", Lang);
107
108 return false;
109 }
110 /*}}}*/
111 // IndexFile::LanguageCode - Return the Language Code /*{{{*/
112 // ---------------------------------------------------------------------
113 /* As we have now possibly more than one LanguageCode this method is
114 supersided by a) private classmembers or b) getLanguages().
115 TODO: Remove method with next API break */
116 APT_DEPRECATED std::string pkgIndexFile::LanguageCode() {
117 if (TranslationsAvailable() == false)
118 return "";
119 return APT::Configuration::getLanguages()[0];
120 }
121 /*}}}*/
122
123 // IndexTarget - Constructor /*{{{*/
124 IndexTarget::IndexTarget(std::string const &MetaKey, std::string const &ShortDesc,
125 std::string const &LongDesc, std::string const &URI, bool const IsOptional,
126 bool const KeepCompressed, std::map<std::string, std::string> const &Options) :
127 URI(URI), Description(LongDesc), ShortDesc(ShortDesc), MetaKey(MetaKey),
128 IsOptional(IsOptional), KeepCompressed(KeepCompressed), Options(Options)
129 {
130 }
131 /*}}}*/
132 std::string IndexTarget::Option(OptionKeys const EnumKey) const /*{{{*/
133 {
134 std::string Key;
135 switch (EnumKey)
136 {
137 #define APT_CASE(X) case X: Key = #X; break
138 APT_CASE(SITE);
139 APT_CASE(RELEASE);
140 APT_CASE(COMPONENT);
141 APT_CASE(LANGUAGE);
142 APT_CASE(ARCHITECTURE);
143 APT_CASE(BASE_URI);
144 APT_CASE(REPO_URI);
145 APT_CASE(TARGET_OF);
146 APT_CASE(CREATED_BY);
147 APT_CASE(PDIFFS);
148 APT_CASE(DEFAULTENABLED);
149 APT_CASE(COMPRESSIONTYPES);
150 APT_CASE(SOURCESENTRY);
151 #undef APT_CASE
152 case FILENAME: return _config->FindDir("Dir::State::lists") + URItoFileName(URI);
153 case EXISTING_FILENAME:
154 std::string const filename = Option(FILENAME);
155 std::vector<std::string> const types = VectorizeString(Option(COMPRESSIONTYPES), ' ');
156 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
157 {
158 if (t->empty())
159 continue;
160 std::string const file = (*t == "uncompressed") ? filename : (filename + "." + *t);
161 if (FileExists(file))
162 return file;
163 }
164 return "";
165 }
166 std::map<std::string,std::string>::const_iterator const M = Options.find(Key);
167 if (M == Options.end())
168 return "";
169 return M->second;
170 }
171 /*}}}*/
172 bool IndexTarget::OptionBool(OptionKeys const EnumKey) const /*{{{*/
173 {
174 return StringToBool(Option(EnumKey));
175 }
176 /*}}}*/
177 std::string IndexTarget::Format(std::string format) const /*{{{*/
178 {
179 for (std::map<std::string, std::string>::const_iterator O = Options.begin(); O != Options.end(); ++O)
180 {
181 format = SubstVar(format, std::string("$(") + O->first + ")", O->second);
182 }
183 format = SubstVar(format, "$(METAKEY)", MetaKey);
184 format = SubstVar(format, "$(SHORTDESC)", ShortDesc);
185 format = SubstVar(format, "$(DESCRIPTION)", Description);
186 format = SubstVar(format, "$(URI)", URI);
187 format = SubstVar(format, "$(FILENAME)", Option(IndexTarget::FILENAME));
188 return format;
189 }
190 /*}}}*/
191
192 pkgDebianIndexTargetFile::pkgDebianIndexTargetFile(IndexTarget const &Target, bool const Trusted) :/*{{{*/
193 pkgDebianIndexFile(Trusted), d(NULL), Target(Target)
194 {
195 }
196 /*}}}*/
197 std::string pkgDebianIndexTargetFile::ArchiveURI(std::string const &File) const/*{{{*/
198 {
199 return Target.Option(IndexTarget::REPO_URI) + File;
200 }
201 /*}}}*/
202 std::string pkgDebianIndexTargetFile::Describe(bool const Short) const /*{{{*/
203 {
204 if (Short)
205 return Target.Description;
206 return Target.Description + " (" + IndexFileName() + ")";
207 }
208 /*}}}*/
209 std::string pkgDebianIndexTargetFile::IndexFileName() const /*{{{*/
210 {
211 std::string const s = Target.Option(IndexTarget::FILENAME);
212 if (FileExists(s))
213 return s;
214
215 std::vector<std::string> const types = VectorizeString(Target.Option(IndexTarget::COMPRESSIONTYPES), ' ');
216 for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
217 {
218 std::string p = s + '.' + *t;
219 if (FileExists(p))
220 return p;
221 }
222 return s;
223 }
224 /*}}}*/
225 unsigned long pkgDebianIndexTargetFile::Size() const /*{{{*/
226 {
227 unsigned long size = 0;
228
229 /* we need to ignore errors here; if the lists are absent, just return 0 */
230 _error->PushToStack();
231
232 FileFd f(IndexFileName(), FileFd::ReadOnly, FileFd::Extension);
233 if (!f.Failed())
234 size = f.Size();
235
236 if (_error->PendingError() == true)
237 size = 0;
238 _error->RevertToStack();
239
240 return size;
241 }
242 /*}}}*/
243 bool pkgDebianIndexTargetFile::Exists() const /*{{{*/
244 {
245 return FileExists(IndexFileName());
246 }
247 /*}}}*/
248 std::string pkgDebianIndexTargetFile::GetArchitecture() const /*{{{*/
249 {
250 return Target.Option(IndexTarget::ARCHITECTURE);
251 }
252 /*}}}*/
253 std::string pkgDebianIndexTargetFile::GetComponent() const /*{{{*/
254 {
255 return Target.Option(IndexTarget::COMPONENT);
256 }
257 /*}}}*/
258 bool pkgDebianIndexTargetFile::OpenListFile(FileFd &Pkg, std::string const &FileName)/*{{{*/
259 {
260 if (Pkg.Open(FileName, FileFd::ReadOnly, FileFd::Extension) == false)
261 return _error->Error("Problem opening %s",FileName.c_str());
262 return true;
263 }
264 /*}}}*/
265 std::string pkgDebianIndexTargetFile::GetProgressDescription() const
266 {
267 return Target.Description;
268 }
269
270 pkgDebianIndexRealFile::pkgDebianIndexRealFile(std::string const &pFile, bool const Trusted) :/*{{{*/
271 pkgDebianIndexFile(Trusted), d(NULL)
272 {
273 if (pFile == "/nonexistent/stdin")
274 File = pFile;
275 else
276 File = flAbsPath(pFile);
277 }
278 /*}}}*/
279 // IndexRealFile::Size - Return the size of the index /*{{{*/
280 unsigned long pkgDebianIndexRealFile::Size() const
281 {
282 struct stat S;
283 if (stat(File.c_str(),&S) != 0)
284 return 0;
285 return S.st_size;
286 }
287 /*}}}*/
288 bool pkgDebianIndexRealFile::Exists() const /*{{{*/
289 {
290 return FileExists(File);
291 }
292 /*}}}*/
293 std::string pkgDebianIndexRealFile::Describe(bool const /*Short*/) const/*{{{*/
294 {
295 return File;
296 }
297 /*}}}*/
298 std::string pkgDebianIndexRealFile::ArchiveURI(std::string const &/*File*/) const/*{{{*/
299 {
300 return "file:" + File;
301 }
302 /*}}}*/
303 std::string pkgDebianIndexRealFile::IndexFileName() const /*{{{*/
304 {
305 return File;
306 }
307 /*}}}*/
308 std::string pkgDebianIndexRealFile::GetProgressDescription() const
309 {
310 return File;
311 }
312 bool pkgDebianIndexRealFile::OpenListFile(FileFd &Pkg, std::string const &FileName)/*{{{*/
313 {
314 if (Pkg.Open(FileName, FileFd::ReadOnly, FileFd::None) == false)
315 return _error->Error("Problem opening %s",FileName.c_str());
316 return true;
317 }
318 /*}}}*/
319
320 pkgDebianIndexFile::pkgDebianIndexFile(bool const Trusted) : pkgIndexFile(Trusted)
321 {
322 }
323 pkgDebianIndexFile::~pkgDebianIndexFile()
324 {
325 }
326 pkgCacheListParser * pkgDebianIndexFile::CreateListParser(FileFd &Pkg)
327 {
328 if (Pkg.IsOpen() == false)
329 return NULL;
330 _error->PushToStack();
331 pkgCacheListParser * const Parser = new debListParser(&Pkg);
332 bool const newError = _error->PendingError();
333 _error->MergeWithStack();
334 return newError ? NULL : Parser;
335 }
336 bool pkgDebianIndexFile::Merge(pkgCacheGenerator &Gen,OpProgress * const Prog)
337 {
338 std::string const PackageFile = IndexFileName();
339 FileFd Pkg;
340 if (OpenListFile(Pkg, PackageFile) == false)
341 return false;
342 _error->PushToStack();
343 std::unique_ptr<pkgCacheListParser> Parser(CreateListParser(Pkg));
344 bool const newError = _error->PendingError();
345 _error->MergeWithStack();
346 if (newError == false && Parser == nullptr)
347 return true;
348 if (Parser == NULL)
349 return false;
350
351 if (Prog != NULL)
352 Prog->SubProgress(0, GetProgressDescription());
353
354 if (Gen.SelectFile(PackageFile, *this, GetArchitecture(), GetComponent(), GetIndexFlags()) == false)
355 return _error->Error("Problem with SelectFile %s",PackageFile.c_str());
356
357 // Store the IMS information
358 pkgCache::PkgFileIterator File = Gen.GetCurFile();
359 pkgCacheGenerator::Dynamic<pkgCache::PkgFileIterator> DynFile(File);
360 File->Size = Pkg.FileSize();
361 File->mtime = Pkg.ModificationTime();
362
363 if (Gen.MergeList(*Parser) == false)
364 return _error->Error("Problem with MergeList %s",PackageFile.c_str());
365 return true;
366 }
367 pkgCache::PkgFileIterator pkgDebianIndexFile::FindInCache(pkgCache &Cache) const
368 {
369 std::string const FileName = IndexFileName();
370 pkgCache::PkgFileIterator File = Cache.FileBegin();
371 for (; File.end() == false; ++File)
372 {
373 if (File.FileName() == NULL || FileName != File.FileName())
374 continue;
375
376 struct stat St;
377 if (stat(File.FileName(),&St) != 0)
378 {
379 if (_config->FindB("Debug::pkgCacheGen", false))
380 std::clog << "DebianIndexFile::FindInCache - stat failed on " << File.FileName() << std::endl;
381 return pkgCache::PkgFileIterator(Cache);
382 }
383 if ((map_filesize_t)St.st_size != File->Size || St.st_mtime != File->mtime)
384 {
385 if (_config->FindB("Debug::pkgCacheGen", false))
386 std::clog << "DebianIndexFile::FindInCache - size (" << St.st_size << " <> " << File->Size
387 << ") or mtime (" << St.st_mtime << " <> " << File->mtime
388 << ") doesn't match for " << File.FileName() << std::endl;
389 return pkgCache::PkgFileIterator(Cache);
390 }
391 return File;
392 }
393
394 return File;
395 }
396
397 APT_CONST pkgIndexFile::~pkgIndexFile() {}
398 APT_CONST pkgDebianIndexTargetFile::~pkgDebianIndexTargetFile() {}
399 APT_CONST pkgDebianIndexRealFile::~pkgDebianIndexRealFile() {}