Exemplo n.º 1
0
/*
 * Read up to len bytes from the given inode, starting at seek bytes
 * from the beginning of the inode. On success, return the number of
 * bytes actually read, or 0 if the end of the file has been reached; on
 * failure, return -errno.
 *
 * This function should allow reading from files or directories,
 * treating them identically.
 *
 * Reading from a sparse block of the file should act like reading
 * zeros; it should not cause the sparse blocks to be allocated.
 *
 * Similarly as in s5_write_file(), do not call s5_seek_to_block()
 * directly from this function.
 *
 * If the region to be read would extend past the end of the file, less
 * data will be read than was requested.
 *
 * You probably want to use pframe_get(), memcpy().
 */
int
s5_read_file(struct vnode *vnode, off_t seek, char *dest, size_t len)
{
    dbg_print("s5_read_file: Reading File, Length: %i\n",len);
    if(seek >= vnode->vn_len)
    {
        dbg_print("s5_read_file: Exiting with Value: 0\n");
        return 0;
    }

    int block_index = S5_DATA_BLOCK(seek);
    int block_offset = S5_DATA_OFFSET(seek);
    int length;
    
    if((int)len < vnode->vn_len - seek)
    {
        length = len;
    }
    else
    {
        length = vnode->vn_len - seek;
    }
    
    pframe_t *pf; 
    if(block_index < S5_NDIRECT_BLOCKS)
    {
        /*  Direct Block */    
        dbg_print("s5_read_file: Reading from Direct Block\n");
        pframe_get(&vnode->vn_mmobj, block_index, &pf);
        pframe_pin(pf);
        memcpy(dest,(char*)pf->pf_addr + block_offset, length);
    }
    else
    {
        s5_inode_t* inode = VNODE_TO_S5INODE(vnode);
        if(inode->s5_indirect_block != 0)
        {
            dbg_print("s5_read_file: Reading from INDIRECT Block\n");
            
            pframe_get(&vnode->vn_mmobj, inode->s5_indirect_block, &pf);
            pframe_pin(pf);

            memcpy(dest,(char*)pf->pf_addr + (block_index - S5_NDIRECT_BLOCKS), length);
        }
        else
        {
            return 0;
        }
    }

    pframe_unpin(pf);
    return length;
}
Exemplo n.º 2
0
/*
 * Read up to len bytes from the given inode, starting at seek bytes
 * from the beginning of the inode. On success, return the number of
 * bytes actually read, or 0 if the end of the file has been reached; on
 * failure, return -errno.
 *
 * This function should allow reading from files or directories,
 * treating them identically.
 *
 * Reading from a sparse block of the file should act like reading
 * zeros; it should not cause the sparse blocks to be allocated.
 *
 * Similarly as in s5_write_file(), do not call s5_seek_to_block()
 * directly from this function.
 *
 * If the region to be read would extend past the end of the file, less
 * data will be read than was requested.
 *
 * You probably want to use pframe_get(), memcpy().
 */
int
s5_read_file(struct vnode *vnode, off_t seek, char *dest, size_t len)
{   
    if (seek < 0){
        dbg(DBG_S5FS, "invalid seek value\n");
        return -EINVAL;
    } else if (seek >= vnode->vn_len){
        return 0;
    }

    off_t start_pos = seek;
    off_t end_pos = min(seek + len, vnode->vn_len);
            
    off_t destpos = 0;
    int get_res;
    int read_size;     
    pframe_t *p;

    while (start_pos + destpos < end_pos){
        int data_offset = S5_DATA_OFFSET(seek);

        get_res = pframe_get(&vnode->vn_mmobj, S5_DATA_BLOCK(seek), &p);

        if (get_res < 0){
            dbg(DBG_S5FS, "error getting page\n");
            return get_res;
        }
       
        read_size = min(PAGE_SIZE - data_offset, end_pos - seek);

        memcpy((void *) dest, (char *) p->pf_addr + data_offset, read_size);

        destpos += read_size;
        seek += read_size;
    }

    return destpos;
}
Exemplo n.º 3
0
/*
 * s5_read_file:
 * Read up to len bytes from the given inode, starting at seek bytes
 * from the beginning of the inode. On success, return the number of
 * bytes actually read, or 0 if the end of the file has been reached; on
 * failure, return -errno.
 * param *vnode: the pointer to the vnode object
 * param seek: the seek position
 * param *bytes: the destination buffer
 * param len: the length of the destination buffer in bytes
 * return: the number of bytes actually read; on failure, return -errno.
 */
int
s5_read_file(struct vnode *vnode, off_t seek, char *dest, size_t len)
{
    dbg(DBG_S5FS, "{\n");

    KASSERT(vnode != NULL);
    KASSERT(dest != NULL);
    KASSERT(PAGE_SIZE == S5_BLOCK_SIZE);
    KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size);

    if (seek >= vnode->vn_len)
    {
        return 0;/* EOF*/
    }

    uint32_t bytes  = 0;
    off_t start_pos = seek;
    int start_block = S5_DATA_BLOCK(start_pos);
    int ret         = 0;
    pframe_t* start = NULL;
    pframe_t* end   = NULL;

    ret = pframe_get(&vnode->vn_mmobj, start_block, &start);
    if (ret < 0)
    {
        return ret;
    }

    off_t end_pos = MIN(start_pos + (off_t)len, vnode->vn_len);
    int end_block = S5_DATA_BLOCK(end_pos);
    ret = pframe_get(&vnode->vn_mmobj, end_block, &end);
    if (ret < 0)
    {
        return ret;
    }

    if (start == end) /* page same */
    {
        pframe_pin(start);
        memcpy(dest, (char*)start->pf_addr + S5_DATA_OFFSET(start_pos),
               end_pos - start_pos);
        pframe_unpin(start);
        bytes = end_pos - start_pos;
    }
    else
    {
        /* copy the start page */
        pframe_pin(start);
        memcpy(dest, (char*)start->pf_addr + S5_DATA_OFFSET(start_pos),
               S5_BLOCK_SIZE-S5_DATA_OFFSET(start_pos));
        pframe_unpin(start);
        dest  += (S5_BLOCK_SIZE - S5_DATA_OFFSET(start_pos));
        bytes += (S5_BLOCK_SIZE - S5_DATA_OFFSET(start_pos));
        /* find next page */
        int off = start_pos + S5_BLOCK_SIZE - S5_DATA_OFFSET(start_pos);

        while(1)
        {
            pframe_t* tmp = NULL;
            int block_number = S5_DATA_BLOCK(off);
            ret = pframe_get(&vnode->vn_mmobj, block_number, &tmp);
            if (tmp == NULL)
            {
                dbg(DBG_S5FS, "}(error code returned)\n");
                return ret;
            }
            if (tmp == end)
            {
                break;
            } else
            {
                pframe_pin(tmp);
                memcpy(dest, tmp->pf_addr, S5_BLOCK_SIZE);
                pframe_unpin(tmp);
                dest  += S5_BLOCK_SIZE;/* shift the dest pointer */
                bytes += S5_BLOCK_SIZE;
            }
        }
        pframe_pin(end);
        memcpy(dest, end->pf_addr, len - bytes);
        pframe_unpin(end);
        bytes = len;
        dbg(DBG_S5FS, "}\n");
    }

    return bytes;
}
Exemplo n.º 4
0
/*
 * s5_write_file:
 * write len bytes to the given inode, starting at seek bytes from the
 * beginning of the inode. On success,
 * param *vnode: the pointer to the vnode object
 * param seek: the seek position
 * param *bytes: the source buffer
 * param len: the length of the source buffer in bytes
 * return: the number of bytes actually written; on failure, return -errno.
 */
int
s5_write_file(vnode_t *vnode, off_t seek, const char *bytes, size_t len)
{
    dbg(DBG_S5FS, "{\n");

    KASSERT(vnode != NULL);
    KASSERT(bytes != NULL);
    KASSERT(PAGE_SIZE == S5_BLOCK_SIZE);
    KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size);

    off_t start_pos = seek;
    off_t start_block_offset = S5_DATA_OFFSET(start_pos);
    off_t end_pos          = MIN(seek + len, S5_MAX_FILE_BLOCKS*PAGE_SIZE);
    off_t end_block_offset = S5_DATA_OFFSET(end_pos);

    int start_block = S5_DATA_BLOCK(start_pos);
    int end_block   = S5_DATA_BLOCK(end_pos);
    int ret = 0;
    pframe_t* start = NULL;
    ret = pframe_get(&vnode->vn_mmobj, start_block, &start);
    if (ret < 0)
    {
        dbg(DBG_S5FS, "}(error code returend)\n");
        return ret;
    }

    pframe_t* end = NULL;
    ret = pframe_get(&vnode->vn_mmobj, end_block, &end);
    if (ret < 0)
    {
        dbg(DBG_S5FS, "}(error code returend)\n");
        return ret;
    }
    uint32_t num_bytes = 0;
    if (start == end)
    {
        pframe_pin(start);
        memcpy((char*)start->pf_addr + start_block_offset, bytes, len);

        KASSERT((char*)start->pf_addr + start_block_offset + len ==
                (char*)start->pf_addr + end_block_offset);
        /* dirty the page */
        pframe_dirty(start);
        pframe_unpin(start);

        num_bytes = len;
        s5_inode_t* inode = VNODE_TO_S5INODE(vnode );
        inode->s5_size    = MAX(end_pos, vnode->vn_len);
        vnode->vn_len     = inode->s5_size;
        s5_dirty_inode(VNODE_TO_S5FS(vnode),inode);
    }
    else
    {
        /* copy the start block */
        pframe_pin(start);
        memcpy((char*)start->pf_addr + start_block_offset, bytes,
               S5_BLOCK_SIZE - start_block_offset);
        bytes     += S5_BLOCK_SIZE - start_block_offset;
        num_bytes += S5_BLOCK_SIZE - start_block_offset;
        pframe_dirty(start);
        pframe_unpin(start);

        s5_inode_t* inode = VNODE_TO_S5INODE(vnode );
        inode->s5_size    = MAX(start_pos + num_bytes, (uint32_t)vnode->vn_len);
        vnode->vn_len     = inode->s5_size;
        while (1)
        {
            pframe_t* tmp;
            int block_number = S5_DATA_BLOCK(start_pos + num_bytes );
            ret = pframe_get(&vnode->vn_mmobj, block_number, &tmp);
            if (tmp == NULL)
            {
                VNODE_TO_S5INODE(vnode)->s5_size = MAX(start_pos + num_bytes,
                                                       (uint32_t)vnode->vn_len);
                vnode->vn_len = VNODE_TO_S5INODE(vnode)->s5_size;
                s5_dirty_inode(VNODE_TO_S5FS(vnode),inode);
                return ret;
            }
            if (tmp == end)
            {
                break;
            }
            pframe_pin(tmp);
            memcpy(tmp->pf_addr, bytes, S5_BLOCK_SIZE);
            pframe_dirty(tmp);
            pframe_unpin(tmp);
            bytes     += S5_BLOCK_SIZE;
            num_bytes += S5_BLOCK_SIZE;
        }
        /* copy the last one */

        pframe_pin(end);
        memcpy(end->pf_addr, bytes, len - num_bytes);
        num_bytes += len - num_bytes; /* len */
        pframe_dirty(end);
        pframe_unpin(end);

        /* add the size */
        inode->s5_size = MAX(end_pos, vnode->vn_len);
        s5_dirty_inode(VNODE_TO_S5FS(vnode),inode);
        vnode->vn_len = inode->s5_size;
    }
    KASSERT((uint32_t)vnode->vn_len == VNODE_TO_S5INODE(vnode)->s5_size);
    dbg(DBG_S5FS, "}\n");

    return num_bytes;
}
Exemplo n.º 5
0
/*
 * Write len bytes to the given inode, starting at seek bytes from the
 * beginning of the inode. On success, return the number of bytes
 * actually written (which should be 'len', unless there's only enough
 * room for a partial write); on failure, return -errno.
 *
 * This function should allow writing to files or directories, treating
 * them identically.
 *
 * Writing to a sparse block of the file should cause that block to be
 * allocated.  Writing past the end of the file should increase the size
 * of the file. Blocks between the end and where you start writing will
 * be sparse.
 *
 * Do not call s5_seek_to_block() directly from this function.  You will
 * use the vnode's pframe functions, which will eventually result in a
 * call to s5_seek_to_block().
 *
 * You will need pframe_dirty(), pframe_get(), memcpy().
 */
int
s5_write_file(vnode_t *vnode, off_t seek, const char *bytes, size_t len)
{
    if (seek < 0){
        dbg(DBG_S5FS, "invalid seek value\n");
        return -EINVAL;
    }

    if (seek + len >= S5_MAX_FILE_SIZE){
        len = S5_MAX_FILE_SIZE - seek - 1;
    }

    /* extend file size, if necessary */
    uint32_t newlength = max(seek + len, vnode->vn_len);
/*    if (seek + len > (unsigned) vnode->vn_len){*/
        /*vnode->vn_len = seek + len;*/
        /*VNODE_TO_S5INODE(vnode)->s5_size = vnode->vn_len;*/
        /*s5_dirty_inode(VNODE_TO_S5FS(vnode), VNODE_TO_S5INODE(vnode));*/
    /*}*/

    off_t start_pos = seek;
    /*off_t end_pos = min(seek + len, vnode->vn_len);*/
    off_t end_pos = min(seek + len, newlength);

    unsigned int srcpos = 0;
    int get_res;
    int write_size;
    pframe_t *p;

    uint32_t err = 0;

    while (srcpos < len){
        int data_offset = S5_DATA_OFFSET(seek);

        get_res = pframe_get(&vnode->vn_mmobj, S5_DATA_BLOCK(seek), &p);

        if (get_res < 0){
            dbg(DBG_S5FS, "error getting page\n");
            err = get_res;
            break;
        }

        write_size = min(PAGE_SIZE - data_offset, end_pos - seek);

        KASSERT(write_size >= 0 && "write size is negative");
        memcpy((char *) p->pf_addr + data_offset, (void *) bytes, write_size);
        int dirty_res = pframe_dirty(p);

        if (dirty_res < 0){
            err = dirty_res;
            break;
        }

        srcpos += write_size;
        seek += write_size; 
    }

    if (seek > vnode->vn_len){
        vnode->vn_len = seek;
        VNODE_TO_S5INODE(vnode)->s5_size = vnode->vn_len;
        s5_dirty_inode(VNODE_TO_S5FS(vnode), VNODE_TO_S5INODE(vnode));
    }

    return err ? err : srcpos;
}
Exemplo n.º 6
0
/*
 * Write len bytes to the given inode, starting at seek bytes from the
 * beginning of the inode. On success, return the number of bytes
 * actually written (which should be 'len', unless there's only enough
 * room for a partial write); on failure, return -errno.
 *
 * This function should allow writing to files or directories, treating
 * them identically.
 *
 * Writing to a sparse block of the file should cause that block to be
 * allocated.  Writing past the end of the file should increase the size
 * of the file. Blocks between the end and where you start writing will
 * be sparse.
 *
 * Do not call s5_seek_to_block() directly from this function.  You will
 * use the vnode's pframe functions, which will eventually result in a
 * call to s5_seek_to_block().
 *
 * You will need pframe_dirty(), pframe_get(), memcpy().
 */
int
s5_write_file(vnode_t *vnode, off_t seek, const char *bytes, size_t len)
{
    dbg_print("s5_write_file: Writing to File, Length: %i\n",len);

    uint32_t to_write = len;

    /* Block Number */
    uint32_t block_index = S5_DATA_BLOCK(seek);
    if(block_index >= S5_MAX_FILE_BLOCKS)
    {
        dbg_print("s5_write_file: Exiting with Value: 0\n");
        return 0;
    }

    /* Offset within block */
    uint32_t block_offset = S5_DATA_OFFSET(seek);
    uint32_t remaining = S5_BLOCK_SIZE - block_offset;
    int total_written = 0;

    s5_inode_t* inode = VNODE_TO_S5INODE(vnode);
    s5fs_t* dir_fs = VNODE_TO_S5FS(vnode);

    if(seek >= vnode->vn_len)
    {
        /* End to Start of Writing should be written as sparse */

    }

    while(to_write > 0)
    {
        pframe_t* pf;
        pframe_get(&(vnode->vn_mmobj),block_index,&pf);
        pframe_pin(pf);

        if(to_write <= remaining)
        {
            memcpy((char*)pf->pf_addr + block_offset,bytes + total_written,to_write);
            total_written += to_write;
            block_offset = 0;
            to_write = 0;
        }
        else
        {
            /* to_write > remaining */
            memcpy((char*)pf->pf_addr + block_offset,bytes + total_written,remaining);
            total_written += remaining;
            block_offset = 0;
            to_write -= remaining;

            block_index++;
            remaining = S5_BLOCK_SIZE;
            if(block_index == S5_MAX_FILE_BLOCKS)
            {
                break;
            }
        }
        pframe_dirty(pf);
        pframe_unpin(pf);
    }

    if(seek + total_written > vnode->vn_len)
    {
        vnode->vn_len = seek + total_written;
        inode->s5_size = seek + total_written;
    }
    s5_dirty_inode(dir_fs,inode);
    return total_written;
}