[1765] | 1 | /* vi: set sw=4 ts=4: */
|
---|
[821] | 2 | /* Copyright 2002 Laurence Anderson
|
---|
| 3 | *
|
---|
| 4 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
|
---|
| 5 | */
|
---|
| 6 |
|
---|
[1765] | 7 | #include "libbb.h"
|
---|
[821] | 8 | #include "unarchive.h"
|
---|
| 9 |
|
---|
| 10 | typedef struct hardlinks_s {
|
---|
[1765] | 11 | char *name;
|
---|
[821] | 12 | int inode;
|
---|
| 13 | struct hardlinks_s *next;
|
---|
| 14 | } hardlinks_t;
|
---|
| 15 |
|
---|
| 16 | char get_header_cpio(archive_handle_t *archive_handle)
|
---|
| 17 | {
|
---|
| 18 | static hardlinks_t *saved_hardlinks = NULL;
|
---|
[1765] | 19 | static unsigned pending_hardlinks = 0;
|
---|
| 20 | static int inode;
|
---|
| 21 |
|
---|
[821] | 22 | file_header_t *file_header = archive_handle->file_header;
|
---|
| 23 | char cpio_header[110];
|
---|
| 24 | int namesize;
|
---|
| 25 | char dummy[16];
|
---|
[1765] | 26 | int major, minor, nlink;
|
---|
[821] | 27 |
|
---|
| 28 | if (pending_hardlinks) { /* Deal with any pending hardlinks */
|
---|
[1765] | 29 | hardlinks_t *tmp, *oldtmp;
|
---|
[821] | 30 |
|
---|
| 31 | tmp = saved_hardlinks;
|
---|
| 32 | oldtmp = NULL;
|
---|
| 33 |
|
---|
[1765] | 34 | file_header->link_target = file_header->name;
|
---|
| 35 | file_header->size = 0;
|
---|
| 36 |
|
---|
[821] | 37 | while (tmp) {
|
---|
[1765] | 38 | if (tmp->inode != inode) {
|
---|
| 39 | tmp = tmp->next;
|
---|
[821] | 40 | continue;
|
---|
| 41 | }
|
---|
[1765] | 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 |
|
---|
[821] | 52 | oldtmp = tmp;
|
---|
| 53 | tmp = tmp->next;
|
---|
[1765] | 54 | free(oldtmp->name);
|
---|
| 55 | free(oldtmp);
|
---|
| 56 | if (oldtmp == saved_hardlinks)
|
---|
| 57 | saved_hardlinks = tmp;
|
---|
[821] | 58 | }
|
---|
[1765] | 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;
|
---|
[821] | 68 | }
|
---|
| 69 |
|
---|
| 70 | /* There can be padding before archive header */
|
---|
| 71 | data_align(archive_handle, 4);
|
---|
| 72 |
|
---|
| 73 | if (archive_xread_all_eof(archive_handle, (unsigned char*)cpio_header, 110) == 0) {
|
---|
[1765] | 74 | return EXIT_FAILURE;
|
---|
[821] | 75 | }
|
---|
| 76 | archive_handle->offset += 110;
|
---|
| 77 |
|
---|
[1765] | 78 | if (strncmp(&cpio_header[0], "07070", 5) != 0
|
---|
| 79 | || (cpio_header[5] != '1' && cpio_header[5] != '2')
|
---|
| 80 | ) {
|
---|
| 81 | bb_error_msg_and_die("unsupported cpio format, use newc or crc");
|
---|
[821] | 82 | }
|
---|
| 83 |
|
---|
| 84 | {
|
---|
[1765] | 85 | unsigned long tmpsize;
|
---|
| 86 | sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
|
---|
[821] | 87 | dummy, &inode, (unsigned int*)&file_header->mode,
|
---|
| 88 | (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid,
|
---|
| 89 | &nlink, &file_header->mtime, &tmpsize,
|
---|
| 90 | dummy, &major, &minor, &namesize, dummy);
|
---|
[1765] | 91 | file_header->size = tmpsize;
|
---|
[821] | 92 | }
|
---|
| 93 |
|
---|
[1765] | 94 | free(file_header->name);
|
---|
| 95 | file_header->name = xzalloc(namesize + 1);
|
---|
| 96 | /* Read in filename */
|
---|
| 97 | xread(archive_handle->src_fd, file_header->name, namesize);
|
---|
[821] | 98 | archive_handle->offset += namesize;
|
---|
| 99 |
|
---|
| 100 | /* Update offset amount and skip padding before file contents */
|
---|
| 101 | data_align(archive_handle, 4);
|
---|
| 102 |
|
---|
| 103 | if (strcmp(file_header->name, "TRAILER!!!") == 0) {
|
---|
[1765] | 104 | /* Always round up */
|
---|
| 105 | printf("%d blocks\n", (int) (archive_handle->offset % 512 ?
|
---|
| 106 | archive_handle->offset / 512 + 1 :
|
---|
| 107 | archive_handle->offset / 512
|
---|
| 108 | ));
|
---|
[821] | 109 | if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
|
---|
| 110 | hardlinks_t *tmp = saved_hardlinks;
|
---|
| 111 | hardlinks_t *oldtmp = NULL;
|
---|
| 112 | while (tmp) {
|
---|
[1765] | 113 | bb_error_msg("%s not created: cannot resolve hardlink", tmp->name);
|
---|
[821] | 114 | oldtmp = tmp;
|
---|
| 115 | tmp = tmp->next;
|
---|
[1765] | 116 | free(oldtmp->name);
|
---|
| 117 | free(oldtmp);
|
---|
[821] | 118 | }
|
---|
| 119 | saved_hardlinks = NULL;
|
---|
| 120 | pending_hardlinks = 0;
|
---|
| 121 | }
|
---|
[1765] | 122 | return EXIT_FAILURE;
|
---|
[821] | 123 | }
|
---|
| 124 |
|
---|
| 125 | if (S_ISLNK(file_header->mode)) {
|
---|
[1765] | 126 | file_header->link_target = xzalloc(file_header->size + 1);
|
---|
| 127 | xread(archive_handle->src_fd, file_header->link_target, file_header->size);
|
---|
[821] | 128 | archive_handle->offset += file_header->size;
|
---|
| 129 | file_header->size = 0; /* Stop possible seeks in future */
|
---|
| 130 | } else {
|
---|
[1765] | 131 | file_header->link_target = NULL;
|
---|
[821] | 132 | }
|
---|
| 133 | if (nlink > 1 && !S_ISDIR(file_header->mode)) {
|
---|
| 134 | if (file_header->size == 0) { /* Put file on a linked list for later */
|
---|
| 135 | hardlinks_t *new = xmalloc(sizeof(hardlinks_t));
|
---|
| 136 | new->next = saved_hardlinks;
|
---|
| 137 | new->inode = inode;
|
---|
[1765] | 138 | /* name current allocated, freed later */
|
---|
| 139 | new->name = file_header->name;
|
---|
| 140 | file_header->name = NULL;
|
---|
[821] | 141 | saved_hardlinks = new;
|
---|
[1765] | 142 | return EXIT_SUCCESS; /* Skip this one */
|
---|
[821] | 143 | }
|
---|
[1765] | 144 | /* Found the file with data in */
|
---|
| 145 | pending_hardlinks = nlink;
|
---|
[821] | 146 | }
|
---|
| 147 | file_header->device = makedev(major, minor);
|
---|
| 148 |
|
---|
| 149 | if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
|
---|
| 150 | archive_handle->action_data(archive_handle);
|
---|
| 151 | archive_handle->action_header(archive_handle->file_header);
|
---|
| 152 | } else {
|
---|
| 153 | data_skip(archive_handle);
|
---|
| 154 | }
|
---|
| 155 |
|
---|
| 156 | archive_handle->offset += file_header->size;
|
---|
| 157 |
|
---|
[1765] | 158 | free(file_header->link_target);
|
---|
[821] | 159 |
|
---|
[1765] | 160 | return EXIT_SUCCESS;
|
---|
[821] | 161 | }
|
---|