1 /* vi: set sw=4 ts=4: */
2 /* Copyright 2002 Laurence Anderson
4 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
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 #define hardlinks_to_create (*(hardlinks_t **)(&archive_handle->ah_priv[0]))
29 #define created_hardlinks (*(hardlinks_t **)(&archive_handle->ah_priv[1]))
30 #define block_count (archive_handle->ah_priv[2])
31 // if (!archive_handle->ah_priv_inited) {
32 // archive_handle->ah_priv_inited = 1;
33 // hardlinks_to_create = NULL;
34 // created_hardlinks = NULL;
37 /* There can be padding before archive header */
38 data_align(archive_handle
, 4);
40 size
= full_read(archive_handle
->src_fd
, cpio_header
, 110);
42 goto create_hardlinks
;
45 bb_error_msg_and_die("short read");
47 archive_handle
->offset
+= 110;
49 if (strncmp(&cpio_header
[0], "07070", 5) != 0
50 || (cpio_header
[5] != '1' && cpio_header
[5] != '2')
52 bb_error_msg_and_die("unsupported cpio format, use newc or crc");
55 if (sscanf(cpio_header
+ 6,
56 "%8x" "%8x" "%8x" "%8x"
57 "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c"
58 /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/,
59 &inode
, &mode
, &uid
, &gid
,
60 &nlink
, &mtime
, &size
,
61 &major
, &minor
, &namesize
) != 10)
62 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
;
69 namesize
&= 0x1fff; /* paranoia: limit names to 8k chars */
70 file_header
->name
= xzalloc(namesize
+ 1);
71 /* Read in filename */
72 xread(archive_handle
->src_fd
, file_header
->name
, namesize
);
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 block_count
= (void*)(ptrdiff_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
= hardlinks_to_create
;
107 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
= created_hardlinks
;
112 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 archive_handle
->action_header(file_header
);
120 data_skip(archive_handle
);
123 archive_handle
->offset
+= file_header
->size
;
125 free(file_header
->link_target
);
126 free(file_header
->name
);
127 file_header
->link_target
= NULL
;
128 file_header
->name
= NULL
;
133 free(file_header
->link_target
);
134 free(file_header
->name
);
136 while (hardlinks_to_create
) {
138 hardlinks_t
*make_me
= hardlinks_to_create
;
140 hardlinks_to_create
= make_me
->next
;
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;*/
151 /* Try to find a file we are hardlinked to */
152 cur
= created_hardlinks
;
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
);
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
;
175 while (created_hardlinks
) {
176 hardlinks_t
*p
= created_hardlinks
;
177 created_hardlinks
= p
->next
;
181 return EXIT_FAILURE
; /* "No more files to process" */