mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-05 17:36:25 +00:00
filesystem: SDL_EnumerateDirectory() gives dirs with path seperators appended.
Fixes #11065. Fixes #11427.
This commit is contained in:
@@ -313,6 +313,9 @@ typedef enum SDL_EnumerationResult
|
||||
* terminate the enumeration early, and dictate the return value of the
|
||||
* enumeration function itself.
|
||||
*
|
||||
* `dirname` is guaranteed to end with a path separator ('\\' on
|
||||
* Windows, '/' on most other platforms).
|
||||
*
|
||||
* \param userdata an app-controlled pointer that is passed to the callback.
|
||||
* \param dirname the directory that is being enumerated.
|
||||
* \param fname the next entry in the enumeration.
|
||||
|
@@ -307,7 +307,7 @@ static SDL_EnumerationResult SDLCALL GlobDirectoryCallback(void *userdata, const
|
||||
// !!! FIXME: and only casefold the new pieces instead of allocating and folding full paths for all of this.
|
||||
|
||||
char *fullpath = NULL;
|
||||
if (SDL_asprintf(&fullpath, "%s/%s", dirname, fname) < 0) {
|
||||
if (SDL_asprintf(&fullpath, "%s%s", dirname, fname) < 0) {
|
||||
return SDL_ENUM_FAILURE;
|
||||
}
|
||||
|
||||
@@ -417,7 +417,8 @@ char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_Glob
|
||||
data.enumerator = enumerator;
|
||||
data.getpathinfo = getpathinfo;
|
||||
data.fsuserdata = userdata;
|
||||
data.basedirlen = SDL_strlen(path) + 1; // +1 for the '/' we'll be adding.
|
||||
data.basedirlen = *path ? (SDL_strlen(path) + 1) : 0; // +1 for the '/' we'll be adding.
|
||||
|
||||
|
||||
char **result = NULL;
|
||||
if (data.enumerator(path, GlobDirectoryCallback, &data, data.fsuserdata)) {
|
||||
|
@@ -37,25 +37,42 @@
|
||||
|
||||
bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback cb, void *userdata)
|
||||
{
|
||||
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
||||
char *pathwithsep = NULL;
|
||||
int pathwithseplen = SDL_asprintf(&pathwithsep, "%s/", path);
|
||||
if ((pathwithseplen == -1) || (!pathwithsep)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DIR *dir = opendir(path);
|
||||
// trim down to a single path separator at the end, in case the caller added one or more.
|
||||
pathwithseplen--;
|
||||
while ((pathwithseplen >= 0) && (pathwithsep[pathwithseplen] == '/')) {
|
||||
pathwithsep[pathwithseplen--] = '\0';
|
||||
}
|
||||
|
||||
DIR *dir = opendir(pathwithsep);
|
||||
if (!dir) {
|
||||
SDL_free(pathwithsep);
|
||||
return SDL_SetError("Can't open directory: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// make sure there's a path separator at the end now for the actual callback.
|
||||
pathwithsep[++pathwithseplen] = '/';
|
||||
pathwithsep[++pathwithseplen] = '\0';
|
||||
|
||||
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
||||
struct dirent *ent;
|
||||
while ((result == SDL_ENUM_CONTINUE) && ((ent = readdir(dir)) != NULL))
|
||||
{
|
||||
while ((result == SDL_ENUM_CONTINUE) && ((ent = readdir(dir)) != NULL)) {
|
||||
const char *name = ent->d_name;
|
||||
if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) {
|
||||
continue;
|
||||
}
|
||||
result = cb(userdata, path, name);
|
||||
result = cb(userdata, pathwithsep, name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
SDL_free(pathwithsep);
|
||||
|
||||
return (result != SDL_ENUM_FAILURE);
|
||||
}
|
||||
|
||||
|
@@ -34,35 +34,45 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
|
||||
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
||||
if (*path == '\0') { // if empty (completely at the root), we need to enumerate drive letters.
|
||||
const DWORD drives = GetLogicalDrives();
|
||||
char name[3] = { 0, ':', '\0' };
|
||||
char name[] = { 0, ':', '\\', '\0' };
|
||||
for (int i = 'A'; (result == SDL_ENUM_CONTINUE) && (i <= 'Z'); i++) {
|
||||
if (drives & (1 << (i - 'A'))) {
|
||||
name[0] = (char) i;
|
||||
result = cb(userdata, path, name);
|
||||
result = cb(userdata, "", name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const size_t patternlen = SDL_strlen(path) + 3;
|
||||
char *pattern = (char *) SDL_malloc(patternlen);
|
||||
if (!pattern) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// you need a wildcard to enumerate through FindFirstFileEx(), but the wildcard is only checked in the
|
||||
// filename element at the end of the path string, so always tack on a "\\*" to get everything, and
|
||||
// also prevent any wildcards inserted by the app from being respected.
|
||||
SDL_snprintf(pattern, patternlen, "%s\\*", path);
|
||||
|
||||
WCHAR *wpattern = WIN_UTF8ToStringW(pattern);
|
||||
SDL_free(pattern);
|
||||
if (!wpattern) {
|
||||
char *pattern = NULL;
|
||||
int patternlen = SDL_asprintf(&pattern, "%s\\\\", path); // we'll replace that second '\\' in the trimdown.
|
||||
if ((patternlen == -1) || (!pattern)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// trim down to a single path separator at the end, in case the caller added one or more.
|
||||
patternlen--;
|
||||
while ((patternlen >= 0) && ((pattern[patternlen] == '\\') || (pattern[patternlen] == '/'))) {
|
||||
pattern[patternlen--] ='\0';
|
||||
}
|
||||
pattern[++patternlen] = '\\';
|
||||
pattern[++patternlen] = '*';
|
||||
pattern[++patternlen] = '\0';
|
||||
|
||||
WCHAR *wpattern = WIN_UTF8ToStringW(pattern);
|
||||
if (!wpattern) {
|
||||
SDL_free(pattern);
|
||||
return false;
|
||||
}
|
||||
|
||||
pattern[--patternlen] = '\0'; // chop off the '*' so we just have the dirname with a path separator.
|
||||
|
||||
WIN32_FIND_DATAW entw;
|
||||
HANDLE dir = FindFirstFileExW(wpattern, FindExInfoStandard, &entw, FindExSearchNameMatch, NULL, 0);
|
||||
SDL_free(wpattern);
|
||||
if (dir == INVALID_HANDLE_VALUE) {
|
||||
SDL_free(pattern);
|
||||
return WIN_SetError("Failed to enumerate directory");
|
||||
}
|
||||
|
||||
@@ -79,12 +89,13 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
|
||||
if (!utf8fn) {
|
||||
result = SDL_ENUM_FAILURE;
|
||||
} else {
|
||||
result = cb(userdata, path, utf8fn);
|
||||
result = cb(userdata, pattern, utf8fn);
|
||||
SDL_free(utf8fn);
|
||||
}
|
||||
} while ((result == SDL_ENUM_CONTINUE) && (FindNextFileW(dir, &entw) != 0));
|
||||
|
||||
FindClose(dir);
|
||||
SDL_free(pattern);
|
||||
}
|
||||
|
||||
return (result != SDL_ENUM_FAILURE);
|
||||
|
@@ -20,14 +20,7 @@ static SDL_EnumerationResult SDLCALL enum_callback(void *userdata, const char *o
|
||||
SDL_PathInfo info;
|
||||
char *fullpath = NULL;
|
||||
|
||||
/* you can use '/' for a path separator on Windows, but to make the log output look correct, we'll #ifdef this... */
|
||||
#ifdef SDL_PLATFORM_WINDOWS
|
||||
const char *pathsep = "\\";
|
||||
#else
|
||||
const char *pathsep = "/";
|
||||
#endif
|
||||
|
||||
if (SDL_asprintf(&fullpath, "%s%s%s", origdir, *origdir ? pathsep : "", fname) < 0) {
|
||||
if (SDL_asprintf(&fullpath, "%s%s", origdir, fname) < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
|
||||
return SDL_ENUM_FAILURE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user