/* 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 #include #include #include #include #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 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 : ""); 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, ""); 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', or ? 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; } }