/* 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 167, function fread() */ #include #include #include #include #include #include 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); #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 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) 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_%zu.tmp", 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 and file path temp_file->ID = num_temp_files; temp_file->file_path = strdup(file_path); temp_file->file = file; // Increase the number of temp files num_temp_files++; // Reallocate memory for the temp_files array temp_files = realloc(temp_files, num_temp_files * sizeof(TempFile)); if (temp_files == NULL) { line_fail(-2); return -1; } // Add the temp file to the array temp_files[num_temp_files - 1] = *temp_file; 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; 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"); #endif return 0; } #define retreat(s) do { \ perror(s); \ exit(EXIT_FAILURE); \ } while (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