39 bool removeImp(
const char * path ,
int * e ) noexcept ;
40 std::pair<bool,mode_t> newmode( mode_t ,
const std::string & ) ;
41 std::pair<std::time_t,unsigned int> mtime(
struct stat & statbuf )
noexcept
43 #if GCONFIG_HAVE_STATBUF_TIMESPEC
44 return { statbuf.st_mtimespec.tv_sec , statbuf.st_mtimespec.tv_nsec/1000U } ;
46 #if GCONFIG_HAVE_STATBUF_NSEC
47 return { statbuf.st_mtime , statbuf.st_mtim.tv_nsec/1000U } ;
49 return { statbuf.st_mtime , 0U } ;
58 ofstream.open( path.
cstr() , std::ios_base::out | std::ios_base::binary ) ;
63 ofstream.open( path.
cstr() , std::ios_base::out ) ;
68 ofstream.open( path.
cstr() , std::ios_base::app | std::ios_base::binary ) ;
73 ifstream.open( path.
cstr() , std::ios_base::in | std::ios_base::binary ) ;
79 ifstream.open( path.
cstr() , std::ios_base::in ) ;
87 fb.open( path.
cstr() , std::ios_base::in | std::ios_base::binary ) :
88 fb.open( path.
cstr() , std::ios_base::out | std::ios_base::binary ) ;
93 static_assert(
noexcept(path.cstr()) ,
"" ) ;
94 const char * path_cstr = path.cstr() ;
95 if( mode == InOutAppend::In )
96 return ::open( path_cstr , O_RDONLY ) ;
97 else if( mode == InOutAppend::Out )
98 return ::open( path_cstr , O_WRONLY|O_CREAT|O_TRUNC , 0666 ) ;
99 else if( mode == InOutAppend::OutNoCreate )
100 return ::open( path_cstr , O_WRONLY , 0666 ) ;
102 return ::open( path_cstr , O_WRONLY|O_CREAT|O_APPEND , 0666 ) ;
108 static_assert(
noexcept(path.cstr()) ,
"" ) ;
109 return ::open( path.cstr() , O_WRONLY|O_CREAT|O_EXCL , 0666 ) ;
116 return std::fopen( path.cstr() , mode ) ;
122 static_assert(
noexcept(path.cstr()) ,
"" ) ;
123 static_assert(
noexcept(
File::remove(path,std::nothrow)) ,
"" ) ;
125 int fd = ::open( path.cstr() , O_WRONLY|O_CREAT|O_EXCL , 0666 ) ;
137 int fd = ::open( path.
cstr() , O_RDONLY|O_CREAT , 0666 ) ;
139 throw CannotCreate( path.
str() ) ;
146 return 0 == std::rename( from.cstr() , to.cstr() ) ;
151 return ::read( fd , p , n ) ;
156 return ::write( fd , p , n ) ;
164bool G::FileImp::removeImp(
const char * path ,
int * e )
noexcept
166 bool ok = path && 0 == std::remove( path ) ;
174 return FileImp::removeImp( arg.str() ,
nullptr ) ;
179 static_assert(
noexcept(path.cstr()) ,
"" ) ;
180 return FileImp::removeImp( path.cstr() ,
nullptr ) ;
186 bool ok = FileImp::removeImp( path.
cstr() , &e ) ;
189 G_WARNING(
"G::File::remove: cannot delete file [" << path <<
"]: " <<
Process::strerror(e) ) ;
194int G::File::mkdirImp(
const Path & dir )
noexcept
196 int rc = ::mkdir( dir.cstr() , 0777 ) ;
204 if( e == 0 ) e = EINVAL ;
209G::File::Stat G::File::statImp(
const char * path ,
bool symlink_nofollow )
noexcept
212 struct stat statbuf {} ;
213 if( 0 == ( symlink_nofollow ? (::lstat(path,&statbuf)) : (::stat(path,&statbuf)) ) )
218 s.is_link = (statbuf.st_mode & S_IFMT) == S_IFLNK ;
219 s.is_dir = (statbuf.st_mode & S_IFMT) == S_IFDIR ;
220 s.is_executable = !!(statbuf.st_mode & S_IXUSR) && !!(statbuf.st_mode & S_IRUSR) ;
221 s.is_empty = statbuf.st_size == 0 ;
222 s.mtime_s = FileImp::mtime(statbuf).first ;
223 s.mtime_us = FileImp::mtime(statbuf).second ;
224 s.mode =
static_cast<unsigned long>( statbuf.st_mode & mode_t(07777) ) ;
225 s.size =
static_cast<unsigned long long>( statbuf.st_size ) ;
226 s.blocks =
static_cast<unsigned long long>(statbuf.st_size) >> 24U ;
227 s.uid = statbuf.st_uid ;
228 s.gid = statbuf.st_gid ;
229 s.inherit = s.is_dir && ( G::is_bsd() || ( statbuf.st_mode & S_ISGID ) ) ;
234 s.error = error ? error : EINVAL ;
235 s.enoent = error == ENOENT || error == ENOTDIR ;
236 s.eaccess = error == EACCES ;
241bool G::File::existsImp(
const char * path ,
bool & enoent ,
bool & eaccess )
noexcept
243 Stat s = statImp( path ) ;
247 eaccess = s.eaccess ;
249 return s.error == 0 ;
254 Stat s = statImp( path.cstr() ) ;
255 mode_t mode = s.error ? mode_t(0777) : mode_t(s.mode) ;
257 mode |= ( S_IRUSR | S_IXUSR ) ;
258 if( mode & S_IRGRP ) mode |= S_IXGRP ;
259 if( mode & S_IROTH ) mode |= S_IXOTH ;
262 mode_t mask = ::umask( 0 ) ; ::umask( mask ) ;
265 bool ok = 0 == ::chmod( path.cstr() , mode ) ;
266 if( !ok && do_throw )
267 throw CannotChmod( path.str() ) ;
274 if( !chmod( path , spec , std::nothrow ) )
275 throw CannotChmod( path.
str() ) ;
285 else if( spec.find_first_not_of(
"01234567") == std::string::npos )
287 mode_t mode =
static_cast<mode_t
>( strtoul( spec.c_str() ,
nullptr , 8 ) ) ;
288 return mode <= 07777 && 0 == ::chmod( path.
cstr() , mode ) ;
292 Stat s = statImp( path.
cstr() ) ;
295 std::pair<bool,mode_t> pair = FileImp::newmode( s.mode , spec ) ;
296 return pair.first && 0 == ::chmod( path.
cstr() , pair.second ) ;
300std::pair<bool,mode_t> G::FileImp::newmode( mode_t mode ,
const std::string & spec_in )
302 mode &= mode_t(07777) ;
304 bool ok = !spec_list.empty() ;
305 for(
auto spec : spec_list )
307 if( spec.size() >= 2U &&
308 ( spec.at(0U) ==
'+' || spec.at(0U) ==
'-' || spec.at(0U) ==
'=' ) )
310 spec.insert( 0U ,
"a" ) ;
312 if( spec.size() >= 3U &&
313 ( spec.at(0U) ==
'u' || spec.at(0U) ==
'g' || spec.at(0U) ==
'o' || spec.at(0U) ==
'a' ) &&
314 ( spec.at(1U) ==
'+' || spec.at(1U) ==
'-' || spec.at(1U) ==
'=' ) )
318 for(
const char * p = spec.c_str()+2 ; *p ; p++ )
326 else if( *p ==
's' && spec[0] ==
'u' )
328 else if( *p ==
's' && spec[0] ==
'g' )
330 else if( *p ==
't' && spec[0] ==
'o' )
335 unsigned int shift = spec[0]==
'u' ? 6U : (spec[0]==
'g'?3U:0U) ;
338 mode_t mask = umask(0) ; umask( mask ) ;
339 part = ( ((part<<6U)|(part<<3U)|part) & ~mask ) ;
341 if( spec[1] ==
'=' && spec[0] ==
'a' )
345 else if( spec[1] ==
'=' )
347 mode_t clearbits = (mode_t(7)<<shift) | (spec[0]==
'u'?mode_t(S_ISUID):(spec[0]==
'g'?mode_t(S_ISGID):mode_t(S_ISVTX))) ;
349 mode |= (part<<shift) ;
352 else if( spec[1] ==
'+' )
354 mode |= ( (part<<shift) | special ) ;
358 mode &= ~( (part<<shift) | special ) ;
366 return { ok , mode } ;
374 throw CannotChgrp( path.
str() ) ;
387 return 0 == ::chown( path.
cstr() , -1 , group_id ) ;
392 return 0 == ::link( src.
cstr() , dst.
cstr() ) ;
398 if( linked(target,new_link) )
401 if( exists(new_link) )
404 int error = linkImp( target.
cstr() , new_link.
cstr() ) ;
408 std::ostringstream ss ;
409 ss <<
"[" << new_link <<
"] -> [" << target <<
"] " "(" << error <<
")" ;
410 throw CannotLink( ss.str() ) ;
418 if( linked(target,new_link) )
421 if( exists(new_link) )
424 return 0 == linkImp( target.
cstr() , new_link.
cstr() ) ;
428int G::File::linkImp(
const char * target ,
const char * new_link )
430 int rc = ::symlink( target , new_link ) ;
432 return rc == 0 ? 0 : (error?error:EINVAL) ;
438 Path result = readlink( link , std::nothrow ) ;
440 throw CannotReadLink( link.
str() ) ;
448 struct stat statbuf {} ;
449 int rc = ::lstat( link.
cstr() , &statbuf ) ;
452 std::size_t buffer_size = statbuf.st_size ? (statbuf.st_size+1U) : 1024U ;
453 std::vector<char> buffer( buffer_size ,
'\0' ) ;
454 ssize_t nread = ::readlink( link.
cstr() , buffer.data() , buffer.size() ) ;
457 if( nread > 0 &&
static_cast<std::size_t
>(nread) < buffer.size() )
459 G_ASSERT( buffer.at(
static_cast<std::size_t
>(nread-1)) !=
'\0' ) ;
460 result =
Path( std::string( buffer.data() ,
static_cast<std::size_t
>(nread) ) ) ;
466bool G::File::linked(
const Path & target ,
const Path & new_link )
469 return readlink(new_link,std::nothrow) == target ;
472std::streamoff
G::File::seek(
int fd , std::streamoff offset , Seek origin )
noexcept
474 off_t rc = ::lseek( fd ,
static_cast<off_t
>(offset) ,
475 origin == Seek::Start ? SEEK_SET : ( origin == Seek::End ? SEEK_END : SEEK_CUR ) ) ;
476 return static_cast<std::streamoff
>(rc) ;
482 int flags = ::fcntl( fd , F_GETFL ) ;
485 flags |= O_NONBLOCK ;
486 GDEF_IGNORE_RETURN ::fcntl( fd , F_SETFL , flags ) ;
An overload discriminator for G::File::open().
An overload discriminator for G::File::open().
static void open(std::ofstream &, const Path &)
Calls open() on the given output file stream.
static void close(int fd) noexcept
Calls ::close() or equivalent.
static void link(const Path &target, const Path &new_link)
Creates a symlink.
static std::streamoff seek(int fd, std::streamoff offset, Seek) noexcept
Does ::lseek() or equivalent.
static void setNonBlocking(int fd) noexcept
Sets the file descriptor to non-blocking mode.
static ssize_t write(int fd, const char *, std::size_t) noexcept
Calls ::write() or equivalent.
static void chmod(const Path &file, const std::string &spec)
Sets the file permissions.
static bool remove(const Path &path, std::nothrow_t) noexcept
Deletes the file or directory. Returns false on error.
static void chmodx(const Path &file)
Makes the file executable. Throws on error.
static ssize_t read(int fd, char *, std::size_t) noexcept
Calls read() or equivalent.
static bool renameOnto(const Path &from, const Path &to, std::nothrow_t) noexcept
Renames the file, deleting 'to' first if necessary.
static void create(const Path &)
Creates the file if it does not exist.
static G::Path readlink(const Path &link)
Reads a symlink. Throws on error.
static std::FILE * fopen(const Path &, const char *mode) noexcept
Calls std::fopen().
static bool hardlink(const Path &src, const Path &dst, std::nothrow_t)
Creates a hard link.
static bool probe(const Path &) noexcept
Creates and deletes a temporary probe file.
static bool cleanup(const Cleanup::Arg &path_arg) noexcept
Deletes the file.
static void chgrp(const Path &file, const std::string &group)
Sets the file group ownership. Throws on error.
static gid_t lookupGroup(const std::string &group)
Does a groupname lookup.
A Path object represents a file system path.
const value_type * cstr() const noexcept
Returns the path's c-string.
std::string str() const
Returns the path string.
bool empty() const noexcept
Returns true if the path is empty.
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
static void splitIntoFields(std::string_view in, StringArray &out, char sep, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
std::vector< std::string > StringArray
A std::vector of std::strings.
Opaque leaky string pointer wrapper created by G::Cleanup::arg().
An overload discriminator for G::File::open().
A portable 'struct stat'.