gen_bitmap64.c revision 69365c689b7164014e539b40ef62fc8eb804a05c
1/* 2 * gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and 3 * block bitmaps. 4 * 5 * Copyright (C) 2007, 2008 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#include <fcntl.h> 19#include <time.h> 20#include <errno.h> 21#if HAVE_SYS_STAT_H 22#include <sys/stat.h> 23#endif 24#if HAVE_SYS_TYPES_H 25#include <sys/types.h> 26#endif 27 28#include "ext2_fs.h" 29#include "ext2fsP.h" 30#include "bmap64.h" 31 32/* 33 * Design of 64-bit bitmaps 34 * 35 * In order maintain ABI compatibility with programs that don't 36 * understand about 64-bit blocks/inodes, 37 * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap() 38 * will create old-style bitmaps unless the application passes the 39 * flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is 40 * passed, then we know the application has been recompiled, so we can 41 * use the new-style bitmaps. If it is not passed, we have to return 42 * an error if trying to open a filesystem which needs 64-bit bitmaps. 43 * 44 * The new bitmaps use a new set of structure magic numbers, so that 45 * both the old-style and new-style interfaces can identify which 46 * version of the data structure was used. Both the old-style and 47 * new-style interfaces will support either type of bitmap, although 48 * of course 64-bit operation will only be possible when both the 49 * new-style interface and the new-style bitmap are used. 50 * 51 * For example, the new bitmap interfaces will check the structure 52 * magic numbers and so will be able to detect old-stype bitmap. If 53 * they see an old-style bitmap, they will pass it to the gen_bitmap.c 54 * functions for handling. The same will be true for the old 55 * interfaces as well. 56 * 57 * The new-style interfaces will have several different back-end 58 * implementations, so we can support different encodings that are 59 * appropriate for different applications. In general the default 60 * should be whatever makes sense, and what the application/library 61 * will use. However, e2fsck may need specialized implementations for 62 * its own uses. For example, when doing parent directory pointer 63 * loop detections in pass 3, the bitmap will *always* be sparse, so 64 * e2fsck can request an encoding which is optimized for that. 65 */ 66 67static void warn_bitmap(ext2fs_generic_bitmap bitmap, 68 int code, __u64 arg) 69{ 70#ifndef OMIT_COM_ERR 71 if (bitmap->description) 72 com_err(0, bitmap->base_error_code+code, 73 "#%llu for %s", arg, bitmap->description); 74 else 75 com_err(0, bitmap->base_error_code + code, "#%llu", arg); 76#endif 77} 78 79 80errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, 81 int type, __u64 start, __u64 end, 82 __u64 real_end, 83 const char *descr, 84 ext2fs_generic_bitmap *ret) 85{ 86 ext2fs_generic_bitmap bitmap; 87 struct ext2_bitmap_ops *ops; 88 errcode_t retval; 89 90 switch (type) { 91 case EXT2FS_BMAP64_BITARRAY: 92 ops = &ext2fs_blkmap64_bitarray; 93 break; 94 default: 95 return EINVAL; 96 } 97 98 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 99 &bitmap); 100 if (retval) 101 return retval; 102 103 /* XXX factor out, repeated in copy_bmap */ 104 bitmap->magic = magic; 105 bitmap->fs = fs; 106 bitmap->start = start; 107 bitmap->end = end; 108 bitmap->real_end = real_end; 109 bitmap->bitmap_ops = ops; 110 switch (magic) { 111 case EXT2_ET_MAGIC_INODE_BITMAP64: 112 bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; 113 break; 114 case EXT2_ET_MAGIC_BLOCK_BITMAP64: 115 bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; 116 break; 117 default: 118 bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; 119 } 120 if (descr) { 121 retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); 122 if (retval) { 123 ext2fs_free_mem(&bitmap); 124 return retval; 125 } 126 strcpy(bitmap->description, descr); 127 } else 128 bitmap->description = 0; 129 130 retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); 131 if (retval) { 132 ext2fs_free_mem(&bitmap); 133 ext2fs_free_mem(&bitmap->description); 134 return retval; 135 } 136 137 *ret = bitmap; 138 return 0; 139} 140 141void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap) 142{ 143 if (!bmap) 144 return; 145 146 if (EXT2FS_IS_32_BITMAP(bmap)) { 147 ext2fs_free_generic_bitmap((ext2fs_generic_bitmap) bmap); 148 return; 149 } 150 151 if (!EXT2FS_IS_64_BITMAP(bmap)) 152 return; 153 154 bmap->bitmap_ops->free_bmap(bmap); 155 156 if (bmap->description) { 157 ext2fs_free_mem(&bmap->description); 158 bmap->description = 0; 159 } 160 bmap->magic = 0; 161} 162 163errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, 164 ext2fs_generic_bitmap *dest) 165{ 166 char *descr, *new_descr; 167 ext2fs_generic_bitmap new_bmap; 168 errcode_t retval; 169 170 if (!src) 171 return EINVAL; 172 173 if (EXT2FS_IS_32_BITMAP(src)) 174 return ext2fs_copy_generic_bitmap((ext2fs_generic_bitmap) src, 175 (ext2fs_generic_bitmap *) dest); 176 177 if (!EXT2FS_IS_64_BITMAP(src)) 178 return EINVAL; 179 180 /* Allocate a new bitmap struct */ 181 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 182 &new_bmap); 183 if (retval) 184 return retval; 185 186 /* Copy all the high-level parts over */ 187 new_bmap->magic = src->magic; 188 new_bmap->fs = src->fs; 189 new_bmap->start = src->start; 190 new_bmap->end = src->end; 191 new_bmap->real_end = src->real_end; 192 new_bmap->bitmap_ops = src->bitmap_ops; 193 new_bmap->base_error_code = src->base_error_code; 194 195 descr = src->description; 196 if (descr) { 197 retval = ext2fs_get_mem(strlen(descr)+1, &new_descr); 198 if (retval) { 199 ext2fs_free_mem(&new_bmap); 200 return retval; 201 } 202 strcpy(new_descr, descr); 203 new_bmap->description = new_descr; 204 } 205 206 retval = src->bitmap_ops->copy_bmap(src, new_bmap); 207 if (retval) { 208 ext2fs_free_mem(&new_bmap->description); 209 ext2fs_free_mem(&new_bmap); 210 return retval; 211 } 212 213 *dest = new_bmap; 214 215 return 0; 216} 217 218errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, 219 __u64 new_end, 220 __u64 new_real_end) 221{ 222 if (!bmap) 223 return EINVAL; 224 225 if (EXT2FS_IS_32_BITMAP(bmap)) { 226 return ext2fs_resize_generic_bitmap(bmap->magic, 227 new_end, new_real_end, 228 (ext2fs_generic_bitmap) bmap); 229 } 230 231 if (!EXT2FS_IS_64_BITMAP(bmap)) 232 return EINVAL; 233 234 return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); 235} 236 237errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, 238 errcode_t neq, 239 __u64 end, __u64 *oend) 240{ 241 if (!bitmap) 242 return EINVAL; 243 244 if (EXT2FS_IS_32_BITMAP(bitmap)) { 245 ext2_ino_t tmp_oend; 246 int retval; 247 248 retval = ext2fs_fudge_generic_bitmap_end((ext2fs_generic_bitmap) bitmap, 249 bitmap->magic, neq, 250 end, &tmp_oend); 251 if (oend) 252 *oend = tmp_oend; 253 return retval; 254 } 255 256 if (!EXT2FS_IS_64_BITMAP(bitmap)) 257 return EINVAL; 258 259 if (end > bitmap->real_end) 260 return neq; 261 if (oend) 262 *oend = bitmap->end; 263 bitmap->end = end; 264 return 0; 265} 266 267__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap) 268{ 269 if (!bitmap) 270 return EINVAL; 271 272 if (EXT2FS_IS_32_BITMAP(bitmap)) { 273 return ext2fs_get_generic_bitmap_start((ext2fs_generic_bitmap) 274 bitmap); 275 276 } 277 278 if (!EXT2FS_IS_64_BITMAP(bitmap)) 279 return EINVAL; 280 281 return bitmap->start; 282} 283 284__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap) 285{ 286 if (!bitmap) 287 return EINVAL; 288 289 if (EXT2FS_IS_32_BITMAP(bitmap)) { 290 return ext2fs_get_generic_bitmap_end((ext2fs_generic_bitmap) 291 bitmap); 292 293 } 294 295 if (!EXT2FS_IS_64_BITMAP(bitmap)) 296 return EINVAL; 297 298 return bitmap->end; 299} 300 301void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap) 302{ 303 if (EXT2FS_IS_32_BITMAP(bitmap)) { 304 ext2fs_clear_generic_bitmap((ext2fs_generic_bitmap) bitmap); 305 return; 306 } 307 308 bitmap->bitmap_ops->clear_bmap (bitmap); 309} 310 311int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, 312 __u64 arg) 313{ 314 if (!bitmap) 315 return 0; 316 317 if (EXT2FS_IS_32_BITMAP(bitmap)) { 318 if (arg & ~0xffffffffULL) { 319 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bitmap, 320 EXT2FS_MARK_ERROR, 0xffffffff); 321 return 0; 322 } 323 return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) 324 bitmap, arg); 325 } 326 327 if (!EXT2FS_IS_64_BITMAP(bitmap)) 328 return 0; 329 330 if ((arg < bitmap->start) || (arg > bitmap->end)) { 331 warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); 332 return 0; 333 } 334 335 return bitmap->bitmap_ops->mark_bmap(bitmap, arg); 336} 337 338int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, 339 __u64 arg) 340{ 341 if (!bitmap) 342 return 0; 343 344 if (EXT2FS_IS_32_BITMAP(bitmap)) { 345 if (arg & ~0xffffffffULL) { 346 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bitmap, 347 EXT2FS_UNMARK_ERROR, 0xffffffff); 348 return 0; 349 } 350 return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) 351 bitmap, arg); 352 } 353 354 if (!EXT2FS_IS_64_BITMAP(bitmap)) 355 return 0; 356 357 if ((arg < bitmap->start) || (arg > bitmap->end)) { 358 warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); 359 return 0; 360 } 361 362 return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); 363} 364 365int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, 366 __u64 arg) 367{ 368 if (!bitmap) 369 return 0; 370 371 if (EXT2FS_IS_32_BITMAP(bitmap)) { 372 if (arg & ~0xffffffffULL) { 373 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bitmap, 374 EXT2FS_TEST_ERROR, 0xffffffff); 375 return 0; 376 } 377 return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) 378 bitmap, arg); 379 } 380 381 if (!EXT2FS_IS_64_BITMAP(bitmap)) 382 return 0; 383 384 if ((arg < bitmap->start) || (arg > bitmap->end)) { 385 warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); 386 return 0; 387 } 388 389 return bitmap->bitmap_ops->test_bmap(bitmap, arg); 390} 391 392errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, 393 __u64 start, unsigned int num, 394 void *in) 395{ 396 if (!bmap) 397 return EINVAL; 398 399 if (EXT2FS_IS_32_BITMAP(bmap)) { 400 if ((start+num) & ~0xffffffffULL) { 401 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 402 EXT2FS_UNMARK_ERROR, 0xffffffff); 403 return EINVAL; 404 } 405 return ext2fs_set_generic_bitmap_range((ext2fs_generic_bitmap) bmap, 406 bmap->magic, start, num, 407 in); 408 } 409 410 if (!EXT2FS_IS_64_BITMAP(bmap)) 411 return EINVAL; 412 413 return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); 414} 415 416errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, 417 __u64 start, unsigned int num, 418 void *out) 419{ 420 if (!bmap) 421 return EINVAL; 422 423 if (EXT2FS_IS_32_BITMAP(bmap)) { 424 if ((start+num) & ~0xffffffffULL) { 425 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 426 EXT2FS_UNMARK_ERROR, 0xffffffff); 427 return EINVAL; 428 } 429 return ext2fs_get_generic_bitmap_range((ext2fs_generic_bitmap) bmap, 430 bmap->magic, start, num, 431 out); 432 } 433 434 if (!EXT2FS_IS_64_BITMAP(bmap)) 435 return EINVAL; 436 437 return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); 438} 439 440errcode_t ext2fs_compare_generic_bmap(errcode_t neq, 441 ext2fs_generic_bitmap bm1, 442 ext2fs_generic_bitmap bm2) 443{ 444 blk64_t i; 445 446 if (!bm1 || !bm2) 447 return EINVAL; 448 if (bm1->magic != bm2->magic) 449 return EINVAL; 450 451 /* Now we know both bitmaps have the same magic */ 452 if (EXT2FS_IS_32_BITMAP(bm1)) 453 return ext2fs_compare_generic_bitmap(bm1->magic, neq, 454 (ext2fs_generic_bitmap) bm1, 455 (ext2fs_generic_bitmap) bm2); 456 457 if (!EXT2FS_IS_64_BITMAP(bm1)) 458 return EINVAL; 459 460 if ((bm1->start != bm2->start) || 461 (bm1->end != bm2->end)) 462 return neq; 463 464 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) 465 if (ext2fs_test_generic_bmap(bm1, i) != 466 ext2fs_test_generic_bmap(bm2, i)) 467 return neq; 468 469 return 0; 470} 471 472void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap) 473{ 474 __u64 start, num; 475 476 if (EXT2FS_IS_32_BITMAP(bmap)) { 477 ext2fs_set_generic_bitmap_padding((ext2fs_generic_bitmap) bmap); 478 return; 479 } 480 481 start = bmap->end + 1; 482 num = bmap->real_end - bmap->end; 483 bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); 484 /* XXX ought to warn on error */ 485} 486 487int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap, 488 blk64_t block, unsigned int num) 489{ 490 if (!bmap) 491 return EINVAL; 492 493 if (num == 1) 494 return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) 495 bmap, block); 496 497 if (EXT2FS_IS_32_BITMAP(bmap)) { 498 if ((block+num) & ~0xffffffffULL) { 499 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 500 EXT2FS_UNMARK_ERROR, 0xffffffff); 501 return EINVAL; 502 } 503 return ext2fs_test_block_bitmap_range( 504 (ext2fs_generic_bitmap) bmap, block, num); 505 } 506 507 if (!EXT2FS_IS_64_BITMAP(bmap)) 508 return EINVAL; 509 510 return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); 511} 512 513void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap, 514 blk64_t block, unsigned int num) 515{ 516 if (!bmap) 517 return; 518 519 if (EXT2FS_IS_32_BITMAP(bmap)) { 520 if ((block+num) & ~0xffffffffULL) { 521 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 522 EXT2FS_UNMARK_ERROR, 0xffffffff); 523 return; 524 } 525 ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 526 block, num); 527 } 528 529 if (!EXT2FS_IS_64_BITMAP(bmap)) 530 return; 531 532 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 533 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, 534 bmap->description); 535 return; 536 } 537 538 bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); 539} 540 541void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap, 542 blk64_t block, unsigned int num) 543{ 544 if (!bmap) 545 return; 546 547 if (EXT2FS_IS_32_BITMAP(bmap)) { 548 if ((block+num) & ~0xffffffffULL) { 549 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 550 EXT2FS_UNMARK_ERROR, 0xffffffff); 551 return; 552 } 553 ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 554 block, num); 555 } 556 557 if (!EXT2FS_IS_64_BITMAP(bmap)) 558 return; 559 560 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 561 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, 562 bmap->description); 563 return; 564 } 565 566 bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); 567} 568