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

📄 readinode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
					   highest_version, because this one is only					   counting _valid_ nodes which could give the					   latest inode metadata */					high_ver = this->version;					rii->latest_ref = this->fn->raw;				}				dbg_readinode("Add %p (v %d, 0x%x-0x%x, ov %d) to fragtree\n",					     this, this->version, this->fn->ofs,					     this->fn->ofs+this->fn->size, this->overlapped);				ret = jffs2_add_full_dnode_to_inode(c, f, this->fn);				if (ret) {					/* Free the nodes in vers_root; let the caller					   deal with the rest */					JFFS2_ERROR("Add node to tree failed %d\n", ret);					while (1) {						vers_next = tn_prev(this);						if (check_tn_node(c, this))							jffs2_mark_node_obsolete(c, this->fn->raw);						jffs2_free_full_dnode(this->fn);						jffs2_free_tmp_dnode_info(this);						this = vers_next;						if (!this)							break;						eat_last(&ver_root, &vers_next->rb);					}					return ret;				}				jffs2_free_tmp_dnode_info(this);			}			this = vers_next;		}	}	return 0;}static void jffs2_free_tmp_dnode_info_list(struct rb_root *list){	struct rb_node *this;	struct jffs2_tmp_dnode_info *tn;	this = list->rb_node;	/* Now at bottom of tree */	while (this) {		if (this->rb_left)			this = this->rb_left;		else if (this->rb_right)			this = this->rb_right;		else {			tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);			jffs2_free_full_dnode(tn->fn);			jffs2_free_tmp_dnode_info(tn);			this = rb_parent(this);			if (!this)				break;			if (this->rb_left == &tn->rb)				this->rb_left = NULL;			else if (this->rb_right == &tn->rb)				this->rb_right = NULL;			else BUG();		}	}	list->rb_node = NULL;}static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd){	struct jffs2_full_dirent *next;	while (fd) {		next = fd->next;		jffs2_free_full_dirent(fd);		fd = next;	}}/* Returns first valid node after 'ref'. May return 'ref' */static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref){	while (ref && ref->next_in_ino) {		if (!ref_obsolete(ref))			return ref;		dbg_noderef("node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref));		ref = ref->next_in_ino;	}	return NULL;}/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an directory entry node is found. * * Returns: 0 on success; * 	    negative error code on failure. */static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,				struct jffs2_raw_dirent *rd, size_t read,				struct jffs2_readinode_info *rii){	struct jffs2_full_dirent *fd;	uint32_t crc;	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */	BUG_ON(ref_obsolete(ref));	crc = crc32(0, rd, sizeof(*rd) - 8);	if (unlikely(crc != je32_to_cpu(rd->node_crc))) {		JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n",			     ref_offset(ref), je32_to_cpu(rd->node_crc), crc);		jffs2_mark_node_obsolete(c, ref);		return 0;	}	/* If we've never checked the CRCs on this node, check them now */	if (ref_flags(ref) == REF_UNCHECKED) {		struct jffs2_eraseblock *jeb;		int len;		/* Sanity check */		if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {			JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",				    ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));			jffs2_mark_node_obsolete(c, ref);			return 0;		}		jeb = &c->blocks[ref->flash_offset / c->sector_size];		len = ref_totlen(c, jeb, ref);		spin_lock(&c->erase_completion_lock);		jeb->used_size += len;		jeb->unchecked_size -= len;		c->used_size += len;		c->unchecked_size -= len;		ref->flash_offset = ref_offset(ref) | dirent_node_state(rd);		spin_unlock(&c->erase_completion_lock);	}	fd = jffs2_alloc_full_dirent(rd->nsize + 1);	if (unlikely(!fd))		return -ENOMEM;	fd->raw = ref;	fd->version = je32_to_cpu(rd->version);	fd->ino = je32_to_cpu(rd->ino);	fd->type = rd->type;	if (fd->version > rii->highest_version)		rii->highest_version = fd->version;	/* Pick out the mctime of the latest dirent */	if(fd->version > rii->mctime_ver && je32_to_cpu(rd->mctime)) {		rii->mctime_ver = fd->version;		rii->latest_mctime = je32_to_cpu(rd->mctime);	}	/*	 * Copy as much of the name as possible from the raw	 * dirent we've already read from the flash.	 */	if (read > sizeof(*rd))		memcpy(&fd->name[0], &rd->name[0],		       min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) ));	/* Do we need to copy any more of the name directly from the flash? */	if (rd->nsize + sizeof(*rd) > read) {		/* FIXME: point() */		int err;		int already = read - sizeof(*rd);		err = jffs2_flash_read(c, (ref_offset(ref)) + read,				rd->nsize - already, &read, &fd->name[already]);		if (unlikely(read != rd->nsize - already) && likely(!err))			return -EIO;		if (unlikely(err)) {			JFFS2_ERROR("read remainder of name: error %d\n", err);			jffs2_free_full_dirent(fd);			return -EIO;		}	}	fd->nhash = full_name_hash(fd->name, rd->nsize);	fd->next = NULL;	fd->name[rd->nsize] = '\0';	/*	 * Wheee. We now have a complete jffs2_full_dirent structure, with	 * the name in it and everything. Link it into the list	 */	jffs2_add_fd_to_list(c, fd, &rii->fds);	return 0;}/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an inode node is found. * * Returns: 0 on success (possibly after marking a bad node obsolete); * 	    negative error code on failure. */static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,			     struct jffs2_raw_inode *rd, int rdlen,			     struct jffs2_readinode_info *rii){	struct jffs2_tmp_dnode_info *tn;	uint32_t len, csize;	int ret = 0;	uint32_t crc;	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */	BUG_ON(ref_obsolete(ref));	crc = crc32(0, rd, sizeof(*rd) - 8);	if (unlikely(crc != je32_to_cpu(rd->node_crc))) {		JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n",			     ref_offset(ref), je32_to_cpu(rd->node_crc), crc);		jffs2_mark_node_obsolete(c, ref);		return 0;	}	tn = jffs2_alloc_tmp_dnode_info();	if (!tn) {		JFFS2_ERROR("failed to allocate tn (%zu bytes).\n", sizeof(*tn));		return -ENOMEM;	}	tn->partial_crc = 0;	csize = je32_to_cpu(rd->csize);	/* If we've never checked the CRCs on this node, check them now */	if (ref_flags(ref) == REF_UNCHECKED) {		/* Sanity checks */		if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||		    unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {			JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref));			jffs2_dbg_dump_node(c, ref_offset(ref));			jffs2_mark_node_obsolete(c, ref);			goto free_out;		}		if (jffs2_is_writebuffered(c) && csize != 0) {			/* At this point we are supposed to check the data CRC			 * of our unchecked node. But thus far, we do not			 * know whether the node is valid or obsolete. To			 * figure this out, we need to walk all the nodes of			 * the inode and build the inode fragtree. We don't			 * want to spend time checking data of nodes which may			 * later be found to be obsolete. So we put off the full			 * data CRC checking until we have read all the inode			 * nodes and have started building the fragtree.			 *			 * The fragtree is being built starting with nodes			 * having the highest version number, so we'll be able			 * to detect whether a node is valid (i.e., it is not			 * overlapped by a node with higher version) or not.			 * And we'll be able to check only those nodes, which			 * are not obsolete.			 *			 * Of course, this optimization only makes sense in case			 * of NAND flashes (or other flashes whith			 * !jffs2_can_mark_obsolete()), since on NOR flashes			 * nodes are marked obsolete physically.			 *			 * Since NAND flashes (or other flashes with			 * jffs2_is_writebuffered(c)) are anyway read by			 * fractions of c->wbuf_pagesize, and we have just read			 * the node header, it is likely that the starting part			 * of the node data is also read when we read the			 * header. So we don't mind to check the CRC of the			 * starting part of the data of the node now, and check			 * the second part later (in jffs2_check_node_data()).			 * Of course, we will not need to re-read and re-check			 * the NAND page which we have just read. This is why we			 * read the whole NAND page at jffs2_get_inode_nodes(),			 * while we needed only the node header.			 */			unsigned char *buf;			/* 'buf' will point to the start of data */			buf = (unsigned char *)rd + sizeof(*rd);			/* len will be the read data length */			len = min_t(uint32_t, rdlen - sizeof(*rd), csize);			tn->partial_crc = crc32(0, buf, len);			dbg_readinode("Calculates CRC (%#08x) for %d bytes, csize %d\n", tn->partial_crc, len, csize);			/* If we actually calculated the whole data CRC			 * and it is wrong, drop the node. */			if (len >= csize && unlikely(tn->partial_crc != je32_to_cpu(rd->data_crc))) {				JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",					ref_offset(ref), tn->partial_crc, je32_to_cpu(rd->data_crc));				jffs2_mark_node_obsolete(c, ref);				goto free_out;			}		} else if (csize == 0) {			/*			 * We checked the header CRC. If the node has no data, adjust			 * the space accounting now. For other nodes this will be done			 * later either when the node is marked obsolete or when its			 * data is checked.			 */			struct jffs2_eraseblock *jeb;			dbg_readinode("the node has no data.\n");			jeb = &c->blocks[ref->flash_offset / c->sector_size];			len = ref_totlen(c, jeb, ref);			spin_lock(&c->erase_completion_lock);			jeb->used_size += len;			jeb->unchecked_size -= len;			c->used_size += len;			c->unchecked_size -= len;			ref->flash_offset = ref_offset(ref) | REF_NORMAL;			spin_unlock(&c->erase_completion_lock);		}	}	tn->fn = jffs2_alloc_full_dnode();	if (!tn->fn) {		JFFS2_ERROR("alloc fn failed\n");		ret = -ENOMEM;		goto free_out;	}	tn->version = je32_to_cpu(rd->version);	tn->fn->ofs = je32_to_cpu(rd->offset);	tn->data_crc = je32_to_cpu(rd->data_crc);	tn->csize = csize;	tn->fn->raw = ref;	tn->overlapped = 0;	if (tn->version > rii->highest_version)		rii->highest_version = tn->version;	/* There was a bug where we wrote hole nodes out with	   csize/dsize swapped. Deal with it */	if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && csize)		tn->fn->size = csize;	else // normal case...		tn->fn->size = je32_to_cpu(rd->dsize);	dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n",		  ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize);	ret = jffs2_add_tn_to_tree(c, rii, tn);	if (ret) {		jffs2_free_full_dnode(tn->fn);	free_out:		jffs2_free_tmp_dnode_info(tn);		return ret;	}#ifdef JFFS2_DBG_READINODE_MESSAGES	dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version));	tn = tn_first(&rii->tn_root);	while (tn) {		dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n",			     tn, tn->version, tn->fn->ofs,			     tn->fn->ofs+tn->fn->size, tn->overlapped);		tn = tn_next(tn);	}#endif	return 0;}/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an unknown node is found. * * Returns: 0 on success; * 	    negative error code on failure. */static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un){	/* We don't mark unknown nodes as REF_UNCHECKED */	if (ref_flags(ref) == REF_UNCHECKED) {		JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n",			    ref_offset(ref));		JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n",			    je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),			    je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc));		jffs2_mark_node_obsolete(c, ref);		return 0;	}	un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));	switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {	case JFFS2_FEATURE_INCOMPAT:		JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n",			    je16_to_cpu(un->nodetype), ref_offset(ref));		/* EEP */		BUG();		break;	case JFFS2_FEATURE_ROCOMPAT:		JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n",			    je16_to_cpu(un->nodetype), ref_offset(ref));		BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));		break;	case JFFS2_FEATURE_RWCOMPAT_COPY:		JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",			     je16_to_cpu(un->nodetype), ref_offset(ref));		break;	case JFFS2_FEATURE_RWCOMPAT_DELETE:		JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",			     je16_to_cpu(un->nodetype), ref_offset(ref));		jffs2_mark_node_obsolete(c, ref);		return 0;	}	return 0;}/* * Helper function for jffs2_get_inode_nodes(). * The function detects whether more data should be read and reads it if yes. * * Returns: 0 on succes; * 	    negative error code on failure. */static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,		     int needed_len, int *rdlen, unsigned char *buf){	int err, to_read = needed_len - *rdlen;	size_t retlen;	uint32_t offs;	if (jffs2_is_writebuffered(c)) {		int rem = to_read % c->wbuf_pagesize;		if (rem)			to_read += c->wbuf_pagesize - rem;	}	/* We need to read more data */	offs = ref_offset(ref) + *rdlen;	dbg_readinode("read more %d bytes\n", to_read);	err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen);	if (err) {		JFFS2_ERROR("can not read %d bytes from 0x%08x, "			"error code: %d.\n", to_read, offs, err);		return err;	}	if (retlen < to_read) {		JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n",				offs, retlen, to_read);		return -EIO;	}	*rdlen += to_read;	return 0;}/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated   with this ino. Perform a preliminary ordering on data nodes, throwing away   those which are completely obsoleted by newer ones. The naïve approach we   use to take of just returning them _all_ in version order will cause us to   run out of memory in certain degenerate cases. */static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,				 struct jffs2_readinode_info *rii){	struct jffs2_raw_node_ref *ref, *valid_ref;	unsigned char *buf = NULL;	union jffs2_node_union *node;

⌨️ 快捷键说明

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