Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
| 2 | /* |
| 3 | * Mini cpio implementation for busybox |
| 4 | * |
| 5 | * Copyright (C) 2001 by Glenn McGrath |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or |
| 10 | * (at your option) any later version. |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | * General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU General Public License |
| 18 | * along with this program; if not, write to the Free Software |
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | * |
| 21 | * Limitations: |
| 22 | * Doesn't check CRC's |
| 23 | * Only supports new ASCII and CRC formats |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 24 | * |
| 25 | */ |
| 26 | #include <fcntl.h> |
| 27 | #include <getopt.h> |
| 28 | #include <stdlib.h> |
| 29 | #include <string.h> |
| 30 | #include <unistd.h> |
Glenn L McGrath | ef0eab5 | 2001-10-25 14:49:48 +0000 | [diff] [blame] | 31 | #include "unarchive.h" |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 32 | #include "busybox.h" |
| 33 | |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 34 | typedef struct hardlinks_s { |
| 35 | file_header_t *entry; |
| 36 | int inode; |
| 37 | struct hardlinks_s *next; |
| 38 | } hardlinks_t; |
| 39 | |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 40 | extern int cpio_main(int argc, char **argv) |
| 41 | { |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 42 | archive_handle_t *archive_handle; |
| 43 | int opt; |
| 44 | |
| 45 | /* Initialise */ |
| 46 | archive_handle = init_handle(); |
| 47 | archive_handle->src_fd = fileno(stdin); |
Glenn L McGrath | 237ae42 | 2002-11-03 14:05:15 +0000 | [diff] [blame] | 48 | archive_handle->seek = seek_by_char; |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 49 | archive_handle->action_header = header_list; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 50 | |
| 51 | while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { |
| 52 | switch (opt) { |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 53 | case 'i': /* extract */ |
| 54 | archive_handle->action_data = data_extract_all; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 55 | break; |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 56 | case 'd': /* create _leading_ directories */ |
| 57 | archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 58 | break; |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 59 | case 'm': /* preserve modification time */ |
| 60 | archive_handle->flags |= ARCHIVE_PRESERVE_DATE; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 61 | break; |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 62 | case 'v': /* verbosly list files */ |
| 63 | archive_handle->action_header = header_verbose_list; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 64 | break; |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 65 | case 'u': /* unconditional */ |
| 66 | archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 67 | break; |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 68 | case 't': /* list files */ |
| 69 | archive_handle->action_header = header_list; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 70 | break; |
| 71 | case 'F': |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 72 | archive_handle->src_fd = xopen(optarg, O_RDONLY); |
Glenn L McGrath | 237ae42 | 2002-11-03 14:05:15 +0000 | [diff] [blame] | 73 | archive_handle->seek = seek_by_jump; |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 74 | break; |
| 75 | default: |
| 76 | show_usage(); |
| 77 | } |
| 78 | } |
| 79 | |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 80 | while (optind < argc) { |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 81 | archive_handle->filter = filter_accept_list; |
| 82 | archive_handle->accept = add_to_list(archive_handle->accept, argv[optind]); |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 83 | optind++; |
| 84 | } |
| 85 | |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 86 | while (1) { |
| 87 | static hardlinks_t *saved_hardlinks = NULL; |
| 88 | static unsigned short pending_hardlinks = 0; |
| 89 | file_header_t *file_header = archive_handle->file_header; |
| 90 | char cpio_header[110]; |
| 91 | int namesize; |
| 92 | char dummy[16]; |
| 93 | int major, minor, nlink, inode; |
| 94 | char extract_flag; |
| 95 | |
| 96 | if (pending_hardlinks) { /* Deal with any pending hardlinks */ |
| 97 | hardlinks_t *tmp; |
| 98 | hardlinks_t *oldtmp; |
| 99 | |
| 100 | tmp = saved_hardlinks; |
| 101 | oldtmp = NULL; |
| 102 | |
| 103 | while (tmp) { |
| 104 | error_msg_and_die("need to fix this\n"); |
| 105 | if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */ |
| 106 | file_header = tmp->entry; |
| 107 | if (oldtmp) { |
| 108 | oldtmp->next = tmp->next; /* Remove item from linked list */ |
| 109 | } else { |
| 110 | saved_hardlinks = tmp->next; |
| 111 | } |
| 112 | free(tmp); |
| 113 | continue; |
| 114 | } |
| 115 | oldtmp = tmp; |
| 116 | tmp = tmp->next; |
| 117 | } |
| 118 | pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */ |
Glenn L McGrath | 8e94098 | 2002-11-04 23:47:31 +0000 | [diff] [blame] | 119 | } |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 120 | |
| 121 | /* There can be padding before archive header */ |
Glenn L McGrath | 237ae42 | 2002-11-03 14:05:15 +0000 | [diff] [blame] | 122 | data_align(archive_handle, 4); |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 123 | |
Glenn L McGrath | 237ae42 | 2002-11-03 14:05:15 +0000 | [diff] [blame] | 124 | if (archive_xread_all_eof(archive_handle, cpio_header, 110) == 0) { |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 125 | return(EXIT_FAILURE); |
| 126 | } |
| 127 | archive_handle->offset += 110; |
| 128 | |
| 129 | if (strncmp(&cpio_header[0], "07070", 5) != 0) { |
| 130 | printf("cpio header is %x-%x-%x-%x-%x\n", |
| 131 | cpio_header[0], |
| 132 | cpio_header[1], |
| 133 | cpio_header[2], |
| 134 | cpio_header[3], |
| 135 | cpio_header[4]); |
| 136 | error_msg_and_die("Unsupported cpio format"); |
| 137 | } |
| 138 | |
| 139 | if ((cpio_header[5] != '1') && (cpio_header[5] != '2')) { |
| 140 | error_msg_and_die("Unsupported cpio format, use newc or crc"); |
Glenn L McGrath | 8e94098 | 2002-11-04 23:47:31 +0000 | [diff] [blame] | 141 | } |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 142 | |
| 143 | sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", |
| 144 | dummy, &inode, (unsigned int*)&file_header->mode, |
| 145 | (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid, |
| 146 | &nlink, &file_header->mtime, &file_header->size, |
| 147 | dummy, &major, &minor, &namesize, dummy); |
| 148 | |
| 149 | file_header->name = (char *) xmalloc(namesize + 1); |
Glenn L McGrath | 237ae42 | 2002-11-03 14:05:15 +0000 | [diff] [blame] | 150 | archive_xread_all(archive_handle, file_header->name, namesize); /* Read in filename */ |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 151 | file_header->name[namesize] = '\0'; |
| 152 | archive_handle->offset += namesize; |
| 153 | |
| 154 | /* Update offset amount and skip padding before file contents */ |
Glenn L McGrath | 237ae42 | 2002-11-03 14:05:15 +0000 | [diff] [blame] | 155 | data_align(archive_handle, 4); |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 156 | |
| 157 | if (strcmp(file_header->name, "TRAILER!!!") == 0) { |
| 158 | printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */ |
| 159 | if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */ |
| 160 | hardlinks_t *tmp = saved_hardlinks; |
| 161 | hardlinks_t *oldtmp = NULL; |
| 162 | while (tmp) { |
| 163 | error_msg("%s not created: cannot resolve hardlink", tmp->entry->name); |
| 164 | oldtmp = tmp; |
| 165 | tmp = tmp->next; |
| 166 | free (oldtmp->entry->name); |
| 167 | free (oldtmp->entry); |
| 168 | free (oldtmp); |
| 169 | } |
| 170 | saved_hardlinks = NULL; |
| 171 | pending_hardlinks = 0; |
| 172 | } |
| 173 | return(EXIT_FAILURE); |
| 174 | } |
| 175 | |
| 176 | if (S_ISLNK(file_header->mode)) { |
| 177 | file_header->link_name = (char *) xmalloc(file_header->size + 1); |
Glenn L McGrath | 237ae42 | 2002-11-03 14:05:15 +0000 | [diff] [blame] | 178 | archive_xread_all(archive_handle, file_header->link_name, file_header->size); |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 179 | file_header->link_name[file_header->size] = '\0'; |
| 180 | archive_handle->offset += file_header->size; |
| 181 | file_header->size = 0; /* Stop possible seeks in future */ |
| 182 | } |
| 183 | if (nlink > 1 && !S_ISDIR(file_header->mode)) { |
| 184 | if (file_header->size == 0) { /* Put file on a linked list for later */ |
| 185 | hardlinks_t *new = xmalloc(sizeof(hardlinks_t)); |
| 186 | new->next = saved_hardlinks; |
| 187 | new->inode = inode; |
| 188 | new->entry = file_header; |
| 189 | saved_hardlinks = new; |
| 190 | continue; |
| 191 | } else { /* Found the file with data in */ |
| 192 | hardlinks_t *tmp = saved_hardlinks; |
| 193 | pending_hardlinks = 1; |
| 194 | while (tmp) { |
| 195 | if (tmp->inode == inode) { |
| 196 | tmp->entry->link_name = xstrdup(file_header->name); |
| 197 | nlink--; |
| 198 | } |
| 199 | tmp = tmp->next; |
| 200 | } |
| 201 | if (nlink > 1) { |
| 202 | error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?"); |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 | file_header->device = (major << 8) | minor; |
| 207 | |
| 208 | extract_flag = FALSE; |
Glenn L McGrath | 8e94098 | 2002-11-04 23:47:31 +0000 | [diff] [blame] | 209 | if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { |
Glenn L McGrath | 7ca04f3 | 2002-09-25 02:47:48 +0000 | [diff] [blame] | 210 | struct stat statbuf; |
| 211 | |
| 212 | extract_flag = TRUE; |
| 213 | |
| 214 | /* Check if the file already exists */ |
| 215 | if (lstat (file_header->name, &statbuf) == 0) { |
| 216 | if ((archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) || (statbuf.st_mtime < file_header->mtime)) { |
| 217 | /* Remove file if flag set or its older than the file to be extracted */ |
| 218 | if (unlink(file_header->name) == -1) { |
| 219 | perror_msg_and_die("Couldnt remove old file"); |
| 220 | } |
| 221 | } else { |
| 222 | if (! archive_handle->flags & ARCHIVE_EXTRACT_QUIET) { |
| 223 | error_msg("%s not created: newer or same age file exists", file_header->name); |
| 224 | } |
| 225 | extract_flag = FALSE; |
| 226 | } |
| 227 | } |
| 228 | archive_handle->action_header(file_header); |
| 229 | } |
| 230 | |
| 231 | archive_handle->action_header(file_header); |
| 232 | if (extract_flag) { |
| 233 | archive_handle->action_data(archive_handle); |
| 234 | } else { |
| 235 | data_skip(archive_handle); |
| 236 | } |
| 237 | archive_handle->offset += file_header->size; |
| 238 | } |
| 239 | |
| 240 | return(EXIT_SUCCESS); |
Glenn L McGrath | 8f5b63e | 2001-06-22 09:22:06 +0000 | [diff] [blame] | 241 | } |
| 242 | |