diff --git a/engine/drumkit.c b/engine/drumkit.c index 599d61cdf60c8355cc135610d986401aa08fb288..6205618fc1403c348705b9d5fd62ca12abae14ff 100644 --- a/engine/drumkit.c +++ b/engine/drumkit.c @@ -3,6 +3,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <unistd.h> #include <libxml/parser.h> #include <libxml/tree.h> @@ -450,6 +452,32 @@ static void fix_bad_xml(xmlNodePtr cur, xmlNsPtr ns) { } } +// Return the final location pointed at by filename if it's a symbolic +// link. In all cases, the resulting memory must be freed by the caller. +static char *resolve_symlink(const char *filename) { + char buf[1024]; + struct stat stbuf; + char *cur = strdup(filename); + int n; + + while (1) { + if (lstat(cur, &stbuf) < 0) { + return NULL; + } + if ((stbuf.st_mode & S_IFLNK) != S_IFLNK) { + return cur; + } + + n = readlink(cur, buf, sizeof(buf)-1); + if (n < 0) { + return NULL; + } + buf[n] = '\0'; + free(cur); + cur = strdup(buf); + } +} + int drumkit_load(struct drumkit *kit, const char *filename, int target_samplerate) { char *basedir = NULL; xmlDocPtr doc = NULL; @@ -459,6 +487,10 @@ int drumkit_load(struct drumkit *kit, const char *filename, int target_samplerat xmlXPathObjectPtr xpathObj = NULL; int n, r = 1; + // Resolve symlinks because sometimes (i.e. in presets) we get sent + // a symbolic link to the actual drumkit.xml, which messes up the + // relative filenames of the samples. + filename = resolve_symlink(filename); basedir = path_dirname(filename); kit->instruments = NULL; @@ -508,6 +540,7 @@ int drumkit_load(struct drumkit *kit, const char *filename, int target_samplerat fix_midi_notes(kit); cleanup: + free(filename); free(basedir); if (xpathObj) { xmlXPathFreeObject(xpathObj);