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->OEMName[0], 42 &BootSector->OEMName[0], 43 FIELD_OFFSET(FAT16_BOOT_SECTOR, Res2) - FIELD_OFFSET(FAT16_BOOT_SECTOR, OEMName)); 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 BootSector.BytesPerSector = DiskGeometry->BytesPerSector; 280 BootSector.SectorsPerCluster = ClusterSize / BootSector.BytesPerSector; 281 BootSector.ReservedSectors = 1; 282 BootSector.FATCount = 2; 283 BootSector.RootEntries = 512; 284 BootSector.Sectors = (SectorCount < 0x10000) ? (unsigned short)SectorCount : 0; 285 BootSector.Media = 0xf8; 286 BootSector.FATSectors = 0; /* Set later. See below. */ 287 BootSector.SectorsPerTrack = DiskGeometry->SectorsPerTrack; 288 BootSector.Heads = DiskGeometry->TracksPerCylinder; 289 BootSector.HiddenSectors = PartitionInfo->HiddenSectors; 290 BootSector.SectorsHuge = (SectorCount >= 0x10000) ? (unsigned long)SectorCount : 0; 291 BootSector.Drive = (DiskGeometry->MediaType == FixedMedia) ? 0x80 : 0x00; 292 BootSector.ExtBootSignature = 0x29; 293 BootSector.VolumeID = CalcVolumeSerialNumber(); 294 if ((Label == NULL) || (Label->Buffer == NULL)) 295 { 296 memcpy(&BootSector.VolumeLabel[0], "NO NAME ", 11); 297 } 298 else 299 { 300 RtlUnicodeStringToOemString(&VolumeLabel, Label, TRUE); 301 RtlFillMemory(&BootSector.VolumeLabel[0], 11, ' '); 302 memcpy(&BootSector.VolumeLabel[0], VolumeLabel.Buffer, 303 VolumeLabel.Length < 11 ? VolumeLabel.Length : 11); 304 RtlFreeOemString(&VolumeLabel); 305 } 306 307 memcpy(&BootSector.SysType[0], "FAT12 ", 8); 308 309 RootDirSectors = ((BootSector.RootEntries * 32) + 310 (BootSector.BytesPerSector - 1)) / BootSector.BytesPerSector; 311 312 /* Calculate number of FAT sectors */ 313 /* ((BootSector.BytesPerSector * 2) / 3) FAT entries (12bit) fit into one sector */ 314 TmpVal1 = SectorCount - (BootSector.ReservedSectors + RootDirSectors); 315 TmpVal2 = (((BootSector.BytesPerSector * 2) / 3) * BootSector.SectorsPerCluster) + BootSector.FATCount; 316 TmpVal3 = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; 317 BootSector.FATSectors = (unsigned short)(TmpVal3 & 0xffff); 318 319 DPRINT("BootSector.FATSectors = %hx\n", BootSector.FATSectors); 320 321 /* Init context data */ 322 Context->TotalSectorCount = 323 1 + (BootSector.FATSectors * 2) + RootDirSectors; 324 325 if (!QuickFormat) 326 { 327 Context->TotalSectorCount += SectorCount; 328 329 Status = FatWipeSectors(FileHandle, 330 SectorCount, 331 (ULONG)BootSector.SectorsPerCluster, 332 (ULONG)BootSector.BytesPerSector, 333 Context); 334 if (!NT_SUCCESS(Status)) 335 { 336 DPRINT("FatWipeSectors() failed with status 0x%.08x\n", Status); 337 return Status; 338 } 339 } 340 341 Status = Fat12WriteBootSector(FileHandle, 342 &BootSector, 343 Context); 344 if (!NT_SUCCESS(Status)) 345 { 346 DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status); 347 return Status; 348 } 349 350 /* Write first FAT copy */ 351 Status = Fat12WriteFAT(FileHandle, 352 0, 353 &BootSector, 354 Context); 355 if (!NT_SUCCESS(Status)) 356 { 357 DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status); 358 return Status; 359 } 360 361 /* Write second FAT copy */ 362 Status = Fat12WriteFAT(FileHandle, 363 (ULONG)BootSector.FATSectors, 364 &BootSector, 365 Context); 366 if (!NT_SUCCESS(Status)) 367 { 368 DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status); 369 return Status; 370 } 371 372 Status = Fat12WriteRootDirectory(FileHandle, 373 &BootSector, 374 Context); 375 if (!NT_SUCCESS(Status)) 376 { 377 DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status); 378 } 379 380 return Status; 381 } 382