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