libzypp 17.32.5
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#include <utility>
21
27
30#include <zypp-core/Digest.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 {
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 //
142 : path_t(std::move( 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 {
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 = nullptr;
384 struct dirent * d = nullptr;
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 ) )
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
469 if ( !sp.isDir() ) {
470 return logResult( ENOTDIR );
471 }
472
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 //
506 {
507 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
508
510 if ( !sp.isDir() ) {
511 return logResult( ENOTDIR );
512 }
513
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 // dirForEachImpl
544 template <class... T>
545 constexpr bool always_false = false;
546
547 template <typename F>
549 {
550 AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ),
551 []( DIR * dir_r ) { if ( dir_r ) ::closedir( dir_r ); } );
552
553 MIL << "readdir " << dir_r << ' ';
554 if ( ! dir )
555 return logResult( errno );
556 MIL << endl; // close line before callbacks are invoked.
557
558 int ret = 0;
559 for ( struct dirent * entry = ::readdir( dir ); entry; entry = ::readdir( dir ) )
560 {
561 if ( entry->d_name[0] == '.' && ( entry->d_name[1] == '\0' || ( entry->d_name[1] == '.' && entry->d_name[2] == '\0' ) ) )
562 continue; // omitt . and ..
563
564 // some static checks to make sure the correct func is selected
565 static_assert( !std::is_invocable_v< function<bool(const Pathname &, const char *const)>, const Pathname &, const DirEntry &> , "Invoke detection broken" );
566 static_assert( !std::is_invocable_v< function<bool(const Pathname &, const DirEntry& )>, const Pathname &, const char *> , "Invoke detection broken" );
567
568 if constexpr ( std::is_invocable_v<F, const Pathname &, const char *const> ) {
569 if ( ! std::forward<F>(fnc_r)( dir_r, entry->d_name ) ) {
570 ret = -1;
571 break;
572 }
573 } else if constexpr ( std::is_invocable_v<F, const Pathname &, const DirEntry&> ) {
574 if ( ! std::forward<F>(fnc_r)( dir_r, DirEntry( entry ) ) ) {
575 ret = -1;
576 break;
577 }
578 } else {
579 static_assert( always_false<F>, "Callback not supported" );
580 }
581 }
582 return ret;
583 }
584
585 int dirForEach( const Pathname & dir_r, const function<bool(const Pathname &, const char *const)>& fnc_r )
586 {
587 if ( ! fnc_r )
588 return 0;
589
590 return dirForEachImpl( dir_r, fnc_r );
591 }
592
593
594 int dirForEachExt( const Pathname & dir_r, const function<bool(const Pathname &, const DirEntry &)> &fnc_r )
595 {
596 if ( ! fnc_r )
597 return 0;
598
599 return dirForEachImpl( dir_r, fnc_r );
600 }
601
603 // readdir
605
606 int readdir( std::list<std::string> & retlist_r, const Pathname & path_r, bool dots_r )
607 {
608 retlist_r.clear();
609 return dirForEach( path_r,
610 [&]( const Pathname & dir_r, const char *const name_r )->bool
611 {
612 if ( dots_r || name_r[0] != '.' )
613 retlist_r.push_back( name_r );
614 return true;
615 } );
616 }
617
618
619 int readdir( std::list<Pathname> & retlist_r, const Pathname & path_r, bool dots_r )
620 {
621 retlist_r.clear();
622 return dirForEach( path_r,
623 [&]( const Pathname & dir_r, const char *const name_r )->bool
624 {
625 if ( dots_r || name_r[0] != '.' )
626 retlist_r.push_back( dir_r/name_r );
627 return true;
628 } );
629 }
630
632 : name( str::asString( entry->d_name ) )
633 {
634 switch( entry->d_type ) {
635 case DT_BLK:
637 break;
638 case DT_CHR:
640 break;
641 case DT_DIR:
642 this->type = FileType::FT_DIR;
643 break;
644 case DT_FIFO:
645 this->type = FileType::FT_FIFO;
646 break;
647 case DT_LNK:
648 this->type = FileType::FT_LINK;
649 break;
650 case DT_REG:
651 this->type = FileType::FT_FILE;
652 break;
653 case DT_SOCK:
655 break;
656 case DT_UNKNOWN:
658 break;
659 }
660 }
661
662 bool DirEntry::operator==( const DirEntry &rhs ) const
663 {
664 // if one of the types is not known, use the name only
665 if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
666 return ( name == rhs.name );
667 return ((name == rhs.name ) && (type == rhs.type));
668 }
669
671 {
672 retlist_r.clear();
673 return dirForEach( path_r,
674 [&]( const Pathname & dir_r, const char *const name_r )->bool
675 {
676 if ( dots_r || name_r[0] != '.' )
677 retlist_r.push_back( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
678 return true;
679 } );
680 }
681
682 std::ostream & operator<<( std::ostream & str, const DirContent & obj )
683 { return dumpRange( str, obj.begin(), obj.end() ); }
684
686 // is_empty_dir
688
690 {
691 return dirForEach( path_r,
692 [&]( const Pathname & dir_r, const char *const name_r )->bool
693 { return false; } );
694 }
695
697 //
698 // METHOD NAME : unlink
699 // METHOD TYPE : int
700 //
701 int unlink( const Pathname & path )
702 {
703 MIL << "unlink " << path;
704 if ( ::unlink( path.asString().c_str() ) == -1 ) {
705 return logResult( errno );
706 }
707 return logResult( 0 );
708 }
709
711 namespace
712 {
713 int safe_rename( const Pathname & oldpath, const Pathname & newpath )
714 {
715 int ret = ::rename( oldpath.asString().c_str(), newpath.asString().c_str() );
716
717 // rename(2) can fail on OverlayFS. Fallback to using mv(1), which is
718 // explicitly mentioned in the kernel docs to deal correctly with OverlayFS.
719 if ( ret == -1 && errno == EXDEV ) {
720 const char *const argv[] = {
721 "/usr/bin/mv",
722 oldpath.asString().c_str(),
723 newpath.asString().c_str(),
724 NULL
725 };
726 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
727 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
728 MIL << " " << output;
729 }
730 ret = prog.close();
731 }
732
733 return ret;
734 }
735 } // namespace
737
739 //
740 // METHOD NAME : rename
741 // METHOD TYPE : int
742 //
743 int rename( const Pathname & oldpath, const Pathname & newpath )
744 {
745 MIL << "rename " << oldpath << " -> " << newpath;
746 if ( safe_rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
747 return logResult( errno );
748 }
749 return logResult( 0 );
750 }
751
753 //
754 // METHOD NAME : exchange
755 // METHOD TYPE : int
756 //
757 int exchange( const Pathname & lpath, const Pathname & rpath )
758 {
759 MIL << "exchange " << lpath << " <-> " << rpath;
760 if ( lpath.empty() || rpath.empty() )
761 return logResult( EINVAL );
762
765
766 if ( ! linfo.isExist() )
767 {
768 if ( ! rinfo.isExist() )
769 return logResult( 0 ); // both don't exist.
770
771 // just rename rpath -> lpath
772 int ret = assert_dir( lpath.dirname() );
773 if ( ret != 0 )
774 return logResult( ret );
775 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
776 return logResult( errno );
777 }
778 return logResult( 0 );
779 }
780
781 // HERE: lpath exists:
782 if ( ! rinfo.isExist() )
783 {
784 // just rename lpath -> rpath
785 int ret = assert_dir( rpath.dirname() );
786 if ( ret != 0 )
787 return logResult( ret );
788 if ( safe_rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
789 return logResult( errno );
790 }
791 return logResult( 0 );
792 }
793
794 // HERE: both exist
796 if ( ! tmpfile )
797 return logResult( errno );
798 Pathname tmp( tmpfile.path() );
799 ::unlink( tmp.c_str() );
800
801 if ( safe_rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
802 return logResult( errno );
803 }
804 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
805 safe_rename( tmp.c_str(), lpath.c_str() );
806 return logResult( errno );
807 }
808 if ( safe_rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
809 safe_rename( lpath.c_str(), rpath.c_str() );
810 safe_rename( tmp.c_str(), lpath.c_str() );
811 return logResult( errno );
812 }
813 return logResult( 0 );
814 }
815
817 //
818 // METHOD NAME : copy
819 // METHOD TYPE : int
820 //
821 int copy( const Pathname & file, const Pathname & dest )
822 {
823 MIL << "copy " << file << " -> " << dest << ' ';
824
825 PathInfo sp( file );
826 if ( !sp.isFile() ) {
827 return logResult( EINVAL );
828 }
829
830 PathInfo dp( dest );
831 if ( dp.isDir() ) {
832 return logResult( EISDIR );
833 }
834
835 const char *const argv[] = {
836 "/bin/cp",
837 "--remove-destination",
838 "--",
839 file.asString().c_str(),
840 dest.asString().c_str(),
841 NULL
842 };
844 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
845 MIL << " " << output;
846 }
847 int ret = prog.close();
848 return logResult( ret, "returned" );
849 }
850
852 //
853 // METHOD NAME : symlink
854 // METHOD TYPE : int
855 //
856 int symlink( const Pathname & oldpath, const Pathname & newpath )
857 {
858 MIL << "symlink " << newpath << " -> " << oldpath;
859 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
860 return logResult( errno );
861 }
862 return logResult( 0 );
863 }
864
866 //
867 // METHOD NAME : hardlink
868 // METHOD TYPE : int
869 //
870 int hardlink( const Pathname & oldpath, const Pathname & newpath )
871 {
872 MIL << "hardlink " << newpath << " -> " << oldpath;
873 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
874 return logResult( errno );
875 }
876 return logResult( 0 );
877 }
878
880 //
881 // METHOD NAME : hardlink
882 // METHOD TYPE : int
883 //
885 {
886 MIL << "hardlinkCopy " << oldpath << " -> " << newpath;
887
889 if ( pi.isLink() )
890 {
891 // dont hardlink symlinks!
892 MIL << " => copy" << endl;
893 return copy( oldpath, newpath );
894 }
895
896 pi.lstat( newpath );
897 if ( pi.isExist() )
898 {
899 int res = unlink( newpath );
900 if ( res != 0 )
901 return logResult( res );
902 }
903
904 // Here: no symlink, no newpath
905 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
906 {
907 switch ( errno )
908 {
909 case EPERM: // /proc/sys/fs/protected_hardlink in proc(5)
910 case EXDEV: // oldpath and newpath are not on the same mounted file system
911 MIL << " => copy" << endl;
912 return copy( oldpath, newpath );
913 break;
914 }
915 return logResult( errno );
916 }
917 return logResult( 0 );
918 }
919
921 //
922 // METHOD NAME : readlink
923 // METHOD TYPE : int
924 //
926 {
927 static const ssize_t bufsiz = 2047;
928 static char buf[bufsiz+1];
929 ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
930 if ( ret == -1 )
931 {
932 target_r = Pathname();
933 MIL << "readlink " << symlink_r;
934 return logResult( errno );
935 }
936 buf[ret] = '\0';
937 target_r = buf;
938 return 0;
939 }
940
942 //
943 // METHOD NAME : expandlink
944 // METHOD TYPE : Pathname
945 //
947 {
948 static const unsigned int level_limit = 256;
949 static unsigned int count;
950 Pathname path(path_r);
952
953 for (count = level_limit; info.isLink() && count; count--)
954 {
955 DBG << "following symlink " << path;
956 path = path.dirname() / readlink(path);
957 DBG << "->" << path << std::endl;
958 info = PathInfo(path, PathInfo::LSTAT);
959 }
960
961 // expand limit reached
962 if (count == 0)
963 {
964 ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
965 return Pathname();
966 }
967 // symlink
968 else if (count < level_limit)
969 {
970 // check for a broken link
971 if (PathInfo(path).isExist())
972 return path;
973 // broken link, return an empty path
974 else
975 {
976 ERR << path << " is broken (expanded from " << path_r << ")" << endl;
977 return Pathname();
978 }
979 }
980
981 // not a symlink, return the original pathname
982 DBG << "not a symlink" << endl;
983 return path;
984 }
985
987 //
988 // METHOD NAME : copy_file2dir
989 // METHOD TYPE : int
990 //
991 int copy_file2dir( const Pathname & file, const Pathname & dest )
992 {
993 MIL << "copy_file2dir " << file << " -> " << dest << ' ';
994
995 PathInfo sp( file );
996 if ( !sp.isFile() ) {
997 return logResult( EINVAL );
998 }
999
1000 PathInfo dp( dest );
1001 if ( !dp.isDir() ) {
1002 return logResult( ENOTDIR );
1003 }
1004
1005 const char *const argv[] = {
1006 "/bin/cp",
1007 "--",
1008 file.asString().c_str(),
1009 dest.asString().c_str(),
1010 NULL
1011 };
1013 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1014 MIL << " " << output;
1015 }
1016 int ret = prog.close();
1017 return logResult( ret, "returned" );
1018 }
1019
1021 //
1022 // METHOD NAME : md5sum
1023 // METHOD TYPE : std::string
1024 //
1025 std::string md5sum( const Pathname & file )
1026 {
1027 if ( ! PathInfo( file ).isFile() ) {
1028 return string();
1029 }
1030 std::ifstream istr( file.asString().c_str() );
1031 if ( ! istr ) {
1032 return string();
1033 }
1034 return Digest::digest( "MD5", istr );
1035 }
1036
1038 //
1039 // METHOD NAME : sha1sum
1040 // METHOD TYPE : std::string
1041 //
1042 std::string sha1sum( const Pathname & file )
1043 {
1044 return checksum(file, "SHA1");
1045 }
1046
1048 //
1049 // METHOD NAME : checksum
1050 // METHOD TYPE : std::string
1051 //
1052 std::string checksum( const Pathname & file, const std::string &algorithm )
1053 {
1054 if ( ! PathInfo( file ).isFile() ) {
1055 return string();
1056 }
1057 std::ifstream istr( file.asString().c_str() );
1058 if ( ! istr ) {
1059 return string();
1060 }
1061 return Digest::digest( algorithm, istr );
1062 }
1063
1064 bool is_checksum( const Pathname & file, const CheckSum &checksum )
1065 {
1066 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
1067 }
1068
1070 //
1071 // METHOD NAME : erase
1072 // METHOD TYPE : int
1073 //
1074 int erase( const Pathname & path )
1075 {
1076 int res = 0;
1077 PathInfo p( path, PathInfo::LSTAT );
1078 if ( p.isExist() )
1079 {
1080 if ( p.isDir() )
1081 res = recursive_rmdir( path );
1082 else
1083 res = unlink( path );
1084 }
1085 return res;
1086 }
1087
1089 //
1090 // METHOD NAME : chmod
1091 // METHOD TYPE : int
1092 //
1093 int chmod( const Pathname & path, mode_t mode )
1094 {
1095 MIL << "chmod " << path << ' ' << str::octstring( mode );
1096 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
1097 return logResult( errno );
1098 }
1099 return logResult( 0 );
1100 }
1101
1102 int chmodApplyUmask( const Pathname & path, mode_t mode )
1103 { return chmod( path, applyUmaskTo( mode ) ); }
1104
1105 int addmod( const Pathname & path, mode_t mode )
1106 {
1107 mode_t omode( PathInfo( path ).st_mode() );
1108 mode_t tmode( omode | mode );
1109 if ( omode != mode )
1110 return chmod( path, tmode );
1111 return 0;
1112 }
1113
1114 int delmod( const Pathname & path, mode_t mode )
1115 {
1116 mode_t omode( PathInfo( path ).st_mode() );
1117 mode_t tmode( omode & ~mode );
1118 if ( omode != mode )
1119 return chmod( path, tmode );
1120 return 0;
1121 }
1122
1124 //
1125 // METHOD NAME : zipType
1126 // METHOD TYPE : ZIP_TYPE
1127 //
1128 ZIP_TYPE zipType( const Pathname & file )
1129 {
1131
1132 int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
1133
1134 if ( fd != -1 ) {
1135 const int magicSize = 5;
1136 unsigned char magic[magicSize];
1137 memset( magic, 0, magicSize );
1138 if ( read( fd, magic, magicSize ) == magicSize ) {
1139 if ( magic[0] == 0037 && magic[1] == 0213 ) {
1140 ret = ZT_GZ;
1141 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
1142 ret = ZT_BZ2;
1143 } else if ( magic[0] == '\0' && magic[1] == 'Z' && magic[2] == 'C' && magic[3] == 'K' && magic[4] == '1') {
1144 ret = ZT_ZCHNK;
1145
1146 }
1147 }
1148 close( fd );
1149 }
1150
1151 return ret;
1152 }
1153
1155 //
1156 // METHOD NAME : df
1157 // METHOD TYPE : ByteCount
1158 //
1160 {
1161 ByteCount ret( -1 );
1162 struct statvfs sb;
1163 if ( statvfs( path_r.c_str(), &sb ) == 0 )
1164 {
1165 ret = sb.f_bfree * sb.f_bsize;
1166 }
1167 return ret;
1168 }
1169
1171 //
1172 // METHOD NAME : getUmask
1173 // METHOD TYPE : mode_t
1174 //
1175 mode_t getUmask()
1176 {
1177 mode_t mask = ::umask( 0022 );
1178 ::umask( mask );
1179 return mask;
1180 }
1181
1183 //
1184 // METHOD NAME : getUmask
1185 // METHOD TYPE : mode_t
1186 //
1187 int assert_file( const Pathname & path, unsigned mode )
1188 {
1189 int ret = assert_dir( path.dirname() );
1190 MIL << "assert_file " << str::octstring( mode ) << " " << path;
1191 if ( ret != 0 )
1192 return logResult( ret );
1193
1194 PathInfo pi( path );
1195 if ( pi.isExist() )
1196 return logResult( pi.isFile() ? 0 : EEXIST );
1197
1198 int fd = ::creat( path.c_str(), mode );
1199 if ( fd == -1 )
1200 return logResult( errno );
1201
1202 ::close( fd );
1203 return logResult( 0 );
1204 }
1205
1206 int assert_file_mode( const Pathname & path, unsigned mode )
1207 {
1208 int ret = assert_dir( path.dirname() );
1209 MIL << "assert_file_mode " << str::octstring( mode ) << " " << path;
1210 if ( ret != 0 )
1211 return logResult( ret );
1212
1213 PathInfo pi( path );
1214 if ( pi.isExist() )
1215 {
1216 if ( ! pi.isFile() )
1217 return logResult( EEXIST );
1218
1219 mode = applyUmaskTo( mode );
1220 if ( pi.st_mode() != mode )
1221 return chmod( path, mode );
1222
1223 return logResult( 0 );
1224 }
1225
1226 int fd = ::creat( path.c_str(), mode );
1227 if ( fd == -1 )
1228 return logResult( errno );
1229 ::close( fd );
1230 return logResult( 0 );
1231 }
1232
1234 //
1235 // METHOD NAME : touch
1236 // METHOD TYPE : int
1237 //
1238 int touch (const Pathname & path)
1239 {
1240 MIL << "touch " << path;
1241 struct ::utimbuf times;
1242 times.actime = ::time( 0 );
1243 times.modtime = ::time( 0 );
1244 if ( ::utime( path.asString().c_str(), &times ) == -1 ) {
1245 return logResult( errno );
1246 }
1247 return logResult( 0 );
1248 }
1249
1251 } // namespace filesystem
1254} // namespace zypp
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
Store and operate with byte count.
Definition ByteCount.h:31
std::string digest()
get hex string representation of the digest
Definition Digest.cc:238
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 ...
Wrapper class for stat/lstat.
Definition PathInfo.h:222
StatMode asStatMode() const
Return st_mode() as filesystem::StatMode.
Definition PathInfo.h:331
bool stat()
STAT current path.
Definition PathInfo.h:270
bool operator()()
Restat current path using current mode.
Definition PathInfo.cc:189
Mode
stat() or lstat()
Definition PathInfo.h:227
unsigned int devMinor() const
Definition PathInfo.cc:252
FileType fileType() const
Definition PathInfo.cc:213
bool lstat()
LSTAT current path.
Definition PathInfo.h:272
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:282
unsigned int devMajor() const
Definition PathInfo.cc:242
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
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:82
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:220
Definition Arch.h:364
String related utilities and Regular expression matching.
int chmod(const Pathname &path, mode_t mode)
Like 'chmod'.
Definition PathInfo.cc:1093
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:1052
int delmod(const Pathname &path, mode_t mode)
Remove the mode bits from the file given by path.
Definition PathInfo.cc:1114
int dirForEachImpl(const Pathname &dir_r, F &&fnc_r)
Definition PathInfo.cc:548
static int recursive_rmdir_1(const Pathname &dir, bool removeDir=true)
Definition PathInfo.cc:381
FileType
File type information.
Definition PathInfo.h:57
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:946
int is_empty_dir(const Pathname &path_r)
Check if the specified directory is empty.
Definition PathInfo.cc:689
mode_t applyUmaskTo(mode_t mode_r)
Modify mode_r according to the current umask ( mode_r & ~getUmask() ).
Definition PathInfo.h:797
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition PathInfo.cc:606
ByteCount df(const Pathname &path_r)
Report free disk space on a mounted file system.
Definition PathInfo.cc:1159
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:701
std::list< DirEntry > DirContent
Returned by readdir.
Definition PathInfo.h:519
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition PathInfo.cc:743
int mkdir(const Pathname &path, unsigned mode)
Like 'mkdir'.
Definition PathInfo.cc:306
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:1064
int assert_file(const Pathname &path, unsigned mode)
Create an empty file if it does not yet exist.
Definition PathInfo.cc:1187
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 dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition PathInfo.cc:32
int erase(const Pathname &path)
Erase whatever happens to be located at path (file or directory).
Definition PathInfo.cc:1074
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition PathInfo.cc:1105
int hardlink(const Pathname &oldpath, const Pathname &newpath)
Like '::link'.
Definition PathInfo.cc:870
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
Definition PathInfo.cc:925
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:991
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition PathInfo.cc:1206
mode_t getUmask()
Get the current umask (file mode creation mask)
Definition PathInfo.cc:1175
int touch(const Pathname &path)
Change file's modification and access times.
Definition PathInfo.cc:1238
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition PathInfo.cc:884
constexpr bool always_false
Definition PathInfo.cc:545
std::string md5sum(const Pathname &file)
Compute a files md5sum.
Definition PathInfo.cc:1025
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
Definition PathInfo.cc:757
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition PathInfo.cc:594
std::string sha1sum(const Pathname &file)
Compute a files sha1sum.
Definition PathInfo.cc:1042
ZIP_TYPE zipType(const Pathname &file)
Definition PathInfo.cc:1128
int copy(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition PathInfo.cc:821
ZIP_TYPE
Test whether a file is compressed (gzip/bzip2).
Definition PathInfo.h:762
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like 'symlink'.
Definition PathInfo.cc:856
int chmodApplyUmask(const Pathname &path, mode_t mode)
Similar to 'chmod', but mode is modified by the process's umask in the usual way.
Definition PathInfo.cc:1102
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:36
std::string octstring(char n, int w=4)
Definition String.h:348
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition String.cc:54
Easy-to use interface to the ZYPP dependency resolver.
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:119
Listentry returned by readdir.
Definition PathInfo.h:502
bool operator==(const DirEntry &rhs) const
Definition PathInfo.cc:662
DirEntry(std::string name_r=std::string(), FileType type_r=FT_NOT_AVAIL)
Definition PathInfo.h:505
#define DBG
Definition Logger.h:95
#define MIL
Definition Logger.h:96
#define ERR
Definition Logger.h:98
#define WAR
Definition Logger.h:97
#define EMUMOUT(T)
#define logResult
Definition PathInfo.cc:285