Imported Upstream version 16.3.2
[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         UrlResolverPlugin::HeaderList::const_iterator it;
175         for (it = custom_headers.begin();
176              it != custom_headers.end();
177              ++it) {
178             std::string header = it->first + ": " + it->second;
179             MIL << "Added custom header -> " << header << endl;
180             curl->settings().addHeader(header);
181         }
182         _handler = curl;
183     }
184     else if (scheme == "plugin" )
185         _handler = new MediaPlugin (url,preferred_attach_point);
186     else
187     {
188         ZYPP_THROW(MediaUnsupportedUrlSchemeException(url));
189     }
190
191     // check created handler
192     if ( !_handler ){
193       ERR << "Failed to create media handler" << endl;
194       ZYPP_THROW(MediaSystemException(url, "Failed to create media handler"));
195     }
196
197     MIL << "Opened: " << *this << endl;
198 }
199
200 // Type of media if open, otherwise NONE.
201 std::string
202 MediaAccess::protocol() const
203 {
204   if ( !_handler )
205     return "unknown";
206
207   return _handler->protocol();
208 }
209
210 bool
211 MediaAccess::downloads() const
212 {
213         return _handler ? _handler->downloads() : false;
214 }
215
216 ///////////////////////////////////////////////////////////////////
217 //
218 //
219 //      METHOD NAME : MediaAccess::url
220 //      METHOD TYPE : Url
221 //
222 Url MediaAccess::url() const
223 {
224   if ( !_handler )
225     return Url();
226
227   return _handler->url();
228 }
229
230 // close handler
231 void
232 MediaAccess::close ()
233 {
234   ///////////////////////////////////////////////////////////////////
235   // !!! make shure handler gets properly deleted.
236   // I.e. release attached media before deleting the handler.
237   ///////////////////////////////////////////////////////////////////
238   if ( _handler ) {
239     try {
240       _handler->release();
241     }
242     catch (const MediaException & excpt_r)
243     {
244       ZYPP_CAUGHT(excpt_r);
245       WAR << "Close: " << *this << " (" << excpt_r << ")" << endl;
246       ZYPP_RETHROW(excpt_r);
247     }
248     MIL << "Close: " << *this << " (OK)" << endl;
249     delete _handler;
250     _handler = 0;
251   }
252 }
253
254
255 // attach media
256 void MediaAccess::attach (bool next)
257 {
258   if ( !_handler ) {
259     ZYPP_THROW(MediaNotOpenException("attach"));
260   }
261   _handler->attach(next);
262 }
263
264 // True if media is open and attached.
265 bool
266 MediaAccess::isAttached() const
267 {
268   return( _handler && _handler->isAttached() );
269 }
270
271
272 bool MediaAccess::hasMoreDevices() const
273 {
274   return _handler && _handler->hasMoreDevices();
275 }
276
277
278 void
279 MediaAccess::getDetectedDevices(std::vector<std::string> & devices,
280                                 unsigned int & index) const
281 {
282   if (_handler)
283   {
284     _handler->getDetectedDevices(devices, index);
285     return;
286   }
287
288   if (!devices.empty())
289     devices.clear();
290   index = 0;
291 }
292
293
294 // local directory that corresponds to medias url
295 // If media is not open an empty pathname.
296 Pathname
297 MediaAccess::localRoot() const
298 {
299   if ( !_handler )
300     return _noPath;
301
302   return _handler->localRoot();
303 }
304
305 // Short for 'localRoot() + pathname', but returns an empty
306 // * pathname if media is not open.
307 Pathname
308 MediaAccess::localPath( const Pathname & pathname ) const
309 {
310   if ( !_handler )
311     return _noPath;
312
313   return _handler->localPath( pathname );
314 }
315
316 void
317 MediaAccess::disconnect()
318 {
319   if ( !_handler )
320     ZYPP_THROW(MediaNotOpenException("disconnect"));
321
322   _handler->disconnect();
323 }
324
325
326 void
327 MediaAccess::release( const std::string & ejectDev )
328 {
329   if ( !_handler )
330     return;
331
332   _handler->release( ejectDev );
333 }
334
335 // provide file denoted by path to attach dir
336 //
337 // filename is interpreted relative to the attached url
338 // and a path prefix is preserved to destination
339 void
340 MediaAccess::provideFile( const Pathname & filename ) const
341 {
342   if ( !_handler ) {
343     ZYPP_THROW(MediaNotOpenException("provideFile(" + filename.asString() + ")"));
344   }
345
346   _handler->provideFile( filename );
347 }
348
349 void
350 MediaAccess::setDeltafile( const Pathname & filename ) const
351 {
352   if ( !_handler ) {
353     ZYPP_THROW(MediaNotOpenException("setDeltafile(" + filename.asString() + ")"));
354   }
355
356   _handler->setDeltafile( filename );
357 }
358
359 void
360 MediaAccess::releaseFile( const Pathname & filename ) const
361 {
362   if ( !_handler )
363     return;
364
365   _handler->releaseFile( filename );
366 }
367
368 // provide directory tree denoted by path to attach dir
369 //
370 // dirname is interpreted relative to the attached url
371 // and a path prefix is preserved to destination
372 void
373 MediaAccess::provideDir( const Pathname & dirname ) const
374 {
375   if ( !_handler ) {
376     ZYPP_THROW(MediaNotOpenException("provideDir(" + dirname.asString() + ")"));
377   }
378
379   _handler->provideDir( dirname );
380 }
381
382 void
383 MediaAccess::provideDirTree( const Pathname & dirname ) const
384 {
385   if ( !_handler ) {
386     ZYPP_THROW(MediaNotOpenException("provideDirTree(" + dirname.asString() + ")"));
387   }
388
389   _handler->provideDirTree( dirname );
390 }
391
392 void
393 MediaAccess::releaseDir( const Pathname & dirname ) const
394 {
395   if ( !_handler )
396     return;
397
398   _handler->releaseDir( dirname );
399 }
400
401 void
402 MediaAccess::releasePath( const Pathname & pathname ) const
403 {
404   if ( !_handler )
405     return;
406
407   _handler->releasePath( pathname );
408 }
409
410 // Return content of directory on media
411 void
412 MediaAccess::dirInfo( std::list<std::string> & retlist, const Pathname & dirname, bool dots ) const
413 {
414   retlist.clear();
415
416   if ( !_handler ) {
417     ZYPP_THROW(MediaNotOpenException("dirInfo(" + dirname.asString() + ")"));
418   }
419
420   _handler->dirInfo( retlist, dirname, dots );
421 }
422
423 // Return content of directory on media
424 void
425 MediaAccess::dirInfo( filesystem::DirContent & retlist, const Pathname & dirname, bool dots ) const
426 {
427   retlist.clear();
428
429   if ( !_handler ) {
430     ZYPP_THROW(MediaNotOpenException("dirInfo(" + dirname.asString() + ")"));
431   }
432
433   _handler->dirInfo( retlist, dirname, dots );
434 }
435
436 // return if a file exists
437 bool
438 MediaAccess::doesFileExist( const Pathname & filename ) const
439 {
440   if ( !_handler ) {
441     ZYPP_THROW(MediaNotOpenException("doesFileExist(" + filename.asString() + ")"));
442   }
443
444   return _handler->doesFileExist( filename );
445 }
446
447 std::ostream &
448 MediaAccess::dumpOn( std::ostream & str ) const
449 {
450   if ( !_handler )
451     return str << "MediaAccess( closed )";
452
453   str << _handler->protocol() << "(" << *_handler << ")";
454   return str;
455 }
456
457 void MediaAccess::getFile( const Url &from, const Pathname &to )
458 {
459   DBG << "From: " << from << endl << "To: " << to << endl;
460
461   Pathname path = from.getPathData();
462   Pathname dir = path.dirname();
463   string base = path.basename();
464
465   Url u = from;
466   u.setPathData( dir.asString() );
467
468   MediaAccess media;
469
470   try {
471     media.open( u );
472     media.attach();
473     media._handler->provideFileCopy( base, to );
474     media.release();
475   }
476   catch (const MediaException & excpt_r)
477   {
478     ZYPP_RETHROW(excpt_r);
479   }
480 }
481
482     std::ostream & operator<<( std::ostream & str, const MediaAccess & obj )
483     { return obj.dumpOn( str ); }
484
485 ///////////////////////////////////////////////////////////////////
486   } // namespace media
487 } // namespace zypp