- Added vfatxlib.

svn path=/trunk/; revision=13286
This commit is contained in:
Hartmut Birr 2005-01-25 22:10:39 +00:00
parent ce143bb72c
commit 85d156faef
5 changed files with 716 additions and 0 deletions

View file

@ -0,0 +1,24 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS VFAT filesystem library
* FILE: include/fslib/vfatlib.h
* PURPOSE: Public definitions for vfat filesystem library
*/
#ifndef __VFATXLIB_H
#define __VFATXLIB_H
#include <fmifs.h>
NTSTATUS
VfatxInitialize (VOID);
NTSTATUS
VfatxCleanup (VOID);
NTSTATUS
VfatxFormat (PUNICODE_STRING DriveRoot,
ULONG MediaFlag,
BOOLEAN QuickFormat,
PFMIFSCALLBACK Callback);
#endif /*__VFATLIB_H */

View file

@ -0,0 +1,18 @@
# $Id$
PATH_TO_TOP = ../../..
TARGET_TYPE = library
TARGET_NAME = vfatxlib
# require os code to explicitly request A/W version of structs/functions
TARGET_CFLAGS += -D_DISABLE_TIDENTS -Wall -Werror
TARGET_OBJECTS = \
fatx.o \
vfatxlib.o
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk

View file

@ -0,0 +1,431 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS VFATX filesystem library
* FILE: fatx.c
* PURPOSE: Fatx support
* PROGRAMMERS: Hartmut Birr
* REVISIONS:
*/
#define NDEBUG
#include <debug.h>
#define NTOS_MODE_USER
#include <ntos.h>
#include <ddk/ntddscsi.h>
#include <mem.h>
#include "vfatxlib.h"
static ULONG
GetShiftCount(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;
}
UpdateProgress (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);
}
UpdateProgress (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);
}
UpdateProgress (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);
}
UpdateProgress (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);
}
UpdateProgress (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 (HANDLE FileHandle,
PPARTITION_INFORMATION PartitionInfo,
PDISK_GEOMETRY DiskGeometry,
BOOLEAN QuickFormat,
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;
}

View file

@ -0,0 +1,198 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS VFATx filesystem library
* FILE: vfatxlib.c
* PURPOSE: Main API
* PROGRAMMERS: Hartmut Birr
* REVISIONS:
* CSH 05/04-2003 Created
*/
#define NTOS_MODE_USER
#include <ntos.h>
#include <ddk/ntddscsi.h>
#include <fslib/vfatxlib.h>
#include "vfatxlib.h"
#define NDEBUG
#include <debug.h>
NTSTATUS
VfatxInitialize(VOID)
{
DPRINT("VfatxInitialize()\n");
return STATUS_SUCCESS;
}
NTSTATUS
VfatxFormat (PUNICODE_STRING DriveRoot,
ULONG MediaFlag,
BOOLEAN QuickFormat,
PFMIFSCALLBACK Callback)
{
OBJECT_ATTRIBUTES ObjectAttributes;
DISK_GEOMETRY DiskGeometry;
IO_STATUS_BLOCK Iosb;
HANDLE FileHandle;
PARTITION_INFORMATION PartitionInfo;
FORMAT_CONTEXT Context;
NTSTATUS Status;
DPRINT("VfatxFormat(DriveRoot '%wZ')\n", DriveRoot);
Context.TotalSectorCount = 0;
Context.CurrentSectorCount = 0;
Context.Callback = Callback;
Context.Success = FALSE;
Context.Percent = 0;
InitializeObjectAttributes(&ObjectAttributes,
DriveRoot,
0,
NULL,
NULL);
Status = NtOpenFile(&FileHandle,
FILE_WRITE_ACCESS | FILE_WRITE_ATTRIBUTES,
&ObjectAttributes,
&Iosb,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status))
{
DPRINT("NtOpenFile() failed with status 0x%.08x\n", Status);
return Status;
}
Status = NtDeviceIoControlFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&DiskGeometry,
sizeof(DISK_GEOMETRY));
if (!NT_SUCCESS(Status))
{
DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY failed with status 0x%.08x\n", Status);
NtClose(FileHandle);
return Status;
}
if (DiskGeometry.MediaType == FixedMedia)
{
DPRINT("Cylinders %I64d\n", DiskGeometry.Cylinders.QuadPart);
DPRINT("TracksPerCylinder %ld\n", DiskGeometry.TracksPerCylinder);
DPRINT("SectorsPerTrack %ld\n", DiskGeometry.SectorsPerTrack);
DPRINT("BytesPerSector %ld\n", DiskGeometry.BytesPerSector);
DPRINT("DiskSize %I64d\n",
DiskGeometry.Cylinders.QuadPart *
(ULONGLONG)DiskGeometry.TracksPerCylinder *
(ULONGLONG)DiskGeometry.SectorsPerTrack *
(ULONGLONG)DiskGeometry.BytesPerSector);
Status = NtDeviceIoControlFile(FileHandle,
NULL,
NULL,
NULL,
&Iosb,
IOCTL_DISK_GET_PARTITION_INFO,
NULL,
0,
&PartitionInfo,
sizeof(PARTITION_INFORMATION));
if (!NT_SUCCESS(Status))
{
DPRINT("IOCTL_DISK_GET_PARTITION_INFO failed with status 0x%.08x\n", Status);
NtClose(FileHandle);
return Status;
}
/*
* FIXME: This is a hack!
* Partitioning software MUST set the correct number of hidden sectors!
*/
PartitionInfo.HiddenSectors = DiskGeometry.SectorsPerTrack;
}
else
{
PartitionInfo.PartitionType = 0;
PartitionInfo.StartingOffset.QuadPart = 0ULL;
PartitionInfo.PartitionLength.QuadPart =
DiskGeometry.Cylinders.QuadPart *
(ULONGLONG)DiskGeometry.TracksPerCylinder *
(ULONGLONG)DiskGeometry.SectorsPerTrack *
(ULONGLONG)DiskGeometry.BytesPerSector;
PartitionInfo.HiddenSectors = 0;
PartitionInfo.PartitionNumber = 0;
PartitionInfo.BootIndicator = FALSE;
PartitionInfo.RewritePartition = FALSE;
PartitionInfo.RecognizedPartition = FALSE;
}
DPRINT("PartitionType 0x%x\n", PartitionInfo.PartitionType);
DPRINT("StartingOffset %I64d\n", PartitionInfo.StartingOffset.QuadPart);
DPRINT("PartitionLength %I64d\n", PartitionInfo.PartitionLength.QuadPart);
DPRINT("HiddenSectors %lu\n", PartitionInfo.HiddenSectors);
DPRINT("PartitionNumber %d\n", PartitionInfo.PartitionNumber);
DPRINT("BootIndicator 0x%x\n", PartitionInfo.BootIndicator);
DPRINT("RewritePartition %d\n", PartitionInfo.RewritePartition);
DPRINT("RecognizedPartition %d\n", PartitionInfo.RecognizedPartition);
if (Callback != NULL)
{
Context.Percent = 0;
Callback (PROGRESS, 0, (PVOID)&Context.Percent);
}
Status = FatxFormat (FileHandle,
&PartitionInfo,
&DiskGeometry,
QuickFormat,
&Context);
NtClose(FileHandle);
if (Callback != NULL)
{
Context.Success = (BOOLEAN)(NT_SUCCESS(Status));
Callback (DONE, 0, (PVOID)&Context.Success);
}
DPRINT("VfatFormat() done. Status 0x%.08x\n", Status);
return Status;
}
NTSTATUS
VfatxCleanup(VOID)
{
DPRINT("VfatxCleanup()\n");
return STATUS_SUCCESS;
}
VOID
VfatxUpdateProgress (PFORMAT_CONTEXT Context,
ULONG Increment)
{
ULONG NewPercent;
Context->CurrentSectorCount += (ULONGLONG)Increment;
NewPercent = (Context->CurrentSectorCount * 100ULL) / Context->TotalSectorCount;
if (NewPercent > Context->Percent)
{
Context->Percent = NewPercent;
Context->Callback (PROGRESS, 0, &Context->Percent);
}
}
/* EOF */

View file

@ -0,0 +1,45 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS VFAT filesystem library
* FILE: vfatxlib.h
*/
#define NDEBUG
#include <debug.h>
#define NTOS_MODE_USER
#include <ntos.h>
#include <fslib/vfatlib.h>
typedef struct _FATX_BOOT_SECTOR
{
unsigned char SysType[4]; // 0
unsigned long VolumeID; // 4
unsigned long SectorsPerCluster; // 8
unsigned short FATCount; // 12
unsigned long Unknown; // 14
unsigned char Unused[4078]; // 18
} __attribute__((packed)) FATX_BOOT_SECTOR, *PFATX_BOOT_SECTOR;
typedef struct _FORMAT_CONTEXT
{
PFMIFSCALLBACK Callback;
ULONG TotalSectorCount;
ULONG CurrentSectorCount;
BOOLEAN Success;
ULONG Percent;
} FORMAT_CONTEXT, *PFORMAT_CONTEXT;
NTSTATUS
FatxFormat (HANDLE FileHandle,
PPARTITION_INFORMATION PartitionInfo,
PDISK_GEOMETRY DiskGeometry,
BOOLEAN QuickFormat,
PFORMAT_CONTEXT Context);
VOID
UpdateProgress (PFORMAT_CONTEXT Context,
ULONG Increment);
/* EOF */