Example #1
0
/**
 * Make a new directory. 'name' consists the name for the new directory
 * to be created using 'permission' under 'parent' directory.
 * Message will be displayed in the terminal for success or failure.
 */
void ext2_mkdir(fs_node_t *parent, char *name, uint16_t permission) {

	uint16_t mode = permission | EXT2_S_IFDIR;
	ext2_inodetable_t *parent_inode = ext2_disk_inode(parent->inode);

	// Check to make sure no same name in the parent dir
	fs_node_t *b_exist = finddir_ext2_disk(parent, name);
	if (b_exist) {
		kprintf("mkdir: %s: Already exists\n", name);
		free(b_exist);
		free(parent_inode);
		return;
	}
	free(b_exist);

	// Create the inode under 'parent'
	uint32_t inode_no;
	ext2_inodetable_t *inode = ext2_disk_alloc_inode(parent_inode, parent->inode, name, mode, &inode_no);
	free(parent_inode);

	if (inode == NULL) {
		kprintf("mkdir: %s: Cannot be created\n", name);
		return;
	}

	// Init this newly created dir, put '.' and '..' into it.
	// Here we pass in 0 as the inode number for '.' and '..' because the 
	// 'cd' command can handle them correctly, so it does not matter.
	insertdir_ext2_disk(inode, inode_no, 0, ".", 2);
	insertdir_ext2_disk(inode, inode_no, 0, "..", 2);

	free(inode);
}
Example #2
0
/**
 * Create a new, regular, and empty file under directory 'parent'.
 */
void ext2_create(fs_node_t *parent, char *name, uint16_t permission) {
	
	kprintf("[kernel/ext2] Creating file.\n");
	uint16_t mode = permission | EXT2_S_IFREG;
	ext2_inodetable_t *parent_inode = ext2_disk_inode(parent->inode);
	
	// Check to make sure no same name in the parent dir
	fs_node_t *b_exist = finddir_ext2_disk(parent, name);
	if (b_exist) {
		kprintf("[kernel/ext2] %s: Already exists\n", name);
		free(b_exist);
		free(parent_inode);
		return;
	}
	free(b_exist);

	// Create the inode under 'parent'
	uint32_t inode_no;
	ext2_inodetable_t *inode = ext2_disk_alloc_inode(parent_inode, parent->inode, name, mode, &inode_no);
	free(parent_inode);

	if (inode == NULL) {
		kprintf("[kernel/ext2] Failed to create file '%s' (inode allocation failed)?\n", name);
		return;
	}

	free(inode);
}
Example #3
0
/**
 * Create a new, regular, and empty file under directory 'parent'.
 */
void ext2_create(fs_node_t *parent, char *name, uint16_t permission) {

	debug_print(NOTICE, "Creating file %s", name);
	uint16_t mode = permission | EXT2_S_IFREG;
	ext2_inodetable_t *parent_inode = ext2_disk_inode(parent->inode);
	
	// Check to make sure no same name in the parent dir
	fs_node_t *b_exist = finddir_ext2_disk(parent, name);
	if (b_exist) {
		debug_print(WARNING, "File already exists!");
		free(b_exist);
		free(parent_inode);
		return;
	}
	free(b_exist);

	// Create the inode under 'parent'
	uint32_t inode_no;
	ext2_inodetable_t *inode = ext2_disk_alloc_inode(parent_inode, parent->inode, name, mode, &inode_no);
	free(parent_inode);

	if (inode == NULL) {
		debug_print(ERROR, "Failed to create file (inode allocation failed)");
		return;
	}

	free(inode);
}
Example #4
0
uint32_t write_ext2_disk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
	ext2_inodetable_t *inode = ext2_disk_inode(node->inode);
	uint32_t end = offset + size;
	uint32_t start_block 	= offset / BLOCKSIZE;
	uint32_t end_block		= end / BLOCKSIZE;
	uint32_t end_size		= end - end_block * BLOCKSIZE;
	uint32_t size_to_write  = end - offset;
	kprintf("[kernel/ext2] Write at node 0x%x, offset %d, size %d, buffer=0x%x\n", node, offset, size, buffer);
	if (end_size == 0) {
		end_block--;
	}
	
	// need to update if size has increased.
	if (inode->size < end) {
		inode->size = end;
		ext2_disk_write_inode(inode, node->inode);
	}
	
	if (start_block == end_block) {
		void *buf = malloc(BLOCKSIZE);
		ext2_disk_inode_read_block(inode, node->inode, start_block, buf);
		memcpy((uint8_t *)((uintptr_t)buf + (offset % BLOCKSIZE)), buffer, size_to_write);
		kprintf("[kernel/ext2] Single-block write.\n");
		ext2_disk_inode_write_block(inode, node->inode, start_block, buf);
		free(buf);
		free(inode);
		return size_to_write;
	} else {
		uint32_t block_offset;
		uint32_t blocks_read = 0;
		for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) {
			if (block_offset == start_block) {
				void *buf = malloc(BLOCKSIZE);
				ext2_disk_inode_read_block(inode, node->inode, block_offset, buf);
				memcpy((uint8_t *)((uint32_t)buf + (offset % BLOCKSIZE)), buffer, BLOCKSIZE - (offset % BLOCKSIZE));
				kprintf("[kernel/ext2] Writing block [loop...]...\n");
				ext2_disk_inode_write_block(inode, node->inode, start_block, buf);
				free(buf);
			} else {
				kprintf("[kernel/ext2] Writing block [buffer...?]...\n");
				ext2_disk_inode_write_block(inode, node->inode, block_offset, 
						buffer + BLOCKSIZE * blocks_read - (block_offset % BLOCKSIZE));
			}
		}
		void *buf = malloc(BLOCKSIZE);
		ext2_disk_inode_read_block(inode, node->inode, end_block, buf);
		memcpy(buf, buffer + BLOCKSIZE * blocks_read - (block_offset % BLOCKSIZE), end_size);
		kprintf("[kernel/ext2] Writing block [tail]...\n");
		ext2_disk_inode_write_block(inode, node->inode, end_block, buf);
		free(buf);
	}
	free(inode);
	return size_to_write;
}
Example #5
0
void ext2_disk_mount() {
	DC = malloc(sizeof(ext2_disk_cache_entry_t) * CACHEENTRIES);
	SB = malloc(BLOCKSIZE);
	ext2_disk_read_block(1, (uint8_t *)SB);
	assert(SB->magic == EXT2_SUPER_MAGIC);
	if (SB->inode_size == 0) {
		SB->inode_size = 128;
	}
	BGDS = SB->blocks_count / SB->blocks_per_group;
	ext2_disk_inodes_per_group = SB->inodes_count / BGDS;

	// load the block group descriptors
	BGD = malloc(BLOCKSIZE);
	ext2_disk_read_block(2, (uint8_t *)BGD);

#if EXT2_DEBUG_BLOCK_DESCRIPTORS
	char bg_buffer[BLOCKSIZE];
	for (uint32_t i = 0; i < BGDS; ++i) {
		kprintf("Block Group Descriptor #%d @ %d\n", i, 2 + i * SB->blocks_per_group);
		kprintf("\tBlock Bitmap @ %d\n", BGD[i].block_bitmap); { 
			kprintf("\t\tExamining block bitmap at %d\n", BGD[i].block_bitmap);
			ext2_disk_read_block(BGD[i].block_bitmap, (uint8_t *)bg_buffer);
			uint32_t j = 0;
			while (BLOCKBIT(j)) {
				++j;
			}
			kprintf("\t\tFirst free block in group is %d\n", j + BGD[i].block_bitmap - 2);
		}
		kprintf("\tInode Bitmap @ %d\n", BGD[i].inode_bitmap); {
			kprintf("\t\tExamining inode bitmap at %d\n", BGD[i].inode_bitmap);
			ext2_disk_read_block(BGD[i].inode_bitmap, (uint8_t *)bg_buffer);
			uint32_t j = 0;
			while (BLOCKBIT(j)) {
				++j;
			}
			kprintf("\t\tFirst free inode in group is %d\n", j + ext2_disk_inodes_per_group * i + 1);
		}
		kprintf("\tInode Table  @ %d\n", BGD[i].inode_table);
		kprintf("\tFree Blocks =  %d\n", BGD[i].free_blocks_count);
		kprintf("\tFree Inodes =  %d\n", BGD[i].free_inodes_count);
	}
#endif
	ext2_inodetable_t *root_inode = ext2_disk_inode(2);

	RN = (fs_node_t *)malloc(sizeof(fs_node_t));
	assert(ext2_disk_node_root(root_inode, RN));
	fs_root = RN;
	LOG(INFO,"Mounted EXT2 disk, root VFS node is at 0x%x", RN);
}
Example #6
0
/**
 * Return the 'index'th entry in the directory 'node'.
 * Caller should free the memory.
 */
struct dirent *
readdir_ext2_disk(fs_node_t *node, uint32_t index) {
	
	ext2_inodetable_t *inode = ext2_disk_inode(node->inode);
	assert(inode->mode & EXT2_S_IFDIR);
	ext2_dir_t *direntry = ext2_disk_direntry(inode, node->inode, index);
	if (!direntry) {
		return NULL;
	}
	struct dirent *dirent = malloc(sizeof(struct dirent));
	memcpy(&dirent->name, &direntry->name, direntry->name_len);
	dirent->name[direntry->name_len] = '\0';
	dirent->ino = direntry->inode;
	free(direntry);
	free(inode);
	return dirent;
}
Example #7
0
uint32_t read_ext2_disk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
	ext2_inodetable_t *inode = ext2_disk_inode(node->inode);
	uint32_t end;
	if (offset + size > inode->size) {
		end = inode->size;
	} else {
		end = offset + size;
	}
	uint32_t start_block  = offset / BLOCKSIZE;
	uint32_t end_block    = end / BLOCKSIZE;
	uint32_t end_size     = end - end_block * BLOCKSIZE;
	uint32_t size_to_read = end - offset;
	if (end_size == 0) {
		end_block--;
	}
	if (start_block == end_block) {
		void *buf = malloc(BLOCKSIZE);
		ext2_disk_inode_read_block(inode, node->inode, start_block, buf);
		memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), size_to_read);
		free(buf);
		free(inode);
		return size_to_read;
	} else {
		uint32_t block_offset;
		uint32_t blocks_read = 0;
		for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) {
			if (block_offset == start_block) {
				void *buf = malloc(BLOCKSIZE);
				ext2_disk_inode_read_block(inode, node->inode, block_offset, buf);
				memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), BLOCKSIZE - (offset % BLOCKSIZE));
				free(buf);
			} else {
				void *buf = malloc(BLOCKSIZE);
				ext2_disk_inode_read_block(inode, node->inode, block_offset, buf);
				memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, BLOCKSIZE);
				free(buf);
			}
		}
		void *buf = malloc(BLOCKSIZE);
		ext2_disk_inode_read_block(inode, node->inode, end_block, buf);
		memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, end_size);
		free(buf);
	}
	free(inode);
	return size_to_read;
}
Example #8
0
/**
 * Find the actual inode in the ramdisk image for the requested file.
 */
fs_node_t *finddir_ext2_disk(fs_node_t *node, char *name) {
	
	ext2_inodetable_t *inode = ext2_disk_inode(node->inode);
	assert(inode->mode & EXT2_S_IFDIR);
	void *block = malloc(BLOCKSIZE);
	ext2_dir_t *direntry = NULL;
	uint8_t block_nr = 0;
	ext2_disk_inode_read_block(inode, node->inode, block_nr, block);
	uint32_t dir_offset = 0;
	uint32_t total_offset = 0;

	// Look through the requested entries until we find what we're looking for
#if EXT2_DEBUG_BLOCK_DESCRIPTORS
	kprintf("file looking for: %s\n", name);
	kprintf("total size: %d\n", inode->size);
#endif
	while (total_offset < inode->size) {
#if EXT2_DEBUG_BLOCK_DESCRIPTORS
		kprintf("dir_offset: %d\n", dir_offset);
		kprintf("total_offset: %d\n", total_offset);
#endif
		ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset);
		
		if (strlen(name) != d_ent->name_len) {
			dir_offset += d_ent->rec_len;
			total_offset += d_ent->rec_len;

			// move on to the next block of this directory if need.
			if (dir_offset >= BLOCKSIZE) {
				block_nr++;
				dir_offset -= BLOCKSIZE;
				ext2_disk_inode_read_block(inode, node->inode, block_nr, block);
			}

			continue;
		}

		char *dname = malloc(sizeof(char) * (d_ent->name_len + 1));
		memcpy(dname, &(d_ent->name), d_ent->name_len);
		dname[d_ent->name_len] = '\0';
#if EXT2_DEBUG_BLOCK_DESCRIPTORS
		kprintf("cur file: %s\n", dname);
#endif
		if (!strcmp(dname, name)) {
			free(dname);
			direntry = malloc(d_ent->rec_len);
			memcpy(direntry, d_ent, d_ent->rec_len);
			break;
		}
		free(dname);

		dir_offset += d_ent->rec_len;
		total_offset += d_ent->rec_len;

		// move on to the next block of this directory if need.
		if (dir_offset >= BLOCKSIZE) {
			block_nr++;
			dir_offset -= BLOCKSIZE;
			ext2_disk_inode_read_block(inode, node->inode, block_nr, block);
		}
	}
	free(inode);
	free(block);
	if (!direntry) {
		// We could not find the requested entry in this directory.
		return NULL;
	}
	fs_node_t *outnode = malloc(sizeof(fs_node_t));
	inode = ext2_disk_inode(direntry->inode);
	ext2_disk_node_from_file(inode, direntry, outnode);
	free(inode);
	return outnode;
}
Example #9
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;
}
Example #10
0
void ext2_disk_mount(uint32_t offset_sector, uint32_t max_sector) {
	debug_print(NOTICE, "Mounting EXT2 partition between sectors [%d:%d].", offset_sector, max_sector);

	ext2_offset = offset_sector;

	BLOCKSIZE = 1024;

	SB = malloc(BLOCKSIZE);
	ext2_disk_read_block(1, (uint8_t *)SB);
	assert(SB->magic == EXT2_SUPER_MAGIC);
	if (SB->inode_size == 0) {
		SB->inode_size = 128;
	}
	BLOCKSIZE = 1024 << SB->log_block_size;
	if (BLOCKSIZE > 2048) {
		CACHEENTRIES /= 4;
	}
	PTRS_PER_BLOCK = BLOCKSIZE / 4;
	debug_print(NOTICE, "Log block size = %d -> %d", SB->log_block_size, BLOCKSIZE);
	BGDS = SB->blocks_count / SB->blocks_per_group;
	if (SB->blocks_per_group * BGDS < SB->blocks_count) {
		BGDS += 1;
	}
	ext2_disk_inodes_per_group = SB->inodes_count / BGDS;

	debug_print(NOTICE, "Allocating cache...");
	DC = malloc(sizeof(ext2_disk_cache_entry_t) * CACHEENTRIES);
	for (uint32_t i = 0; i < CACHEENTRIES; ++i) {
		DC[i].block = malloc(BLOCKSIZE);
		if (i % 128 == 0) {
			debug_print(INFO, "Allocated cache block #%d", i+1);
		}
	}
	debug_print(NOTICE, "Allocated cache.");

	// load the block group descriptors
	int bgd_block_span = sizeof(ext2_bgdescriptor_t) * BGDS / BLOCKSIZE + 1;
	BGD = malloc(BLOCKSIZE * bgd_block_span);

	debug_print(INFO, "bgd_block_span = %d", bgd_block_span);

	int bgd_offset = 2;

	if (BLOCKSIZE > 1024) {
		bgd_offset = 1;
	}

	for (int i = 0; i < bgd_block_span; ++i) {
		ext2_disk_read_block(bgd_offset + i, (uint8_t *)((uint32_t)BGD + BLOCKSIZE * i));
	}

#if EXT2_DEBUG_BLOCK_DESCRIPTORS
	char * bg_buffer = malloc(BLOCKSIZE * sizeof(char));
	for (uint32_t i = 0; i < BGDS; ++i) {
		debug_print(INFO, "Block Group Descriptor #%d @ %d", i, bgd_offset + i * SB->blocks_per_group);
		debug_print(INFO, "\tBlock Bitmap @ %d", BGD[i].block_bitmap); { 
			debug_print(INFO, "\t\tExamining block bitmap at %d", BGD[i].block_bitmap);
			ext2_disk_read_block(BGD[i].block_bitmap, (uint8_t *)bg_buffer);
			uint32_t j = 0;
			while (BLOCKBIT(j)) {
				++j;
			}
			debug_print(INFO, "\t\tFirst free block in group is %d", j + BGD[i].block_bitmap - 2);
		}
		debug_print(INFO, "\tInode Bitmap @ %d", BGD[i].inode_bitmap); {
			debug_print(INFO, "\t\tExamining inode bitmap at %d", BGD[i].inode_bitmap);
			ext2_disk_read_block(BGD[i].inode_bitmap, (uint8_t *)bg_buffer);
			uint32_t j = 0;
			while (BLOCKBIT(j)) {
				++j;
			}
			debug_print(INFO, "\t\tFirst free inode in group is %d", j + ext2_disk_inodes_per_group * i + 1);
		}
		debug_print(INFO, "\tInode Table  @ %d", BGD[i].inode_table);
		debug_print(INFO, "\tFree Blocks =  %d", BGD[i].free_blocks_count);
		debug_print(INFO, "\tFree Inodes =  %d", BGD[i].free_inodes_count);
	}
	free(bg_buffer);
#endif

	ext2_inodetable_t *root_inode = ext2_disk_inode(2);
	RN = (fs_node_t *)malloc(sizeof(fs_node_t));
	if (!ext2_disk_node_root(root_inode, RN)) {
		debug_print(NOTICE, "Oh dear...");
	}
	debug_print(NOTICE, "Root file system is ready.");
	fs_root = RN;
	debug_print(NOTICE, "Mounted EXT2 disk, root VFS node is at 0x%x", RN);
}