d400f9592e0a5deb5bba8a29dd612dbe99c5705c
[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 'M' << 8 | 'U':
466           if (!strcasecmp(tag, "multi-arch"))
467             repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_MULTIARCH, q);
468           break;
469         case 'P' << 8 | 'A':
470           if (!strcasecmp(tag, "package"))
471             s->name = pool_str2id(pool, q, 1);
472           break;
473         case 'P' << 8 | 'R':
474           if (!strcasecmp(tag, "pre-depends"))
475             s->requires = makedeps(repo, q, s->requires, SOLVABLE_PREREQMARKER);
476           else if (!strcasecmp(tag, "provides"))
477             s->provides = makedeps(repo, q, s->provides, 0);
478           break;
479         case 'R' << 8 | 'E':
480           if (!strcasecmp(tag, "replaces"))
481             s->obsoletes = makedeps(repo, q, s->obsoletes, 0);
482           else if (!strcasecmp(tag, "recommends"))
483             s->recommends = makedeps(repo, q, s->recommends, 0);
484           break;
485         case 'S' << 8 | 'H':
486           newtype = solv_chksum_str2type(tag);
487           if (!newtype || solv_chksum_len(newtype) * 2 != strlen(q))
488             break;
489           if (!checksumtype || (newtype == REPOKEY_TYPE_SHA1 && checksumtype != REPOKEY_TYPE_SHA256) || newtype == REPOKEY_TYPE_SHA256)
490             {
491               strcpy(checksum, q);
492               checksumtype = newtype;
493             }
494           break;
495         case 'S' << 8 | 'O':
496           if (!strcasecmp(tag, "source"))
497             {
498               char *q2;
499               /* ignore version for now */
500               for (q2 = q; *q2; q2++)
501                 if (*q2 == ' ' || *q2 == '\t')
502                   {
503                     *q2 = 0;
504                     break;
505                   }
506               if (s->name && !strcmp(q, pool_id2str(pool, s->name)))
507                 repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
508               else
509                 repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, pool_str2id(pool, q, 1));
510               havesource = 1;
511             }
512           break;
513         case 'S' << 8 | 'T':
514           if (!strcasecmp(tag, "status"))
515             repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_INSTALLSTATUS, q);
516           break;
517         case 'S' << 8 | 'U':
518           if (!strcasecmp(tag, "suggests"))
519             s->suggests = makedeps(repo, q, s->suggests, 0);
520           break;
521         case 'V' << 8 | 'E':
522           if (!strcasecmp(tag, "version"))
523             s->evr = pool_str2id(pool, q, 1);
524           break;
525         }
526     }
527   if (checksumtype)
528     repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
529   if (!s->arch)
530     s->arch = ARCH_ALL;
531   if (!s->evr)
532     s->evr = ID_EMPTY;
533   if (s->name)
534     s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
535   if (s->name && !havesource)
536     repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
537   if (s->obsoletes)
538     {
539       /* obsoletes only count when the packages also conflict */
540       /* XXX: should not transcode here */
541       int i, j, k;
542       Id d, cid;
543       for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
544         {
545           if (!s->conflicts)
546             continue;
547           for (k = s->conflicts; (cid = repo->idarraydata[k]) != 0; k++)
548             {
549               if (repo->idarraydata[k] == cid)
550                 break;
551               if (ISRELDEP(cid))
552                 {
553                   Reldep *rd = GETRELDEP(pool, cid);
554                   if (rd->flags < 8 && rd->name == d)
555                     break;      /* specialize obsoletes */
556                 }
557             }
558           if (cid)
559             repo->idarraydata[j++] = cid;
560         }
561       repo->idarraydata[j] = 0;
562       if (j == s->obsoletes)
563         s->obsoletes = 0;
564     }
565 }
566
567 int
568 repo_add_debpackages(Repo *repo, FILE *fp, int flags)
569 {
570   Pool *pool = repo->pool;
571   Repodata *data;
572   char *buf, *p;
573   int bufl, l, ll;
574   Solvable *s;
575
576   data = repo_add_repodata(repo, flags);
577   buf = solv_malloc(4096);
578   bufl = 4096;
579   l = 0;
580   buf[l] = 0;
581   p = buf;
582   for (;;)
583     {
584       if (!(p = strchr(p, '\n')))
585         {
586           int l3;
587           while (l + 1024 >= bufl)
588             {
589               buf = solv_realloc(buf, bufl + 4096);
590               bufl += 4096;
591             }
592           p = buf + l;
593           ll = fread(p, 1, bufl - l - 1, fp);
594           if (ll <= 0)
595             break;
596           p[ll] = 0;
597           while ((l3 = strlen(p)) < ll)
598             p[l3] = '\n';
599           l += ll;
600           if (p != buf)
601             p--;
602           continue;
603         }
604       p++;
605       if (*p != '\n')
606         continue;
607       *p = 0;
608       ll = p - buf + 1;
609       s = pool_id2solvable(pool, repo_add_solvable(repo));
610       control2solvable(s, data, buf);
611       if (!s->name)
612         s = solvable_free(s, 1);
613       if (l > ll)
614         memmove(buf, p + 1, l - ll);
615       l -= ll;
616       p = buf;
617       buf[l] = 0;
618     }
619   if (l)
620     {
621       s = pool_id2solvable(pool, repo_add_solvable(repo));
622       control2solvable(s, data, buf);
623       if (!s->name)
624         s = solvable_free(s, 1);
625     }
626   solv_free(buf);
627   if (!(flags & REPO_NO_INTERNALIZE))
628     repodata_internalize(data);
629   return 0;
630 }
631
632 int
633 repo_add_debdb(Repo *repo, int flags)
634 {
635   FILE *fp;
636   const char *path = "/var/lib/dpkg/status";
637   if (flags & REPO_USE_ROOTDIR)
638     path = pool_prepend_rootdir_tmp(repo->pool, path);
639   if ((fp = fopen(path, "r")) == 0)
640     return pool_error(repo->pool, -1, "%s: %s", path, strerror(errno));
641   repo_add_debpackages(repo, fp, flags);
642   fclose(fp);
643   return 0;
644 }
645
646 #define CONTROL_COMP_NONE       0
647 #define CONTROL_COMP_GZIP       1
648 #define CONTROL_COMP_XZ         2
649 #define CONTROL_COMP_ZSTD       3
650
651 Id
652 repo_add_deb(Repo *repo, const char *deb, int flags)
653 {
654   Pool *pool = repo->pool;
655   Repodata *data;
656   unsigned char buf[4096], *bp;
657   int l, l2, vlen, clen, ctarlen;
658   int control_comp;
659   unsigned char *ctgz;
660   unsigned char pkgid[16];
661   unsigned char *ctar;
662   int gotpkgid;
663   FILE *fp;
664   Solvable *s;
665   struct stat stb;
666
667   data = repo_add_repodata(repo, flags);
668   if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, deb) : deb, "r")) == 0)
669     {
670       pool_error(pool, -1, "%s: %s", deb, strerror(errno));
671       return 0;
672     }
673   if (fstat(fileno(fp), &stb))
674     {
675       pool_error(pool, -1, "fstat: %s", strerror(errno));
676       fclose(fp);
677       return 0;
678     }
679   l = fread(buf, 1, sizeof(buf), fp);
680   if (l < 8 + 60 || (strncmp((char *)buf, "!<arch>\ndebian-binary   ", 8 + 16) != 0 && strncmp((char *)buf, "!<arch>\ndebian-binary/  ", 8 + 16) != 0))
681     {
682       pool_error(pool, -1, "%s: not a deb package", deb);
683       fclose(fp);
684       return 0;
685     }
686   vlen = atoi((char *)buf + 8 + 48);
687   if (vlen < 0 || vlen > l)
688     {
689       pool_error(pool, -1, "%s: not a deb package", deb);
690       fclose(fp);
691       return 0;
692     }
693   vlen += vlen & 1;
694   if (l < 8 + 60 + vlen + 60)
695     {
696       pool_error(pool, -1, "%s: unhandled deb package", deb);
697       fclose(fp);
698       return 0;
699     }
700   control_comp = 0;
701   if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.gz/ ", 16))
702     control_comp = CONTROL_COMP_GZIP;
703   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
704     control_comp = CONTROL_COMP_XZ;
705   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst/", 16))
706     control_comp = CONTROL_COMP_ZSTD;
707   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar     ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/    ", 16))
708     control_comp = CONTROL_COMP_NONE;
709   else
710     {
711       pool_error(pool, -1, "%s: control.tar is not second entry", deb);
712       fclose(fp);
713       return 0;
714     }
715   /* dpkg has no actual maximum size for the control.tar member, so this
716    * just keeps from allocating arbitrarily large amounts of memory.
717    */
718   clen = atoi((char *)buf + 8 + 60 + vlen + 48);
719   if (clen <= 0 || clen >= MAX_CONTROL_SIZE)
720     {
721       pool_error(pool, -1, "%s: control.tar has illegal size", deb);
722       fclose(fp);
723       return 0;
724     }
725   ctgz = solv_calloc(1, clen + 4);
726   bp = buf + 8 + 60 + vlen + 60;
727   l -= 8 + 60 + vlen + 60;
728   if (l > clen)
729     l = clen;
730   if (l)
731     memcpy(ctgz, bp, l);
732   if (l < clen)
733     {
734       if (fread(ctgz + l, clen - l, 1, fp) != 1)
735         {
736           pool_error(pool, -1, "%s: unexpected EOF", deb);
737           solv_free(ctgz);
738           fclose(fp);
739           return 0;
740         }
741     }
742   fclose(fp);
743   gotpkgid = 0;
744   if (flags & DEBS_ADD_WITH_PKGID)
745     {
746       Chksum *chk = solv_chksum_create(REPOKEY_TYPE_MD5);
747       solv_chksum_add(chk, ctgz, clen);
748       solv_chksum_free(chk, pkgid);
749       gotpkgid = 1;
750     }
751   ctar = 0;
752   if (control_comp == CONTROL_COMP_GZIP)
753     ctar = decompress_gz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
754   else if (control_comp == CONTROL_COMP_XZ)
755     ctar = decompress_xz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
756   else if (control_comp == CONTROL_COMP_ZSTD)
757     ctar = decompress_zstd(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
758   else
759     {
760       ctarlen = clen;
761       ctar = solv_memdup(ctgz, clen);
762     }
763   solv_free(ctgz);
764   if (!ctar)
765     {
766       pool_error(pool, -1, "%s: control.tar decompression error", deb);
767       return 0;
768     }
769   bp = ctar;
770   l = ctarlen;
771   l2 = 0;
772   while (l > 512)
773     {
774       int j;
775       l2 = 0;
776       for (j = 124; j < 124 + 12; j++)
777         if (bp[j] >= '0' && bp[j] <= '7')
778           l2 = l2 * 8 + (bp[j] - '0');
779       if (l2 < 0 || l2 > l)
780         {
781           l2 = 0;
782           break;
783         }
784       bp[124] = 0;
785       if (!strcmp((char *)bp, "./control") || !strcmp((char *)bp, "control"))
786         break;
787       l2 = 512 + ((l2 + 511) & ~511);
788       l -= l2;
789       bp += l2;
790     }
791   if (l <= 512 || l - 512 - l2 <= 0 || l2 <= 0)
792     {
793       pool_error(pool, -1, "%s: control.tar contains no control file", deb);
794       free(ctar);
795       return 0;
796     }
797   memmove(ctar, bp + 512, l2);
798   ctar = solv_realloc(ctar, l2 + 1);
799   ctar[l2] = 0;
800   s = pool_id2solvable(pool, repo_add_solvable(repo));
801   control2solvable(s, data, (char *)ctar);
802   if (!(flags & REPO_NO_LOCATION))
803     repodata_set_location(data, s - pool->solvables, 0, 0, deb);
804   if (S_ISREG(stb.st_mode))
805     repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
806   if (gotpkgid)
807     repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
808   solv_free(ctar);
809   if (!(flags & REPO_NO_INTERNALIZE))
810     repodata_internalize(data);
811   return s - pool->solvables;
812 }
813
814 void
815 pool_deb_get_autoinstalled(Pool *pool, FILE *fp, Queue *q, int flags)
816 {
817   Id name = 0, arch = 0;
818   int autoinstalled = -1;
819   char *buf, *bp;
820   int x, l, bufl, eof = 0;
821   Id p, pp;
822
823   queue_empty(q);
824   buf = solv_malloc(4096);
825   bufl = 4096;
826   l = 0;
827   while (!eof)
828     {
829       while (bufl - l < 1024)
830         {
831           bufl += 4096;
832           if (bufl > 1024 * 64)
833             break;      /* hmm? */
834           buf = solv_realloc(buf, bufl);
835         }
836       if (!fgets(buf + l, bufl - l, fp))
837         {
838           eof = 1;
839           buf[l] = '\n';
840           buf[l + 1] = 0;
841         }
842       l = strlen(buf);
843       if (l && buf[l - 1] == '\n')
844         buf[--l] = 0;
845       if (!*buf || eof)
846         {
847           l = 0;
848           if (name && autoinstalled > 0)
849             {
850               if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
851                 queue_push2(q, name, arch);
852               else if ((flags & GET_USERINSTALLED_NAMES) != 0)
853                 queue_push(q, name);
854               else
855                 {
856                   FOR_PROVIDES(p, pp, name)
857                     {
858                       Solvable *s = pool->solvables + p;
859                       if (s->name != name)
860                         continue;
861                       if (arch && s->arch != arch)
862                         continue;
863                       queue_push(q, p);
864                     }
865                 }
866             }
867           name = arch = 0;
868           autoinstalled = -1;
869           continue;
870         }
871       /* strip trailing space */
872       while (l && (buf[l - 1] == ' ' || buf[l - 1] == '\t'))
873         buf[--l] = 0;
874       l = 0;
875
876       bp = strchr(buf, ':');
877       if (!bp || bp - buf < 4)
878         continue;
879       *bp++ = 0;
880       while (*bp == ' ' || *bp == '\t')
881         bp++;
882       x = '@' + (buf[0] & 0x1f);
883       x = (x << 8) + '@' + (buf[1] & 0x1f);
884       switch(x)
885         {
886         case 'P' << 8 | 'A':
887           if (!strcasecmp(buf, "package"))
888             name = pool_str2id(pool, bp, 1);
889           break;
890         case 'A' << 8 | 'R':
891           if (!strcasecmp(buf, "architecture"))
892             arch = pool_str2id(pool, bp, 1);
893           break;
894         case 'A' << 8 | 'U':
895           if (!strcasecmp(buf, "auto-installed"))
896             autoinstalled = atoi(bp);
897           break;
898         default:
899           break;
900         }
901     }
902     solv_free(buf);
903 }
904