Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *  linux/fs/attr.c
  3  *
  4  *  Copyright (C) 1991, 1992  Linus Torvalds
  5  *  changes by Thomas Schoebel-Theuer
  6  */
  7 
  8 #include <linux/module.h>
  9 #include <linux/time.h>
 10 #include <linux/mm.h>
 11 #include <linux/string.h>
 12 #include <linux/capability.h>
 13 #include <linux/fsnotify.h>
 14 #include <linux/fcntl.h>
 15 #include <linux/quotaops.h>
 16 #include <linux/security.h>
 17 
 18 /* Taken over from the old code... */
 19 
 20 /* POSIX UID/GID verification for setting inode attributes. */
 21 int inode_change_ok(struct inode *inode, struct iattr *attr)
 22 {
 23         int retval = -EPERM;
 24         unsigned int ia_valid = attr->ia_valid;
 25 
 26         /* If force is set do it anyway. */
 27         if (ia_valid & ATTR_FORCE)
 28                 goto fine;
 29 
 30         /* Make sure a caller can chown. */
 31         if ((ia_valid & ATTR_UID) &&
 32             (current_fsuid() != inode->i_uid ||
 33              attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
 34                 goto error;
 35 
 36         /* Make sure caller can chgrp. */
 37         if ((ia_valid & ATTR_GID) &&
 38             (current_fsuid() != inode->i_uid ||
 39             (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
 40             !capable(CAP_CHOWN))
 41                 goto error;
 42 
 43         /* Make sure a caller can chmod. */
 44         if (ia_valid & ATTR_MODE) {
 45                 if (!is_owner_or_cap(inode))
 46                         goto error;
 47                 /* Also check the setgid bit! */
 48                 if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
 49                                 inode->i_gid) && !capable(CAP_FSETID))
 50                         attr->ia_mode &= ~S_ISGID;
 51         }
 52 
 53         /* Check for setting the inode time. */
 54         if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
 55                 if (!is_owner_or_cap(inode))
 56                         goto error;
 57         }
 58 fine:
 59         retval = 0;
 60 error:
 61         return retval;
 62 }
 63 
 64 EXPORT_SYMBOL(inode_change_ok);
 65 
 66 int inode_setattr(struct inode * inode, struct iattr * attr)
 67 {
 68         unsigned int ia_valid = attr->ia_valid;
 69 
 70         if (ia_valid & ATTR_SIZE &&
 71             attr->ia_size != i_size_read(inode)) {
 72                 int error = vmtruncate(inode, attr->ia_size);
 73                 if (error)
 74                         return error;
 75         }
 76 
 77         if (ia_valid & ATTR_UID)
 78                 inode->i_uid = attr->ia_uid;
 79         if (ia_valid & ATTR_GID)
 80                 inode->i_gid = attr->ia_gid;
 81         if (ia_valid & ATTR_ATIME)
 82                 inode->i_atime = timespec_trunc(attr->ia_atime,
 83                                                 inode->i_sb->s_time_gran);
 84         if (ia_valid & ATTR_MTIME)
 85                 inode->i_mtime = timespec_trunc(attr->ia_mtime,
 86                                                 inode->i_sb->s_time_gran);
 87         if (ia_valid & ATTR_CTIME)
 88                 inode->i_ctime = timespec_trunc(attr->ia_ctime,
 89                                                 inode->i_sb->s_time_gran);
 90         if (ia_valid & ATTR_MODE) {
 91                 umode_t mode = attr->ia_mode;
 92 
 93                 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
 94                         mode &= ~S_ISGID;
 95                 inode->i_mode = mode;
 96         }
 97         mark_inode_dirty(inode);
 98 
 99         return 0;
100 }
101 EXPORT_SYMBOL(inode_setattr);
102 
103 int notify_change(struct dentry * dentry, struct iattr * attr)
104 {
105         struct inode *inode = dentry->d_inode;
106         mode_t mode = inode->i_mode;
107         int error;
108         struct timespec now;
109         unsigned int ia_valid = attr->ia_valid;
110 
111         if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
112                 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
113                         return -EPERM;
114         }
115 
116         now = current_fs_time(inode->i_sb);
117 
118         attr->ia_ctime = now;
119         if (!(ia_valid & ATTR_ATIME_SET))
120                 attr->ia_atime = now;
121         if (!(ia_valid & ATTR_MTIME_SET))
122                 attr->ia_mtime = now;
123         if (ia_valid & ATTR_KILL_PRIV) {
124                 attr->ia_valid &= ~ATTR_KILL_PRIV;
125                 ia_valid &= ~ATTR_KILL_PRIV;
126                 error = security_inode_need_killpriv(dentry);
127                 if (error > 0)
128                         error = security_inode_killpriv(dentry);
129                 if (error)
130                         return error;
131         }
132 
133         /*
134          * We now pass ATTR_KILL_S*ID to the lower level setattr function so
135          * that the function has the ability to reinterpret a mode change
136          * that's due to these bits. This adds an implicit restriction that
137          * no function will ever call notify_change with both ATTR_MODE and
138          * ATTR_KILL_S*ID set.
139          */
140         if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) &&
141             (ia_valid & ATTR_MODE))
142                 BUG();
143 
144         if (ia_valid & ATTR_KILL_SUID) {
145                 if (mode & S_ISUID) {
146                         ia_valid = attr->ia_valid |= ATTR_MODE;
147                         attr->ia_mode = (inode->i_mode & ~S_ISUID);
148                 }
149         }
150         if (ia_valid & ATTR_KILL_SGID) {
151                 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
152                         if (!(ia_valid & ATTR_MODE)) {
153                                 ia_valid = attr->ia_valid |= ATTR_MODE;
154                                 attr->ia_mode = inode->i_mode;
155                         }
156                         attr->ia_mode &= ~S_ISGID;
157                 }
158         }
159         if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
160                 return 0;
161 
162         error = security_inode_setattr(dentry, attr);
163         if (error)
164                 return error;
165 
166         if (ia_valid & ATTR_SIZE)
167                 down_write(&dentry->d_inode->i_alloc_sem);
168 
169         if (inode->i_op && inode->i_op->setattr) {
170                 error = inode->i_op->setattr(dentry, attr);
171         } else {
172                 error = inode_change_ok(inode, attr);
173                 if (!error) {
174                         if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
175                             (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
176                                 error = vfs_dq_transfer(inode, attr) ?
177                                         -EDQUOT : 0;
178                         if (!error)
179                                 error = inode_setattr(inode, attr);
180                 }
181         }
182 
183         if (ia_valid & ATTR_SIZE)
184                 up_write(&dentry->d_inode->i_alloc_sem);
185 
186         if (!error)
187                 fsnotify_change(dentry, ia_valid);
188 
189         return error;
190 }
191 
192 EXPORT_SYMBOL(notify_change);
193 
  This page was automatically generated by the LXR engine.