1 | /* vi: set sw=4 ts=4: */
|
---|
2 | /* Copyright 2002 Laurence Anderson
|
---|
3 | *
|
---|
4 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
|
---|
5 | */
|
---|
6 |
|
---|
7 | #include "libbb.h"
|
---|
8 | #include "unarchive.h"
|
---|
9 |
|
---|
10 | typedef struct hardlinks_s {
|
---|
11 | char *name;
|
---|
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;
|
---|
19 | static unsigned pending_hardlinks = 0;
|
---|
20 | static int inode;
|
---|
21 |
|
---|
22 | file_header_t *file_header = archive_handle->file_header;
|
---|
23 | char cpio_header[110];
|
---|
24 | int namesize;
|
---|
25 | char dummy[16];
|
---|
26 | int major, minor, nlink;
|
---|
27 |
|
---|
28 | if (pending_hardlinks) { /* Deal with any pending hardlinks */
|
---|
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 |
|
---|
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) {
|
---|
74 | return EXIT_FAILURE;
|
---|
75 | }
|
---|
76 | archive_handle->offset += 110;
|
---|
77 |
|
---|
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");
|
---|
82 | }
|
---|
83 |
|
---|
84 | {
|
---|
85 | unsigned long tmpsize;
|
---|
86 | sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
|
---|
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);
|
---|
91 | file_header->size = tmpsize;
|
---|
92 | }
|
---|
93 |
|
---|
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);
|
---|
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) {
|
---|
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 | ));
|
---|
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 | }
|
---|
124 |
|
---|
125 | if (S_ISLNK(file_header->mode)) {
|
---|
126 | file_header->link_target = xzalloc(file_header->size + 1);
|
---|
127 | xread(archive_handle->src_fd, file_header->link_target, file_header->size);
|
---|
128 | archive_handle->offset += file_header->size;
|
---|
129 | file_header->size = 0; /* Stop possible seeks in future */
|
---|
130 | } else {
|
---|
131 | file_header->link_target = NULL;
|
---|
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;
|
---|
138 | /* name current allocated, freed later */
|
---|
139 | new->name = file_header->name;
|
---|
140 | file_header->name = NULL;
|
---|
141 | saved_hardlinks = new;
|
---|
142 | return EXIT_SUCCESS; /* Skip this one */
|
---|
143 | }
|
---|
144 | /* Found the file with data in */
|
---|
145 | pending_hardlinks = nlink;
|
---|
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 |
|
---|
158 | free(file_header->link_target);
|
---|
159 |
|
---|
160 | return EXIT_SUCCESS;
|
---|
161 | }
|
---|