source: MondoRescue/branches/3.3/mindi-busybox/archival/libarchive/get_header_cpio.c@ 3621

Last change on this file since 3621 was 3621, checked in by Bruno Cornec, 7 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 6.0 KB
Line 
1/* vi: set sw=4 ts=4: */
2/* Copyright 2002 Laurence Anderson
3 *
4 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
5 */
6
7#include "libbb.h"
8#include "bb_archive.h"
9
10typedef struct hardlinks_t {
11 struct hardlinks_t *next;
12 int inode; /* TODO: must match maj/min too! */
13 int mode ;
14 int mtime; /* These three are useful only in corner case */
15 int uid ; /* of hardlinks with zero size body */
16 int gid ;
17 char name[1];
18} hardlinks_t;
19
20char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
21{
22 file_header_t *file_header = archive_handle->file_header;
23 char cpio_header[110];
24 int namesize;
25 int major, minor, nlink, mode, inode;
26 unsigned size, uid, gid, mtime;
27
28 /* There can be padding before archive header */
29 data_align(archive_handle, 4);
30
31 size = full_read(archive_handle->src_fd, cpio_header, 110);
32 if (size == 0) {
33 goto create_hardlinks;
34 }
35 if (size != 110) {
36 bb_error_msg_and_die("short read");
37 }
38 archive_handle->offset += 110;
39
40 if (!is_prefixed_with(&cpio_header[0], "07070")
41 || (cpio_header[5] != '1' && cpio_header[5] != '2')
42 ) {
43 bb_error_msg_and_die("unsupported cpio format, use newc or crc");
44 }
45
46 if (sscanf(cpio_header + 6,
47 "%8x" "%8x" "%8x" "%8x"
48 "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c"
49 /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/,
50 &inode, &mode, &uid, &gid,
51 &nlink, &mtime, &size,
52 &major, &minor, &namesize) != 10)
53 bb_error_msg_and_die("damaged cpio file");
54 file_header->mode = mode;
55 /* "cpio -R USER:GRP" support: */
56 if (archive_handle->cpio__owner.uid != (uid_t)-1L)
57 uid = archive_handle->cpio__owner.uid;
58 if (archive_handle->cpio__owner.gid != (gid_t)-1L)
59 gid = archive_handle->cpio__owner.gid;
60 file_header->uid = uid;
61 file_header->gid = gid;
62 file_header->mtime = mtime;
63 file_header->size = size;
64
65 namesize &= 0x1fff; /* paranoia: limit names to 8k chars */
66 file_header->name = xzalloc(namesize + 1);
67 /* Read in filename */
68 xread(archive_handle->src_fd, file_header->name, namesize);
69 if (file_header->name[0] == '/') {
70 /* Testcase: echo /etc/hosts | cpio -pvd /tmp
71 * Without this code, it tries to unpack /etc/hosts
72 * into "/etc/hosts", not "etc/hosts".
73 */
74 char *p = file_header->name;
75 do p++; while (*p == '/');
76 overlapping_strcpy(file_header->name, p);
77 }
78 archive_handle->offset += namesize;
79
80 /* Update offset amount and skip padding before file contents */
81 data_align(archive_handle, 4);
82
83 if (strcmp(file_header->name, cpio_TRAILER) == 0) {
84 /* Always round up. ">> 9" divides by 512 */
85 archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9;
86 goto create_hardlinks;
87 }
88
89 file_header->link_target = NULL;
90 if (S_ISLNK(file_header->mode)) {
91 file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */
92 file_header->link_target = xzalloc(file_header->size + 1);
93 xread(archive_handle->src_fd, file_header->link_target, file_header->size);
94 archive_handle->offset += file_header->size;
95 file_header->size = 0; /* Stop possible seeks in future */
96 }
97
98// TODO: data_extract_all can't deal with hardlinks to non-files...
99// when fixed, change S_ISREG to !S_ISDIR here
100
101 if (nlink > 1 && S_ISREG(file_header->mode)) {
102 hardlinks_t *new = xmalloc(sizeof(*new) + namesize);
103 new->inode = inode;
104 new->mode = mode ;
105 new->mtime = mtime;
106 new->uid = uid ;
107 new->gid = gid ;
108 strcpy(new->name, file_header->name);
109 /* Put file on a linked list for later */
110 if (size == 0) {
111 new->next = archive_handle->cpio__hardlinks_to_create;
112 archive_handle->cpio__hardlinks_to_create = new;
113 return EXIT_SUCCESS; /* Skip this one */
114 /* TODO: this breaks cpio -t (it does not show hardlinks) */
115 }
116 new->next = archive_handle->cpio__created_hardlinks;
117 archive_handle->cpio__created_hardlinks = new;
118 }
119 file_header->device = makedev(major, minor);
120
121 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
122 archive_handle->action_data(archive_handle);
123//TODO: run "echo /etc/hosts | cpio -pv /tmp" twice. On 2nd run:
124//cpio: etc/hosts not created: newer or same age file exists
125//etc/hosts <-- should NOT show it
126//2 blocks <-- should say "0 blocks"
127 archive_handle->action_header(file_header);
128 } else {
129 data_skip(archive_handle);
130 }
131
132 archive_handle->offset += file_header->size;
133
134 free(file_header->link_target);
135 free(file_header->name);
136 file_header->link_target = NULL;
137 file_header->name = NULL;
138
139 return EXIT_SUCCESS;
140
141 create_hardlinks:
142 free(file_header->link_target);
143 free(file_header->name);
144
145 while (archive_handle->cpio__hardlinks_to_create) {
146 hardlinks_t *cur;
147 hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create;
148
149 archive_handle->cpio__hardlinks_to_create = make_me->next;
150
151 memset(file_header, 0, sizeof(*file_header));
152 file_header->mtime = make_me->mtime;
153 file_header->name = make_me->name;
154 file_header->mode = make_me->mode;
155 file_header->uid = make_me->uid;
156 file_header->gid = make_me->gid;
157 /*file_header->size = 0;*/
158 /*file_header->link_target = NULL;*/
159
160 /* Try to find a file we are hardlinked to */
161 cur = archive_handle->cpio__created_hardlinks;
162 while (cur) {
163 /* TODO: must match maj/min too! */
164 if (cur->inode == make_me->inode) {
165 file_header->link_target = cur->name;
166 /* link_target != NULL, size = 0: "I am a hardlink" */
167 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
168 archive_handle->action_data(archive_handle);
169 free(make_me);
170 goto next_link;
171 }
172 cur = cur->next;
173 }
174 /* Oops... no file with such inode was created... do it now
175 * (happens when hardlinked files are empty (zero length)) */
176 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
177 archive_handle->action_data(archive_handle);
178 /* Move to the list of created hardlinked files */
179 make_me->next = archive_handle->cpio__created_hardlinks;
180 archive_handle->cpio__created_hardlinks = make_me;
181 next_link: ;
182 }
183
184 while (archive_handle->cpio__created_hardlinks) {
185 hardlinks_t *p = archive_handle->cpio__created_hardlinks;
186 archive_handle->cpio__created_hardlinks = p->next;
187 free(p);
188 }
189
190 return EXIT_FAILURE; /* "No more files to process" */
191}
Note: See TracBrowser for help on using the repository browser.