--- trunk/reactos/lib/fslib/vfatxlib/fatx.c 2005-01-25 21:16:19 UTC (rev 13285)
+++ trunk/reactos/lib/fslib/vfatxlib/fatx.c 2005-01-25 22:10:39 UTC (rev 13286)
@@ -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;
+}
--- trunk/reactos/lib/fslib/vfatxlib/vfatxlib.c 2005-01-25 21:16:19 UTC (rev 13285)
+++ trunk/reactos/lib/fslib/vfatxlib/vfatxlib.c 2005-01-25 22:10:39 UTC (rev 13286)
@@ -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 */