libzypp 17.31.23
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-core/fs/PathInfo.h>
22#include <zypp-core/base/LogTools.h>
23#include <zypp-core/base/String.h>
24#include <zypp-core/base/IOStream.h>
25#include <zypp-core/base/Errno.h>
26
27#include <zypp-core/AutoDispose.h>
28#include <zypp-core/ExternalProgram.h>
29#include <zypp-core/Digest.h>
30#include <zypp-core/fs/TmpPath.h>
31
32using std::endl;
33using std::string;
34
36namespace zypp
37{
39 namespace filesystem
40 {
41
42 /******************************************************************
43 **
44 ** FUNCTION NAME : operator<<
45 ** FUNCTION TYPE : std::ostream &
46 */
47 std::ostream & operator<<( std::ostream & str, FileType obj )
48 {
49 switch ( obj ) {
50#define EMUMOUT(T) case T: return str << #T; break
54 EMUMOUT( FT_DIR );
60#undef EMUMOUT
61 }
62 return str;
63 }
64
66 //
67 // METHOD NAME : StatMode::fileType
68 // METHOD TYPE : FileType
69 //
71 {
72 if ( isFile() )
73 return FT_FILE;
74 if ( isDir() )
75 return FT_DIR;
76 if ( isLink() )
77 return FT_LINK;
78 if ( isChr() )
79 return FT_CHARDEV;
80 if ( isBlk() )
81 return FT_BLOCKDEV;
82 if ( isFifo() )
83 return FT_FIFO;
84 if ( isSock() )
85 return FT_SOCKET ;
86
87 return FT_NOT_AVAIL;
88 }
89
90 /******************************************************************
91 **
92 ** FUNCTION NAME : operator<<
93 ** FUNCTION TYPE : std::ostream &
94 */
95 std::ostream & operator<<( std::ostream & str, const StatMode & obj )
96 {
97 iostr::IosFmtFlagsSaver autoResoreState( str );
98
99 char t = '?';
100 if ( obj.isFile() )
101 t = '-';
102 else if ( obj.isDir() )
103 t = 'd';
104 else if ( obj.isLink() )
105 t = 'l';
106 else if ( obj.isChr() )
107 t = 'c';
108 else if ( obj.isBlk() )
109 t = 'b';
110 else if ( obj.isFifo() )
111 t = 'p';
112 else if ( obj.isSock() )
113 t = 's';
114
115 str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
116 return str;
117 }
118
120 //
121 // Class : PathInfo
122 //
124
126 //
127 // METHOD NAME : PathInfo::PathInfo
128 // METHOD TYPE : Constructor
129 //
131 : mode_e( STAT )
132 , error_i( -1 )
133 {}
134
136 //
137 // METHOD NAME : PathInfo::PathInfo
138 // METHOD TYPE : Constructor
139 //
140 PathInfo::PathInfo( const Pathname & path, Mode initial )
141 : path_t( path )
142 , mode_e( initial )
143 , error_i( -1 )
144 {
145 operator()();
146 }
147
149 //
150 // METHOD NAME : PathInfo::PathInfo
151 // METHOD TYPE : Constructor
152 //
153 PathInfo::PathInfo( const std::string & path, Mode initial )
154 : path_t( path )
155 , mode_e( initial )
156 , error_i( -1 )
157 {
158 operator()();
159 }
160
162 //
163 // METHOD NAME : PathInfo::PathInfo
164 // METHOD TYPE : Constructor
165 //
166 PathInfo::PathInfo( const char * path, Mode initial )
167 : path_t( path )
168 , mode_e( initial )
169 , error_i( -1 )
170 {
171 operator()();
172 }
173
175 //
176 // METHOD NAME : PathInfo::~PathInfo
177 // METHOD TYPE : Destructor
178 //
180 {
181 }
182
184 //
185 // METHOD NAME : PathInfo::operator()
186 // METHOD TYPE : bool
187 //
189 {
190 if ( path_t.empty() ) {
191 error_i = -1;
192 } else {
193 switch ( mode_e ) {
194 case STAT:
195 error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
196 break;
197 case LSTAT:
198 error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
199 break;
200 }
201 if ( error_i == -1 )
202 error_i = errno;
203 }
204 return !error_i;
205 }
206
208 //
209 // METHOD NAME : PathInfo::fileType
210 // METHOD TYPE : File_type
211 //
213 {
214 if ( isExist() )
215 return asStatMode().fileType();
216 return FT_NOT_EXIST;
217 }
218
220 //
221 // METHOD NAME : PathInfo::userMay
222 // METHOD TYPE : mode_t
223 //
224 mode_t PathInfo::userMay() const
225 {
226 if ( !isExist() )
227 return 0;
228 if ( owner() == geteuid() ) {
229 return( uperm()/0100 );
230 } else if ( group() == getegid() ) {
231 return( gperm()/010 );
232 }
233 return operm();
234 }
235
236 /******************************************************************
237 **
238 ** FUNCTION NAME : PathInfo::devMajor
239 ** FUNCTION TYPE : unsigned int
240 */
241 unsigned int PathInfo::devMajor() const
242 {
243 return isBlk() || isChr() ? major(statbuf_C.st_rdev) : 0;
244 }
245
246 /******************************************************************
247 **
248 ** FUNCTION NAME : PathInfo::devMinor
249 ** FUNCTION TYPE : unsigned int
250 */
251 unsigned int PathInfo::devMinor() const
252 {
253 return isBlk() || isChr() ? minor(statbuf_C.st_rdev) : 0;
254 }
255
256 /******************************************************************
257 **
258 ** FUNCTION NAME : operator<<
259 ** FUNCTION TYPE : std::ostream &
260 */
261 std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
262 {
263 iostr::IosFmtFlagsSaver autoResoreState( str );
264
265 str << obj.asString() << "{";
266 if ( !obj.isExist() ) {
267 str << Errno( obj.error() );
268 } else {
269 str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
270
271 if ( obj.isFile() )
272 str << " size " << obj.size();
273 }
274
275 return str << "}";
276 }
277
279 //
280 // filesystem utilities
281 //
283
284#define logResult MIL << endl, doLogResult
285 namespace {
287 inline int doLogResult( const int res, const char * rclass = 0 /*errno*/ )
288 {
289 if ( res )
290 {
291 if ( rclass )
292 WAR << " FAILED: " << rclass << " " << res << endl;
293 else
294 WAR << " FAILED: " << str::strerror( res ) << endl;
295 }
296 return res;
297 }
298 } // namespace
299
301 //
302 // METHOD NAME : PathInfo::mkdir
303 // METHOD TYPE : int
304 //
305 int mkdir( const Pathname & path, unsigned mode )
306 {
307 MIL << "mkdir " << path << ' ' << str::octstring( mode );
308 if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
309 return logResult( errno );
310 }
311 return logResult( 0 );
312 }
313
315 //
316 // METHOD NAME : assert_dir()
317 // METHOD TYPE : int
318 //
319 int assert_dir( const Pathname & path, unsigned mode )
320 {
321 if ( path.empty() )
322 return ENOENT;
323
324 { // Handle existing paths in advance.
325 PathInfo pi( path );
326 if ( pi.isDir() )
327 return 0;
328 if ( pi.isExist() )
329 return EEXIST;
330 }
331
332 string spath = path.asString()+"/";
333 std::string::size_type lastpos = ( path.relative() ? 2 : 1 ); // skip leasding './' or '/'
334 std::string::size_type pos = std::string::npos;
335 int ret = 0;
336
337 while ( (pos = spath.find('/',lastpos)) != std::string::npos )
338 {
339 string dir( spath.substr(0,pos) );
340 ret = ::mkdir( dir.c_str(), mode );
341 if ( ret == -1 )
342 {
343 if ( errno == EEXIST ) // ignore errors about already existing paths
344 ret = 0;
345 else
346 {
347 ret = errno;
348 WAR << " FAILED: mkdir " << dir << ' ' << str::octstring( mode ) << " errno " << ret << endl;
349 }
350 }
351 else
352 {
353 MIL << "mkdir " << dir << ' ' << str::octstring( mode ) << endl;
354 }
355 lastpos = pos+1;
356 }
357
358 return ret;
359 }
360
362 //
363 // METHOD NAME : rmdir
364 // METHOD TYPE : int
365 //
366 int rmdir( const Pathname & path )
367 {
368 MIL << "rmdir " << path;
369 if ( ::rmdir( path.asString().c_str() ) == -1 ) {
370 return logResult( errno );
371 }
372 return logResult( 0 );
373 }
374
376 //
377 // METHOD NAME : recursive_rmdir
378 // METHOD TYPE : int
379 //
380 static int recursive_rmdir_1( const Pathname & dir, bool removeDir = true )
381 {
382 DIR * dp;
383 struct dirent * d;
384
385 if ( ! (dp = opendir( dir.c_str() )) )
386 return logResult( errno );
387
388 while ( (d = readdir(dp)) )
389 {
390 std::string direntry = d->d_name;
391 if ( direntry == "." || direntry == ".." )
392 continue;
393 Pathname new_path( dir / d->d_name );
394
395 struct stat st;
396 if ( ! lstat( new_path.c_str(), &st ) )
397 {
398 if ( S_ISDIR( st.st_mode ) )
399 recursive_rmdir_1( new_path );
400 else
401 ::unlink( new_path.c_str() );
402 }
403 }
404 closedir( dp );
405
406 if ( removeDir && ::rmdir( dir.c_str() ) < 0 )
407 return errno;
408
409 return 0;
410 }
412 int recursive_rmdir( const Pathname & path )
413 {
414 MIL << "recursive_rmdir " << path << ' ';
415 PathInfo p( path );
416
417 if ( !p.isExist() ) {
418 return logResult( 0 );
419 }
420
421 if ( !p.isDir() ) {
422 return logResult( ENOTDIR );
423 }
424
425 p.lstat(); // get dir symlinks
426 if ( !p.isDir() ) {
427 MIL << "unlink symlink ";
428 if ( ::unlink( path.asString().c_str() ) == -1 ) {
429 return logResult( errno );
430 }
431 return logResult( 0 );
432 }
433
434 return logResult( recursive_rmdir_1( path ) );
435 }
436
438 //
439 // METHOD NAME : clean_dir
440 // METHOD TYPE : int
441 //
442 int clean_dir( const Pathname & path )
443 {
444 MIL << "clean_dir " << path << ' ';
445 PathInfo p( path );
446
447 if ( !p.isExist() ) {
448 return logResult( 0 );
449 }
450
451 if ( !p.isDir() ) {
452 return logResult( ENOTDIR );
453 }
454
455 return logResult( recursive_rmdir_1( path, false/* don't remove path itself */ ) );
456 }
457
459 //
460 // METHOD NAME : copy_dir
461 // METHOD TYPE : int
462 //
463 int copy_dir( const Pathname & srcpath, const Pathname & destpath )
464 {
465 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
466
467 PathInfo sp( srcpath );
468 if ( !sp.isDir() ) {
469 return logResult( ENOTDIR );
470 }
471
472 PathInfo dp( destpath );
473 if ( !dp.isDir() ) {
474 return logResult( ENOTDIR );
475 }
476
477 PathInfo tp( destpath + srcpath.basename() );
478 if ( tp.isExist() ) {
479 return logResult( EEXIST );
480 }
481
482
483 const char *const argv[] = {
484 "/bin/cp",
485 "-dR",
486 "--",
487 srcpath.asString().c_str(),
488 destpath.asString().c_str(),
489 NULL
490 };
492 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
493 MIL << " " << output;
494 }
495 int ret = prog.close();
496 return logResult( ret, "returned" );
497 }
498
500 //
501 // METHOD NAME : copy_dir_content
502 // METHOD TYPE : int
503 //
504 int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
505 {
506 MIL << "copy_dir " << srcpath << " -> " << destpath << ' ';
507
508 PathInfo sp( srcpath );
509 if ( !sp.isDir() ) {
510 return logResult( ENOTDIR );
511 }
512
513 PathInfo dp( destpath );
514 if ( !dp.isDir() ) {
515 return logResult( ENOTDIR );
516 }
517
518 if ( srcpath == destpath ) {
519 return logResult( EEXIST );
520 }
521
522 std::string src( srcpath.asString());
523 src += "/.";
524 const char *const argv[] = {
525 "/bin/cp",
526 "-dR",
527 "--",
528 src.c_str(),
529 destpath.asString().c_str(),
530 NULL
531 };
533 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
534 MIL << " " << output;
535 }
536 int ret = prog.close();
537 return logResult( ret, "returned" );
538 }
539
541 // dirForEachImpl
543 template <class... T>
544 constexpr bool always_false = false;
545
546 template <typename F>
547 int dirForEachImpl ( const Pathname & dir_r, F &&fnc_r )
548 {
549 AutoDispose<DIR *> dir( ::opendir( dir_r.c_str() ),
550 []( DIR * dir_r ) { if ( dir_r ) ::closedir( dir_r ); } );
551
552 MIL << "readdir " << dir_r << ' ';
553 if ( ! dir )
554 return logResult( errno );
555 MIL << endl; // close line before callbacks are invoked.
556
557 int ret = 0;
558 for ( struct dirent * entry = ::readdir( dir ); entry; entry = ::readdir( dir ) )
559 {
560 if ( entry->d_name[0] == '.' && ( entry->d_name[1] == '\0' || ( entry->d_name[1] == '.' && entry->d_name[2] == '\0' ) ) )
561 continue; // omitt . and ..
562
563 // some static checks to make sure the correct func is selected
564 static_assert( !std::is_invocable_v< function<bool(const Pathname &, const char *const)>, const Pathname &, const DirEntry &> , "Invoke detection broken" );
565 static_assert( !std::is_invocable_v< function<bool(const Pathname &, const DirEntry& )>, const Pathname &, const char *> , "Invoke detection broken" );
566
567 if constexpr ( std::is_invocable_v<F, const Pathname &, const char *const> ) {
568 if ( ! std::forward<F>(fnc_r)( dir_r, entry->d_name ) ) {
569 ret = -1;
570 break;
571 }
572 } else if constexpr ( std::is_invocable_v<F, const Pathname &, const DirEntry&> ) {
573 if ( ! std::forward<F>(fnc_r)( dir_r, DirEntry( entry ) ) ) {
574 ret = -1;
575 break;
576 }
577 } else {
578 static_assert( always_false<F>, "Callback not supported" );
579 }
580 }
581 return ret;
582 }
583
584 int dirForEach( const Pathname & dir_r, function<bool(const Pathname &, const char *const)> fnc_r )
585 {
586 if ( ! fnc_r )
587 return 0;
588
589 return dirForEachImpl( dir_r, fnc_r );
590 }
591
592
593 int dirForEachExt( const Pathname & dir_r, const function<bool(const Pathname &, const DirEntry &)> &fnc_r )
594 {
595 if ( ! fnc_r )
596 return 0;
597
598 return dirForEachImpl( dir_r, fnc_r );
599 }
600
602 // readdir
604
605 int readdir( std::list<std::string> & retlist_r, const Pathname & path_r, bool dots_r )
606 {
607 retlist_r.clear();
608 return dirForEach( path_r,
609 [&]( const Pathname & dir_r, const char *const name_r )->bool
610 {
611 if ( dots_r || name_r[0] != '.' )
612 retlist_r.push_back( name_r );
613 return true;
614 } );
615 }
616
617
618 int readdir( std::list<Pathname> & retlist_r, const Pathname & path_r, bool dots_r )
619 {
620 retlist_r.clear();
621 return dirForEach( path_r,
622 [&]( const Pathname & dir_r, const char *const name_r )->bool
623 {
624 if ( dots_r || name_r[0] != '.' )
625 retlist_r.push_back( dir_r/name_r );
626 return true;
627 } );
628 }
629
630 DirEntry::DirEntry( struct dirent* entry )
631 : name( str::asString( entry->d_name ) )
632 {
633 switch( entry->d_type ) {
634 case DT_BLK:
636 break;
637 case DT_CHR:
639 break;
640 case DT_DIR:
641 this->type = FileType::FT_DIR;
642 break;
643 case DT_FIFO:
644 this->type = FileType::FT_FIFO;
645 break;
646 case DT_LNK:
647 this->type = FileType::FT_LINK;
648 break;
649 case DT_REG:
650 this->type = FileType::FT_FILE;
651 break;
652 case DT_SOCK:
654 break;
655 case DT_UNKNOWN:
657 break;
658 }
659 }
660
661 bool DirEntry::operator==( const DirEntry &rhs ) const
662 {
663 // if one of the types is not known, use the name only
664 if ( type == FT_NOT_AVAIL || rhs.type == FT_NOT_AVAIL )
665 return ( name == rhs.name );
666 return ((name == rhs.name ) && (type == rhs.type));
667 }
668
669 int readdir( DirContent & retlist_r, const Pathname & path_r, bool dots_r, PathInfo::Mode statmode_r )
670 {
671 retlist_r.clear();
672 return dirForEach( path_r,
673 [&]( const Pathname & dir_r, const char *const name_r )->bool
674 {
675 if ( dots_r || name_r[0] != '.' )
676 retlist_r.push_back( DirEntry( name_r, PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
677 return true;
678 } );
679 }
680
681 std::ostream & operator<<( std::ostream & str, const DirContent & obj )
682 { return dumpRange( str, obj.begin(), obj.end() ); }
683
685 // is_empty_dir
687
688 int is_empty_dir( const Pathname & path_r )
689 {
690 return dirForEach( path_r,
691 [&]( const Pathname & dir_r, const char *const name_r )->bool
692 { return false; } );
693 }
694
696 //
697 // METHOD NAME : unlink
698 // METHOD TYPE : int
699 //
700 int unlink( const Pathname & path )
701 {
702 MIL << "unlink " << path;
703 if ( ::unlink( path.asString().c_str() ) == -1 ) {
704 return logResult( errno );
705 }
706 return logResult( 0 );
707 }
708
710 namespace
711 {
712 int safe_rename( const Pathname & oldpath, const Pathname & newpath )
713 {
714 int ret = ::rename( oldpath.asString().c_str(), newpath.asString().c_str() );
715
716 // rename(2) can fail on OverlayFS. Fallback to using mv(1), which is
717 // explicitly mentioned in the kernel docs to deal correctly with OverlayFS.
718 if ( ret == -1 && errno == EXDEV ) {
719 const char *const argv[] = {
720 "/usr/bin/mv",
721 oldpath.asString().c_str(),
722 newpath.asString().c_str(),
723 NULL
724 };
725 ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
726 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
727 MIL << " " << output;
728 }
729 ret = prog.close();
730 }
731
732 return ret;
733 }
734 } // namespace
736
738 //
739 // METHOD NAME : rename
740 // METHOD TYPE : int
741 //
742 int rename( const Pathname & oldpath, const Pathname & newpath )
743 {
744 MIL << "rename " << oldpath << " -> " << newpath;
745 if ( safe_rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
746 return logResult( errno );
747 }
748 return logResult( 0 );
749 }
750
752 //
753 // METHOD NAME : exchange
754 // METHOD TYPE : int
755 //
756 int exchange( const Pathname & lpath, const Pathname & rpath )
757 {
758 MIL << "exchange " << lpath << " <-> " << rpath;
759 if ( lpath.empty() || rpath.empty() )
760 return logResult( EINVAL );
761
762 PathInfo linfo( lpath );
763 PathInfo rinfo( rpath );
764
765 if ( ! linfo.isExist() )
766 {
767 if ( ! rinfo.isExist() )
768 return logResult( 0 ); // both don't exist.
769
770 // just rename rpath -> lpath
771 int ret = assert_dir( lpath.dirname() );
772 if ( ret != 0 )
773 return logResult( ret );
774 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
775 return logResult( errno );
776 }
777 return logResult( 0 );
778 }
779
780 // HERE: lpath exists:
781 if ( ! rinfo.isExist() )
782 {
783 // just rename lpath -> rpath
784 int ret = assert_dir( rpath.dirname() );
785 if ( ret != 0 )
786 return logResult( ret );
787 if ( safe_rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
788 return logResult( errno );
789 }
790 return logResult( 0 );
791 }
792
793 // HERE: both exist
794 TmpFile tmpfile( TmpFile::makeSibling( rpath ) );
795 if ( ! tmpfile )
796 return logResult( errno );
797 Pathname tmp( tmpfile.path() );
798 ::unlink( tmp.c_str() );
799
800 if ( safe_rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
801 return logResult( errno );
802 }
803 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
804 safe_rename( tmp.c_str(), lpath.c_str() );
805 return logResult( errno );
806 }
807 if ( safe_rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
808 safe_rename( lpath.c_str(), rpath.c_str() );
809 safe_rename( tmp.c_str(), lpath.c_str() );
810 return logResult( errno );
811 }
812 return logResult( 0 );
813 }
814
816 //
817 // METHOD NAME : copy
818 // METHOD TYPE : int
819 //
820 int copy( const Pathname & file, const Pathname & dest )
821 {
822 MIL << "copy " << file << " -> " << dest << ' ';
823
824 PathInfo sp( file );
825 if ( !sp.isFile() ) {
826 return logResult( EINVAL );
827 }
828
829 PathInfo dp( dest );
830 if ( dp.isDir() ) {
831 return logResult( EISDIR );
832 }
833
834 const char *const argv[] = {
835 "/bin/cp",
836 "--remove-destination",
837 "--",
838 file.asString().c_str(),
839 dest.asString().c_str(),
840 NULL
841 };
843 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
844 MIL << " " << output;
845 }
846 int ret = prog.close();
847 return logResult( ret, "returned" );
848 }
849
851 //
852 // METHOD NAME : symlink
853 // METHOD TYPE : int
854 //
855 int symlink( const Pathname & oldpath, const Pathname & newpath )
856 {
857 MIL << "symlink " << newpath << " -> " << oldpath;
858 if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
859 return logResult( errno );
860 }
861 return logResult( 0 );
862 }
863
865 //
866 // METHOD NAME : hardlink
867 // METHOD TYPE : int
868 //
869 int hardlink( const Pathname & oldpath, const Pathname & newpath )
870 {
871 MIL << "hardlink " << newpath << " -> " << oldpath;
872 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
873 return logResult( errno );
874 }
875 return logResult( 0 );
876 }
877
879 //
880 // METHOD NAME : hardlink
881 // METHOD TYPE : int
882 //
883 int hardlinkCopy( const Pathname & oldpath, const Pathname & newpath )
884 {
885 MIL << "hardlinkCopy " << oldpath << " -> " << newpath;
886
887 PathInfo pi( oldpath, PathInfo::LSTAT );
888 if ( pi.isLink() )
889 {
890 // dont hardlink symlinks!
891 MIL << " => copy" << endl;
892 return copy( oldpath, newpath );
893 }
894
895 pi.lstat( newpath );
896 if ( pi.isExist() )
897 {
898 int res = unlink( newpath );
899 if ( res != 0 )
900 return logResult( res );
901 }
902
903 // Here: no symlink, no newpath
904 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
905 {
906 switch ( errno )
907 {
908 case EPERM: // /proc/sys/fs/protected_hardlink in proc(5)
909 case EXDEV: // oldpath and newpath are not on the same mounted file system
910 MIL << " => copy" << endl;
911 return copy( oldpath, newpath );
912 break;
913 }
914 return logResult( errno );
915 }
916 return logResult( 0 );
917 }
918
920 //
921 // METHOD NAME : readlink
922 // METHOD TYPE : int
923 //
924 int readlink( const Pathname & symlink_r, Pathname & target_r )
925 {
926 static const ssize_t bufsiz = 2047;
927 static char buf[bufsiz+1];
928 ssize_t ret = ::readlink( symlink_r.c_str(), buf, bufsiz );
929 if ( ret == -1 )
930 {
931 target_r = Pathname();
932 MIL << "readlink " << symlink_r;
933 return logResult( errno );
934 }
935 buf[ret] = '\0';
936 target_r = buf;
937 return 0;
938 }
939
941 //
942 // METHOD NAME : expandlink
943 // METHOD TYPE : Pathname
944 //
945 Pathname expandlink( const Pathname & path_r )
946 {
947 static const unsigned int level_limit = 256;
948 static unsigned int count;
949 Pathname path(path_r);
950 PathInfo info(path_r, PathInfo::LSTAT);
951
952 for (count = level_limit; info.isLink() && count; count--)
953 {
954 DBG << "following symlink " << path;
955 path = path.dirname() / readlink(path);
956 DBG << "->" << path << std::endl;
957 info = PathInfo(path, PathInfo::LSTAT);
958 }
959
960 // expand limit reached
961 if (count == 0)
962 {
963 ERR << "Expand level limit reached. Probably a cyclic symbolic link." << endl;
964 return Pathname();
965 }
966 // symlink
967 else if (count < level_limit)
968 {
969 // check for a broken link
970 if (PathInfo(path).isExist())
971 return path;
972 // broken link, return an empty path
973 else
974 {
975 ERR << path << " is broken (expanded from " << path_r << ")" << endl;
976 return Pathname();
977 }
978 }
979
980 // not a symlink, return the original pathname
981 DBG << "not a symlink" << endl;
982 return path;
983 }
984
986 //
987 // METHOD NAME : copy_file2dir
988 // METHOD TYPE : int
989 //
990 int copy_file2dir( const Pathname & file, const Pathname & dest )
991 {
992 MIL << "copy_file2dir " << file << " -> " << dest << ' ';
993
994 PathInfo sp( file );
995 if ( !sp.isFile() ) {
996 return logResult( EINVAL );
997 }
998
999 PathInfo dp( dest );
1000 if ( !dp.isDir() ) {
1001 return logResult( ENOTDIR );
1002 }
1003
1004 const char *const argv[] = {
1005 "/bin/cp",
1006 "--",
1007 file.asString().c_str(),
1008 dest.asString().c_str(),
1009 NULL
1010 };
1012 for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
1013 MIL << " " << output;
1014 }
1015 int ret = prog.close();
1016 return logResult( ret, "returned" );
1017 }
1018
1020 //
1021 // METHOD NAME : md5sum
1022 // METHOD TYPE : std::string
1023 //
1024 std::string md5sum( const Pathname & file )
1025 {
1026 if ( ! PathInfo( file ).isFile() ) {
1027 return string();
1028 }
1029 std::ifstream istr( file.asString().c_str() );
1030 if ( ! istr ) {
1031 return string();
1032 }
1033 return Digest::digest( "MD5", istr );
1034 }
1035
1037 //
1038 // METHOD NAME : sha1sum
1039 // METHOD TYPE : std::string
1040 //
1041 std::string sha1sum( const Pathname & file )
1042 {
1043 return checksum(file, "SHA1");
1044 }
1045
1047 //
1048 // METHOD NAME : checksum
1049 // METHOD TYPE : std::string
1050 //
1051 std::string checksum( const Pathname & file, const std::string &algorithm )
1052 {
1053 if ( ! PathInfo( file ).isFile() ) {
1054 return string();
1055 }
1056 std::ifstream istr( file.asString().c_str() );
1057 if ( ! istr ) {
1058 return string();
1059 }
1060 return Digest::digest( algorithm, istr );
1061 }
1062
1063 bool is_checksum( const Pathname & file, const CheckSum &checksum )
1064 {
1065 return ( filesystem::checksum(file, checksum.type()) == checksum.checksum() );
1066 }
1067
1069 //
1070 // METHOD NAME : erase
1071 // METHOD TYPE : int
1072 //
1073 int erase( const Pathname & path )
1074 {
1075 int res = 0;
1076 PathInfo p( path, PathInfo::LSTAT );
1077 if ( p.isExist() )
1078 {
1079 if ( p.isDir() )
1080 res = recursive_rmdir( path );
1081 else
1082 res = unlink( path );
1083 }
1084 return res;
1085 }
1086
1088 //
1089 // METHOD NAME : chmod
1090 // METHOD TYPE : int
1091 //
1092 int chmod( const Pathname & path, mode_t mode )
1093 {
1094 MIL << "chmod " << path << ' ' << str::octstring( mode );
1095 if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
1096 return logResult( errno );
1097 }
1098 return logResult( 0 );
1099 }
1100
1101 int addmod( const Pathname & path, mode_t mode )
1102 {
1103 mode_t omode( PathInfo( path ).st_mode() );
1104 mode_t tmode( omode | mode );
1105 if ( omode != mode )
1106 return chmod( path, tmode );
1107 return 0;
1108 }
1109
1110 int delmod( const Pathname & path, mode_t mode )
1111 {
1112 mode_t omode( PathInfo( path ).st_mode() );
1113 mode_t tmode( omode & ~mode );
1114 if ( omode != mode )
1115 return chmod( path, tmode );
1116 return 0;
1117 }
1118
1120 //
1121 // METHOD NAME : zipType
1122 // METHOD TYPE : ZIP_TYPE
1123 //
1124 ZIP_TYPE zipType( const Pathname & file )
1125 {
1126 ZIP_TYPE ret = ZT_NONE;
1127
1128 int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
1129
1130 if ( fd != -1 ) {
1131 const int magicSize = 5;
1132 unsigned char magic[magicSize];
1133 memset( magic, 0, magicSize );
1134 if ( read( fd, magic, magicSize ) == magicSize ) {
1135 if ( magic[0] == 0037 && magic[1] == 0213 ) {
1136 ret = ZT_GZ;
1137 } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
1138 ret = ZT_BZ2;
1139 } else if ( magic[0] == '\0' && magic[1] == 'Z' && magic[2] == 'C' && magic[3] == 'K' && magic[4] == '1') {
1140 ret = ZT_ZCHNK;
1141
1142 }
1143 }
1144 close( fd );
1145 }
1146
1147 return ret;
1148 }
1149
1151 //
1152 // METHOD NAME : df
1153 // METHOD TYPE : ByteCount
1154 //
1155 ByteCount df( const Pathname & path_r )
1156 {
1157 ByteCount ret( -1 );
1158 struct statvfs sb;
1159 if ( statvfs( path_r.c_str(), &sb ) == 0 )
1160 {
1161 ret = sb.f_bfree * sb.f_bsize;
1162 }
1163 return ret;
1164 }
1165
1167 //
1168 // METHOD NAME : getUmask
1169 // METHOD TYPE : mode_t
1170 //
1171 mode_t getUmask()
1172 {
1173 mode_t mask = ::umask( 0022 );
1174 ::umask( mask );
1175 return mask;
1176 }
1177
1179 //
1180 // METHOD NAME : getUmask
1181 // METHOD TYPE : mode_t
1182 //
1183 int assert_file( const Pathname & path, unsigned mode )
1184 {
1185 int ret = assert_dir( path.dirname() );
1186 MIL << "assert_file " << str::octstring( mode ) << " " << path;
1187 if ( ret != 0 )
1188 return logResult( ret );
1189
1190 PathInfo pi( path );
1191 if ( pi.isExist() )
1192 return logResult( pi.isFile() ? 0 : EEXIST );
1193
1194 int fd = ::creat( path.c_str(), mode );
1195 if ( fd == -1 )
1196 return logResult( errno );
1197
1198 ::close( fd );
1199 return logResult( 0 );
1200 }
1201
1202 int assert_file_mode( const Pathname & path, unsigned mode )
1203 {
1204 int ret = assert_dir( path.dirname() );
1205 MIL << "assert_file_mode " << str::octstring( mode ) << " " << path;
1206 if ( ret != 0 )
1207 return logResult( ret );
1208
1209 PathInfo pi( path );
1210 if ( pi.isExist() )
1211 {
1212 if ( ! pi.isFile() )
1213 return logResult( EEXIST );
1214
1215 mode = applyUmaskTo( mode );
1216 if ( pi.st_mode() != mode )
1217 return chmod( path, mode );
1218
1219 return logResult( 0 );
1220 }
1221
1222 int fd = ::creat( path.c_str(), mode );
1223 if ( fd == -1 )
1224 return logResult( errno );
1225 ::close( fd );
1226 return logResult( 0 );
1227 }
1228
1230 //
1231 // METHOD NAME : touch
1232 // METHOD TYPE : int
1233 //
1234 int touch (const Pathname & path)
1235 {
1236 MIL << "touch " << path;
1237 struct ::utimbuf times;
1238 times.actime = ::time( 0 );
1239 times.modtime = ::time( 0 );
1240 if ( ::utime( path.asString().c_str(), &times ) == -1 ) {
1241 return logResult( errno );
1242 }
1243 return logResult( 0 );
1244 }
1245
1247 } // namespace filesystem
1250} // namespace zypp
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:94
Store and operate with byte count.
Definition: ByteCount.h:31
std::string digest()
get hex string representation of the digest
Definition: Digest.cc:206
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.
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:188
Mode
stat() or lstat()
Definition: PathInfo.h:226
unsigned int devMinor() const
Definition: PathInfo.cc:251
FileType fileType() const
Definition: PathInfo.cc:212
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:224
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:241
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:70
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.
int chmod(const Pathname &path, mode_t mode)
Like 'chmod'.
Definition: PathInfo.cc:1092
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:1051
int delmod(const Pathname &path, mode_t mode)
Remove the mode bits from the file given by path.
Definition: PathInfo.cc:1110
int dirForEachImpl(const Pathname &dir_r, F &&fnc_r)
Definition: PathInfo.cc:547
static int recursive_rmdir_1(const Pathname &dir, bool removeDir=true)
Definition: PathInfo.cc:380
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:945
int is_empty_dir(const Pathname &path_r)
Check if the specified directory is empty.
Definition: PathInfo.cc:688
mode_t applyUmaskTo(mode_t mode_r)
Modify mode_r according to the current umask ( mode_r & ~getUmask() ).
Definition: PathInfo.h:789
int readdir(std::list< std::string > &retlist_r, const Pathname &path_r, bool dots_r)
Return content of directory via retlist.
Definition: PathInfo.cc:605
ByteCount df(const Pathname &path_r)
Report free disk space on a mounted file system.
Definition: PathInfo.cc:1155
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:700
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition: PathInfo.cc:742
int mkdir(const Pathname &path, unsigned mode)
Like 'mkdir'.
Definition: PathInfo.cc:305
int rmdir(const Pathname &path)
Like 'rmdir'.
Definition: PathInfo.cc:366
bool is_checksum(const Pathname &file, const CheckSum &checksum)
check files checksum
Definition: PathInfo.cc:1063
int assert_file(const Pathname &path, unsigned mode)
Create an empty file if it does not yet exist.
Definition: PathInfo.cc:1183
int recursive_rmdir(const Pathname &path)
Like 'rm -r DIR'.
Definition: PathInfo.cc:412
int copy_dir(const Pathname &srcpath, const Pathname &destpath)
Like 'cp -a srcpath destpath'.
Definition: PathInfo.cc:463
int copy_dir_content(const Pathname &srcpath, const Pathname &destpath)
Like 'cp -a srcpath/.
Definition: PathInfo.cc:504
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:1073
int addmod(const Pathname &path, mode_t mode)
Add the mode bits to the file given by path.
Definition: PathInfo.cc:1101
int hardlink(const Pathname &oldpath, const Pathname &newpath)
Like '::link'.
Definition: PathInfo.cc:869
int readlink(const Pathname &symlink_r, Pathname &target_r)
Like 'readlink'.
Definition: PathInfo.cc:924
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:319
int copy_file2dir(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition: PathInfo.cc:990
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition: PathInfo.cc:1202
mode_t getUmask()
Get the current umask (file mode creation mask)
Definition: PathInfo.cc:1171
int touch(const Pathname &path)
Change file's modification and access times.
Definition: PathInfo.cc:1234
int hardlinkCopy(const Pathname &oldpath, const Pathname &newpath)
Create newpath as hardlink or copy of oldpath.
Definition: PathInfo.cc:883
constexpr bool always_false
Definition: PathInfo.cc:544
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:518
std::string md5sum(const Pathname &file)
Compute a files md5sum.
Definition: PathInfo.cc:1024
int exchange(const Pathname &lpath, const Pathname &rpath)
Exchanges two files or directories.
Definition: PathInfo.cc:756
int dirForEachExt(const Pathname &dir_r, const function< bool(const Pathname &, const DirEntry &)> &fnc_r)
Simiar to.
Definition: PathInfo.cc:593
std::string sha1sum(const Pathname &file)
Compute a files sha1sum.
Definition: PathInfo.cc:1041
ZIP_TYPE zipType(const Pathname &file)
Definition: PathInfo.cc:1124
int copy(const Pathname &file, const Pathname &dest)
Like 'cp file dest'.
Definition: PathInfo.cc:820
ZIP_TYPE
Test whether a file is compressed (gzip/bzip2).
Definition: PathInfo.h:754
int symlink(const Pathname &oldpath, const Pathname &newpath)
Like 'symlink'.
Definition: PathInfo.cc:855
int clean_dir(const Pathname &path)
Like 'rm -r DIR/ *'.
Definition: PathInfo.cc:442
boost::io::ios_base_all_saver IosFmtFlagsSaver
Save and restore streams width, precision and fmtflags.
Definition: IOStream.h:35
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: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:92
Listentry returned by readdir.
Definition: PathInfo.h:501
bool operator==(const DirEntry &rhs) const
Definition: PathInfo.cc:661
DirEntry(const std::string &name_r=std::string(), FileType type_r=FT_NOT_AVAIL)
Definition: PathInfo.h:504
#define EMUMOUT(T)
#define logResult
Definition: PathInfo.cc:284
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define ERR
Definition: Logger.h:98
#define WAR
Definition: Logger.h:97