libzypp  17.38.13
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>
17 #include <zypp-core/base/String.h>
19 #include <zypp-core/base/UserRequestException>
20 #include <zypp-core/parser/ParseException>
21 
24 
25 using std::endl;
26 #undef ZYPP_BASE_LOGGER_LOGGROUP
27 #define ZYPP_BASE_LOGGER_LOGGROUP "parser::susetags"
28 
30 namespace zypp
31 {
32  namespace parser
34  {
35  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:
84  Impl()
85  {}
86 
88  {
89  if ( !_repoindex )
90  _repoindex = new 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  };
130 
132  //
133  // CLASS NAME : ContentFileReader
134  //
136 
138  //
139  // METHOD NAME : ContentFileReader::ContentFileReader
140  // METHOD TYPE : Ctor
141  //
143  {}
144 
146  //
147  // METHOD NAME : ContentFileReader::~ContentFileReader
148  // METHOD TYPE : Dtor
149  //
151  {}
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  //
189  void ContentFileReader::userRequestedAbort( unsigned lineNo_r )
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  //
215  void ContentFileReader::parse( const InputStream & input_r,
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() )
231  userRequestedAbort( 0 );
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
310  } // namespace parser
313 } // namespace zypp
#define MIL
Definition: Logger.h:103
Repository content data (from /content file).
Definition: RepoIndex.h:48
ProgressData makeProgressData(const InputStream &input_r)
relates: ProgressData Setup from InputStream.
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.
void sendTo(const ReceiverFnc &fnc_r)
Set ReceiverFnc.
Definition: progressdata.h:229
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:459
bool next()
Advance to next line.
Definition: IOStream.cc:72
function< bool(const ProgressData &)> ReceiverFnc
Most simple version of progress reporting The percentage in most cases.
Definition: progressdata.h:140
unsigned lineNo() const
Return the current line number.
Definition: IOStream.h:127
RW_pointer< Impl, rw_pointer::Scoped< Impl > > _pimpl
bool toMax()
Set counter value to current max value (unless no range).
Definition: progressdata.h:276
static bool warning(const std::string &msg_r, const UserData &userData_r=UserData())
send warning text
Helper to create and pass std::istream.
Definition: inputstream.h:56
Simple lineparser: Traverse each line in a file.
Definition: IOStream.h:112
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:39
bool setFileCheckSum(std::map< std::string, CheckSum > &map_r, const std::string &value) const
virtual void userRequestedAbort(unsigned lineNo_r)
Called when user(callback) request to abort.
bool toMin()
Set counter value to current min value.
Definition: progressdata.h:272
unsigned split(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=" \, const Trim trim_r=NO_TRIM)
Split line_r into words.
Definition: String.h:602
std::string stripFirstWord(std::string &line, const bool ltrim_first)
Definition: String.cc:266
const std::string & name() const
Name of the std::istream.
Definition: inputstream.h:107
#define pWAR
Definition: LogTools.h:316
Maintain [min,max] and counter (value) for progress counting.
Definition: progressdata.h:131
std::string sconcat(Args &&... args)
Concat words as string.
Definition: LogTools.h:276
virtual void beginParse()
Called when start parsing.
SolvableIdType size_type
Definition: poolconstants.h:59
std::istream & stream() const
The std::istream.
Definition: inputstream.h:93
virtual void endParse()
Called when the parse is done.
bool set(value_type val_r)
Set new counter value.
Definition: progressdata.h:249
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
virtual void parse(const InputStream &imput_r, const ProgressData::ReceiverFnc &fnc_r=ProgressData::ReceiverFnc())
Parse the stream.
#define DBG
Definition: Logger.h:102