libzypp  17.31.31
PathInfo.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <utime.h> // for ::utime
14 #include <sys/statvfs.h>
15 #include <sys/sysmacros.h> // for ::minor, ::major macros
16 
17 #include <iostream>
18 #include <fstream>
19 #include <iomanip>
20 
21 #include <zypp-core/fs/PathInfo.h>
22 #include <zypp-core/base/LogTools.h>
23 #include <zypp-core/base/String.h>
24 #include <zypp-core/base/IOStream.h>
25 #include <zypp-core/base/Errno.h>
26 
27 #include <zypp-core/AutoDispose.h>
28 #include <zypp-core/ExternalProgram.h>
29 #include <zypp-core/Digest.h>
30 #include <zypp-core/fs/TmpPath.h>
31 
32 using std::endl;
33 using std::string;
34 
36 namespace zypp
37 {
38  namespace filesystem
40  {
41 
42  /******************************************************************
43  **
44  ** FUNCTION NAME : operator<<
45  ** FUNCTION TYPE : std::ostream &
46  */
47  std::ostream & operator<<( std::ostream & str, FileType obj )
48  {
49  switch ( obj ) {
50 #define EMUMOUT(T) case T: return str << #T; break
53  EMUMOUT( FT_FILE );
54  EMUMOUT( FT_DIR );
57  EMUMOUT( FT_FIFO );
58  EMUMOUT( FT_LINK );
59  EMUMOUT( FT_SOCKET );
60 #undef EMUMOUT
61  }
62  return str;
63  }
64 
66  //
67  // METHOD NAME : StatMode::fileType
68  // METHOD TYPE : FileType
69  //
71  {
72  if ( isFile() )
73  return FT_FILE;
74  if ( isDir() )
75  return FT_DIR;
76  if ( isLink() )
77  return FT_LINK;
78  if ( isChr() )
79  return FT_CHARDEV;
80  if ( isBlk() )
81  return FT_BLOCKDEV;
82  if ( isFifo() )
83  return FT_FIFO;
84  if ( isSock() )
85  return FT_SOCKET ;
86 
87  return FT_NOT_AVAIL;
88  }
89 
90  /******************************************************************
91  **
92  ** FUNCTION NAME : operator<<
93  ** FUNCTION TYPE : std::ostream &
94  */
95  std::ostream & operator<<( std::ostream & str, const StatMode & obj )
96  {
97  iostr::IosFmtFlagsSaver autoResoreState( str );
98 
99  char t = '?';
100  if ( obj.isFile() )
101  t = '-';
102  else if ( obj.isDir() )
103  t = 'd';
104  else if ( obj.isLink() )
105  t = 'l';
106  else if ( obj.isChr() )
107  t = 'c';
108  else if ( obj.isBlk() )
109  t = 'b';
110  else if ( obj.isFifo() )
111  t = 'p';
112  else if ( obj.isSock() )
113  t = 's';
114 
115  str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
116  return str;
117  }
118 
120  //
121  // Class : PathInfo
122  //
124 
126  //
127  // METHOD NAME : PathInfo::PathInfo
128  // METHOD TYPE : Constructor
129  //
131  : mode_e( STAT )
132  , error_i( -1 )
133  {}
134 
136  //
137  // METHOD NAME : PathInfo::PathInfo
138  // METHOD TYPE : Constructor
139  //
140  PathInfo::PathInfo( const Pathname & path, Mode initial )
141  : path_t( path )
142  , mode_e( initial )
143  , error_i( -1 )
144  {
145  operator()();
146  }
147 
149  //
150  // METHOD NAME : PathInfo::PathInfo
151  // METHOD TYPE : Constructor
152  //
153  PathInfo::PathInfo( const std::string & path, Mode initial )
154  : path_t( path )
155  , mode_e( initial )
156  , error_i( -1 )
157  {
158  operator()();
159  }
160 
162  //
163  // METHOD NAME : PathInfo::PathInfo
164  // METHOD TYPE : Constructor
165  //
166  PathInfo::PathInfo( const char * path, Mode initial )
167  : path_t( path )
168  , mode_e( initial )
169  , error_i( -1 )
170  {
171  operator()();
172  }
173 
175  //
176  // METHOD NAME : PathInfo::~PathInfo
177  // METHOD TYPE : Destructor
178  //
180  {
181  }
182 
184  //
185  // METHOD NAME : PathInfo::operator()
186  // METHOD TYPE : bool
187  //
189  {
190  if ( path_t.empty() ) {
191  error_i = -1;
192  } else {
193  switch ( mode_e ) {
194  case STAT:
195  error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
196  break;
197  case LSTAT:
198  error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
199  break;
200  }
201  if ( error_i == -1 )
202  error_i = errno;
203  }
204  return !error_i;
205  }
206 
208  //
209  // METHOD NAME : PathInfo::fileType
210  // METHOD TYPE : File_type
211  //
213  {
214  if ( isExist() )
215  return asStatMode().fileType();
216  return FT_NOT_EXIST;
217  }
218 
220  //
221  // METHOD NAME : PathInfo::userMay
222  // METHOD TYPE : mode_t
223  //
224  mode_t PathInfo::userMay() const
225  {
226  if ( !isExist() )
227  return 0;
228  if ( owner() == geteuid() ) {
229  return( uperm()/0100 );
230  } else if ( group() == getegid() ) {
231  return( gperm()/010 );
232  }
233  return operm();
234  }
235 
236  /******************************************************************
237  **
238  ** FUNCTION NAME : PathInfo::devMajor
239  ** FUNCTION TYPE : unsigned int
240  */
241  unsigned int PathInfo::devMajor() const
242  {
243  return isBlk() || isChr() ? major(statbuf_C.st_rdev) : 0;
244  }
245 
246  /******************************************************************
247  **
248  ** FUNCTION NAME : PathInfo::devMinor
249  ** FUNCTION TYPE : unsigned int
250  */
251  unsigned int PathInfo::devMinor() const
252  {
253  return isBlk() || isChr() ? minor(statbuf_C.st_rdev) : 0;
254  }
255 
256  /******************************************************************
257  **
258  ** FUNCTION NAME : operator<<
259  ** FUNCTION TYPE : std::ostream &
260  */
261  std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
262  {
263  iostr::IosFmtFlagsSaver autoResoreState( str );
264 
265  str << obj.asString() << "{";
266  if ( !obj.isExist() ) {
267  str << Errno( obj.error() );
268  } else {
269  str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
270 
271  if ( obj.isFile() )
272  str << " size " << obj.size();
273  }
274 
275  return str << "}";
276  }
277 
279  //
280  // filesystem utilities
281  //
283 
284 #define logResult MIL << endl, doLogResult
285  namespace {
287  inline int doLogResult( const int res, const char * rclass = 0 /*errno*/ )
288  {
289  if ( res )
290  {
291  if ( rclass )
292  WAR << " FAILED: " << rclass << " " << res << endl;
293  else
294  WAR << " FAILED: " << str::strerror( res ) << endl;
295  }
296  return res;
297  }
298  } // namespace
299 
301  //
302  // METHOD NAME : PathInfo::mkdir
303  // METHOD TYPE : int
304  //
305  int mkdir( const Pathname & path, unsigned mode )
306  {
307  MIL << "mkdir " << path << ' ' << str::octstring( mode );
308  if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
309  return logResult( errno );
310  }
311  return logResult( 0 );
312  }
313 
315  //
316  // METHOD NAME : assert_dir()
317  // METHOD TYPE : int
318  //
319  int assert_dir( const Pathname & path, unsigned mode )
320  {
321  if ( path.empty() )
322  return ENOENT;
323 
324  { // Handle existing paths in advance.
325  PathInfo pi( path );
326  if ( pi.isDir() )
327  return 0;
328  if ( pi.isExist() )
329  return EEXIST;
330  }
331 
332  string spath = path.asString()+"/";
333  std::string::size_type lastpos = ( path.relative() ? 2 : 1 ); // skip leasding './' or '/'
334  std::string::size_type pos = std::string::npos;
335  int ret = 0;
336 
337  while ( (pos = spath.find('/',lastpos)) != std::string::npos )
338  {
339  string dir( spath.substr(0,pos) );
340  ret = ::mkdir( dir.c_str(), mode );
341  if ( ret == -1 )
342  {
343  if ( errno == EEXIST ) // ignore errors about already existing paths
344  ret = 0;
345  else
346  {
347  ret = errno;
348  WAR << " FAILED: mkdir " << dir << ' ' << str::octstring( mode ) << " errno " << ret << endl;
349  }
350  }
351  else
352  {
353  MIL << "mkdir " << dir << ' ' << str::octstring( mode ) << endl;
354  }
355  lastpos = pos+1;
356  }
357 
358  return ret;
359  }
360 
362  //
363  // METHOD NAME : rmdir
364  // METHOD TYPE : int
365  //
366  int rmdir( const Pathname & path )
367  {
368  MIL << "rmdir " << path;
369  if ( ::rmdir( path.asString().c_str() ) == -1 ) {
370  return logResult( errno );
371  }
372  return logResult( 0 );
373  }
374 
376  //
377  // METHOD NAME : recursive_rmdir
378  // METHOD TYPE : int
379  //
380  static int recursive_rmdir_1( const Pathname & dir, bool removeDir = true )
381  {
382  DIR * dp;
383  struct dirent * d;
384 
385  if ( ! (dp = opendir( dir.c_str() )) )
386  return logResult( errno );
387 
388  while ( (d = readdir(dp)) )
389  {
390  std::string direntry = d->d_name;
391  if ( direntry == "." || direntry == ".." )
392  continue;
393  Pathname new_path( dir / d->d_name );
394 
395  struct stat st;
396  if ( ! lstat( new_path.c_str(), &st ) )
397  {
398  if ( S_ISDIR( st.st_mode ) )
399  recursive_rmdir_1( new_path );
400  else
401  ::unlink( new_path.c_str() );
402  }
403  }
404  closedir( dp );
405 
406  if ( removeDir && ::rmdir( dir.c_str() ) < 0 )
407  return errno;
408 
409  return 0;
410  }
412  int recursive_rmdir( const Pathname & path )
413  {
414  MIL << "recursive_rmdir " << path << ' ';
415  PathInfo p( path );
416 
417  if ( !p.isExist() ) {
418  return logResult( 0 );
419  }
420 
421  if ( !p.isDir() ) {
422  return logResult( ENOTDIR );
423  }
424 
425  p.lstat(); // get dir symlinks
426  if ( !p.isDir() ) {
427  MIL << "unlink symlink ";
428  if ( ::unlink( path.asString().c_str() ) == -1 ) {
429  return logResult( errno );
430  }
431  return logResult( 0 );
432  }
433 
434  return logResult( recursive_rmdir_1( path ) );
435  }
436 
438  //
439  // METHOD NAME : clean_dir
440  // METHOD TYPE : int
441  //
442  int clean_dir( const Pathname & path )
443  {
444  MIL << "clean_dir " << path << ' ';
445  PathInfo p( path );
446 
447  if ( !p.isExist() ) {
448  return logResult( 0 );
449  }
450 
451  if ( !p.isDir() ) {
452  return logResult( ENOTDIR );
453  }
454 
455  return logResult( recursive_rmdir_1( path, false/* don't remove path itself */ ) );
456  }
457 
459  //
460  // METHOD NAME : copy_dir
461  // METHOD TYPE : int
462  //
463  int copy_dir( const Pathname & srcpath, const Pathname & destpath )
464  {
465  MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
466 
467  PathInfo sp( srcpath );
468  if ( !sp.isDir() ) {
469  return logResult( ENOTDIR );
470  }
471 
472  PathInfo dp( destpath );
473  if ( !dp.isDir() ) {
474  return logResult( ENOTDIR );
475  }
476 
477  PathInfo tp( destpath + srcpath.basename() );
478  if ( tp.isExist() ) {
479  return logResult( EEXIST );
480  }
481 
482 
483  const char *const argv[] = {
484  "/bin/cp",
485  "-dR",
486  "--",
487  srcpath.asString().c_str(),
488  destpath.asString().c_str(),
489  NULL
490  };
492  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
493  MIL << " " << output;
494  }
495  int ret = prog.close();
496  return logResult( ret, "returned" );
497  }
498 
500  //
501  // METHOD NAME : copy_dir_content
502  // METHOD TYPE : int
503  //
504  int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
505  {
506  MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
507 
508  PathInfo sp( srcpath );
509  if ( !sp.isDir() ) {
510  return logResult( ENOTDIR );
511  }
512 
513  PathInfo dp( destpath );
514  if ( !dp.isDir() ) {
515  return logResult( ENOTDIR );
516  }
517 
518  if ( srcpath == destpath ) {
519  return logResult( EEXIST );
520  }
521 
522  std::string src( srcpath.asString());
523  src += "/.";
524  const char *const argv[] = {
525  "/bin/cp",
526  "-dR",
527  "--",
528  src.c_str(),
529  destpath.asString().c_str(),
530  NULL
531  };
533  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
534  MIL << " " << output;
535  }
536  int ret = prog.close();
537  return logResult( ret, "returned" );
538  }
539 
541  // dirForEachImpl
543  template <class... T>
544  constexpr bool always_false = false;
545 
546  template <typename F>
547  int dirForEachImpl ( const Pathname & dir_r, F &&fnc_r )
548  {
549  AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ),
550  []( DIR * dir_r ) { if ( dir_r ) ::closedir( dir_r ); } );
551 
552  MIL << "readdir " << dir_r << ' ';
553  if ( ! dir )
554  return logResult( errno );
555  MIL << endl; // close line before callbacks are invoked.
556 
557  int ret = 0;
558  for ( struct dirent * entry = ::readdir( dir ); entry; entry = ::readdir( dir ) )
559  {
560  if ( entry->d_name[0] == '.' && ( entry->d_name[1] == '\0' || ( entry->d_name[1] == '.' && entry->d_name[2] == '\0' ) ) )
561  continue; // omitt . and ..
562 
563  // some static checks to make sure the correct func is selected
564  static_assert( !std::is_invocable_v< function<bool(const Pathname &, const char *const)>, const Pathname &, const DirEntry &> , "Invoke detection broken" );
565  static_assert( !std::is_invocable_v< function<bool(const Pathname &, const DirEntry& )>, const Pathname &, const char *> , "Invoke detection broken" );
566 
567  if constexpr ( std::is_invocable_v<F, const Pathname &, const char *const> ) {
568  if ( ! std::forward<F>(fnc_r)( dir_r, entry->d_name ) ) {
569  ret = -1;
570  break;
571  }
572  } else if constexpr ( std::is_invocable_v<F, const Pathname &, const DirEntry&> ) {
573  if ( ! std::forward<F>(fnc_r)( dir_r, DirEntry( entry ) ) ) {
574  ret = -1;
575  break;
576  }
577  } else {
578  static_assert( always_false<F>, "Callback not supported" );
579  }
580  }
581  return ret;
582  }
583 
584  int dirForEach( const Pathname & dir_r, function<bool(const Pathname &, const char *const)> fnc_r )
585  {
586  if ( ! fnc_r )
587  return 0;
588 
589  return dirForEachImpl( dir_r, fnc_r );
590  }
591 
592 
593  int dirForEachExt( const Pathname & dir_r, const function<bool(const Pathname &, const DirEntry &)> &fnc_r )
594  {
595  if ( ! fnc_r )
596  return 0;
597 
598  return dirForEachImpl( dir_r, fnc_r );
599  }
600 
602  // readdir
604 
605  int readdir( std::list<std::string> & retlist_r, const Pathname & path_r, bool dots_r )
606  {
607  retlist_r.clear();
608  return dirForEach( path_r,
609  [&]( const Pathname & dir_r, const char *const name_r )->bool
610  {
611  if ( dots_r || name_r[0] != '.' )
612  retlist_r.push_back( name_r );
613  return true;
614  } );
615  }
616 
617 
618  int readdir( std::list<Pathname> & retlist_r, const Pathname & path_r, bool dots_r )
619  {
620  retlist_r.clear();
621  return dirForEach( path_r,
622  [&]( const Pathname & dir_r, const char *const name_r )->bool
623  {
624  if ( dots_r || name_r[0] != '.' )
625  retlist_r.push_back( dir_r/name_r );
626  return true;
627  } );
628  }
629 
630  DirEntry::DirEntry( struct dirent* entry )
631  : name( str::asString( entry->d_name ) )
632  {
633  switch( entry->d_type ) {
634  case DT_BLK:
635  this->type = FileType::FT_BLOCKDEV;
636  break;
637  case DT_CHR:
638  this->type = FileType::FT_CHARDEV;
639  break;
640  case DT_DIR:
641  this->type = FileType::FT_DIR;
642  break;
643  case DT_FIFO:
644  this->type = FileType::FT_FIFO;
645  break;
646  case DT_LNK:
647  this->type = FileType::FT_LINK;
648  break;
649  case DT_REG:
650  this->type = FileType::FT_FILE;
651  break;
652  case DT_SOCK:
653  this->type = FileType::FT_SOCKET;
654  break;
655  case DT_UNKNOWN:
657  break;
658  }
659  }
660 
661  bool DirEntry::operator==( const DirEntry &rhs ) const
662  {
663  // if one of the types is not known, use the name only
664  if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
665  return ( name == rhs.name );
666  return ((name == rhs.name ) && (type == rhs.type));
667  }
668 
669  int readdir( DirContent & retlist_r, const Pathname & path_r, bool dots_r, PathInfo::Mode statmode_r )
670  {
671  retlist_r.clear();
672  return dirForEach( path_r,
673  [&]( const Pathname & dir_r, const char *const name_r )->bool
674  {
675  if ( dots_r || name_r[0] != '.' )
676  retlist_r.push_back( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
677  return true;
678  } );
679  }
680 
681  std::ostream & operator<<( std::ostream & str, const DirContent & obj )
682  { return dumpRange( str, obj.begin(), obj.end() ); }
683 
685  // is_empty_dir
687 
688  int is_empty_dir( const Pathname & path_r )
689  {
690  return dirForEach( path_r,
691  [&]( const Pathname & dir_r, const char *const name_r )->bool
692  { return false; } );
693  }
694 
696  //
697  // METHOD NAME : unlink
698  // METHOD TYPE : int
699  //
700  int unlink( const Pathname & path )
701  {
702  MIL << "unlink " << path;
703  if ( ::unlink( path.asString().c_str() ) == -1 ) {
704  return logResult( errno );
705  }
706  return logResult( 0 );
707  }
708 
710  namespace
711  {
712  int safe_rename( const Pathname & oldpath, const Pathname & newpath )
713  {
714  int ret = ::rename( oldpath.asString().c_str(), newpath.asString().c_str() );
715 
716  // rename(2) can fail on OverlayFS. Fallback to using mv(1), which is
717  // explicitly mentioned in the kernel docs to deal correctly with OverlayFS.
718  if ( ret == -1 && errno == EXDEV ) {
719  const char *const argv[] = {
720  "/usr/bin/mv",
721  oldpath.asString().c_str(),
722  newpath.asString().c_str(),
723  NULL
724  };
725  ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
726  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
727  MIL << " " << output;
728  }
729  ret = prog.close();
730  }
731 
732  return ret;
733  }
734  } // namespace
736 
738  //
739  // METHOD NAME : rename
740  // METHOD TYPE : int
741  //
742  int rename( const Pathname & oldpath, const Pathname & newpath )
743  {
744  MIL << "rename " << oldpath << " -> " << newpath;
745  if ( safe_rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
746  return logResult( errno );
747  }
748  return logResult( 0 );
749  }
750 
752  //
753  // METHOD NAME : exchange
754  // METHOD TYPE : int
755  //
756  int exchange( const Pathname & lpath, const Pathname & rpath )
757  {
758  MIL << "exchange " << lpath << " <-> " << rpath;
759  if ( lpath.empty() || rpath.empty() )
760  return logResult( EINVAL );
761 
762  PathInfo linfo( lpath );
763  PathInfo rinfo( rpath );
764 
765  if ( ! linfo.isExist() )
766  {
767  if ( ! rinfo.isExist() )
768  return logResult( 0 ); // both don't exist.
769 
770  // just rename rpath -> lpath
771  int ret = assert_dir( lpath.dirname() );
772  if ( ret != 0 )
773  return logResult( ret );
774  if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
775  return logResult( errno );
776  }
777  return logResult( 0 );
778  }
779 
780  // HERE: lpath exists:
781  if ( ! rinfo.isExist() )
782  {
783  // just rename lpath -> rpath
784  int ret = assert_dir( rpath.dirname() );
785  if ( ret != 0 )
786  return logResult( ret );
787  if ( safe_rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
788  return logResult( errno );
789  }
790  return logResult( 0 );
791  }
792 
793  // HERE: both exist
794  TmpFile tmpfile( TmpFile::makeSibling( rpath ) );
795  if ( ! tmpfile )
796  return logResult( errno );
797  Pathname tmp( tmpfile.path() );
798  ::unlink( tmp.c_str() );
799 
800  if ( safe_rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
801  return logResult( errno );
802  }
803  if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
804  safe_rename( tmp.c_str(), lpath.c_str() );
805  return logResult( errno );
806  }
807  if ( safe_rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
808  safe_rename( lpath.c_str(), rpath.c_str() );
809  safe_rename( tmp.c_str(), lpath.c_str() );
810  return logResult( errno );
811  }
812  return logResult( 0 );
813  }
814 
816  //
817  // METHOD NAME : copy
818  // METHOD TYPE : int
819  //
820  int copy( const Pathname & file, const Pathname & dest )
821  {
822  MIL << "copy " << file << " -> " << dest << ' ';
823 
824  PathInfo sp( file );
825  if ( !sp.isFile() ) {
826  return logResult( EINVAL );
827  }
828 
829  PathInfo dp( dest );
830  if ( dp.isDir() ) {
831  return logResult( EISDIR );
832  }
833 
834  const char *const argv[] = {
835  "/bin/cp",
836  "--remove-destination",
837  "--",
838  file.asString().c_str(),
839  dest.asString().c_str(),
840  NULL
841  };
843  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
844  MIL << " " << output;
845  }
846  int ret = prog.close();
847  return logResult( ret, "returned" );
848  }
849 
851  //
852  // METHOD NAME : symlink
853  // METHOD TYPE : int
854  //
855  int symlink( const Pathname & oldpath, const Pathname & newpath )
856  {
857  MIL << "symlink " << newpath << " -> " << oldpath;
858  if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
859  return logResult( errno );
860  }
861  return logResult( 0 );
862  }
863 
865  //
866  // METHOD NAME : hardlink
867  // METHOD TYPE : int
868  //
869  int hardlink( const Pathname & oldpath, const Pathname & newpath )
870  {
871  MIL << "hardlink " << newpath << " -> " << oldpath;
872  if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
873  return logResult( errno );
874  }
875  return logResult( 0 );
876  }
877 
879  //
880  // METHOD NAME : hardlink
881  // METHOD TYPE : int
882  //
883  int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath )
884  {
885  MIL << "hardlinkCopy " << oldpath << " -> " << newpath;
886 
887  PathInfo pi( oldpath, PathInfo::LSTAT );
888  if ( pi.isLink() )
889  {
890  // dont hardlink symlinks!
891  MIL << " => copy" << endl;
892  return copy( oldpath, newpath );
893  }
894 
895  pi.lstat( newpath );
896  if ( pi.isExist() )
897  {
898  int res = unlink( newpath );
899  if ( res != 0 )
900  return logResult( res );
901  }
902 
903  // Here: no symlink, no newpath
904  if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
905  {
906  switch ( errno )
907  {
908  case EPERM: // /proc/sys/fs/protected_hardlink in proc(5)
909  case EXDEV: // oldpath and newpath are not on the same mounted file system
910  MIL << " => copy" << endl;
911  return copy( oldpath, newpath );
912  break;
913  }
914  return logResult( errno );
915  }
916  return logResult( 0 );
917  }
918 
920  //
921  // METHOD NAME : readlink
922  // METHOD TYPE : int
923  //
924  int readlink( const Pathname & symlink_r, Pathname & target_r )
925  {
926  static const ssize_t bufsiz = 2047;
927  static char buf[bufsiz+1];
928  ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
929  if ( ret == -1 )
930  {
931  target_r = Pathname();
932  MIL << "readlink " << symlink_r;
933  return logResult( errno );
934  }
935  buf[ret] = '\0';
936  target_r = buf;
937  return 0;
938  }
939 
941  //
942  // METHOD NAME : expandlink
943  // METHOD TYPE : Pathname
944  //
945  Pathname expandlink( const Pathname & path_r )
946  {
947  static const unsigned int level_limit = 256;
948  static unsigned int count;
949  Pathname path(path_r);
950  PathInfo info(path_r, PathInfo::LSTAT);
951 
952  for (count = level_limit; info.isLink() && count; count--)
953  {
954  DBG << "following symlink " << path;
955  path = path.dirname() / readlink(path);
956  DBG << "->" << path << std::endl;
957  info = PathInfo(path, PathInfo::LSTAT);
958  }
959 
960  // expand limit reached
961  if (count == 0)
962  {
963  ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
964  return Pathname();
965  }
966  // symlink
967  else if (count < level_limit)
968  {
969  // check for a broken link
970  if (PathInfo(path).isExist())
971  return path;
972  // broken link, return an empty path
973  else
974  {
975  ERR << path << " is broken (expanded from " << path_r << ")" << endl;
976  return Pathname();
977  }
978  }
979 
980  // not a symlink, return the original pathname
981  DBG << "not a symlink" << endl;
982  return path;
983  }
984 
986  //
987  // METHOD NAME : copy_file2dir
988  // METHOD TYPE : int
989  //
990  int copy_file2dir( const Pathname & file, const Pathname & dest )
991  {
992  MIL << "copy_file2dir " << file << " -> " << dest << ' ';
993 
994  PathInfo sp( file );
995  if ( !sp.isFile() ) {
996  return logResult( EINVAL );
997  }
998 
999  PathInfo dp( dest );
1000  if ( !dp.isDir() ) {
1001  return logResult( ENOTDIR );
1002  }
1003 
1004  const char *const argv[] = {
1005  "/bin/cp",
1006  "--",
1007  file.asString().c_str(),
1008  dest.asString().c_str(),
1009  NULL
1010  };
1012  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1013  MIL << " " << output;
1014  }
1015  int ret = prog.close();
1016  return logResult( ret, "returned" );
1017  }
1018 
1020  //
1021  // METHOD NAME : md5sum
1022  // METHOD TYPE : std::string
1023  //
1024  std::string md5sum( const Pathname & file )
1025  {
1026  if ( ! PathInfo( file ).isFile() ) {
1027  return string();
1028  }
1029  std::ifstream istr( file.asString().c_str() );
1030  if ( ! istr ) {
1031  return string();
1032  }
1033  return Digest::digest( "MD5", istr );
1034  }
1035 
1037  //
1038  // METHOD NAME : sha1sum
1039  // METHOD TYPE : std::string
1040  //
1041  std::string sha1sum( const Pathname & file )
1042  {
1043  return checksum(file, "SHA1");
1044  }
1045 
1047  //
1048  // METHOD NAME : checksum
1049  // METHOD TYPE : std::string
1050  //
1051  std::string checksum( const Pathname & file, const std::string &algorithm )
1052  {
1053  if ( ! PathInfo( file ).isFile() ) {
1054  return string();
1055  }
1056  std::ifstream istr( file.asString().c_str() );
1057  if ( ! istr ) {
1058  return string();
1059  }
1060  return Digest::digest( algorithm, istr );
1061  }
1062 
1063  bool is_checksum( const Pathname & file, const CheckSum &checksum )
1064  {
1065  return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
1066  }
1067 
1069  //
1070  // METHOD NAME : erase
1071  // METHOD TYPE : int
1072  //
1073  int erase( const Pathname & path )
1074  {
1075  int res = 0;
1076  PathInfo p( path, PathInfo::LSTAT );
1077  if ( p.isExist() )
1078  {
1079  if ( p.isDir() )
1080  res = recursive_rmdir( path );
1081  else
1082  res = unlink( path );
1083  }
1084  return res;
1085  }
1086 
1088  //
1089  // METHOD NAME : chmod
1090  // METHOD TYPE : int
1091  //
1092  int chmod( const Pathname & path, mode_t mode )
1093  {
1094  MIL << "chmod " << path << ' ' << str::octstring( mode );
1095  if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
1096  return logResult( errno );
1097  }
1098  return logResult( 0 );
1099  }
1100 
1101  int addmod( const Pathname & path, mode_t mode )
1102  {
1103  mode_t omode( PathInfo( path ).st_mode() );
1104  mode_t tmode( omode | mode );
1105  if ( omode != mode )
1106  return chmod( path, tmode );
1107  return 0;
1108  }
1109 
1110  int delmod( const Pathname & path, mode_t mode )
1111  {
1112  mode_t omode( PathInfo( path ).st_mode() );
1113  mode_t tmode( omode & ~mode );
1114  if ( omode != mode )
1115  return chmod( path, tmode );
1116  return 0;
1117  }
1118 
1120  //
1121  // METHOD NAME : zipType
1122  // METHOD TYPE : ZIP_TYPE
1123  //
1124  ZIP_TYPE zipType( const Pathname & file )
1125  {
1126  ZIP_TYPE ret = ZT_NONE;
1127 
1128  int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
1129 
1130  if ( fd != -1 ) {
1131  const int magicSize = 5;
1132  unsigned char magic[magicSize];
1133  memset( magic, 0, magicSize );
1134  if ( read( fd, magic, magicSize ) == magicSize ) {
1135  if ( magic[0] == 0037 && magic[1] == 0213 ) {
1136  ret = ZT_GZ;
1137  } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
1138  ret = ZT_BZ2;
1139  } else if ( magic[0] == '\0' && magic[1] == 'Z' && magic[2] == 'C' && magic[3] == 'K' && magic[4] == '1') {
1140  ret = ZT_ZCHNK;
1141 
1142  }
1143  }
1144  close( fd );
1145  }
1146 
1147  return ret;
1148  }
1149 
1151  //
1152  // METHOD NAME : df
1153  // METHOD TYPE : ByteCount
1154  //
1155  ByteCount df( const Pathname & path_r )
1156  {
1157  ByteCount ret( -1 );
1158  struct statvfs sb;
1159  if ( statvfs( path_r.c_str(), &sb ) == 0 )
1160  {
1161  ret = sb.f_bfree * sb.f_bsize;
1162  }
1163  return ret;
1164  }
1165 
1167  //
1168  // METHOD NAME : getUmask
1169  // METHOD TYPE : mode_t
1170  //
1171  mode_t getUmask()
1172  {
1173  mode_t mask = ::umask( 0022 );
1174  ::umask( mask );
1175  return mask;
1176  }
1177 
1179  //
1180  // METHOD NAME : getUmask
1181  // METHOD TYPE : mode_t
1182  //
1183  int assert_file( const Pathname & path, unsigned mode )
1184  {
1185  int ret = assert_dir( path.dirname() );
1186  MIL << "assert_file " << str::octstring( mode ) << " " << path;
1187  if ( ret != 0 )
1188  return logResult( ret );
1189 
1190  PathInfo pi( path );
1191  if ( pi.isExist() )
1192  return logResult( pi.isFile() ? 0 : EEXIST );
1193 
1194  int fd = ::creat( path.c_str(), mode );
1195  if ( fd == -1 )
1196  return logResult( errno );
1197 
1198  ::close( fd );
1199  return logResult( 0 );
1200  }
1201 
1202  int assert_file_mode( const Pathname & path, unsigned mode )
1203  {
1204  int ret = assert_dir( path.dirname() );
1205  MIL << "assert_file_mode " << str::octstring( mode ) << " " << path;
1206  if ( ret != 0 )
1207  return logResult( ret );
1208 
1209  PathInfo pi( path );
1210  if ( pi.isExist() )
1211  {
1212  if ( ! pi.isFile() )
1213  return logResult( EEXIST );
1214 
1215  mode = applyUmaskTo( mode );
1216  if ( pi.st_mode() != mode )
1217  return chmod( path, mode );
1218 
1219  return logResult( 0 );
1220  }
1221 
1222  int fd = ::creat( path.c_str(), mode );
1223  if ( fd == -1 )
1224  return logResult( errno );
1225  ::close( fd );
1226  return logResult( 0 );
1227  }
1228 
1230  //
1231  // METHOD NAME : touch
1232  // METHOD TYPE : int
1233  //
1234  int touch (const Pathname & path)
1235  {
1236  MIL << "touch " << path;
1237  struct ::utimbuf times;
1238  times.actime = ::time( 0 );
1239  times.modtime = ::time( 0 );
1240  if ( ::utime( path.asString().c_str(), &times ) == -1 ) {
1241  return logResult( errno );
1242  }
1243  return logResult( 0 );
1244  }
1245 
1247  } // namespace filesystem
1250 } // namespace zypp
std::string asString(const Patch::Category &obj)
Definition: Patch.cc:122
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:319
#define MIL
Definition: Logger.h:96
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
Definition: PathInfo.cc:756
ZIP_TYPE
Test whether a file is compressed (gzip/bzip2).
Definition: PathInfo.h:754
std::string digest()
get hex string representation of the digest
Definition: Digest.cc:236
Listentry returned by readdir.
Definition: PathInfo.h:501
int assert_file(const Pathname &path, unsigned mode)
Create an empty file if it does not yet exist.
Definition: PathInfo.cc:1183
std::string octstring(char n, int w=4)
Definition: String.h:348
std::string sha1sum(const Pathname &file)
Compute a files sha1sum.
Definition: PathInfo.cc:1041
Convenience errno wrapper.
Definition: Errno.h:25
std::string md5sum(const Pathname &file)
Compute a files md5sum.
Definition: PathInfo.cc:1024
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like &#39;readlink&#39;.
Definition: PathInfo.cc:924
bool lstat()
LSTAT current path.
Definition: PathInfo.h:271
Store and operate with byte count.
Definition: ByteCount.h:30
int mkdir(const Pathname &path, unsigned mode)
Like &#39;mkdir&#39;.
Definition: PathInfo.cc:305
bool operator==(const DirEntry &rhs) const
Definition: PathInfo.cc:661
mode_t perm() const
Definition: PathInfo.h:156
int hardlink(const Pathname &oldpath, const Pathname &newpath)
Like &#39;::link&#39;.
Definition: PathInfo.cc:869
int chmod(const Pathname &path, mode_t mode)
Like &#39;chmod&#39;.
Definition: PathInfo.cc:1092
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:107
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition: PathInfo.cc:32
int clean_dir(const Pathname &path)
Like &#39;rm -r DIR/ *&#39;.
Definition: PathInfo.cc:442
const char * c_str() const
String representation.
Definition: Pathname.h:110
boost::io::ios_base_all_saver IosFmtFlagsSaver
Save and restore streams width, precision and fmtflags.
Definition: IOStream.h:35
String related utilities and Regular expression matching.
mode_t userMay() const
Returns current users permission ([0-7])
Definition: PathInfo.cc:224
Pathname path() const
Definition: TmpPath.cc:146
constexpr bool always_false
Definition: PathInfo.cc:544
mode_t uperm() const
Definition: PathInfo.h:321
std::string receiveLine()
Read one line from the input stream.
bool stat()
STAT current path.
Definition: PathInfo.h:269
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:127
unsigned int devMinor() const
Definition: PathInfo.cc:251
std::map< std::string, std::string > read(const Pathname &_path)
Read sysconfig file path_r and return (key,valye) pairs.
Definition: sysconfig.cc:34
int copy_file2dir(const Pathname &file, const Pathname &dest)
Like &#39;cp file dest&#39;.
Definition: PathInfo.cc:990
DirEntry(const std::string &name_r=std::string(), FileType type_r=FT_NOT_AVAIL)
Definition: PathInfo.h:504
#define ERR
Definition: Logger.h:98
#define logResult
Definition: PathInfo.cc:284
Mode
stat() or lstat()
Definition: PathInfo.h:226
int is_empty_dir(const Pathname &path_r)
Check if the specified directory is empty.
Definition: PathInfo.cc:688
mode_t gperm() const
Definition: PathInfo.h:322
ZIP_TYPE zipType(const Pathname &file)
Definition: PathInfo.cc:1124
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition: PathInfo.cc:1101
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition: PathInfo.cc:1202
bool operator()()
Restat current path using current mode.
Definition: PathInfo.cc:188
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:700
const std::string & asString() const
String representation.
Definition: Pathname.h:91
int rename(const Pathname &oldpath, const Pathname &newpath)
Like &#39;rename&#39;.
Definition: PathInfo.cc:742
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
int recursive_rmdir(const Pathname &path)
Like &#39;rm -r DIR&#39;.
Definition: PathInfo.cc:412
int error() const
Return error returned from last stat/lstat call.
Definition: PathInfo.h:254
#define WAR
Definition: Logger.h:97
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:518
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:883
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like &#39;symlink&#39;.
Definition: PathInfo.cc:855
const std::string & asString() const
Return current Pathname as String.
Definition: PathInfo.h:248
int touch(const Pathname &path)
Change file&#39;s modification and access times.
Definition: PathInfo.cc:1234
SolvableIdType size_type
Definition: PoolMember.h:126
int close()
Wait for the progamm to complete.
int copy(const Pathname &file, const Pathname &dest)
Like &#39;cp file dest&#39;.
Definition: PathInfo.cc:820
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 dirForEachImpl(const Pathname &dir_r, F &&fnc_r)
Definition: PathInfo.cc:547
int rmdir(const Pathname &path)
Like &#39;rmdir&#39;.
Definition: PathInfo.cc:366
mode_t getUmask()
Get the current umask (file mode creation mask)
Definition: PathInfo.cc:1171
int copy_dir(const Pathname &srcpath, const Pathname &destpath)
Like &#39;cp -a srcpath destpath&#39;.
Definition: PathInfo.cc:463
Wrapper class for mode_t values as derived from ::stat.
Definition: PathInfo.h:80
FileType
File type information.
Definition: PathInfo.h:55
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition: PathInfo.cc:1051
int erase(const Pathname &path)
Erase whatever happens to be located at path (file or directory).
Definition: PathInfo.cc:1073
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
bool relative() const
Test for a relative path.
Definition: Pathname.h:118
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition: PathInfo.cc:593
unsigned int devMajor() const
Definition: PathInfo.cc:241
int copy_dir_content(const Pathname &srcpath, const Pathname &destpath)
Like &#39;cp -a srcpath/.
Definition: PathInfo.cc:504
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:220
Pathname expandlink(const Pathname &path_r)
Recursively follows the symlink pointed to by path_r and returns the Pathname to the real file or dir...
Definition: PathInfo.cc:945
static TmpFile makeSibling(const Pathname &sibling_r)
Provide a new empty temporary directory as sibling.
Definition: TmpPath.cc:218
#define EMUMOUT(T)
mode_t applyUmaskTo(mode_t mode_r)
Modify mode_r according to the current umask ( mode_r & ~getUmask() ).
Definition: PathInfo.h:789
FileType fileType() const
Definition: PathInfo.cc:212
int delmod(const Pathname &path, mode_t mode)
Remove the mode bits from the file given by path.
Definition: PathInfo.cc:1110
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition: String.cc:53
std::ostream & operator<<(std::ostream &str, const Glob &obj)
Definition: Glob.cc:53
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
bool lstat(const Pathname &path)
LSTAT path.
Definition: PathInfo.h:264
mode_t operm() const
Definition: PathInfo.h:323
static int recursive_rmdir_1(const Pathname &dir, bool removeDir=true)
Definition: PathInfo.cc:380
#define DBG
Definition: Logger.h:95
bool is_checksum(const Pathname &file, const CheckSum &checksum)
check files checksum
Definition: PathInfo.cc:1063
mode_t st_mode() const
Definition: PathInfo.h:326
FileType fileType() const
Definition: PathInfo.cc:70
StatMode asStatMode() const
Return st_mode() as filesystem::StatMode.
Definition: PathInfo.h:330
ByteCount df(const Pathname &path_r)
Report free disk space on a mounted file system.
Definition: PathInfo.cc:1155