Mercurial > hg > nginx
comparison src/core/ngx_open_file_cache.c @ 4479:5e6436812c9a
Disable symlinks: cleanup error handling.
Notably this fixes NGX_INVALID_FILE/NGX_FILE_ERROR mess, and adds
logging of close() errors. In collaboration with Valentin Bartenev.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 15 Feb 2012 12:17:24 +0000 |
parents | 7033faf6dc3c |
children | 5a3cb84545e5 |
comparison
equal
deleted
inserted
replaced
4478:08713bac87fc | 4479:5e6436812c9a |
---|---|
22 | 22 |
23 | 23 |
24 static void ngx_open_file_cache_cleanup(void *data); | 24 static void ngx_open_file_cache_cleanup(void *data); |
25 #if (NGX_HAVE_OPENAT) | 25 #if (NGX_HAVE_OPENAT) |
26 static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, | 26 static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, |
27 ngx_int_t mode, ngx_int_t create, ngx_int_t access); | 27 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); |
28 #endif | 28 #endif |
29 static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, | 29 static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, |
30 ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, | 30 ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, |
31 ngx_int_t access); | 31 ngx_int_t access, ngx_log_t *log); |
32 static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, | 32 static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, |
33 ngx_open_file_info_t *of, ngx_file_info_t *fi); | 33 ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log); |
34 static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, | 34 static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, |
35 ngx_open_file_info_t *of, ngx_log_t *log); | 35 ngx_open_file_info_t *of, ngx_log_t *log); |
36 static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, | 36 static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, |
37 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); | 37 ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); |
38 static void ngx_open_file_cleanup(void *data); | 38 static void ngx_open_file_cleanup(void *data); |
154 | 154 |
155 if (cache == NULL) { | 155 if (cache == NULL) { |
156 | 156 |
157 if (of->test_only) { | 157 if (of->test_only) { |
158 | 158 |
159 if (ngx_file_info_wrapper(name, of, &fi) == NGX_FILE_ERROR) { | 159 if (ngx_file_info_wrapper(name, of, &fi, pool->log) |
160 == NGX_FILE_ERROR) | |
161 { | |
160 return NGX_ERROR; | 162 return NGX_ERROR; |
161 } | 163 } |
162 | 164 |
163 of->uniq = ngx_file_uniq(&fi); | 165 of->uniq = ngx_file_uniq(&fi); |
164 of->mtime = ngx_file_mtime(&fi); | 166 of->mtime = ngx_file_mtime(&fi); |
480 | 482 |
481 #if (NGX_HAVE_OPENAT) | 483 #if (NGX_HAVE_OPENAT) |
482 | 484 |
483 static ngx_fd_t | 485 static ngx_fd_t |
484 ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, | 486 ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, |
485 ngx_int_t mode, ngx_int_t create, ngx_int_t access) | 487 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) |
486 { | 488 { |
487 ngx_fd_t fd; | 489 ngx_fd_t fd; |
490 ngx_err_t err; | |
488 ngx_file_info_t fi, atfi; | 491 ngx_file_info_t fi, atfi; |
489 | 492 |
490 /* | 493 /* |
491 * To allow symlinks with the same owner, use openat() (followed | 494 * To allow symlinks with the same owner, use openat() (followed |
492 * by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare | 495 * by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare |
506 } | 509 } |
507 | 510 |
508 if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW) | 511 if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW) |
509 == NGX_FILE_ERROR) | 512 == NGX_FILE_ERROR) |
510 { | 513 { |
511 ngx_close_file(fd); | 514 err = ngx_errno; |
512 return NGX_FILE_ERROR; | 515 goto failed; |
513 } | 516 } |
514 | 517 |
515 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | 518 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { |
516 ngx_close_file(fd); | 519 err = ngx_errno; |
517 return NGX_FILE_ERROR; | 520 goto failed; |
518 } | 521 } |
519 | 522 |
520 if (fi.st_uid != atfi.st_uid) { | 523 if (fi.st_uid != atfi.st_uid) { |
521 ngx_close_file(fd); | 524 err = NGX_ELOOP; |
522 ngx_set_errno(NGX_ELOOP); | 525 goto failed; |
523 return NGX_FILE_ERROR; | |
524 } | 526 } |
525 | 527 |
526 return fd; | 528 return fd; |
529 | |
530 failed: | |
531 | |
532 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
533 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
534 ngx_close_file_n " \"%V\" failed", name); | |
535 } | |
536 | |
537 ngx_set_errno(err); | |
538 | |
539 return NGX_INVALID_FILE; | |
527 } | 540 } |
528 | 541 |
529 #endif | 542 #endif |
530 | 543 |
531 | 544 |
532 static ngx_fd_t | 545 static ngx_fd_t |
533 ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, | 546 ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, |
534 ngx_int_t mode, ngx_int_t create, ngx_int_t access) | 547 ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) |
535 { | 548 { |
536 ngx_fd_t fd; | 549 ngx_fd_t fd; |
537 | 550 |
538 #if !(NGX_HAVE_OPENAT) | 551 #if !(NGX_HAVE_OPENAT) |
539 | 552 |
540 fd = ngx_open_file(name->data, mode, create, access); | 553 fd = ngx_open_file(name->data, mode, create, access); |
541 | 554 |
542 if (fd == NGX_FILE_ERROR) { | 555 if (fd == NGX_INVALID_FILE) { |
543 of->err = ngx_errno; | 556 of->err = ngx_errno; |
544 of->failed = ngx_open_file_n; | 557 of->failed = ngx_open_file_n; |
545 return NGX_FILE_ERROR; | 558 return NGX_INVALID_FILE; |
546 } | 559 } |
547 | 560 |
548 return fd; | 561 return fd; |
549 | 562 |
550 #else | 563 #else |
551 | 564 |
552 u_char *p, *cp, *end; | 565 u_char *p, *cp, *end; |
553 ngx_fd_t at_fd; | 566 ngx_fd_t at_fd; |
567 ngx_str_t at_name; | |
554 | 568 |
555 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { | 569 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { |
556 fd = ngx_open_file(name->data, mode, create, access); | 570 fd = ngx_open_file(name->data, mode, create, access); |
557 | 571 |
558 if (fd == NGX_FILE_ERROR) { | 572 if (fd == NGX_INVALID_FILE) { |
559 of->err = ngx_errno; | 573 of->err = ngx_errno; |
560 of->failed = ngx_open_file_n; | 574 of->failed = ngx_open_file_n; |
561 return NGX_FILE_ERROR; | 575 return NGX_INVALID_FILE; |
562 } | 576 } |
563 | 577 |
564 return fd; | 578 return fd; |
565 } | 579 } |
566 | 580 |
567 at_fd = ngx_openat_file(AT_FDCWD, "/", NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, | 581 at_fd = ngx_openat_file(AT_FDCWD, "/", NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, |
568 NGX_FILE_OPEN, 0); | 582 NGX_FILE_OPEN, 0); |
569 | 583 |
570 if (at_fd == NGX_FILE_ERROR) { | 584 if (at_fd == NGX_INVALID_FILE) { |
571 of->err = ngx_errno; | 585 of->err = ngx_errno; |
572 of->failed = ngx_openat_file_n; | 586 of->failed = ngx_openat_file_n; |
573 return NGX_FILE_ERROR; | 587 return NGX_INVALID_FILE; |
574 } | 588 } |
589 | |
590 at_name = *name; | |
591 at_name.len = 1; | |
575 | 592 |
576 end = name->data + name->len; | 593 end = name->data + name->len; |
577 p = name->data + 1; | 594 p = name->data + 1; |
578 | 595 |
579 for ( ;; ) { | 596 for ( ;; ) { |
585 *cp = '\0'; | 602 *cp = '\0'; |
586 | 603 |
587 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { | 604 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { |
588 fd = ngx_openat_file_owner(at_fd, p, | 605 fd = ngx_openat_file_owner(at_fd, p, |
589 NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, | 606 NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, |
590 NGX_FILE_OPEN, 0); | 607 NGX_FILE_OPEN, 0, log); |
591 | 608 |
592 } else { | 609 } else { |
593 fd = ngx_openat_file(at_fd, p, | 610 fd = ngx_openat_file(at_fd, p, |
594 NGX_FILE_RDONLY|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW, | 611 NGX_FILE_RDONLY|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW, |
595 NGX_FILE_OPEN, 0); | 612 NGX_FILE_OPEN, 0); |
596 } | 613 } |
597 | 614 |
598 *cp = '/'; | 615 *cp = '/'; |
599 | 616 |
600 ngx_close_file(at_fd); | 617 if (fd == NGX_INVALID_FILE) { |
601 | |
602 if (fd == NGX_FILE_ERROR) { | |
603 of->err = ngx_errno; | 618 of->err = ngx_errno; |
604 of->failed = ngx_openat_file_n; | 619 of->failed = ngx_openat_file_n; |
605 return NGX_FILE_ERROR; | 620 goto failed; |
621 } | |
622 | |
623 if (at_fd != AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { | |
624 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
625 ngx_close_file_n " \"%V\" failed", at_name); | |
606 } | 626 } |
607 | 627 |
608 p = cp + 1; | 628 p = cp + 1; |
609 at_fd = fd; | 629 at_fd = fd; |
630 at_name.len = cp - at_name.data; | |
610 } | 631 } |
611 | 632 |
612 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { | 633 if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { |
613 fd = ngx_openat_file_owner(at_fd, p, mode, create, access); | 634 fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log); |
614 | 635 |
615 } else { | 636 } else { |
616 fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access); | 637 fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access); |
617 } | 638 } |
618 | 639 |
619 if (fd == NGX_FILE_ERROR) { | 640 if (fd == NGX_INVALID_FILE) { |
620 of->err = ngx_errno; | 641 of->err = ngx_errno; |
621 of->failed = ngx_openat_file_n; | 642 of->failed = ngx_openat_file_n; |
622 } | 643 } |
623 | 644 |
624 ngx_close_file(at_fd); | 645 failed: |
646 | |
647 if (at_fd != AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { | |
648 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | |
649 ngx_close_file_n " \"%V\" failed", at_name); | |
650 } | |
625 | 651 |
626 return fd; | 652 return fd; |
627 #endif | 653 #endif |
628 } | 654 } |
629 | 655 |
630 | 656 |
631 static ngx_int_t | 657 static ngx_int_t |
632 ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, | 658 ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, |
633 ngx_file_info_t *fi) | 659 ngx_file_info_t *fi, ngx_log_t *log) |
634 { | 660 { |
635 ngx_int_t rc; | 661 ngx_int_t rc; |
636 | 662 |
637 #if !(NGX_HAVE_OPENAT) | 663 #if !(NGX_HAVE_OPENAT) |
638 | 664 |
662 | 688 |
663 return rc; | 689 return rc; |
664 } | 690 } |
665 | 691 |
666 fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, | 692 fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, |
667 NGX_FILE_OPEN, 0); | 693 NGX_FILE_OPEN, 0, log); |
668 | 694 |
669 if (fd == NGX_FILE_ERROR) { | 695 if (fd == NGX_INVALID_FILE) { |
670 return NGX_FILE_ERROR; | 696 return NGX_FILE_ERROR; |
671 } | 697 } |
672 | 698 |
673 if (ngx_fd_info(fd, fi) == NGX_FILE_ERROR) { | 699 rc = ngx_fd_info(fd, fi); |
700 | |
701 if (rc == NGX_FILE_ERROR) { | |
674 of->err = ngx_errno; | 702 of->err = ngx_errno; |
675 of->failed = ngx_fd_info_n; | 703 of->failed = ngx_fd_info_n; |
676 ngx_close_file(fd); | 704 } |
677 return NGX_FILE_ERROR; | 705 |
678 } | 706 if (ngx_close_file(fd) == NGX_FILE_ERROR) { |
679 | 707 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, |
680 ngx_close_file(fd); | 708 ngx_close_file_n " \"%V\" failed", name); |
681 | 709 } |
682 return NGX_OK; | 710 |
711 return rc; | |
683 #endif | 712 #endif |
684 } | 713 } |
685 | 714 |
686 | 715 |
687 static ngx_int_t | 716 static ngx_int_t |
691 ngx_fd_t fd; | 720 ngx_fd_t fd; |
692 ngx_file_info_t fi; | 721 ngx_file_info_t fi; |
693 | 722 |
694 if (of->fd != NGX_INVALID_FILE) { | 723 if (of->fd != NGX_INVALID_FILE) { |
695 | 724 |
696 if (ngx_file_info_wrapper(name, of, &fi) == NGX_FILE_ERROR) { | 725 if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { |
697 of->fd = NGX_INVALID_FILE; | 726 of->fd = NGX_INVALID_FILE; |
698 return NGX_ERROR; | 727 return NGX_ERROR; |
699 } | 728 } |
700 | 729 |
701 if (of->uniq == ngx_file_uniq(&fi)) { | 730 if (of->uniq == ngx_file_uniq(&fi)) { |
702 goto done; | 731 goto done; |
703 } | 732 } |
704 | 733 |
705 } else if (of->test_dir) { | 734 } else if (of->test_dir) { |
706 | 735 |
707 if (ngx_file_info_wrapper(name, of, &fi) == NGX_FILE_ERROR) { | 736 if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { |
708 of->fd = NGX_INVALID_FILE; | 737 of->fd = NGX_INVALID_FILE; |
709 return NGX_ERROR; | 738 return NGX_ERROR; |
710 } | 739 } |
711 | 740 |
712 if (ngx_is_dir(&fi)) { | 741 if (ngx_is_dir(&fi)) { |
720 * Use non-blocking open() not to hang on FIFO files, etc. | 749 * Use non-blocking open() not to hang on FIFO files, etc. |
721 * This flag has no effect on a regular files. | 750 * This flag has no effect on a regular files. |
722 */ | 751 */ |
723 | 752 |
724 fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, | 753 fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, |
725 NGX_FILE_OPEN, 0); | 754 NGX_FILE_OPEN, 0, log); |
726 | 755 |
727 } else { | 756 } else { |
728 fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND, | 757 fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND, |
729 NGX_FILE_CREATE_OR_OPEN, | 758 NGX_FILE_CREATE_OR_OPEN, |
730 NGX_FILE_DEFAULT_ACCESS); | 759 NGX_FILE_DEFAULT_ACCESS, log); |
731 } | 760 } |
732 | 761 |
733 if (fd == NGX_INVALID_FILE) { | 762 if (fd == NGX_INVALID_FILE) { |
734 of->fd = NGX_INVALID_FILE; | 763 of->fd = NGX_INVALID_FILE; |
735 return NGX_ERROR; | 764 return NGX_ERROR; |