]> git.sesse.net Git - vlc/blob - src/posix/dirs.c
eceb837bbf92d6dadd16fe7fff7676842931fb3a
[vlc] / src / posix / dirs.c
1 /*****************************************************************************
2  * dirs.c: XDG directories configuration
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
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
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, 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 <vlc_charset.h>
32 #include "config/configuration.h"
33
34 #include <unistd.h>
35 #include <pwd.h>
36 #include <assert.h>
37 #include <limits.h>
38
39 /**
40  * Determines the shared data directory
41  *
42  * @return a nul-terminated string or NULL. Use free() to release it.
43  */
44 char *config_GetDataDirDefault (void)
45 {
46     return strdup (DATA_PATH);
47 }
48
49 /**
50  * Determines the architecture-dependent data directory
51  *
52  * @return a string (always succeeds).
53  */
54 const char *config_GetLibDir (void)
55 {
56     return PKGLIBDIR;
57 }
58
59 /**
60  * Determines the system configuration directory.
61  *
62  * @return a string (always succeeds).
63  */
64 const char *config_GetConfDir( void )
65 {
66     return SYSCONFDIR;
67 }
68
69 static char *config_GetHomeDir (void)
70 {
71     /* 1/ Try $HOME  */
72     const char *home = getenv ("HOME");
73 #if defined(HAVE_GETPWUID_R)
74     /* 2/ Try /etc/passwd */
75     char buf[sysconf (_SC_GETPW_R_SIZE_MAX)];
76     if (home == NULL)
77     {
78         struct passwd pw, *res;
79
80         if (!getpwuid_r (getuid (), &pw, buf, sizeof (buf), &res) && res)
81             home = pw.pw_dir;
82     }
83 #endif
84
85     if (!home)
86         return NULL;
87
88     return FromLocaleDup (home);
89 }
90
91 static char *config_GetAppDir (const char *xdg_name, const char *xdg_default)
92 {
93     char *psz_dir;
94     char var[sizeof ("XDG__HOME") + strlen (xdg_name)];
95
96     /* XDG Base Directory Specification - Version 0.6 */
97     snprintf (var, sizeof (var), "XDG_%s_HOME", xdg_name);
98
99     char *psz_home = FromLocale (getenv (var));
100     if( psz_home )
101     {
102         if( asprintf( &psz_dir, "%s/vlc", psz_home ) == -1 )
103             psz_dir = NULL;
104         LocaleFree (psz_home);
105         return psz_dir;
106     }
107
108     psz_home = config_GetHomeDir ();
109     if( psz_home == NULL
110      || asprintf( &psz_dir, "%s/%s/vlc", psz_home, xdg_default ) == -1 )
111         psz_dir = NULL;
112     free (psz_home);
113     return psz_dir;
114 }
115
116 static char *config_GetTypeDir (const char *xdg_name)
117 {
118     const size_t namelen = strlen (xdg_name);
119     const char *home = getenv ("HOME");
120     const char *dir = getenv ("XDG_CONFIG_HOME");
121     const char *file = "user-dirs.dirs";
122
123     if (home == NULL)
124         return NULL;
125     if (dir == NULL)
126     {
127         dir = home;
128         file = ".config/user-dirs.dirs";
129     }
130
131     char *path;
132     if (asprintf (&path, "%s/%s", dir, file) == -1)
133         return NULL;
134
135     FILE *stream = fopen (path, "rt");
136     free (path);
137     path = NULL;
138     if (stream != NULL)
139     {
140         char *linebuf = NULL;
141         size_t linelen = 0;
142
143         while (getline (&linebuf, &linelen, stream) != -1)
144         {
145             char *ptr = linebuf;
146             ptr += strspn (ptr, " \t"); /* Skip whites */
147             if (strncmp (ptr, "XDG_", 4))
148                 continue;
149             ptr += 4; /* Skip XDG_ */
150             if (strncmp (ptr, xdg_name, namelen))
151                 continue;
152             ptr += namelen; /* Skip XDG type name */
153             if (strncmp (ptr, "_DIR", 4))
154                 continue;
155             ptr += 4; /* Skip _DIR */
156             ptr += strspn (ptr, " \t"); /* Skip whites */
157             if (*ptr != '=')
158                 continue;
159             ptr++; /* Skip equality sign */
160             ptr += strspn (ptr, " \t"); /* Skip whites */
161             if (*ptr != '"')
162                 continue;
163             ptr++; /* Skip quote */
164             linelen -= ptr - linebuf;
165
166             char *out;
167             if (strncmp (ptr, "$HOME", 5))
168             {
169                 path = malloc (linelen);
170                 if (path == NULL)
171                     continue;
172                 out = path;
173             }
174             else
175             {   /* Prefix with $HOME */
176                 const size_t homelen = strlen (home);
177                 ptr += 5;
178                 path = malloc (homelen + linelen - 5);
179                 if (path == NULL)
180                     continue;
181                 memcpy (path, home, homelen);
182                 out = path + homelen;
183             }
184
185             while (*ptr != '"')
186             {
187                 if (*ptr == '\\')
188                     ptr++;
189                 if (*ptr == '\0')
190                 {
191                     free (path);
192                     path = NULL;
193                     continue;
194                 }
195                 *(out++) = *(ptr++);
196             }
197             *out = '\0';
198             break;
199         }
200         free (linebuf);
201         fclose (stream);
202     }
203
204     /* Default! */
205     if (path == NULL)
206     {
207         if (strcmp (xdg_name, "DESKTOP") == 0)
208         {
209             if (asprintf (&path, "%s/Desktop", home) == -1)
210                 return NULL;
211         }
212         else
213             path = strdup (home);
214     }
215
216     char *ret = FromLocaleDup (path);
217     free (path);
218     return ret;
219 }
220
221
222 char *config_GetUserDir (vlc_userdir_t type)
223 {
224     switch (type)
225     {
226         case VLC_HOME_DIR:
227             break;
228         case VLC_CONFIG_DIR:
229             return config_GetAppDir ("CONFIG", ".config");
230         case VLC_DATA_DIR:
231             return config_GetAppDir ("DATA", ".local/share");
232         case VLC_CACHE_DIR:
233             return config_GetAppDir ("CACHE", ".cache");
234
235         case VLC_DESKTOP_DIR:
236             return config_GetTypeDir ("DESKTOP");
237         case VLC_DOWNLOAD_DIR:
238             return config_GetTypeDir ("DOWNLOAD");
239         case VLC_TEMPLATES_DIR:
240             return config_GetTypeDir ("TEMPLATES");
241         case VLC_PUBLICSHARE_DIR:
242             return config_GetTypeDir ("PUBLICSHARE");
243         case VLC_DOCUMENTS_DIR:
244             return config_GetTypeDir ("DOCUMENTS");
245         case VLC_MUSIC_DIR:
246             return config_GetTypeDir ("MUSIC");
247         case VLC_PICTURES_DIR:
248             return config_GetTypeDir ("PICTURES");
249         case VLC_VIDEOS_DIR:
250             return config_GetTypeDir ("VIDEOS");
251     }
252     return config_GetHomeDir ();
253 }