mkpkg, extract: implement support for symlinks, devices and fifos

cute-signatures
Timo Teräs 2021-06-23 18:06:20 +03:00
parent 2433c9d23b
commit 22a81e8fb5
4 changed files with 101 additions and 33 deletions

View File

@ -448,7 +448,7 @@ const struct adb_object_schema schema_file = {
ADB_FIELD(ADBI_FI_SIZE, "size", scalar_int),
ADB_FIELD(ADBI_FI_MTIME, "mtime", scalar_int),
ADB_FIELD(ADBI_FI_HASHES, "hash", scalar_hexblob),
ADB_FIELD(ADBI_FI_TARGET, "target", scalar_string),
ADB_FIELD(ADBI_FI_TARGET, "target", scalar_hexblob),
},
};

View File

@ -169,25 +169,62 @@ static int apk_extract_file(struct extract_ctx *ctx, off_t sz, struct apk_istrea
struct adb_obj acl;
struct apk_digest_ctx dctx;
struct apk_digest d;
apk_blob_t target;
int r;
apk_digest_from_blob(&fi.digest, adb_ro_blob(&ctx->file, ADBI_FI_HASHES));
if (fi.digest.alg == APK_DIGEST_NONE) return -APKE_ADB_SCHEMA;
apk_extract_acl(&fi, adb_ro_obj(&ctx->file, ADBI_FI_ACL, &acl), apk_ctx_get_id_cache(ctx->ac));
fi.mode |= S_IFREG;
apk_digest_ctx_init(&dctx, fi.digest.alg);
if (ctx->is_uvol) {
r = apk_extract_volume(ac, &fi, is, &dctx);
} else {
r = apk_archive_entry_extract(
ctx->root_fd, &fi, 0, 0, is, 0, 0, &dctx,
target = adb_ro_blob(&ctx->file, ADBI_FI_TARGET);
if (!APK_BLOB_IS_NULL(target)) {
char *target_path;
uint16_t mode;
if (target.len < 2) return -APKE_ADB_SCHEMA;
mode = *(uint16_t*)target.ptr;
target.ptr += 2;
target.len -= 2;
switch (mode) {
case S_IFBLK:
case S_IFCHR:
case S_IFIFO:
if (target.len != sizeof(uint64_t)) return -APKE_ADB_SCHEMA;
struct unaligned64 {
uint64_t value;
} __attribute__((packed));
fi.device = ((struct unaligned64 *)target.ptr)->value;
break;
case S_IFLNK:
target_path = alloca(target.len + 1);
memcpy(target_path, target.ptr, target.len);
target_path[target.len] = 0;
fi.link_target = target_path;
break;
default:
return -APKE_ADB_SCHEMA;
}
fi.mode |= mode;
return apk_archive_entry_extract(
ctx->root_fd, &fi, 0, 0, is, 0, 0, 0,
ctx->extract_flags, out);
} else {
apk_digest_from_blob(&fi.digest, adb_ro_blob(&ctx->file, ADBI_FI_HASHES));
if (fi.digest.alg == APK_DIGEST_NONE) return -APKE_ADB_SCHEMA;
fi.mode |= S_IFREG;
apk_digest_ctx_init(&dctx, fi.digest.alg);
if (ctx->is_uvol) {
r = apk_extract_volume(ac, &fi, is, &dctx);
} else {
r = apk_archive_entry_extract(
ctx->root_fd, &fi, 0, 0, is, 0, 0, &dctx,
ctx->extract_flags, out);
}
apk_digest_ctx_final(&dctx, &d);
apk_digest_ctx_free(&dctx);
if (r != 0) return r;
if (apk_digest_cmp(&fi.digest, &d) != 0) return -APKE_FILE_INTEGRITY;
}
apk_digest_ctx_final(&dctx, &d);
apk_digest_ctx_free(&dctx);
if (r != 0) return r;
if (apk_digest_cmp(&fi.digest, &d) != 0) return -APKE_FILE_INTEGRITY;
return 0;
}

View File

@ -119,40 +119,71 @@ static int mkpkg_process_dirent(void *pctx, int dirfd, const char *entry)
struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
struct apk_file_info fi;
struct adb_obj fio, acl;
apk_blob_t target = APK_BLOB_NULL;
union {
uint16_t mode;
struct {
uint16_t mode;
uint64_t dev;
} __attribute__((packed)) dev;
struct {
uint16_t mode;
char target[1022];
} symlink;
} ft;
int r;
r = apk_fileinfo_get(dirfd, entry, APK_FI_NOFOLLOW | APK_FI_DIGEST(APK_DIGEST_SHA256), &fi, NULL);
if (r) return r;
switch (fi.mode & S_IFMT) {
case S_IFREG:
ctx->installed_size += (fi.size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE-1);
break;
case S_IFBLK:
case S_IFCHR:
case S_IFIFO:
ft.dev.mode = fi.mode & S_IFMT;
ft.dev.dev = fi.device;
target = APK_BLOB_STRUCT(ft.dev);
break;
case S_IFLNK:
ft.symlink.mode = fi.mode & S_IFMT;
r = readlinkat(dirfd, entry, ft.symlink.target, sizeof ft.symlink.target);
if (r < 0) return r;
target = APK_BLOB_PTR_LEN((void*)&ft.symlink, sizeof(ft.symlink.mode) + r);
r = 0;
break;
case S_IFDIR:
apk_pathbuilder_push(&ctx->pb, entry);
r = mkpkg_process_directory(ctx, openat(dirfd, entry, O_RDONLY), &fi);
apk_pathbuilder_pop(&ctx->pb);
break;
case S_IFREG:
adb_wo_alloca(&fio, &schema_file, &ctx->db);
adb_wo_alloca(&acl, &schema_acl, &ctx->db);
adb_wo_blob(&fio, ADBI_FI_NAME, APK_BLOB_STR(entry));
adb_wo_blob(&fio, ADBI_FI_HASHES, APK_DIGEST_BLOB(fi.digest));
adb_wo_int(&fio, ADBI_FI_MTIME, fi.mtime);
adb_wo_int(&fio, ADBI_FI_SIZE, fi.size);
ctx->installed_size += (fi.size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE-1);
adb_wo_int(&acl, ADBI_ACL_MODE, fi.mode & 07777);
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, fi.uid));
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, fi.gid));
adb_wo_obj(&fio, ADBI_FI_ACL, &acl);
adb_wa_append_obj(ctx->files, &fio);
break;
return r;
default:
apk_pathbuilder_push(&ctx->pb, entry);
apk_out(out, "%s: special file ignored",
apk_pathbuilder_cstr(&ctx->pb), entry);
apk_pathbuilder_pop(&ctx->pb);
break;
return 0;
}
adb_wo_alloca(&fio, &schema_file, &ctx->db);
adb_wo_alloca(&acl, &schema_acl, &ctx->db);
adb_wo_blob(&fio, ADBI_FI_NAME, APK_BLOB_STR(entry));
if (APK_BLOB_IS_NULL(target))
adb_wo_blob(&fio, ADBI_FI_HASHES, APK_DIGEST_BLOB(fi.digest));
else
adb_wo_blob(&fio, ADBI_FI_TARGET, target);
adb_wo_int(&fio, ADBI_FI_MTIME, fi.mtime);
adb_wo_int(&fio, ADBI_FI_SIZE, fi.size);
adb_wo_int(&acl, ADBI_ACL_MODE, fi.mode & 07777);
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, fi.uid));
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, fi.gid));
adb_wo_obj(&fio, ADBI_FI_ACL, &acl);
adb_wa_append_obj(ctx->files, &fio);
return r;
}

View File

@ -724,7 +724,7 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags,
.gid = st.st_gid,
.mode = st.st_mode,
.mtime = st.st_mtime,
.device = st.st_dev,
.device = st.st_rdev,
};
if (xattr_hash_alg != APK_DIGEST_NONE) {