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