[AUTOCHK] Improve the timeout countdown prompt by displaying the actual remaining seconds before the disk check.

Make also keyboard availability optional.
This commit is contained in:
Hermès Bélusca-Maïto 2018-07-29 15:19:30 +02:00
parent 4225172506
commit 472d1d2f64
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0

View file

@ -6,6 +6,7 @@
* Copyright 2006-2018 Aleksey Bragin * Copyright 2006-2018 Aleksey Bragin
* Copyright 2006-2018 Hervé Poussineau * Copyright 2006-2018 Hervé Poussineau
* Copyright 2008-2018 Pierre Schweitzer * Copyright 2008-2018 Pierre Schweitzer
* Copyright 2018 Hermes Belusca-Maito
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
@ -58,7 +59,7 @@ FILESYSTEM_CHKDSK FileSystems[10] =
{ L"CDFS", CdfsChkdsk }, { L"CDFS", CdfsChkdsk },
}; };
HANDLE KeyboardHandle; HANDLE KeyboardHandle = NULL;
/* FUNCTIONS ****************************************************************/ /* FUNCTIONS ****************************************************************/
@ -66,16 +67,17 @@ HANDLE KeyboardHandle;
// FMIFS function // FMIFS function
// //
static VOID static INT
PrintString(char* fmt,...) PrintString(char* fmt,...)
{ {
INT Len;
char buffer[512]; char buffer[512];
va_list ap; va_list ap;
UNICODE_STRING UnicodeString; UNICODE_STRING UnicodeString;
ANSI_STRING AnsiString; ANSI_STRING AnsiString;
va_start(ap, fmt); va_start(ap, fmt);
vsprintf(buffer, fmt, ap); Len = vsprintf(buffer, fmt, ap);
va_end(ap); va_end(ap);
RtlInitAnsiString(&AnsiString, buffer); RtlInitAnsiString(&AnsiString, buffer);
@ -84,6 +86,42 @@ PrintString(char* fmt,...)
TRUE); TRUE);
NtDisplayString(&UnicodeString); NtDisplayString(&UnicodeString);
RtlFreeUnicodeString(&UnicodeString); RtlFreeUnicodeString(&UnicodeString);
return Len;
}
static VOID
EraseLine(
IN INT LineLength)
{
INT Len;
UNICODE_STRING UnicodeString;
WCHAR buffer[512];
if (LineLength <= 0)
return;
/* Go to the beginning of the line */
RtlInitUnicodeString(&UnicodeString, L"\r");
NtDisplayString(&UnicodeString);
/* Fill the buffer chunk with spaces */
Len = min(LineLength, ARRAYSIZE(buffer));
while (Len > 0) buffer[--Len] = L' ';
RtlInitEmptyUnicodeString(&UnicodeString, buffer, sizeof(buffer));
while (LineLength > 0)
{
/* Display the buffer */
Len = min(LineLength, ARRAYSIZE(buffer));
LineLength -= Len;
UnicodeString.Length = Len * sizeof(WCHAR);
NtDisplayString(&UnicodeString);
}
/* Go to the beginning of the line */
RtlInitUnicodeString(&UnicodeString, L"\r");
NtDisplayString(&UnicodeString);
} }
// this func is taken from kernel32/file/volume.c // this func is taken from kernel32/file/volume.c
@ -138,7 +176,8 @@ OpenDirectory(
} }
static NTSTATUS static NTSTATUS
OpenKeyboard(VOID) OpenKeyboard(
OUT PHANDLE KeyboardHandle)
{ {
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
@ -150,7 +189,7 @@ OpenKeyboard(VOID)
0, 0,
NULL, NULL,
NULL); NULL);
return NtOpenFile(&KeyboardHandle, return NtOpenFile(KeyboardHandle,
FILE_ALL_ACCESS, FILE_ALL_ACCESS,
&ObjectAttributes, &ObjectAttributes,
&IoStatusBlock, &IoStatusBlock,
@ -160,39 +199,79 @@ OpenKeyboard(VOID)
static NTSTATUS static NTSTATUS
WaitForKeyboard( WaitForKeyboard(
IN HANDLE KeyboardHandle,
IN LONG TimeOut) IN LONG TimeOut)
{ {
NTSTATUS Status; NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock; IO_STATUS_BLOCK IoStatusBlock;
LARGE_INTEGER Offset, Timeout; LARGE_INTEGER Offset, Timeout;
KEYBOARD_INPUT_DATA InputData; KEYBOARD_INPUT_DATA InputData;
INT Len = 0;
/* Attempt to read from the keyboard */ /* Skip the wait if there is no timeout */
Offset.QuadPart = 0; if (TimeOut <= 0)
Status = NtReadFile(KeyboardHandle, return STATUS_TIMEOUT;
NULL,
NULL, /* Attempt to read a down key-press from the keyboard */
NULL, do
&IoStatusBlock,
&InputData,
sizeof(KEYBOARD_INPUT_DATA),
&Offset,
NULL);
if (Status == STATUS_PENDING)
{ {
/* Wait TimeOut seconds */ Offset.QuadPart = 0;
Timeout.QuadPart = TimeOut * -10000000; Status = NtReadFile(KeyboardHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
&InputData,
sizeof(KEYBOARD_INPUT_DATA),
&Offset,
NULL);
if (!NT_SUCCESS(Status))
{
/* Something failed, bail out */
return Status;
}
if ((Status != STATUS_PENDING) && !(InputData.Flags & KEY_BREAK))
{
/* We have a down key-press, return */
return Status;
}
} while (Status != STATUS_PENDING);
/* Perform the countdown of TimeOut seconds */
Status = STATUS_TIMEOUT;
while (TimeOut > 0)
{
/*
* Display the countdown string.
* Note that we only do a carriage return to go back to the
* beginning of the line to possibly erase it. Note also that
* we display a trailing space to erase any last character
* when the string length decreases.
*/
Len = PrintString("Press any key within %d second(s) to cancel and resume startup. \r", TimeOut);
/* Decrease the countdown */
--TimeOut;
/* Wait one second for a key press */
Timeout.QuadPart = -10000000;
Status = NtWaitForSingleObject(KeyboardHandle, FALSE, &Timeout); Status = NtWaitForSingleObject(KeyboardHandle, FALSE, &Timeout);
/* The user didn't enter anything, cancel the read */ if (Status != STATUS_TIMEOUT)
if (Status == STATUS_TIMEOUT) break;
{ }
NtCancelIoFile(KeyboardHandle, &IoStatusBlock);
} /* Erase the countdown string */
/* Else, return some status */ EraseLine(Len);
else
{ if (Status == STATUS_TIMEOUT)
Status = IoStatusBlock.Status; {
} /* The user did not press any key, cancel the read */
NtCancelIoFile(KeyboardHandle, &IoStatusBlock);
}
else
{
/* Otherwise, return some status */
Status = IoStatusBlock.Status;
} }
return Status; return Status;
@ -395,16 +474,11 @@ CheckVolume(
/* It is */ /* It is */
if (Status == STATUS_DISK_CORRUPT_ERROR) if (Status == STATUS_DISK_CORRUPT_ERROR)
{ {
NTSTATUS WaitStatus;
/* Let the user decide whether to repair */ /* Let the user decide whether to repair */
PrintString(" The file system on this volume needs to be checked for problems.\r\n"); 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"); PrintString(" You may cancel this check, but it's recommended that you continue.\r\n\r\n");
PrintString(" Press any key within %d second(s) to cancel and resume startup.\r\n\r\n", TimeOut);
/* Timeout == fix it! */ if (!KeyboardHandle || WaitForKeyboard(KeyboardHandle, TimeOut) == STATUS_TIMEOUT)
WaitStatus = WaitForKeyboard(TimeOut);
if (WaitStatus == STATUS_TIMEOUT)
{ {
PrintString(" The system will now check the file system.\r\n\r\n"); PrintString(" The system will now check the file system.\r\n\r\n");
Status = FileSystems[Count].ChkdskFunc(&DrivePathU, Status = FileSystems[Count].ChkdskFunc(&DrivePathU,
@ -478,12 +552,12 @@ _main(
return 1; return 1;
} }
/* Open keyboard */ /* Open the keyboard */
Status = OpenKeyboard(); Status = OpenKeyboard(&KeyboardHandle);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("OpenKeyboard() failed, Status 0x%08lx\n", Status); DPRINT1("OpenKeyboard() failed, Status 0x%08lx\n", Status);
return 1; /* Ignore keyboard interaction */
} }
for (i = 0; i < 26; i++) for (i = 0; i < 26; i++)
@ -496,8 +570,9 @@ _main(
} }
} }
/* Close keyboard */ /* Close the keyboard */
NtClose(KeyboardHandle); if (KeyboardHandle)
NtClose(KeyboardHandle);
// PrintString("Done\r\n\r\n"); // PrintString("Done\r\n\r\n");
return 0; return 0;