[VFD] Add support for installing driver from System32\drivers.
[reactos.git] / modules / rosapps / lib / vfdlib / vfdctl.c
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 #ifdef _MSC_VER
19 #pragma warning (push, 3)
20 #endif
21 #include <shlobj.h>
22 #include <winioctl.h>
23 #ifdef _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(&params, 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)&params) <= 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 }