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