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 41bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongkerstatic struct block_allocation* saved_allocation_head = NULL; 42bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker 43bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongkerstruct block_allocation* get_saved_allocation_chain() { 44bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker return saved_allocation_head; 45bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker} 46bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker 47ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 dentry_size(u32 entries, struct dentry *dentries) 48ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 49ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 len = 24; 50ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross unsigned int i; 516bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross unsigned int dentry_len; 52ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 53ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross for (i = 0; i < entries; i++) { 5440ce87a70a064eeb462d3c3935422918c1f6114ePaul Lawrence dentry_len = 8 + EXT4_ALIGN(strlen(dentries[i].filename), 4); 55ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (len % info.block_size + dentry_len > info.block_size) 56ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross len += info.block_size - (len % info.block_size); 57ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross len += dentry_len; 58ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 59ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 60ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return len; 61ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 62ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 63ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic struct ext4_dir_entry_2 *add_dentry(u8 *data, u32 *offset, 64ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_dir_entry_2 *prev, u32 inode, const char *name, 65ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 file_type) 66ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 67ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 name_len = strlen(name); 6840ce87a70a064eeb462d3c3935422918c1f6114ePaul Lawrence u16 rec_len = 8 + EXT4_ALIGN(name_len, 4); 69ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_dir_entry_2 *dentry; 70ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 71ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 start_block = *offset / info.block_size; 722ff1c5b6e8c1457dbb65fb8305db92c74e95dd42Colin Cross u32 end_block = (*offset + rec_len - 1) / info.block_size; 73ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (start_block != end_block) { 74ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross /* Adding this dentry will cross a block boundary, so pad the previous 75ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry to the block boundary */ 76ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!prev) 77ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross critical_error("no prev"); 78ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross prev->rec_len += end_block * info.block_size - *offset; 79ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *offset = end_block * info.block_size; 80ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 81ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 82ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = (struct ext4_dir_entry_2 *)(data + *offset); 83ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->inode = inode; 84ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->rec_len = rec_len; 85ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->name_len = name_len; 86ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->file_type = file_type; 87ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross memcpy(dentry->name, name, name_len); 88ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 89ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *offset += rec_len; 90ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return dentry; 91ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 92ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 93ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a directory structure for an array of directory entries, dentries, 94ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross and stores the location of the structure in an inode. The new inode's 95ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross .. link is set to dir_inode_num. Stores the location of the inode number 96ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross of each directory entry into dentries[i].inode, to be filled in later 97ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross when the inode for the entry is allocated. Returns the inode number of the 98ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross new directory */ 99ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries, 1008aef66d2125af8de7672a12895276802fcc1948fColin Cross u32 dirs) 101ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 102ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode; 1036bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross u32 blocks; 1046bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross u32 len; 105ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 offset = 0; 106ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 inode_num; 107ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 *data; 108ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross unsigned int i; 109ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_dir_entry_2 *dentry; 110ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 1116bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross blocks = DIV_ROUND_UP(dentry_size(entries, dentries), info.block_size); 1126bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross len = blocks * info.block_size; 1136bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross 114ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (dir_inode_num) { 115ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = allocate_inode(info); 116ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } else { 117ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dir_inode_num = EXT4_ROOT_INO; 118ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = EXT4_ROOT_INO; 119ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 120ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 121ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode_num == EXT4_ALLOCATE_FAILED) { 122ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to allocate inode\n"); 123ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 124ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 125ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 126ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross add_directory(inode_num); 127ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 128ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode = get_inode(inode_num); 129ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode == NULL) { 130ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to get inode %u", inode_num); 131ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 132ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 133ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 134ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross data = inode_allocate_data_extents(inode, len, len); 135ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (data == NULL) { 1362e905e5f2a3df605c68cb8633580c918e9f4ba71Colin Cross error("failed to allocate %u extents", len); 137ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 138ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 139ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 140ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode = S_IFDIR; 141ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_links_count = dirs + 2; 142ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_flags |= aux_info.default_i_flags; 143ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 144ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = NULL; 145ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 146ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = add_dentry(data, &offset, NULL, 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 dentry = add_dentry(data, &offset, dentry, dir_inode_num, "..", EXT4_FT_DIR); 153ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!dentry) { 154ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to add .. directory"); 155ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 156ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 157ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 158ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross for (i = 0; i < entries; i++) { 1596bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross dentry = add_dentry(data, &offset, dentry, 0, 1606bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross dentries[i].filename, dentries[i].file_type); 1616bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross if (offset > len || (offset == len && i != entries - 1)) 1626bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross critical_error("internal error: dentry for %s ends at %d, past %d\n", 1636bd2b5d80db5630cb73e3e5a4be3b38afa241c5aColin Cross dentries[i].filename, offset, len); 164ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentries[i].inode = &dentry->inode; 165ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!dentry) { 166ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to add directory"); 167ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 168ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 169ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 170ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 1718748938228acad9e53c4f3cdfa132d2aff7917bfColin Cross /* pad the last dentry out to the end of the block */ 1728748938228acad9e53c4f3cdfa132d2aff7917bfColin Cross dentry->rec_len += len - offset; 173ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 174ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return inode_num; 175ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 176ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 177ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk. Returns the inode number of the new file */ 178ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_file(const char *filename, u64 len) 179ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 180ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode; 181ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 inode_num; 182ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 183ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = allocate_inode(info); 184ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode_num == EXT4_ALLOCATE_FAILED) { 185ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to allocate inode\n"); 186ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 187ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 188ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 189ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode = get_inode(inode_num); 190ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode == NULL) { 191ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to get inode %u", inode_num); 192ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 193ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 194ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 195bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker if (len > 0) { 196bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker struct block_allocation* alloc = inode_allocate_file_extents(inode, len, filename); 1979922135de65b717267d8173f61e360fbb9cf1ebdDoug Zongker if (alloc) { 1989922135de65b717267d8173f61e360fbb9cf1ebdDoug Zongker alloc->filename = strdup(filename); 1999922135de65b717267d8173f61e360fbb9cf1ebdDoug Zongker alloc->next = saved_allocation_head; 2009922135de65b717267d8173f61e360fbb9cf1ebdDoug Zongker saved_allocation_head = alloc; 2019922135de65b717267d8173f61e360fbb9cf1ebdDoug Zongker } 202bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker } 203ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 204ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode = S_IFREG; 205ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_links_count = 1; 206ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_flags |= aux_info.default_i_flags; 207ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 208ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return inode_num; 209ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 210ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 211ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk. Returns the inode number of the new file */ 2125446bde9c02f6ae95a30d9c178b13a05bb580fe1Nick Kralevichu32 make_link(const char *link) 213ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 214ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode; 215ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 inode_num; 216ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 len = strlen(link); 217ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 218ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = allocate_inode(info); 219ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode_num == EXT4_ALLOCATE_FAILED) { 220ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to allocate inode\n"); 221ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 222ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 223ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 224ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode = get_inode(inode_num); 225ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode == NULL) { 226ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to get inode %u", inode_num); 227ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 228ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 229ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 230ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode = S_IFLNK; 231ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_links_count = 1; 232ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_flags |= aux_info.default_i_flags; 233ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_size_lo = len; 234ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 235ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (len + 1 <= sizeof(inode->i_block)) { 236ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross /* Fast symlink */ 237ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross memcpy((char*)inode->i_block, link, len); 238ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } else { 239ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 *data = inode_allocate_data_indirect(inode, info.block_size, info.block_size); 240ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross memcpy(data, link, len); 241ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_blocks_lo = info.block_size / 512; 242ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 243ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 244ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return inode_num; 245ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 246ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 247de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Crossint inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime) 248ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 249ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode = get_inode(inode_num); 250ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 251ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!inode) 252ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return -1; 253ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 254ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode |= mode; 255ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_uid = uid; 256ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_gid = gid; 257de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross inode->i_mtime = mtime; 258de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross inode->i_atime = mtime; 259de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross inode->i_ctime = mtime; 260ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 261ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return 0; 262ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 263b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley 2644df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich/* 2654df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * Returns the amount of free space available in the specified 2664df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * xattr region 2674df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich */ 2684df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic size_t xattr_free_space(struct ext4_xattr_entry *entry, char *end) 2694df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 2709036d55be0a9bccf6721b64ba0d116d7afd66201Mark Salyzyn end -= sizeof(uint32_t); /* Required four null bytes */ 2714df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich while(!IS_LAST_ENTRY(entry) && (((char *) entry) < end)) { 2724df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich end -= EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)); 2734df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich entry = EXT4_XATTR_NEXT(entry); 2744df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 275b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley 2764df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (((char *) entry) > end) { 2774df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich error("unexpected read beyond end of xattr space"); 2784df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return 0; 2794df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 280b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley 2819036d55be0a9bccf6721b64ba0d116d7afd66201Mark Salyzyn return end - ((char *) entry); 2824df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 2834df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 2844df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich/* 2854df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * Returns a pointer to the free space immediately after the 2864df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * last xattr element 2874df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich */ 2884df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic struct ext4_xattr_entry* xattr_get_last(struct ext4_xattr_entry *entry) 289b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley{ 2904df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { 2914df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich // skip entry 2924df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 2934df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return entry; 2944df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 295b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley 2964df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich/* 2974df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * assert that the elements in the ext4 xattr section are in sorted order 2984df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 2994df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * The ext4 filesystem requires extended attributes to be sorted when 3004df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * they're not stored in the inode. The kernel ext4 code uses the following 3014df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * sorting algorithm: 3024df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 3034df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 1) First sort extended attributes by their name_index. For example, 3044df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * EXT4_XATTR_INDEX_USER (1) comes before EXT4_XATTR_INDEX_SECURITY (6). 3054df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 2) If the name_indexes are equal, then sorting is based on the length 3064df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * of the name. For example, XATTR_SELINUX_SUFFIX ("selinux") comes before 3074df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * XATTR_CAPS_SUFFIX ("capability") because "selinux" is shorter than "capability" 3084df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 3) If the name_index and name_length are equal, then memcmp() is used to determine 3094df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * which name comes first. For example, "selinux" would come before "yelinux". 3104df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * 3114df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * This method is intended to implement the sorting function defined in 3124df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich * the Linux kernel file fs/ext4/xattr.c function ext4_xattr_find_entry(). 3134df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich */ 3144df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic void xattr_assert_sane(struct ext4_xattr_entry *entry) 3154df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 3164df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich for( ; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { 3174df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry); 3184df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (IS_LAST_ENTRY(next)) { 3194df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return; 3204df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 3214df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3224df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich int cmp = next->e_name_index - entry->e_name_index; 3234df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (cmp == 0) 3244df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich cmp = next->e_name_len - entry->e_name_len; 3254df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (cmp == 0) 3264df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich cmp = memcmp(next->e_name, entry->e_name, next->e_name_len); 3274df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (cmp < 0) { 3284df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich error("BUG: extended attributes are not sorted\n"); 3294df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return; 3304df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 3314df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (cmp == 0) { 3324df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich error("BUG: duplicate extended attributes detected\n"); 3334df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return; 3344df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 3354df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 3364df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 3374df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3384df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#define NAME_HASH_SHIFT 5 3394df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#define VALUE_HASH_SHIFT 16 3404df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3414df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic void ext4_xattr_hash_entry(struct ext4_xattr_header *header, 3424df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *entry) 3434df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 3447900c773815d062deb266f744f95aa76b3573fa3Colin Cross u32 hash = 0; 3454df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich char *name = entry->e_name; 3464df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich int n; 3474df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3484df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich for (n = 0; n < entry->e_name_len; n++) { 3494df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich hash = (hash << NAME_HASH_SHIFT) ^ 3504df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ 3514df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich *name++; 3524df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 3534df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3544df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (entry->e_value_block == 0 && entry->e_value_size != 0) { 3557900c773815d062deb266f744f95aa76b3573fa3Colin Cross u32 *value = (u32 *)((char *)header + 3564df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich le16_to_cpu(entry->e_value_offs)); 3574df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich for (n = (le32_to_cpu(entry->e_value_size) + 3584df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) { 3594df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich hash = (hash << VALUE_HASH_SHIFT) ^ 3604df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ 3614df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich le32_to_cpu(*value++); 3624df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 3634df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 3644df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich entry->e_hash = cpu_to_le32(hash); 3654df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 3664df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3674df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#undef NAME_HASH_SHIFT 3684df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich#undef VALUE_HASH_SHIFT 3694df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3704df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic struct ext4_xattr_entry* xattr_addto_range( 3714df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich void *block_start, 3724df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich void *block_end, 3734df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *first, 3744df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich int name_index, 3754df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich const char *name, 3764df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich const void *value, 3774df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich size_t value_len) 3784df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 3794df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich size_t name_len = strlen(name); 3804df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (name_len > 255) 3814df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return NULL; 3824df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3834df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich size_t available_size = xattr_free_space(first, block_end); 3844df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich size_t needed_size = EXT4_XATTR_LEN(name_len) + EXT4_XATTR_SIZE(value_len); 3854df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3864df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (needed_size > available_size) 3874df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return NULL; 3884df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3894df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *new_entry = xattr_get_last(first); 3904df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich memset(new_entry, 0, EXT4_XATTR_LEN(name_len)); 3914df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3924df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich new_entry->e_name_len = name_len; 3934df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich new_entry->e_name_index = name_index; 3944df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich memcpy(new_entry->e_name, name, name_len); 3954df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich new_entry->e_value_block = 0; 3964df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich new_entry->e_value_size = cpu_to_le32(value_len); 3974df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 3984df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich char *val = (char *) new_entry + available_size - EXT4_XATTR_SIZE(value_len); 3994df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich size_t e_value_offs = val - (char *) block_start; 4004df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4014df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich new_entry->e_value_offs = cpu_to_le16(e_value_offs); 4024df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich memset(val, 0, EXT4_XATTR_SIZE(value_len)); 4034df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich memcpy(val, value, value_len); 4044df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4054df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich xattr_assert_sane(first); 4064df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return new_entry; 4074df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 4084df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4094df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic int xattr_addto_inode(struct ext4_inode *inode, int name_index, 4104df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich const char *name, const void *value, size_t value_len) 4114df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 4124df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_ibody_header *hdr = (struct ext4_xattr_ibody_header *) (inode + 1); 4134df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (hdr + 1); 4144df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich char *block_end = ((char *) inode) + info.inode_size; 4154df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4164df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *result = 4174df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich xattr_addto_range(first, block_end, first, name_index, name, value, value_len); 4184df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4194df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (result == NULL) 420b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley return -1; 421b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley 4224df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich hdr->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); 423b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley inode->i_extra_isize = cpu_to_le16(sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE); 424b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley 425b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley return 0; 426b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley} 4274df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4284df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic int xattr_addto_block(struct ext4_inode *inode, int name_index, 4294df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich const char *name, const void *value, size_t value_len) 4304df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 4314df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_header *header = get_xattr_block_for_inode(inode); 4324df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (!header) 4334df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return -1; 4344df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4354df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (header + 1); 4364df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich char *block_end = ((char *) header) + info.block_size; 4374df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4384df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_xattr_entry *result = 4394df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich xattr_addto_range(header, block_end, first, name_index, name, value, value_len); 4404df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4414df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (result == NULL) 4424df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return -1; 4434df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4444df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich ext4_xattr_hash_entry(header, result); 4454df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return 0; 4464df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 4474df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4484df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4494df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichstatic int xattr_add(u32 inode_num, int name_index, const char *name, 4504df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich const void *value, size_t value_len) 4514df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 4524df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (!value) 4534df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return 0; 4544df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4554df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct ext4_inode *inode = get_inode(inode_num); 4564df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4574df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (!inode) 4584df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return -1; 4594df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4604df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich int result = xattr_addto_inode(inode, name_index, name, value, value_len); 4614df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (result != 0) { 4624df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich result = xattr_addto_block(inode, name_index, name, value, value_len); 4634df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich } 4644df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return result; 4654df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 4664df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4674df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichint inode_set_selinux(u32 inode_num, const char *secon) 4684df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich{ 469192238d9081d4ad8c090a77e8e1d40b66e8fae4aSungmin Choi if (!secon) 470192238d9081d4ad8c090a77e8e1d40b66e8fae4aSungmin Choi return 0; 471192238d9081d4ad8c090a77e8e1d40b66e8fae4aSungmin Choi 4724df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY, 4734df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich XATTR_SELINUX_SUFFIX, secon, strlen(secon) + 1); 4744df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 4754df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4764df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevichint inode_set_capabilities(u32 inode_num, uint64_t capabilities) { 4774df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich if (capabilities == 0) 4784df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return 0; 4794df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4804df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich struct vfs_cap_data cap_data; 4814df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich memset(&cap_data, 0, sizeof(cap_data)); 4824df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4834df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; 4844df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich cap_data.data[0].permitted = (uint32_t) (capabilities & 0xffffffff); 4854df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich cap_data.data[0].inheritable = 0; 4864df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich cap_data.data[1].permitted = (uint32_t) (capabilities >> 32); 4874df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich cap_data.data[1].inheritable = 0; 4884df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich 4894df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY, 4904df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich XATTR_CAPS_SUFFIX, &cap_data, sizeof(cap_data)); 4914df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich} 492