Made small modifications
This commit is contained in:
332
src/backing.c
332
src/backing.c
@@ -1,332 +0,0 @@
|
||||
#include "backing.h"
|
||||
|
||||
#include "disk.h"
|
||||
#include "entry.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
bool IsBackingIdentifierValid(const char* backing_identifier) {
|
||||
if (backing_identifier == NULL)
|
||||
return false;
|
||||
|
||||
// Check that the identifier is not empty or too long
|
||||
size_t length = strlen(backing_identifier);
|
||||
if (length == 0 || length > 64)
|
||||
return false;
|
||||
|
||||
// Check that the identifier does not contain any slashes
|
||||
for (size_t i = 0; i < length; i++)
|
||||
if (backing_identifier[i] == '/')
|
||||
return false;
|
||||
|
||||
// Check that the identifier is not "." or ".."
|
||||
if (strcmp(backing_identifier, ".") == 0 || strcmp(backing_identifier, "..") == 0)
|
||||
return false;
|
||||
|
||||
// Check that the identifier starts with a number
|
||||
if (backing_identifier[0] < '0' || backing_identifier[0] > '9')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int GetBackingIndex(const char* backing_identifier) {
|
||||
// Check that the identifier is valid
|
||||
if (!IsBackingIdentifierValid(backing_identifier))
|
||||
return -1;
|
||||
|
||||
// Get the index
|
||||
return atoi(backing_identifier);
|
||||
}
|
||||
|
||||
Status GetBackingPoolPath(char** _backing_pool_path) {
|
||||
return Format(_backing_pool_path, "/var/lib/sandbox/backings");
|
||||
}
|
||||
|
||||
Status GetBackingPath(const char* backing_identifier, char** _backing_path) {
|
||||
// Check that the identifier is valid, as it will be used in a path
|
||||
if (!IsBackingIdentifierValid(backing_identifier)) {
|
||||
Log(LOG_LEVEL_ERROR, "Invalid backing identifier '%s'.", backing_identifier);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the backing pool path
|
||||
char* backing_pool_path = NULL;
|
||||
Status status = GetBackingPoolPath(&backing_pool_path);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
// Format the backing path
|
||||
status = Format(_backing_path, "%s/%s", backing_pool_path, backing_identifier);
|
||||
free(backing_pool_path);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Status DoesBackingExist(const char* backing_identifier, bool* _result) {
|
||||
// Get the backing path
|
||||
char* backing_path = NULL;
|
||||
Status status = GetBackingPath(backing_identifier, &backing_path);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
// Check if the backing exists and is a regular file
|
||||
struct stat st;
|
||||
*_result = stat(backing_path, &st) == 0 && S_ISREG(st.st_mode);
|
||||
free(backing_path);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Status AddBacking(const char* backing_identifier, const char* entry_identifier) {
|
||||
// Check that the backing does not already exist
|
||||
bool exists;
|
||||
Status status = DoesBackingExist(backing_identifier, &exists);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
if (exists) {
|
||||
Log(LOG_LEVEL_ERROR, "The backing '%s' already exists.", backing_identifier);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Check that the entry disk exists
|
||||
status = DoesEntryDiskExist(entry_identifier, &exists);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
if (!exists) {
|
||||
Log(LOG_LEVEL_ERROR, "The entry disk '%s' does not exist. Cannot create backing from it.", entry_identifier);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get information about the entry disk
|
||||
DiskInfo entry_info;
|
||||
status = GetEntryDiskInfo(entry_identifier, &entry_info);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
// Check that the backing used by the entry actually exists (broken backing chain)
|
||||
if (entry_info.backing_identifier != NULL) {
|
||||
status = DoesBackingExist(entry_info.backing_identifier, &exists);
|
||||
if (status != SUCCESS) {
|
||||
FreeDiskInfo(&entry_info);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
Log(LOG_LEVEL_ERROR, "The backing '%s' of the entry disk '%s' does not exist.", entry_info.backing_identifier, entry_identifier);
|
||||
|
||||
FreeDiskInfo(&entry_info);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the entry disk to the backing disk
|
||||
char* entry_disk_path = NULL;
|
||||
status = GetEntryDiskPath(entry_identifier, &entry_disk_path);
|
||||
if (status != SUCCESS) {
|
||||
FreeDiskInfo(&entry_info);
|
||||
return status;
|
||||
}
|
||||
|
||||
char* backing_path = NULL;
|
||||
status = GetBackingPath(backing_identifier, &backing_path);
|
||||
if (status != SUCCESS) {
|
||||
free(entry_disk_path);
|
||||
FreeDiskInfo(&entry_info);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = CopyFile(entry_disk_path, backing_path);
|
||||
if (status != SUCCESS) {
|
||||
free(entry_disk_path);
|
||||
free(backing_path);
|
||||
FreeDiskInfo(&entry_info);
|
||||
return status;
|
||||
}
|
||||
|
||||
free(entry_disk_path);
|
||||
|
||||
// If the entry disk has a backing, rebase the backing to the new backing
|
||||
if (entry_info.backing_identifier != NULL) {
|
||||
status = RebaseDisk(backing_path, entry_info.backing_identifier);
|
||||
if (status != SUCCESS) {
|
||||
RemoveBacking(backing_identifier);
|
||||
|
||||
free(backing_path);
|
||||
FreeDiskInfo(&entry_info);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
free(backing_path);
|
||||
FreeDiskInfo(&entry_info);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Status RemoveBacking(const char* backing_identifier) {
|
||||
// Check that the backing exists
|
||||
bool exists;
|
||||
Status status = DoesBackingExist(backing_identifier, &exists);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
if (!exists) {
|
||||
Log(LOG_LEVEL_ERROR, "The backing '%s' does not exist.", backing_identifier);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Get the backing path
|
||||
char* backing_path = NULL;
|
||||
status = GetBackingPath(backing_identifier, &backing_path);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
// Remove the backing
|
||||
if (unlink(backing_path) != 0) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to remove the backing '%s' (%s).", backing_identifier, strerror(errno));
|
||||
free(backing_path);
|
||||
return FAILURE;
|
||||
}
|
||||
free(backing_path);
|
||||
|
||||
// TODO: Remove all the backings that use this backing as a base
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Status ListBackings(char*** _backings) {
|
||||
*_backings = NULL;
|
||||
|
||||
// Open the backing pool directory
|
||||
char* backing_pool_path = NULL;
|
||||
Status status = GetBackingPoolPath(&backing_pool_path);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
DIR* dir = opendir(backing_pool_path);
|
||||
if (dir == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to open the backing pool directory %s (%s).", backing_pool_path, strerror(errno));
|
||||
free(backing_pool_path);
|
||||
return FAILURE;
|
||||
}
|
||||
free(backing_pool_path);
|
||||
|
||||
// Allocate memory for at least one backing (the NULL terminator)
|
||||
*_backings = malloc(sizeof(char*));
|
||||
if (*_backings == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for the backings list (%s).", strerror(errno));
|
||||
closedir(dir);
|
||||
return FAILURE;
|
||||
}
|
||||
(*_backings)[0] = NULL;
|
||||
|
||||
// Read the files in the backing pool directory
|
||||
size_t count = 0;
|
||||
struct dirent* file;
|
||||
while ((file = readdir(dir)) != NULL) {
|
||||
if (strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
// Check if the backing exists (this checks for validity)
|
||||
bool exists;
|
||||
Status status = DoesBackingExist(file->d_name, &exists);
|
||||
if (status != SUCCESS || !exists)
|
||||
continue;
|
||||
|
||||
// Allocate memory for the new backing list
|
||||
char** new_backings = realloc(*_backings, (count + 2) * sizeof(char*)); // +2 for the new entry and the NULL terminator
|
||||
if (new_backings == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to reallocate memory for the backing list (%s).", strerror(errno));
|
||||
closedir(dir);
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
free((*_backings)[i]);
|
||||
free(*_backings);
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
*_backings = new_backings;
|
||||
|
||||
// Duplicate the file name and add it to the list
|
||||
(*_backings)[count] = strdup(file->d_name);
|
||||
if ((*_backings)[count] == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to duplicate the backing name (%s).", strerror(errno));
|
||||
closedir(dir);
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
free((*_backings)[i]);
|
||||
free(*_backings);
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Add the NULL terminator
|
||||
(*_backings)[count + 1] = NULL;
|
||||
count++;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Status GetLatestBacking(char** _backing_identifier) {
|
||||
// List the backings
|
||||
char** backings = NULL;
|
||||
Status status = ListBackings(&backings);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
// Find the latest backing
|
||||
int latest_identifier_index = -1;
|
||||
int latest_index = -1;
|
||||
for (int i = 0; backings[i] != NULL; i++) {
|
||||
int index = GetBackingIndex(backings[i]);
|
||||
if (index > latest_index) {
|
||||
latest_identifier_index = i;
|
||||
latest_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the latest backing
|
||||
if (latest_identifier_index == -1) {
|
||||
*_backing_identifier = NULL;
|
||||
} else {
|
||||
*_backing_identifier = strdup(backings[latest_identifier_index]);
|
||||
if (*_backing_identifier == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to duplicate the backing identifier (%s).", strerror(errno));
|
||||
status = FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Free the backings list
|
||||
for (int i = 0; backings[i] != NULL; i++)
|
||||
free(backings[i]);
|
||||
free(backings);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Status GetBackingDiskInfo(const char* backing_identifier, DiskInfo* _info) {
|
||||
*_info = (DiskInfo){0};
|
||||
|
||||
// Get the backing path
|
||||
char* backing_path = NULL;
|
||||
Status status = GetBackingPath(backing_identifier, &backing_path);
|
||||
if (status != SUCCESS)
|
||||
return status;
|
||||
|
||||
// Get the disk info
|
||||
status = GetDiskInfo(backing_path, _info);
|
||||
free(backing_path);
|
||||
|
||||
return status;
|
||||
}
|
Reference in New Issue
Block a user