1/* 2 Copyright 1999-2001, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4*/ 5 6 7#include "fat.h" 8 9#include "system_dependencies.h" 10 11#include "dosfs.h" 12#include "file.h" 13#include "util.h" 14#include "vcache.h" 15 16 17#define END_FAT_ENTRY 0x0fffffff 18#define BAD_FAT_ENTRY 0x0ffffff1 19 20#define DPRINTF(a,b) if (debug_fat > (a)) dprintf b 21 22 23static status_t 24mirror_fats(nspace *vol, uint32 sector, uint8 *buffer) 25{ 26 uint32 i; 27 28 if (!vol->fat_mirrored) 29 return B_OK; 30 31 sector -= vol->active_fat * vol->sectors_per_fat; 32 33 for (i = 0; i < vol->fat_count; i++) { 34 char *blockData; 35 status_t status; 36 if (i == vol->active_fat) 37 continue; 38 39 status = block_cache_get_writable_etc(vol->fBlockCache, 40 sector + i * vol->sectors_per_fat, 0, 1, -1, 41 (void**)&blockData); 42 if (status != B_OK) 43 return status; 44 45 memcpy(blockData, buffer, vol->bytes_per_sector); 46 block_cache_put(vol->fBlockCache, sector + i * vol->sectors_per_fat); 47 } 48 49 return B_OK; 50} 51 52 53static int32 54_count_free_clusters_fat32(nspace *vol) 55{ 56 int32 count = 0; 57 const uint8 *block; 58 uint32 fat_sector; 59 uint32 i; 60 uint32 cur_sector; 61 62 cur_sector = vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat; 63 64 for (fat_sector = 0; fat_sector < vol->sectors_per_fat; fat_sector++) { 65 block = (uint8 *)block_cache_get(vol->fBlockCache, cur_sector); 66 if(block == NULL) 67 return B_IO_ERROR; 68 69 for (i = 0; i < vol->bytes_per_sector; i += sizeof(uint32)) { 70 uint32 val = read32(block, i); 71 if ((val & 0x0fffffff) == 0) 72 count++; 73 } 74 75 block_cache_put(vol->fBlockCache, cur_sector); 76 cur_sector++; 77 } 78 79 return count; 80} 81 82// count free: no parameters. returns int32 83// get_entry: cluster #. returns int32 entry/status 84// set_entry: cluster #, value. returns int32 status 85// allocate: # clusters in N, returns int32 status/starting cluster 86 87enum { 88 _IOCTL_COUNT_FREE_, 89 _IOCTL_GET_ENTRY_, 90 _IOCTL_SET_ENTRY_, 91 _IOCTL_ALLOCATE_N_ENTRIES_ 92}; 93 94static int32 95_fat_ioctl_(nspace *vol, uint32 action, uint32 cluster, uint32 N) 96{ 97 int32 result = 0; 98 uint32 n = 0, first = 0, last = 0; 99 uint32 i; 100 uint32 sector; 101 uint32 offset, value = 0; /* quiet warning */ 102 uint8 *block1, *block2 = NULL; /* quiet warning */ 103 bool readOnly 104 = action != _IOCTL_SET_ENTRY_ && action != _IOCTL_ALLOCATE_N_ENTRIES_; 105 106 // mark end of chain for allocations 107 uint32 endOfChainMarker = (action == _IOCTL_SET_ENTRY_) ? N : 0x0fffffff; 108 109 ASSERT(action >= _IOCTL_COUNT_FREE_ 110 && action <= _IOCTL_ALLOCATE_N_ENTRIES_); 111 112 DPRINTF(3, ("_fat_ioctl_: action %" B_PRIu32 ", cluster %" B_PRIu32 113 ", N %" B_PRId32 "\n", action, cluster, N)); 114 115 if (action == _IOCTL_COUNT_FREE_) { 116 if(vol->fat_bits == 32) 117 // use a optimized version of the cluster counting algorithms 118 return _count_free_clusters_fat32(vol); 119 else 120 cluster = 2; 121 } 122 123 if (action == _IOCTL_ALLOCATE_N_ENTRIES_) 124 cluster = vol->last_allocated; 125 126 if (action != _IOCTL_COUNT_FREE_) { 127 if (!IS_DATA_CLUSTER(cluster)) { 128 DPRINTF(0, ("_fat_ioctl_ called with invalid cluster (%" B_PRIu32 129 ")\n", cluster)); 130 return B_BAD_VALUE; 131 } 132 } 133 134 offset = cluster * vol->fat_bits / 8; 135 sector = vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat + 136 offset / vol->bytes_per_sector; 137 offset %= vol->bytes_per_sector; 138 139 if (readOnly) { 140 block1 = (uint8 *)block_cache_get(vol->fBlockCache, sector); 141 } else { 142 block1 = (uint8 *)block_cache_get_writable(vol->fBlockCache, sector, 143 -1); 144 } 145 146 if (block1 == NULL) { 147 DPRINTF(0, ("_fat_ioctl_: error reading fat (sector %" B_PRIu32 ")\n", 148 sector)); 149 return B_IO_ERROR; 150 } 151 152 for (i = 0; i < vol->total_clusters; i++) { 153 ASSERT(IS_DATA_CLUSTER(cluster)); 154 ASSERT(offset == ((cluster * vol->fat_bits / 8) 155 % vol->bytes_per_sector)); 156 157 if (vol->fat_bits == 12) { 158 if (offset == vol->bytes_per_sector - 1) { 159 if (readOnly) { 160 block2 = (uint8 *)block_cache_get(vol->fBlockCache, 161 ++sector); 162 } else { 163 block2 = (uint8 *)block_cache_get_writable(vol->fBlockCache, 164 ++sector, -1); 165 } 166 167 if (block2 == NULL) { 168 DPRINTF(0, ("_fat_ioctl_: error reading fat (sector %" 169 B_PRIu32 ")\n", sector)); 170 result = B_IO_ERROR; 171 sector--; 172 goto bi; 173 } 174 } 175 176 if (action != _IOCTL_SET_ENTRY_) { 177 if (offset == vol->bytes_per_sector - 1) 178 value = block1[offset] + 0x100 * block2[0]; 179 else 180 value = block1[offset] + 0x100 * block1[offset + 1]; 181 182 if (cluster & 1) 183 value >>= 4; 184 else 185 value &= 0xfff; 186 187 if (value > 0xff0) 188 value |= 0x0ffff000; 189 } 190 191 if (((action == _IOCTL_ALLOCATE_N_ENTRIES_) && (value == 0)) 192 || action == _IOCTL_SET_ENTRY_) { 193 uint32 andmask, ormask; 194 if (cluster & 1) { 195 ormask = (endOfChainMarker & 0xfff) << 4; 196 andmask = 0xf; 197 } else { 198 ormask = endOfChainMarker & 0xfff; 199 andmask = 0xf000; 200 } 201 202 block1[offset] &= (andmask & 0xff); 203 block1[offset] |= (ormask & 0xff); 204 if (offset == vol->bytes_per_sector - 1) { 205 mirror_fats(vol, sector - 1, block1); 206 block2[0] &= (andmask >> 8); 207 block2[0] |= (ormask >> 8); 208 } else { 209 block1[offset + 1] &= (andmask >> 8); 210 block1[offset + 1] |= (ormask >> 8); 211 } 212 } 213 214 if (offset == vol->bytes_per_sector - 1) { 215 offset = (cluster & 1) ? 1 : 0; 216 block_cache_put(vol->fBlockCache, sector - 1); 217 block1 = block2; 218 } else 219 offset += (cluster & 1) ? 2 : 1; 220 221 } else if (vol->fat_bits == 16) { 222 if (action != _IOCTL_SET_ENTRY_) { 223 value = read16(block1, offset); 224 if (value > 0xfff0) 225 value |= 0x0fff0000; 226 } 227 228 if (((action == _IOCTL_ALLOCATE_N_ENTRIES_) && (value == 0)) 229 || action == _IOCTL_SET_ENTRY_) { 230 *(uint16 *)&block1[offset] 231 = B_HOST_TO_LENDIAN_INT16(endOfChainMarker); 232 } 233 234 offset += 2; 235 } else if (vol->fat_bits == 32) { 236 if (action != _IOCTL_SET_ENTRY_) 237 value = read32(block1, offset) & 0x0fffffff; 238 239 if (((action == _IOCTL_ALLOCATE_N_ENTRIES_) && (value == 0)) 240 || action == _IOCTL_SET_ENTRY_) { 241 ASSERT((endOfChainMarker & 0xf0000000) == 0); 242 *(uint32 *)&block1[offset] 243 = B_HOST_TO_LENDIAN_INT32(endOfChainMarker); 244 } 245 246 offset += 4; 247 } else 248 ASSERT(0); 249 250 if (action == _IOCTL_COUNT_FREE_) { 251 if (value == 0) 252 result++; 253 } else if (action == _IOCTL_GET_ENTRY_) { 254 result = value; 255 goto bi; 256 } else if (action == _IOCTL_SET_ENTRY_) { 257 mirror_fats(vol, sector, block1); 258 goto bi; 259 } else if (action == _IOCTL_ALLOCATE_N_ENTRIES_ && value == 0) { 260 vol->free_clusters--; 261 mirror_fats(vol, sector, block1); 262 263 if (n == 0) { 264 ASSERT(first == 0); 265 first = last = cluster; 266 } else { 267 ASSERT(IS_DATA_CLUSTER(first)); 268 ASSERT(IS_DATA_CLUSTER(last)); 269 // set last cluster to point to us 270 271 result = _fat_ioctl_(vol, _IOCTL_SET_ENTRY_, last, cluster); 272 if (result < 0) { 273 ASSERT(0); 274 goto bi; 275 } 276 277 last = cluster; 278 } 279 280 if (++n == N) 281 goto bi; 282 } 283 284 // iterate cluster and sector if needed 285 if (++cluster == vol->total_clusters + 2) { 286 block_cache_put(vol->fBlockCache, sector); 287 288 cluster = 2; 289 offset = cluster * vol->fat_bits / 8; 290 sector = vol->reserved_sectors + vol->active_fat 291 * vol->sectors_per_fat; 292 293 if (readOnly) 294 block1 = (uint8 *)block_cache_get(vol->fBlockCache, sector); 295 else { 296 block1 = (uint8 *)block_cache_get_writable(vol->fBlockCache, 297 sector, -1); 298 } 299 } 300 301 if (offset >= vol->bytes_per_sector) { 302 block_cache_put(vol->fBlockCache, sector); 303 304 sector++; 305 offset -= vol->bytes_per_sector; 306 ASSERT(sector < vol->reserved_sectors + (vol->active_fat + 1) 307 * vol->sectors_per_fat); 308 309 if (readOnly) 310 block1 = (uint8 *)block_cache_get(vol->fBlockCache, sector); 311 else { 312 block1 = (uint8 *)block_cache_get_writable(vol->fBlockCache, 313 sector, -1); 314 } 315 } 316 317 if (block1 == NULL) { 318 DPRINTF(0, ("_fat_ioctl_: error reading fat (sector %" B_PRIu32 319 ")\n", sector)); 320 result = B_IO_ERROR; 321 goto bi; 322 } 323 } 324 325bi: 326 if (block1 != NULL) 327 block_cache_put(vol->fBlockCache, sector); 328 329 if (action == _IOCTL_ALLOCATE_N_ENTRIES_) { 330 if (result < 0) { 331 DPRINTF(0, ("pooh. there is a problem. clearing chain (%" B_PRIu32 332 ")\n", first)); 333 if (first != 0) 334 clear_fat_chain(vol, first, false); 335 } else if (n != N) { 336 DPRINTF(0, ("not enough free entries (%" B_PRId32 "/%" B_PRId32 337 " found)\n", n, N)); 338 if (first != 0) 339 clear_fat_chain(vol, first, false); 340 result = B_DEVICE_FULL; 341 } else if (result == 0) { 342 vol->last_allocated = cluster; 343 result = first; 344 ASSERT(IS_DATA_CLUSTER(first)); 345 } 346 } 347 348 if (result < B_OK) { 349 DPRINTF(0, ("_fat_ioctl_ error: action = %" B_PRIu32 " cluster = %" 350 B_PRIu32 " N = %" B_PRId32 " (%s)\n", action, cluster, N, 351 strerror(result))); 352 } 353 354 return result; 355} 356 357 358int32 359count_free_clusters(nspace *vol) 360{ 361 return _fat_ioctl_(vol, _IOCTL_COUNT_FREE_, 0, 0); 362} 363 364 365static int32 366get_fat_entry(nspace *vol, uint32 cluster) 367{ 368 int32 value = _fat_ioctl_(vol, _IOCTL_GET_ENTRY_, cluster, 0); 369 370 if (value < 0) 371 return value; 372 373 if (value == 0 || IS_DATA_CLUSTER(value)) 374 return value; 375 376 if (value > 0x0ffffff7) 377 return END_FAT_ENTRY; 378 379 if (value > 0x0ffffff0) 380 return BAD_FAT_ENTRY; 381 382 DPRINTF(0, ("invalid fat entry: %" B_PRIu32 "\n", value)); 383 return BAD_FAT_ENTRY; 384} 385 386 387static status_t 388set_fat_entry(nspace *vol, uint32 cluster, int32 value) 389{ 390 return _fat_ioctl_(vol, _IOCTL_SET_ENTRY_, cluster, value); 391} 392 393 394//! Traverse n fat entries 395int32 396get_nth_fat_entry(nspace *vol, int32 cluster, uint32 n) 397{ 398 while (n--) { 399 cluster = get_fat_entry(vol, cluster); 400 401 if (!IS_DATA_CLUSTER(cluster)) 402 break; 403 } 404 405 ASSERT(cluster != 0); 406 return cluster; 407} 408 409 410// count number of clusters in fat chain starting at given cluster 411// should only be used for calculating directory sizes because it doesn't 412// return proper error codes 413uint32 414count_clusters(nspace *vol, int32 cluster) 415{ 416 uint32 count = 0; 417 418 DPRINTF(2, ("count_clusters %" B_PRId32 "\n", cluster)); 419 420 // not intended for use on root directory 421 if (!IS_DATA_CLUSTER(cluster)) { 422 DPRINTF(0, ("count_clusters called on invalid cluster (%" B_PRId32 423 ")\n", cluster)); 424 return 0; 425 } 426 427 while (IS_DATA_CLUSTER(cluster)) { 428 count++; 429 430 // break out of circular fat chains in a sketchy manner 431 if (count == vol->total_clusters) 432 return 0; 433 434 cluster = get_fat_entry(vol, cluster); 435 } 436 437 DPRINTF(2, ("count_clusters %" B_PRId32 " = %" B_PRId32 "\n", cluster, 438 count)); 439 440 if (cluster == END_FAT_ENTRY) 441 return count; 442 443 dprintf("cluster = %" B_PRId32 "\n", cluster); 444 ASSERT(0); 445 return 0; 446} 447 448 449status_t 450clear_fat_chain(nspace *vol, uint32 cluster, bool discardBlockCache) 451{ 452 int32 c; 453 status_t result; 454 455 if (!IS_DATA_CLUSTER(cluster)) { 456 DPRINTF(0, ("clear_fat_chain called on invalid cluster (%" B_PRIu32 457 ")\n", cluster)); 458 return B_BAD_VALUE; 459 } 460 461 ASSERT(count_clusters(vol, cluster) != 0); 462 463 DPRINTF(2, ("clearing fat chain: %" B_PRIu32, cluster)); 464 while (IS_DATA_CLUSTER(cluster)) { 465 if ((c = get_fat_entry(vol, cluster)) < 0) { 466 DPRINTF(0, ("clear_fat_chain: error clearing fat entry for cluster " 467 "%" B_PRIu32 " (%s)\n", cluster, strerror(c))); 468 return c; 469 } 470 471 if ((result = set_fat_entry(vol, cluster, 0)) != B_OK) { 472 DPRINTF(0, ("clear_fat_chain: error clearing fat entry for cluster " 473 "%" B_PRIu32 " (%s)\n", cluster, strerror(result))); 474 return result; 475 } 476 477 if (discardBlockCache) { 478 block_cache_discard(vol->fBlockCache, 479 vol->data_start + (cluster - 2) * vol->sectors_per_cluster, 480 vol->sectors_per_cluster); 481 } 482 483 vol->free_clusters++; 484 cluster = c; 485 DPRINTF(2, (", %" B_PRIu32, cluster)); 486 } 487 DPRINTF(2, ("\n")); 488 489 if (cluster != END_FAT_ENTRY) { 490 dprintf("clear_fat_chain: fat chain terminated improperly with %" 491 B_PRIu32 "\n", cluster); 492 } 493 494 return 0; 495} 496 497 498status_t 499allocate_n_fat_entries(nspace *vol, int32 n, int32 *start) 500{ 501 int32 c; 502 503 ASSERT(n > 0); 504 505 DPRINTF(2, ("allocating %" B_PRId32 " fat entries\n", n)); 506 507 c = _fat_ioctl_(vol, _IOCTL_ALLOCATE_N_ENTRIES_, 0, n); 508 if (c < 0) 509 return c; 510 511 ASSERT(IS_DATA_CLUSTER(c)); 512 ASSERT(count_clusters(vol, c) == (uint32)n); 513 514 DPRINTF(2, ("allocated %" B_PRId32 " fat entries at %" B_PRId32 "\n", n, 515 c)); 516 517 *start = c; 518 return 0; 519} 520 521 522status_t 523set_fat_chain_length(nspace *vol, vnode *node, uint32 clusters, 524 bool discardBlockCache) 525{ 526 status_t result; 527 int32 c, n; 528 uint32 i; 529 530 DPRINTF(1, ("set_fat_chain_length: %" B_PRIdINO " to %" B_PRIu32 531 " clusters (%" B_PRIu32 ")\n", node->vnid, clusters, node->cluster)); 532 533 if (IS_FIXED_ROOT(node->cluster) 534 || (!IS_DATA_CLUSTER(node->cluster) && (node->cluster != 0))) { 535 DPRINTF(0, ("set_fat_chain_length called on invalid cluster (%" B_PRIu32 536 ")\n", node->cluster)); 537 return B_BAD_VALUE; 538 } 539 540 if (clusters == 0) { 541 DPRINTF(1, ("truncating node to zero bytes\n")); 542 if (node->cluster == 0) 543 return B_OK; 544 545 c = node->cluster; 546 if ((result = clear_fat_chain(vol, c, discardBlockCache)) != B_OK) 547 return result; 548 549 node->cluster = 0; 550 node->end_cluster = 0; 551 552 // TODO: don't have to do this this way -- can clean up nicely 553 do { 554 result = vcache_set_entry(vol, node->vnid, 555 GENERATE_DIR_INDEX_VNID(node->dir_vnid, node->sindex)); 556 // repeat until memory is freed up 557 if (result != B_OK) 558 snooze(5000LL); 559 } while (result != B_OK); 560 561 /* write to disk so that get_next_dirent doesn't barf */ 562 write_vnode_entry(vol, node); 563 return result; 564 } 565 566 if (node->cluster == 0) { 567 DPRINTF(1, ("node has no clusters. adding %" B_PRIu32 " clusters\n", 568 clusters)); 569 570 if ((result = allocate_n_fat_entries(vol, clusters, &n)) != B_OK) 571 return result; 572 573 node->cluster = n; 574 node->end_cluster = get_nth_fat_entry(vol, n, clusters - 1); 575 576 // TODO: don't have to do this this way -- can clean up nicely 577 do { 578 result = vcache_set_entry(vol, node->vnid, 579 GENERATE_DIR_CLUSTER_VNID(node->dir_vnid, node->cluster)); 580 // repeat until memory is freed up 581 if (result != B_OK) 582 snooze(5000LL); 583 } while (result != B_OK); 584 585 /* write to disk so that get_next_dirent doesn't barf */ 586 write_vnode_entry(vol, node); 587 return result; 588 } 589 590 i = (node->st_size + vol->bytes_per_sector * vol->sectors_per_cluster - 1) 591 / vol->bytes_per_sector / vol->sectors_per_cluster; 592 if (i == clusters) 593 return B_OK; 594 595 if (clusters > i) { 596 // add new fat entries 597 DPRINTF(1, ("adding %" B_PRIu32 " new fat entries\n", clusters - i)); 598 if ((result = allocate_n_fat_entries(vol, clusters - i, &n)) != B_OK) 599 return result; 600 601 ASSERT(IS_DATA_CLUSTER(n)); 602 603 result = set_fat_entry(vol, node->end_cluster, n); 604 if (result < B_OK) { 605 clear_fat_chain(vol, n, false); 606 return result; 607 } 608 609 node->end_cluster = get_nth_fat_entry(vol, n, clusters - i - 1); 610 return result; 611 } 612 613 // traverse fat chain 614 c = node->cluster; 615 n = get_fat_entry(vol, c); 616 for (i = 1; i < clusters; i++) { 617 if (!IS_DATA_CLUSTER(n)) 618 break; 619 620 c = n; 621 n = get_fat_entry(vol, c); 622 } 623 624 ASSERT(i == clusters); 625 ASSERT(n != END_FAT_ENTRY); 626 627 if (i == clusters && n == END_FAT_ENTRY) 628 return B_OK; 629 630 if (n < 0) 631 return n; 632 633 if (n != END_FAT_ENTRY && !IS_DATA_CLUSTER(n)) 634 return B_BAD_VALUE; 635 636 // clear trailing fat entries 637 DPRINTF(1, ("clearing trailing fat entries\n")); 638 if ((result = set_fat_entry(vol, c, 0x0fffffff)) != B_OK) 639 return result; 640 641 node->end_cluster = c; 642 return clear_fat_chain(vol, n, discardBlockCache); 643} 644 645 646void 647dump_fat_chain(nspace *vol, uint32 cluster) 648{ 649 dprintf("fat chain: %" B_PRIu32, cluster); 650 while (IS_DATA_CLUSTER(cluster)) { 651 cluster = get_fat_entry(vol, cluster); 652 dprintf(" %" B_PRIu32, cluster); 653 } 654 655 dprintf("\n"); 656} 657 658/* 659status_t fragment(nspace *vol, uint32 *pattern) 660{ 661 uint32 sector, offset, previous_entry, i, val; 662 uchar *buffer; 663 bool dirty = FALSE; 664 665 srand(time(NULL)|1); 666 667 if (vol->fat_bits == 16) 668 previous_entry = 0xffff; 669 else if (vol->fat_bits == 32) 670 previous_entry = 0x0fffffff; 671 else { 672 dprintf("fragment: only for FAT16 and FAT32\n"); 673 return ENOSYS; 674 } 675 676 sector = vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat + 677 ((vol->total_clusters + 2 - 1) * (vol->fat_bits / 8)) / 678 vol->bytes_per_sector; 679 offset = ((vol->total_clusters + 2 - 1) * (vol->fat_bits / 8)) % 680 vol->bytes_per_sector; 681 682 buffer = (uchar *)get_block(vol->fd, sector, vol->bytes_per_sector); 683 if (!buffer) { 684 dprintf("fragment: error getting fat block %lx\n", sector); 685 return EINVAL; 686 } 687 688 val = pattern ? *pattern : rand(); 689 690 for (i=vol->total_clusters+1;i>=2;i--) { 691 if (val & (1 << (i & 31))) { 692 if (vol->fat_bits == 16) { 693 if (read16(buffer, offset) == 0) { 694 buffer[offset+0] = (previous_entry ) & 0xff; 695 buffer[offset+1] = (previous_entry >> 8) & 0xff; 696 previous_entry = i; 697 dirty = TRUE; 698 vol->free_clusters--; 699 } 700 } else { 701 if (read32(buffer, offset) == 0) { 702 buffer[offset+0] = (previous_entry ) & 0xff; 703 buffer[offset+1] = (previous_entry >> 8) & 0xff; 704 buffer[offset+2] = (previous_entry >> 16) & 0xff; 705 buffer[offset+3] = (previous_entry >> 24) & 0xff; 706 previous_entry = i; 707 dirty = TRUE; 708 vol->free_clusters--; 709 } 710 } 711 } 712 713 if (!offset) { 714 if (dirty) { 715 mark_blocks_dirty(vol->fd, sector, 1); 716 mirror_fats(vol, sector, buffer); 717 } 718 release_block(vol->fd, sector); 719 720 dirty = FALSE; 721 sector--; 722 723 buffer = (uchar *)get_block(vol->fd, sector, 724 vol->bytes_per_sector); 725 if (!buffer) { 726 dprintf("fragment: error getting fat block %lx\n", sector); 727 return EINVAL; 728 } 729 } 730 731 offset = (offset - vol->fat_bits / 8 + vol->bytes_per_sector) % 732 vol->bytes_per_sector; 733 734 if (!pattern && ((i & 31) == 31)) 735 val = rand(); 736 } 737 738 if (dirty) { 739 mark_blocks_dirty(vol->fd, sector, 1); 740 mirror_fats(vol, sector, buffer); 741 } 742 release_block(vol->fd, sector); 743 744 vol->last_allocated = (rand() % vol->total_clusters) + 2; 745 746 return B_OK; 747} 748*/ 749 750