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