Apache Mesos
path.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_PATH_HPP__
14 #define __STOUT_PATH_HPP__
15 
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #include <stout/stringify.hpp>
21 #include <stout/strings.hpp>
22 
23 #include <stout/os/constants.hpp>
24 
25 
26 namespace path {
27 
28 // Converts a fully formed URI to a filename for the platform.
29 //
30 // On all platforms, the optional "file://" prefix is removed if it
31 // exists.
32 //
33 // On Windows, this also converts "/" characters to "\" characters.
34 // The Windows file system APIs don't work with "/" in the filename
35 // when using long paths (although they do work fine if the file
36 // path happens to be short).
37 //
38 // NOTE: Currently, Mesos uses URIs and files somewhat interchangably.
39 // For compatibility, lack of "file://" prefix is not considered an
40 // error.
41 inline std::string from_uri(const std::string& uri)
42 {
43  // Remove the optional "file://" if it exists.
44  // TODO(coffler): Remove the `hostname` component.
45  const std::string path = strings::remove(uri, "file://", strings::PREFIX);
46 
47 #ifndef __WINDOWS__
48  return path;
49 #else
50  return strings::replace(path, "/", "\\");
51 #endif // __WINDOWS__
52 }
53 
54 
55 // Base case.
56 inline std::string join(
57  const std::string& path1,
58  const std::string& path2,
59  const char _separator = os::PATH_SEPARATOR)
60 {
61  const std::string separator = stringify(_separator);
62  return strings::remove(path1, separator, strings::SUFFIX) +
63  separator +
64  strings::remove(path2, separator, strings::PREFIX);
65 }
66 
67 
68 template <typename... Paths>
69 inline std::string join(
70  const std::string& path1,
71  const std::string& path2,
72  Paths&&... paths)
73 {
74  return join(path1, join(path2, std::forward<Paths>(paths)...));
75 }
76 
77 
78 inline std::string join(const std::vector<std::string>& paths)
79 {
80  if (paths.empty()) {
81  return "";
82  }
83 
84  std::string result = paths[0];
85  for (size_t i = 1; i < paths.size(); ++i) {
86  result = join(result, paths[i]);
87  }
88  return result;
89 }
90 
91 
96 inline bool absolute(const std::string& path)
97 {
98 #ifndef __WINDOWS__
100 #else
101  // NOTE: We do not use `PathIsRelative` Windows utility function
102  // here because it does not support long paths.
103  //
104  // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
105  // for details on paths. In short, an absolute path for files on Windows
106  // looks like one of the following:
107  // * "[A-Za-z]:\"
108  // * "[A-Za-z]:/"
109  // * "\\?\..."
110  // * "\\server\..." where "server" is a network host.
111  //
112  // NOLINT(whitespace/line_length)
113 
114  // A uniform naming convention (UNC) name of any format,
115  // always starts with two backslash characters.
116  if (strings::startsWith(path, "\\\\")) {
117  return true;
118  }
119 
120  // A disk designator with a slash, for example "C:\" or "d:/".
121  if (path.length() < 3) {
122  return false;
123  }
124 
125  const char letter = path[0];
126  if (!((letter >= 'A' && letter <= 'Z') ||
127  (letter >= 'a' && letter <= 'z'))) {
128  return false;
129  }
130 
131  std::string colon = path.substr(1, 2);
132  return colon == ":\\" || colon == ":/";
133 #endif // __WINDOWS__
134 }
135 
136 } // namespace path {
137 
138 
145 class Path
146 {
147 public:
148  Path() : value(), separator(os::PATH_SEPARATOR) {}
149 
150  explicit Path(
151  const std::string& path, const char path_separator = os::PATH_SEPARATOR)
152  : value(strings::remove(path, "file://", strings::PREFIX)),
153  separator(path_separator)
154  {}
155 
156  // TODO(cmaloney): Add more useful operations such as 'directoryname()',
157  // 'filename()', etc.
158 
182  inline std::string basename() const
183  {
184  if (value.empty()) {
185  return std::string(".");
186  }
187 
188  size_t end = value.size() - 1;
189 
190  // Remove trailing slashes.
191  if (value[end] == separator) {
192  end = value.find_last_not_of(separator, end);
193 
194  // Paths containing only slashes result into "/".
195  if (end == std::string::npos) {
196  return stringify(separator);
197  }
198  }
199 
200  // 'start' should point towards the character after the last slash
201  // that is non trailing.
202  size_t start = value.find_last_of(separator, end);
203 
204  if (start == std::string::npos) {
205  start = 0;
206  } else {
207  start++;
208  }
209 
210  return value.substr(start, end + 1 - start);
211  }
212 
213  // TODO(hausdorff) Make sure this works on Windows for very short path names,
214  // such as "C:\Temp". There is a distinction between "C:" and "C:\", the
215  // former means "current directory of the C drive", while the latter means
216  // "The root of the C drive". Also make sure that UNC paths are handled.
217  // Will probably need to use the Windows path functions for that.
241  inline std::string dirname() const
242  {
243  if (value.empty()) {
244  return std::string(".");
245  }
246 
247  size_t end = value.size() - 1;
248 
249  // Remove trailing slashes.
250  if (value[end] == separator) {
251  end = value.find_last_not_of(separator, end);
252  }
253 
254  // Remove anything trailing the last slash.
255  end = value.find_last_of(separator, end);
256 
257  // Paths containing no slashes result in ".".
258  if (end == std::string::npos) {
259  return std::string(".");
260  }
261 
262  // Paths containing only slashes result in "/".
263  if (end == 0) {
264  return stringify(separator);
265  }
266 
267  // 'end' should point towards the last non slash character
268  // preceding the last slash.
269  end = value.find_last_not_of(separator, end);
270 
271  // Paths containing no non slash characters result in "/".
272  if (end == std::string::npos) {
273  return stringify(separator);
274  }
275 
276  return value.substr(0, end + 1);
277  }
278 
297  {
298  std::string _basename = basename();
299  size_t index = _basename.rfind('.');
300 
301  if (_basename == "." || _basename == ".." || index == std::string::npos) {
302  return None();
303  }
304 
305  return _basename.substr(index);
306  }
307 
308  // Checks whether the path is absolute.
309  inline bool absolute() const
310  {
311  return path::absolute(value);
312  }
313 
314  // Implicit conversion from Path to string.
315  operator std::string() const
316  {
317  return value;
318  }
319 
320  const std::string& string() const
321  {
322  return value;
323  }
324 
325 private:
326  std::string value;
327  char separator;
328 };
329 
330 
331 inline bool operator==(const Path& left, const Path& right)
332 {
333  return left.string() == right.string();
334 }
335 
336 
337 inline bool operator!=(const Path& left, const Path& right)
338 {
339  return !(left == right);
340 }
341 
342 
343 inline bool operator<(const Path& left, const Path& right)
344 {
345  return left.string() < right.string();
346 }
347 
348 
349 inline bool operator>(const Path& left, const Path& right)
350 {
351  return right < left;
352 }
353 
354 
355 inline bool operator<=(const Path& left, const Path& right)
356 {
357  return !(left > right);
358 }
359 
360 
361 inline bool operator>=(const Path& left, const Path& right)
362 {
363  return !(left < right);
364 }
365 
366 
367 inline std::ostream& operator<<(
368  std::ostream& stream,
369  const Path& path)
370 {
371  return stream << path.string();
372 }
373 
374 #endif // __STOUT_PATH_HPP__
Definition: path.hpp:26
Definition: format.hpp:45
std::string paths()
Definition: os.hpp:136
Definition: posix_signalhandler.hpp:23
std::string join(const std::string &path1, const std::string &path2, const char _separator=os::PATH_SEPARATOR)
Definition: path.hpp:56
Try< Nothing > start(const std::string &name)
Starts the slice with the given name (via &#39;systemctl start <name>&#39;).
bool absolute(const std::string &path)
Returns whether the given path is an absolute path.
Definition: path.hpp:96
std::string remove(const std::string &from, const std::string &substring, Mode mode=ANY)
Definition: strings.hpp:41
bool operator>=(const Path &left, const Path &right)
Definition: path.hpp:361
Try< Nothing > remove(const std::string &hierarchy, const std::string &cgroup)
bool operator>(const Path &left, const Path &right)
Definition: path.hpp:349
Definition: strings.hpp:36
Represents a POSIX or Windows file system path and offers common path manipulations.
Definition: path.hpp:145
std::string from_uri(const std::string &uri)
Definition: path.hpp:41
std::string replace(const std::string &s, const std::string &from, const std::string &to)
Definition: strings.hpp:113
bool absolute() const
Definition: path.hpp:309
Path(const std::string &path, const char path_separator=os::PATH_SEPARATOR)
Definition: path.hpp:150
std::string dirname() const
Extracts the component up to, but not including, the final &#39;/&#39;.
Definition: path.hpp:241
std::ostream & operator<<(std::ostream &stream, const Path &path)
Definition: path.hpp:367
Definition: none.hpp:27
Option< std::string > extension() const
Returns the file extension of the path, including the dot.
Definition: path.hpp:296
bool operator==(const Path &left, const Path &right)
Definition: path.hpp:331
bool operator<=(const Path &left, const Path &right)
Definition: path.hpp:355
bool operator<(const Path &left, const Path &right)
Definition: path.hpp:343
Definition: uri.hpp:21
std::string basename() const
Extracts the component following the final &#39;/&#39;.
Definition: path.hpp:182
std::string stringify(int flags)
bool startsWith(const std::string &s, const std::string &prefix)
Definition: strings.hpp:381
const std::string & string() const
Definition: path.hpp:320
Path()
Definition: path.hpp:148
bool operator!=(const Path &left, const Path &right)
Definition: path.hpp:337
constexpr char PATH_SEPARATOR
Definition: constants.hpp:24
Definition: strings.hpp:35