libzypp  16.15.6
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 #define logResult MIL << endl, doLogResult
286  namespace {
288  inline int doLogResult( const int res, const char * rclass = 0 /*errno*/ )
289  {
290  if ( res )
291  {
292  if ( rclass )
293  WAR << " FAILED: " << rclass << " " << res << endl;
294  else
295  WAR << " FAILED: " << str::strerror( res ) << endl;
296  }
297  return res;
298  }
299  } // namespace
300 
302  //
303  // METHOD NAME : PathInfo::mkdir
304  // METHOD TYPE : int
305  //
306  int mkdir( const Pathname & path, unsigned mode )
307  {
308  MIL << "mkdir " << path << ' ' << str::octstring( mode );
309  if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
310  return logResult( errno );
311  }
312  return logResult( 0 );
313  }
314 
316  //
317  // METHOD NAME : assert_dir()
318  // METHOD TYPE : int
319  //
320  int assert_dir( const Pathname & path, unsigned mode )
321  {
322  if ( path.empty() )
323  return ENOENT;
324 
325  { // Handle existing paths in advance.
326  PathInfo pi( path );
327  if ( pi.isDir() )
328  return 0;
329  if ( pi.isExist() )
330  return EEXIST;
331  }
332 
333  string spath = path.asString()+"/";
334  string::size_type lastpos = ( path.relative() ? 2 : 1 ); // skip leasding './' or '/'
335  string::size_type pos = string::npos;
336  int ret = 0;
337 
338  while ( (pos = spath.find('/',lastpos)) != string::npos )
339  {
340  string dir( spath.substr(0,pos) );
341  ret = ::mkdir( dir.c_str(), mode );
342  if ( ret == -1 )
343  {
344  if ( errno == EEXIST ) // ignore errors about already existing paths
345  ret = 0;
346  else
347  {
348  ret = errno;
349  WAR << " FAILED: mkdir " << dir << ' ' << str::octstring( mode ) << " errno " << ret << endl;
350  }
351  }
352  else
353  {
354  MIL << "mkdir " << dir << ' ' << str::octstring( mode ) << endl;
355  }
356  lastpos = pos+1;
357  }
358 
359  return ret;
360  }
361 
363  //
364  // METHOD NAME : rmdir
365  // METHOD TYPE : int
366  //
367  int rmdir( const Pathname & path )
368  {
369  MIL << "rmdir " << path;
370  if ( ::rmdir( path.asString().c_str() ) == -1 ) {
371  return logResult( errno );
372  }
373  return logResult( 0 );
374  }
375 
377  //
378  // METHOD NAME : recursive_rmdir
379  // METHOD TYPE : int
380  //
381  static int recursive_rmdir_1( const Pathname & dir, bool removeDir = true )
382  {
383  DIR * dp;
384  struct dirent * d;
385 
386  if ( ! (dp = opendir( dir.c_str() )) )
387  return logResult( errno );
388 
389  while ( (d = readdir(dp)) )
390  {
391  std::string direntry = d->d_name;
392  if ( direntry == "." || direntry == ".." )
393  continue;
394  Pathname new_path( dir / d->d_name );
395 
396  struct stat st;
397  if ( ! lstat( new_path.c_str(), &st ) )
398  {
399  if ( S_ISDIR( st.st_mode ) )
400  recursive_rmdir_1( new_path );
401  else
402  ::unlink( new_path.c_str() );
403  }
404  }
405  closedir( dp );
406 
407  if ( removeDir && ::rmdir( dir.c_str() ) < 0 )
408  return errno;
409 
410  return 0;
411  }
414  {
415  MIL << "recursive_rmdir " << path << ' ';
416  PathInfo p( path );
417 
418  if ( !p.isExist() ) {
419  return logResult( 0 );
420  }
421 
422  if ( !p.isDir() ) {
423  return logResult( ENOTDIR );
424  }
425 
426  return logResult( recursive_rmdir_1( path ) );
427  }
428 
430  //
431  // METHOD NAME : clean_dir
432  // METHOD TYPE : int
433  //
434  int clean_dir( const Pathname & path )
435  {
436  MIL << "clean_dir " << path << ' ';
437  PathInfo p( path );
438 
439  if ( !p.isExist() ) {
440  return logResult( 0 );
441  }
442 
443  if ( !p.isDir() ) {
444  return logResult( ENOTDIR );
445  }
446 
447  return logResult( recursive_rmdir_1( path, false/* don't remove path itself */ ) );
448  }
449 
451  //
452  // METHOD NAME : copy_dir
453  // METHOD TYPE : int
454  //
455  int copy_dir( const Pathname & srcpath, const Pathname & destpath )
456  {
457  MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
458 
459  PathInfo sp( srcpath );
460  if ( !sp.isDir() ) {
461  return logResult( ENOTDIR );
462  }
463 
464  PathInfo dp( destpath );
465  if ( !dp.isDir() ) {
466  return logResult( ENOTDIR );
467  }
468 
469  PathInfo tp( destpath + srcpath.basename() );
470  if ( tp.isExist() ) {
471  return logResult( EEXIST );
472  }
473 
474 
475  const char *const argv[] = {
476  "/bin/cp",
477  "-dR",
478  "--",
479  srcpath.asString().c_str(),
480  destpath.asString().c_str(),
481  NULL
482  };
484  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
485  MIL << " " << output;
486  }
487  int ret = prog.close();
488  return logResult( ret, "returned" );
489  }
490 
492  //
493  // METHOD NAME : copy_dir_content
494  // METHOD TYPE : int
495  //
496  int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
497  {
498  MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
499 
500  PathInfo sp( srcpath );
501  if ( !sp.isDir() ) {
502  return logResult( ENOTDIR );
503  }
504 
505  PathInfo dp( destpath );
506  if ( !dp.isDir() ) {
507  return logResult( ENOTDIR );
508  }
509 
510  if ( srcpath == destpath ) {
511  return logResult( EEXIST );
512  }
513 
514  std::string src( srcpath.asString());
515  src += "/.";
516  const char *const argv[] = {
517  "/bin/cp",
518  "-dR",
519  "--",
520  src.c_str(),
521  destpath.asString().c_str(),
522  NULL
523  };
525  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
526  MIL << " " << output;
527  }
528  int ret = prog.close();
529  return logResult( ret, "returned" );
530  }
531 
533  // dirForEach
535 
537  {
538  static StrMatcher noDots( "[^.]*", Match::GLOB );
539  return noDots;
540  }
541 
542  int dirForEach( const Pathname & dir_r, function<bool(const Pathname &, const char *const)> fnc_r )
543  {
544  if ( ! fnc_r )
545  return 0;
546 
547  AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ),
548  []( DIR * dir_r ) { if ( dir_r ) ::closedir( dir_r ); } );
549 
550  MIL << "readdir " << dir_r << ' ';
551  if ( ! dir )
552  return logResult( errno );
553  MIL << endl; // close line before callbacks are invoked.
554 
555  int ret = 0;
556  for ( struct dirent * entry = ::readdir( dir ); entry; entry = ::readdir( dir ) )
557  {
558  if ( entry->d_name[0] == '.' && ( entry->d_name[1] == '\0' || ( entry->d_name[1] == '.' && entry->d_name[2] == '\0' ) ) )
559  continue; // omitt . and ..
560 
561  if ( ! fnc_r( dir_r, entry->d_name ) )
562  {
563  ret = -1;
564  break;
565  }
566  }
567  return ret;
568  }
569 
570  int dirForEach( const Pathname & dir_r, const StrMatcher & matcher_r, function<bool( const Pathname &, const char *const)> fnc_r )
571  {
572  if ( ! fnc_r )
573  return 0;
574 
575  bool nodots = ( &matcher_r == &matchNoDots() );
576  return dirForEach( dir_r,
577  [&]( const Pathname & dir_r, const char *const name_r )->bool
578  {
579  if ( ( nodots && name_r[0] == '.' ) || ! matcher_r( name_r ) )
580  return true;
581  return fnc_r( dir_r, name_r );
582  } );
583  }
584 
586  // readdir
588 
589  int readdir( std::list<std::string> & retlist_r, const Pathname & path_r, bool dots_r )
590  {
591  retlist_r.clear();
592  return dirForEach( path_r,
593  [&]( const Pathname & dir_r, const char *const name_r )->bool
594  {
595  if ( dots_r || name_r[0] != '.' )
596  retlist_r.push_back( name_r );
597  return true;
598  } );
599  }
600 
601 
602  int readdir( std::list<Pathname> & retlist_r, const Pathname & path_r, bool dots_r )
603  {
604  retlist_r.clear();
605  return dirForEach( path_r,
606  [&]( const Pathname & dir_r, const char *const name_r )->bool
607  {
608  if ( dots_r || name_r[0] != '.' )
609  retlist_r.push_back( dir_r/name_r );
610  return true;
611  } );
612  }
613 
614  bool DirEntry::operator==( const DirEntry &rhs ) const
615  {
616  // if one of the types is not known, use the name only
617  if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
618  return ( name == rhs.name );
619  return ((name == rhs.name ) && (type == rhs.type));
620  }
621 
622  int readdir( DirContent & retlist_r, const Pathname & path_r, bool dots_r, PathInfo::Mode statmode_r )
623  {
624  retlist_r.clear();
625  return dirForEach( path_r,
626  [&]( const Pathname & dir_r, const char *const name_r )->bool
627  {
628  if ( dots_r || name_r[0] != '.' )
629  retlist_r.push_back( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
630  return true;
631  } );
632  }
633 
634  std::ostream & operator<<( std::ostream & str, const DirContent & obj )
635  { return dumpRange( str, obj.begin(), obj.end() ); }
636 
638  // is_empty_dir
640 
641  int is_empty_dir( const Pathname & path_r )
642  {
643  return dirForEach( path_r,
644  [&]( const Pathname & dir_r, const char *const name_r )->bool
645  { return false; } );
646  }
647 
649  //
650  // METHOD NAME : unlink
651  // METHOD TYPE : int
652  //
653  int unlink( const Pathname & path )
654  {
655  MIL << "unlink " << path;
656  if ( ::unlink( path.asString().c_str() ) == -1 ) {
657  return logResult( errno );
658  }
659  return logResult( 0 );
660  }
661 
663  namespace
664  {
665  int safe_rename( const Pathname & oldpath, const Pathname & newpath )
666  {
667  int ret = ::rename( oldpath.asString().c_str(), newpath.asString().c_str() );
668 
669  // rename(2) can fail on OverlayFS. Fallback to using mv(1), which is
670  // explicitly mentioned in the kernel docs to deal correctly with OverlayFS.
671  if ( ret == -1 && errno == EXDEV ) {
672  const char *const argv[] = {
673  "/usr/bin/mv",
674  oldpath.asString().c_str(),
675  newpath.asString().c_str(),
676  NULL
677  };
679  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
680  MIL << " " << output;
681  }
682  ret = prog.close();
683  }
684 
685  return ret;
686  }
687  } // namespace
689 
691  //
692  // METHOD NAME : rename
693  // METHOD TYPE : int
694  //
695  int rename( const Pathname & oldpath, const Pathname & newpath )
696  {
697  MIL << "rename " << oldpath << " -> " << newpath;
698  if ( safe_rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
699  return logResult( errno );
700  }
701  return logResult( 0 );
702  }
703 
705  //
706  // METHOD NAME : exchange
707  // METHOD TYPE : int
708  //
709  int exchange( const Pathname & lpath, const Pathname & rpath )
710  {
711  MIL << "exchange " << lpath << " <-> " << rpath;
712  if ( lpath.empty() || rpath.empty() )
713  return logResult( EINVAL );
714 
715  PathInfo linfo( lpath );
716  PathInfo rinfo( rpath );
717 
718  if ( ! linfo.isExist() )
719  {
720  if ( ! rinfo.isExist() )
721  return logResult( 0 ); // both don't exist.
722 
723  // just rename rpath -> lpath
724  int ret = assert_dir( lpath.dirname() );
725  if ( ret != 0 )
726  return logResult( ret );
727  if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
728  return logResult( errno );
729  }
730  return logResult( 0 );
731  }
732 
733  // HERE: lpath exists:
734  if ( ! rinfo.isExist() )
735  {
736  // just rename lpath -> rpath
737  int ret = assert_dir( rpath.dirname() );
738  if ( ret != 0 )
739  return logResult( ret );
740  if ( safe_rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
741  return logResult( errno );
742  }
743  return logResult( 0 );
744  }
745 
746  // HERE: both exist
747  TmpFile tmpfile( TmpFile::makeSibling( rpath ) );
748  if ( ! tmpfile )
749  return logResult( errno );
750  Pathname tmp( tmpfile.path() );
751  ::unlink( tmp.c_str() );
752 
753  if ( safe_rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
754  return logResult( errno );
755  }
756  if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
757  safe_rename( tmp.c_str(), lpath.c_str() );
758  return logResult( errno );
759  }
760  if ( safe_rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
761  safe_rename( lpath.c_str(), rpath.c_str() );
762  safe_rename( tmp.c_str(), lpath.c_str() );
763  return logResult( errno );
764  }
765  return logResult( 0 );
766  }
767 
769  //
770  // METHOD NAME : copy
771  // METHOD TYPE : int
772  //
773  int copy( const Pathname & file, const Pathname & dest )
774  {
775  MIL << "copy " << file << " -> " << dest << ' ';
776 
777  PathInfo sp( file );
778  if ( !sp.isFile() ) {
779  return logResult( EINVAL );
780  }
781 
782  PathInfo dp( dest );
783  if ( dp.isDir() ) {
784  return logResult( EISDIR );
785  }
786 
787  const char *const argv[] = {
788  "/bin/cp",
789  "--remove-destination",
790  "--",
791  file.asString().c_str(),
792  dest.asString().c_str(),
793  NULL
794  };
796  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
797  MIL << " " << output;
798  }
799  int ret = prog.close();
800  return logResult( ret, "returned" );
801  }
802 
804  //
805  // METHOD NAME : symlink
806  // METHOD TYPE : int
807  //
808  int symlink( const Pathname & oldpath, const Pathname & newpath )
809  {
810  MIL << "symlink " << newpath << " -> " << oldpath;
811  if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
812  return logResult( errno );
813  }
814  return logResult( 0 );
815  }
816 
818  //
819  // METHOD NAME : hardlink
820  // METHOD TYPE : int
821  //
822  int hardlink( const Pathname & oldpath, const Pathname & newpath )
823  {
824  MIL << "hardlink " << newpath << " -> " << oldpath;
825  if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
826  return logResult( errno );
827  }
828  return logResult( 0 );
829  }
830 
832  //
833  // METHOD NAME : hardlink
834  // METHOD TYPE : int
835  //
836  int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath )
837  {
838  MIL << "hardlinkCopy " << oldpath << " -> " << newpath;
839 
840  PathInfo pi( oldpath, PathInfo::LSTAT );
841  if ( pi.isLink() )
842  {
843  // dont hardlink symlinks!
844  return copy( oldpath, newpath );
845  }
846 
847  pi.lstat( newpath );
848  if ( pi.isExist() )
849  {
850  int res = unlink( newpath );
851  if ( res != 0 )
852  return logResult( res );
853  }
854 
855  // Here: no symlink, no newpath
856  if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
857  {
858  switch ( errno )
859  {
860  case EPERM: // /proc/sys/fs/protected_hardlink in proc(5)
861  case EXDEV: // oldpath and newpath are not on the same mounted file system
862  return copy( oldpath, newpath );
863  break;
864  }
865  return logResult( errno );
866  }
867  return logResult( 0 );
868  }
869 
871  //
872  // METHOD NAME : readlink
873  // METHOD TYPE : int
874  //
875  int readlink( const Pathname & symlink_r, Pathname & target_r )
876  {
877  static const ssize_t bufsiz = 2047;
878  static char buf[bufsiz+1];
879  ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
880  if ( ret == -1 )
881  {
882  target_r = Pathname();
883  MIL << "readlink " << symlink_r;
884  return logResult( errno );
885  }
886  buf[ret] = '\0';
887  target_r = buf;
888  return 0;
889  }
890 
892  //
893  // METHOD NAME : expandlink
894  // METHOD TYPE : Pathname
895  //
896  Pathname expandlink( const Pathname & path_r )
897  {
898  static const unsigned int level_limit = 256;
899  static unsigned int count;
900  Pathname path(path_r);
901  PathInfo info(path_r, PathInfo::LSTAT);
902 
903  for (count = level_limit; info.isLink() && count; count--)
904  {
905  DBG << "following symlink " << path;
906  path = path.dirname() / readlink(path);
907  DBG << "->" << path << std::endl;
908  info = PathInfo(path, PathInfo::LSTAT);
909  }
910 
911  // expand limit reached
912  if (count == 0)
913  {
914  ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
915  return Pathname();
916  }
917  // symlink
918  else if (count < level_limit)
919  {
920  // check for a broken link
921  if (PathInfo(path).isExist())
922  return path;
923  // broken link, return an empty path
924  else
925  {
926  ERR << path << " is broken (expanded from " << path_r << ")" << endl;
927  return Pathname();
928  }
929  }
930 
931  // not a symlink, return the original pathname
932  DBG << "not a symlink" << endl;
933  return path;
934  }
935 
937  //
938  // METHOD NAME : copy_file2dir
939  // METHOD TYPE : int
940  //
941  int copy_file2dir( const Pathname & file, const Pathname & dest )
942  {
943  MIL << "copy_file2dir " << file << " -> " << dest << ' ';
944 
945  PathInfo sp( file );
946  if ( !sp.isFile() ) {
947  return logResult( EINVAL );
948  }
949 
950  PathInfo dp( dest );
951  if ( !dp.isDir() ) {
952  return logResult( ENOTDIR );
953  }
954 
955  const char *const argv[] = {
956  "/bin/cp",
957  "--",
958  file.asString().c_str(),
959  dest.asString().c_str(),
960  NULL
961  };
963  for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
964  MIL << " " << output;
965  }
966  int ret = prog.close();
967  return logResult( ret, "returned" );
968  }
969 
971  //
972  // METHOD NAME : md5sum
973  // METHOD TYPE : std::string
974  //
975  std::string md5sum( const Pathname & file )
976  {
977  if ( ! PathInfo( file ).isFile() ) {
978  return string();
979  }
980  std::ifstream istr( file.asString().c_str() );
981  if ( ! istr ) {
982  return string();
983  }
984  return Digest::digest( "MD5", istr );
985  }
986 
988  //
989  // METHOD NAME : sha1sum
990  // METHOD TYPE : std::string
991  //
992  std::string sha1sum( const Pathname & file )
993  {
994  return checksum(file, "SHA1");
995  }
996 
998  //
999  // METHOD NAME : checksum
1000  // METHOD TYPE : std::string
1001  //
1002  std::string checksum( const Pathname & file, const std::string &algorithm )
1003  {
1004  if ( ! PathInfo( file ).isFile() ) {
1005  return string();
1006  }
1007  std::ifstream istr( file.asString().c_str() );
1008  if ( ! istr ) {
1009  return string();
1010  }
1011  return Digest::digest( algorithm, istr );
1012  }
1013 
1014  bool is_checksum( const Pathname & file, const CheckSum &checksum )
1015  {
1016  return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
1017  }
1018 
1020  //
1021  // METHOD NAME : erase
1022  // METHOD TYPE : int
1023  //
1024  int erase( const Pathname & path )
1025  {
1026  int res = 0;
1027  PathInfo p( path, PathInfo::LSTAT );
1028  if ( p.isExist() )
1029  {
1030  if ( p.isDir() )
1031  res = recursive_rmdir( path );
1032  else
1033  res = unlink( path );
1034  }
1035  return res;
1036  }
1037 
1039  //
1040  // METHOD NAME : chmod
1041  // METHOD TYPE : int
1042  //
1043  int chmod( const Pathname & path, mode_t mode )
1044  {
1045  MIL << "chmod " << path << ' ' << str::octstring( mode );
1046  if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
1047  return logResult( errno );
1048  }
1049  return logResult( 0 );
1050  }
1051 
1052  int addmod( const Pathname & path, mode_t mode )
1053  {
1054  mode_t omode( PathInfo( path ).st_mode() );
1055  mode_t tmode( omode | mode );
1056  if ( omode != mode )
1057  return chmod( path, tmode );
1058  return 0;
1059  }
1060 
1061  int delmod( const Pathname & path, mode_t mode )
1062  {
1063  mode_t omode( PathInfo( path ).st_mode() );
1064  mode_t tmode( omode & ~mode );
1065  if ( omode != mode )
1066  return chmod( path, tmode );
1067  return 0;
1068  }
1069 
1071  //
1072  // METHOD NAME : zipType
1073  // METHOD TYPE : ZIP_TYPE
1074  //
1075  ZIP_TYPE zipType( const Pathname & file )
1076  {
1077  ZIP_TYPE ret = ZT_NONE;
1078 
1079  int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
1080 
1081  if ( fd != -1 ) {
1082  const int magicSize = 3;
1083  unsigned char magic[magicSize];
1084  memset( magic, 0, magicSize );
1085  if ( read( fd, magic, magicSize ) == magicSize ) {
1086  if ( magic[0] == 0037 && magic[1] == 0213 ) {
1087  ret = ZT_GZ;
1088  } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
1089  ret = ZT_BZ2;
1090  }
1091  }
1092  close( fd );
1093  }
1094 
1095  return ret;
1096  }
1097 
1099  //
1100  // METHOD NAME : df
1101  // METHOD TYPE : ByteCount
1102  //
1103  ByteCount df( const Pathname & path_r )
1104  {
1105  ByteCount ret( -1 );
1106  struct statvfs sb;
1107  if ( statvfs( path_r.c_str(), &sb ) == 0 )
1108  {
1109  ret = sb.f_bfree * sb.f_bsize;
1110  }
1111  return ret;
1112  }
1113 
1115  //
1116  // METHOD NAME : getUmask
1117  // METHOD TYPE : mode_t
1118  //
1119  mode_t getUmask()
1120  {
1121  mode_t mask = ::umask( 0022 );
1122  ::umask( mask );
1123  return mask;
1124  }
1125 
1127  //
1128  // METHOD NAME : getUmask
1129  // METHOD TYPE : mode_t
1130  //
1131  int assert_file( const Pathname & path, unsigned mode )
1132  {
1133  int ret = assert_dir( path.dirname() );
1134  MIL << "assert_file " << str::octstring( mode ) << " " << path;
1135  if ( ret != 0 )
1136  return logResult( ret );
1137 
1138  PathInfo pi( path );
1139  if ( pi.isExist() )
1140  return logResult( pi.isFile() ? 0 : EEXIST );
1141 
1142  int fd = ::creat( path.c_str(), mode );
1143  if ( fd == -1 )
1144  return logResult( errno );
1145 
1146  ::close( fd );
1147  return logResult( 0 );
1148  }
1149 
1151  //
1152  // METHOD NAME : touch
1153  // METHOD TYPE : int
1154  //
1155  int touch (const Pathname & path)
1156  {
1157  MIL << "touch " << path;
1158  struct ::utimbuf times;
1159  times.actime = ::time( 0 );
1160  times.modtime = ::time( 0 );
1161  if ( ::utime( path.asString().c_str(), &times ) == -1 ) {
1162  return logResult( errno );
1163  }
1164  return logResult( 0 );
1165  }
1166 
1168  } // namespace filesystem
1171 } // namespace zypp
FileType fileType() const
Definition: PathInfo.cc:213
int assert_dir(const Pathname &path, unsigned mode)
Like &#39;mkdir -p&#39;.
Definition: PathInfo.cc:320
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:246
#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:709
ZIP_TYPE
Test whether a file is compressed (gzip/bzip2).
Definition: PathInfo.h:774
std::string digest()
get hex string representation of the digest
Definition: Digest.cc:191
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:1131
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:364
std::string sha1sum(const Pathname &file)
Compute a files sha1sum.
Definition: PathInfo.cc:992
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:975
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 &#39;readlink&#39;.
Definition: PathInfo.cc:875
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 &#39;mkdir&#39;.
Definition: PathInfo.cc:306
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 &#39;::link&#39;.
Definition: PathInfo.cc:822
mode_t operm() const
Definition: PathInfo.h:323
friend std::ostream & operator<<(std::ostream &str, const StatMode &obj)
Definition: PathInfo.cc:96
int chmod(const Pathname &path, mode_t mode)
Like &#39;chmod&#39;.
Definition: PathInfo.cc:1043
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 &#39;rm -r DIR/ *&#39;.
Definition: PathInfo.cc:434
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
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 &#39;cp file dest&#39;.
Definition: PathInfo.cc:941
#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:641
ZIP_TYPE zipType(const Pathname &file)
Definition: PathInfo.cc:1075
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition: PathInfo.cc:1052
const StrMatcher & matchNoDots()
Convenience returning StrMatcher( "[^.]*", Match::GLOB )
Definition: PathInfo.cc:536
std::ostream & dumpRange(std::ostream &str, TIterator begin, TIterator end, const std::string &intro="{", const std::string &pfx="\n ", const std::string &sep="\n ", const std::string &sfx="\n", const std::string &extro="}")
Print range defined by iterators (multiline style).
Definition: LogTools.h:91
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 &#39;unlink&#39;.
Definition: PathInfo.cc:653
int rename(const Pathname &oldpath, const Pathname &newpath)
Like &#39;rename&#39;.
Definition: PathInfo.cc:695
const char * c_str() const
String representation.
Definition: Pathname.h:109
int recursive_rmdir(const Pathname &path)
Like &#39;rm -r DIR&#39;.
Definition: PathInfo.cc:413
#define WAR
Definition: Logger.h:65
bool operator==(const DirEntry &rhs) const
Definition: PathInfo.cc:614
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:836
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 &#39;symlink&#39;.
Definition: PathInfo.cc:808
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&#39;s modification and access times.
Definition: PathInfo.cc:1155
SolvableIdType size_type
Definition: PoolMember.h:126
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 &#39;cp file dest&#39;.
Definition: PathInfo.cc:773
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:589
int rmdir(const Pathname &path)
Like &#39;rmdir&#39;.
Definition: PathInfo.cc:367
mode_t getUmask()
Get the current umask (file mode creation mask)
Definition: PathInfo.cc:1119
int copy_dir(const Pathname &srcpath, const Pathname &destpath)
Like &#39;cp -a srcpath destpath&#39;.
Definition: PathInfo.cc:455
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
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition: PathInfo.cc:1002
int erase(const Pathname &path)
Erase whatever happens to be located at path (file or directory).
Definition: PathInfo.cc:1024
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:92
int copy_dir_content(const Pathname &srcpath, const Pathname &destpath)
Like &#39;cp -a srcpath/.
Definition: PathInfo.cc:496
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:542
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:896
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:1061
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
#define logResult
Definition: PathInfo.cc:285
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
bool lstat(const Pathname &path)
LSTAT path.
Definition: PathInfo.h:264
friend std::ostream & operator<<(std::ostream &str, const PathInfo &obj)
Definition: PathInfo.cc:262
Mode mode() const
Return current stat Mode.
Definition: PathInfo.h:252
static int recursive_rmdir_1(const Pathname &dir, bool removeDir=true)
Definition: PathInfo.cc:381
#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:1014
mode_t st_mode() const
Definition: PathInfo.h:326
ByteCount df(const Pathname &path_r)
Report free disk space on a mounted file system.
Definition: PathInfo.cc:1103