Example #1
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;
        */
}
Example #2
0
/* Simply call s5_write_file. */
static int
s5fs_write(vnode_t *vnode, off_t offset, const void *buf, size_t len)
{
    kmutex_lock(&vnode->vn_mutex);
    int ret = s5_write_file(vnode, offset, buf, len);
    kmutex_unlock(&vnode->vn_mutex);
    return ret;
}
Example #3
0
/*
 * s5fs_write:
 * Simply call s5_write_file; should be in critical section
 * param *vnode: the pointer to the vnode object
 * param offset: the offset in the file where you want to write
 * param *buf: the source buffer
 * param len: the length of the buffer
 * return: just return the result of s5_write_file
 */
static int
s5fs_write(vnode_t *vnode, off_t offset, const void *buf, size_t len)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(vnode != NULL);
    KASSERT(buf != NULL);
    int ret = 0;
    kmutex_lock(&vnode->vn_mutex);
    ret = s5_write_file(vnode, offset, buf, len);
    kmutex_unlock(&vnode->vn_mutex);
    
    dbg(DBG_S5FS, "}\n");
    
    return ret;
}
Example #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;
    }
}
Example #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;
}
Example #6
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;
        }
}
Example #7
0
/*
 * s5_remove_dirent:
 * 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.
 * param *vnode: the pointer to the vnode object
 * param *name: the name string
 * param namelen: the length of the name string
 * return: 0 on success and -ENOENT if there is no entry
 */
int
s5_remove_dirent(vnode_t *vnode, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");

    KASSERT(vnode != NULL);
    KASSERT(name != NULL);
    KASSERT(namelen <= S5_NAME_LEN - 1);
    KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size);
    KASSERT(vnode->vn_len%sizeof(s5_dirent_t) == 0);
    s5_dirent_t tmp;

    off_t offset = 0;
    while (1)
    {
        int bytes = s5_read_file(vnode, offset, (char*)&tmp, sizeof(s5_dirent_t));

        if (bytes < 0)
        {
            return bytes;
        }
        else if (bytes == 0)
        {
            return -ENOENT;
        }
        else if (bytes != sizeof(s5_dirent_t))
        {
            return -1;
        }
        else
        {
            if (name_match(tmp.s5d_name, name, namelen))
            {
                if (offset + (off_t)sizeof(s5_dirent_t) < vnode->vn_len)
                {
                    s5_dirent_t last_dirent;
                    int bytes2 = s5_read_file(vnode, vnode->vn_len - sizeof(s5_dirent_t),
                                              (char*)&last_dirent, sizeof(s5_dirent_t));
                    if (bytes2 < 0)
                    {
                        return bytes2;
                    }
                    else if (bytes2 != sizeof(s5_dirent_t))
                    {
                        return -1;
                    }
                    else
                    {
                        bytes2 = s5_write_file(vnode, offset, (char*)&last_dirent,
                                               sizeof(s5_dirent_t));
                        if (bytes2 < 0)
                        {
                            return bytes2;
                        }
                    }
                }

                vnode->vn_len -= sizeof(s5_dirent_t);
                s5_inode_t* inode = VNODE_TO_S5INODE(vnode );
                inode->s5_size = vnode->vn_len;
                s5_dirty_inode(VNODE_TO_S5FS(vnode),inode);

                vnode_t* vn = vget(vnode->vn_fs,tmp.s5d_inode);

                KASSERT(vn);
                s5_inode_t* remove_inode = VNODE_TO_S5INODE(vn);
                remove_inode->s5_linkcount--;
                s5_dirty_inode(FS_TO_S5FS(vn->vn_fs), remove_inode);
                vput(vn);

                return 0;
            }
            else
            {
                offset+= sizeof(s5_dirent_t);
            }
        }
    }
    KASSERT(0);
}
Example #8
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)
{
    static unsigned int dirent_size = sizeof(s5_dirent_t);

    KASSERT(vnode->vn_ops->mkdir != NULL);

    int deleted_ino;
    off_t dir_offset;

    int find_res = 
        s5_find_dirent_helper(vnode, name, namelen, &dir_offset, &deleted_ino);

    if (find_res == -ENOENT){
        dbg(DBG_S5FS, "couldn't find specified dirent\n");
        return -ENOENT;
    }

    KASSERT(find_res == 0 && "you missed an error case");
    KASSERT((unsigned) vnode->vn_len >= dir_offset + dirent_size);

    /* if the dirent to remove isn't the last dirent, we need to
     * copy the last dirent into its place */
    if ((unsigned) vnode->vn_len > dir_offset + dirent_size){
        KASSERT((unsigned) vnode->vn_len >= dir_offset + (2 * dirent_size));

        s5_dirent_t to_move;

        int read_res = s5_read_file(vnode, vnode->vn_len - dirent_size,
                (char *) &to_move, dirent_size);

        if (read_res < 0){
            dbg(DBG_S5FS, "error reading final dirent in directory\n");
            return read_res;
        }

        int write_res = s5_write_file(vnode, dir_offset,
                (char *) &to_move, dirent_size);

        if (write_res < 0){
            dbg(DBG_S5FS, "error overwriting dirent to remove with last dirent\n");
            return write_res;
        }
    }

    s5fs_t *fs = VNODE_TO_S5FS(vnode);

    /* decrease the length of the directory file */
    s5_inode_t *dir_inode = VNODE_TO_S5INODE(vnode);

    vnode->vn_len -= dirent_size;     

    dir_inode->s5_size -= dirent_size;
    s5_dirty_inode(fs, dir_inode);

    /* decrement the linkcount on the unlinked file */
    vnode_t *deleted_vnode = vget(fs->s5f_fs, deleted_ino);
    s5_inode_t *deleted_inode = VNODE_TO_S5INODE(deleted_vnode);

    deleted_inode->s5_linkcount--;

    KASSERT(deleted_inode->s5_linkcount >= 0 && "linkcount went below 0!");

    s5_dirty_inode(fs, deleted_inode);

    vput(deleted_vnode);

    return 0;
}