#include "disk.h" #include #include #include #include #include #include #include Status CreateRootDisk(const char* path, uint64_t disk_size) { // Convert the size to a string char* size_str; Status status = Format(&size_str, "%lu", disk_size); if (status != SUCCESS) return status; // Create the disk int exit_code; // char* stdout; char* stderrb; status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "create", "-f", "qcow2", path, size_str, NULL); free(size_str); // Check if the disk was created successfully if (status != SUCCESS) return status; if (exit_code != 0) { if (stderrb != NULL) { // Remove newlines from the stderr buffer for (int i = 0; stderrb[i] != '\0'; i++) if (stderrb[i] == '\n') stderrb[i] = ' '; Log(LOG_LEVEL_ERROR, "Failed to create disk at '%s' (%s).", path, stderrb); free(stderrb); } else Log(LOG_LEVEL_ERROR, "Failed to create disk"); return FAILURE; } return SUCCESS; } Status CreateBackedDisk(const char* path, const char* backing_file) { // Create the disk int exit_code; // char* stdout; char* stderrb; Status status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", backing_file, path, NULL); // Check if the disk was created successfully if (status != SUCCESS) return status; if (exit_code != 0) { if (stderrb != NULL) { // Remove newlines from the stderr buffer for (int i = 0; stderrb[i] != '\0'; i++) if (stderrb[i] == '\n') stderrb[i] = ' '; Log(LOG_LEVEL_ERROR, "Failed to create disk at '%s' (%s).", path, stderrb); free(stderrb); } else Log(LOG_LEVEL_ERROR, "Failed to create disk"); return FAILURE; } return SUCCESS; } Status TrimDisk(const char* path) { char* tmp_path = NULL; Status status = Format(&tmp_path, "%s.tmp", path); if (status != SUCCESS) return status; DiskInfo info; status = GetDiskInfo(path, &info); if (status != SUCCESS) { free(tmp_path); return status; } // Create the temporary disk int exit_code; // char* stdout; char* stderrb; if (info.backing_file != NULL) { char* backing_file_opt = NULL; status = Format(&backing_file_opt, "backing_file=%s", info.backing_file); if (status != SUCCESS) { free(tmp_path); FreeDiskInfo(&info); return status; } status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-O", "qcow2", "-o", backing_file_opt, tmp_path, NULL); free(backing_file_opt); } else status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "create", "-f", "qcow2", "-O", "qcow2", tmp_path, NULL); FreeDiskInfo(&info); // Check if the disk was created successfully if (status != SUCCESS) { free(tmp_path); return status; } if (exit_code != 0) { if (stderrb != NULL) { // Remove newlines from the stderr buffer for (int i = 0; stderrb[i] != '\0'; i++) if (stderrb[i] == '\n') stderrb[i] = ' '; Log(LOG_LEVEL_ERROR, "Failed to create temporary disk at '%s' (%s).", tmp_path, stderrb); free(stderrb); } else Log(LOG_LEVEL_ERROR, "Failed to create temporary disk"); free(tmp_path); return FAILURE; } // Try to move the temporary disk to the original path if (rename(tmp_path, path) != 0) { Log(LOG_LEVEL_ERROR, "Failed to move the temporary disk to the original path '%s' (%s).", path, strerror(errno)); unlink(tmp_path); free(tmp_path); return FAILURE; } free(tmp_path); return SUCCESS; } Status RebaseDisk(const char* path, const char* backing_file) { // Create the disk int exit_code; // char* stdout; char* stderrb; Status status = RunExecutable(&exit_code, NULL, &stderrb, "/usr/bin/qemu-img", "rebase", "-u", "-b", backing_file, path, NULL); // Check if the disk was created successfully if (status != SUCCESS) return status; if (exit_code != 0) { if (stderrb != NULL) { // Remove newlines from the stderr buffer for (int i = 0; stderrb[i] != '\0'; i++) if (stderrb[i] == '\n') stderrb[i] = ' '; Log(LOG_LEVEL_ERROR, "Failed to rebase disk at '%s' (%s).", path, stderrb); free(stderrb); } else Log(LOG_LEVEL_ERROR, "Failed to rebase disk"); return FAILURE; } return SUCCESS; } Status GetDiskInfo(const char* path, DiskInfo* _info) { *_info = (DiskInfo){0}; // Get the disk info int exit_code; char* stdoutb; char* stderrb; Status status = RunExecutable(&exit_code, &stdoutb, &stderrb, "/usr/bin/qemu-img", "info", "--output", "json", path, NULL); if (status != SUCCESS) return status; if (exit_code != 0) { if (stderrb != NULL) { // Remove newlines from the stderr buffer for (int i = 0; stderrb[i] != '\0'; i++) if (stderrb[i] == '\n') stderrb[i] = ' '; Log(LOG_LEVEL_ERROR, "Failed to get disk info at '%s' (%s).", path, stderrb); free(stderrb); } else Log(LOG_LEVEL_ERROR, "Failed to get disk info"); free(stdoutb); return FAILURE; } free(stderrb); // Parse the JSON output json_object* root = json_tokener_parse(stdoutb); free(stdoutb); if (root == NULL) { Log(LOG_LEVEL_ERROR, "Failed to parse the JSON output"); return FAILURE; } json_object* virtual_size = NULL; json_object* actual_size = NULL; json_object* backing_file = NULL; json_object_object_get_ex(root, "virtual-size", &virtual_size); json_object_object_get_ex(root, "actual-size", &actual_size); json_object_object_get_ex(root, "backing-filename", &backing_file); if (virtual_size != NULL) _info->size = json_object_get_int64(virtual_size); if (actual_size != NULL) _info->allocated = json_object_get_int64(actual_size); if (backing_file != NULL) _info->backing_file = strdup(json_object_get_string(backing_file)); json_object_put(root); return SUCCESS; } void FreeDiskInfo(DiskInfo* info) { free(info->backing_file); }