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