E-MailRelay

gdirectory_unix.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 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/// \file gdirectory_unix.cpp
19///
20
21#include "gdef.h"
22#include "gdirectory.h"
23#include "gprocess.h"
24#include "gdatetime.h"
25#include "gfile.h"
26#include "glog.h"
27#include <sstream>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <dirent.h>
31#include <unistd.h>
32#include <fcntl.h>
33
34 namespace G
35{
36 class DirectoryIteratorImp ;
37}
38
39//| \class G::DirectoryIteratorImp
40/// A pimple-pattern implementation class for DirectoryIterator using
41/// opendir()/readdir().
42///
43 class G::DirectoryIteratorImp
44{
45 public:
46 explicit DirectoryIteratorImp( const Directory & dir ) ;
47 ~DirectoryIteratorImp() ;
48 bool isDir() const ;
49 bool more() ;
50 bool error() const ;
51 std::string sizeString() const ;
52 Path filePath() const ;
53 std::string fileName() const ;
54
55 public:
56 DirectoryIteratorImp( const DirectoryIteratorImp & ) = delete ;
57 DirectoryIteratorImp( DirectoryIteratorImp && ) = delete ;
58 void operator=( const DirectoryIteratorImp & ) = delete ;
59 void operator=( DirectoryIteratorImp && ) = delete ;
60
61 private:
62 DIR * m_d ;
63 struct dirent * m_dp ;
64 Directory m_dir ;
65 bool m_error ;
66 bool m_is_dir ;
67} ;
68
69//
70
71 int G::Directory::usable( bool for_creation ) const
72{
73 if( m_path.empty() )
74 return ENOTDIR ;
75
76 // use opendir("foo/.") rather than opendir("foo") to verify
77 // that any contained files can be stat()ed -- ie. that all
78 // directory parts in the m_path have '--x'
79 std::string path_dot = m_path.str() + (m_path.str()=="/"?"":"/") + "." ;
80
81 DIR * p = ::opendir( path_dot.c_str() ) ;
82 int error = p ? 0 : Process::errno_() ;
83 if( p )
84 ::closedir( p ) ;
85
86 if( !error && for_creation )
87 {
88 // (not definitive -- see also GNU/Linux ::euidaccess())
89 int rc = ::access( m_path.cstr() , W_OK ) ;
90 error = rc == 0 ? 0 : Process::errno_() ;
91 }
92 return error ;
93}
94
95 bool G::Directory::writeable( const std::string & filename ) const
96{
97 Path path( m_path , filename.empty() ? tmp() : filename ) ;
98 return File::probe( path.cstr() ) ;
99}
100
101// ===
102
103 G::DirectoryIterator::DirectoryIterator( const Directory & dir ) :
104 m_imp(std::make_unique<DirectoryIteratorImp>(dir))
105{
106}
107
108 G::DirectoryIterator::~DirectoryIterator()
109= default ;
110
111 bool G::DirectoryIterator::error() const
112{
113 return m_imp->error() ;
114}
115
116 bool G::DirectoryIterator::more()
117{
118 return m_imp->more() ;
119}
120
121 G::Path G::DirectoryIterator::filePath() const
122{
123 return m_imp->filePath() ;
124}
125
126std::string G::DirectoryIterator::fileName() const
127{
128 return m_imp->fileName() ;
129}
130
131 bool G::DirectoryIterator::isDir() const
132{
133 return m_imp->isDir() ;
134}
135
136std::string G::DirectoryIterator::sizeString() const
137{
138 return m_imp->sizeString() ;
139}
140
141// ===
142
143G::DirectoryIteratorImp::DirectoryIteratorImp( const Directory & dir ) :
144 m_d(nullptr) ,
145 m_dp(nullptr) ,
146 m_dir(dir) ,
147 m_error(true) ,
148 m_is_dir(false)
149{
150 m_d = ::opendir( dir.path().cstr() ) ;
151 m_error = m_d == nullptr ;
152}
153
154 bool G::DirectoryIteratorImp::error() const
155{
156 return m_error ;
157}
158
159 bool G::DirectoryIteratorImp::more()
160{
161 while( !m_error )
162 {
163 m_dp = ::readdir( m_d ) ;
164 m_error = m_dp == nullptr ;
165 bool special = !m_error && ( fileName() == "." || fileName() == ".." ) ;
166 m_is_dir = !m_error && ( special || File::isDirectory(filePath(),std::nothrow) ) ;
167 if( !special )
168 break ;
169 }
170 return !m_error ;
171}
172
173 G::Path G::DirectoryIteratorImp::filePath() const
174{
175 return m_dir.path() + fileName() ;
176}
177
178std::string G::DirectoryIteratorImp::fileName() const
179{
180 return m_dp == nullptr ? std::string() : std::string(m_dp->d_name) ;
181}
182
183 bool G::DirectoryIteratorImp::isDir() const
184{
185 return m_is_dir ;
186}
187
188G::DirectoryIteratorImp::~DirectoryIteratorImp()
189{
190 if( m_d != nullptr )
191 ::closedir( m_d ) ;
192}
193
194std::string G::DirectoryIteratorImp::sizeString() const
195{
196 std::string s = File::sizeString( filePath() ) ;
197 return s.empty() ? std::string("0") : s ;
198}
199
G::DirectoryIteratorImp
A pimple-pattern implementation class for DirectoryIterator using opendir()/readdir().
Definition: gdirectory_unix.cpp:44
G::DirectoryIterator::DirectoryIterator
DirectoryIterator(const Directory &dir)
Constructor taking a directory reference.
Definition: gdirectory_unix.cpp:103
G::DirectoryIterator::fileName
std::string fileName() const
Returns the name of the current item.
Definition: gdirectory_unix.cpp:126
G::DirectoryIterator::error
bool error() const
Returns true on error. The caller should stop the iteration.
Definition: gdirectory_unix.cpp:111
G::DirectoryIterator::sizeString
std::string sizeString() const
Returns the file size as a decimal string.
Definition: gdirectory_unix.cpp:136
G::DirectoryIterator::~DirectoryIterator
~DirectoryIterator()
Destructor.
G::DirectoryIterator::isDir
bool isDir() const
Returns true if the current item is a directory.
Definition: gdirectory_unix.cpp:131
G::DirectoryIterator::more
bool more()
Returns true if more and advances by one.
Definition: gdirectory_unix.cpp:116
G::DirectoryIterator::filePath
Path filePath() const
Returns the path of the current item.
Definition: gdirectory_unix.cpp:121
G::Directory
An encapsulation of a file system directory that works with G::DirectoryIterator.
Definition: gdirectory.h:46
G::Directory::usable
int usable(bool for_creating_files=false) const
Returns zero if the object represents a valid directory with permissions that dont disallow reading o...
Definition: gdirectory_unix.cpp:71
G::Directory::writeable
bool writeable(const std::string &probe_filename=tmp()) const
Tries to create and then delete an empty test file in the directory.
Definition: gdirectory_unix.cpp:95
G::Directory::path
Path path() const
Returns the directory's path, as passed in to the ctor.
Definition: gdirectory.cpp:52
G::File::probe
static bool probe(const char *) noexcept
Creates and deletes a temporary probe file.
Definition: gfile_unix.cpp:98
G::File::isDirectory
static bool isDirectory(const Path &path, std::nothrow_t)
Returns true if the path exists() and is a directory.
Definition: gfile.cpp:187
G::File::sizeString
static std::string sizeString(const Path &file)
Returns the file's size in string format.
Definition: gfile.cpp:205
G::Path
A Path object represents a file system path.
Definition: gpath.h:72
G::Path::cstr
const char * cstr() const noexcept
Returns the path string.
Definition: gpath.h:221
G::Path::str
std::string str() const
Returns the path string.
Definition: gpath.h:215
G::Path::empty
bool empty() const noexcept
Returns true if size() is zero.
Definition: gpath.h:203
G::Process::errno_
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
Definition: gprocess_unix.cpp:115
gdatetime.h
gdirectory.h
gfile.h
glog.h
gprocess.h
G
Low-level classes.
Definition: galign.h:28