2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
4 * FILE: lib\fslib\vfatlib\vfatlib.c
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 05/04-2003 Created
15 PFMIFSCALLBACK ChkdskCallback
= NULL
;
16 PVOID FsCheckMemQueue
;
18 ULONG FsCheckTotalFiles
;
22 VfatFormat(IN PUNICODE_STRING DriveRoot
,
23 IN FMIFS_MEDIA_FLAG MediaFlag
,
24 IN PUNICODE_STRING Label
,
25 IN BOOLEAN QuickFormat
,
27 IN PFMIFSCALLBACK Callback
)
29 OBJECT_ATTRIBUTES ObjectAttributes
;
30 DISK_GEOMETRY DiskGeometry
;
33 PARTITION_INFORMATION PartitionInfo
;
34 FORMAT_CONTEXT Context
;
35 NTSTATUS Status
, LockStatus
;
37 DPRINT("VfatFormat(DriveRoot '%wZ')\n", DriveRoot
);
39 Context
.TotalSectorCount
= 0;
40 Context
.CurrentSectorCount
= 0;
41 Context
.Callback
= Callback
;
42 Context
.Success
= FALSE
;
45 InitializeObjectAttributes(&ObjectAttributes
,
51 Status
= NtOpenFile(&FileHandle
,
52 FILE_GENERIC_READ
| FILE_GENERIC_WRITE
,
56 FILE_SYNCHRONOUS_IO_ALERT
);
57 if (!NT_SUCCESS(Status
))
59 DPRINT1("NtOpenFile() failed with status 0x%.08x\n", Status
);
63 Status
= NtDeviceIoControlFile(FileHandle
,
68 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
72 sizeof(DISK_GEOMETRY
));
73 if (!NT_SUCCESS(Status
))
75 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY failed with status 0x%.08x\n", Status
);
80 if (DiskGeometry
.MediaType
== FixedMedia
)
82 DPRINT("Cylinders %I64d\n", DiskGeometry
.Cylinders
.QuadPart
);
83 DPRINT("TracksPerCylinder %ld\n", DiskGeometry
.TracksPerCylinder
);
84 DPRINT("SectorsPerTrack %ld\n", DiskGeometry
.SectorsPerTrack
);
85 DPRINT("BytesPerSector %ld\n", DiskGeometry
.BytesPerSector
);
86 DPRINT("DiskSize %I64d\n",
87 DiskGeometry
.Cylinders
.QuadPart
*
88 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
89 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
*
90 (ULONGLONG
)DiskGeometry
.BytesPerSector
);
92 Status
= NtDeviceIoControlFile(FileHandle
,
97 IOCTL_DISK_GET_PARTITION_INFO
,
101 sizeof(PARTITION_INFORMATION
));
102 if (!NT_SUCCESS(Status
))
104 DPRINT("IOCTL_DISK_GET_PARTITION_INFO failed with status 0x%.08x\n", Status
);
110 * FIXME: This is a hack!
111 * Partitioning software MUST set the correct number of hidden sectors!
113 PartitionInfo
.HiddenSectors
= DiskGeometry
.SectorsPerTrack
;
117 PartitionInfo
.PartitionType
= 0;
118 PartitionInfo
.StartingOffset
.QuadPart
= 0ULL;
119 PartitionInfo
.PartitionLength
.QuadPart
=
120 DiskGeometry
.Cylinders
.QuadPart
*
121 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
122 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
*
123 (ULONGLONG
)DiskGeometry
.BytesPerSector
;
124 PartitionInfo
.HiddenSectors
= 0;
125 PartitionInfo
.PartitionNumber
= 0;
126 PartitionInfo
.BootIndicator
= FALSE
;
127 PartitionInfo
.RewritePartition
= FALSE
;
128 PartitionInfo
.RecognizedPartition
= FALSE
;
131 /* If it already has a FAT FS, we'll use that type.
132 * If it doesn't, we will determine the FAT type based on size and offset */
133 if (PartitionInfo
.PartitionType
!= PARTITION_FAT_12
&&
134 PartitionInfo
.PartitionType
!= PARTITION_FAT_16
&&
135 PartitionInfo
.PartitionType
!= PARTITION_HUGE
&&
136 PartitionInfo
.PartitionType
!= PARTITION_XINT13
&&
137 PartitionInfo
.PartitionType
!= PARTITION_FAT32
&&
138 PartitionInfo
.PartitionType
!= PARTITION_FAT32_XINT13
)
140 /* Determine the correct type based upon size and offset (copied from usetup) */
141 if (PartitionInfo
.PartitionLength
.QuadPart
< (4200LL * 1024LL))
143 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
144 PartitionInfo
.PartitionType
= PARTITION_FAT_12
;
146 else if (PartitionInfo
.StartingOffset
.QuadPart
< (1024LL * 255LL * 63LL * 512LL))
148 /* Partition starts below the 8.4GB boundary ==> CHS partition */
150 if (PartitionInfo
.PartitionLength
.QuadPart
< (32LL * 1024LL * 1024LL))
152 /* FAT16 CHS partition (partiton size < 32MB) */
153 PartitionInfo
.PartitionType
= PARTITION_FAT_16
;
155 else if (PartitionInfo
.PartitionLength
.QuadPart
< (512LL * 1024LL * 1024LL))
157 /* FAT16 CHS partition (partition size < 512MB) */
158 PartitionInfo
.PartitionType
= PARTITION_HUGE
;
162 /* FAT32 CHS partition (partition size >= 512MB) */
163 PartitionInfo
.PartitionType
= PARTITION_FAT32
;
168 /* Partition starts above the 8.4GB boundary ==> LBA partition */
170 if (PartitionInfo
.PartitionLength
.QuadPart
< (512LL * 1024LL * 1024LL))
172 /* FAT16 LBA partition (partition size < 512MB) */
173 PartitionInfo
.PartitionType
= PARTITION_XINT13
;
177 /* FAT32 LBA partition (partition size >= 512MB) */
178 PartitionInfo
.PartitionType
= PARTITION_FAT32_XINT13
;
183 DPRINT("PartitionType 0x%x\n", PartitionInfo
.PartitionType
);
184 DPRINT("StartingOffset %I64d\n", PartitionInfo
.StartingOffset
.QuadPart
);
185 DPRINT("PartitionLength %I64d\n", PartitionInfo
.PartitionLength
.QuadPart
);
186 DPRINT("HiddenSectors %lu\n", PartitionInfo
.HiddenSectors
);
187 DPRINT("PartitionNumber %d\n", PartitionInfo
.PartitionNumber
);
188 DPRINT("BootIndicator 0x%x\n", PartitionInfo
.BootIndicator
);
189 DPRINT("RewritePartition %d\n", PartitionInfo
.RewritePartition
);
190 DPRINT("RecognizedPartition %d\n", PartitionInfo
.RecognizedPartition
);
192 if (Callback
!= NULL
)
195 Callback (PROGRESS
, 0, (PVOID
)&Context
.Percent
);
198 LockStatus
= NtFsControlFile(FileHandle
,
208 if (!NT_SUCCESS(LockStatus
))
210 DPRINT1("WARNING: Failed to lock volume for formatting! Format may fail! (Status: 0x%x)\n", LockStatus
);
213 if (PartitionInfo
.PartitionType
== PARTITION_FAT_12
)
216 Status
= Fat12Format(FileHandle
,
224 else if (PartitionInfo
.PartitionType
== PARTITION_FAT_16
||
225 PartitionInfo
.PartitionType
== PARTITION_HUGE
||
226 PartitionInfo
.PartitionType
== PARTITION_XINT13
)
229 Status
= Fat16Format(FileHandle
,
237 else if (PartitionInfo
.PartitionType
== PARTITION_FAT32
||
238 PartitionInfo
.PartitionType
== PARTITION_FAT32_XINT13
)
241 Status
= Fat32Format(FileHandle
,
251 Status
= STATUS_INVALID_PARAMETER
;
254 LockStatus
= NtFsControlFile(FileHandle
,
264 if (!NT_SUCCESS(LockStatus
))
266 DPRINT1("Failed to unlock volume (Status: 0x%x)\n", LockStatus
);
271 if (Callback
!= NULL
)
273 Context
.Success
= (BOOLEAN
)(NT_SUCCESS(Status
));
274 Callback (DONE
, 0, (PVOID
)&Context
.Success
);
277 DPRINT("VfatFormat() done. Status 0x%.08x\n", Status
);
284 UpdateProgress(PFORMAT_CONTEXT Context
,
289 Context
->CurrentSectorCount
+= (ULONGLONG
)Increment
;
292 NewPercent
= (Context
->CurrentSectorCount
* 100ULL) / Context
->TotalSectorCount
;
294 if (NewPercent
> Context
->Percent
)
296 Context
->Percent
= NewPercent
;
297 if (Context
->Callback
!= NULL
)
299 Context
->Callback (PROGRESS
, 0, &Context
->Percent
);
306 VfatPrint(PCHAR Format
, ...)
312 va_start(valist
, Format
);
313 _vsnprintf(TextBuf
, sizeof(TextBuf
), Format
, valist
);
316 /* Prepare parameters */
318 TextOut
.Output
= TextBuf
;
320 /* Do the callback */
322 ChkdskCallback(OUTPUT
, 0, &TextOut
);
328 VfatChkdsk(IN PUNICODE_STRING DriveRoot
,
329 IN BOOLEAN FixErrors
,
331 IN BOOLEAN CheckOnlyIfDirty
,
332 IN BOOLEAN ScanDrive
,
333 IN PFMIFSCALLBACK Callback
)
337 BOOLEAN salvage_files
;
339 //ULONG free_clusters;
342 /* Store callback pointer */
343 ChkdskCallback
= Callback
;
344 FsCheckMemQueue
= NULL
;
349 FsCheckFlags
|= FSCHECK_VERBOSE
;
351 FsCheckTotalFiles
= 0;
355 salvage_files
= TRUE
;
357 /* Open filesystem */
358 fs_open(DriveRoot
,FixErrors
);
360 if (CheckOnlyIfDirty
&& !fs_isdirty())
362 /* No need to check FS */
363 return fs_close(FALSE
);
368 VfatPrint("Starting check/repair pass.\n");
370 while (read_fat(&fs
), scan_root(&fs
))
371 qfree(&FsCheckMemQueue
);
381 free_clusters
= update_free(&fs
);
383 qfree(&FsCheckMemQueue
);
386 VfatPrint("Starting verification pass.\n");
390 qfree(&FsCheckMemQueue
);
397 if (FsCheckFlags
& FSCHECK_INTERACTIVE
)
398 FixErrors
= get_key("yn","Perform changes ? (y/n)") == 'y';
400 VfatPrint("Performing changes.\n");
404 VfatPrint("Leaving file system unchanged.\n");
408 VfatPrint("%wZ: %u files, %lu/%lu clusters\n", DriveRoot
,
409 FsCheckTotalFiles
, fs
.clusters
- free_clusters
, fs
.clusters
);
413 /* Dismount the volume */
416 /* Unlock the volume */
420 /* Close the volume */
421 return fs_close(FixErrors
) ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
423 return STATUS_SUCCESS
;