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

📄 catalog.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}		/* Block writers */	start_read(dir);	/* Find the directory */	hfs_cat_build_key(dir->cnid, NULL, &key);	error = hfs_bfind(brec, dir->mdb->cat_tree,			  HFS_BKEY(&key), HFS_BFIND_READ_EQ);	if (error) {		end_read(dir);	}	return error;}/* * hfs_cat_next() * * Given a catalog brec structure, replace it with the count'th next brec * in the same directory. * Return an error code if there is a problem, 0 if OK. * Note that an error code of -ENOENT means there are no more entries * in this directory. * The directory is "closed" on an error. */int hfs_cat_next(struct hfs_cat_entry *dir, struct hfs_brec *brec,		 hfs_u16 count, hfs_u32 *cnid, hfs_u8 *type){	int error;	if (!dir || !brec) {		return -EINVAL;	}	/* Get the count'th next catalog tree entry */	error = hfs_bsucc(brec, count);	if (!error) {		struct hfs_cat_key *key = (struct hfs_cat_key *)brec->key;		if (hfs_get_nl(key->ParID) != dir->cnid) {			hfs_brec_relse(brec, NULL);			error = -ENOENT;		}	}	if (!error) {		*type = ((struct hfs_cat_rec *)brec->data)->cdrType;		*cnid = brec_to_id(brec);	} else {		end_read(dir);	}	return error;}/* * hfs_cat_close() * * Given a catalog brec structure, replace it with the count'th next brec * in the same directory. * Return an error code if there is a problem, 0 if OK. * Note that an error code of -ENOENT means there are no more entries * in this directory. */void hfs_cat_close(struct hfs_cat_entry *dir, struct hfs_brec *brec){	if (dir && brec) {		hfs_brec_relse(brec, NULL);		end_read(dir);	}}/* * hfs_cat_parent() * * Given a catalog entry, return the entry for its parent. * Uses catalog key for the entry to get its parent's ID * and then uses the parent's thread record to locate the * parent's actual catalog entry. */struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry){	struct hfs_cat_entry *retval = NULL;	struct hfs_mdb *mdb = entry->mdb;	struct hfs_brec brec;	struct hfs_cat_key key;	int error;	lock_entry(entry);	if (!(entry->state & HFS_DELETED)) {		hfs_cat_build_key(hfs_get_nl(entry->key.ParID), NULL, &key);		error = hfs_bfind(&brec, mdb->cat_tree,				  HFS_BKEY(&key), HFS_BFIND_READ_EQ);		if (!error) {			/* convert thread record to key */			struct hfs_cat_rec *rec = brec.data;			key.KeyLen = 6 + rec->u.thd.CName.Len;			memcpy(&key.ParID, &rec->u.thd.ParID,                       	       sizeof(hfs_u32) + sizeof(struct hfs_name));                	hfs_brec_relse(&brec, NULL);			retval = hfs_cat_get(mdb, &key);		}	}	unlock_entry(entry);	return retval;}	/* * hfs_cat_create() * * Create a new file with the indicated name in the indicated directory. * The file will have the indicated flags, type and creator. * If successful an (struct hfs_cat_entry) is returned in '*result'. */int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key,		   hfs_u8 flags, hfs_u32 type, hfs_u32 creator,		   struct hfs_cat_entry **result){	struct hfs_cat_rec record;	hfs_u32 id = new_cnid(parent->mdb);	hfs_u32 mtime = hfs_time();#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)	hfs_warn("hfs_cat_create: %p/%s flags=%d res=%p\n",		 parent, key->CName.Name, flags, result);#endif	/* init some fields for the file record */	memset(&record, 0, sizeof(record));	record.cdrType = HFS_CDR_FIL;	record.u.fil.Flags = flags | HFS_FIL_USED;	hfs_put_nl(id,      record.u.fil.FlNum);	hfs_put_nl(mtime,   record.u.fil.CrDat);	hfs_put_nl(mtime,   record.u.fil.MdDat);	hfs_put_nl(0,       record.u.fil.BkDat);	hfs_put_nl(type,    record.u.fil.UsrWds.fdType);	hfs_put_nl(creator, record.u.fil.UsrWds.fdCreator);	return create_entry(parent, key, &record, 0, id, result);}/* * hfs_cat_mkdir() * * Create a new directory with the indicated name in the indicated directory. * If successful an (struct hfs_cat_entry) is returned in '*result'. */int hfs_cat_mkdir(struct hfs_cat_entry *parent, struct hfs_cat_key *key,		  struct hfs_cat_entry **result){	struct hfs_cat_rec record;	hfs_u32 id = new_cnid(parent->mdb);	hfs_u32 mtime = hfs_time();#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)	hfs_warn("hfs_cat_mkdir: %p/%s res=%p\n", parent, key->CName.Name,		 result);#endif	/* init some fields for the directory record */	memset(&record, 0, sizeof(record));	record.cdrType = HFS_CDR_DIR;	hfs_put_nl(id,     record.u.dir.DirID);	hfs_put_nl(mtime, record.u.dir.CrDat);	hfs_put_nl(mtime, record.u.dir.MdDat);	hfs_put_nl(0,     record.u.dir.BkDat);	hfs_put_hs(0xff,  record.u.dir.UsrInfo.frView);	return create_entry(parent, key, &record, 1, id, result);}/* * hfs_cat_delete() * * Delete the indicated file or directory. * The associated thread is also removed unless ('with_thread'==0). */int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry,		   int with_thread){	struct hfs_cat_key key;	struct hfs_mdb *mdb = parent->mdb;	int is_dir, error = 0;#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)	hfs_warn("hfs_cat_delete: %p/%p type=%d state=%lu, thread=%d\n",		 parent, entry, entry->type, entry->state, with_thread);#endif	if (parent->mdb != entry->mdb) {		return -EINVAL;	}	if (entry->type == HFS_CDR_FIL) {		with_thread = (entry->u.file.flags&HFS_FIL_THD) && with_thread;		is_dir = 0;	} else {		is_dir = 1;	}	/* keep readers from getting confused by changing dir size */	start_write(parent);	/* don't delete a busy directory */	if (entry->type == HFS_CDR_DIR) {		start_read(entry);		error = -ENOTEMPTY;		if (entry->u.dir.files || entry->u.dir.dirs) 			goto hfs_delete_end;	}	/* try to delete the file or directory */	lock_entry(entry);	error = -ENOENT;	if ((entry->state & HFS_DELETED)) {		/* somebody beat us to it. */		goto hfs_delete_unlock;	}			/* delete the catalog record */	if ((error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key)))) {		goto hfs_delete_unlock;	}	/* Mark the entry deleted and remove it from the cache */	delete_entry(entry);	/* try to delete the thread entry if it exists */	if (with_thread) {		hfs_cat_build_key(entry->cnid, NULL, &key);		(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key));	}		update_dir(mdb, parent, is_dir, -1);hfs_delete_unlock:	unlock_entry(entry);hfs_delete_end:	if (entry->type == HFS_CDR_DIR) {		end_read(entry);	}	end_write(parent);	return error;}/* * hfs_cat_move() * * Rename a file or directory, possibly to a new directory. * If the destination exists it is removed and a * (struct hfs_cat_entry) for it is returned in '*result'. */int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir,		 struct hfs_cat_entry *entry, struct hfs_cat_key *new_key,		 struct hfs_cat_entry **removed){	struct hfs_cat_entry *dest;	struct hfs_mdb *mdb;	int error = 0;	int is_dir, has_thread;	if (removed) {		*removed = NULL;	}	/* sanity checks */	if (!old_dir || !new_dir) {		return -EINVAL;	}	mdb = old_dir->mdb;	if (mdb != new_dir->mdb) {		return -EXDEV;	}	/* precompute a few things */	if (entry->type == HFS_CDR_DIR) {		is_dir = 1;		has_thread = 1;	} else if (entry->type == HFS_CDR_FIL) {		is_dir = 0;		has_thread = entry->u.file.flags & HFS_FIL_THD;	} else {		return -EINVAL;	}	while (mdb->rename_lock) {		hfs_sleep_on(&mdb->rename_wait);	}	spin_lock(&entry_lock);	mdb->rename_lock = 1; /* XXX: should be atomic_inc */	spin_unlock(&entry_lock);	/* keep readers from getting confused by changing dir size */	start_write(new_dir);	if (old_dir != new_dir) {		start_write(old_dir);	}	/* Don't move a directory inside itself */	if (is_dir) {		struct hfs_cat_key thd_key;		struct hfs_brec brec;		hfs_u32 id = new_dir->cnid;		while (id != htonl(HFS_ROOT_CNID)) {			if (id == entry->cnid) {				error = -EINVAL;			} else {				hfs_cat_build_key(id, NULL, &thd_key);				error = hfs_bfind(&brec, mdb->cat_tree,						  HFS_BKEY(&thd_key),						  HFS_BFIND_READ_EQ);			}			if (error) {				goto done;			} else {				struct hfs_cat_rec *rec = brec.data;				id = hfs_get_nl(rec->u.thd.ParID);				hfs_brec_relse(&brec, NULL);			}		}	}restart:	/* see if the destination exists, getting it if it does */	dest = hfs_cat_get(mdb, new_key);	if (!dest) {		/* destination doesn't exist, so create it */		struct hfs_cat_rec new_record;		/* create a locked entry in the cache */		dest = get_entry(mdb, new_key, 0);		if (!dest) {			error = -EIO;			goto done;		}		if (dest->cnid) {			/* The (unlocked) entry exists in the cache */			goto have_distinct;		}		/* limit directory valence to signed 16-bit integer */        	if ((new_dir->u.dir.dirs + new_dir->u.dir.files) >=							HFS_MAX_VALENCE) {			error = -ENOSPC;			goto bail3;		}		/* build the new record. make sure to zero out the                   record. */		memset(&new_record, 0, sizeof(new_record));		new_record.cdrType = entry->type;		__write_entry(entry, &new_record);		/* insert the new record */		error = hfs_binsert(mdb->cat_tree, HFS_BKEY(new_key),				    &new_record, is_dir ? 2 + sizeof(DIR_REC) :				    2 + sizeof(FIL_REC));		if (error == -EEXIST) {			delete_entry(dest);			unlock_entry(dest);			hfs_cat_put(dest);			goto restart;		} else if (error) {			goto bail3;		}		/* update the destination directory */		update_dir(mdb, new_dir, is_dir, 1);	} else if (entry != dest) {have_distinct:		/* The destination exists and is not same as source */		lock_entry(dest);		if ((dest->state & HFS_DELETED)) {		        unlock_entry(dest);			hfs_cat_put(dest);			goto restart;		}		if (dest->type != entry->type) {			/* can't move a file on top			   of a dir nor vice versa. */			error = is_dir ? -ENOTDIR : -EISDIR;		} else if (is_dir && (dest->u.dir.dirs || dest->u.dir.files)) {			/* directory to replace is not empty */			error = -ENOTEMPTY;		}		if (error) {			goto bail2;		}	} else {		/* The destination exists but is same as source */	        --entry->count;		dest = NULL;	}	/* lock the entry */	lock_entry(entry);	if ((entry->state & HFS_DELETED)) {		error = -ENOENT;		goto bail1;	}	if (dest) {		/* remove the old entry */		error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key));		if (error) {			/* We couldn't remove the entry for the			   original file, so nothing has changed. */			goto bail1;		}		update_dir(mdb, old_dir, is_dir, -1);	}	/* update the thread of the dir/file we're moving */	if (has_thread) {		struct hfs_cat_key thd_key;		struct hfs_brec brec;		hfs_cat_build_key(entry->cnid, NULL, &thd_key);		error = hfs_bfind(&brec, mdb->cat_tree,				  HFS_BKEY(&thd_key), HFS_BFIND_WRITE);		if (error == -ENOENT) {			if (is_dir) {				/* directory w/o a thread! */				error = -EIO;			} else {				/* We were lied to! */				entry->u.file.flags &= ~HFS_FIL_THD;				hfs_cat_mark_dirty(entry);			}		}		if (!error) {			struct hfs_cat_rec *rec = brec.data;			memcpy(&rec->u.thd.ParID, &new_key->ParID,			       sizeof(hfs_u32) + sizeof(struct hfs_name));			hfs_brec_relse(&brec, NULL);		} else if (error == -ENOENT) {			error = 0;		} else if (!dest) {			/* Nothing was changed */			unlock_entry(entry);			goto done;		} else {			/* Something went seriously wrong.			   The dir/file has been deleted. */			/* XXX try some recovery? */			delete_entry(entry);			goto bail1;		}	}	/* TRY to remove the thread for the pre-existing entry */	if (dest && dest->cnid &&	    (is_dir || (dest->u.file.flags & HFS_FIL_THD))) {		struct hfs_cat_key thd_key;		hfs_cat_build_key(dest->cnid, NULL, &thd_key);		(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key));	}	/* update directories */	new_dir->modify_date = hfs_time();	hfs_cat_mark_dirty(new_dir);	/* update key */	remove_hash(entry);	memcpy(&entry->key, new_key, sizeof(*new_key));	/* KEYDIRTY as case might differ */	entry->state |= HFS_KEYDIRTY;	insert_hash(entry);	hfs_cat_mark_dirty(entry);	unlock_entry(entry);	/* delete any pre-existing or place-holder entry */	if (dest) {		delete_entry(dest);		unlock_entry(dest);		if (removed && dest->cnid) {			*removed = dest;		} else {			hfs_cat_put(dest);		}	}	goto done;bail1:	unlock_entry(entry);bail2:	if (dest) {		if (!dest->cnid) {			/* TRY to remove the new entry */			(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key));			update_dir(mdb, new_dir, is_dir, -1);bail3:			delete_entry(dest);		}		unlock_entry(dest);		hfs_cat_put(dest);	}done:	if (new_dir != old_dir) {		end_write(old_dir);	}	end_write(new_dir);	spin_lock(&entry_lock);	mdb->rename_lock = 0; /* XXX: should use atomic_dec */	hfs_wake_up(&mdb->rename_wait);	spin_unlock(&entry_lock);	return error;}/* * Initialize the hash tables */void hfs_cat_init(void){	int i;	struct list_head *head = hash_table;        i = C_HASHSIZE;        do {                INIT_LIST_HEAD(head);                head++;                i--;        } while (i);}

⌨️ 快捷键说明

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