624 lines
16 KiB
C
624 lines
16 KiB
C
/** @file */
|
|
#include "disk.h"
|
|
#include "env.h"
|
|
#include "struct.h"
|
|
#include <linux/limits.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
int init_inode_in_disk(disk *d, int inode_index, int filetype,
|
|
unsigned short perms, int owned_bloc) {
|
|
if (d->inodes[inode_index].filetype != TYPE_NULL)
|
|
return -1;
|
|
|
|
d->owned_blocs[owned_bloc] = 1;
|
|
|
|
d->inodes[inode_index].filetype = filetype;
|
|
d->inodes[inode_index].perms = perms;
|
|
|
|
for (int i = 0; i < MAX_BLOCS; i++) {
|
|
d->inodes[inode_index].blocs[i] = -1;
|
|
}
|
|
d->inodes[inode_index].blocs[0] = owned_bloc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int find_free_bloc(disk *d) {
|
|
for (int i = 0; i < MAX_BLOCS; i++) {
|
|
if (d->owned_blocs[i] == 0) {
|
|
d->owned_blocs[i] = 1;
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int find_offset_in_parent_bloc(bloc *parent_bloc) {
|
|
int entry_size = MAX_INODE_NAME + sizeof(int);
|
|
int max_entries = MAX_BYTES_PER_BLOC / entry_size;
|
|
|
|
for (int i = 0; i < max_entries; i++) {
|
|
int current_offset = i * entry_size;
|
|
// Si le premier caractère est '\0', la case est libre
|
|
if (parent_bloc->datas[current_offset] == '\0') {
|
|
return current_offset;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int is_dir_empty(disk *d, int bloc_index) {
|
|
for (int i = 0; i < MAX_BYTES_PER_BLOC; i+= MAX_INODE_NAME + sizeof(int)) {
|
|
char name[MAX_INODE_NAME];
|
|
strncpy(name, &d->blocs[bloc_index].datas[i], MAX_INODE_NAME);
|
|
if (strcmp(name, "..") != 0 && strcmp(name, ".") != 0 && name[0] != 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int is_file_empty(disk *d, int bloc_index) {
|
|
for (int i = 0; i < MAX_BYTES_PER_BLOC; i++) {
|
|
if (d->blocs[bloc_index].datas[i] != 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int allocate_node(disk *disk, inode *parent, char *name, char type) {
|
|
int inode_index = 0;
|
|
while (inode_index < MAX_INODE &&
|
|
disk->inodes[inode_index].filetype != TYPE_NULL) {
|
|
inode_index++;
|
|
}
|
|
if (inode_index >= MAX_INODE) {
|
|
dprintf(STDERR_FILENO, "No free inodes\n");
|
|
return -1;
|
|
}
|
|
|
|
int new_bloc_idx = find_free_bloc(disk);
|
|
if (new_bloc_idx == -1) {
|
|
dprintf(STDERR_FILENO, "Disk Full\n");
|
|
return -1;
|
|
}
|
|
|
|
int p_bloc_idx = parent->blocs[0];
|
|
int offset = find_offset_in_parent_bloc(&disk->blocs[p_bloc_idx]);
|
|
if (offset == -1) {
|
|
dprintf(STDERR_FILENO, "Parent directory full\n");
|
|
return -1;
|
|
}
|
|
|
|
strncpy(&disk->blocs[p_bloc_idx].datas[offset], name, MAX_INODE_NAME);
|
|
memcpy(&disk->blocs[p_bloc_idx].datas[offset + MAX_INODE_NAME], &inode_index,
|
|
sizeof(int));
|
|
|
|
init_inode_in_disk(disk, inode_index, type, 0b111111111, new_bloc_idx);
|
|
|
|
return inode_index;
|
|
}
|
|
|
|
int remove_inode(disk *disk, inode *parent, inode *inode_to_remove,
|
|
int inode_to_remove_idx) {
|
|
|
|
if (parent == inode_to_remove) {
|
|
dprintf(STDERR_FILENO, "rm: can't delete root\n");
|
|
return -1;
|
|
}
|
|
int parent_bloc_idx = parent->blocs[0];
|
|
if (parent_bloc_idx == -1) {
|
|
return -1;
|
|
}
|
|
|
|
int found = 0;
|
|
|
|
// on efface la référence de l'inode dans son parent
|
|
for (int i = 0; i < MAX_BYTES_PER_BLOC && !found;
|
|
i += MAX_INODE_NAME + sizeof(int)) {
|
|
if (*(int *)&disk->blocs[parent_bloc_idx].datas[i + MAX_INODE_NAME] ==
|
|
inode_to_remove_idx) {
|
|
memset(&disk->blocs[parent_bloc_idx].datas[i], 0,
|
|
MAX_INODE_NAME + sizeof(int));
|
|
found = 1;
|
|
}
|
|
}
|
|
|
|
// on efface tout le contenu de l'inode
|
|
int bloc_inode_idx = inode_to_remove->blocs[0];
|
|
memset(&disk->blocs[bloc_inode_idx].datas[0], 0, MAX_BYTES_PER_BLOC);
|
|
|
|
disk->owned_blocs[inode_to_remove->blocs[0]] = 0;
|
|
inode_to_remove->blocs[0] = -1;
|
|
inode_to_remove->perms = 0b000000000;
|
|
inode_to_remove->filetype = TYPE_NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int do_rmdir(disk *disk, char *filepath) {
|
|
char *parent_path = NULL;
|
|
char *dirname = NULL;
|
|
|
|
if (get_dirname_and_parent_path_by_absolute_path(filepath, &parent_path, &dirname) == -1) {
|
|
dprintf(STDERR_FILENO, "rmdir: path error\n");
|
|
return -1;
|
|
}
|
|
|
|
int parent_index = 0;
|
|
char *token = strtok(parent_path, "/");
|
|
|
|
while (token != NULL) {
|
|
parent_index = find_dir_inode_by_name(token, parent_index, disk);
|
|
|
|
if (parent_index == -1) {
|
|
dprintf(STDERR_FILENO, "rmdir: path '%s' does not exist\n", token);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
if (disk->inodes[parent_index].filetype != TYPE_DIRECTORY) {
|
|
dprintf(STDERR_FILENO, "rmdir: '%s' is not a directory\n", token);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
token = strtok(NULL, "/");
|
|
}
|
|
|
|
int file_index = find_dir_inode_by_name(dirname, parent_index, disk);
|
|
|
|
if (file_index == -1) {
|
|
dprintf(STDERR_FILENO, "rmdir: can't delete '%s': no such directory\n", dirname);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
if (disk->inodes[file_index].filetype != TYPE_DIRECTORY) {
|
|
dprintf(STDERR_FILENO, "rmdir: can't delete '%s': not a directory\n", dirname);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
if (!(is_dir_empty(disk, disk->inodes[file_index].blocs[0]) == 1)) {
|
|
dprintf(STDERR_FILENO, "rmdir: directory not empty\n");
|
|
return -1;
|
|
}
|
|
|
|
int res = remove_inode(disk, &disk->inodes[parent_index], &disk->inodes[file_index], file_index);
|
|
|
|
if (res == 1) {
|
|
} else {
|
|
dprintf(STDERR_FILENO, "rmdir: can't delete because of a fatal error\n");
|
|
}
|
|
|
|
free(parent_path);
|
|
free(dirname);
|
|
|
|
persist_on_disk(disk);
|
|
|
|
return (res == 1) ? 0 : -1;
|
|
}
|
|
|
|
int do_rm(disk *disk, char *filepath) {
|
|
char *parent_path = NULL;
|
|
char *dirname = NULL;
|
|
|
|
if (get_dirname_and_parent_path_by_absolute_path(filepath, &parent_path, &dirname) == -1) {
|
|
dprintf(STDERR_FILENO, "rm: erreur de chemin\n");
|
|
return -1;
|
|
}
|
|
|
|
int parent_index = 0;
|
|
char *token = strtok(parent_path, "/");
|
|
|
|
while (token != NULL) {
|
|
parent_index = find_dir_inode_by_name(token, parent_index, disk);
|
|
|
|
if (parent_index == -1) {
|
|
dprintf(STDERR_FILENO, "rm: path '%s' does not exist\n", token);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
if (disk->inodes[parent_index].filetype != TYPE_DIRECTORY) {
|
|
dprintf(STDERR_FILENO, "rm: '%s' is not a directory\n", token);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
token = strtok(NULL, "/");
|
|
}
|
|
|
|
int file_index = find_dir_inode_by_name(dirname, parent_index, disk);
|
|
|
|
if (file_index == -1) {
|
|
dprintf(STDERR_FILENO, "rm: can't delete '%s': no such file\n", dirname);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
if (disk->inodes[file_index].filetype != TYPE_FILE &&
|
|
disk->inodes[file_index].filetype != TYPE_SYMBOLIC_LINK) {
|
|
dprintf(STDERR_FILENO, "rm: can't delete '%s': not a file\n", dirname);
|
|
free(parent_path); free(dirname);
|
|
return -1;
|
|
}
|
|
|
|
int res = remove_inode(disk, &disk->inodes[parent_index], &disk->inodes[file_index], file_index);
|
|
|
|
if (res == 1) {
|
|
} else {
|
|
dprintf(STDERR_FILENO, "rm: can't delete because of a fatal error\n");
|
|
}
|
|
|
|
free(parent_path);
|
|
free(dirname);
|
|
|
|
persist_on_disk(disk);
|
|
|
|
return (res == 1) ? 0 : -1;
|
|
}
|
|
|
|
int create_file(disk *disk, inode *parent, char *filename) {
|
|
return allocate_node(disk, parent, filename, TYPE_FILE);
|
|
}
|
|
|
|
int create_directory(disk *disk, inode *parent, char *dirname) {
|
|
int new_idx = allocate_node(disk, parent, dirname, TYPE_DIRECTORY);
|
|
|
|
if (new_idx == -1)
|
|
return -1;
|
|
|
|
int bloc_idx = disk->inodes[new_idx].blocs[0];
|
|
int entry_size = MAX_INODE_NAME + sizeof(int);
|
|
int p_idx = (int)(parent - disk->inodes);
|
|
|
|
strncpy(&disk->blocs[bloc_idx].datas[0], ".", MAX_INODE_NAME);
|
|
memcpy(&disk->blocs[bloc_idx].datas[MAX_INODE_NAME], &new_idx, sizeof(int));
|
|
|
|
strncpy(&disk->blocs[bloc_idx].datas[entry_size], "..", MAX_INODE_NAME);
|
|
memcpy(&disk->blocs[bloc_idx].datas[entry_size + MAX_INODE_NAME], &p_idx,
|
|
sizeof(int));
|
|
|
|
return new_idx;
|
|
}
|
|
|
|
int do_touch(disk *d, char *filepath) {
|
|
char *parent_path;
|
|
char *dirname;
|
|
|
|
if (get_name_and_parent_path_by_absolute_path(filepath, &parent_path,
|
|
&dirname) == -1) {
|
|
dprintf(STDERR_FILENO, "touch: erreur jsp\n");
|
|
return -1;
|
|
}
|
|
|
|
char *token = strtok(parent_path, "/");
|
|
int dir_index = 0;
|
|
|
|
while (token != NULL) {
|
|
|
|
dir_index = find_dir_inode_by_name(token, dir_index, d);
|
|
|
|
if (dir_index == -1) {
|
|
dprintf(STDERR_FILENO, "touch: %s file does not exist\n", token);
|
|
return -1;
|
|
}
|
|
|
|
if (d->inodes[dir_index].filetype != TYPE_DIRECTORY) {
|
|
dprintf(STDERR_FILENO, "touch: %s is not a directory\n", token);
|
|
return -1;
|
|
}
|
|
|
|
token = strtok(NULL, "/");
|
|
}
|
|
|
|
create_file(d, &d->inodes[dir_index], dirname);
|
|
return 0;
|
|
}
|
|
|
|
int do_mkdir(disk *d, char *dirpath) {
|
|
char *parent_path;
|
|
char *dirname;
|
|
|
|
if (get_name_and_parent_path_by_absolute_path(dirpath, &parent_path,
|
|
&dirname) == -1) {
|
|
dprintf(STDERR_FILENO, "mkdir: erreur jsp");
|
|
return -1;
|
|
}
|
|
|
|
char *token = strtok(parent_path, "/");
|
|
int dir_index = 0;
|
|
|
|
while (token != NULL) {
|
|
|
|
dir_index = find_dir_inode_by_name(token, dir_index, d);
|
|
|
|
if (dir_index == -1) {
|
|
dprintf(STDERR_FILENO, "mkdir: %s directory does not exist\n", token);
|
|
return -1;
|
|
}
|
|
|
|
if (d->inodes[dir_index].filetype != TYPE_DIRECTORY) {
|
|
dprintf(STDERR_FILENO, "mkdir: %s is not a directory\n", token);
|
|
return -1;
|
|
}
|
|
|
|
token = strtok(NULL, "/");
|
|
}
|
|
|
|
create_directory(d, &d->inodes[dir_index], dirname);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void write_in_file(disk *d, int file_index, char *data /*, char mode*/) {
|
|
inode file = d->inodes[file_index];
|
|
if (file.filetype != TYPE_FILE) {
|
|
dprintf(STDERR_FILENO, "Can only write in files\n");
|
|
return;
|
|
}
|
|
|
|
// mode 'w' (on écrase tout ^^)
|
|
// les blocs sont possédés par un seul inode donc c'est ok de tout écraser
|
|
// TODO: regarder si l'inode est sur plusieurs blocs et écraser tous les blocs
|
|
// possédé
|
|
|
|
int bloc_index_to_overwrite = file.blocs[0];
|
|
if (bloc_index_to_overwrite == -1) {
|
|
dprintf(STDERR_FILENO, "This inode does not have any bloc\n");
|
|
return;
|
|
}
|
|
|
|
strncpy(&d->blocs[bloc_index_to_overwrite].datas[0], data, strlen(data));
|
|
}
|
|
|
|
int get_number_of_free_blocs(disk *d) {
|
|
int out = 0;
|
|
for (int i = 0; i < MAX_BLOCS; i++) {
|
|
if (d->owned_blocs[i] == 0) {
|
|
out++;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
int get_number_of_inode_left(disk *d) {
|
|
int out = 0;
|
|
for (int i = 0; i < MAX_INODE; i++) {
|
|
if (d->inodes[i].filetype == TYPE_NULL) {
|
|
out++;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
int do_df(disk *d) {
|
|
int free_blocs = get_number_of_free_blocs(d);
|
|
printf(" Free blocs : %i\n", free_blocs);
|
|
printf(" Inode left : %i\n", get_number_of_inode_left(d));
|
|
// N'est pas la taille réelle à proprement parlé mais plutot l'espace
|
|
// possiblement occupable par le reste d'inode sur le disque
|
|
printf(" Space left : %.2fKb\n",
|
|
(float)(free_blocs * MAX_BYTES_PER_BLOC) / 1000);
|
|
return 0;
|
|
}
|
|
|
|
int find_dir_inode_by_name(char *name, int dir_index, disk *d) {
|
|
if (dir_index < 0 || dir_index >= MAX_INODE)
|
|
return -1;
|
|
|
|
int bloc = d->inodes[dir_index].blocs[0];
|
|
|
|
for (int i = 0; i < MAX_BYTES_PER_BLOC; i += MAX_INODE_NAME + sizeof(int)) {
|
|
char inode_name[MAX_INODE_NAME];
|
|
strncpy(inode_name, &d->blocs[bloc].datas[i], MAX_INODE_NAME);
|
|
if (strcmp(name, inode_name) == 0) {
|
|
int inode_id;
|
|
memcpy(&inode_id, &d->blocs[bloc].datas[i + MAX_INODE_NAME], sizeof(int));
|
|
return inode_id;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int do_ls(disk *d, char *path) {
|
|
|
|
char *path_to_process = malloc(1024);
|
|
if (path_to_process == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (path == NULL) {
|
|
path = strdup(get_env_value("PWD"));
|
|
}
|
|
|
|
format_path(path_to_process, path, 1024);
|
|
|
|
int dir_index = 0;
|
|
char *token = strtok(path_to_process, "/");
|
|
|
|
while (token != NULL) {
|
|
dir_index = find_dir_inode_by_name(token, dir_index, d);
|
|
|
|
if (dir_index == -1) {
|
|
dprintf(STDERR_FILENO, "ls: This directory does not exist\n");
|
|
free(path_to_process);
|
|
return -1;
|
|
}
|
|
|
|
if (d->inodes[dir_index].filetype != TYPE_DIRECTORY) {
|
|
dprintf(STDERR_FILENO, "ls: '%s' is not a directory\n", token);
|
|
free(path_to_process);
|
|
return -1;
|
|
}
|
|
|
|
token = strtok(NULL, "/");
|
|
}
|
|
|
|
inode dir_to_list = d->inodes[dir_index];
|
|
int bloc = dir_to_list.blocs[0];
|
|
|
|
if (bloc == -1) {
|
|
free(path_to_process);
|
|
return 1;
|
|
}
|
|
|
|
for (int i = 0; i < MAX_BYTES_PER_BLOC; i += MAX_INODE_NAME + sizeof(int)) {
|
|
if (d->blocs[bloc].datas[i] != '\0') {
|
|
int inode_id;
|
|
memcpy(&inode_id, &d->blocs[bloc].datas[i + MAX_INODE_NAME], sizeof(int));
|
|
dprintf(STDOUT_FILENO, "%s%-16s %s%d\n",
|
|
d->inodes[inode_id].filetype == TYPE_FILE ? COLOR_GREEN
|
|
: COLOR_BLUE,
|
|
&d->blocs[bloc].datas[i], ESCAPE_COLOR, inode_id);
|
|
}
|
|
}
|
|
|
|
free(path_to_process);
|
|
return 1;
|
|
}
|
|
|
|
char *read_in_file(disk *d, int file_index) {
|
|
inode file = d->inodes[file_index];
|
|
if (file.filetype != TYPE_FILE) {
|
|
dprintf(STDERR_FILENO, "Can only read in files\n");
|
|
return NULL;
|
|
}
|
|
|
|
// TODO: chercher sur tous les blocs possédés
|
|
int bloc = file.blocs[0];
|
|
char *out;
|
|
int c_index = 0;
|
|
while (d->blocs[bloc].datas[c_index] != '\0' ||
|
|
c_index < MAX_BYTES_PER_BLOC) {
|
|
c_index++;
|
|
}
|
|
|
|
out = malloc(c_index * sizeof(char));
|
|
if (out == NULL) {
|
|
dprintf(STDERR_FILENO, "Error while allocating with malloc\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
strncpy(out, d->blocs[bloc].datas, c_index);
|
|
|
|
return out;
|
|
}
|
|
|
|
int do_cat(disk *disk, char* path_to_file) {
|
|
(void)disk;
|
|
(void)path_to_file;
|
|
|
|
if (path_to_file == NULL) {
|
|
char buffer[4096];
|
|
|
|
while (fgets(buffer, 4096, stdin)) {
|
|
fprintf(stdout, "%s", buffer);
|
|
}
|
|
}
|
|
|
|
char full_path[1024] = {0};
|
|
|
|
format_path(full_path, path_to_file, 1024);
|
|
|
|
char *path_tmp = strdup(full_path);
|
|
int inode_index = 0;
|
|
char *token = strtok(path_tmp, "/");
|
|
|
|
while (token != NULL) {
|
|
inode_index = find_dir_inode_by_name(token, inode_index, disk);
|
|
|
|
token = strtok(NULL, "/");
|
|
}
|
|
|
|
if (disk->inodes[inode_index].filetype == TYPE_DIRECTORY) {
|
|
dprintf(STDERR_FILENO, "cat: '%s' is a directory\n", full_path);
|
|
return -1;
|
|
}
|
|
|
|
printf("%s\n", read_in_file(disk, inode_index));
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* @brief Créer un fichier "disk" de taille MAX_BYTES_PER_BLOC * MAX_BLOCS,
|
|
* renvoi ce disque
|
|
* @return Le disque créé
|
|
*/
|
|
disk create_disk() {
|
|
FILE *fptr;
|
|
fptr = fopen("disk", "wb");
|
|
|
|
disk d;
|
|
for (int i = 0; i < MAX_INODE; i++) {
|
|
d.inodes[i].filetype = TYPE_NULL;
|
|
d.inodes[i].perms = 0b000000000;
|
|
for (int j = 0; j < MAX_BLOCS; j++) {
|
|
d.inodes[i].blocs[j] = -1;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < MAX_BLOCS; i++) {
|
|
d.owned_blocs[i] = 0;
|
|
}
|
|
|
|
int root_inode = 0;
|
|
|
|
// création de la racine '/'
|
|
d.inodes[root_inode].filetype = TYPE_DIRECTORY;
|
|
d.inodes[root_inode].perms = 0b111111111; // tlm fait ce qu'il veut
|
|
d.inodes[root_inode].blocs[0] = 0; // utilise le bloc 0
|
|
d.owned_blocs[root_inode] = 1; // le bloc 1 est maintenant occupé
|
|
|
|
// création de '.' dans '/'
|
|
strncpy(&d.blocs[0].datas[0], ".", MAX_INODE_NAME);
|
|
memcpy(&d.blocs[0].datas[MAX_INODE_NAME], &root_inode, sizeof(int));
|
|
|
|
// création de '..' dans '/'
|
|
strncpy(&d.blocs[0].datas[MAX_INODE_NAME + sizeof(int)], "..", MAX_INODE_NAME);
|
|
memcpy(&d.blocs[0].datas[2*(MAX_INODE_NAME) + sizeof(int)], &root_inode, sizeof(int));
|
|
|
|
int test_file_inode = create_file(&d, &d.inodes[0], "test");
|
|
write_in_file(&d, test_file_inode, "coucou petit\ntest!!");
|
|
|
|
int n = fwrite(&d, sizeof(disk), 1, fptr);
|
|
if (n == 1) {
|
|
dprintf(STDOUT_FILENO, "Disk of size %.2fKb created successfully.\n",
|
|
(float)(MAX_BYTES_PER_BLOC * MAX_BLOCS) / 1000);
|
|
}
|
|
|
|
fclose(fptr);
|
|
return d;
|
|
}
|
|
|
|
/**
|
|
* @brief Si un fichier filename existe, alors on le lit et le stocke en mémoire
|
|
* @param char *filename Le nom du fichier à lire
|
|
* @return Le disque lu
|
|
*/
|
|
disk open_disk(char *filename) {
|
|
disk d;
|
|
FILE *fptr = fopen(filename, "r");
|
|
if (fptr == NULL)
|
|
exit(EXIT_FAILURE);
|
|
fread(&d, sizeof(d), 1, fptr);
|
|
fclose(fptr);
|
|
return d;
|
|
}
|
|
|
|
void persist_on_disk(disk *d) {
|
|
FILE *fptr;
|
|
fptr = fopen("disk", "wb");
|
|
|
|
int n = fwrite(d, sizeof(disk), 1, fptr);
|
|
if (n != 1) {
|
|
dprintf(STDERR_FILENO, "Failed to persist datas on disk.\n");
|
|
}
|
|
} |