4 * PROGRAMMER: Matt Wu <mattwu@163.com>
5 * HOMEPAGE: http://ext2.yeah.net
8 /* INCLUDES **************************************************************/
13 /* GLOBALS ***************************************************************/
15 int inode_ratio
= 4096;
17 BOOLEAN bLocked
= FALSE
;
19 /* FUNCTIONS *************************************************************/
36 int int_log10(unsigned int arg
)
47 static char default_str
[] = "default";
49 struct mke2fs_defaults
{
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 },
65 void set_fs_defaults(const char *fs_type
,
66 PEXT2_SUPER_BLOCK super
,
67 int blocksize
, int *inode_ratio
)
71 struct mke2fs_defaults
*p
;
73 megs
= (super
->s_blocks_count
* (EXT2_BLOCK_SIZE(super
) / 1024) / 1024);
79 fs_type
= default_str
;
81 for (p
= settings
; p
->type
; p
++)
83 if ((strcmp(p
->type
, fs_type
) != 0) &&
84 (strcmp(p
->type
, default_str
) != 0))
92 *inode_ratio
= p
->inode_ratio
;
96 super
->s_log_frag_size
= super
->s_log_block_size
=
97 int_log2(p
->blocksize
>> EXT2_MIN_BLOCK_LOG_SIZE
);
103 super
->s_blocks_count
/= EXT2_BLOCK_SIZE(super
) / 1024;
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.
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.)
117 bool zero_blocks(PEXT2_FILESYS fs
, ULONG blk
, ULONG num
,
118 ULONG
*ret_blk
, ULONG
*ret_count
)
120 ULONG j
, count
, next_update
, next_update_incr
;
121 static unsigned char *buf
;
124 /* If fs is null, clean up the static buffer and return */
129 RtlFreeHeap(GetProcessHeap(), 0, buf
);
135 #define STRIDE_LENGTH 8
137 /* Allocate the zeroizing buffer if necessary */
140 buf
= (unsigned char *)
141 RtlAllocateHeap(GetProcessHeap(), 0, fs
->blocksize
* STRIDE_LENGTH
);
144 KdPrint(("Mke2fs: while allocating zeroizing buffer"));
147 memset(buf
, 0, fs
->blocksize
* STRIDE_LENGTH
);
150 /* OK, do the write loop */
152 next_update_incr
= num
/ 100;
153 if (next_update_incr
< 1)
154 next_update_incr
= 1;
156 for (j
=0; j
< num
; j
+= STRIDE_LENGTH
, blk
+= STRIDE_LENGTH
)
158 if (num
-j
> STRIDE_LENGTH
)
159 count
= STRIDE_LENGTH
;
163 retval
= NT_SUCCESS(Ext2WriteDisk(
165 ((ULONGLONG
)blk
* fs
->blocksize
),
166 count
* fs
->blocksize
,
185 bool zap_sector(PEXT2_FILESYS Ext2Sys
, int sect
, int nsect
)
190 buf
= (unsigned char *)
191 RtlAllocateHeap(GetProcessHeap(), 0, SECTOR_SIZE
*nsect
);
194 KdPrint(("Mke2fs: Out of memory erasing sectors %d-%d\n",
195 sect
, sect
+ nsect
- 1));
199 memset(buf
, 0, (ULONG
)nsect
* SECTOR_SIZE
);
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
))
219 Ext2WriteDisk( Ext2Sys
,
220 (LONGLONG
)(sect
* SECTOR_SIZE
),
221 (ULONG
)nsect
* SECTOR_SIZE
,
226 RtlFreeHeap(GetProcessHeap(), 0, buf
);
231 bool ext2_mkdir( PEXT2_FILESYS fs
,
239 EXT2_INODE parent_inode
, inode
;
246 LARGE_INTEGER SysTime
;
248 NtQuerySystemTime(&SysTime
);
251 * Allocate an inode, if necessary
255 retval
= ext2_new_inode(fs
, parent
, LINUX_S_IFDIR
| 0755, 0, &ino
);
264 * Allocate a data block for the directory
266 retval
= ext2_new_block(fs
, 0, 0, &blk
);
271 * Create a scratch template for the directory
273 retval
= ext2_new_dir_block(fs
, ino
, parent
, &block
);
278 * Get the parent's inode, if necessary
282 retval
= ext2_load_inode(fs
, parent
, &parent_inode
);
288 memset(&parent_inode
, 0, sizeof(parent_inode
));
292 * Create the inode structure....
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
;
305 * Write out the inode and inode data block
307 retval
= ext2_write_block(fs
, blk
, block
);
311 retval
= ext2_save_inode(fs
, ino
, &inode
);
323 * Add entry for this inode to parent dir 's block
326 if (fs
->ext2_sb
->s_feature_incompat
& EXT2_FEATURE_INCOMPAT_FILETYPE
)
327 filetype
= EXT2_FT_DIR
;
329 retval
= ext2_add_entry(fs
, parent
, ino
, filetype
, name
);
335 * Update parent inode's counts
338 parent_inode
.i_links_count
++;
339 retval
= ext2_save_inode(fs
, parent
, &parent_inode
);
346 * Update accounting....
348 ext2_block_alloc_stats(fs
, blk
, +1);
349 ext2_inode_alloc_stats2(fs
, ino
, +1, 1);
355 RtlFreeHeap(GetProcessHeap(), 0, block
);
362 bool create_root_dir(PEXT2_FILESYS fs
)
367 retval
= ext2_mkdir(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, 0, NULL
, &inode
);
371 KdPrint(("Mke2fs: while creating root dir"));
379 retval
= ext2_save_inode(fs
, EXT2_ROOT_INO
, &inode
);
382 KdPrint(("Mke2fs: while setting root inode ownership"));
390 bool create_lost_and_found(PEXT2_FILESYS Ext2Sys
)
394 char *name
= "lost+found";
404 buf
= (char *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys
->blocksize
);
411 memset(buf
, 0, Ext2Sys
->blocksize
);
413 dir
= (PEXT2_DIR_ENTRY
) buf
;
414 dir
->rec_len
= Ext2Sys
->blocksize
;
417 Ext2Sys
->umask
= 077;
418 retval
= ext2_mkdir(Ext2Sys
, EXT2_ROOT_INO
, 0, name
, &ino
, &inode
);
422 KdPrint(("Mke2fs: while creating /lost+found.\n"));
429 lpf_size
= inode
.i_size
;
433 if (lpf_size
>= 16*1024)
436 retval
= ext2_alloc_block(Ext2Sys
, 0, &dwBlk
);
440 KdPrint(("Mke2fs: create_lost_and_found: error alloc block.\n"));
444 retval
= ext2_expand_inode(Ext2Sys
, &inode
, dwBlk
);
447 KdPrint(("Mke2fs: errors when expanding /lost+found.\n"));
451 ext2_write_block(Ext2Sys
, dwBlk
, buf
);
453 inode
.i_blocks
+= (Ext2Sys
->blocksize
/SECTOR_SIZE
);
454 lpf_size
+= Ext2Sys
->blocksize
;
458 inode
.i_size
= lpf_size
;
460 ASSERT( (inode
.i_size
/Ext2Sys
->blocksize
) ==
461 Ext2DataBlocks(Ext2Sys
, inode
.i_blocks
/(Ext2Sys
->blocksize
/SECTOR_SIZE
)));
463 ASSERT( (inode
.i_blocks
/(Ext2Sys
->blocksize
/SECTOR_SIZE
)) ==
464 Ext2TotalBlocks(Ext2Sys
, inode
.i_size
/Ext2Sys
->blocksize
));
468 ext2_save_inode(Ext2Sys
, ino
, &inode
);
474 RtlFreeHeap(GetProcessHeap(), 0, buf
);
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
486 * It takes as input a superblock which has already been byte swapped
490 bool write_primary_superblock(PEXT2_FILESYS Ext2Sys
, PEXT2_SUPER_BLOCK super
)
494 bRet
= NT_SUCCESS(Ext2WriteDisk(
496 ((LONGLONG
)SUPERBLOCK_OFFSET
),
497 SUPERBLOCK_SIZE
, (PUCHAR
)super
));
506 * Updates the revision to EXT2_DYNAMIC_REV
508 void ext2_update_dynamic_rev(PEXT2_FILESYS fs
)
510 PEXT2_SUPER_BLOCK sb
= fs
->ext2_sb
;
512 if (sb
->s_rev_level
> EXT2_GOOD_OLD_REV
)
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 */
523 bool ext2_flush(PEXT2_FILESYS fs
)
525 ULONG i
,j
,maxgroup
,sgrp
;
529 unsigned long fs_state
;
530 PEXT2_SUPER_BLOCK super_shadow
= 0;
531 PEXT2_GROUP_DESC group_shadow
= 0;
533 LARGE_INTEGER SysTime
;
535 NtQuerySystemTime(&SysTime
);
537 fs_state
= fs
->ext2_sb
->s_state
;
539 RtlTimeToSecondsSince1970(&SysTime
, &fs
->ext2_sb
->s_wtime
);
540 fs
->ext2_sb
->s_block_group_nr
= 0;
542 super_shadow
= fs
->ext2_sb
;
543 group_shadow
= fs
->group_desc
;
546 * Write out master superblock. This has to be done
547 * separately, since it is located at a fixed location
548 * (SUPERBLOCK_OFFSET).
550 retval
= write_primary_superblock(fs
, super_shadow
);
555 * If this is an external journal device, don't write out the
556 * block group descriptors or any of the backup superblocks
558 if (fs
->ext2_sb
->s_feature_incompat
&
559 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV
)
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
570 fs
->ext2_sb
->s_state
&= ~EXT2_VALID_FS
;
573 * Write out the master group descriptors, and the backup
574 * superblocks and group descriptors.
576 group_block
= fs
->ext2_sb
->s_first_data_block
;
577 maxgroup
= fs
->group_desc_count
;
579 for (i
= 0; i
< maxgroup
; i
++)
581 if (!ext2_bg_has_super(fs
->ext2_sb
, i
))
585 if (sgrp
> ((1 << 16) - 1))
586 sgrp
= (1 << 16) - 1;
588 fs
->ext2_sb
->s_block_group_nr
= (USHORT
) sgrp
;
592 retval
= NT_SUCCESS(Ext2WriteDisk(
594 ((ULONGLONG
)group_block
* fs
->blocksize
),
595 SUPERBLOCK_SIZE
, (PUCHAR
)super_shadow
));
603 group_ptr
= (char *) group_shadow
;
605 for (j
=0; j
< fs
->desc_blocks
; j
++)
608 retval
= NT_SUCCESS(Ext2WriteDisk(
610 ((ULONGLONG
)(group_block
+1+j
) * fs
->blocksize
),
611 fs
->blocksize
, (PUCHAR
) group_ptr
));
618 group_ptr
+= fs
->blocksize
;
622 group_block
+= EXT2_BLOCKS_PER_GROUP(fs
->ext2_sb
);
626 fs
->ext2_sb
->s_block_group_nr
= 0;
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.
634 retval
= ext2_write_bitmaps(fs
);
639 * Flush the blocks out to disk
642 // retval = io_channel_flush(fs->io);
646 fs
->ext2_sb
->s_state
= (USHORT
) fs_state
;
652 bool create_journal_dev(PEXT2_FILESYS fs
)
661 KdPrint(("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n"));
665 KdPrint(("Mke2fs: Zeroing journal device: \n"));
667 retval
= zero_blocks(fs
, 0, fs
->ext2_sb
->s_blocks_count
,
670 zero_blocks(0, 0, 0, 0, 0);
674 KdPrint(("Mke2fs: create_journal_dev: while zeroing journal device (block %lu, count %lu).\n",
679 retval
= NT_SUCCESS(Ext2WriteDisk(
681 ((ULONGLONG
)blk
* (fs
->ext2_sb
->s_first_data_block
+1)),
682 fs
->blocksize
, (unsigned char *)buf
));
686 KdPrint(("Mke2fs: create_journal_dev: while writing journal superblock.\n"));
693 #define BLOCK_BITS (Ext2Sys->ext2_sb->s_log_block_size + 10)
696 Ext2DataBlocks(PEXT2_FILESYS Ext2Sys
, ULONG TotalBlocks
)
698 ULONG dwData
[4] = {1, 1, 1, 1};
699 ULONG dwMeta
[4] = {0, 0, 0, 0};
700 ULONG DataBlocks
= 0;
703 if (TotalBlocks
<= EXT2_NDIR_BLOCKS
)
708 TotalBlocks
-= EXT2_NDIR_BLOCKS
;
710 for (i
= 0; i
< 4; i
++)
712 dwData
[i
] = dwData
[i
] << ((BLOCK_BITS
- 2) * i
);
716 dwMeta
[i
] = 1 + (dwMeta
[i
- 1] << (BLOCK_BITS
- 2));
720 for( i
=1; (i
< 4) && (TotalBlocks
> 0); i
++)
722 if (TotalBlocks
>= (dwData
[i
] + dwMeta
[i
]))
724 TotalBlocks
-= (dwData
[i
] + dwMeta
[i
]);
725 DataBlocks
+= dwData
[i
];
732 for (j
=i
; (j
> 0) && (TotalBlocks
> 0); j
--)
734 dwDivide
= (TotalBlocks
- 1) / (dwData
[j
-1] + dwMeta
[j
-1]);
735 dwRemain
= (TotalBlocks
- 1) % (dwData
[j
-1] + dwMeta
[j
-1]);
737 DataBlocks
+= (dwDivide
* dwData
[j
-1]);
738 TotalBlocks
= dwRemain
;
743 return (DataBlocks
+ EXT2_NDIR_BLOCKS
);
748 Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys
, ULONG DataBlocks
)
750 ULONG dwData
[4] = {1, 1, 1, 1};
751 ULONG dwMeta
[4] = {0, 0, 0, 0};
752 ULONG TotalBlocks
= 0;
755 if (DataBlocks
<= EXT2_NDIR_BLOCKS
)
760 DataBlocks
-= EXT2_NDIR_BLOCKS
;
762 for (i
= 0; i
< 4; i
++)
764 dwData
[i
] = dwData
[i
] << ((BLOCK_BITS
- 2) * i
);
768 dwMeta
[i
] = 1 + (dwMeta
[i
- 1] << (BLOCK_BITS
- 2));
772 for( i
=1; (i
< 4) && (DataBlocks
> 0); i
++)
774 if (DataBlocks
>= dwData
[i
])
776 DataBlocks
-= dwData
[i
];
777 TotalBlocks
+= (dwData
[i
] + dwMeta
[i
]);
784 for (j
=i
; (j
> 0) && (DataBlocks
> 0); j
--)
786 dwDivide
= (DataBlocks
) / (dwData
[j
-1]);
787 dwRemain
= (DataBlocks
) % (dwData
[j
-1]);
789 TotalBlocks
+= (dwDivide
* (dwData
[j
-1] + dwMeta
[j
-1]) + 1);
790 DataBlocks
= dwRemain
;
795 return (TotalBlocks
+ EXT2_NDIR_BLOCKS
);
800 Ext2Format(PUNICODE_STRING DriveRoot
,
802 PUNICODE_STRING Label
,
805 PFMIFSCALLBACK Callback
)
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
;
815 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
817 Callback(PROGRESS
, 0, (PVOID
)&Percent
);
819 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
821 RtlZeroMemory(&Ext2Sb
, sizeof(EXT2_SUPER_BLOCK
));
822 RtlZeroMemory(&FileSys
, sizeof(EXT2_FILESYS
));
823 FileSys
.ext2_sb
= &Ext2Sb
;
825 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
827 if (!NT_SUCCESS(Ext2OpenDevice(&FileSys
, DriveRoot
)))
829 KdPrint(("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot
));
833 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
835 if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys
)))
837 KdPrint(("Mke2fs: Can't get media information\n"));
841 set_fs_defaults(NULL
, &Ext2Sb
, ClusterSize
, &inode_ratio
);
843 Ext2Sb
.s_blocks_count
= FileSys
.PartInfo
.PartitionLength
.QuadPart
/
844 EXT2_BLOCK_SIZE(&Ext2Sb
);
846 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
849 * Calculate number of inodes based on the inode ratio
851 Ext2Sb
.s_inodes_count
=
852 (ULONG
)(((LONGLONG
) Ext2Sb
.s_blocks_count
* EXT2_BLOCK_SIZE(&Ext2Sb
)) / inode_ratio
);
855 * Calculate number of blocks to reserve
857 Ext2Sb
.s_r_blocks_count
= (Ext2Sb
.s_blocks_count
* 5) / 100;
859 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
861 Status
= Ext2LockVolume(&FileSys
);
862 if (NT_SUCCESS(Status
))
867 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
870 if (!ext2_initialize_sb(&FileSys
))
872 KdPrint(("Mke2fs: error...\n"));
876 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
878 zap_sector(&FileSys
, 2, 6);
881 * Generate a UUID for it...
885 uuid_generate(&uuid
[0]);
886 memcpy(&Ext2Sb
.s_uuid
[0], &uuid
[0], 16);
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.
897 for (i
= 0, val
= 0 ; i
< sizeof(Ext2Sb
.s_uuid
); i
++)
898 val
+= Ext2Sb
.s_uuid
[i
];
900 Ext2Sb
.s_max_mnt_count
+= val
% EXT2_DFL_MAX_MNT_COUNT
;
904 * Set the volume label...
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
);
915 ext2_print_super(&Ext2Sb
);
917 bRet
= ext2_allocate_tables(&FileSys
);
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
;
931 zap_sector(&FileSys
, 0, 2);
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.
940 start
= (blocks
& ~(rsv
- 1));
945 bRet
= zero_blocks(&FileSys
, start
, blocks
- start
, &ret_blk
, NULL
);
949 KdPrint(("Mke2fs: zeroing block %lu at end of filesystem", ret_blk
));
953 write_inode_tables(&FileSys
);
955 create_root_dir(&FileSys
);
956 create_lost_and_found(&FileSys
);
958 ext2_reserve_inodes(&FileSys
);
960 create_bad_block_inode(&FileSys
, NULL
);
962 KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information ... \n"));
966 KdPrint(("Mke2fs: Slow format not supported yet\n"));
969 if (!ext2_flush(&FileSys
))
972 KdPrint(("Mke2fs: Warning, had trouble writing out superblocks.\n"));
976 KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information done!\n"));
979 Status
= STATUS_SUCCESS
;
984 ext2_free_group_desc(&FileSys
);
986 ext2_free_block_bitmap(&FileSys
);
987 ext2_free_inode_bitmap(&FileSys
);
991 Ext2DisMountVolume(&FileSys
);
997 Ext2UnLockVolume(&FileSys
);
1001 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
1002 Ext2CloseDevice(&FileSys
);
1003 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
1005 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));
1006 Callback(DONE
, 0, (PVOID
)&bRet
);
1007 KdPrint(("%s:%d\n", __FILE__
, __LINE__
));