reactos/sdk/lib/fslib/vfatxlib/fatx.c
2021-06-11 15:33:08 +03:00

435 lines
12 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS VFATX filesystem library
* FILE: fatx.c
* PURPOSE: Fatx support
* PROGRAMMERS:
* REVISIONS:
*/
#include "vfatxlib.h"
#include <ndk/kefuncs.h>
#include <ndk/rtlfuncs.h>
#define NDEBUG
#include <debug.h>
static ULONG
GetShiftCount(IN ULONG Value)
{
ULONG i = 1;
while (Value > 0)
{
i++;
Value /= 2;
}
return i - 2;
}
static ULONG
CalcVolumeSerialNumber(VOID)
{
LARGE_INTEGER SystemTime;
TIME_FIELDS TimeFields;
ULONG Serial;
PUCHAR Buffer;
NtQuerySystemTime (&SystemTime);
RtlTimeToTimeFields (&SystemTime, &TimeFields);
Buffer = (PUCHAR)&Serial;
Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
return Serial;
}
static NTSTATUS
FatxWriteBootSector(IN HANDLE FileHandle,
IN PFATX_BOOT_SECTOR BootSector,
IN OUT PFORMAT_CONTEXT Context)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
PUCHAR NewBootSector;
LARGE_INTEGER FileOffset;
/* Allocate buffer for new bootsector */
NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
0,
sizeof(FATX_BOOT_SECTOR));
if (NewBootSector == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
/* Zero the new bootsector */
memset(NewBootSector, 0, sizeof(FATX_BOOT_SECTOR));
/* Copy FAT16 BPB to new bootsector */
memcpy(NewBootSector, BootSector, 18); /* FAT16 BPB length (up to (not including) Res2) */
/* Write sector 0 */
FileOffset.QuadPart = 0ULL;
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
NewBootSector,
sizeof(FATX_BOOT_SECTOR),
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
return Status;
}
VfatxUpdateProgress(Context, 1);
/* Free the new boot sector */
RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector);
return Status;
}
static NTSTATUS
Fatx16WriteFAT(IN HANDLE FileHandle,
IN ULONG SectorOffset,
IN ULONG FATSectors,
IN OUT PFORMAT_CONTEXT Context)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
PUCHAR Buffer;
LARGE_INTEGER FileOffset;
ULONG i;
ULONG Sectors;
/* Allocate buffer */
Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
0,
32 * 1024);
if (Buffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
/* Zero the buffer */
memset(Buffer, 0, 32 * 1024);
/* FAT cluster 0 */
Buffer[0] = 0xf8; /* Media type */
Buffer[1] = 0xff;
/* FAT cluster 1 */
Buffer[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
Buffer[3] = 0xff;
/* Write first sector of the FAT */
FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR);
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
512,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return Status;
}
VfatxUpdateProgress(Context, 1);
/* Zero the begin of the buffer */
memset(Buffer, 0, 4);
/* Zero the rest of the FAT */
Sectors = 32 * 1024 / 512;
for (i = 1; i < FATSectors; i += Sectors)
{
/* Zero some sectors of the FAT */
FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR) ;
if ((FATSectors - i) <= Sectors)
{
Sectors = FATSectors - i;
}
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
Sectors * 512,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return Status;
}
VfatxUpdateProgress(Context, Sectors);
}
/* Free the buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return Status;
}
static NTSTATUS
Fatx32WriteFAT(IN HANDLE FileHandle,
IN ULONG SectorOffset,
IN ULONG FATSectors,
IN OUT PFORMAT_CONTEXT Context)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
PUCHAR Buffer;
LARGE_INTEGER FileOffset;
ULONG i;
ULONG Sectors;
/* Allocate buffer */
Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
0,
64 * 1024);
if (Buffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
/* Zero the buffer */
memset(Buffer, 0, 64 * 1024);
/* FAT cluster 0 */
Buffer[0] = 0xf8; /* Media type */
Buffer[1] = 0xff;
Buffer[2] = 0xff;
Buffer[3] = 0x0f;
/* FAT cluster 1 */
Buffer[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */
Buffer[5] = 0xff;
Buffer[6] = 0xff;
Buffer[7] = 0x0f;
/* Write first sector of the FAT */
FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR);
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
512,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return Status;
}
VfatxUpdateProgress(Context, 1);
/* Zero the begin of the buffer */
memset(Buffer, 0, 8);
/* Zero the rest of the FAT */
Sectors = 64 * 1024 / 512;
for (i = 1; i < FATSectors; i += Sectors)
{
/* Zero some sectors of the FAT */
FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR);
if ((FATSectors - i) <= Sectors)
{
Sectors = FATSectors - i;
}
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
Sectors * 512,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return Status;
}
VfatxUpdateProgress(Context, Sectors);
}
/* Free the buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return Status;
}
static NTSTATUS
FatxWriteRootDirectory(IN HANDLE FileHandle,
IN ULONG FATSectors,
IN OUT PFORMAT_CONTEXT Context)
{
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status = STATUS_SUCCESS;
PUCHAR Buffer;
LARGE_INTEGER FileOffset;
ULONG FirstRootDirSector;
ULONG RootDirSectors;
/* Write cluster */
RootDirSectors = 256 * 64 / 512;
FirstRootDirSector = sizeof(FATX_BOOT_SECTOR) / 512 + FATSectors;
DPRINT("RootDirSectors = %lu\n", RootDirSectors);
DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector);
/* Allocate buffer for the cluster */
Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
0,
RootDirSectors * 512);
if (Buffer == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
/* Zero the buffer */
memset(Buffer, 0xff, RootDirSectors * 512);
/* Zero some sectors of the root directory */
FileOffset.QuadPart = FirstRootDirSector * 512;
Status = NtWriteFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
RootDirSectors * 512,
&FileOffset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
}
/* Free the buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
return Status;
}
NTSTATUS
FatxFormat(IN HANDLE FileHandle,
IN PPARTITION_INFORMATION PartitionInfo,
IN PDISK_GEOMETRY DiskGeometry,
IN BOOLEAN QuickFormat,
IN OUT PFORMAT_CONTEXT Context)
{
FATX_BOOT_SECTOR BootSector;
ULONGLONG SectorCount;
ULONG ClusterCount;
ULONG RootDirSectors;
ULONG FATSectors;
NTSTATUS Status;
SectorCount = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(512); /* Use shifting to avoid 64-bit division */
memset(&BootSector, 0, sizeof(FATX_BOOT_SECTOR));
memcpy(&BootSector.SysType[0], "FATX", 4);
BootSector.SectorsPerCluster = 32;
BootSector.FATCount = 1;
BootSector.VolumeID = CalcVolumeSerialNumber();
RootDirSectors = 256 * 64 / 512;
/* Calculate number of FAT sectors */
ClusterCount = SectorCount >> GetShiftCount(32);
if (ClusterCount > 65525)
{
FATSectors = (((ClusterCount * 4) + 4095) & ~4095) >> GetShiftCount(512);
}
else
{
FATSectors = (((ClusterCount * 2) + 4095) & ~4095) >> GetShiftCount(512);
}
DPRINT("FATSectors = %hu\n", FATSectors);
/* Init context data */
if (QuickFormat)
{
Context->TotalSectorCount =
1 + FATSectors + RootDirSectors;
}
else
{
Context->TotalSectorCount = SectorCount;
}
Status = FatxWriteBootSector(FileHandle,
&BootSector,
Context);
if (!NT_SUCCESS(Status))
{
DPRINT("FatxWriteBootSector() failed with status 0x%.08x\n", Status);
return Status;
}
/* Write first FAT copy */
if (ClusterCount > 65525)
{
Status = Fatx32WriteFAT(FileHandle,
0,
FATSectors,
Context);
}
else
{
Status = Fatx16WriteFAT(FileHandle,
0,
FATSectors,
Context);
}
if (!NT_SUCCESS(Status))
{
DPRINT("FatxWriteFAT() failed with status 0x%.08x\n", Status);
return Status;
}
Status = FatxWriteRootDirectory(FileHandle,
FATSectors,
Context);
if (!NT_SUCCESS(Status))
{
DPRINT("FatxWriteRootDirectory() failed with status 0x%.08x\n", Status);
}
if (!QuickFormat)
{
/* FIXME: Fill remaining sectors */
}
return Status;
}