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

📄 namei.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
	ext3_journal_stop(handle, dir);	return err;out_no_entry:	inode->i_nlink = 0;	ext3_mark_inode_dirty(handle, inode);	iput (inode);	goto out_stop;}/* * routine to check that the specified directory is empty (for rmdir) */static int empty_dir (struct inode * inode){	unsigned long offset;	struct buffer_head * bh;	struct ext3_dir_entry_2 * de, * de1;	struct super_block * sb;	int err;	sb = inode->i_sb;	if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) ||	    !(bh = ext3_bread (NULL, inode, 0, 0, &err))) {	    	ext3_warning (inode->i_sb, "empty_dir",			      "bad directory (dir #%lu) - no data block",			      inode->i_ino);		return 1;	}	de = (struct ext3_dir_entry_2 *) bh->b_data;	de1 = (struct ext3_dir_entry_2 *)			((char *) de + le16_to_cpu(de->rec_len));	if (le32_to_cpu(de->inode) != inode->i_ino ||			!le32_to_cpu(de1->inode) || 			strcmp (".", de->name) ||			strcmp ("..", de1->name)) {	    	ext3_warning (inode->i_sb, "empty_dir",			      "bad directory (dir #%lu) - no `.' or `..'",			      inode->i_ino);		brelse (bh);		return 1;	}	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);	de = (struct ext3_dir_entry_2 *)			((char *) de1 + le16_to_cpu(de1->rec_len));	while (offset < inode->i_size ) {		if (!bh ||			(void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {			brelse (bh);			bh = ext3_bread (NULL, inode,				offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err);			if (!bh) {#if 0				ext3_error (sb, "empty_dir",				"directory #%lu contains a hole at offset %lu",					inode->i_ino, offset);#endif				offset += sb->s_blocksize;				continue;			}			de = (struct ext3_dir_entry_2 *) bh->b_data;		}		if (!ext3_check_dir_entry ("empty_dir", inode, de, bh,					   offset)) {			brelse (bh);			return 1;		}		if (le32_to_cpu(de->inode)) {			brelse (bh);			return 0;		}		offset += le16_to_cpu(de->rec_len);		de = (struct ext3_dir_entry_2 *)				((char *) de + le16_to_cpu(de->rec_len));	}	brelse (bh);	return 1;}/* ext3_orphan_add() links an unlinked or truncated inode into a list of * such inodes, starting at the superblock, in case we crash before the * file is closed/deleted, or in case the inode truncate spans multiple * transactions and the last transaction is not recovered after a crash. * * At filesystem recovery time, we walk this list deleting unlinked * inodes and truncating linked inodes in ext3_orphan_cleanup(). */int ext3_orphan_add(handle_t *handle, struct inode *inode){	struct super_block *sb = inode->i_sb;	struct ext3_iloc iloc;	int err = 0, rc;		lock_super(sb);	if (!list_empty(&inode->u.ext3_i.i_orphan))		goto out_unlock;	/* Orphan handling is only valid for files with data blocks	 * being truncated, or files being unlinked. */	/* @@@ FIXME: Observation from aviro:	 * I think I can trigger J_ASSERT in ext3_orphan_add().  We block 	 * here (on lock_super()), so race with ext3_link() which might bump	 * ->i_nlink. For, say it, character device. Not a regular file,	 * not a directory, not a symlink and ->i_nlink > 0.	 */	J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||		S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);	BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "get_write_access");	err = ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);	if (err)		goto out_unlock;		err = ext3_reserve_inode_write(handle, inode, &iloc);	if (err)		goto out_unlock;	/* Insert this inode at the head of the on-disk orphan list... */	NEXT_ORPHAN(inode) = le32_to_cpu(EXT3_SB(sb)->s_es->s_last_orphan);	EXT3_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);	err = ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);	rc = ext3_mark_iloc_dirty(handle, inode, &iloc);	if (!err)		err = rc;	/* Only add to the head of the in-memory list if all the	 * previous operations succeeded.  If the orphan_add is going to	 * fail (possibly taking the journal offline), we can't risk	 * leaving the inode on the orphan list: stray orphan-list	 * entries can cause panics at unmount time.	 *	 * This is safe: on error we're going to ignore the orphan list	 * anyway on the next recovery. */	if (!err)		list_add(&inode->u.ext3_i.i_orphan, &EXT3_SB(sb)->s_orphan);	jbd_debug(4, "superblock will point to %ld\n", inode->i_ino);	jbd_debug(4, "orphan inode %ld will point to %d\n",			inode->i_ino, NEXT_ORPHAN(inode));out_unlock:	unlock_super(sb);	ext3_std_error(inode->i_sb, err);	return err;}/* * ext3_orphan_del() removes an unlinked or truncated inode from the list * of such inodes stored on disk, because it is finally being cleaned up. */int ext3_orphan_del(handle_t *handle, struct inode *inode){	struct list_head *prev;	struct ext3_sb_info *sbi;	ino_t ino_next; 	struct ext3_iloc iloc;	int err = 0;		lock_super(inode->i_sb);	if (list_empty(&inode->u.ext3_i.i_orphan)) {		unlock_super(inode->i_sb);		return 0;	}	ino_next = NEXT_ORPHAN(inode);	prev = inode->u.ext3_i.i_orphan.prev;	sbi = EXT3_SB(inode->i_sb);	jbd_debug(4, "remove inode %ld from orphan list\n", inode->i_ino);	list_del(&inode->u.ext3_i.i_orphan);	INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);	/* If we're on an error path, we may not have a valid	 * transaction handle with which to update the orphan list on	 * disk, but we still need to remove the inode from the linked	 * list in memory. */	if (!handle)		goto out;		err = ext3_reserve_inode_write(handle, inode, &iloc);	if (err)		goto out_err;	if (prev == &sbi->s_orphan) {		jbd_debug(4, "superblock will point to %ld\n", ino_next);		BUFFER_TRACE(sbi->s_sbh, "get_write_access");		err = ext3_journal_get_write_access(handle, sbi->s_sbh);		if (err)			goto out_brelse;		sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);		err = ext3_journal_dirty_metadata(handle, sbi->s_sbh);	} else {		struct ext3_iloc iloc2;		struct inode *i_prev =			list_entry(prev, struct inode, u.ext3_i.i_orphan);				jbd_debug(4, "orphan inode %ld will point to %ld\n",			  i_prev->i_ino, ino_next);		err = ext3_reserve_inode_write(handle, i_prev, &iloc2);		if (err)			goto out_brelse;		NEXT_ORPHAN(i_prev) = ino_next;		err = ext3_mark_iloc_dirty(handle, i_prev, &iloc2);	}	if (err)		goto out_brelse;	NEXT_ORPHAN(inode) = 0;	err = ext3_mark_iloc_dirty(handle, inode, &iloc);	if (err)		goto out_brelse;out_err: 		ext3_std_error(inode->i_sb, err);out:	unlock_super(inode->i_sb);	return err;out_brelse:	brelse(iloc.bh);	goto out_err;}static int ext3_rmdir (struct inode * dir, struct dentry *dentry){	int retval;	struct inode * inode;	struct buffer_head * bh;	struct ext3_dir_entry_2 * de;	handle_t *handle;	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);	if (IS_ERR(handle))		return PTR_ERR(handle);	retval = -ENOENT;	bh = ext3_find_entry (dentry, &de);	if (!bh)		goto end_rmdir;	if (IS_SYNC(dir))		handle->h_sync = 1;	inode = dentry->d_inode;	DQUOT_INIT(inode);	retval = -EIO;	if (le32_to_cpu(de->inode) != inode->i_ino)		goto end_rmdir;	retval = -ENOTEMPTY;	if (!empty_dir (inode))		goto end_rmdir;	retval = ext3_delete_entry(handle, dir, de, bh);	if (retval)		goto end_rmdir;	if (inode->i_nlink != 2)		ext3_warning (inode->i_sb, "ext3_rmdir",			      "empty directory has nlink!=2 (%d)",			      inode->i_nlink);	inode->i_version = ++event;	inode->i_nlink = 0;	/* There's no need to set i_disksize: the fact that i_nlink is	 * zero will ensure that the right thing happens during any	 * recovery. */	inode->i_size = 0;	ext3_orphan_add(handle, inode);	ext3_mark_inode_dirty(handle, inode);	dir->i_nlink--;	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;	dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;	ext3_mark_inode_dirty(handle, dir);end_rmdir:	ext3_journal_stop(handle, dir);	brelse (bh);	return retval;}static int ext3_unlink(struct inode * dir, struct dentry *dentry){	int retval;	struct inode * inode;	struct buffer_head * bh;	struct ext3_dir_entry_2 * de;	handle_t *handle;	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_SYNC(dir))		handle->h_sync = 1;	retval = -ENOENT;	bh = ext3_find_entry (dentry, &de);	if (!bh)		goto end_unlink;	inode = dentry->d_inode;	DQUOT_INIT(inode);	retval = -EIO;	if (le32_to_cpu(de->inode) != inode->i_ino)		goto end_unlink;		if (!inode->i_nlink) {		ext3_warning (inode->i_sb, "ext3_unlink",			      "Deleting nonexistent file (%lu), %d",			      inode->i_ino, inode->i_nlink);		inode->i_nlink = 1;	}	retval = ext3_delete_entry(handle, dir, de, bh);	if (retval)		goto end_unlink;	dir->i_ctime = dir->i_mtime = CURRENT_TIME;	dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;	ext3_mark_inode_dirty(handle, dir);	inode->i_nlink--;	if (!inode->i_nlink)		ext3_orphan_add(handle, inode);	ext3_mark_inode_dirty(handle, inode);	inode->i_ctime = dir->i_ctime;	retval = 0;end_unlink:	ext3_journal_stop(handle, dir);	brelse (bh);	return retval;}static int ext3_symlink (struct inode * dir,		struct dentry *dentry, const char * symname){	handle_t *handle;	struct inode * inode;	int l, err;	l = strlen(symname)+1;	if (l > dir->i_sb->s_blocksize)		return -ENAMETOOLONG;	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 5);	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_SYNC(dir))		handle->h_sync = 1;	inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);	err = PTR_ERR(inode);	if (IS_ERR(inode))		goto out_stop;	if (l > sizeof (inode->u.ext3_i.i_data)) {		inode->i_op = &page_symlink_inode_operations;		inode->i_mapping->a_ops = &ext3_aops;		/*		 * block_symlink() calls back into ext3_prepare/commit_write.		 * We have a transaction open.  All is sweetness.  It also sets		 * i_size in generic_commit_write().		 */		err = block_symlink(inode, symname, l);		if (err)			goto out_no_entry;	} else {		inode->i_op = &ext3_fast_symlink_inode_operations;		memcpy((char*)&inode->u.ext3_i.i_data,symname,l);		inode->i_size = l-1;	}	inode->u.ext3_i.i_disksize = inode->i_size;	err = ext3_add_nondir(handle, dentry, inode);	ext3_mark_inode_dirty(handle, inode);out_stop:	ext3_journal_stop(handle, dir);	return err;out_no_entry:	ext3_dec_count(handle, inode);	ext3_mark_inode_dirty(handle, inode);	iput (inode);	goto out_stop;}static int ext3_link (struct dentry * old_dentry,		struct inode * dir, struct dentry *dentry){	handle_t *handle;	struct inode *inode = old_dentry->d_inode;	int err;	if (S_ISDIR(inode->i_mode))		return -EPERM;	if (inode->i_nlink >= EXT3_LINK_MAX)		return -EMLINK;	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS);	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_SYNC(dir))		handle->h_sync = 1;	inode->i_ctime = CURRENT_TIME;	ext3_inc_count(handle, inode);	atomic_inc(&inode->i_count);	err = ext3_add_nondir(handle, dentry, inode);	ext3_mark_inode_dirty(handle, inode);	ext3_journal_stop(handle, dir);	return err;}#define PARENT_INO(buffer) \	((struct ext3_dir_entry_2 *) ((char *) buffer + \	le16_to_cpu(((struct ext3_dir_entry_2 *) buffer)->rec_len)))->inode/* * Anybody can rename anything with this: the permission checks are left to the * higher-level routines. */static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,			   struct inode * new_dir,struct dentry *new_dentry){	handle_t *handle;	struct inode * old_inode, * new_inode;	struct buffer_head * old_bh, * new_bh, * dir_bh;	struct ext3_dir_entry_2 * old_de, * new_de;	int retval;	old_bh = new_bh = dir_bh = NULL;	handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + 2);	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_SYNC(old_dir) || IS_SYNC(new_dir))		handle->h_sync = 1;	old_bh = ext3_find_entry (old_dentry, &old_de);	/*	 *  Check for inode number is _not_ due to possible IO errors.	 *  We might rmdir the source, keep it as pwd of some process	 *  and merrily kill the link to whatever was created under the	 *  same name. Goodbye sticky bit ;-<	 */	old_inode = old_dentry->d_inode;	retval = -ENOENT;	if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)		goto end_rename;	new_inode = new_dentry->d_inode;	new_bh = ext3_find_entry (new_dentry, &new_de);	if (new_bh) {		if (!new_inode) {			brelse (new_bh);			new_bh = NULL;		} else {			DQUOT_INIT(new_inode);		}	}	if (S_ISDIR(old_inode->i_mode)) {		if (new_inode) {			retval = -ENOTEMPTY;			if (!empty_dir (new_inode))				goto end_rename;		}		retval = -EIO;		dir_bh = ext3_bread (handle, old_inode, 0, 0, &retval);		if (!dir_bh)			goto end_rename;		if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)			goto end_rename;		retval = -EMLINK;		if (!new_inode && new_dir!=old_dir &&				new_dir->i_nlink >= EXT3_LINK_MAX)			goto end_rename;	}	if (!new_bh) {		retval = ext3_add_entry (handle, new_dentry, old_inode);		if (retval)			goto end_rename;	} else {		BUFFER_TRACE(new_bh, "get write access");		BUFFER_TRACE(new_bh, "get_write_access");		ext3_journal_get_write_access(handle, new_bh);		new_de->inode = le32_to_cpu(old_inode->i_ino);		if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb,					      EXT3_FEATURE_INCOMPAT_FILETYPE))			new_de->file_type = old_de->file_type;		new_dir->i_version = ++event;		BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata");		ext3_journal_dirty_metadata(handle, new_bh);		brelse(new_bh);		new_bh = NULL;	}	/*	 * Like most other Unix systems, set the ctime for inodes on a	 * rename.	 */	old_inode->i_ctime = CURRENT_TIME;	ext3_mark_inode_dirty(handle, old_inode);	/*	 * ok, that's it	 */	ext3_delete_entry(handle, old_dir, old_de, old_bh);	if (new_inode) {		new_inode->i_nlink--;		new_inode->i_ctime = CURRENT_TIME;	}	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;	old_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;	if (dir_bh) {		BUFFER_TRACE(dir_bh, "get_write_access");		ext3_journal_get_write_access(handle, dir_bh);		PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);		BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata");		ext3_journal_dirty_metadata(handle, dir_bh);		old_dir->i_nlink--;		if (new_inode) {			new_inode->i_nlink--;		} else {			new_dir->i_nlink++;			new_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;			ext3_mark_inode_dirty(handle, new_dir);		}	}	ext3_mark_inode_dirty(handle, old_dir);	if (new_inode) {		ext3_mark_inode_dirty(handle, new_inode);		if (!new_inode->i_nlink)			ext3_orphan_add(handle, new_inode);	}	retval = 0;end_rename:	brelse (dir_bh);	brelse (old_bh);	brelse (new_bh);	ext3_journal_stop(handle, old_dir);	return retval;}/* * directories can handle most operations... */struct inode_operations ext3_dir_inode_operations = {	create:		ext3_create,		/* BKL held */	lookup:		ext3_lookup,		/* BKL held */	link:		ext3_link,		/* BKL held */	unlink:		ext3_unlink,		/* BKL held */	symlink:	ext3_symlink,		/* BKL held */	mkdir:		ext3_mkdir,		/* BKL held */	rmdir:		ext3_rmdir,		/* BKL held */	mknod:		ext3_mknod,		/* BKL held */	rename:		ext3_rename,		/* BKL held */};

⌨️ 快捷键说明

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