"Fossies" - the Fresh Open Source Software Archive 
Member "unipkg-0.6.5/unipkglib/unipkg-rpm.c" (16 Dec 2005, 16641 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 ///////////////////////////////////////////////////////////////////////////////
11 // //
12 // B A S E I N C L U S I O N S A N D D E F I N I T I O N S //
13 // //
14 ///////////////////////////////////////////////////////////////////////////////
15 #define _GNU_SOURCE
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <libgen.h>
23
24 #include <sys/types.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27
28 #ifdef HAVE_SYSMACROS_H
29 #include <sys/sysmacros.h>
30 #endif
31
32 #include <errno.h>
33
34 #include <zlib.h>
35
36 #include "../archive.h"
37 #include "../common.h"
38 #include "../compression.h"
39
40 #define RPMLEAD_MAGIC "\xed\xab\xee\xdb"
41 #define RPMLEAD_MAGICSIZE 4
42 #define RPMLEAD_SIZE 96
43 #define RPMCOMMON_SIZEBLOCK 4
44 #define RPMCOMMON_INDEXSIZE 16
45
46 #define RPMHEADER_MAGIC "\x8e\xad\xe8"
47 #define RPMHEADER_MAGICSIZE 3
48
49 #define RPMTAG_I18NTABLE 100
50 #define RPMTAG_NAME 1000
51 #define RPMTAG_VERSION 1001
52
53 #define RPMHT_NULL 0
54 #define RPMHT_CHAR 1
55 #define RPMHT_INT8 2
56 #define RPMHT_INT16 3
57 #define RPMHT_INT32 4
58 #define RPMHT_INT64 5
59 #define RPMHT_STRING 6
60 #define RPMHT_BIN 7
61 #define RPMHT_STRING_ARRAY 8
62 #define RPMHT_I18NSTRING 9
63
64 #define RAW2DEC(buffer) (256*(256*(256*((unsigned char)((buffer)[0])) + ((unsigned char)((buffer)[1]))) + ((unsigned char)((buffer)[2]))) + ((unsigned char)((buffer)[3])))
65
66 typedef struct {
67 unsigned long tagdef;
68 unsigned long tagdatatype;
69 unsigned long tagdatacount;
70 unsigned long tagdataoffset;
71 } rpmheader;
72
73 ///////////////////////////////////////////////////////////////////////////////
74 // //
75 // B A S E F U N C T I O N S //
76 // //
77 ///////////////////////////////////////////////////////////////////////////////
78
79 // PARSE_RPM_HEADER
80 //
81 // Parses the RPM header
82 //
83 // Parameters:
84 // the header bloxk
85 // pointer to rpm data structure, to which data is written
86 //
87 // Return value:
88 // none
89 static void parse_rpm_header(char *block, rpmheader *chead) {
90 chead->tagdef = RAW2DEC(block);
91 chead->tagdatatype = RAW2DEC(block+4);
92 chead->tagdataoffset = RAW2DEC(block+8);
93 chead->tagdatacount = RAW2DEC(block+12);
94 }
95
96 // COMPRESSIONSWITCH()
97 //
98 // Used to switch for proper compression
99 //
100 // Parameters:
101 // the value of header ID 1125
102 // original compression
103 //
104 // Return value:
105 // new compression
106 static int compressionswitch(const char *header, int compression) {
107 if (!strcmp(header, "gzip")) { return C_GZIP; }
108 if (!strcmp(header, "bzip2")) { return C_BZIP2; }
109 return compression;
110 }
111
112 // ADDFILEWITHDIR()
113 //
114 // Ensures that the directories are properly listed in pkginfo.
115 //
116 // Parameters:
117 // package descriptor
118 // filename
119 //
120 // Return value:
121 // none
122 static void addfilewithdir(pkginfo *pinfo, char *filename, int flag) {
123 char *buf, *ptr, tmpc;
124 unsigned long i, buflen, ofilecount;
125 int found;
126
127 buf = strdup(filename);
128 buflen = strlen(filename);
129
130 ofilecount = pinfo->filecount;
131
132 ptr = buf;
133 tmpc = '\0';
134 while ((ptr = strchr(ptr, '/')) != NULL) {
135 if ((unsigned long)(ptr - buf) < buflen) {
136 tmpc = ptr[1];
137 ptr[1] = '\0';
138 }
139
140 // Ensure adding.
141 found = 0;
142
143 if (ofilecount > 0) {
144 i = ofilecount; // Otherwise a loop occures.
145
146 while (i-- > 0) {
147 if (!strcmp(pinfo->files[i].name, buf)) {
148 found = 1;
149 break;
150 }
151 }
152 }
153
154 if (!found) {
155 addfile(pinfo, strdup(buf), F_DIRECTORY);
156 }
157
158 if ((unsigned long)(ptr - buf) < buflen) {
159 ptr[1] = tmpc;
160 }
161 ptr++;
162 }
163 free(buf);
164
165 addfile(pinfo, filename, flag);
166 }
167
168 ///////////////////////////////////////////////////////////////////////////////
169 // //
170 // A P I F U N C T I O N S //
171 // //
172 ///////////////////////////////////////////////////////////////////////////////
173 int identify(packdef pdef) {
174 char buf[RPMLEAD_MAGICSIZE];
175 unsigned long curpos;
176 if ((curpos = ftell(pdef.filepointer)) == -1) {
177 return 2;
178 }
179 if (fseek(pdef.filepointer, 0, SEEK_SET)) {
180 return 2;
181 }
182
183 if (!fread(buf, RPMLEAD_MAGICSIZE, 1, pdef.filepointer)) {
184 return 2;
185 }
186
187 if (fseek(pdef.filepointer, curpos, SEEK_SET)) {
188 return 2;
189 }
190
191 if (memcmp(buf, RPMLEAD_MAGIC, RPMLEAD_MAGICSIZE) == 0) {
192 return 0;
193 }
194 else {
195 return 1;
196 }
197 }
198
199 int pkgdetails(packdef pdef, pkginfo *pinfo) {
200 void *filemap;
201 struct stat statbuf;
202 off_t offset, store_offset, current_offset;
203 off_t i, indexes, storesize;
204 rpmheader rheader;
205 int cloc_id = 0;
206 unsigned long cloop;
207
208 int err, compression = C_GZIP;
209 c_compdata cstream;
210 comarchive *cpio_archive;
211 char *obuf;
212 unsigned long obuflen;
213
214 fstat(fileno(pdef.filepointer), &statbuf);
215 filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0);
216 if (filemap == MAP_FAILED) { return 1; }
217
218 offset = RPMLEAD_SIZE;
219
220 // We now jump the signatures
221 if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
222 munmap(filemap, statbuf.st_size);
223 return 1;
224 }
225 indexes = RAW2DEC((char*)(filemap + offset + 8));
226 storesize = RAW2DEC((char*)(filemap + offset + 12));
227
228 offset += RPMCOMMON_INDEXSIZE; // Skip the initial header of section
229 offset += RPMCOMMON_INDEXSIZE * indexes + storesize + ((8 - (storesize % 8)) % 8);
230
231 // And arrive at headers
232 if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
233 munmap(filemap, statbuf.st_size);
234 return 1;
235 }
236 indexes = RAW2DEC((char*)(filemap + offset + 8));
237 storesize = RAW2DEC((char*)(filemap + offset + 12));
238
239 offset += RPMCOMMON_INDEXSIZE;
240 store_offset = offset + RPMCOMMON_INDEXSIZE * indexes;
241 for (i = 0; i < indexes; i++) {
242 parse_rpm_header(filemap + offset, &rheader);
243
244 switch (rheader.tagdef) {
245 case 100:
246 // Locale list table.
247 if (rheader.tagdatatype != RPMHT_STRING_ARRAY) continue;
248
249 current_offset = store_offset + rheader.tagdataoffset;
250 for (cloop = 0; cloop < rheader.tagdatacount; cloop++) {
251 if (!strcmp(filemap + current_offset, "C")) {
252 cloc_id = cloop;
253 break;
254 }
255
256 current_offset += strlen(filemap + current_offset) + 1;
257 }
258 break;
259
260 case 1000:
261 if (rheader.tagdatatype != RPMHT_STRING) continue;
262
263 current_offset = store_offset + rheader.tagdataoffset;
264 pinfo->name = strdup(filemap + current_offset);
265 break;
266
267 case 1001:
268 if (rheader.tagdatatype != RPMHT_STRING) continue;
269
270 current_offset = store_offset + rheader.tagdataoffset;
271 pinfo->version = strdup(filemap + current_offset);
272 break;
273
274 case 1004:
275 current_offset = store_offset + rheader.tagdataoffset;
276 switch (rheader.tagdatatype) {
277 case RPMHT_I18NSTRING:
278 for (cloop = 0; cloop < cloc_id; cloop++) {
279 current_offset += strlen(filemap + current_offset) + 1;
280 }
281 pinfo->description = strdup(filemap + current_offset);
282 break;
283 case RPMHT_STRING:
284 pinfo->description = strdup(filemap + current_offset);
285 break;
286 }
287 break;
288
289
290 case 1023:
291 current_offset = store_offset + rheader.tagdataoffset;
292 switch (rheader.tagdatatype) {
293 case RPMHT_STRING:
294 pinfo->preinst.data = strdup(filemap + current_offset);
295 pinfo->preinst.len = strlen(pinfo->preinst.data);
296 break;
297 case RPMHT_BIN:
298 pinfo->preinst.len = rheader.tagdatacount;
299 pinfo->preinst.data = malloc(pinfo->preinst.len);
300 memcpy(pinfo->preinst.data, filemap + current_offset, pinfo->preinst.len);
301 break;
302 }
303 break;
304 case 1024:
305 current_offset = store_offset + rheader.tagdataoffset;
306 switch (rheader.tagdatatype) {
307 case RPMHT_STRING:
308 pinfo->postinst.data = strdup(filemap + current_offset);
309 pinfo->postinst.len = strlen(pinfo->postinst.data);
310 break;
311 case RPMHT_BIN:
312 pinfo->postinst.len = rheader.tagdatacount;
313 pinfo->postinst.data = malloc(pinfo->postinst.len);
314 memcpy(pinfo->postinst.data, filemap + current_offset, pinfo->postinst.len);
315 break;
316 }
317 break;
318 case 1025:
319 current_offset = store_offset + rheader.tagdataoffset;
320 switch (rheader.tagdatatype) {
321 case RPMHT_STRING:
322 pinfo->prerm.data = strdup(filemap + current_offset);
323 pinfo->prerm.len = strlen(pinfo->prerm.data);
324 break;
325 case RPMHT_BIN:
326 pinfo->prerm.len = rheader.tagdatacount;
327 pinfo->prerm.data = malloc(pinfo->prerm.len);
328 memcpy(pinfo->prerm.data, filemap + current_offset, pinfo->prerm.len);
329 break;
330 }
331 break;
332 case 1026:
333 current_offset = store_offset + rheader.tagdataoffset;
334 switch (rheader.tagdatatype) {
335 case RPMHT_STRING:
336 pinfo->postrm.data = strdup(filemap + current_offset);
337 pinfo->postrm.len = strlen(pinfo->postrm.data);
338 break;
339 case RPMHT_BIN:
340 pinfo->postrm.len = rheader.tagdatacount;
341 pinfo->postrm.data = malloc(pinfo->postrm.len);
342 memcpy(pinfo->postrm.data, filemap + current_offset, pinfo->postrm.len);
343 break;
344 }
345 break;
346
347 case 1125:
348 if (rheader.tagdatatype != RPMHT_STRING) continue;
349
350 current_offset = store_offset + rheader.tagdataoffset;
351 compression = compressionswitch(filemap + current_offset, compression);
352 break;
353 }
354
355 offset += RPMCOMMON_INDEXSIZE;
356 }
357 offset += storesize;
358
359 obuflen = 100;
360 obuf = malloc(obuflen);
361
362 err = decompression_setup(&cstream, filemap, offset, statbuf.st_size, obuf, obuflen, C_GZIP);
363 if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) {
364 decompression_cleanup(&cstream);
365 munmap(filemap, statbuf.st_size);
366 free(obuf);
367 return 1;
368 }
369
370 cpio_archive = init_archive(AT_CPIO);
371 do {
372 if (cpio_archive->stage == AS_NEWFILE) {
373 addfilewithdir(pinfo, absolutizestr(cpio_archive->name, "/"), (cpio_archive->ftype == AF_DIRECTORY) ? F_DIRECTORY : F_REGULAR);
374 pinfo->pkgsize += cpio_archive->filesize;
375 }
376
377 update_nextblock(cpio_archive);
378
379 if (cpio_archive->nextblock > obuflen) {
380 obuflen = cpio_archive->nextblock;
381 obuf = realloc(obuf, obuflen);
382 }
383 memset(obuf, 0, obuflen);
384
385 if (decompression_decompress(&cstream, cpio_archive->nextblock, obuf) != CE_OK)
386 break;
387
388 if (decompression_ammount_not_processed(&cstream) > 0)
389 break;
390
391 update_stage(cpio_archive);
392
393 switch (cpio_archive->stage) {
394 case AS_DATA:
395 update_upfilesize(cpio_archive);
396 break;
397 case AS_HEADER:
398 clear_archive_member(cpio_archive);
399 break;
400 }
401
402 err = parse_block(cpio_archive, obuf);
403
404 if (err)
405 break;
406 } while (decompression_ammount_left(&cstream, 0) > 0);
407 deinit_archive(cpio_archive);
408 decompression_cleanup(&cstream);
409 munmap(filemap, statbuf.st_size);
410 free(obuf);
411 return 0;
412 }
413
414 int pkginstall(packdef pdef) {
415 void *filemap;
416 struct stat statbuf;
417 off_t offset, store_offset, current_offset;
418 off_t i, indexes, storesize;
419 rpmheader rheader;
420 int cloc_id = 0;
421 unsigned long cloop;
422
423 int err, compression = C_GZIP;
424 c_compdata cstream;
425 comarchive *cpio_archive;
426 char *obuf;
427 unsigned long obuflen;
428 char *curpath;
429 FILE *fpout;
430
431 fstat(fileno(pdef.filepointer), &statbuf);
432 filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fileno(pdef.filepointer), 0);
433 if (filemap == MAP_FAILED)
434 return 1;
435
436 offset = RPMLEAD_SIZE;
437
438 // We now jump the signatures
439 if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
440 munmap(filemap, statbuf.st_size);
441 return 1;
442 }
443 indexes = RAW2DEC((char*)(filemap + offset + 8));
444 storesize = RAW2DEC((char*)(filemap + offset + 12));
445
446 offset += RPMCOMMON_INDEXSIZE; // Skip the initial header of section
447 offset += RPMCOMMON_INDEXSIZE * indexes + storesize + ((8 - (storesize % 8)) % 8);
448
449 // And arrive at headers
450 if (memcmp(filemap + offset, RPMHEADER_MAGIC, RPMHEADER_MAGICSIZE)) {
451 munmap(filemap, statbuf.st_size);
452 return 1;
453 }
454 indexes = RAW2DEC((char*)(filemap + offset + 8));
455 storesize = RAW2DEC((char*)(filemap + offset + 12));
456
457 offset += RPMCOMMON_INDEXSIZE;
458 offset += RPMCOMMON_INDEXSIZE * indexes + storesize;
459
460 obuflen = 100;
461 obuf = malloc(obuflen);
462
463 err = decompression_setup(&cstream, filemap, offset, statbuf.st_size, obuf, obuflen, C_GZIP);
464 if ((decompression_init(&cstream) != CE_OK) || (err != CE_OK)) {
465 decompression_cleanup(&cstream);
466 munmap(filemap, statbuf.st_size);
467 free(obuf);
468 return 1;
469 }
470
471 fpout = NULL;
472 curpath = NULL;
473
474 cpio_archive = init_archive(AT_CPIO);
475 do {
476 if (cpio_archive->stage == AS_NEWFILE) {
477 free(curpath);
478 curpath = absolutizestr(cpio_archive->name, pdef.destdir);
479 // Create relevant files
480 switch (cpio_archive->ftype) {
481 case AF_REGULAR:
482 if (fpout != NULL) {
483 fclose(fpout);
484 }
485 if ((fpout = fopen(curpath, "w")) == NULL) {
486 free(curpath);
487 free(obuf);
488 decompression_cleanup(&cstream);
489 munmap(filemap, statbuf.st_size);
490 deinit_archive(cpio_archive);
491 return 2;
492 }
493
494 FCHOWNMOD(fileno(fpout), cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
495
496 if (cpio_archive->filesize == 0) {
497 // Nothing to write. We just created it.
498 fclose(fpout);
499 fpout = NULL;
500
501 // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored
502 CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
503 }
504 break;
505 case AF_SYMLINK:
506 symlink(cpio_archive->linktarget, curpath);
507 CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
508 break;
509 case AF_DEVNODE:
510 mknod(curpath, cpio_archive->mode, makedev(cpio_archive->dmajor, cpio_archive->dminor));
511 CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
512 break;
513 case AF_FIFOBUF:
514 mkfifo(curpath, cpio_archive->mode);
515 CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
516 break;
517 case AF_DIRECTORY:
518 if (stat(curpath, &statbuf)) {
519 mkdir(curpath, cpio_archive->mode);
520 CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
521 }
522 break;
523 }
524 }
525
526 update_nextblock(cpio_archive);
527
528 if (cpio_archive->nextblock > obuflen) {
529 obuflen = cpio_archive->nextblock;
530 obuf = realloc(obuf, obuflen);
531 }
532 memset(obuf, 0, obuflen);
533
534 if (decompression_decompress(&cstream, cpio_archive->nextblock, obuf) != CE_OK)
535 break;
536
537 if (decompression_ammount_not_processed(&cstream) > 0)
538 break;
539
540 update_stage(cpio_archive);
541
542 switch (cpio_archive->stage) {
543 case AS_DATA:
544 // Feed data...
545 if (cpio_archive->ftype == AF_REGULAR) {
546 if (fpout != NULL) {
547 fwrite(obuf, ((cpio_archive->filesize - cpio_archive->upfilesize) > cpio_archive->nextblock) ? cpio_archive->nextblock : cpio_archive->filesize - cpio_archive->upfilesize, 1, fpout);
548 }
549 }
550
551 update_upfilesize(cpio_archive);
552 break;
553 case AS_HEADER:
554 // Clear up...
555 if (cpio_archive->ftype == AF_REGULAR) {
556 if (fpout != NULL) {
557 fsync(fileno(fpout));
558 fclose(fpout);
559 fpout = NULL;
560
561 // For SUID and SGID; fchown + file open for writing + suid/sgid = suid/sgid may be ignored
562 CHOWNMOD(curpath, cpio_archive->mode, cpio_archive->uid, cpio_archive->gid);
563 }
564 }
565 clear_archive_member(cpio_archive);
566 break;
567 }
568
569 err = parse_block(cpio_archive, obuf);
570
571 if (err)
572 break;
573 } while (decompression_ammount_left(&cstream, 0) > 0);
574 deinit_archive(cpio_archive);
575 decompression_cleanup(&cstream);
576 munmap(filemap, statbuf.st_size);
577 free(curpath);
578 free(obuf);
579 return 0;
580 }