Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

readdir: move compat syscalls from compat.c

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 0460b2a2 4ada54ee

+165 -162
-162
fs/compat.c
··· 548 548 return retval; 549 549 } 550 550 551 - struct compat_old_linux_dirent { 552 - compat_ulong_t d_ino; 553 - compat_ulong_t d_offset; 554 - unsigned short d_namlen; 555 - char d_name[1]; 556 - }; 557 - 558 - struct compat_readdir_callback { 559 - struct dir_context ctx; 560 - struct compat_old_linux_dirent __user *dirent; 561 - int result; 562 - }; 563 - 564 - static int compat_fillonedir(struct dir_context *ctx, const char *name, 565 - int namlen, loff_t offset, u64 ino, 566 - unsigned int d_type) 567 - { 568 - struct compat_readdir_callback *buf = 569 - container_of(ctx, struct compat_readdir_callback, ctx); 570 - struct compat_old_linux_dirent __user *dirent; 571 - compat_ulong_t d_ino; 572 - 573 - if (buf->result) 574 - return -EINVAL; 575 - d_ino = ino; 576 - if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 577 - buf->result = -EOVERFLOW; 578 - return -EOVERFLOW; 579 - } 580 - buf->result++; 581 - dirent = buf->dirent; 582 - if (!access_ok(VERIFY_WRITE, dirent, 583 - (unsigned long)(dirent->d_name + namlen + 1) - 584 - (unsigned long)dirent)) 585 - goto efault; 586 - if ( __put_user(d_ino, &dirent->d_ino) || 587 - __put_user(offset, &dirent->d_offset) || 588 - __put_user(namlen, &dirent->d_namlen) || 589 - __copy_to_user(dirent->d_name, name, namlen) || 590 - __put_user(0, dirent->d_name + namlen)) 591 - goto efault; 592 - return 0; 593 - efault: 594 - buf->result = -EFAULT; 595 - return -EFAULT; 596 - } 597 - 598 - COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 599 - struct compat_old_linux_dirent __user *, dirent, unsigned int, count) 600 - { 601 - int error; 602 - struct fd f = fdget_pos(fd); 603 - struct compat_readdir_callback buf = { 604 - .ctx.actor = compat_fillonedir, 605 - .dirent = dirent 606 - }; 607 - 608 - if (!f.file) 609 - return -EBADF; 610 - 611 - error = iterate_dir(f.file, &buf.ctx); 612 - if (buf.result) 613 - error = buf.result; 614 - 615 - fdput_pos(f); 616 - return error; 617 - } 618 - 619 - struct compat_linux_dirent { 620 - compat_ulong_t d_ino; 621 - compat_ulong_t d_off; 622 - unsigned short d_reclen; 623 - char d_name[1]; 624 - }; 625 - 626 - struct compat_getdents_callback { 627 - struct dir_context ctx; 628 - struct compat_linux_dirent __user *current_dir; 629 - struct compat_linux_dirent __user *previous; 630 - int count; 631 - int error; 632 - }; 633 - 634 - static int compat_filldir(struct dir_context *ctx, const char *name, int namlen, 635 - loff_t offset, u64 ino, unsigned int d_type) 636 - { 637 - struct compat_linux_dirent __user * dirent; 638 - struct compat_getdents_callback *buf = 639 - container_of(ctx, struct compat_getdents_callback, ctx); 640 - compat_ulong_t d_ino; 641 - int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + 642 - namlen + 2, sizeof(compat_long_t)); 643 - 644 - buf->error = -EINVAL; /* only used if we fail.. */ 645 - if (reclen > buf->count) 646 - return -EINVAL; 647 - d_ino = ino; 648 - if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 649 - buf->error = -EOVERFLOW; 650 - return -EOVERFLOW; 651 - } 652 - dirent = buf->previous; 653 - if (dirent) { 654 - if (signal_pending(current)) 655 - return -EINTR; 656 - if (__put_user(offset, &dirent->d_off)) 657 - goto efault; 658 - } 659 - dirent = buf->current_dir; 660 - if (__put_user(d_ino, &dirent->d_ino)) 661 - goto efault; 662 - if (__put_user(reclen, &dirent->d_reclen)) 663 - goto efault; 664 - if (copy_to_user(dirent->d_name, name, namlen)) 665 - goto efault; 666 - if (__put_user(0, dirent->d_name + namlen)) 667 - goto efault; 668 - if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 669 - goto efault; 670 - buf->previous = dirent; 671 - dirent = (void __user *)dirent + reclen; 672 - buf->current_dir = dirent; 673 - buf->count -= reclen; 674 - return 0; 675 - efault: 676 - buf->error = -EFAULT; 677 - return -EFAULT; 678 - } 679 - 680 - COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, 681 - struct compat_linux_dirent __user *, dirent, unsigned int, count) 682 - { 683 - struct fd f; 684 - struct compat_linux_dirent __user * lastdirent; 685 - struct compat_getdents_callback buf = { 686 - .ctx.actor = compat_filldir, 687 - .current_dir = dirent, 688 - .count = count 689 - }; 690 - int error; 691 - 692 - if (!access_ok(VERIFY_WRITE, dirent, count)) 693 - return -EFAULT; 694 - 695 - f = fdget_pos(fd); 696 - if (!f.file) 697 - return -EBADF; 698 - 699 - error = iterate_dir(f.file, &buf.ctx); 700 - if (error >= 0) 701 - error = buf.error; 702 - lastdirent = buf.previous; 703 - if (lastdirent) { 704 - if (put_user(buf.ctx.pos, &lastdirent->d_off)) 705 - error = -EFAULT; 706 - else 707 - error = count - buf.count; 708 - } 709 - fdput_pos(f); 710 - return error; 711 - } 712 - 713 551 /* 714 552 * Exactly like fs/open.c:sys_open(), except that it doesn't set the 715 553 * O_LARGEFILE flag.
+165
fs/readdir.c
··· 18 18 #include <linux/security.h> 19 19 #include <linux/syscalls.h> 20 20 #include <linux/unistd.h> 21 + #include <linux/compat.h> 21 22 22 23 #include <linux/uaccess.h> 23 24 ··· 325 324 fdput_pos(f); 326 325 return error; 327 326 } 327 + 328 + #ifdef CONFIG_COMPAT 329 + struct compat_old_linux_dirent { 330 + compat_ulong_t d_ino; 331 + compat_ulong_t d_offset; 332 + unsigned short d_namlen; 333 + char d_name[1]; 334 + }; 335 + 336 + struct compat_readdir_callback { 337 + struct dir_context ctx; 338 + struct compat_old_linux_dirent __user *dirent; 339 + int result; 340 + }; 341 + 342 + static int compat_fillonedir(struct dir_context *ctx, const char *name, 343 + int namlen, loff_t offset, u64 ino, 344 + unsigned int d_type) 345 + { 346 + struct compat_readdir_callback *buf = 347 + container_of(ctx, struct compat_readdir_callback, ctx); 348 + struct compat_old_linux_dirent __user *dirent; 349 + compat_ulong_t d_ino; 350 + 351 + if (buf->result) 352 + return -EINVAL; 353 + d_ino = ino; 354 + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 355 + buf->result = -EOVERFLOW; 356 + return -EOVERFLOW; 357 + } 358 + buf->result++; 359 + dirent = buf->dirent; 360 + if (!access_ok(VERIFY_WRITE, dirent, 361 + (unsigned long)(dirent->d_name + namlen + 1) - 362 + (unsigned long)dirent)) 363 + goto efault; 364 + if ( __put_user(d_ino, &dirent->d_ino) || 365 + __put_user(offset, &dirent->d_offset) || 366 + __put_user(namlen, &dirent->d_namlen) || 367 + __copy_to_user(dirent->d_name, name, namlen) || 368 + __put_user(0, dirent->d_name + namlen)) 369 + goto efault; 370 + return 0; 371 + efault: 372 + buf->result = -EFAULT; 373 + return -EFAULT; 374 + } 375 + 376 + COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, 377 + struct compat_old_linux_dirent __user *, dirent, unsigned int, count) 378 + { 379 + int error; 380 + struct fd f = fdget_pos(fd); 381 + struct compat_readdir_callback buf = { 382 + .ctx.actor = compat_fillonedir, 383 + .dirent = dirent 384 + }; 385 + 386 + if (!f.file) 387 + return -EBADF; 388 + 389 + error = iterate_dir(f.file, &buf.ctx); 390 + if (buf.result) 391 + error = buf.result; 392 + 393 + fdput_pos(f); 394 + return error; 395 + } 396 + 397 + struct compat_linux_dirent { 398 + compat_ulong_t d_ino; 399 + compat_ulong_t d_off; 400 + unsigned short d_reclen; 401 + char d_name[1]; 402 + }; 403 + 404 + struct compat_getdents_callback { 405 + struct dir_context ctx; 406 + struct compat_linux_dirent __user *current_dir; 407 + struct compat_linux_dirent __user *previous; 408 + int count; 409 + int error; 410 + }; 411 + 412 + static int compat_filldir(struct dir_context *ctx, const char *name, int namlen, 413 + loff_t offset, u64 ino, unsigned int d_type) 414 + { 415 + struct compat_linux_dirent __user * dirent; 416 + struct compat_getdents_callback *buf = 417 + container_of(ctx, struct compat_getdents_callback, ctx); 418 + compat_ulong_t d_ino; 419 + int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + 420 + namlen + 2, sizeof(compat_long_t)); 421 + 422 + buf->error = -EINVAL; /* only used if we fail.. */ 423 + if (reclen > buf->count) 424 + return -EINVAL; 425 + d_ino = ino; 426 + if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { 427 + buf->error = -EOVERFLOW; 428 + return -EOVERFLOW; 429 + } 430 + dirent = buf->previous; 431 + if (dirent) { 432 + if (signal_pending(current)) 433 + return -EINTR; 434 + if (__put_user(offset, &dirent->d_off)) 435 + goto efault; 436 + } 437 + dirent = buf->current_dir; 438 + if (__put_user(d_ino, &dirent->d_ino)) 439 + goto efault; 440 + if (__put_user(reclen, &dirent->d_reclen)) 441 + goto efault; 442 + if (copy_to_user(dirent->d_name, name, namlen)) 443 + goto efault; 444 + if (__put_user(0, dirent->d_name + namlen)) 445 + goto efault; 446 + if (__put_user(d_type, (char __user *) dirent + reclen - 1)) 447 + goto efault; 448 + buf->previous = dirent; 449 + dirent = (void __user *)dirent + reclen; 450 + buf->current_dir = dirent; 451 + buf->count -= reclen; 452 + return 0; 453 + efault: 454 + buf->error = -EFAULT; 455 + return -EFAULT; 456 + } 457 + 458 + COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, 459 + struct compat_linux_dirent __user *, dirent, unsigned int, count) 460 + { 461 + struct fd f; 462 + struct compat_linux_dirent __user * lastdirent; 463 + struct compat_getdents_callback buf = { 464 + .ctx.actor = compat_filldir, 465 + .current_dir = dirent, 466 + .count = count 467 + }; 468 + int error; 469 + 470 + if (!access_ok(VERIFY_WRITE, dirent, count)) 471 + return -EFAULT; 472 + 473 + f = fdget_pos(fd); 474 + if (!f.file) 475 + return -EBADF; 476 + 477 + error = iterate_dir(f.file, &buf.ctx); 478 + if (error >= 0) 479 + error = buf.error; 480 + lastdirent = buf.previous; 481 + if (lastdirent) { 482 + if (put_user(buf.ctx.pos, &lastdirent->d_off)) 483 + error = -EFAULT; 484 + else 485 + error = count - buf.count; 486 + } 487 + fdput_pos(f); 488 + return error; 489 + } 490 + #endif