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