comparison src/core/ngx_file.c @ 3024:8101d9101ed8

allow cross device temporary files atomic copying: *) ngx_copy_file() *) delete ngx_ext_rename_file_t.log_rename_error and .rename_error fields
author Igor Sysoev <igor@sysoev.ru>
date Wed, 12 Aug 2009 12:05:33 +0000
parents 7d5501988fe3
children 3e1b653fd22f
comparison
equal deleted inserted replaced
3023:7d5501988fe3 3024:8101d9101ed8
522 522
523 523
524 ngx_int_t 524 ngx_int_t
525 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) 525 ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext)
526 { 526 {
527 ngx_err_t err; 527 u_char *name;
528 ngx_err_t err;
529 ngx_copy_file_t cf;
528 530
529 #if !(NGX_WIN32) 531 #if !(NGX_WIN32)
530 532
531 if (ext->access) { 533 if (ext->access) {
532 if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) { 534 if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) {
593 } 595 }
594 } 596 }
595 597
596 #endif 598 #endif
597 599
600 if (err == NGX_EXDEV) {
601
602 cf.size = -1;
603 cf.buf_size = 0;
604 cf.access = ext->access;
605 cf.time = ext->time;
606 cf.log = ext->log;
607
608 name = ngx_alloc(to->len + 1 + 10, ext->log);
609 if (name == NULL) {
610 return NGX_ERROR;
611 }
612
613 (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len - 1, to->data,
614 (uint32_t) ngx_next_temp_number(0));
615
616 if (ngx_copy_file(src->data, name, &cf) == NGX_OK) {
617
618 if (ngx_rename_file(name, to->data) == NGX_FILE_ERROR) {
619 ngx_free(name);
620 goto failed;
621 }
622
623 ngx_free(name);
624
625 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
626 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
627 ngx_delete_file_n " \"%s\" failed", src->data);
628
629 return NGX_ERROR;
630 }
631
632 return NGX_OK;
633 }
634
635 ngx_free(name);
636 }
637
598 failed: 638 failed:
599 639
600 if (ext->delete_file) { 640 if (ext->delete_file) {
601 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { 641 if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
602 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, 642 ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
603 ngx_delete_file_n " \"%s\" failed", src->data); 643 ngx_delete_file_n " \"%s\" failed", src->data);
604 } 644 }
605 } 645 }
606 646
607 if (err && ext->log_rename_error) { 647 if (err) {
608 ngx_log_error(NGX_LOG_CRIT, ext->log, err, 648 ngx_log_error(NGX_LOG_CRIT, ext->log, err,
609 ngx_rename_file_n " \"%s\" to \"%s\" failed", 649 ngx_rename_file_n " \"%s\" to \"%s\" failed",
610 src->data, to->data); 650 src->data, to->data);
611 } 651 }
612 652
613 ext->rename_error = err;
614
615 return NGX_ERROR; 653 return NGX_ERROR;
654 }
655
656
657 ngx_int_t
658 ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf)
659 {
660 char *buf;
661 off_t size;
662 size_t len;
663 ssize_t n;
664 ngx_fd_t fd, nfd;
665 ngx_int_t rc;
666 ngx_file_info_t fi;
667
668 rc = NGX_ERROR;
669 buf = NULL;
670 nfd = NGX_INVALID_FILE;
671
672 fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
673
674 if (fd == NGX_INVALID_FILE) {
675 ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
676 ngx_open_file_n " \"%s\" failed", from);
677 goto failed;
678 }
679
680 if (cf->size != -1) {
681 size = cf->size;
682
683 } else {
684 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
685 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
686 ngx_fd_info_n " \"%s\" failed", from);
687
688 goto failed;
689 }
690
691 size = ngx_file_size(&fi);
692 }
693
694 len = cf->buf_size ? cf->buf_size : 65536;
695
696 if (len > size) {
697 len = (size_t) size;
698 }
699
700 buf = ngx_alloc(len, cf->log);
701 if (buf == NULL) {
702 goto failed;
703 }
704
705 nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
706 cf->access);
707
708 if (nfd == NGX_INVALID_FILE) {
709 ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno,
710 ngx_open_file_n " \"%s\" failed", to);
711 goto failed;
712 }
713
714 while (size > 0) {
715
716 if (len > size) {
717 len = (size_t) size;
718 }
719
720 n = ngx_read_fd(fd, buf, len);
721
722 if (n == NGX_FILE_ERROR) {
723 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
724 ngx_read_fd_n " \"%s\" failed", from);
725 goto failed;
726 }
727
728 if ((size_t) n != len) {
729 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
730 ngx_read_fd_n " has read only %z of %uz from %s",
731 n, size, from);
732 goto failed;
733 }
734
735 n = ngx_write_fd(nfd, buf, len);
736
737 if (n == NGX_FILE_ERROR) {
738 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
739 ngx_write_fd_n " \"%s\" failed", to);
740 goto failed;
741 }
742
743 if ((size_t) n != len) {
744 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
745 ngx_write_fd_n " has written only %z of %uz to %s",
746 n, size, to);
747 goto failed;
748 }
749
750 size -= n;
751 }
752
753 if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) {
754 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
755 ngx_set_file_time_n " \"%s\" failed", to);
756 goto failed;
757 }
758
759 rc = NGX_OK;
760
761 failed:
762
763 if (nfd != NGX_INVALID_FILE) {
764 if (ngx_close_file(nfd) == NGX_FILE_ERROR) {
765 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
766 ngx_close_file_n " \"%s\" failed", to);
767 }
768 }
769
770 if (fd != NGX_INVALID_FILE) {
771 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
772 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
773 ngx_close_file_n " \"%s\" failed", from);
774 }
775 }
776
777 if (buf) {
778 ngx_free(buf);
779 }
780
781 return rc;
616 } 782 }
617 783
618 784
619 /* 785 /*
620 * ctx->init_handler() - see ctx->alloc 786 * ctx->init_handler() - see ctx->alloc