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