|
|
/*++
Copyright (c) 1999-2001 Microsoft Corporation
Module Name:
efichk.cxx
Abstract:
This is the main program for the eficheck version of chkdsk.
--*/
#pragma warning(disable: 4091)
#include "ulib.hxx"
#include "wstring.hxx"
#include "fatvol.hxx"
#include "efickmsg.hxx"
#include "error.hxx"
#include "ifssys.hxx"
#include "rtmsg.h"
#include "rcache.hxx"
#include "ifsserv.hxx"
#include "efiwintypes.hxx"
extern "C" BOOLEAN InitializeUfat( PVOID DllHandle, ULONG Reason, PCONTEXT Context );
extern "C" BOOLEAN InitializeIfsUtil( PVOID DllHandle, ULONG Reason, PCONTEXT Context );
USHORT InvokeAutoChk ( IN PWSTRING DriveLetter, IN PWSTRING VolumeName, IN ULONG ChkdskFlags, IN BOOLEAN RemoveRegistry, IN BOOLEAN SetupMode, IN BOOLEAN Extend, IN ULONG LogfileSize, IN INT ArgCount, IN WCHAR **ArgArray, IN OUT PMESSAGE Msg, OUT PULONG ExitStatus );
int __cdecl main( int argc, WCHAR** argv, WCHAR** envp );
extern "C" { #include "efi.h"
#include "efilib.h"
}
int argc; WCHAR ** argv;
#if defined(EFI_DEBUG)
VOID PrintLoadedImageInfo ( IN EFI_LOADED_IMAGE *LoadedImage ); #endif
VOID InvokeAutochkMain ( IN EFI_HANDLE ImageHandle, IN EFI_LOADED_IMAGE *LoadedImage );
extern "C" {
EFI_STATUS __declspec(dllexport) InitializeEfiChkApplication( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_LOADED_IMAGE *LoadedImage;
/*
* Initialize the Library. Set BS, RT, &ST globals * BS = Boot Services RT = RunTime Services * ST = System Table */ InitializeLib (ImageHandle, SystemTable); InitializeShellApplication( ImageHandle, SystemTable );
Print(TEXT("EFI Check Disk Version 0.2\n")); Print(TEXT("Based on EFI Core ")); Print(TEXT("Version %d.%d.%d.%d\n"), EFI_SPECIFICATION_MAJOR_REVISION, EFI_SPECIFICATION_MINOR_REVISION, EFI_FIRMWARE_MAJOR_REVISION, EFI_FIRMWARE_MINOR_REVISION );
DEBUG((D_INFO,(CHAR8*)"EFICHK application started\n"));
BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID**)&LoadedImage);
#if 0
PrintLoadedImageInfo (LoadedImage); #endif
// call into autochk.
InvokeAutochkMain (ImageHandle, LoadedImage);
#if 0
EfiWaitForKey(); ST->ConOut->OutputString (ST->ConOut, TEXT("\n\n")); #endif
return EFI_SUCCESS; }
} // extern "C"
UINT16 *MemoryType[] = { TEXT("reserved "), TEXT("LoaderCode"), TEXT("LoaderData"), TEXT("BS_code "), TEXT("BS_data "), TEXT("RT_code "), TEXT("RT_data "), TEXT("available "), TEXT("Unusable "), TEXT("ACPI_recl "), TEXT("ACPI_NVS "), TEXT("MemMapIO "), TEXT("MemPortIO "), TEXT("PAL_code "), TEXT("BUG:BUG: MaxMemoryType") };
VOID InvokeAutochkMain ( IN EFI_HANDLE ImageHandle, IN EFI_LOADED_IMAGE *LoadedImage ) { EFI_LOADED_IMAGE *ParentImage;
if (!LoadedImage->ParentHandle) { /*
* If you are loaded from the EFI boot manager the ParentHandle * is Null. Thus a pure EFI application will not have a parrent. */ DEBUG((D_INFO,(CHAR8*)"\n%HImage was loaded from EFI Boot Manager%N\n")); return; }
BS->HandleProtocol (LoadedImage->ParentHandle, &LoadedImageProtocol, (VOID**)&ParentImage);
{ argc = SI->Argc; argv = SI->Argv;
DEBUG((D_INFO,(CHAR8*)"Launching main...\n")); // call main.
main(argc,argv,NULL); DEBUG((D_INFO,(CHAR8*)"Returned from main...\n"));
} }
#if defined(EFI_DEBUG)
VOID PrintLoadedImageInfo ( IN EFI_LOADED_IMAGE *LoadedImage ) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath;
Print( TEXT("\n%HImage was loaded from file %N%s\n"), DevicePathToStr (LoadedImage->FilePath));
BS->HandleProtocol (LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID**)&DevicePath); if (DevicePath) { Print( TEXT("%HImage was loaded from this device %N%s\n"), DevicePathToStr (DevicePath));
}
Print( TEXT("\n Image Base is %X"), LoadedImage->ImageBase); Print( TEXT("\n Image Size is %X"), LoadedImage->ImageSize); Print( TEXT("\n Image Code Type %s"), MemoryType[LoadedImage->ImageCodeType]); Print( TEXT("\n Image Data Type %s"), MemoryType[LoadedImage->ImageDataType]); Print( TEXT("\n %d Bytes of Options passed to this Image\n"), LoadedImage->LoadOptionsSize);
if (LoadedImage->ParentHandle) { Status = BS->HandleProtocol (LoadedImage->ParentHandle, &DevicePathProtocol, (VOID**)&DevicePath); if (Status == EFI_SUCCESS && DevicePath) { Print( TEXT("Images parent is %s\n\n"), DevicePathToStr (DevicePath)); } } } #endif
BOOLEAN force = FALSE; BOOLEAN readonly = TRUE;
int __cdecl main( int argc, WCHAR** argv, WCHAR** envp ) /*++
Routine Description:
This routine is the main program for autocheck FAT chkdsk.
Arguments:
argc, argv - Supplies the fully qualified NT path name of the the drive to check.
Return Value:
0 - Success. 1 - Failure.
--*/ { DEBUG( (D_INFO,(CHAR8*)"\nInit Libs...\n"));
if (!InitializeUlib( NULL, !DLL_PROCESS_DETACH, NULL ) || !InitializeIfsUtil(NULL,0,NULL) || !InitializeUfat(NULL,0,NULL)) { return 1; } DEBUG( (D_INFO,(CHAR8*)"Init Libs Successful.\n")); //
// The declarations must come after these initialization functions.
//
DSTRING dos_drive_name; DSTRING volume_name; DSTRING drive_letter;
EFICHECK_MESSAGE *msg = NULL;
BOOLEAN onlyifdirty = TRUE; BOOLEAN recover = FALSE; BOOLEAN extend = FALSE; BOOLEAN remove_registry = FALSE;
ULONG ArgOffset = 1;
BOOLEAN SetupOutput = FALSE; BOOLEAN SetupTextMode = FALSE; BOOLEAN SetupSpecialFixLevel = FALSE;
ULONG exit_status = 0;
BOOLEAN SuppressOutput = TRUE; // dots only by default
BOOLEAN all_drives = FALSE; BOOLEAN resize_logfile = FALSE; BOOLEAN skip_index_scan = FALSE; BOOLEAN skip_cycle_scan = FALSE; BOOLEAN showhelp = FALSE; BOOLEAN drive_already_specified = FALSE;
LONG logfile_size = 0;
USHORT rtncode; ULONG chkdsk_flags;
if (!drive_letter.Initialize() || !volume_name.Initialize()) { DEBUG((D_ERROR,(CHAR8*)"Out of memory.\n")); return 1; }
force = FALSE; onlyifdirty = FALSE;
// Parse the arguments--the accepted arguments are:
//
// efichk [/f] [/r] device-name
//
// /f - fix errors
// /r - recover; implies /f
//
msg = NEW EFICHECK_MESSAGE;
if (NULL == msg || !msg->Initialize()) { return 1; }
DEBUG( (D_INFO,(CHAR8*)"\nParse Options\n"));
for (ArgOffset = 1; ArgOffset < (ULONG)argc; ++ArgOffset) {
if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') && (argv[ArgOffset][1] == 'r' || argv[ArgOffset][1] == 'R') && (argv[ArgOffset][2] == 0) ) {
// Note that /r implies /f.
//
recover = TRUE; readonly = FALSE; } else if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') && (argv[ArgOffset][1] == 'f' || argv[ArgOffset][1] == 'F') && (argv[ArgOffset][2] == 0) ) {
// Note that /r implies /p.
//
readonly = FALSE; } else if ((argv[ArgOffset][0] != '/' && argv[ArgOffset][0] != '-')) { // we assume this refers to a device
if (!volume_name.Initialize(argv[ArgOffset])) { return 1; } drive_already_specified = TRUE; } else if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') && (argv[ArgOffset][1] == '?') && (argv[ArgOffset][2] == 0) ) {
// show some usage help
showhelp = TRUE; } else if ( strcmp(argv[ArgOffset], TEXT("/FORCE")) == 0 ) { // have a /FORCE switch to allow efichk to check really messed up volumes.
force = TRUE; } else { // this is a switch we don't know of
msg->Set(MSG_INVALID_PARAMETER); msg->Display("%ws",argv[ArgOffset]); msg->Set(MSG_BLANK_LINE); msg->Display(); showhelp = TRUE; } }
SuppressOutput = FALSE;
if(showhelp || !drive_already_specified) { msg->Set(MSG_CHK_USAGE_HEADER); msg->Display(); msg->Set(MSG_BLANK_LINE); msg->Display(); msg->Set(MSG_CHK_COMMAND_LINE); msg->Display(); msg->Set(MSG_CHK_DRIVE); msg->Display(); msg->Set(MSG_CHK_F_SWITCH); msg->Display(); msg->Set(MSG_CHK_V_SWITCH); msg->Display(); return 1; }
// make drive letter the same as volume name
if (!drive_letter.Initialize(&volume_name)) { return 1; }
DEBUG( (D_INFO,(CHAR8*)"\nParsed Args\n"));
chkdsk_flags = 0; chkdsk_flags = (onlyifdirty ? CHKDSK_CHECK_IF_DIRTY : 0); chkdsk_flags |= ((recover || extend) ? CHKDSK_RECOVER_FREE_SPACE : 0); chkdsk_flags |= (recover ? CHKDSK_RECOVER_ALLOC_SPACE : 0);
DEBUG((D_INFO,(CHAR8*)"Invoking chkdsk.\n"));
rtncode = InvokeAutoChk(&drive_letter, &volume_name, chkdsk_flags, remove_registry, SetupOutput || SetupTextMode, extend, logfile_size, argc, argv, msg, &exit_status);
DEBUG((D_INFO,(CHAR8*)"Back from chkdsk.\n")); #if 0
switch( exit_status ) { case 0: msg->Set(MSG_CHK_AUTOCHK_COMPLETE); break; case 1: case 2: msg->Set(MSG_CHK_ERRORS_FIXED); break; case 3: msg->Set(MSG_CHK_ERRORS_NOT_FIXED); break; default: msg->Set(MSG_CHK_AUTOCHK_COMPLETE); break; } msg->Display(); #endif
DELETE(msg);
DEBUG((D_ERROR,(CHAR8*)"EFICHK: Exit Status %d\n", exit_status));
return exit_status; }
USHORT InvokeAutoChk ( IN PWSTRING DriveLetter, IN PWSTRING VolumeName, IN ULONG ChkdskFlags, IN BOOLEAN RemoveRegistry, IN BOOLEAN SetupMode, IN BOOLEAN Extend, IN ULONG LogfileSize, IN INT ArgCount, IN WCHAR **ArgArray, IN OUT PMESSAGE Msg, OUT PULONG ExitStatus ) /*++
Routine Description:
This is the core of efichk. It checks the specified drive.
Arguments:
DriveLetter - Supplies the drive letter of the drive (can be empty string) VolumeName - Supplies the guid volume name of the drive ChkdskFlags - Supplies the chkdsk control flags RemoveRegistry - Supplies TRUE if registry entry is to be removed SetupMode - Supplies TRUE if invoked through setup Extend - Supplies TRUE if extending the volume (obsolete) LogfileSize - Supplies the size of the logfile ArgCount - Supplies the number of arguments given to autochk. ArgArray - Supplies the arguments given to autochk. Msg - Supplies the outlet of messages ExitStatus - Retrieves the exit status of chkdsk
Return Value:
0 - Success 1 - Fatal error 2 - Volume specific error
--*/ { DSTRING fsname; DSTRING fsNameAndVersion;
PFAT_VOL fatvol = NULL; PVOL_LIODPDRV vol;
BOOLEAN SetupSpecialFixLevel = FALSE;
PREAD_CACHE read_cache;
DSTRING boot_execute_log_file_name; FSTRING boot_ex_temp; HMEM logged_message_mem; NTSTATUS result;
DSTRING fatname; DSTRING fat32name; DSTRING rawname; DSTRING ntfsname;
*ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
if (!fatname.Initialize("FAT") || !rawname.Initialize("RAW") || !fat32name.Initialize("FAT32")) { return 1; }
if (VolumeName->QueryChCount() == 0) { DEBUG((D_ERROR,(CHAR8*)"EFICHK: Volume name is missing.\n")); return 2; // continue if all_drives are enabled
}
if (DriveLetter->QueryChCount() == 0) { // unable to map VolumeName to a drive letter so do the default
if (!IFS_SYSTEM::NtDriveNameToDosDriveName(VolumeName, DriveLetter)) { DEBUG((D_ERROR,(CHAR8*)"Out of memory.\n")); return 1; } }
if (!IFS_SYSTEM::QueryFileSystemName(VolumeName, &fsname, &result, &fsNameAndVersion)) { Msg->Set( MSG_FS_NOT_DETERMINED ); Msg->Display( "%W", VolumeName );
if(result != 0 ){ Msg->Set(MSG_CANT_DASD); Msg->Display(); } return 2; }
// Msg->SetLoggingEnabled();
Msg->Set(MSG_CHK_RUNNING); Msg->Display("%W", DriveLetter);
Msg->Set(MSG_FILE_SYSTEM_TYPE); Msg->Display("%W", &fsname);
if (fsname == fatname || fsname == fat32name || force) {
if (!(fatvol = NEW FAT_VOL)) { DEBUG((D_ERROR,(CHAR8*)"Out of memory.\n")); return 1; }
if (NoError != fatvol->Initialize(Msg, VolumeName, (BOOLEAN)(ChkdskFlags & CHKDSK_CHECK_IF_DIRTY))) { DELETE(fatvol); return 2; }
if ((read_cache = NEW READ_CACHE) && read_cache->Initialize(fatvol, 75)) { fatvol->SetCache(read_cache); } else { DELETE(read_cache); }
vol = fatvol;
} else { Msg->Set( MSG_FS_NOT_SUPPORTED ); Msg->Display( "%s%W", "EFICHK", &fsname ); return 2; }
// Invoke chkdsk.
if (!vol->ChkDsk(readonly ? CheckOnly : TotalFix, Msg, ChkdskFlags, LogfileSize, ExitStatus, DriveLetter)) {
DELETE(vol);
DEBUG((D_ERROR,(CHAR8*)"EFICHK: ChkDsk failure\n"));
return 2; }
DELETE(vol);
return 0; }
|