PatchworkOS
Loading...
Searching...
No Matches
dentry.c
Go to the documentation of this file.
1#include <kernel/fs/dentry.h>
2
3#include <stdio.h>
4
5#include <kernel/fs/vfs.h>
6#include <kernel/log/log.h>
8#include <kernel/sync/lock.h>
9#include <kernel/sync/mutex.h>
10
11#include <stdlib.h>
12
13static void dentry_free(dentry_t* dentry)
14{
15 if (dentry == NULL)
16 {
17 return;
18 }
19
20 assert(dentry->parent != NULL);
21
22 vfs_remove_dentry(dentry);
23
24 if (dentry->ops != NULL && dentry->ops->cleanup != NULL)
25 {
26 dentry->ops->cleanup(dentry);
27 }
28
29 if (dentry->inode != NULL)
30 {
31 DEREF(dentry->inode);
32 dentry->inode = NULL;
33 }
34
35 if (!DENTRY_IS_ROOT(dentry))
36 {
37 if (!(atomic_load(&dentry->flags) & DENTRY_NEGATIVE))
38 {
40 list_remove(&dentry->parent->children, &dentry->siblingEntry);
42 }
43
44 DEREF(dentry->parent);
45 dentry->parent = NULL;
46 }
47
48 free(dentry);
49}
50
51dentry_t* dentry_new(superblock_t* superblock, dentry_t* parent, const char* name)
52{
53 if (name == NULL || superblock == NULL)
54 {
55 errno = EINVAL;
56 return NULL;
57 }
58
59 size_t nameLen = strnlen_s(name, MAX_NAME);
60 if (nameLen >= MAX_NAME || nameLen == 0)
61 {
62 errno = EINVAL;
63 return NULL;
64 }
65
66 assert(parent == NULL || superblock == parent->superblock);
67
68 dentry_t* dentry = malloc(sizeof(dentry_t));
69 if (dentry == NULL)
70 {
71 return NULL;
72 }
73
74 ref_init(&dentry->ref, dentry_free);
75 map_entry_init(&dentry->mapEntry);
76 dentry->id = vfs_get_new_id();
77 strncpy(dentry->name, name, MAX_NAME - 1);
78 dentry->name[MAX_NAME - 1] = '\0';
79 dentry->inode = NULL;
80 dentry->parent = parent != NULL
81 ? REF(parent)
82 : dentry; // We set its parent now but its only added to its list when it is made positive.
84 list_init(&dentry->children);
85 mutex_init(&dentry->childrenMutex);
86 dentry->superblock = REF(superblock);
87 dentry->ops = dentry->superblock != NULL ? dentry->superblock->dentryOps : NULL;
88 dentry->private = NULL;
89 atomic_init(&dentry->flags, DENTRY_NEGATIVE);
90 atomic_init(&dentry->mountCount, 0);
91
92 if (vfs_add_dentry(dentry) == ERR)
93 {
94 DEREF(dentry);
95 return NULL;
96 }
97
98 return dentry;
99}
100
102{
103 if (dentry == NULL || inode == NULL)
104 {
105 errno = EINVAL;
106 return ERR;
107 }
108
109 MUTEX_SCOPE(&dentry->childrenMutex);
110
111 // Sanity checks.
112 assert(atomic_load(&dentry->flags) & DENTRY_NEGATIVE);
113 assert(dentry->inode == NULL);
114
115 dentry->inode = REF(inode);
116
117 if (!DENTRY_IS_ROOT(dentry))
118 {
120 list_push(&dentry->parent->children, &dentry->siblingEntry);
121 }
122
123 atomic_fetch_and(&dentry->flags, ~DENTRY_NEGATIVE);
124
125 return 0;
126}
127
129{
130 atomic_fetch_add(&dentry->mountCount, 1);
131}
132
134{
135 atomic_fetch_sub(&dentry->mountCount, 1);
136}
137
147
148static void getdents_write(getdents_ctx_t* ctx, inode_number_t number, inode_type_t type, const char* name)
149{
150 uint64_t start = *ctx->offset / sizeof(dirent_t);
151 uint64_t amount = ctx->count / sizeof(dirent_t);
152
153 if (ctx->index >= start && ctx->index < start + amount)
154 {
155 dirent_t* dirent = &ctx->buffer[ctx->index - start];
156 dirent->number = number;
157 dirent->type = type;
158 strncpy(dirent->name, name, MAX_PATH - 1);
159 dirent->name[MAX_PATH - 1] = '\0';
160 }
161
162 ctx->index++;
163}
164
166{
167 getdents_write(ctx, dentry->inode->number, dentry->inode->type, ctx->basePath);
168
169 MUTEX_SCOPE(&dentry->childrenMutex);
170
171 dentry_t* child;
172 LIST_FOR_EACH(child, &dentry->children, siblingEntry)
173 {
174 if (ctx->flags & PATH_RECURSIVE && child->inode->type == INODE_DIR)
175 {
176 char originalBasePath[MAX_PATH];
177 strncpy(originalBasePath, ctx->basePath, MAX_PATH - 1);
178 originalBasePath[MAX_PATH - 1] = '\0';
179
180 snprintf(ctx->basePath, MAX_PATH, "%s/%s", originalBasePath, child->name);
182
183 strncpy(ctx->basePath, originalBasePath, MAX_PATH - 1);
184 ctx->basePath[MAX_PATH - 1] = '\0';
185 }
186 else
187 {
188 char fullPath[MAX_PATH];
189 snprintf(fullPath, MAX_PATH, "%s/%s", ctx->basePath, child->name);
190 getdents_write(ctx, child->inode->number, child->inode->type, fullPath);
191 }
192 }
193}
194
196 path_flags_t flags)
197{
198 getdents_ctx_t ctx = {
199 .index = 0,
200 .buffer = buffer,
201 .count = count,
202 .offset = offset,
203 .flags = flags,
204 .basePath = "",
205 };
206
207 MUTEX_SCOPE(&dentry->childrenMutex);
208
209 getdents_write(&ctx, dentry->inode->number, dentry->inode->type, ".");
210 getdents_write(&ctx, dentry->parent->inode->number, dentry->parent->inode->type, "..");
211
212 if (flags & PATH_RECURSIVE)
213 {
214 dentry_t* child;
215 LIST_FOR_EACH(child, &dentry->children, siblingEntry)
216 {
217 if (child->inode->type == INODE_DIR)
218 {
219 snprintf(ctx.basePath, MAX_PATH, "%s", child->name);
220 getdents_recursive_traversal(&ctx, child);
221 ctx.basePath[0] = '\0';
222 }
223 else
224 {
225 getdents_write(&ctx, child->inode->number, child->inode->type, child->name);
226 }
227 }
228 }
229 else
230 {
231 dentry_t* child;
232 LIST_FOR_EACH(child, &dentry->children, siblingEntry)
233 {
234 getdents_write(&ctx, child->inode->number, child->inode->type, child->name);
235 }
236 }
237
238 uint64_t start = *offset / sizeof(dirent_t);
239 if (start >= ctx.index)
240 {
241 return 0;
242 }
243
244 uint64_t entriesWritten = MIN(ctx.index - start, count / sizeof(dirent_t));
245 uint64_t bytesWritten = entriesWritten * sizeof(dirent_t);
246 *offset += bytesWritten;
247 return bytesWritten;
248}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define assert(expression)
Definition assert.h:29
static void getdents_write(getdents_ctx_t *ctx, inode_number_t number, inode_type_t type, const char *name)
Definition dentry.c:148
static void dentry_free(dentry_t *dentry)
Definition dentry.c:13
static void getdents_recursive_traversal(getdents_ctx_t *ctx, dentry_t *dentry)
Definition dentry.c:165
void dentry_dec_mount_count(dentry_t *dentry)
Decrements the mount count of a dentry.
Definition dentry.c:133
void dentry_inc_mount_count(dentry_t *dentry)
Increments the mount count of a dentry.
Definition dentry.c:128
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:51
uint64_t dentry_make_positive(dentry_t *dentry, inode_t *inode)
Make a dentry positive by associating it with an inode.
Definition dentry.c:101
#define DENTRY_IS_ROOT(dentry)
Macro to check if a dentry is the root entry in its filesystem.
Definition dentry.h:43
uint64_t dentry_generic_getdents(dentry_t *dentry, dirent_t *buffer, uint64_t count, uint64_t *offset, path_flags_t flags)
Helper function for a basic getdents.
Definition dentry.c:195
@ DENTRY_NEGATIVE
Definition dentry.h:59
path_flags_t
Path flags.
Definition path.h:83
@ PATH_RECURSIVE
Definition path.h:91
uint64_t vfs_get_new_id(void)
Generates a new unique ID.
Definition vfs.c:97
void vfs_remove_dentry(dentry_t *dentry)
Remove a dentry from the dentry cache.
Definition vfs.c:324
uint64_t vfs_add_dentry(dentry_t *dentry)
Add a dentry to the dentry cache.
Definition vfs.c:288
void mutex_release(mutex_t *mtx)
Releases a mutex.
Definition mutex.c:103
void mutex_acquire(mutex_t *mtx)
Acquires a mutex, blocking until it is available.
Definition mutex.c:26
void mutex_init(mutex_t *mtx)
Initializes a mutex.
Definition mutex.c:12
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
void map_entry_init(map_entry_t *entry)
Initialize a map entry.
Definition map.c:71
static void ref_init(ref_t *ref, void *free)
Initialize a reference counter.
Definition ref.h:92
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define DEREF(ptr)
Decrement reference count.
Definition ref.h:80
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
inode_type_t
Inode type enum.
Definition io.h:344
uint64_t inode_number_t
Inode number enum.
Definition io.h:353
@ INODE_DIR
Is a directory.
Definition io.h:346
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:65
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
#define MIN(x, y)
Definition math.h:16
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static void start()
Definition main.c:542
static atomic_long count
Definition main.c:9
#define atomic_fetch_sub(object, operand)
Definition stdatomic.h:286
#define atomic_load(object)
Definition stdatomic.h:288
#define atomic_fetch_and(object, operand)
Definition stdatomic.h:284
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:283
#define atomic_init(obj, value)
Definition stdatomic.h:75
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC char * strncpy(char *_RESTRICT s1, const char *_RESTRICT s2, size_t n)
Definition strncpy.c:3
size_t strnlen_s(const char *s, size_t maxsize)
Definition strnlen_s.c:4
void(* cleanup)(dentry_t *entry)
Called when the dentry is being freed.
Definition dentry.h:75
Directory entry structure.
Definition dentry.h:83
list_t children
Definition dentry.h:90
inode_t * inode
Definition dentry.h:87
atomic_uint64_t mountCount
Definition dentry.h:114
mutex_t childrenMutex
Definition dentry.h:91
char name[MAX_NAME]
Definition dentry.h:86
ref_t ref
Definition dentry.h:84
dentry_id_t id
Definition dentry.h:85
const dentry_ops_t * ops
Definition dentry.h:93
dentry_t * parent
Definition dentry.h:88
void * private
Definition dentry.h:94
superblock_t * superblock
Definition dentry.h:92
list_entry_t siblingEntry
Definition dentry.h:89
map_entry_t mapEntry
Definition dentry.h:95
Directory entry struct.
Definition io.h:424
char name[MAX_PATH]
The relative name of the directory.
Definition io.h:427
inode_type_t type
The type of the entries inode.
Definition io.h:426
inode_number_t number
The number of the entries inode.
Definition io.h:425
uint64_t count
Definition dentry.c:142
uint32_t flags
Definition dentry.c:144
char basePath[MAX_PATH]
Definition dentry.c:145
uint64_t index
Definition dentry.c:140
uint64_t * offset
Definition dentry.c:143
dirent_t * buffer
Definition dentry.c:141
Inode structure.
Definition inode.h:54
inode_type_t type
Constant after creation.
Definition inode.h:57
inode_number_t number
Constant after creation.
Definition inode.h:56
Superblock structure.
Definition superblock.h:44
const dentry_ops_t * dentryOps
Definition superblock.h:53