]> git.saurik.com Git - apt.git/blame - apt-pkg/deb/debsrcrecords.cc
Bug #807012 also involves package dependencies :/.
[apt.git] / apt-pkg / deb / debsrcrecords.cc
CommitLineData
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 32using std::max;
8f3ba4e8
DK
33using std::string;
34
c8a4ce6c 35debSrcRecordParser::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
44std::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
60const 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 100bool 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 147bool 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}
170bool 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/* */
283debSrcRecordParser::~debSrcRecordParser()
284{
7f48c4df
MV
285 // was allocated via strndup()
286 free(Buffer);
7a9f09bd
MV
287}
288 /*}}}*/
feab34c5
MV
289
290
a49e7948 291debDscRecordParser::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}