contents.c revision 7900c773815d062deb266f744f95aa76b3573fa3
1ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/*
2ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * Copyright (C) 2010 The Android Open Source Project
3ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *
4ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * Licensed under the Apache License, Version 2.0 (the "License");
5ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * you may not use this file except in compliance with the License.
6ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * You may obtain a copy of the License at
7ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *
8ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *      http://www.apache.org/licenses/LICENSE-2.0
9ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *
10ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * Unless required by applicable law or agreed to in writing, software
11ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * distributed under the License is distributed on an "AS IS" BASIS,
12ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * See the License for the specific language governing permissions and
14ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * limitations under the License.
15ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross */
16ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
17ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include <sys/stat.h>
18ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include <string.h>
19ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include <stdio.h>
208a63232ae7d992c148b75a03d83df5c2188935fcNick Kralevich
218a63232ae7d992c148b75a03d83df5c2188935fcNick Kralevich#ifdef HAVE_ANDROID_OS
224df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#include <linux/capability.h>
233ebdcb8f9378320ec126bb130f167b7b4908e605Nick Kralevich#else
248a63232ae7d992c148b75a03d83df5c2188935fcNick Kralevich#include <private/android_filesystem_capability.h>
258a63232ae7d992c148b75a03d83df5c2188935fcNick Kralevich#endif
263ebdcb8f9378320ec126bb130f167b7b4908e605Nick Kralevich
273ebdcb8f9378320ec126bb130f167b7b4908e605Nick Kralevich#define XATTR_SELINUX_SUFFIX "selinux"
283ebdcb8f9378320ec126bb130f167b7b4908e605Nick Kralevich#define XATTR_CAPS_SUFFIX "capability"
29ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
30ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "ext4_utils.h"
31ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "make_ext4fs.h"
32ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "allocate.h"
33ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "contents.h"
34ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "extent.h"
35ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "indirect.h"
36ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
374605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#ifdef USE_MINGW
384605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IFLNK 0  /* used by make_link, not needed under mingw */
394605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#endif
404605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll
41ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 dentry_size(u32 entries, struct dentry *dentries)
42ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
43ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 len = 24;
44ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	unsigned int i;
456bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	unsigned int dentry_len;
46ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
47ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	for (i = 0; i < entries; i++) {
486bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross		dentry_len = 8 + ALIGN(strlen(dentries[i].filename), 4);
49ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (len % info.block_size + dentry_len > info.block_size)
50ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			len += info.block_size - (len % info.block_size);
51ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		len += dentry_len;
52ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
53ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
54ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return len;
55ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
56ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
57ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic struct ext4_dir_entry_2 *add_dentry(u8 *data, u32 *offset,
58ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		struct ext4_dir_entry_2 *prev, u32 inode, const char *name,
59ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		u8 file_type)
60ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
61ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u8 name_len = strlen(name);
626bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	u16 rec_len = 8 + ALIGN(name_len, 4);
63ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_dir_entry_2 *dentry;
64ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
65ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 start_block = *offset / info.block_size;
662ff1c5b6e8c1457dbb65fb8305db92c74e95dd42Colin Cross	u32 end_block = (*offset + rec_len - 1) / info.block_size;
67ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (start_block != end_block) {
68ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		/* Adding this dentry will cross a block boundary, so pad the previous
69ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		   dentry to the block boundary */
70ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (!prev)
71ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			critical_error("no prev");
72ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		prev->rec_len += end_block * info.block_size - *offset;
73ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		*offset = end_block * info.block_size;
74ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
75ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
76ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = (struct ext4_dir_entry_2 *)(data + *offset);
77ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->inode = inode;
78ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->rec_len = rec_len;
79ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->name_len = name_len;
80ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->file_type = file_type;
81ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	memcpy(dentry->name, name, name_len);
82ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
83ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	*offset += rec_len;
84ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return dentry;
85ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
86ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
87ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a directory structure for an array of directory entries, dentries,
88ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   and stores the location of the structure in an inode.  The new inode's
89ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   .. link is set to dir_inode_num.  Stores the location of the inode number
90ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   of each directory entry into dentries[i].inode, to be filled in later
91ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   when the inode for the entry is allocated.  Returns the inode number of the
92ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   new directory */
93ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries,
948aef66d2125af8de7672a12895276802fcc1948fColin Cross	u32 dirs)
95ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
96ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode;
976bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	u32 blocks;
986bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	u32 len;
99ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 offset = 0;
100ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode_num;
101ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u8 *data;
102ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	unsigned int i;
103ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_dir_entry_2 *dentry;
104ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
1056bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	blocks = DIV_ROUND_UP(dentry_size(entries, dentries), info.block_size);
1066bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	len = blocks * info.block_size;
1076bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross
108ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (dir_inode_num) {
109ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		inode_num = allocate_inode(info);
110ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	} else {
111ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		dir_inode_num = EXT4_ROOT_INO;
112ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		inode_num = EXT4_ROOT_INO;
113ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
114ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
115ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode_num == EXT4_ALLOCATE_FAILED) {
116ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to allocate inode\n");
117ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
118ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
119ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
120ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	add_directory(inode_num);
121ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
122ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = get_inode(inode_num);
123ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode == NULL) {
124ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to get inode %u", inode_num);
125ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
126ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
127ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
128ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	data = inode_allocate_data_extents(inode, len, len);
129ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (data == NULL) {
1302e905e5f2a3df605c68cb8633580c918e9f4ba71Colin Cross		error("failed to allocate %u extents", len);
131ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
132ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
133ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
134ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode = S_IFDIR;
135ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_links_count = dirs + 2;
136ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_flags |= aux_info.default_i_flags;
137ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
138ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = NULL;
139ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
140ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = add_dentry(data, &offset, NULL, inode_num, ".", EXT4_FT_DIR);
141ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (!dentry) {
142ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to add . directory");
143ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
144ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
145ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
146ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = add_dentry(data, &offset, dentry, dir_inode_num, "..", EXT4_FT_DIR);
147ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (!dentry) {
148ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to add .. directory");
149ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
150ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
151ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
152ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	for (i = 0; i < entries; i++) {
1536bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross		dentry = add_dentry(data, &offset, dentry, 0,
1546bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross				dentries[i].filename, dentries[i].file_type);
1556bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross		if (offset > len || (offset == len && i != entries - 1))
1566bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross			critical_error("internal error: dentry for %s ends at %d, past %d\n",
1576bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross				dentries[i].filename, offset, len);
158ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		dentries[i].inode = &dentry->inode;
159ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (!dentry) {
160ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			error("failed to add directory");
161ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			return EXT4_ALLOCATE_FAILED;
162ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		}
163ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
164ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
1658748938228acad9e53c4f3cdfa132d2aff7917bfColin Cross	/* pad the last dentry out to the end of the block */
1668748938228acad9e53c4f3cdfa132d2aff7917bfColin Cross	dentry->rec_len += len - offset;
167ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
168ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return inode_num;
169ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
170ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
171ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk.  Returns the inode number of the new file */
172ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_file(const char *filename, u64 len)
173ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
174ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode;
175ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode_num;
176ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
177ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode_num = allocate_inode(info);
178ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode_num == EXT4_ALLOCATE_FAILED) {
179ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to allocate inode\n");
180ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
181ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
182ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
183ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = get_inode(inode_num);
184ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode == NULL) {
185ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to get inode %u", inode_num);
186ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
187ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
188ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
189cf5c39c1851f8826264822414dbab31c1aeaeec6Colin Cross	if (len > 0)
190cf5c39c1851f8826264822414dbab31c1aeaeec6Colin Cross		inode_allocate_file_extents(inode, len, filename);
191ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
192ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode = S_IFREG;
193ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_links_count = 1;
194ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_flags |= aux_info.default_i_flags;
195ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
196ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return inode_num;
197ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
198ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
199ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk.  Returns the inode number of the new file */
2005446bde9c02f6ae95a30d9c178b13a05bb580fe1Nick Kralevichu32 make_link(const char *link)
201ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
202ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode;
203ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode_num;
204ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 len = strlen(link);
205ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
206ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode_num = allocate_inode(info);
207ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode_num == EXT4_ALLOCATE_FAILED) {
208ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to allocate inode\n");
209ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
210ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
211ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
212ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = get_inode(inode_num);
213ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode == NULL) {
214ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to get inode %u", inode_num);
215ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
216ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
217ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
218ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode = S_IFLNK;
219ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_links_count = 1;
220ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_flags |= aux_info.default_i_flags;
221ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_size_lo = len;
222ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
223ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (len + 1 <= sizeof(inode->i_block)) {
224ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		/* Fast symlink */
225ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		memcpy((char*)inode->i_block, link, len);
226ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	} else {
227ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		u8 *data = inode_allocate_data_indirect(inode, info.block_size, info.block_size);
228ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		memcpy(data, link, len);
229ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		inode->i_blocks_lo = info.block_size / 512;
230ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
231ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
232ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return inode_num;
233ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
234ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
235de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Crossint inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime)
236ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
237ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode = get_inode(inode_num);
238ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
239ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (!inode)
240ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return -1;
241ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
242ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode |= mode;
243ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_uid = uid;
244ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_gid = gid;
245de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross	inode->i_mtime = mtime;
246de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross	inode->i_atime = mtime;
247de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross	inode->i_ctime = mtime;
248ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
249ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return 0;
250ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
251b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
2524df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich/*
2534df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * Returns the amount of free space available in the specified
2544df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * xattr region
2554df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich */
2564df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic size_t xattr_free_space(struct ext4_xattr_entry *entry, char *end)
2574df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
2584df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	while(!IS_LAST_ENTRY(entry) && (((char *) entry) < end)) {
2594df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		end   -= EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
2604df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		entry  = EXT4_XATTR_NEXT(entry);
2614df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	}
262b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
2634df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (((char *) entry) > end) {
2644df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		error("unexpected read beyond end of xattr space");
2654df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return 0;
2664df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	}
267b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
2684df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	return end - ((char *) entry);
2694df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
2704df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
2714df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich/*
2724df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * Returns a pointer to the free space immediately after the
2734df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * last xattr element
2744df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich */
2754df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic struct ext4_xattr_entry* xattr_get_last(struct ext4_xattr_entry *entry)
276b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley{
2774df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
2784df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		// skip entry
2794df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	}
2804df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	return entry;
2814df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
282b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
2834df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich/*
2844df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * assert that the elements in the ext4 xattr section are in sorted order
2854df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *
2864df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * The ext4 filesystem requires extended attributes to be sorted when
2874df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * they're not stored in the inode. The kernel ext4 code uses the following
2884df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * sorting algorithm:
2894df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *
2904df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 1) First sort extended attributes by their name_index. For example,
2914df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *    EXT4_XATTR_INDEX_USER (1) comes before EXT4_XATTR_INDEX_SECURITY (6).
2924df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 2) If the name_indexes are equal, then sorting is based on the length
2934df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *    of the name. For example, XATTR_SELINUX_SUFFIX ("selinux") comes before
2944df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *    XATTR_CAPS_SUFFIX ("capability") because "selinux" is shorter than "capability"
2954df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 3) If the name_index and name_length are equal, then memcmp() is used to determine
2964df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *    which name comes first. For example, "selinux" would come before "yelinux".
2974df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *
2984df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * This method is intended to implement the sorting function defined in
2994df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * the Linux kernel file fs/ext4/xattr.c function ext4_xattr_find_entry().
3004df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich */
3014df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic void xattr_assert_sane(struct ext4_xattr_entry *entry)
3024df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
3034df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	for( ; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
3044df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
3054df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		if (IS_LAST_ENTRY(next)) {
3064df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			return;
3074df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		}
3084df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3094df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		int cmp = next->e_name_index - entry->e_name_index;
3104df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		if (cmp == 0)
3114df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			cmp = next->e_name_len - entry->e_name_len;
3124df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		if (cmp == 0)
3134df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			cmp = memcmp(next->e_name, entry->e_name, next->e_name_len);
3144df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		if (cmp < 0) {
3154df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			error("BUG: extended attributes are not sorted\n");
3164df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			return;
3174df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		}
3184df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		if (cmp == 0) {
3194df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			error("BUG: duplicate extended attributes detected\n");
3204df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			return;
3214df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		}
3224df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	}
3234df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
3244df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3254df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#define NAME_HASH_SHIFT 5
3264df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#define VALUE_HASH_SHIFT 16
3274df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3284df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
3294df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		struct ext4_xattr_entry *entry)
3304df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
3317900c773815d062deb266f744f95aa76b3573fa3Colin Cross	u32 hash = 0;
3324df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	char *name = entry->e_name;
3334df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	int n;
3344df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3354df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	for (n = 0; n < entry->e_name_len; n++) {
3364df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		hash = (hash << NAME_HASH_SHIFT) ^
3374df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			(hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
3384df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			*name++;
3394df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	}
3404df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3414df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (entry->e_value_block == 0 && entry->e_value_size != 0) {
3427900c773815d062deb266f744f95aa76b3573fa3Colin Cross		u32 *value = (u32 *)((char *)header +
3434df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			le16_to_cpu(entry->e_value_offs));
3444df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		for (n = (le32_to_cpu(entry->e_value_size) +
3454df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
3464df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			hash = (hash << VALUE_HASH_SHIFT) ^
3474df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich				(hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
3484df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich				le32_to_cpu(*value++);
3494df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		}
3504df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	}
3514df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	entry->e_hash = cpu_to_le32(hash);
3524df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
3534df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3544df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#undef NAME_HASH_SHIFT
3554df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#undef VALUE_HASH_SHIFT
3564df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3574df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic struct ext4_xattr_entry* xattr_addto_range(
3584df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		void *block_start,
3594df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		void *block_end,
3604df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		struct ext4_xattr_entry *first,
3614df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		int name_index,
3624df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		const char *name,
3634df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		const void *value,
3644df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		size_t value_len)
3654df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
3664df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	size_t name_len = strlen(name);
3674df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (name_len > 255)
3684df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return NULL;
3694df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3704df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	size_t available_size = xattr_free_space(first, block_end);
3714df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	size_t needed_size = EXT4_XATTR_LEN(name_len) + EXT4_XATTR_SIZE(value_len);
3724df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3734df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (needed_size > available_size)
3744df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return NULL;
3754df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3764df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_xattr_entry *new_entry = xattr_get_last(first);
3774df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	memset(new_entry, 0, EXT4_XATTR_LEN(name_len));
3784df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3794df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	new_entry->e_name_len = name_len;
3804df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	new_entry->e_name_index = name_index;
3814df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	memcpy(new_entry->e_name, name, name_len);
3824df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	new_entry->e_value_block = 0;
3834df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	new_entry->e_value_size = cpu_to_le32(value_len);
3844df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3854df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	char *val = (char *) new_entry + available_size - EXT4_XATTR_SIZE(value_len);
3864df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	size_t e_value_offs = val - (char *) block_start;
3874df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3884df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	new_entry->e_value_offs = cpu_to_le16(e_value_offs);
3894df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	memset(val, 0, EXT4_XATTR_SIZE(value_len));
3904df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	memcpy(val, value, value_len);
3914df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3924df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	xattr_assert_sane(first);
3934df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	return new_entry;
3944df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
3954df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3964df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic int xattr_addto_inode(struct ext4_inode *inode, int name_index,
3974df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		const char *name, const void *value, size_t value_len)
3984df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
3994df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_xattr_ibody_header *hdr = (struct ext4_xattr_ibody_header *) (inode + 1);
4004df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (hdr + 1);
4014df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	char *block_end = ((char *) inode) + info.inode_size;
4024df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4034df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_xattr_entry *result =
4044df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		xattr_addto_range(first, block_end, first, name_index, name, value, value_len);
4054df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4064df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (result == NULL)
407b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		return -1;
408b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
4094df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	hdr->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
410b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	inode->i_extra_isize = cpu_to_le16(sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE);
411b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
412b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	return 0;
413b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley}
4144df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4154df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic int xattr_addto_block(struct ext4_inode *inode, int name_index,
4164df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		const char *name, const void *value, size_t value_len)
4174df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
4184df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_xattr_header *header = get_xattr_block_for_inode(inode);
4194df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (!header)
4204df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return -1;
4214df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4224df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (header + 1);
4234df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	char *block_end = ((char *) header) + info.block_size;
4244df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4254df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_xattr_entry *result =
4264df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		xattr_addto_range(header, block_end, first, name_index, name, value, value_len);
4274df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4284df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (result == NULL)
4294df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return -1;
4304df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4314df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	ext4_xattr_hash_entry(header, result);
4324df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	return 0;
4334df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
4344df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4354df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4364df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic int xattr_add(u32 inode_num, int name_index, const char *name,
4374df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		const void *value, size_t value_len)
4384df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
4394df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (!value)
4404df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return 0;
4414df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4424df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct ext4_inode *inode = get_inode(inode_num);
4434df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4444df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (!inode)
4454df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return -1;
4464df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4474df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	int result = xattr_addto_inode(inode, name_index, name, value, value_len);
4484df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (result != 0) {
4494df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		result = xattr_addto_block(inode, name_index, name, value, value_len);
4504df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	}
4514df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	return result;
4524df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
4534df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4544df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichint inode_set_selinux(u32 inode_num, const char *secon)
4554df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{
456192238d9081d4ad8c090a77e8e1d40b66e8fae4aSungmin Choi	if (!secon)
457192238d9081d4ad8c090a77e8e1d40b66e8fae4aSungmin Choi		return 0;
458192238d9081d4ad8c090a77e8e1d40b66e8fae4aSungmin Choi
4594df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY,
4604df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		XATTR_SELINUX_SUFFIX, secon, strlen(secon) + 1);
4614df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
4624df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4634df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichint inode_set_capabilities(u32 inode_num, uint64_t capabilities) {
4644df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	if (capabilities == 0)
4654df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		return 0;
4664df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4674df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	struct vfs_cap_data cap_data;
4684df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	memset(&cap_data, 0, sizeof(cap_data));
4694df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4704df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
4714df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff);
4724df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	cap_data.data[0].inheritable = 0;
4734df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
4744df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	cap_data.data[1].inheritable = 0;
4754df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
4764df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich	return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY,
4774df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		XATTR_CAPS_SUFFIX, &cap_data, sizeof(cap_data));
4784df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich}
4794df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
480