use zlib internally to decompress
parent
6967c28b96
commit
aef0f036f0
3
TODO
3
TODO
|
@ -1,5 +1,4 @@
|
||||||
- Internal gunzip (via lib) to speed up stuff, and avoid threads
|
- mmapped block stream from file
|
||||||
- mmap() if possible for reading
|
|
||||||
|
|
||||||
- Index/pkginfo reader: same field multiple times -> memleak
|
- Index/pkginfo reader: same field multiple times -> memleak
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ apk_OBJS = \
|
||||||
package.o \
|
package.o \
|
||||||
archive.o \
|
archive.o \
|
||||||
version.o \
|
version.o \
|
||||||
|
io.o \
|
||||||
|
gunzip.o \
|
||||||
blob.o \
|
blob.o \
|
||||||
hash.o \
|
hash.o \
|
||||||
md5.o \
|
md5.o \
|
||||||
|
@ -30,7 +32,7 @@ ALL_OBJS = $(apk_OBJS)
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
apk: $(apk_OBJS)
|
apk: $(apk_OBJS)
|
||||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) /usr/lib/libz.a
|
||||||
|
|
||||||
clean::
|
clean::
|
||||||
@rm -f $(TARGETS) $(ALL_OBJS)
|
@rm -f $(TARGETS) $(ALL_OBJS)
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
#define APK_ARCHIVE
|
#define APK_ARCHIVE
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include "apk_blob.h"
|
#include "apk_blob.h"
|
||||||
|
#include "apk_io.h"
|
||||||
|
|
||||||
struct apk_archive_entry {
|
struct apk_archive_entry {
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -27,16 +27,19 @@ struct apk_archive_entry {
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
dev_t device;
|
dev_t device;
|
||||||
int read_fd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*apk_archive_entry_parser)(struct apk_archive_entry *entry, void *ctx);
|
typedef int (*apk_archive_entry_parser)(void *ctx,
|
||||||
|
const struct apk_archive_entry *ae,
|
||||||
|
struct apk_istream *istream);
|
||||||
|
|
||||||
pid_t apk_open_gz(int *fd);
|
struct apk_istream *apk_gunzip_bstream(struct apk_bstream *);
|
||||||
int apk_parse_tar(int fd, apk_archive_entry_parser parser, void *ctx);
|
|
||||||
int apk_parse_tar_gz(int fd, apk_archive_entry_parser parser, void *ctx);
|
int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx);
|
||||||
apk_blob_t apk_archive_entry_read(struct apk_archive_entry *ae);
|
int apk_parse_tar_gz(struct apk_bstream *, apk_archive_entry_parser parser, void *ctx);
|
||||||
int apk_archive_entry_extract(struct apk_archive_entry *ae, const char *to);
|
|
||||||
pthread_t apk_checksum_and_tee(int *fd, void *ptr);
|
int apk_archive_entry_extract(const struct apk_archive_entry *ae,
|
||||||
|
struct apk_istream *is,
|
||||||
|
const char *to);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* apk_io.h - Alpine Package Keeper (APK)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published
|
||||||
|
* by the Free Software Foundation. See http://www.gnu.org/ for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef APK_IO
|
||||||
|
#define APK_IO
|
||||||
|
|
||||||
|
#include "apk_defines.h"
|
||||||
|
#include "apk_blob.h"
|
||||||
|
|
||||||
|
struct apk_istream {
|
||||||
|
size_t (*read)(void *stream, void *ptr, size_t size);
|
||||||
|
size_t (*splice)(void *stream, int fd, size_t size);
|
||||||
|
void (*close)(void *stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct apk_bstream {
|
||||||
|
size_t (*read)(void *stream, void **ptr);
|
||||||
|
void (*close)(void *stream, csum_t csum);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct apk_istream *apk_istream_from_fd(int fd);
|
||||||
|
struct apk_istream *apk_istream_from_file(const char *file);
|
||||||
|
size_t apk_istream_skip(struct apk_istream *istream, size_t size);
|
||||||
|
size_t apk_istream_splice(void *stream, int fd, size_t size);
|
||||||
|
|
||||||
|
struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream);
|
||||||
|
struct apk_bstream *apk_bstream_from_fd(int fd);
|
||||||
|
|
||||||
|
apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size);
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "apk_version.h"
|
#include "apk_version.h"
|
||||||
#include "apk_hash.h"
|
#include "apk_hash.h"
|
||||||
|
#include "apk_io.h"
|
||||||
|
|
||||||
struct apk_database;
|
struct apk_database;
|
||||||
struct apk_name;
|
struct apk_name;
|
||||||
|
@ -75,7 +76,7 @@ struct apk_package *apk_pkg_read(struct apk_database *db, const char *name);
|
||||||
void apk_pkg_free(struct apk_package *pkg);
|
void apk_pkg_free(struct apk_package *pkg);
|
||||||
|
|
||||||
int apk_pkg_get_state(struct apk_package *pkg);
|
int apk_pkg_get_state(struct apk_package *pkg);
|
||||||
int apk_pkg_add_script(struct apk_package *pkg, int fd,
|
int apk_pkg_add_script(struct apk_package *pkg, struct apk_istream *is,
|
||||||
unsigned int type, unsigned int size);
|
unsigned int type, unsigned int size);
|
||||||
int apk_pkg_run_script(struct apk_package *pkg, int root_fd,
|
int apk_pkg_run_script(struct apk_package *pkg, int root_fd,
|
||||||
unsigned int type);
|
unsigned int type);
|
||||||
|
|
245
src/archive.c
245
src/archive.c
|
@ -47,75 +47,62 @@ struct tar_header {
|
||||||
char padding[12]; /* 500-512 */
|
char padding[12]; /* 500-512 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_dev_null(void)
|
|
||||||
{
|
|
||||||
static int fd_null = 0;
|
|
||||||
|
|
||||||
if (fd_null == 0) {
|
|
||||||
fd_null = open("/dev/null", O_WRONLY);
|
|
||||||
if (fd_null < 0)
|
|
||||||
err(EX_OSFILE, "/dev/null");
|
|
||||||
}
|
|
||||||
return fd_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t apk_open_gz(int *fd)
|
|
||||||
{
|
|
||||||
int pipe_fd[2];
|
|
||||||
pid_t child_pid;
|
|
||||||
|
|
||||||
if (pipe(pipe_fd) < 0)
|
|
||||||
err(EX_OSERR, "pipe");
|
|
||||||
|
|
||||||
child_pid = fork();
|
|
||||||
if (child_pid < 0)
|
|
||||||
err(EX_OSERR, "fork");
|
|
||||||
|
|
||||||
if (child_pid == 0) {
|
|
||||||
close(pipe_fd[0]);
|
|
||||||
dup2(pipe_fd[1], STDOUT_FILENO);
|
|
||||||
dup2(*fd, STDIN_FILENO);
|
|
||||||
dup2(get_dev_null(), STDERR_FILENO);
|
|
||||||
close(pipe_fd[1]);
|
|
||||||
execl(GUNZIP_BINARY, "gunzip", "-c", NULL);
|
|
||||||
err(EX_UNAVAILABLE, GUNZIP_BINARY);
|
|
||||||
}
|
|
||||||
|
|
||||||
close(pipe_fd[1]);
|
|
||||||
*fd = pipe_fd[0];
|
|
||||||
|
|
||||||
return child_pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GET_OCTAL(s) apk_blob_uint(APK_BLOB_PTR_LEN(s, sizeof(s)), 8)
|
#define GET_OCTAL(s) apk_blob_uint(APK_BLOB_PTR_LEN(s, sizeof(s)), 8)
|
||||||
|
|
||||||
static int do_splice(int from_fd, int to_fd, int len)
|
struct apk_tar_entry_istream {
|
||||||
|
struct apk_istream is;
|
||||||
|
struct apk_istream *tar_is;
|
||||||
|
size_t bytes_left;
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t tar_entry_read(void *stream, void *ptr, size_t size)
|
||||||
{
|
{
|
||||||
int i = 0, r;
|
struct apk_tar_entry_istream *teis =
|
||||||
|
container_of(stream, struct apk_tar_entry_istream, is);
|
||||||
|
|
||||||
while (i != len) {
|
if (size > teis->bytes_left)
|
||||||
r = splice(from_fd, NULL, to_fd, NULL, len - i, SPLICE_F_MOVE);
|
size = teis->bytes_left;
|
||||||
if (r == -1)
|
size = teis->tar_is->read(teis->tar_is, ptr, size);
|
||||||
return i;
|
if (size >= 0)
|
||||||
i += r;
|
teis->bytes_left -= size;
|
||||||
}
|
return size;
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_parse_tar(int fd, apk_archive_entry_parser parser, void *ctx)
|
static size_t tar_entry_splice(void *stream, int fd, size_t size)
|
||||||
{
|
{
|
||||||
|
struct apk_tar_entry_istream *teis =
|
||||||
|
container_of(stream, struct apk_tar_entry_istream, is);
|
||||||
|
|
||||||
|
if (size > teis->bytes_left)
|
||||||
|
size = teis->bytes_left;
|
||||||
|
size = teis->tar_is->splice(teis->tar_is, fd, size);
|
||||||
|
if (size >= 0)
|
||||||
|
teis->bytes_left -= size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
struct apk_tar_entry_istream teis = {
|
||||||
|
.is.read = tar_entry_read,
|
||||||
|
.is.splice = tar_entry_splice,
|
||||||
|
.tar_is = is,
|
||||||
|
};
|
||||||
struct apk_archive_entry entry;
|
struct apk_archive_entry entry;
|
||||||
struct tar_header buf;
|
struct tar_header buf;
|
||||||
unsigned long offset = 0;
|
unsigned long offset = 0;
|
||||||
int end = 0, r;
|
int end = 0, r;
|
||||||
|
size_t toskip;
|
||||||
|
|
||||||
memset(&entry, 0, sizeof(entry));
|
memset(&entry, 0, sizeof(entry));
|
||||||
while (read(fd, &buf, 512) == 512) {
|
while ((r = is->read(is, &buf, 512)) == 512) {
|
||||||
offset += 512;
|
offset += 512;
|
||||||
if (buf.name[0] == '\0') {
|
if (buf.name[0] == '\0') {
|
||||||
if (end)
|
if (end) {
|
||||||
|
r = 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
end++;
|
end++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +118,6 @@ int apk_parse_tar(int fd, apk_archive_entry_parser parser, void *ctx)
|
||||||
.gname = buf.gname,
|
.gname = buf.gname,
|
||||||
.device = makedev(GET_OCTAL(buf.devmajor),
|
.device = makedev(GET_OCTAL(buf.devmajor),
|
||||||
GET_OCTAL(buf.devminor)),
|
GET_OCTAL(buf.devminor)),
|
||||||
.read_fd = fd,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (buf.typeflag) {
|
switch (buf.typeflag) {
|
||||||
|
@ -139,7 +125,7 @@ int apk_parse_tar(int fd, apk_archive_entry_parser parser, void *ctx)
|
||||||
if (entry.name != NULL)
|
if (entry.name != NULL)
|
||||||
free(entry.name);
|
free(entry.name);
|
||||||
entry.name = malloc(entry.size+1);
|
entry.name = malloc(entry.size+1);
|
||||||
read(fd, entry.name, entry.size);
|
is->read(is, entry.name, entry.size);
|
||||||
offset += entry.size;
|
offset += entry.size;
|
||||||
entry.size = 0;
|
entry.size = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -168,74 +154,48 @@ int apk_parse_tar(int fd, apk_archive_entry_parser parser, void *ctx)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
teis.bytes_left = entry.size;
|
||||||
if (entry.mode & S_IFMT) {
|
if (entry.mode & S_IFMT) {
|
||||||
if (entry.name == NULL)
|
if (entry.name == NULL)
|
||||||
entry.name = strdup(buf.name);
|
entry.name = strdup(buf.name);
|
||||||
|
|
||||||
/* callback parser function */
|
/* callback parser function */
|
||||||
offset += entry.size;
|
r = parser(ctx, &entry, &teis.is);
|
||||||
r = parser(&entry, ctx);
|
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return r;
|
return r;
|
||||||
offset -= entry.size;
|
|
||||||
|
|
||||||
free(entry.name);
|
free(entry.name);
|
||||||
entry.name = NULL;
|
entry.name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.size)
|
offset += entry.size - teis.bytes_left;
|
||||||
offset += do_splice(fd, get_dev_null(), entry.size);
|
toskip = teis.bytes_left;
|
||||||
|
if ((offset + toskip) & 511)
|
||||||
|
toskip += 512 - ((offset + toskip) & 511);
|
||||||
|
offset += toskip;
|
||||||
|
if (toskip != 0)
|
||||||
|
is->read(is, NULL, toskip);
|
||||||
|
}
|
||||||
|
|
||||||
/* align to next 512 block */
|
if (r != 0) {
|
||||||
if (offset & 511)
|
apk_error("Bad TAR header (r=%d)", r);
|
||||||
offset += do_splice(fd, get_dev_null(),
|
return -1;
|
||||||
512 - (offset & 511));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_parse_tar_gz(int fd, apk_archive_entry_parser parser, void *ctx)
|
int apk_parse_tar_gz(struct apk_bstream *bs, apk_archive_entry_parser parser,
|
||||||
|
void *ctx)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
return apk_parse_tar(apk_gunzip_bstream(bs), parser, ctx);
|
||||||
int r, status;
|
|
||||||
|
|
||||||
pid = apk_open_gz(&fd);
|
|
||||||
if (pid < 0)
|
|
||||||
return pid;
|
|
||||||
|
|
||||||
r = apk_parse_tar(fd, parser, ctx);
|
|
||||||
close(fd);
|
|
||||||
waitpid(pid, &status, 0);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apk_blob_t apk_archive_entry_read(struct apk_archive_entry *ae)
|
int apk_archive_entry_extract(const struct apk_archive_entry *ae,
|
||||||
|
struct apk_istream *is,
|
||||||
|
const char *fn)
|
||||||
{
|
{
|
||||||
char *str;
|
int r = -1, fd;
|
||||||
int pos = 0;
|
|
||||||
ssize_t r;
|
|
||||||
|
|
||||||
str = malloc(ae->size + 1);
|
|
||||||
pos = 0;
|
|
||||||
while (ae->size) {
|
|
||||||
r = read(ae->read_fd, &str[pos], ae->size);
|
|
||||||
if (r < 0) {
|
|
||||||
free(str);
|
|
||||||
return APK_BLOB_NULL;
|
|
||||||
}
|
|
||||||
pos += r;
|
|
||||||
ae->size -= r;
|
|
||||||
}
|
|
||||||
str[pos] = 0;
|
|
||||||
|
|
||||||
return APK_BLOB_PTR_LEN(str, pos+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int apk_archive_entry_extract(struct apk_archive_entry *ae, const char *fn)
|
|
||||||
{
|
|
||||||
int r = -1;
|
|
||||||
|
|
||||||
if (fn == NULL)
|
if (fn == NULL)
|
||||||
fn = ae->name;
|
fn = ae->name;
|
||||||
|
@ -251,12 +211,14 @@ int apk_archive_entry_extract(struct apk_archive_entry *ae, const char *fn)
|
||||||
break;
|
break;
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
if (ae->link_target == NULL) {
|
if (ae->link_target == NULL) {
|
||||||
r = open(fn, O_WRONLY | O_CREAT, ae->mode & 07777);
|
fd = open(fn, O_WRONLY | O_CREAT, ae->mode & 07777);
|
||||||
if (r < 0)
|
if (fd < 0) {
|
||||||
|
r = -1;
|
||||||
break;
|
break;
|
||||||
ae->size -= do_splice(ae->read_fd, r, ae->size);
|
}
|
||||||
close(r);
|
if (is->splice(is, fd, ae->size) == ae->size)
|
||||||
r = ae->size ? -1 : 0;
|
r = 0;
|
||||||
|
close(fd);
|
||||||
} else {
|
} else {
|
||||||
r = link(ae->link_target, fn);
|
r = link(ae->link_target, fn);
|
||||||
}
|
}
|
||||||
|
@ -284,74 +246,3 @@ int apk_archive_entry_extract(struct apk_archive_entry *ae, const char *fn)
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct checksum_and_tee {
|
|
||||||
int in_fd, tee_fd;
|
|
||||||
void *ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *__apk_checksum_and_tee(void *arg)
|
|
||||||
{
|
|
||||||
struct checksum_and_tee *args = (struct checksum_and_tee *) arg;
|
|
||||||
char buf[2*1024];
|
|
||||||
int r, w, wt;
|
|
||||||
__off64_t offset;
|
|
||||||
csum_ctx_t ctx;
|
|
||||||
int dosplice = 1;
|
|
||||||
|
|
||||||
offset = lseek(args->in_fd, 0, SEEK_CUR);
|
|
||||||
csum_init(&ctx);
|
|
||||||
do {
|
|
||||||
r = read(args->in_fd, buf, sizeof(buf));
|
|
||||||
if (r <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
wt = 0;
|
|
||||||
do {
|
|
||||||
if (dosplice) {
|
|
||||||
w = splice(args->in_fd, &offset, args->tee_fd, NULL,
|
|
||||||
r - wt, SPLICE_F_MOVE);
|
|
||||||
if (w < 0) {
|
|
||||||
dosplice = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
w = write(args->tee_fd, &buf[wt], r - wt);
|
|
||||||
if (w < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
wt += w;
|
|
||||||
} while (wt != r);
|
|
||||||
|
|
||||||
csum_process(&ctx, buf, r);
|
|
||||||
} while (r == sizeof(buf));
|
|
||||||
|
|
||||||
csum_finish(&ctx, args->ptr);
|
|
||||||
close(args->tee_fd);
|
|
||||||
close(args->in_fd);
|
|
||||||
free(args);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_t apk_checksum_and_tee(int *fd, void *ptr)
|
|
||||||
{
|
|
||||||
struct checksum_and_tee *args;
|
|
||||||
int fds[2];
|
|
||||||
pthread_t tid;
|
|
||||||
|
|
||||||
if (pipe(fds) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
fcntl(fds[0], F_SETFD, FD_CLOEXEC);
|
|
||||||
fcntl(fds[1], F_SETFD, FD_CLOEXEC);
|
|
||||||
|
|
||||||
args = malloc(sizeof(*args));
|
|
||||||
*args = (struct checksum_and_tee){ *fd, fds[1], ptr };
|
|
||||||
if (pthread_create(&tid, NULL, __apk_checksum_and_tee, args) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
*fd = fds[0];
|
|
||||||
return tid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -376,14 +376,14 @@ static int apk_db_write_scriptdb(struct apk_database *db, int fd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apk_db_read_scriptdb(struct apk_database *db, int fd)
|
static int apk_db_read_scriptdb(struct apk_database *db, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
struct apk_package *pkg;
|
struct apk_package *pkg;
|
||||||
struct apk_script_header hdr;
|
struct apk_script_header hdr;
|
||||||
|
|
||||||
while (read(fd, &hdr, sizeof(hdr)) == sizeof(hdr)) {
|
while (is->read(is, &hdr, sizeof(hdr)) == sizeof(hdr)) {
|
||||||
pkg = apk_db_get_pkg(db, hdr.csum);
|
pkg = apk_db_get_pkg(db, hdr.csum);
|
||||||
apk_pkg_add_script(pkg, fd, hdr.type, hdr.size);
|
apk_pkg_add_script(pkg, is, hdr.type, hdr.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -416,6 +416,7 @@ int apk_db_create(const char *root)
|
||||||
|
|
||||||
static int apk_db_read_config(struct apk_database *db)
|
static int apk_db_read_config(struct apk_database *db)
|
||||||
{
|
{
|
||||||
|
struct apk_istream *is;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *buf;
|
char *buf;
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -452,10 +453,10 @@ static int apk_db_read_config(struct apk_database *db)
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open("var/lib/apk/scripts", O_RDONLY);
|
is = apk_istream_from_file("var/lib/apk/scripts");
|
||||||
if (fd >= 0) {
|
if (is != NULL) {
|
||||||
apk_db_read_scriptdb(db, fd);
|
apk_db_read_scriptdb(db, is);
|
||||||
close(fd);
|
is->close(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -664,9 +665,11 @@ int apk_db_recalculate_and_commit(struct apk_database *db)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apk_db_install_archive_entry(struct apk_archive_entry *ae,
|
static int apk_db_install_archive_entry(void *_ctx,
|
||||||
struct install_ctx *ctx)
|
const struct apk_archive_entry *ae,
|
||||||
|
struct apk_istream *is)
|
||||||
{
|
{
|
||||||
|
struct install_ctx *ctx = (struct install_ctx *) _ctx;
|
||||||
struct apk_database *db = ctx->db;
|
struct apk_database *db = ctx->db;
|
||||||
struct apk_package *pkg = ctx->pkg;
|
struct apk_package *pkg = ctx->pkg;
|
||||||
apk_blob_t name = APK_BLOB_STR(ae->name);
|
apk_blob_t name = APK_BLOB_STR(ae->name);
|
||||||
|
@ -698,8 +701,7 @@ static int apk_db_install_archive_entry(struct apk_archive_entry *ae,
|
||||||
|
|
||||||
/* Handle script */
|
/* Handle script */
|
||||||
if (type != APK_SCRIPT_INVALID) {
|
if (type != APK_SCRIPT_INVALID) {
|
||||||
ae->size -= apk_pkg_add_script(pkg, ae->read_fd,
|
apk_pkg_add_script(pkg, is, type, ae->size);
|
||||||
type, ae->size);
|
|
||||||
|
|
||||||
if (type == APK_SCRIPT_GENERIC ||
|
if (type == APK_SCRIPT_GENERIC ||
|
||||||
type == ctx->script) {
|
type == ctx->script) {
|
||||||
|
@ -736,7 +738,7 @@ static int apk_db_install_archive_entry(struct apk_archive_entry *ae,
|
||||||
if (strncmp(file->filename, ".keep_", 6) == 0)
|
if (strncmp(file->filename, ".keep_", 6) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = apk_archive_entry_extract(ae, NULL);
|
r = apk_archive_entry_extract(ae, is, NULL);
|
||||||
} else {
|
} else {
|
||||||
if (name.ptr[name.len-1] == '/')
|
if (name.ptr[name.len-1] == '/')
|
||||||
name.len--;
|
name.len--;
|
||||||
|
@ -775,10 +777,10 @@ int apk_db_install_pkg(struct apk_database *db,
|
||||||
struct apk_package *oldpkg,
|
struct apk_package *oldpkg,
|
||||||
struct apk_package *newpkg)
|
struct apk_package *newpkg)
|
||||||
{
|
{
|
||||||
|
struct apk_bstream *bs;
|
||||||
struct install_ctx ctx;
|
struct install_ctx ctx;
|
||||||
csum_t csum;
|
csum_t csum;
|
||||||
char file[256];
|
char file[256];
|
||||||
pthread_t tid = 0;
|
|
||||||
int fd, r;
|
int fd, r;
|
||||||
|
|
||||||
if (fchdir(db->root_fd) < 0)
|
if (fchdir(db->root_fd) < 0)
|
||||||
|
@ -813,8 +815,8 @@ int apk_db_install_pkg(struct apk_database *db,
|
||||||
|
|
||||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
tid = apk_checksum_and_tee(&fd, csum);
|
bs = apk_bstream_from_fd(fd);
|
||||||
if (tid < 0)
|
if (bs == NULL)
|
||||||
goto err_close;
|
goto err_close;
|
||||||
|
|
||||||
ctx = (struct install_ctx) {
|
ctx = (struct install_ctx) {
|
||||||
|
@ -823,12 +825,10 @@ int apk_db_install_pkg(struct apk_database *db,
|
||||||
.script = (oldpkg == NULL) ?
|
.script = (oldpkg == NULL) ?
|
||||||
APK_SCRIPT_PRE_INSTALL : APK_SCRIPT_PRE_UPGRADE,
|
APK_SCRIPT_PRE_INSTALL : APK_SCRIPT_PRE_UPGRADE,
|
||||||
};
|
};
|
||||||
if (apk_parse_tar_gz(fd, (apk_archive_entry_parser)
|
if (apk_parse_tar_gz(bs, apk_db_install_archive_entry, &ctx) != 0)
|
||||||
apk_db_install_archive_entry, &ctx) != 0)
|
|
||||||
goto err_close;
|
goto err_close;
|
||||||
|
|
||||||
pthread_join(tid, NULL);
|
bs->close(bs, csum);
|
||||||
close(fd);
|
|
||||||
|
|
||||||
db->installed.stats.packages++;
|
db->installed.stats.packages++;
|
||||||
hlist_add_head(&newpkg->installed_pkgs_list, &db->installed.packages);
|
hlist_add_head(&newpkg->installed_pkgs_list, &db->installed.packages);
|
||||||
|
@ -850,7 +850,5 @@ int apk_db_install_pkg(struct apk_database *db,
|
||||||
|
|
||||||
err_close:
|
err_close:
|
||||||
close(fd);
|
close(fd);
|
||||||
if (tid != 0)
|
|
||||||
pthread_join(tid, NULL);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* gunzip.c - Alpine Package Keeper (APK)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published
|
||||||
|
* by the Free Software Foundation. See http://www.gnu.org/ for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "apk_defines.h"
|
||||||
|
#include "apk_io.h"
|
||||||
|
|
||||||
|
struct apk_gzip_istream {
|
||||||
|
struct apk_istream is;
|
||||||
|
struct apk_bstream *bs;
|
||||||
|
z_stream zs;
|
||||||
|
int z_err;
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t gz_read(void *stream, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
struct apk_gzip_istream *gis =
|
||||||
|
container_of(stream, struct apk_gzip_istream, is);
|
||||||
|
|
||||||
|
if (gis->z_err == Z_DATA_ERROR || gis->z_err == Z_ERRNO)
|
||||||
|
return -1;
|
||||||
|
if (gis->z_err == Z_STREAM_END)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ptr == NULL)
|
||||||
|
return apk_istream_skip(&gis->is, size);
|
||||||
|
|
||||||
|
gis->zs.avail_out = size;
|
||||||
|
gis->zs.next_out = ptr;
|
||||||
|
|
||||||
|
while (gis->zs.avail_out != 0 && gis->z_err == Z_OK) {
|
||||||
|
if (gis->zs.avail_in == 0) {
|
||||||
|
gis->zs.avail_in = gis->bs->read(gis->bs, (void **) &gis->zs.next_in);
|
||||||
|
if (gis->zs.avail_in < 0) {
|
||||||
|
gis->z_err = Z_DATA_ERROR;
|
||||||
|
return size - gis->zs.avail_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gis->z_err = inflate(&gis->zs, Z_NO_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gis->z_err != Z_OK && gis->z_err != Z_STREAM_END)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return size - gis->zs.avail_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gz_close(void *stream)
|
||||||
|
{
|
||||||
|
struct apk_gzip_istream *gis =
|
||||||
|
container_of(stream, struct apk_gzip_istream, is);
|
||||||
|
|
||||||
|
inflateEnd(&gis->zs);
|
||||||
|
free(gis);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct apk_istream *apk_gunzip_bstream(struct apk_bstream *bs)
|
||||||
|
{
|
||||||
|
struct apk_gzip_istream *gis;
|
||||||
|
|
||||||
|
gis = malloc(sizeof(struct apk_gzip_istream));
|
||||||
|
if (gis == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*gis = (struct apk_gzip_istream) {
|
||||||
|
.is.read = gz_read,
|
||||||
|
.is.splice = apk_istream_splice,
|
||||||
|
.is.close = gz_close,
|
||||||
|
.bs = bs,
|
||||||
|
.z_err = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (inflateInit2(&gis->zs, 15+32) != Z_OK) {
|
||||||
|
free(gis);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &gis->is;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
/* io.c - Alpine Package Keeper (APK)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
|
||||||
|
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published
|
||||||
|
* by the Free Software Foundation. See http://www.gnu.org/ for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "apk_defines.h"
|
||||||
|
#include "apk_io.h"
|
||||||
|
|
||||||
|
struct apk_fd_istream {
|
||||||
|
struct apk_istream is;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t fd_read(void *stream, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
struct apk_fd_istream *fis =
|
||||||
|
container_of(stream, struct apk_fd_istream, is);
|
||||||
|
size_t i = 0, r;
|
||||||
|
|
||||||
|
if (ptr == NULL) {
|
||||||
|
if (lseek(fis->fd, size, SEEK_CUR) < 0)
|
||||||
|
return -1;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < size) {
|
||||||
|
r = read(fis->fd, ptr + i, size - i);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return i;
|
||||||
|
i += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t fd_splice(void *stream, int fd, size_t size)
|
||||||
|
{
|
||||||
|
struct apk_fd_istream *fis =
|
||||||
|
container_of(stream, struct apk_fd_istream, is);
|
||||||
|
size_t i = 0, r;
|
||||||
|
|
||||||
|
while (i != size) {
|
||||||
|
r = splice(fis->fd, NULL, fd, NULL, size - i, SPLICE_F_MOVE);
|
||||||
|
if (r == -1)
|
||||||
|
return i;
|
||||||
|
i += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fd_close(void *stream)
|
||||||
|
{
|
||||||
|
struct apk_fd_istream *fis =
|
||||||
|
container_of(stream, struct apk_fd_istream, is);
|
||||||
|
|
||||||
|
close(fis->fd);
|
||||||
|
free(fis);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct apk_istream *apk_istream_from_fd(int fd)
|
||||||
|
{
|
||||||
|
struct apk_fd_istream *fis;
|
||||||
|
|
||||||
|
fis = malloc(sizeof(struct apk_fd_istream));
|
||||||
|
if (fis == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*fis = (struct apk_fd_istream) {
|
||||||
|
.is.read = fd_read,
|
||||||
|
.is.splice = fd_splice,
|
||||||
|
.is.close = fd_close,
|
||||||
|
.fd = fd,
|
||||||
|
};
|
||||||
|
|
||||||
|
return &fis->is;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct apk_istream *apk_istream_from_file(const char *file)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(file, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return apk_istream_from_fd(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t apk_istream_skip(struct apk_istream *is, size_t size)
|
||||||
|
{
|
||||||
|
unsigned char buf[2048];
|
||||||
|
size_t done = 0, r, togo;
|
||||||
|
|
||||||
|
while (done < size) {
|
||||||
|
togo = size - done;
|
||||||
|
if (togo > sizeof(buf))
|
||||||
|
togo = sizeof(buf);
|
||||||
|
r = is->read(is, buf, togo);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
done += r;
|
||||||
|
if (r != togo)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t apk_istream_splice(void *stream, int fd, size_t size)
|
||||||
|
{
|
||||||
|
struct apk_istream *is = (struct apk_istream *) stream;
|
||||||
|
unsigned char buf[2048];
|
||||||
|
size_t done = 0, r, togo;
|
||||||
|
|
||||||
|
while (done < size) {
|
||||||
|
togo = size - done;
|
||||||
|
if (togo > sizeof(buf))
|
||||||
|
togo = sizeof(buf);
|
||||||
|
r = is->read(is, buf, togo);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (write(fd, buf, r) != r)
|
||||||
|
return -1;
|
||||||
|
done += r;
|
||||||
|
if (r != togo)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct apk_istream_bstream {
|
||||||
|
struct apk_bstream bs;
|
||||||
|
struct apk_istream *is;
|
||||||
|
csum_ctx_t csum_ctx;
|
||||||
|
unsigned char buffer[8*1024];
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t is_bs_read(void *stream, void **ptr)
|
||||||
|
{
|
||||||
|
struct apk_istream_bstream *isbs =
|
||||||
|
container_of(stream, struct apk_istream_bstream, bs);
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
size = isbs->is->read(isbs->is, isbs->buffer, sizeof(isbs->buffer));
|
||||||
|
if (size <= 0)
|
||||||
|
return size;
|
||||||
|
|
||||||
|
csum_process(&isbs->csum_ctx, isbs->buffer, size);
|
||||||
|
|
||||||
|
*ptr = isbs->buffer;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void is_bs_close(void *stream, csum_t csum)
|
||||||
|
{
|
||||||
|
struct apk_istream_bstream *isbs =
|
||||||
|
container_of(stream, struct apk_istream_bstream, bs);
|
||||||
|
|
||||||
|
if (csum != NULL)
|
||||||
|
csum_finish(&isbs->csum_ctx, csum);
|
||||||
|
|
||||||
|
isbs->is->close(isbs->is);
|
||||||
|
free(isbs);
|
||||||
|
}
|
||||||
|
struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream)
|
||||||
|
{
|
||||||
|
struct apk_istream_bstream *isbs;
|
||||||
|
|
||||||
|
isbs = malloc(sizeof(struct apk_istream_bstream));
|
||||||
|
if (isbs == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
isbs->bs = (struct apk_bstream) {
|
||||||
|
.read = is_bs_read,
|
||||||
|
.close = is_bs_close,
|
||||||
|
};
|
||||||
|
isbs->is = istream;
|
||||||
|
csum_init(&isbs->csum_ctx);
|
||||||
|
|
||||||
|
return &isbs->bs;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct apk_bstream *apk_bstream_from_fd(int fd)
|
||||||
|
{
|
||||||
|
/* FIXME: Write mmap based bstream for files */
|
||||||
|
return apk_bstream_from_istream(apk_istream_from_fd(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
size_t rsize;
|
||||||
|
|
||||||
|
ptr = malloc(size);
|
||||||
|
if (ptr == NULL)
|
||||||
|
return APK_BLOB_NULL;
|
||||||
|
|
||||||
|
rsize = is->read(is, ptr, size);
|
||||||
|
if (rsize < 0) {
|
||||||
|
free(ptr);
|
||||||
|
return APK_BLOB_NULL;
|
||||||
|
}
|
||||||
|
if (rsize != size)
|
||||||
|
ptr = realloc(ptr, rsize);
|
||||||
|
|
||||||
|
return APK_BLOB_PTR_LEN(ptr, rsize);
|
||||||
|
}
|
||||||
|
|
|
@ -254,7 +254,8 @@ static int read_info_line(void *ctx, apk_blob_t line)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_info_entry(struct apk_archive_entry *ae, void *ctx)
|
static int read_info_entry(void *ctx, const struct apk_archive_entry *ae,
|
||||||
|
struct apk_istream *is)
|
||||||
{
|
{
|
||||||
static struct {
|
static struct {
|
||||||
const char *str;
|
const char *str;
|
||||||
|
@ -277,7 +278,7 @@ static int read_info_entry(struct apk_archive_entry *ae, void *ctx)
|
||||||
if (ae->name[0] == '.') {
|
if (ae->name[0] == '.') {
|
||||||
/* APK 2.0 format */
|
/* APK 2.0 format */
|
||||||
if (strcmp(ae->name, ".PKGINFO") == 0) {
|
if (strcmp(ae->name, ".PKGINFO") == 0) {
|
||||||
apk_blob_t blob = apk_archive_entry_read(ae);
|
apk_blob_t blob = apk_blob_from_istream(is, ae->size);
|
||||||
apk_blob_for_each_segment(blob, "\n", read_info_line, ctx);
|
apk_blob_for_each_segment(blob, "\n", read_info_line, ctx);
|
||||||
free(blob.ptr);
|
free(blob.ptr);
|
||||||
/* FIXME: all done after checking if .INSTALL exists */
|
/* FIXME: all done after checking if .INSTALL exists */
|
||||||
|
@ -306,7 +307,7 @@ static int read_info_entry(struct apk_archive_entry *ae, void *ctx)
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fields); i++) {
|
for (i = 0; i < ARRAY_SIZE(fields); i++) {
|
||||||
if (strcmp(fields[i].str, slash+1) == 0) {
|
if (strcmp(fields[i].str, slash+1) == 0) {
|
||||||
apk_blob_t blob = apk_archive_entry_read(ae);
|
apk_blob_t blob = apk_blob_from_istream(is, ae->size);
|
||||||
add_info(ri->db, ri->pkg, fields[i].field,
|
add_info(ri->db, ri->pkg, fields[i].field,
|
||||||
trim(blob));
|
trim(blob));
|
||||||
free(blob.ptr);
|
free(blob.ptr);
|
||||||
|
@ -326,8 +327,8 @@ static int read_info_entry(struct apk_archive_entry *ae, void *ctx)
|
||||||
struct apk_package *apk_pkg_read(struct apk_database *db, const char *file)
|
struct apk_package *apk_pkg_read(struct apk_database *db, const char *file)
|
||||||
{
|
{
|
||||||
struct read_info_ctx ctx;
|
struct read_info_ctx ctx;
|
||||||
|
struct apk_bstream *bs;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
pthread_t tid;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
ctx.pkg = calloc(1, sizeof(struct apk_package));
|
ctx.pkg = calloc(1, sizeof(struct apk_package));
|
||||||
|
@ -341,27 +342,27 @@ struct apk_package *apk_pkg_read(struct apk_database *db, const char *file)
|
||||||
fstat(fd, &st);
|
fstat(fd, &st);
|
||||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
tid = apk_checksum_and_tee(&fd, ctx.pkg->csum);
|
bs = apk_bstream_from_fd(fd);
|
||||||
if (fd < 0)
|
if (bs == NULL) {
|
||||||
|
close(fd);
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ctx.db = db;
|
ctx.db = db;
|
||||||
ctx.pkg->size = st.st_size;
|
ctx.pkg->size = st.st_size;
|
||||||
ctx.has_install = 0;
|
ctx.has_install = 0;
|
||||||
if (apk_parse_tar_gz(fd, read_info_entry, &ctx) < 0) {
|
if (apk_parse_tar_gz(bs, read_info_entry, &ctx) < 0) {
|
||||||
apk_error("File %s is not an APK archive", file);
|
apk_error("File %s is not an APK archive", file);
|
||||||
pthread_join(tid, NULL);
|
bs->close(bs, NULL);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
pthread_join(tid, NULL);
|
bs->close(bs, ctx.pkg->csum);
|
||||||
|
|
||||||
if (ctx.pkg->name == NULL) {
|
if (ctx.pkg->name == NULL) {
|
||||||
apk_error("File %s is corrupted", file);
|
apk_error("File %s is corrupted", file);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
/* Add implicit busybox dependency if there is scripts */
|
/* Add implicit busybox dependency if there is scripts */
|
||||||
if (ctx.has_install) {
|
if (ctx.has_install) {
|
||||||
struct apk_dependency dep = {
|
struct apk_dependency dep = {
|
||||||
|
@ -405,7 +406,7 @@ int apk_pkg_get_state(struct apk_package *pkg)
|
||||||
return APK_STATE_NO_INSTALL;
|
return APK_STATE_NO_INSTALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_pkg_add_script(struct apk_package *pkg, int fd,
|
int apk_pkg_add_script(struct apk_package *pkg, struct apk_istream *is,
|
||||||
unsigned int type, unsigned int size)
|
unsigned int type, unsigned int size)
|
||||||
{
|
{
|
||||||
struct apk_script *script;
|
struct apk_script *script;
|
||||||
|
@ -414,7 +415,7 @@ int apk_pkg_add_script(struct apk_package *pkg, int fd,
|
||||||
script = malloc(sizeof(struct apk_script) + size);
|
script = malloc(sizeof(struct apk_script) + size);
|
||||||
script->type = type;
|
script->type = type;
|
||||||
script->size = size;
|
script->size = size;
|
||||||
r = read(fd, script->script, size);
|
r = is->read(is, script->script, size);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
free(script);
|
free(script);
|
||||||
return r;
|
return r;
|
||||||
|
|
Loading…
Reference in New Issue