Initial revision 6759
[qball-mpd.git] / src / path.c
blobf30eb07936791eb816580727092f8126a31268d0
1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 * This project's homepage is: http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "path.h"
20 #include "log.h"
21 #include "charConv.h"
22 #include "conf.h"
23 #include "utf8.h"
24 #include "utils.h"
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <dirent.h>
34 #ifdef HAVE_LOCALE
35 #ifdef HAVE_LANGINFO_CODESET
36 #include <locale.h>
37 #include <langinfo.h>
38 #endif
39 #endif
41 const char *musicDir;
42 static const char *playlistDir;
43 static char *fsCharset;
45 static char *pathConvCharset(char *to, char *from, char *str, char *ret)
47 if (ret)
48 free(ret);
49 return setCharSetConversion(to, from) ? NULL : convStrDup(str);
52 char *fsCharsetToUtf8(char *str)
54 static char *ret;
56 ret = pathConvCharset("UTF-8", fsCharset, str, ret);
58 if (ret && !validUtf8String(ret)) {
59 free(ret);
60 ret = NULL;
63 return ret;
66 char *utf8ToFsCharset(char *str)
68 static char *ret;
70 ret = pathConvCharset(fsCharset, "UTF-8", str, ret);
72 if (!ret)
73 ret = xstrdup(str);
75 return ret;
78 void setFsCharset(char *charset)
80 int error = 0;
82 if (fsCharset)
83 free(fsCharset);
85 fsCharset = xstrdup(charset);
87 DEBUG("setFsCharset: fs charset is: %s\n", fsCharset);
89 if (setCharSetConversion("UTF-8", fsCharset) != 0) {
90 WARNING("fs charset conversion problem: "
91 "not able to convert from \"%s\" to \"%s\"\n",
92 fsCharset, "UTF-8");
93 error = 1;
95 if (setCharSetConversion(fsCharset, "UTF-8") != 0) {
96 WARNING("fs charset conversion problem: "
97 "not able to convert from \"%s\" to \"%s\"\n",
98 "UTF-8", fsCharset);
99 error = 1;
102 if (error) {
103 free(fsCharset);
104 WARNING("setting fs charset to ISO-8859-1!\n");
105 fsCharset = xstrdup("ISO-8859-1");
109 char *getFsCharset(void)
111 return fsCharset;
114 static char *appendSlash(char **path)
116 char *temp = *path;
117 int len = strlen(temp);
119 if (temp[len - 1] != '/') {
120 temp = xmalloc(len + 2);
121 memset(temp, 0, len + 2);
122 memcpy(temp, *path, len);
123 temp[len] = '/';
124 free(*path);
125 *path = temp;
128 return temp;
131 void initPaths(void)
133 ConfigParam *musicParam = parseConfigFilePath(CONF_MUSIC_DIR, 1);
134 ConfigParam *playlistParam = parseConfigFilePath(CONF_PLAYLIST_DIR, 1);
135 ConfigParam *fsCharsetParam = getConfigParam(CONF_FS_CHARSET);
137 char *charset = NULL;
138 char *originalLocale;
139 DIR *dir;
141 musicDir = appendSlash(&(musicParam->value));
142 playlistDir = appendSlash(&(playlistParam->value));
144 if ((dir = opendir(playlistDir)) == NULL) {
145 FATAL("cannot open %s \"%s\" (config line %i): %s\n",
146 CONF_PLAYLIST_DIR, playlistParam->value,
147 playlistParam->line, strerror(errno));
149 closedir(dir);
151 if ((dir = opendir(musicDir)) == NULL) {
152 FATAL("cannot open %s \"%s\" (config line %i): %s\n",
153 CONF_MUSIC_DIR, musicParam->value,
154 musicParam->line, strerror(errno));
156 closedir(dir);
158 if (fsCharsetParam) {
159 charset = xstrdup(fsCharsetParam->value);
161 #ifdef HAVE_LOCALE
162 #ifdef HAVE_LANGINFO_CODESET
163 else if ((originalLocale = setlocale(LC_CTYPE, NULL))) {
164 char *temp;
165 char *currentLocale;
166 originalLocale = xstrdup(originalLocale);
168 if (!(currentLocale = setlocale(LC_CTYPE, ""))) {
169 WARNING("problems setting current locale with "
170 "setlocale()\n");
171 } else {
172 if (strcmp(currentLocale, "C") == 0 ||
173 strcmp(currentLocale, "POSIX") == 0) {
174 WARNING("current locale is \"%s\"\n",
175 currentLocale);
176 } else if ((temp = nl_langinfo(CODESET))) {
177 charset = xstrdup(temp);
178 } else
179 WARNING
180 ("problems getting charset for locale\n");
181 if (!setlocale(LC_CTYPE, originalLocale)) {
182 WARNING
183 ("problems resetting locale with setlocale()\n");
187 free(originalLocale);
188 } else
189 WARNING("problems getting locale with setlocale()\n");
190 #endif
191 #endif
193 if (charset) {
194 setFsCharset(charset);
195 free(charset);
196 } else {
197 WARNING("setting filesystem charset to ISO-8859-1\n");
198 setFsCharset("ISO-8859-1");
202 void finishPaths(void)
204 free(fsCharset);
205 fsCharset = NULL;
208 static char *pfx_path(const char *path, const char *pfx, const size_t pfx_len)
210 static char ret[MAXPATHLEN+1];
211 size_t rp_len = strlen(path);
213 /* check for the likely condition first: */
214 if (mpd_likely((pfx_len + rp_len) < MAXPATHLEN)) {
215 memcpy(ret, pfx, pfx_len);
216 memcpy(ret + pfx_len, path, rp_len + 1);
217 return ret;
220 /* unlikely, return an empty string because truncating would
221 * also be wrong... break early and break loudly (the system
222 * headers are likely screwed, not mpd) */
223 ERROR("Cannot prefix '%s' to '%s', max: %d", pfx, path, MAXPATHLEN);
224 ret[0] = '\0';
225 return ret;
228 char *rmp2amp(char *relativePath)
230 size_t pfx_len = strlen(musicDir);
231 return pfx_path(relativePath, musicDir, pfx_len);
234 char *rpp2app(char *relativePath)
236 size_t pfx_len = strlen(playlistDir);
237 return pfx_path(relativePath, playlistDir, pfx_len);
240 /* this is actually like strlcpy (OpenBSD), but we don't actually want to
241 * blindly use it everywhere, only for paths that are OK to truncate (for
242 * error reporting and such */
243 void pathcpy_trunc(char *dest, const char *src)
245 size_t len = strlen(src);
247 if (mpd_unlikely(len > MAXPATHLEN))
248 len = MAXPATHLEN;
249 memcpy(dest, src, len);
250 dest[len] = '\0';
253 char *parentPath(char *path)
255 static char parentPath[MAXPATHLEN+1];
256 char *c;
258 pathcpy_trunc(parentPath, path);
259 c = strrchr(parentPath,'/');
261 if (c == NULL)
262 parentPath[0] = '\0';
263 else {
264 while ((parentPath <= c) && *(--c) == '/') /* nothing */
266 c[1] = '\0';
269 return parentPath;
272 char *sanitizePathDup(char *path)
274 int len = strlen(path) + 1;
275 char *ret = xmalloc(len);
276 char *cp = ret;
278 memset(ret, 0, len);
280 len = 0;
282 /* eliminate more than one '/' in a row, like "///" */
283 while (*path) {
284 while (*path == '/')
285 path++;
286 if (*path == '.') {
287 /* we don't want to have hidden directories, or '.' or
288 ".." in our path */
289 free(ret);
290 return NULL;
292 while (*path && *path != '/') {
293 *(cp++) = *(path++);
294 len++;
296 if (*path == '/') {
297 *(cp++) = *(path++);
298 len++;
302 if (len && ret[len - 1] == '/') {
303 len--;
304 ret[len] = '\0';
307 DEBUG("sanitized: %s\n", ret);
309 return xrealloc(ret, len + 1);