ReactOS 0.4.16-dev-88-ga65b6ae
vfatlib.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VFAT filesystem library
4 * FILE: lib\fslib\vfatlib\vfatlib.c
5 * PURPOSE: Main API
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Aleksey Bragin (aleksey@reactos.org)
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 */
10/* fsck.fat.c - User interface
11
12 Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
13 Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
14 Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
15
16 This program is free software: you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28
29 The complete text of the GNU General Public License
30 can be found in /usr/share/common-licenses/GPL-3 file.
31*/
32
33/* INCLUDES *******************************************************************/
34
35#include "vfatlib.h"
36
37#define NDEBUG
38#include <debug.h>
39
40
41/* GLOBALS & FUNCTIONS ********************************************************/
42
47
51 IN PUNICODE_STRING DriveRoot,
54 IN BOOLEAN BackwardCompatible,
55 IN MEDIA_TYPE MediaType,
58{
60 DISK_GEOMETRY DiskGeometry;
65 NTSTATUS Status, LockStatus;
66
67 DPRINT("VfatFormat(DriveRoot '%wZ')\n", DriveRoot);
68
69 // FIXME:
70 UNREFERENCED_PARAMETER(BackwardCompatible);
71 UNREFERENCED_PARAMETER(MediaType);
72
73 Context.TotalSectorCount = 0;
74 Context.CurrentSectorCount = 0;
75 Context.Callback = Callback;
76 Context.Success = FALSE;
77 Context.Percent = 0;
78
80 DriveRoot,
81 0,
82 NULL,
83 NULL);
84
88 &Iosb,
91 if (!NT_SUCCESS(Status))
92 {
93 DPRINT1("NtOpenFile() failed with status 0x%08x\n", Status);
94 return FALSE;
95 }
96
98 NULL,
99 NULL,
100 NULL,
101 &Iosb,
103 NULL,
104 0,
105 &DiskGeometry,
106 sizeof(DISK_GEOMETRY));
107 if (!NT_SUCCESS(Status))
108 {
109 DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY failed with status 0x%08x\n", Status);
111 return FALSE;
112 }
113
114 if (DiskGeometry.MediaType == FixedMedia)
115 {
116 DPRINT("Cylinders %I64d\n", DiskGeometry.Cylinders.QuadPart);
117 DPRINT("TracksPerCylinder %ld\n", DiskGeometry.TracksPerCylinder);
118 DPRINT("SectorsPerTrack %ld\n", DiskGeometry.SectorsPerTrack);
119 DPRINT("BytesPerSector %ld\n", DiskGeometry.BytesPerSector);
120 DPRINT("DiskSize %I64d\n",
121 DiskGeometry.Cylinders.QuadPart *
122 (ULONGLONG)DiskGeometry.TracksPerCylinder *
123 (ULONGLONG)DiskGeometry.SectorsPerTrack *
124 (ULONGLONG)DiskGeometry.BytesPerSector);
125
127 NULL,
128 NULL,
129 NULL,
130 &Iosb,
132 NULL,
133 0,
135 sizeof(PARTITION_INFORMATION));
136 if (!NT_SUCCESS(Status))
137 {
138 DPRINT("IOCTL_DISK_GET_PARTITION_INFO failed with status 0x%08x\n", Status);
140 return FALSE;
141 }
142 }
143 else
144 {
145 PartitionInfo.PartitionType = 0;
146 PartitionInfo.StartingOffset.QuadPart = 0ULL;
147 PartitionInfo.PartitionLength.QuadPart =
148 DiskGeometry.Cylinders.QuadPart *
149 (ULONGLONG)DiskGeometry.TracksPerCylinder *
150 (ULONGLONG)DiskGeometry.SectorsPerTrack *
151 (ULONGLONG)DiskGeometry.BytesPerSector;
152 PartitionInfo.HiddenSectors = 0;
153 PartitionInfo.PartitionNumber = 0;
154 PartitionInfo.BootIndicator = FALSE;
155 PartitionInfo.RewritePartition = FALSE;
156 PartitionInfo.RecognizedPartition = FALSE;
157 }
158
159 /* If it already has a FAT FS, we'll use that type.
160 * If it doesn't, we will determine the FAT type based on size and offset */
161 if (PartitionInfo.PartitionType != PARTITION_FAT_12 &&
162 PartitionInfo.PartitionType != PARTITION_FAT_16 &&
163 PartitionInfo.PartitionType != PARTITION_HUGE &&
164 PartitionInfo.PartitionType != PARTITION_XINT13 &&
165 PartitionInfo.PartitionType != PARTITION_FAT32 &&
166 PartitionInfo.PartitionType != PARTITION_FAT32_XINT13)
167 {
168 /* Determine the correct type based upon size and offset (copied from usetup) */
169 if (PartitionInfo.PartitionLength.QuadPart < (4200LL * 1024LL))
170 {
171 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
172 PartitionInfo.PartitionType = PARTITION_FAT_12;
173 }
174 else if (PartitionInfo.StartingOffset.QuadPart < (1024LL * 255LL * 63LL * 512LL))
175 {
176 /* Partition starts below the 8.4GB boundary ==> CHS partition */
177
178 if (PartitionInfo.PartitionLength.QuadPart < (32LL * 1024LL * 1024LL))
179 {
180 /* FAT16 CHS partition (partition size < 32MB) */
181 PartitionInfo.PartitionType = PARTITION_FAT_16;
182 }
183 else if (PartitionInfo.PartitionLength.QuadPart < (512LL * 1024LL * 1024LL))
184 {
185 /* FAT16 CHS partition (partition size < 512MB) */
186 PartitionInfo.PartitionType = PARTITION_HUGE;
187 }
188 else
189 {
190 /* FAT32 CHS partition (partition size >= 512MB) */
191 PartitionInfo.PartitionType = PARTITION_FAT32;
192 }
193 }
194 else
195 {
196 /* Partition starts above the 8.4GB boundary ==> LBA partition */
197
198 if (PartitionInfo.PartitionLength.QuadPart < (512LL * 1024LL * 1024LL))
199 {
200 /* FAT16 LBA partition (partition size < 512MB) */
201 PartitionInfo.PartitionType = PARTITION_XINT13;
202 }
203 else
204 {
205 /* FAT32 LBA partition (partition size >= 512MB) */
207 }
208 }
209 }
210
211 DPRINT("PartitionType 0x%x\n", PartitionInfo.PartitionType);
212 DPRINT("StartingOffset %I64d\n", PartitionInfo.StartingOffset.QuadPart);
213 DPRINT("PartitionLength %I64d\n", PartitionInfo.PartitionLength.QuadPart);
214 DPRINT("HiddenSectors %lu\n", PartitionInfo.HiddenSectors);
215 DPRINT("PartitionNumber %d\n", PartitionInfo.PartitionNumber);
216 DPRINT("BootIndicator 0x%x\n", PartitionInfo.BootIndicator);
217 DPRINT("RewritePartition %d\n", PartitionInfo.RewritePartition);
218 DPRINT("RecognizedPartition %d\n", PartitionInfo.RecognizedPartition);
219
220 if (Callback != NULL)
221 {
222 Context.Percent = 0;
223 Callback(PROGRESS, 0, (PVOID)&Context.Percent);
224 }
225
226 LockStatus = NtFsControlFile(FileHandle,
227 NULL,
228 NULL,
229 NULL,
230 &Iosb,
232 NULL,
233 0,
234 NULL,
235 0);
236 if (!NT_SUCCESS(LockStatus))
237 {
238 DPRINT1("WARNING: Failed to lock volume for formatting! Format may fail! (Status: 0x%x)\n", LockStatus);
239 }
240
241 if (PartitionInfo.PartitionType == PARTITION_FAT_12)
242 {
243 /* FAT12 */
246 &DiskGeometry,
247 Label,
250 &Context);
251 }
252 else if (PartitionInfo.PartitionType == PARTITION_FAT_16 ||
253 PartitionInfo.PartitionType == PARTITION_HUGE ||
254 PartitionInfo.PartitionType == PARTITION_XINT13)
255 {
256 /* FAT16 */
259 &DiskGeometry,
260 Label,
263 &Context);
264 }
265 else if (PartitionInfo.PartitionType == PARTITION_FAT32 ||
266 PartitionInfo.PartitionType == PARTITION_FAT32_XINT13)
267 {
268 /* FAT32 */
271 &DiskGeometry,
272 Label,
275 &Context);
276 }
277 else
278 {
280 }
281
282 /* Attempt to dismount formatted volume */
283 LockStatus = NtFsControlFile(FileHandle,
284 NULL,
285 NULL,
286 NULL,
287 &Iosb,
289 NULL,
290 0,
291 NULL,
292 0);
293 if (!NT_SUCCESS(LockStatus))
294 {
295 DPRINT1("Failed to umount volume (Status: 0x%x)\n", LockStatus);
296 }
297
298 LockStatus = NtFsControlFile(FileHandle,
299 NULL,
300 NULL,
301 NULL,
302 &Iosb,
304 NULL,
305 0,
306 NULL,
307 0);
308 if (!NT_SUCCESS(LockStatus))
309 {
310 DPRINT1("Failed to unlock volume (Status: 0x%x)\n", LockStatus);
311 }
312
314
315 DPRINT("VfatFormat() done. Status 0x%08x\n", Status);
316 return NT_SUCCESS(Status);
317}
318
319
320VOID
323{
324 ULONG NewPercent;
325
326 Context->CurrentSectorCount += (ULONGLONG)Increment;
327
328 NewPercent = (Context->CurrentSectorCount * 100ULL) / Context->TotalSectorCount;
329
330 if (NewPercent > Context->Percent)
331 {
332 Context->Percent = NewPercent;
333 if (Context->Callback != NULL)
334 {
335 Context->Callback(PROGRESS, 0, &Context->Percent);
336 }
337 }
338}
339
340
341VOID
343{
345 CHAR TextBuf[512];
346
347 _vsnprintf(TextBuf, sizeof(TextBuf), Format, args);
348
349 /* Prepare parameters */
350 TextOut.Lines = 1;
351 TextOut.Output = TextBuf;
352
353 DPRINT1("VfatPrint -- %s", TextBuf);
354
355 /* Do the callback */
356 if (ChkdskCallback)
358}
359
360
361VOID
363{
365
368 va_end(args);
369}
370
371
373NTAPI
375 IN PUNICODE_STRING DriveRoot,
379 IN BOOLEAN CheckOnlyIfDirty,
380 IN BOOLEAN ScanDrive,
381 IN PVOID pUnknown1,
382 IN PVOID pUnknown2,
383 IN PVOID pUnknown3,
384 IN PVOID pUnknown4,
386{
387 BOOLEAN verify;
388 BOOLEAN salvage_files;
389 ULONG free_clusters;
390 DOS_FS fs;
392
393 UNREFERENCED_PARAMETER(pUnknown1);
394 UNREFERENCED_PARAMETER(pUnknown2);
395 UNREFERENCED_PARAMETER(pUnknown3);
396 UNREFERENCED_PARAMETER(pUnknown4);
397
398 RtlZeroMemory(&fs, sizeof(fs));
399
400 /* Store callback pointer */
403
404 /* Set parameters */
405 FsCheckFlags = 0;
406 if (Verbose)
408 if (FixErrors)
410
412
413 verify = TRUE;
414 salvage_files = TRUE;
415
416 /* Open filesystem and lock it */
419 {
420 /* We failed to lock, ask the caller whether we should continue */
421 if (Callback(VOLUMEINUSE, 0, NULL))
422 {
424 }
425 }
426 if (!NT_SUCCESS(Status))
427 {
430 return FALSE;
431 }
432
433 if (CheckOnlyIfDirty && !fs_isdirty())
434 {
435 /* Unlock volume if required */
437 fs_lock(FALSE);
438
439 /* No need to check FS */
442 return (Status == STATUS_SUCCESS);
443 }
444 else if (CheckOnlyIfDirty && fs_isdirty())
445 {
447 {
450 return FALSE;
451 }
452 }
453
454 read_boot(&fs);
455
456 if (verify)
457 VfatPrint("Starting check/repair pass.\n");
458
459 while (read_fat(&fs), scan_root(&fs))
461
462 if (ScanDrive)
463 fix_bad(&fs);
464
465 if (salvage_files)
467 else
469
470 free_clusters = update_free(&fs);
471 file_unused();
473 if (verify)
474 {
476 VfatPrint("Starting verification pass.\n");
477 read_fat(&fs);
478 scan_root(&fs);
481 }
482
483 if (fs_changed())
484 {
486 {
488 {
489 FixErrors = get_key("yn", "Perform changes ? (y/n)") == 'y';
490 if (FixErrors)
492 else
493 FsCheckFlags &= ~FSCHECK_READ_WRITE;
494 }
495 else
496 VfatPrint("Performing changes.\n");
497 }
498 else
499 {
500 VfatPrint("Leaving filesystem unchanged.\n");
501 }
502 }
503
504 VfatPrint("%wZ: %u files, %lu/%lu clusters\n", DriveRoot,
505 FsCheckTotalFiles, fs.data_clusters - free_clusters, fs.data_clusters);
506
508 {
509 /* Dismount the volume */
510 fs_dismount();
511
512 /* Unlock the volume */
513 fs_lock(FALSE);
514 }
515
516 // https://technet.microsoft.com/en-us/library/cc730714.aspx
517 // https://support.microsoft.com/en-us/kb/265533
518
519 /* Close the volume */
522 return (Status == STATUS_SUCCESS);
523}
524
525/* EOF */
unsigned char BOOLEAN
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
BOOL FixErrors
Definition: chkdsk.c:69
BOOL Verbose
Definition: chkdsk.c:72
BOOL QuickFormat
Definition: format.c:66
PWCHAR Label
Definition: format.c:70
DWORD ClusterSize
Definition: format.c:67
#define PARTITION_XINT13
Definition: disk.h:98
#define PARTITION_FAT32
Definition: disk.h:96
#define PARTITION_FAT_12
Definition: disk.h:88
#define PARTITION_HUGE
Definition: disk.h:93
#define PARTITION_FAT_16
Definition: disk.h:91
#define PARTITION_FAT32_XINT13
Definition: disk.h:97
#define IOCTL_DISK_GET_DRIVE_GEOMETRY
Definition: cdrw_usr.h:169
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define FILE_SHARE_READ
Definition: compat.h:136
return Iosb
Definition: create.c:4402
NTSTATUS Fat12Format(IN HANDLE FileHandle, IN PPARTITION_INFORMATION PartitionInfo, IN PDISK_GEOMETRY DiskGeometry, IN PUNICODE_STRING Label, IN BOOLEAN QuickFormat, IN ULONG ClusterSize, IN OUT PFORMAT_CONTEXT Context)
Definition: fat12.c:239
NTSTATUS Fat16Format(IN HANDLE FileHandle, IN PPARTITION_INFORMATION PartitionInfo, IN PDISK_GEOMETRY DiskGeometry, IN PUNICODE_STRING Label, IN BOOLEAN QuickFormat, IN ULONG ClusterSize, IN OUT PFORMAT_CONTEXT Context)
Definition: fat16.c:238
NTSTATUS Fat32Format(IN HANDLE FileHandle, IN PPARTITION_INFORMATION PartitionInfo, IN PDISK_GEOMETRY DiskGeometry, IN PUNICODE_STRING Label, IN BOOLEAN QuickFormat, IN ULONG ClusterSize, IN OUT PFORMAT_CONTEXT Context)
Definition: fat32.c:386
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:46
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
@ OUTPUT
Definition: fmifs.h:82
@ VOLUMEINUSE
Definition: fmifs.h:76
@ PROGRESS
Definition: fmifs.h:68
BOOLEAN(NTAPI * PFMIFSCALLBACK)(IN CALLBACKCOMMAND Command, IN ULONG SubAction, IN PVOID ActionInfo)
Definition: fmifs.h:89
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
int scan_root(DOS_FS *fs)
Definition: check.c:1232
Status
Definition: gdiplustypes.h:25
#define fs
Definition: i386-dis.c:444
if(dx< 0)
Definition: linetemp.h:194
#define ULL(a, b)
Definition: format_msg.c:27
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
_In_ NTSTATUS ExitStatus
Definition: psfuncs.h:867
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3952
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FSCTL_LOCK_VOLUME
Definition: nt_native.h:832
NTSYSAPI NTSTATUS NTAPI NtDeviceIoControlFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG DeviceIoControlCode, IN PVOID InBuffer OPTIONAL, IN ULONG InBufferLength, OUT PVOID OutBuffer OPTIONAL, IN ULONG OutBufferLength)
#define FSCTL_UNLOCK_VOLUME
Definition: nt_native.h:833
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define FSCTL_DISMOUNT_VOLUME
Definition: nt_native.h:834
NTSYSAPI NTSTATUS NTAPI NtFsControlFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG DeviceIoControlCode, IN PVOID InBuffer OPTIONAL, IN ULONG InBufferLength, OUT PVOID OutBuffer OPTIONAL, IN ULONG OutBufferLength)
#define FILE_GENERIC_READ
Definition: nt_native.h:653
#define FILE_GENERIC_WRITE
Definition: nt_native.h:660
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
enum _MEDIA_TYPE MEDIA_TYPE
@ FixedMedia
Definition: ntdddisk.h:383
#define IOCTL_DISK_GET_PARTITION_INFO
Definition: ntdddisk.h:106
#define FSCHECK_VERBOSE
Definition: rosglue.h:25
#define FSCHECK_READ_WRITE
Definition: rosglue.h:27
#define FSCHECK_INTERACTIVE
Definition: rosglue.h:23
void read_boot(DOS_FS *fs)
Definition: boot.c:334
void qfree(void **root)
Definition: common.c:157
char get_key(const char *valid, const char *prompt)
Definition: common.c:184
void fix_bad(DOS_FS *fs)
Definition: fat.c:322
void reclaim_free(DOS_FS *fs)
Definition: fat.c:340
uint32_t update_free(DOS_FS *fs)
Definition: fat.c:531
void read_fat(DOS_FS *fs)
Definition: fat.c:81
void reclaim_file(DOS_FS *fs)
Definition: fat.c:426
void file_unused(void)
Definition: file.c:269
int fs_changed(void)
Definition: io.c:475
int fs_close(int write)
Definition: io.c:455
void fs_open(char *path, int rw)
Definition: io.c:163
#define args
Definition: format.c:66
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
MEDIA_TYPE MediaType
Definition: ntdddisk.h:401
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:400
ULONG TracksPerCylinder
Definition: ntdddisk.h:402
ULONG SectorsPerTrack
Definition: ntdddisk.h:403
ULONG BytesPerSector
Definition: ntdddisk.h:404
Definition: match.c:390
Definition: ffs.h:70
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
char * PCHAR
Definition: typedefs.h:51
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_DISK_CORRUPT_ERROR
Definition: udferr_usr.h:147
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG FsCheckFlags
Definition: vfatlib.c:44
PFMIFSCALLBACK ChkdskCallback
Definition: vfatlib.c:43
BOOLEAN NTAPI VfatChkdsk(IN PUNICODE_STRING DriveRoot, IN PFMIFSCALLBACK Callback, IN BOOLEAN FixErrors, IN BOOLEAN Verbose, IN BOOLEAN CheckOnlyIfDirty, IN BOOLEAN ScanDrive, IN PVOID pUnknown1, IN PVOID pUnknown2, IN PVOID pUnknown3, IN PVOID pUnknown4, IN PULONG ExitStatus)
Definition: vfatlib.c:374
VOID VfatPrint(PCHAR Format,...)
Definition: vfatlib.c:362
PVOID FsCheckMemQueue
Definition: vfatlib.c:45
ULONG FsCheckTotalFiles
Definition: vfatlib.c:46
VOID UpdateProgress(PFORMAT_CONTEXT Context, ULONG Increment)
Definition: vfatlib.c:321
BOOLEAN NTAPI VfatFormat(IN PUNICODE_STRING DriveRoot, IN PFMIFSCALLBACK Callback, IN BOOLEAN QuickFormat, IN BOOLEAN BackwardCompatible, IN MEDIA_TYPE MediaType, IN PUNICODE_STRING Label, IN ULONG ClusterSize)
Definition: vfatlib.c:50
VOID VfatPrintV(PCHAR Format, va_list args)
Definition: vfatlib.c:342
_In_ WDFINTERRUPT _In_ PFN_WDF_INTERRUPT_SYNCHRONIZE Callback
Definition: wdfinterrupt.h:458
#define TextOut
Definition: wingdi.h:4483
_In_ ULONG _In_ struct _SET_PARTITION_INFORMATION_EX * PartitionInfo
Definition: iofuncs.h:2105
#define _vsnprintf
Definition: xmlstorage.h:202
char CHAR
Definition: xmlstorage.h:175