#include "backing.h" #include "disk.h" #include "entry.h" #include #include #include #include #include #include #include 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 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; }