/** * @file Directory.cpp * @author apio (cloudapio.eu) * @brief A C++-friendly API for directory access. * * @copyright Copyright (c) 2023, the Luna authors. * */ #include #include #include #include #include #include #include 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> 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::from_syscall(rc)); DIR* dp = fdopendir(fd); if (!dp) { close(fd); return err(errno); } dir->m_dirp = dp; return dir; } Result 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> Directory::list_names(Filter filter) { Vector result; rewind(); String entry {}; while ((entry = TRY(next(filter))), !entry.is_empty()) TRY(result.try_append(move(entry))); return result; } Result> Directory::list(Filter filter) { Vector 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) { } }