[PATCH] m68k: bitops update [3/20]
[linux-2.6/history.git] / fs / stat.c
blob925fc44f67ba74b0f3c67321e67048bf33c21a92
1 /*
2 * linux/fs/stat.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/config.h>
8 #include <linux/mm.h>
9 #include <linux/errno.h>
10 #include <linux/file.h>
11 #include <linux/smp_lock.h>
12 #include <linux/highuid.h>
13 #include <linux/fs.h>
15 #include <asm/uaccess.h>
18 * Revalidate the inode. This is required for proper NFS attribute caching.
20 static __inline__ int
21 do_revalidate(struct dentry *dentry)
23 struct inode * inode = dentry->d_inode;
24 if (inode->i_op && inode->i_op->revalidate)
25 return inode->i_op->revalidate(dentry);
26 return 0;
29 static int do_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
31 int res = 0;
32 unsigned int blocks, indirect;
33 struct inode *inode = dentry->d_inode;
35 res = do_revalidate(dentry);
36 if (res)
37 return res;
39 stat->dev = kdev_t_to_nr(inode->i_dev);
40 stat->ino = inode->i_ino;
41 stat->mode = inode->i_mode;
42 stat->nlink = inode->i_nlink;
43 stat->uid = inode->i_uid;
44 stat->gid = inode->i_gid;
45 stat->rdev = kdev_t_to_nr(inode->i_rdev);
46 stat->atime = inode->i_atime;
47 stat->mtime = inode->i_mtime;
48 stat->ctime = inode->i_ctime;
49 stat->ctime = inode->i_ctime;
50 stat->size = inode->i_size;
52 * st_blocks and st_blksize are approximated with a simple algorithm if
53 * they aren't supported directly by the filesystem. The minix and msdos
54 * filesystems don't keep track of blocks, so they would either have to
55 * be counted explicitly (by delving into the file itself), or by using
56 * this simple algorithm to get a reasonable (although not 100% accurate)
57 * value.
61 * Use minix fs values for the number of direct and indirect blocks. The
62 * count is now exact for the minix fs except that it counts zero blocks.
63 * Everything is in units of BLOCK_SIZE until the assignment to
64 * tmp.st_blksize.
66 #define D_B 7
67 #define I_B (BLOCK_SIZE / sizeof(unsigned short))
69 if (!inode->i_blksize) {
70 blocks = (stat->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
71 if (blocks > D_B) {
72 indirect = (blocks - D_B + I_B - 1) / I_B;
73 blocks += indirect;
74 if (indirect > 1) {
75 indirect = (indirect - 1 + I_B - 1) / I_B;
76 blocks += indirect;
77 if (indirect > 1)
78 blocks++;
81 stat->blocks = (BLOCK_SIZE / 512) * blocks;
82 stat->blksize = BLOCK_SIZE;
83 } else {
84 stat->blocks = inode->i_blocks;
85 stat->blksize = inode->i_blksize;
87 return 0;
90 int vfs_stat(char *name, struct kstat *stat)
92 struct nameidata nd;
93 int error;
95 error = user_path_walk(name, &nd);
96 if (!error) {
97 error = do_getattr(nd.mnt, nd.dentry, stat);
98 path_release(&nd);
100 return error;
103 int vfs_lstat(char *name, struct kstat *stat)
105 struct nameidata nd;
106 int error;
108 error = user_path_walk_link(name, &nd);
109 if (!error) {
110 error = do_getattr(nd.mnt, nd.dentry, stat);
111 path_release(&nd);
113 return error;
116 int vfs_fstat(unsigned int fd, struct kstat *stat)
118 struct file *f = fget(fd);
119 int error = -EBADF;
121 if (f) {
122 error = do_getattr(f->f_vfsmnt, f->f_dentry, stat);
123 fput(f);
125 return error;
128 #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) \
129 && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) \
130 && !defined(__arm__)
133 * For backward compatibility? Maybe this should be moved
134 * into arch/i386 instead?
136 static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat * statbuf)
138 static int warncount = 5;
139 struct __old_kernel_stat tmp;
141 if (warncount > 0) {
142 warncount--;
143 printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
144 current->comm);
145 } else if (warncount < 0) {
146 /* it's laughable, but... */
147 warncount = 0;
150 tmp.st_dev = stat->dev;
151 tmp.st_ino = stat->ino;
152 tmp.st_mode = stat->mode;
153 tmp.st_nlink = stat->nlink;
154 SET_OLDSTAT_UID(tmp, stat->uid);
155 SET_OLDSTAT_GID(tmp, stat->gid);
156 tmp.st_rdev = stat->rdev;
157 #if BITS_PER_LONG == 32
158 if (stat->size > MAX_NON_LFS)
159 return -EOVERFLOW;
160 #endif
161 tmp.st_size = stat->size;
162 tmp.st_atime = stat->atime;
163 tmp.st_mtime = stat->mtime;
164 tmp.st_ctime = stat->ctime;
165 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
168 asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
170 struct kstat stat;
171 int error = vfs_stat(filename, &stat);
173 if (!error)
174 error = cp_old_stat(&stat, statbuf);
176 return error;
178 asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
180 struct kstat stat;
181 int error = vfs_lstat(filename, &stat);
183 if (!error)
184 error = cp_old_stat(&stat, statbuf);
186 return error;
188 asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
190 struct kstat stat;
191 int error = vfs_fstat(fd, &stat);
193 if (!error)
194 error = cp_old_stat(&stat, statbuf);
196 return error;
199 #endif
201 static int cp_new_stat(struct kstat *stat, struct stat *statbuf)
203 struct stat tmp;
205 memset(&tmp, 0, sizeof(tmp));
206 tmp.st_dev = stat->dev;
207 tmp.st_ino = stat->ino;
208 tmp.st_mode = stat->mode;
209 tmp.st_nlink = stat->nlink;
210 SET_STAT_UID(tmp, stat->uid);
211 SET_STAT_GID(tmp, stat->gid);
212 tmp.st_rdev = stat->rdev;
213 #if BITS_PER_LONG == 32
214 if (stat->size > MAX_NON_LFS)
215 return -EOVERFLOW;
216 #endif
217 tmp.st_size = stat->size;
218 tmp.st_atime = stat->atime;
219 tmp.st_mtime = stat->mtime;
220 tmp.st_ctime = stat->ctime;
221 tmp.st_blocks = stat->blocks;
222 tmp.st_blksize = stat->blksize;
223 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
226 asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
228 struct kstat stat;
229 int error = vfs_stat(filename, &stat);
231 if (!error)
232 error = cp_new_stat(&stat, statbuf);
234 return error;
236 asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
238 struct kstat stat;
239 int error = vfs_lstat(filename, &stat);
241 if (!error)
242 error = cp_new_stat(&stat, statbuf);
244 return error;
246 asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf)
248 struct kstat stat;
249 int error = vfs_fstat(fd, &stat);
251 if (!error)
252 error = cp_new_stat(&stat, statbuf);
254 return error;
257 asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
259 struct nameidata nd;
260 int error;
262 if (bufsiz <= 0)
263 return -EINVAL;
265 error = user_path_walk_link(path, &nd);
266 if (!error) {
267 struct inode * inode = nd.dentry->d_inode;
269 error = -EINVAL;
270 if (inode->i_op && inode->i_op->readlink &&
271 !(error = do_revalidate(nd.dentry))) {
272 UPDATE_ATIME(inode);
273 error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
275 path_release(&nd);
277 return error;
281 /* ---------- LFS-64 ----------- */
282 #if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(__x86_64__) && !defined(CONFIG_ARCH_S390X)
284 static long cp_new_stat64(struct kstat *stat, struct stat64 *statbuf)
286 struct stat64 tmp;
288 memset(&tmp, 0, sizeof(tmp));
289 tmp.st_dev = stat->dev;
290 tmp.st_ino = stat->ino;
291 #ifdef STAT64_HAS_BROKEN_ST_INO
292 tmp.__st_ino = stat->ino;
293 #endif
294 tmp.st_mode = stat->mode;
295 tmp.st_nlink = stat->nlink;
296 tmp.st_uid = stat->uid;
297 tmp.st_gid = stat->gid;
298 tmp.st_rdev = stat->rdev;
299 tmp.st_atime = stat->atime;
300 tmp.st_mtime = stat->mtime;
301 tmp.st_ctime = stat->ctime;
302 tmp.st_size = stat->size;
303 tmp.st_blocks = stat->blocks;
304 tmp.st_blksize = stat->blksize;
305 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
308 asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags)
310 struct kstat stat;
311 int error = vfs_stat(filename, &stat);
313 if (!error)
314 error = cp_new_stat64(&stat, statbuf);
316 return error;
318 asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags)
320 struct kstat stat;
321 int error = vfs_lstat(filename, &stat);
323 if (!error)
324 error = cp_new_stat64(&stat, statbuf);
326 return error;
328 asmlinkage long sys_fstat64(unsigned long fd, struct stat64 * statbuf, long flags)
330 struct kstat stat;
331 int error = vfs_fstat(fd, &stat);
333 if (!error)
334 error = cp_new_stat64(&stat, statbuf);
336 return error;
339 #endif /* LFS-64 */