#include "entry.h" #include "utils.h" #include "disk.h" #include #include #include #include #include #include bool is_entry_id_valid(const char* entry_id) { if (entry_id == NULL) return false; size_t length = strlen(entry_id); // Check that the length is valid if (length == 0 || length > MAX_ENTRY_LENGTH) return false; // Check that the entry id does not contain any slashes for (size_t i = 0; i < length; i++) if (entry_id[i] == '/') return false; // Check that the entry id is not a reserved name if (strcmp(entry_id, ".") == 0 || strcmp(entry_id, "..") == 0) return false; return true; } Result get_entry_path(const char* entry_id, char** out_path) { *out_path = NULL; // Check that the entry id is valid if (!is_entry_id_valid(entry_id)) { log_message(LOG_LEVEL_ERROR, "Invalid entry id '%s'.", entry_id); return FAILURE; } return format(out_path, "%s/%s", ENTRY_POOL_DIR, entry_id); } Result get_entry_disk_path(const char* entry_id, char** out_path) { *out_path = NULL; // Get the path of the entry char* entry_path; Result result = get_entry_path(entry_id, &entry_path); if (result != SUCCESS) return result; // Get the path of the disk result = format(out_path, "%s/disk", entry_path); // Free the entry path free(entry_path); return result; } Result get_entry_type_path(const char* entry_id, char** out_path) { *out_path = NULL; // Get the path of the entry char* entry_path; Result result = get_entry_path(entry_id, &entry_path); if (result != SUCCESS) return result; // Get the path of the type file result = format(out_path, "%s/type", entry_path); // Free the entry path free(entry_path); return result; } Result entry_exists(const char* entry_id, bool* out_exists) { *out_exists = false; // Get the path of the entry char* path; Result result = get_entry_path(entry_id, &path); if (result != SUCCESS) return result; // Check if the entry exists and is a directory struct stat st; bool exists = stat(path, &st) == 0 && S_ISDIR(st.st_mode); // Free the path free(path); // Output the result *out_exists = exists; return SUCCESS; } Result add_entry(const char* entry_id, EntryType type) { // Check that it does not exist bool exists; Result result = entry_exists(entry_id, &exists); if (result != SUCCESS) return result; if (exists) { log_message(LOG_LEVEL_ERROR, "The entry '%s' already exists.", entry_id); return FAILURE; } // Get the path of the entry char* entry_path; result = get_entry_path(entry_id, &entry_path); if (result != SUCCESS) return result; // Create the directory if (mkdir(entry_path, 0755) == -1) { log_message(LOG_LEVEL_ERROR, "Failed to create the directory '%s' (%s).", entry_path, strerror(errno)); free(entry_path); return FAILURE; } // Free the entry path free(entry_path); // Get the path of the type file char* type_path; result = get_entry_type_path(entry_id, &type_path); if (result != SUCCESS) { remove_entry(entry_id); return result; } // Write the type file const char* type_string; switch (type) { case ENTRY_TYPE_ROOT: type_string = ENTRY_TYPE_ROOT_STRING; break; case ENTRY_TYPE_BACKED: type_string = ENTRY_TYPE_BACKED_STRING; break; case ENTRY_TYPE_AUTOMATIC: type_string = ENTRY_TYPE_AUTOMATIC_STRING; break; default: log_message(LOG_LEVEL_ERROR, "Invalid entry type."); remove_entry(entry_id); return FAILURE; } result = write_file(type_path, type_string); // Free the type path free(type_path); if (result != SUCCESS) { remove_entry(entry_id); return result; } return SUCCESS; } Result add_root_entry(const char* entry_id, uint64_t size) { // Add the entry Result result = add_entry(entry_id, ENTRY_TYPE_ROOT); if (result != SUCCESS) return result; // Get the path of the disk char* disk_path; result = get_entry_disk_path(entry_id, &disk_path); if (result != SUCCESS) { remove_entry(entry_id); return result; } // Create the disk result = create_root_disk(disk_path, size, 0644); // Free the disk path free(disk_path); if (result != SUCCESS) { remove_entry(entry_id); return result; } return SUCCESS; } Result remove_entry(const char* entry_id) { // Check that it exists bool exists; Result result = entry_exists(entry_id, &exists); if (result != SUCCESS) return result; if (!exists) { log_message(LOG_LEVEL_ERROR, "The entry '%s' does not exist.", entry_id); return FAILURE; } // Get the path of the entry char* entry_path; result = get_entry_path(entry_id, &entry_path); if (result != SUCCESS) return result; // Remove the directory if (rmdir(entry_path) == -1) { log_message(LOG_LEVEL_ERROR, "Failed to remove the directory '%s' (%s).", entry_path, strerror(errno)); free(entry_path); return FAILURE; } // Free the entry path free(entry_path); return SUCCESS; } Result reset_entry(const char* entry_id) { // Check that it exists bool exists; Result result = entry_exists(entry_id, &exists); if (result != SUCCESS) return result; if (!exists) { log_message(LOG_LEVEL_ERROR, "The entry '%s' does not exist.", entry_id); return FAILURE; } // Get the path of the disk char* disk_path; result = get_entry_disk_path(entry_id, &disk_path); if (result != SUCCESS) return result; // Reset the disk result = reset_disk(disk_path); // Free the disk path free(disk_path); return result; } Result get_entry_info(const char* entry_id, EntryInfo* out_info) { out_info->backing_id = NULL; out_info->type = ENTRY_TYPE_UNKNOWN; // Get the path of the type file char* type_path; Result result = get_entry_type_path(entry_id, &type_path); if (result != SUCCESS) return result; // Read the type file char* type; result = read_file(type_path, &type); if (result != SUCCESS) { free(type_path); return result; } // Free the type path free(type_path); // Check the type if (strcmp(type, ENTRY_TYPE_ROOT_STRING) == 0) out_info->type = ENTRY_TYPE_ROOT; else if (strcmp(type, ENTRY_TYPE_BACKED_STRING) == 0) out_info->type = ENTRY_TYPE_BACKED; else if (strcmp(type, ENTRY_TYPE_AUTOMATIC_STRING) == 0) out_info->type = ENTRY_TYPE_AUTOMATIC; // Free the type free(type); // Get the path of the entry disk char* disk_path; result = get_entry_disk_path(entry_id, &disk_path); if (result != SUCCESS) return result; // Get the information about the disk result = get_disk_info(disk_path, &out_info->disk_info); // Free the disk path free(disk_path); if (result != SUCCESS) return result; // Check if the disk is backed if (out_info->disk_info.backing_file != NULL) { out_info->backing_id = strdup(basename(out_info->disk_info.backing_file)); if (out_info->backing_id == NULL) { free_disk_info(&out_info->disk_info); return OUT_OF_MEMORY; } } return SUCCESS; } void free_entry_info(EntryInfo* info) { free(info->backing_id); free_disk_info(&info->disk_info); }