diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2015-11-12 10:31:27 +0100 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2015-11-12 10:50:04 +0100 |
commit | 50044efbd6e713e86f705a60eddab0c034dffeba (patch) | |
tree | ab36a5fda13e1bae857a7b1f6b2ab37127a4cdf8 | |
parent | 978494f76e110154a3035cb1cdbe92965c5552ce (diff) |
mkfs.ubifs: Add extended attribute support
This adds extended attribute support to mkfs.ubifs. When creating
an image from a directory tree the existing extended attributes are
added to the UBIFS image.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r-- | ubifs-utils/mkfs.ubifs/key.h | 18 | ||||
-rw-r--r-- | ubifs-utils/mkfs.ubifs/mkfs.ubifs.c | 205 | ||||
-rw-r--r-- | ubifs-utils/mkfs.ubifs/ubifs.h | 9 |
3 files changed, 205 insertions, 27 deletions
diff --git a/ubifs-utils/mkfs.ubifs/key.h b/ubifs-utils/mkfs.ubifs/key.h index d3a02d4..39379fd 100644 --- a/ubifs-utils/mkfs.ubifs/key.h +++ b/ubifs-utils/mkfs.ubifs/key.h @@ -119,6 +119,24 @@ static inline void dent_key_init(const struct ubifs_info *c, } /** + * xent_key_init - initialize extended attribute entry key. + * @c: UBIFS file-system description object + * @key: key to initialize + * @inum: host inode number + * @nm: extended attribute entry name and length + */ +static inline void xent_key_init(const struct ubifs_info *c, + union ubifs_key *key, ino_t inum, + const struct qstr *nm) +{ + uint32_t hash = c->key_hash(nm->name, nm->len); + + ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); + key->u32[0] = inum; + key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS); +} + +/** * data_key_init - initialize data key. * @c: UBIFS file-system description object * @key: key to initialize diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c index a99c613..30cd10c 100644 --- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c +++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c @@ -25,6 +25,10 @@ #include "mkfs.ubifs.h" #include <crc32.h> #include "common.h" +#include <sys/types.h> +#ifndef WITHOUT_XATTR +#include <attr/xattr.h> +#endif /* Size (prime number) of hash table for link counting */ #define HASH_TABLE_SIZE 10099 @@ -980,20 +984,170 @@ static int add_node(union ubifs_key *key, char *name, void *node, int len) return 0; } +#ifdef WITHOUT_XATTR +static inline int inode_add_xattr(struct ubifs_ino_node *host_ino, + const char *path_name, struct stat *st, ino_t inum) +{ + (void)host_ino; + (void)path_name; + (void)st; + (void)inum; + + return 0; +} +#else +static int add_xattr(struct stat *st, ino_t inum, const void *data, + unsigned int data_len, struct qstr *nm) +{ + struct ubifs_ino_node *ino; + struct ubifs_dent_node *xent; + union ubifs_key xkey, nkey; + int len, ret; + + xent = xzalloc(sizeof(*xent) + nm->len + 1); + ino = xzalloc(sizeof(*ino) + data_len); + + xent_key_init(c, &xkey, inum, nm); + xent->ch.node_type = UBIFS_XENT_NODE; + key_write(&xkey, &xent->key); + + len = UBIFS_XENT_NODE_SZ + nm->len + 1; + + xent->ch.len = len; + xent->padding1 = 0; + xent->type = UBIFS_ITYPE_DIR; + xent->nlen = cpu_to_le16(nm->len); + + memcpy(xent->name, nm->name, nm->len + 1); + + inum = ++c->highest_inum; + creat_sqnum = ++c->max_sqnum; + + xent->inum = cpu_to_le64(inum); + + ret = add_node(&xkey, nm->name, xent, len); + if (ret) + goto out; + + ino->creat_sqnum = cpu_to_le64(creat_sqnum); + ino->nlink = cpu_to_le32(st->st_nlink); + /* + * The time fields are updated assuming the default time granularity + * of 1 second. To support finer granularities, utime() would be needed. + */ + ino->atime_sec = cpu_to_le64(st->st_atime); + ino->ctime_sec = cpu_to_le64(st->st_ctime); + ino->mtime_sec = cpu_to_le64(st->st_mtime); + ino->atime_nsec = 0; + ino->ctime_nsec = 0; + ino->mtime_nsec = 0; + ino->uid = cpu_to_le32(st->st_uid); + ino->gid = cpu_to_le32(st->st_gid); + ino->compr_type = cpu_to_le16(c->default_compr); + ino->ch.node_type = UBIFS_INO_NODE; + + ino_key_init(&nkey, inum); + key_write(&nkey, &ino->key); + + ino->size = cpu_to_le64(data_len); + ino->mode = cpu_to_le32(S_IFREG); + ino->data_len = cpu_to_le32(data_len); + ino->flags = cpu_to_le32(UBIFS_XATTR_FL); + + if (data_len) + memcpy(&ino->data, data, data_len); + + ret = add_node(&nkey, nm->name, ino, UBIFS_INO_NODE_SZ + data_len) ; + +out: + free(xent); + free(ino); + + return ret; +} + +static int inode_add_xattr(struct ubifs_ino_node *host_ino, + const char *path_name, struct stat *st, ino_t inum) +{ + int ret; + struct qstr nm; + void *buf = NULL; + ssize_t len; + ssize_t pos = 0; + + len = llistxattr(path_name, NULL, 0); + if (len < 0) { + if (errno == ENOENT) + return 0; + + sys_err_msg("llistxattr failed on %s", path_name); + + return len; + } + + if (len == 0) + goto noxattr; + + buf = xmalloc(len); + + len = llistxattr(path_name, buf, len); + if (len < 0) { + sys_err_msg("llistxattr failed on %s", path_name); + goto out_free; + } + + while (pos < len) { + char attrbuf[1024] = { }; + char *name; + ssize_t attrsize; + + name = buf + pos; + pos += strlen(name) + 1; + + attrsize = lgetxattr(path_name, name, attrbuf, sizeof(attrbuf) - 1); + if (attrsize < 0) { + sys_err_msg("lgetxattr failed on %s", path_name); + goto out_free; + } + + nm.name = name; + nm.len = strlen(name); + + host_ino->xattr_cnt++; + host_ino->xattr_size += CALC_DENT_SIZE(nm.len); + host_ino->xattr_size += CALC_XATTR_BYTES(attrsize); + host_ino->xattr_names += nm.len; + + ret = add_xattr(st, inum, attrbuf, attrsize, &nm); + if (ret < 0) + goto out_free; + } + +noxattr: + free(buf); + return 0; + +out_free: + free(buf); + + return -1; +} +#endif + /** - * add_inode_with_data - write an inode. + * add_inode - write an inode. * @st: stat information of source inode * @inum: target inode number * @data: inode data (for special inodes e.g. symlink path etc) * @data_len: inode data length * @flags: source inode flags */ -static int add_inode_with_data(struct stat *st, ino_t inum, void *data, - unsigned int data_len, int flags) +static int add_inode(struct stat *st, ino_t inum, void *data, + unsigned int data_len, int flags, const char *xattr_path) { struct ubifs_ino_node *ino = node_buf; union ubifs_key key; - int len, use_flags = 0; + int len, use_flags = 0, ret; if (c->default_compr != UBIFS_COMPR_NONE) use_flags |= UBIFS_COMPR_FL; @@ -1037,18 +1191,13 @@ static int add_inode_with_data(struct stat *st, ino_t inum, void *data, len = UBIFS_INO_NODE_SZ + data_len; - return add_node(&key, NULL, ino, len); -} + if (xattr_path) { + ret = inode_add_xattr(ino, xattr_path, st, inum); + if (ret < 0) + return ret; + } -/** - * add_inode - write an inode. - * @st: stat information of source inode - * @inum: target inode number - * @flags: source inode flags - */ -static int add_inode(struct stat *st, ino_t inum, int flags) -{ - return add_inode_with_data(st, inum, NULL, 0, flags); + return add_node(&key, NULL, ino, len); } /** @@ -1064,8 +1213,8 @@ static int add_inode(struct stat *st, ino_t inum, int flags) * is being created does not exist at the host file system, but is defined by * the device table. */ -static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink, - struct stat *st) +static int add_dir_inode(const char *path_name, DIR *dir, ino_t inum, loff_t size, + unsigned int nlink, struct stat *st) { int fd, flags = 0; @@ -1080,7 +1229,7 @@ static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink, flags = 0; } - return add_inode(st, inum, flags); + return add_inode(st, inum, NULL, 0, flags, path_name); } /** @@ -1089,12 +1238,12 @@ static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink, * @inum: target inode number * @flags: source inode flags */ -static int add_dev_inode(struct stat *st, ino_t inum, int flags) +static int add_dev_inode(const char *path_name, struct stat *st, ino_t inum, int flags) { union ubifs_dev_desc dev; dev.huge = cpu_to_le64(makedev(major(st->st_rdev), minor(st->st_rdev))); - return add_inode_with_data(st, inum, &dev, 8, flags); + return add_inode(st, inum, &dev, 8, flags, path_name); } /** @@ -1117,7 +1266,7 @@ static int add_symlink_inode(const char *path_name, struct stat *st, ino_t inum, if (len > UBIFS_MAX_INO_DATA) return err_msg("symlink too long for %s", path_name); - return add_inode_with_data(st, inum, buf, len, flags); + return add_inode(st, inum, buf, len, flags, path_name); } /** @@ -1275,12 +1424,14 @@ static int add_file(const char *path_name, struct stat *st, ino_t inum, return err; } } while (ret != 0); + if (close(fd) == -1) return sys_err_msg("failed to close file '%s'", path_name); if (file_size != st->st_size) return err_msg("file size changed during writing file '%s'", path_name); - return add_inode(st, inum, flags); + + return add_inode(st, inum, NULL, 0, flags, path_name); } /** @@ -1360,15 +1511,15 @@ static int add_non_dir(const char *path_name, ino_t *inum, unsigned int nlink, if (S_ISREG(st->st_mode)) return add_file(path_name, st, *inum, flags); if (S_ISCHR(st->st_mode)) - return add_dev_inode(st, *inum, flags); + return add_dev_inode(path_name, st, *inum, flags); if (S_ISBLK(st->st_mode)) - return add_dev_inode(st, *inum, flags); + return add_dev_inode(path_name, st, *inum, flags); if (S_ISLNK(st->st_mode)) return add_symlink_inode(path_name, st, *inum, flags); if (S_ISSOCK(st->st_mode)) - return add_inode(st, *inum, flags); + return add_inode(st, *inum, NULL, 0, flags, NULL); if (S_ISFIFO(st->st_mode)) - return add_inode(st, *inum, flags); + return add_inode(st, *inum, NULL, 0, flags, NULL); return err_msg("file '%s' has unknown inode type", path_name); } @@ -1548,7 +1699,7 @@ static int add_directory(const char *dir_name, ino_t dir_inum, struct stat *st, creat_sqnum = dir_creat_sqnum; - err = add_dir_inode(dir, dir_inum, size, nlink, st); + err = add_dir_inode(dir ? dir_name : NULL, dir, dir_inum, size, nlink, st); if (err) goto out_free; diff --git a/ubifs-utils/mkfs.ubifs/ubifs.h b/ubifs-utils/mkfs.ubifs/ubifs.h index 434b651..2f080a8 100644 --- a/ubifs-utils/mkfs.ubifs/ubifs.h +++ b/ubifs-utils/mkfs.ubifs/ubifs.h @@ -42,6 +42,15 @@ */ #define UBIFS_TRUN_KEY UBIFS_KEY_TYPES_CNT +/* + * How much a directory entry/extended attribute entry adds to the parent/host + * inode. + */ +#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8) + +/* How much an extended attribute adds to the host inode */ +#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8) + /* The below union makes it easier to deal with keys */ union ubifs_key { |