* This function updates path string to vnode's full global path * and checks the size of the new path string against the pathlen argument. * * Requires a locked, referenced vnode. * Vnode is re-locked on success or ENODEV, otherwise unlocked. * * If vp is a directory, the call to vn_fullpath_global() always succeeds * because it falls back to the ".." lookup if the namecache lookup fails.
| 3545 | * because it falls back to the ".." lookup if the namecache lookup fails. |
| 3546 | */ |
| 3547 | int |
| 3548 | vn_path_to_global_path(struct thread *td, struct vnode *vp, char *path, |
| 3549 | u_int pathlen) |
| 3550 | { |
| 3551 | struct nameidata nd; |
| 3552 | struct vnode *vp1; |
| 3553 | char *rpath, *fbuf; |
| 3554 | int error; |
| 3555 | |
| 3556 | ASSERT_VOP_ELOCKED(vp, __func__); |
| 3557 | |
| 3558 | /* Construct global filesystem path from vp. */ |
| 3559 | VOP_UNLOCK(vp); |
| 3560 | error = vn_fullpath_global(vp, &rpath, &fbuf); |
| 3561 | |
| 3562 | if (error != 0) { |
| 3563 | vrele(vp); |
| 3564 | return (error); |
| 3565 | } |
| 3566 | |
| 3567 | if (strlen(rpath) >= pathlen) { |
| 3568 | vrele(vp); |
| 3569 | error = ENAMETOOLONG; |
| 3570 | goto out; |
| 3571 | } |
| 3572 | |
| 3573 | /* |
| 3574 | * Re-lookup the vnode by path to detect a possible rename. |
| 3575 | * As a side effect, the vnode is relocked. |
| 3576 | * If vnode was renamed, return ENOENT. |
| 3577 | */ |
| 3578 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, |
| 3579 | UIO_SYSSPACE, path, td); |
| 3580 | error = namei(&nd); |
| 3581 | if (error != 0) { |
| 3582 | vrele(vp); |
| 3583 | goto out; |
| 3584 | } |
| 3585 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 3586 | vp1 = nd.ni_vp; |
| 3587 | vrele(vp); |
| 3588 | if (vp1 == vp) |
| 3589 | strcpy(path, rpath); |
| 3590 | else { |
| 3591 | vput(vp1); |
| 3592 | error = ENOENT; |
| 3593 | } |
| 3594 | |
| 3595 | out: |
| 3596 | free(fbuf, M_TEMP); |
| 3597 | return (error); |
| 3598 | } |
| 3599 | |
| 3600 | #ifdef DDB |
| 3601 | static void |