summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibCore/Directory.cpp
blob: 5e821d16fc903ab3ea3b51d09784376c61dc0755 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * 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<void> Directory::chown(uid_t uid, gid_t gid)
{
    if (m_directory_fd == -1)
        return Error::from_syscall("fchown"sv, -EBADF);
    TRY(Core::System::fchown(m_directory_fd, uid, gid));
    return {};
}

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(DeprecatedString path, CreateDirectories create_directories, mode_t creation_mode)
{
    return create(LexicalPath { move(path) }, create_directories, creation_mode);
}

ErrorOr<Directory> Directory::create(LexicalPath path, CreateDirectories create_directories, mode_t creation_mode)
{
    if (create_directories == CreateDirectories::Yes)
        TRY(ensure_directory(path, creation_mode));
    // 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, mode_t creation_mode)
{
    if (path.basename() == "/" || path.basename() == ".")
        return {};

    TRY(ensure_directory(path.parent(), creation_mode));

    auto return_value = System::mkdir(path.string(), creation_mode);
    // 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<File>> Directory::open(StringView filename, File::OpenMode mode) const
{
    auto fd = TRY(System::openat(m_directory_fd, filename, File::open_mode_to_options(mode)));
    return 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() };
}

}