xref: /reactos/sdk/lib/fslib/ext2lib/Mke2fs.c (revision 7e22dc05)
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