reactos/modules/rosapps/applications/cmdutils/vfdcmd/vfdcmd.c

3499 lines
64 KiB
C
Raw Normal View History

/*
vfdcmd.c
Virtual Floppy Drive for Windows
Driver control program (console version)
Copyright (C) 2003-2008 Ken Kato
*/
#ifdef __cplusplus
#pragma message(__FILE__": Compiled as C++ for testing purpose.")
#endif // __cplusplus
#define WIN32_LEAN_AND_MEAN
#define _CRTDBG_MAP_ALLOC
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <crtdbg.h>
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif // INVALID_FILE_ATTRIBUTES
#include "vfdtypes.h"
#include "vfdapi.h"
#include "vfdver.h"
#include "vfdmsg.h"
//
// current driver state
//
static DWORD driver_state = VFD_NOT_INSTALLED;
//
// interactive flag
//
static const char *help_progname = "VFD.EXE ";
//
// command functions return value
//
#define VFD_OK 0
#define VFD_NG 1
//
// operation mode
//
#define OPERATION_ASK 0 // ask user on error
#define OPERATION_QUIT 1 // quits on error
#define OPERATION_FORCE 2 // force on error
//
// invalid target number
//
#define TARGET_NONE (ULONG)-1
//
// command processing functions
//
typedef int (*cmdfnc)(const char **args);
static int Install(const char **args);
static int Remove(const char **args);
static int Config(const char **args);
static int Start(const char **args);
static int Stop(const char **args);
static int Shell(const char **args);
static int Open(const char **args);
static int Close(const char **args);
static int Save(const char **args);
static int Protect(const char **args);
static int Format(const char **args);
static int Link(const char **args);
static int Unlink(const char **args);
static int Status(const char **args);
static int Help(const char **args);
static int Version(const char **args);
//
// Command table
//
static const struct {
char *cmd; // command string
int max_args; // maximum allowed number of argc
cmdfnc func; // command processing function
DWORD hint; // command hint message id
}
Commands[] = {
{"INSTALL", 2, Install, MSG_HINT_INSTALL},
{"REMOVE", 1, Remove, MSG_HINT_REMOVE },
{"CONFIG", 1, Config, MSG_HINT_CONFIG },
{"START", 0, Start, MSG_HINT_START },
{"STOP", 1, Stop, MSG_HINT_STOP },
{"SHELL", 1, Shell, MSG_HINT_SHELL },
{"OPEN", 6, Open, MSG_HINT_OPEN },
{"CLOSE", 2, Close, MSG_HINT_CLOSE },
{"SAVE", 3, Save, MSG_HINT_SAVE, },
{"PROTECT", 2, Protect, MSG_HINT_PROTECT},
{"FORMAT", 2, Format, MSG_HINT_FORMAT },
{"LINK", 3, Link, MSG_HINT_LINK },
{"ULINK", 1, Unlink, MSG_HINT_ULINK },
{"STATUS", 0, Status, MSG_HINT_STATUS },
{"HELP", 1, Help, MSG_HELP_HELP },
{"?", 1, Help, MSG_HELP_HELP },
{"VERSION", 0, Version, MSG_HINT_VERSION},
{0, 0, 0, 0}
};
//
// Help message table
//
static const struct {
char *keyword; // help keyword
DWORD help; // help message id
}
HelpMsg[] = {
{"GENERAL", MSG_HELP_GENERAL},
{"CONSOLE", MSG_HELP_CONSOLE},
{"INSTALL", MSG_HELP_INSTALL},
{"REMOVE", MSG_HELP_REMOVE },
{"CONFIG", MSG_HELP_CONFIG },
{"START", MSG_HELP_START },
{"STOP", MSG_HELP_STOP },
{"SHELL", MSG_HELP_SHELL },
{"OPEN", MSG_HELP_OPEN },
{"CLOSE", MSG_HELP_CLOSE },
{"SAVE", MSG_HELP_SAVE },
{"PROTECT", MSG_HELP_PROTECT},
{"FORMAT", MSG_HELP_FORMAT },
{"LINK", MSG_HELP_LINK },
{"ULINK", MSG_HELP_ULINK },
{"STATUS", MSG_HELP_STATUS },
{"HELP", MSG_HELP_HELP },
{"VERSION", MSG_HINT_VERSION},
{0, 0}
};
//
// local functions
//
static int InteractiveConsole();
static int ProcessCommandLine(int argc, const char **args);
static int ParseCommand(const char *cmd);
static int ParseHelpTopic(const char *topic);
static int CheckDriver();
static int InputChar(ULONG msg, PCSTR ans);
static void PrintImageInfo(HANDLE hDevice);
static void PrintDriveLetter(HANDLE hDevice, ULONG nDrive);
static void PrintMessage(UINT msg, ...);
static BOOL ConsolePager(char *pBuffer, BOOL bReset);
static const char *SystemError(DWORD err);
static void ConvertPathCase(char *src, char *dst);
//
// utility macro
//
#define IS_WINDOWS_NT() ((GetVersion() & 0xff) < 5)
//
// main
//
int main(int argc, const char **argv)
{
#ifdef _DEBUG
// output vfd.exe command reference text
if (*(argv + 1) && !_stricmp(*(argv + 1), "doc")) {
int idx = 0;
char *buf = "";
printf("\r\n VFD.EXE Command Reference\r\n");
while (HelpMsg[idx].keyword) {
int len = strlen(HelpMsg[idx].keyword);
printf(
"\r\n\r\n"
"====================\r\n"
"%*s\r\n"
"====================\r\n"
"\r\n",
(20 + len) / 2, HelpMsg[idx].keyword);
FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL, HelpMsg[idx].help, 0,
(LPTSTR)&buf, 0, (va_list *)&help_progname);
printf("%s", buf);
LocalFree(buf);
idx++;
}
return 0;
}
#endif
// Reports memory leaks at process termination
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
// Check the operating system version
if (!VfdIsValidPlatform()) {
PrintMessage(MSG_WRONG_PLATFORM);
return VFD_NG;
}
if (argc < 2) {
// If no parameter is given, enter the interactive mode
return InteractiveConsole();
}
else {
// Perform a single operation
return ProcessCommandLine(argc - 1, argv + 1);
}
}
//
// VFD interactive console
//
int InteractiveConsole()
{
char input[1024]; // user input buffer
int argc; // number of args in the user input
char *args[10]; // args to pass to command functions
char sepa; // argument separator
char *p; // work pointer
// Disable the system default Ctrl+C handler
SetConsoleCtrlHandler(NULL, TRUE);
// Set the console title
SetConsoleTitle(VFD_PRODUCT_DESC);
// print version information and the console hint text
Version(NULL);
PrintMessage(MSG_CONSOLE_HINT);
// set interactive flag to exclude "VFD.EXE" from help text
help_progname = "";
// process user input
for (;;) {
// print the prompt
printf("[VFD] ");
fflush(stdout);
// read user input
fflush(stdin);
p = fgets(input, sizeof(input), stdin);
if (p == NULL) {
// most likely <ctrl+c>
printf("exit\n");
break;
}
// skip leading blank characters
while (*p == ' ' || *p == '\t' || *p == '\n') {
p++;
}
if (*p == '\0') {
// empty input
continue;
}
// handle external commands
if (!_strnicmp(p, "dir", 3) ||
!_strnicmp(p, "attrib", 6)) {
// special cases - frequently used commands
// pass these to system() even without '.'
system(p);
printf("\n");
continue;
}
else if (*p == '.') {
// external command
system(p + 1);
printf("\n");
continue;
}
// split the input line into parameters (10 parameters max)
argc = 0;
ZeroMemory(args, sizeof(args));
do {
// top of a parameter
args[argc++] = p;
// is the parameter quoted?
if (*p == '\"' || *p == '\'') {
sepa = *(p++);
}
else {
sepa = ' ';
}
// search the end of the parameter
while (*p && *p != '\n') {
if (sepa == ' ') {
if (*p == '\t' || *p == ' ') {
break; // tail of a non-quoted parameter
}
}
else {
if (*p == sepa) {
sepa = ' '; // close quote
}
}
p++;
}
// terminate the parameter
if (*p) {
*(p++) = '\0';
}
// skip trailing blank characters
while (*p == ' ' || *p == '\t' || *p == '\n') {
p++;
}
if (*p == '\0') {
// end of the input line - no more args
break;
}
}
while (argc < sizeof(args) / sizeof(args[0]));
// check the first parameter for special commands
if (!_stricmp(args[0], "exit") ||
!_stricmp(args[0], "quit") ||
!_stricmp(args[0], "bye")) {
// exit command
break;
}
else if (!_stricmp(args[0], "cd") ||
!_stricmp(args[0], "chdir")) {
// internal change directory command
if (args[1]) {
char path[MAX_PATH];
int i;
// ignore the /d option (of the standard cd command)
if (_stricmp(args[1], "/d")) {
i = 1;
}
else {
i = 2;
}
p = args[i];
if (*p == '\"' || *p == '\'') {
// the parameter is quoted -- remove quotations
p++;
while (*p && *p != *args[i]) {
p++;
}
args[i]++; // skip a leading quote
*p = '\0'; // remove a trailing quote
}
else {
// the parameter is not quoted
// -- concatenate params to allow spaces in unquoted path
while (i < argc - 1) {
*(args[i] + strlen(args[i])) = ' ';
i++;
}
}
// Match the case of the path to the name on the disk
ConvertPathCase(p, path);
if (!SetCurrentDirectory(path)) {
DWORD ret = GetLastError();
if (ret == ERROR_FILE_NOT_FOUND) {
ret = ERROR_PATH_NOT_FOUND;
}
printf("%s", SystemError(ret));
}
}
else {
if (!GetCurrentDirectory(sizeof(input), input)) {
printf("%s", SystemError(GetLastError()));
}
else {
printf("%s\n", input);
}
}
}
else if (isalpha(*args[0]) &&
*(args[0] + 1) == ':' &&
*(args[0] + 2) == '\0') {
// internal change drive command
*args[0] = (char)toupper(*args[0]);
*(args[0] + 2) = '\\';
*(args[0] + 3) = '\0';
if (!SetCurrentDirectory(args[0])) {
printf("%s", SystemError(GetLastError()));
}
}
else {
// perform the requested VFD command
ProcessCommandLine(argc, (const char **)args);
}
printf("\n");
}
return VFD_OK;
}
//
// process a single command
//
int ProcessCommandLine(int argc, const char **args)
{
int cmd;
DWORD ret;
//
// Decide a command to perform
//
cmd = ParseCommand(*args);
if (cmd < 0) {
// no matching command
return VFD_NG;
}
if (*(++args) &&
(!strcmp(*args, "/?") ||
!_stricmp(*args, "/h"))) {
// print a short hint for the command
PrintMessage(Commands[cmd].hint);
return VFD_NG;
}
if (--argc > Commands[cmd].max_args) {
// too many parameters for the command
PrintMessage(MSG_TOO_MANY_ARGS);
PrintMessage(Commands[cmd].hint);
return VFD_NG;
}
// Get the current driver state
ret = VfdGetDriverState(&driver_state);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_GET_STAT_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
// Perform the requested operation
return (*Commands[cmd].func)(args);
}
//
// Install the Virtual Floppy Driver
// Command Line Parameters:
// (optional) driver file path - default to executive's dir
// (optional) auto start switch - default to demand start
//
int Install(const char **args)
{
const char *install_path = NULL;
DWORD start_type = SERVICE_DEMAND_START;
DWORD ret;
// process parameters
while (args && *args) {
if (!_stricmp(*args, "/a") ||
!_stricmp(*args, "/auto")) {
if (start_type != SERVICE_DEMAND_START) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
/*
if (IS_WINDOWS_NT()) {
// On Windows NT, SYSTEM start drivers must be placed
// under the winnt\system32 directory. Since I don't
// care to handle driver file copying, I use the AUTO
// start method for Windows NT.
start_type = SERVICE_AUTO_START;
}
else {
// On Windows XP, the VFD driver must be running when
// the shell starts -- otherwise the shell doesn't
// recognize the VFD drives. Since Windows XP allows
// SYSTEM start drivers to be placed in any local
// directories, I use the SYSTEM start method here.
//
// This is not an issue when the driver is started
// manually because in that case VFD.EXE and VFDWIN.EXE
// notify the shell of the VFD drives.
//
// On Windows 2000 both SYSTEM and AUTO work fine.
start_type = SERVICE_SYSTEM_START;
}
*/
// On second thought -- Win2K / XP mount manager assigns
// arbitrary drive letters to all drives it finds during
// the system start up. There is no way to prevent it
// until the driver is fully PnP compatible, so I'd settle
// for AUTO start for the time being.
start_type = SERVICE_AUTO_START;
}
else if (**args == '/') {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_INSTALL, help_progname);
return VFD_NG;
}
else {
if (install_path) {
PrintMessage(MSG_DUPLICATE_ARGS, "path");
return VFD_NG;
}
install_path = *args;
}
args++;
}
// already installed?
if (driver_state != VFD_NOT_INSTALLED) {
PrintMessage(MSG_DRIVER_EXISTS);
return VFD_NG;
}
// install the driver
ret = VfdInstallDriver(
install_path,
start_type);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_INSTALL_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
// Get the latest driver state
ret = VfdGetDriverState(&driver_state);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_GET_STAT_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
// operation successfull
PrintMessage(MSG_INSTALL_OK);
return VFD_OK;
}
//
// Remove Virtual Floppy Driver from system
// Command Line Parameters:
// [/F | /FORCE | /Q | /QUIT]
// /F forces remove operation if the driver cannot be stopped
// /Q quits remove operation if the driver cannot be stopped
//
int Remove(const char **args)
{
int mode = OPERATION_ASK;
const char *stop_params[] = { NULL, NULL };
DWORD ret;
int idx;
// parse parameters
while (args && *args) {
if (!_stricmp(*args, "/f") ||
!_stricmp(*args, "/force")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_FORCE;
stop_params[0] = *args;
}
else if (!_stricmp(*args, "/q") ||
!_stricmp(*args, "/quit")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_QUIT;
stop_params[0] = *args;
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_REMOVE, help_progname);
return VFD_NG;
}
args++;
}
// ensure the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure the driver is stopped
if (driver_state == SERVICE_RUNNING) {
// Try to stop with the same command line option (/F or /Q)
while (Stop(stop_params) != VFD_OK) {
// stop failed
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_REMOVE_FORCE);
break;
}
else if (mode == OPERATION_QUIT) {
PrintMessage(MSG_REMOVE_QUIT);
return VFD_NG;
}
else {
int c;
PrintMessage(MSG_REMOVE_WARN);
c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
if (c == 'f') { // force
break;
}
else if (c == 'c') { // cancel
return VFD_NG;
}
}
}
}
// remove the driver
ret = VfdRemoveDriver();
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_REMOVE_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
// Wait for the driver to be actually removed for 3 secs Max.
for (idx = 0; idx < 10; idx++) {
ret = VfdGetDriverState(&driver_state);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_GET_STAT_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
if (driver_state == VFD_NOT_INSTALLED) {
break;
}
Sleep(300);
}
if (driver_state != VFD_NOT_INSTALLED) {
PrintMessage(MSG_REMOVE_PENDING);
return VFD_NG;
}
// operation successful
PrintMessage(MSG_REMOVE_OK);
return VFD_OK;
}
//
// Configure the Virtual Floppy Driver
// Command Line Parameters:
// /auto, /manual
//
int Config(const char **args)
{
DWORD start_type = SERVICE_DISABLED;
DWORD ret;
while (args && *args) {
if (!_stricmp(*args, "/a") ||
!_stricmp(*args, "/auto")) {
if (start_type != SERVICE_DISABLED) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
start_type = SERVICE_AUTO_START;
}
else if (!_stricmp(*args, "/m") ||
!_stricmp(*args, "/manual")) {
if (start_type != SERVICE_DISABLED) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
start_type = SERVICE_DEMAND_START;
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_CONFIG, help_progname);
return VFD_NG;
}
args++;
}
if (start_type == SERVICE_DISABLED) {
// no parameter is specified
PrintMessage(MSG_HINT_CONFIG, help_progname);
return VFD_NG;
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// configure the driver
ret = VfdConfigDriver(start_type);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_CONFIG_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
// operation successfull
PrintMessage(MSG_CONFIG_OK);
return VFD_OK;
}
//
// Start the Virtual Floppy Driver
// Command Line Parameters: None
//
int Start(const char **args)
{
DWORD ret;
UNREFERENCED_PARAMETER(args);
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED &&
Install(NULL) != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is not running
if (driver_state == SERVICE_RUNNING) {
PrintMessage(MSG_ALREADY_RUNNING);
return VFD_NG;
}
// start the driver
ret = VfdStartDriver(&driver_state);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_START_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
// operation successfull
PrintMessage(MSG_START_OK);
return VFD_OK;
}
//
// Stop the Virtual Floppy Driver
// Command Line Parameters:
// /FORCE | /F Forces the operation on error
// /QUIT | /Q Quits the operation on error
//
int Stop(const char **args)
{
int mode = OPERATION_ASK;
const char *close_params[] = { "*", NULL, NULL };
DWORD ret;
while (args && *args) {
if (!_stricmp(*args, "/f") ||
!_stricmp(*args, "/force")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_FORCE;
// parameter to pass to the Close() function
close_params[1] = *args;
}
else if (!_stricmp(*args, "/q") ||
!_stricmp(*args, "/quit")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_QUIT;
// parameter to pass to the Close() function
close_params[1] = *args;
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_STOP, help_progname);
return VFD_NG;
}
args++;
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is running
if (driver_state == SERVICE_STOPPED) {
PrintMessage(MSG_NOT_STARTED);
return VFD_NG;
}
// ensure that all drives are empty
if (driver_state == SERVICE_RUNNING) {
// Try to close drives with the same operation mode (/F or /Q)
while (Close(close_params) != VFD_OK) {
// close failed
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_STOP_FORCE);
break;
}
else if (mode == OPERATION_QUIT) {
PrintMessage(MSG_STOP_QUIT);
return VFD_NG;
}
else {
int c;
PrintMessage(MSG_STOP_WARN);
c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
if (c == 'f') { // force
break;
}
else if (c == 'c') { // cancel
return VFD_NG;
}
}
}
}
// stop the driver
ret = VfdStopDriver(&driver_state);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_STOP_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
if (driver_state != SERVICE_STOPPED) {
PrintMessage(MSG_STOP_PENDING);
return VFD_NG;
}
// operation successful
PrintMessage(MSG_STOP_OK);
return VFD_OK;
}
//
// Enable / Disable the shell extension
// Command Line Parameters:
// (optional) /ON or /OFF
//
int Shell(const char **args)
{
DWORD ret;
ret = VfdCheckHandlers();
if (ret != ERROR_SUCCESS &&
ret != ERROR_PATH_NOT_FOUND &&
ret != ERROR_FILE_NOT_FOUND) {
PrintMessage(MSG_GET_SHELLEXT_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
if (args && *args) {
if (_stricmp(*args, "/on") == 0) {
if (ret != ERROR_SUCCESS) {
ret = VfdRegisterHandlers();
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_SET_SHELLEXT_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
}
}
else if (_stricmp(*args, "/off") == 0) {
if (ret == ERROR_SUCCESS) {
ret = VfdUnregisterHandlers();
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_SET_SHELLEXT_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
}
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_SHELL, help_progname);
return VFD_NG;
}
ret = VfdCheckHandlers();
}
if (ret == ERROR_PATH_NOT_FOUND ||
ret == ERROR_FILE_NOT_FOUND) {
PrintMessage(MSG_SHELLEXT_DISABLED);
}
else if (ret == ERROR_SUCCESS) {
PrintMessage(MSG_SHELLEXT_ENABLED);
}
else {
PrintMessage(MSG_GET_SHELLEXT_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
return VFD_OK;
}
//
// Open an image file to a Virtual Floppy Drive
// Command Line Parameters:
// [drive:] [file] [/NEW] [/RAM] [/P | /W]
// [/size] [/media] [/F | /FORCE | /Q | /QUIT]
int Open(const char **args)
{
int mode = OPERATION_ASK;
BOOL create = FALSE;
ULONG target = TARGET_NONE;
PCSTR file_name = NULL;
VFD_DISKTYPE disk_type = VFD_DISKTYPE_FILE;
CHAR protect = '\0';
VFD_MEDIA media_type = VFD_MEDIA_NONE;
BOOL five_inch = FALSE;
VFD_FLAGS media_flags = 0;
HANDLE hDevice;
CHAR letter;
DWORD ret;
// process parameters
while (args && *args) {
if (!_stricmp(*args, "/f") ||
!_stricmp(*args, "/force")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_FORCE;
}
else if (!_stricmp(*args, "/q") ||
!_stricmp(*args, "/quit")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_QUIT;
}
else if (!_stricmp(*args, "/new")) {
if (create) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
create = TRUE;
}
// Disk type options
else if (_stricmp(*args, "/ram") == 0) {
if (disk_type != VFD_DISKTYPE_FILE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
disk_type = VFD_DISKTYPE_RAM;
}
// Protect options
else if (_stricmp(*args, "/p") == 0 ||
_stricmp(*args, "/w") == 0) {
if (protect) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
protect = (CHAR)toupper(*(*args + 1));
}
// media size options
else if (strcmp(*args, "/160") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F5_160;
}
else if (strcmp(*args, "/180") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F5_180;
}
else if (strcmp(*args, "/320") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F5_320;
}
else if (strcmp(*args, "/360") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F5_360;
}
else if (strcmp(*args, "/640") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_640;
}
else if (strcmp(*args, "/720") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_720;
}
else if (strcmp(*args, "/820") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_820;
}
else if (strcmp(*args, "/120") == 0 ||
strcmp(*args, "/1.20") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_1P2;
}
else if (strcmp(*args, "/144") == 0 ||
strcmp(*args, "/1.44") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_1P4;
}
else if (strcmp(*args, "/168") == 0 ||
strcmp(*args, "/1.68") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_1P6;
}
else if (strcmp(*args, "/172") == 0 ||
strcmp(*args, "/1.72") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_1P7;
}
else if (strcmp(*args, "/288") == 0 ||
strcmp(*args, "/2.88") == 0) {
if (media_type) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
media_type = VFD_MEDIA_F3_2P8;
}
// 5.25 inch media
else if (strcmp(*args, "/5") == 0 ||
strcmp(*args, "/525") == 0 ||
strcmp(*args, "/5.25") == 0) {
if (five_inch) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
five_inch = TRUE;
}
// target option
else if (isalnum(**args) &&
*(*args + 1) == ':' &&
*(*args + 2) == '\0') {
if (target != TARGET_NONE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
target = toupper(**args);
}
// filename
else if (**args != '/') {
if (file_name) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
file_name = *args;
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_OPEN, help_progname);
return VFD_NG;
}
args++;
}
if (target == TARGET_NONE) {
// default target
target = '0';
PrintMessage(MSG_TARGET_NOTICE, target);
}
// check target file
if (file_name) {
DWORD file_attr;
VFD_FILETYPE file_type;
ULONG image_size;
BOOL overwrite = FALSE;
ret = VfdCheckImageFile(
file_name, &file_attr, &file_type, &image_size);
if (ret == ERROR_FILE_NOT_FOUND) {
// the target file does not exist
if (!create) { // create option not specified
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_CREATE_NOTICE);
}
else {
printf("%s", SystemError(ret));
if (mode == OPERATION_QUIT ||
InputChar(MSG_CREATE_CONFIRM, "yn") == 'n') {
return VFD_NG;
}
}
create = TRUE;
}
}
else if (ret == ERROR_SUCCESS) {
// the target file exists
if (create) { // create option is specified
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_OVERWRITE_NOTICE);
}
else {
printf("%s", SystemError(ERROR_FILE_EXISTS));
if (mode == OPERATION_QUIT ||
InputChar(MSG_OVERWRITE_CONFIRM, "yn") == 'n') {
return VFD_NG;
}
}
overwrite = TRUE;
}
}
else {
PrintMessage(MSG_OPEN_NG, file_name);
printf("%s", SystemError(ret));
return VFD_NG;
}
//
// create or overwrite the target file
//
if (create) {
if (media_type == VFD_MEDIA_NONE) {
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_CREATE144_NOTICE);
}
else {
PrintMessage(MSG_FILE_MEDIA_UNKNOWN);
if (mode == OPERATION_QUIT ||
InputChar(MSG_CREATE144_CONFIRM, "yn") == 'n') {
return VFD_NG;
}
}
media_type = VFD_MEDIA_F3_1P4;
}
ret = VfdCreateImageFile(
file_name, media_type, VFD_FILETYPE_RAW, overwrite);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_CREATE_NG, file_name);
printf("%s", SystemError(ret));
return VFD_NG;
}
PrintMessage(MSG_FILE_CREATED);
ret = VfdCheckImageFile(
file_name, &file_attr, &file_type, &image_size);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_OPEN_NG, file_name);
printf("%s", SystemError(ret));
return VFD_NG;
}
}
else {
//
// use the existing target file
// check image size and the media type
//
VFD_MEDIA def_media; // default media for image size
ULONG media_size; // specified media size
media_size = VfdGetMediaSize(media_type);
if (media_size > image_size) {
// specified media is too large for the image
PrintMessage(MSG_IMAGE_TOO_SMALL);
return VFD_NG;
}
def_media = VfdLookupMedia(image_size);
if (def_media == VFD_MEDIA_NONE) {
// image is too small for the smallest media
PrintMessage(MSG_IMAGE_TOO_SMALL);
return VFD_NG;
}
if (media_type == VFD_MEDIA_NONE) {
// media type is not specified
ULONG def_size = VfdGetMediaSize(def_media);
if (def_size != image_size) {
// image size does not match the largest media size
PrintMessage(MSG_NO_MATCHING_MEDIA, image_size);
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_MEDIATYPE_NOTICE,
VfdMediaTypeName(def_media), def_size);
}
else if (mode == OPERATION_QUIT) {
return VFD_NG;
}
else {
PrintMessage(MSG_MEDIATYPE_SUGGEST,
VfdMediaTypeName(def_media), def_size);
if (InputChar(MSG_MEDIATYPE_CONFIRM, "yn") == 'n') {
return VFD_NG;
}
}
}
media_type = def_media;
}
}
// check file attributes against the disk type
if (file_type == VFD_FILETYPE_ZIP ||
(file_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))) {
if (disk_type != VFD_DISKTYPE_RAM) {
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_RAM_MODE_NOTICE);
}
else {
PrintMessage(MSG_RAM_MODE_ONLY);
if (mode == OPERATION_QUIT ||
InputChar(MSG_RAM_MODE_CONFIRM, "yn") == 'n') {
return VFD_NG;
}
}
disk_type = VFD_DISKTYPE_RAM;
}
}
if (disk_type != VFD_DISKTYPE_FILE) {
if (!protect) {
PrintMessage(MSG_DEFAULT_PROTECT);
protect = 'P';
}
}
}
else {
//
// pure RAM disk
//
disk_type = VFD_DISKTYPE_RAM;
if (media_type == VFD_MEDIA_NONE) {
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_CREATE144_NOTICE);
}
else {
PrintMessage(MSG_RAM_MEDIA_UNKNOWN);
if (mode == OPERATION_QUIT ||
InputChar(MSG_CREATE144_CONFIRM, "yn") == 'n') {
return VFD_NG;
}
}
media_type = VFD_MEDIA_F3_1P4;
}
}
if (protect == 'P') {
media_flags |= VFD_FLAG_WRITE_PROTECTED;
}
if (five_inch &&
VfdGetMediaSize(media_type) ==
VfdGetMediaSize((VFD_MEDIA)(media_type + 1))) {
media_type = (VFD_MEDIA)(media_type + 1);
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED &&
Install(NULL) != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is running
if (driver_state != SERVICE_RUNNING &&
Start(NULL) != VFD_OK) {
return VFD_NG;
}
// Open the target device
hDevice = VfdOpenDevice(target);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target);
printf("%s", SystemError(ret));
return VFD_NG;
}
// Ensure that the drive is empty
ret = VfdGetMediaState(hDevice);
if (ret != ERROR_NOT_READY) {
if (ret == ERROR_SUCCESS ||
ret == ERROR_WRITE_PROTECT) {
PrintMessage(MSG_DRIVE_BUSY);
}
else {
PrintMessage(MSG_GET_MEDIA_NG);
printf("%s", SystemError(ret));
}
CloseHandle(hDevice);
return VFD_NG;
}
// Open the image file
ret = VfdOpenImage(hDevice, file_name,
disk_type, media_type, media_flags);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_OPEN_NG, file_name ? file_name : "<RAM>");
printf("%s", SystemError(ret));
CloseHandle(hDevice);
return VFD_NG;
}
// assign a drive letter if the drive has none
VfdGetGlobalLink(hDevice, &letter);
if (!isalpha(letter)) {
VfdGetLocalLink(hDevice, &letter);
}
if (!isalpha(letter)) {
VfdSetLocalLink(hDevice, VfdChooseLetter());
}
// Get the actually opened image information.
PrintImageInfo(hDevice);
CloseHandle(hDevice);
return VFD_OK;
}
//
// Close the current virtual floppy image
// Command Line Parameters:
// drive number or drive letter
// /F | /FORCE | /Q | /QUIT
//
int Close(const char **args)
{
ULONG mode = OPERATION_ASK;
ULONG target_min = TARGET_NONE;
ULONG target_max = TARGET_NONE;
HANDLE hDevice;
VFD_MEDIA media_type;
VFD_FLAGS media_flags;
DWORD ret;
// check parameterS
while (args && *args) {
if (!_stricmp(*args, "/f") ||
!_stricmp(*args, "/force")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_FORCE;
}
else if (!_stricmp(*args, "/q") ||
!_stricmp(*args, "/quit")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_QUIT;
}
else if ((isalnum(**args) || **args == '*') &&
(*(*args + 1) == ':' || *(*args + 1) == '\0')) {
if (target_min != TARGET_NONE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
if (**args == '*') {
target_min = '0';
target_max = '0' + VFD_MAXIMUM_DEVICES;
}
else {
target_min = toupper(**args);
target_max = target_min + 1;
}
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_CLOSE, help_progname);
return VFD_NG;
}
args++;
}
if (target_min == TARGET_NONE) {
// default target = drive 0
target_min = '0';
target_max = '1';
PrintMessage(MSG_TARGET_NOTICE, target_min);
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is running
if (driver_state != SERVICE_RUNNING) {
PrintMessage(MSG_NOT_STARTED);
return VFD_NG;
}
// Close the drive(s)
while (target_min < target_max) {
// open the target device
hDevice = VfdOpenDevice(target_min);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target_min);
printf("%s", SystemError(ret));
if (mode != OPERATION_FORCE) {
return VFD_NG;
}
target_min++;
continue;
}
// get the current image information
ret = VfdGetImageInfo(hDevice, NULL, NULL,
&media_type, &media_flags, NULL, NULL);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_ACCESS_NG, target_min);
printf("%s", SystemError(ret));
CloseHandle(hDevice);
if (mode != OPERATION_FORCE) {
return VFD_NG;
}
target_min++;
continue;
}
if (media_type == VFD_MEDIA_NONE) {
// drive is empty
CloseHandle(hDevice);
target_min++;
continue;
}
if (media_flags & VFD_FLAG_DATA_MODIFIED) {
// RAM disk data is modified
PrintMessage(MSG_MEDIA_MODIFIED, target_min);
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_CLOSE_FORCE);
}
else if (mode == OPERATION_QUIT) {
PrintMessage(MSG_CLOSE_QUIT);
CloseHandle(hDevice);
return VFD_NG;
}
else {
if (InputChar(MSG_CLOSE_CONFIRM, "yn") == 'n') {
CloseHandle(hDevice);
return VFD_NG;
}
}
}
retry:
ret = VfdCloseImage(
hDevice, (mode == OPERATION_FORCE));
if (ret == ERROR_ACCESS_DENIED) {
PrintMessage(MSG_LOCK_NG, target_min);
if (mode == OPERATION_QUIT) {
CloseHandle(hDevice);
return VFD_NG;
}
else if (mode == OPERATION_ASK) {
int c;
if (IS_WINDOWS_NT()) {
c = InputChar(MSG_RETRY_CANCEL, "rc");
}
else {
c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
}
if (c == 'f') { // force
ret = VfdCloseImage(hDevice, TRUE);
}
else if (c == 'c') { // cancel
CloseHandle(hDevice);
return VFD_NG;
}
else {
goto retry;
}
}
}
CloseHandle(hDevice);
if (ret == ERROR_SUCCESS) {
PrintMessage(MSG_CLOSE_OK, target_min);
}
else if (ret != ERROR_NOT_READY) {
PrintMessage(MSG_CLOSE_NG, target_min);
printf("%s", SystemError(ret));
if (mode != OPERATION_FORCE) {
return VFD_NG;
}
}
target_min++;
}
return VFD_OK;
}
//
// Save the current image into a file
//
int Save(const char **args)
{
int mode = OPERATION_ASK;
ULONG target = TARGET_NONE;
CHAR file_name[MAX_PATH] = {0};
BOOL overwrite = FALSE;
BOOL truncate = FALSE;
HANDLE hDevice;
CHAR current[MAX_PATH] = {0};
VFD_MEDIA media_type;
VFD_FLAGS media_flags;
VFD_FILETYPE file_type;
DWORD file_attr;
ULONG image_size;
DWORD ret;
// check parameters
while (args && *args) {
if (!_stricmp(*args, "/f") ||
!_stricmp(*args, "/force")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_FORCE;
}
else if (!_stricmp(*args, "/q") ||
!_stricmp(*args, "/quit")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_QUIT;
}
else if (!_stricmp(*args, "/o") ||
!_stricmp(*args, "/over")) {
if (truncate || overwrite) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
overwrite = TRUE;
}
else if (!_stricmp(*args, "/t") ||
!_stricmp(*args, "/trunc")) {
if (truncate || overwrite) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
truncate = TRUE;
}
else if (isalnum(**args) &&
*(*args + 1) == ':' &&
*(*args + 2) == '\0') {
if (target != TARGET_NONE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
target = toupper(**args);
}
else if (**args == '/') {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_SAVE, help_progname);
return VFD_NG;
}
else {
strcpy(file_name, *args);
}
args++;
}
if (target == TARGET_NONE) {
target = '0';
PrintMessage(MSG_TARGET_NOTICE, target);
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is running
if (driver_state != SERVICE_RUNNING) {
PrintMessage(MSG_NOT_STARTED);
return VFD_NG;
}
// Open the target device
hDevice = VfdOpenDevice(target);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target);
printf("%s", SystemError(ret));
return VFD_NG;
}
// Get the current image info
ret = VfdGetImageInfo(hDevice, current, NULL,
&media_type, &media_flags, NULL, NULL);
if (ret != ERROR_SUCCESS) {
printf("%s", SystemError(ret));
CloseHandle(hDevice);
return VFD_NG;
}
if (media_type == VFD_MEDIA_NONE) {
printf("%s", SystemError(ERROR_NOT_READY));
CloseHandle(hDevice);
return VFD_NG;
}
if (file_name[0] == '\0') {
if (current[0] == '\0') {
PrintMessage(MSG_TARGET_REQUIRED);
CloseHandle(hDevice);
return VFD_NG;
}
strcpy(file_name, current);
}
if (!_stricmp(file_name, current)) {
// target is the current image file
if (!(media_flags & VFD_FLAG_DATA_MODIFIED)) {
// FILE disk (always up to date) or RAM disk is not modified
PrintMessage(MSG_TARGET_UP_TO_DATE);
CloseHandle(hDevice);
return VFD_OK;
}
overwrite = TRUE;
}
// check target file
ret = VfdCheckImageFile(file_name,
&file_attr, &file_type, &image_size);
if (ret == ERROR_SUCCESS) {
if (!overwrite && !truncate) {
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_OVERWRITE_NOTICE);
overwrite = TRUE;
}
else if (mode == OPERATION_QUIT) {
printf("%s", SystemError(ERROR_FILE_EXISTS));
CloseHandle(hDevice);
return VFD_NG;
}
else {
int c;
printf("%s", SystemError(ERROR_FILE_EXISTS));
c = InputChar(MSG_OVERWRITE_PROMPT, "otc");
if (c == 'o') {
overwrite = TRUE;
}
else if (c == 't') {
truncate = TRUE;
}
else {
CloseHandle(hDevice);
return VFD_NG;
}
}
}
}
else if (ret != ERROR_FILE_NOT_FOUND) {
printf("%s", SystemError(ret));
CloseHandle(hDevice);
return VFD_NG;
}
if (file_type == VFD_FILETYPE_ZIP) {
// Cannot update a zip file
PrintMessage(MSG_TARGET_IS_ZIP);
CloseHandle(hDevice);
return VFD_NG;
}
retry:
ret = VfdDismountVolume(
hDevice, (mode == OPERATION_FORCE));
if (ret == ERROR_ACCESS_DENIED) {
PrintMessage(MSG_LOCK_NG, target);
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_SAVE_FORCE);
}
else if (mode == OPERATION_QUIT) {
PrintMessage(MSG_SAVE_QUIT);
CloseHandle(hDevice);
return VFD_NG;
}
else {
int c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
if (c == 'r') { // retry
goto retry;
}
else if (c == 'f') { // force
VfdDismountVolume(hDevice, TRUE);
}
else { // cancel
CloseHandle(hDevice);
return VFD_NG;
}
}
}
else if (ret != ERROR_SUCCESS) {
printf("%s", SystemError(ret));
CloseHandle(hDevice);
return VFD_NG;
}
ret = VfdSaveImage(hDevice, file_name,
(overwrite || truncate), truncate);
CloseHandle(hDevice);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_SAVE_NG, target, file_name);
printf("%s", SystemError(ret));
return VFD_NG;
}
PrintMessage(MSG_SAVE_OK, target, file_name);
return VFD_OK;
}
//
// Enable/disable virtual media write protection
//
int Protect(const char **args)
{
#define PROTECT_NONE 0
#define PROTECT_ON 1
#define PROTECT_OFF 2
ULONG protect = PROTECT_NONE;
ULONG target = TARGET_NONE;
HANDLE hDevice;
DWORD ret;
// check parameters
while (args && *args) {
// Disk type options
if (_stricmp(*args, "/on") == 0) {
if (protect) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
protect = PROTECT_ON;
}
else if (_stricmp(*args, "/off") == 0) {
if (protect) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
protect = PROTECT_OFF;
}
else if (isalnum(**args)) {
if (target != TARGET_NONE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
target = toupper(**args);
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_PROTECT, help_progname);
return VFD_NG;
}
args++;
}
if (target == TARGET_NONE) {
target = '0';
PrintMessage(MSG_TARGET_NOTICE, target);
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is running
if (driver_state != SERVICE_RUNNING) {
PrintMessage(MSG_NOT_STARTED);
return VFD_NG;
}
// open the target drive
hDevice = VfdOpenDevice(target);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target);
printf("%s", SystemError(ret));
return VFD_NG;
}
if (protect) {
// change protect state
ret = VfdWriteProtect(
hDevice, (protect == PROTECT_ON));
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_PROTECT_NG, target);
printf("%s", SystemError(ret));
CloseHandle(hDevice);
return VFD_NG;
}
}
// get the current protect state
ret = VfdGetMediaState(hDevice);
CloseHandle(hDevice);
if (ret == ERROR_SUCCESS) {
PrintMessage(MSG_MEDIA_WRITABLE);
}
else if (ret == ERROR_WRITE_PROTECT) {
PrintMessage(MSG_MEDIA_PROTECTED);
}
else {
PrintMessage(MSG_GET_MEDIA_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
return VFD_OK;
}
//
// Format the virtual media with FAT12
//
int Format(const char **args)
{
int mode = OPERATION_ASK;
ULONG target = TARGET_NONE;
HANDLE hDevice;
DWORD ret;
// check parameters
while (args && *args) {
if (!_stricmp(*args, "/f") ||
!_stricmp(*args, "/force")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_FORCE;
}
else if (!_stricmp(*args, "/q") ||
!_stricmp(*args, "/quit")) {
if (mode != OPERATION_ASK) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
mode = OPERATION_QUIT;
}
else if (isalnum(**args)) {
if (target != TARGET_NONE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
target = toupper(**args);
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_FORMAT, help_progname);
return VFD_NG;
}
args++;
}
if (target == TARGET_NONE) {
target = '0';
PrintMessage(MSG_TARGET_NOTICE, target);
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is running
if (driver_state != SERVICE_RUNNING) {
PrintMessage(MSG_NOT_STARTED);
return VFD_NG;
}
// Open the device
hDevice = VfdOpenDevice(target);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target);
printf("%s", SystemError(ret));
return VFD_NG;
}
// check if the media is writable
ret = VfdGetMediaState(hDevice);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_FORMAT_NG, target);
printf("%s", SystemError(ret));
CloseHandle(hDevice);
return VFD_NG;
}
// format the media
retry:
ret = VfdDismountVolume(
hDevice, (mode == OPERATION_FORCE));
if (ret == ERROR_ACCESS_DENIED) {
PrintMessage(MSG_LOCK_NG, target);
if (mode == OPERATION_FORCE) {
PrintMessage(MSG_FORMAT_FORCE);
}
else if (mode == OPERATION_QUIT) {
PrintMessage(MSG_FORMAT_QUIT);
CloseHandle(hDevice);
return VFD_NG;
}
else {
int c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc");
if (c == 'r') { // retry
goto retry;
}
else if (c == 'f') { // force
VfdDismountVolume(hDevice, TRUE);
}
else { // cancel
CloseHandle(hDevice);
return VFD_NG;
}
}
}
else if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_LOCK_NG, target);
CloseHandle(hDevice);
return VFD_NG;
}
ret = VfdFormatMedia(hDevice);
CloseHandle(hDevice);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_FORMAT_NG, target);
printf("%s", SystemError(ret));
return VFD_NG;
}
// successful operation
PrintMessage(MSG_FORMAT_OK);
return VFD_OK;
}
//
// Assign a drive letter to a Virtual Floppy Drive
//
int Link(const char **args)
{
ULONG target_min = TARGET_NONE;
ULONG target_max = TARGET_NONE;
PCSTR letters = NULL;
BOOL global = TRUE;
HANDLE hDevice;
DWORD ret;
while (args && *args) {
if (!_stricmp(*args, "/g")) {
global = TRUE;
}
else if (!_stricmp(*args, "/l")) {
global = FALSE;
}
else if (isdigit(**args) || **args == '*') {
if (target_min != TARGET_NONE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
if (**args == '*') {
target_min = '0';
target_max = '0' + VFD_MAXIMUM_DEVICES;
}
else {
target_min = **args;
target_max = target_min + 1;
}
}
else if (isalpha(**args)) {
if (letters) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
letters = *args;
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_LINK, help_progname);
return VFD_NG;
}
args++;
}
if (target_min == TARGET_NONE) {
// default: drive 0
target_min = '0';
target_max = '1';
PrintMessage(MSG_TARGET_NOTICE, target_min);
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is running
if (driver_state != SERVICE_RUNNING) {
PrintMessage(MSG_NOT_STARTED);
return VFD_NG;
}
while (target_min < target_max) {
ULONG number;
CHAR letter;
hDevice = VfdOpenDevice(target_min);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target_min);
printf("%s", SystemError(ret));
target_min++;
continue;
}
ret = VfdGetDeviceNumber(hDevice, &number);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_ACCESS_NG, target_min);
printf("%s", SystemError(ret));
CloseHandle(hDevice);
target_min++;
continue;
}
if (letters && isalpha(*letters)) {
letter = (CHAR)toupper(*(letters++));
}
else {
letter = VfdChooseLetter();
}
if (letter) {
if (global) {
ret = VfdSetGlobalLink(hDevice, letter);
}
else {
ret = VfdSetLocalLink(hDevice, letter);
}
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_LINK_NG, number, letter);
printf("%s", SystemError(ret));
}
}
else {
PrintMessage(MSG_LINK_FULL);
}
PrintDriveLetter(hDevice, number);
CloseHandle(hDevice);
target_min++;
}
return VFD_OK;
}
//
// Remove a drive letter from a Virtual Floppy Drive
//
int Unlink(const char **args)
{
ULONG target_min = TARGET_NONE;
ULONG target_max = TARGET_NONE;
HANDLE hDevice;
DWORD ret;
while (args && *args) {
if ((isalnum(**args) || **args == '*') &&
(*(*args + 1) == ':' || *(*args + 1) == '\0')) {
if (target_min != TARGET_NONE) {
PrintMessage(MSG_DUPLICATE_ARGS, *args);
return VFD_NG;
}
if (**args == '*') {
target_min = '0';
target_max = '0' + VFD_MAXIMUM_DEVICES;
}
else {
target_min = **args;
target_max = target_min + 1;
}
}
else {
PrintMessage(MSG_UNKNOWN_OPTION, *args);
PrintMessage(MSG_HINT_ULINK, help_progname);
return VFD_NG;
}
args++;
}
if (target_min == TARGET_NONE) {
// default: drive 0
target_min = '0';
target_max = '1';
PrintMessage(MSG_TARGET_NOTICE, target_min);
}
// ensure that the driver is installed
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
return VFD_NG;
}
// ensure that the driver is up to date
if (CheckDriver() != VFD_OK) {
return VFD_NG;
}
// ensure that the driver is running
if (driver_state != SERVICE_RUNNING) {
PrintMessage(MSG_NOT_STARTED);
return VFD_NG;
}
while (target_min < target_max) {
ULONG number;
hDevice = VfdOpenDevice(target_min);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target_min);
printf("%s", SystemError(ret));
target_min++;
continue;
}
ret = VfdGetDeviceNumber(hDevice, &number);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_ACCESS_NG, target_min);
printf("%s", SystemError(ret));
CloseHandle(hDevice);
target_min++;
continue;
}
VfdSetGlobalLink(hDevice, 0);
VfdSetLocalLink(hDevice, 0);
PrintDriveLetter(hDevice, number);
CloseHandle(hDevice);
target_min++;
}
return VFD_OK;
}
//
// Print current driver state
// Command Line Parameters: None
//
int Status(const char **args)
{
HANDLE hDevice;
TCHAR path[MAX_PATH];
DWORD start_type;
DWORD version;
ULONG target;
DWORD ret;
UNREFERENCED_PARAMETER(args);
if (driver_state == VFD_NOT_INSTALLED) {
PrintMessage(MSG_NOT_INSTALLED);
}
else {
// get current driver config
ret = VfdGetDriverConfig(path, &start_type);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_GET_CONFIG_NG);
printf("%s", SystemError(ret));
return VFD_NG;
}
// print driver file path
PrintMessage(MSG_DRIVER_FILE, path);
// print driver version
version = 0;
if (driver_state == SERVICE_RUNNING) {
hDevice = VfdOpenDevice(0);
if (hDevice != INVALID_HANDLE_VALUE) {
ret = VfdGetDriverVersion(hDevice, &version);
CloseHandle(hDevice);
}
}
if (version == 0) {
ret = VfdCheckDriverFile(path, &version);
}
if (ret == ERROR_SUCCESS) {
PrintMessage(MSG_DRIVER_VERSION,
HIWORD(version) & 0x7fff,
LOWORD(version),
(version & 0x80000000) ? "(debug)" : "");
}
else {
PrintMessage(MSG_GET_VERSION_NG);
printf("%s", SystemError(ret));
}
// print driver start type
PrintMessage(MSG_START_TYPE);
switch (start_type) {
case SERVICE_AUTO_START:
PrintMessage(MSG_START_AUTO);
break;
case SERVICE_BOOT_START:
PrintMessage(MSG_START_BOOT);
break;
case SERVICE_DEMAND_START:
PrintMessage(MSG_START_DEMAND);
break;
case SERVICE_DISABLED:
PrintMessage(MSG_START_DISABLED);
break;
case SERVICE_SYSTEM_START :
PrintMessage(MSG_START_SYSTEM);
break;
default:
PrintMessage(MSG_UNKNOWN_LONG, start_type);
break;
}
// print current driver state
PrintMessage(MSG_DRIVER_STATUS);
switch (driver_state) {
case SERVICE_STOPPED:
PrintMessage(MSG_STATUS_STOPPED);
break;
case SERVICE_START_PENDING:
PrintMessage(MSG_STATUS_START_P);
break;
case SERVICE_STOP_PENDING:
PrintMessage(MSG_STATUS_STOP_P);
break;
case SERVICE_RUNNING:
PrintMessage(MSG_STATUS_RUNNING);
break;
case SERVICE_CONTINUE_PENDING:
PrintMessage(MSG_STATUS_CONT_P);
break;
case SERVICE_PAUSE_PENDING:
PrintMessage(MSG_STATUS_PAUSE_P);
break;
case SERVICE_PAUSED:
PrintMessage(MSG_STATUS_PAUSED);
break;
default:
PrintMessage(MSG_UNKNOWN_LONG, driver_state);
break;
}
}
// print shell extension status
printf("\n");
if (VfdCheckHandlers() == ERROR_SUCCESS) {
PrintMessage(MSG_SHELLEXT_ENABLED);
}
else {
PrintMessage(MSG_SHELLEXT_DISABLED);
}
// if driver is not running, no more info
if (driver_state != SERVICE_RUNNING) {
return VFD_OK;
}
// print image information
for (target = 0; target < VFD_MAXIMUM_DEVICES; target++) {
HANDLE hDevice = VfdOpenDevice(target);
if (hDevice == INVALID_HANDLE_VALUE) {
ret = GetLastError();
PrintMessage(MSG_ACCESS_NG, target + '0');
printf("%s", SystemError(ret));
return VFD_NG;
}
PrintImageInfo(hDevice);
CloseHandle(hDevice);
}
return VFD_OK;
}
//
// Print usage help
//
int Help(const char **args)
{
DWORD msg = MSG_HELP_GENERAL;
char *buf = NULL;
if (args && *args) {
int cmd = ParseHelpTopic(*args);
if (cmd < 0) {
msg = MSG_HELP_HELP;
}
else {
msg = HelpMsg[cmd].help;
}
}
FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL, msg, 0, (LPTSTR)&buf, 0,
(va_list *)&help_progname);
if (buf == NULL) {
printf("%s", SystemError(GetLastError()));
return VFD_NG;
}
ConsolePager(buf, TRUE);
LocalFree(buf);
return VFD_OK;
}
//
// Print version information
//
int Version(const char **args)
{
UNREFERENCED_PARAMETER(args);
printf(VFD_PRODUCT_DESC "\n" VFD_COPYRIGHT_STR "\n"
"http://chitchat.at.infoseek.co.jp/vmware/vfd.html\n");
return VFD_OK;
}
//
// Parse command parameter
//
int ParseCommand(const char *cmd)
{
#define CMD_MATCH_NONE -1
#define CMD_MATCH_MULTI -2
size_t len;
int idx;
int match;
// skip a leading '/'
if (*cmd == '/') {
cmd++;
}
if (*cmd == '\0') {
// empty command
return CMD_MATCH_NONE;
}
// find a match
len = strlen(cmd);
idx = 0;
match = CMD_MATCH_NONE;
while (Commands[idx].cmd) {
if (strlen(Commands[idx].cmd) >= len &&
!_strnicmp(cmd, Commands[idx].cmd, len)) {
if (match == CMD_MATCH_NONE) { // first match
match = idx;
}
else { // multiple matches
if (match != CMD_MATCH_MULTI) { // first time
PrintMessage(MSG_AMBIGUOUS_COMMAND, cmd);
printf("> %s ", Commands[match].cmd);
match = CMD_MATCH_MULTI;
}
printf("%s ", Commands[idx].cmd);
}
}
idx++;
}
if (match == CMD_MATCH_NONE) { // match not found
PrintMessage(MSG_UNKNOWN_COMMAND, cmd);
}
else if (match == CMD_MATCH_MULTI) { // multiple matches
printf("\n");
}
return match;
}
int ParseHelpTopic(const char *topic)
{
size_t len;
int idx;
int match;
if (*topic == '\0') {
// empty command
return CMD_MATCH_NONE;
}
// find a match
len = strlen(topic);
idx = 0;
match = CMD_MATCH_NONE;
while (HelpMsg[idx].keyword) {
if (strlen(HelpMsg[idx].keyword) >= len &&
!_strnicmp(topic, HelpMsg[idx].keyword, len)) {
if (match == CMD_MATCH_NONE) { // first match
match = idx;
}
else { // multiple matches
if (match != CMD_MATCH_MULTI) { // first time
PrintMessage(MSG_AMBIGUOUS_COMMAND, topic);
printf("> %s ", HelpMsg[match].keyword);
match = CMD_MATCH_MULTI;
}
printf("%s ", HelpMsg[idx].keyword);
}
}
idx++;
}
if (match == CMD_MATCH_NONE) { // match not found
PrintMessage(MSG_UNKNOWN_COMMAND, topic);
}
else if (match == CMD_MATCH_MULTI) { // multiple matches
printf("\n");
}
return match;
}
//
// Check driver version and update if necessary
//
int CheckDriver()
{
char path[MAX_PATH];
DWORD start;
// check installed driver file version
if (VfdGetDriverConfig(path, &start) == ERROR_SUCCESS &&
VfdCheckDriverFile(path, NULL) == ERROR_SUCCESS) {
HANDLE hDevice;
if (driver_state != SERVICE_RUNNING) {
return VFD_OK;
}
// check running driver version
hDevice = VfdOpenDevice(0);
if (hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
return VFD_OK;
}
}
PrintMessage(MSG_WRONG_DRIVER);
return VFD_NG;
}
//
// Print a prompt message and accept the reply input
//
int InputChar(ULONG msg, PCSTR ans)
{
HANDLE hStdIn;
INPUT_RECORD input;
DWORD result;
int reply;
PrintMessage(msg);
fflush(NULL);
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
FlushConsoleInputBuffer(hStdIn);
for (;;) {
ReadConsoleInput(hStdIn, &input, sizeof(input), &result);
if (input.EventType == KEY_EVENT &&
input.Event.KeyEvent.bKeyDown) {
reply = tolower(input.Event.KeyEvent.uChar.AsciiChar);
if (strchr(ans, reply)) {
break;
}
}
}
printf("%c\n", reply);
return reply;
}
//
// Print image information on a Virtual Floppy Drive
//
void PrintImageInfo(
HANDLE hDevice)
{
ULONG device_number;
CHAR file_name[MAX_PATH];
CHAR file_desc[MAX_PATH];
VFD_DISKTYPE disk_type;
VFD_MEDIA media_type;
VFD_FLAGS media_flags;
VFD_FILETYPE file_type;
ULONG image_size;
DWORD ret;
printf("\n");
// get current device number
ret = VfdGetDeviceNumber(hDevice, &device_number);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_GET_LINK_NG);
printf("%s", SystemError(ret));
device_number = (ULONG)-1;
}
// get current drive letters
PrintDriveLetter(hDevice, device_number);
// image file information
ret = VfdGetImageInfo(hDevice, file_name, &disk_type,
&media_type, &media_flags, &file_type, &image_size);
if (ret != ERROR_SUCCESS) {
PrintMessage(MSG_GET_FILE_NG);
printf("%s", SystemError(ret));
return;
}
// print image file information
if (media_type == VFD_MEDIA_NONE) {
PrintMessage(MSG_IMAGE_NONE);
return;
}
if (file_name[0]) {
PrintMessage(MSG_IMAGE_NAME, file_name);
VfdMakeFileDesc(file_desc, sizeof(file_desc),
file_type, image_size, GetFileAttributes(file_name));
}
else {
PrintMessage(MSG_IMAGE_NAME, "<RAM>");
VfdMakeFileDesc(file_desc, sizeof(file_desc),
VFD_FILETYPE_NONE, image_size, 0);
}
PrintMessage(MSG_FILE_DESC, file_desc);
if (disk_type == VFD_DISKTYPE_FILE) {
PrintMessage(MSG_DISKTYPE_FILE);
}
else {
if (media_flags & VFD_FLAG_DATA_MODIFIED) {
PrintMessage(MSG_DISKTYPE_RAM_DIRTY);
}
else {
PrintMessage(MSG_DISKTYPE_RAM_CLEAN);
}
}
// print other file info
PrintMessage(MSG_MEDIA_TYPE, VfdMediaTypeName(media_type));
if (media_flags & VFD_FLAG_WRITE_PROTECTED) {
PrintMessage(MSG_MEDIA_PROTECTED);
}
else {
PrintMessage(MSG_MEDIA_WRITABLE);
}
}
//
// Print drive letters on a virtual floppy drive
//
void PrintDriveLetter(
HANDLE hDevice,
ULONG nDrive)
{
CHAR letter;
PrintMessage(MSG_DRIVE_LETTER, nDrive);
VfdGetGlobalLink(hDevice, &letter);
if (isalpha(letter)) {
PrintMessage(MSG_PERSISTENT, toupper(letter));
}
while (VfdGetLocalLink(hDevice, &letter) == ERROR_SUCCESS &&
isalpha(letter)) {
PrintMessage(MSG_EPHEMERAL, toupper(letter));
}
printf("\n");
}
//
// Prints a text on screen a page a time
//
BOOL ConsolePager(char *pBuffer, BOOL bReset)
{
static int rows = 0;
char prompt[80];
int prompt_len = 0;
HANDLE hStdOut;
HANDLE hStdIn;
//
// prepare the console input and output handles
//
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
for (;;) {
CONSOLE_SCREEN_BUFFER_INFO info;
INPUT_RECORD input;
DWORD result;
DWORD mode;
int cols;
char *cur;
char save;
//
// Get the current console screen information
//
GetConsoleScreenBufferInfo(hStdOut, &info);
if (bReset || rows <= 0) {
rows = info.srWindow.Bottom - info.srWindow.Top - 1;
}
cols = info.dwSize.X;
// console window is too small for paging
if (rows <= 0) {
// print all text and exit
printf("%s", pBuffer);
break;
}
//
// find the tail of the text to be printed this time
//
cur = pBuffer;
save = '\0';
while (*cur) {
if (*(cur++) == '\n' || (cols--) == 0) {
// reached the end of a line
if (--rows == 0) {
// reached the end of a page
// insert a terminating NULL char
save = *cur;
*cur = '\0';
break;
}
cols = info.dwSize.X;
}
}
// print the current page
printf("%s", pBuffer);
// end of the whole text?
if (save == '\0') {
break;
}
//
// prompt for the next page
//
// prepare the prompt text
if (prompt_len == 0) {
prompt_len = FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, MSG_PAGER_PROMPT, 0,
prompt, sizeof(prompt), NULL);
if (prompt_len == 0) {
strcpy(prompt, "Press any key to continue...");
prompt_len = strlen(prompt);
}
}
// get the current console input mode
GetConsoleMode(hStdIn, &mode);
// change the mode to receive Ctrl+C as a regular input
SetConsoleMode(hStdIn, (mode & ~ENABLE_PROCESSED_INPUT));
// get the current cursor position
GetConsoleScreenBufferInfo(hStdOut, &info);
// print the prompt text
WriteConsoleOutputCharacter(hStdOut, prompt,
prompt_len, info.dwCursorPosition, &result);
// reverse the text color
FillConsoleOutputAttribute(hStdOut,
(WORD)(info.wAttributes | COMMON_LVB_REVERSE_VIDEO),
prompt_len, info.dwCursorPosition, &result);
// move cursor to the end of the prompt text
info.dwCursorPosition.X =
(short)(info.dwCursorPosition.X + prompt_len);
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
// wait for a key press event
FlushConsoleInputBuffer(hStdIn);
do {
ReadConsoleInput(hStdIn, &input, sizeof(input), &result);
}
while (input.EventType != KEY_EVENT ||
!input.Event.KeyEvent.bKeyDown ||
!input.Event.KeyEvent.uChar.AsciiChar);
// restore the original cursor position
info.dwCursorPosition.X =
(short)(info.dwCursorPosition.X - prompt_len);
SetConsoleCursorPosition(hStdOut, info.dwCursorPosition);
// delete the prompt text
FillConsoleOutputCharacter(hStdOut, ' ',
prompt_len, info.dwCursorPosition, &result);
// restore the text attribute to norml
FillConsoleOutputAttribute(hStdOut, info.wAttributes,
prompt_len, info.dwCursorPosition, &result);
// restore the original console mode
SetConsoleMode(hStdIn, mode);
// check if the input was 'q', <esc> or <Ctrl+C> ?
if (input.Event.KeyEvent.uChar.AsciiChar == VK_CANCEL ||
input.Event.KeyEvent.uChar.AsciiChar == VK_ESCAPE ||
tolower(input.Event.KeyEvent.uChar.AsciiChar) == 'q') {
// cancelled by the user
return FALSE;
}
//
// process the next page
//
*cur = save;
pBuffer = cur;
}
return TRUE;
}
//
// Format and print a message text
//
void PrintMessage(UINT msg, ...)
{
char *buf = NULL;
va_list list;
va_start(list, msg);
if (FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, msg, 0, (LPTSTR)&buf, 0, &list)) {
printf("%s", buf);
}
else {
printf("Unknown Message ID %u\n", msg);
}
va_end(list);
if (buf) {
LocalFree(buf);
}
}
//
// Return a system error message text
//
const char *SystemError(DWORD err)
{
static char msg[256];
if (!FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, 0, msg, sizeof(msg), NULL)) {
#ifndef __REACTOS__
sprintf(msg, "Unknown system error %lu (0x%08x)\n", err, err);
#else
sprintf(msg, "Unknown system error %lu (0x%08lx)\n", err, err);
#endif
}
return msg;
}
//
// Convert a path to match the case of names on the disk
//
void ConvertPathCase(char *src, char *dst)
{
HANDLE hFind;
WIN32_FIND_DATA find;
char *p;
p = dst;
if (*src == '\"') {
src++;
}
if (*(src + strlen(src) - 1) == '\"') {
*(src + strlen(src) - 1) = '\0';
}
//
// handle drive / remote server name
//
if (isalpha(*src) && *(src + 1) == ':') {
// drive name
*(p++) = (char)toupper(*src);
strcpy(p++, ":\\");
src += 2;
}
else if (*src == '\\' || *src == '/') {
// absolute path or remote name
if ((*(src + 1) == '\\' || *(src + 1) == '/') &&
*(src + 2) && *(src + 2) != '\\' && *(src + 2) != '/') {
// remote path
*(p++) = '\\';
*(p++) = '\\';
src += 2;
while (*src && *src != '\\' && *src != '/') {
*(p++) = *(src++);
}
}
strcpy(p, "\\");
}
else {
*p = '\0';
}
// skip redundant '\'
while (*src == '\\' || *src == '/') {
src++;
}
// process the path
while (*src) {
char *q = src;
// separate the next part
while (*q && *q != '\\' && *q != '/') {
q++;
}
if ((q - src) == 2 && !strncmp(src, "..", 2)) {
// parent dir - copy as it is
if (p != dst) {
*p++ = '\\';
}
strcpy(p, "..");
p += 2;
}
else if ((q - src) > 1 || *src != '.') {
// path name other than "."
if (p != dst) {
*(p++) = '\\';
}
strncpy(p, src, (q - src));
*(p + (q - src)) = '\0';
hFind = FindFirstFile(dst, &find);
if (hFind == INVALID_HANDLE_VALUE) {
strcpy(p, src);
break;
}
FindClose(hFind);
strcpy(p, find.cFileName);
p += strlen(p);
}
// skip trailing '\'s
while (*q == '\\' || *q == '/') {
q++;
}
src = q;
}
}