📄 readinode.c
字号:
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 + -