| 1565 | } |
| 1566 | |
| 1567 | static int |
| 1568 | kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path, |
| 1569 | enum uio_seg segflag) |
| 1570 | { |
| 1571 | struct nameidata nd; |
| 1572 | struct mount *mp; |
| 1573 | int error; |
| 1574 | |
| 1575 | if (vp->v_type == VDIR) { |
| 1576 | vrele(vp); |
| 1577 | return (EPERM); /* POSIX */ |
| 1578 | } |
| 1579 | NDINIT_ATRIGHTS(&nd, CREATE, |
| 1580 | LOCKPARENT | SAVENAME | AUDITVNODE2 | NOCACHE, segflag, path, fd, |
| 1581 | &cap_linkat_target_rights, td); |
| 1582 | if ((error = namei(&nd)) == 0) { |
| 1583 | if (nd.ni_vp != NULL) { |
| 1584 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 1585 | if (nd.ni_dvp == nd.ni_vp) |
| 1586 | vrele(nd.ni_dvp); |
| 1587 | else |
| 1588 | vput(nd.ni_dvp); |
| 1589 | vrele(nd.ni_vp); |
| 1590 | vrele(vp); |
| 1591 | return (EEXIST); |
| 1592 | } else if (nd.ni_dvp->v_mount != vp->v_mount) { |
| 1593 | /* |
| 1594 | * Cross-device link. No need to recheck |
| 1595 | * vp->v_type, since it cannot change, except |
| 1596 | * to VBAD. |
| 1597 | */ |
| 1598 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 1599 | vput(nd.ni_dvp); |
| 1600 | vrele(vp); |
| 1601 | return (EXDEV); |
| 1602 | } else if ((error = vn_lock(vp, LK_EXCLUSIVE)) == 0) { |
| 1603 | error = can_hardlink(vp, td->td_ucred); |
| 1604 | #ifdef MAC |
| 1605 | if (error == 0) |
| 1606 | error = mac_vnode_check_link(td->td_ucred, |
| 1607 | nd.ni_dvp, vp, &nd.ni_cnd); |
| 1608 | #endif |
| 1609 | if (error != 0) { |
| 1610 | vput(vp); |
| 1611 | vput(nd.ni_dvp); |
| 1612 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 1613 | return (error); |
| 1614 | } |
| 1615 | error = vn_start_write(vp, &mp, V_NOWAIT); |
| 1616 | if (error != 0) { |
| 1617 | vput(vp); |
| 1618 | vput(nd.ni_dvp); |
| 1619 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 1620 | error = vn_start_write(NULL, &mp, |
| 1621 | V_XSLEEP | PCATCH); |
| 1622 | if (error != 0) |
| 1623 | return (error); |
| 1624 | return (EAGAIN); |
no test coverage detected