1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/slab.h>
23#include <linux/stat.h>
24#include <linux/fcntl.h>
25#include <linux/file.h>
26#include <linux/uio.h>
27#include <linux/smp_lock.h>
28#include <linux/dnotify.h>
29
30#include <asm/uaccess.h>
31
32struct file_operations generic_ro_fops = {
33 llseek: generic_file_llseek,
34 read: generic_file_read,
35 mmap: generic_file_mmap,
36};
37
38ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
39{
40 return -EISDIR;
41}
42
43loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
44{
45 long long retval;
46
47 switch (origin) {
48 case 2:
49 offset += file->f_dentry->d_inode->i_size;
50 break;
51 case 1:
52 offset += file->f_pos;
53 }
54 retval = -EINVAL;
55 if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
56 if (offset != file->f_pos) {
57 file->f_pos = offset;
58 file->f_reada = 0;
59 file->f_version = ++event;
60 }
61 retval = offset;
62 }
63 return retval;
64}
65
66loff_t no_llseek(struct file *file, loff_t offset, int origin)
67{
68 return -ESPIPE;
69}
70
71loff_t default_llseek(struct file *file, loff_t offset, int origin)
72{
73 long long retval;
74
75 switch (origin) {
76 case 2:
77 offset += file->f_dentry->d_inode->i_size;
78 break;
79 case 1:
80 offset += file->f_pos;
81 }
82 retval = -EINVAL;
83 if (offset >= 0) {
84 if (offset != file->f_pos) {
85 file->f_pos = offset;
86 file->f_reada = 0;
87 file->f_version = ++event;
88 }
89 retval = offset;
90 }
91 return retval;
92}
93
94static inline loff_t llseek(struct file *file, loff_t offset, int origin)
95{
96 loff_t (*fn)(struct file *, loff_t, int);
97 loff_t retval;
98
99 fn = default_llseek;
100 if (file->f_op && file->f_op->llseek)
101 fn = file->f_op->llseek;
102 lock_kernel();
103 retval = fn(file, offset, origin);
104 unlock_kernel();
105 return retval;
106}
107
108asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
109{
110 off_t retval;
111 struct file * file;
112
113 retval = -EBADF;
114 file = fget(fd);
115 if (!file)
116 goto bad;
117 retval = -EINVAL;
118 if (origin <= 2) {
119 loff_t res = llseek(file, offset, origin);
120 retval = res;
121 if (res != (loff_t)retval)
122 retval = -EOVERFLOW;
123 }
124 fput(file);
125bad:
126 return retval;
127}
128
129#if !defined(__alpha__)
130asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
131 unsigned long offset_low, loff_t * result,
132 unsigned int origin)
133{
134 int retval;
135 struct file * file;
136 loff_t offset;
137
138 retval = -EBADF;
139 file = fget(fd);
140 if (!file)
141 goto bad;
142 retval = -EINVAL;
143 if (origin > 2)
144 goto out_putf;
145
146 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
147 origin);
148
149 retval = (int)offset;
150 if (offset >= 0) {
151 retval = -EFAULT;
152 if (!copy_to_user(result, &offset, sizeof(offset)))
153 retval = 0;
154 }
155out_putf:
156 fput(file);
157bad:
158 return retval;
159}
160#endif
161
162asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
163{
164 ssize_t ret;
165 struct file * file;
166
167 ret = -EBADF;
168 file = fget(fd);
169 if (file) {
170 if (file->f_mode & FMODE_READ) {
171 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
172 file, file->f_pos, count);
173 if (!ret) {
174 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
175 ret = -EINVAL;
176 if (file->f_op && (read = file->f_op->read) != NULL)
177 ret = read(file, buf, count, &file->f_pos);
178 }
179 }
180 if (ret > 0)
181 dnotify_parent(file->f_dentry, DN_ACCESS);
182 fput(file);
183 }
184 return ret;
185}
186
187asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
188{
189 ssize_t ret;
190 struct file * file;
191
192 ret = -EBADF;
193 file = fget(fd);
194 if (file) {
195 if (file->f_mode & FMODE_WRITE) {
196 struct inode *inode = file->f_dentry->d_inode;
197 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
198 file->f_pos, count);
199 if (!ret) {
200 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
201 ret = -EINVAL;
202 if (file->f_op && (write = file->f_op->write) != NULL)
203 ret = write(file, buf, count, &file->f_pos);
204 }
205 }
206 if (ret > 0)
207 dnotify_parent(file->f_dentry, DN_MODIFY);
208 fput(file);
209 }
210 return ret;
211}
212
213
214static ssize_t do_readv_writev(int type, struct file *file,
215 const struct iovec * vector,
216 unsigned long count)
217{
218 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
219 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
220
221 ssize_t tot_len;
222 struct iovec iovstack[UIO_FASTIOV];
223 struct iovec *iov=iovstack;
224 ssize_t ret, i;
225 io_fn_t fn;
226 iov_fn_t fnv;
227 struct inode *inode;
228
229
230
231
232
233 ret = 0;
234 if (!count)
235 goto out_nofree;
236 ret = -EINVAL;
237 if (count > UIO_MAXIOV)
238 goto out_nofree;
239 if (!file->f_op)
240 goto out_nofree;
241 if (count > UIO_FASTIOV) {
242 ret = -ENOMEM;
243 iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
244 if (!iov)
245 goto out_nofree;
246 }
247 ret = -EFAULT;
248 if (copy_from_user(iov, vector, count*sizeof(*vector)))
249 goto out;
250
251
252
253
254
255
256
257
258
259 tot_len = 0;
260 ret = -EINVAL;
261 for (i = 0 ; i < count ; i++) {
262 ssize_t tmp = tot_len;
263 ssize_t len = (ssize_t) iov[i].iov_len;
264 if (len < 0)
265 goto out;
266 tot_len += len;
267 if (tot_len < tmp)
268 goto out;
269 }
270
271 inode = file->f_dentry->d_inode;
272
273 ret = locks_verify_area((type == VERIFY_WRITE
274 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
275 inode, file, file->f_pos, tot_len);
276 if (ret) goto out;
277
278 fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
279 if (fnv) {
280 ret = fnv(file, iov, count, &file->f_pos);
281 goto out;
282 }
283
284
285 fn = (type == VERIFY_WRITE ? file->f_op->read :
286 (io_fn_t) file->f_op->write);
287
288 ret = 0;
289 vector = iov;
290 while (count > 0) {
291 void * base;
292 size_t len;
293 ssize_t nr;
294
295 base = vector->iov_base;
296 len = vector->iov_len;
297 vector++;
298 count--;
299
300 nr = fn(file, base, len, &file->f_pos);
301
302 if (nr < 0) {
303 if (!ret) ret = nr;
304 break;
305 }
306 ret += nr;
307 if (nr != len)
308 break;
309 }
310
311out:
312 if (iov != iovstack)
313 kfree(iov);
314out_nofree:
315
316 if ((ret + (type == VERIFY_WRITE)) > 0)
317 dnotify_parent(file->f_dentry,
318 (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
319 return ret;
320}
321
322asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
323 unsigned long count)
324{
325 struct file * file;
326 ssize_t ret;
327
328
329 ret = -EBADF;
330 file = fget(fd);
331 if (!file)
332 goto bad_file;
333 if (file->f_op && (file->f_mode & FMODE_READ) &&
334 (file->f_op->readv || file->f_op->read))
335 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
336 fput(file);
337
338bad_file:
339 return ret;
340}
341
342asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
343 unsigned long count)
344{
345 struct file * file;
346 ssize_t ret;
347
348
349 ret = -EBADF;
350 file = fget(fd);
351 if (!file)
352 goto bad_file;
353 if (file->f_op && (file->f_mode & FMODE_WRITE) &&
354 (file->f_op->writev || file->f_op->write))
355 ret = do_readv_writev(VERIFY_READ, file, vector, count);
356 fput(file);
357
358bad_file:
359 return ret;
360}
361
362
363
364
365
366asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
367 size_t count, loff_t pos)
368{
369 ssize_t ret;
370 struct file * file;
371 ssize_t (*read)(struct file *, char *, size_t, loff_t *);
372
373 ret = -EBADF;
374 file = fget(fd);
375 if (!file)
376 goto bad_file;
377 if (!(file->f_mode & FMODE_READ))
378 goto out;
379 ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
380 file, pos, count);
381 if (ret)
382 goto out;
383 ret = -EINVAL;
384 if (!file->f_op || !(read = file->f_op->read))
385 goto out;
386 if (pos < 0)
387 goto out;
388 ret = read(file, buf, count, &pos);
389 if (ret > 0)
390 dnotify_parent(file->f_dentry, DN_ACCESS);
391out:
392 fput(file);
393bad_file:
394 return ret;
395}
396
397asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
398 size_t count, loff_t pos)
399{
400 ssize_t ret;
401 struct file * file;
402 ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
403
404 ret = -EBADF;
405 file = fget(fd);
406 if (!file)
407 goto bad_file;
408 if (!(file->f_mode & FMODE_WRITE))
409 goto out;
410 ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
411 file, pos, count);
412 if (ret)
413 goto out;
414 ret = -EINVAL;
415 if (!file->f_op || !(write = file->f_op->write))
416 goto out;
417 if (pos < 0)
418 goto out;
419
420 ret = write(file, buf, count, &pos);
421 if (ret > 0)
422 dnotify_parent(file->f_dentry, DN_MODIFY);
423out:
424 fput(file);
425bad_file:
426 return ret;
427}
428