1 /* 2 * PROJECT: Mke2fs 3 * FILE: Disk.c 4 * PROGRAMMER: Matt Wu <mattwu@163.com> 5 * HOMEPAGE: http://ext2.yeah.net 6 */ 7 8 /* INCLUDES **************************************************************/ 9 10 #include "Mke2fs.h" 11 12 #include <fmifs/fmifs.h> 13 #include <debug.h> 14 15 /* GLOBALS ***************************************************************/ 16 17 int inode_ratio = 4096; 18 19 BOOLEAN bLocked = FALSE; 20 21 /* This is needed for the ext2fs driver to mount the volume */ 22 #define ZAP_BOOTBLOCK 23 24 /* FUNCTIONS *************************************************************/ 25 26 int int_log2(int arg) 27 { 28 int l = 0; 29 30 arg >>= 1; 31 32 while (arg) 33 { 34 l++; 35 arg >>= 1; 36 } 37 38 return l; 39 } 40 41 int int_log10(unsigned int arg) 42 { 43 int l; 44 45 for (l=0; arg ; l++) 46 arg = arg / 10; 47 48 return l; 49 } 50 51 52 static char default_str[] = "default"; 53 54 struct mke2fs_defaults { 55 const char *type; 56 int size; 57 int blocksize; 58 int inode_ratio; 59 } settings[] = { 60 { default_str, 0, 4096, 8192 }, 61 { default_str, 512, 1024, 4096 }, 62 { default_str, 3, 1024, 8192 }, 63 { "journal", 0, 4096, 8192 }, 64 { "news", 0, 4096, 4096 }, 65 { "largefile", 0, 4096, 1024 * 1024 }, 66 { "largefile4", 0, 4096, 4096 * 1024 }, 67 { 0, 0, 0, 0}, 68 }; 69 70 void set_fs_defaults(const char *fs_type, 71 PEXT2_SUPER_BLOCK super, 72 int blocksize, int *inode_ratio) 73 { 74 int megs; 75 int ratio = 0; 76 struct mke2fs_defaults *p; 77 78 megs = (super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024); 79 80 if (inode_ratio) 81 ratio = *inode_ratio; 82 83 if (!fs_type) 84 fs_type = default_str; 85 86 for (p = settings; p->type; p++) 87 { 88 if ((strcmp(p->type, fs_type) != 0) && 89 (strcmp(p->type, default_str) != 0)) 90 continue; 91 92 if ((p->size != 0) && 93 (megs > p->size)) 94 continue; 95 96 if (ratio == 0) 97 *inode_ratio = p->inode_ratio; 98 99 if (blocksize == 0) 100 { 101 super->s_log_frag_size = super->s_log_block_size = 102 int_log2(p->blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); 103 } 104 } 105 106 if (blocksize == 0) 107 { 108 super->s_blocks_count /= EXT2_BLOCK_SIZE(super) / 1024; 109 } 110 } 111 112 /* 113 * Helper function which zeros out _num_ blocks starting at _blk_. In 114 * case of an error, the details of the error is returned via _ret_blk_ 115 * and _ret_count_ if they are non-NULL pointers. Returns 0 on 116 * success, and an error code on an error. 117 * 118 * As a special case, if the first argument is NULL, then it will 119 * attempt to free the static zeroizing buffer. (This is to keep 120 * programs that check for memory leaks happy.) 121 */ 122 bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num, 123 ULONG *ret_blk, ULONG *ret_count) 124 { 125 ULONG j, count; 126 static unsigned char *buf; 127 bool retval; 128 129 /* If fs is null, clean up the static buffer and return */ 130 if (!fs) 131 { 132 if (buf) 133 { 134 RtlFreeHeap(RtlGetProcessHeap(), 0, buf); 135 buf = 0; 136 } 137 return true; 138 } 139 140 #define STRIDE_LENGTH 8 141 142 /* Allocate the zeroizing buffer if necessary */ 143 if (!buf) 144 { 145 buf = (unsigned char *) 146 RtlAllocateHeap(RtlGetProcessHeap(), 0, fs->blocksize * STRIDE_LENGTH); 147 if (!buf) 148 { 149 DPRINT1("Mke2fs: while allocating zeroizing buffer"); 150 if (ret_blk) 151 *ret_blk = blk; 152 return false; 153 } 154 memset(buf, 0, fs->blocksize * STRIDE_LENGTH); 155 } 156 157 /* OK, do the write loop */ 158 for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) 159 { 160 if (num-j > STRIDE_LENGTH) 161 count = STRIDE_LENGTH; 162 else 163 count = num - j; 164 165 retval = NT_SUCCESS(Ext2WriteDisk( 166 fs, 167 ((ULONGLONG)blk * fs->blocksize), 168 count * fs->blocksize, 169 buf)); 170 171 if (!retval) 172 { 173 if (ret_count) 174 *ret_count = count; 175 176 if (ret_blk) 177 *ret_blk = blk; 178 179 return retval; 180 } 181 } 182 183 return true; 184 } 185 186 187 bool zap_sector(PEXT2_FILESYS Ext2Sys, int sect, int nsect) 188 { 189 unsigned char *buf; 190 ULONG *magic; 191 192 buf = (unsigned char *) 193 RtlAllocateHeap(RtlGetProcessHeap(), 0, SECTOR_SIZE*nsect); 194 if (!buf) 195 { 196 DPRINT1("Mke2fs: Out of memory erasing sectors %d-%d\n", 197 sect, sect + nsect - 1); 198 return false; 199 } 200 201 #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ 202 #define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */ 203 #define BSD_LABEL_OFFSET 64 204 205 if (sect == 0) 206 { 207 Ext2ReadDisk( 208 Ext2Sys, 209 (LONGLONG)(sect * SECTOR_SIZE), 210 SECTOR_SIZE, buf); 211 212 // Check for a BSD disklabel, and don't erase it if so 213 magic = (ULONG *) (buf + BSD_LABEL_OFFSET); 214 if ((*magic == BSD_DISKMAGIC) || (*magic == BSD_MAGICDISK)) 215 goto clean_up; 216 } 217 218 memset(buf, 0, (ULONG)nsect * SECTOR_SIZE); 219 220 // Write buf to disk 221 Ext2WriteDisk( Ext2Sys, 222 (LONGLONG)(sect * SECTOR_SIZE), 223 (ULONG)nsect * SECTOR_SIZE, 224 buf ); 225 226 clean_up: 227 228 RtlFreeHeap(RtlGetProcessHeap(), 0, buf); 229 230 return true; 231 } 232 233 bool ext2_mkdir( PEXT2_FILESYS fs, 234 ULONG parent, 235 ULONG inum, 236 char *name, 237 ULONG *no, 238 PEXT2_INODE pid ) 239 { 240 bool retval; 241 EXT2_INODE parent_inode, inode; 242 ULONG ino = inum; 243 //ULONG scratch_ino; 244 ULONG blk; 245 char *block = 0; 246 int filetype = 0; 247 248 LARGE_INTEGER SysTime; 249 250 NtQuerySystemTime(&SysTime); 251 252 /* 253 * Allocate an inode, if necessary 254 */ 255 if (!ino) 256 { 257 retval = ext2_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino); 258 if (!retval) 259 goto cleanup; 260 } 261 262 if (no) 263 *no = ino; 264 265 /* 266 * Allocate a data block for the directory 267 */ 268 retval = ext2_new_block(fs, 0, 0, &blk); 269 if (!retval) 270 goto cleanup; 271 272 /* 273 * Create a scratch template for the directory 274 */ 275 retval = ext2_new_dir_block(fs, ino, parent, &block); 276 if (!retval) 277 goto cleanup; 278 279 /* 280 * Get the parent's inode, if necessary 281 */ 282 if (parent != ino) 283 { 284 retval = ext2_load_inode(fs, parent, &parent_inode); 285 if (!retval) 286 goto cleanup; 287 } 288 else 289 { 290 memset(&parent_inode, 0, sizeof(parent_inode)); 291 } 292 293 /* 294 * Create the inode structure.... 295 */ 296 memset(&inode, 0, sizeof(EXT2_INODE)); 297 inode.i_mode = (USHORT)(LINUX_S_IFDIR | (0777 & ~fs->umask)); 298 inode.i_uid = inode.i_gid = 0; 299 inode.i_blocks = fs->blocksize / 512; 300 inode.i_block[0] = blk; 301 inode.i_links_count = 2; 302 RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime); 303 inode.i_ctime = inode.i_atime = inode.i_mtime; 304 inode.i_size = fs->blocksize; 305 306 /* 307 * Write out the inode and inode data block 308 */ 309 retval = ext2_write_block(fs, blk, block); 310 if (!retval) 311 goto cleanup; 312 313 retval = ext2_save_inode(fs, ino, &inode); 314 if (!retval) 315 goto cleanup; 316 317 if (pid) 318 { 319 *pid = inode; 320 } 321 322 if (parent != ino) 323 { 324 /* 325 * Add entry for this inode to parent dir 's block 326 */ 327 328 if (fs->ext2_sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE) 329 filetype = EXT2_FT_DIR; 330 331 retval = ext2_add_entry(fs, parent, ino, filetype, name); 332 333 if (!retval) 334 goto cleanup; 335 336 /* 337 * Update parent inode's counts 338 */ 339 340 parent_inode.i_links_count++; 341 retval = ext2_save_inode(fs, parent, &parent_inode); 342 if (!retval) 343 goto cleanup; 344 345 } 346 347 /* 348 * Update accounting.... 349 */ 350 ext2_block_alloc_stats(fs, blk, +1); 351 ext2_inode_alloc_stats2(fs, ino, +1, 1); 352 353 cleanup: 354 355 if (block) 356 { 357 RtlFreeHeap(RtlGetProcessHeap(), 0, block); 358 block = NULL; 359 } 360 361 return retval; 362 } 363 364 bool create_root_dir(PEXT2_FILESYS fs) 365 { 366 bool retval; 367 EXT2_INODE inode; 368 369 retval = ext2_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0, NULL, &inode); 370 371 if (!retval) 372 { 373 DPRINT1("Mke2fs: while creating root dir"); 374 return false; 375 } 376 377 { 378 inode.i_uid = 0; 379 inode.i_gid = 0; 380 381 retval = ext2_save_inode(fs, EXT2_ROOT_INO, &inode); 382 if (!retval) 383 { 384 DPRINT1("Mke2fs: while setting root inode ownership"); 385 return false; 386 } 387 } 388 389 return true; 390 } 391 392 bool create_lost_and_found(PEXT2_FILESYS Ext2Sys) 393 { 394 bool retval; 395 ULONG ino; 396 char *name = "lost+found"; 397 int lpf_size = 0; 398 EXT2_INODE inode; 399 ULONG dwBlk = 0; 400 BOOLEAN bExt= TRUE; 401 402 PEXT2_DIR_ENTRY dir; 403 404 char * buf; 405 406 buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize); 407 if (!buf) 408 { 409 bExt = FALSE; 410 } 411 else 412 { 413 memset(buf, 0, Ext2Sys->blocksize); 414 415 dir = (PEXT2_DIR_ENTRY) buf; 416 dir->rec_len = Ext2Sys->blocksize; 417 } 418 419 Ext2Sys->umask = 077; 420 retval = ext2_mkdir(Ext2Sys, EXT2_ROOT_INO, 0, name, &ino, &inode); 421 422 if (!retval) 423 { 424 DPRINT1("Mke2fs: while creating /lost+found.\n"); 425 return false; 426 } 427 428 if (!bExt) 429 goto errorout; 430 431 lpf_size = inode.i_size; 432 433 while(TRUE) 434 { 435 if (lpf_size >= 16*1024) 436 break; 437 438 retval = ext2_alloc_block(Ext2Sys, 0, &dwBlk); 439 440 if (! retval) 441 { 442 DPRINT1("Mke2fs: create_lost_and_found: error alloc block.\n"); 443 break; 444 } 445 446 retval = ext2_expand_inode(Ext2Sys, &inode, dwBlk); 447 if (!retval) 448 { 449 DPRINT1("Mke2fs: errors when expanding /lost+found.\n"); 450 break; 451 } 452 453 ext2_write_block(Ext2Sys, dwBlk, buf); 454 455 inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE); 456 lpf_size += Ext2Sys->blocksize; 457 } 458 459 { 460 inode.i_size = lpf_size; 461 462 ASSERT( (inode.i_size/Ext2Sys->blocksize) == 463 Ext2DataBlocks(Ext2Sys, inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE))); 464 465 ASSERT( (inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)) == 466 Ext2TotalBlocks(Ext2Sys, inode.i_size/Ext2Sys->blocksize)); 467 468 } 469 470 ext2_save_inode(Ext2Sys, ino, &inode); 471 472 errorout: 473 474 if (buf) 475 { 476 RtlFreeHeap(RtlGetProcessHeap(), 0, buf); 477 } 478 479 return true; 480 } 481 482 /* 483 * This function forces out the primary superblock. We need to only 484 * write out those fields which we have changed, since if the 485 * filesystem is mounted, it may have changed some of the other 486 * fields. 487 * 488 * It takes as input a superblock which has already been byte swapped 489 * (if necessary). 490 */ 491 492 bool write_primary_superblock(PEXT2_FILESYS Ext2Sys, PEXT2_SUPER_BLOCK super) 493 { 494 bool bRet; 495 496 bRet = NT_SUCCESS(Ext2WriteDisk( 497 Ext2Sys, 498 ((LONGLONG)SUPERBLOCK_OFFSET), 499 SUPERBLOCK_SIZE, (PUCHAR)super)); 500 501 502 503 return bRet; 504 } 505 506 507 /* 508 * Updates the revision to EXT2_DYNAMIC_REV 509 */ 510 void ext2_update_dynamic_rev(PEXT2_FILESYS fs) 511 { 512 PEXT2_SUPER_BLOCK sb = fs->ext2_sb; 513 514 if (sb->s_rev_level > EXT2_GOOD_OLD_REV) 515 return; 516 517 sb->s_rev_level = EXT2_DYNAMIC_REV; 518 sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; 519 sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; 520 /* s_uuid is handled by e2fsck already */ 521 /* other fields should be left alone */ 522 } 523 524 525 bool ext2_flush(PEXT2_FILESYS fs) 526 { 527 ULONG i,j,maxgroup,sgrp; 528 ULONG group_block; 529 bool retval; 530 char *group_ptr; 531 unsigned long fs_state; 532 PEXT2_SUPER_BLOCK super_shadow = 0; 533 PEXT2_GROUP_DESC group_shadow = 0; 534 535 LARGE_INTEGER SysTime; 536 537 NtQuerySystemTime(&SysTime); 538 539 fs_state = fs->ext2_sb->s_state; 540 541 RtlTimeToSecondsSince1970(&SysTime, &fs->ext2_sb->s_wtime); 542 fs->ext2_sb->s_block_group_nr = 0; 543 544 super_shadow = fs->ext2_sb; 545 group_shadow = fs->group_desc; 546 547 /* 548 * Write out master superblock. This has to be done 549 * separately, since it is located at a fixed location 550 * (SUPERBLOCK_OFFSET). 551 */ 552 retval = write_primary_superblock(fs, super_shadow); 553 if (!retval) 554 goto errout; 555 556 /* 557 * If this is an external journal device, don't write out the 558 * block group descriptors or any of the backup superblocks 559 */ 560 if (fs->ext2_sb->s_feature_incompat & 561 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) 562 { 563 retval = false; 564 goto errout; 565 } 566 567 /* 568 * Set the state of the FS to be non-valid. (The state has 569 * already been backed up earlier, and will be restored when 570 * we exit.) 571 */ 572 fs->ext2_sb->s_state &= ~EXT2_VALID_FS; 573 574 /* 575 * Write out the master group descriptors, and the backup 576 * superblocks and group descriptors. 577 */ 578 group_block = fs->ext2_sb->s_first_data_block; 579 maxgroup = fs->group_desc_count; 580 581 for (i = 0; i < maxgroup; i++) 582 { 583 if (!ext2_bg_has_super(fs->ext2_sb, i)) 584 goto next_group; 585 586 sgrp = i; 587 if (sgrp > ((1 << 16) - 1)) 588 sgrp = (1 << 16) - 1; 589 590 fs->ext2_sb->s_block_group_nr = (USHORT) sgrp; 591 592 if (i !=0 ) 593 { 594 retval = NT_SUCCESS(Ext2WriteDisk( 595 fs, 596 ((ULONGLONG)group_block * fs->blocksize), 597 SUPERBLOCK_SIZE, (PUCHAR)super_shadow)); 598 599 if (!retval) 600 { 601 goto errout; 602 } 603 } 604 605 group_ptr = (char *) group_shadow; 606 607 for (j=0; j < fs->desc_blocks; j++) 608 { 609 610 retval = NT_SUCCESS(Ext2WriteDisk( 611 fs, 612 ((ULONGLONG)(group_block+1+j) * fs->blocksize), 613 fs->blocksize, (PUCHAR) group_ptr)); 614 615 if (!retval) 616 { 617 goto errout; 618 } 619 620 group_ptr += fs->blocksize; 621 } 622 623 next_group: 624 group_block += EXT2_BLOCKS_PER_GROUP(fs->ext2_sb); 625 626 } 627 628 fs->ext2_sb->s_block_group_nr = 0; 629 630 /* 631 * If the write_bitmaps() function is present, call it to 632 * flush the bitmaps. This is done this way so that a simple 633 * program that doesn't mess with the bitmaps doesn't need to 634 * drag in the bitmaps.c code. 635 */ 636 retval = ext2_write_bitmaps(fs); 637 if (!retval) 638 goto errout; 639 640 /* 641 * Flush the blocks out to disk 642 */ 643 644 // retval = io_channel_flush(fs->io); 645 646 errout: 647 648 fs->ext2_sb->s_state = (USHORT) fs_state; 649 650 return retval; 651 } 652 653 654 bool create_journal_dev(PEXT2_FILESYS fs) 655 { 656 bool retval = false; 657 char *buf = NULL; 658 ULONG blk; 659 ULONG count; 660 661 if (!retval) 662 { 663 DPRINT1("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n"); 664 return false; 665 } 666 667 DPRINT("Mke2fs: Zeroing journal device: \n"); 668 669 retval = zero_blocks(fs, 0, fs->ext2_sb->s_blocks_count, 670 &blk, &count); 671 672 zero_blocks(0, 0, 0, 0, 0); 673 674 if (!retval) 675 { 676 DPRINT1("Mke2fs: create_journal_dev: while zeroing journal device (block %lu, count %lu).\n", 677 blk, count); 678 return false; 679 } 680 681 retval = NT_SUCCESS(Ext2WriteDisk( 682 fs, 683 ((ULONGLONG)blk * (fs->ext2_sb->s_first_data_block+1)), 684 fs->blocksize, (unsigned char *)buf)); 685 686 if (!retval) 687 { 688 DPRINT1("Mke2fs: create_journal_dev: while writing journal superblock.\n"); 689 return false; 690 } 691 692 return true; 693 } 694 695 #define BLOCK_BITS (Ext2Sys->ext2_sb->s_log_block_size + 10) 696 697 ULONG 698 Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks) 699 { 700 ULONG dwData[4] = {1, 1, 1, 1}; 701 ULONG dwMeta[4] = {0, 0, 0, 0}; 702 ULONG DataBlocks = 0; 703 ULONG i, j; 704 705 if (TotalBlocks <= EXT2_NDIR_BLOCKS) 706 { 707 return TotalBlocks; 708 } 709 710 TotalBlocks -= EXT2_NDIR_BLOCKS; 711 712 for (i = 0; i < 4; i++) 713 { 714 dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i); 715 716 if (i > 0) 717 { 718 dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2)); 719 } 720 } 721 722 for( i=1; (i < 4) && (TotalBlocks > 0); i++) 723 { 724 if (TotalBlocks >= (dwData[i] + dwMeta[i])) 725 { 726 TotalBlocks -= (dwData[i] + dwMeta[i]); 727 DataBlocks += dwData[i]; 728 } 729 else 730 { 731 ULONG dwDivide = 0; 732 ULONG dwRemain = 0; 733 734 for (j=i; (j > 0) && (TotalBlocks > 0); j--) 735 { 736 dwDivide = (TotalBlocks - 1) / (dwData[j-1] + dwMeta[j-1]); 737 dwRemain = (TotalBlocks - 1) % (dwData[j-1] + dwMeta[j-1]); 738 739 DataBlocks += (dwDivide * dwData[j-1]); 740 TotalBlocks = dwRemain; 741 } 742 } 743 } 744 745 return (DataBlocks + EXT2_NDIR_BLOCKS); 746 } 747 748 749 ULONG 750 Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks) 751 { 752 ULONG dwData[4] = {1, 1, 1, 1}; 753 ULONG dwMeta[4] = {0, 0, 0, 0}; 754 ULONG TotalBlocks = 0; 755 ULONG i, j; 756 757 if (DataBlocks <= EXT2_NDIR_BLOCKS) 758 { 759 return DataBlocks; 760 } 761 762 DataBlocks -= EXT2_NDIR_BLOCKS; 763 764 for (i = 0; i < 4; i++) 765 { 766 dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i); 767 768 if (i > 0) 769 { 770 dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2)); 771 } 772 } 773 774 for( i=1; (i < 4) && (DataBlocks > 0); i++) 775 { 776 if (DataBlocks >= dwData[i]) 777 { 778 DataBlocks -= dwData[i]; 779 TotalBlocks += (dwData[i] + dwMeta[i]); 780 } 781 else 782 { 783 ULONG dwDivide = 0; 784 ULONG dwRemain = 0; 785 786 for (j=i; (j > 0) && (DataBlocks > 0); j--) 787 { 788 dwDivide = (DataBlocks) / (dwData[j-1]); 789 dwRemain = (DataBlocks) % (dwData[j-1]); 790 791 TotalBlocks += (dwDivide * (dwData[j-1] + dwMeta[j-1]) + 1); 792 DataBlocks = dwRemain; 793 } 794 } 795 } 796 797 return (TotalBlocks + EXT2_NDIR_BLOCKS); 798 } 799 800 801 BOOLEAN 802 NTAPI 803 Ext2Format( 804 IN PUNICODE_STRING DriveRoot, 805 IN PFMIFSCALLBACK Callback, 806 IN BOOLEAN QuickFormat, 807 IN BOOLEAN BackwardCompatible, 808 IN MEDIA_TYPE MediaType, 809 IN PUNICODE_STRING Label, 810 IN ULONG ClusterSize) 811 { 812 BOOLEAN bRet; 813 NTSTATUS Status = STATUS_UNSUCCESSFUL; 814 /* Super Block: 1024 bytes long */ 815 EXT2_SUPER_BLOCK Ext2Sb; 816 /* File Sys Structure */ 817 EXT2_FILESYS FileSys; 818 ULONG Percent; 819 ULONG rsv; 820 ULONG blocks; 821 ULONG start; 822 ULONG ret_blk; 823 824 // FIXME: 825 UNREFERENCED_PARAMETER(BackwardCompatible); 826 UNREFERENCED_PARAMETER(MediaType); 827 828 if (Callback != NULL) 829 { 830 Callback(PROGRESS, 0, (PVOID)&Percent); 831 } 832 833 834 RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK)); 835 RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS)); 836 FileSys.ext2_sb = &Ext2Sb; 837 838 839 if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot))) 840 { 841 DPRINT1("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot); 842 goto clean_up; 843 } 844 845 846 if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys))) 847 { 848 DPRINT1("Mke2fs: Can't get media information\n"); 849 goto clean_up; 850 } 851 852 set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio); 853 854 Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart / 855 EXT2_BLOCK_SIZE(&Ext2Sb); 856 857 858 /* 859 * Calculate number of inodes based on the inode ratio 860 */ 861 Ext2Sb.s_inodes_count = 862 (ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio); 863 864 /* 865 * Calculate number of blocks to reserve 866 */ 867 Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100; 868 869 870 Status = Ext2LockVolume(&FileSys); 871 if (NT_SUCCESS(Status)) 872 { 873 bLocked = TRUE; 874 } 875 876 Status = STATUS_UNSUCCESSFUL; 877 878 // Initialize 879 if (!ext2_initialize_sb(&FileSys)) 880 { 881 DPRINT1("Mke2fs: error...\n"); 882 goto clean_up; 883 } 884 885 886 zap_sector(&FileSys, 2, 6); 887 888 /* 889 * Generate a UUID for it... 890 */ 891 { 892 __u8 uuid[16]; 893 uuid_generate(&uuid[0]); 894 memcpy(&Ext2Sb.s_uuid[0], &uuid[0], 16); 895 } 896 897 /* 898 * Add "jitter" to the superblock's check interval so that we 899 * don't check all the filesystems at the same time. We use a 900 * kludgy hack of using the UUID to derive a random jitter value. 901 */ 902 { 903 ULONG i, val; 904 905 for (i = 0, val = 0 ; i < sizeof(Ext2Sb.s_uuid); i++) 906 val += Ext2Sb.s_uuid[i]; 907 908 Ext2Sb.s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT; 909 } 910 911 /* 912 * Set the volume label... 913 */ 914 if (Label) 915 { 916 ANSI_STRING ansi_label; 917 ansi_label.MaximumLength = sizeof(Ext2Sb.s_volume_name); 918 ansi_label.Length = 0; 919 ansi_label.Buffer = Ext2Sb.s_volume_name; 920 RtlUnicodeStringToAnsiString(&ansi_label, Label, FALSE); 921 } 922 923 ext2_print_super(&Ext2Sb); 924 925 bRet = ext2_allocate_tables(&FileSys); 926 if (!bRet) 927 { 928 goto clean_up; 929 } 930 931 /* rsv must be a power of two (64kB is MD RAID sb alignment) */ 932 rsv = 65536 / FileSys.blocksize; 933 blocks = Ext2Sb.s_blocks_count; 934 935 #ifdef ZAP_BOOTBLOCK 936 DPRINT1("Mke2fs: zeroing volume boot record\n"); 937 zap_sector(&FileSys, 0, 2); 938 #endif 939 940 /* 941 * Wipe out any old MD RAID (or other) metadata at the end 942 * of the device. This will also verify that the device is 943 * as large as we think. Be careful with very small devices. 944 */ 945 946 start = (blocks & ~(rsv - 1)); 947 if (start > rsv) 948 start -= rsv; 949 950 bRet = TRUE; 951 if (start > 0) 952 bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL); 953 954 if (!bRet) 955 { 956 DPRINT1("Mke2fs: zeroing block %lu at end of filesystem", ret_blk); 957 goto clean_up; 958 } 959 960 write_inode_tables(&FileSys); 961 962 create_root_dir(&FileSys); 963 create_lost_and_found(&FileSys); 964 965 ext2_reserve_inodes(&FileSys); 966 967 create_bad_block_inode(&FileSys, NULL); 968 969 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information ... \n"); 970 971 if (!QuickFormat) 972 { 973 DPRINT1("Mke2fs: Slow format not supported yet\n"); 974 } 975 976 if (!ext2_flush(&FileSys)) 977 { 978 DPRINT1("Mke2fs: Warning, had trouble writing out superblocks.\n"); 979 goto clean_up; 980 } 981 982 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information done!\n"); 983 984 Status = STATUS_SUCCESS; 985 986 clean_up: 987 988 // Clean up ... 989 ext2_free_group_desc(&FileSys); 990 991 ext2_free_block_bitmap(&FileSys); 992 ext2_free_inode_bitmap(&FileSys); 993 994 if(bLocked) 995 { 996 Ext2DisMountVolume(&FileSys); 997 Ext2UnLockVolume(&FileSys); 998 } 999 1000 Ext2CloseDevice(&FileSys); 1001 1002 return NT_SUCCESS(Status); 1003 } 1004 1005 BOOLEAN 1006 NTAPI 1007 Ext2Chkdsk( 1008 IN PUNICODE_STRING DriveRoot, 1009 IN PFMIFSCALLBACK Callback, 1010 IN BOOLEAN FixErrors, 1011 IN BOOLEAN Verbose, 1012 IN BOOLEAN CheckOnlyIfDirty, 1013 IN BOOLEAN ScanDrive, 1014 IN PVOID pUnknown1, 1015 IN PVOID pUnknown2, 1016 IN PVOID pUnknown3, 1017 IN PVOID pUnknown4, 1018 IN PULONG ExitStatus) 1019 { 1020 UNIMPLEMENTED; 1021 *ExitStatus = (ULONG)STATUS_SUCCESS; 1022 return TRUE; 1023 } 1024