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