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