Pull one more egcs 1.1.2 workaround.
[linux-2.6/linux-mips.git] / fs / read_write.c
blob428f9f3a21a15a5000e2ee72e17a91d21c701459
1 /*
2 * linux/fs/read_write.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
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>
17 #include <asm/uaccess.h>
19 struct file_operations generic_ro_fops = {
20 .llseek = generic_file_llseek,
21 .read = generic_file_read,
22 .mmap = generic_file_mmap,
23 .sendfile = generic_file_sendfile,
26 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
28 long long retval;
29 struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
31 down(&inode->i_sem);
32 switch (origin) {
33 case 2:
34 offset += inode->i_size;
35 break;
36 case 1:
37 offset += file->f_pos;
39 retval = -EINVAL;
40 if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
41 if (offset != file->f_pos) {
42 file->f_pos = offset;
43 file->f_version = 0;
45 retval = offset;
47 up(&inode->i_sem);
48 return retval;
51 loff_t remote_llseek(struct file *file, loff_t offset, int origin)
53 long long retval;
55 lock_kernel();
56 switch (origin) {
57 case 2:
58 offset += file->f_dentry->d_inode->i_size;
59 break;
60 case 1:
61 offset += file->f_pos;
63 retval = -EINVAL;
64 if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
65 if (offset != file->f_pos) {
66 file->f_pos = offset;
67 file->f_version = 0;
69 retval = offset;
71 unlock_kernel();
72 return retval;
75 loff_t no_llseek(struct file *file, loff_t offset, int origin)
77 return -ESPIPE;
80 loff_t default_llseek(struct file *file, loff_t offset, int origin)
82 long long retval;
84 lock_kernel();
85 switch (origin) {
86 case 2:
87 offset += file->f_dentry->d_inode->i_size;
88 break;
89 case 1:
90 offset += file->f_pos;
92 retval = -EINVAL;
93 if (offset >= 0) {
94 if (offset != file->f_pos) {
95 file->f_pos = offset;
96 file->f_version = 0;
98 retval = offset;
100 unlock_kernel();
101 return retval;
104 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
106 loff_t (*fn)(struct file *, loff_t, int);
108 fn = default_llseek;
109 if (file->f_op && file->f_op->llseek)
110 fn = file->f_op->llseek;
111 return fn(file, offset, origin);
114 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
116 off_t retval;
117 struct file * file;
119 retval = -EBADF;
120 file = fget(fd);
121 if (!file)
122 goto bad;
124 retval = -EINVAL;
125 if (origin <= 2) {
126 loff_t res = llseek(file, offset, origin);
127 retval = res;
128 if (res != (loff_t)retval)
129 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
131 fput(file);
132 bad:
133 return retval;
136 #if !defined(__alpha__)
137 asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
138 unsigned long offset_low, loff_t * result,
139 unsigned int origin)
141 int retval;
142 struct file * file;
143 loff_t offset;
145 retval = -EBADF;
146 file = fget(fd);
147 if (!file)
148 goto bad;
150 retval = -EINVAL;
151 if (origin > 2)
152 goto out_putf;
154 offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
155 origin);
157 retval = (int)offset;
158 if (offset >= 0) {
159 retval = -EFAULT;
160 if (!copy_to_user(result, &offset, sizeof(offset)))
161 retval = 0;
163 out_putf:
164 fput(file);
165 bad:
166 return retval;
168 #endif
170 ssize_t do_sync_read(struct file *filp, char *buf, size_t len, loff_t *ppos)
172 struct kiocb kiocb;
173 ssize_t ret;
175 init_sync_kiocb(&kiocb, filp);
176 kiocb.ki_pos = *ppos;
177 ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos);
178 if (-EIOCBQUEUED == ret)
179 ret = wait_on_sync_kiocb(&kiocb);
180 *ppos = kiocb.ki_pos;
181 return ret;
184 ssize_t vfs_read(struct file *file, char *buf, size_t count, loff_t *pos)
186 struct inode *inode = file->f_dentry->d_inode;
187 ssize_t ret;
189 if (!(file->f_mode & FMODE_READ))
190 return -EBADF;
191 if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
192 return -EINVAL;
194 ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
195 if (!ret) {
196 ret = security_ops->file_permission (file, MAY_READ);
197 if (!ret) {
198 if (file->f_op->read)
199 ret = file->f_op->read(file, buf, count, pos);
200 else
201 ret = do_sync_read(file, buf, count, pos);
202 if (ret > 0)
203 dnotify_parent(file->f_dentry, DN_ACCESS);
207 return ret;
210 ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *ppos)
212 struct kiocb kiocb;
213 ssize_t ret;
215 init_sync_kiocb(&kiocb, filp);
216 kiocb.ki_pos = *ppos;
217 ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos);
218 if (-EIOCBQUEUED == ret)
219 ret = wait_on_sync_kiocb(&kiocb);
220 *ppos = kiocb.ki_pos;
221 return ret;
224 ssize_t vfs_write(struct file *file, const char *buf, size_t count, loff_t *pos)
226 struct inode *inode = file->f_dentry->d_inode;
227 ssize_t ret;
229 if (!(file->f_mode & FMODE_WRITE))
230 return -EBADF;
231 if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
232 return -EINVAL;
234 ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
235 if (!ret) {
236 ret = security_ops->file_permission (file, MAY_WRITE);
237 if (!ret) {
238 if (file->f_op->write)
239 ret = file->f_op->write(file, buf, count, pos);
240 else
241 ret = do_sync_write(file, buf, count, pos);
242 if (ret > 0)
243 dnotify_parent(file->f_dentry, DN_MODIFY);
247 return ret;
250 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
252 struct file *file;
253 ssize_t ret = -EBADF;
255 file = fget(fd);
256 if (file) {
257 ret = vfs_read(file, buf, count, &file->f_pos);
258 fput(file);
261 return ret;
264 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
266 struct file *file;
267 ssize_t ret = -EBADF;
269 file = fget(fd);
270 if (file) {
271 ret = vfs_write(file, buf, count, &file->f_pos);
272 fput(file);
275 return ret;
278 asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf,
279 size_t count, loff_t pos)
281 struct file *file;
282 ssize_t ret = -EBADF;
284 if (pos < 0)
285 return -EINVAL;
287 file = fget(fd);
288 if (file) {
289 ret = vfs_read(file, buf, count, &pos);
290 fput(file);
293 return ret;
296 asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf,
297 size_t count, loff_t pos)
299 struct file *file;
300 ssize_t ret = -EBADF;
302 if (pos < 0)
303 return -EINVAL;
305 file = fget(fd);
306 if (file) {
307 ret = vfs_write(file, buf, count, &pos);
308 fput(file);
311 return ret;
315 * Reduce an iovec's length in-place. Return the resulting number of segments
317 unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
319 unsigned long seg = 0;
320 size_t len = 0;
322 while (seg < nr_segs) {
323 seg++;
324 if (len + iov->iov_len >= to) {
325 iov->iov_len = to - len;
326 break;
328 len += iov->iov_len;
329 iov++;
331 return seg;
334 static ssize_t do_readv_writev(int type, struct file *file,
335 const struct iovec * vector,
336 unsigned long nr_segs, loff_t *pos)
338 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
339 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
341 size_t tot_len;
342 struct iovec iovstack[UIO_FASTIOV];
343 struct iovec *iov=iovstack;
344 ssize_t ret;
345 int seg;
346 io_fn_t fn;
347 iov_fn_t fnv;
348 struct inode *inode;
351 * SuS says "The readv() function *may* fail if the iovcnt argument
352 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
353 * traditionally returned zero for zero segments, so...
355 ret = 0;
356 if (nr_segs == 0)
357 goto out;
360 * First get the "struct iovec" from user memory and
361 * verify all the pointers
363 ret = -EINVAL;
364 if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
365 goto out;
366 if (!file->f_op)
367 goto out;
368 if (nr_segs > UIO_FASTIOV) {
369 ret = -ENOMEM;
370 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
371 if (!iov)
372 goto out;
374 ret = -EFAULT;
375 if (copy_from_user(iov, vector, nr_segs*sizeof(*vector)))
376 goto out;
379 * Single unix specification:
380 * We should -EINVAL if an element length is not >= 0 and fitting an
381 * ssize_t. The total length is fitting an ssize_t
383 * Be careful here because iov_len is a size_t not an ssize_t
385 tot_len = 0;
386 ret = -EINVAL;
387 for (seg = 0 ; seg < nr_segs; seg++) {
388 ssize_t tmp = tot_len;
389 ssize_t len = (ssize_t)iov[seg].iov_len;
390 if (len < 0) /* size_t not fitting an ssize_t .. */
391 goto out;
392 tot_len += len;
393 if (tot_len < tmp) /* maths overflow on the ssize_t */
394 goto out;
396 if (tot_len == 0) {
397 ret = 0;
398 goto out;
401 inode = file->f_dentry->d_inode;
402 /* VERIFY_WRITE actually means a read, as we write to user space */
403 ret = locks_verify_area((type == READ
404 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
405 inode, file, *pos, tot_len);
406 if (ret)
407 goto out;
409 fnv = NULL;
410 if (type == READ) {
411 fn = file->f_op->read;
412 fnv = file->f_op->readv;
413 } else {
414 fn = (io_fn_t)file->f_op->write;
415 fnv = file->f_op->writev;
417 if (fnv) {
418 ret = fnv(file, iov, nr_segs, pos);
419 goto out;
422 /* Do it by hand, with file-ops */
423 ret = 0;
424 vector = iov;
425 while (nr_segs > 0) {
426 void * base;
427 size_t len;
428 ssize_t nr;
430 base = vector->iov_base;
431 len = vector->iov_len;
432 vector++;
433 nr_segs--;
435 nr = fn(file, base, len, pos);
437 if (nr < 0) {
438 if (!ret) ret = nr;
439 break;
441 ret += nr;
442 if (nr != len)
443 break;
445 out:
446 if (iov != iovstack)
447 kfree(iov);
448 if ((ret + (type == READ)) > 0)
449 dnotify_parent(file->f_dentry,
450 (type == READ) ? DN_MODIFY : DN_ACCESS);
451 return ret;
454 ssize_t vfs_readv(struct file *file, const struct iovec *vec,
455 unsigned long vlen, loff_t *pos)
457 if (!(file->f_mode & FMODE_READ))
458 return -EBADF;
459 if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
460 return -EINVAL;
462 return do_readv_writev(READ, file, vec, vlen, pos);
465 ssize_t vfs_writev(struct file *file, const struct iovec *vec,
466 unsigned long vlen, loff_t *pos)
468 if (!(file->f_mode & FMODE_WRITE))
469 return -EBADF;
470 if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
471 return -EINVAL;
473 return do_readv_writev(WRITE, file, vec, vlen, pos);
477 asmlinkage ssize_t
478 sys_readv(unsigned long fd, const struct iovec *vec, unsigned long vlen)
480 struct file *file;
481 ssize_t ret = -EBADF;
483 file = fget(fd);
484 if (file) {
485 ret = vfs_readv(file, vec, vlen, &file->f_pos);
486 fput(file);
489 return ret;
492 asmlinkage ssize_t
493 sys_writev(unsigned long fd, const struct iovec *vec, unsigned long vlen)
495 struct file *file;
496 ssize_t ret = -EBADF;
498 file = fget(fd);
499 if (file) {
500 ret = vfs_writev(file, vec, vlen, &file->f_pos);
501 fput(file);
504 return ret;
507 static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
508 size_t count, loff_t max)
510 struct file * in_file, * out_file;
511 struct inode * in_inode, * out_inode;
512 loff_t pos;
513 ssize_t retval;
516 * Get input file, and verify that it is ok..
518 retval = -EBADF;
519 in_file = fget(in_fd);
520 if (!in_file)
521 goto out;
522 if (!(in_file->f_mode & FMODE_READ))
523 goto fput_in;
524 retval = -EINVAL;
525 in_inode = in_file->f_dentry->d_inode;
526 if (!in_inode)
527 goto fput_in;
528 if (!in_file->f_op || !in_file->f_op->sendfile)
529 goto fput_in;
530 retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count);
531 if (retval)
532 goto fput_in;
535 * Get output file, and verify that it is ok..
537 retval = -EBADF;
538 out_file = fget(out_fd);
539 if (!out_file)
540 goto fput_in;
541 if (!(out_file->f_mode & FMODE_WRITE))
542 goto fput_out;
543 retval = -EINVAL;
544 if (!out_file->f_op || !out_file->f_op->sendpage)
545 goto fput_out;
546 out_inode = out_file->f_dentry->d_inode;
547 retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
548 if (retval)
549 goto fput_out;
551 if (!ppos)
552 ppos = &in_file->f_pos;
554 if (!max)
555 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
557 pos = *ppos;
558 retval = -EINVAL;
559 if (unlikely(pos < 0))
560 goto fput_out;
561 if (unlikely(pos + count > max)) {
562 retval = -EOVERFLOW;
563 if (pos >= max)
564 goto fput_out;
565 count = max - pos;
568 retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
570 if (*ppos > max)
571 retval = -EOVERFLOW;
573 fput_out:
574 fput(out_file);
575 fput_in:
576 fput(in_file);
577 out:
578 return retval;
581 asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
583 loff_t pos;
584 off_t off;
585 ssize_t ret;
587 if (offset) {
588 if (unlikely(get_user(off, offset)))
589 return -EFAULT;
590 pos = off;
591 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
592 if (unlikely(put_user(pos, offset)))
593 return -EFAULT;
594 return ret;
597 return do_sendfile(out_fd, in_fd, NULL, count, MAX_NON_LFS);
600 asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count)
602 loff_t pos;
603 ssize_t ret;
605 if (offset) {
606 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
607 return -EFAULT;
608 ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
609 if (unlikely(put_user(pos, offset)))
610 return -EFAULT;
611 return ret;
614 return do_sendfile(out_fd, in_fd, NULL, count, 0);
617 EXPORT_SYMBOL(do_sync_read);
618 EXPORT_SYMBOL(do_sync_write);