Implementación en C de Funciones de Sistema de Archivos MFS

Informática11,15 KB

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
    }
}
}

Descargar

PDF Word HTML