1/* 2 * icount.c --- an efficient inode count abstraction 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#if HAVE_UNISTD_H 13#include <unistd.h> 14#endif 15#include <string.h> 16#include <stdio.h> 17#include <sys/stat.h> 18#include <fcntl.h> 19#include <errno.h> 20 21#include "ext2_fs.h" 22#include "ext2fs.h" 23#include "tdb.h" 24 25/* 26 * The data storage strategy used by icount relies on the observation 27 * that most inode counts are either zero (for non-allocated inodes), 28 * one (for most files), and only a few that are two or more 29 * (directories and files that are linked to more than one directory). 30 * 31 * Also, e2fsck tends to load the icount data sequentially. 32 * 33 * So, we use an inode bitmap to indicate which inodes have a count of 34 * one, and then use a sorted list to store the counts for inodes 35 * which are greater than one. 36 * 37 * We also use an optional bitmap to indicate which inodes are already 38 * in the sorted list, to speed up the use of this abstraction by 39 * e2fsck's pass 2. Pass 2 increments inode counts as it finds them, 40 * so this extra bitmap avoids searching the sorted list to see if a 41 * particular inode is on the sorted list already. 42 */ 43 44struct ext2_icount_el { 45 ext2_ino_t ino; 46 __u16 count; 47}; 48 49struct ext2_icount { 50 errcode_t magic; 51 ext2fs_inode_bitmap single; 52 ext2fs_inode_bitmap multiple; 53 ext2_ino_t count; 54 ext2_ino_t size; 55 ext2_ino_t num_inodes; 56 ext2_ino_t cursor; 57 struct ext2_icount_el *list; 58 struct ext2_icount_el *last_lookup; 59 char *tdb_fn; 60 TDB_CONTEXT *tdb; 61}; 62 63void ext2fs_free_icount(ext2_icount_t icount) 64{ 65 if (!icount) 66 return; 67 68 icount->magic = 0; 69 if (icount->list) 70 ext2fs_free_mem(&icount->list); 71 if (icount->single) 72 ext2fs_free_inode_bitmap(icount->single); 73 if (icount->multiple) 74 ext2fs_free_inode_bitmap(icount->multiple); 75 if (icount->tdb) 76 tdb_close(icount->tdb); 77 if (icount->tdb_fn) { 78 unlink(icount->tdb_fn); 79 free(icount->tdb_fn); 80 } 81 82 ext2fs_free_mem(&icount); 83} 84 85static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret) 86{ 87 ext2_icount_t icount; 88 errcode_t retval; 89 90 *ret = 0; 91 92 retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount); 93 if (retval) 94 return retval; 95 memset(icount, 0, sizeof(struct ext2_icount)); 96 97 retval = ext2fs_allocate_inode_bitmap(fs, 0, &icount->single); 98 if (retval) 99 goto errout; 100 101 if (flags & EXT2_ICOUNT_OPT_INCREMENT) { 102 retval = ext2fs_allocate_inode_bitmap(fs, 0, 103 &icount->multiple); 104 if (retval) 105 goto errout; 106 } else 107 icount->multiple = 0; 108 109 icount->magic = EXT2_ET_MAGIC_ICOUNT; 110 icount->num_inodes = fs->super->s_inodes_count; 111 112 *ret = icount; 113 return 0; 114 115errout: 116 ext2fs_free_icount(icount); 117 return(retval); 118} 119 120struct uuid { 121 __u32 time_low; 122 __u16 time_mid; 123 __u16 time_hi_and_version; 124 __u16 clock_seq; 125 __u8 node[6]; 126}; 127 128static void unpack_uuid(void *in, struct uuid *uu) 129{ 130 __u8 *ptr = in; 131 __u32 tmp; 132 133 tmp = *ptr++; 134 tmp = (tmp << 8) | *ptr++; 135 tmp = (tmp << 8) | *ptr++; 136 tmp = (tmp << 8) | *ptr++; 137 uu->time_low = tmp; 138 139 tmp = *ptr++; 140 tmp = (tmp << 8) | *ptr++; 141 uu->time_mid = tmp; 142 143 tmp = *ptr++; 144 tmp = (tmp << 8) | *ptr++; 145 uu->time_hi_and_version = tmp; 146 147 tmp = *ptr++; 148 tmp = (tmp << 8) | *ptr++; 149 uu->clock_seq = tmp; 150 151 memcpy(uu->node, ptr, 6); 152} 153 154static void uuid_unparse(void *uu, char *out) 155{ 156 struct uuid uuid; 157 158 unpack_uuid(uu, &uuid); 159 sprintf(out, 160 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 161 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, 162 uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, 163 uuid.node[0], uuid.node[1], uuid.node[2], 164 uuid.node[3], uuid.node[4], uuid.node[5]); 165} 166 167errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, 168 int flags, ext2_icount_t *ret) 169{ 170 ext2_icount_t icount; 171 errcode_t retval; 172 char *fn, uuid[40]; 173 int fd; 174 175 retval = alloc_icount(fs, flags, &icount); 176 if (retval) 177 return retval; 178 179 retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn); 180 if (retval) 181 goto errout; 182 uuid_unparse(fs->super->s_uuid, uuid); 183 sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid); 184 fd = mkstemp(fn); 185 186 icount->tdb_fn = fn; 187 icount->tdb = tdb_open(fn, 0, TDB_CLEAR_IF_FIRST, 188 O_RDWR | O_CREAT | O_TRUNC, 0600); 189 if (icount->tdb) { 190 close(fd); 191 *ret = icount; 192 return 0; 193 } 194 195 retval = errno; 196 close(fd); 197 198errout: 199 ext2fs_free_icount(icount); 200 return(retval); 201} 202 203errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size, 204 ext2_icount_t hint, ext2_icount_t *ret) 205{ 206 ext2_icount_t icount; 207 errcode_t retval; 208 size_t bytes; 209 ext2_ino_t i; 210 211 if (hint) { 212 EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT); 213 if (hint->size > size) 214 size = (size_t) hint->size; 215 } 216 217 retval = alloc_icount(fs, flags, &icount); 218 if (retval) 219 return retval; 220 221 if (size) { 222 icount->size = size; 223 } else { 224 /* 225 * Figure out how many special case inode counts we will 226 * have. We know we will need one for each directory; 227 * we also need to reserve some extra room for file links 228 */ 229 retval = ext2fs_get_num_dirs(fs, &icount->size); 230 if (retval) 231 goto errout; 232 icount->size += fs->super->s_inodes_count / 50; 233 } 234 235 bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el)); 236#if 0 237 printf("Icount allocated %u entries, %d bytes.\n", 238 icount->size, bytes); 239#endif 240 retval = ext2fs_get_array(icount->size, sizeof(struct ext2_icount_el), 241 &icount->list); 242 if (retval) 243 goto errout; 244 memset(icount->list, 0, bytes); 245 246 icount->count = 0; 247 icount->cursor = 0; 248 249 /* 250 * Populate the sorted list with those entries which were 251 * found in the hint icount (since those are ones which will 252 * likely need to be in the sorted list this time around). 253 */ 254 if (hint) { 255 for (i=0; i < hint->count; i++) 256 icount->list[i].ino = hint->list[i].ino; 257 icount->count = hint->count; 258 } 259 260 *ret = icount; 261 return 0; 262 263errout: 264 ext2fs_free_icount(icount); 265 return(retval); 266} 267 268errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, 269 unsigned int size, 270 ext2_icount_t *ret) 271{ 272 return ext2fs_create_icount2(fs, flags, size, 0, ret); 273} 274 275/* 276 * insert_icount_el() --- Insert a new entry into the sorted list at a 277 * specified position. 278 */ 279static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount, 280 ext2_ino_t ino, int pos) 281{ 282 struct ext2_icount_el *el; 283 errcode_t retval; 284 ext2_ino_t new_size = 0; 285 int num; 286 287 if (icount->last_lookup && icount->last_lookup->ino == ino) 288 return icount->last_lookup; 289 290 if (icount->count >= icount->size) { 291 if (icount->count) { 292 new_size = icount->list[(unsigned)icount->count-1].ino; 293 new_size = (ext2_ino_t) (icount->count * 294 ((float) icount->num_inodes / new_size)); 295 } 296 if (new_size < (icount->size + 100)) 297 new_size = icount->size + 100; 298#if 0 299 printf("Reallocating icount %u entries...\n", new_size); 300#endif 301 retval = ext2fs_resize_mem((size_t) icount->size * 302 sizeof(struct ext2_icount_el), 303 (size_t) new_size * 304 sizeof(struct ext2_icount_el), 305 &icount->list); 306 if (retval) 307 return 0; 308 icount->size = new_size; 309 } 310 num = (int) icount->count - pos; 311 if (num < 0) 312 return 0; /* should never happen */ 313 if (num) { 314 memmove(&icount->list[pos+1], &icount->list[pos], 315 sizeof(struct ext2_icount_el) * num); 316 } 317 icount->count++; 318 el = &icount->list[pos]; 319 el->count = 0; 320 el->ino = ino; 321 icount->last_lookup = el; 322 return el; 323} 324 325/* 326 * get_icount_el() --- given an inode number, try to find icount 327 * information in the sorted list. If the create flag is set, 328 * and we can't find an entry, create one in the sorted list. 329 */ 330static struct ext2_icount_el *get_icount_el(ext2_icount_t icount, 331 ext2_ino_t ino, int create) 332{ 333 float range; 334 int low, high, mid; 335 ext2_ino_t lowval, highval; 336 337 if (!icount || !icount->list) 338 return 0; 339 340 if (create && ((icount->count == 0) || 341 (ino > icount->list[(unsigned)icount->count-1].ino))) { 342 return insert_icount_el(icount, ino, (unsigned) icount->count); 343 } 344 if (icount->count == 0) 345 return 0; 346 347 if (icount->cursor >= icount->count) 348 icount->cursor = 0; 349 if (ino == icount->list[icount->cursor].ino) 350 return &icount->list[icount->cursor++]; 351#if 0 352 printf("Non-cursor get_icount_el: %u\n", ino); 353#endif 354 low = 0; 355 high = (int) icount->count-1; 356 while (low <= high) { 357#if 0 358 mid = (low+high)/2; 359#else 360 if (low == high) 361 mid = low; 362 else { 363 /* Interpolate for efficiency */ 364 lowval = icount->list[low].ino; 365 highval = icount->list[high].ino; 366 367 if (ino < lowval) 368 range = 0; 369 else if (ino > highval) 370 range = 1; 371 else { 372 range = ((float) (ino - lowval)) / 373 (highval - lowval); 374 if (range > 0.9) 375 range = 0.9; 376 if (range < 0.1) 377 range = 0.1; 378 } 379 mid = low + ((int) (range * (high-low))); 380 } 381#endif 382 if (ino == icount->list[mid].ino) { 383 icount->cursor = mid+1; 384 return &icount->list[mid]; 385 } 386 if (ino < icount->list[mid].ino) 387 high = mid-1; 388 else 389 low = mid+1; 390 } 391 /* 392 * If we need to create a new entry, it should be right at 393 * low (where high will be left at low-1). 394 */ 395 if (create) 396 return insert_icount_el(icount, ino, low); 397 return 0; 398} 399 400static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino, 401 __u16 count) 402{ 403 struct ext2_icount_el *el; 404 TDB_DATA key, data; 405 406 if (icount->tdb) { 407 key.dptr = (unsigned char *) &ino; 408 key.dsize = sizeof(ext2_ino_t); 409 data.dptr = (unsigned char *) &count; 410 data.dsize = sizeof(__u16); 411 if (count) { 412 if (tdb_store(icount->tdb, key, data, TDB_REPLACE)) 413 return tdb_error(icount->tdb) + 414 EXT2_ET_TDB_SUCCESS; 415 } else { 416 if (tdb_delete(icount->tdb, key)) 417 return tdb_error(icount->tdb) + 418 EXT2_ET_TDB_SUCCESS; 419 } 420 return 0; 421 } 422 423 el = get_icount_el(icount, ino, 1); 424 if (!el) 425 return EXT2_ET_NO_MEMORY; 426 427 el->count = count; 428 return 0; 429} 430 431static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino, 432 __u16 *count) 433{ 434 struct ext2_icount_el *el; 435 TDB_DATA key, data; 436 437 if (icount->tdb) { 438 key.dptr = (unsigned char *) &ino; 439 key.dsize = sizeof(ext2_ino_t); 440 441 data = tdb_fetch(icount->tdb, key); 442 if (data.dptr == NULL) { 443 *count = 0; 444 return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS; 445 } 446 447 *count = *((__u16 *) data.dptr); 448 free(data.dptr); 449 return 0; 450 } 451 el = get_icount_el(icount, ino, 0); 452 if (!el) { 453 *count = 0; 454 return ENOENT; 455 } 456 457 *count = el->count; 458 return 0; 459} 460 461errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out) 462{ 463 errcode_t ret = 0; 464 unsigned int i; 465 const char *bad = "bad icount"; 466 467 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 468 469 if (icount->count > icount->size) { 470 fprintf(out, "%s: count > size\n", bad); 471 return EXT2_ET_INVALID_ARGUMENT; 472 } 473 for (i=1; i < icount->count; i++) { 474 if (icount->list[i-1].ino >= icount->list[i].ino) { 475 fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n", 476 bad, i-1, icount->list[i-1].ino, 477 i, icount->list[i].ino); 478 ret = EXT2_ET_INVALID_ARGUMENT; 479 } 480 } 481 return ret; 482} 483 484errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) 485{ 486 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 487 488 if (!ino || (ino > icount->num_inodes)) 489 return EXT2_ET_INVALID_ARGUMENT; 490 491 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 492 *ret = 1; 493 return 0; 494 } 495 if (icount->multiple && 496 !ext2fs_test_inode_bitmap(icount->multiple, ino)) { 497 *ret = 0; 498 return 0; 499 } 500 get_inode_count(icount, ino, ret); 501 return 0; 502} 503 504errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, 505 __u16 *ret) 506{ 507 __u16 curr_value; 508 509 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 510 511 if (!ino || (ino > icount->num_inodes)) 512 return EXT2_ET_INVALID_ARGUMENT; 513 514 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 515 /* 516 * If the existing count is 1, then we know there is 517 * no entry in the list. 518 */ 519 if (set_inode_count(icount, ino, 2)) 520 return EXT2_ET_NO_MEMORY; 521 curr_value = 2; 522 ext2fs_unmark_inode_bitmap(icount->single, ino); 523 } else if (icount->multiple) { 524 /* 525 * The count is either zero or greater than 1; if the 526 * inode is set in icount->multiple, then there should 527 * be an entry in the list, so we need to fix it. 528 */ 529 if (ext2fs_test_inode_bitmap(icount->multiple, ino)) { 530 get_inode_count(icount, ino, &curr_value); 531 curr_value++; 532 if (set_inode_count(icount, ino, curr_value)) 533 return EXT2_ET_NO_MEMORY; 534 } else { 535 /* 536 * The count was zero; mark the single bitmap 537 * and return. 538 */ 539 ext2fs_mark_inode_bitmap(icount->single, ino); 540 if (ret) 541 *ret = 1; 542 return 0; 543 } 544 } else { 545 /* 546 * The count is either zero or greater than 1; try to 547 * find an entry in the list to determine which. 548 */ 549 get_inode_count(icount, ino, &curr_value); 550 curr_value++; 551 if (set_inode_count(icount, ino, curr_value)) 552 return EXT2_ET_NO_MEMORY; 553 } 554 if (icount->multiple) 555 ext2fs_mark_inode_bitmap(icount->multiple, ino); 556 if (ret) 557 *ret = curr_value; 558 return 0; 559} 560 561errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, 562 __u16 *ret) 563{ 564 __u16 curr_value; 565 566 if (!ino || (ino > icount->num_inodes)) 567 return EXT2_ET_INVALID_ARGUMENT; 568 569 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 570 571 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 572 ext2fs_unmark_inode_bitmap(icount->single, ino); 573 if (icount->multiple) 574 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 575 else { 576 set_inode_count(icount, ino, 0); 577 } 578 if (ret) 579 *ret = 0; 580 return 0; 581 } 582 583 if (icount->multiple && 584 !ext2fs_test_inode_bitmap(icount->multiple, ino)) 585 return EXT2_ET_INVALID_ARGUMENT; 586 587 get_inode_count(icount, ino, &curr_value); 588 if (!curr_value) 589 return EXT2_ET_INVALID_ARGUMENT; 590 curr_value--; 591 if (set_inode_count(icount, ino, curr_value)) 592 return EXT2_ET_NO_MEMORY; 593 594 if (curr_value == 1) 595 ext2fs_mark_inode_bitmap(icount->single, ino); 596 if ((curr_value == 0) && icount->multiple) 597 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 598 599 if (ret) 600 *ret = curr_value; 601 return 0; 602} 603 604errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, 605 __u16 count) 606{ 607 if (!ino || (ino > icount->num_inodes)) 608 return EXT2_ET_INVALID_ARGUMENT; 609 610 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 611 612 if (count == 1) { 613 ext2fs_mark_inode_bitmap(icount->single, ino); 614 if (icount->multiple) 615 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 616 return 0; 617 } 618 if (count == 0) { 619 ext2fs_unmark_inode_bitmap(icount->single, ino); 620 if (icount->multiple) { 621 /* 622 * If the icount->multiple bitmap is enabled, 623 * we can just clear both bitmaps and we're done 624 */ 625 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 626 } else 627 set_inode_count(icount, ino, 0); 628 return 0; 629 } 630 631 if (set_inode_count(icount, ino, count)) 632 return EXT2_ET_NO_MEMORY; 633 ext2fs_unmark_inode_bitmap(icount->single, ino); 634 if (icount->multiple) 635 ext2fs_mark_inode_bitmap(icount->multiple, ino); 636 return 0; 637} 638 639ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount) 640{ 641 if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT) 642 return 0; 643 644 return icount->size; 645} 646 647#ifdef DEBUG 648 649ext2_filsys test_fs; 650ext2_icount_t icount; 651 652#define EXIT 0x00 653#define FETCH 0x01 654#define STORE 0x02 655#define INCREMENT 0x03 656#define DECREMENT 0x04 657 658struct test_program { 659 int cmd; 660 ext2_ino_t ino; 661 __u16 arg; 662 __u16 expected; 663}; 664 665struct test_program prog[] = { 666 { STORE, 42, 42, 42 }, 667 { STORE, 1, 1, 1 }, 668 { STORE, 2, 2, 2 }, 669 { STORE, 3, 3, 3 }, 670 { STORE, 10, 1, 1 }, 671 { STORE, 42, 0, 0 }, 672 { INCREMENT, 5, 0, 1 }, 673 { INCREMENT, 5, 0, 2 }, 674 { INCREMENT, 5, 0, 3 }, 675 { INCREMENT, 5, 0, 4 }, 676 { DECREMENT, 5, 0, 3 }, 677 { DECREMENT, 5, 0, 2 }, 678 { DECREMENT, 5, 0, 1 }, 679 { DECREMENT, 5, 0, 0 }, 680 { FETCH, 10, 0, 1 }, 681 { FETCH, 1, 0, 1 }, 682 { FETCH, 2, 0, 2 }, 683 { FETCH, 3, 0, 3 }, 684 { INCREMENT, 1, 0, 2 }, 685 { DECREMENT, 2, 0, 1 }, 686 { DECREMENT, 2, 0, 0 }, 687 { FETCH, 12, 0, 0 }, 688 { EXIT, 0, 0, 0 } 689}; 690 691struct test_program extended[] = { 692 { STORE, 1, 1, 1 }, 693 { STORE, 2, 2, 2 }, 694 { STORE, 3, 3, 3 }, 695 { STORE, 4, 4, 4 }, 696 { STORE, 5, 5, 5 }, 697 { STORE, 6, 1, 1 }, 698 { STORE, 7, 2, 2 }, 699 { STORE, 8, 3, 3 }, 700 { STORE, 9, 4, 4 }, 701 { STORE, 10, 5, 5 }, 702 { STORE, 11, 1, 1 }, 703 { STORE, 12, 2, 2 }, 704 { STORE, 13, 3, 3 }, 705 { STORE, 14, 4, 4 }, 706 { STORE, 15, 5, 5 }, 707 { STORE, 16, 1, 1 }, 708 { STORE, 17, 2, 2 }, 709 { STORE, 18, 3, 3 }, 710 { STORE, 19, 4, 4 }, 711 { STORE, 20, 5, 5 }, 712 { STORE, 21, 1, 1 }, 713 { STORE, 22, 2, 2 }, 714 { STORE, 23, 3, 3 }, 715 { STORE, 24, 4, 4 }, 716 { STORE, 25, 5, 5 }, 717 { STORE, 26, 1, 1 }, 718 { STORE, 27, 2, 2 }, 719 { STORE, 28, 3, 3 }, 720 { STORE, 29, 4, 4 }, 721 { STORE, 30, 5, 5 }, 722 { EXIT, 0, 0, 0 } 723}; 724 725/* 726 * Setup the variables for doing the inode scan test. 727 */ 728static void setup(void) 729{ 730 errcode_t retval; 731 struct ext2_super_block param; 732 733 initialize_ext2_error_table(); 734 735 memset(¶m, 0, sizeof(param)); 736 param.s_blocks_count = 12000; 737 738 retval = ext2fs_initialize("test fs", 0, ¶m, 739 test_io_manager, &test_fs); 740 if (retval) { 741 com_err("setup", retval, 742 "while initializing filesystem"); 743 exit(1); 744 } 745 retval = ext2fs_allocate_tables(test_fs); 746 if (retval) { 747 com_err("setup", retval, 748 "while allocating tables for test filesystem"); 749 exit(1); 750 } 751} 752 753int run_test(int flags, int size, char *dir, struct test_program *prog) 754{ 755 errcode_t retval; 756 ext2_icount_t icount; 757 struct test_program *pc; 758 __u16 result; 759 int problem = 0; 760 761 if (dir) { 762 retval = ext2fs_create_icount_tdb(test_fs, dir, 763 flags, &icount); 764 if (retval) { 765 com_err("run_test", retval, 766 "while creating icount using tdb"); 767 exit(1); 768 } 769 } else { 770 retval = ext2fs_create_icount2(test_fs, flags, size, 0, 771 &icount); 772 if (retval) { 773 com_err("run_test", retval, "while creating icount"); 774 exit(1); 775 } 776 } 777 for (pc = prog; pc->cmd != EXIT; pc++) { 778 switch (pc->cmd) { 779 case FETCH: 780 printf("icount_fetch(%u) = ", pc->ino); 781 break; 782 case STORE: 783 retval = ext2fs_icount_store(icount, pc->ino, pc->arg); 784 if (retval) { 785 com_err("run_test", retval, 786 "while calling icount_store"); 787 exit(1); 788 } 789 printf("icount_store(%u, %u) = ", pc->ino, pc->arg); 790 break; 791 case INCREMENT: 792 retval = ext2fs_icount_increment(icount, pc->ino, 0); 793 if (retval) { 794 com_err("run_test", retval, 795 "while calling icount_increment"); 796 exit(1); 797 } 798 printf("icount_increment(%u) = ", pc->ino); 799 break; 800 case DECREMENT: 801 retval = ext2fs_icount_decrement(icount, pc->ino, 0); 802 if (retval) { 803 com_err("run_test", retval, 804 "while calling icount_decrement"); 805 exit(1); 806 } 807 printf("icount_decrement(%u) = ", pc->ino); 808 break; 809 } 810 retval = ext2fs_icount_fetch(icount, pc->ino, &result); 811 if (retval) { 812 com_err("run_test", retval, 813 "while calling icount_fetch"); 814 exit(1); 815 } 816 printf("%u (%s)\n", result, (result == pc->expected) ? 817 "OK" : "NOT OK"); 818 if (result != pc->expected) 819 problem++; 820 } 821 printf("icount size is %u\n", ext2fs_get_icount_size(icount)); 822 retval = ext2fs_icount_validate(icount, stdout); 823 if (retval) { 824 com_err("run_test", retval, "while calling icount_validate"); 825 exit(1); 826 } 827 ext2fs_free_icount(icount); 828 return problem; 829} 830 831 832int main(int argc, char **argv) 833{ 834 int failed = 0; 835 836 setup(); 837 printf("Standard icount run:\n"); 838 failed += run_test(0, 0, 0, prog); 839 printf("\nMultiple bitmap test:\n"); 840 failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, 0, prog); 841 printf("\nResizing icount:\n"); 842 failed += run_test(0, 3, 0, extended); 843 printf("\nStandard icount run with tdb:\n"); 844 failed += run_test(0, 0, ".", prog); 845 printf("\nMultiple bitmap test with tdb:\n"); 846 failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, ".", prog); 847 if (failed) 848 printf("FAILED!\n"); 849 return failed; 850} 851#endif 852