reactos/sdk/lib/fslib/ext2lib/Mke2fs.c

1018 lines
23 KiB
C
Raw Normal View History

/*
* PROJECT: Mke2fs
* FILE: Disk.c
* PROGRAMMER: Matt Wu <mattwu@163.com>
* HOMEPAGE: http://ext2.yeah.net
*/
/* INCLUDES **************************************************************/
#include "Mke2fs.h"
#include <fmifs/fmifs.h>
#include <debug.h>
/* GLOBALS ***************************************************************/
int inode_ratio = 4096;
BOOLEAN bLocked = FALSE;
/* This is needed for the ext2fs driver to mount the volume */
#define ZAP_BOOTBLOCK
/* FUNCTIONS *************************************************************/
int int_log2(int arg)
{
int l = 0;
arg >>= 1;
while (arg)
{
l++;
arg >>= 1;
}
return l;
}
int int_log10(unsigned int arg)
{
int l;
for (l=0; arg ; l++)
arg = arg / 10;
return l;
}
static char default_str[] = "default";
struct mke2fs_defaults {
const char *type;
int size;
int blocksize;
int inode_ratio;
} settings[] = {
{ default_str, 0, 4096, 8192 },
{ default_str, 512, 1024, 4096 },
{ default_str, 3, 1024, 8192 },
{ "journal", 0, 4096, 8192 },
{ "news", 0, 4096, 4096 },
{ "largefile", 0, 4096, 1024 * 1024 },
{ "largefile4", 0, 4096, 4096 * 1024 },
{ 0, 0, 0, 0},
};
void set_fs_defaults(const char *fs_type,
PEXT2_SUPER_BLOCK super,
int blocksize, int *inode_ratio)
{
int megs;
int ratio = 0;
struct mke2fs_defaults *p;
megs = (super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024);
if (inode_ratio)
ratio = *inode_ratio;
if (!fs_type)
fs_type = default_str;
for (p = settings; p->type; p++)
{
if ((strcmp(p->type, fs_type) != 0) &&
(strcmp(p->type, default_str) != 0))
continue;
if ((p->size != 0) &&
(megs > p->size))
continue;
if (ratio == 0)
*inode_ratio = p->inode_ratio;
if (blocksize == 0)
{
super->s_log_frag_size = super->s_log_block_size =
int_log2(p->blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
}
}
if (blocksize == 0)
{
super->s_blocks_count /= EXT2_BLOCK_SIZE(super) / 1024;
}
}
/*
* Helper function which zeros out _num_ blocks starting at _blk_. In
* case of an error, the details of the error is returned via _ret_blk_
* and _ret_count_ if they are non-NULL pointers. Returns 0 on
* success, and an error code on an error.
*
* As a special case, if the first argument is NULL, then it will
* attempt to free the static zeroizing buffer. (This is to keep
* programs that check for memory leaks happy.)
*/
bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num,
ULONG *ret_blk, ULONG *ret_count)
{
ULONG j, count;
static unsigned char *buf;
bool retval;
/* If fs is null, clean up the static buffer and return */
if (!fs)
{
if (buf)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, buf);
buf = 0;
}
return true;
}
#define STRIDE_LENGTH 8
/* Allocate the zeroizing buffer if necessary */
if (!buf)
{
buf = (unsigned char *)
RtlAllocateHeap(RtlGetProcessHeap(), 0, fs->blocksize * STRIDE_LENGTH);
if (!buf)
{
DPRINT1("Mke2fs: while allocating zeroizing buffer");
if (ret_blk)
*ret_blk = blk;
return false;
}
memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
}
/* OK, do the write loop */
for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH)
{
if (num-j > STRIDE_LENGTH)
count = STRIDE_LENGTH;
else
count = num - j;
retval = NT_SUCCESS(Ext2WriteDisk(
fs,
((ULONGLONG)blk * fs->blocksize),
count * fs->blocksize,
buf));
if (!retval)
{
if (ret_count)
*ret_count = count;
if (ret_blk)
*ret_blk = blk;
return retval;
}
}
return true;
}
bool zap_sector(PEXT2_FILESYS Ext2Sys, int sect, int nsect)
{
unsigned char *buf;
ULONG *magic;
buf = (unsigned char *)
RtlAllocateHeap(RtlGetProcessHeap(), 0, SECTOR_SIZE*nsect);
if (!buf)
{
DPRINT1("Mke2fs: Out of memory erasing sectors %d-%d\n",
sect, sect + nsect - 1);
return false;
}
#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
#define BSD_MAGICDISK (0x57455682UL) /* The disk magic number reversed */
#define BSD_LABEL_OFFSET 64
if (sect == 0)
{
Ext2ReadDisk(
Ext2Sys,
(LONGLONG)(sect * SECTOR_SIZE),
SECTOR_SIZE, buf);
// Check for a BSD disklabel, and don't erase it if so
magic = (ULONG *) (buf + BSD_LABEL_OFFSET);
if ((*magic == BSD_DISKMAGIC) || (*magic == BSD_MAGICDISK))
goto clean_up;
}
memset(buf, 0, (ULONG)nsect * SECTOR_SIZE);
// Write buf to disk
Ext2WriteDisk( Ext2Sys,
(LONGLONG)(sect * SECTOR_SIZE),
(ULONG)nsect * SECTOR_SIZE,
buf );
clean_up:
RtlFreeHeap(RtlGetProcessHeap(), 0, buf);
return true;
}
bool ext2_mkdir( PEXT2_FILESYS fs,
ULONG parent,
ULONG inum,
char *name,
ULONG *no,
PEXT2_INODE pid )
{
bool retval;
EXT2_INODE parent_inode, inode;
ULONG ino = inum;
//ULONG scratch_ino;
ULONG blk;
char *block = 0;
int filetype = 0;
LARGE_INTEGER SysTime;
NtQuerySystemTime(&SysTime);
/*
* Allocate an inode, if necessary
*/
if (!ino)
{
retval = ext2_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino);
if (!retval)
goto cleanup;
}
if (no)
*no = ino;
/*
* Allocate a data block for the directory
*/
retval = ext2_new_block(fs, 0, 0, &blk);
if (!retval)
goto cleanup;
/*
* Create a scratch template for the directory
*/
retval = ext2_new_dir_block(fs, ino, parent, &block);
if (!retval)
goto cleanup;
/*
* Get the parent's inode, if necessary
*/
if (parent != ino)
{
retval = ext2_load_inode(fs, parent, &parent_inode);
if (!retval)
goto cleanup;
}
else
{
memset(&parent_inode, 0, sizeof(parent_inode));
}
/*
* Create the inode structure....
*/
memset(&inode, 0, sizeof(EXT2_INODE));
inode.i_mode = (USHORT)(LINUX_S_IFDIR | (0777 & ~fs->umask));
inode.i_uid = inode.i_gid = 0;
inode.i_blocks = fs->blocksize / 512;
inode.i_block[0] = blk;
inode.i_links_count = 2;
RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime);
inode.i_ctime = inode.i_atime = inode.i_mtime;
inode.i_size = fs->blocksize;
/*
* Write out the inode and inode data block
*/
retval = ext2_write_block(fs, blk, block);
if (!retval)
goto cleanup;
retval = ext2_save_inode(fs, ino, &inode);
if (!retval)
goto cleanup;
if (pid)
{
*pid = inode;
}
if (parent != ino)
{
/*
* Add entry for this inode to parent dir 's block
*/
if (fs->ext2_sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
filetype = EXT2_FT_DIR;
retval = ext2_add_entry(fs, parent, ino, filetype, name);
if (!retval)
goto cleanup;
/*
* Update parent inode's counts
*/
parent_inode.i_links_count++;
retval = ext2_save_inode(fs, parent, &parent_inode);
if (!retval)
goto cleanup;
}
/*
* Update accounting....
*/
ext2_block_alloc_stats(fs, blk, +1);
ext2_inode_alloc_stats2(fs, ino, +1, 1);
cleanup:
if (block)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, block);
block = NULL;
}
return retval;
}
bool create_root_dir(PEXT2_FILESYS fs)
{
bool retval;
EXT2_INODE inode;
retval = ext2_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0, NULL, &inode);
if (!retval)
{
DPRINT1("Mke2fs: while creating root dir");
return false;
}
{
inode.i_uid = 0;
inode.i_gid = 0;
retval = ext2_save_inode(fs, EXT2_ROOT_INO, &inode);
if (!retval)
{
DPRINT1("Mke2fs: while setting root inode ownership");
return false;
}
}
return true;
}
bool create_lost_and_found(PEXT2_FILESYS Ext2Sys)
{
bool retval;
ULONG ino;
char *name = "lost+found";
int lpf_size = 0;
EXT2_INODE inode;
ULONG dwBlk = 0;
BOOLEAN bExt= TRUE;
PEXT2_DIR_ENTRY dir;
char * buf;
buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize);
if (!buf)
{
bExt = FALSE;
}
else
{
memset(buf, 0, Ext2Sys->blocksize);
dir = (PEXT2_DIR_ENTRY) buf;
dir->rec_len = Ext2Sys->blocksize;
}
Ext2Sys->umask = 077;
retval = ext2_mkdir(Ext2Sys, EXT2_ROOT_INO, 0, name, &ino, &inode);
if (!retval)
{
DPRINT1("Mke2fs: while creating /lost+found.\n");
return false;
}
if (!bExt)
goto errorout;
lpf_size = inode.i_size;
while(TRUE)
{
if (lpf_size >= 16*1024)
break;
retval = ext2_alloc_block(Ext2Sys, 0, &dwBlk);
if (! retval)
{
DPRINT1("Mke2fs: create_lost_and_found: error alloc block.\n");
break;
}
retval = ext2_expand_inode(Ext2Sys, &inode, dwBlk);
if (!retval)
{
DPRINT1("Mke2fs: errors when expanding /lost+found.\n");
break;
}
ext2_write_block(Ext2Sys, dwBlk, buf);
inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE);
lpf_size += Ext2Sys->blocksize;
}
{
inode.i_size = lpf_size;
ASSERT( (inode.i_size/Ext2Sys->blocksize) ==
Ext2DataBlocks(Ext2Sys, inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)));
ASSERT( (inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)) ==
Ext2TotalBlocks(Ext2Sys, inode.i_size/Ext2Sys->blocksize));
}
ext2_save_inode(Ext2Sys, ino, &inode);
errorout:
if (buf)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, buf);
}
return true;
}
/*
* This function forces out the primary superblock. We need to only
* write out those fields which we have changed, since if the
* filesystem is mounted, it may have changed some of the other
* fields.
*
* It takes as input a superblock which has already been byte swapped
* (if necessary).
*/
bool write_primary_superblock(PEXT2_FILESYS Ext2Sys, PEXT2_SUPER_BLOCK super)
{
bool bRet;
bRet = NT_SUCCESS(Ext2WriteDisk(
Ext2Sys,
((LONGLONG)SUPERBLOCK_OFFSET),
SUPERBLOCK_SIZE, (PUCHAR)super));
return bRet;
}
/*
* Updates the revision to EXT2_DYNAMIC_REV
*/
void ext2_update_dynamic_rev(PEXT2_FILESYS fs)
{
PEXT2_SUPER_BLOCK sb = fs->ext2_sb;
if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
return;
sb->s_rev_level = EXT2_DYNAMIC_REV;
sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
/* s_uuid is handled by e2fsck already */
/* other fields should be left alone */
}
bool ext2_flush(PEXT2_FILESYS fs)
{
ULONG i,j,maxgroup,sgrp;
ULONG group_block;
bool retval;
char *group_ptr;
unsigned long fs_state;
PEXT2_SUPER_BLOCK super_shadow = 0;
PEXT2_GROUP_DESC group_shadow = 0;
LARGE_INTEGER SysTime;
NtQuerySystemTime(&SysTime);
fs_state = fs->ext2_sb->s_state;
RtlTimeToSecondsSince1970(&SysTime, &fs->ext2_sb->s_wtime);
fs->ext2_sb->s_block_group_nr = 0;
super_shadow = fs->ext2_sb;
group_shadow = fs->group_desc;
/*
* Write out master superblock. This has to be done
* separately, since it is located at a fixed location
* (SUPERBLOCK_OFFSET).
*/
retval = write_primary_superblock(fs, super_shadow);
if (!retval)
goto errout;
/*
* If this is an external journal device, don't write out the
* block group descriptors or any of the backup superblocks
*/
if (fs->ext2_sb->s_feature_incompat &
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
{
retval = false;
goto errout;
}
/*
* Set the state of the FS to be non-valid. (The state has
* already been backed up earlier, and will be restored when
* we exit.)
*/
fs->ext2_sb->s_state &= ~EXT2_VALID_FS;
/*
* Write out the master group descriptors, and the backup
* superblocks and group descriptors.
*/
group_block = fs->ext2_sb->s_first_data_block;
maxgroup = fs->group_desc_count;
for (i = 0; i < maxgroup; i++)
{
if (!ext2_bg_has_super(fs->ext2_sb, i))
goto next_group;
sgrp = i;
if (sgrp > ((1 << 16) - 1))
sgrp = (1 << 16) - 1;
fs->ext2_sb->s_block_group_nr = (USHORT) sgrp;
if (i !=0 )
{
retval = NT_SUCCESS(Ext2WriteDisk(
fs,
((ULONGLONG)group_block * fs->blocksize),
SUPERBLOCK_SIZE, (PUCHAR)super_shadow));
if (!retval)
{
goto errout;
}
}
group_ptr = (char *) group_shadow;
for (j=0; j < fs->desc_blocks; j++)
{
retval = NT_SUCCESS(Ext2WriteDisk(
fs,
((ULONGLONG)(group_block+1+j) * fs->blocksize),
fs->blocksize, (PUCHAR) group_ptr));
if (!retval)
{
goto errout;
}
group_ptr += fs->blocksize;
}
next_group:
group_block += EXT2_BLOCKS_PER_GROUP(fs->ext2_sb);
}
fs->ext2_sb->s_block_group_nr = 0;
/*
* If the write_bitmaps() function is present, call it to
* flush the bitmaps. This is done this way so that a simple
* program that doesn't mess with the bitmaps doesn't need to
* drag in the bitmaps.c code.
*/
retval = ext2_write_bitmaps(fs);
if (!retval)
goto errout;
/*
* Flush the blocks out to disk
*/
// retval = io_channel_flush(fs->io);
errout:
fs->ext2_sb->s_state = (USHORT) fs_state;
return retval;
}
bool create_journal_dev(PEXT2_FILESYS fs)
{
bool retval = false;
char *buf = NULL;
ULONG blk;
ULONG count;
if (!retval)
{
DPRINT1("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n");
return false;
}
DPRINT("Mke2fs: Zeroing journal device: \n");
retval = zero_blocks(fs, 0, fs->ext2_sb->s_blocks_count,
&blk, &count);
zero_blocks(0, 0, 0, 0, 0);
if (!retval)
{
DPRINT1("Mke2fs: create_journal_dev: while zeroing journal device (block %lu, count %lu).\n",
blk, count);
return false;
}
retval = NT_SUCCESS(Ext2WriteDisk(
fs,
((ULONGLONG)blk * (fs->ext2_sb->s_first_data_block+1)),
fs->blocksize, (unsigned char *)buf));
if (!retval)
{
DPRINT1("Mke2fs: create_journal_dev: while writing journal superblock.\n");
return false;
}
return true;
}
#define BLOCK_BITS (Ext2Sys->ext2_sb->s_log_block_size + 10)
ULONG
Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks)
{
ULONG dwData[4] = {1, 1, 1, 1};
ULONG dwMeta[4] = {0, 0, 0, 0};
ULONG DataBlocks = 0;
ULONG i, j;
if (TotalBlocks <= EXT2_NDIR_BLOCKS)
{
return TotalBlocks;
}
TotalBlocks -= EXT2_NDIR_BLOCKS;
for (i = 0; i < 4; i++)
{
dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
if (i > 0)
{
dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2));
}
}
for( i=1; (i < 4) && (TotalBlocks > 0); i++)
{
if (TotalBlocks >= (dwData[i] + dwMeta[i]))
{
TotalBlocks -= (dwData[i] + dwMeta[i]);
DataBlocks += dwData[i];
}
else
{
ULONG dwDivide = 0;
ULONG dwRemain = 0;
for (j=i; (j > 0) && (TotalBlocks > 0); j--)
{
dwDivide = (TotalBlocks - 1) / (dwData[j-1] + dwMeta[j-1]);
dwRemain = (TotalBlocks - 1) % (dwData[j-1] + dwMeta[j-1]);
DataBlocks += (dwDivide * dwData[j-1]);
TotalBlocks = dwRemain;
}
}
}
return (DataBlocks + EXT2_NDIR_BLOCKS);
}
ULONG
Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks)
{
ULONG dwData[4] = {1, 1, 1, 1};
ULONG dwMeta[4] = {0, 0, 0, 0};
ULONG TotalBlocks = 0;
ULONG i, j;
if (DataBlocks <= EXT2_NDIR_BLOCKS)
{
return DataBlocks;
}
DataBlocks -= EXT2_NDIR_BLOCKS;
for (i = 0; i < 4; i++)
{
dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
if (i > 0)
{
dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2));
}
}
for( i=1; (i < 4) && (DataBlocks > 0); i++)
{
if (DataBlocks >= dwData[i])
{
DataBlocks -= dwData[i];
TotalBlocks += (dwData[i] + dwMeta[i]);
}
else
{
ULONG dwDivide = 0;
ULONG dwRemain = 0;
for (j=i; (j > 0) && (DataBlocks > 0); j--)
{
dwDivide = (DataBlocks) / (dwData[j-1]);
dwRemain = (DataBlocks) % (dwData[j-1]);
TotalBlocks += (dwDivide * (dwData[j-1] + dwMeta[j-1]) + 1);
DataBlocks = dwRemain;
}
}
}
return (TotalBlocks + EXT2_NDIR_BLOCKS);
}
NTSTATUS
NTAPI
Ext2Format(IN PUNICODE_STRING DriveRoot,
IN FMIFS_MEDIA_FLAG MediaFlag,
IN PUNICODE_STRING Label,
IN BOOLEAN QuickFormat,
IN ULONG ClusterSize,
IN PFMIFSCALLBACK Callback)
{
BOOLEAN bRet = FALSE;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
/* Super Block: 1024 bytes long */
EXT2_SUPER_BLOCK Ext2Sb;
/* File Sys Structure */
EXT2_FILESYS FileSys;
ULONG Percent;
ULONG rsv;
ULONG blocks;
ULONG start;
ULONG ret_blk;
if (Callback != NULL)
{
Callback(PROGRESS, 0, (PVOID)&Percent);
}
RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK));
RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS));
FileSys.ext2_sb = &Ext2Sb;
if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot)))
{
DPRINT1("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot);
goto clean_up;
}
if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys)))
{
DPRINT1("Mke2fs: Can't get media information\n");
goto clean_up;
}
set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio);
Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart /
EXT2_BLOCK_SIZE(&Ext2Sb);
/*
* Calculate number of inodes based on the inode ratio
*/
Ext2Sb.s_inodes_count =
(ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio);
/*
* Calculate number of blocks to reserve
*/
Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100;
Status = Ext2LockVolume(&FileSys);
if (NT_SUCCESS(Status))
{
bLocked = TRUE;
}
// Initialize
if (!ext2_initialize_sb(&FileSys))
{
DPRINT1("Mke2fs: error...\n");
goto clean_up;
}
zap_sector(&FileSys, 2, 6);
/*
* Generate a UUID for it...
*/
{
__u8 uuid[16];
uuid_generate(&uuid[0]);
memcpy(&Ext2Sb.s_uuid[0], &uuid[0], 16);
}
/*
* Add "jitter" to the superblock's check interval so that we
* don't check all the filesystems at the same time. We use a
* kludgy hack of using the UUID to derive a random jitter value.
*/
{
ULONG i, val;
for (i = 0, val = 0 ; i < sizeof(Ext2Sb.s_uuid); i++)
val += Ext2Sb.s_uuid[i];
Ext2Sb.s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
}
/*
* Set the volume label...
*/
if (Label)
{
ANSI_STRING ansi_label;
ansi_label.MaximumLength = sizeof(Ext2Sb.s_volume_name);
ansi_label.Length = 0;
ansi_label.Buffer = Ext2Sb.s_volume_name;
RtlUnicodeStringToAnsiString(&ansi_label, Label, FALSE);
}
ext2_print_super(&Ext2Sb);
bRet = ext2_allocate_tables(&FileSys);
if (!bRet)
{
goto clean_up;
}
/* rsv must be a power of two (64kB is MD RAID sb alignment) */
rsv = 65536 / FileSys.blocksize;
blocks = Ext2Sb.s_blocks_count;
#ifdef ZAP_BOOTBLOCK
DPRINT1("Mke2fs: zeroing volume boot record\n");
zap_sector(&FileSys, 0, 2);
#endif
/*
* Wipe out any old MD RAID (or other) metadata at the end
* of the device. This will also verify that the device is
* as large as we think. Be careful with very small devices.
*/
start = (blocks & ~(rsv - 1));
if (start > rsv)
start -= rsv;
if (start > 0)
bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL);
if (!bRet)
{
DPRINT1("Mke2fs: zeroing block %lu at end of filesystem", ret_blk);
goto clean_up;
}
write_inode_tables(&FileSys);
create_root_dir(&FileSys);
create_lost_and_found(&FileSys);
ext2_reserve_inodes(&FileSys);
create_bad_block_inode(&FileSys, NULL);
DPRINT("Mke2fs: Writing superblocks and filesystem accounting information ... \n");
if (!QuickFormat)
{
DPRINT1("Mke2fs: Slow format not supported yet\n");
}
if (!ext2_flush(&FileSys))
{
bRet = false;
DPRINT1("Mke2fs: Warning, had trouble writing out superblocks.\n");
goto clean_up;
}
DPRINT("Mke2fs: Writing superblocks and filesystem accounting information done!\n");
bRet = true;
Status = STATUS_SUCCESS;
clean_up:
// Clean up ...
ext2_free_group_desc(&FileSys);
ext2_free_block_bitmap(&FileSys);
ext2_free_inode_bitmap(&FileSys);
if(bLocked)
{
Ext2DisMountVolume(&FileSys);
Ext2UnLockVolume(&FileSys);
}
Ext2CloseDevice(&FileSys);
if (Callback != NULL)
{
Callback(DONE, 0, (PVOID)&bRet);
}
return Status;
}
NTSTATUS
NTAPI
Ext2Chkdsk(IN PUNICODE_STRING DriveRoot,
IN BOOLEAN FixErrors,
IN BOOLEAN Verbose,
IN BOOLEAN CheckOnlyIfDirty,
IN BOOLEAN ScanDrive,
IN PFMIFSCALLBACK Callback)
{
UNIMPLEMENTED;
return STATUS_SUCCESS;
}