libutil++  1.9.3
 All Classes Functions Variables
Path.cpp
1 /*
2 ** libutil++
3 ** $Id: Path.cpp 1911 2017-09-02 17:37:35Z 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: Path.cpp 1911 2017-09-02 17:37:35Z sella $";
10 
11 #include "Path.h"
12 #include "CommonMacro.h"
13 #include "String.h"
14 
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/statvfs.h>
18 
19 #include <fcntl.h>
20 #include <dirent.h>
21 
22 #include <regex>
23 
24 using namespace sella::util;
25 
26 std::vector<std::string>& Path::search(std::vector<std::string> &file, const std::string &path, const std::string &regex) throw (PathException) {
27  char buffer[8192];
28  struct dirent ** listing;
29 
30  int length = ::scandir(path.c_str(), &(listing), NULL, ::alphasort);
31 
32  for (int i = 0; i < length; i++) {
33  if (String::regex_match(listing[i]->d_name, regex)) {
34  ::snprintf(buffer, sizeof(buffer), "%s/%s", path.c_str(), listing[i]->d_name);
35 
36  file.push_back(buffer);
37  }
38  ::free(listing[i]);
39  }
40  ::free(listing);
41 
42  return file;
43 }
44 
45 std::string Path::create(const std::vector<std::string> &path, mode_t mode, uid_t uid, gid_t gid) throw (PathException) {
46  std::string root;
47 
48  for (auto iter = path.begin(); iter != path.end(); ++iter) {
49  if (root.empty() == false) {
50  root.append("/");
51  }
52  root.append(*iter);
53  }
54 
55  return Path::create(root, mode, uid, gid);
56 }
57 
58 std::string Path::create(const std::string &path, mode_t mode, uid_t uid, gid_t gid) throw (PathException) {
59  char buffer[512];
60  std::string root = path;
61 
62  /* Remove any trailing slash characters from the path. */
63  while (*(root.rbegin()) == '/') {
64  root.erase(root.length() - 1, 1);
65  }
66 
67  /* Ensure the supplied path is valid. */
68  DIR * directory = ::opendir(root.c_str());
69  std::string partial;
70 
71  if (directory == NULL) {
72  /* Directory does not exist, so create it. */
73  for (auto iter = root.begin(), end = root.end(); iter != end; ++iter) {
74  if ((*iter) == '/') {
75  partial = std::string(root.begin(), iter);
76 
77  if (partial.length() > 0) {
78  if ((directory = ::opendir(partial.c_str())) == NULL) {
79  if (::mkdir(partial.c_str(), mode) != 0) {
80  if (errno != EEXIST) {
81  THROW(PathException, "failed to create directory '%s': %s", partial.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
82  }
83  }
84 
85  if (uid != (uid_t) -1 && gid != (gid_t) 0) {
86  if (::chown(partial.c_str(), uid, gid) != 0) {
87  THROW(PathException, "failed to set owner on directory '%s': %s", partial.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
88  }
89  }
90  } else {
91  ::closedir(directory);
92  }
93  }
94  }
95  }
96 
97  if ((directory = ::opendir(root.c_str())) == NULL) {
98  if (::mkdir(root.c_str(), mode) != 0) {
99  if (errno != EEXIST) {
100  THROW(PathException, "failed to create directory '%s': %s", root.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
101  }
102  }
103 
104  if (uid != (uid_t) -1 && gid != (gid_t) 0) {
105  if (::chown(root.c_str(), uid, gid) != 0) {
106  THROW(PathException, "failed to set owner on directory '%s': %s", root.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
107  }
108  }
109 
110  if ((directory = ::opendir(root.c_str())) == NULL) {
111  THROW(PathException, "failed to open directory '%s' for writing: %s", root.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
112  }
113  }
114  }
115 
116  ::closedir(directory);
117 
118  return root;
119 }
120 
121 void Path::unlink(const std::string &path) throw (PathException) {
122  char buffer[512];
123  struct stat stats;
124 
125  if (::stat(path.c_str(), &(stats)) != 0) {
126  THROW(PathException, "failed to unlink directory %s: %s", path.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
127  }
128 
129  if (S_ISDIR(stats.st_mode)) {
130  struct dirent ** files = NULL;
131  int count = ::scandir(path.c_str(), &(files), NULL, ::versionsort);
132 
133  for (int i = 0; i < count; i++) {
134  try {
135  Path::unlink(std::string(path).append("/").append(files[i]->d_name));
136  } catch (PathException &e) {
137  for (int j = i; j < count; j++) {
138  ::free(files[j]);
139  }
140  ::free(files);
141 
142  throw e;
143  }
144  ::free(files[i]);
145  }
146  ::free(files);
147  } else {
148  if (::unlink(path.c_str()) != 0) {
149  THROW(PathException, "failed to unlink file %s: %s", path.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
150  }
151  }
152 }
153 
154 uint64_t Path::getPartitionSize(const std::string &path) throw (PathException) {
155  char buffer[512];
156  struct statvfs vfs;
157 
158  if (statvfs(path.c_str(), &vfs) == -1) {
159  THROW(PathException, "failed to get stats for directory '%s': %s", path.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
160  }
161 
162  double total = ceil((double) (vfs.f_blocks * vfs.f_frsize));
163 
164  return (uint64_t) total;
165 }
166 
167 uint64_t Path::getPartitionUsed(const std::string &path) throw (PathException) {
168  char buffer[512];
169  struct statvfs vfs;
170 
171  if (statvfs(path.c_str(), &vfs) == -1) {
172  THROW(PathException, "failed to get stats for directory '%s': %s", path.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
173  }
174 
175  double total = ceil((double) (vfs.f_blocks * vfs.f_frsize));
176  double available = ceil((double) (vfs.f_bfree * vfs.f_frsize));
177  double used = total - available;
178 
179  return (uint64_t) used;
180 }
181 
182 uint64_t Path::getPartitionFree(const std::string &path) throw (PathException) {
183  char buffer[512];
184  struct statvfs vfs;
185 
186  if (statvfs(path.c_str(), &vfs) == -1) {
187  THROW(PathException, "failed to get stats for directory '%s': %s", path.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
188  }
189 
190  double available = ceil((double) (vfs.f_bfree * vfs.f_frsize));
191 
192  return (uint64_t) available;
193 }
194 
195 double Path::getPartitionFull(const std::string &path) throw (PathException) {
196  char buffer[512];
197  struct statvfs vfs;
198 
199  if (statvfs(path.c_str(), &vfs) == -1) {
200  THROW(PathException, "failed to get stats for directory '%s': %s", path.c_str(), ::strerror_r(errno, buffer, sizeof(buffer)));
201  }
202 
203  double total = ceil((double) (vfs.f_blocks * vfs.f_frsize));
204  double available = ceil((double) (vfs.f_bfree * vfs.f_frsize));
205  double used = total - available;
206  double usedPercentage = ceil((double) (used / total) * (double) 100);
207 
208  return usedPercentage;
209 }
210 
211 /*
212 ** vim: noet ts=3 sw=3
213 */