summaryrefslogtreecommitdiff
path: root/Kernel/FileSystem/InodeMetadata.h
blob: 93e5ed2742134c91f6295f2168ac1ca19f0d4e6f (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
/*
 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Error.h>
#include <AK/Span.h>
#include <Kernel/FileSystem/DeviceFileTypes.h>
#include <Kernel/FileSystem/InodeIdentifier.h>
#include <Kernel/Forward.h>
#include <Kernel/UnixTypes.h>

namespace Kernel {

class Process;

constexpr u64 encoded_device(MajorNumber major, MinorNumber minor)
{
    return (minor.value() & 0xff) | (major.value() << 8) | ((minor.value() & ~0xff) << 12);
}
static inline MajorNumber major_from_encoded_device(dev_t dev) { return (dev & 0xfff00u) >> 8u; }
static inline MinorNumber minor_from_encoded_device(dev_t dev) { return (dev & 0xffu) | ((dev >> 12u) & 0xfff00u); }

inline bool is_directory(mode_t mode) { return (mode & S_IFMT) == S_IFDIR; }
inline bool is_character_device(mode_t mode) { return (mode & S_IFMT) == S_IFCHR; }
inline bool is_block_device(mode_t mode) { return (mode & S_IFMT) == S_IFBLK; }
inline bool is_regular_file(mode_t mode) { return (mode & S_IFMT) == S_IFREG; }
inline bool is_fifo(mode_t mode) { return (mode & S_IFMT) == S_IFIFO; }
inline bool is_symlink(mode_t mode) { return (mode & S_IFMT) == S_IFLNK; }
inline bool is_socket(mode_t mode) { return (mode & S_IFMT) == S_IFSOCK; }
inline bool is_sticky(mode_t mode) { return (mode & S_ISVTX) == S_ISVTX; }
inline bool is_setuid(mode_t mode) { return (mode & S_ISUID) == S_ISUID; }
inline bool is_setgid(mode_t mode) { return (mode & S_ISGID) == S_ISGID; }

struct InodeMetadata {
    bool is_valid() const { return inode.is_valid(); }

    bool may_read(Process const&) const;
    bool may_write(Process const&) const;
    bool may_execute(Process const&) const;

    bool may_read(UserID u, GroupID g, Span<GroupID const> eg) const
    {
        if (u == 0)
            return true;
        if (uid == u)
            return (mode & S_IRUSR) == S_IRUSR;
        if (gid == g || eg.contains_slow(gid))
            return (mode & S_IRGRP) == S_IRGRP;
        return (mode & S_IROTH) == S_IROTH;
    }

    bool may_write(UserID u, GroupID g, Span<GroupID const> eg) const
    {
        if (u == 0)
            return true;
        if (uid == u)
            return (mode & S_IWUSR) == S_IWUSR;
        if (gid == g || eg.contains_slow(gid))
            return (mode & S_IWGRP) == S_IWGRP;
        return (mode & S_IWOTH) == S_IWOTH;
    }

    bool may_execute(UserID u, GroupID g, Span<GroupID const> eg) const
    {
        if (u == 0)
            return true;
        if (uid == u)
            return (mode & S_IXUSR) == S_IXUSR;
        if (gid == g || eg.contains_slow(gid))
            return (mode & S_IXGRP) == S_IXGRP;
        return (mode & S_IXOTH) == S_IXOTH;
    }

    bool is_directory() const { return Kernel::is_directory(mode); }
    bool is_character_device() const { return Kernel::is_character_device(mode); }
    bool is_block_device() const { return Kernel::is_block_device(mode); }
    bool is_device() const { return is_character_device() || is_block_device(); }
    bool is_regular_file() const { return Kernel::is_regular_file(mode); }
    bool is_fifo() const { return Kernel::is_fifo(mode); }
    bool is_symlink() const { return Kernel::is_symlink(mode); }
    bool is_socket() const { return Kernel::is_socket(mode); }
    bool is_sticky() const { return Kernel::is_sticky(mode); }
    bool is_setuid() const { return Kernel::is_setuid(mode); }
    bool is_setgid() const { return Kernel::is_setgid(mode); }

    ErrorOr<struct stat> stat() const
    {
        if (!is_valid())
            return EIO;
        struct stat buffer = {};
        buffer.st_rdev = encoded_device(major_device, minor_device);
        buffer.st_ino = inode.index().value();
        buffer.st_mode = mode;
        buffer.st_nlink = link_count;
        buffer.st_uid = uid.value();
        buffer.st_gid = gid.value();
        buffer.st_dev = 0; // FIXME
        buffer.st_size = size;
        buffer.st_blksize = block_size;
        buffer.st_blocks = block_count;
        buffer.st_atim.tv_sec = atime;
        buffer.st_atim.tv_nsec = 0;
        buffer.st_mtim.tv_sec = mtime;
        buffer.st_mtim.tv_nsec = 0;
        buffer.st_ctim.tv_sec = ctime;
        buffer.st_ctim.tv_nsec = 0;
        return buffer;
    }

    InodeIdentifier inode;
    off_t size { 0 };
    mode_t mode { 0 };
    UserID uid { 0 };
    GroupID gid { 0 };
    nlink_t link_count { 0 };
    time_t atime { 0 };
    time_t ctime { 0 };
    time_t mtime { 0 };
    time_t dtime { 0 };
    blkcnt_t block_count { 0 };
    blksize_t block_size { 0 };
    MajorNumber major_device { 0 };
    MinorNumber minor_device { 0 };
};

}