2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
5 * PURPOSE: Fat12 support
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * EK 05/04-2003 Created
17 GetShiftCount(ULONG Value
)
30 CalcVolumeSerialNumber(VOID
)
32 LARGE_INTEGER SystemTime
;
33 TIME_FIELDS TimeFields
;
37 NtQuerySystemTime (&SystemTime
);
38 RtlTimeToTimeFields (&SystemTime
, &TimeFields
);
40 Buffer
= (PUCHAR
)&Serial
;
41 Buffer
[0] = (UCHAR
)(TimeFields
.Year
& 0xFF) + (UCHAR
)(TimeFields
.Hour
& 0xFF);
42 Buffer
[1] = (UCHAR
)(TimeFields
.Year
>> 8) + (UCHAR
)(TimeFields
.Minute
& 0xFF);
43 Buffer
[2] = (UCHAR
)(TimeFields
.Month
& 0xFF) + (UCHAR
)(TimeFields
.Second
& 0xFF);
44 Buffer
[3] = (UCHAR
)(TimeFields
.Day
& 0xFF) + (UCHAR
)(TimeFields
.Milliseconds
& 0xFF);
51 Fat12WriteBootSector (IN HANDLE FileHandle
,
52 IN PFAT16_BOOT_SECTOR BootSector
,
53 IN OUT PFORMAT_CONTEXT Context
)
55 IO_STATUS_BLOCK IoStatusBlock
;
58 LARGE_INTEGER FileOffset
;
60 /* Allocate buffer for new bootsector */
61 NewBootSector
= (PUCHAR
)RtlAllocateHeap (RtlGetProcessHeap (),
64 if (NewBootSector
== NULL
)
65 return(STATUS_INSUFFICIENT_RESOURCES
);
67 /* Zero the new bootsector */
68 memset(NewBootSector
, 0, SECTORSIZE
);
70 /* Copy FAT16 BPB to new bootsector */
71 memcpy((NewBootSector
+ 3),
72 &BootSector
->OEMName
[0],
73 59); /* FAT16 BPB length (up to (not including) Res2) */
76 FileOffset
.QuadPart
= 0ULL;
77 Status
= NtWriteFile(FileHandle
,
86 if (!NT_SUCCESS(Status
))
88 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
89 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
93 /* Free the new boot sector */
94 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector
);
96 UpdateProgress (Context
, 1);
103 Fat12WriteFAT (IN HANDLE FileHandle
,
104 IN ULONG SectorOffset
,
105 IN PFAT16_BOOT_SECTOR BootSector
,
106 IN OUT PFORMAT_CONTEXT Context
)
108 IO_STATUS_BLOCK IoStatusBlock
;
111 LARGE_INTEGER FileOffset
;
116 /* Allocate buffer */
117 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
121 return(STATUS_INSUFFICIENT_RESOURCES
);
123 /* Zero the buffer */
124 memset(Buffer
, 0, 32 * 1024);
126 /* FAT cluster 0 & 1*/
127 Buffer
[0] = 0xf8; /* Media type */
131 /* Write first sector of the FAT */
132 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
) * BootSector
->BytesPerSector
;
133 Status
= NtWriteFile(FileHandle
,
139 BootSector
->BytesPerSector
,
142 if (!NT_SUCCESS(Status
))
144 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
145 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
149 UpdateProgress (Context
, 1);
151 /* Zero the begin of the buffer */
152 memset(Buffer
, 0, 3);
154 /* Zero the rest of the FAT */
155 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
156 for (i
= 1; i
< (ULONG
)BootSector
->FATSectors
; i
+= Sectors
)
158 /* Zero some sectors of the FAT */
159 FileOffset
.QuadPart
= (SectorOffset
+ BootSector
->ReservedSectors
+ i
) * BootSector
->BytesPerSector
;
160 if (((ULONG
)BootSector
->FATSectors
- i
) <= Sectors
)
162 Sectors
= (ULONG
)BootSector
->FATSectors
- i
;
165 Size
= Sectors
* BootSector
->BytesPerSector
;
166 Status
= NtWriteFile(FileHandle
,
175 if (!NT_SUCCESS(Status
))
177 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
178 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
182 UpdateProgress (Context
, Sectors
);
185 /* Free the buffer */
186 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
193 Fat12WriteRootDirectory (IN HANDLE FileHandle
,
194 IN PFAT16_BOOT_SECTOR BootSector
,
195 IN OUT PFORMAT_CONTEXT Context
)
197 IO_STATUS_BLOCK IoStatusBlock
;
198 NTSTATUS Status
= STATUS_SUCCESS
;
200 LARGE_INTEGER FileOffset
;
201 ULONG FirstRootDirSector
;
202 ULONG RootDirSectors
;
207 DPRINT("BootSector->ReservedSectors = %hu\n", BootSector
->ReservedSectors
);
208 DPRINT("BootSector->FATSectors = %hu\n", BootSector
->FATSectors
);
209 DPRINT("BootSector->SectorsPerCluster = %u\n", BootSector
->SectorsPerCluster
);
212 RootDirSectors
= ((BootSector
->RootEntries
* 32) +
213 (BootSector
->BytesPerSector
- 1)) / BootSector
->BytesPerSector
;
215 BootSector
->ReservedSectors
+ (BootSector
->FATCount
* BootSector
->FATSectors
);
217 DPRINT("RootDirSectors = %lu\n", RootDirSectors
);
218 DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector
);
220 /* Allocate buffer for the cluster */
221 Buffer
= (PUCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
225 return(STATUS_INSUFFICIENT_RESOURCES
);
227 /* Zero the buffer */
228 memset(Buffer
, 0, 32 * 1024);
230 Sectors
= 32 * 1024 / BootSector
->BytesPerSector
;
231 for (i
= 0; i
< RootDirSectors
; i
+= Sectors
)
233 /* Zero some sectors of the root directory */
234 FileOffset
.QuadPart
= (FirstRootDirSector
+ i
) * BootSector
->BytesPerSector
;
236 if ((RootDirSectors
- i
) <= Sectors
)
238 Sectors
= RootDirSectors
- i
;
240 Size
= Sectors
* BootSector
->BytesPerSector
;
242 Status
= NtWriteFile(FileHandle
,
251 if (!NT_SUCCESS(Status
))
253 DPRINT("NtWriteFile() failed (Status %lx)\n", Status
);
254 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
257 UpdateProgress (Context
, Sectors
);
260 /* Free the buffer */
261 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
268 Fat12Format (HANDLE FileHandle
,
269 PPARTITION_INFORMATION PartitionInfo
,
270 PDISK_GEOMETRY DiskGeometry
,
271 PUNICODE_STRING Label
,
274 PFORMAT_CONTEXT Context
)
276 FAT16_BOOT_SECTOR BootSector
;
277 OEM_STRING VolumeLabel
;
279 ULONG RootDirSectors
;
285 /* Calculate cluster size */
286 if (ClusterSize
== 0)
288 /* 4KB Cluster (Harddisk only) */
292 SectorCount
= PartitionInfo
->PartitionLength
.QuadPart
>>
293 GetShiftCount(DiskGeometry
->BytesPerSector
); /* Use shifting to avoid 64-bit division */
295 DPRINT("SectorCount = %lu\n", SectorCount
);
297 memset(&BootSector
, 0, sizeof(FAT16_BOOT_SECTOR
));
298 memcpy(&BootSector
.OEMName
[0], "MSWIN4.1", 8);
299 BootSector
.BytesPerSector
= DiskGeometry
->BytesPerSector
;
300 BootSector
.SectorsPerCluster
= ClusterSize
/ BootSector
.BytesPerSector
;
301 BootSector
.ReservedSectors
= 1;
302 BootSector
.FATCount
= 2;
303 BootSector
.RootEntries
= 512;
304 BootSector
.Sectors
= (SectorCount
< 0x10000) ? (unsigned short)SectorCount
: 0;
305 BootSector
.Media
= 0xf8;
306 BootSector
.FATSectors
= 0; /* Set later. See below. */
307 BootSector
.SectorsPerTrack
= DiskGeometry
->SectorsPerTrack
;
308 BootSector
.Heads
= DiskGeometry
->TracksPerCylinder
;
309 BootSector
.HiddenSectors
= PartitionInfo
->HiddenSectors
;
310 BootSector
.SectorsHuge
= (SectorCount
>= 0x10000) ? (unsigned long)SectorCount
: 0;
311 BootSector
.Drive
= 0xff; /* No BIOS boot drive available */
312 BootSector
.ExtBootSignature
= 0x29;
313 BootSector
.VolumeID
= CalcVolumeSerialNumber();
314 if ((Label
== NULL
) || (Label
->Buffer
== NULL
))
316 memcpy(&BootSector
.VolumeLabel
[0], "NO NAME ", 11);
320 RtlUnicodeStringToOemString(&VolumeLabel
, Label
, TRUE
);
321 memset(&BootSector
.VolumeLabel
[0], ' ', 11);
322 memcpy(&BootSector
.VolumeLabel
[0], VolumeLabel
.Buffer
,
323 VolumeLabel
.Length
< 11 ? VolumeLabel
.Length
: 11);
324 RtlFreeOemString(&VolumeLabel
);
326 memcpy(&BootSector
.SysType
[0], "FAT12 ", 8);
328 RootDirSectors
= ((BootSector
.RootEntries
* 32) +
329 (BootSector
.BytesPerSector
- 1)) / BootSector
.BytesPerSector
;
331 /* Calculate number of FAT sectors */
332 /* ((BootSector.BytesPerSector * 2) / 3) FAT entries (12bit) fit into one sector */
333 TmpVal1
= SectorCount
- (BootSector
.ReservedSectors
+ RootDirSectors
);
334 TmpVal2
= (((BootSector
.BytesPerSector
* 2) / 3) * BootSector
.SectorsPerCluster
) + BootSector
.FATCount
;
335 TmpVal3
= (TmpVal1
+ (TmpVal2
- 1)) / TmpVal2
;
336 BootSector
.FATSectors
= (unsigned short)(TmpVal3
& 0xffff);
338 DPRINT("BootSector.FATSectors = %hx\n", BootSector
.FATSectors
);
340 /* Init context data */
341 Context
->TotalSectorCount
=
342 1 + (BootSector
.FATSectors
* 2) + RootDirSectors
;
344 Status
= Fat12WriteBootSector (FileHandle
,
347 if (!NT_SUCCESS(Status
))
349 DPRINT("Fat12WriteBootSector() failed with status 0x%.08x\n", Status
);
353 /* Write first FAT copy */
354 Status
= Fat12WriteFAT (FileHandle
,
358 if (!NT_SUCCESS(Status
))
360 DPRINT("Fat12WriteFAT() failed with status 0x%.08x\n", Status
);
364 /* Write second FAT copy */
365 Status
= Fat12WriteFAT (FileHandle
,
366 (ULONG
)BootSector
.FATSectors
,
369 if (!NT_SUCCESS(Status
))
371 DPRINT("Fat12WriteFAT() failed with status 0x%.08x.\n", Status
);
375 Status
= Fat12WriteRootDirectory (FileHandle
,
378 if (!NT_SUCCESS(Status
))
380 DPRINT("Fat12WriteRootDirectory() failed with status 0x%.08x\n", Status
);
385 /* FIXME: Fill remaining sectors */