1
2
3
4
5
6
7#include <linux/mm.h>
8#include <linux/errno.h>
9#include <linux/file.h>
10#include <linux/smp_lock.h>
11
12#include <asm/uaccess.h>
13
14
15
16
17static __inline__ int
18do_revalidate(struct dentry *dentry)
19{
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;
24}
25
26
27#if !defined(__alpha__) && !defined(__sparc__)
28
29
30
31
32
33static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
34{
35 static int warncount = 5;
36 struct __old_kernel_stat tmp;
37
38 if (warncount) {
39 warncount--;
40 printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
41 current->comm);
42 }
43
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;
56}
57
58#endif
59
60static int cp_new_stat(struct inode * inode, struct stat * statbuf)
61{
62 struct stat tmp;
63 unsigned int blocks, indirect;
64
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;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92#define D_B 7
93#define I_B (BLOCK_SIZE / sizeof(unsigned short))
94
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++;
105 }
106 }
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;
112 }
113 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
114}
115
116
117#if !defined(__alpha__) && !defined(__sparc__)
118
119
120
121
122asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
123{
124 struct dentry * dentry;
125 int error;
126
127 lock_kernel();
128 dentry = namei(filename);
129
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);
135
136 dput(dentry);
137 }
138 unlock_kernel();
139 return error;
140}
141#endif
142
143asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
144{
145 struct dentry * dentry;
146 int error;
147
148 lock_kernel();
149 dentry = namei(filename);
150
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);
156
157 dput(dentry);
158 }
159 unlock_kernel();
160 return error;
161}
162
163#if !defined(__alpha__) && !defined(__sparc__)
164
165
166
167
168
169asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
170{
171 struct dentry * dentry;
172 int error;
173
174 lock_kernel();
175 dentry = lnamei(filename);
176
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);
182
183 dput(dentry);
184 }
185 unlock_kernel();
186 return error;
187}
188
189#endif
190
191asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
192{
193 struct dentry * dentry;
194 int error;
195
196 lock_kernel();
197 dentry = lnamei(filename);
198
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);
204
205 dput(dentry);
206 }
207 unlock_kernel();
208 return error;
209}
210
211#if !defined(__alpha__) && !defined(__sparc__)
212
213
214
215
216
217asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
218{
219 struct file * f;
220 int err = -EBADF;
221
222 lock_kernel();
223 f = fget(fd);
224 if (f) {
225 struct dentry * dentry = f->f_dentry;
226
227 err = do_revalidate(dentry);
228 if (!err)
229 err = cp_old_stat(dentry->d_inode, statbuf);
230 fput(f);
231 }
232 unlock_kernel();
233 return err;
234}
235
236#endif
237
238asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf)
239{
240 struct file * f;
241 int err = -EBADF;
242
243 lock_kernel();
244 f = fget(fd);
245 if (f) {
246 struct dentry * dentry = f->f_dentry;
247
248 err = do_revalidate(dentry);
249 if (!err)
250 err = cp_new_stat(dentry->d_inode, statbuf);
251 fput(f);
252 }
253 unlock_kernel();
254 return err;
255}
256
257asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
258{
259 struct dentry * dentry;
260 int error;
261
262 if (bufsiz <= 0)
263 return -EINVAL;
264
265 lock_kernel();
266 dentry = lnamei(path);
267
268 error = PTR_ERR(dentry);
269 if (!IS_ERR(dentry)) {
270 struct inode * inode = dentry->d_inode;
271
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);
277 }
278 dput(dentry);
279 }
280 unlock_kernel();
281 return error;
282}
283