diff options
Diffstat (limited to 'ubifs-utils')
| -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  { | 
