aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-04-05 02:44:30 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-04-05 02:44:30 +0000
commit1af00eda92e9a036ff217b11ff45ebe559de66f9 (patch)
tree67472bb3e4eddce347cfe7fa753c24f07faa5c4a
parent1a95e3960ca7dde16bda26ec9dad986199bae3c3 (diff)
downloadbusybox-w32-1af00eda92e9a036ff217b11ff45ebe559de66f9.tar.gz
busybox-w32-1af00eda92e9a036ff217b11ff45ebe559de66f9.tar.bz2
busybox-w32-1af00eda92e9a036ff217b11ff45ebe559de66f9.zip
cpio: fix a bug where we do not extract zero-sized hardlinks
(spotted at http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=466771). Add testsuite entry for that, and another one for another bug: we do not list hardlinks in cpio -t (not fixed). function old new delta get_header_cpio 884 909 +25 static.saved_hardlinks_created - 4 +4 static.pending_hardlinks 4 - -4 static.inode 4 - -4 cpio_main 1122 1060 -62
-rw-r--r--TODO_config_nommu1
-rw-r--r--archival/Config.in7
-rw-r--r--archival/cpio.c4
-rw-r--r--archival/libunarchive/data_extract_all.c2
-rw-r--r--archival/libunarchive/get_header_cpio.c183
-rw-r--r--archival/libunarchive/seek_by_jump.c6
-rw-r--r--scripts/defconfig1
7 files changed, 99 insertions, 105 deletions
diff --git a/TODO_config_nommu b/TODO_config_nommu
index 42d17314a..7fdec69bd 100644
--- a/TODO_config_nommu
+++ b/TODO_config_nommu
@@ -130,7 +130,6 @@ CONFIG_UNZIP=y
130# 130#
131# Common options for cpio and tar 131# Common options for cpio and tar
132# 132#
133CONFIG_FEATURE_UNARCHIVE_TAPE=y
134 133
135# 134#
136# Common options for dpkg and dpkg_deb 135# Common options for dpkg and dpkg_deb
diff --git a/archival/Config.in b/archival/Config.in
index 28450612e..35ac40bb7 100644
--- a/archival/Config.in
+++ b/archival/Config.in
@@ -307,13 +307,6 @@ config UNZIP
307comment "Common options for cpio and tar" 307comment "Common options for cpio and tar"
308 depends on CPIO || TAR 308 depends on CPIO || TAR
309 309
310config FEATURE_UNARCHIVE_TAPE
311 bool "Enable tape drive support"
312 default n
313 depends on CPIO || TAR
314 help
315 I don't think this is needed anymore.
316
317comment "Common options for dpkg and dpkg_deb" 310comment "Common options for dpkg and dpkg_deb"
318 depends on DPKG || DPKG_DEB 311 depends on DPKG || DPKG_DEB
319 312
diff --git a/archival/cpio.c b/archival/cpio.c
index dd9ed756c..2919ff8de 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -171,9 +171,7 @@ static int cpio_o(void)
171 int fd = xopen(name, O_RDONLY); 171 int fd = xopen(name, O_RDONLY);
172 fflush(stdout); 172 fflush(stdout);
173 /* We must abort if file got shorter too! */ 173 /* We must abort if file got shorter too! */
174 if (bb_copyfd_size(fd, STDOUT_FILENO, st.st_size) != st.st_size) { 174 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
175 bb_error_msg_and_die("I/O error or file '%s' was truncated", name);
176 }
177 bytes += st.st_size; 175 bytes += st.st_size;
178 close(fd); 176 close(fd);
179 } 177 }
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c
index 4df9c09a7..29a224bbc 100644
--- a/archival/libunarchive/data_extract_all.c
+++ b/archival/libunarchive/data_extract_all.c
@@ -20,7 +20,7 @@ void data_extract_all(archive_handle_t *archive_handle)
20 20
21 /* Check if the file already exists */ 21 /* Check if the file already exists */
22 if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) { 22 if (archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
23 /* Remove the existing entry if it exists */ 23 /* Remove the entry if it exists */
24 if (((file_header->mode & S_IFMT) != S_IFDIR) 24 if (((file_header->mode & S_IFMT) != S_IFDIR)
25 && (unlink(file_header->name) == -1) 25 && (unlink(file_header->name) == -1)
26 && (errno != ENOENT) 26 && (errno != ENOENT)
diff --git a/archival/libunarchive/get_header_cpio.c b/archival/libunarchive/get_header_cpio.c
index 3f5135512..b97b53b20 100644
--- a/archival/libunarchive/get_header_cpio.c
+++ b/archival/libunarchive/get_header_cpio.c
@@ -8,70 +8,32 @@
8#include "unarchive.h" 8#include "unarchive.h"
9 9
10typedef struct hardlinks_s { 10typedef struct hardlinks_s {
11 char *name;
12 int inode;
13 struct hardlinks_s *next; 11 struct hardlinks_s *next;
12 int inode; /* TODO: must match maj/min too! */
13 int mode ;
14 int mtime; /* These three are useful only in corner case */
15 int uid ; /* of hardlinks with zero size body */
16 int gid ;
17 char name[1];
14} hardlinks_t; 18} hardlinks_t;
15 19
16char get_header_cpio(archive_handle_t *archive_handle) 20char get_header_cpio(archive_handle_t *archive_handle)
17{ 21{
18 static hardlinks_t *saved_hardlinks = NULL; 22 static hardlinks_t *saved_hardlinks = NULL;
19 static unsigned pending_hardlinks = 0; 23 static hardlinks_t *saved_hardlinks_created = NULL;
20 static int inode;
21 24
22 file_header_t *file_header = archive_handle->file_header; 25 file_header_t *file_header = archive_handle->file_header;
23 char cpio_header[110]; 26 char cpio_header[110];
24 int namesize;
25 char dummy[16]; 27 char dummy[16];
26 int major, minor, nlink; 28 int namesize;
27 29 int major, minor, nlink, mode, inode;
28 if (pending_hardlinks) { /* Deal with any pending hardlinks */ 30 unsigned size, uid, gid, mtime;
29 hardlinks_t *tmp, *oldtmp;
30
31 tmp = saved_hardlinks;
32 oldtmp = NULL;
33
34 file_header->link_target = file_header->name;
35 file_header->size = 0;
36
37 while (tmp) {
38 if (tmp->inode != inode) {
39 tmp = tmp->next;
40 continue;
41 }
42
43 file_header->name = tmp->name;
44
45 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
46 archive_handle->action_data(archive_handle);
47 archive_handle->action_header(archive_handle->file_header);
48 }
49
50 pending_hardlinks--;
51
52 oldtmp = tmp;
53 tmp = tmp->next;
54 free(oldtmp->name);
55 free(oldtmp);
56 if (oldtmp == saved_hardlinks)
57 saved_hardlinks = tmp;
58 }
59
60 file_header->name = file_header->link_target;
61
62 if (pending_hardlinks > 1) {
63 bb_error_msg("error resolving hardlink: archive made by GNU cpio 2.0-2.2?");
64 }
65
66 /* No more pending hardlinks, read next file entry */
67 pending_hardlinks = 0;
68 }
69 31
70 /* There can be padding before archive header */ 32 /* There can be padding before archive header */
71 data_align(archive_handle, 4); 33 data_align(archive_handle, 4);
72 34
73 if (archive_xread_all_eof(archive_handle, (unsigned char*)cpio_header, 110) == 0) { 35 if (archive_xread_all_eof(archive_handle, (unsigned char*)cpio_header, 110) == 0) {
74 return EXIT_FAILURE; 36 goto create_hardlinks;
75 } 37 }
76 archive_handle->offset += 110; 38 archive_handle->offset += 110;
77 39
@@ -81,17 +43,19 @@ char get_header_cpio(archive_handle_t *archive_handle)
81 bb_error_msg_and_die("unsupported cpio format, use newc or crc"); 43 bb_error_msg_and_die("unsupported cpio format, use newc or crc");
82 } 44 }
83 45
84 { 46 sscanf(cpio_header + 6,
85 unsigned long tmpsize; 47 "%8x" "%8x" "%8x" "%8x"
86 sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", 48 "%8x" "%8x" "%8x" /*maj,min:*/ "%16c"
87 dummy, &inode, (unsigned int*)&file_header->mode, 49 /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum:*/ "%8c",
88 (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid, 50 &inode, &mode, &uid, &gid,
89 &nlink, &file_header->mtime, &tmpsize, 51 &nlink, &mtime, &size, dummy,
90 dummy, &major, &minor, &namesize, dummy); 52 &major, &minor, &namesize, dummy);
91 file_header->size = tmpsize; 53 file_header->mode = mode;
92 } 54 file_header->uid = uid;
55 file_header->gid = gid;
56 file_header->mtime = mtime;
57 file_header->size = size;
93 58
94 free(file_header->name);
95 file_header->name = xzalloc(namesize + 1); 59 file_header->name = xzalloc(namesize + 1);
96 /* Read in filename */ 60 /* Read in filename */
97 xread(archive_handle->src_fd, file_header->name, namesize); 61 xread(archive_handle->src_fd, file_header->name, namesize);
@@ -101,25 +65,9 @@ char get_header_cpio(archive_handle_t *archive_handle)
101 data_align(archive_handle, 4); 65 data_align(archive_handle, 4);
102 66
103 if (strcmp(file_header->name, "TRAILER!!!") == 0) { 67 if (strcmp(file_header->name, "TRAILER!!!") == 0) {
104 /* Always round up */ 68 /* Always round up. ">> 9" divides by 512 */
105 printf("%d blocks\n", (int) (archive_handle->offset % 512 ? 69 printf("%"OFF_FMT"u blocks\n", (archive_handle->offset + 511) >> 9);
106 archive_handle->offset / 512 + 1 : 70 goto create_hardlinks;
107 archive_handle->offset / 512
108 ));
109 if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
110 hardlinks_t *tmp = saved_hardlinks;
111 hardlinks_t *oldtmp = NULL;
112 while (tmp) {
113 bb_error_msg("%s not created: cannot resolve hardlink", tmp->name);
114 oldtmp = tmp;
115 tmp = tmp->next;
116 free(oldtmp->name);
117 free(oldtmp);
118 }
119 saved_hardlinks = NULL;
120 pending_hardlinks = 0;
121 }
122 return EXIT_FAILURE;
123 } 71 }
124 72
125 if (S_ISLNK(file_header->mode)) { 73 if (S_ISLNK(file_header->mode)) {
@@ -130,25 +78,33 @@ char get_header_cpio(archive_handle_t *archive_handle)
130 } else { 78 } else {
131 file_header->link_target = NULL; 79 file_header->link_target = NULL;
132 } 80 }
133 if (nlink > 1 && !S_ISDIR(file_header->mode)) { 81
134 if (file_header->size == 0) { /* Put file on a linked list for later */ 82// TODO: data_extract_all can't deal with hardlinks to non-files...
135 hardlinks_t *new = xmalloc(sizeof(hardlinks_t)); 83// (should be !S_ISDIR instead of S_ISREG here)
84
85 if (nlink > 1 && S_ISREG(file_header->mode)) {
86 hardlinks_t *new = xmalloc(sizeof(*new) + namesize);
87 new->inode = inode;
88 new->mode = mode ;
89 new->mtime = mtime;
90 new->uid = uid ;
91 new->gid = gid ;
92 strcpy(new->name, file_header->name);
93 /* Put file on a linked list for later */
94 if (size == 0) {
136 new->next = saved_hardlinks; 95 new->next = saved_hardlinks;
137 new->inode = inode;
138 /* name current allocated, freed later */
139 new->name = file_header->name;
140 file_header->name = NULL;
141 saved_hardlinks = new; 96 saved_hardlinks = new;
142 return EXIT_SUCCESS; /* Skip this one */ 97 return EXIT_SUCCESS; /* Skip this one */
98 /* TODO: this breaks cpio -t (it does not show hardlinks) */
143 } 99 }
144 /* Found the file with data in */ 100 new->next = saved_hardlinks_created;
145 pending_hardlinks = nlink; 101 saved_hardlinks_created = new;
146 } 102 }
147 file_header->device = makedev(major, minor); 103 file_header->device = makedev(major, minor);
148 104
149 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { 105 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
150 archive_handle->action_data(archive_handle); 106 archive_handle->action_data(archive_handle);
151 archive_handle->action_header(archive_handle->file_header); 107 archive_handle->action_header(file_header);
152 } else { 108 } else {
153 data_skip(archive_handle); 109 data_skip(archive_handle);
154 } 110 }
@@ -156,6 +112,57 @@ char get_header_cpio(archive_handle_t *archive_handle)
156 archive_handle->offset += file_header->size; 112 archive_handle->offset += file_header->size;
157 113
158 free(file_header->link_target); 114 free(file_header->link_target);
115 free(file_header->name);
116 file_header->link_target = NULL;
117 file_header->name = NULL;
159 118
160 return EXIT_SUCCESS; 119 return EXIT_SUCCESS;
120
121 create_hardlinks:
122 free(file_header->link_target);
123 free(file_header->name);
124
125 while (saved_hardlinks) {
126 hardlinks_t *cur;
127 hardlinks_t *make_me = saved_hardlinks;
128 saved_hardlinks = make_me->next;
129
130 memset(file_header, 0, sizeof(*file_header));
131 file_header->name = make_me->name;
132 file_header->mode = make_me->mode;
133 /*file_header->size = 0;*/
134
135 /* Try to find a file we are hardlinked to */
136 cur = saved_hardlinks_created;
137 while (cur) {
138 /* TODO: must match maj/min too! */
139 if (cur->inode == make_me->inode) {
140 file_header->link_target = cur->name;
141 /* link_target != NULL, size = 0: "I am a hardlink" */
142 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
143 archive_handle->action_data(archive_handle);
144 free(make_me);
145 goto next_link;
146 }
147 }
148 /* Oops... no file with such inode was created... do it now
149 * (happens when hardlinked files are empty (zero length)) */
150 file_header->mtime = make_me->mtime;
151 file_header->uid = make_me->uid ;
152 file_header->gid = make_me->gid ;
153 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
154 archive_handle->action_data(archive_handle);
155 /* Move to the list of created hardlinked files */
156 make_me->next = saved_hardlinks_created;
157 saved_hardlinks_created = make_me;
158 next_link: ;
159 }
160
161 while (saved_hardlinks_created) {
162 hardlinks_t *p = saved_hardlinks_created;
163 saved_hardlinks_created = p->next;
164 free(p);
165 }
166
167 return EXIT_FAILURE; /* "No more files to process" */
161} 168}
diff --git a/archival/libunarchive/seek_by_jump.c b/archival/libunarchive/seek_by_jump.c
index 8b5f3e887..5288c1d73 100644
--- a/archival/libunarchive/seek_by_jump.c
+++ b/archival/libunarchive/seek_by_jump.c
@@ -9,11 +9,9 @@
9void seek_by_jump(const archive_handle_t *archive_handle, unsigned amount) 9void seek_by_jump(const archive_handle_t *archive_handle, unsigned amount)
10{ 10{
11 if (lseek(archive_handle->src_fd, (off_t) amount, SEEK_CUR) == (off_t) -1) { 11 if (lseek(archive_handle->src_fd, (off_t) amount, SEEK_CUR) == (off_t) -1) {
12#if ENABLE_FEATURE_UNARCHIVE_TAPE 12 if (errno == ESPIPE)
13 if (errno == ESPIPE) {
14 seek_by_read(archive_handle, amount); 13 seek_by_read(archive_handle, amount);
15 } else 14 else
16#endif
17 bb_perror_msg_and_die("seek failure"); 15 bb_perror_msg_and_die("seek failure");
18 } 16 }
19} 17}
diff --git a/scripts/defconfig b/scripts/defconfig
index c24d85242..26cc8d25d 100644
--- a/scripts/defconfig
+++ b/scripts/defconfig
@@ -130,7 +130,6 @@ CONFIG_UNZIP=y
130# 130#
131# Common options for cpio and tar 131# Common options for cpio and tar
132# 132#
133CONFIG_FEATURE_UNARCHIVE_TAPE=y
134# CONFIG_FEATURE_DEB_TAR_GZ is not set 133# CONFIG_FEATURE_DEB_TAR_GZ is not set
135# CONFIG_FEATURE_DEB_TAR_BZ2 is not set 134# CONFIG_FEATURE_DEB_TAR_BZ2 is not set
136# CONFIG_FEATURE_DEB_TAR_LZMA is not set 135# CONFIG_FEATURE_DEB_TAR_LZMA is not set