From 796d29831360c55d8b8b7d9aa5f33c817094c1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Sat, 17 Jul 2021 17:57:07 +0300 Subject: [PATCH] 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 --- src/adb.c | 3 +- src/adb_comp.c | 5 +- src/adb_walk_text.c | 3 +- src/apk_io.h | 19 ++++-- src/app_extract.c | 8 ++- src/app_fetch.c | 29 +++----- src/database.c | 78 ++++++++-------------- src/io.c | 158 +++++++++++++++----------------------------- src/io_archive.c | 16 ++--- src/io_gunzip.c | 5 +- 10 files changed, 120 insertions(+), 204 deletions(-) diff --git a/src/adb.c b/src/adb.c index 640f01b..a4fe612 100644 --- a/src/adb.c +++ b/src/adb.c @@ -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) diff --git a/src/adb_comp.c b/src/adb_comp.c index d1f5bb2..9f339b8 100644 --- a/src/adb_comp.c +++ b/src/adb_comp.c @@ -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; } diff --git a/src/adb_walk_text.c b/src/adb_walk_text.c index 972df4f..1b7f5cf 100644 --- a/src/adb_walk_text.c +++ b/src/adb_walk_text.c @@ -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); } diff --git a/src/apk_io.h b/src/apk_io.h index 4f03dbc..13ab4a9 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -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) diff --git a/src/app_extract.c b/src/app_extract.c index 9de2bc2..1f11738 100644 --- a/src/app_extract.c +++ b/src/app_extract.c @@ -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; diff --git a/src/app_fetch.c b/src/app_fetch.c index 870dda2..c54a8e0 100644 --- a/src/app_fetch.c +++ b/src/app_fetch.c @@ -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; diff --git a/src/database.c b/src/database.c index 35de195..ef05047 100644 --- a/src/database.c +++ b/src/database.c @@ -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; diff --git a/src/io.c b/src/io.c index 15eee26..1f53d3a 100644 --- a/src/io.c +++ b/src/io.c @@ -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; diff --git a/src/io_archive.c b/src/io_archive.c index 94071f6..984af09 100644 --- a/src/io_archive.c +++ b/src/io_archive.c @@ -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; diff --git a/src/io_gunzip.c b/src/io_gunzip.c index 3cab464..96c66d2 100644 --- a/src/io_gunzip.c +++ b/src/io_gunzip.c @@ -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 {