[VFD] Import the VFD project (Virtual Floppy Drive) which allows creating virtual
[reactos.git] / modules / rosapps / drivers / vfd / vfdlink.c
1 /*
2 vfdlink.c
3
4 Virtual Floppy Drive for Windows NT platform
5 Kernel mode driver: persistent drive letter functions
6
7 Copyright (C) 2003-2005 Ken Kato
8 */
9
10 #include "imports.h"
11 #include "vfddrv.h"
12 #include "vfddbg.h"
13
14 #ifdef ALLOC_PRAGMA
15 #pragma alloc_text(PAGE, VfdSetLink)
16 #pragma alloc_text(PAGE, VfdLoadLink)
17 #pragma alloc_text(PAGE, VfdStoreLink)
18 #endif // ALLOC_PRAGMA
19
20 //
21 // create or remove the persistent drive letter (Windows NT)
22 //
23 NTSTATUS
24 VfdSetLink(
25 IN PDEVICE_EXTENSION DeviceExtension,
26 IN CHAR DriveLetter)
27 {
28 UNICODE_STRING unicode_name;
29 WCHAR name_buf[15];
30 NTSTATUS status = STATUS_SUCCESS;
31
32 VFDTRACE(VFDINFO, ("[VFD] VfdSetLink - IN\n"));
33
34 // convert lower case into upper case
35
36 if (DriveLetter >= 'a' && DriveLetter <= 'z') {
37 DriveLetter -= ('a' - 'A');
38 }
39
40 // check the drive letter range
41
42 if (DriveLetter != 0 &&
43 (DriveLetter < 'A' || DriveLetter > 'Z')) {
44 return STATUS_INVALID_PARAMETER;
45 }
46
47 if (DeviceExtension->DriveLetter &&
48 DeviceExtension->DriveLetter != DriveLetter) {
49 //
50 // Delete the old drive letter
51 //
52 name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
53
54 _snwprintf(name_buf, sizeof(name_buf) - 1,
55 L"\\??\\%wc:", DeviceExtension->DriveLetter);
56
57 RtlInitUnicodeString(&unicode_name, name_buf);
58
59 status = IoDeleteSymbolicLink(&unicode_name);
60
61 if (NT_SUCCESS(status)) {
62 VFDTRACE(VFDINFO,
63 ("[VFD] Link %ws deleted\n", name_buf));
64
65 DeviceExtension->DriveLetter = 0;
66 }
67 else if (status != STATUS_OBJECT_NAME_NOT_FOUND) {
68 // the driver letter did not exist in the first place
69
70 VFDTRACE(VFDINFO,
71 ("[VFD] Link %ws not found\n", name_buf));
72
73 DeviceExtension->DriveLetter = 0;
74 status = STATUS_SUCCESS;
75 }
76 else {
77 VFDTRACE(VFDWARN,
78 ("[VFD] IoDeleteSymbolicLink %ws - %s\n",
79 name_buf, GetStatusName(status)));
80 }
81 }
82
83 if (NT_SUCCESS(status) && DriveLetter) {
84 //
85 // Create a new drive letter
86 //
87
88 name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
89
90 _snwprintf(name_buf, sizeof(name_buf) - 1,
91 (OsMajorVersion >= 5) ?
92 L"\\??\\Global\\%wc:" : L"\\??\\%wc:",
93 DriveLetter);
94
95 RtlInitUnicodeString(&unicode_name, name_buf);
96
97 status = IoCreateSymbolicLink(
98 &unicode_name, &(DeviceExtension->DeviceName));
99
100 if (NT_SUCCESS(status)) {
101 VFDTRACE(VFDINFO, ("[VFD] Link %ws created\n", name_buf));
102
103 DeviceExtension->DriveLetter = DriveLetter;
104 }
105 else {
106 VFDTRACE(VFDWARN,
107 ("[VFD] IoCreateSymbolicLink %ws - %s\n",
108 name_buf, GetStatusName(status)));
109 }
110 }
111
112 VFDTRACE(VFDINFO,
113 ("[VFD] VfdSetLink - %s\n", GetStatusName(status)));
114
115 return status;
116 }
117
118 //
119 // load the persistent drive letter from the registry
120 //
121 NTSTATUS
122 VfdLoadLink(
123 IN PDEVICE_EXTENSION DeviceExtension,
124 IN PWSTR RegistryPath)
125 {
126 RTL_QUERY_REGISTRY_TABLE params[2];
127 WCHAR name_buf[20];
128 ULONG letter;
129 ULONG zero = 0;
130 NTSTATUS status;
131
132 VFDTRACE(VFDINFO, ("[VFD] VfdLoadLink - IN\n"));
133
134 RtlZeroMemory(params, sizeof(params));
135
136 name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
137
138 _snwprintf(name_buf, sizeof(name_buf) - 1,
139 VFD_REG_DRIVE_LETTER L"%lu",
140 DeviceExtension->DeviceNumber);
141
142 params[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
143 params[0].Name = name_buf;
144 params[0].EntryContext = &letter;
145 params[0].DefaultType = REG_DWORD;
146 params[0].DefaultData = &zero;
147 params[0].DefaultLength = sizeof(ULONG);
148
149 status = RtlQueryRegistryValues(
150 RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
151 RegistryPath, &params[0], NULL, NULL);
152
153 VFDTRACE(VFDINFO,
154 ("[VFD] Drive letter '%wc' loaded from the registry\n",
155 letter ? letter : ' '));
156
157 DeviceExtension->DriveLetter = (CHAR)letter;
158
159 VFDTRACE(VFDINFO,
160 ("[VFD] VfdLoadLink - %s\n", GetStatusName(status)));
161
162 return status;
163 }
164
165 //
166 // store the persistent drive letter into the registry
167 //
168 NTSTATUS
169 VfdStoreLink(
170 IN PDEVICE_EXTENSION DeviceExtension)
171 {
172 PVFD_DRIVER_EXTENSION driver_extension;
173 WCHAR name_buf[20];
174 ULONG letter;
175 NTSTATUS status;
176
177 VFDTRACE(VFDINFO, ("[VFD] VfdStoreLink - IN\n"));
178
179 #ifdef VFD_PNP
180 driver_extension = IoGetDriverObjectExtension(
181 DeviceExtension->device_object->DriverObject,
182 VFD_DRIVER_EXTENSION_ID);
183 #else // VFD_PNP
184 driver_extension = DeviceExtension->DriverExtension;
185 #endif // VFD_PNP
186
187 if (!driver_extension ||
188 !driver_extension->RegistryPath.Buffer) {
189
190 VFDTRACE(VFDWARN, ("[VFD] Registry Path not present.\n"));
191 VFDTRACE(VFDINFO, ("[VFD] VfdStoreLinks - OUT\n"));
192 return STATUS_DRIVER_INTERNAL_ERROR;
193 }
194
195 name_buf[sizeof(name_buf) - 1] = UNICODE_NULL;
196
197 _snwprintf(name_buf, sizeof(name_buf) - 1,
198 VFD_REG_DRIVE_LETTER L"%lu",
199 DeviceExtension->DeviceNumber);
200
201 letter = DeviceExtension->DriveLetter;
202
203 status = RtlWriteRegistryValue(
204 RTL_REGISTRY_ABSOLUTE,
205 driver_extension->RegistryPath.Buffer,
206 name_buf,
207 REG_DWORD,
208 &letter,
209 sizeof(ULONG));
210
211 if (!NT_SUCCESS(status)) {
212 VFDTRACE(VFDWARN,
213 ("[VFD] RtlWriteRegistryValue - %s\n",
214 GetStatusName(status)));
215 }
216 else {
217 VFDTRACE(VFDINFO,
218 ("[VFD] Drive letter '%wc' stored into the registry\n",
219 letter ? letter : L' '));
220 }
221
222 VFDTRACE(VFDINFO,
223 ("[VFD] VfdStoreLink - %s\n", GetStatusName(status)));
224
225 return status;
226 }