AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
pseudofs.c
Go to the documentation of this file.
1
7
8#include <core/system.h>
9#include <core/time.h>
10
11#include <fs/pseudofs.h>
12
13MALLOC_DEFINE(M_PSEUDOFS_DENT, "pseudofs-dirent", "pseudofs directory entry");
14
15/*
16 * A directory is the list of its entries (vnode->p). Its ".." is one of
17 * them, as on a disk: it points to the parent's vnode (without a
18 * reference, since the parent can't go while it has the directory).
19 * finddir finds it like any other entry, and rename moves it; readdir
20 * skips it, and makes up "." and ".." itself. A filesystem's root has no
21 * "..".
22 */
23static const char dotdot[] = "..";
24
26static void pseudofs_dirent_name(struct dirent *dirent, const char *name)
27{
28 size_t len = strlen(name);
29
30 if (len >= MAXNAMELEN)
31 len = MAXNAMELEN - 1;
32
33 memcpy(dirent->d_name, name, len);
34 dirent->d_name[len] = '\0';
35}
36
49int pseudofs_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
50{
51 int err = 0;
52 struct vnode *vnode = NULL;
53 struct pseudofs_dirent *dirent = NULL;
54
55 if (strlen(fn) >= MAXNAMELEN)
56 return -ENAMETOOLONG;
57
58 struct dirent dirent_tmp;
59 if (!pseudofs_finddir(dir, fn, &dirent_tmp)) {
60 err = -EEXIST;
61 goto error;
62 }
63
64 vnode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);
65 if (!vnode) goto error_nomem;
66
67 vnode->ino = (ino_t) vnode;
68 vnode->mode = mode;
69 vnode->size = 0;
70 vnode->uid = uio->uid;
71 vnode->gid = uio->gid;
72 vnode->nlink = S_ISDIR(mode)? 2 : 1;
73 vnode->rdev = dev;
74
75 struct timespec ts;
76 gettime(&ts);
77
78 vnode->ctime = ts;
79 vnode->atime = ts;
80 vnode->mtime = ts;
81
82 vnode->fs = dir->fs; /* the directory's filesystem */
83
84 struct pseudofs_dirent *cur_dir = (struct pseudofs_dirent *) dir->p;
85
86 dirent = kmalloc(sizeof(struct pseudofs_dirent), &M_PSEUDOFS_DENT, 0);
87 if (!dirent) goto error_nomem;
88
89 dirent->d_ino = vnode;
90 dirent->d_name = strdup(fn);
91
92 if (!dirent->d_name) goto error_nomem;
93
94 /* the new directory's .. */
95 if (S_ISDIR(mode)) {
96 struct pseudofs_dirent *parent = kmalloc(sizeof(struct pseudofs_dirent), &M_PSEUDOFS_DENT, 0);
97 if (!parent) goto error_nomem;
98
99 parent->d_name = dotdot;
100 parent->d_ino = dir;
101 parent->next = NULL;
102 vnode->p = parent;
103 dir->nlink++;
104 }
105
106 dirent->next = cur_dir;
107 dir->p = dirent;
108
109 if (ref)
110 *ref = vnode;
111
112 return 0;
113
114error_nomem:
115 err = -ENOMEM;
116 goto error;
117
118error:
119 if (vnode)
120 kfree(vnode);
121
122 if (dirent) {
123 if (dirent->d_name)
124 kfree((void *) dirent->d_name);
125
126 kfree(dirent);
127 }
128
129 return err;
130}
131
134static struct pseudofs_dirent *entry_find(struct vnode *dir, const char *fn, struct pseudofs_dirent **prev)
135{
136 *prev = NULL;
137
138 for (struct pseudofs_dirent *e = dir->p; e; e = e->next) {
139 if (!strcmp(e->d_name, fn))
140 return e;
141
142 *prev = e;
143 }
144
145 return NULL;
146}
147
150static void entry_remove(struct vnode *dir, struct pseudofs_dirent *entry, struct pseudofs_dirent *prev)
151{
152 struct vnode *vnode = entry->d_ino;
153
154 if (prev)
155 prev->next = entry->next;
156 else
157 dir->p = entry->next;
158
159 kfree((void *) entry->d_name);
160 kfree(entry);
161
162 if (S_ISDIR(vnode->mode)) {
163 /* a directory loses its . link, and the parent the link of its
164 * .. */
165 vnode->nlink = 0;
166 dir->nlink--;
167 } else {
168 vnode->nlink--;
169 }
170
171 /* free it if nothing references it anymore */
172 if (!vnode->nlink && !vnode->ref) {
173 vnode->ref = 1; /* vfs_close() drops this one */
175 }
176}
177
186int pseudofs_vunlink(struct vnode *vnode, const char *fn, struct uio *uio)
187{
188 struct pseudofs_dirent *prev;
189
190 if (!S_ISDIR(vnode->mode))
191 return -ENOTDIR;
192
193 struct pseudofs_dirent *entry = entry_find(vnode, fn, &prev);
194
195 if (!entry)
196 return -ENOENT;
197
198 entry_remove(vnode, entry, prev);
199 return 0;
200}
201
211int pseudofs_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
212{
213 struct pseudofs_dirent *prev;
214
215 if (strlen(fn) >= MAXNAMELEN)
216 return -ENAMETOOLONG;
217
218 if (entry_find(dir, fn, &prev))
219 return -EEXIST;
220
221 struct pseudofs_dirent *entry = kmalloc(sizeof(struct pseudofs_dirent), &M_PSEUDOFS_DENT, 0);
222 if (!entry)
223 return -ENOMEM;
224
225 if (!(entry->d_name = strdup(fn))) {
226 kfree(entry);
227 return -ENOMEM;
228 }
229
230 entry->d_ino = vnode;
231 entry->next = dir->p;
232 dir->p = entry;
233
234 vnode->nlink++;
235 return 0;
236}
237
250int pseudofs_vrename(struct vnode *odir, const char *ofn, struct vnode *ndir, const char *nfn, struct uio *uio)
251{
252 struct pseudofs_dirent *oprev, *nprev;
253
254 if (strlen(nfn) >= MAXNAMELEN)
255 return -ENAMETOOLONG;
256
257 struct pseudofs_dirent *entry = entry_find(odir, ofn, &oprev);
258 if (!entry)
259 return -ENOENT;
260
261 char *name = strdup(nfn);
262 if (!name)
263 return -ENOMEM;
264
265 /* replace the entry at the new name, if there's one */
266 struct pseudofs_dirent *old = entry_find(ndir, nfn, &nprev);
267 if (old) {
268 entry_remove(ndir, old, nprev);
269
270 /* removing it may have removed the entry before ours: find it
271 * again */
272 entry_find(odir, ofn, &oprev);
273 }
274
275 if (oprev)
276 oprev->next = entry->next;
277 else
278 odir->p = entry->next;
279
280 kfree((void *) entry->d_name);
281 entry->d_name = name;
282 entry->next = ndir->p;
283 ndir->p = entry;
284
285 /* a directory's .. now points to its new parent */
286 if (S_ISDIR(entry->d_ino->mode)) {
287 struct pseudofs_dirent *prev, *up = entry_find(entry->d_ino, dotdot, &prev);
288
289 if (up)
290 up->d_ino = ndir;
291
292 odir->nlink--;
293 ndir->nlink++;
294 }
295
296 return 0;
297}
298
307{
308 return 0;
309}
310
320ssize_t pseudofs_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)
321{
322 if (offset == 0) {
323 strcpy(dirent->d_name, ".");
324 return 1;
325 }
326
327 if (offset == 1) {
328 strcpy(dirent->d_name, "..");
329 return 1;
330 }
331
332 struct pseudofs_dirent *_dirent = (struct pseudofs_dirent *) dir->p;
333
334 if (!_dirent)
335 return 0;
336
337 int found = 0;
338
339 offset -= 2;
340
341 int i = 0;
342 for (struct pseudofs_dirent *e = _dirent; e; e = e->next) {
343 /* .. was made up above */
344 if (e->d_name == dotdot)
345 continue;
346
347 if (i == offset) {
348 found = 1;
349 dirent->d_ino = e->d_ino->ino;
350 pseudofs_dirent_name(dirent, e->d_name);
351 break;
352 }
353 ++i;
354 }
355
356 return found;
357}
358
367int pseudofs_finddir(struct vnode *dir, const char *name, struct dirent *dirent)
368{
369 if (!dir || !name || !dirent)
370 return -EINVAL;
371
372 if (!S_ISDIR(dir->mode))
373 return -ENOTDIR;
374
375 struct pseudofs_dirent *_dirent = (struct pseudofs_dirent *) dir->p;
376 if (!_dirent) return -ENOENT;
377
378 for (struct pseudofs_dirent *e = _dirent; e; e = e->next) {
379 if (!strcmp(name, e->d_name)) {
380 dirent->d_ino = e->d_ino->ino;
381 pseudofs_dirent_name(dirent, e->d_name);
382 return 0;
383 }
384 }
385
386 return -ENOENT;
387}
388
398{
400 kfree(vnode);
401 return 0;
402}
int vfs_close(struct vnode *vnode)
Drops a reference to a vnode.
Definition close.c:18
void vnode_pages_free(struct vnode *vnode)
Frees a vnode's vm object and its cached pages, when the vnode itself is freed.
Definition vm_object.c:172
#define MALLOC_DEFINE(type, _name, _desc)
Definition kvmem.h:30
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
#define M_ZERO
Definition kvmem.h:26
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
static int dotdot(struct vnode *dir, struct uio *uio, struct vnode **ref)
Finds where .. goes from dir during a walk, up through mounts; the walk's root's ....
Definition lookup.c:107
int pseudofs_setattr(struct vnode *vnode)
Stores a vnode's attributes: there's nothing to do, since they only live in the vnode.
Definition pseudofs.c:306
int pseudofs_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
Makes a node in a directory: a new vnode, owned by the caller, and an entry for it.
Definition pseudofs.c:49
int pseudofs_finddir(struct vnode *dir, const char *name, struct dirent *dirent)
Finds the entry of a directory that has a name.
Definition pseudofs.c:367
int pseudofs_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
Adds an entry for an existing vnode (a hard link) to a directory.
Definition pseudofs.c:211
int pseudofs_close(struct vnode *vnode)
Frees a vnode that has no names or references left, and its cached pages.
Definition pseudofs.c:397
int pseudofs_vunlink(struct vnode *vnode, const char *fn, struct uio *uio)
Removes an entry from a directory.
Definition pseudofs.c:186
ssize_t pseudofs_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)
Reads a directory's entry at an offset.
Definition pseudofs.c:320
static void entry_remove(struct vnode *dir, struct pseudofs_dirent *entry, struct pseudofs_dirent *prev)
Removes entry (which comes after prev) from directory dir, and drops a link to its vnode,...
Definition pseudofs.c:150
static struct pseudofs_dirent * entry_find(struct vnode *dir, const char *fn, struct pseudofs_dirent **prev)
Finds the entry fn of directory dir, and the entry before it in *prev (NULL if it's the first).
Definition pseudofs.c:134
int pseudofs_vrename(struct vnode *odir, const char *ofn, struct vnode *ndir, const char *nfn, struct uio *uio)
Renames an entry, possibly to another directory, replacing an entry at the new name.
Definition pseudofs.c:250
static void pseudofs_dirent_name(struct dirent *dirent, const char *name)
Copies an entry's name into a struct dirent, cut to fit.
Definition pseudofs.c:26
#define NULL
Definition stddef.h:27
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
A directory entry, kept in memory.
Definition pseudofs.h:10
struct vnode * d_ino
Definition pseudofs.h:12
const char * d_name
Definition pseudofs.h:11
struct pseudofs_dirent * next
Definition pseudofs.h:14
Who does a filesystem operation: where its paths start, and its credentials and umask.
Definition vfs.h:60
gid_t gid
Definition vfs.h:64
uid_t uid
Definition vfs.h:63
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
ino_t ino
Definition vfs.h:114
_time_t atime
Definition vfs.h:123
_time_t ctime
Definition vfs.h:125
size_t ref
how many references there are to it
Definition vfs.h:133
nlink_t nlink
Definition vfs.h:121
struct fs * fs
Definition vfs.h:127
_time_t mtime
Definition vfs.h:124
gid_t gid
Definition vfs.h:120
size_t size
Definition vfs.h:115
void * p
the filesystem's own data
Definition vfs.h:130
mode_t mode
Definition vfs.h:118
uid_t uid
Definition vfs.h:119
dev_t rdev
Definition vfs.h:117
int gettime(struct timespec *ts)
Reads the wall clock (CLOCK_REALTIME).
Definition time.c:29
uint16_t dev_t
Definition types.h:18
uintptr_t ino_t
Definition types.h:23
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10
uint32_t mode_t
Definition types.h:15