提交 642cd5e5 编写于 作者: W WangFengTu 提交者: lifeng68

support import rootfs tarbal to be image

Signed-off-by: NWangFengTu <wangfengtu@huawei.com>
上级 8e735c3d
#!/bin/bash
#
# attributes: isulad basic image
# concurrent: NA
# spend time: 2
#######################################################################
##- @Copyright (C) Huawei Technologies., Ltd. 2020. All rights reserved.
# - iSulad licensed under the Mulan PSL v2.
# - You can use this software according to the terms and conditions of the Mulan PSL v2.
# - You may obtain a copy of Mulan PSL v2 at:
# - http://license.coscl.org.cn/MulanPSL2
# - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# - IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# - PURPOSE.
# - See the Mulan PSL v2 for more details.
##- @Description:CI
##- @Author: wangfengtu
##- @Create: 2020-06-19
#######################################################################
declare -r curr_path=$(dirname $(readlink -f "$0"))
source ../helpers.bash
rootfs_tar="${curr_path}/rootfs.tar"
rootfs_tar_xz="${curr_path}/rootfs.tar.xz"
import_tar="import_tar"
import_tar_xz="import_tar_xz"
function test_image_import()
{
local ret=0
local test="isula import image test => (${FUNCNAME[@]})"
msg_info "${test} starting..."
isula import $rootfs_tar ${import_tar}
[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - import image failed: ${rootfs_tar}" && ((ret++))
isula import $rootfs_tar_xz ${import_tar_xz}
[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - import image failed: ${rootfs_tar_xz}" && ((ret++))
isula run --rm -ti ${import_tar} echo hello
[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to run ${import_tar}" && ((ret++))
isula run --rm -ti ${import_tar_xz} echo hello
[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to run ${import_tar_xz}" && ((ret++))
isula rm -f `isula ps -a -q`
isula rmi ${import_tar}
[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to remove ${import_tar}" && ((ret++))
isula rmi ${import_tar_xz}
[[ $? -ne 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - fail to remove ${import_tar_xz}" && ((ret++))
msg_info "${test} finished with return ${ret}..."
return ${ret}
}
declare -i ans=0
test_image_import || ((ans++))
show_result ${ans} "${curr_path}/${0}"
......@@ -39,6 +39,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <sys/utsname.h>
#include "utils.h"
#include "isula_libutils/log.h"
......@@ -1647,3 +1648,114 @@ char *util_int_to_string(long long int data)
return util_strdup_s(numstr);
}
static char *get_cpu_variant()
{
char *variant = NULL;
char *cpuinfo = NULL;
char *start_pos = NULL;
char *end_pos = NULL;
cpuinfo = util_read_text_file("/proc/cpuinfo");
if (cpuinfo == NULL) {
ERROR("read /proc/cpuinfo failed");
return NULL;
}
start_pos = strstr(cpuinfo, "CPU architecture");
if (start_pos == NULL) {
ERROR("can not found the key \"CPU architecture\" when try to get cpu variant");
goto out;
}
end_pos = strchr(start_pos, '\n');
if (end_pos != NULL) {
*end_pos = 0;
}
start_pos = strchr(start_pos, ':');
if (start_pos == NULL) {
ERROR("can not found delimiter \":\" when try to get cpu variant");
goto out;
}
util_trim_newline(start_pos);
start_pos = util_trim_space(start_pos);
variant = strings_to_lower(start_pos);
out:
free(cpuinfo);
cpuinfo = NULL;
return variant;
}
int normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant)
{
int ret = 0;
struct utsname uts;
char *tmp_variant = NULL;
if (host_os == NULL || host_arch == NULL || host_variant == NULL) {
ERROR("Invalid NULL pointer");
return -1;
}
if (uname(&uts) < 0) {
ERROR("Failed to read host arch and os: %s", strerror(errno));
ret = -1;
goto out;
}
*host_os = strings_to_lower(uts.sysname);
if (strcasecmp("i386", uts.machine) == 0) {
*host_arch = util_strdup_s("386");
} else if ((strcasecmp("x86_64", uts.machine) == 0) || (strcasecmp("x86-64", uts.machine) == 0)) {
*host_arch = util_strdup_s("amd64");
} else if (strcasecmp("aarch64", uts.machine) == 0) {
*host_arch = util_strdup_s("arm64");
} else if ((strcasecmp("armhf", uts.machine) == 0) || (strcasecmp("armel", uts.machine) == 0)) {
*host_arch = util_strdup_s("arm");
} else {
*host_arch = util_strdup_s(uts.machine);
}
if (!strcmp(*host_arch, "arm") || !strcmp(*host_arch, "arm64")) {
*host_variant = get_cpu_variant();
if (!strcmp(*host_arch, "arm64") && *host_variant != NULL &&
(!strcmp(*host_variant, "8") || !strcmp(*host_variant, "v8"))) {
free(*host_variant);
*host_variant = NULL;
}
if (!strcmp(*host_arch, "arm") && *host_variant == NULL) {
*host_variant = util_strdup_s("v7");
} else if (!strcmp(*host_arch, "arm") && *host_variant != NULL) {
tmp_variant = *host_variant;
*host_variant = NULL;
if (!strcmp(tmp_variant, "5")) {
*host_variant = util_strdup_s("v5");
} else if (!strcmp(tmp_variant, "6")) {
*host_variant = util_strdup_s("v6");
} else if (!strcmp(tmp_variant, "7")) {
*host_variant = util_strdup_s("v7");
} else if (!strcmp(tmp_variant, "8")) {
*host_variant = util_strdup_s("v8");
} else {
*host_variant = util_strdup_s(tmp_variant);
}
free(tmp_variant);
tmp_variant = NULL;
}
}
out:
if (ret != 0) {
free(*host_os);
*host_os = NULL;
free(*host_arch);
*host_arch = NULL;
free(*host_variant);
*host_variant = NULL;
}
return ret;
}
......@@ -397,6 +397,12 @@ char *util_uint_to_string(long long unsigned int data);
char *util_int_to_string(long long int data);
char *without_sha256_prefix(char *digest);
int normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant);
char *util_full_digest_str(char *str);
#ifdef __cplusplus
}
#endif
......
......@@ -97,6 +97,19 @@ out:
return ret;
}
static void cleanup_image_tmpdir()
{
if (util_recursive_rmdir(IMAGE_TMP_PATH, 0)) {
ERROR("failed to remove directory %s", IMAGE_TMP_PATH);
}
if (util_mkdir_p(IMAGE_TMP_PATH, 0600)) {
ERROR("failed to create directory %s", IMAGE_TMP_PATH);
}
return;
}
int oci_init(const struct service_arguments *args)
{
int ret = 0;
......@@ -106,6 +119,8 @@ int oci_init(const struct service_arguments *args)
return ret;
}
cleanup_image_tmpdir();
ret = registry_init();
if (ret != 0) {
ret = -1;
......
......@@ -12,11 +12,547 @@
* Create: 2020-05-26
* Description: isula image import operator implement
*******************************************************************************/
#include "mediatype.h"
#include "oci_import.h"
#include "isula_libutils/log.h"
#include "storage.h"
#include "libisulad.h"
#include "utils.h"
#include "isula_libutils/registry_manifest_schema2.h"
#include "isula_libutils/docker_image_config_v2.h"
#include "util_archive.h"
#include "utils_images.h"
#include "sha256.h"
int oci_do_import(const char *file, const char *tag, char **id)
#define IMPORT_COMMENT "Imported from tarball"
#define ROOTFS_TYPE "layers"
#define MANIFEST_BIG_DATA_KEY "manifest"
#define TIME_BUF_MAX_LEN 128
#define TEMP_FILE_TEMPLATE IMAGE_TMP_PATH"import-XXXXXX"
typedef struct {
char *manifest;
char *manifest_digest;
char *config;
char *config_digest;
char *uncompressed_digest;
char *compressed_digest;
int64_t compressed_size;
types_timestamp_t now_time;
char *tag;
char *uncompressed_file;
} import_desc;
static void free_import_desc(import_desc *desc)
{
if (desc == NULL) {
return;
}
free(desc->manifest);
desc->manifest = NULL;
free(desc->manifest_digest);
desc->manifest_digest = NULL;
free(desc->config);
desc->config = NULL;
free(desc->config_digest);
desc->config_digest = NULL;
free(desc->uncompressed_digest);
desc->uncompressed_digest = NULL;
free(desc->compressed_digest);
desc->compressed_digest = NULL;
free(desc->tag);
desc->tag = NULL;
free(desc->uncompressed_digest);
desc->uncompressed_digest = NULL;
free(desc->uncompressed_file);
desc->uncompressed_file = NULL;
free(desc);
return;
}
static int register_layer(import_desc *desc)
{
char *id = NULL;
struct layer *l = NULL;
if (desc == NULL || desc->uncompressed_digest == NULL || desc->compressed_digest == NULL) {
ERROR("Invalid NULL param");
return -1;
}
id = without_sha256_prefix(desc->uncompressed_digest);
if (id == NULL) {
ERROR("Invalid NULL param");
return -1;
}
l = storage_layer_get(id);
if (l != NULL) {
free_layer(l);
l = NULL;
return 0;
} else {
storage_layer_create_opts_t copts = {
.parent = NULL,
.uncompress_digest = desc->uncompressed_digest,
.compressed_digest = desc->compressed_digest,
.writable = false,
.layer_data_path = desc->uncompressed_file,
};
return storage_layer_create(id, &copts);
}
}
static int create_config(import_desc *desc)
{
int ret = 0;
docker_image_config_v2 *config = NULL;
char *host_os = NULL;
char *host_arch = NULL;
char *host_variant = NULL;
parser_error err = NULL;
char time_str[TIME_BUF_MAX_LEN] = {0};
if (desc == NULL || desc->uncompressed_digest == NULL) {
ERROR("Invalid NULL param");
return -1;
}
config = util_common_calloc_s(sizeof(docker_image_config_v2));
if (config == NULL) {
ERROR("out of memory");
return -1;
}
ret = normalized_host_os_arch(&host_os, &host_arch, &host_variant);
if (ret != 0) {
ERROR("get host os and arch for import failed");
isulad_try_set_error_message("get host os and arch for import failed");
goto out;
}
config->rootfs = util_common_calloc_s(sizeof(docker_image_rootfs));
config->config = util_common_calloc_s(sizeof(container_config));
config->container_config = util_common_calloc_s(sizeof(container_config));
config->history = util_common_calloc_s(sizeof(docker_image_history*));
if (config->history == NULL || config->config == NULL ||
config->container_config == NULL || config->rootfs == NULL) {
ERROR("out of memory");
isulad_try_set_error_message("out of memory");
ret = -1;
goto out;
}
config->history_len = 1;
config->rootfs->type = util_strdup_s(ROOTFS_TYPE);
config->rootfs->diff_ids = util_common_calloc_s(sizeof(char *));
if (config->rootfs->diff_ids == NULL) {
ERROR("out of memory");
isulad_try_set_error_message("out of memory");
ret = -1;
goto out;
}
config->rootfs->diff_ids_len = 1;
config->history[0] = util_common_calloc_s(sizeof(docker_image_history));
if (config->history[0] == NULL) {
ERROR("out of memory");
isulad_try_set_error_message("out of memory");
ret = -1;
goto out;
}
if (!get_time_buffer(&desc->now_time, time_str, TIME_BUF_MAX_LEN)) {
ERROR("get time string from timestamp failed");
isulad_try_set_error_message("get time string from timestamp failed");
ret = -1;
goto out;
}
config->history[0]->comment = util_strdup_s(IMPORT_COMMENT);
config->history[0]->created = util_strdup_s(time_str);
config->rootfs->diff_ids[0] = util_strdup_s(desc->uncompressed_digest);
config->comment = util_strdup_s(IMPORT_COMMENT);
config->created = util_strdup_s(time_str);
config->os = host_os;
host_os = NULL;
config->architecture = host_arch;
host_arch = NULL;
desc->config = docker_image_config_v2_generate_json(config, NULL, &err);
if (desc->config == NULL) {
ERROR("generate default config for import failed: %s", err);
isulad_try_set_error_message("generate default config for import failed: %s", err);
ret = -1;
goto out;
}
desc->config_digest = sha256_full_digest_str(desc->config);
if (desc->config_digest == NULL) {
ERROR("calc digest of config for import failed");
isulad_try_set_error_message("calc digest of config for import failed");
ret = -1;
goto out;
}
out:
free(err);
err = NULL;
free(host_os);
host_os = NULL;
free(host_arch);
host_arch = NULL;
free(host_variant);
host_variant = NULL;
free_docker_image_config_v2(config);
config = NULL;
return ret;
}
static int create_manifest(import_desc *desc)
{
int ret = 0;
registry_manifest_schema2 *manifest = NULL;
parser_error err = NULL;
if (desc == NULL || desc->compressed_digest == NULL || desc->config == NULL ||
desc->config_digest == NULL) {
ERROR("Invalid NULL param");
return -1;
}
manifest = util_common_calloc_s(sizeof(registry_manifest_schema2));
if (manifest == NULL) {
ERROR("out of memory");
isulad_try_set_error_message("out of memory");
ret = -1;
goto out;
}
manifest->config = util_common_calloc_s(sizeof(registry_manifest_schema2_config));
manifest->layers = util_common_calloc_s(sizeof(registry_manifest_schema2_layers_element*));
if (manifest->config == NULL || manifest->layers == NULL) {
ERROR("out of memory");
isulad_try_set_error_message("out of memory");
ret = -1;
goto out;
}
manifest->layers_len = 1;
manifest->layers[0] = util_common_calloc_s(sizeof(registry_manifest_schema2_layers_element*));
if (manifest->layers[0] == NULL) {
ERROR("out of memory");
isulad_try_set_error_message("out of memory");
ret = -1;
goto out;
}
manifest->config->size = strlen(desc->config);
manifest->config->media_type = util_strdup_s(DOCKER_IMAGE_V1);
manifest->config->digest = util_strdup_s(desc->config_digest);
manifest->layers[0]->media_type = util_strdup_s(DOCKER_IMAGE_LAYER_TAR_GZIP);
manifest->layers[0]->size = desc->compressed_size;
manifest->layers[0]->digest = util_strdup_s(desc->compressed_digest);
manifest->schema_version = 2;
manifest->media_type = util_strdup_s(DOCKER_MANIFEST_SCHEMA2_JSON);
desc->manifest = registry_manifest_schema2_generate_json(manifest, NULL, &err);
if (desc->manifest == NULL) {
ERROR("generate default manifest for import failed: %s", err);
isulad_try_set_error_message("generate default manifest for import failed: %s", err);
ret = -1;
goto out;
}
desc->manifest_digest = sha256_full_digest_str(desc->manifest);
if (desc->manifest_digest == NULL) {
ERROR("calc digest of manifest for import failed");
isulad_try_set_error_message("calc digest of manifest for import failed");
ret = -1;
goto out;
}
out:
free(err);
err = NULL;
free_registry_manifest_schema2(manifest);
manifest = NULL;
return ret;
}
static int register_image(import_desc *desc)
{
int ret = 0;
char *image_id = NULL;
char *pre_top_layer = NULL;
char *top_layer_id = NULL;
bool image_created = false;
struct storage_img_create_options opts = { 0 };
if (desc == NULL || desc->manifest == NULL || desc->manifest_digest == NULL ||
desc->config == NULL || desc->config_digest == NULL ||
desc->uncompressed_digest == NULL) {
ERROR("Invalid NULL param");
return -1;
}
opts.create_time = &desc->now_time;
opts.digest = desc->manifest_digest;
image_id = without_sha256_prefix(desc->config_digest);
top_layer_id = without_sha256_prefix(desc->uncompressed_digest);
ret = storage_img_create(image_id, top_layer_id, NULL, &opts);
if (ret != 0) {
pre_top_layer = storage_get_img_top_layer(image_id);
if (pre_top_layer == NULL) {
ERROR("create image %s for %s failed", image_id, desc->tag);
ret = -1;
goto out;
}
if (strcmp(pre_top_layer, top_layer_id) != 0) {
ERROR("error committing image, image id %s exist, but top layer doesn't match. local %s, import %s",
image_id, pre_top_layer, top_layer_id);
ret = -1;
goto out;
}
ret = 0;
}
image_created = true;
ret = storage_img_add_name(image_id, desc->tag);
if (ret != 0) {
ERROR("add image name %s failed", desc->tag);
goto out;
}
ret = storage_img_set_big_data(image_id, desc->config_digest, desc->config);
if (ret != 0) {
ERROR("set config for import %s failed", desc->tag);
goto out;
}
ret = storage_img_set_big_data(image_id, MANIFEST_BIG_DATA_KEY, desc->manifest);
if (ret != 0) {
ERROR("set manifest for import %s failed", desc->tag);
goto out;
}
ret = storage_img_set_loaded_time(image_id, &desc->now_time);
if (ret != 0) {
ERROR("set loaded time failed");
goto out;
}
ret = storage_img_set_image_size(image_id);
if (ret != 0) {
ERROR("set image size failed for %s failed", desc->tag);
isulad_try_set_error_message("set image size failed");
goto out;
}
out:
if (ret != 0 && image_created) {
if (storage_img_delete(image_id, true)) {
ERROR("delete image %s failed", image_id);
}
}
return ret;
}
static char * create_temp_file()
{
int fd = -1;
char temp_file[] = TEMP_FILE_TEMPLATE;
fd = mkstemp(temp_file);
if (fd < 0) {
ERROR("make temporary file failed: %s", strerror(errno));
isulad_try_set_error_message("make temporary file failed: %s", strerror(errno));
return NULL;
}
close(fd);
return util_strdup_s(temp_file);
}
static import_desc *prepre_import(char *file, char *tag)
{
int ret = 0;
import_desc *desc = NULL;
char *errmsg = NULL;
desc = util_common_calloc_s(sizeof(import_desc));
if (desc == NULL) {
ERROR("out of memory");
isulad_try_set_error_message("out of memory");
return NULL;
}
desc->compressed_size = util_file_size(file);
if (desc->compressed_size < 0) {
ERROR("Calc size of file %s for import failed", file);
isulad_try_set_error_message("Calc size of file %s for import failed", file);
ret = -1;
goto out;
}
desc->compressed_digest = sha256_full_file_digest(file);
if (desc->compressed_digest == NULL) {
ERROR("Calc compressed digest of file %s failed", file);
isulad_try_set_error_message("Calc compressed digest of file %s failed", file);
ret = -1;
goto out;
}
desc->uncompressed_file = create_temp_file();
if (desc->uncompressed_file == NULL) {
ERROR("create temporary file for import failed");
isulad_try_set_error_message("create temporary file for import failed");
ret = -1;
goto out;
}
ret = archive_uncompress(file, desc->uncompressed_file, &errmsg);
if (ret != 0) {
ERROR("uncompress %s for import failed: %s", file, errmsg);
isulad_try_set_error_message("uncompress %s for import failed: %s", file, errmsg);
ret = -1;
goto out;
}
desc->uncompressed_digest = sha256_full_file_digest(desc->uncompressed_file);
if (desc->uncompressed_digest == NULL) {
ERROR("Calc uncompressed digest of file %s failed", file);
isulad_try_set_error_message("Calc uncompressed digest of file %s failed", file);
ret = -1;
goto out;
}
if (!get_now_time_stamp(&desc->now_time)) {
ERROR("get time stamp for import failed");
isulad_try_set_error_message("get time stamp for import failed");
ret = -1;
goto out;
}
desc->tag = util_strdup_s(tag);
out:
if (ret != 0) {
free_import_desc(desc);
desc = NULL;
}
free(errmsg);
errmsg = NULL;
return desc;
}
static int do_import(char *file, char *tag)
{
int ret = 0;
import_desc *desc = NULL;
if (file == NULL || tag == NULL) {
ERROR("Invalid NULL param");
return -1;
}
desc = prepre_import(file, tag);
if (desc == NULL) {
ERROR("Prepare import %s to be %s failed", file, tag);
isulad_try_set_error_message("Prepare import failed");
return -1;
}
ret = register_layer(desc);
if (ret != 0) {
ERROR("Register layer from file %s for import failed", file);
isulad_try_set_error_message("Register layer from file %s for import failed", file);
goto out;
}
ret = create_config(desc);
if (ret != 0) {
ERROR("Create config for import failed");
isulad_try_set_error_message("Create config for import failed");
ret = -1;
goto out;
}
ret = create_manifest(desc);
if (ret != 0) {
ERROR("Create manifest for import failed");
isulad_try_set_error_message("Create manifest for import failed");
ret = -1;
goto out;
}
ret = register_image(desc);
if (ret != 0) {
ERROR("Register image for import failed");
isulad_try_set_error_message("Register image for import failed");
goto out;
}
out:
if (desc->uncompressed_file != NULL) {
if (util_path_remove(desc->uncompressed_file)) {
WARN("failed to remove file %s: %s", desc->uncompressed_file, strerror(errno));
}
}
free_import_desc(desc);
desc = NULL;
return ret;
}
int oci_do_import(char *file, char *tag, char **id)
{
int ret = 0;
imagetool_image *image = NULL;
if (file == NULL || tag == NULL || id == NULL) {
ERROR("Invalid NULL param");
return -1;
}
ret = do_import(file, tag);
if (ret != 0) {
ERROR("import %s failed", tag);
goto out;
}
image = storage_img_get(tag);
if (image == NULL) {
ERROR("get image %s failed after import", tag);
isulad_try_set_error_message("get image %s failed after import", tag);
ret = -1;
goto out;
}
*id = util_strdup_s(image->id);
out:
free_imagetool_image(image);
return ret;
}
void oci_import_cleanup()
{
//TODO implement import function by storage API
return 0;
return;
}
......@@ -19,7 +19,8 @@
extern "C" {
#endif
int oci_do_import(const char *file, const char *tag, char **id);
int oci_do_import(char *file, char *tag, char **id);
void oci_import_cleanup();
#ifdef __cplusplus
}
......
......@@ -1476,7 +1476,7 @@ static int prepare_pull_desc(pull_descriptor *desc, registry_pull_options *optio
{
int ret = 0;
int sret = 0;
char blobpath[REGISTRY_TMP_DIR_LEN] = REGISTRY_TMP_DIR;
char blobpath[] = REGISTRY_TMP_DIR;
char scope[PATH_MAX] = { 0 };
if (desc == NULL || options == NULL) {
......@@ -1630,32 +1630,10 @@ static void cached_layers_kvfree(void *key, void *value)
return;
}
static void remove_temporary_dirs()
{
int ret = 0;
int sret = 0;
char cmd[PATH_MAX] = { 0 };
sret = snprintf(cmd, sizeof(cmd), "/usr/bin/rm -rf %s", REGISTRY_TMP_DIR_ALL);
if (sret < 0 || (size_t)sret >= sizeof(cmd)) {
ERROR("Failed to sprintf cmd to remove temporary directory");
return;
}
ret = system(cmd);
if (ret != 0) {
ERROR("execute \"%s\" got result %d", cmd, ret);
}
return;
}
int registry_init()
{
int ret = 0;
remove_temporary_dirs();
g_shared = util_common_calloc_s(sizeof(registry_global));
if (g_shared == NULL) {
ERROR("out of memory");
......
......@@ -680,117 +680,6 @@ out:
return ret;
}
static char *get_cpu_variant()
{
char *variant = NULL;
char *cpuinfo = NULL;
char *start_pos = NULL;
char *end_pos = NULL;
cpuinfo = util_read_text_file("/proc/cpuinfo");
if (cpuinfo == NULL) {
ERROR("read /proc/cpuinfo failed");
return NULL;
}
start_pos = strstr(cpuinfo, "CPU architecture");
if (start_pos == NULL) {
ERROR("can not found the key \"CPU architecture\" when try to get cpu variant");
goto out;
}
end_pos = strchr(start_pos, '\n');
if (end_pos != NULL) {
*end_pos = 0;
}
start_pos = strchr(start_pos, ':');
if (start_pos == NULL) {
ERROR("can not found delimiter \":\" when try to get cpu variant");
goto out;
}
util_trim_newline(start_pos);
start_pos = util_trim_space(start_pos);
variant = util_strdup_s(start_pos);
out:
free(cpuinfo);
cpuinfo = NULL;
return variant;
}
static int normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant)
{
int ret = 0;
struct utsname uts;
char *tmp_variant = NULL;
if (host_os == NULL || host_arch == NULL || host_variant == NULL) {
ERROR("Invalid NULL pointer");
return -1;
}
if (uname(&uts) < 0) {
ERROR("Failed to read host arch and os: %s", strerror(errno));
ret = -1;
goto out;
}
*host_os = util_strdup_s(uts.sysname);
if (strcasecmp("i386", uts.machine) == 0) {
*host_arch = util_strdup_s("386");
} else if ((strcasecmp("x86_64", uts.machine) == 0) || (strcasecmp("x86-64", uts.machine) == 0)) {
*host_arch = util_strdup_s("amd64");
} else if (strcasecmp("aarch64", uts.machine) == 0) {
*host_arch = strdup("arm64");
} else if ((strcasecmp("armhf", uts.machine) == 0) || (strcasecmp("armel", uts.machine) == 0)) {
*host_arch = strdup("arm");
} else {
*host_arch = strdup(uts.machine);
}
if (!strcmp(*host_arch, "arm") || !strcmp(*host_arch, "arm64")) {
*host_variant = get_cpu_variant();
if (!strcmp(*host_arch, "arm64") && *host_variant != NULL &&
(!strcmp(*host_variant, "8") || !strcmp(*host_variant, "v8"))) {
free(*host_variant);
*host_variant = NULL;
}
if (!strcmp(*host_arch, "arm") && *host_variant == NULL) {
*host_variant = util_strdup_s("v7");
} else if (!strcmp(*host_arch, "arm") && *host_variant != NULL) {
tmp_variant = *host_variant;
*host_variant = NULL;
if (!strcmp(tmp_variant, "5")) {
*host_variant = util_strdup_s("v5");
} else if (!strcmp(tmp_variant, "6")) {
*host_variant = util_strdup_s("v6");
} else if (!strcmp(tmp_variant, "7")) {
*host_variant = util_strdup_s("v7");
} else if (!strcmp(tmp_variant, "8")) {
*host_variant = util_strdup_s("v8");
} else {
*host_variant = util_strdup_s(tmp_variant);
}
free(tmp_variant);
tmp_variant = NULL;
}
}
out:
if (ret != 0) {
free(*host_os);
*host_os = NULL;
free(*host_arch);
*host_arch = NULL;
free(*host_variant);
*host_variant = NULL;
}
return ret;
}
static bool is_variant_same(char *variant1, char *variant2)
{
if (variant1 == NULL && variant2 == NULL) {
......
......@@ -159,16 +159,6 @@ out:
return ret;
}
char *without_sha256_prefix(char *digest)
{
if (digest == NULL) {
ERROR("Invalid digest NULL when strip sha256 prefix");
return NULL;
}
return digest + strlen(SHA256_PREFIX);
}
types_timestamp_t created_to_timestamp(char *created)
{
int64_t nanos = 0;
......
......@@ -32,7 +32,6 @@ extern "C" {
void free_items_not_inherit(docker_image_config_v2 *config);
int add_rootfs_and_history(const layer_blob *layers, size_t layers_len,
const registry_manifest_schema1 *manifest, docker_image_config_v2 *config);
char *without_sha256_prefix(char *digest);
types_timestamp_t created_to_timestamp(char *created);
#ifdef __cplusplus
......
......@@ -20,14 +20,12 @@
#include <time.h>
#include "types_def.h"
#include "utils_images.h"
// 8 is enough for challenge, usually only one challenge is provided.
#define CHALLENGE_MAX 8
#define REGISTRY_TMP_DIR_COMMON "/var/tmp/isulad-registry-"
#define REGISTRY_TMP_DIR_LEN 32
#define REGISTRY_TMP_DIR REGISTRY_TMP_DIR_COMMON"XXXXXX"
#define REGISTRY_TMP_DIR_ALL REGISTRY_TMP_DIR_COMMON"*"
#define REGISTRY_TMP_DIR IMAGE_TMP_PATH"registry-XXXXXX"
#define MAX_LAYER_NUM 125
#define ROOTFS_TYPE "layers"
......
......@@ -32,6 +32,8 @@ extern "C" {
#define DEFAULT_REPO_PREFIX "library/"
#define MAX_ID_BUF_LEN 256
#define IMAGE_TMP_PATH "/var/tmp/isula-image/"
char *oci_get_host(const char *name);
char *oci_host_from_mirror(const char *mirror);
char *oci_default_tag(const char *name);
......
......@@ -496,3 +496,31 @@ bool sha256_valid_digest_file(const char *path, const char *digest)
return true;
}
char *sha256_full_digest_str(char *str)
{
char *digest = NULL;
char *full_digest = NULL;
digest = sha256_digest_str(str);
if (digest == NULL) {
ERROR("Failed to calculate chain id");
return NULL;
}
full_digest = util_full_digest(digest);
free(digest);
return full_digest;
}
char *without_sha256_prefix(char *digest)
{
if (digest == NULL || !util_has_prefix(digest, SHA256_PREFIX)) {
ERROR("Invalid digest when strip sha256 prefix");
return NULL;
}
return digest + strlen(SHA256_PREFIX);
}
......@@ -50,6 +50,10 @@ char *sha256_full_file_digest(const char *filename);
bool sha256_valid_digest_file(const char *path, const char *digest);
char *sha256_full_digest_str(char *str);
char *without_sha256_prefix(char *digest);
#ifdef __cplusplus
}
#endif
......
......@@ -294,3 +294,264 @@ child_out:
cleanup:
return ret;
}
static void try_set_errbuf_and_log(char *errbuf, const char *format, ...)
{
int ret = 0;
if (errbuf == NULL || strlen(errbuf) > 0) {
return;
}
va_list argp;
va_start(argp, format);
ret = vsnprintf(errbuf, BUFSIZ, format, argp);
va_end(argp);
if (ret < 0 || ret >= BUFSIZ) {
return;
}
ERROR("%s", errbuf);
return;
}
static int copy_data_between_archives(struct archive *ar, struct archive *aw, char *errbuf)
{
int r = ARCHIVE_FAILED;
const void *buff = NULL;
size_t size;
int64_t offset;
for (;;) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF) {
return ARCHIVE_OK;
}
if (r < ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "tar archive read result %d, error: %s",
r, archive_error_string(ar));
return r;
}
r = archive_write_data(aw, buff, size);
if (r < ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "tar archive write result %d, error: %s",
r, archive_error_string(aw));
return r;
}
}
}
static int archive_uncompress_handler(struct archive* src, struct archive* dest, char *errbuf)
{
int ret = 0;
struct archive_entry *entry = NULL;
for (;;) {
ret = archive_read_next_header(src, &entry);
if (ret == ARCHIVE_EOF) {
break;
}
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Warning reading tar header: %s", archive_error_string(src));
ret = -1;
goto out;
}
ret = archive_write_header(dest, entry);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Fail to handle tar header: %s", archive_error_string(dest));
ret = -1;
goto out;
} else if (archive_entry_size(entry) > 0) {
ret = copy_data_between_archives(src, dest, errbuf);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to do copy tar data: %s", archive_error_string(dest));
ret = -1;
goto out;
}
}
ret = archive_write_finish_entry(dest);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to freeing archive entry: %s\n", archive_error_string(dest));
ret = -1;
goto out;
}
}
ret = 0;
out:
return ret;
}
static struct archive * create_read_archive(const char *file, char *errbuf)
{
int ret = 0;
struct archive *read_archive = NULL;
read_archive = archive_read_new();
if (read_archive == NULL) {
try_set_errbuf_and_log(errbuf, "Failed to malloc archive read object: %s", strerror(errno));
ret = -1;
goto out;
}
ret = archive_read_support_filter_all(read_archive);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to set archive read support filter all, result is %d, errmsg: %s",
ret, archive_error_string(read_archive));
ret = -1;
goto out;
}
ret = archive_read_support_format_all(read_archive);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to set archive read support format all, result is %d, errmsg: %s",
ret, archive_error_string(read_archive));
ret = -1;
goto out;
}
ret = archive_read_open_filename(read_archive, file, ARCHIVE_READ_BUFFER_SIZE);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to open archive %s: %s", file, archive_error_string(read_archive));
ret = -1;
goto out;
}
out:
if (ret != ARCHIVE_OK && read_archive != NULL) {
if (archive_read_free(read_archive) != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to free archive %s: %s", file, archive_error_string(read_archive));
}
read_archive = NULL;
}
return read_archive;
}
static struct archive * create_write_archive(const char *file, int format_code, char *errbuf)
{
int ret = 0;
struct archive *write_archive = NULL;
write_archive = archive_write_new();
if (write_archive == NULL) {
try_set_errbuf_and_log(errbuf, "Failed to malloc archive write object: %s", strerror(errno));
ret = -1;
goto out;
}
ret = archive_write_set_format(write_archive, format_code);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to set format %d, result is %d, errmsg: %s",
format_code, ret, archive_error_string(write_archive));
ret = -1;
goto out;
}
ret = archive_write_open_filename(write_archive, file);
if (ret != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to open archive %s: %s",
file, archive_error_string(write_archive));
ret = -1;
goto out;
}
out:
if (ret != ARCHIVE_OK && write_archive != NULL) {
if (archive_write_free(write_archive) != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to free archive %s: %s",
file, archive_error_string(write_archive));
}
write_archive = NULL;
}
return write_archive;
}
void destroy_all_archive(struct archive *read_archive, struct archive *write_archive, char *errbuf)
{
if (read_archive != NULL) {
if (archive_read_free(read_archive) != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to free read archive: %s", archive_error_string(read_archive));
}
}
if (write_archive != NULL) {
if (archive_write_free(write_archive) != ARCHIVE_OK) {
try_set_errbuf_and_log(errbuf, "Failed to free write archive: %s", archive_error_string(write_archive));
}
}
return;
}
static int try_read_format_code(const char *file)
{
int ret = 0;
char errbuf[BUFSIZ] = {0};
int format_code = ARCHIVE_FORMAT_TAR_GNUTAR;
struct archive_entry *entry = NULL;
struct archive *ar = NULL;
ar = create_read_archive(file, errbuf);
if (ar == NULL) {
return ARCHIVE_FORMAT_TAR_GNUTAR;
}
// format code upated when archive_read_next_header is called
ret = archive_read_next_header(ar, &entry);
if (ret == ARCHIVE_OK) {
ret = archive_format(ar);
if (ret != 0) { // if not updated, result format code is default to be 0
format_code = ret;
}
}
archive_read_free(ar);
return format_code;
}
int archive_uncompress(const char *src, const char *dest, char **errmsg)
{
char errbuf[BUFSIZ] = {0};
struct archive *src_archive = NULL;
struct archive *dest_archive = NULL;
int ret = 0;
src_archive = create_read_archive(src, errbuf);
if (src_archive == NULL) {
try_set_errbuf_and_log(errbuf, "Failed to create archive read object");
ret = -1;
goto out;
}
dest_archive = create_write_archive(dest, try_read_format_code(src), errbuf);
if (dest_archive == NULL) {
try_set_errbuf_and_log(errbuf, "Failed to create archive write object");
ret = -1;
goto out;
}
ret = archive_uncompress_handler(src_archive, dest_archive, errbuf);
if (ret != 0) {
try_set_errbuf_and_log(errbuf, "Failed to uncompress %s to %s", src, dest);
goto out;
}
out:
destroy_all_archive(src_archive, dest_archive, errbuf);
src_archive = NULL;
dest_archive = NULL;
if (errmsg != NULL && strlen(errbuf) != 0) {
*errmsg = util_strdup_s(errbuf);
}
return ret;
}
......@@ -38,6 +38,8 @@ struct archive_options {
int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, const struct archive_options *options);
int archive_uncompress(const char *src, const char *dest, char **errmsg);
#ifdef __cplusplus
}
#endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册