Added the image system
This commit is contained in:
parent
0373d159a2
commit
b90502c4f2
@ -1,76 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
|
||||
/// @brief Checks whether the specified backing identifier is valid. This call returns a failure if the identifier is invalid.
|
||||
/// @param backing The backing identifier to check.
|
||||
/// @return The result of the operation.
|
||||
result_t check_backing_identifier(const char* backing);
|
||||
|
||||
/// @brief Returns the path of the backing pool.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the path.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_backing_pool_path(char** _path, const config_t* config);
|
||||
|
||||
/// @brief Returns the path of the specified backing.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the path.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param backing The identifier of the backing to get the path of.
|
||||
/// @return The result of the operation.
|
||||
result_t get_backing_path(char** _path, const config_t* config, const char* backing);
|
||||
|
||||
/// @brief Returns the path of the default disk file.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the path.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_backing_default_path(char** _path, const config_t* config);
|
||||
|
||||
/// @brief Returns the path of the temporary disk file.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the path.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_backing_temporary_path(char** _path, const config_t* config);
|
||||
|
||||
/// @brief Checks whether the specified backing exists. This call returns a failure if the backing does not exist.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param backing The identifier of the backing to check.
|
||||
/// @return Whether the backing exists.
|
||||
result_t check_backing_exists(const config_t* config, const char* backing);
|
||||
|
||||
/// @brief Returns the default backing identifier.
|
||||
/// @param _backing The pointer to where the backing should be stored. The caller is responsible for freeing the backing.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_default_backing(char** _backing, const config_t* config);
|
||||
|
||||
/// @brief Sets the default backing identifier.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param backing The identifier of the backing to set as default.
|
||||
/// @return The result of the operation.
|
||||
result_t set_default_backing(const config_t* config, const char* backing);
|
||||
|
||||
/// @brief Adds a new backing to the backing pool from the specified container.
|
||||
/// @param _backing The pointer to where the backing identifier should be stored. The caller is responsible for freeing the backing.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param container The identifier of the container to add the backing from.
|
||||
/// @return The result of the operation.
|
||||
result_t add_backing(char** _backing, const config_t* config, const char* container);
|
||||
|
||||
/// @brief Removes the specified backing from the backing pool.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param backing The identifier of the backing to remove.
|
||||
/// @return The result of the operation.
|
||||
result_t remove_backing(const config_t* config, const char* backing);
|
||||
|
||||
/// @brief Lists the backings in the backing pool, and returns the result in a null-terminated array of strings.
|
||||
/// @param _backings The pointer to where the backings array should be stored. The caller is responsible for freeing the backings array as well as the strings in the array.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t list_backings(char*** _backings, const config_t* config);
|
||||
|
||||
/// @brief Executes the syncronization script.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t sync_backing(const config_t* config);
|
28
src/config.c
28
src/config.c
@ -67,10 +67,10 @@ result_t init_config(config_t** _config) {
|
||||
free(config);
|
||||
}
|
||||
|
||||
// Get the backing pool path.
|
||||
json_object* backing_pool;
|
||||
if (!json_object_object_get_ex(root, "backing-pool", &backing_pool)) {
|
||||
result = failure("Failed to get the backing pool path from the configuration JSON.");
|
||||
// Get the image pool path.
|
||||
json_object* image_pool;
|
||||
if (!json_object_object_get_ex(root, "image-pool", &image_pool)) {
|
||||
result = failure("Failed to get the image pool path from the configuration JSON.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
json_object_put(root);
|
||||
@ -79,10 +79,10 @@ result_t init_config(config_t** _config) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the backing pool path string.
|
||||
const char* backing_pool_string = json_object_get_string(backing_pool);
|
||||
if (backing_pool_string == NULL) {
|
||||
result = failure("Failed to parse the backing pool path from the configuration JSON.");
|
||||
// Get the image pool path string.
|
||||
const char* image_pool_string = json_object_get_string(image_pool);
|
||||
if (image_pool_string == NULL) {
|
||||
result = failure("Failed to parse the image pool path from the configuration JSON.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
json_object_put(root);
|
||||
@ -102,10 +102,10 @@ result_t init_config(config_t** _config) {
|
||||
}
|
||||
verbose("Configuration -> Container pool: %s", config->container_pool);
|
||||
|
||||
// Set the backing pool path in the configuration.
|
||||
config->backing_pool = strdup(backing_pool_string);
|
||||
if (config->backing_pool == NULL) {
|
||||
result = failure("Failed to allocate memory for the backing pool path.");
|
||||
// Set the image pool path in the configuration.
|
||||
config->image_pool = strdup(image_pool_string);
|
||||
if (config->image_pool == NULL) {
|
||||
result = failure("Failed to allocate memory for the image pool path.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
json_object_put(root);
|
||||
@ -114,7 +114,7 @@ result_t init_config(config_t** _config) {
|
||||
|
||||
return result;
|
||||
}
|
||||
verbose("Configuration -> Backing pool: %s", config->backing_pool);
|
||||
verbose("Configuration -> image pool: %s", config->image_pool);
|
||||
|
||||
// Set the configuration if requested.
|
||||
if (_config != NULL)
|
||||
@ -130,7 +130,7 @@ result_t init_config(config_t** _config) {
|
||||
|
||||
void free_config(config_t* config) {
|
||||
free(config->container_pool);
|
||||
free(config->backing_pool);
|
||||
free(config->image_pool);
|
||||
|
||||
free(config);
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
typedef struct {
|
||||
/// @brief The path of the directory where the containers are stored.
|
||||
char* container_pool;
|
||||
/// @brief The path of the directory where the backings are stored.
|
||||
char* backing_pool;
|
||||
/// @brief The path of the directory where the images are stored.
|
||||
char* image_pool;
|
||||
} config_t;
|
||||
|
||||
/// @brief Initializes the program configuration.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "container.h"
|
||||
|
||||
#include "image.h"
|
||||
#include "disk.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -71,11 +71,12 @@ result_t check_container_exists(bool* _exists, const config_t* config, const cha
|
||||
struct stat st;
|
||||
if (stat(path, &st) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
verbose("The container '%s' does not exist.", identifier);
|
||||
free(path);
|
||||
|
||||
// The container does not exist.
|
||||
*_exists = false;
|
||||
|
||||
free(path);
|
||||
verbose("The container '%s' does not exist.", identifier);
|
||||
|
||||
return success();
|
||||
}
|
||||
@ -223,6 +224,71 @@ result_t add_root_container(const config_t* config, const char* identifier, size
|
||||
return success();
|
||||
}
|
||||
|
||||
result_t add_backed_container(const config_t* config, const char* identifier, const char* image) {
|
||||
result_t result;
|
||||
|
||||
// Check that the container does not already exist.
|
||||
bool exists;
|
||||
result = check_container_exists(&exists, config, identifier);
|
||||
if (result != success()) {
|
||||
result = failure("Failed to check whether the container exists.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
result = failure("The specified container already exists.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the container path.
|
||||
char* path;
|
||||
result = get_container_path(&path, config, identifier);
|
||||
if (result != success()) {
|
||||
result = failure("Failed to get the container path.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the image path.
|
||||
char* image_path;
|
||||
result = get_image_path(&image_path, config, image);
|
||||
if (result != success()) {
|
||||
result = failure("Failed to get the image path.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
free(path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create the container disk.
|
||||
result = create_backed_disk(path, image_path);
|
||||
if (result != success()) {
|
||||
result = failure("Failed to create the container disk.");
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
free(image_path);
|
||||
free(path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Free the image path.
|
||||
free(image_path);
|
||||
|
||||
// Free the container path.
|
||||
free(path);
|
||||
|
||||
verbose("Successfully added backed container '%s' to the container pool, backed by the image '%s'.", identifier, image);
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
result_t remove_container(const config_t* config, const char* identifier) {
|
||||
result_t result;
|
||||
|
||||
|
@ -38,12 +38,12 @@ result_t get_container_path(char** _path, const config_t* config, const char* id
|
||||
/// @return The result of the operation.
|
||||
result_t add_root_container(const config_t* config, const char* identifier, size_t size);
|
||||
|
||||
/// @brief Adds a new backed container to the pool, with the specified identifier and backing.
|
||||
/// @brief Adds a new backed container to the pool, with the specified identifier and image.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param identifier The identifier of the container to add.
|
||||
/// @param backing The identifier of the backing to use.
|
||||
/// @param image The identifier of the image to use.
|
||||
/// @return The result of the operation.
|
||||
result_t add_backed_container(const config_t* config, const char* identifier, const char* backing);
|
||||
result_t add_backed_container(const config_t* config, const char* identifier, const char* image);
|
||||
|
||||
/// @brief Removes the specified container from the pool.
|
||||
/// @param config The program configuration to use.
|
||||
|
@ -246,7 +246,7 @@ result_t create_backed_disk(const char* disk, const char* backing) {
|
||||
// char* stdout_buffer;
|
||||
char* stderr_buffer;
|
||||
|
||||
result = execute_file(&exit_code, NULL, NULL, &stderr_buffer, NULL, NULL, "/usr/bin/qemu-img", "create", "-f", "qcow2", "-o", "backing_file", backing, disk, NULL);
|
||||
result = execute_file(&exit_code, NULL, NULL, &stderr_buffer, NULL, NULL, "/usr/bin/qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", backing, disk, NULL);
|
||||
|
||||
if (result != success()) {
|
||||
result = failure("Failed to execute qemu-img create on the backed disk '%s'.", disk);
|
||||
|
554
src/image.c
Normal file
554
src/image.c
Normal file
File diff suppressed because it is too large
Load Diff
73
src/image.h
Normal file
73
src/image.h
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
|
||||
/// @brief Checks whether the specified image identifier is valid. This call will return an error with a message describing the problem if the identifier is invalid.
|
||||
/// @param identifier The identifier to check.
|
||||
/// @return The result of the operation.
|
||||
result_t check_image_identifier(const char* identifier);
|
||||
|
||||
/// @brief Checks whether the specified image exists.
|
||||
/// @param _exists The pointer to where the result should be stored.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param identifier The identifier of the image to check.
|
||||
/// @return The result of the operation.
|
||||
result_t check_image_exists(bool* _exists, const config_t* config, const char* identifier);
|
||||
|
||||
/// @brief Returns the path of the image pool directory.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the memory.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_image_pool_path(char** _path, const config_t* config);
|
||||
|
||||
/// @brief Returns the path of the specified image.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the memory.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param identifier The identifier of the image.
|
||||
/// @return The result of the operation.
|
||||
result_t get_image_path(char** _path, const config_t* config, const char* identifier);
|
||||
|
||||
/// @brief Returns the path of the file containing the default image identifier.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the memory.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_default_image_path(char** _path, const config_t* config);
|
||||
|
||||
/// @brief Returns the path of the temporary file used to store the disk before it is moved to the image pool.
|
||||
/// @param _path The pointer to where the path should be stored. The caller is responsible for freeing the memory.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_temporary_image_path(char** _path, const config_t* config);
|
||||
|
||||
/// @brief Returns the identifier of the default image.
|
||||
/// @param _identifier The pointer to where the identifier should be stored. The caller is responsible for freeing the memory.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t get_default_image(char** _identifier, const config_t* config);
|
||||
|
||||
/// @brief Sets the identifier of the default image.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param identifier The identifier of the image to set as default.
|
||||
/// @return The result of the operation.
|
||||
result_t set_default_image(const config_t* config, const char* identifier);
|
||||
|
||||
/// @brief Adds a new image to the pool, using the specified container as the source.
|
||||
/// @param _identifier The pointer to where the identifier should be stored. The caller is responsible for freeing the memory.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param container The identifier of the container to use as the source.
|
||||
/// @return The result of the operation.
|
||||
result_t add_image(char** _identifier, const config_t* config, const char* container);
|
||||
|
||||
/// @brief Removes the specified image from the pool.
|
||||
/// @param config The program configuration to use.
|
||||
/// @param identifier The identifier of the image to remove.
|
||||
/// @return The result of the operation.
|
||||
result_t remove_image(const config_t* config, const char* identifier);
|
||||
|
||||
/// @brief Lists the images in the pool.
|
||||
/// @param _identifiers The pointer to where the list of identifiers should be stored. The caller is responsible for freeing the strings and the array.
|
||||
/// @param _count The pointer to where the count of identifiers should be stored.
|
||||
/// @param config The program configuration to use.
|
||||
/// @return The result of the operation.
|
||||
result_t list_images(char*** _identifiers, size_t* _count, const config_t* config);
|
@ -2,6 +2,7 @@
|
||||
#include "disk.h"
|
||||
#include "config.h"
|
||||
#include "container.h"
|
||||
#include "image.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
@ -12,5 +13,16 @@ int main(int argc, char* argv[]) {
|
||||
if (result != success())
|
||||
return -1;
|
||||
|
||||
add_root_container(config, "test", 1024ULL);
|
||||
|
||||
char* image;
|
||||
add_image(&image, config, "test");
|
||||
|
||||
printf("Image: %s\n", image);
|
||||
|
||||
add_backed_container(config, "test2", image);
|
||||
|
||||
add_image(&image, config, "test2");
|
||||
|
||||
free_config(config);
|
||||
}
|
10
src/utils.c
10
src/utils.c
@ -291,7 +291,7 @@ result_t read_fd(char** _buffer, size_t* _size, int fd) {
|
||||
|
||||
// If an error occurred, return it.
|
||||
if (bytes_read == -1) {
|
||||
result = failure("Failed to read the file descriptor (%s).", strerror(errno));
|
||||
result = failure("Failed to read the file descriptor %d (%s).", fd, strerror(errno));
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
free(buffer);
|
||||
@ -320,7 +320,7 @@ result_t write_fd(int fd, const char* buffer, size_t size) {
|
||||
// Write the buffer to the file descriptor.
|
||||
ssize_t bytes_written = write(fd, buffer, size);
|
||||
if (bytes_written == -1) {
|
||||
result = failure("Failed to write to the file descriptor (%s).", strerror(errno));
|
||||
result = failure("Failed to write to the file descriptor %d (%s).", fd, strerror(errno));
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
return result;
|
||||
@ -405,7 +405,7 @@ result_t copy_fd(int source_fd, int destination_fd) {
|
||||
while (bytes_written < bytes_read) {
|
||||
ssize_t written = write(destination_fd, buffer + bytes_written, bytes_read - bytes_written);
|
||||
if (written == -1) {
|
||||
result = failure("Failed to write to the file descriptor (%s).", strerror(errno));
|
||||
result = failure("Failed to write to the file descriptor %d (%s).", destination_fd, strerror(errno));
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
return result;
|
||||
@ -417,7 +417,7 @@ result_t copy_fd(int source_fd, int destination_fd) {
|
||||
|
||||
// If an error occurred, return it.
|
||||
if (bytes_read == -1) {
|
||||
result = failure("Failed to read the file descriptor (%s).", strerror(errno));
|
||||
result = failure("Failed to read the file descriptor %d (%s).", source_fd, strerror(errno));
|
||||
verbose("Exception -> %s", last_error());
|
||||
|
||||
return result;
|
||||
@ -765,7 +765,7 @@ result_t md5_fd(char** _hash, int fd) {
|
||||
// Set the hash.
|
||||
*_hash = md5;
|
||||
|
||||
verbose("Calculated MD5 hash '%s' from file descriptor %d (%zd bytes).", md5, fd, total_bytes_read);
|
||||
verbose("Successfully calculated MD5 hash '%s' from file descriptor %d (%zd bytes).", md5, fd, total_bytes_read);
|
||||
|
||||
return success();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user