1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS VFATX filesystem library 4 * FILE: fatx.c 5 * PURPOSE: Fatx support 6 * PROGRAMMERS: 7 * REVISIONS: 8 */ 9 10 #include "vfatxlib.h" 11 12 #include <ndk/kefuncs.h> 13 #include <ndk/rtlfuncs.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 static ULONG 19 GetShiftCount(IN ULONG Value) 20 { 21 ULONG i = 1; 22 23 while (Value > 0) 24 { 25 i++; 26 Value /= 2; 27 } 28 29 return i - 2; 30 } 31 32 33 static ULONG 34 CalcVolumeSerialNumber(VOID) 35 { 36 LARGE_INTEGER SystemTime; 37 TIME_FIELDS TimeFields; 38 ULONG Serial; 39 PUCHAR Buffer; 40 41 NtQuerySystemTime (&SystemTime); 42 RtlTimeToTimeFields (&SystemTime, &TimeFields); 43 44 Buffer = (PUCHAR)&Serial; 45 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF); 46 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF); 47 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF); 48 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF); 49 50 return Serial; 51 } 52 53 54 static NTSTATUS 55 FatxWriteBootSector(IN HANDLE FileHandle, 56 IN PFATX_BOOT_SECTOR BootSector, 57 IN OUT PFORMAT_CONTEXT Context) 58 { 59 IO_STATUS_BLOCK IoStatusBlock; 60 NTSTATUS Status; 61 PUCHAR NewBootSector; 62 LARGE_INTEGER FileOffset; 63 64 /* Allocate buffer for new bootsector */ 65 NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 66 0, 67 sizeof(FATX_BOOT_SECTOR)); 68 if (NewBootSector == NULL) 69 return STATUS_INSUFFICIENT_RESOURCES; 70 71 /* Zero the new bootsector */ 72 memset(NewBootSector, 0, sizeof(FATX_BOOT_SECTOR)); 73 74 /* Copy FAT16 BPB to new bootsector */ 75 memcpy(NewBootSector, BootSector, 18); /* FAT16 BPB length (up to (not including) Res2) */ 76 77 /* Write sector 0 */ 78 FileOffset.QuadPart = 0ULL; 79 Status = NtWriteFile(FileHandle, 80 NULL, 81 NULL, 82 NULL, 83 &IoStatusBlock, 84 NewBootSector, 85 sizeof(FATX_BOOT_SECTOR), 86 &FileOffset, 87 NULL); 88 if (!NT_SUCCESS(Status)) 89 { 90 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 91 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); 92 return Status; 93 } 94 95 VfatxUpdateProgress(Context, 1); 96 97 /* Free the new boot sector */ 98 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); 99 100 return Status; 101 } 102 103 104 static NTSTATUS 105 Fatx16WriteFAT(IN HANDLE FileHandle, 106 IN ULONG SectorOffset, 107 IN ULONG FATSectors, 108 IN OUT PFORMAT_CONTEXT Context) 109 { 110 IO_STATUS_BLOCK IoStatusBlock; 111 NTSTATUS Status; 112 PUCHAR Buffer; 113 LARGE_INTEGER FileOffset; 114 ULONG i; 115 ULONG Sectors; 116 117 /* Allocate buffer */ 118 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 119 0, 120 32 * 1024); 121 if (Buffer == NULL) 122 return STATUS_INSUFFICIENT_RESOURCES; 123 124 /* Zero the buffer */ 125 memset(Buffer, 0, 32 * 1024); 126 127 /* FAT cluster 0 */ 128 Buffer[0] = 0xf8; /* Media type */ 129 Buffer[1] = 0xff; 130 131 /* FAT cluster 1 */ 132 Buffer[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */ 133 Buffer[3] = 0xff; 134 135 /* Write first sector of the FAT */ 136 FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR); 137 Status = NtWriteFile(FileHandle, 138 NULL, 139 NULL, 140 NULL, 141 &IoStatusBlock, 142 Buffer, 143 512, 144 &FileOffset, 145 NULL); 146 if (!NT_SUCCESS(Status)) 147 { 148 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 149 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 150 return Status; 151 } 152 153 VfatxUpdateProgress(Context, 1); 154 155 /* Zero the begin of the buffer */ 156 memset(Buffer, 0, 4); 157 158 /* Zero the rest of the FAT */ 159 Sectors = 32 * 1024 / 512; 160 for (i = 1; i < FATSectors; i += Sectors) 161 { 162 /* Zero some sectors of the FAT */ 163 FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR) ; 164 if ((FATSectors - i) <= Sectors) 165 { 166 Sectors = FATSectors - i; 167 } 168 169 Status = NtWriteFile(FileHandle, 170 NULL, 171 NULL, 172 NULL, 173 &IoStatusBlock, 174 Buffer, 175 Sectors * 512, 176 &FileOffset, 177 NULL); 178 if (!NT_SUCCESS(Status)) 179 { 180 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 181 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 182 return Status; 183 } 184 185 VfatxUpdateProgress(Context, Sectors); 186 } 187 188 /* Free the buffer */ 189 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 190 191 return Status; 192 } 193 194 static NTSTATUS 195 Fatx32WriteFAT(IN HANDLE FileHandle, 196 IN ULONG SectorOffset, 197 IN ULONG FATSectors, 198 IN OUT PFORMAT_CONTEXT Context) 199 { 200 IO_STATUS_BLOCK IoStatusBlock; 201 NTSTATUS Status; 202 PUCHAR Buffer; 203 LARGE_INTEGER FileOffset; 204 ULONG i; 205 ULONG Sectors; 206 207 /* Allocate buffer */ 208 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 209 0, 210 64 * 1024); 211 if (Buffer == NULL) 212 return STATUS_INSUFFICIENT_RESOURCES; 213 214 /* Zero the buffer */ 215 memset(Buffer, 0, 64 * 1024); 216 217 /* FAT cluster 0 */ 218 Buffer[0] = 0xf8; /* Media type */ 219 Buffer[1] = 0xff; 220 Buffer[2] = 0xff; 221 Buffer[3] = 0x0f; 222 223 /* FAT cluster 1 */ 224 Buffer[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */ 225 Buffer[5] = 0xff; 226 Buffer[6] = 0xff; 227 Buffer[7] = 0x0f; 228 229 /* Write first sector of the FAT */ 230 FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR); 231 Status = NtWriteFile(FileHandle, 232 NULL, 233 NULL, 234 NULL, 235 &IoStatusBlock, 236 Buffer, 237 512, 238 &FileOffset, 239 NULL); 240 if (!NT_SUCCESS(Status)) 241 { 242 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 243 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 244 return Status; 245 } 246 247 VfatxUpdateProgress(Context, 1); 248 249 /* Zero the begin of the buffer */ 250 memset(Buffer, 0, 8); 251 252 /* Zero the rest of the FAT */ 253 Sectors = 64 * 1024 / 512; 254 for (i = 1; i < FATSectors; i += Sectors) 255 { 256 /* Zero some sectors of the FAT */ 257 FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR); 258 259 if ((FATSectors - i) <= Sectors) 260 { 261 Sectors = FATSectors - i; 262 } 263 264 Status = NtWriteFile(FileHandle, 265 NULL, 266 NULL, 267 NULL, 268 &IoStatusBlock, 269 Buffer, 270 Sectors * 512, 271 &FileOffset, 272 NULL); 273 if (!NT_SUCCESS(Status)) 274 { 275 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 276 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 277 return Status; 278 } 279 280 VfatxUpdateProgress(Context, Sectors); 281 } 282 283 /* Free the buffer */ 284 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 285 286 return Status; 287 } 288 289 static NTSTATUS 290 FatxWriteRootDirectory(IN HANDLE FileHandle, 291 IN ULONG FATSectors, 292 IN OUT PFORMAT_CONTEXT Context) 293 { 294 IO_STATUS_BLOCK IoStatusBlock; 295 NTSTATUS Status = STATUS_SUCCESS; 296 PUCHAR Buffer; 297 LARGE_INTEGER FileOffset; 298 ULONG FirstRootDirSector; 299 ULONG RootDirSectors; 300 301 /* Write cluster */ 302 RootDirSectors = 256 * 64 / 512; 303 FirstRootDirSector = sizeof(FATX_BOOT_SECTOR) / 512 + FATSectors; 304 305 DPRINT("RootDirSectors = %lu\n", RootDirSectors); 306 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector); 307 308 /* Allocate buffer for the cluster */ 309 Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 310 0, 311 RootDirSectors * 512); 312 if (Buffer == NULL) 313 return STATUS_INSUFFICIENT_RESOURCES; 314 315 /* Zero the buffer */ 316 memset(Buffer, 0xff, RootDirSectors * 512); 317 318 /* Zero some sectors of the root directory */ 319 FileOffset.QuadPart = FirstRootDirSector * 512; 320 321 Status = NtWriteFile(FileHandle, 322 NULL, 323 NULL, 324 NULL, 325 &IoStatusBlock, 326 Buffer, 327 RootDirSectors * 512, 328 &FileOffset, 329 NULL); 330 if (!NT_SUCCESS(Status)) 331 { 332 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 333 } 334 335 /* Free the buffer */ 336 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 337 338 return Status; 339 } 340 341 342 NTSTATUS 343 FatxFormat(IN HANDLE FileHandle, 344 IN PPARTITION_INFORMATION PartitionInfo, 345 IN PDISK_GEOMETRY DiskGeometry, 346 IN BOOLEAN QuickFormat, 347 IN OUT PFORMAT_CONTEXT Context) 348 { 349 FATX_BOOT_SECTOR BootSector; 350 ULONGLONG SectorCount; 351 ULONG ClusterCount; 352 ULONG RootDirSectors; 353 ULONG FATSectors; 354 NTSTATUS Status; 355 356 SectorCount = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(512); /* Use shifting to avoid 64-bit division */ 357 358 memset(&BootSector, 0, sizeof(FATX_BOOT_SECTOR)); 359 memcpy(&BootSector.SysType[0], "FATX", 4); 360 BootSector.SectorsPerCluster = 32; 361 BootSector.FATCount = 1; 362 BootSector.VolumeID = CalcVolumeSerialNumber(); 363 RootDirSectors = 256 * 64 / 512; 364 365 /* Calculate number of FAT sectors */ 366 ClusterCount = SectorCount >> GetShiftCount(32); 367 368 if (ClusterCount > 65525) 369 { 370 FATSectors = (((ClusterCount * 4) + 4095) & ~4095) >> GetShiftCount(512); 371 } 372 else 373 { 374 FATSectors = (((ClusterCount * 2) + 4095) & ~4095) >> GetShiftCount(512); 375 } 376 DPRINT("FATSectors = %hu\n", FATSectors); 377 378 /* Init context data */ 379 if (QuickFormat) 380 { 381 Context->TotalSectorCount = 382 1 + FATSectors + RootDirSectors; 383 } 384 else 385 { 386 Context->TotalSectorCount = SectorCount; 387 } 388 389 Status = FatxWriteBootSector(FileHandle, 390 &BootSector, 391 Context); 392 if (!NT_SUCCESS(Status)) 393 { 394 DPRINT("FatxWriteBootSector() failed with status 0x%.08x\n", Status); 395 return Status; 396 } 397 398 /* Write first FAT copy */ 399 if (ClusterCount > 65525) 400 { 401 Status = Fatx32WriteFAT(FileHandle, 402 0, 403 FATSectors, 404 Context); 405 } 406 else 407 { 408 Status = Fatx16WriteFAT(FileHandle, 409 0, 410 FATSectors, 411 Context); 412 } 413 414 if (!NT_SUCCESS(Status)) 415 { 416 DPRINT("FatxWriteFAT() failed with status 0x%.08x\n", Status); 417 return Status; 418 } 419 420 Status = FatxWriteRootDirectory(FileHandle, 421 FATSectors, 422 Context); 423 if (!NT_SUCCESS(Status)) 424 { 425 DPRINT("FatxWriteRootDirectory() failed with status 0x%.08x\n", Status); 426 } 427 428 if (!QuickFormat) 429 { 430 /* FIXME: Fill remaining sectors */ 431 } 432 433 return Status; 434 } 435