contents.c revision cf5c39c1851f8826264822414dbab31c1aeaeec6
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <sys/stat.h> 18#include <string.h> 19#include <stdio.h> 20 21#include "ext4_utils.h" 22#include "ext4.h" 23#include "make_ext4fs.h" 24#include "allocate.h" 25#include "contents.h" 26#include "extent.h" 27#include "indirect.h" 28 29static u32 dentry_size(u32 entries, struct dentry *dentries) 30{ 31 u32 len = 24; 32 unsigned int i; 33 34 for (i = 0; i < entries; i++) { 35 unsigned int dentry_len = 8 + 4 * 36 DIV_ROUND_UP(strlen(dentries[i].filename), 4); 37 if (len % info.block_size + dentry_len > info.block_size) 38 len += info.block_size - (len % info.block_size); 39 len += dentry_len; 40 } 41 42 return len; 43} 44 45#define PAD_TO(x, y) (x + (y - (x % y))) 46 47static struct ext4_dir_entry_2 *add_dentry(u8 *data, u32 *offset, 48 struct ext4_dir_entry_2 *prev, u32 inode, const char *name, 49 u8 file_type) 50{ 51 u8 name_len = strlen(name); 52 u16 rec_len = 8 + PAD_TO(name_len, 4); 53 struct ext4_dir_entry_2 *dentry; 54 55 u32 start_block = *offset / info.block_size; 56 u32 end_block = (*offset + rec_len) / info.block_size; 57 if (start_block != end_block) { 58 /* Adding this dentry will cross a block boundary, so pad the previous 59 dentry to the block boundary */ 60 if (!prev) 61 critical_error("no prev"); 62 prev->rec_len += end_block * info.block_size - *offset; 63 *offset = end_block * info.block_size; 64 } 65 66 dentry = (struct ext4_dir_entry_2 *)(data + *offset); 67 dentry->inode = inode; 68 dentry->rec_len = rec_len; 69 dentry->name_len = name_len; 70 dentry->file_type = file_type; 71 memcpy(dentry->name, name, name_len); 72 73 *offset += rec_len; 74 return dentry; 75} 76 77/* Creates a directory structure for an array of directory entries, dentries, 78 and stores the location of the structure in an inode. The new inode's 79 .. link is set to dir_inode_num. Stores the location of the inode number 80 of each directory entry into dentries[i].inode, to be filled in later 81 when the inode for the entry is allocated. Returns the inode number of the 82 new directory */ 83u32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries, 84 u32 dirs) 85{ 86 struct ext4_inode *inode; 87 u32 blocks = DIV_ROUND_UP(dentry_size(entries, dentries), info.block_size); 88 u64 len = (u64)blocks * info.block_size; 89 u32 offset = 0; 90 u32 inode_num; 91 u8 *data; 92 unsigned int i; 93 struct ext4_dir_entry_2 *dentry; 94 95 if (dir_inode_num) { 96 inode_num = allocate_inode(info); 97 } else { 98 dir_inode_num = EXT4_ROOT_INO; 99 inode_num = EXT4_ROOT_INO; 100 } 101 102 if (inode_num == EXT4_ALLOCATE_FAILED) { 103 error("failed to allocate inode\n"); 104 return EXT4_ALLOCATE_FAILED; 105 } 106 107 add_directory(inode_num); 108 109 inode = get_inode(inode_num); 110 if (inode == NULL) { 111 error("failed to get inode %u", inode_num); 112 return EXT4_ALLOCATE_FAILED; 113 } 114 115 data = inode_allocate_data_extents(inode, len, len); 116 if (data == NULL) { 117 error("failed to allocate %llu extents", len); 118 return EXT4_ALLOCATE_FAILED; 119 } 120 121 inode->i_mode = S_IFDIR; 122 inode->i_links_count = dirs + 2; 123 inode->i_flags |= aux_info.default_i_flags; 124 125 dentry = NULL; 126 127 dentry = add_dentry(data, &offset, NULL, inode_num, ".", EXT4_FT_DIR); 128 if (!dentry) { 129 error("failed to add . directory"); 130 return EXT4_ALLOCATE_FAILED; 131 } 132 133 dentry = add_dentry(data, &offset, dentry, dir_inode_num, "..", EXT4_FT_DIR); 134 if (!dentry) { 135 error("failed to add .. directory"); 136 return EXT4_ALLOCATE_FAILED; 137 } 138 139 for (i = 0; i < entries; i++) { 140 dentry = add_dentry(data, &offset, dentry, 0, dentries[i].filename, 141 dentries[i].file_type); 142 dentries[i].inode = &dentry->inode; 143 if (!dentry) { 144 error("failed to add directory"); 145 return EXT4_ALLOCATE_FAILED; 146 } 147 } 148 149 dentry = (struct ext4_dir_entry_2 *)(data + offset); 150 dentry->inode = 0; 151 dentry->rec_len = len - offset; 152 dentry->name_len = 0; 153 dentry->file_type = EXT4_FT_UNKNOWN; 154 155 return inode_num; 156} 157 158/* Creates a file on disk. Returns the inode number of the new file */ 159u32 make_file(const char *filename, u64 len) 160{ 161 struct ext4_inode *inode; 162 u32 inode_num; 163 164 inode_num = allocate_inode(info); 165 if (inode_num == EXT4_ALLOCATE_FAILED) { 166 error("failed to allocate inode\n"); 167 return EXT4_ALLOCATE_FAILED; 168 } 169 170 inode = get_inode(inode_num); 171 if (inode == NULL) { 172 error("failed to get inode %u", inode_num); 173 return EXT4_ALLOCATE_FAILED; 174 } 175 176 if (len > 0) 177 inode_allocate_file_extents(inode, len, filename); 178 179 inode->i_mode = S_IFREG; 180 inode->i_links_count = 1; 181 inode->i_flags |= aux_info.default_i_flags; 182 183 return inode_num; 184} 185 186/* Creates a file on disk. Returns the inode number of the new file */ 187u32 make_link(const char *filename, const char *link) 188{ 189 struct ext4_inode *inode; 190 u32 inode_num; 191 u32 len = strlen(link); 192 193 inode_num = allocate_inode(info); 194 if (inode_num == EXT4_ALLOCATE_FAILED) { 195 error("failed to allocate inode\n"); 196 return EXT4_ALLOCATE_FAILED; 197 } 198 199 inode = get_inode(inode_num); 200 if (inode == NULL) { 201 error("failed to get inode %u", inode_num); 202 return EXT4_ALLOCATE_FAILED; 203 } 204 205 inode->i_mode = S_IFLNK; 206 inode->i_links_count = 1; 207 inode->i_flags |= aux_info.default_i_flags; 208 inode->i_size_lo = len; 209 210 if (len + 1 <= sizeof(inode->i_block)) { 211 /* Fast symlink */ 212 memcpy((char*)inode->i_block, link, len); 213 } else { 214 u8 *data = inode_allocate_data_indirect(inode, info.block_size, info.block_size); 215 memcpy(data, link, len); 216 inode->i_blocks_lo = info.block_size / 512; 217 } 218 219 return inode_num; 220} 221 222int inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime) 223{ 224 struct ext4_inode *inode = get_inode(inode_num); 225 226 if (!inode) 227 return -1; 228 229 inode->i_mode |= mode; 230 inode->i_uid = uid; 231 inode->i_gid = gid; 232 inode->i_mtime = mtime; 233 inode->i_atime = mtime; 234 inode->i_ctime = mtime; 235 236 return 0; 237} 238