1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#pragma once
4
5#include <mos/filesystem/fs_types.h>
6#include <mos/filesystem/vfs_types.hpp>
7#include <mos/lib/structures/list.hpp>
8#include <mos/mos_global.h>
9
10/**
11 * @defgroup dentry Directory Entry
12 * @brief Directory entry
13 * @ingroup vfs
14 *
15 * @details
16 * A dentry is a directory entry, it is a reference to an inode.
17 *
18 * dentry cache policy: The function who references the dentry should be
19 * responsible for unrefing it.
20 *
21 * All existing files' dentries have a reference count of 0 at the start.
22 * When a file is opened, the dentry will be referenced, and the reference
23 * count will be incremented by 1.
24 *
25 * For all directories, the initial reference count is also 0, but when
26 * a directory is opened, the reference count will be incremented by 1.
27 *
28 * When mounting a filesystem, the root dentry of the filesystem is
29 * inserted into the dentry cache, and will have a reference count of 1.
30 * The mountpoint itself will have its reference count incremented by 1.
31 *
32 * For the root dentry ("/"), the reference count is 2, one for the mountpoint,
33 * and one for the dentry cache.
34 * @{
35 */
36
37typedef enum
38{
39 // bit 0, 1: the operation only succeeds if the inode is a...
40 RESOLVE_EXPECT_FILE = 1 << 0,
41 RESOLVE_EXPECT_DIR = 1 << 1,
42 RESOLVE_EXPECT_ANY_TYPE = RESOLVE_EXPECT_FILE | RESOLVE_EXPECT_DIR,
43
44 // bit 2: follow symlinks?
45 // only for the last segment, (if it is a symlink)
46 RESOLVE_SYMLINK_NOFOLLOW = 1 << 2,
47
48 // bit 3, 4: the operation only succeeds if...
49 RESOLVE_EXPECT_EXIST = 1 << 3,
50 RESOLVE_EXPECT_NONEXIST = 1 << 4,
51 RESOLVE_EXPECT_ANY_EXIST = RESOLVE_EXPECT_EXIST | RESOLVE_EXPECT_NONEXIST,
52} lastseg_resolve_flags_t;
53
54MOS_ENUM_OPERATORS(lastseg_resolve_flags_t)
55
56/**
57 * @brief Check if a path is absolute
58 *
59 * @param path The path to check
60 * @return true if the path is absolute (starts with a '/'), false otherwise
61 */
62should_inline bool path_is_absolute(const char *path)
63{
64 return path[0] == '/';
65}
66
67should_inline dentry_t *dentry_parent(const dentry_t &dentry)
68{
69 return tree_parent(&dentry, dentry_t);
70}
71
72/**
73 * @brief Check the reference count of a dentry
74 *
75 * @param dentry The dentry to check
76 */
77void dentry_check_refstat(const dentry_t *dentry);
78typedef void(dump_refstat_receiver_t)(int depth, const dentry_t *dentry, bool mountroot, void *data);
79void dentry_dump_refstat(const dentry_t *dentry, dump_refstat_receiver_t receiver, void *data);
80
81/**
82 * @brief Increment the reference count of a dentry
83 *
84 * @param dentry The dentry to increment the reference count of
85 * @return the dentry itself
86 */
87dentry_t *dentry_ref(dentry_t *dentry);
88
89/**
90 * @brief Increment the reference count of a dentry up to a given dentry
91 *
92 * @param dentry The dentry to increment the reference count of
93 * @param root The dentry to stop at
94 * @return dentry_t* The dentry itself
95 */
96dentry_t *dentry_ref_up_to(dentry_t *dentry, dentry_t *root);
97
98/**
99 * @brief Decrement the reference count of a dentry
100 *
101 * @param dentry The dentry to decrement the reference count of
102 */
103void dentry_unref(dentry_t *dentry);
104__nodiscard bool dentry_unref_one_norelease(dentry_t *dentry);
105void dentry_try_release(dentry_t *dentry);
106
107/**
108 * @brief Attach an inode to a dentry
109 *
110 * @param d The dentry to attach the inode to
111 * @param inode The inode to attach
112 */
113void dentry_attach(dentry_t *d, inode_t *inode);
114
115/**
116 * @brief Detach the inode from a dentry
117 *
118 * @param dentry The dentry to detach the inode from
119 */
120void dentry_detach(dentry_t *dentry);
121
122/**
123 * @brief Get the dentry from a file descriptor
124 *
125 * @param fd The file descriptor, there's a special case for AT_FDCWD, which corresponds to the process's current working directory
126 *
127 * @return The dentry associated with the file descriptor, or NULL if the file descriptor is invalid
128 */
129PtrResult<dentry_t> dentry_from_fd(fd_t fd);
130
131/**
132 * @brief Get a child dentry from a parent dentry
133 *
134 * @param parent The parent dentry
135 * @param name The name of the child dentry
136 *
137 * @return The child dentry, always non-NULL, even if the child dentry does not exist in the filesystem
138 * @note The returned dentry will have its reference count incremented, even if it does not exist.
139 */
140PtrResult<dentry_t> dentry_lookup_child(dentry_t *parent, const char *name);
141
142/**
143 * @brief Lookup a path in the filesystem
144 *
145 * @details If the path is absolute, the base is ignored and the path starts from the root_dir
146 * If the path is relative, the base is used as the starting points
147 *
148 * @param starting_dir The starting directory when resolving a [relative] path
149 * @param root_dir the root directory when resolving the path, the resolved path will not go above this directory
150 * @param path The path to resolve, can be absolute or relative
151 * @param flags Flags to control the behavior of the path resolution, see \ref lastseg_resolve_flags_t
152 *
153 * @return The parent directory (if such a parent exists) containing (or to contain) the last segment of the path, or
154 * NULL if any intermediate directory in the path does not exist.
155 *
156 */
157PtrResult<dentry_t> dentry_resolve(dentry_t *starting_dir, dentry_t *root_dir, const char *path, lastseg_resolve_flags_t flags);
158
159/**
160 * @brief Mount a filesystem at a mountpoint
161 *
162 * @param mountpoint The mountpoint
163 * @param root The root directory of the filesystem
164 * @param fs The filesystem to mount
165 *
166 * @return true if the filesystem was mounted successfully, false otherwise
167 */
168__nodiscard bool dentry_mount(dentry_t *mountpoint, dentry_t *root, filesystem_t *fs);
169
170/**
171 * @brief Unmount a filesystem at the mountpoint
172 *
173 * @return __nodiscard
174 */
175__nodiscard dentry_t *dentry_unmount(dentry_t *root);
176
177/**
178 * @brief List the contents of a directory
179 *
180 * @param dir The directory to list
181 * @param state The state of the directory iterator
182 */
183void vfs_populate_listdir_buf(dentry_t *dir, vfs_listdir_state_t *state);
184
185/**
186 * @brief Get the path of a dentry
187 *
188 * @param dentry The dentry to get the path of
189 * @param root The root directory, the path will not go above this directory
190 * @param buf The buffer to write the path to
191 * @param size The size of the buffer
192 * @return ssize_t
193 */
194ssize_t dentry_path(dentry_t *dentry, dentry_t *root, char *buf, size_t size);
195
196/**@}*/
197