Blame view
fs/attr.c
6.04 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 |
/* * linux/fs/attr.c * * Copyright (C) 1991, 1992 Linus Torvalds * changes by Thomas Schoebel-Theuer */ #include <linux/module.h> #include <linux/time.h> #include <linux/mm.h> #include <linux/string.h> |
16f7e0fe2 [PATCH] capable/c... |
12 |
#include <linux/capability.h> |
0eeca2830 [PATCH] inotify |
13 |
#include <linux/fsnotify.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 |
#include <linux/fcntl.h> #include <linux/quotaops.h> #include <linux/security.h> |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 20 |
/* Taken over from the old code... */ /* POSIX UID/GID verification for setting inode attributes. */ |
25d9e2d15 truncate: new hel... |
21 |
int inode_change_ok(const struct inode *inode, struct iattr *attr) |
1da177e4c Linux-2.6.12-rc2 |
22 23 24 25 26 27 28 29 30 31 |
{ int retval = -EPERM; unsigned int ia_valid = attr->ia_valid; /* If force is set do it anyway. */ if (ia_valid & ATTR_FORCE) goto fine; /* Make sure a caller can chown. */ if ((ia_valid & ATTR_UID) && |
da9592ede CRED: Wrap task c... |
32 |
(current_fsuid() != inode->i_uid || |
1da177e4c Linux-2.6.12-rc2 |
33 34 35 36 37 |
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) goto error; /* Make sure caller can chgrp. */ if ((ia_valid & ATTR_GID) && |
da9592ede CRED: Wrap task c... |
38 |
(current_fsuid() != inode->i_uid || |
1da177e4c Linux-2.6.12-rc2 |
39 40 41 42 43 44 |
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && !capable(CAP_CHOWN)) goto error; /* Make sure a caller can chmod. */ if (ia_valid & ATTR_MODE) { |
3bd858ab1 Introduce is_owne... |
45 |
if (!is_owner_or_cap(inode)) |
1da177e4c Linux-2.6.12-rc2 |
46 47 48 49 50 51 52 53 |
goto error; /* Also check the setgid bit! */ if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : inode->i_gid) && !capable(CAP_FSETID)) attr->ia_mode &= ~S_ISGID; } /* Check for setting the inode time. */ |
9767d7495 [patch 1/4] vfs: ... |
54 |
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) { |
3bd858ab1 Introduce is_owne... |
55 |
if (!is_owner_or_cap(inode)) |
1da177e4c Linux-2.6.12-rc2 |
56 57 58 59 60 61 62 |
goto error; } fine: retval = 0; error: return retval; } |
1da177e4c Linux-2.6.12-rc2 |
63 |
EXPORT_SYMBOL(inode_change_ok); |
25d9e2d15 truncate: new hel... |
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
/** * inode_newsize_ok - may this inode be truncated to a given size * @inode: the inode to be truncated * @offset: the new size to assign to the inode * @Returns: 0 on success, -ve errno on failure * * inode_newsize_ok will check filesystem limits and ulimits to check that the * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ * when necessary. Caller must not proceed with inode size change if failure is * returned. @inode must be a file (not directory), with appropriate * permissions to allow truncate (inode_newsize_ok does NOT check these * conditions). * * inode_newsize_ok must be called with i_mutex held. */ int inode_newsize_ok(const struct inode *inode, loff_t offset) { if (inode->i_size < offset) { unsigned long limit; limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; if (limit != RLIM_INFINITY && offset > limit) goto out_sig; if (offset > inode->i_sb->s_maxbytes) goto out_big; } else { /* * truncation of in-use swapfiles is disallowed - it would * cause subsequent swapout to scribble on the now-freed * blocks. */ if (IS_SWAPFILE(inode)) return -ETXTBSY; } return 0; out_sig: send_sig(SIGXFSZ, current, 0); out_big: return -EFBIG; } EXPORT_SYMBOL(inode_newsize_ok); |
1da177e4c Linux-2.6.12-rc2 |
106 107 108 |
int inode_setattr(struct inode * inode, struct iattr * attr) { unsigned int ia_valid = attr->ia_valid; |
4a30131e7 [PATCH] Fix some ... |
109 110 111 112 113 114 |
if (ia_valid & ATTR_SIZE && attr->ia_size != i_size_read(inode)) { int error = vmtruncate(inode, attr->ia_size); if (error) return error; |
1da177e4c Linux-2.6.12-rc2 |
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
} if (ia_valid & ATTR_UID) inode->i_uid = attr->ia_uid; if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; if (ia_valid & ATTR_ATIME) inode->i_atime = timespec_trunc(attr->ia_atime, inode->i_sb->s_time_gran); if (ia_valid & ATTR_MTIME) inode->i_mtime = timespec_trunc(attr->ia_mtime, inode->i_sb->s_time_gran); if (ia_valid & ATTR_CTIME) inode->i_ctime = timespec_trunc(attr->ia_ctime, inode->i_sb->s_time_gran); if (ia_valid & ATTR_MODE) { umode_t mode = attr->ia_mode; if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) mode &= ~S_ISGID; inode->i_mode = mode; } mark_inode_dirty(inode); |
4a30131e7 [PATCH] Fix some ... |
138 139 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
140 |
} |
1da177e4c Linux-2.6.12-rc2 |
141 |
EXPORT_SYMBOL(inode_setattr); |
1da177e4c Linux-2.6.12-rc2 |
142 143 144 |
int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; |
6de0ec00b VFS: make notify_... |
145 |
mode_t mode = inode->i_mode; |
1da177e4c Linux-2.6.12-rc2 |
146 147 148 |
int error; struct timespec now; unsigned int ia_valid = attr->ia_valid; |
beb29e058 [patch 4/4] vfs: ... |
149 150 151 152 |
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; } |
1da177e4c Linux-2.6.12-rc2 |
153 154 155 156 157 158 159 |
now = current_fs_time(inode->i_sb); attr->ia_ctime = now; if (!(ia_valid & ATTR_ATIME_SET)) attr->ia_atime = now; if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; |
b53767719 Implement file po... |
160 161 162 163 164 165 166 167 168 |
if (ia_valid & ATTR_KILL_PRIV) { attr->ia_valid &= ~ATTR_KILL_PRIV; ia_valid &= ~ATTR_KILL_PRIV; error = security_inode_need_killpriv(dentry); if (error > 0) error = security_inode_killpriv(dentry); if (error) return error; } |
6de0ec00b VFS: make notify_... |
169 170 171 172 173 174 175 176 177 178 179 |
/* * We now pass ATTR_KILL_S*ID to the lower level setattr function so * that the function has the ability to reinterpret a mode change * that's due to these bits. This adds an implicit restriction that * no function will ever call notify_change with both ATTR_MODE and * ATTR_KILL_S*ID set. */ if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && (ia_valid & ATTR_MODE)) BUG(); |
1da177e4c Linux-2.6.12-rc2 |
180 |
if (ia_valid & ATTR_KILL_SUID) { |
1da177e4c Linux-2.6.12-rc2 |
181 |
if (mode & S_ISUID) { |
6de0ec00b VFS: make notify_... |
182 183 |
ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = (inode->i_mode & ~S_ISUID); |
1da177e4c Linux-2.6.12-rc2 |
184 185 186 |
} } if (ia_valid & ATTR_KILL_SGID) { |
1da177e4c Linux-2.6.12-rc2 |
187 188 189 190 191 192 193 194 |
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { if (!(ia_valid & ATTR_MODE)) { ia_valid = attr->ia_valid |= ATTR_MODE; attr->ia_mode = inode->i_mode; } attr->ia_mode &= ~S_ISGID; } } |
6de0ec00b VFS: make notify_... |
195 |
if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) |
1da177e4c Linux-2.6.12-rc2 |
196 |
return 0; |
a77b72da2 [patch] vfs: make... |
197 198 199 |
error = security_inode_setattr(dentry, attr); if (error) return error; |
1da177e4c Linux-2.6.12-rc2 |
200 201 202 203 |
if (ia_valid & ATTR_SIZE) down_write(&dentry->d_inode->i_alloc_sem); if (inode->i_op && inode->i_op->setattr) { |
a77b72da2 [patch] vfs: make... |
204 |
error = inode->i_op->setattr(dentry, attr); |
1da177e4c Linux-2.6.12-rc2 |
205 206 |
} else { error = inode_change_ok(inode, attr); |
1da177e4c Linux-2.6.12-rc2 |
207 208 209 |
if (!error) { if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) |
9e3509e27 vfs: Use lowercas... |
210 211 |
error = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0; |
1da177e4c Linux-2.6.12-rc2 |
212 213 214 215 216 217 218 |
if (!error) error = inode_setattr(inode, attr); } } if (ia_valid & ATTR_SIZE) up_write(&dentry->d_inode->i_alloc_sem); |
0eeca2830 [PATCH] inotify |
219 220 |
if (!error) fsnotify_change(dentry, ia_valid); |
1da177e4c Linux-2.6.12-rc2 |
221 222 223 224 |
return error; } EXPORT_SYMBOL(notify_change); |