/** @file */ #include "disk.h" #include "env.h" #include "struct.h" #include #include #include #include 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"); } }