diff -rpNU3 mtd-20051127.xattr/util/mkfs.jffs2.1 mtd-20051127.mkfs/util/mkfs.jffs2.1
--- mtd-20051127.xattr/util/mkfs.jffs2.1	2005-11-27 00:00:13.000000000 -0500
+++ mtd-20051127.mkfs/util/mkfs.jffs2.1	2005-11-27 00:00:36.000000000 -0500
@@ -49,6 +49,15 @@ mkfs.jffs2 \- Create a JFFS2 file system
 .B -P,--squash-perms
 ]
 [
+.B --with-xattr
+]
+[
+.B --with-selinux
+]
+[
+.B --with-posix-acl
+]
+[
 .B -m,--compression-mode=MODE
 ]
 [
@@ -178,6 +187,15 @@ Squash owners making all files be owned 
 .B -P, --squash-perms
 Squash permissions, removing write permission for \'group\' and \'other\'.
 .TP
+.B --with-xattr
+Enables xattr, stuff all xattr entries into jffs2 image file.
+.TP
+.B --with-selinux
+Enables xattr, stuff only SELinux Labels into jffs2 image file.
+.TP
+.B --with-posix-acl
+Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
+.TP
 .B -m, --compression-mode=MODE
 Set the default compression mode. The default mode is 
 .B priority 
diff -rpNU3 mtd-20051127.xattr/util/mkfs.jffs2.c mtd-20051127.mkfs/util/mkfs.jffs2.c
--- mtd-20051127.xattr/util/mkfs.jffs2.c	2005-11-27 00:00:13.000000000 -0500
+++ mtd-20051127.mkfs/util/mkfs.jffs2.c	2005-11-27 00:00:36.000000000 -0500
@@ -7,6 +7,7 @@
  *           2002 Axis Communications AB
  *           2001, 2002 Erik Andersen <andersen@codepoet.org>
  *           2004 University of Szeged, Hungary
+ *           2005 KaiGai Kohei <kaigai@ak.jp.nec.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -63,6 +64,8 @@
 #include <ctype.h>
 #include <time.h>
 #include <getopt.h>
+#include <attr/xattr.h>
+#include <sys/acl.h>
 #include <byteswap.h>
 #define crc32 __complete_crap
 #include <zlib.h>
@@ -1018,6 +1021,282 @@ static void write_special_file(struct fi
 	padword();
 }
 
+#include "../fs/jffs2/acl.h"
+#define XATTR_BUFFER_SIZE	65536
+typedef struct {
+	uint16_t		e_tag;
+	uint16_t		e_perm;
+	uint32_t		e_id;
+} posix_acl_xattr_entry;
+
+typedef struct {
+	uint32_t		a_version;
+	posix_acl_xattr_entry	a_entries[0];
+} posix_acl_xattr_header;
+
+typedef struct xattr_entry {
+	struct xattr_entry *next;
+	uint32_t xid;
+	int xprefix;
+	char *xname;
+	char *xvalue;
+	int name_len;
+	int value_len;
+} xattr_entry_t;
+
+#define le16_to_cpu(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define le32_to_cpu(x)	(__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+
+static uint32_t enable_xattr = 0;
+static uint32_t xseqno = 0;
+
+static struct {
+	int xprefix;
+	char *string;
+	int strict;
+} xprefix_tbl[] = {
+	{ JFFS2_XPREFIX_USER,		"user.", 			0 },
+	{ JFFS2_XPREFIX_SECURITY,	"security.",			0 },
+	{ JFFS2_XPREFIX_ACL_ACCESS,	"system.posix_acl_access",	1 },
+	{ JFFS2_XPREFIX_ACL_DEFAULT,	"system.posix_acl_default",	1 },
+	{ JFFS2_XPREFIX_TRUSTED,	"trusted.",			0 },
+	{ 0,				NULL,				0 }
+};
+
+static void write_xattr_normal(xattr_entry_t *xe)
+{
+	struct jffs2_raw_xattr rx;
+
+	memset(&rx, 0, sizeof(rx));
+	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
+	rx.totlen = cpu_to_je32(sizeof(rx) + xe->name_len + 1 + xe->value_len);
+	rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
+
+	rx.xid = cpu_to_je32(xe->xid);
+	rx.xprefix = xe->xprefix;
+	rx.name_len = xe->name_len;
+	rx.value_len = cpu_to_je16(xe->value_len);
+	rx.data_crc = cpu_to_je32(crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
+	rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(rx) - 8));
+
+	pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len);
+	full_write(out_fd, &rx, sizeof(rx));
+	full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len);
+	padword();
+}
+
+static void write_xattr_acl(xattr_entry_t *xe)
+{
+	struct jffs2_raw_xattr rx;
+	posix_acl_xattr_header *header;
+	posix_acl_xattr_entry *entry, *end;
+	jffs2_acl_header *jheader;
+	jffs2_acl_entry *jent;
+	jffs2_acl_entry_short *jent_s;
+	char buffer[XATTR_BUFFER_SIZE];
+	int i, offset = 0;
+
+	header = (posix_acl_xattr_header *)xe->xvalue;
+	entry  = header->a_entries;
+	end = (posix_acl_xattr_entry *)(xe->xvalue + xe->value_len);
+
+	buffer[offset++] = '\0';	/* termination char of xname */
+	jheader = (jffs2_acl_header *)(buffer + offset);
+	jheader->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
+	offset += sizeof(jffs2_acl_header);
+
+	for (i=0; i < xe->value_len; i+=sizeof(unsigned long)) {
+		unsigned long *value = (unsigned long *)(xe->xvalue + i);
+		printf(" %08lx", *value);
+	}
+	putchar('\n');
+
+	while (entry < end) {
+		switch (le16_to_cpu(entry->e_tag)) {
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_MASK:
+		case ACL_OTHER:
+			jent_s = (jffs2_acl_entry_short *)(buffer + offset);
+			offset += sizeof(jffs2_acl_entry_short);
+			jent_s->e_tag = cpu_to_je16(le16_to_cpu(entry->e_tag));
+			jent_s->e_perm = cpu_to_je16(le16_to_cpu(entry->e_perm));
+			break;
+		case ACL_USER:
+		case ACL_GROUP:
+			jent = (jffs2_acl_entry *)(buffer + offset);
+			offset += sizeof(jffs2_acl_entry);
+			jent->e_tag = cpu_to_je16(le16_to_cpu(entry->e_tag));
+			jent->e_perm = cpu_to_je16(le16_to_cpu(entry->e_perm));
+			jent->e_id = cpu_to_je32(le32_to_cpu(entry->e_id));
+			break;
+		default:
+			printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(entry->e_tag));
+		}
+		entry++;
+	}
+	
+	memset(&rx, 0, sizeof(rx));
+	rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
+	rx.totlen = cpu_to_je32(sizeof(rx) + 1 + offset);
+	rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
+
+	rx.xid = cpu_to_je32(xe->xid);
+	rx.xprefix = xe->xprefix;
+	rx.name_len = 0;
+	rx.value_len = cpu_to_je16(offset - 1);
+	rx.data_crc = cpu_to_je32(crc32(0, buffer, offset));
+	rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(rx) - 8));
+
+	pad_block_if_less_than(sizeof(rx) + offset);
+	full_write(out_fd, &rx, sizeof(rx));
+	full_write(out_fd, buffer, offset);
+	padword();
+
+	for (i=0; i < offset; i+= sizeof(unsigned long)) {
+		unsigned long *value = (unsigned long *)(buffer + 1 + i);
+		printf(" %08lx", *value);
+	}
+	putchar('\n');
+	printf("wrote-a: xid = %u xprefix = %d dlen = %d hcrc = %08x dcrc = %08x\n", xe->xid, xe->xprefix, offset, je32_to_cpu(rx.node_crc), je32_to_cpu(rx.data_crc));
+}
+
+static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+	xattr_entry_t *xe;
+	int name_len;
+
+	name_len = strlen(xname);
+	xe = xcalloc(1, sizeof(struct xattr_entry) + name_len + 1 + value_len);
+	xe->xid = ++xseqno;
+	xe->xprefix = xprefix;
+	xe->xname = (char *)(xe + 1);
+	xe->xvalue = xe->xname + name_len + 1;
+	xe->name_len = name_len;
+	xe->value_len = value_len;
+	strcpy(xe->xname, xname);
+	memcpy(xe->xvalue, xvalue, value_len);
+
+	switch (xprefix) {
+	case JFFS2_XPREFIX_ACL_ACCESS:
+	case JFFS2_XPREFIX_ACL_DEFAULT:
+		write_xattr_acl(xe);
+		break;
+	default:
+		write_xattr_normal(xe);
+		break;
+	}
+	return xe;
+}
+
+#define XATTRENTRY_HASHSIZE	37
+static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+	static xattr_entry_t **xentry_hash = NULL;
+	xattr_entry_t *xe;
+	int name_len, index;
+
+	if ((enable_xattr & (1 << xprefix)) == 0)
+		return NULL;
+
+	/* find or create xattr entry */
+	if (!xentry_hash)
+		xentry_hash = xcalloc(1, sizeof(struct xattr_entry *) * XATTRENTRY_HASHSIZE);
+
+	name_len = strlen(xname) + 1;
+	index = (crc32(0, xname, name_len) ^ crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE;
+	for (xe = xentry_hash[index]; xe; xe = xe->next) {
+		if (xe->xprefix == xprefix
+		    && xe->value_len == value_len
+		    && !strcmp(xe->xname, xname)
+		    && !memcmp(xe->xvalue, xvalue, value_len))
+			break;
+	}
+	if (!xe) {
+		xe = create_xattr_entry(xprefix, xname, xvalue, value_len);
+		xe->next = xentry_hash[index];
+		xentry_hash[index] = xe;
+	}
+
+	return xe;
+}
+
+static void write_xattr_entry(struct filesystem_entry *e)
+{
+	struct jffs2_raw_xref ref;
+	struct xattr_entry *xe;
+	char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE];
+	char *xname;
+	int list_sz, offset, name_len, value_len;
+
+	if (!enable_xattr)
+		return;
+
+	list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE);
+	if (list_sz < 0) {
+		if (verbose)
+			printf("llistxattr('%s') = %d : %s\n",
+			       e->hostname, errno, strerror(errno));
+		return;
+	}
+
+	for (offset = 0; offset < list_sz; offset += name_len) {
+		int i, xprefix, prefix_len;
+		char *prefix_str;
+
+		xname = xlist + offset;
+		name_len = strlen(xname) + 1;
+
+		for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) {
+			prefix_str = xprefix_tbl[i].string;
+			prefix_len = strlen(prefix_str);
+
+			if (xprefix_tbl[i].strict) {
+				if (!strcmp(xname, prefix_str))
+					break;
+			} else {
+				if (!strncmp(xname, prefix_str, prefix_len))
+					break;
+			}
+		}
+		if (!xprefix) {
+			if (verbose)
+				printf("%s : XATTR '%s' was not supported.\n", e->hostname, xname);
+			continue;
+		}
+		value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE);
+		if (value_len < 0) {
+			if (verbose)
+				printf("lgetxattr('%s', '%s') = %d : %s\n",
+				       e->hostname, xname, errno, strerror(errno));
+			continue;
+		}
+		xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len);
+		if (!xe) {
+			if (verbose)
+				printf("%s : XATTR '%s' was ignored.\n",
+				       e->hostname, xname);
+			continue;
+		}
+
+		memset(&ref, 0, sizeof(ref));
+		ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+		ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
+		ref.totlen = cpu_to_je32(sizeof(ref));
+		ref.hdr_crc = cpu_to_je32(crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4));
+		ref.seqno = cpu_to_je32(++xseqno);
+		ref.ino = cpu_to_je32(e->sb.st_ino);
+		ref.xid = cpu_to_je32(xe->xid);
+		ref.node_crc = cpu_to_je32(crc32(0, &ref, sizeof(ref) - 4));
+
+		pad_block_if_less_than(sizeof(ref));
+		full_write(out_fd, &ref, sizeof(ref));
+		padword();
+	}
+}
+
 static void recursive_populate_directory(struct filesystem_entry *dir)
 {
 	struct filesystem_entry *e;
@@ -1025,6 +1304,8 @@ static void recursive_populate_directory
 	if (verbose) {
 		printf("%s\n", dir->fullname);
 	}
+	write_xattr_entry(dir);		/* for '/' */
+
 	e = dir->files;
 	while (e) {
 
@@ -1037,6 +1318,7 @@ static void recursive_populate_directory
 							e->name);
 				}
 				write_pipe(e);
+				write_xattr_entry(e);
 				break;
 			case S_IFSOCK:
 				if (verbose) {
@@ -1045,6 +1327,7 @@ static void recursive_populate_directory
 							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
 				}
 				write_pipe(e);
+				write_xattr_entry(e);
 				break;
 			case S_IFIFO:
 				if (verbose) {
@@ -1053,6 +1336,7 @@ static void recursive_populate_directory
 							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
 				}
 				write_pipe(e);
+				write_xattr_entry(e);
 				break;
 			case S_IFCHR:
 				if (verbose) {
@@ -1062,6 +1346,7 @@ static void recursive_populate_directory
 							(int) e->sb.st_gid, e->name);
 				}
 				write_special_file(e);
+				write_xattr_entry(e);
 				break;
 			case S_IFBLK:
 				if (verbose) {
@@ -1071,6 +1356,7 @@ static void recursive_populate_directory
 							(int) e->sb.st_gid, e->name);
 				}
 				write_special_file(e);
+				write_xattr_entry(e);
 				break;
 			case S_IFLNK:
 				if (verbose) {
@@ -1080,6 +1366,7 @@ static void recursive_populate_directory
 							e->link);
 				}
 				write_symlink(e);
+				write_xattr_entry(e);
 				break;
 			case S_IFREG:
 				if (verbose) {
@@ -1088,6 +1375,7 @@ static void recursive_populate_directory
 							(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
 				}
 				write_regular_file(e);
+				write_xattr_entry(e);
 				break;
 			default:
 				error_msg("Unknown mode %o for %s", e->sb.st_mode,
@@ -1172,6 +1460,9 @@ static struct option long_options[] = {
 	{"test-compression", 0, NULL, 't'},
 	{"compressor-priority", 1, NULL, 'y'},
 	{"incremental", 1, NULL, 'i'},
+	{"with-xattr", 0, NULL, 1000 },
+	{"with-selinux", 0, NULL, 1001 },
+	{"with-posix-acl", 0, NULL, 1002 },
 	{NULL, 0, NULL, 0}
 };
 
@@ -1204,6 +1495,9 @@ static char *helptext =
 	"  -q, --squash            Squash permissions and owners making all files be owned by root\n"
 	"  -U, --squash-uids       Squash owners making all files be owned by root\n"
 	"  -P, --squash-perms      Squash permissions on all files\n"
+	"      --with-xattr        stuff all xattr entries into image\n"
+	"      --with-selinux      stuff only SELinux Labels into jffs2 image\n"
+	"      --with-posix-acl    stuff only POSIX ACL entries into jffs2 image\n"
 	"  -h, --help              Display this help text\n"
 	"  -v, --verbose           Verbose operation\n"
 	"  -V, --version           Display version information\n"
@@ -1531,6 +1825,20 @@ int main(int argc, char **argv)
 					perror_msg_and_die("cannot open (incremental) file");
 				}
 				break;
+			case 1000:	/* --with-xattr  */
+				enable_xattr |= (1 << JFFS2_XPREFIX_USER)
+						| (1 << JFFS2_XPREFIX_SECURITY)
+						| (1 << JFFS2_XPREFIX_ACL_ACCESS)
+						| (1 << JFFS2_XPREFIX_ACL_DEFAULT)
+						| (1 << JFFS2_XPREFIX_TRUSTED);
+				break;
+			case 1001:	/*  --with-selinux  */
+				enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY);
+				break;
+			case 1002:	/*  --with-posix-acl  */
+				enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS)
+						| (1 << JFFS2_XPREFIX_ACL_DEFAULT);
+				break;
 		}
 	}
 	if (out_fd == -1) {
