blob: 725c4911ad71c2e0bfe46d3cfbc61669c7a1036b [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Rob Landley1ec5b292006-05-29 07:42:02 +00002/* Copyright 2002 Laurence Anderson
Glenn L McGrathb72a7352002-12-10 00:17:22 +00003 *
Rob Landley1ec5b292006-05-29 07:42:02 +00004 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGrathb72a7352002-12-10 00:17:22 +00005 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
Eric Andersen4f807a82004-07-26 09:11:12 +000011#include <sys/sysmacros.h> /* major() and minor() */
Glenn L McGrathb72a7352002-12-10 00:17:22 +000012#include "unarchive.h"
13#include "libbb.h"
14
15typedef struct hardlinks_s {
16 file_header_t *entry;
17 int inode;
18 struct hardlinks_s *next;
19} hardlinks_t;
20
Rob Landleydfba7412006-03-06 20:47:33 +000021char get_header_cpio(archive_handle_t *archive_handle)
Glenn L McGrathb72a7352002-12-10 00:17:22 +000022{
23 static hardlinks_t *saved_hardlinks = NULL;
24 static unsigned short pending_hardlinks = 0;
25 file_header_t *file_header = archive_handle->file_header;
26 char cpio_header[110];
27 int namesize;
28 char dummy[16];
29 int major, minor, nlink, inode;
Eric Andersenc7bda1c2004-03-15 08:29:22 +000030
Glenn L McGrathb72a7352002-12-10 00:17:22 +000031 if (pending_hardlinks) { /* Deal with any pending hardlinks */
32 hardlinks_t *tmp;
33 hardlinks_t *oldtmp;
34
35 tmp = saved_hardlinks;
36 oldtmp = NULL;
37
38 while (tmp) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000039 bb_error_msg_and_die("need to fix this\n");
Glenn L McGrathb72a7352002-12-10 00:17:22 +000040 if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
41 file_header = tmp->entry;
42 if (oldtmp) {
43 oldtmp->next = tmp->next; /* Remove item from linked list */
44 } else {
45 saved_hardlinks = tmp->next;
46 }
47 free(tmp);
48 continue;
49 }
50 oldtmp = tmp;
51 tmp = tmp->next;
52 }
53 pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
54 }
55
56 /* There can be padding before archive header */
57 data_align(archive_handle, 4);
58
Eric Andersend78aea82006-01-30 18:00:02 +000059 if (archive_xread_all_eof(archive_handle, (unsigned char*)cpio_header, 110) == 0) {
Glenn L McGrathb72a7352002-12-10 00:17:22 +000060 return(EXIT_FAILURE);
61 }
62 archive_handle->offset += 110;
63
Glenn L McGrath4cee66d2003-08-28 19:12:23 +000064 if ((strncmp(&cpio_header[0], "07070", 5) != 0) || ((cpio_header[5] != '1') && (cpio_header[5] != '2'))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000065 bb_error_msg_and_die("Unsupported cpio format, use newc or crc");
Glenn L McGrathb72a7352002-12-10 00:17:22 +000066 }
67
Eric Andersenf4b273c2002-12-11 21:45:08 +000068 {
69 unsigned long tmpsize;
70 sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
Eric Andersenc7bda1c2004-03-15 08:29:22 +000071 dummy, &inode, (unsigned int*)&file_header->mode,
Eric Andersenf4b273c2002-12-11 21:45:08 +000072 (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid,
73 &nlink, &file_header->mtime, &tmpsize,
74 dummy, &major, &minor, &namesize, dummy);
75 file_header->size = tmpsize;
76 }
Glenn L McGrathb72a7352002-12-10 00:17:22 +000077
Rob Landley1ec5b292006-05-29 07:42:02 +000078 file_header->name = (char *) xzalloc(namesize + 1);
Glenn L McGrathb72a7352002-12-10 00:17:22 +000079 archive_xread_all(archive_handle, file_header->name, namesize); /* Read in filename */
Glenn L McGrathb72a7352002-12-10 00:17:22 +000080 archive_handle->offset += namesize;
81
82 /* Update offset amount and skip padding before file contents */
83 data_align(archive_handle, 4);
84
85 if (strcmp(file_header->name, "TRAILER!!!") == 0) {
86 printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */
87 if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
88 hardlinks_t *tmp = saved_hardlinks;
89 hardlinks_t *oldtmp = NULL;
90 while (tmp) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000091 bb_error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
Glenn L McGrathb72a7352002-12-10 00:17:22 +000092 oldtmp = tmp;
93 tmp = tmp->next;
94 free (oldtmp->entry->name);
95 free (oldtmp->entry);
96 free (oldtmp);
97 }
98 saved_hardlinks = NULL;
99 pending_hardlinks = 0;
100 }
101 return(EXIT_FAILURE);
102 }
103
104 if (S_ISLNK(file_header->mode)) {
Rob Landley1ec5b292006-05-29 07:42:02 +0000105 file_header->link_name = (char *) xzalloc(file_header->size + 1);
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000106 archive_xread_all(archive_handle, file_header->link_name, file_header->size);
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000107 archive_handle->offset += file_header->size;
108 file_header->size = 0; /* Stop possible seeks in future */
Glenn L McGrathfaa35462004-04-29 09:24:19 +0000109 } else {
110 file_header->link_name = NULL;
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000111 }
112 if (nlink > 1 && !S_ISDIR(file_header->mode)) {
113 if (file_header->size == 0) { /* Put file on a linked list for later */
114 hardlinks_t *new = xmalloc(sizeof(hardlinks_t));
115 new->next = saved_hardlinks;
116 new->inode = inode;
117 new->entry = file_header;
118 saved_hardlinks = new;
119 return(EXIT_SUCCESS); // Skip this one
120 } else { /* Found the file with data in */
121 hardlinks_t *tmp = saved_hardlinks;
122 pending_hardlinks = 1;
123 while (tmp) {
124 if (tmp->inode == inode) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000125 tmp->entry->link_name = bb_xstrdup(file_header->name);
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000126 nlink--;
127 }
128 tmp = tmp->next;
129 }
130 if (nlink > 1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000131 bb_error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000132 }
133 }
134 }
Eric Andersen4f807a82004-07-26 09:11:12 +0000135 file_header->device = makedev(major, minor);
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000136
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000137 if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000138 archive_handle->action_data(archive_handle);
Glenn L McGrath4cee66d2003-08-28 19:12:23 +0000139 archive_handle->action_header(archive_handle->file_header);
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000140 } else {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000141 data_skip(archive_handle);
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000142 }
Glenn L McGrath4cee66d2003-08-28 19:12:23 +0000143
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000144 archive_handle->offset += file_header->size;
Glenn L McGrathfaa35462004-04-29 09:24:19 +0000145
146 free(file_header->link_name);
147
Glenn L McGrathb72a7352002-12-10 00:17:22 +0000148 return (EXIT_SUCCESS);
149}