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
);
111 PartitionInfo
.PartitionType
= 0;
112 PartitionInfo
.StartingOffset
.QuadPart
= 0ULL;
113 PartitionInfo
.PartitionLength
.QuadPart
=
114 DiskGeometry
.Cylinders
.QuadPart
*
115 (ULONGLONG
)DiskGeometry
.TracksPerCylinder
*
116 (ULONGLONG
)DiskGeometry
.SectorsPerTrack
*
117 (ULONGLONG
)DiskGeometry
.BytesPerSector
;
118 PartitionInfo
.HiddenSectors
= 0;
119 PartitionInfo
.PartitionNumber
= 0;
120 PartitionInfo
.BootIndicator
= FALSE
;
121 PartitionInfo
.RewritePartition
= FALSE
;
122 PartitionInfo
.RecognizedPartition
= FALSE
;
125 /* If it already has a FAT FS, we'll use that type.
126 * If it doesn't, we will determine the FAT type based on size and offset */
127 if (PartitionInfo
.PartitionType
!= PARTITION_FAT_12
&&
128 PartitionInfo
.PartitionType
!= PARTITION_FAT_16
&&
129 PartitionInfo
.PartitionType
!= PARTITION_HUGE
&&
130 PartitionInfo
.PartitionType
!= PARTITION_XINT13
&&
131 PartitionInfo
.PartitionType
!= PARTITION_FAT32
&&
132 PartitionInfo
.PartitionType
!= PARTITION_FAT32_XINT13
)
134 /* Determine the correct type based upon size and offset (copied from usetup) */
135 if (PartitionInfo
.PartitionLength
.QuadPart
< (4200LL * 1024LL))
137 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
138 PartitionInfo
.PartitionType
= PARTITION_FAT_12
;
140 else if (PartitionInfo
.StartingOffset
.QuadPart
< (1024LL * 255LL * 63LL * 512LL))
142 /* Partition starts below the 8.4GB boundary ==> CHS partition */
144 if (PartitionInfo
.PartitionLength
.QuadPart
< (32LL * 1024LL * 1024LL))
146 /* FAT16 CHS partition (partiton size < 32MB) */
147 PartitionInfo
.PartitionType
= PARTITION_FAT_16
;
149 else if (PartitionInfo
.PartitionLength
.QuadPart
< (512LL * 1024LL * 1024LL))
151 /* FAT16 CHS partition (partition size < 512MB) */
152 PartitionInfo
.PartitionType
= PARTITION_HUGE
;
156 /* FAT32 CHS partition (partition size >= 512MB) */
157 PartitionInfo
.PartitionType
= PARTITION_FAT32
;
162 /* Partition starts above the 8.4GB boundary ==> LBA partition */
164 if (PartitionInfo
.PartitionLength
.QuadPart
< (512LL * 1024LL * 1024LL))
166 /* FAT16 LBA partition (partition size < 512MB) */
167 PartitionInfo
.PartitionType
= PARTITION_XINT13
;
171 /* FAT32 LBA partition (partition size >= 512MB) */
172 PartitionInfo
.PartitionType
= PARTITION_FAT32_XINT13
;
177 DPRINT("PartitionType 0x%x\n", PartitionInfo
.PartitionType
);
178 DPRINT("StartingOffset %I64d\n", PartitionInfo
.StartingOffset
.QuadPart
);
179 DPRINT("PartitionLength %I64d\n", PartitionInfo
.PartitionLength
.QuadPart
);
180 DPRINT("HiddenSectors %lu\n", PartitionInfo
.HiddenSectors
);
181 DPRINT("PartitionNumber %d\n", PartitionInfo
.PartitionNumber
);
182 DPRINT("BootIndicator 0x%x\n", PartitionInfo
.BootIndicator
);
183 DPRINT("RewritePartition %d\n", PartitionInfo
.RewritePartition
);
184 DPRINT("RecognizedPartition %d\n", PartitionInfo
.RecognizedPartition
);
186 if (Callback
!= NULL
)
189 Callback (PROGRESS
, 0, (PVOID
)&Context
.Percent
);
192 LockStatus
= NtFsControlFile(FileHandle
,
202 if (!NT_SUCCESS(LockStatus
))
204 DPRINT1("WARNING: Failed to lock volume for formatting! Format may fail! (Status: 0x%x)\n", LockStatus
);
207 if (PartitionInfo
.PartitionType
== PARTITION_FAT_12
)
210 Status
= Fat12Format(FileHandle
,
218 else if (PartitionInfo
.PartitionType
== PARTITION_FAT_16
||
219 PartitionInfo
.PartitionType
== PARTITION_HUGE
||
220 PartitionInfo
.PartitionType
== PARTITION_XINT13
)
223 Status
= Fat16Format(FileHandle
,
231 else if (PartitionInfo
.PartitionType
== PARTITION_FAT32
||
232 PartitionInfo
.PartitionType
== PARTITION_FAT32_XINT13
)
235 Status
= Fat32Format(FileHandle
,
245 Status
= STATUS_INVALID_PARAMETER
;
248 /* Attempt to dismount formatted volume */
249 LockStatus
= NtFsControlFile(FileHandle
,
254 FSCTL_DISMOUNT_VOLUME
,
259 if (!NT_SUCCESS(LockStatus
))
261 DPRINT1("Failed to umount volume (Status: 0x%x)\n", LockStatus
);
265 LockStatus
= NtFsControlFile(FileHandle
,
275 if (!NT_SUCCESS(LockStatus
))
277 DPRINT1("Failed to unlock volume (Status: 0x%x)\n", LockStatus
);
282 if (Callback
!= NULL
)
284 Context
.Success
= (BOOLEAN
)(NT_SUCCESS(Status
));
285 Callback (DONE
, 0, (PVOID
)&Context
.Success
);
288 DPRINT("VfatFormat() done. Status 0x%.08x\n", Status
);
295 UpdateProgress(PFORMAT_CONTEXT Context
,
300 Context
->CurrentSectorCount
+= (ULONGLONG
)Increment
;
303 NewPercent
= (Context
->CurrentSectorCount
* 100ULL) / Context
->TotalSectorCount
;
305 if (NewPercent
> Context
->Percent
)
307 Context
->Percent
= NewPercent
;
308 if (Context
->Callback
!= NULL
)
310 Context
->Callback (PROGRESS
, 0, &Context
->Percent
);
317 VfatPrint(PCHAR Format
, ...)
323 va_start(valist
, Format
);
324 _vsnprintf(TextBuf
, sizeof(TextBuf
), Format
, valist
);
327 /* Prepare parameters */
329 TextOut
.Output
= TextBuf
;
331 /* Do the callback */
333 ChkdskCallback(OUTPUT
, 0, &TextOut
);
339 VfatChkdsk(IN PUNICODE_STRING DriveRoot
,
340 IN BOOLEAN FixErrors
,
342 IN BOOLEAN CheckOnlyIfDirty
,
343 IN BOOLEAN ScanDrive
,
344 IN PFMIFSCALLBACK Callback
)
348 BOOLEAN salvage_files
;
350 //ULONG free_clusters;
353 /* Store callback pointer */
354 ChkdskCallback
= Callback
;
355 FsCheckMemQueue
= NULL
;
360 FsCheckFlags
|= FSCHECK_VERBOSE
;
362 FsCheckTotalFiles
= 0;
366 salvage_files
= TRUE
;
368 /* Open filesystem */
369 fs_open(DriveRoot
,FixErrors
);
371 if (CheckOnlyIfDirty
&& !fs_isdirty())
373 /* No need to check FS */
374 return fs_close(FALSE
);
379 VfatPrint("Starting check/repair pass.\n");
381 while (read_fat(&fs
), scan_root(&fs
))
382 qfree(&FsCheckMemQueue
);
392 free_clusters
= update_free(&fs
);
394 qfree(&FsCheckMemQueue
);
397 VfatPrint("Starting verification pass.\n");
401 qfree(&FsCheckMemQueue
);
408 if (FsCheckFlags
& FSCHECK_INTERACTIVE
)
409 FixErrors
= get_key("yn","Perform changes ? (y/n)") == 'y';
411 VfatPrint("Performing changes.\n");
415 VfatPrint("Leaving file system unchanged.\n");
419 VfatPrint("%wZ: %u files, %lu/%lu clusters\n", DriveRoot
,
420 FsCheckTotalFiles
, fs
.clusters
- free_clusters
, fs
.clusters
);
424 /* Dismount the volume */
427 /* Unlock the volume */
431 /* Close the volume */
432 return fs_close(FixErrors
) ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
434 return STATUS_SUCCESS
;