#include "util.h"
#include "chksum.h"
#include "solv_xfopen.h"
+#include "tarhead.h"
#include "repo_arch.h"
-static long long parsenum(unsigned char *p, int cnt)
-{
- long long x = 0;
- if (!cnt)
- return -1;
- if (*p & 0x80)
- {
- /* binary format */
- x = *p & 0x40 ? (-1 << 8 | *p) : (*p ^ 0x80);
- while (--cnt > 0)
- x = (x << 8) | *p++;
- return x;
- }
- while (cnt > 0 && (*p == ' ' || *p == '\t'))
- cnt--, p++;
- if (*p == '-')
- return -1;
- for (; cnt > 0 && *p >= '0' && *p < '8'; cnt--, p++)
- x = (x << 3) | (*p - '0');
- return x;
-}
-
-static int readblock(FILE *fp, unsigned char *blk)
-{
- int r, l = 0;
- while (l < 512)
- {
- r = fread(blk + l, 1, 512 - l, fp);
- if (r <= 0)
- return -1;
- l += r;
- }
- return 0;
-}
-
-struct tarhead {
- FILE *fp;
- unsigned char blk[512];
- int type;
- long long length;
- char *path;
- int eof;
- int ispax;
- int off;
- int end;
-};
-
-static char *getsentry(struct tarhead *th, char *s, int size)
-{
- char *os = s;
- if (th->eof || size <= 1)
- return 0;
- size--; /* terminating 0 */
- for (;;)
- {
- int i;
- for (i = th->off; i < th->end; i++)
- {
- *s++ = th->blk[i];
- size--;
- if (!size || th->blk[i] == '\n')
- {
- th->off = i + 1;
- *s = 0;
- return os;
- }
- }
- th->off = i;
- if (!th->path)
- {
- /* fake entry */
- th->end = fread(th->blk, 1, 512, th->fp);
- if (th->end <= 0)
- {
- th->eof = 1;
- return 0;
- }
- th->off = 0;
- continue;
- }
- if (th->length <= 0)
- return 0;
- if (readblock(th->fp, th->blk))
- {
- th->eof = 1;
- return 0;
- }
- th->off = 0;
- th->end = th->length > 512 ? 512 : th->length;
- th->length -= th->end;
- }
-}
-
-static void skipentry(struct tarhead *th)
-{
- for (; th->length > 0; th->length -= 512)
- {
- if (readblock(th->fp, th->blk))
- {
- th->eof = 1;
- th->length = 0;
- return;
- }
- }
- th->length = 0;
- th->off = th->end = 0;
-}
-
-static void inittarhead(struct tarhead *th, FILE *fp)
-{
- memset(th, 0, sizeof(*th));
- th->fp = fp;
-}
-
-static void freetarhead(struct tarhead *th)
-{
- solv_free(th->path);
-}
-
-static int gettarhead(struct tarhead *th)
-{
- int l, type;
- long long length;
-
- th->path = solv_free(th->path);
- th->ispax = 0;
- th->type = 0;
- th->length = 0;
- th->off = 0;
- th->end = 0;
- if (th->eof)
- return 0;
- for (;;)
- {
- int r = readblock(th->fp, th->blk);
- if (r)
- {
- if (feof(th->fp))
- {
- th->eof = 1;
- return 0;
- }
- return -1;
- }
- if (th->blk[0] == 0)
- {
- th->eof = 1;
- return 0;
- }
- length = parsenum(th->blk + 124, 12);
- if (length < 0)
- return -1;
- type = 0;
- switch (th->blk[156])
- {
- case 'S': case '0':
- type = 1; /* file */
- break;
- case '1':
- /* hard link, special length magic... */
- if (!th->ispax)
- length = 0;
- break;
- case '5':
- type = 2; /* dir */
- break;
- case '2': case '3': case '4': case '6':
- length = 0;
- break;
- case 'X': case 'x': case 'L':
- {
- char *data, *pp;
- if (length < 1 || length >= 1024 * 1024)
- return -1;
- data = pp = solv_malloc(length + 512);
- for (l = length; l > 0; l -= 512, pp += 512)
- if (readblock(th->fp, (unsigned char *)pp))
- {
- solv_free(data);
- return -1;
- }
- data[length] = 0;
- type = 3; /* extension */
- if (th->blk[156] == 'L')
- {
- solv_free(th->path);
- th->path = data;
- length = 0;
- break;
- }
- pp = data;
- while (length > 0)
- {
- int ll = 0;
- for (l = 0; l < length && pp[l] >= '0' && pp[l] <= '9'; l++)
- ll = ll * 10 + (pp[l] - '0');
- if (l == length || pp[l] != ' ' || ll < 1 || ll > length || pp[ll - 1] != '\n')
- {
- solv_free(data);
- return -1;
- }
- length -= ll;
- pp += l + 1;
- ll -= l + 1;
- pp[ll - 1] = 0;
- if (!strncmp(pp, "path=", 5))
- {
- solv_free(th->path);
- th->path = solv_strdup(pp + 5);
- }
- pp += ll;
- }
- solv_free(data);
- th->ispax = 1;
- length = 0;
- break;
- }
- default:
- type = 3; /* extension */
- break;
- }
- if ((type == 1 || type == 2) && !th->path)
- {
- char path[157];
- memcpy(path, th->blk, 156);
- path[156] = 0;
- if (!memcmp(th->blk + 257, "ustar\0\060\060", 8) && !th->path && th->blk[345])
- {
- /* POSIX ustar with prefix */
- char prefix[156];
- memcpy(prefix, th->blk + 345, 155);
- prefix[155] = 0;
- l = strlen(prefix);
- if (l && prefix[l - 1] == '/')
- prefix[l - 1] = 0;
- th->path = solv_dupjoin(prefix, "/", path);
- }
- else
- th->path = solv_dupjoin(path, 0, 0);
- }
- if (type == 1 || type == 2)
- {
- l = strlen(th->path);
- if (l && th->path[l - 1] == '/')
- {
- if (l > 1)
- th->path[l - 1] = 0;
- type = 2;
- }
- }
- if (type != 3)
- break;
- while (length > 0)
- {
- r = readblock(th->fp, th->blk);
- if (r)
- return r;
- length -= 512;
- }
- }
- th->type = type;
- th->length = length;
- return 1;
-}
-
static Offset
adddep(Repo *repo, Offset olddeps, char *line)
{
Repodata *data;
FILE *fp;
struct tarhead th;
- char line[4096];
- int ignoreline;
+ char *line = 0;
+ size_t line_alloc = 0, l;
Solvable *s;
- int l, fd;
+ int fd;
struct stat stb;
Chksum *pkgidchk = 0;
return 0;
}
s = 0;
- inittarhead(&th, fp);
- while (gettarhead(&th) > 0)
+ tarhead_init(&th, fp);
+ while (tarhead_next(&th) > 0)
{
if (th.type != 1 || strcmp(th.path, ".PKGINFO") != 0)
{
- skipentry(&th);
+ tarhead_skip(&th);
continue;
}
- ignoreline = 0;
s = pool_id2solvable(pool, repo_add_solvable(repo));
if (flags & ARCH_ADD_WITH_PKGID)
pkgidchk = solv_chksum_create(REPOKEY_TYPE_MD5);
- while (getsentry(&th, line, sizeof(line)))
+ while ((l = tarhead_gets(&th, &line, &line_alloc)) > 0)
{
- l = strlen(line);
- if (l == 0)
- continue;
if (pkgidchk)
solv_chksum_add(pkgidchk, line, l);
- if (line[l - 1] != '\n')
- {
- ignoreline = 1;
- continue;
- }
- if (ignoreline)
- {
- ignoreline = 0;
- continue;
- }
- line[--l] = 0;
+ l = strlen(line); /* no NULs please */
+ if (l && line[l - 1] == '\n')
+ line[--l] = 0;
if (l == 0 || line[0] == '#')
continue;
if (!strncmp(line, "pkgname = ", 10))
}
break;
}
- freetarhead(&th);
+ solv_free(line);
+ tarhead_free(&th);
fclose(fp);
if (!s)
{
return s ? s - pool->solvables : 0;
}
-static char *getsentrynl(struct tarhead *th, char *s, int size)
-{
- int l;
- if (!getsentry(th, s, size))
- {
- *s = 0; /* eof */
- return 0;
- }
- l = strlen(s);
- if (!l)
- return 0;
- if (l && s[l - 1] == '\n')
- {
- s[l - 1] = 0;
- return s;
- }
- while (getsentry(th, s, size))
- {
- l = strlen(s);
- if (!l || s[l - 1] == '\n')
- return 0;
- }
- *s = 0; /* eof */
- return 0;
-}
-
static Hashtable
joinhash_init(Repo *repo, Hashval *hmp)
{
return 0;
}
+static int getsentrynl(struct tarhead *th, char **linep, size_t *line_allocp)
+{
+ size_t l = tarhead_gets(th, linep, line_allocp);
+ if (l)
+ l = strlen(*linep);
+ if (l && (*linep)[l - 1] == '\n')
+ (*linep)[--l] = 0;
+ return l ? 1 : 0;
+}
+
static void
adddata(Repodata *data, Solvable *s, struct tarhead *th)
{
Repo *repo = data->repo;
Pool *pool = repo->pool;
- char line[4096];
- int l;
+ char *line = 0;
+ size_t l, line_alloc = 0;
int havesha256 = 0;
- while (getsentry(th, line, sizeof(line)))
+ while ((l = tarhead_gets(th, &line, &line_alloc)) > 0)
{
l = strlen(line);
- if (l == 0 || line[l - 1] != '\n')
- continue;
- line[--l] = 0;
+ if (l && line[l - 1] == '\n')
+ line[--l] = 0;
if (l <= 2 || line[0] != '%' || line[l - 1] != '%')
continue;
if (!strcmp(line, "%FILENAME%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_set_location(data, s - pool->solvables, 0, 0, line);
}
else if (!strcmp(line, "%NAME%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
s->name = pool_str2id(pool, line, 1);
}
else if (!strcmp(line, "%VERSION%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
s->evr = pool_str2id(pool, line, 1);
}
else if (!strcmp(line, "%DESC%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
{
repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line);
repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line);
}
else if (!strcmp(line, "%GROUPS%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_GROUP, line);
}
else if (!strcmp(line, "%CSIZE%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(line, 0, 10));
}
else if (!strcmp(line, "%ISIZE%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line, 0, 10));
}
else if (!strcmp(line, "%MD5SUM%"))
{
- if (getsentrynl(th, line, sizeof(line)) && !havesha256)
+ if (getsentrynl(th, &line, &line_alloc) && !havesha256)
repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_MD5, line);
}
else if (!strcmp(line, "%SHA256SUM%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
{
repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, line);
havesha256 = 1;
}
else if (!strcmp(line, "%URL%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line);
}
else if (!strcmp(line, "%LICENSE%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line);
}
else if (!strcmp(line, "%ARCH%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
s->arch = pool_str2id(pool, line, 1);
}
else if (!strcmp(line, "%BUILDDATE%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line, 0, 10));
}
else if (!strcmp(line, "%PACKAGER%"))
{
- if (getsentrynl(th, line, sizeof(line)))
+ if (getsentrynl(th, &line, &line_alloc))
repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line);
}
else if (!strcmp(line, "%REPLACES%"))
{
- while (getsentrynl(th, line, sizeof(line)) && *line)
+ while (getsentrynl(th, &line, &line_alloc) && *line)
s->obsoletes = adddep(repo, s->obsoletes, line);
}
else if (!strcmp(line, "%DEPENDS%"))
{
- while (getsentrynl(th, line, sizeof(line)) && *line)
+ while (getsentrynl(th, &line, &line_alloc) && *line)
s->requires = adddep(repo, s->requires, line);
}
else if (!strcmp(line, "%CONFLICTS%"))
{
- while (getsentrynl(th, line, sizeof(line)) && *line)
+ while (getsentrynl(th, &line, &line_alloc) && *line)
s->conflicts = adddep(repo, s->conflicts, line);
}
else if (!strcmp(line, "%PROVIDES%"))
{
- while (getsentrynl(th, line, sizeof(line)) && *line)
+ while (getsentrynl(th, &line, &line_alloc) && *line)
s->provides = adddep(repo, s->provides, line);
}
else if (!strcmp(line, "%OPTDEPENDS%"))
{
- while (getsentrynl(th, line, sizeof(line)) && *line)
+ while (getsentrynl(th, &line, &line_alloc) && *line)
{
char *p = strchr(line, ':');
if (p && p > line)
}
else if (!strcmp(line, "%FILES%"))
{
- while (getsentrynl(th, line, sizeof(line)) && *line)
+ while (getsentrynl(th, &line, &line_alloc) && *line)
{
char *p;
Id id;
repodata_add_dirstr(data, s - pool->solvables, SOLVABLE_FILELIST, id, p);
}
}
- while (*line)
- getsentrynl(th, line, sizeof(line));
+ while (*line && getsentrynl(th, &line, &line_alloc))
+ ;
}
+ solv_free(line);
}
static void
if (flags & REPO_EXTEND_SOLVABLES)
joinhash = joinhash_init(repo, &joinhashmask);
- inittarhead(&th, fp);
- while (gettarhead(&th) > 0)
+ tarhead_init(&th, fp);
+ while (tarhead_next(&th) > 0)
{
char *bn;
if (th.type != 1)
{
- skipentry(&th);
+ tarhead_skip(&th);
continue;
}
bn = strrchr(th.path, '/');
if (!bn || (strcmp(bn + 1, "desc") != 0 && strcmp(bn + 1, "depends") != 0 && strcmp(bn + 1, "files") != 0))
{
- skipentry(&th);
+ tarhead_skip(&th);
continue;
}
if ((flags & REPO_EXTEND_SOLVABLES) != 0 && (!strcmp(bn + 1, "desc") || !strcmp(bn + 1, "depends")))
{
- skipentry(&th);
+ tarhead_skip(&th);
continue; /* skip those when we're extending */
}
if (!lastdn || (bn - th.path) != lastdnlen || strncmp(lastdn, th.path, lastdnlen) != 0)
s = joinhash_lookup(repo, joinhash, joinhashmask, lastdn);
if (!s)
{
- skipentry(&th);
+ tarhead_skip(&th);
continue;
}
}
if ((fp = fopen(file, "r")) != 0)
{
struct tarhead th;
- inittarhead(&th, fp);
+ tarhead_init(&th, fp);
s = pool_id2solvable(pool, repo_add_solvable(repo));
adddata(data, s, &th);
- freetarhead(&th);
+ tarhead_free(&th);
fclose(fp);
file = pool_tmpjoin(repo->pool, entrydir, "/files", 0);
if ((fp = fopen(file, "r")) != 0)
{
- inittarhead(&th, fp);
+ tarhead_init(&th, fp);
adddata(data, s, &th);
- freetarhead(&th);
+ tarhead_free(&th);
fclose(fp);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2012, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#include "util.h"
+#include "tarhead.h"
+
+static long long parsenum(unsigned char *p, int cnt)
+{
+ long long x = 0;
+ if (!cnt)
+ return -1;
+ if (*p & 0x80)
+ {
+ /* binary format */
+ x = *p & 0x40 ? (-1 << 8 | *p) : (*p ^ 0x80);
+ while (--cnt > 0)
+ x = (x << 8) | *p++;
+ return x;
+ }
+ while (cnt > 0 && (*p == ' ' || *p == '\t'))
+ cnt--, p++;
+ if (*p == '-')
+ return -1;
+ for (; cnt > 0 && *p >= '0' && *p < '8'; cnt--, p++)
+ x = (x << 3) | (*p - '0');
+ return x;
+}
+
+static int readblock(FILE *fp, unsigned char *blk)
+{
+ int r, l = 0;
+ while (l < 512)
+ {
+ r = fread(blk + l, 1, 512 - l, fp);
+ if (r <= 0)
+ return -1;
+ l += r;
+ }
+ return 0;
+}
+
+void tarhead_skip(struct tarhead *th)
+{
+ for (; th->length > 0; th->length -= 512)
+ {
+ if (readblock(th->fp, th->blk))
+ {
+ th->eof = 1;
+ th->length = 0;
+ return;
+ }
+ }
+ th->length = 0;
+ th->off = th->end = 0;
+}
+
+void tarhead_init(struct tarhead *th, FILE *fp)
+{
+ memset(th, 0, sizeof(*th));
+ th->fp = fp;
+}
+
+void tarhead_free(struct tarhead *th)
+{
+ solv_free(th->path);
+}
+
+int tarhead_next(struct tarhead *th)
+{
+ int l, type;
+ long long length;
+
+ th->path = solv_free(th->path);
+ th->ispax = 0;
+ th->type = 0;
+ th->length = 0;
+ th->off = 0;
+ th->end = 0;
+ if (th->eof)
+ return 0;
+ for (;;)
+ {
+ int r = readblock(th->fp, th->blk);
+ if (r)
+ {
+ if (feof(th->fp))
+ {
+ th->eof = 1;
+ return 0;
+ }
+ return -1;
+ }
+ if (th->blk[0] == 0)
+ {
+ th->eof = 1;
+ return 0;
+ }
+ length = parsenum(th->blk + 124, 12);
+ if (length < 0)
+ return -1;
+ type = 0;
+ switch (th->blk[156])
+ {
+ case 'S': case '0':
+ type = 1; /* file */
+ break;
+ case '1':
+ /* hard link, special length magic... */
+ if (!th->ispax)
+ length = 0;
+ break;
+ case '5':
+ type = 2; /* dir */
+ break;
+ case '2': case '3': case '4': case '6':
+ length = 0;
+ break;
+ case 'X': case 'x': case 'L':
+ {
+ char *data, *pp;
+ if (length < 1 || length >= 1024 * 1024)
+ return -1;
+ data = pp = solv_malloc(length + 512);
+ for (l = length; l > 0; l -= 512, pp += 512)
+ if (readblock(th->fp, (unsigned char *)pp))
+ {
+ solv_free(data);
+ return -1;
+ }
+ data[length] = 0;
+ type = 3; /* extension */
+ if (th->blk[156] == 'L')
+ {
+ solv_free(th->path);
+ th->path = data;
+ length = 0;
+ break;
+ }
+ pp = data;
+ while (length > 0)
+ {
+ int ll = 0;
+ for (l = 0; l < length && pp[l] >= '0' && pp[l] <= '9'; l++)
+ ll = ll * 10 + (pp[l] - '0');
+ if (l == length || pp[l] != ' ' || ll < 1 || ll > length || pp[ll - 1] != '\n')
+ {
+ solv_free(data);
+ return -1;
+ }
+ length -= ll;
+ pp += l + 1;
+ ll -= l + 1;
+ pp[ll - 1] = 0;
+ if (!strncmp(pp, "path=", 5))
+ {
+ solv_free(th->path);
+ th->path = solv_strdup(pp + 5);
+ }
+ pp += ll;
+ }
+ solv_free(data);
+ th->ispax = 1;
+ length = 0;
+ break;
+ }
+ default:
+ type = 3; /* extension */
+ break;
+ }
+ if ((type == 1 || type == 2) && !th->path)
+ {
+ char path[157];
+ memcpy(path, th->blk, 156);
+ path[156] = 0;
+ if (!memcmp(th->blk + 257, "ustar\0\060\060", 8) && !th->path && th->blk[345])
+ {
+ /* POSIX ustar with prefix */
+ char prefix[156];
+ memcpy(prefix, th->blk + 345, 155);
+ prefix[155] = 0;
+ l = strlen(prefix);
+ if (l && prefix[l - 1] == '/')
+ prefix[l - 1] = 0;
+ th->path = solv_dupjoin(prefix, "/", path);
+ }
+ else
+ th->path = solv_dupjoin(path, 0, 0);
+ }
+ if (type == 1 || type == 2)
+ {
+ l = strlen(th->path);
+ if (l && th->path[l - 1] == '/')
+ {
+ if (l > 1)
+ th->path[l - 1] = 0;
+ type = 2;
+ }
+ }
+ if (type != 3)
+ break;
+ while (length > 0)
+ {
+ r = readblock(th->fp, th->blk);
+ if (r)
+ return r;
+ length -= 512;
+ }
+ }
+ th->type = type;
+ th->length = length;
+ return 1;
+}
+
+size_t tarhead_gets(struct tarhead *th, char **linep , size_t *allocsizep)
+{
+ char *line = *linep;
+ size_t lsize = allocsizep ? *allocsizep : 0, size = 0;
+ int i;
+
+ if (th->eof)
+ return 0;
+ for (;;)
+ {
+ size_t fsize = lsize - size;
+ if (fsize < 2)
+ {
+ line = *linep = solv_realloc(line, lsize += 1024);
+ fsize = lsize - size;
+ }
+ for (i = th->off; i < th->end && fsize > 1;)
+ {
+ fsize--;
+ if ((line[size++] = th->blk[i++]) == '\n')
+ {
+ th->off = i;
+ line[size] = 0;
+ return size;
+ }
+ }
+ /* end of block reached, read next block */
+ th->off = i;
+ if (th->off < th->end)
+ continue;
+ if (!th->path)
+ {
+ /* fake entry */
+ th->off = 0;
+ th->end = fread(th->blk, 1, 512, th->fp);
+ if (th->end <= 0)
+ {
+ th->eof = 1;
+ if (th->end < 0)
+ return 0;
+ break;
+ }
+ continue;
+ }
+ if (th->length <= 0)
+ break; /* reached end of entry */
+ if (readblock(th->fp, th->blk))
+ {
+ th->eof = 1;
+ return 0;
+ }
+ th->off = 0;
+ th->end = th->length > 512 ? 512 : th->length;
+ th->length -= th->end;
+ }
+ line[size] = 0;
+ return size;
+}
+