diff options
author | bug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-09-25 02:47:48 +0000 |
---|---|---|
committer | bug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-09-25 02:47:48 +0000 |
commit | d4a48a11220f6a86ee2702c01c986d0a1a0a7bbc (patch) | |
tree | f38c7ef4317eea28c6abdb0adbbb286fe041711e /archival/cpio.c | |
parent | d2871e072e3f545a35e07d715f3cf02cf96c011d (diff) | |
download | busybox-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.c | 216 |
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 | ||
34 | typedef struct hardlinks_s { | ||
35 | file_header_t *entry; | ||
36 | int inode; | ||
37 | struct hardlinks_s *next; | ||
38 | } hardlinks_t; | ||
39 | |||
34 | extern int cpio_main(int argc, char **argv) | 40 | extern 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 | ||