- add repo_deb.[ch], needed for build service code
[platform/upstream/libsolv.git] / ext / repo_deb.c
1 /*
2  * Copyright (c) 2009, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <zlib.h>
15
16 #include "pool.h"
17 #include "repo.h"
18 #include "util.h"
19 #include "chksum.h"
20 #include "repo_deb.h"
21
22 static unsigned char *
23 decompress(unsigned char *in, int inl, int *outlp)
24 {
25   z_stream strm;
26   int outl, ret;
27   unsigned char *out;
28
29   memset(&strm, 0, sizeof(strm));
30   strm.next_in = in;
31   strm.avail_in = inl;
32   out = sat_malloc(4096);
33   strm.next_out = out;
34   strm.avail_out = 4096;
35   outl = 0;
36   ret = inflateInit2(&strm, -MAX_WBITS);
37   if (ret != Z_OK)
38     {
39       free(out);
40       return 0;
41     }
42   for (;;)
43     {
44       if (strm.avail_out == 0)
45         {
46           outl += 4096;
47           out = sat_realloc(out, outl + 4096);
48           strm.next_out = out + outl;
49           strm.avail_out = 4096;
50         }
51       ret = inflate(&strm, Z_NO_FLUSH);
52       if (ret == Z_STREAM_END)
53         break;
54       if (ret != Z_OK)
55         {
56           free(out);
57           return 0;
58         }
59     }
60   outl += 4096 - strm.avail_out;
61   inflateEnd(&strm);
62   *outlp = outl;
63   return out;
64 }
65
66 static void
67 control2solvable(Solvable *s, char *control)
68 {
69 }
70
71 void
72 repo_add_debs(Repo *repo, const char **debs, int ndebs, int flags)
73 {
74   Pool *pool = repo->pool;
75   Repodata *data;
76   unsigned char buf[4096], *bp;
77   int i, l, l2, vlen, clen, ctarlen;
78   unsigned char *ctgz;
79   unsigned char pkgid[16];
80   unsigned char *ctar;
81   int gotpkgid;
82   FILE *fp;
83   Solvable *s;
84   struct stat stb;
85
86   if (!(flags & REPO_REUSE_REPODATA))
87     data = repo_add_repodata(repo, 0);
88   else
89     data = repo_last_repodata(repo);
90   for (i = 0; i < ndebs; i++)
91     {
92       if ((fp = fopen(debs[i], "r")) == 0)
93         {
94           perror(debs[i]);
95           continue;
96         }
97       if (fstat(fileno(fp), &stb))
98         {
99           perror("stat");
100           continue;
101         }
102       l = fread(buf, 1, sizeof(buf), fp);
103       if (l < 8 + 60 || strncmp(buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0)
104         {
105           fprintf(stderr, "%s: not a deb package\n", debs[i]);
106           fclose(fp);
107           continue;
108         }
109       vlen = atoi(buf + 8 + 48);
110       if (vlen < 0 || vlen > l)
111         {
112           fprintf(stderr, "%s: not a deb package\n", debs[i]);
113           fclose(fp);
114           continue;
115         }
116       vlen += vlen & 1;
117       if (l < 8 + 60 + vlen + 60)
118         {
119           fprintf(stderr, "%s: unhandled deb package\n", debs[i]);
120           fclose(fp);
121           continue;
122         }
123       if (strncmp(buf + 8 + 60 + vlen, "control.tar.gz  ", 16) != 0)
124         {
125           fprintf(stderr, "%s: control.tar.gz is not second entry\n", debs[i]);
126           fclose(fp);
127           continue;
128         }
129       clen = atoi(buf + 8 + 60 + vlen + 48);
130       if (clen <= 0)
131         {
132           fprintf(stderr, "%s: control.tar.gz has illegal size\n", debs[i]);
133           fclose(fp);
134           continue;
135         }
136       ctgz = sat_calloc(1, clen + 4);
137       bp = buf + 8 + 60 + vlen + 60;
138       l -= 8 + 60 + vlen + 60;
139       if (l > clen)
140         l = clen;
141       if (l)
142         memcpy(ctgz, bp, l);
143       if (l < clen)
144         {
145           if (fread(ctgz + l, clen - l, 1, fp) != 1)
146             {
147               fprintf(stderr, "%s: unexpected EOF\n", debs[i]);
148               sat_free(ctgz);
149               fclose(fp);
150               continue;
151             }
152         }
153       fclose(fp);
154       gotpkgid = 0;
155       if (flags & DEBS_ADD_WITH_PKGID)
156         {
157           void *handle = sat_chksum_create(REPOKEY_TYPE_MD5);
158           sat_chksum_add(handle, ctgz, clen);
159           sat_chksum_free(handle, pkgid);
160           gotpkgid = 1;
161         }
162       if (ctgz[0] != 0x1f || ctgz[1] != 0x8b)
163         {
164           fprintf(stderr, "%s: control.tar.gz is not gzipped\n", debs[i]);
165           sat_free(ctgz);
166           continue;
167         }
168       if (ctgz[2] != 8 || (ctgz[3] & 0xe0) != 0)
169         {
170           fprintf(stderr, "%s: control.tar.gz is compressed in a strange way\n", debs[i]);
171           sat_free(ctgz);
172           continue;
173         }
174       bp = ctgz + 4;
175       bp += 6;  /* skip time, xflags and OS code */
176       if (ctgz[3] & 0x04)
177         {
178           /* skip extra field */
179           l = bp[0] | bp[1] << 8;
180           bp += l + 2;
181           if (bp >= ctgz + clen)
182             {
183               fprintf(stderr, "%s: corrupt gzip\n", debs[i]);
184               sat_free(ctgz);
185               continue;
186             }
187         }
188       if (ctgz[3] & 0x08)       /* orig filename */
189         while (*bp)
190           bp++;
191       if (ctgz[3] & 0x10)       /* file comment */
192         while (*bp)
193           bp++;
194       if (ctgz[3] & 0x02)       /* header crc */
195         bp += 2;
196       if (bp >= ctgz + clen)
197         {
198           fprintf(stderr, "%s: corrupt control.tar.gz\n", debs[i]);
199           sat_free(ctgz);
200           continue;
201         }
202       ctar = decompress(bp, ctgz + clen - bp, &ctarlen);
203       sat_free(ctgz);
204       if (!ctar)
205         {
206           fprintf(stderr, "%s: corrupt control.tar.gz\n", debs[i]);
207           continue;
208         }
209       bp = ctar;
210       l = ctarlen;
211       while (l > 512)
212         {
213           int j;
214           l2 = 0;
215           for (j = 124; j < 124 + 12; j++)
216             if (bp[j] >= '0' && bp[j] <= '7')
217               l2 = l2 * 8 + (bp[j] - '0');
218           if (!strcmp(bp, "./control"))
219             break;
220           l2 = 512 + ((l2 + 511) & ~511);
221           l -= l2;
222           bp += l2;
223         }
224       if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
225         {
226           fprintf(stderr, "%s: control.tar.gz contains no ./control file\n", debs[i]);
227           free(ctar);
228           continue;
229         }
230       memmove(ctar, bp + 512, l2);
231       ctar = sat_realloc(ctar, l2 + 1);
232       ctar[l2] = 0;
233       s = pool_id2solvable(pool, repo_add_solvable(repo));
234       control2solvable(s, (char *)ctar);
235       repodata_set_location(data, s - pool->solvables, 0, 0, debs[i]);
236       repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned int)((stb.st_size + 1023) / 1024));
237       if (gotpkgid)
238         repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
239       sat_free(ctar);
240     }
241   if (!(flags & REPO_NO_INTERNALIZE))
242     repodata_internalize(data);
243 }
244
245 int
246 main(int argc, const char **argv)
247 {
248   Pool *pool = pool_create();
249   Repo *repo = repo_create(pool, "debs2solv");
250   repo_add_debs(repo, argv + 1, argc - 1, DEBS_ADD_WITH_PKGID);
251   repo_write(repo, stdout, 0, 0, 0);
252   pool_free(pool);
253 }