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
int_log2(int arg)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
int_log10(unsigned int arg)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
set_fs_defaults(const char * fs_type,PEXT2_SUPER_BLOCK super,int blocksize,int * inode_ratio)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 */
zero_blocks(PEXT2_FILESYS fs,ULONG blk,ULONG num,ULONG * ret_blk,ULONG * ret_count)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
zap_sector(PEXT2_FILESYS Ext2Sys,int sect,int nsect)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
ext2_mkdir(PEXT2_FILESYS fs,ULONG parent,ULONG inum,char * name,ULONG * no,PEXT2_INODE pid)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
create_root_dir(PEXT2_FILESYS fs)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
create_lost_and_found(PEXT2_FILESYS Ext2Sys)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
write_primary_superblock(PEXT2_FILESYS Ext2Sys,PEXT2_SUPER_BLOCK super)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 */
ext2_update_dynamic_rev(PEXT2_FILESYS fs)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
ext2_flush(PEXT2_FILESYS fs)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
create_journal_dev(PEXT2_FILESYS fs)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
Ext2DataBlocks(PEXT2_FILESYS Ext2Sys,ULONG TotalBlocks)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
Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys,ULONG DataBlocks)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
Ext2Format(IN PUNICODE_STRING DriveRoot,IN PFMIFSCALLBACK Callback,IN BOOLEAN QuickFormat,IN BOOLEAN BackwardCompatible,IN MEDIA_TYPE MediaType,IN PUNICODE_STRING Label,IN ULONG ClusterSize)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
Ext2Chkdsk(IN PUNICODE_STRING DriveRoot,IN PFMIFSCALLBACK Callback,IN BOOLEAN FixErrors,IN BOOLEAN Verbose,IN BOOLEAN CheckOnlyIfDirty,IN BOOLEAN ScanDrive,IN PVOID pUnknown1,IN PVOID pUnknown2,IN PVOID pUnknown3,IN PVOID pUnknown4,IN PULONG ExitStatus)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