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 thingscute-signatures
parent
b559a81694
commit
796d298313
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
19
src/apk_io.h
19
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
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));
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
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
158
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue