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

📄 catalog.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		   if (hfs_bfind(&brec, mdb->cat_tree,				 HFS_BKEY(key), HFS_BFIND_READ_EQ)) {		        /* uh oh. we failed to read the record.			 * the entry doesn't actually exist. */		        goto read_fail;		   }		   read_entry(entry, &brec);		   		   /* error */		   if (!entry->cnid) {		        goto read_fail;		   }		   /* we don't have to acquire a spinlock here or		    * below for the unlocking bits as we're the first		    * user of this entry. */		   entry->state &= ~HFS_LOCK;		   hfs_wake_up(&entry->wait);		}		return entry;	}	/* try to allocate more entries. grow_entries() doesn't release	 * the spinlock. */	if (grow_entries())	        goto add_new_entry;	spin_unlock(&entry_lock);	return NULL;read_fail: 	/* short-cut hfs_cat_put by doing everything here. */	spin_lock(&entry_lock);	list_del(&entry->hash);	list_del(&entry->list);	init_entry(entry);	list_add(&entry->list, &entry_unused);	entries_stat.nr_free_entries++;	spin_unlock(&entry_lock);	return NULL;}/* * get_entry() * * Try to return an entry for the indicated file or directory. * If ('read' == 0) then no attempt will be made to read it from disk * and a locked, but uninitialized, entry is returned. */static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb,				       const struct hfs_cat_key *key,				       const int read){	struct hfs_cat_entry * entry;#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)	hfs_warn("hfs_get_entry: mdb=%p key=%s read=%d\n",		 mdb, key->CName.Name, read);#endif	spin_lock(&entry_lock);	entry = find_entry(mdb, key);	if (!entry) {	        return get_new_entry(mdb, key, read);	}	spin_unlock(&entry_lock);	wait_on_entry(entry);	return entry;}/*  * new_cnid() * * Allocate a CNID to use for a new file or directory. */static inline hfs_u32 new_cnid(struct hfs_mdb *mdb){	/* If the create succeeds then the mdb will get dirtied */	return htonl(mdb->next_id++);}/* * update_dir() * * Update counts, times and dirt on a changed directory */static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir,		       int is_dir, int count){	/* update counts */	if (is_dir) {		mdb->dir_count += count;		dir->u.dir.dirs += count;		if (dir->cnid == htonl(HFS_ROOT_CNID)) {			mdb->root_dirs += count;		}	} else {		mdb->file_count += count;		dir->u.dir.files += count;		if (dir->cnid == htonl(HFS_ROOT_CNID)) {			mdb->root_files += count;		}	}		/* update times and dirt */	dir->modify_date = hfs_time();	hfs_cat_mark_dirty(dir);}/* * Add a writer to dir, excluding readers. * * XXX: this is wrong. it allows a move to occur when a directory *      is being written to.  */static inline void start_write(struct hfs_cat_entry *dir){	if (dir->u.dir.readers || waitqueue_active(&dir->u.dir.read_wait)) {		hfs_sleep_on(&dir->u.dir.write_wait);	}	++dir->u.dir.writers;}/* * Add a reader to dir, excluding writers. */static inline void start_read(struct hfs_cat_entry *dir){	if (dir->u.dir.writers || waitqueue_active(&dir->u.dir.write_wait)) {		hfs_sleep_on(&dir->u.dir.read_wait);	}	++dir->u.dir.readers;}/* * Remove a writer from dir, possibly admitting readers. */static inline void end_write(struct hfs_cat_entry *dir){	if (!(--dir->u.dir.writers)) {		hfs_wake_up(&dir->u.dir.read_wait);	}}/* * Remove a reader from dir, possibly admitting writers. */static inline void end_read(struct hfs_cat_entry *dir){	if (!(--dir->u.dir.readers)) {		hfs_wake_up(&dir->u.dir.write_wait);	}}/* * create_entry() * * Add a new file or directory to the catalog B-tree and * return a (struct hfs_cat_entry) for it in '*result'. */static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key,			const struct hfs_cat_rec *record, int is_dir,			hfs_u32 cnid, struct hfs_cat_entry **result){	struct hfs_mdb *mdb = parent->mdb;	struct hfs_cat_entry *entry;	struct hfs_cat_key thd_key;	struct hfs_cat_rec thd_rec;	int error, has_thread;	if (result) {		*result = NULL;	}	/* keep readers from getting confused by changing dir size */	start_write(parent);	/* create a locked entry in the cache */	entry = get_entry(mdb, key, 0);	if (!entry) {		/* The entry exists but can't be read */		error = -EIO;		goto done;	}	if (entry->cnid) {		/* The (unlocked) entry exists in the cache */		error = -EEXIST;		goto bail2;	}	/* limit directory valence to signed 16-bit integer */        if ((parent->u.dir.dirs + parent->u.dir.files) >= HFS_MAX_VALENCE) {		error = -ENOSPC;		goto bail1;	}	has_thread = is_dir || (record->u.fil.Flags & HFS_FIL_THD);	if (has_thread) {		/* init some fields for the thread record */		memset(&thd_rec, 0, sizeof(thd_rec));		thd_rec.cdrType = is_dir ? HFS_CDR_THD : HFS_CDR_FTH;		memcpy(&thd_rec.u.thd.ParID, &key->ParID,		       sizeof(hfs_u32) + sizeof(struct hfs_name));		/* insert the thread record */		hfs_cat_build_key(cnid, NULL, &thd_key);		error = hfs_binsert(mdb->cat_tree, HFS_BKEY(&thd_key),				    &thd_rec, 2 + sizeof(THD_REC));		if (error) {			goto bail1;		}	}	/* insert the record */	error = hfs_binsert(mdb->cat_tree, HFS_BKEY(key), record,				is_dir ?  2 + sizeof(DIR_REC) :					  2 + sizeof(FIL_REC));	if (error) {		if (has_thread && (error != -EIO)) {			/* at least TRY to remove the thread record */			(void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&thd_key));		}		goto bail1;	}	/* update the parent directory */	update_dir(mdb, parent, is_dir, 1);	/* complete the cache entry and return success */	__read_entry(entry, record);	unlock_entry(entry);	if (result) {		*result = entry;	} else {		hfs_cat_put(entry);	}	goto done;bail1:	/* entry really didn't exist, so we don't need to really delete it.	 * we do need to remove it from the hash, though. */	entry->state |= HFS_DELETED;	remove_hash(entry);	unlock_entry(entry);bail2:	hfs_cat_put(entry);done:	end_write(parent);	return error;}/*================ Global functions ================*//*  * hfs_cat_put() * * Release an entry we aren't using anymore. * * nothing in hfs_cat_put goes to sleep now except on the initial entry.   */void hfs_cat_put(struct hfs_cat_entry * entry){	if (entry) {	        wait_on_entry(entry);		/* just in case. this should never happen. */		if (!entry->count) { 		  hfs_warn("hfs_cat_put: trying to free free entry: %p\n",			   entry);		  return;		}#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)		hfs_warn("hfs_cat_put: %p(%u) type=%d state=%lu\n", 			 entry, entry->count, entry->type, entry->state);#endif		spin_lock(&entry_lock);		if (!--entry->count) {			if ((entry->state & HFS_DELETED))			        goto entry_deleted;			if ((entry->type == HFS_CDR_FIL)) {		                /* clear out any cached extents */			        if (entry->u.file.data_fork.first.next) {				  hfs_extent_free(&entry->u.file.data_fork);				}				if (entry->u.file.rsrc_fork.first.next) {				  hfs_extent_free(&entry->u.file.rsrc_fork);				}			}			/* if we put a dirty entry, write it out. */			if ((entry->state & HFS_DIRTY)) {			        entry->state ^= HFS_DIRTY | HFS_LOCK;				write_entry(entry);				entry->state &= ~HFS_LOCK;			}			list_del(&entry->hash);entry_deleted: 		/* deleted entries have already been removed			 * from the hash list. */			list_del(&entry->list);			if (entries_stat.nr_free_entries > CCACHE_MAX) {			        HFS_DELETE(entry);				entries_stat.nr_entries--;			} else {				init_entry(entry);				list_add(&entry->list, &entry_unused);				entries_stat.nr_free_entries++;			}		}		spin_unlock(&entry_lock);	}}/*  * hfs_cat_get() * * Wrapper for get_entry() which always calls with ('read'==1). * Used for access to get_entry() from outside this file. */struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *mdb,				  const struct hfs_cat_key *key){	return get_entry(mdb, key, 1);}/* invalidate all entries for a device */static void invalidate_list(struct list_head *head, struct hfs_mdb *mdb,			    struct list_head *dispose){        struct list_head *next;	next = head->next;	for (;;) {	        struct list_head *tmp = next;		struct hfs_cat_entry * entry;				next = next->next;		if (tmp == head)		        break;		entry = list_entry(tmp, struct hfs_cat_entry, list);		if (entry->mdb != mdb) {			continue;		}		if (!entry->count) {		        list_del(&entry->hash);			INIT_LIST_HEAD(&entry->hash);			list_del(&entry->list);			list_add(&entry->list, dispose);			continue;		}				hfs_warn("hfs_fs: entry %p(%u) busy on removed device %s.\n",			 entry, entry->count, 			 hfs_mdb_name(entry->mdb->sys_mdb));	}}/* delete entries from a list */static void delete_list(struct list_head *head) {	struct list_head *next = head->next;	struct hfs_cat_entry *entry;		for (;;) {		struct list_head * tmp = next;		next = next->next;		if (tmp == head) {			break;		}		entry = list_entry(tmp, struct hfs_cat_entry, list);		HFS_DELETE(entry);	}}/*  * hfs_cat_invalidate() * * Called by hfs_mdb_put() to remove all the entries * in the cache that are associated with a given MDB. */void hfs_cat_invalidate(struct hfs_mdb *mdb){	LIST_HEAD(throw_away);	spin_lock(&entry_lock);	invalidate_list(&entry_in_use, mdb, &throw_away);	invalidate_list(&mdb->entry_dirty, mdb, &throw_away);	spin_unlock(&entry_lock);	delete_list(&throw_away);#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL)	hfs_warn("hfs_cat_invalidate: free=%d total=%d\n",		 entries_stat.nr_free_entries,		 entries_stat.nr_entries);#endif}/* * hfs_cat_commit() * * Called by hfs_mdb_commit() to write dirty entries to the disk buffers. */void hfs_cat_commit(struct hfs_mdb *mdb){        struct list_head *tmp, *head = &mdb->entry_dirty;	struct hfs_cat_entry *entry;	spin_lock(&entry_lock);	while ((tmp = head->prev) != head) {	        entry = list_entry(tmp, struct hfs_cat_entry, list);		  		if ((entry->state & HFS_LOCK)) {		        spin_unlock(&entry_lock);			wait_on_entry(entry);			spin_lock(&entry_lock);		} else {		       struct list_head *insert = &entry_in_use;		       if (!entry->count)			        insert = entry_in_use.prev;		       /* add to in_use list */		       list_del(&entry->list);		       list_add(&entry->list, insert);		       /* reset DIRTY, set LOCK */		       entry->state ^= HFS_DIRTY | HFS_LOCK;		       spin_unlock(&entry_lock);		       write_entry(entry);		       spin_lock(&entry_lock);		       entry->state &= ~HFS_LOCK;		       hfs_wake_up(&entry->wait);		}	}	spin_unlock(&entry_lock);}/* * hfs_cat_free() * * Releases all the memory allocated in grow_entries(). * Must call hfs_cat_invalidate() on all MDBs before calling this. * This only gets rid of the unused pool of entries. all the other * entry references should have either been freed by cat_invalidate * or moved onto the unused list. */void hfs_cat_free(void){	delete_list(&entry_unused);}/* * hfs_cat_compare() * * Description: *   This is the comparison function used for the catalog B-tree.  In *   comparing catalog B-tree entries, the parent id is the most *   significant field (compared as unsigned ints).  The name field is *   the least significant (compared in "Macintosh lexical order", *   see hfs_strcmp() in string.c) * Input Variable(s): *   struct hfs_cat_key *key1: pointer to the first key to compare *   struct hfs_cat_key *key2: pointer to the second key to compare * Output Variable(s): *   NONE * Returns: *   int: negative if key1<key2, positive if key1>key2, and 0 if key1==key2 * Preconditions: *   key1 and key2 point to "valid" (struct hfs_cat_key)s. * Postconditions: *   This function has no side-effects */int hfs_cat_compare(const struct hfs_cat_key *key1,		    const struct hfs_cat_key *key2){	unsigned int parents;	int retval;	parents = hfs_get_hl(key1->ParID) - hfs_get_hl(key2->ParID);	if (parents != 0) {		retval = (int)parents;	} else {		retval = hfs_strcmp(key1->CName.Name, key1->CName.Len,				    key2->CName.Name, key2->CName.Len);	}	return retval;}/* * hfs_cat_build_key() * * Given the ID of the parent and the name build a search key. */void hfs_cat_build_key(hfs_u32 parent, const struct hfs_name *cname,		       struct hfs_cat_key *key){	hfs_put_nl(parent, key->ParID);	if (cname) {		key->KeyLen = 6 + cname->Len;		memcpy(&key->CName, cname, sizeof(*cname));	} else {		key->KeyLen = 6;		memset(&key->CName, 0, sizeof(*cname));	}}/* * hfs_cat_open() * * Given a directory on an HFS filesystem get its thread and * lock the directory against insertions and deletions. * Return 0 on success or an error code on failure. */int hfs_cat_open(struct hfs_cat_entry *dir, struct hfs_brec *brec){	struct hfs_cat_key key;	int error;	if (dir->type != HFS_CDR_DIR) {		return -EINVAL;

⌨️ 快捷键说明

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