https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3b6faba11a0d0593cd03e…
commit 3b6faba11a0d0593cd03e036fde79d7e0fb7bec9
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sun Jul 29 16:00:49 2018 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sun Jul 29 16:21:09 2018 +0200
[AUTOCHK] Improvements: code + command-line handling.
- Add support for the following command-line arguments: /k, /p (and a little bit
of /r), and add support for checking a particular volume.
A description of these arguments can be found at:
"Description of Enhanced Chkdsk, Autochk, and Chkntfs Tools in Windows
2000",
https://web.archive.org/web/20150215210228/http://support.microsoft.com:80/…
- Slightly improve some messages.
- Get rid of legacy OpenDirectory() and simplify GetFileSystem().
---
base/system/autochk/autochk.c | 317 ++++++++++++++++++++++++++++--------------
1 file changed, 212 insertions(+), 105 deletions(-)
diff --git a/base/system/autochk/autochk.c b/base/system/autochk/autochk.c
index fb8239b3c9..72b010f8d8 100644
--- a/base/system/autochk/autochk.c
+++ b/base/system/autochk/autochk.c
@@ -124,57 +124,6 @@ EraseLine(
NtDisplayString(&UnicodeString);
}
-// this func is taken from kernel32/file/volume.c
-static HANDLE
-OpenDirectory(
- IN LPCWSTR DirName,
- IN BOOLEAN Write)
-{
- UNICODE_STRING NtPathU;
- OBJECT_ATTRIBUTES ObjectAttributes;
- NTSTATUS Status;
- IO_STATUS_BLOCK IoStatusBlock;
- HANDLE hFile;
-
- if (!RtlDosPathNameToNtPathName_U(DirName,
- &NtPathU,
- NULL,
- NULL))
- {
- DPRINT1("Invalid path!\n");
- return INVALID_HANDLE_VALUE;
- }
-
- InitializeObjectAttributes(
- &ObjectAttributes,
- &NtPathU,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
-
- Status = NtCreateFile(
- &hFile,
- Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
- &ObjectAttributes,
- &IoStatusBlock,
- NULL,
- 0,
- FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_OPEN,
- 0,
- NULL,
- 0);
-
- RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
-
- if (!NT_SUCCESS(Status))
- {
- return INVALID_HANDLE_VALUE;
- }
-
- return hFile;
-}
-
static NTSTATUS
OpenKeyboard(
OUT PHANDLE KeyboardHandle)
@@ -279,21 +228,42 @@ WaitForKeyboard(
static NTSTATUS
GetFileSystem(
- IN LPCWSTR Drive,
- IN OUT LPWSTR FileSystemName,
+ IN PUNICODE_STRING VolumePathU,
+ IN OUT PWSTR FileSystemName,
IN SIZE_T FileSystemNameSize)
{
- HANDLE FileHandle;
NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE FileHandle;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
UCHAR Buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
- FileHandle = OpenDirectory(Drive, FALSE);
- if (FileHandle == INVALID_HANDLE_VALUE)
- return STATUS_INVALID_PARAMETER;
+ InitializeObjectAttributes(&ObjectAttributes,
+ VolumePathU,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtCreateFile(&FileHandle,
+ FILE_GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0,
+ NULL,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("Could not open volume '%wZ' to obtain its file system,
Status 0x%08lx\n",
+ VolumePathU, Status);
+ return Status;
+ }
Status = NtQueryVolumeInformationFile(FileHandle,
&IoStatusBlock,
@@ -308,7 +278,7 @@ GetFileSystem(
return Status;
}
- if (FileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength
+ sizeof(WCHAR))
+ if (FileSystemNameSize >= FileFsAttribute->FileSystemNameLength +
sizeof(WCHAR))
{
RtlCopyMemory(FileSystemName,
FileFsAttribute->FileSystemName,
@@ -421,32 +391,46 @@ ChkdskCallback(
static NTSTATUS
CheckVolume(
- IN PWCHAR DrivePath,
- IN LONG TimeOut)
+ IN PCWSTR VolumePath,
+ IN LONG TimeOut,
+ IN BOOLEAN CheckOnlyIfDirty)
{
- WCHAR FileSystem[128];
- WCHAR NtDrivePath[64];
- UNICODE_STRING DrivePathU;
NTSTATUS Status;
- DWORD Count;
+ PCWSTR DisplayName;
+ UNICODE_STRING VolumePathU;
+ ULONG Count;
+ WCHAR FileSystem[128];
- swprintf(NtDrivePath, L"\\??\\");
- wcscat(NtDrivePath, DrivePath);
- NtDrivePath[wcslen(NtDrivePath)-1] = 0;
- RtlInitUnicodeString(&DrivePathU, NtDrivePath);
+ RtlInitUnicodeString(&VolumePathU, VolumePath);
- DPRINT1("AUTOCHK: Checking %wZ\n", &DrivePathU);
- PrintString(" Checking file system on %S\r\n", DrivePath);
+ /* Get a drive string for display purposes only */
+ if (wcslen(VolumePath) == 6 &&
+ VolumePath[0] == L'\\' &&
+ VolumePath[1] == L'?' &&
+ VolumePath[2] == L'?' &&
+ VolumePath[3] == L'\\' &&
+ VolumePath[5] == L':')
+ {
+ /* DOS drive */
+ DisplayName = &VolumePath[4];
+ }
+ else
+ {
+ DisplayName = VolumePath;
+ }
+
+ DPRINT1("AUTOCHK: Checking %wZ\n", &VolumePathU);
+ PrintString("Verifying the file system on %S\r\n", DisplayName);
/* Get the file system */
- Status = GetFileSystem(DrivePath,
+ Status = GetFileSystem(&VolumePathU,
FileSystem,
- ARRAYSIZE(FileSystem));
+ sizeof(FileSystem));
if (!NT_SUCCESS(Status))
{
DPRINT1("GetFileSystem() failed, Status 0x%08lx\n", Status);
- PrintString(" Unable to detect file system of %S\r\n", DrivePath);
- return Status;
+ PrintString(" Unable to detect the file system of volume %S\r\n",
DisplayName);
+ goto Quit;
}
PrintString(" The file system type is %S.\r\n\r\n", FileSystem);
@@ -459,41 +443,52 @@ CheckVolume(
}
if (Count >= RTL_NUMBER_OF(FileSystems))
{
- DPRINT1("File system not supported\n");
- PrintString(" Unable to check the file system. %S is not
supported.\r\n", FileSystem);
- return STATUS_DLL_NOT_FOUND;
+ DPRINT1("File system %S not supported\n", FileSystem);
+ PrintString(" Unable to verify the volume. The %S file system is not
supported.\r\n", FileSystem);
+ Status = STATUS_DLL_NOT_FOUND;
+ goto Quit;
}
- /* First, check whether the volume is dirty */
- Status = FileSystems[Count].ChkdskFunc(&DrivePathU,
+ /* Check whether the volume is dirty */
+ Status = FileSystems[Count].ChkdskFunc(&VolumePathU,
FALSE, // FixErrors
TRUE, // Verbose
TRUE, // CheckOnlyIfDirty
FALSE, // ScanDrive
ChkdskCallback);
- /* It is */
- if (Status == STATUS_DISK_CORRUPT_ERROR)
+
+ /* Perform the check either when the volume is dirty or a check is forced */
+ if ((Status == STATUS_DISK_CORRUPT_ERROR) || !CheckOnlyIfDirty)
{
/* Let the user decide whether to repair */
- PrintString(" The file system on this volume needs to be checked for
problems.\r\n");
- PrintString(" You may cancel this check, but it's recommended that you
continue.\r\n\r\n");
+ if (Status == STATUS_DISK_CORRUPT_ERROR)
+ {
+ PrintString("The file system on volume %S needs to be checked for
problems.\r\n", DisplayName);
+ PrintString("You may cancel this check, but it is recommended that you
continue.\r\n");
+ }
+ else
+ {
+ PrintString("A volume check has been scheduled.\r\n");
+ }
if (!KeyboardHandle || WaitForKeyboard(KeyboardHandle, TimeOut) ==
STATUS_TIMEOUT)
{
- PrintString(" The system will now check the file
system.\r\n\r\n");
- Status = FileSystems[Count].ChkdskFunc(&DrivePathU,
+ PrintString("The system will now check the file system.\r\n\r\n");
+ Status = FileSystems[Count].ChkdskFunc(&VolumePathU,
TRUE, // FixErrors
TRUE, // Verbose
- TRUE, // CheckOnlyIfDirty
+ CheckOnlyIfDirty,
FALSE, // ScanDrive
ChkdskCallback);
}
else
{
- PrintString(" File system check has been skipped.\r\n");
+ PrintString("The file system check has been skipped.\r\n");
}
}
+Quit:
+ PrintString("\r\n\r\n");
return Status;
}
@@ -521,24 +516,84 @@ _main(
IN PCHAR envp[],
IN ULONG DebugFlag)
{
- PROCESS_DEVICEMAP_INFORMATION DeviceMap;
- ULONG i;
NTSTATUS Status;
- WCHAR DrivePath[128];
LONG TimeOut;
+ ULONG i;
+ BOOLEAN CheckAllVolumes = FALSE;
+ BOOLEAN CheckOnlyIfDirty = TRUE;
+ PROCESS_DEVICEMAP_INFORMATION DeviceMap;
+ PCHAR SkipDrives = NULL;
+ ANSI_STRING VolumePathA;
+ UNICODE_STRING VolumePathU;
+ WCHAR VolumePath[128] = L"";
- // Win2003 passes the only param - "*". Probably means to check all drives
/*
- DPRINT("Got %d params\n", argc);
- for (i=0; i<argc; i++)
- DPRINT("Param %d: %s\n", i, argv[i]);
- */
-
- /* Query timeout */
- TimeOut = 3;
- QueryTimeout(&TimeOut);
+ * Parse the command-line: optional command switches,
+ * then the NT volume name (or drive letter) to be analysed.
+ * If "*" is passed this means that we check all the volumes.
+ */
+ if (argc <= 1)
+ {
+ /* Only one parameter (the program name), bail out */
+ return 1;
+ }
+ for (i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] == '/' || argv[i][0] == '-')
+ {
+ DPRINT("Parameter %d: %s\n", i, argv[i]);
+ switch (toupper(argv[i][1]))
+ {
+ case 'K': /* List of drive letters to skip */
+ {
+ /* Check for the separator */
+ if (argv[i][2] != ':')
+ goto Default;
+
+ SkipDrives = &argv[i][3];
+ break;
+ }
+
+ case 'R': /* Repair the errors, implies /P */
+ case 'P': /* Check even if not dirty */
+ {
+ if (argv[i][2] != ANSI_NULL)
+ goto Default;
+
+ CheckOnlyIfDirty = FALSE;
+ break;
+ }
+
+ default: Default:
+ DPRINT1("Unknown switch %d: %s\n", i, argv[i]);
+ break;
+ }
+ }
+ else
+ {
+ DPRINT("Parameter %d - Volume specification: %s\n", i, argv[i]);
+ if (strcmp(argv[i], "*") == 0)
+ {
+ CheckAllVolumes = TRUE;
+ }
+ else
+ {
+ RtlInitEmptyUnicodeString(&VolumePathU,
+ VolumePath,
+ sizeof(VolumePath));
+ RtlInitAnsiString(&VolumePathA, argv[i]);
+ Status = RtlAnsiStringToUnicodeString(&VolumePathU,
+ &VolumePathA,
+ FALSE);
+ }
+
+ /* Stop the parsing now */
+ break;
+ }
+ }
- /* FIXME: We should probably use here the mount manager to be
+ /*
+ * FIXME: We should probably use here the mount manager to be
* able to check volumes which don't have a drive letter.
*/
Status = NtQueryInformationProcess(NtCurrentProcess(),
@@ -552,6 +607,30 @@ _main(
return 1;
}
+ /* Filter out the skipped drives from the map */
+ if (SkipDrives && *SkipDrives)
+ {
+ DPRINT1("Skipping drives:");
+ while (*SkipDrives)
+ {
+#if DBG
+ DbgPrint(" %c:", *SkipDrives);
+#endif
+ /* Retrieve the index and filter the drive out */
+ i = toupper(*SkipDrives) - 'A';
+ if (0 <= i && i <= 'Z'-'A')
+ DeviceMap.Query.DriveMap &= ~(1 << i);
+
+ /* Go to the next drive letter */
+ ++SkipDrives;
+ }
+ DbgPrint("\n");
+ }
+
+ /* Query the timeout */
+ TimeOut = 3;
+ QueryTimeout(&TimeOut);
+
/* Open the keyboard */
Status = OpenKeyboard(&KeyboardHandle);
if (!NT_SUCCESS(Status))
@@ -560,13 +639,41 @@ _main(
/* Ignore keyboard interaction */
}
- for (i = 0; i < 26; i++)
+ if (CheckAllVolumes)
{
- if ((DeviceMap.Query.DriveMap & (1 << i))
- && (DeviceMap.Query.DriveType[i] == DOSDEVICE_DRIVE_FIXED))
+ /* Enumerate and check each of the available volumes */
+ for (i = 0; i <= 'Z'-'A'; i++)
+ {
+ if ((DeviceMap.Query.DriveMap & (1 << i)) &&
+ (DeviceMap.Query.DriveType[i] == DOSDEVICE_DRIVE_FIXED))
+ {
+ swprintf(VolumePath, L"\\??\\%c:", L'A' + i);
+ CheckVolume(VolumePath, TimeOut, CheckOnlyIfDirty);
+ }
+ }
+ }
+ else
+ {
+ /* Retrieve our index and analyse the volume */
+ if (wcslen(VolumePath) == 6 &&
+ VolumePath[0] == L'\\' &&
+ VolumePath[1] == L'?' &&
+ VolumePath[2] == L'?' &&
+ VolumePath[3] == L'\\' &&
+ VolumePath[5] == L':')
+ {
+ i = toupper(VolumePath[4]) - 'A';
+ if ((DeviceMap.Query.DriveMap & (1 << i)) &&
+ (DeviceMap.Query.DriveType[i] == DOSDEVICE_DRIVE_FIXED))
+ {
+ CheckVolume(VolumePath, TimeOut, CheckOnlyIfDirty);
+ }
+ }
+ else
{
- swprintf(DrivePath, L"%c:\\", L'A'+i);
- CheckVolume(DrivePath, TimeOut);
+ /* Just perform the check on the specified volume */
+ // TODO: Check volume type using
NtQueryVolumeInformationFile(FileFsDeviceInformation)
+ CheckVolume(VolumePath, TimeOut, CheckOnlyIfDirty);
}
}