Luna/libos/src/Directory.cpp

78 lines
1.7 KiB
C++

#include <luna/CString.h>
#include <os/Directory.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
static bool should_skip_entry(const char* name, os::Directory::Filter filter)
{
if (filter == os::Directory::Filter::None) return false;
if (filter == os::Directory::Filter::Hidden) return *name == '.';
if (filter == os::Directory::Filter::ParentAndBase) return !strcmp(name, ".") || !strcmp(name, "..");
unreachable();
}
namespace os
{
Result<SharedPtr<Directory>> Directory::open(StringView path)
{
auto dir = TRY(adopt_shared_if_nonnull(new (std::nothrow) Directory({})));
DIR* dp = opendir(path.chars());
if (!dp) return err(errno);
dir->m_dirp = dp;
return dir;
}
Result<SharedPtr<Directory>> Directory::openat(int dirfd, StringView path)
{
auto dir = TRY(adopt_shared_if_nonnull(new (std::nothrow) Directory({})));
long rc = syscall(SYS_openat, dirfd, path.chars(), O_RDONLY | O_DIRECTORY, 0);
int fd = TRY(Result<int>::from_syscall(rc));
DIR* dp = fdopendir(fd);
if (!dp)
{
close(fd);
return err(errno);
}
dir->m_dirp = dp;
return dir;
}
Result<String> Directory::next(Filter filter)
{
errno = 0;
struct dirent* ent;
do {
ent = readdir(m_dirp);
} while (ent && should_skip_entry(ent->d_name, filter));
if (!ent && errno) return err(errno);
if (!ent) return String {};
return String::from_cstring(ent->d_name);
}
Directory::~Directory()
{
if (m_dirp) closedir(m_dirp);
}
Directory::Directory(Badge<Directory>)
{
}
}