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;