static int devfs_vop_setattr(struct vop_setattr_args *ap) { struct devfs_node *node = DEVFS_NODE(ap->a_vp); struct vattr *vap; uid_t cur_uid; gid_t cur_gid; mode_t cur_mode; int error = 0; if (!devfs_node_is_accessible(node)) return ENOENT; node_sync_dev_get(node); lockmgr(&devfs_lock, LK_EXCLUSIVE); vap = ap->a_vap; if ((vap->va_uid != (uid_t)VNOVAL) || (vap->va_gid != (gid_t)VNOVAL)) { cur_uid = node->uid; cur_gid = node->gid; cur_mode = node->mode; error = vop_helper_chown(ap->a_vp, vap->va_uid, vap->va_gid, ap->a_cred, &cur_uid, &cur_gid, &cur_mode); if (error) goto out; if (node->uid != cur_uid || node->gid != cur_gid) { node->uid = cur_uid; node->gid = cur_gid; node->mode = cur_mode; } } if (vap->va_mode != (mode_t)VNOVAL) { cur_mode = node->mode; error = vop_helper_chmod(ap->a_vp, vap->va_mode, ap->a_cred, node->uid, node->gid, &cur_mode); if (error == 0 && node->mode != cur_mode) { node->mode = cur_mode; } } out: node_sync_dev_set(node); nanotime(&node->ctime); lockmgr(&devfs_lock, LK_RELEASE); return error; }
/* * Change access mode on the given vnode. * Caller should execute tmpfs_update on vp after a successful execution. * The vnode must be locked on entry and remain locked on exit. */ int tmpfs_chmod(struct vnode *vp, mode_t vamode, struct ucred *cred) { struct tmpfs_node *node; mode_t cur_mode; int error; KKASSERT(vn_islocked(vp)); node = VP_TO_TMPFS_NODE(vp); /* Disallow this operation if the file system is mounted read-only. */ if (vp->v_mount->mnt_flag & MNT_RDONLY) return EROFS; /* Immutable or append-only files cannot be modified, either. */ if (node->tn_flags & (IMMUTABLE | APPEND)) return EPERM; cur_mode = node->tn_mode; error = vop_helper_chmod(vp, vamode, cred, node->tn_uid, node->tn_gid, &cur_mode); if (error == 0 && (node->tn_mode & ALLPERMS) != (cur_mode & ALLPERMS)) { TMPFS_NODE_LOCK(node); node->tn_mode &= ~ALLPERMS; node->tn_mode |= cur_mode & ALLPERMS; node->tn_status |= TMPFS_NODE_CHANGED; TMPFS_NODE_UNLOCK(node); } KKASSERT(vn_islocked(vp)); return 0; }