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 ) ;
77 ifstream.open( path.
cstr() , std::ios_base::in ) ;
84 fb.open( path.
cstr() , std::ios_base::in | std::ios_base::binary ) :
85 fb.open( path.
cstr() , std::ios_base::out | std::ios_base::binary ) ;
90 if( mode == InOutAppend::In )
91 return ::open( path , O_RDONLY ) ;
92 else if( mode == InOutAppend::Out )
93 return ::open( path , O_WRONLY|O_CREAT|O_TRUNC , 0666 ) ;
95 return ::open( path , O_WRONLY|O_CREAT|O_APPEND , 0666 ) ;
100 int fd = ::open( path , O_WRONLY|O_CREAT|O_EXCL , 0666 ) ;
103 std::remove( path ) ;
110 int fd = ::open( path.
cstr() , O_RDONLY|O_CREAT , 0666 ) ;
112 throw CannotCreate( path.
str() ) ;
118 return ::read( fd , p , n ) ;
123 return ::write( fd , p , n ) ;
131int G::File::mkdirImp(
const Path & dir )
noexcept
133 int rc = ::mkdir( dir.cstr() , 0777 ) ;
141 if( e == 0 ) e = EINVAL ;
146G::File::Stat G::File::statImp(
const char * path ,
bool link )
noexcept
149 struct stat statbuf {} ;
150 if( 0 == ( link ? (::lstat(path,&statbuf)) : (::stat(path,&statbuf)) ) )
155 s.is_link = (statbuf.st_mode & S_IFMT) == S_IFLNK ;
156 s.is_dir = (statbuf.st_mode & S_IFMT) == S_IFDIR ;
157 s.is_executable = !!(statbuf.st_mode & S_IXUSR) && !!(statbuf.st_mode & S_IRUSR) ;
158 s.is_empty = statbuf.st_size == 0 ;
159 s.mtime_s = FileImp::mtime(statbuf).first ;
160 s.mtime_us = FileImp::mtime(statbuf).second ;
161 s.mode =
static_cast<unsigned long>( statbuf.st_mode & mode_t(07777) ) ;
162 s.size =
static_cast<unsigned long long>( statbuf.st_size ) ;
163 s.blocks =
static_cast<unsigned long long>(statbuf.st_size) >> 24U ;
168 s.error = error ? error : EINVAL ;
169 s.enoent = error == ENOENT || error == ENOTDIR ;
170 s.eaccess = error == EACCES ;
175bool G::File::existsImp(
const char * path ,
bool & enoent ,
bool & eaccess )
noexcept
177 Stat s = statImp( path ) ;
181 eaccess = s.eaccess ;
183 return s.error == 0 ;
188 Stat s = statImp( path.cstr() ) ;
189 mode_t mode = s.error ? mode_t(0777) : mode_t(s.mode) ;
191 mode |= ( S_IRUSR | S_IXUSR ) ;
192 if( mode & S_IRGRP ) mode |= S_IXGRP ;
193 if( mode & S_IROTH ) mode |= S_IXOTH ;
196 mode_t mask = ::umask( 0 ) ; ::umask( mask ) ;
199 bool ok = 0 == ::chmod( path.cstr() , mode ) ;
200 if( !ok && do_throw )
201 throw CannotChmod( path.str() ) ;
207 if( !chmod( path , spec , std::nothrow ) )
208 throw CannotChmod( path.
str() ) ;
217 else if( spec.find_first_not_of(
"01234567") == std::string::npos )
219 mode_t mode =
static_cast<mode_t
>( strtoul( spec.c_str() ,
nullptr , 8 ) ) ;
220 return mode <= 07777 && 0 == ::chmod( path.
cstr() , mode ) ;
224 Stat s = statImp( path.
cstr() ) ;
227 std::pair<bool,mode_t> pair = FileImp::newmode( s.mode , spec ) ;
228 return pair.first && 0 == ::chmod( path.
cstr() , pair.second ) ;
232std::pair<bool,mode_t> G::FileImp::newmode( mode_t mode ,
const std::string & spec_in )
234 mode &= mode_t(07777) ;
236 bool ok = !spec_list.empty() ;
237 for(
auto spec : spec_list )
239 if( spec.size() >= 2U &&
240 ( spec.at(0U) ==
'+' || spec.at(0U) ==
'-' || spec.at(0U) ==
'=' ) )
242 spec.insert( 0U ,
"a" ) ;
244 if( spec.size() >= 3U &&
245 ( spec.at(0U) ==
'u' || spec.at(0U) ==
'g' || spec.at(0U) ==
'o' || spec.at(0U) ==
'a' ) &&
246 ( spec.at(1U) ==
'+' || spec.at(1U) ==
'-' || spec.at(1U) ==
'=' ) )
250 for(
const char * p = spec.c_str()+2 ; *p ; p++ )
258 else if( *p ==
's' && spec[0] ==
'u' )
260 else if( *p ==
's' && spec[0] ==
'g' )
262 else if( *p ==
't' && spec[0] ==
'o' )
267 unsigned int shift = spec[0]==
'u' ? 6U : (spec[0]==
'g'?3U:0U) ;
270 mode_t mask = umask(0) ; umask( mask ) ;
271 part = ( ((part<<6U)|(part<<3U)|part) & ~mask ) ;
273 if( spec[1] ==
'=' && spec[0] ==
'a' )
277 else if( spec[1] ==
'=' )
279 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))) ;
281 mode |= (part<<shift) ;
284 else if( spec[1] ==
'+' )
286 mode |= ( (part<<shift) | special ) ;
290 mode &= ~( (part<<shift) | special ) ;
298 return { ok , mode } ;
305 throw CannotChgrp( path.
str() ) ;
315 if( linked(target,new_link) )
318 if( exists(new_link) )
319 remove( new_link , std::nothrow ) ;
321 int error = linkImp( target.
cstr() , new_link.
cstr() ) ;
325 std::ostringstream ss ;
326 ss <<
"[" << new_link <<
"] -> [" << target <<
"] " "(" << error <<
")" ;
327 throw CannotLink( ss.str() ) ;
333 if( linked(target,new_link) )
336 if( exists(new_link) )
337 remove( new_link , std::nothrow ) ;
339 return 0 == linkImp( target.
cstr() , new_link.
cstr() ) ;
342int G::File::linkImp(
const char * target ,
const char * new_link )
344 int rc = ::symlink( target , new_link ) ;
346 return rc == 0 ? 0 : (error?error:EINVAL) ;
351 Path result = readlink( link , std::nothrow ) ;
353 throw CannotReadLink( link.
str() ) ;
360 struct stat statbuf {} ;
361 int rc = ::lstat( link.
cstr() , &statbuf ) ;
364 std::size_t buffer_size = statbuf.st_size ? (statbuf.st_size+1U) : 1024U ;
365 std::vector<char> buffer( buffer_size ,
'\0' ) ;
366 ssize_t nread = ::readlink( link.
cstr() , &buffer[0] , buffer.size() ) ;
369 if( nread > 0 &&
static_cast<std::size_t
>(nread) < buffer.size() )
371 G_ASSERT( buffer.at(
static_cast<std::size_t
>(nread-1)) !=
'\0' ) ;
372 result =
Path( std::string( &buffer[0] ,
static_cast<std::size_t
>(nread) ) ) ;
378bool G::File::linked(
const Path & target ,
const Path & new_link )
381 return readlink(new_link,std::nothrow) == target ;
An overload discriminator for G::File::open().
An overload discriminator for G::File::open().
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 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 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 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. Throws on error.
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(const std::string &in, StringArray &out, string_view ws, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
std::vector< std::string > StringArray
A std::vector of std::strings.
A portable 'struct stat'.