diff options
Diffstat (limited to 'package/mtd/src')
| -rw-r--r-- | package/mtd/src/Makefile | 14 | ||||
| -rw-r--r-- | package/mtd/src/crc32.c | 95 | ||||
| -rw-r--r-- | package/mtd/src/crc32.h | 19 | ||||
| -rw-r--r-- | package/mtd/src/jffs2.c | 303 | ||||
| -rw-r--r-- | package/mtd/src/jffs2.h | 217 | ||||
| -rw-r--r-- | package/mtd/src/mtd-api.h (renamed from package/mtd/src/mtd.h) | 0 | ||||
| -rw-r--r-- | package/mtd/src/mtd.c | 295 | 
7 files changed, 809 insertions, 134 deletions
diff --git a/package/mtd/src/Makefile b/package/mtd/src/Makefile index 99e3ad792..5ab7d7b1e 100644 --- a/package/mtd/src/Makefile +++ b/package/mtd/src/Makefile @@ -1,12 +1,6 @@ -# $Id$ - -all: mtd - -%.o: %.c -	$(CC) -I. $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $^ - -mtd: mtd.o -	$(CC) -o $@ $^ +CC = gcc +CFLAGS += -Wall +mtd: mtd.o jffs2.o crc32.o  clean: -	rm -f *.o mtd +	rm -f *.o jffs2  diff --git a/package/mtd/src/crc32.c b/package/mtd/src/crc32.c new file mode 100644 index 000000000..6b1e50c42 --- /dev/null +++ b/package/mtd/src/crc32.c @@ -0,0 +1,95 @@ +/* + *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or + *  code or tables extracted from it, as desired without restriction. + * + *  First, the polynomial itself and its table of feedback terms.  The + *  polynomial is + *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + *  Note that we take it "backwards" and put the highest-order term in + *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the + *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in + *  the MSB being 1 + * + *  Note that the usual hardware shift register implementation, which + *  is what we're using (we're merely optimizing it by doing eight-bit + *  chunks at a time) shifts bits into the lowest-order term.  In our + *  implementation, that means shifting towards the right.  Why do we + *  do it this way?  Because the calculated CRC must be transmitted in + *  order from highest-order term to lowest-order term.  UARTs transmit + *  characters in order from LSB to MSB.  By storing the CRC this way + *  we hand it to the UART in the order low-byte to high-byte; the UART + *  sends each low-bit to hight-bit; and the result is transmission bit + *  by bit from highest- to lowest-order term without requiring any bit + *  shuffling on our part.  Reception works similarly + * + *  The feedback terms table consists of 256, 32-bit entries.  Notes + * + *      The table can be generated at runtime if desired; code to do so + *      is shown later.  It might not be obvious, but the feedback + *      terms simply represent the results of eight shift/xor opera + *      tions for all combinations of data and CRC register values + * + *      The values must be right-shifted by eight bits by the "updcrc + *      logic; the shift must be unsigned (bring in zeroes).  On some + *      hardware you could probably optimize the shift in assembler by + *      using byte-swap instructions + *      polynomial $edb88320 + */ + +#include <stdint.h> + +const uint32_t crc32_table[256] = { +	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, +	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, +	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, +	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, +	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, +	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, +	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, +	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, +	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, +	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, +	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, +	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, +	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, +	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, +	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, +	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, +	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, +	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, +	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, +	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, +	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, +	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, +	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, +	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, +	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, +	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, +	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, +	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, +	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, +	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, +	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, +	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, +	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, +	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, +	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, +	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, +	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, +	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, +	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, +	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, +	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, +	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, +	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, +	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, +	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, +	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, +	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, +	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, +	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, +	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, +	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, +	0x2d02ef8dL +}; diff --git a/package/mtd/src/crc32.h b/package/mtd/src/crc32.h new file mode 100644 index 000000000..ee3145bc1 --- /dev/null +++ b/package/mtd/src/crc32.h @@ -0,0 +1,19 @@ +#ifndef CRC32_H +#define CRC32_H + +#include <stdint.h> + +extern const uint32_t crc32_table[256]; + +/* Return a 32-bit CRC of the contents of the buffer. */ + +	static inline uint32_t +crc32(uint32_t val, const void *ss, int len) +{ +	const unsigned char *s = ss; +	while (--len >= 0) +		val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); +	return val; +} + +#endif diff --git a/package/mtd/src/jffs2.c b/package/mtd/src/jffs2.c new file mode 100644 index 000000000..7b68ae575 --- /dev/null +++ b/package/mtd/src/jffs2.c @@ -0,0 +1,303 @@ +#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 "jffs2.h" +#include "crc32.h" +#include "mtd.h" + +#define PAD(x) (((x)+3)&~3) + +#define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4" +#define JFFS2_EOF "\xde\xad\xc0\xde" + +static int last_ino = 0; +static int last_version = 0; +static char *buf = NULL; +static int ofs = 0; +static int outfd = 0; +static int mtdofs = 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) { +		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(char *name, 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(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(char *name, int parent) +{ +	int inode, f_offset = 0, fd; +	struct jffs2_raw_inode ri; +	struct stat st; +	char wbuf[4096], *fname; +	FILE *f; + +	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(name, 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_write_jffs2(char *mtd, char *filename, char *dir) +{ +	int target_ino = 0; +	int err = -1, fdeof = 0; +	off_t offset; + +	outfd = mtd_check_open(mtd); +	if (!outfd) +		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; +	} + +	/* 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; +		unsigned int ofs = 0; + +		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; + +		while (ofs < erasesize) { +			node = (struct jffs2_unknown_node *) (buf + ofs); +			if (node->magic == 0x1985) { +				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 ((de->pino == 1) && !strncmp(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; +				} +			} else { +				ofs = ~0; +			} +		} +	} + +	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; + +done: +	close(outfd); +	if (buf) +		free(buf); + +	return err; +} diff --git a/package/mtd/src/jffs2.h b/package/mtd/src/jffs2.h new file mode 100644 index 000000000..70d461953 --- /dev/null +++ b/package/mtd/src/jffs2.h @@ -0,0 +1,217 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by David Woodhouse <dwmw2@infradead.org> + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + * + * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $ + * + */ + +#ifndef __LINUX_JFFS2_H__ +#define __LINUX_JFFS2_H__ + +#define JFFS2_SUPER_MAGIC   0x72b6 + +/* You must include something which defines the C99 uintXX_t types.  +   We don't do it from here because this file is used in too many +   different environments. */ + +/* Values we may expect to find in the 'magic' field */ +#define JFFS2_OLD_MAGIC_BITMASK 0x1984 +#define JFFS2_MAGIC_BITMASK 0x1985 +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ +#define JFFS2_EMPTY_BITMASK 0xffff +#define JFFS2_DIRTY_BITMASK 0x0000 + +/* Summary node MAGIC marker */ +#define JFFS2_SUM_MAGIC	0x02851885 + +/* We only allow a single char for length, and 0xFF is empty flash so +   we don't want it confused with a real length. Hence max 254. +*/ +#define JFFS2_MAX_NAME_LEN 254 + +/* How small can we sensibly write nodes? */ +#define JFFS2_MIN_DATA_LEN 128 + +#define JFFS2_COMPR_NONE	0x00 +#define JFFS2_COMPR_ZERO	0x01 +#define JFFS2_COMPR_RTIME	0x02 +#define JFFS2_COMPR_RUBINMIPS	0x03 +#define JFFS2_COMPR_COPY	0x04 +#define JFFS2_COMPR_DYNRUBIN	0x05 +#define JFFS2_COMPR_ZLIB	0x06 +/* Compatibility flags. */ +#define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */ +#define JFFS2_NODE_ACCURATE 0x2000 +/* INCOMPAT: Fail to mount the filesystem */ +#define JFFS2_FEATURE_INCOMPAT 0xc000 +/* ROCOMPAT: Mount read-only */ +#define JFFS2_FEATURE_ROCOMPAT 0x8000 +/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 +/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 + +#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) +#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) +#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) + +#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) + +#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) +#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) + +/* XATTR Related */ +#define JFFS2_XPREFIX_USER		1	/* for "user." */ +#define JFFS2_XPREFIX_SECURITY		2	/* for "security." */ +#define JFFS2_XPREFIX_ACL_ACCESS	3	/* for "system.posix_acl_access" */ +#define JFFS2_XPREFIX_ACL_DEFAULT	4	/* for "system.posix_acl_default" */ +#define JFFS2_XPREFIX_TRUSTED		5	/* for "trusted.*" */ + +#define JFFS2_ACL_VERSION		0x0001 + +// Maybe later... +//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) + + +#define JFFS2_INO_FLAG_PREREAD	  1	/* Do read_inode() for this one at +					   mount time, don't wait for it to +					   happen later */ +#define JFFS2_INO_FLAG_USERCOMPR  2	/* User has requested a specific +					   compression type */ + + +/* These can go once we've made sure we've caught all uses without +   byteswapping */ + +typedef	uint32_t jint32_t; + +typedef uint32_t jmode_t; + +typedef uint16_t jint16_t; + +struct jffs2_unknown_node +{ +	/* All start like this */ +	jint16_t magic; +	jint16_t nodetype; +	jint32_t totlen; /* So we can skip over nodes we don't grok */ +	jint32_t hdr_crc; +}; + +struct jffs2_raw_dirent +{ +	jint16_t magic; +	jint16_t nodetype;	/* == JFFS2_NODETYPE_DIRENT */ +	jint32_t totlen; +	jint32_t hdr_crc; +	jint32_t pino; +	jint32_t version; +	jint32_t ino; /* == zero for unlink */ +	jint32_t mctime; +	uint8_t nsize; +	uint8_t type; +	uint8_t unused[2]; +	jint32_t node_crc; +	jint32_t name_crc; +	uint8_t name[0]; +}; + +/* The JFFS2 raw inode structure: Used for storage on physical media.  */ +/* The uid, gid, atime, mtime and ctime members could be longer, but +   are left like this for space efficiency. If and when people decide +   they really need them extended, it's simple enough to add support for +   a new type of raw node. +*/ +struct jffs2_raw_inode +{ +	jint16_t magic;      /* A constant magic number.  */ +	jint16_t nodetype;   /* == JFFS2_NODETYPE_INODE */ +	jint32_t totlen;     /* Total length of this node (inc data, etc.) */ +	jint32_t hdr_crc; +	jint32_t ino;        /* Inode number.  */ +	jint32_t version;    /* Version number.  */ +	jmode_t mode;       /* The file's type or mode.  */ +	jint16_t uid;        /* The file's owner.  */ +	jint16_t gid;        /* The file's group.  */ +	jint32_t isize;      /* Total resultant size of this inode (used for truncations)  */ +	jint32_t atime;      /* Last access time.  */ +	jint32_t mtime;      /* Last modification time.  */ +	jint32_t ctime;      /* Change time.  */ +	jint32_t offset;     /* Where to begin to write.  */ +	jint32_t csize;      /* (Compressed) data size */ +	jint32_t dsize;	     /* Size of the node's data. (after decompression) */ +	uint8_t compr;       /* Compression algorithm used */ +	uint8_t usercompr;   /* Compression algorithm requested by the user */ +	jint16_t flags;	     /* See JFFS2_INO_FLAG_* */ +	jint32_t data_crc;   /* CRC for the (compressed) data.  */ +	jint32_t node_crc;   /* CRC for the raw inode (excluding data)  */ +	uint8_t data[0]; +}; + +struct jffs2_raw_xattr { +	jint16_t magic; +	jint16_t nodetype;	/* = JFFS2_NODETYPE_XATTR */ +	jint32_t totlen; +	jint32_t hdr_crc; +	jint32_t xid;		/* XATTR identifier number */ +	jint32_t version; +	uint8_t xprefix; +	uint8_t name_len; +	jint16_t value_len; +	jint32_t data_crc; +	jint32_t node_crc; +	uint8_t data[0]; +} __attribute__((packed)); + +struct jffs2_raw_xref +{ +	jint16_t magic; +	jint16_t nodetype;	/* = JFFS2_NODETYPE_XREF */ +	jint32_t totlen; +	jint32_t hdr_crc; +	jint32_t ino;		/* inode number */ +	jint32_t xid;		/* XATTR identifier number */ +	jint32_t xseqno;	/* xref sequencial number */ +	jint32_t node_crc; +} __attribute__((packed)); + +struct jffs2_raw_summary +{ +	jint16_t magic; +	jint16_t nodetype; 	/* = JFFS2_NODETYPE_SUMMARY */ +	jint32_t totlen; +	jint32_t hdr_crc; +	jint32_t sum_num;	/* number of sum entries*/ +	jint32_t cln_mkr;	/* clean marker size, 0 = no cleanmarker */ +	jint32_t padded;	/* sum of the size of padding nodes */ +	jint32_t sum_crc;	/* summary information crc */ +	jint32_t node_crc; 	/* node crc */ +	jint32_t sum[0]; 	/* inode summary info */ +}; + +union jffs2_node_union +{ +	struct jffs2_raw_inode i; +	struct jffs2_raw_dirent d; +	struct jffs2_raw_xattr x; +	struct jffs2_raw_xref r; +	struct jffs2_raw_summary s; +	struct jffs2_unknown_node u; +}; + +/* Data payload for device nodes. */ +union jffs2_device_node { +	jint16_t old; +	jint32_t new; +}; + +#endif /* __LINUX_JFFS2_H__ */ diff --git a/package/mtd/src/mtd.h b/package/mtd/src/mtd-api.h index 6ce62611e..6ce62611e 100644 --- a/package/mtd/src/mtd.h +++ b/package/mtd/src/mtd-api.h diff --git a/package/mtd/src/mtd.c b/package/mtd/src/mtd.c index 85b069f81..92018c23c 100644 --- a/package/mtd/src/mtd.c +++ b/package/mtd/src/mtd.c @@ -28,6 +28,7 @@  #include <stdlib.h>  #include <stdio.h>  #include <stdint.h> +#include <signal.h>  #include <sys/ioctl.h>  #include <sys/syscall.h>  #include <fcntl.h> @@ -43,7 +44,7 @@  #include <sys/reboot.h>  #include <linux/reboot.h> -#include "mtd.h" +#include "mtd-api.h"  #define TRX_MAGIC       0x30524448      /* "HDR0" */  #define BUFSIZE (16 * 1024) @@ -51,6 +52,8 @@  #define DEBUG +#define JFFS2_DEFAULT_DIR	"tmp" +  #define SYSTYPE_UNKNOWN     0  #define SYSTYPE_BROADCOM    1  /* to be continued */ @@ -63,16 +66,86 @@ struct trx_header {  	uint32_t offsets[3];    /* Offsets of partitions from start of header */  }; -char buf[BUFSIZE]; -int buflen; +static char buf[BUFSIZE]; +static char *imagefile; +static int buflen;  int quiet; +int mtdsize = 0; +int erasesize = 0; + +int mtd_open(const char *mtd) +{ +	FILE *fp; +	char dev[PATH_MAX]; +	int i; +	int ret; +	int flags = O_RDWR | O_SYNC; + +	if ((fp = fopen("/proc/mtd", "r"))) { +		while (fgets(dev, sizeof(dev), fp)) { +			if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) { +				snprintf(dev, sizeof(dev), "/dev/mtd/%d", i); +				if ((ret=open(dev, flags))<0) { +					snprintf(dev, sizeof(dev), "/dev/mtd%d", i); +					ret=open(dev, flags); +				} +				fclose(fp); +				return ret; +			} +		} +		fclose(fp); +	} + +	return open(mtd, flags); +} + +int mtd_check_open(const char *mtd) +{ +	struct mtd_info_user mtdInfo; +	int fd; + +	fd = mtd_open(mtd); +	if(fd < 0) { +		fprintf(stderr, "Could not open mtd device: %s\n", mtd); +		return 0; +	} + +	if(ioctl(fd, MEMGETINFO, &mtdInfo)) { +		fprintf(stderr, "Could not get MTD device info from %s\n", mtd); +		close(fd); +		return 0; +	} +	mtdsize = mtdInfo.size; +	erasesize = mtdInfo.erasesize; + +	return fd; +} + +int mtd_erase_block(int fd, int offset) +{ +	struct erase_info_user mtdEraseInfo; + +	mtdEraseInfo.start = offset; +	mtdEraseInfo.length = erasesize; +	ioctl(fd, MEMUNLOCK, &mtdEraseInfo); +	if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0) { +		fprintf(stderr, "Erasing mtd failed.\n"); +		exit(1); +	} +} + +int mtd_write_buffer(int fd, char *buf, int offset, int length) +{ +	lseek(fd, offset, SEEK_SET); +	write(fd, buf, length); +} +  #ifdef target_brcm -int +static int  image_check_brcm(int imagefd, const char *mtd)  {  	struct trx_header *trx = (struct trx_header *) buf; -	struct mtd_info_user mtdInfo;  	int fd;  	if (strcmp(mtd, "linux") != 0) @@ -94,18 +167,13 @@ image_check_brcm(int imagefd, const char *mtd)  	}  	/* check if image fits to mtd device */ -	fd = mtd_open(mtd, O_RDWR | O_SYNC); +	fd = mtd_check_open(mtd);  	if(fd < 0) {  		fprintf(stderr, "Could not open mtd device: %s\n", mtd);  		exit(1);  	} -	if(ioctl(fd, MEMGETINFO, &mtdInfo)) { -		fprintf(stderr, "Could not get MTD device info from %s\n", mtd); -		exit(1); -	} -		 -	if(mtdInfo.size < trx->len) { +	if(mtdsize < trx->len) {  		fprintf(stderr, "Image too big for partition: %s\n", mtd);  		close(fd);  		return 0; @@ -116,7 +184,7 @@ image_check_brcm(int imagefd, const char *mtd)  }  #endif /* target_brcm */ -int +static int  image_check(int imagefd, const char *mtd)  {  	int fd, systype; @@ -129,48 +197,35 @@ image_check(int imagefd, const char *mtd)  #endif  } -int mtd_check(char *mtd) +static int mtd_check(const char *mtd)  { -	struct mtd_info_user mtdInfo;  	int fd; -	fd = mtd_open(mtd, O_RDWR | O_SYNC); -	if(fd < 0) { -		fprintf(stderr, "Could not open mtd device: %s\n", mtd); +	fd = mtd_check_open(mtd); +	if (!fd)  		return 0; -	} - -	if(ioctl(fd, MEMGETINFO, &mtdInfo)) { -		fprintf(stderr, "Could not get MTD device info from %s\n", mtd); -		close(fd); -		return 0; -	}  	close(fd);  	return 1;  } -int +static int  mtd_unlock(const char *mtd)  {  	int fd; -	struct mtd_info_user mtdInfo;  	struct erase_info_user mtdLockInfo; -	fd = mtd_open(mtd, O_RDWR | O_SYNC); -	if(fd < 0) { +	fd = mtd_check_open(mtd); +	if(fd <= 0) {  		fprintf(stderr, "Could not open mtd device: %s\n", mtd);  		exit(1);  	} -	if(ioctl(fd, MEMGETINFO, &mtdInfo)) { -		fprintf(stderr, "Could not get MTD device info from %s\n", mtd); -		close(fd); -		exit(1); -	} +	if (quiet < 2)  +		fprintf(stderr, "Unlocking %s ...\n", mtd);  	mtdLockInfo.start = 0; -	mtdLockInfo.length = mtdInfo.size; +	mtdLockInfo.length = mtdsize;  	if(ioctl(fd, MEMUNLOCK, &mtdLockInfo)) {  		close(fd);  		return 0; @@ -180,56 +235,26 @@ mtd_unlock(const char *mtd)  	return 0;  } -int -mtd_open(const char *mtd, int flags) -{ -	FILE *fp; -	char dev[PATH_MAX]; -	int i; -	int ret; - -	if ((fp = fopen("/proc/mtd", "r"))) { -		while (fgets(dev, sizeof(dev), fp)) { -			if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) { -				snprintf(dev, sizeof(dev), "/dev/mtd/%d", i); -				if ((ret=open(dev, flags))<0) { -					snprintf(dev, sizeof(dev), "/dev/mtd%d", i); -					ret=open(dev, flags); -				} -				fclose(fp); -				return ret; -			} -		} -		fclose(fp); -	} - -	return open(mtd, flags); -} - -int +static int  mtd_erase(const char *mtd)  {  	int fd; -	struct mtd_info_user mtdInfo;  	struct erase_info_user mtdEraseInfo; -	fd = mtd_open(mtd, O_RDWR | O_SYNC); -	if(fd < 0) { -		fprintf(stderr, "Could not open mtd device: %s\n", mtd); -		exit(1); -	} +	if (quiet < 2) +		fprintf(stderr, "Erasing %s ...\n", mtd); -	if(ioctl(fd, MEMGETINFO, &mtdInfo)) { -		fprintf(stderr, "Could not get MTD device info from %s\n", mtd); -		close(fd); +	fd = mtd_check_open(mtd); +	if(fd <= 0) { +		fprintf(stderr, "Could not open mtd device: %s\n", mtd);  		exit(1);  	} -	mtdEraseInfo.length = mtdInfo.erasesize; +	mtdEraseInfo.length = erasesize;  	for (mtdEraseInfo.start = 0; -		 mtdEraseInfo.start < mtdInfo.size; -		 mtdEraseInfo.start += mtdInfo.erasesize) { +		 mtdEraseInfo.start < mtdsize; +		 mtdEraseInfo.start += erasesize) {  		ioctl(fd, MEMUNLOCK, &mtdEraseInfo);  		if(ioctl(fd, MEMERASE, &mtdEraseInfo)) @@ -241,46 +266,50 @@ mtd_erase(const char *mtd)  } -int +static int  mtd_refresh(const char *mtd)  {  	int fd; -	fd = mtd_open(mtd, O_RDWR | O_SYNC); -	if(fd < 0) { +	if (quiet < 2) +		fprintf(stderr, "Refreshing mtd partition %s ... ", mtd); + +	fd = mtd_check_open(mtd); +	if(fd <= 0) {  		fprintf(stderr, "Could not open mtd device: %s\n", mtd);  		exit(1);  	} +  	if (ioctl(fd, MTDREFRESH, NULL)) {  		fprintf(stderr, "Failed to refresh the MTD device\n");  		close(fd);  		exit(1);  	}  	close(fd); + +	if (quiet < 2) +		fprintf(stderr, "\n"); +  	return 0;  } -int +static int  mtd_write(int imagefd, const char *mtd)  {  	int fd, i, result;  	size_t r, w, e; -	struct mtd_info_user mtdInfo;  	struct erase_info_user mtdEraseInfo;  	int ret = 0; -	fd = mtd_open(mtd, O_RDWR | O_SYNC); +	fd = mtd_check_open(mtd);  	if(fd < 0) {  		fprintf(stderr, "Could not open mtd device: %s\n", mtd);  		exit(1);  	} - -	if(ioctl(fd, MEMGETINFO, &mtdInfo)) { -		fprintf(stderr, "Could not get MTD device info from %s\n", mtd); -		close(fd); -		exit(1); -	} +	if (quiet < 2) +		fprintf(stderr, "Writing from %s to %s ... ", imagefile, mtd); +  	r = w = e = 0;  	if (!quiet)  		fprintf(stderr, " [ ]"); @@ -296,17 +325,13 @@ mtd_write(int imagefd, const char *mtd)  		/* need to erase the next block before writing data to it */  		while (w > e) { -			mtdEraseInfo.start = e; -			mtdEraseInfo.length = mtdInfo.erasesize; -  			if (!quiet)  				fprintf(stderr, "\b\b\b[e]"); + +			mtd_erase_block(fd, e); +  			/* erase the chunk */ -			if (ioctl (fd,MEMERASE,&mtdEraseInfo) < 0) { -				fprintf(stderr, "Erasing mtd failed: %s\n", mtd); -				exit(1); -			} -			e += mtdInfo.erasesize; +			e += erasesize;  		}  		if (!quiet) @@ -327,11 +352,14 @@ mtd_write(int imagefd, const char *mtd)  	if (!quiet)  		fprintf(stderr, "\b\b\b\b"); +	if (quiet < 2) +		fprintf(stderr, "\n"); +  	close(fd);  	return 0;  } -void usage(void) +static void usage(void)  {  	fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <device>\n\n"  	"The device is in the format of mtdX (eg: mtd4) or its label.\n" @@ -340,26 +368,44 @@ void usage(void)  	"        refresh                 refresh mtd partition\n"  	"        erase                   erase all data on device\n"  	"        write <imagefile>|-     write <imagefile> (use - for stdin) to device\n" +	"        jffs2write <file>       append <file> to the jffs2 partition on the device\n"  	"Following options are available:\n"  	"        -q                      quiet mode (once: no [w] on writing,\n"  	"                                           twice: no status messages)\n"  	"        -r                      reboot after successful command\n"  	"        -f                      force write without trx checks\n" -	"        -e <device>             erase <device> before executing the command\n\n" +	"        -e <device>             erase <device> before executing the command\n" +	"        -d <name>               directory for jffs2write, defaults to \"tmp\"\n" +	"\n"  	"Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n"  	"         mtd -r write linux.trx linux\n\n");  	exit(1);  } +static void do_reboot(void) +{ +	fprintf(stderr, "Rebooting ...\n"); +	fflush(stderr); + +	/* try regular reboot method first */ +	system("/sbin/reboot"); +	sleep(2); + +	/* if we're still alive at this point, force the kernel to reboot */ +	syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL); +} +  int main (int argc, char **argv)  {  	int ch, i, boot, unlock, imagefd, force, unlocked; -	char *erase[MAX_ARGS], *device, *imagefile; +	char *erase[MAX_ARGS], *device; +	char *jffs2dir = JFFS2_DEFAULT_DIR;  	enum {  		CMD_ERASE,  		CMD_WRITE,  		CMD_UNLOCK, -		CMD_REFRESH +		CMD_REFRESH, +		CMD_JFFS2WRITE  	} cmd;  	erase[0] = NULL; @@ -368,7 +414,7 @@ int main (int argc, char **argv)  	buflen = 0;  	quiet = 0; -	while ((ch = getopt(argc, argv, "frqe:")) != -1) +	while ((ch = getopt(argc, argv, "frqe:d:")) != -1)  		switch (ch) {  			case 'f':  				force = 1; @@ -387,7 +433,9 @@ int main (int argc, char **argv)  				erase[i++] = optarg;  				erase[i] = NULL;  				break; -			 +			case 'd': +				jffs2dir = optarg; +				break;  			case '?':  			default:  				usage(); @@ -434,6 +482,15 @@ int main (int argc, char **argv)  				exit(1);  			}  		} +	} else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) { +		cmd = CMD_JFFS2WRITE; +		device = argv[2]; +	 +		imagefile = argv[1]; +		if (!mtd_check(device)) { +			fprintf(stderr, "Can't open device for writing!\n"); +			exit(1); +		}  	} else {  		usage();  	} @@ -443,53 +500,43 @@ int main (int argc, char **argv)  	i = 0;  	unlocked = 0;  	while (erase[i] != NULL) { -		if (quiet < 2) -			fprintf(stderr, "Unlocking %s ...\n", erase[i]);  		mtd_unlock(erase[i]); -		if (quiet < 2) -			fprintf(stderr, "Erasing %s ...\n", erase[i]);  		mtd_erase(erase[i]);  		if (strcmp(erase[i], device) == 0)  			unlocked = 1;  		i++;  	} -	if (!unlocked) { -		if (quiet < 2)  -			fprintf(stderr, "Unlocking %s ...\n", device); -		mtd_unlock(device); -	}  	switch (cmd) {  		case CMD_UNLOCK: +			if (!unlocked) +				mtd_unlock(device);  			break;  		case CMD_ERASE: -			if (quiet < 2) -				fprintf(stderr, "Erasing %s ...\n", device); +			if (!unlocked) +				mtd_unlock(device);  			mtd_erase(device);  			break;  		case CMD_WRITE: -			if (quiet < 2) -				fprintf(stderr, "Writing from %s to %s ... ", imagefile, device); +			if (!unlocked) +				mtd_unlock(device);  			mtd_write(imagefd, device); -			if (quiet < 2) -				fprintf(stderr, "\n"); +			break; +		case CMD_JFFS2WRITE: +			if (!unlocked) +				mtd_unlock(device); +			mtd_write_jffs2(device, imagefile, jffs2dir);  			break;  		case CMD_REFRESH: -			if (quiet < 2) -				fprintf(stderr, "Refreshing mtd partition %s ... ");  			mtd_refresh(device); -			if (quiet < 2) -				fprintf(stderr, "\n");  			break;  	}  	sync(); -	if (boot) { -		fprintf(stderr, "Rebooting ...\n"); -		fflush(stderr); -		syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL); -	} +	if (boot) +		do_reboot(); +  	return 0;  }  | 
