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
34namespace G
35{
36 class DirectoryIteratorImp ;
37}
38
39//| \class G::DirectoryIteratorImp
40/// A pimple-pattern implementation class for DirectoryIterator using
41/// opendir()/readdir().
42///
44{
45public:
46 explicit DirectoryIteratorImp( const Directory & dir ) ;
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
55public:
56 DirectoryIteratorImp( const DirectoryIteratorImp & ) = delete ;
58 void operator=( const DirectoryIteratorImp & ) = delete ;
59 void operator=( DirectoryIteratorImp && ) = delete ;
60
61private:
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
71int 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
95bool 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
104 m_imp(std::make_unique<DirectoryIteratorImp>(dir))
105{
106}
107
109= default ;
110
112{
113 return m_imp->error() ;
114}
115
117{
118 return m_imp->more() ;
119}
120
122{
123 return m_imp->filePath() ;
124}
125
127{
128 return m_imp->fileName() ;
129}
130
132{
133 return m_imp->isDir() ;
134}
135
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
154bool G::DirectoryIteratorImp::error() const
155{
156 return m_error ;
157}
158
159bool 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
173G::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
183bool 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
A pimple-pattern implementation class for DirectoryIterator using opendir()/readdir().
DirectoryIterator(const Directory &dir)
Constructor taking a directory reference.
std::string fileName() const
Returns the name of the current item.
bool error() const
Returns true on error. The caller should stop the iteration.
std::string sizeString() const
Returns the file size as a decimal string.
~DirectoryIterator()
Destructor.
bool isDir() const
Returns true if the current item is a directory.
bool more()
Returns true if more and advances by one.
Path filePath() const
Returns the path of the current item.
An encapsulation of a file system directory that works with G::DirectoryIterator.
Definition: gdirectory.h:46
int usable(bool for_creating_files=false) const
Returns zero if the object represents a valid directory with permissions that dont disallow reading o...
bool writeable(const std::string &probe_filename=tmp()) const
Tries to create and then delete an empty test file in the directory.
Path path() const
Returns the directory's path, as passed in to the ctor.
Definition: gdirectory.cpp:52
static bool probe(const char *) noexcept
Creates and deletes a temporary probe file.
Definition: gfile_unix.cpp:98
static bool isDirectory(const Path &path, std::nothrow_t)
Returns true if the path exists() and is a directory.
Definition: gfile.cpp:187
static std::string sizeString(const Path &file)
Returns the file's size in string format.
Definition: gfile.cpp:205
A Path object represents a file system path.
Definition: gpath.h:72
const char * cstr() const noexcept
Returns the path string.
Definition: gpath.h:221
std::string str() const
Returns the path string.
Definition: gpath.h:215
bool empty() const noexcept
Returns true if size() is zero.
Definition: gpath.h:203
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
Low-level classes.
Definition: galign.h:28