aboutsummaryrefslogtreecommitdiff
path: root/archival/cpio.c
diff options
context:
space:
mode:
authorbug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277>2002-09-25 02:47:48 +0000
committerbug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277>2002-09-25 02:47:48 +0000
commitd4a48a11220f6a86ee2702c01c986d0a1a0a7bbc (patch)
treef38c7ef4317eea28c6abdb0adbbb286fe041711e /archival/cpio.c
parentd2871e072e3f545a35e07d715f3cf02cf96c011d (diff)
downloadbusybox-w32-d4a48a11220f6a86ee2702c01c986d0a1a0a7bbc.tar.gz
busybox-w32-d4a48a11220f6a86ee2702c01c986d0a1a0a7bbc.tar.bz2
busybox-w32-d4a48a11220f6a86ee2702c01c986d0a1a0a7bbc.zip
New common unarchive code.
git-svn-id: svn://busybox.net/trunk/busybox@5589 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'archival/cpio.c')
-rw-r--r--archival/cpio.c216
1 files changed, 180 insertions, 36 deletions
diff --git a/archival/cpio.c b/archival/cpio.c
index baaa72ea1..761517516 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -31,66 +31,210 @@
31#include "unarchive.h" 31#include "unarchive.h"
32#include "busybox.h" 32#include "busybox.h"
33 33
34typedef struct hardlinks_s {
35 file_header_t *entry;
36 int inode;
37 struct hardlinks_s *next;
38} hardlinks_t;
39
34extern int cpio_main(int argc, char **argv) 40extern int cpio_main(int argc, char **argv)
35{ 41{
36 FILE *src_stream = stdin; 42 archive_handle_t *archive_handle;
37 char **extract_names = NULL; 43 int opt;
38 int extract_function = 0; 44
39 int num_of_entries = 0; 45 /* Initialise */
40 int opt = 0; 46 archive_handle = init_handle();
41 mode_t oldmask = 0; 47 archive_handle->src_fd = fileno(stdin);
48 archive_handle->action_header = header_list;
42 49
43 while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { 50 while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) {
44 switch (opt) { 51 switch (opt) {
45 case 'i': // extract 52 case 'i': /* extract */
46 extract_function |= extract_all_to_fs; 53 archive_handle->action_data = data_extract_all;
47 break; 54 break;
48 case 'd': // create _leading_ directories 55 case 'd': /* create _leading_ directories */
49 extract_function |= extract_create_leading_dirs; 56 archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
50 oldmask = umask(077); /* Make make_directory act like GNU cpio */
51 break; 57 break;
52 case 'm': // preserve modification time 58 case 'm': /* preserve modification time */
53 extract_function |= extract_preserve_date; 59 archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
54 break; 60 break;
55 case 'v': // verbosly list files 61 case 'v': /* verbosly list files */
56 extract_function |= extract_verbose_list; 62 archive_handle->action_header = header_verbose_list;
57 break; 63 break;
58 case 'u': // unconditional 64 case 'u': /* unconditional */
59 extract_function |= extract_unconditional; 65 archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
60 break; 66 break;
61 case 't': // list files 67 case 't': /* list files */
62 extract_function |= extract_list; 68 archive_handle->action_header = header_list;
63 break; 69 break;
64 case 'F': 70 case 'F':
65 src_stream = xfopen(optarg, "r"); 71 archive_handle->src_fd = xopen(optarg, O_RDONLY);
66 break; 72 break;
67 default: 73 default:
68 show_usage(); 74 show_usage();
69 } 75 }
70 } 76 }
71 77
72 if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) { 78 while (optind < argc) {
73 extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/ 79 archive_handle->filter = filter_accept_list;
80 archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]);
81 optind++;
74 } 82 }
75 83
76 if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) { 84 while (1) {
77 /* The meaning of v changes on extract */ 85 static hardlinks_t *saved_hardlinks = NULL;
78 extract_function ^= extract_verbose_list; 86 static unsigned short pending_hardlinks = 0;
79 extract_function |= extract_list; 87 file_header_t *file_header = archive_handle->file_header;
88 char cpio_header[110];
89 int namesize;
90 char dummy[16];
91 int major, minor, nlink, inode;
92 char extract_flag;
93
94 if (pending_hardlinks) { /* Deal with any pending hardlinks */
95 hardlinks_t *tmp;
96 hardlinks_t *oldtmp;
97
98 tmp = saved_hardlinks;
99 oldtmp = NULL;
100
101 while (tmp) {
102 error_msg_and_die("need to fix this\n");
103 if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
104 file_header = tmp->entry;
105 if (oldtmp) {
106 oldtmp->next = tmp->next; /* Remove item from linked list */
107 } else {
108 saved_hardlinks = tmp->next;
109 }
110 free(tmp);
111 continue;
112 }
113 oldtmp = tmp;
114 tmp = tmp->next;
115 }
116 pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
80 } 117 }
81 118
82 while (optind < argc) { 119 /* There can be padding before archive header */
83 extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); 120 archive_handle->offset += data_align(archive_handle->src_fd, archive_handle->offset, 4);
84 extract_names[num_of_entries] = xstrdup(argv[optind]); 121
85 num_of_entries++; 122 if (xread_all_eof(archive_handle->src_fd, cpio_header, 110) == 0) {
86 extract_names[num_of_entries] = NULL; 123 return(EXIT_FAILURE);
87 optind++; 124 }
125 archive_handle->offset += 110;
126
127 if (strncmp(&cpio_header[0], "07070", 5) != 0) {
128 printf("cpio header is %x-%x-%x-%x-%x\n",
129 cpio_header[0],
130 cpio_header[1],
131 cpio_header[2],
132 cpio_header[3],
133 cpio_header[4]);
134 error_msg_and_die("Unsupported cpio format");
135 }
136
137 if ((cpio_header[5] != '1') && (cpio_header[5] != '2')) {
138 error_msg_and_die("Unsupported cpio format, use newc or crc");
139 }
140
141 sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
142 dummy, &inode, (unsigned int*)&file_header->mode,
143 (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid,
144 &nlink, &file_header->mtime, &file_header->size,
145 dummy, &major, &minor, &namesize, dummy);
146
147 file_header->name = (char *) xmalloc(namesize + 1);
148 xread(archive_handle->src_fd, file_header->name, namesize); /* Read in filename */
149 file_header->name[namesize] = '\0';
150 archive_handle->offset += namesize;
151
152 /* Update offset amount and skip padding before file contents */
153 archive_handle->offset += data_align(archive_handle->src_fd, archive_handle->offset, 4);
154
155 if (strcmp(file_header->name, "TRAILER!!!") == 0) {
156 printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */
157 if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
158 hardlinks_t *tmp = saved_hardlinks;
159 hardlinks_t *oldtmp = NULL;
160 while (tmp) {
161 error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
162 oldtmp = tmp;
163 tmp = tmp->next;
164 free (oldtmp->entry->name);
165 free (oldtmp->entry);
166 free (oldtmp);
167 }
168 saved_hardlinks = NULL;
169 pending_hardlinks = 0;
88 } 170 }
171 return(EXIT_FAILURE);
172 }
173
174 if (S_ISLNK(file_header->mode)) {
175 file_header->link_name = (char *) xmalloc(file_header->size + 1);
176 xread(archive_handle->src_fd, file_header->link_name, file_header->size);
177 file_header->link_name[file_header->size] = '\0';
178 archive_handle->offset += file_header->size;
179 file_header->size = 0; /* Stop possible seeks in future */
180 }
181 if (nlink > 1 && !S_ISDIR(file_header->mode)) {
182 if (file_header->size == 0) { /* Put file on a linked list for later */
183 hardlinks_t *new = xmalloc(sizeof(hardlinks_t));
184 new->next = saved_hardlinks;
185 new->inode = inode;
186 new->entry = file_header;
187 saved_hardlinks = new;
188 continue;
189 } else { /* Found the file with data in */
190 hardlinks_t *tmp = saved_hardlinks;
191 pending_hardlinks = 1;
192 while (tmp) {
193 if (tmp->inode == inode) {
194 tmp->entry->link_name = xstrdup(file_header->name);
195 nlink--;
196 }
197 tmp = tmp->next;
198 }
199 if (nlink > 1) {
200 error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
201 }
202 }
203 }
204 file_header->device = (major << 8) | minor;
205
206 extract_flag = FALSE;
207 if (archive_handle->filter(archive_handle->accept, archive_handle->reject, file_header->name) == EXIT_SUCCESS) {
208 struct stat statbuf;
89 209
90 unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names, NULL); 210 extract_flag = TRUE;
91 if (oldmask) { 211
92 umask(oldmask); /* Restore umask if we changed it */ 212 /* Check if the file already exists */
213 if (lstat (file_header->name, &statbuf) == 0) {
214 if ((archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) || (statbuf.st_mtime < file_header->mtime)) {
215 /* Remove file if flag set or its older than the file to be extracted */
216 if (unlink(file_header->name) == -1) {
217 perror_msg_and_die("Couldnt remove old file");
218 }
219 } else {
220 if (! archive_handle->flags & ARCHIVE_EXTRACT_QUIET) {
221 error_msg("%s not created: newer or same age file exists", file_header->name);
222 }
223 extract_flag = FALSE;
224 }
225 }
226 archive_handle->action_header(file_header);
227 }
228
229 archive_handle->action_header(file_header);
230 if (extract_flag) {
231 archive_handle->action_data(archive_handle);
232 } else {
233 data_skip(archive_handle);
234 }
235 archive_handle->offset += file_header->size;
93 } 236 }
94 return EXIT_SUCCESS; 237
238 return(EXIT_SUCCESS);
95} 239}
96 240