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
, *sym_vp_l
, *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
259 * is one. Note: depending on the previous advance, we might not be
260 * able to lock the resulting vnode. For example, when we look up "./."
261 * and request a VNODE_WRITE lock on the result, then the previous
262 * advance has "./" locked. The next advance to "." will try to lock
263 * the same vnode with a VNODE_READ lock, and fail. When that happens,
264 * sym_vp_l will be NULL and we must not unlock the vnode. If we would
265 * unlock, we actually unlock the vnode locked by the previous advance.
267 lookup_init(&symlink
, resolve
->l_path
,
268 resolve
->l_flags
|PATH_RET_SYMLINK
, &sym_vmp
, &sym_vp_l
);
269 symlink
.l_vmnt_lock
= VMNT_READ
;
270 symlink
.l_vnode_lock
= VNODE_READ
;
271 sym_vp
= advance(res_vp
, &symlink
, rfp
);
273 if (sym_vp
== NULL
) break;
275 if (S_ISLNK(sym_vp
->v_mode
)) {
276 /* Last component is a symlink, but if we've been asked to not
277 * resolve it, return now.
279 if (ret_on_symlink
) {
283 r
= req_rdlink(sym_vp
->v_fs_e
, sym_vp
->v_inode_nr
, NONE
,
284 (vir_bytes
) resolve
->l_path
, PATH_MAX
- 1, 1);
287 /* Failed to read link */
289 unlock_vnode(res_vp
);
290 unlock_vmnt(*resolve
->l_vmp
);
292 *resolve
->l_vmp
= NULL
;
293 *resolve
->l_vnode
= NULL
;
297 resolve
->l_path
[r
] = '\0';
299 if (strrchr(resolve
->l_path
, '/') != NULL
) {
300 if (sym_vp_l
!= NULL
)
301 unlock_vnode(sym_vp
);
302 unlock_vmnt(*resolve
->l_vmp
);
304 unlock_vmnt(sym_vmp
);
305 *resolve
->l_vmp
= NULL
;
311 /* Relative symlinks are relative to res_vp, not cwd */
312 if (resolve
->l_path
[0] != '/') {
315 /* Absolute symlink, forget about res_vp */
316 unlock_vnode(res_vp
);
323 symloop
= 0; /* Not a symlink, so restart counting */
325 /* If we're crossing a mount point, return root node of mount
326 * point on which the file resides. That's the 'real' last
327 * dir that holds the file we're looking for.
329 if (sym_vp
->v_fs_e
!= res_vp
->v_fs_e
) {
330 assert(sym_vmp
!= NULL
);
332 /* Unlock final file, it might have wrong lock types */
333 if (sym_vp_l
!= NULL
)
334 unlock_vnode(sym_vp
);
335 unlock_vmnt(sym_vmp
);
339 /* Also unlock and release erroneous result */
340 unlock_vnode(*resolve
->l_vnode
);
341 unlock_vmnt(*resolve
->l_vmp
);
344 /* Relock vmnt and vnode with correct lock types */
345 lock_vmnt(sym_vmp
, resolve
->l_vmnt_lock
);
346 lock_vnode(sym_vmp
->m_root_node
, resolve
->l_vnode_lock
);
347 res_vp
= sym_vmp
->m_root_node
;
349 *resolve
->l_vnode
= res_vp
;
350 *resolve
->l_vmp
= sym_vmp
;
352 /* We've effectively resolved the final component, so
353 * change it to current directory to prevent future
354 * 'advances' of returning erroneous results.
356 strlcpy(dir_entry
, ".", NAME_MAX
+1);
360 } while (symloop
< SYMLOOP_MAX
);
362 if (symloop
>= SYMLOOP_MAX
) {
367 if (sym_vp
!= NULL
) {
368 if (sym_vp_l
!= NULL
) {
369 unlock_vnode(sym_vp
);
371 if (sym_vmp
!= NULL
) {
372 unlock_vmnt(sym_vmp
);
377 if (loop_start
!= NULL
) {
378 unlock_vnode(loop_start
);
379 put_vnode(loop_start
);
382 /* Copy the directory entry back to user_fullpath */
383 strlcpy(resolve
->l_path
, dir_entry
, NAME_MAX
+ 1);
385 /* Turn PATH_RET_SYMLINK flag back on if it was on */
386 if (ret_on_symlink
) resolve
->l_flags
|= PATH_RET_SYMLINK
;
391 /*===========================================================================*
393 *===========================================================================*/
394 static int lookup(start_node
, resolve
, result_node
, rfp
)
395 struct vnode
*start_node
;
396 struct lookup
*resolve
;
397 node_details_t
*result_node
;
400 /* Resolve a path name relative to start_node. */
404 size_t path_off
, path_left_len
;
405 ino_t dir_ino
, root_ino
;
408 struct vnode
*dir_vp
;
409 struct vmnt
*vmp
, *vmpres
;
410 struct lookup_res res
;
411 tll_access_t mnt_lock_type
;
413 assert(resolve
->l_vmp
);
414 assert(resolve
->l_vnode
);
416 *(resolve
->l_vmp
) = vmpres
= NULL
; /* No vmnt found nor locked yet */
418 /* Empty (start) path? */
419 if (resolve
->l_path
[0] == '\0') {
420 result_node
->inode_nr
= 0;
424 if (!rfp
->fp_rd
|| !rfp
->fp_wd
) {
425 printf("VFS: lookup %d: no rd/wd\n", rfp
->fp_endpoint
);
429 fs_e
= start_node
->v_fs_e
;
430 dir_ino
= start_node
->v_inode_nr
;
431 vmpres
= find_vmnt(fs_e
);
433 if (vmpres
== NULL
) return(EIO
); /* mountpoint vanished? */
435 /* Is the process' root directory on the same partition?,
436 * if so, set the chroot directory too. */
437 if (rfp
->fp_rd
->v_dev
== rfp
->fp_wd
->v_dev
)
438 root_ino
= rfp
->fp_rd
->v_inode_nr
;
442 /* Set user and group ids according to the system call */
443 uid
= (job_call_nr
== ACCESS
? rfp
->fp_realuid
: rfp
->fp_effuid
);
444 gid
= (job_call_nr
== ACCESS
? rfp
->fp_realgid
: rfp
->fp_effgid
);
446 symloop
= 0; /* Number of symlinks seen so far */
449 if (resolve
->l_vmnt_lock
== VMNT_READ
)
450 mnt_lock_type
= VMNT_WRITE
;
452 mnt_lock_type
= resolve
->l_vmnt_lock
;
454 if ((r
= lock_vmnt(vmpres
, mnt_lock_type
)) != OK
) {
455 if (r
== EBUSY
) /* vmnt already locked */
460 *(resolve
->l_vmp
) = vmpres
;
462 /* Issue the request */
463 r
= req_lookup(fs_e
, dir_ino
, root_ino
, uid
, gid
, resolve
, &res
, rfp
);
465 if (r
!= OK
&& r
!= EENTERMOUNT
&& r
!= ELEAVEMOUNT
&& r
!= ESYMLINK
) {
466 if (vmpres
) unlock_vmnt(vmpres
);
467 *(resolve
->l_vmp
) = NULL
;
468 return(r
); /* i.e., an error occured */
471 /* While the response is related to mount control set the
472 * new requests respectively */
473 while (r
== EENTERMOUNT
|| r
== ELEAVEMOUNT
|| r
== ESYMLINK
) {
474 /* Update user_fullpath to reflect what's left to be parsed. */
475 path_off
= res
.char_processed
;
476 path_left_len
= strlen(&resolve
->l_path
[path_off
]);
477 memmove(resolve
->l_path
, &resolve
->l_path
[path_off
], path_left_len
);
478 resolve
->l_path
[path_left_len
] = '\0'; /* terminate string */
480 /* Update the current value of the symloop counter */
481 symloop
+= res
.symloop
;
482 if (symloop
> SYMLOOP_MAX
) {
483 if (vmpres
) unlock_vmnt(vmpres
);
484 *(resolve
->l_vmp
) = NULL
;
488 /* Symlink encountered with absolute path */
492 } else if (r
== EENTERMOUNT
) {
493 /* Entering a new partition */
495 /* Start node is now the mounted partition's root node */
496 for (vmp
= &vmnt
[0]; vmp
!= &vmnt
[NR_MNTS
]; ++vmp
) {
497 if (vmp
->m_dev
!= NO_DEV
&& vmp
->m_mounted_on
) {
498 if (vmp
->m_mounted_on
->v_inode_nr
== res
.inode_nr
&&
499 vmp
->m_mounted_on
->v_fs_e
== res
.fs_e
) {
500 dir_vp
= vmp
->m_root_node
;
505 if (dir_vp
== NULL
) {
506 printf("VFS: path lookup error; root node not found\n");
507 if (vmpres
) unlock_vmnt(vmpres
);
508 *(resolve
->l_vmp
) = NULL
;
512 /* Climbing up mount */
513 /* Find the vmnt that represents the partition on
514 * which we "climb up". */
515 if ((vmp
= find_vmnt(res
.fs_e
)) == NULL
) {
516 panic("VFS lookup: can't find parent vmnt");
519 /* Make sure that the child FS does not feed a bogus path
520 * to the parent FS. That is, when we climb up the tree, we
521 * must've encountered ".." in the path, and that is exactly
522 * what we're going to feed to the parent */
523 if(strncmp(resolve
->l_path
, "..", 2) != 0 ||
524 (resolve
->l_path
[2] != '\0' && resolve
->l_path
[2] != '/')) {
525 printf("VFS: bogus path: %s\n", resolve
->l_path
);
526 if (vmpres
) unlock_vmnt(vmpres
);
527 *(resolve
->l_vmp
) = NULL
;
531 /* Start node is the vnode on which the partition is
533 dir_vp
= vmp
->m_mounted_on
;
536 /* Set the starting directories inode number and FS endpoint */
537 fs_e
= dir_vp
->v_fs_e
;
538 dir_ino
= dir_vp
->v_inode_nr
;
540 /* Is the process' root directory on the same partition?,
541 * if so, set the chroot directory too. */
542 if (dir_vp
->v_dev
== rfp
->fp_rd
->v_dev
)
543 root_ino
= rfp
->fp_rd
->v_inode_nr
;
547 /* Unlock a previously locked vmnt if locked and lock new vmnt */
548 if (vmpres
) unlock_vmnt(vmpres
);
549 vmpres
= find_vmnt(fs_e
);
550 if (vmpres
== NULL
) return(EIO
); /* mount point vanished? */
551 if ((r
= lock_vmnt(vmpres
, mnt_lock_type
)) != OK
) {
553 vmpres
= NULL
; /* Already locked */
557 *(resolve
->l_vmp
) = vmpres
;
559 r
= req_lookup(fs_e
, dir_ino
, root_ino
, uid
, gid
, resolve
, &res
, rfp
);
561 if (r
!= OK
&& r
!= EENTERMOUNT
&& r
!= ELEAVEMOUNT
&& r
!= ESYMLINK
) {
562 if (vmpres
) unlock_vmnt(vmpres
);
563 *(resolve
->l_vmp
) = NULL
;
568 if (*(resolve
->l_vmp
) != NULL
&& resolve
->l_vmnt_lock
!= mnt_lock_type
) {
569 /* downgrade VMNT_WRITE to VMNT_READ */
570 downgrade_vmnt_lock(*(resolve
->l_vmp
));
573 /* Fill in response fields */
574 result_node
->inode_nr
= res
.inode_nr
;
575 result_node
->fmode
= res
.fmode
;
576 result_node
->fsize
= res
.fsize
;
577 result_node
->dev
= res
.dev
;
578 result_node
->fs_e
= res
.fs_e
;
579 result_node
->uid
= res
.uid
;
580 result_node
->gid
= res
.gid
;
585 /*===========================================================================*
587 *===========================================================================*/
588 void lookup_init(resolve
, path
, flags
, vmp
, vp
)
589 struct lookup
*resolve
;
598 resolve
->l_path
= path
;
599 resolve
->l_flags
= flags
;
600 resolve
->l_vmp
= vmp
;
601 resolve
->l_vnode
= vp
;
602 resolve
->l_vmnt_lock
= TLL_NONE
;
603 resolve
->l_vnode_lock
= TLL_NONE
;
604 *vmp
= NULL
; /* Initialize lookup result to NULL */
608 /*===========================================================================*
610 *===========================================================================*/
611 int get_name(dirp
, entry
, ename
)
614 char ename
[NAME_MAX
+ 1];
616 #define DIR_ENTRIES 8
617 #define DIR_ENTRY_SIZE (sizeof(struct dirent) + NAME_MAX)
619 int r
, consumed
, totalbytes
, name_len
;
620 char buf
[DIR_ENTRY_SIZE
* DIR_ENTRIES
];
625 if (!S_ISDIR(dirp
->v_mode
)) return(EBADF
);
628 r
= req_getdents(dirp
->v_fs_e
, dirp
->v_inode_nr
, pos
, buf
, sizeof(buf
),
632 return(ENOENT
); /* end of entries -- matching inode !found */
634 return(r
); /* error */
637 consumed
= 0; /* bytes consumed */
638 totalbytes
= r
; /* number of bytes to consume */
641 cur
= (struct dirent
*) (buf
+ consumed
);
642 name_len
= cur
->d_reclen
- offsetof(struct dirent
, d_name
) - 1;
644 if(cur
->d_name
+ name_len
+1 > &buf
[sizeof(buf
)])
645 return(EINVAL
); /* Rubbish in dir entry */
646 if (entry
->v_inode_nr
== cur
->d_ino
) {
647 /* found the entry we were looking for */
648 int copylen
= MIN(name_len
+ 1, NAME_MAX
+ 1);
649 if (strlcpy(ename
, cur
->d_name
, copylen
) >= copylen
) {
650 return(ENAMETOOLONG
);
652 ename
[NAME_MAX
] = '\0';
656 /* not a match -- move on to the next dirent */
657 consumed
+= cur
->d_reclen
;
658 } while (consumed
< totalbytes
);
664 /*===========================================================================*
666 *===========================================================================*/
667 int canonical_path(orig_path
, rfp
)
668 char orig_path
[PATH_MAX
];
671 /* Find canonical path of a given path */
674 struct vnode
*dir_vp
, *parent_dir
;
675 struct vmnt
*dir_vmp
, *parent_vmp
;
676 char component
[NAME_MAX
+1]; /* NAME_MAX does /not/ include '\0' */
677 char temp_path
[PATH_MAX
];
678 struct lookup resolve
;
680 parent_dir
= dir_vp
= NULL
;
681 parent_vmp
= dir_vmp
= NULL
;
682 strlcpy(temp_path
, orig_path
, PATH_MAX
);
683 temp_path
[PATH_MAX
- 1] = '\0';
685 /* First resolve path to the last directory holding the file */
688 unlock_vnode(dir_vp
);
689 unlock_vmnt(dir_vmp
);
693 lookup_init(&resolve
, temp_path
, PATH_NOFLAGS
, &dir_vmp
, &dir_vp
);
694 resolve
.l_vmnt_lock
= VMNT_READ
;
695 resolve
.l_vnode_lock
= VNODE_READ
;
696 if ((dir_vp
= last_dir(&resolve
, rfp
)) == NULL
) return(err_code
);
698 /* dir_vp points to dir and resolve path now contains only the
701 strlcpy(orig_path
, temp_path
, NAME_MAX
+1); /* Store file name */
703 /* If we're just crossing a mount point, our name has changed to '.' */
704 if (!strcmp(orig_path
, ".")) orig_path
[0] = '\0';
706 /* check if the file is a symlink, if so resolve it */
707 r
= rdlink_direct(orig_path
, temp_path
, rfp
);
712 /* encountered a symlink -- loop again */
713 strlcpy(orig_path
, temp_path
, PATH_MAX
);
715 } while (symloop
< SYMLOOP_MAX
);
717 if (symloop
>= SYMLOOP_MAX
) {
719 unlock_vnode(dir_vp
);
720 unlock_vmnt(dir_vmp
);
726 /* We've got the filename and the actual directory holding the file. From
727 * here we start building up the canonical path by climbing up the tree */
728 while (dir_vp
!= rfp
->fp_rd
) {
730 strlcpy(temp_path
, "..", NAME_MAX
+1);
732 /* check if we're at the root node of the file system */
733 if (dir_vp
->v_vmnt
->m_root_node
== dir_vp
) {
734 if (dir_vp
->v_vmnt
->m_mounted_on
== NULL
) {
735 /* Bail out, we can't go any higher */
738 unlock_vnode(dir_vp
);
739 unlock_vmnt(dir_vmp
);
741 dir_vp
= dir_vp
->v_vmnt
->m_mounted_on
;
742 dir_vmp
= dir_vp
->v_vmnt
;
743 if (lock_vmnt(dir_vmp
, VMNT_READ
) != OK
)
744 panic("failed to lock vmnt");
745 if (lock_vnode(dir_vp
, VNODE_READ
) != OK
)
746 panic("failed to lock vnode");
750 lookup_init(&resolve
, temp_path
, PATH_NOFLAGS
, &parent_vmp
,
752 resolve
.l_vmnt_lock
= VMNT_READ
;
753 resolve
.l_vnode_lock
= VNODE_READ
;
755 if ((parent_dir
= advance(dir_vp
, &resolve
, rfp
)) == NULL
) {
756 unlock_vnode(dir_vp
);
757 unlock_vmnt(dir_vmp
);
762 /* now we have to retrieve the name of the parent directory */
763 if (get_name(parent_dir
, dir_vp
, component
) != OK
) {
764 unlock_vnode(parent_dir
);
765 unlock_vmnt(parent_vmp
);
766 unlock_vnode(dir_vp
);
767 unlock_vmnt(dir_vmp
);
768 put_vnode(parent_dir
);
773 len
+= strlen(component
) + 1;
774 if (len
>= PATH_MAX
) {
775 /* adding the component to orig_path would exceed PATH_MAX */
776 unlock_vnode(parent_dir
);
777 unlock_vmnt(parent_vmp
);
778 unlock_vnode(dir_vp
);
779 unlock_vmnt(dir_vmp
);
780 put_vnode(parent_dir
);
785 /* Store result of component in orig_path. First make space by moving
786 * the contents of orig_path to the right. Move strlen + 1 bytes to
787 * include the terminating '\0'. Move to strlen + 1 bytes to reserve
788 * space for the slash.
790 memmove(orig_path
+strlen(component
)+1, orig_path
, strlen(orig_path
)+1);
791 /* Copy component into canon_path */
792 memmove(orig_path
, component
, strlen(component
));
793 /* Put slash into place */
794 orig_path
[strlen(component
)] = '/';
796 /* Store parent_dir result, and continue the loop once more */
797 unlock_vnode(dir_vp
);
798 unlock_vmnt(dir_vmp
);
801 dir_vmp
= parent_vmp
;
805 unlock_vmnt(dir_vmp
);
806 unlock_vnode(dir_vp
);
809 /* add the leading slash */
810 len
= strlen(orig_path
);
811 if (strlen(orig_path
) >= PATH_MAX
) return(ENAMETOOLONG
);
812 memmove(orig_path
+1, orig_path
, len
);
815 /* remove trailing slash if there is any */
816 if (len
> 1 && orig_path
[len
] == '/') orig_path
[len
] = '\0';
821 /*===========================================================================*
823 *===========================================================================*/
824 static int check_perms(ep
, io_gr
, pathlen
)
833 char canon_path
[PATH_MAX
];
834 struct lookup resolve
;
836 if (isokendpt(ep
, &slot
) != OK
) return(EINVAL
);
837 if (pathlen
< UNIX_PATH_MAX
|| pathlen
>= PATH_MAX
) return(EINVAL
);
839 rfp
= &(fproc
[slot
]);
840 r
= sys_safecopyfrom(PFS_PROC_NR
, io_gr
, (vir_bytes
) 0,
841 (vir_bytes
) canon_path
, pathlen
);
842 if (r
!= OK
) return(r
);
843 canon_path
[pathlen
] = '\0';
845 /* Turn path into canonical path to the socket file */
846 if ((r
= canonical_path(canon_path
, rfp
)) != OK
) return(r
);
847 if (strlen(canon_path
) >= pathlen
) return(ENAMETOOLONG
);
849 /* copy canon_path back to PFS */
850 r
= sys_safecopyto(PFS_PROC_NR
, (cp_grant_id_t
) io_gr
, (vir_bytes
) 0,
851 (vir_bytes
) canon_path
, pathlen
);
852 if (r
!= OK
) return(r
);
854 /* Now do permissions checking */
855 lookup_init(&resolve
, canon_path
, PATH_NOFLAGS
, &vmp
, &vp
);
856 resolve
.l_vmnt_lock
= VMNT_READ
;
857 resolve
.l_vnode_lock
= VNODE_READ
;
858 if ((vp
= eat_path(&resolve
, rfp
)) == NULL
) return(err_code
);
860 /* check permissions */
861 r
= forbidden(rfp
, vp
, (R_BIT
| W_BIT
));
870 /*===========================================================================*
872 *===========================================================================*/
873 int do_check_perms(void)
875 return check_perms(job_m_in
.USER_ENDPT
, (cp_grant_id_t
) job_m_in
.IO_GRANT
,
876 (size_t) job_m_in
.COUNT
);