diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-04-09 14:11:45 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-04-09 14:11:45 +0200 |
commit | e69ad87802139b7b62fc06ff5d5d09cc4245d5fc (patch) | |
tree | 5140bc5e536c722f9aa5a0896a7229cf9b2148b0 | |
parent | 02365a6ef73defb8689d3ed5228125d72993dec9 (diff) | |
download | busybox-w32-e69ad87802139b7b62fc06ff5d5d09cc4245d5fc.tar.gz busybox-w32-e69ad87802139b7b62fc06ff5d5d09cc4245d5fc.tar.bz2 busybox-w32-e69ad87802139b7b62fc06ff5d5d09cc4245d5fc.zip |
tar: fix "hardlinks to symlinks chown" bug 1519.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/libunarchive/data_extract_all.c | 102 | ||||
-rw-r--r-- | archival/libunarchive/header_verbose_list.c | 1 | ||||
-rwxr-xr-x | testsuite/tar.tests | 29 |
3 files changed, 82 insertions, 50 deletions
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c index de2367ac2..815261036 100644 --- a/archival/libunarchive/data_extract_all.c +++ b/archival/libunarchive/data_extract_all.c | |||
@@ -96,58 +96,60 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
96 | file_header->name, | 96 | file_header->name, |
97 | file_header->link_target); | 97 | file_header->link_target); |
98 | } | 98 | } |
99 | } else { | 99 | /* Hardlinks have no separate mode/ownership, skip chown/chmod */ |
100 | /* Create the filesystem entry */ | 100 | goto ret; |
101 | switch (file_header->mode & S_IFMT) { | 101 | } |
102 | case S_IFREG: { | 102 | |
103 | /* Regular file */ | 103 | /* Create the filesystem entry */ |
104 | int flags = O_WRONLY | O_CREAT | O_EXCL; | 104 | switch (file_header->mode & S_IFMT) { |
105 | if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) | 105 | case S_IFREG: { |
106 | flags = O_WRONLY | O_CREAT | O_TRUNC; | 106 | /* Regular file */ |
107 | dst_fd = xopen3(file_header->name, | 107 | int flags = O_WRONLY | O_CREAT | O_EXCL; |
108 | flags, | 108 | if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) |
109 | file_header->mode | 109 | flags = O_WRONLY | O_CREAT | O_TRUNC; |
110 | ); | 110 | dst_fd = xopen3(file_header->name, |
111 | bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); | 111 | flags, |
112 | close(dst_fd); | 112 | file_header->mode |
113 | break; | 113 | ); |
114 | bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); | ||
115 | close(dst_fd); | ||
116 | break; | ||
117 | } | ||
118 | case S_IFDIR: | ||
119 | res = mkdir(file_header->name, file_header->mode); | ||
120 | if ((res == -1) | ||
121 | && (errno != EISDIR) /* btw, Linux doesn't return this */ | ||
122 | && (errno != EEXIST) | ||
123 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | ||
124 | ) { | ||
125 | bb_perror_msg("can't make dir %s", file_header->name); | ||
114 | } | 126 | } |
115 | case S_IFDIR: | 127 | break; |
116 | res = mkdir(file_header->name, file_header->mode); | 128 | case S_IFLNK: |
117 | if ((res == -1) | 129 | /* Symlink */ |
118 | && (errno != EISDIR) /* btw, Linux doesn't return this */ | 130 | res = symlink(file_header->link_target, file_header->name); |
119 | && (errno != EEXIST) | 131 | if ((res == -1) |
120 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | 132 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
121 | ) { | 133 | ) { |
122 | bb_perror_msg("can't make dir %s", file_header->name); | 134 | bb_perror_msg("can't create %slink " |
123 | } | 135 | "from %s to %s", "sym", |
124 | break; | 136 | file_header->name, |
125 | case S_IFLNK: | 137 | file_header->link_target); |
126 | /* Symlink */ | 138 | } |
127 | res = symlink(file_header->link_target, file_header->name); | 139 | break; |
128 | if ((res == -1) | 140 | case S_IFSOCK: |
129 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | 141 | case S_IFBLK: |
130 | ) { | 142 | case S_IFCHR: |
131 | bb_perror_msg("can't create %slink " | 143 | case S_IFIFO: |
132 | "from %s to %s", "sym", | 144 | res = mknod(file_header->name, file_header->mode, file_header->device); |
133 | file_header->name, | 145 | if ((res == -1) |
134 | file_header->link_target); | 146 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) |
135 | } | 147 | ) { |
136 | break; | 148 | bb_perror_msg("can't create node %s", file_header->name); |
137 | case S_IFSOCK: | ||
138 | case S_IFBLK: | ||
139 | case S_IFCHR: | ||
140 | case S_IFIFO: | ||
141 | res = mknod(file_header->name, file_header->mode, file_header->device); | ||
142 | if ((res == -1) | ||
143 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | ||
144 | ) { | ||
145 | bb_perror_msg("can't create node %s", file_header->name); | ||
146 | } | ||
147 | break; | ||
148 | default: | ||
149 | bb_error_msg_and_die("unrecognized file type"); | ||
150 | } | 149 | } |
150 | break; | ||
151 | default: | ||
152 | bb_error_msg_and_die("unrecognized file type"); | ||
151 | } | 153 | } |
152 | 154 | ||
153 | if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { | 155 | if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { |
diff --git a/archival/libunarchive/header_verbose_list.c b/archival/libunarchive/header_verbose_list.c index f6f04cfd5..3319e63a9 100644 --- a/archival/libunarchive/header_verbose_list.c +++ b/archival/libunarchive/header_verbose_list.c | |||
@@ -61,6 +61,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) | |||
61 | 61 | ||
62 | #endif /* FEATURE_TAR_UNAME_GNAME */ | 62 | #endif /* FEATURE_TAR_UNAME_GNAME */ |
63 | 63 | ||
64 | /* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */ | ||
64 | if (file_header->link_target) { | 65 | if (file_header->link_target) { |
65 | printf(" -> %s", file_header->link_target); | 66 | printf(" -> %s", file_header->link_target); |
66 | } | 67 | } |
diff --git a/testsuite/tar.tests b/testsuite/tar.tests index dd8f11062..a96382932 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests | |||
@@ -69,6 +69,35 @@ dr-xr-x--- input_dir | |||
69 | " \ | 69 | " \ |
70 | "" "" | 70 | "" "" |
71 | 71 | ||
72 | testing "tar symlinks mode" '\ | ||
73 | rm -rf input_* test.tar 2>/dev/null | ||
74 | >input_file | ||
75 | chmod 741 input_file | ||
76 | ln -s input_file input_soft | ||
77 | mkdir input_dir | ||
78 | chmod 550 input_dir | ||
79 | ln input_file input_dir | ||
80 | ln input_soft input_dir | ||
81 | tar cf test.tar input_* | ||
82 | tar tvf test.tar | sed "s/.*[0-9] input/input/" | ||
83 | tar xf test.tar 2>&1 | ||
84 | echo Ok: $? | ||
85 | ls -l . input_dir/* | grep input_ | sed "s/\\(^[^ ]*\\) .* input/\\1 input/" | ||
86 | ' "\ | ||
87 | input_dir/ | ||
88 | input_dir/input_file | ||
89 | input_dir/input_soft -> input_file | ||
90 | input_file -> input_dir/input_file | ||
91 | input_soft -> input_dir/input_soft | ||
92 | Ok: 0 | ||
93 | -rwxr----x input_dir/input_file | ||
94 | lrwxrwxrwx input_file | ||
95 | dr-xr-x--- input_dir | ||
96 | -rwxr----x input_file | ||
97 | lrwxrwxrwx input_file | ||
98 | " \ | ||
99 | "" "" | ||
100 | |||
72 | optional FEATURE_TAR_LONG_OPTIONS | 101 | optional FEATURE_TAR_LONG_OPTIONS |
73 | testing "tar --overwrite" "\ | 102 | testing "tar --overwrite" "\ |
74 | rm -rf input_* test.tar 2>/dev/null | 103 | rm -rf input_* test.tar 2>/dev/null |