#include "medianin.h" #include #include #include #include #include #include #include #include #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; idisk_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); inum_from = dir_search(self->disk_mem, from_dir, basename((char *)from)); if(inum_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) uint16_t 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; }