Implemented some more functions

This commit is contained in:
Alexei KADIR 2024-02-15 12:50:30 +01:00
parent a059611982
commit f64f39c9c8
8 changed files with 306 additions and 29 deletions

View File

@ -7,6 +7,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
char* get_backings_path(void) { char* get_backings_path(void) {
@ -22,10 +24,16 @@ bool is_valid_backing_name(const char* name) {
if (length == 0) if (length == 0)
return false; 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++) for (size_t i = 0; i < length; i++)
if (name[i] < '0' || name[i] > '9') if (name[i] >= '0' && name[i] <= '9')
return false; timestamp_length++;
else
break;
if (timestamp_length == 0)
return false;
return true; return true;
} }
@ -65,7 +73,112 @@ bool backing_exists(const char* backing) {
return true; return true;
} }
uint64_t get_backing_creation_time(const char* backing) { char** list_backings(void) {
// A valid backing name is a number, corresponding to the timestamp of the backing disk creation char* path = get_backings_path();
return strtoull(backing, NULL, 10); 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;
} }

View File

@ -37,5 +37,6 @@ char* find_latest_backing(void);
/// @brief Creates a new backing disk. /// @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 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. /// @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);

View File

@ -12,7 +12,7 @@ bool create_empty_disk(const char* disk, uint64_t size) {
char* stderrb = NULL; char* stderrb = NULL;
// Create an empty disk // 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 // Check if the command was successful
if (result != 0) { if (result != 0) {
@ -40,7 +40,7 @@ bool create_backed_disk(const char* disk, const char* backing) {
char* stderrb = NULL; char* stderrb = NULL;
// Create a backed disk // 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 // Check if the command was successful
if (result != 0) { if (result != 0) {

View File

@ -5,10 +5,15 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <inttypes.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <dirent.h>
char* get_entries_path(void) { char* get_entries_path(void) {
return format("%s/%s", MASTER_DIRECTORY, ENTRIES_DIRECTORY); return format("%s/%s", MASTER_DIRECTORY, ENTRIES_DIRECTORY);
@ -70,21 +75,135 @@ bool entry_exists(const char* entry) {
return true; 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) { bool create_entry(const char* entry) {
char* entry_path = get_entry_path(entry); char* entry_path = get_entry_path(entry);
if (entry_path == NULL) if (entry_path == NULL)
return false; return false;
// Create the entry directory // Create the entry directory
int result = mkdir(entry_path, 0755); bool result = create_directory(entry_path, 0700, 0, 0);
// Free the entry path // Free the entry path
free(entry_path); free(entry_path);
if (result != 0) return result;
return false;
return true;
} }
bool delete_entry(const char* entry) { bool delete_entry(const char* entry) {
@ -93,7 +212,7 @@ bool delete_entry(const char* entry) {
return false; return false;
// Delete the entry directory // Delete the entry directory
bool result = delete_directory(entry_path); bool result = delete_directory(entry_path, 0);
// Free the entry path // Free the entry path
free(entry_path); free(entry_path);

View File

@ -3,6 +3,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#define DISK_PATH "disk"
/// @brief Returns the directory path where the entries are stored. /// @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. /// @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); char* get_entries_path(void);
@ -22,11 +24,16 @@ char* get_entry_path(const char* entry);
/// @return true if the entry exists, otherwise false. /// @return true if the entry exists, otherwise false.
bool entry_exists(const char* entry); 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. /// @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. /// @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); 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. /// @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. /// @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); 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. /// @return true if the entry was deleted, otherwise false.
bool delete_entry(const char* entry); 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. /// @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. /// @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); uint64_t get_available_space(void);

View File

@ -10,7 +10,12 @@
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <libgen.h> #include <libgen.h>
#include <string.h>
#include <errno.h>
int main(int argc, char* argv[]) { 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);
}
} }

View File

@ -7,6 +7,7 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.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; 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 // Open the directory
DIR* dir = opendir(directory); DIR* dir = opendir(directory);
if (dir == NULL) { 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; return false;
} }
@ -297,7 +319,7 @@ bool delete_directory(const char* directory) {
struct stat statbuf; struct stat statbuf;
int result = stat(entry_path, &statbuf); int result = stat(entry_path, &statbuf);
if (result != 0) { 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); free(entry_path);
closedir(dir); closedir(dir);
return false; return false;
@ -305,7 +327,9 @@ bool delete_directory(const char* directory) {
if (S_ISDIR(statbuf.st_mode)) { if (S_ISDIR(statbuf.st_mode)) {
// Delete the directory // 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); free(entry_path);
closedir(dir); closedir(dir);
return false; return false;
@ -313,7 +337,8 @@ bool delete_directory(const char* directory) {
} else { } else {
// Delete the file // Delete the file
if (unlink(entry_path) != 0) { 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); free(entry_path);
closedir(dir); closedir(dir);
return false; return false;
@ -328,7 +353,7 @@ bool delete_directory(const char* directory) {
// Delete the directory // Delete the directory
if (rmdir(directory) != 0) { 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; return false;
} }

View File

@ -2,6 +2,9 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <sys/types.h>
#define MAX_RECURSION_LEVEL 256
/// @brief The log levels. /// @brief The log levels.
typedef enum { typedef enum {
@ -31,7 +34,16 @@ void log_msg(LogLevel level, const char* fmt, ...);
/// @return The exit code of the command. /// @return The exit code of the command.
int execute(char** stdout_buffer, char** stderr_buffer, const char* file, ...); 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. /// @brief Deletes the specified directory and all its contents.
/// @param directory The directory to delete. /// @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. /// @return true if the directory was deleted, otherwise false.
bool delete_directory(const char* directory); bool delete_directory(const char* directory, int level);