diff --git a/reactos/lib/fslib/vfatlib/Makefile b/reactos/lib/fslib/vfatlib/Makefile index 36f0c199254..22384c0fe00 100755 --- a/reactos/lib/fslib/vfatlib/Makefile +++ b/reactos/lib/fslib/vfatlib/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.4 2003/08/22 13:53:02 ekohl Exp $ +# $Id: Makefile,v 1.5 2003/08/24 16:15:31 ekohl Exp $ PATH_TO_TOP = ../../.. @@ -10,6 +10,7 @@ TARGET_NAME = vfatlib TARGET_CFLAGS += -D_DISABLE_TIDENTS TARGET_OBJECTS = \ + fat12.o \ fat16.o \ fat32.o \ vfatlib.o diff --git a/reactos/lib/fslib/vfatlib/fat12.c b/reactos/lib/fslib/vfatlib/fat12.c new file mode 100644 index 00000000000..679e614611d --- /dev/null +++ b/reactos/lib/fslib/vfatlib/fat12.c @@ -0,0 +1,376 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS VFAT filesystem library + * FILE: fat12.c + * PURPOSE: Fat12 support + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * Eric Kohl (ekohl@rz-online.de) + * REVISIONS: + * EK 05/04-2003 Created + */ +#define NDEBUG +#include +#define NTOS_MODE_USER +#include +#include +#include "vfatlib.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 +Fat12WriteBootSector(IN HANDLE FileHandle, + IN PFAT16_BOOT_SECTOR BootSector) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING Name; + NTSTATUS Status; + PUCHAR NewBootSector; + LARGE_INTEGER FileOffset; + + /* Allocate buffer for new bootsector */ + NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), + 0, + SECTORSIZE); + if (NewBootSector == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Zero the new bootsector */ + memset(NewBootSector, 0, SECTORSIZE); + + /* Copy FAT16 BPB to new bootsector */ + memcpy((NewBootSector + 3), + &BootSector->OEMName[0], + 59); /* FAT16 BPB length (up to (not including) Res2) */ + + /* Write sector 0 */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + SECTORSIZE, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); + return(Status); + } + + /* Free the new boot sector */ + RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); + + return(Status); +} + + +static NTSTATUS +Fat12WriteFAT(IN HANDLE FileHandle, + ULONG SectorOffset, + IN PFAT16_BOOT_SECTOR BootSector) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING Name; + NTSTATUS Status; + PUCHAR Buffer; + LARGE_INTEGER FileOffset; + ULONG i; + ULONG Size; + 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 & 1*/ + Buffer[0] = 0xf8; /* Media type */ + Buffer[1] = 0xff; + Buffer[2] = 0xff; + + /* Write first sector of the FAT */ + FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors) * BootSector->BytesPerSector; + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + BootSector->BytesPerSector, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + return(Status); + } + + /* Zero the begin of the buffer */ + memset(Buffer, 0, 3); + + /* Zero the rest of the FAT */ + Sectors = 32 * 1024 / BootSector->BytesPerSector; + for (i = 1; i < (ULONG)BootSector->FATSectors; i += Sectors) + { + /* Zero some sectors of the FAT */ + FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors + i) * BootSector->BytesPerSector; + Size = (ULONG)BootSector->FATSectors - i; + if (Size > Sectors) + { + Size = Sectors; + } + Size *= BootSector->BytesPerSector; + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + Size, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + return(Status); + } + } + + /* Free the buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + + return(Status); +} + + +static NTSTATUS +Fat12WriteRootDirectory(IN HANDLE FileHandle, + IN PFAT16_BOOT_SECTOR BootSector) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + PUCHAR Buffer; + LARGE_INTEGER FileOffset; + ULONG FirstRootDirSector; + ULONG RootDirSectors; + ULONG Sectors; + ULONG Size; + ULONG i; + + DPRINT("BootSector->ReservedSectors = %hu\n", BootSector->ReservedSectors); + DPRINT("BootSector->FATSectors = %hu\n", BootSector->FATSectors); + DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector->SectorsPerCluster); + + /* Write cluster */ + RootDirSectors = ((BootSector->RootEntries * 32) + + (BootSector->BytesPerSector - 1)) / BootSector->BytesPerSector; + FirstRootDirSector = + BootSector->ReservedSectors + (BootSector->FATCount * BootSector->FATSectors); + + DPRINT("RootDirSectors = %lu\n", RootDirSectors); + DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector); + + /* Allocate buffer for the cluster */ + Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), + 0, + 32 * 1024); + if (Buffer == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Zero the buffer */ + memset(Buffer, 0, 32 * 1024); + + Sectors = 32 * 1024 / BootSector->BytesPerSector; + for (i = 1; i < RootDirSectors; i += Sectors) + { + /* Zero some sectors of the root directory */ + FileOffset.QuadPart = (FirstRootDirSector + i) * BootSector->BytesPerSector; + Size = RootDirSectors - i; + if (Size > Sectors) + { + Size = Sectors; + } + Size *= BootSector->BytesPerSector; + + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + Size, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + return(Status); + } + } + + /* Free the buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + + return(Status); +} + + +NTSTATUS +Fat12Format (HANDLE FileHandle, + PPARTITION_INFORMATION PartitionInfo, + PDISK_GEOMETRY DiskGeometry, + PUNICODE_STRING Label, + BOOL QuickFormat, + DWORD ClusterSize, + PFMIFSCALLBACK Callback) +{ + FAT16_BOOT_SECTOR BootSector; + ANSI_STRING VolumeLabel; + ULONG SectorCount; + ULONG RootDirSectors; + ULONG TmpVal1; + ULONG TmpVal2; + ULONG TmpVal3; + NTSTATUS Status; + + /* Calculate cluster size */ + if (ClusterSize == 0) + { + /* 4KB Cluster (Harddisk only) */ + ClusterSize = 4096; + } + + SectorCount = PartitionInfo->PartitionLength.QuadPart >> + GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */ + +// SectorCount = +// PartitionInfo->PartitionLength.u.LowPart / DiskGeometry->BytesPerSector; + + DPRINT1("SectorCount = %lu\n", SectorCount); + + memset(&BootSector, 0, sizeof(FAT16_BOOT_SECTOR)); + memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8); + BootSector.BytesPerSector = DiskGeometry->BytesPerSector; + BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector; + BootSector.ReservedSectors = 1; + BootSector.FATCount = 2; + BootSector.RootEntries = 512; + BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0; + BootSector.Media = 0xf8; + BootSector.FATSectors = 0; /* Set later. See below. */ + BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack; + BootSector.Heads = DiskGeometry->TracksPerCylinder; + BootSector.HiddenSectors = DiskGeometry->SectorsPerTrack; //PartitionInfo->HiddenSectors; /* FIXME: Hack! */ + BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0; + BootSector.Drive = 0xff; /* No BIOS boot drive available */ + BootSector.ExtBootSignature = 0x29; + BootSector.VolumeID = CalcVolumeSerialNumber(); + if ((Label == NULL) || (Label->Buffer == NULL)) + { + memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); + } + else + { + RtlUnicodeStringToAnsiString(&VolumeLabel, Label, TRUE); + memset(&BootSector.VolumeLabel[0], ' ', 11); + memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer, + VolumeLabel.Length < 11 ? VolumeLabel.Length : 11); + RtlFreeAnsiString(&VolumeLabel); + } + memcpy(&BootSector.SysType[0], "FAT12 ", 8); + + RootDirSectors = ((BootSector.RootEntries * 32) + + (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector; + + /* 341 FAT entries (12bit) fit into one 512 byte sector */ + TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors); + TmpVal2 = (341 * BootSector.SectorsPerCluster) + BootSector.FATCount; + TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; + BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff); + + DPRINT1("BootSector.FATSectors = %hx\n", BootSector.FATSectors); + + Status = Fat12WriteBootSector(FileHandle, + &BootSector); + if (!NT_SUCCESS(Status)) + { + DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status); + return Status; + } + + /* Write first FAT copy */ + Status = Fat12WriteFAT(FileHandle, + 0, + &BootSector); + if (!NT_SUCCESS(Status)) + { + DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status); + return Status; + } + + /* Write second FAT copy */ + Status = Fat12WriteFAT(FileHandle, + (ULONG)BootSector.FATSectors, + &BootSector); + if (!NT_SUCCESS(Status)) + { + DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status); + return Status; + } + + Status = Fat12WriteRootDirectory(FileHandle, + &BootSector); + if (!NT_SUCCESS(Status)) + { + DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status); + } + + return Status; +} diff --git a/reactos/lib/fslib/vfatlib/fat16.c b/reactos/lib/fslib/vfatlib/fat16.c index bc54d45733a..3beb4dfe4ef 100644 --- a/reactos/lib/fslib/vfatlib/fat16.c +++ b/reactos/lib/fslib/vfatlib/fat16.c @@ -3,7 +3,8 @@ * PROJECT: ReactOS VFAT filesystem library * FILE: fat16.c * PURPOSE: Fat16 support - * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de) + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * Eric Kohl (ekohl@rz-online.de) * REVISIONS: * EK 05/04-2003 Created */ @@ -28,6 +29,27 @@ GetShiftCount(ULONG Value) } +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 Fat16WriteBootSector(IN HANDLE FileHandle, IN PFAT16_BOOT_SECTOR BootSector) @@ -254,6 +276,7 @@ Fat16Format (HANDLE FileHandle, { FAT16_BOOT_SECTOR BootSector; ANSI_STRING VolumeLabel; + ULONG SectorCount; ULONG RootDirSectors; ULONG TmpVal1; ULONG TmpVal2; @@ -285,6 +308,9 @@ Fat16Format (HANDLE FileHandle, } } + SectorCount = PartitionInfo->PartitionLength.QuadPart >> + GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */ + memset(&BootSector, 0, sizeof(FAT16_BOOT_SECTOR)); memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8); BootSector.BytesPerSector = DiskGeometry->BytesPerSector; @@ -292,17 +318,16 @@ Fat16Format (HANDLE FileHandle, BootSector.ReservedSectors = 1; BootSector.FATCount = 2; BootSector.RootEntries = 512; - BootSector.Sectors = 0; //(SectorCount < 0x10000) ? SectorCount : 0; + BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0; BootSector.Media = 0xf8; BootSector.FATSectors = 0; /* Set later. See below. */ BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack; BootSector.Heads = DiskGeometry->TracksPerCylinder; BootSector.HiddenSectors = DiskGeometry->SectorsPerTrack; //PartitionInfo->HiddenSectors; /* FIXME: Hack! */ - BootSector.SectorsHuge = PartitionInfo->PartitionLength.QuadPart >> - GetShiftCount(BootSector.BytesPerSector); /* Use shifting to avoid 64-bit division */ + BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0; BootSector.Drive = 0xff; /* No BIOS boot drive available */ BootSector.ExtBootSignature = 0x29; - BootSector.VolumeID = 0x45768798; /* FIXME: */ + BootSector.VolumeID = CalcVolumeSerialNumber(); if ((Label == NULL) || (Label->Buffer == NULL)) { memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); @@ -322,7 +347,8 @@ Fat16Format (HANDLE FileHandle, RootDirSectors = ((BootSector.RootEntries * 32) + (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector; - TmpVal1 = BootSector.SectorsHuge - (BootSector.ReservedSectors + RootDirSectors); + /* 265 FAT entries (16bit) fit into one 512 byte sector */ + TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors); TmpVal2 = (256 * BootSector.SectorsPerCluster) + BootSector.FATCount; TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff); diff --git a/reactos/lib/fslib/vfatlib/fat32.c b/reactos/lib/fslib/vfatlib/fat32.c index e44e80cb94b..4db82d7dbaf 100644 --- a/reactos/lib/fslib/vfatlib/fat32.c +++ b/reactos/lib/fslib/vfatlib/fat32.c @@ -1,9 +1,10 @@ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS VFAT filesystem library - * FILE: fat16.c - * PURPOSE: Fat16 support - * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de) + * FILE: fat32.c + * PURPOSE: Fat32 support + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * Eric Kohl (ekohl@rz-online.de) * REVISIONS: * EK 05/04-2003 Created */ @@ -28,6 +29,27 @@ GetShiftCount(ULONG Value) } +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 Fat32WriteBootSector(IN HANDLE FileHandle, IN PFAT32_BOOT_SECTOR BootSector) @@ -377,7 +399,7 @@ Fat32Format (HANDLE FileHandle, BootSector.BootBackup = 6; BootSector.Drive = 0xff; /* No BIOS boot drive available */ BootSector.ExtBootSignature = 0x29; - BootSector.VolumeID = 0x45768798; /* FIXME: */ + BootSector.VolumeID = CalcVolumeSerialNumber (); if ((Label == NULL) || (Label->Buffer == NULL)) { memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); @@ -416,6 +438,14 @@ Fat32Format (HANDLE FileHandle, BootSector.FATSectors32 = TmpVal2; } +#if 0 + /* experimental */ + /* 128 FAT entries (32bit) fit into one 512 byte sector */ + TmpVal1 = BootSector.SectorsHuge - BootSector.ReservedSectors; + TmpVal2 = (128 * BootSector.SectorsPerCluster) + BootSector.FATCount; + BootSector.FATSectors32 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; +#endif + Status = Fat32WriteBootSector(FileHandle, &BootSector); if (!NT_SUCCESS(Status)) diff --git a/reactos/lib/fslib/vfatlib/vfatlib.c b/reactos/lib/fslib/vfatlib/vfatlib.c index a620775673a..9bd37ab2aa7 100755 --- a/reactos/lib/fslib/vfatlib/vfatlib.c +++ b/reactos/lib/fslib/vfatlib/vfatlib.c @@ -129,8 +129,7 @@ VfatFormat( ClusterSize, Callback); } -#if 0 - else if (PartitionInfo.PartitionType == PARTITION_FAT12) + else if (PartitionInfo.PartitionType == PARTITION_FAT_12) { Status = Fat12Format (FileHandle, &PartitionInfo, @@ -140,7 +139,6 @@ VfatFormat( ClusterSize, Callback); } -#endif else { Status = Fat16Format (FileHandle, diff --git a/reactos/lib/fslib/vfatlib/vfatlib.h b/reactos/lib/fslib/vfatlib/vfatlib.h index 15c4faf6577..02406cf4c6a 100755 --- a/reactos/lib/fslib/vfatlib/vfatlib.h +++ b/reactos/lib/fslib/vfatlib/vfatlib.h @@ -87,6 +87,15 @@ typedef struct _FAT32_FSINFO } __attribute__((packed)) FAT32_FSINFO, *PFAT32_FSINFO; +NTSTATUS +Fat12Format (HANDLE FileHandle, + PPARTITION_INFORMATION PartitionInfo, + PDISK_GEOMETRY DiskGeometry, + PUNICODE_STRING Label, + BOOL QuickFormat, + DWORD ClusterSize, + PFMIFSCALLBACK Callback); + NTSTATUS Fat16Format (HANDLE FileHandle, PPARTITION_INFORMATION PartitionInfo,