gen_bitmap64.c revision 5fff975431e02c2b746b023d3c5e6755e910eaa9
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->description); 133 ext2fs_free_mem(&bitmap); 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(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 ext2fs_free_mem(&bmap); 162} 163 164errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, 165 ext2fs_generic_bitmap *dest) 166{ 167 char *descr, *new_descr; 168 ext2fs_generic_bitmap new_bmap; 169 errcode_t retval; 170 171 if (!src) 172 return EINVAL; 173 174 if (EXT2FS_IS_32_BITMAP(src)) 175 return ext2fs_copy_generic_bitmap(src, 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, new_end, 227 new_real_end, bmap); 228 229 if (!EXT2FS_IS_64_BITMAP(bmap)) 230 return EINVAL; 231 232 return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); 233} 234 235errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, 236 errcode_t neq, 237 __u64 end, __u64 *oend) 238{ 239 if (!bitmap) 240 return EINVAL; 241 242 if (EXT2FS_IS_32_BITMAP(bitmap)) { 243 ext2_ino_t tmp_oend; 244 int retval; 245 246 retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic, 247 neq, end, &tmp_oend); 248 if (oend) 249 *oend = tmp_oend; 250 return retval; 251 } 252 253 if (!EXT2FS_IS_64_BITMAP(bitmap)) 254 return EINVAL; 255 256 if (end > bitmap->real_end) 257 return neq; 258 if (oend) 259 *oend = bitmap->end; 260 bitmap->end = end; 261 return 0; 262} 263 264__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap) 265{ 266 if (!bitmap) 267 return EINVAL; 268 269 if (EXT2FS_IS_32_BITMAP(bitmap)) 270 return ext2fs_get_generic_bitmap_start(bitmap); 271 272 if (!EXT2FS_IS_64_BITMAP(bitmap)) 273 return EINVAL; 274 275 return bitmap->start; 276} 277 278__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap) 279{ 280 if (!bitmap) 281 return EINVAL; 282 283 if (EXT2FS_IS_32_BITMAP(bitmap)) 284 return ext2fs_get_generic_bitmap_end(bitmap); 285 286 if (!EXT2FS_IS_64_BITMAP(bitmap)) 287 return EINVAL; 288 289 return bitmap->end; 290} 291 292void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap) 293{ 294 if (EXT2FS_IS_32_BITMAP(bitmap)) 295 ext2fs_clear_generic_bitmap(bitmap); 296 297 bitmap->bitmap_ops->clear_bmap (bitmap); 298} 299 300int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, 301 __u64 arg) 302{ 303 if (!bitmap) 304 return 0; 305 306 if (EXT2FS_IS_32_BITMAP(bitmap)) { 307 if (arg & ~0xffffffffULL) { 308 ext2fs_warn_bitmap2(bitmap, 309 EXT2FS_MARK_ERROR, 0xffffffff); 310 return 0; 311 } 312 return ext2fs_mark_generic_bitmap(bitmap, arg); 313 } 314 315 if (!EXT2FS_IS_64_BITMAP(bitmap)) 316 return 0; 317 318 if ((arg < bitmap->start) || (arg > bitmap->end)) { 319 warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); 320 return 0; 321 } 322 323 return bitmap->bitmap_ops->mark_bmap(bitmap, arg); 324} 325 326int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, 327 __u64 arg) 328{ 329 if (!bitmap) 330 return 0; 331 332 if (EXT2FS_IS_32_BITMAP(bitmap)) { 333 if (arg & ~0xffffffffULL) { 334 ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, 335 0xffffffff); 336 return 0; 337 } 338 return ext2fs_unmark_generic_bitmap(bitmap, arg); 339 } 340 341 if (!EXT2FS_IS_64_BITMAP(bitmap)) 342 return 0; 343 344 if ((arg < bitmap->start) || (arg > bitmap->end)) { 345 warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); 346 return 0; 347 } 348 349 return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); 350} 351 352int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, 353 __u64 arg) 354{ 355 if (!bitmap) 356 return 0; 357 358 if (EXT2FS_IS_32_BITMAP(bitmap)) { 359 if (arg & ~0xffffffffULL) { 360 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, 361 0xffffffff); 362 return 0; 363 } 364 return ext2fs_test_generic_bitmap(bitmap, arg); 365 } 366 367 if (!EXT2FS_IS_64_BITMAP(bitmap)) 368 return 0; 369 370 if ((arg < bitmap->start) || (arg > bitmap->end)) { 371 warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); 372 return 0; 373 } 374 375 return bitmap->bitmap_ops->test_bmap(bitmap, arg); 376} 377 378errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, 379 __u64 start, unsigned int num, 380 void *in) 381{ 382 if (!bmap) 383 return EINVAL; 384 385 if (EXT2FS_IS_32_BITMAP(bmap)) { 386 if ((start+num) & ~0xffffffffULL) { 387 ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR, 388 0xffffffff); 389 return EINVAL; 390 } 391 return ext2fs_set_generic_bitmap_range(bmap, bmap->magic, 392 start, num, in); 393 } 394 395 if (!EXT2FS_IS_64_BITMAP(bmap)) 396 return EINVAL; 397 398 return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); 399} 400 401errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, 402 __u64 start, unsigned int num, 403 void *out) 404{ 405 if (!bmap) 406 return EINVAL; 407 408 if (EXT2FS_IS_32_BITMAP(bmap)) { 409 if ((start+num) & ~0xffffffffULL) { 410 ext2fs_warn_bitmap2(bmap, 411 EXT2FS_UNMARK_ERROR, 0xffffffff); 412 return EINVAL; 413 } 414 return ext2fs_get_generic_bitmap_range(bmap, bmap->magic, 415 start, num, out); 416 } 417 418 if (!EXT2FS_IS_64_BITMAP(bmap)) 419 return EINVAL; 420 421 return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); 422} 423 424errcode_t ext2fs_compare_generic_bmap(errcode_t neq, 425 ext2fs_generic_bitmap bm1, 426 ext2fs_generic_bitmap bm2) 427{ 428 blk64_t i; 429 430 if (!bm1 || !bm2) 431 return EINVAL; 432 if (bm1->magic != bm2->magic) 433 return EINVAL; 434 435 /* Now we know both bitmaps have the same magic */ 436 if (EXT2FS_IS_32_BITMAP(bm1)) 437 return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2); 438 439 if (!EXT2FS_IS_64_BITMAP(bm1)) 440 return EINVAL; 441 442 if ((bm1->start != bm2->start) || 443 (bm1->end != bm2->end)) 444 return neq; 445 446 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) 447 if (ext2fs_test_generic_bmap(bm1, i) != 448 ext2fs_test_generic_bmap(bm2, i)) 449 return neq; 450 451 return 0; 452} 453 454void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap) 455{ 456 __u64 start, num; 457 458 if (EXT2FS_IS_32_BITMAP(bmap)) { 459 ext2fs_set_generic_bitmap_padding(bmap); 460 return; 461 } 462 463 start = bmap->end + 1; 464 num = bmap->real_end - bmap->end; 465 bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); 466 /* XXX ought to warn on error */ 467} 468 469int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap, 470 blk64_t block, unsigned int num) 471{ 472 if (!bmap) 473 return EINVAL; 474 475 if (num == 1) 476 return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) 477 bmap, block); 478 479 if (EXT2FS_IS_32_BITMAP(bmap)) { 480 if ((block+num) & ~0xffffffffULL) { 481 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 482 EXT2FS_UNMARK_ERROR, 0xffffffff); 483 return EINVAL; 484 } 485 return ext2fs_test_block_bitmap_range( 486 (ext2fs_generic_bitmap) bmap, block, num); 487 } 488 489 if (!EXT2FS_IS_64_BITMAP(bmap)) 490 return EINVAL; 491 492 return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); 493} 494 495void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap, 496 blk64_t block, unsigned int num) 497{ 498 if (!bmap) 499 return; 500 501 if (EXT2FS_IS_32_BITMAP(bmap)) { 502 if ((block+num) & ~0xffffffffULL) { 503 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 504 EXT2FS_UNMARK_ERROR, 0xffffffff); 505 return; 506 } 507 ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 508 block, num); 509 } 510 511 if (!EXT2FS_IS_64_BITMAP(bmap)) 512 return; 513 514 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 515 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, 516 bmap->description); 517 return; 518 } 519 520 bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); 521} 522 523void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap, 524 blk64_t block, unsigned int num) 525{ 526 if (!bmap) 527 return; 528 529 if (EXT2FS_IS_32_BITMAP(bmap)) { 530 if ((block+num) & ~0xffffffffULL) { 531 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 532 EXT2FS_UNMARK_ERROR, 0xffffffff); 533 return; 534 } 535 ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 536 block, num); 537 } 538 539 if (!EXT2FS_IS_64_BITMAP(bmap)) 540 return; 541 542 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 543 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, 544 bmap->description); 545 return; 546 } 547 548 bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); 549} 550 551int ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) 552{ 553#ifndef OMIT_COM_ERR 554 if (bitmap && bitmap->description) 555 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 556 "called %s with 64-bit bitmap for %s", func, 557 bitmap->description); 558 else 559 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 560 "called %s with 64-bit bitmap", func); 561#endif 562} 563