summaryrefslogtreecommitdiff
path: root/jffs-dump.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@shinybook.infradead.org>2006-04-11 19:09:16 -0400
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>2006-04-11 19:09:16 -0400
commit72212c137c574b564723327af751c4054c7cfca6 (patch)
tree13be2da9d4be695002d6ea9c396660c986e5fa5c /jffs-dump.c
Initial commit
Diffstat (limited to 'jffs-dump.c')
-rw-r--r--jffs-dump.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/jffs-dump.c b/jffs-dump.c
new file mode 100644
index 0000000..0a8b7e5
--- /dev/null
+++ b/jffs-dump.c
@@ -0,0 +1,361 @@
+/*
+ * Dump JFFS filesystem.
+ * Useful when it buggers up.
+ */
+
+/* $Id: jffs-dump.c,v 1.3 2005/11/07 11:15:12 gleixner Exp $ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define BLOCK_SIZE 1024
+#define JFFS_MAGIC 0x34383931 /* "1984" */
+#define JFFS_MAX_NAME_LEN 256
+#define JFFS_MIN_INO 1
+#define JFFS_TRACE_INDENT 4
+#define JFFS_ALIGN_SIZE 4
+#define MAX_CHUNK_SIZE 32768
+
+/* How many padding bytes should be inserted between two chunks of data
+ on the flash? */
+#define JFFS_GET_PAD_BYTES(size) ((JFFS_ALIGN_SIZE \
+ - ((__u32)(size) % JFFS_ALIGN_SIZE)) \
+ % JFFS_ALIGN_SIZE)
+
+#define JFFS_EMPTY_BITMASK 0xffffffff
+#define JFFS_MAGIC_BITMASK 0x34383931
+#define JFFS_DIRTY_BITMASK 0x00000000
+
+#define min(x,y) (x) > (y) ? (y) : (x)
+
+struct jffs_raw_inode
+{
+ __u32 magic; /* A constant magic number. */
+ __u32 ino; /* Inode number. */
+ __u32 pino; /* Parent's inode number. */
+ __u32 version; /* Version number. */
+ __u32 mode; /* file_type, mode */
+ __u16 uid;
+ __u16 gid;
+ __u32 atime;
+ __u32 mtime;
+ __u32 ctime;
+ __u32 offset; /* Where to begin to write. */
+ __u32 dsize; /* Size of the file data. */
+ __u32 rsize; /* How much are going to be replaced? */
+ __u8 nsize; /* Name length. */
+ __u8 nlink; /* Number of links. */
+ __u8 spare : 6; /* For future use. */
+ __u8 rename : 1; /* Is this a special rename? */
+ __u8 deleted : 1; /* Has this file been deleted? */
+ __u8 accurate; /* The inode is obsolete if accurate == 0. */
+ __u32 dchksum; /* Checksum for the data. */
+ __u16 nchksum; /* Checksum for the name. */
+ __u16 chksum; /* Checksum for the raw_inode. */
+};
+
+
+struct jffs_file
+{
+ struct jffs_raw_inode inode;
+ char *name;
+ unsigned char *data;
+};
+
+
+char *root_directory_name = NULL;
+int fs_pos = 0;
+int verbose = 0;
+
+#define ENDIAN_HOST 0
+#define ENDIAN_BIG 1
+#define ENDIAN_LITTLE 2
+int endian = ENDIAN_HOST;
+
+static __u32 jffs_checksum(void *data, int size);
+void jffs_print_trace(const char *path, int depth);
+int make_root_dir(FILE *fs, int first_ino, const char *root_dir_path,
+ int depth);
+void write_file(struct jffs_file *f, FILE *fs, struct stat st);
+void read_data(struct jffs_file *f, const char *path, int offset);
+int mkfs(FILE *fs, const char *path, int ino, int parent, int depth);
+
+
+static __u32
+jffs_checksum(void *data, int size)
+{
+ __u32 sum = 0;
+ __u8 *ptr = (__u8 *)data;
+
+ while (size-- > 0)
+ {
+ sum += *ptr++;
+ }
+
+ return sum;
+}
+
+
+void
+jffs_print_trace(const char *path, int depth)
+{
+ int path_len = strlen(path);
+ int out_pos = depth * JFFS_TRACE_INDENT;
+ int pos = path_len - 1;
+ char *out = (char *)alloca(depth * JFFS_TRACE_INDENT + path_len + 1);
+
+ if (verbose >= 2)
+ {
+ fprintf(stderr, "jffs_print_trace(): path: \"%s\"\n", path);
+ }
+
+ if (!out) {
+ fprintf(stderr, "jffs_print_trace(): Allocation failed.\n");
+ fprintf(stderr, " path: \"%s\"\n", path);
+ fprintf(stderr, "depth: %d\n", depth);
+ exit(1);
+ }
+
+ memset(out, ' ', depth * JFFS_TRACE_INDENT);
+
+ if (path[pos] == '/')
+ {
+ pos--;
+ }
+ while (path[pos] && (path[pos] != '/'))
+ {
+ pos--;
+ }
+ for (pos++; path[pos] && (path[pos] != '/'); pos++)
+ {
+ out[out_pos++] = path[pos];
+ }
+ out[out_pos] = '\0';
+ fprintf(stderr, "%s\n", out);
+}
+
+
+/* Print the contents of a raw inode. */
+void
+jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
+{
+ fprintf(stdout, "jffs_raw_inode: inode number: %u, version %u\n", raw_inode->ino, raw_inode->version);
+ fprintf(stdout, "{\n");
+ fprintf(stdout, " 0x%08x, /* magic */\n", raw_inode->magic);
+ fprintf(stdout, " 0x%08x, /* ino */\n", raw_inode->ino);
+ fprintf(stdout, " 0x%08x, /* pino */\n", raw_inode->pino);
+ fprintf(stdout, " 0x%08x, /* version */\n", raw_inode->version);
+ fprintf(stdout, " 0x%08x, /* mode */\n", raw_inode->mode);
+ fprintf(stdout, " 0x%04x, /* uid */\n", raw_inode->uid);
+ fprintf(stdout, " 0x%04x, /* gid */\n", raw_inode->gid);
+ fprintf(stdout, " 0x%08x, /* atime */\n", raw_inode->atime);
+ fprintf(stdout, " 0x%08x, /* mtime */\n", raw_inode->mtime);
+ fprintf(stdout, " 0x%08x, /* ctime */\n", raw_inode->ctime);
+ fprintf(stdout, " 0x%08x, /* offset */\n", raw_inode->offset);
+ fprintf(stdout, " 0x%08x, /* dsize */\n", raw_inode->dsize);
+ fprintf(stdout, " 0x%08x, /* rsize */\n", raw_inode->rsize);
+ fprintf(stdout, " 0x%02x, /* nsize */\n", raw_inode->nsize);
+ fprintf(stdout, " 0x%02x, /* nlink */\n", raw_inode->nlink);
+ fprintf(stdout, " 0x%02x, /* spare */\n",
+ raw_inode->spare);
+ fprintf(stdout, " %u, /* rename */\n",
+ raw_inode->rename);
+ fprintf(stdout, " %u, /* deleted */\n",
+ raw_inode->deleted);
+ fprintf(stdout, " 0x%02x, /* accurate */\n",
+ raw_inode->accurate);
+ fprintf(stdout, " 0x%08x, /* dchksum */\n", raw_inode->dchksum);
+ fprintf(stdout, " 0x%04x, /* nchksum */\n", raw_inode->nchksum);
+ fprintf(stdout, " 0x%04x, /* chksum */\n", raw_inode->chksum);
+ fprintf(stdout, "}\n");
+}
+
+static void write_val32(__u32 *adr, __u32 val)
+{
+ switch(endian) {
+ case ENDIAN_HOST:
+ *adr = val;
+ break;
+ case ENDIAN_LITTLE:
+ *adr = __cpu_to_le32(val);
+ break;
+ case ENDIAN_BIG:
+ *adr = __cpu_to_be32(val);
+ break;
+ }
+}
+
+static void write_val16(__u16 *adr, __u16 val)
+{
+ switch(endian) {
+ case ENDIAN_HOST:
+ *adr = val;
+ break;
+ case ENDIAN_LITTLE:
+ *adr = __cpu_to_le16(val);
+ break;
+ case ENDIAN_BIG:
+ *adr = __cpu_to_be16(val);
+ break;
+ }
+}
+
+static __u32 read_val32(__u32 *adr)
+{
+ __u32 val;
+
+ switch(endian) {
+ case ENDIAN_HOST:
+ val = *adr;
+ break;
+ case ENDIAN_LITTLE:
+ val = __le32_to_cpu(*adr);
+ break;
+ case ENDIAN_BIG:
+ val = __be32_to_cpu(*adr);
+ break;
+ }
+ return val;
+}
+
+static __u16 read_val16(__u16 *adr)
+{
+ __u16 val;
+
+ switch(endian) {
+ case ENDIAN_HOST:
+ val = *adr;
+ break;
+ case ENDIAN_LITTLE:
+ val = __le16_to_cpu(*adr);
+ break;
+ case ENDIAN_BIG:
+ val = __be16_to_cpu(*adr);
+ break;
+ }
+ return val;
+}
+
+int
+main(int argc, char **argv)
+{
+ int fs;
+ struct stat sb;
+ __u32 wordbuf;
+ off_t pos = 0;
+ off_t end;
+ struct jffs_raw_inode ino;
+ unsigned char namebuf[4096];
+ int myino = -1;
+
+ if (argc < 2) {
+ printf("no filesystem given\n");
+ exit(1);
+ }
+
+ fs = open(argv[1], O_RDONLY);
+ if (fs < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (argc > 2) {
+ myino = atol(argv[2]);
+ printf("Printing ino #%d\n" , myino);
+ }
+
+ if (fstat(fs, &sb) < 0) {
+ perror("stat");
+ close(fs);
+ exit(1);
+ }
+ end = sb.st_size;
+
+ while (pos < end) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+
+ switch(wordbuf) {
+ case JFFS_EMPTY_BITMASK:
+ // printf("0xff started at 0x%lx\n", pos);
+ for (; pos < end && wordbuf == JFFS_EMPTY_BITMASK; pos += 4) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ }
+ if (pos < end)
+ pos -= 4;
+ // printf("0xff ended at 0x%lx\n", pos);
+ continue;
+
+ case JFFS_DIRTY_BITMASK:
+ // printf("0x00 started at 0x%lx\n", pos);
+ for (; pos < end && wordbuf == JFFS_DIRTY_BITMASK; pos += 4) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ }
+ if (pos < end)
+ pos -=4;
+ // printf("0x00 ended at 0x%lx\n", pos);
+ continue;
+
+ default:
+ printf("Argh. Dirty memory at 0x%lx\n", pos);
+ // file_hexdump(fs, pos, 128);
+ for (pos += 4; pos < end; pos += 4) {
+ if (pread(fs, &wordbuf, 4, pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ if (wordbuf == JFFS_MAGIC_BITMASK)
+ break;
+ }
+
+ case JFFS_MAGIC_BITMASK:
+ if (pread(fs, &ino, sizeof(ino), pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ if (myino == -1 || ino.ino == myino) {
+ printf("Magic found at 0x%lx\n", pos);
+ jffs_print_raw_inode(&ino);
+ }
+ pos += sizeof(ino);
+
+ if (myino == -1 || ino.ino == myino) {
+ if (ino.nsize) {
+ if (pread(fs, namebuf, min(ino.nsize, 4095), pos) < 0) {
+ perror("pread");
+ exit(1);
+ }
+ if (ino.nsize < 4095)
+ namebuf[ino.nsize] = 0;
+ else
+ namebuf[4095] = 0;
+ printf("Name: \"%s\"\n", namebuf);
+ } else {
+ printf("No Name\n");
+ }
+ }
+ pos += (ino.nsize + 3) & ~3;
+
+ pos += (ino.dsize + 3) & ~3;
+ }
+
+
+
+ }
+}