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