[EXT2LIB]
[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
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 NTSTATUS
802 NTAPI
803 Ext2Format(IN PUNICODE_STRING DriveRoot,
804 IN FMIFS_MEDIA_FLAG MediaFlag,
805 IN PUNICODE_STRING Label,
806 IN BOOLEAN QuickFormat,
807 IN ULONG ClusterSize,
808 IN PFMIFSCALLBACK Callback)
809 {
810 BOOLEAN bRet = FALSE;
811 NTSTATUS Status = STATUS_UNSUCCESSFUL;
812 /* Super Block: 1024 bytes long */
813 EXT2_SUPER_BLOCK Ext2Sb;
814 /* File Sys Structure */
815 EXT2_FILESYS FileSys;
816 ULONG Percent;
817 ULONG rsv;
818 ULONG blocks;
819 ULONG start;
820 ULONG ret_blk;
821
822
823 if (Callback != NULL)
824 {
825 Callback(PROGRESS, 0, (PVOID)&Percent);
826 }
827
828
829 RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK));
830 RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS));
831 FileSys.ext2_sb = &Ext2Sb;
832
833
834 if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot)))
835 {
836 DPRINT1("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot);
837 goto clean_up;
838 }
839
840
841 if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys)))
842 {
843 DPRINT1("Mke2fs: Can't get media information\n");
844 goto clean_up;
845 }
846
847 set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio);
848
849 Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart /
850 EXT2_BLOCK_SIZE(&Ext2Sb);
851
852
853 /*
854 * Calculate number of inodes based on the inode ratio
855 */
856 Ext2Sb.s_inodes_count =
857 (ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio);
858
859 /*
860 * Calculate number of blocks to reserve
861 */
862 Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100;
863
864
865 Status = Ext2LockVolume(&FileSys);
866 if (NT_SUCCESS(Status))
867 {
868 bLocked = TRUE;
869 }
870
871
872 // Initialize
873 if (!ext2_initialize_sb(&FileSys))
874 {
875 DPRINT1("Mke2fs: error...\n");
876 goto clean_up;
877 }
878
879
880 zap_sector(&FileSys, 2, 6);
881
882 /*
883 * Generate a UUID for it...
884 */
885 {
886 __u8 uuid[16];
887 uuid_generate(&uuid[0]);
888 memcpy(&Ext2Sb.s_uuid[0], &uuid[0], 16);
889 }
890
891 /*
892 * Add "jitter" to the superblock's check interval so that we
893 * don't check all the filesystems at the same time. We use a
894 * kludgy hack of using the UUID to derive a random jitter value.
895 */
896 {
897 ULONG i, val;
898
899 for (i = 0, val = 0 ; i < sizeof(Ext2Sb.s_uuid); i++)
900 val += Ext2Sb.s_uuid[i];
901
902 Ext2Sb.s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
903 }
904
905 /*
906 * Set the volume label...
907 */
908 if (Label)
909 {
910 ANSI_STRING ansi_label;
911 ansi_label.MaximumLength = sizeof(Ext2Sb.s_volume_name);
912 ansi_label.Length = 0;
913 ansi_label.Buffer = Ext2Sb.s_volume_name;
914 RtlUnicodeStringToAnsiString(&ansi_label, Label, FALSE);
915 }
916
917 ext2_print_super(&Ext2Sb);
918
919 bRet = ext2_allocate_tables(&FileSys);
920
921 if (!bRet)
922 {
923 goto clean_up;
924 }
925
926 /* rsv must be a power of two (64kB is MD RAID sb alignment) */
927 rsv = 65536 / FileSys.blocksize;
928 blocks = Ext2Sb.s_blocks_count;
929
930 #ifdef ZAP_BOOTBLOCK
931 DPRINT1("Mke2fs: zeroing volume boot record\n");
932 zap_sector(&FileSys, 0, 2);
933 #endif
934
935 /*
936 * Wipe out any old MD RAID (or other) metadata at the end
937 * of the device. This will also verify that the device is
938 * as large as we think. Be careful with very small devices.
939 */
940
941 start = (blocks & ~(rsv - 1));
942 if (start > rsv)
943 start -= rsv;
944
945 if (start > 0)
946 bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL);
947
948 if (!bRet)
949 {
950 DPRINT1("Mke2fs: zeroing block %lu at end of filesystem", ret_blk);
951 goto clean_up;
952 }
953
954 write_inode_tables(&FileSys);
955
956 create_root_dir(&FileSys);
957 create_lost_and_found(&FileSys);
958
959 ext2_reserve_inodes(&FileSys);
960
961 create_bad_block_inode(&FileSys, NULL);
962
963 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information ... \n");
964
965 if (!QuickFormat)
966 {
967 DPRINT1("Mke2fs: Slow format not supported yet\n");
968 }
969
970 if (!ext2_flush(&FileSys))
971 {
972 bRet = false;
973 DPRINT1("Mke2fs: Warning, had trouble writing out superblocks.\n");
974 goto clean_up;
975 }
976
977 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information done!\n");
978
979 bRet = true;
980 Status = STATUS_SUCCESS;
981
982 clean_up:
983
984 // Clean up ...
985 ext2_free_group_desc(&FileSys);
986
987 ext2_free_block_bitmap(&FileSys);
988 ext2_free_inode_bitmap(&FileSys);
989
990 if(bLocked)
991 {
992 Ext2DisMountVolume(&FileSys);
993 Ext2UnLockVolume(&FileSys);
994 }
995
996 Ext2CloseDevice(&FileSys);
997
998 if (Callback != NULL)
999 {
1000 Callback(DONE, 0, (PVOID)&bRet);
1001 }
1002
1003 return Status;
1004 }
1005
1006 NTSTATUS
1007 WINAPI
1008 Ext2Chkdsk(IN PUNICODE_STRING DriveRoot,
1009 IN BOOLEAN FixErrors,
1010 IN BOOLEAN Verbose,
1011 IN BOOLEAN CheckOnlyIfDirty,
1012 IN BOOLEAN ScanDrive,
1013 IN PFMIFSCALLBACK Callback)
1014 {
1015 UNIMPLEMENTED;
1016 return STATUS_SUCCESS;
1017 }