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>
20ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
21ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "ext4_utils.h"
22ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "ext4.h"
23ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "make_ext4fs.h"
24ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "allocate.h"
25ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "contents.h"
26ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "extent.h"
27ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include "indirect.h"
28b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#include "xattr.h"
29ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
304605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#ifdef USE_MINGW
314605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IFLNK 0  /* used by make_link, not needed under mingw */
324605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#endif
334605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll
34ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 dentry_size(u32 entries, struct dentry *dentries)
35ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
36ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 len = 24;
37ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	unsigned int i;
386bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	unsigned int dentry_len;
39ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
40ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	for (i = 0; i < entries; i++) {
416bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross		dentry_len = 8 + ALIGN(strlen(dentries[i].filename), 4);
42ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (len % info.block_size + dentry_len > info.block_size)
43ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			len += info.block_size - (len % info.block_size);
44ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		len += dentry_len;
45ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
46ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
477c81ec40f5f466b23c2ebacabe1e4e9ac6932bd5Ken Sumrall	/* include size of the dentry used to pad until the end of the block */
487c81ec40f5f466b23c2ebacabe1e4e9ac6932bd5Ken Sumrall	if (len % info.block_size + 8 > info.block_size)
497c81ec40f5f466b23c2ebacabe1e4e9ac6932bd5Ken Sumrall		len += info.block_size - (len % info.block_size);
507c81ec40f5f466b23c2ebacabe1e4e9ac6932bd5Ken Sumrall	len += 8;
517c81ec40f5f466b23c2ebacabe1e4e9ac6932bd5Ken Sumrall
52ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return len;
53ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
54ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
55ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic struct ext4_dir_entry_2 *add_dentry(u8 *data, u32 *offset,
56ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		struct ext4_dir_entry_2 *prev, u32 inode, const char *name,
57ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		u8 file_type)
58ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
59ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u8 name_len = strlen(name);
606bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	u16 rec_len = 8 + ALIGN(name_len, 4);
61ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_dir_entry_2 *dentry;
62ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
63ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 start_block = *offset / info.block_size;
642ff1c5b6e8c1457dbb65fb8305db92c74e95dd42Colin Cross	u32 end_block = (*offset + rec_len - 1) / info.block_size;
65ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (start_block != end_block) {
66ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		/* Adding this dentry will cross a block boundary, so pad the previous
67ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		   dentry to the block boundary */
68ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (!prev)
69ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			critical_error("no prev");
70ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		prev->rec_len += end_block * info.block_size - *offset;
71ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		*offset = end_block * info.block_size;
72ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
73ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
74ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = (struct ext4_dir_entry_2 *)(data + *offset);
75ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->inode = inode;
76ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->rec_len = rec_len;
77ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->name_len = name_len;
78ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->file_type = file_type;
79ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	memcpy(dentry->name, name, name_len);
80ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
81ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	*offset += rec_len;
82ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return dentry;
83ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
84ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
85ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a directory structure for an array of directory entries, dentries,
86ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   and stores the location of the structure in an inode.  The new inode's
87ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   .. link is set to dir_inode_num.  Stores the location of the inode number
88ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   of each directory entry into dentries[i].inode, to be filled in later
89ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   when the inode for the entry is allocated.  Returns the inode number of the
90ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   new directory */
91ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries,
928aef66d2125af8de7672a12895276802fcc1948fColin Cross	u32 dirs)
93ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
94ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode;
956bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	u32 blocks;
966bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	u32 len;
97ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 offset = 0;
98ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode_num;
99ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u8 *data;
100ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	unsigned int i;
101ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_dir_entry_2 *dentry;
102ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
1036bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	blocks = DIV_ROUND_UP(dentry_size(entries, dentries), info.block_size);
1046bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross	len = blocks * info.block_size;
1056bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross
106ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (dir_inode_num) {
107ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		inode_num = allocate_inode(info);
108ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	} else {
109ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		dir_inode_num = EXT4_ROOT_INO;
110ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		inode_num = EXT4_ROOT_INO;
111ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
112ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
113ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode_num == EXT4_ALLOCATE_FAILED) {
114ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to allocate inode\n");
115ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
116ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
117ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
118ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	add_directory(inode_num);
119ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
120ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = get_inode(inode_num);
121ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode == NULL) {
122ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to get inode %u", inode_num);
123ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
124ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
125ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
126ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	data = inode_allocate_data_extents(inode, len, len);
127ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (data == NULL) {
1282e905e5f2a3df605c68cb8633580c918e9f4ba71Colin Cross		error("failed to allocate %u extents", len);
129ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
130ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
131ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
132ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode = S_IFDIR;
133ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_links_count = dirs + 2;
134ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_flags |= aux_info.default_i_flags;
135ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
136ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = NULL;
137ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
138ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = add_dentry(data, &offset, NULL, inode_num, ".", EXT4_FT_DIR);
139ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (!dentry) {
140ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to add . directory");
141ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
142ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
143ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
144ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = add_dentry(data, &offset, dentry, dir_inode_num, "..", EXT4_FT_DIR);
145ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (!dentry) {
146ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to add .. directory");
147ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
148ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
149ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
150ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	for (i = 0; i < entries; i++) {
1516bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross		dentry = add_dentry(data, &offset, dentry, 0,
1526bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross				dentries[i].filename, dentries[i].file_type);
1536bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross		if (offset > len || (offset == len && i != entries - 1))
1546bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross			critical_error("internal error: dentry for %s ends at %d, past %d\n",
1556bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross				dentries[i].filename, offset, len);
156ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		dentries[i].inode = &dentry->inode;
157ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (!dentry) {
158ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			error("failed to add directory");
159ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			return EXT4_ALLOCATE_FAILED;
160ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		}
161ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
162ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
163ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry = (struct ext4_dir_entry_2 *)(data + offset);
164ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->inode = 0;
165ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->rec_len = len - offset;
166ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->name_len = 0;
167ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentry->file_type = EXT4_FT_UNKNOWN;
168ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
169ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return inode_num;
170ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
171ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
172ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk.  Returns the inode number of the new file */
173ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_file(const char *filename, u64 len)
174ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
175ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode;
176ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode_num;
177ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
178ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode_num = allocate_inode(info);
179ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode_num == EXT4_ALLOCATE_FAILED) {
180ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to allocate inode\n");
181ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
182ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
183ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
184ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = get_inode(inode_num);
185ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode == NULL) {
186ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to get inode %u", inode_num);
187ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
188ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
189ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
190cf5c39c1851f8826264822414dbab31c1aeaeec6Colin Cross	if (len > 0)
191cf5c39c1851f8826264822414dbab31c1aeaeec6Colin Cross		inode_allocate_file_extents(inode, len, filename);
192ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
193ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode = S_IFREG;
194ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_links_count = 1;
195ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_flags |= aux_info.default_i_flags;
196ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
197ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return inode_num;
198ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
199ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
200ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk.  Returns the inode number of the new file */
201ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_link(const char *filename, const char *link)
202ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
203ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode;
204ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode_num;
205ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 len = strlen(link);
206ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
207ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode_num = allocate_inode(info);
208ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode_num == EXT4_ALLOCATE_FAILED) {
209ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to allocate inode\n");
210ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
211ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
212ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
213ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = get_inode(inode_num);
214ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (inode == NULL) {
215ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to get inode %u", inode_num);
216ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return EXT4_ALLOCATE_FAILED;
217ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
218ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
219ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode = S_IFLNK;
220ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_links_count = 1;
221ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_flags |= aux_info.default_i_flags;
222ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_size_lo = len;
223ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
224ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (len + 1 <= sizeof(inode->i_block)) {
225ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		/* Fast symlink */
226ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		memcpy((char*)inode->i_block, link, len);
227ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	} else {
228ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		u8 *data = inode_allocate_data_indirect(inode, info.block_size, info.block_size);
229ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		memcpy(data, link, len);
230ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		inode->i_blocks_lo = info.block_size / 512;
231ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
232ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
233ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return inode_num;
234ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
235ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
236de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Crossint inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime)
237ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
238ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct ext4_inode *inode = get_inode(inode_num);
239ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
240ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (!inode)
241ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		return -1;
242ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
243ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_mode |= mode;
244ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_uid = uid;
245ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode->i_gid = gid;
246de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross	inode->i_mtime = mtime;
247de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross	inode->i_atime = mtime;
248de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross	inode->i_ctime = mtime;
249ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
250ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return 0;
251ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
252b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
253b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#ifdef HAVE_SELINUX
254b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#define XATTR_SELINUX_SUFFIX "selinux"
255b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
256b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley/* XXX */
257b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#define cpu_to_le32(x) (x)
258b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#define cpu_to_le16(x) (x)
259b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
260b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalleyint inode_set_selinux(u32 inode_num, const char *secon)
261b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley{
262b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	struct ext4_inode *inode = get_inode(inode_num);
263b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	u32 *hdr;
264b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	struct ext4_xattr_entry *entry;
265b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	size_t name_len = strlen(XATTR_SELINUX_SUFFIX);
2663def37fa6f8e037d39c19be9e624f15745032d08Matt Finifter	size_t value_len;
267b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	size_t size, min_offs;
268b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	char *val;
269b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
270b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	if (!secon)
271b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		return 0;
272b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
273b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	if (!inode)
274b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		return -1;
275b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
276b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	hdr = (u32 *) (inode + 1);
277b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	*hdr = cpu_to_le32(EXT4_XATTR_MAGIC);
278b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	entry = (struct ext4_xattr_entry *) (hdr+1);
279b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	memset(entry, 0, EXT4_XATTR_LEN(name_len));
280b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	entry->e_name_index = EXT4_XATTR_INDEX_SECURITY;
281b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	entry->e_name_len = name_len;
282b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	memcpy(entry->e_name, XATTR_SELINUX_SUFFIX, name_len);
2833def37fa6f8e037d39c19be9e624f15745032d08Matt Finifter	value_len = strlen(secon)+1;
284b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	entry->e_value_size = cpu_to_le32(value_len);
285b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	min_offs = (char *)inode + info.inode_size - (char*) entry;
286b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	size = EXT4_XATTR_SIZE(value_len);
287b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	val = (char *)entry + min_offs - size;
288b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	entry->e_value_offs = cpu_to_le16(min_offs - size);
289b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	memset(val + size - EXT4_XATTR_PAD, 0, EXT4_XATTR_PAD);
290b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	memcpy(val, secon, value_len);
291b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	inode->i_extra_isize = cpu_to_le16(sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE);
292b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
293b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	return 0;
294b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley}
295b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#else
296b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalleyint inode_set_selinux(u32 inode_num, const char *secon)
297b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley{
298b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	return 0;
299b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley}
300b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#endif
301