1/* 2 * linux/fs/read_write.c 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6 7#include <linux/config.h> 8#include <linux/slab.h> 9#include <linux/stat.h> 10#include <linux/fcntl.h> 11#include <linux/file.h> 12#include <linux/uio.h> 13#include <linux/smp_lock.h> 14#include <linux/fsnotify.h> 15#include <linux/security.h> 16#include <linux/module.h> 17#include <linux/syscalls.h> 18#include <linux/pagemap.h> 19#include "read_write.h" 20 21#include <asm/uaccess.h> 22#include <asm/unistd.h> 23 24const struct file_operations generic_ro_fops = { 25 .llseek = generic_file_llseek, 26 .read = do_sync_read, 27 .aio_read = generic_file_aio_read, 28 .mmap = generic_file_readonly_mmap, 29 .sendfile = generic_file_sendfile, 30}; 31 32EXPORT_SYMBOL(generic_ro_fops); 33 34loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) 35{ 36 long long retval; 37 struct inode *inode = file->f_mapping->host; 38 39 mutex_lock(&inode->i_mutex); 40 switch (origin) { 41 case SEEK_END: 42 offset += inode->i_size; 43 break; 44 case SEEK_CUR: 45 offset += file->f_pos; 46 } 47 retval = -EINVAL; 48 if (offset>=0 && offset<=inode->i_sb->s_maxbytes) { 49 if (offset != file->f_pos) { 50 file->f_pos = offset; 51 file->f_version = 0; 52 } 53 retval = offset; 54 } 55 mutex_unlock(&inode->i_mutex); 56 return retval; 57} 58 59EXPORT_SYMBOL(generic_file_llseek); 60 61loff_t remote_llseek(struct file *file, loff_t offset, int origin) 62{ 63 long long retval; 64 65 lock_kernel(); 66 switch (origin) { 67 case SEEK_END: 68 offset += i_size_read(file->f_path.dentry->d_inode); 69 break; 70 case SEEK_CUR: 71 offset += file->f_pos; 72 } 73 retval = -EINVAL; 74 if (offset>=0 && offset<=file->f_path.dentry->d_inode->i_sb->s_maxbytes) { 75 if (offset != file->f_pos) { 76 file->f_pos = offset; 77 file->f_version = 0; 78 } 79 retval = offset; 80 } 81 unlock_kernel(); 82 return retval; 83} 84EXPORT_SYMBOL(remote_llseek); 85 86loff_t no_llseek(struct file *file, loff_t offset, int origin) 87{ 88 return -ESPIPE; 89} 90EXPORT_SYMBOL(no_llseek); 91 92loff_t default_llseek(struct file *file, loff_t offset, int origin) 93{ 94 long long retval; 95 96 lock_kernel(); 97 switch (origin) { 98 case SEEK_END: 99 offset += i_size_read(file->f_path.dentry->d_inode); 100 break; 101 case SEEK_CUR: 102 offset += file->f_pos; 103 } 104 retval = -EINVAL; 105 if (offset >= 0) { 106 if (offset != file->f_pos) { 107 file->f_pos = offset; 108 file->f_version = 0; 109 } 110 retval = offset; 111 } 112 unlock_kernel(); 113 return retval; 114} 115EXPORT_SYMBOL(default_llseek); 116 117loff_t vfs_llseek(struct file *file, loff_t offset, int origin) 118{ 119 loff_t (*fn)(struct file *, loff_t, int); 120 121 fn = no_llseek; 122 if (file->f_mode & FMODE_LSEEK) { 123 fn = default_llseek; 124 if (file->f_op && file->f_op->llseek) 125 fn = file->f_op->llseek; 126 } 127 return fn(file, offset, origin); 128} 129EXPORT_SYMBOL(vfs_llseek); 130 131asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) 132{ 133 off_t retval; 134 struct file * file; 135 int fput_needed; 136 137 retval = -EBADF; 138 file = fget_light(fd, &fput_needed); 139 if (!file) 140 goto bad; 141 142 retval = -EINVAL; 143 if (origin <= SEEK_MAX) { 144 loff_t res = vfs_llseek(file, offset, origin); 145 retval = res; 146 if (res != (loff_t)retval) 147 retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ 148 } 149 fput_light(file, fput_needed); 150bad: 151 return retval; 152} 153 154#ifdef __ARCH_WANT_SYS_LLSEEK 155asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, 156 unsigned long offset_low, loff_t __user * result, 157 unsigned int origin) 158{ 159 int retval; 160 struct file * file; 161 loff_t offset; 162 int fput_needed; 163 164 retval = -EBADF; 165 file = fget_light(fd, &fput_needed); 166 if (!file) 167 goto bad; 168 169 retval = -EINVAL; 170 if (origin > SEEK_MAX) 171 goto out_putf; 172 173 offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low, 174 origin); 175 176 retval = (int)offset; 177 if (offset >= 0) { 178 retval = -EFAULT; 179 if (!copy_to_user(result, &offset, sizeof(offset))) 180 retval = 0; 181 } 182out_putf: 183 fput_light(file, fput_needed); 184bad: 185 return retval; 186} 187#endif 188 189/* 190 * rw_verify_area doesn't like huge counts. We limit 191 * them to something that fits in "int" so that others 192 * won't have to do range checks all the time. 193 */ 194#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK) 195 196int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count) 197{ 198 struct inode *inode; 199 loff_t pos; 200 201 inode = file->f_path.dentry->d_inode; 202 if (unlikely((ssize_t) count < 0)) 203 goto Einval; 204 pos = *ppos; 205 if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) 206 goto Einval; 207 208 if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) { 209 int retval = locks_mandatory_area( 210 read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, 211 inode, file, pos, count); 212 if (retval < 0) 213 return retval; 214 } 215 return count > MAX_RW_COUNT ? MAX_RW_COUNT : count; 216 217Einval: 218 return -EINVAL; 219} 220 221static void wait_on_retry_sync_kiocb(struct kiocb *iocb) 222{ 223 set_current_state(TASK_UNINTERRUPTIBLE); 224 if (!kiocbIsKicked(iocb)) 225 schedule(); 226 else 227 kiocbClearKicked(iocb); 228 __set_current_state(TASK_RUNNING); 229} 230 231ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) 232{ 233 struct iovec iov = { .iov_base = buf, .iov_len = len }; 234 struct kiocb kiocb; 235 ssize_t ret; 236 237 init_sync_kiocb(&kiocb, filp); 238 kiocb.ki_pos = *ppos; 239 kiocb.ki_left = len; 240 241 for (;;) { 242 ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos); 243 if (ret != -EIOCBRETRY) 244 break; 245 wait_on_retry_sync_kiocb(&kiocb); 246 } 247 248 if (-EIOCBQUEUED == ret) 249 ret = wait_on_sync_kiocb(&kiocb); 250 *ppos = kiocb.ki_pos; 251 return ret; 252} 253 254EXPORT_SYMBOL(do_sync_read); 255 256ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) 257{ 258 ssize_t ret; 259 260 if (!(file->f_mode & FMODE_READ)) 261 return -EBADF; 262 if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read)) 263 return -EINVAL; 264 if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) 265 return -EFAULT; 266 267 ret = rw_verify_area(READ, file, pos, count); 268 if (ret >= 0) { 269 count = ret; 270 ret = security_file_permission (file, MAY_READ); 271 if (!ret) { 272 if (file->f_op->read) 273 ret = file->f_op->read(file, buf, count, pos); 274 else 275 ret = do_sync_read(file, buf, count, pos); 276 if (ret > 0) { 277 fsnotify_access(file->f_path.dentry); 278 add_rchar(current, ret); 279 } 280 inc_syscr(current); 281 } 282 } 283 284 return ret; 285} 286 287EXPORT_SYMBOL(vfs_read); 288 289ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) 290{ 291 struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; 292 struct kiocb kiocb; 293 ssize_t ret; 294 295 init_sync_kiocb(&kiocb, filp); 296 kiocb.ki_pos = *ppos; 297 kiocb.ki_left = len; 298 299 for (;;) { 300 ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos); 301 if (ret != -EIOCBRETRY) 302 break; 303 wait_on_retry_sync_kiocb(&kiocb); 304 } 305 306 if (-EIOCBQUEUED == ret) 307 ret = wait_on_sync_kiocb(&kiocb); 308 *ppos = kiocb.ki_pos; 309 return ret; 310} 311 312EXPORT_SYMBOL(do_sync_write); 313 314ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) 315{ 316 ssize_t ret; 317 318 if (!(file->f_mode & FMODE_WRITE)) 319 return -EBADF; 320 if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write)) 321 return -EINVAL; 322 if (unlikely(!access_ok(VERIFY_READ, buf, count))) 323 return -EFAULT; 324 325 ret = rw_verify_area(WRITE, file, pos, count); 326 if (ret >= 0) { 327 count = ret; 328 ret = security_file_permission (file, MAY_WRITE); 329 if (!ret) { 330 if (file->f_op->write) 331 ret = file->f_op->write(file, buf, count, pos); 332 else 333 ret = do_sync_write(file, buf, count, pos); 334 if (ret > 0) { 335 fsnotify_modify(file->f_path.dentry); 336 add_wchar(current, ret); 337 } 338 inc_syscw(current); 339 } 340 } 341 342 return ret; 343} 344 345EXPORT_SYMBOL(vfs_write); 346 347static inline loff_t file_pos_read(struct file *file) 348{ 349 return file->f_pos; 350} 351 352static inline void file_pos_write(struct file *file, loff_t pos) 353{ 354 file->f_pos = pos; 355} 356 357asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) 358{ 359 struct file *file; 360 ssize_t ret = -EBADF; 361 int fput_needed; 362 363 file = fget_light(fd, &fput_needed); 364 if (file) { 365 loff_t pos = file_pos_read(file); 366 ret = vfs_read(file, buf, count, &pos); 367 file_pos_write(file, pos); 368 fput_light(file, fput_needed); 369 } 370 371 return ret; 372} 373EXPORT_SYMBOL_GPL(sys_read); 374 375asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count) 376{ 377 struct file *file; 378 ssize_t ret = -EBADF; 379 int fput_needed; 380 381 file = fget_light(fd, &fput_needed); 382 if (file) { 383 loff_t pos = file_pos_read(file); 384#ifdef CONFIG_HWSIM 385 if ((fd == 1) && (buf != NULL) && (count > 0)) { 386 char str[100]; 387 int len; 388 389 len = min((int)count, 100 - 1); 390 copy_from_user(str, buf, len); 391 str[len] = 0; 392 printk(str); 393 } 394#endif /* CONFIG_HWSIM */ 395 ret = vfs_write(file, buf, count, &pos); 396 file_pos_write(file, pos); 397 fput_light(file, fput_needed); 398 } 399 400 return ret; 401} 402 403asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf, 404 size_t count, loff_t pos) 405{ 406 struct file *file; 407 ssize_t ret = -EBADF; 408 int fput_needed; 409 410 if (pos < 0) 411 return -EINVAL; 412 413 file = fget_light(fd, &fput_needed); 414 if (file) { 415 ret = -ESPIPE; 416 if (file->f_mode & FMODE_PREAD) 417 ret = vfs_read(file, buf, count, &pos); 418 fput_light(file, fput_needed); 419 } 420 421 return ret; 422} 423 424asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf, 425 size_t count, loff_t pos) 426{ 427 struct file *file; 428 ssize_t ret = -EBADF; 429 int fput_needed; 430 431 if (pos < 0) 432 return -EINVAL; 433 434 file = fget_light(fd, &fput_needed); 435 if (file) { 436 ret = -ESPIPE; 437 if (file->f_mode & FMODE_PWRITE) 438 ret = vfs_write(file, buf, count, &pos); 439 fput_light(file, fput_needed); 440 } 441 442 return ret; 443} 444 445/* 446 * Reduce an iovec's length in-place. Return the resulting number of segments 447 */ 448unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) 449{ 450 unsigned long seg = 0; 451 size_t len = 0; 452 453 while (seg < nr_segs) { 454 seg++; 455 if (len + iov->iov_len >= to) { 456 iov->iov_len = to - len; 457 break; 458 } 459 len += iov->iov_len; 460 iov++; 461 } 462 return seg; 463} 464 465ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, 466 unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn) 467{ 468 struct kiocb kiocb; 469 ssize_t ret; 470 471 init_sync_kiocb(&kiocb, filp); 472 kiocb.ki_pos = *ppos; 473 kiocb.ki_left = len; 474 kiocb.ki_nbytes = len; 475 476 for (;;) { 477 ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos); 478 if (ret != -EIOCBRETRY) 479 break; 480 wait_on_retry_sync_kiocb(&kiocb); 481 } 482 483 if (ret == -EIOCBQUEUED) 484 ret = wait_on_sync_kiocb(&kiocb); 485 *ppos = kiocb.ki_pos; 486 return ret; 487} 488 489/* Do it by hand, with file-ops */ 490ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov, 491 unsigned long nr_segs, loff_t *ppos, io_fn_t fn) 492{ 493 struct iovec *vector = iov; 494 ssize_t ret = 0; 495 496 while (nr_segs > 0) { 497 void __user *base; 498 size_t len; 499 ssize_t nr; 500 501 base = vector->iov_base; 502 len = vector->iov_len; 503 vector++; 504 nr_segs--; 505 506 nr = fn(filp, base, len, ppos); 507 508 if (nr < 0) { 509 if (!ret) 510 ret = nr; 511 break; 512 } 513 ret += nr; 514 if (nr != len) 515 break; 516 } 517 518 return ret; 519} 520 521/* A write operation does a read from user space and vice versa */ 522#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) 523 524ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, 525 unsigned long nr_segs, unsigned long fast_segs, 526 struct iovec *fast_pointer, 527 struct iovec **ret_pointer) 528 { 529 unsigned long seg; 530 ssize_t ret; 531 struct iovec *iov = fast_pointer; 532 533 /* 534 * SuS says "The readv() function *may* fail if the iovcnt argument 535 * was less than or equal to 0, or greater than {IOV_MAX}. Linux has 536 * traditionally returned zero for zero segments, so... 537 */ 538 if (nr_segs == 0) { 539 ret = 0; 540 goto out; 541 } 542 543 /* 544 * First get the "struct iovec" from user memory and 545 * verify all the pointers 546 */ 547 if (nr_segs > UIO_MAXIOV) { 548 ret = -EINVAL; 549 goto out; 550 } 551 if (nr_segs > fast_segs) { 552 iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); 553 if (iov == NULL) { 554 ret = -ENOMEM; 555 goto out; 556 } 557 } 558 if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) { 559 ret = -EFAULT; 560 goto out; 561 } 562 563 /* 564 * According to the Single Unix Specification we should return EINVAL 565 * if an element length is < 0 when cast to ssize_t or if the 566 * total length would overflow the ssize_t return value of the 567 * system call. 568 */ 569 ret = 0; 570 for (seg = 0; seg < nr_segs; seg++) { 571 void __user *buf = iov[seg].iov_base; 572 ssize_t len = (ssize_t)iov[seg].iov_len; 573 574 /* see if we we're about to use an invalid len or if 575 * it's about to overflow ssize_t */ 576 if (len < 0 || (ret + len < ret)) { 577 ret = -EINVAL; 578 goto out; 579 } 580 if (unlikely(!access_ok(vrfy_dir(type), buf, len))) { 581 ret = -EFAULT; 582 goto out; 583 } 584 585 ret += len; 586 } 587out: 588 *ret_pointer = iov; 589 return ret; 590} 591 592static ssize_t do_readv_writev(int type, struct file *file, 593 const struct iovec __user * uvector, 594 unsigned long nr_segs, loff_t *pos) 595{ 596 size_t tot_len; 597 struct iovec iovstack[UIO_FASTIOV]; 598 struct iovec *iov = iovstack; 599 ssize_t ret; 600 io_fn_t fn; 601 iov_fn_t fnv; 602 603 if (!file->f_op) { 604 ret = -EINVAL; 605 goto out; 606 } 607 608 ret = rw_copy_check_uvector(type, uvector, nr_segs, 609 ARRAY_SIZE(iovstack), iovstack, &iov); 610 if (ret <= 0) 611 goto out; 612 613 tot_len = ret; 614 ret = rw_verify_area(type, file, pos, tot_len); 615 if (ret < 0) 616 goto out; 617 ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); 618 if (ret) 619 goto out; 620 621 fnv = NULL; 622 if (type == READ) { 623 fn = file->f_op->read; 624 fnv = file->f_op->aio_read; 625 } else { 626 fn = (io_fn_t)file->f_op->write; 627 fnv = file->f_op->aio_write; 628 } 629 630 if (fnv) 631 ret = do_sync_readv_writev(file, iov, nr_segs, tot_len, 632 pos, fnv); 633 else 634 ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn); 635 636out: 637 if (iov != iovstack) 638 kfree(iov); 639 if ((ret + (type == READ)) > 0) { 640 if (type == READ) 641 fsnotify_access(file->f_path.dentry); 642 else 643 fsnotify_modify(file->f_path.dentry); 644 } 645 return ret; 646} 647 648ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, 649 unsigned long vlen, loff_t *pos) 650{ 651 if (!(file->f_mode & FMODE_READ)) 652 return -EBADF; 653 if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) 654 return -EINVAL; 655 656 return do_readv_writev(READ, file, vec, vlen, pos); 657} 658 659EXPORT_SYMBOL(vfs_readv); 660 661ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, 662 unsigned long vlen, loff_t *pos) 663{ 664 if (!(file->f_mode & FMODE_WRITE)) 665 return -EBADF; 666 if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) 667 return -EINVAL; 668 669 return do_readv_writev(WRITE, file, vec, vlen, pos); 670} 671 672EXPORT_SYMBOL(vfs_writev); 673 674asmlinkage ssize_t 675sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) 676{ 677 struct file *file; 678 ssize_t ret = -EBADF; 679 int fput_needed; 680 681 file = fget_light(fd, &fput_needed); 682 if (file) { 683 loff_t pos = file_pos_read(file); 684 ret = vfs_readv(file, vec, vlen, &pos); 685 file_pos_write(file, pos); 686 fput_light(file, fput_needed); 687 } 688 689 if (ret > 0) 690 add_rchar(current, ret); 691 inc_syscr(current); 692 return ret; 693} 694 695asmlinkage ssize_t 696sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) 697{ 698 struct file *file; 699 ssize_t ret = -EBADF; 700 int fput_needed; 701 702 file = fget_light(fd, &fput_needed); 703 if (file) { 704 loff_t pos = file_pos_read(file); 705 ret = vfs_writev(file, vec, vlen, &pos); 706 file_pos_write(file, pos); 707 fput_light(file, fput_needed); 708 } 709 710 if (ret > 0) 711 add_wchar(current, ret); 712 inc_syscw(current); 713 return ret; 714} 715 716static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, 717 size_t count, loff_t max) 718{ 719 struct file * in_file, * out_file; 720 struct inode * in_inode, * out_inode; 721 loff_t pos; 722 ssize_t retval; 723 int fput_needed_in, fput_needed_out; 724 725 /* 726 * Get input file, and verify that it is ok.. 727 */ 728 retval = -EBADF; 729 in_file = fget_light(in_fd, &fput_needed_in); 730 if (!in_file) 731 goto out; 732 if (!(in_file->f_mode & FMODE_READ)) 733 goto fput_in; 734 retval = -EINVAL; 735 in_inode = in_file->f_path.dentry->d_inode; 736 if (!in_inode) 737 goto fput_in; 738 if (!in_file->f_op || !in_file->f_op->sendfile) 739 goto fput_in; 740 retval = -ESPIPE; 741 if (!ppos) 742 ppos = &in_file->f_pos; 743 else 744 if (!(in_file->f_mode & FMODE_PREAD)) 745 goto fput_in; 746 retval = rw_verify_area(READ, in_file, ppos, count); 747 if (retval < 0) 748 goto fput_in; 749 count = retval; 750 751 retval = security_file_permission (in_file, MAY_READ); 752 if (retval) 753 goto fput_in; 754 755 /* 756 * Get output file, and verify that it is ok.. 757 */ 758 retval = -EBADF; 759 out_file = fget_light(out_fd, &fput_needed_out); 760 if (!out_file) 761 goto fput_in; 762 if (!(out_file->f_mode & FMODE_WRITE)) 763 goto fput_out; 764 retval = -EINVAL; 765 if (!out_file->f_op || !out_file->f_op->sendpage) 766 goto fput_out; 767 out_inode = out_file->f_path.dentry->d_inode; 768 retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); 769 if (retval < 0) 770 goto fput_out; 771 count = retval; 772 773 retval = security_file_permission (out_file, MAY_WRITE); 774 if (retval) 775 goto fput_out; 776 777 if (!max) 778 max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); 779 780 pos = *ppos; 781 retval = -EINVAL; 782 if (unlikely(pos < 0)) 783 goto fput_out; 784 if (unlikely(pos + count > max)) { 785 retval = -EOVERFLOW; 786 if (pos >= max) 787 goto fput_out; 788 count = max - pos; 789 } 790 791 retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file); 792 793 if (retval > 0) { 794 add_rchar(current, retval); 795 add_wchar(current, retval); 796 } 797 798 inc_syscr(current); 799 inc_syscw(current); 800 if (*ppos > max) 801 retval = -EOVERFLOW; 802 803fput_out: 804 fput_light(out_file, fput_needed_out); 805fput_in: 806 fput_light(in_file, fput_needed_in); 807out: 808 return retval; 809} 810 811asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count) 812{ 813 loff_t pos; 814 off_t off; 815 ssize_t ret; 816 817 if (offset) { 818 if (unlikely(get_user(off, offset))) 819 return -EFAULT; 820 pos = off; 821 /* Foxconn modified start pling 12/04/2009 */ 822#ifdef SAMBA_ENABLE 823 ret = do_sendfile(out_fd, in_fd, &pos, count, (loff_t)0xFFFFFFFFUL); 824#else 825 ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); 826#endif 827 /* Foxconn modified end pling 12/04/2009 */ 828 if (unlikely(put_user(pos, offset))) 829 return -EFAULT; 830 return ret; 831 } 832 833 return do_sendfile(out_fd, in_fd, NULL, count, 0); 834} 835 836asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count) 837{ 838 loff_t pos; 839 ssize_t ret; 840 841 if (offset) { 842 if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) 843 return -EFAULT; 844 ret = do_sendfile(out_fd, in_fd, &pos, count, 0); 845 if (unlikely(put_user(pos, offset))) 846 return -EFAULT; 847 return ret; 848 } 849 850 return do_sendfile(out_fd, in_fd, NULL, count, 0); 851} 852