2 * jffs2 on-disk structure generator for mtd
4 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License v2
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * JFFS2 -- Journalling Flash File System, Version 2.
16 * Copyright © 2001-2007 Red Hat, Inc.
17 * Created by David Woodhouse <dwmw2@infradead.org>
19 #include <sys/types.h>
33 #define PAD(x) (((x)+3)&~3)
35 #if BYTE_ORDER == BIG_ENDIAN
36 # define CLEANMARKER "\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98"
38 # define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4"
41 static int last_ino = 0;
42 static int last_version = 0;
43 static char *buf = NULL;
45 static int outfd = -1;
46 static int mtdofs = 0;
47 static int target_ino = 0;
49 static void prep_eraseblock(void);
51 static void pad(int size)
53 if ((ofs % size == 0) && (ofs < erasesize))
56 if (ofs < erasesize) {
57 memset(buf + ofs, 0xff, (size - (ofs % size)));
58 ofs += (size - (ofs % size));
60 ofs = ofs % erasesize;
62 while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize)) {
64 fprintf(stderr, "\nSkipping bad block at 0x%08x ", mtdofs);
68 /* Move the file pointer along over the bad block. */
69 lseek(outfd, erasesize, SEEK_CUR);
71 mtd_erase_block(outfd, mtdofs);
72 write(outfd, buf, erasesize);
77 static inline int rbytes(void)
79 return erasesize - (ofs % erasesize);
82 static inline void add_data(char *ptr, int len)
84 if (ofs + len > erasesize) {
88 memcpy(buf + ofs, ptr, len);
92 static void prep_eraseblock(void)
97 add_data(CLEANMARKER, sizeof(CLEANMARKER) - 1);
100 static int add_dirent(const char *name, const char type, int parent)
102 struct jffs2_raw_dirent *de;
104 if (ofs - erasesize < sizeof(struct jffs2_raw_dirent) + strlen(name))
109 memset(buf + ofs, 0, sizeof(struct jffs2_raw_dirent));
110 de = (struct jffs2_raw_dirent *) (buf + ofs);
112 de->magic = JFFS2_MAGIC_BITMASK;
113 de->nodetype = JFFS2_NODETYPE_DIRENT;
115 de->name_crc = crc32(0, name, strlen(name));
116 de->ino = last_ino++;
118 de->totlen = sizeof(*de) + strlen(name);
119 de->hdr_crc = crc32(0, (void *) de, sizeof(struct jffs2_unknown_node) - 4);
120 de->version = last_version++;
122 de->nsize = strlen(name);
123 de->node_crc = crc32(0, (void *) de, sizeof(*de) - 8);
124 memcpy(de->name, name, strlen(name));
126 ofs += sizeof(struct jffs2_raw_dirent) + de->nsize;
132 static int add_dir(const char *name, int parent)
134 struct jffs2_raw_inode ri;
137 inode = add_dirent(name, IFTODT(S_IFDIR), parent);
139 if (rbytes() < sizeof(ri))
143 memset(&ri, 0, sizeof(ri));
144 ri.magic = JFFS2_MAGIC_BITMASK;
145 ri.nodetype = JFFS2_NODETYPE_INODE;
146 ri.totlen = sizeof(ri);
147 ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
150 ri.mode = S_IFDIR | 0755;
152 ri.atime = ri.ctime = ri.mtime = 0;
153 ri.isize = ri.csize = ri.dsize = 0;
155 ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
158 add_data((char *) &ri, sizeof(ri));
163 static void add_file(const char *name, int parent)
165 int inode, f_offset = 0, fd;
166 struct jffs2_raw_inode ri;
171 if (stat(name, &st)) {
172 fprintf(stderr, "File %s does not exist\n", name);
176 fname = strrchr(name, '/');
182 inode = add_dirent(fname, IFTODT(S_IFREG), parent);
183 memset(&ri, 0, sizeof(ri));
184 ri.magic = JFFS2_MAGIC_BITMASK;
185 ri.nodetype = JFFS2_NODETYPE_INODE;
188 ri.mode = st.st_mode;
190 ri.atime = st.st_atime;
191 ri.ctime = st.st_ctime;
192 ri.mtime = st.st_mtime;
193 ri.isize = st.st_size;
199 fprintf(stderr, "File %s does not exist\n", name);
207 len = rbytes() - sizeof(ri);
215 if (len > sizeof(wbuf))
218 len = read(fd, wbuf, len);
222 ri.totlen = sizeof(ri) + len;
223 ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
224 ri.version = ++last_version;
225 ri.offset = f_offset;
226 ri.csize = ri.dsize = len;
227 ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
228 ri.data_crc = crc32(0, wbuf, len);
230 add_data((char *) &ri, sizeof(ri));
239 int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
244 buf = malloc(erasesize);
248 add_file(filename, target_ino);
251 /* add eof marker, pad to eraseblock size and write the data */
252 add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
256 return (mtdofs - ofs);
259 void mtd_parse_jffs2data(const char *buf, const char *dir)
261 struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
262 unsigned int ofs = 0;
264 while (ofs < erasesize) {
265 node = (struct jffs2_unknown_node *) (buf + ofs);
266 if (node->magic != 0x1985)
269 ofs += PAD(node->totlen);
270 if (node->nodetype == JFFS2_NODETYPE_DIRENT) {
271 struct jffs2_raw_dirent *de = (struct jffs2_raw_dirent *) node;
273 /* is this the right directory name and is it a subdirectory of / */
274 if (*dir && (de->pino == 1) && !strncmp((char *) de->name, dir, de->nsize))
275 target_ino = de->ino;
277 /* store the last inode and version numbers for adding extra files */
278 if (last_ino < de->ino)
280 if (last_version < de->version)
281 last_version = de->version;
286 int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
288 int err = -1, fdeof = 0;
290 outfd = mtd_check_open(mtd);
295 fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd);
297 buf = malloc(erasesize);
299 fprintf(stderr, "Out of memory!\n");
306 /* parse the structure of the jffs2 first
307 * locate the directory that the file is going to be placed in */
309 struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
311 if (read(outfd, buf, erasesize) != erasesize) {
317 if (node->magic == 0x8519) {
318 fprintf(stderr, "Error: wrong endianness filesystem\n");
322 /* assume no magic == end of filesystem
323 * the filesystem will probably end with be32(0xdeadc0de) */
324 if (node->magic != 0x1985)
327 mtd_parse_jffs2data(buf, dir);
331 fprintf(stderr, "Error: No room for additional data\n");
335 /* jump back one eraseblock */
337 lseek(outfd, mtdofs, SEEK_SET);
345 target_ino = add_dir(dir, 1);
347 add_file(filename, target_ino);
350 /* add eof marker, pad to eraseblock size and write the data */
351 add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
357 trx_fixup(outfd, mtd);