14 #include <sys/statvfs.h>
15 #include <sys/sysmacros.h>
51 #define EMUMOUT(T) case T: return str << #T; break
103 else if ( obj.
isDir() )
107 else if ( obj.
isChr() )
109 else if ( obj.
isBlk() )
116 str << t <<
" " << std::setfill(
'0' ) << std::setw( 4 ) << std::oct << obj.
perm();
229 if (
owner() == geteuid() ) {
230 return(
uperm()/0100 );
231 }
else if (
group() == getegid() ) {
232 return(
gperm()/010 );
285 #define logResult MIL << endl, doLogResult
288 inline int doLogResult(
const int res,
const char * rclass = 0 )
293 WAR <<
" FAILED: " << rclass <<
" " << res << endl;
306 int mkdir(
const Pathname & path,
unsigned mode )
309 if ( ::
mkdir( path.asString().c_str(), mode ) == -1 ) {
320 int assert_dir(
const Pathname & path,
unsigned mode )
333 string spath = path.asString()+
"/";
338 while ( (pos = spath.find(
'/',lastpos)) != string::npos )
340 string dir( spath.substr(0,pos) );
341 ret =
::mkdir( dir.c_str(), mode );
344 if ( errno == EEXIST )
349 WAR <<
" FAILED: mkdir " << dir <<
' ' <<
str::octstring( mode ) <<
" errno " << ret << endl;
367 int rmdir(
const Pathname & path )
369 MIL <<
"rmdir " << path;
370 if ( ::
rmdir( path.asString().c_str() ) == -1 ) {
386 if ( ! (dp = opendir( dir.c_str() )) )
391 std::string direntry = d->d_name;
392 if ( direntry ==
"." || direntry ==
".." )
394 Pathname new_path( dir / d->d_name );
397 if ( ! lstat( new_path.c_str(), &st ) )
399 if ( S_ISDIR( st.st_mode ) )
407 if ( removeDir && ::
rmdir( dir.c_str() ) < 0 )
415 MIL <<
"recursive_rmdir " << path <<
' ';
436 MIL <<
"clean_dir " << path <<
' ';
455 int copy_dir(
const Pathname & srcpath,
const Pathname & destpath )
457 MIL <<
"copy_dir " << srcpath <<
" -> " << destpath <<
' ';
459 PathInfo sp( srcpath );
464 PathInfo dp( destpath );
469 PathInfo tp( destpath + srcpath.basename() );
470 if ( tp.isExist() ) {
475 const char *
const argv[] = {
479 srcpath.asString().c_str(),
480 destpath.asString().c_str(),
484 for (
string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
485 MIL <<
" " << output;
487 int ret = prog.close();
498 MIL <<
"copy_dir " << srcpath <<
" -> " << destpath <<
' ';
500 PathInfo sp( srcpath );
505 PathInfo dp( destpath );
510 if ( srcpath == destpath ) {
514 std::string src( srcpath.asString());
516 const char *
const argv[] = {
521 destpath.asString().c_str(),
525 for (
string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
526 MIL <<
" " << output;
528 int ret = prog.close();
548 []( DIR * dir_r ) {
if ( dir_r ) ::closedir( dir_r ); } );
550 MIL <<
"readdir " << dir_r <<
' ';
556 for (
struct dirent * entry = ::
readdir( dir ); entry; entry =
::readdir( dir ) )
558 if ( entry->d_name[0] ==
'.' && ( entry->d_name[1] ==
'\0' || ( entry->d_name[1] ==
'.' && entry->d_name[2] ==
'\0' ) ) )
561 if ( ! fnc_r( dir_r, entry->d_name ) )
570 int dirForEach(
const Pathname & dir_r,
const StrMatcher & matcher_r,
function<
bool(
const Pathname &,
const char *
const)> fnc_r )
577 [&](
const Pathname & dir_r,
const char *
const name_r )->
bool
579 if ( ( nodots && name_r[0] ==
'.' ) || ! matcher_r( name_r ) )
581 return fnc_r( dir_r, name_r );
589 int readdir( std::list<std::string> & retlist_r,
const Pathname & path_r,
bool dots_r )
593 [&](
const Pathname & dir_r,
const char *
const name_r )->
bool
595 if ( dots_r || name_r[0] !=
'.' )
596 retlist_r.push_back( name_r );
602 int readdir( std::list<Pathname> & retlist_r,
const Pathname & path_r,
bool dots_r )
606 [&](
const Pathname & dir_r,
const char *
const name_r )->
bool
608 if ( dots_r || name_r[0] !=
'.' )
609 retlist_r.push_back( dir_r/name_r );
618 return (
name == rhs.name );
619 return ((
name == rhs.name ) && (
type == rhs.type));
626 [&](
const Pathname & dir_r,
const char *
const name_r )->
bool
628 if ( dots_r || name_r[0] !=
'.' )
629 retlist_r.push_back(
DirEntry( name_r,
PathInfo( dir_r/name_r, statmode_r ).fileType() ) );
644 [&](
const Pathname & dir_r,
const char *
const name_r )->
bool
655 MIL <<
"unlink " << path;
656 if ( ::
unlink( path.asString().c_str() ) == -1 ) {
665 int safe_rename(
const Pathname & oldpath,
const Pathname & newpath )
667 int ret =
::rename( oldpath.asString().c_str(), newpath.asString().c_str() );
671 if ( ret == -1 && errno == EXDEV ) {
672 const char *
const argv[] = {
674 oldpath.asString().c_str(),
675 newpath.asString().c_str(),
679 for (
string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
680 MIL <<
" " << output;
695 int rename(
const Pathname & oldpath,
const Pathname & newpath )
697 MIL <<
"rename " << oldpath <<
" -> " << newpath;
698 if ( safe_rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
709 int exchange(
const Pathname & lpath,
const Pathname & rpath )
711 MIL <<
"exchange " << lpath <<
" <-> " << rpath;
712 if ( lpath.empty() || rpath.empty() )
715 PathInfo linfo( lpath );
716 PathInfo rinfo( rpath );
718 if ( ! linfo.isExist() )
720 if ( ! rinfo.isExist() )
727 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
734 if ( ! rinfo.isExist() )
740 if ( safe_rename( lpath.c_str(), rpath.c_str() ) == -1 ) {
750 Pathname tmp( tmpfile.path() );
753 if ( safe_rename( lpath.c_str(), tmp.c_str() ) == -1 ) {
756 if ( safe_rename( rpath.c_str(), lpath.c_str() ) == -1 ) {
757 safe_rename( tmp.c_str(), lpath.c_str() );
760 if ( safe_rename( tmp.c_str(), rpath.c_str() ) == -1 ) {
761 safe_rename( lpath.c_str(), rpath.c_str() );
762 safe_rename( tmp.c_str(), lpath.c_str() );
773 int copy(
const Pathname & file,
const Pathname & dest )
775 MIL <<
"copy " << file <<
" -> " << dest <<
' ';
778 if ( !sp.isFile() ) {
787 const char *
const argv[] = {
789 "--remove-destination",
791 file.asString().c_str(),
792 dest.asString().c_str(),
796 for (
string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
797 MIL <<
" " << output;
799 int ret = prog.close();
808 int symlink(
const Pathname & oldpath,
const Pathname & newpath )
810 MIL <<
"symlink " << newpath <<
" -> " << oldpath;
811 if ( ::
symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
822 int hardlink(
const Pathname & oldpath,
const Pathname & newpath )
824 MIL <<
"hardlink " << newpath <<
" -> " << oldpath;
825 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
836 int hardlinkCopy(
const Pathname & oldpath,
const Pathname & newpath )
838 MIL <<
"hardlinkCopy " << oldpath <<
" -> " << newpath;
844 MIL <<
" => copy" << endl;
845 return copy( oldpath, newpath );
851 int res =
unlink( newpath );
857 if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 )
863 MIL <<
" => copy" << endl;
864 return copy( oldpath, newpath );
877 int readlink(
const Pathname & symlink_r, Pathname & target_r )
879 static const ssize_t bufsiz = 2047;
880 static char buf[bufsiz+1];
881 ssize_t ret =
::readlink( symlink_r.c_str(), buf, bufsiz );
884 target_r = Pathname();
885 MIL <<
"readlink " << symlink_r;
898 Pathname
expandlink(
const Pathname & path_r )
900 static const unsigned int level_limit = 256;
901 static unsigned int count;
902 Pathname path(path_r);
905 for (count = level_limit; info.isLink() && count; count--)
907 DBG <<
"following symlink " << path;
908 path = path.dirname() /
readlink(path);
909 DBG <<
"->" << path << std::endl;
916 ERR <<
"Expand level limit reached. Probably a cyclic symbolic link." << endl;
920 else if (count < level_limit)
923 if (PathInfo(path).isExist())
928 ERR << path <<
" is broken (expanded from " << path_r <<
")" << endl;
934 DBG <<
"not a symlink" << endl;
943 int copy_file2dir(
const Pathname & file,
const Pathname & dest )
945 MIL <<
"copy_file2dir " << file <<
" -> " << dest <<
' ';
948 if ( !sp.isFile() ) {
957 const char *
const argv[] = {
960 file.asString().c_str(),
961 dest.asString().c_str(),
965 for (
string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
966 MIL <<
" " << output;
968 int ret = prog.close();
977 std::string
md5sum(
const Pathname & file )
979 if ( ! PathInfo( file ).isFile() ) {
982 std::ifstream istr( file.asString().c_str() );
994 std::string
sha1sum(
const Pathname & file )
1004 std::string
checksum(
const Pathname & file,
const std::string &algorithm )
1006 if ( ! PathInfo( file ).isFile() ) {
1009 std::ifstream istr( file.asString().c_str() );
1026 int erase(
const Pathname & path )
1045 int chmod(
const Pathname & path, mode_t mode )
1048 if ( ::
chmod( path.asString().c_str(), mode ) == -1 ) {
1054 int addmod(
const Pathname & path, mode_t mode )
1056 mode_t omode( PathInfo( path ).st_mode() );
1057 mode_t tmode( omode | mode );
1058 if ( omode != mode )
1059 return chmod( path, tmode );
1065 mode_t omode(
PathInfo( path ).st_mode() );
1066 mode_t tmode( omode & ~mode );
1067 if ( omode != mode )
1068 return chmod( path, tmode );
1081 int fd = open( file.asString().c_str(), O_RDONLY|O_CLOEXEC );
1084 const int magicSize = 5;
1085 unsigned char magic[magicSize];
1086 memset( magic, 0, magicSize );
1087 if (
read( fd, magic, magicSize ) == magicSize ) {
1088 if ( magic[0] == 0037 && magic[1] == 0213 ) {
1090 }
else if ( magic[0] ==
'B' && magic[1] ==
'Z' && magic[2] ==
'h' ) {
1092 }
else if ( magic[0] ==
'\0' && magic[1] ==
'Z' && magic[2] ==
'C' && magic[3] ==
'K' && magic[4] ==
'1') {
1108 ByteCount
df(
const Pathname & path_r )
1110 ByteCount ret( -1 );
1112 if ( statvfs( path_r.c_str(), &sb ) == 0 )
1114 ret = sb.f_bfree * sb.f_bsize;
1126 mode_t mask = ::umask( 0022 );
1136 int assert_file(
const Pathname & path,
unsigned mode )
1143 PathInfo pi( path );
1145 return logResult( pi.isFile() ? 0 : EEXIST );
1147 int fd = ::creat( path.c_str(), mode );
1165 if ( ! pi.isFile() )
1169 if ( pi.st_mode() != mode )
1170 return chmod( path, mode );
1175 int fd = ::creat( path.c_str(), mode );
1187 int touch (
const Pathname & path)
1189 MIL <<
"touch " << path;
1190 struct ::utimbuf times;
1191 times.actime = ::time( 0 );
1192 times.modtime = ::time( 0 );
1193 if ( ::utime( path.asString().c_str(), × ) == -1 ) {