VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gdirectory_unix.cpp
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 // 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 "gdebug.h"
27 #include "glog.h"
28 #include <sstream>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 
35 namespace G
36 {
37  class DirectoryIteratorImp ;
38 }
39 
40 /// \class G::DirectoryIteratorImp
41 /// A pimple-pattern implementation class for DirectoryIterator using
42 /// opendir()/readdir().
43 ///
45 {
46 private:
47  DIR * m_d ;
48  struct dirent * m_dp ;
49  Directory m_dir ;
50  bool m_error ;
51 
52 public:
53  explicit DirectoryIteratorImp( const Directory & dir ) ;
55  bool isDir() const ;
56  bool more() ;
57  bool error() const ;
58  std::string sizeString() const ;
59  Path filePath() const ;
60  std::string fileName() const ;
61 
62 private:
63  void operator=( const DirectoryIteratorImp & ) ;
65 } ;
66 
67 //
68 
69 bool G::Directory::valid( bool for_creation ) const
70 {
71  bool rc = true ;
72  struct stat statbuf ;
73  if( ::stat( m_path.str().c_str() , &statbuf ) )
74  {
75  rc = false ; // doesnt exist
76  }
77  else if( !(statbuf.st_mode & S_IFDIR) )
78  {
79  rc = false ; // not a directory
80  }
81  else
82  {
83  DIR * p = ::opendir( m_path.str().c_str() ) ;
84  if( p == nullptr )
85  rc = false ; // cant open directory for reading
86  else
87  ::closedir( p ) ;
88  }
89 
90  if( rc && for_creation )
91  {
92  // (not definitive -- see also GNU/Linux ::euidaccess())
93  if( 0 != ::access( m_path.str().c_str() , W_OK ) )
94  rc = false ;
95  }
96  return rc ;
97 }
98 
99 std::string G::Directory::tmp()
100 {
101  std::ostringstream ss ;
102  ss << "." << DateTime::now() << "." << Process::Id() << ".tmp" ;
103  return ss.str() ;
104 }
105 
106 bool G::Directory::writeable( std::string tmp_filename ) const
107 {
108  G::Path test_file( m_path ) ;
109  if( tmp_filename.empty() ) tmp_filename = tmp() ;
110  test_file.pathAppend( tmp_filename ) ;
111 
112  int fd = ::open( test_file.str().c_str() , O_WRONLY | O_CREAT | O_EXCL , S_IRWXU ) ;
113  if( fd == -1 )
114  {
115  return false ;
116  }
117  ::close( fd ) ;
118  bool ok = 0 == ::unlink( test_file.str().c_str() ) ;
119  return ok ;
120 }
121 
122 // ===
123 
125  m_imp( new DirectoryIteratorImp(dir) )
126 {
127 }
128 
130 {
131  return m_imp->error() ;
132 }
133 
135 {
136  return m_imp->more() ;
137 }
138 
140 {
141  return m_imp->filePath() ;
142 }
143 
145 {
146  return m_imp->fileName() ;
147 }
148 
150 {
151  return m_imp->isDir() ;
152 }
153 
155 {
156  return m_imp->sizeString() ;
157 }
158 
160 {
161  delete m_imp ;
162 }
163 
164 // ===
165 
166 G::DirectoryIteratorImp::DirectoryIteratorImp( const Directory & dir ) :
167  m_d(nullptr) ,
168  m_dp(nullptr) ,
169  m_dir(dir) ,
170  m_error(true)
171 {
172  m_d = ::opendir( dir.path().str().c_str() ) ;
173  m_error = m_d == nullptr ;
174 }
175 
176 bool G::DirectoryIteratorImp::error() const
177 {
178  return m_error ;
179 }
180 
181 bool G::DirectoryIteratorImp::more()
182 {
183  while( !m_error )
184  {
185  m_dp = ::readdir( m_d ) ;
186  m_error = m_dp == nullptr ;
187  bool special = !m_error && ( fileName() == "." || fileName() == ".." ) ;
188  if( !special )
189  break ;
190  }
191  return !m_error ;
192 }
193 
194 G::Path G::DirectoryIteratorImp::filePath() const
195 {
196  return m_dir.path() + fileName() ;
197 }
198 
199 std::string G::DirectoryIteratorImp::fileName() const
200 {
201  return m_dp == nullptr ? std::string() : std::string(m_dp->d_name) ;
202 }
203 
204 bool G::DirectoryIteratorImp::isDir() const
205 {
206  struct stat statbuf ;
207  return ::stat( filePath().str().c_str() , &statbuf ) == 0 && (statbuf.st_mode & S_IFDIR) ;
208 }
209 
210 G::DirectoryIteratorImp::~DirectoryIteratorImp()
211 {
212  if( m_d != nullptr )
213  ::closedir( m_d ) ;
214 }
215 
216 std::string G::DirectoryIteratorImp::sizeString() const
217 {
218  std::string s = G::File::sizeString( filePath() ) ;
219  return s.empty() ? std::string("0") : s ;
220 }
221 
std::string str() const
Returns the path string.
Definition: gpath.cpp:290
std::string sizeString() const
Returns the file size as a decimal string.
Path filePath() const
Returns the path of the current item.
Path path() const
Returns the directory's path.
Definition: gdirectory.cpp:67
bool valid(bool for_creating_files=false) const
Returns true if the object represents a valid directory.
bool writeable(std::string probe_filename=tmp()) const
Tries to create and then delete an empty test file in the directory.
~DirectoryIterator()
Destructor.
static EpochTime now()
Returns the current epoch time.
An encapsulation of a file system directory that allows for iterating through the set of contained fi...
Definition: gdirectory.h:45
static std::string tmp()
A convenience function for constructing a filename for writeable().
bool more()
Returns true if more and advances by one.
bool isDir() const
Returns true if the current item is a directory.
void pathAppend(const std::string &tail)
Appends a filename or a relative path to this path.
Definition: gpath.cpp:357
static std::string sizeString(const Path &file)
Returns the file's size in string format.
Definition: gfile_unix.cpp:90
A pimple-pattern implementation class for DirectoryIterator using opendir()/readdir().
std::string fileName() const
Returns the name of the current item.
bool error() const
Returns true on error. The caller should stop the iteration.
A Path object represents a file system path.
Definition: gpath.h:72
DirectoryIterator(const Directory &dir)
Constructor taking a directory reference.