2021-06-09 20:12:52 +00:00
|
|
|
/* extract.c - Alpine Package Keeper (APK)
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008-2021 Timo Teräs <timo.teras@iki.fi>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "apk_applet.h"
|
|
|
|
#include "apk_print.h"
|
2021-07-26 13:25:03 +00:00
|
|
|
#include "apk_extract.h"
|
2021-11-05 11:20:19 +00:00
|
|
|
#include "apk_fs.h"
|
2021-06-09 20:12:52 +00:00
|
|
|
|
|
|
|
struct extract_ctx {
|
|
|
|
const char *destination;
|
|
|
|
unsigned int extract_flags;
|
|
|
|
|
2021-07-30 13:38:53 +00:00
|
|
|
struct apk_extract_ctx ectx;
|
2021-06-09 20:12:52 +00:00
|
|
|
struct apk_ctx *ac;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#define EXTRACT_OPTIONS(OPT) \
|
|
|
|
OPT(OPT_EXTRACT_destination, APK_OPT_ARG "destination") \
|
|
|
|
OPT(OPT_EXTRACT_no_chown, "no-chown")
|
|
|
|
|
|
|
|
APK_OPT_APPLET(option_desc, EXTRACT_OPTIONS);
|
|
|
|
|
|
|
|
static int option_parse_applet(void *pctx, struct apk_ctx *ac, int opt, const char *optarg)
|
|
|
|
{
|
|
|
|
struct extract_ctx *ctx = (struct extract_ctx *) pctx;
|
|
|
|
|
|
|
|
switch (opt) {
|
|
|
|
case OPT_EXTRACT_destination:
|
|
|
|
ctx->destination = optarg;
|
|
|
|
break;
|
|
|
|
case OPT_EXTRACT_no_chown:
|
2021-11-05 11:20:19 +00:00
|
|
|
ctx->extract_flags |= APK_FSEXTRACTF_NO_CHOWN;
|
2021-06-09 20:12:52 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct apk_option_group optgroup_applet = {
|
|
|
|
.desc = option_desc,
|
|
|
|
.parse = option_parse_applet,
|
|
|
|
};
|
|
|
|
|
2021-09-03 10:44:48 +00:00
|
|
|
static int extract_v3_meta(struct apk_extract_ctx *ectx, struct adb_obj *pkg)
|
2021-06-09 20:12:52 +00:00
|
|
|
{
|
2021-07-30 13:38:53 +00:00
|
|
|
return 0;
|
2021-06-09 20:12:52 +00:00
|
|
|
}
|
|
|
|
|
2021-07-30 13:38:53 +00:00
|
|
|
static int extract_file(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
|
2021-06-09 20:12:52 +00:00
|
|
|
{
|
2021-07-30 13:38:53 +00:00
|
|
|
struct extract_ctx *ctx = container_of(ectx, struct extract_ctx, ectx);
|
2021-08-03 18:21:09 +00:00
|
|
|
struct apk_out *out = &ctx->ac->out;
|
2021-06-09 20:12:52 +00:00
|
|
|
|
2021-08-03 18:21:09 +00:00
|
|
|
apk_dbg2(out, "%s", fi->name);
|
|
|
|
|
2021-11-05 11:20:19 +00:00
|
|
|
return apk_fs_extract(ctx->ac, fi, is, 0, 0, ctx->extract_flags, APK_BLOB_NULL);
|
2021-06-09 20:12:52 +00:00
|
|
|
}
|
|
|
|
|
2021-07-30 13:38:53 +00:00
|
|
|
static const struct apk_extract_ops extract_ops = {
|
|
|
|
.v2meta = apk_extract_v2_meta,
|
|
|
|
.v3meta = extract_v3_meta,
|
|
|
|
.file = extract_file,
|
|
|
|
};
|
|
|
|
|
2021-06-09 20:12:52 +00:00
|
|
|
static int extract_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
|
|
|
|
{
|
|
|
|
struct extract_ctx *ctx = pctx;
|
|
|
|
struct apk_out *out = &ac->out;
|
|
|
|
char **parg;
|
2021-07-26 11:10:58 +00:00
|
|
|
int r = 0;
|
2021-06-09 20:12:52 +00:00
|
|
|
|
|
|
|
ctx->ac = ac;
|
2021-11-05 11:20:19 +00:00
|
|
|
if (!(ac->force & APK_FORCE_OVERWRITE)) ctx->extract_flags |= APK_FSEXTRACTF_NO_OVERWRITE;
|
2021-06-09 20:12:52 +00:00
|
|
|
if (!ctx->destination) ctx->destination = ".";
|
2021-11-05 11:20:19 +00:00
|
|
|
|
|
|
|
ac->dest_fd = openat(AT_FDCWD, ctx->destination, O_RDONLY);
|
|
|
|
if (ac->dest_fd < 0) {
|
2021-06-09 20:12:52 +00:00
|
|
|
r = -errno;
|
|
|
|
apk_err(out, "Error opening destination '%s': %s",
|
|
|
|
ctx->destination, apk_error_str(r));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2021-07-30 13:38:53 +00:00
|
|
|
apk_extract_init(&ctx->ectx, ac, &extract_ops);
|
2021-06-09 20:12:52 +00:00
|
|
|
foreach_array_item(parg, args) {
|
|
|
|
apk_out(out, "Extracting %s...", *parg);
|
2021-07-30 13:38:53 +00:00
|
|
|
r = apk_extract(&ctx->ectx, apk_istream_from_fd_url(AT_FDCWD, *parg, apk_ctx_since(ac, 0)));
|
2021-06-09 20:12:52 +00:00
|
|
|
if (r != 0) {
|
|
|
|
apk_err(out, "%s: %s", *parg, apk_error_str(r));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-11-05 11:20:19 +00:00
|
|
|
close(ac->dest_fd);
|
2021-06-09 20:12:52 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2021-07-26 13:25:03 +00:00
|
|
|
static struct apk_applet app_extract = {
|
2021-06-09 20:12:52 +00:00
|
|
|
.name = "extract",
|
|
|
|
.context_size = sizeof(struct extract_ctx),
|
|
|
|
.optgroups = { &optgroup_global, &optgroup_applet },
|
|
|
|
.main = extract_main,
|
|
|
|
};
|
|
|
|
|
2021-07-26 13:25:03 +00:00
|
|
|
APK_DEFINE_APPLET(app_extract);
|
2021-06-09 20:12:52 +00:00
|
|
|
|