rework apk_istream_splice and apk_istream_tee

- apk_istream_splice usage is converted to apk_stream_copy which
  is the newer variant. With caching enabled by default, this
  makes more sense mmapping or using separate buffers.

- apk_istream_tee is reworked to write to apk_ostream, which simplifies
  quite a bit of various things
cute-signatures
Timo Teräs 2021-07-17 17:57:07 +03:00
parent b559a81694
commit 796d298313
10 changed files with 120 additions and 204 deletions

View File

@ -220,8 +220,7 @@ bad_msg:
err:
if (r >= 0) r = -APKE_ADB_BLOCK;
done:
apk_istream_close(is);
return r;
return apk_istream_close_error(is, r);
}
static int __adb_dummy_cb(struct adb *db, struct adb_block *b, struct apk_istream *is)

View File

@ -26,10 +26,7 @@ struct apk_istream *adb_decompress(struct apk_istream *is, adb_comp_t *compressi
is = apk_istream_deflate(is);
break;
}
if (c == -1) {
apk_istream_close(is);
return ERR_PTR(-APKE_ADB_COMPRESSION);
}
if (c == -1) return ERR_PTR(apk_istream_close_error(is, -APKE_ADB_COMPRESSION));
if (compression) *compression = c;
return is;
}

View File

@ -126,6 +126,5 @@ int adb_walk_text(struct adb_walk *d, struct apk_istream *is)
d->ops->end(d);
err:
if (r) apk_istream_error(is, r);
return apk_istream_close(is);
return apk_istream_close_error(is, r);
}

View File

@ -40,7 +40,6 @@ APK_ARRAY(apk_xattr_array, struct apk_xattr);
struct apk_file_meta {
time_t mtime, atime;
};
void apk_file_meta_to_fd(int fd, struct apk_file_meta *meta);
struct apk_file_info {
const char *name;
@ -101,8 +100,6 @@ void *apk_istream_get(struct apk_istream *is, size_t len);
int apk_istream_get_max(struct apk_istream *is, size_t size, apk_blob_t *data);
int apk_istream_get_delim(struct apk_istream *is, apk_blob_t token, apk_blob_t *data);
static inline int apk_istream_get_all(struct apk_istream *is, apk_blob_t *data) { return apk_istream_get_max(is, APK_IO_ALL, data); }
ssize_t apk_istream_splice(struct apk_istream *is, int fd, size_t size,
apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx);
ssize_t apk_stream_copy(struct apk_istream *is, struct apk_ostream *os, size_t size,
apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx);
@ -122,6 +119,11 @@ static inline int apk_istream_close(struct apk_istream *is)
{
return is->ops->close(is);
}
static inline int apk_istream_close_error(struct apk_istream *is, int r)
{
if (r < 0) apk_istream_error(is, r);
return apk_istream_close(is);
}
struct apk_segment_istream {
struct apk_istream is;
@ -130,10 +132,15 @@ struct apk_segment_istream {
time_t mtime;
};
struct apk_istream *apk_istream_segment(struct apk_segment_istream *sis, struct apk_istream *is, size_t len, time_t mtime);
struct apk_istream *apk_istream_tee(struct apk_istream *from, int atfd, const char *to, int copy_meta,
#define APK_ISTREAM_TEE_COPY_META 1
#define APK_ISTREAM_TEE_OPTIONAL 2
struct apk_istream *apk_istream_tee(struct apk_istream *from, struct apk_ostream *to, int copy_meta,
apk_progress_cb cb, void *cb_ctx);
struct apk_ostream_ops {
void (*set_meta)(struct apk_ostream *os, struct apk_file_meta *meta);
ssize_t (*write)(struct apk_ostream *os, const void *buf, size_t size);
int (*close)(struct apk_ostream *os);
};
@ -146,8 +153,8 @@ struct apk_ostream {
struct apk_ostream *apk_ostream_counter(off_t *);
struct apk_ostream *apk_ostream_to_fd(int fd);
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode);
struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, const char *tmpfile, mode_t mode);
size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string);
size_t apk_ostream_write_string(struct apk_ostream *os, const char *string);
void apk_ostream_copy_meta(struct apk_ostream *os, struct apk_istream *is);
static inline int apk_ostream_error(struct apk_ostream *os) { return os->rc; }
static inline int apk_ostream_cancel(struct apk_ostream *os, int rc) { if (!os->rc) os->rc = rc; return rc; }
static inline ssize_t apk_ostream_write(struct apk_ostream *os, const void *buf, size_t size)

View File

@ -105,6 +105,7 @@ static int uvol_run(struct apk_ctx *ac, char *action, const char *volname, char
static int uvol_extract(struct apk_ctx *ac, char *action, const char *volname, char *arg1, off_t sz, struct apk_istream *is, struct apk_digest_ctx *dctx)
{
struct apk_out *out = &ac->out;
struct apk_ostream *os;
pid_t pid;
int r, status, pipefds[2];
char *argv[] = { (char*)apk_ctx_get_uvol(ac), action, (char*) volname, arg1, 0 };
@ -121,9 +122,10 @@ static int uvol_extract(struct apk_ctx *ac, char *action, const char *volname, c
return r;
}
close(pipefds[0]);
r = apk_istream_splice(is, pipefds[1], sz, 0, 0, dctx);
close(pipefds[1]);
if (r != sz) {
os = apk_ostream_to_fd(pipefds[1]);
apk_stream_copy(is, os, sz, 0, 0, dctx);
r = apk_ostream_close(os);
if (r != 0) {
if (r >= 0) r = -APKE_UVOL;
apk_err(out, "%s: uvol write error: %s", volname, apk_error_str(r));
return r;

View File

@ -120,10 +120,11 @@ static int fetch_package(apk_hash_item item, void *pctx)
struct apk_out *out = &db->ctx->out;
struct apk_package *pkg = (struct apk_package *) item;
struct apk_istream *is;
struct apk_ostream *os;
struct apk_repository *repo;
struct apk_file_info fi;
char url[PATH_MAX], filename[256];
int r, fd, urlfd;
int r, urlfd;
if (!pkg->marked)
return 0;
@ -154,7 +155,7 @@ static int fetch_package(apk_hash_item item, void *pctx)
goto err;
if (ctx->flags & FETCH_STDOUT) {
fd = STDOUT_FILENO;
os = apk_ostream_to_fd(STDOUT_FILENO);
} else {
if ((ctx->flags & FETCH_LINK) && urlfd >= 0) {
if (linkat(urlfd, url,
@ -162,10 +163,9 @@ static int fetch_package(apk_hash_item item, void *pctx)
AT_SYMLINK_FOLLOW) == 0)
return 0;
}
fd = openat(ctx->outdir_fd, filename,
O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644);
if (fd < 0) {
r = -errno;
os = apk_ostream_to_file(ctx->outdir_fd, filename, 0644);
if (IS_ERR(os)) {
r = PTR_ERR(os);
goto err;
}
}
@ -176,20 +176,11 @@ static int fetch_package(apk_hash_item item, void *pctx)
goto err;
}
r = apk_istream_splice(is, fd, pkg->size, progress_cb, ctx, 0);
if (fd != STDOUT_FILENO) {
struct apk_file_meta meta;
apk_istream_get_meta(is, &meta);
apk_file_meta_to_fd(fd, &meta);
close(fd);
}
apk_stream_copy(is, os, pkg->size, progress_cb, ctx, 0);
apk_ostream_copy_meta(os, is);
apk_istream_close(is);
if (r != pkg->size) {
unlinkat(ctx->outdir_fd, filename, 0);
if (r >= 0) r = -EIO;
goto err;
}
r = apk_ostream_close(os);
if (r) goto err;
ctx->done += pkg->size;
return 0;

View File

@ -47,7 +47,6 @@ enum {
APK_DIR_REMOVE
};
static apk_blob_t tmpprefix = APK_BLOB_STRLIT(".apknew.");
static const char * const apkindex_tar_gz = "APKINDEX.tar.gz";
static const char * const apk_static_cache_dir = "var/cache/apk";
static const char * const apk_world_file = "etc/apk/world";
@ -629,18 +628,17 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
struct stat st = {0};
struct apk_url_print urlp;
struct apk_istream *is;
struct apk_ostream *os;
struct apk_sign_ctx sctx;
char url[PATH_MAX];
char tmpcacheitem[128], *cacheitem = &tmpcacheitem[tmpprefix.len];
apk_blob_t b = APK_BLOB_BUF(tmpcacheitem);
int r, fd;
char cacheitem[128];
int r;
time_t now = time(NULL);
apk_blob_push_blob(&b, tmpprefix);
if (pkg != NULL)
r = apk_pkg_format_cache_pkg(b, pkg);
r = apk_pkg_format_cache_pkg(APK_BLOB_BUF(cacheitem), pkg);
else
r = apk_repo_format_cache_index(b, repo);
r = apk_repo_format_cache_index(APK_BLOB_BUF(cacheitem), repo);
if (r < 0) return r;
r = apk_repo_format_real_url(db->arch, repo, pkg, url, sizeof(url), &urlp);
@ -654,44 +652,34 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
apk_msg(out, "fetch " URL_FMT, URL_PRINTF(urlp));
if (db->ctx->flags & APK_SIMULATE) return 0;
os = apk_ostream_to_file(db->cache_fd, cacheitem, 0644);
if (IS_ERR(os)) return PTR_ERR(os);
if (cb) cb(cb_ctx, 0);
if (verify != APK_SIGN_NONE) {
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx));
is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
is = apk_istream_tee(is, db->cache_fd, tmpcacheitem, !autoupdate, cb, cb_ctx);
is = apk_istream_tee(is, os, autoupdate ? 0 : APK_ISTREAM_TEE_COPY_META, cb, cb_ctx);
is = apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx);
r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, db->id_cache);
apk_sign_ctx_free(&sctx);
} else {
is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
if (!IS_ERR_OR_NULL(is)) {
fd = openat(db->cache_fd, tmpcacheitem, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
if (fd < 0) r = -errno;
} else fd = -1, r = PTR_ERR(is) ?: -EIO;
if (fd >= 0) {
struct apk_file_meta meta;
r = apk_istream_splice(is, fd, APK_IO_ALL, cb, cb_ctx, 0);
if (!autoupdate) {
apk_istream_get_meta(is, &meta);
apk_file_meta_to_fd(fd, &meta);
}
close(fd);
if (!IS_ERR(is)) {
apk_stream_copy(is, os, APK_IO_ALL, cb, cb_ctx, 0);
if (!autoupdate) apk_ostream_copy_meta(os, is);
apk_istream_close(is);
} else {
apk_ostream_cancel(os, PTR_ERR(is));
}
if (!IS_ERR_OR_NULL(is)) apk_istream_close(is);
r = apk_ostream_close(os);
}
if (r == -EALREADY) {
if (autoupdate) utimensat(db->cache_fd, cacheitem, NULL, 0);
return r;
}
if (r < 0) {
unlinkat(db->cache_fd, tmpcacheitem, 0);
return r;
}
if (renameat(db->cache_fd, tmpcacheitem, db->cache_fd, cacheitem) < 0)
return -errno;
return 0;
}
@ -2781,11 +2769,11 @@ static int apk_db_unpack_pkg(struct apk_database *db,
{
struct apk_out *out = &db->ctx->out;
struct install_ctx ctx;
struct apk_istream *is = NULL, *cache_is;
struct apk_istream *is = NULL;
struct apk_repository *repo;
struct apk_package *pkg = ipkg->pkg;
char file[PATH_MAX];
char tmpcacheitem[128], *cacheitem = &tmpcacheitem[tmpprefix.len];
char cacheitem[128];
int r, filefd = AT_FDCWD, need_copy = FALSE;
if (pkg->filename == NULL) {
@ -2817,15 +2805,13 @@ static int apk_db_unpack_pkg(struct apk_database *db,
goto err_msg;
}
if (need_copy) {
apk_blob_t b = APK_BLOB_BUF(tmpcacheitem);
apk_blob_push_blob(&b, tmpprefix);
apk_pkg_format_cache_pkg(b, pkg);
cache_is = apk_istream_tee(is, db->cache_fd, tmpcacheitem, 1, NULL, NULL);
if (!IS_ERR_OR_NULL(cache_is))
is = cache_is;
else
apk_warn(out, PKG_VER_FMT": unable to cache: %s",
PKG_VER_PRINTF(pkg), apk_error_str(errno));
struct apk_istream *origis = is;
apk_pkg_format_cache_pkg(APK_BLOB_BUF(cacheitem), pkg);
is = apk_istream_tee(is, apk_ostream_to_file(db->cache_fd, cacheitem, 0644),
APK_ISTREAM_TEE_COPY_META|APK_ISTREAM_TEE_OPTIONAL, NULL, NULL);
if (is == origis)
apk_warn(out, PKG_VER_FMT": unable to cache package",
PKG_VER_PRINTF(pkg));
}
ctx = (struct install_ctx) {
@ -2842,16 +2828,8 @@ static int apk_db_unpack_pkg(struct apk_database *db,
r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx.sctx), apk_db_install_archive_entry, &ctx, db->id_cache);
apk_sign_ctx_free(&ctx.sctx);
if (need_copy) {
if (r == 0) {
renameat(db->cache_fd, tmpcacheitem, db->cache_fd, cacheitem);
pkg->repos |= BIT(APK_REPOSITORY_CACHED);
} else {
unlinkat(db->cache_fd, tmpcacheitem, 0);
}
}
if (r != 0)
goto err_msg;
if (need_copy && r == 0) pkg->repos |= BIT(APK_REPOSITORY_CACHED);
if (r != 0) goto err_msg;
apk_db_run_pending_script(&ctx);
return 0;

158
src/io.c
View File

@ -61,15 +61,6 @@ static void apk_file_meta_from_fd(int fd, struct apk_file_meta *meta)
}
}
void apk_file_meta_to_fd(int fd, struct apk_file_meta *meta)
{
struct timespec times[2] = {
{ .tv_sec = meta->atime, .tv_nsec = meta->atime ? 0 : UTIME_OMIT },
{ .tv_sec = meta->mtime, .tv_nsec = meta->mtime ? 0 : UTIME_OMIT }
};
futimens(fd, times);
}
apk_blob_t apk_istream_mmap(struct apk_istream *is)
{
if (is->flags & APK_ISTREAM_SINGLE_READ)
@ -310,7 +301,8 @@ struct apk_istream *apk_istream_segment(struct apk_segment_istream *sis, struct
struct apk_tee_istream {
struct apk_istream is;
struct apk_istream *inner_is;
int fd, copy_meta;
struct apk_ostream *to;
int flags;
size_t size;
apk_progress_cb cb;
void *cb_ctx;
@ -324,7 +316,7 @@ static void tee_get_meta(struct apk_istream *is, struct apk_file_meta *meta)
static ssize_t __tee_write(struct apk_tee_istream *tee, void *ptr, size_t size)
{
ssize_t w = write(tee->fd, ptr, size);
ssize_t w = apk_ostream_write(tee->to, ptr, size);
if (size != w) {
if (w < 0) return w;
return -ENOSPC;
@ -347,17 +339,15 @@ static ssize_t tee_read(struct apk_istream *is, void *ptr, size_t size)
static int tee_close(struct apk_istream *is)
{
int r;
struct apk_tee_istream *tee = container_of(is, struct apk_tee_istream, is);
struct apk_file_meta meta;
int r;
if (tee->copy_meta) {
apk_istream_get_meta(tee->inner_is, &meta);
apk_file_meta_to_fd(tee->fd, &meta);
}
if (tee->flags & APK_ISTREAM_TEE_COPY_META)
apk_ostream_copy_meta(tee->to, tee->inner_is);
r = apk_istream_close(tee->inner_is);
close(tee->fd);
r = apk_istream_close_error(tee->inner_is, tee->is.err);
if (r < 0) apk_ostream_cancel(tee->to, r);
r = apk_ostream_close(tee->to);
free(tee);
return r;
}
@ -368,24 +358,24 @@ static const struct apk_istream_ops tee_istream_ops = {
.close = tee_close,
};
struct apk_istream *apk_istream_tee(struct apk_istream *from, int atfd, const char *to, int copy_meta, apk_progress_cb cb, void *cb_ctx)
struct apk_istream *apk_istream_tee(struct apk_istream *from, struct apk_ostream *to, int flags, apk_progress_cb cb, void *cb_ctx)
{
struct apk_tee_istream *tee;
int fd, r;
int r;
if (IS_ERR_OR_NULL(from)) return ERR_CAST(from);
fd = openat(atfd, to, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd < 0) {
r = -errno;
goto err_is;
if (IS_ERR(from)) {
r = PTR_ERR(from);
goto err;
}
if (IS_ERR(to)) {
r = PTR_ERR(to);
goto err;
}
tee = malloc(sizeof *tee);
if (!tee) {
r = -ENOMEM;
goto err_fd;
goto err;
}
*tee = (struct apk_tee_istream) {
@ -395,8 +385,8 @@ struct apk_istream *apk_istream_tee(struct apk_istream *from, int atfd, const ch
.is.ptr = from->ptr,
.is.end = from->end,
.inner_is = from,
.fd = fd,
.copy_meta = copy_meta,
.to = to,
.flags = flags,
.cb = cb,
.cb_ctx = cb_ctx,
};
@ -409,11 +399,11 @@ struct apk_istream *apk_istream_tee(struct apk_istream *from, int atfd, const ch
return &tee->is;
err_free:
free(tee);
err_fd:
close(fd);
err_is:
apk_istream_close(from);
return ERR_PTR(r);
err:
if (!IS_ERR(to)) apk_ostream_close(to);
if (!IS_ERR(from) && (flags & APK_ISTREAM_TEE_OPTIONAL))
return from;
return ERR_PTR(apk_istream_close_error(from, r));
}
struct apk_mmap_istream {
@ -559,12 +549,16 @@ ssize_t apk_stream_copy(struct apk_istream *is, struct apk_ostream *os, size_t s
apk_blob_t d;
int r;
if (IS_ERR(is)) return PTR_ERR(is);
if (IS_ERR(os)) return PTR_ERR(os);
while (done < size) {
if (cb != NULL) cb(cb_ctx, done);
r = apk_istream_get_max(is, size - done, &d);
if (r < 0) {
if (r == -APKE_EOF && d.len) return d.len;
if (r == -APKE_EOF && size == APK_IO_ALL) break;
apk_ostream_cancel(os, r);
return r;
}
if (dctx) apk_digest_ctx_update(dctx, d.ptr, d.len);
@ -577,67 +571,6 @@ ssize_t apk_stream_copy(struct apk_istream *is, struct apk_ostream *os, size_t s
return done;
}
ssize_t apk_istream_splice(struct apk_istream *is, int fd, size_t size,
apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx)
{
static void *splice_buffer = NULL;
unsigned char *buf, *mmapbase = MAP_FAILED;
size_t bufsz, done = 0, togo;
ssize_t r;
bufsz = size;
if (size > 128 * 1024) {
if (size != APK_IO_ALL) {
r = posix_fallocate(fd, 0, size);
if (r == 0)
mmapbase = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
else if (r == EBADF || r == EFBIG || r == ENOSPC || r == EIO)
return -r;
}
bufsz = min(bufsz, 2*1024*1024);
buf = mmapbase;
}
if (mmapbase == MAP_FAILED) {
if (!splice_buffer) splice_buffer = malloc(256*1024);
buf = splice_buffer;
if (!buf) return -ENOMEM;
bufsz = min(bufsz, 256*1024);
}
while (done < size) {
if (cb != NULL) cb(cb_ctx, done);
togo = min(size - done, bufsz);
r = apk_istream_read(is, buf, togo);
if (r <= 0) {
if (r && r != -APKE_EOF) goto err;
if (size != APK_IO_ALL && done != size) {
r = -APKE_EOF;
goto err;
}
break;
}
if (dctx) apk_digest_ctx_update(dctx, buf, r);
if (mmapbase == MAP_FAILED) {
if (write(fd, buf, r) != r) {
if (r < 0)
r = -errno;
goto err;
}
} else
buf += r;
done += r;
}
r = done;
err:
if (mmapbase != MAP_FAILED)
munmap(mmapbase, size);
return r;
}
apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size)
{
void *ptr;
@ -893,11 +826,11 @@ static ssize_t fdo_flush(struct apk_fd_ostream *fos)
{
ssize_t r;
if (fos->bytes == 0)
return 0;
if (fos->os.rc < 0) return fos->os.rc;
if (fos->bytes == 0) return 0;
if ((r = apk_write_fully(fos->fd, fos->buffer, fos->bytes)) != fos->bytes) {
apk_ostream_cancel(&fos->os, r < 0 ? r : -EIO);
apk_ostream_cancel(&fos->os, r < 0 ? r : -ENOSPC);
return r;
}
@ -905,6 +838,17 @@ static ssize_t fdo_flush(struct apk_fd_ostream *fos)
return 0;
}
static void fdo_set_meta(struct apk_ostream *os, struct apk_file_meta *meta)
{
struct apk_fd_ostream *fos = container_of(os, struct apk_fd_ostream, os);
struct timespec times[2] = {
{ .tv_sec = meta->atime, .tv_nsec = meta->atime ? 0 : UTIME_OMIT },
{ .tv_sec = meta->mtime, .tv_nsec = meta->mtime ? 0 : UTIME_OMIT }
};
futimens(fos->fd, times);
}
static ssize_t fdo_write(struct apk_ostream *os, const void *ptr, size_t size)
{
struct apk_fd_ostream *fos = container_of(os, struct apk_fd_ostream, os);
@ -916,7 +860,7 @@ static ssize_t fdo_write(struct apk_ostream *os, const void *ptr, size_t size)
return r;
if (size >= sizeof(fos->buffer) / 2) {
r = apk_write_fully(fos->fd, ptr, size);
if (r != size) apk_ostream_cancel(&fos->os, r < 0 ? r : -EIO);
if (r != size) apk_ostream_cancel(&fos->os, r < 0 ? r : -ENOSPC);
return r;
}
}
@ -958,6 +902,7 @@ static int fdo_close(struct apk_ostream *os)
}
static const struct apk_ostream_ops fd_ostream_ops = {
.set_meta = fdo_set_meta,
.write = fdo_write,
.close = fdo_close,
};
@ -994,8 +939,6 @@ struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode)
fd = openat(atfd, tmpname, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, mode);
if (fd < 0) return ERR_PTR(-errno);
fcntl(fd, F_SETFD, FD_CLOEXEC);
os = apk_ostream_to_fd(fd);
if (IS_ERR_OR_NULL(os)) return ERR_CAST(os);
@ -1059,6 +1002,13 @@ size_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
return len;
}
void apk_ostream_copy_meta(struct apk_ostream *os, struct apk_istream *is)
{
struct apk_file_meta meta;
apk_istream_get_meta(is, &meta);
os->ops->set_meta(os, &meta);
}
struct cache_item {
struct hlist_node by_id, by_name;
unsigned long id;

View File

@ -263,8 +263,7 @@ ok:
free(pax.ptr);
free(longname.ptr);
apk_fileinfo_free(&entry);
apk_istream_close(is);
return r;
return apk_istream_close_error(is, r);
}
int apk_tar_write_entry(struct apk_ostream *os, const struct apk_file_info *ae,
@ -356,15 +355,10 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
case S_IFREG:
if (ae->link_target == NULL) {
int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_EXCL;
fd = openat(atfd, fn, flags, ae->mode & 07777);
if (fd < 0) {
ret = -errno;
break;
}
r = apk_istream_splice(is, fd, ae->size, cb, cb_ctx, dctx);
if (r != ae->size) ret = r < 0 ? r : -ENOSPC;
close(fd);
struct apk_ostream *os = apk_ostream_to_fd(openat(atfd, fn, flags, ae->mode & 07777));
apk_stream_copy(is, os, ae->size, cb, cb_ctx, dctx);
r = apk_ostream_close(os);
if (r < 0) ret = r;
} else {
r = linkat(atfd, link_target ?: ae->link_target, atfd, fn, 0);
if (r < 0) ret = -errno;

View File

@ -125,7 +125,7 @@ static int gzi_close(struct apk_istream *is)
struct apk_gzip_istream *gis = container_of(is, struct apk_gzip_istream, is);
inflateEnd(&gis->zs);
r = apk_istream_close(gis->zis);
r = apk_istream_close_error(gis->zis, gis->is.err);
free(gis);
return r;
}
@ -167,8 +167,7 @@ struct apk_istream *apk_istream_zlib(struct apk_istream *is, int raw, apk_multip
return &gis->is;
err:
apk_istream_close(is);
return ERR_PTR(-ENOMEM);
return ERR_PTR(apk_istream_close_error(is, -ENOMEM));
}
struct apk_gzip_ostream {