Directory operation and file operation of Linux kernel file system

Posted by sciwaysoft on Fri, 17 Dec 2021 08:50:30 +0100

namei.c
1. Through nameI C continue to be familiar with the workflow and mode of file system inode dir_ Entry (file entry structure)

dir_ The entry structure has two elements
File name file inode number

2. By interpreting the actual process of the source code, we know the implementation method of directory operation, file operation and link operation
mkdir rmdir touch open read ln

3. Design method of code robustness
Operation permission of a file - inode node of the file - i_mode

dir_entry structure the entry structure of the file
We can think of it as a simplified i-node descriptor
One file corresponds to one inode node

Take another look at find_ What is the entry function
Function to find a file entry point in the current directory
Find dir of a file_ Enntry structure
Find the file entry point of the specified name parameter in the dir parameter directory, return the pointer entry point and return the cache, and find the cache of the name file.

add_entry
Add a file entry point with the specified name in the specified directory and use its res_dir returns the entry point and returns

static struct buffer_head * add_entry(struct m_inode * dir,
	const char * name, int namelen, struct dir_entry ** res_dir)
{
	int block,i;
	struct buffer_head * bh;
	struct dir_entry * de;

	*res_dir = NULL;
#ifdef NO_TRUNCATE
	if (namelen > NAME_LEN)
		return NULL;
#else
	if (namelen > NAME_LEN)
		namelen = NAME_LEN;
#endif
//Name truncation
	if (!namelen)
		return NULL;
//Logical block number of the storage directory file
//What's in the file directory
	if (!(block = dir->i_zone[0]))
		return NULL;
//Read the cache corresponding to BLOCK
	if (!(bh = bread(dir->i_dev,block)))
		return NULL;
	i = 0;
//Dir is stored in the directory_ entry
	de = (struct dir_entry *) bh->b_data;
	while (1) {
		if ((char *)de >= BLOCK_SIZE+bh->b_data) {
			brelse(bh);
			bh = NULL;
			block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK);
			if (!block)
				return NULL;
			if (!(bh = bread(dir->i_dev,block))) {
				i += DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			de = (struct dir_entry *) bh->b_data;
		}
		if (i*sizeof(struct dir_entry) >= dir->i_size) {
			de->inode=0;
			dir->i_size = (i+1)*sizeof(struct dir_entry);
			dir->i_dirt = 1;
			dir->i_ctime = CURRENT_TIME;
		}
		if (!de->inode) {
			dir->i_mtime = CURRENT_TIME;
			for (i=0; i < NAME_LEN ; i++)
				de->name[i]=(i<namelen)?get_fs_byte(name+i):0;
			bh->b_dirt = 1;
			*res_dir = de;
			return bh;
		}
		de++;
		i++;
	}
	brelse(bh);
	return NULL;
}

dir lookup for the specified directory
An empty file access point was found (the de - > inode of the dir_entry is 0)
The bh returned is the disk cache of the directory

static struct m_inode * get_dir(const char * pathname)

static struct m_inode * get_dir(const char * pathname)
{
	char c;
	const char * thisname;
	struct m_inode * inode;
	struct buffer_head * bh;
	int namelen,inr,idev;
	struct dir_entry * de;

//Current root file system in Beijing
	if (!current->root || !current->root->i_count)
		panic("No root inode");
//Working directory of the current process
	if (!current->pwd || !current->pwd->i_count)
		panic("No cwd inode");
	if ((c=get_fs_byte(pathname))=='/') {
		inode = current->root;
		pathname++;
	} else if (c)
		inode = current->pwd;
	else
		return NULL;	/* empty name is bad */
	inode->i_count++;
	while (1) {
		thisname = pathname;
		if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) {
			iput(inode);
			return NULL;
		}
		for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++)
			/* nothing */ ;
		if (!c)
			return inode;
		if (!(bh = find_entry(&inode,thisname,namelen,&de))) {
			iput(inode);
			return NULL;
		}
		inr = de->inode;
		idev = inode->i_dev;
		brelse(bh);
		iput(inode);
		if (!(inode = iget(idev,inr)))
			return NULL;
	}
}

To manipulate a file, we first need to find its inode node
The inode node of the specified path can be found
For example, cd /work/work /, we need to find the inode node of the specified path first

static struct m_inode * dir_namei(const char * pathname,
int * namelen, const char ** name)

static struct m_inode * dir_namei(const char * pathname,
	int * namelen, const char ** name)
{
	char c;
	const char * basename;
	struct m_inode * dir;

	if (!(dir = get_dir(pathname)))
		return NULL;
	basename = pathname;
	while (c=get_fs_byte(pathname++))
		if (c=='/')
			basename=pathname;
	*namelen = pathname-basename-1;
	*name = basename;
	return dir;
}

This is a supplement to the one above
Find the highest directory with the given path name, return its inode node, return the name length of the highest path, and return the name of the highest path

sys_unlink

sys_link rename the file
Create a linked file (hard link) for the file
When creating a linked file, explain what the linked file is
To link a file is to add a dir to an existing file_ entry
1. Find inode of existing file
2. Creates a new dir in the specified file path_ entry
3. Put the new dir_ The entry is mapped to the old inode.

Topics: Linux CTF