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

📄 dir.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
字号:
/* * linux/fs/hfs/dir.c * * Copyright (C) 1995-1997  Paul H. Hargrove * This file may be distributed under the terms of the GNU General Public License. * * This file contains directory-related functions independent of which * scheme is being used to represent forks. * * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds * * "XXX" in a comment is a note to myself to consider changing something. * * In function preconditions the term "valid" applied to a pointer to * a structure means that the pointer is non-NULL and the structure it * points to has all fields initialized to consistent values. */#include "hfs.h"#include <linux/hfs_fs_sb.h>#include <linux/hfs_fs_i.h>#include <linux/hfs_fs.h>/*================ File-local functions ================*//* * build_key() * * Build a key for a file by the given name in the given directory. * If the name matches one of the reserved names returns 1 otherwise 0. */static int build_key(struct hfs_cat_key *key, struct inode *dir,		     const char *name, int len){	struct hfs_name cname;	const struct hfs_name *reserved;	/* mangle the name */	hfs_nameout(dir, &cname, name, len);	/* check against reserved names */	reserved = HFS_SB(dir->i_sb)->s_reserved1;	while (reserved->Len) {		if (hfs_streq(reserved->Name, reserved->Len, 			      cname.Name, cname.Len)) {			return 1;		}		++reserved;	}	/* check against the names reserved only in the root directory */	if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) {		reserved = HFS_SB(dir->i_sb)->s_reserved2;		while (reserved->Len) {			if (hfs_streq(reserved->Name, reserved->Len,				      cname.Name, cname.Len)) {				return 1;			}			++reserved;		}	}	/* build the key */	hfs_cat_build_key(HFS_I(dir)->entry->cnid, &cname, key);	return 0;}/* * update_dirs_plus() * * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and * 'i_version' of the inodes associated with a directory that has * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it. */static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir){	int i;	for (i = 0; i < 4; ++i) {		struct dentry *de = dir->sys_entry[i];		if (de) {		        struct inode *tmp = de->d_inode;			if (S_ISDIR(tmp->i_mode)) {				if (is_dir &&				    (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {					/* In "normal" directory only */					++(tmp->i_nlink);				}				tmp->i_size += HFS_I(tmp)->dir_size;				tmp->i_version = ++event;			}			tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;			mark_inode_dirty(tmp);		}	}}/* * update_dirs_minus() * * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and * 'i_version' of the inodes associated with a directory that has * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed. */static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir){	int i;	for (i = 0; i < 4; ++i) {		struct dentry *de = dir->sys_entry[i];		if (de) {		        struct inode *tmp = de->d_inode;			if (S_ISDIR(tmp->i_mode)) {				if (is_dir &&				    (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {					/* In "normal" directory only */					--(tmp->i_nlink);				}				tmp->i_size -= HFS_I(tmp)->dir_size;				tmp->i_version = ++event;			}			tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;			mark_inode_dirty(tmp);		}	}}/* * mark_inodes_deleted() * * Update inodes associated with a deleted entry to reflect its deletion. * Well, we really just drop the dentry. * * XXX: we should be using delete_inode for some of this stuff. */static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, 				       struct dentry *dentry){	struct dentry *de;	struct inode *tmp;	int i;	for (i = 0; i < 4; ++i) {		if ((de = entry->sys_entry[i]) && (dentry != de)) {		      dget(de);		      tmp = de->d_inode;		      tmp->i_nlink = 0;		      tmp->i_ctime = CURRENT_TIME;		      mark_inode_dirty(tmp);		      d_delete(de);		      dput(de);		}	}}/*================ Global functions ================*//* * hfs_create() * * This is the create() entry in the inode_operations structure for * regular HFS directories.  The purpose is to create a new file in * a directory and return a corresponding inode, given the inode for * the directory and the name (and its length) of the new file. */int hfs_create(struct inode * dir, struct dentry *dentry, int mode){	struct hfs_cat_entry *entry = HFS_I(dir)->entry;	struct hfs_cat_entry *new;	struct hfs_cat_key key;	struct inode *inode;	int error;	/* build the key, checking against reserved names */	if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) 		return -EEXIST;	if ((error = hfs_cat_create(entry, &key, 			       (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,			       HFS_SB(dir->i_sb)->s_type,			       HFS_SB(dir->i_sb)->s_creator, &new)))		return error;	/* create an inode for the new file. back out if we run	 * into trouble. */	new->count++; /* hfs_iget() eats one */	if (!(inode = hfs_iget(new, HFS_I(dir)->file_type, dentry))) {		hfs_cat_delete(entry, new, 1);		hfs_cat_put(new);		return -EIO;	}	hfs_cat_put(new);	update_dirs_plus(entry, 0);	/* toss any relevant negative dentries */	if (HFS_I(dir)->d_drop_op)		HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);	mark_inode_dirty(inode);	d_instantiate(dentry, inode);	return 0;}/* * hfs_mkdir() * * This is the mkdir() entry in the inode_operations structure for * regular HFS directories.  The purpose is to create a new directory * in a directory, given the inode for the parent directory and the * name (and its length) of the new directory. */int hfs_mkdir(struct inode * parent, struct dentry *dentry, int mode){	struct hfs_cat_entry *entry = HFS_I(parent)->entry;	struct hfs_cat_entry *new;	struct hfs_cat_key key;	struct inode *inode;	int error;	/* build the key, checking against reserved names */	if (build_key(&key, parent, dentry->d_name.name, 		      dentry->d_name.len)) 		return -EEXIST;	/* try to create the directory */	if ((error = hfs_cat_mkdir(entry, &key, &new)))		return error;	/* back out if we run into trouble */	new->count++; /* hfs_iget eats one */	if (!(inode = hfs_iget(new, HFS_I(parent)->file_type, dentry))) {		hfs_cat_delete(entry, new, 1);		hfs_cat_put(new);		return -EIO;	}	hfs_cat_put(new);	update_dirs_plus(entry, 1);	mark_inode_dirty(inode);	d_instantiate(dentry, inode);	return 0;}/* * hfs_unlink() * * This is the unlink() entry in the inode_operations structure for * regular HFS directories.  The purpose is to delete an existing * file, given the inode for the parent directory and the name * (and its length) of the existing file. */int hfs_unlink(struct inode * dir, struct dentry *dentry){	struct hfs_cat_entry *entry = HFS_I(dir)->entry;	struct hfs_cat_entry *victim = NULL;	struct hfs_cat_key key;	int error;	if (build_key(&key, dir, dentry->d_name.name,		      dentry->d_name.len)) 		return -EPERM;	if (!(victim = hfs_cat_get(entry->mdb, &key))) 		return -ENOENT;	error = -EPERM;	if (victim->type != HFS_CDR_FIL)		goto hfs_unlink_put;	if (!(error = hfs_cat_delete(entry, victim, 1))) {		struct inode *inode = dentry->d_inode;		mark_inodes_deleted(victim, dentry);		inode->i_nlink--; 		inode->i_ctime = CURRENT_TIME;		mark_inode_dirty(inode);		update_dirs_minus(entry, 0);	}hfs_unlink_put:	hfs_cat_put(victim);	/* Note that hfs_cat_put(NULL) is safe. */	return error;}/* * hfs_rmdir() * * This is the rmdir() entry in the inode_operations structure for * regular HFS directories.  The purpose is to delete an existing * directory, given the inode for the parent directory and the name * (and its length) of the existing directory. */int hfs_rmdir(struct inode * parent, struct dentry *dentry){	struct hfs_cat_entry *entry = HFS_I(parent)->entry;	struct hfs_cat_entry *victim = NULL;	struct inode *inode = dentry->d_inode;	struct hfs_cat_key key;	int error;	if (build_key(&key, parent, dentry->d_name.name,		      dentry->d_name.len))		return -EPERM;	if (!(victim = hfs_cat_get(entry->mdb, &key)))		return -ENOENT;	error = -ENOTDIR;	if (victim->type != HFS_CDR_DIR) 		goto hfs_rmdir_put;	error = -EBUSY;	if (!d_unhashed(dentry))		goto hfs_rmdir_put;	/* we only have to worry about 2 and 3 for mount points */	if (victim->sys_entry[2] && d_mountpoint(victim->sys_entry[2]))		goto hfs_rmdir_put;	if (victim->sys_entry[3] && d_mountpoint(victim->sys_entry[3])) 		goto hfs_rmdir_put;		if ((error = hfs_cat_delete(entry, victim, 1)))		goto hfs_rmdir_put;	mark_inodes_deleted(victim, dentry);	inode->i_nlink = 0;	inode->i_ctime = CURRENT_TIME;	mark_inode_dirty(inode);	update_dirs_minus(entry, 1);	 hfs_rmdir_put:	hfs_cat_put(victim);	/* Note that hfs_cat_put(NULL) is safe. */	return error;}/* * hfs_rename() * * This is the rename() entry in the inode_operations structure for * regular HFS directories.  The purpose is to rename an existing * file or directory, given the inode for the current directory and * the name (and its length) of the existing file/directory and the * inode for the new directory and the name (and its length) of the * new file/directory. * XXX: how do you handle must_be dir? */int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,	       struct inode *new_dir, struct dentry *new_dentry){	struct hfs_cat_entry *old_parent = HFS_I(old_dir)->entry;	struct hfs_cat_entry *new_parent = HFS_I(new_dir)->entry;	struct hfs_cat_entry *victim = NULL;	struct hfs_cat_entry *deleted;	struct hfs_cat_key key;	int error;	if (build_key(&key, old_dir, old_dentry->d_name.name,		      old_dentry->d_name.len) ||	    (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) 		return -EPERM;	if (!(victim = hfs_cat_get(old_parent->mdb, &key))) 		return -ENOENT;	error = -EPERM;	if (build_key(&key, new_dir, new_dentry->d_name.name,			     new_dentry->d_name.len)) 		goto hfs_rename_put;	if (!(error = hfs_cat_move(old_parent, new_parent,				   victim, &key, &deleted))) {		int is_dir = (victim->type == HFS_CDR_DIR);				/* drop the old dentries */		mark_inodes_deleted(victim, old_dentry);		update_dirs_minus(old_parent, is_dir);		if (deleted) {			mark_inodes_deleted(deleted, new_dentry);			hfs_cat_put(deleted);		} else {			/* no existing inodes. just drop negative dentries */			if (HFS_I(new_dir)->d_drop_op) 				HFS_I(new_dir)->d_drop_op(new_dentry, 					  HFS_I(new_dir)->file_type);			update_dirs_plus(new_parent, is_dir);		}		}hfs_rename_put:	hfs_cat_put(victim);	/* Note that hfs_cat_put(NULL) is safe. */	return error;}

⌨️ 快捷键说明

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