263a9d583a
strncpy isn't really safe because it doesn't guarantee null termination, and we have had to work around it in several places. strlcpy (from OpenBSD) isn't great, either because it often leaves errors going unchecked (by truncating strings). So we'll add the pathcpy_trunc() function with is basically strlcpy with a hardcoded MAXPATHLEN as the limit, and we'll acknowledge truncation since we only work on paths and MAXPATHLEN should be set correctly by the system headers[1]. file-specific notes: inputStream_http: eyeballing the changes here, it seems to look alright but I haven't actually tested it myself. ls: don't even bother printing a file if the filename is too long (and when is it ever?) since we won't be able to read it anyways. metadataChunk: it's only metadata, and it's only for showin the user, so truncating it here souldn't be a big issue. memset to zero in init is unecessary, so lets not waste cycles [1] - If the system headers are screwed up, then we're majorly screwed regardless of what we do :x git-svn-id: https://svn.musicpd.org/mpd/trunk@4491 09075e82-0dd4-0310-85a5-a0d7c8717e4f
289 lines
5.6 KiB
C
289 lines
5.6 KiB
C
/* the Music Player Daemon (MPD)
|
|
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
|
|
* This project's homepage is: http://www.musicpd.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "ls.h"
|
|
#include "playlist.h"
|
|
#include "path.h"
|
|
#include "myfprintf.h"
|
|
#include "log.h"
|
|
#include "utf8.h"
|
|
|
|
#include <dirent.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
static char *remoteUrlPrefixes[] = {
|
|
"http://",
|
|
NULL
|
|
};
|
|
|
|
int printRemoteUrlHandlers(int fd)
|
|
{
|
|
char **prefixes = remoteUrlPrefixes;
|
|
|
|
while (*prefixes) {
|
|
fdprintf(fd, "handler: %s\n", *prefixes);
|
|
prefixes++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int isValidRemoteUtf8Url(char *utf8url)
|
|
{
|
|
int ret = 0;
|
|
char *temp;
|
|
|
|
switch (isRemoteUrl(utf8url)) {
|
|
case 1:
|
|
ret = 1;
|
|
temp = utf8url;
|
|
while (*temp) {
|
|
if ((*temp >= 'a' && *temp <= 'z') ||
|
|
(*temp >= 'A' && *temp <= 'Z') ||
|
|
(*temp >= '0' && *temp <= '9') ||
|
|
*temp == '$' ||
|
|
*temp == '-' ||
|
|
*temp == '.' ||
|
|
*temp == '+' ||
|
|
*temp == '!' ||
|
|
*temp == '*' ||
|
|
*temp == '\'' ||
|
|
*temp == '(' ||
|
|
*temp == ')' ||
|
|
*temp == ',' ||
|
|
*temp == '%' ||
|
|
*temp == '/' ||
|
|
*temp == ':' ||
|
|
*temp == '?' ||
|
|
*temp == ';' || *temp == '&' || *temp == '=') {
|
|
} else {
|
|
ret = 1;
|
|
break;
|
|
}
|
|
temp++;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int isRemoteUrl(char *url)
|
|
{
|
|
int count = 0;
|
|
char **urlPrefixes = remoteUrlPrefixes;
|
|
|
|
while (*urlPrefixes) {
|
|
count++;
|
|
if (strncmp(*urlPrefixes, url, strlen(*urlPrefixes)) == 0) {
|
|
return count;
|
|
}
|
|
urlPrefixes++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lsPlaylists(int fd, char *utf8path)
|
|
{
|
|
DIR *dir;
|
|
struct stat st;
|
|
struct dirent *ent;
|
|
char *dup;
|
|
char *utf8;
|
|
char s[MAXPATHLEN + 1];
|
|
List *list = NULL;
|
|
ListNode *node = NULL;
|
|
char *path = utf8ToFsCharset(utf8path);
|
|
char *actualPath = rpp2app(path);
|
|
int actlen = strlen(actualPath) + 1;
|
|
int maxlen = MAXPATHLEN - actlen;
|
|
int suflen = strlen(PLAYLIST_FILE_SUFFIX) + 1;
|
|
int suff;
|
|
|
|
if (actlen > MAXPATHLEN - 1 || (dir = opendir(actualPath)) == NULL) {
|
|
free(path);
|
|
return 0;
|
|
}
|
|
|
|
s[MAXPATHLEN] = '\0';
|
|
/* this is safe, notice actlen > MAXPATHLEN-1 above */
|
|
strcpy(s, actualPath);
|
|
strcat(s, "/");
|
|
|
|
while ((ent = readdir(dir))) {
|
|
size_t len = strlen(ent->d_name) + 1;
|
|
dup = ent->d_name;
|
|
if (mpd_likely(len <= maxlen) &&
|
|
dup[0] != '.' &&
|
|
(suff = strlen(dup) - suflen) > 0 &&
|
|
dup[suff] == '.' &&
|
|
strcmp(dup + suff + 1, PLAYLIST_FILE_SUFFIX) == 0) {
|
|
memcpy(s + actlen, ent->d_name, len);
|
|
if (stat(s, &st) == 0) {
|
|
if (S_ISREG(st.st_mode)) {
|
|
if (list == NULL)
|
|
list = makeList(NULL, 1);
|
|
dup[suff] = '\0';
|
|
if ((utf8 = fsCharsetToUtf8(dup))) {
|
|
insertInList(list, utf8, NULL);
|
|
free(utf8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
free(path);
|
|
|
|
if (list) {
|
|
int i;
|
|
sortList(list);
|
|
|
|
dup = malloc(strlen(utf8path) + 2);
|
|
strcpy(dup, utf8path);
|
|
for (i = strlen(dup) - 1; i >= 0 && dup[i] == '/'; i--) {
|
|
dup[i] = '\0';
|
|
}
|
|
if (strlen(dup))
|
|
strcat(dup, "/");
|
|
|
|
node = list->firstNode;
|
|
while (node != NULL) {
|
|
if (!strchr(node->key, '\n')) {
|
|
fdprintf(fd, "playlist: %s%s\n", dup,
|
|
node->key);
|
|
}
|
|
node = node->nextNode;
|
|
}
|
|
|
|
freeList(list);
|
|
free(dup);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int myStat(char *utf8file, struct stat *st)
|
|
{
|
|
char *file = utf8ToFsCharset(utf8file);
|
|
char *actualFile = file;
|
|
int ret;
|
|
|
|
if (actualFile[0] != '/')
|
|
actualFile = rmp2amp(file);
|
|
|
|
ret = stat(actualFile, st);
|
|
|
|
free(file);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int isFile(char *utf8file, time_t * mtime)
|
|
{
|
|
struct stat st;
|
|
|
|
if (myStat(utf8file, &st) == 0) {
|
|
if (S_ISREG(st.st_mode)) {
|
|
if (mtime)
|
|
*mtime = st.st_mtime;
|
|
return 1;
|
|
} else {
|
|
DEBUG("isFile: %s is not a regular file\n", utf8file);
|
|
return 0;
|
|
}
|
|
} else {
|
|
DEBUG("isFile: failed to stat: %s: %s\n", utf8file,
|
|
strerror(errno));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* suffixes should be ascii only characters */
|
|
char *getSuffix(char *utf8file)
|
|
{
|
|
char *ret = NULL;
|
|
|
|
while (*utf8file) {
|
|
if (*utf8file == '.')
|
|
ret = utf8file + 1;
|
|
utf8file++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hasSuffix(char *utf8file, char *suffix)
|
|
{
|
|
char *s = getSuffix(utf8file);
|
|
if (s && 0 == strcmp(s, suffix))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int isPlaylist(char *utf8file)
|
|
{
|
|
if (isFile(utf8file, NULL)) {
|
|
return hasSuffix(utf8file, PLAYLIST_FILE_SUFFIX);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int isDir(char *utf8name)
|
|
{
|
|
struct stat st;
|
|
|
|
if (myStat(utf8name, &st) == 0) {
|
|
if (S_ISDIR(st.st_mode)) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
InputPlugin *hasMusicSuffix(char *utf8file, unsigned int next)
|
|
{
|
|
InputPlugin *ret = NULL;
|
|
|
|
char *s = getSuffix(utf8file);
|
|
if (s) {
|
|
ret = getInputPluginFromSuffix(s, next);
|
|
} else {
|
|
DEBUG("hasMusicSuffix: The file: %s has no valid suffix\n",
|
|
utf8file);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
InputPlugin *isMusic(char *utf8file, time_t * mtime, unsigned int next)
|
|
{
|
|
if (isFile(utf8file, mtime)) {
|
|
InputPlugin *plugin = hasMusicSuffix(utf8file, next);
|
|
if (plugin != NULL)
|
|
return plugin;
|
|
}
|
|
DEBUG("isMusic: %s is not a valid file\n", utf8file);
|
|
return NULL;
|
|
}
|