1 | // |
---|---|
2 | // Path_UNIX.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Filesystem |
6 | // Module: Path |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Path_UNIX.h" |
16 | #include "Poco/Exception.h" |
17 | #include "Poco/Environment_UNIX.h" |
18 | #include "Poco/Ascii.h" |
19 | #include <unistd.h> |
20 | #include <stdlib.h> |
21 | #include <sys/types.h> |
22 | #if !defined(POCO_VXWORKS) |
23 | #include <pwd.h> |
24 | #endif |
25 | #if POCO_OS == POCO_OS_MAC_OS_X |
26 | #include <mach-o/dyld.h> |
27 | #endif |
28 | #include <climits> |
29 | |
30 | |
31 | #ifndef PATH_MAX |
32 | #define PATH_MAX 1024 // fallback |
33 | #endif |
34 | |
35 | |
36 | namespace Poco { |
37 | |
38 | |
39 | std::string PathImpl::currentImpl() |
40 | { |
41 | std::string path; |
42 | char cwd[PATH_MAX]; |
43 | if (getcwd(cwd, sizeof(cwd))) |
44 | path = cwd; |
45 | else |
46 | throw SystemException("cannot get current directory"); |
47 | std::string::size_type n = path.size(); |
48 | if (n > 0 && path[n - 1] != '/') path.append("/"); |
49 | return path; |
50 | } |
51 | |
52 | |
53 | std::string PathImpl::homeImpl() |
54 | { |
55 | #if defined(POCO_VXWORKS) |
56 | if (EnvironmentImpl::hasImpl("HOME")) |
57 | return EnvironmentImpl::getImpl("HOME"); |
58 | else |
59 | return "/"; |
60 | #else |
61 | std::string path; |
62 | struct passwd* pwd = getpwuid(getuid()); |
63 | if (pwd) |
64 | path = pwd->pw_dir; |
65 | else |
66 | { |
67 | pwd = getpwuid(geteuid()); |
68 | if (pwd) |
69 | path = pwd->pw_dir; |
70 | else |
71 | if (EnvironmentImpl::hasImpl("HOME")) |
72 | path = EnvironmentImpl::getImpl("HOME"); |
73 | } |
74 | std::string::size_type n = path.size(); |
75 | if (n > 0 && path[n - 1] != '/') path.append("/"); |
76 | return path; |
77 | #endif |
78 | } |
79 | |
80 | |
81 | std::string PathImpl::configHomeImpl() |
82 | { |
83 | #if defined(POCO_VXWORKS) |
84 | return PathImpl::homeImpl(); |
85 | #elif POCO_OS == POCO_OS_MAC_OS_X |
86 | std::string path = PathImpl::homeImpl(); |
87 | std::string::size_type n = path.size(); |
88 | if (n > 0 && path[n - 1] == '/') |
89 | path.append("Library/Preferences/"); |
90 | return path; |
91 | #else |
92 | std::string path; |
93 | if (EnvironmentImpl::hasImpl("XDG_CONFIG_HOME")) |
94 | path = EnvironmentImpl::getImpl("XDG_CONFIG_HOME"); |
95 | if (!path.empty()) |
96 | return path; |
97 | |
98 | path = PathImpl::homeImpl(); |
99 | std::string::size_type n = path.size(); |
100 | if (n > 0 && path[n - 1] == '/') |
101 | path.append(".config/"); |
102 | |
103 | return path; |
104 | #endif |
105 | } |
106 | |
107 | |
108 | std::string PathImpl::dataHomeImpl() |
109 | { |
110 | #if defined(POCO_VXWORKS) |
111 | return PathImpl::homeImpl(); |
112 | #elif POCO_OS == POCO_OS_MAC_OS_X |
113 | std::string path = PathImpl::homeImpl(); |
114 | std::string::size_type n = path.size(); |
115 | if (n > 0 && path[n - 1] == '/') |
116 | path.append("Library/Application Support/"); |
117 | return path; |
118 | #else |
119 | std::string path; |
120 | if (EnvironmentImpl::hasImpl("XDG_DATA_HOME")) |
121 | path = EnvironmentImpl::getImpl("XDG_DATA_HOME"); |
122 | if (!path.empty()) |
123 | return path; |
124 | |
125 | path = PathImpl::homeImpl(); |
126 | std::string::size_type n = path.size(); |
127 | if (n > 0 && path[n - 1] == '/') |
128 | path.append(".local/share/"); |
129 | |
130 | return path; |
131 | #endif |
132 | } |
133 | |
134 | |
135 | std::string PathImpl::cacheHomeImpl() |
136 | { |
137 | #if defined(POCO_VXWORKS) |
138 | return PathImpl::tempImpl(); |
139 | #elif POCO_OS == POCO_OS_MAC_OS_X |
140 | std::string path = PathImpl::homeImpl(); |
141 | std::string::size_type n = path.size(); |
142 | if (n > 0 && path[n - 1] == '/') |
143 | path.append("Library/Caches/"); |
144 | return path; |
145 | #else |
146 | std::string path; |
147 | if (EnvironmentImpl::hasImpl("XDG_CACHE_HOME")) |
148 | path = EnvironmentImpl::getImpl("XDG_CACHE_HOME"); |
149 | if (!path.empty()) |
150 | return path; |
151 | |
152 | path = PathImpl::homeImpl(); |
153 | std::string::size_type n = path.size(); |
154 | if (n > 0 && path[n - 1] == '/') |
155 | path.append(".cache/"); |
156 | |
157 | return path; |
158 | #endif |
159 | } |
160 | |
161 | |
162 | std::string PathImpl::selfImpl() |
163 | { |
164 | #if POCO_OS == POCO_OS_MAC_OS_X |
165 | char path[1024]; |
166 | uint32_t size = sizeof(path); |
167 | if (_NSGetExecutablePath(path, &size) != 0) |
168 | throw SystemException("cannot obtain path for executable"); |
169 | return path; |
170 | #elif POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID |
171 | #ifdef PATH_MAX |
172 | std::size_t sz = PATH_MAX; |
173 | #else |
174 | std::size_t sz = 4096; |
175 | #endif |
176 | char buf[sz]; |
177 | ssize_t ret = readlink("/proc/self/exe", buf, sz); |
178 | if (-1 == ret) throw SystemException("cannot obtain path for executable"); |
179 | poco_assert_dbg(ret < sz); |
180 | buf[ret-1] = '\0'; |
181 | return buf; |
182 | #endif |
183 | // TODO (see https://stackoverflow.com/a/1024937/205386) |
184 | // Solaris: getexecname() |
185 | // FreeBSD: sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1 |
186 | // FreeBSD if it has procfs: readlink /proc/curproc/file (FreeBSD doesn't have procfs by default) |
187 | // NetBSD: readlink /proc/curproc/exe |
188 | // DragonFly BSD: readlink /proc/curproc/file |
189 | return ""; |
190 | } |
191 | |
192 | |
193 | std::string PathImpl::tempImpl() |
194 | { |
195 | std::string path; |
196 | char* tmp = getenv("TMPDIR"); |
197 | if (tmp) |
198 | { |
199 | path = tmp; |
200 | std::string::size_type n = path.size(); |
201 | if (n > 0 && path[n - 1] != '/') path.append("/"); |
202 | } |
203 | else |
204 | { |
205 | path = "/tmp/"; |
206 | } |
207 | return path; |
208 | } |
209 | |
210 | |
211 | std::string PathImpl::configImpl() |
212 | { |
213 | std::string path; |
214 | |
215 | #if POCO_OS == POCO_OS_MAC_OS_X |
216 | path = "/Library/Preferences/"; |
217 | #else |
218 | path = "/etc/"; |
219 | #endif |
220 | return path; |
221 | } |
222 | |
223 | |
224 | std::string PathImpl::nullImpl() |
225 | { |
226 | #if defined(POCO_VXWORKS) |
227 | return "/null"; |
228 | #else |
229 | return "/dev/null"; |
230 | #endif |
231 | } |
232 | |
233 | |
234 | std::string PathImpl::expandImpl(const std::string& path) |
235 | { |
236 | std::string result; |
237 | std::string::const_iterator it = path.begin(); |
238 | std::string::const_iterator end = path.end(); |
239 | if (it != end && *it == '~') |
240 | { |
241 | ++it; |
242 | if (it != end && *it == '/') |
243 | { |
244 | const char* homeEnv = getenv("HOME"); |
245 | if (homeEnv) |
246 | { |
247 | result += homeEnv; |
248 | std::string::size_type resultSize = result.size(); |
249 | if (resultSize > 0 && result[resultSize - 1] != '/') |
250 | result.append("/"); |
251 | } |
252 | else |
253 | { |
254 | result += homeImpl(); |
255 | } |
256 | ++it; |
257 | } |
258 | else result += '~'; |
259 | } |
260 | while (it != end) |
261 | { |
262 | if (*it == '\\') |
263 | { |
264 | ++it; |
265 | if (*it == '$') |
266 | { |
267 | result += *it++; |
268 | } |
269 | } |
270 | else if (*it == '$') |
271 | { |
272 | std::string var; |
273 | ++it; |
274 | if (it != end && *it == '{') |
275 | { |
276 | ++it; |
277 | while (it != end && *it != '}') var += *it++; |
278 | if (it != end) ++it; |
279 | } |
280 | else |
281 | { |
282 | while (it != end && (Ascii::isAlphaNumeric(*it) || *it == '_')) var += *it++; |
283 | } |
284 | char* val = getenv(var.c_str()); |
285 | if (val) result += val; |
286 | } |
287 | else result += *it++; |
288 | } |
289 | std::string::size_type found = result.find("//"); |
290 | while (found != std::string::npos) |
291 | { |
292 | result.replace(found, 2, "/"); |
293 | found = result.find("//", found+1); |
294 | } |
295 | return result; |
296 | } |
297 | |
298 | |
299 | void PathImpl::listRootsImpl(std::vector<std::string>& roots) |
300 | { |
301 | roots.clear(); |
302 | roots.push_back("/"); |
303 | } |
304 | |
305 | |
306 | } // namespace Poco |
307 |