1 /* 2 vfdctl.c 3 4 Virtual Floppy Drive for Windows 5 Driver control library 6 Driver and image control functions 7 8 Copyright (C) 2003-2005 Ken Kato 9 */ 10 11 #ifdef __cplusplus 12 #pragma message(__FILE__": Compiled as C++ for testing purpose.") 13 #endif // __cplusplus 14 15 #define WIN32_LEAN_AND_MEAN 16 #include <windows.h> 17 #include <dbt.h> 18 #if !defined(__REACTOS__) || defined(_MSC_VER) 19 #pragma warning (push, 3) 20 #endif 21 #include <shlobj.h> 22 #include <winioctl.h> 23 #if !defined(__REACTOS__) || defined(_MSC_VER) 24 #pragma warning (pop) 25 #endif 26 #include <stdio.h> 27 28 #include "vfdtypes.h" 29 #include "vfdio.h" 30 #include "vfdapi.h" 31 #include "vfdlib.h" 32 #include "vfdver.h" 33 34 #ifndef IOCTL_DISK_GET_LENGTH_INFO 35 // Old winioctl.h header doesn't define the following 36 37 #define IOCTL_DISK_GET_LENGTH_INFO CTL_CODE(\ 38 IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS) 39 40 typedef struct _GET_LENGTH_INFORMATION { 41 LARGE_INTEGER Length; 42 } GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION; 43 44 #endif // IOCTL_DISK_GET_LENGTH_INFO 45 46 // 47 // DOS device name (\\.\VirtualFD) 48 // 49 #ifndef __REACTOS__ 50 #define VFD_DEVICE_TEMPLATE "\\\\.\\" VFD_DEVICE_BASENAME "%u" 51 #else 52 #define VFD_DEVICE_TEMPLATE "\\\\.\\" VFD_DEVICE_BASENAME "%lu" 53 #endif 54 #define VFD_VOLUME_TEMPLATE "\\\\.\\%c:" 55 56 #define VFD_INSTALL_DIRECTORY "\\system32\\drivers\\" 57 58 #ifdef _DEBUG 59 #ifndef __REACTOS__ 60 extern ULONG TraceFlags = (ULONG)-1;//0; 61 extern CHAR *TraceFile = NULL; 62 extern ULONG TraceLine = 0; 63 #else 64 ULONG TraceFlags = (ULONG)-1;//0; 65 CHAR const * TraceFile = NULL; 66 ULONG TraceLine = 0; 67 #endif 68 #endif 69 70 // 71 // broadcast a WM_DEVICECHANGE system message to inform 72 // a drive letter creation / removal 73 // 74 #define VFD_LINK_CREATED 0 75 #define VFD_LINK_REMOVED 1 76 77 static void VfdBroadcastLink( 78 CHAR cLetter, 79 BOOL bRemoved) 80 { 81 DWORD receipients; 82 DWORD device_event; 83 DEV_BROADCAST_VOLUME params; 84 85 if (!isalpha(cLetter)) { 86 VFDTRACE(0, 87 ("VfdBroadcastLink: invalid parameter")) 88 return; 89 } 90 91 receipients = BSM_APPLICATIONS; 92 93 device_event = bRemoved ? 94 DBT_DEVICEREMOVECOMPLETE : DBT_DEVICEARRIVAL; 95 96 ZeroMemory(¶ms, sizeof(params)); 97 98 params.dbcv_size = sizeof(params); 99 params.dbcv_devicetype = DBT_DEVTYP_VOLUME; 100 params.dbcv_reserved = 0; 101 params.dbcv_unitmask = (1 << (toupper(cLetter) - 'A')); 102 params.dbcv_flags = 0; 103 104 if (BroadcastSystemMessage( 105 BSF_NOHANG | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG, 106 &receipients, 107 WM_DEVICECHANGE, 108 device_event, 109 (LPARAM)¶ms) <= 0) { 110 111 VFDTRACE(0, 112 ("VfdBroadcastLink: BroadcastSystemMessage - %s", 113 SystemMessage(GetLastError()))); 114 } 115 } 116 117 // 118 // Broadcast a VFD notify message 119 // 120 static __inline void VfdNotify( 121 WPARAM wParam, 122 LPARAM lParam) 123 { 124 // SendNotifyMessage causes volume locking conflict (I think) 125 // on Windows XP while closing an image with VfdWin 126 // SendNotifyMessage(HWND_BROADCAST, uVfdMsg, wParam, lParam); 127 PostMessage(HWND_BROADCAST, g_nNotifyMsg, wParam, lParam); 128 } 129 130 #ifdef VFD_EMBED_DRIVER 131 // 132 // Restore the VFD driver file in the system directory 133 // 134 135 static DWORD VfdRestoreDriver( 136 PCSTR sPath) 137 { 138 #define FUNC "VfdRestoreDriver" 139 HRSRC hRes; 140 DWORD size; 141 HGLOBAL hDrv; 142 PVOID pData; 143 DWORD result; 144 HANDLE hFile; 145 DWORD ret; 146 147 // 148 // Prepare driver binary 149 // 150 151 // use embedded driver binary 152 153 #define S(s) #s 154 hRes = FindResource(g_hDllModule, 155 S(VFD_DRIVER_NAME_ID), S(VFD_DRIVER_TYPE_ID)); 156 #undef S 157 158 if (hRes == NULL) { 159 ret = GetLastError(); 160 161 VFDTRACE(0, 162 (FUNC ": FindResource - %s", 163 SystemMessage(ret))); 164 165 return ret; 166 } 167 168 size = SizeofResource(g_hDllModule, hRes); 169 170 if (size == 0) { 171 ret = GetLastError(); 172 173 VFDTRACE(0, 174 (FUNC ": SizeofResource - %s", 175 SystemMessage(ret))); 176 177 return ret; 178 } 179 180 hDrv = LoadResource(g_hDllModule, hRes); 181 182 if (hDrv == NULL) { 183 ret = GetLastError(); 184 185 VFDTRACE(0, 186 (FUNC ": LoadResource - %s", 187 SystemMessage(ret))); 188 189 return ret; 190 } 191 192 pData = LockResource(hDrv); 193 194 if (pData == NULL) { 195 ret = GetLastError(); 196 197 VFDTRACE(0, 198 (FUNC ": LockResource - %s", 199 SystemMessage(ret))); 200 201 return ret; 202 } 203 204 // create the driver file 205 206 hFile = CreateFile(sPath, GENERIC_WRITE, 207 0, NULL, OPEN_ALWAYS, 0, NULL); 208 209 if (hFile == INVALID_HANDLE_VALUE) { 210 ret = GetLastError(); 211 212 VFDTRACE(0, 213 (FUNC ": CreateFile(%s) - %s", 214 sPath, SystemMessage(ret))); 215 216 return ret; 217 } 218 219 if (!WriteFile(hFile, pData, size, &result, NULL) || 220 size != result) { 221 ret = GetLastError(); 222 223 VFDTRACE(0, 224 (FUNC ": CreateFile - %s", 225 SystemMessage(ret))); 226 227 CloseHandle(hFile); 228 return ret; 229 } 230 231 SetEndOfFile(hFile); 232 CloseHandle(hFile); 233 234 return ERROR_SUCCESS; 235 } 236 #endif // VFD_EMBED_DRIVER 237 238 // 239 // Install the Virtual Floppy Driver 240 // 241 DWORD WINAPI VfdInstallDriver( 242 PCSTR sFileName, 243 DWORD nStart) 244 { 245 #undef FUNC 246 #define FUNC "VfdInstallDriver" 247 SC_HANDLE hScManager; // Service Control Manager 248 SC_HANDLE hService = NULL; // Service (= Driver) 249 #ifndef VFD_EMBED_DRIVER 250 CHAR file_path[MAX_PATH]; 251 PSTR file_name; 252 #endif // VFD_EMBED_DRIVER 253 CHAR system_dir[MAX_PATH]; 254 PSTR inst_path; 255 DWORD len; 256 DWORD ret = ERROR_SUCCESS; 257 258 #ifdef __REACTOS__ 259 CHAR full_file_path[MAX_PATH]; 260 #endif 261 262 // get SystemRoot directory path 263 264 // len = GetEnvironmentVariable( 265 // "SystemRoot", system_dir, sizeof(system_dir)); 266 len = GetWindowsDirectory(system_dir, sizeof(system_dir)); 267 268 if (len == 0 || len > sizeof(system_dir)) { 269 VFDTRACE(0, 270 (FUNC ": %%SystemRoot%% is empty or too long.\n")); 271 272 return ERROR_BAD_ENVIRONMENT; 273 } 274 275 inst_path = &system_dir[len]; 276 277 #ifdef __REACTOS__ 278 strcpy(full_file_path, system_dir); 279 strcat(full_file_path, VFD_INSTALL_DIRECTORY); 280 strcat(full_file_path, VFD_DRIVER_FILENAME); 281 #endif 282 283 #ifdef VFD_EMBED_DRIVER 284 // 285 // use embedded driver file 286 // 287 strcpy(inst_path++, VFD_INSTALL_DIRECTORY VFD_DRIVER_FILENAME); 288 289 ret = VfdRestoreDriver(system_dir); 290 291 if (ret != ERROR_SUCCESS) { 292 return ret; 293 } 294 295 #else // VFD_EMBED_DRIVER 296 // Prepare driver binary's full path 297 298 if (sFileName == NULL || *sFileName == '\0') { 299 300 // default driver file is vfd.sys in the same directory as executable 301 302 len = GetModuleFileName( 303 NULL, file_path, sizeof(file_path)); 304 305 if (len == 0) { 306 ret = GetLastError(); 307 308 VFDTRACE(0, 309 (FUNC ": GetModuleFileName - %s", 310 SystemMessage(ret))); 311 312 return ret; 313 } 314 315 // search the last '\' character 316 317 while (len > 0 && file_path[len - 1] != '\\') { 318 len --; 319 } 320 321 // supply the file name (vfd.sys) 322 323 file_name = &file_path[len]; 324 strcpy(file_name, VFD_DRIVER_FILENAME); 325 } 326 else { 327 328 // ensure that tha path is an absolute full path 329 330 len = GetFullPathName( 331 sFileName, 332 sizeof(file_path), 333 file_path, 334 &file_name); 335 336 if (len == 0) { 337 ret = GetLastError(); 338 339 VFDTRACE(0, 340 (FUNC ": GetFullPathName(%s) - %s\n", 341 sFileName, SystemMessage(ret))); 342 343 return ret; 344 } 345 346 if (GetFileAttributes(file_path) & FILE_ATTRIBUTE_DIRECTORY) { 347 // if the specified path is a directory, 348 // supply the file name (vfd.sys) 349 350 file_name = &file_path[len]; 351 strcpy(file_name++, "\\" VFD_DRIVER_FILENAME); 352 } 353 } 354 355 #ifdef __REACTOS__ 356 // Check install directory & file exist or use full_file_path 357 358 if (GetFileAttributesA(file_path) == INVALID_FILE_ATTRIBUTES) { 359 strcpy(file_path, full_file_path); 360 } 361 #endif 362 363 // Check if the file is a valid Virtual Floppy driver 364 365 ret = VfdCheckDriverFile(file_path, NULL); 366 367 if (ret != ERROR_SUCCESS) { 368 VFDTRACE(0, 369 (FUNC ": VfdCheckDriverFile(%s)\n", file_path)); 370 371 return ret; 372 } 373 374 // if the path is under the system directory, make it relative 375 // to the system directory 376 377 len = strlen(system_dir); 378 379 if (!_strnicmp(file_path, system_dir, len)) { 380 inst_path = &file_path[len]; 381 382 while (*inst_path == '\\') { 383 inst_path++; 384 } 385 } 386 else { 387 inst_path = &file_path[0]; 388 } 389 #endif // VFD_EMBED_DRIVER 390 391 // Connect to the Service Control Manager 392 393 hScManager = OpenSCManager( 394 NULL, // local machine 395 NULL, // local database 396 SC_MANAGER_CREATE_SERVICE); // access required 397 398 if (hScManager == NULL) { 399 ret = GetLastError(); 400 401 VFDTRACE(0, 402 (FUNC ": OpenSCManager() - %s", 403 SystemMessage(ret))); 404 405 goto cleanup; 406 } 407 408 // Create a new service object 409 410 hService = CreateService( 411 hScManager, // service control manager 412 VFD_DEVICE_BASENAME, // internal service name 413 VFD_DEVICE_BASENAME, // display name 414 SERVICE_ALL_ACCESS, // access mode 415 SERVICE_KERNEL_DRIVER, // service type 416 nStart, // service start type 417 SERVICE_ERROR_NORMAL, // start error sevirity 418 inst_path, // service image file path 419 NULL, // service group 420 NULL, // service tag 421 NULL, // service dependency 422 NULL, // use LocalSystem account 423 NULL // password for the account 424 ); 425 426 if (!hService) { 427 // Failed to create a service object 428 ret = GetLastError(); 429 430 VFDTRACE(0, 431 (FUNC ": CreateService() - %s", 432 SystemMessage(ret))); 433 434 goto cleanup; 435 } 436 437 cleanup: 438 // Close the service object handle 439 440 if (hService) { 441 CloseServiceHandle(hService); 442 } 443 444 // Close handle to the service control manager. 445 446 if (hScManager) { 447 CloseServiceHandle(hScManager); 448 } 449 450 if (ret == ERROR_SUCCESS) { 451 // Broadcast the successful operation 452 VfdNotify(VFD_OPERATION_INSTALL, 0); 453 } 454 #ifdef VFD_EMBED_DRIVER 455 else { 456 // Delete the restored driver file 457 DeleteFile(system_dir); 458 } 459 #endif // VFD_EMBED_DRIVER 460 461 return ret; 462 } 463 464 // 465 // Configure the Virtual Floppy Driver (change the start method) 466 // 467 468 DWORD WINAPI VfdConfigDriver( 469 DWORD nStart) 470 { 471 #undef FUNC 472 #define FUNC "VfdConfigDriver" 473 SC_HANDLE hScManager; // Service Control Manager 474 SC_HANDLE hService; // Service (= Driver) 475 DWORD ret = ERROR_SUCCESS; 476 477 // Connect to the Service Control Manager 478 479 hScManager = OpenSCManager(NULL, NULL, 0); 480 481 if (hScManager == NULL) { 482 ret = GetLastError(); 483 484 VFDTRACE(0, 485 (FUNC ": OpenSCManager() - %s", 486 SystemMessage(ret))); 487 488 return ret; 489 } 490 491 // Open the VFD driver entry in the service database 492 493 hService = OpenService( 494 hScManager, // Service control manager 495 VFD_DEVICE_BASENAME, // service name 496 SERVICE_CHANGE_CONFIG); // service access mode 497 498 if (hService == NULL) { 499 ret = GetLastError(); 500 501 VFDTRACE(0, 502 (FUNC ": OpenService(SERVICE_CHANGE_CONFIG) - %s", 503 SystemMessage(ret))); 504 505 goto cleanup; 506 } 507 508 // Change the start method of the VFD driver 509 510 if (!ChangeServiceConfig( 511 hService, 512 SERVICE_NO_CHANGE, 513 nStart, 514 SERVICE_NO_CHANGE, 515 NULL, 516 NULL, 517 NULL, 518 NULL, 519 NULL, 520 NULL, 521 NULL)) { 522 523 ret = GetLastError(); 524 525 VFDTRACE(0, 526 (FUNC ": ChangeServiceConfig() - %s", 527 SystemMessage(ret))); 528 529 goto cleanup; 530 } 531 532 cleanup: 533 // Close the service object handle 534 535 if (hService) { 536 CloseServiceHandle(hService); 537 } 538 539 // Close handle to the service control manager. 540 541 if (hScManager) { 542 CloseServiceHandle(hScManager); 543 } 544 545 // Broadcast the successful operation 546 547 if (ret == ERROR_SUCCESS) { 548 VfdNotify(VFD_OPERATION_CONFIG, 0); 549 } 550 551 return ret; 552 } 553 554 // 555 // Remove the Virtual Floppy Driver entry from the service database 556 // 557 DWORD WINAPI VfdRemoveDriver() 558 { 559 #undef FUNC 560 #define FUNC "VfdRemoveDriver" 561 SC_HANDLE hScManager; // Service Control Manager 562 SC_HANDLE hService; // Service (= Driver) 563 CHAR file_path[MAX_PATH]; 564 DWORD ret = ERROR_SUCCESS; 565 566 // Get the current driver path 567 568 ret = VfdGetDriverConfig(file_path, NULL); 569 570 if (ret != ERROR_SUCCESS) { 571 return ret; 572 } 573 574 // Connect to the Service Control Manager 575 576 hScManager = OpenSCManager(NULL, NULL, 0); 577 578 if (hScManager == NULL) { 579 ret = GetLastError(); 580 581 VFDTRACE(0, 582 (FUNC ": OpenSCManager() - %s", 583 SystemMessage(ret))); 584 585 return ret; 586 } 587 588 // Open the VFD driver entry in the service database 589 590 hService = OpenService( 591 hScManager, // Service control manager 592 VFD_DEVICE_BASENAME, // service name 593 DELETE); // service access mode 594 595 if (hService == NULL) { 596 ret = GetLastError(); 597 598 VFDTRACE(0, 599 (FUNC ": OpenService(DELETE) - %s", 600 SystemMessage(ret))); 601 602 goto cleanup; 603 } 604 605 // Remove driver entry from registry 606 607 if (!DeleteService(hService)) { 608 ret = GetLastError(); 609 610 VFDTRACE(0, 611 (FUNC ": DeleteService() - %s", 612 SystemMessage(ret))); 613 614 goto cleanup; 615 } 616 617 cleanup: 618 // Close the service object handle 619 620 if (hService) { 621 CloseServiceHandle(hService); 622 } 623 624 // Close handle to the service control manager. 625 626 if (hScManager) { 627 CloseServiceHandle(hScManager); 628 } 629 630 // Broadcast the successful operation 631 632 if (ret == ERROR_SUCCESS) { 633 VfdNotify(VFD_OPERATION_REMOVE, 0); 634 635 #ifdef VFD_EMBED_DRIVER 636 // Remove the driver file 637 DeleteFile(file_path); 638 #endif // VFD_EMBED_DRIVER 639 } 640 641 return ret; 642 } 643 644 // 645 // Start the Virtual Floppy Driver 646 // 647 DWORD WINAPI VfdStartDriver( 648 PDWORD pState) 649 { 650 #undef FUNC 651 #define FUNC "VfdStartDriver" 652 SC_HANDLE hScManager; // Service Control Manager 653 SC_HANDLE hService; // Service (= Driver) 654 SERVICE_STATUS stat; 655 DWORD ret = ERROR_SUCCESS; 656 HCURSOR original; 657 int i; 658 659 if (pState) { 660 *pState = 0; 661 } 662 663 // Connect to the Service Control Manager 664 665 hScManager = OpenSCManager(NULL, NULL, 0); 666 667 if (hScManager == NULL) { 668 ret = GetLastError(); 669 670 VFDTRACE(0, 671 (FUNC ": OpenSCManager() - %s", 672 SystemMessage(ret))); 673 674 return ret; 675 } 676 677 // show an hourglass cursor 678 679 original = SetCursor(LoadCursor(NULL, IDC_WAIT)); 680 681 // Open the VFD driver entry in the service database 682 683 hService = OpenService( 684 hScManager, // Service control manager 685 VFD_DEVICE_BASENAME, // service name 686 SERVICE_START 687 | SERVICE_QUERY_STATUS); // service access mode 688 689 if (hService == NULL) { 690 ret = GetLastError(); 691 692 VFDTRACE(0, 693 (FUNC ": OpenService(SERVICE_START) - %s", 694 SystemMessage(ret))); 695 696 goto cleanup; 697 } 698 699 // Start the driver 700 701 if (!StartService(hService, 0, NULL)) { 702 ret = GetLastError(); 703 704 VFDTRACE(0, 705 (FUNC ": StartService() - %s", 706 SystemMessage(ret))); 707 708 goto cleanup; 709 } 710 711 // Wait until the driver is properly running 712 713 i = 0; 714 715 for (;;) { 716 if (!QueryServiceStatus(hService, &stat)) { 717 ret = GetLastError(); 718 719 VFDTRACE(0, 720 (FUNC ": QueryServiceStatus() - %s", 721 SystemMessage(ret))); 722 723 break; 724 } 725 726 if (stat.dwCurrentState == SERVICE_RUNNING || ++i == 5) { 727 break; 728 } 729 730 Sleep(1000); 731 } 732 733 if (stat.dwCurrentState == SERVICE_RUNNING) { 734 735 // Broadcast the successful operation 736 737 if (ret == ERROR_SUCCESS) { 738 VfdNotify(VFD_OPERATION_START, 0); 739 } 740 741 // broadcast the arrival of VFD drives 742 // otherwise WinXP explorer doesn't recognize the VFD drives 743 744 for (i = 0; i < VFD_MAXIMUM_DEVICES; i++) { 745 HANDLE hDevice; 746 CHAR letter = 0; 747 748 hDevice = VfdOpenDevice(i); 749 750 if (hDevice != INVALID_HANDLE_VALUE) { 751 752 VfdGetGlobalLink(hDevice, &letter); 753 754 CloseHandle(hDevice); 755 756 if (isalpha(letter)) { 757 VfdBroadcastLink(letter, VFD_LINK_CREATED); 758 VfdNotify(VFD_OPERATION_SETLINK, i); 759 } 760 } 761 else { 762 VFDTRACE(0, 763 (FUNC ": VfdOpenDevice(%d) - %s", 764 i, SystemMessage(GetLastError()))); 765 } 766 } 767 } 768 else { 769 // somehow failed to start the driver 770 771 ret = ERROR_SERVICE_NOT_ACTIVE; 772 } 773 774 if (pState) { 775 *pState = stat.dwCurrentState; 776 } 777 778 cleanup: 779 // Close the service object handle 780 781 if (hService) { 782 CloseServiceHandle(hService); 783 } 784 785 // Close handle to the service control manager. 786 787 if (hScManager) { 788 CloseServiceHandle(hScManager); 789 } 790 791 // revert to the original cursor 792 793 SetCursor(original); 794 795 return ret; 796 } 797 798 // 799 // Stop the Virtual Floppy Driver 800 // 801 DWORD WINAPI VfdStopDriver( 802 PDWORD pState) 803 { 804 #undef FUNC 805 #define FUNC "VfdStopDriver" 806 SC_HANDLE hScManager; // Service Control Manager 807 SC_HANDLE hService; // Service (= Driver) 808 SERVICE_STATUS stat; 809 CHAR drive_letters[VFD_MAXIMUM_DEVICES]; 810 DWORD ret = ERROR_SUCCESS; 811 int i; 812 HCURSOR original; 813 814 if (pState) { 815 *pState = 0; 816 } 817 818 // Connect to the Service Control Manager 819 820 hScManager = OpenSCManager(NULL, NULL, 0); 821 822 if (hScManager == NULL) { 823 ret = GetLastError(); 824 825 VFDTRACE(0, 826 (FUNC ": OpenSCManager() - %s", 827 SystemMessage(ret))); 828 829 return ret; 830 } 831 832 // Show the hourglass cursor 833 834 original = SetCursor(LoadCursor(NULL, IDC_WAIT)); 835 836 // Open the VFD driver entry in the service database 837 838 hService = OpenService( 839 hScManager, // Service control manager 840 VFD_DEVICE_BASENAME, // service name 841 SERVICE_STOP 842 | SERVICE_QUERY_STATUS); // service access mode 843 844 if (hService == NULL) { 845 ret = GetLastError(); 846 847 VFDTRACE(0, 848 (FUNC ": OpenService(SERVICE_STOP) - %s", 849 SystemMessage(ret))); 850 851 goto cleanup; 852 } 853 854 // Get assigned drive letters 855 856 for (i = 0; i < VFD_MAXIMUM_DEVICES; i++) { 857 HANDLE hDevice; 858 CHAR letter; 859 860 hDevice = VfdOpenDevice(i); 861 862 if (hDevice != INVALID_HANDLE_VALUE) { 863 864 // remove all session local drive letters 865 866 while (VfdGetLocalLink(hDevice, &letter) == ERROR_SUCCESS && 867 isalpha(letter)) { 868 VfdSetLocalLink(hDevice, 0); 869 } 870 871 // store existing persistent drive letters 872 873 VfdGetGlobalLink(hDevice, &drive_letters[i]); 874 875 CloseHandle(hDevice); 876 } 877 else { 878 VFDTRACE(0, 879 (FUNC ": VfdOpenDevice(%d) - %s", 880 i, SystemMessage(GetLastError()))); 881 } 882 } 883 884 // Stop the driver 885 886 if (!ControlService(hService, SERVICE_CONTROL_STOP, &stat)) { 887 ret = GetLastError(); 888 889 VFDTRACE(0, 890 (FUNC ": ControlService(SERVICE_CONTROL_STOP) - %s", 891 SystemMessage(ret))); 892 893 goto cleanup; 894 } 895 896 // Wait until the driver is stopped 897 898 i = 0; 899 900 while (stat.dwCurrentState != SERVICE_STOPPED && ++i < 5) { 901 Sleep(1000); 902 903 if (!QueryServiceStatus(hService, &stat)) { 904 ret = GetLastError(); 905 906 VFDTRACE(0, 907 (FUNC ": QueryServiceStatus() - %s", 908 SystemMessage(ret))); 909 910 break; 911 } 912 } 913 914 if (stat.dwCurrentState != SERVICE_RUNNING) { 915 916 // broadcast the removal of persistent drive letters 917 918 for (i = 0; i < VFD_MAXIMUM_DEVICES; i++) { 919 if (isalpha(drive_letters[i])) { 920 VfdBroadcastLink(drive_letters[i], VFD_LINK_REMOVED); 921 VfdNotify(VFD_OPERATION_DELLINK, i); 922 } 923 } 924 } 925 926 if (pState) { 927 *pState = stat.dwCurrentState; 928 } 929 930 cleanup: 931 // Close the service object handle 932 933 if (hService) { 934 CloseServiceHandle(hService); 935 } 936 937 // Close handle to the service control manager. 938 939 if (hScManager) { 940 CloseServiceHandle(hScManager); 941 } 942 943 // Broadcast the successful operation 944 945 if (ret == ERROR_SUCCESS) { 946 VfdNotify(VFD_OPERATION_STOP, 0); 947 } 948 949 // revert to the original cursor 950 951 SetCursor(original); 952 953 return ret; 954 } 955 956 // 957 // Get the Virtual Floppy Driver configuration 958 // 959 DWORD WINAPI VfdGetDriverConfig( 960 PSTR sFileName, 961 PDWORD pStart) 962 { 963 #undef FUNC 964 #define FUNC "VfdGetDriverConfig" 965 SC_HANDLE hScManager; // Service Control Manager 966 SC_HANDLE hService; // Service (= Driver) 967 LPQUERY_SERVICE_CONFIG config = NULL; 968 DWORD result; 969 DWORD ret = ERROR_SUCCESS; 970 971 if (sFileName) { 972 ZeroMemory(sFileName, MAX_PATH); 973 } 974 975 if (pStart) { 976 *pStart = 0; 977 } 978 979 // Connect to the Service Control Manager 980 981 hScManager = OpenSCManager(NULL, NULL, 0); 982 983 if (hScManager == NULL) { 984 ret = GetLastError(); 985 986 VFDTRACE(0, 987 (FUNC ": OpenSCManager() - %s", SystemMessage(ret))); 988 989 return ret; 990 } 991 992 // Open the VFD driver entry in the service database 993 994 hService = OpenService( 995 hScManager, // Service control manager 996 VFD_DEVICE_BASENAME, // service name 997 SERVICE_QUERY_CONFIG); // service access mode 998 999 if (hService == NULL) { 1000 ret = GetLastError(); 1001 1002 VFDTRACE(0, 1003 (FUNC ": OpenService(SERVICE_QUERY_CONFIG) - %s", 1004 SystemMessage(ret))); 1005 1006 goto cleanup; 1007 } 1008 1009 // Get the length of config information 1010 1011 if (!QueryServiceConfig(hService, NULL, 0, &result)) { 1012 ret = GetLastError(); 1013 1014 if (ret == ERROR_INSUFFICIENT_BUFFER) { 1015 ret = ERROR_SUCCESS; 1016 } 1017 else { 1018 VFDTRACE(0, 1019 (FUNC ": QueryServiceConfig() - %s", 1020 SystemMessage(ret))); 1021 1022 goto cleanup; 1023 } 1024 } 1025 1026 // allocate a required buffer 1027 1028 config = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LPTR, result); 1029 1030 if (config == NULL) { 1031 ret = GetLastError(); 1032 1033 VFDTRACE(0, 1034 (FUNC ": LocalAlloc(%lu) - %s\n", 1035 result, SystemMessage(ret))); 1036 1037 goto cleanup; 1038 } 1039 1040 // get the config information 1041 1042 if (!QueryServiceConfig(hService, config, result, &result)) { 1043 ret = GetLastError(); 1044 1045 VFDTRACE(0, 1046 (FUNC ": QueryServiceConfig() - %s", 1047 SystemMessage(ret))); 1048 1049 goto cleanup; 1050 } 1051 1052 // copy information to output buffer 1053 1054 if (sFileName) { 1055 if (strncmp(config->lpBinaryPathName, "\\??\\", 4) == 0) { 1056 1057 // driver path is an absolute UNC path 1058 strncpy( 1059 sFileName, 1060 config->lpBinaryPathName + 4, 1061 MAX_PATH); 1062 } 1063 else if (config->lpBinaryPathName[0] == '\\' || 1064 (isalpha(config->lpBinaryPathName[0]) && 1065 config->lpBinaryPathName[1] == ':')) { 1066 1067 // driver path is an absolute path 1068 strncpy(sFileName, 1069 config->lpBinaryPathName, 1070 MAX_PATH); 1071 } 1072 else { 1073 // driver path is relative to the SystemRoot 1074 // DWORD len = GetEnvironmentVariable( 1075 // "SystemRoot", sFileName, MAX_PATH); 1076 1077 DWORD len = GetWindowsDirectory(sFileName, MAX_PATH); 1078 1079 if (len == 0 || len > MAX_PATH) { 1080 VFDTRACE(0, 1081 (FUNC ": %%SystemRoot%% is empty or too long.\n")); 1082 1083 ret = ERROR_BAD_ENVIRONMENT; 1084 goto cleanup; 1085 } 1086 1087 sprintf((sFileName + len), "\\%s", 1088 config->lpBinaryPathName); 1089 } 1090 } 1091 1092 if (pStart) { 1093 *pStart = config->dwStartType; 1094 } 1095 1096 cleanup: 1097 // Free service config buffer 1098 1099 if (config) { 1100 LocalFree(config); 1101 } 1102 1103 // Close the service object handle 1104 1105 if (hService) { 1106 CloseServiceHandle(hService); 1107 } 1108 1109 // Close handle to the service control manager. 1110 1111 if (hScManager) { 1112 CloseServiceHandle(hScManager); 1113 } 1114 1115 return ret; 1116 } 1117 1118 // 1119 // Get the Virtual Floppy Driver running state 1120 // 1121 DWORD WINAPI VfdGetDriverState( 1122 PDWORD pState) 1123 { 1124 #undef FUNC 1125 #define FUNC "VfdGetDriverState" 1126 SC_HANDLE hScManager = NULL; // Service Control Manager 1127 SC_HANDLE hService = NULL; // Service (= Driver) 1128 SERVICE_STATUS status; 1129 DWORD ret = ERROR_SUCCESS; 1130 1131 if (pState) { 1132 *pState = 0; 1133 } 1134 1135 // Connect to the Service Control Manager 1136 1137 hScManager = OpenSCManager(NULL, NULL, 0); 1138 1139 if (hScManager == NULL) { 1140 ret = GetLastError(); 1141 1142 VFDTRACE(0, 1143 (FUNC ": OpenSCManager() - %s", 1144 SystemMessage(ret))); 1145 1146 return ret; 1147 } 1148 1149 // Open the VFD driver entry in the service database 1150 1151 hService = OpenService( 1152 hScManager, // Service control manager 1153 VFD_DEVICE_BASENAME, // service name 1154 SERVICE_QUERY_STATUS); // service access mode 1155 1156 if (hService == NULL) { 1157 1158 ret = GetLastError(); 1159 1160 if (ret == ERROR_SERVICE_DOES_NOT_EXIST) { 1161 1162 if (pState) { 1163 *pState = VFD_NOT_INSTALLED; 1164 } 1165 1166 ret = ERROR_SUCCESS; 1167 } 1168 else { 1169 VFDTRACE(0, 1170 (FUNC ": OpenService(SERVICE_QUERY_STATUS) - %s", 1171 SystemMessage(ret))); 1172 } 1173 1174 goto cleanup; 1175 } 1176 1177 // Get current driver status 1178 1179 ZeroMemory(&status, sizeof(status)); 1180 1181 if (!QueryServiceStatus(hService, &status)) { 1182 ret = GetLastError(); 1183 1184 VFDTRACE(0, 1185 (FUNC ": QueryServiceStatus() - %s", 1186 SystemMessage(ret))); 1187 1188 goto cleanup; 1189 } 1190 1191 if (pState) { 1192 *pState = status.dwCurrentState; 1193 } 1194 1195 cleanup: 1196 // Close the service object handle 1197 1198 if (hService) { 1199 CloseServiceHandle(hService); 1200 } 1201 1202 // Close handle to the service control manager. 1203 1204 if (hScManager) { 1205 CloseServiceHandle(hScManager); 1206 } 1207 1208 return ret; 1209 } 1210 1211 // 1212 // open a Virtual Floppy drive without showing the "Insert Floppy" 1213 // dialog when the drive is empty. 1214 // 1215 HANDLE WINAPI VfdOpenDevice( 1216 ULONG nTarget) // either a drive letter or a device number 1217 { 1218 #undef FUNC 1219 #define FUNC "VfdOpenDevice" 1220 CHAR dev_name[20]; 1221 UINT err_mode; 1222 HANDLE hDevice; 1223 1224 // format a device name string 1225 1226 if (isalpha(nTarget)) { 1227 // nTarget is a drive letter 1228 // \\.\<x>: 1229 #ifndef __REACTOS__ 1230 sprintf(dev_name, VFD_VOLUME_TEMPLATE, nTarget); 1231 #else 1232 sprintf(dev_name, VFD_VOLUME_TEMPLATE, (CHAR)nTarget); 1233 #endif 1234 } 1235 else if (isdigit(nTarget)) { 1236 // nTarget is a device number in character 1237 // \\.\VirtualFD<n> 1238 sprintf(dev_name, VFD_DEVICE_TEMPLATE, nTarget - '0'); 1239 } 1240 else { 1241 // nTarget is a device number value 1242 // \\.\VirtualFD<n> 1243 sprintf(dev_name, VFD_DEVICE_TEMPLATE, nTarget); 1244 } 1245 1246 // change error mode in order to avoid "Insert Floppy" dialog 1247 1248 err_mode = SetErrorMode(SEM_FAILCRITICALERRORS); 1249 1250 // open the target drive 1251 1252 hDevice = CreateFile( 1253 dev_name, 1254 GENERIC_READ | GENERIC_WRITE, 1255 FILE_SHARE_READ | FILE_SHARE_WRITE, 1256 NULL, 1257 OPEN_EXISTING, 1258 FILE_FLAG_NO_BUFFERING, 1259 NULL); 1260 1261 // revert to the original error mode 1262 1263 SetErrorMode(err_mode); 1264 1265 if (hDevice != INVALID_HANDLE_VALUE) { 1266 1267 // check if the target is a valid VFD drive 1268 1269 ULONG version; 1270 1271 if (VfdGetDriverVersion(hDevice, &version) != ERROR_SUCCESS) { 1272 1273 // Failed to get the driver version 1274 1275 CloseHandle(hDevice); 1276 hDevice = INVALID_HANDLE_VALUE; 1277 } 1278 else if ((version & ~0x80000000) != 1279 MAKELONG(VFD_DRIVER_MINOR, VFD_DRIVER_MAJOR)) { 1280 1281 // the driver version mismatch 1282 1283 // CloseHandle(hDevice); 1284 // hDevice = INVALID_HANDLE_VALUE; 1285 1286 SetLastError(ERROR_REVISION_MISMATCH); 1287 } 1288 } 1289 else { 1290 VFDTRACE(0,( 1291 "CreateFile(%s) - %s", dev_name, 1292 SystemMessage(GetLastError())));; 1293 } 1294 1295 return hDevice; 1296 } 1297 1298 // 1299 // Open a Virtual Floppy Image 1300 // 1301 DWORD WINAPI VfdOpenImage( 1302 HANDLE hDevice, 1303 PCSTR sFileName, 1304 VFD_DISKTYPE nDiskType, 1305 VFD_MEDIA nMediaType, 1306 VFD_FLAGS nMediaFlags) 1307 { 1308 #undef FUNC 1309 #define FUNC "VfdOpenImage" 1310 PCSTR prefix; 1311 CHAR abspath[MAX_PATH]; 1312 DWORD name_len; 1313 DWORD result; 1314 DWORD ret = ERROR_SUCCESS; 1315 1316 PVFD_IMAGE_INFO image_info = NULL; 1317 PUCHAR image_buf = NULL; 1318 ULONG image_size; 1319 VFD_FILETYPE file_type; 1320 1321 // 1322 // Check parameters 1323 // 1324 1325 if (hDevice == NULL || 1326 hDevice == INVALID_HANDLE_VALUE) { 1327 return ERROR_INVALID_HANDLE; 1328 } 1329 1330 if (nMediaType == VFD_MEDIA_NONE || 1331 nMediaType >= VFD_MEDIA_MAX) { 1332 1333 VFDTRACE(0, 1334 (FUNC ": Invalid MediaType - %u\n", nMediaType)); 1335 1336 return ERROR_INVALID_PARAMETER; 1337 } 1338 1339 1340 if (sFileName && *sFileName) { 1341 1342 // check file contents and attributes 1343 1344 HANDLE hFile = CreateFile(sFileName, GENERIC_READ, 1345 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 1346 1347 if (hFile == INVALID_HANDLE_VALUE) { 1348 ret = GetLastError(); 1349 1350 VFDTRACE(0, 1351 (FUNC ": CreateFile(%s) - %s", 1352 sFileName, SystemMessage(ret))); 1353 1354 return ret; 1355 } 1356 1357 // try extracting image data from zip compressed file 1358 1359 ExtractZipImage(hFile, &image_buf, &image_size); 1360 1361 if (image_buf) { 1362 1363 file_type = VFD_FILETYPE_ZIP; 1364 1365 // imz file must be opened in RAM mode 1366 1367 if (nDiskType == VFD_DISKTYPE_FILE) { 1368 1369 VFDTRACE(0, 1370 (FUNC ": %s is a zip compressed file", 1371 sFileName)); 1372 1373 CloseHandle(hFile); 1374 ret = ERROR_INVALID_PARAMETER; 1375 1376 goto exit_func; 1377 } 1378 } 1379 else { 1380 1381 file_type = VFD_FILETYPE_RAW; 1382 1383 if (nDiskType == VFD_DISKTYPE_FILE) { 1384 1385 // direct image file must not be compressed or encrypted 1386 1387 BY_HANDLE_FILE_INFORMATION info; 1388 1389 if (!GetFileInformationByHandle(hFile, &info)) { 1390 ret = GetLastError(); 1391 1392 VFDTRACE(0, 1393 (FUNC ": GetFileInformationByHandle - %s", 1394 SystemMessage(ret))); 1395 1396 CloseHandle(hFile); 1397 1398 return ret; 1399 } 1400 1401 if (info.dwFileAttributes & 1402 (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_ENCRYPTED)) { 1403 1404 VFDTRACE(0, 1405 (FUNC ": file is compressed/encrypted")); 1406 1407 CloseHandle(hFile); 1408 1409 return ERROR_FILE_ENCRYPTED; 1410 } 1411 1412 image_size = info.nFileSizeLow; 1413 } 1414 else { 1415 1416 // prepare image data for a file based RAM disk 1417 1418 image_size = GetFileSize(hFile, NULL); 1419 1420 if (image_size == 0 || image_size == INVALID_FILE_SIZE) { 1421 ret = GetLastError(); 1422 1423 VFDTRACE(0, 1424 (FUNC ": GetFileSize - %s", 1425 SystemMessage(ret))); 1426 1427 CloseHandle(hFile); 1428 1429 return ret; 1430 } 1431 1432 image_buf = (PUCHAR)LocalAlloc(LPTR, image_size); 1433 1434 if (image_buf == NULL) { 1435 ret = GetLastError(); 1436 1437 VFDTRACE(0, 1438 (FUNC ": LocalAlloc - %s", 1439 SystemMessage(ret))); 1440 1441 CloseHandle(hFile); 1442 1443 return ret; 1444 } 1445 1446 if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) { 1447 ret = GetLastError(); 1448 1449 VFDTRACE(0, 1450 (FUNC ": SetFilePointer - %s", 1451 SystemMessage(ret))); 1452 1453 CloseHandle(hFile); 1454 1455 goto exit_func; 1456 } 1457 1458 if (!ReadFile(hFile, image_buf, image_size, &result, NULL) || 1459 image_size != result) { 1460 1461 ret = GetLastError(); 1462 1463 VFDTRACE(0, 1464 (FUNC ": ReadFile - %s", 1465 SystemMessage(ret))); 1466 1467 CloseHandle(hFile); 1468 1469 goto exit_func; 1470 } 1471 } 1472 } 1473 1474 CloseHandle(hFile); 1475 1476 // Prepare absolute path in the kernel namespace 1477 1478 if (*sFileName == '\\' && *(sFileName + 1) == '\\') { 1479 1480 // \\server\share\path\floppy.img 1481 1482 prefix = "\\??\\UNC"; 1483 sFileName++; // drip the first '\' 1484 } 1485 else { 1486 1487 // local path 1488 1489 PSTR file_part; 1490 1491 if (GetFullPathName(sFileName, 1492 sizeof(abspath), abspath, &file_part) == 0) { 1493 1494 ret = GetLastError(); 1495 1496 VFDTRACE(0, 1497 (FUNC ": GetFullPathName(%s) - %s\n", 1498 sFileName, SystemMessage(ret))); 1499 1500 goto exit_func; 1501 } 1502 1503 prefix = "\\??\\"; 1504 sFileName = abspath; 1505 } 1506 1507 name_len = strlen(prefix) + strlen(sFileName); 1508 } 1509 else { 1510 1511 // filename is not specified -- pure RAM disk 1512 1513 nDiskType = VFD_DISKTYPE_RAM; 1514 file_type = VFD_FILETYPE_NONE; 1515 1516 prefix = NULL; 1517 name_len = 0; 1518 1519 // prepare a FAT formatted RAM image 1520 1521 image_size = VfdGetMediaSize(nMediaType); 1522 1523 image_buf = (PUCHAR)LocalAlloc(LPTR, image_size); 1524 1525 if (image_buf == NULL) { 1526 ret = GetLastError(); 1527 1528 VFDTRACE(0, 1529 (FUNC ": LocalAlloc - %s", 1530 SystemMessage(ret))); 1531 1532 return ret; 1533 } 1534 1535 FormatBufferFat(image_buf, VFD_BYTE_TO_SECTOR(image_size)); 1536 } 1537 1538 if (image_size < VfdGetMediaSize(nMediaType)) { 1539 1540 // image is too small for the specified media type 1541 1542 VFDTRACE(0, 1543 (FUNC ": Image is too small for the specified media type\n")); 1544 1545 ret = ERROR_INVALID_PARAMETER; 1546 goto exit_func; 1547 } 1548 1549 // prepare VFD_IMAGE_INFO structure 1550 1551 image_info = (PVFD_IMAGE_INFO)LocalAlloc(LPTR, 1552 sizeof(VFD_IMAGE_INFO) + name_len + 1); 1553 1554 if (image_info == NULL) { 1555 ret = GetLastError(); 1556 1557 VFDTRACE(0, 1558 (FUNC ": LocalAlloc(%lu) - %s\n", 1559 sizeof(VFD_IMAGE_INFO) + name_len + 1, 1560 SystemMessage(ret))); 1561 1562 goto exit_func; 1563 } 1564 1565 ZeroMemory(image_info, 1566 sizeof(VFD_IMAGE_INFO) + name_len + 1); 1567 1568 if (name_len) { 1569 sprintf(image_info->FileName, 1570 "%s%s", prefix, sFileName); 1571 } 1572 1573 image_info->NameLength = (USHORT)name_len; 1574 1575 image_info->DiskType = nDiskType; 1576 image_info->MediaType = nMediaType; 1577 image_info->MediaFlags = nMediaFlags; 1578 image_info->FileType = file_type; 1579 image_info->ImageSize = image_size; 1580 1581 if (nDiskType != VFD_DISKTYPE_FILE) { 1582 // protect flag for a RAM disk is set after 1583 // initializing the image buffer 1584 image_info->MediaFlags &= ~VFD_FLAG_WRITE_PROTECTED; 1585 } 1586 1587 VFDTRACE(0, 1588 (FUNC ": Opening file \"%s\" (%lu bytes) %s %s %s %s\n", 1589 name_len ? image_info->FileName : "<RAM>", 1590 image_info->ImageSize, 1591 (file_type == VFD_FILETYPE_ZIP) ? "ZIP image" : "RAW image", 1592 VfdMediaTypeName(nMediaType), 1593 (nDiskType == VFD_DISKTYPE_FILE) ? "FILE disk" : "RAM disk", 1594 (nMediaFlags & VFD_FLAG_WRITE_PROTECTED) ? "Protected" : "Writable")); 1595 1596 // Open the image file / create a ram disk 1597 1598 if (!DeviceIoControl( 1599 hDevice, 1600 IOCTL_VFD_OPEN_IMAGE, 1601 image_info, 1602 sizeof(VFD_IMAGE_INFO) + name_len, 1603 NULL, 1604 0, 1605 &result, 1606 NULL)) 1607 { 1608 ret = GetLastError(); 1609 1610 VFDTRACE(0, 1611 (FUNC ": DeviceIoControl(IOCTL_VFD_OPEN_FILE) - %s", 1612 SystemMessage(ret))); 1613 1614 goto exit_func; 1615 } 1616 1617 // initialize the RAM disk image 1618 1619 if (nDiskType != VFD_DISKTYPE_FILE) { 1620 1621 image_size &= ~VFD_SECTOR_ALIGN_MASK; 1622 1623 if (SetFilePointer(hDevice, 0, NULL, FILE_BEGIN) != 0) { 1624 ret = GetLastError(); 1625 1626 VFDTRACE(0, 1627 (FUNC ": SetFilePointer - %s", 1628 SystemMessage(ret))); 1629 1630 goto exit_func; 1631 } 1632 1633 if (!WriteFile(hDevice, image_buf, image_size, &result, NULL) || 1634 image_size != result) { 1635 1636 ret = GetLastError(); 1637 1638 VFDTRACE(0, 1639 (FUNC ": WriteFile - %s", 1640 SystemMessage(ret))); 1641 1642 goto exit_func; 1643 } 1644 1645 if (nMediaFlags & VFD_FLAG_WRITE_PROTECTED) { 1646 VfdWriteProtect(hDevice, TRUE); 1647 } 1648 1649 if (!DeviceIoControl( 1650 hDevice, 1651 IOCTL_VFD_RESET_MODIFY, 1652 NULL, 1653 0, 1654 NULL, 1655 0, 1656 &result, 1657 NULL)) 1658 { 1659 VFDTRACE(0, 1660 (FUNC ": DeviceIoControl(IOCTL_VFD_RESET_MODIFY) - %s", 1661 SystemMessage(GetLastError()))); 1662 } 1663 } 1664 1665 // Broadcast the successful operation 1666 1667 if (ret == ERROR_SUCCESS) { 1668 ULONG number; 1669 CHAR root[] = "A:\\"; 1670 1671 if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) { 1672 VfdNotify(VFD_OPERATION_OPEN, number); 1673 } 1674 1675 VfdGetGlobalLink(hDevice, &root[0]); 1676 1677 if (isalpha(root[0])) { 1678 SHChangeNotify(SHCNE_MEDIAINSERTED, SHCNF_PATH, root, NULL); 1679 } 1680 1681 while (VfdGetLocalLink(hDevice, &root[0]) == ERROR_SUCCESS && 1682 isalpha(root[0])) { 1683 SHChangeNotify(SHCNE_MEDIAINSERTED, SHCNF_PATH, root, NULL); 1684 } 1685 } 1686 1687 exit_func: 1688 if (image_info) { 1689 LocalFree(image_info); 1690 } 1691 1692 if (image_buf) { 1693 LocalFree(image_buf); 1694 } 1695 1696 return ret; 1697 } 1698 1699 // 1700 // Close the virtual floppy Image 1701 // 1702 DWORD WINAPI VfdCloseImage( 1703 HANDLE hDevice, 1704 BOOL bForce) 1705 { 1706 #undef FUNC 1707 #define FUNC "VfdCloseImage" 1708 DWORD result; 1709 DWORD ret = ERROR_SUCCESS; 1710 int retry = 0; 1711 1712 lock_retry: 1713 if (!DeviceIoControl( 1714 hDevice, 1715 FSCTL_LOCK_VOLUME, 1716 NULL, 1717 0, 1718 NULL, 1719 0, 1720 &result, 1721 NULL)) 1722 { 1723 ret = GetLastError(); 1724 1725 VFDTRACE(0, 1726 (FUNC ": DeviceIoControl(FSCTL_LOCK_VOLUME) - %s", 1727 SystemMessage(ret))); 1728 1729 if (ret != ERROR_ACCESS_DENIED || retry == 5) { 1730 // error other than access denied or 1731 // operation kept failing for 5 seconds 1732 return ret; 1733 } 1734 1735 if (!bForce) { 1736 // error is access denied and 1737 // the force flag is not set 1738 1739 if (retry == 0) { 1740 1741 // send the MEDIAREMOVED notification to the shell and 1742 // see if the shell releases the target drive 1743 1744 CHAR root[] = "A:\\"; 1745 1746 VfdGetGlobalLink(hDevice, &root[0]); 1747 1748 if (isalpha(root[0])) { 1749 SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATH, root, NULL); 1750 } 1751 1752 while (VfdGetLocalLink(hDevice, &root[0]) == ERROR_SUCCESS && 1753 isalpha(root[0])) { 1754 SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATH, root, NULL); 1755 } 1756 } 1757 1758 Sleep(1000); 1759 retry++; 1760 1761 goto lock_retry; 1762 } 1763 } 1764 1765 ret = ERROR_SUCCESS; 1766 1767 if (!DeviceIoControl( 1768 hDevice, 1769 FSCTL_DISMOUNT_VOLUME, 1770 NULL, 1771 0, 1772 NULL, 1773 0, 1774 &result, 1775 NULL)) 1776 { 1777 ret = GetLastError(); 1778 1779 VFDTRACE(0, 1780 (FUNC ": DeviceIoControl(FSCTL_DISMOUNT_VOLUME) - %s", 1781 SystemMessage(ret))); 1782 1783 return ret; 1784 } 1785 1786 if (!DeviceIoControl( 1787 hDevice, 1788 IOCTL_VFD_CLOSE_IMAGE, 1789 NULL, 1790 0, 1791 NULL, 1792 0, 1793 &result, 1794 NULL)) 1795 { 1796 ret = GetLastError(); 1797 1798 if (ret != ERROR_NOT_READY) { 1799 VFDTRACE(0, 1800 (FUNC ": DeviceIoControl(IOCTL_VFD_CLOSE_FILE) - %s", 1801 SystemMessage(ret))); 1802 } 1803 1804 return ret; 1805 } 1806 1807 if (!DeviceIoControl( 1808 hDevice, 1809 FSCTL_UNLOCK_VOLUME, 1810 NULL, 1811 0, 1812 NULL, 1813 0, 1814 &result, 1815 NULL)) 1816 { 1817 // This should not be fatal because the volume is unlocked 1818 // when the handle is closed anyway 1819 VFDTRACE(0, 1820 (FUNC ": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s", 1821 SystemMessage(GetLastError()))); 1822 } 1823 1824 // Broadcast the successful operation 1825 if (ret == ERROR_SUCCESS) { 1826 ULONG number; 1827 1828 if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) { 1829 VfdNotify(VFD_OPERATION_CLOSE, number); 1830 } 1831 } 1832 1833 return ret; 1834 } 1835 1836 // 1837 // Get Virtual Floppy image info 1838 // 1839 DWORD WINAPI VfdGetImageInfo( 1840 HANDLE hDevice, 1841 PSTR sFileName, 1842 PVFD_DISKTYPE pDiskType, 1843 PVFD_MEDIA pMediaType, 1844 PVFD_FLAGS pMediaFlags, 1845 PVFD_FILETYPE pFileType, 1846 PULONG pImageSize) 1847 { 1848 #undef FUNC 1849 #define FUNC "VfdGetImageInfo" 1850 PVFD_IMAGE_INFO image_info; 1851 DWORD result; 1852 DWORD ret = ERROR_SUCCESS; 1853 1854 image_info = (PVFD_IMAGE_INFO)LocalAlloc( 1855 LPTR, sizeof(VFD_IMAGE_INFO) + MAX_PATH); 1856 1857 if (image_info == NULL) { 1858 ret = GetLastError(); 1859 1860 VFDTRACE(0, 1861 (FUNC ": LocalAlloc(%lu) - %s\n", 1862 sizeof(VFD_IMAGE_INFO) + MAX_PATH, SystemMessage(ret))); 1863 1864 return ret; 1865 } 1866 1867 ZeroMemory(image_info, sizeof(VFD_IMAGE_INFO) + MAX_PATH); 1868 1869 // Query file information 1870 1871 if (!DeviceIoControl( 1872 hDevice, 1873 IOCTL_VFD_QUERY_IMAGE, 1874 NULL, 1875 0, 1876 image_info, 1877 sizeof(VFD_IMAGE_INFO) + MAX_PATH, 1878 &result, 1879 NULL)) 1880 { 1881 ret = GetLastError(); 1882 1883 if (ret != ERROR_MORE_DATA) { 1884 VFDTRACE(0, 1885 (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_FILE) - %s", 1886 SystemMessage(ret))); 1887 1888 goto cleanup; 1889 } 1890 } 1891 1892 // copy obtained information to output buffer 1893 1894 if (sFileName) { 1895 1896 // if filename is too long, clip it 1897 1898 if (image_info->NameLength >= MAX_PATH) { 1899 image_info->NameLength = MAX_PATH - 1; 1900 } 1901 1902 // ensure the name is properly terminated 1903 1904 image_info->FileName[image_info->NameLength] = '\0'; 1905 1906 if (strncmp(image_info->FileName, "\\??\\UNC", 7) == 0) { 1907 *sFileName = '\\'; 1908 strcpy(sFileName + 1, image_info->FileName + 7); 1909 } 1910 else if (strncmp(image_info->FileName, "\\??\\", 4) == 0) { 1911 strcpy(sFileName, image_info->FileName + 4); 1912 } 1913 else { 1914 strcpy(sFileName, image_info->FileName); 1915 } 1916 } 1917 1918 if (pDiskType) { 1919 *pDiskType = image_info->DiskType; 1920 } 1921 1922 if (pMediaType) { 1923 *pMediaType = image_info->MediaType; 1924 } 1925 1926 if (pMediaFlags) { 1927 *pMediaFlags = image_info->MediaFlags; 1928 } 1929 1930 if (pFileType) { 1931 *pFileType = image_info->FileType; 1932 } 1933 1934 if (pImageSize) { 1935 *pImageSize = image_info->ImageSize; 1936 } 1937 1938 cleanup: 1939 if (image_info) { 1940 LocalFree(image_info); 1941 } 1942 1943 return ret; 1944 } 1945 1946 // 1947 // Get current media state (opened / write protected) 1948 // 1949 DWORD WINAPI VfdGetMediaState( 1950 HANDLE hDevice) 1951 { 1952 #undef FUNC 1953 #define FUNC "VfdGetMediaState" 1954 DWORD result; 1955 DWORD ret = ERROR_SUCCESS; 1956 1957 // Query file information 1958 1959 if (!DeviceIoControl( 1960 hDevice, 1961 IOCTL_DISK_IS_WRITABLE, 1962 NULL, 1963 0, 1964 NULL, 1965 0, 1966 &result, 1967 NULL)) 1968 { 1969 ret = GetLastError(); 1970 1971 if (ret != ERROR_NOT_READY) { 1972 VFDTRACE(0, 1973 (FUNC ": DeviceIoControl(IOCTL_DISK_IS_WRITABLE) - %s", 1974 SystemMessage(ret))); 1975 } 1976 } 1977 1978 return ret; 1979 } 1980 1981 // 1982 // Set or Delete a global drive letter 1983 // 1984 DWORD WINAPI VfdSetGlobalLink( 1985 HANDLE hDevice, 1986 CHAR cLetter) 1987 { 1988 #undef FUNC 1989 #define FUNC "VfdSetGlobalLink" 1990 CHAR letter; 1991 ULONG number; 1992 DWORD result; 1993 DWORD ret; 1994 1995 if (isalpha(cLetter)) { 1996 1997 // make sure the drive does not have a drive letter 1998 1999 letter = 0; 2000 2001 VfdGetGlobalLink(hDevice, &letter); 2002 2003 if (isalpha(letter)) { 2004 VFDTRACE(0, 2005 (FUNC ": Drive already has a drive letter %c\n", letter)); 2006 return ERROR_ALREADY_ASSIGNED; 2007 } 2008 2009 VfdGetLocalLink(hDevice, &letter); 2010 2011 if (isalpha(letter)) { 2012 VFDTRACE(0, 2013 (FUNC ": Drive already has a drive letter %c\n", letter)); 2014 return ERROR_ALREADY_ASSIGNED; 2015 } 2016 2017 // make sure drive letter is not in use 2018 2019 cLetter = (CHAR)toupper(cLetter); 2020 2021 if (GetLogicalDrives() & (1 << (cLetter - 'A'))) { 2022 VFDTRACE(0, 2023 (FUNC ": Drive letter %c already used\n", cLetter)); 2024 return ERROR_ALREADY_ASSIGNED; 2025 } 2026 2027 // Assign a new drive letter 2028 2029 if (!DeviceIoControl( 2030 hDevice, 2031 IOCTL_VFD_SET_LINK, 2032 &cLetter, 2033 sizeof(cLetter), 2034 NULL, 2035 0, 2036 &result, 2037 NULL)) 2038 { 2039 ret = GetLastError(); 2040 2041 VFDTRACE(0, 2042 (FUNC ": DeviceIoControl(IOCTL_VFD_SET_LINK) - %s", 2043 SystemMessage(ret))); 2044 2045 return ret; 2046 } 2047 2048 // broadcast system message 2049 2050 VfdBroadcastLink(cLetter, VFD_LINK_CREATED); 2051 2052 // broadcast VFD message 2053 2054 if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) { 2055 VfdNotify(VFD_OPERATION_SETLINK, number); 2056 } 2057 2058 return ERROR_SUCCESS; 2059 } 2060 else if (!cLetter) { 2061 2062 // make sure the drive has a global drive letter 2063 2064 letter = 0; 2065 2066 VfdGetGlobalLink(hDevice, &letter); 2067 2068 if (!isalpha(letter)) { 2069 VFDTRACE(0, 2070 (FUNC ": Drive does not have a drive letter\n")); 2071 return ERROR_INVALID_FUNCTION; 2072 } 2073 2074 // Remove drive letters 2075 2076 if (!DeviceIoControl( 2077 hDevice, 2078 IOCTL_VFD_SET_LINK, 2079 &cLetter, 2080 sizeof(cLetter), 2081 NULL, 2082 0, 2083 &result, 2084 NULL)) 2085 { 2086 ret = GetLastError(); 2087 2088 VFDTRACE(0, 2089 (FUNC ": DeviceIoControl(IOCTL_VFD_SET_LINK) - %s", 2090 SystemMessage(ret))); 2091 2092 return ret; 2093 } 2094 2095 // broadcast system message 2096 2097 VfdBroadcastLink(letter, VFD_LINK_REMOVED); 2098 2099 // broadcast VFD message 2100 if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) { 2101 VfdNotify(VFD_OPERATION_DELLINK, number); 2102 } 2103 2104 return ERROR_SUCCESS; 2105 } 2106 else { 2107 return ERROR_INVALID_PARAMETER; 2108 } 2109 } 2110 2111 // 2112 // Get a global drive letter 2113 // 2114 DWORD WINAPI VfdGetGlobalLink( 2115 HANDLE hDevice, 2116 PCHAR pLetter) 2117 { 2118 #undef FUNC 2119 #define FUNC "VfdGetGlobalLinks" 2120 DWORD result; 2121 DWORD ret; 2122 2123 if (!pLetter) { 2124 return ERROR_INVALID_PARAMETER; 2125 } 2126 2127 *pLetter = 0; 2128 2129 if (!DeviceIoControl( 2130 hDevice, 2131 IOCTL_VFD_QUERY_LINK, 2132 NULL, 2133 0, 2134 pLetter, 2135 sizeof(*pLetter), 2136 &result, 2137 NULL)) 2138 { 2139 ret = GetLastError(); 2140 2141 VFDTRACE(0, 2142 (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_LINK) - %s", 2143 SystemMessage(ret))); 2144 2145 return ret; 2146 } 2147 2148 return ERROR_SUCCESS; 2149 } 2150 2151 // 2152 // Set or remove a local drive letter 2153 // 2154 DWORD WINAPI VfdSetLocalLink( 2155 HANDLE hDevice, 2156 CHAR cLetter) 2157 { 2158 #undef FUNC 2159 #define FUNC "VfdSetLocalLink" 2160 CHAR letter; 2161 CHAR dos_name[] = "A:"; 2162 CHAR dev_name[MAX_PATH]; 2163 ULONG number; 2164 DWORD ret; 2165 2166 if (isalpha(cLetter)) { 2167 2168 // make sure the drive does not have a drive letter 2169 2170 letter = 0; 2171 2172 VfdGetGlobalLink(hDevice, &letter); 2173 2174 if (isalpha(letter)) { 2175 VFDTRACE(0, 2176 (FUNC ": Drive already has a drive letter %c\n", letter)); 2177 return ERROR_ALREADY_ASSIGNED; 2178 } 2179 2180 VfdGetLocalLink(hDevice, &letter); 2181 2182 if (isalpha(letter)) { 2183 VFDTRACE(0, 2184 (FUNC ": Drive already has a drive letter %c\n", letter)); 2185 return ERROR_ALREADY_ASSIGNED; 2186 } 2187 2188 // make sure drive letters are not in use 2189 2190 cLetter = (CHAR)toupper(cLetter); 2191 2192 if (GetLogicalDrives() & (1 << (cLetter - 'A'))) { 2193 VFDTRACE(0, 2194 (FUNC ": Drive letter already used\n")); 2195 2196 return ERROR_ALREADY_ASSIGNED; 2197 } 2198 2199 // get VFD device name 2200 2201 ret = VfdGetDeviceName(hDevice, dev_name, sizeof(dev_name)); 2202 2203 if (ret != ERROR_SUCCESS) { 2204 return ret; 2205 } 2206 2207 // assign a drive letter 2208 2209 dos_name[0] = cLetter; 2210 2211 if (!DefineDosDevice(DDD_RAW_TARGET_PATH, dos_name, dev_name)) { 2212 ret = GetLastError(); 2213 2214 VFDTRACE(0, 2215 (FUNC ": DefineDosDevice(%s,%s) - %s", 2216 dos_name, dev_name, SystemMessage(ret))); 2217 } 2218 2219 if (ret == ERROR_SUCCESS) { 2220 // broadcast VFD message 2221 2222 if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) { 2223 VfdNotify(VFD_OPERATION_SETLINK, number); 2224 } 2225 } 2226 2227 return ret; 2228 } 2229 else if (!cLetter) { 2230 2231 // make sure the drive has a local drive letter 2232 2233 letter = 0; 2234 2235 VfdGetLocalLink(hDevice, &letter); 2236 2237 if (!isalpha(letter)) { 2238 VFDTRACE(0, 2239 (FUNC ": Drive letter is not assigned to this drive\n")); 2240 return ERROR_INVALID_FUNCTION; 2241 } 2242 2243 // get VFD device name 2244 2245 ret = VfdGetDeviceName(hDevice, dev_name, sizeof(dev_name)); 2246 2247 if (ret != ERROR_SUCCESS) { 2248 return ret; 2249 } 2250 2251 // remove drive letters 2252 #define DDD_FLAGS (DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE) 2253 2254 dos_name[0] = (CHAR)toupper(letter); 2255 2256 if (!DefineDosDevice(DDD_FLAGS, dos_name, dev_name)) { 2257 ret = GetLastError(); 2258 2259 VFDTRACE(0, 2260 (FUNC ": DefineDosDevice(%s,%s) - %s", 2261 dos_name, dev_name, SystemMessage(ret))); 2262 } 2263 2264 if (ret == ERROR_SUCCESS) { 2265 // broadcast VFD message 2266 if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) { 2267 VfdNotify(VFD_OPERATION_DELLINK, number); 2268 } 2269 } 2270 2271 return ret; 2272 } 2273 else { 2274 return ERROR_INVALID_PARAMETER; 2275 } 2276 } 2277 2278 // 2279 // Get local drive letters 2280 // 2281 DWORD WINAPI VfdGetLocalLink( 2282 HANDLE hDevice, 2283 PCHAR pLetter) 2284 { 2285 #undef FUNC 2286 #define FUNC "VfdGetLocalLinks" 2287 CHAR global; 2288 ULONG logical; 2289 CHAR dos_name[] = "A:"; 2290 CHAR dev_name[MAX_PATH]; 2291 CHAR dos_target[MAX_PATH * 2]; 2292 DWORD ret; 2293 2294 if (!pLetter) { 2295 return ERROR_INVALID_PARAMETER; 2296 } 2297 2298 // Get the VFD device name 2299 2300 ret = VfdGetDeviceName(hDevice, dev_name, sizeof(dev_name)); 2301 2302 if (ret != ERROR_SUCCESS) { 2303 return ret; 2304 } 2305 2306 // Get global drive letter 2307 2308 ret = VfdGetGlobalLink(hDevice, &global); 2309 2310 if (ret != ERROR_SUCCESS) { 2311 return ret; 2312 } 2313 2314 // Get logical drives 2315 2316 logical = GetLogicalDrives(); 2317 2318 // exclude the global drive letter 2319 2320 if (isalpha(global)) { 2321 logical &= ~(1 << (toupper(global) - 'A')); 2322 } 2323 2324 // start searching from the next drive letter 2325 2326 if (isalpha(*pLetter)) { 2327 dos_name[0] = (CHAR)(toupper(*pLetter) + 1); 2328 logical >>= (dos_name[0] - 'A'); 2329 } 2330 2331 // Check dos device targets 2332 2333 *pLetter = '\0'; 2334 2335 while (logical) { 2336 if (logical & 0x01) { 2337 if (QueryDosDevice(dos_name, dos_target, sizeof(dos_target))) { 2338 if (_stricmp(dos_target, dev_name) == 0) { 2339 *pLetter = dos_name[0]; 2340 break; 2341 } 2342 } 2343 else { 2344 VFDTRACE(0, 2345 (FUNC ": QueryDosDevice(%s) - %s", 2346 dos_name, SystemMessage(GetLastError()))); 2347 } 2348 } 2349 logical >>= 1; 2350 dos_name[0]++; 2351 } 2352 2353 return ERROR_SUCCESS; 2354 } 2355 2356 // 2357 // Get the Virtual Floppy device number 2358 // 2359 DWORD WINAPI VfdGetDeviceNumber( 2360 HANDLE hDevice, 2361 PULONG pNumber) 2362 { 2363 #undef FUNC 2364 #define FUNC "VfdGetDeviceNumber" 2365 DWORD result; 2366 DWORD ret = ERROR_SUCCESS; 2367 2368 if (!pNumber) { 2369 return ERROR_INVALID_PARAMETER; 2370 } 2371 2372 *pNumber = 0; 2373 2374 if (!DeviceIoControl( 2375 hDevice, 2376 IOCTL_VFD_QUERY_NUMBER, 2377 NULL, 2378 0, 2379 pNumber, 2380 sizeof(ULONG), 2381 &result, 2382 NULL)) 2383 { 2384 ret = GetLastError(); 2385 2386 VFDTRACE(0, 2387 (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_NUMBER) - %s", 2388 SystemMessage(ret))); 2389 } 2390 2391 return ret; 2392 } 2393 2394 // Get the Virtual Floppy device name 2395 2396 DWORD WINAPI VfdGetDeviceName( 2397 HANDLE hDevice, 2398 PCHAR pName, 2399 ULONG nLength) 2400 { 2401 #undef FUNC 2402 #define FUNC "VfdGetDeviceName" 2403 DWORD result; 2404 WCHAR wname[MAX_PATH]; 2405 DWORD ret = ERROR_SUCCESS; 2406 2407 if (!pName || !nLength) { 2408 return ERROR_INVALID_PARAMETER; 2409 } 2410 2411 ZeroMemory(pName, nLength); 2412 2413 if (!DeviceIoControl( 2414 hDevice, 2415 IOCTL_VFD_QUERY_NAME, 2416 NULL, 2417 0, 2418 wname, 2419 sizeof(wname), 2420 &result, 2421 NULL)) 2422 { 2423 ret = GetLastError(); 2424 2425 VFDTRACE(0, 2426 (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_NUMBER) - %s", 2427 SystemMessage(ret))); 2428 } 2429 2430 if (!WideCharToMultiByte(CP_OEMCP, 0, &wname[1], 2431 wname[0] / sizeof(WCHAR), pName, nLength, NULL, NULL)) { 2432 2433 ret = GetLastError(); 2434 2435 VFDTRACE(0, 2436 (FUNC ": WideCharToMultiByte - %s", 2437 SystemMessage(ret))); 2438 } 2439 2440 return ret; 2441 } 2442 2443 // 2444 // Get Virtual Floppy driver version 2445 // 2446 DWORD WINAPI VfdGetDriverVersion( 2447 HANDLE hDevice, 2448 PULONG pVersion) 2449 { 2450 #undef FUNC 2451 #define FUNC "VfdGetDriverVersion" 2452 DWORD result; 2453 DWORD ret = ERROR_SUCCESS; 2454 2455 if (!pVersion) { 2456 return ERROR_INVALID_PARAMETER; 2457 } 2458 2459 *pVersion = '\0'; 2460 2461 if (!DeviceIoControl( 2462 hDevice, 2463 IOCTL_VFD_QUERY_VERSION, 2464 NULL, 2465 0, 2466 pVersion, 2467 sizeof(ULONG), 2468 &result, 2469 NULL)) 2470 { 2471 ret = GetLastError(); 2472 2473 VFDTRACE(0, 2474 (FUNC ": DeviceIoControl(IOCTL_VFD_QUERY_VERSION) - %s", 2475 SystemMessage(ret))); 2476 } 2477 2478 return ret; 2479 } 2480 2481 // 2482 // Change the write protect state of the media 2483 // 2484 DWORD WINAPI VfdWriteProtect( 2485 HANDLE hDevice, 2486 BOOL bProtect) 2487 { 2488 #undef FUNC 2489 #define FUNC "VfdWriteProtect" 2490 DWORD result; 2491 DWORD ret = ERROR_SUCCESS; 2492 2493 if (!DeviceIoControl( 2494 hDevice, 2495 bProtect ? IOCTL_VFD_SET_PROTECT : IOCTL_VFD_CLEAR_PROTECT, 2496 NULL, 2497 0, 2498 NULL, 2499 0, 2500 &result, 2501 NULL)) 2502 { 2503 ret = GetLastError(); 2504 2505 VFDTRACE(0, 2506 (FUNC ": DeviceIoControl(IOCTL_VFD_SET_PROTECT) - %s", 2507 SystemMessage(ret))); 2508 } 2509 2510 if (ret == ERROR_SUCCESS) { 2511 ULONG number; 2512 2513 if (VfdGetDeviceNumber(hDevice, &number) == ERROR_SUCCESS) { 2514 VfdNotify(VFD_OPERATION_PROTECT, number); 2515 } 2516 } 2517 2518 return ret; 2519 } 2520 2521 // Format the current media with FAT12 2522 2523 DWORD WINAPI VfdFormatMedia( 2524 HANDLE hDevice) 2525 { 2526 #undef FUNC 2527 #define FUNC "VfdFormatMedia" 2528 DWORD result; 2529 DWORD ret = ERROR_SUCCESS; 2530 PUCHAR buf = NULL; 2531 GET_LENGTH_INFORMATION length; 2532 2533 // Get the media size 2534 2535 if (!DeviceIoControl( 2536 hDevice, 2537 IOCTL_DISK_GET_LENGTH_INFO, 2538 NULL, 2539 0, 2540 &length, 2541 sizeof(length), 2542 &result, 2543 NULL)) 2544 { 2545 ret = GetLastError(); 2546 2547 VFDTRACE(0, 2548 (FUNC ": DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO) - %s", 2549 SystemMessage(ret))); 2550 2551 goto exit_func; 2552 } 2553 2554 // Prepare a formatted image buffer 2555 2556 buf = (PUCHAR)LocalAlloc(LPTR, length.Length.LowPart); 2557 2558 if (buf == NULL) { 2559 ret = GetLastError(); 2560 2561 VFDTRACE(0, 2562 (FUNC ": LocalAlloc - %s", 2563 SystemMessage(ret))); 2564 2565 goto exit_func; 2566 } 2567 2568 // format the buffer 2569 2570 ret = FormatBufferFat(buf, 2571 VFD_BYTE_TO_SECTOR(length.Length.LowPart)); 2572 2573 if (ret != ERROR_SUCCESS) { 2574 goto exit_func; 2575 } 2576 2577 // seek the top of the media 2578 2579 if (SetFilePointer(hDevice, 0, NULL, FILE_BEGIN) != 0) { 2580 ret = GetLastError(); 2581 2582 VFDTRACE(0, 2583 (FUNC ": SetFilePointer - %s", 2584 SystemMessage(ret))); 2585 2586 goto exit_func; 2587 } 2588 2589 // write the image into the media 2590 2591 if (!WriteFile(hDevice, buf, length.Length.LowPart, &result, NULL) || 2592 result != length.Length.LowPart) { 2593 ret = GetLastError(); 2594 2595 VFDTRACE(0, 2596 (FUNC ": WriteFile - %s", 2597 SystemMessage(ret))); 2598 2599 goto exit_func; 2600 } 2601 2602 exit_func: 2603 // unlock the target volume 2604 if (!DeviceIoControl( 2605 hDevice, 2606 FSCTL_UNLOCK_VOLUME, 2607 NULL, 2608 0, 2609 NULL, 2610 0, 2611 &result, 2612 NULL)) 2613 { 2614 VFDTRACE(0, 2615 (FUNC ": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s", 2616 SystemMessage(GetLastError()))); 2617 } 2618 2619 // release the format image buffer 2620 if (buf) { 2621 LocalFree(buf); 2622 } 2623 2624 return ret; 2625 } 2626 2627 // Dismount the volume (should be called before Save, Format) 2628 2629 DWORD WINAPI VfdDismountVolume( 2630 HANDLE hDevice, 2631 BOOL bForce) 2632 { 2633 #undef FUNC 2634 #define FUNC "VfdDismountVolume" 2635 DWORD result; 2636 DWORD ret = ERROR_SUCCESS; 2637 2638 // Lock the target volume 2639 2640 if (!DeviceIoControl( 2641 hDevice, 2642 FSCTL_LOCK_VOLUME, 2643 NULL, 2644 0, 2645 NULL, 2646 0, 2647 &result, 2648 NULL)) 2649 { 2650 ret = GetLastError(); 2651 2652 VFDTRACE(0, 2653 (FUNC ": DeviceIoControl(FSCTL_LOCK_VOLUME) - %s", 2654 SystemMessage(ret))); 2655 2656 if (ret != ERROR_ACCESS_DENIED || !bForce) { 2657 return ret; 2658 } 2659 } 2660 2661 // Dismount the target volume 2662 2663 if (!DeviceIoControl( 2664 hDevice, 2665 FSCTL_DISMOUNT_VOLUME, 2666 NULL, 2667 0, 2668 NULL, 2669 0, 2670 &result, 2671 NULL)) 2672 { 2673 ret = GetLastError(); 2674 2675 VFDTRACE(0, 2676 (FUNC ": DeviceIoControl(FSCTL_DISMOUNT_VOLUME) - %s", 2677 SystemMessage(ret))); 2678 } 2679 2680 return ret; 2681 } 2682 2683 // Save the current image into a file 2684 2685 DWORD WINAPI VfdSaveImage( 2686 HANDLE hDevice, 2687 PCSTR sFileName, 2688 BOOL bOverWrite, 2689 BOOL bTruncate) 2690 { 2691 #undef FUNC 2692 #define FUNC "VfdSaveImage" 2693 HANDLE hFile = INVALID_HANDLE_VALUE; 2694 DWORD result; 2695 DWORD ret = ERROR_SUCCESS; 2696 PUCHAR buf = NULL; 2697 GET_LENGTH_INFORMATION length; 2698 2699 2700 ret = ERROR_SUCCESS; 2701 2702 // Get the media size 2703 2704 if (!DeviceIoControl( 2705 hDevice, 2706 IOCTL_DISK_GET_LENGTH_INFO, 2707 NULL, 2708 0, 2709 &length, 2710 sizeof(length), 2711 &result, 2712 NULL)) 2713 { 2714 ret = GetLastError(); 2715 2716 VFDTRACE(0, 2717 (FUNC ": DeviceIoControl(IOCTL_DISK_GET_LENGTH_INFO) - %s", 2718 SystemMessage(ret))); 2719 2720 goto exit_func; 2721 } 2722 2723 // Prepare an intermediate image buffer 2724 2725 buf = (PUCHAR)LocalAlloc(LPTR, length.Length.LowPart); 2726 2727 if (buf == NULL) { 2728 ret = GetLastError(); 2729 2730 VFDTRACE(0, 2731 (FUNC ": LocalAlloc - %s", 2732 SystemMessage(ret))); 2733 2734 goto exit_func; 2735 } 2736 2737 // seek the top of the media 2738 2739 if (SetFilePointer(hDevice, 0, NULL, FILE_BEGIN) != 0) { 2740 ret = GetLastError(); 2741 2742 VFDTRACE(0, 2743 (FUNC ": SetFilePointer - %s", 2744 SystemMessage(ret))); 2745 2746 goto exit_func; 2747 } 2748 2749 // read the image data 2750 2751 if (!ReadFile(hDevice, buf, length.Length.LowPart, &result, NULL) || 2752 result != length.Length.LowPart) { 2753 ret = GetLastError(); 2754 2755 VFDTRACE(0, 2756 (FUNC ": ReadFile - %s", 2757 SystemMessage(ret))); 2758 2759 goto exit_func; 2760 } 2761 2762 // open the destination file 2763 2764 hFile = CreateFile(sFileName, GENERIC_WRITE, 0, NULL, 2765 bOverWrite ? OPEN_ALWAYS : CREATE_NEW, 0, NULL); 2766 2767 if (hFile == INVALID_HANDLE_VALUE) { 2768 ret = GetLastError(); 2769 2770 VFDTRACE(0, 2771 (FUNC ": CreateFile - %s", 2772 SystemMessage(ret))); 2773 2774 goto exit_func; 2775 } 2776 2777 // seek the top of the file 2778 2779 if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) != 0) { 2780 ret = GetLastError(); 2781 2782 VFDTRACE(0, 2783 (FUNC ": SetFilePointer - %s", 2784 SystemMessage(ret))); 2785 2786 goto exit_func; 2787 } 2788 2789 // write the image data 2790 2791 if (!WriteFile(hFile, buf, length.Length.LowPart, &result, NULL) || 2792 result != length.Length.LowPart) { 2793 ret = GetLastError(); 2794 2795 VFDTRACE(0, 2796 (FUNC ": WriteFile - %s", 2797 SystemMessage(ret))); 2798 2799 goto exit_func; 2800 } 2801 2802 // truncate the target file 2803 2804 if (bTruncate && !SetEndOfFile(hFile)) { 2805 ret = GetLastError(); 2806 2807 VFDTRACE(0, 2808 (FUNC ": SetEndOfFile - %s", 2809 SystemMessage(ret))); 2810 2811 goto exit_func; 2812 } 2813 2814 // reset the media modified flag 2815 2816 if (!DeviceIoControl( 2817 hDevice, 2818 IOCTL_VFD_RESET_MODIFY, 2819 NULL, 2820 0, 2821 NULL, 2822 0, 2823 &result, 2824 NULL)) 2825 { 2826 VFDTRACE(0, 2827 (FUNC ": DeviceIoControl(IOCTL_VFD_RESET_MODIFY) - %s", 2828 SystemMessage(GetLastError()))); 2829 } 2830 2831 exit_func: 2832 // unlock the target volume 2833 2834 if (!DeviceIoControl( 2835 hDevice, 2836 FSCTL_UNLOCK_VOLUME, 2837 NULL, 2838 0, 2839 NULL, 2840 0, 2841 &result, 2842 NULL)) 2843 { 2844 VFDTRACE(0, 2845 (FUNC ": DeviceIoControl(FSCTL_UNLOCK_VOLUME) - %s", 2846 SystemMessage(GetLastError()))); 2847 } 2848 2849 // release the format image buffer 2850 2851 if (buf) { 2852 LocalFree(buf); 2853 } 2854 2855 // close the image file 2856 2857 if (hFile != INVALID_HANDLE_VALUE) { 2858 CloseHandle(hFile); 2859 } 2860 2861 return ret; 2862 } 2863 2864 // 2865 // Check if specified file is valid VFD driver 2866 // 2867 DWORD WINAPI VfdCheckDriverFile( 2868 PCSTR sFileName, 2869 PULONG pFileVersion) 2870 { 2871 #undef FUNC 2872 #define FUNC "VfdCheckDriverFile" 2873 DWORD result; 2874 DWORD dummy; 2875 PVOID info; 2876 VS_FIXEDFILEINFO *fixedinfo; 2877 DWORD ret = ERROR_SUCCESS; 2878 PSTR str; 2879 2880 // Check parameter 2881 2882 if (!sFileName || !*sFileName) { 2883 return ERROR_INVALID_PARAMETER; 2884 } 2885 2886 if (pFileVersion) { 2887 *pFileVersion = 0; 2888 } 2889 2890 // check file existence 2891 2892 if (GetFileAttributes(sFileName) == INVALID_FILE_ATTRIBUTES) { 2893 ret = GetLastError(); 2894 2895 VFDTRACE(0, 2896 (FUNC ": GetFileAttributes - %s\n", 2897 SystemMessage(ret))); 2898 2899 return ret; 2900 } 2901 2902 // check file version 2903 2904 result = GetFileVersionInfoSize((PSTR)sFileName, &dummy); 2905 2906 if (result == 0) { 2907 VFDTRACE(0, 2908 (FUNC ": GetFileVersionInfoSize == 0\n")); 2909 2910 return ERROR_BAD_DRIVER; 2911 } 2912 2913 info = LocalAlloc(LPTR, result); 2914 2915 if (info == NULL) { 2916 ret = GetLastError(); 2917 2918 VFDTRACE(0, 2919 (FUNC ": LocalAlloc(%lu) - %s\n", 2920 result, SystemMessage(ret))); 2921 2922 return ret; 2923 } 2924 2925 if (!GetFileVersionInfo((PSTR)sFileName, 0, result, info)) { 2926 ret = GetLastError(); 2927 2928 VFDTRACE(0, 2929 (FUNC ": GetFileVersionInfo - %s", SystemMessage(ret))); 2930 2931 goto cleanup; 2932 } 2933 2934 result = sizeof(fixedinfo); 2935 2936 if (!VerQueryValue(info, "\\", (PVOID *)&fixedinfo, (PUINT)&result)) { 2937 ret = GetLastError(); 2938 2939 VFDTRACE(0, 2940 (FUNC ": VerQueryValue(\"\\\") - %s", SystemMessage(ret))); 2941 2942 goto cleanup; 2943 } 2944 2945 if (fixedinfo->dwFileOS != VOS_NT_WINDOWS32 || 2946 fixedinfo->dwFileType != VFT_DRV || 2947 fixedinfo->dwFileSubtype != VFT2_DRV_SYSTEM) { 2948 2949 VFDTRACE(0, 2950 (FUNC ": Invalid file type flags\n")); 2951 2952 ret = ERROR_BAD_DRIVER; 2953 2954 goto cleanup; 2955 } 2956 2957 if (pFileVersion) { 2958 *pFileVersion = fixedinfo->dwFileVersionMS; 2959 2960 if (fixedinfo->dwFileFlags & VS_FF_DEBUG) { 2961 *pFileVersion |= 0x80000000; 2962 } 2963 } 2964 2965 if (!VerQueryValue(info, 2966 "\\StringFileInfo\\" VFD_VERSIONINFO_LANG "\\OriginalFileName", 2967 (PVOID *)&str, (PUINT)&result)) { 2968 ret = GetLastError(); 2969 2970 VFDTRACE(0, 2971 (FUNC ": VerQueryValue(\"OriginalFileName\") - %s", 2972 SystemMessage(ret))); 2973 2974 goto cleanup; 2975 } 2976 2977 if (strcmp(str, VFD_DRIVER_FILENAME)) { 2978 VFDTRACE(0, 2979 (FUNC ": Invalid original file name\n")); 2980 2981 ret = ERROR_BAD_DRIVER; 2982 2983 goto cleanup; 2984 } 2985 2986 if (fixedinfo->dwFileVersionMS != MAKELONG(VFD_DRIVER_MINOR, VFD_DRIVER_MAJOR) || 2987 fixedinfo->dwProductVersionMS != MAKELONG(VFD_PRODUCT_MINOR, VFD_PRODUCT_MAJOR)) { 2988 2989 VFDTRACE(0, 2990 (FUNC ": Invalid version values - file:%08x, prod: %08x\n", 2991 fixedinfo->dwFileVersionMS, fixedinfo->dwProductVersionMS)); 2992 2993 ret = ERROR_BAD_DRIVER; 2994 2995 goto cleanup; 2996 } 2997 2998 // Ensure that the driver binary is located on a local drive 2999 // because device driver cannot be started on network drives. 3000 3001 if (*sFileName == '\\' && *(sFileName + 1) == '\\') { 3002 // full path is a UNC path -- \\server\dir\... 3003 3004 VFDTRACE(0, 3005 (FUNC ": Driver is located on a network drive\n")); 3006 3007 return ERROR_NETWORK_ACCESS_DENIED; 3008 } 3009 else { 3010 // ensure that the drive letter is not a network drive 3011 3012 CHAR root[] = " :\\"; 3013 3014 root[0] = *sFileName; 3015 3016 if (GetDriveType(root) == DRIVE_REMOTE) { 3017 // the drive is a network drive 3018 3019 VFDTRACE(0, 3020 (FUNC ": Driver is located on a network drive\n")); 3021 3022 return ERROR_NETWORK_ACCESS_DENIED; 3023 } 3024 } 3025 3026 cleanup: 3027 LocalFree(info); 3028 3029 return ret; 3030 } 3031 3032 // 3033 // check an image file 3034 // 3035 DWORD WINAPI VfdCheckImageFile( 3036 PCSTR sFileName, 3037 PDWORD pAttributes, 3038 PVFD_FILETYPE pFileType, 3039 PULONG pImageSize) 3040 { 3041 #undef FUNC 3042 #define FUNC "VfdCheckImageFile" 3043 HANDLE hFile; 3044 DWORD ret = ERROR_SUCCESS; 3045 3046 if (!sFileName || !*sFileName || !pAttributes || !pImageSize || !pFileType) { 3047 return ERROR_INVALID_PARAMETER; 3048 } 3049 3050 // get file attributes 3051 3052 *pAttributes = GetFileAttributes(sFileName); 3053 3054 if (*pAttributes == INVALID_FILE_ATTRIBUTES) { 3055 ret = GetLastError(); 3056 3057 if (ret != ERROR_FILE_NOT_FOUND) { 3058 VFDTRACE(0, 3059 (FUNC ": GetFileAttributes(%s) - %s\n", 3060 sFileName, SystemMessage(ret))); 3061 } 3062 3063 return ret; 3064 } 3065 3066 // Open the target file 3067 3068 hFile = CreateFile(sFileName, GENERIC_READ | GENERIC_WRITE, 3069 0, NULL, OPEN_EXISTING, 0, NULL); 3070 3071 if (hFile == INVALID_HANDLE_VALUE) { 3072 3073 // failed to open 3074 3075 ret = GetLastError(); 3076 3077 if (ret != ERROR_ACCESS_DENIED) { 3078 VFDTRACE(0, 3079 (FUNC ": CreateFile(%s) - %s\n", 3080 sFileName, SystemMessage(ret))); 3081 3082 return ret; 3083 } 3084 3085 // try opening it read-only 3086 3087 hFile = CreateFile(sFileName, GENERIC_READ, 3088 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 3089 3090 if (hFile == INVALID_HANDLE_VALUE) { 3091 3092 // cannot open even read-only 3093 3094 ret = GetLastError(); 3095 3096 VFDTRACE(0, 3097 (FUNC ": CreateFile(%s) - %s\n", 3098 sFileName, SystemMessage(ret))); 3099 3100 return ret; 3101 } 3102 3103 // file can be opened read-only 3104 *pAttributes |= FILE_ATTRIBUTE_READONLY; 3105 ret = ERROR_SUCCESS; 3106 } 3107 3108 // check if the image is an IMZ file 3109 3110 if (ExtractZipInfo(hFile, pImageSize) == ERROR_SUCCESS) { 3111 *pFileType = VFD_FILETYPE_ZIP; 3112 } 3113 else { 3114 *pImageSize = GetFileSize(hFile, NULL); 3115 *pFileType = VFD_FILETYPE_RAW; 3116 } 3117 3118 CloseHandle(hFile); 3119 3120 return ret; 3121 } 3122 3123 // 3124 // Create a formatted new image file 3125 // 3126 DWORD WINAPI VfdCreateImageFile( 3127 PCSTR sFileName, 3128 VFD_MEDIA nMediaType, 3129 VFD_FILETYPE nFileType, 3130 BOOL bOverWrite) 3131 { 3132 #undef FUNC 3133 #define FUNC "VfdCreateImageFile" 3134 HANDLE hFile; 3135 ULONG file_size; 3136 PUCHAR image_buf = NULL; 3137 DWORD result; 3138 DWORD ret = ERROR_SUCCESS; 3139 3140 if (nFileType != VFD_FILETYPE_RAW) { 3141 return ERROR_INVALID_PARAMETER; 3142 } 3143 3144 file_size = VfdGetMediaSize(nMediaType); 3145 3146 if (file_size == 0) { 3147 return ERROR_INVALID_PARAMETER; 3148 } 3149 3150 hFile = CreateFile(sFileName, GENERIC_WRITE, 0, NULL, 3151 bOverWrite ? CREATE_ALWAYS : CREATE_NEW, 0, NULL); 3152 3153 if (hFile == INVALID_HANDLE_VALUE) { 3154 ret = GetLastError(); 3155 3156 VFDTRACE(0, 3157 (FUNC ": CreateFile - %s", 3158 SystemMessage(ret))); 3159 3160 return ret; 3161 } 3162 3163 image_buf = (PUCHAR)LocalAlloc(LPTR, file_size); 3164 3165 if (image_buf == NULL) { 3166 ret = GetLastError(); 3167 3168 VFDTRACE(0, 3169 (FUNC ": LocalAlloc - %s", 3170 SystemMessage(ret))); 3171 3172 goto exit_func; 3173 } 3174 3175 FormatBufferFat(image_buf, VFD_BYTE_TO_SECTOR(file_size)); 3176 3177 if (!WriteFile(hFile, image_buf, file_size, &result, NULL) || 3178 file_size != result) { 3179 3180 ret = GetLastError(); 3181 3182 VFDTRACE(0, 3183 (FUNC ": WriteFile - %s", 3184 SystemMessage(ret))); 3185 3186 goto exit_func; 3187 } 3188 3189 SetEndOfFile(hFile); 3190 3191 exit_func: 3192 CloseHandle(hFile); 3193 3194 if (image_buf) { 3195 LocalFree(image_buf); 3196 } 3197 3198 return ret; 3199 } 3200 3201 3202 // 3203 // choose first available drive letter 3204 // 3205 CHAR WINAPI VfdChooseLetter() 3206 { 3207 DWORD logical_drives = GetLogicalDrives(); 3208 CHAR drive_letter = 'A'; 3209 3210 if (logical_drives == 0) { 3211 return '\0'; 3212 } 3213 3214 while (logical_drives & 0x1) { 3215 logical_drives >>= 1; 3216 drive_letter++; 3217 } 3218 3219 if (drive_letter > 'Z') { 3220 return '\0'; 3221 } 3222 3223 return drive_letter; 3224 } 3225 3226 // 3227 // media type functions 3228 // 3229 static const struct 3230 { 3231 ULONG Size; 3232 PCSTR Name; 3233 } 3234 media_tbl[VFD_MEDIA_MAX] = 3235 { 3236 { 0, "" }, // VFD_MEDIA_NONE, 3237 { VFD_SECTOR_TO_BYTE(320), "5.25\" 160KB" }, // VFD_MEDIA_F5_160 3238 { VFD_SECTOR_TO_BYTE(360), "5.25\" 180KB" }, // VFD_MEDIA_F5_180 3239 { VFD_SECTOR_TO_BYTE(640), "5.25\" 320KB" }, // VFD_MEDIA_F5_320 3240 { VFD_SECTOR_TO_BYTE(720), "5.25\" 360KB" }, // VFD_MEDIA_F5_360 3241 { VFD_SECTOR_TO_BYTE(1280), "3.5\" 640KB" }, // VFD_MEDIA_F3_640 3242 { VFD_SECTOR_TO_BYTE(1280), "5.25\" 640KB" }, // VFD_MEDIA_F5_640 3243 { VFD_SECTOR_TO_BYTE(1440), "3.5\" 720KB" }, // VFD_MEDIA_F3_720 3244 { VFD_SECTOR_TO_BYTE(1440), "5.25\" 720KB" }, // VFD_MEDIA_F5_720 3245 { VFD_SECTOR_TO_BYTE(1640), "3.5\" 820KB" }, // VFD_MEDIA_F3_820 3246 { VFD_SECTOR_TO_BYTE(2400), "3.5\" 1.2MB" }, // VFD_MEDIA_F3_1P2 3247 { VFD_SECTOR_TO_BYTE(2400), "5.25\" 1.2MB" }, // VFD_MEDIA_F5_1P2 3248 { VFD_SECTOR_TO_BYTE(2880), "3.5\" 1.44MB" }, // VFD_MEDIA_F3_1P4 3249 { VFD_SECTOR_TO_BYTE(3360), "3.5\" 1.68MB DMF" }, // VFD_MEDIA_F3_1P6 3250 { VFD_SECTOR_TO_BYTE(3444), "3.5\" 1.72MB DMF" }, // VFD_MEDIA_F3_1P7 3251 { VFD_SECTOR_TO_BYTE(5760), "3.5\" 2.88MB"} // VFD_MEDIA_F3_2P8 3252 }; 3253 3254 // Lookup the largest media to fit in a size 3255 3256 VFD_MEDIA WINAPI VfdLookupMedia( 3257 ULONG nSize) 3258 { 3259 VFD_MEDIA i; 3260 3261 for (i = 1; i < VFD_MEDIA_MAX; i++) { 3262 if (nSize < media_tbl[i].Size) { 3263 break; 3264 } 3265 } 3266 3267 return (--i); 3268 } 3269 3270 // Get media size (in bytes) of a media type 3271 3272 ULONG WINAPI VfdGetMediaSize( 3273 VFD_MEDIA nMediaType) 3274 { 3275 return nMediaType < VFD_MEDIA_MAX ? media_tbl[nMediaType].Size : 0; 3276 } 3277 3278 // Get media type name 3279 3280 PCSTR WINAPI VfdMediaTypeName( 3281 VFD_MEDIA nMediaType) 3282 { 3283 return nMediaType < VFD_MEDIA_MAX ? media_tbl[nMediaType].Name : NULL; 3284 } 3285