reactos/base/setup/lib/fsutil.c

914 lines
31 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Setup Library
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
* PURPOSE: Filesystem Format and ChkDsk support functions.
* COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
* Copyright 2017-2020 Hermes Belusca-Maito
*/
//
// See also: https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/dll/win32/fmifs/init.c;h=e895f5ef9cae4806123f6bbdd3dfed37ec1c8d33;hb=b9db9a4e377a2055f635b2fb69fef4e1750d219c
// for how to get FS providers in a dynamic way. In the (near) future we may
// consider merging some of this code with us into a fmifs / fsutil / fslib library...
//
/* INCLUDES *****************************************************************/
#include "precomp.h"
#include "partlist.h"
#include "fsrec.h"
#include "bootcode.h"
#include "fsutil.h"
#include <fslib/vfatlib.h>
#include <fslib/btrfslib.h>
// #include <fslib/ext2lib.h>
// #include <fslib/ntfslib.h>
#define NDEBUG
#include <debug.h>
/* TYPEDEFS *****************************************************************/
#include <pshpack1.h>
typedef struct _FAT_BOOTSECTOR
{
UCHAR JumpBoot[3]; // Jump instruction to boot code
CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes
USHORT BytesPerSector; // Bytes per sector
UCHAR SectorsPerCluster; // Number of sectors in a cluster
USHORT ReservedSectors; // Reserved sectors, usually 1 (the bootsector)
UCHAR NumberOfFats; // Number of FAT tables
USHORT RootDirEntries; // Number of root directory entries (fat12/16)
USHORT TotalSectors; // Number of total sectors on the drive, 16-bit
UCHAR MediaDescriptor; // Media descriptor byte
USHORT SectorsPerFat; // Sectors per FAT table (fat12/16)
USHORT SectorsPerTrack; // Number of sectors in a track
USHORT NumberOfHeads; // Number of heads on the disk
ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table)
ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume
UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80)
UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
ULONG VolumeSerialNumber; // Volume serial number
CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory
CHAR FileSystemType[8]; // One of the strings "FAT12 ", "FAT16 ", or "FAT "
UCHAR BootCodeAndData[448]; // The remainder of the boot sector
USHORT BootSectorMagic; // 0xAA55
} FAT_BOOTSECTOR, *PFAT_BOOTSECTOR;
C_ASSERT(sizeof(FAT_BOOTSECTOR) == FAT_BOOTSECTOR_SIZE);
typedef struct _FAT32_BOOTSECTOR
{
UCHAR JumpBoot[3]; // Jump instruction to boot code
CHAR OemName[8]; // "MSWIN4.1" for MS formatted volumes
USHORT BytesPerSector; // Bytes per sector
UCHAR SectorsPerCluster; // Number of sectors in a cluster
USHORT ReservedSectors; // Reserved sectors, usually 1 (the bootsector)
UCHAR NumberOfFats; // Number of FAT tables
USHORT RootDirEntries; // Number of root directory entries (fat12/16)
USHORT TotalSectors; // Number of total sectors on the drive, 16-bit
UCHAR MediaDescriptor; // Media descriptor byte
USHORT SectorsPerFat; // Sectors per FAT table (fat12/16)
USHORT SectorsPerTrack; // Number of sectors in a track
USHORT NumberOfHeads; // Number of heads on the disk
ULONG HiddenSectors; // Hidden sectors (sectors before the partition start like the partition table)
ULONG TotalSectorsBig; // This field is the new 32-bit total count of sectors on the volume
ULONG SectorsPerFatBig; // This field is the FAT32 32-bit count of sectors occupied by ONE FAT. BPB_FATSz16 must be 0
USHORT ExtendedFlags; // Extended flags (fat32)
USHORT FileSystemVersion; // File system version (fat32)
ULONG RootDirStartCluster; // Starting cluster of the root directory (fat32)
USHORT FsInfo; // Sector number of FSINFO structure in the reserved area of the FAT32 volume. Usually 1.
USHORT BackupBootSector; // If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6.
UCHAR Reserved[12]; // Reserved for future expansion
UCHAR DriveNumber; // Int 0x13 drive number (e.g. 0x80)
UCHAR Reserved1; // Reserved (used by Windows NT). Code that formats FAT volumes should always set this byte to 0.
UCHAR BootSignature; // Extended boot signature (0x29). This is a signature byte that indicates that the following three fields in the boot sector are present.
ULONG VolumeSerialNumber; // Volume serial number
CHAR VolumeLabel[11]; // Volume label. This field matches the 11-byte volume label recorded in the root directory
CHAR FileSystemType[8]; // Always set to the string "FAT32 "
UCHAR BootCodeAndData[420]; // The remainder of the boot sector
USHORT BootSectorMagic; // 0xAA55
} FAT32_BOOTSECTOR, *PFAT32_BOOTSECTOR;
C_ASSERT(sizeof(FAT32_BOOTSECTOR) == FAT32_BOOTSECTOR_SIZE);
typedef struct _BTRFS_BOOTSECTOR
{
UCHAR JumpBoot[3];
UCHAR ChunkMapSize;
UCHAR BootDrive;
ULONGLONG PartitionStartLBA;
UCHAR Fill[1521]; // 1536 - 15
USHORT BootSectorMagic;
} BTRFS_BOOTSECTOR, *PBTRFS_BOOTSECTOR;
C_ASSERT(sizeof(BTRFS_BOOTSECTOR) == BTRFS_BOOTSECTOR_SIZE);
typedef struct _NTFS_BOOTSECTOR
{
UCHAR Jump[3];
UCHAR OEMID[8];
USHORT BytesPerSector;
UCHAR SectorsPerCluster;
UCHAR Unused0[7];
UCHAR MediaId;
UCHAR Unused1[2];
USHORT SectorsPerTrack;
USHORT Heads;
UCHAR Unused2[4];
UCHAR Unused3[4];
USHORT Unknown[2];
ULONGLONG SectorCount;
ULONGLONG MftLocation;
ULONGLONG MftMirrLocation;
CHAR ClustersPerMftRecord;
UCHAR Unused4[3];
CHAR ClustersPerIndexRecord;
UCHAR Unused5[3];
ULONGLONG SerialNumber;
UCHAR Checksum[4];
UCHAR BootStrap[426];
USHORT EndSector;
UCHAR BootCodeAndData[7680]; // The remainder of the boot sector (8192 - 512)
} NTFS_BOOTSECTOR, *PNTFS_BOOTSECTOR;
C_ASSERT(sizeof(NTFS_BOOTSECTOR) == NTFS_BOOTSECTOR_SIZE);
// TODO: Add more bootsector structures!
#include <poppack.h>
/* LOCALS *******************************************************************/
/** IFS_PROVIDER **/
typedef struct _FILE_SYSTEM
{
PCWSTR FileSystemName;
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
PULIB_FORMAT FormatFunc;
PULIB_CHKDSK ChkdskFunc;
} FILE_SYSTEM, *PFILE_SYSTEM;
/* The list of file systems on which we can install ReactOS */
static FILE_SYSTEM RegisteredFileSystems[] =
{
/* NOTE: The FAT formatter will automatically
* determine whether to use FAT12/16 or FAT32. */
{ L"FAT" , VfatFormat, VfatChkdsk },
{ L"FAT32", VfatFormat, VfatChkdsk },
#if 0
{ L"FATX" , VfatxFormat, VfatxChkdsk },
{ L"NTFS" , NtfsFormat, NtfsChkdsk },
#endif
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
{ L"BTRFS", BtrfsFormat, BtrfsChkdsk },
#if 0
{ L"EXT2" , Ext2Format, Ext2Chkdsk },
{ L"EXT3" , Ext2Format, Ext2Chkdsk },
{ L"EXT4" , Ext2Format, Ext2Chkdsk },
#endif
};
/* FUNCTIONS ****************************************************************/
/** QueryAvailableFileSystemFormat() **/
BOOLEAN
GetRegisteredFileSystems(
IN ULONG Index,
OUT PCWSTR* FileSystemName)
{
if (Index >= ARRAYSIZE(RegisteredFileSystems))
return FALSE;
*FileSystemName = RegisteredFileSystems[Index].FileSystemName;
return TRUE;
}
/** GetProvider() **/
static PFILE_SYSTEM
GetFileSystemByName(
IN PCWSTR FileSystemName)
{
#if 0 // Reenable when the list of registered FSes will again be dynamic
PLIST_ENTRY ListEntry;
PFILE_SYSTEM_ITEM Item;
ListEntry = List->ListHead.Flink;
while (ListEntry != &List->ListHead)
{
Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
if (Item->FileSystemName &&
(wcsicmp(FileSystemName, Item->FileSystemName) == 0))
{
return Item;
}
ListEntry = ListEntry->Flink;
}
#else
ULONG Count = ARRAYSIZE(RegisteredFileSystems);
PFILE_SYSTEM FileSystems = RegisteredFileSystems;
ASSERT(FileSystems && Count != 0);
while (Count--)
{
if (FileSystems->FileSystemName &&
(wcsicmp(FileSystemName, FileSystems->FileSystemName) == 0))
{
return FileSystems;
}
++FileSystems;
}
#endif
return NULL;
}
/** ChkdskEx() **/
NTSTATUS
ChkdskFileSystem_UStr(
IN PUNICODE_STRING DriveRoot,
IN PCWSTR FileSystemName,
IN BOOLEAN FixErrors,
IN BOOLEAN Verbose,
IN BOOLEAN CheckOnlyIfDirty,
IN BOOLEAN ScanDrive,
IN PFMIFSCALLBACK Callback)
{
PFILE_SYSTEM FileSystem;
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
NTSTATUS Status;
BOOLEAN Success;
FileSystem = GetFileSystemByName(FileSystemName);
if (!FileSystem || !FileSystem->ChkdskFunc)
{
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
// Success = FALSE;
// Callback(DONE, 0, &Success);
return STATUS_NOT_SUPPORTED;
}
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
Status = STATUS_SUCCESS;
Success = FileSystem->ChkdskFunc(DriveRoot,
Callback,
FixErrors,
Verbose,
CheckOnlyIfDirty,
ScanDrive,
NULL,
NULL,
NULL,
NULL,
(PULONG)&Status);
if (!Success)
DPRINT1("ChkdskFunc() failed with Status 0x%lx\n", Status);
// Callback(DONE, 0, &Success);
return Status;
}
NTSTATUS
ChkdskFileSystem(
IN PCWSTR DriveRoot,
IN PCWSTR FileSystemName,
IN BOOLEAN FixErrors,
IN BOOLEAN Verbose,
IN BOOLEAN CheckOnlyIfDirty,
IN BOOLEAN ScanDrive,
IN PFMIFSCALLBACK Callback)
{
UNICODE_STRING DriveRootU;
RtlInitUnicodeString(&DriveRootU, DriveRoot);
return ChkdskFileSystem_UStr(&DriveRootU,
FileSystemName,
FixErrors,
Verbose,
CheckOnlyIfDirty,
ScanDrive,
Callback);
}
/** FormatEx() **/
NTSTATUS
FormatFileSystem_UStr(
IN PUNICODE_STRING DriveRoot,
IN PCWSTR FileSystemName,
IN FMIFS_MEDIA_FLAG MediaFlag,
IN PUNICODE_STRING Label,
IN BOOLEAN QuickFormat,
IN ULONG ClusterSize,
IN PFMIFSCALLBACK Callback)
{
PFILE_SYSTEM FileSystem;
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
BOOLEAN Success;
BOOLEAN BackwardCompatible = FALSE; // Default to latest FS versions.
MEDIA_TYPE MediaType;
FileSystem = GetFileSystemByName(FileSystemName);
if (!FileSystem || !FileSystem->FormatFunc)
{
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
// Success = FALSE;
// Callback(DONE, 0, &Success);
return STATUS_NOT_SUPPORTED;
}
[FSLIB][FMIFS][AUTOCHK][SETUPLIB] Use more Windows-compatible (but not fully compatible yet) Format() and Chkdsk() ULIB functions. [AUTOCHK] Add also support for scanning FATX volumes. The Format(), FormatEx(), Chkdsk(), ChkdskEx() functions exposed by the U*.DLL user-mode FS library dlls are different (and have different prototypes) than the similarly-named functions exported by FMIFS.DLL . In particular, what we used to call "xxxChkdskEx()" and "xxxFormatEx()" in our U*.DLL libraries actually correspond more, from their arguments, to the "Chkdsk()" and "Format()" functions in Windows' U*.DLL . Their *Ex() counterparts instead take most of the parameters through a structure passed by pointer. On FMIFS.DLL side, while FMIFS!Chkdsk() calls U*.DLL!Chkdsk() and FMIFS!ChkdskEx() calls U*.DLL!ChkdskEx() (and we do not implement these *Ex() functions at the moment), both FMIFS!Format() and FMIFS!FormatEx() call U*.DLL!Format() instead, while FMIFS!FormatEx2() calls U*.DLL!FormatEx() (that we do not implement yet either) !! To improve that, refactor the calls to these U*.DLL functions so as to respect the more compatible prototypes: They contain the correct number of parameters in a compatible order. However, some of the parameters do not have the same types yet: the strings are kept here in PUNICODE_STRINGS, while on Windows they are passed via an undocumented DSTRING struct, and the FMIFS callback is instead a MESSAGE struct/class on Windows. Finally, the MEDIA_TYPE parameter in U*.DLL!Format() is equivalent, yet not fully 100% in 1-to-1 correspondence, with the FMIFS_MEDIA_FLAG used in the corresponding FMIFS.DLL functions. One thing to notice is that the U*.DLL!Format() (and the Ex) functions support a BOOLEAN (a flag resp.) for telling that a backwards-compatible FS version should be used instead of the (default) latest FS version. This is used e.g. by the FAT FS, where by default FAT32 is selected (depending also on other constraints like, the disk and the partition sizes), unless that bit is set in which case, FAT16 (or 12) is used.
2020-11-22 04:35:37 +00:00
/* Set the BackwardCompatible flag in case we format with older FAT12/16 */
if (wcsicmp(FileSystemName, L"FAT") == 0)
BackwardCompatible = TRUE;
// else if (wcsicmp(FileSystemName, L"FAT32") == 0)
// BackwardCompatible = FALSE;
/* Convert the FMIFS MediaFlag to a NT MediaType */
// FIXME: Actually covert all the possible flags.
switch (MediaFlag)
{
case FMIFS_FLOPPY:
MediaType = F5_320_1024; // FIXME: This is hardfixed!
break;
case FMIFS_REMOVABLE:
MediaType = RemovableMedia;
break;
case FMIFS_HARDDISK:
MediaType = FixedMedia;
break;
default:
DPRINT1("Unknown FMIFS MediaFlag %d, converting 1-to-1 to NT MediaType\n",
MediaFlag);
MediaType = (MEDIA_TYPE)MediaFlag;
break;
}
Success = FileSystem->FormatFunc(DriveRoot,
Callback,
QuickFormat,
BackwardCompatible,
MediaType,
Label,
ClusterSize);
if (!Success)
DPRINT1("FormatFunc() failed\n");
// Callback(DONE, 0, &Success);
return (Success ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}
NTSTATUS
FormatFileSystem(
IN PCWSTR DriveRoot,
IN PCWSTR FileSystemName,
IN FMIFS_MEDIA_FLAG MediaFlag,
IN PCWSTR Label,
IN BOOLEAN QuickFormat,
IN ULONG ClusterSize,
IN PFMIFSCALLBACK Callback)
{
UNICODE_STRING DriveRootU;
UNICODE_STRING LabelU;
RtlInitUnicodeString(&DriveRootU, DriveRoot);
RtlInitUnicodeString(&LabelU, Label);
return FormatFileSystem_UStr(&DriveRootU,
FileSystemName,
MediaFlag,
&LabelU,
QuickFormat,
ClusterSize,
Callback);
}
//
// Bootsector routines
//
NTSTATUS
InstallFatBootCode(
IN PCWSTR SrcPath, // FAT12/16 bootsector source file (on the installation medium)
IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information
IN HANDLE RootPartition) // Partition holding the (old) FAT12/16 information
{
NTSTATUS Status;
UNICODE_STRING Name;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
BOOTCODE OrigBootSector = {0};
BOOTCODE NewBootSector = {0};
/* Allocate and read the current original partition bootsector */
Status = ReadBootCodeByHandle(&OrigBootSector,
RootPartition,
FAT_BOOTSECTOR_SIZE);
if (!NT_SUCCESS(Status))
return Status;
/* Allocate and read the new bootsector from SrcPath */
RtlInitUnicodeString(&Name, SrcPath);
Status = ReadBootCodeFromFile(&NewBootSector,
&Name,
FAT_BOOTSECTOR_SIZE);
if (!NT_SUCCESS(Status))
{
FreeBootCode(&OrigBootSector);
return Status;
}
/* Adjust the bootsector (copy a part of the FAT12/16 BPB) */
RtlCopyMemory(&((PFAT_BOOTSECTOR)NewBootSector.BootCode)->OemName,
&((PFAT_BOOTSECTOR)OrigBootSector.BootCode)->OemName,
FIELD_OFFSET(FAT_BOOTSECTOR, BootCodeAndData) -
FIELD_OFFSET(FAT_BOOTSECTOR, OemName));
/* Free the original bootsector */
FreeBootCode(&OrigBootSector);
/* Write the new bootsector to DstPath */
FileOffset.QuadPart = 0ULL;
Status = NtWriteFile(DstPath,
NULL,
NULL,
NULL,
&IoStatusBlock,
NewBootSector.BootCode,
NewBootSector.Length,
&FileOffset,
NULL);
/* Free the new bootsector */
FreeBootCode(&NewBootSector);
return Status;
}
NTSTATUS
InstallFat32BootCode(
IN PCWSTR SrcPath, // FAT32 bootsector source file (on the installation medium)
IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information
IN HANDLE RootPartition) // Partition holding the (old) FAT32 information
{
NTSTATUS Status;
UNICODE_STRING Name;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
USHORT BackupBootSector = 0;
BOOTCODE OrigBootSector = {0};
BOOTCODE NewBootSector = {0};
/* Allocate and read the current original partition bootsector */
Status = ReadBootCodeByHandle(&OrigBootSector,
RootPartition,
FAT32_BOOTSECTOR_SIZE);
if (!NT_SUCCESS(Status))
return Status;
/* Allocate and read the new bootsector (2 sectors) from SrcPath */
RtlInitUnicodeString(&Name, SrcPath);
Status = ReadBootCodeFromFile(&NewBootSector,
&Name,
2 * FAT32_BOOTSECTOR_SIZE);
if (!NT_SUCCESS(Status))
{
FreeBootCode(&OrigBootSector);
return Status;
}
/* Adjust the bootsector (copy a part of the FAT32 BPB) */
RtlCopyMemory(&((PFAT32_BOOTSECTOR)NewBootSector.BootCode)->OemName,
&((PFAT32_BOOTSECTOR)OrigBootSector.BootCode)->OemName,
FIELD_OFFSET(FAT32_BOOTSECTOR, BootCodeAndData) -
FIELD_OFFSET(FAT32_BOOTSECTOR, OemName));
/*
* We know we copy the boot code to a file only when DstPath != RootPartition,
* otherwise the boot code is copied to the specified root partition.
*/
if (DstPath != RootPartition)
{
/* Copy to a file: Disable the backup bootsector */
((PFAT32_BOOTSECTOR)NewBootSector.BootCode)->BackupBootSector = 0;
}
else
{
/* Copy to a disk: Get the location of the backup bootsector */
BackupBootSector = ((PFAT32_BOOTSECTOR)OrigBootSector.BootCode)->BackupBootSector;
}
/* Free the original bootsector */
FreeBootCode(&OrigBootSector);
/* Write the first sector of the new bootcode to DstPath sector 0 */
FileOffset.QuadPart = 0ULL;
Status = NtWriteFile(DstPath,
NULL,
NULL,
NULL,
&IoStatusBlock,
NewBootSector.BootCode,
FAT32_BOOTSECTOR_SIZE,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
FreeBootCode(&NewBootSector);
return Status;
}
if (DstPath == RootPartition)
{
/* Copy to a disk: Write the backup bootsector */
if ((BackupBootSector != 0x0000) && (BackupBootSector != 0xFFFF))
{
FileOffset.QuadPart = (ULONGLONG)((ULONG)BackupBootSector * FAT32_BOOTSECTOR_SIZE);
Status = NtWriteFile(DstPath,
NULL,
NULL,
NULL,
&IoStatusBlock,
NewBootSector.BootCode,
FAT32_BOOTSECTOR_SIZE,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
FreeBootCode(&NewBootSector);
return Status;
}
}
}
/* Write the second sector of the new bootcode to boot disk sector 14 */
// FileOffset.QuadPart = (ULONGLONG)(14 * FAT32_BOOTSECTOR_SIZE);
FileOffset.QuadPart = 14 * FAT32_BOOTSECTOR_SIZE;
Status = NtWriteFile(DstPath, // or really RootPartition ???
NULL,
NULL,
NULL,
&IoStatusBlock,
((PUCHAR)NewBootSector.BootCode + FAT32_BOOTSECTOR_SIZE),
FAT32_BOOTSECTOR_SIZE,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
}
/* Free the new bootsector */
FreeBootCode(&NewBootSector);
return Status;
}
NTSTATUS
InstallBtrfsBootCode(
IN PCWSTR SrcPath, // BTRFS bootsector source file (on the installation medium)
IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information
IN HANDLE RootPartition) // Partition holding the (old) BTRFS information
{
NTSTATUS Status;
NTSTATUS LockStatus;
UNICODE_STRING Name;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
PARTITION_INFORMATION_EX PartInfo;
BOOTCODE NewBootSector = {0};
/* Allocate and read the new bootsector from SrcPath */
RtlInitUnicodeString(&Name, SrcPath);
Status = ReadBootCodeFromFile(&NewBootSector,
&Name,
BTRFS_BOOTSECTOR_SIZE);
if (!NT_SUCCESS(Status))
return Status;
/*
* The BTRFS driver requires the volume to be locked in order to modify
* the first sectors of the partition, even though they are outside the
* file-system space / in the reserved area (they are situated before
* the super-block at 0x1000) and is in principle allowed by the NT
* storage stack.
* So we lock here in order to write the bootsector at sector 0.
* If locking fails, we ignore and continue nonetheless.
*/
LockStatus = NtFsControlFile(DstPath,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_LOCK_VOLUME,
NULL,
0,
NULL,
0);
if (!NT_SUCCESS(LockStatus))
{
DPRINT1("WARNING: Failed to lock BTRFS volume for writing bootsector! Operations may fail! (Status 0x%lx)\n", LockStatus);
}
/* Obtain partition info and write it to the bootsector */
Status = NtDeviceIoControlFile(RootPartition,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_PARTITION_INFO_EX,
NULL,
0,
&PartInfo,
sizeof(PartInfo));
if (!NT_SUCCESS(Status))
{
DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status);
goto Quit;
}
/* Write new bootsector to RootPath */
((PBTRFS_BOOTSECTOR)NewBootSector.BootCode)->PartitionStartLBA =
PartInfo.StartingOffset.QuadPart / SECTORSIZE;
/* Write sector 0 */
FileOffset.QuadPart = 0ULL;
Status = NtWriteFile(DstPath,
NULL,
NULL,
NULL,
&IoStatusBlock,
NewBootSector.BootCode,
NewBootSector.Length,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
goto Quit;
}
Quit:
/* Unlock the volume */
LockStatus = NtFsControlFile(DstPath,
NULL,
NULL,
NULL,
&IoStatusBlock,
FSCTL_UNLOCK_VOLUME,
NULL,
0,
NULL,
0);
if (!NT_SUCCESS(LockStatus))
{
DPRINT1("Failed to unlock BTRFS volume (Status 0x%lx)\n", LockStatus);
}
/* Free the new bootsector */
FreeBootCode(&NewBootSector);
return Status;
}
NTSTATUS
InstallNtfsBootCode(
IN PCWSTR SrcPath, // NTFS bootsector source file (on the installation medium)
IN HANDLE DstPath, // Where to save the bootsector built from the source + partition information
IN HANDLE RootPartition) // Partition holding the (old) NTFS information
{
NTSTATUS Status;
UNICODE_STRING Name;
IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER FileOffset;
BOOTCODE OrigBootSector = {0};
BOOTCODE NewBootSector = {0};
/* Allocate and read the current original partition bootsector */
Status = ReadBootCodeByHandle(&OrigBootSector, RootPartition, NTFS_BOOTSECTOR_SIZE);
if (!NT_SUCCESS(Status))
{
DPRINT1("InstallNtfsBootCode: Status %lx\n", Status);
return Status;
}
/* Allocate and read the new bootsector (16 sectors) from SrcPath */
RtlInitUnicodeString(&Name, SrcPath);
Status = ReadBootCodeFromFile(&NewBootSector, &Name, NTFS_BOOTSECTOR_SIZE);
if (!NT_SUCCESS(Status))
{
DPRINT1("InstallNtfsBootCode: Status %lx\n", Status);
FreeBootCode(&OrigBootSector);
return Status;
}
/* Adjust the bootsector (copy a part of the NTFS BPB) */
RtlCopyMemory(&((PNTFS_BOOTSECTOR)NewBootSector.BootCode)->OEMID,
&((PNTFS_BOOTSECTOR)OrigBootSector.BootCode)->OEMID,
FIELD_OFFSET(NTFS_BOOTSECTOR, BootStrap) - FIELD_OFFSET(NTFS_BOOTSECTOR, OEMID));
/* Write sector 0 */
FileOffset.QuadPart = 0ULL;
Status = NtWriteFile(DstPath,
NULL,
NULL,
NULL,
&IoStatusBlock,
NewBootSector.BootCode,
NewBootSector.Length,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
goto Quit;
}
Quit:
/* Free the new bootsector */
FreeBootCode(&NewBootSector);
return Status;
}
//
// Formatting routines
//
NTSTATUS
ChkdskPartition(
IN PPARTENTRY PartEntry,
IN BOOLEAN FixErrors,
IN BOOLEAN Verbose,
IN BOOLEAN CheckOnlyIfDirty,
IN BOOLEAN ScanDrive,
IN PFMIFSCALLBACK Callback)
{
NTSTATUS Status;
PDISKENTRY DiskEntry = PartEntry->DiskEntry;
// UNICODE_STRING PartitionRootPath;
WCHAR PartitionRootPath[MAX_PATH]; // PathBuffer
ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
/* HACK: Do not try to check a partition with an unknown filesystem */
if (!*PartEntry->FileSystem)
{
PartEntry->NeedsCheck = FALSE;
return STATUS_SUCCESS;
}
/* Set PartitionRootPath */
RtlStringCchPrintfW(PartitionRootPath, ARRAYSIZE(PartitionRootPath),
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskEntry->DiskNumber,
PartEntry->PartitionNumber);
DPRINT("PartitionRootPath: %S\n", PartitionRootPath);
/* Check the partition */
Status = ChkdskFileSystem(PartitionRootPath,
PartEntry->FileSystem,
FixErrors,
Verbose,
CheckOnlyIfDirty,
ScanDrive,
Callback);
if (!NT_SUCCESS(Status))
return Status;
PartEntry->NeedsCheck = FALSE;
return STATUS_SUCCESS;
}
NTSTATUS
FormatPartition(
IN PPARTENTRY PartEntry,
IN PCWSTR FileSystemName,
IN FMIFS_MEDIA_FLAG MediaFlag,
IN PCWSTR Label,
IN BOOLEAN QuickFormat,
IN ULONG ClusterSize,
IN PFMIFSCALLBACK Callback)
{
NTSTATUS Status;
PDISKENTRY DiskEntry = PartEntry->DiskEntry;
UCHAR PartitionType;
// UNICODE_STRING PartitionRootPath;
WCHAR PartitionRootPath[MAX_PATH]; // PathBuffer
ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
if (!FileSystemName || !*FileSystemName)
{
DPRINT1("No file system specified?\n");
return STATUS_UNRECOGNIZED_VOLUME;
}
/*
* Prepare the partition for formatting (for MBR disks, reset the
* partition type), and adjust the filesystem name in case of FAT
* vs. FAT32, depending on the geometry of the partition.
*/
// FIXME: Do this only if QuickFormat == FALSE? What about FAT handling?
/*
* Retrieve a partition type as a hint only. It will be used to determine
* whether to actually use FAT12/16 or FAT32 filesystem, depending on the
* geometry of the partition. If the partition resides on an MBR disk,
* the partition style will be reset to this value as well, unless the
* partition is OEM.
*/
PartitionType = FileSystemToMBRPartitionType(FileSystemName,
PartEntry->StartSector.QuadPart,
PartEntry->SectorCount.QuadPart);
if (PartitionType == PARTITION_ENTRY_UNUSED)
{
/* Unknown file system */
DPRINT1("Unknown file system '%S'\n", FileSystemName);
return STATUS_UNRECOGNIZED_VOLUME;
}
/* Reset the MBR partition type, unless this is an OEM partition */
if (DiskEntry->DiskStyle == PARTITION_STYLE_MBR)
{
if (!IsOEMPartition(PartEntry->PartitionType))
SetMBRPartitionType(PartEntry, PartitionType);
}
/*
* Adjust the filesystem name in case of FAT vs. FAT32, according to
* the type of partition returned by FileSystemToMBRPartitionType().
*/
if (wcsicmp(FileSystemName, L"FAT") == 0)
{
if ((PartitionType == PARTITION_FAT32) ||
(PartitionType == PARTITION_FAT32_XINT13))
{
FileSystemName = L"FAT32";
}
}
/* Commit the partition changes to the disk */
Status = WritePartitions(DiskEntry);
if (!NT_SUCCESS(Status))
{
DPRINT1("WritePartitions(disk %lu) failed, Status 0x%08lx\n",
DiskEntry->DiskNumber, Status);
return STATUS_PARTITION_FAILURE;
}
/* Set PartitionRootPath */
RtlStringCchPrintfW(PartitionRootPath, ARRAYSIZE(PartitionRootPath),
L"\\Device\\Harddisk%lu\\Partition%lu",
DiskEntry->DiskNumber,
PartEntry->PartitionNumber);
DPRINT("PartitionRootPath: %S\n", PartitionRootPath);
/* Format the partition */
Status = FormatFileSystem(PartitionRootPath,
FileSystemName,
MediaFlag,
Label,
QuickFormat,
ClusterSize,
Callback);
if (!NT_SUCCESS(Status))
return Status;
//
// TODO: Here, call a partlist.c function that update the actual
// FS name and the label fields of the volume.
//
PartEntry->FormatState = Formatted;
/* Set the new partition's file system proper */
RtlStringCbCopyW(PartEntry->FileSystem,
sizeof(PartEntry->FileSystem),
FileSystemName);
PartEntry->New = FALSE;
return STATUS_SUCCESS;
}
/* EOF */