Merge branch 'folder-fixes' into 'next'

Fix minor issues with folder addons

See merge request STJr/SRB2!1617
This commit is contained in:
Tatsuru 2021-09-12 21:08:07 +00:00
commit df249a4a4d
8 changed files with 405 additions and 188 deletions

View file

@ -944,13 +944,13 @@ static void D_AddFile(char **list, const char *file)
static void D_AddFolder(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; char *newfile;
for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) 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) if (!newfile)
I_Error("No more free memory to AddFolder %s",file); I_Error("No more free memory to AddFolder %s",file);

View file

@ -3416,9 +3416,10 @@ static void Command_Addfolder(void)
for (curarg = 1; curarg < argc; curarg++) for (curarg = 1; curarg < argc; curarg++)
{ {
const char *fn, *p; const char *fn, *p;
char *fullpath;
char buf[256]; char buf[256];
char *buf_p = buf; char *buf_p = buf;
INT32 i; INT32 i, stat;
size_t ii; size_t ii;
boolean folderadded = false; boolean folderadded = false;
@ -3461,6 +3462,13 @@ static void Command_Addfolder(void)
break; break;
++p; ++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 // check total packet size and no of files currently loaded
// See W_InitFile in w_wad.c // See W_InitFile in w_wad.c
if ((numwadfiles >= MAX_WADFILES) if ((numwadfiles >= MAX_WADFILES)
@ -3470,10 +3478,52 @@ static void Command_Addfolder(void)
return; 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; addedfolders[numfoldersadded++] = fn;
WRITESTRINGN(buf_p,p,240);
if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file
SendNetXCmd(XD_REQADDFOLDER, buf, buf_p - buf); SendNetXCmd(XD_REQADDFOLDER, buf, buf_p - buf);
else else

View file

@ -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 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) filestatus_t findfolder(const char *path)
{ {
// Check the path by itself first. // Check the path by itself first.
if (checkfolderpath(path, NULL, true)) if (concatpaths(path, NULL) == 1)
return FS_FOUND; return FS_FOUND;
#define checkpath(startpath) { \ #define checkpath(startpath) \
if (checkfolderpath(path, startpath, true)) \ if (concatpaths(path, startpath) == 1) \
return FS_FOUND; \ return FS_FOUND
}
checkpath(srb2home) // Then, look in srb2home. checkpath(srb2home); // Then, look in srb2home.
checkpath(srb2path) // Now, look in srb2path. checkpath(srb2path); // Now, look in srb2path.
checkpath(".") // Finally, look in ".". checkpath("."); // Finally, look in the current directory.
#undef checkpath #undef checkpath

View file

@ -341,8 +341,8 @@ char *refreshdirname = NULL;
size_t packetsizetally = 0; size_t packetsizetally = 0;
size_t mainwadstally = 0; size_t mainwadstally = 0;
#define folderpathlen 1024 #define dirpathlen 1024
#define maxfolderdepth 48 #define maxdirdepth 48
#define isuptree(dirent) ((dirent)[0]=='.' && ((dirent)[1]=='\0' || ((dirent)[1]=='.' && (dirent)[2]=='\0'))) #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; return retval;
} }
// Called from findfolder and ResGetLumpsFolder in w_wad.c. #ifndef AVOID_ERRNO
// Call with cleanup true if the path has to be verified. int direrror = 0;
boolean checkfolderpath(const char *path, const char *startpath, boolean cleanup) #endif
{
char folderpath[folderpathlen], basepath[folderpathlen], *fn = NULL;
DIR *dirhandle;
// Remove path separators from the filename, and don't try adding "/". // Checks if the specified path is a directory.
// See also the same code in W_InitFolder. // Returns 1 if so, 0 if not, and -1 if an error occurred.
if (cleanup) // direrror is set if there was an error.
{ INT32 pathisdirectory(const char *path)
const char *p = path + strlen(path);
size_t len;
--p;
while (*p == '\\' || *p == '/' || *p == ':')
{
p--;
if (p < path)
return false;
}
++p;
// Allocate the new path name.
len = (p - path) + 1;
fn = ZZ_Alloc(len);
strlcpy(fn, path, len);
}
if (startpath)
{
snprintf(basepath, sizeof basepath, "%s" PATHSEP, startpath);
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);
// Home path and folder path are the same? Not valid.
if (!strcmp(basepath, folderpath))
return false;
}
else if (cleanup)
{
snprintf(folderpath, sizeof folderpath, "%s", fn);
Z_Free(fn); // Don't need this anymore.
}
else
snprintf(folderpath, sizeof folderpath, "%s", path);
dirhandle = opendir(folderpath);
if (dirhandle == NULL)
return false;
else
closedir(dirhandle);
return true;
}
INT32 pathisfolder(const char *path)
{ {
struct stat fsstat; struct stat fsstat;
if (stat(path, &fsstat) < 0) if (stat(path, &fsstat) < 0)
{
#ifndef AVOID_ERRNO
direrror = errno;
#endif
return -1; return -1;
}
else if (S_ISDIR(fsstat.st_mode)) else if (S_ISDIR(fsstat.st_mode))
return 1; return 1;
return 0; return 0;
} }
// 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);
// Base path and directory path are the same? Not valid.
stat = samepaths(basepath, dirpath);
if (stat == 1)
return 0;
else if (stat < 0)
return -1;
}
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)
{
// The path doesn't exist, so it can't be a directory.
if (direrror == ENOENT)
return 0;
return -1;
}
// Open the directory.
// Will return 0 if it couldn't be opened.
dirhandle = opendir(dirpath);
if (dirhandle == NULL)
return 0;
else
closedir(dirhandle);
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) INT32 samepaths(const char *path1, const char *path2)
{ {
struct stat stat1; struct stat stat1;
struct stat stat2; struct stat stat2;
if (stat(path1, &stat1) < 0) if (stat(path1, &stat1) < 0)
{
#ifndef AVOID_ERRNO
direrror = errno;
#endif
return -1; return -1;
}
if (stat(path2, &stat2) < 0) if (stat(path2, &stat2) < 0)
return -1; {
#ifndef AVOID_ERRNO
direrror = errno;
#endif
return -2;
}
if (stat1.st_dev == stat2.st_dev) if (stat1.st_dev == stat2.st_dev)
{ {
#if !defined(_WIN32) #if !defined(_WIN32)
return (stat1.st_ino == stat2.st_ino); return (stat1.st_ino == stat2.st_ino);
#else #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 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); HANDLE file2 = CreateFileA(path2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
BY_HANDLE_FILE_INFORMATION file1info, file2info; 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)) #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 (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber if (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber
&& file1info.nFileIndexLow == file2info.nFileIndexLow && file1info.nFileIndexLow == file2info.nFileIndexLow
&& file1info.nFileIndexHigh == file2info.nFileIndexHigh) && file1info.nFileIndexHigh == file2info.nFileIndexHigh)
ok = true; {
}
}
if (file1 != INVALID_HANDLE_VALUE)
CloseHandle(file1); CloseHandle(file1);
if (file2 != INVALID_HANDLE_VALUE)
CloseHandle(file2); CloseHandle(file2);
return 1;
}
return ok; return 0;
#endif #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]; dirpath[dirpathindex[depthleft]-1] = PATHSEP[0];
folderpath[folderpathindex[depthleft]] = 0; dirpath[dirpathindex[depthleft]] = 0;
} }
else 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; DIR **dirhandle;
struct dirent *dent; struct dirent *dent;
struct stat fsstat; struct stat fsstat;
int rootfolder = (maxfolderdepth - 1); int rootdir = (maxdirdepth - 1);
int depthleft = rootfolder; int depthleft = rootdir;
char folderpath[folderpathlen]; char dirpath[dirpathlen];
size_t *folderpathindex; size_t *dirpathindex;
lumpinfo_t *lumpinfo, *lump_p; lumpinfo_t *lumpinfo, *lump_p;
UINT16 i = 0, numlumps = (*nlmp); UINT16 i = 0, numlumps = 0;
dirhandle = (DIR **)malloc(maxfolderdepth * sizeof (DIR*)); boolean failure = false;
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 // Open the root directory
strlcpy(folderpath, path, folderpathlen); strlcpy(dirpath, path, dirpathlen);
dirhandle[depthleft] = opendir(folderpath); dirhandle[depthleft] = opendir(dirpath);
if (dirhandle[depthleft] == NULL) if (dirhandle[depthleft] == NULL)
{ {
free(dirhandle); free(dirhandle);
free(folderpathindex); free(dirpathindex);
return NULL; return NULL;
} }
initfolderpath(folderpath, folderpathindex, depthleft); initdirpath(dirpath, dirpathindex, depthleft);
(*nfiles) = 0;
(*nfolders) = 0; (*nfolders) = 0;
// Count files and directories // Count files and directories
while (depthleft < maxfolderdepth) while (depthleft < maxdirdepth)
{ {
folderpath[folderpathindex[depthleft]] = 0; dirpath[dirpathindex[depthleft]] = 0;
dent = readdir(dirhandle[depthleft]); dent = readdir(dirhandle[depthleft]);
if (!dent) if (!dent)
{ {
if (depthleft != rootfolder) // Don't close the root directory if (depthleft != rootdir) // Don't close the root directory
closedir(dirhandle[depthleft]); closedir(dirhandle[depthleft]);
depthleft++; depthleft++;
continue; continue;
@ -631,62 +676,67 @@ lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT1
else if (isuptree(dent->d_name)) else if (isuptree(dent->d_name))
continue; 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) else if (S_ISDIR(fsstat.st_mode) && depthleft)
{ {
folderpathindex[--depthleft] = strlen(folderpath) + 1; dirpathindex[--depthleft] = strlen(dirpath) + 1;
dirhandle[depthleft] = opendir(folderpath); dirhandle[depthleft] = opendir(dirpath);
if (dirhandle[depthleft]) if (dirhandle[depthleft])
{
numlumps++;
(*nfolders)++; (*nfolders)++;
}
else else
depthleft++; depthleft++;
folderpath[folderpathindex[depthleft]-1] = '/'; dirpath[dirpathindex[depthleft]-1] = '/';
folderpath[folderpathindex[depthleft]] = 0; dirpath[dirpathindex[depthleft]] = 0;
} }
else else
{
numlumps++; numlumps++;
(*nfiles)++;
}
if (numlumps == (UINT16_MAX-1)) // Failure: Too many files.
if (numlumps == UINT16_MAX)
{
(*nlmp) = UINT16_MAX;
failure = true;
break; break;
} }
}
// Failure: No files have been found. // Failure: No files have been found.
if (!(*nfiles)) if (!numlumps)
{ {
(*nfiles) = UINT16_MAX; (*nlmp) = 0;
free(folderpathindex); failure = true;
}
// Close any open directories and return if something went wrong.
if (failure)
{
free(dirpathindex);
free(dirhandle); free(dirhandle);
for (; depthleft < maxfolderdepth; closedir(dirhandle[depthleft++])); // Close any open directories. for (; depthleft < maxdirdepth; closedir(dirhandle[depthleft++]));
return NULL; return NULL;
} }
// Create the files and directories as lump entries // Create the files and directories as lump entries
// It's possible to create lumps and count files at the same time, // 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. // but I didn't want to have to reallocate memory for every lump.
rewinddir(dirhandle[rootfolder]); rewinddir(dirhandle[rootdir]);
depthleft = rootfolder; depthleft = rootdir;
strlcpy(folderpath, path, folderpathlen); strlcpy(dirpath, path, dirpathlen);
initfolderpath(folderpath, folderpathindex, depthleft); initdirpath(dirpath, dirpathindex, depthleft);
lump_p = lumpinfo = Z_Calloc(numlumps * sizeof(lumpinfo_t), PU_STATIC, NULL); lump_p = lumpinfo = Z_Calloc(numlumps * sizeof(lumpinfo_t), PU_STATIC, NULL);
while (depthleft < maxfolderdepth) while (depthleft < maxdirdepth)
{ {
char *fullname, *trimname; char *fullname, *trimname;
folderpath[folderpathindex[depthleft]] = 0; dirpath[dirpathindex[depthleft]] = 0;
dent = readdir(dirhandle[depthleft]); dent = readdir(dirhandle[depthleft]);
if (!dent) if (!dent)
@ -697,29 +747,30 @@ lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT1
else if (isuptree(dent->d_name)) else if (isuptree(dent->d_name))
continue; 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; continue;
else if (S_ISDIR(fsstat.st_mode) && depthleft) else if (S_ISDIR(fsstat.st_mode) && depthleft)
{ {
folderpathindex[--depthleft] = strlen(folderpath) + 1; dirpathindex[--depthleft] = strlen(dirpath) + 1;
dirhandle[depthleft] = opendir(folderpath); dirhandle[depthleft] = opendir(dirpath);
if (!dirhandle[depthleft]) if (dirhandle[depthleft])
{ {
dirpath[dirpathindex[depthleft]-1] = '/';
dirpath[dirpathindex[depthleft]] = 0;
}
else
depthleft++; depthleft++;
continue; continue;
} }
folderpath[folderpathindex[depthleft]-1] = '/'; lump_p->diskpath = Z_StrDup(dirpath); // Path in the filesystem to the file
folderpath[folderpathindex[depthleft]] = 0;
}
lump_p->diskpath = Z_StrDup(folderpath); // Path in the filesystem to the file
lump_p->compression = CM_NOCOMPRESSION; // Lump is uncompressed lump_p->compression = CM_NOCOMPRESSION; // Lump is uncompressed
// Remove the folder path. // Remove the directory's path.
fullname = lump_p->diskpath; fullname = lump_p->diskpath;
if (strstr(fullname, path)) if (strstr(fullname, path))
fullname += strlen(path) + 1; 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); lump_p->longname = Z_Calloc(1, PU_STATIC, NULL);
// The complete name of the file, with its extension, // 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->fullname = Z_StrDup(fullname);
lump_p++; lump_p++;
@ -755,12 +806,12 @@ lumpinfo_t *getfolderfiles(const char *path, UINT16 *nlmp, UINT16 *nfiles, UINT1
if (i > numlumps || i == (UINT16_MAX-1)) 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; break;
} }
} }
free(folderpathindex); free(dirpathindex);
free(dirhandle); free(dirhandle);
(*nlmp) = numlumps; (*nlmp) = numlumps;

View file

@ -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, filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum,
boolean completepath, int maxsearchdepth); boolean completepath, int maxsearchdepth);
INT32 pathisfolder(const char *path); INT32 pathisdirectory(const char *path);
boolean checkfolderpath(const char *path, const char *startpath, boolean cleanup);
INT32 samepaths(const char *path1, const char *path2); 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 #define menudepth 20

View file

@ -2694,7 +2694,7 @@ boolean M_IsStringEmpty(const char *s)
{ {
const char *ch = s; const char *ch = s;
if (ch == NULL || (ch && strlen(ch) < 1)) if (s == NULL || s[0] == '\0')
return true; return true;
for (;;ch++) for (;;ch++)

View file

@ -687,11 +687,67 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
return lumpinfo; 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. // Checks if the combination of the first path and the second path are valid.
// If they are, the concatenated path is returned. // 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; char *fn;
@ -710,23 +766,23 @@ static char *W_CheckFolderPath(const char *startpath, const char *path)
return NULL; return NULL;
} }
// Returns the first valid path for a folder. // Looks for the first valid full path for a folder.
static char *W_GetFullFolderPath(const char *path) // 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. // Check the path by itself first.
char *fn = W_CheckFolderPath(NULL, path); char *fn = CheckConcatFolderPath(NULL, path);
if (fn) if (fn)
return fn; return fn;
#define checkpath(startpath) { \ #define checkpath(startpath) \
fn = W_CheckFolderPath(startpath, path); \ fn = CheckConcatFolderPath(startpath, path); \
if (fn) \ if (fn) \
return fn; \ return fn
} \
checkpath(srb2home) // Then, look in srb2home. checkpath(srb2home); // Then, look in srb2home.
checkpath(srb2path) // Now, look in srb2path. checkpath(srb2path); // Now, look in srb2path.
checkpath(".") // Finally, look in ".". checkpath("."); // Finally, look in the current directory.
#undef checkpath #undef checkpath
@ -734,9 +790,9 @@ static char *W_GetFullFolderPath(const char *path)
} }
// Loads files from a folder into a lumpinfo structure. // 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) 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->type = type;
wadfile->handle = handle; wadfile->handle = handle;
wadfile->numlumps = numlumps; wadfile->numlumps = numlumps;
wadfile->filecount = wadfile->foldercount = 0; wadfile->foldercount = 0;
wadfile->lumpinfo = lumpinfo; wadfile->lumpinfo = lumpinfo;
wadfile->important = important; wadfile->important = important;
fseek(handle, 0, SEEK_END); fseek(handle, 0, SEEK_END);
@ -966,11 +1022,12 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
lumpinfo_t *lumpinfo = NULL; lumpinfo_t *lumpinfo = NULL;
wadfile_t *wadfile; wadfile_t *wadfile;
UINT16 numlumps = 0; UINT16 numlumps = 0;
UINT16 filecount, foldercount; UINT16 foldercount;
size_t i; size_t i;
char *fn, *fullpath; char *fn, *fullpath;
const char *p; const char *p;
int important; int important;
INT32 stat;
if (!(refreshdirmenu & REFRESHDIR_ADDFILE)) if (!(refreshdirmenu & REFRESHDIR_ADDFILE))
refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier 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; packetsizetally = packetsize;
} }
// Remove path separators from the filename, and don't try adding "/". // Remove path delimiters.
p = path+strlen(path); p = path + (strlen(path) - 1);
--p;
while (*p == '\\' || *p == '/' || *p == ':') while (*p == '\\' || *p == '/' || *p == ':')
{ {
p--; p--;
if (p < path) 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); return W_InitFileError(path, startup);
} }
} }
@ -1026,6 +1082,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
fn = ZZ_Alloc(i); fn = ZZ_Alloc(i);
strlcpy(fn, path, i); strlcpy(fn, path, i);
// Don't add an empty path.
if (M_IsStringEmpty(fn)) if (M_IsStringEmpty(fn))
{ {
CONS_Alert(CONS_ERROR, M_GetText("Folder name is empty\n")); 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); 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); fullpath = W_GetFullFolderPath(fn);
if (fullpath == NULL) if (fullpath == NULL)
{ {
CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn);
Z_Free(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++) for (i = 0; i < numwadfiles; i++)
{ {
if (wadfiles[i]->type != RET_FOLDER) 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 (lumpinfo == NULL)
{ {
if (filecount == UINT16_MAX) if (!numlumps)
CONS_Alert(CONS_ERROR, M_GetText("Folder %s is empty\n"), path); 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(fn);
Z_Free(fullpath); Z_Free(fullpath);
@ -1082,7 +1166,6 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup)
wadfile->type = RET_FOLDER; wadfile->type = RET_FOLDER;
wadfile->handle = NULL; wadfile->handle = NULL;
wadfile->numlumps = numlumps; wadfile->numlumps = numlumps;
wadfile->filecount = filecount;
wadfile->foldercount = foldercount; wadfile->foldercount = foldercount;
wadfile->lumpinfo = lumpinfo; wadfile->lumpinfo = lumpinfo;
wadfile->important = important; 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->lumpcache), PU_STATIC, &wadfile->lumpcache);
Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); 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; wadfiles[numwadfiles] = wadfile;
numwadfiles++; numwadfiles++;
@ -1506,12 +1589,24 @@ size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
l = wadfiles[wad]->lumpinfo + 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) 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) 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. else if (stat == 1) // Path is a folder.
return 0; return 0;
else else
@ -1617,7 +1712,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
lumpinfo_t *l; lumpinfo_t *l;
FILE *handle = NULL; FILE *handle = NULL;
if (!TestValidLump(wad,lump)) if (!TestValidLump(wad, lump))
return 0; return 0;
l = wadfiles[wad]->lumpinfo + lump; 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. // Open the external file for this lump, if the WAD is a folder.
if (wadfiles[wad]->type == RET_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) 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. else if (stat == 1) // Path is a folder.
return 0; return 0;
else else

View file

@ -122,7 +122,7 @@ typedef struct wadfile_s
lumpcache_t *lumpcache; lumpcache_t *lumpcache;
lumpcache_t *patchcache; lumpcache_t *patchcache;
UINT16 numlumps; // this wad's number of resources UINT16 numlumps; // this wad's number of resources
UINT16 filecount, foldercount; // file and folder count UINT16 foldercount; // folder count
FILE *handle; FILE *handle;
UINT32 filesize; // for network UINT32 filesize; // for network
UINT8 md5sum[16]; UINT8 md5sum[16];
@ -152,6 +152,9 @@ void W_InitMultipleFiles(char **filenames);
#define W_FileHasFolders(wadfile) ((wadfile)->type == RET_PK3 || (wadfile)->type == RET_FOLDER) #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_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum); const char *W_CheckNameForNum(lumpnum_t lumpnum);