Implementación en C de Funciones de Sistema de Archivos MFS
Introducción al Código del Sistema de Archivos MFS
A continuación se presenta el código fuente en lenguaje C correspondiente a la implementación de funciones clave para la gestión de un sistema de archivos minimalista (MFS), incluyendo operaciones de escritura, resolución de rutas, obtención de inodos y lectura de directorios.
Funciones de Escritura y Gestión de Inodos
Escritura de Archivos
int mfs_write(int fd, void *buf, size_t count){
int start, not_done;
int num_block;
char block[fs->sb.block_size];
char *next;
if (fd < 0 || fd >= NUM_FILES)
return -1;
if (fs->file[fd].num == -1) {
printf("Trying to write unopened fd\n");
return -1;
}
if (count > fs->file[fd].ino.e.size * fs->sb.block_size - fs->file[fd].pos)
count = fs->file[fd].ino.e.size * fs->sb.block_size - fs->file[fd].pos;
start = fs->file[fd].pos % fs->sb.block_size;
num_block = (fs->file[fd].pos / fs->sb.block_size) + fs->file[fd].ino.e.start;
not_done = count;
next = buf;
while(not_done) {
int len;
if (not_done > fs->sb.block_size - start)
len = fs->sb.block_size - start;
else
len = not_done;
if (len != fs->sb.block_size) {
data_read(fs, block, num_block);
memcpy(block + start, next, len);
data_write(fs, block, num_block);
}
else {
data_write(fs, next, num_block);
}
num_block++;
not_done -= len;
next += len;
start = 0;
}
fs->file[fd].pos += count;
if (fs->file[fd].pos > fs->file[fd].ino.size) {
fs->file[fd].ino.size = fs->file[fd].pos;
inode_write(fs, &fs->file[fd].ino, fs->file[fd].num);
}
return count;
}Obtención de Inodos por Ruta (Path)
static int get_inodo_previo(struct file_system *fs, const char *path){
// Obtiene el inodo previo a partir del path completo
int i = 0;
int j = 0;
int inodo = -1;
int inodo_anterior = -1;
int con_dir = -1;
int path_len = strlen(path);
char *resto = malloc(sizeof(char) * path_len);
char *name = malloc(sizeof(char) * path_len);
struct disk_inode ino;
while(path[i] != '\0' && path[i] != '/'){
// Obtenemos el primer [dir1]/[dir2/archivo.1txt] de la separación de cadena
name[i] = path[i];
i++;
if(path[i] == '/')
con_dir = 0; // Si / entonces tiene path en el directorio a recorrer
name[i] = '\0'; // Vamos añadiendo \0 a la cadena para que siempre termine en algo lógico
}
i++;
while(i < strlen(path)){
resto[j] = path[i];
i++;
j++;
resto[j] = '\0';
if(path[i] == '\0')
break;
}
inodo = namei(fs, &(fs->root), name); // Obtenemos el inodo inicial del raíz
if(con_dir == -1){
return 0;
}
inodo_anterior = inodo; // Al analizar el resto la primera vez este será el inodo anterior
if(inodo == -1)
return -1; // El primer elemento del path no existe
else
while(inodo != -1){ // Existe
i = 0;
j = 0;
con_dir = -1;
inode_read(fs, &ino, inodo); // Leemos el inodo correspondiente al último inodo que obtuvimos
while(resto[i] != '\0' && resto[i] != '/'){
name[i] = resto[i];
i++;
if(resto[i] == '/')
con_dir = 0;
name[i] = '\0';
}
i++;
while(i < strlen(resto)){
resto[j] = resto[i];
i++;
j++;
if(resto[i] == '\0')
break;
}
resto[j] = '\0'; // Le damos final a la cadena resto, si no guarda basura
inodo_anterior = inodo; // El inodo anterior es justo el que tenemos antes de pasar al siguiente
inodo = namei(fs, &ino, name); // Obtenemos el nuevo inodo
if(con_dir == 0)
continue; // Si el resto tiene más /, es decir directorios por ver, se continúa
else
return inodo_anterior;
}
return inodo;
}static int get_inodo(struct file_system *fs, const char *path){
// Obtiene el inodo a partir del path completo
int i = 0;
int j = 0;
int s = 0;
int inodo = -1;
int inodo_anterior = -1;
int con_dir = -1;
int path_len = strlen(path);
char *resto = malloc(sizeof(char) * path_len);
char *name = malloc(sizeof(char) * path_len);
char *dir_anterior = malloc(sizeof(char) * path_len);
struct disk_inode ino;
while(path[i] != '\0' && path[i] != '/'){
// Mientras no sea final de path o barra /
name[i] = path[i]; // Copiamos primer elemento en name
i++;
if(path[i] == '/')
con_dir = 0; // Si lo siguiente en el path completo es una barra es que es un directorio
name[i] = '\0'; // Metemos un \0 al final de name
}
i++;
while(i < strlen(path)){
// En este while copiamos todo el resto del path completo que queda en resto
resto[j] = path[i];
i++;
j++;
resto[j] = '\0';
if(path[i] == '\0')
break;
}
if(strcmp(name, "..") == 0)
return 0; // Si nos pasan un .., estamos en el directorio anterior, aquí el raíz
inodo = namei(fs, &(fs->root), name); // Obtenemos el inodo del primer elemento del path
if(con_dir == -1)
return inodo; // Si no es un directorio devolvemos el inodo ya
inodo_anterior = inodo; // Guardamos el inodo en inodo anterior para el siguiente desglosamiento
if(inodo == -1)
return -1;
else
while(inodo != -1){
i = 0;
j = 0;
con_dir = -1;
inode_read(fs, &ino, inodo); // Leemos el número de inodo en ino
while(resto[i] != '\0' && resto[i] != '/'){
// En este while vamos a coger el segundo elemento igual que el primero
name[i] = resto[i];
i++;
if(resto[i] == '/')
con_dir = 0;
name[i] = '\0';
}
i++;
while(i < strlen(resto)){
// Copiamos el resto
resto[j] = resto[i];
i++;
j++;
if(resto[i] == '\0')
break;
}
resto[j] = '\0';
inodo_anterior = inodo; // El inodo anterior antes de pasar al siguiente inodo (Usado en "..")
inodo = namei(fs, &ino, name); // Obtenemos el inodo del segundo elemento del path
if(name[0] == '.' && name[1] == '.')
for(s = 0; s < strlen(path); s++){
if((path[s] == '/') && (path[s+1] == '.') && (path[s+2] == '.'))
return get_inodo_previo(fs, dir_anterior); // Si el último es .. devolvemos el inodo del penúltimo
dir_anterior[s] = path[s]; // En dir_anterior guardamos el elemento anterior del path
}
if(name[0] == '.' && name[1] == '\0')
return inodo_anterior; // Si estamos en el . devolvemos el anterior
if(con_dir == 0)
continue; // Si sigue habiendo directorios continuamos desglosando
else
return inodo; // Si no, devolvemos el inodo
}
return inodo;
}Verificación y Manipulación de Directorios
Comprobación de Directorio
static int is_dir(struct file_system *fs, struct disk_inode *d, const char *directory){
// Dado un directorio comprueba si es un directorio en la lista de inodos actual
char block[fs->sb.block_size];
struct entry *dir = (struct entry *)block;
int r = 0;
int i, j;
if(directory[0] == '.' && directory[1] == '\0')
return 1; // Si es un . es directorio
for (i = 0; i < d->e.size; i++) {
data_read(fs, block, d->e.start + i);
for (j = 0; j < fs->sb.block_size / sizeof(struct entry); j++){
if (dir[j].inode != -1 && strncmp(directory, dir[j].name, ENTRY_SIZE) == 0){
if(dir[j].is_dir == 0)
r = 1;
}
}
}
return r;
}Apertura y Lectura de Directorios
struct mfs_dir *mfs_opendir(const char *name){
// Abre un directorio a partir del name
if (fs == NULL)
fs_init();
int num_inodo;
printf("\t\tExplorando directorio: '%s'\n", name);
if(name[0] == '.' && name[1] == '\0'){
// Si estamos en el caso de . operaciones en raíz
if(fs->dir.num_inodo == -1){
// Si la estructura dir no está inicializada
inode_read(fs, &fs->dir.inodo, fs->sb.root_inode); // Leemos la estructura disk_inode del root
fs->dir.num_inodo = fs->sb.root_inode; // Copiamos el número de inodo del root = 0
fs->dir.pos = 0;
fs->dir.pos_block = 0;
strcpy(fs->dir.path, name); // Copiamos el nombre
} else {
return NULL;
}
} else {
// Si estamos en cualquier otro caso
if(fs->dir.num_inodo == -1){
// Si la estructura dir no está inicializada
num_inodo = get_inodo(fs, name); // Obtenemos el inodo del último elemento del path
if(num_inodo == -1)
return NULL;
inode_read(fs, &fs->dir.inodo, num_inodo);
fs->dir.num_inodo = num_inodo;
fs->dir.pos = 0;
fs->dir.pos_block = 0;
strcpy(fs->dir.path, name);
} else {
return NULL;
}
}
return &fs->dir; // Devolvemos la estructura dir con los campos inicializados
}struct dirent *mfs_readdir(MFS_DIR *dir){
// Dado un directorio obtiene entradas de él
char block[fs->sb.block_size];
struct dirent *entrada = NULL;
struct entry *ent = (struct entry*)block;
struct disk_inode ino_previo;
int num_inodo_root;
int inodo_root_previo;
int root_is_dir = 1;
int i = 0;
printf("ent[dir->pos].name %s\n", ent[dir->pos].name);
printf("ent[dir->pos].inode %d\n", ent[dir->pos].inode);
printf("dir->inodo.e.start %d\n", dir->inodo.e.start);
printf("dir->pos %d\n", dir->pos);
data_read(fs, block, dir->inodo.e.start + i); // Leemos el bloque correspondiente al inodo del dir abierto
if(dir->pos != -1){
// Posición dentro del fichero válida
if (ent[dir->pos].inode != -1){
// Inodo válido (estructura entry inicializada)
printf("dir->num_inodo %d \n", dir->num_inodo);
printf("get_inodo_previo(fs,dir->path) %d \n", get_inodo_previo(fs, dir->path));
entrada = malloc(sizeof(struct dirent));
strcpy(entrada->d_name, ent[dir->pos].name); // Asignamos el nombre de la entrada
num_inodo_root = dir->num_inodo; // Guardamos el inodo del elemento que nos pasan
}
}
}