1
2
3
4
5
6
7#include <linux/slab.h>
8#include <linux/stat.h>
9#include <linux/fcntl.h>
10#include <linux/file.h>
11#include <linux/uio.h>
12#include <linux/smp_lock.h>
13#include <linux/dnotify.h>
14#include <linux/security.h>
15
16#include <asm/uaccess.h>
17
18struct file_operations generic_ro_fops = {
19 .llseek = generic_file_llseek,
20 .read = generic_file_read,
21 .mmap = generic_file_mmap,
22 .sendfile = generic_file_sendfile,
23};
24
25loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
26{
27 long long retval;
28 struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
29
30 down(&inode->i_sem);
31 switch (origin) {
32 case 2:
33 offset += inode->i_size;
34 break;
35 case 1:
36 offset += file->f_pos;
37 }
38 retval = -EINVAL;
39 if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
40 if (offset != file->f_pos) {
41 file->f_pos = offset;
42 file->f_version = ++event;
43 }
44 retval = offset;
45 }
46 up(&inode->i_sem);
47 return retval;
48}
49
50loff_t remote_llseek(struct file *file, loff_t offset, int origin)
51{
52 long long retval;
53
54 lock_kernel();
55 switch (origin) {
56 case 2:
57 offset += file->f_dentry->d_inode->i_size;
58 break;
59 case 1:
60 offset += file->f_pos;
61 }
62 retval = -EINVAL;
63 if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
64 if (offset != file->f_pos) {
65 file->f_pos = offset;
66 file->f_version = ++event;
67 }
68 retval = offset;
69 }
70 unlock_kernel();
71 return retval;
72}
73
74loff_t no_llseek(struct file *file, loff_t offset, int origin)
75{
76 return -ESPIPE;
77}
78
79loff_t default_llseek(struct file *file, loff_t offset, int origin)
80{
81 long long retval;
82
83 lock_kernel();
84 switch (origin) {
85 case 2:
86 offset += file->f_dentry->d_inode->i_size;
87 break;
88 case 1:
89 offset += file->f_pos;
90 }
91 retval = -EINVAL;
92 if (offset >= 0) {
93 if (offset != file->f_pos) {
94 file->f_pos = offset;
95 file->f_version = ++event;
96 }
97 retval = offset;
98 }
99 unlock_kernel();
100 return retval;
101}
102
103static inline loff_t llseek(struct file *file, loff_t offset, int origin)
104{
105 loff_t (*fn)(struct file *, loff_t, int);
106
107 fn = default_llseek;
108 if (file->f_op && file->f_op->llseek)
109 fn = file->f_op->llseek;
110 return fn(file, offset, origin);
111}
112
113asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
114{
115 off_t retval;
116 struct file * file;
117
118 retval = -EBADF;
119 file = fget(fd);
120 if (!file)
121 goto bad;
122
123 retval = security_ops->file_llseek(file);
124 if (retval) {
125 fput(file);
126 goto bad;
127 }
128
129 retval = -EINVAL;
130 if (origin <= 2) {
131 loff_t res = llseek(file, offset, origin);
132 retval = res;
133 if (res != (loff_t)retval)
134 retval = -EOVERFLOW;
135 }
136 fput(file);
137bad:
138 return retval;
139}
140
141#if !defined(__alpha__)
142asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
143 unsigned long offset_low, loff_t * result,
144 unsigned int origin)
145{
146 int retval;
147 struct file * file;
148 loff_t offset;
149
150 retval = -EBADF;
151 file = fget(fd);
152 if (!file)
153 goto bad;
154
155 retval = security_ops->file_llseek(file);
156 if (retval)
157 goto out_putf;
158
159 retval = -EINVAL;
160 if (origin > 2)
161 goto out_putf;
162
163 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
164 origin);
165
166 retval = (int)offset;
167 if (offset >= 0) {
168 retval = -EFAULT;
169 if (!copy_to_user(result, &offset, sizeof(offset)))
170 retval = 0;
171 }
172out_putf:
173 fput(file);
174bad:
175 return retval;
176}
177#endif
178
179ssize_t vfs_read(struct file *file, char *buf, size_t count, loff_t *pos)
180{
181 struct inode *inode = file->f_dentry->d_inode;
182 ssize_t ret;
183
184 if (!(file->f_mode & FMODE_READ))
185 return -EBADF;
186 if (!file->f_op || !file->f_op->read)
187 return -EINVAL;
188
189 ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
190 if (!ret) {
191 ret = security_ops->file_permission (file, MAY_READ);
192 if (!ret) {
193 ret = file->f_op->read(file, buf, count, pos);
194 if (ret > 0)
195 dnotify_parent(file->f_dentry, DN_ACCESS);
196 }
197 }
198
199 return ret;
200}
201
202ssize_t vfs_write(struct file *file, const char *buf, size_t count, loff_t *pos)
203{
204 struct inode *inode = file->f_dentry->d_inode;
205 ssize_t ret;
206
207 if (!(file->f_mode & FMODE_WRITE))
208 return -EBADF;
209 if (!file->f_op || !file->f_op->write)
210 return -EINVAL;
211
212 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
213 if (!ret) {
214 ret = security_ops->file_permission (file, MAY_WRITE);
215 if (!ret) {
216 ret = file->f_op->write(file, buf, count, pos);
217 if (ret > 0)
218 dnotify_parent(file->f_dentry, DN_MODIFY);
219 }
220 }
221
222 return ret;
223}
224
225asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
226{
227 struct file *file;
228 ssize_t ret = -EBADF;
229
230 file = fget(fd);
231 if (file) {
232 ret = vfs_read(file, buf, count, &file->f_pos);
233 fput(file);
234 }
235
236 return ret;
237}
238
239asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
240{
241 struct file *file;
242 ssize_t ret = -EBADF;
243
244 file = fget(fd);
245 if (file) {
246 ret = vfs_write(file, buf, count, &file->f_pos);
247 fput(file);
248 }
249
250 return ret;
251}
252
253asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf,
254 size_t count, loff_t pos)
255{
256 struct file *file;
257 ssize_t ret = -EBADF;
258
259 if (pos < 0)
260 return -EINVAL;
261
262 file = fget(fd);
263 if (file) {
264 ret = vfs_read(file, buf, count, &pos);
265 fput(file);
266 }
267
268 return ret;
269}
270
271asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf,
272 size_t count, loff_t pos)
273{
274 struct file *file;
275 ssize_t ret = -EBADF;
276
277 if (pos < 0)
278 return -EINVAL;
279
280 file = fget(fd);
281 if (file) {
282 ret = vfs_write(file, buf, count, &pos);
283 fput(file);
284 }
285
286 return ret;
287}
288
289
290
291
292unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
293{
294 unsigned long seg = 0;
295 size_t len = 0;
296
297 while (seg < nr_segs) {
298 seg++;
299 if (len + iov->iov_len >= to) {
300 iov->iov_len = to - len;
301 break;
302 }
303 len += iov->iov_len;
304 iov++;
305 }
306 return seg;
307}
308
309static ssize_t do_readv_writev(int type, struct file *file,
310 const struct iovec * vector,
311 unsigned long nr_segs)
312{
313 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
314 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
315
316 size_t tot_len;
317 struct iovec iovstack[UIO_FASTIOV];
318 struct iovec *iov=iovstack;
319 ssize_t ret = -EINVAL;
320 int seg;
321 io_fn_t fn;
322 iov_fn_t fnv;
323 struct inode *inode;
324
325
326
327
328
329
330 if (nr_segs == 0)
331 goto out;
332
333
334
335
336
337 if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
338 goto out;
339 if (!file->f_op)
340 goto out;
341 if (nr_segs > UIO_FASTIOV) {
342 ret = -ENOMEM;
343 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
344 if (!iov)
345 goto out;
346 }
347 ret = -EFAULT;
348 if (copy_from_user(iov, vector, nr_segs*sizeof(*vector)))
349 goto out;
350
351
352
353
354
355
356
357
358 tot_len = 0;
359 ret = -EINVAL;
360 for (seg = 0 ; seg < nr_segs; seg++) {
361 ssize_t tmp = tot_len;
362 ssize_t len = (ssize_t)iov[seg].iov_len;
363 if (len < 0)
364 goto out;
365 tot_len += len;
366 if (tot_len < tmp)
367 goto out;
368 }
369 if (tot_len == 0) {
370 ret = 0;
371 goto out;
372 }
373
374 inode = file->f_dentry->d_inode;
375
376 ret = locks_verify_area((type == READ
377 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
378 inode, file, file->f_pos, tot_len);
379 if (ret)
380 goto out;
381
382 fnv = NULL;
383 if (type == READ) {
384 fn = file->f_op->read;
385 fnv = file->f_op->readv;
386 } else {
387 fn = (io_fn_t)file->f_op->write;
388 fnv = file->f_op->writev;
389 }
390 if (fnv) {
391 ret = fnv(file, iov, nr_segs, &file->f_pos);
392 goto out;
393 }
394
395
396 ret = 0;
397 vector = iov;
398 while (nr_segs > 0) {
399 void * base;
400 size_t len;
401 ssize_t nr;
402
403 base = vector->iov_base;
404 len = vector->iov_len;
405 vector++;
406 nr_segs--;
407
408 nr = fn(file, base, len, &file->f_pos);
409
410 if (nr < 0) {
411 if (!ret) ret = nr;
412 break;
413 }
414 ret += nr;
415 if (nr != len)
416 break;
417 }
418out:
419 if (iov != iovstack)
420 kfree(iov);
421 if ((ret + (type == READ)) > 0)
422 dnotify_parent(file->f_dentry,
423 (type == READ) ? DN_MODIFY : DN_ACCESS);
424 return ret;
425}
426
427
428asmlinkage ssize_t
429sys_readv(unsigned long fd, const struct iovec *vector, unsigned long nr_segs)
430{
431 struct file * file;
432 ssize_t ret;
433
434
435 ret = -EBADF;
436 file = fget(fd);
437 if (!file)
438 goto bad_file;
439 if (file->f_op && (file->f_mode & FMODE_READ) &&
440 (file->f_op->readv || file->f_op->read)) {
441 ret = security_ops->file_permission (file, MAY_READ);
442 if (!ret)
443 ret = do_readv_writev(READ, file, vector, nr_segs);
444 }
445 fput(file);
446
447bad_file:
448 return ret;
449}
450
451asmlinkage ssize_t
452sys_writev(unsigned long fd, const struct iovec * vector, unsigned long nr_segs)
453{
454 struct file * file;
455 ssize_t ret;
456
457
458 ret = -EBADF;
459 file = fget(fd);
460 if (!file)
461 goto bad_file;
462 if (file->f_op && (file->f_mode & FMODE_WRITE) &&
463 (file->f_op->writev || file->f_op->write)) {
464 ret = security_ops->file_permission (file, MAY_WRITE);
465 if (!ret)
466 ret = do_readv_writev(WRITE, file, vector, nr_segs);
467 }
468 fput(file);
469
470bad_file:
471 return ret;
472}
473
474static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
475 size_t count, loff_t max)
476{
477 struct file * in_file, * out_file;
478 struct inode * in_inode, * out_inode;
479 loff_t pos;
480 ssize_t retval;
481
482
483
484
485 retval = -EBADF;
486 in_file = fget(in_fd);
487 if (!in_file)
488 goto out;
489 if (!(in_file->f_mode & FMODE_READ))
490 goto fput_in;
491 retval = -EINVAL;
492 in_inode = in_file->f_dentry->d_inode;
493 if (!in_inode)
494 goto fput_in;
495 if (!in_file->f_op || !in_file->f_op->sendfile)
496 goto fput_in;
497 retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count);
498 if (retval)
499 goto fput_in;
500
501
502
503
504 retval = -EBADF;
505 out_file = fget(out_fd);
506 if (!out_file)
507 goto fput_in;
508 if (!(out_file->f_mode & FMODE_WRITE))
509 goto fput_out;
510 retval = -EINVAL;
511 if (!out_file->f_op || !out_file->f_op->sendpage)
512 goto fput_out;
513 out_inode = out_file->f_dentry->d_inode;
514 retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
515 if (retval)
516 goto fput_out;
517
518 if (!ppos)
519 ppos = &in_file->f_pos;
520
521 if (!max)
522 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
523
524 pos = *ppos;
525 retval = -EINVAL;
526 if (unlikely(pos < 0))
527 goto fput_out;
528 if (unlikely(pos + count > max)) {
529 retval = -EOVERFLOW;
530 if (pos >= max)
531 goto fput_out;
532 count = max - pos;
533 }
534
535 retval = in_file->f_op->sendfile(out_file, in_file, ppos, count);
536
537 if (*ppos > max)
538 retval = -EOVERFLOW;
539
540fput_out:
541 fput(out_file);
542fput_in:
543 fput(in_file);
544out:
545 return retval;
546}
547
548asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
549{
550 loff_t pos;
551 off_t off;
552 ssize_t ret;
553
554 if (offset) {
555 if (unlikely(get_user(off, offset)))
556 return -EFAULT;
557 pos = off;
558 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
559 if (unlikely(put_user(pos, offset)))
560 return -EFAULT;
561 return ret;
562 }
563
564 return do_sendfile(out_fd, in_fd, NULL, count, MAX_NON_LFS);
565}
566
567asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count)
568{
569 loff_t pos;
570 ssize_t ret;
571
572 if (offset) {
573 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
574 return -EFAULT;
575 ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
576 if (unlikely(put_user(pos, offset)))
577 return -EFAULT;
578 return ret;
579 }
580
581 return do_sendfile(out_fd, in_fd, NULL, count, 0);
582}
583