contents.c revision ec0a2e83dc66d67addeb90e83144187691852a3e
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" 28ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 29ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 dentry_size(u32 entries, struct dentry *dentries) 30ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 31ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 len = 24; 32ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross unsigned int i; 33ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 34ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross for (i = 0; i < entries; i++) { 35ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross unsigned int dentry_len = 8 + 4 36ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * DIV_ROUND_UP(strlen(dentries[i].filename), 4); 37ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (len % info.block_size + dentry_len > info.block_size) 38ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross len += info.block_size - (len % info.block_size); 39ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross len += dentry_len; 40ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 41ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 42ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return len; 43ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 44ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 45ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#define PAD_TO(x, y) (x + (y - (x % y))) 46ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 47ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic struct ext4_dir_entry_2 *add_dentry(u8 *data, u32 *offset, 48ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_dir_entry_2 *prev, u32 inode, const char *name, 49ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 file_type) 50ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 51ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 name_len = strlen(name); 52ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u16 rec_len = 8 + PAD_TO(name_len, 4); 53ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_dir_entry_2 *dentry; 54ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 55ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 start_block = *offset / info.block_size; 56ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 end_block = (*offset + rec_len) / info.block_size; 57ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (start_block != end_block) { 58ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross /* Adding this dentry will cross a block boundary, so pad the previous 59ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry to the block boundary */ 60ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!prev) 61ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross critical_error("no prev"); 62ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross prev->rec_len += end_block * info.block_size - *offset; 63ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *offset = end_block * info.block_size; 64ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 65ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 66ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = (struct ext4_dir_entry_2 *)(data + *offset); 67ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->inode = inode; 68ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->rec_len = rec_len; 69ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->name_len = name_len; 70ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->file_type = file_type; 71ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross memcpy(dentry->name, name, name_len); 72ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 73ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *offset += rec_len; 74ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return dentry; 75ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 76ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 77ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a directory structure for an array of directory entries, dentries, 78ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross and stores the location of the structure in an inode. The new inode's 79ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross .. link is set to dir_inode_num. Stores the location of the inode number 80ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross of each directory entry into dentries[i].inode, to be filled in later 81ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross when the inode for the entry is allocated. Returns the inode number of the 82ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross new directory */ 83ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries, 84ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 dirs) 85ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 86ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode; 87ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 blocks = DIV_ROUND_UP(dentry_size(entries, dentries), info.block_size); 88ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u64 len = (u64)blocks * info.block_size; 89ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 offset = 0; 90ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 inode_num; 91ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 *data; 92ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross unsigned int i; 93ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_dir_entry_2 *dentry; 94ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 95ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (dir_inode_num) { 96ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = allocate_inode(info); 97ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } else { 98ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dir_inode_num = EXT4_ROOT_INO; 99ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = EXT4_ROOT_INO; 100ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 101ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 102ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode_num == EXT4_ALLOCATE_FAILED) { 103ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to allocate inode\n"); 104ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 105ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 106ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 107ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross add_directory(inode_num); 108ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 109ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode = get_inode(inode_num); 110ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode == NULL) { 111ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to get inode %u", inode_num); 112ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 113ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 114ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 115ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross data = inode_allocate_data_extents(inode, len, len); 116ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (data == NULL) { 117ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to allocate %llu extents", len); 118ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 119ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 120ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 121ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode = S_IFDIR; 122ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_links_count = dirs + 2; 123ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_flags |= aux_info.default_i_flags; 124ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 125ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = NULL; 126ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 127ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = add_dentry(data, &offset, NULL, inode_num, ".", EXT4_FT_DIR); 128ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!dentry) { 129ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to add . directory"); 130ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 131ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 132ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 133ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = add_dentry(data, &offset, dentry, dir_inode_num, "..", EXT4_FT_DIR); 134ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!dentry) { 135ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to add .. directory"); 136ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 137ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 138ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 139ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross for (i = 0; i < entries; i++) { 140ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = add_dentry(data, &offset, dentry, 0, dentries[i].filename, 141ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentries[i].file_type); 142ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentries[i].inode = &dentry->inode; 143ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!dentry) { 144ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to add directory"); 145ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 146ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 147ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 148ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 149ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry = (struct ext4_dir_entry_2 *)(data + offset); 150ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->inode = 0; 151ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->rec_len = len - offset; 152ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->name_len = 0; 153ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross dentry->file_type = EXT4_FT_UNKNOWN; 154ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 155ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return inode_num; 156ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 157ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 158ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk. Returns the inode number of the new file */ 159ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_file(const char *filename, u64 len) 160ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 161ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode; 162ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 inode_num; 163ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 164ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = allocate_inode(info); 165ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode_num == EXT4_ALLOCATE_FAILED) { 166ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to allocate inode\n"); 167ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 168ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 169ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 170ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode = get_inode(inode_num); 171ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode == NULL) { 172ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to get inode %u", inode_num); 173ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 174ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 175ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 176ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_allocate_file_extents(inode, len, filename); 177ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 178ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode = S_IFREG; 179ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_links_count = 1; 180ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_flags |= aux_info.default_i_flags; 181ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 182ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return inode_num; 183ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 184ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 185ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Creates a file on disk. Returns the inode number of the new file */ 186ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossu32 make_link(const char *filename, const char *link) 187ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 188ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode; 189ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 inode_num; 190ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u32 len = strlen(link); 191ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 192ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode_num = allocate_inode(info); 193ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode_num == EXT4_ALLOCATE_FAILED) { 194ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to allocate inode\n"); 195ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 196ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 197ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 198ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode = get_inode(inode_num); 199ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (inode == NULL) { 200ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross error("failed to get inode %u", inode_num); 201ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return EXT4_ALLOCATE_FAILED; 202ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 203ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 204ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode = S_IFLNK; 205ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_links_count = 1; 206ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_flags |= aux_info.default_i_flags; 207ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_size_lo = len; 208ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 209ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (len + 1 <= sizeof(inode->i_block)) { 210ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross /* Fast symlink */ 211ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross memcpy((char*)inode->i_block, link, len); 212ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } else { 213ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross u8 *data = inode_allocate_data_indirect(inode, info.block_size, info.block_size); 214ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross memcpy(data, link, len); 215ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_blocks_lo = info.block_size / 512; 216ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross } 217ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 218ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return inode_num; 219ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 220ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 221ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossint inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid) 222ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{ 223ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross struct ext4_inode *inode = get_inode(inode_num); 224ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 225ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross if (!inode) 226ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return -1; 227ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 228ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_mode |= mode; 229ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_uid = uid; 230ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross inode->i_gid = gid; 231ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross 232ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross return 0; 233ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross} 234