minor fixes for safecopy & safemap tests
[minix.git] / servers / vfs / path.c
blobc19f1e1353f74465cadbcaa555eb708f4b105dd9
1 /* lookup() is the main routine that controls the path name lookup. It
2 * handles mountpoints and symbolic links. The actual lookup requests
3 * are sent through the req_lookup wrapper function.
4 */
6 #include "fs.h"
7 #include <string.h>
8 #include <minix/callnr.h>
9 #include <minix/com.h>
10 #include <minix/keymap.h>
11 #include <minix/const.h>
12 #include <minix/endpoint.h>
13 #include <stddef.h>
14 #include <unistd.h>
15 #include <assert.h>
16 #include <minix/vfsif.h>
17 #include <sys/param.h>
18 #include <sys/stat.h>
19 #include <sys/un.h>
20 #include <dirent.h>
21 #include "threads.h"
22 #include "vmnt.h"
23 #include "vnode.h"
24 #include "path.h"
25 #include "fproc.h"
26 #include "param.h"
28 /* Set to following define to 1 if you really want to use the POSIX definition
29 * (IEEE Std 1003.1, 2004) of pathname resolution. POSIX requires pathnames
30 * with a traling slash (and that do not entirely consist of slash characters)
31 * to be treated as if a single dot is appended. This means that for example
32 * mkdir("dir/", ...) and rmdir("dir/") will fail because the call tries to
33 * create or remove the directory '.'. Historically, Unix systems just ignore
34 * trailing slashes.
36 #define DO_POSIX_PATHNAME_RES 0
38 static int lookup(struct vnode *dirp, struct lookup *resolve,
39 node_details_t *node, struct fproc *rfp);
40 static int check_perms(endpoint_t ep, cp_grant_id_t io_gr, size_t
41 pathlen);
43 /*===========================================================================*
44 * advance *
45 *===========================================================================*/
46 struct vnode *advance(dirp, resolve, rfp)
47 struct vnode *dirp;
48 struct lookup *resolve;
49 struct fproc *rfp;
51 /* Resolve a path name starting at dirp to a vnode. */
52 int r;
53 int do_downgrade = 1;
54 struct vnode *new_vp, *vp;
55 struct vmnt *vmp;
56 struct node_details res = {0,0,0,0,0,0,0};
57 tll_access_t initial_locktype;
59 assert(dirp);
60 assert(resolve->l_vnode_lock != TLL_NONE);
61 assert(resolve->l_vmnt_lock != TLL_NONE);
63 if (resolve->l_vnode_lock == VNODE_READ)
64 initial_locktype = VNODE_OPCL;
65 else
66 initial_locktype = resolve->l_vnode_lock;
68 /* Get a free vnode and lock it */
69 if ((new_vp = get_free_vnode()) == NULL) return(NULL);
70 lock_vnode(new_vp, initial_locktype);
72 /* Lookup vnode belonging to the file. */
73 if ((r = lookup(dirp, resolve, &res, rfp)) != OK) {
74 err_code = r;
75 unlock_vnode(new_vp);
76 return(NULL);
79 /* Check whether we already have a vnode for that file */
80 if ((vp = find_vnode(res.fs_e, res.inode_nr)) != NULL) {
81 unlock_vnode(new_vp); /* Don't need this anymore */
82 do_downgrade = (lock_vnode(vp, initial_locktype) != EBUSY);
84 /* Unfortunately, by the time we get the lock, another thread might've
85 * rid of the vnode (e.g., find_vnode found the vnode while a
86 * req_putnode was being processed). */
87 if (vp->v_ref_count == 0) { /* vnode vanished! */
88 /* As the lookup before increased the usage counters in the FS,
89 * we can simply set the usage counters to 1 and proceed as
90 * normal, because the putnode resulted in a use count of 1 in
91 * the FS. Other data is still valid, because the vnode was
92 * marked as pending lock, so get_free_vnode hasn't
93 * reinitialized the vnode yet. */
94 vp->v_fs_count = 1;
95 if (vp->v_mapfs_e != NONE) vp->v_mapfs_count = 1;
96 } else {
97 vp->v_fs_count++; /* We got a reference from the FS */
100 } else {
101 /* Vnode not found, fill in the free vnode's fields */
103 new_vp->v_fs_e = res.fs_e;
104 new_vp->v_inode_nr = res.inode_nr;
105 new_vp->v_mode = res.fmode;
106 new_vp->v_size = res.fsize;
107 new_vp->v_uid = res.uid;
108 new_vp->v_gid = res.gid;
109 new_vp->v_sdev = res.dev;
111 if( (vmp = find_vmnt(new_vp->v_fs_e)) == NULL)
112 panic("advance: vmnt not found");
114 new_vp->v_vmnt = vmp;
115 new_vp->v_dev = vmp->m_dev;
116 new_vp->v_fs_count = 1;
118 vp = new_vp;
121 dup_vnode(vp);
122 if (do_downgrade) {
123 /* Only downgrade a lock if we managed to lock it in the first place */
124 *(resolve->l_vnode) = vp;
126 if (initial_locktype != resolve->l_vnode_lock)
127 tll_downgrade(&vp->v_lock);
129 #if LOCK_DEBUG
130 if (resolve->l_vnode_lock == VNODE_READ)
131 fp->fp_vp_rdlocks++;
132 #endif
135 return(vp);
138 /*===========================================================================*
139 * eat_path *
140 *===========================================================================*/
141 struct vnode *eat_path(resolve, rfp)
142 struct lookup *resolve;
143 struct fproc *rfp;
145 /* Resolve path to a vnode. advance does the actual work. */
146 struct vnode *start_dir;
148 start_dir = (resolve->l_path[0] == '/' ? rfp->fp_rd : rfp->fp_wd);
149 return advance(start_dir, resolve, rfp);
152 /*===========================================================================*
153 * last_dir *
154 *===========================================================================*/
155 struct vnode *last_dir(resolve, rfp)
156 struct lookup *resolve;
157 struct fproc *rfp;
159 /* Parse a path, as far as the last directory, fetch the vnode
160 * for the last directory into the vnode table, and return a pointer to the
161 * vnode. In addition, return the final component of the path in 'string'. If
162 * the last directory can't be opened, return NULL and the reason for
163 * failure in 'err_code'. We can't parse component by component as that would
164 * be too expensive. Alternatively, we cut off the last component of the path,
165 * and parse the path up to the penultimate component.
168 size_t len;
169 char *cp;
170 char dir_entry[NAME_MAX+1];
171 struct vnode *start_dir, *res_vp, *sym_vp, *loop_start;
172 struct vmnt *sym_vmp = NULL;
173 int r, symloop = 0, ret_on_symlink = 0;
174 struct lookup symlink;
176 *resolve->l_vnode = NULL;
177 *resolve->l_vmp = NULL;
178 loop_start = NULL;
179 sym_vp = NULL;
181 ret_on_symlink = !!(resolve->l_flags & PATH_RET_SYMLINK);
183 do {
184 /* Is the path absolute or relative? Initialize 'start_dir'
185 * accordingly. Use loop_start in case we're looping.
187 if (loop_start != NULL)
188 start_dir = loop_start;
189 else
190 start_dir = (resolve->l_path[0] == '/' ? rfp->fp_rd:rfp->fp_wd);
192 len = strlen(resolve->l_path);
194 /* If path is empty, return ENOENT. */
195 if (len == 0) {
196 err_code = ENOENT;
197 res_vp = NULL;
198 break;
201 #if !DO_POSIX_PATHNAME_RES
202 /* Remove trailing slashes */
203 while (len > 1 && resolve->l_path[len-1] == '/') {
204 len--;
205 resolve->l_path[len]= '\0';
207 #endif
209 cp = strrchr(resolve->l_path, '/');
210 if (cp == NULL) {
211 /* Just an entry in the current working directory. Prepend
212 * "./" in front of the path and resolve it.
214 if (strlcpy(dir_entry, resolve->l_path, NAME_MAX+1) >= NAME_MAX + 1) {
215 err_code = ENAMETOOLONG;
216 res_vp = NULL;
217 break;
219 dir_entry[NAME_MAX] = '\0';
220 resolve->l_path[0] = '.';
221 resolve->l_path[1] = '\0';
222 } else if (cp[1] == '\0') {
223 /* Path ends in a slash. The directory entry is '.' */
224 strlcpy(dir_entry, ".", NAME_MAX+1);
225 } else {
226 /* A path name for the directory and a directory entry */
227 if (strlcpy(dir_entry, cp+1, NAME_MAX+1) >= NAME_MAX + 1) {
228 err_code = ENAMETOOLONG;
229 res_vp = NULL;
230 break;
232 cp[1] = '\0';
233 dir_entry[NAME_MAX] = '\0';
236 /* Remove trailing slashes */
237 while (cp > resolve->l_path && cp[0] == '/') {
238 cp[0]= '\0';
239 cp--;
242 /* Resolve up to and including the last directory of the path. Turn off
243 * PATH_RET_SYMLINK, because we do want to follow the symlink in this
244 * case. That is, the flag is meant for the actual filename of the path,
245 * not the last directory.
247 resolve->l_flags &= ~PATH_RET_SYMLINK;
248 if ((res_vp = advance(start_dir, resolve, rfp)) == NULL) {
249 break;
252 /* If the directory entry is not a symlink we're done now. If it is a
253 * symlink, then we're not at the last directory, yet. */
255 /* Copy the directory entry back to user_fullpath */
256 strlcpy(resolve->l_path, dir_entry, NAME_MAX + 1);
258 /* Look up the directory entry, but do not follow the symlink when it
259 * is one.
261 lookup_init(&symlink, resolve->l_path,
262 resolve->l_flags|PATH_RET_SYMLINK, &sym_vmp, &sym_vp);
263 symlink.l_vnode_lock = VNODE_READ;
264 symlink.l_vmnt_lock = VMNT_READ;
265 sym_vp = advance(res_vp, &symlink, rfp);
267 if (sym_vp != NULL && S_ISLNK(sym_vp->v_mode)) {
268 /* Last component is a symlink, but if we've been asked to not
269 * resolve it, return now.
271 if (ret_on_symlink) {
272 break;
275 r = req_rdlink(sym_vp->v_fs_e, sym_vp->v_inode_nr, NONE,
276 (vir_bytes) resolve->l_path, PATH_MAX - 1, 1);
278 if (r < 0) {
279 /* Failed to read link */
280 err_code = r;
281 unlock_vnode(res_vp);
282 unlock_vmnt(*resolve->l_vmp);
283 put_vnode(res_vp);
284 *resolve->l_vmp = NULL;
285 *resolve->l_vnode = NULL;
286 res_vp = NULL;
287 break;
289 resolve->l_path[r] = '\0';
291 if (strrchr(resolve->l_path, '/') != NULL) {
292 unlock_vnode(sym_vp);
293 unlock_vmnt(*resolve->l_vmp);
294 if (sym_vmp != NULL)
295 unlock_vmnt(sym_vmp);
296 *resolve->l_vmp = NULL;
297 put_vnode(sym_vp);
298 sym_vp = NULL;
300 symloop++;
302 /* Relative symlinks are relative to res_vp, not cwd */
303 if (resolve->l_path[0] != '/') {
304 loop_start = res_vp;
305 } else {
306 /* Absolute symlink, forget about res_vp */
307 unlock_vnode(res_vp);
308 put_vnode(res_vp);
311 continue;
314 break;
315 } while (symloop < SYMLOOP_MAX);
317 if (symloop >= SYMLOOP_MAX) {
318 err_code = ELOOP;
319 res_vp = NULL;
322 if (sym_vp != NULL) {
323 unlock_vnode(sym_vp);
324 if (sym_vmp != NULL) {
325 unlock_vmnt(sym_vmp);
327 put_vnode(sym_vp);
330 if (loop_start != NULL) {
331 unlock_vnode(loop_start);
332 put_vnode(loop_start);
335 /* Copy the directory entry back to user_fullpath */
336 strlcpy(resolve->l_path, dir_entry, NAME_MAX + 1);
338 /* Turn PATH_RET_SYMLINK flag back on if it was on */
339 if (ret_on_symlink) resolve->l_flags |= PATH_RET_SYMLINK;
341 return(res_vp);
344 /*===========================================================================*
345 * lookup *
346 *===========================================================================*/
347 static int lookup(start_node, resolve, result_node, rfp)
348 struct vnode *start_node;
349 struct lookup *resolve;
350 node_details_t *result_node;
351 struct fproc *rfp;
353 /* Resolve a path name relative to start_node. */
355 int r, symloop;
356 endpoint_t fs_e;
357 size_t path_off, path_left_len;
358 ino_t dir_ino, root_ino;
359 uid_t uid;
360 gid_t gid;
361 struct vnode *dir_vp;
362 struct vmnt *vmp, *vmpres;
363 struct lookup_res res;
365 assert(resolve->l_vmp);
366 assert(resolve->l_vnode);
368 *(resolve->l_vmp) = vmpres = NULL; /* No vmnt found nor locked yet */
370 /* Empty (start) path? */
371 if (resolve->l_path[0] == '\0') {
372 result_node->inode_nr = 0;
373 return(ENOENT);
376 if (!rfp->fp_rd || !rfp->fp_wd) {
377 printf("VFS: lookup %d: no rd/wd\n", rfp->fp_endpoint);
378 return(ENOENT);
381 fs_e = start_node->v_fs_e;
382 dir_ino = start_node->v_inode_nr;
383 vmpres = find_vmnt(fs_e);
385 if (vmpres == NULL) return(EIO); /* mountpoint vanished? */
387 /* Is the process' root directory on the same partition?,
388 * if so, set the chroot directory too. */
389 if (rfp->fp_rd->v_dev == rfp->fp_wd->v_dev)
390 root_ino = rfp->fp_rd->v_inode_nr;
391 else
392 root_ino = 0;
394 /* Set user and group ids according to the system call */
395 uid = (job_call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid);
396 gid = (job_call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid);
398 symloop = 0; /* Number of symlinks seen so far */
400 /* Lock vmnt */
401 if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) {
402 if (r == EBUSY) /* vmnt already locked */
403 vmpres = NULL;
404 else
405 return(r);
407 *(resolve->l_vmp) = vmpres;
409 /* Issue the request */
410 r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, resolve, &res, rfp);
412 if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) {
413 if (vmpres) unlock_vmnt(vmpres);
414 *(resolve->l_vmp) = NULL;
415 return(r); /* i.e., an error occured */
418 /* While the response is related to mount control set the
419 * new requests respectively */
420 while (r == EENTERMOUNT || r == ELEAVEMOUNT || r == ESYMLINK) {
421 /* Update user_fullpath to reflect what's left to be parsed. */
422 path_off = res.char_processed;
423 path_left_len = strlen(&resolve->l_path[path_off]);
424 memmove(resolve->l_path, &resolve->l_path[path_off], path_left_len);
425 resolve->l_path[path_left_len] = '\0'; /* terminate string */
427 /* Update the current value of the symloop counter */
428 symloop += res.symloop;
429 if (symloop > SYMLOOP_MAX) {
430 if (vmpres) unlock_vmnt(vmpres);
431 *(resolve->l_vmp) = NULL;
432 return(ELOOP);
435 /* Symlink encountered with absolute path */
436 if (r == ESYMLINK) {
437 dir_vp = rfp->fp_rd;
438 vmp = NULL;
439 } else if (r == EENTERMOUNT) {
440 /* Entering a new partition */
441 dir_vp = NULL;
442 /* Start node is now the mounted partition's root node */
443 for (vmp = &vmnt[0]; vmp != &vmnt[NR_MNTS]; ++vmp) {
444 if (vmp->m_dev != NO_DEV && vmp->m_mounted_on) {
445 if (vmp->m_mounted_on->v_inode_nr == res.inode_nr &&
446 vmp->m_mounted_on->v_fs_e == res.fs_e) {
447 dir_vp = vmp->m_root_node;
448 break;
452 if (dir_vp == NULL) {
453 printf("VFS: path lookup error; root node not found\n");
454 if (vmpres) unlock_vmnt(vmpres);
455 *(resolve->l_vmp) = NULL;
456 return(EIO);
458 } else {
459 /* Climbing up mount */
460 /* Find the vmnt that represents the partition on
461 * which we "climb up". */
462 if ((vmp = find_vmnt(res.fs_e)) == NULL) {
463 panic("VFS lookup: can't find parent vmnt");
466 /* Make sure that the child FS does not feed a bogus path
467 * to the parent FS. That is, when we climb up the tree, we
468 * must've encountered ".." in the path, and that is exactly
469 * what we're going to feed to the parent */
470 if(strncmp(resolve->l_path, "..", 2) != 0 ||
471 (resolve->l_path[2] != '\0' && resolve->l_path[2] != '/')) {
472 printf("VFS: bogus path: %s\n", resolve->l_path);
473 if (vmpres) unlock_vmnt(vmpres);
474 *(resolve->l_vmp) = NULL;
475 return(ENOENT);
478 /* Start node is the vnode on which the partition is
479 * mounted */
480 dir_vp = vmp->m_mounted_on;
483 /* Set the starting directories inode number and FS endpoint */
484 fs_e = dir_vp->v_fs_e;
485 dir_ino = dir_vp->v_inode_nr;
487 /* Is the process' root directory on the same partition?,
488 * if so, set the chroot directory too. */
489 if (dir_vp->v_dev == rfp->fp_rd->v_dev)
490 root_ino = rfp->fp_rd->v_inode_nr;
491 else
492 root_ino = 0;
494 /* Unlock a previously locked vmnt if locked and lock new vmnt */
495 if (vmpres) unlock_vmnt(vmpres);
496 vmpres = find_vmnt(fs_e);
497 if (vmpres == NULL) return(EIO); /* mount point vanished? */
498 if ((r = lock_vmnt(vmpres, resolve->l_vmnt_lock)) != OK) {
499 if (r == EBUSY)
500 vmpres = NULL; /* Already locked */
501 else
502 return(r);
504 *(resolve->l_vmp) = vmpres;
506 r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, resolve, &res, rfp);
508 if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) {
509 if (vmpres) unlock_vmnt(vmpres);
510 *(resolve->l_vmp) = NULL;
511 return(r);
515 /* Fill in response fields */
516 result_node->inode_nr = res.inode_nr;
517 result_node->fmode = res.fmode;
518 result_node->fsize = res.fsize;
519 result_node->dev = res.dev;
520 result_node->fs_e = res.fs_e;
521 result_node->uid = res.uid;
522 result_node->gid = res.gid;
524 return(r);
527 /*===========================================================================*
528 * lookup_init *
529 *===========================================================================*/
530 void lookup_init(resolve, path, flags, vmp, vp)
531 struct lookup *resolve;
532 char *path;
533 int flags;
534 struct vmnt **vmp;
535 struct vnode **vp;
537 assert(vmp != NULL);
538 assert(vp != NULL);
540 resolve->l_path = path;
541 resolve->l_flags = flags;
542 resolve->l_vmp = vmp;
543 resolve->l_vnode = vp;
544 resolve->l_vmnt_lock = TLL_NONE;
545 resolve->l_vnode_lock = TLL_NONE;
546 *vmp = NULL; /* Initialize lookup result to NULL */
547 *vp = NULL;
550 /*===========================================================================*
551 * get_name *
552 *===========================================================================*/
553 int get_name(dirp, entry, ename)
554 struct vnode *dirp;
555 struct vnode *entry;
556 char ename[NAME_MAX + 1];
558 #define DIR_ENTRIES 8
559 #define DIR_ENTRY_SIZE (sizeof(struct dirent) + NAME_MAX)
560 u64_t pos, new_pos;
561 int r, consumed, totalbytes, name_len;
562 char buf[DIR_ENTRY_SIZE * DIR_ENTRIES];
563 struct dirent *cur;
565 pos = make64(0, 0);
567 if (!S_ISDIR(dirp->v_mode)) return(EBADF);
569 do {
570 r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, buf, sizeof(buf),
571 &new_pos, 1);
573 if (r == 0) {
574 return(ENOENT); /* end of entries -- matching inode !found */
575 } else if (r < 0) {
576 return(r); /* error */
579 consumed = 0; /* bytes consumed */
580 totalbytes = r; /* number of bytes to consume */
582 do {
583 cur = (struct dirent *) (buf + consumed);
584 name_len = cur->d_reclen - offsetof(struct dirent, d_name) - 1;
586 if(cur->d_name + name_len+1 >= &buf[DIR_ENTRIES*DIR_ENTRY_SIZE])
587 return(EINVAL); /* Rubbish in dir entry */
588 if (entry->v_inode_nr == cur->d_ino) {
589 /* found the entry we were looking for */
590 int copylen = MIN(name_len + 1, NAME_MAX + 1);
591 if (strlcpy(ename, cur->d_name, copylen) >= copylen) {
592 return(ENAMETOOLONG);
594 ename[NAME_MAX] = '\0';
595 return(OK);
598 /* not a match -- move on to the next dirent */
599 consumed += cur->d_reclen;
600 } while (consumed < totalbytes);
602 pos = new_pos;
603 } while (1);
606 /*===========================================================================*
607 * canonical_path *
608 *===========================================================================*/
609 int canonical_path(orig_path, rfp)
610 char orig_path[PATH_MAX];
611 struct fproc *rfp;
613 /* Find canonical path of a given path */
614 int len = 0;
615 int r, symloop = 0;
616 struct vnode *dir_vp, *parent_dir;
617 struct vmnt *dir_vmp, *parent_vmp;
618 char component[NAME_MAX+1]; /* NAME_MAX does /not/ include '\0' */
619 char temp_path[PATH_MAX];
620 struct lookup resolve;
622 dir_vp = NULL;
623 strlcpy(temp_path, orig_path, PATH_MAX);
624 temp_path[PATH_MAX - 1] = '\0';
626 /* First resolve path to the last directory holding the file */
627 do {
628 if (dir_vp) {
629 unlock_vnode(dir_vp);
630 unlock_vmnt(dir_vmp);
631 put_vnode(dir_vp);
634 lookup_init(&resolve, temp_path, PATH_NOFLAGS, &dir_vmp, &dir_vp);
635 resolve.l_vmnt_lock = VMNT_READ;
636 resolve.l_vnode_lock = VNODE_READ;
637 if ((dir_vp = last_dir(&resolve, rfp)) == NULL) return(err_code);
639 /* dir_vp points to dir and resolve path now contains only the
640 * filename.
642 strlcpy(orig_path, temp_path, NAME_MAX+1); /* Store file name */
644 /* check if the file is a symlink, if so resolve it */
645 r = rdlink_direct(orig_path, temp_path, rfp);
647 if (r <= 0)
648 break;
650 /* encountered a symlink -- loop again */
651 strlcpy(orig_path, temp_path, PATH_MAX);
652 symloop++;
653 } while (symloop < SYMLOOP_MAX);
655 if (symloop >= SYMLOOP_MAX) {
656 if (dir_vp) {
657 unlock_vnode(dir_vp);
658 unlock_vmnt(dir_vmp);
659 put_vnode(dir_vp);
661 return(ELOOP);
664 /* We've got the filename and the actual directory holding the file. From
665 * here we start building up the canonical path by climbing up the tree */
666 while (dir_vp != rfp->fp_rd) {
668 strlcpy(temp_path, "..", NAME_MAX+1);
670 /* check if we're at the root node of the file system */
671 if (dir_vp->v_vmnt->m_root_node == dir_vp) {
672 unlock_vnode(dir_vp);
673 unlock_vmnt(dir_vmp);
674 put_vnode(dir_vp);
675 dir_vp = dir_vp->v_vmnt->m_mounted_on;
676 dir_vmp = dir_vp->v_vmnt;
677 if (lock_vmnt(dir_vmp, VMNT_READ) != OK)
678 panic("failed to lock vmnt");
679 if (lock_vnode(dir_vp, VNODE_READ) != OK)
680 panic("failed to lock vnode");
681 dup_vnode(dir_vp);
684 lookup_init(&resolve, temp_path, PATH_NOFLAGS, &parent_vmp,
685 &parent_dir);
686 resolve.l_vmnt_lock = VMNT_READ;
687 resolve.l_vnode_lock = VNODE_READ;
689 if ((parent_dir = advance(dir_vp, &resolve, rfp)) == NULL) {
690 unlock_vnode(dir_vp);
691 unlock_vmnt(dir_vmp);
692 put_vnode(dir_vp);
693 return(err_code);
696 /* now we have to retrieve the name of the parent directory */
697 if (get_name(parent_dir, dir_vp, component) != OK) {
698 unlock_vnode(parent_dir);
699 unlock_vmnt(parent_vmp);
700 unlock_vnode(dir_vp);
701 unlock_vmnt(dir_vmp);
702 put_vnode(parent_dir);
703 put_vnode(dir_vp);
704 return(ENOENT);
707 len += strlen(component) + 1;
708 if (len >= PATH_MAX) {
709 /* adding the component to orig_path would exceed PATH_MAX */
710 unlock_vnode(parent_dir);
711 unlock_vmnt(parent_vmp);
712 unlock_vnode(dir_vp);
713 unlock_vmnt(dir_vmp);
714 put_vnode(parent_dir);
715 put_vnode(dir_vp);
716 return(ENOMEM);
719 /* Store result of component in orig_path. First make space by moving
720 * the contents of orig_path to the right. Move strlen + 1 bytes to
721 * include the terminating '\0'. Move to strlen + 1 bytes to reserve
722 * space for the slash.
724 memmove(orig_path+strlen(component)+1, orig_path, strlen(orig_path)+1);
725 /* Copy component into canon_path */
726 memmove(orig_path, component, strlen(component));
727 /* Put slash into place */
728 orig_path[strlen(component)] = '/';
730 /* Store parent_dir result, and continue the loop once more */
731 unlock_vnode(dir_vp);
732 unlock_vmnt(dir_vmp);
733 put_vnode(dir_vp);
734 dir_vp = parent_dir;
737 unlock_vnode(dir_vp);
738 unlock_vmnt(parent_vmp);
740 put_vnode(dir_vp);
742 /* add the leading slash */
743 if (strlen(orig_path) >= PATH_MAX) return(ENAMETOOLONG);
744 memmove(orig_path+1, orig_path, strlen(orig_path));
745 orig_path[0] = '/';
747 return(OK);
750 /*===========================================================================*
751 * check_perms *
752 *===========================================================================*/
753 static int check_perms(ep, io_gr, pathlen)
754 endpoint_t ep;
755 cp_grant_id_t io_gr;
756 size_t pathlen;
758 int r, slot;
759 struct vnode *vp;
760 struct vmnt *vmp;
761 struct fproc *rfp;
762 char canon_path[PATH_MAX];
763 struct lookup resolve;
765 if (isokendpt(ep, &slot) != OK) return(EINVAL);
766 if (pathlen < UNIX_PATH_MAX || pathlen >= PATH_MAX) return(EINVAL);
768 rfp = &(fproc[slot]);
769 r = sys_safecopyfrom(PFS_PROC_NR, io_gr, (vir_bytes) 0,
770 (vir_bytes) canon_path, pathlen);
771 if (r != OK) return(r);
772 canon_path[pathlen] = '\0';
774 /* Turn path into canonical path to the socket file */
775 if ((r = canonical_path(canon_path, rfp)) != OK) return(r);
776 if (strlen(canon_path) >= pathlen) return(ENAMETOOLONG);
778 /* copy canon_path back to PFS */
779 r = sys_safecopyto(PFS_PROC_NR, (cp_grant_id_t) io_gr, (vir_bytes) 0,
780 (vir_bytes) canon_path, pathlen);
781 if (r != OK) return(r);
783 /* Now do permissions checking */
784 lookup_init(&resolve, canon_path, PATH_NOFLAGS, &vmp, &vp);
785 resolve.l_vmnt_lock = VMNT_READ;
786 resolve.l_vnode_lock = VNODE_READ;
787 if ((vp = eat_path(&resolve, rfp)) == NULL) return(err_code);
789 /* check permissions */
790 r = forbidden(rfp, vp, (R_BIT | W_BIT));
792 unlock_vnode(vp);
793 unlock_vmnt(vmp);
795 put_vnode(vp);
796 return(r);
799 /*===========================================================================*
800 * do_check_perms *
801 *===========================================================================*/
802 int do_check_perms(void)
804 return check_perms(job_m_in.USER_ENDPT, (cp_grant_id_t) job_m_in.IO_GRANT,
805 (size_t) job_m_in.COUNT);