libzypp 17.38.11
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 // HASH SHA1 d423ad41e93a51195a6264961e4a074c6d89359d boot/../x86_64/bind => x86_64/bind
56 // HASH SHA1 d423ad41e93a51195a6264961e4a074c6d89359d boot/../../x86_64/bind => ../* discarded
57 // Turning it into a Pathname normalizes the representation.
58 if ( path_r.relativeDotDot() ) {
59 // Don't accept downloadable data outside repo root
60 JobReport::warning( str::sconcat( "Content file: hostile location ",path_r," => discard data entry" ) );
61 pWAR( "Hostile location:", path_r, "=>", "discard data entry" );
62 return {};
63 }
64 // Skip leading "/" or "./" trying to retain the original string format
65 std::string ret = path_r.asString();
66 if ( ret.size() <= 1 )
67 return ret; // is "", "." or "/"
68 if ( ret[0] == '/' )
69 ret = ret.substr( 1 ); // skip leading "/"
70 else
71 ret = ret.substr( 2 ); // skip leading "./"
72 return ret;
73 }
74 }
75
77 //
78 // CLASS NAME : ContentFileReader::Impl
79 //
82 {
83 public:
85 {}
86
88 {
89 if ( !_repoindex )
91 return *_repoindex;
92 }
93
94 bool hasRepoIndex() const
95 { return _repoindex != nullptr; }
96
97 RepoIndex_Ptr handoutRepoIndex()
98 {
99 RepoIndex_Ptr ret;
100 ret.swap( _repoindex );
101 _repoindex = nullptr;
102 return ret;
103 }
104
105 public:
106 bool setFileCheckSum( std::map<std::string, CheckSum> & map_r, const std::string & value ) const
107 {
108 bool error = false;
109 std::vector<std::string> words;
110 if ( str::split( value, std::back_inserter( words ) ) == 3 )
111 {
112 std::string pathstr = sanitizeEntry( words[2] );
113 if ( not pathstr.empty() )
114 map_r[std::move(pathstr)] = CheckSum( words[0], words[1] );
115 }
116 else
117 {
118 error = true;
119 }
120 return error;
121 }
122
123 public:
124 std::string _inputname;
125
126 private:
127 RepoIndex_Ptr _repoindex;
128 };
129
130
132 //
133 // CLASS NAME : ContentFileReader
134 //
136
138 //
139 // METHOD NAME : ContentFileReader::ContentFileReader
140 // METHOD TYPE : Ctor
141 //
144
146 //
147 // METHOD NAME : ContentFileReader::~ContentFileReader
148 // METHOD TYPE : Dtor
149 //
152
154 //
155 // METHOD NAME : ContentFileReader::beginParse
156 // METHOD TYPE : void
157 //
159 {
160 _pimpl.reset( new Impl() );
161 // actually mandatory, but in case they were forgotten...
162 _pimpl->repoindex().descrdir = "suse/setup/descr";
163 _pimpl->repoindex().datadir = "suse";
164 }
165
167 //
168 // METHOD NAME : ContentFileReader::endParse
169 // METHOD TYPE : void
170 //
172 {
173 // consume oldData
174 if ( _pimpl->hasRepoIndex() )
175 {
176 if ( _repoIndexConsumer )
177 _repoIndexConsumer( _pimpl->handoutRepoIndex() );
178 }
179
180 MIL << "[Content]" << endl;
181 _pimpl.reset();
182 }
183
185 //
186 // METHOD NAME : ContentFileReader::userRequestedAbort
187 // METHOD TYPE : void
188 //
190 {
191 ZYPP_THROW( AbortRequestException( errPrefix( lineNo_r ) ) );
192 }
193
195 //
196 // METHOD NAME : ContentFileReader::errPrefix
197 // METHOD TYPE : std::string
198 //
199 std::string ContentFileReader::errPrefix( unsigned lineNo_r,
200 const std::string & msg_r,
201 const std::string & line_r ) const
202 {
203 return str::form( "%s:%u:%s | %s",
204 _pimpl->_inputname.c_str(),
205 lineNo_r,
206 line_r.c_str(),
207 msg_r.c_str() );
208 }
209
211 //
212 // METHOD NAME : ContentFileReader::parse
213 // METHOD TYPE : void
214 //
216 const ProgressData::ReceiverFnc & fnc_r )
217 {
218 MIL << "Start parsing content repoindex" << input_r << endl;
219 if ( ! input_r.stream() )
220 {
221 std::ostringstream s;
222 s << "Can't read bad stream: " << input_r;
223 ZYPP_THROW( ParseException( s.str() ) );
224 }
225 beginParse();
226 _pimpl->_inputname = input_r.name();
227
228 ProgressData ticks( makeProgressData( input_r ) );
229 ticks.sendTo( fnc_r );
230 if ( ! ticks.toMin() )
232
233 iostr::EachLine line( input_r );
234 for( ; line; line.next() )
235 {
236 // strip 1st word from line to separate tag and value.
237 std::string value( *line );
238 std::string key( str::stripFirstWord( value, /*ltrim_first*/true ) );
239
240 if ( key.empty() || *key.c_str() == '#' ) // empty or comment line
241 {
242 continue;
243 }
244
245 // strip modifier if exists
246 std::string modifier;
247 std::string::size_type pos = key.rfind( '.' );
248 if ( pos != std::string::npos )
249 {
250 modifier = key.substr( pos+1 );
251 key.erase( pos );
252 }
253
254 //
255 // ReppoIndex related data:
256 //
257 else if ( key == "DESCRDIR" )
258 {
259 _pimpl->repoindex().descrdir = sanitize( value );
260 }
261 else if ( key == "DATADIR" )
262 {
263 _pimpl->repoindex().datadir = sanitize( value );
264 }
265 else if ( key == "KEY" )
266 {
267 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().signingKeys, value ) )
268 {
269 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [KEY algorithm checksum filename]", *line ) ) );
270 }
271 }
272 else if ( key == "META" )
273 {
274 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().metaFileChecksums, value ) )
275 {
276 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
277 }
278 }
279 else if ( key == "HASH" )
280 {
281 if ( _pimpl->setFileCheckSum( _pimpl->repoindex().mediaFileChecksums, value ) )
282 {
283 ZYPP_THROW( ParseException( errPrefix( line.lineNo(), "Expected [algorithm checksum filename]", *line ) ) );
284 }
285 }
286 else
287 {
288 DBG << errPrefix( line.lineNo(), "ignored", *line ) << endl;
289 }
290
291
292 if ( ! ticks.set( input_r.stream().tellg() ) )
293 userRequestedAbort( line.lineNo() );
294 }
295
296 //
297 // post processing
298 //
299 if ( ! ticks.toMax() )
300 userRequestedAbort( line.lineNo() );
301
302 endParse();
303 MIL << "Done parsing " << input_r << endl;
304 }
305
307 } // namespace susetags
308
310 } // namespace parser
313} // 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
const std::string & asString() const
String representation.
Definition Pathname.h:94
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