Implemented creation of root disks
This commit is contained in:
parent
188e57dc31
commit
694092e12e
231
src/entry.c
231
src/entry.c
@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
bool is_entry_id_valid(const char* entry_id) {
|
||||
@ -43,6 +44,42 @@ Result get_entry_path(const char* entry_id, char** out_path) {
|
||||
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;
|
||||
|
||||
@ -63,4 +100,196 @@ Result entry_exists(const char* entry_id, bool* out_exists) {
|
||||
*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 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);
|
||||
}
|
||||
|
23
src/entry.h
23
src/entry.h
@ -10,11 +10,16 @@
|
||||
#define MAX_ENTRY_LENGTH 256
|
||||
|
||||
typedef enum {
|
||||
ENTRY_TYPE_UNKNOWN,
|
||||
ENTRY_TYPE_ROOT,
|
||||
ENTRY_TYPE_BACKED,
|
||||
ENTRY_TYPE_AUTOMATIC
|
||||
} EntryType;
|
||||
|
||||
#define ENTRY_TYPE_ROOT_STRING "root"
|
||||
#define ENTRY_TYPE_BACKED_STRING "backed"
|
||||
#define ENTRY_TYPE_AUTOMATIC_STRING "automatic"
|
||||
|
||||
typedef struct {
|
||||
EntryType type;
|
||||
char* backing_id;
|
||||
@ -33,12 +38,30 @@ bool is_entry_id_valid(const char* entry_id);
|
||||
/// @return The result of the operation.
|
||||
Result get_entry_path(const char* entry_id, char** out_path);
|
||||
|
||||
/// @brief Gets the path of the disk of the given entry.
|
||||
/// @param entry_id The entry id.
|
||||
/// @param out_path The pointer to the output path string. The caller is responsible for freeing the memory.
|
||||
/// @return The result of the operation.
|
||||
Result get_entry_disk_path(const char* entry_id, char** out_path);
|
||||
|
||||
/// @brief Gets the path of the type file of the given entry.
|
||||
/// @param entry_id The entry id.
|
||||
/// @param out_path The pointer to the output path string. The caller is responsible for freeing the memory.
|
||||
/// @return The result of the operation.
|
||||
Result get_entry_type_path(const char* entry_id, char** out_path);
|
||||
|
||||
/// @brief Checks whether the given entry exists in the pool.
|
||||
/// @param entry_id The entry id.
|
||||
/// @param out_exists The pointer to the output boolean.
|
||||
/// @return The result of the operation.
|
||||
Result entry_exists(const char* entry_id, bool* out_exists);
|
||||
|
||||
/// @brief Adds an entry directory to the pool.
|
||||
/// @param entry_id The entry id.
|
||||
/// @param type The type of the entry.
|
||||
/// @return The result of the operation.
|
||||
Result add_entry(const char* entry_id, EntryType type);
|
||||
|
||||
/// @brief Adds a root entry to the pool.
|
||||
/// @param entry_id The entry id.
|
||||
/// @param size The size of the entry.
|
||||
|
@ -19,7 +19,7 @@ const Command COMMANDS[] = {
|
||||
"Adds an entry to the entry pool with the given id. The entry can either be a root entry or a backed entry. If the entry is a root entry, the size of the entry must be specified. If the entry is a backed entry, the backing id must be specified. By default, the entry will be an automatic entry, which will be backed by the latest backing disk available and will automatically reset to its initial state when a new backing disk is added."},
|
||||
{command_remove_entry, "remove-entry", "<entry id>", "Removes an entry from the entry pool.",
|
||||
"Removes the entry with the given id from the entry pool."},
|
||||
{command_list_entries, "list-entries", "", "Lists the entries in the entry pool.",
|
||||
{command_list_entries, "entries", "", "Lists the entries in the entry pool.",
|
||||
"Lists the entries in the entry pool, as well as their types and backing disks."},
|
||||
{command_clear_entries, "clear-entries", "", "Removes all the entries from the entry pool.",
|
||||
"Removes all the entries from the entry pool."},
|
||||
@ -119,24 +119,12 @@ int command_version(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
int command_add_entry(int argc, char* argv[]) {
|
||||
if (argc < 1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// TODO: Parse options
|
||||
|
||||
// TODO: Call add_root_entry or add_backed_entry depending on the options
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int command_remove_entry(int argc, char* argv[]) {
|
||||
if (argc < 1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// TODO: Call remove_entry
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
@ -157,33 +145,18 @@ int command_clear_entries(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
int command_reset_entry(int argc, char* argv[]) {
|
||||
if (argc < 1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// TODO: Call reset_entry
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int command_update_entry(int argc, char* argv[]) {
|
||||
if (argc < 1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// TODO: Call update_entry
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int command_add_backing(int argc, char* argv[]) {
|
||||
if (argc < 1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Missing entry id.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// TODO: Call add_backing
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
55
src/utils.c
55
src/utils.c
@ -7,6 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
@ -287,3 +288,57 @@ Result read_fd(int fd, char** out_string) {
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result read_file(const char* path, char** out_string) {
|
||||
*out_string = NULL;
|
||||
|
||||
// Open the file
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to open the file '%s' (%s).", path, strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Read the file
|
||||
Result result = read_fd(fd, out_string);
|
||||
|
||||
// Close the file
|
||||
close(fd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result write_fd(int fd, const char* string) {
|
||||
// Write the string to the file descriptor
|
||||
size_t length = strlen(string);
|
||||
ssize_t bytes_written = 0;
|
||||
|
||||
while (bytes_written < length) {
|
||||
ssize_t result = write(fd, string + bytes_written, length - bytes_written);
|
||||
if (result == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to write to the file descriptor (%s).", strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
bytes_written += result;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result write_file(const char* path, const char* string) {
|
||||
// Open the file
|
||||
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to open the file '%s' (%s).", path, strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Write the string to the file
|
||||
Result result = write_fd(fd, string);
|
||||
|
||||
// Close the file
|
||||
close(fd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
20
src/utils.h
20
src/utils.h
@ -46,4 +46,22 @@ Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr,
|
||||
/// @param fd The file descriptor to read from.
|
||||
/// @param out_string The pointer to the output string. The caller is responsible for freeing the memory.
|
||||
/// @return The result of the operation.
|
||||
Result read_fd(int fd, char** out_string);
|
||||
Result read_fd(int fd, char** out_string);
|
||||
|
||||
/// @brief Reads the contents of a file into a string.
|
||||
/// @param path The path of the file to read.
|
||||
/// @param out_string The pointer to the output string. The caller is responsible for freeing the memory.
|
||||
/// @return The result of the operation.
|
||||
Result read_file(const char* path, char** out_string);
|
||||
|
||||
/// @brief Writes the given string to a file descriptor.
|
||||
/// @param fd The file descriptor to write to.
|
||||
/// @param string The string to write.
|
||||
/// @return The result of the operation.
|
||||
Result write_fd(int fd, const char* string);
|
||||
|
||||
/// @brief Writes the given string to a file.
|
||||
/// @param path The path of the file to write.
|
||||
/// @param string The string to write.
|
||||
/// @return The result of the operation.
|
||||
Result write_file(const char* path, const char* string);
|
Loading…
Reference in New Issue
Block a user