/* * Return the disk-block number for the given seek pointer (aka file * position). * * If the seek pointer refers to a sparse block, and alloc is false, * then return 0. If the seek pointer refers to a sparse block, and * alloc is true, then allocate a new disk block (and make the inode * point to it) and return it. * * Be sure to handle indirect blocks! * * If there is an error, return -errno. * * You probably want to use pframe_get, pframe_pin, pframe_unpin, pframe_dirty. */ int s5_seek_to_block(vnode_t *vnode, off_t seekptr, int alloc) { int block_index = S5_DATA_BLOCK(seekptr); if ((unsigned) block_index >= S5_MAX_FILE_BLOCKS){ dbg(DBG_S5FS, "file too large"); return -EFBIG; } if (seekptr > vnode->vn_len && !alloc){ return 0; } s5_inode_t *inode = VNODE_TO_S5INODE(vnode); uint32_t block_num; if (block_index >= S5_NDIRECT_BLOCKS){ pframe_t *ind_page; mmobj_t *mmo = S5FS_TO_VMOBJ(VNODE_TO_S5FS(vnode)); if (inode->s5_indirect_block == 0){ if (!alloc){ return 0; } int alloc_res = alloc_indirect_block(vnode); if (alloc_res < 0){ dbg(DBG_S5FS, "error allocating indirect block\n"); return alloc_res; } } if (pframe_get(mmo, inode->s5_indirect_block, &ind_page) < 0){ panic("an indirect block is messed up\n"); } block_num = ((uint32_t *) ind_page->pf_addr)[block_index - S5_NDIRECT_BLOCKS]; /* case where we've found a sparse block and need to allocate*/ if (block_num == 0 && alloc){ pframe_pin(ind_page); int block_num = s5_alloc_block(VNODE_TO_S5FS(vnode)); pframe_unpin(ind_page); if (block_num == -ENOSPC){ dbg(DBG_S5FS, "couldn't alloc a new block\n"); return -ENOSPC; } KASSERT(block_num > 0 && "forgot to handle an error case"); ((uint32_t *) ind_page->pf_addr)[block_index - S5_NDIRECT_BLOCKS] = block_num; int dirty_res = pframe_dirty(ind_page); if (dirty_res < 0){ return dirty_res; } } } else { block_num = inode->s5_direct_blocks[block_index]; /* case where we've found a sparse block and need to allocate*/ if (block_num == 0 && alloc){ int block_num = s5_alloc_block(VNODE_TO_S5FS(vnode)); if (block_num == -ENOSPC){ dbg(DBG_S5FS, "couldn't alloc a new block\n"); return -ENOSPC; } KASSERT(block_num > 0 && "forgot to handle an error case"); inode->s5_direct_blocks[block_index] = block_num; s5_dirty_inode(VNODE_TO_S5FS(vnode), inode); } } return block_num; }
int _write(t_ext2* ext2,int fd, const void *buf,u32 count) { u32 i; u32 first_inode_block; u32 first_data_offset; u32 last_inode_block; u32 last_data_offset; u32 inode_block; u32 lba; u32 indirect_lba; u32 indirect_old_lba; u32 sector_count; u32 byte_to_read; u32 byte_read; u32 byte_count; u32 load_block; u32 update_indirct_block; t_inode* inode; char* iob_data_block; char* iob_indirect_block; u32 update_indirect_block; u32 byte_written; u32 byte_to_write; iob_data_block=kmalloc(BLOCK_SIZE); iob_indirect_block=kmalloc(BLOCK_SIZE); kfillmem(iob_data_block,0,BLOCK_SIZE); kfillmem(iob_indirect_block,0,BLOCK_SIZE); update_indirect_block=FALSE; byte_written=0; inode=hashtable_get(((struct t_process_context*)system.process_info->current_process)->file_desc,fd); first_inode_block=inode->file_offset/BLOCK_SIZE; first_data_offset=inode->file_offset%BLOCK_SIZE; last_inode_block=(inode->file_offset+count)/BLOCK_SIZE; last_data_offset=(inode->file_offset+count)%BLOCK_SIZE; byte_to_write=count; if (last_inode_block>=12) { if (inode->i_block[12]==0) { inode->i_block[12]=alloc_indirect_block(ext2,inode); } else { sector_count=BLOCK_SIZE/SECTOR_SIZE; READ(sector_count,inode->i_block[12],iob_indirect_block); } } for (i=first_inode_block;i<=last_inode_block;i++) { if ((i==first_inode_block && first_data_offset!=0) || (i==last_inode_block && last_data_offset!=0)) { load_block=1; if (i>12) { if (iob_indirect_block[i-12]==0) { iob_indirect_block[i-12]=alloc_block(ext2,inode,i); load_block=0; update_indirect_block=TRUE; } lba=iob_indirect_block[i-12]; } else { if (inode->i_block[i]==0) { inode->i_block[i]=alloc_block(ext2,inode,i); load_block=0; } lba=inode->i_block[i]; } if (load_block) { sector_count=BLOCK_SIZE/SECTOR_SIZE; _read_28_ata(sector_count,lba,iob_data_block); if (i==first_inode_block) { iob_data_block+=first_data_offset; byte_count=BLOCK_SIZE-first_data_offset; byte_to_write-=byte_count; } else if (i==last_inode_block) { byte_count=last_data_offset; byte_to_write-=byte_count; } } } else { byte_count=BLOCK_SIZE; byte_to_write-=BLOCK_SIZE; if (i>12) { if (iob_indirect_block[i-12]==0) { iob_indirect_block[i-12]=alloc_block(ext2,inode,i); update_indirect_block=TRUE; } lba=iob_indirect_block[i-12]; } else { if (inode->i_block[i]==0) { inode->i_block[i]=alloc_block(ext2,inode,i); } lba=inode->i_block[i]; } byte_count=BLOCK_SIZE; byte_to_write-=BLOCK_SIZE; } kmemcpy(iob_data_block,buf,byte_count); sector_count=BLOCK_SIZE/SECTOR_SIZE; WRITE(sector_count,lba,iob_data_block); inode->file_offset+=byte_count; buf+=byte_count; byte_written+=byte_count; } if (update_indirect_block) { WRITE(sector_count,inode->i_block[12],iob_indirect_block); } kfree(iob_data_block); kfree(iob_indirect_block); return byte_written; }