1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS VFAT filesystem library 4 * FILE: fat12.c 5 * PURPOSE: Fat12 support 6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * Eric Kohl 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include "vfatlib.h" 13 14 #define NDEBUG 15 #include <debug.h> 16 17 18 /* FUNCTIONS ******************************************************************/ 19 20 static NTSTATUS 21 Fat12WriteBootSector(IN HANDLE FileHandle, 22 IN PFAT16_BOOT_SECTOR BootSector, 23 IN OUT PFORMAT_CONTEXT Context) 24 { 25 IO_STATUS_BLOCK IoStatusBlock; 26 NTSTATUS Status; 27 PFAT16_BOOT_SECTOR NewBootSector; 28 LARGE_INTEGER FileOffset; 29 30 /* Allocate buffer for new bootsector */ 31 NewBootSector = (PFAT16_BOOT_SECTOR)RtlAllocateHeap(RtlGetProcessHeap (), 32 0, 33 BootSector->BytesPerSector); 34 if (NewBootSector == NULL) 35 return STATUS_INSUFFICIENT_RESOURCES; 36 37 /* Zero the new bootsector */ 38 RtlZeroMemory(NewBootSector, BootSector->BytesPerSector); 39 40 /* Copy FAT16 BPB to new bootsector */ 41 memcpy(NewBootSector, BootSector, 42 FIELD_OFFSET(FAT16_BOOT_SECTOR, Res2) - FIELD_OFFSET(FAT16_BOOT_SECTOR, Jump)); 43 /* FAT16 BPB length (up to (not including) Res2) */ 44 45 /* Write the boot sector signature */ 46 NewBootSector->Signature1 = 0xAA550000; 47 48 /* Write sector 0 */ 49 FileOffset.QuadPart = 0ULL; 50 Status = NtWriteFile(FileHandle, 51 NULL, 52 NULL, 53 NULL, 54 &IoStatusBlock, 55 NewBootSector, 56 BootSector->BytesPerSector, 57 &FileOffset, 58 NULL); 59 if (!NT_SUCCESS(Status)) 60 { 61 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 62 goto done; 63 } 64 65 UpdateProgress(Context, 1); 66 67 done: 68 /* Free the buffer */ 69 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); 70 return Status; 71 } 72 73 74 static NTSTATUS 75 Fat12WriteFAT(IN HANDLE FileHandle, 76 IN ULONG SectorOffset, 77 IN PFAT16_BOOT_SECTOR BootSector, 78 IN OUT PFORMAT_CONTEXT Context) 79 { 80 IO_STATUS_BLOCK IoStatusBlock; 81 NTSTATUS Status; 82 PUCHAR Buffer; 83 LARGE_INTEGER FileOffset; 84 ULONG i; 85 ULONG Size; 86 ULONG Sectors; 87 88 /* Allocate buffer */ 89 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 90 0, 91 32 * 1024); 92 if (Buffer == NULL) 93 return STATUS_INSUFFICIENT_RESOURCES; 94 95 /* Zero the buffer */ 96 RtlZeroMemory(Buffer, 32 * 1024); 97 98 /* FAT cluster 0 & 1*/ 99 Buffer[0] = 0xf8; /* Media type */ 100 Buffer[1] = 0xff; 101 Buffer[2] = 0xff; 102 103 /* Write first sector of the FAT */ 104 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors) * BootSector->BytesPerSector; 105 Status = NtWriteFile(FileHandle, 106 NULL, 107 NULL, 108 NULL, 109 &IoStatusBlock, 110 Buffer, 111 BootSector->BytesPerSector, 112 &FileOffset, 113 NULL); 114 if (!NT_SUCCESS(Status)) 115 { 116 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 117 goto done; 118 } 119 120 UpdateProgress(Context, 1); 121 122 /* Zero the begin of the buffer */ 123 RtlZeroMemory(Buffer, 3); 124 125 /* Zero the rest of the FAT */ 126 Sectors = 32 * 1024 / BootSector->BytesPerSector; 127 for (i = 1; i < (ULONG)BootSector->FATSectors; i += Sectors) 128 { 129 /* Zero some sectors of the FAT */ 130 FileOffset.QuadPart = (SectorOffset + BootSector->ReservedSectors + i) * BootSector->BytesPerSector; 131 if (((ULONG)BootSector->FATSectors - i) <= Sectors) 132 { 133 Sectors = (ULONG)BootSector->FATSectors - i; 134 } 135 136 Size = Sectors * BootSector->BytesPerSector; 137 Status = NtWriteFile(FileHandle, 138 NULL, 139 NULL, 140 NULL, 141 &IoStatusBlock, 142 Buffer, 143 Size, 144 &FileOffset, 145 NULL); 146 if (!NT_SUCCESS(Status)) 147 { 148 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 149 goto done; 150 } 151 152 UpdateProgress(Context, Sectors); 153 } 154 155 done: 156 /* Free the buffer */ 157 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 158 return Status; 159 } 160 161 162 static NTSTATUS 163 Fat12WriteRootDirectory(IN HANDLE FileHandle, 164 IN PFAT16_BOOT_SECTOR BootSector, 165 IN OUT PFORMAT_CONTEXT Context) 166 { 167 IO_STATUS_BLOCK IoStatusBlock; 168 NTSTATUS Status = STATUS_SUCCESS; 169 PUCHAR Buffer; 170 LARGE_INTEGER FileOffset; 171 ULONG FirstRootDirSector; 172 ULONG RootDirSectors; 173 ULONG Sectors; 174 ULONG Size; 175 ULONG i; 176 177 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector->ReservedSectors); 178 DPRINT("BootSector->FATSectors = %hu\n", BootSector->FATSectors); 179 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector->SectorsPerCluster); 180 181 /* Write cluster */ 182 RootDirSectors = ((BootSector->RootEntries * 32) + 183 (BootSector->BytesPerSector - 1)) / BootSector->BytesPerSector; 184 FirstRootDirSector = 185 BootSector->ReservedSectors + (BootSector->FATCount * BootSector->FATSectors); 186 187 DPRINT("RootDirSectors = %lu\n", RootDirSectors); 188 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector); 189 190 /* Allocate buffer for the cluster */ 191 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 192 0, 193 32 * 1024); 194 if (Buffer == NULL) 195 return STATUS_INSUFFICIENT_RESOURCES; 196 197 /* Zero the buffer */ 198 RtlZeroMemory(Buffer, 32 * 1024); 199 200 Sectors = 32 * 1024 / BootSector->BytesPerSector; 201 for (i = 0; i < RootDirSectors; i += Sectors) 202 { 203 /* Zero some sectors of the root directory */ 204 FileOffset.QuadPart = (FirstRootDirSector + i) * BootSector->BytesPerSector; 205 206 if ((RootDirSectors - i) <= Sectors) 207 { 208 Sectors = RootDirSectors - i; 209 } 210 211 Size = Sectors * BootSector->BytesPerSector; 212 213 Status = NtWriteFile(FileHandle, 214 NULL, 215 NULL, 216 NULL, 217 &IoStatusBlock, 218 Buffer, 219 Size, 220 &FileOffset, 221 NULL); 222 if (!NT_SUCCESS(Status)) 223 { 224 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 225 goto done; 226 } 227 228 UpdateProgress(Context, Sectors); 229 } 230 231 done: 232 /* Free the buffer */ 233 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 234 return Status; 235 } 236 237 238 NTSTATUS 239 Fat12Format(IN HANDLE FileHandle, 240 IN PPARTITION_INFORMATION PartitionInfo, 241 IN PDISK_GEOMETRY DiskGeometry, 242 IN PUNICODE_STRING Label, 243 IN BOOLEAN QuickFormat, 244 IN ULONG ClusterSize, 245 IN OUT PFORMAT_CONTEXT Context) 246 { 247 FAT16_BOOT_SECTOR BootSector; 248 OEM_STRING VolumeLabel; 249 ULONG SectorCount; 250 ULONG RootDirSectors; 251 ULONG TmpVal1; 252 ULONG TmpVal2; 253 ULONG TmpVal3; 254 NTSTATUS Status; 255 256 /* Calculate cluster size */ 257 if (ClusterSize == 0) 258 { 259 if (DiskGeometry->MediaType == FixedMedia) 260 { 261 /* 4KB Cluster (Harddisk only) */ 262 ClusterSize = 4096; 263 } 264 else 265 { 266 /* 512 byte cluster (floppy) */ 267 ClusterSize = 512; 268 } 269 } 270 271 SectorCount = PartitionInfo->PartitionLength.QuadPart >> 272 GetShiftCount(DiskGeometry->BytesPerSector); /* Use shifting to avoid 64-bit division */ 273 274 DPRINT("SectorCount = %lu\n", SectorCount); 275 276 RtlZeroMemory(&BootSector, sizeof(FAT16_BOOT_SECTOR)); 277 memcpy(&BootSector.OEMName[0], "MSWIN4.1", 8); 278 /* FIXME: Add dummy bootloader for real */ 279 BootSector.Jump[0] = 0xeb; 280 BootSector.Jump[1] = 0x3c; 281 BootSector.Jump[2] = 0x90; 282 BootSector.BytesPerSector = DiskGeometry->BytesPerSector; 283 BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector; 284 BootSector.ReservedSectors = 1; 285 BootSector.FATCount = 2; 286 BootSector.RootEntries = 512; 287 BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0; 288 BootSector.Media = 0xf8; 289 BootSector.FATSectors = 0; /* Set later. See below. */ 290 BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack; 291 BootSector.Heads = DiskGeometry->TracksPerCylinder; 292 BootSector.HiddenSectors = PartitionInfo->HiddenSectors; 293 BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0; 294 BootSector.Drive = (DiskGeometry->MediaType == FixedMedia) ? 0x80 : 0x00; 295 BootSector.ExtBootSignature = 0x29; 296 BootSector.VolumeID = CalcVolumeSerialNumber(); 297 if ((Label == NULL) || (Label->Buffer == NULL)) 298 { 299 memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); 300 } 301 else 302 { 303 RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE); 304 RtlFillMemory(&BootSector.VolumeLabel[0], 11, ' '); 305 memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer, 306 VolumeLabel.Length < 11 ? VolumeLabel.Length : 11); 307 RtlFreeOemString(&VolumeLabel); 308 } 309 310 memcpy(&BootSector.SysType[0], "FAT12 ", 8); 311 312 RootDirSectors = ((BootSector.RootEntries * 32) + 313 (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector; 314 315 /* Calculate number of FAT sectors */ 316 /* ((BootSector.BytesPerSector * 2) / 3) FAT entries (12bit) fit into one sector */ 317 TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors); 318 TmpVal2 = (((BootSector.BytesPerSector * 2) / 3) * BootSector.SectorsPerCluster) + BootSector.FATCount; 319 TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; 320 BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff); 321 322 DPRINT("BootSector.FATSectors = %hx\n", BootSector.FATSectors); 323 324 /* Init context data */ 325 Context->TotalSectorCount = 326 1 + (BootSector.FATSectors * 2) + RootDirSectors; 327 328 if (!QuickFormat) 329 { 330 Context->TotalSectorCount += SectorCount; 331 332 Status = FatWipeSectors(FileHandle, 333 SectorCount, 334 (ULONG)BootSector.SectorsPerCluster, 335 (ULONG)BootSector.BytesPerSector, 336 Context); 337 if (!NT_SUCCESS(Status)) 338 { 339 DPRINT("FatWipeSectors() failed with status 0x%.08x\n", Status); 340 return Status; 341 } 342 } 343 344 Status = Fat12WriteBootSector(FileHandle, 345 &BootSector, 346 Context); 347 if (!NT_SUCCESS(Status)) 348 { 349 DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status); 350 return Status; 351 } 352 353 /* Write first FAT copy */ 354 Status = Fat12WriteFAT(FileHandle, 355 0, 356 &BootSector, 357 Context); 358 if (!NT_SUCCESS(Status)) 359 { 360 DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status); 361 return Status; 362 } 363 364 /* Write second FAT copy */ 365 Status = Fat12WriteFAT(FileHandle, 366 (ULONG)BootSector.FATSectors, 367 &BootSector, 368 Context); 369 if (!NT_SUCCESS(Status)) 370 { 371 DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status); 372 return Status; 373 } 374 375 Status = Fat12WriteRootDirectory(FileHandle, 376 &BootSector, 377 Context); 378 if (!NT_SUCCESS(Status)) 379 { 380 DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status); 381 } 382 383 return Status; 384 } 385