1 /* vi: set sw=4 ts=4: */
2 /* Copyright 2002 Laurence Anderson
4 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 #include "bb_archive.h"
10 typedef struct hardlinks_t
{
11 struct hardlinks_t
*next
;
12 int inode
; /* TODO: must match maj/min too! */
14 int mtime
; /* These three are useful only in corner case */
15 int uid
; /* of hardlinks with zero size body */
20 char FAST_FUNC
get_header_cpio(archive_handle_t
*archive_handle
)
22 file_header_t
*file_header
= archive_handle
->file_header
;
23 char cpio_header
[110];
25 int major
, minor
, nlink
, mode
, inode
;
26 unsigned size
, uid
, gid
, mtime
;
28 /* There can be padding before archive header */
29 data_align(archive_handle
, 4);
31 size
= full_read(archive_handle
->src_fd
, cpio_header
, 110);
33 goto create_hardlinks
;
36 bb_error_msg_and_die("short read");
38 archive_handle
->offset
+= 110;
40 if (strncmp(&cpio_header
[0], "07070", 5) != 0
41 || (cpio_header
[5] != '1' && cpio_header
[5] != '2')
43 bb_error_msg_and_die("unsupported cpio format, use newc or crc");
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 file_header
->uid
= uid
;
56 file_header
->gid
= gid
;
57 file_header
->mtime
= mtime
;
58 file_header
->size
= size
;
60 namesize
&= 0x1fff; /* paranoia: limit names to 8k chars */
61 file_header
->name
= xzalloc(namesize
+ 1);
62 /* Read in filename */
63 xread(archive_handle
->src_fd
, file_header
->name
, namesize
);
64 if (file_header
->name
[0] == '/') {
65 /* Testcase: echo /etc/hosts | cpio -pvd /tmp
66 * Without this code, it tries to unpack /etc/hosts
67 * into "/etc/hosts", not "etc/hosts".
69 char *p
= file_header
->name
;
70 do p
++; while (*p
== '/');
71 overlapping_strcpy(file_header
->name
, p
);
73 archive_handle
->offset
+= namesize
;
75 /* Update offset amount and skip padding before file contents */
76 data_align(archive_handle
, 4);
78 if (strcmp(file_header
->name
, "TRAILER!!!") == 0) {
79 /* Always round up. ">> 9" divides by 512 */
80 archive_handle
->cpio__blocks
= (uoff_t
)(archive_handle
->offset
+ 511) >> 9;
81 goto create_hardlinks
;
84 file_header
->link_target
= NULL
;
85 if (S_ISLNK(file_header
->mode
)) {
86 file_header
->size
&= 0x1fff; /* paranoia: limit names to 8k chars */
87 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
;
90 file_header
->size
= 0; /* Stop possible seeks in future */
93 // TODO: data_extract_all can't deal with hardlinks to non-files...
94 // when fixed, change S_ISREG to !S_ISDIR here
96 if (nlink
> 1 && S_ISREG(file_header
->mode
)) {
97 hardlinks_t
*new = xmalloc(sizeof(*new) + namesize
);
103 strcpy(new->name
, file_header
->name
);
104 /* Put file on a linked list for later */
106 new->next
= archive_handle
->cpio__hardlinks_to_create
;
107 archive_handle
->cpio__hardlinks_to_create
= new;
108 return EXIT_SUCCESS
; /* Skip this one */
109 /* TODO: this breaks cpio -t (it does not show hardlinks) */
111 new->next
= archive_handle
->cpio__created_hardlinks
;
112 archive_handle
->cpio__created_hardlinks
= new;
114 file_header
->device
= makedev(major
, minor
);
116 if (archive_handle
->filter(archive_handle
) == EXIT_SUCCESS
) {
117 archive_handle
->action_data(archive_handle
);
118 //TODO: run "echo /etc/hosts | cpio -pv /tmp" twice. On 2nd run:
119 //cpio: etc/hosts not created: newer or same age file exists
120 //etc/hosts <-- should NOT show it
121 //2 blocks <-- should say "0 blocks"
122 archive_handle
->action_header(file_header
);
124 data_skip(archive_handle
);
127 archive_handle
->offset
+= file_header
->size
;
129 free(file_header
->link_target
);
130 free(file_header
->name
);
131 file_header
->link_target
= NULL
;
132 file_header
->name
= NULL
;
137 free(file_header
->link_target
);
138 free(file_header
->name
);
140 while (archive_handle
->cpio__hardlinks_to_create
) {
142 hardlinks_t
*make_me
= archive_handle
->cpio__hardlinks_to_create
;
144 archive_handle
->cpio__hardlinks_to_create
= make_me
->next
;
146 memset(file_header
, 0, sizeof(*file_header
));
147 file_header
->mtime
= make_me
->mtime
;
148 file_header
->name
= make_me
->name
;
149 file_header
->mode
= make_me
->mode
;
150 file_header
->uid
= make_me
->uid
;
151 file_header
->gid
= make_me
->gid
;
152 /*file_header->size = 0;*/
153 /*file_header->link_target = NULL;*/
155 /* Try to find a file we are hardlinked to */
156 cur
= archive_handle
->cpio__created_hardlinks
;
158 /* TODO: must match maj/min too! */
159 if (cur
->inode
== make_me
->inode
) {
160 file_header
->link_target
= cur
->name
;
161 /* link_target != NULL, size = 0: "I am a hardlink" */
162 if (archive_handle
->filter(archive_handle
) == EXIT_SUCCESS
)
163 archive_handle
->action_data(archive_handle
);
169 /* Oops... no file with such inode was created... do it now
170 * (happens when hardlinked files are empty (zero length)) */
171 if (archive_handle
->filter(archive_handle
) == EXIT_SUCCESS
)
172 archive_handle
->action_data(archive_handle
);
173 /* Move to the list of created hardlinked files */
174 make_me
->next
= archive_handle
->cpio__created_hardlinks
;
175 archive_handle
->cpio__created_hardlinks
= make_me
;
179 while (archive_handle
->cpio__created_hardlinks
) {
180 hardlinks_t
*p
= archive_handle
->cpio__created_hardlinks
;
181 archive_handle
->cpio__created_hardlinks
= p
->next
;
185 return EXIT_FAILURE
; /* "No more files to process" */