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