Bring back ext2 code from branch
[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 <fmifs.h>
12
13 /* GLOBALS ***************************************************************/
14
15 int inode_ratio = 4096;
16
17 BOOLEAN bLocked = FALSE;
18
19 /* FUNCTIONS *************************************************************/
20
21 int int_log2(int arg)
22 {
23 int l = 0;
24
25 arg >>= 1;
26
27 while (arg)
28 {
29 l++;
30 arg >>= 1;
31 }
32
33 return l;
34 }
35
36 int int_log10(unsigned int arg)
37 {
38 int l;
39
40 for (l=0; arg ; l++)
41 arg = arg / 10;
42
43 return l;
44 }
45
46
47 static char default_str[] = "default";
48
49 struct mke2fs_defaults {
50 const char *type;
51 int size;
52 int blocksize;
53 int inode_ratio;
54 } settings[] = {
55 { default_str, 0, 4096, 8192 },
56 { default_str, 512, 1024, 4096 },
57 { default_str, 3, 1024, 8192 },
58 { "journal", 0, 4096, 8192 },
59 { "news", 0, 4096, 4096 },
60 { "largefile", 0, 4096, 1024 * 1024 },
61 { "largefile4", 0, 4096, 4096 * 1024 },
62 { 0, 0, 0, 0},
63 };
64
65 void set_fs_defaults(const char *fs_type,
66 PEXT2_SUPER_BLOCK super,
67 int blocksize, int *inode_ratio)
68 {
69 int megs;
70 int ratio = 0;
71 struct mke2fs_defaults *p;
72
73 megs = (super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024);
74
75 if (inode_ratio)
76 ratio = *inode_ratio;
77
78 if (!fs_type)
79 fs_type = default_str;
80
81 for (p = settings; p->type; p++)
82 {
83 if ((strcmp(p->type, fs_type) != 0) &&
84 (strcmp(p->type, default_str) != 0))
85 continue;
86
87 if ((p->size != 0) &&
88 (megs > p->size))
89 continue;
90
91 if (ratio == 0)
92 *inode_ratio = p->inode_ratio;
93
94 if (blocksize == 0)
95 {
96 super->s_log_frag_size = super->s_log_block_size =
97 int_log2(p->blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
98 }
99 }
100
101 if (blocksize == 0)
102 {
103 super->s_blocks_count /= EXT2_BLOCK_SIZE(super) / 1024;
104 }
105 }
106
107 /*
108 * Helper function which zeros out _num_ blocks starting at _blk_. In
109 * case of an error, the details of the error is returned via _ret_blk_
110 * and _ret_count_ if they are non-NULL pointers. Returns 0 on
111 * success, and an error code on an error.
112 *
113 * As a special case, if the first argument is NULL, then it will
114 * attempt to free the static zeroizing buffer. (This is to keep
115 * programs that check for memory leaks happy.)
116 */
117 bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num,
118 ULONG *ret_blk, ULONG *ret_count)
119 {
120 ULONG j, count, next_update, next_update_incr;
121 static unsigned char *buf;
122 bool retval;
123
124 /* If fs is null, clean up the static buffer and return */
125 if (!fs)
126 {
127 if (buf)
128 {
129 RtlFreeHeap(GetProcessHeap(), 0, buf);
130 buf = 0;
131 }
132 return true;
133 }
134
135 #define STRIDE_LENGTH 8
136
137 /* Allocate the zeroizing buffer if necessary */
138 if (!buf)
139 {
140 buf = (unsigned char *)
141 RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize * STRIDE_LENGTH);
142 if (!buf)
143 {
144 KdPrint(("Mke2fs: while allocating zeroizing buffer"));
145 return false;
146 }
147 memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
148 }
149
150 /* OK, do the write loop */
151 next_update = 0;
152 next_update_incr = num / 100;
153 if (next_update_incr < 1)
154 next_update_incr = 1;
155
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(GetProcessHeap(), 0, SECTOR_SIZE*nsect);
192 if (!buf)
193 {
194 KdPrint(("Mke2fs: Out of memory erasing sectors %d-%d\n",
195 sect, sect + nsect - 1));
196 return false;
197 }
198
199 memset(buf, 0, (ULONG)nsect * SECTOR_SIZE);
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 // 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(GetProcessHeap(), 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(GetProcessHeap(), 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 KdPrint(("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 KdPrint(("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(GetProcessHeap(), 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 KdPrint(("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 KdPrint(("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 KdPrint(("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(GetProcessHeap(), 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 KdPrint(("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n"));
662 return false;
663 }
664
665 KdPrint(("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 KdPrint(("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 KdPrint(("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 Ext2Format(PUNICODE_STRING DriveRoot,
801 ULONG MediaFlag,
802 PUNICODE_STRING Label,
803 BOOLEAN QuickFormat,
804 ULONG ClusterSize,
805 PFMIFSCALLBACK Callback)
806 {
807 BOOLEAN bRet = FALSE;
808 NTSTATUS Status = STATUS_UNSUCCESSFUL;
809 /* Super Block: 1024 bytes long */
810 EXT2_SUPER_BLOCK Ext2Sb;
811 /* File Sys Structure */
812 EXT2_FILESYS FileSys;
813 ULONG Percent;
814
815 KdPrint(("%s:%d\n", __FILE__, __LINE__));
816
817 Callback(PROGRESS, 0, (PVOID)&Percent);
818
819 KdPrint(("%s:%d\n", __FILE__, __LINE__));
820
821 RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK));
822 RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS));
823 FileSys.ext2_sb = &Ext2Sb;
824
825 KdPrint(("%s:%d\n", __FILE__, __LINE__));
826
827 if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot)))
828 {
829 KdPrint(("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot));
830 goto clean_up;
831 }
832
833 KdPrint(("%s:%d\n", __FILE__, __LINE__));
834
835 if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys)))
836 {
837 KdPrint(("Mke2fs: Can't get media information\n"));
838 goto clean_up;
839 }
840
841 set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio);
842
843 Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart /
844 EXT2_BLOCK_SIZE(&Ext2Sb);
845
846 KdPrint(("%s:%d\n", __FILE__, __LINE__));
847
848 /*
849 * Calculate number of inodes based on the inode ratio
850 */
851 Ext2Sb.s_inodes_count =
852 (ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio);
853
854 /*
855 * Calculate number of blocks to reserve
856 */
857 Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100;
858
859 KdPrint(("%s:%d\n", __FILE__, __LINE__));
860
861 Status = Ext2LockVolume(&FileSys);
862 if (NT_SUCCESS(Status))
863 {
864 bLocked = TRUE;
865 }
866
867 KdPrint(("%s:%d\n", __FILE__, __LINE__));
868
869 // Initialize
870 if (!ext2_initialize_sb(&FileSys))
871 {
872 KdPrint(("Mke2fs: error...\n"));
873 goto clean_up;
874 }
875
876 KdPrint(("%s:%d\n", __FILE__, __LINE__));
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 int 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 ULONG rsv = 65536 / FileSys.blocksize;
926 ULONG blocks = Ext2Sb.s_blocks_count;
927 ULONG start;
928 ULONG ret_blk;
929
930 #ifdef ZAP_BOOTBLOCK
931 zap_sector(&FileSys, 0, 2);
932 #endif
933
934 /*
935 * Wipe out any old MD RAID (or other) metadata at the end
936 * of the device. This will also verify that the device is
937 * as large as we think. Be careful with very small devices.
938 */
939
940 start = (blocks & ~(rsv - 1));
941 if (start > rsv)
942 start -= rsv;
943
944 if (start > 0)
945 bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL);
946
947 if (!bRet)
948 {
949 KdPrint(("Mke2fs: zeroing block %lu at end of filesystem", ret_blk));
950 goto clean_up;
951 }
952
953 write_inode_tables(&FileSys);
954
955 create_root_dir(&FileSys);
956 create_lost_and_found(&FileSys);
957
958 ext2_reserve_inodes(&FileSys);
959
960 create_bad_block_inode(&FileSys, NULL);
961
962 KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information ... \n"));
963
964 if (!QuickFormat)
965 {
966 KdPrint(("Mke2fs: Slow format not supported yet\n"));
967 }
968
969 if (!ext2_flush(&FileSys))
970 {
971 bRet = false;
972 KdPrint(("Mke2fs: Warning, had trouble writing out superblocks.\n"));
973 goto clean_up;
974 }
975
976 KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information done!\n"));
977
978 bRet = true;
979 Status = STATUS_SUCCESS;
980
981 clean_up:
982
983 // Clean up ...
984 ext2_free_group_desc(&FileSys);
985
986 ext2_free_block_bitmap(&FileSys);
987 ext2_free_inode_bitmap(&FileSys);
988
989 if (!bRet)
990 {
991 Ext2DisMountVolume(&FileSys);
992 }
993 else
994 {
995 if(bLocked)
996 {
997 Ext2UnLockVolume(&FileSys);
998 }
999 }
1000
1001 KdPrint(("%s:%d\n", __FILE__, __LINE__));
1002 Ext2CloseDevice(&FileSys);
1003 KdPrint(("%s:%d\n", __FILE__, __LINE__));
1004
1005 KdPrint(("%s:%d\n", __FILE__, __LINE__));
1006 Callback(DONE, 0, (PVOID)&bRet);
1007 KdPrint(("%s:%d\n", __FILE__, __LINE__));
1008
1009 return Status;
1010 }