Ejemplo n.º 1
0
int
s5_find_dirent(vnode_t *vnode, const char *name, size_t namelen)
{
    dbg_print("s5_find_dirent: Searching for Dir of Name: %s, Length: %i\n", name,namelen);
    s5_dirent_t traverse_dir;
    uint32_t offset = 0;

    int read = s5_read_file(vnode, offset, (char *) &traverse_dir, sizeof(s5_dirent_t));

    /* Loop through the inode blocks until the dirent is found. */
    while (read > 0)
    {
        dbg_print("s5_find_dirent: Temp Name: %s\n",traverse_dir.s5d_name);
        /* Once found, return. */
        if (name_match(traverse_dir.s5d_name, name, namelen))
        {
            dbg_print("s5_find_dirent: Found Directory!\n");
            return traverse_dir.s5d_inode;
        }
        offset += sizeof(s5_dirent_t);

        read = s5_read_file(vnode, offset, (char *) &traverse_dir, sizeof(s5_dirent_t));
    }

    /* If the function has not returned by this point, then dirent with parameter name DNE. */
    dbg_print("s5_find_dirent: Directory Not Found :(\n");
    return -ENOENT;
}
Ejemplo n.º 2
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;
        */
}
Ejemplo n.º 3
0
/*
 * s5fs_readdir:
 * s5fs_readdir reads one directory entry from the dir into the struct
 * dirent. On success, it returns the amount that offset should be
 * increased by to obtain the next directory entry with a
 * subsequent call to readdir. If the end of the file as been
 * reached (offset == file->vn_len), no directory entry will be
 * read and 0 will be returned.
 * param vnode: the pointer to the vnode object
 * param offset: the offset in the directory where you want to read
 * param d: the dirent object that needs to be filled
 * return: the bytes that have been read
 */
static int
s5fs_readdir(vnode_t *vnode, off_t offset, struct dirent *d)
{
    dbg(DBG_S5FS, "{\n");
    
    KASSERT(vnode != NULL);
    KASSERT(S_ISDIR(vnode->vn_mode));
    
    s5_dirent_t tmp;
    int bytes = 0;
    if ((bytes  = s5_read_file(vnode, offset,
                               (char*)&tmp, sizeof(s5_dirent_t))) < 0)
    {
        return bytes;
    }
    else if (bytes == 0)
    {
        return bytes;
    }
    
    d->d_ino = tmp.s5d_inode;
    memcpy(d->d_name, tmp.s5d_name, NAME_LEN);
    d->d_off = 0; /* unused */
    
    dbg(DBG_S5FS, "}\n");
    
    return bytes;
}
Ejemplo n.º 4
0
/*
 * See the comment in vnode.h for what is expected of this function.
 *
 * Here you need to use s5_read_file() to read a s5_dirent_t from a directory
 * and copy that data into the given dirent. The value of d_off is dependent on
 * your implementation and may or may not b e necessary.  Finally, return the
 * number of bytes read.
 */
static int s5fs_readdir(vnode_t *vnode, off_t offset, struct dirent *d)
{
    static int s5_dirent_size = sizeof(s5_dirent_t);

    KASSERT(vnode != NULL);
    KASSERT(d != NULL);
    KASSERT(offset <= vnode->vn_len);

    if (offset == vnode->vn_len){
        return 0;
    }    

    kmutex_lock(&vnode->vn_mutex);

    s5_dirent_t s5d;

    int read_res = s5_read_file(vnode, offset, (char *) &s5d, s5_dirent_size);

    KASSERT(read_res <= s5_dirent_size && "read too much!");

    if (read_res == s5_dirent_size){
        d->d_ino = s5d.s5d_inode;
        d->d_off = offset + s5_dirent_size;
        strcpy(d->d_name, s5d.s5d_name);
    } else {
        KASSERT(read_res < 0 && "bad offset or incomplete read");
        dbg(DBG_S5FS, "error reading dirent from file\n");
    }

    kmutex_unlock(&vnode->vn_mutex);
    return read_res;
}
Ejemplo n.º 5
0
/* Simply call s5_read_file. */
static int
s5fs_read(vnode_t *vnode, off_t offset, void *buf, size_t len)
{
    kmutex_lock(&vnode->vn_mutex);
    int ret = s5_read_file(vnode, offset, buf, len);
    kmutex_unlock(&vnode->vn_mutex);
    return ret;
}
Ejemplo n.º 6
0
/*
 * s5_find_dirent:
 * Locate the directory entry in the given inode with the given name,
 * and return its inode number.
 * return: the inode number, if there is no entry with the given
 * name, return -ENOENT.
 * param *vnode: the pointer to the vnode object
 * param name: name string
 * param namelen: the length of name
 * return: the inode number, or -ENOENT if there is no entry
 */
int
s5_find_dirent(vnode_t *vnode, const char *name, size_t namelen)
{
    dbg(DBG_S5FS, "{\n");

    KASSERT(vnode != NULL);
    KASSERT(namelen <= S5_NAME_LEN - 1);
    KASSERT(name != NULL);
    KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size);

    if (!namelen)
    {
        return 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)
        {
            /* error */
            dbg(DBG_S5FS, "}(error code returned)\n");
            return bytes;
        }
        else if (bytes == 0)
        {
            dbg(DBG_S5FS, "}(error code returned)\n");
            return -ENOENT;
        }
        else if (bytes != sizeof(s5_dirent_t))
        {
            dbg(DBG_S5FS, "}(error code returned)\n");
            return -1; /* not sure */
        }
        else
        {
            if (name_match(tmp.s5d_name, name, namelen))
            {
                dbg(DBG_S5FS, "}\n");
                return tmp.s5d_inode;
            }
            else
            {
                offset+= sizeof(s5_dirent_t);
            }
        }
    }

    KASSERT(0);
}
Ejemplo n.º 7
0
/* 
 * s5fs_read:
 * Simply call s5_read_file; should be in critical section
 * param *vnode: the pointer to the vnode object
 * param offset: offset in the file where you want to read
 * param *buf: the data should be stored here
 * param len: the length of the buffer
 * return: just return the result of s5_read_file
 */
static int
s5fs_read(vnode_t *vnode, off_t offset, 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_read_file(vnode, offset, buf, len);
    kmutex_unlock(&vnode->vn_mutex);
    
    dbg(DBG_S5FS, "}\n");
    
    return ret;
}
Ejemplo n.º 8
0
static int s5_find_dirent_helper(vnode_t *vnode, const char *name, size_t namelen,
        off_t *offset, int *ino){
    s5_dirent_t dirents[NDIRENTS];

    off_t seek = 0;

    while (seek < vnode->vn_len){
        int read_res = s5_read_file(vnode, seek, (char *) dirents, 
                NDIRENTS * sizeof(s5_dirent_t)); 

        KASSERT(seek + read_res <= vnode->vn_len);

        if (read_res < 0){
            dbg(DBG_S5FS, "error getting dirents\n");
            return read_res;
        }

        int dirents_read = read_res / sizeof(s5_dirent_t);

        int i;
        for (i = 0; i < dirents_read; i++){
            if (name_match(dirents[i].s5d_name, name, namelen)){
                if (offset != NULL){
                    *offset = seek + (i * sizeof(s5_dirent_t));
                }

                if (ino != NULL){
                    *ino = dirents[i].s5d_inode;
                }

                return 0;
            }            
        }
        seek += read_res;
    }

    return -ENOENT;
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
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;
}