libzypp 17.25.7
PathInfo.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
13#include <utime.h> // for ::utime
14#include <sys/statvfs.h>
15#include <sys/sysmacros.h> // for ::minor, ::major macros
16
17#include <iostream>
18#include <fstream>
19#include <iomanip>
20
21#include <zypp/base/LogTools.h>
22#include <zypp/base/String.h>
23#include <zypp/base/IOStream.h>
25#include <zypp/base/Errno.h>
26
27#include <zypp/AutoDispose.h>
29#include <zypp/PathInfo.h>
30#include <zypp/Digest.h>
31#include <zypp/TmpPath.h>
32
33using std::endl;
34using std::string;
35
37namespace zypp
38{
40 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
55 EMUMOUT( FT_DIR );
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 std::string::size_type lastpos = ( path.relative() ? 2 : 1 ); // skip leasding './' or '/'
335 std::string::size_type pos = std::string::npos;
336 int ret = 0;
337
338 while ( (pos = spath.find('/',lastpos)) != std::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 }
413 int recursive_rmdir( const Pathname & path )
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 p.lstat(); // get dir symlinks
427 if ( !p.isDir() ) {
428 MIL << "unlink symlink ";
429 if ( ::unlink( path.asString().c_str() ) == -1 ) {
430 return logResult( errno );
431 }
432 return logResult( 0 );
433 }
434
435 return logResult( 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 logResult( 0 );
450 }
451
452 if ( !p.isDir() ) {
453 return logResult( ENOTDIR );
454 }
455
456 return logResult( recursive_rmdir_1( path, false/* don't remove path itself */ ) );
457 }
458
460 //
461 // METHOD NAME : copy_dir
462 // METHOD TYPE : int
463 //
464 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
465 {
466 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
467
468 PathInfo sp( srcpath );
469 if ( !sp.isDir() ) {
470 return logResult( ENOTDIR );
471 }
472
473 PathInfo dp( destpath );
474 if ( !dp.isDir() ) {
475 return logResult( ENOTDIR );
476 }
477
478 PathInfo tp( destpath + srcpath.basename() );
479 if ( tp.isExist() ) {
480 return logResult( EEXIST );
481 }
482
483
484 const char *const argv[] = {
485 "/bin/cp",
486 "-dR",
487 "--",
488 srcpath.asString().c_str(),
489 destpath.asString().c_str(),
490 NULL
491 };
493 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
494 MIL << " " << output;
495 }
496 int ret = prog.close();
497 return logResult( ret, "returned" );
498 }
499
501 //
502 // METHOD NAME : copy_dir_content
503 // METHOD TYPE : int
504 //
505 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
506 {
507 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
508
509 PathInfo sp( srcpath );
510 if ( !sp.isDir() ) {
511 return logResult( ENOTDIR );
512 }
513
514 PathInfo dp( destpath );
515 if ( !dp.isDir() ) {
516 return logResult( ENOTDIR );
517 }
518
519 if ( srcpath == destpath ) {
520 return logResult( EEXIST );
521 }
522
523 std::string src( srcpath.asString());
524 src += "/.";
525 const char *const argv[] = {
526 "/bin/cp",
527 "-dR",
528 "--",
529 src.c_str(),
530 destpath.asString().c_str(),
531 NULL
532 };
534 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
535 MIL << " " << output;
536 }
537 int ret = prog.close();
538 return logResult( ret, "returned" );
539 }
540
542 // dirForEach
544
546 {
547 static StrMatcher noDots( "[^.]*", Match::GLOB );
548 return noDots;
549 }
550
551 int dirForEach( const Pathname & dir_r, function<bool(const Pathname &, const char *const)> fnc_r )
552 {
553 if ( ! fnc_r )
554 return 0;
555
556 AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ),
557 []( DIR * dir_r ) { if ( dir_r ) ::closedir( dir_r ); } );
558
559 MIL << "readdir " << dir_r << ' ';
560 if ( ! dir )
561 return logResult( errno );
562 MIL << endl; // close line before callbacks are invoked.
563
564 int ret = 0;
565 for ( struct dirent * entry = ::readdir( dir ); entry; entry = ::readdir( dir ) )
566 {
567 if ( entry->d_name[0] == '.' && ( entry->d_name[1] == '\0' || ( entry->d_name[1] == '.' && entry->d_name[2] == '\0' ) ) )
568 continue; // omitt . and ..
569
570 if ( ! fnc_r( dir_r, entry->d_name ) )
571 {
572 ret = -1;
573 break;
574 }
575 }
576 return ret;
577 }
578
579 int dirForEach( const Pathname & dir_r, const StrMatcher & matcher_r, function<bool( const Pathname &, const char *const)> fnc_r )
580 {
581 if ( ! fnc_r )
582 return 0;
583
584 bool nodots = ( &matcher_r == &matchNoDots() );
585 return dirForEach( dir_r,
586 [&]( const Pathname & dir_r, const char *const name_r )->bool
587 {
588 if ( ( nodots && name_r[0] == '.' ) || ! matcher_r( name_r ) )
589 return true;
590 return fnc_r( dir_r, name_r );
591 } );
592 }
593
595 // readdir
597
598 int readdir( std::list<std::string> & retlist_r, const Pathname & path_r, bool dots_r )
599 {
600 retlist_r.clear();
601 return dirForEach( path_r,
602 [&]( const Pathname & dir_r, const char *const name_r )->bool
603 {
604 if ( dots_r || name_r[0] != '.' )
605 retlist_r.push_back( name_r );
606 return true;
607 } );
608 }
609
610
611 int readdir( std::list<Pathname> & retlist_r, const Pathname & path_r, bool dots_r )
612 {
613 retlist_r.clear();
614 return dirForEach( path_r,
615 [&]( const Pathname & dir_r, const char *const name_r )->bool
616 {
617 if ( dots_r || name_r[0] != '.' )
618 retlist_r.push_back( dir_r/name_r );
619 return true;
620 } );
621 }
622
623 bool DirEntry::operator==( const DirEntry &rhs ) const
624 {
625 // if one of the types is not known, use the name only
626 if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
627 return ( name == rhs.name );
628 return ((name == rhs.name ) && (type == rhs.type));
629 }
630
631 int readdir( DirContent & retlist_r, const Pathname & path_r, bool dots_r, PathInfo::Mode statmode_r )
632 {
633 retlist_r.clear();
634 return dirForEach( path_r,
635 [&]( const Pathname & dir_r, const char *const name_r )->bool
636 {
637 if ( dots_r || name_r[0] != '.' )
638 retlist_r.push_back( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
639 return true;
640 } );
641 }
642
643 std::ostream & operator<<( std::ostream & str, const DirContent & obj )
644 { return dumpRange( str, obj.begin(), obj.end() ); }
645
647 // is_empty_dir
649
650 int is_empty_dir( const Pathname & path_r )
651 {
652 return dirForEach( path_r,
653 [&]( const Pathname & dir_r, const char *const name_r )->bool
654 { return false; } );
655 }
656
658 //
659 // METHOD NAME : unlink
660 // METHOD TYPE : int
661 //
662 int unlink( const Pathname & path )
663 {
664 MIL << "unlink " << path;
665 if ( ::unlink( path.asString().c_str() ) == -1 ) {
666 return logResult( errno );
667 }
668 return logResult( 0 );
669 }
670
672 namespace
673 {
674 int safe_rename( const Pathname & oldpath, const Pathname & newpath )
675 {
676 int ret = ::rename( oldpath.asString().c_str(), newpath.asString().c_str() );
677
678 // rename(2) can fail on OverlayFS. Fallback to using mv(1), which is
679 // explicitly mentioned in the kernel docs to deal correctly with OverlayFS.
680 if ( ret == -1 && errno == EXDEV ) {
681 const char *const argv[] = {
682 "/usr/bin/mv",
683 oldpath.asString().c_str(),
684 newpath.asString().c_str(),
685 NULL
686 };
687 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
688 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
689 MIL << " " << output;
690 }
691 ret = prog.close();
692 }
693
694 return ret;
695 }
696 } // namespace
698
700 //
701 // METHOD NAME : rename
702 // METHOD TYPE : int
703 //
704 int rename( const Pathname & oldpath, const Pathname & newpath )
705 {
706 MIL << "rename " << oldpath << " -> " << newpath;
707 if ( safe_rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
708 return logResult( errno );
709 }
710 return logResult( 0 );
711 }
712
714 //
715 // METHOD NAME : exchange
716 // METHOD TYPE : int
717 //
718 int exchange( const Pathname & lpath, const Pathname & rpath )
719 {
720 MIL << "exchange " << lpath << " <-> " << rpath;
721 if ( lpath.empty() || rpath.empty() )
722 return logResult( EINVAL );
723
724 PathInfo linfo( lpath );
725 PathInfo rinfo( rpath );
726
727 if ( ! linfo.isExist() )
728 {
729 if ( ! rinfo.isExist() )
730 return logResult( 0 ); // both don't exist.
731
732 // just rename rpath -> lpath
733 int ret = assert_dir( lpath.dirname() );
734 if ( ret != 0 )
735 return logResult( ret );
736 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
737 return logResult( errno );
738 }
739 return logResult( 0 );
740 }
741
742 // HERE: lpath exists:
743 if ( ! rinfo.isExist() )
744 {
745 // just rename lpath -> rpath
746 int ret = assert_dir( rpath.dirname() );
747 if ( ret != 0 )
748 return logResult( ret );
749 if ( safe_rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
750 return logResult( errno );
751 }
752 return logResult( 0 );
753 }
754
755 // HERE: both exist
756 TmpFile tmpfile( TmpFile::makeSibling( rpath ) );
757 if ( ! tmpfile )
758 return logResult( errno );
759 Pathname tmp( tmpfile.path() );
760 ::unlink( tmp.c_str() );
761
762 if ( safe_rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
763 return logResult( errno );
764 }
765 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
766 safe_rename( tmp.c_str(), lpath.c_str() );
767 return logResult( errno );
768 }
769 if ( safe_rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
770 safe_rename( lpath.c_str(), rpath.c_str() );
771 safe_rename( tmp.c_str(), lpath.c_str() );
772 return logResult( errno );
773 }
774 return logResult( 0 );
775 }
776
778 //
779 // METHOD NAME : copy
780 // METHOD TYPE : int
781 //
782 int copy( const Pathname & file, const Pathname & dest )
783 {
784 MIL << "copy " << file << " -> " << dest << ' ';
785
786 PathInfo sp( file );
787 if ( !sp.isFile() ) {
788 return logResult( EINVAL );
789 }
790
791 PathInfo dp( dest );
792 if ( dp.isDir() ) {
793 return logResult( EISDIR );
794 }
795
796 const char *const argv[] = {
797 "/bin/cp",
798 "--remove-destination",
799 "--",
800 file.asString().c_str(),
801 dest.asString().c_str(),
802 NULL
803 };
805 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
806 MIL << " " << output;
807 }
808 int ret = prog.close();
809 return logResult( ret, "returned" );
810 }
811
813 //
814 // METHOD NAME : symlink
815 // METHOD TYPE : int
816 //
817 int symlink( const Pathname & oldpath, const Pathname & newpath )
818 {
819 MIL << "symlink " << newpath << " -> " << oldpath;
820 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
821 return logResult( errno );
822 }
823 return logResult( 0 );
824 }
825
827 //
828 // METHOD NAME : hardlink
829 // METHOD TYPE : int
830 //
831 int hardlink( const Pathname & oldpath, const Pathname & newpath )
832 {
833 MIL << "hardlink " << newpath << " -> " << oldpath;
834 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
835 return logResult( errno );
836 }
837 return logResult( 0 );
838 }
839
841 //
842 // METHOD NAME : hardlink
843 // METHOD TYPE : int
844 //
845 int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath )
846 {
847 MIL << "hardlinkCopy " << oldpath << " -> " << newpath;
848
849 PathInfo pi( oldpath, PathInfo::LSTAT );
850 if ( pi.isLink() )
851 {
852 // dont hardlink symlinks!
853 MIL << " => copy" << endl;
854 return copy( oldpath, newpath );
855 }
856
857 pi.lstat( newpath );
858 if ( pi.isExist() )
859 {
860 int res = unlink( newpath );
861 if ( res != 0 )
862 return logResult( res );
863 }
864
865 // Here: no symlink, no newpath
866 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
867 {
868 switch ( errno )
869 {
870 case EPERM: // /proc/sys/fs/protected_hardlink in proc(5)
871 case EXDEV: // oldpath and newpath are not on the same mounted file system
872 MIL << " => copy" << endl;
873 return copy( oldpath, newpath );
874 break;
875 }
876 return logResult( errno );
877 }
878 return logResult( 0 );
879 }
880
882 //
883 // METHOD NAME : readlink
884 // METHOD TYPE : int
885 //
886 int readlink( const Pathname & symlink_r, Pathname & target_r )
887 {
888 static const ssize_t bufsiz = 2047;
889 static char buf[bufsiz+1];
890 ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
891 if ( ret == -1 )
892 {
893 target_r = Pathname();
894 MIL << "readlink " << symlink_r;
895 return logResult( errno );
896 }
897 buf[ret] = '\0';
898 target_r = buf;
899 return 0;
900 }
901
903 //
904 // METHOD NAME : expandlink
905 // METHOD TYPE : Pathname
906 //
907 Pathname expandlink( const Pathname & path_r )
908 {
909 static const unsigned int level_limit = 256;
910 static unsigned int count;
911 Pathname path(path_r);
912 PathInfo info(path_r, PathInfo::LSTAT);
913
914 for (count = level_limit; info.isLink() && count; count--)
915 {
916 DBG << "following symlink " << path;
917 path = path.dirname() / readlink(path);
918 DBG << "->" << path << std::endl;
919 info = PathInfo(path, PathInfo::LSTAT);
920 }
921
922 // expand limit reached
923 if (count == 0)
924 {
925 ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
926 return Pathname();
927 }
928 // symlink
929 else if (count < level_limit)
930 {
931 // check for a broken link
932 if (PathInfo(path).isExist())
933 return path;
934 // broken link, return an empty path
935 else
936 {
937 ERR << path << " is broken (expanded from " << path_r << ")" << endl;
938 return Pathname();
939 }
940 }
941
942 // not a symlink, return the original pathname
943 DBG << "not a symlink" << endl;
944 return path;
945 }
946
948 //
949 // METHOD NAME : copy_file2dir
950 // METHOD TYPE : int
951 //
952 int copy_file2dir( const Pathname & file, const Pathname & dest )
953 {
954 MIL << "copy_file2dir " << file << " -> " << dest << ' ';
955
956 PathInfo sp( file );
957 if ( !sp.isFile() ) {
958 return logResult( EINVAL );
959 }
960
961 PathInfo dp( dest );
962 if ( !dp.isDir() ) {
963 return logResult( ENOTDIR );
964 }
965
966 const char *const argv[] = {
967 "/bin/cp",
968 "--",
969 file.asString().c_str(),
970 dest.asString().c_str(),
971 NULL
972 };
974 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
975 MIL << " " << output;
976 }
977 int ret = prog.close();
978 return logResult( ret, "returned" );
979 }
980
982 //
983 // METHOD NAME : md5sum
984 // METHOD TYPE : std::string
985 //
986 std::string md5sum( const Pathname & file )
987 {
988 if ( ! PathInfo( file ).isFile() ) {
989 return string();
990 }
991 std::ifstream istr( file.asString().c_str() );
992 if ( ! istr ) {
993 return string();
994 }
995 return Digest::digest( "MD5", istr );
996 }
997
999 //
1000 // METHOD NAME : sha1sum
1001 // METHOD TYPE : std::string
1002 //
1003 std::string sha1sum( const Pathname & file )
1004 {
1005 return checksum(file, "SHA1");
1006 }
1007
1009 //
1010 // METHOD NAME : checksum
1011 // METHOD TYPE : std::string
1012 //
1013 std::string checksum( const Pathname & file, const std::string &algorithm )
1014 {
1015 if ( ! PathInfo( file ).isFile() ) {
1016 return string();
1017 }
1018 std::ifstream istr( file.asString().c_str() );
1019 if ( ! istr ) {
1020 return string();
1021 }
1022 return Digest::digest( algorithm, istr );
1023 }
1024
1025 bool is_checksum( const Pathname & file, const CheckSum &checksum )
1026 {
1027 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
1028 }
1029
1031 //
1032 // METHOD NAME : erase
1033 // METHOD TYPE : int
1034 //
1035 int erase( const Pathname & path )
1036 {
1037 int res = 0;
1038 PathInfo p( path, PathInfo::LSTAT );
1039 if ( p.isExist() )
1040 {
1041 if ( p.isDir() )
1042 res = recursive_rmdir( path );
1043 else
1044 res = unlink( path );
1045 }
1046 return res;
1047 }
1048
1050 //
1051 // METHOD NAME : chmod
1052 // METHOD TYPE : int
1053 //
1054 int chmod( const Pathname & path, mode_t mode )
1055 {
1056 MIL << "chmod " << path << ' ' << str::octstring( mode );
1057 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
1058 return logResult( errno );
1059 }
1060 return logResult( 0 );
1061 }
1062
1063 int addmod( const Pathname & path, mode_t mode )
1064 {
1065 mode_t omode( PathInfo( path ).st_mode() );
1066 mode_t tmode( omode | mode );
1067 if ( omode != mode )
1068 return chmod( path, tmode );
1069 return 0;
1070 }
1071
1072 int delmod( const Pathname & path, mode_t mode )
1073 {
1074 mode_t omode( PathInfo( path ).st_mode() );
1075 mode_t tmode( omode & ~mode );
1076 if ( omode != mode )
1077 return chmod( path, tmode );
1078 return 0;
1079 }
1080
1082 //
1083 // METHOD NAME : zipType
1084 // METHOD TYPE : ZIP_TYPE
1085 //
1086 ZIP_TYPE zipType( const Pathname & file )
1087 {
1088 ZIP_TYPE ret = ZT_NONE;
1089
1090 int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
1091
1092 if ( fd != -1 ) {
1093 const int magicSize = 5;
1094 unsigned char magic[magicSize];
1095 memset( magic, 0, magicSize );
1096 if ( read( fd, magic, magicSize ) == magicSize ) {
1097 if ( magic[0] == 0037 && magic[1] == 0213 ) {
1098 ret = ZT_GZ;
1099 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
1100 ret = ZT_BZ2;
1101 } else if ( magic[0] == '\0' && magic[1] == 'Z' && magic[2] == 'C' && magic[3] == 'K' && magic[4] == '1') {
1102 ret = ZT_ZCHNK;
1103
1104 }
1105 }
1106 close( fd );
1107 }
1108
1109 return ret;
1110 }
1111
1113 //
1114 // METHOD NAME : df
1115 // METHOD TYPE : ByteCount
1116 //
1117 ByteCount df( const Pathname & path_r )
1118 {
1119 ByteCount ret( -1 );
1120 struct statvfs sb;
1121 if ( statvfs( path_r.c_str(), &sb ) == 0 )
1122 {
1123 ret = sb.f_bfree * sb.f_bsize;
1124 }
1125 return ret;
1126 }
1127
1129 //
1130 // METHOD NAME : getUmask
1131 // METHOD TYPE : mode_t
1132 //
1133 mode_t getUmask()
1134 {
1135 mode_t mask = ::umask( 0022 );
1136 ::umask( mask );
1137 return mask;
1138 }
1139
1141 //
1142 // METHOD NAME : getUmask
1143 // METHOD TYPE : mode_t
1144 //
1145 int assert_file( const Pathname & path, unsigned mode )
1146 {
1147 int ret = assert_dir( path.dirname() );
1148 MIL << "assert_file " << str::octstring( mode ) << " " << path;
1149 if ( ret != 0 )
1150 return logResult( ret );
1151
1152 PathInfo pi( path );
1153 if ( pi.isExist() )
1154 return logResult( pi.isFile() ? 0 : EEXIST );
1155
1156 int fd = ::creat( path.c_str(), mode );
1157 if ( fd == -1 )
1158 return logResult( errno );
1159
1160 ::close( fd );
1161 return logResult( 0 );
1162 }
1163
1164 int assert_file_mode( const Pathname & path, unsigned mode )
1165 {
1166 int ret = assert_dir( path.dirname() );
1167 MIL << "assert_file_mode " << str::octstring( mode ) << " " << path;
1168 if ( ret != 0 )
1169 return logResult( ret );
1170
1171 PathInfo pi( path );
1172 if ( pi.isExist() )
1173 {
1174 if ( ! pi.isFile() )
1175 return logResult( EEXIST );
1176
1177 mode = applyUmaskTo( mode );
1178 if ( pi.st_mode() != mode )
1179 return chmod( path, mode );
1180
1181 return logResult( 0 );
1182 }
1183
1184 int fd = ::creat( path.c_str(), mode );
1185 if ( fd == -1 )
1186 return logResult( errno );
1187 ::close( fd );
1188 return logResult( 0 );
1189 }
1190
1192 //
1193 // METHOD NAME : touch
1194 // METHOD TYPE : int
1195 //
1196 int touch (const Pathname & path)
1197 {
1198 MIL << "touch " << path;
1199 struct ::utimbuf times;
1200 times.actime = ::time( 0 );
1201 times.modtime = ::time( 0 );
1202 if ( ::utime( path.asString().c_str(), &times ) == -1 ) {
1203 return logResult( errno );
1204 }
1205 return logResult( 0 );
1206 }
1207
1209 } // namespace filesystem
1212} // namespace zypp
#define DBG
Definition: Logger.h:78
#define MIL
Definition: Logger.h:79
#define ERR
Definition: Logger.h:81
#define WAR
Definition: Logger.h:80
#define EMUMOUT(T)
#define logResult
Definition: PathInfo.cc:285
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
Store and operate with byte count.
Definition: ByteCount.h:31
std::string digest()
get hex string representation of the digest
Definition: Digest.cc:189
Convenience errno wrapper.
Definition: Errno.h:26
Execute a program and give access to its io An object of this class encapsulates the execution of an ...
int close()
Wait for the progamm to complete.
@ GLOB
Glob.
Definition: StrMatcher.h:47
String matching (STRING|SUBSTRING|GLOB|REGEX).
Definition: StrMatcher.h:298
std::string receiveLine()
Read one line from the input stream.
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
bool lstat(const Pathname &path)
LSTAT path.
Definition: PathInfo.h:264
mode_t uperm() const
Definition: PathInfo.h:321
StatMode asStatMode() const
Return st_mode() as filesystem::StatMode.
Definition: PathInfo.h:330
bool stat()
STAT current path.
Definition: PathInfo.h:269
mode_t st_mode() const
Definition: PathInfo.h:326
bool operator()()
Restat current path using current mode.
Definition: PathInfo.cc:189
Mode
stat() or lstat()
Definition: PathInfo.h:226
unsigned int devMinor() const
Definition: PathInfo.cc:252
FileType fileType() const
Definition: PathInfo.cc:213
mode_t gperm() const
Definition: PathInfo.h:322
bool lstat()
LSTAT current path.
Definition: PathInfo.h:271
mode_t userMay() const
Returns current users permission ([0-7])
Definition: PathInfo.cc:225
bool isExist() const
Return whether valid stat info exists.
Definition: PathInfo.h:281
mode_t operm() const
Definition: PathInfo.h:323
const std::string & asString() const
Return current Pathname as String.
Definition: PathInfo.h:248
unsigned int devMajor() const
Definition: PathInfo.cc:242
int error() const
Return error returned from last stat/lstat call.
Definition: PathInfo.h:254
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
const char * c_str() const
String representation.
Definition: Pathname.h:110
const std::string & asString() const
String representation.
Definition: Pathname.h:91
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
bool relative() const
Test for a relative path.
Definition: Pathname.h:118
Wrapper class for mode_t values as derived from ::stat.
Definition: PathInfo.h:81
mode_t perm() const
Definition: PathInfo.h:156
FileType fileType() const
Definition: PathInfo.cc:71
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:128
static TmpFile makeSibling(const Pathname &sibling_r)
Provide a new empty temporary directory as sibling.
Definition: TmpPath.cc:218
Pathname path() const
Definition: TmpPath.cc:146
String related utilities and Regular expression matching.
std::map< std::string, std::string > read(const Pathname &_path)
Read sysconfig file path_r and return (key,valye) pairs.
Definition: Sysconfig.cc:34
int chmod(const Pathname &path, mode_t mode)
Like 'chmod'.
Definition: PathInfo.cc:1054
const StrMatcher & matchNoDots()
Convenience returning StrMatcher( "[^.]*", Match::GLOB )
Definition: PathInfo.cc:545
std::ostream & operator<<(std::ostream &str, const Glob &obj)
Definition: Glob.cc:53
std::string checksum(const Pathname &file, const std::string &algorithm)
Compute a files checksum.
Definition: PathInfo.cc:1013
int delmod(const Pathname &path, mode_t mode)
Remove the mode bits from the file given by path.
Definition: PathInfo.cc:1072
static int recursive_rmdir_1(const Pathname &dir, bool removeDir=true)
Definition: PathInfo.cc:381
FileType
File type information.
Definition: PathInfo.h:56
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:907
int is_empty_dir(const Pathname &path_r)
Check if the specified directory is empty.
Definition: PathInfo.cc:650
mode_t applyUmaskTo(mode_t mode_r)
Modify mode_r according to the current umask ( mode_r & ~getUmask() ).
Definition: PathInfo.h:813
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:598
ByteCount df(const Pathname &path_r)
Report free disk space on a mounted file system.
Definition: PathInfo.cc:1117
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:662
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition: PathInfo.cc:704
int mkdir(const Pathname &path, unsigned mode)
Like 'mkdir'.
Definition: PathInfo.cc:306
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:551
int rmdir(const Pathname &path)
Like 'rmdir'.
Definition: PathInfo.cc:367
bool is_checksum(const Pathname &file, const CheckSum &checksum)
check files checksum
Definition: PathInfo.cc:1025
int assert_file(const Pathname &path, unsigned mode)
Create an empty file if it does not yet exist.
Definition: PathInfo.cc:1145
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition: PathInfo.cc:413
int copy_dir(const Pathname &srcpath, const Pathname &destpath)
Like 'cp -a srcpath destpath'.
Definition: PathInfo.cc:464
int copy_dir_content(const Pathname &srcpath, const Pathname &destpath)
Like 'cp -a srcpath/.
Definition: PathInfo.cc:505
int erase(const Pathname &path)
Erase whatever happens to be located at path (file or directory).
Definition: PathInfo.cc:1035
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition: PathInfo.cc:1063
int hardlink(const Pathname &oldpath, const Pathname &newpath)
Like '::link'.
Definition: PathInfo.cc:831
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
Definition: PathInfo.cc:886
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:320
int copy_file2dir(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition: PathInfo.cc:952
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition: PathInfo.cc:1164
mode_t getUmask()
Get the current umask (file mode creation mask)
Definition: PathInfo.cc:1133
int touch(const Pathname &path)
Change file's modification and access times.
Definition: PathInfo.cc:1196
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:845
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:547
std::string md5sum(const Pathname &file)
Compute a files md5sum.
Definition: PathInfo.cc:986
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
Definition: PathInfo.cc:718
std::string sha1sum(const Pathname &file)
Compute a files sha1sum.
Definition: PathInfo.cc:1003
ZIP_TYPE zipType(const Pathname &file)
Definition: PathInfo.cc:1086
int copy(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition: PathInfo.cc:782
ZIP_TYPE
Test whether a file is compressed (gzip/bzip2).
Definition: PathInfo.h:778
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like 'symlink'.
Definition: PathInfo.cc:817
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
Definition: PathInfo.cc:443
boost::io::ios_base_all_saver IosFmtFlagsSaver
Save and restore streams width, precision and fmtflags.
Definition: IOStream.h:35
SolvableIdType size_type
Definition: PoolMember.h:126
std::string octstring(char n, int w=4)
Definition: String.h:345
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition: String.cc:53
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
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
Listentry returned by readdir.
Definition: PathInfo.h:532
bool operator==(const DirEntry &rhs) const
Definition: PathInfo.cc:623