aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ls.c82
-rw-r--r--src/stored_playlist.c79
-rw-r--r--src/stored_playlist.h18
3 files changed, 106 insertions, 73 deletions
diff --git a/src/ls.c b/src/ls.c
index 3683881ad..15b7b4813 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -23,6 +23,7 @@
#include "log.h"
#include "utils.h"
#include "list.h"
+#include "stored_playlist.h"
#include "os_compat.h"
static const char *remoteUrlPrefixes[] = {
@@ -99,84 +100,19 @@ int isRemoteUrl(const char *url)
int lsPlaylists(struct client *client, const char *utf8path)
{
- DIR *dir;
- struct stat st;
- struct dirent *ent;
- char *duplicated;
- char *utf8;
- char s[MPD_PATH_MAX];
- char path_max_tmp[MPD_PATH_MAX];
- List *list = NULL;
- ListNode *node;
- char *actualPath = rpp2app_r(path_max_tmp,
- utf8_to_fs_charset(path_max_tmp,
- utf8path));
- size_t actlen = strlen(actualPath) + 1;
- size_t maxlen = MPD_PATH_MAX - actlen;
- size_t suflen = strlen(PLAYLIST_FILE_SUFFIX) + 1;
- ssize_t suff;
-
- if (actlen > MPD_PATH_MAX - 1 || (dir = opendir(actualPath)) == NULL) {
+ GPtrArray *list = spl_list();
+ if (list == NULL)
return 0;
- }
-
- s[MPD_PATH_MAX - 1] = '\0';
- /* this is safe, notice actlen > MPD_PATH_MAX-1 above */
- strcpy(s, actualPath);
- strcat(s, "/");
-
- while ((ent = readdir(dir))) {
- size_t len = strlen(ent->d_name) + 1;
- duplicated = ent->d_name;
- if (mpd_likely(len <= maxlen) &&
- duplicated[0] != '.' &&
- (suff = (ssize_t)(strlen(duplicated) - suflen)) > 0 &&
- duplicated[suff] == '.' &&
- strcmp(duplicated + 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);
- duplicated[suff] = '\0';
- utf8 = fs_charset_to_utf8(path_max_tmp,
- duplicated);
- if (utf8)
- insertInList(list, utf8, NULL);
- }
- }
- }
- }
- closedir(dir);
-
- if (list) {
- int i;
- sortList(list);
-
- duplicated = xmalloc(strlen(utf8path) + 2);
- strcpy(duplicated, utf8path);
- for (i = strlen(duplicated) - 1;
- i >= 0 && duplicated[i] == '/';
- i--) {
- duplicated[i] = '\0';
- }
- if (strlen(duplicated))
- strcat(duplicated, "/");
-
- node = list->firstNode;
- while (node != NULL) {
- if (!strchr(node->key, '\n')) {
- client_printf(client, "playlist: %s%s\n",
- duplicated, node->key);
- }
- node = node->nextNode;
- }
+ for (unsigned i = 0; i < list->len; ++i) {
+ struct stored_playlist_info *playlist =
+ g_ptr_array_index(list, i);
- freeList(list);
- free(duplicated);
+ client_printf(client, "playlist: %s%s\n",
+ utf8path, playlist->name);
}
+ spl_list_free(list);
return 0;
}
diff --git a/src/stored_playlist.c b/src/stored_playlist.c
index ad9e43ce4..121f5ed3d 100644
--- a/src/stored_playlist.c
+++ b/src/stored_playlist.c
@@ -27,6 +27,85 @@
#include "idle.h"
#include "os_compat.h"
+static struct stored_playlist_info *
+load_playlist_info(const char *parent_path_fs, const char *name_fs)
+{
+ size_t name_length = strlen(name_fs);
+ char buffer[MPD_PATH_MAX], *name, *name_utf8;
+ int ret;
+ struct stat st;
+ struct stored_playlist_info *playlist;
+
+ if (name_length < 1 + sizeof(PLAYLIST_FILE_SUFFIX) ||
+ strlen(parent_path_fs) + name_length >= sizeof(buffer) ||
+ memchr(name_fs, '\n', name_length) != NULL)
+ return NULL;
+
+ if (name_fs[name_length - sizeof(PLAYLIST_FILE_SUFFIX)] != '.' ||
+ memcmp(name_fs + name_length - sizeof(PLAYLIST_FILE_SUFFIX) + 1,
+ PLAYLIST_FILE_SUFFIX,
+ sizeof(PLAYLIST_FILE_SUFFIX) - 1) != 0)
+ return NULL;
+
+ pfx_dir(buffer, name_fs, name_length,
+ parent_path_fs, strlen(parent_path_fs));
+
+ ret = stat(buffer, &st);
+ if (ret < 0 || !S_ISREG(st.st_mode))
+ return NULL;
+
+ name = g_strdup(name_fs);
+ name[name_length - sizeof(PLAYLIST_FILE_SUFFIX)] = 0;
+ name_utf8 = fs_charset_to_utf8(buffer, name);
+ g_free(name);
+ if (name_utf8 == NULL)
+ return NULL;
+
+ playlist = g_new(struct stored_playlist_info, 1);
+ playlist->name = g_strdup(name_utf8);
+ playlist->mtime = st.st_mtime;
+ return playlist;
+}
+
+GPtrArray *
+spl_list(void)
+{
+ char parent_path_fs[MPD_PATH_MAX];
+ DIR *dir;
+ struct dirent *ent;
+ GPtrArray *list;
+ struct stored_playlist_info *playlist;
+
+ rpp2app_r(parent_path_fs, "");
+ dir = opendir(parent_path_fs);
+ if (dir == NULL)
+ return NULL;
+
+ list = g_ptr_array_new();
+
+ while ((ent = readdir(dir)) != NULL) {
+ playlist = load_playlist_info(parent_path_fs, ent->d_name);
+ if (playlist != NULL)
+ g_ptr_array_add(list, playlist);
+ }
+
+ closedir(dir);
+ return list;
+}
+
+void
+spl_list_free(GPtrArray *list)
+{
+ for (unsigned i = 0; i < list->len; ++i) {
+ struct stored_playlist_info *playlist =
+ g_ptr_array_index(list, i);
+ g_free(playlist->name);
+ g_free(playlist);
+ }
+
+ g_ptr_array_free(list, true);
+}
+
static ListNode *
spl_get_index(List *list, int idx)
{
diff --git a/src/stored_playlist.h b/src/stored_playlist.h
index 637a1093d..f524829df 100644
--- a/src/stored_playlist.h
+++ b/src/stored_playlist.h
@@ -22,8 +22,26 @@
#include "list.h"
#include "playlist.h"
+#include <glib.h>
+
struct song;
+struct stored_playlist_info {
+ char *name;
+
+ time_t mtime;
+};
+
+/**
+ * Returns a list of stored_playlist_info struct pointers. Returns
+ * NULL if an error occured.
+ */
+GPtrArray *
+spl_list(void);
+
+void
+spl_list_free(GPtrArray *list);
+
List *
spl_load(const char *utf8path);