summaryrefslogtreecommitdiff
path: root/Kernel/FileSystem/Custody.cpp
blob: 0875f9c8286f5a67dfdfd1e0186825cb4402c423 (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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <AK/Singleton.h>
#include <AK/StringBuilder.h>
#include <AK/StringView.h>
#include <AK/Vector.h>
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/FileSystem/Inode.h>
#include <Kernel/Locking/MutexProtected.h>

namespace Kernel {

static Singleton<MutexProtected<Custody::AllCustodiesList>> s_all_custodies;

static MutexProtected<Custody::AllCustodiesList>& all_custodies()
{
    return s_all_custodies;
}

KResultOr<NonnullRefPtr<Custody>> Custody::try_create(Custody* parent, StringView name, Inode& inode, int mount_flags)
{
    return all_custodies().with_exclusive([&](auto& all_custodies) -> KResultOr<NonnullRefPtr<Custody>> {
        for (Custody& custody : all_custodies) {
            if (custody.parent() == parent
                && custody.name() == name
                && &custody.inode() == &inode
                && custody.mount_flags() == mount_flags) {
                return custody;
            }
        }

        auto name_kstring = KString::try_create(name);
        if (!name_kstring)
            return ENOMEM;
        auto custody = adopt_ref_if_nonnull(new (nothrow) Custody(parent, name_kstring.release_nonnull(), inode, mount_flags));
        if (!custody)
            return ENOMEM;

        all_custodies.prepend(*custody);
        return custody.release_nonnull();
    });
}

bool Custody::unref() const
{
    bool should_destroy = all_custodies().with_exclusive([&](auto&) {
        if (deref_base())
            return false;
        m_all_custodies_list_node.remove();
        return true;
    });

    if (should_destroy)
        delete this;
    return should_destroy;
}

Custody::Custody(Custody* parent, NonnullOwnPtr<KString> name, Inode& inode, int mount_flags)
    : m_parent(parent)
    , m_name(move(name))
    , m_inode(inode)
    , m_mount_flags(mount_flags)
{
}

Custody::~Custody()
{
}

KResultOr<NonnullOwnPtr<KString>> Custody::try_serialize_absolute_path() const
{
    if (!parent()) {
        auto string = KString::try_create("/"sv);
        if (!string)
            return ENOMEM;
        return string.release_nonnull();
    }

    Vector<Custody const*, 32> custody_chain;
    size_t path_length = 0;
    for (auto* custody = this; custody; custody = custody->parent()) {
        custody_chain.append(custody);
        path_length += custody->m_name->length() + 1;
    }
    VERIFY(path_length > 0);

    char* buffer;
    auto string = KString::try_create_uninitialized(path_length - 1, buffer);
    if (!string)
        return ENOMEM;
    size_t string_index = 0;
    for (size_t custody_index = custody_chain.size() - 1; custody_index > 0; --custody_index) {
        buffer[string_index] = '/';
        ++string_index;
        auto& custody_name = *custody_chain[custody_index - 1]->m_name;
        __builtin_memcpy(buffer + string_index, custody_name.characters(), custody_name.length());
        string_index += custody_name.length();
    }
    VERIFY(string->length() == string_index);
    buffer[string_index] = 0;
    return string.release_nonnull();
}

String Custody::absolute_path() const
{
    if (!parent())
        return "/";
    Vector<Custody const*, 32> custody_chain;
    for (auto* custody = this; custody; custody = custody->parent())
        custody_chain.append(custody);
    StringBuilder builder;
    for (int i = custody_chain.size() - 2; i >= 0; --i) {
        builder.append('/');
        builder.append(custody_chain[i]->name());
    }
    return builder.to_string();
}

bool Custody::is_readonly() const
{
    if (m_mount_flags & MS_RDONLY)
        return true;

    return m_inode->fs().is_readonly();
}

}