mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibCore: Introduce Directory
Core::Directory represents an existing directory on the system, and it holds an actual file descriptor so that the user can be sure the directory stays in existence.
This commit is contained in:
parent
ceba27c3fe
commit
46b76f2f55
Notes:
sideshowbarker
2024-07-17 12:07:29 +09:00
Author: https://github.com/kleinesfilmroellchen Commit: https://github.com/SerenityOS/serenity/commit/46b76f2f55 Pull-request: https://github.com/SerenityOS/serenity/pull/13603 Issue: https://github.com/SerenityOS/serenity/issues/13555 Reviewed-by: https://github.com/BertalanD Reviewed-by: https://github.com/alichraghi ✅ Reviewed-by: https://github.com/awesomekling
3 changed files with 171 additions and 0 deletions
|
@ -5,6 +5,7 @@ set(SOURCES
|
|||
ConfigFile.cpp
|
||||
Command.cpp
|
||||
DateTime.cpp
|
||||
Directory.cpp
|
||||
DirIterator.cpp
|
||||
ElapsedTimer.cpp
|
||||
Event.cpp
|
||||
|
|
100
Userland/Libraries/LibCore/Directory.cpp
Normal file
100
Userland/Libraries/LibCore/Directory.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "Directory.h"
|
||||
#include "DirIterator.h"
|
||||
#include "System.h"
|
||||
#include <dirent.h>
|
||||
|
||||
namespace Core {
|
||||
|
||||
// We assume that the fd is a valid directory.
|
||||
Directory::Directory(int fd, Optional<LexicalPath> path)
|
||||
: m_path(move(path))
|
||||
, m_directory_fd(fd)
|
||||
{
|
||||
}
|
||||
|
||||
Directory::Directory(Directory&& other)
|
||||
: m_path(move(other.m_path))
|
||||
, m_directory_fd(other.m_directory_fd)
|
||||
{
|
||||
other.m_directory_fd = -1;
|
||||
}
|
||||
|
||||
Directory::~Directory()
|
||||
{
|
||||
if (m_directory_fd != -1)
|
||||
MUST(System::close(m_directory_fd));
|
||||
}
|
||||
|
||||
ErrorOr<bool> Directory::is_valid_directory(int fd)
|
||||
{
|
||||
auto stat = TRY(System::fstat(fd));
|
||||
return stat.st_mode & S_IFDIR;
|
||||
}
|
||||
|
||||
ErrorOr<Directory> Directory::adopt_fd(int fd, Optional<LexicalPath> path)
|
||||
{
|
||||
// This will also fail if the fd is invalid in the first place.
|
||||
if (!TRY(Directory::is_valid_directory(fd)))
|
||||
return Error::from_errno(ENOTDIR);
|
||||
return Directory { fd, move(path) };
|
||||
}
|
||||
|
||||
ErrorOr<Directory> Directory::create(String path, CreateDirectories create_directories)
|
||||
{
|
||||
return create(LexicalPath { move(path) }, create_directories);
|
||||
}
|
||||
|
||||
ErrorOr<Directory> Directory::create(LexicalPath path, CreateDirectories create_directories)
|
||||
{
|
||||
if (create_directories == CreateDirectories::Yes)
|
||||
TRY(ensure_directory(path));
|
||||
// FIXME: doesn't work on Linux probably
|
||||
auto fd = TRY(System::open(path.string(), O_CLOEXEC));
|
||||
return adopt_fd(fd, move(path));
|
||||
}
|
||||
|
||||
ErrorOr<void> Directory::ensure_directory(LexicalPath const& path)
|
||||
{
|
||||
if (path.basename() == "/")
|
||||
return {};
|
||||
|
||||
TRY(ensure_directory(path.parent()));
|
||||
|
||||
auto return_value = System::mkdir(path.string(), 0755);
|
||||
// We don't care if the directory already exists.
|
||||
if (return_value.is_error() && return_value.error().code() != EEXIST)
|
||||
return return_value;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<LexicalPath> Directory::path() const
|
||||
{
|
||||
if (!m_path.has_value())
|
||||
return Error::from_string_literal("Directory wasn't created with a path");
|
||||
return m_path.value();
|
||||
}
|
||||
|
||||
ErrorOr<NonnullOwnPtr<Stream::File>> Directory::open(StringView filename, Stream::OpenMode mode) const
|
||||
{
|
||||
auto fd = TRY(System::openat(m_directory_fd, filename, Stream::File::open_mode_to_options(mode)));
|
||||
return Stream::File::adopt_fd(fd, mode);
|
||||
}
|
||||
|
||||
ErrorOr<struct stat> Directory::stat() const
|
||||
{
|
||||
return System::fstat(m_directory_fd);
|
||||
}
|
||||
|
||||
ErrorOr<DirIterator> Directory::create_iterator() const
|
||||
{
|
||||
return DirIterator { TRY(path()).string() };
|
||||
}
|
||||
|
||||
}
|
70
Userland/Libraries/LibCore/Directory.h
Normal file
70
Userland/Libraries/LibCore/Directory.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <LibCore/Stream.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace Core {
|
||||
|
||||
class DirIterator;
|
||||
|
||||
// Deal with real system directories. Any Directory instance always refers to a valid existing directory.
|
||||
class Directory {
|
||||
AK_MAKE_NONCOPYABLE(Directory);
|
||||
|
||||
public:
|
||||
Directory(Directory&&);
|
||||
~Directory();
|
||||
|
||||
// When this flag is set, both the directory attempted to instantiate as well as all of its parents are created with mode 0755 if necessary.
|
||||
enum class CreateDirectories : bool {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
static ErrorOr<Directory> create(LexicalPath path, CreateDirectories);
|
||||
static ErrorOr<Directory> create(String path, CreateDirectories);
|
||||
static ErrorOr<Directory> adopt_fd(int fd, Optional<LexicalPath> path = {});
|
||||
|
||||
ErrorOr<NonnullOwnPtr<Stream::File>> open(StringView filename, Stream::OpenMode mode) const;
|
||||
ErrorOr<struct stat> stat() const;
|
||||
ErrorOr<DirIterator> create_iterator() const;
|
||||
|
||||
ErrorOr<LexicalPath> path() const;
|
||||
|
||||
static ErrorOr<bool> is_valid_directory(int fd);
|
||||
|
||||
private:
|
||||
Directory(int directory_fd, Optional<LexicalPath> path);
|
||||
static ErrorOr<void> ensure_directory(LexicalPath const& path);
|
||||
|
||||
Optional<LexicalPath> m_path;
|
||||
int m_directory_fd;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
template<>
|
||||
struct Formatter<Core::Directory> : Formatter<StringView> {
|
||||
ErrorOr<void> format(FormatBuilder& builder, Core::Directory const& directory)
|
||||
{
|
||||
auto path = directory.path();
|
||||
if (path.is_error())
|
||||
return Formatter<StringView>::format(builder, "<unknown>");
|
||||
return Formatter<StringView>::format(builder, path.release_value().string());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in a new issue