]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/debsrcrecords.cc
Switch performance critical code to use APT::StringView
[apt.git] / apt-pkg / deb / debsrcrecords.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: debsrcrecords.cc,v 1.6 2004/03/17 05:58:54 mdz Exp $
4 /* ######################################################################
5
6 Debian Source Package Records - Parser implementation for Debian style
7 source indexes
8
9 ##################################################################### */
10 /*}}}*/
11 // Include Files /*{{{*/
12 #include <config.h>
13
14 #include <apt-pkg/deblistparser.h>
15 #include <apt-pkg/debsrcrecords.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/aptconfiguration.h>
19 #include <apt-pkg/srcrecords.h>
20 #include <apt-pkg/tagfile.h>
21 #include <apt-pkg/hashes.h>
22 #include <apt-pkg/gpgv.h>
23
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <algorithm>
28 #include <string>
29 #include <vector>
30 /*}}}*/
31
32 using std::max;
33 using std::string;
34
35 debSrcRecordParser::debSrcRecordParser(std::string const &File,pkgIndexFile const *Index)
36 : Parser(Index), d(NULL), Tags(&Fd), iOffset(0), Buffer(NULL)
37 {
38 if (File.empty() == false)
39 {
40 if (Fd.Open(File, FileFd::ReadOnly, FileFd::Extension))
41 Tags.Init(&Fd, 102400);
42 }
43 }
44
45 // SrcRecordParser::Binaries - Return the binaries field /*{{{*/
46 // ---------------------------------------------------------------------
47 /* This member parses the binaries field into a pair of class arrays and
48 returns a list of strings representing all of the components of the
49 binaries field. The returned array need not be freed and will be
50 reused by the next Binaries function call. This function is commonly
51 used during scanning to find the right package */
52 const char **debSrcRecordParser::Binaries()
53 {
54 const char *Start, *End;
55 if (Sect.Find("Binary", Start, End) == false)
56 return NULL;
57 for (; isspace_ascii(*Start) != 0; ++Start);
58 if (Start >= End)
59 return NULL;
60
61 StaticBinList.clear();
62 free(Buffer);
63 Buffer = strndup(Start, End - Start);
64
65 char* bin = Buffer;
66 do {
67 char* binStartNext = strchrnul(bin, ',');
68 char* binEnd = binStartNext - 1;
69 for (; isspace_ascii(*binEnd) != 0; --binEnd)
70 binEnd = 0;
71 StaticBinList.push_back(bin);
72 if (*binStartNext != ',')
73 break;
74 *binStartNext = '\0';
75 for (bin = binStartNext + 1; isspace_ascii(*bin) != 0; ++bin)
76 ;
77 } while (*bin != '\0');
78 StaticBinList.push_back(NULL);
79
80 return &StaticBinList[0];
81 }
82 /*}}}*/
83 // SrcRecordParser::BuildDepends - Return the Build-Depends information /*{{{*/
84 // ---------------------------------------------------------------------
85 /* This member parses the build-depends information and returns a list of
86 package/version records representing the build dependency. The returned
87 array need not be freed and will be reused by the next call to this
88 function */
89 bool debSrcRecordParser::BuildDepends(std::vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps,
90 bool const &ArchOnly, bool const &StripMultiArch)
91 {
92 unsigned int I;
93 const char *Start, *Stop;
94 BuildDepRec rec;
95 const char *fields[] = {"Build-Depends",
96 "Build-Depends-Indep",
97 "Build-Conflicts",
98 "Build-Conflicts-Indep"};
99
100 BuildDeps.clear();
101
102 for (I = 0; I < 4; I++)
103 {
104 if (ArchOnly && (I == 1 || I == 3))
105 continue;
106
107 if (Sect.Find(fields[I], Start, Stop) == false)
108 continue;
109
110 while (1)
111 {
112 Start = debListParser::ParseDepends(Start, Stop,
113 rec.Package,rec.Version,rec.Op,true,StripMultiArch,true);
114
115 if (Start == 0)
116 return _error->Error("Problem parsing dependency: %s", fields[I]);
117 rec.Type = I;
118
119 if (rec.Package != "")
120 BuildDeps.push_back(rec);
121
122 if (Start == Stop)
123 break;
124 }
125 }
126
127 return true;
128 }
129 /*}}}*/
130 // SrcRecordParser::Files - Return a list of files for this source /*{{{*/
131 // ---------------------------------------------------------------------
132 /* This parses the list of files and returns it, each file is required to have
133 a complete source package */
134 bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &F)
135 {
136 std::vector<pkgSrcRecords::File2> F2;
137 if (Files2(F2) == false)
138 return false;
139 for (std::vector<pkgSrcRecords::File2>::const_iterator f2 = F2.begin(); f2 != F2.end(); ++f2)
140 {
141 pkgSrcRecords::File2 f;
142 #if __GNUC__ >= 4
143 #pragma GCC diagnostic push
144 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
145 #endif
146 f.MD5Hash = f2->MD5Hash;
147 f.Size = f2->Size;
148 #if __GNUC__ >= 4
149 #pragma GCC diagnostic pop
150 #endif
151 f.Path = f2->Path;
152 f.Type = f2->Type;
153 F.push_back(f);
154 }
155 return true;
156 }
157 bool debSrcRecordParser::Files2(std::vector<pkgSrcRecords::File2> &List)
158 {
159 List.clear();
160
161 // Stash the / terminated directory prefix
162 string Base = Sect.FindS("Directory");
163 if (Base.empty() == false && Base[Base.length()-1] != '/')
164 Base += '/';
165
166 std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions();
167
168 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
169 {
170 // derive field from checksum type
171 std::string checksumField("Checksums-");
172 if (strcmp(*type, "MD5Sum") == 0)
173 checksumField = "Files"; // historic name for MD5 checksums
174 else
175 checksumField.append(*type);
176
177 string const Files = Sect.FindS(checksumField.c_str());
178 if (Files.empty() == true)
179 continue;
180
181 // Iterate over the entire list grabbing each triplet
182 const char *C = Files.c_str();
183 while (*C != 0)
184 {
185 string hash, size, path;
186
187 // Parse each of the elements
188 if (ParseQuoteWord(C, hash) == false ||
189 ParseQuoteWord(C, size) == false ||
190 ParseQuoteWord(C, path) == false)
191 return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
192
193 HashString const hashString(*type, hash);
194 if (Base.empty() == false)
195 path = Base + path;
196
197 // look if we have a record for this file already
198 std::vector<pkgSrcRecords::File2>::iterator file = List.begin();
199 for (; file != List.end(); ++file)
200 if (file->Path == path)
201 break;
202
203 // we have it already, store the new hash and be done
204 if (file != List.end())
205 {
206 if (checksumField == "Files")
207 APT_IGNORE_DEPRECATED(file->MD5Hash = hash;)
208 // an error here indicates that we have two different hashes for the same file
209 if (file->Hashes.push_back(hashString) == false)
210 return _error->Error("Error parsing checksum in %s of source package %s", checksumField.c_str(), Package().c_str());
211 continue;
212 }
213
214 // we haven't seen this file yet
215 pkgSrcRecords::File2 F;
216 F.Path = path;
217 F.FileSize = strtoull(size.c_str(), NULL, 10);
218 F.Hashes.push_back(hashString);
219
220 APT_IGNORE_DEPRECATED_PUSH
221 F.Size = F.FileSize;
222 if (checksumField == "Files")
223 F.MD5Hash = hash;
224 APT_IGNORE_DEPRECATED_POP
225
226 // Try to guess what sort of file it is we are getting.
227 string::size_type Pos = F.Path.length()-1;
228 while (1)
229 {
230 string::size_type Tmp = F.Path.rfind('.',Pos);
231 if (Tmp == string::npos)
232 break;
233 if (F.Type == "tar") {
234 // source v3 has extension 'debian.tar.*' instead of 'diff.*'
235 if (string(F.Path, Tmp+1, Pos-Tmp) == "debian")
236 F.Type = "diff";
237 break;
238 }
239 F.Type = string(F.Path,Tmp+1,Pos-Tmp);
240
241 if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() ||
242 F.Type == "tar")
243 {
244 Pos = Tmp-1;
245 continue;
246 }
247
248 break;
249 }
250 List.push_back(F);
251 }
252 }
253
254 return true;
255 }
256 /*}}}*/
257 // SrcRecordParser::~SrcRecordParser - Destructor /*{{{*/
258 // ---------------------------------------------------------------------
259 /* */
260 debSrcRecordParser::~debSrcRecordParser()
261 {
262 // was allocated via strndup()
263 free(Buffer);
264 }
265 /*}}}*/
266
267
268 debDscRecordParser::debDscRecordParser(std::string const &DscFile, pkgIndexFile const *Index)
269 : debSrcRecordParser("", Index)
270 {
271 // support clear signed files
272 if (OpenMaybeClearSignedFile(DscFile, Fd) == false)
273 {
274 _error->Error("Failed to open %s", DscFile.c_str());
275 return;
276 }
277
278 // re-init to ensure the updated Fd is used
279 Tags.Init(&Fd, pkgTagFile::SUPPORT_COMMENTS);
280 // read the first (and only) record
281 Step();
282
283 }