4 * PROGRAMMER: Matt Wu <mattwu@163.com>
5 * HOMEPAGE: http://ext2.yeah.net
8 /* INCLUDES **************************************************************/
12 #include <fmifs/fmifs.h>
15 /* GLOBALS ***************************************************************/
17 int inode_ratio
= 4096;
19 BOOLEAN bLocked
= FALSE
;
21 /* This is needed for the ext2fs driver to mount the volume */
24 /* FUNCTIONS *************************************************************/
41 int int_log10(unsigned int arg
)
52 static char default_str
[] = "default";
54 struct mke2fs_defaults
{
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 },
70 void set_fs_defaults(const char *fs_type
,
71 PEXT2_SUPER_BLOCK super
,
72 int blocksize
, int *inode_ratio
)
76 struct mke2fs_defaults
*p
;
78 megs
= (super
->s_blocks_count
* (EXT2_BLOCK_SIZE(super
) / 1024) / 1024);
84 fs_type
= default_str
;
86 for (p
= settings
; p
->type
; p
++)
88 if ((strcmp(p
->type
, fs_type
) != 0) &&
89 (strcmp(p
->type
, default_str
) != 0))
97 *inode_ratio
= p
->inode_ratio
;
101 super
->s_log_frag_size
= super
->s_log_block_size
=
102 int_log2(p
->blocksize
>> EXT2_MIN_BLOCK_LOG_SIZE
);
108 super
->s_blocks_count
/= EXT2_BLOCK_SIZE(super
) / 1024;
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.
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.)
122 bool zero_blocks(PEXT2_FILESYS fs
, ULONG blk
, ULONG num
,
123 ULONG
*ret_blk
, ULONG
*ret_count
)
126 static unsigned char *buf
;
129 /* If fs is null, clean up the static buffer and return */
134 RtlFreeHeap(RtlGetProcessHeap(), 0, buf
);
140 #define STRIDE_LENGTH 8
142 /* Allocate the zeroizing buffer if necessary */
145 buf
= (unsigned char *)
146 RtlAllocateHeap(RtlGetProcessHeap(), 0, fs
->blocksize
* STRIDE_LENGTH
);
149 DPRINT1("Mke2fs: while allocating zeroizing buffer");
154 memset(buf
, 0, fs
->blocksize
* STRIDE_LENGTH
);
157 /* OK, do the write loop */
158 for (j
=0; j
< num
; j
+= STRIDE_LENGTH
, blk
+= STRIDE_LENGTH
)
160 if (num
-j
> STRIDE_LENGTH
)
161 count
= STRIDE_LENGTH
;
165 retval
= NT_SUCCESS(Ext2WriteDisk(
167 ((ULONGLONG
)blk
* fs
->blocksize
),
168 count
* fs
->blocksize
,
187 bool zap_sector(PEXT2_FILESYS Ext2Sys
, int sect
, int nsect
)
192 buf
= (unsigned char *)
193 RtlAllocateHeap(RtlGetProcessHeap(), 0, SECTOR_SIZE
*nsect
);
196 DPRINT1("Mke2fs: Out of memory erasing sectors %d-%d\n",
197 sect
, sect
+ nsect
- 1);
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
209 (LONGLONG
)(sect
* SECTOR_SIZE
),
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
))
218 memset(buf
, 0, (ULONG
)nsect
* SECTOR_SIZE
);
221 Ext2WriteDisk( Ext2Sys
,
222 (LONGLONG
)(sect
* SECTOR_SIZE
),
223 (ULONG
)nsect
* SECTOR_SIZE
,
228 RtlFreeHeap(RtlGetProcessHeap(), 0, buf
);
233 bool ext2_mkdir( PEXT2_FILESYS fs
,
241 EXT2_INODE parent_inode
, inode
;
248 LARGE_INTEGER SysTime
;
250 NtQuerySystemTime(&SysTime
);
253 * Allocate an inode, if necessary
257 retval
= ext2_new_inode(fs
, parent
, LINUX_S_IFDIR
| 0755, 0, &ino
);
266 * Allocate a data block for the directory
268 retval
= ext2_new_block(fs
, 0, 0, &blk
);
273 * Create a scratch template for the directory
275 retval
= ext2_new_dir_block(fs
, ino
, parent
, &block
);
280 * Get the parent's inode, if necessary
284 retval
= ext2_load_inode(fs
, parent
, &parent_inode
);
290 memset(&parent_inode
, 0, sizeof(parent_inode
));
294 * Create the inode structure....
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
;
307 * Write out the inode and inode data block
309 retval
= ext2_write_block(fs
, blk
, block
);
313 retval
= ext2_save_inode(fs
, ino
, &inode
);
325 * Add entry for this inode to parent dir 's block
328 if (fs
->ext2_sb
->s_feature_incompat
& EXT2_FEATURE_INCOMPAT_FILETYPE
)
329 filetype
= EXT2_FT_DIR
;
331 retval
= ext2_add_entry(fs
, parent
, ino
, filetype
, name
);
337 * Update parent inode's counts
340 parent_inode
.i_links_count
++;
341 retval
= ext2_save_inode(fs
, parent
, &parent_inode
);
348 * Update accounting....
350 ext2_block_alloc_stats(fs
, blk
, +1);
351 ext2_inode_alloc_stats2(fs
, ino
, +1, 1);
357 RtlFreeHeap(RtlGetProcessHeap(), 0, block
);
364 bool create_root_dir(PEXT2_FILESYS fs
)
369 retval
= ext2_mkdir(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, 0, NULL
, &inode
);
373 DPRINT1("Mke2fs: while creating root dir");
381 retval
= ext2_save_inode(fs
, EXT2_ROOT_INO
, &inode
);
384 DPRINT1("Mke2fs: while setting root inode ownership");
392 bool create_lost_and_found(PEXT2_FILESYS Ext2Sys
)
396 char *name
= "lost+found";
406 buf
= (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys
->blocksize
);
413 memset(buf
, 0, Ext2Sys
->blocksize
);
415 dir
= (PEXT2_DIR_ENTRY
) buf
;
416 dir
->rec_len
= Ext2Sys
->blocksize
;
419 Ext2Sys
->umask
= 077;
420 retval
= ext2_mkdir(Ext2Sys
, EXT2_ROOT_INO
, 0, name
, &ino
, &inode
);
424 DPRINT1("Mke2fs: while creating /lost+found.\n");
431 lpf_size
= inode
.i_size
;
435 if (lpf_size
>= 16*1024)
438 retval
= ext2_alloc_block(Ext2Sys
, 0, &dwBlk
);
442 DPRINT1("Mke2fs: create_lost_and_found: error alloc block.\n");
446 retval
= ext2_expand_inode(Ext2Sys
, &inode
, dwBlk
);
449 DPRINT1("Mke2fs: errors when expanding /lost+found.\n");
453 ext2_write_block(Ext2Sys
, dwBlk
, buf
);
455 inode
.i_blocks
+= (Ext2Sys
->blocksize
/SECTOR_SIZE
);
456 lpf_size
+= Ext2Sys
->blocksize
;
460 inode
.i_size
= lpf_size
;
462 ASSERT( (inode
.i_size
/Ext2Sys
->blocksize
) ==
463 Ext2DataBlocks(Ext2Sys
, inode
.i_blocks
/(Ext2Sys
->blocksize
/SECTOR_SIZE
)));
465 ASSERT( (inode
.i_blocks
/(Ext2Sys
->blocksize
/SECTOR_SIZE
)) ==
466 Ext2TotalBlocks(Ext2Sys
, inode
.i_size
/Ext2Sys
->blocksize
));
470 ext2_save_inode(Ext2Sys
, ino
, &inode
);
476 RtlFreeHeap(RtlGetProcessHeap(), 0, buf
);
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
488 * It takes as input a superblock which has already been byte swapped
492 bool write_primary_superblock(PEXT2_FILESYS Ext2Sys
, PEXT2_SUPER_BLOCK super
)
496 bRet
= NT_SUCCESS(Ext2WriteDisk(
498 ((LONGLONG
)SUPERBLOCK_OFFSET
),
499 SUPERBLOCK_SIZE
, (PUCHAR
)super
));
508 * Updates the revision to EXT2_DYNAMIC_REV
510 void ext2_update_dynamic_rev(PEXT2_FILESYS fs
)
512 PEXT2_SUPER_BLOCK sb
= fs
->ext2_sb
;
514 if (sb
->s_rev_level
> EXT2_GOOD_OLD_REV
)
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 */
525 bool ext2_flush(PEXT2_FILESYS fs
)
527 ULONG i
,j
,maxgroup
,sgrp
;
531 unsigned long fs_state
;
532 PEXT2_SUPER_BLOCK super_shadow
= 0;
533 PEXT2_GROUP_DESC group_shadow
= 0;
535 LARGE_INTEGER SysTime
;
537 NtQuerySystemTime(&SysTime
);
539 fs_state
= fs
->ext2_sb
->s_state
;
541 RtlTimeToSecondsSince1970(&SysTime
, &fs
->ext2_sb
->s_wtime
);
542 fs
->ext2_sb
->s_block_group_nr
= 0;
544 super_shadow
= fs
->ext2_sb
;
545 group_shadow
= fs
->group_desc
;
548 * Write out master superblock. This has to be done
549 * separately, since it is located at a fixed location
550 * (SUPERBLOCK_OFFSET).
552 retval
= write_primary_superblock(fs
, super_shadow
);
557 * If this is an external journal device, don't write out the
558 * block group descriptors or any of the backup superblocks
560 if (fs
->ext2_sb
->s_feature_incompat
&
561 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)
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
572 fs
->ext2_sb
->s_state
&= ~EXT2_VALID_FS
;
575 * Write out the master group descriptors, and the backup
576 * superblocks and group descriptors.
578 group_block
= fs
->ext2_sb
->s_first_data_block
;
579 maxgroup
= fs
->group_desc_count
;
581 for (i
= 0; i
< maxgroup
; i
++)
583 if (!ext2_bg_has_super(fs
->ext2_sb
, i
))
587 if (sgrp
> ((1 << 16) - 1))
588 sgrp
= (1 << 16) - 1;
590 fs
->ext2_sb
->s_block_group_nr
= (USHORT
) sgrp
;
594 retval
= NT_SUCCESS(Ext2WriteDisk(
596 ((ULONGLONG
)group_block
* fs
->blocksize
),
597 SUPERBLOCK_SIZE
, (PUCHAR
)super_shadow
));
605 group_ptr
= (char *) group_shadow
;
607 for (j
=0; j
< fs
->desc_blocks
; j
++)
610 retval
= NT_SUCCESS(Ext2WriteDisk(
612 ((ULONGLONG
)(group_block
+1+j
) * fs
->blocksize
),
613 fs
->blocksize
, (PUCHAR
) group_ptr
));
620 group_ptr
+= fs
->blocksize
;
624 group_block
+= EXT2_BLOCKS_PER_GROUP(fs
->ext2_sb
);
628 fs
->ext2_sb
->s_block_group_nr
= 0;
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.
636 retval
= ext2_write_bitmaps(fs
);
641 * Flush the blocks out to disk
644 // retval = io_channel_flush(fs->io);
648 fs
->ext2_sb
->s_state
= (USHORT
) fs_state
;
654 bool create_journal_dev(PEXT2_FILESYS fs
)
663 DPRINT1("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n");
667 DPRINT("Mke2fs: Zeroing journal device: \n");
669 retval
= zero_blocks(fs
, 0, fs
->ext2_sb
->s_blocks_count
,
672 zero_blocks(0, 0, 0, 0, 0);
676 DPRINT1("Mke2fs: create_journal_dev: while zeroing journal device (block %lu, count %lu).\n",
681 retval
= NT_SUCCESS(Ext2WriteDisk(
683 ((ULONGLONG
)blk
* (fs
->ext2_sb
->s_first_data_block
+1)),
684 fs
->blocksize
, (unsigned char *)buf
));
688 DPRINT1("Mke2fs: create_journal_dev: while writing journal superblock.\n");
695 #define BLOCK_BITS (Ext2Sys->ext2_sb->s_log_block_size + 10)
698 Ext2DataBlocks(PEXT2_FILESYS Ext2Sys
, ULONG TotalBlocks
)
700 ULONG dwData
[4] = {1, 1, 1, 1};
701 ULONG dwMeta
[4] = {0, 0, 0, 0};
702 ULONG DataBlocks
= 0;
705 if (TotalBlocks
<= EXT2_NDIR_BLOCKS
)
710 TotalBlocks
-= EXT2_NDIR_BLOCKS
;
712 for (i
= 0; i
< 4; i
++)
714 dwData
[i
] = dwData
[i
] << ((BLOCK_BITS
- 2) * i
);
718 dwMeta
[i
] = 1 + (dwMeta
[i
- 1] << (BLOCK_BITS
- 2));
722 for( i
=1; (i
< 4) && (TotalBlocks
> 0); i
++)
724 if (TotalBlocks
>= (dwData
[i
] + dwMeta
[i
]))
726 TotalBlocks
-= (dwData
[i
] + dwMeta
[i
]);
727 DataBlocks
+= dwData
[i
];
734 for (j
=i
; (j
> 0) && (TotalBlocks
> 0); j
--)
736 dwDivide
= (TotalBlocks
- 1) / (dwData
[j
-1] + dwMeta
[j
-1]);
737 dwRemain
= (TotalBlocks
- 1) % (dwData
[j
-1] + dwMeta
[j
-1]);
739 DataBlocks
+= (dwDivide
* dwData
[j
-1]);
740 TotalBlocks
= dwRemain
;
745 return (DataBlocks
+ EXT2_NDIR_BLOCKS
);
750 Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys
, ULONG DataBlocks
)
752 ULONG dwData
[4] = {1, 1, 1, 1};
753 ULONG dwMeta
[4] = {0, 0, 0, 0};
754 ULONG TotalBlocks
= 0;
757 if (DataBlocks
<= EXT2_NDIR_BLOCKS
)
762 DataBlocks
-= EXT2_NDIR_BLOCKS
;
764 for (i
= 0; i
< 4; i
++)
766 dwData
[i
] = dwData
[i
] << ((BLOCK_BITS
- 2) * i
);
770 dwMeta
[i
] = 1 + (dwMeta
[i
- 1] << (BLOCK_BITS
- 2));
774 for( i
=1; (i
< 4) && (DataBlocks
> 0); i
++)
776 if (DataBlocks
>= dwData
[i
])
778 DataBlocks
-= dwData
[i
];
779 TotalBlocks
+= (dwData
[i
] + dwMeta
[i
]);
786 for (j
=i
; (j
> 0) && (DataBlocks
> 0); j
--)
788 dwDivide
= (DataBlocks
) / (dwData
[j
-1]);
789 dwRemain
= (DataBlocks
) % (dwData
[j
-1]);
791 TotalBlocks
+= (dwDivide
* (dwData
[j
-1] + dwMeta
[j
-1]) + 1);
792 DataBlocks
= dwRemain
;
797 return (TotalBlocks
+ EXT2_NDIR_BLOCKS
);
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
)
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
;
823 if (Callback
!= NULL
)
825 Callback(PROGRESS
, 0, (PVOID
)&Percent
);
829 RtlZeroMemory(&Ext2Sb
, sizeof(EXT2_SUPER_BLOCK
));
830 RtlZeroMemory(&FileSys
, sizeof(EXT2_FILESYS
));
831 FileSys
.ext2_sb
= &Ext2Sb
;
834 if (!NT_SUCCESS(Ext2OpenDevice(&FileSys
, DriveRoot
)))
836 DPRINT1("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot
);
841 if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys
)))
843 DPRINT1("Mke2fs: Can't get media information\n");
847 set_fs_defaults(NULL
, &Ext2Sb
, ClusterSize
, &inode_ratio
);
849 Ext2Sb
.s_blocks_count
= FileSys
.PartInfo
.PartitionLength
.QuadPart
/
850 EXT2_BLOCK_SIZE(&Ext2Sb
);
854 * Calculate number of inodes based on the inode ratio
856 Ext2Sb
.s_inodes_count
=
857 (ULONG
)(((LONGLONG
) Ext2Sb
.s_blocks_count
* EXT2_BLOCK_SIZE(&Ext2Sb
)) / inode_ratio
);
860 * Calculate number of blocks to reserve
862 Ext2Sb
.s_r_blocks_count
= (Ext2Sb
.s_blocks_count
* 5) / 100;
865 Status
= Ext2LockVolume(&FileSys
);
866 if (NT_SUCCESS(Status
))
873 if (!ext2_initialize_sb(&FileSys
))
875 DPRINT1("Mke2fs: error...\n");
880 zap_sector(&FileSys
, 2, 6);
883 * Generate a UUID for it...
887 uuid_generate(&uuid
[0]);
888 memcpy(&Ext2Sb
.s_uuid
[0], &uuid
[0], 16);
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.
899 for (i
= 0, val
= 0 ; i
< sizeof(Ext2Sb
.s_uuid
); i
++)
900 val
+= Ext2Sb
.s_uuid
[i
];
902 Ext2Sb
.s_max_mnt_count
+= val
% EXT2_DFL_MAX_MNT_COUNT
;
906 * Set the volume label...
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
);
917 ext2_print_super(&Ext2Sb
);
919 bRet
= ext2_allocate_tables(&FileSys
);
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
;
931 DPRINT1("Mke2fs: zeroing volume boot record\n");
932 zap_sector(&FileSys
, 0, 2);
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.
941 start
= (blocks
& ~(rsv
- 1));
946 bRet
= zero_blocks(&FileSys
, start
, blocks
- start
, &ret_blk
, NULL
);
950 DPRINT1("Mke2fs: zeroing block %lu at end of filesystem", ret_blk
);
954 write_inode_tables(&FileSys
);
956 create_root_dir(&FileSys
);
957 create_lost_and_found(&FileSys
);
959 ext2_reserve_inodes(&FileSys
);
961 create_bad_block_inode(&FileSys
, NULL
);
963 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information ... \n");
967 DPRINT1("Mke2fs: Slow format not supported yet\n");
970 if (!ext2_flush(&FileSys
))
973 DPRINT1("Mke2fs: Warning, had trouble writing out superblocks.\n");
977 DPRINT("Mke2fs: Writing superblocks and filesystem accounting information done!\n");
980 Status
= STATUS_SUCCESS
;
985 ext2_free_group_desc(&FileSys
);
987 ext2_free_block_bitmap(&FileSys
);
988 ext2_free_inode_bitmap(&FileSys
);
992 Ext2DisMountVolume(&FileSys
);
993 Ext2UnLockVolume(&FileSys
);
996 Ext2CloseDevice(&FileSys
);
998 if (Callback
!= NULL
)
1000 Callback(DONE
, 0, (PVOID
)&bRet
);
1008 Ext2Chkdsk(IN PUNICODE_STRING DriveRoot
,
1009 IN BOOLEAN FixErrors
,
1011 IN BOOLEAN CheckOnlyIfDirty
,
1012 IN BOOLEAN ScanDrive
,
1013 IN PFMIFSCALLBACK Callback
)
1016 return STATUS_SUCCESS
;