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
;
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 DPRINT("PartitionType 0x%x\n", PartitionInfo
.PartitionType
);
132 DPRINT("StartingOffset %I64d\n", PartitionInfo
.StartingOffset
.QuadPart
);
133 DPRINT("PartitionLength %I64d\n", PartitionInfo
.PartitionLength
.QuadPart
);
134 DPRINT("HiddenSectors %lu\n", PartitionInfo
.HiddenSectors
);
135 DPRINT("PartitionNumber %d\n", PartitionInfo
.PartitionNumber
);
136 DPRINT("BootIndicator 0x%x\n", PartitionInfo
.BootIndicator
);
137 DPRINT("RewritePartition %d\n", PartitionInfo
.RewritePartition
);
138 DPRINT("RecognizedPartition %d\n", PartitionInfo
.RecognizedPartition
);
140 if (Callback
!= NULL
)
143 Callback (PROGRESS
, 0, (PVOID
)&Context
.Percent
);
146 if (PartitionInfo
.PartitionType
== PARTITION_FAT_12
)
149 Status
= Fat12Format(FileHandle
,
157 else if (PartitionInfo
.PartitionType
== PARTITION_FAT_16
||
158 PartitionInfo
.PartitionType
== PARTITION_HUGE
||
159 PartitionInfo
.PartitionType
== PARTITION_XINT13
)
162 Status
= Fat16Format(FileHandle
,
170 else if (PartitionInfo
.PartitionType
== PARTITION_FAT32
||
171 PartitionInfo
.PartitionType
== PARTITION_FAT32_XINT13
)
174 Status
= Fat32Format(FileHandle
,
184 Status
= STATUS_INVALID_PARAMETER
;
189 if (Callback
!= NULL
)
191 Context
.Success
= (BOOLEAN
)(NT_SUCCESS(Status
));
192 Callback (DONE
, 0, (PVOID
)&Context
.Success
);
195 DPRINT("VfatFormat() done. Status 0x%.08x\n", Status
);
202 UpdateProgress(PFORMAT_CONTEXT Context
,
207 Context
->CurrentSectorCount
+= (ULONGLONG
)Increment
;
210 NewPercent
= (Context
->CurrentSectorCount
* 100ULL) / Context
->TotalSectorCount
;
212 if (NewPercent
> Context
->Percent
)
214 Context
->Percent
= NewPercent
;
215 Context
->Callback (PROGRESS
, 0, &Context
->Percent
);
221 VfatPrint(PCHAR Format
, ...)
227 va_start(valist
, Format
);
228 _vsnprintf(TextBuf
, sizeof(TextBuf
), Format
, valist
);
231 /* Prepare parameters */
233 TextOut
.Output
= TextBuf
;
235 /* Do the callback */
237 ChkdskCallback(OUTPUT
, 0, &TextOut
);
243 VfatChkdsk(IN PUNICODE_STRING DriveRoot
,
244 IN BOOLEAN FixErrors
,
246 IN BOOLEAN CheckOnlyIfDirty
,
247 IN BOOLEAN ScanDrive
,
248 IN PFMIFSCALLBACK Callback
)
250 BOOLEAN verify
, salvage_files
;
251 //ULONG free_clusters;
254 /* Store callback pointer */
255 ChkdskCallback
= Callback
;
256 FsCheckMemQueue
= NULL
;
261 FsCheckFlags
|= FSCHECK_VERBOSE
;
263 FsCheckTotalFiles
= 0;
266 salvage_files
= TRUE
;
268 /* Open filesystem */
269 fs_open(DriveRoot
,FixErrors
);
271 if (CheckOnlyIfDirty
&& !fs_isdirty())
273 /* No need to check FS */
274 return fs_close(FALSE
);
279 VfatPrint("Starting check/repair pass.\n");
281 while (read_fat(&fs
), scan_root(&fs
))
282 qfree(&FsCheckMemQueue
);
292 free_clusters
= update_free(&fs
);
294 qfree(&FsCheckMemQueue
);
297 VfatPrint("Starting verification pass.\n");
301 qfree(&FsCheckMemQueue
);
308 if (FsCheckFlags
& FSCHECK_INTERACTIVE
)
309 FixErrors
= get_key("yn","Perform changes ? (y/n)") == 'y';
311 VfatPrint("Performing changes.\n");
315 VfatPrint("Leaving file system unchanged.\n");
319 VfatPrint("%wZ: %u files, %lu/%lu clusters\n", DriveRoot
,
320 FsCheckTotalFiles
, fs
.clusters
- free_clusters
, fs
.clusters
);
324 /* Dismount the volume */
327 /* Unlock the volume */
331 /* Close the volume */
332 return fs_close(FixErrors
) ? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
334 return STATUS_SUCCESS
;