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