bmap.c revision c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4e
1/* 2 * bmap.c --- logical to physical block mapping 3 * 4 * Copyright (C) 1997 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#include <stdio.h> 13#include <string.h> 14#if HAVE_UNISTD_H 15#include <unistd.h> 16#endif 17 18#include "ext2_fs.h" 19#include "ext2fs.h" 20 21#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS) 22#define _BMAP_INLINE_ __inline__ 23#else 24#define _BMAP_INLINE_ 25#endif 26 27extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, 28 struct ext2_inode *inode, 29 char *block_buf, int bmap_flags, 30 blk_t block, blk_t *phys_blk); 31 32#define BMAP_ALLOC 1 33 34#define inode_bmap(inode, nr) ((inode)->i_block[(nr)]) 35 36static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags, 37 blk_t ind, char *block_buf, 38 int *blocks_alloc, 39 blk_t nr, blk_t *ret_blk) 40{ 41 errcode_t retval; 42 blk_t b; 43 44 if (!ind) { 45 *ret_blk = 0; 46 return 0; 47 } 48 retval = io_channel_read_blk(fs->io, ind, 1, block_buf); 49 if (retval) 50 return retval; 51 52 b = ((blk_t *) block_buf)[nr]; 53 54#ifdef EXT2FS_ENABLE_SWAPFS 55 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || 56 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) 57 b = ext2fs_swab32(b); 58#endif 59 60 if (!b && (flags & BMAP_ALLOC)) { 61 b = nr ? ((blk_t *) block_buf)[nr-1] : 0; 62 retval = ext2fs_alloc_block(fs, b, 63 block_buf + fs->blocksize, &b); 64 if (retval) 65 return retval; 66 67#ifdef EXT2FS_ENABLE_SWAPFS 68 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || 69 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) 70 ((blk_t *) block_buf)[nr] = ext2fs_swab32(b); 71 else 72#endif 73 ((blk_t *) block_buf)[nr] = b; 74 75 retval = io_channel_write_blk(fs->io, ind, 1, block_buf); 76 if (retval) 77 return retval; 78 79 (*blocks_alloc)++; 80 } 81 82 *ret_blk = b; 83 return 0; 84} 85 86static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags, 87 blk_t dind, char *block_buf, 88 int *blocks_alloc, 89 blk_t nr, blk_t *ret_blk) 90{ 91 blk_t b; 92 errcode_t retval; 93 blk_t addr_per_block; 94 95 addr_per_block = (blk_t) fs->blocksize >> 2; 96 97 retval = block_ind_bmap(fs, flags, dind, block_buf, blocks_alloc, 98 nr / addr_per_block, &b); 99 if (retval) 100 return retval; 101 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, 102 nr % addr_per_block, ret_blk); 103 return retval; 104} 105 106static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags, 107 blk_t tind, char *block_buf, 108 int *blocks_alloc, 109 blk_t nr, blk_t *ret_blk) 110{ 111 blk_t b; 112 errcode_t retval; 113 blk_t addr_per_block; 114 115 addr_per_block = (blk_t) fs->blocksize >> 2; 116 117 retval = block_dind_bmap(fs, flags, tind, block_buf, blocks_alloc, 118 nr / addr_per_block, &b); 119 if (retval) 120 return retval; 121 retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, 122 nr % addr_per_block, ret_blk); 123 return retval; 124} 125 126errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, 127 char *block_buf, int bmap_flags, blk_t block, 128 blk_t *phys_blk) 129{ 130 struct ext2_inode inode_buf; 131 blk_t addr_per_block; 132 blk_t b; 133 char *buf = 0; 134 errcode_t retval = 0; 135 int blocks_alloc = 0; 136 137 *phys_blk = 0; 138 139 /* Read inode structure if necessary */ 140 if (!inode) { 141 retval = ext2fs_read_inode(fs, ino, &inode_buf); 142 if (retval) 143 return retval; 144 inode = &inode_buf; 145 } 146 addr_per_block = (blk_t) fs->blocksize >> 2; 147 148 if (!block_buf) { 149 retval = ext2fs_get_mem(fs->blocksize * 2, &buf); 150 if (retval) 151 return retval; 152 block_buf = buf; 153 } 154 155 if (block < EXT2_NDIR_BLOCKS) { 156 *phys_blk = inode_bmap(inode, block); 157 b = block ? inode_bmap(inode, block-1) : 0; 158 159 if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { 160 retval = ext2fs_alloc_block(fs, b, block_buf, &b); 161 if (retval) 162 goto done; 163 inode_bmap(inode, block) = b; 164 blocks_alloc++; 165 *phys_blk = b; 166 } 167 goto done; 168 } 169 170 /* Indirect block */ 171 block -= EXT2_NDIR_BLOCKS; 172 if (block < addr_per_block) { 173 b = inode_bmap(inode, EXT2_IND_BLOCK); 174 if (!b) { 175 if (!(bmap_flags & BMAP_ALLOC)) 176 goto done; 177 178 b = inode_bmap(inode, EXT2_IND_BLOCK-1); 179 retval = ext2fs_alloc_block(fs, b, block_buf, &b); 180 if (retval) 181 goto done; 182 inode_bmap(inode, EXT2_IND_BLOCK) = b; 183 blocks_alloc++; 184 } 185 retval = block_ind_bmap(fs, bmap_flags, b, block_buf, 186 &blocks_alloc, block, phys_blk); 187 goto done; 188 } 189 190 /* Doubly indirect block */ 191 block -= addr_per_block; 192 if (block < addr_per_block * addr_per_block) { 193 b = inode_bmap(inode, EXT2_DIND_BLOCK); 194 if (!b) { 195 if (!(bmap_flags & BMAP_ALLOC)) 196 goto done; 197 198 b = inode_bmap(inode, EXT2_IND_BLOCK); 199 retval = ext2fs_alloc_block(fs, b, block_buf, &b); 200 if (retval) 201 goto done; 202 inode_bmap(inode, EXT2_DIND_BLOCK) = b; 203 blocks_alloc++; 204 } 205 retval = block_dind_bmap(fs, bmap_flags, b, block_buf, 206 &blocks_alloc, block, phys_blk); 207 goto done; 208 } 209 210 /* Triply indirect block */ 211 block -= addr_per_block * addr_per_block; 212 b = inode_bmap(inode, EXT2_TIND_BLOCK); 213 if (!b) { 214 if (!(bmap_flags & BMAP_ALLOC)) 215 goto done; 216 217 b = inode_bmap(inode, EXT2_DIND_BLOCK); 218 retval = ext2fs_alloc_block(fs, b, block_buf, &b); 219 if (retval) 220 goto done; 221 inode_bmap(inode, EXT2_TIND_BLOCK) = b; 222 blocks_alloc++; 223 } 224 retval = block_tind_bmap(fs, bmap_flags, b, block_buf, 225 &blocks_alloc, block, phys_blk); 226done: 227 if (buf) 228 ext2fs_free_mem(&buf); 229 if ((retval == 0) && blocks_alloc) { 230 inode->i_blocks += (blocks_alloc * fs->blocksize) / 512; 231 retval = ext2fs_write_inode(fs, ino, inode); 232 } 233 return retval; 234} 235 236 237 238