📄 intrep.c
字号:
/* Get data and size if there is any */ if (raw_inode->dsize) { node_iovec[iovec_cnt].iov_base = (void *) data; node_iovec[iovec_cnt].iov_len = (size_t) raw_inode->dsize; iovec_cnt++; /* No need to pad this because we're not actually putting anything after it. */ } if ((err = flash_safe_writev(fmc->mtd, node_iovec, iovec_cnt, pos) < 0)) { jffs_fmfree_partly(fmc, fm, 0); jffs_fm_write_unlock(fmc); printk(KERN_ERR "JFFS: jffs_write_node: Failed to write, " "requested %i, wrote %i\n", total_size, err); goto retry; } if (raw_inode->deleted) f->deleted = 1; jffs_fm_write_unlock(fmc); D3(printk("jffs_write_node(): Leaving...\n")); return raw_inode->dsize;} /* jffs_write_node() *//* Read data from the node and write it to the buffer. 'node_offset' is how much we have read from this particular node before and which shouldn't be read again. 'max_size' is how much space there is in the buffer. */static intjffs_get_node_data(struct jffs_file *f, struct jffs_node *node, unsigned char *buf,__u32 node_offset, __u32 max_size, kdev_t dev){ struct jffs_fmcontrol *fmc = f->c->fmc; __u32 pos = node->fm->offset + node->fm_offset + node_offset; __u32 avail = node->data_size - node_offset; __u32 r; D2(printk(" jffs_get_node_data(): file: \"%s\", ino: %u, " "version: %u, node_offset: %u\n", f->name, node->ino, node->version, node_offset)); r = min(avail, max_size); D3(printk(KERN_NOTICE "jffs_get_node_data\n")); flash_safe_read(fmc->mtd, pos, buf, r); D3(printk(" jffs_get_node_data(): Read %u byte%s.\n", r, (r == 1 ? "" : "s"))); return r;}/* Read data from the file's nodes. Write the data to the buffer 'buf'. 'read_offset' tells how much data we should skip. */intjffs_read_data(struct jffs_file *f, unsigned char *buf, __u32 read_offset, __u32 size){ struct jffs_node *node; __u32 read_data = 0; /* Total amount of read data. */ __u32 node_offset = 0; __u32 pos = 0; /* Number of bytes traversed. */ D2(printk("jffs_read_data(): file = \"%s\", read_offset = %d, " "size = %u\n", (f->name ? f->name : ""), read_offset, size)); if (read_offset >= f->size) { D(printk(" f->size: %d\n", f->size)); return 0; } /* First find the node to read data from. */ node = f->range_head; while (pos <= read_offset) { node_offset = read_offset - pos; if (node_offset >= node->data_size) { pos += node->data_size; node = node->range_next; } else { break; } } /* "Cats are living proof that not everything in nature has to be useful." - Garrison Keilor ('97) */ /* Fill the buffer. */ while (node && (read_data < size)) { int r; if (!node->fm) { /* This node does not refer to real data. */ r = min(size - read_data, node->data_size - node_offset); memset(&buf[read_data], 0, r); } else if ((r = jffs_get_node_data(f, node, &buf[read_data], node_offset, size - read_data, f->c->sb->s_dev)) < 0) { return r; } read_data += r; node_offset = 0; node = node->range_next; } D3(printk(" jffs_read_data(): Read %u bytes.\n", read_data)); return read_data;}/* Used for traversing all nodes in the hash table. */intjffs_foreach_file(struct jffs_control *c, int (*func)(struct jffs_file *)){ int pos; int r; int result = 0; for (pos = 0; pos < c->hash_len; pos++) { struct list_head *p, *next; for (p = c->hash[pos].next; p != &c->hash[pos]; p = next) { /* We need a reference to the next file in the list because `func' might remove the current file `f'. */ next = p->next; r = func(list_entry(p, struct jffs_file, hash)); if (r < 0) return r; result += r; } } return result;}/* Free all nodes associated with a file. */intjffs_free_node_list(struct jffs_file *f){ struct jffs_node *node; struct jffs_node *p; D3(printk("jffs_free_node_list(): f #%u, \"%s\"\n", f->ino, (f->name ? f->name : ""))); node = f->version_head; while (node) { p = node; node = node->version_next; jffs_free_node(p); DJM(no_jffs_node--); } return 0;}/* Free a file and its name. */intjffs_free_file(struct jffs_file *f){ D3(printk("jffs_free_file: f #%u, \"%s\"\n", f->ino, (f->name ? f->name : ""))); if (f->name) { kfree(f->name); DJM(no_name--); } kfree(f); no_jffs_file--; return 0;}longjffs_get_file_count(void){ return no_jffs_file;}/* See if a file is deleted. If so, mark that file's nodes as obsolete. */intjffs_possibly_delete_file(struct jffs_file *f){ struct jffs_node *n; D3(printk("jffs_possibly_delete_file(): ino: %u\n", f->ino)); ASSERT(if (!f) { printk(KERN_ERR "jffs_possibly_delete_file(): f == NULL\n"); return -1; }); if (f->deleted) { /* First try to remove all older versions. Commence with the oldest node. */ for (n = f->version_head; n; n = n->version_next) { if (!n->fm) { continue; } if (jffs_fmfree(f->c->fmc, n->fm, n) < 0) { break; } } /* Unlink the file from the filesystem. */ if (!f->c->building_fs) { jffs_unlink_file_from_tree(f); } jffs_unlink_file_from_hash(f); jffs_free_node_list(f); jffs_free_file(f); } return 0;}/* Used in conjunction with jffs_foreach_file() to count the number of files in the file system. */intjffs_file_count(struct jffs_file *f){ return 1;}/* Build up a file's range list from scratch by going through the version list. */intjffs_build_file(struct jffs_file *f){ struct jffs_node *n; D3(printk("jffs_build_file(): ino: %u, name: \"%s\"\n", f->ino, (f->name ? f->name : ""))); for (n = f->version_head; n; n = n->version_next) { jffs_update_file(f, n); } return 0;}/* Remove an amount of data from a file. If this amount of data is zero, that could mean that a node should be split in two parts. We remove or change the appropriate nodes in the lists. Starting offset of area to be removed is node->data_offset, and the length of the area is in node->removed_size. */static intjffs_delete_data(struct jffs_file *f, struct jffs_node *node){ struct jffs_node *n; __u32 offset = node->data_offset; __u32 remove_size = node->removed_size; D3(printk("jffs_delete_data(): offset = %u, remove_size = %u\n", offset, remove_size)); if (remove_size == 0 && f->range_tail && f->range_tail->data_offset + f->range_tail->data_size == offset) { /* A simple append; nothing to remove or no node to split. */ return 0; } /* Find the node where we should begin the removal. */ for (n = f->range_head; n; n = n->range_next) { if (n->data_offset + n->data_size > offset) { break; } } if (!n) { /* If there's no data in the file there's no data to remove either. */ return 0; } if (n->data_offset > offset) { /* XXX: Not implemented yet. */ printk(KERN_WARNING "JFFS: An unexpected situation " "occurred in jffs_delete_data.\n"); } else if (n->data_offset < offset) { /* See if the node has to be split into two parts. */ if (n->data_offset + n->data_size > offset + remove_size) { /* Do the split. */ struct jffs_node *new_node; D3(printk("jffs_delete_data(): Split node with " "version number %u.\n", n->version)); if (!(new_node = jffs_alloc_node())) { D(printk("jffs_delete_data(): -ENOMEM\n")); return -ENOMEM; } DJM(no_jffs_node++); new_node->ino = n->ino; new_node->version = n->version; new_node->data_offset = offset; new_node->data_size = n->data_size - (remove_size + (offset - n->data_offset)); new_node->fm_offset = n->fm_offset + (remove_size + (offset - n->data_offset)); new_node->name_size = n->name_size; new_node->fm = n->fm; new_node->version_prev = n; new_node->version_next = n->version_next; if (new_node->version_next) { new_node->version_next->version_prev = new_node; } else { f->version_tail = new_node; } n->version_next = new_node; new_node->range_prev = n; new_node->range_next = n->range_next; if (new_node->range_next) { new_node->range_next->range_prev = new_node; } else { f->range_tail = new_node; } /* A very interesting can of worms. */ n->range_next = new_node; n->data_size = offset - n->data_offset; if (new_node->fm) jffs_add_node(new_node); else { D1(printk(KERN_WARNING "jffs_delete_data(): Splitting an empty node (file hold).\n!")); D1(printk(KERN_WARNING "FIXME: Did dwmw2 do the right thing here?\n")); } n = new_node->range_next; remove_size = 0; } else { /* No. No need to split the node. Just remove the end of the node. */ int r = min(n->data_offset + n->data_size - offset, remove_size); n->data_size -= r; remove_size -= r; n = n->range_next; } } /* Remove as many nodes as necessary. */ while (n && remove_size) { if (n->data_size <= remove_size) { struct jffs_node *p = n; remove_size -= n->data_size; n = n->range_next; D3(printk("jffs_delete_data(): Removing node: " "ino: %u, version: %u%s\n", p->ino, p->version, (p->fm ? "" : " (virtual)"))); if (p->fm) { jffs_fmfree(f->c->fmc, p->fm, p); } jffs_unlink_node_from_range_list(f, p); jffs_unlink_node_from_version_list(f, p); jffs_free_node(p); DJM(no_jffs_node--); } else { n->data_size -= remove_size; n->fm_offset += remove_size; n->data_offset -= (node->removed_size - remove_size); n = n->range_next; break; } } /* Adjust the following nodes' information about offsets etc. */ while (n && node->removed_size) { n->data_offset -= node->removed_size; n = n->range_next; } if (node->removed_size > (f->size - node->data_offset)) { /* It's possible that the removed_size is in fact * greater than the amount of data we actually thought * were present in the first place - some of the nodes * which this node originally obsoleted may already have * been deleted from the flash by subsequent garbage * collection. * * If this is the case, don't let f->size go negative. * Bad things would happen :) */ f->size = node->data_offset; } else { f->size -= node->removed_size; } D3(printk("jffs_delete_data(): f->size = %d\n", f->size)); return 0;} /* jffs_delete_data() *//* Insert some data into a file. Prior to the call to this function, jffs_delete_data should be called. */static intjffs_insert_data(struct jffs_file *f, struct jffs_node *node){ D3(printk("jffs_insert_data(): node->data_offset = %u, " "node->data_size = %u, f->size = %u\n", node->data_offset, node->data_size, f->size)); /* Find the position where we should insert data. */ retry: if (node->data_offset == f->size) { /* A simple append. This is the most common operation. */ node->range_next = 0; node->range_prev = f->range_tail; if (node->range_prev) { node->range_prev->range_next = node; } f->range_tail = node; f->size += node->data_size; if (!f->range_head) { f->range_head = node; } } else if (node->data_offset < f->size) { /* Trying to insert data into the middle of the file. This means no problem because jffs_delete_data() has already prepared the range list for us. */ struct jffs_node *n; /* Find the correct place for the insertion and then insert the node. */ for (n = f->range_head; n; n = n->range_next) { D2(printk("Cool stuff's happening!\n")); if (n->data_offset == node->data_offset) { node->range_prev = n->range_prev; if (node->range_prev) { node->range_prev->range_next = node; } else { f->range_head = node; } node->range_next = n; n->range_prev = node; break; } ASSERT(else if (n->data_offset + n->data_size > node->data_offset) { printk(KERN_ERR "jffs_insert_data(): " "Couldn't find a place to insert " "the data!\n"); return -1; }); } /* Adjust later nodes' offsets etc. */ n = node->range_next; while (n) { n->data_offset += node->data_size; n = n->range_next; } f->size += node->data_size; } else if (node->data_offset > f->size) { /* Okay. This is tricky. This means that we want to insert data at a place that is beyond the limits of the file as it is constructed right now. This is actually a common event that for instance could occur during the mounting of the file system if a large file have been truncated, rewritten and then only partially garbage collected. */ struct jffs_node *n; /* We need a place holder for the data that is missing in front of this insertion. This "virtual node" will not be associated with any space on the flash device. */ struct jffs_node *virtual_node; if (!(virtual_node = jffs_alloc_node())) { re
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -