E-MailRelay

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gfile_unix.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2018 Graeme Walker <graeme_walker@users.sourceforge.net>
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::isLink( const Path & path )
68 {
69 struct stat statbuf ;
70 return 0 == ::stat( path.str().c_str() , &statbuf ) && (statbuf.st_mode & S_IFLNK) ;
71 }
72
73 bool G::File::isDirectory( const Path & path )
74 {
75 struct stat statbuf ;
76 return 0 == ::stat( path.str().c_str() , &statbuf ) && (statbuf.st_mode & S_IFDIR) ;
77 }
78
79 bool G::File::executable( const Path & path )
80 {
81 struct stat statbuf ;
82 if( 0 == ::stat( path.str().c_str() , &statbuf ) )
83 {
84 bool x = !!( statbuf.st_mode & S_IXUSR ) ;
85 bool r =
86 ( statbuf.st_mode & S_IFMT ) == S_IFREG ||
87 ( statbuf.st_mode & S_IFMT ) == S_IFLNK ;
88 return x && r ; // indicitive only
89 }
90 else
91 {
92 return false ;
93 }
94 }
95
96 std::string G::File::sizeString( const Path & path )
97 {
98 struct stat statbuf ;
99 if( 0 != ::stat( path.str().c_str() , &statbuf ) )
100 return std::string() ;
101
102 std::ostringstream ss ;
103 ss << statbuf.st_size ;
104 return ss.str() ;
105 }
106
107 G::EpochTime G::File::time( const Path & path )
108 {
109 struct stat statbuf ;
110 if( 0 != ::stat( path.str().c_str() , &statbuf ) )
111 throw TimeError( path.str() ) ;
112 return mtime( statbuf ) ;
113 }
114
115 G::EpochTime G::File::time( const Path & path , const NoThrow & )
116 {
117 struct stat statbuf ;
118 if( ::stat( path.str().c_str() , &statbuf ) != 0 )
119 return EpochTime( 0 ) ;
120 return mtime( statbuf ) ;
121 }
122
123 bool G::File::chmodx( const Path & path , bool do_throw )
124 {
125 struct stat statbuf ;
126 mode_t mode =
127 0 == ::stat( path.str().c_str() , &statbuf ) ?
128 statbuf.st_mode :
129 mode_t(0777) ; // default to open permissions, but limited by umask
130
131 mode |= ( S_IRUSR | S_IXUSR ) ; // add user-read and user-executable
132 if( mode & S_IRGRP ) mode |= S_IXGRP ; // add group-executable iff group-read
133 if( mode & S_IROTH ) mode |= S_IXOTH ; // add world-executable iff world-read
134
135 // apply the current umask
136 mode_t mask = ::umask( ::umask(0) ) ;
137 mode &= ~mask ;
138
139 bool ok = 0 == ::chmod( path.str().c_str() , mode ) ;
140 if( !ok && do_throw )
141 throw CannotChmod( path.str() ) ;
142 return ok ;
143 }
144
145 void G::File::link( const Path & target , const Path & new_link )
146 {
147 if( linked(target,new_link) ) // optimisation
148 return ;
149
150 if( exists(new_link) )
151 remove( new_link , NoThrow() ) ;
152
153 int error = link( target.str().c_str() , new_link.str().c_str() ) ;
154
155 if( error != 0 )
156 {
157 std::ostringstream ss ;
158 ss << "[" << new_link << "] -> [" << target << "] " "(" << error << ")" ;
159 throw CannotLink( ss.str() ) ;
160 }
161 }
162
163 bool G::File::link( const Path & target , const Path & new_link , const NoThrow & )
164 {
165 if( linked(target,new_link) ) // optimisation
166 return true ;
167
168 if( exists(new_link) )
169 remove( new_link , NoThrow() ) ;
170
171 return 0 == link( target.str().c_str() , new_link.str().c_str() ) ;
172 }
173
174 int G::File::link( const char * target , const char * new_link )
175 {
176 int rc = ::symlink( target , new_link ) ;
177 int error = G::Process::errno_() ;
178 return rc == 0 ? 0 : (error?error:EINVAL) ;
179 }
180
181 bool G::File::linked( const Path & target , const Path & new_link )
182 {
183 // see if already linked correctly - errors and overflows are not fatal
184 std::vector<char> buffer( limits::path , '\0' ) ;
185 ssize_t rc = ::readlink( new_link.str().c_str() , &buffer[0] , buffer.size() ) ;
186 size_t n = rc < 0 ? size_t(0U) : static_cast<size_t>(rc) ;
187 if( rc > 0 && n != buffer.size() )
188 {
189 std::string old_target( &buffer[0] , n ) ;
190 if( target.str() == old_target )
191 return true ;
192 }
193 return false ;
194 }
195
196 /// \file gfile_unix.cpp
G::Path::str
std::string str() const
Returns the path string.
Definition: gpath.cpp:290
G::EpochTime
A subsecond-resolution timestamp based on a time_t.
Definition: gdatetime.h:39
G::File::isDirectory
static bool isDirectory(const Path &path)
Returns true if the path exists() and is a directory.
Definition: gfile_unix.cpp:73
G::File::isLink
static bool isLink(const Path &path)
Returns true if the path is an existing symlink.
Definition: gfile_unix.cpp:67
glimits.h
G::File::executable
static bool executable(const Path &)
Returns true if the path is probably executable.
Definition: gfile_unix.cpp:79
gfile.h
gprocess.h
G::File::exists
static bool exists(const Path &file)
Returns true if the file (directory, device etc.) exists.
Definition: gfile.cpp:141
G::File::mkdir
static bool mkdir(const Path &dir, const NoThrow &)
Creates a directory. Returns false on error.
Definition: gfile_unix.cpp:45
G::File::NoThrow
An overload discriminator class for File methods.
Definition: gfile.h:53
G::File::chmodx
static void chmodx(const Path &file)
Makes the file executable.
Definition: gfile.cpp:176
G::File::link
static void link(const Path &target, const Path &new_link)
Creates a symlink.
Definition: gfile_unix.cpp:145
G::File::sizeString
static std::string sizeString(const Path &file)
Returns the file's size in string format.
Definition: gfile_unix.cpp:96
G::File::time
static EpochTime time(const Path &file)
Returns the file's timestamp.
Definition: gfile_unix.cpp:107
G::Path
A Path object represents a file system path.
Definition: gpath.h:72
gdebug.h