"Fossies" - the Fresh Open Source Software Archive 
Member "unipkg-0.6.5/archive.c" (16 Dec 2005, 14887 Bytes) of package /linux/privat/old/unipkg-0.6.5.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /******************************************************************************\
2 * *
3 * UniPKG (c) iSteve <isteve@bofh.cz>, 2005 *
4 * *
5 * Universal PacKaGer. *
6 * Licensed under GNU/GPL - if you don't like the software, fix it! *
7 * *
8 \******************************************************************************/
9
10 #define _GNU_SOURCE
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16
17 #include <ctype.h>
18 #include <libgen.h>
19
20 #include <sys/types.h>
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23
24 #include "common.h"
25 #include "archive.h"
26
27 #ifdef HAVE_SYSMACROS_H
28 #include <sys/sysmacros.h>
29 #endif
30
31 typedef struct {
32 char *name;
33 time_t time;
34 uid_t uid;
35 gid_t gid;
36 mode_t mode;
37 off_t filesize;
38 } arheader;
39
40 typedef struct {
41 char *name;
42 mode_t mode;
43 time_t time;
44 uid_t uid;
45 gid_t gid;
46 off_t filesize;
47 char linkflag;
48 char *linktarget;
49 unsigned long devmajor;
50 unsigned long devminor;
51
52 int tarstage; // for GNU tar extensions
53 } tarheader;
54
55 typedef struct {
56 char *name;
57 mode_t mode;
58 uid_t uid;
59 gid_t gid;
60 time_t time;
61 off_t filesize;
62 unsigned long devmajor;
63 unsigned long devminor;
64 off_t namesize;
65
66 off_t archivesize;
67 int pad;
68 } cpioheader;
69
70 ///////////////////////////////////////////////////////////////////////////////
71 // T A R F U N C T I O N S //
72 ///////////////////////////////////////////////////////////////////////////////
73 static tarheader *init_tar_archive(void) {
74 tarheader *rv;
75
76 rv = malloc(sizeof(tarheader));
77 rv->name = NULL;
78 rv->linktarget = NULL;
79 rv->tarstage = 0;
80 rv->linkflag = '\0';
81
82 return rv;
83 }
84
85 static void clear_tar_archive(tarheader *tarhdr) {
86 free(tarhdr->name);
87 free(tarhdr->linktarget);
88 tarhdr->name = NULL;
89 tarhdr->tarstage = 0;
90 tarhdr->linktarget = NULL;
91 }
92
93 ///////////////////////////////////////////////////////////////////////////////
94 // A R F U N C T I O N S //
95 ///////////////////////////////////////////////////////////////////////////////
96 static arheader *init_ar_archive(void) {
97 arheader *rv;
98
99 rv = malloc(sizeof(arheader));
100 rv->name = NULL;
101
102 return rv;
103 }
104
105 static void clear_ar_archive(arheader *arhdr) {
106 free(arhdr->name);
107 arhdr->name = NULL;
108 }
109
110 ///////////////////////////////////////////////////////////////////////////////
111 // C P I O F U N C T I O N S //
112 ///////////////////////////////////////////////////////////////////////////////
113 static cpioheader *init_cpio_archive(void) {
114 cpioheader *rv;
115
116 rv = malloc(sizeof(cpioheader));
117 rv->archivesize = 0;
118 rv->pad = 0;
119 rv->name = NULL;
120
121 return rv;
122 }
123
124 static void clear_cpio_archive(cpioheader *cpiohdr) {
125 free(cpiohdr->name);
126 cpiohdr->name = NULL;
127 }
128
129 ///////////////////////////////////////////////////////////////////////////////
130 // A P I F U N C T I O N S //
131 ///////////////////////////////////////////////////////////////////////////////
132 static unsigned long strtouln(char *src, unsigned long len, int base) {
133 char *tmp;
134 unsigned long rv;
135
136 tmp = strndup(src, len);
137 rv = strtoul(tmp, NULL, base);
138 free(tmp);
139 return rv;
140 }
141
142 static void update_stage_simple(comarchive *carchive) {
143 if (carchive->stage == AS_DATA) {
144 if (carchive->filesize > 0) {
145 if (carchive->upfilesize >= carchive->filesize) {
146 carchive->stage = AS_HEADER;
147 } else {
148 carchive->stage = AS_DATA;
149 }
150 } else {
151 carchive->stage = AS_HEADER;
152 }
153 }
154 }
155
156 comarchive *init_archive(int atype) {
157 comarchive *rv;
158
159 rv = malloc(sizeof(comarchive));
160 rv->atype = atype;
161 rv->internal = NULL;
162
163 switch (rv->atype) {
164 case AT_TAR:
165 rv->internal = init_tar_archive();
166 break;
167 case AT_AR:
168 rv->internal = init_ar_archive();
169 break;
170 case AT_CPIO:
171 rv->internal = init_cpio_archive();
172 break;
173 }
174
175 rv->name = NULL;
176 rv->linktarget = NULL;
177 rv->stage = AS_HEADER;
178 rv->ftype = AF_UNDEFINED;
179 rv->filesize = 0;
180 rv->upfilesize = 0;
181 rv->longheader = 0;
182
183 return rv;
184 }
185
186 void clear_archive_member(comarchive *carchive) {
187 if (carchive->longheader)
188 return;
189
190 switch (carchive->atype) {
191 case AT_TAR:
192 clear_tar_archive(carchive->internal);
193 break;
194 case AT_AR:
195 clear_ar_archive(carchive->internal);
196 break;
197 case AT_CPIO:
198 clear_cpio_archive(carchive->internal);
199 break;
200 }
201
202 free(carchive->name);
203 free(carchive->linktarget);
204
205 carchive->name = NULL;
206 carchive->linktarget = NULL;
207 carchive->ftype = AF_UNDEFINED;
208 carchive->filesize = 0;
209 carchive->upfilesize = 0;
210 }
211
212 void deinit_archive(comarchive *carchive) {
213 clear_archive_member(carchive);
214
215 free(carchive->internal);
216 free(carchive);
217 }
218
219 void update_stage(comarchive *carchive) {
220 if (carchive->stage == AS_NEWFILE)
221 carchive->stage = AS_DATA;
222
223 update_stage_simple(carchive);
224 }
225
226 void update_upfilesize(comarchive *carchive) {
227 switch (carchive->atype) {
228 case AT_CPIO:
229 if (((cpioheader*)(carchive->internal)) -> pad == -1)
230 return; // And thus prevent updating upfilesize;
231 break;
232 }
233 carchive->upfilesize += carchive->nextblock;
234 }
235
236 void update_nextblock(comarchive *carchive) {
237 update_stage(carchive);
238
239 switch (carchive->atype) {
240 case AT_TAR:
241 carchive->nextblock = 512; // Fix size.
242 if (carchive->stage == AS_MOREHEAD) {
243 // We have the long name here. Let's unpack it in one burst.
244 carchive->nextblock = carchive->filesize + TARPAD(carchive->filesize);
245 }
246 break;
247 case AT_AR:
248 switch (carchive->stage) {
249 case AS_HEADER:
250 carchive->nextblock = 60;
251 break;
252 case AS_DATA:
253 // 512 is such a neat blocksize...
254 carchive->nextblock = (carchive->filesize - carchive->upfilesize > 512) ? 512 : carchive->filesize - carchive->upfilesize;
255 break;
256 }
257 break;
258 case AT_CPIO:
259 if ((((cpioheader*)(carchive->internal)) -> pad == 1) && (CPIOPAD(((cpioheader*)(carchive->internal)) -> archivesize))) {
260 carchive->nextblock = CPIOPAD(((cpioheader*)(carchive->internal)) -> archivesize);
261 ((cpioheader*)(carchive->internal)) -> pad = -1;
262 } else {
263 ((cpioheader*)(carchive->internal)) -> pad = 0;
264 switch (carchive->stage) {
265 case AS_HEADER:
266 carchive->nextblock = 110;
267 break;
268 case AS_MOREHEAD:
269 if (carchive->name == NULL) {
270 carchive->nextblock = ((cpioheader*)(carchive->internal)) -> namesize;
271 } else if (carchive->ftype == AF_SYMLINK) {
272 carchive->nextblock = ((cpioheader*)(carchive->internal)) -> filesize;
273 }
274 break;
275 case AS_DATA:
276 if (carchive->filesize - carchive->upfilesize > 512) {
277 carchive->nextblock = 512;
278 } else {
279 carchive->nextblock = carchive->filesize - carchive->upfilesize;
280 carchive->nextblock += CPIOPAD(((cpioheader*)(carchive->internal)) -> archivesize + carchive->nextblock);
281 }
282 break;
283 }
284 }
285 ((cpioheader*)(carchive->internal)) -> archivesize += carchive->nextblock;
286 break;
287 }
288 }
289
290 // Returns 0 on data reading, 1 on file header parsing finished, 2 on end of archive
291 // Sets stage, too; 0 = finished file, need initial header; 1 = need more header, ask nextblock; 2 = reading data.
292 int parse_block(comarchive *carchive, char *block) {
293 int rv;
294
295 if (carchive->stage == AS_DATA)
296 return 0;
297
298 rv = 0;
299
300 // Block is exactly nextblock large.
301 switch (carchive->atype) {
302 case AT_TAR:
303 switch (carchive->stage) {
304 case AS_HEADER:
305 if (block[0] == 0x0) {
306 rv = 2;
307 break;
308 }
309
310 carchive->upfilesize = 0;
311
312 carchive->mode = ((tarheader*)(carchive->internal))->mode = strtouln((block+100), 8, 8);
313 carchive->uid = ((tarheader*)(carchive->internal))->uid = strtouln((block+108), 8, 8);
314 carchive->gid = ((tarheader*)(carchive->internal))->gid = strtouln((block+116), 8, 8);
315 carchive->filesize = ((tarheader*)(carchive->internal))->filesize = strtouln((block+124), 12, 8);
316 carchive->time = ((tarheader*)(carchive->internal))->time = strtouln((block+136), 12, 8);
317 ((tarheader*)(carchive->internal))->linkflag = block[156];
318
319 carchive->dmajor = ((tarheader*)(carchive->internal))->devmajor = strtouln((block+329), 8, 10);
320 carchive->dminor = ((tarheader*)(carchive->internal))->devminor = strtouln((block+337), 8, 10);
321
322 carchive->stage = AS_NEWFILE;
323
324 if (((tarheader*)(carchive->internal))->tarstage == 0) {
325 ((tarheader*)(carchive->internal))->name = strndup(block, 100);
326 carchive->name = strdup(((tarheader*)(carchive->internal))->name);
327
328 ((tarheader*)(carchive->internal))->linktarget = strndup(block+157, 100);
329 carchive->linktarget = strdup(((tarheader*)(carchive->internal))->linktarget);
330 } else {
331 ((tarheader*)(carchive->internal))->tarstage = 0;
332 }
333
334 switch (((tarheader*)(carchive->internal))->linkflag) {
335 // Them bloody GNU tar extensions...
336 case 'L':
337 ((tarheader*)(carchive->internal))->name = realloc(((tarheader*)(carchive->internal))->name, ((tarheader*)(carchive->internal))->filesize+1);
338 carchive->stage = AS_MOREHEAD;
339 ((tarheader*)(carchive->internal))->tarstage = 1;
340 carchive->longheader = 1;
341 break;
342 case 'K':
343 ((tarheader*)(carchive->internal))->linktarget = realloc(((tarheader*)(carchive->internal))->linktarget, ((tarheader*)(carchive->internal))->filesize+1);
344 carchive->stage = AS_MOREHEAD;
345 ((tarheader*)(carchive->internal))->tarstage = 1;
346 carchive->longheader = 1;
347 break;
348
349 case '\0':
350 case '0':
351 carchive->ftype = AF_REGULAR;
352 break;
353 /*case '1':
354 // Hard link
355 break;*/
356 case '2':
357 carchive->ftype = AF_SYMLINK;
358 break;
359 case '3':
360 case '4':
361 carchive->ftype = AF_DEVNODE;
362 break;
363 case '5':
364 carchive->ftype = AF_DIRECTORY;
365 break;
366 case '6':
367 carchive->ftype = AF_FIFOBUF;
368 break;
369 }
370
371 if (carchive->stage == AS_NEWFILE)
372 carchive->longheader = 0;
373
374 break;
375
376 case AS_MOREHEAD:
377 switch (((tarheader*)(carchive->internal))->linkflag) {
378 // Them bloody GNU tar extensions...
379 case 'L':
380 memcpy(((tarheader*)(carchive->internal))->name, block, carchive->filesize);
381 free(carchive->name);
382 carchive->name = strdup(((tarheader*)(carchive->internal))->name);
383 break;
384 case 'K':
385 memcpy(((tarheader*)(carchive->internal))->linktarget, block, carchive->filesize);
386 free(carchive->linktarget);
387 carchive->linktarget = strdup(((tarheader*)(carchive->internal))->linktarget);
388 break;
389 }
390 carchive->stage = AS_HEADER;
391 break;
392 }
393 break;
394
395 case AT_AR:
396 if (carchive->stage == AS_HEADER) {
397 ((arheader*)(carchive->internal))->name = strndup(block, 16);
398 carchive->name = strdup(((arheader*)(carchive->internal))->name);
399
400 carchive->time = ((arheader*)(carchive->internal))->time = strtouln(block + 16, 12, 10);
401
402 carchive->uid = ((arheader*)(carchive->internal))->uid = strtouln(block + 28, 6, 10);
403 carchive->gid = ((arheader*)(carchive->internal))->gid = strtouln(block + 34, 6, 10);
404
405 carchive->mode = ((arheader*)(carchive->internal))->mode = strtouln(block + 40, 8, 8);
406
407 if (S_ISREG(carchive->mode)) carchive->ftype = AF_REGULAR;
408 else if (S_ISDIR(carchive->mode)) carchive->ftype = AF_DIRECTORY;
409 else if (S_ISLNK(carchive->mode)) carchive->ftype = AF_SYMLINK;
410 else if (S_ISFIFO(carchive->mode)) carchive->ftype = AF_FIFOBUF;
411 else if (S_ISSOCK(carchive->mode)) carchive->ftype = AF_SOCKET;
412 else if ((S_ISBLK(carchive->mode)) || (S_ISCHR(carchive->mode))) carchive->ftype = AF_DEVNODE;
413
414 carchive->filesize = ((arheader*)(carchive->internal))->filesize = strtouln(block + 48, 10, 10);
415
416 carchive->stage = AS_NEWFILE;
417 }
418 break;
419 case AT_CPIO:
420 if (((cpioheader*)(carchive->internal)) -> pad == -1) {
421 ((cpioheader*)(carchive->internal)) -> pad = 0;
422 break;
423 }
424
425 switch (carchive->stage) {
426 case AS_HEADER:
427 if ((memcmp(block, "07070", 5)) || ((block[5] != '1') && (block[5] != '2'))) {
428 fprintf(stderr, "block[0] = '%c' = %d\n", block[0], block[0]);
429 return 2;
430 }
431
432 carchive->stage = AS_MOREHEAD;
433 carchive->name = NULL;
434
435 carchive->mode = ((cpioheader*)(carchive->internal))->mode = strtouln(block + 14, 8, 16);
436 carchive->uid = ((cpioheader*)(carchive->internal))->uid = strtouln(block + 22, 8, 16);
437 carchive->gid = ((cpioheader*)(carchive->internal))->gid = strtouln(block + 30, 8, 16);
438
439 carchive->time = ((cpioheader*)(carchive->internal))->time = strtouln(block + 46, 8, 16);
440 carchive->filesize = ((cpioheader*)(carchive->internal))->filesize = strtouln(block + 54, 8, 16);
441
442 carchive->dmajor = ((cpioheader*)(carchive->internal))->devmajor = strtouln(block + 78, 8, 16);
443 carchive->dminor = ((cpioheader*)(carchive->internal))->devminor = strtouln(block + 86, 8, 16);
444
445 ((cpioheader*)(carchive->internal))->namesize = strtouln(block + 94, 8, 16);
446
447 if (S_ISREG(carchive->mode)) carchive->ftype = AF_REGULAR;
448 else if (S_ISDIR(carchive->mode)) carchive->ftype = AF_DIRECTORY;
449 else if (S_ISLNK(carchive->mode)) carchive->ftype = AF_SYMLINK;
450 else if (S_ISFIFO(carchive->mode)) carchive->ftype = AF_FIFOBUF;
451 else if (S_ISSOCK(carchive->mode)) carchive->ftype = AF_SOCKET;
452 else if ((S_ISBLK(carchive->mode)) || (S_ISCHR(carchive->mode))) carchive->ftype = AF_DEVNODE;
453 break;
454 case AS_MOREHEAD:
455 if (carchive->name == NULL) {
456 ((cpioheader*)(carchive->internal))->name = strndup(block, ((cpioheader*)(carchive->internal))->namesize);
457 carchive->name = strdup(((cpioheader*)(carchive->internal))->name);
458
459 if ((carchive->filesize == 0) && (!strcmp(carchive->name, "TRAILER!!!"))) {
460 return 2;
461 }
462
463 if (carchive->ftype != AF_SYMLINK) {
464 carchive->stage = AS_NEWFILE;
465 }
466 } else if (carchive->ftype == AF_SYMLINK) {
467 carchive->linktarget = strndup(block, carchive->filesize);
468 carchive->upfilesize = carchive->filesize;
469 carchive->stage = AS_DATA;
470 }
471 ((cpioheader*)(carchive->internal)) -> pad = 1;
472 break;
473 }
474 break;
475 }
476
477 return rv;
478 }