#include #include #include #include // DEBUG #include #include #define TRUE 1 #define FALSE 0 static int montado = FALSE; static u8 super_bloque[SO_BLOCKSIZE];; static u8 vectorbits[SO_BLOCKSIZE]; static u8 tabla_inode_uno[SO_BLOCKSIZE]; static u8 tabla_inode_dos[SO_BLOCKSIZE]; /********************************** * Operaciones sobre el superbloque ***********************************/ /** * Conseguir una COPIA del superbloque. *---- * Parámetros: * psb(OUT): Puntero a la estructura donde se copiará el superbloque. * * Códigos de retorno: * OK: Copio correctamente. * ERROR: Hubo un error. *---- **/ int SO_vol_getSuperBlock(struct so_sb * psb) { if (!montado) return ERROR; memcpy( (void*) psb, (void*) &super_bloque ,SO_BLOCKSIZE); return OK; } /*************************** * Operaciones sobre I-Nodos *****************************/ /** * Conseguir una copia del I-Nodo inodeNum. *---- * Parámetros: * inodeNum (IN): Número de I-Nodo. * inode (OUT): Estructura donde se copia el I-Nodo. * * Códigos de retorno: * OK: Copio correctamente. * ERROR: Hubo un error. *---- **/ int SO_vol_getInode(u16 inodeNum, struct so_inode * inode) { void *ptr; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr = (void*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr = (void*) &tabla_inode_dos; } // llegue al inodo ptr = (void*) ((u8*) ptr + (inodeNum * 16)); memcpy ( (void*) inode, ptr, 16); return OK; } /** * Setea el nuevo tamaño de un I-Nodo. *---- * Parámetros: * inodeNum (IN): Número de I-Nodo. * size (IN): Tamaño nuevo. * * Códigos de retorno: * OK: Pudo setear el nuevo valor. * ERROR: Hubo un error. *---- **/ int SO_vol_setInodeSize(u16 inodeNum, u16 size) { void *ptr; u16 *ptr_isize; if ( size > 5*1024 ) return ERROR; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr = (void*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr = (void*) &tabla_inode_dos; } // llegue al inodo ptr = (void*) ((u8*) ptr + (inodeNum * 16)); ptr_isize = (u16*) ptr + 2; *ptr_isize = size; return OK; } /** * Setea la cantidad de enlaces que tiene el I-Nodo. *---- * Parámetros: * inodeNum (IN): Número de I-Nodo. * link (IN): Nueva cantidad de enlaces fuertes. * * Códigos de retorno: * OK: Pudo setear el nuevo valor. * ERROR: Hubo un error. *---- **/ int SO_vol_setInodeLink(u16 inodeNum, u16 link) { void *ptr; u16 *ptr_ilink; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr = (void*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr = (void*) &tabla_inode_dos; } // llegue al inodo ptr = (void*) ((u8*) ptr + (inodeNum * 16)); ptr_ilink = (u16*) ptr + 1; *ptr_ilink = link; return OK; } /** * Consigue un I-Nodo libre y devuelve el número de I-Nodo. LO MARCA COMO USADO, i_bsize = 0, i_link = 1, i_size = 0 *---- * Parámetros: * inodeNum (OUT): Número de I-Nodo libre conseguido. * * Códigos de retorno: * OK: Pudo conseguir el I-Nodo. * ERROR: Hubo un error. *---- **/ int SO_vol_allocateInode(u16 * inodeNum) { int i; int tabla_en_que_encontre; int encontre; struct so_inode *inode; u8 *ptr; i = 0; ptr = (u8*) (&tabla_inode_uno); tabla_en_que_encontre = 0; encontre = FALSE; while ( encontre == FALSE && i < 64 ) { if ( *ptr == 0 ) encontre = TRUE; else { ptr = ptr + 16; i++; } } /* si no encontre busco en la otra tabla de inodos */ if ( encontre == FALSE ) { tabla_en_que_encontre = 1; i = 0; ptr = (u8*) (&tabla_inode_dos); while ( encontre == FALSE && i < 64 ) { if ( *ptr == 0 ) encontre = TRUE; else { ptr = ptr + 16; i++; } } } if ( encontre == TRUE ) { *ptr = 1; // lo marco como ocupado *inodeNum = i + tabla_en_que_encontre*64; inode = (struct so_inode*) ptr; inode->i_bsize = 0; inode->i_link = 1; inode->i_size = 0; struct so_sb *ptr_superbloque = (so_sb*) &super_bloque; ptr_superbloque->s_fic -= 1; return OK; } return ERROR; } /** * Libera un I-Nodo. *---- * Parámetros: * inodeNum (IN): Número de I-Nodo a liberar. * * Códigos de retorno: * OK: Pudo liberar el I-Nodo. * ERROR: Hubo un error. *---- **/ int SO_vol_deallocateInode(u16 inodeNum) { u8 *ptr_itype; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr_itype = (u8*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr_itype = (u8*) &tabla_inode_dos; } // llegue al inodo ptr_itype = ptr_itype + (inodeNum * 16); if ( *ptr_itype == 0) return ERROR; // si tiene bloques asignados if ( *(ptr_itype + 1) >0 ) return ERROR; // lo libero *ptr_itype = 0; struct so_sb *ptr_superbloque = (so_sb*)&super_bloque; ptr_superbloque->s_fic += 1; return OK; } /************************************ * Operaciones sobre bloques de datos *************************************/ /** * Lee una copia del bloque de datos número (blockNum) de un I-Nodo. *---- * Parámetros: * inodeNum (IN): Número de I-Nodo. * blockNum (IN): Número de bloque de datos del I-Nodo (0..4) * block (OUT): Puntero a un bloque. * * Códigos de retorno: * OK: Se pudo leer el bloque de datos. * ERROR: Hubo un error. *---- **/ int SO_vol_bread(u16 inodeNum, u16 blockNum, void * block) { u16 num_bloque; u8 *ptr_inode; if (blockNum >4) return ERROR; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr_inode = (u8*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr_inode = (u8*) &tabla_inode_dos; } // llegue al inodo ptr_inode = ptr_inode + (inodeNum * 16); // si el inodo no esta siendo usado if ( *ptr_inode != 1) return ERROR; // si blockNum >= i_bsize if ( blockNum >= * (ptr_inode + 1) ) return ERROR; num_bloque = * ( (u16*)(ptr_inode + 6 + 2 * blockNum) ) + 4; // si el i-nodo apunta a un bloque que no existe o a uno del sistema if ( num_bloque >= SO_FSSIZE ) return ERROR; SO_blk_bread(num_bloque, block); return OK; } /** * Graba el bloque de datos número (blockNum) de un I-Nodo. *---- * Parámetros: * inodeNum (IN): Número de I-Nodo. * blockNum (IN): Número de bloque de datos del I-Nodo (0..4) * block (IN): Estructura donde se copia el bloque. * * Códigos de retorno: * OK: Se grabó el bloque de datos. * ERROR: Hubo un error. *---- **/ int SO_vol_bwrite(u16 inodeNum, u16 blockNum, const void * block) { u16 num_bloque; u8 *ptr_inode; if (blockNum >4) return ERROR; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr_inode = (u8*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr_inode = (u8*) &tabla_inode_dos; } // llegue al inodo ptr_inode = ptr_inode + (inodeNum * 16); // si blockNum >= i_bsize if ( blockNum >= * (ptr_inode + 1) ) return ERROR; num_bloque = (u16) ( *(ptr_inode + 6 + 2 * blockNum) + 4 ); // si el i-nodo apunta a un bloque que no existe o a uno del sistema if ( num_bloque >= SO_FSSIZE) return ERROR; SO_blk_bwrite(num_bloque, block); return OK; } /** * Consigue un bloque de datos libres para el I-Nodo (inodeNum). *---- * Parámetros: * inodeNum (IN): Número de I-Nodo. * * Códigos de retorno: * OK: Consiguió el bloque de datos. * ERROR: Hubo un error. *---- **/ int SO_vol_allocateBlock(u16 inodeNum) { u8 i; u16 pos; u8 word; int encontre; u8 *ptr_bitmap; u8 *ptr_inode; u16 *ptr_new_iblock; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr_inode = (u8*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr_inode = (u8*) &tabla_inode_dos; } // llegue al inodo ptr_inode = ptr_inode + (inodeNum * 16); if ( *ptr_inode != 1) return ERROR; // si ya tengo 5 bloques if ( *(ptr_inode + 1) >= 5) return ERROR; struct so_sb *ptr_superbloque = (so_sb*) &super_bloque; // si no tengo bloques libres if ( ptr_superbloque->s_fdb == 0) return ERROR; ptr_superbloque->s_freedb -= 1; //busco en el bitmap un bloque vacio; encontre = FALSE; i = 0; ptr_bitmap = (u8*) &vectorbits; while ( encontre == FALSE && i < 16 ) { if ( *ptr_bitmap != (u8) 0xFF) { encontre = TRUE; } else { ptr_bitmap += 1; i++; } } pos = 8*i; i = (u8) 0x80; word = *ptr_bitmap; while ( (~word & i) == 0) { i = i >> 1; pos++; } // marco en el bitmap como usado *ptr_bitmap |= i; // como encontre un bloque tengo que asignarselo al inode u8 *aux_u8 = ptr_inode + 1; *aux_u8 += 1; // le incremento i_bsize ptr_new_iblock = (u16*) (ptr_inode + 6 + (*aux_u8 - 1)*2 ); *ptr_new_iblock = (u16) pos; // i_block tiene el indice del bloque return OK; } /** * Libera el último bloque de datos ocupado por el I-Nodo (inodeNum). *---- * Parámetros: * inodeNum (IN): Número de I-Nodo. * * Códigos de retorno: * OK: Liberó el bloque de datos. * ERROR: Hubo un error. *---- **/ int SO_vol_deallocateBlock(u16 inodeNum) { int j; u8 *ptr_bitmap; u8 *ptr_aux_bloque_liberar; u8 *ptr_inode; u8 *ptr_bsize; u16 *dir_block; if ( inodeNum >= 64*2 || montado == FALSE) return ERROR; if (inodeNum < 64) ptr_inode = (u8*) &tabla_inode_uno; else { inodeNum = inodeNum % 64; ptr_inode = (u8*) &tabla_inode_dos; } // llegue al inodo ptr_inode = ptr_inode + (inodeNum * 16); if ( *ptr_inode != 1) return ERROR; ptr_bsize = ptr_inode + 1; // si tengo 0 bloques if ( *ptr_bsize == 0) return ERROR; dir_block = (u16*) (ptr_inode + 6 + (*(ptr_inode+1) - 1)*2 ); *ptr_bsize -= 1; ptr_bitmap = (u8*) &vectorbits; ptr_aux_bloque_liberar = ptr_bitmap + (int) ( *dir_block / 8 ); unsigned char i = 0x80; for (j=0; j != (*dir_block % 8); j++) i = i >> 1; *ptr_aux_bloque_liberar &= (u8) ~i; struct so_sb *ptr_superbloque = (so_sb*) &super_bloque; ptr_superbloque->s_freedb += 1; return OK; } /****************************************** * Operaciones sobre el sistema de archivos *******************************************/ /** * Monta el volumen. Invoca a SO_blk_mount y se trae una copia del superbloque, el vector de bits y la tabla de I-Nodos. *---- * Parámetros: * path (IN): ruta UNIX al volumen * * Códigos de retorno: * OK: Logró montar. * ERROR: Hubo un error. *---- **/ int SO_vol_mount(char * path) { if (montado == TRUE) { return ERROR; } if ( SO_blk_mount(path) != OK) { return ERROR; } montado = TRUE; // grabo el superbloque a la cache SO_blk_bread( 0, (void*) (&super_bloque) ); // grabo el bloque de bits a la cache SO_blk_bread( 1, (void*) (&vectorbits) ); // grabo los bloques de tabla de indos a la cache SO_blk_bread( 2, (void*) (&tabla_inode_uno)); SO_blk_bread( 3, (void*) (&tabla_inode_dos)); return OK; } /** * Desmonta el volumen. Graba el superbloque, vector de bits y la tabla de I- Nodos. Luego invoca la operación SO_blk_umount. *---- * Parámetros: * * Códigos de retorno: * OK: Desmontó correctamente. * ERROR: Hubo un error. *---- **/ int SO_vol_umount(void) { if (montado == FALSE) return ERROR; else { // grabo el superbloque de la cache disco SO_blk_bwrite( 0, (void*) (&super_bloque) ); // grabo el bloque de bits de la cache al disco SO_blk_bwrite( 1, (void*) (&vectorbits) ); // grabo los bloques de tabla de indos de la cache al disco SO_blk_bwrite( 2, (void*) (&tabla_inode_uno)); SO_blk_bwrite( 3, (void*) (&tabla_inode_dos)); montado = FALSE; /* desmonto fisicamente el disco */ return SO_blk_umount(); } } //////////////// DEBUG //////////////// /* void imprimir_superbloque_inodos_capa_vol(void) { struct so_sb super; struct so_inode inode; // Leo el superbloque SO_vol_getSuperBlock(&super); // Imprimo el superbloque fprintf(stdout,"## SuperBlock ##\n"); fprintf(stdout,"s_bs: %d\ns_fss: %d\ns_is: %d\ns_dbb: %d\ns_dbbn: %d\ns_fib: %d\ns_nib: %d\ns_tni: %d\ns_fic: %d\ns_fdb: %d\ns_ndb: %d\ns_freedb: %d\nname: %s\n",super.s_bs,super.s_fss,super.s_is,super.s_dbb,super.s_dbbn,super.s_fib,super.s_nib,super.s_tni,super.s_fic,super.s_fdb,super.s_ndb,super.s_freedb,super.name); // Leo los inodos fprintf(stdout,"## Bloque de Inodos ##\n"); for (int i = 0; i < super.s_tni; i++) { SO_vol_getInode(i,&inode); fprintf(stdout,"Inodo: %d -> i_type: %d, i_bsize: %d, i_link: %d, i_size: %d, i_block: %d %d %d %d %d\n",i,inode.i_type,inode.i_bsize,inode.i_link,inode.i_size,inode.i_block[0],inode.i_block[1],inode.i_block[2],inode.i_block[3],inode.i_block[4]); } } */