libzypp  17.32.4
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 
15 namespace 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 
58  {
59  return _id;
60  }
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 }
IMPL_PTR_TYPE(AttachedSyncMediaInfo)
Res(MediaHandle hdl, zypp::ManagedFile file)
Definition: mediafacade.cc:140
Implementation of the traditional SUSE media verifier.
bool doesFileExist(MediaAccessId accessId, const Pathname &filename) const
FIXME: see MediaAccess class.
const zypp::Url & baseUrl() const
Definition: mediafacade.cc:119
expected< Res > provide(const std::vector< zypp::Url > &urls, const ProvideFileSpec &request)
Definition: mediafacade.cc:222
AttachedSyncMediaInfo(MediaSyncFacadeRef parentRef, zypp::media::MediaAccessId mediaId, zypp::Url baseUrl, ProvideMediaSpec mediaSpec, const zypp::Pathname &locPath)
Definition: mediafacade.cc:49
Definition: Arch.h:363
zypp::media::MediaAccessId mediaId() const
Definition: mediafacade.cc:57
zypp::media::MediaAccessId _id
Definition: mediafacade.cc:40
ZYPP_IMPL_PRIVATE_CONSTR(Context)
Definition: context.cc:19
ZYPP_DEPRECATED void provideFile(MediaAccessId accessId, const Pathname &filename, const ByteCount &expectedFileSize) const
MediaSyncFacadeRef parent() const
Definition: mediafacade.cc:77
expected< zypp::ManagedFile > copyFile(const zypp::Pathname &source, const zypp::Pathname &target)
Definition: mediafacade.cc:309
#define ZYPP_EXCPT_PTR(EXCPT)
Drops a logline and returns Exception as a std::exception_ptr.
Definition: Exception.h:433
zypp::OnMediaLocation asOnMediaLocation(const zypp::Pathname &path, unsigned int mediaNr) const
Definition: providespec.cc:269
#define ERR
Definition: Logger.h:98
AttachedSyncMediaInfo_Ptr _data
Definition: mediafacade.h:39
Pathname localPath(MediaAccessId accessId, const Pathname &pathname) const
Shortcut for &#39;localRoot() + pathname&#39;, but returns an empty pathname if media is not attached...
unsigned int MediaAccessId
Media manager access Id type.
Definition: MediaSource.h:30
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:768
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:211
unsigned medianr() const
Definition: providespec.cc:109
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:701
zypp::Pathname mediaFile() const
Definition: providespec.cc:118
const std::string & asString() const
String representation.
Definition: Pathname.h:91
Just inherits Exception to separate media exceptions.
#define WAR
Definition: Logger.h:97
zypp::TriBool isSameMedium(const ProvideMediaSpec &other)
Definition: providespec.cc:145
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:884
void addVerifier(MediaAccessId accessId, const MediaVerifierRef &verifier)
Add verifier implementation for the specified media id.
Base class for reference counted objects.
MediaSyncFacadeRef parent() const
Definition: mediafacade.cc:109
friend class AttachedSyncMediaInfo
Definition: mediafacade.h:52
expected< MediaHandle > attachMedia(const std::vector< zypp::Url > &urls, const ProvideMediaSpec &request)
Definition: mediafacade.cc:151
void releaseMedium(const AttachedSyncMediaInfo *ptr)
Definition: mediafacade.cc:340
void attach(MediaAccessId accessId)
Attach the media using the concrete handler (checks all devices).
void setDispose(const Dispose &dispose_r)
Set a new dispose function.
Definition: AutoDispose.h:167
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:437
const AttachedSyncMediaInfo & info() const
Definition: mediafacade.cc:135
Manages access to the &#39;physical&#39; media, e.g CDROM drives, Disk volumes, directory trees...
Definition: MediaManager.h:453
Base class for Exception.
Definition: Exception.h:146
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition: PathInfo.cc:1052
const std::optional< zypp::Pathname > & localPath() const
Definition: mediafacade.cc:127
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:608
const std::optional< zypp::Pathname > & rootPath() const
Definition: mediafacade.cc:72
bool isSameMedium(const std::vector< zypp::Url > &urls, const ProvideMediaSpec &spec)
Definition: mediafacade.cc:82
Wrapper for const correct access via Smart pointer types.
Definition: PtrTypes.h:291
const zypp::Pathname file() const
Definition: mediafacade.cc:145
std::vector< AttachedSyncMediaInfo_Ptr > _attachedMedia
Definition: mediafacade.h:113
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
MediaSyncFacadeRef _parent
Definition: mediafacade.cc:43
bool check(const std::string &sequenceinfo_r, bool quick_r)
Check via sequence info.
const ProvideMediaSpec & spec() const
Definition: mediafacade.cc:62
expected< zypp::CheckSum > checksumForFile(const zypp::Pathname &p, const std::string &algorithm)
Definition: mediafacade.cc:300
void unref_to(unsigned int) const override
Definition: mediafacade.cc:92
std::optional< zypp::Pathname > _localPath
Definition: mediafacade.cc:44
MediaAccessId open(const Url &url, const Pathname &preferred_attach_point="")
Opens the media access for specified with the url.
Url manipulation class.
Definition: Url.h:91
bool checkExistsOnly() const
Definition: providespec.cc:197
void close(MediaAccessId accessId)
Close the media access with specified id.
const zypp::Url & url() const
Definition: mediafacade.cc:67
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26