CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
directory.cpp
Go to the documentation of this file.
1
10
11#include "utility/countof.h"
12#include "utility/resource.h"
13
14#include <cstring>
15#include <regex>
16
17#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
18#include <sys/stat.h>
19#include <dirent.h>
20#include <fcntl.h>
21#include <unistd.h>
22#elif defined(_WIN32) || defined(_WIN64)
23#include <windows.h>
24#endif
25
26namespace CppCommon {
27
28const Flags<FileAttributes> Directory::DEFAULT_ATTRIBUTES = FileAttributes::NORMAL;
30
32{
33#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
34 struct stat status;
35 int result = stat(string().c_str(), &status);
36 if (result != 0)
37 {
38 if ((errno == ENOENT) || (errno == ENOTDIR))
39 return false;
40 else
41 throwex FileSystemException("Cannot get the status of the directory!").Attach(*this);
42 }
43
44 if (S_ISDIR(status.st_mode))
45 return true;
46 else
47 return false;
48#elif defined(_WIN32) || defined(_WIN64)
49 DWORD attributes = GetFileAttributesW(wstring().c_str());
50 if (attributes == INVALID_FILE_ATTRIBUTES)
51 return false;
52
53 if (attributes & FILE_ATTRIBUTE_DIRECTORY)
54 return true;
55 else
56 return false;
57#endif
58}
59
61{
62#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
63 DIR* dir = opendir(string().c_str());
64 if (dir == nullptr)
65 throwex FileSystemException("Cannot open a directory!").Attach(*this);
66
67 // Smart resource cleaner pattern
68 auto directory = resource(dir, [](DIR* dirp) { closedir(dirp); });
69
70 struct dirent* pentry;
71 while ((pentry = readdir(dir)) != nullptr)
72 {
73 if (std::strncmp(pentry->d_name, ".", sizeof(pentry->d_name)) == 0)
74 continue;
75 if (std::strncmp(pentry->d_name, "..", sizeof(pentry->d_name)) == 0)
76 continue;
77 return false;
78 }
79
80 // Release the resource manually
81 int result = closedir(dir);
82 if (result != 0)
83 throwex FileSystemException("Cannot close a directory!").Attach(*this);
84 directory.release();
85
86 return true;
87#elif defined(_WIN32) || defined(_WIN64)
88 WIN32_FIND_DATAW fd;
89 HANDLE hDirectory = FindFirstFileW((*this / "*").wstring().c_str(), &fd);
90 if (hDirectory == INVALID_HANDLE_VALUE)
91 throwex FileSystemException("Cannot open a directory!").Attach(*this);
92
93 // Smart resource cleaner pattern
94 auto directory = resource(hDirectory, [](HANDLE hFindFile) { FindClose(hFindFile); });
95
96 do
97 {
98 if (std::wcsncmp(fd.cFileName, L".", countof(fd.cFileName)) == 0)
99 continue;
100 if (std::wcsncmp(fd.cFileName, L"..", countof(fd.cFileName)) == 0)
101 continue;
102 return false;
103 } while (FindNextFileW(hDirectory, &fd) != 0);
104
105 if (GetLastError() != ERROR_NO_MORE_FILES)
106 throwex FileSystemException("Cannot read directory entries!").Attach(*this);
107
108 // Release the resource manually
109 if (!FindClose(hDirectory))
110 throwex FileSystemException("Cannot close a directory!").Attach(*this);
111 directory.release();
112
113 return true;
114#endif
115}
116
118{
119 return DirectoryIterator(*this, false);
120}
121
123{
124 return DirectoryIterator();
125}
126
128{
129 return DirectoryIterator(*this, true);
130}
131
136
137std::vector<Path> Directory::GetEntries(const std::string& pattern)
138{
139 std::vector<Path> result;
140 std::regex matcher(pattern);
141 for (auto it = begin(); it != end(); ++it)
142 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
143 result.push_back(*it);
144 return result;
145}
146
147std::vector<Path> Directory::GetEntriesRecursive(const std::string& pattern)
148{
149 std::vector<Path> result;
150 std::regex matcher(pattern);
151 for (auto it = rbegin(); it != rend(); ++it)
152 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
153 result.push_back(Directory(*it));
154 return result;
155}
156
157std::vector<Directory> Directory::GetDirectories(const std::string& pattern)
158{
159 std::vector<Directory> result;
160 std::regex matcher(pattern);
161 for (auto it = begin(); it != end(); ++it)
162 {
163 // Special check for symbolic link
164 Directory target(*it);
165 if (it->IsSymlink())
166 target = Symlink(target).target();
167
168 // Special check for directory
169 if (target.IsDirectory())
170 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
171 result.emplace_back(*it);
172 }
173 return result;
174}
175
176std::vector<Directory> Directory::GetDirectoriesRecursive(const std::string& pattern)
177{
178 std::vector<Directory> result;
179 std::regex matcher(pattern);
180 for (auto it = rbegin(); it != rend(); ++it)
181 {
182 // Special check for symbolic link
183 Directory target(*it);
184 if (it->IsSymlink())
185 target = Symlink(target).target();
186
187 // Special check for directory
188 if (target.IsDirectory())
189 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
190 result.emplace_back(*it);
191 }
192 return result;
193}
194
195std::vector<File> Directory::GetFiles(const std::string& pattern)
196{
197 std::vector<File> result;
198 std::regex matcher(pattern);
199 for (auto it = begin(); it != end(); ++it)
200 {
201 // Special check for symbolic link
202 File target(*it);
203 if (it->IsSymlink())
204 target = Symlink(target).target();
205
206 // Special check for directory
207 if (!target.IsDirectory())
208 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
209 result.emplace_back(*it);
210 }
211 return result;
212}
213
214std::vector<File> Directory::GetFilesRecursive(const std::string& pattern)
215{
216 std::vector<File> result;
217 std::regex matcher(pattern);
218 for (auto it = rbegin(); it != rend(); ++it)
219 {
220 // Special check for symbolic link
221 File target(*it);
222 if (it->IsSymlink())
223 target = Symlink(target).target();
224
225 // Special check for directory
226 if (!target.IsDirectory())
227 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
228 result.emplace_back(*it);
229 }
230 return result;
231}
232
233std::vector<Symlink> Directory::GetSymlinks(const std::string& pattern)
234{
235 std::vector<Symlink> result;
236 std::regex matcher(pattern);
237 for (auto it = begin(); it != end(); ++it)
238 {
239 // Special check for symbolic link
240 if (it->IsSymlink())
241 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
242 result.emplace_back(*it);
243 }
244 return result;
245}
246
247std::vector<Symlink> Directory::GetSymlinksRecursive(const std::string& pattern)
248{
249 std::vector<Symlink> result;
250 std::regex matcher(pattern);
251 for (auto it = rbegin(); it != rend(); ++it)
252 {
253 // Special check for symbolic link
254 if (it->IsSymlink())
255 if (pattern.empty() || std::regex_match(it->filename().string(), matcher))
256 result.emplace_back(*it);
257 }
258 return result;
259}
260
261Directory Directory::Create(const Path& path, const Flags<FileAttributes>& attributes, const Flags<FilePermissions>& permissions)
262{
263 Directory directory(path);
264 if (directory.IsDirectoryExists())
265 return directory;
266#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
267 mode_t mode = 0;
269 mode |= S_IRUSR;
271 mode |= S_IWUSR;
273 mode |= S_IXUSR;
275 mode |= S_IRGRP;
277 mode |= S_IWGRP;
279 mode |= S_IXGRP;
281 mode |= S_IROTH;
283 mode |= S_IWOTH;
285 mode |= S_IXOTH;
287 mode |= S_ISUID;
289 mode |= S_ISGID;
291 mode |= S_ISVTX;
292
293 int result = mkdir(path.string().c_str(), mode);
294 if (result != 0)
295 throwex FileSystemException("Cannot create directory!").Attach(path);
296#elif defined(_WIN32) || defined(_WIN64)
297 if (!CreateDirectoryW(path.wstring().c_str(), nullptr))
298 throwex FileSystemException("Cannot create directory!").Attach(path);
299#endif
300 return directory;
301}
302
303Directory Directory::CreateTree(const Path& path, const Flags<FileAttributes>& attributes, const Flags<FilePermissions>& permissions)
304{
305 Directory tree(path);
306 if (tree.IsDirectoryExists())
307 return tree;
308
309 // Try to create the last directory
310 try
311 {
312 Create(tree);
313 return tree;
314 }
315 catch (const FileSystemException&) {}
316
317 // Failed, try to get the parent path and retry
318 Directory parent = tree.parent();
319 if (parent.empty())
320 throwex FileSystemException("Cannot create directory tree!").Attach(path);
321 else
323
324 // Retry to create the last directory
325 Create(tree);
326
327 return tree;
328}
329
330} // namespace CppCommon
Filesystem directory.
Definition directory.h:25
std::vector< File > GetFilesRecursive(const std::string &pattern="")
Recursively get all files (including symbolic link files) in the current directory.
static const Flags< FileAttributes > DEFAULT_ATTRIBUTES
Default directory attributes (Normal)
Definition directory.h:28
std::vector< Path > GetEntriesRecursive(const std::string &pattern="")
Recursively get all entries (directories, files, symbolic links) in the current directory.
bool IsDirectoryExists() const
Is the directory exists?
Definition directory.cpp:31
DirectoryIterator begin() const
Get the directory begin iterator.
static Directory CreateTree(const Path &path, const Flags< FileAttributes > &attributes=Directory::DEFAULT_ATTRIBUTES, const Flags< FilePermissions > &permissions=Directory::DEFAULT_PERMISSIONS)
Create full directory tree of the given path.
DirectoryIterator end() const
Get the directory end iterator.
std::vector< Symlink > GetSymlinksRecursive(const std::string &pattern="")
Recursively get all symbolic links (including symbolic link directories) in the current directory.
static const Flags< FilePermissions > DEFAULT_PERMISSIONS
Default directory permissions (IRUSR | IWUSR | IXUSR | IRGRP | IXGRP | IROTH | IXOTH)
Definition directory.h:30
std::vector< Directory > GetDirectoriesRecursive(const std::string &pattern="")
Recursively get all directories (including symbolic link directories) in the current directory.
std::vector< Symlink > GetSymlinks(const std::string &pattern="")
Get all symbolic links (including symbolic link directories) in the current directory.
std::vector< Path > GetEntries(const std::string &pattern="")
Get all entries (directories, files, symbolic links) in the current directory.
DirectoryIterator rbegin() const
Get the directory recursive begin iterator.
std::vector< Directory > GetDirectories(const std::string &pattern="")
Get all directories (including symbolic link directories) in the current directory.
static Directory Create(const Path &path, const Flags< FileAttributes > &attributes=Directory::DEFAULT_ATTRIBUTES, const Flags< FilePermissions > &permissions=Directory::DEFAULT_PERMISSIONS)
Create directory from the given path.
std::vector< File > GetFiles(const std::string &pattern="")
Get all files (including symbolic link files) in the current directory.
bool IsDirectoryEmpty() const
Is the directory empty?
Definition directory.cpp:60
DirectoryIterator rend() const
Get the directory recursive end iterator.
Filesystem directory iterator.
Filesystem file.
Definition file.h:28
File system exception.
Definition exceptions.h:19
FileSystemException & Attach(const Path &path)
Attach the given path to the exception.
Definition exceptions.h:33
Enum-based flags.
Definition flags.h:65
Filesystem path.
Definition path.h:90
std::wstring wstring() const
Get the path value as a wide string.
Definition path.h:153
Flags< FileAttributes > attributes() const
Get the path file attributes.
Definition path.cpp:472
bool IsDirectory() const
Is the path points to directory?
Definition path.h:217
Path parent() const
Decompose parent path from the current path.
Definition path.cpp:144
bool empty() const noexcept
Is the path empty?
Definition path.h:191
Flags< FilePermissions > permissions() const
Get the path file permissions.
Definition path.cpp:499
const std::string & string() const noexcept
Get the path value as UTF-8 string.
Definition path.h:151
Static array countof definition.
Filesystem directory definition.
#define throwex
Throw extended exception macro.
Definition exceptions.h:23
C++ Common project definitions.
auto resource(T handle, TCleaner cleaner)
Resource smart cleaner pattern.
Definition resource.h:43
constexpr size_t countof(const T(&)[N]) noexcept
Count of elements in static array.
Definition countof.h:16
@ IXOTH
Execute or search permission bit for other users.
@ IWUSR
Write permission bit for the owner of the file.
@ IWGRP
Write permission bit for the group owner of the file.
@ IXUSR
Execute (for ordinary files) or search (for directories) permission bit for the owner of the file.
@ ISVTX
This is the sticky bit.
@ IRGRP
Read permission bit for the group owner of the file.
@ IRUSR
Read permission bit for the owner of the file.
@ IXGRP
Execute or search permission bit for the group owner of the file.
@ IWOTH
Write permission bit for other users.
@ IROTH
Read permission bit for other users.
@ ISUID
This is the set-user-ID on execute bit.
@ ISGID
This is the set-group-ID on execute bit.
Resource smart cleaner pattern definition.