39 std::pair<bool,mode_t> newmode( mode_t ,
const std::string & ) ;
40 std::pair<std::time_t,unsigned int> mtime(
struct stat & statbuf )
noexcept
42 #if GCONFIG_HAVE_STATBUF_TIMESPEC
43 return { statbuf.st_mtimespec.tv_sec , statbuf.st_mtimespec.tv_nsec/1000U } ;
45 #if GCONFIG_HAVE_STATBUF_NSEC
46 return { statbuf.st_mtime , statbuf.st_mtim.tv_nsec/1000U } ;
48 return { statbuf.st_mtime , 0U } ;
57 ofstream.open( path.
cstr() , std::ios_base::out | std::ios_base::binary ) ;
62 ofstream.open( path.
cstr() , std::ios_base::out ) ;
67 ofstream.open( path.
cstr() , std::ios_base::app | std::ios_base::binary ) ;
72 ifstream.open( path.
cstr() , std::ios_base::in | std::ios_base::binary ) ;
78 ifstream.open( path.
cstr() , std::ios_base::in ) ;
86 fb.open( path.
cstr() , std::ios_base::in | std::ios_base::binary ) :
87 fb.open( path.
cstr() , std::ios_base::out | std::ios_base::binary ) ;
92 if( mode == InOutAppend::In )
93 return ::open( path , O_RDONLY ) ;
94 else if( mode == InOutAppend::Out )
95 return ::open( path , O_WRONLY|O_CREAT|O_TRUNC , 0666 ) ;
97 return ::open( path , O_WRONLY|O_CREAT|O_APPEND , 0666 ) ;
103 return ::open( path , O_WRONLY|O_CREAT|O_EXCL , 0666 ) ;
110 return std::fopen( path , mode ) ;
116 int fd = ::open( path , O_WRONLY|O_CREAT|O_EXCL , 0666 ) ;
119 std::remove( path ) ;
127 int fd = ::open( path.
cstr() , O_RDONLY|O_CREAT , 0666 ) ;
129 throw CannotCreate( path.
str() ) ;
136 return 0 == std::rename( from.cstr() , to.cstr() ) ;
141 return ::read( fd , p , n ) ;
146 return ::write( fd , p , n ) ;
154int G::File::mkdirImp(
const Path & dir )
noexcept
156 int rc = ::mkdir( dir.cstr() , 0777 ) ;
164 if( e == 0 ) e = EINVAL ;
169G::File::Stat G::File::statImp(
const char * path ,
bool read_symlink )
noexcept
172 struct stat statbuf {} ;
173 if( 0 == ( read_symlink ? (::lstat(path,&statbuf)) : (::stat(path,&statbuf)) ) )
178 s.is_link = (statbuf.st_mode & S_IFMT) == S_IFLNK ;
179 s.is_dir = (statbuf.st_mode & S_IFMT) == S_IFDIR ;
180 s.is_executable = !!(statbuf.st_mode & S_IXUSR) && !!(statbuf.st_mode & S_IRUSR) ;
181 s.is_empty = statbuf.st_size == 0 ;
182 s.mtime_s = FileImp::mtime(statbuf).first ;
183 s.mtime_us = FileImp::mtime(statbuf).second ;
184 s.mode =
static_cast<unsigned long>( statbuf.st_mode & mode_t(07777) ) ;
185 s.size =
static_cast<unsigned long long>( statbuf.st_size ) ;
186 s.blocks =
static_cast<unsigned long long>(statbuf.st_size) >> 24U ;
187 s.uid = statbuf.st_uid ;
188 s.gid = statbuf.st_gid ;
189 s.inherit = s.is_dir && ( G::is_bsd() || ( statbuf.st_mode & S_ISGID ) ) ;
194 s.error = error ? error : EINVAL ;
195 s.enoent = error == ENOENT || error == ENOTDIR ;
196 s.eaccess = error == EACCES ;
201bool G::File::existsImp(
const char * path ,
bool & enoent ,
bool & eaccess )
noexcept
203 Stat s = statImp( path ) ;
207 eaccess = s.eaccess ;
209 return s.error == 0 ;
214 Stat s = statImp( path.cstr() ) ;
215 mode_t mode = s.error ? mode_t(0777) : mode_t(s.mode) ;
217 mode |= ( S_IRUSR | S_IXUSR ) ;
218 if( mode & S_IRGRP ) mode |= S_IXGRP ;
219 if( mode & S_IROTH ) mode |= S_IXOTH ;
222 mode_t mask = ::umask( 0 ) ; ::umask( mask ) ;
225 bool ok = 0 == ::chmod( path.cstr() , mode ) ;
226 if( !ok && do_throw )
227 throw CannotChmod( path.str() ) ;
234 if( !chmod( path , spec , std::nothrow ) )
235 throw CannotChmod( path.
str() ) ;
245 else if( spec.find_first_not_of(
"01234567") == std::string::npos )
247 mode_t mode =
static_cast<mode_t
>( strtoul( spec.c_str() ,
nullptr , 8 ) ) ;
248 return mode <= 07777 && 0 == ::chmod( path.
cstr() , mode ) ;
252 Stat s = statImp( path.
cstr() ) ;
255 std::pair<bool,mode_t> pair = FileImp::newmode( s.mode , spec ) ;
256 return pair.first && 0 == ::chmod( path.
cstr() , pair.second ) ;
260std::pair<bool,mode_t> G::FileImp::newmode( mode_t mode ,
const std::string & spec_in )
262 mode &= mode_t(07777) ;
264 bool ok = !spec_list.empty() ;
265 for(
auto spec : spec_list )
267 if( spec.size() >= 2U &&
268 ( spec.at(0U) ==
'+' || spec.at(0U) ==
'-' || spec.at(0U) ==
'=' ) )
270 spec.insert( 0U ,
"a" ) ;
272 if( spec.size() >= 3U &&
273 ( spec.at(0U) ==
'u' || spec.at(0U) ==
'g' || spec.at(0U) ==
'o' || spec.at(0U) ==
'a' ) &&
274 ( spec.at(1U) ==
'+' || spec.at(1U) ==
'-' || spec.at(1U) ==
'=' ) )
278 for(
const char * p = spec.c_str()+2 ; *p ; p++ )
286 else if( *p ==
's' && spec[0] ==
'u' )
288 else if( *p ==
's' && spec[0] ==
'g' )
290 else if( *p ==
't' && spec[0] ==
'o' )
295 unsigned int shift = spec[0]==
'u' ? 6U : (spec[0]==
'g'?3U:0U) ;
298 mode_t mask = umask(0) ; umask( mask ) ;
299 part = ( ((part<<6U)|(part<<3U)|part) & ~mask ) ;
301 if( spec[1] ==
'=' && spec[0] ==
'a' )
305 else if( spec[1] ==
'=' )
307 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))) ;
309 mode |= (part<<shift) ;
312 else if( spec[1] ==
'+' )
314 mode |= ( (part<<shift) | special ) ;
318 mode &= ~( (part<<shift) | special ) ;
326 return { ok , mode } ;
334 throw CannotChgrp( path.
str() ) ;
347 return 0 == ::chown( path.
cstr() , -1 , group_id ) ;
352 return 0 == ::link( src.
cstr() , dst.
cstr() ) ;
358 if( linked(target,new_link) )
361 if( exists(new_link) )
362 remove( new_link , std::nothrow ) ;
364 int error = linkImp( target.
cstr() , new_link.
cstr() ) ;
368 std::ostringstream ss ;
369 ss <<
"[" << new_link <<
"] -> [" << target <<
"] " "(" << error <<
")" ;
370 throw CannotLink( ss.str() ) ;
378 if( linked(target,new_link) )
381 if( exists(new_link) )
382 remove( new_link , std::nothrow ) ;
384 return 0 == linkImp( target.
cstr() , new_link.
cstr() ) ;
388int G::File::linkImp(
const char * target ,
const char * new_link )
390 int rc = ::symlink( target , new_link ) ;
392 return rc == 0 ? 0 : (error?error:EINVAL) ;
398 Path result = readlink( link , std::nothrow ) ;
400 throw CannotReadLink( link.
str() ) ;
408 struct stat statbuf {} ;
409 int rc = ::lstat( link.
cstr() , &statbuf ) ;
412 std::size_t buffer_size = statbuf.st_size ? (statbuf.st_size+1U) : 1024U ;
413 std::vector<char> buffer( buffer_size ,
'\0' ) ;
414 ssize_t nread = ::readlink( link.
cstr() , &buffer[0] , buffer.size() ) ;
417 if( nread > 0 &&
static_cast<std::size_t
>(nread) < buffer.size() )
419 G_ASSERT( buffer.at(
static_cast<std::size_t
>(nread-1)) !=
'\0' ) ;
420 result =
Path( std::string( &buffer[0] ,
static_cast<std::size_t
>(nread) ) ) ;
426bool G::File::linked(
const Path & target ,
const Path & new_link )
429 return readlink(new_link,std::nothrow) == target ;
432std::streamoff
G::File::seek(
int fd , std::streamoff offset , Seek origin )
noexcept
434 off_t rc = ::lseek( fd ,
static_cast<off_t
>(offset) ,
435 origin == Seek::Start ? SEEK_SET : ( origin == Seek::End ? SEEK_END : SEEK_CUR ) ) ;
436 return static_cast<std::streamoff
>(rc) ;
442 int flags = ::fcntl( fd , F_GETFL ) ;
443 flags |= O_NONBLOCK ;
444 GDEF_IGNORE_RETURN ::fcntl( fd , F_SETFL , flags ) ;
An overload discriminator for G::File::open().
An overload discriminator for G::File::open().
static std::FILE * fopen(const char *, const char *mode) noexcept
Calls std::fopen().
static bool probe(const char *) noexcept
Creates and deletes a temporary probe file.
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 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 bool hardlink(const Path &src, const Path &dst, std::nothrow_t)
Creates a hard link.
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 char * cstr() const noexcept
Returns the path string.
std::string str() const
Returns the path string.
bool empty() const noexcept
Returns true if size() is zero.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
static void splitIntoFields(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.
An overload discriminator for G::File::open().
A portable 'struct stat'.