~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/stat.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/stat.c
  3  *
  4  *  Copyright (C) 1991, 1992  Linus Torvalds
  5  */
  6 
  7 #include <linux/mm.h>
  8 #include <linux/errno.h>
  9 #include <linux/file.h>
 10 #include <linux/smp_lock.h>
 11 #include <linux/highuid.h>
 12 
 13 #include <asm/uaccess.h>
 14 
 15 /*
 16  * Revalidate the inode. This is required for proper NFS attribute caching.
 17  */
 18 static __inline__ int
 19 do_revalidate(struct dentry *dentry)
 20 {
 21         struct inode * inode = dentry->d_inode;
 22         if (inode->i_op && inode->i_op->revalidate)
 23                 return inode->i_op->revalidate(dentry);
 24         return 0;
 25 }
 26 
 27 
 28 #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
 29 
 30 /*
 31  * For backward compatibility?  Maybe this should be moved
 32  * into arch/i386 instead?
 33  */
 34 static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
 35 {
 36         static int warncount = 5;
 37         struct __old_kernel_stat tmp;
 38 
 39         if (warncount > 0) {
 40                 warncount--;
 41                 printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
 42                         current->comm);
 43         } else if (warncount < 0) {
 44                 /* it's laughable, but... */
 45                 warncount = 0;
 46         }
 47 
 48         tmp.st_dev = kdev_t_to_nr(inode->i_dev);
 49         tmp.st_ino = inode->i_ino;
 50         tmp.st_mode = inode->i_mode;
 51         tmp.st_nlink = inode->i_nlink;
 52         SET_OLDSTAT_UID(tmp, inode->i_uid);
 53         SET_OLDSTAT_GID(tmp, inode->i_gid);
 54         tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 55 #if BITS_PER_LONG == 32
 56         if (inode->i_size > 0x7fffffff)
 57                 return -EOVERFLOW;
 58 #endif  
 59         tmp.st_size = inode->i_size;
 60         tmp.st_atime = inode->i_atime;
 61         tmp.st_mtime = inode->i_mtime;
 62         tmp.st_ctime = inode->i_ctime;
 63         return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 64 }
 65 
 66 #endif
 67 
 68 static int cp_new_stat(struct inode * inode, struct stat * statbuf)
 69 {
 70         struct stat tmp;
 71         unsigned int blocks, indirect;
 72 
 73         memset(&tmp, 0, sizeof(tmp));
 74         tmp.st_dev = kdev_t_to_nr(inode->i_dev);
 75         tmp.st_ino = inode->i_ino;
 76         tmp.st_mode = inode->i_mode;
 77         tmp.st_nlink = inode->i_nlink;
 78         SET_STAT_UID(tmp, inode->i_uid);
 79         SET_STAT_GID(tmp, inode->i_gid);
 80         tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 81 #if BITS_PER_LONG == 32
 82         if (inode->i_size > 0x7fffffff)
 83                 return -EOVERFLOW;
 84 #endif  
 85         tmp.st_size = inode->i_size;
 86         tmp.st_atime = inode->i_atime;
 87         tmp.st_mtime = inode->i_mtime;
 88         tmp.st_ctime = inode->i_ctime;
 89 /*
 90  * st_blocks and st_blksize are approximated with a simple algorithm if
 91  * they aren't supported directly by the filesystem. The minix and msdos
 92  * filesystems don't keep track of blocks, so they would either have to
 93  * be counted explicitly (by delving into the file itself), or by using
 94  * this simple algorithm to get a reasonable (although not 100% accurate)
 95  * value.
 96  */
 97 
 98 /*
 99  * Use minix fs values for the number of direct and indirect blocks.  The
100  * count is now exact for the minix fs except that it counts zero blocks.
101  * Everything is in units of BLOCK_SIZE until the assignment to
102  * tmp.st_blksize.
103  */
104 #define D_B   7
105 #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
106 
107         if (!inode->i_blksize) {
108                 blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
109                 if (blocks > D_B) {
110                         indirect = (blocks - D_B + I_B - 1) / I_B;
111                         blocks += indirect;
112                         if (indirect > 1) {
113                                 indirect = (indirect - 1 + I_B - 1) / I_B;
114                                 blocks += indirect;
115                                 if (indirect > 1)
116                                         blocks++;
117                         }
118                 }
119                 tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
120                 tmp.st_blksize = BLOCK_SIZE;
121         } else {
122                 tmp.st_blocks = inode->i_blocks;
123                 tmp.st_blksize = inode->i_blksize;
124         }
125         return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
126 }
127 
128 
129 #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
130 /*
131  * For backward compatibility?  Maybe this should be moved
132  * into arch/i386 instead?
133  */
134 asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
135 {
136         struct nameidata nd;
137         int error;
138 
139         error = user_path_walk(filename, &nd);
140         if (!error) {
141                 error = do_revalidate(nd.dentry);
142                 if (!error)
143                         error = cp_old_stat(nd.dentry->d_inode, statbuf);
144                 path_release(&nd);
145         }
146         return error;
147 }
148 #endif
149 
150 asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
151 {
152         struct nameidata nd;
153         int error;
154 
155         error = user_path_walk(filename, &nd);
156         if (!error) {
157                 error = do_revalidate(nd.dentry);
158                 if (!error)
159                         error = cp_new_stat(nd.dentry->d_inode, statbuf);
160                 path_release(&nd);
161         }
162         return error;
163 }
164 
165 #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
166 
167 /*
168  * For backward compatibility?  Maybe this should be moved
169  * into arch/i386 instead?
170  */
171 asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
172 {
173         struct nameidata nd;
174         int error;
175 
176         error = user_path_walk_link(filename, &nd);
177         if (!error) {
178                 error = do_revalidate(nd.dentry);
179                 if (!error)
180                         error = cp_old_stat(nd.dentry->d_inode, statbuf);
181                 path_release(&nd);
182         }
183         return error;
184 }
185 
186 #endif
187 
188 asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
189 {
190         struct nameidata nd;
191         int error;
192 
193         error = user_path_walk_link(filename, &nd);
194         if (!error) {
195                 error = do_revalidate(nd.dentry);
196                 if (!error)
197                         error = cp_new_stat(nd.dentry->d_inode, statbuf);
198                 path_release(&nd);
199         }
200         return error;
201 }
202 
203 #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(__s390__) && !defined(__hppa__)
204 
205 /*
206  * For backward compatibility?  Maybe this should be moved
207  * into arch/i386 instead?
208  */
209 asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
210 {
211         struct file * f;
212         int err = -EBADF;
213 
214         f = fget(fd);
215         if (f) {
216                 struct dentry * dentry = f->f_dentry;
217 
218                 err = do_revalidate(dentry);
219                 if (!err)
220                         err = cp_old_stat(dentry->d_inode, statbuf);
221                 fput(f);
222         }
223         return err;
224 }
225 
226 #endif
227 
228 asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf)
229 {
230         struct file * f;
231         int err = -EBADF;
232 
233         f = fget(fd);
234         if (f) {
235                 struct dentry * dentry = f->f_dentry;
236 
237                 err = do_revalidate(dentry);
238                 if (!err)
239                         err = cp_new_stat(dentry->d_inode, statbuf);
240                 fput(f);
241         }
242         return err;
243 }
244 
245 asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
246 {
247         struct nameidata nd;
248         int error;
249 
250         if (bufsiz <= 0)
251                 return -EINVAL;
252 
253         error = user_path_walk_link(path, &nd);
254         if (!error) {
255                 struct inode * inode = nd.dentry->d_inode;
256 
257                 error = -EINVAL;
258                 if (inode->i_op && inode->i_op->readlink &&
259                     !(error = do_revalidate(nd.dentry))) {
260                         UPDATE_ATIME(inode);
261                         error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
262                 }
263                 path_release(&nd);
264         }
265         return error;
266 }
267 
268 
269 /* ---------- LFS-64 ----------- */
270 #if !defined(__alpha__) && !defined (__ia64__) && !defined(__mips64)
271 
272 static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
273 {
274         struct stat64 tmp;
275         unsigned int blocks, indirect;
276 
277         memset(&tmp, 0, sizeof(tmp));
278         tmp.st_dev = kdev_t_to_nr(inode->i_dev);
279         tmp.st_ino = inode->i_ino;
280 #ifdef STAT64_HAS_BROKEN_ST_INO
281         tmp.__st_ino = inode->i_ino;
282 #endif
283         tmp.st_mode = inode->i_mode;
284         tmp.st_nlink = inode->i_nlink;
285         tmp.st_uid = inode->i_uid;
286         tmp.st_gid = inode->i_gid;
287         tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
288         tmp.st_atime = inode->i_atime;
289         tmp.st_mtime = inode->i_mtime;
290         tmp.st_ctime = inode->i_ctime;
291         tmp.st_size = inode->i_size;
292 /*
293  * st_blocks and st_blksize are approximated with a simple algorithm if
294  * they aren't supported directly by the filesystem. The minix and msdos
295  * filesystems don't keep track of blocks, so they would either have to
296  * be counted explicitly (by delving into the file itself), or by using
297  * this simple algorithm to get a reasonable (although not 100% accurate)
298  * value.
299  */
300 
301 /*
302  * Use minix fs values for the number of direct and indirect blocks.  The
303  * count is now exact for the minix fs except that it counts zero blocks.
304  * Everything is in units of BLOCK_SIZE until the assignment to
305  * tmp.st_blksize.
306  */
307 #define D_B   7
308 #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
309 
310         if (!inode->i_blksize) {
311                 blocks = (tmp.st_size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
312                 if (blocks > D_B) {
313                         indirect = (blocks - D_B + I_B - 1) / I_B;
314                         blocks += indirect;
315                         if (indirect > 1) {
316                                 indirect = (indirect - 1 + I_B - 1) / I_B;
317                                 blocks += indirect;
318                                 if (indirect > 1)
319                                         blocks++;
320                         }
321                 }
322                 tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
323                 tmp.st_blksize = BLOCK_SIZE;
324         } else {
325                 tmp.st_blocks = inode->i_blocks;
326                 tmp.st_blksize = inode->i_blksize;
327         }
328         return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
329 }
330 
331 asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags)
332 {
333         struct nameidata nd;
334         int error;
335 
336         error = user_path_walk(filename, &nd);
337         if (!error) {
338                 error = do_revalidate(nd.dentry);
339                 if (!error)
340                         error = cp_new_stat64(nd.dentry->d_inode, statbuf);
341                 path_release(&nd);
342         }
343         return error;
344 }
345 
346 asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags)
347 {
348         struct nameidata nd;
349         int error;
350 
351         error = user_path_walk_link(filename, &nd);
352         if (!error) {
353                 error = do_revalidate(nd.dentry);
354                 if (!error)
355                         error = cp_new_stat64(nd.dentry->d_inode, statbuf);
356                 path_release(&nd);
357         }
358         return error;
359 }
360 
361 asmlinkage long sys_fstat64(unsigned long fd, struct stat64 * statbuf, long flags)
362 {
363         struct file * f;
364         int err = -EBADF;
365 
366         f = fget(fd);
367         if (f) {
368                 struct dentry * dentry = f->f_dentry;
369 
370                 err = do_revalidate(dentry);
371                 if (!err)
372                         err = cp_new_stat64(dentry->d_inode, statbuf);
373                 fput(f);
374         }
375         return err;
376 }
377 
378 #endif /* LFS-64 */
379 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.