FreeBSD/sys/fs/ext2fs/ext2_vnops.c
/*
 * Set attribute vnode op. called from several syscalls
 */
Set attribute vnode op. called from several syscalls
Set attribute vnode op . called from several syscalls
static int
ext2_setattr(struct vop_setattr_args *ap)
{
	struct vattr *vap = ap->a_vap;
	struct vnode *vp = ap->a_vp;
	struct inode *ip = VTOI(vp);
	struct ucred *cred = ap->a_cred;
	struct thread *td = curthread;
	int error;
	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
		return (EINVAL);
	}
	if (vap->va_flags != VNOVAL) {
		if(vap->va_flags & ~(SF_APPEND | SF_IMMUTABLE | UF_NODUMP))
			return (EOPNOTSUPP);
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);
		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
			return (error);
		if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) {
			if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) {
				error = securelevel_gt(cred, 0);
				if (error)
					return (error);
			}
		} else {
			if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND) ||
			    ((vap->va_flags ^ ip->i_flags) & SF_SETTABLE))
				return (EPERM);
		}
		ip->i_flags = vap->va_flags;
		ip->i_flag |= IN_CHANGE;
		if (ip->i_flags & (IMMUTABLE | APPEND))
			return (0);
	}
	if (ip->i_flags & (IMMUTABLE | APPEND))
		return (EPERM);
	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);
		if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred,
		    td)) != 0)
			return (error);
	}
	if (vap->va_size != VNOVAL) {
		switch (vp->v_type) {
		case VDIR:
			return (EISDIR);
		case VLNK:
		case VREG:
			if (vp->v_mount->mnt_flag & MNT_RDONLY)
				return (EROFS);
			break;
		default:
			break;
		}
		if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0)
			return (error);
	}
	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);
		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) &&
		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
		    (error = VOP_ACCESS(vp, VWRITE, cred, td))))
			return (error);
		ip->i_flag |= IN_CHANGE | IN_MODIFIED;
		if (vap->va_atime.tv_sec != VNOVAL) {
			ip->i_flag &= ~IN_ACCESS;
			ip->i_atime = vap->va_atime.tv_sec;
			ip->i_atimensec = vap->va_atime.tv_nsec;
		}
		if (vap->va_mtime.tv_sec != VNOVAL) {
			ip->i_flag &= ~IN_UPDATE;
			ip->i_mtime = vap->va_mtime.tv_sec;
			ip->i_mtimensec = vap->va_mtime.tv_nsec;
		}
		ip->i_birthtime = vap->va_birthtime.tv_sec;
		ip->i_birthnsec = vap->va_birthtime.tv_nsec;
		error = ext2_update(vp, 0);
		if (error)
			return (error);
	}
	error = 0;
	if (vap->va_mode != (mode_t)VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);
		error = ext2_chmod(vp, (int)vap->va_mode, cred, td);
	}
	return (error);
}
static int ext2_setattr ( struct vop_setattr_args * ap ) { struct vattr * vap = ap -> a_vap ; struct vnode * vp = ap -> a_vp ; struct inode * ip = VTOI ( vp ) ; struct ucred * cred = ap -> a_cred ; struct thread * td = curthread ; int error ; if ( ( vap -> va_type != VNON ) || ( vap -> va_nlink != VNOVAL ) || ( vap -> va_fsid != VNOVAL ) || ( vap -> va_fileid != VNOVAL ) || ( vap -> va_blocksize != VNOVAL ) || ( vap -> va_rdev != VNOVAL ) || ( ( int ) vap -> va_bytes != VNOVAL ) || ( vap -> va_gen != VNOVAL ) ) { return ( EINVAL ) ; } if ( vap -> va_flags != VNOVAL ) { if ( vap -> va_flags & ~ ( SF_APPEND | SF_IMMUTABLE | UF_NODUMP ) ) return ( EOPNOTSUPP ) ; if ( vp -> v_mount -> mnt_flag & MNT_RDONLY ) return ( EROFS ) ; if ( ( error = VOP_ACCESS ( vp , VADMIN , cred , td ) ) ) return ( error ) ; if ( ! priv_check_cred ( cred , PRIV_VFS_SYSFLAGS , 0 ) ) { if ( ip -> i_flags & ( SF_IMMUTABLE | SF_APPEND ) ) { error = securelevel_gt ( cred , 0 ) ; if ( error ) return ( error ) ; } } else { if ( ip -> i_flags & ( SF_IMMUTABLE | SF_APPEND ) || ( ( vap -> va_flags ^ ip -> i_flags ) & SF_SETTABLE ) ) return ( EPERM ) ; } ip -> i_flags = vap -> va_flags ; ip -> i_flag |= IN_CHANGE ; if ( ip -> i_flags & ( IMMUTABLE | APPEND ) ) return ( 0 ) ; } if ( ip -> i_flags & ( IMMUTABLE | APPEND ) ) return ( EPERM ) ; if ( vap -> va_uid != ( uid_t ) VNOVAL || vap -> va_gid != ( gid_t ) VNOVAL ) { if ( vp -> v_mount -> mnt_flag & MNT_RDONLY ) return ( EROFS ) ; if ( ( error = ext2_chown ( vp , vap -> va_uid , vap -> va_gid , cred , td ) ) != 0 ) return ( error ) ; } if ( vap -> va_size != VNOVAL ) { switch ( vp -> v_type ) { case VDIR : return ( EISDIR ) ; case VLNK : case VREG : if ( vp -> v_mount -> mnt_flag & MNT_RDONLY ) return ( EROFS ) ; break ; default : break ; } if ( ( error = ext2_truncate ( vp , vap -> va_size , 0 , cred , td ) ) != 0 ) return ( error ) ; } if ( vap -> va_atime . tv_sec != VNOVAL || vap -> va_mtime . tv_sec != VNOVAL ) { if ( vp -> v_mount -> mnt_flag & MNT_RDONLY ) return ( EROFS ) ; if ( ( error = VOP_ACCESS ( vp , VADMIN , cred , td ) ) && ( ( vap -> va_vaflags & VA_UTIMES_NULL ) == 0 || ( error = VOP_ACCESS ( vp , VWRITE , cred , td ) ) ) ) return ( error ) ; ip -> i_flag |= IN_CHANGE | IN_MODIFIED ; if ( vap -> va_atime . tv_sec != VNOVAL ) { ip -> i_flag &= ~ IN_ACCESS ; ip -> i_atime = vap -> va_atime . tv_sec ; ip -> i_atimensec = vap -> va_atime . tv_nsec ; } if ( vap -> va_mtime . tv_sec != VNOVAL ) { ip -> i_flag &= ~ IN_UPDATE ; ip -> i_mtime = vap -> va_mtime . tv_sec ; ip -> i_mtimensec = vap -> va_mtime . tv_nsec ; } ip -> i_birthtime = vap -> va_birthtime . tv_sec ; ip -> i_birthnsec = vap -> va_birthtime . tv_nsec ; error = ext2_update ( vp , 0 ) ; if ( error ) return ( error ) ; } error = 0 ; if ( vap -> va_mode != ( mode_t ) VNOVAL ) { if ( vp -> v_mount -> mnt_flag & MNT_RDONLY ) return ( EROFS ) ; error = ext2_chmod ( vp , ( int ) vap -> va_mode , cred , td ) ; } return ( error ) ; }
Set attribute vnode op.
Set attribute vnode op .
/*
	 * Check for unsettable attributes.
	 */ /* Disallow flags not supported by ext2fs. */ /*
		 * Callers may only modify the file flags on objects they
		 * have VADMIN rights for.
		 */ /*
		 * Unprivileged processes and privileged processes in
		 * jail() are not permitted to unset system flags, or
		 * modify flags if any system flags are set.
		 * Privileged non-jail processes may not modify system flags
		 * if securelevel > 0 and any existing system flags are set.
		 */ /*
	 * Go through the fields and update iff not VNOVAL.
	 */ /*
		 * Disallow write attempts on read-only file systems;
		 * unless the file is a socket, fifo, or a block or
		 * character device resident on the file system.
		 */ /*
		 * From utimes(2):
		 * If times is NULL, ... The caller must be the owner of
		 * the file, have permission to write the file, or be the
		 * super-user.
		 * If times is non-NULL, ... The caller must be the owner of
		 * the file or be the super-user.
		 */