]> git.saurik.com Git - apt.git/blob - apt-pkg/deb/debsrcrecords.cc
correct cross & disappear progress detection
[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 // 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 }
82 StaticBinList.push_back(bin);
83 if (*binStartNext != ',')
84 break;
85 *binStartNext = '\0';
86 for (bin = binStartNext + 1; isspace_ascii(*bin) != 0; ++bin)
87 ;
88 } while (*bin != '\0');
89 StaticBinList.push_back(NULL);
90
91 return &StaticBinList[0];
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 */
100 bool debSrcRecordParser::BuildDepends(std::vector<pkgSrcRecords::Parser::BuildDepRec> &BuildDeps,
101 bool const &ArchOnly, bool const &StripMultiArch)
102 {
103 unsigned int I;
104 const char *Start, *Stop;
105 BuildDepRec rec;
106 const char *fields[] = {"Build-Depends",
107 "Build-Depends-Indep",
108 "Build-Conflicts",
109 "Build-Conflicts-Indep",
110 "Build-Depends-Arch",
111 "Build-Conflicts-Arch"};
112
113 BuildDeps.clear();
114
115 for (I = 0; I < 6; I++)
116 {
117 if (ArchOnly && (I == 1 || I == 3))
118 continue;
119
120 if (Sect.Find(fields[I], Start, Stop) == false)
121 continue;
122
123 while (1)
124 {
125 Start = debListParser::ParseDepends(Start, Stop,
126 rec.Package,rec.Version,rec.Op,true,StripMultiArch,true);
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 }
138 }
139
140 return true;
141 }
142 /*}}}*/
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 */
147 bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &F)
148 {
149 std::vector<pkgSrcRecords::File2> F2;
150 if (Files2(F2) == false)
151 return false;
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();
173
174 // Stash the / terminated directory prefix
175 string Base = Sect.FindS("Directory");
176 if (Base.empty() == false && Base[Base.length()-1] != '/')
177 Base += '/';
178
179 std::vector<std::string> const compExts = APT::Configuration::getCompressorExtensions();
180
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;
193
194 // Iterate over the entire list grabbing each triplet
195 const char *C = Files.c_str();
196 while (*C != 0)
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
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
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
220 std::vector<pkgSrcRecords::File2>::iterator file = List.begin();
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 {
228 if (checksumField == "Files")
229 APT_IGNORE_DEPRECATED(file->MD5Hash = hash;)
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
237 pkgSrcRecords::File2 F;
238 F.Path = path;
239 F.FileSize = strtoull(size.c_str(), NULL, 10);
240 F.Hashes.push_back(hashString);
241 F.Hashes.FileSize(F.FileSize);
242
243 APT_IGNORE_DEPRECATED_PUSH
244 F.Size = F.FileSize;
245 if (checksumField == "Files")
246 F.MD5Hash = hash;
247 APT_IGNORE_DEPRECATED_POP
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);
274 }
275 }
276
277 return true;
278 }
279 /*}}}*/
280 // SrcRecordParser::~SrcRecordParser - Destructor /*{{{*/
281 // ---------------------------------------------------------------------
282 /* */
283 debSrcRecordParser::~debSrcRecordParser()
284 {
285 // was allocated via strndup()
286 free(Buffer);
287 }
288 /*}}}*/
289
290
291 debDscRecordParser::debDscRecordParser(std::string const &DscFile, pkgIndexFile const *Index)
292 : debSrcRecordParser("", Index)
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
302 Tags.Init(&Fd, pkgTagFile::SUPPORT_COMMENTS);
303 // read the first (and only) record
304 Step();
305
306 }