apio
bc07cc94cb
All checks were successful
continuous-integration/drone/push Build is passing
Also, add copyright information to individual files. This is going to be a hassle to do for EVERY file.
118 lines
2.6 KiB
C++
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>)
|
|
{
|
|
}
|
|
}
|