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 * 2004 University of Szeged, Hungary + * 2005 KaiGai Kohei * * 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 #include #include +#include +#include #include #define crc32 __complete_crap #include @@ -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) {