/* 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_add_older_frag_to_fragtree(). * * Checks the node if we are in the checking stage. */ static int check_tn_node(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) { int ret; BUG_ON(ref_obsolete(tn->fn->raw)); /* We only check the data CRC of unchecked nodes */ if (ref_flags(tn->fn->raw) != REF_UNCHECKED) return 0; dbg_readinode("check node %#04x-%#04x, phys offs %#08x\n", tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw)); ret = check_node_data(c, tn); if (unlikely(ret < 0)) { JFFS2_ERROR("check_node_data() returned error: %d.\n", ret); } else if (unlikely(ret > 0)) { dbg_readinode("CRC error, mark it obsolete.\n"); jffs2_mark_node_obsolete(c, tn->fn->raw); } return ret; }
static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *latest_node) { struct jffs2_tmp_dnode_info *tn; struct rb_root tn_list; struct rb_node *rb, *repl_rb; struct jffs2_full_dirent *fd_list; struct jffs2_full_dnode *fn, *first_fn = NULL; uint32_t crc; uint32_t latest_mctime, mctime_ver; size_t retlen; int ret; dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); /* Grab all nodes relevant to this ino */ ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); if (ret) { JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret); if (f->inocache->state == INO_STATE_READING) jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return ret; } f->dents = fd_list; rb = rb_first(&tn_list); while (rb) { cond_resched(); tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); fn = tn->fn; ret = 1; dbg_readinode("consider node ver %u, phys offset " "%#08x(%d), range %u-%u.\n", tn->version, ref_offset(fn->raw), ref_flags(fn->raw), fn->ofs, fn->ofs + fn->size); if (fn->size) { ret = jffs2_add_older_frag_to_fragtree(c, f, tn); /* TODO: the error code isn't checked, check it */ jffs2_dbg_fragtree_paranoia_check_nolock(f); BUG_ON(ret < 0); if (!first_fn && ret == 0) first_fn = fn; } else if (!first_fn) { first_fn = fn; f->metadata = fn; ret = 0; /* Prevent freeing the metadata update node */ } else jffs2_mark_node_obsolete(c, fn->raw); BUG_ON(rb->rb_left); if (rb->rb_parent && rb->rb_parent->rb_left == rb) { /* We were then left-hand child of our parent. We need * to move our own right-hand child into our place. */ repl_rb = rb->rb_right; if (repl_rb) repl_rb->rb_parent = rb->rb_parent; } else repl_rb = NULL; rb = rb_next(rb); /* Remove the spent tn from the tree; don't bother rebalancing * but put our right-hand child in our own place. */ if (tn->rb.rb_parent) { if (tn->rb.rb_parent->rb_left == &tn->rb) tn->rb.rb_parent->rb_left = repl_rb; else if (tn->rb.rb_parent->rb_right == &tn->rb) tn->rb.rb_parent->rb_right = repl_rb; else BUG(); } else if (tn->rb.rb_right) tn->rb.rb_right->rb_parent = NULL; jffs2_free_tmp_dnode_info(tn); if (ret) { dbg_readinode("delete dnode %u-%u.\n", fn->ofs, fn->ofs + fn->size); jffs2_free_full_dnode(fn); } } jffs2_dbg_fragtree_paranoia_check_nolock(f); BUG_ON(first_fn && ref_obsolete(first_fn->raw)); fn = first_fn; if (unlikely(!first_fn)) { /* No data nodes for this inode. */ if (f->inocache->ino != 1) { JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino); if (!fd_list) { if (f->inocache->state == INO_STATE_READING) jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return -EIO; } JFFS2_NOTICE("but it has children so we fake some modes for it\n"); } latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); latest_node->version = cpu_to_je32(0); latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0); latest_node->isize = cpu_to_je32(0); latest_node->gid = cpu_to_je16(0); latest_node->uid = cpu_to_je16(0); if (f->inocache->state == INO_STATE_READING) jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); return 0; } ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); if (ret || retlen != sizeof(*latest_node)) { JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", ret, retlen, sizeof(*latest_node)); /* FIXME: If this fails, there seems to be a memory leak. Find it. */ up(&f->sem); jffs2_do_clear_inode(c, f); return ret?ret:-EIO; } crc = crc32(0, latest_node, sizeof(*latest_node)-8); if (crc != je32_to_cpu(latest_node->node_crc)) { JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { case S_IFDIR: if (mctime_ver > je32_to_cpu(latest_node->version)) { /* The times in the latest_node are actually older than mctime in the latest dirent. Cheat. */ latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime); } break; case S_IFREG: /* If it was a regular file, truncate it to the latest node's isize */ jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); break; case S_IFLNK: /* Hack to work around broken isize in old symlink code. Remove this when dwmw2 comes to his senses and stops symlinks from being an entirely gratuitous special case. */ if (!je32_to_cpu(latest_node->isize)) latest_node->isize = latest_node->dsize; if (f->inocache->state != INO_STATE_CHECKING) { /* Symlink's inode data is the target path. Read it and * keep in RAM to facilitate quick follow symlink * operation. */ f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); if (!f->target) { JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); up(&f->sem); jffs2_do_clear_inode(c, f); return -ENOMEM; } ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), je32_to_cpu(latest_node->csize), &retlen, (char *)f->target); if (ret || retlen != je32_to_cpu(latest_node->csize)) { if (retlen != je32_to_cpu(latest_node->csize)) ret = -EIO; kfree(f->target); f->target = NULL; up(&f->sem); jffs2_do_clear_inode(c, f); return -ret; } f->target[je32_to_cpu(latest_node->csize)] = '\0'; dbg_readinode("symlink's target '%s' cached\n", f->target); } /* fall through... */ case S_IFBLK: case S_IFCHR: /* Certain inode types should have only one data node, and it's kept as the metadata node */ if (f->metadata) { JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n", f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } if (!frag_first(&f->fragtree)) { JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n", f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } /* ASSERT: f->fraglist != NULL */ if (frag_next(frag_first(&f->fragtree))) { JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n", f->inocache->ino, jemode_to_cpu(latest_node->mode)); /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } /* OK. We're happy */ f->metadata = frag_first(&f->fragtree)->node; jffs2_free_node_frag(frag_first(&f->fragtree)); f->fragtree = RB_ROOT; break; } if (f->inocache->state == INO_STATE_READING) jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); return 0; }
/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an inode node is found. * * Returns: 0 on succes; * 1 if the node should be marked 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, struct rb_root *tnp, int rdlen, uint32_t *latest_mctime, uint32_t *mctime_ver) { struct jffs2_tmp_dnode_info *tn; uint32_t len, csize; int ret = 1; /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ BUG_ON(ref_obsolete(ref)); tn = jffs2_alloc_tmp_dnode_info(); if (!tn) { JFFS2_ERROR("failed to allocate tn (%d 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) { uint32_t crc; crc = crc32(0, rd, sizeof(*rd) - 8); if (unlikely(crc != je32_to_cpu(rd->node_crc))) { JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", ref_offset(ref), je32_to_cpu(rd->node_crc), crc); goto free_out; } /* 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)); 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)); 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; /* 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); jffs2_add_tn_to_tree(tn, tnp); return 0; free_out: jffs2_free_tmp_dnode_info(tn); return ret; }
/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an directory entry node is found. * * Returns: 0 on succes; * 1 if the node should be marked obsolete; * 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_full_dirent **fdp, uint32_t *latest_mctime, uint32_t *mctime_ver) { struct jffs2_full_dirent *fd; /* The direntry nodes are checked during the flash scanning */ BUG_ON(ref_flags(ref) == REF_UNCHECKED); /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ BUG_ON(ref_obsolete(ref)); /* 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)); return 1; } 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; /* Pick out the mctime of the latest dirent */ if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) { *mctime_ver = fd->version; *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, fdp); return 0; }
/* * Helper function for jffs2_get_inode_nodes(). * It is called every time an inode node is found. * * Returns: 0 on succes; * 1 if the node should be marked 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, uint32_t read, struct rb_root *tnp, int32_t *latest_mctime, uint32_t *mctime_ver) { struct jffs2_eraseblock *jeb; struct jffs2_tmp_dnode_info *tn; /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ BUG_ON(ref_obsolete(ref)); /* If we've never checked the CRCs on this node, check them now */ if (ref_flags(ref) == REF_UNCHECKED) { uint32_t crc, len; crc = crc32(0, rd, sizeof(*rd) - 8); if (unlikely(crc != je32_to_cpu(rd->node_crc))) { JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", ref_offset(ref), je32_to_cpu(rd->node_crc), crc); return 1; } /* 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)); return 1; } if (rd->compr != JFFS2_COMPR_ZERO && je32_to_cpu(rd->csize)) { unsigned char *buf = NULL; uint32_t pointed = 0; int err; #ifndef __ECOS if (c->mtd->point) { err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize), &read, &buf); if (unlikely(read < je32_to_cpu(rd->csize)) && likely(!err)) { JFFS2_ERROR("MTD point returned len too short: 0x%zx\n", read); c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize)); } else if (unlikely(err)){ JFFS2_ERROR("MTD point failed %d\n", err); } else pointed = 1; /* succefully pointed to device */ } #endif if(!pointed){ buf = kmalloc(je32_to_cpu(rd->csize), GFP_KERNEL); if (!buf) return -ENOMEM; err = jffs2_flash_read(c, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize), &read, buf); if (unlikely(read != je32_to_cpu(rd->csize)) && likely(!err)) err = -EIO; if (err) { kfree(buf); return err; } } crc = crc32(0, buf, je32_to_cpu(rd->csize)); if(!pointed) kfree(buf); #ifndef __ECOS else c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize)); #endif if (crc != je32_to_cpu(rd->data_crc)) { JFFS2_NOTICE("data CRC failed on node at %#08x: read %#08x, calculated %#08x\n", ref_offset(ref), je32_to_cpu(rd->data_crc), crc); return 1; } } /* Mark the node as having been checked and fix the accounting accordingly */ 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; /* If node covers at least a whole page, or if it starts at the beginning of a page and runs to the end of the file, or if it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) when the overlapping node(s) get added to the tree anyway. */ if ((je32_to_cpu(rd->dsize) >= PAGE_CACHE_SIZE) || ( ((je32_to_cpu(rd->offset) & (PAGE_CACHE_SIZE-1))==0) && (je32_to_cpu(rd->dsize) + je32_to_cpu(rd->offset) == je32_to_cpu(rd->isize)))) { JFFS2_DBG_READINODE("marking node at %#08x REF_PRISTINE\n", ref_offset(ref)); ref->flash_offset = ref_offset(ref) | REF_PRISTINE; } else { JFFS2_DBG_READINODE("marking node at %#08x REF_NORMAL\n", ref_offset(ref)); ref->flash_offset = ref_offset(ref) | REF_NORMAL; } spin_unlock(&c->erase_completion_lock); } tn = jffs2_alloc_tmp_dnode_info(); if (!tn) { JFFS2_ERROR("alloc tn failed\n"); return -ENOMEM; } tn->fn = jffs2_alloc_full_dnode(); if (!tn->fn) { JFFS2_ERROR("alloc fn failed\n"); jffs2_free_tmp_dnode_info(tn); return -ENOMEM; } tn->version = je32_to_cpu(rd->version); tn->fn->ofs = je32_to_cpu(rd->offset); tn->fn->raw = ref; /* 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) && je32_to_cpu(rd->csize)) tn->fn->size = je32_to_cpu(rd->csize); else // normal case... tn->fn->size = je32_to_cpu(rd->dsize); JFFS2_DBG_READINODE("dnode @%08x: ver %u, offset %#04x, dsize %#04x\n", ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize)); jffs2_add_tn_to_tree(tn, tnp); return 0; }
/* * 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; }