- catch exceptions in dtors
[platform/upstream/libzypp.git] / zypp / media / MediaHandler.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/media/MediaHandler.cc
10  *
11 */
12
13 #include <iostream>
14 #include <fstream>
15 #include <sstream>
16
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/String.h"
19 #include "zypp/media/MediaHandler.h"
20 #include "zypp/media/MediaManager.h"
21
22 using namespace std;
23
24 // use directory.yast on every media (not just via ftp/http)
25 #define NONREMOTE_DIRECTORY_YAST 1
26
27 namespace zypp {
28   namespace media {
29
30
31
32 ///////////////////////////////////////////////////////////////////
33 //
34 //      CLASS NAME : MediaHandler
35 //
36 ///////////////////////////////////////////////////////////////////
37
38 ///////////////////////////////////////////////////////////////////
39 //
40 //
41 //      METHOD NAME : MediaHandler::MediaHandler
42 //      METHOD TYPE : Constructor
43 //
44 //      DESCRIPTION :
45 //
46 MediaHandler::MediaHandler ( const Url &      url_r,
47                              const Pathname & attach_point_r,
48                              const Pathname & urlpath_below_attachpoint_r,
49                              const bool       does_download_r )
50     : _attachPoint( new AttachPoint())
51     , _relativeRoot( urlpath_below_attachpoint_r)
52     , _does_download( does_download_r )
53     , _url( url_r )
54 {
55   if ( !attach_point_r.empty() ) {
56     ///////////////////////////////////////////////////////////////////
57     // check if provided attachpoint is usable.
58     ///////////////////////////////////////////////////////////////////
59
60     PathInfo adir( attach_point_r );
61     // FIXME: verify if attach_point_r isn't a mountpoint of other device
62     if ( !adir.isDir() ) {
63       ERR << "Provided attach point is not a directory: " << adir << endl;
64     }
65     else {
66       setAttachPoint( attach_point_r, false);
67     }
68   }
69 }
70
71 ///////////////////////////////////////////////////////////////////
72 //
73 //
74 //      METHOD NAME : MediaHandler::~MediaHandler
75 //      METHOD TYPE : Destructor
76 //
77 //      DESCRIPTION :
78 //
79 MediaHandler::~MediaHandler()
80 {
81   try
82     {
83       removeAttachPoint();
84     }
85   catch(...) {}
86 }
87
88 ///////////////////////////////////////////////////////////////////
89 //
90 //
91 //      METHOD NAME : MediaHandler::removeAttachPoint
92 //      METHOD TYPE : void
93 //
94 //      DESCRIPTION :
95 //
96 void
97 MediaHandler::removeAttachPoint()
98 {
99   if ( _mediaSource ) {
100     INT << "MediaHandler deleted with media attached." << endl;
101     return; // no cleanup if media still mounted!
102   }
103
104   if ( _attachPoint.unique() &&
105        _attachPoint->temp    &&
106        !_attachPoint->path.empty())
107   {
108     int res = recursive_rmdir( _attachPoint->path );
109     if ( res == 0 ) {
110       MIL << "Deleted default attach point " << _attachPoint->path << endl;
111     } else {
112       ERR << "Failed to Delete default attach point " << _attachPoint->path
113         << " errno(" << res << ")" << endl;
114     }
115   }
116 }
117
118
119 ///////////////////////////////////////////////////////////////////
120 //
121 //
122 //      METHOD NAME : MediaHandler::attachPoint
123 //      METHOD TYPE : Pathname
124 //
125 //      DESCRIPTION :
126 //
127 Pathname
128 MediaHandler::attachPoint() const
129 {
130   return _attachPoint->path;
131 }
132
133
134 ///////////////////////////////////////////////////////////////////
135 //
136 //
137 //      METHOD NAME : MediaHandler::attachPoint
138 //      METHOD TYPE :
139 //
140 //      DESCRIPTION :
141 //
142 void
143 MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
144 {
145   _localRoot = Pathname();
146
147   _attachPoint.reset( new AttachPoint(path, temporary));
148
149   if( !_attachPoint->path.empty())
150     _localRoot = _attachPoint->path + _relativeRoot;
151 }
152
153
154 ///////////////////////////////////////////////////////////////////
155 //
156 //
157 //      METHOD NAME : MediaHandler::attachPoint
158 //      METHOD TYPE :
159 //
160 //      DESCRIPTION :
161 //
162 void
163 MediaHandler::setAttachPoint(const AttachPointRef &ref)
164 {
165   _localRoot = Pathname();
166
167   if( ref)
168     AttachPointRef(ref).swap(_attachPoint);
169   else
170     _attachPoint.reset( new AttachPoint());
171
172   if( !_attachPoint->path.empty())
173     _localRoot = _attachPoint->path + _relativeRoot;
174 }
175
176
177 ///////////////////////////////////////////////////////////////////
178 //
179 //
180 //      METHOD NAME : MediaHandler::findAttachedMedia
181 //      METHOD TYPE : AttachedMedia
182 //
183 //      DESCRIPTION :
184 //
185 AttachedMedia
186 MediaHandler::findAttachedMedia(const MediaSourceRef &media) const
187 {
188         return MediaManager().findAttachedMedia(media);
189 }
190
191
192 ///////////////////////////////////////////////////////////////////
193 //
194 //
195 //      METHOD NAME : MediaHandler::attach
196 //      METHOD TYPE : Pathname
197 //
198 //      DESCRIPTION :
199 //
200 Pathname
201 MediaHandler::createAttachPoint() const
202 {
203   /////////////////////////////////////////////////////////////////
204   // provide a default (temporary) attachpoint
205   /////////////////////////////////////////////////////////////////
206   const char * defmounts[] = {
207       "/var/adm/mount", "/var/tmp", /**/NULL/**/
208   };
209
210   Pathname aroot;
211   PathInfo adir;
212   for ( const char ** def = defmounts; *def; ++def ) {
213     adir( *def );
214     if ( adir.isDir() && adir.userMayRWX() ) {
215       aroot = adir.path();
216       break;
217     }
218   }
219   if ( aroot.empty() ) {
220     ERR << "Create attach point: Can't find a writable directory to create an attach point" << std::endl;
221     return aroot;
222   }
223
224   Pathname abase( aroot + "AP_" );
225   Pathname apoint;
226   for ( unsigned i = 1; i < 1000; ++i ) {
227     adir( Pathname::extend( abase, str::hexstring( i ) ) );
228     if ( ! adir.isExist() && mkdir( adir.path() ) == 0 ) {
229             apoint = adir.path();
230             break;
231     }
232   }
233   if ( apoint.empty() ) {
234     ERR << "Unable to create an attach point below " << aroot << std::endl;
235   } else {
236     MIL << "Created default attach point " << apoint << std::endl;
237   }
238   return apoint;
239 }
240
241 ///////////////////////////////////////////////////////////////////
242 //
243 //
244 //      METHOD NAME : MediaHandler::setMediaSource
245 //      METHOD TYPE : void
246 //
247 //      DESCRIPTION :
248 //
249 void
250 MediaHandler::setMediaSource(const MediaSourceRef &ref)
251 {
252   _mediaSource.reset();
253   if( ref && !ref->type.empty() && !ref->name.empty())
254     _mediaSource = ref;
255 }
256
257 ///////////////////////////////////////////////////////////////////
258 //
259 //
260 //      METHOD NAME : MediaHandler::attachedMedia
261 //      METHOD TYPE : AttachedMedia
262 //
263 //      DESCRIPTION :
264 //
265 AttachedMedia
266 MediaHandler::attachedMedia() const
267 {
268   if ( _mediaSource && _attachPoint)
269     return AttachedMedia(_mediaSource, _attachPoint);
270   else
271     return AttachedMedia();
272 }
273
274
275 ///////////////////////////////////////////////////////////////////
276 //
277 //
278 //      METHOD NAME : MediaHandler::attach
279 //      METHOD TYPE : PMError
280 //
281 //      DESCRIPTION :
282 //
283 void MediaHandler::attach( bool next )
284 {
285   if ( isAttached() )
286     return;
287
288 /**
289   if ( _attachPoint->empty() ) {
290     ERR << "Bad Attachpoint" << endl;
291     ZYPP_THROW( MediaBadAttachPointException(url()));
292   }
293 */
294
295   attachTo( next ); // pass to concrete handler
296   MIL << "Attached: " << *this << endl;
297 }
298
299
300
301
302 ///////////////////////////////////////////////////////////////////
303 //
304 //
305 //      METHOD NAME : MediaHandler::localPath
306 //      METHOD TYPE : Pathname
307 //
308 Pathname MediaHandler::localPath( const Pathname & pathname ) const {
309     if ( _localRoot.empty() )
310         return _localRoot;
311
312     // we must check maximum file name length
313     // this is important for fetching the suseservers, the
314     // url with all parameters can get too long (bug #42021)
315
316     return _localRoot + pathname.absolutename();
317 }
318
319
320
321
322
323 ///////////////////////////////////////////////////////////////////
324 //
325 //
326 //      METHOD NAME : MediaHandler::disconnect
327 //      METHOD TYPE : PMError
328 //
329 void MediaHandler::disconnect()
330 {
331   if ( !isAttached() )
332     return;
333
334   disconnectFrom(); // pass to concrete handler
335   MIL << "Disconnected: " << *this << endl;
336 }
337
338 ///////////////////////////////////////////////////////////////////
339 //
340 //
341 //      METHOD NAME : MediaHandler::release
342 //      METHOD TYPE : PMError
343 //
344 //      DESCRIPTION :
345 //
346 void MediaHandler::release( bool eject )
347 {
348   if ( !isAttached() ) {
349     DBG << "Request to release media - not attached" << std::endl;
350     if ( eject )
351       forceEject();
352     return;
353   }
354
355   DBG << "Request to release attached media "
356       << _mediaSource->asString()
357       << (_mediaSource.unique() ? ", unique" : ", not unique")
358       << std::endl;
359
360   if( _mediaSource.unique())
361   {
362     DBG << "Releasing media " << _mediaSource->asString() << std::endl;
363     releaseFrom( eject ); // pass to concrete handler
364   }
365
366   _mediaSource.reset();
367   MIL << "Released: " << *this << endl;
368 }
369
370 ///////////////////////////////////////////////////////////////////
371 //
372 //
373 //      METHOD NAME : MediaHandler::provideFile
374 //      METHOD TYPE : PMError
375 //
376 //      DESCRIPTION :
377 //
378 void MediaHandler::provideFileCopy( Pathname srcFilename,
379                                        Pathname targetFilename ) const
380 {
381   if ( !isAttached() ) {
382     INT << "Media not_attached on provideFileCopy(" << srcFilename
383         << "," << targetFilename << ")" << endl;
384     ZYPP_THROW(MediaNotAttachedException(url()));
385   }
386
387   getFileCopy( srcFilename, targetFilename ); // pass to concrete handler
388   DBG << "provideFileCopy(" << srcFilename << "," << targetFilename  << ")" << endl;
389 }
390
391 void MediaHandler::provideFile( Pathname filename ) const
392 {
393   if ( !isAttached() ) {
394     INT << "Error: Not attached on provideFile(" << filename << ")" << endl;
395     ZYPP_THROW(MediaNotAttachedException(url()));
396   }
397
398   getFile( filename ); // pass to concrete handler
399   DBG << "provideFile(" << filename << ")" << endl;
400 }
401
402
403 ///////////////////////////////////////////////////////////////////
404 //
405 //
406 //      METHOD NAME : MediaHandler::provideDir
407 //      METHOD TYPE : PMError
408 //
409 //      DESCRIPTION :
410 //
411 void MediaHandler::provideDir( Pathname dirname ) const
412 {
413   if ( !isAttached() ) {
414     INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
415     ZYPP_THROW(MediaNotAttachedException(url()));
416   }
417
418   getDir( dirname, /*recursive*/false ); // pass to concrete handler
419   MIL << "provideDir(" << dirname << ")" << endl;
420 }
421
422 ///////////////////////////////////////////////////////////////////
423 //
424 //
425 //      METHOD NAME : MediaHandler::provideDirTree
426 //      METHOD TYPE : PMError
427 //
428 //      DESCRIPTION :
429 //
430 void MediaHandler::provideDirTree( Pathname dirname ) const
431 {
432   if ( !isAttached() ) {
433     INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
434     ZYPP_THROW(MediaNotAttachedException(url()));
435   }
436
437   getDir( dirname, /*recursive*/true ); // pass to concrete handler
438   MIL << "provideDirTree(" << dirname << ")" << endl;
439 }
440
441 ///////////////////////////////////////////////////////////////////
442 //
443 //
444 //      METHOD NAME : MediaHandler::releasePath
445 //      METHOD TYPE : PMError
446 //
447 //      DESCRIPTION :
448 //
449 void MediaHandler::releasePath( Pathname pathname ) const
450 {
451   if ( ! _does_download || _attachPoint->empty() )
452     return;
453
454   PathInfo info( localPath( pathname ) );
455
456   if ( info.isFile() ) {
457     unlink( info.path() );
458   } else if ( info.isDir() ) {
459     if ( info.path() != _localRoot ) {
460       recursive_rmdir( info.path() );
461     } else {
462       clean_dir( info.path() );
463     }
464   }
465 }
466
467 ///////////////////////////////////////////////////////////////////
468 //
469 //
470 //      METHOD NAME : MediaHandler::dirInfo
471 //      METHOD TYPE : PMError
472 //
473 //      DESCRIPTION :
474 //
475 void MediaHandler::dirInfo( list<string> & retlist,
476                                const Pathname & dirname, bool dots ) const
477 {
478   retlist.clear();
479
480   if ( !isAttached() ) {
481     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
482     ZYPP_THROW(MediaNotAttachedException(url()));
483   }
484
485   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
486   MIL << "dirInfo(" << dirname << ")" << endl;
487 }
488
489 ///////////////////////////////////////////////////////////////////
490 //
491 //
492 //      METHOD NAME : MediaHandler::dirInfo
493 //      METHOD TYPE : PMError
494 //
495 //      DESCRIPTION :
496 //
497 void MediaHandler::dirInfo( filesystem::DirContent & retlist,
498                             const Pathname & dirname, bool dots ) const
499 {
500   retlist.clear();
501
502   if ( !isAttached() ) {
503     INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
504     ZYPP_THROW(MediaNotAttachedException(url()));
505   }
506
507   getDirInfo( retlist, dirname, dots ); // pass to concrete handler
508   MIL << "dirInfo(" << dirname << ")" << endl;
509 }
510
511 ///////////////////////////////////////////////////////////////////
512 //
513 //
514 //      METHOD NAME : MediaHandler::getDirectoryYast
515 //      METHOD TYPE : PMError
516 //
517 void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
518                                         const Pathname & dirname, bool dots ) const
519 {
520   retlist.clear();
521
522   filesystem::DirContent content;
523   getDirectoryYast( content, dirname, dots );
524
525   // convert to std::list<std::string>
526   for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
527     retlist.push_back( it->name );
528   }
529 }
530
531 ///////////////////////////////////////////////////////////////////
532 //
533 //
534 //      METHOD NAME : MediaHandler::getDirectoryYast
535 //      METHOD TYPE : PMError
536 //
537 void MediaHandler::getDirectoryYast( filesystem::DirContent & retlist,
538                                      const Pathname & dirname, bool dots ) const
539 {
540   retlist.clear();
541
542   // look for directory.yast
543   Pathname dirFile = dirname + "directory.yast";
544   getFile( dirFile );
545   DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
546
547   // using directory.yast
548   ifstream dir( localPath( dirFile ).asString().c_str() );
549   if ( dir.fail() ) {
550     ERR << "Unable to load '" << localPath( dirFile ) << "'" << endl;
551     ZYPP_THROW(MediaSystemException(url(),
552       "Unable to load '" + localPath( dirFile ).asString() + "'"));
553   }
554
555   string line;
556   while( getline( dir, line ) ) {
557     if ( line.empty() ) continue;
558     if ( line == "directory.yast" ) continue;
559
560     // Newer directory.yast append '/' to directory names
561     // Remaining entries are unspecified, although most probabely files.
562     filesystem::FileType type = filesystem::FT_NOT_AVAIL;
563     if ( *line.rbegin() == '/' ) {
564       line.erase( line.end()-1 );
565       type = filesystem::FT_DIR;
566     }
567
568     if ( dots ) {
569       if ( line == "." || line == ".." ) continue;
570     } else {
571       if ( *line.begin() == '.' ) continue;
572     }
573
574     retlist.push_back( filesystem::DirEntry( line, type ) );
575   }
576 }
577
578 /******************************************************************
579 **
580 **
581 **      FUNCTION NAME : operator<<
582 **      FUNCTION TYPE : ostream &
583 */
584 ostream & operator<<( ostream & str, const MediaHandler & obj )
585 {
586   str << obj.url() << ( obj.isAttached() ? "" : " not" )
587     << " attached; localRoot \"" << obj.localRoot() << "\"";
588   return str;
589 }
590
591 ///////////////////////////////////////////////////////////////////
592 //
593 //
594 //      METHOD NAME : MediaHandler::getFile
595 //      METHOD TYPE : PMError
596 //
597 //      DESCRIPTION : Asserted that media is attached.
598 //                    Default implementation of pure virtual.
599 //
600 void MediaHandler::getFile( const Pathname & filename ) const
601 {
602     PathInfo info( localPath( filename ) );
603     if( info.isFile() ) {
604         return;
605     }
606
607     if (info.isExist())
608       ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
609     else
610       ZYPP_THROW(MediaFileNotFoundException(url(), filename));
611 }
612
613
614 void MediaHandler::getFileCopy ( const Pathname & srcFilename, const Pathname & targetFilename ) const
615 {
616   getFile(srcFilename);
617
618   if ( copy( localPath( srcFilename ), targetFilename ) != 0 ) {
619     ZYPP_THROW(MediaWriteException(targetFilename));
620   }
621 }
622
623
624
625 ///////////////////////////////////////////////////////////////////
626 //
627 //
628 //      METHOD NAME : MediaHandler::getDir
629 //      METHOD TYPE : PMError
630 //
631 //      DESCRIPTION : Asserted that media is attached.
632 //                    Default implementation of pure virtual.
633 //
634 void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
635 {
636   PathInfo info( localPath( dirname ) );
637   if( info.isDir() ) {
638     return;
639   }
640
641   if (info.isExist())
642     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
643   else
644     ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
645 }
646
647 ///////////////////////////////////////////////////////////////////
648 //
649 //
650 //      METHOD NAME : MediaHandler::getDirInfo
651 //      METHOD TYPE : PMError
652 //
653 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
654 //                    Default implementation of pure virtual.
655 //
656 void MediaHandler::getDirInfo( std::list<std::string> & retlist,
657                                const Pathname & dirname, bool dots ) const
658 {
659   PathInfo info( localPath( dirname ) );
660   if( ! info.isDir() ) {
661     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
662   }
663
664 #if NONREMOTE_DIRECTORY_YAST
665   // use directory.yast if available
666   try {
667     getDirectoryYast( retlist, dirname, dots );
668   }
669   catch (const MediaException & excpt_r)
670   {
671 #endif
672
673   // readdir
674     int res = readdir( retlist, info.path(), dots );
675   if ( res )
676     ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
677
678 #if NONREMOTE_DIRECTORY_YAST
679   }
680 #endif
681
682   return;
683 }
684
685 ///////////////////////////////////////////////////////////////////
686 //
687 //
688 //      METHOD NAME : MediaHandler::getDirInfo
689 //      METHOD TYPE : PMError
690 //
691 //      DESCRIPTION : Asserted that media is attached and retlist is empty.
692 //                    Default implementation of pure virtual.
693 //
694 void MediaHandler::getDirInfo( filesystem::DirContent & retlist,
695                                const Pathname & dirname, bool dots ) const
696 {
697   PathInfo info( localPath( dirname ) );
698   if( ! info.isDir() ) {
699     ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
700   }
701
702 #if NONREMOTE_DIRECTORY_YAST
703   // use directory.yast if available
704   try {
705     getDirectoryYast( retlist, dirname, dots );
706   }
707   catch (const MediaException & excpt_r)
708   {
709 #endif
710
711   // readdir
712   int res = readdir( retlist, info.path(), dots );
713   if ( res )
714     ZYPP_THROW(MediaSystemException(url(), "readdir failed"));
715 #if NONREMOTE_DIRECTORY_YAST
716   }
717 #endif
718 }
719
720   } // namespace media
721 } // namespace zypp