Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/archival/libunarchive/get_header_cpio.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 984 - (hide annotations) (download)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 5915 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 niro 532 /* vi: set sw=4 ts=4: */
2     /* Copyright 2002 Laurence Anderson
3     *
4     * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
5     */
6    
7     #include "libbb.h"
8     #include "unarchive.h"
9    
10 niro 816 typedef 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 niro 532 } hardlinks_t;
19    
20 niro 816 char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
21 niro 532 {
22     file_header_t *file_header = archive_handle->file_header;
23     char cpio_header[110];
24     int namesize;
25 niro 816 int major, minor, nlink, mode, inode;
26     unsigned size, uid, gid, mtime;
27 niro 532
28     /* There can be padding before archive header */
29     data_align(archive_handle, 4);
30    
31 niro 816 size = full_read(archive_handle->src_fd, cpio_header, 110);
32     if (size == 0) {
33     goto create_hardlinks;
34 niro 532 }
35 niro 816 if (size != 110) {
36     bb_error_msg_and_die("short read");
37     }
38 niro 532 archive_handle->offset += 110;
39    
40     if (strncmp(&cpio_header[0], "07070", 5) != 0
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 niro 816 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;
59 niro 532
60 niro 816 namesize &= 0x1fff; /* paranoia: limit names to 8k chars */
61 niro 532 file_header->name = xzalloc(namesize + 1);
62     /* Read in filename */
63     xread(archive_handle->src_fd, file_header->name, namesize);
64 niro 984 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".
68     */
69     char *p = file_header->name;
70     do p++; while (*p == '/');
71     overlapping_strcpy(file_header->name, p);
72     }
73 niro 532 archive_handle->offset += namesize;
74    
75     /* Update offset amount and skip padding before file contents */
76     data_align(archive_handle, 4);
77    
78     if (strcmp(file_header->name, "TRAILER!!!") == 0) {
79 niro 816 /* Always round up. ">> 9" divides by 512 */
80 niro 984 archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9;
81 niro 816 goto create_hardlinks;
82 niro 532 }
83    
84 niro 816 file_header->link_target = NULL;
85 niro 532 if (S_ISLNK(file_header->mode)) {
86 niro 816 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 niro 532 archive_handle->offset += file_header->size;
90     file_header->size = 0; /* Stop possible seeks in future */
91     }
92 niro 816
93     // TODO: data_extract_all can't deal with hardlinks to non-files...
94     // when fixed, change S_ISREG to !S_ISDIR here
95    
96     if (nlink > 1 && S_ISREG(file_header->mode)) {
97     hardlinks_t *new = xmalloc(sizeof(*new) + namesize);
98     new->inode = inode;
99     new->mode = mode ;
100     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 niro 984 new->next = archive_handle->cpio__hardlinks_to_create;
107     archive_handle->cpio__hardlinks_to_create = new;
108 niro 532 return EXIT_SUCCESS; /* Skip this one */
109 niro 816 /* TODO: this breaks cpio -t (it does not show hardlinks) */
110 niro 532 }
111 niro 984 new->next = archive_handle->cpio__created_hardlinks;
112     archive_handle->cpio__created_hardlinks = new;
113 niro 532 }
114     file_header->device = makedev(major, minor);
115    
116     if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
117     archive_handle->action_data(archive_handle);
118 niro 984 //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 niro 816 archive_handle->action_header(file_header);
123 niro 532 } else {
124     data_skip(archive_handle);
125     }
126    
127     archive_handle->offset += file_header->size;
128    
129 niro 816 free(file_header->link_target);
130     free(file_header->name);
131     file_header->link_target = NULL;
132     file_header->name = NULL;
133 niro 532
134     return EXIT_SUCCESS;
135 niro 816
136     create_hardlinks:
137     free(file_header->link_target);
138     free(file_header->name);
139    
140 niro 984 while (archive_handle->cpio__hardlinks_to_create) {
141 niro 816 hardlinks_t *cur;
142 niro 984 hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create;
143 niro 816
144 niro 984 archive_handle->cpio__hardlinks_to_create = make_me->next;
145 niro 816
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;*/
154    
155     /* Try to find a file we are hardlinked to */
156 niro 984 cur = archive_handle->cpio__created_hardlinks;
157 niro 816 while (cur) {
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);
164     free(make_me);
165     goto next_link;
166     }
167     cur = cur->next;
168     }
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 niro 984 make_me->next = archive_handle->cpio__created_hardlinks;
175     archive_handle->cpio__created_hardlinks = make_me;
176 niro 816 next_link: ;
177     }
178    
179 niro 984 while (archive_handle->cpio__created_hardlinks) {
180     hardlinks_t *p = archive_handle->cpio__created_hardlinks;
181     archive_handle->cpio__created_hardlinks = p->next;
182 niro 816 free(p);
183     }
184    
185     return EXIT_FAILURE; /* "No more files to process" */
186 niro 532 }