Flutter Engine
path_posix.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <dirent.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 
12 #include <cerrno>
13 #include <climits>
14 #include <cstdlib>
15 #include <cstring>
16 #include <functional>
17 #include <list>
18 #include <memory>
19 
22 
23 namespace filesystem {
24 namespace {
25 
26 size_t ResolveParentDirectoryTraversal(const std::string& path, size_t put) {
27  if (put >= 2) {
28  size_t previous_separator = path.rfind('/', put - 2);
29  if (previous_separator != std::string::npos)
30  return previous_separator + 1;
31  }
32  if (put == 1 && path[0] == '/') {
33  return put;
34  }
35  return 0;
36 }
37 
38 std::string GetCurrentDirectory() {
39  char buffer[PATH_MAX];
40  if (getcwd(buffer, sizeof(buffer)) == NULL) {
41  return {};
42  }
43  return std::string(buffer);
44 }
45 
46 } // namespace
47 
48 std::string SimplifyPath(std::string path) {
49  if (path.empty())
50  return ".";
51 
52  size_t put = 0;
53  size_t get = 0;
54  size_t traversal_root = 0;
55  size_t component_start = 0;
56 
57  if (path[0] == '/') {
58  put = 1;
59  get = 1;
60  component_start = 1;
61  }
62 
63  while (get < path.size()) {
64  char c = path[get];
65 
66  if (c == '.' && (get == component_start || get == component_start + 1)) {
67  // We've seen "." or ".." so far in this component. We need to continue
68  // searching.
69  ++get;
70  continue;
71  }
72 
73  if (c == '/') {
74  if (get == component_start || get == component_start + 1) {
75  // We've found a "/" or a "./", which we can elide.
76  ++get;
77  component_start = get;
78  continue;
79  }
80  if (get == component_start + 2) {
81  // We've found a "../", which means we need to remove the previous
82  // component.
83  if (put == traversal_root) {
84  path[put++] = '.';
85  path[put++] = '.';
86  path[put++] = '/';
87  traversal_root = put;
88  } else {
89  put = ResolveParentDirectoryTraversal(path, put);
90  }
91  ++get;
92  component_start = get;
93  continue;
94  }
95  }
96 
97  size_t next_separator = path.find('/', get);
98  if (next_separator == std::string::npos) {
99  // We've reached the last component.
100  break;
101  }
102  size_t next_component_start = next_separator + 1;
103  ++next_separator;
104  size_t component_size = next_component_start - component_start;
105  if (put != component_start && component_size > 0) {
106  path.replace(put, component_size,
107  path.substr(component_start, component_size));
108  }
109  put += component_size;
110  get = next_component_start;
111  component_start = next_component_start;
112  }
113 
114  size_t last_component_size = path.size() - component_start;
115  if (last_component_size == 1 && path[component_start] == '.') {
116  // The last component is ".", which we can elide.
117  } else if (last_component_size == 2 && path[component_start] == '.' &&
118  path[component_start + 1] == '.') {
119  // The last component is "..", which means we need to remove the previous
120  // component.
121  if (put == traversal_root) {
122  path[put++] = '.';
123  path[put++] = '.';
124  path[put++] = '/';
125  traversal_root = put;
126  } else {
127  put = ResolveParentDirectoryTraversal(path, put);
128  }
129  } else {
130  // Otherwise, we need to copy over the last component.
131  if (put != component_start && last_component_size > 0) {
132  path.replace(put, last_component_size,
133  path.substr(component_start, last_component_size));
134  }
135  put += last_component_size;
136  }
137 
138  if (put >= 2 && path[put - 1] == '/')
139  --put; // Trim trailing /
140  else if (put == 0)
141  return "."; // Use . for otherwise empty paths to treat them as relative.
142 
143  path.resize(put);
144  return path;
145 }
146 
147 std::string AbsolutePath(const std::string& path) {
148  if (path.size() > 0) {
149  if (path[0] == '/') {
150  // Path is already absolute.
151  return path;
152  }
153  return GetCurrentDirectory() + "/" + path;
154  } else {
155  // Path is empty.
156  return GetCurrentDirectory();
157  }
158 }
159 
160 std::string GetDirectoryName(const std::string& path) {
161  size_t separator = path.rfind('/');
162  if (separator == 0u)
163  return "/";
164  if (separator == std::string::npos)
165  return std::string();
166  return path.substr(0, separator);
167 }
168 
169 std::string GetBaseName(const std::string& path) {
170  size_t separator = path.rfind('/');
171  if (separator == std::string::npos)
172  return path;
173  return path.substr(separator + 1);
174 }
175 
176 std::string GetAbsoluteFilePath(const std::string& path) {
177 #if defined(OS_FUCHSIA)
178  // realpath() isn't supported by Fuchsia. See MG-425.
179  return SimplifyPath(AbsolutePath(path));
180 #else
181  char buffer[PATH_MAX];
182  if (realpath(path.c_str(), buffer) == nullptr)
183  return std::string();
184  return buffer;
185 #endif // defined(OS_FUCHSIA)
186 }
187 
188 } // namespace filesystem
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
std::string AbsolutePath(const std::string &path)
Definition: path_posix.cc:147
std::string GetBaseName(const std::string &path)
Definition: path_posix.cc:169
std::string GetAbsoluteFilePath(const std::string &path)
Definition: path_posix.cc:176
std::string GetDirectoryName(const std::string &path)
Definition: path_posix.cc:160
std::string SimplifyPath(std::string path)
Definition: path_posix.cc:48