📄 intrep.c
字号:
/* * JFFS -- Journalling Flash File System, Linux implementation. * * Copyright (C) 1999, 2000 Finn Hakansson, Axis Communications, Inc. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * $Id: intrep.c,v 1.92 2000/01/11 12:26:06 finn Exp $ * *//* This file contains the code for the internal structure of the Journalling Flash File System, JFFS. *//* * Todo list: * * memcpy_to_flash()- and memcpy_from_flash()-functions. * * Implementation of hard links. * * Organize the source code in a better way. Against the VFS we could * have jffs_ext.c, and against the block device jffs_int.c. * A better file-internal organization too. * * A better checksum algorithm. * * Consider endianness stuff. ntohl() etc. * * Check all comments beginning with XXX. * * Are we handling the atime, mtime, ctime members of the inode right? * * Remove some duplicated code. Take a look at jffs_write_node() and * jffs_rewrite_data() for instance. * * Implement more meaning of the nlink member in various data structures. * nlink could be used in conjunction with hard links for instance. * * Fix the rename stuff. (I.e. if we have two files `a' and `b' and we * do a `mv b a'.) Half of this is already implemented. * */#include <linux/module.h>#include <linux/types.h>#include <linux/malloc.h>#include <linux/jffs.h>#include <linux/fs.h>#include <linux/stat.h>#include <linux/pagemap.h>#include <linux/locks.h>#include <asm/byteorder.h>#include "intrep.h"#include "jffs_fm.h"#if defined(CONFIG_JFFS_FS_VERBOSE) && CONFIG_JFFS_FS_VERBOSE#define D(x) x#else#define D(x)#endif#define D1(x)#define D2(x)#define D3(x)#define ASSERT(x) x#if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUGlong no_jffs_file = 0;long no_jffs_node = 0;long no_jffs_control = 0;long no_jffs_raw_inode = 0;long no_jffs_node_ref = 0;long no_jffs_fm = 0;long no_jffs_fmcontrol = 0;long no_hash = 0;long no_name = 0;#endifstatic int jffs_scan_flash(struct jffs_control *c);static int jffs_update_file(struct jffs_file *f, struct jffs_node *node);#if 0#define _U 01#define _L 02#define _N 04#define _S 010#define _P 020#define _C 040#define _X 0100#define _B 0200const unsigned char jffs_ctype_[1 + 256] = { 0, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _S|_B, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _P, _N, _N, _N, _N, _N, _N, _N, _N, _N, _N, _P, _P, _P, _P, _P, _P, _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _U, _P, _P, _P, _P, _P, _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _L, _P, _P, _P, _P, _C};#define jffs_isalpha(c) ((jffs_ctype_+1)[c]&(_U|_L))#define jffs_isupper(c) ((jffs_ctype_+1)[c]&_U)#define jffs_islower(c) ((jffs_ctype_+1)[c]&_L)#define jffs_isdigit(c) ((jffs_ctype_+1)[c]&_N)#define jffs_isxdigit(c) ((jffs_ctype_+1)[c]&(_X|_N))#define jffs_isspace(c) ((jffs_ctype_+1)[c]&_S)#define jffs_ispunct(c) ((jffs_ctype_+1)[c]&_P)#define jffs_isalnum(c) ((jffs_ctype_+1)[c]&(_U|_L|_N))#define jffs_isprint(c) ((jffs_ctype_+1)[c]&(_P|_U|_L|_N|_B))#define jffs_isgraph(c) ((jffs_ctype_+1)[c]&(_P|_U|_L|_N))#define jffs_iscntrl(c) ((jffs_ctype_+1)[c]&_C)voidjffs_hexdump(const unsigned char* ptr, int size){ char line[16]; int j = 0; while (size > 0) { int i; printk("%p:", ptr); for (j = 0; j < 16; j++) { line[j] = *ptr++; } for (i = 0; i < j; i++) { if (!(i & 1)) { printk(" %.2x", line[i] & 0xff); } else { printk("%.2x", line[i] & 0xff); } } /* Print empty space */ for (; i < 16; i++) { if (!(i & 1)) { printk(" "); } else { printk(" "); } } printk(" "); for (i = 0; i < j; i++) { if (jffs_isgraph(line[i])) { printk("%c", line[i]); } else { printk("."); } } printk("\n"); size -= 16; }}#endifinline intjffs_min(int a, int b){ return (a < b ? a : b);}inline intjffs_max(int a, int b){ return (a > b ? a : b);}/* This routine calculates checksums in JFFS. */__u32jffs_checksum(const void *data, int size){ __u32 sum = 0; __u8 *ptr = (__u8 *)data; D3(printk("#csum at 0x%p, {0x%08lx, 0x%08lx, ... }, size: %d", data, *(long *)data, *((long *)data + 1), size)); while (size-- > 0) { sum += *ptr++; } D3(printk(", result: 0x%08x\n", sum)); return sum;}/* Create and initialize a new struct jffs_file. */static struct jffs_file *jffs_create_file(struct jffs_control *c, const struct jffs_raw_inode *raw_inode){ struct jffs_file *f; if (!(f = (struct jffs_file *)kmalloc(sizeof(struct jffs_file), GFP_KERNEL))) { D(printk("jffs_create_file(): Failed!\n")); return 0; } DJM(no_jffs_file++); memset(f, 0, sizeof(struct jffs_file)); f->ino = raw_inode->ino; f->pino = raw_inode->pino; f->nlink = raw_inode->nlink; f->deleted = raw_inode->deleted; f->c = c; return f;}/* Build a control block for the file system. */static struct jffs_control *jffs_create_control(kdev_t dev){ struct jffs_control *c; register int s = sizeof(struct jffs_control); D(char *t = 0); D2(printk("jffs_create_control()\n")); if (!(c = (struct jffs_control *)kmalloc(s, GFP_KERNEL))) { goto fail_control; } DJM(no_jffs_control++); c->root = 0; c->hash_len = JFFS_HASH_SIZE; s = sizeof(struct jffs_file *) * c->hash_len; if (!(c->hash = (struct jffs_file **)kmalloc(s, GFP_KERNEL))) { goto fail_hash; } DJM(no_hash++); memset(c->hash, 0, s); if (!(c->fmc = jffs_build_begin(c, dev))) { goto fail_fminit; } c->next_ino = JFFS_MIN_INO + 1; c->rename_lock = 0; c->rename_wait = (struct wait_queue *)0; return c;fail_fminit: D(t = "c->fmc");fail_hash: kfree(c); DJM(no_jffs_control--); D(t = t ? t : "c->hash");fail_control: D(t = t ? t : "control"); D(printk("jffs_create_control(): Allocation failed: (%s)\n", t)); return (struct jffs_control *)0;}/* Clean up all data structures associated with the file system. */voidjffs_cleanup_control(struct jffs_control *c){ D2(printk("jffs_cleanup_control()\n")); if (!c) { D(printk("jffs_cleanup_control(): c == NULL !!!\n")); return; } /* Free all files and nodes. */ if (c->hash) { jffs_foreach_file(c, jffs_free_node_list); kfree(c->hash); DJM(no_hash--); } jffs_cleanup_fmcontrol(c->fmc); kfree(c); DJM(no_jffs_control--); D3(printk("jffs_cleanup_control(): Leaving...\n"));}/* This function adds a virtual root node to the in-RAM representation. Called by jffs_build_fs(). */static intjffs_add_virtual_root(struct jffs_control *c){ struct jffs_file *root; struct jffs_node *node; D2(printk("jffs_add_virtual_root(): " "Creating a virtual root directory.\n")); if (!(root = (struct jffs_file *)kmalloc(sizeof(struct jffs_file), GFP_KERNEL))) { return -ENOMEM; } DJM(no_jffs_file++); if (!(node = (struct jffs_node *)kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) { kfree(root); DJM(no_jffs_file--); return -ENOMEM; } DJM(no_jffs_node++); memset(node, 0, sizeof(struct jffs_node)); node->ino = JFFS_MIN_INO; memset(root, 0, sizeof(struct jffs_file)); root->ino = JFFS_MIN_INO; root->mode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; root->atime = root->mtime = root->ctime = CURRENT_TIME; root->nlink = 1; root->c = c; root->version_head = root->version_tail = node; jffs_insert_file_into_hash(root); return 0;}/* This is where the file system is built and initialized. */intjffs_build_fs(struct super_block *sb){ struct jffs_control *c; int err = 0; D2(printk("jffs_build_fs()\n")); if (!(c = jffs_create_control(sb->s_dev))) { return -ENOMEM; } c->building_fs = 1; c->sb = sb; if ((err = jffs_scan_flash(c)) < 0) { goto jffs_build_fs_fail; } /* Add a virtual root node if no one exists. */ if (!jffs_find_file(c, JFFS_MIN_INO)) { if ((err = jffs_add_virtual_root(c)) < 0) { goto jffs_build_fs_fail; } } /* Remove deleted nodes. */ if ((err = jffs_foreach_file(c, jffs_possibly_delete_file)) < 0) { printk(KERN_ERR "JFFS: Failed to remove deleted nodes.\n"); goto jffs_build_fs_fail; } /* Remove redundant nodes. (We are not interested in the return value in this case.) */ jffs_foreach_file(c, jffs_remove_redundant_nodes); /* Try to build a tree from all the nodes. */ if ((err = jffs_foreach_file(c, jffs_insert_file_into_tree)) < 0) { printk("JFFS: Failed to build tree.\n"); goto jffs_build_fs_fail; } /* Compute the sizes of all files in the filesystem. Adjust if necessary. */ if ((err = jffs_foreach_file(c, jffs_build_file)) < 0) { printk("JFFS: Failed to build file system.\n"); goto jffs_build_fs_fail; } sb->u.generic_sbp = (void *)c; c->building_fs = 0; D1(jffs_print_hash_table(c)); D1(jffs_print_tree(c->root, 0)); return 0;jffs_build_fs_fail: jffs_cleanup_control(c); return err;} /* jffs_build_fs() */#if defined(JFFS_FLASH_SHORTCUT) && JFFS_FLASH_SHORTCUT/* Scan the whole flash memory in order to find all nodes in the file systems. */static intjffs_scan_flash(struct jffs_control *c){ char name[JFFS_MAX_NAME_LEN + 2]; struct jffs_raw_inode raw_inode; struct jffs_node *node = 0; struct jffs_fmcontrol *fmc = c->fmc; __u32 checksum; __u8 tmp_accurate; __u16 tmp_chksum; unsigned char *pos = (unsigned char *) fmc->flash_start; unsigned char *start; unsigned char *end = (unsigned char *) (fmc->flash_start + fmc->flash_size); D1(printk("jffs_scan_flash(): start pos = 0x%p, end = 0x%p\n", pos, end)); flash_safe_acquire(fmc->flash_part); /* Start the scan. */ while (pos < end) { /* Remember the position from where we started this scan. */ start = pos; switch (*(__u32 *)pos) { case JFFS_EMPTY_BITMASK: /* We have found 0xff on this block. We have to scan the rest of the block to be sure it is filled with 0xff. */ D1(printk("jffs_scan_flash(): 0xff at pos 0x%p.\n", pos)); for (; pos < end && JFFS_EMPTY_BITMASK == *(__u32 *)pos; pos += 4); D1(printk("jffs_scan_flash(): 0xff ended at " "pos 0x%p.\n", pos)); continue; case JFFS_DIRTY_BITMASK: /* We have found 0x00 on this block. We have to scan as far as possible to find out how much is dirty. */ D1(printk("jffs_scan_flash(): 0x00 at pos 0x%p.\n", pos)); for (; pos < end && JFFS_DIRTY_BITMASK == *(__u32 *)pos; pos += 4); D1(printk("jffs_scan_flash(): 0x00 ended at " "pos 0x%p.\n", pos)); jffs_fmalloced(fmc, (__u32) start, (__u32) (pos - start), 0); continue; case JFFS_MAGIC_BITMASK: /* We have probably found a new raw inode. */ break; default: bad_inode: /* We're f*cked. This is not solved yet. We have to scan for the magic pattern. */ D1(printk("*************** Dirty flash memory or bad inode: " "hexdump(pos = 0x%p, len = 128):\n", pos)); D1(jffs_hexdump(pos, 128)); for (pos += 4; pos < end; pos += 4) { switch (*(__u32 *)pos) { case JFFS_MAGIC_BITMASK: jffs_fmalloced(fmc, (__u32) start, (__u32) (pos - start), 0); goto cont_scan; default: break; } } cont_scan: continue; } /* We have found the beginning of an inode. Create a node for it. */ if (!node) { if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -