summaryrefslogtreecommitdiffstats
path: root/fs/attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/attr.c')
-rw-r--r--fs/attr.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/fs/attr.c b/fs/attr.c
new file mode 100644
index 000000000..be824dd4a
--- /dev/null
+++ b/fs/attr.c
@@ -0,0 +1,99 @@
+/*
+ * linux/fs/attr.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * changes by Thomas Schoebel-Theuer
+ */
+
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/system.h>
+
+/* Taken over from the old code... */
+
+/* POSIX UID/GID verification for setting inode attributes. */
+int inode_change_ok(struct inode *inode, struct iattr *attr)
+{
+ /* If force is set do it anyway. */
+ if (attr->ia_valid & ATTR_FORCE)
+ return 0;
+
+ /* Make sure a caller can chown. */
+ if ((attr->ia_valid & ATTR_UID) &&
+ (current->fsuid != inode->i_uid ||
+ attr->ia_uid != inode->i_uid) && !fsuser())
+ return -EPERM;
+
+ /* Make sure caller can chgrp. */
+ if ((attr->ia_valid & ATTR_GID) &&
+ (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) &&
+ !fsuser())
+ return -EPERM;
+
+ /* Make sure a caller can chmod. */
+ if (attr->ia_valid & ATTR_MODE) {
+ if ((current->fsuid != inode->i_uid) && !fsuser())
+ return -EPERM;
+ /* Also check the setgid bit! */
+ if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid :
+ inode->i_gid))
+ attr->ia_mode &= ~S_ISGID;
+ }
+
+ /* Check for setting the inode time. */
+ if ((attr->ia_valid & ATTR_ATIME_SET) &&
+ ((current->fsuid != inode->i_uid) && !fsuser()))
+ return -EPERM;
+ if ((attr->ia_valid & ATTR_MTIME_SET) &&
+ ((current->fsuid != inode->i_uid) && !fsuser()))
+ return -EPERM;
+ return 0;
+}
+
+void inode_setattr(struct inode * inode, struct iattr * attr)
+{
+ if(attr->ia_valid &
+ (ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_MODE)) {
+ if (attr->ia_valid & ATTR_UID)
+ inode->i_uid = attr->ia_uid;
+ if (attr->ia_valid & ATTR_GID)
+ inode->i_gid = attr->ia_gid;
+ if (attr->ia_valid & ATTR_SIZE)
+ inode->i_size = attr->ia_size;
+ if (attr->ia_valid & ATTR_ATIME)
+ inode->i_atime = attr->ia_atime;
+ if (attr->ia_valid & ATTR_MTIME)
+ inode->i_mtime = attr->ia_mtime;
+ if (attr->ia_valid & ATTR_CTIME)
+ inode->i_ctime = attr->ia_ctime;
+ if (attr->ia_valid & ATTR_MODE) {
+ inode->i_mode = attr->ia_mode;
+ if (!fsuser() && !in_group_p(inode->i_gid))
+ inode->i_mode &= ~S_ISGID;
+ }
+ inode->i_dirt = 1;
+ }
+}
+
+int notify_change(struct inode * inode, struct iattr * attr)
+{
+ int error;
+ time_t now = CURRENT_TIME;
+
+ attr->ia_ctime = now;
+ if ((attr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET)) == ATTR_ATIME)
+ attr->ia_atime = now;
+ if ((attr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET)) == ATTR_MTIME)
+ attr->ia_mtime = now;
+ attr->ia_valid &= ~(ATTR_CTIME);
+ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change)
+ return inode->i_sb->s_op->notify_change(inode, attr);
+ error = inode_change_ok(inode, attr);
+ if(!error)
+ inode_setattr(inode, attr);
+ return error;
+}
+