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