Reintegrate header-work branch. Important changes include continued work on headers...
[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 /* 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(RtlGetProcessHeap(), 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(RtlGetProcessHeap(), 0, fs->blocksize * STRIDE_LENGTH);
142 if (!buf)
143 {
144 DPRINT1("Mke2fs: while allocating zeroizing buffer");
145 if (ret_blk)
146 *ret_blk = blk;
147 return false;
148 }
149 memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
150 }
151
152 /* OK, do the write loop */
153 next_update = 0;
154 next_update_incr = num / 100;
155 if (next_update_incr < 1)
156 next_update_incr = 1;
157
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 memset(buf, 0, (ULONG)nsect * SECTOR_SIZE);
202
203 #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
204 #define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */
205 #define BSD_LABEL_OFFSET 64
206
207 if (sect == 0)
208 {
209 Ext2ReadDisk(
210 Ext2Sys,
211 (LONGLONG)(sect * SECTOR_SIZE),
212 SECTOR_SIZE, buf);
213
214 // Check for a BSD disklabel, and don't erase it if so
215 magic = (ULONG *) (buf + BSD_LABEL_OFFSET);
216 if ((*magic == BSD_DISKMAGIC) || (*magic == BSD_MAGICDISK))
217 goto clean_up;
218 }
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 NTAPI
802 Ext2Format(
803 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 Callback(PROGRESS, 0, (PVOID)&Percent);
824
825
826 RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK));
827 RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS));
828 FileSys.ext2_sb = &Ext2Sb;
829
830
831 if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot)))
832 {
833 DPRINT1("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot);
834 goto clean_up;
835 }
836
837
838 if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys)))
839 {
840 DPRINT1("Mke2fs: Can't get media information\n");
841 goto clean_up;
842 }
843
844 set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio);
845
846 Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart /
847 EXT2_BLOCK_SIZE(&Ext2Sb);
848
849
850 /*
851 * Calculate number of inodes based on the inode ratio
852 */
853 Ext2Sb.s_inodes_count =
854 (ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio);
855
856 /*
857 * Calculate number of blocks to reserve
858 */
859 Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100;
860
861
862 Status = Ext2LockVolume(&FileSys);
863 if (NT_SUCCESS(Status))
864 {
865 bLocked = TRUE;
866 }
867
868
869 // Initialize
870 if (!ext2_initialize_sb(&FileSys))
871 {
872 DPRINT1("Mke2fs: error...\n");
873 goto clean_up;
874 }
875
876
877 zap_sector(&FileSys, 2, 6);
878
879 /*
880 * Generate a UUID for it...
881 */
882 {
883 __u8 uuid[16];
884 uuid_generate(&uuid[0]);
885 memcpy(&Ext2Sb.s_uuid[0], &uuid[0], 16);
886 }
887
888 /*
889 * Add "jitter" to the superblock's check interval so that we
890 * don't check all the filesystems at the same time. We use a
891 * kludgy hack of using the UUID to derive a random jitter value.
892 */
893 {
894 ULONG i, val;
895
896 for (i = 0, val = 0 ; i < sizeof(Ext2Sb.s_uuid); i++)
897 val += Ext2Sb.s_uuid[i];
898
899 Ext2Sb.s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
900 }
901
902 /*
903 * Set the volume label...
904 */
905 if (Label)
906 {
907 ANSI_STRING ansi_label;
908 ansi_label.MaximumLength = sizeof(Ext2Sb.s_volume_name);
909 ansi_label.Length = 0;
910 ansi_label.Buffer = Ext2Sb.s_volume_name;
911 RtlUnicodeStringToAnsiString(&ansi_label, Label, FALSE);
912 }
913
914 ext2_print_super(&Ext2Sb);
915
916 bRet = ext2_allocate_tables(&FileSys);
917
918 if (!bRet)
919 {
920 goto clean_up;
921 }
922
923 /* rsv must be a power of two (64kB is MD RAID sb alignment) */
924 rsv = 65536 / FileSys.blocksize;
925 blocks = Ext2Sb.s_blocks_count;
926
927 #ifdef ZAP_BOOTBLOCK
928 zap_sector(&FileSys, 0, 2);
929 #endif
930
931 /*
932 * Wipe out any old MD RAID (or other) metadata at the end
933 * of the device. This will also verify that the device is
934 * as large as we think. Be careful with very small devices.
935 */
936
937 start = (blocks & ~(rsv - 1));
938 if (start > rsv)
939 start -= rsv;
940
941 if (start > 0)
942 bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL);
943
944 if (!bRet)
945 {
946 DPRINT1("Mke2fs: zeroing block %lu at end of filesystem", ret_blk);
947 goto clean_up;
948 }
949
950 write_inode_tables(&FileSys);
951
952 create_root_dir(&FileSys);
953 create_lost_and_found(&FileSys);
954
955 ext2_reserve_inodes(&FileSys);
956
957 create_bad_block_inode(&FileSys, NULL);
958
959 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information ... \n");
960
961 if (!QuickFormat)
962 {
963 DPRINT1("Mke2fs: Slow format not supported yet\n");
964 }
965
966 if (!ext2_flush(&FileSys))
967 {
968 bRet = false;
969 DPRINT1("Mke2fs: Warning, had trouble writing out superblocks.\n");
970 goto clean_up;
971 }
972
973 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information done!\n");
974
975 bRet = true;
976 Status = STATUS_SUCCESS;
977
978 clean_up:
979
980 // Clean up ...
981 ext2_free_group_desc(&FileSys);
982
983 ext2_free_block_bitmap(&FileSys);
984 ext2_free_inode_bitmap(&FileSys);
985
986 if (!bRet)
987 {
988 Ext2DisMountVolume(&FileSys);
989 }
990 else
991 {
992 if(bLocked)
993 {
994 Ext2UnLockVolume(&FileSys);
995 }
996 }
997
998 Ext2CloseDevice(&FileSys);
999
1000 Callback(DONE, 0, (PVOID)&bRet);
1001
1002 return Status;
1003 }
1004
1005 NTSTATUS WINAPI
1006 Ext2Chkdsk(
1007 IN PUNICODE_STRING DriveRoot,
1008 IN BOOLEAN FixErrors,
1009 IN BOOLEAN Verbose,
1010 IN BOOLEAN CheckOnlyIfDirty,
1011 IN BOOLEAN ScanDrive,
1012 IN PFMIFSCALLBACK Callback)
1013 {
1014 UNIMPLEMENTED;
1015 return STATUS_SUCCESS;
1016 }