shell and ls command
This commit is contained in:
parent
ba12753402
commit
a43436b20b
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
|||||||
NAME := seyshell
|
NAME := seyshell
|
||||||
DRIVE := disk
|
DRIVE := disk
|
||||||
CC := gcc
|
CC := gcc
|
||||||
CFLAGS :=
|
CFLAGS := -Wall -Wextra -Werror -g
|
||||||
OBJ_DIR := obj
|
OBJ_DIR := obj
|
||||||
SRC_DIR := src
|
SRC_DIR := src
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,5 @@
|
|||||||
|
|
||||||
#define TYPE_NULL 0
|
#define TYPE_NULL 0
|
||||||
#define TYPE_FILE 1
|
#define TYPE_FILE 1
|
||||||
#define TYPE_BINARY 2
|
|
||||||
#define TYPE_DIRECTORY 3
|
#define TYPE_DIRECTORY 3
|
||||||
#define TYPE_SYMBOLIC_LINK 4
|
#define TYPE_SYMBOLIC_LINK 4
|
||||||
131
src/disk.c
131
src/disk.c
@ -1,5 +1,6 @@
|
|||||||
/** @file */
|
/** @file */
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
|
#include "env.h"
|
||||||
#include "struct.h"
|
#include "struct.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -48,15 +49,12 @@ int find_offset_in_parent_bloc(bloc *parent_bloc) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_directory(disk *disk, inode *parent, char *dirname) {}
|
int allocate_node(disk *disk, inode *parent, char *name, char type) {
|
||||||
|
|
||||||
int create_file(disk *disk, inode *parent, char *filename) {
|
|
||||||
int inode_index = 0;
|
int inode_index = 0;
|
||||||
while (inode_index < MAX_INODE &&
|
while (inode_index < MAX_INODE &&
|
||||||
disk->inodes[inode_index].filetype != TYPE_NULL) {
|
disk->inodes[inode_index].filetype != TYPE_NULL) {
|
||||||
inode_index++;
|
inode_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inode_index >= MAX_INODE) {
|
if (inode_index >= MAX_INODE) {
|
||||||
dprintf(STDERR_FILENO, "No free inodes\n");
|
dprintf(STDERR_FILENO, "No free inodes\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -70,46 +68,42 @@ int create_file(disk *disk, inode *parent, char *filename) {
|
|||||||
|
|
||||||
int p_bloc_idx = parent->blocs[0];
|
int p_bloc_idx = parent->blocs[0];
|
||||||
int offset = find_offset_in_parent_bloc(&disk->blocs[p_bloc_idx]);
|
int offset = find_offset_in_parent_bloc(&disk->blocs[p_bloc_idx]);
|
||||||
|
|
||||||
if (offset == -1) {
|
if (offset == -1) {
|
||||||
dprintf(STDERR_FILENO, "Parent directory full\n");
|
dprintf(STDERR_FILENO, "Parent directory full\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(&disk->blocs[p_bloc_idx].datas[offset], filename, MAX_INODE_NAME);
|
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,
|
memcpy(&disk->blocs[p_bloc_idx].datas[offset + MAX_INODE_NAME], &inode_index,
|
||||||
sizeof(int));
|
sizeof(int));
|
||||||
|
|
||||||
init_inode_in_disk(disk, inode_index, TYPE_FILE, 0b111111111, new_bloc_idx);
|
init_inode_in_disk(disk, inode_index, type, 0b111111111, new_bloc_idx);
|
||||||
|
|
||||||
return inode_index;
|
return inode_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_inode(disk *disk, inode *parent, char inode_type, char *name) {
|
int create_file(disk *disk, inode *parent, char *filename) {
|
||||||
if (strlen(name) > MAX_INODE_NAME) {
|
return allocate_node(disk, parent, filename, TYPE_FILE);
|
||||||
dprintf(STDERR_FILENO, "A inode name must be < %d\n", MAX_INODE_NAME);
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (parent->filetype != TYPE_DIRECTORY) {
|
|
||||||
dprintf(STDERR_FILENO, "A parent's inode must be a directory!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (inode_type) {
|
int create_directory(disk *disk, inode *parent, char *dirname) {
|
||||||
case TYPE_DIRECTORY:
|
int new_idx = allocate_node(disk, parent, dirname, TYPE_DIRECTORY);
|
||||||
return create_directory(disk, parent, name);
|
|
||||||
break;
|
if (new_idx == -1)
|
||||||
case TYPE_FILE:
|
|
||||||
return create_file(disk, parent, name);
|
|
||||||
case TYPE_BINARY:
|
|
||||||
// TODO plus tard
|
|
||||||
break;
|
|
||||||
case TYPE_SYMBOLIC_LINK:
|
|
||||||
// TODO plus tard
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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*/) {
|
||||||
@ -133,15 +127,60 @@ void write_in_file(disk *d, int file_index, char *data /*, char mode*/) {
|
|||||||
strncpy(&d->blocs[bloc_index_to_overwrite].datas[0], data, strlen(data));
|
strncpy(&d->blocs[bloc_index_to_overwrite].datas[0], data, strlen(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_ls(disk *d, int dir_index) {
|
int find_dir_inode_by_name(char *name, int dir_index, disk *d) {
|
||||||
inode dir = d->inodes[dir_index];
|
|
||||||
if (dir.filetype != TYPE_DIRECTORY) {
|
int bloc = d->inodes[dir_index].blocs[0];
|
||||||
dprintf(STDERR_FILENO, "ls: Can only list in directories\n");
|
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: chercher sur tous les blocs possédés
|
return -1;
|
||||||
int bloc = dir.blocs[0];
|
}
|
||||||
|
|
||||||
|
int do_ls(disk *d, char *path) {
|
||||||
|
char *path_to_process;
|
||||||
|
|
||||||
|
if (path == NULL) {
|
||||||
|
path_to_process = strdup(get_env_value("PWD"));
|
||||||
|
} else {
|
||||||
|
path_to_process = strdup(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)) {
|
for (int i = 0; i < MAX_BYTES_PER_BLOC; i += MAX_INODE_NAME + sizeof(int)) {
|
||||||
if (d->blocs[bloc].datas[i] != '\0') {
|
if (d->blocs[bloc].datas[i] != '\0') {
|
||||||
@ -150,6 +189,9 @@ void do_ls(disk *d, int dir_index) {
|
|||||||
dprintf(STDOUT_FILENO, "%-16s %d\n", &d->blocs[bloc].datas[i], inode_id);
|
dprintf(STDOUT_FILENO, "%-16s %d\n", &d->blocs[bloc].datas[i], inode_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(path_to_process);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *read_in_file(disk *d, int file_index) {
|
char *read_in_file(disk *d, int file_index) {
|
||||||
@ -163,7 +205,8 @@ char *read_in_file(disk *d, int file_index) {
|
|||||||
int bloc = file.blocs[0];
|
int bloc = file.blocs[0];
|
||||||
char *out;
|
char *out;
|
||||||
int c_index = 0;
|
int c_index = 0;
|
||||||
while (d->blocs[bloc].datas[c_index] != '\0' || c_index < MAX_BYTES_PER_BLOC) {
|
while (d->blocs[bloc].datas[c_index] != '\0' ||
|
||||||
|
c_index < MAX_BYTES_PER_BLOC) {
|
||||||
c_index++;
|
c_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,9 +221,11 @@ char *read_in_file(disk *d, int file_index) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_env_var_file(disk *d) {
|
void init_test_files(disk *d) {
|
||||||
int inode_idx = create_inode(d, &d->inodes[0], TYPE_FILE, "env");
|
int inode_idx = create_file(d, &d->inodes[0], "test");
|
||||||
write_in_file(d, inode_idx, "PWD=/\nUSER=user");
|
write_in_file(d, inode_idx, "Contenu du fichier :)\n");
|
||||||
|
int dir_idx = create_directory(d, &d->inodes[0], "dir");
|
||||||
|
create_file(d, &d->inodes[dir_idx], "test1");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -211,7 +256,7 @@ disk create_disk() {
|
|||||||
d.inodes[0].blocs[0] = 0; // utilise le bloc 0
|
d.inodes[0].blocs[0] = 0; // utilise le bloc 0
|
||||||
d.owned_blocs[0] = 1; // le bloc 1 est maintenant occupé
|
d.owned_blocs[0] = 1; // le bloc 1 est maintenant occupé
|
||||||
|
|
||||||
init_env_var_file(&d);
|
init_test_files(&d);
|
||||||
|
|
||||||
int n = fwrite(&d, sizeof(disk), 1, fptr);
|
int n = fwrite(&d, sizeof(disk), 1, fptr);
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
|
|||||||
@ -5,7 +5,8 @@
|
|||||||
#include "const.h"
|
#include "const.h"
|
||||||
#include "struct.h"
|
#include "struct.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "env.h"
|
||||||
|
|
||||||
disk create_disk();
|
disk create_disk();
|
||||||
disk open_disk(char* filename);
|
disk open_disk(char* filename);
|
||||||
void do_ls(disk *d, int dir_index);
|
int do_ls(disk *d, char* path);
|
||||||
47
src/env.c
Normal file
47
src/env.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "env.h"
|
||||||
|
|
||||||
|
env *init_envs() {
|
||||||
|
env *envs = malloc(sizeof(env) * 3);
|
||||||
|
|
||||||
|
if (envs == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
envs[0].key = "PWD";
|
||||||
|
envs[0].value = "/";
|
||||||
|
|
||||||
|
envs[1].key = "USER";
|
||||||
|
envs[1].value = "guams";
|
||||||
|
|
||||||
|
envs[2].key = "HOST";
|
||||||
|
envs[2].value = "tartempion";
|
||||||
|
|
||||||
|
return envs;
|
||||||
|
}
|
||||||
|
|
||||||
|
env *get_instance() {
|
||||||
|
static env *instance = NULL;
|
||||||
|
|
||||||
|
if (instance == NULL) {
|
||||||
|
instance = init_envs();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_env_len(env *envs) {
|
||||||
|
int i = 0;
|
||||||
|
while (envs[i].key != NULL) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_env_value(char *key) {
|
||||||
|
env *envs = get_instance();
|
||||||
|
for (int i = 0; i < get_env_len(envs); i++) {
|
||||||
|
if (strcmp(envs[i].key, key) == 0) {
|
||||||
|
return envs[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
8
src/env.h
Normal file
8
src/env.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "struct.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char* get_env_value(char* key);
|
||||||
|
int get_env_len(env *envs);
|
||||||
|
env* init_envs();
|
||||||
35
src/exec.c
35
src/exec.c
@ -1,18 +1,13 @@
|
|||||||
/** @file */
|
/** @file */
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
|
#include "disk.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// TODO : Tout ce fichier est à changer je pense
|
|
||||||
|
|
||||||
int is_builtin_cmd(char *executable) {
|
|
||||||
(void)executable;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// à changer parce que je veux pas chercher dans le PATH, je veux juste executer
|
// à changer parce que je veux pas chercher dans le PATH, je veux juste executer
|
||||||
// les futures primitives qui seront implémentées
|
// les futures primitives qui seront implémentées
|
||||||
int execute_cmd(char **args) {
|
/*int execute_cmd(char **args) {
|
||||||
if (!is_builtin_cmd(args[0])) {
|
if (!is_builtin_cmd(args[0])) {
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
@ -31,3 +26,27 @@ int execute_cmd(char **args) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int child_process_job(disk *d, char **args) {
|
||||||
|
if (strcmp("ls", args[0]) == 0) {
|
||||||
|
do_ls(d, args[1]);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int execute_cmd(disk *d, char **args) {
|
||||||
|
int pid = fork();
|
||||||
|
|
||||||
|
if (pid == 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
child_process_job(d, args);
|
||||||
|
} else {
|
||||||
|
int status;
|
||||||
|
waitpid(pid, &status, WUNTRACED);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
/** @file */
|
/** @file */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "disk.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
int is_builtin_cmd(char *executable);
|
int is_builtin_cmd(char *executable);
|
||||||
int execute_cmd(char **args);
|
int execute_cmd(disk *d, char **args);
|
||||||
11
src/main.c
11
src/main.c
@ -1,24 +1,17 @@
|
|||||||
/** @file */
|
/** @file */
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
#include "parsing.h"
|
#include "parsing.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *envp[]) {
|
int main() {
|
||||||
(void)argc;
|
|
||||||
(void)argv;
|
|
||||||
(void)envp;
|
|
||||||
|
|
||||||
// shell_loop();
|
|
||||||
|
|
||||||
disk drive;
|
disk drive;
|
||||||
if (access("disk", F_OK) == 0) {
|
if (access("disk", F_OK) == 0) {
|
||||||
drive = open_disk("disk");
|
drive = open_disk("disk");
|
||||||
do_ls(&drive, 0);
|
|
||||||
} else
|
} else
|
||||||
drive = create_disk();
|
drive = create_disk();
|
||||||
|
|
||||||
(void)drive;
|
open_seyshell(&drive);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
/** @file */
|
/** @file */
|
||||||
#include "parsing.h"
|
#include "parsing.h"
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
#include "env.h"
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -15,6 +16,8 @@
|
|||||||
char *read_line() {
|
char *read_line() {
|
||||||
char c;
|
char c;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
// buffer overflow attention
|
||||||
char *buffer = malloc(BUFSIZE * sizeof(char));
|
char *buffer = malloc(BUFSIZE * sizeof(char));
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
dprintf(STDERR_FILENO, "Line read buffer allocation error !");
|
dprintf(STDERR_FILENO, "Line read buffer allocation error !");
|
||||||
@ -70,15 +73,14 @@ char **split_line(char *line) {
|
|||||||
* @see char** split_line(char *line)
|
* @see char** split_line(char *line)
|
||||||
* @see int execute_cmd(char **args)
|
* @see int execute_cmd(char **args)
|
||||||
*/
|
*/
|
||||||
void shell_loop(void) {
|
void shell_loop(disk *disk) {
|
||||||
char *user = getenv("USER");
|
char *user = get_env_value("USER");
|
||||||
|
|
||||||
char *hostname = malloc(BUFSIZE * sizeof(char));
|
if (user == NULL) {
|
||||||
if (hostname == NULL) {
|
exit(EXIT_FAILURE);
|
||||||
dprintf(STDERR_FILENO, "Allocation error");
|
|
||||||
}
|
}
|
||||||
// sur le sgf le hostname se récupèrera pas comme ça donc à changer :)
|
|
||||||
gethostname(hostname, sizeof(hostname));
|
char *hostname = get_env_value("HOST");
|
||||||
|
|
||||||
char *line;
|
char *line;
|
||||||
char **args;
|
char **args;
|
||||||
@ -86,13 +88,19 @@ void shell_loop(void) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
// ça aussi c'est pas bien, ça sera à changer une fois le sgf fonctionnel
|
// ça aussi c'est pas bien, ça sera à changer une fois le sgf fonctionnel
|
||||||
dprintf(STDOUT_FILENO, "%s@%s %s> ", user, hostname, getenv("PWD"));
|
dprintf(STDOUT_FILENO, "%s@%s %s> ", user, hostname, get_env_value("PWD"));
|
||||||
line = read_line();
|
line = read_line();
|
||||||
args = split_line(line);
|
args = split_line(line);
|
||||||
status = execute_cmd(args);
|
status = execute_cmd(disk, args);
|
||||||
|
|
||||||
free(line);
|
free(line);
|
||||||
free(args);
|
free(args);
|
||||||
} while (status);
|
} while (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void open_seyshell(disk* disk) {
|
||||||
|
env* envs = init_envs();
|
||||||
|
shell_loop(disk);
|
||||||
|
free(envs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
/** @file */
|
/** @file */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "env.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include "struct.h"
|
||||||
|
|
||||||
void shell_loop(void);
|
void open_seyshell(disk* disk);
|
||||||
@ -2,6 +2,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
|
||||||
|
typedef struct env {
|
||||||
|
char* key;
|
||||||
|
char* value;
|
||||||
|
} env;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct inode
|
* @struct inode
|
||||||
* @brief Un inode est un fichier, il possède des permissions, un type
|
* @brief Un inode est un fichier, il possède des permissions, un type
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user