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

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2018  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
#ifdef __native_client__
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
#ifdef __native_client__
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
489
std::string getRealPath(const std::string &str)
84
{
85
#if defined(__GLIBC__)
86
489
    if (str.find("(unreachable)") != std::string::npos)
87
        return "";
88
#endif  // defined(__GLIBC__)
89
90
    // possible fix for realpath overflow
91
489
    if (str.size() > SSIZE_MAX / 10)
92
    {
93
        return std::string();
94
    }
95
#if defined(__OpenBSD__) || defined(__ANDROID__) || defined(__native_client__)
96
    char *realPath = reinterpret_cast<char*>(calloc(PATH_MAX, sizeof(char)));
97
    if (!realPath)
98
        return "";
99
    realpath(str.c_str(), realPath);
100
#else  // defined(__OpenBSD__) || defined(__ANDROID__) ||
101
       // defined(__native_client__)
102
103
978
    char *realPath = realpath(str.c_str(), nullptr);
104
489
    if (realPath == nullptr)
105
        return "";
106
#endif  // defined(__OpenBSD__) || defined(__ANDROID__) ||
107
        // defined(__native_client__)
108
109
1467
    std::string path = realPath;
110
489
    free(realPath);
111
489
    return path;
112
}
113
114
bool isRealPath(const std::string &str)
115
{
116
    return str == getRealPath(str);
117
}
118
119
10774
bool checkPath(const std::string &path)
120
{
121
10774
    if (path.empty())
122
        return true;
123
10483
    return path.find("../") == std::string::npos
124
10481
        && path.find("..\\") == std::string::npos
125
10481
        && path.find("/..") == std::string::npos
126
10481
        && path.find("\\..") == std::string::npos
127

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

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