* Resolve an arbitrary vnode to a pathname (taking care of hardlinks). * * Since the namecache does not track hardlinks, the caller is expected to first * look up the target vnode with SAVENAME | WANTPARENT flags passed to namei. * * Then we have 2 cases: * - if the found vnode is a directory, the path can be constructed just by * following names up the chain * - otherwise we populate th
| 3404 | * from the parent |
| 3405 | */ |
| 3406 | static int |
| 3407 | vn_fullpath_hardlink(struct nameidata *ndp, char **retbuf, char **freebuf, |
| 3408 | size_t *buflen) |
| 3409 | { |
| 3410 | char *buf, *tmpbuf; |
| 3411 | struct pwd *pwd; |
| 3412 | struct componentname *cnp; |
| 3413 | struct vnode *vp; |
| 3414 | size_t addend; |
| 3415 | int error; |
| 3416 | enum vtype type; |
| 3417 | |
| 3418 | if (*buflen < 2) |
| 3419 | return (EINVAL); |
| 3420 | if (*buflen > MAXPATHLEN) |
| 3421 | *buflen = MAXPATHLEN; |
| 3422 | |
| 3423 | buf = malloc(*buflen, M_TEMP, M_WAITOK); |
| 3424 | |
| 3425 | addend = 0; |
| 3426 | vp = ndp->ni_vp; |
| 3427 | /* |
| 3428 | * Check for VBAD to work around the vp_crossmp bug in lookup(). |
| 3429 | * |
| 3430 | * For example consider tmpfs on /tmp and realpath /tmp. ni_vp will be |
| 3431 | * set to mount point's root vnode while ni_dvp will be vp_crossmp. |
| 3432 | * If the type is VDIR (like in this very case) we can skip looking |
| 3433 | * at ni_dvp in the first place. However, since vnodes get passed here |
| 3434 | * unlocked the target may transition to doomed state (type == VBAD) |
| 3435 | * before we get to evaluate the condition. If this happens, we will |
| 3436 | * populate part of the buffer and descend to vn_fullpath_dir with |
| 3437 | * vp == vp_crossmp. Prevent the problem by checking for VBAD. |
| 3438 | * |
| 3439 | * This should be atomic_load(&vp->v_type) but it is illegal to take |
| 3440 | * an address of a bit field, even if said field is sized to char. |
| 3441 | * Work around the problem by reading the value into a full-sized enum |
| 3442 | * and then re-reading it with atomic_load which will still prevent |
| 3443 | * the compiler from re-reading down the road. |
| 3444 | */ |
| 3445 | type = vp->v_type; |
| 3446 | type = atomic_load_int(&type); |
| 3447 | if (type == VBAD) { |
| 3448 | error = ENOENT; |
| 3449 | goto out_bad; |
| 3450 | } |
| 3451 | if (type != VDIR) { |
| 3452 | cnp = &ndp->ni_cnd; |
| 3453 | addend = cnp->cn_namelen + 2; |
| 3454 | if (*buflen < addend) { |
| 3455 | error = ENOMEM; |
| 3456 | goto out_bad; |
| 3457 | } |
| 3458 | *buflen -= addend; |
| 3459 | tmpbuf = buf + *buflen; |
| 3460 | tmpbuf[0] = '/'; |
| 3461 | memcpy(&tmpbuf[1], cnp->cn_nameptr, cnp->cn_namelen); |
| 3462 | tmpbuf[addend - 1] = '\0'; |
| 3463 | vp = ndp->ni_dvp; |
no test coverage detected