| 3377 | } |
| 3378 | |
| 3379 | int |
| 3380 | kern_truncate(struct thread *td, const char *path, enum uio_seg pathseg, |
| 3381 | off_t length) |
| 3382 | { |
| 3383 | struct mount *mp; |
| 3384 | struct vnode *vp; |
| 3385 | void *rl_cookie; |
| 3386 | struct vattr vattr; |
| 3387 | struct nameidata nd; |
| 3388 | int error; |
| 3389 | |
| 3390 | if (length < 0) |
| 3391 | return (EINVAL); |
| 3392 | retry: |
| 3393 | NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, td); |
| 3394 | if ((error = namei(&nd)) != 0) |
| 3395 | return (error); |
| 3396 | vp = nd.ni_vp; |
| 3397 | rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX); |
| 3398 | if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) { |
| 3399 | vn_rangelock_unlock(vp, rl_cookie); |
| 3400 | vrele(vp); |
| 3401 | return (error); |
| 3402 | } |
| 3403 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 3404 | vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
| 3405 | if (vp->v_type == VDIR) |
| 3406 | error = EISDIR; |
| 3407 | #ifdef MAC |
| 3408 | else if ((error = mac_vnode_check_write(td->td_ucred, NOCRED, vp))) { |
| 3409 | } |
| 3410 | #endif |
| 3411 | else if ((error = vn_writechk(vp)) == 0 && |
| 3412 | (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) { |
| 3413 | VATTR_NULL(&vattr); |
| 3414 | vattr.va_size = length; |
| 3415 | error = VOP_SETATTR(vp, &vattr, td->td_ucred); |
| 3416 | } |
| 3417 | VOP_UNLOCK(vp); |
| 3418 | vn_finished_write(mp); |
| 3419 | vn_rangelock_unlock(vp, rl_cookie); |
| 3420 | vrele(vp); |
| 3421 | if (error == ERELOOKUP) |
| 3422 | goto retry; |
| 3423 | return (error); |
| 3424 | } |
| 3425 | |
| 3426 | #if defined(COMPAT_43) |
| 3427 | /* |
no test coverage detected