Imported Upstream version 17.20.0
[platform/upstream/libzypp.git] / zypp / media / MediaAccess.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaAccess.cc
10  *
11 */
12
13 #include <ctype.h>
14
15 #include <iostream>
16 #include <map>
17
18 #include "zypp/base/Logger.h"
19 #include "zypp/ZConfig.h"
20 #include "zypp/PluginScript.h"
21 #include "zypp/ExternalProgram.h"
22
23 #include "zypp/media/MediaException.h"
24 #include "zypp/media/MediaAccess.h"
25 #include "zypp/media/MediaHandler.h"
26
27 #include "zypp/media/MediaNFS.h"
28 #include "zypp/media/MediaCD.h"
29 #include "zypp/media/MediaDIR.h"
30 #include "zypp/media/MediaDISK.h"
31 #include "zypp/media/MediaCIFS.h"
32 #include "zypp/media/MediaCurl.h"
33 #include "zypp/media/MediaMultiCurl.h"
34 #include "zypp/media/MediaISO.h"
35 #include "zypp/media/MediaPlugin.h"
36 #include "zypp/media/UrlResolverPlugin.h"
37
38 using namespace std;
39
40 namespace zypp {
41   namespace media {
42
43 ///////////////////////////////////////////////////////////////////
44 //
45 //      CLASS NAME : MediaAccess
46 //
47 ///////////////////////////////////////////////////////////////////
48
49 const Pathname MediaAccess::_noPath; // empty path
50
51 ///////////////////////////////////////////////////////////////////
52 // constructor
53 MediaAccess::MediaAccess ()
54     : _handler (0)
55 {
56 }
57
58 // destructor
59 MediaAccess::~MediaAccess()
60 {
61   try
62     {
63       close(); // !!! make sure handler gets properly deleted.
64     }
65   catch(...) {}
66 }
67
68 AttachedMedia
69 MediaAccess::attachedMedia() const
70 {
71         return _handler ? _handler->attachedMedia()
72                         : AttachedMedia();
73 }
74
75 bool
76 MediaAccess::isSharedMedia() const
77 {
78         return _handler ? _handler->isSharedMedia()
79                         : false;
80 }
81
82 void
83 MediaAccess::resetParentId()
84 {
85         if( _handler) _handler->resetParentId();
86 }
87
88 bool
89 MediaAccess::dependsOnParent() const
90 {
91         return _handler ? _handler->dependsOnParent() : false;
92 }
93
94 bool
95 MediaAccess::dependsOnParent(MediaAccessId parentId,
96                              bool exactIdMatch) const
97 {
98         return _handler ? _handler->dependsOnParent(parentId, exactIdMatch)
99                         : false;
100 }
101
102 // open URL
103 void
104 MediaAccess::open (const Url& o_url, const Pathname & preferred_attach_point)
105 {
106     if(!o_url.isValid()) {
107         MIL << "Url is not valid" << endl;
108         ZYPP_THROW(MediaBadUrlException(o_url));
109     }
110
111     close();
112
113     UrlResolverPlugin::HeaderList custom_headers;
114     Url url = UrlResolverPlugin::resolveUrl(o_url, custom_headers);
115
116     std::string scheme = url.getScheme();
117     MIL << "Trying scheme '" << scheme << "'" << endl;
118
119     /*
120     ** WARNING: Don't forget to update MediaAccess::downloads(url)
121     **          if you are adding a new url scheme / handler!
122     */
123     if (scheme == "cd" || scheme == "dvd")
124         _handler = new MediaCD (url,preferred_attach_point);
125     else if (scheme == "nfs" || scheme == "nfs4")
126         _handler = new MediaNFS (url,preferred_attach_point);
127     else if (scheme == "iso")
128         _handler = new MediaISO (url,preferred_attach_point);
129     else if (scheme == "file" || scheme == "dir")
130         _handler = new MediaDIR (url,preferred_attach_point);
131     else if (scheme == "hd")
132         _handler = new MediaDISK (url,preferred_attach_point);
133     else if (scheme == "cifs" || scheme == "smb")
134         _handler = new MediaCIFS (url,preferred_attach_point);
135     else if (scheme == "ftp" || scheme == "tftp" || scheme == "http" || scheme == "https")
136     {
137         bool use_multicurl = true;
138         string urlmediahandler ( url.getQueryParam("mediahandler") );
139         if ( urlmediahandler == "multicurl" )
140         {
141           use_multicurl = true;
142         }
143         else if ( urlmediahandler == "curl" )
144         {
145           use_multicurl = false;
146         }
147         else
148         {
149           if ( ! urlmediahandler.empty() )
150           {
151             WAR << "unknown mediahandler set: " << urlmediahandler << endl;
152           }
153           const char *multicurlenv = getenv( "ZYPP_MULTICURL" );
154           // if user disabled it manually
155           if ( use_multicurl && multicurlenv && ( strcmp(multicurlenv, "0" ) == 0 ) )
156           {
157               WAR << "multicurl manually disabled." << endl;
158               use_multicurl = false;
159           }
160           else if ( !use_multicurl && multicurlenv && ( strcmp(multicurlenv, "1" ) == 0 ) )
161           {
162               WAR << "multicurl manually enabled." << endl;
163               use_multicurl = true;
164           }
165         }
166
167         MediaCurl *curl;
168
169         if ( use_multicurl )
170             curl = new MediaMultiCurl (url,preferred_attach_point);
171         else
172             curl = new MediaCurl (url,preferred_attach_point);
173
174         for ( const auto & el : custom_headers ) {
175             std::string header { el.first };
176             header += ": ";
177             header += el.second;
178             MIL << "Added custom header -> " << header << endl;
179             curl->settings().addHeader( std::move(header) );
180         }
181         _handler = curl;
182     }
183     else if (scheme == "plugin" )
184         _handler = new MediaPlugin (url,preferred_attach_point);
185     else
186     {
187         ZYPP_THROW(MediaUnsupportedUrlSchemeException(url));
188     }
189
190     // check created handler
191     if ( !_handler ){
192       ERR << "Failed to create media handler" << endl;
193       ZYPP_THROW(MediaSystemException(url, "Failed to create media handler"));
194     }
195
196     MIL << "Opened: " << *this << endl;
197 }
198
199 // Type of media if open, otherwise NONE.
200 std::string
201 MediaAccess::protocol() const
202 {
203   if ( !_handler )
204     return "unknown";
205
206   return _handler->protocol();
207 }
208
209 bool
210 MediaAccess::downloads() const
211 {
212         return _handler ? _handler->downloads() : false;
213 }
214
215 ///////////////////////////////////////////////////////////////////
216 //
217 //
218 //      METHOD NAME : MediaAccess::url
219 //      METHOD TYPE : Url
220 //
221 Url MediaAccess::url() const
222 {
223   if ( !_handler )
224     return Url();
225
226   return _handler->url();
227 }
228
229 // close handler
230 void
231 MediaAccess::close ()
232 {
233   ///////////////////////////////////////////////////////////////////
234   // !!! make shure handler gets properly deleted.
235   // I.e. release attached media before deleting the handler.
236   ///////////////////////////////////////////////////////////////////
237   if ( _handler ) {
238     try {
239       _handler->release();
240     }
241     catch (const MediaException & excpt_r)
242     {
243       ZYPP_CAUGHT(excpt_r);
244       WAR << "Close: " << *this << " (" << excpt_r << ")" << endl;
245       ZYPP_RETHROW(excpt_r);
246     }
247     MIL << "Close: " << *this << " (OK)" << endl;
248     delete _handler;
249     _handler = 0;
250   }
251 }
252
253
254 // attach media
255 void MediaAccess::attach (bool next)
256 {
257   if ( !_handler ) {
258     ZYPP_THROW(MediaNotOpenException("attach"));
259   }
260   _handler->attach(next);
261 }
262
263 // True if media is open and attached.
264 bool
265 MediaAccess::isAttached() const
266 {
267   return( _handler && _handler->isAttached() );
268 }
269
270
271 bool MediaAccess::hasMoreDevices() const
272 {
273   return _handler && _handler->hasMoreDevices();
274 }
275
276
277 void
278 MediaAccess::getDetectedDevices(std::vector<std::string> & devices,
279                                 unsigned int & index) const
280 {
281   if (_handler)
282   {
283     _handler->getDetectedDevices(devices, index);
284     return;
285   }
286
287   if (!devices.empty())
288     devices.clear();
289   index = 0;
290 }
291
292
293 // local directory that corresponds to medias url
294 // If media is not open an empty pathname.
295 Pathname
296 MediaAccess::localRoot() const
297 {
298   if ( !_handler )
299     return _noPath;
300
301   return _handler->localRoot();
302 }
303
304 // Short for 'localRoot() + pathname', but returns an empty
305 // * pathname if media is not open.
306 Pathname
307 MediaAccess::localPath( const Pathname & pathname ) const
308 {
309   if ( !_handler )
310     return _noPath;
311
312   return _handler->localPath( pathname );
313 }
314
315 void
316 MediaAccess::disconnect()
317 {
318   if ( !_handler )
319     ZYPP_THROW(MediaNotOpenException("disconnect"));
320
321   _handler->disconnect();
322 }
323
324
325 void
326 MediaAccess::release( const std::string & ejectDev )
327 {
328   if ( !_handler )
329     return;
330
331   _handler->release( ejectDev );
332 }
333
334 // provide file denoted by path to attach dir
335 //
336 // filename is interpreted relative to the attached url
337 // and a path prefix is preserved to destination
338 void
339 MediaAccess::provideFile(const Pathname & filename , const ByteCount &expectedFileSize) const
340 {
341   if ( !_handler ) {
342     ZYPP_THROW(MediaNotOpenException("provideFile(" + filename.asString() + ")"));
343   }
344
345   _handler->provideFile( filename, expectedFileSize );
346 }
347
348 void
349 MediaAccess::setDeltafile( const Pathname & filename ) const
350 {
351   if ( !_handler ) {
352     ZYPP_THROW(MediaNotOpenException("setDeltafile(" + filename.asString() + ")"));
353   }
354
355   _handler->setDeltafile( filename );
356 }
357
358 void
359 MediaAccess::releaseFile( const Pathname & filename ) const
360 {
361   if ( !_handler )
362     return;
363
364   _handler->releaseFile( filename );
365 }
366
367 // provide directory tree denoted by path to attach dir
368 //
369 // dirname is interpreted relative to the attached url
370 // and a path prefix is preserved to destination
371 void
372 MediaAccess::provideDir( const Pathname & dirname ) const
373 {
374   if ( !_handler ) {
375     ZYPP_THROW(MediaNotOpenException("provideDir(" + dirname.asString() + ")"));
376   }
377
378   _handler->provideDir( dirname );
379 }
380
381 void
382 MediaAccess::provideDirTree( const Pathname & dirname ) const
383 {
384   if ( !_handler ) {
385     ZYPP_THROW(MediaNotOpenException("provideDirTree(" + dirname.asString() + ")"));
386   }
387
388   _handler->provideDirTree( dirname );
389 }
390
391 void
392 MediaAccess::releaseDir( const Pathname & dirname ) const
393 {
394   if ( !_handler )
395     return;
396
397   _handler->releaseDir( dirname );
398 }
399
400 void
401 MediaAccess::releasePath( const Pathname & pathname ) const
402 {
403   if ( !_handler )
404     return;
405
406   _handler->releasePath( pathname );
407 }
408
409 // Return content of directory on media
410 void
411 MediaAccess::dirInfo( std::list<std::string> & retlist, const Pathname & dirname, bool dots ) const
412 {
413   retlist.clear();
414
415   if ( !_handler ) {
416     ZYPP_THROW(MediaNotOpenException("dirInfo(" + dirname.asString() + ")"));
417   }
418
419   _handler->dirInfo( retlist, dirname, dots );
420 }
421
422 // Return content of directory on media
423 void
424 MediaAccess::dirInfo( filesystem::DirContent & retlist, const Pathname & dirname, bool dots ) const
425 {
426   retlist.clear();
427
428   if ( !_handler ) {
429     ZYPP_THROW(MediaNotOpenException("dirInfo(" + dirname.asString() + ")"));
430   }
431
432   _handler->dirInfo( retlist, dirname, dots );
433 }
434
435 // return if a file exists
436 bool
437 MediaAccess::doesFileExist( const Pathname & filename ) const
438 {
439   if ( !_handler ) {
440     ZYPP_THROW(MediaNotOpenException("doesFileExist(" + filename.asString() + ")"));
441   }
442
443   return _handler->doesFileExist( filename );
444 }
445
446 std::ostream &
447 MediaAccess::dumpOn( std::ostream & str ) const
448 {
449   if ( !_handler )
450     return str << "MediaAccess( closed )";
451
452   str << _handler->protocol() << "(" << *_handler << ")";
453   return str;
454 }
455
456 void MediaAccess::getFile( const Url &from, const Pathname &to )
457 {
458   DBG << "From: " << from << endl << "To: " << to << endl;
459
460   Pathname path = from.getPathData();
461   Pathname dir = path.dirname();
462   string base = path.basename();
463
464   Url u = from;
465   u.setPathData( dir.asString() );
466
467   MediaAccess media;
468
469   try {
470     media.open( u );
471     media.attach();
472     media._handler->provideFileCopy( base, to, 0 );
473     media.release();
474   }
475   catch (const MediaException & excpt_r)
476   {
477     ZYPP_RETHROW(excpt_r);
478   }
479 }
480
481     std::ostream & operator<<( std::ostream & str, const MediaAccess & obj )
482     { return obj.dumpOn( str ); }
483
484 ///////////////////////////////////////////////////////////////////
485   } // namespace media
486 } // namespace zypp