-
Florian Burgener authoredFlorian Burgener authored
Directory.c 4.50 KiB
// CAUTION : l'implémentation ne va pas fonctionner avec les records supprimés.
// Je devrais optimiser l'implémentation avec le FILE.
#include "Directory.h"
#include <openssl/sha.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Array.h"
#include "DirectoryRecord.h"
#include "BPTree.h"
static uint64_t hash_string(char *str) {
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str, strlen(str));
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_Final(hash, &sha256);
uint64_t truncated_hash = 0;
for (int i = 0; i < 8; i++) {
truncated_hash |= hash[i];
if (i != 7) {
// No shift because it is the last byte.
truncated_hash <<= 8;
}
}
return truncated_hash;
}
static long get_file_size(FILE *fp) {
fseek(fp, 0, SEEK_END);
long file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
return file_size;
}
static void rebuild_index(Directory *directory) {
FILE *fp;
fp = fopen(directory->database_filename, "rb");
if (fp == NULL) {
return;
}
long file_size = get_file_size(fp);
while (true) {
uint64_t data_ptr = (uint64_t)ftell(fp);
fseek(fp, 1, SEEK_CUR);
char phone_number[PHONE_NUMBER_MAX_LENGTH];
phone_number[PHONE_NUMBER_MAX_LENGTH - 1] = '\0';
fread(phone_number, 1, PHONE_NUMBER_MAX_LENGTH_WITHOUT_NULL_CHARACTER, fp);
BPTree_insert(directory->index, hash_string(phone_number), data_ptr);
fseek(fp, DirectoryRecord_size_on_disk() - 1 - PHONE_NUMBER_MAX_LENGTH_WITHOUT_NULL_CHARACTER, SEEK_CUR);
if (ftell(fp) == file_size) {
break;
}
}
fclose(fp);
}
Directory *Directory_init(char database_filename[100]) {
Directory *directory = (Directory *)malloc(sizeof(Directory));
strcpy(directory->database_filename, database_filename);
directory->index = BPTree_init(DEFAULT_ORDER);
rebuild_index(directory);
BPTree_print(directory->index, 0);
return directory;
}
void Directory_destroy(Directory **directory) {
BPTree_destroy(&(*directory)->index);
free(*directory);
*directory = NULL;
}
void Directory_print(Directory *directory) {
FILE *fp;
fp = fopen(directory->database_filename, "rb");
if (fp == NULL) {
printf("===>The directory is empty.\n");
}
long file_size = get_file_size(fp);
printf("========================\n");
while (true) {
ByteArray *byte_array = ByteArray_init(DirectoryRecord_size_on_disk());
fread(byte_array->items, 1, DirectoryRecord_size_on_disk(), fp);
byte_array->size = DirectoryRecord_size_on_disk();
DirectoryRecord *record = ByteArray_to_DirectoryRecord(byte_array);
DirectoryRecord_print(record);
DirectoryRecord_destroy(&record);
ByteArray_destroy(&byte_array);
if (ftell(fp) == file_size) {
break;
} else {
printf("------------------------\n");
}
}
printf("========================\n");
fclose(fp);
}
bool Directory_append(Directory *directory, DirectoryRecord *record) {
uint64_t a;
if (BPTree_search(directory->index, hash_string(record->phone_number), &a)) {
return false;
}
// Writes the record to the file.
FILE *fp;
fp = fopen(directory->database_filename, "a+b");
if (fp == NULL) {
exit(EXIT_FAILURE);
}
ByteArray *byte_array = DirectoryRecord_to_ByteArray(record);
fwrite(byte_array->items, 1, byte_array->size, fp);
ByteArray_destroy(&byte_array);
uint64_t data_ptr = (uint64_t)ftell(fp) - DirectoryRecord_size_on_disk();
fclose(fp);
BPTree_insert(directory->index, hash_string(record->phone_number), data_ptr);
return true;
}
DirectoryRecord *Directory_search(Directory *directory, char phone_number[11]) {
uint64_t data_ptr;
if (BPTree_search(directory->index, hash_string(phone_number), &data_ptr)) {
FILE *fp;
fp = fopen(directory->database_filename, "rb");
if (fp == NULL) {
exit(EXIT_FAILURE);
}
fseek(fp, data_ptr, SEEK_SET);
ByteArray *byte_array = ByteArray_init(DirectoryRecord_size_on_disk());
fread(byte_array->items, 1, DirectoryRecord_size_on_disk(), fp);
byte_array->size = DirectoryRecord_size_on_disk();
fclose(fp);
DirectoryRecord *record = ByteArray_to_DirectoryRecord(byte_array);
ByteArray_destroy(&byte_array);
return record;
}
return NULL;
}