Пример #1
0
/**
 * ext2_alloc_block - Allocate a new block id
 * 
 * This functions allocates a new block from device @dev, and applies
 * the allocation to the superblock. Outputs to @out
 */
void ext2_alloc_block(uint32_t *out, struct device *dev)
{
	/* Algorithm: Loop through block group descriptors,
	 * find which bg has a free block
	 * and set that.
	 */
	 struct ext2_priv_data *priv = EXT2_PRIV(dev);
	 uint8_t *buffer = malloc(priv->blocksize);
	 ext2_read_block(buffer, priv->first_bgd, dev);
	 struct ext2_block_group_desc *bg = (struct ext2_block_group_desc *)buffer;
	 for(int i = 0; i < priv->number_of_bgs; i++)
	 {
	 	if(bg->num_of_unalloc_block)
	 	{
	 		*out = priv->sb.blocks - bg->num_of_unalloc_block + 1;
	 		bg->num_of_unalloc_block --;
	 		ext2_write_block(buffer, priv->first_bgd + i, dev);

	 		ext2_read_block(buffer, priv->sb.superblock_id, dev);
			struct ext2_superblock *sb = (struct ext2_superblock *)buffer;
			sb->unallocatedblocks --;
			ext2_write_block(buffer, priv->sb.superblock_id, dev);
			goto out;
	 	}
	 	bg++;
	 }
out: free(buffer);
}
Пример #2
0
SFUNC(uint32_t, ext2_allocate_indirect_block, 
					ext2_device_t *device, 
					ext2_inode_t *inode)
{
	int status;
	size_t block_size = 1024 << device->superblock.block_size_enc;
	aoff_t size;
	uint32_t id;

	status = ext2_alloc_block(device, 0, &id);//TODO: Prevent fragmentation, swap 0 for previous block in inode

	if (status)
		THROW(status, 0);

	inode->blocks += 2 << device->superblock.block_size_enc;

	if (!ext2_zero_buffer) {
		ext2_zero_buffer = heapmm_alloc(block_size);
		memset(ext2_zero_buffer, 0, block_size);
	}

	status = ext2_write_block(device, id, 0, ext2_zero_buffer, block_size, &size);
	if (status) {
		THROW(status, 0);
	}

	RETURN(id);
}
Пример #3
0
SFUNC(aoff_t, ext2_write_inode, inode_t *_inode, void *_buffer, aoff_t f_offset, aoff_t length)
{
	ext2_device_t *device;
	ext2_vinode_t *inode;
	aoff_t count;
	aoff_t block_size;
	aoff_t in_blk_size;
	aoff_t rsize;
	aoff_t in_blk;
	aoff_t in_file;
	uint32_t block_addr, p_block_addr;	
	uint8_t *buffer = _buffer;
	int status;

	assert( _inode != NULL );
	assert( buffer != NULL );

	device = (ext2_device_t *) _inode->device;
	inode = (ext2_vinode_t *) _inode;

	block_size = 1024 << device->superblock.block_size_enc;
	
	p_block_addr = 0;

	for (count = 0; count < length; count += in_blk_size) {
		in_file = count + f_offset;
		in_blk = in_file % block_size;				
		in_blk_size = length - count;

		if (in_blk_size > (block_size - in_blk))
			in_blk_size = block_size - in_blk;

		status = ext2_decode_block_id (device, &(inode->inode), in_file / block_size, &block_addr);
		if (status)
			THROW(status, 0);

		if (!block_addr) {
			//debugcon_printf("ext2: growing file!\n");
			status = ext2_alloc_block(device, p_block_addr, &block_addr);
			if (status) 
				THROW(status, 0);

			status = ext2_set_block_id(device, &(inode->inode), in_file / block_size, block_addr);
			if (status)
				THROW(status, 0);

			inode->inode.blocks += 2 << device->superblock.block_size_enc;
		}

		status = ext2_write_block(device, block_addr, in_blk, &(buffer[count]), in_blk_size, &rsize);

		if (status)
			THROW(status, 0);

		p_block_addr = block_addr;
	}
	
	RETURN(count);
}
Пример #4
0
SVFUNC(ext2_free_block, ext2_device_t *device, uint32_t block_id)
{
	uint32_t b_count = device->superblock.block_count;
	uint32_t bgrp_id = 0;
	uint32_t bgrp_bcnt = device->superblock.blocks_per_group;
	uint32_t bm_block_size = 256 << device->superblock.block_size_enc;
	uint32_t bm_block_bcnt = bm_block_size * 32;
	uint32_t bm_id;
	uint32_t block_map[bm_block_size];
	uint32_t first_b = device->superblock.block_size_enc ? 0 : 1;
	uint32_t idx ,nb;
	aoff_t rsize;
	int status;
	ext2_block_group_desc_t *bgd;

	assert ( device != NULL );
	assert (block_id < b_count);
	assert (block_id > first_b);

	bgrp_id = (block_id - first_b) / bgrp_bcnt;
	idx = block_id - first_b - bgrp_id * bgrp_bcnt;
	bm_id = idx / bm_block_bcnt;
	idx -= bm_id * bm_block_bcnt;
	nb = idx % 32;
	idx -= nb;
	idx /= 32;
	
	status = ext2_load_bgd(device, bgrp_id, &bgd);
	if (status)
		THROWV(status);

	status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize);
	if (status)
		THROWV(status);

	EXT2_BITMAP_CLR(block_map[idx], nb);

	status = ext2_write_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize);
	if (status) {
		debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
		ext2_handle_error(device);
		THROWV(status);
	}

	bgd->free_block_count++;

	status = ext2_store_bgd(device, bgrp_id, bgd);
	if (status) {
		debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
		ext2_handle_error(device);
		THROWV(status);
	}
	ext2_free_bgd(device, bgd);

	device->superblock.free_block_count++;

	RETURNV;
}
Пример #5
0
int ext2_sb_update(ext2_fs_t *fs, ext2_superblock_t *sb)
{
	int old = sb->block_size;
	fs->sb->block_size=0;
	sb->write_time = get_epoch_time();
	ext2_write_block(fs, 1, (unsigned char *)sb);
	fs->sb = sb;
	sb->block_size = old;
	return 0;
}
Пример #6
0
/* Write ENTRY item of the inode table from BLOCK_GROUP */
void ext2_write_inode(struct block *b, uint32_t ino_idx, struct inode *inode){
	struct ext2_meta_data *meta = NULL;
	struct bg_desc_table *bg_desc_tabs = NULL;
	uint32_t block_size = 0;
	uint32_t inode_table = 0, inodes_per_group = 0, inodes_per_block = 0;
	uint32_t block_group = 0, block_idx = 0, block_offset = 0;
	struct inode *inode_tab = NULL;

	//get meta data
	ASSERT(b != NULL);
	meta = ext2_get_meta(b);
	ASSERT(meta != NULL);
	bg_desc_tabs = meta->bg_desc_tabs;
	ASSERT(bg_desc_tabs != NULL);
	ASSERT(block_group < DIV_ROUND_UP(meta->sb->s_blocks_count,
		meta->sb->s_blocks_per_group));
	inodes_per_group = meta->sb->s_inodes_per_group;
	block_size = ext2_get_block_size(meta->sb);

	// get block group
	ino_idx = ino_idx - 1; // inode index starts from 1 !!!
	block_group = ino_idx / inodes_per_group;
	bg_desc_tabs = &bg_desc_tabs[block_group];

	// get inode table
	inode_table = bg_desc_tabs->bg_inode_table;
	inodes_per_block = block_size/sizeof(struct inode);
	ASSERT((block_size % sizeof(struct inode)) == 0);

	// calculate inode index in local table
	ino_idx -= block_group * inodes_per_group;
	
	// get block location of inode
	block_idx = inode_table + ino_idx/inodes_per_block;
	block_offset = ino_idx % inodes_per_block;

	// read block data
	inode_tab = ext2_read_block(b,block_idx,block_size,NULL);
	// modify corresponding entry
	memcpy(&inode_tab[block_offset], inode, sizeof(struct inode));
	// write to disk
	ext2_write_block(b,block_idx,block_size,inode_tab);

	// release memory
	kfree(inode_tab);
}
Пример #7
0
SVFUNC(ext2_set_block_id, ext2_device_t *device, 
							ext2_inode_t *inode, 
							uint32_t block_id, 
							uint32_t block_v)
{
	uint32_t indirect_count = 256 << device->superblock.block_size_enc;
	uint32_t indirect_id, indirect_off, indirect_rd;
	uint32_t s_indir_l = indirect_count;
	uint32_t d_indir_l = indirect_count * indirect_count;
	uint32_t s_indir_s = 12;
	uint32_t d_indir_s = s_indir_s + s_indir_l;
	uint32_t t_indir_s = d_indir_s + d_indir_l;
	int status;
	aoff_t rsize;	

	assert ( device != NULL );

	if (block_id >= t_indir_s) { //Triply indirect
		indirect_id = inode->block[14];
		indirect_off = (block_id - t_indir_s) / d_indir_l;

		if (!indirect_id) {

			status = ext2_allocate_indirect_block(device, inode, &indirect_id);

			if (status)
				THROWV(status);	

			inode->block[14] = indirect_id;
		}

		status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize);
		if (status)
			THROWV(status);	

		if (!indirect_rd) {

			status = ext2_allocate_indirect_block(device, inode, &indirect_id);

			if (status)
				THROWV(status);	

			status = ext2_write_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize);
			if (status)
				THROWV(status);			
		}

		indirect_id = indirect_rd;

		block_id -= indirect_off * d_indir_l + d_indir_l;
		
	} else if (block_id >= d_indir_s) {

		indirect_id = inode->block[13];

		if (!indirect_id) {

			status = ext2_allocate_indirect_block(device, inode, &indirect_id);

			if (status)
				THROWV(status);	

			inode->block[13] = indirect_id;
		}
	}

	if (block_id >= d_indir_s) { //Doubly indirect
		indirect_off = (block_id - d_indir_s) / s_indir_l;

		status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize);
		if (status)
			THROWV(status);	

		if (!indirect_rd) {

			status = ext2_allocate_indirect_block(device, inode, &indirect_id);

			if (status)
				THROWV(status);	

			status = ext2_write_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, &rsize);
			if (status)
				THROWV(status);			
		}

		indirect_id = indirect_rd;

		block_id -= s_indir_l + indirect_off * s_indir_l;

	} else if (block_id >= s_indir_s){

		indirect_id = inode->block[12];

		if (!indirect_id) {

			status = ext2_allocate_indirect_block(device, inode, &indirect_id);

			if (status)
				THROWV(status);	

			inode->block[12] = indirect_id;
		}

	}

	if (block_id >= s_indir_s) { //Singly Indirect

		indirect_off = block_id - s_indir_s;

		status = ext2_write_block(device, indirect_id, indirect_off * 4, &block_v, 4, &rsize);
		if (status)
			THROWV(status);	

		RETURNV;
	}

	inode->block[block_id] = block_v;

	RETURNV;
}
Пример #8
0
SFUNC(uint32_t, ext2_alloc_block, ext2_device_t *device, uint32_t start)
{
	uint32_t b_count = device->superblock.block_count;
	uint32_t block_id = start;
	uint32_t bgrp_id = 0;
	uint32_t bgrp_bcnt = device->superblock.blocks_per_group;
	uint32_t bgrp_count = ext2_divup(b_count,bgrp_bcnt);//DIVUP
	uint32_t bm_block_size = 256 << device->superblock.block_size_enc;
	uint32_t bm_block_bcnt = bm_block_size * 32;
	uint32_t bgrp_bmcnt = ext2_divup(bgrp_bcnt,bm_block_bcnt);//DIVUP
	uint32_t bm_id;
	uint32_t block_map[bm_block_size];
	uint32_t first_b = device->superblock.block_size_enc ? 0 : 1;
	uint32_t idx ,nb;
	aoff_t rsize;
	int status;
	ext2_block_group_desc_t *bgd;

	assert ( device != NULL );
	assert (start < b_count);

	if (start == 0)
		block_id = first_b;

	bgrp_id = (block_id - first_b) / bgrp_bcnt;
	idx = block_id - first_b - bgrp_id * bgrp_bcnt;
	bm_id = idx / bm_block_bcnt;
	idx -= bm_id * bm_block_bcnt;
	nb = idx % 32;
	idx -= nb;
	idx /= 32;
	for (; bgrp_id < bgrp_count; bgrp_id++) {
		status = ext2_load_bgd(device, bgrp_id, &bgd);
		if (status)
			THROW(status, 0);

		if (bgd->free_block_count) {
			for (; bm_id < bgrp_bmcnt; bm_id++) {
				status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize);
				if (status)
					THROW(status, 0);
				for (; idx < bm_block_size; idx++) {
					if (block_map[idx] != 0xFFFFFFFF) {					
						for (; nb < 32; nb++)
							if (!EXT2_BITMAP_GET(block_map[idx], nb))
								goto found_it;
					}
					nb = 0;	
				}
				idx = 0;
			}
		}
		bm_id = 0;		
		ext2_free_bgd(device, bgd);
	}
	bgrp_id = 0;
	for (; bgrp_id < bgrp_count; bgrp_id++) {
		status = ext2_load_bgd(device, bgrp_id, &bgd);
		if (status)
			THROW(status, 0);

		if (bgd->free_block_count) {
			for (; bm_id < bgrp_bmcnt; bm_id++) {
				status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize);
				if (status)
					THROW(status, 0);
				for (; idx < bm_block_size; idx++) {
					if (block_map[idx] != 0xFFFFFFFF) {					
						for (; nb < 32; nb++)
							if (!EXT2_BITMAP_GET(block_map[idx], nb))
								goto found_it;
					}
					nb = 0;	
				}
				idx = 0;
			}
		}
		bm_id = 0;		
		ext2_free_bgd(device, bgd);
	}

	THROW(ENOSPC, 0);
found_it:

	block_id = nb + idx * 32 + bm_id * bm_block_bcnt + bgrp_id * bgrp_bcnt + first_b;

	EXT2_BITMAP_SET(block_map[idx], nb);
	status = ext2_write_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, &rsize);
	if (status) {
		debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
		ext2_handle_error(device);
		THROW(status, 0);
	}

	bgd->free_block_count--;

	status = ext2_store_bgd(device, bgrp_id, bgd);
	if (status) {
		debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
		ext2_handle_error(device);
		THROW(status, 0);
	}
	ext2_free_bgd(device, bgd);

	device->superblock.free_block_count--;
	
	memset(block_map, 0, bm_block_size * 4);

	status = ext2_write_block(device, block_id, 0, block_map, bm_block_size * 4, &rsize);
	if (status) {
		debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block clear)!");
		ext2_handle_error(device);
		THROW(status, 0);
	}

	RETURN(block_id);
}
Пример #9
0
bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode,
                        ULONG dwContent, ULONG Index, int layer,
                        ULONG newBlk, ULONG *dwRet, ULONG *off  )
{
    ULONG       *pData = NULL;
    ULONG       i = 0, j = 0, temp = 1;
    ULONG       dwBlk;
    ULONG       dwNewBlk = newBlk;
    bool        bDirty = false;
    bool        bRet = true;
    ULONG       Offset = 0;

    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
 
    pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize);
    
    if (!pData)
    {
        bRet = false;
        goto errorout;
    }
    
    if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData))
    {
        bRet = false;
        goto errorout;
    }
    
    if (layer == 1)
    {
        *dwRet = dwContent;
        *off   = Index;
        pData[Index] = newBlk;

        bDirty = TRUE;
    }
    else if (layer <= 3)
    {
        temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));

        i = Index / temp;
        j = Index % temp;

        dwBlk = pData[i];
        
        if (dwBlk == 0)
        {
            if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) )
            {
                pData[i] = dwBlk;
                bDirty = true;

                Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE);
            }
            
            if (!bDirty)
                goto errorout;
        }
        
        if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset))
        {
            bRet = false;
            DPRINT1("Mke2fs: ext2_expand_block: ... error recuise...\n");
            goto errorout;
        }
    }

    if (bDirty)
    {
        bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData);
    }


errorout:

    if (pData)
        RtlFreeHeap(RtlGetProcessHeap(), 0, pData);

    if (bRet && dwRet)
        *dwRet = dwNewBlk;

    return bRet;
}
Пример #10
0
static int inode_shrink_range(uint32_t block_id, uint32_t level, uint32_t start, uint32_t end, uint32_t items_per_block,uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3){
	struct block *d = block_get_role(BLOCK_FILESYS);
	uint32_t item_start, item_end;
	uint32_t *level_data;
	uint32_t block_id2;
	int i, ret = 0;
	enum RANGE range_comparison;

	ASSERT(d != NULL);
	ASSERT(level > 0);

	level_data = ext2_read_block(d,block_id,items_per_block*sizeof(uint32_t),NULL);
	for(i = 0; i < items_per_block; i++){
		// Get Block range the item represents
		if(level == 1){
			item_start = inode_get_direct_block_idx(items_per_block,l0,i,0,0);
			item_end = inode_get_direct_block_idx(items_per_block,l0,i,items_per_block-1,items_per_block-1);
		}
		else if (level == 2){
			item_start = inode_get_direct_block_idx(items_per_block,l0,l1,i,0);
			item_end = inode_get_direct_block_idx(items_per_block,l0,l1,i,items_per_block-1);
		}
		else {
			item_start = inode_get_direct_block_idx(items_per_block,l0,l1,l2,i);
			item_end = item_start;
		}
		// Compare range
		range_comparison = inode_range_compare(item_start,item_end,start,end);
		if((range_comparison & RANGE_OVERLAP) > 0){ // In Range
			block_id2 = level_data[i];

			// If the block is cleared already.
			if(block_id2 == 0) continue;

			/* If it is a leaf node */
			if(item_start == item_end) {
				// free block and set entry to zero
				freemap_free_block(block_id2);
				level_data[i] = 0;
				continue;
			}

			/* If not a leaf node*/

			// free sub level
			if(level == 1)
				inode_shrink_range(block_id2,level+1,start,end,items_per_block,l0,i,0,0);
			else if(level == 2)
				inode_shrink_range(block_id2,level+1,start,end,items_per_block,l0,l1,i,0);
			else
				PANIC("Inode Shrink Range Reach Unexpected Level.\n");

			// if shrink range contains entire level
			if(start <= item_start){
				// free block and set entry to zero
				freemap_free_block(block_id2);
				level_data[i] = 0;
			}
		}
		else if((range_comparison & RANGE_AHEAD) > 0){ //Item Ahead of start
			continue;
		}
		else{ // Item Passed End
			break;
		}
	}
	ext2_write_block(d,block_id,items_per_block*sizeof(uint32_t),level_data);
	kfree(level_data);

	return ret;
}
Пример #11
0
static int inode_expand_range(uint32_t block_id, uint32_t level, uint32_t start, uint32_t end, uint32_t items_per_block,uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3){
	struct block *d = block_get_role(BLOCK_FILESYS);
	uint32_t item_start, item_end;
	uint32_t *level_data;
	uint32_t block_id2;
	int i, ret = 0;
	enum RANGE range_comparison;

	ASSERT(d != NULL);
	ASSERT(level > 0);

	level_data = ext2_read_block(d,block_id,items_per_block*sizeof(uint32_t),NULL);
	for(i = 0; i < items_per_block; i++){
		// Get Block range the item represents
		if(level == 1){
			item_start = inode_get_direct_block_idx(items_per_block,l0,i,0,0);
			item_end = inode_get_direct_block_idx(items_per_block,l0,i,items_per_block-1,items_per_block-1);
		}
		else if (level == 2){
			item_start = inode_get_direct_block_idx(items_per_block,l0,l1,i,0);
			item_end = inode_get_direct_block_idx(items_per_block,l0,l1,i,items_per_block-1);
		}
		else {
			item_start = inode_get_direct_block_idx(items_per_block,l0,l1,l2,i);
			item_end = item_start;
		}
		// Compare range
		range_comparison = inode_range_compare(item_start,item_end,start,end);
		if((range_comparison & RANGE_OVERLAP) > 0){ // In Range
			block_id2 = level_data[i];
			// Allocate block in disk if not exist.
			if(block_id2 == 0){
				if(item_start == item_end) block_id2 = freemap_get_block(false);
				else block_id2 = freemap_get_block(true);	
#ifdef FILESYS_EXT2_DEBUG
				printf(" New block id: 0x%x for %d/%d/%d/%d:%d\n",
					block_id2,l0,l1,l2,l3,i);
#endif
			}

			if(block_id2 != FREEMAP_GET_ERROR) {level_data[i] = block_id2;}
			else {ret = -1; break;}

			/* If it is a leaf node */
			if(item_start == item_end) continue;
			/* If not leaf node*/
			if(level == 1)
				inode_expand_range(block_id2,level+1,start,end,items_per_block,l0,i,0,0);
			else if(level == 2)
				inode_expand_range(block_id2,level+1,start,end,items_per_block,l0,l1,i,0);
			else
				PANIC("Inode Fill Range Reach Unexpected Level.\n");
		}
		else if((range_comparison & RANGE_AHEAD) > 0){ //Ahead of start
			continue;
		}
		else{ // Passed End
			break;
		}
	}
	ext2_write_block(d,block_id,items_per_block*sizeof(uint32_t),level_data);
	kfree(level_data);

	return ret;
}
Пример #12
0
/* inode read from given position */
off_t inode_write_at(struct block *d, struct inode *inode, const void *buffer_, off_t size, off_t offset){
	struct ext2_meta_data *meta;
	uint32_t block_size,block_id,block_idx,block_ofs;
	const uint8_t *buffer = buffer_;
	uint8_t *bounce = NULL;
	off_t bytes_written = 0, err;

	ASSERT(d != NULL && inode != NULL);

	// Resize inode
	err = inode_resize(inode,offset + size);
	if(err < 0) {
		printf("inode_write_at: resize failed.\n");
		return 0;
	}

	// get device meta data
	meta = ext2_get_meta(d);
	ASSERT(meta != NULL && meta->sb != NULL);
	block_size = ext2_get_block_size(meta->sb);

	// read from disk
	while(size > 0){
		// get data block id
		block_idx = offset / block_size; // the nth data block
		block_ofs = offset % block_size; // byte offset with data block
		block_id = inode_get_data_block(d,inode,block_idx); // data block id in fs
		ASSERT(block_id != UINT32_MAX);

		// Calculate bytes to write
		// off_t is signed.
		off_t inode_left = inode->i_size - offset;
		off_t block_left = block_size - block_ofs;
		off_t min_left = inode_left < block_left ? inode_left : block_left;
		off_t chunk_size = size < min_left ? size : min_left;

		// no bytes to be read
		if(chunk_size <= 0) break;

		// whole block data
		if(block_ofs == 0 && chunk_size == block_size)
			ext2_write_block(d,block_id,block_size,buffer+bytes_written);
		else{
			if(bounce == NULL){
				bounce = kmalloc(block_size);
				if(bounce == NULL) break;
			}
			// First read the block from disk
			ext2_read_block(d,block_id,block_size,bounce);
			// Modify data read
			memcpy(bounce+block_ofs,buffer+bytes_written,chunk_size);
			// Write to disk
			ext2_write_block(d,block_id,block_size,bounce);
		}

		// advance.
		size -= chunk_size;
		offset += chunk_size;
		bytes_written += chunk_size;
	}

	if(bounce != NULL) kfree(bounce);
	return bytes_written;
}
Пример #13
0
SFUNC(uint32_t, ext2_alloc_inode, ext2_device_t *device)
{
	uint32_t i_count = device->superblock.inode_count;
	uint32_t inode_id = 11;
	uint32_t bgrp_id = 0;
	uint32_t bgrp_icnt = device->superblock.inodes_per_group;
	uint32_t bgrp_count = ext2_divup(i_count,bgrp_icnt);//DIVUP
	uint32_t bm_block_size = 256 << device->superblock.block_size_enc;
	uint32_t bm_block_icnt = bm_block_size * 32;
	uint32_t bgrp_bmcnt = ext2_divup(bgrp_icnt,bm_block_icnt);//DIVUP
	uint32_t bm_id;
	uint32_t inode_map[bm_block_size];
	uint32_t first_i = 1;
	uint32_t idx ,nb;
	aoff_t rsize;

	int status;

	ext2_block_group_desc_t *bgd;

	assert ( device != NULL );

	bgrp_id = (inode_id - first_i) / bgrp_icnt;
	idx = inode_id - first_i - bgrp_id * bgrp_icnt;
	bm_id = idx / bm_block_icnt;
	idx -= bm_id * bm_block_icnt;
	nb = idx % 32;
	idx -= nb;
	idx /= 32;

	for (; bgrp_id < bgrp_count; bgrp_id++) {
		status = ext2_load_bgd(device, bgrp_id, &bgd);
		if (status)
			THROW(status, 0);

		if (bgd->free_inode_count) {
			for (; bm_id < bgrp_bmcnt; bm_id++) {
				status = ext2_read_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, &rsize);
				if (status)
					THROW(status, 0);
				for (; idx < bm_block_size; idx++) {
					if (inode_map[idx] != 0xFFFFFFFF) {					
						for (; nb < 32; nb++)
							if (!EXT2_BITMAP_GET(inode_map[idx], nb))
								goto found_it;
					}
					nb = 0;	
				}
				idx = 0;
			}
		}
		bm_id = 0;		
		ext2_free_bgd(device, bgd);
	}
	bgrp_id = 0;

	THROW(ENOSPC, 0);
found_it:

	inode_id = nb + idx * 32 + bm_id * bm_block_icnt + bgrp_id * bgrp_icnt + first_i;

	EXT2_BITMAP_SET(inode_map[idx], nb);
	status = ext2_write_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, &rsize);
	if (status) {
		debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (inode bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
		ext2_handle_error(device);
		THROW(status, 0);
	}

	bgd->free_inode_count--;

	status = ext2_store_bgd(device, bgrp_id, bgd);
	if (status) {
		debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
		ext2_handle_error(device);
		THROW(status, 0);
	}
	ext2_free_bgd(device, bgd);

	device->superblock.free_inode_count--;

	RETURN(inode_id);
}