1 /* 2 * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 3 */ 4 5 #include <linux/time.h> 6 #include <linux/reiserfs_fs.h> 7 8 // this contains item handlers for old item types: sd, direct, 9 // indirect, directory 10 11 /* and where are the comments? how about saying where we can find an 12 explanation of each item handler method? -Hans */ 13 14 ////////////////////////////////////////////////////////////////////////////// 15 // stat data functions 16 // 17 static int sd_bytes_number(struct item_head *ih, int block_size) 18 { 19 return 0; 20 } 21 22 static void sd_decrement_key(struct cpu_key *key) 23 { 24 key->on_disk_key.k_objectid--; 25 set_cpu_key_k_type(key, TYPE_ANY); 26 set_cpu_key_k_offset(key, (loff_t) (-1)); 27 } 28 29 static int sd_is_left_mergeable(struct reiserfs_key *key, unsigned long bsize) 30 { 31 return 0; 32 } 33 34 static char *print_time(time_t t) 35 { 36 static char timebuf[256]; 37 38 sprintf(timebuf, "%ld", t); 39 return timebuf; 40 } 41 42 static void sd_print_item(struct item_head *ih, char *item) 43 { 44 printk("\tmode | size | nlinks | first direct | mtime\n"); 45 if (stat_data_v1(ih)) { 46 struct stat_data_v1 *sd = (struct stat_data_v1 *)item; 47 48 printk("\t0%-6o | %6u | %2u | %d | %s\n", sd_v1_mode(sd), 49 sd_v1_size(sd), sd_v1_nlink(sd), 50 sd_v1_first_direct_byte(sd), 51 print_time(sd_v1_mtime(sd))); 52 } else { 53 struct stat_data *sd = (struct stat_data *)item; 54 55 printk("\t0%-6o | %6Lu | %2u | %d | %s\n", sd_v2_mode(sd), 56 (unsigned long long)sd_v2_size(sd), sd_v2_nlink(sd), 57 sd_v2_rdev(sd), print_time(sd_v2_mtime(sd))); 58 } 59 } 60 61 static void sd_check_item(struct item_head *ih, char *item) 62 { 63 // FIXME: type something here! 64 } 65 66 static int sd_create_vi(struct virtual_node *vn, 67 struct virtual_item *vi, 68 int is_affected, int insert_size) 69 { 70 vi->vi_index = TYPE_STAT_DATA; 71 //vi->vi_type |= VI_TYPE_STAT_DATA;// not needed? 72 return 0; 73 } 74 75 static int sd_check_left(struct virtual_item *vi, int free, 76 int start_skip, int end_skip) 77 { 78 if (start_skip || end_skip) 79 BUG(); 80 return -1; 81 } 82 83 static int sd_check_right(struct virtual_item *vi, int free) 84 { 85 return -1; 86 } 87 88 static int sd_part_size(struct virtual_item *vi, int first, int count) 89 { 90 if (count) 91 BUG(); 92 return 0; 93 } 94 95 static int sd_unit_num(struct virtual_item *vi) 96 { 97 return vi->vi_item_len - IH_SIZE; 98 } 99 100 static void sd_print_vi(struct virtual_item *vi) 101 { 102 reiserfs_warning(NULL, "STATDATA, index %d, type 0x%x, %h", 103 vi->vi_index, vi->vi_type, vi->vi_ih); 104 } 105 106 static struct item_operations stat_data_ops = { 107 .bytes_number = sd_bytes_number, 108 .decrement_key = sd_decrement_key, 109 .is_left_mergeable = sd_is_left_mergeable, 110 .print_item = sd_print_item, 111 .check_item = sd_check_item, 112 113 .create_vi = sd_create_vi, 114 .check_left = sd_check_left, 115 .check_right = sd_check_right, 116 .part_size = sd_part_size, 117 .unit_num = sd_unit_num, 118 .print_vi = sd_print_vi 119 }; 120 121 ////////////////////////////////////////////////////////////////////////////// 122 // direct item functions 123 // 124 static int direct_bytes_number(struct item_head *ih, int block_size) 125 { 126 return ih_item_len(ih); 127 } 128 129 // FIXME: this should probably switch to indirect as well 130 static void direct_decrement_key(struct cpu_key *key) 131 { 132 cpu_key_k_offset_dec(key); 133 if (cpu_key_k_offset(key) == 0) 134 set_cpu_key_k_type(key, TYPE_STAT_DATA); 135 } 136 137 static int direct_is_left_mergeable(struct reiserfs_key *key, 138 unsigned long bsize) 139 { 140 int version = le_key_version(key); 141 return ((le_key_k_offset(version, key) & (bsize - 1)) != 1); 142 } 143 144 static void direct_print_item(struct item_head *ih, char *item) 145 { 146 int j = 0; 147 148 // return; 149 printk("\""); 150 while (j < ih_item_len(ih)) 151 printk("%c", item[j++]); 152 printk("\"\n"); 153 } 154 155 static void direct_check_item(struct item_head *ih, char *item) 156 { 157 // FIXME: type something here! 158 } 159 160 static int direct_create_vi(struct virtual_node *vn, 161 struct virtual_item *vi, 162 int is_affected, int insert_size) 163 { 164 vi->vi_index = TYPE_DIRECT; 165 //vi->vi_type |= VI_TYPE_DIRECT; 166 return 0; 167 } 168 169 static int direct_check_left(struct virtual_item *vi, int free, 170 int start_skip, int end_skip) 171 { 172 int bytes; 173 174 bytes = free - free % 8; 175 return bytes ? : -1; 176 } 177 178 static int direct_check_right(struct virtual_item *vi, int free) 179 { 180 return direct_check_left(vi, free, 0, 0); 181 } 182 183 static int direct_part_size(struct virtual_item *vi, int first, int count) 184 { 185 return count; 186 } 187 188 static int direct_unit_num(struct virtual_item *vi) 189 { 190 return vi->vi_item_len - IH_SIZE; 191 } 192 193 static void direct_print_vi(struct virtual_item *vi) 194 { 195 reiserfs_warning(NULL, "DIRECT, index %d, type 0x%x, %h", 196 vi->vi_index, vi->vi_type, vi->vi_ih); 197 } 198 199 static struct item_operations direct_ops = { 200 .bytes_number = direct_bytes_number, 201 .decrement_key = direct_decrement_key, 202 .is_left_mergeable = direct_is_left_mergeable, 203 .print_item = direct_print_item, 204 .check_item = direct_check_item, 205 206 .create_vi = direct_create_vi, 207 .check_left = direct_check_left, 208 .check_right = direct_check_right, 209 .part_size = direct_part_size, 210 .unit_num = direct_unit_num, 211 .print_vi = direct_print_vi 212 }; 213 214 ////////////////////////////////////////////////////////////////////////////// 215 // indirect item functions 216 // 217 218 static int indirect_bytes_number(struct item_head *ih, int block_size) 219 { 220 return ih_item_len(ih) / UNFM_P_SIZE * block_size; //- get_ih_free_space (ih); 221 } 222 223 // decrease offset, if it becomes 0, change type to stat data 224 static void indirect_decrement_key(struct cpu_key *key) 225 { 226 cpu_key_k_offset_dec(key); 227 if (cpu_key_k_offset(key) == 0) 228 set_cpu_key_k_type(key, TYPE_STAT_DATA); 229 } 230 231 // if it is not first item of the body, then it is mergeable 232 static int indirect_is_left_mergeable(struct reiserfs_key *key, 233 unsigned long bsize) 234 { 235 int version = le_key_version(key); 236 return (le_key_k_offset(version, key) != 1); 237 } 238 239 // printing of indirect item 240 static void start_new_sequence(__u32 * start, int *len, __u32 new) 241 { 242 *start = new; 243 *len = 1; 244 } 245 246 static int sequence_finished(__u32 start, int *len, __u32 new) 247 { 248 if (start == INT_MAX) 249 return 1; 250 251 if (start == 0 && new == 0) { 252 (*len)++; 253 return 0; 254 } 255 if (start != 0 && (start + *len) == new) { 256 (*len)++; 257 return 0; 258 } 259 return 1; 260 } 261 262 static void print_sequence(__u32 start, int len) 263 { 264 if (start == INT_MAX) 265 return; 266 267 if (len == 1) 268 printk(" %d", start); 269 else 270 printk(" %d(%d)", start, len); 271 } 272 273 static void indirect_print_item(struct item_head *ih, char *item) 274 { 275 int j; 276 __le32 *unp; 277 __u32 prev = INT_MAX; 278 int num; 279 280 unp = (__le32 *) item; 281 282 if (ih_item_len(ih) % UNFM_P_SIZE) 283 reiserfs_warning(NULL, "indirect_print_item: invalid item len"); 284 285 printk("%d pointers\n[ ", (int)I_UNFM_NUM(ih)); 286 for (j = 0; j < I_UNFM_NUM(ih); j++) { 287 if (sequence_finished(prev, &num, get_block_num(unp, j))) { 288 print_sequence(prev, num); 289 start_new_sequence(&prev, &num, get_block_num(unp, j)); 290 } 291 } 292 print_sequence(prev, num); 293 printk("]\n"); 294 } 295 296 static void indirect_check_item(struct item_head *ih, char *item) 297 { 298 // FIXME: type something here! 299 } 300 301 static int indirect_create_vi(struct virtual_node *vn, 302 struct virtual_item *vi, 303 int is_affected, int insert_size) 304 { 305 vi->vi_index = TYPE_INDIRECT; 306 //vi->vi_type |= VI_TYPE_INDIRECT; 307 return 0; 308 } 309 310 static int indirect_check_left(struct virtual_item *vi, int free, 311 int start_skip, int end_skip) 312 { 313 int bytes; 314 315 bytes = free - free % UNFM_P_SIZE; 316 return bytes ? : -1; 317 } 318 319 static int indirect_check_right(struct virtual_item *vi, int free) 320 { 321 return indirect_check_left(vi, free, 0, 0); 322 } 323 324 // return size in bytes of 'units' units. If first == 0 - calculate from the head (left), otherwise - from tail (right) 325 static int indirect_part_size(struct virtual_item *vi, int first, int units) 326 { 327 // unit of indirect item is byte (yet) 328 return units; 329 } 330 331 static int indirect_unit_num(struct virtual_item *vi) 332 { 333 // unit of indirect item is byte (yet) 334 return vi->vi_item_len - IH_SIZE; 335 } 336 337 static void indirect_print_vi(struct virtual_item *vi) 338 { 339 reiserfs_warning(NULL, "INDIRECT, index %d, type 0x%x, %h", 340 vi->vi_index, vi->vi_type, vi->vi_ih); 341 } 342 343 static struct item_operations indirect_ops = { 344 .bytes_number = indirect_bytes_number, 345 .decrement_key = indirect_decrement_key, 346 .is_left_mergeable = indirect_is_left_mergeable, 347 .print_item = indirect_print_item, 348 .check_item = indirect_check_item, 349 350 .create_vi = indirect_create_vi, 351 .check_left = indirect_check_left, 352 .check_right = indirect_check_right, 353 .part_size = indirect_part_size, 354 .unit_num = indirect_unit_num, 355 .print_vi = indirect_print_vi 356 }; 357 358 ////////////////////////////////////////////////////////////////////////////// 359 // direntry functions 360 // 361 362 static int direntry_bytes_number(struct item_head *ih, int block_size) 363 { 364 reiserfs_warning(NULL, "vs-16090: direntry_bytes_number: " 365 "bytes number is asked for direntry"); 366 return 0; 367 } 368 369 static void direntry_decrement_key(struct cpu_key *key) 370 { 371 cpu_key_k_offset_dec(key); 372 if (cpu_key_k_offset(key) == 0) 373 set_cpu_key_k_type(key, TYPE_STAT_DATA); 374 } 375 376 static int direntry_is_left_mergeable(struct reiserfs_key *key, 377 unsigned long bsize) 378 { 379 if (le32_to_cpu(key->u.k_offset_v1.k_offset) == DOT_OFFSET) 380 return 0; 381 return 1; 382 383 } 384 385 static void direntry_print_item(struct item_head *ih, char *item) 386 { 387 int i; 388 int namelen; 389 struct reiserfs_de_head *deh; 390 char *name; 391 static char namebuf[80]; 392 393 printk("\n # %-15s%-30s%-15s%-15s%-15s\n", "Name", 394 "Key of pointed object", "Hash", "Gen number", "Status"); 395 396 deh = (struct reiserfs_de_head *)item; 397 398 for (i = 0; i < I_ENTRY_COUNT(ih); i++, deh++) { 399 namelen = 400 (i ? (deh_location(deh - 1)) : ih_item_len(ih)) - 401 deh_location(deh); 402 name = item + deh_location(deh); 403 if (name[namelen - 1] == 0) 404 namelen = strlen(name); 405 namebuf[0] = '"'; 406 if (namelen > sizeof(namebuf) - 3) { 407 strncpy(namebuf + 1, name, sizeof(namebuf) - 3); 408 namebuf[sizeof(namebuf) - 2] = '"'; 409 namebuf[sizeof(namebuf) - 1] = 0; 410 } else { 411 memcpy(namebuf + 1, name, namelen); 412 namebuf[namelen + 1] = '"'; 413 namebuf[namelen + 2] = 0; 414 } 415 416 printk("%d: %-15s%-15d%-15d%-15Ld%-15Ld(%s)\n", 417 i, namebuf, 418 deh_dir_id(deh), deh_objectid(deh), 419 GET_HASH_VALUE(deh_offset(deh)), 420 GET_GENERATION_NUMBER((deh_offset(deh))), 421 (de_hidden(deh)) ? "HIDDEN" : "VISIBLE"); 422 } 423 } 424 425 static void direntry_check_item(struct item_head *ih, char *item) 426 { 427 int i; 428 struct reiserfs_de_head *deh; 429 430 // FIXME: type something here! 431 deh = (struct reiserfs_de_head *)item; 432 for (i = 0; i < I_ENTRY_COUNT(ih); i++, deh++) { 433 ; 434 } 435 } 436 437 #define DIRENTRY_VI_FIRST_DIRENTRY_ITEM 1 438 439 /* 440 * function returns old entry number in directory item in real node 441 * using new entry number in virtual item in virtual node */ 442 static inline int old_entry_num(int is_affected, int virtual_entry_num, 443 int pos_in_item, int mode) 444 { 445 if (mode == M_INSERT || mode == M_DELETE) 446 return virtual_entry_num; 447 448 if (!is_affected) 449 /* cut or paste is applied to another item */ 450 return virtual_entry_num; 451 452 if (virtual_entry_num < pos_in_item) 453 return virtual_entry_num; 454 455 if (mode == M_CUT) 456 return virtual_entry_num + 1; 457 458 RFALSE(mode != M_PASTE || virtual_entry_num == 0, 459 "vs-8015: old_entry_num: mode must be M_PASTE (mode = \'%c\'", 460 mode); 461 462 return virtual_entry_num - 1; 463 } 464 465 /* Create an array of sizes of directory entries for virtual 466 item. Return space used by an item. FIXME: no control over 467 consuming of space used by this item handler */ 468 static int direntry_create_vi(struct virtual_node *vn, 469 struct virtual_item *vi, 470 int is_affected, int insert_size) 471 { 472 struct direntry_uarea *dir_u = vi->vi_uarea; 473 int i, j; 474 int size = sizeof(struct direntry_uarea); 475 struct reiserfs_de_head *deh; 476 477 vi->vi_index = TYPE_DIRENTRY; 478 479 if (!(vi->vi_ih) || !vi->vi_item) 480 BUG(); 481 482 dir_u->flags = 0; 483 if (le_ih_k_offset(vi->vi_ih) == DOT_OFFSET) 484 dir_u->flags |= DIRENTRY_VI_FIRST_DIRENTRY_ITEM; 485 486 deh = (struct reiserfs_de_head *)(vi->vi_item); 487 488 /* virtual directory item have this amount of entry after */ 489 dir_u->entry_count = ih_entry_count(vi->vi_ih) + 490 ((is_affected) ? ((vn->vn_mode == M_CUT) ? -1 : 491 (vn->vn_mode == M_PASTE ? 1 : 0)) : 0); 492 493 for (i = 0; i < dir_u->entry_count; i++) { 494 j = old_entry_num(is_affected, i, vn->vn_pos_in_item, 495 vn->vn_mode); 496 dir_u->entry_sizes[i] = 497 (j ? deh_location(&(deh[j - 1])) : ih_item_len(vi->vi_ih)) - 498 deh_location(&(deh[j])) + DEH_SIZE; 499 } 500 501 size += (dir_u->entry_count * sizeof(short)); 502 503 /* set size of pasted entry */ 504 if (is_affected && vn->vn_mode == M_PASTE) 505 dir_u->entry_sizes[vn->vn_pos_in_item] = insert_size; 506 507 #ifdef CONFIG_REISERFS_CHECK 508 /* compare total size of entries with item length */ 509 { 510 int k, l; 511 512 l = 0; 513 for (k = 0; k < dir_u->entry_count; k++) 514 l += dir_u->entry_sizes[k]; 515 516 if (l + IH_SIZE != vi->vi_item_len + 517 ((is_affected 518 && (vn->vn_mode == M_PASTE 519 || vn->vn_mode == M_CUT)) ? insert_size : 0)) { 520 reiserfs_panic(NULL, 521 "vs-8025: set_entry_sizes: (mode==%c, insert_size==%d), invalid length of directory item", 522 vn->vn_mode, insert_size); 523 } 524 } 525 #endif 526 527 return size; 528 529 } 530 531 // 532 // return number of entries which may fit into specified amount of 533 // free space, or -1 if free space is not enough even for 1 entry 534 // 535 static int direntry_check_left(struct virtual_item *vi, int free, 536 int start_skip, int end_skip) 537 { 538 int i; 539 int entries = 0; 540 struct direntry_uarea *dir_u = vi->vi_uarea; 541 542 for (i = start_skip; i < dir_u->entry_count - end_skip; i++) { 543 if (dir_u->entry_sizes[i] > free) 544 /* i-th entry doesn't fit into the remaining free space */ 545 break; 546 547 free -= dir_u->entry_sizes[i]; 548 entries++; 549 } 550 551 if (entries == dir_u->entry_count) { 552 reiserfs_panic(NULL, "free space %d, entry_count %d\n", free, 553 dir_u->entry_count); 554 } 555 556 /* "." and ".." can not be separated from each other */ 557 if (start_skip == 0 && (dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM) 558 && entries < 2) 559 entries = 0; 560 561 return entries ? : -1; 562 } 563 564 static int direntry_check_right(struct virtual_item *vi, int free) 565 { 566 int i; 567 int entries = 0; 568 struct direntry_uarea *dir_u = vi->vi_uarea; 569 570 for (i = dir_u->entry_count - 1; i >= 0; i--) { 571 if (dir_u->entry_sizes[i] > free) 572 /* i-th entry doesn't fit into the remaining free space */ 573 break; 574 575 free -= dir_u->entry_sizes[i]; 576 entries++; 577 } 578 if (entries == dir_u->entry_count) 579 BUG(); 580 581 /* "." and ".." can not be separated from each other */ 582 if ((dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM) 583 && entries > dir_u->entry_count - 2) 584 entries = dir_u->entry_count - 2; 585 586 return entries ? : -1; 587 } 588 589 /* sum of entry sizes between from-th and to-th entries including both edges */ 590 static int direntry_part_size(struct virtual_item *vi, int first, int count) 591 { 592 int i, retval; 593 int from, to; 594 struct direntry_uarea *dir_u = vi->vi_uarea; 595 596 retval = 0; 597 if (first == 0) 598 from = 0; 599 else 600 from = dir_u->entry_count - count; 601 to = from + count - 1; 602 603 for (i = from; i <= to; i++) 604 retval += dir_u->entry_sizes[i]; 605 606 return retval; 607 } 608 609 static int direntry_unit_num(struct virtual_item *vi) 610 { 611 struct direntry_uarea *dir_u = vi->vi_uarea; 612 613 return dir_u->entry_count; 614 } 615 616 static void direntry_print_vi(struct virtual_item *vi) 617 { 618 int i; 619 struct direntry_uarea *dir_u = vi->vi_uarea; 620 621 reiserfs_warning(NULL, "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x", 622 vi->vi_index, vi->vi_type, vi->vi_ih, dir_u->flags); 623 printk("%d entries: ", dir_u->entry_count); 624 for (i = 0; i < dir_u->entry_count; i++) 625 printk("%d ", dir_u->entry_sizes[i]); 626 printk("\n"); 627 } 628 629 static struct item_operations direntry_ops = { 630 .bytes_number = direntry_bytes_number, 631 .decrement_key = direntry_decrement_key, 632 .is_left_mergeable = direntry_is_left_mergeable, 633 .print_item = direntry_print_item, 634 .check_item = direntry_check_item, 635 636 .create_vi = direntry_create_vi, 637 .check_left = direntry_check_left, 638 .check_right = direntry_check_right, 639 .part_size = direntry_part_size, 640 .unit_num = direntry_unit_num, 641 .print_vi = direntry_print_vi 642 }; 643 644 ////////////////////////////////////////////////////////////////////////////// 645 // Error catching functions to catch errors caused by incorrect item types. 646 // 647 static int errcatch_bytes_number(struct item_head *ih, int block_size) 648 { 649 reiserfs_warning(NULL, 650 "green-16001: Invalid item type observed, run fsck ASAP"); 651 return 0; 652 } 653 654 static void errcatch_decrement_key(struct cpu_key *key) 655 { 656 reiserfs_warning(NULL, 657 "green-16002: Invalid item type observed, run fsck ASAP"); 658 } 659 660 static int errcatch_is_left_mergeable(struct reiserfs_key *key, 661 unsigned long bsize) 662 { 663 reiserfs_warning(NULL, 664 "green-16003: Invalid item type observed, run fsck ASAP"); 665 return 0; 666 } 667 668 static void errcatch_print_item(struct item_head *ih, char *item) 669 { 670 reiserfs_warning(NULL, 671 "green-16004: Invalid item type observed, run fsck ASAP"); 672 } 673 674 static void errcatch_check_item(struct item_head *ih, char *item) 675 { 676 reiserfs_warning(NULL, 677 "green-16005: Invalid item type observed, run fsck ASAP"); 678 } 679 680 static int errcatch_create_vi(struct virtual_node *vn, 681 struct virtual_item *vi, 682 int is_affected, int insert_size) 683 { 684 reiserfs_warning(NULL, 685 "green-16006: Invalid item type observed, run fsck ASAP"); 686 return 0; // We might return -1 here as well, but it won't help as create_virtual_node() from where 687 // this operation is called from is of return type void. 688 } 689 690 static int errcatch_check_left(struct virtual_item *vi, int free, 691 int start_skip, int end_skip) 692 { 693 reiserfs_warning(NULL, 694 "green-16007: Invalid item type observed, run fsck ASAP"); 695 return -1; 696 } 697 698 static int errcatch_check_right(struct virtual_item *vi, int free) 699 { 700 reiserfs_warning(NULL, 701 "green-16008: Invalid item type observed, run fsck ASAP"); 702 return -1; 703 } 704 705 static int errcatch_part_size(struct virtual_item *vi, int first, int count) 706 { 707 reiserfs_warning(NULL, 708 "green-16009: Invalid item type observed, run fsck ASAP"); 709 return 0; 710 } 711 712 static int errcatch_unit_num(struct virtual_item *vi) 713 { 714 reiserfs_warning(NULL, 715 "green-16010: Invalid item type observed, run fsck ASAP"); 716 return 0; 717 } 718 719 static void errcatch_print_vi(struct virtual_item *vi) 720 { 721 reiserfs_warning(NULL, 722 "green-16011: Invalid item type observed, run fsck ASAP"); 723 } 724 725 static struct item_operations errcatch_ops = { 726 errcatch_bytes_number, 727 errcatch_decrement_key, 728 errcatch_is_left_mergeable, 729 errcatch_print_item, 730 errcatch_check_item, 731 732 errcatch_create_vi, 733 errcatch_check_left, 734 errcatch_check_right, 735 errcatch_part_size, 736 errcatch_unit_num, 737 errcatch_print_vi 738 }; 739 740 ////////////////////////////////////////////////////////////////////////////// 741 // 742 // 743 #if ! (TYPE_STAT_DATA == 0 && TYPE_INDIRECT == 1 && TYPE_DIRECT == 2 && TYPE_DIRENTRY == 3) 744 #error Item types must use disk-format assigned values. 745 #endif 746 747 struct item_operations *item_ops[TYPE_ANY + 1] = { 748 &stat_data_ops, 749 &indirect_ops, 750 &direct_ops, 751 &direntry_ops, 752 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 753 &errcatch_ops /* This is to catch errors with invalid type (15th entry for TYPE_ANY) */ 754 }; 755