upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / fs / read_write.c
1 /*
2  *  linux/fs/read_write.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
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 #include <linux/module.h>
16 #include <linux/syscalls.h>
17
18 #include <asm/uaccess.h>
19 #include <asm/unistd.h>
20
21 struct file_operations generic_ro_fops = {
22         .llseek         = generic_file_llseek,
23         .read           = generic_file_read,
24         .mmap           = generic_file_readonly_mmap,
25         .sendfile       = generic_file_sendfile,
26 };
27
28 EXPORT_SYMBOL(generic_ro_fops);
29
30 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
31 {
32         long long retval;
33         struct inode *inode = file->f_mapping->host;
34
35         down(&inode->i_sem);
36         switch (origin) {
37                 case 2:
38                         offset += inode->i_size;
39                         break;
40                 case 1:
41                         offset += file->f_pos;
42         }
43         retval = -EINVAL;
44         if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
45                 if (offset != file->f_pos) {
46                         file->f_pos = offset;
47                         file->f_version = 0;
48                 }
49                 retval = offset;
50         }
51         up(&inode->i_sem);
52         return retval;
53 }
54
55 EXPORT_SYMBOL(generic_file_llseek);
56
57 loff_t remote_llseek(struct file *file, loff_t offset, int origin)
58 {
59         long long retval;
60
61         lock_kernel();
62         switch (origin) {
63                 case 2:
64                         offset += i_size_read(file->f_dentry->d_inode);
65                         break;
66                 case 1:
67                         offset += file->f_pos;
68         }
69         retval = -EINVAL;
70         if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
71                 if (offset != file->f_pos) {
72                         file->f_pos = offset;
73                         file->f_version = 0;
74                 }
75                 retval = offset;
76         }
77         unlock_kernel();
78         return retval;
79 }
80 EXPORT_SYMBOL(remote_llseek);
81
82 loff_t no_llseek(struct file *file, loff_t offset, int origin)
83 {
84         return -ESPIPE;
85 }
86 EXPORT_SYMBOL(no_llseek);
87
88 loff_t default_llseek(struct file *file, loff_t offset, int origin)
89 {
90         long long retval;
91
92         lock_kernel();
93         switch (origin) {
94                 case 2:
95                         offset += i_size_read(file->f_dentry->d_inode);
96                         break;
97                 case 1:
98                         offset += file->f_pos;
99         }
100         retval = -EINVAL;
101         if (offset >= 0) {
102                 if (offset != file->f_pos) {
103                         file->f_pos = offset;
104                         file->f_version = 0;
105                 }
106                 retval = offset;
107         }
108         unlock_kernel();
109         return retval;
110 }
111 EXPORT_SYMBOL(default_llseek);
112
113 loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
114 {
115         loff_t (*fn)(struct file *, loff_t, int);
116
117         fn = no_llseek;
118         if (file->f_mode & FMODE_LSEEK) {
119                 fn = default_llseek;
120                 if (file->f_op && file->f_op->llseek)
121                         fn = file->f_op->llseek;
122         }
123         return fn(file, offset, origin);
124 }
125 EXPORT_SYMBOL(vfs_llseek);
126
127 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
128 {
129         off_t retval;
130         struct file * file;
131         int fput_needed;
132
133         retval = -EBADF;
134         file = fget_light(fd, &fput_needed);
135         if (!file)
136                 goto bad;
137
138         retval = -EINVAL;
139         if (origin <= 2) {
140                 loff_t res = vfs_llseek(file, offset, origin);
141                 retval = res;
142                 if (res != (loff_t)retval)
143                         retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
144         }
145         fput_light(file, fput_needed);
146 bad:
147         return retval;
148 }
149
150 #ifdef __ARCH_WANT_SYS_LLSEEK
151 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
152                            unsigned long offset_low, loff_t __user * result,
153                            unsigned int origin)
154 {
155         int retval;
156         struct file * file;
157         loff_t offset;
158         int fput_needed;
159
160         retval = -EBADF;
161         file = fget_light(fd, &fput_needed);
162         if (!file)
163                 goto bad;
164
165         retval = -EINVAL;
166         if (origin > 2)
167                 goto out_putf;
168
169         offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
170                         origin);
171
172         retval = (int)offset;
173         if (offset >= 0) {
174                 retval = -EFAULT;
175                 if (!copy_to_user(result, &offset, sizeof(offset)))
176                         retval = 0;
177         }
178 out_putf:
179         fput_light(file, fput_needed);
180 bad:
181         return retval;
182 }
183 #endif
184
185 ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
186 {
187         struct kiocb kiocb;
188         ssize_t ret;
189
190         init_sync_kiocb(&kiocb, filp);
191         kiocb.ki_pos = *ppos;
192         ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos);
193         if (-EIOCBQUEUED == ret)
194                 ret = wait_on_sync_kiocb(&kiocb);
195         *ppos = kiocb.ki_pos;
196         return ret;
197 }
198
199 EXPORT_SYMBOL(do_sync_read);
200
201 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
202 {
203         struct inode *inode = file->f_dentry->d_inode;
204         ssize_t ret;
205
206         if (!(file->f_mode & FMODE_READ))
207                 return -EBADF;
208         if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
209                 return -EINVAL;
210
211         ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
212         if (!ret) {
213                 ret = security_file_permission (file, MAY_READ);
214                 if (!ret) {
215                         if (file->f_op->read)
216                                 ret = file->f_op->read(file, buf, count, pos);
217                         else
218                                 ret = do_sync_read(file, buf, count, pos);
219                         if (ret > 0)
220                                 dnotify_parent(file->f_dentry, DN_ACCESS);
221                 }
222         }
223
224         return ret;
225 }
226
227 EXPORT_SYMBOL(vfs_read);
228
229 ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
230 {
231         struct kiocb kiocb;
232         ssize_t ret;
233
234         init_sync_kiocb(&kiocb, filp);
235         kiocb.ki_pos = *ppos;
236         ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos);
237         if (-EIOCBQUEUED == ret)
238                 ret = wait_on_sync_kiocb(&kiocb);
239         *ppos = kiocb.ki_pos;
240         return ret;
241 }
242
243 EXPORT_SYMBOL(do_sync_write);
244
245 ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
246 {
247         struct inode *inode = file->f_dentry->d_inode;
248         ssize_t ret;
249
250         if (!(file->f_mode & FMODE_WRITE))
251                 return -EBADF;
252         if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
253                 return -EINVAL;
254
255         ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
256         if (!ret) {
257                 ret = security_file_permission (file, MAY_WRITE);
258                 if (!ret) {
259                         if (file->f_op->write)
260                                 ret = file->f_op->write(file, buf, count, pos);
261                         else
262                                 ret = do_sync_write(file, buf, count, pos);
263                         if (ret > 0)
264                                 dnotify_parent(file->f_dentry, DN_MODIFY);
265                 }
266         }
267
268         return ret;
269 }
270
271 EXPORT_SYMBOL(vfs_write);
272
273 static inline loff_t file_pos_read(struct file *file)
274 {
275         return file->f_pos;
276 }
277
278 static inline void file_pos_write(struct file *file, loff_t pos)
279 {
280         file->f_pos = pos;
281 }
282
283 asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
284 {
285         struct file *file;
286         ssize_t ret = -EBADF;
287         int fput_needed;
288
289         file = fget_light(fd, &fput_needed);
290         if (file) {
291                 loff_t pos = file_pos_read(file);
292                 ret = vfs_read(file, buf, count, &pos);
293                 file_pos_write(file, pos);
294                 fput_light(file, fput_needed);
295         }
296
297         return ret;
298 }
299 EXPORT_SYMBOL_GPL(sys_read);
300
301 asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
302 {
303         struct file *file;
304         ssize_t ret = -EBADF;
305         int fput_needed;
306
307         file = fget_light(fd, &fput_needed);
308         if (file) {
309                 loff_t pos = file_pos_read(file);
310                 ret = vfs_write(file, buf, count, &pos);
311                 file_pos_write(file, pos);
312                 fput_light(file, fput_needed);
313         }
314
315         return ret;
316 }
317
318 EXPORT_SYMBOL_GPL(sys_write);
319
320 asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
321                              size_t count, loff_t pos)
322 {
323         struct file *file;
324         ssize_t ret = -EBADF;
325         int fput_needed;
326
327         if (pos < 0)
328                 return -EINVAL;
329
330         file = fget_light(fd, &fput_needed);
331         if (file) {
332                 ret = -ESPIPE;
333                 if (file->f_mode & FMODE_PREAD)
334                         ret = vfs_read(file, buf, count, &pos);
335                 fput_light(file, fput_needed);
336         }
337
338         return ret;
339 }
340
341 asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
342                               size_t count, loff_t pos)
343 {
344         struct file *file;
345         ssize_t ret = -EBADF;
346         int fput_needed;
347
348         if (pos < 0)
349                 return -EINVAL;
350
351         file = fget_light(fd, &fput_needed);
352         if (file) {
353                 ret = -ESPIPE;
354                 if (file->f_mode & FMODE_PWRITE)  
355                         ret = vfs_write(file, buf, count, &pos);
356                 fput_light(file, fput_needed);
357         }
358
359         return ret;
360 }
361
362 /*
363  * Reduce an iovec's length in-place.  Return the resulting number of segments
364  */
365 unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
366 {
367         unsigned long seg = 0;
368         size_t len = 0;
369
370         while (seg < nr_segs) {
371                 seg++;
372                 if (len + iov->iov_len >= to) {
373                         iov->iov_len = to - len;
374                         break;
375                 }
376                 len += iov->iov_len;
377                 iov++;
378         }
379         return seg;
380 }
381
382 EXPORT_SYMBOL(iov_shorten);
383
384 static ssize_t do_readv_writev(int type, struct file *file,
385                                const struct iovec __user * uvector,
386                                unsigned long nr_segs, loff_t *pos)
387 {
388         typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
389         typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
390
391         size_t tot_len;
392         struct iovec iovstack[UIO_FASTIOV];
393         struct iovec *iov=iovstack, *vector;
394         ssize_t ret;
395         int seg;
396         io_fn_t fn;
397         iov_fn_t fnv;
398         struct inode *inode;
399
400         /*
401          * SuS says "The readv() function *may* fail if the iovcnt argument
402          * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
403          * traditionally returned zero for zero segments, so...
404          */
405         ret = 0;
406         if (nr_segs == 0)
407                 goto out;
408
409         /*
410          * First get the "struct iovec" from user memory and
411          * verify all the pointers
412          */
413         ret = -EINVAL;
414         if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
415                 goto out;
416         if (!file->f_op)
417                 goto out;
418         if (nr_segs > UIO_FASTIOV) {
419                 ret = -ENOMEM;
420                 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
421                 if (!iov)
422                         goto out;
423         }
424         ret = -EFAULT;
425         if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector)))
426                 goto out;
427
428         /*
429          * Single unix specification:
430          * We should -EINVAL if an element length is not >= 0 and fitting an
431          * ssize_t.  The total length is fitting an ssize_t
432          *
433          * Be careful here because iov_len is a size_t not an ssize_t
434          */
435         tot_len = 0;
436         ret = -EINVAL;
437         for (seg = 0; seg < nr_segs; seg++) {
438                 ssize_t len = (ssize_t)iov[seg].iov_len;
439
440                 if (len < 0)    /* size_t not fitting an ssize_t .. */
441                         goto out;
442                 tot_len += len;
443                 if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
444                         goto out;
445         }
446         if (tot_len == 0) {
447                 ret = 0;
448                 goto out;
449         }
450
451         inode = file->f_dentry->d_inode;
452         /* VERIFY_WRITE actually means a read, as we write to user space */
453         ret = locks_verify_area((type == READ 
454                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
455                                 inode, file, *pos, tot_len);
456         if (ret)
457                 goto out;
458
459         fnv = NULL;
460         if (type == READ) {
461                 fn = file->f_op->read;
462                 fnv = file->f_op->readv;
463         } else {
464                 fn = (io_fn_t)file->f_op->write;
465                 fnv = file->f_op->writev;
466         }
467         if (fnv) {
468                 ret = fnv(file, iov, nr_segs, pos);
469                 goto out;
470         }
471
472         /* Do it by hand, with file-ops */
473         ret = 0;
474         vector = iov;
475         while (nr_segs > 0) {
476                 void __user * base;
477                 size_t len;
478                 ssize_t nr;
479
480                 base = vector->iov_base;
481                 len = vector->iov_len;
482                 vector++;
483                 nr_segs--;
484
485                 nr = fn(file, base, len, pos);
486
487                 if (nr < 0) {
488                         if (!ret) ret = nr;
489                         break;
490                 }
491                 ret += nr;
492                 if (nr != len)
493                         break;
494         }
495 out:
496         if (iov != iovstack)
497                 kfree(iov);
498         if ((ret + (type == READ)) > 0)
499                 dnotify_parent(file->f_dentry,
500                                 (type == READ) ? DN_ACCESS : DN_MODIFY);
501         return ret;
502 }
503
504 ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
505                   unsigned long vlen, loff_t *pos)
506 {
507         if (!(file->f_mode & FMODE_READ))
508                 return -EBADF;
509         if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
510                 return -EINVAL;
511
512         return do_readv_writev(READ, file, vec, vlen, pos);
513 }
514
515 EXPORT_SYMBOL(vfs_readv);
516
517 ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
518                    unsigned long vlen, loff_t *pos)
519 {
520         if (!(file->f_mode & FMODE_WRITE))
521                 return -EBADF;
522         if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
523                 return -EINVAL;
524
525         return do_readv_writev(WRITE, file, vec, vlen, pos);
526 }
527
528 EXPORT_SYMBOL(vfs_writev);
529
530 asmlinkage ssize_t
531 sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
532 {
533         struct file *file;
534         ssize_t ret = -EBADF;
535         int fput_needed;
536
537         file = fget_light(fd, &fput_needed);
538         if (file) {
539                 loff_t pos = file_pos_read(file);
540                 ret = vfs_readv(file, vec, vlen, &pos);
541                 file_pos_write(file, pos);
542                 fput_light(file, fput_needed);
543         }
544
545         return ret;
546 }
547
548 asmlinkage ssize_t
549 sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
550 {
551         struct file *file;
552         ssize_t ret = -EBADF;
553         int fput_needed;
554
555         file = fget_light(fd, &fput_needed);
556         if (file) {
557                 loff_t pos = file_pos_read(file);
558                 ret = vfs_writev(file, vec, vlen, &pos);
559                 file_pos_write(file, pos);
560                 fput_light(file, fput_needed);
561         }
562
563         return ret;
564 }
565
566 static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
567                            size_t count, loff_t max)
568 {
569         struct file * in_file, * out_file;
570         struct inode * in_inode, * out_inode;
571         loff_t pos;
572         ssize_t retval;
573         int fput_needed_in, fput_needed_out;
574
575         /*
576          * Get input file, and verify that it is ok..
577          */
578         retval = -EBADF;
579         in_file = fget_light(in_fd, &fput_needed_in);
580         if (!in_file)
581                 goto out;
582         if (!(in_file->f_mode & FMODE_READ))
583                 goto fput_in;
584         retval = -EINVAL;
585         in_inode = in_file->f_dentry->d_inode;
586         if (!in_inode)
587                 goto fput_in;
588         if (!in_file->f_op || !in_file->f_op->sendfile)
589                 goto fput_in;
590         retval = -ESPIPE;
591         if (!ppos)
592                 ppos = &in_file->f_pos;
593         else
594                 if (!(in_file->f_mode & FMODE_PREAD))
595                         goto fput_in;
596         retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, *ppos, count);
597         if (retval)
598                 goto fput_in;
599
600         retval = security_file_permission (in_file, MAY_READ);
601         if (retval)
602                 goto fput_in;
603
604         /*
605          * Get output file, and verify that it is ok..
606          */
607         retval = -EBADF;
608         out_file = fget_light(out_fd, &fput_needed_out);
609         if (!out_file)
610                 goto fput_in;
611         if (!(out_file->f_mode & FMODE_WRITE))
612                 goto fput_out;
613         retval = -EINVAL;
614         if (!out_file->f_op || !out_file->f_op->sendpage)
615                 goto fput_out;
616         out_inode = out_file->f_dentry->d_inode;
617         retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
618         if (retval)
619                 goto fput_out;
620
621         retval = security_file_permission (out_file, MAY_WRITE);
622         if (retval)
623                 goto fput_out;
624
625         if (!max)
626                 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
627
628         pos = *ppos;
629         retval = -EINVAL;
630         if (unlikely(pos < 0))
631                 goto fput_out;
632         if (unlikely(pos + count > max)) {
633                 retval = -EOVERFLOW;
634                 if (pos >= max)
635                         goto fput_out;
636                 count = max - pos;
637         }
638
639         retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
640
641         if (*ppos > max)
642                 retval = -EOVERFLOW;
643
644 fput_out:
645         fput_light(out_file, fput_needed_out);
646 fput_in:
647         fput_light(in_file, fput_needed_in);
648 out:
649         return retval;
650 }
651
652 asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)
653 {
654         loff_t pos;
655         off_t off;
656         ssize_t ret;
657
658         if (offset) {
659                 if (unlikely(get_user(off, offset)))
660                         return -EFAULT;
661                 pos = off;
662                 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
663                 if (unlikely(put_user(pos, offset)))
664                         return -EFAULT;
665                 return ret;
666         }
667
668         return do_sendfile(out_fd, in_fd, NULL, count, 0);
669 }
670
671 asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count)
672 {
673         loff_t pos;
674         ssize_t ret;
675
676         if (offset) {
677                 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
678                         return -EFAULT;
679                 ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
680                 if (unlikely(put_user(pos, offset)))
681                         return -EFAULT;
682                 return ret;
683         }
684
685         return do_sendfile(out_fd, in_fd, NULL, count, 0);
686 }