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

Last change on this file since 3803 was 3621, checked in by Bruno Cornec, 10 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
RevLine 
[2725]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"
[3232]8#include "bb_archive.h"
[2725]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
[3621]40 if (!is_prefixed_with(&cpio_header[0], "07070")
[2725]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;
[3621]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;
[2725]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
[3621]83 if (strcmp(file_header->name, cpio_TRAILER) == 0) {
[2725]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.