- fix mem leak in arch code
[platform/upstream/libsolv.git] / ext / repo_arch.c
1 /*
2  * Copyright (c) 2012, 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 #include <fcntl.h>
16
17 #include "pool.h"
18 #include "repo.h"
19 #include "util.h"
20 #include "chksum.h"
21 #include "solv_xfopen.h"
22 #include "repo_arch.h"
23
24 static long long parsenum(unsigned char *p, int cnt)
25 {
26   long long x = 0;
27   if (!cnt)
28     return -1;
29   if (*p & 0x80)
30     {
31       /* binary format */
32       x = *p & 0x40 ? (-1 << 8 | *p)  : (*p ^ 0x80);
33       while (--cnt > 0)
34         x = (x << 8) | *p++;
35       return x;
36     }
37   while (cnt > 0 && (*p == ' ' || *p == '\t'))
38     cnt--, p++;
39   if (*p == '-')
40     return -1;
41   for (; cnt > 0 && *p >= '0' && *p < '8'; cnt--, p++)
42     x = (x << 3) | (*p - '0');
43   return x;
44 }
45
46 static int readblock(FILE *fp, unsigned char *blk)
47 {
48   int r, l = 0;
49   while (l < 512)
50     {
51       r = fread(blk + l, 1, 512 - l, fp);
52       if (r <= 0)
53         return -1;
54       l += r;
55     }
56   return 0;
57 }
58
59 struct tarhead {
60   FILE *fp;
61   unsigned char blk[512];
62   int type;
63   long long length;
64   char *path;
65   int eof;
66   int ispax;
67   int off;
68   int end;
69 };
70
71 static char *getsentry(struct tarhead *th, char *s, int size)
72 {
73   char *os = s;
74   if (th->eof || size <= 1)
75     return 0;
76   size--;       /* terminating 0 */
77   for (;;)
78     {
79       int i;
80       for (i = th->off; i < th->end; i++)
81         {
82           *s++ = th->blk[i];
83           size--;
84           if (!size || th->blk[i] == '\n')
85             {
86               th->off = i + 1;
87               *s = 0;
88               return os;
89             }
90         }
91       th->off = i;
92       if (th->length <= 0)
93         return 0;
94       if (readblock(th->fp, th->blk))
95         {
96           th->eof = 1;
97           return 0;
98         }
99       th->off = 0;
100       th->end = th->length > 512 ? 512 : th->length;
101       th->length -= th->end;
102     }
103 }
104
105 static void skipentry(struct tarhead *th)
106 {
107   for (; th->length > 0; th->length -= 512)
108     {
109       if (readblock(th->fp, th->blk))
110         {
111           th->eof = 1;
112           th->length = 0;
113           return;
114         }
115     }
116   th->length = 0;
117   th->off = th->end = 0;
118 }
119
120 static void inittarhead(struct tarhead *th, FILE *fp)
121 {
122   memset(th, 0, sizeof(*th));
123   th->fp = fp;
124 }
125
126 static void freetarhead(struct tarhead *th)
127 {
128   solv_free(th->path);
129 }
130
131 static int gettarhead(struct tarhead *th)
132 {
133   int l, type;
134   long long length;
135
136   th->path = solv_free(th->path);
137   th->ispax = 0;
138   th->type = 0;
139   th->length = 0;
140   th->off = 0;
141   th->end = 0;
142   if (th->eof)
143     return 0;
144   for (;;)
145     {
146       int r = readblock(th->fp, th->blk);
147       if (r)
148         {
149           if (feof(th->fp))
150             {
151               th->eof = 1;
152               return 0;
153             }
154           return -1;
155         }
156       if (th->blk[0] == 0)
157         {
158           th->eof = 1;
159           return 0;
160         }
161       length = parsenum(th->blk + 124, 12);
162       if (length < 0)
163         return -1;
164       type = 0;
165       switch (th->blk[156])
166         {
167         case 'S': case '0':
168           type = 1;     /* file */
169           break;
170         case '1':
171           /* hard link, special length magic... */
172           if (!th->ispax)
173             length = 0;
174           break;
175         case '5':
176           type = 2;     /* dir */
177           break;
178         case '2': case '3': case '4': case '6':
179           length = 0;
180           break;
181         case 'X': case 'x': case 'L':
182           {
183             char *data, *pp;
184             if (length < 1 || length >= 1024 * 1024)
185               return -1;
186             l = length;
187             data = pp = solv_malloc(l + 512);
188             for (; l > 0; l -= 512, pp += 512)
189               if (readblock(th->fp, (unsigned char *)pp))
190                 {
191                   solv_free(data);
192                   return -1;
193                 }
194             type = 3;           /* extension */
195             if (th->blk[156] == 'L')
196               {
197                 solv_free(th->path);
198                 th->path = data;
199                 length = 0;
200                 break;
201               }
202             pp = data;
203             while (length > 0)
204               {
205                 int ll = 0;
206                 int l;
207                 for (l = 0; l < length && pp[l] >= '0' && pp[l] <= '9'; l++)
208                   ll = ll * 10 + (pp[l] - '0');
209                 if (l == length || pp[l] != ' ' || ll < 1 || ll > length || pp[ll - 1] != '\n')
210                   {
211                     solv_free(data);
212                     return -1;
213                   }
214                 length -= ll;
215                 pp += l + 1;
216                 ll -= l + 1;
217                 pp[ll - 1] = 0;
218                 if (!strncmp(pp, "path=", 5))
219                   {
220                     solv_free(th->path);
221                     th->path = solv_strdup(pp + 5);
222                   }
223                 pp += ll;
224               }
225             solv_free(data);
226             th->ispax = 1;
227             length = 0;
228             break;
229           }
230         default:
231           type = 3;     /* extension */
232           break;
233         }
234       if ((type == 1 || type == 2) && !th->path)
235         {
236           char path[157];
237           memcpy(path, th->blk, 156);
238           path[156] = 0;
239           if (!memcmp(th->blk + 257, "ustar\0\060\060", 8) && !th->path && th->blk[345])
240             {
241               /* POSIX ustar with prefix */
242               char prefix[156];
243               memcpy(prefix, th->blk + 345, 155);
244               prefix[155] = 0;
245               l = strlen(prefix);
246               if (prefix[l - 1] == '/')
247                 prefix[l - 1] = 0;
248               th->path = solv_dupjoin(prefix, "/", path);
249             }
250           else
251             th->path = solv_dupjoin(path, 0, 0);
252         }
253       if (type == 1 || type == 2)
254         {
255           l = strlen(th->path);
256           if (l && th->path[l - 1] == '/')
257             {
258               if (l > 1)
259                 th->path[l - 1] = 0;
260               type = 2;
261             }
262         }
263       if (type != 3)
264         break;
265       while (length > 0)
266         {
267           r = readblock(th->fp, th->blk);
268           if (r)
269             return r;
270           length -= 512;
271         }
272     }
273   th->type = type;
274   th->length = length;
275   return 1;
276 }
277
278 static Offset
279 adddep(Repo *repo, Offset olddeps, char *line)
280 {
281   Pool *pool = repo->pool;
282   char *p;
283   Id id;
284
285   while (*line == ' ' && *line == '\t')
286     line++;
287   p = line;
288   while (*p && *p != ' ' && *p != '\t' && *p != '<' && *p != '=' && *p != '>')
289     p++;
290   id = pool_strn2id(pool, line, p - line, 1);
291   while (*p == ' ' && *p == '\t')
292     p++;
293   if (*p == '<' || *p == '=' || *p == '>')
294     {
295       int flags = 0;
296       for (;; p++)
297         {  
298           if (*p == '<')
299             flags |= REL_LT;
300           else if (*p == '=')
301             flags |= REL_EQ;
302           else if (*p == '>')
303             flags |= REL_GT;
304           else
305             break;
306         }
307       while (*p == ' ' && *p == '\t')
308         p++;
309       line = p;
310       while (*p && *p != ' ' && *p != '\t')
311         p++;
312       id = pool_rel2id(pool, id, pool_strn2id(pool, line, p - line, 1), flags, 1);
313     }
314   return repo_addid_dep(repo, olddeps, id, 0);
315 }
316
317 Id
318 repo_add_arch_pkg(Repo *repo, const char *fn, int flags)
319 {
320   Pool *pool = repo->pool;
321   Repodata *data;
322   FILE *fp;
323   struct tarhead th;
324   char line[4096];
325   int ignoreline;
326   Solvable *s;
327   int l, fd;
328   struct stat stb;
329   void *pkgidhandle = 0;
330
331   data = repo_add_repodata(repo, flags);
332   if ((fd = open(fn, O_RDONLY, 0)) < 0)
333     {
334       pool_debug(pool, SOLV_ERROR, "repo_add_arch_pkg: %s: %s\n", fn, strerror(errno));
335       return 0;
336     }
337   if (fstat(fd, &stb))
338     {
339       pool_debug(pool, SOLV_ERROR, "repo_add_arch_pkg: %s: fstat failed\n", fn);
340       close(fd);
341       return 0;
342     }
343   if (!(fp = solv_xfopen_fd(fn, fd, "r")))
344     {
345       pool_debug(pool, SOLV_ERROR, "repo_add_arch_pkg: %s: fdopen failed\n", fn);
346       close(fd);
347       return 0;
348     }
349   s = 0;
350   inittarhead(&th, fp);
351   while (gettarhead(&th) > 0)
352     {
353       if (th.type != 1 || strcmp(th.path, ".PKGINFO") != 0)
354         {
355           skipentry(&th);
356           continue;
357         }
358       ignoreline = 0;
359       s = pool_id2solvable(pool, repo_add_solvable(repo));
360       if (flags & ARCH_ADD_WITH_PKGID)
361         pkgidhandle = solv_chksum_create(REPOKEY_TYPE_MD5);
362       while (getsentry(&th, line, sizeof(line)))
363         {
364           l = strlen(line);
365           if (l == 0)
366             continue;
367           if (pkgidhandle)
368             solv_chksum_add(pkgidhandle, line, l);
369           if (line[l - 1] != '\n')
370             {
371               ignoreline = 1;
372               continue;
373             }
374           if (ignoreline)
375             {
376               ignoreline = 0;
377               continue;
378             }
379           line[--l] = 0;
380           if (l == 0 || line[0] == '#')
381             continue;
382           if (!strncmp(line, "pkgname = ", 10))
383             s->name = pool_str2id(pool, line + 10, 1);
384           else if (!strncmp(line, "pkgver = ", 9))
385             s->evr = pool_str2id(pool, line + 9, 1);
386           else if (!strncmp(line, "pkgdesc = ", 10))
387             {
388               repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 10);
389               repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line + 10);
390             }
391           else if (!strncmp(line, "url = ", 6))
392             repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line + 6);
393           else if (!strncmp(line, "builddate = ", 12))
394             repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line + 12, 0, 10));
395           else if (!strncmp(line, "packager = ", 11))
396             repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line + 11);
397           else if (!strncmp(line, "size = ", 7))
398             repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line + 7, 0, 10));
399           else if (!strncmp(line, "arch = ", 7))
400             s->arch = pool_str2id(pool, line + 7, 1);
401           else if (!strncmp(line, "license = ", 10))
402             repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_LICENSE, line + 10);
403           else if (!strncmp(line, "replaces = ", 11))
404             s->obsoletes = adddep(repo, s->obsoletes, line + 11);
405           else if (!strncmp(line, "group = ", 8))
406             repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_GROUP, line + 8);
407           else if (!strncmp(line, "depend = ", 9))
408             s->requires = adddep(repo, s->requires, line + 9);
409           else if (!strncmp(line, "optdepend = ", 12))
410             {
411               char *p = strchr(line, ':');
412               if (p)
413                 *p = 0;
414               s->suggests = adddep(repo, s->suggests, line + 12);
415             }
416           else if (!strncmp(line, "conflict = ", 11))
417             s->conflicts = adddep(repo, s->conflicts, line + 11);
418           else if (!strncmp(line, "provides = ", 11))
419             s->provides = adddep(repo, s->provides, line + 11);
420         }
421       break;
422     }
423   freetarhead(&th);
424   fclose(fp);
425   if (s && !s->name)
426     {
427       repo_free_solvable_block(repo, s - pool->solvables, 1, 1);
428       s = 0;
429     }
430   if (s)
431     {
432       if (!s->arch)
433         s->arch = ARCH_NOARCH;
434       if (!s->evr)
435         s->evr = ID_EMPTY;
436       s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
437       repodata_set_location(data, s - pool->solvables, 0, 0, fn);
438       repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
439       if (pkgidhandle)
440         {
441           unsigned char pkgid[16];
442           solv_chksum_free(pkgidhandle, pkgid);
443           repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
444           pkgidhandle = 0;
445         }
446     }
447   if (pkgidhandle)
448     solv_chksum_free(pkgidhandle, 0);
449   if (!(flags & REPO_NO_INTERNALIZE))
450     repodata_internalize(data);
451   return s ? s - pool->solvables : 0;
452 }
453
454 static char *getsentrynl(struct tarhead *th, char *s, int size)
455 {
456   int l;
457   if (!getsentry(th, s, size))
458     {
459       *s = 0;   /* eof */
460       return 0;
461     }
462   l = strlen(s);
463   if (!l)
464     return 0;
465   if (l && s[l - 1] == '\n')
466     {
467       s[l - 1] = 0;
468       return s;
469     }
470   while (getsentry(th, s, size))
471     {
472       l = strlen(s);
473       if (!l || s[l - 1] == '\n')
474         return 0;
475     }
476   *s = 0;       /* eof */
477   return 0;
478 }
479
480 static Hashtable
481 joinhash_init(Repo *repo, Hashmask *hmp)
482 {
483   Hashmask hm = mkmask(repo->nsolvables);
484   Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
485   Hashval h, hh;
486   Solvable *s;
487   int i;
488
489   FOR_REPO_SOLVABLES(repo, i, s)
490     {
491       hh = HASHCHAIN_START;
492       h = s->name & hm;
493       while (ht[h])
494         h = HASHCHAIN_NEXT(h, hh, hm);
495       ht[h] = i;
496     }
497   *hmp = hm;
498   return ht;
499 }
500
501 static Solvable *
502 joinhash_lookup(Repo *repo, Hashtable ht, Hashmask hm, const char *fn)
503 {
504   const char *p;
505   Id name, evr;
506   Hashval h, hh;
507
508   if ((p = strrchr(fn, '/')) != 0)
509     fn = p + 1;
510   /* here we assume that the dirname is name-evr */
511   if (!*fn)
512     return 0;
513   for (p = fn + strlen(fn) - 1; p > fn; p--)
514     {
515       while (p > fn && *p != '-')
516         p--;
517       if (p == fn)
518         return 0;
519       name = pool_strn2id(repo->pool, fn, p - fn, 0);
520       if (!name)
521         continue;
522       evr = pool_str2id(repo->pool, p + 1, 0);
523       if (!evr)
524         continue;
525       /* found valid name/evr combination, check hash */
526       hh = HASHCHAIN_START;
527       h = name & hm;
528       while (ht[h])
529         {
530           Solvable *s = repo->pool->solvables + ht[h];
531           if (s->name == name && s->evr == evr)
532             return s;
533           h = HASHCHAIN_NEXT(h, hh, hm);
534         }
535     }
536   return 0;
537 }
538
539 int
540 repo_add_arch_repo(Repo *repo, FILE *fp, int flags)
541 {
542   Pool *pool = repo->pool;
543   Repodata *data;
544   data = repo_add_repodata(repo, flags);
545   struct tarhead th;
546   char *lastdn = 0;
547   int l, lastdnlen = 0;
548   char line[4096];
549   Solvable *s = 0;
550   int havesha256 = 0;
551   Hashtable joinhash = 0;
552   Hashmask joinhashmask = 0;
553
554   if (flags & REPO_EXTEND_SOLVABLES)
555     joinhash = joinhash_init(repo, &joinhashmask);
556
557   inittarhead(&th, fp);
558   while (gettarhead(&th) > 0)
559     {
560       char *bn;
561       if (th.type != 1)
562         {
563           skipentry(&th);
564           continue;
565         }
566       bn = strrchr(th.path, '/');
567       if (!bn || (strcmp(bn + 1, "desc") != 0 && strcmp(bn + 1, "depends") != 0 && strcmp(bn + 1, "files") != 0))
568         {
569           skipentry(&th);
570           continue;
571         }
572       if ((flags & REPO_EXTEND_SOLVABLES) != 0 && (!strcmp(bn + 1, "desc") || !strcmp(bn + 1, "depends")))
573         {
574           skipentry(&th);
575           continue;     /* skip those when we're extending */
576         }
577       if (!lastdn || (bn - th.path) != lastdnlen || strncmp(lastdn, th.path, lastdnlen) != 0)
578         {
579           if (s)
580             {
581               if (s && !s->name)
582                 {
583                   repo_free_solvable_block(repo, s - pool->solvables, 1, 1);
584                   s = 0;
585                 }
586               if (s)
587                 {
588                   if (!s->arch)
589                     s->arch = ARCH_NOARCH;
590                   if (!s->evr)
591                     s->evr = ID_EMPTY;
592                   s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
593                 }
594             }
595           solv_free(lastdn);
596           lastdn = solv_strdup(th.path);
597           lastdnlen = bn - th.path;
598           lastdn[lastdnlen] = 0;
599           if (flags & REPO_EXTEND_SOLVABLES)
600             {
601               s = joinhash_lookup(repo, joinhash, joinhashmask, lastdn);
602               if (!s)
603                 {
604                   skipentry(&th);
605                   continue;
606                 }
607             }
608           else
609             s = pool_id2solvable(pool, repo_add_solvable(repo));
610           havesha256 = 0;
611         }
612       while (getsentry(&th, line, sizeof(line)))
613         {
614           l = strlen(line);
615           if (l == 0 || line[l - 1] != '\n')
616             continue;
617           line[--l] = 0;
618           if (l <= 2 || line[0] != '%' || line[l - 1] != '%')
619             continue;
620           if (!strcmp(line, "%FILENAME%"))
621             {
622               if (getsentrynl(&th, line, sizeof(line)))
623                 repodata_set_location(data, s - pool->solvables, 0, 0, line);
624             }
625           else if (!strcmp(line, "%NAME%"))
626             {
627               if (getsentrynl(&th, line, sizeof(line)))
628                 s->name = pool_str2id(pool, line, 1);
629             }
630           else if (!strcmp(line, "%VERSION%"))
631             {
632               if (getsentrynl(&th, line, sizeof(line)))
633                 s->evr = pool_str2id(pool, line, 1);
634             }
635           else if (!strcmp(line, "%DESC%"))
636             {
637               if (getsentrynl(&th, line, sizeof(line)))
638                 {
639                   repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line);
640                   repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line);
641                 }
642             }
643           else if (!strcmp(line, "%GROUPS%"))
644             {
645               if (getsentrynl(&th, line, sizeof(line)))
646                 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_GROUP, line);
647             }
648           else if (!strcmp(line, "%CSIZE%"))
649             {
650               if (getsentrynl(&th, line, sizeof(line)))
651                 repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(line, 0, 10));
652             }
653           else if (!strcmp(line, "%ISIZE%"))
654             {
655               if (getsentrynl(&th, line, sizeof(line)))
656                 repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line, 0, 10));
657             }
658           else if (!strcmp(line, "%MD5SUM%"))
659             {
660               if (getsentrynl(&th, line, sizeof(line)) && !havesha256)
661                 repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_MD5, line);
662             }
663           else if (!strcmp(line, "%SHA256SUM%"))
664             {
665               if (getsentrynl(&th, line, sizeof(line)))
666                 {
667                   repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, line);
668                   havesha256 = 1;
669                 }
670             }
671           else if (!strcmp(line, "%URL%"))
672             {
673               if (getsentrynl(&th, line, sizeof(line)))
674                 repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line);
675             }
676           else if (!strcmp(line, "%LICENSE%"))
677             {
678               if (getsentrynl(&th, line, sizeof(line)))
679                 repodata_set_str(data, s - pool->solvables, SOLVABLE_LICENSE, line);
680             }
681           else if (!strcmp(line, "%ARCH%"))
682             {
683               if (getsentrynl(&th, line, sizeof(line)))
684                 s->arch = pool_str2id(pool, line, 1);
685             }
686           else if (!strcmp(line, "%BUILDDATE%"))
687             {
688               if (getsentrynl(&th, line, sizeof(line)))
689                 repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line, 0, 10));
690             }
691           else if (!strcmp(line, "%PACKAGER%"))
692             {
693               if (getsentrynl(&th, line, sizeof(line)))
694                 repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line);
695             }
696           else if (!strcmp(line, "%REPLACES%"))
697             {
698               while (getsentrynl(&th, line, sizeof(line)) && *line)
699                 s->obsoletes = adddep(repo, s->obsoletes, line);
700             }
701           else if (!strcmp(line, "%DEPENDS%"))
702             {
703               while (getsentrynl(&th, line, sizeof(line)) && *line)
704                 s->requires = adddep(repo, s->requires, line);
705             }
706           else if (!strcmp(line, "%CONFLICTS%"))
707             {
708               while (getsentrynl(&th, line, sizeof(line)) && *line)
709                 s->conflicts = adddep(repo, s->conflicts, line);
710             }
711           else if (!strcmp(line, "%PROVIDES%"))
712             {
713               while (getsentrynl(&th, line, sizeof(line)) && *line)
714                 s->provides = adddep(repo, s->provides, line);
715             }
716           else if (!strcmp(line, "%OPTDEPENDS%"))
717             {
718               while (getsentrynl(&th, line, sizeof(line)) && *line)
719                 {
720                   char *p = strchr(line, ':');
721                   if (p && p > line)
722                     *p = 0;
723                   s->suggests = adddep(repo, s->suggests, line);
724                 }
725             }
726           else if (!strcmp(line, "%FILES%"))
727             {
728               while (getsentrynl(&th, line, sizeof(line)) && *line)
729                 {
730                   char *p;
731                   Id id;
732                   l = strlen(line);
733                   if (l > 1 && line[l - 1] == '/')
734                     line[--l] = 0;      /* remove trailing slashes */
735                   if ((p = strrchr(line , '/')) != 0)
736                     {
737                       *p++ = 0;
738                       if (line[0] != '/')       /* anchor */
739                         {
740                           char tmp = *p;
741                           memmove(line + 1, line, p - 1 - line);
742                           *line = '/';
743                           *p = 0;
744                           id = repodata_str2dir(data, line, 1);
745                           *p = tmp;
746                         }
747                       else
748                         id = repodata_str2dir(data, line, 1);
749                     }
750                   else
751                     {
752                       p = line;
753                       id = 0;
754                     }
755                   if (!id)
756                     id = repodata_str2dir(data, "/", 1);
757                   repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, id, p);
758                 }
759             }
760           while (*line)
761             getsentrynl(&th, line, sizeof(line));
762         }
763     }
764   if (s)
765     {
766       if (s && !s->name)
767         {
768           repo_free_solvable_block(repo, s - pool->solvables, 1, 1);
769           s = 0;
770         }
771       if (s)
772         {
773           if (!s->arch)
774             s->arch = ARCH_NOARCH;
775           if (!s->evr)
776             s->evr = ID_EMPTY;
777           s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
778         }
779     }
780   solv_free(joinhash);
781   solv_free(lastdn);
782   if (!(flags & REPO_NO_INTERNALIZE))
783     repodata_internalize(data);
784   return 0;
785 }
786