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