ManaPlus
paths.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2011-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #ifdef _MSC_VER
23 # include "msvc/config.h"
24 #elif defined(HAVE_CONFIG_H)
25 #include "config.h"
26 #endif // _MSC_VER
27 
28 #include "fs/paths.h"
29 
30 #include "fs/virtfs/fs.h"
31 
32 #include "utils/checkutils.h"
33 #include "utils/stringutils.h"
34 
35 #ifdef USE_X11
36 #include "fs/files.h"
37 
38 #include "utils/foreach.h"
39 #endif // USE_X11
40 
41 #if defined(__native_client__) || defined(__SWITCH__)
42 #define realpath(N, R) strcpy(R, N)
43 #endif // __native_client__
44 
45 #ifdef WIN32
46 #include "fs/specialfolder.h"
47 #define realpath(N, R) _fullpath((R), (N), _MAX_PATH)
48 #endif
49 
50 #if defined __OpenBSD__
51 #include <limits>
52 #else
53 #include <climits>
54 #endif // WIN32
55 
56 #ifndef WIN32
57 #include <unistd.h>
58 #include <sys/types.h>
59 #include <pwd.h>
60 #endif // WIN32
61 
62 PRAGMA48(GCC diagnostic push)
63 PRAGMA48(GCC diagnostic ignored "-Wshadow")
64 #ifdef ANDROID
65 #ifdef USE_SDL2
66 #include <SDL_system.h>
67 #endif // USE_SDL2
68 #endif // ANDROID
69 PRAGMA48(GCC diagnostic pop)
70 
71 #if defined(__native_client__) || defined(__SWITCH__)
72 #ifndef SSIZE_MAX
73 #define SSIZE_MAX INT_MAX
74 #endif
75 #endif // __native_client__
76 
77 #include "debug.h"
78 
79 namespace
80 {
81  std::string mPackageDir;
82 } // namespace
83 
84 std::string getRealPath(const std::string &str)
85 {
86 #if defined(__GLIBC__)
87  if (str.find("(unreachable)") != std::string::npos)
88  return "";
89 #endif // defined(__GLIBC__)
90 
91  // possible fix for realpath overflow
92  if (str.size() > SSIZE_MAX / 10)
93  {
94  return std::string();
95  }
96 #if defined(__OpenBSD__) || defined(__ANDROID__) || \
97  defined(__native_client__) || defined(__SWITCH__)
98  char *realPath = reinterpret_cast<char*>(calloc(PATH_MAX, sizeof(char)));
99  if (!realPath)
100  return "";
101  realpath(str.c_str(), realPath);
102 #else // defined(__OpenBSD__) || defined(__ANDROID__) ||
103  // defined(__native_client__)
104 
105  char *realPath = realpath(str.c_str(), nullptr);
106  if (realPath == nullptr)
107  return "";
108 #endif // defined(__OpenBSD__) || defined(__ANDROID__) ||
109  // defined(__native_client__)
110 
111  std::string path = realPath;
112  free(realPath);
113  return path;
114 }
115 
116 bool isRealPath(const std::string &str)
117 {
118  return str == getRealPath(str);
119 }
120 
121 bool checkPath(const std::string &path)
122 {
123  if (path.empty())
124  return true;
125  return path.find("../") == std::string::npos
126  && path.find("..\\") == std::string::npos
127  && path.find("/..") == std::string::npos
128  && path.find("\\..") == std::string::npos
129  && path.find("(unreachable)") == std::string::npos;
130 }
131 
132 void prepareFsPath(std::string &path)
133 {
134 #ifdef DEBUGFS
135  std::string path2 = path;
136 #endif
137  sanitizePath(path);
138 // can be enabled for debugging
139 #ifdef DEBUGFS
140  if (path != path2)
141  {
142  reportAlways("Path can be improved: '%s' -> '%s'",
143  path2.c_str(),
144  path.c_str())
145  }
146 #endif
147 }
148 
149 std::string &fixDirSeparators(std::string &str)
150 {
151 #ifdef WIN32
152  return replaceAll(str, "/", "\\");
153 #else
154  return str;
155 #endif
156 }
157 
158 std::string removeLast(const std::string &str)
159 {
160  size_t pos2 = str.rfind('/');
161  const size_t pos3 = str.rfind('\\');
162  if (pos3 != std::string::npos)
163  {
164  if (pos2 == std::string::npos || pos3 > pos2)
165  pos2 = pos3;
166  }
167  if (pos2 != std::string::npos)
168  return str.substr(0, pos2);
169  return str;
170 }
171 
172 #ifdef WIN32
173 std::string getSelfName()
174 {
175  return "manaplus.exe";
176 }
177 
178 #elif defined(__APPLE__)
179 std::string getSelfName()
180 {
181  return "manaplus.exe";
182 }
183 
184 #elif defined __linux__ || defined __linux
185 
186 std::string getSelfName()
187 {
188  char buf[257];
189  const ssize_t sz = readlink("/proc/self/exe", buf, 256);
190  if (sz > 0 && sz < 256)
191  {
192  buf[sz] = 0;
193  return buf;
194  }
195  return "";
196 }
197 
198 #else // WIN32
199 
200 std::string getSelfName()
201 {
202  return "";
203 }
204 
205 #endif // WIN32
206 
207 std::string getPicturesDir()
208 {
209 #ifdef WIN32
210  std::string dir = getSpecialFolderLocation(CSIDL_MYPICTURES);
211  if (dir.empty())
212  dir = getSpecialFolderLocation(CSIDL_DESKTOP);
213  return dir;
214 #elif defined USE_X11
215  char *xdg = getenv("XDG_CONFIG_HOME");
216  std::string file;
217  if (!xdg)
218  {
219  file = pathJoin(VirtFs::getUserDir(),
220  ".config/user-dirs.dirs");
221  }
222  else
223  {
224  file = pathJoin(xdg, "user-dirs.dirs");
225  }
226 
227  if (Files::existsLocal(file))
228  {
229  StringVect arr;
230  Files::loadTextFileLocal(file, arr);
231  FOR_EACH (StringVectCIter, it, arr)
232  {
233  std::string str = *it;
234  if (findCutFirst(str, "XDG_PICTURES_DIR=\""))
235  {
236  str = str.substr(0, str.size() - 1);
237  // use hack to replace $HOME var.
238  // if in string other vars, fallback to default path
239  replaceAll(str, "$HOME/", VirtFs::getUserDir());
240  str = getRealPath(str);
241  if (str.empty())
242  str = pathJoin(VirtFs::getUserDir(), "Desktop");
243  return str;
244  }
245  }
246  }
247 #endif // WIN32
248 
249  return pathJoin(VirtFs::getUserDir(), "Desktop");
250 }
251 
252 std::string getHomePath()
253 {
254 #if defined(UNITTESTS) && defined(UNITESTSDIR)
255  std::string dir = UNITESTSDIR;
256  if (findLast(dir, std::string(dirSeparator)) == false)
257  dir += dirSeparator;
258  return dir;
259 #else // defined(UNITTESTS) && defined(UNITESTSDIR)
260 #ifdef WIN32
261  return getSpecialFolderLocation(CSIDL_LOCAL_APPDATA);
262 #elif defined(__SWITCH__)
263  return VirtFs::getBaseDir();
264 #else
265  const char *path = getenv("HOME");
266  if (path == nullptr)
267  {
268  const uid_t uid = getuid();
269  const passwd *const pw = getpwuid(uid);
270  if (pw != nullptr &&
271  pw->pw_dir != nullptr)
272  {
273  path = pw->pw_dir;
274  }
275  if (path == nullptr)
276  return dirSeparator;
277  }
278  std::string dir = path;
279  if (findLast(dir, std::string(dirSeparator)) == false)
280  dir += dirSeparator;
281  return dir;
282 #endif // WIN32
283 #endif // defined(UNITTESTS) && defined(UNITESTSDIR)
284 }
285 
286 #ifdef ANDROID
287 std::string getSdStoragePath()
288 {
289  return getenv("DATADIR2");
290 }
291 #endif // ANDROID
292 
293 std::string getPackageDir()
294 {
295  return mPackageDir;
296 }
297 
298 void setPackageDir(const std::string &dir)
299 {
300  mPackageDir = dir;
301 }
#define reportAlways(...)
Definition: checkutils.h:253
const char * dirSeparator
Definition: fs.cpp:43
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define PRAGMA48(str)
Definition: localconsts.h:199
bool loadTextFileLocal(const std::string &fileName, StringVect &lines)
Definition: files.cpp:229
bool existsLocal(const std::string &path)
Definition: files.cpp:209
const char * getBaseDir()
Definition: fs.cpp:79
const char * getUserDir()
Definition: fs.cpp:84
std::string & fixDirSeparators(std::string &str)
Definition: paths.cpp:149
std::string getRealPath(const std::string &str)
Definition: paths.cpp:84
std::string getPicturesDir()
Definition: paths.cpp:207
std::string getPackageDir()
Definition: paths.cpp:293
std::string getSelfName()
Definition: paths.cpp:200
bool checkPath(const std::string &path)
Definition: paths.cpp:121
void setPackageDir(const std::string &dir)
Definition: paths.cpp:298
std::string getHomePath()
Definition: paths.cpp:252
bool isRealPath(const std::string &str)
Definition: paths.cpp:116
void prepareFsPath(std::string &path)
Definition: paths.cpp:132
std::string removeLast(const std::string &str)
Definition: paths.cpp:158
void sanitizePath(std::string &path)
std::string & replaceAll(std::string &context, const std::string &from, const std::string &to)
bool findCutFirst(std::string &str1, const std::string &str2)
bool findLast(const std::string &str1, const std::string &str2)
std::string pathJoin(std::string str1, const std::string &str2)
StringVect::const_iterator StringVectCIter
Definition: stringvector.h:31
std::vector< std::string > StringVect
Definition: stringvector.h:29