libzypp 17.37.18
provide.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include "provide.h"
10
11#include <utility>
12#include <zypp-core/TriBool.h>
14#include <zypp-media/mount.h>
15#include <zypp-media/ng/ProvideSpec>
16
17#include <zypp/ZYppCallbacks.h>
18#include <zypp/MediaSetAccess.h>
20#include <zypp/repo/SUSEMediaVerifier.h>
21
22namespace zyppng {
23
25 {
26
27 public:
28
30
32 const ProvideMediaSpec &spec() const;
33 zypp::Url url() const;
34 const zypp::MirroredOrigin &origin() const;
35 const std::optional<zypp::Pathname> &rootPath() const;
36 ProvideRef parent() const;
37
42
43 // ReferenceCounted interface
44 protected:
45 void unref_to(unsigned int) const override;
46
47 private:
51 ProvideRef _parent;
52 std::optional<zypp::Pathname> _localPath;
53 };
54
56
58 : _id( mediaId )
59 , _origin( std::move( origin ) )
60 , _spec(std::move( mediaSpec ))
61 , _parent(std::move( parentRef ))
62 , _localPath( locPath )
63 {}
64
69
71 {
72 return _spec;
73 }
74
76 {
77 return _origin.authority().url();
78 }
79
81 {
82 return _origin;
83 }
84
85 const std::optional<zypp::Pathname> &AttachedMediaInfo::rootPath() const
86 {
87 return _localPath;
88 }
89
90 ProvideRef AttachedMediaInfo::parent() const
91 {
92 return _parent;
93 }
94
99
100 void AttachedMediaInfo::unref_to( unsigned int count ) const
101 {
102 // once count reaches 1 only the Provide holds a reference,
103 // time to release the medium
104 if ( count == 1 ) {
105 _parent->releaseMedium ( this );
106 // !!!! careful from here on out 'this' is most likely invalid !!!!
107 return;
108 }
109 }
110
111
113
114 ProvideMediaHandle::ProvideMediaHandle(AttachedMediaInfo_Ptr dataPtr) : _data( std::move(dataPtr) )
115 { }
116
117 ProvideRef ProvideMediaHandle::parent() const
118 {
119 return _data->parent();
120 }
121
123 {
124 return _data.get() != nullptr;
125 }
126
128 {
129 static zypp::Url invalidHandle;
130 if ( !_data ) return invalidHandle;
131 return _data->origin().authority().url();
132 }
133
134 const std::optional<zypp::Pathname> &ProvideMediaHandle::localPath() const
135 {
136 static std::optional<zypp::Pathname> invalidPath;
137 if ( !_data )
138 return invalidPath;
139 return _data->rootPath();
140 }
141
143 {
144 return *_data;
145 }
146
151
153 return _res;
154 }
155
157
159 {
160 const auto &handlerType = zypp::media::MediaHandlerFactory::handlerType ( origin.authority().url() );
161 if ( !handlerType ) {
162 ERR << "Authority URL: " << origin.authority() << " is not supported!" << std::endl;
163 return {};
164 }
165
166 zypp::MirroredOrigin sanitized( origin.authority() );
167 for ( const auto &mirror : origin.mirrors() ) {
168 const auto &s = zypp::media::MediaHandlerFactory::handlerType ( mirror.url() );
169 if ( !s ) {
170 WAR << "URL: " << mirror << " is not supported, ignoring!" << std::endl;
171 continue;
172 }
173 if ( handlerType == *s) {
174 sanitized.addMirror(mirror);
175 } else {
176 WAR << "URL: " << mirror << " has different handler type than the authority URL: "<< origin.authority() <<", ignoring!" << std::endl;
177 }
178 }
179
180 return sanitized;
181 }
182
187
189 {
190 // rewrite and sanitize the urls if required
191 zypp::MirroredOrigin sanitizedOrigin = sanitizeUrls(origin);
192
193 if ( !sanitizedOrigin.isValid() )
195
196 if ( request.medianr() > 1 ) {
197 for ( auto &ep : sanitizedOrigin )
198 ep.url() = zypp::MediaSetAccess::rewriteUrl( ep.url(), request.medianr() );
199 }
200
201 // first try and find a already attached medium
202 auto i = std::find_if( _attachedMedia.begin (), _attachedMedia.end(), [&]( const AttachedMediaInfo_Ptr &medium ) {
203 return medium->isSameMedium( sanitizedOrigin, request );
204 });
205
206 if ( i != _attachedMedia.end() ) {
208 }
209
210 bool isVolatile = sanitizedOrigin.authority().url().schemeIsVolatile();
211
212 std::optional<zypp::media::MediaAccessId> attachId;
213 zypp::callback::SendReport<zypp::media::MediaChangeReport> report;
214
215 // nothing attached, make a new one
217 do {
218 try {
219 if ( !attachId ) {
220 attachId = mgr.open( sanitizedOrigin );
221 if ( !request.mediaFile().empty() ) {
222 mgr.addVerifier( *attachId, zypp::media::MediaVerifierRef( new zypp::repo::SUSEMediaVerifier( request.mediaFile(), request.medianr() ) ) );
223 }
224 }
225
226 // attach the medium
227 mgr.attach( *attachId );
228
229 auto locPath = mgr.localPath( *attachId, "/" );
230 auto attachInfo = AttachedMediaInfo_Ptr( new AttachedMediaInfo( shared_this<Provide>(), *attachId, std::move(sanitizedOrigin), request, locPath ) );
231 _attachedMedia.push_back( attachInfo );
232 return expected<Provide::MediaHandle>::success( std::move(attachInfo) );
233
234 } catch ( const zypp::media::MediaException &excp ) {
235
236 ZYPP_CAUGHT(excp);
237
238 // if no one is listening, just return the error as is
239 if ( !zypp::callback::SendReport<zypp::media::MediaChangeReport>::connected() || !attachId ) {
241 }
242
243 // default action is to cancel
244 zypp::media::MediaChangeReport::Action user = zypp::media::MediaChangeReport::ABORT;
245
246 do {
247 // here: Manager tried all not attached drives and could not find the desired medium
248 // we need to send the media change report
249
250 // set up the reason
251 auto reason = zypp::media::MediaChangeReport::INVALID;
252 if( typeid(excp) == typeid( zypp::media::MediaNotDesiredException) ) {
253 reason = zypp::media::MediaChangeReport::WRONG;
254 }
255
256 unsigned int devindex = 0;
257
258 std::vector<std::string> devices;
259 mgr.getDetectedDevices(*attachId, devices, devindex);
260
261 std::optional<std::string> currentlyUsed;
262 if ( devices.size() ) currentlyUsed = devices[devindex];
263
264 if ( isVolatile ) {
265 // filter devices that are mounted, aka used, we can not eject them
266 const auto &mountedDevs = zypp::media::Mount::getEntries();
267 devices.erase( std::remove_if( devices.begin (), devices.end(), [&](const std::string &dev) {
268 zypp::PathInfo devInfo(dev);
269 return std::any_of( mountedDevs.begin (), mountedDevs.end(), [&devInfo]( const zypp::media::MountEntry &e ) {
270 zypp::PathInfo pi( e.src );
271 return ( pi.isBlk() && pi.devMajor() == devInfo.devMajor() && pi.devMinor() == devInfo.devMinor() );
272 });
273 }), devices.end() );
274
275 if ( !devices.size () ) {
276 // Jammed, no currently free device
277 MIL << "No free device available, return jammed and try again later ( hopefully) " << std::endl;
278 if ( attachId ) mgr.close ( *attachId );
280 }
281
282 // update index to currenty used dev
283 bool foundCurrent = false;
284 if ( currentlyUsed ) {
285 for ( unsigned int i = 0; i < devices.size(); i++ ) {
286 if ( devices[i] == *currentlyUsed ) {
287 foundCurrent = true;
288 devindex = i;
289 break;
290 }
291 }
292 }
293
294 if ( !foundCurrent ){
295 devindex = 0; // seems 0 is what is set in the handlers too if there is no current
296 }
297 }
298
299 zypp::Url effectiveUrl = sanitizedOrigin.authority().url();
300
301 user = report->requestMedia (
302 effectiveUrl,
303 request.medianr(),
304 request.label(),
305 reason,
306 excp.asUserHistory(),
307 devices,
308 devindex
309 );
310
311 MIL << "ProvideFile exception caught, callback answer: " << user << std::endl;
312
313 switch ( user ) {
314 case zypp::media::MediaChangeReport::ABORT: {
315 DBG << "Aborting" << std::endl;
316 if ( attachId ) mgr.close ( *attachId );
317 zypp::AbortRequestException aexcp("Aborting requested by user");
318 aexcp.remember(excp);
320 }
321 case zypp::media::MediaChangeReport::IGNORE: {
322 DBG << "Skipping" << std::endl;
323 if ( attachId ) mgr.close ( *attachId );
324 zypp::SkipRequestException nexcp("User-requested skipping of a file");
325 nexcp.remember(excp);
327 }
328 case zypp::media::MediaChangeReport::EJECT: {
329 DBG << "Eject: try to release" << std::endl;
330 try
331 {
332 // MediaSetAccess does a releaseAll, but we can not release other devices that are in use
333 // media_mgr.releaseAll();
334 mgr.release (*attachId, devindex < devices.size() ? devices[devindex] : "");
335 }
336 catch ( const zypp::Exception & e)
337 {
338 ZYPP_CAUGHT(e);
339 }
340 break;
341 }
342 case zypp::media::MediaChangeReport::RETRY:
343 case zypp::media::MediaChangeReport::CHANGE_URL: {
344 // retry
345 DBG << "Going to try again" << std::endl;
346
347 // invalidate current media access id
348 if ( attachId ) {
349 mgr.close(*attachId);
350 attachId.reset();
351 }
352
353 // explicitely setting a URL from the callback wipes all mirrors
354 if ( sanitizedOrigin.authority().url() != effectiveUrl ) {
355 sanitizedOrigin.clearMirrors ();
356 sanitizedOrigin.setAuthority ( effectiveUrl );
357 }
358
359 // not attaching, media set will do that for us
360 // this could generate uncaught exception (#158620)
361 break;
362 }
363 default: {
364 DBG << "Don't know, let's ABORT" << std::endl;
365 if ( attachId ) mgr.close ( *attachId );
367 }
368 }
369 } while( user == zypp::media::MediaChangeReport::EJECT );
370 } catch ( const zypp::Exception &e ) {
371 ZYPP_CAUGHT(e);
372 if ( attachId ) mgr.close ( *attachId );
374 } catch (...) {
375 // didn't work -> clean up
376 if ( attachId ) mgr.close ( *attachId );
378 }
379 } while ( true );
380 }
381
383 {
384 // this should never happen because every handle has a reference to the media manager, but still add a debug output
385 // so we know in case we have weird behavior.
386 if ( _attachedMedia.size () ) {
387 WAR << "Releasing zyppng::Provide with still valid MediaHandles, this is a bug!" << std::endl;
388 }
389 }
390
392 {
393 const auto &sanitizedOrigin = sanitizeUrls(origin);
394 if ( !sanitizedOrigin.isValid() )
396 return expected<LazyMediaHandle>::success( shared_this<Provide>(), std::move(sanitizedOrigin), request );
397 }
398
403
405 {
406 using namespace zyppng::operators;
407 if ( lazyHandle.attached() )
408 return expected<MediaHandle>::success( *lazyHandle.handle() );
409
410 MIL << "Attaching lazy medium with label: [" << lazyHandle.spec().label() << "]" << std::endl;
411
412 return attachMedia( lazyHandle.origin(), lazyHandle.spec () )
413 | and_then([lazyHandle]( MediaHandle handle ) {
414 lazyHandle._sharedData->_mediaHandle = handle;
415 return expected<MediaHandle>::success( std::move(handle) );
416 });
417 }
418
420 {
421 using namespace zyppng::operators;
422
423 if ( !origin.isValid() )
424 return expected<ProvideRes>::error( ZYPP_EXCPT_PTR ( zypp::media::MediaException("Can not provide a file without a URL.") ));
425
426 std::optional<expected<ProvideRes>> lastErr;
427 for ( const zypp::OriginEndpoint& file_url : origin ) {
428
429 zypp::OriginEndpoint ep(file_url);
430 zypp::Pathname fileName(ep.url().getPathName());
431 ep.url().setPathName ("/");
432
434 | and_then( [&, this]( const Provide::MediaHandle& handle ) {
435 return provide( handle, fileName, request.asOnMediaLocation(fileName, 1));
436 });
437
438 if ( res )
439 return res;
440
441 lastErr = res;
442 }
443
444 // we always should have a last error, except if the URLs are empty
445 if ( lastErr )
446 return *lastErr;
447
448 // we should not get here, but if we do simply use the first entry to make a not found error
449 zypp::Url url( origin.authority().url() );
450 zypp::Pathname fileName(url.getPathName());
451 url.setPathName ("/");
453
454 }
455
457 {
458 return provide( zypp::MirroredOrigin{url}, request );
459 }
460
461 expected<ProvideRes> Provide::provide(const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request)
462 {
464 const auto &handleInfo = attachHandle.info();
465
466 try {
467 if ( request.checkExistsOnly() ) {
468 if ( !mgr.doesFileExist ( handleInfo.mediaId (), fileName ) ) {
470 }
471
472 // we return a result pointing to a non existant file, since the code just asked us to check if the file exists
473 return expected<ProvideRes>::success( attachHandle, zypp::ManagedFile( mgr.localPath( handleInfo.mediaId(), fileName ) ) );
474
475 } else {
476 mgr.provideFile( handleInfo.mediaId (), request.asOnMediaLocation( fileName, handleInfo.spec().medianr()) );
477
478 zypp::ManagedFile locFile( mgr.localPath( handleInfo.mediaId(), fileName ) );
479
480 // do not clean up files for now, they are cleaned up anyways on detach
481#if 0
482 // if the file is downloaded we want to clean it up again
483 if ( handleInfo.url().schemeIsDownloading() )
485#endif
486
487 return expected<ProvideRes>::success( attachHandle, locFile );
488 }
489 } catch ( const zypp::Exception &e ) {
490 ZYPP_CAUGHT(e);
492 } catch (...) {
494 }
495 }
496
497 expected<ProvideRes> Provide::provide( const LazyMediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request )
498 {
499 using namespace zyppng::operators;
500 return attachMediaIfNeeded ( attachHandle )
501 | and_then([weakMe = weak_this<Provide>(), fName = fileName, req = request ]( MediaHandle handle ){
502 auto me = weakMe.lock();
503 if ( !me )
504 return expected<Res>::error(ZYPP_EXCPT_PTR(zypp::Exception("Provide was released during a operation")));
505 return me->provide( handle, fName, req);
506 });
507 }
508
510 {
511 try {
512 return expected<zypp::CheckSum>::success( zypp::CheckSum( algorithm, zypp::filesystem::checksum ( p, algorithm ) ) );
513 } catch(...) {
514 return expected<zypp::CheckSum>::error ( std::current_exception () );
515 }
516 }
517
519 {
520 try {
521 // do what Provide would do and make a URL
522 zypp::Url url("copy:///");
523 url.setPathName( source );
524
525 auto sourcePi = zypp::PathInfo(source);
526 if ( !sourcePi.isExist() ) {
528 }
529 if ( !sourcePi.isFile () )
531
532 auto res = zypp::filesystem::hardlinkCopy( source, target.asString() );
533 if ( res == 0 ) {
535 } else {
536 return expected<zypp::ManagedFile>::error ( ZYPP_EXCPT_PTR( zypp::media::MediaException( zypp::str::Str() << "Failed to create file " << target << " errno: " << res ) ) );
537 }
538 } catch(...) {
539 return expected<zypp::ManagedFile>::error ( std::current_exception () );
540 }
541 }
542
544 {
545 // not much to do here, since this will block until the file has been copied we do not need to remember the ProvideRes
546 return copyFile( source.file(), target );
547 }
548
550 {
551 if ( !ptr ) return;
552
553 auto i = std::find_if(_attachedMedia.begin (), _attachedMedia.end(), [&]( const auto &p ) { return p.get() == ptr; } );
554
555 try {
557 mgr.close ( ptr->mediaId() );
558 } catch ( const zypp::Exception & e ) {
559 ZYPP_CAUGHT(e);
560 }
561
562 if ( i != _attachedMedia.end() ) {
563 _attachedMedia.erase(i);
564 } else {
565 ERR << "Releasing unknown medium " << ptr->mediaId () << " should not happen";
566 }
567 }
568
569
570}
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:463
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition Exception.h:471
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102
#define WAR
Definition Logger.h:101
#define IMPL_PTR_TYPE(NAME)
void setDispose(const Dispose &dispose_r)
Set a new dispose function.
Base class for Exception.
Definition Exception.h:153
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition Exception.cc:140
Manages a data source characterized by an authoritative URL and a list of mirror URLs.
const std::vector< OriginEndpoint > & mirrors() const
void setAuthority(OriginEndpoint newAuthority)
bool addMirror(OriginEndpoint newMirror)
const OriginEndpoint & authority() const
Represents a single, configurable network endpoint, combining a URL with specific access settings.
const zypp::Url & url() const
Url manipulation class.
Definition Url.h:93
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition Url.cc:622
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition Url.cc:782
static bool schemeIsVolatile(const std::string &scheme_r)
cd dvd
Definition Url.cc:487
Base class for reference counted objects.
Wrapper class for stat/lstat.
Definition PathInfo.h:226
const std::string & asString() const
String representation.
Definition Pathname.h:93
bool empty() const
Test for an empty path.
Definition Pathname.h:116
Just inherits Exception to separate media exceptions.
static std::optional< MediaHandlerType > handlerType(const Url &url)
Manages access to the 'physical' media, e.g CDROM drives, Disk volumes, directory trees,...
MediaAccessId open(const Url &url, const Pathname &preferred_attach_point="")
Opens the media access for specified with the url.
void attach(MediaAccessId accessId)
Attach the media using the concrete handler (checks all devices).
void close(MediaAccessId accessId)
Close the media access with specified id.
ZYPP_DEPRECATED void provideFile(MediaAccessId accessId, const Pathname &filename, const ByteCount &expectedFileSize) const
void release(MediaAccessId accessId, const std::string &ejectDev="")
Release the attached media and optionally eject.
bool doesFileExist(MediaAccessId accessId, const Pathname &filename) const
FIXME: see MediaAccess class.
Pathname localPath(MediaAccessId accessId, const Pathname &pathname) const
Shortcut for 'localRoot() + pathname', but returns an empty pathname if media is not attached.
void addVerifier(MediaAccessId accessId, const MediaVerifierRef &verifier)
Add verifier implementation for the specified media id.
void getDetectedDevices(MediaAccessId accessId, std::vector< std::string > &devices, unsigned int &index) const
Fill in a vector of detected ejectable devices and the index of the currently attached device within ...
static MountEntries getEntries(const std::string &mtab="")
Return mount entries from /etc/mtab or /etc/fstab file.
Definition mount.cc:169
AttachedMediaInfo(ProvideRef parentRef, zypp::media::MediaAccessId mediaId, zypp::MirroredOrigin origin, ProvideMediaSpec mediaSpec, const zypp::Pathname &locPath)
Definition provide.cc:57
ProvideMediaSpec _spec
Definition provide.cc:50
void unref_to(unsigned int) const override
Definition provide.cc:100
const std::optional< zypp::Pathname > & rootPath() const
Definition provide.cc:85
bool isSameMedium(const zypp::MirroredOrigin &origin, const ProvideMediaSpec &spec)
Definition provide.cc:95
const zypp::MirroredOrigin & origin() const
Definition provide.cc:80
zypp::Url url() const
Definition provide.cc:75
std::optional< zypp::Pathname > _localPath
Definition provide.cc:52
const ProvideMediaSpec & spec() const
Definition provide.cc:70
zypp::media::MediaAccessId _id
Definition provide.cc:48
zypp::MirroredOrigin _origin
Definition provide.cc:49
ProvideRef parent() const
Definition provide.cc:90
zypp::media::MediaAccessId mediaId() const
Definition provide.cc:65
std::shared_ptr< T > shared_this() const
Definition base.h:113
std::weak_ptr< T > weak_this() const
Definition base.h:123
const zypp::MirroredOrigin & origin() const
const ProvideMediaSpec & spec() const
std::optional< MediaHandle > handle() const
zypp::OnMediaLocation asOnMediaLocation(const zypp::Pathname &path, unsigned int mediaNr) const
bool checkExistsOnly() const
const zypp::Url & baseUrl() const
Definition provide.cc:127
const std::optional< zypp::Pathname > & localPath() const
Definition provide.cc:134
ProvideRef parent() const
Definition provide.cc:117
const AttachedMediaInfo & info() const
Definition provide.cc:142
AttachedMediaInfo_Ptr _data
Definition provide.h:40
zypp::TriBool isSameMedium(const ProvideMediaSpec &other) const
unsigned medianr() const
zypp::Pathname mediaFile() const
const std::string & label() const
ProvideRes(ProvideMediaHandle hdl, zypp::ManagedFile file)
Definition provide.cc:147
const zypp::Pathname file() const
Definition provide.cc:152
ProvideMediaHandle _provideHandle
Definition provide.h:91
zypp::ManagedFile _res
Definition provide.h:90
expected< zypp::CheckSum > checksumForFile(const zypp::Pathname &p, const std::string &algorithm)
Definition provide.cc:509
zypp::MirroredOrigin sanitizeUrls(const zypp::MirroredOrigin &origin) const
Definition provide.cc:158
expected< MediaHandle > attachMedia(const zypp::MirroredOrigin &origin, const ProvideMediaSpec &request)
Definition provide.cc:188
expected< LazyMediaHandle > prepareMedia(const zypp::MirroredOrigin &origin, const ProvideMediaSpec &request)
Definition provide.cc:391
friend class AttachedMediaInfo
Definition provide.h:106
expected< zypp::ManagedFile > copyFile(const zypp::Pathname &source, const zypp::Pathname &target)
Definition provide.cc:518
expected< Res > provide(const zypp::MirroredOrigin &origin, const ProvideFileSpec &request)
Definition provide.cc:419
::zyppng::LazyMediaHandle< Provide > LazyMediaHandle
Definition provide.h:109
std::vector< AttachedMediaInfo_Ptr > _attachedMedia
Definition provide.h:150
~Provide() override
Definition provide.cc:382
expected< MediaHandle > attachMediaIfNeeded(LazyMediaHandle lazyHandle)
Definition provide.cc:404
void releaseMedium(const AttachedMediaInfo *ptr)
Definition provide.cc:549
ProvideMediaHandle MediaHandle
Definition provide.h:108
static expected success(ConsParams &&...params)
Definition expected.h:115
Definition ansi.h:855
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition NonCopyable.h:26
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition PathInfo.cc:1056
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition PathInfo.cc:888
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:705
unsigned int MediaAccessId
Media manager access Id type.
Definition MediaSource.h:30
zypp::RW_pointer< MediaVerifierBase > MediaVerifierRef
A shared reference to the MediaVerifier implementation.
Url details namespace.
Definition UrlBase.cc:58
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition ManagedFile.h:27
ResultType and_then(const expected< T, E > &exp, Function &&f)
Definition expected.h:423
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:213
#define ZYPP_IMPL_PRIVATE_CONSTR(Class)
Definition zyppglobal.h:222