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