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)
{
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);

View file

@ -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

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
}
// 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

View file

@ -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)
{
char folderpath[folderpathlen], basepath[folderpathlen], *fn = NULL;
DIR *dirhandle;
#ifndef AVOID_ERRNO
int direrror = 0;
#endif
// Remove path separators from the filename, and don't try adding "/".
// See also the same code in W_InitFolder.
if (cleanup)
{
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)
// 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)
{
struct stat fsstat;
if (stat(path, &fsstat) < 0)
{
#ifndef AVOID_ERRNO
direrror = errno;
#endif
return -1;
}
else if (S_ISDIR(fsstat.st_mode))
return 1;
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)
{
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;
}
if (file1 != INVALID_HANDLE_VALUE)
// 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);
if (file2 != INVALID_HANDLE_VALUE)
CloseHandle(file2);
#ifndef AVOID_ERRNO
direrror = EIO;
#endif
return -2;
}
return ok;
if (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber
&& file1info.nFileIndexLow == file2info.nFileIndexLow
&& file1info.nFileIndexHigh == file2info.nFileIndexHigh)
{
CloseHandle(file1);
CloseHandle(file2);
return 1;
}
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;
dirhandle = (DIR **)malloc(maxfolderdepth * sizeof (DIR*));
folderpathindex = (size_t *)malloc(maxfolderdepth * sizeof(size_t));
boolean failure = false;
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;

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,
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

View file

@ -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++)

View file

@ -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

View file

@ -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);