Coverage Report

Created: 2026-09-01 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/src/posix/dirs.c
Line
Count
Source
1
/*****************************************************************************
2
 * dirs.c: XDG directories configuration
3
 *****************************************************************************
4
 * Copyright (C) 2001-2007 VLC authors and VideoLAN
5
 * Copyright © 2007-2009 Rémi Denis-Courmont
6
 *
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
24
#ifdef HAVE_CONFIG_H
25
# include "config.h"
26
#endif
27
28
#include <vlc_common.h>
29
30
#include "../libvlc.h"
31
#include "../config/configuration.h"
32
33
#include <unistd.h>
34
#include <pwd.h>
35
#include <assert.h>
36
#include <limits.h>
37
38
/**
39
 * Determines the architecture-dependent data directory
40
 *
41
 * @return a string (always succeeds).
42
 */
43
VLC_WEAK char *config_GetLibDir(void)
44
0
{
45
0
    return strdup(LIBDIR);
46
0
}
47
48
char *config_GetSysPath(vlc_sysdir_t type, const char *filename)
49
0
{
50
0
    static const char env_vars[][17] = {
51
0
        [VLC_PKG_DATA_DIR] = "VLC_DATA_PATH",
52
0
        [VLC_PKG_LIB_DIR] = "VLC_LIB_PATH",
53
0
        [VLC_PKG_LIBEXEC_DIR] = "VLC_LIBEXEC_PATH",
54
0
    };
55
56
0
    if (type < ARRAY_SIZE(env_vars)) {
57
0
        const char *name = env_vars[type];
58
0
         if (*name != '\0') {
59
0
             const char *value = getenv(name);
60
0
             if (value != NULL) {
61
0
                 const char *fmt = (filename != NULL) ? "%s/%s" : "%s";
62
0
                 char *filepath;
63
64
0
                 if (unlikely(asprintf(&filepath, fmt, value, filename) == -1))
65
0
                     filepath = NULL;
66
0
                 return filepath;
67
0
             }
68
0
         }
69
0
    }
70
71
0
    char *libdir = config_GetLibDir();
72
0
    if (libdir == NULL)
73
0
        return NULL; /* OOM */
74
75
0
    static const char *const dirs[] = {
76
0
        [VLC_PKG_DATA_DIR] = PKGDATADIR,
77
0
        [VLC_PKG_LIB_DIR] = PKGLIBDIR,
78
0
        [VLC_PKG_LIBEXEC_DIR] = PKGLIBEXECDIR,
79
0
        [VLC_SYSDATA_DIR] = SYSDATADIR,
80
0
        [VLC_LIB_DIR] = LIBDIR,
81
0
        [VLC_LIBEXEC_DIR] = LIBEXECDIR,
82
0
        [VLC_LOCALE_DIR] = LOCALEDIR,
83
0
    };
84
0
    assert(type < ARRAY_SIZE(dirs));
85
86
0
    const char *dir_static = dirs[type];
87
0
    assert(*dir_static != '\0');
88
    /* Look for common static prefix. */
89
0
    size_t prefix_len = 0;
90
0
    while (prefix_len < strlen(LIBDIR)
91
0
        && LIBDIR[prefix_len] == dir_static[prefix_len])
92
0
        prefix_len++;
93
94
    /* Check that suffix matches between static and dynamic libdir paths. */
95
0
    char *filepath = NULL;
96
0
    size_t suffix_len = strlen(LIBDIR) - prefix_len;
97
0
    size_t libdir_len = strlen(libdir);
98
99
0
    if (suffix_len > libdir_len
100
0
     || memcmp(&LIBDIR[prefix_len], libdir + (libdir_len - suffix_len),
101
0
               suffix_len)) {
102
0
        suffix_len = libdir_len;
103
0
        prefix_len = 0;
104
0
    }
105
106
    /* Graft non-common static suffix to dynamically computed common prefix. */
107
0
    const char *fmt = (filename != NULL) ? "%.*s%s/%s" : "%.*s%s";
108
109
0
    if (unlikely(asprintf(&filepath, fmt, (int)(libdir_len - suffix_len),
110
0
                          libdir, dir_static + prefix_len, filename) == -1))
111
0
        filepath = NULL;
112
113
0
    free(libdir);
114
0
    return filepath;
115
0
}
116
117
static char *config_GetHomeDir (void)
118
0
{
119
    /* 1/ Try $HOME  */
120
0
    const char *home = getenv ("HOME");
121
0
    if (home != NULL)
122
0
        return strdup (home);
123
0
#if defined(HAVE_GETPWUID_R)
124
    /* 2/ Try /etc/passwd */
125
0
    long max = sysconf (_SC_GETPW_R_SIZE_MAX);
126
0
    if (max != -1)
127
0
    {
128
0
        char buf[max];
129
0
        struct passwd pwbuf, *pw;
130
131
0
        if (getpwuid_r (getuid (), &pwbuf, buf, sizeof (buf), &pw) == 0
132
0
          && pw != NULL)
133
0
            return strdup (pw->pw_dir);
134
0
    }
135
0
#endif
136
0
    return NULL;
137
0
}
138
139
static char *config_GetAppDir (const char *xdg_name, const char *xdg_default)
140
0
{
141
0
    char *psz_dir;
142
0
    char var[sizeof ("XDG__HOME") + strlen (xdg_name)];
143
144
    /* XDG Base Directory Specification - Version 0.6 */
145
0
    snprintf (var, sizeof (var), "XDG_%s_HOME", xdg_name);
146
147
0
    const char *home = getenv (var);
148
0
    if (home != NULL)
149
0
    {
150
0
        if (asprintf (&psz_dir, "%s/vlc", home) == -1)
151
0
            psz_dir = NULL;
152
0
        return psz_dir;
153
0
    }
154
155
0
    char *psz_home = config_GetHomeDir ();
156
0
    if( psz_home == NULL
157
0
     || asprintf( &psz_dir, "%s/%s/vlc", psz_home, xdg_default ) == -1 )
158
0
        psz_dir = NULL;
159
0
    free (psz_home);
160
0
    return psz_dir;
161
0
}
162
163
static char *config_GetTypeDir (const char *xdg_name)
164
0
{
165
0
    const size_t namelen = strlen (xdg_name);
166
0
    const char *home = getenv ("HOME");
167
0
    const char *dir = getenv ("XDG_CONFIG_HOME");
168
0
    const char *file = "user-dirs.dirs";
169
170
0
    if (home == NULL)
171
0
        return NULL;
172
0
    if (dir == NULL)
173
0
    {
174
0
        dir = home;
175
0
        file = ".config/user-dirs.dirs";
176
0
    }
177
178
0
    char *path;
179
0
    if (asprintf (&path, "%s/%s", dir, file) == -1)
180
0
        return NULL;
181
182
0
    FILE *stream = fopen (path, "rte");
183
0
    free (path);
184
0
    path = NULL;
185
0
    if (stream != NULL)
186
0
    {
187
0
        char *linebuf = NULL;
188
0
        size_t linelen = 0;
189
190
0
        while (getline (&linebuf, &linelen, stream) != -1)
191
0
        {
192
0
            char *ptr = linebuf;
193
0
            ptr += strspn (ptr, " \t"); /* Skip whites */
194
0
            if (strncmp (ptr, "XDG_", 4))
195
0
                continue;
196
0
            ptr += 4; /* Skip XDG_ */
197
0
            if (strncmp (ptr, xdg_name, namelen))
198
0
                continue;
199
0
            ptr += namelen; /* Skip XDG type name */
200
0
            if (strncmp (ptr, "_DIR", 4))
201
0
                continue;
202
0
            ptr += 4; /* Skip _DIR */
203
0
            ptr += strspn (ptr, " \t"); /* Skip whites */
204
0
            if (*ptr != '=')
205
0
                continue;
206
0
            ptr++; /* Skip equality sign */
207
0
            ptr += strspn (ptr, " \t"); /* Skip whites */
208
0
            if (*ptr != '"')
209
0
                continue;
210
0
            ptr++; /* Skip quote */
211
0
            linelen -= ptr - linebuf;
212
213
0
            char *out;
214
0
            if (strncmp (ptr, "$HOME", 5))
215
0
            {
216
0
                path = malloc (linelen);
217
0
                if (path == NULL)
218
0
                    continue;
219
0
                out = path;
220
0
            }
221
0
            else
222
0
            {   /* Prefix with $HOME */
223
0
                const size_t homelen = strlen (home);
224
0
                ptr += 5;
225
0
                path = malloc (homelen + linelen - 5);
226
0
                if (path == NULL)
227
0
                    continue;
228
0
                memcpy (path, home, homelen);
229
0
                out = path + homelen;
230
0
            }
231
232
0
            while (*ptr != '"')
233
0
            {
234
0
                if (*ptr == '\\')
235
0
                    ptr++;
236
0
                if (*ptr == '\0')
237
0
                {
238
0
                    free (path);
239
0
                    path = NULL;
240
0
                    break;
241
0
                }
242
0
                *(out++) = *(ptr++);
243
0
            }
244
0
            if (path != NULL)
245
0
                *out = '\0';
246
0
            break;
247
0
        }
248
0
        free (linebuf);
249
0
        fclose (stream);
250
0
    }
251
252
    /* Default! */
253
0
    if (path == NULL)
254
0
    {
255
0
        if (strcmp (xdg_name, "DESKTOP") == 0)
256
0
        {
257
0
            if (asprintf (&path, "%s/Desktop", home) == -1)
258
0
                return NULL;
259
0
        }
260
0
        else
261
0
            path = strdup (home);
262
0
    }
263
264
0
    return path;
265
0
}
266
267
268
char *platform_GetUserDir (vlc_userdir_t type)
269
0
{
270
0
    switch (type)
271
0
    {
272
0
        case VLC_HOME_DIR:
273
0
            break;
274
0
        case VLC_CONFIG_DIR:
275
0
            return config_GetAppDir ("CONFIG", ".config");
276
0
        case VLC_USERDATA_DIR:
277
0
            return config_GetAppDir ("DATA", ".local/share");
278
0
        case VLC_CACHE_DIR:
279
0
            return config_GetAppDir ("CACHE", ".cache");
280
281
0
        case VLC_DESKTOP_DIR:
282
0
            return config_GetTypeDir ("DESKTOP");
283
0
        case VLC_DOWNLOAD_DIR:
284
0
            return config_GetTypeDir ("DOWNLOAD");
285
0
        case VLC_TEMPLATES_DIR:
286
0
            return config_GetTypeDir ("TEMPLATES");
287
0
        case VLC_PUBLICSHARE_DIR:
288
0
            return config_GetTypeDir ("PUBLICSHARE");
289
0
        case VLC_DOCUMENTS_DIR:
290
0
            return config_GetTypeDir ("DOCUMENTS");
291
0
        case VLC_MUSIC_DIR:
292
0
            return config_GetTypeDir ("MUSIC");
293
0
        case VLC_SNAPSHOTS_DIR:
294
0
        case VLC_PICTURES_DIR:
295
0
            return config_GetTypeDir ("PICTURES");
296
0
        case VLC_VIDEOS_DIR:
297
0
            return config_GetTypeDir ("VIDEOS");
298
0
    }
299
0
    return config_GetHomeDir ();
300
0
}