aboutsummaryrefslogtreecommitdiff
path: root/medianin.c
diff options
context:
space:
mode:
Diffstat (limited to 'medianin.c')
-rw-r--r--medianin.c667
1 files changed, 667 insertions, 0 deletions
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;
+}