Implemented some more functions
This commit is contained in:
parent
a059611982
commit
f64f39c9c8
123
src/backing.c
123
src/backing.c
@ -7,6 +7,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
char* get_backings_path(void) {
|
||||
@ -22,9 +24,15 @@ bool is_valid_backing_name(const char* name) {
|
||||
if (length == 0)
|
||||
return false;
|
||||
|
||||
// Check that the name is a number (the number is the timestamp of the backing disk creation)
|
||||
// Check that the name starts with a number, corresponding to the timestamp of the backing disk creation
|
||||
size_t timestamp_length = 0;
|
||||
for (size_t i = 0; i < length; i++)
|
||||
if (name[i] < '0' || name[i] > '9')
|
||||
if (name[i] >= '0' && name[i] <= '9')
|
||||
timestamp_length++;
|
||||
else
|
||||
break;
|
||||
|
||||
if (timestamp_length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -65,7 +73,112 @@ bool backing_exists(const char* backing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t get_backing_creation_time(const char* backing) {
|
||||
// A valid backing name is a number, corresponding to the timestamp of the backing disk creation
|
||||
return strtoull(backing, NULL, 10);
|
||||
char** list_backings(void) {
|
||||
char* path = get_backings_path();
|
||||
if (path == NULL)
|
||||
return NULL;
|
||||
|
||||
// Open the directory
|
||||
DIR* dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
log_msg(LOG_ERROR, "Failed to open directory '%s' (%s).", path, strerror(errno));
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
free(path);
|
||||
|
||||
// Count the number of entries
|
||||
size_t count = 0;
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
if (is_valid_backing_name(entry->d_name) && backing_exists(entry->d_name))
|
||||
count++;
|
||||
|
||||
// Allocate the array of strings
|
||||
char** backings = malloc((count + 1) * sizeof(char*));
|
||||
if (backings == NULL) {
|
||||
log_msg(LOG_ERROR, "Failed to allocate memory for the backings array.");
|
||||
closedir(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fill the array of strings
|
||||
rewinddir(dir);
|
||||
size_t index = 0;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (is_valid_backing_name(entry->d_name) && backing_exists(entry->d_name)) {
|
||||
backings[index] = strdup(entry->d_name);
|
||||
if (backings[index] == NULL) {
|
||||
log_msg(LOG_ERROR, "Failed to allocate memory for the backing name.");
|
||||
for (size_t i = 0; i < index; i++)
|
||||
free(backings[i]);
|
||||
free(backings);
|
||||
closedir(dir);
|
||||
return NULL;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate the array of strings
|
||||
backings[count] = NULL;
|
||||
|
||||
// Close the directory
|
||||
closedir(dir);
|
||||
|
||||
return backings;
|
||||
}
|
||||
|
||||
uint64_t get_backing_creation_time(const char* backing) {
|
||||
size_t length = strlen(backing);
|
||||
size_t timestamp_length = 0;
|
||||
|
||||
// Find the length of the timestamp
|
||||
for (size_t i = 0; i < length; i++)
|
||||
if (backing[i] >= '0' && backing[i] <= '9')
|
||||
timestamp_length++;
|
||||
else
|
||||
break;
|
||||
|
||||
// Extract the timestamp
|
||||
char* timestamp = strndup(backing, timestamp_length);
|
||||
if (timestamp == NULL)
|
||||
return 0;
|
||||
|
||||
// Convert the timestamp to a number
|
||||
uint64_t creation_time = strtoull(timestamp, NULL, 10);
|
||||
|
||||
// Free the timestamp
|
||||
free(timestamp);
|
||||
|
||||
return creation_time;
|
||||
}
|
||||
|
||||
char* find_latest_backing(void) {
|
||||
char** backings = list_backings();
|
||||
if (backings == NULL)
|
||||
return NULL;
|
||||
|
||||
// Find the latest backing disk
|
||||
char* latest_backing = NULL;
|
||||
uint64_t latest_time = 0;
|
||||
|
||||
for (size_t i = 0; backings[i] != NULL; i++) {
|
||||
uint64_t time = get_backing_creation_time(backings[i]);
|
||||
if (time >= latest_time) {
|
||||
latest_time = time;
|
||||
latest_backing = backings[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate the latest backing disk
|
||||
if (latest_backing != NULL)
|
||||
latest_backing = strdup(latest_backing);
|
||||
|
||||
// Free the backings
|
||||
for (size_t i = 0; backings[i] != NULL; i++)
|
||||
free(backings[i]);
|
||||
free(backings);
|
||||
|
||||
return latest_backing;
|
||||
}
|
||||
|
@ -37,5 +37,6 @@ char* find_latest_backing(void);
|
||||
|
||||
/// @brief Creates a new backing disk.
|
||||
/// @param backing_disk The disk to use as the backing disk. Warning: the disk must be part of the backing disks.
|
||||
/// @param description The description of the backing disk.
|
||||
/// @return true if the backing disk was created, otherwise false.
|
||||
bool create_backing(const char* backing_disk);
|
||||
bool create_backing(const char* backing_disk, const char* description);
|
@ -12,7 +12,7 @@ bool create_empty_disk(const char* disk, uint64_t size) {
|
||||
char* stderrb = NULL;
|
||||
|
||||
// Create an empty disk
|
||||
int result = execute(&stdoutb, &stderrb, "qemu-img", "create", "-c", "-f", "qcow2", disk, format("%" PRIu64, size), NULL);
|
||||
int result = execute(&stdoutb, &stderrb, "qemu-img", "create", "-f", "qcow2", disk, format("%" PRIu64, size), NULL);
|
||||
|
||||
// Check if the command was successful
|
||||
if (result != 0) {
|
||||
@ -40,7 +40,7 @@ bool create_backed_disk(const char* disk, const char* backing) {
|
||||
char* stderrb = NULL;
|
||||
|
||||
// Create a backed disk
|
||||
int result = execute(&stdoutb, &stderrb, "qemu-img", "create", "-c", "-f", "qcow2", "-F", "qcow2", "-b", backing, disk, NULL);
|
||||
int result = execute(&stdoutb, &stderrb, "qemu-img", "create", "-f", "qcow2", "-F", "qcow2", "-b", backing, disk, NULL);
|
||||
|
||||
// Check if the command was successful
|
||||
if (result != 0) {
|
||||
|
131
src/entry.c
131
src/entry.c
@ -5,10 +5,15 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <dirent.h>
|
||||
|
||||
char* get_entries_path(void) {
|
||||
return format("%s/%s", MASTER_DIRECTORY, ENTRIES_DIRECTORY);
|
||||
@ -70,21 +75,135 @@ bool entry_exists(const char* entry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char* get_entry_disk_path(const char* entry) {
|
||||
char* entry_path = get_entry_path(entry);
|
||||
if (entry_path == NULL)
|
||||
return NULL;
|
||||
|
||||
// Combine the entry path with the disk name
|
||||
char* disk_path = format("%s/%s", entry_path, DISK_PATH);
|
||||
|
||||
// Free the entry path
|
||||
free(entry_path);
|
||||
|
||||
return disk_path;
|
||||
}
|
||||
|
||||
char** list_entries(void) {
|
||||
char* path = get_entries_path();
|
||||
if (path == NULL)
|
||||
return NULL;
|
||||
|
||||
// Open the directory
|
||||
DIR* dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
log_msg(LOG_ERROR, "Failed to open directory '%s' (%s).", path, strerror(errno));
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
free(path);
|
||||
|
||||
// Count the number of entries
|
||||
size_t count = 0;
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
if (is_valid_entry_name(entry->d_name) && entry_exists(entry->d_name))
|
||||
count++;
|
||||
|
||||
// Allocate the array of entries
|
||||
char** entries = malloc((count + 1) * sizeof(char*));
|
||||
if (entries == NULL) {
|
||||
log_msg(LOG_ERROR, "Failed to allocate memory for the entries array.");
|
||||
closedir(dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fill the array of entries
|
||||
rewinddir(dir);
|
||||
size_t index = 0;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (is_valid_entry_name(entry->d_name) && entry_exists(entry->d_name)) {
|
||||
entries[index] = strdup(entry->d_name);
|
||||
if (entries[index] == NULL) {
|
||||
log_msg(LOG_ERROR, "Failed to allocate memory for the entry name.");
|
||||
for (size_t i = 0; i < index; i++)
|
||||
free(entries[i]);
|
||||
free(entries);
|
||||
closedir(dir);
|
||||
return NULL;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate the array of entries
|
||||
entries[count] = NULL;
|
||||
|
||||
// Close the directory
|
||||
closedir(dir);
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
uint64_t get_entry_last_access(const char* entry) {
|
||||
char* disk = get_entry_disk_path(entry);
|
||||
if (disk == NULL)
|
||||
return 0;
|
||||
|
||||
// Get the last access time of the disk
|
||||
struct stat statbuf;
|
||||
int result = stat(disk, &statbuf);
|
||||
|
||||
// Free the disk path
|
||||
free(disk);
|
||||
|
||||
if (result != 0)
|
||||
return 0;
|
||||
|
||||
return statbuf.st_atime;
|
||||
}
|
||||
|
||||
char* find_oldest_entry(void) {
|
||||
char** entries = list_entries();
|
||||
if (entries == NULL)
|
||||
return NULL;
|
||||
|
||||
// Find the oldest entry
|
||||
char* oldest_entry = NULL;
|
||||
uint64_t oldest_time = UINT64_MAX;
|
||||
|
||||
for (size_t i = 0; entries[i] != NULL; i++) {
|
||||
uint64_t time = get_entry_last_access(entries[i]);
|
||||
if (time <= oldest_time) {
|
||||
oldest_time = time;
|
||||
oldest_entry = entries[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate the oldest entry
|
||||
if (oldest_entry != NULL)
|
||||
oldest_entry = strdup(oldest_entry);
|
||||
|
||||
// Free the entries
|
||||
for (size_t i = 0; entries[i] != NULL; i++)
|
||||
free(entries[i]);
|
||||
free(entries);
|
||||
|
||||
return oldest_entry;
|
||||
}
|
||||
|
||||
bool create_entry(const char* entry) {
|
||||
char* entry_path = get_entry_path(entry);
|
||||
if (entry_path == NULL)
|
||||
return false;
|
||||
|
||||
// Create the entry directory
|
||||
int result = mkdir(entry_path, 0755);
|
||||
bool result = create_directory(entry_path, 0700, 0, 0);
|
||||
|
||||
// Free the entry path
|
||||
free(entry_path);
|
||||
|
||||
if (result != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool delete_entry(const char* entry) {
|
||||
@ -93,7 +212,7 @@ bool delete_entry(const char* entry) {
|
||||
return false;
|
||||
|
||||
// Delete the entry directory
|
||||
bool result = delete_directory(entry_path);
|
||||
bool result = delete_directory(entry_path, 0);
|
||||
|
||||
// Free the entry path
|
||||
free(entry_path);
|
||||
|
14
src/entry.h
14
src/entry.h
@ -3,6 +3,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define DISK_PATH "disk"
|
||||
|
||||
/// @brief Returns the directory path where the entries are stored.
|
||||
/// @return The directory path where the entries are stored. The caller is responsible for freeing the returned string. This function can return NULL.
|
||||
char* get_entries_path(void);
|
||||
@ -22,11 +24,16 @@ char* get_entry_path(const char* entry);
|
||||
/// @return true if the entry exists, otherwise false.
|
||||
bool entry_exists(const char* entry);
|
||||
|
||||
/// @brief Returns the path to the disk of the specified entry.
|
||||
/// @param entry The valid entry name.
|
||||
/// @return The path to the disk of the specified entry. The caller is responsible for freeing the returned string. This function can return NULL.
|
||||
char* get_entry_disk_path(const char* entry);
|
||||
|
||||
/// @brief Lists the entries.
|
||||
/// @return The list of entries. The caller is responsible for freeing the returned array and strings. This function can return NULL.
|
||||
char** list_entries(void);
|
||||
|
||||
/// @brief Get the last access time of the specified entry.
|
||||
/// @brief Returns the last access time of the specified entry.
|
||||
/// @param entry The valid entry name, which must exist.
|
||||
/// @return The last access time of the specified entry. If the entry does not exist, this function returns 0.
|
||||
uint64_t get_entry_last_access(const char* entry);
|
||||
@ -45,11 +52,6 @@ bool create_entry(const char* entry);
|
||||
/// @return true if the entry was deleted, otherwise false.
|
||||
bool delete_entry(const char* entry);
|
||||
|
||||
/// @brief Updates the last access time of the specified entry.
|
||||
/// @param entry The valid entry name, which must exist.
|
||||
/// @return true if the last access time was updated, otherwise false.
|
||||
bool update_entry_last_access(const char* entry);
|
||||
|
||||
/// @brief Returns the available space in the entries directory.
|
||||
/// @return The available space in the entries directory. If the entries directory does not exist, this function returns 0.
|
||||
uint64_t get_available_space(void);
|
||||
|
@ -10,7 +10,12 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
log_msg(LOG_INFO, "Available space : %lld", get_available_space());
|
||||
while (1) {
|
||||
char* oldest_entry = find_oldest_entry();
|
||||
free(oldest_entry);
|
||||
}
|
||||
}
|
37
src/utils.c
37
src/utils.c
@ -7,6 +7,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@ -270,11 +271,32 @@ int execute(char** stdout_buffer, char** stderr_buffer, const char* file, ...) {
|
||||
return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
|
||||
}
|
||||
|
||||
bool delete_directory(const char* directory) {
|
||||
bool create_directory(const char* directory, mode_t mode, uid_t uid, gid_t gid) {
|
||||
// Create the directory
|
||||
if (mkdir(directory, mode) != 0) {
|
||||
log_msg(LOG_ERROR, "Failed to create directory '%s' (%s).", directory, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Change the owner of the directory
|
||||
if (chown(directory, uid, gid) != 0) {
|
||||
log_msg(LOG_ERROR, "Failed to change the owner of directory '%s' (%s).", directory, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool delete_directory(const char* directory, int level) {
|
||||
if (level > MAX_RECURSION_LEVEL) {
|
||||
log_msg(LOG_ERROR, "Too many levels of recursion when deleting directory '%s'.", directory);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the directory
|
||||
DIR* dir = opendir(directory);
|
||||
if (dir == NULL) {
|
||||
log_msg(LOG_ERROR, "Failed to open directory '%s'.", directory);
|
||||
log_msg(LOG_ERROR, "Failed to open directory '%s' (%s).", directory, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -297,7 +319,7 @@ bool delete_directory(const char* directory) {
|
||||
struct stat statbuf;
|
||||
int result = stat(entry_path, &statbuf);
|
||||
if (result != 0) {
|
||||
log_msg(LOG_ERROR, "Failed to get information about entry '%s'.", entry_path);
|
||||
log_msg(LOG_ERROR, "Failed to get information about file '%s' (%s).", entry_path, strerror(errno));
|
||||
free(entry_path);
|
||||
closedir(dir);
|
||||
return false;
|
||||
@ -305,7 +327,9 @@ bool delete_directory(const char* directory) {
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode)) {
|
||||
// Delete the directory
|
||||
if (!delete_directory(entry_path)) {
|
||||
if (!delete_directory(entry_path, level + 1)) {
|
||||
log_msg(LOG_ERROR, "Failed to delete directory '%s'.", entry_path);
|
||||
|
||||
free(entry_path);
|
||||
closedir(dir);
|
||||
return false;
|
||||
@ -313,7 +337,8 @@ bool delete_directory(const char* directory) {
|
||||
} else {
|
||||
// Delete the file
|
||||
if (unlink(entry_path) != 0) {
|
||||
log_msg(LOG_ERROR, "Failed to delete entry '%s'.", entry_path);
|
||||
log_msg(LOG_ERROR, "Failed to delete file '%s' (%s).", entry_path, strerror(errno));
|
||||
|
||||
free(entry_path);
|
||||
closedir(dir);
|
||||
return false;
|
||||
@ -328,7 +353,7 @@ bool delete_directory(const char* directory) {
|
||||
|
||||
// Delete the directory
|
||||
if (rmdir(directory) != 0) {
|
||||
log_msg(LOG_ERROR, "Failed to delete directory '%s'.", directory);
|
||||
log_msg(LOG_ERROR, "Failed to delete directory '%s' (%s).", directory, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
14
src/utils.h
14
src/utils.h
@ -2,6 +2,9 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define MAX_RECURSION_LEVEL 256
|
||||
|
||||
/// @brief The log levels.
|
||||
typedef enum {
|
||||
@ -31,7 +34,16 @@ void log_msg(LogLevel level, const char* fmt, ...);
|
||||
/// @return The exit code of the command.
|
||||
int execute(char** stdout_buffer, char** stderr_buffer, const char* file, ...);
|
||||
|
||||
/// @brief Creates the specified directory.
|
||||
/// @param directory The directory to create.
|
||||
/// @param mode The mode to use when creating the directory.
|
||||
/// @param uid The user ID to use when creating the directory.
|
||||
/// @param gid The group ID to use when creating the directory.
|
||||
/// @return true if the directory was created, otherwise false.
|
||||
bool create_directory(const char* directory, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
/// @brief Deletes the specified directory and all its contents.
|
||||
/// @param directory The directory to delete.
|
||||
/// @param level The current level of recursion. This parameter is used internally and should be set to 0.
|
||||
/// @return true if the directory was deleted, otherwise false.
|
||||
bool delete_directory(const char* directory);
|
||||
bool delete_directory(const char* directory, int level);
|
||||
|
Loading…
Reference in New Issue
Block a user