AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
lookup.c
Go to the documentation of this file.
1
27
28#include <core/system.h>
29#include <core/string.h>
30#include <fs/vfs.h>
31#include <aquila/fcntl.h>
32
33/* the most symbolic links followed in a lookup (POSIX SYMLOOP_MAX) */
34#define SYMLOOP_MAX 8
35
36/* the longest component (POSIX NAME_MAX) */
37#define NAME_MAX 255
38
39/* a walk() flag: stop at the last component, with its directory and its
40 * name */
41#define WALK_PARENT 1
42
44static struct vnode *vref(struct vnode *vnode)
45{
46 vnode->ref++;
47 return vnode;
48}
49
52static struct vnode *walk_root(struct uio *uio)
53{
54 return uio->root ? uio->root : vfs_root;
55}
56
60static struct vnode *cross_down(struct vnode *vnode)
61{
62 while (vnode->mounted) {
63 struct vnode *root = vref(vnode->mounted);
65 vnode = root;
66 }
67
68 return vnode;
69}
70
80int vfs_parent(struct vnode *dir, struct vnode **ref)
81{
82 struct dirent dirent;
83 struct vnode *parent = NULL;
84 int err;
85
86 *ref = NULL;
87
88 /* no .. entry: it's a root */
89 if (vfs_finddir(dir, "..", &dirent))
90 return 0;
91
92 if ((err = vfs_vget(dir, dirent.d_ino, &parent)))
93 return err;
94
95 /* a root's .. is itself */
96 if (parent == dir) {
97 vfs_close(parent);
98 return 0;
99 }
100
101 *ref = parent;
102 return 0;
103}
104
107static int dotdot(struct vnode *dir, struct uio *uio, struct vnode **ref)
108{
109 struct vnode *root = walk_root(uio), *d = dir, *parent;
110 int err;
111
112 /* from the root of a mounted filesystem, go to where it's mounted */
113 while (d != root && d->covered)
114 d = d->covered;
115
116 if (d == root) {
117 *ref = vref(dir);
118 return 0;
119 }
120
121 if ((err = vfs_parent(d, &parent)))
122 return err;
123
124 /* a filesystem's root that is mounted nowhere: go no further */
125 *ref = parent ? cross_down(parent) : vref(dir);
126 return 0;
127}
128
131static int lookup_name(struct vnode *dir, const char *name, size_t len, struct vnode **ref)
132{
133 char buf[NAME_MAX + 1];
134 struct dirent dirent;
135 struct vnode *vnode;
136 int err;
137
138 if (len > NAME_MAX)
139 return -ENAMETOOLONG;
140
141 memcpy(buf, name, len);
142 buf[len] = '\0';
143
144 if ((err = vfs_finddir(dir, buf, &dirent)))
145 return err;
146
147 if ((err = vfs_vget(dir, dirent.d_ino, &vnode)))
148 return err;
149
150 *ref = cross_down(vnode);
151 return 0;
152}
153
158static char *link_path(struct vnode *link, const char *rest, int *err)
159{
160 char *path = kmalloc(1024 + strlen(rest), &M_BUFFER, 0);
161
162 if (!path) {
163 *err = -ENOMEM;
164 return NULL;
165 }
166
167 ssize_t len = vfs_read(link, 0, 1023, path);
168
169 if (len <= 0) {
170 *err = len < 0 ? len : -ENOENT;
171 kfree(path);
172 return NULL;
173 }
174
175 path[len] = '\0';
176 strcpy(path + len, rest);
177 return path;
178}
179
182static int is_dot(const char *c, size_t len)
183{
184 return len == 1 && c[0] == '.';
185}
186
188static int is_dotdot(const char *c, size_t len)
189{
190 return len == 2 && c[0] == '.' && c[1] == '.';
191}
192
204static int walk(struct vnode *dir, const char *path, struct uio *uio, int flags, int *links,
205 struct vnode **ref, char **name, struct vnode **where)
206{
207 const char *p = path;
208 int err = 0;
209
210 if (*p == '/') {
211 vfs_close(dir);
212 dir = vref(walk_root(uio));
213 }
214
215 for (;;) {
216 while (*p == '/')
217 ++p;
218
219 if (!*p)
220 break;
221
222 /* the component c (len bytes); whether it's the last one, and
223 * whether a slash comes after it */
224 const char *c = p;
225 size_t len = 0;
226
227 while (c[len] && c[len] != '/')
228 ++len;
229
230 p += len;
231
232 const char *rest = p;
233 while (*rest == '/')
234 ++rest;
235
236 int last = !*rest, slash = *p == '/';
237
238 if (!S_ISDIR(dir->mode)) {
239 err = -ENOTDIR;
240 break;
241 }
242
243 if ((flags & WALK_PARENT) && last) {
244 if (is_dot(c, len) || is_dotdot(c, len)) {
245 err = -EINVAL;
246 break;
247 }
248
249 if (len > NAME_MAX) {
250 err = -ENAMETOOLONG;
251 break;
252 }
253
254 if (!(*name = kmalloc(len + 1, &M_BUFFER, 0))) {
255 err = -ENOMEM;
256 break;
257 }
258
259 memcpy(*name, c, len);
260 (*name)[len] = '\0';
261
262 *ref = dir;
263 return 0;
264 }
265
266 /* searching the directory needs its x permission */
267 if ((err = vfs_access(dir, uio, VFS_X)))
268 break;
269
270 struct vnode *next = NULL;
271
272 if (is_dot(c, len))
273 next = vref(dir);
274 else if (is_dotdot(c, len))
275 err = dotdot(dir, uio, &next);
276 else
277 err = lookup_name(dir, c, len, &next);
278
279 if (err)
280 break;
281
282 if (S_ISLNK(next->mode) && (!last || slash || !(uio->flags & O_NOFOLLOW))) {
283 if (++*links > SYMLOOP_MAX) {
284 vfs_close(next);
285 err = -ELOOP;
286 break;
287 }
288
289 char *target = link_path(next, p, &err);
290 vfs_close(next);
291
292 if (!target)
293 break;
294
295 /* go on from the link's directory (or from the root, for an
296 * absolute target) */
297 err = walk(dir, target, uio, flags, links, ref, name, where);
298 kfree(target);
299 return err;
300 }
301
302 /* keep the last component's directory for the caller */
303 if (last && where) {
304 if (*where)
305 vfs_close(*where);
306 *where = dir;
307 } else {
308 vfs_close(dir);
309 }
310
311 dir = next;
312
313 if (last && slash && !S_ISDIR(dir->mode)) {
314 err = -ENOTDIR;
315 break;
316 }
317 }
318
319 if (!err && (flags & WALK_PARENT))
320 err = -EBUSY;
321
322 if (err) {
323 vfs_close(dir);
324 return err;
325 }
326
327 *ref = dir;
328 return 0;
329}
330
333static struct vnode *walk_start(struct uio *uio)
334{
335 return vref(uio->cwd ? uio->cwd : walk_root(uio));
336}
337
349int vfs_lookup(const char *path, struct uio *uio, struct vnode **ref)
350{
351 vfs_log(LOG_DEBUG, "vfs_lookup(path=%s, uio=%p, ref=%p)\n", path, uio, ref);
352
353 struct vnode *vnode;
354 int links = 0, err;
355
356 if (!path || !*path)
357 return -ENOENT;
358
359 if ((err = walk(walk_start(uio), path, uio, 0, &links, &vnode, NULL, NULL)))
360 return err;
361
362 if (ref)
363 *ref = vnode;
364 else
366
367 return 0;
368}
369
381int vfs_lookup_dir(const char *path, struct uio *uio, struct vnode **ref, struct vnode **dir)
382{
383 struct vnode *vnode, *where = NULL;
384 int links = 0, err;
385
386 if (!path || !*path)
387 return -ENOENT;
388
389 if ((err = walk(walk_start(uio), path, uio, 0, &links, &vnode, NULL, &where))) {
390 if (where)
391 vfs_close(where);
392 return err;
393 }
394
395 if (!where)
396 where = vref(vnode);
397
398 *ref = vnode;
399 *dir = where;
400 return 0;
401}
402
414int vfs_lookup_parent(const char *path, struct uio *uio, struct vnode **dir, char **name)
415{
416 struct vnode *vnode = NULL;
417 char *last = NULL;
418 int links = 0, err;
419
420 if (!path || !*path)
421 return -ENOENT;
422
423 if ((err = walk(walk_start(uio), path, uio, WALK_PARENT, &links, &vnode, &last, NULL)))
424 return err;
425
426 /* a mount point: its entry is covered by the mounted filesystem */
427 struct dirent dirent;
428 struct vnode *entry;
429
430 if (!vfs_finddir(vnode, last, &dirent) && !vfs_vget(vnode, dirent.d_ino, &entry)) {
431 int covered = entry->mounted != NULL;
432 vfs_close(entry);
433
434 if (covered) {
436 kfree(last);
437 return -EBUSY;
438 }
439 }
440
441 *dir = vnode;
442 *name = last;
443 return 0;
444}
445
453{
454 struct vnode *cur = vref(vnode), *parent;
455
456 while (cur != vfs_root && !cur->covered && !vfs_parent(cur, &parent) && parent) {
457 vfs_close(cur);
458 cur = parent;
459 }
460
461 vfs_close(cur);
462 return cur;
463}
464
473int vfs_under(struct vnode *vnode, struct vnode *dir)
474{
475 struct vnode *cur = vref(vnode), *parent;
476 int under = 0;
477
478 for (;;) {
479 if (cur == dir) {
480 under = 1;
481 break;
482 }
483
484 if (vfs_parent(cur, &parent) || !parent)
485 break;
486
487 vfs_close(cur);
488 cur = parent;
489 }
490
491 vfs_close(cur);
492 return under;
493}
494
498static int entry_name(struct vnode *parent, struct vnode *child, char *name)
499{
500 struct dirent dirent, found;
501 off_t off = 0;
502 ssize_t r;
503
504 while ((r = vfs_readdir(parent, off, &dirent)) > 0) {
505 off += r;
506
507 if (!strcmp(dirent.d_name, ".") || !strcmp(dirent.d_name, ".."))
508 continue;
509
510 /* compare the entry's inode number as finddir has it (readdir
511 * may not fill it in) */
512 if (!vfs_finddir(parent, dirent.d_name, &found) && found.d_ino == child->ino) {
513 strcpy(name, dirent.d_name);
514 return 0;
515 }
516 }
517
518 return r < 0 ? r : -ENOENT;
519}
520
532int vfs_vnode_path(struct vnode *vnode, struct vnode *root, char *buf, size_t size)
533{
534 char name[NAME_MAX + 1];
535 struct vnode *cur = vref(vnode), *parent;
536 size_t pos = size;
537 int err = 0;
538
539 if (!root)
540 root = vfs_root;
541
542 if (!size)
543 return -ERANGE;
544
545 buf[--pos] = '\0';
546
547 for (;;) {
548 /* from the root of a mounted filesystem, go to the directory it's
549 * mounted on */
550 while (cur != root && cur->covered) {
551 struct vnode *covered = vref(cur->covered);
552 vfs_close(cur);
553 cur = covered;
554 }
555
556 if (cur == root)
557 break;
558
559 if ((err = vfs_parent(cur, &parent)))
560 break;
561
562 /* a filesystem's root that is mounted nowhere: stop */
563 if (!parent)
564 break;
565
566 if ((err = entry_name(parent, cur, name))) {
567 vfs_close(parent);
568 break;
569 }
570
571 size_t len = strlen(name);
572
573 if (len + 1 > pos) {
574 vfs_close(parent);
575 err = -ERANGE;
576 break;
577 }
578
579 pos -= len;
580 memcpy(buf + pos, name, len);
581 buf[--pos] = '/';
582
583 vfs_close(cur);
584 cur = parent;
585 }
586
587 vfs_close(cur);
588
589 if (err)
590 return err;
591
592 /* the root itself is "/" */
593 if (!buf[pos]) {
594 if (!pos)
595 return -ERANGE;
596
597 buf[--pos] = '/';
598 }
599
600 memmove(buf, buf + pos, size - pos);
601 return 0;
602}
int vfs_close(struct vnode *vnode)
Drops a reference to a vnode.
Definition close.c:18
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memmove(void *dst, const void *src, size_t n)
Copies n bytes; dst and src may overlap.
Definition libc.c:34
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 is_dotdot(const char *c, size_t len)
Says whether a component (len bytes) is ...
Definition lookup.c:188
static struct vnode * walk_root(struct uio *uio)
Returns where absolute paths start: the process's root directory, or the system's.
Definition lookup.c:52
static struct vnode * walk_start(struct uio *uio)
Returns where a relative path starts (with a reference): the current directory.
Definition lookup.c:333
int vfs_lookup_dir(const char *path, struct uio *uio, struct vnode **ref, struct vnode **dir)
Finds the vnode a path names, as vfs_lookup() does, and the directory it was found in.
Definition lookup.c:381
static int walk(struct vnode *dir, const char *path, struct uio *uio, int flags, int *links, struct vnode **ref, char **name, struct vnode **where)
Walks path from dir, whose reference the walk takes.
Definition lookup.c:204
static int entry_name(struct vnode *parent, struct vnode *child, char *name)
Finds the name child has in parent (into name, NAME_MAX + 1 bytes).
Definition lookup.c:498
#define SYMLOOP_MAX
Definition lookup.c:34
#define WALK_PARENT
Definition lookup.c:41
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
static char * link_path(struct vnode *link, const char *rest, int *err)
Returns the path a walk goes on with at a symbolic link: the link's target, then rest (what's left of...
Definition lookup.c:158
static int is_dot(const char *c, size_t len)
Says whether a path component of len bytes is a single dot, the name of a directory itself.
Definition lookup.c:182
int vfs_lookup_parent(const char *path, struct uio *uio, struct vnode **dir, char **name)
Finds the directory of a path's last component, and the component's name, to make or remove an entry ...
Definition lookup.c:414
struct vnode * vfs_mount_root_of(struct vnode *vnode)
Finds the root of the mounted filesystem a vnode is in.
Definition lookup.c:452
int vfs_under(struct vnode *vnode, struct vnode *dir)
Says whether a vnode is a directory or under it, in the same filesystem: rename() can't move a direct...
Definition lookup.c:473
int vfs_lookup(const char *path, struct uio *uio, struct vnode **ref)
Finds the vnode a path names.
Definition lookup.c:349
int vfs_vnode_path(struct vnode *vnode, struct vnode *root, char *buf, size_t size)
Computes a vnode's path, for getcwd() and /proc/mounts: it goes up through .., and finds each directo...
Definition lookup.c:532
#define NAME_MAX
Definition lookup.c:37
int vfs_parent(struct vnode *dir, struct vnode **ref)
Finds a directory's parent in its own filesystem, through its .. entry.
Definition lookup.c:80
static struct vnode * vref(struct vnode *vnode)
Adds a reference to a vnode, and returns it.
Definition lookup.c:44
static int lookup_name(struct vnode *dir, const char *name, size_t len, struct vnode **ref)
Finds the entry name (len bytes) of dir, and crosses into what is mounted on it.
Definition lookup.c:131
static struct vnode * cross_down(struct vnode *vnode)
Returns the root of what's mounted on vnode (all the way down, if a mount is mounted on too),...
Definition lookup.c:60
#define LOG_DEBUG
Definition printk.h:19
ssize_t vfs_read(struct vnode *vnode, off_t off, size_t size, void *buf)
Reads from a vnode into a kernel buffer.
Definition read.c:52
int vfs_finddir(struct vnode *dir, const char *name, struct dirent *dirent)
Finds the entry of a directory that has a name.
Definition readdir.c:46
ssize_t vfs_readdir(struct vnode *dir, off_t off, struct dirent *dirent)
Reads a directory's entry at an offset.
Definition readdir.c:19
#define NULL
Definition stddef.h:27
Who does a filesystem operation: where its paths start, and its credentials and umask.
Definition vfs.h:60
struct vnode * cwd
Definition vfs.h:62
struct vnode * root
Definition vfs.h:61
uint32_t flags
Definition vfs.h:66
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
struct vnode * covered
Definition vfs.h:149
ino_t ino
Definition vfs.h:114
size_t ref
how many references there are to it
Definition vfs.h:133
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
struct vnode * mounted
for a directory that a filesystem is mounted on, that filesystem's root; for a mounted filesystem's r...
Definition vfs.h:148
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10
int vfs_access(struct vnode *vnode, struct uio *uio, int mode)
Checks whether a user may access a vnode in a way: the owner's permissions apply to its owner,...
Definition vfs.c:114
struct vnode * vfs_root
Definition vfs.c:29
#define VFS_X
Definition vfs.h:297
int vfs_vget(struct vnode *super, ino_t ino, struct vnode **ref)
Gets the vnode of an inode, by its number.
Definition vops.c:176