mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 07:57:46 +00:00
LibC: Implement scandir(...) to enumerate directories.
I ran into a need for this when running stress-ng against the system. This change implements the full functionality of scandir, where it accepts a selection callback, as well as a comparison callback. These can be used to trim and sort the entries from the directory that we are being asked to enumerate. A test was also included to validate the new functionality.
This commit is contained in:
parent
d4d988532a
commit
331ab52318
4 changed files with 95 additions and 0 deletions
|
@ -5,7 +5,9 @@
|
|||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/ScopeGuard.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
@ -184,4 +186,64 @@ int dirfd(DIR* dirp)
|
|||
VERIFY(dirp);
|
||||
return dirp->fd;
|
||||
}
|
||||
|
||||
int scandir(const char* dir_name,
|
||||
struct dirent*** namelist,
|
||||
int (*select)(const struct dirent*),
|
||||
int (*compare)(const struct dirent**, const struct dirent**))
|
||||
{
|
||||
auto dir = opendir(dir_name);
|
||||
if (dir == nullptr)
|
||||
return -1;
|
||||
ScopeGuard guard = [&] {
|
||||
closedir(dir);
|
||||
};
|
||||
|
||||
Vector<struct dirent*> tmp_names;
|
||||
ScopeGuard names_guard = [&] {
|
||||
tmp_names.remove_all_matching([&](auto& entry) {
|
||||
free(entry);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
while (true) {
|
||||
errno = 0;
|
||||
auto entry = readdir(dir);
|
||||
if (!entry)
|
||||
break;
|
||||
|
||||
// Omit entries the caller chooses to ignore.
|
||||
if (select && !select(entry))
|
||||
continue;
|
||||
|
||||
auto entry_copy = (struct dirent*)malloc(entry->d_reclen);
|
||||
if (!entry_copy)
|
||||
break;
|
||||
memcpy(entry_copy, entry, entry->d_reclen);
|
||||
tmp_names.append(entry_copy);
|
||||
}
|
||||
|
||||
// Propagate any errors encountered while accumulating back to the user.
|
||||
if (errno) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Sort the entries if the user provided a comparator.
|
||||
if (compare) {
|
||||
qsort(tmp_names.data(), tmp_names.size(), sizeof(struct dirent*), (int (*)(const void*, const void*))compare);
|
||||
}
|
||||
|
||||
const int size = tmp_names.size();
|
||||
auto names = (struct dirent**)malloc(size * sizeof(struct dirent*));
|
||||
for (auto i = 0; i < size; i++) {
|
||||
names[i] = tmp_names[i];
|
||||
}
|
||||
|
||||
// Disable the scope guard which free's names on error.
|
||||
tmp_names.clear();
|
||||
|
||||
*namelist = names;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue