GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/fs/paths.cpp Lines: 31 78 39.7 %
Date: 2020-06-04 Branches: 15 100 15.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2019  The ManaPlus Developers
4
 *
5
 *  This file is part of The ManaPlus Client.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#ifdef _MSC_VER
22
# include "msvc/config.h"
23
#elif defined(HAVE_CONFIG_H)
24
#include "config.h"
25
#endif  // _MSC_VER
26
27
#include "fs/paths.h"
28
29
#include "fs/virtfs/fs.h"
30
31
#include "utils/checkutils.h"
32
#include "utils/stringutils.h"
33
34
#ifdef USE_X11
35
#include "fs/files.h"
36
37
#include "utils/foreach.h"
38
#endif  // USE_X11
39
40
#if defined(__native_client__) || defined(__SWITCH__)
41
#define realpath(N, R) strcpy(R, N)
42
#endif  // __native_client__
43
44
#ifdef WIN32
45
#include "fs/specialfolder.h"
46
#define realpath(N, R) _fullpath((R), (N), _MAX_PATH)
47
#endif
48
49
#if defined __OpenBSD__
50
#include <limits>
51
#else
52
#include <climits>
53
#endif  // WIN32
54
55
#ifndef WIN32
56
#include <unistd.h>
57
#include <sys/types.h>
58
#include <pwd.h>
59
#endif  // WIN32
60
61
PRAGMA48(GCC diagnostic push)
62
PRAGMA48(GCC diagnostic ignored "-Wshadow")
63
#ifdef ANDROID
64
#ifdef USE_SDL2
65
#include <SDL_system.h>
66
#endif  // USE_SDL2
67
#endif  // ANDROID
68
PRAGMA48(GCC diagnostic pop)
69
70
#if defined(__native_client__) || defined(__SWITCH__)
71
#ifndef SSIZE_MAX
72
#define SSIZE_MAX INT_MAX
73
#endif
74
#endif  // __native_client__
75
76
#include "debug.h"
77
78
namespace
79
{
80
1
    std::string mPackageDir;
81
}  // namespace
82
83
500
std::string getRealPath(const std::string &str)
84
{
85
#if defined(__GLIBC__)
86
500
    if (str.find("(unreachable)") != std::string::npos)
87
        return "";
88
#endif  // defined(__GLIBC__)
89
90
    // possible fix for realpath overflow
91
500
    if (str.size() > SSIZE_MAX / 10)
92
    {
93
        return std::string();
94
    }
95
#if defined(__OpenBSD__) || defined(__ANDROID__) || \
96
    defined(__native_client__) || defined(__SWITCH__)
97
    char *realPath = reinterpret_cast<char*>(calloc(PATH_MAX, sizeof(char)));
98
    if (!realPath)
99
        return "";
100
    realpath(str.c_str(), realPath);
101
#else  // defined(__OpenBSD__) || defined(__ANDROID__) ||
102
       // defined(__native_client__)
103
104
1000
    char *realPath = realpath(str.c_str(), nullptr);
105
500
    if (realPath == nullptr)
106
        return "";
107
#endif  // defined(__OpenBSD__) || defined(__ANDROID__) ||
108
        // defined(__native_client__)
109
110
1500
    std::string path = realPath;
111
500
    free(realPath);
112
500
    return path;
113
}
114
115
bool isRealPath(const std::string &str)
116
{
117
    return str == getRealPath(str);
118
}
119
120
11038
bool checkPath(const std::string &path)
121
{
122
11038
    if (path.empty())
123
        return true;
124
10736
    return path.find("../") == std::string::npos
125
10734
        && path.find("..\\") == std::string::npos
126
10734
        && path.find("/..") == std::string::npos
127
10734
        && path.find("\\..") == std::string::npos
128

21470
        && path.find("(unreachable)") == std::string::npos;
129
}
130
131
14129
void prepareFsPath(std::string &path)
132
{
133
#ifdef DEBUGFS
134
    std::string path2 = path;
135
#endif
136
14129
    sanitizePath(path);
137
// can be enabled for debugging
138
#ifdef DEBUGFS
139
    if (path != path2)
140
    {
141
        reportAlways("Path can be improved: '%s' -> '%s'",
142
            path2.c_str(),
143
            path.c_str())
144
    }
145
#endif
146
14129
}
147
148
764
std::string &fixDirSeparators(std::string &str)
149
{
150
#ifdef WIN32
151
    return replaceAll(str, "/", "\\");
152
#else
153
764
    return str;
154
#endif
155
}
156
157
std::string removeLast(const std::string &str)
158
{
159
    size_t pos2 = str.rfind('/');
160
    const size_t pos3 = str.rfind('\\');
161
    if (pos3 != std::string::npos)
162
    {
163
        if (pos2 == std::string::npos || pos3 > pos2)
164
            pos2 = pos3;
165
    }
166
    if (pos2 != std::string::npos)
167
        return str.substr(0, pos2);
168
    return str;
169
}
170
171
#ifdef WIN32
172
std::string getSelfName()
173
{
174
    return "manaplus.exe";
175
}
176
177
#elif defined(__APPLE__)
178
std::string getSelfName()
179
{
180
    return "manaplus.exe";
181
}
182
183
#elif defined __linux__ || defined __linux
184
185
std::string getSelfName()
186
{
187
    char buf[257];
188
    const ssize_t sz = readlink("/proc/self/exe", buf, 256);
189
    if (sz > 0 && sz < 256)
190
    {
191
        buf[sz] = 0;
192
        return buf;
193
    }
194
    return "";
195
}
196
197
#else  // WIN32
198
199
std::string getSelfName()
200
{
201
    return "";
202
}
203
204
#endif  // WIN32
205
206
std::string getPicturesDir()
207
{
208
#ifdef WIN32
209
    std::string dir = getSpecialFolderLocation(CSIDL_MYPICTURES);
210
    if (dir.empty())
211
        dir = getSpecialFolderLocation(CSIDL_DESKTOP);
212
    return dir;
213
#elif defined USE_X11
214
    char *xdg = getenv("XDG_CONFIG_HOME");
215
    std::string file;
216
    if (!xdg)
217
    {
218
        file = pathJoin(VirtFs::getUserDir(),
219
            ".config/user-dirs.dirs");
220
    }
221
    else
222
    {
223
        file = pathJoin(xdg, "user-dirs.dirs");
224
    }
225
226
    if (Files::existsLocal(file))
227
    {
228
        StringVect arr;
229
        Files::loadTextFileLocal(file, arr);
230
        FOR_EACH (StringVectCIter, it, arr)
231
        {
232
            std::string str = *it;
233
            if (findCutFirst(str, "XDG_PICTURES_DIR=\""))
234
            {
235
                str = str.substr(0, str.size() - 1);
236
                // use hack to replace $HOME var.
237
                // if in string other vars, fallback to default path
238
                replaceAll(str, "$HOME/", VirtFs::getUserDir());
239
                str = getRealPath(str);
240
                if (str.empty())
241
                    str = pathJoin(VirtFs::getUserDir(), "Desktop");
242
                return str;
243
            }
244
        }
245
    }
246
#endif  // WIN32
247
248
    return pathJoin(VirtFs::getUserDir(), "Desktop");
249
}
250
251
120
std::string getHomePath()
252
{
253
#if defined(UNITTESTS) && defined(UNITESTSDIR)
254
    std::string dir = UNITESTSDIR;
255
    if (findLast(dir, std::string(dirSeparator)) == false)
256
        dir += dirSeparator;
257
    return dir;
258
#else  // defined(UNITTESTS) && defined(UNITESTSDIR)
259
#ifdef WIN32
260
    return getSpecialFolderLocation(CSIDL_LOCAL_APPDATA);
261
#elif defined(__SWITCH__)
262
    return VirtFs::getBaseDir();
263
#else
264
120
    const char *path = getenv("HOME");
265
120
    if (path == nullptr)
266
    {
267
        const uid_t uid = getuid();
268
        const passwd *const pw = getpwuid(uid);
269
        if (pw != nullptr &&
270
            pw->pw_dir != nullptr)
271
        {
272
            path = pw->pw_dir;
273
        }
274
        if (path == nullptr)
275
            return dirSeparator;
276
    }
277
360
    std::string dir = path;
278

480
    if (findLast(dir, std::string(dirSeparator)) == false)
279
120
        dir += dirSeparator;
280
120
    return dir;
281
#endif  // WIN32
282
#endif  // defined(UNITTESTS) && defined(UNITESTSDIR)
283
}
284
285
#ifdef ANDROID
286
std::string getSdStoragePath()
287
{
288
    return getenv("DATADIR2");
289
}
290
#endif  // ANDROID
291
292
2
std::string getPackageDir()
293
{
294
2
    return mPackageDir;
295
}
296
297
void setPackageDir(const std::string &dir)
298
{
299
    mPackageDir = dir;
300
2
}