libzypp 17.38.10
ContentFileReader.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12#include <iostream>
13#include <sstream>
14
15#include <zypp/ZYppCallbacks.h>
19#include <zypp-core/base/UserRequestException>
20#include <zypp-core/parser/ParseException>
21
24
25using std::endl;
26#undef ZYPP_BASE_LOGGER_LOGGROUP
27#define ZYPP_BASE_LOGGER_LOGGROUP "parser::susetags"
28
30namespace zypp
31{
33 namespace parser
34 {
36 namespace susetags
37 {
38
39 namespace {
40 // Take care the parsed pathnames do not
41 // refer to locations outside the repo!
42 Pathname sanitize( Pathname path_r )
43 {
44 Pathname ret = path_r.absolutename(); // strips leading ../s.
45 if ( path_r.relativeDotDot() ) {
46 // Don't accept downloadable data outside repo root
47 JobReport::warning( str::sconcat( "Content file: hostile location ",path_r," => ", ret ) );
48 pWAR( "Hostile location:", path_r, "=>", ret );
49 }
50 return ret;
51 }
52
53 std::string sanitizeEntry( Pathname path_r )
54 {
55 if ( path_r.empty() )
56 return {};
57 // HASH SHA1 d423ad41e93a51195a6264961e4a074c6d89359d boot/../x86_64/bind => x86_64/bind
58 // HASH SHA1 d423ad41e93a51195a6264961e4a074c6d89359d boot/../../x86_64/bind => ../* discarded
59 // Turning it into a Pathname normalizes the representation.
60 if ( path_r.relativeDotDot() ) {
61 // Don't accept downloadable data outside repo root
62 JobReport::warning( str::sconcat( "Content file: hostile location ",path_r," => discard data entry" ) );
63 pWAR( "Hostile location:", path_r, "=>", "discard data entry" );
64 return {};
65 }
66 return path_r.asString().substr( path_r.absolute() ? 1 : 2 ); // skip leading "/" or "./"
67 }
68 }
69
71 //
72 // CLASS NAME : ContentFileReader::Impl
73 //
76 {
77 public:
79 {}
80
82 {
83 if ( !_repoindex )
85 return *_repoindex;
86 }
87
88 bool hasRepoIndex() const
89 { return _repoindex != nullptr; }
90
91 RepoIndex_Ptr handoutRepoIndex()
92 {
93 RepoIndex_Ptr ret;
94 ret.swap( _repoindex );
95 _repoindex = nullptr;
96 return ret;
97 }
98
99 public:
100 bool setFileCheckSum( std::map<std::string, CheckSum> & map_r, const std::string & value ) const
101 {
102 bool error = false;
103 std::vector<std::string> words;
104 if ( str::split( value, std::back_inserter( words ) ) == 3 )
105 {
106 std::string pathstr = sanitizeEntry( words[2] );
107 if ( not pathstr.empty() )
108 map_r[std::move(pathstr)] = CheckSum( words[0], words[1] );
109 }
110 else
111 {
112 error = true;
113 }
114 return error;
115 }
116
117 public:
118 std::string _inputname;
119
120 private:
121 RepoIndex_Ptr _repoindex;
122 };
123
124
126 //
127 // CLASS NAME : ContentFileReader
128 //
130
132 //
133 // METHOD NAME : ContentFileReader::ContentFileReader
134 // METHOD TYPE : Ctor
135 //
138
140 //
141 // METHOD NAME : ContentFileReader::~ContentFileReader
142 // METHOD TYPE : Dtor
143 //
146
148 //
149 // METHOD NAME : ContentFileReader::beginParse
150 // METHOD TYPE : void
151 //
153 {
154 _pimpl.reset( new Impl() );
155 // actually mandatory, but in case they were forgotten...
156 _pimpl->repoindex().descrdir = "suse/setup/descr";
157 _pimpl->repoindex().datadir = "suse";
158 }
159
161 //
162 // METHOD NAME : ContentFileReader::endParse
163 // METHOD TYPE : void
164 //
166 {
167 // consume oldData
168 if ( _pimpl->hasRepoIndex() )
169 {
170 if ( _repoIndexConsumer )
171 _repoIndexConsumer( _pimpl->handoutRepoIndex() );
172 }
173
174 MIL << "[Content]" << endl;
175 _pimpl.reset();
176 }
177
179 //
180 // METHOD NAME : ContentFileReader::userRequestedAbort
181 // METHOD TYPE : void
182 //
184 {
185 ZYPP_THROW( AbortRequestException( errPrefix( lineNo_r ) ) );
186 }
187
189 //
190 // METHOD NAME : ContentFileReader::errPrefix
191 // METHOD TYPE : std::string
192 //
193 std::string ContentFileReader::errPrefix( unsigned lineNo_r,
194 const std::string & msg_r,
195 const std::string & line_r ) const
196 {
197 return str::form( "%s:%u:%s | %s",
198 _pimpl->_inputname.c_str(),
199 lineNo_r,
200 line_r.c_str(),
201 msg_r.c_str() );
202 }
203
205 //
206 // METHOD NAME : ContentFileReader::parse
207 // METHOD TYPE : void
208 //
210 const ProgressData::ReceiverFnc & fnc_r )
211 {
212 MIL << "Start parsing content repoindex" << input_r << endl;
213 if ( ! input_r.stream() )
214 {
215 std::ostringstream s;
216 s << "Can't read bad stream: " << input_r;
217 ZYPP_THROW( ParseException( s.str() ) );
218 }
219 beginParse();
220 _pimpl->_inputname = input_r.name();
221
222 ProgressData ticks( makeProgressData( input_r ) );
223 ticks.sendTo( fnc_r );
224 if ( ! ticks.toMin() )
226
227 iostr::EachLine line( input_r );
228 for( ; line; line.next() )
229 {
230 // strip 1st word from line to separate tag and value.
231 std::string value( *line );
232 std::string key( str::stripFirstWord( value, /*ltrim_first*/true ) );
233
234 if ( key.empty() || *key.c_str() == '#' ) // empty or comment line
235 {
236 continue;
237 }
238
239 // strip modifier if exists
240 std::string modifier;
241 std::string::size_type pos = key.rfind( '.' );
242 if ( pos != std::string::npos )
243 {
244 modifier = key.substr( pos+1 );
245 key.erase( pos );
246 }
247
248 //
249 // ReppoIndex related data:
250 //
251 else if ( key == "DESCRDIR" )
252 {
253 _pimpl->repoindex().descrdir = sanitize( value );
254 }
255 else if ( key == "DATADIR" )
256 {
257 _pimpl->repoindex().datadir = sanitize( value );
258 }
259 else if ( key == "KEY" )
260 {
261 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().signingKeys, value ) )
262 {
263 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [KEY algorithm checksum filename]", *line ) ) );
264 }
265 }
266 else if ( key == "META" )
267 {
268 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().metaFileChecksums, value ) )
269 {
270 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
271 }
272 }
273 else if ( key == "HASH" )
274 {
275 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().mediaFileChecksums, value ) )
276 {
277 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
278 }
279 }
280 else
281 {
282 DBG << errPrefix( line.lineNo(), "ignored", *line ) << endl;
283 }
284
285
286 if ( ! ticks.set( input_r.stream().tellg() ) )
287 userRequestedAbort( line.lineNo() );
288 }
289
290 //
291 // post processing
292 //
293 if ( ! ticks.toMax() )
294 userRequestedAbort( line.lineNo() );
295
296 endParse();
297 MIL << "Done parsing " << input_r << endl;
298 }
299
301 } // namespace susetags
302
304 } // namespace parser
307} // namespace zypp
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define pWAR
Definition LogTools.h:316
#define DBG
Definition Logger.h:102
#define MIL
Definition Logger.h:103
Helper to create and pass std::istream.
Definition inputstream.h:57
const std::string & name() const
Name of the std::istream.
std::istream & stream() const
The std::istream.
Definition inputstream.h:93
Maintain [min,max] and counter (value) for progress counting.
void sendTo(const ReceiverFnc &fnc_r)
Set ReceiverFnc.
bool toMax()
Set counter value to current max value (unless no range).
function< bool(const ProgressData &)> ReceiverFnc
Most simple version of progress reporting The percentage in most cases.
bool toMin()
Set counter value to current min value.
bool set(value_type val_r)
Set new counter value.
bool relativeDotDot() const
Test for a relative path referring to ../.
Definition Pathname.h:124
bool absolute() const
Test for an absolute path.
Definition Pathname.h:119
const std::string & asString() const
String representation.
Definition Pathname.h:94
bool empty() const
Test for an empty path.
Definition Pathname.h:117
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition Pathname.h:148
Simple lineparser: Traverse each line in a file.
Definition IOStream.h:113
unsigned lineNo() const
Return the current line number.
Definition IOStream.h:127
bool next()
Advance to next line.
Definition IOStream.cc:72
virtual void userRequestedAbort(unsigned lineNo_r)
Called when user(callback) request to abort.
virtual void parse(const InputStream &imput_r, const ProgressData::ReceiverFnc &fnc_r=ProgressData::ReceiverFnc())
Parse the stream.
virtual void endParse()
Called when the parse is done.
std::string errPrefix(unsigned lineNo_r, const std::string &msg_r=std::string(), const std::string &line_r="-") const
Prefix exception message with line information.
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
virtual void beginParse()
Called when start parsing.
Repository content data (from /content file).
Definition RepoIndex.h:49
std::string stripFirstWord(std::string &line, const bool ltrim_first)
Definition String.cc:266
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:39
unsigned split(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=" \t", const Trim trim_r=NO_TRIM)
Split line_r into words.
Definition String.h:602
std::string sconcat(Args &&... args)
Concat words as string.
Definition LogTools.h:276
Easy-to use interface to the ZYPP dependency resolver.
ProgressData makeProgressData(const InputStream &input_r)
relates: ProgressData Setup from InputStream.
static bool warning(const std::string &msg_r, const UserData &userData_r=UserData())
send warning text
bool setFileCheckSum(std::map< std::string, CheckSum > &map_r, const std::string &value) const