libutil++  1.9.3
 All Classes Functions Variables
File.cpp
1 /*
2 ** libutil++
3 ** $Id: File.cpp 1669 2016-04-09 20:07:12Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: File.cpp 1669 2016-04-09 20:07:12Z sella $";
10 
11 #include "File.h"
12 #include "CommonMacro.h"
13 #include "String.h"
14 
15 #include <dirent.h>
16 
17 #include <fstream>
18 
19 using namespace sella::util;
20 
21 const std::string File::any = "^.*";
22 const std::set<uint8_t> File::all = { DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, DT_UNKNOWN };
23 const std::set<uint8_t> File::regular = { DT_LNK, DT_REG, DT_UNKNOWN };
24 const std::set<uint8_t> File::files = { DT_BLK, DT_CHR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, DT_UNKNOWN };
25 const std::set<uint8_t> File::dirs = { DT_DIR };
26 
27 std::string File::getBaseName(const std::string &fullpath) throw () {
28  if (fullpath.empty()) {
29  return fullpath;
30  }
31 
32  return fullpath.substr(fullpath.rfind('/') + 1);
33 }
34 
35 std::string File::getDirName(const std::string &fullpath) throw () {
36  if (fullpath.empty()) {
37  return fullpath;
38  }
39 
40  return fullpath.substr(0, fullpath.rfind('/'));
41 }
42 
43 std::string File::getRealPath(const std::string &fullpath) throw (FileException) {
44  char realPath[PATH_MAX];
45 
46  if (fullpath.empty()) {
47  return fullpath;
48  }
49 
50  if (::realpath(fullpath.c_str(), realPath) != NULL) {
51  return std::string(realPath);
52  }
53 
54  THROW2(FileException, "realpath()");
55 }
56 
57 std::vector<std::string> File::getDirectory(const std::string &path, const std::string &regex, const std::set<uint8_t> &types) throw (FileException) {
58  std::vector<std::string> results;
59  struct dirent entry, *result;
60  DIR *dir;
61  int e;
62 
63  if ((dir = opendir(path.c_str())) == NULL) {
64  THROW(FileException, "failed to open %s", path.c_str());
65  }
66 
67  try {
68  boost::regex re(regex);
69 
70  for (;;) {
71  if ((e = readdir_r(dir, &entry, &result)) != 0) {
72  closedir(dir);
73 
74  THROW2(FileException, "Failed to read directory %s", path.c_str());
75  }
76 
77  if (result == NULL) {
78  break;
79  }
80 
81  if (types.count(result->d_type) > 0) {
82  if (String::regex_search(result->d_name, re)) {
83  results.push_back(result->d_name);
84  }
85  }
86  }
87  } catch (RegexException &e) {
88  closedir(dir);
89 
90  RETHROW(FileException, e);
91  }
92 
93  closedir(dir);
94 
95  return results;
96 }
97 
98 std::string File::read(const std::string &fullpath, size_t limit, std::ios_base::openmode mode) throw (FileException) {
99  std::ifstream file(fullpath, mode);
100 
101  if (!file.is_open() || !file.good()) {
102  THROW(FileException, "Failed to open file %s for reading", fullpath.c_str());
103  }
104 
105  file.seekg(0, std::ios::end);
106  std::streamsize size = file.tellg();
107  file.seekg(0, std::ios::beg);
108 
109  if (size == -1) { /* Slow path - /proc entries need this */
110  std::string buf((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
111 
112  if (limit > 0 && buf.size() > limit) {
113  buf.resize(limit);
114  }
115 
116  return buf;
117  } else { /* Fast path */
118  size_t len = (limit == 0 || (size_t) size < limit) ? size : limit;
119  std::string buf(len, '\0'); /* Reserve and set string size */
120 
121  if (!file.read((char*) buf.data(), len)) {
122  THROW(FileException, "Failed to read file %s", fullpath.c_str());
123  }
124 
125  return buf;
126  }
127 }
128 
129 std::string File::readline(const std::string &fullpath, char delim, std::ios_base::openmode mode) throw (FileException) {
130  std::ifstream file(fullpath, mode);
131 
132  if (!file.is_open() || !file.good()) {
133  THROW(FileException, "Failed to open file %s for reading", fullpath.c_str());
134  }
135 
136  std::string buf;
137 
138  std::getline(file, buf, delim);
139 
140  return buf;
141 }
142 
143 std::vector<std::string> File::readlines(const std::string &fullpath, size_t limit, char delim, std::ios_base::openmode mode) throw (FileException) {
144  std::ifstream file(fullpath, mode);
145 
146  if (!file.is_open() || !file.good()) {
147  THROW(FileException, "Failed to open file %s for reading", fullpath.c_str());
148  }
149 
150  size_t count = 0;
151  std::string buf;
152  std::vector<std::string> lines;
153 
154  lines.reserve((limit > 0) ? limit : 32);
155 
156  //for (std::string line; std::getline(file, buf, delim);) {
157  while (std::getline(file, buf, delim)) {
158  lines.push_back(buf);
159 
160  if (limit > 0 && ++count > limit) {
161  break;
162  }
163  }
164 
165  return lines;
166 }
167 
168 void File::write(const std::string &fullpath, const std::string &data, std::ios_base::openmode mode) throw (FileException) {
169  std::ofstream file(fullpath, mode);
170 
171  if (!file.is_open() || !file.good()) {
172  THROW(FileException, "Failed to open file %s for writing", fullpath.c_str());
173  }
174 
175  if (!file.write((char*) data.data(), data.size())) {
176  THROW(FileException, "Failed to write to file %s", fullpath.c_str());
177  }
178 }
179 
180 bool File::exists(const std::string &fullpath, bool followSymlink) throw () {
181  struct stat sb;
182 
183  if (followSymlink) {
184  return (stat(fullpath.c_str(), &sb) == 0);
185  } else {
186  return (lstat(fullpath.c_str(), &sb) == 0);
187  }
188 }
189 
190 bool File::isReadable(const std::string &fullpath) throw () {
191  std::ifstream file(fullpath);
192 
193  if (!file.is_open() || !file.good()) {
194  return false;
195  }
196 
197  return true;
198 }
199 
200 bool File::isRegularFile(const std::string &fullpath, bool followSymlink) throw (FileException) {
201  return S_ISREG(File::getMode(fullpath, followSymlink));
202 }
203 
204 bool File::isDirectory(const std::string &fullpath, bool followSymlink) throw (FileException) {
205  return S_ISDIR(File::getMode(fullpath, followSymlink));
206 }
207 
208 bool File::isCharacterDevice(const std::string &fullpath, bool followSymlink) throw (FileException) {
209  return S_ISCHR(File::getMode(fullpath, followSymlink));
210 }
211 
212 bool File::isBlockDevice(const std::string &fullpath, bool followSymlink) throw (FileException) {
213  return S_ISBLK(File::getMode(fullpath, followSymlink));
214 }
215 
216 bool File::isFIFO(const std::string &fullpath, bool followSymlink) throw (FileException) {
217  return S_ISFIFO(File::getMode(fullpath, followSymlink));
218 }
219 
220 bool File::isSymLink(const std::string &fullpath) throw (FileException) {
221  return S_ISLNK(File::getMode(fullpath, false));
222 }
223 
224 bool File::isSocket(const std::string &fullpath, bool followSymlink) throw (FileException) {
225  return S_ISSOCK(File::getMode(fullpath, followSymlink));
226 }
227 
228 uid_t File::getUID(const std::string &fullpath, bool followSymlink) throw (FileException) {
229  return File::getStat(fullpath, followSymlink).st_uid;
230 }
231 
232 gid_t File::getGID(const std::string &fullpath, bool followSymlink) throw (FileException) {
233  return File::getStat(fullpath, followSymlink).st_gid;
234 }
235 
236 int64_t File::getSize(const std::string &fullpath, bool followSymlink) throw (FileException) {
237  return (int64_t) File::getStat(fullpath, followSymlink).st_size;
238 }
239 
240 int64_t File::getBlocks(const std::string &fullpath, bool followSymlink) throw (FileException) {
241  return (int64_t) File::getStat(fullpath, followSymlink).st_blocks;
242 }
243 
244 int64_t File::getBlockSize(const std::string &fullpath, bool followSymlink) throw (FileException) {
245  return (int64_t) File::getStat(fullpath, followSymlink).st_blksize;
246 }
247 
248 time_t File::getATime(const std::string &fullpath, bool followSymlink) throw (FileException) {
249  return File::getStat(fullpath, followSymlink).st_atime;
250 }
251 
252 time_t File::getMTime(const std::string &fullpath, bool followSymlink) throw (FileException) {
253  return File::getStat(fullpath, followSymlink).st_mtime;
254 }
255 
256 time_t File::getCTime(const std::string &fullpath, bool followSymlink) throw (FileException) {
257  return File::getStat(fullpath, followSymlink).st_ctime;
258 }
259 
260 struct stat File::getStat(const std::string &fullpath, bool followSymlink) throw (FileException) {
261  struct stat sb;
262 
263  if (followSymlink) {
264  if (stat(fullpath.c_str(), &sb) < 0) {
265  THROW2(FileException, "stat()");
266  }
267  } else {
268  if (lstat(fullpath.c_str(), &sb)) {
269  THROW2(FileException, "lstat()");
270  }
271  }
272 
273  return sb;
274 }
275 
276 mode_t File::getMode(const std::string &fullpath, bool followSymlink) throw (FileException) {
277  return File::getStat(fullpath, followSymlink).st_mode;
278 }
279 
280 mode_t File::itomode(int mode) throw (FileException) {
281  int ua;
282  int ga;
283  int oa;
284 
285  mode_t uam;
286  mode_t gam;
287  mode_t oam;
288 
289  if (mode >= 0 && mode <= 777) {
290  oa = mode % 10;
291  mode /= 10;
292  ga = mode % 10;
293  mode /= 10;
294  ua = mode;
295  } else {
296  THROW2(FileException, "invalid mode %d", mode);
297  }
298 
299  if (oa > 7 || ga > 7 || ua > 7) {
300  THROW2(FileException, "invalid mode %d", mode);
301  }
302 
303  if (ua == 7) {
304  uam = S_IRWXU;
305  } else if (ua == 6) {
306  uam = S_IRUSR | S_IWUSR;
307  } else if (ua == 5) {
308  uam = S_IRUSR | S_IXUSR;
309  } else if (ua == 4) {
310  uam = S_IRUSR;
311  } else if (ua == 3) {
312  uam = S_IWUSR | S_IXUSR;
313  } else if (ua == 2) {
314  uam = S_IWUSR;
315  } else if (ua == 1) {
316  uam = S_IXUSR;
317  } else {
318  uam = 0;
319  }
320 
321  if (ga == 7) {
322  gam = S_IRWXG;
323  } else if (ga == 6) {
324  gam = S_IRGRP | S_IWGRP;
325  } else if (ga == 5) {
326  gam = S_IRGRP | S_IXGRP;
327  } else if (ga == 4) {
328  gam = S_IRGRP;
329  } else if (ga == 3) {
330  gam = S_IWGRP | S_IXGRP;
331  } else if (ga == 2) {
332  gam = S_IWGRP;
333  } else if (ga == 1) {
334  gam = S_IXGRP;
335  } else {
336  gam = 0;
337  }
338 
339  if (oa == 7) {
340  oam = S_IRWXO;
341  } else if (oa == 6) {
342  oam = S_IROTH | S_IWOTH;
343  } else if (oa == 5) {
344  oam = S_IROTH | S_IXOTH;
345  } else if (oa == 4) {
346  oam = S_IROTH;
347  } else if (oa == 3) {
348  oam = S_IWOTH | S_IXOTH;
349  } else if (oa == 2) {
350  oam = S_IWOTH;
351  } else if (oa == 1) {
352  oam = S_IXOTH;
353  } else {
354  oam = 0;
355  }
356 
357  return (uam | gam | oam);
358 }
359 
360 /*
361 ** vim: noet ts=3 sw=3
362 */