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