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

Line Branch Exec Source
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
1
    std::string mPackageDir;
82
}  // namespace
83
84
489
std::string getRealPath(const std::string &str)
85
{
86
#if defined(__GLIBC__)
87
489
    if (str.find("(unreachable)") != std::string::npos)
88
        return "";
89
#endif  // defined(__GLIBC__)
90
91
    // possible fix for realpath overflow
92
489
    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
978
    char *realPath = realpath(str.c_str(), nullptr);
106
489
    if (realPath == nullptr)
107
        return "";
108
#endif  // defined(__OpenBSD__) || defined(__ANDROID__) ||
109
        // defined(__native_client__)
110
111
1467
    std::string path = realPath;
112
489
    free(realPath);
113
489
    return path;
114
}
115
116
bool isRealPath(const std::string &str)
117
{
118
    return str == getRealPath(str);
119
}
120
121
10772
bool checkPath(const std::string &path)
122
{
123
10772
    if (path.empty())
124
        return true;
125
10481
    return path.find("../") == std::string::npos
126
10479
        && path.find("..\\") == std::string::npos
127
10479
        && path.find("/..") == std::string::npos
128
10479
        && path.find("\\..") == std::string::npos
129

20960
        && path.find("(unreachable)") == std::string::npos;
130
}
131
132
13830
void prepareFsPath(std::string &path)
133
{
134
#ifdef DEBUGFS
135
    std::string path2 = path;
136
#endif
137
13830
    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
13830
}
148
149
764
std::string &fixDirSeparators(std::string &str)
150
{
151
#ifdef WIN32
152
    return replaceAll(str, "/", "\\");
153
#else
154
764
    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
120
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
120
    const char *path = getenv("HOME");
266
120
    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
360
    std::string dir = path;
279

480
    if (findLast(dir, std::string(dirSeparator)) == false)
280
120
        dir += dirSeparator;
281
120
    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
2
std::string getPackageDir()
294
{
295
2
    return mPackageDir;
296
}
297
298
void setPackageDir(const std::string &dir)
299
{
300
    mPackageDir = dir;
301
2
}