diff --git a/Makefile.am b/Makefile.am
index 952d42762..004fae3c7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,5 +5,7 @@ docdir = $(prefix)/share/doc/$(PACKAGE)
 doc_DATA = README UPGRADING
 EXTRA_DIST = COPYING $(doc_DATA)
 
-sparse-check:
+sparse-check test:
 	$(MAKE) -C src $@
+
+.PHONY: sparse-check test
diff --git a/src/Makefile.am b/src/Makefile.am
index cf56ba1fb..653ccb824 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -151,3 +151,15 @@ sparse-check:
 		$(SPARSE) -I. $(mpd_CFLAGS) $(SPARSE_FLAGS) $(srcdir)/$$i || exit; \
 	done
 
+TEST_CFLAGS = -DUNIT_TEST
+TEST_FILES := $(shell grep UNIT_TEST $(mpd_SOURCES) | \
+               awk -F: '{print $$1}' | uniq)
+
+test: $(addprefix test-, $(subst .c,,$(TEST_FILES)))
+
+test-%: %.c
+	$(CC) $(CFLAGS) $(TEST_CFLAGS) -o $@ $<
+	@./$@
+	@echo $@: OK
+
+.PHONY: sparse-check test
diff --git a/src/audio.c b/src/audio.c
index 96712d713..a2d21edd3 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -37,7 +37,7 @@
 
 #define AUDIO_DEVICE_STATE	"audio_device_state:"
 #define AUDIO_DEVICE_STATE_LEN	19	/* strlen(AUDIO_DEVICE_STATE) */
-#define AUDIO_BUFFER_SIZE	2*MAXPATHLEN
+#define AUDIO_BUFFER_SIZE	2*MPD_PATH_MAX
 
 static AudioFormat audio_format;
 
diff --git a/src/buffer2array.c b/src/buffer2array.c
index d7bfc4561..1684bad94 100644
--- a/src/buffer2array.c
+++ b/src/buffer2array.c
@@ -79,48 +79,56 @@ int main()
 	int max;
 
 	b = strdup("lsinfo \"/some/dir/name \\\"test\\\"\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("/some/dir/name \"test\"", a[1]) );
 	assert( !a[2] );
 
 	b = strdup("lsinfo \"/some/dir/name \\\"test\\\" something else\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("/some/dir/name \"test\" something else", a[1]) );
 	assert( !a[2] );
 
 	b = strdup("lsinfo \"/some/dir\\\\name\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("/some/dir\\name", a[1]) );
 	assert( !a[2] );
 
 	b = strdup("lsinfo \"/some/dir name\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("/some/dir name", a[1]) );
 	assert( !a[2] );
 
 	b = strdup("lsinfo \"\\\"/some/dir\\\"\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("\"/some/dir\"", a[1]) );
 	assert( !a[2] );
 
 	b = strdup("lsinfo \"\\\"/some/dir\\\" x\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("\"/some/dir\" x", a[1]) );
 	assert( !a[2] );
 
 	b = strdup("lsinfo \"single quote\\'d from php magicquotes\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("single quote\'d from php magicquotes", a[1]) );
 	assert( !a[2] );
 
 	b = strdup("lsinfo \"double quote\\\"d from php magicquotes\"");
+	assert(b);
 	max = buffer2array(b, a, 4);
 	assert( !strcmp("lsinfo", a[0]) );
 	assert( !strcmp("double quote\"d from php magicquotes", a[1]) );
diff --git a/src/charConv.c b/src/charConv.c
index 69777c47a..71a86e7d7 100644
--- a/src/charConv.c
+++ b/src/charConv.c
@@ -95,26 +95,25 @@ int setCharSetConversion(char *to, char *from)
 	return -1;
 }
 
-char *convStrDup(char *string)
+char *char_conv_str(char *dest, char *string)
 {
 	if (!char_conv_to)
 		return NULL;
 
 	if (char_conv_same)
-		return xstrdup(string);
+		return strcpy(dest, string);
 
 #ifdef HAVE_ICONV
 	if (char_conv_use_iconv) {
+		/* not optimized: */
 		char buffer[BUFFER_SIZE];
 		size_t inleft = strlen(string);
-		char *ret;
 		size_t outleft;
 		size_t retlen = 0;
 		size_t err;
 		char *bufferPtr;
 
-		ret = xmalloc(1);
-		ret[0] = '\0';
+		dest[0] = '\0';
 
 		while (inleft) {
 			bufferPtr = buffer;
@@ -124,27 +123,22 @@ char *convStrDup(char *string)
 				  &outleft);
 			if (outleft == BUFFER_SIZE
 			    || (err == -1L && errno != E2BIG)) {
-				free(ret);
 				return NULL;
 			}
-
-			ret = xrealloc(ret, retlen + BUFFER_SIZE - outleft + 1);
-			memcpy(ret + retlen, buffer, BUFFER_SIZE - outleft);
+			memcpy(dest + retlen, buffer, BUFFER_SIZE - outleft);
 			retlen += BUFFER_SIZE - outleft;
-			ret[retlen] = '\0';
+			dest[retlen] = '\0';
 		}
 
-		return ret;
+		return dest;
 	}
 #endif
 
 	switch (char_conv_latin1ToUtf8) {
 	case 1:
-		return latin1StrToUtf8Dup(string);
-		break;
+		return latin1_to_utf8(dest, string);
 	case -1:
-		return utf8StrToLatin1Dup(string);
-		break;
+		return utf8_to_latin1(dest, string);
 	}
 
 	return NULL;
diff --git a/src/charConv.h b/src/charConv.h
index 4b1ed4237..d50e84520 100644
--- a/src/charConv.h
+++ b/src/charConv.h
@@ -23,6 +23,6 @@
 
 int setCharSetConversion(char *to, char *from);
 
-char *convStrDup(char *string);
+char *char_conv_str(char *dest, char *string);
 
 #endif
diff --git a/src/conf.c b/src/conf.c
index 44f082acd..291ae30d2 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -32,8 +32,9 @@
 #include <sys/types.h>
 #include <pwd.h>
 #include <errno.h>
+#include "path.h"
 
-#define MAX_STRING_SIZE	MAXPATHLEN+80
+#define MAX_STRING_SIZE	MPD_PATH_MAX+80
 
 #define CONF_COMMENT		'#'
 #define CONF_BLOCK_BEGIN	"{"
diff --git a/src/decode.c b/src/decode.c
index ab255e3c6..79504dc94 100644
--- a/src/decode.c
+++ b/src/decode.c
@@ -280,29 +280,28 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
 	int ret;
 	InputStream inStream;
 	InputPlugin *plugin = NULL;
-	char *path;
+	char path_max_tmp[MPD_PATH_MAX];
 
-	if (isRemoteUrl(pc->utf8url))
-		path = utf8StrToLatin1Dup(pc->utf8url);
-	else
-		path = xstrdup(rmp2amp(utf8ToFsCharset(pc->utf8url)));
-
-	if (!path) {
-		dc->error = DECODE_ERROR_FILE;
-		dc->state = DECODE_STATE_STOP;
-		dc->start = 0;
-		return;
-	}
+	/* not actually sure why we convert between latin/UTF8 for URLs */
+	if (isRemoteUrl(pc->utf8url)) {
+		if (!utf8_to_latin1(path_max_tmp, pc->utf8url)) {
+			dc->error = DECODE_ERROR_FILE;
+			dc->state = DECODE_STATE_STOP;
+			dc->start = 0;
+			return;
+		}
+	} else
+		rmp2amp_r(path_max_tmp,
+		          utf8_to_fs_charset(path_max_tmp, pc->utf8url));
 
 	copyMpdTagToOutputBuffer(cb, NULL);
 
 	pathcpy_trunc(dc->utf8url, pc->utf8url);
 
-	if (openInputStream(&inStream, path) < 0) {
+	if (openInputStream(&inStream, path_max_tmp) < 0) {
 		dc->error = DECODE_ERROR_FILE;
 		dc->state = DECODE_STATE_STOP;
 		dc->start = 0;
-		free(path);
 		return;
 	}
 
@@ -321,7 +320,6 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
 	if (dc->stop) {
 		dc->state = DECODE_STATE_STOP;
 		dc->stop = 0;
-		free(path);
 		return;
 	}
 
@@ -392,7 +390,8 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
 
 			if (plugin->fileDecodeFunc) {
 				closeInputStream(&inStream);
-				ret = plugin->fileDecodeFunc(cb, dc, path);
+				ret = plugin->fileDecodeFunc(cb, dc,
+				                             path_max_tmp);
 				break;
 			} else if (plugin->streamDecodeFunc) {
 				ret = plugin->streamDecodeFunc(cb, dc, &inStream);
@@ -412,8 +411,6 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
 		dc->stop = 0;
 		dc->state = DECODE_STATE_STOP;
 	}
-
-	free(path);
 }
 
 static int decoderInit(PlayerControl * pc, OutputBuffer * cb,
diff --git a/src/decode.h b/src/decode.h
index 09eaec416..1c93d3843 100644
--- a/src/decode.h
+++ b/src/decode.h
@@ -20,6 +20,7 @@
 #define DECODE_H
 
 #include "../config.h"
+#include "path.h"
 #include "tag.h"
 
 #include "mpd_types.h"
@@ -51,7 +52,7 @@ typedef struct _DecoderControl {
 	volatile mpd_sint8 cycleLogFiles;
 	volatile double seekWhere;
 	AudioFormat audioFormat;
-	char utf8url[MAXPATHLEN + 1];
+	char utf8url[MPD_PATH_MAX];
 	volatile float totalTime;
 } DecoderControl;
 
diff --git a/src/directory.c b/src/directory.c
index 2a7e37def..b706b4208 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -35,6 +35,7 @@
 #include "tagTracker.h"
 #include "utils.h"
 #include "volume.h"
+#include "ls.h"
 
 #include <sys/wait.h>
 #include <dirent.h>
@@ -296,7 +297,9 @@ static void removeSongFromDirectory(Directory * directory, char *shortname)
 	void *song;
 
 	if (findInList(directory->songs, shortname, &song)) {
-		LOG("removing: %s\n", getSongUrl((Song *) song));
+		char path_max_tmp[MPD_PATH_MAX]; /* wasteful */
+		LOG("removing: %s\n",
+		    get_song_url(path_max_tmp, (Song *) song));
 		deleteFromList(directory->songs, shortname);
 	}
 }
@@ -359,64 +362,40 @@ static int updateInDirectory(Directory * directory, char *shortname, char *name)
 	return 0;
 }
 
+/* we don't look at hidden files nor files with newlines in them */
+static int skip_path(const char *path)
+{
+	return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0;
+}
+
 /* return values:
    -1 -> error
     0 -> no error, but nothing removed
     1 -> no error, and stuff removed
  */
-static int removeDeletedFromDirectory(Directory * directory, DIR * dir)
+static int removeDeletedFromDirectory(char *path_max_tmp, Directory * directory)
 {
-	char cwd[2];
-	struct dirent *ent;
-	char *dirname = getDirectoryPath(directory);
-	List *entList = makeList(free, 1);
-	void *name;
-	char *s;
-	char *utf8;
-	ListNode *node;
-	ListNode *tmpNode;
+	const char *dirname = (directory && directory->path) ?
+	    directory->path : NULL;
+	ListNode *node, *tmpNode;
+	DirectoryList *subdirs = directory->subDirectories;
 	int ret = 0;
 
-	cwd[0] = '.';
-	cwd[1] = '\0';
-	if (dirname == NULL)
-		dirname = cwd;
-
-	while ((ent = readdir(dir))) {
-		if (ent->d_name[0] == '.')
-			continue;	/* hide hidden stuff */
-		if (strchr(ent->d_name, '\n'))
-			continue;
-
-		utf8 = fsCharsetToUtf8(ent->d_name);
-
-		if (!utf8)
-			continue;
-
-		if (directory->path) {
-			s = xmalloc(strlen(getDirectoryPath(directory))
-				   + strlen(utf8) + 2);
-			sprintf(s, "%s/%s", getDirectoryPath(directory), utf8);
-		} else
-			s = xstrdup(utf8);
-		insertInList(entList, utf8, s);
-	}
-
-	node = directory->subDirectories->firstNode;
+	node = subdirs->firstNode;
 	while (node) {
 		tmpNode = node->nextNode;
-		if (findInList(entList, node->key, &name)) {
-			if (!isDir((char *)name)) {
-				LOG("removing directory: %s\n", (char *)name);
-				deleteFromList(directory->subDirectories,
-					       node->key);
+		if (node->key) {
+			if (dirname)
+				sprintf(path_max_tmp, "%s/%s", dirname,
+					node->key);
+			else
+				strcpy(path_max_tmp, node->key);
+
+			if (!isDir(path_max_tmp)) {
+				LOG("removing directory: %s\n", path_max_tmp);
+				deleteFromList(subdirs, node->key);
 				ret = 1;
 			}
-		} else {
-			LOG("removing directory: %s/%s\n",
-			    getDirectoryPath(directory), node->key);
-			deleteFromList(directory->subDirectories, node->key);
-			ret = 1;
 		}
 		node = tmpNode;
 	}
@@ -424,40 +403,40 @@ static int removeDeletedFromDirectory(Directory * directory, DIR * dir)
 	node = directory->songs->firstNode;
 	while (node) {
 		tmpNode = node->nextNode;
-		if (findInList(entList, node->key, (void **)&name)) {
-			if (!isMusic(name, NULL, 0)) {
+		if (node->key) {
+			if (dirname)
+				sprintf(path_max_tmp, "%s/%s", dirname,
+					node->key);
+			else
+				strcpy(path_max_tmp, node->key);
+
+			if (!isFile(path_max_tmp, NULL)) {
 				removeSongFromDirectory(directory, node->key);
 				ret = 1;
 			}
-		} else {
-			removeSongFromDirectory(directory, node->key);
-			ret = 1;
 		}
 		node = tmpNode;
 	}
 
-	freeList(entList);
-
 	return ret;
 }
 
 static Directory *addDirectoryPathToDB(char *utf8path, char **shortname)
 {
+	char path_max_tmp[MPD_PATH_MAX];
 	char *parent;
 	Directory *parentDirectory;
 	void *directory;
 
-	parent = xstrdup(parentPath(utf8path));
+	parent = parent_path(path_max_tmp, utf8path);
 
 	if (strlen(parent) == 0)
 		parentDirectory = (void *)mp3rootDirectory;
 	else
 		parentDirectory = addDirectoryPathToDB(parent, shortname);
 
-	if (!parentDirectory) {
-		free(parent);
+	if (!parentDirectory)
 		return NULL;
-	}
 
 	*shortname = utf8path + strlen(parent);
 	while (*(*shortname) && *(*shortname) == '/')
@@ -467,10 +446,9 @@ static Directory *addDirectoryPathToDB(char *utf8path, char **shortname)
 	    (parentDirectory->subDirectories, *shortname, &directory)) {
 		struct stat st;
 		if (myStat(utf8path, &st) < 0 ||
-		    inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev)) {
-			free(parent);
+		    inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev))
 			return NULL;
-		} else {
+		else {
 			directory = newDirectory(utf8path, parentDirectory);
 			insertInList(parentDirectory->subDirectories,
 				     *shortname, directory);
@@ -481,34 +459,29 @@ static Directory *addDirectoryPathToDB(char *utf8path, char **shortname)
 	   with potentially the same name */
 	removeSongFromDirectory(parentDirectory, *shortname);
 
-	free(parent);
-
 	return (Directory *) directory;
 }
 
 static Directory *addParentPathToDB(char *utf8path, char **shortname)
 {
 	char *parent;
+	char path_max_tmp[MPD_PATH_MAX];
 	Directory *parentDirectory;
 
-	parent = xstrdup(parentPath(utf8path));
+	parent = parent_path(path_max_tmp, utf8path);
 
 	if (strlen(parent) == 0)
 		parentDirectory = (void *)mp3rootDirectory;
 	else
 		parentDirectory = addDirectoryPathToDB(parent, shortname);
 
-	if (!parentDirectory) {
-		free(parent);
+	if (!parentDirectory)
 		return NULL;
-	}
 
 	*shortname = utf8path + strlen(parent);
 	while (*(*shortname) && *(*shortname) == '/')
 		(*shortname)++;
 
-	free(parent);
-
 	return (Directory *) parentDirectory;
 }
 
@@ -526,6 +499,7 @@ static int updatePath(char *utf8path)
 	char *path = sanitizePathDup(utf8path);
 	time_t mtime;
 	int ret = 0;
+	char path_max_tmp[MPD_PATH_MAX];
 
 	if (NULL == path)
 		return -1;
@@ -563,7 +537,8 @@ static int updatePath(char *utf8path)
 		else if (0 == inodeFoundInParent(parentDirectory->parent,
 						 parentDirectory->stat->inode,
 						 parentDirectory->stat->device)
-			 && song && isMusic(getSongUrl(song), &mtime, 0)) {
+			 && song &&
+			 isMusic(get_song_url(path_max_tmp, song), &mtime, 0)) {
 			free(path);
 			if (song->mtime == mtime)
 				return 0;
@@ -606,6 +581,14 @@ static int updatePath(char *utf8path)
 	return ret;
 }
 
+static const char *opendir_path(char *path_max_tmp, char *dirname)
+{
+	if (*dirname != '\0')
+		return rmp2amp_r(path_max_tmp,
+		                 utf8_to_fs_charset(path_max_tmp, dirname));
+	return musicDir;
+}
+
 /* return values:
    -1 -> error
     0 -> no error, but nothing updated
@@ -614,59 +597,39 @@ static int updatePath(char *utf8path)
 static int updateDirectory(Directory * directory)
 {
 	DIR *dir;
-	char cwd[2];
-	struct dirent *ent;
-	char *s;
-	char *utf8;
 	char *dirname = getDirectoryPath(directory);
+	struct dirent *ent;
+	char path_max_tmp[MPD_PATH_MAX];
 	int ret = 0;
 
-	{
-		if (!directory->stat && statDirectory(directory) < 0) {
-			return -1;
-		} else if (inodeFoundInParent(directory->parent,
-					      directory->stat->inode,
-					      directory->stat->device)) {
-			return -1;
-		}
-	}
-
-	cwd[0] = '.';
-	cwd[1] = '\0';
-	if (dirname == NULL)
-		dirname = cwd;
-
-	if ((dir = opendir(rmp2amp(utf8ToFsCharset(dirname)))) == NULL)
+	if (!directory->stat && statDirectory(directory) < 0)
+		return -1;
+	else if (inodeFoundInParent(directory->parent,
+				    directory->stat->inode,
+				    directory->stat->device))
 		return -1;
 
-	if (removeDeletedFromDirectory(directory, dir) > 0)
+	dir = opendir(opendir_path(path_max_tmp, dirname));
+	if (!dir)
+		return -1;
+
+	if (removeDeletedFromDirectory(path_max_tmp, directory) > 0)
 		ret = 1;
 
-	rewinddir(dir);
-
 	while ((ent = readdir(dir))) {
-		if (ent->d_name[0] == '.')
-			continue;	/* hide hidden stuff */
-		if (strchr(ent->d_name, '\n'))
+		char *utf8;
+		if (skip_path(ent->d_name))
 			continue;
 
-		utf8 = fsCharsetToUtf8(ent->d_name);
-
+		utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name);
 		if (!utf8)
 			continue;
 
-		utf8 = xstrdup(utf8);
-
-		if (directory->path) {
-			s = xmalloc(strlen(getDirectoryPath(directory)) +
-				   strlen(utf8) + 2);
-			sprintf(s, "%s/%s", getDirectoryPath(directory), utf8);
-		} else
-			s = xstrdup(utf8);
-		if (updateInDirectory(directory, utf8, s) > 0)
+		if (directory->path)
+			utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8),
+			               dirname, strlen(dirname));
+		if (updateInDirectory(directory, utf8, path_max_tmp) > 0)
 			ret = 1;
-		free(utf8);
-		free(s);
 	}
 
 	closedir(dir);
@@ -682,48 +645,35 @@ static int updateDirectory(Directory * directory)
 static int exploreDirectory(Directory * directory)
 {
 	DIR *dir;
-	char cwd[2];
-	struct dirent *ent;
-	char *s;
-	char *utf8;
 	char *dirname = getDirectoryPath(directory);
+	struct dirent *ent;
+	char path_max_tmp[MPD_PATH_MAX];
 	int ret = 0;
 
-	cwd[0] = '.';
-	cwd[1] = '\0';
-	if (dirname == NULL)
-		dirname = cwd;
-
 	DEBUG("explore: attempting to opendir: %s\n", dirname);
-	if ((dir = opendir(rmp2amp(utf8ToFsCharset(dirname)))) == NULL)
+
+	dir = opendir(opendir_path(path_max_tmp, dirname));
+	if (!dir)
 		return -1;
 
 	DEBUG("explore: %s\n", dirname);
+
 	while ((ent = readdir(dir))) {
-		if (ent->d_name[0] == '.')
-			continue;	/* hide hidden stuff */
-		if (strchr(ent->d_name, '\n'))
+		char *utf8;
+		if (skip_path(ent->d_name))
 			continue;
 
-		utf8 = fsCharsetToUtf8(ent->d_name);
-
+		utf8 = fs_charset_to_utf8(path_max_tmp, ent->d_name);
 		if (!utf8)
 			continue;
 
-		utf8 = xstrdup(utf8);
-
 		DEBUG("explore: found: %s (%s)\n", ent->d_name, utf8);
 
-		if (directory->path) {
-			s = xmalloc(strlen(getDirectoryPath(directory)) +
-				   strlen(utf8) + 2);
-			sprintf(s, "%s/%s", getDirectoryPath(directory), utf8);
-		} else
-			s = xstrdup(utf8);
-		if (addToDirectory(directory, utf8, s) > 0)
+		if (directory->path)
+			utf8 = pfx_dir(path_max_tmp, utf8, strlen(utf8),
+			               dirname, strlen(dirname));
+		if (addToDirectory(directory, utf8, path_max_tmp) > 0)
 			ret = 1;
-		free(utf8);
-		free(s);
 	}
 
 	closedir(dir);
@@ -735,10 +685,8 @@ static int statDirectory(Directory * dir)
 {
 	struct stat st;
 
-	if (myStat(getDirectoryPath(dir) ? getDirectoryPath(dir) : "", &st) < 0)
-	{
+	if (myStat(getDirectoryPath(dir), &st) < 0)
 		return -1;
-	}
 
 	dir->stat = newDirectoryStat(&st);
 
@@ -953,8 +901,8 @@ static void writeDirectoryInfo(FILE * fp, Directory * directory)
 
 static void readDirectoryInfo(FILE * fp, Directory * directory)
 {
-	char buffer[MAXPATHLEN * 2];
-	int bufferSize = MAXPATHLEN * 2;
+	char buffer[MPD_PATH_MAX * 2];
+	int bufferSize = MPD_PATH_MAX * 2;
 	char *key;
 	Directory *subDirectory;
 	int strcmpRet;
diff --git a/src/locate.c b/src/locate.c
index 7c3bab899..d09e68a1e 100644
--- a/src/locate.c
+++ b/src/locate.c
@@ -16,8 +16,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include "path.h"
 #include "locate.h"
-
 #include "utils.h"
 
 #define LOCATE_TAG_FILE_KEY     "file"
@@ -127,13 +127,13 @@ static int strstrSearchTag(Song * song, int type, char *str)
 	int ret = 0;
 
 	if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
-		dup = strDupToUpper(getSongUrl(song));
-		if (strstr(dup, str))
+		char path_max_tmp[MPD_PATH_MAX];
+
+		string_toupper(get_song_url(path_max_tmp, song));
+		if (strstr(path_max_tmp, str))
 			ret = 1;
-		free(dup);
-		if (ret == 1 || type == LOCATE_TAG_FILE_TYPE) {
+		if (ret == 1 || type == LOCATE_TAG_FILE_TYPE)
 			return ret;
-		}
 	}
 
 	if (!song->tag)
@@ -173,7 +173,8 @@ static int tagItemFoundAndMatches(Song * song, int type, char *str)
 	int i;
 
 	if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
-		if (0 == strcmp(str, getSongUrl(song)))
+		char path_max_tmp[MPD_PATH_MAX];
+		if (0 == strcmp(str, get_song_url(path_max_tmp, song)))
 			return 1;
 		if (type == LOCATE_TAG_FILE_TYPE)
 			return 0;
diff --git a/src/ls.c b/src/ls.c
index 0b3f7f354..7d0421537 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -108,22 +108,24 @@ int lsPlaylists(int fd, char *utf8path)
 	struct dirent *ent;
 	char *dup;
 	char *utf8;
-	char s[MAXPATHLEN + 1];
+	char s[MPD_PATH_MAX];
+	char path_max_tmp[MPD_PATH_MAX];
 	List *list = NULL;
 	ListNode *node = NULL;
-	char *path = utf8ToFsCharset(utf8path);
-	char *actualPath = rpp2app(path);
+	char *actualPath = rpp2app_r(path_max_tmp,
+	                             utf8_to_fs_charset(path_max_tmp,
+				                        utf8path));
 	int actlen = strlen(actualPath) + 1;
-	int maxlen = MAXPATHLEN - actlen;
+	int maxlen = MPD_PATH_MAX - actlen;
 	int suflen = strlen(PLAYLIST_FILE_SUFFIX) + 1;
 	int suff;
 
-	if (actlen > MAXPATHLEN - 1 || (dir = opendir(actualPath)) == NULL) {
+	if (actlen > MPD_PATH_MAX - 1 || (dir = opendir(actualPath)) == NULL) {
 		return 0;
 	}
 
-	s[MAXPATHLEN] = '\0';
-	/* this is safe, notice actlen > MAXPATHLEN-1 above */
+	s[MPD_PATH_MAX - 1] = '\0';
+	/* this is safe, notice actlen > MPD_PATH_MAX-1 above */
 	strcpy(s, actualPath);
 	strcat(s, "/");
 
@@ -138,12 +140,14 @@ int lsPlaylists(int fd, char *utf8path)
 			memcpy(s + actlen, ent->d_name, len);
 			if (stat(s, &st) == 0) {
 				if (S_ISREG(st.st_mode)) {
+					char path_max_tmp[MPD_PATH_MAX];
 					if (list == NULL)
 						list = makeList(NULL, 1);
 					dup[suff] = '\0';
-					if ((utf8 = fsCharsetToUtf8(dup))) {
+					utf8 = fs_charset_to_utf8(path_max_tmp,
+					                          dup);
+					if (utf8)
 						insertInList(list, utf8, NULL);
-					}
 				}
 			}
 		}
@@ -181,16 +185,17 @@ int lsPlaylists(int fd, char *utf8path)
 
 int myStat(char *utf8file, struct stat *st)
 {
-	char *file = utf8ToFsCharset(utf8file);
+	char path_max_tmp[MPD_PATH_MAX];
+	char *file = utf8_to_fs_charset(path_max_tmp, utf8file);
 	char *actualFile = file;
 
 	if (actualFile[0] != '/')
-		actualFile = rmp2amp(file);
+		actualFile = rmp2amp_r(path_max_tmp, file);
 
 	return stat(actualFile, st);
 }
 
-static int isFile(char *utf8file, time_t * mtime)
+int isFile(char *utf8file, time_t * mtime)
 {
 	struct stat st;
 
diff --git a/src/ls.h b/src/ls.h
index 20f668bd9..aa34187c2 100644
--- a/src/ls.h
+++ b/src/ls.h
@@ -49,4 +49,6 @@ InputPlugin *isMusic(char *utf8file, time_t * mtime, unsigned int next);
 
 int printRemoteUrlHandlers(int fd);
 
+int isFile(char *utf8file, time_t * mtime);
+
 #endif
diff --git a/src/main.c b/src/main.c
index ddfe508b6..72359820a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -208,10 +208,10 @@ static void parseOptions(int argc, char **argv, Options * options)
 		} else if (argcLeft == 1) {
 			struct stat st;
 			char *homedir = getenv("HOME");
-			char userfile[MAXPATHLEN + 1] = "";
+			char userfile[MPD_PATH_MAX] = "";
 			if (homedir && (strlen(homedir) +
 					strlen(USER_CONFIG_FILE_LOCATION)) <
-			    MAXPATHLEN) {
+			    MPD_PATH_MAX) {
 				strcpy(userfile, homedir);
 				strcat(userfile, USER_CONFIG_FILE_LOCATION);
 			}
diff --git a/src/myfprintf.c b/src/myfprintf.c
index a09ae4324..930078398 100644
--- a/src/myfprintf.c
+++ b/src/myfprintf.c
@@ -31,7 +31,7 @@
 #include <string.h>
 #include <errno.h>
 
-#define BUFFER_LENGTH	MAXPATHLEN+1024
+#define BUFFER_LENGTH	MPD_PATH_MAX+1024
 
 static void blockingWrite(const int fd, const char *string, size_t len)
 {
diff --git a/src/path.c b/src/path.c
index 134a0701c..c02103331 100644
--- a/src/path.c
+++ b/src/path.c
@@ -40,39 +40,25 @@
 
 const char *musicDir;
 static const char *playlistDir;
+static size_t music_dir_len;
+static size_t playlist_dir_len;
 static char *fsCharset;
 
-static char *pathConvCharset(char *to, char *from, char *str, char *ret)
+static char *path_conv_charset(char *dest, char *to, char *from, char *str)
 {
-	if (ret)
-		free(ret);
-	return setCharSetConversion(to, from) ? NULL : convStrDup(str);
+	return setCharSetConversion(to, from) ? NULL : char_conv_str(dest, str);
 }
 
-char *fsCharsetToUtf8(char *str)
+char *fs_charset_to_utf8(char *dst, char *str)
 {
-	static char *ret;
-
-	ret = pathConvCharset("UTF-8", fsCharset, str, ret);
-
-	if (ret && !validUtf8String(ret)) {
-		free(ret);
-		ret = NULL;
-	}
-
-	return ret;
+	char *ret = path_conv_charset(dst, "UTF-8", fsCharset, str);
+	return (ret && !validUtf8String(ret)) ? NULL : ret;
 }
 
-char *utf8ToFsCharset(char *str)
+char *utf8_to_fs_charset(char *dst, char *str)
 {
-	static char *ret;
-
-	ret = pathConvCharset(fsCharset, "UTF-8", str, ret);
-
-	if (!ret)
-		ret = xstrdup(str);
-
-	return ret;
+	char *ret = path_conv_charset(dst, fsCharset, "UTF-8", str);
+	return ret ? ret : strcpy(dst, str);
 }
 
 void setFsCharset(char *charset)
@@ -111,23 +97,6 @@ char *getFsCharset(void)
 	return fsCharset;
 }
 
-static char *appendSlash(char **path)
-{
-	char *temp = *path;
-	int len = strlen(temp);
-
-	if (temp[len - 1] != '/') {
-		temp = xmalloc(len + 2);
-		memset(temp, 0, len + 2);
-		memcpy(temp, *path, len);
-		temp[len] = '/';
-		free(*path);
-		*path = temp;
-	}
-
-	return temp;
-}
-
 void initPaths(void)
 {
 	ConfigParam *musicParam = parseConfigFilePath(CONF_MUSIC_DIR, 1);
@@ -138,8 +107,11 @@ void initPaths(void)
 	char *originalLocale;
 	DIR *dir;
 
-	musicDir = appendSlash(&(musicParam->value));
-	playlistDir = appendSlash(&(playlistParam->value));
+	musicDir = xstrdup(musicParam->value);
+	playlistDir = xstrdup(playlistParam->value);
+
+	music_dir_len = strlen(musicDir);
+	playlist_dir_len = strlen(playlistDir);
 
 	if ((dir = opendir(playlistDir)) == NULL) {
 		FATAL("cannot open %s \"%s\" (config line %i): %s\n",
@@ -205,36 +177,35 @@ void finishPaths(void)
 	fsCharset = NULL;
 }
 
-static char *pfx_path(const char *path, const char *pfx, const size_t pfx_len)
+char *pfx_dir(char *dst,
+              const char *path, const size_t path_len,
+              const char *pfx, const size_t pfx_len)
 {
-	static char ret[MAXPATHLEN+1];
-	size_t rp_len = strlen(path);
+	if (mpd_unlikely((pfx_len + path_len + 1) >= MPD_PATH_MAX))
+		FATAL("Cannot prefix '%s' to '%s', PATH_MAX: %d\n",
+		      pfx, path, MPD_PATH_MAX);
 
-	/* check for the likely condition first: */
-	if (mpd_likely((pfx_len + rp_len) < MAXPATHLEN)) {
-		memcpy(ret, pfx, pfx_len);
-		memcpy(ret + pfx_len, path, rp_len + 1);
-		return ret;
-	}
+	/* memmove allows dst == path */
+	memmove(dst + pfx_len + 1, path, path_len + 1);
+	memcpy(dst, pfx, pfx_len);
+	dst[pfx_len] = '/';
 
-	/* unlikely, return an empty string because truncating would
-	 * also be wrong... break early and break loudly (the system
-	 * headers are likely screwed, not mpd) */
-	ERROR("Cannot prefix '%s' to '%s', max: %d\n", pfx, path, MAXPATHLEN);
-	ret[0] = '\0';
-	return ret;
+	/* this is weird, but directory.c can use it more safely/efficiently */
+	return (dst + pfx_len + 1);
 }
 
-char *rmp2amp(char *relativePath)
+char *rmp2amp_r(char *dst, const char *rel_path)
 {
-	size_t pfx_len = strlen(musicDir);
-	return pfx_path(relativePath, musicDir, pfx_len);
+	pfx_dir(dst, rel_path, strlen(rel_path),
+	        (const char *)musicDir, music_dir_len);
+	return dst;
 }
 
-char *rpp2app(char *relativePath)
+char *rpp2app_r(char *dst, const char *rel_path)
 {
-	size_t pfx_len = strlen(playlistDir);
-	return pfx_path(relativePath, playlistDir, pfx_len);
+	pfx_dir(dst, rel_path, strlen(rel_path),
+	        (const char *)playlistDir, playlist_dir_len);
+	return dst;
 }
 
 /* this is actually like strlcpy (OpenBSD), but we don't actually want to
@@ -244,29 +215,28 @@ void pathcpy_trunc(char *dest, const char *src)
 {
 	size_t len = strlen(src);
 
-	if (mpd_unlikely(len > MAXPATHLEN))
-		len = MAXPATHLEN;
+	if (mpd_unlikely(len >= MPD_PATH_MAX))
+		len = MPD_PATH_MAX - 1;
 	memcpy(dest, src, len);
 	dest[len] = '\0';
 }
 
-char *parentPath(char *path)
+char *parent_path(char *path_max_tmp, const char *path)
 {
-	static char parentPath[MAXPATHLEN+1];
 	char *c;
 
-	pathcpy_trunc(parentPath, path);
-	c = strrchr(parentPath,'/');
+	pathcpy_trunc(path_max_tmp, path);
+	c = strrchr(path_max_tmp,'/');
 
 	if (c == NULL)
-		parentPath[0] = '\0';
+		path_max_tmp[0] = '\0';
 	else {
-		while ((parentPath <= c) && *(--c) == '/')	/* nothing */
+		while ((path_max_tmp <= c) && *(--c) == '/')	/* nothing */
 			;
 		c[1] = '\0';
 	}
 
-	return parentPath;
+	return path_max_tmp;
 }
 
 char *sanitizePathDup(char *path)
diff --git a/src/path.h b/src/path.h
index 2357aa25d..ef7bc62a0 100644
--- a/src/path.h
+++ b/src/path.h
@@ -22,6 +22,17 @@
 #include "../config.h"
 
 #include <sys/param.h>
+#include <limits.h>
+
+#if !defined(MPD_PATH_MAX)
+#  if defined(MAXPATHLEN)
+#    define MPD_PATH_MAX MAXPATHLEN
+#  elif defined(PATH_MAX)
+#    define MPD_PATH_MAX PATH_MAX
+#  else
+#    define MPD_PATH_MAX 256
+#  endif
+#endif
 
 extern const char *musicDir;
 
@@ -29,33 +40,34 @@ void initPaths(void);
 
 void finishPaths(void);
 
-/* utf8ToFsCharset() and fsCharsetToUtf8()
- * Each returns a static pointer to a dynamically allocated buffer
- * which means:
- * - Do not manually free the return value of these functions, it'll be
- *   automatically freed the next time it is called.
- * - They are not reentrant, xstrdup the return value immediately if
- *   you expect to call one of these functions again, but still need the
- *   previous result.
- * - The static pointer is unique to each function.
- */
-char *utf8ToFsCharset(char *str);
-char *fsCharsetToUtf8(char *str);
+char *fs_charset_to_utf8(char *dst, char *str);
+
+char *utf8_to_fs_charset(char *dst, char *str);
 
 void setFsCharset(char *charset);
 
 char *getFsCharset(void);
 
+/*
+ * pfx_dir - sets dst="$pfx/$path" and returns a pointer to path inside * dst
+ * this will unconditionally put a '/' between pfx and path unlike
+ * the static pfx_path() function in path.c
+ * dst is assumed to be MAXPATHLEN in size
+ * dst can point to the same location as path, but not pfx, which makes
+ * this better than sprintf(3) in some cases
+ */
+char *pfx_dir(char *dst,
+              const char *path, const size_t path_len,
+              const char *pfx, const size_t pfx_len);
+
 /* relative music path to absolute music path
  * char * passed is a static variable, so don't free it
  */
-char *rmp2amp(char *file);
+char *rmp2amp_r(char *dst, const char *rel_path);
 
-/* static char * returned */
-char *rpp2app(char *file);
+char *rpp2app_r(char *dst, const char *rel_path);
 
-/* static char * returned */
-char *parentPath(char *path);
+char *parent_path(char *path_max_tmp, const char *path);
 
 /* strips extra "///" and leading "/" and trailing "/" */
 char *sanitizePathDup(char *path);
diff --git a/src/player.c b/src/player.c
index 5fbf590ff..ef66229bc 100644
--- a/src/player.c
+++ b/src/player.c
@@ -222,7 +222,7 @@ int playerPlay(int fd, Song * song)
 
 	copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
 
-	pathcpy_trunc(pc->utf8url, getSongUrl(song));
+	get_song_url(pc->utf8url, song);
 
 	pc->play = 1;
 	if (playerInit() < 0) {
@@ -337,7 +337,7 @@ int getPlayerError(void)
 char *getPlayerErrorStr(void)
 {
 	static char *error;
-	int errorlen = MAXPATHLEN + 1024;
+	int errorlen = MPD_PATH_MAX + 1024;
 	PlayerControl *pc = &(getPlayerData()->playerControl);
 
 	error = xrealloc(error, errorlen);
@@ -395,7 +395,7 @@ int queueSong(Song * song)
 	PlayerControl *pc = &(getPlayerData()->playerControl);
 
 	if (pc->queueState == PLAYER_QUEUE_BLANK) {
-		pathcpy_trunc(pc->utf8url, getSongUrl(song));
+		get_song_url(pc->utf8url, song);
 
 		if (song->tag)
 			pc->fileTime = song->tag->time;
@@ -454,6 +454,7 @@ void playerQueueUnlock(void)
 int playerSeek(int fd, Song * song, float time)
 {
 	PlayerControl *pc = &(getPlayerData()->playerControl);
+	char path_max_tmp[MPD_PATH_MAX];
 
 	if (pc->state == PLAYER_STATE_STOP) {
 		commandError(fd, ACK_ERROR_PLAYER_SYNC,
@@ -461,7 +462,7 @@ int playerSeek(int fd, Song * song, float time)
 		return -1;
 	}
 
-	if (strcmp(pc->utf8url, getSongUrl(song)) != 0) {
+	if (strcmp(pc->utf8url, get_song_url(path_max_tmp, song)) != 0) {
 		if (song->tag)
 			pc->fileTime = song->tag->time;
 		else
@@ -469,7 +470,7 @@ int playerSeek(int fd, Song * song, float time)
 
 		copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
 
-		pathcpy_trunc(pc->utf8url, getSongUrl(song));
+		strcpy(pc->utf8url, path_max_tmp);
 	}
 
 	if (pc->error == PLAYER_ERROR_NOERROR) {
diff --git a/src/player.h b/src/player.h
index cf265635f..462c0b2c9 100644
--- a/src/player.h
+++ b/src/player.h
@@ -71,9 +71,9 @@ typedef struct _PlayerControl {
 	volatile float totalTime;
 	volatile float elapsedTime;
 	volatile float fileTime;
-	char utf8url[MAXPATHLEN + 1];
-	char currentUrl[MAXPATHLEN + 1];
-	char erroredUrl[MAXPATHLEN + 1];
+	char utf8url[MPD_PATH_MAX];
+	char currentUrl[MPD_PATH_MAX];
+	char erroredUrl[MPD_PATH_MAX];
 	volatile mpd_sint8 queueState;
 	volatile mpd_sint8 queueLockState;
 	volatile mpd_sint8 lockQueue;
diff --git a/src/playerData.c b/src/playerData.c
index 380e4a148..69ef56bae 100644
--- a/src/playerData.c
+++ b/src/playerData.c
@@ -130,9 +130,9 @@ void initPlayerData(void)
 	playerData_pd->playerControl.queueLockState = PLAYER_QUEUE_UNLOCKED;
 	playerData_pd->playerControl.seek = 0;
 	playerData_pd->playerControl.closeAudio = 0;
-	memset(playerData_pd->playerControl.utf8url, 0, MAXPATHLEN + 1);
-	memset(playerData_pd->playerControl.erroredUrl, 0, MAXPATHLEN + 1);
-	memset(playerData_pd->playerControl.currentUrl, 0, MAXPATHLEN + 1);
+	memset(playerData_pd->playerControl.utf8url, 0, MPD_PATH_MAX);
+	memset(playerData_pd->playerControl.erroredUrl, 0, MPD_PATH_MAX);
+	memset(playerData_pd->playerControl.currentUrl, 0, MPD_PATH_MAX);
 	playerData_pd->playerControl.crossFade = crossfade;
 	playerData_pd->playerControl.softwareVolume = 1000;
 	playerData_pd->playerControl.totalPlayTime = 0;
@@ -145,7 +145,7 @@ void initPlayerData(void)
 	playerData_pd->decoderControl.state = DECODE_STATE_STOP;
 	playerData_pd->decoderControl.seek = 0;
 	playerData_pd->decoderControl.error = DECODE_ERROR_NOERROR;
-	memset(playerData_pd->decoderControl.utf8url, 0, MAXPATHLEN + 1);
+	memset(playerData_pd->decoderControl.utf8url, 0, MPD_PATH_MAX);
 }
 
 PlayerData *getPlayerData(void)
diff --git a/src/playlist.c b/src/playlist.c
index ce2748930..6d47bdb8f 100644
--- a/src/playlist.c
+++ b/src/playlist.c
@@ -56,7 +56,7 @@
 #define PLAYLIST_STATE_FILE_STATE_PAUSE		"pause"
 #define PLAYLIST_STATE_FILE_STATE_STOP		"stop"
 
-#define PLAYLIST_BUFFER_SIZE	2*MAXPATHLEN
+#define PLAYLIST_BUFFER_SIZE	2*MPD_PATH_MAX
 
 #define PLAYLIST_HASH_MULT	4
 
@@ -244,9 +244,11 @@ int clearStoredPlaylist(int fd, char *utf8file)
 int showPlaylist(int fd)
 {
 	int i;
+	char path_max_tmp[MPD_PATH_MAX];
 
 	for (i = 0; i < playlist.length; i++) {
-		fdprintf(fd, "%i:%s\n", i, getSongUrl(playlist.songs[i]));
+		fdprintf(fd, "%i:%s\n", i,
+		         get_song_url(path_max_tmp, playlist.songs[i]));
 	}
 
 	return 0;
@@ -499,6 +501,8 @@ static void swapSongs(int song1, int song2)
 
 static void queueNextSongInPlaylist(void)
 {
+	char path_max_tmp[MPD_PATH_MAX];
+
 	if (playlistQueue->numberOfNodes != 0) {
 		int i;
 		/* we need to find where in order[] is first song from queue */
@@ -511,8 +515,9 @@ static void queueNextSongInPlaylist(void)
 		playlist.queued = i;
 		DEBUG("playlist: queue song %i:\"%s\"\n",
 		      playlist.queued,
-		      getSongUrl(playlist.
-				 songs[playlist.order[playlist.queued]]));
+		      get_song_url(path_max_tmp,
+		                   playlist.
+				   songs[playlist.order[playlist.queued]]));
 		
 		if (queueSong(playlist.songs[playlist.order[playlist.queued]]) <
 		    0) {
@@ -524,8 +529,9 @@ static void queueNextSongInPlaylist(void)
 		playlist.queued = playlist.current + 1;
 		DEBUG("playlist: queue song %i:\"%s\"\n",
 		      playlist.queued,
-		      getSongUrl(playlist.
-				 songs[playlist.order[playlist.queued]]));
+		      get_song_url(path_max_tmp,
+		                   playlist.
+				   songs[playlist.order[playlist.queued]]));
 		if (queueSong(playlist.songs[playlist.order[playlist.queued]]) <
 		    0) {
 			playlist.queued = -1;
@@ -539,8 +545,9 @@ static void queueNextSongInPlaylist(void)
 		playlist.queued = 0;
 		DEBUG("playlist: queue song %i:\"%s\"\n",
 		      playlist.queued,
-		      getSongUrl(playlist.
-				 songs[playlist.order[playlist.queued]]));
+		      get_song_url(path_max_tmp,
+		                   playlist.
+		                   songs[playlist.order[playlist.queued]]));
 		if (queueSong(playlist.songs[playlist.order[playlist.queued]]) <
 		    0) {
 			playlist.queued = -1;
@@ -897,6 +904,8 @@ int stopPlaylist(int fd)
 
 static int playPlaylistOrderNumber(int fd, int orderNum)
 {
+	char path_max_tmp[MPD_PATH_MAX];
+
 	if (playerStop(fd) < 0)
 		return -1;
 
@@ -906,7 +915,8 @@ static int playPlaylistOrderNumber(int fd, int orderNum)
 	playlist_queueError = 0;
 
 	DEBUG("playlist: play %i:\"%s\"\n", orderNum,
-	      getSongUrl(playlist.songs[playlist.order[orderNum]]));
+	      get_song_url(path_max_tmp,
+	                   playlist.songs[playlist.order[orderNum]]));
 
 	if (playerPlay(fd, (playlist.songs[playlist.order[orderNum]])) < 0) {
 		stopPlaylist(fd);
@@ -1003,6 +1013,7 @@ static void syncCurrentPlayerDecodeMetadata(void)
 	Song *songPlayer = playerCurrentDecodeSong();
 	Song *song;
 	int songNum;
+	char path_max_tmp[MPD_PATH_MAX];
 
 	if (!songPlayer)
 		return;
@@ -1014,7 +1025,7 @@ static void syncCurrentPlayerDecodeMetadata(void)
 	song = playlist.songs[songNum];
 
 	if (song->type == SONG_TYPE_URL &&
-	    0 == strcmp(getSongUrl(song), songPlayer->url) &&
+	    0 == strcmp(get_song_url(path_max_tmp, song), songPlayer->url) &&
 	    !mpdTagsAreEqual(song->tag, songPlayer->tag)) {
 		if (song->tag)
 			freeMpdTag(song->tag);
@@ -1376,16 +1387,18 @@ int shufflePlaylist(int fd)
 
 int deletePlaylist(int fd, char *utf8file)
 {
-	char *file = utf8ToFsCharset(utf8file);
+	char path_max_tmp[MPD_PATH_MAX];
+	char *file = utf8_to_fs_charset(path_max_tmp, utf8file);
 	char *rfile = xmalloc(strlen(file) + strlen(".") +
-			     strlen(PLAYLIST_FILE_SUFFIX) + 1);
+			      strlen(PLAYLIST_FILE_SUFFIX) + 1);
 	char *actualFile;
 
 	strcpy(rfile, file);
 	strcat(rfile, ".");
 	strcat(rfile, PLAYLIST_FILE_SUFFIX);
 
-	if ((actualFile = rpp2app(rfile)) && isPlaylist(actualFile))
+	actualFile = rpp2app_r(path_max_tmp, rfile);
+	if (isPlaylist(actualFile))
 		free(rfile);
 	else {
 		free(rfile);
diff --git a/src/song.c b/src/song.c
index 9bcb1a0b4..1a3a78682 100644
--- a/src/song.c
+++ b/src/song.c
@@ -66,9 +66,11 @@ Song *newSong(char *url, int type, Directory * parentDir)
 	if (song->type == SONG_TYPE_FILE) {
 		InputPlugin *plugin;
 		unsigned int next = 0;
-		char *song_url = getSongUrl(song);
-		char *abs_path = rmp2amp(utf8ToFsCharset(song_url));
-		while (!song->tag && (plugin = isMusic(song_url,
+		char path_max_tmp[MPD_PATH_MAX];
+		char *abs_path = rmp2amp_r(path_max_tmp,
+		                           get_song_url(path_max_tmp, song));
+
+		while (!song->tag && (plugin = isMusic(abs_path,
 						       &(song->mtime),
 						       next++))) {
 			song->tag = plugin->tagDupFunc(abs_path);
@@ -94,7 +96,6 @@ void freeJustSong(Song * song)
 	if (song->tag)
 		freeMpdTag(song->tag);
 	free(song);
-	getSongUrl(NULL);
 }
 
 SongList *newSongList(void)
@@ -231,8 +232,8 @@ static int matchesAnMpdTagItemKey(char *buffer, int *itemType)
 
 void readSongInfoIntoList(FILE * fp, SongList * list, Directory * parentDir)
 {
-	char buffer[MAXPATHLEN + 1024];
-	int bufferSize = MAXPATHLEN + 1024;
+	char buffer[MPD_PATH_MAX + 1024];
+	int bufferSize = MPD_PATH_MAX + 1024;
 	Song *song = NULL;
 	ListNode *nextSongNode = list->firstNode;
 	ListNode *nodeTemp;
@@ -292,15 +293,16 @@ int updateSongInfo(Song * song)
 	if (song->type == SONG_TYPE_FILE) {
 		InputPlugin *plugin;
 		unsigned int next = 0;
-		char *song_url = getSongUrl(song);
-		char *abs_path = rmp2amp(song_url);
+		char path_max_tmp[MPD_PATH_MAX];
+		char *abs_path = rmp2amp_r(path_max_tmp,
+		                           get_song_url(path_max_tmp, song));
 
 		if (song->tag)
 			freeMpdTag(song->tag);
 
 		song->tag = NULL;
 
-		while (!song->tag && (plugin = isMusic(song_url,
+		while (!song->tag && (plugin = isMusic(abs_path,
 						       &(song->mtime),
 						       next++))) {
 			song->tag = plugin->tagDupFunc(abs_path);
@@ -312,42 +314,15 @@ int updateSongInfo(Song * song)
 	return 0;
 }
 
-/* pass song = NULL to reset, we do this freeJustSong(), so that if
- * 	we free and recreate this memory we make sure to print it correctly*/
-char *getSongUrl(Song * song)
+char *get_song_url(char *path_max_tmp, Song *song)
 {
-	static char *buffer;
-	static int bufferSize;
-	static Song *lastSong;
-	int slen;
-	int dlen;
-	int size;
-
-	if (!song) {
-		lastSong = song;
+	if (!song)
 		return NULL;
-	}
-
 	if (!song->parentDir || !song->parentDir->path)
-		return song->url;
-
-	/* be careful with this! */
-	if (song == lastSong)
-		return buffer;
-
-	slen = strlen(song->url);
-	dlen = strlen(getDirectoryPath(song->parentDir));
-
-	size = slen + dlen + 2;
-
-	if (size > bufferSize) {
-		buffer = xrealloc(buffer, size);
-		bufferSize = size;
-	}
-
-	strcpy(buffer, getDirectoryPath(song->parentDir));
-	buffer[dlen] = '/';
-	strcpy(buffer + dlen + 1, song->url);
-
-	return buffer;
+		strcpy(path_max_tmp, song->url);
+	else
+		pfx_dir(path_max_tmp, song->url, strlen(song->url),
+			getDirectoryPath(song->parentDir),
+			strlen(getDirectoryPath(song->parentDir)));
+	return path_max_tmp;
 }
diff --git a/src/song.h b/src/song.h
index c4100d2a2..46435efb8 100644
--- a/src/song.h
+++ b/src/song.h
@@ -74,6 +74,6 @@ int updateSongInfo(Song * song);
 
 void printSongUrl(int fd, Song * song);
 
-char *getSongUrl(Song * song);
+char *get_song_url(char *path_max_tmp, Song * song);
 
 #endif
diff --git a/src/storedPlaylist.c b/src/storedPlaylist.c
index 322cb1b5b..a166064ab 100644
--- a/src/storedPlaylist.c
+++ b/src/storedPlaylist.c
@@ -34,6 +34,7 @@ static char *utf8pathToFsPathInStoredPlaylist(const char *utf8path, int fd)
 	char *file;
 	char *rfile;
 	char *actualFile;
+	static char path_max_tmp[MPD_PATH_MAX]; /* should be MT-safe */
 
 	if (strstr(utf8path, "/")) {
 		commandError(fd, ACK_ERROR_ARG, "playlist name \"%s\" is "
@@ -42,8 +43,7 @@ static char *utf8pathToFsPathInStoredPlaylist(const char *utf8path, int fd)
 		return NULL;
 	}
 
-	file = utf8ToFsCharset((char *)utf8path);
-
+	file = utf8_to_fs_charset(path_max_tmp, (char *)utf8path);
 	rfile = xmalloc(strlen(file) + strlen(".") +
 	                strlen(PLAYLIST_FILE_SUFFIX) + 1);
 
@@ -51,7 +51,7 @@ static char *utf8pathToFsPathInStoredPlaylist(const char *utf8path, int fd)
 	strcat(rfile, ".");
 	strcat(rfile, PLAYLIST_FILE_SUFFIX);
 
-	actualFile = rpp2app(rfile);
+	actualFile = rpp2app_r(path_max_tmp, rfile);
 
 	free(rfile);
 
@@ -100,7 +100,10 @@ static ListNode *nodeOfStoredPlaylist(StoredPlaylist *sp, int index)
 
 static void appendSongToStoredPlaylist(StoredPlaylist *sp, Song *song)
 {
-	insertInListWithoutKey(sp->list, xstrdup(getSongUrl(song)));
+	char path_max_tmp[MPD_PATH_MAX];
+
+	get_song_url(path_max_tmp, song);
+	insertInListWithoutKey(sp->list, xstrdup(path_max_tmp));
 }
 
 StoredPlaylist *newStoredPlaylist(const char *utf8name, int fd, int ignoreExisting)
@@ -138,10 +141,13 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
 	char *filename;
 	StoredPlaylist *sp;
 	FILE *file;
-	char s[MAXPATHLEN + 1];
+	char s[MPD_PATH_MAX];
+	char path_max_tmp[MPD_PATH_MAX];
+	char path_max_tmp2[MPD_PATH_MAX]; /* TODO: cleanup */
+	char path_max_tmp3[MPD_PATH_MAX]; /* TODO: cleanup */
 	int slength = 0;
-	char *temp = utf8ToFsCharset((char *)utf8path);
-	char *parent = parentPath(temp);
+	char *temp = utf8_to_fs_charset(path_max_tmp2, (char *)utf8path);
+	char *parent = parent_path(path_max_tmp3, temp);
 	int parentlen = strlen(parent);
 	int tempInt;
 	int commentCharFound = 0;
@@ -169,15 +175,18 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
 			s[slength] = '\0';
 			if (s[0] == PLAYLIST_COMMENT)
 				commentCharFound = 1;
-			if (strncmp(s, musicDir, strlen(musicDir)) == 0) {
-				strcpy(s, &(s[strlen(musicDir)]));
+			if (!strncmp(s, musicDir, strlen(musicDir)) &&
+			    s[strlen(musicDir)] == '/') {
+				memmove(s, &(s[strlen(musicDir) + 1]),
+				        strlen(&(s[strlen(musicDir) + 1])) + 1);
+				printf("s: <%s>\n", s);
 			} else if (parentlen) {
 				temp = xstrdup(s);
-				memset(s, 0, MAXPATHLEN + 1);
+				memset(s, 0, MPD_PATH_MAX);
 				strcpy(s, parent);
-				strncat(s, "/", MAXPATHLEN - parentlen);
-				strncat(s, temp, MAXPATHLEN - parentlen - 1);
-				if (strlen(s) >= MAXPATHLEN) {
+				strncat(s, "/", MPD_PATH_MAX - parentlen);
+				strncat(s, temp, MPD_PATH_MAX - parentlen - 1);
+				if (strlen(s) >= MPD_PATH_MAX) {
 					commandError(sp->fd,
 					             ACK_ERROR_PLAYLIST_LOAD,
 					             "\"%s\" is too long", temp);
@@ -189,7 +198,7 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
 				free(temp);
 			}
 			slength = 0;
-			temp = fsCharsetToUtf8(s);
+			temp = fs_charset_to_utf8(path_max_tmp, s);
 			if (temp && !commentCharFound) {
 				song = getSongFromDB(temp);
 				if (song) {
@@ -206,7 +215,7 @@ StoredPlaylist *loadStoredPlaylist(const char *utf8path, int fd)
 					freeJustSong(song);
 				}
 			}
-		} else if (slength == MAXPATHLEN) {
+		} else if (slength == (MPD_PATH_MAX - 1)) {
 			s[slength] = '\0';
 			commandError(sp->fd, ACK_ERROR_PLAYLIST_LOAD,
 				     "line \"%s\" in playlist \"%s\" "
@@ -401,11 +410,11 @@ static int writeStoredPlaylistToPath(StoredPlaylist *sp, const char *fspath)
 
 	node = sp->list->firstNode;
 	while (node != NULL) {
-		s = (char *)node->data;
-		if (isValidRemoteUtf8Url(s) || !playlist_saveAbsolutePaths)
-			s = utf8ToFsCharset(s);
-		else
-			s = rmp2amp(utf8ToFsCharset(s));
+		char path_max_tmp[MPD_PATH_MAX];
+
+		s = utf8_to_fs_charset(path_max_tmp, (char *)node->data);
+		if (playlist_saveAbsolutePaths && !isValidRemoteUtf8Url(s))
+			s = rmp2amp_r(path_max_tmp, s);
 		fprintf(file, "%s\n", s);
 		node = node->nextNode;
 	}
@@ -424,6 +433,8 @@ int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song)
 	char *filename;
 	FILE *file;
 	char *s;
+	char path_max_tmp[MPD_PATH_MAX];
+	char path_max_tmp2[MPD_PATH_MAX];
 
 	filename = utf8pathToFsPathInStoredPlaylist(utf8path, fd);
 	if (!filename)
@@ -436,10 +447,10 @@ int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song)
 		return -1;
 	}
 
+	s = utf8_to_fs_charset(path_max_tmp2, get_song_url(path_max_tmp, song));
+
 	if (playlist_saveAbsolutePaths && song->type == SONG_TYPE_FILE)
-		s = rmp2amp(utf8ToFsCharset(getSongUrl(song)));
-	else
-		s = utf8ToFsCharset(getSongUrl(song));
+		s = rmp2amp_r(path_max_tmp, s);
 
 	fprintf(file, "%s\n", s);
 
diff --git a/src/tag.c b/src/tag.c
index 57ca14669..3761e2079 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -157,7 +157,8 @@ static id3_utf8_t * processID3FieldString (int is_id3v1, const id3_ucs4_t *ucs4,
             return NULL;
         }
         setCharSetConversion("UTF-8", encoding);
-        utf8 = (id3_utf8_t *)convStrDup((char *)isostr);
+        utf8 = xmalloc(strlen((char *)isostr) + 1);
+        utf8 = (id3_utf8_t *)char_conv_str((char *)utf8, (char *)isostr);
         if (!utf8) {
             DEBUG("Unable to convert %s string to UTF-8: "
                     "'%s'\n", encoding, isostr);
diff --git a/src/utf8.c b/src/utf8.c
index 2061a78de..bb62a34f7 100644
--- a/src/utf8.c
+++ b/src/utf8.c
@@ -23,51 +23,42 @@
 #include <string.h>
 #include <stdlib.h>
 
-static char *latin1ToUtf8(char c)
+char *latin1_to_utf8(char *dest, char *in_latin1)
 {
-	static unsigned char utf8[3];
-	unsigned char uc = c;
+	unsigned char *cp = (unsigned char *)dest;
+	unsigned char *latin1 = (unsigned char *)in_latin1;
 
-	memset(utf8, 0, 3);
-
-	if (uc < 128)
-		utf8[0] = uc;
-	else if (uc < 192) {
-		utf8[0] = 194;
-		utf8[1] = uc;
-	} else {
-		utf8[0] = 195;
-		utf8[1] = uc - 64;
+	while (*latin1) {
+		if (*latin1 < 128)
+			*(cp++) = *latin1;
+		else {
+			if (*latin1 < 192) {
+				*(cp++) = 194;
+				*(cp++) = *latin1;
+			} else {
+				*(cp++) = 195;
+				*(cp++) = (*latin1) - 64;
+			}
+		}
+		++latin1;
 	}
 
-	return (char *)utf8;
+	*cp = '\0';
+
+	return dest;
 }
 
 char *latin1StrToUtf8Dup(char *latin1)
 {
 	/* utf8 should have at most two char's per latin1 char */
-	int len = strlen(latin1) * 2 + 1;
-	char *ret = xmalloc(len);
-	char *cp = ret;
-	char *utf8;
+	char *ret = xmalloc(strlen(latin1) * 2 + 1);
 
-	memset(ret, 0, len);
+	ret = latin1_to_utf8(ret, latin1);
 
-	len = 0;
-
-	while (*latin1) {
-		utf8 = latin1ToUtf8(*latin1);
-		while (*utf8) {
-			*(cp++) = *(utf8++);
-			len++;
-		}
-		latin1++;
-	}
-
-	return xrealloc(ret, len + 1);
+	return ((ret) ? xrealloc(ret, strlen((char *)ret) + 1) : NULL);
 }
 
-static char utf8ToLatin1(char *inUtf8)
+static char utf8_to_latin1_char(char *inUtf8)
 {
 	unsigned char c = 0;
 	unsigned char *utf8 = (unsigned char *)inUtf8;
@@ -124,14 +115,10 @@ int validUtf8String(char *string)
 char *utf8StrToLatin1Dup(char *utf8)
 {
 	/* utf8 should have at most two char's per latin1 char */
-	int len = strlen(utf8) + 1;
-	char *ret = xmalloc(len);
+	char *ret = xmalloc(strlen(utf8) + 1);
 	char *cp = ret;
 	int count;
-
-	memset(ret, 0, len);
-
-	len = 0;
+	size_t len = 0;
 
 	while (*utf8) {
 		count = validateUtf8Char(utf8);
@@ -139,10 +126,32 @@ char *utf8StrToLatin1Dup(char *utf8)
 			free(ret);
 			return NULL;
 		}
-		*(cp++) = utf8ToLatin1(utf8);
+		*(cp++) = utf8_to_latin1_char(utf8);
 		utf8 += count;
 		len++;
 	}
 
+	*cp = '\0';
+
 	return xrealloc(ret, len + 1);
 }
+
+char *utf8_to_latin1(char *dest, char *utf8)
+{
+	char *cp = dest;
+	int count;
+	size_t len = 0;
+
+	while (*utf8) {
+		count = validateUtf8Char(utf8);
+		if (count) {
+			*(cp++) = utf8_to_latin1_char(utf8);
+			utf8 += count;
+			len++;
+		} else
+			return NULL;
+	}
+
+	*cp = '\0';
+	return dest;
+}
diff --git a/src/utf8.h b/src/utf8.h
index 0eb60d82c..05e1a4a31 100644
--- a/src/utf8.h
+++ b/src/utf8.h
@@ -25,4 +25,9 @@ char *utf8StrToLatin1Dup(char *utf8);
 
 int validUtf8String(char *string);
 
+char *utf8_to_latin1(char *dest, char *utf8);
+
+char *latin1_to_utf8(char *dest, char *utf8);
+
+
 #endif
diff --git a/src/utils.c b/src/utils.c
index ea7edb4c5..e9865aa24 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -30,6 +30,8 @@
 #include <unistd.h>
 #include <assert.h>
 #include <pwd.h>
+#include <signal.h>
+#include <sys/param.h>
 
 char *myFgets(char *buffer, int bufferSize, FILE * fp)
 {
@@ -43,15 +45,21 @@ char *myFgets(char *buffer, int bufferSize, FILE * fp)
 	return ret;
 }
 
-char *strDupToUpper(char *str)
+char *string_toupper(char *str)
 {
-	char *ret = xstrdup(str);
-	int i;
+	int i = strlen(str);
+	char *ret = str;
 
-	for (i = 0; i < strlen(str); i++)
-		ret[i] = toupper((int)ret[i]);
+	for (; --i >= 0; ++str)
+		*str = toupper((int)(*str));
 
 	return ret;
+
+}
+
+char *strDupToUpper(char *str)
+{
+	return string_toupper(xstrdup(str));
 }
 
 void stripReturnChar(char *string)
diff --git a/src/utils.h b/src/utils.h
index 09a9bc4e8..258b725f3 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -34,7 +34,9 @@
 
 char *myFgets(char *buffer, int bufferSize, FILE * fp);
 
-char *strDupToUpper(char *str);
+char *string_toupper(char *str);
+
+char *strDupToUpper(char *str); /* avoid, use string_toupper instead */
 
 void stripReturnChar(char *string);