Luna/libos/src/Directory.cpp
apio bc07cc94cb
All checks were successful
continuous-integration/drone/push Build is passing
libos: Document it entirely using Doxygen comments =D
Also, add copyright information to individual files. This is going to be a hassle to do for EVERY file.
2023-06-09 22:45:06 +02:00

118 lines
2.6 KiB
C++

/**
* @file Directory.cpp
* @author apio (cloudapio.eu)
* @brief A C++-friendly API for directory access.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <errno.h>
#include <fcntl.h>
#include <luna/CString.h>
#include <os/Directory.h>
#include <os/FileSystem.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(const Path& path)
{
auto dir = TRY(adopt_shared_if_nonnull(new (std::nothrow) Directory({})));
long rc = syscall(SYS_openat, path.dirfd(), path.name().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);
}
Result<Vector<String>> Directory::list_names(Filter filter)
{
Vector<String> result;
rewind();
String entry {};
while ((entry = TRY(next(filter))), !entry.is_empty()) TRY(result.try_append(move(entry)));
return result;
}
Result<Vector<Directory::Entry>> Directory::list(Filter filter)
{
Vector<Directory::Entry> result;
rewind();
String name {};
while ((name = TRY(next(filter))), !name.is_empty())
{
struct stat st;
TRY(FileSystem::stat({ dirfd(m_dirp), name.chars() }, st, false));
Directory::Entry entry {
.name = move(name),
.mode = st.st_mode,
.size = (usize)st.st_size,
.mtime = st.st_mtime,
};
TRY(result.try_append(move(entry)));
}
return result;
}
void Directory::rewind()
{
rewinddir(m_dirp);
}
Directory::~Directory()
{
if (m_dirp) closedir(m_dirp);
}
Directory::Directory(Badge<Directory>)
{
}
}