diff --git a/src/backing.c b/src/backing.c index 22272bf..182208d 100755 --- a/src/backing.c +++ b/src/backing.c @@ -9,6 +9,7 @@ #include #include #include +#include #include result_t check_backing_identifier(const char* backing) { @@ -69,10 +70,16 @@ result_t check_backing_exists(const char* backing) { } result_t get_backing_pool_path(char** _path) { + // Initialize the output parameters + *_path = NULL; + return format(_path, "/var/lib/sandbox/backings"); } result_t get_backing_path(char** _path, const char* backing) { + // Initialize the output parameters + *_path = NULL; + // Check the backing identifier result_t result = check_backing_identifier(backing); if (result != success()) @@ -92,6 +99,9 @@ result_t get_backing_path(char** _path, const char* backing) { } result_t get_backing_default_path(char** _path) { + // Initialize the output parameters + *_path = NULL; + // Get the backing pool path char* pool_path; result_t result = get_backing_pool_path(&pool_path); @@ -105,6 +115,148 @@ result_t get_backing_default_path(char** _path) { return result; } +result_t get_backing_temp_path(char** _path) { + // Initialize the output parameters + *_path = NULL; + + // Get the backing pool path + char* pool_path; + result_t result = get_backing_pool_path(&pool_path); + if (result != success()) + return result; + + // Format the backing path + result = format(_path, "%s/temp", pool_path); + + free(pool_path); + return result; +} + +result_t add_backing(char** _backing, const char* container) { + // Initialize the output parameters + *_backing = NULL; + + // Get the container path + char* path; + result_t result = get_container_path(&path, container); + if (result != success()) + return result; + + // Import the container as a backing + result = import_backing(_backing, path); + + free(path); + return result; +} + +result_t import_backing(char** _backing, const char* path) { + // Initialize the output parameters + *_backing = NULL; + + // Get the temporary backing path + char* temp_path; + result_t result = get_backing_temp_path(&temp_path); + if (result != success()) + return result; + + // Copy the disk to the temporary backing path + result = copy_file(path, temp_path); + if (result != success()) { + free(temp_path); + return result; + } + + // Get the disk info to know if the disk is backed + disk_info_t info; + result = get_disk_info(&info, temp_path); + if (result != success()) { + remove(temp_path); + free(temp_path); + return result; + } + + if (info.backing_path != NULL) { + // Get the backing identifier of the parent + char* backing = strdup(basename(info.backing_path)); + if (backing == NULL) { + free_disk_info(&info); + remove(temp_path); + free(temp_path); + return failure("Failed to get the backing identifier of the parent."); + } + + // Check that the backing exists + result = check_backing_exists(backing); + if (result != success()) { + free_disk_info(&info); + remove(temp_path); + free(temp_path); + free(backing); + return result; + } + + // Reback the disk to the parent + result = reback_disk(temp_path, backing); + if (result != success()) { + free_disk_info(&info); + remove(temp_path); + free(temp_path); + free(backing); + return result; + } + + free(backing); + } + + free_disk_info(&info); + + // Get the md5 hash of the disk as the backing identifier + char* backing; + result = md5sum(&backing, temp_path); + if (result != success()) { + remove(temp_path); + free(temp_path); + return result; + } + + // Check if the backing already exists + result = check_backing_exists(backing); + if (result == success()) { + result = failure("Backing '%s' already exists.", backing); + free(backing); + remove(temp_path); + free(temp_path); + return result; + } + + // Get the path of the final backing + char* backing_path; + result = get_backing_path(&backing_path, backing); + if (result != success()) { + free(backing); + remove(temp_path); + free(temp_path); + return result; + } + + // Move the temporary backing to the final backing path + errno = 0; + if (rename(temp_path, backing_path) != 0) { + result = failure("Failed to move the temporary backing to the final backing path (%s).", strerror(errno)); + free(backing); + free(backing_path); + remove(temp_path); + free(temp_path); + return result; + } + + free(backing_path); + free(temp_path); + + *_backing = backing; + return result; +} + result_t remove_backing(const char* backing) { // Check that the backing exists result_t result = check_backing_exists(backing); @@ -137,6 +289,9 @@ bool backing_filter(const char* file) { } result_t list_backings(char*** _backings) { + // Initialize the output parameters + *_backings = NULL; + // Get the backing pool path char* pool_path; result_t result = get_backing_pool_path(&pool_path); @@ -151,6 +306,9 @@ result_t list_backings(char*** _backings) { } result_t get_default_backing(char** _backing) { + // Initialize the output parameters + *_backing = NULL; + // Get the backing default path char* path; result_t result = get_backing_default_path(&path); diff --git a/src/backing.h b/src/backing.h index 61dfb2d..9e58420 100755 --- a/src/backing.h +++ b/src/backing.h @@ -8,8 +8,10 @@ result_t check_backing_exists(const char* backing); result_t get_backing_pool_path(char** _path); result_t get_backing_path(char** _path, const char* backing); result_t get_backing_default_path(char** _path); +result_t get_backing_temp_path(char** _path); -result_t add_backing(const char* backing, const char* container); +result_t add_backing(char** _backing, const char* container); +result_t import_backing(char** _backing, const char* path); result_t remove_backing(const char* backing); bool backing_filter(const char* file); diff --git a/src/container.c b/src/container.c index 7f3bc1c..93ff943 100755 --- a/src/container.c +++ b/src/container.c @@ -71,10 +71,16 @@ result_t check_container_exists(const char* container) { } result_t get_container_pool_path(char** _path) { + // Initialize the output parameters + *_path = NULL; + return format(_path, "/var/lib/sandbox/containers"); } result_t get_container_path(char** _path, const char* container) { + // Initialize the output parameters + *_path = NULL; + // Check the container identifier result_t result = check_container_identifier(container); if (result != success()) @@ -208,6 +214,9 @@ bool container_filter(const char* file) { } result_t list_containers(char*** _containers) { + // Initialize the output parameters + *_containers = NULL; + // Get the container pool path char* pool_path; result_t result = get_container_pool_path(&pool_path); diff --git a/src/sandbox.c b/src/sandbox.c index e2c8e12..b3a7621 100755 --- a/src/sandbox.c +++ b/src/sandbox.c @@ -1,6 +1,8 @@ #include "sandbox.h" #include "utils.h" +#include "backing.h" +#include "container.h" #include #include @@ -65,6 +67,13 @@ int main(int argc, char** argv) { } // TODO: Parse commands from the command line + while (1) { + char* backing2; + result_t result = add_backing(&backing2, "test2"); + if (result != success()) { + fprintf(stderr, "Failed to add backing: %s\n", error()); + } + } } int command_help(int argc, char* argv[]) { diff --git a/src/utils.c b/src/utils.c index 43fd00b..2b66234 100755 --- a/src/utils.c +++ b/src/utils.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include char ERROR_BUFFER[ERROR_BUFFER_SIZE]; @@ -412,6 +412,62 @@ result_t write_file(const char* path, const char* str) { return result; } +result_t copy_file(const char* src, const char* dst) { + // Open the source file + errno = 0; + int src_fd = open(src, O_RDONLY); + if (src_fd < 0) + return failure("Failed to open the source file '%s' (%s).", src, strerror(errno)); + + // Open the destination file + errno = 0; + int dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (dst_fd < 0) { + close(src_fd); + return failure("Failed to open the destination file '%s' (%s).", dst, strerror(errno)); + } + + // Copy the source file to the destination file + char buffer[4096]; + ssize_t count; + + while (1) { + // Read from the source file + errno = 0; + count = read(src_fd, buffer, sizeof(buffer)); + if (count < 0) { + close(src_fd); + close(dst_fd); + return failure("Failed to read from the source file '%s' (%s).", src, strerror(errno)); + } + + // If the end of the file is reached, stop copying + if (count == 0) + break; + + // Write to the destination file + while (count > 0) { + errno = 0; + ssize_t written = write(dst_fd, buffer, count); + if (written < 0) { + close(src_fd); + close(dst_fd); + return failure("Failed to write to the destination file '%s' (%s).", dst, strerror(errno)); + } + + count -= written; + } + } + + // Close the source file + close(src_fd); + + // Close the destination file + close(dst_fd); + + return success(); +} + result_t list_files(char*** _files, const char* path, bool (*filter)(const char*)) { // Initialize the output parameters *_files = NULL; @@ -493,3 +549,85 @@ result_t list_files(char*** _files, const char* path, bool (*filter)(const char* *_files = files; return success(); } + +result_t md5sum(char** _md5, const char* path) { + // Initialize the output parameters + *_md5 = NULL; + + // Open the file + errno = 0; + int fd = open(path, O_RDONLY); + if (fd < 0) + return failure("Failed to open the file '%s' (%s).", path, strerror(errno)); + + // Initialize the MD5 context + EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); + if (mdctx == NULL) { + close(fd); + return failure("Failed to initialize the MD5 context."); + } + + if (EVP_DigestInit_ex(mdctx, EVP_md5(), NULL) != 1) { + EVP_MD_CTX_free(mdctx); + close(fd); + return failure("Failed to initialize the MD5 context."); + } + + // Read the file and update the MD5 context + char buffer[4096]; + ssize_t count; + + while (1) { + // Read from the file + errno = 0; + count = read(fd, buffer, sizeof(buffer)); + if (count < 0) { + EVP_MD_CTX_free(mdctx); + close(fd); + return failure("Failed to read from the file '%s' (%s).", path, strerror(errno)); + } + + // If the end of the file is reached, stop updating the MD5 context + if (count == 0) + break; + + // Update the MD5 context + if (EVP_DigestUpdate(mdctx, buffer, count) != 1) { + EVP_MD_CTX_free(mdctx); + close(fd); + return failure("Failed to update the MD5 context."); + } + } + + // Finalize the MD5 context + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; + + if (EVP_DigestFinal_ex(mdctx, md_value, &md_len) != 1) { + EVP_MD_CTX_free(mdctx); + close(fd); + return failure("Failed to finalize the MD5 context."); + } + + EVP_MD_CTX_free(mdctx); + + // Close the file + close(fd); + + // Format the MD5 checksum + errno = 0; + char* md5 = malloc(2 * md_len + 1); // +1 for the null terminator + if (md5 == NULL) + return failure("Failed to allocate memory for the MD5 checksum (%s).", strerror(errno)); + + for (unsigned int i = 0; i < md_len; i++) + if (snprintf(md5 + 2 * i, 3, "%02x", md_value[i]) != 2) { + free(md5); + return failure("Failed to format the MD5 checksum."); + } + md5[2 * md_len] = '\0'; + + // Return the MD5 checksum + *_md5 = md5; + return success(); +} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h index a4c90b6..36575c8 100755 --- a/src/utils.h +++ b/src/utils.h @@ -26,5 +26,8 @@ result_t read_fd(char** _str, int fd); result_t write_fd(int fd, const char* str); result_t read_file(char** _str, const char* path); result_t write_file(const char* path, const char* str); +result_t copy_file(const char* src, const char* dst); result_t list_files(char*** _files, const char* path, bool (*filter)(const char*)); + +result_t md5sum(char** _md5, const char* path);