2024-02-17 00:40:09 +01:00
|
|
|
#include "entry.h"
|
|
|
|
|
|
|
|
#include "utils.h"
|
2024-02-17 02:28:17 +01:00
|
|
|
#include "disk.h"
|
2024-02-17 00:40:09 +01:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2024-02-17 00:57:30 +01:00
|
|
|
#include <errno.h>
|
2024-02-17 02:28:17 +01:00
|
|
|
#include <unistd.h>
|
2024-02-17 00:40:09 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
bool is_entry_id_valid(const char* entry_id) {
|
|
|
|
if (entry_id == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
size_t length = strlen(entry_id);
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// Check that the length is valid
|
2024-02-17 00:40:09 +01:00
|
|
|
if (length == 0 || length > MAX_ENTRY_LENGTH)
|
|
|
|
return false;
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// Check that the entry id does not contain any slashes
|
2024-02-17 00:40:09 +01:00
|
|
|
for (size_t i = 0; i < length; i++)
|
|
|
|
if (entry_id[i] == '/')
|
|
|
|
return false;
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// Check that the entry id is not a reserved name
|
|
|
|
if (strcmp(entry_id, ".") == 0 || strcmp(entry_id, "..") == 0)
|
|
|
|
return false;
|
|
|
|
|
2024-02-17 00:40:09 +01:00
|
|
|
return true;
|
2024-02-17 00:45:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Result get_entry_path(const char* entry_id, char** out_path) {
|
|
|
|
*out_path = NULL;
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// 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);
|
2024-02-17 00:45:44 +01:00
|
|
|
return FAILURE;
|
2024-02-17 00:57:30 +01:00
|
|
|
}
|
2024-02-17 00:45:44 +01:00
|
|
|
|
|
|
|
return format(out_path, "%s/%s", ENTRY_POOL_DIR, entry_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
Result entry_exists(const char* entry_id, bool* out_exists) {
|
|
|
|
*out_exists = false;
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// Get the path of the entry
|
2024-02-17 00:45:44 +01:00
|
|
|
char* path;
|
|
|
|
Result result = get_entry_path(entry_id, &path);
|
|
|
|
if (result != SUCCESS)
|
|
|
|
return result;
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// Check if the entry exists and is a directory
|
2024-02-17 00:45:44 +01:00
|
|
|
struct stat st;
|
|
|
|
bool exists = stat(path, &st) == 0 && S_ISDIR(st.st_mode);
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// Free the path
|
2024-02-17 00:45:44 +01:00
|
|
|
free(path);
|
|
|
|
|
2024-02-17 00:57:30 +01:00
|
|
|
// Output the result
|
2024-02-17 00:45:44 +01:00
|
|
|
*out_exists = exists;
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
2024-02-17 02:28:17 +01:00
|
|
|
|
|
|
|
Result add_root_entry(const char* entry_id, uint64_t size) {
|
|
|
|
// Check that the entry does not exist
|
|
|
|
bool exists;
|
|
|
|
Result result = entry_exists(entry_id, &exists);
|
|
|
|
if (result != SUCCESS)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
if (exists) {
|
|
|
|
log_message(LOG_LEVEL_ERROR, "Entry '%s' already exists.", entry_id);
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the path of the entry
|
|
|
|
char* path;
|
|
|
|
result = get_entry_path(entry_id, &path);
|
|
|
|
if (result != SUCCESS)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// Create the directory
|
|
|
|
int return_code = mkdir(path, 0755);
|
|
|
|
|
|
|
|
// Free the path as it is no longer needed
|
|
|
|
free(path);
|
|
|
|
|
|
|
|
// Check if the directory was created
|
|
|
|
if (return_code != 0) {
|
|
|
|
log_message(LOG_LEVEL_ERROR, "Failed to create the entry '%s' (%s).", entry_id, strerror(errno));
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the disk path
|
|
|
|
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 as it is no longer needed
|
|
|
|
free(disk_path);
|
|
|
|
|
|
|
|
// Remove the entry if the disk could not be created
|
|
|
|
if (result != SUCCESS) {
|
|
|
|
remove_entry(entry_id);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result remove_entry(const char* entry_id) {
|
|
|
|
// Remove the disk
|
|
|
|
char* disk_path;
|
|
|
|
Result result = get_entry_disk_path(entry_id, &disk_path);
|
|
|
|
if (result == SUCCESS) {
|
|
|
|
unlink(disk_path);
|
|
|
|
free(disk_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the path of the entry
|
|
|
|
char* path;
|
|
|
|
result = get_entry_path(entry_id, &path);
|
|
|
|
if (result != SUCCESS)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// Remove the directory
|
|
|
|
int return_code = rmdir(path);
|
|
|
|
|
|
|
|
// Free the path as it is no longer needed
|
|
|
|
free(path);
|
|
|
|
|
|
|
|
// Check if the directory was removed
|
|
|
|
if (return_code != 0) {
|
|
|
|
log_message(LOG_LEVEL_ERROR, "Failed to remove the entry '%s' (%s).", entry_id, strerror(errno));
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result get_entry_disk_path(const char* entry_id, char** out_path) {
|
|
|
|
*out_path = NULL;
|
|
|
|
|
|
|
|
// Get the path of the entry
|
|
|
|
char* path;
|
|
|
|
Result result = get_entry_path(entry_id, &path);
|
|
|
|
if (result != SUCCESS)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// Format the disk path
|
|
|
|
result = format(out_path, "%s/disk", path);
|
|
|
|
|
|
|
|
// Free the path as it is no longer needed
|
|
|
|
free(path);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2024-02-17 02:46:21 +01:00
|
|
|
|
|
|
|
Result trim_entry_disk(const char* entry_id) {
|
|
|
|
// Get the disk path
|
|
|
|
char* disk_path;
|
|
|
|
Result result = get_entry_disk_path(entry_id, &disk_path);
|
|
|
|
if (result != SUCCESS)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// Trim the disk
|
|
|
|
result = trim_disk(disk_path);
|
|
|
|
|
|
|
|
// Free the disk path as it is no longer needed
|
|
|
|
free(disk_path);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result reset_entry_disk(const char* entry_id) {
|
|
|
|
// Get the disk path
|
|
|
|
char* disk_path;
|
|
|
|
Result 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 as it is no longer needed
|
|
|
|
free(disk_path);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|