1 /* 2 vfdcmd.c 3 4 Virtual Floppy Drive for Windows 5 Driver control program (console version) 6 7 Copyright (C) 2003-2008 Ken Kato 8 */ 9 10 #ifdef __cplusplus 11 #pragma message(__FILE__": Compiled as C++ for testing purpose.") 12 #endif // __cplusplus 13 14 #define WIN32_LEAN_AND_MEAN 15 #define _CRTDBG_MAP_ALLOC 16 #include <windows.h> 17 #include <stdio.h> 18 #include <stdarg.h> 19 #include <stdlib.h> 20 #include <crtdbg.h> 21 22 #ifndef INVALID_FILE_ATTRIBUTES 23 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) 24 #endif // INVALID_FILE_ATTRIBUTES 25 26 #include "vfdtypes.h" 27 #include "vfdapi.h" 28 #include "vfdver.h" 29 #include "vfdmsg.h" 30 31 // 32 // current driver state 33 // 34 static DWORD driver_state = VFD_NOT_INSTALLED; 35 36 // 37 // interactive flag 38 // 39 static const char *help_progname = "VFD.EXE "; 40 41 // 42 // command functions return value 43 // 44 #define VFD_OK 0 45 #define VFD_NG 1 46 47 // 48 // operation mode 49 // 50 #define OPERATION_ASK 0 // ask user on error 51 #define OPERATION_QUIT 1 // quits on error 52 #define OPERATION_FORCE 2 // force on error 53 54 // 55 // invalid target number 56 // 57 #define TARGET_NONE (ULONG)-1 58 59 // 60 // command processing functions 61 // 62 typedef int (*cmdfnc)(const char **args); 63 64 static int Install(const char **args); 65 static int Remove(const char **args); 66 static int Config(const char **args); 67 static int Start(const char **args); 68 static int Stop(const char **args); 69 static int Shell(const char **args); 70 static int Open(const char **args); 71 static int Close(const char **args); 72 static int Save(const char **args); 73 static int Protect(const char **args); 74 static int Format(const char **args); 75 static int Link(const char **args); 76 static int Unlink(const char **args); 77 static int Status(const char **args); 78 static int Help(const char **args); 79 static int Version(const char **args); 80 81 // 82 // Command table 83 // 84 static const struct { 85 char *cmd; // command string 86 int max_args; // maximum allowed number of argc 87 cmdfnc func; // command processing function 88 DWORD hint; // command hint message id 89 } 90 Commands[] = { 91 {"INSTALL", 2, Install, MSG_HINT_INSTALL}, 92 {"REMOVE", 1, Remove, MSG_HINT_REMOVE }, 93 {"CONFIG", 1, Config, MSG_HINT_CONFIG }, 94 {"START", 0, Start, MSG_HINT_START }, 95 {"STOP", 1, Stop, MSG_HINT_STOP }, 96 {"SHELL", 1, Shell, MSG_HINT_SHELL }, 97 {"OPEN", 6, Open, MSG_HINT_OPEN }, 98 {"CLOSE", 2, Close, MSG_HINT_CLOSE }, 99 {"SAVE", 3, Save, MSG_HINT_SAVE, }, 100 {"PROTECT", 2, Protect, MSG_HINT_PROTECT}, 101 {"FORMAT", 2, Format, MSG_HINT_FORMAT }, 102 {"LINK", 3, Link, MSG_HINT_LINK }, 103 {"ULINK", 1, Unlink, MSG_HINT_ULINK }, 104 {"STATUS", 0, Status, MSG_HINT_STATUS }, 105 {"HELP", 1, Help, MSG_HELP_HELP }, 106 {"?", 1, Help, MSG_HELP_HELP }, 107 {"VERSION", 0, Version, MSG_HINT_VERSION}, 108 {0, 0, 0, 0} 109 }; 110 111 // 112 // Help message table 113 // 114 static const struct { 115 char *keyword; // help keyword 116 DWORD help; // help message id 117 } 118 HelpMsg[] = { 119 {"GENERAL", MSG_HELP_GENERAL}, 120 {"CONSOLE", MSG_HELP_CONSOLE}, 121 {"INSTALL", MSG_HELP_INSTALL}, 122 {"REMOVE", MSG_HELP_REMOVE }, 123 {"CONFIG", MSG_HELP_CONFIG }, 124 {"START", MSG_HELP_START }, 125 {"STOP", MSG_HELP_STOP }, 126 {"SHELL", MSG_HELP_SHELL }, 127 {"OPEN", MSG_HELP_OPEN }, 128 {"CLOSE", MSG_HELP_CLOSE }, 129 {"SAVE", MSG_HELP_SAVE }, 130 {"PROTECT", MSG_HELP_PROTECT}, 131 {"FORMAT", MSG_HELP_FORMAT }, 132 {"LINK", MSG_HELP_LINK }, 133 {"ULINK", MSG_HELP_ULINK }, 134 {"STATUS", MSG_HELP_STATUS }, 135 {"HELP", MSG_HELP_HELP }, 136 {"VERSION", MSG_HINT_VERSION}, 137 {0, 0} 138 }; 139 140 // 141 // local functions 142 // 143 static int InteractiveConsole(); 144 static int ProcessCommandLine(int argc, const char **args); 145 static int ParseCommand(const char *cmd); 146 static int ParseHelpTopic(const char *topic); 147 static int CheckDriver(); 148 static int InputChar(ULONG msg, PCSTR ans); 149 static void PrintImageInfo(HANDLE hDevice); 150 static void PrintDriveLetter(HANDLE hDevice, ULONG nDrive); 151 static void PrintMessage(UINT msg, ...); 152 static BOOL ConsolePager(char *pBuffer, BOOL bReset); 153 static const char *SystemError(DWORD err); 154 static void ConvertPathCase(char *src, char *dst); 155 156 // 157 // utility macro 158 // 159 #define IS_WINDOWS_NT() ((GetVersion() & 0xff) < 5) 160 161 // 162 // main 163 // 164 int main(int argc, const char **argv) 165 { 166 #ifdef _DEBUG 167 168 // output vfd.exe command reference text 169 170 if (*(argv + 1) && !_stricmp(*(argv + 1), "doc")) { 171 int idx = 0; 172 char *buf = ""; 173 174 printf("\r\n VFD.EXE Command Reference\r\n"); 175 176 while (HelpMsg[idx].keyword) { 177 int len = strlen(HelpMsg[idx].keyword); 178 179 printf( 180 "\r\n\r\n" 181 "====================\r\n" 182 "%*s\r\n" 183 "====================\r\n" 184 "\r\n", 185 (20 + len) / 2, HelpMsg[idx].keyword); 186 187 FormatMessage( 188 FORMAT_MESSAGE_FROM_HMODULE | 189 FORMAT_MESSAGE_ALLOCATE_BUFFER | 190 FORMAT_MESSAGE_ARGUMENT_ARRAY, 191 NULL, HelpMsg[idx].help, 0, 192 (LPTSTR)&buf, 0, (va_list *)&help_progname); 193 194 printf("%s", buf); 195 196 LocalFree(buf); 197 198 idx++; 199 } 200 201 return 0; 202 } 203 #endif 204 205 // Reports memory leaks at process termination 206 207 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF); 208 209 // Check the operating system version 210 211 if (!VfdIsValidPlatform()) { 212 PrintMessage(MSG_WRONG_PLATFORM); 213 return VFD_NG; 214 } 215 216 if (argc < 2) { 217 // If no parameter is given, enter the interactive mode 218 219 return InteractiveConsole(); 220 } 221 else { 222 // Perform a single operation 223 224 return ProcessCommandLine(argc - 1, argv + 1); 225 } 226 } 227 228 // 229 // VFD interactive console 230 // 231 int InteractiveConsole() 232 { 233 char input[1024]; // user input buffer 234 235 int argc; // number of args in the user input 236 char *args[10]; // args to pass to command functions 237 238 char sepa; // argument separator 239 char *p; // work pointer 240 241 // Disable the system default Ctrl+C handler 242 243 SetConsoleCtrlHandler(NULL, TRUE); 244 245 // Set the console title 246 247 SetConsoleTitle(VFD_PRODUCT_DESC); 248 249 // print version information and the console hint text 250 251 Version(NULL); 252 253 PrintMessage(MSG_CONSOLE_HINT); 254 255 // set interactive flag to exclude "VFD.EXE" from help text 256 257 help_progname = ""; 258 259 // process user input 260 261 for (;;) { 262 263 // print the prompt 264 265 printf("[VFD] "); 266 fflush(stdout); 267 268 // read user input 269 270 fflush(stdin); 271 p = fgets(input, sizeof(input), stdin); 272 273 if (p == NULL) { 274 275 // most likely <ctrl+c> 276 277 printf("exit\n"); 278 break; 279 } 280 281 // skip leading blank characters 282 283 while (*p == ' ' || *p == '\t' || *p == '\n') { 284 p++; 285 } 286 287 if (*p == '\0') { 288 289 // empty input 290 291 continue; 292 } 293 294 // handle external commands 295 296 if (!_strnicmp(p, "dir", 3) || 297 !_strnicmp(p, "attrib", 6)) { 298 299 // special cases - frequently used commands 300 // pass these to system() even without '.' 301 302 system(p); 303 printf("\n"); 304 continue; 305 } 306 else if (*p == '.') { 307 308 // external command 309 310 system(p + 1); 311 printf("\n"); 312 continue; 313 } 314 315 // split the input line into parameters (10 parameters max) 316 317 argc = 0; 318 ZeroMemory(args, sizeof(args)); 319 320 do { 321 // top of a parameter 322 323 args[argc++] = p; 324 325 // is the parameter quoted? 326 327 if (*p == '\"' || *p == '\'') { 328 sepa = *(p++); 329 } 330 else { 331 sepa = ' '; 332 } 333 334 // search the end of the parameter 335 336 while (*p && *p != '\n') { 337 if (sepa == ' ') { 338 if (*p == '\t' || *p == ' ') { 339 break; // tail of a non-quoted parameter 340 } 341 } 342 else { 343 if (*p == sepa) { 344 sepa = ' '; // close quote 345 } 346 } 347 p++; 348 } 349 350 // terminate the parameter 351 352 if (*p) { 353 *(p++) = '\0'; 354 } 355 356 // skip trailing blank characters 357 358 while (*p == ' ' || *p == '\t' || *p == '\n') { 359 p++; 360 } 361 362 if (*p == '\0') { 363 364 // end of the input line - no more args 365 366 break; 367 } 368 } 369 while (argc < sizeof(args) / sizeof(args[0])); 370 371 // check the first parameter for special commands 372 373 if (!_stricmp(args[0], "exit") || 374 !_stricmp(args[0], "quit") || 375 !_stricmp(args[0], "bye")) { 376 377 // exit command 378 379 break; 380 } 381 else if (!_stricmp(args[0], "cd") || 382 !_stricmp(args[0], "chdir")) { 383 384 // internal change directory command 385 386 if (args[1]) { 387 char path[MAX_PATH]; 388 int i; 389 390 // ignore the /d option (of the standard cd command) 391 392 if (_stricmp(args[1], "/d")) { 393 i = 1; 394 } 395 else { 396 i = 2; 397 } 398 399 p = args[i]; 400 401 if (*p == '\"' || *p == '\'') { 402 403 // the parameter is quoted -- remove quotations 404 405 p++; 406 407 while (*p && *p != *args[i]) { 408 p++; 409 } 410 411 args[i]++; // skip a leading quote 412 *p = '\0'; // remove a trailing quote 413 } 414 else { 415 416 // the parameter is not quoted 417 // -- concatenate params to allow spaces in unquoted path 418 419 while (i < argc - 1) { 420 *(args[i] + strlen(args[i])) = ' '; 421 i++; 422 } 423 } 424 425 // Match the case of the path to the name on the disk 426 427 ConvertPathCase(p, path); 428 429 if (!SetCurrentDirectory(path)) { 430 DWORD ret = GetLastError(); 431 432 if (ret == ERROR_FILE_NOT_FOUND) { 433 ret = ERROR_PATH_NOT_FOUND; 434 } 435 436 printf("%s", SystemError(ret)); 437 } 438 } 439 else { 440 if (!GetCurrentDirectory(sizeof(input), input)) { 441 printf("%s", SystemError(GetLastError())); 442 } 443 else { 444 printf("%s\n", input); 445 } 446 } 447 } 448 else if (isalpha(*args[0]) && 449 *(args[0] + 1) == ':' && 450 *(args[0] + 2) == '\0') { 451 452 // internal change drive command 453 454 *args[0] = (char)toupper(*args[0]); 455 *(args[0] + 2) = '\\'; 456 *(args[0] + 3) = '\0'; 457 458 if (!SetCurrentDirectory(args[0])) { 459 printf("%s", SystemError(GetLastError())); 460 } 461 } 462 else { 463 464 // perform the requested VFD command 465 466 ProcessCommandLine(argc, (const char **)args); 467 } 468 469 printf("\n"); 470 } 471 472 return VFD_OK; 473 } 474 475 // 476 // process a single command 477 // 478 int ProcessCommandLine(int argc, const char **args) 479 { 480 int cmd; 481 DWORD ret; 482 483 // 484 // Decide a command to perform 485 // 486 cmd = ParseCommand(*args); 487 488 if (cmd < 0) { 489 490 // no matching command 491 492 return VFD_NG; 493 } 494 495 if (*(++args) && 496 (!strcmp(*args, "/?") || 497 !_stricmp(*args, "/h"))) { 498 499 // print a short hint for the command 500 501 PrintMessage(Commands[cmd].hint); 502 return VFD_NG; 503 } 504 505 if (--argc > Commands[cmd].max_args) { 506 507 // too many parameters for the command 508 509 PrintMessage(MSG_TOO_MANY_ARGS); 510 PrintMessage(Commands[cmd].hint); 511 return VFD_NG; 512 } 513 514 // Get the current driver state 515 516 ret = VfdGetDriverState(&driver_state); 517 518 if (ret != ERROR_SUCCESS) { 519 PrintMessage(MSG_GET_STAT_NG); 520 printf("%s", SystemError(ret)); 521 return VFD_NG; 522 } 523 524 // Perform the requested operation 525 526 return (*Commands[cmd].func)(args); 527 } 528 529 // 530 // Install the Virtual Floppy Driver 531 // Command Line Parameters: 532 // (optional) driver file path - default to executive's dir 533 // (optional) auto start switch - default to demand start 534 // 535 int Install(const char **args) 536 { 537 const char *install_path = NULL; 538 DWORD start_type = SERVICE_DEMAND_START; 539 540 DWORD ret; 541 542 // process parameters 543 544 while (args && *args) { 545 546 if (!_stricmp(*args, "/a") || 547 !_stricmp(*args, "/auto")) { 548 549 if (start_type != SERVICE_DEMAND_START) { 550 PrintMessage(MSG_DUPLICATE_ARGS, *args); 551 return VFD_NG; 552 } 553 /* 554 if (IS_WINDOWS_NT()) { 555 556 // On Windows NT, SYSTEM start drivers must be placed 557 // under the winnt\system32 directory. Since I don't 558 // care to handle driver file copying, I use the AUTO 559 // start method for Windows NT. 560 561 start_type = SERVICE_AUTO_START; 562 } 563 else { 564 565 // On Windows XP, the VFD driver must be running when 566 // the shell starts -- otherwise the shell doesn't 567 // recognize the VFD drives. Since Windows XP allows 568 // SYSTEM start drivers to be placed in any local 569 // directories, I use the SYSTEM start method here. 570 // 571 // This is not an issue when the driver is started 572 // manually because in that case VFD.EXE and VFDWIN.EXE 573 // notify the shell of the VFD drives. 574 // 575 // On Windows 2000 both SYSTEM and AUTO work fine. 576 577 start_type = SERVICE_SYSTEM_START; 578 } 579 */ 580 // On second thought -- Win2K / XP mount manager assigns 581 // arbitrary drive letters to all drives it finds during 582 // the system start up. There is no way to prevent it 583 // until the driver is fully PnP compatible, so I'd settle 584 // for AUTO start for the time being. 585 586 start_type = SERVICE_AUTO_START; 587 } 588 else if (**args == '/') { 589 PrintMessage(MSG_UNKNOWN_OPTION, *args); 590 PrintMessage(MSG_HINT_INSTALL, help_progname); 591 return VFD_NG; 592 } 593 else { 594 if (install_path) { 595 PrintMessage(MSG_DUPLICATE_ARGS, "path"); 596 return VFD_NG; 597 } 598 599 install_path = *args; 600 } 601 602 args++; 603 } 604 605 // already installed? 606 607 if (driver_state != VFD_NOT_INSTALLED) { 608 PrintMessage(MSG_DRIVER_EXISTS); 609 return VFD_NG; 610 } 611 612 // install the driver 613 614 ret = VfdInstallDriver( 615 install_path, 616 start_type); 617 618 if (ret != ERROR_SUCCESS) { 619 PrintMessage(MSG_INSTALL_NG); 620 printf("%s", SystemError(ret)); 621 return VFD_NG; 622 } 623 624 // Get the latest driver state 625 626 ret = VfdGetDriverState(&driver_state); 627 628 if (ret != ERROR_SUCCESS) { 629 PrintMessage(MSG_GET_STAT_NG); 630 printf("%s", SystemError(ret)); 631 return VFD_NG; 632 } 633 634 // operation successfull 635 636 PrintMessage(MSG_INSTALL_OK); 637 638 return VFD_OK; 639 } 640 641 // 642 // Remove Virtual Floppy Driver from system 643 // Command Line Parameters: 644 // [/F | /FORCE | /Q | /QUIT] 645 // /F forces remove operation if the driver cannot be stopped 646 // /Q quits remove operation if the driver cannot be stopped 647 // 648 int Remove(const char **args) 649 { 650 int mode = OPERATION_ASK; 651 const char *stop_params[] = { NULL, NULL }; 652 DWORD ret; 653 int idx; 654 655 // parse parameters 656 657 while (args && *args) { 658 659 if (!_stricmp(*args, "/f") || 660 !_stricmp(*args, "/force")) { 661 662 if (mode != OPERATION_ASK) { 663 PrintMessage(MSG_DUPLICATE_ARGS, *args); 664 return VFD_NG; 665 } 666 667 mode = OPERATION_FORCE; 668 stop_params[0] = *args; 669 } 670 else if (!_stricmp(*args, "/q") || 671 !_stricmp(*args, "/quit")) { 672 673 if (mode != OPERATION_ASK) { 674 PrintMessage(MSG_DUPLICATE_ARGS, *args); 675 return VFD_NG; 676 } 677 678 mode = OPERATION_QUIT; 679 stop_params[0] = *args; 680 } 681 else { 682 PrintMessage(MSG_UNKNOWN_OPTION, *args); 683 PrintMessage(MSG_HINT_REMOVE, help_progname); 684 return VFD_NG; 685 } 686 687 args++; 688 } 689 690 // ensure the driver is installed 691 692 if (driver_state == VFD_NOT_INSTALLED) { 693 PrintMessage(MSG_NOT_INSTALLED); 694 return VFD_NG; 695 } 696 697 // ensure the driver is stopped 698 699 if (driver_state == SERVICE_RUNNING) { 700 701 // Try to stop with the same command line option (/F or /Q) 702 703 while (Stop(stop_params) != VFD_OK) { 704 705 // stop failed 706 707 if (mode == OPERATION_FORCE) { 708 PrintMessage(MSG_REMOVE_FORCE); 709 break; 710 } 711 else if (mode == OPERATION_QUIT) { 712 PrintMessage(MSG_REMOVE_QUIT); 713 return VFD_NG; 714 } 715 else { 716 int c; 717 718 PrintMessage(MSG_REMOVE_WARN); 719 720 c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc"); 721 722 if (c == 'f') { // force 723 break; 724 } 725 else if (c == 'c') { // cancel 726 return VFD_NG; 727 } 728 } 729 } 730 } 731 732 // remove the driver 733 734 ret = VfdRemoveDriver(); 735 736 if (ret != ERROR_SUCCESS) { 737 PrintMessage(MSG_REMOVE_NG); 738 printf("%s", SystemError(ret)); 739 return VFD_NG; 740 } 741 742 // Wait for the driver to be actually removed for 3 secs Max. 743 744 for (idx = 0; idx < 10; idx++) { 745 746 ret = VfdGetDriverState(&driver_state); 747 748 if (ret != ERROR_SUCCESS) { 749 PrintMessage(MSG_GET_STAT_NG); 750 printf("%s", SystemError(ret)); 751 return VFD_NG; 752 } 753 754 if (driver_state == VFD_NOT_INSTALLED) { 755 break; 756 } 757 758 Sleep(300); 759 } 760 761 if (driver_state != VFD_NOT_INSTALLED) { 762 PrintMessage(MSG_REMOVE_PENDING); 763 return VFD_NG; 764 } 765 766 // operation successful 767 768 PrintMessage(MSG_REMOVE_OK); 769 770 return VFD_OK; 771 } 772 773 // 774 // Configure the Virtual Floppy Driver 775 // Command Line Parameters: 776 // /auto, /manual 777 // 778 int Config(const char **args) 779 { 780 DWORD start_type = SERVICE_DISABLED; 781 DWORD ret; 782 783 while (args && *args) { 784 if (!_stricmp(*args, "/a") || 785 !_stricmp(*args, "/auto")) { 786 787 if (start_type != SERVICE_DISABLED) { 788 PrintMessage(MSG_DUPLICATE_ARGS, *args); 789 return VFD_NG; 790 } 791 792 start_type = SERVICE_AUTO_START; 793 } 794 else if (!_stricmp(*args, "/m") || 795 !_stricmp(*args, "/manual")) { 796 797 if (start_type != SERVICE_DISABLED) { 798 PrintMessage(MSG_DUPLICATE_ARGS, *args); 799 return VFD_NG; 800 } 801 802 start_type = SERVICE_DEMAND_START; 803 } 804 else { 805 PrintMessage(MSG_UNKNOWN_OPTION, *args); 806 PrintMessage(MSG_HINT_CONFIG, help_progname); 807 return VFD_NG; 808 } 809 810 args++; 811 } 812 813 if (start_type == SERVICE_DISABLED) { 814 // no parameter is specified 815 PrintMessage(MSG_HINT_CONFIG, help_progname); 816 return VFD_NG; 817 } 818 819 // ensure that the driver is installed 820 821 if (driver_state == VFD_NOT_INSTALLED) { 822 PrintMessage(MSG_NOT_INSTALLED); 823 return VFD_NG; 824 } 825 826 // ensure that the driver is up to date 827 828 if (CheckDriver() != VFD_OK) { 829 return VFD_NG; 830 } 831 832 // configure the driver 833 834 ret = VfdConfigDriver(start_type); 835 836 if (ret != ERROR_SUCCESS) { 837 PrintMessage(MSG_CONFIG_NG); 838 printf("%s", SystemError(ret)); 839 return VFD_NG; 840 } 841 842 // operation successfull 843 844 PrintMessage(MSG_CONFIG_OK); 845 846 return VFD_OK; 847 } 848 849 // 850 // Start the Virtual Floppy Driver 851 // Command Line Parameters: None 852 // 853 int Start(const char **args) 854 { 855 DWORD ret; 856 857 UNREFERENCED_PARAMETER(args); 858 859 // ensure that the driver is installed 860 861 if (driver_state == VFD_NOT_INSTALLED && 862 Install(NULL) != VFD_OK) { 863 return VFD_NG; 864 } 865 866 // ensure that the driver is up to date 867 868 if (CheckDriver() != VFD_OK) { 869 return VFD_NG; 870 } 871 872 // ensure that the driver is not running 873 874 if (driver_state == SERVICE_RUNNING) { 875 PrintMessage(MSG_ALREADY_RUNNING); 876 return VFD_NG; 877 } 878 879 // start the driver 880 881 ret = VfdStartDriver(&driver_state); 882 883 if (ret != ERROR_SUCCESS) { 884 PrintMessage(MSG_START_NG); 885 printf("%s", SystemError(ret)); 886 return VFD_NG; 887 } 888 889 // operation successfull 890 891 PrintMessage(MSG_START_OK); 892 893 return VFD_OK; 894 } 895 896 // 897 // Stop the Virtual Floppy Driver 898 // Command Line Parameters: 899 // /FORCE | /F Forces the operation on error 900 // /QUIT | /Q Quits the operation on error 901 // 902 int Stop(const char **args) 903 { 904 int mode = OPERATION_ASK; 905 const char *close_params[] = { "*", NULL, NULL }; 906 DWORD ret; 907 908 while (args && *args) { 909 if (!_stricmp(*args, "/f") || 910 !_stricmp(*args, "/force")) { 911 912 if (mode != OPERATION_ASK) { 913 PrintMessage(MSG_DUPLICATE_ARGS, *args); 914 return VFD_NG; 915 } 916 917 mode = OPERATION_FORCE; 918 919 // parameter to pass to the Close() function 920 close_params[1] = *args; 921 } 922 else if (!_stricmp(*args, "/q") || 923 !_stricmp(*args, "/quit")) { 924 925 if (mode != OPERATION_ASK) { 926 PrintMessage(MSG_DUPLICATE_ARGS, *args); 927 return VFD_NG; 928 } 929 930 mode = OPERATION_QUIT; 931 932 // parameter to pass to the Close() function 933 close_params[1] = *args; 934 } 935 else { 936 PrintMessage(MSG_UNKNOWN_OPTION, *args); 937 PrintMessage(MSG_HINT_STOP, help_progname); 938 return VFD_NG; 939 } 940 941 args++; 942 } 943 944 // ensure that the driver is installed 945 946 if (driver_state == VFD_NOT_INSTALLED) { 947 PrintMessage(MSG_NOT_INSTALLED); 948 return VFD_NG; 949 } 950 951 // ensure that the driver is running 952 953 if (driver_state == SERVICE_STOPPED) { 954 PrintMessage(MSG_NOT_STARTED); 955 return VFD_NG; 956 } 957 958 // ensure that all drives are empty 959 960 if (driver_state == SERVICE_RUNNING) { 961 962 // Try to close drives with the same operation mode (/F or /Q) 963 964 while (Close(close_params) != VFD_OK) { 965 966 // close failed 967 968 if (mode == OPERATION_FORCE) { 969 PrintMessage(MSG_STOP_FORCE); 970 break; 971 } 972 else if (mode == OPERATION_QUIT) { 973 PrintMessage(MSG_STOP_QUIT); 974 return VFD_NG; 975 } 976 else { 977 int c; 978 979 PrintMessage(MSG_STOP_WARN); 980 981 c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc"); 982 983 if (c == 'f') { // force 984 break; 985 } 986 else if (c == 'c') { // cancel 987 return VFD_NG; 988 } 989 } 990 } 991 } 992 993 // stop the driver 994 995 ret = VfdStopDriver(&driver_state); 996 997 if (ret != ERROR_SUCCESS) { 998 PrintMessage(MSG_STOP_NG); 999 printf("%s", SystemError(ret)); 1000 return VFD_NG; 1001 } 1002 1003 if (driver_state != SERVICE_STOPPED) { 1004 PrintMessage(MSG_STOP_PENDING); 1005 return VFD_NG; 1006 } 1007 1008 // operation successful 1009 1010 PrintMessage(MSG_STOP_OK); 1011 1012 return VFD_OK; 1013 } 1014 1015 // 1016 // Enable / Disable the shell extension 1017 // Command Line Parameters: 1018 // (optional) /ON or /OFF 1019 // 1020 int Shell(const char **args) 1021 { 1022 DWORD ret; 1023 1024 ret = VfdCheckHandlers(); 1025 1026 if (ret != ERROR_SUCCESS && 1027 ret != ERROR_PATH_NOT_FOUND && 1028 ret != ERROR_FILE_NOT_FOUND) { 1029 PrintMessage(MSG_GET_SHELLEXT_NG); 1030 printf("%s", SystemError(ret)); 1031 return VFD_NG; 1032 } 1033 1034 if (args && *args) { 1035 if (_stricmp(*args, "/on") == 0) { 1036 if (ret != ERROR_SUCCESS) { 1037 ret = VfdRegisterHandlers(); 1038 1039 if (ret != ERROR_SUCCESS) { 1040 PrintMessage(MSG_SET_SHELLEXT_NG); 1041 printf("%s", SystemError(ret)); 1042 return VFD_NG; 1043 } 1044 } 1045 } 1046 else if (_stricmp(*args, "/off") == 0) { 1047 if (ret == ERROR_SUCCESS) { 1048 ret = VfdUnregisterHandlers(); 1049 1050 if (ret != ERROR_SUCCESS) { 1051 PrintMessage(MSG_SET_SHELLEXT_NG); 1052 printf("%s", SystemError(ret)); 1053 return VFD_NG; 1054 } 1055 } 1056 } 1057 else { 1058 PrintMessage(MSG_UNKNOWN_OPTION, *args); 1059 PrintMessage(MSG_HINT_SHELL, help_progname); 1060 return VFD_NG; 1061 } 1062 1063 ret = VfdCheckHandlers(); 1064 } 1065 1066 if (ret == ERROR_PATH_NOT_FOUND || 1067 ret == ERROR_FILE_NOT_FOUND) { 1068 PrintMessage(MSG_SHELLEXT_DISABLED); 1069 } 1070 else if (ret == ERROR_SUCCESS) { 1071 PrintMessage(MSG_SHELLEXT_ENABLED); 1072 } 1073 else { 1074 PrintMessage(MSG_GET_SHELLEXT_NG); 1075 printf("%s", SystemError(ret)); 1076 return VFD_NG; 1077 } 1078 1079 return VFD_OK; 1080 } 1081 1082 // 1083 // Open an image file to a Virtual Floppy Drive 1084 // Command Line Parameters: 1085 // [drive:] [file] [/NEW] [/RAM] [/P | /W] 1086 // [/size] [/media] [/F | /FORCE | /Q | /QUIT] 1087 1088 int Open(const char **args) 1089 { 1090 int mode = OPERATION_ASK; 1091 BOOL create = FALSE; 1092 ULONG target = TARGET_NONE; 1093 PCSTR file_name = NULL; 1094 VFD_DISKTYPE disk_type = VFD_DISKTYPE_FILE; 1095 CHAR protect = '\0'; 1096 VFD_MEDIA media_type = VFD_MEDIA_NONE; 1097 BOOL five_inch = FALSE; 1098 VFD_FLAGS media_flags = 0; 1099 HANDLE hDevice; 1100 CHAR letter; 1101 DWORD ret; 1102 1103 // process parameters 1104 1105 while (args && *args) { 1106 1107 if (!_stricmp(*args, "/f") || 1108 !_stricmp(*args, "/force")) { 1109 1110 if (mode != OPERATION_ASK) { 1111 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1112 return VFD_NG; 1113 } 1114 1115 mode = OPERATION_FORCE; 1116 } 1117 else if (!_stricmp(*args, "/q") || 1118 !_stricmp(*args, "/quit")) { 1119 1120 if (mode != OPERATION_ASK) { 1121 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1122 return VFD_NG; 1123 } 1124 1125 mode = OPERATION_QUIT; 1126 } 1127 1128 else if (!_stricmp(*args, "/new")) { 1129 1130 if (create) { 1131 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1132 return VFD_NG; 1133 } 1134 1135 create = TRUE; 1136 } 1137 1138 // Disk type options 1139 1140 else if (_stricmp(*args, "/ram") == 0) { 1141 1142 if (disk_type != VFD_DISKTYPE_FILE) { 1143 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1144 return VFD_NG; 1145 } 1146 1147 disk_type = VFD_DISKTYPE_RAM; 1148 } 1149 1150 // Protect options 1151 else if (_stricmp(*args, "/p") == 0 || 1152 _stricmp(*args, "/w") == 0) { 1153 1154 if (protect) { 1155 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1156 return VFD_NG; 1157 } 1158 1159 protect = (CHAR)toupper(*(*args + 1)); 1160 } 1161 1162 // media size options 1163 1164 else if (strcmp(*args, "/160") == 0) { 1165 if (media_type) { 1166 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1167 return VFD_NG; 1168 } 1169 1170 media_type = VFD_MEDIA_F5_160; 1171 } 1172 else if (strcmp(*args, "/180") == 0) { 1173 if (media_type) { 1174 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1175 return VFD_NG; 1176 } 1177 1178 media_type = VFD_MEDIA_F5_180; 1179 } 1180 else if (strcmp(*args, "/320") == 0) { 1181 if (media_type) { 1182 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1183 return VFD_NG; 1184 } 1185 1186 media_type = VFD_MEDIA_F5_320; 1187 } 1188 else if (strcmp(*args, "/360") == 0) { 1189 if (media_type) { 1190 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1191 return VFD_NG; 1192 } 1193 1194 media_type = VFD_MEDIA_F5_360; 1195 } 1196 else if (strcmp(*args, "/640") == 0) { 1197 if (media_type) { 1198 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1199 return VFD_NG; 1200 } 1201 1202 media_type = VFD_MEDIA_F3_640; 1203 } 1204 else if (strcmp(*args, "/720") == 0) { 1205 if (media_type) { 1206 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1207 return VFD_NG; 1208 } 1209 1210 media_type = VFD_MEDIA_F3_720; 1211 } 1212 else if (strcmp(*args, "/820") == 0) { 1213 if (media_type) { 1214 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1215 return VFD_NG; 1216 } 1217 1218 media_type = VFD_MEDIA_F3_820; 1219 } 1220 else if (strcmp(*args, "/120") == 0 || 1221 strcmp(*args, "/1.20") == 0) { 1222 if (media_type) { 1223 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1224 return VFD_NG; 1225 } 1226 1227 media_type = VFD_MEDIA_F3_1P2; 1228 } 1229 else if (strcmp(*args, "/144") == 0 || 1230 strcmp(*args, "/1.44") == 0) { 1231 if (media_type) { 1232 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1233 return VFD_NG; 1234 } 1235 1236 media_type = VFD_MEDIA_F3_1P4; 1237 } 1238 else if (strcmp(*args, "/168") == 0 || 1239 strcmp(*args, "/1.68") == 0) { 1240 if (media_type) { 1241 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1242 return VFD_NG; 1243 } 1244 1245 media_type = VFD_MEDIA_F3_1P6; 1246 } 1247 else if (strcmp(*args, "/172") == 0 || 1248 strcmp(*args, "/1.72") == 0) { 1249 if (media_type) { 1250 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1251 return VFD_NG; 1252 } 1253 1254 media_type = VFD_MEDIA_F3_1P7; 1255 } 1256 else if (strcmp(*args, "/288") == 0 || 1257 strcmp(*args, "/2.88") == 0) { 1258 if (media_type) { 1259 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1260 return VFD_NG; 1261 } 1262 1263 media_type = VFD_MEDIA_F3_2P8; 1264 } 1265 1266 // 5.25 inch media 1267 1268 else if (strcmp(*args, "/5") == 0 || 1269 strcmp(*args, "/525") == 0 || 1270 strcmp(*args, "/5.25") == 0) { 1271 1272 if (five_inch) { 1273 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1274 return VFD_NG; 1275 } 1276 1277 five_inch = TRUE; 1278 } 1279 1280 // target option 1281 1282 else if (isalnum(**args) && 1283 *(*args + 1) == ':' && 1284 *(*args + 2) == '\0') { 1285 1286 if (target != TARGET_NONE) { 1287 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1288 return VFD_NG; 1289 } 1290 1291 target = toupper(**args); 1292 } 1293 1294 // filename 1295 1296 else if (**args != '/') { 1297 if (file_name) { 1298 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1299 return VFD_NG; 1300 } 1301 1302 file_name = *args; 1303 } 1304 else { 1305 PrintMessage(MSG_UNKNOWN_OPTION, *args); 1306 PrintMessage(MSG_HINT_OPEN, help_progname); 1307 return VFD_NG; 1308 } 1309 1310 args++; 1311 } 1312 1313 if (target == TARGET_NONE) { 1314 // default target 1315 target = '0'; 1316 PrintMessage(MSG_TARGET_NOTICE, target); 1317 } 1318 1319 // check target file 1320 1321 if (file_name) { 1322 DWORD file_attr; 1323 VFD_FILETYPE file_type; 1324 ULONG image_size; 1325 BOOL overwrite = FALSE; 1326 1327 ret = VfdCheckImageFile( 1328 file_name, &file_attr, &file_type, &image_size); 1329 1330 if (ret == ERROR_FILE_NOT_FOUND) { 1331 1332 // the target file does not exist 1333 1334 if (!create) { // create option not specified 1335 1336 if (mode == OPERATION_FORCE) { 1337 PrintMessage(MSG_CREATE_NOTICE); 1338 } 1339 else { 1340 printf("%s", SystemError(ret)); 1341 1342 if (mode == OPERATION_QUIT || 1343 InputChar(MSG_CREATE_CONFIRM, "yn") == 'n') { 1344 return VFD_NG; 1345 } 1346 } 1347 1348 create = TRUE; 1349 } 1350 } 1351 else if (ret == ERROR_SUCCESS) { 1352 1353 // the target file exists 1354 1355 if (create) { // create option is specified 1356 1357 if (mode == OPERATION_FORCE) { 1358 PrintMessage(MSG_OVERWRITE_NOTICE); 1359 } 1360 else { 1361 printf("%s", SystemError(ERROR_FILE_EXISTS)); 1362 1363 if (mode == OPERATION_QUIT || 1364 InputChar(MSG_OVERWRITE_CONFIRM, "yn") == 'n') { 1365 return VFD_NG; 1366 } 1367 } 1368 1369 overwrite = TRUE; 1370 } 1371 } 1372 else { 1373 PrintMessage(MSG_OPEN_NG, file_name); 1374 printf("%s", SystemError(ret)); 1375 return VFD_NG; 1376 } 1377 1378 // 1379 // create or overwrite the target file 1380 // 1381 1382 if (create) { 1383 1384 if (media_type == VFD_MEDIA_NONE) { 1385 1386 if (mode == OPERATION_FORCE) { 1387 PrintMessage(MSG_CREATE144_NOTICE); 1388 } 1389 else { 1390 PrintMessage(MSG_FILE_MEDIA_UNKNOWN); 1391 1392 if (mode == OPERATION_QUIT || 1393 InputChar(MSG_CREATE144_CONFIRM, "yn") == 'n') { 1394 return VFD_NG; 1395 } 1396 } 1397 1398 media_type = VFD_MEDIA_F3_1P4; 1399 } 1400 1401 ret = VfdCreateImageFile( 1402 file_name, media_type, VFD_FILETYPE_RAW, overwrite); 1403 1404 if (ret != ERROR_SUCCESS) { 1405 PrintMessage(MSG_CREATE_NG, file_name); 1406 printf("%s", SystemError(ret)); 1407 return VFD_NG; 1408 } 1409 1410 PrintMessage(MSG_FILE_CREATED); 1411 1412 ret = VfdCheckImageFile( 1413 file_name, &file_attr, &file_type, &image_size); 1414 1415 if (ret != ERROR_SUCCESS) { 1416 PrintMessage(MSG_OPEN_NG, file_name); 1417 printf("%s", SystemError(ret)); 1418 return VFD_NG; 1419 } 1420 } 1421 else { 1422 // 1423 // use the existing target file 1424 // check image size and the media type 1425 // 1426 1427 VFD_MEDIA def_media; // default media for image size 1428 ULONG media_size; // specified media size 1429 1430 media_size = VfdGetMediaSize(media_type); 1431 1432 if (media_size > image_size) { 1433 1434 // specified media is too large for the image 1435 1436 PrintMessage(MSG_IMAGE_TOO_SMALL); 1437 return VFD_NG; 1438 } 1439 1440 def_media = VfdLookupMedia(image_size); 1441 1442 if (def_media == VFD_MEDIA_NONE) { 1443 1444 // image is too small for the smallest media 1445 1446 PrintMessage(MSG_IMAGE_TOO_SMALL); 1447 return VFD_NG; 1448 } 1449 1450 if (media_type == VFD_MEDIA_NONE) { 1451 1452 // media type is not specified 1453 1454 ULONG def_size = VfdGetMediaSize(def_media); 1455 1456 if (def_size != image_size) { 1457 1458 // image size does not match the largest media size 1459 1460 PrintMessage(MSG_NO_MATCHING_MEDIA, image_size); 1461 1462 if (mode == OPERATION_FORCE) { 1463 PrintMessage(MSG_MEDIATYPE_NOTICE, 1464 VfdMediaTypeName(def_media), def_size); 1465 } 1466 else if (mode == OPERATION_QUIT) { 1467 return VFD_NG; 1468 } 1469 else { 1470 PrintMessage(MSG_MEDIATYPE_SUGGEST, 1471 VfdMediaTypeName(def_media), def_size); 1472 1473 if (InputChar(MSG_MEDIATYPE_CONFIRM, "yn") == 'n') { 1474 return VFD_NG; 1475 } 1476 } 1477 } 1478 1479 media_type = def_media; 1480 } 1481 } 1482 1483 // check file attributes against the disk type 1484 1485 if (file_type == VFD_FILETYPE_ZIP || 1486 (file_attr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED))) { 1487 1488 if (disk_type != VFD_DISKTYPE_RAM) { 1489 1490 if (mode == OPERATION_FORCE) { 1491 PrintMessage(MSG_RAM_MODE_NOTICE); 1492 } 1493 else { 1494 PrintMessage(MSG_RAM_MODE_ONLY); 1495 1496 if (mode == OPERATION_QUIT || 1497 InputChar(MSG_RAM_MODE_CONFIRM, "yn") == 'n') { 1498 return VFD_NG; 1499 } 1500 } 1501 1502 disk_type = VFD_DISKTYPE_RAM; 1503 } 1504 } 1505 1506 if (disk_type != VFD_DISKTYPE_FILE) { 1507 if (!protect) { 1508 PrintMessage(MSG_DEFAULT_PROTECT); 1509 protect = 'P'; 1510 } 1511 } 1512 } 1513 else { 1514 // 1515 // pure RAM disk 1516 // 1517 disk_type = VFD_DISKTYPE_RAM; 1518 1519 if (media_type == VFD_MEDIA_NONE) { 1520 1521 if (mode == OPERATION_FORCE) { 1522 PrintMessage(MSG_CREATE144_NOTICE); 1523 } 1524 else { 1525 PrintMessage(MSG_RAM_MEDIA_UNKNOWN); 1526 1527 if (mode == OPERATION_QUIT || 1528 InputChar(MSG_CREATE144_CONFIRM, "yn") == 'n') { 1529 return VFD_NG; 1530 } 1531 } 1532 1533 media_type = VFD_MEDIA_F3_1P4; 1534 } 1535 } 1536 1537 if (protect == 'P') { 1538 media_flags |= VFD_FLAG_WRITE_PROTECTED; 1539 } 1540 1541 if (five_inch && 1542 VfdGetMediaSize(media_type) == 1543 VfdGetMediaSize((VFD_MEDIA)(media_type + 1))) { 1544 media_type = (VFD_MEDIA)(media_type + 1); 1545 } 1546 1547 // ensure that the driver is installed 1548 1549 if (driver_state == VFD_NOT_INSTALLED && 1550 Install(NULL) != VFD_OK) { 1551 return VFD_NG; 1552 } 1553 1554 // ensure that the driver is up to date 1555 1556 if (CheckDriver() != VFD_OK) { 1557 return VFD_NG; 1558 } 1559 1560 // ensure that the driver is running 1561 1562 if (driver_state != SERVICE_RUNNING && 1563 Start(NULL) != VFD_OK) { 1564 return VFD_NG; 1565 } 1566 1567 // Open the target device 1568 1569 hDevice = VfdOpenDevice(target); 1570 1571 if (hDevice == INVALID_HANDLE_VALUE) { 1572 ret = GetLastError(); 1573 PrintMessage(MSG_ACCESS_NG, target); 1574 printf("%s", SystemError(ret)); 1575 return VFD_NG; 1576 } 1577 1578 // Ensure that the drive is empty 1579 1580 ret = VfdGetMediaState(hDevice); 1581 1582 if (ret != ERROR_NOT_READY) { 1583 if (ret == ERROR_SUCCESS || 1584 ret == ERROR_WRITE_PROTECT) { 1585 PrintMessage(MSG_DRIVE_BUSY); 1586 } 1587 else { 1588 PrintMessage(MSG_GET_MEDIA_NG); 1589 printf("%s", SystemError(ret)); 1590 } 1591 1592 CloseHandle(hDevice); 1593 return VFD_NG; 1594 } 1595 1596 // Open the image file 1597 1598 ret = VfdOpenImage(hDevice, file_name, 1599 disk_type, media_type, media_flags); 1600 1601 if (ret != ERROR_SUCCESS) { 1602 PrintMessage(MSG_OPEN_NG, file_name ? file_name : "<RAM>"); 1603 printf("%s", SystemError(ret)); 1604 1605 CloseHandle(hDevice); 1606 return VFD_NG; 1607 } 1608 1609 // assign a drive letter if the drive has none 1610 1611 VfdGetGlobalLink(hDevice, &letter); 1612 1613 if (!isalpha(letter)) { 1614 VfdGetLocalLink(hDevice, &letter); 1615 } 1616 1617 if (!isalpha(letter)) { 1618 VfdSetLocalLink(hDevice, VfdChooseLetter()); 1619 } 1620 1621 // Get the actually opened image information. 1622 1623 PrintImageInfo(hDevice); 1624 1625 CloseHandle(hDevice); 1626 1627 return VFD_OK; 1628 } 1629 1630 // 1631 // Close the current virtual floppy image 1632 // Command Line Parameters: 1633 // drive number or drive letter 1634 // /F | /FORCE | /Q | /QUIT 1635 // 1636 int Close(const char **args) 1637 { 1638 ULONG mode = OPERATION_ASK; 1639 1640 ULONG target_min = TARGET_NONE; 1641 ULONG target_max = TARGET_NONE; 1642 HANDLE hDevice; 1643 1644 VFD_MEDIA media_type; 1645 VFD_FLAGS media_flags; 1646 1647 DWORD ret; 1648 1649 // check parameterS 1650 1651 while (args && *args) { 1652 1653 if (!_stricmp(*args, "/f") || 1654 !_stricmp(*args, "/force")) { 1655 1656 if (mode != OPERATION_ASK) { 1657 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1658 return VFD_NG; 1659 } 1660 1661 mode = OPERATION_FORCE; 1662 } 1663 else if (!_stricmp(*args, "/q") || 1664 !_stricmp(*args, "/quit")) { 1665 1666 if (mode != OPERATION_ASK) { 1667 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1668 return VFD_NG; 1669 } 1670 1671 mode = OPERATION_QUIT; 1672 } 1673 else if ((isalnum(**args) || **args == '*') && 1674 (*(*args + 1) == ':' || *(*args + 1) == '\0')) { 1675 1676 if (target_min != TARGET_NONE) { 1677 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1678 return VFD_NG; 1679 } 1680 1681 if (**args == '*') { 1682 target_min = '0'; 1683 target_max = '0' + VFD_MAXIMUM_DEVICES; 1684 } 1685 else { 1686 target_min = toupper(**args); 1687 target_max = target_min + 1; 1688 } 1689 } 1690 else { 1691 PrintMessage(MSG_UNKNOWN_OPTION, *args); 1692 PrintMessage(MSG_HINT_CLOSE, help_progname); 1693 return VFD_NG; 1694 } 1695 1696 args++; 1697 } 1698 1699 if (target_min == TARGET_NONE) { 1700 // default target = drive 0 1701 target_min = '0'; 1702 target_max = '1'; 1703 PrintMessage(MSG_TARGET_NOTICE, target_min); 1704 } 1705 1706 // ensure that the driver is installed 1707 1708 if (driver_state == VFD_NOT_INSTALLED) { 1709 PrintMessage(MSG_NOT_INSTALLED); 1710 return VFD_NG; 1711 } 1712 1713 // ensure that the driver is running 1714 1715 if (driver_state != SERVICE_RUNNING) { 1716 PrintMessage(MSG_NOT_STARTED); 1717 return VFD_NG; 1718 } 1719 1720 // Close the drive(s) 1721 1722 while (target_min < target_max) { 1723 1724 // open the target device 1725 1726 hDevice = VfdOpenDevice(target_min); 1727 1728 if (hDevice == INVALID_HANDLE_VALUE) { 1729 ret = GetLastError(); 1730 1731 PrintMessage(MSG_ACCESS_NG, target_min); 1732 printf("%s", SystemError(ret)); 1733 1734 if (mode != OPERATION_FORCE) { 1735 return VFD_NG; 1736 } 1737 1738 target_min++; 1739 continue; 1740 } 1741 1742 // get the current image information 1743 1744 ret = VfdGetImageInfo(hDevice, NULL, NULL, 1745 &media_type, &media_flags, NULL, NULL); 1746 1747 if (ret != ERROR_SUCCESS) { 1748 PrintMessage(MSG_ACCESS_NG, target_min); 1749 printf("%s", SystemError(ret)); 1750 1751 CloseHandle(hDevice); 1752 1753 if (mode != OPERATION_FORCE) { 1754 return VFD_NG; 1755 } 1756 1757 target_min++; 1758 continue; 1759 } 1760 1761 if (media_type == VFD_MEDIA_NONE) { 1762 1763 // drive is empty 1764 1765 CloseHandle(hDevice); 1766 target_min++; 1767 continue; 1768 } 1769 1770 if (media_flags & VFD_FLAG_DATA_MODIFIED) { 1771 1772 // RAM disk data is modified 1773 1774 PrintMessage(MSG_MEDIA_MODIFIED, target_min); 1775 1776 if (mode == OPERATION_FORCE) { 1777 PrintMessage(MSG_CLOSE_FORCE); 1778 } 1779 else if (mode == OPERATION_QUIT) { 1780 PrintMessage(MSG_CLOSE_QUIT); 1781 CloseHandle(hDevice); 1782 return VFD_NG; 1783 } 1784 else { 1785 if (InputChar(MSG_CLOSE_CONFIRM, "yn") == 'n') { 1786 CloseHandle(hDevice); 1787 return VFD_NG; 1788 } 1789 } 1790 } 1791 1792 retry: 1793 ret = VfdCloseImage( 1794 hDevice, (mode == OPERATION_FORCE)); 1795 1796 if (ret == ERROR_ACCESS_DENIED) { 1797 1798 PrintMessage(MSG_LOCK_NG, target_min); 1799 1800 if (mode == OPERATION_QUIT) { 1801 CloseHandle(hDevice); 1802 return VFD_NG; 1803 } 1804 else if (mode == OPERATION_ASK) { 1805 1806 int c; 1807 1808 if (IS_WINDOWS_NT()) { 1809 c = InputChar(MSG_RETRY_CANCEL, "rc"); 1810 } 1811 else { 1812 c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc"); 1813 } 1814 1815 if (c == 'f') { // force 1816 ret = VfdCloseImage(hDevice, TRUE); 1817 } 1818 else if (c == 'c') { // cancel 1819 CloseHandle(hDevice); 1820 return VFD_NG; 1821 } 1822 else { 1823 goto retry; 1824 } 1825 } 1826 } 1827 1828 CloseHandle(hDevice); 1829 1830 if (ret == ERROR_SUCCESS) { 1831 PrintMessage(MSG_CLOSE_OK, target_min); 1832 } 1833 else if (ret != ERROR_NOT_READY) { 1834 PrintMessage(MSG_CLOSE_NG, target_min); 1835 printf("%s", SystemError(ret)); 1836 1837 if (mode != OPERATION_FORCE) { 1838 return VFD_NG; 1839 } 1840 } 1841 1842 target_min++; 1843 } 1844 1845 return VFD_OK; 1846 } 1847 1848 // 1849 // Save the current image into a file 1850 // 1851 int Save(const char **args) 1852 { 1853 int mode = OPERATION_ASK; 1854 ULONG target = TARGET_NONE; 1855 CHAR file_name[MAX_PATH] = {0}; 1856 BOOL overwrite = FALSE; 1857 BOOL truncate = FALSE; 1858 1859 HANDLE hDevice; 1860 CHAR current[MAX_PATH] = {0}; 1861 VFD_MEDIA media_type; 1862 VFD_FLAGS media_flags; 1863 VFD_FILETYPE file_type; 1864 DWORD file_attr; 1865 ULONG image_size; 1866 DWORD ret; 1867 1868 // check parameters 1869 1870 while (args && *args) { 1871 1872 if (!_stricmp(*args, "/f") || 1873 !_stricmp(*args, "/force")) { 1874 1875 if (mode != OPERATION_ASK) { 1876 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1877 return VFD_NG; 1878 } 1879 1880 mode = OPERATION_FORCE; 1881 } 1882 else if (!_stricmp(*args, "/q") || 1883 !_stricmp(*args, "/quit")) { 1884 1885 if (mode != OPERATION_ASK) { 1886 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1887 return VFD_NG; 1888 } 1889 1890 mode = OPERATION_QUIT; 1891 } 1892 else if (!_stricmp(*args, "/o") || 1893 !_stricmp(*args, "/over")) { 1894 1895 if (truncate || overwrite) { 1896 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1897 return VFD_NG; 1898 } 1899 1900 overwrite = TRUE; 1901 } 1902 else if (!_stricmp(*args, "/t") || 1903 !_stricmp(*args, "/trunc")) { 1904 1905 if (truncate || overwrite) { 1906 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1907 return VFD_NG; 1908 } 1909 1910 truncate = TRUE; 1911 } 1912 else if (isalnum(**args) && 1913 *(*args + 1) == ':' && 1914 *(*args + 2) == '\0') { 1915 1916 if (target != TARGET_NONE) { 1917 PrintMessage(MSG_DUPLICATE_ARGS, *args); 1918 return VFD_NG; 1919 } 1920 1921 target = toupper(**args); 1922 } 1923 else if (**args == '/') { 1924 PrintMessage(MSG_UNKNOWN_OPTION, *args); 1925 PrintMessage(MSG_HINT_SAVE, help_progname); 1926 return VFD_NG; 1927 } 1928 else { 1929 strcpy(file_name, *args); 1930 } 1931 1932 args++; 1933 } 1934 1935 if (target == TARGET_NONE) { 1936 target = '0'; 1937 PrintMessage(MSG_TARGET_NOTICE, target); 1938 } 1939 1940 // ensure that the driver is installed 1941 1942 if (driver_state == VFD_NOT_INSTALLED) { 1943 PrintMessage(MSG_NOT_INSTALLED); 1944 return VFD_NG; 1945 } 1946 1947 // ensure that the driver is up to date 1948 1949 if (CheckDriver() != VFD_OK) { 1950 return VFD_NG; 1951 } 1952 1953 // ensure that the driver is running 1954 1955 if (driver_state != SERVICE_RUNNING) { 1956 PrintMessage(MSG_NOT_STARTED); 1957 return VFD_NG; 1958 } 1959 1960 // Open the target device 1961 1962 hDevice = VfdOpenDevice(target); 1963 1964 if (hDevice == INVALID_HANDLE_VALUE) { 1965 ret = GetLastError(); 1966 PrintMessage(MSG_ACCESS_NG, target); 1967 printf("%s", SystemError(ret)); 1968 return VFD_NG; 1969 } 1970 1971 // Get the current image info 1972 1973 ret = VfdGetImageInfo(hDevice, current, NULL, 1974 &media_type, &media_flags, NULL, NULL); 1975 1976 if (ret != ERROR_SUCCESS) { 1977 printf("%s", SystemError(ret)); 1978 CloseHandle(hDevice); 1979 return VFD_NG; 1980 } 1981 1982 if (media_type == VFD_MEDIA_NONE) { 1983 printf("%s", SystemError(ERROR_NOT_READY)); 1984 CloseHandle(hDevice); 1985 return VFD_NG; 1986 } 1987 1988 if (file_name[0] == '\0') { 1989 1990 if (current[0] == '\0') { 1991 1992 PrintMessage(MSG_TARGET_REQUIRED); 1993 CloseHandle(hDevice); 1994 1995 return VFD_NG; 1996 } 1997 1998 strcpy(file_name, current); 1999 } 2000 2001 if (!_stricmp(file_name, current)) { 2002 2003 // target is the current image file 2004 2005 if (!(media_flags & VFD_FLAG_DATA_MODIFIED)) { 2006 2007 // FILE disk (always up to date) or RAM disk is not modified 2008 2009 PrintMessage(MSG_TARGET_UP_TO_DATE); 2010 CloseHandle(hDevice); 2011 2012 return VFD_OK; 2013 } 2014 2015 overwrite = TRUE; 2016 } 2017 2018 // check target file 2019 2020 ret = VfdCheckImageFile(file_name, 2021 &file_attr, &file_type, &image_size); 2022 2023 if (ret == ERROR_SUCCESS) { 2024 2025 if (!overwrite && !truncate) { 2026 2027 if (mode == OPERATION_FORCE) { 2028 PrintMessage(MSG_OVERWRITE_NOTICE); 2029 overwrite = TRUE; 2030 } 2031 else if (mode == OPERATION_QUIT) { 2032 printf("%s", SystemError(ERROR_FILE_EXISTS)); 2033 CloseHandle(hDevice); 2034 2035 return VFD_NG; 2036 } 2037 else { 2038 int c; 2039 2040 printf("%s", SystemError(ERROR_FILE_EXISTS)); 2041 2042 c = InputChar(MSG_OVERWRITE_PROMPT, "otc"); 2043 2044 if (c == 'o') { 2045 overwrite = TRUE; 2046 } 2047 else if (c == 't') { 2048 truncate = TRUE; 2049 } 2050 else { 2051 CloseHandle(hDevice); 2052 return VFD_NG; 2053 } 2054 } 2055 } 2056 } 2057 else if (ret != ERROR_FILE_NOT_FOUND) { 2058 2059 printf("%s", SystemError(ret)); 2060 CloseHandle(hDevice); 2061 2062 return VFD_NG; 2063 } 2064 2065 if (file_type == VFD_FILETYPE_ZIP) { 2066 2067 // Cannot update a zip file 2068 2069 PrintMessage(MSG_TARGET_IS_ZIP); 2070 CloseHandle(hDevice); 2071 2072 return VFD_NG; 2073 } 2074 2075 retry: 2076 ret = VfdDismountVolume( 2077 hDevice, (mode == OPERATION_FORCE)); 2078 2079 if (ret == ERROR_ACCESS_DENIED) { 2080 2081 PrintMessage(MSG_LOCK_NG, target); 2082 2083 if (mode == OPERATION_FORCE) { 2084 PrintMessage(MSG_SAVE_FORCE); 2085 } 2086 else if (mode == OPERATION_QUIT) { 2087 PrintMessage(MSG_SAVE_QUIT); 2088 CloseHandle(hDevice); 2089 return VFD_NG; 2090 } 2091 else { 2092 int c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc"); 2093 2094 if (c == 'r') { // retry 2095 goto retry; 2096 } 2097 else if (c == 'f') { // force 2098 VfdDismountVolume(hDevice, TRUE); 2099 } 2100 else { // cancel 2101 CloseHandle(hDevice); 2102 return VFD_NG; 2103 } 2104 } 2105 } 2106 else if (ret != ERROR_SUCCESS) { 2107 printf("%s", SystemError(ret)); 2108 CloseHandle(hDevice); 2109 return VFD_NG; 2110 } 2111 2112 ret = VfdSaveImage(hDevice, file_name, 2113 (overwrite || truncate), truncate); 2114 2115 CloseHandle(hDevice); 2116 2117 if (ret != ERROR_SUCCESS) { 2118 PrintMessage(MSG_SAVE_NG, target, file_name); 2119 printf("%s", SystemError(ret)); 2120 2121 return VFD_NG; 2122 } 2123 2124 PrintMessage(MSG_SAVE_OK, target, file_name); 2125 2126 return VFD_OK; 2127 } 2128 2129 // 2130 // Enable/disable virtual media write protection 2131 // 2132 int Protect(const char **args) 2133 { 2134 #define PROTECT_NONE 0 2135 #define PROTECT_ON 1 2136 #define PROTECT_OFF 2 2137 ULONG protect = PROTECT_NONE; 2138 ULONG target = TARGET_NONE; 2139 HANDLE hDevice; 2140 DWORD ret; 2141 2142 // check parameters 2143 2144 while (args && *args) { 2145 2146 // Disk type options 2147 2148 if (_stricmp(*args, "/on") == 0) { 2149 2150 if (protect) { 2151 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2152 return VFD_NG; 2153 } 2154 2155 protect = PROTECT_ON; 2156 } 2157 else if (_stricmp(*args, "/off") == 0) { 2158 2159 if (protect) { 2160 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2161 return VFD_NG; 2162 } 2163 2164 protect = PROTECT_OFF; 2165 } 2166 else if (isalnum(**args)) { 2167 2168 if (target != TARGET_NONE) { 2169 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2170 return VFD_NG; 2171 } 2172 2173 target = toupper(**args); 2174 } 2175 else { 2176 PrintMessage(MSG_UNKNOWN_OPTION, *args); 2177 PrintMessage(MSG_HINT_PROTECT, help_progname); 2178 return VFD_NG; 2179 } 2180 2181 args++; 2182 } 2183 2184 if (target == TARGET_NONE) { 2185 target = '0'; 2186 PrintMessage(MSG_TARGET_NOTICE, target); 2187 } 2188 2189 // ensure that the driver is installed 2190 2191 if (driver_state == VFD_NOT_INSTALLED) { 2192 PrintMessage(MSG_NOT_INSTALLED); 2193 return VFD_NG; 2194 } 2195 2196 // ensure that the driver is up to date 2197 2198 if (CheckDriver() != VFD_OK) { 2199 return VFD_NG; 2200 } 2201 2202 // ensure that the driver is running 2203 2204 if (driver_state != SERVICE_RUNNING) { 2205 PrintMessage(MSG_NOT_STARTED); 2206 return VFD_NG; 2207 } 2208 2209 // open the target drive 2210 2211 hDevice = VfdOpenDevice(target); 2212 2213 if (hDevice == INVALID_HANDLE_VALUE) { 2214 ret = GetLastError(); 2215 PrintMessage(MSG_ACCESS_NG, target); 2216 printf("%s", SystemError(ret)); 2217 return VFD_NG; 2218 } 2219 2220 if (protect) { 2221 // change protect state 2222 2223 ret = VfdWriteProtect( 2224 hDevice, (protect == PROTECT_ON)); 2225 2226 if (ret != ERROR_SUCCESS) { 2227 PrintMessage(MSG_PROTECT_NG, target); 2228 printf("%s", SystemError(ret)); 2229 2230 CloseHandle(hDevice); 2231 return VFD_NG; 2232 } 2233 } 2234 2235 // get the current protect state 2236 2237 ret = VfdGetMediaState(hDevice); 2238 2239 CloseHandle(hDevice); 2240 2241 if (ret == ERROR_SUCCESS) { 2242 PrintMessage(MSG_MEDIA_WRITABLE); 2243 } 2244 else if (ret == ERROR_WRITE_PROTECT) { 2245 PrintMessage(MSG_MEDIA_PROTECTED); 2246 } 2247 else { 2248 PrintMessage(MSG_GET_MEDIA_NG); 2249 printf("%s", SystemError(ret)); 2250 return VFD_NG; 2251 } 2252 2253 return VFD_OK; 2254 } 2255 2256 // 2257 // Format the virtual media with FAT12 2258 // 2259 int Format(const char **args) 2260 { 2261 int mode = OPERATION_ASK; 2262 ULONG target = TARGET_NONE; 2263 HANDLE hDevice; 2264 DWORD ret; 2265 2266 // check parameters 2267 2268 while (args && *args) { 2269 2270 if (!_stricmp(*args, "/f") || 2271 !_stricmp(*args, "/force")) { 2272 2273 if (mode != OPERATION_ASK) { 2274 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2275 return VFD_NG; 2276 } 2277 2278 mode = OPERATION_FORCE; 2279 } 2280 else if (!_stricmp(*args, "/q") || 2281 !_stricmp(*args, "/quit")) { 2282 2283 if (mode != OPERATION_ASK) { 2284 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2285 return VFD_NG; 2286 } 2287 2288 mode = OPERATION_QUIT; 2289 } 2290 else if (isalnum(**args)) { 2291 if (target != TARGET_NONE) { 2292 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2293 return VFD_NG; 2294 } 2295 2296 target = toupper(**args); 2297 } 2298 else { 2299 PrintMessage(MSG_UNKNOWN_OPTION, *args); 2300 PrintMessage(MSG_HINT_FORMAT, help_progname); 2301 return VFD_NG; 2302 } 2303 2304 args++; 2305 } 2306 2307 if (target == TARGET_NONE) { 2308 target = '0'; 2309 PrintMessage(MSG_TARGET_NOTICE, target); 2310 } 2311 2312 // ensure that the driver is installed 2313 2314 if (driver_state == VFD_NOT_INSTALLED) { 2315 PrintMessage(MSG_NOT_INSTALLED); 2316 return VFD_NG; 2317 } 2318 2319 // ensure that the driver is up to date 2320 2321 if (CheckDriver() != VFD_OK) { 2322 return VFD_NG; 2323 } 2324 2325 // ensure that the driver is running 2326 2327 if (driver_state != SERVICE_RUNNING) { 2328 PrintMessage(MSG_NOT_STARTED); 2329 return VFD_NG; 2330 } 2331 2332 // Open the device 2333 2334 hDevice = VfdOpenDevice(target); 2335 2336 if (hDevice == INVALID_HANDLE_VALUE) { 2337 ret = GetLastError(); 2338 PrintMessage(MSG_ACCESS_NG, target); 2339 printf("%s", SystemError(ret)); 2340 return VFD_NG; 2341 } 2342 2343 // check if the media is writable 2344 2345 ret = VfdGetMediaState(hDevice); 2346 2347 if (ret != ERROR_SUCCESS) { 2348 PrintMessage(MSG_FORMAT_NG, target); 2349 printf("%s", SystemError(ret)); 2350 2351 CloseHandle(hDevice); 2352 return VFD_NG; 2353 } 2354 2355 // format the media 2356 2357 retry: 2358 ret = VfdDismountVolume( 2359 hDevice, (mode == OPERATION_FORCE)); 2360 2361 if (ret == ERROR_ACCESS_DENIED) { 2362 2363 PrintMessage(MSG_LOCK_NG, target); 2364 2365 if (mode == OPERATION_FORCE) { 2366 PrintMessage(MSG_FORMAT_FORCE); 2367 } 2368 else if (mode == OPERATION_QUIT) { 2369 PrintMessage(MSG_FORMAT_QUIT); 2370 CloseHandle(hDevice); 2371 return VFD_NG; 2372 } 2373 else { 2374 int c = InputChar(MSG_RETRY_FORCE_CANCEL, "rfc"); 2375 2376 if (c == 'r') { // retry 2377 goto retry; 2378 } 2379 else if (c == 'f') { // force 2380 VfdDismountVolume(hDevice, TRUE); 2381 } 2382 else { // cancel 2383 CloseHandle(hDevice); 2384 return VFD_NG; 2385 } 2386 } 2387 } 2388 else if (ret != ERROR_SUCCESS) { 2389 PrintMessage(MSG_LOCK_NG, target); 2390 CloseHandle(hDevice); 2391 return VFD_NG; 2392 } 2393 2394 ret = VfdFormatMedia(hDevice); 2395 2396 CloseHandle(hDevice); 2397 2398 if (ret != ERROR_SUCCESS) { 2399 PrintMessage(MSG_FORMAT_NG, target); 2400 printf("%s", SystemError(ret)); 2401 return VFD_NG; 2402 } 2403 2404 // successful operation 2405 2406 PrintMessage(MSG_FORMAT_OK); 2407 2408 return VFD_OK; 2409 } 2410 2411 // 2412 // Assign a drive letter to a Virtual Floppy Drive 2413 // 2414 int Link(const char **args) 2415 { 2416 ULONG target_min = TARGET_NONE; 2417 ULONG target_max = TARGET_NONE; 2418 PCSTR letters = NULL; 2419 BOOL global = TRUE; 2420 HANDLE hDevice; 2421 DWORD ret; 2422 2423 while (args && *args) { 2424 if (!_stricmp(*args, "/g")) { 2425 global = TRUE; 2426 } 2427 else if (!_stricmp(*args, "/l")) { 2428 global = FALSE; 2429 } 2430 else if (isdigit(**args) || **args == '*') { 2431 if (target_min != TARGET_NONE) { 2432 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2433 return VFD_NG; 2434 } 2435 2436 if (**args == '*') { 2437 target_min = '0'; 2438 target_max = '0' + VFD_MAXIMUM_DEVICES; 2439 } 2440 else { 2441 target_min = **args; 2442 target_max = target_min + 1; 2443 } 2444 } 2445 else if (isalpha(**args)) { 2446 if (letters) { 2447 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2448 return VFD_NG; 2449 } 2450 letters = *args; 2451 } 2452 else { 2453 PrintMessage(MSG_UNKNOWN_OPTION, *args); 2454 PrintMessage(MSG_HINT_LINK, help_progname); 2455 return VFD_NG; 2456 } 2457 2458 args++; 2459 } 2460 2461 if (target_min == TARGET_NONE) { 2462 // default: drive 0 2463 target_min = '0'; 2464 target_max = '1'; 2465 PrintMessage(MSG_TARGET_NOTICE, target_min); 2466 } 2467 2468 // ensure that the driver is installed 2469 2470 if (driver_state == VFD_NOT_INSTALLED) { 2471 PrintMessage(MSG_NOT_INSTALLED); 2472 return VFD_NG; 2473 } 2474 2475 // ensure that the driver is up to date 2476 2477 if (CheckDriver() != VFD_OK) { 2478 return VFD_NG; 2479 } 2480 2481 // ensure that the driver is running 2482 2483 if (driver_state != SERVICE_RUNNING) { 2484 PrintMessage(MSG_NOT_STARTED); 2485 return VFD_NG; 2486 } 2487 2488 while (target_min < target_max) { 2489 ULONG number; 2490 CHAR letter; 2491 2492 hDevice = VfdOpenDevice(target_min); 2493 2494 if (hDevice == INVALID_HANDLE_VALUE) { 2495 ret = GetLastError(); 2496 PrintMessage(MSG_ACCESS_NG, target_min); 2497 printf("%s", SystemError(ret)); 2498 target_min++; 2499 continue; 2500 } 2501 2502 ret = VfdGetDeviceNumber(hDevice, &number); 2503 2504 if (ret != ERROR_SUCCESS) { 2505 PrintMessage(MSG_ACCESS_NG, target_min); 2506 printf("%s", SystemError(ret)); 2507 CloseHandle(hDevice); 2508 target_min++; 2509 continue; 2510 } 2511 2512 if (letters && isalpha(*letters)) { 2513 letter = (CHAR)toupper(*(letters++)); 2514 } 2515 else { 2516 letter = VfdChooseLetter(); 2517 } 2518 2519 if (letter) { 2520 if (global) { 2521 ret = VfdSetGlobalLink(hDevice, letter); 2522 } 2523 else { 2524 ret = VfdSetLocalLink(hDevice, letter); 2525 } 2526 2527 if (ret != ERROR_SUCCESS) { 2528 PrintMessage(MSG_LINK_NG, number, letter); 2529 printf("%s", SystemError(ret)); 2530 } 2531 } 2532 else { 2533 PrintMessage(MSG_LINK_FULL); 2534 } 2535 2536 PrintDriveLetter(hDevice, number); 2537 2538 CloseHandle(hDevice); 2539 2540 target_min++; 2541 } 2542 2543 return VFD_OK; 2544 } 2545 2546 // 2547 // Remove a drive letter from a Virtual Floppy Drive 2548 // 2549 int Unlink(const char **args) 2550 { 2551 ULONG target_min = TARGET_NONE; 2552 ULONG target_max = TARGET_NONE; 2553 HANDLE hDevice; 2554 DWORD ret; 2555 2556 while (args && *args) { 2557 if ((isalnum(**args) || **args == '*') && 2558 (*(*args + 1) == ':' || *(*args + 1) == '\0')) { 2559 2560 if (target_min != TARGET_NONE) { 2561 PrintMessage(MSG_DUPLICATE_ARGS, *args); 2562 return VFD_NG; 2563 } 2564 2565 if (**args == '*') { 2566 target_min = '0'; 2567 target_max = '0' + VFD_MAXIMUM_DEVICES; 2568 } 2569 else { 2570 target_min = **args; 2571 target_max = target_min + 1; 2572 } 2573 } 2574 else { 2575 PrintMessage(MSG_UNKNOWN_OPTION, *args); 2576 PrintMessage(MSG_HINT_ULINK, help_progname); 2577 return VFD_NG; 2578 } 2579 2580 args++; 2581 } 2582 2583 if (target_min == TARGET_NONE) { 2584 // default: drive 0 2585 target_min = '0'; 2586 target_max = '1'; 2587 PrintMessage(MSG_TARGET_NOTICE, target_min); 2588 } 2589 2590 // ensure that the driver is installed 2591 2592 if (driver_state == VFD_NOT_INSTALLED) { 2593 PrintMessage(MSG_NOT_INSTALLED); 2594 return VFD_NG; 2595 } 2596 2597 // ensure that the driver is up to date 2598 2599 if (CheckDriver() != VFD_OK) { 2600 return VFD_NG; 2601 } 2602 2603 // ensure that the driver is running 2604 2605 if (driver_state != SERVICE_RUNNING) { 2606 PrintMessage(MSG_NOT_STARTED); 2607 return VFD_NG; 2608 } 2609 2610 while (target_min < target_max) { 2611 ULONG number; 2612 2613 hDevice = VfdOpenDevice(target_min); 2614 2615 if (hDevice == INVALID_HANDLE_VALUE) { 2616 ret = GetLastError(); 2617 PrintMessage(MSG_ACCESS_NG, target_min); 2618 printf("%s", SystemError(ret)); 2619 target_min++; 2620 continue; 2621 } 2622 2623 ret = VfdGetDeviceNumber(hDevice, &number); 2624 2625 if (ret != ERROR_SUCCESS) { 2626 PrintMessage(MSG_ACCESS_NG, target_min); 2627 printf("%s", SystemError(ret)); 2628 CloseHandle(hDevice); 2629 target_min++; 2630 continue; 2631 } 2632 2633 VfdSetGlobalLink(hDevice, 0); 2634 VfdSetLocalLink(hDevice, 0); 2635 2636 PrintDriveLetter(hDevice, number); 2637 2638 CloseHandle(hDevice); 2639 2640 target_min++; 2641 } 2642 2643 return VFD_OK; 2644 } 2645 2646 // 2647 // Print current driver state 2648 // Command Line Parameters: None 2649 // 2650 int Status(const char **args) 2651 { 2652 HANDLE hDevice; 2653 TCHAR path[MAX_PATH]; 2654 DWORD start_type; 2655 DWORD version; 2656 ULONG target; 2657 DWORD ret; 2658 2659 UNREFERENCED_PARAMETER(args); 2660 2661 if (driver_state == VFD_NOT_INSTALLED) { 2662 PrintMessage(MSG_NOT_INSTALLED); 2663 } 2664 else { 2665 2666 // get current driver config 2667 2668 ret = VfdGetDriverConfig(path, &start_type); 2669 2670 if (ret != ERROR_SUCCESS) { 2671 PrintMessage(MSG_GET_CONFIG_NG); 2672 printf("%s", SystemError(ret)); 2673 return VFD_NG; 2674 } 2675 2676 // print driver file path 2677 2678 PrintMessage(MSG_DRIVER_FILE, path); 2679 2680 // print driver version 2681 version = 0; 2682 2683 if (driver_state == SERVICE_RUNNING) { 2684 2685 hDevice = VfdOpenDevice(0); 2686 2687 if (hDevice != INVALID_HANDLE_VALUE) { 2688 ret = VfdGetDriverVersion(hDevice, &version); 2689 2690 CloseHandle(hDevice); 2691 } 2692 2693 } 2694 2695 if (version == 0) { 2696 ret = VfdCheckDriverFile(path, &version); 2697 } 2698 2699 if (ret == ERROR_SUCCESS) { 2700 PrintMessage(MSG_DRIVER_VERSION, 2701 HIWORD(version) & 0x7fff, 2702 LOWORD(version), 2703 (version & 0x80000000) ? "(debug)" : ""); 2704 } 2705 else { 2706 PrintMessage(MSG_GET_VERSION_NG); 2707 printf("%s", SystemError(ret)); 2708 } 2709 2710 2711 // print driver start type 2712 2713 PrintMessage(MSG_START_TYPE); 2714 2715 switch (start_type) { 2716 case SERVICE_AUTO_START: 2717 PrintMessage(MSG_START_AUTO); 2718 break; 2719 2720 case SERVICE_BOOT_START: 2721 PrintMessage(MSG_START_BOOT); 2722 break; 2723 2724 case SERVICE_DEMAND_START: 2725 PrintMessage(MSG_START_DEMAND); 2726 break; 2727 2728 case SERVICE_DISABLED: 2729 PrintMessage(MSG_START_DISABLED); 2730 break; 2731 2732 case SERVICE_SYSTEM_START : 2733 PrintMessage(MSG_START_SYSTEM); 2734 break; 2735 2736 default: 2737 PrintMessage(MSG_UNKNOWN_LONG, start_type); 2738 break; 2739 } 2740 2741 // print current driver state 2742 2743 PrintMessage(MSG_DRIVER_STATUS); 2744 2745 switch (driver_state) { 2746 case SERVICE_STOPPED: 2747 PrintMessage(MSG_STATUS_STOPPED); 2748 break; 2749 2750 case SERVICE_START_PENDING: 2751 PrintMessage(MSG_STATUS_START_P); 2752 break; 2753 2754 case SERVICE_STOP_PENDING: 2755 PrintMessage(MSG_STATUS_STOP_P); 2756 break; 2757 2758 case SERVICE_RUNNING: 2759 PrintMessage(MSG_STATUS_RUNNING); 2760 break; 2761 2762 case SERVICE_CONTINUE_PENDING: 2763 PrintMessage(MSG_STATUS_CONT_P); 2764 break; 2765 2766 case SERVICE_PAUSE_PENDING: 2767 PrintMessage(MSG_STATUS_PAUSE_P); 2768 break; 2769 2770 case SERVICE_PAUSED: 2771 PrintMessage(MSG_STATUS_PAUSED); 2772 break; 2773 2774 default: 2775 PrintMessage(MSG_UNKNOWN_LONG, driver_state); 2776 break; 2777 } 2778 } 2779 2780 // print shell extension status 2781 2782 printf("\n"); 2783 2784 if (VfdCheckHandlers() == ERROR_SUCCESS) { 2785 PrintMessage(MSG_SHELLEXT_ENABLED); 2786 } 2787 else { 2788 PrintMessage(MSG_SHELLEXT_DISABLED); 2789 } 2790 2791 // if driver is not running, no more info 2792 2793 if (driver_state != SERVICE_RUNNING) { 2794 return VFD_OK; 2795 } 2796 2797 // print image information 2798 2799 for (target = 0; target < VFD_MAXIMUM_DEVICES; target++) { 2800 HANDLE hDevice = VfdOpenDevice(target); 2801 2802 if (hDevice == INVALID_HANDLE_VALUE) { 2803 ret = GetLastError(); 2804 PrintMessage(MSG_ACCESS_NG, target + '0'); 2805 printf("%s", SystemError(ret)); 2806 return VFD_NG; 2807 } 2808 2809 PrintImageInfo(hDevice); 2810 2811 CloseHandle(hDevice); 2812 } 2813 2814 return VFD_OK; 2815 } 2816 2817 // 2818 // Print usage help 2819 // 2820 int Help(const char **args) 2821 { 2822 DWORD msg = MSG_HELP_GENERAL; 2823 char *buf = NULL; 2824 2825 if (args && *args) { 2826 int cmd = ParseHelpTopic(*args); 2827 2828 if (cmd < 0) { 2829 msg = MSG_HELP_HELP; 2830 } 2831 else { 2832 msg = HelpMsg[cmd].help; 2833 } 2834 } 2835 2836 FormatMessage( 2837 FORMAT_MESSAGE_FROM_HMODULE | 2838 FORMAT_MESSAGE_ALLOCATE_BUFFER | 2839 FORMAT_MESSAGE_ARGUMENT_ARRAY, 2840 NULL, msg, 0, (LPTSTR)&buf, 0, 2841 (va_list *)&help_progname); 2842 2843 if (buf == NULL) { 2844 printf("%s", SystemError(GetLastError())); 2845 return VFD_NG; 2846 } 2847 2848 ConsolePager(buf, TRUE); 2849 LocalFree(buf); 2850 2851 return VFD_OK; 2852 } 2853 2854 // 2855 // Print version information 2856 // 2857 int Version(const char **args) 2858 { 2859 UNREFERENCED_PARAMETER(args); 2860 2861 printf(VFD_PRODUCT_DESC "\n" VFD_COPYRIGHT_STR "\n" 2862 "http://chitchat.at.infoseek.co.jp/vmware/vfd.html\n"); 2863 2864 return VFD_OK; 2865 } 2866 2867 // 2868 // Parse command parameter 2869 // 2870 int ParseCommand(const char *cmd) 2871 { 2872 #define CMD_MATCH_NONE -1 2873 #define CMD_MATCH_MULTI -2 2874 2875 size_t len; 2876 int idx; 2877 int match; 2878 2879 // skip a leading '/' 2880 2881 if (*cmd == '/') { 2882 cmd++; 2883 } 2884 2885 if (*cmd == '\0') { 2886 2887 // empty command 2888 2889 return CMD_MATCH_NONE; 2890 } 2891 2892 // find a match 2893 len = strlen(cmd); 2894 idx = 0; 2895 match = CMD_MATCH_NONE; 2896 2897 while (Commands[idx].cmd) { 2898 2899 if (strlen(Commands[idx].cmd) >= len && 2900 !_strnicmp(cmd, Commands[idx].cmd, len)) { 2901 2902 if (match == CMD_MATCH_NONE) { // first match 2903 match = idx; 2904 } 2905 else { // multiple matches 2906 if (match != CMD_MATCH_MULTI) { // first time 2907 PrintMessage(MSG_AMBIGUOUS_COMMAND, cmd); 2908 printf("> %s ", Commands[match].cmd); 2909 match = CMD_MATCH_MULTI; 2910 } 2911 2912 printf("%s ", Commands[idx].cmd); 2913 } 2914 } 2915 2916 idx++; 2917 } 2918 2919 if (match == CMD_MATCH_NONE) { // match not found 2920 PrintMessage(MSG_UNKNOWN_COMMAND, cmd); 2921 } 2922 else if (match == CMD_MATCH_MULTI) { // multiple matches 2923 printf("\n"); 2924 } 2925 2926 return match; 2927 } 2928 2929 int ParseHelpTopic(const char *topic) 2930 { 2931 size_t len; 2932 int idx; 2933 int match; 2934 2935 if (*topic == '\0') { 2936 2937 // empty command 2938 2939 return CMD_MATCH_NONE; 2940 } 2941 2942 // find a match 2943 len = strlen(topic); 2944 idx = 0; 2945 match = CMD_MATCH_NONE; 2946 2947 while (HelpMsg[idx].keyword) { 2948 2949 if (strlen(HelpMsg[idx].keyword) >= len && 2950 !_strnicmp(topic, HelpMsg[idx].keyword, len)) { 2951 2952 if (match == CMD_MATCH_NONE) { // first match 2953 match = idx; 2954 } 2955 else { // multiple matches 2956 if (match != CMD_MATCH_MULTI) { // first time 2957 PrintMessage(MSG_AMBIGUOUS_COMMAND, topic); 2958 printf("> %s ", HelpMsg[match].keyword); 2959 match = CMD_MATCH_MULTI; 2960 } 2961 2962 printf("%s ", HelpMsg[idx].keyword); 2963 } 2964 } 2965 2966 idx++; 2967 } 2968 2969 if (match == CMD_MATCH_NONE) { // match not found 2970 PrintMessage(MSG_UNKNOWN_COMMAND, topic); 2971 } 2972 else if (match == CMD_MATCH_MULTI) { // multiple matches 2973 printf("\n"); 2974 } 2975 2976 return match; 2977 } 2978 2979 // 2980 // Check driver version and update if necessary 2981 // 2982 int CheckDriver() 2983 { 2984 char path[MAX_PATH]; 2985 DWORD start; 2986 2987 // check installed driver file version 2988 2989 if (VfdGetDriverConfig(path, &start) == ERROR_SUCCESS && 2990 VfdCheckDriverFile(path, NULL) == ERROR_SUCCESS) { 2991 2992 HANDLE hDevice; 2993 2994 if (driver_state != SERVICE_RUNNING) { 2995 return VFD_OK; 2996 } 2997 2998 // check running driver version 2999 3000 hDevice = VfdOpenDevice(0); 3001 3002 if (hDevice != INVALID_HANDLE_VALUE) { 3003 CloseHandle(hDevice); 3004 return VFD_OK; 3005 } 3006 } 3007 3008 PrintMessage(MSG_WRONG_DRIVER); 3009 return VFD_NG; 3010 } 3011 3012 // 3013 // Print a prompt message and accept the reply input 3014 // 3015 int InputChar(ULONG msg, PCSTR ans) 3016 { 3017 HANDLE hStdIn; 3018 INPUT_RECORD input; 3019 DWORD result; 3020 int reply; 3021 3022 PrintMessage(msg); 3023 fflush(NULL); 3024 3025 hStdIn = GetStdHandle(STD_INPUT_HANDLE); 3026 3027 FlushConsoleInputBuffer(hStdIn); 3028 3029 for (;;) { 3030 ReadConsoleInput(hStdIn, &input, sizeof(input), &result); 3031 3032 if (input.EventType == KEY_EVENT && 3033 input.Event.KeyEvent.bKeyDown) { 3034 3035 reply = tolower(input.Event.KeyEvent.uChar.AsciiChar); 3036 3037 if (strchr(ans, reply)) { 3038 break; 3039 } 3040 } 3041 } 3042 3043 printf("%c\n", reply); 3044 3045 return reply; 3046 } 3047 3048 // 3049 // Print image information on a Virtual Floppy Drive 3050 // 3051 void PrintImageInfo( 3052 HANDLE hDevice) 3053 { 3054 ULONG device_number; 3055 CHAR file_name[MAX_PATH]; 3056 CHAR file_desc[MAX_PATH]; 3057 VFD_DISKTYPE disk_type; 3058 VFD_MEDIA media_type; 3059 VFD_FLAGS media_flags; 3060 VFD_FILETYPE file_type; 3061 ULONG image_size; 3062 DWORD ret; 3063 3064 printf("\n"); 3065 3066 // get current device number 3067 3068 ret = VfdGetDeviceNumber(hDevice, &device_number); 3069 3070 if (ret != ERROR_SUCCESS) { 3071 PrintMessage(MSG_GET_LINK_NG); 3072 printf("%s", SystemError(ret)); 3073 device_number = (ULONG)-1; 3074 } 3075 3076 // get current drive letters 3077 3078 PrintDriveLetter(hDevice, device_number); 3079 3080 // image file information 3081 3082 ret = VfdGetImageInfo(hDevice, file_name, &disk_type, 3083 &media_type, &media_flags, &file_type, &image_size); 3084 3085 if (ret != ERROR_SUCCESS) { 3086 PrintMessage(MSG_GET_FILE_NG); 3087 printf("%s", SystemError(ret)); 3088 return; 3089 } 3090 3091 // print image file information 3092 if (media_type == VFD_MEDIA_NONE) { 3093 PrintMessage(MSG_IMAGE_NONE); 3094 return; 3095 } 3096 3097 if (file_name[0]) { 3098 PrintMessage(MSG_IMAGE_NAME, file_name); 3099 3100 VfdMakeFileDesc(file_desc, sizeof(file_desc), 3101 file_type, image_size, GetFileAttributes(file_name)); 3102 } 3103 else { 3104 PrintMessage(MSG_IMAGE_NAME, "<RAM>"); 3105 3106 VfdMakeFileDesc(file_desc, sizeof(file_desc), 3107 VFD_FILETYPE_NONE, image_size, 0); 3108 } 3109 3110 PrintMessage(MSG_FILE_DESC, file_desc); 3111 3112 if (disk_type == VFD_DISKTYPE_FILE) { 3113 PrintMessage(MSG_DISKTYPE_FILE); 3114 } 3115 else { 3116 if (media_flags & VFD_FLAG_DATA_MODIFIED) { 3117 PrintMessage(MSG_DISKTYPE_RAM_DIRTY); 3118 } 3119 else { 3120 PrintMessage(MSG_DISKTYPE_RAM_CLEAN); 3121 } 3122 } 3123 3124 // print other file info 3125 3126 PrintMessage(MSG_MEDIA_TYPE, VfdMediaTypeName(media_type)); 3127 3128 if (media_flags & VFD_FLAG_WRITE_PROTECTED) { 3129 PrintMessage(MSG_MEDIA_PROTECTED); 3130 } 3131 else { 3132 PrintMessage(MSG_MEDIA_WRITABLE); 3133 } 3134 } 3135 3136 // 3137 // Print drive letters on a virtual floppy drive 3138 // 3139 void PrintDriveLetter( 3140 HANDLE hDevice, 3141 ULONG nDrive) 3142 { 3143 CHAR letter; 3144 3145 PrintMessage(MSG_DRIVE_LETTER, nDrive); 3146 3147 VfdGetGlobalLink(hDevice, &letter); 3148 3149 if (isalpha(letter)) { 3150 PrintMessage(MSG_PERSISTENT, toupper(letter)); 3151 } 3152 3153 while (VfdGetLocalLink(hDevice, &letter) == ERROR_SUCCESS && 3154 isalpha(letter)) { 3155 PrintMessage(MSG_EPHEMERAL, toupper(letter)); 3156 } 3157 3158 printf("\n"); 3159 } 3160 3161 // 3162 // Prints a text on screen a page a time 3163 // 3164 BOOL ConsolePager(char *pBuffer, BOOL bReset) 3165 { 3166 static int rows = 0; 3167 char prompt[80]; 3168 int prompt_len = 0; 3169 HANDLE hStdOut; 3170 HANDLE hStdIn; 3171 3172 // 3173 // prepare the console input and output handles 3174 // 3175 hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 3176 hStdIn = GetStdHandle(STD_INPUT_HANDLE); 3177 3178 for (;;) { 3179 CONSOLE_SCREEN_BUFFER_INFO info; 3180 INPUT_RECORD input; 3181 DWORD result; 3182 DWORD mode; 3183 int cols; 3184 char *cur; 3185 char save; 3186 3187 // 3188 // Get the current console screen information 3189 // 3190 GetConsoleScreenBufferInfo(hStdOut, &info); 3191 3192 if (bReset || rows <= 0) { 3193 rows = info.srWindow.Bottom - info.srWindow.Top - 1; 3194 } 3195 3196 cols = info.dwSize.X; 3197 3198 // console window is too small for paging 3199 3200 if (rows <= 0) { 3201 // print all text and exit 3202 printf("%s", pBuffer); 3203 break; 3204 } 3205 3206 // 3207 // find the tail of the text to be printed this time 3208 // 3209 cur = pBuffer; 3210 save = '\0'; 3211 3212 while (*cur) { 3213 if (*(cur++) == '\n' || (cols--) == 0) { 3214 // reached the end of a line 3215 if (--rows == 0) { 3216 // reached the end of a page 3217 // insert a terminating NULL char 3218 save = *cur; 3219 *cur = '\0'; 3220 break; 3221 } 3222 3223 cols = info.dwSize.X; 3224 } 3225 } 3226 3227 // print the current page 3228 printf("%s", pBuffer); 3229 3230 // end of the whole text? 3231 if (save == '\0') { 3232 break; 3233 } 3234 3235 // 3236 // prompt for the next page 3237 // 3238 3239 // prepare the prompt text 3240 3241 if (prompt_len == 0) { 3242 3243 prompt_len = FormatMessage( 3244 FORMAT_MESSAGE_FROM_HMODULE | 3245 FORMAT_MESSAGE_IGNORE_INSERTS, 3246 NULL, MSG_PAGER_PROMPT, 0, 3247 prompt, sizeof(prompt), NULL); 3248 3249 if (prompt_len == 0) { 3250 strcpy(prompt, "Press any key to continue..."); 3251 prompt_len = strlen(prompt); 3252 } 3253 } 3254 3255 // get the current console input mode 3256 3257 GetConsoleMode(hStdIn, &mode); 3258 3259 // change the mode to receive Ctrl+C as a regular input 3260 3261 SetConsoleMode(hStdIn, (mode & ~ENABLE_PROCESSED_INPUT)); 3262 3263 // get the current cursor position 3264 3265 GetConsoleScreenBufferInfo(hStdOut, &info); 3266 3267 // print the prompt text 3268 3269 WriteConsoleOutputCharacter(hStdOut, prompt, 3270 prompt_len, info.dwCursorPosition, &result); 3271 3272 // reverse the text color 3273 3274 FillConsoleOutputAttribute(hStdOut, 3275 (WORD)(info.wAttributes | COMMON_LVB_REVERSE_VIDEO), 3276 prompt_len, info.dwCursorPosition, &result); 3277 3278 // move cursor to the end of the prompt text 3279 3280 info.dwCursorPosition.X = 3281 (short)(info.dwCursorPosition.X + prompt_len); 3282 3283 SetConsoleCursorPosition(hStdOut, info.dwCursorPosition); 3284 3285 // wait for a key press event 3286 3287 FlushConsoleInputBuffer(hStdIn); 3288 3289 do { 3290 ReadConsoleInput(hStdIn, &input, sizeof(input), &result); 3291 } 3292 while (input.EventType != KEY_EVENT || 3293 !input.Event.KeyEvent.bKeyDown || 3294 !input.Event.KeyEvent.uChar.AsciiChar); 3295 3296 // restore the original cursor position 3297 3298 info.dwCursorPosition.X = 3299 (short)(info.dwCursorPosition.X - prompt_len); 3300 3301 SetConsoleCursorPosition(hStdOut, info.dwCursorPosition); 3302 3303 // delete the prompt text 3304 3305 FillConsoleOutputCharacter(hStdOut, ' ', 3306 prompt_len, info.dwCursorPosition, &result); 3307 3308 // restore the text attribute to norml 3309 3310 FillConsoleOutputAttribute(hStdOut, info.wAttributes, 3311 prompt_len, info.dwCursorPosition, &result); 3312 3313 // restore the original console mode 3314 3315 SetConsoleMode(hStdIn, mode); 3316 3317 // check if the input was 'q', <esc> or <Ctrl+C> ? 3318 3319 if (input.Event.KeyEvent.uChar.AsciiChar == VK_CANCEL || 3320 input.Event.KeyEvent.uChar.AsciiChar == VK_ESCAPE || 3321 tolower(input.Event.KeyEvent.uChar.AsciiChar) == 'q') { 3322 3323 // cancelled by the user 3324 return FALSE; 3325 } 3326 3327 // 3328 // process the next page 3329 // 3330 *cur = save; 3331 pBuffer = cur; 3332 } 3333 3334 return TRUE; 3335 } 3336 3337 // 3338 // Format and print a message text 3339 // 3340 void PrintMessage(UINT msg, ...) 3341 { 3342 char *buf = NULL; 3343 va_list list; 3344 3345 va_start(list, msg); 3346 3347 if (FormatMessage( 3348 FORMAT_MESSAGE_FROM_HMODULE | 3349 FORMAT_MESSAGE_ALLOCATE_BUFFER, 3350 NULL, msg, 0, (LPTSTR)&buf, 0, &list)) { 3351 3352 printf("%s", buf); 3353 } 3354 else { 3355 printf("Unknown Message ID %u\n", msg); 3356 } 3357 3358 va_end(list); 3359 3360 if (buf) { 3361 LocalFree(buf); 3362 } 3363 } 3364 3365 // 3366 // Return a system error message text 3367 // 3368 const char *SystemError(DWORD err) 3369 { 3370 static char msg[256]; 3371 3372 if (!FormatMessage( 3373 FORMAT_MESSAGE_FROM_SYSTEM | 3374 FORMAT_MESSAGE_IGNORE_INSERTS, 3375 NULL, err, 0, msg, sizeof(msg), NULL)) { 3376 #ifndef __REACTOS__ 3377 sprintf(msg, "Unknown system error %lu (0x%08x)\n", err, err); 3378 #else 3379 sprintf(msg, "Unknown system error %lu (0x%08lx)\n", err, err); 3380 #endif 3381 } 3382 3383 return msg; 3384 } 3385 3386 // 3387 // Convert a path to match the case of names on the disk 3388 // 3389 void ConvertPathCase(char *src, char *dst) 3390 { 3391 HANDLE hFind; 3392 WIN32_FIND_DATA find; 3393 char *p; 3394 3395 p = dst; 3396 3397 if (*src == '\"') { 3398 src++; 3399 } 3400 3401 if (*(src + strlen(src) - 1) == '\"') { 3402 *(src + strlen(src) - 1) = '\0'; 3403 } 3404 3405 // 3406 // handle drive / remote server name 3407 // 3408 if (isalpha(*src) && *(src + 1) == ':') { 3409 3410 // drive name 3411 3412 *(p++) = (char)toupper(*src); 3413 strcpy(p++, ":\\"); 3414 3415 src += 2; 3416 } 3417 else if (*src == '\\' || *src == '/') { 3418 3419 // absolute path or remote name 3420 3421 if ((*(src + 1) == '\\' || *(src + 1) == '/') && 3422 *(src + 2) && *(src + 2) != '\\' && *(src + 2) != '/') { 3423 3424 // remote path 3425 3426 *(p++) = '\\'; 3427 *(p++) = '\\'; 3428 src += 2; 3429 3430 while (*src && *src != '\\' && *src != '/') { 3431 *(p++) = *(src++); 3432 } 3433 } 3434 3435 strcpy(p, "\\"); 3436 } 3437 else { 3438 *p = '\0'; 3439 } 3440 3441 // skip redundant '\' 3442 3443 while (*src == '\\' || *src == '/') { 3444 src++; 3445 } 3446 3447 // process the path 3448 3449 while (*src) { 3450 3451 char *q = src; 3452 3453 // separate the next part 3454 3455 while (*q && *q != '\\' && *q != '/') { 3456 q++; 3457 } 3458 3459 if ((q - src) == 2 && !strncmp(src, "..", 2)) { 3460 // parent dir - copy as it is 3461 if (p != dst) { 3462 *p++ = '\\'; 3463 } 3464 3465 strcpy(p, ".."); 3466 p += 2; 3467 } 3468 else if ((q - src) > 1 || *src != '.') { 3469 // path name other than "." 3470 if (p != dst) { 3471 *(p++) = '\\'; 3472 } 3473 3474 strncpy(p, src, (q - src)); 3475 *(p + (q - src)) = '\0'; 3476 3477 hFind = FindFirstFile(dst, &find); 3478 3479 if (hFind == INVALID_HANDLE_VALUE) { 3480 strcpy(p, src); 3481 break; 3482 } 3483 3484 FindClose(hFind); 3485 3486 strcpy(p, find.cFileName); 3487 p += strlen(p); 3488 } 3489 3490 // skip trailing '\'s 3491 3492 while (*q == '\\' || *q == '/') { 3493 q++; 3494 } 3495 3496 src = q; 3497 } 3498 } 3499