aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatias Linares <matiaslina@opmbx.org>2015-04-26 21:43:42 -0300
committerMatias Linares <matiaslina@opmbx.org>2015-04-26 21:43:42 -0300
commit2dd5cf430edaae01594d566c9f27d780c3ffb4ef (patch)
tree13111bc82a73e951d5d7c07865a206c025d15529
downloadmedianinfs-2dd5cf430edaae01594d566c9f27d780c3ffb4ef.tar.gz
Initial commit
-rw-r--r--Makefile28
-rw-r--r--README0
-rw-r--r--block_walker.c368
-rw-r--r--block_walker.h25
-rw-r--r--defs.h54
-rw-r--r--dir.c265
-rw-r--r--dir.h41
-rw-r--r--disk.mdfsbin0 -> 33554432 bytes
-rw-r--r--file.c178
-rw-r--r--file.h32
-rw-r--r--fusewrapper.c412
-rw-r--r--inode.c204
-rw-r--r--inode.h76
-rw-r--r--log.c50
-rw-r--r--log.h16
-rw-r--r--medianin.c667
-rw-r--r--medianin.h44
-rw-r--r--mkfs.md/Makefile14
-rw-r--r--mkfs.md/disk.mdfsbin0 -> 33554432 bytes
-rw-r--r--mkfs.md/mkfs.c90
-rw-r--r--mkfs.md/mkfs.mdbin0 -> 10016 bytes
-rw-r--r--mkfs.md/out2
-rw-r--r--run.sh21
-rw-r--r--test.sh10
-rw-r--r--tests/read_diferentes_offsets.py20
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/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
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
diff --git a/defs.h b/defs.h
new file mode 100644
index 0000000..d74abd5
--- /dev/null
+++ b/defs.h
@@ -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
diff --git a/dir.c b/dir.c
new file mode 100644
index 0000000..4b692bb
--- /dev/null
+++ b/dir.c
@@ -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;
+}
diff --git a/dir.h b/dir.h
new file mode 100644
index 0000000..8c04b05
--- /dev/null
+++ b/dir.h
@@ -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
new file mode 100644
index 0000000..3318d0b
--- /dev/null
+++ b/disk.mdfs
Binary files differ
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..71f84ac
--- /dev/null
+++ b/file.c
@@ -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);
+}
diff --git a/file.h b/file.h
new file mode 100644
index 0000000..0c0ac5e
--- /dev/null
+++ b/file.h
@@ -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;
+}
diff --git a/inode.c b/inode.c
new file mode 100644
index 0000000..556aad3
--- /dev/null
+++ b/inode.c
@@ -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;
+}
diff --git a/inode.h b/inode.h
new file mode 100644
index 0000000..7eee890
--- /dev/null
+++ b/inode.h
@@ -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
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..cfa1cf6
--- /dev/null
+++ b/log.c
@@ -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);
+}
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..384f0e6
--- /dev/null
+++ b/log.h
@@ -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
new file mode 100644
index 0000000..0dae906
--- /dev/null
+++ b/mkfs.md/disk.mdfs
Binary files differ
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
new file mode 100644
index 0000000..90a9507
--- /dev/null
+++ b/mkfs.md/mkfs.md
Binary files differ
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
diff --git a/run.sh b/run.sh
new file mode 100644
index 0000000..0beb5eb
--- /dev/null
+++ b/run.sh
@@ -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
diff --git a/test.sh b/test.sh
new file mode 100644
index 0000000..b86ee89
--- /dev/null
+++ b/test.sh
@@ -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!"