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