libzypp  17.31.1
MediaHandler.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <iostream>
14 #include <fstream>
15 #include <sstream>
16 
17 #include <zypp/ZConfig.h>
18 #include <zypp/TmpPath.h>
19 #include <zypp/Date.h>
20 #include <zypp/base/LogTools.h>
21 #include <zypp/base/Gettext.h>
22 #include <zypp/base/String.h>
25 #include <zypp-media/Mount>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 
30 using std::endl;
31 
32 // use directory.yast on every media (not just via ftp/http)
33 #define NONREMOTE_DIRECTORY_YAST 1
34 
35 namespace zypp {
36  namespace media {
37 
38  Pathname MediaHandler::_attachPrefix("");
39 
41 //
42 // CLASS NAME : MediaHandler
43 //
45 
47 //
48 //
49 // METHOD NAME : MediaHandler::MediaHandler
50 // METHOD TYPE : Constructor
51 //
52 // DESCRIPTION :
53 //
55  const Pathname & attach_point_r,
56  const Pathname & urlpath_below_attachpoint_r,
57  const bool does_download_r )
58  : _mediaSource()
59  , _attachPoint( new AttachPoint())
60  , _attachPointHint()
61  , _relativeRoot( urlpath_below_attachpoint_r)
62  , _does_download( does_download_r )
63  , _attach_mtime(0)
64  , _url( url_r )
65  , _parentId(0)
66 {
67  Pathname real_attach_point( getRealPath(attach_point_r.asString()));
68 
69  if ( !real_attach_point.empty() ) {
71  // check if provided attachpoint is usable.
73 
74  PathInfo adir( real_attach_point );
75  //
76  // The verify if attach_point_r isn't a mountpoint of another
77  // device is done in the particular media handler (if needed).
78  //
79  // We just verify, if attach_point_r is a directory and for
80  // schemes other than "file" and "dir", if it is absolute.
81  //
82  if ( !adir.isDir()
83  || (_url.getScheme() != "file"
84  && _url.getScheme() != "dir"
85  && !real_attach_point.absolute()) )
86  {
87  ERR << "Provided attach point is not a absolute directory: "
88  << adir << endl;
89  }
90  else {
91  attachPointHint( real_attach_point, false);
92  setAttachPoint( real_attach_point, false);
93  }
94  }
95 }
96 
98 //
99 //
100 // METHOD NAME : MediaHandler::~MediaHandler
101 // METHOD TYPE : Destructor
102 //
103 // DESCRIPTION :
104 //
106 {
107  try
108  {
110  }
111  catch(...) {}
112 }
113 
114 void
116 {
117  _parentId = 0;
118 }
119 
120 std::string
121 MediaHandler::getRealPath(const std::string &path)
122 {
123  return getRealPath(zypp::Pathname(path)).asString();
124 }
125 
128 {
129  return path.realpath();
130 }
131 
132 
134 //
135 //
136 // METHOD NAME : MediaHandler::removeAttachPoint
137 // METHOD TYPE : void
138 //
139 // DESCRIPTION :
140 //
141 void
143 {
144  if ( _mediaSource ) {
145  INT << "MediaHandler deleted with media attached." << endl;
146  return; // no cleanup if media still mounted!
147  }
148 
149  DBG << "MediaHandler - checking if to remove attach point" << endl;
150  if ( _attachPoint.unique() &&
151  _attachPoint->temp &&
152  !_attachPoint->path.empty() &&
153  PathInfo(_attachPoint->path).isDir())
154  {
155  Pathname path(_attachPoint->path);
156 
157  setAttachPoint("", true);
158 
159  int res = recursive_rmdir( path );
160  if ( res == 0 ) {
161  MIL << "Deleted default attach point " << path << endl;
162  } else {
163  ERR << "Failed to Delete default attach point " << path
164  << " errno(" << res << ")" << endl;
165  }
166  }
167  else
168  {
169  if( !_attachPoint->path.empty() && !_attachPoint->temp)
170  DBG << "MediaHandler - attachpoint is not temporary" << endl;
171  }
172 }
173 
174 
176 //
177 //
178 // METHOD NAME : MediaHandler::attachPoint
179 // METHOD TYPE : Pathname
180 //
181 // DESCRIPTION :
182 //
183 Pathname
185 {
186  return _attachPoint->path;
187 }
188 
189 
191 //
192 //
193 // METHOD NAME : MediaHandler::attachPoint
194 // METHOD TYPE :
195 //
196 // DESCRIPTION :
197 //
198 void
199 MediaHandler::setAttachPoint(const Pathname &path, bool temporary)
200 {
201  _attachPoint.reset( new AttachPoint(path, temporary));
202 }
203 
204 Pathname
206 {
207  if( _attachPoint->path.empty())
208  return Pathname();
209  else
210  return _attachPoint->path + _relativeRoot;
211 }
212 
214 //
215 //
216 // METHOD NAME : MediaHandler::attachPoint
217 // METHOD TYPE :
218 //
219 // DESCRIPTION :
220 //
221 void
223 {
224  if( ref)
226  else
228 }
229 
231 //
232 //
233 // METHOD NAME : MediaHandler::attachPointHint
234 // METHOD TYPE : void
235 //
236 // DESCRIPTION :
237 //
238 void
239 MediaHandler::attachPointHint(const Pathname &path, bool temporary)
240 {
241  _attachPointHint.path = path;
242  _attachPointHint.temp = temporary;
243 }
244 
246 //
247 //
248 // METHOD NAME : MediaHandler::attachPointHint
249 // METHOD TYPE : AttachPoint
250 //
251 // DESCRIPTION :
252 //
255 {
256  return _attachPointHint;
257 }
258 
260 //
261 //
262 // METHOD NAME : MediaHandler::findAttachedMedia
263 // METHOD TYPE : AttachedMedia
264 //
265 // DESCRIPTION :
266 //
269 {
270  return MediaManager().findAttachedMedia(media);
271 }
272 
274 //
275 //
276 // METHOD NAME : MediaHandler::setAttachPrefix
277 // METHOD TYPE : void
278 //
279 // DESCRIPTION :
280 //
281 bool
283 {
284  if( attach_prefix.empty())
285  {
286  MIL << "Resetting to built-in attach point prefixes."
287  << std::endl;
288  MediaHandler::_attachPrefix = attach_prefix;
289  return true;
290  }
291  else
292  if( MediaHandler::checkAttachPoint(attach_prefix, false, true))
293  {
294  MIL << "Setting user defined attach point prefix: "
295  << attach_prefix << std::endl;
296  MediaHandler::_attachPrefix = attach_prefix;
297  return true;
298  }
299  return false;
300 }
301 
303 //
304 //
305 // METHOD NAME : MediaHandler::attach
306 // METHOD TYPE : Pathname
307 //
308 // DESCRIPTION :
309 //
310 Pathname
312 {
313  Pathname aroot;
314  Pathname apoint;
315  {
316  aroot = MediaHandler::_attachPrefix; // explicit request
317  if ( ! aroot.empty() )
318  apoint = createAttachPoint( aroot );
319  }
320 
321  if ( apoint.empty() ) // fallback to config value
322  {
324  if ( ! aroot.empty() )
325  apoint = createAttachPoint( aroot );
326  }
327 
328  if ( apoint.empty() ) // fall back to temp space
329  {
331  if ( ! aroot.empty() )
332  apoint = createAttachPoint( aroot );
333  }
334 
335  if ( apoint.empty() )
336  {
337  auto except = MediaBadAttachPointException( url() );
338  except.addHistory( _("Create attach point: Can't find a writable directory to create an attach point") );
339  ZYPP_THROW( std::move(except) );
340  }
341 
342  MIL << "Created default attach point " << apoint << std::endl;
343  return apoint;
344 }
345 
346 Pathname
347 MediaHandler::createAttachPoint(const Pathname &attach_root) const
348 {
349  Pathname apoint;
350 
351  if( attach_root.empty() || !attach_root.absolute()) {
352  ERR << "Create attach point: invalid attach root: '"
353  << attach_root << "'" << std::endl;
354  return apoint;
355  }
356 
357  PathInfo adir( attach_root );
358  if( !adir.isDir() || (geteuid() != 0 && !adir.userMayRWX())) {
359  DBG << "Create attach point: attach root is not a writable directory: '"
360  << attach_root << "'" << std::endl;
361  return apoint;
362  }
363 
364  static bool cleanup_once( true );
365  if ( cleanup_once )
366  {
367  cleanup_once = false;
368  DBG << "Look for orphaned attach points in " << adir << std::endl;
369  std::list<std::string> entries;
370  filesystem::readdir( entries, attach_root, false );
371  for ( const std::string & entry : entries )
372  {
373  if ( ! str::hasPrefix( entry, "AP_0x" ) )
374  continue;
375  PathInfo sdir( attach_root + entry );
376  if ( sdir.isDir()
377  && sdir.dev() == adir.dev()
378  && ( Date::now()-sdir.mtime() > Date::month ) )
379  {
380  DBG << "Remove orphaned attach point " << sdir << std::endl;
382  }
383  }
384  }
385 
386  filesystem::TmpDir tmpdir( attach_root, "AP_0x" );
387  if ( tmpdir )
388  {
389  apoint = getRealPath( tmpdir.path().asString() );
390  if ( ! apoint.empty() )
391  {
392  tmpdir.autoCleanup( false ); // Take responsibility for cleanup.
393  }
394  else
395  {
396  ERR << "Unable to resolve real path for attach point " << tmpdir << std::endl;
397  }
398  }
399  else
400  {
401  ERR << "Unable to create attach point below " << attach_root << std::endl;
402  }
403  return apoint;
404 }
405 
407 //
408 //
409 // METHOD NAME : MediaHandler::isUseableAttachPoint
410 // METHOD TYPE : bool
411 //
412 // DESCRIPTION :
413 //
414 bool
415 MediaHandler::isUseableAttachPoint(const Pathname &path, bool mtab) const
416 {
417  MediaManager manager;
418  return manager.isUseableAttachPoint(path, mtab);
419 }
420 
421 
423 //
424 //
425 // METHOD NAME : MediaHandler::setMediaSource
426 // METHOD TYPE : void
427 //
428 // DESCRIPTION :
429 //
430 void
432 {
434  if( ref && !ref->type.empty() && !ref->name.empty())
435  _mediaSource = ref;
436 }
437 
439 //
440 //
441 // METHOD NAME : MediaHandler::attachedMedia
442 // METHOD TYPE : AttachedMedia
443 //
444 // DESCRIPTION :
445 //
448 {
449  if ( _mediaSource && _attachPoint)
451  else
452  return AttachedMedia();
453 }
454 
456 //
457 //
458 // METHOD NAME : MediaHandler::isSharedMedia
459 // METHOD TYPE : bool
460 //
461 // DESCRIPTION :
462 //
463 bool
465 {
466  return !_mediaSource.unique();
467 }
468 
470 //
471 //
472 // METHOD NAME : MediaHandler::checkAttached
473 // METHOD TYPE : bool
474 //
475 // DESCRIPTION :
476 //
477 bool
478 MediaHandler::checkAttached(bool matchMountFs) const
479 {
480  bool _isAttached = false;
481 
482  AttachedMedia ref( attachedMedia() );
483  if( ref.mediaSource )
484  {
485  time_t old_mtime = _attach_mtime;
487  if( !(old_mtime <= 0 || _attach_mtime != old_mtime) )
488  {
489  // OK, skip the check (we've seen it at least once)
490  _isAttached = true;
491  }
492  else
493  {
494  if( old_mtime > 0)
495  DBG << "Mount table changed - rereading it" << std::endl;
496  else
497  DBG << "Forced check of the mount table" << std::endl;
498 
499  MountEntries entries( MediaManager::getMountEntries());
500  for_( e, entries.begin(), entries.end() )
501  {
502  if ( ref.attachPoint->path != Pathname(e->dir) )
503  continue; // at least the mount points must match
504 
505  bool is_device = e->isBlockDevice();
506  if( is_device && (ref.mediaSource->maj_nr &&
507  ref.mediaSource->bdir.empty()))
508  {
509  PathInfo dev_info(e->src);
510  std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
511  MediaSource media(mtype, e->src, dev_info.devMajor(), dev_info.devMinor());
512 
513  if( ref.mediaSource->equals( media ) )
514  {
515  DBG << "Found media device "
516  << ref.mediaSource->asString()
517  << " in the mount table as " << e->src << std::endl;
518  _isAttached = true;
519  break;
520  }
521  // differs
522  }
523  else
524  if(!is_device && (!ref.mediaSource->maj_nr ||
525  !ref.mediaSource->bdir.empty()))
526  {
527  if( ref.mediaSource->bdir.empty())
528  {
529  // bnc#710269: Type nfs may appear as nfs4 in in the mount table
530  // and maybe vice versa. Similar cifs/smb. Need to unify these types:
531  if ( matchMountFs && e->type != ref.mediaSource->type )
532  {
533  if ( str::hasPrefix( e->type, "nfs" ) && str::hasPrefix( ref.mediaSource->type, "nfs" ) )
534  matchMountFs = false;
535  else if ( ( e->type == "cifs" || e->type == "smb" ) && ( ref.mediaSource->type == "cifs" || ref.mediaSource->type == "smb" ) )
536  matchMountFs = false;
537  else
538  continue; // different types cannot match
539  }
540  // Here: Types are ok or not to check.
541  // Check the name except for nfs (bnc#804544; symlink resolution in mount path)
542  //
543  // [fibonacci]$ ls -l /Local/ma/c12.1
544  // lrwxrwxrwx /Local/ma/c12.1 -> zypp-SuSE-Code-12_1-Branch/
545  //
546  // [localhost]$ mount -t nfs4 fibonacci:/Local/ma/c12.1 /mnt
547  // [localhost]$ mount
548  // fibonacci:/Local/ma/zypp-SuSE-Code-12_1-Branch on /mnt
549 
550  // std::string mtype(matchMountFs ? e->type : ref.mediaSource->type);
551  // MediaSource media(mtype, e->src);
552 
553  if( ref.mediaSource->name == e->src || str::hasPrefix( ref.mediaSource->type, "nfs" ) )
554  {
555  DBG << "Found media name "
556  << ref.mediaSource->asString()
557  << " in the mount table as " << e->src << std::endl;
558  _isAttached = true;
559  break;
560  }
561  }
562  else
563  {
564  if ( ref.mediaSource->bdir == e->src )
565  {
566  DBG << "Found bound media "
567  << ref.mediaSource->asString()
568  << " in the mount table as " << e->src << std::endl;
569  _isAttached = true;
570  break;
571  }
572  }
573  // differs
574  }
575  else // mixed cases:
576  {
577  // Type ISO: Since 11.1 mtab might contain the name of
578  // the loop device instead of the iso file:
579  if ( ref.mediaSource->type == "iso"
580  && str::hasPrefix( Pathname(e->src).asString(), "/dev/loop" )
581  && ref.attachPoint->path == Pathname(e->dir) )
582  {
583  DBG << "Found bound media "
584  << ref.mediaSource->asString()
585  << " in the mount table as " << e->src << std::endl;
586  _isAttached = true;
587  break;
588  }
589  }
590  }
591 
592  if( !_isAttached)
593  {
594  MIL << "Looking for " << ref << endl;
595  if( entries.empty() )
596  {
597  ERR << "Unable to find any entry in the /etc/mtab file" << std::endl;
598  }
599  else
600  {
601  dumpRange( DBG << "MountEntries: ", entries.begin(), entries.end() ) << endl;
602  }
603  if( old_mtime > 0 )
604  {
605  ERR << "Attached media not in mount table any more - forcing reset!"
606  << std::endl;
607 
609  }
610  else
611  {
612  WAR << "Attached media not in mount table ..." << std::endl;
613  }
614 
615  // reset the mtime and force a new check to make sure,
616  // that we've found the media at least once in the mtab.
617  _attach_mtime = 0;
618  }
619  }
620  }
621  return _isAttached;
622 }
623 
625 //
626 //
627 // METHOD NAME : MediaHandler::attach
628 // METHOD TYPE : PMError
629 //
630 // DESCRIPTION :
631 //
632 void MediaHandler::attach( bool next )
633 {
634  if ( isAttached() )
635  return;
636 
637  // reset it in case of overloaded isAttached()
638  // that checks the media against /etc/mtab ...
640 
642  setAttachPoint(ap.path, ap.temp);
643 
644  try
645  {
646  attachTo( next ); // pass to concrete handler
647  }
648  catch(const MediaException &e)
649  {
651  ZYPP_RETHROW(e);
652  }
653  MIL << "Attached: " << *this << endl;
654 }
655 
656 
658 //
659 //
660 // METHOD NAME : MediaHandler::localPath
661 // METHOD TYPE : Pathname
662 //
663 Pathname MediaHandler::localPath( const Pathname & pathname ) const
664 {
665  Pathname _localRoot( localRoot());
666  if ( _localRoot.empty() )
667  return _localRoot;
668 
669  // we must check maximum file name length
670  // this is important for fetching the suseservers, the
671  // url with all parameters can get too long (bug #42021)
672 
673  return _localRoot + pathname.absolutename();
674 }
675 
676 
677 
678 
679 
681 //
682 //
683 // METHOD NAME : MediaHandler::disconnect
684 // METHOD TYPE : PMError
685 //
687 {
688  if ( !isAttached() )
689  return;
690 
691  disconnectFrom(); // pass to concrete handler
692  MIL << "Disconnected: " << *this << endl;
693 }
694 
696 //
697 //
698 // METHOD NAME : MediaHandler::release
699 // METHOD TYPE : PMError
700 //
701 // DESCRIPTION :
702 //
703 void MediaHandler::release( const std::string & ejectDev )
704 {
705  if ( !isAttached() ) {
706  DBG << "Request to release media - not attached; eject '" << ejectDev << "'"
707  << std::endl;
708  if ( !ejectDev.empty() )
709  forceEject(ejectDev);
710  return;
711  }
712 
713  DBG << "Request to release attached media "
714  << _mediaSource->asString()
715  << ", use count=" << _mediaSource.use_count()
716  << std::endl;
717 
718  if( _mediaSource.unique())
719  {
720  DBG << "Releasing media " << _mediaSource->asString() << std::endl;
721  try {
722  releaseFrom( ejectDev ); // pass to concrete handler
723  }
724  catch(const MediaNotEjectedException &e)
725  {
726  // not ejected because the media
727  // is mounted by somebody else
728  // (if our attach point is busy,
729  // we get an umount exception)
730  _mediaSource.reset(NULL);
732  // OK, retrow now
733  ZYPP_RETHROW(e);
734  }
735  _mediaSource.reset(NULL);
737  }
738  else if( !ejectDev.empty() ) {
739  //
740  // Can't eject a shared media
741  //
742  //ZYPP_THROW(MediaIsSharedException(_mediaSource->asString()));
743 
745  _mediaSource.reset(NULL);
746 
747  MediaManager manager;
748  manager.forceReleaseShared(media);
749 
750  setMediaSource(media);
751  DBG << "Releasing media (forced) " << _mediaSource->asString() << std::endl;
752  try {
753  releaseFrom( ejectDev ); // pass to concrete handler
754  }
755  catch(const MediaNotEjectedException &e)
756  {
757  // not ejected because the media
758  // is mounted by somebody else
759  // (if our attach point is busy,
760  // we get an umount exception)
761  _mediaSource.reset(NULL);
763  // OK, retrow now
764  ZYPP_RETHROW(e);
765  }
766  _mediaSource.reset(NULL);
768  }
769  else {
770  DBG << "Releasing shared media reference only" << std::endl;
771  _mediaSource.reset(NULL);
772  setAttachPoint("", true);
773  }
774  MIL << "Released: " << *this << endl;
775 }
776 
777 void MediaHandler::forceRelaseAllMedia(bool matchMountFs)
778 {
779  forceRelaseAllMedia( attachedMedia().mediaSource, matchMountFs);
780 }
781 
783  bool matchMountFs)
784 {
785  if( !ref)
786  return;
787 
788  MountEntries entries( MediaManager::getMountEntries());
789  MountEntries::const_iterator e;
790  for( e = entries.begin(); e != entries.end(); ++e)
791  {
792  bool is_device = false;
793  PathInfo dev_info;
794 
795  if( str::hasPrefix( Pathname(e->src).asString(), "/dev/" ) &&
796  dev_info(e->src) && dev_info.isBlk())
797  {
798  is_device = true;
799  }
800 
801  if( is_device && ref->maj_nr)
802  {
803  std::string mtype(matchMountFs ? e->type : ref->type);
804  MediaSource media(mtype, e->src, dev_info.devMajor(), dev_info.devMinor());
805 
806  if( ref->equals( media) && e->type != "subfs")
807  {
808  DBG << "Forcing release of media device "
809  << ref->asString()
810  << " in the mount table as "
811  << e->src << std::endl;
812  try {
813  Mount mount;
814  mount.umount(e->dir);
815  }
816  catch (const Exception &e)
817  {
818  ZYPP_CAUGHT(e);
819  }
820  }
821  }
822  else
823  if(!is_device && !ref->maj_nr)
824  {
825  std::string mtype(matchMountFs ? e->type : ref->type);
826  MediaSource media(mtype, e->src);
827  if( ref->equals( media))
828  {
829  DBG << "Forcing release of media name "
830  << ref->asString()
831  << " in the mount table as "
832  << e->src << std::endl;
833  try {
834  Mount mount;
835  mount.umount(e->dir);
836  }
837  catch (const Exception &e)
838  {
839  ZYPP_CAUGHT(e);
840  }
841  }
842  }
843  }
844 }
845 
846 bool
848 {
849  return MediaHandler::checkAttachPoint( apoint, true, false);
850 }
851 
852 // STATIC
853 bool
855  bool emptydir,
856  bool writeable)
857 {
858  if( apoint.empty() || !apoint.absolute())
859  {
860  ERR << "Attach point '" << apoint << "' is not absolute"
861  << std::endl;
862  return false;
863  }
864  if( apoint == "/")
865  {
866  ERR << "Attach point '" << apoint << "' is not allowed"
867  << std::endl;
868  return false;
869  }
870 
871  PathInfo ainfo(apoint);
872  if( !ainfo.isDir())
873  {
874  ERR << "Attach point '" << apoint << "' is not a directory"
875  << std::endl;
876  return false;
877  }
878 
879  if( emptydir)
880  {
881  if( 0 != zypp::filesystem::is_empty_dir(apoint))
882  {
883  ERR << "Attach point '" << apoint << "' is not a empty directory"
884  << std::endl;
885  return false;
886  }
887  }
888 
889  if( writeable)
890  {
891  Pathname apath(apoint + "XXXXXX");
892  char *atemp = ::strdup( apath.asString().c_str());
893  char *atest = NULL;
894  if( !ainfo.userMayRWX() || atemp == NULL ||
895  (atest=::mkdtemp(atemp)) == NULL)
896  {
897  if( atemp != NULL)
898  ::free(atemp);
899 
900  ERR << "Attach point '" << ainfo.path()
901  << "' is not a writeable directory" << std::endl;
902  return false;
903  }
904  else if( atest != NULL)
905  ::rmdir(atest);
906 
907  if( atemp != NULL)
908  ::free(atemp);
909  }
910  return true;
911 }
912 
914 //
915 // METHOD NAME : MediaHandler::dependsOnParent
916 // METHOD TYPE : bool
917 //
918 // DESCRIPTION :
919 //
920 bool
922 {
923  return _parentId != 0;
924 }
925 
926 bool
927 MediaHandler::dependsOnParent(MediaAccessId parentId, bool exactIdMatch)
928 {
929  if( _parentId != 0)
930  {
931  if(parentId == _parentId)
932  return true;
933 
934  if( !exactIdMatch)
935  {
936  MediaManager mm;
938  AttachedMedia am2 = mm.getAttachedMedia(parentId);
939  if( am1.mediaSource && am2.mediaSource)
940  {
941  return am1.mediaSource->equals( *(am2.mediaSource));
942  }
943  }
944  }
945  return false;
946 }
947 
949 //
950 //
951 // METHOD NAME : MediaHandler::provideFile
952 // METHOD TYPE : PMError
953 //
954 // DESCRIPTION :
955 //
956 void MediaHandler::provideFileCopy( const OnMediaLocation &srcFile, Pathname targetFilename ) const
957 {
958  if ( !isAttached() ) {
959  INT << "Media not_attached on provideFileCopy(" << srcFile
960  << "," << targetFilename << ")" << endl;
961  ZYPP_THROW(MediaNotAttachedException(url()));
962  }
963 
964  getFileCopy( srcFile, targetFilename ); // pass to concrete handler
965  DBG << "provideFileCopy(" << srcFile << "," << targetFilename << ")" << endl;
966 }
967 
969 {
970  if ( !isAttached() ) {
971  INT << "Error: Not attached on provideFile(" << file << ")" << endl;
972  ZYPP_THROW(MediaNotAttachedException(url()));
973  }
974 
975  getFile( file ); // pass to concrete handler
976  DBG << "provideFile(" << file << ")" << endl;
977 }
978 
979 
981 //
982 //
983 // METHOD NAME : MediaHandler::provideDir
984 // METHOD TYPE : PMError
985 //
986 // DESCRIPTION :
987 //
988 void MediaHandler::provideDir( Pathname dirname ) const
989 {
990  if ( !isAttached() ) {
991  INT << "Error: Not attached on provideDir(" << dirname << ")" << endl;
992  ZYPP_THROW(MediaNotAttachedException(url()));
993  }
994 
995  getDir( dirname, /*recursive*/false ); // pass to concrete handler
996  MIL << "provideDir(" << dirname << ")" << endl;
997 }
998 
1000 //
1001 //
1002 // METHOD NAME : MediaHandler::provideDirTree
1003 // METHOD TYPE : PMError
1004 //
1005 // DESCRIPTION :
1006 //
1008 {
1009  if ( !isAttached() ) {
1010  INT << "Error Not attached on provideDirTree(" << dirname << ")" << endl;
1011  ZYPP_THROW(MediaNotAttachedException(url()));
1012  }
1013 
1014  getDir( dirname, /*recursive*/true ); // pass to concrete handler
1015  MIL << "provideDirTree(" << dirname << ")" << endl;
1016 }
1017 
1019 //
1020 //
1021 // METHOD NAME : MediaHandler::releasePath
1022 // METHOD TYPE : PMError
1023 //
1024 // DESCRIPTION :
1025 //
1026 void MediaHandler::releasePath( Pathname pathname ) const
1027 {
1028  if ( ! _does_download || _attachPoint->empty() )
1029  return;
1030 
1031  PathInfo info( localPath( pathname ) );
1032 
1033  if ( info.isFile() ) {
1034  unlink( info.path() );
1035  } else if ( info.isDir() ) {
1036  if ( info.path() != localRoot() ) {
1037  recursive_rmdir( info.path() );
1038  } else {
1039  clean_dir( info.path() );
1040  }
1041  }
1042 }
1043 
1045 //
1046 //
1047 // METHOD NAME : MediaHandler::dirInfo
1048 // METHOD TYPE : PMError
1049 //
1050 // DESCRIPTION :
1051 //
1052 void MediaHandler::dirInfo( std::list<std::string> & retlist,
1053  const Pathname & dirname, bool dots ) const
1054 {
1055  retlist.clear();
1056 
1057  if ( !isAttached() ) {
1058  INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
1059  ZYPP_THROW(MediaNotAttachedException(url()));
1060  }
1061 
1062  getDirInfo( retlist, dirname, dots ); // pass to concrete handler
1063  MIL << "dirInfo(" << dirname << ")" << endl;
1064 }
1065 
1067 //
1068 //
1069 // METHOD NAME : MediaHandler::dirInfo
1070 // METHOD TYPE : PMError
1071 //
1072 // DESCRIPTION :
1073 //
1075  const Pathname & dirname, bool dots ) const
1076 {
1077  retlist.clear();
1078 
1079  if ( !isAttached() ) {
1080  INT << "Error: Not attached on dirInfo(" << dirname << ")" << endl;
1081  ZYPP_THROW(MediaNotAttachedException(url()));
1082  }
1083 
1084  getDirInfo( retlist, dirname, dots ); // pass to concrete handler
1085  MIL << "dirInfo(" << dirname << ")" << endl;
1086 }
1087 
1089 //
1090 //
1091 // METHOD NAME : MediaHandler::doesFileExist
1092 // METHOD TYPE : PMError
1093 //
1094 // DESCRIPTION :
1095 //
1096 bool MediaHandler::doesFileExist( const Pathname & filename ) const
1097 {
1098  // TODO do some logging
1099  if ( !isAttached() ) {
1100  INT << "Error Not attached on doesFileExist(" << filename << ")" << endl;
1101  ZYPP_THROW(MediaNotAttachedException(url()));
1102  }
1103  return getDoesFileExist( filename );
1104  MIL << "doesFileExist(" << filename << ")" << endl;
1105 }
1106 
1108 //
1109 //
1110 // METHOD NAME : MediaHandler::getDirectoryYast
1111 // METHOD TYPE : PMError
1112 //
1113 void MediaHandler::getDirectoryYast( std::list<std::string> & retlist,
1114  const Pathname & dirname, bool dots ) const
1115 {
1116  retlist.clear();
1117 
1118  filesystem::DirContent content;
1119  getDirectoryYast( content, dirname, dots );
1120 
1121  // convert to std::list<std::string>
1122  for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
1123  retlist.push_back( it->name );
1124  }
1125 }
1126 
1128 //
1129 //
1130 // METHOD NAME : MediaHandler::getDirectoryYast
1131 // METHOD TYPE : PMError
1132 //
1134  const Pathname & dirname, bool dots ) const
1135 {
1136  retlist.clear();
1137 
1138  // look for directory.yast
1139  auto dirFile = OnMediaLocation( dirname + "directory.yast" );
1140  getFile( dirFile );
1141  DBG << "provideFile(" << dirFile << "): " << "OK" << endl;
1142 
1143  // using directory.yast
1144  std::ifstream dir( localPath( dirFile.filename() ).asString().c_str() );
1145  if ( dir.fail() ) {
1146  ERR << "Unable to load '" << localPath( dirFile.filename() ) << "'" << endl;
1147  ZYPP_THROW(MediaSystemException(url(),
1148  "Unable to load '" + localPath( dirFile.filename() ).asString() + "'"));
1149  }
1150 
1151  std::string line;
1152  while( getline( dir, line ) ) {
1153  if ( line.empty() ) continue;
1154  if ( line == "directory.yast" ) continue;
1155 
1156  // Newer directory.yast append '/' to directory names
1157  // Remaining entries are unspecified, although most probabely files.
1159  if ( *line.rbegin() == '/' ) {
1160  line.erase( line.end()-1 );
1161  type = filesystem::FT_DIR;
1162  }
1163 
1164  if ( dots ) {
1165  if ( line == "." || line == ".." ) continue;
1166  } else {
1167  if ( *line.begin() == '.' ) continue;
1168  }
1169 
1170  retlist.push_back( filesystem::DirEntry( line, type ) );
1171  }
1172 }
1173 
1174 /******************************************************************
1175 **
1176 **
1177 ** FUNCTION NAME : operator<<
1178 ** FUNCTION TYPE : ostream &
1179 */
1180 std::ostream & operator<<( std::ostream & str, const MediaHandler & obj )
1181 {
1182  str << obj.url() << ( obj.isAttached() ? "" : " not" )
1183  << " attached; localRoot \"" << obj.localRoot() << "\"";
1184  return str;
1185 }
1186 
1187 void MediaHandler::getFile( const OnMediaLocation &file ) const
1188 {
1189  PathInfo info( localPath( file.filename() ) );
1190  if( info.isFile() ) {
1191  return;
1192  }
1193 
1194  if (info.isExist())
1195  ZYPP_THROW(MediaNotAFileException(url(), localPath(file.filename())));
1196  else
1197  ZYPP_THROW(MediaFileNotFoundException(url(), file.filename()));
1198 }
1199 
1200 void MediaHandler::getFileCopy( const OnMediaLocation &file, const Pathname &targetFilename ) const
1201 {
1202  getFile( file );
1203  if ( copy( localPath( file.filename() ), targetFilename ) != 0 ) {
1204  ZYPP_THROW(MediaWriteException(targetFilename));
1205  }
1206 }
1207 
1208 
1210 //
1211 //
1212 // METHOD NAME : MediaHandler::getDir
1213 // METHOD TYPE : PMError
1214 //
1215 // DESCRIPTION : Asserted that media is attached.
1216 // Default implementation of pure virtual.
1217 //
1218 void MediaHandler::getDir( const Pathname & dirname, bool recurse_r ) const
1219 {
1220  PathInfo info( localPath( dirname ) );
1221  if( info.isDir() ) {
1222  return;
1223  }
1224 
1225  if (info.isExist())
1226  ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1227  else
1228  ZYPP_THROW(MediaFileNotFoundException(url(), dirname));
1229 }
1230 
1232 //
1233 //
1234 // METHOD NAME : MediaHandler::getDirInfo
1235 // METHOD TYPE : PMError
1236 //
1237 // DESCRIPTION : Asserted that media is attached and retlist is empty.
1238 // Default implementation of pure virtual.
1239 //
1240 void MediaHandler::getDirInfo( std::list<std::string> & retlist,
1241  const Pathname & dirname, bool dots ) const
1242 {
1243  PathInfo info( localPath( dirname ) );
1244  if( ! info.isDir() ) {
1245  ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1246  }
1247 
1248 #if NONREMOTE_DIRECTORY_YAST
1249  // use directory.yast if available
1250  try {
1251  getDirectoryYast( retlist, dirname, dots );
1252  }
1253  catch (const MediaException & excpt_r)
1254  {
1255 #endif
1256 
1257  // readdir
1258  int res = readdir( retlist, info.path(), dots );
1259  if ( res )
1260  {
1261  MediaSystemException nexcpt(url(), "readdir failed");
1262 #if NONREMOTE_DIRECTORY_YAST
1263  nexcpt.remember(excpt_r);
1264 #endif
1265  ZYPP_THROW(nexcpt);
1266  }
1267 
1268 #if NONREMOTE_DIRECTORY_YAST
1269  }
1270 #endif
1271 
1272  return;
1273 }
1274 
1276 //
1277 //
1278 // METHOD NAME : MediaHandler::getDirInfo
1279 // METHOD TYPE : PMError
1280 //
1281 // DESCRIPTION : Asserted that media is attached and retlist is empty.
1282 // Default implementation of pure virtual.
1283 //
1285  const Pathname & dirname, bool dots ) const
1286 {
1287  PathInfo info( localPath( dirname ) );
1288  if( ! info.isDir() ) {
1289  ZYPP_THROW(MediaNotADirException(url(), localPath(dirname)));
1290  }
1291 
1292 #if NONREMOTE_DIRECTORY_YAST
1293  // use directory.yast if available
1294  try {
1295  getDirectoryYast( retlist, dirname, dots );
1296  }
1297  catch (const MediaException & excpt_r)
1298  {
1299 #endif
1300 
1301  // readdir
1302  int res = readdir( retlist, info.path(), dots );
1303  if ( res )
1304  {
1305  MediaSystemException nexcpt(url(), "readdir failed");
1306 #if NONREMOTE_DIRECTORY_YAST
1307  nexcpt.remember(excpt_r);
1308 #endif
1309  ZYPP_THROW(nexcpt);
1310  }
1311 #if NONREMOTE_DIRECTORY_YAST
1312  }
1313 #endif
1314 }
1315 
1317 //
1318 //
1319 // METHOD NAME : MediaHandler::getDoesFileExist
1320 // METHOD TYPE : PMError
1321 //
1322 // DESCRIPTION : Asserted that file is not a directory
1323 // Default implementation of pure virtual.
1324 //
1325 bool MediaHandler::getDoesFileExist( const Pathname & filename ) const
1326 {
1327  PathInfo info( localPath( filename ) );
1328  if( info.isDir() ) {
1329  ZYPP_THROW(MediaNotAFileException(url(), localPath(filename)));
1330  }
1331  return info.isExist();
1332 }
1333 
1335 {
1336  return false;
1337 }
1338 
1339 void MediaHandler::getDetectedDevices(std::vector<std::string> & devices,
1340  unsigned int & index) const
1341 {
1342  // clear the vector by default
1343  if (!devices.empty())
1344  devices.clear();
1345  index = 0;
1346 
1347  DBG << "No devices for this medium" << endl;
1348 }
1349 
1350 void MediaHandler::precacheFiles( const std::vector<OnMediaLocation> & )
1351 {
1352  /* do nothing */
1353 }
1354 
1355  } // namespace media
1356 } // namespace zypp
1357 // vim: set ts=8 sts=2 sw=2 ai noet:
static const ValueType month
Definition: Date.h:49
static Date now()
Return the current time.
Definition: Date.h:78
Base class for Exception.
Definition: Exception.h:146
Describes a resource file located on a medium.
const Pathname & filename() const
The path to the resource on the medium.
Url manipulation class.
Definition: Url.h:92
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:533
Pathname download_mediaMountdir() const
Path where media are preferably mounted or downloaded.
Definition: ZConfig.cc:1092
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:823
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
time_t mtime() const
Definition: PathInfo.h:376
bool userMayRWX() const
Definition: PathInfo.h:353
unsigned int devMinor() const
Definition: PathInfo.cc:251
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
unsigned int devMajor() const
Definition: PathInfo.cc:241
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:246
bool absolute() const
Test for an absolute path.
Definition: Pathname.h:116
const std::string & asString() const
String representation.
Definition: Pathname.h:91
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
Pathname realpath() const
Returns this path as the absolute canonical pathname.
Definition: Pathname.cc:230
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition: Pathname.h:139
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:178
static const Pathname & defaultLocation()
Definition: TmpPath.cc:157
Pathname path() const
Definition: TmpPath.cc:146
bool autoCleanup() const
Whether path is valid and deleted when the last reference drops.
Definition: TmpPath.cc:163
Attach point of a media source.
Definition: MediaSource.h:106
Pathname path
The path name (mount point).
Definition: MediaSource.h:116
bool temp
If it was created temporary.
Definition: MediaSource.h:117
Abstract base class for 'physical' MediaHandler like MediaCD, etc.
Definition: MediaHandler.h:51
bool isUseableAttachPoint(const Pathname &path, bool mtab=true) const
Ask media manager, if the specified path is already used as attach point or if there are another atta...
virtual void getFile(const OnMediaLocation &file) const
Call concrete handler to provide file below attach point.
virtual void attachTo(bool next=false)=0
Call concrete handler to attach the media.
Url url() const
Url used.
Definition: MediaHandler.h:503
virtual bool getDoesFileExist(const Pathname &filename) const =0
check if a file exists
virtual void getDetectedDevices(std::vector< std::string > &devices, unsigned int &index) const
Fill in a vector of detected ejectable devices and the index of the currently attached device within ...
void provideDirTree(Pathname dirname) const
Use concrete handler to provide directory tree denoted by path below 'localRoot' (recursive!...
MediaHandler(const Url &url_r, const Pathname &attach_point_r, const Pathname &urlpath_below_attachpoint_r, const bool does_download_r)
If the concrete media handler provides a nonempty attach_point, it must be an existing directory.
Definition: MediaHandler.cc:54
virtual bool checkAttachPoint(const Pathname &apoint) const
Verify if the specified directory as attach point (root) as requires by the particular media handler ...
void disconnect()
Use concrete handler to isconnect media.
MediaSourceRef _mediaSource
The attached media source description reference.
Definition: MediaHandler.h:73
void attach(bool next)
Use concrete handler to attach the media.
void resetParentId()
Called in case, where the media manager takes over the destruction of the parent id (e....
time_t _attach_mtime
timestamp of the the last attach verification
Definition: MediaHandler.h:107
virtual void precacheFiles(const std::vector< OnMediaLocation > &files)
Tries to fetch the given files and precaches them.
virtual bool isAttached() const
True if media is attached.
Definition: MediaHandler.h:520
virtual bool hasMoreDevices()
Check if the media has one more device available for attach(true).
AttachPoint _attachPointHint
The user provided attach preferred point.
Definition: MediaHandler.h:91
virtual void disconnectFrom()
Call concrete handler to disconnect media.
Definition: MediaHandler.h:322
static std::string getRealPath(const std::string &path)
void dirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const
Return content of directory on media via retlist.
Pathname createAttachPoint() const
Try to create a default / temporary attach point.
AttachPointRef _attachPoint
This is where the media will be actually attached ("mounted").
Definition: MediaHandler.h:79
AttachPoint attachPointHint() const
Get the actual attach point hint.
bool doesFileExist(const Pathname &filename) const
check if a file exists
void releasePath(Pathname pathname) const
Remove pathname below localRoot IFF handler downloads files to the local filesystem.
static bool setAttachPrefix(const Pathname &attach_prefix)
virtual void getFileCopy(const OnMediaLocation &file, const Pathname &targetFilename) const
Call concrete handler to provide a file under a different place in the file system (usually not under...
void setMediaSource(const MediaSourceRef &ref)
Set new media source reference.
Pathname localPath(const Pathname &pathname) const
Files provided will be available at 'localPath(filename)'.
static Pathname _attachPrefix
User defined default attach point prefix.
Definition: MediaHandler.h:67
void forceRelaseAllMedia(bool matchMountFs)
Call to this function will try to release all media matching the currenlty attached media source,...
const Url _url
Url to handle.
Definition: MediaHandler.h:113
void release(const std::string &ejectDev="")
Use concrete handler to release the media.
bool checkAttached(bool matchMountFs) const
Check actual mediaSource attachment against the current mount table of the system.
void removeAttachPoint()
Remove unused attach point.
void getDirectoryYast(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const
Retrieve and if available scan dirname/directory.yast.
void setAttachPoint(const Pathname &path, bool temp)
Set a new attach point.
Pathname attachPoint() const
Return the currently used attach point.
Pathname localRoot() const
Return the local directory that corresponds to medias url, no matter if media isAttached or not.
void provideDir(Pathname dirname) const
Use concrete handler to provide directory denoted by path below 'localRoot' (not recursive!...
virtual ~MediaHandler()
Contolling MediaAccess takes care, that attached media is released prior to deleting this.
void provideFileCopy(const OnMediaLocation &srcFile, Pathname targetFilename) const
Call concrete handler to provide a copy of a file under a different place in the file system (usually...
virtual void getDir(const Pathname &dirname, bool recurse_r) const =0
Call concrete handler to provide directory content (not recursive!) below attach point.
Pathname _relativeRoot
The relative root directory of the data on the media.
Definition: MediaHandler.h:98
AttachedMedia findAttachedMedia(const MediaSourceRef &media) const
Ask the media manager if specified media source is already attached.
bool isSharedMedia() const
Returns a hint if the media is shared or not.
virtual void releaseFrom(const std::string &ejectDev="")=0
Call concrete handler to release the media.
void provideFile(const OnMediaLocation &file) const
Use concrete handler to provide file denoted by path below 'localRoot'.
AttachedMedia attachedMedia() const
Returns the attached media.
virtual void forceEject(const std::string &device)
Call concrete handler to physically eject the media (i.e.
Definition: MediaHandler.h:344
bool _does_download
True if concrete handler downloads files to the local filesystem.
Definition: MediaHandler.h:104
virtual void getDirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const =0
Call concrete handler to provide a content list of directory on media via retlist.
MediaAccessId _parentId
Access Id of media handler we depend on.
Definition: MediaHandler.h:118
Manages access to the 'physical' media, e.g CDROM drives, Disk volumes, directory trees,...
Definition: MediaManager.h:454
void forceReleaseShared(const MediaSourceRef &media)
AttachedMedia getAttachedMedia(MediaAccessId &accessId) const
static time_t getMountTableMTime()
Get the modification time of the /etc/mtab file.
AttachedMedia findAttachedMedia(const MediaSourceRef &media) const
bool isUseableAttachPoint(const Pathname &path, bool mtab=true) const
Check if the specified path is useable as attach point.
static std::vector< MountEntry > getMountEntries()
Get current mount entries from /etc/mtab file.
Media source internally used by MediaManager and MediaHandler.
Definition: MediaSource.h:37
String related utilities and Regular expression matching.
FileType
File type information.
Definition: PathInfo.h:56
int is_empty_dir(const Pathname &path_r)
Check if the specified directory is empty.
Definition: PathInfo.cc:688
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:605
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:700
int rmdir(const Pathname &path)
Like 'rmdir'.
Definition: PathInfo.cc:366
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition: PathInfo.cc:412
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:518
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
Definition: PathInfo.cc:442
std::ostream & copy(std::istream &from_r, std::ostream &to_r)
Copy istream to ostream.
Definition: IOStream.h:50
std::string getline(std::istream &str)
Read one line from stream.
Definition: IOStream.cc:33
zypp::RW_pointer< MediaSource > MediaSourceRef
Definition: MediaSource.h:124
std::ostream & operator<<(std::ostream &str, const MediaHandler &obj)
unsigned int MediaAccessId
Media manager access Id type.
Definition: MediaSource.h:29
zypp::RW_pointer< AttachPoint > AttachPointRef
Definition: MediaSource.h:125
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1027
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
std::ostream & dumpRange(std::ostream &str, TIterator begin, TIterator end, const std::string &intro="{", const std::string &pfx="\n ", const std::string &sep="\n ", const std::string &sfx="\n", const std::string &extro="}")
Print range defined by iterators (multiline style).
Definition: LogTools.h:91
long use_count() const
Definition: PtrTypes.h:346
void swap(RW_pointer &rhs)
Definition: PtrTypes.h:315
bool unique() const
Definition: PtrTypes.h:343
Listentry returned by readdir.
Definition: PathInfo.h:501
A simple structure containing references to a media source and its attach point.
Definition: MediaSource.h:134
MediaSourceRef mediaSource
Definition: MediaSource.h:144
AttachPointRef attachPoint
Definition: MediaSource.h:145
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:440
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:436
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define ERR
Definition: Logger.h:98
#define WAR
Definition: Logger.h:97
#define INT
Definition: Logger.h:100