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