ac01b654487c0ae2c2972ed64a776673aa486337
[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 <errno.h>
15 #ifdef ENABLE_ZLIB_COMPRESSION
16 #include <zlib.h>
17 #endif
18 #ifdef ENABLE_LZMA_COMPRESSION
19 #include <lzma.h>
20 #endif
21 #ifdef ENABLE_ZSTD_COMPRESSION
22 #include <zstd.h>
23 #endif
24
25 #include "pool.h"
26 #include "repo.h"
27 #include "util.h"
28 #include "solver.h"     /* for GET_USERINSTALLED_ flags */
29 #include "chksum.h"
30 #include "repo_deb.h"
31
32 #ifdef _WIN32
33   #include "strfncs.h"
34 #endif
35
36 #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
37 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
38 #endif
39
40 #define MAX_CONTROL_SIZE        0x1000000
41
42 #ifdef ENABLE_ZLIB_COMPRESSION
43
44 static unsigned char *
45 decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
46 {
47   z_stream strm;
48   int outl, ret;
49   unsigned char *bp, *out;
50
51   /* first skip the gz header */
52   if (inl <= 10 || in[0] != 0x1f || in[1] != 0x8b)
53     return 0;
54   if (in[2] != 8 || (in[3] & 0xe0) != 0)
55     return 0;
56   bp = in + 4;
57   bp += 6;      /* skip time, xflags and OS code */
58   if (in[3] & 0x04)
59     {
60       /* skip extra field */
61       int l = bp + 2 >= in + inl ? 0 : (bp[0] | bp[1] << 8);
62       bp += l + 2;
63     }
64   if (in[3] & 0x08)     /* orig filename */
65     while (bp < in + inl && *bp++)
66       ;
67   if (in[3] & 0x10)     /* file comment */
68     while (bp < in + inl && *bp++)
69       ;
70   if (in[3] & 0x02)     /* header crc */
71     bp += 2;
72   if (bp >= in + inl)
73     return 0;
74   inl -= bp - in;
75   in = bp;
76
77   memset(&strm, 0, sizeof(strm));
78   strm.next_in = in;
79   strm.avail_in = inl;
80   out = solv_malloc(4096);
81   strm.next_out = out;
82   strm.avail_out = 4096;
83   outl = 0;
84   ret = inflateInit2(&strm, -MAX_WBITS);
85   if (ret != Z_OK)
86     {
87       free(out);
88       return 0;
89     }
90   for (;;)
91     {
92       if (strm.avail_out == 0)
93         {
94           outl += 4096;
95           if (outl >= maxoutl)
96             {
97               inflateEnd(&strm);
98               free(out);
99               return 0;
100             }
101           out = solv_realloc(out, outl + 4096);
102           strm.next_out = out + outl;
103           strm.avail_out = 4096;
104         }
105       ret = inflate(&strm, Z_NO_FLUSH);
106       if (ret == Z_STREAM_END)
107         break;
108       if (ret != Z_OK)
109         {
110           inflateEnd(&strm);
111           free(out);
112           return 0;
113         }
114     }
115   outl += 4096 - strm.avail_out;
116   inflateEnd(&strm);
117   *outlp = outl;
118   return out;
119 }
120
121 #else
122
123 static unsigned char *
124 decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
125 {
126   return 0;
127 }
128
129 #endif  /* ENABLE_ZLIB_COMPRESSION */
130
131 #ifdef ENABLE_LZMA_COMPRESSION
132
133 static unsigned char *
134 decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
135 {
136   static lzma_stream stream_init = LZMA_STREAM_INIT;
137   lzma_stream strm;
138   int outl, ret;
139   unsigned char *out;
140
141   strm = stream_init;
142   strm.next_in = in;
143   strm.avail_in = inl;
144   out = solv_malloc(4096);
145   strm.next_out = out;
146   strm.avail_out = 4096;
147   outl = 0;
148   ret = lzma_auto_decoder(&strm, 100 << 20, 0);
149   if (ret != LZMA_OK)
150     {
151       free(out);
152       return 0;
153     }
154   for (;;)
155     {
156       if (strm.avail_out == 0)
157         {
158           outl += 4096;
159           if (outl >= maxoutl)
160             {
161               lzma_end(&strm);
162               free(out);
163               return 0;
164             }
165           out = solv_realloc(out, outl + 4096);
166           strm.next_out = out + outl;
167           strm.avail_out = 4096;
168         }
169       ret = lzma_code(&strm, LZMA_RUN);
170       if (ret == LZMA_STREAM_END)
171         break;
172       if (ret != LZMA_OK)
173         {
174           lzma_end(&strm);
175           free(out);
176           return 0;
177         }
178     }
179   outl += 4096 - strm.avail_out;
180   lzma_end(&strm);
181   *outlp = outl;
182   return out;
183 }
184
185 #else
186
187 static unsigned char *
188 decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
189 {
190   return 0;
191 }
192
193 #endif  /* ENABLE_LZMA_COMPRESSION */
194
195 #ifdef ENABLE_ZSTD_COMPRESSION
196
197 static unsigned char *
198 decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
199 {
200   ZSTD_DStream *dstream;
201   ZSTD_inBuffer inbuf;
202   ZSTD_outBuffer outbuf;
203   int ret;
204
205   dstream = ZSTD_createDStream();
206   if (!dstream)
207     return 0;
208   if (ZSTD_isError(ZSTD_initDStream(dstream)))
209     {
210       ZSTD_freeDStream(dstream);
211       return 0;
212     }
213   inbuf.src = in;
214   inbuf.pos = 0;
215   inbuf.size = inl;
216   outbuf.dst = solv_malloc(4096);
217   outbuf.pos = 0;
218   outbuf.size = 4096;
219   for (;;)
220     {
221       if (outbuf.pos == outbuf.size)
222         {
223           outbuf.size += 4096;
224           if (outbuf.size >= maxoutl)
225             {
226               ret = 1;
227               break;
228             }
229           outbuf.dst = solv_realloc(outbuf.dst, outbuf.size + 4096);
230         }
231       ret = ZSTD_decompressStream(dstream, &outbuf, &inbuf);
232       if (ret == 0 && inbuf.pos == inbuf.size)
233         break;
234       if (ZSTD_isError(ret) || (inbuf.pos == inbuf.size && outbuf.pos < outbuf.size))
235         {
236           ret = 1;
237           break;
238         }
239     }
240   ZSTD_freeDStream(dstream);
241   if (ret)
242     {
243       solv_free(outbuf.dst);
244       return 0;
245     }
246   *outlp = outbuf.pos;
247   return outbuf.dst;
248 }
249
250 #else
251
252 static unsigned char *
253 decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
254 {
255   return 0;
256 }
257
258 #endif  /* ENABLE_ZSTD_COMPRESSION */
259
260 static Id
261 parseonedep(Pool *pool, char *p)
262 {
263   char *n, *ne, *e, *ee;
264   Id name, evr;
265   int flags;
266
267   while (*p == ' ' || *p == '\t' || *p == '\n')
268     p++;
269   if (!*p || *p == '(')
270     return 0;
271   n = p;
272   /* find end of name */
273   while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '(' && *p != '|')
274     p++;
275   ne = p;
276   while (*p == ' ' || *p == '\t' || *p == '\n')
277     p++;
278   evr = 0;
279   flags = 0;
280   e = ee = 0;
281   if (*p == '(')
282     {
283       p++;
284       while (*p == ' ' || *p == '\t' || *p == '\n')
285         p++;
286       if (*p == '>')
287         flags |= REL_GT;
288       else if (*p == '=')
289         flags |= REL_EQ;
290       else if (*p == '<')
291         flags |= REL_LT;
292       if (flags)
293         {
294           p++;
295           if (*p == '>')
296             flags |= REL_GT;
297           else if (*p == '=')
298             flags |= REL_EQ;
299           else if (*p == '<')
300             flags |= REL_LT;
301           else
302             p--;
303           p++;
304         }
305       while (*p == ' ' || *p == '\t' || *p == '\n')
306         p++;
307       e = p;
308       while (*p && *p != ' ' && *p != '\t' && *p != '\n' && *p != ')')
309         p++;
310       ee = p;
311       while (*p && *p != ')')
312         p++;
313       if (*p)
314         p++;
315       while (*p == ' ' || *p == '\t' || *p == '\n')
316         p++;
317     }
318   if (ne - n > 4 && ne[-4] == ':' && !strncmp(ne - 4, ":any", 4))
319     {
320       /* multiarch annotation */
321       name = pool_strn2id(pool, n, ne - n - 4, 1);
322       name = pool_rel2id(pool, name, ARCH_ANY, REL_MULTIARCH, 1);
323     }
324   else
325     name = pool_strn2id(pool, n, ne - n, 1);
326   if (e)
327     {
328       evr = pool_strn2id(pool, e, ee - e, 1);
329       name = pool_rel2id(pool, name, evr, flags, 1);
330     }
331   if (*p == '|')
332     {
333       Id id = parseonedep(pool, p + 1);
334       if (id)
335         name = pool_rel2id(pool, name, id, REL_OR, 1);
336     }
337   return name;
338 }
339
340 static unsigned int
341 makedeps(Repo *repo, char *deps, unsigned int olddeps, Id marker)
342 {
343   Pool *pool = repo->pool;
344   char *p;
345   Id id;
346
347   while ((p = strchr(deps, ',')) != 0)
348     {
349       *p = 0;
350       olddeps = makedeps(repo, deps, olddeps, marker);
351       *p = ',';
352       deps = p + 1;
353     }
354   id = parseonedep(pool, deps);
355   if (!id)
356     return olddeps;
357   return repo_addid_dep(repo, olddeps, id, marker);
358 }
359
360
361 /* put data from control file into the solvable */
362 /* warning: does inplace changes */
363 static void
364 control2solvable(Solvable *s, Repodata *data, char *control)
365 {
366   Repo *repo = s->repo;
367   Pool *pool = repo->pool;
368   char *p, *q, *end, *tag;
369   int x, l;
370   int havesource = 0;
371   char checksum[32 * 2 + 1];
372   Id checksumtype = 0;
373   Id newtype;
374
375   p = control;
376   while (*p)
377     {
378       p = strchr(p, '\n');
379       if (!p)
380         break;
381       if (p[1] == ' ' || p[1] == '\t')
382         {
383           char *q;
384           /* continuation line */
385           q = p - 1;
386           while (q >= control && *q == ' ' && *q == '\t')
387             q--;
388           l = q + 1 - control;
389           if (l)
390             memmove(p + 1 - l, control, l);
391           control = p + 1 - l;
392           p[1] = '\n';
393           p += 2;
394           continue;
395         }
396       end = p - 1;
397       if (*p)
398         *p++ = 0;
399       /* strip trailing space */
400       while (end >= control && (*end == ' ' || *end == '\t'))
401         *end-- = 0;
402       tag = control;
403       control = p;
404       q = strchr(tag, ':');
405       if (!q || q - tag < 4)
406         continue;
407       *q++ = 0;
408       while (*q == ' ' || *q == '\t')
409         q++;
410       x = '@' + (tag[0] & 0x1f);
411       x = (x << 8) + '@' + (tag[1] & 0x1f);
412       switch(x)
413         {
414         case 'A' << 8 | 'R':
415           if (!strcasecmp(tag, "architecture"))
416             s->arch = pool_str2id(pool, q, 1);
417           break;
418         case 'B' << 8 | 'R':
419           if (!strcasecmp(tag, "breaks"))
420             s->conflicts = makedeps(repo, q, s->conflicts, 0);
421           break;
422         case 'C' << 8 | 'O':
423           if (!strcasecmp(tag, "conflicts"))
424             s->conflicts = makedeps(repo, q, s->conflicts, 0);
425           break;
426         case 'D' << 8 | 'E':
427           if (!strcasecmp(tag, "depends"))
428             s->requires = makedeps(repo, q, s->requires, -SOLVABLE_PREREQMARKER);
429           else if (!strcasecmp(tag, "description"))
430             {
431               char *ld = strchr(q, '\n');
432               if (ld)
433                 {
434                   *ld++ = 0;
435                   repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, ld);
436                 }
437               else
438                 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, q);
439               repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, q);
440             }
441           break;
442         case 'E' << 8 | 'N':
443           if (!strcasecmp(tag, "enhances"))
444             s->enhances = makedeps(repo, q, s->enhances, 0);
445           break;
446         case 'F' << 8 | 'I':
447           if (!strcasecmp(tag, "filename"))
448             repodata_set_location(data, s - pool->solvables, 0, 0, q);
449           break;
450         case 'H' << 8 | 'O':
451           if (!strcasecmp(tag, "homepage"))
452             repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
453           break;
454         case 'I' << 8 | 'N':
455           if (!strcasecmp(tag, "installed-size"))
456             repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(q, 0, 10) << 10);
457           break;
458         case 'M' << 8 | 'D':
459           if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
460             {
461               strcpy(checksum, q);
462               checksumtype = REPOKEY_TYPE_MD5;
463             }
464           break;
465         case 'P' << 8 | 'A':
466           if (!strcasecmp(tag, "package"))
467             s->name = pool_str2id(pool, q, 1);
468           break;
469         case 'P' << 8 | 'R':
470           if (!strcasecmp(tag, "pre-depends"))
471             s->requires = makedeps(repo, q, s->requires, SOLVABLE_PREREQMARKER);
472           else if (!strcasecmp(tag, "provides"))
473             s->provides = makedeps(repo, q, s->provides, 0);
474           break;
475         case 'R' << 8 | 'E':
476           if (!strcasecmp(tag, "replaces"))
477             s->obsoletes = makedeps(repo, q, s->obsoletes, 0);
478           else if (!strcasecmp(tag, "recommends"))
479             s->recommends = makedeps(repo, q, s->recommends, 0);
480           break;
481         case 'S' << 8 | 'H':
482           newtype = solv_chksum_str2type(tag);
483           if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q))
484             break;
485           if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256)
486             {
487               strcpy(checksum, q);
488               checksumtype = newtype;
489             }
490           break;
491         case 'S' << 8 | 'O':
492           if (!strcasecmp(tag, "source"))
493             {
494               char *q2;
495               /* ignore version for now */
496               for (q2 = q; *q2; q2++)
497                 if (*q2 == ' ' || *q2 == '\t')
498                   {
499                     *q2 = 0;
500                     break;
501                   }
502               if (s->name && !strcmp(q, pool_id2str(pool, s->name)))
503                 repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
504               else
505                 repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1));
506               havesource = 1;
507             }
508           break;
509         case 'S' << 8 | 'T':
510           if (!strcasecmp(tag, "status"))
511             repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q);
512           break;
513         case 'S' << 8 | 'U':
514           if (!strcasecmp(tag, "suggests"))
515             s->suggests = makedeps(repo, q, s->suggests, 0);
516           break;
517         case 'V' << 8 | 'E':
518           if (!strcasecmp(tag, "version"))
519             s->evr = pool_str2id(pool, q, 1);
520           break;
521         }
522     }
523   if (checksumtype)
524     repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
525   if (!s->arch)
526     s->arch = ARCH_ALL;
527   if (!s->evr)
528     s->evr = ID_EMPTY;
529   if (s->name)
530     s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
531   if (s->name && !havesource)
532     repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
533   if (s->obsoletes)
534     {
535       /* obsoletes only count when the packages also conflict */
536       /* XXX: should not transcode here */
537       int i, j, k;
538       Id d, cid;
539       for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
540         {
541           if (!s->conflicts)
542             continue;
543           for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++)
544             {
545               if (repo->idarraydata[k] == cid)
546                 break;
547               if (ISRELDEP(cid))
548                 {
549                   Reldep *rd = GETRELDEP(pool, cid);
550                   if (rd->flags < 8 && rd->name == d)
551                     break;      /* specialize obsoletes */
552                 }
553             }
554           if (cid)
555             repo->idarraydata[j++] = cid;
556         }
557       repo->idarraydata[j] = 0;
558       if (j == s->obsoletes)
559         s->obsoletes = 0;
560     }
561 }
562
563 int
564 repo_add_debpackages(Repo *repo, FILE *fp, int flags)
565 {
566   Pool *pool = repo->pool;
567   Repodata *data;
568   char *buf, *p;
569   int bufl, l, ll;
570   Solvable *s;
571
572   data = repo_add_repodata(repo, flags);
573   buf = solv_malloc(4096);
574   bufl = 4096;
575   l = 0;
576   buf[l] = 0;
577   p = buf;
578   for (;;)
579     {
580       if (!(p = strchr(p, '\n')))
581         {
582           int l3;
583           while (l + 1024 >= bufl)
584             {
585               buf = solv_realloc(buf, bufl + 4096);
586               bufl += 4096;
587             }
588           p = buf + l;
589           ll = fread(p, 1, bufl - l - 1, fp);
590           if (ll <= 0)
591             break;
592           p[ll] = 0;
593           while ((l3 = strlen(p)) < ll)
594             p[l3] = '\n';
595           l += ll;
596           if (p != buf)
597             p--;
598           continue;
599         }
600       p++;
601       if (*p != '\n')
602         continue;
603       *p = 0;
604       ll = p - buf + 1;
605       s = pool_id2solvable(pool, repo_add_solvable(repo));
606       control2solvable(s, data, buf);
607       if (!s->name)
608         s = solvable_free(s, 1);
609       if (l > ll)
610         memmove(buf, p + 1, l - ll);
611       l -= ll;
612       p = buf;
613       buf[l] = 0;
614     }
615   if (l)
616     {
617       s = pool_id2solvable(pool, repo_add_solvable(repo));
618       control2solvable(s, data, buf);
619       if (!s->name)
620         s = solvable_free(s, 1);
621     }
622   solv_free(buf);
623   if (!(flags & REPO_NO_INTERNALIZE))
624     repodata_internalize(data);
625   return 0;
626 }
627
628 int
629 repo_add_debdb(Repo *repo, int flags)
630 {
631   FILE *fp;
632   const char *path = "/var/lib/dpkg/status";
633   if (flags & REPO_USE_ROOTDIR)
634     path = pool_prepend_rootdir_tmp(repo->pool, path);
635   if ((fp = fopen(path, "r")) == 0)
636     return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno));
637   repo_add_debpackages(repo, fp, flags);
638   fclose(fp);
639   return 0;
640 }
641
642 #define CONTROL_COMP_NONE       0
643 #define CONTROL_COMP_GZIP       1
644 #define CONTROL_COMP_XZ         2
645 #define CONTROL_COMP_ZSTD       3
646
647 Id
648 repo_add_deb(Repo *repo, const char *deb, int flags)
649 {
650   Pool *pool = repo->pool;
651   Repodata *data;
652   unsigned char buf[4096], *bp;
653   int l, l2, vlen, clen, ctarlen;
654   int control_comp;
655   unsigned char *ctgz;
656   unsigned char pkgid[16];
657   unsigned char *ctar;
658   int gotpkgid;
659   FILE *fp;
660   Solvable *s;
661   struct stat stb;
662
663   data = repo_add_repodata(repo, flags);
664   if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0)
665     {
666       pool_error(pool, -1, "%s: %s", deb, strerror(errno));
667       return 0;
668     }
669   if (fstat(fileno(fp), &stb))
670     {
671       pool_error(pool, -1, "fstat: %s", strerror(errno));
672       fclose(fp);
673       return 0;
674     }
675   l = fread(buf, 1, sizeof(buf), fp);
676   if (l < 8 + 60 || (strncmp((char *)buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0 && strncmp((char *)buf, "!<arch>\ndebian-binary/  ", 8 + 16) != 0))
677     {
678       pool_error(pool, -1, "%s: not a deb package", deb);
679       fclose(fp);
680       return 0;
681     }
682   vlen = atoi((char *)buf + 8 + 48);
683   if (vlen < 0 || vlen > l)
684     {
685       pool_error(pool, -1, "%s: not a deb package", deb);
686       fclose(fp);
687       return 0;
688     }
689   vlen += vlen & 1;
690   if (l < 8 + 60 + vlen + 60)
691     {
692       pool_error(pool, -1, "%s: unhandled deb package", deb);
693       fclose(fp);
694       return 0;
695     }
696   control_comp = 0;
697   if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16))
698     control_comp = CONTROL_COMP_GZIP;
699   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
700     control_comp = CONTROL_COMP_XZ;
701   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst/", 16))
702     control_comp = CONTROL_COMP_ZSTD;
703   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar     ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/    ", 16))
704     control_comp = CONTROL_COMP_NONE;
705   else
706     {
707       pool_error(pool, -1, "%s: control.tar is not second entry", deb);
708       fclose(fp);
709       return 0;
710     }
711   /* dpkg has no actual maximum size for the control.tar member, so this
712    * just keeps from allocating arbitrarily large amounts of memory.
713    */
714   clen = atoi((char *)buf + 8 + 60 + vlen + 48);
715   if (clen <= 0 || clen >= MAX_CONTROL_SIZE)
716     {
717       pool_error(pool, -1, "%s: control.tar has illegal size", deb);
718       fclose(fp);
719       return 0;
720     }
721   ctgz = solv_calloc(1, clen + 4);
722   bp = buf + 8 + 60 + vlen + 60;
723   l -= 8 + 60 + vlen + 60;
724   if (l > clen)
725     l = clen;
726   if (l)
727     memcpy(ctgz, bp, l);
728   if (l < clen)
729     {
730       if (fread(ctgz + l, clen - l, 1, fp) != 1)
731         {
732           pool_error(pool, -1, "%s: unexpected EOF", deb);
733           solv_free(ctgz);
734           fclose(fp);
735           return 0;
736         }
737     }
738   fclose(fp);
739   gotpkgid = 0;
740   if (flags & DEBS_ADD_WITH_PKGID)
741     {
742       Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5);
743       solv_chksum_add(chk, ctgz, clen);
744       solv_chksum_free(chk, pkgid);
745       gotpkgid = 1;
746     }
747   ctar = 0;
748   if (control_comp == CONTROL_COMP_GZIP)
749     ctar = decompress_gz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
750   else if (control_comp == CONTROL_COMP_XZ)
751     ctar = decompress_xz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
752   else if (control_comp == CONTROL_COMP_ZSTD)
753     ctar = decompress_zstd(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
754   else
755     {
756       ctarlen = clen;
757       ctar = solv_memdup(ctgz, clen);
758     }
759   solv_free(ctgz);
760   if (!ctar)
761     {
762       pool_error(pool, -1, "%s: control.tar decompression error", deb);
763       return 0;
764     }
765   bp = ctar;
766   l = ctarlen;
767   l2 = 0;
768   while (l > 512)
769     {
770       int j;
771       l2 = 0;
772       for (j = 124; j < 124 + 12; j++)
773         if (bp[j] >= '0' && bp[j] <= '7')
774           l2 = l2 * 8 + (bp[j] - '0');
775       if (l2 < 0 || l2 > l)
776         {
777           l2 = 0;
778           break;
779         }
780       bp[124] = 0;
781       if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
782         break;
783       l2 = 512 + ((l2 + 511) & ~511);
784       l -= l2;
785       bp += l2;
786     }
787   if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
788     {
789       pool_error(pool, -1, "%s: control.tar contains no control file", deb);
790       free(ctar);
791       return 0;
792     }
793   memmove(ctar, bp + 512, l2);
794   ctar = solv_realloc(ctar, l2 + 1);
795   ctar[l2] = 0;
796   s = pool_id2solvable(pool, repo_add_solvable(repo));
797   control2solvable(s, data, (char *)ctar);
798   if (!(flags & REPO_NO_LOCATION))
799     repodata_set_location(data, s - pool->solvables, 0, 0, deb);
800   if (S_ISREG(stb.st_mode))
801     repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
802   if (gotpkgid)
803     repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
804   solv_free(ctar);
805   if (!(flags & REPO_NO_INTERNALIZE))
806     repodata_internalize(data);
807   return s - pool->solvables;
808 }
809
810 void
811 pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags)
812 {
813   Id name = 0, arch = 0;
814   int autoinstalled = -1;
815   char *buf, *bp;
816   int x, l, bufl, eof = 0;
817   Id p, pp;
818
819   queue_empty(q);
820   buf = solv_malloc(4096);
821   bufl = 4096;
822   l = 0;
823   while (!eof)
824     {
825       while (bufl - l < 1024)
826         {
827           bufl += 4096;
828           if (bufl > 1024 * 64)
829             break;      /* hmm? */
830           buf = solv_realloc(buf, bufl);
831         }
832       if (!fgets(buf + l, bufl - l, fp))
833         {
834           eof = 1;
835           buf[l] = '\n';
836           buf[l + 1] = 0;
837         }
838       l = strlen(buf);
839       if (l && buf[l - 1] == '\n')
840         buf[--l] = 0;
841       if (!*buf || eof)
842         {
843           l = 0;
844           if (name && autoinstalled > 0)
845             {
846               if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
847                 queue_push2(q, name, arch);
848               else if ((flags & GET_USERINSTALLED_NAMES) != 0)
849                 queue_push(q, name);
850               else
851                 {
852                   FOR_PROVIDES(p, pp, name)
853                     {
854                       Solvable *s = pool->solvables + p;
855                       if (s->name != name)
856                         continue;
857                       if (arch && s->arch != arch)
858                         continue;
859                       queue_push(q, p);
860                     }
861                 }
862             }
863           name = arch = 0;
864           autoinstalled = -1;
865           continue;
866         }
867       /* strip trailing space */
868       while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
869         buf[--l] = 0;
870       l = 0;
871
872       bp = strchr(buf, ':');
873       if (!bp || bp - buf < 4)
874         continue;
875       *bp++ = 0;
876       while (*bp == ' ' || *bp == '\t')
877         bp++;
878       x = '@' + (buf[0] & 0x1f);
879       x = (x << 8) + '@' + (buf[1] & 0x1f);
880       switch(x)
881         {
882         case 'P' << 8 | 'A':
883           if (!strcasecmp(buf, "package"))
884             name = pool_str2id(pool, bp, 1);
885           break;
886         case 'A' << 8 | 'R':
887           if (!strcasecmp(buf, "architecture"))
888             arch = pool_str2id(pool, bp, 1);
889           break;
890         case 'A' << 8 | 'U':
891           if (!strcasecmp(buf, "auto-installed"))
892             autoinstalled = atoi(bp);
893           break;
894         default:
895           break;
896         }
897     }
898     solv_free(buf);
899 }
900