-
Notifications
You must be signed in to change notification settings - Fork 4
/
directory.h
208 lines (173 loc) · 5.14 KB
/
directory.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/**
* Directory.h
*
* Creates a temporary directory in a folder where the Yothalot data
* files are going to be stored
*
* @author Emiel Bruijntjes <[email protected]>
* @copyright 2015 Copernica BV
*/
/**
* Include guard
*/
#pragma once
/**
* Dependencies
*/
#include "base.h"
#include <string>
#include <phpcpp.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <dirent.h>
/**
* Class definition
*/
class Directory
{
private:
/**
* The full name of the directory
* @var Yothalot::Fullname
*/
Yothalot::Fullname _name;
/**
* Does the directory exist
* @return bool
*/
mutable bool _exists = false;
public:
/**
* Constructor, will create a temporary directory in the gluster mount point/tmp
*/
Directory() :
_name(base(), std::string("tmp/") + (std::string)Yothalot::UniqueName()) {}
/**
* Constructor on string, that will use temporary directory in the gluster mount point/tmp
* @param name name of the directory, relative to the glusterfs mount point (should not be null)
*/
Directory(const char *name) : _name(base(), name) {}
/**
* Destructor, can be empty since the server is cleaning up this directory
*/
virtual ~Directory() = default;
/**
* Cast to boolean: does the directory exist?
* @return bool
*/
operator bool () const { return exists(); }
bool operator! () const { return !exists(); }
/**
* Does the directory exist?
* @return bool
*/
bool exists() const
{
// do we already know this?
if (_exists) return true;
// file properties
struct stat props;
// read in properties
if (stat(_name.full(), &props) != 0) return false;
// must be a dir
return _exists = S_ISDIR(props.st_mode);
}
/**
* Create the directory
* @return bool
*/
bool create()
{
// if the directory already exists
if (exists()) return true;
// try to construct the directory
if (mkdir(_name.full(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) return true;
// directory could not be created, make sure base exists
Yothalot::Fullname basedir(base(), "tmp");
// create the base directory (we don't check the result, it can also fail
// because it already exists, and we do not want to check all such details)
mkdir(basedir.full(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
// retry to create the actual directory
return _exists = mkdir(_name.full(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
}
/**
* Get to the full path
* @return const char *
*/
const char *full() const
{
return _name.full();
}
/**
* Get the relative path, relative to the gluster mount point.
* @return const std::string
*/
const char *relative() const
{
// delegate
return _name.relative();
}
/**
* Traverse the directory and apply a callback to each item
* passing the raw entry information
* it resets at the end so it can be called again.
* @param callback
* @return bool
*/
bool traverse(const std::function<void(struct dirent *entry)> &callback) const
{
// reset the dir so traverse can be called again.
auto *dirp = opendir(_name);
// leap out if directory could not be opened
if (dirp == nullptr) return false;
// iterate over the files and stop if all files are consumed
while (true)
{
// read next entry
auto *result = readdir(dirp);
// If all files are consumed we break
if (result == nullptr) break;
// we ignore the '.' and '..' files
if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0) continue;
// Callback
callback(result);
}
// close dir
closedir(dirp);
// done
return true;
}
/**
* Traverse the directory and apply a callback to each item
* passing the entry name as a string
* it resets at the end so it can be called again.
* @param callback
* @return bool
*/
bool traverse(const std::function<void(const char *name)> &callback) const
{
// call the other traverse implementation
return traverse([callback](struct dirent *entry) {
callback(entry->d_name);
});
}
/**
* Remove the directory (and all files in it)
* @return true
*/
bool remove()
{
// traverse over the files
traverse([this](const char *name) {
// construct full path name
std::string fullname(_name.full());
// append file name
fullname.append("/").append(name);
// remove it
unlink(fullname.data());
});
// remove the directory
return rmdir(full()) == 0;
}
};