/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }