⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	int namelen = dentry->d_name.len;	unsigned reclen = EXT2_DIR_REC_LEN(namelen);	unsigned long start, n;	unsigned long npages = dir_pages(dir);	struct page *page = NULL;	struct ext2_inode_info *ei = EXT2_I(dir);	ext2_dirent * de;	if (npages == 0)		goto out;	/* OFFSET_CACHE */	*res_page = NULL;	start = ei->i_dir_start_lookup;	if (start >= npages)		start = 0;	n = start;	do {		char *kaddr;		page = ext2_get_page(dir, n);		if (!IS_ERR(page)) {			kaddr = page_address(page);			de = (ext2_dirent *) kaddr;			kaddr += ext2_last_byte(dir, n) - reclen;			while ((char *) de <= kaddr) {				if (de->rec_len == 0) {					ext2_error(dir->i_sb, __FUNCTION__,						"zero-length directory entry");					ext2_put_page(page);					goto out;				}				if (ext2_match (namelen, name, de))					goto found;				de = ext2_next_entry(de);			}			ext2_put_page(page);		}		if (++n >= npages)			n = 0;		/* next page is past the blocks we've got */		if (unlikely(n > (dir->i_blocks >> (PAGE_CACHE_SHIFT - 9)))) {			ext2_error(dir->i_sb, __FUNCTION__,				"dir %lu size %lld exceeds block count %llu",				dir->i_ino, dir->i_size,				(unsigned long long)dir->i_blocks);			goto out;		}	} while (n != start);out:	return NULL;found:	*res_page = page;	ei->i_dir_start_lookup = n;	return de;}struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p){	struct page *page = ext2_get_page(dir, 0);	ext2_dirent *de = NULL;	if (!IS_ERR(page)) {		de = ext2_next_entry((ext2_dirent *) page_address(page));		*p = page;	}	return de;}ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry){	ino_t res = 0;	struct ext2_dir_entry_2 * de;	struct page *page;		de = ext2_find_entry (dir, dentry, &page);	if (de) {		res = le32_to_cpu(de->inode);		ext2_put_page(page);	}	return res;}/* Releases the page */void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,			struct page *page, struct inode *inode){	loff_t pos = page_offset(page) +			(char *) de - (char *) page_address(page);	unsigned len = ext2_rec_len_from_disk(de->rec_len);	int err;	lock_page(page);	err = __ext2_write_begin(NULL, page->mapping, pos, len,				AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);	BUG_ON(err);	de->inode = cpu_to_le32(inode->i_ino);	ext2_set_de_type(de, inode);	err = ext2_commit_chunk(page, pos, len);	ext2_put_page(page);	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;	EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;	mark_inode_dirty(dir);}/* *	Parent is locked. */int ext2_add_link (struct dentry *dentry, struct inode *inode){	struct inode *dir = dentry->d_parent->d_inode;	const char *name = dentry->d_name.name;	int namelen = dentry->d_name.len;	unsigned chunk_size = ext2_chunk_size(dir);	unsigned reclen = EXT2_DIR_REC_LEN(namelen);	unsigned short rec_len, name_len;	struct page *page = NULL;	ext2_dirent * de;	unsigned long npages = dir_pages(dir);	unsigned long n;	char *kaddr;	loff_t pos;	int err;	/*	 * We take care of directory expansion in the same loop.	 * This code plays outside i_size, so it locks the page	 * to protect that region.	 */	for (n = 0; n <= npages; n++) {		char *dir_end;		page = ext2_get_page(dir, n);		err = PTR_ERR(page);		if (IS_ERR(page))			goto out;		lock_page(page);		kaddr = page_address(page);		dir_end = kaddr + ext2_last_byte(dir, n);		de = (ext2_dirent *)kaddr;		kaddr += PAGE_CACHE_SIZE - reclen;		while ((char *)de <= kaddr) {			if ((char *)de == dir_end) {				/* We hit i_size */				name_len = 0;				rec_len = chunk_size;				de->rec_len = ext2_rec_len_to_disk(chunk_size);				de->inode = 0;				goto got_it;			}			if (de->rec_len == 0) {				ext2_error(dir->i_sb, __FUNCTION__,					"zero-length directory entry");				err = -EIO;				goto out_unlock;			}			err = -EEXIST;			if (ext2_match (namelen, name, de))				goto out_unlock;			name_len = EXT2_DIR_REC_LEN(de->name_len);			rec_len = ext2_rec_len_from_disk(de->rec_len);			if (!de->inode && rec_len >= reclen)				goto got_it;			if (rec_len >= name_len + reclen)				goto got_it;			de = (ext2_dirent *) ((char *) de + rec_len);		}		unlock_page(page);		ext2_put_page(page);	}	BUG();	return -EINVAL;got_it:	pos = page_offset(page) +		(char*)de - (char*)page_address(page);	err = __ext2_write_begin(NULL, page->mapping, pos, rec_len, 0,							&page, NULL);	if (err)		goto out_unlock;	if (de->inode) {		ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len);		de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len);		de->rec_len = ext2_rec_len_to_disk(name_len);		de = de1;	}	de->name_len = namelen;	memcpy(de->name, name, namelen);	de->inode = cpu_to_le32(inode->i_ino);	ext2_set_de_type (de, inode);	err = ext2_commit_chunk(page, pos, rec_len);	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;	EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL;	mark_inode_dirty(dir);	/* OFFSET_CACHE */out_put:	ext2_put_page(page);out:	return err;out_unlock:	unlock_page(page);	goto out_put;}/* * ext2_delete_entry deletes a directory entry by merging it with the * previous entry. Page is up-to-date. Releases the page. */int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ){	struct address_space *mapping = page->mapping;	struct inode *inode = mapping->host;	char *kaddr = page_address(page);	unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);	unsigned to = ((char *)dir - kaddr) +				ext2_rec_len_from_disk(dir->rec_len);	loff_t pos;	ext2_dirent * pde = NULL;	ext2_dirent * de = (ext2_dirent *) (kaddr + from);	int err;	while ((char*)de < (char*)dir) {		if (de->rec_len == 0) {			ext2_error(inode->i_sb, __FUNCTION__,				"zero-length directory entry");			err = -EIO;			goto out;		}		pde = de;		de = ext2_next_entry(de);	}	if (pde)		from = (char*)pde - (char*)page_address(page);	pos = page_offset(page) + from;	lock_page(page);	err = __ext2_write_begin(NULL, page->mapping, pos, to - from, 0,							&page, NULL);	BUG_ON(err);	if (pde)		pde->rec_len = ext2_rec_len_to_disk(to - from);	dir->inode = 0;	err = ext2_commit_chunk(page, pos, to - from);	inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;	EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL;	mark_inode_dirty(inode);out:	ext2_put_page(page);	return err;}/* * Set the first fragment of directory. */int ext2_make_empty(struct inode *inode, struct inode *parent){	struct address_space *mapping = inode->i_mapping;	struct page *page = grab_cache_page(mapping, 0);	unsigned chunk_size = ext2_chunk_size(inode);	struct ext2_dir_entry_2 * de;	int err;	void *kaddr;	if (!page)		return -ENOMEM;	err = __ext2_write_begin(NULL, page->mapping, 0, chunk_size, 0,							&page, NULL);	if (err) {		unlock_page(page);		goto fail;	}	kaddr = kmap_atomic(page, KM_USER0);	memset(kaddr, 0, chunk_size);	de = (struct ext2_dir_entry_2 *)kaddr;	de->name_len = 1;	de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1));	memcpy (de->name, ".\0\0", 4);	de->inode = cpu_to_le32(inode->i_ino);	ext2_set_de_type (de, inode);	de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1));	de->name_len = 2;	de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1));	de->inode = cpu_to_le32(parent->i_ino);	memcpy (de->name, "..\0", 4);	ext2_set_de_type (de, inode);	kunmap_atomic(kaddr, KM_USER0);	err = ext2_commit_chunk(page, 0, chunk_size);fail:	page_cache_release(page);	return err;}/* * routine to check that the specified directory is empty (for rmdir) */int ext2_empty_dir (struct inode * inode){	struct page *page = NULL;	unsigned long i, npages = dir_pages(inode);	for (i = 0; i < npages; i++) {		char *kaddr;		ext2_dirent * de;		page = ext2_get_page(inode, i);		if (IS_ERR(page))			continue;		kaddr = page_address(page);		de = (ext2_dirent *)kaddr;		kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1);		while ((char *)de <= kaddr) {			if (de->rec_len == 0) {				ext2_error(inode->i_sb, __FUNCTION__,					"zero-length directory entry");				printk("kaddr=%p, de=%p\n", kaddr, de);				goto not_empty;			}			if (de->inode != 0) {				/* check for . and .. */				if (de->name[0] != '.')					goto not_empty;				if (de->name_len > 2)					goto not_empty;				if (de->name_len < 2) {					if (de->inode !=					    cpu_to_le32(inode->i_ino))						goto not_empty;				} else if (de->name[1] != '.')					goto not_empty;			}			de = ext2_next_entry(de);		}		ext2_put_page(page);	}	return 1;not_empty:	ext2_put_page(page);	return 0;}const struct file_operations ext2_dir_operations = {	.llseek		= generic_file_llseek,	.read		= generic_read_dir,	.readdir	= ext2_readdir,	.ioctl		= ext2_ioctl,#ifdef CONFIG_COMPAT	.compat_ioctl	= ext2_compat_ioctl,#endif	.fsync		= ext2_sync_file,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -