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 /* Attempt to dismount formatted volume */
255 LockStatus
= NtFsControlFile(FileHandle
,
260 FSCTL_DISMOUNT_VOLUME
,
265 if (!NT_SUCCESS(LockStatus
))
267 DPRINT1("Failed to umount volume (Status: 0x%x)\n", LockStatus
);
271 LockStatus
= NtFsControlFile(FileHandle
,
281 if (!NT_SUCCESS(LockStatus
))
283 DPRINT1("Failed to unlock volume (Status: 0x%x)\n", LockStatus
);
288 if (Callback
!= NULL
)
290 Context
.Success
= (BOOLEAN
)(NT_SUCCESS(Status
));
291 Callback (DONE
, 0, (PVOID
)&Context
.Success
);
294 DPRINT("VfatFormat() done. Status 0x%.08x\n", Status
);
301 UpdateProgress(PFORMAT_CONTEXT Context
,
306 Context
->CurrentSectorCount
+= (ULONGLONG
)Increment
;
309 NewPercent
= (Context
->CurrentSectorCount
* 100ULL) / Context
->TotalSectorCount
;
311 if (NewPercent
> Context
->Percent
)
313 Context
->Percent
= NewPercent
;
314 if (Context
->Callback
!= NULL
)
316 Context
->Callback (PROGRESS
, 0, &Context
->Percent
);
323 VfatPrint(PCHAR Format
, ...)
329 va_start(valist
, Format
);
330 _vsnprintf(TextBuf
, sizeof(TextBuf
), Format
, valist
);
333 /* Prepare parameters */
335 TextOut
.Output
= TextBuf
;
337 /* Do the callback */
339 ChkdskCallback(OUTPUT
, 0, &TextOut
);
345 VfatChkdsk(IN PUNICODE_STRING DriveRoot
,
346 IN BOOLEAN FixErrors
,
348 IN BOOLEAN CheckOnlyIfDirty
,
349 IN BOOLEAN ScanDrive
,
350 IN PFMIFSCALLBACK Callback
)
354 BOOLEAN salvage_files
;
356 //ULONG free_clusters;
359 /* Store callback pointer */
360 ChkdskCallback
= Callback
;
361 FsCheckMemQueue
= NULL
;
366 FsCheckFlags
|= FSCHECK_VERBOSE
;
368 FsCheckTotalFiles
= 0;
372 salvage_files
= TRUE
;
374 /* Open filesystem */
375 fs_open(DriveRoot
,FixErrors
);
377 if (CheckOnlyIfDirty
&& !fs_isdirty())
379 /* No need to check FS */
380 return fs_close(FALSE
);
385 VfatPrint("Starting check/repair pass.\n");
387 while (read_fat(&fs
), scan_root(&fs
))
388 qfree(&FsCheckMemQueue
);
398 free_clusters
= update_free(&fs
);
400 qfree(&FsCheckMemQueue
);
403 VfatPrint("Starting verification pass.\n");
407 qfree(&FsCheckMemQueue
);
414 if (FsCheckFlags
& FSCHECK_INTERACTIVE
)
415 FixErrors
= get_key("yn","Perform changes ? (y/n)") == 'y';
417 VfatPrint("Performing changes.\n");
421 VfatPrint("Leaving file system unchanged.\n");
425 VfatPrint("%wZ: %u files, %lu/%lu clusters\n", DriveRoot
,
426 FsCheckTotalFiles
, fs
.clusters
- free_clusters
, fs
.clusters
);
430 /* Dismount the volume */
433 /* Unlock the volume */
437 /* Close the volume */
438 return fs_close(FixErrors
) ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
440 return STATUS_SUCCESS
;