Home | History | Annotate | Download | only in fsck
      1 /**
      2  * xattr.c
      3  *
      4  * Many parts of codes are copied from Linux kernel/fs/f2fs.
      5  *
      6  * Copyright (C) 2015 Huawei Ltd.
      7  * Witten by:
      8  *   Hou Pengyang <houpengyang (at) huawei.com>
      9  *   Liu Shuoran <liushuoran (at) huawei.com>
     10  *   Jaegeuk Kim <jaegeuk (at) kernel.org>
     11  *
     12  * This program is free software; you can redistribute it and/or modify
     13  * it under the terms of the GNU General Public License version 2 as
     14  * published by the Free Software Foundation.
     15  */
     16 #include "fsck.h"
     17 #include "node.h"
     18 #include "xattr.h"
     19 
     20 #define XATTR_CREATE 0x1
     21 #define XATTR_REPLACE 0x2
     22 
     23 static void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode)
     24 {
     25 	struct f2fs_xattr_header *header;
     26 	void *txattr_addr;
     27 	u64 inline_size = inline_xattr_size(&inode->i);
     28 
     29 	txattr_addr = calloc(inline_size + BLOCK_SZ, 1);
     30 	ASSERT(txattr_addr);
     31 
     32 	if (inline_size)
     33 		memcpy(txattr_addr, inline_xattr_addr(&inode->i), inline_size);
     34 
     35 	/* Read from xattr node block. */
     36 	if (inode->i.i_xattr_nid) {
     37 		struct node_info ni;
     38 		int ret;
     39 
     40 		get_node_info(sbi, le32_to_cpu(inode->i.i_xattr_nid), &ni);
     41 		ret = dev_read_block(txattr_addr + inline_size, ni.blk_addr);
     42 		ASSERT(ret >= 0);
     43 	}
     44 
     45 	header = XATTR_HDR(txattr_addr);
     46 
     47 	/* Never been allocated xattrs */
     48 	if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) {
     49 		header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
     50 		header->h_refcount = cpu_to_le32(1);
     51 	}
     52 	return txattr_addr;
     53 }
     54 
     55 static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
     56 		size_t len, const char *name)
     57 {
     58 	struct f2fs_xattr_entry *entry;
     59 	list_for_each_xattr(entry, base_addr) {
     60 		if (entry->e_name_index != index)
     61 			continue;
     62 		if (entry->e_name_len != len)
     63 			continue;
     64 		if (!memcmp(entry->e_name, name, len))
     65 			break;
     66 	}
     67 	return entry;
     68 }
     69 
     70 static void write_all_xattrs(struct f2fs_sb_info *sbi,
     71 		struct f2fs_node *inode, __u32 hsize, void *txattr_addr)
     72 {
     73 	void *xattr_addr;
     74 	struct dnode_of_data dn;
     75 	struct node_info ni;
     76 	struct f2fs_node *xattr_node;
     77 	nid_t new_nid = 0;
     78 	block_t blkaddr;
     79 	nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
     80 	u64 inline_size = inline_xattr_size(&inode->i);
     81 	int ret;
     82 
     83 	ASSERT(inode->i.i_inline & F2FS_INLINE_XATTR);
     84 	memcpy(inline_xattr_addr(&inode->i), txattr_addr, inline_size);
     85 
     86 	if (hsize <= inline_size)
     87 		return;
     88 
     89 	if (!xnid) {
     90 		f2fs_alloc_nid(sbi, &new_nid, 0);
     91 
     92 		set_new_dnode(&dn, inode, NULL, new_nid);
     93 		/* NAT entry would be updated by new_node_page. */
     94 		blkaddr = new_node_block(sbi, &dn, XATTR_NODE_OFFSET);
     95 		ASSERT(dn.node_blk);
     96 		xattr_node = dn.node_blk;
     97 		inode->i.i_xattr_nid = cpu_to_le32(new_nid);
     98 	} else {
     99 		set_new_dnode(&dn, inode, NULL, xnid);
    100 		get_node_info(sbi, xnid, &ni);
    101 		blkaddr = ni.blk_addr;
    102 		xattr_node = calloc(BLOCK_SZ, 1);
    103 		ASSERT(xattr_node);
    104 		ret = dev_read_block(xattr_node, ni.blk_addr);
    105 		ASSERT(ret >= 0);
    106 	}
    107 
    108 	/* write to xattr node block */
    109 	xattr_addr = (void *)xattr_node;
    110 	memcpy(xattr_addr, txattr_addr + inline_size,
    111 			PAGE_SIZE - sizeof(struct node_footer));
    112 
    113 	ret = dev_write_block(xattr_node, blkaddr);
    114 	ASSERT(ret >= 0);
    115 }
    116 
    117 int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *name,
    118 		const void *value, size_t size, int flags)
    119 {
    120 	struct f2fs_node *inode;
    121 	void *base_addr;
    122 	struct f2fs_xattr_entry *here, *last;
    123 	struct node_info ni;
    124 	int error = 0;
    125 	int len;
    126 	int found, newsize;
    127 	__u32 new_hsize;
    128 	int ret;
    129 
    130 	if (name == NULL)
    131 		return -EINVAL;
    132 
    133 	if (value == NULL)
    134 		return -EINVAL;
    135 
    136 	len = strlen(name);
    137 
    138 	if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN)
    139 		return -ERANGE;
    140 
    141 	if (ino < 3)
    142 		return -EINVAL;
    143 
    144 	/* Now We just support selinux */
    145 	ASSERT(index == F2FS_XATTR_INDEX_SECURITY);
    146 
    147 	get_node_info(sbi, ino, &ni);
    148 	inode = calloc(BLOCK_SZ, 1);
    149 	ASSERT(inode);
    150 	ret = dev_read_block(inode, ni.blk_addr);
    151 	ASSERT(ret >= 0);
    152 
    153 	base_addr = read_all_xattrs(sbi, inode);
    154 	ASSERT(base_addr);
    155 
    156 	here = __find_xattr(base_addr, index, len, name);
    157 
    158 	found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1;
    159 
    160 	if ((flags & XATTR_REPLACE) && !found) {
    161 		error = -ENODATA;
    162 		goto exit;
    163 	} else if ((flags & XATTR_CREATE) && found) {
    164 		error = -EEXIST;
    165 		goto exit;
    166 	}
    167 
    168 	last = here;
    169 	while (!IS_XATTR_LAST_ENTRY(last))
    170 		last = XATTR_NEXT_ENTRY(last);
    171 
    172 	newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
    173 
    174 	/* 1. Check space */
    175 	if (value) {
    176 		int free;
    177 		/*
    178 		 * If value is NULL, it is remove operation.
    179 		 * In case of update operation, we calculate free.
    180 		 */
    181 		free = MIN_OFFSET - ((char *)last - (char *)base_addr);
    182 		if (found)
    183 			free = free + ENTRY_SIZE(here);
    184 		if (free < newsize) {
    185 			error = -ENOSPC;
    186 			goto exit;
    187 		}
    188 	}
    189 
    190 	/* 2. Remove old entry */
    191 	if (found) {
    192 		/*
    193 		 * If entry if sound, remove old entry.
    194 		 * If not found, remove operation is not needed
    195 		 */
    196 		struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
    197 		int oldsize = ENTRY_SIZE(here);
    198 
    199 		memmove(here, next, (char *)last - (char *)next);
    200 		last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
    201 		memset(last, 0, oldsize);
    202 
    203 	}
    204 
    205 	new_hsize = (char *)last - (char *)base_addr;
    206 
    207 	/* 3. Write new entry */
    208 	if (value) {
    209 		char *pval;
    210 		/*
    211 		 * Before we come here, old entry is removed.
    212 		 * We just write new entry.
    213 		 */
    214 		memset(last, 0, newsize);
    215 		last->e_name_index = index;
    216 		last->e_name_len = len;
    217 		memcpy(last->e_name, name, len);
    218 		pval = last->e_name + len;
    219 		memcpy(pval, value, size);
    220 		last->e_value_size = cpu_to_le16(size);
    221 		new_hsize += newsize;
    222 	}
    223 
    224 	write_all_xattrs(sbi, inode, new_hsize, base_addr);
    225 
    226 	/* inode need update */
    227 	ret = dev_write_block(inode, ni.blk_addr);
    228 	ASSERT(ret >= 0);
    229 exit:
    230 	free(base_addr);
    231 	return error;
    232 }
    233 
    234 int inode_set_selinux(struct f2fs_sb_info *sbi, u32 ino, const char *secon)
    235 {
    236 	if (!secon)
    237 		return 0;
    238 
    239 	return f2fs_setxattr(sbi, ino, F2FS_XATTR_INDEX_SECURITY,
    240 			XATTR_SELINUX_SUFFIX, secon, strlen(secon), 1);
    241 }
    242