Files
linuxinstall/src/entry.c

378 lines
9.4 KiB
C
Raw Normal View History

#include "entry.h"
2024-02-17 02:28:17 +01:00
#include "disk.h"
2024-02-18 02:06:49 +01:00
#include "backing.h"
#include <stdlib.h>
#include <string.h>
2024-02-17 00:57:30 +01:00
#include <errno.h>
#include <dirent.h>
2024-02-17 23:59:38 +01:00
#include <unistd.h>
#include <sys/stat.h>
2024-02-17 23:59:38 +01:00
bool IsEntryIdentifierValid(const char* entry_identifier) {
if (entry_identifier == NULL)
return false;
2024-02-17 23:59:38 +01:00
// Check that the identifier is not empty or too long
size_t length = strlen(entry_identifier);
if (length == 0 || length > 64)
return false;
2024-02-17 23:59:38 +01:00
// Check that the identifier does not contain any slashes
for (size_t i = 0; i < length; i++)
2024-02-17 23:59:38 +01:00
if (entry_identifier[i] == '/')
return false;
2024-02-17 23:59:38 +01:00
// Check that the identifier is not "." or ".."
if (strcmp(entry_identifier, ".") == 0 || strcmp(entry_identifier, "..") == 0)
2024-02-17 00:57:30 +01:00
return false;
return true;
}
2024-02-17 23:59:38 +01:00
Status GetEntryPoolPath(char** _entry_pool_path) {
return Format(_entry_pool_path, "/var/lib/sandbox/entries");
}
2024-02-17 23:59:38 +01:00
Status GetEntryPath(const char* entry_identifier, char** _entry_path) {
// Check that the identifier is valid, as it will be used in a path
if (!IsEntryIdentifierValid(entry_identifier)) {
Log(LOG_LEVEL_ERROR, "Invalid entry identifier '%s'.", entry_identifier);
return FAILURE;
}
2024-02-17 23:59:38 +01:00
// Get the entry pool path
char* entry_pool_path = NULL;
Status status = GetEntryPoolPath(&entry_pool_path);
if (status != SUCCESS)
return status;
2024-02-17 23:59:38 +01:00
// Format the entry path
status = Format(_entry_path, "%s/%s", entry_pool_path, entry_identifier);
free(entry_pool_path);
2024-02-17 23:59:38 +01:00
return status;
}
2024-02-17 23:59:38 +01:00
Status GetEntryDiskPath(const char* entry_identifier, char** _entry_disk_path) {
// Get the entry path
char* entry_path = NULL;
Status status = GetEntryPath(entry_identifier, &entry_path);
if (status != SUCCESS)
return status;
2024-02-17 12:34:24 +01:00
2024-02-17 23:59:38 +01:00
// Format the disk path
status = Format(_entry_disk_path, "%s/disk", entry_path);
2024-02-17 12:34:24 +01:00
free(entry_path);
2024-02-17 23:59:38 +01:00
return status;
2024-02-17 12:34:24 +01:00
}
2024-02-17 23:59:38 +01:00
Status DoesEntryExist(const char* entry_identifier, bool* _result) {
// Get the entry path
char* entry_path = NULL;
Status status = GetEntryPath(entry_identifier, &entry_path);
if (status != SUCCESS)
return status;
2024-02-17 15:15:40 +01:00
2024-02-17 23:59:38 +01:00
// Check if the entry exists and is a directory
struct stat st;
*_result = stat(entry_path, &st) == 0 && S_ISDIR(st.st_mode);
free(entry_path);
2024-02-17 15:15:40 +01:00
return SUCCESS;
}
2024-02-17 23:59:38 +01:00
Status DoesEntryDiskExist(const char* entry_identifier, bool* _result) {
// Get the disk path
char* entry_disk_path = NULL;
Status status = GetEntryDiskPath(entry_identifier, &entry_disk_path);
if (status != SUCCESS)
return status;
2024-02-17 23:59:38 +01:00
// Check if the disk exists and is a regular file
struct stat st;
2024-02-17 23:59:38 +01:00
*_result = stat(entry_disk_path, &st) == 0 && S_ISREG(st.st_mode);
free(entry_disk_path);
return SUCCESS;
2024-02-17 12:34:24 +01:00
}
2024-02-17 23:59:38 +01:00
Status AddEntry(const char* entry_identifier) {
// Check if the entry already exists
2024-02-17 12:34:24 +01:00
bool exists;
2024-02-17 23:59:38 +01:00
Status status = DoesEntryExist(entry_identifier, &exists);
if (status != SUCCESS)
return status;
2024-02-17 12:34:24 +01:00
if (exists) {
2024-02-17 23:59:38 +01:00
Log(LOG_LEVEL_ERROR, "The entry '%s' already exists.", entry_identifier);
2024-02-17 12:34:24 +01:00
return FAILURE;
}
2024-02-17 23:59:38 +01:00
// Create the entry directory
char* entry_path = NULL;
status = GetEntryPath(entry_identifier, &entry_path);
if (status != SUCCESS)
return status;
2024-02-17 12:34:24 +01:00
2024-02-17 23:59:38 +01:00
if (mkdir(entry_path, 0755) != 0) {
Log(LOG_LEVEL_ERROR, "Failed to create the entry directory '%s' (%s).", entry_path, strerror(errno));
2024-02-17 12:34:24 +01:00
free(entry_path);
return FAILURE;
}
free(entry_path);
2024-02-17 23:59:38 +01:00
return SUCCESS;
}
2024-02-17 12:34:24 +01:00
2024-02-17 23:59:38 +01:00
Status RemoveEntry(const char* entry_identifier) {
// Check if the entry exists
bool exists;
Status status = DoesEntryExist(entry_identifier, &exists);
if (status != SUCCESS)
return status;
if (!exists) {
Log(LOG_LEVEL_ERROR, "The entry '%s' does not exist.", entry_identifier);
2024-02-17 12:34:24 +01:00
return FAILURE;
}
2024-02-17 23:59:38 +01:00
// Check if the disk exists, and remove it if it does
bool disk_exists;
status = DoesEntryDiskExist(entry_identifier, &disk_exists);
if (status != SUCCESS)
return status;
2024-02-17 12:34:24 +01:00
2024-02-17 23:59:38 +01:00
if (disk_exists) {
status = RemoveEntryDisk(entry_identifier);
if (status != SUCCESS)
return status;
2024-02-17 12:34:24 +01:00
}
2024-02-17 23:59:38 +01:00
// Remove the entry directory
char* entry_path = NULL;
status = GetEntryPath(entry_identifier, &entry_path);
if (status != SUCCESS)
return status;
2024-02-17 12:34:24 +01:00
2024-02-17 23:59:38 +01:00
if (rmdir(entry_path) != 0) {
Log(LOG_LEVEL_ERROR, "Failed to remove the entry directory '%s' (%s).", entry_path, strerror(errno));
free(entry_path);
return FAILURE;
2024-02-17 12:34:24 +01:00
}
2024-02-17 23:59:38 +01:00
free(entry_path);
2024-02-17 12:34:24 +01:00
return SUCCESS;
}
2024-02-17 23:59:38 +01:00
Status ListEntries(char*** _entries) {
*_entries = NULL;
2024-02-17 14:38:52 +01:00
2024-02-17 23:59:38 +01:00
// Open the entry pool directory
char* entry_pool_path = NULL;
Status status = GetEntryPoolPath(&entry_pool_path);
if (status != SUCCESS)
return status;
2024-02-17 14:38:52 +01:00
2024-02-17 23:59:38 +01:00
DIR* dir = opendir(entry_pool_path);
if (dir == NULL) {
Log(LOG_LEVEL_ERROR, "Failed to open the entry pool directory '%s' (%s).", entry_pool_path, strerror(errno));
free(entry_pool_path);
2024-02-17 12:34:24 +01:00
return FAILURE;
}
2024-02-17 23:59:38 +01:00
free(entry_pool_path);
2024-02-17 12:34:24 +01:00
2024-02-17 23:59:38 +01:00
// Allocate memory for at least one entry (the NULL terminator)
*_entries = malloc(sizeof(char*));
if (*_entries == NULL) {
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for the entries list (%s).", strerror(errno));
closedir(dir);
2024-02-17 14:38:52 +01:00
return FAILURE;
}
2024-02-17 23:59:38 +01:00
(*_entries)[0] = NULL;
2024-02-17 14:38:52 +01:00
2024-02-17 23:59:38 +01:00
// Read the entries from the directory
size_t count = 0;
2024-02-17 14:38:52 +01:00
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
2024-02-18 02:06:49 +01:00
bool exists;
Status status = DoesEntryExist(entry->d_name, &exists);
if (status != SUCCESS || !exists)
continue;
2024-02-17 23:59:38 +01:00
char** new_entries = realloc(*_entries, (count + 2) * sizeof(char*)); // +2 for the new entry and the NULL terminator
if (new_entries == NULL) {
Log(LOG_LEVEL_ERROR, "Failed to reallocate memory for the entries list (%s).", strerror(errno));
2024-02-17 14:38:52 +01:00
closedir(dir);
2024-02-17 23:59:38 +01:00
for (size_t i = 0; i < count; i++)
free((*_entries)[i]);
free(*_entries);
2024-02-17 14:38:52 +01:00
2024-02-17 23:59:38 +01:00
return FAILURE;
}
*_entries = new_entries;
// Duplicate the entry name and add it to the list
(*_entries)[count] = strdup(entry->d_name);
if ((*_entries)[count] == NULL) {
Log(LOG_LEVEL_ERROR, "Failed to duplicate the entry name (%s).", strerror(errno));
2024-02-17 14:38:52 +01:00
closedir(dir);
2024-02-17 23:59:38 +01:00
for (size_t i = 0; i < count; i++)
free((*_entries)[i]);
free(*_entries);
2024-02-17 14:38:52 +01:00
return FAILURE;
}
2024-02-17 23:59:38 +01:00
// Add the NULL terminator
(*_entries)[count + 1] = NULL;
count++;
2024-02-17 14:38:52 +01:00
}
closedir(dir);
2024-02-17 23:59:38 +01:00
return SUCCESS;
}
2024-02-17 12:34:24 +01:00
2024-02-17 23:59:38 +01:00
Status ClearEntries() {
// Get the entries
char** entries = NULL;
Status status = ListEntries(&entries);
if (status != SUCCESS)
return status;
// Remove the entries
for (size_t i = 0; entries[i] != NULL; i++) {
status = RemoveEntry(entries[i]);
if (status != SUCCESS)
Log(LOG_LEVEL_WARNING, "Failed to remove the entry '%s'. Non-critical error.", entries[i]);
2024-02-17 12:34:24 +01:00
}
2024-02-17 23:59:38 +01:00
// Clean up
for (size_t i = 0; entries[i] != NULL; i++)
free(entries[i]);
free(entries);
2024-02-17 12:34:24 +01:00
return SUCCESS;
}
2024-02-17 23:59:38 +01:00
Status AddRootEntryDisk(const char* entry_identifier, uint64_t disk_size) {
// Check if the disk already exists
bool exists;
Status status = DoesEntryDiskExist(entry_identifier, &exists);
if (status != SUCCESS)
return status;
2024-02-17 23:59:38 +01:00
if (exists) {
Log(LOG_LEVEL_ERROR, "The disk for the entry '%s' already exists.", entry_identifier);
return FAILURE;
}
2024-02-17 23:59:38 +01:00
// Get the disk path
char* entry_disk_path = NULL;
status = GetEntryDiskPath(entry_identifier, &entry_disk_path);
if (status != SUCCESS)
return status;
2024-02-17 23:59:38 +01:00
// Create the disk
status = CreateRootDisk(entry_disk_path, disk_size);
free(entry_disk_path);
2024-02-17 23:59:38 +01:00
return status;
}
2024-02-18 02:06:49 +01:00
Status AddBackedEntryDisk(const char* entry_identifier, const char* backing_identifier) {
// Check if the disk already exists
bool exists;
Status status = DoesEntryDiskExist(entry_identifier, &exists);
if (status != SUCCESS)
return status;
if (exists) {
Log(LOG_LEVEL_ERROR, "The disk for the entry '%s' already exists.", entry_identifier);
return FAILURE;
}
// Get the backing disk path
char* backing_disk_path = NULL;
status = GetBackingDiskPath(backing_identifier, &backing_disk_path);
if (status != SUCCESS)
return status;
// Get the disk path
char* entry_disk_path = NULL;
status = GetEntryDiskPath(entry_identifier, &entry_disk_path);
if (status != SUCCESS) {
free(backing_disk_path);
return status;
}
// Create the disk
status = CreateBackedDisk(entry_disk_path, backing_disk_path);
free(backing_disk_path);
free(entry_disk_path);
return status;
}
2024-02-17 23:59:38 +01:00
Status RemoveEntryDisk(const char* entry_identifier) {
// Check if the disk exists
bool exists;
Status status = DoesEntryDiskExist(entry_identifier, &exists);
if (status != SUCCESS)
return status;
2024-02-17 23:59:38 +01:00
if (!exists) {
Log(LOG_LEVEL_ERROR, "The disk for the entry '%s' does not exist.", entry_identifier);
return FAILURE;
}
2024-02-17 23:59:38 +01:00
// Get the disk path
char* entry_disk_path = NULL;
status = GetEntryDiskPath(entry_identifier, &entry_disk_path);
if (status != SUCCESS)
return status;
2024-02-17 23:59:38 +01:00
// Remove the disk
if (unlink(entry_disk_path) != 0) {
Log(LOG_LEVEL_ERROR, "Failed to remove the disk for the entry '%s' (%s).", entry_identifier, strerror(errno));
free(entry_disk_path);
return FAILURE;
}
2024-02-17 23:59:38 +01:00
free(entry_disk_path);
return SUCCESS;
}
2024-02-17 23:59:38 +01:00
Status TrimEntryDisk(const char* entry_identifier) {
// Check if the disk exists
bool exists;
Status status = DoesEntryDiskExist(entry_identifier, &exists);
if (status != SUCCESS)
return status;
if (!exists) {
Log(LOG_LEVEL_ERROR, "The disk for the entry '%s' does not exist.", entry_identifier);
return FAILURE;
2024-02-17 13:01:40 +01:00
}
2024-02-17 23:59:38 +01:00
// Get the disk path
char* entry_disk_path = NULL;
status = GetEntryDiskPath(entry_identifier, &entry_disk_path);
if (status != SUCCESS)
return status;
2024-02-17 13:01:40 +01:00
2024-02-17 23:59:38 +01:00
// Trim the disk
status = TrimDisk(entry_disk_path);
free(entry_disk_path);
return status;
2024-02-17 13:01:40 +01:00
}