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
);