1
0
mirror of https://gitlab.com/80486DX2-66/gists synced 2024-11-15 14:55:55 +05:30
gists/c-programming/reverse-ramdisk.c

239 lines
5.1 KiB
C

/*
C programming idea: Handling temporary files like memory allocations (allocating -> creating empty file, using -> locking for R/W, freeing -> deleting).
50% AI, 50% human (the code is tested and reviewed)
Warning: The current result is quick and dirty. Not for educational or
production purposes.
GCC/Clang/TCC: Compile with -DTEST to set macro TEST as defined, with -DDEBUG
to enable debug mode
To-Do: error handling on line 184, function fread()
*/
#include <errno.h>
#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef DEBUG
# define line_fail(x) do { \
printf("failed on line %d\n", __LINE__ + x); \
} while (0)
#else
# define line_fail(x) do {} while (0)
#endif
#define retreat(s) do { \
perror(s); \
exit(EXIT_FAILURE); \
} while (0)
typedef struct {
int ID;
char* file_path;
FILE* file;
} TempFile;
TempFile* temp_files = NULL;
size_t num_temp_files = 0;
int tf_alloc(size_t n, size_t type_size);
int tf_free(int ID);
int tf_write(int ID, size_t offset, void* data, size_t data_size);
int tf_read(int ID, size_t offset, void* dest, size_t data_size);
int tf_alloc(size_t n, size_t type_size) {
// Create an empty file
size_t len_digit;
if (num_temp_files == 0)
len_digit = 1;
else
len_digit = (size_t) ceil(log((double) num_temp_files + 1.) / log(10.));
size_t file_path_len = len_digit + strlen("tf_.tmp");
char* file_path = malloc((file_path_len + 1) * sizeof(char));
if (file_path == NULL) {
line_fail(-2);
return -1;
}
int res = snprintf(file_path, file_path_len, "tf_%" PRIuMAX ".tmp",
(uintmax_t) num_temp_files);
if ((size_t) res != file_path_len) {
line_fail(-2);
return -1;
}
// Open the file
FILE* file = fopen(file_path, "w+b");
if (file == NULL) {
line_fail(-2);
return -1;
}
// Allocate memory for the TempFile struct
TempFile* temp_file = malloc(sizeof(TempFile));
if (temp_file == NULL) {
line_fail(-2);
return -1;
}
// Assign the ID, file path, file handler
temp_file->ID = num_temp_files;
temp_file->file_path = strdup(file_path);
temp_file->file = file;
// Add the temp file to the array
temp_files[num_temp_files] = *temp_file;
num_temp_files++;
// Allocate/reallocate memory for the temp_files structure
if (temp_files == NULL)
temp_files = malloc(sizeof(TempFile));
else
temp_files = realloc(temp_files,
(size_t) num_temp_files * sizeof(TempFile));
if (temp_files == NULL) {
line_fail(-2);
return -1;
}
return temp_file->ID;
}
int tf_free(int ID) {
size_t index = (size_t) ID;
if (index == -1)
return -1;
fclose(temp_files[index].file);
// Delete the file
if (remove(temp_files[index].file_path) != 0) {
line_fail(-1);
return -1;
}
free(temp_files[index].file_path);
// Shift the remaining temp files in the array
for (int i = index; i < num_temp_files - 1; i++) {
temp_files[(size_t) i] = temp_files[(size_t) i + 1];
}
num_temp_files--;
// Reallocate memory for the temp_files array
temp_files = realloc(temp_files, num_temp_files * sizeof(TempFile));
if (temp_files == NULL && num_temp_files > 0) {
line_fail(-2);
return -1;
}
return 0;
}
int tf_write(int ID, size_t offset, void* data, size_t data_size) {
size_t index = (size_t) ID;
if (index == -1)
return -1;
// Check file handler for NULL
FILE* file = temp_files[index].file;
if (file == NULL)
return -1;
// Set the position
fseek(file, offset, SEEK_SET);
// Write the data to the file
size_t bytes_written = fwrite(data, 1, data_size, file);
if (bytes_written != data_size)
return -1;
if (fdatasync(file) == -1) {
line_fail(-1);
return -1;
}
return 0;
}
int tf_read(int ID, size_t offset, void* dest, size_t data_size) {
size_t index = (size_t) ID;
// Open the file in read mode
FILE* file = temp_files[index].file;
if (file == NULL)
return -1;
// Read the data from the file
void* data = malloc(data_size);
if (data == NULL) {
fclose(file);
line_fail(-3);
return -1;
}
// Initialize the memory in the data buffer
memset(data, 0, data_size); // clear destination
fseek(file, offset, SEEK_SET); // set position
size_t bytes_read = fread(data, 1, data_size, file); // read bytes
memcpy(dest, data, data_size);
free(data); // Free the allocated memory
if (bytes_read != data_size) {
errno = EIO;
return -1;
}
#ifdef DEBUG
printf("Read: ID = %d, data = %016" PRIXPTR ", size = %zu -> '",
ID, (uintptr_t)dest, data_size);
for (size_t i = 0; i < data_size; i++)
printf("0x%02" PRIX8 " ", *((uint8_t*)((uint8_t*)dest + i)));
printf("'\n");
fflush(stdout);
#endif
return 0;
}
#ifdef TEST
int main(void) {
int ID = tf_alloc(4, sizeof(int));
if (ID == -1)
retreat("tf_alloc");
int test_data[4] = {123, 456, 789, -123};
for (size_t i = 0; i < 4; i++)
if (tf_write(ID, i * sizeof(int), &test_data[i], sizeof(int)) == -1)
retreat("tf_write");
// round-trip
test_data[0] = 111;
test_data[1] = 222;
test_data[2] = 333;
test_data[3] = 444;
for (size_t i = 0; i < 4; i++)
if (tf_read(ID, i * sizeof(int), &test_data[i], sizeof(int)) == -1)
retreat("tf_read");
printf("Values: %d %d %d %d\n",
test_data[0], test_data[1], test_data[2], test_data[3]);
tf_free(ID);
return 0;
}
#endif