Exemplo n.º 1
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * When this function returns, the inode refcount on the parent should be
 * decremented (since ".." in the removed directory no longer references
 * it). Remember that the directory must be empty (except for "." and
 * "..").
 *
 * You probably want to use s5_find_dirent() and s5_remove_dirent().
 */
static int
s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen)
{
    KASSERT(!(namelen == 1 && name[0] == '.'));
    KASSERT(!(namelen == 2 && name[0] == '.' && name[1] == '.'));
    KASSERT(parent->vn_ops->rmdir != NULL);

    kmutex_lock(&parent->vn_mutex);

    int ino = s5_find_dirent(parent, name, namelen);

    /* we check in do_rmdir to make sure the directory exists */
    KASSERT(ino != -ENOENT);

    if (ino < 0){
        dbg(DBG_S5FS, "error finding child dir to delete\n");
        kmutex_unlock(&parent->vn_mutex);
        return ino;
    }

    vnode_t *child = vget(VNODE_TO_S5FS(parent)->s5f_fs, ino);
    kmutex_lock(&child->vn_mutex);

    int dot_lookup_res = s5_find_dirent(child, ".", 1);
    int dotdot_lookup_res = s5_find_dirent(child, "..", 2);

    KASSERT(dot_lookup_res != -ENOENT && dotdot_lookup_res != -ENOENT);

    if (dot_lookup_res < 0 || dotdot_lookup_res < 0){
        dbg(DBG_S5FS, "error reading dirents of directory to delete\n");
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&parent->vn_mutex);
        return (dot_lookup_res < 0) ? dot_lookup_res : dotdot_lookup_res;
    }

    KASSERT((unsigned) child->vn_len >= 2 * sizeof(s5_dirent_t));

    if ((unsigned) child->vn_len > 2 * sizeof(s5_dirent_t)){
        vput(child);
        kmutex_unlock(&child->vn_mutex);
        kmutex_unlock(&parent->vn_mutex);
        return -ENOTEMPTY;
    }

    vput(child);

    VNODE_TO_S5INODE(parent)->s5_linkcount--;
    s5_dirty_inode(VNODE_TO_S5FS(parent), VNODE_TO_S5INODE(parent));

    kmutex_unlock(&child->vn_mutex);
    kmutex_unlock(&parent->vn_mutex);
    return s5_remove_dirent(parent, name, namelen);
}
Exemplo n.º 2
0
/*
 * s5fs_lookup:
 * s5fs_lookup sets *result to the vnode in dir with the specified name.
 * param *base: the vnode object of the base directory
 * param *name: name string
 * param namelen: the length of the name
 * param **result: *result points to the vnode in dir with the specified name
 * return: 0 on success; negative number on a variety of errors
 */
int
s5fs_lookup(vnode_t *base, const char *name, size_t namelen, vnode_t **result)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(base != NULL);
    KASSERT(name != NULL);
    KASSERT(namelen <= S5_NAME_LEN-1);
    
    kmutex_lock(&base->vn_mutex);
    
    int inode_number = 0;
    if ((inode_number = s5_find_dirent(base, name, namelen)) < 0)
    {
        kmutex_unlock(&base->vn_mutex);
        return inode_number;
    }
    /* May block here */
    /* No modification, no need to lock */
    *result = vget(base->vn_fs, inode_number);
    
    kmutex_unlock(&base->vn_mutex);
    
    dbg(DBG_S5FS, "}\n");
    return 0;
}
Exemplo n.º 3
0
/*
 * Locate the directory entry in the given inode with the given name,
 * and delete it. If there is no entry with the given name, return
 * -ENOENT.
 *
 * In order to ensure that the directory entries are contiguous in the
 * directory file, you will need to move the last directory entry into
 * the remove dirent's place.
 *
 * When this function returns, the inode refcount on the removed file
 * should be decremented.
 *
 * It would be a nice extension to free blocks from the end of the
 * directory file which are no longer needed.
 *
 * Don't forget to dirty appropriate blocks!
 *
 * You probably want to use vget(), vput(), s5_read_file(),
 * s5_write_file(), and s5_dirty_inode().
 */
int
s5_remove_dirent(vnode_t *vnode, const char *name, size_t namelen)
{
    dbg_print("s5_remove_dirent: Removing Dirent");
    int inode = s5_find_dirent(vnode,name,namelen);
    if(inode == -ENOENT)
    {
        dbg_print("s5_remove_dirent: ERROR, Directory not found");
        return -ENOENT;
    }
    else
    {
        vnode_t* vnode_to_remove = vget(vnode->vn_fs,inode);
        s5_inode_t* inode_to_remove = VNODE_TO_S5INODE(vnode_to_remove);
        inode_to_remove->s5_linkcount--;
        vput(vnode_to_remove);

        /* Need to get the offset of where the dirent is */
        int total_count = 0;
        int dir_index = 0;

        /* Loop through the inode blocks until the dirent is found. */
        s5_dirent_t traverse_dir;
        while (s5_read_file(vnode, dir_index * sizeof(s5_dirent_t), (char *) &traverse_dir, sizeof(s5_dirent_t)) > 0)
        {
            /* Once found, return. */
            if (name_match(traverse_dir.s5d_name, name, namelen))
            {
                dir_index = total_count;
            }
            total_count++;
        }
        total_count--;

        if(dir_index != total_count)
        {
            /* swap dir with last */
            char* last_buffer = kmalloc(sizeof(s5_dirent_t));
            s5_dirent_t* dirent = (s5_dirent_t*)last_buffer;
            int read = s5_read_file(vnode,vnode->vn_len - sizeof(s5_dirent_t),last_buffer,sizeof(s5_dirent_t));
            KASSERT(read == sizeof(s5_dirent_t));

            int write = s5_write_file(vnode, dir_index * sizeof(s5_dirent_t), last_buffer, sizeof(s5_dirent_t));
            KASSERT(write == sizeof(s5_dirent_t));
        }

        s5_inode_t* inode = VNODE_TO_S5INODE(vnode);

        vnode->vn_len -= sizeof(s5_dirent_t);
        inode->s5_size -= sizeof(s5_dirent_t);

        s5_dirty_inode(VNODE_TO_S5FS(vnode),inode);

        return 0;
    }
        /* NOT_YET_IMPLEMENTED("S5FS: s5_remove_dirent");
        * return -1;
        */
}
Exemplo n.º 4
0
/*
 * s5_link:
 * Create a new directory entry in directory 'parent' with the given name, which
 * refers to the same file as 'child'.
 * param *parent: the pointer to the parent vnode object of the vnode child
 * param *child: the pointer to the child vnode object
 * param *name: name string
 * param namelen: the length of the name
 * return: bytes that has been added to the parent's block, or negative number
 *         on failure
 */
int
s5_link(vnode_t *parent, vnode_t *child, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");

    KASSERT(parent != NULL);
    KASSERT(child != NULL);
    KASSERT(name != NULL);
    KASSERT(S_ISDIR(parent->vn_mode));
    KASSERT((uint32_t)parent->vn_len == VNODE_TO_S5INODE(parent)->s5_size);
    KASSERT((uint32_t)child->vn_len == VNODE_TO_S5INODE(child)->s5_size);

    int exist = s5_find_dirent(parent, name, namelen);
    if (exist >= 0)
    {
        return -1;
    }
    else
    {
        s5_inode_t* child_inode = VNODE_TO_S5INODE(child);
        ino_t child_inode_num   = child_inode->s5_number;
        KASSERT(child_inode_num == child->vn_vno);

        s5_dirent_t dirent;
        memcpy(dirent.s5d_name, name, S5_NAME_LEN);
        KASSERT(dirent.s5d_name[namelen] == '\0');

        dirent.s5d_inode = child_inode_num;
        s5_inode_t* inode_parent = VNODE_TO_S5INODE(parent);

        KASSERT((uint32_t)parent->vn_len == inode_parent->s5_size);
        int bytes = s5_write_file(parent, inode_parent->s5_size,
                                  (char*)&dirent, sizeof(s5_dirent_t));
        if (bytes == sizeof(s5_dirent_t))
        {
            /* If not '.' or '..', we need to add the link */
            if (!name_match(name, ".", 1))
            {
                child_inode->s5_linkcount++;
                s5_dirty_inode(VNODE_TO_S5FS(child), child_inode);
            }
            dbg(DBG_S5FS, "}\n");
            return 0;
        }
        return bytes;
    }
}
Exemplo n.º 5
0
/*
 * Create a new directory entry in directory 'parent' with the given name, which
 * refers to the same file as 'child'.
 *
 * When this function returns, the inode refcount on the file that was linked to
 * should be incremented.
 *
 * Remember to increment the ref counts appropriately
 *
 * You probably want to use s5_find_dirent(), s5_write_file(), and s5_dirty_inode().
 */
int
s5_link(vnode_t *parent, vnode_t *child, const char *name, size_t namelen)
{
    KASSERT(parent->vn_ops->mkdir != NULL);
    KASSERT(s5_find_dirent(parent, name, namelen) < 0 && "file exists\n");

    int init_refcount = VNODE_TO_S5INODE(child)->s5_linkcount;

    s5_dirent_t d;
    d.s5d_inode = VNODE_TO_S5INODE(child)->s5_number;
    memcpy(d.s5d_name, name, namelen);
    d.s5d_name[namelen] = '\0';

    off_t write_offset = parent->vn_len; /*find_empty_dirent(parent);*/

    if (write_offset < 0){
        dbg(DBG_S5FS, "error finding dirent to write to\n");
    }

    int res = s5_write_file(parent, write_offset, (char *) &d,
            sizeof(s5_dirent_t));

    if (res < 0){
        dbg(DBG_S5FS, "error writing child entry in parent\n");
        return res;
    }

    s5_dirty_inode(VNODE_TO_S5FS(parent), VNODE_TO_S5INODE(parent));

    if (parent != child){
        dbg(DBG_S5FS, "incrementing link count on inode %d from %d to %d\n",
            VNODE_TO_S5INODE(child)->s5_number, VNODE_TO_S5INODE(child)->s5_linkcount,
            VNODE_TO_S5INODE(child)->s5_linkcount + 1);

        VNODE_TO_S5INODE(child)->s5_linkcount++;
        s5_dirty_inode(VNODE_TO_S5FS(child), VNODE_TO_S5INODE(child));

        KASSERT(VNODE_TO_S5INODE(child)->s5_linkcount == init_refcount + 1 &&
                "link count not incremented properly");
    }

    return 0;
}
Exemplo n.º 6
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * You probably want to use s5_find_dirent() and vget().
 */
int
s5fs_lookup(vnode_t *base, const char *name, size_t namelen, vnode_t **result)
{
    kmutex_lock(&base->vn_mutex);
    int ino = s5_find_dirent(base, name, namelen);

    if (ino == -ENOENT){
        kmutex_unlock(&base->vn_mutex);
        return -ENOENT;
    }

    KASSERT(ino >= 0 && "forgot an error case\n");

    vnode_t *child = vget(VNODE_TO_S5FS(base)->s5f_fs, ino);

    KASSERT(child != NULL);

    *result = child;

    kmutex_unlock(&base->vn_mutex);
    return 0;
}
Exemplo n.º 7
0
/*
 * Create a new directory entry in directory 'parent' with the given name, which
 * refers to the same file as 'child'.
 *
 * When this function returns, the inode refcount on the file that was linked to
 * should be incremented.
 *
 * Remember to incrament the ref counts appropriately
 *
 * You probably want to use s5_find_dirent(), s5_write_file(), and s5_dirty_inode().
 */
int
s5_link(vnode_t *parent, vnode_t *child, const char *name, size_t namelen)
{
        /* NOT_YET_IMPLEMENTED("S5FS: s5_link");
        * return -1;
        */
        dbg_print("s5_link: Linking!\n");
        s5_inode_t* child_inode = VNODE_TO_S5INODE(child);

        if(s5_find_dirent(parent,name,namelen) >= 0)
        {
            /* Directory already exists */
            dbg_print("s5_link: Directory Already Exists, Name: %s\n",name);
            return -1;
        }
        else
        {
            s5_dirent_t* new_dir = kmalloc(sizeof(s5_dirent_t));
            /* memset(new_dir, 0, sizeof(s5_dirent_t)); */
            new_dir->s5d_inode = child_inode->s5_number;
            /* Copy Over name for Directory */
            memcpy(new_dir->s5d_name,name,namelen);
            new_dir->s5d_name[namelen] = '\0';

            int write_dir = s5_write_file(parent,parent->vn_len,(char*)new_dir,sizeof(s5_dirent_t));
            KASSERT(write_dir == sizeof(s5_dirent_t));

            /* Increment indoe refcount */
            dbg_print("s5_link: Incrementing Linkcount for Inode: %s\n",name);
            child_inode->s5_linkcount++;
            dbg_print("s5_link: Linkcount for Inode: %s is: %i\n",name,child_inode->s5_linkcount);
            s5_dirty_inode(VNODE_TO_S5FS(parent),child_inode);
            kfree(new_dir);
            return 0;
        }
}
Exemplo n.º 8
0
/*
 * s5fs_rmdir:
 * s5fs_rmdir removes the directory called name from dir. the directory
 * to be removed must be empty (except for . and .. of course).
 * param *parent: the pointer to the parent dir of the name specified
 * param *name: name string
 * param namelen: the length of the name string
 * return: 0 on success; negative numbers on a variety of errors
 */
static int
s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(parent != NULL);
    KASSERT(name != NULL);
    KASSERT(namelen <= NAME_LEN - 1);
    KASSERT((uint32_t)parent->vn_len == VNODE_TO_S5INODE(parent)->s5_size);
    
    kmutex_lock(&parent->vn_mutex);
    
    int inode_number = 0;
    if ((inode_number = s5_find_dirent(parent, name, namelen)) < 0)
    {
        kmutex_unlock(&parent->vn_mutex);
        /* Need vput? */
        return inode_number;
    }
    
    /* May block here */
    vnode_t* vn = vget(parent->vn_fs, inode_number);
    KASSERT(vn != NULL);
    
    if (!S_ISDIR(vn->vn_mode))
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&parent->vn_mutex);
        return -ENOTDIR;
    }
    
    /* Check empty */
    if (VNODE_TO_S5INODE(vn)->s5_size > sizeof(dirent_t)*2)
    {
        vput(vn);
        kmutex_unlock(&parent->vn_mutex);
        return -ENOTEMPTY;
    }
    
    int ret;
    if ((ret = s5_remove_dirent(parent, name, namelen)) < 0)
    {
        /* May block here */
        vput(vn);
        kmutex_unlock(&parent->vn_mutex);
        return ret;
    }
    /* Decrease the linkcount because .. is removed */
    s5_inode_t* parent_inode = VNODE_TO_S5INODE(parent);
    parent_inode->s5_linkcount--;
    s5_dirty_inode(VNODE_TO_S5FS(parent), parent_inode);
    
    /* May block here */
    vput(vn);
    kmutex_unlock(&parent->vn_mutex);
    
    dbg(DBG_S5FS, "}\n");
    
    return ret;
}