/* * linux/fs/attr.c * * Copyright (C) 1991, 1992 Linus Torvalds * changes by Thomas Schoebel-Theuer */ #include <linux/sched.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/smp_lock.h> #include <linux/dnotify.h> #include <linux/fcntl.h> /* Taken over from the old code... */ /* POSIX UID/GID verification for setting inode attributes. */ 18 int inode_change_ok(struct inode *inode, struct iattr *attr) { int retval = -EPERM; unsigned int ia_valid = attr->ia_valid; /* If force is set do it anyway. */ 24 if (ia_valid & ATTR_FORCE) 25 goto fine; /* Make sure a caller can chown. */ if ((ia_valid & ATTR_UID) && (current->fsuid != inode->i_uid || 30 attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) 31 goto error; /* Make sure caller can chgrp. */ if ((ia_valid & ATTR_GID) && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && 36 !capable(CAP_CHOWN)) 37 goto error; /* Make sure a caller can chmod. */ 40 if (ia_valid & ATTR_MODE) { 41 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 42 goto error; /* Also check the setgid bit! */ if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : 45 inode->i_gid) && !capable(CAP_FSETID)) attr->ia_mode &= ~S_ISGID; } /* Check for setting the inode time. */ 50 if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { 51 if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) 52 goto error; } fine: retval = 0; error: 57 return retval; } 60 void inode_setattr(struct inode * inode, struct iattr * attr) { unsigned int ia_valid = attr->ia_valid; 64 if (ia_valid & ATTR_UID) inode->i_uid = attr->ia_uid; 66 if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; 68 if (ia_valid & ATTR_SIZE) vmtruncate(inode, attr->ia_size); 70 if (ia_valid & ATTR_ATIME) inode->i_atime = attr->ia_atime; 72 if (ia_valid & ATTR_MTIME) inode->i_mtime = attr->ia_mtime; 74 if (ia_valid & ATTR_CTIME) inode->i_ctime = attr->ia_ctime; 76 if (ia_valid & ATTR_MODE) { inode->i_mode = attr->ia_mode; 78 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) inode->i_mode &= ~S_ISGID; } mark_inode_dirty(inode); } 84 static int setattr_mask(unsigned int ia_valid) { unsigned long dn_mask = 0; 88 if (ia_valid & ATTR_UID) dn_mask |= DN_ATTRIB; 90 if (ia_valid & ATTR_GID) dn_mask |= DN_ATTRIB; 92 if (ia_valid & ATTR_SIZE) dn_mask |= DN_MODIFY; /* both times implies a utime(s) call */ 95 if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME)) dn_mask |= DN_ATTRIB; 97 else if (ia_valid & ATTR_ATIME) dn_mask |= DN_ACCESS; 99 else if (ia_valid & ATTR_MTIME) dn_mask |= DN_MODIFY; 101 if (ia_valid & ATTR_MODE) dn_mask |= DN_ATTRIB; 103 return dn_mask; } 106 int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; int error; time_t now = CURRENT_TIME; unsigned int ia_valid = attr->ia_valid; 113 if (!inode) 114 BUG(); attr->ia_ctime = now; 117 if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; 119 if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; 122 lock_kernel(); 123 if (inode->i_op && inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); 125 else { error = inode_change_ok(inode, attr); 127 if (!error) inode_setattr(inode, attr); } 130 unlock_kernel(); 131 if (!error) { unsigned long dn_mask = setattr_mask(ia_valid); 133 if (dn_mask) inode_dir_notify(dentry->d_parent->d_inode, dn_mask); } 136 return error; }