Linux 2.2.0
[davej-history.git] / fs / stat.c
blob0246a44a137a8f24816aa215b675ae04ec84ca5e
1 /*
2 * linux/fs/stat.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/mm.h>
8 #include <linux/errno.h>
9 #include <linux/file.h>
10 #include <linux/smp_lock.h>
12 #include <asm/uaccess.h>
15 * Revalidate the inode. This is required for proper NFS attribute caching.
17 static __inline__ int
18 do_revalidate(struct dentry *dentry)
20 struct inode * inode = dentry->d_inode;
21 if (inode->i_op && inode->i_op->revalidate)
22 return inode->i_op->revalidate(dentry);
23 return 0;
27 #if !defined(__alpha__) && !defined(__sparc__)
30 * For backward compatibility? Maybe this should be moved
31 * into arch/i386 instead?
33 static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
35 static int warncount = 5;
36 struct __old_kernel_stat tmp;
38 if (warncount) {
39 warncount--;
40 printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
41 current->comm);
44 tmp.st_dev = kdev_t_to_nr(inode->i_dev);
45 tmp.st_ino = inode->i_ino;
46 tmp.st_mode = inode->i_mode;
47 tmp.st_nlink = inode->i_nlink;
48 tmp.st_uid = inode->i_uid;
49 tmp.st_gid = inode->i_gid;
50 tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
51 tmp.st_size = inode->i_size;
52 tmp.st_atime = inode->i_atime;
53 tmp.st_mtime = inode->i_mtime;
54 tmp.st_ctime = inode->i_ctime;
55 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
58 #endif
60 static int cp_new_stat(struct inode * inode, struct stat * statbuf)
62 struct stat tmp;
63 unsigned int blocks, indirect;
65 memset(&tmp, 0, sizeof(tmp));
66 tmp.st_dev = kdev_t_to_nr(inode->i_dev);
67 tmp.st_ino = inode->i_ino;
68 tmp.st_mode = inode->i_mode;
69 tmp.st_nlink = inode->i_nlink;
70 tmp.st_uid = inode->i_uid;
71 tmp.st_gid = inode->i_gid;
72 tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
73 tmp.st_size = inode->i_size;
74 tmp.st_atime = inode->i_atime;
75 tmp.st_mtime = inode->i_mtime;
76 tmp.st_ctime = inode->i_ctime;
78 * st_blocks and st_blksize are approximated with a simple algorithm if
79 * they aren't supported directly by the filesystem. The minix and msdos
80 * filesystems don't keep track of blocks, so they would either have to
81 * be counted explicitly (by delving into the file itself), or by using
82 * this simple algorithm to get a reasonable (although not 100% accurate)
83 * value.
87 * Use minix fs values for the number of direct and indirect blocks. The
88 * count is now exact for the minix fs except that it counts zero blocks.
89 * Everything is in units of BLOCK_SIZE until the assignment to
90 * tmp.st_blksize.
92 #define D_B 7
93 #define I_B (BLOCK_SIZE / sizeof(unsigned short))
95 if (!inode->i_blksize) {
96 blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
97 if (blocks > D_B) {
98 indirect = (blocks - D_B + I_B - 1) / I_B;
99 blocks += indirect;
100 if (indirect > 1) {
101 indirect = (indirect - 1 + I_B - 1) / I_B;
102 blocks += indirect;
103 if (indirect > 1)
104 blocks++;
107 tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
108 tmp.st_blksize = BLOCK_SIZE;
109 } else {
110 tmp.st_blocks = inode->i_blocks;
111 tmp.st_blksize = inode->i_blksize;
113 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
117 #if !defined(__alpha__) && !defined(__sparc__)
119 * For backward compatibility? Maybe this should be moved
120 * into arch/i386 instead?
122 asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
124 struct dentry * dentry;
125 int error;
127 lock_kernel();
128 dentry = namei(filename);
130 error = PTR_ERR(dentry);
131 if (!IS_ERR(dentry)) {
132 error = do_revalidate(dentry);
133 if (!error)
134 error = cp_old_stat(dentry->d_inode, statbuf);
136 dput(dentry);
138 unlock_kernel();
139 return error;
141 #endif
143 asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
145 struct dentry * dentry;
146 int error;
148 lock_kernel();
149 dentry = namei(filename);
151 error = PTR_ERR(dentry);
152 if (!IS_ERR(dentry)) {
153 error = do_revalidate(dentry);
154 if (!error)
155 error = cp_new_stat(dentry->d_inode, statbuf);
157 dput(dentry);
159 unlock_kernel();
160 return error;
163 #if !defined(__alpha__) && !defined(__sparc__)
166 * For backward compatibility? Maybe this should be moved
167 * into arch/i386 instead?
169 asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
171 struct dentry * dentry;
172 int error;
174 lock_kernel();
175 dentry = lnamei(filename);
177 error = PTR_ERR(dentry);
178 if (!IS_ERR(dentry)) {
179 error = do_revalidate(dentry);
180 if (!error)
181 error = cp_old_stat(dentry->d_inode, statbuf);
183 dput(dentry);
185 unlock_kernel();
186 return error;
189 #endif
191 asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
193 struct dentry * dentry;
194 int error;
196 lock_kernel();
197 dentry = lnamei(filename);
199 error = PTR_ERR(dentry);
200 if (!IS_ERR(dentry)) {
201 error = do_revalidate(dentry);
202 if (!error)
203 error = cp_new_stat(dentry->d_inode, statbuf);
205 dput(dentry);
207 unlock_kernel();
208 return error;
211 #if !defined(__alpha__) && !defined(__sparc__)
214 * For backward compatibility? Maybe this should be moved
215 * into arch/i386 instead?
217 asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
219 struct file * f;
220 int err = -EBADF;
222 lock_kernel();
223 f = fget(fd);
224 if (f) {
225 struct dentry * dentry = f->f_dentry;
227 err = do_revalidate(dentry);
228 if (!err)
229 err = cp_old_stat(dentry->d_inode, statbuf);
230 fput(f);
232 unlock_kernel();
233 return err;
236 #endif
238 asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf)
240 struct file * f;
241 int err = -EBADF;
243 lock_kernel();
244 f = fget(fd);
245 if (f) {
246 struct dentry * dentry = f->f_dentry;
248 err = do_revalidate(dentry);
249 if (!err)
250 err = cp_new_stat(dentry->d_inode, statbuf);
251 fput(f);
253 unlock_kernel();
254 return err;
257 asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
259 struct dentry * dentry;
260 int error;
262 if (bufsiz <= 0)
263 return -EINVAL;
265 lock_kernel();
266 dentry = lnamei(path);
268 error = PTR_ERR(dentry);
269 if (!IS_ERR(dentry)) {
270 struct inode * inode = dentry->d_inode;
272 error = -EINVAL;
273 if (inode->i_op && inode->i_op->readlink &&
274 !(error = do_revalidate(dentry))) {
275 UPDATE_ATIME(inode);
276 error = inode->i_op->readlink(dentry, buf, bufsiz);
278 dput(dentry);
280 unlock_kernel();
281 return error;