mirror of
https://github.com/AltraMayor/f3.git
synced 2025-08-03 18:46:00 -04:00
f3read/f3write: avoid the execution stack to list files
For large number of files, the original, recursive version of __ls_my_files() triggers a stack overflow; see issue #153 for an example. This patch replaces __ls_my_files() with a version that replaces the recursion with two scans of the target folder.
This commit is contained in:
parent
46a509578f
commit
7c5d6b7894
105
utils.c
105
utils.c
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -76,40 +77,77 @@ static long number_from_filename(const char *filename)
|
|||||||
return num - 1;
|
return num - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't call this function directly, use ls_my_files() instead. */
|
static inline bool include_this_file(const char *filename,
|
||||||
static long *__ls_my_files(DIR *dir, long start_at, long end_at,
|
long start_at, long end_at, long *number)
|
||||||
int *pcount, int *pindex)
|
|
||||||
{
|
{
|
||||||
struct dirent *entry;
|
if (!is_my_file(filename))
|
||||||
const char *filename;
|
return false;
|
||||||
long number, *ret;
|
|
||||||
int my_index;
|
|
||||||
|
|
||||||
entry = readdir(dir);
|
*number = number_from_filename(filename);
|
||||||
if (!entry) {
|
|
||||||
ret = malloc(sizeof(long) * (*pcount + 1));
|
return start_at <= *number && *number <= end_at;
|
||||||
assert(ret);
|
|
||||||
*pindex = *pcount - 1;
|
|
||||||
ret[*pcount] = -1;
|
|
||||||
closedir(dir);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = entry->d_name;
|
static long count_files(const char *path, long start_at, long end_at)
|
||||||
if (!is_my_file(filename))
|
{
|
||||||
return __ls_my_files(dir, start_at, end_at, pcount, pindex);
|
DIR *dir = opendir(path);
|
||||||
|
struct dirent *entry;
|
||||||
|
long dummy, total = 0;
|
||||||
|
|
||||||
/* Cache @number because @entry may go away. */
|
if (!dir)
|
||||||
number = number_from_filename(filename);
|
err(errno, "Can't open path %s at %s()", path, __func__);
|
||||||
|
|
||||||
/* Ignore files before @start_at and after @end_at. */
|
entry = readdir(dir);
|
||||||
if (number < start_at || end_at < number)
|
while (entry) {
|
||||||
return __ls_my_files(dir, start_at, end_at, pcount, pindex);
|
if (include_this_file(entry->d_name, start_at, end_at, &dummy))
|
||||||
|
total++;
|
||||||
|
entry = readdir(dir);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
(*pcount)++;
|
return total;
|
||||||
ret = __ls_my_files(dir, start_at, end_at, pcount, &my_index);
|
}
|
||||||
ret[my_index] = number;
|
|
||||||
*pindex = my_index - 1;
|
/* Don't call this function directly, use ls_my_files() instead. */
|
||||||
|
static long *__ls_my_files(const char *path, long start_at, long end_at,
|
||||||
|
long *pcount)
|
||||||
|
{
|
||||||
|
long total_files = count_files(path, start_at, end_at);
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
long *ret, index;
|
||||||
|
|
||||||
|
assert(total_files >= 0);
|
||||||
|
ret = malloc(sizeof(*ret) * (total_files + 1));
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir)
|
||||||
|
err(errno, "Can't open path %s at %s()", path, __func__);
|
||||||
|
|
||||||
|
entry = readdir(dir);
|
||||||
|
index = 0;
|
||||||
|
while (entry) {
|
||||||
|
long number;
|
||||||
|
if (include_this_file(entry->d_name, start_at, end_at,
|
||||||
|
&number)) {
|
||||||
|
if (index >= total_files) {
|
||||||
|
/* The folder @path received more files
|
||||||
|
* before we finished scanning it.
|
||||||
|
*/
|
||||||
|
closedir(dir);
|
||||||
|
free(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ret[index++] = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = readdir(dir);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
ret[index] = -1;
|
||||||
|
*pcount = index;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,17 +159,12 @@ static int cmpintp(const void *p1, const void *p2)
|
|||||||
|
|
||||||
const long *ls_my_files(const char *path, long start_at, long end_at)
|
const long *ls_my_files(const char *path, long start_at, long end_at)
|
||||||
{
|
{
|
||||||
DIR *dir = opendir(path);
|
long *ret, my_count;
|
||||||
int my_count;
|
|
||||||
int my_index;
|
|
||||||
long *ret;
|
|
||||||
|
|
||||||
if (!dir)
|
do {
|
||||||
err(errno, "Can't open path %s", path);
|
ret = __ls_my_files(path, start_at, end_at, &my_count);
|
||||||
|
} while (!ret);
|
||||||
|
|
||||||
my_count = 0;
|
|
||||||
ret = __ls_my_files(dir, start_at, end_at, &my_count, &my_index);
|
|
||||||
assert(my_index == -1);
|
|
||||||
qsort(ret, my_count, sizeof(*ret), cmpintp);
|
qsort(ret, my_count, sizeof(*ret), cmpintp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user