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.
8 #include <minix/callnr.h>
10 #include <minix/keymap.h>
11 #include <minix/const.h>
12 #include <minix/endpoint.h>
16 #include <minix/vfsif.h>
17 #include <sys/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
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
43 /*===========================================================================*
45 *===========================================================================*/
46 struct vnode
*advance(dirp
, resolve
, rfp
)
48 struct lookup
*resolve
;
51 /* Resolve a path name starting at dirp to a vnode. */
54 struct vnode
*new_vp
, *vp
;
56 struct node_details res
= {0,0,0,0,0,0,0};
57 tll_access_t initial_locktype
;
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
;
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
) {
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. */
95 if (vp
->v_mapfs_e
!= NONE
) vp
->v_mapfs_count
= 1;
97 vp
->v_fs_count
++; /* We got a reference from the FS */
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;
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
);
130 if (resolve
->l_vnode_lock
== VNODE_READ
)
138 /*===========================================================================*
140 *===========================================================================*/
141 struct vnode
*eat_path(resolve
, rfp
)
142 struct lookup
*resolve
;
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 /*===========================================================================*
154 *===========================================================================*/
155 struct vnode
*last_dir(resolve
, rfp
)
156 struct lookup
*resolve
;
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.
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
;
181 ret_on_symlink
= !!(resolve
->l_flags
& PATH_RET_SYMLINK
);
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
;
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. */
201 #if !DO_POSIX_PATHNAME_RES
202 /* Remove trailing slashes */
203 while (len
> 1 && resolve
->l_path
[len
-1] == '/') {
205 resolve
->l_path
[len
]= '\0';
209 cp
= strrchr(resolve
->l_path
, '/');
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
;
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);
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
;
233 dir_entry
[NAME_MAX
] = '\0';
236 /* Remove trailing slashes */
237 while (cp
> resolve
->l_path
&& cp
[0] == '/') {
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
) {
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
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
) {
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);
279 /* Failed to read link */
281 unlock_vnode(res_vp
);
282 unlock_vmnt(*resolve
->l_vmp
);
284 *resolve
->l_vmp
= NULL
;
285 *resolve
->l_vnode
= NULL
;
289 resolve
->l_path
[r
] = '\0';
291 if (strrchr(resolve
->l_path
, '/') != NULL
) {
292 unlock_vnode(sym_vp
);
293 unlock_vmnt(*resolve
->l_vmp
);
295 unlock_vmnt(sym_vmp
);
296 *resolve
->l_vmp
= NULL
;
302 /* Relative symlinks are relative to res_vp, not cwd */
303 if (resolve
->l_path
[0] != '/') {
306 /* Absolute symlink, forget about res_vp */
307 unlock_vnode(res_vp
);
315 } while (symloop
< SYMLOOP_MAX
);
317 if (symloop
>= SYMLOOP_MAX
) {
322 if (sym_vp
!= NULL
) {
323 unlock_vnode(sym_vp
);
324 if (sym_vmp
!= NULL
) {
325 unlock_vmnt(sym_vmp
);
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
;
344 /*===========================================================================*
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
;
353 /* Resolve a path name relative to start_node. */
357 size_t path_off
, path_left_len
;
358 ino_t dir_ino
, root_ino
;
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;
376 if (!rfp
->fp_rd
|| !rfp
->fp_wd
) {
377 printf("VFS: lookup %d: no rd/wd\n", rfp
->fp_endpoint
);
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
;
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 */
401 if ((r
= lock_vmnt(vmpres
, resolve
->l_vmnt_lock
)) != OK
) {
402 if (r
== EBUSY
) /* vmnt already locked */
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
;
435 /* Symlink encountered with absolute path */
439 } else if (r
== EENTERMOUNT
) {
440 /* Entering a new partition */
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
;
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
;
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
;
478 /* Start node is the vnode on which the partition is
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
;
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
) {
500 vmpres
= NULL
; /* Already locked */
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
;
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
;
527 /*===========================================================================*
529 *===========================================================================*/
530 void lookup_init(resolve
, path
, flags
, vmp
, vp
)
531 struct lookup
*resolve
;
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 */
550 /*===========================================================================*
552 *===========================================================================*/
553 int get_name(dirp
, entry
, ename
)
556 char ename
[NAME_MAX
+ 1];
558 #define DIR_ENTRIES 8
559 #define DIR_ENTRY_SIZE (sizeof(struct dirent) + NAME_MAX)
561 int r
, consumed
, totalbytes
, name_len
;
562 char buf
[DIR_ENTRY_SIZE
* DIR_ENTRIES
];
567 if (!S_ISDIR(dirp
->v_mode
)) return(EBADF
);
570 r
= req_getdents(dirp
->v_fs_e
, dirp
->v_inode_nr
, pos
, buf
, sizeof(buf
),
574 return(ENOENT
); /* end of entries -- matching inode !found */
576 return(r
); /* error */
579 consumed
= 0; /* bytes consumed */
580 totalbytes
= r
; /* number of bytes to consume */
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';
598 /* not a match -- move on to the next dirent */
599 consumed
+= cur
->d_reclen
;
600 } while (consumed
< totalbytes
);
606 /*===========================================================================*
608 *===========================================================================*/
609 int canonical_path(orig_path
, rfp
)
610 char orig_path
[PATH_MAX
];
613 /* Find canonical path of a given path */
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
;
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 */
629 unlock_vnode(dir_vp
);
630 unlock_vmnt(dir_vmp
);
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
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
);
650 /* encountered a symlink -- loop again */
651 strlcpy(orig_path
, temp_path
, PATH_MAX
);
653 } while (symloop
< SYMLOOP_MAX
);
655 if (symloop
>= SYMLOOP_MAX
) {
657 unlock_vnode(dir_vp
);
658 unlock_vmnt(dir_vmp
);
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
);
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");
684 lookup_init(&resolve
, temp_path
, PATH_NOFLAGS
, &parent_vmp
,
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
);
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
);
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
);
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
);
737 unlock_vnode(dir_vp
);
738 unlock_vmnt(parent_vmp
);
742 /* add the leading slash */
743 if (strlen(orig_path
) >= PATH_MAX
) return(ENAMETOOLONG
);
744 memmove(orig_path
+1, orig_path
, strlen(orig_path
));
750 /*===========================================================================*
752 *===========================================================================*/
753 static int check_perms(ep
, io_gr
, pathlen
)
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
));
799 /*===========================================================================*
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
);