Mercurial > hg > nginx
comparison src/core/ngx_file.c @ 3248:8c76116820f3 stable-0.7
merge r3024, r3025, r3028, r3033, r3034, r3035, r3036:
allow cross device temporary files atomic copying
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 26 Oct 2009 17:32:17 +0000 |
parents | 1f3cd08ebb82 |
children | d65ba5392f59 |
comparison
equal
deleted
inserted
replaced
3247:1f3cd08ebb82 | 3248:8c76116820f3 |
---|---|
6 | 6 |
7 #include <ngx_config.h> | 7 #include <ngx_config.h> |
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 | 9 |
10 | 10 |
11 static ngx_atomic_uint_t ngx_temp_number; | 11 static ngx_atomic_t temp_number = 0; |
12 static ngx_atomic_uint_t ngx_random_number; | 12 ngx_atomic_t *ngx_temp_number = &temp_number; |
13 ngx_atomic_int_t ngx_random_number = 123456; | |
13 | 14 |
14 | 15 |
15 ssize_t | 16 ssize_t |
16 ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) | 17 ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) |
17 { | 18 { |
97 if (err == NGX_EEXIST) { | 98 if (err == NGX_EEXIST) { |
98 n = (uint32_t) ngx_next_temp_number(1); | 99 n = (uint32_t) ngx_next_temp_number(1); |
99 continue; | 100 continue; |
100 } | 101 } |
101 | 102 |
102 if ((path->level[0] == 0) | 103 if ((path->level[0] == 0) || (err != NGX_ENOPATH)) { |
103 || (err != NGX_ENOENT | |
104 #if (NGX_WIN32) | |
105 && err != NGX_ENOTDIR | |
106 #endif | |
107 )) | |
108 { | |
109 ngx_log_error(NGX_LOG_CRIT, file->log, err, | 104 ngx_log_error(NGX_LOG_CRIT, file->log, err, |
110 ngx_open_tempfile_n " \"%s\" failed", | 105 ngx_open_tempfile_n " \"%s\" failed", |
111 file->name.data); | 106 file->name.data); |
112 return NGX_ERROR; | 107 return NGX_ERROR; |
113 } | 108 } |
209 | 204 |
210 return 0; | 205 return 0; |
211 } | 206 } |
212 | 207 |
213 | 208 |
214 void | |
215 ngx_init_temp_number(void) | |
216 { | |
217 ngx_temp_number = 0; | |
218 ngx_random_number = 123456; | |
219 } | |
220 | |
221 | |
222 ngx_atomic_uint_t | 209 ngx_atomic_uint_t |
223 ngx_next_temp_number(ngx_uint_t collision) | 210 ngx_next_temp_number(ngx_uint_t collision) |
224 { | 211 { |
225 if (collision) { | 212 ngx_atomic_uint_t n, add; |
226 ngx_temp_number += ngx_random_number; | 213 |
227 } | 214 add = collision ? ngx_random_number : 1; |
228 | 215 |
229 return ngx_temp_number++; | 216 n = ngx_atomic_fetch_add(ngx_temp_number, add); |
217 | |
218 return n + add; | |
230 } | 219 } |
231 | 220 |
232 | 221 |
233 char * | 222 char * |
234 ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 223 ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
528 | 517 |
529 | 518 |
530 ngx_int_t | 519 ngx_int_t |
531 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) | 520 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) |
532 { | 521 { |
533 ngx_err_t err; | 522 u_char *name; |
523 ngx_err_t err; | |
524 ngx_copy_file_t cf; | |
534 | 525 |
535 #if !(NGX_WIN32) | 526 #if !(NGX_WIN32) |
536 | 527 |
537 if (ext->access) { | 528 if (ext->access) { |
538 if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) { | 529 if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) { |
558 return NGX_OK; | 549 return NGX_OK; |
559 } | 550 } |
560 | 551 |
561 err = ngx_errno; | 552 err = ngx_errno; |
562 | 553 |
563 if (err | 554 if (err == NGX_ENOPATH) { |
564 #if (NGX_WIN32) | 555 |
565 == ERROR_PATH_NOT_FOUND | |
566 #else | |
567 == NGX_ENOENT | |
568 #endif | |
569 ) | |
570 { | |
571 if (!ext->create_path) { | 556 if (!ext->create_path) { |
572 goto failed; | 557 goto failed; |
573 } | 558 } |
574 | 559 |
575 err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access)); | 560 err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access)); |
584 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { | 569 if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { |
585 return NGX_OK; | 570 return NGX_OK; |
586 } | 571 } |
587 | 572 |
588 err = ngx_errno; | 573 err = ngx_errno; |
589 goto failed; | |
590 } | 574 } |
591 | 575 |
592 #if (NGX_WIN32) | 576 #if (NGX_WIN32) |
593 | 577 |
594 if (err == NGX_EEXIST) { | 578 if (err == NGX_EEXIST) { |
604 err = 0; | 588 err = 0; |
605 } | 589 } |
606 } | 590 } |
607 | 591 |
608 #endif | 592 #endif |
593 | |
594 if (err == NGX_EXDEV) { | |
595 | |
596 cf.size = -1; | |
597 cf.buf_size = 0; | |
598 cf.access = ext->access; | |
599 cf.time = ext->time; | |
600 cf.log = ext->log; | |
601 | |
602 name = ngx_alloc(to->len + 1 + 10 + 1, ext->log); | |
603 if (name == NULL) { | |
604 return NGX_ERROR; | |
605 } | |
606 | |
607 (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data, | |
608 (uint32_t) ngx_next_temp_number(0)); | |
609 | |
610 if (ngx_copy_file(src->data, name, &cf) == NGX_OK) { | |
611 | |
612 if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) { | |
613 ngx_free(name); | |
614 | |
615 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { | |
616 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, | |
617 ngx_delete_file_n " \"%s\" failed", | |
618 src->data); | |
619 return NGX_ERROR; | |
620 } | |
621 | |
622 return NGX_OK; | |
623 } | |
624 | |
625 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, | |
626 ngx_rename_file_n " \"%s\" to \"%s\" failed", | |
627 name, to->data); | |
628 | |
629 if (ngx_delete_file(name) == NGX_FILE_ERROR) { | |
630 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, | |
631 ngx_delete_file_n " \"%s\" failed", name); | |
632 | |
633 } | |
634 } | |
635 | |
636 ngx_free(name); | |
637 | |
638 err = 0; | |
639 } | |
609 | 640 |
610 failed: | 641 failed: |
611 | 642 |
612 if (ext->delete_file) { | 643 if (ext->delete_file) { |
613 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { | 644 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { |
614 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, | 645 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, |
615 ngx_delete_file_n " \"%s\" failed", src->data); | 646 ngx_delete_file_n " \"%s\" failed", src->data); |
616 } | 647 } |
617 } | 648 } |
618 | 649 |
619 if (err && ext->log_rename_error) { | 650 if (err) { |
620 ngx_log_error(NGX_LOG_CRIT, ext->log, err, | 651 ngx_log_error(NGX_LOG_CRIT, ext->log, err, |
621 ngx_rename_file_n " \"%s\" to \"%s\" failed", | 652 ngx_rename_file_n " \"%s\" to \"%s\" failed", |
622 src->data, to->data); | 653 src->data, to->data); |
623 } | 654 } |
624 | 655 |
625 ext->rename_error = err; | |
626 | |
627 return NGX_ERROR; | 656 return NGX_ERROR; |
657 } | |
658 | |
659 | |
660 ngx_int_t | |
661 ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) | |
662 { | |
663 char *buf; | |
664 off_t size; | |
665 size_t len; | |
666 ssize_t n; | |
667 ngx_fd_t fd, nfd; | |
668 ngx_int_t rc; | |
669 ngx_file_info_t fi; | |
670 | |
671 rc = NGX_ERROR; | |
672 buf = NULL; | |
673 nfd = NGX_INVALID_FILE; | |
674 | |
675 fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); | |
676 | |
677 if (fd == NGX_INVALID_FILE) { | |
678 ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, | |
679 ngx_open_file_n " \"%s\" failed", from); | |
680 goto failed; | |
681 } | |
682 | |
683 if (cf->size != -1) { | |
684 size = cf->size; | |
685 | |
686 } else { | |
687 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { | |
688 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
689 ngx_fd_info_n " \"%s\" failed", from); | |
690 | |
691 goto failed; | |
692 } | |
693 | |
694 size = ngx_file_size(&fi); | |
695 } | |
696 | |
697 len = cf->buf_size ? cf->buf_size : 65536; | |
698 | |
699 if ((off_t) len > size) { | |
700 len = (size_t) size; | |
701 } | |
702 | |
703 buf = ngx_alloc(len, cf->log); | |
704 if (buf == NULL) { | |
705 goto failed; | |
706 } | |
707 | |
708 nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, | |
709 cf->access); | |
710 | |
711 if (nfd == NGX_INVALID_FILE) { | |
712 ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, | |
713 ngx_open_file_n " \"%s\" failed", to); | |
714 goto failed; | |
715 } | |
716 | |
717 while (size > 0) { | |
718 | |
719 if ((off_t) len > size) { | |
720 len = (size_t) size; | |
721 } | |
722 | |
723 n = ngx_read_fd(fd, buf, len); | |
724 | |
725 if (n == NGX_FILE_ERROR) { | |
726 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
727 ngx_read_fd_n " \"%s\" failed", from); | |
728 goto failed; | |
729 } | |
730 | |
731 if ((size_t) n != len) { | |
732 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
733 ngx_read_fd_n " has read only %z of %uz from %s", | |
734 n, size, from); | |
735 goto failed; | |
736 } | |
737 | |
738 n = ngx_write_fd(nfd, buf, len); | |
739 | |
740 if (n == NGX_FILE_ERROR) { | |
741 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
742 ngx_write_fd_n " \"%s\" failed", to); | |
743 goto failed; | |
744 } | |
745 | |
746 if ((size_t) n != len) { | |
747 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
748 ngx_write_fd_n " has written only %z of %uz to %s", | |
749 n, size, to); | |
750 goto failed; | |
751 } | |
752 | |
753 size -= n; | |
754 } | |
755 | |
756 if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { | |
757 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
758 ngx_set_file_time_n " \"%s\" failed", to); | |
759 goto failed; | |
760 } | |
761 | |
762 rc = NGX_OK; | |
763 | |
764 failed: | |
765 | |
766 if (nfd != NGX_INVALID_FILE) { | |
767 if (ngx_close_file(nfd) == NGX_FILE_ERROR) { | |
768 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
769 ngx_close_file_n " \"%s\" failed", to); | |
770 } | |
771 } | |
772 | |
773 if (fd != NGX_INVALID_FILE) { | |
774 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
775 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
776 ngx_close_file_n " \"%s\" failed", from); | |
777 } | |
778 } | |
779 | |
780 if (buf) { | |
781 ngx_free(buf); | |
782 } | |
783 | |
784 return rc; | |
628 } | 785 } |
629 | 786 |
630 | 787 |
631 /* | 788 /* |
632 * ctx->init_handler() - see ctx->alloc | 789 * ctx->init_handler() - see ctx->alloc |