OLD | NEW |
1 /////////////////////////////////////////////////////////////////////////////// | 1 /////////////////////////////////////////////////////////////////////////////// |
2 // | 2 // |
3 /// \file file_io.c | 3 /// \file file_io.c |
4 /// \brief File opening, unlinking, and closing | 4 /// \brief File opening, unlinking, and closing |
5 // | 5 // |
6 // Author: Lasse Collin | 6 // Author: Lasse Collin |
7 // | 7 // |
8 // This file has been put into the public domain. | 8 // This file has been put into the public domain. |
9 // You can do whatever you want with this file. | 9 // You can do whatever you want with this file. |
10 // | 10 // |
(...skipping 23 matching lines...) Expand all Loading... |
34 | 34 |
35 #ifndef O_NOCTTY | 35 #ifndef O_NOCTTY |
36 # define O_NOCTTY 0 | 36 # define O_NOCTTY 0 |
37 #endif | 37 #endif |
38 | 38 |
39 | 39 |
40 /// If true, try to create sparse files when decompressing. | 40 /// If true, try to create sparse files when decompressing. |
41 static bool try_sparse = true; | 41 static bool try_sparse = true; |
42 | 42 |
43 #ifndef TUKLIB_DOSLIKE | 43 #ifndef TUKLIB_DOSLIKE |
44 /// File status flags of standard output. This is used by io_open_dest() | 44 /// Original file status flags of standard output. This is used by |
45 /// and io_close_dest(). | 45 /// io_open_dest() and io_close_dest() to save and restore the flags. |
46 static int stdout_flags = 0; | 46 static int stdout_flags; |
| 47 static bool restore_stdout_flags = false; |
47 #endif | 48 #endif |
48 | 49 |
49 | 50 |
50 static bool io_write_buf(file_pair *pair, const uint8_t *buf, size_t size); | 51 static bool io_write_buf(file_pair *pair, const uint8_t *buf, size_t size); |
51 | 52 |
52 | 53 |
53 extern void | 54 extern void |
54 io_init(void) | 55 io_init(void) |
55 { | 56 { |
56 // Make sure that stdin, stdout, and stderr are connected to | 57 // Make sure that stdin, stdout, and stderr are connected to |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 | 391 |
391 # if defined(__FreeBSD__) || defined(__DragonFly__) | 392 # if defined(__FreeBSD__) || defined(__DragonFly__) |
392 if (errno == EMLINK) | 393 if (errno == EMLINK) |
393 was_symlink = true; | 394 was_symlink = true; |
394 | 395 |
395 # elif defined(__digital__) && defined(__unix__) | 396 # elif defined(__digital__) && defined(__unix__) |
396 if (errno == ENOTSUP) | 397 if (errno == ENOTSUP) |
397 was_symlink = true; | 398 was_symlink = true; |
398 | 399 |
399 # elif defined(__NetBSD__) | 400 # elif defined(__NetBSD__) |
400 // As of 2010-09-05, NetBSD doesn't document what errno is | |
401 // used with O_NOFOLLOW. It is EFTYPE though, and I | |
402 // understood that is very unlikely to change even though | |
403 // it is undocumented. | |
404 if (errno == EFTYPE) | 401 if (errno == EFTYPE) |
405 was_symlink = true; | 402 was_symlink = true; |
406 | 403 |
407 # else | 404 # else |
408 if (errno == ELOOP && !follow_symlinks) { | 405 if (errno == ELOOP && !follow_symlinks) { |
409 const int saved_errno = errno; | 406 const int saved_errno = errno; |
410 struct stat st; | 407 struct stat st; |
411 if (lstat(pair->src_name, &st) == 0 | 408 if (lstat(pair->src_name, &st) == 0 |
412 && S_ISLNK(st.st_mode)) | 409 && S_ISLNK(st.st_mode)) |
413 was_symlink = true; | 410 was_symlink = true; |
(...skipping 20 matching lines...) Expand all Loading... |
434 // Drop O_NONBLOCK, which is used only when we are accepting only | 431 // Drop O_NONBLOCK, which is used only when we are accepting only |
435 // regular files. After the open() call, we want things to block | 432 // regular files. After the open() call, we want things to block |
436 // instead of giving EAGAIN. | 433 // instead of giving EAGAIN. |
437 if (reg_files_only) { | 434 if (reg_files_only) { |
438 flags = fcntl(pair->src_fd, F_GETFL); | 435 flags = fcntl(pair->src_fd, F_GETFL); |
439 if (flags == -1) | 436 if (flags == -1) |
440 goto error_msg; | 437 goto error_msg; |
441 | 438 |
442 flags &= ~O_NONBLOCK; | 439 flags &= ~O_NONBLOCK; |
443 | 440 |
444 » » if (fcntl(pair->src_fd, F_SETFL, flags)) | 441 » » if (fcntl(pair->src_fd, F_SETFL, flags) == -1) |
445 goto error_msg; | 442 goto error_msg; |
446 } | 443 } |
447 #endif | 444 #endif |
448 | 445 |
449 // Stat the source file. We need the result also when we copy | 446 // Stat the source file. We need the result also when we copy |
450 // the permissions, and when unlinking. | 447 // the permissions, and when unlinking. |
451 if (fstat(pair->src_fd, &pair->src_st)) | 448 if (fstat(pair->src_fd, &pair->src_st)) |
452 goto error_msg; | 449 goto error_msg; |
453 | 450 |
454 if (S_ISDIR(pair->src_st.st_mode)) { | 451 if (S_ISDIR(pair->src_st.st_mode)) { |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 // - O_APPEND may be active. | 624 // - O_APPEND may be active. |
628 // | 625 // |
629 // TODO: I'm keeping this disabled for DOS-like systems | 626 // TODO: I'm keeping this disabled for DOS-like systems |
630 // for now. FAT doesn't support sparse files, but NTFS | 627 // for now. FAT doesn't support sparse files, but NTFS |
631 // does, so maybe this should be enabled on Windows after | 628 // does, so maybe this should be enabled on Windows after |
632 // some testing. | 629 // some testing. |
633 if (pair->dest_fd == STDOUT_FILENO) { | 630 if (pair->dest_fd == STDOUT_FILENO) { |
634 if (!S_ISREG(pair->dest_st.st_mode)) | 631 if (!S_ISREG(pair->dest_st.st_mode)) |
635 return false; | 632 return false; |
636 | 633 |
637 » » » const int flags = fcntl(STDOUT_FILENO, F_GETFL); | 634 » » » stdout_flags = fcntl(STDOUT_FILENO, F_GETFL); |
638 » » » if (flags == -1) | 635 » » » if (stdout_flags == -1) |
639 return false; | 636 return false; |
640 | 637 |
641 » » » if (flags & O_APPEND) { | 638 » » » if (stdout_flags & O_APPEND) { |
642 // Creating a sparse file is not possible | 639 // Creating a sparse file is not possible |
643 // when O_APPEND is active (it's used by | 640 // when O_APPEND is active (it's used by |
644 // shell's >> redirection). As I understand | 641 // shell's >> redirection). As I understand |
645 // it, it is safe to temporarily disable | 642 // it, it is safe to temporarily disable |
646 // O_APPEND in xz, because if someone | 643 // O_APPEND in xz, because if someone |
647 // happened to write to the same file at the | 644 // happened to write to the same file at the |
648 // same time, results would be bad anyway | 645 // same time, results would be bad anyway |
649 // (users shouldn't assume that xz uses any | 646 // (users shouldn't assume that xz uses any |
650 // specific block size when writing data). | 647 // specific block size when writing data). |
651 // | 648 // |
652 // The write position may be something else | 649 // The write position may be something else |
653 // than the end of the file, so we must fix | 650 // than the end of the file, so we must fix |
654 // it to start writing at the end of the file | 651 // it to start writing at the end of the file |
655 // to imitate O_APPEND. | 652 // to imitate O_APPEND. |
656 if (lseek(STDOUT_FILENO, 0, SEEK_END) == -1) | 653 if (lseek(STDOUT_FILENO, 0, SEEK_END) == -1) |
657 return false; | 654 return false; |
658 | 655 |
659 if (fcntl(STDOUT_FILENO, F_SETFL, | 656 if (fcntl(STDOUT_FILENO, F_SETFL, |
660 » » » » » » stdout_flags & ~O_APPEND)) | 657 » » » » » » stdout_flags & ~O_APPEND) |
| 658 » » » » » » == -1) |
661 return false; | 659 return false; |
662 | 660 |
663 » » » » // Remember the flags so that io_close_dest() | 661 » » » » // Disabling O_APPEND succeeded. Mark |
664 » » » » // can restore them. | 662 » » » » // that the flags should be restored |
665 » » » » stdout_flags = flags; | 663 » » » » // in io_close_dest(). |
| 664 » » » » restore_stdout_flags = true; |
666 | 665 |
667 } else if (lseek(STDOUT_FILENO, 0, SEEK_CUR) | 666 } else if (lseek(STDOUT_FILENO, 0, SEEK_CUR) |
668 != pair->dest_st.st_size) { | 667 != pair->dest_st.st_size) { |
669 // Writing won't start exactly at the end | 668 // Writing won't start exactly at the end |
670 // of the file. We cannot use sparse output, | 669 // of the file. We cannot use sparse output, |
671 // because it would probably corrupt the file. | 670 // because it would probably corrupt the file. |
672 return false; | 671 return false; |
673 } | 672 } |
674 } | 673 } |
675 | 674 |
(...skipping 20 matching lines...) Expand all Loading... |
696 /// \param pair File whose dest_fd should be closed | 695 /// \param pair File whose dest_fd should be closed |
697 /// \param success If false, the file will be removed from the disk. | 696 /// \param success If false, the file will be removed from the disk. |
698 /// | 697 /// |
699 /// \return Zero if closing succeeds. On error, -1 is returned and | 698 /// \return Zero if closing succeeds. On error, -1 is returned and |
700 /// error message printed. | 699 /// error message printed. |
701 static bool | 700 static bool |
702 io_close_dest(file_pair *pair, bool success) | 701 io_close_dest(file_pair *pair, bool success) |
703 { | 702 { |
704 #ifndef TUKLIB_DOSLIKE | 703 #ifndef TUKLIB_DOSLIKE |
705 // If io_open_dest() has disabled O_APPEND, restore it here. | 704 // If io_open_dest() has disabled O_APPEND, restore it here. |
706 » if (stdout_flags != 0) { | 705 » if (restore_stdout_flags) { |
707 assert(pair->dest_fd == STDOUT_FILENO); | 706 assert(pair->dest_fd == STDOUT_FILENO); |
708 | 707 |
709 » » const int fail = fcntl(STDOUT_FILENO, F_SETFL, stdout_flags); | 708 » » restore_stdout_flags = false; |
710 » » stdout_flags = 0; | |
711 | 709 |
712 » » if (fail) { | 710 » » if (fcntl(STDOUT_FILENO, F_SETFL, stdout_flags) == -1) { |
713 message_error(_("Error restoring the O_APPEND flag " | 711 message_error(_("Error restoring the O_APPEND flag " |
714 "to standard output: %s"), | 712 "to standard output: %s"), |
715 strerror(errno)); | 713 strerror(errno)); |
716 return true; | 714 return true; |
717 } | 715 } |
718 } | 716 } |
719 #endif | 717 #endif |
720 | 718 |
721 if (pair->dest_fd == -1 || pair->dest_fd == STDOUT_FILENO) | 719 if (pair->dest_fd == -1 || pair->dest_fd == STDOUT_FILENO) |
722 return false; | 720 return false; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
875 static bool | 873 static bool |
876 io_write_buf(file_pair *pair, const uint8_t *buf, size_t size) | 874 io_write_buf(file_pair *pair, const uint8_t *buf, size_t size) |
877 { | 875 { |
878 assert(size < SSIZE_MAX); | 876 assert(size < SSIZE_MAX); |
879 | 877 |
880 while (size > 0) { | 878 while (size > 0) { |
881 const ssize_t amount = write(pair->dest_fd, buf, size); | 879 const ssize_t amount = write(pair->dest_fd, buf, size); |
882 if (amount == -1) { | 880 if (amount == -1) { |
883 if (errno == EINTR) { | 881 if (errno == EINTR) { |
884 if (user_abort) | 882 if (user_abort) |
885 » » » » » return -1; | 883 » » » » » return true; |
886 | 884 |
887 continue; | 885 continue; |
888 } | 886 } |
889 | 887 |
890 // Handle broken pipe specially. gzip and bzip2 | 888 // Handle broken pipe specially. gzip and bzip2 |
891 // don't print anything on SIGPIPE. In addition, | 889 // don't print anything on SIGPIPE. In addition, |
892 // gzip --quiet uses exit status 2 (warning) on | 890 // gzip --quiet uses exit status 2 (warning) on |
893 // broken pipe instead of whatever raise(SIGPIPE) | 891 // broken pipe instead of whatever raise(SIGPIPE) |
894 // would make it return. It is there to hide "Broken | 892 // would make it return. It is there to hide "Broken |
895 // pipe" message on some old shells (probably old | 893 // pipe" message on some old shells (probably old |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
948 strerror(errno)); | 946 strerror(errno)); |
949 return true; | 947 return true; |
950 } | 948 } |
951 | 949 |
952 pair->dest_pending_sparse = 0; | 950 pair->dest_pending_sparse = 0; |
953 } | 951 } |
954 } | 952 } |
955 | 953 |
956 return io_write_buf(pair, buf->u8, size); | 954 return io_write_buf(pair, buf->u8, size); |
957 } | 955 } |
OLD | NEW |