extFS-Seyshell/src/disk.c
2026-05-24 10:44:08 +02:00

720 lines
18 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);
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);
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 check_if_name_is_already_taken(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];
char buff[MAX_INODE_NAME];
for (int i = 0; i < MAX_BYTES_PER_BLOC; i += MAX_INODE_NAME + sizeof(int)) {
strncpy(buff, &d->blocs[bloc].datas[i], MAX_INODE_NAME);
if (strcmp(buff, name) == 0) {
return 1;
}
}
return 0;
}
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, "/");
}
if (check_if_name_is_already_taken(dirname, dir_index, d)) {
dprintf(STDERR_FILENO, "touch: name '%s' is already taken \n", dirname);
return -1;
}
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, "/");
}
if (check_if_name_is_already_taken(dirname, dir_index, d)) {
dprintf(STDERR_FILENO, "mkdir: name '%s' is already taken \n", dirname);
return -1;
}
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];
int bloc = file.blocs[0];
if (file.filetype != TYPE_FILE) {
dprintf(STDERR_FILENO, "Can only write in files\n");
return;
}
if (bloc == -1)
return;
// mode 0 (on écrase tout ^^)
if (!mode) {
memset(d->blocs[bloc].datas, 0, MAX_BYTES_PER_BLOC);
if (bloc == -1) {
dprintf(STDERR_FILENO, "This inode does not have any bloc\n");
return;
}
strncpy(&d->blocs[bloc].datas[0], data, strlen(data));
} else {
int i = 0;
while (i < MAX_BYTES_PER_BLOC && d->blocs[bloc].datas[i] != '\0') {
i++;
}
if (i < MAX_BYTES_PER_BLOC) {
strncpy(&d->blocs[bloc].datas[i], data, MAX_BYTES_PER_BLOC - i - 1);
}
}
}
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);
int inodes_left = get_number_of_inode_left(d);
float space_left = (float)(free_blocs * MAX_BYTES_PER_BLOC) / 1000;
dprintf(STDOUT_FILENO,
" Free blocs : %i\n Inode left : %i\n Space left : %.2fKb\n",
free_blocs, inodes_left, space_left);
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) {
if (path_to_file == NULL) {
char buffer[1024];
while (fgets(buffer, 1024, stdin)) {
dprintf(STDOUT_FILENO, "%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;
}
dprintf(STDOUT_FILENO, "%s\n", read_in_file(disk, inode_index));
return 1;
}
int redirect_out(disk *d, int mode, char *file, int in) {
char *parent_path;
char *dirname;
if (get_name_and_parent_path_by_absolute_path(file, &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, "%s directory does not exist\n", token);
return -1;
}
if (d->inodes[dir_index].filetype != TYPE_DIRECTORY) {
dprintf(STDERR_FILENO, "%s is not a directory\n", token);
return -1;
}
token = strtok(NULL, "/");
}
char buffer[1024] = {0};
int nbytes = read(in, buffer, 1023);
if (nbytes < 0)
nbytes = 0;
buffer[nbytes] = '\0';
if (check_if_name_is_already_taken(dirname, dir_index, d)) {
write_in_file(d, find_dir_inode_by_name(dirname, dir_index, d), buffer,
mode);
} else {
int new_file_inode = create_file(d, &d->inodes[dir_index], dirname);
write_in_file(d, new_file_inode, buffer, mode);
}
persist_on_disk(d);
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!!", 0);
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");
}
}