diff --git a/src/d_main.c b/src/d_main.c
index 89579ea91c2644baffcc4e5ed29306cfcefceebf..b4b668f4bc0c8b984800cae319862f7b2aa2fe7c 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -944,13 +944,13 @@ static void D_AddFile(char **list, const char *file)
 
 static void D_AddFolder(char **list, const char *file)
 {
-	size_t pnumwadfiles, len = strlen(file);
+	size_t pnumwadfiles;
 	char *newfile;
 
 	for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++)
 		;
 
-	newfile = malloc(len + 2); // NULL terminator + path separator
+	newfile = malloc(strlen(file) + 2); // Path delimiter + NULL terminator
 	if (!newfile)
 		I_Error("No more free memory to AddFolder %s",file);
 
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index ea0d9ca80684e8a741978325b8717c3a56af1484..1e4e2b464ab0073978d9570acbabf1d609f21d58 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -1518,7 +1518,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 			{
 				illegalMask &= ~(1 << i);
 			}
-			
+
 			if ((p->availabilities & illegalMask) != 0)
 			{
 				kick = true;
@@ -3416,9 +3416,10 @@ static void Command_Addfolder(void)
 	for (curarg = 1; curarg < argc; curarg++)
 	{
 		const char *fn, *p;
+		char *fullpath;
 		char buf[256];
 		char *buf_p = buf;
-		INT32 i;
+		INT32 i, stat;
 		size_t ii;
 		boolean folderadded = false;
 
@@ -3461,6 +3462,13 @@ static void Command_Addfolder(void)
 				break;
 		++p;
 
+		// Don't add an empty path.
+		if (M_IsStringEmpty(fn))
+		{
+			CONS_Alert(CONS_WARNING, M_GetText("Folder name is empty, skipping\n"));
+			continue;
+		}
+
 		// check total packet size and no of files currently loaded
 		// See W_InitFile in w_wad.c
 		if ((numwadfiles >= MAX_WADFILES)
@@ -3470,10 +3478,52 @@ static void Command_Addfolder(void)
 			return;
 		}
 
-		WRITESTRINGN(buf_p,p,240);
+		// Check if the path is valid.
+		stat = W_IsPathToFolderValid(fn);
+
+		if (stat == 0)
+		{
+			CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn);
+			continue;
+		}
+		else if (stat < 0)
+		{
+#ifndef AVOID_ERRNO
+			CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s (%s), skipping\n"), fn, strerror(direrror));
+#else
+			CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s, skipping\n"), fn);
+#endif
+			continue;
+		}
+
+		// Get the full path for this folder.
+		fullpath = W_GetFullFolderPath(fn);
+
+		if (fullpath == NULL)
+		{
+			CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn);
+			continue;
+		}
+
+		// Check if the folder is already added.
+		for (i = 0; i < numwadfiles; i++)
+		{
+			if (wadfiles[i]->type != RET_FOLDER)
+				continue;
+
+			if (samepaths(wadfiles[i]->path, fullpath) > 0)
+			{
+				CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn);
+				continue;
+			}
+		}
+
+		Z_Free(fullpath);
 
 		addedfolders[numfoldersadded++] = fn;
 
+		WRITESTRINGN(buf_p,p,240);
+
 		if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file
 			SendNetXCmd(XD_REQADDFOLDER, buf, buf_p - buf);
 		else
diff --git a/src/d_netfil.c b/src/d_netfil.c
index 15f9f1ff5ce7f00d7ae367484f531a34e706d5db..12c5ee6a211640046b74bd1b7ade6fcb811e1ff0 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -1584,20 +1584,23 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet
 	return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found
 }
 
+// Searches for a folder.
+// This can be used with a full path, or an incomplete path.
+// In the latter case, the function will try to find folders in
+// srb2home, srb2path, and the current directory.
 filestatus_t findfolder(const char *path)
 {
 	// Check the path by itself first.
-	if (checkfolderpath(path, NULL, true))
+	if (concatpaths(path, NULL) == 1)
 		return FS_FOUND;
 
-#define checkpath(startpath) { \
-	if (checkfolderpath(path, startpath, true)) \
-		return FS_FOUND; \
-	}
+#define checkpath(startpath) \
+	if (concatpaths(path, startpath) == 1) \
+		return FS_FOUND
 
-	checkpath(srb2home) // Then, look in srb2home.
-	checkpath(srb2path) // Now, look in srb2path.
-	checkpath(".") // Finally, look in ".".
+	checkpath(srb2home); // Then, look in srb2home.
+	checkpath(srb2path); // Now, look in srb2path.
+	checkpath("."); // Finally, look in the current directory.
 
 #undef checkpath
 
diff --git a/src/filesrch.c b/src/filesrch.c
index f01fc0bd2e236a9b74625ecb089e2e131571969f..e5c9b21589f74d3cb39f0d88fa905f20f577d385 100644
--- a/src/filesrch.c
+++ b/src/filesrch.c
@@ -341,8 +341,8 @@ char *refreshdirname = NULL;
 size_t packetsizetally = 0;
 size_t mainwadstally = 0;
 
-#define folderpathlen 1024
-#define maxfolderdepth 48
+#define dirpathlen 1024
+#define maxdirdepth 48
 
 #define isuptree(dirent) ((dirent)[0]=='.' && ((dirent)[1]=='\0' || ((dirent)[1]=='.' && (dirent)[2]=='\0')))
 
@@ -448,182 +448,227 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
 	return retval;
 }
 
-// Called from findfolder and ResGetLumpsFolder in w_wad.c.
-// Call with cleanup true if the path has to be verified.
-boolean checkfolderpath(const char *path, const char *startpath, boolean cleanup)
+#ifndef AVOID_ERRNO
+int direrror = 0;
+#endif
+
+// Checks if the specified path is a directory.
+// Returns 1 if so, 0 if not, and -1 if an error occurred.
+// direrror is set if there was an error.
+INT32 pathisdirectory(const char *path)
 {
-	char folderpath[folderpathlen], basepath[folderpathlen], *fn = NULL;
-	DIR *dirhandle;
+	struct stat fsstat;
 
-	// Remove path separators from the filename, and don't try adding "/".
-	// See also the same code in W_InitFolder.
-	if (cleanup)
+	if (stat(path, &fsstat) < 0)
 	{
-		const char *p = path + strlen(path);
-		size_t len;
+#ifndef AVOID_ERRNO
+		direrror = errno;
+#endif
+		return -1;
+	}
+	else if (S_ISDIR(fsstat.st_mode))
+		return 1;
 
-		--p;
-		while (*p == '\\' || *p == '/' || *p == ':')
-		{
-			p--;
-			if (p < path)
-				return false;
-		}
-		++p;
+	return 0;
+}
 
-		// Allocate the new path name.
-		len = (p - path) + 1;
-		fn = ZZ_Alloc(len);
-		strlcpy(fn, path, len);
-	}
+// Concatenates two paths, and checks if it is a directory that can be opened.
+// Returns 1 if so, 0 if not, and -1 if an error occurred.
+INT32 concatpaths(const char *path, const char *startpath)
+{
+	char dirpath[dirpathlen];
+	DIR *dirhandle;
+	INT32 stat;
 
 	if (startpath)
 	{
+		char basepath[dirpathlen];
+
 		snprintf(basepath, sizeof basepath, "%s" PATHSEP, startpath);
+		snprintf(dirpath, sizeof dirpath, "%s%s", basepath, path);
 
-		if (cleanup)
-		{
-			snprintf(folderpath, sizeof folderpath, "%s%s", basepath, fn);
-			Z_Free(fn); // Don't need this anymore.
-		}
-		else
-			snprintf(folderpath, sizeof folderpath, "%s%s", basepath, path);
+		// Base path and directory path are the same? Not valid.
+		stat = samepaths(basepath, dirpath);
 
-		// Home path and folder path are the same? Not valid.
-		if (!strcmp(basepath, folderpath))
-			return false;
+		if (stat == 1)
+			return 0;
+		else if (stat < 0)
+			return -1;
 	}
-	else if (cleanup)
+	else
+		snprintf(dirpath, sizeof dirpath, "%s", path);
+
+	// Check if the path is a directory.
+	// Will return -1 if there was an error.
+	stat = pathisdirectory(dirpath);
+	if (stat == 0)
+		return 0;
+	else if (stat < 0)
 	{
-		snprintf(folderpath, sizeof folderpath, "%s", fn);
-		Z_Free(fn); // Don't need this anymore.
+		// The path doesn't exist, so it can't be a directory.
+		if (direrror == ENOENT)
+			return 0;
+
+		return -1;
 	}
-	else
-		snprintf(folderpath, sizeof folderpath, "%s", path);
 
-	dirhandle = opendir(folderpath);
+	// Open the directory.
+	// Will return 0 if it couldn't be opened.
+	dirhandle = opendir(dirpath);
 	if (dirhandle == NULL)
-		return false;
+		return 0;
 	else
 		closedir(dirhandle);
 
-	return true;
-}
-
-INT32 pathisfolder(const char *path)
-{
-	struct stat fsstat;
-
-	if (stat(path, &fsstat) < 0)
-		return -1;
-	else if (S_ISDIR(fsstat.st_mode))
-		return 1;
-
-	return 0;
+	return 1;
 }
 
+// Checks if two paths are the same. Returns 1 if so, and 0 if not.
+// Returns -1 if an error occurred with the first path,
+// and returns -2 if an error occurred with the second path.
+// direrror is set if there was an error.
 INT32 samepaths(const char *path1, const char *path2)
 {
 	struct stat stat1;
 	struct stat stat2;
 
 	if (stat(path1, &stat1) < 0)
+	{
+#ifndef AVOID_ERRNO
+		direrror = errno;
+#endif
 		return -1;
+	}
 	if (stat(path2, &stat2) < 0)
-		return -1;
+	{
+#ifndef AVOID_ERRNO
+		direrror = errno;
+#endif
+		return -2;
+	}
 
 	if (stat1.st_dev == stat2.st_dev)
 	{
 #if !defined(_WIN32)
 		return (stat1.st_ino == stat2.st_ino);
 #else
+		// The above doesn't work on NTFS or FAT.
 		HANDLE file1 = CreateFileA(path1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 		HANDLE file2 = CreateFileA(path2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
 		BY_HANDLE_FILE_INFORMATION file1info, file2info;
-		boolean ok = false;
 
-		if (file1 != INVALID_HANDLE_VALUE && file2 != INVALID_HANDLE_VALUE)
+		if (file1 == INVALID_HANDLE_VALUE)
 		{
-			if (GetFileInformationByHandle(file1, &file1info) && GetFileInformationByHandle(file2, &file2info))
-			{
-				if (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber
-				&& file1info.nFileIndexLow == file2info.nFileIndexLow
-				&& file1info.nFileIndexHigh == file2info.nFileIndexHigh)
-					ok = true;
-			}
+#ifndef AVOID_ERRNO
+			direrror = ENOENT;
+#endif
+			return -1;
+		}
+		else if (file2 == INVALID_HANDLE_VALUE)
+		{
+			CloseHandle(file1);
+#ifndef AVOID_ERRNO
+			direrror = ENOENT;
+#endif
+			return -2;
+		}
+
+		// I have no idea why GetFileInformationByHandle would fail.
+		// Microsoft's documentation doesn't tell me.
+		// I'll just use EIO...
+		if (!GetFileInformationByHandle(file1, &file1info))
+		{
+#ifndef AVOID_ERRNO
+			direrror = EIO;
+#endif
+			return -1;
+		}
+		else if (!GetFileInformationByHandle(file2, &file2info))
+		{
+			CloseHandle(file1);
+			CloseHandle(file2);
+#ifndef AVOID_ERRNO
+			direrror = EIO;
+#endif
+			return -2;
 		}
 
-		if (file1 != INVALID_HANDLE_VALUE)
+		if (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber
+		&& file1info.nFileIndexLow == file2info.nFileIndexLow
+		&& file1info.nFileIndexHigh == file2info.nFileIndexHigh)
+		{
 			CloseHandle(file1);
-		if (file2 != INVALID_HANDLE_VALUE)
 			CloseHandle(file2);
+			return 1;
+		}
 
-		return ok;
+		return 0;
 #endif
 	}
 
-	return false;
+	return 0;
 }
 
 //
-// Folder loading
+// Directory loading
 //
 
-static void initfolderpath(char *folderpath, size_t *folderpathindex, int depthleft)
+static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft)
 {
-	folderpathindex[depthleft] = strlen(folderpath) + 1;
+	dirpathindex[depthleft] = strlen(dirpath) + 1;
 
-	if (folderpath[folderpathindex[depthleft]-2] != PATHSEP[0])
+	if (dirpath[dirpathindex[depthleft]-2] != PATHSEP[0])
 	{
-		folderpath[folderpathindex[depthleft]-1] = PATHSEP[0];
-		folderpath[folderpathindex[depthleft]] = 0;
+		dirpath[dirpathindex[depthleft]-1] = PATHSEP[0];
+		dirpath[dirpathindex[depthleft]] = 0;
 	}
 	else
-		folderpathindex[depthleft]--;
+		dirpathindex[depthleft]--;
 }
 
-lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT16 *nfolders)
+lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
 {
 	DIR **dirhandle;
 	struct dirent *dent;
 	struct stat fsstat;
 
-	int rootfolder = (maxfolderdepth - 1);
-	int depthleft = rootfolder;
+	int rootdir = (maxdirdepth - 1);
+	int depthleft = rootdir;
 
-	char folderpath[folderpathlen];
-	size_t *folderpathindex;
+	char dirpath[dirpathlen];
+	size_t *dirpathindex;
 
 	lumpinfo_t *lumpinfo, *lump_p;
-	UINT16 i = 0, numlumps = (*nlmp);
+	UINT16 i = 0, numlumps = 0;
+
+	boolean failure = false;
 
-	dirhandle = (DIR **)malloc(maxfolderdepth * sizeof (DIR*));
-	folderpathindex = (size_t *)malloc(maxfolderdepth * sizeof(size_t));
+	dirhandle = (DIR **)malloc(maxdirdepth * sizeof (DIR*));
+	dirpathindex = (size_t *)malloc(maxdirdepth * sizeof(size_t));
 
 	// Open the root directory
-	strlcpy(folderpath, path, folderpathlen);
-	dirhandle[depthleft] = opendir(folderpath);
+	strlcpy(dirpath, path, dirpathlen);
+	dirhandle[depthleft] = opendir(dirpath);
 
 	if (dirhandle[depthleft] == NULL)
 	{
 		free(dirhandle);
-		free(folderpathindex);
+		free(dirpathindex);
 		return NULL;
 	}
 
-	initfolderpath(folderpath, folderpathindex, depthleft);
-	(*nfiles) = 0;
+	initdirpath(dirpath, dirpathindex, depthleft);
 	(*nfolders) = 0;
 
 	// Count files and directories
-	while (depthleft < maxfolderdepth)
+	while (depthleft < maxdirdepth)
 	{
-		folderpath[folderpathindex[depthleft]] = 0;
+		dirpath[dirpathindex[depthleft]] = 0;
 		dent = readdir(dirhandle[depthleft]);
 
 		if (!dent)
 		{
-			if (depthleft != rootfolder) // Don't close the root directory
+			if (depthleft != rootdir) // Don't close the root directory
 				closedir(dirhandle[depthleft]);
 			depthleft++;
 			continue;
@@ -631,62 +676,67 @@ lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT1
 		else if (isuptree(dent->d_name))
 			continue;
 
-		strcpy(&folderpath[folderpathindex[depthleft]], dent->d_name);
+		strcpy(&dirpath[dirpathindex[depthleft]], dent->d_name);
 
-		if (stat(folderpath, &fsstat) < 0)
+		if (stat(dirpath, &fsstat) < 0)
 			;
 		else if (S_ISDIR(fsstat.st_mode) && depthleft)
 		{
-			folderpathindex[--depthleft] = strlen(folderpath) + 1;
-			dirhandle[depthleft] = opendir(folderpath);
+			dirpathindex[--depthleft] = strlen(dirpath) + 1;
+			dirhandle[depthleft] = opendir(dirpath);
 
 			if (dirhandle[depthleft])
-			{
-				numlumps++;
 				(*nfolders)++;
-			}
 			else
 				depthleft++;
 
-			folderpath[folderpathindex[depthleft]-1] = '/';
-			folderpath[folderpathindex[depthleft]] = 0;
+			dirpath[dirpathindex[depthleft]-1] = '/';
+			dirpath[dirpathindex[depthleft]] = 0;
 		}
 		else
-		{
 			numlumps++;
-			(*nfiles)++;
-		}
 
-		if (numlumps == (UINT16_MAX-1))
+		// Failure: Too many files.
+		if (numlumps == UINT16_MAX)
+		{
+			(*nlmp) = UINT16_MAX;
+			failure = true;
 			break;
+		}
 	}
 
 	// Failure: No files have been found.
-	if (!(*nfiles))
+	if (!numlumps)
 	{
-		(*nfiles) = UINT16_MAX;
-		free(folderpathindex);
+		(*nlmp) = 0;
+		failure = true;
+	}
+
+	// Close any open directories and return if something went wrong.
+	if (failure)
+	{
+		free(dirpathindex);
 		free(dirhandle);
-		for (; depthleft < maxfolderdepth; closedir(dirhandle[depthleft++])); // Close any open directories.
+		for (; depthleft < maxdirdepth; closedir(dirhandle[depthleft++]));
 		return NULL;
 	}
 
 	// Create the files and directories as lump entries
 	// It's possible to create lumps and count files at the same time,
-	// but I didn't to constantly have to reallocate memory for every lump.
-	rewinddir(dirhandle[rootfolder]);
-	depthleft = rootfolder;
+	// but I didn't want to have to reallocate memory for every lump.
+	rewinddir(dirhandle[rootdir]);
+	depthleft = rootdir;
 
-	strlcpy(folderpath, path, folderpathlen);
-	initfolderpath(folderpath, folderpathindex, depthleft);
+	strlcpy(dirpath, path, dirpathlen);
+	initdirpath(dirpath, dirpathindex, depthleft);
 
 	lump_p = lumpinfo = Z_Calloc(numlumps * sizeof(lumpinfo_t), PU_STATIC, NULL);
 
-	while (depthleft < maxfolderdepth)
+	while (depthleft < maxdirdepth)
 	{
 		char *fullname, *trimname;
 
-		folderpath[folderpathindex[depthleft]] = 0;
+		dirpath[dirpathindex[depthleft]] = 0;
 		dent = readdir(dirhandle[depthleft]);
 
 		if (!dent)
@@ -697,29 +747,30 @@ lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT1
 		else if (isuptree(dent->d_name))
 			continue;
 
-		strcpy(&folderpath[folderpathindex[depthleft]], dent->d_name);
+		strcpy(&dirpath[dirpathindex[depthleft]], dent->d_name);
 
-		if (stat(folderpath, &fsstat) < 0)
+		if (stat(dirpath, &fsstat) < 0)
 			continue;
 		else if (S_ISDIR(fsstat.st_mode) && depthleft)
 		{
-			folderpathindex[--depthleft] = strlen(folderpath) + 1;
-			dirhandle[depthleft] = opendir(folderpath);
+			dirpathindex[--depthleft] = strlen(dirpath) + 1;
+			dirhandle[depthleft] = opendir(dirpath);
 
-			if (!dirhandle[depthleft])
+			if (dirhandle[depthleft])
 			{
-				depthleft++;
-				continue;
+				dirpath[dirpathindex[depthleft]-1] = '/';
+				dirpath[dirpathindex[depthleft]] = 0;
 			}
+			else
+				depthleft++;
 
-			folderpath[folderpathindex[depthleft]-1] = '/';
-			folderpath[folderpathindex[depthleft]] = 0;
+			continue;
 		}
 
-		lump_p->diskpath = Z_StrDup(folderpath); // Path in the filesystem to the file
+		lump_p->diskpath = Z_StrDup(dirpath); // Path in the filesystem to the file
 		lump_p->compression = CM_NOCOMPRESSION; // Lump is uncompressed
 
-		// Remove the folder path.
+		// Remove the directory's path.
 		fullname = lump_p->diskpath;
 		if (strstr(fullname, path))
 			fullname += strlen(path) + 1;
@@ -747,7 +798,7 @@ lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT1
 			lump_p->longname = Z_Calloc(1, PU_STATIC, NULL);
 
 		// The complete name of the file, with its extension,
-		// excluding the path of the folder where it resides.
+		// excluding the path of the directory where it resides.
 		lump_p->fullname = Z_StrDup(fullname);
 
 		lump_p++;
@@ -755,12 +806,12 @@ lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT1
 
 		if (i > numlumps || i == (UINT16_MAX-1))
 		{
-			for (; depthleft < maxfolderdepth; closedir(dirhandle[depthleft++])); // Close any open directories.
+			for (; depthleft < maxdirdepth; closedir(dirhandle[depthleft++])); // Close any open directories.
 			break;
 		}
 	}
 
-	free(folderpathindex);
+	free(dirpathindex);
 	free(dirhandle);
 
 	(*nlmp) = numlumps;
diff --git a/src/filesrch.h b/src/filesrch.h
index 92e3341f34675bd0ddb97ff3492a7daf6bba601a..e358d799356d99643aecaac6d39c56d2ac2906e3 100644
--- a/src/filesrch.h
+++ b/src/filesrch.h
@@ -29,11 +29,15 @@ extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_sh
 filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
 	boolean completepath, int maxsearchdepth);
 
-INT32 pathisfolder(const char *path);
-boolean checkfolderpath(const char *path, const char *startpath, boolean cleanup);
+INT32 pathisdirectory(const char *path);
 INT32 samepaths(const char *path1, const char *path2);
+boolean concatpaths(const char *path, const char *startpath);
 
-lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT16 *nfolders);
+#ifndef AVOID_ERRNO
+extern int direrror;
+#endif
+
+lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders);
 
 #define menudepth 20
 
diff --git a/src/m_misc.c b/src/m_misc.c
index 61f0f8a5b652a23154548d6112761e4d15ad8690..59783d5d30dc8d195d5b732d2de474833459f816 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -2694,7 +2694,7 @@ boolean M_IsStringEmpty(const char *s)
 {
 	const char *ch = s;
 
-	if (ch == NULL || (ch && strlen(ch) < 1))
+	if (s == NULL || s[0] == '\0')
 		return true;
 
 	for (;;ch++)
diff --git a/src/w_wad.c b/src/w_wad.c
index e37c86bacde53017c1618b49a0877466e27c4bc0..3ff301117bca03d03868e7dead7bb5fa03e44c2b 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -687,11 +687,67 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
 	return lumpinfo;
 }
 
+static INT32 CheckPathsNotEqual(const char *path1, const char *path2)
+{
+	INT32 stat = samepaths(path1, path2);
+
+	if (stat == 1)
+		return 0;
+	else if (stat < 0)
+		return -1;
+
+	return 1;
+}
+
+// Returns 1 if the path is valid, 0 if not, and -1 if there was an error.
+INT32 W_IsPathToFolderValid(const char *path)
+{
+	INT32 stat;
+
+	// Remove path delimiters.
+	const char *p = path + (strlen(path) - 1);
+	while (*p == '\\' || *p == '/' || *p == ':')
+	{
+		p--;
+		if (p < path)
+			return 0;
+	}
+
+	// Check if the path is a directory.
+	stat = pathisdirectory(path);
+	if (stat == 0)
+		return 0;
+	else if (stat < 0)
+	{
+		// The path doesn't exist, so it can't be a directory.
+		if (direrror == ENOENT)
+			return 0;
+
+		return -1;
+	}
+
+	// Don't add your home, you sodding tic tac.
+	stat = CheckPathsNotEqual(path, srb2home);
+	if (stat != 1)
+		return stat;
+
+	// Do the same checks for SRB2's path, and the current directory.
+	stat = CheckPathsNotEqual(path, srb2path);
+	if (stat != 1)
+		return stat;
+
+	stat = CheckPathsNotEqual(path, ".");
+	if (stat != 1)
+		return stat;
+
+	return 1;
+}
+
 // Checks if the combination of the first path and the second path are valid.
 // If they are, the concatenated path is returned.
-static char *W_CheckFolderPath(const char *startpath, const char *path)
+static char *CheckConcatFolderPath(const char *startpath, const char *path)
 {
-	if (checkfolderpath(path, startpath, false))
+	if (concatpaths(path, startpath) == 1)
 	{
 		char *fn;
 
@@ -710,23 +766,23 @@ static char *W_CheckFolderPath(const char *startpath, const char *path)
 	return NULL;
 }
 
-// Returns the first valid path for a folder.
-static char *W_GetFullFolderPath(const char *path)
+// Looks for the first valid full path for a folder.
+// Returns NULL if the folder doesn't exist, or it isn't valid.
+char *W_GetFullFolderPath(const char *path)
 {
 	// Check the path by itself first.
-	char *fn = W_CheckFolderPath(NULL, path);
+	char *fn = CheckConcatFolderPath(NULL, path);
 	if (fn)
 		return fn;
 
-#define checkpath(startpath) { \
-	fn = W_CheckFolderPath(startpath, path); \
+#define checkpath(startpath) \
+	fn = CheckConcatFolderPath(startpath, path); \
 	if (fn) \
-		return fn; \
-} \
+		return fn
 
-	checkpath(srb2home) // Then, look in srb2home.
-	checkpath(srb2path) // Now, look in srb2path.
-	checkpath(".") // Finally, look in ".".
+	checkpath(srb2home); // Then, look in srb2home.
+	checkpath(srb2path); // Now, look in srb2path.
+	checkpath("."); // Finally, look in the current directory.
 
 #undef checkpath
 
@@ -734,9 +790,9 @@ static char *W_GetFullFolderPath(const char *path)
 }
 
 // Loads files from a folder into a lumpinfo structure.
-static lumpinfo_t *ResGetLumpsFolder(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT16 *nfolders)
+static lumpinfo_t *ResGetLumpsFolder(const char *path, UINT16 *nlmp, UINT16 *nfolders)
 {
-	return getfolderfiles(path, nlmp, nfiles, nfolders);
+	return getdirectoryfiles(path, nlmp, nfolders);
 }
 
 static UINT16 W_InitFileError (const char *filename, boolean exitworthy)
@@ -908,7 +964,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
 	wadfile->type = type;
 	wadfile->handle = handle;
 	wadfile->numlumps = numlumps;
-	wadfile->filecount = wadfile->foldercount = 0;
+	wadfile->foldercount = 0;
 	wadfile->lumpinfo = lumpinfo;
 	wadfile->important = important;
 	fseek(handle, 0, SEEK_END);
@@ -966,11 +1022,12 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 	lumpinfo_t *lumpinfo = NULL;
 	wadfile_t *wadfile;
 	UINT16 numlumps = 0;
-	UINT16 filecount, foldercount;
+	UINT16 foldercount;
 	size_t i;
 	char *fn, *fullpath;
 	const char *p;
 	int important;
+	INT32 stat;
 
 	if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
 		refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier
@@ -1006,16 +1063,15 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 		packetsizetally = packetsize;
 	}
 
-	// Remove path separators from the filename, and don't try adding "/".
-	p = path+strlen(path);
-	--p;
+	// Remove path delimiters.
+	p = path + (strlen(path) - 1);
 
 	while (*p == '\\' || *p == '/' || *p == ':')
 	{
 		p--;
 		if (p < path)
 		{
-			CONS_Alert(CONS_ERROR, M_GetText("Path %s is prohibited\n"), path);
+			CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), path);
 			return W_InitFileError(path, startup);
 		}
 	}
@@ -1026,6 +1082,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 	fn = ZZ_Alloc(i);
 	strlcpy(fn, path, i);
 
+	// Don't add an empty path.
 	if (M_IsStringEmpty(fn))
 	{
 		CONS_Alert(CONS_ERROR, M_GetText("Folder name is empty\n"));
@@ -1037,14 +1094,36 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 			return W_InitFileError("a folder", false);
 	}
 
-	// Get the full path for this filename.
+	// Check if the path is valid.
+	stat = W_IsPathToFolderValid(fn);
+
+	if (stat != 1)
+	{
+		if (stat == 0)
+			CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn);
+		else if (stat < 0)
+		{
+#ifndef AVOID_ERRNO
+			CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s: %s\n"), fn, strerror(direrror));
+#else
+			CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s\n"), fn);
+#endif
+		}
+
+		Z_Free(fn);
+		return W_InitFileError(path, startup);
+	}
+
+	// Get the full path for this folder.
 	fullpath = W_GetFullFolderPath(fn);
 	if (fullpath == NULL)
 	{
+		CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn);
 		Z_Free(fn);
-		return W_InitFileError(path, false);
+		return W_InitFileError(path, startup);
 	}
 
+	// Check if the folder is already added.
 	for (i = 0; i < numwadfiles; i++)
 	{
 		if (wadfiles[i]->type != RET_FOLDER)
@@ -1061,11 +1140,16 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 		}
 	}
 
-	lumpinfo = ResGetLumpsFolder(fullpath, &numlumps, &filecount, &foldercount);
+	lumpinfo = ResGetLumpsFolder(fullpath, &numlumps, &foldercount);
+
 	if (lumpinfo == NULL)
 	{
-		if (filecount == UINT16_MAX)
+		if (!numlumps)
 			CONS_Alert(CONS_ERROR, M_GetText("Folder %s is empty\n"), path);
+		else if (numlumps == UINT16_MAX)
+			CONS_Alert(CONS_ERROR, M_GetText("Folder %s contains too many files\n"), path);
+		else
+			CONS_Alert(CONS_ERROR, M_GetText("Unknown error enumerating files from folder %s\n"), path);
 
 		Z_Free(fn);
 		Z_Free(fullpath);
@@ -1082,7 +1166,6 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 	wadfile->type = RET_FOLDER;
 	wadfile->handle = NULL;
 	wadfile->numlumps = numlumps;
-	wadfile->filecount = filecount;
 	wadfile->foldercount = foldercount;
 	wadfile->lumpinfo = lumpinfo;
 	wadfile->important = important;
@@ -1094,7 +1177,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
 	Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache);
 	Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache);
 
-	CONS_Printf(M_GetText("Added folder %s (%u files, %u folders)\n"), fn, filecount, foldercount);
+	CONS_Printf(M_GetText("Added folder %s (%u files, %u folders)\n"), fn, numlumps, foldercount);
 	wadfiles[numwadfiles] = wadfile;
 	numwadfiles++;
 
@@ -1506,12 +1589,24 @@ size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
 
 	l = wadfiles[wad]->lumpinfo + lump;
 
+	// Open the external file for this lump, if the WAD is a folder.
 	if (wadfiles[wad]->type == RET_FOLDER)
 	{
-		INT32 stat = pathisfolder(l->diskpath);
+		// pathisdirectory calls stat, so if anything wrong has happened,
+		// this is the time to be aware of it.
+		INT32 stat = pathisdirectory(l->diskpath);
 
 		if (stat < 0)
-			I_Error("W_LumpLengthPwad: could not stat %s", l->diskpath);
+		{
+#ifndef AVOID_ERRNO
+			if (direrror == ENOENT)
+				I_Error("W_LumpLengthPwad: file %s doesn't exist", l->diskpath);
+			else
+				I_Error("W_LumpLengthPwad: could not stat %s: %s", l->diskpath, strerror(direrror));
+#else
+			I_Error("W_LumpLengthPwad: could not access %s", l->diskpath);
+#endif
+		}
 		else if (stat == 1) // Path is a folder.
 			return 0;
 		else
@@ -1617,7 +1712,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
 	lumpinfo_t *l;
 	FILE *handle = NULL;
 
-	if (!TestValidLump(wad,lump))
+	if (!TestValidLump(wad, lump))
 		return 0;
 
 	l = wadfiles[wad]->lumpinfo + lump;
@@ -1625,10 +1720,21 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
 	// Open the external file for this lump, if the WAD is a folder.
 	if (wadfiles[wad]->type == RET_FOLDER)
 	{
-		INT32 stat = pathisfolder(l->diskpath);
+		// pathisdirectory calls stat, so if anything wrong has happened,
+		// this is the time to be aware of it.
+		INT32 stat = pathisdirectory(l->diskpath);
 
 		if (stat < 0)
-			I_Error("W_ReadLumpHeaderPwad: could not stat %s", l->diskpath);
+		{
+#ifndef AVOID_ERRNO
+			if (direrror == ENOENT)
+				I_Error("W_ReadLumpHeaderPwad: file %s doesn't exist", l->diskpath);
+			else
+				I_Error("W_ReadLumpHeaderPwad: could not stat %s: %s", l->diskpath, strerror(direrror));
+#else
+			I_Error("W_ReadLumpHeaderPwad: could not access %s", l->diskpath);
+#endif
+		}
 		else if (stat == 1) // Path is a folder.
 			return 0;
 		else
diff --git a/src/w_wad.h b/src/w_wad.h
index 25b4bffa8399eae0e6fd908b4b7c2515c35bd505..3958f7faff311da87b0d22ca320c39a8ae88f9cb 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -122,7 +122,7 @@ typedef struct wadfile_s
 	lumpcache_t *lumpcache;
 	lumpcache_t *patchcache;
 	UINT16 numlumps; // this wad's number of resources
-	UINT16 filecount, foldercount; // file and folder count
+	UINT16 foldercount; // folder count
 	FILE *handle;
 	UINT32 filesize; // for network
 	UINT8 md5sum[16];
@@ -152,6 +152,9 @@ void W_InitMultipleFiles(char **filenames);
 
 #define W_FileHasFolders(wadfile) ((wadfile)->type == RET_PK3 || (wadfile)->type == RET_FOLDER)
 
+boolean W_IsPathToFolderValid(const char *path);
+char *W_GetFullFolderPath(const char *path);
+
 const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
 const char *W_CheckNameForNum(lumpnum_t lumpnum);