1/* 2 * rw_bitmaps.c --- routines to read and write the inode and block bitmaps. 3 * 4 * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12#include "config.h" 13#include <stdio.h> 14#include <string.h> 15#if HAVE_UNISTD_H 16#include <unistd.h> 17#endif 18#include <fcntl.h> 19#include <time.h> 20#ifdef HAVE_SYS_STAT_H 21#include <sys/stat.h> 22#endif 23#ifdef HAVE_SYS_TYPES_H 24#include <sys/types.h> 25#endif 26 27#include "ext2_fs.h" 28#include "ext2fs.h" 29#include "e2image.h" 30 31static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block) 32{ 33 dgrp_t i; 34 unsigned int j; 35 int block_nbytes, inode_nbytes; 36 unsigned int nbits; 37 errcode_t retval; 38 char *block_buf = NULL, *inode_buf = NULL; 39 int csum_flag; 40 blk64_t blk; 41 blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); 42 ext2_ino_t ino_itr = 1; 43 44 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 45 46 if (!(fs->flags & EXT2_FLAG_RW)) 47 return EXT2_ET_RO_FILSYS; 48 49 csum_flag = ext2fs_has_group_desc_csum(fs); 50 51 inode_nbytes = block_nbytes = 0; 52 if (do_block) { 53 block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; 54 retval = io_channel_alloc_buf(fs->io, 0, &block_buf); 55 if (retval) 56 goto errout; 57 memset(block_buf, 0xff, fs->blocksize); 58 } 59 if (do_inode) { 60 inode_nbytes = (size_t) 61 ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); 62 retval = io_channel_alloc_buf(fs->io, 0, &inode_buf); 63 if (retval) 64 goto errout; 65 memset(inode_buf, 0xff, fs->blocksize); 66 } 67 68 for (i = 0; i < fs->group_desc_count; i++) { 69 if (!do_block) 70 goto skip_block_bitmap; 71 72 if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) 73 ) 74 goto skip_this_block_bitmap; 75 76 retval = ext2fs_get_block_bitmap_range2(fs->block_map, 77 blk_itr, block_nbytes << 3, block_buf); 78 if (retval) 79 goto errout; 80 81 if (i == fs->group_desc_count - 1) { 82 /* Force bitmap padding for the last group */ 83 nbits = EXT2FS_NUM_B2C(fs, 84 ((ext2fs_blocks_count(fs->super) 85 - (__u64) fs->super->s_first_data_block) 86 % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super))); 87 if (nbits) 88 for (j = nbits; j < fs->blocksize * 8; j++) 89 ext2fs_set_bit(j, block_buf); 90 } 91 92 retval = ext2fs_block_bitmap_csum_set(fs, i, block_buf, 93 block_nbytes); 94 if (retval) 95 return retval; 96 ext2fs_group_desc_csum_set(fs, i); 97 98 blk = ext2fs_block_bitmap_loc(fs, i); 99 if (blk) { 100 retval = io_channel_write_blk64(fs->io, blk, 1, 101 block_buf); 102 if (retval) { 103 retval = EXT2_ET_BLOCK_BITMAP_WRITE; 104 goto errout; 105 } 106 } 107 skip_this_block_bitmap: 108 blk_itr += block_nbytes << 3; 109 skip_block_bitmap: 110 111 if (!do_inode) 112 continue; 113 114 if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) 115 ) 116 goto skip_this_inode_bitmap; 117 118 retval = ext2fs_get_inode_bitmap_range2(fs->inode_map, 119 ino_itr, inode_nbytes << 3, inode_buf); 120 if (retval) 121 goto errout; 122 123 retval = ext2fs_inode_bitmap_csum_set(fs, i, inode_buf, 124 inode_nbytes); 125 if (retval) 126 goto errout; 127 ext2fs_group_desc_csum_set(fs, i); 128 129 blk = ext2fs_inode_bitmap_loc(fs, i); 130 if (blk) { 131 retval = io_channel_write_blk64(fs->io, blk, 1, 132 inode_buf); 133 if (retval) { 134 retval = EXT2_ET_INODE_BITMAP_WRITE; 135 goto errout; 136 } 137 } 138 skip_this_inode_bitmap: 139 ino_itr += inode_nbytes << 3; 140 141 } 142 if (do_block) { 143 fs->flags &= ~EXT2_FLAG_BB_DIRTY; 144 ext2fs_free_mem(&block_buf); 145 } 146 if (do_inode) { 147 fs->flags &= ~EXT2_FLAG_IB_DIRTY; 148 ext2fs_free_mem(&inode_buf); 149 } 150 return 0; 151errout: 152 if (inode_buf) 153 ext2fs_free_mem(&inode_buf); 154 if (block_buf) 155 ext2fs_free_mem(&block_buf); 156 return retval; 157} 158 159static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs) 160{ 161 dgrp_t i; 162 blk64_t blk; 163 ext2fs_block_bitmap bmap = fs->block_map; 164 165 for (i = 0; i < fs->group_desc_count; i++) { 166 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)) 167 continue; 168 169 ext2fs_reserve_super_and_bgd(fs, i, bmap); 170 171 /* 172 * Mark the blocks used for the inode table 173 */ 174 blk = ext2fs_inode_table_loc(fs, i); 175 if (blk) 176 ext2fs_mark_block_bitmap_range2(bmap, blk, 177 fs->inode_blocks_per_group); 178 179 /* 180 * Mark block used for the block bitmap 181 */ 182 blk = ext2fs_block_bitmap_loc(fs, i); 183 if (blk) 184 ext2fs_mark_block_bitmap2(bmap, blk); 185 186 /* 187 * Mark block used for the inode bitmap 188 */ 189 blk = ext2fs_inode_bitmap_loc(fs, i); 190 if (blk) 191 ext2fs_mark_block_bitmap2(bmap, blk); 192 } 193 return 0; 194} 195 196static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) 197{ 198 dgrp_t i; 199 char *block_bitmap = 0, *inode_bitmap = 0; 200 char *buf; 201 errcode_t retval; 202 int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; 203 int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; 204 int csum_flag; 205 unsigned int cnt; 206 blk64_t blk; 207 blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); 208 blk64_t blk_cnt; 209 ext2_ino_t ino_itr = 1; 210 ext2_ino_t ino_cnt; 211 212 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 213 214 if ((block_nbytes > (int) fs->blocksize) || 215 (inode_nbytes > (int) fs->blocksize)) 216 return EXT2_ET_CORRUPT_SUPERBLOCK; 217 218 fs->write_bitmaps = ext2fs_write_bitmaps; 219 220 csum_flag = ext2fs_has_group_desc_csum(fs); 221 222 retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); 223 if (retval) 224 return retval; 225 if (do_block) { 226 if (fs->block_map) 227 ext2fs_free_block_bitmap(fs->block_map); 228 strcpy(buf, "block bitmap for "); 229 strcat(buf, fs->device_name); 230 retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); 231 if (retval) 232 goto cleanup; 233 retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap); 234 if (retval) 235 goto cleanup; 236 } else 237 block_nbytes = 0; 238 if (do_inode) { 239 if (fs->inode_map) 240 ext2fs_free_inode_bitmap(fs->inode_map); 241 strcpy(buf, "inode bitmap for "); 242 strcat(buf, fs->device_name); 243 retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); 244 if (retval) 245 goto cleanup; 246 retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap); 247 if (retval) 248 goto cleanup; 249 } else 250 inode_nbytes = 0; 251 ext2fs_free_mem(&buf); 252 253 if (fs->flags & EXT2_FLAG_IMAGE_FILE) { 254 blk = (fs->image_header->offset_inodemap / fs->blocksize); 255 ino_cnt = fs->super->s_inodes_count; 256 while (inode_nbytes > 0) { 257 retval = io_channel_read_blk64(fs->image_io, blk++, 258 1, inode_bitmap); 259 if (retval) 260 goto cleanup; 261 cnt = fs->blocksize << 3; 262 if (cnt > ino_cnt) 263 cnt = ino_cnt; 264 retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, 265 ino_itr, cnt, inode_bitmap); 266 if (retval) 267 goto cleanup; 268 ino_itr += fs->blocksize << 3; 269 ino_cnt -= fs->blocksize << 3; 270 inode_nbytes -= fs->blocksize; 271 } 272 blk = (fs->image_header->offset_blockmap / 273 fs->blocksize); 274 blk_cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, 275 fs->group_desc_count); 276 while (block_nbytes > 0) { 277 retval = io_channel_read_blk64(fs->image_io, blk++, 278 1, block_bitmap); 279 if (retval) 280 goto cleanup; 281 cnt = fs->blocksize << 3; 282 if (cnt > blk_cnt) 283 cnt = blk_cnt; 284 retval = ext2fs_set_block_bitmap_range2(fs->block_map, 285 blk_itr, cnt, block_bitmap); 286 if (retval) 287 goto cleanup; 288 blk_itr += fs->blocksize << 3; 289 blk_cnt -= fs->blocksize << 3; 290 block_nbytes -= fs->blocksize; 291 } 292 goto success_cleanup; 293 } 294 295 for (i = 0; i < fs->group_desc_count; i++) { 296 if (block_bitmap) { 297 blk = ext2fs_block_bitmap_loc(fs, i); 298 if (csum_flag && 299 ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && 300 ext2fs_group_desc_csum_verify(fs, i)) 301 blk = 0; 302 if (blk) { 303 retval = io_channel_read_blk64(fs->io, blk, 304 1, block_bitmap); 305 if (retval) { 306 retval = EXT2_ET_BLOCK_BITMAP_READ; 307 goto cleanup; 308 } 309 /* verify block bitmap checksum */ 310 if (!(fs->flags & 311 EXT2_FLAG_IGNORE_CSUM_ERRORS) && 312 !ext2fs_block_bitmap_csum_verify(fs, i, 313 block_bitmap, block_nbytes)) { 314 retval = 315 EXT2_ET_BLOCK_BITMAP_CSUM_INVALID; 316 goto cleanup; 317 } 318 } else 319 memset(block_bitmap, 0, block_nbytes); 320 cnt = block_nbytes << 3; 321 retval = ext2fs_set_block_bitmap_range2(fs->block_map, 322 blk_itr, cnt, block_bitmap); 323 if (retval) 324 goto cleanup; 325 blk_itr += block_nbytes << 3; 326 } 327 if (inode_bitmap) { 328 blk = ext2fs_inode_bitmap_loc(fs, i); 329 if (csum_flag && 330 ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && 331 ext2fs_group_desc_csum_verify(fs, i)) 332 blk = 0; 333 if (blk) { 334 retval = io_channel_read_blk64(fs->io, blk, 335 1, inode_bitmap); 336 if (retval) { 337 retval = EXT2_ET_INODE_BITMAP_READ; 338 goto cleanup; 339 } 340 341 /* verify inode bitmap checksum */ 342 if (!(fs->flags & 343 EXT2_FLAG_IGNORE_CSUM_ERRORS) && 344 !ext2fs_inode_bitmap_csum_verify(fs, i, 345 inode_bitmap, inode_nbytes)) { 346 retval = 347 EXT2_ET_INODE_BITMAP_CSUM_INVALID; 348 goto cleanup; 349 } 350 } else 351 memset(inode_bitmap, 0, inode_nbytes); 352 cnt = inode_nbytes << 3; 353 retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, 354 ino_itr, cnt, inode_bitmap); 355 if (retval) 356 goto cleanup; 357 ino_itr += inode_nbytes << 3; 358 } 359 } 360 361 /* Mark group blocks for any BLOCK_UNINIT groups */ 362 if (do_block) { 363 retval = mark_uninit_bg_group_blocks(fs); 364 if (retval) 365 goto cleanup; 366 } 367 368success_cleanup: 369 if (inode_bitmap) 370 ext2fs_free_mem(&inode_bitmap); 371 if (block_bitmap) 372 ext2fs_free_mem(&block_bitmap); 373 return 0; 374 375cleanup: 376 if (do_block) { 377 ext2fs_free_mem(&fs->block_map); 378 fs->block_map = 0; 379 } 380 if (do_inode) { 381 ext2fs_free_mem(&fs->inode_map); 382 fs->inode_map = 0; 383 } 384 if (inode_bitmap) 385 ext2fs_free_mem(&inode_bitmap); 386 if (block_bitmap) 387 ext2fs_free_mem(&block_bitmap); 388 if (buf) 389 ext2fs_free_mem(&buf); 390 return retval; 391} 392 393errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs) 394{ 395 return read_bitmaps(fs, 1, 0); 396} 397 398errcode_t ext2fs_read_block_bitmap(ext2_filsys fs) 399{ 400 return read_bitmaps(fs, 0, 1); 401} 402 403errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs) 404{ 405 return write_bitmaps(fs, 1, 0); 406} 407 408errcode_t ext2fs_write_block_bitmap (ext2_filsys fs) 409{ 410 return write_bitmaps(fs, 0, 1); 411} 412 413errcode_t ext2fs_read_bitmaps(ext2_filsys fs) 414{ 415 if (fs->inode_map && fs->block_map) 416 return 0; 417 418 return read_bitmaps(fs, !fs->inode_map, !fs->block_map); 419} 420 421errcode_t ext2fs_write_bitmaps(ext2_filsys fs) 422{ 423 int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs); 424 int do_block = fs->block_map && ext2fs_test_bb_dirty(fs); 425 426 if (!do_inode && !do_block) 427 return 0; 428 429 return write_bitmaps(fs, do_inode, do_block); 430} 431