libzypp 17.37.17
PathInfo.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12
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 {
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 //
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 {
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( ... ) doLogResult( __FUNCTION__, __LINE__, __VA_ARGS__ )
286 namespace {
288 inline int doLogResult( const char *function, const int line, const int res, const char * rclass = 0 /*errno*/ )
289 {
290 // calling code has started a logline via: `MIL << "Some text";` but did not flush it via endl yet.
291 // we need to do this here but pass the actual function and line to getStream, because the last call to it before
292 // flushing is setting the logging location ( function/line ).
294 if ( res )
295 {
296 if ( rclass )
297 WAR << " FAILED: " << rclass << " " << res << endl;
298 else
299 WAR << " FAILED: " << str::strerror( res ) << endl;
300 }
301 return res;
302 }
303 } // namespace
304
306 //
307 // METHOD NAME : PathInfo::mkdir
308 // METHOD TYPE : int
309 //
310 int mkdir( const Pathname & path, unsigned mode )
311 {
312 MIL << "mkdir " << path << ' ' << str::octstring( mode );
313 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
314 return logResult( errno );
315 }
316 return logResult( 0 );
317 }
318
320 //
321 // METHOD NAME : assert_dir()
322 // METHOD TYPE : int
323 //
324 int assert_dir( const Pathname & path, unsigned mode )
325 {
326 if ( path.empty() )
327 return ENOENT;
328
329 { // Handle existing paths in advance.
330 PathInfo pi( path );
331 if ( pi.isDir() )
332 return 0;
333 if ( pi.isExist() )
334 return EEXIST;
335 }
336
337 string spath = path.asString()+"/";
338 std::string::size_type lastpos = ( path.relative() ? 2 : 1 ); // skip leasding './' or '/'
339 std::string::size_type pos = std::string::npos;
340 int ret = 0;
341
342 while ( (pos = spath.find('/',lastpos)) != std::string::npos )
343 {
344 string dir( spath.substr(0,pos) );
345 ret = ::mkdir( dir.c_str(), mode );
346 if ( ret == -1 )
347 {
348 if ( errno == EEXIST ) // ignore errors about already existing paths
349 ret = 0;
350 else
351 {
352 ret = errno;
353 WAR << " FAILED: mkdir " << dir << ' ' << str::octstring( mode ) << " errno " << ret << endl;
354 }
355 }
356 else
357 {
358 MIL << "mkdir " << dir << ' ' << str::octstring( mode ) << endl;
359 }
360 lastpos = pos+1;
361 }
362
363 return ret;
364 }
365
367 //
368 // METHOD NAME : rmdir
369 // METHOD TYPE : int
370 //
371 int rmdir( const Pathname & path )
372 {
373 MIL << "rmdir " << path;
374 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
375 return logResult( errno );
376 }
377 return logResult( 0 );
378 }
379
381 //
382 // METHOD NAME : recursive_rmdir
383 // METHOD TYPE : int
384 //
385 static int recursive_rmdir_1( const Pathname & dir, bool removeDir = true )
386 {
387 DIR * dp = nullptr;
388 struct dirent * d = nullptr;
389
390 if ( ! (dp = opendir( dir.c_str() )) )
391 return logResult( errno );
392
393 while ( (d = readdir(dp)) )
394 {
395 std::string direntry = d->d_name;
396 if ( direntry == "." || direntry == ".." )
397 continue;
398 Pathname new_path( dir / d->d_name );
399
400 struct stat st;
401 if ( ! lstat( new_path.c_str(), &st ) )
402 {
403 if ( S_ISDIR( st.st_mode ) )
404 recursive_rmdir_1( new_path );
405 else
406 ::unlink( new_path.c_str() );
407 }
408 }
409 closedir( dp );
410
411 if ( removeDir && ::rmdir( dir.c_str() ) < 0 )
412 return errno;
413
414 return 0;
415 }
416
417 int recursive_rmdir( const Pathname & path )
418 {
419 MIL << "recursive_rmdir " << path << ' ';
420 PathInfo p( path );
421
422 if ( !p.isExist() ) {
423 return logResult( 0 );
424 }
425
426 if ( !p.isDir() ) {
427 return logResult( ENOTDIR );
428 }
429
430 p.lstat(); // get dir symlinks
431 if ( !p.isDir() ) {
432 MIL << "unlink symlink ";
433 if ( ::unlink( path.asString().c_str() ) == -1 ) {
434 return logResult( errno );
435 }
436 return logResult( 0 );
437 }
438
439 return logResult( recursive_rmdir_1( path ) );
440 }
441
443 //
444 // METHOD NAME : clean_dir
445 // METHOD TYPE : int
446 //
447 int clean_dir( const Pathname & path )
448 {
449 MIL << "clean_dir " << path << ' ';
450 PathInfo p( path );
451
452 if ( !p.isExist() ) {
453 return logResult( 0 );
454 }
455
456 if ( !p.isDir() ) {
457 return logResult( ENOTDIR );
458 }
459
460 return logResult( recursive_rmdir_1( path, false/* don't remove path itself */ ) );
461 }
462
464 //
465 // METHOD NAME : copy_dir
466 // METHOD TYPE : int
467 //
468 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
469 {
470 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
471
472 PathInfo sp( srcpath );
473 if ( !sp.isDir() ) {
474 return logResult( ENOTDIR );
475 }
476
477 PathInfo dp( destpath );
478 if ( !dp.isDir() ) {
479 return logResult( ENOTDIR );
480 }
481
482 PathInfo tp( destpath + srcpath.basename() );
483 if ( tp.isExist() ) {
484 return logResult( EEXIST );
485 }
486
487
488 const char *const argv[] = {
489 "/bin/cp",
490 "-dR",
491 "--",
492 srcpath.asString().c_str(),
493 destpath.asString().c_str(),
494 NULL
495 };
497 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
498 MIL << " " << output;
499 }
500 int ret = prog.close();
501 return logResult( ret, "returned" );
502 }
503
505 //
506 // METHOD NAME : copy_dir_content
507 // METHOD TYPE : int
508 //
509 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
510 {
511 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
512
513 PathInfo sp( srcpath );
514 if ( !sp.isDir() ) {
515 return logResult( ENOTDIR );
516 }
517
518 PathInfo dp( destpath );
519 if ( !dp.isDir() ) {
520 return logResult( ENOTDIR );
521 }
522
523 if ( srcpath == destpath ) {
524 return logResult( EEXIST );
525 }
526
527 std::string src( srcpath.asString());
528 src += "/.";
529 const char *const argv[] = {
530 "/bin/cp",
531 "-dR",
532 "--",
533 src.c_str(),
534 destpath.asString().c_str(),
535 NULL
536 };
538 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
539 MIL << " " << output;
540 }
541 int ret = prog.close();
542 return logResult( ret, "returned" );
543 }
544
546 // dirForEachImpl
548 template <class... T>
549 constexpr bool always_false = false;
550
551 template <typename F>
552 int dirForEachImpl ( const Pathname & dir_r, F &&fnc_r )
553 {
554 AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ),
555 []( DIR * dir_r ) { if ( dir_r ) ::closedir( dir_r ); } );
556
557 MIL << "readdir " << dir_r << ' ';
558 if ( ! dir )
559 return logResult( errno );
560 MIL << endl; // close line before callbacks are invoked.
561
562 int ret = 0;
563 for ( struct dirent * entry = ::readdir( dir ); entry; entry = ::readdir( dir ) )
564 {
565 if ( entry->d_name[0] == '.' && ( entry->d_name[1] == '\0' || ( entry->d_name[1] == '.' && entry->d_name[2] == '\0' ) ) )
566 continue; // omitt . and ..
567
568 // some static checks to make sure the correct func is selected
569 static_assert( !std::is_invocable_v< function<bool(const Pathname &, const char *const)>, const Pathname &, const DirEntry &> , "Invoke detection broken" );
570 static_assert( !std::is_invocable_v< function<bool(const Pathname &, const DirEntry& )>, const Pathname &, const char *> , "Invoke detection broken" );
571
572 if constexpr ( std::is_invocable_v<F, const Pathname &, const char *const> ) {
573 if ( ! std::forward<F>(fnc_r)( dir_r, entry->d_name ) ) {
574 ret = -1;
575 break;
576 }
577 } else if constexpr ( std::is_invocable_v<F, const Pathname &, const DirEntry&> ) {
578 if ( ! std::forward<F>(fnc_r)( dir_r, DirEntry( entry ) ) ) {
579 ret = -1;
580 break;
581 }
582 } else {
583 static_assert( always_false<F>, "Callback not supported" );
584 }
585 }
586 return ret;
587 }
588
589 int dirForEach( const Pathname & dir_r, const function<bool(const Pathname &, const char *const)>& fnc_r )
590 {
591 if ( ! fnc_r )
592 return 0;
593
594 return dirForEachImpl( dir_r, fnc_r );
595 }
596
597
598 int dirForEachExt( const Pathname & dir_r, const function<bool(const Pathname &, const DirEntry &)> &fnc_r )
599 {
600 if ( ! fnc_r )
601 return 0;
602
603 return dirForEachImpl( dir_r, fnc_r );
604 }
605
607 // readdir
609
610 int readdir( std::list<std::string> & retlist_r, const Pathname & path_r, bool dots_r )
611 {
612 retlist_r.clear();
613 return dirForEach( path_r,
614 [&]( const Pathname & dir_r, const char *const name_r )->bool
615 {
616 if ( dots_r || name_r[0] != '.' )
617 retlist_r.push_back( name_r );
618 return true;
619 } );
620 }
621
622
623 int readdir( std::list<Pathname> & retlist_r, const Pathname & path_r, bool dots_r )
624 {
625 retlist_r.clear();
626 return dirForEach( path_r,
627 [&]( const Pathname & dir_r, const char *const name_r )->bool
628 {
629 if ( dots_r || name_r[0] != '.' )
630 retlist_r.push_back( dir_r/name_r );
631 return true;
632 } );
633 }
634
635 DirEntry::DirEntry( struct dirent* entry )
636 : name( str::asString( entry->d_name ) )
637 {
638 switch( entry->d_type ) {
639 case DT_BLK:
640 this->type = FileType::FT_BLOCKDEV;
641 break;
642 case DT_CHR:
643 this->type = FileType::FT_CHARDEV;
644 break;
645 case DT_DIR:
646 this->type = FileType::FT_DIR;
647 break;
648 case DT_FIFO:
649 this->type = FileType::FT_FIFO;
650 break;
651 case DT_LNK:
652 this->type = FileType::FT_LINK;
653 break;
654 case DT_REG:
655 this->type = FileType::FT_FILE;
656 break;
657 case DT_SOCK:
658 this->type = FileType::FT_SOCKET;
659 break;
660 case DT_UNKNOWN:
661 this->type = FileType::FT_NOT_AVAIL;
662 break;
663 }
664 }
665
666 bool DirEntry::operator==( const DirEntry &rhs ) const
667 {
668 // if one of the types is not known, use the name only
669 if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
670 return ( name == rhs.name );
671 return ((name == rhs.name ) && (type == rhs.type));
672 }
673
674 int readdir( DirContent & retlist_r, const Pathname & path_r, bool dots_r, PathInfo::Mode statmode_r )
675 {
676 retlist_r.clear();
677 return dirForEach( path_r,
678 [&]( const Pathname & dir_r, const char *const name_r )->bool
679 {
680 if ( dots_r || name_r[0] != '.' )
681 retlist_r.push_back( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
682 return true;
683 } );
684 }
685
686 std::ostream & operator<<( std::ostream & str, const DirContent & obj )
687 { return dumpRange( str, obj.begin(), obj.end() ); }
688
690 // is_empty_dir
692
693 int is_empty_dir( const Pathname & path_r )
694 {
695 return dirForEach( path_r,
696 [&]( const Pathname & dir_r, const char *const name_r )->bool
697 { return false; } );
698 }
699
701 //
702 // METHOD NAME : unlink
703 // METHOD TYPE : int
704 //
705 int unlink( const Pathname & path )
706 {
707 MIL << "unlink " << path;
708 if ( ::unlink( path.asString().c_str() ) == -1 ) {
709 return logResult( errno );
710 }
711 return logResult( 0 );
712 }
713
715 namespace
716 {
717 int safe_rename( const Pathname & oldpath, const Pathname & newpath )
718 {
719 int ret = ::rename( oldpath.asString().c_str(), newpath.asString().c_str() );
720
721 // rename(2) can fail on OverlayFS. Fallback to using mv(1), which is
722 // explicitly mentioned in the kernel docs to deal correctly with OverlayFS.
723 if ( ret == -1 && errno == EXDEV ) {
724 const char *const argv[] = {
725 "/usr/bin/mv",
726 oldpath.asString().c_str(),
727 newpath.asString().c_str(),
728 NULL
729 };
730 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
731 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
732 MIL << " " << output;
733 }
734 ret = prog.close();
735 }
736
737 return ret;
738 }
739 } // namespace
741
743 //
744 // METHOD NAME : rename
745 // METHOD TYPE : int
746 //
747 int rename( const Pathname & oldpath, const Pathname & newpath )
748 {
749 MIL << "rename " << oldpath << " -> " << newpath;
750 if ( safe_rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
751 return logResult( errno );
752 }
753 return logResult( 0 );
754 }
755
757 //
758 // METHOD NAME : exchange
759 // METHOD TYPE : int
760 //
761 int exchange( const Pathname & lpath, const Pathname & rpath )
762 {
763 MIL << "exchange " << lpath << " <-> " << rpath;
764 if ( lpath.empty() || rpath.empty() )
765 return logResult( EINVAL );
766
767 PathInfo linfo( lpath );
768 PathInfo rinfo( rpath );
769
770 if ( ! linfo.isExist() )
771 {
772 if ( ! rinfo.isExist() )
773 return logResult( 0 ); // both don't exist.
774
775 // just rename rpath -> lpath
776 int ret = assert_dir( lpath.dirname() );
777 if ( ret != 0 )
778 return logResult( ret );
779 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
780 return logResult( errno );
781 }
782 return logResult( 0 );
783 }
784
785 // HERE: lpath exists:
786 if ( ! rinfo.isExist() )
787 {
788 // just rename lpath -> rpath
789 int ret = assert_dir( rpath.dirname() );
790 if ( ret != 0 )
791 return logResult( ret );
792 if ( safe_rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
793 return logResult( errno );
794 }
795 return logResult( 0 );
796 }
797
798 // HERE: both exist
799 TmpFile tmpfile( TmpFile::makeSibling( rpath ) );
800 if ( ! tmpfile )
801 return logResult( errno );
802 Pathname tmp( tmpfile.path() );
803 ::unlink( tmp.c_str() );
804
805 if ( safe_rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
806 return logResult( errno );
807 }
808 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
809 safe_rename( tmp.c_str(), lpath.c_str() );
810 return logResult( errno );
811 }
812 if ( safe_rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
813 safe_rename( lpath.c_str(), rpath.c_str() );
814 safe_rename( tmp.c_str(), lpath.c_str() );
815 return logResult( errno );
816 }
817 return logResult( 0 );
818 }
819
821 //
822 // METHOD NAME : copy
823 // METHOD TYPE : int
824 //
825 int copy( const Pathname & file, const Pathname & dest )
826 {
827 MIL << "copy " << file << " -> " << dest << ' ';
828
829 PathInfo sp( file );
830 if ( !sp.isFile() ) {
831 return logResult( EINVAL );
832 }
833
834 PathInfo dp( dest );
835 if ( dp.isDir() ) {
836 return logResult( EISDIR );
837 }
838
839 const char *const argv[] = {
840 "/bin/cp",
841 "--remove-destination",
842 "--",
843 file.asString().c_str(),
844 dest.asString().c_str(),
845 NULL
846 };
848 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
849 MIL << " " << output;
850 }
851 int ret = prog.close();
852 return logResult( ret, "returned" );
853 }
854
856 //
857 // METHOD NAME : symlink
858 // METHOD TYPE : int
859 //
860 int symlink( const Pathname & oldpath, const Pathname & newpath )
861 {
862 MIL << "symlink " << newpath << " -> " << oldpath;
863 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
864 return logResult( errno );
865 }
866 return logResult( 0 );
867 }
868
870 //
871 // METHOD NAME : hardlink
872 // METHOD TYPE : int
873 //
874 int hardlink( const Pathname & oldpath, const Pathname & newpath )
875 {
876 MIL << "hardlink " << newpath << " -> " << oldpath;
877 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
878 return logResult( errno );
879 }
880 return logResult( 0 );
881 }
882
884 //
885 // METHOD NAME : hardlink
886 // METHOD TYPE : int
887 //
888 int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath )
889 {
890 MIL << "hardlinkCopy " << oldpath << " -> " << newpath;
891
892 PathInfo pi( oldpath, PathInfo::LSTAT );
893 if ( pi.isLink() )
894 {
895 // dont hardlink symlinks!
896 MIL << " => copy" << endl;
897 return copy( oldpath, newpath );
898 }
899
900 pi.lstat( newpath );
901 if ( pi.isExist() )
902 {
903 int res = unlink( newpath );
904 if ( res != 0 )
905 return logResult( res );
906 }
907
908 // Here: no symlink, no newpath
909 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
910 {
911 switch ( errno )
912 {
913 case EPERM: // /proc/sys/fs/protected_hardlink in proc(5)
914 case EXDEV: // oldpath and newpath are not on the same mounted file system
915 MIL << " => copy" << endl;
916 return copy( oldpath, newpath );
917 break;
918 }
919 return logResult( errno );
920 }
921 return logResult( 0 );
922 }
923
925 //
926 // METHOD NAME : readlink
927 // METHOD TYPE : int
928 //
929 int readlink( const Pathname & symlink_r, Pathname & target_r )
930 {
931 static const ssize_t bufsiz = 2047;
932 static char buf[bufsiz+1];
933 ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
934 if ( ret == -1 )
935 {
936 target_r = Pathname();
937 MIL << "readlink " << symlink_r;
938 return logResult( errno );
939 }
940 buf[ret] = '\0';
941 target_r = buf;
942 return 0;
943 }
944
946 //
947 // METHOD NAME : expandlink
948 // METHOD TYPE : Pathname
949 //
950 Pathname expandlink( const Pathname & path_r )
951 {
952 static const unsigned int level_limit = 256;
953 static unsigned int count;
954 Pathname path(path_r);
955 PathInfo info(path_r, PathInfo::LSTAT);
956
957 for (count = level_limit; info.isLink() && count; count--)
958 {
959 DBG << "following symlink " << path;
960 path = path.dirname() / readlink(path);
961 DBG << "->" << path << std::endl;
962 info = PathInfo(path, PathInfo::LSTAT);
963 }
964
965 // expand limit reached
966 if (count == 0)
967 {
968 ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
969 return Pathname();
970 }
971 // symlink
972 else if (count < level_limit)
973 {
974 // check for a broken link
975 if (PathInfo(path).isExist())
976 return path;
977 // broken link, return an empty path
978 else
979 {
980 ERR << path << " is broken (expanded from " << path_r << ")" << endl;
981 return Pathname();
982 }
983 }
984
985 // not a symlink, return the original pathname
986 DBG << "not a symlink" << endl;
987 return path;
988 }
989
991 //
992 // METHOD NAME : copy_file2dir
993 // METHOD TYPE : int
994 //
995 int copy_file2dir( const Pathname & file, const Pathname & dest )
996 {
997 MIL << "copy_file2dir " << file << " -> " << dest << ' ';
998
999 PathInfo sp( file );
1000 if ( !sp.isFile() ) {
1001 return logResult( EINVAL );
1002 }
1003
1004 PathInfo dp( dest );
1005 if ( !dp.isDir() ) {
1006 return logResult( ENOTDIR );
1007 }
1008
1009 const char *const argv[] = {
1010 "/bin/cp",
1011 "--",
1012 file.asString().c_str(),
1013 dest.asString().c_str(),
1014 NULL
1015 };
1017 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1018 MIL << " " << output;
1019 }
1020 int ret = prog.close();
1021 return logResult( ret, "returned" );
1022 }
1023
1025 //
1026 // METHOD NAME : md5sum
1027 // METHOD TYPE : std::string
1028 //
1029 std::string md5sum( const Pathname & file )
1030 {
1031 if ( ! PathInfo( file ).isFile() ) {
1032 return string();
1033 }
1034 std::ifstream istr( file.asString().c_str() );
1035 if ( ! istr ) {
1036 return string();
1037 }
1038 return Digest::digest( "MD5", istr );
1039 }
1040
1042 //
1043 // METHOD NAME : sha1sum
1044 // METHOD TYPE : std::string
1045 //
1046 std::string sha1sum( const Pathname & file )
1047 {
1048 return checksum(file, "SHA1");
1049 }
1050
1052 //
1053 // METHOD NAME : checksum
1054 // METHOD TYPE : std::string
1055 //
1056 std::string checksum( const Pathname & file, const std::string &algorithm )
1057 {
1058 if ( ! PathInfo( file ).isFile() ) {
1059 return string();
1060 }
1061 std::ifstream istr( file.asString().c_str() );
1062 if ( ! istr ) {
1063 return string();
1064 }
1065 return Digest::digest( algorithm, istr );
1066 }
1067
1068 bool is_checksum( const Pathname & file, const CheckSum &checksum )
1069 {
1070 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
1071 }
1072
1074 //
1075 // METHOD NAME : erase
1076 // METHOD TYPE : int
1077 //
1078 int erase( const Pathname & path )
1079 {
1080 int res = 0;
1081 PathInfo p( path, PathInfo::LSTAT );
1082 if ( p.isExist() )
1083 {
1084 if ( p.isDir() )
1085 res = recursive_rmdir( path );
1086 else
1087 res = unlink( path );
1088 }
1089 return res;
1090 }
1091
1093 //
1094 // METHOD NAME : chmod
1095 // METHOD TYPE : int
1096 //
1097 int chmod( const Pathname & path, mode_t mode )
1098 {
1099 MIL << "chmod " << path << ' ' << str::octstring( mode );
1100 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
1101 return logResult( errno );
1102 }
1103 return logResult( 0 );
1104 }
1105
1106 int chmodApplyUmask( const Pathname & path, mode_t mode )
1107 { return chmod( path, applyUmaskTo( mode ) ); }
1108
1109 int addmod( const Pathname & path, mode_t mode )
1110 {
1111 mode_t omode( PathInfo( path ).st_mode() );
1112 mode_t tmode( omode | mode );
1113 if ( omode != mode )
1114 return chmod( path, tmode );
1115 return 0;
1116 }
1117
1118 int delmod( const Pathname & path, mode_t mode )
1119 {
1120 mode_t omode( PathInfo( path ).st_mode() );
1121 mode_t tmode( omode & ~mode );
1122 if ( omode != mode )
1123 return chmod( path, tmode );
1124 return 0;
1125 }
1126
1128 //
1129 // METHOD NAME : zipType
1130 // METHOD TYPE : ZIP_TYPE
1131 //
1132 ZIP_TYPE zipType( const Pathname & file )
1133 {
1134 ZIP_TYPE ret = ZT_NONE;
1135
1136 int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
1137
1138 if ( fd != -1 ) {
1139 const int magicSize = 5;
1140 unsigned char magic[magicSize];
1141 memset( magic, 0, magicSize );
1142 if ( read( fd, magic, magicSize ) == magicSize ) {
1143 if ( magic[0] == 0037 && magic[1] == 0213 ) {
1144 ret = ZT_GZ;
1145 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
1146 ret = ZT_BZ2;
1147 } else if ( magic[0] == '\0' && magic[1] == 'Z' && magic[2] == 'C' && magic[3] == 'K' && magic[4] == '1') {
1148 ret = ZT_ZCHNK;
1149
1150 }
1151 }
1152 close( fd );
1153 }
1154
1155 return ret;
1156 }
1157
1159 //
1160 // METHOD NAME : df
1161 // METHOD TYPE : ByteCount
1162 //
1163 ByteCount df( const Pathname & path_r )
1164 {
1165 ByteCount ret( -1 );
1166 struct statvfs sb;
1167 if ( statvfs( path_r.c_str(), &sb ) == 0 )
1168 {
1169 ret = sb.f_bfree * sb.f_bsize;
1170 }
1171 return ret;
1172 }
1173
1175 //
1176 // METHOD NAME : getUmask
1177 // METHOD TYPE : mode_t
1178 //
1179 mode_t getUmask()
1180 {
1181 mode_t mask = ::umask( 0022 );
1182 ::umask( mask );
1183 return mask;
1184 }
1185
1187 //
1188 // METHOD NAME : getUmask
1189 // METHOD TYPE : mode_t
1190 //
1191 int assert_file( const Pathname & path, unsigned mode )
1192 {
1193 int ret = assert_dir( path.dirname() );
1194 MIL << "assert_file " << str::octstring( mode ) << " " << path;
1195 if ( ret != 0 )
1196 return logResult( ret );
1197
1198 PathInfo pi( path );
1199 if ( pi.isExist() )
1200 return logResult( pi.isFile() ? 0 : EEXIST );
1201
1202 int fd = ::creat( path.c_str(), mode );
1203 if ( fd == -1 )
1204 return logResult( errno );
1205
1206 ::close( fd );
1207 return logResult( 0 );
1208 }
1209
1210 int assert_file_mode( const Pathname & path, unsigned mode )
1211 {
1212 int ret = assert_dir( path.dirname() );
1213 MIL << "assert_file_mode " << str::octstring( mode ) << " " << path;
1214 if ( ret != 0 )
1215 return logResult( ret );
1216
1217 PathInfo pi( path );
1218 if ( pi.isExist() )
1219 {
1220 if ( ! pi.isFile() )
1221 return logResult( EEXIST );
1222
1223 mode = applyUmaskTo( mode );
1224 if ( pi.st_mode() != mode )
1225 return chmod( path, mode );
1226
1227 return logResult( 0 );
1228 }
1229
1230 int fd = ::creat( path.c_str(), mode );
1231 if ( fd == -1 )
1232 return logResult( errno );
1233 ::close( fd );
1234 return logResult( 0 );
1235 }
1236
1238 //
1239 // METHOD NAME : touch
1240 // METHOD TYPE : int
1241 //
1242 int touch (const Pathname & path)
1243 {
1244 MIL << "touch " << path;
1245 struct ::utimbuf times;
1246 times.actime = ::time( 0 );
1247 times.modtime = ::time( 0 );
1248 if ( ::utime( path.asString().c_str(), &times ) == -1 ) {
1249 return logResult( errno );
1250 }
1251 return logResult( 0 );
1252 }
1253
1255 } // namespace filesystem
1258} // namespace zypp
#define ZYPP_BASE_LOGGER_LOGGROUP
Definition Measure.cc:27
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:32
std::string digest()
get hex string representation of the digest
Definition Digest.cc:239
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() override
Wait for the progamm to complete.
std::string receiveLine()
Read one line from the input stream.
Wrapper class for stat/lstat.
Definition PathInfo.h:226
bool lstat(const Pathname &path)
LSTAT path.
Definition PathInfo.h:269
StatMode asStatMode() const
Return st_mode() as filesystem::StatMode.
Definition PathInfo.h:336
bool stat()
STAT current path.
Definition PathInfo.h:274
mode_t st_mode() const
Definition PathInfo.h:332
const Pathname & path() const
Return current Pathname.
Definition PathInfo.h:251
bool operator()()
Restat current path using current mode.
Definition PathInfo.cc:189
Mode
stat() or lstat()
Definition PathInfo.h:231
unsigned int devMinor() const
Definition PathInfo.cc:252
FileType fileType() const
Definition PathInfo.cc:213
bool lstat()
LSTAT current path.
Definition PathInfo.h:276
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:286
const std::string & asString() const
Return current Pathname as String.
Definition PathInfo.h:253
unsigned int devMajor() const
Definition PathInfo.cc:242
int error() const
Return error returned from last stat/lstat call.
Definition PathInfo.h:259
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:126
const char * c_str() const
String representation.
Definition Pathname.h:112
const std::string & asString() const
String representation.
Definition Pathname.h:93
std::string basename() const
Return the last component of this path.
Definition Pathname.h:130
bool empty() const
Test for an empty path.
Definition Pathname.h:116
bool relative() const
Test for a relative path.
Definition Pathname.h:120
FileType fileType() const
Definition PathInfo.cc:71
StatMode(const mode_t &mode_r=0)
Ctor taking mode_t value from stat.
Definition PathInfo.h:91
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:222
Pathname path() const
Definition TmpPath.cc:152
Definition Arch.h:364
String related utilities and Regular expression matching.
@ E_MIL
Milestone.
Definition Logger.h:159
std::ostream & getStream(const char *group_r, LogLevel level_r, const char *file_r, const char *func_r, const int line_r)
Return a log stream to write on.
Types and functions for filesystem operations.
Definition Glob.cc:24
int chmod(const Pathname &path, mode_t mode)
Like 'chmod'.
Definition PathInfo.cc:1097
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like 'symlink'.
Definition PathInfo.cc:860
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:1056
int delmod(const Pathname &path, mode_t mode)
Remove the mode bits from the file given by path.
Definition PathInfo.cc:1118
int dirForEachImpl(const Pathname &dir_r, F &&fnc_r)
Definition PathInfo.cc:552
int rmdir(const Pathname &path)
Like 'rmdir'.
Definition PathInfo.cc:371
int mkdir(const Pathname &path, unsigned mode)
Like 'mkdir'.
Definition PathInfo.cc:310
static int recursive_rmdir_1(const Pathname &dir, bool removeDir=true)
Definition PathInfo.cc:385
FileType
File type information.
Definition PathInfo.h:60
int assert_file(const Pathname &path, unsigned mode)
Create an empty file if it does not yet exist.
Definition PathInfo.cc:1191
int copy_dir(const Pathname &srcpath, const Pathname &destpath)
Like 'cp -a srcpath destpath'.
Definition PathInfo.cc:468
mode_t applyUmaskTo(mode_t mode_r)
Modify mode_r according to the current umask ( mode_r & ~getUmask() ).
Definition PathInfo.h:805
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition PathInfo.cc:417
ByteCount df(const Pathname &path_r)
Report free disk space on a mounted file system.
Definition PathInfo.cc:1163
std::list< DirEntry > DirContent
Returned by readdir.
Definition PathInfo.h:526
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition PathInfo.cc:888
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition PathInfo.cc:1210
int copy(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition PathInfo.cc:825
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
Definition PathInfo.cc:447
bool is_checksum(const Pathname &file, const CheckSum &checksum)
check files checksum
Definition PathInfo.cc:1068
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:950
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:705
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition PathInfo.cc:610
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:1078
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition PathInfo.cc:1109
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition PathInfo.cc:324
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
Definition PathInfo.cc:929
int copy_file2dir(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition PathInfo.cc:995
mode_t getUmask()
Get the current umask (file mode creation mask)
Definition PathInfo.cc:1179
int copy_dir_content(const Pathname &srcpath, const Pathname &destpath)
Like 'cp -a srcpath/.
Definition PathInfo.cc:509
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition PathInfo.cc:598
constexpr bool always_false
Definition PathInfo.cc:549
int is_empty_dir(const Pathname &path_r)
Check if the specified directory is empty.
Definition PathInfo.cc:693
std::string md5sum(const Pathname &file)
Compute a files md5sum.
Definition PathInfo.cc:1029
int hardlink(const Pathname &oldpath, const Pathname &newpath)
Like 'link'.
Definition PathInfo.cc:874
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
Definition PathInfo.cc:761
std::string sha1sum(const Pathname &file)
Compute a files sha1sum.
Definition PathInfo.cc:1046
ZIP_TYPE zipType(const Pathname &file)
Definition PathInfo.cc:1132
ZIP_TYPE
Test whether a file is compressed (gzip/bzip2).
Definition PathInfo.h:770
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition PathInfo.cc:747
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:1106
int touch(const Pathname &path)
Change file's modification and access times.
Definition PathInfo.cc:1242
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:419
std::string strerror(int errno_r)
Return string describing the error_r code.
Definition String.cc:56
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:120
std::string asString(const Patch::Category &obj)
Definition Patch.cc:122
Listentry returned by readdir.
Definition PathInfo.h:509
bool operator==(const DirEntry &rhs) const
Definition PathInfo.cc:666
DirEntry(std::string name_r=std::string(), FileType type_r=FT_NOT_AVAIL)
Definition PathInfo.h:512
#define L_BASEFILE
Definition Logger.h:133
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102
#define WAR
Definition Logger.h:101
#define EMUMOUT(T)
#define logResult(...)
Definition PathInfo.cc:285