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() {}
149 
150  explicit Path(const std::string& path)
151  : value(strings::remove(path, "file://", strings::PREFIX)) {}
152 
153  // TODO(cmaloney): Add more useful operations such as 'directoryname()',
154  // 'filename()', etc.
155 
179  inline std::string basename() const
180  {
181  if (value.empty()) {
182  return std::string(".");
183  }
184 
185  size_t end = value.size() - 1;
186 
187  // Remove trailing slashes.
188  if (value[end] == os::PATH_SEPARATOR) {
189  end = value.find_last_not_of(os::PATH_SEPARATOR, end);
190 
191  // Paths containing only slashes result into "/".
192  if (end == std::string::npos) {
194  }
195  }
196 
197  // 'start' should point towards the character after the last slash
198  // that is non trailing.
199  size_t start = value.find_last_of(os::PATH_SEPARATOR, end);
200 
201  if (start == std::string::npos) {
202  start = 0;
203  } else {
204  start++;
205  }
206 
207  return value.substr(start, end + 1 - start);
208  }
209 
210  // TODO(hausdorff) Make sure this works on Windows for very short path names,
211  // such as "C:\Temp". There is a distinction between "C:" and "C:\", the
212  // former means "current directory of the C drive", while the latter means
213  // "The root of the C drive". Also make sure that UNC paths are handled.
214  // Will probably need to use the Windows path functions for that.
238  inline std::string dirname() const
239  {
240  if (value.empty()) {
241  return std::string(".");
242  }
243 
244  size_t end = value.size() - 1;
245 
246  // Remove trailing slashes.
247  if (value[end] == os::PATH_SEPARATOR) {
248  end = value.find_last_not_of(os::PATH_SEPARATOR, end);
249  }
250 
251  // Remove anything trailing the last slash.
252  end = value.find_last_of(os::PATH_SEPARATOR, end);
253 
254  // Paths containing no slashes result in ".".
255  if (end == std::string::npos) {
256  return std::string(".");
257  }
258 
259  // Paths containing only slashes result in "/".
260  if (end == 0) {
262  }
263 
264  // 'end' should point towards the last non slash character
265  // preceding the last slash.
266  end = value.find_last_not_of(os::PATH_SEPARATOR, end);
267 
268  // Paths containing no non slash characters result in "/".
269  if (end == std::string::npos) {
271  }
272 
273  return value.substr(0, end + 1);
274  }
275 
294  {
295  std::string _basename = basename();
296  size_t index = _basename.rfind('.');
297 
298  if (_basename == "." || _basename == ".." || index == std::string::npos) {
299  return None();
300  }
301 
302  return _basename.substr(index);
303  }
304 
305  // Checks whether the path is absolute.
306  inline bool absolute() const
307  {
308  return path::absolute(value);
309  }
310 
311  // Implicit conversion from Path to string.
312  operator std::string() const
313  {
314  return value;
315  }
316 
317  const std::string& string() const
318  {
319  return value;
320  }
321 
322 private:
323  std::string value;
324 };
325 
326 
327 inline bool operator==(const Path& left, const Path& right)
328 {
329  return left.string() == right.string();
330 }
331 
332 
333 inline bool operator!=(const Path& left, const Path& right)
334 {
335  return !(left == right);
336 }
337 
338 
339 inline bool operator<(const Path& left, const Path& right)
340 {
341  return left.string() < right.string();
342 }
343 
344 
345 inline bool operator>(const Path& left, const Path& right)
346 {
347  return right < left;
348 }
349 
350 
351 inline bool operator<=(const Path& left, const Path& right)
352 {
353  return !(left > right);
354 }
355 
356 
357 inline bool operator>=(const Path& left, const Path& right)
358 {
359  return !(left < right);
360 }
361 
362 
363 inline std::ostream& operator<<(
364  std::ostream& stream,
365  const Path& path)
366 {
367  return stream << path.string();
368 }
369 
370 #endif // __STOUT_PATH_HPP__
Path(const std::string &path)
Definition: path.hpp:150
std::string paths()
Definition: os.hpp:136
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 &lt;name&gt;&#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:40
bool operator>=(const Path &left, const Path &right)
Definition: path.hpp:357
Try< Nothing > remove(const std::string &hierarchy, const std::string &cgroup)
bool operator>(const Path &left, const Path &right)
Definition: path.hpp:345
Definition: strings.hpp:35
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:112
bool absolute() const
Definition: path.hpp:306
std::string dirname() const
Extracts the component up to, but not including, the final &#39;/&#39;.
Definition: path.hpp:238
Definition: none.hpp:27
Option< std::string > extension() const
Returns the file extension of the path, including the dot.
Definition: path.hpp:293
bool operator==(const Path &left, const Path &right)
Definition: path.hpp:327
std::ostream & operator<<(std::ostream &stream, const Call::Type &type)
Definition: agent.hpp:28
bool operator<=(const Path &left, const Path &right)
Definition: path.hpp:351
bool operator<(const Path &left, const Path &right)
Definition: path.hpp:339
std::string basename() const
Extracts the component following the final &#39;/&#39;.
Definition: path.hpp:179
std::string stringify(int flags)
bool startsWith(const std::string &s, const std::string &prefix)
Definition: strings.hpp:380
const std::string & string() const
Definition: path.hpp:317
Path()
Definition: path.hpp:148
bool operator!=(const Path &left, const Path &right)
Definition: path.hpp:333
constexpr char PATH_SEPARATOR
Definition: constants.hpp:24
Definition: strings.hpp:34