7 |
#include "libbb.h" |
#include "libbb.h" |
8 |
#include "unarchive.h" |
#include "unarchive.h" |
9 |
|
|
10 |
typedef struct hardlinks_s { |
typedef struct hardlinks_t { |
11 |
char *name; |
struct hardlinks_t *next; |
12 |
int inode; |
int inode; /* TODO: must match maj/min too! */ |
13 |
struct hardlinks_s *next; |
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; |
} hardlinks_t; |
19 |
|
|
20 |
char get_header_cpio(archive_handle_t *archive_handle) |
char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) |
21 |
{ |
{ |
|
static hardlinks_t *saved_hardlinks = NULL; |
|
|
static unsigned short pending_hardlinks = 0; |
|
|
static int inode; |
|
22 |
file_header_t *file_header = archive_handle->file_header; |
file_header_t *file_header = archive_handle->file_header; |
23 |
char cpio_header[110]; |
char cpio_header[110]; |
24 |
int namesize; |
int namesize; |
25 |
char dummy[16]; |
int major, minor, nlink, mode, inode; |
26 |
int major, minor, nlink; |
unsigned size, uid, gid, mtime; |
27 |
|
|
28 |
if (pending_hardlinks) { /* Deal with any pending hardlinks */ |
#define hardlinks_to_create (*(hardlinks_t **)(&archive_handle->ah_priv[0])) |
29 |
hardlinks_t *tmp, *oldtmp; |
#define created_hardlinks (*(hardlinks_t **)(&archive_handle->ah_priv[1])) |
30 |
|
#define block_count (archive_handle->ah_priv[2]) |
31 |
tmp = saved_hardlinks; |
// if (!archive_handle->ah_priv_inited) { |
32 |
oldtmp = NULL; |
// archive_handle->ah_priv_inited = 1; |
33 |
|
// hardlinks_to_create = NULL; |
34 |
file_header->link_name = file_header->name; |
// created_hardlinks = NULL; |
35 |
file_header->size = 0; |
// } |
|
|
|
|
while (tmp) { |
|
|
if (tmp->inode != inode) { |
|
|
tmp = tmp->next; |
|
|
continue; |
|
|
} |
|
|
|
|
|
file_header->name = tmp->name; |
|
|
|
|
|
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { |
|
|
archive_handle->action_data(archive_handle); |
|
|
archive_handle->action_header(archive_handle->file_header); |
|
|
} |
|
|
|
|
|
pending_hardlinks--; |
|
|
|
|
|
oldtmp = tmp; |
|
|
tmp = tmp->next; |
|
|
free(oldtmp->name); |
|
|
free(oldtmp); |
|
|
if (oldtmp == saved_hardlinks) |
|
|
saved_hardlinks = tmp; |
|
|
} |
|
|
|
|
|
file_header->name = file_header->link_name; |
|
|
|
|
|
if (pending_hardlinks > 1) { |
|
|
bb_error_msg("error resolving hardlink: archive made by GNU cpio 2.0-2.2?"); |
|
|
} |
|
|
|
|
|
/* No more pending hardlinks, read next file entry */ |
|
|
pending_hardlinks = 0; |
|
|
} |
|
36 |
|
|
37 |
/* There can be padding before archive header */ |
/* There can be padding before archive header */ |
38 |
data_align(archive_handle, 4); |
data_align(archive_handle, 4); |
39 |
|
|
40 |
if (archive_xread_all_eof(archive_handle, (unsigned char*)cpio_header, 110) == 0) { |
size = full_read(archive_handle->src_fd, cpio_header, 110); |
41 |
return EXIT_FAILURE; |
if (size == 0) { |
42 |
|
goto create_hardlinks; |
43 |
|
} |
44 |
|
if (size != 110) { |
45 |
|
bb_error_msg_and_die("short read"); |
46 |
} |
} |
47 |
archive_handle->offset += 110; |
archive_handle->offset += 110; |
48 |
|
|
52 |
bb_error_msg_and_die("unsupported cpio format, use newc or crc"); |
bb_error_msg_and_die("unsupported cpio format, use newc or crc"); |
53 |
} |
} |
54 |
|
|
55 |
{ |
if (sscanf(cpio_header + 6, |
56 |
unsigned long tmpsize; |
"%8x" "%8x" "%8x" "%8x" |
57 |
sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", |
"%8x" "%8x" "%8x" /*maj,min:*/ "%*16c" |
58 |
dummy, &inode, (unsigned int*)&file_header->mode, |
/*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/, |
59 |
(unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid, |
&inode, &mode, &uid, &gid, |
60 |
&nlink, &file_header->mtime, &tmpsize, |
&nlink, &mtime, &size, |
61 |
dummy, &major, &minor, &namesize, dummy); |
&major, &minor, &namesize) != 10) |
62 |
file_header->size = tmpsize; |
bb_error_msg_and_die("damaged cpio file"); |
63 |
} |
file_header->mode = mode; |
64 |
|
file_header->uid = uid; |
65 |
|
file_header->gid = gid; |
66 |
|
file_header->mtime = mtime; |
67 |
|
file_header->size = size; |
68 |
|
|
69 |
free(file_header->name); |
namesize &= 0x1fff; /* paranoia: limit names to 8k chars */ |
70 |
file_header->name = xzalloc(namesize + 1); |
file_header->name = xzalloc(namesize + 1); |
71 |
/* Read in filename */ |
/* Read in filename */ |
72 |
xread(archive_handle->src_fd, file_header->name, namesize); |
xread(archive_handle->src_fd, file_header->name, namesize); |
76 |
data_align(archive_handle, 4); |
data_align(archive_handle, 4); |
77 |
|
|
78 |
if (strcmp(file_header->name, "TRAILER!!!") == 0) { |
if (strcmp(file_header->name, "TRAILER!!!") == 0) { |
79 |
/* Always round up */ |
/* Always round up. ">> 9" divides by 512 */ |
80 |
printf("%d blocks\n", (int) (archive_handle->offset % 512 ? |
block_count = (void*)(ptrdiff_t) ((archive_handle->offset + 511) >> 9); |
81 |
archive_handle->offset / 512 + 1 : |
goto create_hardlinks; |
|
archive_handle->offset / 512 |
|
|
)); |
|
|
if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */ |
|
|
hardlinks_t *tmp = saved_hardlinks; |
|
|
hardlinks_t *oldtmp = NULL; |
|
|
while (tmp) { |
|
|
bb_error_msg("%s not created: cannot resolve hardlink", tmp->name); |
|
|
oldtmp = tmp; |
|
|
tmp = tmp->next; |
|
|
free(oldtmp->name); |
|
|
free(oldtmp); |
|
|
} |
|
|
saved_hardlinks = NULL; |
|
|
pending_hardlinks = 0; |
|
|
} |
|
|
return EXIT_FAILURE; |
|
82 |
} |
} |
83 |
|
|
84 |
|
file_header->link_target = NULL; |
85 |
if (S_ISLNK(file_header->mode)) { |
if (S_ISLNK(file_header->mode)) { |
86 |
file_header->link_name = xzalloc(file_header->size + 1); |
file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */ |
87 |
xread(archive_handle->src_fd, file_header->link_name, file_header->size); |
file_header->link_target = xzalloc(file_header->size + 1); |
88 |
|
xread(archive_handle->src_fd, file_header->link_target, file_header->size); |
89 |
archive_handle->offset += file_header->size; |
archive_handle->offset += file_header->size; |
90 |
file_header->size = 0; /* Stop possible seeks in future */ |
file_header->size = 0; /* Stop possible seeks in future */ |
|
} else { |
|
|
file_header->link_name = NULL; |
|
91 |
} |
} |
92 |
if (nlink > 1 && !S_ISDIR(file_header->mode)) { |
|
93 |
if (file_header->size == 0) { /* Put file on a linked list for later */ |
// TODO: data_extract_all can't deal with hardlinks to non-files... |
94 |
hardlinks_t *new = xmalloc(sizeof(hardlinks_t)); |
// when fixed, change S_ISREG to !S_ISDIR here |
95 |
new->next = saved_hardlinks; |
|
96 |
new->inode = inode; |
if (nlink > 1 && S_ISREG(file_header->mode)) { |
97 |
/* name current allocated, freed later */ |
hardlinks_t *new = xmalloc(sizeof(*new) + namesize); |
98 |
new->name = file_header->name; |
new->inode = inode; |
99 |
file_header->name = NULL; |
new->mode = mode ; |
100 |
saved_hardlinks = new; |
new->mtime = mtime; |
101 |
|
new->uid = uid ; |
102 |
|
new->gid = gid ; |
103 |
|
strcpy(new->name, file_header->name); |
104 |
|
/* Put file on a linked list for later */ |
105 |
|
if (size == 0) { |
106 |
|
new->next = hardlinks_to_create; |
107 |
|
hardlinks_to_create = new; |
108 |
return EXIT_SUCCESS; /* Skip this one */ |
return EXIT_SUCCESS; /* Skip this one */ |
109 |
|
/* TODO: this breaks cpio -t (it does not show hardlinks) */ |
110 |
} |
} |
111 |
/* Found the file with data in */ |
new->next = created_hardlinks; |
112 |
pending_hardlinks = nlink; |
created_hardlinks = new; |
113 |
} |
} |
114 |
file_header->device = makedev(major, minor); |
file_header->device = makedev(major, minor); |
115 |
|
|
116 |
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { |
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { |
117 |
archive_handle->action_data(archive_handle); |
archive_handle->action_data(archive_handle); |
118 |
archive_handle->action_header(archive_handle->file_header); |
archive_handle->action_header(file_header); |
119 |
} else { |
} else { |
120 |
data_skip(archive_handle); |
data_skip(archive_handle); |
121 |
} |
} |
122 |
|
|
123 |
archive_handle->offset += file_header->size; |
archive_handle->offset += file_header->size; |
124 |
|
|
125 |
free(file_header->link_name); |
free(file_header->link_target); |
126 |
|
free(file_header->name); |
127 |
|
file_header->link_target = NULL; |
128 |
|
file_header->name = NULL; |
129 |
|
|
130 |
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
131 |
|
|
132 |
|
create_hardlinks: |
133 |
|
free(file_header->link_target); |
134 |
|
free(file_header->name); |
135 |
|
|
136 |
|
while (hardlinks_to_create) { |
137 |
|
hardlinks_t *cur; |
138 |
|
hardlinks_t *make_me = hardlinks_to_create; |
139 |
|
|
140 |
|
hardlinks_to_create = make_me->next; |
141 |
|
|
142 |
|
memset(file_header, 0, sizeof(*file_header)); |
143 |
|
file_header->mtime = make_me->mtime; |
144 |
|
file_header->name = make_me->name; |
145 |
|
file_header->mode = make_me->mode; |
146 |
|
file_header->uid = make_me->uid; |
147 |
|
file_header->gid = make_me->gid; |
148 |
|
/*file_header->size = 0;*/ |
149 |
|
/*file_header->link_target = NULL;*/ |
150 |
|
|
151 |
|
/* Try to find a file we are hardlinked to */ |
152 |
|
cur = created_hardlinks; |
153 |
|
while (cur) { |
154 |
|
/* TODO: must match maj/min too! */ |
155 |
|
if (cur->inode == make_me->inode) { |
156 |
|
file_header->link_target = cur->name; |
157 |
|
/* link_target != NULL, size = 0: "I am a hardlink" */ |
158 |
|
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) |
159 |
|
archive_handle->action_data(archive_handle); |
160 |
|
free(make_me); |
161 |
|
goto next_link; |
162 |
|
} |
163 |
|
cur = cur->next; |
164 |
|
} |
165 |
|
/* Oops... no file with such inode was created... do it now |
166 |
|
* (happens when hardlinked files are empty (zero length)) */ |
167 |
|
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) |
168 |
|
archive_handle->action_data(archive_handle); |
169 |
|
/* Move to the list of created hardlinked files */ |
170 |
|
make_me->next = created_hardlinks; |
171 |
|
created_hardlinks = make_me; |
172 |
|
next_link: ; |
173 |
|
} |
174 |
|
|
175 |
|
while (created_hardlinks) { |
176 |
|
hardlinks_t *p = created_hardlinks; |
177 |
|
created_hardlinks = p->next; |
178 |
|
free(p); |
179 |
|
} |
180 |
|
|
181 |
|
return EXIT_FAILURE; /* "No more files to process" */ |
182 |
} |
} |