diff options
Diffstat (limited to 'medianin.c')
-rw-r--r-- | medianin.c | 667 |
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; +} |