diff options
-rw-r--r-- | Makefile | 28 | ||||
-rw-r--r-- | README | 0 | ||||
-rw-r--r-- | block_walker.c | 368 | ||||
-rw-r--r-- | block_walker.h | 25 | ||||
-rw-r--r-- | defs.h | 54 | ||||
-rw-r--r-- | dir.c | 265 | ||||
-rw-r--r-- | dir.h | 41 | ||||
-rw-r--r-- | disk.mdfs | bin | 0 -> 33554432 bytes | |||
-rw-r--r-- | file.c | 178 | ||||
-rw-r--r-- | file.h | 32 | ||||
-rw-r--r-- | fusewrapper.c | 412 | ||||
-rw-r--r-- | inode.c | 204 | ||||
-rw-r--r-- | inode.h | 76 | ||||
-rw-r--r-- | log.c | 50 | ||||
-rw-r--r-- | log.h | 16 | ||||
-rw-r--r-- | medianin.c | 667 | ||||
-rw-r--r-- | medianin.h | 44 | ||||
-rw-r--r-- | mkfs.md/Makefile | 14 | ||||
-rw-r--r-- | mkfs.md/disk.mdfs | bin | 0 -> 33554432 bytes | |||
-rw-r--r-- | mkfs.md/mkfs.c | 90 | ||||
-rw-r--r-- | mkfs.md/mkfs.md | bin | 0 -> 10016 bytes | |||
-rw-r--r-- | mkfs.md/out | 2 | ||||
-rw-r--r-- | run.sh | 21 | ||||
-rw-r--r-- | test.sh | 10 | ||||
-rw-r--r-- | tests/read_diferentes_offsets.py | 20 |
25 files changed, 2617 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ed14cc9 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +TARGET=fusewrapper +CC=clang + +# Agregado glib para el block walker +CFLAGS+= -O0 -ansi -Werror -Wall -Wdeclaration-after-statement \ + -Wbad-function-cast -Wstrict-prototypes -Wmissing-declarations \ + -Wmissing-prototypes -Wno-unused-parameter \ + -Wunused-variable -g \ + `pkg-config --cflags fuse glib-2.0` +LDFLAGS=`pkg-config --libs fuse glib-2.0` + +SOURCES=$(shell echo *.c) +OBJECTS=$(SOURCES:.c=.o) + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) $^ -o $@ $(LDFLAGS) + +clean: + rm -f $(TARGET) $(OBJECTS) .depend *~ + +.depend: *.[ch] + $(CC) -MM `pkg-config --cflags fuse glib-2.0` $(SOURCES) >.depend + +-include .depend + +.PHONY: clean all diff --git a/block_walker.c b/block_walker.c new file mode 100644 index 0000000..b4c2682 --- /dev/null +++ b/block_walker.c @@ -0,0 +1,368 @@ +#include <assert.h> +#include <glib.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <time.h> + +#include "block_walker.h" +#include "defs.h" + +struct _block_walker { + const char *fib; + const char *fbb; + const char *ipool; + const char *bpool; + + uint16_t *indblock_mem; + + GList *block_list; + GList *indirect_list; +}PACKED; + +uint16_t allocate_block(bwalker *bw); +int free_block(bwalker *bw, uint16_t block); + +/* Auxiliares */ +uint16_t allocate_block(bwalker *bw) +{ + uint16_t result = 0; + uint16_t i = 0; + + assert (bw != NULL); + /* Solo queremos desde el segundo inodo para + * que tengamos como error el 0 */ + for(i = 1; i < BLOCKPOOL_BLOCKS; i++) + if(GET_BIT(bw->fbb, i) == 0) + { + /* cambiamos el bitmap */ + SET_BIT_1((char*)bw->fbb, i); + result = i; + break; + } + /* Tiene que estar seteado a 1 */ + assert(GET_BIT(bw->fbb, i) == 1); + + return (result); +} + +int free_block(bwalker *bw, uint16_t block) +{ + char *block_mem = NULL; + assert (bw != NULL); + + block_mem = (char *) bw->bpool + (block * BLOCK_SIZE); + + /* Chequeamos error */ + if (GET_BIT(bw->fbb, block) == 0) + return -1; + + SET_BIT_0((char *)bw->fbb, block); + + return (0); +} + + +/* Creacion y destruccion */ + +bwalker *bwalker_create(const char *base_mem, size_t size, uint16_t *indirect_mem) +{ + bwalker *bw = NULL; + unsigned int i = 0; + uint16_t *indirect_ptr; + uint16_t indirect_num = 0; + + bw = calloc(1, sizeof(struct _block_walker)); + + assert (bw != NULL); + bw->fbb = (char *)base_mem + FBB_OFFSET; + bw->fib = (char *)base_mem + FIB_OFFSET; + bw->ipool = (char *)base_mem + INODEPOOL_OFFSET; + bw->bpool = (char *)base_mem + BLOCKPOOL_OFFSET; + + bw->indblock_mem = indirect_mem; + bw->block_list = NULL; + bw->indirect_list = NULL; + + if (size == 0) + { + /* No hay bloques, no hay nada, + * retornamos aqui */ + return (bw); + } + /* Deberia tener al menos un bloque indirecto. */ + assert ((*indirect_mem) != 0); + + indirect_num = *indirect_mem; + bw->indirect_list = g_list_append (bw->indirect_list, + GUINT_TO_POINTER(indirect_num)); + assert(indirect_num == GPOINTER_TO_UINT(bw->indirect_list->data)); + + indirect_ptr = (uint16_t *) bw->bpool + (BLOCK_SIZE*indirect_num); + + + while (size > 0) + { + /* Empezamos a meterles bloques */ + for(i = 0; i < 255 && size>0; i++) + { + if (indirect_ptr[i] != 0){ + bw->block_list = g_list_append (bw->block_list, + GUINT_TO_POINTER(indirect_ptr[i])); + } + if(indirect_ptr[i]==0){ + break; + } + + if(size > BLOCK_SIZE){ + size -= BLOCK_SIZE; + }else{ + size = 0; + } + } + + if(size != 0 && size>0) + + if(indirect_ptr[255] != 0) + + { + bw->indirect_list = g_list_append (bw->indirect_list, + GUINT_TO_POINTER(indirect_ptr[255])); + indirect_ptr = (uint16_t *) bw->bpool + (BLOCK_SIZE*indirect_ptr[255]); + } + } + + + /*assert (g_list_length(bw->indirect_list) > 0);*/ + + /*assert (*indirect_mem == GPOINTER_TO_UINT(g_list_first(bw->indirect_list)->data));*/ + /*assert (g_list_length(bw->indirect_list) > 0); + assert (g_list_length(bw->block_list) > 0);*/ + + return (bw); +} + +void bwalker_destroy (bwalker *bw) +{ + assert (bw != NULL); + + if(bw->block_list != NULL) + g_list_free(g_list_first(bw->block_list)); + if(bw->indirect_list != NULL) + g_list_free(g_list_first(bw->indirect_list)); + + free(bw); + bw = NULL; +} + +uint16_t bwalker_direct_length(bwalker *bw) +{ + assert(bw != NULL); + return ((uint16_t) g_list_length(bw->block_list)); +} + +uint16_t bwalker_indirect_length(bwalker *bw) +{ + assert(bw != NULL); + return ((uint16_t) g_list_length(bw->indirect_list)); +} + +uint16_t bwalker_allocate_block(bwalker *bw) +{ + uint16_t block = 0; + uint16_t indirect_block = 0; + uint16_t *buf; + uint16_t i =0 ; + bool no_first_indblock = false; + bool indblk_alloc = false; + assert (bw != NULL); + + no_first_indblock = (g_list_length(bw->indirect_list) == 0); + + if(no_first_indblock) + goto ALLOCATE_INDBLK; + + indirect_block = bwalker_last_indirect(bw); + /* Esto tiene que ser distinto de 0 si o si */ + buf = (uint16_t *) bw->bpool + (indirect_block * BLOCK_SIZE); + for(i = 0; i < 255; i++){ + if(buf[i] == 0) + goto ALLOCATE_BLOCK; + } + /* Si llegamos aca, aloca un indirecto y encima _no_ es el primero :B */ + +ALLOCATE_INDBLK: + indirect_block = allocate_block (bw); + assert(indirect_block != 0); + + if(!indirect_block) + goto ENOBLK; + if(no_first_indblock) + *(bw->indblock_mem) = indirect_block; + else + { + assert(buf != NULL); + assert(&(buf[255]) == &(buf[i])); + assert(i == 255); + buf[i] = indirect_block; + } + bw->indirect_list = g_list_append(bw->indirect_list, GUINT_TO_POINTER(indirect_block)); + i = 0; + indblk_alloc = true; + +ALLOCATE_BLOCK: + buf = (uint16_t *) bw->bpool + (indirect_block * BLOCK_SIZE); + block = allocate_block (bw); + if(!block) + { + if(indblk_alloc) + { + free_block(bw,indirect_block); + bw->indirect_list = g_list_remove(bw->indirect_list, GUINT_TO_POINTER(indirect_block)); + if(no_first_indblock) + *bw->indblock_mem = 0; + } + goto ENOBLK; + } + buf[i] = block; + + bw->block_list = g_list_append(bw->block_list, GUINT_TO_POINTER(block)); + + assert(block != 0); + return block; + +ENOBLK: + return 0; +} + +void bwalker_free_block(bwalker *bw) +{ + uint16_t list_length_b, list_length_i; + uint16_t *buf = NULL; + uint16_t block = 0; + uint16_t i = 0; + GList *auxlist = NULL; + assert(bw != NULL); + + if(g_list_length(bw->block_list) == 0) + return; + + list_length_b=g_list_length(bw->block_list); + list_length_i=g_list_length(bw->indirect_list); + /* Aca tenemos que ver si necesitamos deallocar un + * bloque indirecto. */ + auxlist = g_list_last(bw->indirect_list); + block = (uint16_t) auxlist->data; + buf = (uint16_t *) bw->bpool + (block*BLOCK_SIZE); + if(!buf[1]) + { + /* Dealocamos solamente un bloque. */ + for(i=1; buf[i]; i++) + ; + block = buf[i-1]; + free_block(bw, block); + /*no se actualiza la lista. mirenlo a ver que onda, + * me parecio que era asi, pero no me hace caso*/ + bw->block_list=g_list_remove(bw->block_list, g_list_last(bw->block_list)->data); + + buf[i-1] = 0; + + } + else + { + free_block(bw, buf[0]); + bw->block_list=g_list_remove(bw->block_list, g_list_last(bw->block_list)->data); + + buf[0] = 0; + + + if((auxlist = g_list_previous(auxlist))) + { + block = (uint16_t) auxlist->data; + buf = (uint16_t *) bw->bpool + + (block*BLOCK_SIZE); + free_block(bw, buf[255]); + /*el indirecto == buf[255]???*/ + bw->indirect_list=g_list_remove(bw->indirect_list, g_list_last(bw->indirect_list)->data); + + buf[255] = 0; + } + else + { + free_block(bw, *bw->indblock_mem); + bw->indirect_list=g_list_remove(bw->indirect_list, bw->indblock_mem); + + *bw->indblock_mem = 0; + } + + } + +} + +uint16_t bwalker_next(bwalker *bw) +{ + uint16_t result = 0; + + assert (bw != NULL); + if(g_list_length(bw->block_list) == 0) + return 0; + + + if(g_list_length(bw->block_list) == 1){ + return (uint16_t)GPOINTER_TO_UINT(bw->block_list->data); + } + if(bw->block_list!=g_list_last(bw->block_list)){ + assert(*(bw->indblock_mem)!=GPOINTER_TO_UINT(bw->block_list->data)); + result = (uint16_t)GPOINTER_TO_UINT(bw->block_list->data); + bw->block_list = g_list_next(bw->block_list); + } + return (result); +} + +uint16_t bwalker_prev(bwalker *bw) +{ + uint16_t result = 0; + + assert (bw != NULL); + + if (bw->block_list != g_list_first(bw->block_list)) + { + result = GPOINTER_TO_UINT(bw->block_list->data); + bw->block_list = g_list_previous(bw->block_list); + } + + return (result); +} + +uint16_t bwalker_last_indirect (bwalker *bw) +{ + uint16_t result = 0; + assert(bw != NULL); + assert(g_list_length(bw->indirect_list) > 0); + if(g_list_last(bw->indirect_list)) + { + result = (uint16_t) + GPOINTER_TO_UINT(g_list_last(bw->indirect_list)->data); + } + + return result; +} + +uint16_t bwalker_last_block (bwalker *bw) +{ + uint16_t result = 0; + assert (bw != NULL); + if(g_list_last(bw->block_list)) + result = GPOINTER_TO_UINT(g_list_last(bw->block_list)->data); + return result; +} + +uint16_t bwalker_block_is_last(bwalker *bw) +{ + assert(bw != NULL); + return (bw->block_list == g_list_last(bw->block_list)); +} +void bwalker_set_first(bwalker *bw) +{ + bw->block_list=g_list_first(bw->block_list); +} diff --git a/block_walker.h b/block_walker.h new file mode 100644 index 0000000..00efc09 --- /dev/null +++ b/block_walker.h @@ -0,0 +1,25 @@ +#ifndef _BLOCK_WALKER_H +#define _BLOCK_WALKER_H +#include <stdint.h> + +typedef struct _block_walker bwalker; + +/* Creacion y destruccion */ +bwalker *bwalker_create(const char *base_mem,size_t size, uint16_t *indirect_mem); +void bwalker_destroy (bwalker *bw); + +/* Consigue un bloque libre. En caso de fallar, retorna 0 */ +uint16_t bwalker_direct_length(bwalker *bw); +uint16_t bwalker_indirect_length(bwalker *bw); + +uint16_t bwalker_allocate_block(bwalker *bw); +void bwalker_free_block(bwalker *bw); + +uint16_t bwalker_next(bwalker *bw); +uint16_t bwalker_prev(bwalker *bw); +uint16_t bwalker_last_indirect (bwalker *bw); +uint16_t bwalker_last_block (bwalker *bw); +uint16_t bwalker_block_is_last(bwalker *bw); + +void bwalker_set_first(bwalker *bw); +#endif @@ -0,0 +1,54 @@ +#ifndef _DEFS_H +#define _DEFS_H + +/* Gatos */ +/* Parámetros del disco */ +#define BLOCKS 65536 +#define BLOCK_SIZE 512 +#define MDFS_FILENAME "disk.mdfs" +#define BLOCKPOOL_BLOCKS 64491 +#define INODEPOOL_BLOCKS 1024 +/* Parámetros de la organización lógica del disco */ +/* superblock */ +#define MDFS_SUPER_MAGIC (0x14F5) +#define SUPERBLOCK_SIZE (1*BLOCK_SIZE) +/* inode bitmap */ +#define FIB_BLOCKS 4 +#define FIB_SIZE (FIB_BLOCKS*BLOCK_SIZE) +/* free block bitmap */ +#define FBB_SIZE (16*BLOCK_SIZE) +/* inode info */ +#define INODE_ENTRIES 16384 +#define INODE_SIZE 32 +#define NAME_LENGTH 26 +#define INODEPOOL_SIZE (1024*BLOCK_SIZE) +/* Posiciones absolutas de cada una de las secciones del disco */ +#define SUPERBLOCK_OFFSET 0 +#define FIB_OFFSET (SUPERBLOCK_OFFSET+SUPERBLOCK_SIZE) +#define FBB_OFFSET (FIB_OFFSET+FIB_SIZE) +#define INODEPOOL_OFFSET (FBB_OFFSET+FBB_SIZE) +#define BLOCKPOOL_OFFSET (INODEPOOL_OFFSET+INODEPOOL_SIZE) + +/* Operaciones FBB */ +#define SET_BIT_0(buf, i) ((buf)[(i)/8]&=~(1u<<(i)%8)) +#define SET_BIT_1(buf, i) ((buf)[(i)/8]|=1<<(i)%8) +#define GET_BIT(buf, i) ((buf)[(i)/8]>>(i)%8&1) + +/* Operaciones varias */ +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#define DIV_CEIL(a,b) (((a)+(b)-1)/(b)) + +/* No quiero huecos al medio */ +#define PACKED __attribute__((packed)) + +/* Nos hartamos de poner lo mismo */ +#define NEW_TIME (uint32_t) time(NULL) + +#endif @@ -0,0 +1,265 @@ +#include "dir.h" + +#include <assert.h> +#include <unistd.h> +#include <libgen.h> +#include <string.h> +#include <stdbool.h> +#include <sys/mman.h> + +#include "defs.h" +#include "block_walker.h" + +uint16_t dir_create(const char *disk_mem, mode_t mode) +{ + uint16_t ipos = 0; + dir *d = NULL; + time_t new_time = NEW_TIME; + + assert (disk_mem != NULL); + + ipos = inode_allocate_block(disk_mem); + if(ipos == 0) + return 0; + + d = (dir *) disk_mem + INODEPOOL_OFFSET + (ipos * INODE_SIZE); + d->uid = getuid(); + d->gid = getgid(); + d->mode = mode; + d->size = 0; + d->type = I_DIR; + d->nlinks = 1; + d->ctime = new_time; + d->mtime = new_time; + d->atime = new_time; + + return (ipos); +} + +uint16_t dir_add_direntry(const char *disk_mem, dir *d, const char *name, + uint16_t inumber, uint16_t sym) +{ + bwalker *walker = NULL; + uint16_t block = 0; + direntry *dentry = NULL; + uint16_t i = 0; + int result = 0; + + assert (disk_mem != NULL); + assert (d != NULL); + assert (name != NULL); + assert (strlen(name) < NAME_LENGTH); + + walker = bwalker_create(disk_mem, d->size, &(d->indirect)); + + if(bwalker_direct_length(walker)*BLOCK_SIZE<d->size+32){ + block = bwalker_allocate_block(walker); + }else{ + block = bwalker_last_block(walker); + + if(!block) + goto CLEAN; + } + + dentry = (direntry *) disk_mem + BLOCKPOOL_OFFSET + (block * BLOCK_SIZE); + + for(i = 0; i < 16; i++){ + if(strcmp(dentry[i].name, "\0") == 0){ + d->size += sizeof(direntry); /* Deberia ser 32*/ + dentry = &(dentry[i]); + strcpy(dentry->name, name); + dentry->inum = inumber; + dentry->symlink = sym; + result = 1; + goto CLEAN; + } + } + +CLEAN: + bwalker_destroy(walker); + + return result; +} + +uint16_t dir_remove_direntry(const char *disk_mem, dir *d, const char *name) +{ + bwalker *walker = NULL; + uint16_t result = 0; + uint16_t block = 0; + direntry *rm_dentry = NULL; + direntry *last_dentry = NULL; + uint16_t i; + + assert(disk_mem != NULL); + assert(d != NULL); + assert(name != NULL); + assert(strlen(name) < NAME_LENGTH); + + walker = bwalker_create(disk_mem, d->size, &(d->indirect)); + + /* Conseguimos el ultimo direntry */ + block = bwalker_last_block(walker); + assert(block != 0); + last_dentry = (direntry *) disk_mem + BLOCKPOOL_OFFSET + + (block * BLOCK_SIZE); + assert(last_dentry[0].inum != 0); + for(i = 0; i < 16; i++){ + if(last_dentry[i].inum == 0) + break; + } + assert(i > 0); + last_dentry = &(last_dentry[i-1]); + + while((block = bwalker_next(walker))) + { + rm_dentry = (direntry *) disk_mem + BLOCKPOOL_OFFSET + + (block * BLOCK_SIZE); + for(i = 0; i < 16; i++) + if(strcmp(name, rm_dentry[i].name) == 0) + { + /* Retornamos esto para eliminarlo fuera. */ + result = rm_dentry[i].inum; + /* Copiamos a la nueva posicion para ahorrarnos la + * fragmentacion externa. */ + strcpy(rm_dentry[i].name, last_dentry->name); + rm_dentry[i].inum = last_dentry->inum; + rm_dentry[i].symlink = last_dentry->symlink; + + /* Borramos los contenidos del ultimo. */ + last_dentry->name[0] = '\0'; + last_dentry->inum = 0; + last_dentry->symlink = 0; + + goto END; + } + + if(bwalker_block_is_last(walker)) + break; + } +END: + bwalker_destroy(walker); + return result; +} + + +dir *dir_get_from_path(const char *disk_mem, const char *path) +{ + uint16_t inum = 0; + char *dir_name = NULL; + + assert (disk_mem != NULL); + assert (path != NULL); + dir_name = calloc(strlen(path) + 1, sizeof(char)); + strcpy(dir_name, path); + inum = get_inode_from_path(disk_mem, dirname(dir_name), 1); + free(dir_name); + if(inum==0){ + return NULL; + } + return ((dir *)disk_mem+INODEPOOL_OFFSET+INODE_SIZE*inum); + +} + +uint16_t dir_search(const char *disk_mem, dir *idir,const char *name) +{ + bwalker *bw = NULL; + direntry *dentry; + uint16_t bnum, i; + + + assert(disk_mem != NULL); + assert(idir != NULL); + assert(name != NULL); + assert(strcmp(name, "")); + + + /* Salimos si esto esta vacio obviamente. */ + if(idir->size == 0){ + return 0; + } + + bw = bwalker_create(disk_mem, idir->size, &(idir->indirect)); + while ((bnum = bwalker_next(bw))) + { + dentry=(direntry *) disk_mem + BLOCKPOOL_OFFSET + (bnum*BLOCK_SIZE); + for(i=0; i<16; i++){ + if(strcmp(name, dentry[i].name) == 0){ + bwalker_destroy(bw); + return dentry[i].inum; + } + } + + if(bwalker_block_is_last(bw)) + break; + } + bwalker_destroy(bw); + return 0; +} + +int dir_rename_inode(const char *disk_mem, dir *d, + const char *old_name, const char *new_name) +{ + bwalker *bw = NULL; + direntry *dentry; + uint16_t i; + uint16_t bnum; + + assert(disk_mem != NULL); + assert(d != NULL); + assert(strcmp(old_name, "")); + assert(new_name != NULL); + assert(old_name != NULL); + assert(strlen(new_name) < NAME_LENGTH); + + /* Salimos si esto esta vacio obviamente. */ + if(d->size == 0){ + return 0; + } + + bw = bwalker_create(disk_mem, d->size, &(d->indirect)); + while ((bnum = bwalker_next(bw))) + { + dentry=(direntry *) disk_mem + BLOCKPOOL_OFFSET + (bnum*BLOCK_SIZE); + for(i=0; i<16; i++){ + if(strcmp(old_name, dentry[i].name) == 0){ + bwalker_destroy(bw); + strcpy(dentry[i].name,new_name); + return 1; + } + } + + if(bwalker_block_is_last(bw)) + break; + } + bwalker_destroy(bw); + return 0; +} + +uint16_t dir_readdir(const char *disk_mem, dir *d, void *buf, fuse_fill_dir_t filler) +{ + + bwalker *bw = NULL; + direntry *dentry; + uint16_t bnum, i; + + + assert(disk_mem != NULL); + assert(d != NULL); + + /* Salimos si esto esta vacio obviamente. */ + if(d->size == 0) + return 0; + + bw = bwalker_create(disk_mem, d->size, &(d->indirect)); + while ((bnum = bwalker_next(bw))){ + dentry=(direntry *) disk_mem + BLOCKPOOL_OFFSET + (bnum*BLOCK_SIZE); + for(i=0; i<16 && dentry[i].name[0] != '\0' ; i++){ + filler(buf, (const char *)&(dentry[i].name), NULL, 0); + } + + if(bwalker_block_is_last(bw)) + break; + } + bwalker_destroy(bw); + return 0; +} @@ -0,0 +1,41 @@ +#ifndef _DIR_H +#define _DIR_H + +#define _GNU_SOURCE +#include "inode.h" +#include <time.h> +#include <stdlib.h> +#include <fuse.h> + + +typedef inode dir; + +/* Crea un directorio con el modo pasado por parametro. + * Retorna el numero de inodo alocado. 0 en caso de error. */ +uint16_t dir_create(const char *disk_mem, mode_t mode); + +/* Agrega un direntry al directorio @d@ pasado por parametro. + * En caso de error retorna 0. */ +uint16_t dir_add_direntry(const char *disk_mem, dir *d, const char *name, + uint16_t inumber, uint16_t sym); +/* Quita un direntry del directorio y devuelve el numero de inodo a liberar + * a posteriori */ +uint16_t dir_remove_direntry(const char *disk_mem, dir *d, const char *name); + +/* Busca un nombre por las direntry del dir. Retorna el inodo del nombre + * buscado o 0 si no lo encuentra. */ +uint16_t dir_search(const char *disk_mem, dir *d,const char *name); + +/* Renombra un inodo pisando el nombre antiguo*/ +int dir_rename_inode(const char *disk_mem, dir *d, + const char *old_name, const char *new_name); + +/* Abstraccion del readdir */ +uint16_t dir_readdir(const char *disk_mem, dir *d, + void *buf, fuse_fill_dir_t filler); + +/* Retorna el ultimo directorio del path dado. + * Ex: path=/usr/share/icons/archlinux.png, retorna el directorio de incons*/ +dir *dir_get_from_path(const char *disk_mem, const char *path); + +#endif diff --git a/disk.mdfs b/disk.mdfs Binary files differnew file mode 100644 index 0000000..3318d0b --- /dev/null +++ b/disk.mdfs @@ -0,0 +1,178 @@ +#include "file.h" +#include "block_walker.h" + +#include <assert.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include "defs.h" + +uint16_t file_create(const char *disk_mem, mode_t mode) +{ + uint16_t ipos = 0; + file *f = NULL; + bwalker *bw = NULL; + + assert (disk_mem != NULL); + + bw = bwalker_create (disk_mem, 0, 0); + ipos = inode_allocate_block(disk_mem); + + f = (file *) disk_mem + INODEPOOL_OFFSET + (ipos * INODE_SIZE); + f->uid = getuid(); + f->gid = getgid(); + f->mode = mode; + f->size = 0; + f->type = I_FILE; + f->nlinks = 1; + f->ctime = NEW_TIME; + f->mtime = NEW_TIME; + f->atime = NEW_TIME; + + bwalker_destroy (bw); + + return (ipos); +} + +size_t file_read (const char *disk_mem, file *f, char *buf, + size_t size, off_t offset) +{ + size_t result = 0; + size_t len = 0; + bwalker *bw = NULL; + uint16_t *block; + uint16_t bnum; + + assert (f != NULL); + assert (buf != NULL); + + bw = bwalker_create (disk_mem, f->size, &(f->indirect)); + + while (size > 0 && (bnum = bwalker_next(bw))) + { + block = (uint16_t *) disk_mem + BLOCKPOOL_OFFSET + (bnum*BLOCK_SIZE); + if (offset >= BLOCK_SIZE){ + /* Nos movemos (no escribimos) */ + offset -= BLOCK_SIZE; + continue; + } + assert(offset < BLOCK_SIZE); + + block += offset; + + len = MIN(size,(BLOCK_SIZE - offset)); + + memcpy(buf, block, len); + result += len; + buf += len; + size -= len; + offset = 0; + if(bwalker_block_is_last(bw)){ + break; + } + + } + + bwalker_destroy (bw); + return (result); +} + +int file_truncate (const char *disk_mem, file *f, off_t size) +{ + bwalker *walker; + uint16_t offset, i, fb_size, block=0; + assert(disk_mem != NULL); + assert(f != NULL); + + + walker=bwalker_create(disk_mem, f->size, &(f->indirect)); + /*el tamaño en bytes de la cantidad de bloques que ocupa el file + * siempre es >= file_size*/ + fb_size=(bwalker_direct_length(walker)*BLOCK_SIZE); + + if(f->size < size){ + /*si el pedacito que jode...*/ + offset=size-f->size; + /*es menor que 512, y ademas el nuevo tamaño no pasa al fb_size + * no es neceasrio alocar bloques, solo se cambia el tamaño*/ + if(offset<BLOCK_SIZE&&size<=fb_size){ + f->size=size; + bwalker_destroy(walker); + return 0; + } + for(i=0; i<(DIV_CEIL(offset, BLOCK_SIZE)); i++){ + /*aloca lo que necesita*/ + block=bwalker_allocate_block(walker); + } + /*change size*/ + f->size=size; + }else{ + /*idem, pero al verez*/ + offset=f->size-size; + f->size=size; + if(offset<BLOCK_SIZE&&size>=fb_size){ + f->size=size; + bwalker_destroy(walker); + return 0; + } + for(i=0; i<(DIV_CEIL(offset, BLOCK_SIZE)); i++){ + bwalker_free_block(walker); + } + f->size=size; + } + bwalker_destroy(walker); + return 0; +} + +size_t file_write (const char *disk_mem, file *f, char *buf, + size_t size, off_t offset) +{ + size_t result = 0; + size_t len = BLOCK_SIZE; + bwalker *bw = NULL; + uint16_t *block = NULL; + uint16_t bnum = 0; + time_t new_time = NEW_TIME; + + assert (disk_mem != NULL); + assert (f != NULL); + + + bw = bwalker_create (disk_mem, f->size, &(f->indirect)); + + while (size > 0 && (bnum = bwalker_next(bw))) + { + assert(bnum != f->indirect); + if (offset >= BLOCK_SIZE){ + /* Nos movemos (no escribimos) */ + offset -= BLOCK_SIZE; + continue; + } + block = (uint16_t *) disk_mem + BLOCKPOOL_OFFSET + (bnum*BLOCK_SIZE); + + assert(offset < BLOCK_SIZE); + block += offset; + + len = MIN(size,(BLOCK_SIZE - offset)); + + memcpy(block, buf, len); + + result += len; + buf += len; + size -= len; + offset = 0; + + if(bwalker_direct_length(bw)<=1){ + break; + } + + } + + f->atime = new_time; + f->mtime = new_time; + + bwalker_destroy (bw); + + return (result); +} @@ -0,0 +1,32 @@ +#ifndef _FILE_H +#define _FILE_H + +#define _GNU_SOURCE + +#include "inode.h" +#include "block_walker.h" + +#include <sys/types.h> +#include <time.h> +#include <utime.h> +#include <sys/stat.h> +#include <sys/statvfs.h> + +typedef inode file; + +/* Crea un archivo vacio con el nombre y modo pasados por parametro. + * Devuelve el numero de inodo asociado o 0 en caso de error. */ +uint16_t file_create(const char *disk_mem, mode_t mode); + +/* Abstraccion de lectura de un archivo */ +size_t file_read (const char *disk_mem, file *f, char *buf, + size_t size, off_t offset); + +/* Abstraccion de truncar un archivo */ +int file_truncate (const char *disk_mem, file *f, off_t offset); + +/* Abstraccion de escribir un archivo */ +size_t file_write (const char *disk_mem, file *f, char *buf, + size_t size, off_t offset); + +#endif diff --git a/fusewrapper.c b/fusewrapper.c new file mode 100644 index 0000000..604f4a2 --- /dev/null +++ b/fusewrapper.c @@ -0,0 +1,412 @@ +/* $Date: 2010-09-30 15:40:39 -0300 (Thu, 30 Sep 2010) $ */ +/* $Revision: 1364 $ */ + +#define _GNU_SOURCE +#define FUSE_USE_VERSION 26 + +#include <assert.h> + +#include <stdlib.h> +#include <fuse.h> +#include <errno.h> +#include <malloc.h> +#include <time.h> +#include <stdio.h> +#include <time.h> +#include <string.h> +#include "medianin.h" +#include "log.h" + +/* Variable global que contiene el SimpleFS */ +medianin *fs = NULL; + +/* + * Operaciones Básicas + */ + +static int fs_getattr(const char *path, struct stat *stbuf) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("getattr:%s", path); + rta = medianin_getattr(fs, path, stbuf); + debug2(" -> mode:%o size:%li", stbuf->st_mode, (long)stbuf->st_size); + debug3(" returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_readlink(const char *path, char *buf, size_t size) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("readlink:%s size:%li", path, (long)size); + rta = medianin_readlink(fs, path, buf, size); + debug2(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_mknod(const char *path, mode_t mode, dev_t rdev) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("mknod:%s mode:%o", path, mode); + rta = medianin_mknod(fs, path, mode); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_unlink(const char *path) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("unlink_file:%s", path); + rta = medianin_unlink(fs, path); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_symlink(const char *from, const char *to) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("symlink from:%s to:%s", from, to); + rta = medianin_symlink(fs, from, to); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_rename(const char *from, const char *to) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("rename from:%s to:%s", from, to); + rta = medianin_rename(fs, from, to); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_link(const char *from, const char *to) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("link from:%s to:%s", from, to); + rta = medianin_link(fs, from, to); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_chmod(const char *path, mode_t mode) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("chmod:%s modo:%o", path, mode); + rta = medianin_chmod(fs, path, mode); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_chown(const char *path, uid_t uid, gid_t gid) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("chown:%s uid:%i gid:%i", path, uid, gid); + rta = medianin_chown(fs, path, uid, gid); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_truncate(const char *path, off_t size) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("truncate:%s size:%li", path, (long)size); + rta = medianin_truncate(fs, path, size); + debug1("\n"); + return rta; +} + +static int fs_utime(const char *path, struct utimbuf *utb) +{ + int rta = 0; + struct timespec tv[2]; + tv[0].tv_sec = utb->actime; + tv[0].tv_nsec = 0; + tv[1].tv_sec = utb->modtime; + tv[1].tv_nsec = 0; + debug3("[%li] ", time(NULL)); + debug1("utime:%s atime:%li mtime:%li", + path, (long)utb->actime, (long)utb->modtime); + rta = medianin_utimens(fs, path, tv); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_open(const char *path, struct fuse_file_info *fi) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("*open:%s flags:%i", path, fi->flags); + debug1("\n"); + return rta; +} + +static int fs_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + int rta = 0; + (void) fi; + debug3("[%li] ", time(NULL)); + debug1("read:%s size:%li offset:%li", path, (long)size, (long)offset); + rta = medianin_read(fs, path, buf, size, offset); + debug2(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_write(const char *path, const char *buf, size_t size,off_t offset, + struct fuse_file_info *fi) +{ + int rta = 0; + (void) fi; + debug3("[%li] ", time(NULL)); + debug1("write:%s size:%li offset:%li", path, (long)size, (long)offset); + rta = medianin_write(fs, path, buf, size, offset); + debug2(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_statfs(const char *path, struct statvfs *stbuf) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("statfs:%s", path); + rta = medianin_statfs(fs, path, stbuf); + debug2(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + + +static int fs_release(const char *path, struct fuse_file_info *fi) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("*release:%s flags:%i", path, fi->flags); + debug1("\n"); + return rta; +} + +static int fs_utimens(const char *path, const struct timespec tv[2]) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("utimens:%s atime:%li mtime:%li", + path, (long)tv[0].tv_sec, (long)tv[1].tv_sec); + rta = medianin_utimens(fs, path, tv); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +/* + * Operaciones sobre Directorios + */ + +static int fs_mkdir(const char *path, mode_t mode) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("mkdir:%s mode:%o", path, mode); + rta = medianin_mkdir(fs, path, mode); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_rmdir(const char *path) +{ + int rta = 0; + debug3("[%li] ", time(NULL)); + debug1("rmdir:%s", path); + rta = medianin_rmdir(fs, path); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + +static int fs_readdir(const char *path, void *buf, + fuse_fill_dir_t filler, off_t offset, + struct fuse_file_info *fi) +{ + int rta = 0; + (void) fi; /* Para que no diga que la variable está sin usar */ + debug3("[%li] ", time(NULL)); + debug1("readdir:%s", path); + rta = medianin_readdir(fs, path, buf, filler); + debug3(" -> returns:%i", rta); + debug1("\n"); + return rta; +} + + +static struct fuse_operations fs_oper = +{ + /* Operaciones sobre archivos, NI = no implementada */ + .getattr = fs_getattr, /* Done */ + .readlink = fs_readlink, + .mknod = fs_mknod, /* Done */ + .unlink = fs_unlink, + .symlink = fs_symlink, + .rename = fs_rename, + .link = fs_link, + .chmod = fs_chmod, /* Almost done */ + .chown = fs_chown, /* Almost done */ + .truncate = fs_truncate, + .utime = fs_utime, /* Almost done */ + .open = fs_open, /* NI */ + .read = fs_read, + .write = fs_write, + .statfs = fs_statfs, /* Done */ + .release = fs_release, /* NI */ + .utimens = fs_utimens, /* Almost done */ + /* Operaciones sobre directorios */ + .mkdir = fs_mkdir, + .rmdir = fs_rmdir, + .readdir = fs_readdir, +}; + +/* !! end Rafa !! */ + +int main(int argc, char *argv[]) +{ + /* Cheat es una variable al estilo de argv pero solo con argumentos + * parseados como validos. La uso para trabajar menos + */ + char *cheat[10]; /* 10 es un indice que nunca se alcanza */ + int i = 1; + int argi = 1; + char *logfilename = NULL; + char *mountpoint = NULL; + char *tailptr = NULL; /* Variable temporal usada pora strtol */ + int loglevel = 3; /* default loglevel */ + fs_oper.utimens = 0; + cheat[0] = argv[0]; + + /* i==1 && argi == 1 i se usa con cheat y argi con argv */ + /* cuando consumo un argumento aumento argi */ + /* cuando agrego uno para fusemain aumento i */ + while (argi < argc) + { + if (strcmp(argv[argi], "-h") == 0) + { + printf("uso: %s [opciones] mountpoint\n" + "opciones:\n" + "\t-h\t\tImprime esta ayuda.\n\n" + "\t-logfile file\n" + "\t-l file\t\tGuarda los logs en el archivo" + " especificado.\n\n" + "\t-loglevel num\n" + "\t-n num\t\tEspecifica el nivel de log. " + "Por defecto es 3.\n\n" + , argv[0]); + return 1; + } + else if (strcmp(argv[argi], "-logfile") == 0 + || strcmp(argv[argi], "-l") == 0) + { + argi++; + if(argi < argc) logfilename = argv[argi]; + else + { + fprintf(stderr, "Se debe especificar un nombre" + " de archivo\n"); + return 1; + } + loglevel=1; /* Para evitar malos usos */ + } + else if (strcmp(argv[argi], "-loglevel") == 0 + || strcmp(argv[argi], "-n") == 0) + { + argi++; + if (argi < argc) + { + loglevel = (int)strtol(argv[argi], &tailptr, 10); + if (tailptr == argv[argi]) + { + fprintf(stderr, + "El nivel de log debe" + "ser ún numero\n"); + return 1; + } + if (loglevel < 0) + { + fprintf(stderr, + "El nivel de log debe" + "ser un número natural\n"); + return 1; + } + } + else + { + fprintf(stderr, "Se debe especificar un nivel" + " de log\n"); + return 1; + } + } + else if (argv[argi][0] == '-') + { + fprintf(stderr, "Opción no reconocida:" + "%s\n",argv[argi]); + return 1; + } + else if (mountpoint == NULL) + { + mountpoint = argv[argi]; + } + argi++; + } + if(mountpoint == NULL) + { + fprintf(stderr, "Argumentos insuficientes: " + "hace falta un mountpoint\n"); + return 1; + } + cheat[i++] = mountpoint; + if (loglevel != 0) + { + cheat[i++] = "-f"; + } + cheat[i] = NULL; + + if (log_open(logfilename, loglevel)!=0) + { + fprintf(stderr, "Advertencia! no se pudo inicializar el log\n"); + } + + debug3("Los numeros a la izquierda indican el momento en que la " + "llamada a la\nfunción se efectuó según time(NULL).\n"); + + fs = medianin_create(); + if (fs == NULL) + { + return ENOMEM; + } + + fuse_main(i, cheat, &fs_oper, NULL); /* El corazón del programa */ + + medianin_destroy(fs); + log_close(); + + return 0; +} @@ -0,0 +1,204 @@ +#include "inode.h" + +#include <assert.h> +#include <sys/mman.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <libgen.h> + +#include "defs.h" +#include "block_walker.h" + + +/* Auxiliares */ +uint16_t get_path_length(const char *path); +char *get_next_dir(const char *path, uint16_t position); +int16_t name_check(char *path, direntry *entry_block); +int16_t inode_search(const char *disk_mem, inode *current, char *path); + +/*Parser*/ + +int16_t name_check(char *path, direntry *entry_block) +{ + int16_t result=-1; + int i = 0; + + assert(path != NULL); + assert(entry_block != NULL); + + for(i=0; i<16 && entry_block[i].inum != 0; i++){ + if(strcmp(entry_block[i].name, path)){ + result=entry_block[i].inum; + break; + } + } + return result; +} + +int16_t inode_search(const char *disk_mem, inode *current, char *path) +{ + + bwalker *bw = NULL; + direntry *dentry = NULL; + int16_t result = -1; + uint16_t block; + + assert (disk_mem != NULL); + assert (current != NULL); + assert (path != NULL); + + bw=bwalker_create(disk_mem, current->size, &(current->indirect)); + + while(result==-1 && (block=bwalker_next(bw))!=0){ + dentry=(direntry *)disk_mem+BLOCKPOOL_OFFSET+(block*BLOCK_SIZE); + result=name_check(path, dentry); + } + bwalker_destroy (bw); + + return result; +} + +/* Publico. */ + +/*Parse*/ +int16_t get_inode_from_path(const char *disk_mem, char *path, int16_t current_inum) +{ + int16_t i=1, path_len=strlen(path), result=0; + char *path_mod = NULL; + inode *current=(inode *)disk_mem+INODEPOOL_OFFSET+current_inum*INODE_SIZE; + + assert (disk_mem != NULL); + assert (path != NULL); + + /* Chequeamos si es root al principio :) */ + if (strcmp(path, "/") == 0) + return 1; + + /* Vamos a ponerle 2 mas por las moscas :) */ + path_mod = calloc(path_len + 2, sizeof(char)); + strcpy(path_mod, path); + + while(i<path_len){ + /*el while empieza desde i=1, se come el primer slash, necesario + * para usar basename*/ + if(path_mod[i] == '/'){ + /*NULL-terminamos el string para conseguir solo ese dir/file*/ + path_mod[i]='\0'; + break; + } + i++; + } + + result=inode_search(disk_mem, current, path_mod); + free(path_mod); + + if(i < path_len){ + /* *si no se llego al final, se busca el dir actual, y se continua + * la busqueda*/ + /*RECURSION FTW!*/ + return get_inode_from_path(disk_mem, path + i, result); + } + + /*si se llego al final, devolvemos el inodo correspondiente a la + * iteracion*/ + + + return result; +} + +int inode_getattr(inode *f, ino_t inum, struct stat *stbuf) +{ + assert (f != NULL); + + stbuf->st_ino = inum; + stbuf->st_mode = f->mode; + stbuf->st_nlink = f->nlinks; + stbuf->st_uid = f->uid; + stbuf->st_gid = f->gid; + stbuf->st_size = f->size; + stbuf->st_blksize = BLOCK_SIZE; + stbuf->st_blocks = (f->size / BLOCK_SIZE); + stbuf->st_atime = f->atime; + stbuf->st_ctime = f->ctime; + stbuf->st_mtime = f->mtime; + + return (0); +} +uint16_t inode_allocate_block(const char *disk_mem) +{ + uint16_t result = 0; + uint16_t i = 0; + + assert (disk_mem != NULL); + /* Solo queremos desde el segundo inodo para + * que tengamos como error el 0 */ + for(i = 1; i < FIB_SIZE; i++) + if(GET_BIT(disk_mem + FIB_OFFSET, i) == 0) + { + /* cambiamos el bitmap */ + SET_BIT_1((char*)disk_mem + FIB_OFFSET, i); + result = i; + break; + } + assert(GET_BIT(disk_mem + FIB_OFFSET, i) == 1); + + return (result); +} + +void inode_free_block(const char *disk_mem, uint16_t pos) +{ + assert (disk_mem != NULL); + assert (pos <= FIB_SIZE); + SET_BIT_0((char *)disk_mem + FIB_OFFSET, pos); +} + +int inode_chmod (inode *f, mode_t mode) +{ + assert (f != NULL); + + f->mode = mode; + f->ctime = NEW_TIME; + return (0); +} + +int inode_chown(inode *f, uid_t uid, gid_t gid) +{ + assert (f != NULL); + if (gid != -1) + f->gid = gid; + if (uid != -1) + f->uid = uid; + + f->ctime = NEW_TIME; + + return 0; +} + +int inode_utime(inode *f, const struct timespec tv[2]) +{ + assert (f != NULL); + + f->atime = (uint32_t) tv[1].tv_nsec; + f->ctime = (uint32_t) tv[1].tv_nsec; + f->mtime = (uint32_t) tv[1].tv_nsec; + + return (0); +} + +mode_t inode_get_mode(inode *i) +{ + assert (i != NULL); + return i->mode; +} + + +/* Direntry */ + +void direntry_clean(direntry *dentry) +{ + assert (dentry != NULL); + dentry->inum = 0; + dentry->name[0] = '\0'; + dentry->symlink = 0; +} @@ -0,0 +1,76 @@ +#ifndef _INODE_H +#define _INODE_H + +#define _GNU_SOURCE +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/statvfs.h> + +#include <time.h> + +/* Define los tipos que pueden ser los inodos. */ +enum { + I_FILE = 0, + I_DIR = 1, +}; + +/* + * {4} size + * {4} tipo (necesario para llegar a 32) + * {2} mode + * {2} uid + * {2} gid + * {12} atime,ctime, mtime + * {2} indirect + * {4} nlinks + * + * total 32 bytes + */ +struct _inode_t { + uint32_t size; /* Tamaño del inodo */ + uint32_t type; /* tipo */ + + uint16_t mode; /* acceso */ + uint16_t uid; + uint16_t gid; + + uint32_t atime; + uint32_t ctime; + uint32_t mtime; + + uint16_t indirect; + + uint32_t nlinks; +} __attribute__((packed)); + +/* Sinonimo ? */ +typedef struct _inode_t inode; + +/* Asociacion de nombre y numero de inodo + * 32 bytes tambien */ +struct _direntry_t { + uint32_t inum; + char name[26]; + uint16_t symlink; +} __attribute__((packed)); + +typedef struct _direntry_t direntry; + +/* Consigue un numero de inodo a partir de un path */ +int16_t get_inode_from_path(const char *disk_mem, char *path, int16_t current); + +/* Funciones del filesystem */ +int inode_getattr(inode *i, ino_t inum, struct stat *stbuf); +int inode_chown(inode *i, uid_t uid, gid_t gid); +int inode_chmod (inode *i, mode_t mode); +int inode_utime(inode *i, const struct timespec tv[2]); +mode_t inode_get_mode (inode *i); + +/* Consigue un nuevo inodo, devolviendo su numero y alocandolo */ +uint16_t inode_allocate_block(const char *disk_mem); +/* Libera un bloque pasado por parametro */ +void inode_free_block(const char *disk_mem, uint16_t pos); + +void direntry_clean(direntry *dentry); +#endif @@ -0,0 +1,50 @@ +/* $Date: 2010-09-30 15:40:39 -0300 (Thu, 30 Sep 2010) $ */ +/* $Revision: 1364 $ */ + +#include "log.h" +#include <stdarg.h> + +static int loglevel=0; +static FILE *logfile=NULL; + +int log_open(const char *filename, const int ll) +{ + loglevel = 0; + if (filename == NULL) logfile = stdout; + else logfile = fopen(filename, "w"); + if (logfile == NULL) return 1; + loglevel = ll; + return 0; +} + +void log_close(void) +{ + fclose(logfile); +} + +void debug1(const char * format, ...) +{ + va_list args; + if (loglevel < 1 || logfile == NULL) return; + va_start(args, format); + vfprintf(logfile,format,args); + va_end(args); +} + +void debug2(const char *format, ...) +{ + va_list args; + if (loglevel < 2 || logfile == NULL) return; + va_start(args, format); + vfprintf(logfile,format,args); + va_end(args); +} + +void debug3(const char *format, ...) +{ + va_list args; + if (loglevel < 3 || logfile == NULL) return; + va_start(args, format); + vfprintf(logfile,format,args); + va_end(args); +} @@ -0,0 +1,16 @@ +/* $Date: 2010-09-30 15:40:39 -0300 (Thu, 30 Sep 2010) $ */ +/* $Revision: 1364 $ */ + +#ifndef __LOG_H +#define __LOG_H + +#include <stdio.h> + +int log_open(const char *filename, const int level); +void log_close(void); + +void debug1(const char *format, ...) __attribute__((format(printf, 1, 2))); +void debug2(const char *format, ...) __attribute__((format(printf, 1, 2))); +void debug3(const char *format, ...) __attribute__((format(printf, 1, 2))); + +#endif /* __LOG_H */ diff --git a/medianin.c b/medianin.c new file mode 100644 index 0000000..36781a6 --- /dev/null +++ b/medianin.c @@ -0,0 +1,667 @@ +#include "medianin.h" +#include <malloc.h> +#include <assert.h> +#include <sys/mman.h> +#include <unistd.h> +#include <libgen.h> +#include <errno.h> +#include <string.h> +#include <stdbool.h> + +#include "defs.h" +#include "dir.h" +#include "file.h" +#include "inode.h" +#include "block_walker.h" + +/* Invariante de representación */ +#define INVREP(self) ((self)!=NULL && (self)->disk_mem!=NULL && 0<(self)->disk_fd) + +/* El FS medianin es el archivo con el disco mapeado en memoria y su fd */ +struct PACKED medianin_s +{ + char *disk_mem; /* puntero al inicio del disco mapeado en memoria */ + int disk_fd; /* fd del openfile con el disco */ + time_t mount_time; /* tiempo de montaje: a,m,ctime del rootdir */ +}; + +char *media_block=NULL; +/* Auxiliares */ + +uint16_t free_blocks_count(const char *disk_mem); +uint16_t free_inodes_count(const char *disk_mem); + +uint16_t free_blocks_count(const char *disk_mem) +{ + uint16_t i, s=0; + char *buf=(char *)disk_mem+FBB_OFFSET; + /*Conseguir los bloques vacios*/ + for(i=0; i<BLOCKPOOL_BLOCKS; i++){ + if(GET_BIT(buf, i)==1) + s++; + } + + return (BLOCKPOOL_BLOCKS-s); +} + +uint16_t free_inodes_count(const char *disk_mem) +{ + uint16_t i, s=0; + char *buf=(char *)disk_mem+FIB_OFFSET; + /*Conseguir los bloques vacios*/ + for(i=0; i<INODE_ENTRIES; i++){ + if(GET_BIT(buf, i)==1) + s++; + } + + return (INODE_ENTRIES-s); +} +/*Constructores y Destructores*/ +medianin *medianin_create(void) +{ + medianin *result = NULL; + void *map; + + result = calloc(1, sizeof(*result)); + + result->disk_mem = NULL; + result->disk_fd = open(MDFS_FILENAME, O_RDWR); + map=mmap(NULL, BLOCKS*BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, result->disk_fd, 0); + /*Nos aseguramos que el mapeo se realize correctamente*/ + if(map==MAP_FAILED) + perror("mmap"); + + result->disk_mem = map; + + result->mount_time = time(NULL); + + assert(result != NULL); + assert(INVREP(result)); + + return result; +} + +void medianin_destroy(medianin *self) +{ + assert(INVREP(self)); + + close (self->disk_fd); + /*Cerramos el fd, y guardamos los cambios*/ + if(msync(self->disk_mem, BLOCKS*BLOCK_SIZE, MS_SYNC) == -1) + perror("msync"); + if(munmap(self->disk_mem, BLOCKS*BLOCK_SIZE) == -1) + perror("munmap"); + + free(self); self = NULL; +} + +/* + * Operaciones Básicas + */ + +int medianin_getattr(medianin *self, const char *path, struct stat *stbuf) +{ + dir *pdir = NULL; + char *name, *path_c; + uint16_t block = 0; + inode *ind = NULL; + + assert(INVREP(self)); + assert(path != NULL); + assert(stbuf != NULL); + + if(strcmp(path,"/") == 0) + { + ind = (inode *) self->disk_mem + INODEPOOL_OFFSET + (1 * INODE_SIZE); + return inode_getattr(ind, 1, stbuf); + } + + pdir = dir_get_from_path(self->disk_mem, path); + + if (!pdir) + return -ENOENT; + + path_c=calloc(NAME_LENGTH, sizeof(char)); + strcpy(path_c, path); + + + name=calloc(NAME_LENGTH, sizeof(char)); + strcpy (name, basename(path_c)); + + block = dir_search(self->disk_mem, pdir, name); + free(path_c); + free(name); + + if (!block){ + return -ENOENT; + } + + ind = (inode *) self->disk_mem + INODEPOOL_OFFSET + (block * INODE_SIZE); + + return inode_getattr(ind, block, stbuf); +} + +int medianin_readlink(medianin *self, const char *path, char *buf, size_t size) +{ + uint16_t inode_block = 0; + dir *parent_dir = NULL; + file *f = NULL; + char name[26]; + + assert(INVREP(self)); + assert(path!=NULL); + assert(buf!=NULL); + + parent_dir = dir_get_from_path(self->disk_mem, path); + + if(!parent_dir) + return -ENOENT; + + strncpy(&(name[0]), basename((char *)path), 26); + + inode_block = dir_search(self->disk_mem, parent_dir, name); + + if(!inode_block) + return -ENOENT; + f = (file *) self->disk_mem + INODEPOOL_OFFSET + (inode_block*INODE_SIZE); + + if(S_ISDIR(inode_get_mode((inode *) f))) + return -EISDIR; + + return file_read(self->disk_mem, f, buf, size, 0); +} + +int medianin_mknod(medianin *self, const char *path, mode_t mode) +{ + dir *idir = NULL; + uint16_t ifile = 0; + char bname[26]; + + assert(INVREP(self)); + assert(path!=NULL); + + strncpy(&(bname[0]),basename((char *) path), 26); + + if(strlen(bname)>25){ + return -ENAMETOOLONG; + } + + idir=dir_get_from_path(self->disk_mem, path); + + if(dir_search(self->disk_mem ,idir, bname)){ + return -EEXIST; + } + + if((ifile=file_create(self->disk_mem, mode))==0){ + return -ENOSPC; + } + + if((dir_add_direntry(self->disk_mem, idir, bname, ifile, 0))==0){ + inode_free_block(self->disk_mem, ifile); + return -ENOSPC; + } + + return 0; +} + +int medianin_unlink(medianin *self, const char *path) +{ + int result = 0; + assert(INVREP(self)); + assert(path!=NULL); + + result = 0; + return result; +} + +int medianin_symlink(medianin *self, const char *from, const char *to) +{ + int result = 0; + assert(INVREP(self)); + assert(from!=NULL && to!=NULL); + + result = 0; + return result; +} + +int medianin_rename(medianin *self, const char *from, const char *to) +{ + int result = 0; + + assert(INVREP(self)); + assert(from!=NULL && to!=NULL); + + result = 0; + return result; +} + +int medianin_link(medianin *self, const char *from, const char *to) +{ + int result = 0; + char *to_c = NULL; + char *from_c = NULL; + uint16_t inum_from; + dir *from_dir, *to_dir; + file *f; + time_t itime; + + assert(INVREP(self)); + assert(from!=NULL && to!=NULL); + + + if(strlen(basename((char *)to))>25){ + return -ENAMETOOLONG; + } + + to_c = calloc(NAME_LENGTH, sizeof(char)); + from_c = calloc(NAME_LENGTH, sizeof(char)); + + strcpy(to_c, to); + strcpy(from_c, from); + + from_dir=dir_get_from_path(self->disk_mem, to); + + if((inum_from=dir_search(self->disk_mem, from_dir, basename((char *)from)))==0){ + result = -ENOENT; + goto CLEAN; + } + + f=(file *)self->disk_mem+INODEPOOL_OFFSET+inum_from*INODE_SIZE; + + if(S_ISDIR(f->mode)==1){ + result = -EPERM; + goto CLEAN; + } + + if((to_dir=dir_get_from_path(self->disk_mem, to))==NULL){ + result = -ENOENT; + goto CLEAN; + } + + if(!dir_add_direntry(self->disk_mem, to_dir, basename((char *)to), inum_from, 0)){ + result = -ENOSPC; + goto CLEAN; + } + + itime=NEW_TIME; + + f->nlinks+=1; + f->atime=itime; + f->mtime=itime; + +CLEAN: + free(to_c); + free(from_c); + return result; +} + +int medianin_chmod(medianin *self, const char *path, mode_t mode) +{ + dir *pdir = NULL; + char *name; + uint16_t block = 0; + inode *ind = NULL; + + assert(INVREP(self)); + assert(path != NULL); + + if(strcmp(path,"/") == 0) + { + ind = (inode *) self->disk_mem + INODEPOOL_OFFSET + (1 * INODE_SIZE); + return inode_chmod(ind, mode); + } + + pdir = dir_get_from_path(self->disk_mem, path); + + if (!pdir) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy (name, basename((char *) path), NAME_LENGTH); + + block = dir_search(self->disk_mem, pdir, name); + free(name); + + if (!block) + return -ENOENT; + + ind = (inode *) self->disk_mem + INODEPOOL_OFFSET + (block * INODE_SIZE); + return inode_chmod(ind, mode); +} + +int medianin_chown(medianin *self,const char *path, uid_t uid, gid_t gid) +{ + dir *pdir = NULL; + char *name = NULL; + uint16_t block = 0; + inode *ind = NULL; + + assert(INVREP(self)); + assert(path != NULL); + + if(strcmp(path,"/") == 0) + { + ind = (inode *) self->disk_mem + INODEPOOL_OFFSET + (1 * INODE_SIZE); + return inode_chown(ind, uid,gid); + } + + pdir = dir_get_from_path(self->disk_mem, path); + + if (!pdir) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy (name, basename((char *) path), 24); + + block = dir_search(self->disk_mem, pdir, name); + free(name); + + if (!block) + return -ENOENT; + + ind = (inode *) self->disk_mem + INODEPOOL_OFFSET + (block * INODE_SIZE); + + return inode_chown(ind, uid, gid); +} + +int medianin_truncate(medianin *self, const char *path, off_t size) +{ + dir *parent_dir = NULL; + file *f = NULL; + char *name = NULL; + uint16_t file_pos = 0; + + assert(INVREP(self)); + assert(path!=NULL); + + if(strcmp(path,"/") == 0) + return -EISDIR; + /* Conseguimos el directorio padre. */ + parent_dir = dir_get_from_path(self->disk_mem, path); + if(!parent_dir) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy (name, basename((char *) path), 26); + + + file_pos = dir_search(self->disk_mem, parent_dir, name); + free(name); + + if(!file_pos) + return -ENOENT; + + f = (file *) self->disk_mem + INODEPOOL_OFFSET + (file_pos*INODE_SIZE); + file_truncate(self->disk_mem, f, size); + return 0; + + +} + +int medianin_read(medianin *self, const char *path, + char *buffer, size_t size, off_t offset) +{ + uint16_t inode_block = 0; + dir *parent_dir = NULL; + file *f = NULL; + char *name = NULL; + + assert(INVREP(self)); + assert(path!=NULL); + assert(buffer!=NULL); + + parent_dir = dir_get_from_path(self->disk_mem, path); + + if(!parent_dir) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy(name, basename((char *)path), NAME_LENGTH); + + inode_block = dir_search(self->disk_mem, parent_dir, name); + free(name); + + if(!inode_block) + return -ENOENT; + f = (file *) self->disk_mem + INODEPOOL_OFFSET + (inode_block*INODE_SIZE); + + if(S_ISDIR(inode_get_mode((inode *) f))) + return -EISDIR; + + return file_read(self->disk_mem, f, buffer, size, offset); +} + +int medianin_write(medianin *self, const char *path, + const char *buffer, size_t size, off_t offset) +{ + uint16_t inode_block = 0, result = 0; + dir *parent_dir = NULL; + file *f = NULL; + char *name = NULL; + + assert(INVREP(self)); + assert(path!=NULL); + assert(buffer!=NULL); + + parent_dir = dir_get_from_path(self->disk_mem, path); + + if(parent_dir==NULL) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy (name, basename((char *) path), NAME_LENGTH); + + + inode_block = dir_search(self->disk_mem, parent_dir, name); + free(name); + + if(inode_block == 0) + return -ENOENT; + f = (file *) self->disk_mem + INODEPOOL_OFFSET + (inode_block*INODE_SIZE); + + if(S_ISDIR(inode_get_mode((inode *)f))) + return -EISDIR; + + + if(file_truncate(self->disk_mem, f, f->size+size)!=0){ + return -ENOSPC; + } + + result=file_write(self->disk_mem, f, (char *)buffer, size, offset); + + return result; +} + +int medianin_statfs(medianin *self, const char *path, struct statvfs *stbuf) { + int result = 0; + uint16_t free_blocks=free_blocks_count(self->disk_mem), free_inodes=free_inodes_count(self->disk_mem); + + assert(INVREP(self)); + assert(path!=NULL); + assert(stbuf!=NULL); + + + /* man statvfs */ + stbuf->f_bsize=BLOCK_SIZE; + stbuf->f_frsize=BLOCK_SIZE; + stbuf->f_blocks=(fsblkcnt_t)BLOCKS; + stbuf->f_bfree=(fsblkcnt_t)free_blocks; + stbuf->f_bavail=(fsblkcnt_t)free_blocks; + stbuf->f_files=(fsblkcnt_t)INODE_ENTRIES; + stbuf->f_ffree=(fsblkcnt_t)free_inodes; + stbuf->f_ffree=(fsblkcnt_t)free_inodes; + stbuf->f_flag=S_IRUSR | S_IWUSR | S_IXUSR | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH | S_IFDIR; + stbuf->f_namemax=26; + + result = 0; + return result; +} + +int medianin_utimens(medianin *self, const char *path, const struct timespec tv[2]) +{ + char *name = NULL; + dir *parent_dir = NULL; + inode *in = NULL; + uint16_t inode_block = 0; + + assert(INVREP(self)); + assert(path!=NULL); + + if(strcmp(path, "/")) + { + in = (inode *) self->disk_mem + INODEPOOL_OFFSET + INODE_SIZE; + return inode_utime(in, tv); + } + + parent_dir = dir_get_from_path(self->disk_mem, path); + + if(!parent_dir) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy (name, basename((char *) path), NAME_LENGTH); + + inode_block = dir_search(self->disk_mem, parent_dir, name); + free(name); + + if (!inode_block) + return -ENOENT; + + in = (inode *) self->disk_mem + INODEPOOL_OFFSET + + (inode_block*INODE_SIZE); + return inode_utime(in, tv); +} + +/* + * Operaciones sobre Directorios + */ + +int medianin_mkdir(medianin *self, const char *path, mode_t mode) +{ + int result = 0; + dir *idir = NULL; + uint16_t inode_dir = 0; + char *name = NULL; + + assert(INVREP(self)); + assert(path!=NULL); + + if(S_ISDIR(mode) == 0) + mode = mode | S_IFDIR; + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy (name, basename((char *) path), NAME_LENGTH); + + if(strlen(name) > 25){ + result = -ENAMETOOLONG; + goto CLEAN; + } + + idir=dir_get_from_path(self->disk_mem, path); + + if(dir_search(self->disk_mem ,idir, name)){ + result = -EEXIST; + goto CLEAN; + } + + if((inode_dir=dir_create(self->disk_mem, mode))==0){ + result = -ENOSPC; + goto CLEAN; + } + + if((dir_add_direntry(self->disk_mem, idir, name, inode_dir, 0))==0){ + inode_free_block(self->disk_mem, inode_dir); + result = -ENOSPC; + goto CLEAN; + } + + assert(GET_BIT(self->disk_mem + FIB_OFFSET, inode_dir) == 1); + +CLEAN: + free(name); + return result; +} + +int medianin_rmdir(medianin *self, const char *path) +{ + int result = 0; + dir *parent_dir = NULL; + char *name; + uint16_t inum; + uint16_t search_num; + inode *i; + + assert(INVREP(self)); + assert(path!=NULL); + + + parent_dir = dir_get_from_path(self->disk_mem, path); + if(!parent_dir) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy (name, basename((char *) path), NAME_LENGTH); + + search_num = dir_search(self->disk_mem, parent_dir, name); + + if(!search_num) + return -ENOENT; + + i = (inode *) self->disk_mem + INODEPOOL_OFFSET + (search_num * INODE_SIZE); + + + if(!S_ISDIR(inode_get_mode(i))) + return -ENOTDIR; + if((inode_get_mode(i) & S_IWUSR) == 0) + return -EPERM; + + /* Chequeos de permisos. */ + inum = dir_remove_direntry(self->disk_mem, parent_dir, name); + free(name); + + inode_free_block(self->disk_mem, inum); + + assert(inum == search_num); + return result; +} + +int medianin_readdir(medianin *self, const char *path, void *buf, + fuse_fill_dir_t filler) +{ + int result = 0; + dir *parent_dir = NULL; + dir *my_dir = NULL; + uint16_t dir_inumber = 0; + char *name = NULL; + + assert(INVREP(self)); + assert(path!=NULL && buf!=NULL); + + if(strcmp(path, "/") == 0) + { + /* Root dir */ + my_dir = (dir *) self->disk_mem + INODEPOOL_OFFSET + (1 * INODE_SIZE); + goto FILL; + } + parent_dir = dir_get_from_path(self->disk_mem, path); + + if (parent_dir == NULL) + return -ENOENT; + + name = calloc(NAME_LENGTH, sizeof(char)); + strncpy(name, basename((char *) path), NAME_LENGTH); + + dir_inumber = dir_search(self->disk_mem, parent_dir, name); + free(name); + + if(!dir_inumber) + return -ENOENT; + my_dir = (dir *) self->disk_mem + INODEPOOL_OFFSET + (dir_inumber * INODE_SIZE); + +FILL: + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + + dir_readdir(self->disk_mem, my_dir, buf, filler); + + return result; +} diff --git a/medianin.h b/medianin.h new file mode 100644 index 0000000..e0b070b --- /dev/null +++ b/medianin.h @@ -0,0 +1,44 @@ +#ifndef __MEDIANIN_H +#define __MEDIANIN_H + +#define _GNU_SOURCE +#define FUSE_USE_VERSION 26 + +#include <fuse.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <time.h> + +#include "defs.h" +typedef struct medianin_s medianin; + +/* Constructores y Destructores */ +medianin *medianin_create(void); +void medianin_destroy(medianin *self); + +/* Operaciones Básicas */ +int medianin_getattr(medianin *self, const char *path, struct stat *stbuf); +int medianin_readlink(medianin *self, const char *path, char *buf, size_t size); +int medianin_mknod(medianin *self, const char *path, mode_t mode); +int medianin_unlink(medianin *self, const char *path); +int medianin_symlink(medianin *self, const char *from, const char *to); +int medianin_rename(medianin *self, const char *from, const char *to); +int medianin_link(medianin *self, const char *from, const char *to); +int medianin_chmod(medianin *self, const char *path, mode_t mode); +int medianin_chown(medianin *self, const char *path, uid_t uid, gid_t gid); +int medianin_truncate(medianin *self, const char *path, off_t size); +int medianin_read(medianin *self, const char *path, + char *buffer, size_t size, off_t offset); +int medianin_write(medianin *self, const char *path, + const char *buffer, size_t size, off_t offset); +int medianin_statfs(medianin *self, const char *path, struct statvfs *stbuf); +int medianin_utimens(medianin *self, const char *path, const struct timespec tv[2]); + +/* Operaciones sobre Directorios */ +int medianin_mkdir(medianin *self, const char *path, mode_t mode); +int medianin_rmdir(medianin *self, const char *path); +int medianin_readdir(medianin *self, const char *path, void *buf, + fuse_fill_dir_t filler); + +#endif /* __MEDIANIN_H */ diff --git a/mkfs.md/Makefile b/mkfs.md/Makefile new file mode 100644 index 0000000..e91a5e5 --- /dev/null +++ b/mkfs.md/Makefile @@ -0,0 +1,14 @@ +FILES=mkfs.c +TARGET=mkfs.md +CFLAGS=-Wall -Werror -Wextra -g + +all: $(FILES) + clang $(CFLAGS) -o $(TARGET) $(FILES) + +with-inode: $(FILES) + clang $(CFLAGS) -D_HAS_TRACKED_INODE -o $(TARGET) $(FILES) + +clean: + rm -f $(TARGET) *.o + +.PHONY: clean diff --git a/mkfs.md/disk.mdfs b/mkfs.md/disk.mdfs Binary files differnew file mode 100644 index 0000000..0dae906 --- /dev/null +++ b/mkfs.md/disk.mdfs diff --git a/mkfs.md/mkfs.c b/mkfs.md/mkfs.c new file mode 100644 index 0000000..37c6e6e --- /dev/null +++ b/mkfs.md/mkfs.c @@ -0,0 +1,90 @@ +#include "../defs.h" +#include "../inode.h" + +#include <fcntl.h> + +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stdio.h> +#include <time.h> + +#include <unistd.h> +#include <sys/stat.h> + +struct PACKED superblock { + uint16_t magic; + uint32_t free_size; + uint32_t max_size; +}; + +int main(int argc, char *argv[]) +{ + char *fs = NULL; + int fd = 0; + struct superblock *sb= NULL; + inode *rootdir = NULL; +#ifdef _HAS_TRACKED_INODE + direntry *dentry = NULL; +#endif + + if (argc != 2){ + printf("Uso: %s [file]\n" + "Necesita proveer un nombre para el filesystem", + argv[0]); + return -2; + } + + fd = open(argv[1], O_WRONLY | O_CREAT, 0777); + + fs = calloc (BLOCKS*BLOCK_SIZE, sizeof(char)); + if (!fs){ + fprintf(stderr, "No hay suficiente memoria para alocar el filesystem\n"); + return (1); + } + sb = (struct superblock *) fs; + + sb->magic = 0xF514; /* No hay ganas de hacer aritmetica con lo que esta en el defs.h */ + sb->max_size = BLOCK_SIZE * BLOCKPOOL_BLOCKS; + sb->free_size = BLOCK_SIZE * BLOCKPOOL_BLOCKS; + SET_BIT_1((char *)sb + FBB_OFFSET, 0); + /* El primer elemento del inodepool es el rootdir */ + SET_BIT_1((char*) sb + FIB_OFFSET, 1); + + + rootdir = (inode *) sb + INODEPOOL_OFFSET + sizeof(inode); + + rootdir->type = I_DIR; + rootdir->mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH | S_IFDIR; + rootdir->uid = getuid(); + rootdir->gid = getgid(); + rootdir->indirect=2; + rootdir->atime = (uint32_t) time(NULL); + rootdir->ctime = (uint32_t) time(NULL); + rootdir->mtime = (uint32_t) time(NULL); + + rootdir->nlinks = 1; + +#ifndef _HAS_TRACKED_INODE + rootdir->size = 0; +#else + rootdir->size = sizeof(direntry); + /* Primer bloque */ + /*SET_BIT_1((char *)sb + FBB_OFFSET, 0); */ + dentry = (direntry *) sb + BLOCKPOOL_OFFSET; + dentry->inode = 0; + dentry->name[0] = '/'; + dentry->name[1] = '\0'; + dentry->symlink = 0; +#endif + + if ((write(fd, (void *) fs, BLOCKS*BLOCK_SIZE)) == -1){ + perror("write"); + close(fd); + return -1; + } + close(fd); + free(fs); + + return (0); +} diff --git a/mkfs.md/mkfs.md b/mkfs.md/mkfs.md Binary files differnew file mode 100644 index 0000000..90a9507 --- /dev/null +++ b/mkfs.md/mkfs.md diff --git a/mkfs.md/out b/mkfs.md/out new file mode 100644 index 0000000..ad97aa8 --- /dev/null +++ b/mkfs.md/out @@ -0,0 +1,2 @@ +clang -Wall -Werror -Wextra -g -std=c99 -o mkfs.md mkfs.c +Makefile:6: recipe for target 'all' failed @@ -0,0 +1,21 @@ +NEW_DISK="mkfs.md/disk.mdfs" + +echo "Compilando..." +make > /dev/null +if [ $? -ne 0 ]; then + echo "Error de compilacion" + exit 1 +fi + +fusermount -u ./mnt 2> /dev/null && echo "Desmontando" + +echo "Copiando $NEW_DISK" +cp ./$NEW_DISK . + +if [ "$1" == "valgrind" ]; then + valgrind --show-reachable=yes --leak-check=full ./fusewrapper mnt +else + ./fusewrapper mnt +fi + +exit 0 @@ -0,0 +1,10 @@ +touch mnt/{a,b,c,d,e,f} +mkdir mnt/{1,2,3,4,5,6,7} +mkdir -p mnt/z/z/z/z/z/z/z +echo "Hola mundo" > mnt/a +link mnt/a mnt/linked +stat mnt/a +stat mnt/linked +rmdir mnt/1 +cat -v mnt/a +cat -v mnt/linked diff --git a/tests/read_diferentes_offsets.py b/tests/read_diferentes_offsets.py new file mode 100644 index 0000000..008ef05 --- /dev/null +++ b/tests/read_diferentes_offsets.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +import sys +import random +random.seed("Yeah babe") + +text = open(sys.argv[1]).read() + +fin = open(sys.argv[1]) +for _ in xrange(1000): + offset = random.randint(0, len(text)) + size = random.randint(0, min(len(text) - offset - 1, 10 * 1024)) + fin.seek(offset) + chunk = fin.read(size) + assert len(chunk) <= size + assert len(chunk) != 0 + if text[offset:offset + len(chunk)] != chunk: + s = "Read fails for file {} with offset {} and size {}" + raise IOError(s.format(sys.argv[1], offset, size)) +print "Success!" |