add: redirect outuput to file
This commit is contained in:
parent
bc6ed93ad8
commit
3a5b0b86b7
@ -10,10 +10,13 @@ make all
|
||||
## Les différentes commandes
|
||||
|
||||
* mkdir <nom-du-répertoire>
|
||||
* touch <nom-u-fichier>
|
||||
* touch <nom-du-fichier>
|
||||
* cd <nom-du-répertoire>
|
||||
* cat
|
||||
* echo
|
||||
* df
|
||||
* rm <nom-du-fichier>
|
||||
* rmdir <nom-du-répertoire>
|
||||
|
||||
## Les fichiers
|
||||
|
||||
|
||||
231
docs/compte_rendus/compte_rendu_final.md
Normal file
231
docs/compte_rendus/compte_rendu_final.md
Normal file
@ -0,0 +1,231 @@
|
||||
---
|
||||
title: "Rapport final"
|
||||
subtitle: "Projet Système 2025/2026 – Système de Gestion de Fichiers (SGF)"
|
||||
geometry: margin=25mm
|
||||
header-includes:
|
||||
- \usepackage{fancyhdr}
|
||||
- \pagestyle{fancy}
|
||||
- \fancyhead[L]{Projet Système 2025/2026}
|
||||
- \fancyhead[R]{\includegraphics[width=2cm]{../img/logo_isty.png}}
|
||||
- \fancyfoot[C]{\thepage}
|
||||
- \setkeys{Gin}{width=\textwidth}
|
||||
---
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
\begin{flushleft}
|
||||
\small
|
||||
\textbf{Auteurs :} \\
|
||||
• CHOISY Alexis \\
|
||||
• DEGAT Teddy \\
|
||||
• DA SILVA FERREIRA Lucas \\
|
||||
• FOURNIE Baptiste \\
|
||||
• FATIHI Youssef
|
||||
\end{flushleft}
|
||||
|
||||
\vspace{1cm}
|
||||
|
||||
# Sommaire
|
||||
- [I. Introduction](#intro)
|
||||
- [II. Explication du travail réalisé](#travail)
|
||||
- [III. Points à améliorer](#ameliorer)
|
||||
- [IV. Conclusion](#conclusion)
|
||||
|
||||
# I. Introduction {#intro}
|
||||
|
||||
Ce projet consiste à réaliser un SGF (Système de Gestion de Fichier) dans le cadre d'un projet.
|
||||
|
||||
Le cahier des charges impose la réalisation de ce SGF en se basant sur un système d'inode et de blocs stockés (ext3fs ou ext4fs) sur un volume afin de persister les données.
|
||||
|
||||
Ce rapport a pour but de montrer l'avancement du projet, notamment concernant la conception et l'explication du fonctionnement des primitives du SGF.
|
||||
|
||||
# II. Explication du travail réalisé {#travail}
|
||||
|
||||
## 2.1 Fonctionnement général du shell
|
||||
|
||||
Le projet se décompose en deux modules :
|
||||
|
||||
* Le SGF qui permet d'intéragir avec le disque
|
||||
* Le Shell qui sert d'interface avec le SGF, il s'agit d'appeler des primitives système grâce à des commandes
|
||||
|
||||
|
||||
{width=80%}
|
||||
|
||||
|
||||
Le travail du Shell se décompose en plusieurs étapes :
|
||||
|
||||
* Lire les entrées utilisateur
|
||||
* Formater l'entrée utilisateur
|
||||
* Exécuter la commande associée à l'entrée utilisateur (en faisant appel à des primitives du SGF)
|
||||
|
||||
|
||||
## 2.2 Fonctionnement général du SGF
|
||||
|
||||
Le SGF propose des primitives système afin de communiquer avec le disque comme :
|
||||
|
||||
* `create_file()`
|
||||
* `create_directory()`
|
||||
* `write_in_file()`
|
||||
* `read_in_file()`
|
||||
* `remove_inode()`
|
||||
|
||||
Dans un SGF type `ext4` le disque structure l'information sous forme d'inode et de blocs
|
||||
|
||||
* Un inode définit un fichier, un dossier ou bien un lien symbolique, il possède des permissions et pointe sur un bloc de donnée.
|
||||
* Un bloc définit de la donnée brut, c'est un espace mémoire possédé par un inode et celui-ci est libre d'écrire ce qu'il veut dans cet espace
|
||||
```c
|
||||
typedef struct inode {
|
||||
unsigned short perms; // rwxrwxrwx
|
||||
char filetype;
|
||||
int blocs[MAX_BLOCS];
|
||||
} inode;
|
||||
|
||||
typedef struct bloc {
|
||||
char datas[MAX_BYTES_PER_BLOC];
|
||||
} bloc;
|
||||
|
||||
typedef struct disk {
|
||||
char owned_blocs[MAX_BLOCS]; // 1 si possédé par un inode, 0 si libre
|
||||
inode inodes[MAX_INODE];
|
||||
bloc blocs[MAX_BLOCS];
|
||||
} disk;
|
||||
```
|
||||
|
||||
Dans le cas de notre projet, le disque est représenté sous forme de fichier.
|
||||
|
||||
## 2.3 Création du disque
|
||||
|
||||
Le processus de création du disque est réalisé grâce à un dump des données de la structure `disk` en mémoire sur un fichier intitulé `disk`.
|
||||
|
||||
On y initialise chacun des inodes à la constante `TYPE_NULL`, les blocs sont aussi initialisé à `-1`. Ensuite on créé la racine du système (`/`) et on lui alloue un bloc.
|
||||
Ensuite on initialise la racine elle-même en créant les deux dossiers `.` et `..` qui pointent sur le même répertoire (la racine).
|
||||
|
||||
|
||||
## 2.4 Création d'un fichier
|
||||
|
||||
Avant d'expliquer le fonctionnement de la primitive, il est nécessaire d'expliquer comment fonctionne un fichier dans un système ext3fs
|
||||
|
||||
{width=80%}
|
||||
|
||||
Il s'agit simplement d'un inode qui pointe sur un ou plusieur bloc de donnée (ici 128 octets). Ce bloc décrit le contenu du fichier. L'inode contient
|
||||
|
||||
* Si l'inode concerne un fichier, un répertoire ou un lien symbolique
|
||||
* les droits de l'inode concerné (droit de lecture/écriture/exécution)
|
||||
|
||||
La primitive fonctionne de la manière suivante :
|
||||
|
||||
* On trouve un bloc de donné libre
|
||||
* Une fois ce bloc trouvé, on trouve un espace libre de 32 octets (28 pour le nom du fichier et 4 pour la référence à l'index de l'inode concerné)
|
||||
|
||||
|
||||
## 2.5 Création d'un dossier
|
||||
|
||||
Premièrement il faut savoir comment se structure un dossier dans un système ext3fs
|
||||
|
||||

|
||||
|
||||
La primitive fonctionne de la manière suivante :
|
||||
|
||||
* On trouve un bloc de donné libre
|
||||
* Une fois ce bloc trouvé, on trouve un espace libre de 32 octets (28 pour le nom du fichier et 4 pour la référence à l'index de l'inode concerné)
|
||||
* On créer un dossier '.' qui pointe sur l'inode du dossier en création
|
||||
* On créer un dossier '..' qui pointe sur le parent de l'inode en création
|
||||
|
||||
à noter qu'un dossier n'est qu'un fichier qui structure l'information d'une manière différente (en faisant stockant le nom et la référence vers les inodes de ses fils)
|
||||
|
||||
## 2.6 Le nommage d'un inode
|
||||
|
||||
Un inode n'a pas de nom en soit, en fait son nom est stocké dans le parent. Et un répertoire stocke les noms des repértoires ainsi qu'une référence à chacun des inodes.s
|
||||
|
||||
Dans notre SGF, nous avons choisi de stocker les noms/référence comme la figure ci-dessous
|
||||
|
||||

|
||||
|
||||
Sur un bloc de 1024 octets ça fait 32 inodes max référencés dans le dossier.
|
||||
|
||||
## 2.7 Les commandes et leurs fonctionnement
|
||||
|
||||
### 2.7.1 La commande `cd`
|
||||
|
||||
Contrairement aux autres commandes du projet, cd est une commande assez spéciale car elle est toujours implémentée par le shell lui même et non déjà existante dans le système. En bref, elle est propre à chaque shell (bash, zsh, fish...). Dans les faits ça ne change pas grand chose mais l'implémentation n'est pas dans le fichier `disk.c` mais `exec.c` qui s'occupe de tout l'aspect exécution de commande (et non implémentation à la base).
|
||||
|
||||
Le plus long est le parsing du chemin, le fait de séparer les noms des dossiers des '/'. Par exemple pour le chemin `/dir1/dir2/` on va devoir parcourir `dir1` puis `dir2`. Pour cela, il existe une fonction `find_dir_inode_by_name()` qui comme son nom l'indique sert à retrouver un inode grâce à son nom et comme on le sait déjà, le nom d'un inode est stocké dans le/les blocs du parent.
|
||||
|
||||
En bref, on va commencer du tout début du/des blocs du parent jusqu'à trouver (ou non) le nom du dossier donnné en paramètre. Et comme les noms sont stockés de cette manière :
|
||||
|
||||
Une fois l'inode associé au nom du dernier dossier dans le chemin trouvé. on change la variable d'environnement 'PWD'.
|
||||
|
||||
|
||||
### 2.7.2 La commande `ls`
|
||||
|
||||
ls est très similaire à cd sur le fonctionnement à la seule différence que ls affiche le contenu du dossier avec l'inode associé.
|
||||
|
||||
### 2.7.3 Les commandes `mkdir` et `touch`
|
||||
|
||||
Ces deux commandes sont sensiblement les mêmes, c'est pour celà qu'elles sont dans la même section.
|
||||
|
||||
* `touch` fait appel à la primitive `create_file()` avec quelques vérification au préalable (par exemple l'emplacement dans l'arborescence pour créer le fichier)
|
||||
|
||||
`create_file()` fonctionne le manière suivante :
|
||||
|
||||
1. On essaie de trouver si il reste un inode disponible, si non on renvoit un message d'erreur
|
||||
2. On essaie de trouver si il rest un bloc disponible, si non on renvoit un message d'erreur
|
||||
3. On trouve de l'espace dans le répertoire parent pour pouvoir référencer l'inode dans l'arborescence
|
||||
4. On écrit le nom du fichier dans le répertoire parent, ses permissions, son bloc alloué et son numéro d'inode
|
||||
|
||||
En ce qui concerne `mkdir` cette commande fait appel `create_directory()` qui s'occupe de faire concrètement le même travail que `create_file()` à la seul différence que l'inode est de type `TYPE_DIRECTORY` et non de `TYPE_FILE`. (à noté que dans un système UNIX tout est fichier).
|
||||
|
||||
### 2.7.4 Les commandes `rmdir` et `rm`
|
||||
|
||||
Comme `touch` et `mkdir`, `rmdir` et `rm` sont très similaire.
|
||||
|
||||
Ces deux commandes sont encore plus similaire que les deux précédente car leurs seule différence est seulement la vérification si l'inode est un fichier ou un répertoire.
|
||||
|
||||
Ils font appel à la même primitive `remove_inode()` qui fonctionne de la manière suivante :
|
||||
|
||||
1. On vérifie si le dossier à supprimer est la racine, si oui on renvoit une erreur
|
||||
2. On efface la référence de l'inode à supprimer dans le parent
|
||||
3. On efface tout le contenu de l'inode en réinitialisant le contenu du bloc avec des 0
|
||||
4. On précise que le bloc supprimé est désormais libre
|
||||
5. On définit l'inode comme `TYPE_NULL`
|
||||
|
||||
### 2.7.5 La commande `cat`
|
||||
|
||||
`cat` permet de voir le contenu des fichiers en lui précisant le nom d'un fichier grâce à la primitive `read_in_file()`
|
||||
|
||||
cette primitive est très simple car elle se contente de lire la donnée brute du bloc et renvoyer ce contenu sous forme de `char *`.
|
||||
|
||||
Il est aussi possible de faire appel à `cat` sans spécifier de fichier, si c'est le cas alors le programme va juste écouter son entrée standard jusqu'à que l'utilisateur tue le processus grâce à un SIGINT par exemple.
|
||||
|
||||
### 2.7.6 La commande `df`
|
||||
|
||||
Cette commande affiche le nombre de bloc restant sur le disque, le nombre d'inode ainsi que l'espace de stockage restant sur le système.
|
||||
|
||||
Exemple :
|
||||
```
|
||||
iatic@tartempion /> df
|
||||
Free blocs : 28
|
||||
Inode left : 28
|
||||
Space left : 14.34Kb
|
||||
```
|
||||
|
||||
### 2.7.7 La commande `echo`
|
||||
|
||||
Comme `cd`, `echo` est une commande built-in au Shell, c'est à dire que contrairement aux autres commande, c'est une commande qui est normalement implémenté par le shell lui même et ce n'est pas un exécutable.
|
||||
|
||||
`echo` se contente de rediriger ce qu'il reçoit en argument vers sa sortie standard, il regarde au préalable si dans la chaine qu'on lui a passé, y est inclut une variable d'environnement ($PWD par exemple), si c'est le cas, il l'affiche.
|
||||
|
||||
# III. Points à améliorer {#ameliorer}
|
||||
|
||||
Bien que le SGF et son shell soient fonctionnels et respectent les primitives de base demandées, plusieurs axes d'amélioration permettront de rapprocher le système d'un comportement de type UNIX/ext4 réel :
|
||||
|
||||
* **Gestion de la mémoire et robustesse :** Actuellement, le code présente des risques de *buffer overflow*, notamment lors de la manipulation des chemins de fichiers ou des arguments dans le shell. L'utilisation systématique de fonctions sécurisées et une validation stricte de la taille des entrées utilisateur sont nécessaires pour sécuriser le système.
|
||||
* **Mise en œuvre concrète des permissions :** Bien que la structure `inode` intègre un champ `perms`, les mécanismes de vérification lors de l'appel aux primitives ne sont pas encore activés. Il faudrait l'implémenter pour interdire, par exemple, l'écriture dans un fichier en lecture seule.
|
||||
* **Système de gestion des utilisateurs :** Le SGF ne gère pour l'instant qu'un utilisateur unique (équivalent à un accès *root* permanent). L'ajout d'une table des utilisateurs, d'une commande `su`/`login` et le stockage de l'UID (User ID) dans l'inode permettraient une isolation complète des données.
|
||||
* **Allocation dynamique et fragmentation :** Actuellement, la taille des fichiers est contrainte par un nombre fixe de blocs contigus (`MAX_BLOCS`). L'introduction de pointeurs indirects dans l'inode permettrait de supporter des fichiers de taille variable et plus importante sans gaspiller l'espace disque.
|
||||
|
||||
# IV. Conclusion {#conclusion}
|
||||
|
||||
Ce projet nous a permis de concevoir et de réaliser l'architecture complète d'un Système de Gestion de Fichiers (SGF) simplifié ainsi que son interface en ligne de commande. En modélisant un disque virtuel par un simple fichier binaire, nous avons pu manipuler concrètement les concepts fondamentaux des systèmes d'exploitation : la structure et le cycle de vie des inodes, l'indexation des blocs de données, le fonctionnement interne d'un répertoire et le parsing de commandes d'un shell.
|
||||
|
||||
Malgré les limitations actuelles en termes de sécurité mémoire et de gestion des droits, le système développé offre une base solide, logique et fonctionnelle, illustrant parfaitement la maxime UNIX selon laquelle tout est fichier.
|
||||
BIN
docs/compte_rendus/compte_rendu_final.pdf
Normal file
BIN
docs/compte_rendus/compte_rendu_final.pdf
Normal file
Binary file not shown.
BIN
docs/img/illustration.png
Normal file
BIN
docs/img/illustration.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
156
src/disk.c
156
src/disk.c
@ -210,6 +210,7 @@ int do_rmdir(disk *disk, char *filepath) {
|
||||
}
|
||||
|
||||
int do_rm(disk *disk, char *filepath) {
|
||||
|
||||
char *parent_path = NULL;
|
||||
char *dirname = NULL;
|
||||
|
||||
@ -297,14 +298,14 @@ int create_directory(disk *disk, inode *parent, char *dirname) {
|
||||
return new_idx;
|
||||
}
|
||||
|
||||
int check_if_name_is_already_taken(char* name, int dir_index, disk* d) {
|
||||
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)) {
|
||||
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;
|
||||
@ -392,25 +393,35 @@ int do_mkdir(disk *d, char *dirpath) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write_in_file(disk *d, int file_index, char *data /*, char mode*/) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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");
|
||||
if (bloc == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(&d->blocs[bloc_index_to_overwrite].datas[0], data, strlen(data));
|
||||
// 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) {
|
||||
@ -603,45 +614,94 @@ int *find_all_occ_of_pattern(char *pattern, char *txt) {
|
||||
}
|
||||
|
||||
int do_grep(char *pattern) {
|
||||
char buffer[1024];
|
||||
if (pattern == NULL) {
|
||||
dprintf(STDERR_FILENO, "grep: pattern missing\n");
|
||||
return -1;
|
||||
char buffer[1024];
|
||||
if (pattern == NULL) {
|
||||
dprintf(STDERR_FILENO, "grep: pattern missing\n");
|
||||
return -1;
|
||||
}
|
||||
ssize_t n;
|
||||
while ((n = read(STDIN_FILENO, buffer, sizeof(buffer) - 1)) > 0) {
|
||||
buffer[n] = '\0';
|
||||
|
||||
int *occs = find_all_occ_of_pattern(pattern, buffer);
|
||||
|
||||
if (occs == NULL || occs[0] == -1) {
|
||||
continue;
|
||||
}
|
||||
ssize_t n;
|
||||
while ((n = read(STDIN_FILENO, buffer, sizeof(buffer) - 1)) > 0) {
|
||||
buffer[n] = '\0';
|
||||
|
||||
int *occs = find_all_occ_of_pattern(pattern, buffer);
|
||||
|
||||
if (occs == NULL || occs[0] == -1) {
|
||||
continue;
|
||||
}
|
||||
int nbr_occ = 0;
|
||||
for (nbr_occ = 0; occs[nbr_occ] != -1; nbr_occ++)
|
||||
;
|
||||
|
||||
int nbr_occ = 0;
|
||||
for (nbr_occ = 0; occs[nbr_occ] != -1; nbr_occ++);
|
||||
|
||||
int new_size = n + (nbr_occ * (strlen(COLOR_RED) + strlen(ESCAPE_COLOR)));
|
||||
char *colored_line = malloc(new_size + 1);
|
||||
|
||||
int last_pos = 0;
|
||||
colored_line[0] = '\0';
|
||||
int new_size = n + (nbr_occ * (strlen(COLOR_RED) + strlen(ESCAPE_COLOR)));
|
||||
char *colored_line = malloc(new_size + 1);
|
||||
|
||||
for (int i = 0; occs[i] != -1; i++) {
|
||||
int pos = occs[i];
|
||||
strncat(colored_line, buffer + last_pos, pos - last_pos);
|
||||
strcat(colored_line, COLOR_RED);
|
||||
strncat(colored_line, buffer + pos, strlen(pattern));
|
||||
strcat(colored_line, ESCAPE_COLOR);
|
||||
|
||||
last_pos = pos + strlen(pattern);
|
||||
}
|
||||
strcat(colored_line, buffer + last_pos);
|
||||
write(STDOUT_FILENO, colored_line, strlen(colored_line));
|
||||
free(occs);
|
||||
free(colored_line);
|
||||
int last_pos = 0;
|
||||
colored_line[0] = '\0';
|
||||
|
||||
for (int i = 0; occs[i] != -1; i++) {
|
||||
int pos = occs[i];
|
||||
strncat(colored_line, buffer + last_pos, pos - last_pos);
|
||||
strcat(colored_line, COLOR_RED);
|
||||
strncat(colored_line, buffer + pos, strlen(pattern));
|
||||
strcat(colored_line, ESCAPE_COLOR);
|
||||
|
||||
last_pos = pos + strlen(pattern);
|
||||
}
|
||||
return 1;
|
||||
strcat(colored_line, buffer + last_pos);
|
||||
write(STDOUT_FILENO, colored_line, strlen(colored_line));
|
||||
free(occs);
|
||||
free(colored_line);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -685,7 +745,7 @@ disk create_disk() {
|
||||
sizeof(int));
|
||||
|
||||
int test_file_inode = create_file(&d, &d.inodes[0], "test");
|
||||
write_in_file(&d, test_file_inode, "coucou petit\ntest!!");
|
||||
write_in_file(&d, test_file_inode, "coucou petit\ntest!!", 0);
|
||||
|
||||
int n = fwrite(&d, sizeof(disk), 1, fptr);
|
||||
if (n == 1) {
|
||||
|
||||
@ -23,4 +23,5 @@ int do_rmdir(disk *disk, char *filepath);
|
||||
int do_cat(disk *disk, char* path_to_file);
|
||||
int do_grep(char* arg);
|
||||
int find_dir_inode_by_name(char *name, int dir_index, disk *d);
|
||||
int redirect_out(disk *d, int mode, char *file, int in);
|
||||
void persist_on_disk(disk* d);
|
||||
31
src/exec.c
31
src/exec.c
@ -103,8 +103,10 @@ int exec_cmd_job(disk *d, char **args) {
|
||||
persist_on_disk(d);
|
||||
} else if (strcmp("cat", args[0]) == 0) {
|
||||
do_cat(d, args[1]);
|
||||
} else if(strcmp("grep", args[0]) == 0) {
|
||||
} else if (strcmp("grep", args[0]) == 0) {
|
||||
do_grep(args[1]);
|
||||
} else if (strcmp("echo", args[0]) == 0) {
|
||||
do_echo(&args[1]);
|
||||
} else {
|
||||
dprintf(STDERR_FILENO, "%s: command does not exist\n", args[0]);
|
||||
return 0;
|
||||
@ -128,7 +130,8 @@ int spawn_proc(disk *d, int in, int out, command *cmd) {
|
||||
close(in);
|
||||
}
|
||||
|
||||
return exec_cmd_job(d, cmd->argv);
|
||||
int ret = exec_cmd_job(d, cmd->argv);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
return pid;
|
||||
@ -136,6 +139,10 @@ int spawn_proc(disk *d, int in, int out, command *cmd) {
|
||||
|
||||
int execute_cmd(disk *d, command **args) {
|
||||
|
||||
if (strcmp(args[0]->argv[0], "cd") == 0) {
|
||||
return do_cd(d, args[0]->argv[1]);
|
||||
}
|
||||
|
||||
// cas ou l'utilisateur fait CTRD+D
|
||||
if (args == NULL) {
|
||||
dprintf(STDOUT_FILENO, "\n");
|
||||
@ -151,17 +158,29 @@ int execute_cmd(disk *d, command **args) {
|
||||
int in, p[2];
|
||||
in = 0;
|
||||
|
||||
for (i = 0; i < args_len - 2; i++) {
|
||||
for (i = 0; i < args_len - 1; i++) {
|
||||
pipe(p);
|
||||
spawn_proc(d, in, p[1], args[i]);
|
||||
close(p[1]);
|
||||
in = p[0];
|
||||
}
|
||||
|
||||
spawn_proc(d, in, STDOUT_FILENO, args[i]);
|
||||
if (args[i]->redirect_out != NULL) {
|
||||
int p_out[2];
|
||||
pipe(p_out);
|
||||
|
||||
if (in != 0) {
|
||||
close(in);
|
||||
spawn_proc(d, in, p_out[1], args[i]);
|
||||
close(p_out[1]);
|
||||
|
||||
if (in != 0)
|
||||
close(in);
|
||||
|
||||
redirect_out(d, args[i]->append_mode, args[i]->redirect_out, p_out[0]);
|
||||
close(p_out[0]);
|
||||
} else {
|
||||
spawn_proc(d, in, STDOUT_FILENO, args[i]);
|
||||
if (in != 0)
|
||||
close(in);
|
||||
}
|
||||
|
||||
int status;
|
||||
|
||||
11
src/main.c
11
src/main.c
@ -2,16 +2,19 @@
|
||||
#include "disk.h"
|
||||
#include "parsing.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int main() {
|
||||
|
||||
disk drive;
|
||||
disk *drive = mmap(NULL, sizeof(disk), PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1,
|
||||
0); // pour partager la mémoire entre le père et ses fils
|
||||
if (access("disk", F_OK) == 0) {
|
||||
drive = open_disk("disk");
|
||||
*drive = open_disk("disk");
|
||||
} else
|
||||
drive = create_disk();
|
||||
*drive = create_disk();
|
||||
|
||||
open_seyshell(&drive);
|
||||
open_seyshell(drive);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -76,18 +76,39 @@ command **split_line(char *line) {
|
||||
|
||||
cmd_lines[0] = malloc(sizeof(command));
|
||||
cmd_lines[0]->argv = malloc(sizeof(char *));
|
||||
cmd_lines[0]->redirect_out = NULL;
|
||||
cmd_lines[0]->append_mode = 0;
|
||||
|
||||
i = 0;
|
||||
int idx_cmd = 0;
|
||||
int nbr_args_in_actual_cmd = 0;
|
||||
while (args[i] != NULL) {
|
||||
if (strcmp(args[i], "|") == 0) {
|
||||
cmd_lines[idx_cmd]->argv[nbr_args_in_actual_cmd + 1] = NULL;
|
||||
cmd_lines[idx_cmd]->argv[nbr_args_in_actual_cmd] = NULL;
|
||||
|
||||
idx_cmd++;
|
||||
cmd_lines = realloc(cmd_lines, (idx_cmd + 1) * sizeof(command *));
|
||||
if (cmd_lines == NULL)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
cmd_lines[idx_cmd] = malloc(sizeof(command));
|
||||
cmd_lines[idx_cmd]->argv = malloc(sizeof(char *));
|
||||
cmd_lines[idx_cmd]->redirect_out = NULL;
|
||||
cmd_lines[idx_cmd]->append_mode = 0;
|
||||
nbr_args_in_actual_cmd = 0;
|
||||
} else {
|
||||
} else if (strcmp(args[i], ">") == 0 || strcmp(args[i], ">>") == 0) {
|
||||
cmd_lines[idx_cmd]->append_mode = (strcmp(args[i], ">>") == 0);
|
||||
|
||||
if (args[i + 1] != NULL) {
|
||||
cmd_lines[idx_cmd]->redirect_out = strdup(args[i + 1]);
|
||||
i++;
|
||||
} else {
|
||||
dprintf(STDERR_FILENO,
|
||||
"syntax error near unexpected token 'newline'\n");
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
cmd_lines[idx_cmd]->argv =
|
||||
realloc(cmd_lines[idx_cmd]->argv,
|
||||
(nbr_args_in_actual_cmd + 1) * sizeof(char *));
|
||||
@ -97,9 +118,15 @@ command **split_line(char *line) {
|
||||
|
||||
i++;
|
||||
}
|
||||
cmd_lines[idx_cmd + 1] = malloc(sizeof(command));
|
||||
cmd_lines[idx_cmd]->argv = realloc(
|
||||
cmd_lines[idx_cmd]->argv, (nbr_args_in_actual_cmd + 1) * sizeof(char *));
|
||||
cmd_lines[idx_cmd]->argv[nbr_args_in_actual_cmd] = NULL;
|
||||
|
||||
cmd_lines = realloc(cmd_lines, (idx_cmd + 2) * sizeof(command *));
|
||||
cmd_lines[idx_cmd + 1] = NULL;
|
||||
|
||||
free(args);
|
||||
|
||||
return cmd_lines;
|
||||
}
|
||||
|
||||
@ -126,7 +153,6 @@ void shell_loop(disk *disk) {
|
||||
int status = 1;
|
||||
|
||||
do {
|
||||
// ça aussi c'est pas bien, ça sera à changer une fois le sgf fonctionnel
|
||||
dprintf(STDOUT_FILENO, "%s@%s %s> ", user, hostname, get_env_value("PWD"));
|
||||
line = read_line();
|
||||
args = split_line(line);
|
||||
@ -134,7 +160,7 @@ void shell_loop(disk *disk) {
|
||||
|
||||
free(line);
|
||||
free(args);
|
||||
} while (status);
|
||||
} while (status != 67);
|
||||
}
|
||||
|
||||
void signal_handler(int sig) {
|
||||
|
||||
20
src/struct.h
20
src/struct.h
@ -2,6 +2,10 @@
|
||||
#pragma once
|
||||
#include "const.h"
|
||||
|
||||
/**
|
||||
* @struct env
|
||||
* @brief Une variable d'environnement stockée sous forme de dictionnaire
|
||||
*/
|
||||
typedef struct env {
|
||||
char* key;
|
||||
char* value;
|
||||
@ -39,14 +43,12 @@ typedef struct disk {
|
||||
// pour 10 inode qui a 30 blocs de chacun 1024 octets, on a 30720 octets, soit
|
||||
// 30,7 Ko sur le disque
|
||||
|
||||
/**
|
||||
* @struct command
|
||||
* @brief une ligne de commande et ses arguments
|
||||
*/
|
||||
typedef struct command {
|
||||
char **argv;
|
||||
} command;
|
||||
/*
|
||||
ce structure de cette façon :
|
||||
commands[0].argv[0]: ls
|
||||
commands[0].argv[1]: -l
|
||||
commands[1].argv[0]: head
|
||||
commands[2].argv[0]: tail
|
||||
commands[2].argv[1]: -4
|
||||
*/
|
||||
char *redirect_out;
|
||||
int append_mode;
|
||||
} command;
|
||||
Loading…
Reference in New Issue
Block a user