Beispiel #1
0
/**
 * Allocate memory for a block in an inode whose inode number is 'no'.
 */
void ext2_disk_inode_alloc_block(ext2_inodetable_t *inode, uint32_t no, uint32_t block) {
	uint32_t block_no = 0, block_offset = 0, group = 0;
	char *bg_buffer = malloc(BLOCKSIZE);
	for (uint32_t i = 0; i < BGDS; ++i) {
		if (BGD[i].free_blocks_count > 0) {
			ext2_disk_read_block(BGD[i].block_bitmap, (uint8_t *)bg_buffer);
			while (BLOCKBIT(block_offset))
				++block_offset;
			block_no = block_offset + SB->blocks_per_group * i + 1;
			group = i;
			break;
		}
	}
	if (!block_no) {
		kprintf("[kernel/ext2] No available blocks!\n");
		free(bg_buffer);
		return;
	}

	// Found a block (block_no), we need to mark it as in-use
	uint8_t b = BLOCKBYTE(block_offset);
	b |= SETBIT(block_offset);
	BLOCKBYTE(block_offset) = b;
	ext2_disk_write_block(BGD[group].block_bitmap, (uint8_t *)bg_buffer);
	free(bg_buffer);

	ext2_set_real_block(inode, block, block_no);

	// Now update available blocks count
	BGD[group].free_blocks_count -= 1;
	ext2_disk_write_block(2, (uint8_t *)BGD);

	inode->blocks++;
	ext2_disk_write_inode(inode, no);
}
Beispiel #2
0
void ext2_set_real_block(ext2_inodetable_t *inode, uint32_t block, uint32_t real) {
	if (block < 12) {
		inode->block[block] = real;
		return;
	} else if (block < 12 + BLOCKSIZE / sizeof(uint32_t)) {
		uint8_t *tmp = malloc(BLOCKSIZE);
		ext2_disk_read_block(inode->block[12], tmp);
		((uint32_t *)tmp)[block - 12] = real;
		ext2_disk_write_block(inode->block[12], tmp);
		free(tmp);
		return;
	} else if (block < 12 + 256 + 256 * 256) {
		uint32_t a = block - 12;
		uint32_t b = a - 256;
		uint32_t c = b / 256;
		uint32_t d = b - c * 256;
		uint8_t *tmp = malloc(BLOCKSIZE);
		ext2_disk_read_block(inode->block[13], tmp);
		uint32_t nblock = ((uint32_t *)tmp)[c];
		ext2_disk_read_block(nblock, tmp);
		((uint32_t *)tmp)[d] = real;
		ext2_disk_write_block(nblock, tmp);
		free(tmp);
		return;
	} else if (block < 12 + 256 + 256 * 256 + 256 * 256 * 256) {
		uint32_t a = block - 12;
		uint32_t b = a - 256;
		uint32_t c = b - 256 * 256;
		uint32_t d = c / (256 * 256);
		uint32_t e = c - d * 256 * 256;
		uint32_t f = e / 256;
		uint32_t g = e - f * 256;
		uint8_t *tmp = malloc(BLOCKSIZE);
		ext2_disk_read_block(inode->block[14], tmp);
		uint32_t nblock = ((uint32_t *)tmp)[d];
		ext2_disk_read_block(nblock, tmp);
		nblock = ((uint32_t *)tmp)[f];
		ext2_disk_read_block(nblock, tmp);
		((uint32_t *)tmp)[g] = nblock;
		ext2_disk_write_block(nblock, tmp);
		free(tmp);
		return;
	}

	HALT_AND_CATCH_FIRE("Attempted to set a file block that was too high :(", NULL);
}
Beispiel #3
0
/**
 * Write to the 'block'th block within an inode 'inode' from the buffer 'buf'. 
 * In other words, this function writes to the actual file content.
 * @return the actual block number read from.
 */
uint32_t ext2_disk_inode_write_block(ext2_inodetable_t *inode, uint32_t no, uint32_t block, uint8_t *buf) {
	/* We must allocate blocks up to this point to account for unused space in the middle. */
	while (block >= inode->blocks) {
		kprintf("[kernel/ext2] Need to allocate blocks, have %d, want to write to #%d.\n", inode->blocks, block);
		ext2_disk_inode_alloc_block(inode, no, inode->blocks);
		if (block != inode->blocks - 1) {
			/* Clear the block */
			uint32_t real_block = ext2_get_real_block(inode, inode->blocks - 1);
			uint8_t empty[1024] = {0};
			memset(empty, 0x00, 1024);
			ext2_disk_write_block(real_block, empty);
		}
	}

	// The real work to write to a block of an inode.
	uint32_t real_block = ext2_get_real_block(inode, block);
	ext2_disk_write_block(real_block, buf);
	return real_block;
}
Beispiel #4
0
/**
 * Write to the 'block'th block within an inode 'inode' from the buffer 'buf'. 
 * In other words, this function writes to the actual file content.
 * @return the actual block number read from.
 */
uint32_t ext2_disk_inode_write_block(ext2_inodetable_t *inode, uint32_t inode_no, uint32_t block, uint8_t *buf) {
	/* We must allocate blocks up to this point to account for unused space in the middle. */
	while (block >= inode->blocks) {
		ext2_disk_inode_alloc_block(inode, inode_no, inode->blocks);
		if (block != inode->blocks - 1) {
			/* Clear the block */
			uint32_t real_block = ext2_get_real_block(inode, inode->blocks - 1);
			uint8_t * empty = malloc(BLOCKSIZE);
			memset(empty, 0x00, BLOCKSIZE);
			ext2_disk_write_block(real_block, empty);
			free(empty);
		}
	}

	// The real work to write to a block of an inode.
	uint32_t real_block = ext2_get_real_block(inode, block);

	debug_print(INFO, "virtual block %d maps to real block %d", block, real_block);

	ext2_disk_write_block(real_block, buf);
	return real_block;
}
Beispiel #5
0
/**
 * Write the 'inode' into the inode table at position 'index'.
 */
void ext2_disk_write_inode(ext2_inodetable_t *inode, uint32_t index) {
	uint32_t group = index / ext2_disk_inodes_per_group;
	if (group > BGDS) {
		return;
	}
	
	uint32_t inode_table_block = BGD[group].inode_table;
	index -= group * ext2_disk_inodes_per_group;	// adjust index within group
	uint32_t block_offset = ((index - 1) * SB->inode_size) / BLOCKSIZE;
	uint32_t offset_in_block = (index - 1) - block_offset * (BLOCKSIZE / SB->inode_size);

	ext2_inodetable_t *inodet = malloc(BLOCKSIZE);
	/* Read the current table block */
	ext2_disk_read_block(inode_table_block + block_offset, (uint8_t *)inodet);
	memcpy(&inodet[offset_in_block], inode, sizeof(ext2_inodetable_t));
	ext2_disk_write_block(inode_table_block + block_offset, (uint8_t *)inodet);
	free(inodet);
}
Beispiel #6
0
/**
 * Allocate a new inode with parent as the parent directory node and name as the filename
 * within that parent directory. Returns a pointer to a memory-copy of the node which
 * the client can (and should) free.
 * 'ftype' is file type, used when adding the entry to the parent dir. 1 for regular file,
 * 2 for directory, etc... 'no' is the inode number of 'parent'.
 * Upon return, the inode number of the newly allocated inode will be stored in 'inode_no'.
 * 
 * This function assumes that parent directory 'parent' does not contain any entry with 
 * same name as 'name'. Caller shuold ensure this.
 * Note that inode just created using this function has size of 0, which means no data 
 * blocks have been allocated to the inode.
 */
ext2_inodetable_t *ext2_disk_alloc_inode
(
	ext2_inodetable_t *parent, 
	uint32_t no,
	char *name, 
	uint16_t mode, 
    uint32_t *inode_no	
) {
	if ((parent->mode & EXT2_S_IFDIR) == 0 || name == NULL) {
		kprintf("[kernel/ext2] No name or bad parent.\n");
		return NULL;
	}
	
	ext2_inodetable_t *inode;

	uint32_t node_no = 0, node_offset = 0, group = 0;
	char *bg_buffer = malloc(BLOCKSIZE);
	/* Locate a block with an available inode. Will probably be the first block group. */
	for (uint32_t i = 0; i < BGDS; ++i) {
		if (BGD[i].free_inodes_count > 0) {
#if EXT2_DEBUG_BLOCK_DESCRIPTORS
			kprintf("Group %d has %d free inodes!\n", i, BGD[i].free_inodes_count);
#endif
			ext2_disk_read_block(BGD[i].inode_bitmap, (uint8_t *)bg_buffer);
			while (BLOCKBIT(node_offset))
				++node_offset;
			node_no = node_offset + ext2_disk_inodes_per_group * i + 1;
			group = i;
			break;
		}
	}
	if (!node_no) {
		kprintf("[kernel/ext2] Failure: No free inodes in block descriptors!\n");
		free(bg_buffer);
		return NULL;
	}
	/* Alright, we found an inode (node_no), we need to mark it as in-use... */
	uint8_t b = BLOCKBYTE(node_offset);
#if EXT2_DEBUG_BLOCK_DESCRIPTORS
	kprintf("Located an inode at #%d (%d), the byte for this block is currently set to %x\n", node_no, node_offset, (uint32_t)b);
#endif
	b |= SETBIT(node_offset);
#if EXT2_DEBUG_BLOCK_DESCRIPTORS	
	kprintf("We would want to set it to %x\n", (uint32_t)b);
	kprintf("Setting it in our temporary buffer...\n");
#endif
	BLOCKBYTE(node_offset) = b;
#if EXT2_DEBUG_BLOCK_DESCRIPTORS	
	kprintf("\nWriting back out.\n");
#endif
	ext2_disk_write_block(BGD[group].inode_bitmap, (uint8_t *)bg_buffer);
	free(bg_buffer);
#if EXT2_DEBUG_BLOCK_DESCRIPTORS	
	kprintf("Okay, now we need to update the available inodes count...\n");
	kprintf("it is %d, it should be %d\n", BGD[group].free_inodes_count, BGD[group].free_inodes_count - 1);
	kprintf("\n");
	kprintf("%d\n", BGD[group].free_inodes_count);
#endif
	BGD[group].free_inodes_count -= 1;
#if EXT2_DEBUG_BLOCK_DESCRIPTORS	
	kprintf("%d\n", BGD[group].free_inodes_count);
	kprintf("\nOkay, writing the block descriptors back to disk.\n");
#endif	
	ext2_disk_write_block(2, (uint8_t *)BGD);
	
#if EXT2_DEBUG_BLOCK_DESCRIPTORS	
	kprintf("Alright, we have an inode (%d), time to write it out to disk and make the file in the directory.\n", node_no);
#endif

	// Get the inode struct from the disk and init it
	inode = ext2_disk_inode(node_no);
	inode->size = 0;
	inode->blocks = 0;
	inode->mode = mode;
	ext2_disk_write_inode(inode, node_no);
	*inode_no = node_no;

	// Create an entry in the parent directory
	uint8_t ftype = mode_to_filetype(mode);
	kprintf("[kernel/ext2] Allocated inode, inserting directory entry [%d]...\n", node_no);
	insertdir_ext2_disk(parent, no, node_no, name, ftype);

	return inode;
}