123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- /*
- * jffs2 on-disk structure generator for mtd
- *
- * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License v2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * Based on:
- * JFFS2 -- Journalling Flash File System, Version 2.
- * Copyright © 2001-2007 Red Hat, Inc.
- * Created by David Woodhouse <dwmw2@infradead.org>
- */
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dirent.h>
- #include <unistd.h>
- #include <endian.h>
- #include "jffs2.h"
- #include "crc32.h"
- #include "mtd.h"
- #define PAD(x) (((x)+3)&~3)
- #if BYTE_ORDER == BIG_ENDIAN
- # define CLEANMARKER "\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98"
- #else
- # define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4"
- #endif
- static int last_ino = 0;
- static int last_version = 0;
- static char *buf = NULL;
- static int ofs = 0;
- static int outfd = -1;
- static int mtdofs = 0;
- static int target_ino = 0;
- static void prep_eraseblock(void);
- static void pad(int size)
- {
- if ((ofs % size == 0) && (ofs < erasesize))
- return;
- if (ofs < erasesize) {
- memset(buf + ofs, 0xff, (size - (ofs % size)));
- ofs += (size - (ofs % size));
- }
- ofs = ofs % erasesize;
- if (ofs == 0) {
- while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize)) {
- if (!quiet)
- fprintf(stderr, "\nSkipping bad block at 0x%08x ", mtdofs);
- mtdofs += erasesize;
- /* Move the file pointer along over the bad block. */
- lseek(outfd, erasesize, SEEK_CUR);
- }
- mtd_erase_block(outfd, mtdofs);
- write(outfd, buf, erasesize);
- mtdofs += erasesize;
- }
- }
- static inline int rbytes(void)
- {
- return erasesize - (ofs % erasesize);
- }
- static inline void add_data(char *ptr, int len)
- {
- if (ofs + len > erasesize) {
- pad(erasesize);
- prep_eraseblock();
- }
- memcpy(buf + ofs, ptr, len);
- ofs += len;
- }
- static void prep_eraseblock(void)
- {
- if (ofs > 0)
- return;
- add_data(CLEANMARKER, sizeof(CLEANMARKER) - 1);
- }
- static int add_dirent(const char *name, const char type, int parent)
- {
- struct jffs2_raw_dirent *de;
- if (ofs - erasesize < sizeof(struct jffs2_raw_dirent) + strlen(name))
- pad(erasesize);
- prep_eraseblock();
- last_ino++;
- memset(buf + ofs, 0, sizeof(struct jffs2_raw_dirent));
- de = (struct jffs2_raw_dirent *) (buf + ofs);
- de->magic = JFFS2_MAGIC_BITMASK;
- de->nodetype = JFFS2_NODETYPE_DIRENT;
- de->type = type;
- de->name_crc = crc32(0, name, strlen(name));
- de->ino = last_ino++;
- de->pino = parent;
- de->totlen = sizeof(*de) + strlen(name);
- de->hdr_crc = crc32(0, (void *) de, sizeof(struct jffs2_unknown_node) - 4);
- de->version = last_version++;
- de->mctime = 0;
- de->nsize = strlen(name);
- de->node_crc = crc32(0, (void *) de, sizeof(*de) - 8);
- memcpy(de->name, name, strlen(name));
- ofs += sizeof(struct jffs2_raw_dirent) + de->nsize;
- pad(4);
- return de->ino;
- }
- static int add_dir(const char *name, int parent)
- {
- struct jffs2_raw_inode ri;
- int inode;
- inode = add_dirent(name, IFTODT(S_IFDIR), parent);
- if (rbytes() < sizeof(ri))
- pad(erasesize);
- prep_eraseblock();
- memset(&ri, 0, sizeof(ri));
- ri.magic = JFFS2_MAGIC_BITMASK;
- ri.nodetype = JFFS2_NODETYPE_INODE;
- ri.totlen = sizeof(ri);
- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
- ri.ino = inode;
- ri.mode = S_IFDIR | 0755;
- ri.uid = ri.gid = 0;
- ri.atime = ri.ctime = ri.mtime = 0;
- ri.isize = ri.csize = ri.dsize = 0;
- ri.version = 1;
- ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
- ri.data_crc = 0;
- add_data((char *) &ri, sizeof(ri));
- pad(4);
- return inode;
- }
- static void add_file(const char *name, int parent)
- {
- int inode, f_offset = 0, fd;
- struct jffs2_raw_inode ri;
- struct stat st;
- char wbuf[4096];
- const char *fname;
- if (stat(name, &st)) {
- fprintf(stderr, "File %s does not exist\n", name);
- return;
- }
- fname = strrchr(name, '/');
- if (fname)
- fname++;
- else
- fname = name;
- inode = add_dirent(fname, IFTODT(S_IFREG), parent);
- memset(&ri, 0, sizeof(ri));
- ri.magic = JFFS2_MAGIC_BITMASK;
- ri.nodetype = JFFS2_NODETYPE_INODE;
- ri.ino = inode;
- ri.mode = st.st_mode;
- ri.uid = ri.gid = 0;
- ri.atime = st.st_atime;
- ri.ctime = st.st_ctime;
- ri.mtime = st.st_mtime;
- ri.isize = st.st_size;
- ri.compr = 0;
- ri.usercompr = 0;
- fd = open(name, 0);
- if (fd < 0) {
- fprintf(stderr, "File %s does not exist\n", name);
- return;
- }
- for (;;) {
- int len = 0;
- for (;;) {
- len = rbytes() - sizeof(ri);
- if (len > 128)
- break;
- pad(erasesize);
- prep_eraseblock();
- }
- if (len > sizeof(wbuf))
- len = sizeof(wbuf);
- len = read(fd, wbuf, len);
- if (len <= 0)
- break;
- ri.totlen = sizeof(ri) + len;
- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4);
- ri.version = ++last_version;
- ri.offset = f_offset;
- ri.csize = ri.dsize = len;
- ri.node_crc = crc32(0, &ri, sizeof(ri) - 8);
- ri.data_crc = crc32(0, wbuf, len);
- f_offset += len;
- add_data((char *) &ri, sizeof(ri));
- add_data(wbuf, len);
- pad(4);
- prep_eraseblock();
- }
- close(fd);
- }
- int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename)
- {
- outfd = fd;
- mtdofs = ofs;
- buf = malloc(erasesize);
- target_ino = 1;
- if (!last_ino)
- last_ino = 1;
- add_file(filename, target_ino);
- pad(erasesize);
- /* add eof marker, pad to eraseblock size and write the data */
- add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
- pad(erasesize);
- free(buf);
- return (mtdofs - ofs);
- }
- void mtd_parse_jffs2data(const char *buf, const char *dir)
- {
- struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
- unsigned int ofs = 0;
- while (ofs < erasesize) {
- node = (struct jffs2_unknown_node *) (buf + ofs);
- if (node->magic != 0x1985)
- break;
- ofs += PAD(node->totlen);
- if (node->nodetype == JFFS2_NODETYPE_DIRENT) {
- struct jffs2_raw_dirent *de = (struct jffs2_raw_dirent *) node;
- /* is this the right directory name and is it a subdirectory of / */
- if (*dir && (de->pino == 1) && !strncmp((char *) de->name, dir, de->nsize))
- target_ino = de->ino;
- /* store the last inode and version numbers for adding extra files */
- if (last_ino < de->ino)
- last_ino = de->ino;
- if (last_version < de->version)
- last_version = de->version;
- }
- }
- }
- int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir)
- {
- int err = -1, fdeof = 0;
- outfd = mtd_check_open(mtd);
- if (outfd < 0)
- return -1;
- if (quiet < 2)
- fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd);
-
- buf = malloc(erasesize);
- if (!buf) {
- fprintf(stderr, "Out of memory!\n");
- goto done;
- }
- if (!*dir)
- target_ino = 1;
- /* parse the structure of the jffs2 first
- * locate the directory that the file is going to be placed in */
- for(;;) {
- struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf;
- if (read(outfd, buf, erasesize) != erasesize) {
- fdeof = 1;
- break;
- }
- mtdofs += erasesize;
- if (node->magic == 0x8519) {
- fprintf(stderr, "Error: wrong endianness filesystem\n");
- goto done;
- }
- /* assume no magic == end of filesystem
- * the filesystem will probably end with be32(0xdeadc0de) */
- if (node->magic != 0x1985)
- break;
- mtd_parse_jffs2data(buf, dir);
- }
- if (fdeof) {
- fprintf(stderr, "Error: No room for additional data\n");
- goto done;
- }
- /* jump back one eraseblock */
- mtdofs -= erasesize;
- lseek(outfd, mtdofs, SEEK_SET);
- ofs = 0;
- if (!last_ino)
- last_ino = 1;
- if (!target_ino)
- target_ino = add_dir(dir, 1);
- add_file(filename, target_ino);
- pad(erasesize);
- /* add eof marker, pad to eraseblock size and write the data */
- add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1);
- pad(erasesize);
- err = 0;
- if (trx_fixup) {
- trx_fixup(outfd, mtd);
- }
- done:
- close(outfd);
- if (buf)
- free(buf);
- return err;
- }
|