]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/debsrcrecords.cc
5454d79c3de9164f0a7d12f842fa69840f7581c6
[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 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 /*}}}*/
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
58 reused by the next Binaries function call. This function is commonly
59 used during scanning to find the right package */
60 const char **debSrcRecordParser::Binaries()
61 {
62 const char *Start, *End;
63 if (Sect.Find("Binary", Start, End) == false)
64 return NULL;
65 for (; isspace_ascii(*Start) != 0; ++Start);
66 if (Start >= End)
67 return NULL;
68
69 StaticBinList.clear();
70 free(Buffer);
71 Buffer = strndup(Start, End - Start);
72
73 char* bin = Buffer;
74 do {
75 char* binStartNext = strchrnul(bin, ',');
76 char* binEnd = binStartNext - 1;
77 for (; isspace_ascii(*binEnd) != 0; --binEnd)
78 binEnd = 0;
79 StaticBinList.push_back(bin);
80 if (*binStartNext != ',')
81 break;
82 *binStartNext = '\0';
83 for (bin = binStartNext + 1; isspace_ascii(*bin) != 0; ++bin)
84 ;
85 } while (*bin != '\0');
86 StaticBinList.push_back(NULL);
87
88 return &StaticBinList[0];
89 }
90 /*}}}*/
91 // SrcRecordParser::BuildDepends - Return the Build-Depends information /*{{{*/
92 // ---------------------------------------------------------------------
93 /* This member parses the build-depends information and returns a list of
94 package/version records representing the build dependency. The returned
95 array need not be freed and will be reused by the next call to this
96 function */
97 bool debSrcRecordParser::BuildDepends(std::vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps,
98 bool const &ArchOnly, bool const &StripMultiArch)
99 {
100 unsigned int I;
101 const char *Start, *Stop;
102 BuildDepRec rec;
103 const char *fields[] = {"Build-Depends",
104 "Build-Depends-Indep",
105 "Build-Conflicts",
106 "Build-Conflicts-Indep"};
107
108 BuildDeps.clear();
109
110 for (I = 0; I < 4; I++)
111 {
112 if (ArchOnly && (I == 1 || I == 3))
113 continue;
114
115 if (Sect.Find(fields[I], Start, Stop) == false)
116 continue;
117
118 while (1)
119 {
120 Start = debListParser::ParseDepends(Start, Stop,
121 rec.Package,rec.Version,rec.Op,true,StripMultiArch,true);
122
123 if (Start == 0)
124 return _error->Error("Problem parsing dependency: %s", fields[I]);
125 rec.Type = I;
126
127 if (rec.Package != "")
128 BuildDeps.push_back(rec);
129
130 if (Start == Stop)
131 break;
132 }
133 }
134
135 return true;
136 }
137 /*}}}*/
138 // SrcRecordParser::Files - Return a list of files for this source /*{{{*/
139 // ---------------------------------------------------------------------
140 /* This parses the list of files and returns it, each file is required to have
141 a complete source package */
142 bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &F)
143 {
144 std::vector<pkgSrcRecords::File2> F2;
145 if (Files2(F2) == false)
146 return false;
147 for (std::vector<pkgSrcRecords::File2>::const_iterator f2 = F2.begin(); f2 != F2.end(); ++f2)
148 {
149 pkgSrcRecords::File2 f;
150 #if __GNUC__ >= 4
151 #pragma GCC diagnostic push
152 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
153 #endif
154 f.MD5Hash = f2->MD5Hash;
155 f.Size = f2->Size;
156 #if __GNUC__ >= 4
157 #pragma GCC diagnostic pop
158 #endif
159 f.Path = f2->Path;
160 f.Type = f2->Type;
161 F.push_back(f);
162 }
163 return true;
164 }
165 bool debSrcRecordParser::Files2(std::vector<pkgSrcRecords::File2> &List)
166 {
167 List.clear();
168
169 // Stash the / terminated directory prefix
170 string Base = Sect.FindS("Directory");
171 if (Base.empty() == false && Base[Base.length()-1] != '/')
172 Base += '/';
173
174 std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions();
175
176 for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
177 {
178 // derive field from checksum type
179 std::string checksumField("Checksums-");
180 if (strcmp(*type, "MD5Sum") == 0)
181 checksumField = "Files"; // historic name for MD5 checksums
182 else
183 checksumField.append(*type);
184
185 string const Files = Sect.FindS(checksumField.c_str());
186 if (Files.empty() == true)
187 continue;
188
189 // Iterate over the entire list grabbing each triplet
190 const char *C = Files.c_str();
191 while (*C != 0)
192 {
193 string hash, size, path;
194
195 // Parse each of the elements
196 if (ParseQuoteWord(C, hash) == false ||
197 ParseQuoteWord(C, size) == false ||
198 ParseQuoteWord(C, path) == false)
199 return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
200
201 if (iIndex == nullptr && checksumField == "Files")
202 {
203 // the Files field has a different format than the rest in deb-changes files
204 std::string ignore;
205 if (ParseQuoteWord(C, ignore) == false ||
206 ParseQuoteWord(C, path) == false)
207 return _error->Error("Error parsing file record in %s of source package %s", checksumField.c_str(), Package().c_str());
208 }
209
210 HashString const hashString(*type, hash);
211 if (Base.empty() == false)
212 path = Base + path;
213
214 // look if we have a record for this file already
215 std::vector<pkgSrcRecords::File2>::iterator file = List.begin();
216 for (; file != List.end(); ++file)
217 if (file->Path == path)
218 break;
219
220 // we have it already, store the new hash and be done
221 if (file != List.end())
222 {
223 if (checksumField == "Files")
224 APT_IGNORE_DEPRECATED(file->MD5Hash = hash;)
225 // an error here indicates that we have two different hashes for the same file
226 if (file->Hashes.push_back(hashString) == false)
227 return _error->Error("Error parsing checksum in %s of source package %s", checksumField.c_str(), Package().c_str());
228 continue;
229 }
230
231 // we haven't seen this file yet
232 pkgSrcRecords::File2 F;
233 F.Path = path;
234 F.FileSize = strtoull(size.c_str(), NULL, 10);
235 F.Hashes.push_back(hashString);
236 F.Hashes.FileSize(F.FileSize);
237
238 APT_IGNORE_DEPRECATED_PUSH
239 F.Size = F.FileSize;
240 if (checksumField == "Files")
241 F.MD5Hash = hash;
242 APT_IGNORE_DEPRECATED_POP
243
244 // Try to guess what sort of file it is we are getting.
245 string::size_type Pos = F.Path.length()-1;
246 while (1)
247 {
248 string::size_type Tmp = F.Path.rfind('.',Pos);
249 if (Tmp == string::npos)
250 break;
251 if (F.Type == "tar") {
252 // source v3 has extension 'debian.tar.*' instead of 'diff.*'
253 if (string(F.Path, Tmp+1, Pos-Tmp) == "debian")
254 F.Type = "diff";
255 break;
256 }
257 F.Type = string(F.Path,Tmp+1,Pos-Tmp);
258
259 if (std::find(compExts.begin(), compExts.end(), std::string(".").append(F.Type)) != compExts.end() ||
260 F.Type == "tar")
261 {
262 Pos = Tmp-1;
263 continue;
264 }
265
266 break;
267 }
268 List.push_back(F);
269 }
270 }
271
272 return true;
273 }
274 /*}}}*/
275 // SrcRecordParser::~SrcRecordParser - Destructor /*{{{*/
276 // ---------------------------------------------------------------------
277 /* */
278 debSrcRecordParser::~debSrcRecordParser()
279 {
280 // was allocated via strndup()
281 free(Buffer);
282 }
283 /*}}}*/
284
285
286 debDscRecordParser::debDscRecordParser(std::string const &DscFile, pkgIndexFile const *Index)
287 : debSrcRecordParser("", Index)
288 {
289 // support clear signed files
290 if (OpenMaybeClearSignedFile(DscFile, Fd) == false)
291 {
292 _error->Error("Failed to open %s", DscFile.c_str());
293 return;
294 }
295
296 // re-init to ensure the updated Fd is used
297 Tags.Init(&Fd, pkgTagFile::SUPPORT_COMMENTS);
298 // read the first (and only) record
299 Step();
300
301 }