libzypp 17.32.2
mediafacade.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9#include "mediafacade.h"
10#include <zypp-core/TriBool.h>
11#include <utility>
12#include <zypp-media/ng/ProvideSpec>
14
15namespace zyppng {
16
18 {
19
20 public:
21
22 AttachedSyncMediaInfo( MediaSyncFacadeRef parentRef, zypp::media::MediaAccessId mediaId, zypp::Url baseUrl, ProvideMediaSpec mediaSpec, const zypp::Pathname &locPath );
23
25 const ProvideMediaSpec &spec() const;
26 const zypp::Url &url() const;
27 const std::optional<zypp::Pathname> &rootPath() const;
28 MediaSyncFacadeRef parent() const;
29
33 bool isSameMedium ( const std::vector<zypp::Url> &urls, const ProvideMediaSpec &spec );
34
35 // ReferenceCounted interface
36 protected:
37 void unref_to(unsigned int) const override;
38
39 private:
43 MediaSyncFacadeRef _parent;
44 std::optional<zypp::Pathname> _localPath;
45 };
46
48
49 AttachedSyncMediaInfo::AttachedSyncMediaInfo(MediaSyncFacadeRef parentRef, zypp::media::MediaAccessId mediaId, zypp::Url baseUrl, ProvideMediaSpec mediaSpec, const zypp::Pathname &locPath)
50 : _id( mediaId )
51 , _attachedUrl(std::move( baseUrl ))
52 , _spec(std::move( mediaSpec ))
53 , _parent(std::move( parentRef ))
54 , _localPath( locPath )
55 {}
56
61
63 {
64 return _spec;
65 }
66
68 {
69 return _attachedUrl;
70 }
71
72 const std::optional<zypp::Pathname> &AttachedSyncMediaInfo::rootPath() const
73 {
74 return _localPath;
75 }
76
77 MediaSyncFacadeRef AttachedSyncMediaInfo::parent() const
78 {
79 return _parent;
80 }
81
82 bool AttachedSyncMediaInfo::isSameMedium(const std::vector<zypp::Url> &urls, const ProvideMediaSpec &spec) {
83
84 const auto check = _spec.isSameMedium(spec);
85 if ( !zypp::indeterminate (check) )
86 return (bool)check;
87
88 // let the URL rule
89 return ( std::find( urls.begin(), urls.end(), _attachedUrl ) != urls.end() );
90 }
91
92 void AttachedSyncMediaInfo::unref_to( unsigned int count ) const
93 {
94 // once count reaches 1 only the MediaSyncFacade holds a reference,
95 // time to release the medium
96 if ( count == 1 ) {
97 _parent->releaseMedium ( this );
98 // !!!! careful from here on out 'this' is most likely invalid !!!!
99 return;
100 }
101 }
102
103
105
106 SyncMediaHandle::SyncMediaHandle(AttachedSyncMediaInfo_Ptr dataPtr) : _data( std::move(dataPtr) )
107 { }
108
109 MediaSyncFacadeRef SyncMediaHandle::parent() const
110 {
111 return _data->parent();
112 }
113
115 {
116 return _data.get() != nullptr;
117 }
118
120 {
121 static zypp::Url invalidHandle;
122 if ( !_data )
123 return invalidHandle;
124 return _data->url();
125 }
126
127 const std::optional<zypp::Pathname> &SyncMediaHandle::localPath() const
128 {
129 static std::optional<zypp::Pathname> invalidPath;
130 if ( !_data )
131 return invalidPath;
132 return _data->rootPath();
133 }
134
136 {
137 return *_data;
138 }
139
141 : _res( std::move(file) )
142 , _provideHandle( std::move (hdl) )
143 { }
144
146 return _res;
147 }
148
150
151 expected<MediaSyncFacade::MediaHandle> MediaSyncFacade::attachMedia( const std::vector<zypp::Url> &urls, const ProvideMediaSpec &request )
152 {
153 // rewrite and sanitize the urls if required
154 std::vector<zypp::Url> useableUrls = urls;
155
156 // first try and find a already attached medium
157 auto i = std::find_if( _attachedMedia.begin (), _attachedMedia.end(), [&]( const AttachedSyncMediaInfo_Ptr &medium ) {
158 return medium->isSameMedium( useableUrls, request );
159 });
160
161 if ( i != _attachedMedia.end() ) {
162 return expected<MediaSyncFacade::MediaHandle>::success( *i );
163 }
164
165 // nothing attached, make a new one
167 std::exception_ptr lastError;
168 for ( const auto &url : useableUrls ) {
169 std::optional<zypp::media::MediaAccessId> attachId;
170 try {
171
172 attachId = mgr.open( url );
173 if ( !request.mediaFile().empty() ) {
174 mgr.addVerifier( *attachId, zypp::media::MediaVerifierRef( new zypp::repo::SUSEMediaVerifier( request.mediaFile(), request.medianr() ) ) );
175 }
176
177 // attach the medium
178 mgr.attach( *attachId );
179
180 auto locPath = mgr.localPath( *attachId, "/" );
181 auto attachInfo = AttachedSyncMediaInfo_Ptr( new AttachedSyncMediaInfo( shared_this<MediaSyncFacade>(), *attachId, url, request, locPath ) );
182 _attachedMedia.push_back( attachInfo );
183 return expected<MediaSyncFacade::MediaHandle>::success( std::move(attachInfo) );
184
185 } catch ( const zypp::Exception &e ) {
186 lastError = std::current_exception();
187 ZYPP_CAUGHT(e);
188 } catch (...) {
189 // didn't work -> clean up
190 lastError = std::current_exception();
191 }
192
193 // this URL wasn't the one, prepare to try a new one
194 if ( attachId )
195 mgr.close ( *attachId );
196
197 attachId.reset();
198 }
199
200 // if we have a error stored, return that one
201 if ( lastError ) {
202 return expected<MediaSyncFacade::MediaHandle>::error( lastError );
203 }
204
205 return expected<MediaSyncFacade::MediaHandle>::error( ZYPP_EXCPT_PTR( zypp::media::MediaException("No URL to attach") ) );
206 }
207
209 {
210 // this should never happen because every handle has a reference to the media manager, but still add a debug output
211 // so we know in case we have weird behavior.
212 if ( _attachedMedia.size () ) {
213 WAR << "Releasing zyppng::MediaSyncFacade with still valid MediaHandles, this is a bug!" << std::endl;
214 }
215 }
216
217 expected<MediaSyncFacade::MediaHandle> MediaSyncFacade::attachMedia( const zypp::Url &url, const ProvideMediaSpec &request )
218 {
219 return attachMedia( std::vector<zypp::Url>{url}, request );
220 }
221
222 expected<MediaSyncFacade::Res> MediaSyncFacade::provide(const std::vector<zypp::Url> &urls, const ProvideFileSpec &request)
223 {
224 using namespace zyppng::operators;
225
226 if ( !urls.size() )
227 return expected<MediaSyncFacade::Res>::error( ZYPP_EXCPT_PTR ( zypp::media::MediaException("Can not provide a file without a URL.") ));
228
229 std::optional<expected<MediaSyncFacade::Res>> lastErr;
230 for ( const zypp::Url& file_url : urls ) {
231
232 zypp::Url url(file_url);
233 zypp::Pathname fileName(url.getPathName());
234 url.setPathName ("/");
235
236 expected<MediaSyncFacade::Res> res = attachMedia( urls, ProvideMediaSpec( "" ) )
237 | and_then( [&, this]( const MediaSyncFacade::MediaHandle& handle ) {
238 return provide( handle, fileName, request.asOnMediaLocation(fileName, 1));
239 });
240
241 if ( res )
242 return res;
243
244 lastErr = res;
245 }
246
247 // we always should have a last error, except if the URLs are empty
248 if ( lastErr )
249 return *lastErr;
250
251 // we should not get here, but if we do simply use the first entry to make a not found error
252 zypp::Url url( urls.front() );
253 zypp::Pathname fileName(url.getPathName());
254 url.setPathName ("/");
255 return expected<MediaSyncFacade::Res>::error( ZYPP_EXCPT_PTR ( zypp::media::MediaFileNotFoundException( url, fileName )));
256
257 }
258
259 expected<MediaSyncFacade::Res> MediaSyncFacade::provide(const zypp::Url &url, const ProvideFileSpec &request)
260 {
261 return provide( std::vector<zypp::Url>{url}, request );
262 }
263
264 expected<MediaSyncFacade::Res> MediaSyncFacade::provide(const MediaHandle &attachHandle, const zypp::Pathname &fileName, const ProvideFileSpec &request)
265 {
267 const auto &handleInfo = attachHandle.info();
268
269 try {
270 if ( request.checkExistsOnly() ) {
271 if ( !mgr.doesFileExist ( handleInfo.mediaId (), fileName ) ) {
272 return expected<MediaSyncFacade::Res>::error( ZYPP_EXCPT_PTR( zypp::media::MediaFileNotFoundException( handleInfo.url(), fileName ) ) );
273 }
274
275 // we return a result pointing to a non existant file, since the code just asked us to check if the file exists
276 return expected<MediaSyncFacade::Res>::success( attachHandle, zypp::ManagedFile( mgr.localPath( handleInfo.mediaId(), fileName ) ) );
277
278 } else {
279 mgr.provideFile( handleInfo.mediaId (), request.asOnMediaLocation( fileName, handleInfo.spec().medianr()) );
280
281 zypp::ManagedFile locFile( mgr.localPath( handleInfo.mediaId(), fileName ) );
282
283 // do not clean up files for now, they are cleaned up anyways on detach
284#if 0
285 // if the file is downloaded we want to clean it up again
286 if ( handleInfo.url().schemeIsDownloading() )
288#endif
289
290 return expected<MediaSyncFacade::Res>::success( attachHandle, locFile );
291 }
292 } catch ( const zypp::Exception &e ) {
293 ZYPP_CAUGHT(e);
294 return expected<MediaSyncFacade::Res>::error(std::current_exception());
295 } catch (...) {
296 return expected<MediaSyncFacade::Res>::error(std::current_exception());
297 }
298 }
299
300 zyppng::expected<zypp::CheckSum> MediaSyncFacade::checksumForFile(const zypp::Pathname &p, const std::string &algorithm)
301 {
302 try {
303 return expected<zypp::CheckSum>::success( zypp::CheckSum( algorithm, zypp::filesystem::checksum ( p, algorithm ) ) );
304 } catch(...) {
305 return expected<zypp::CheckSum>::error ( std::current_exception () );
306 }
307 }
308
309 expected<zypp::ManagedFile> MediaSyncFacade::copyFile(const zypp::Pathname &source, const zypp::Pathname &target)
310 {
311 try {
312 // do what Provide would do and make a URL
313 zypp::Url url("copy:///");
314 url.setPathName( source );
315
316 auto sourcePi = zypp::PathInfo(source);
317 if ( !sourcePi.isExist() ) {
318 return expected<zypp::ManagedFile>::error ( ZYPP_EXCPT_PTR( zypp::media::MediaFileNotFoundException( url, "" ) ) );
319 }
320 if ( !sourcePi.isFile () )
321 return expected<zypp::ManagedFile>::error ( ZYPP_EXCPT_PTR( zypp::media::MediaNotAFileException( url, "" ) ) );
322
323 auto res = zypp::filesystem::hardlinkCopy( source, target.asString() );
324 if ( res == 0 ) {
325 return expected<zypp::ManagedFile>::success( zypp::ManagedFile( target, zypp::filesystem::unlink ) );
326 } else {
327 return expected<zypp::ManagedFile>::error ( ZYPP_EXCPT_PTR( zypp::media::MediaException( zypp::str::Str() << "Failed to create file " << target << " errno: " << res ) ) );
328 }
329 } catch(...) {
330 return expected<zypp::ManagedFile>::error ( std::current_exception () );
331 }
332 }
333
334 expected<zypp::ManagedFile> MediaSyncFacade::copyFile(zyppng::MediaSyncFacade::Res source, const zypp::Pathname &target)
335 {
336 // not much to do here, since this will block until the file has been copied we do not need to remember the ProvideRes
337 return copyFile( source.file(), target );
338 }
339
341 {
342 if ( !ptr ) return;
343
344 auto i = std::find_if(_attachedMedia.begin (), _attachedMedia.end(), [&]( const auto &p ) { return p.get() == ptr; } );
345
346 try {
348 mgr.close ( ptr->mediaId() );
349 } catch ( const zypp::Exception & e ) {
350 ZYPP_CAUGHT(e);
351 }
352
353 if ( i != _attachedMedia.end() ) {
354 _attachedMedia.erase(i);
355 } else {
356 ERR << "Releasing unknown medium " << ptr->mediaId () << " should not happen";
357 }
358 }
359
360
361}
void reset()
Reset to default Ctor values.
void setDispose(const Dispose &dispose_r)
Set a new dispose function.
Base class for Exception.
Definition Exception.h:147
Url manipulation class.
Definition Url.h:92
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition Url.cc:608
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition Url.cc:768
Base class for reference counted objects.
Wrapper class for stat/lstat.
Definition PathInfo.h:222
const std::string & asString() const
String representation.
Definition Pathname.h:91
bool empty() const
Test for an empty path.
Definition Pathname.h:114
Just inherits Exception to separate media exceptions.
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
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.
Implementation of the traditional SUSE media verifier.
zypp::media::MediaAccessId _id
MediaSyncFacadeRef _parent
std::optional< zypp::Pathname > _localPath
AttachedSyncMediaInfo(MediaSyncFacadeRef parentRef, zypp::media::MediaAccessId mediaId, zypp::Url baseUrl, ProvideMediaSpec mediaSpec, const zypp::Pathname &locPath)
const zypp::Url & url() const
MediaSyncFacadeRef parent() const
bool isSameMedium(const std::vector< zypp::Url > &urls, const ProvideMediaSpec &spec)
const std::optional< zypp::Pathname > & rootPath() const
zypp::media::MediaAccessId mediaId() const
void unref_to(unsigned int) const override
const ProvideMediaSpec & spec() const
Res(MediaHandle hdl, zypp::ManagedFile file)
const zypp::Pathname file() const
expected< Res > provide(const std::vector< zypp::Url > &urls, const ProvideFileSpec &request)
expected< MediaHandle > attachMedia(const std::vector< zypp::Url > &urls, const ProvideMediaSpec &request)
friend class AttachedSyncMediaInfo
Definition mediafacade.h:52
expected< zypp::CheckSum > checksumForFile(const zypp::Pathname &p, const std::string &algorithm)
expected< zypp::ManagedFile > copyFile(const zypp::Pathname &source, const zypp::Pathname &target)
std::vector< AttachedSyncMediaInfo_Ptr > _attachedMedia
void releaseMedium(const AttachedSyncMediaInfo *ptr)
zypp::OnMediaLocation asOnMediaLocation(const zypp::Pathname &path, unsigned int mediaNr) const
bool checkExistsOnly() const
zypp::TriBool isSameMedium(const ProvideMediaSpec &other)
unsigned medianr() const
zypp::Pathname mediaFile() const
const std::optional< zypp::Pathname > & localPath() const
const AttachedSyncMediaInfo & info() const
MediaSyncFacadeRef parent() const
const zypp::Url & baseUrl() const
AttachedSyncMediaInfo_Ptr _data
Definition mediafacade.h:39
Definition Arch.h:364
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:1052
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:701
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition PathInfo.cc:884
unsigned int MediaAccessId
Media manager access Id type.
Definition MediaSource.h:30
ZYPP_IMPL_PRIVATE_CONSTR(Context)
Definition context.cc:19
Wrapper for const correct access via Smart pointer types.
Definition PtrTypes.h:292
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:212
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:437
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition Exception.h:433
#define ERR
Definition Logger.h:98
#define WAR
Definition Logger.h:97
#define IMPL_PTR_TYPE(NAME)