VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gfile_unix.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gfile_unix.cpp
19 //
20 
21 #include "gdef.h"
22 #include "glimits.h"
23 #include "gfile.h"
24 #include "gprocess.h"
25 #include "gdebug.h"
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <vector>
31 #include <sstream>
32 
33 namespace
34 {
35  G::EpochTime mtime( struct stat & statbuf )
36  {
37 #if GCONFIG_HAVE_STATBUF_NSEC
38  return G::EpochTime( statbuf.st_mtime , statbuf.st_mtim.tv_nsec/1000U ) ;
39 #else
40  return G::EpochTime( statbuf.st_mtime ) ;
41 #endif
42  }
43 }
44 
45 bool G::File::mkdir( const Path & dir , const NoThrow & )
46 {
47  // open permissions, but limited by umask
48  return 0 == ::mkdir( dir.str().c_str() , 0777 ) ;
49 }
50 
51 bool G::File::exists( const char * path , bool & enoent , bool & eaccess )
52 {
53  struct stat statbuf ;
54  if( 0 == ::stat( path , &statbuf ) )
55  {
56  return true ;
57  }
58  else
59  {
60  int error = G::Process::errno_() ;
61  enoent = error == ENOENT || error == ENOTDIR ;
62  eaccess = error == EACCES ;
63  return false ;
64  }
65 }
66 
67 bool G::File::isDirectory( const Path & path )
68 {
69  struct stat statbuf ;
70  return 0 == ::stat( path.str().c_str() , &statbuf ) && (statbuf.st_mode & S_IFDIR) ;
71 }
72 
73 bool G::File::executable( const Path & path )
74 {
75  struct stat statbuf ;
76  if( 0 == ::stat( path.str().c_str() , &statbuf ) )
77  {
78  bool x = !!( statbuf.st_mode & S_IXUSR ) ;
79  bool r =
80  ( statbuf.st_mode & S_IFMT ) == S_IFREG ||
81  ( statbuf.st_mode & S_IFMT ) == S_IFLNK ;
82  return x && r ; // indicitive only
83  }
84  else
85  {
86  return false ;
87  }
88 }
89 
90 std::string G::File::sizeString( const Path & path )
91 {
92  struct stat statbuf ;
93  if( 0 != ::stat( path.str().c_str() , &statbuf ) )
94  return std::string() ;
95 
96  std::ostringstream ss ;
97  ss << statbuf.st_size ;
98  return ss.str() ;
99 }
100 
102 {
103  struct stat statbuf ;
104  if( 0 != ::stat( path.str().c_str() , &statbuf ) )
105  throw TimeError( path.str() ) ;
106  return mtime( statbuf ) ;
107 }
108 
109 G::EpochTime G::File::time( const Path & path , const NoThrow & )
110 {
111  struct stat statbuf ;
112  if( ::stat( path.str().c_str() , &statbuf ) != 0 )
113  return EpochTime( 0 ) ;
114  return mtime( statbuf ) ;
115 }
116 
117 bool G::File::chmodx( const Path & path , bool do_throw )
118 {
119  mode_t mode = 0 ;
120  struct stat statbuf ;
121  if( 0 == ::stat( path.str().c_str() , &statbuf ) )
122  {
123  mode = statbuf.st_mode | S_IRUSR | S_IXUSR ; // add user-read and user-executable
124  if( mode & S_IRGRP ) mode |= S_IXGRP ; // add group-executable iff group-read
125  if( mode & S_IROTH ) mode |= S_IXOTH ; // add world-executable iff world-read
126  }
127  else
128  {
129  // shouldnt really get here -- default to open permissions, but limited by umask
130  mode = 0777 ;
131  }
132 
133  // apply the current umask
134  mode_t mask = ::umask( ::umask(0) ) ;
135  mode &= ~mask ;
136 
137  bool ok = 0 == ::chmod( path.str().c_str() , mode ) ;
138  if( !ok && do_throw )
139  throw CannotChmod( path.str() ) ;
140  return ok ;
141 }
142 
143 void G::File::link( const Path & target , const Path & new_link )
144 {
145  if( !link(target,new_link,NoThrow()) )
146  {
147  int error = G::Process::errno_() ; // keep first
148  std::ostringstream ss ;
149  ss << "[" << new_link << "] -> [" << target << "] " "(" << error << ")" ;
150  throw CannotLink( ss.str() ) ;
151  }
152 }
153 
154 bool G::File::link( const Path & target , const Path & new_link , const NoThrow & )
155 {
156  // see if already linked correctly, as an optimisation - errors and overflows are not fatal
157  std::vector<char> buffer( limits::path , '\0' ) ;
158  ssize_t rc = ::readlink( new_link.str().c_str() , &buffer[0] , buffer.size() ) ;
159  size_t n = rc < 0 ? size_t(0U) : static_cast<size_t>(rc) ;
160  if( rc > 0 && n != buffer.size() )
161  {
162  std::string old_target( &buffer[0] , n ) ;
163  if( target.str() == old_target )
164  return true ;
165  }
166 
167  if( exists(new_link) )
168  remove( new_link , NoThrow() ) ;
169 
170  rc = ::symlink( target.str().c_str() , new_link.str().c_str() ) ;
171  // dont put anything here (preserve errno)
172  return rc == 0 ;
173 }
174 
175 /// \file gfile_unix.cpp
std::string str() const
Returns the path string.
Definition: gpath.cpp:290
A subsecond-resolution timestamp based on a time_t.
Definition: gdatetime.h:39
static bool isDirectory(const Path &path)
Returns true if the path exists() and is a directory.
Definition: gfile_unix.cpp:67
static bool executable(const Path &)
Returns true if the path is probably executable.
Definition: gfile_unix.cpp:73
static bool exists(const Path &file)
Returns true if the file (directory, device etc.) exists.
Definition: gfile.cpp:132
static bool mkdir(const Path &dir, const NoThrow &)
Creates a directory. Returns false on error.
Definition: gfile_unix.cpp:45
An overload discriminator class for File methods.
Definition: gfile.h:53
static void chmodx(const Path &file)
Makes the file executable.
Definition: gfile.cpp:167
static void link(const Path &target, const Path &new_link)
Creates a symlink.
Definition: gfile_unix.cpp:143
static std::string sizeString(const Path &file)
Returns the file's size in string format.
Definition: gfile_unix.cpp:90
static EpochTime time(const Path &file)
Returns the file's timestamp.
Definition: gfile_unix.cpp:101
A Path object represents a file system path.
Definition: gpath.h:72