814ec76a1a034db3b1c41e13aae221e1955274b5
[reactos.git] / rosapps / applications / cmdutils / rosvboxmgmt / rosvboxmgmt.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS VBox Shared Folders Management
4 * FILE: cmdutils/hackssign/client.c
5 * PURPOSE: Communicate with VBox mini redirector to deal with shared folders
6 * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
7 */
8
9 #include <stdio.h>
10 #include <wchar.h>
11 #include <windows.h>
12 #include <shlobj.h>
13 #include <shobjidl.h>
14 #include <shlwapi.h>
15
16 /* DON'T CHANGE ORDER!!!! */
17 PCWSTR devices[3] = { L"\\\\.\\VBoxMiniRdrDN", L"\\??\\VBoxMiniRdrDN", L"\\Device\\VBoxMiniRdr" };
18
19 #define MAX_LEN 255
20
21 /* Taken from VBox header */
22 #define _MRX_MAX_DRIVE_LETTERS 26
23 #define IOCTL_MRX_VBOX_BASE FILE_DEVICE_NETWORK_FILE_SYSTEM
24 #define _MRX_VBOX_CONTROL_CODE(request, method, access) \
25 CTL_CODE(IOCTL_MRX_VBOX_BASE, request, method, access)
26 #define IOCTL_MRX_VBOX_ADDCONN _MRX_VBOX_CONTROL_CODE(100, METHOD_BUFFERED, FILE_ANY_ACCESS)
27 #define IOCTL_MRX_VBOX_GETLIST _MRX_VBOX_CONTROL_CODE(103, METHOD_BUFFERED, FILE_ANY_ACCESS)
28 #define IOCTL_MRX_VBOX_GETGLOBALLIST _MRX_VBOX_CONTROL_CODE(104, METHOD_BUFFERED, FILE_ANY_ACCESS)
29 #define IOCTL_MRX_VBOX_GETGLOBALCONN _MRX_VBOX_CONTROL_CODE(105, METHOD_BUFFERED, FILE_ANY_ACCESS)
30 #define IOCTL_MRX_VBOX_START _MRX_VBOX_CONTROL_CODE(106, METHOD_BUFFERED, FILE_ANY_ACCESS)
31
32 BOOL performDevIoCtl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize)
33 {
34 short i;
35 BOOL ret;
36 DWORD lpBytesReturned;
37 HANDLE dev = INVALID_HANDLE_VALUE;
38
39 wprintf(L"Trying to open a VBoxSRV device\n");
40 for (i = 0; i < 3; ++i)
41 {
42 dev = CreateFile(devices[i],
43 GENERIC_READ | GENERIC_WRITE,
44 FILE_SHARE_READ | FILE_SHARE_WRITE,
45 NULL, OPEN_EXISTING, 0, NULL);
46 if (dev != INVALID_HANDLE_VALUE)
47 {
48 break;
49 }
50 }
51
52 if (dev == INVALID_HANDLE_VALUE)
53 {
54 return FALSE;
55 }
56
57 wprintf(L"%s opened.\n", devices[i]);
58
59 ret = DeviceIoControl(dev, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, &lpBytesReturned, NULL);
60 wprintf(L"Done: it %s with error: %lx\n", (ret != 0 ? L"succeed" : L"failed"), (ret != 0 ? ERROR_SUCCESS : GetLastError()));
61
62 CloseHandle(dev);
63
64 return ret;
65 }
66
67 int startVBoxSrv(void)
68 {
69 return (performDevIoCtl(IOCTL_MRX_VBOX_START, NULL, 0, NULL, 0) == FALSE);
70 }
71
72 int addConn(PCWSTR letter, PCWSTR path)
73 {
74 BOOL ret;
75 PWSTR inputBuffer;
76 DWORD inputBufferSize;
77
78 if (iswalpha(letter[0]) == 0)
79 {
80 wprintf(L"Invalid letter provided\n");
81 return 1;
82 }
83
84 if (wcschr(path, L'\\') != NULL)
85 {
86 wprintf(L"Only give the name of a share\n");
87 return 1;
88 }
89
90 inputBufferSize = (wcslen(path) + wcslen(devices[2]) + wcslen(L"\\;Z:\\vboxsvr\\")) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
91 inputBuffer = malloc(inputBufferSize);
92 if (inputBuffer == NULL)
93 {
94 wprintf(L"Memory failure\n");
95 return 1;
96 }
97
98 swprintf(inputBuffer, L"%s\\;%c:\\vboxsvr\\%s", devices[2], towupper(letter[0]), path);
99 wprintf(L"Will create the following connection: %s\n", inputBuffer);
100 ret = performDevIoCtl(IOCTL_MRX_VBOX_ADDCONN, inputBuffer, inputBufferSize, NULL, 0);
101 free(inputBuffer);
102
103 return (ret == FALSE);
104 }
105
106 int getList(void)
107 {
108 short i;
109 BOOL ret;
110 DWORD outputBufferSize;
111 char outputBuffer[_MRX_MAX_DRIVE_LETTERS];
112
113 outputBufferSize = sizeof(outputBuffer);
114 ret = performDevIoCtl(IOCTL_MRX_VBOX_GETLIST, NULL, 0, &outputBuffer, outputBufferSize);
115 if (ret == FALSE)
116 {
117 return 1;
118 }
119
120 for (i = 0; i < _MRX_MAX_DRIVE_LETTERS; i += 2)
121 {
122 wprintf(L"%c: %s\t%c: %s\n", 'A' + i, (outputBuffer[i] == 0 ? L"FALSE" : L"TRUE"),
123 'A' + (i + 1), (outputBuffer[i + 1] == 0 ? L"FALSE" : L"TRUE"));
124 }
125
126 return 0;
127 }
128
129 PCWSTR getGlobalConn(CHAR id)
130 {
131 BOOL ret;
132 static WCHAR name[MAX_LEN];
133
134 ret = performDevIoCtl(IOCTL_MRX_VBOX_GETGLOBALCONN, &id, sizeof(id), name, sizeof(name));
135 if (ret == FALSE)
136 {
137 return NULL;
138 }
139
140 name[MAX_LEN - 1] = 0;
141 return name;
142 }
143
144 int getGlobalList(void)
145 {
146 short i;
147 BOOL ret;
148 DWORD outputBufferSize;
149 char outputBuffer[_MRX_MAX_DRIVE_LETTERS];
150
151 outputBufferSize = sizeof(outputBuffer);
152 memset(outputBuffer, 0, outputBufferSize);
153 ret = performDevIoCtl(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, &outputBuffer, outputBufferSize);
154 if (ret == FALSE)
155 {
156 return 1;
157 }
158
159 for (i = 0; i < _MRX_MAX_DRIVE_LETTERS; ++i)
160 {
161 CHAR id = outputBuffer[i];
162 BOOL active = ((id & 0x80) == 0x80);
163 PCWSTR name = NULL;
164
165 if (active)
166 {
167 name = getGlobalConn(id);
168 }
169 if (name == NULL)
170 {
171 name = L"None";
172 }
173
174 wprintf(L"%c: %s (%s)%c", 'A' + i, (active ? L"Active" : L"Inactive"), name, (i & 1 ? '\n' : '\t'));
175 }
176
177 return 0;
178 }
179
180 BOOL CreateUNCShortcut(PCWSTR share)
181 {
182 HRESULT res;
183 IShellLink *link;
184 IPersistFile *persist;
185 WCHAR path[MAX_PATH];
186 WCHAR linkPath[MAX_PATH];
187
188 res = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (void**)&link);
189 if (FAILED(res))
190 {
191 return FALSE;
192 }
193
194 res = link->lpVtbl->QueryInterface(link, &IID_IPersistFile, (void **)&persist);
195 if (FAILED(res))
196 {
197 link->lpVtbl->Release(link);
198 return FALSE;
199 }
200
201 wcscpy(path, L"\\\\vboxsvr\\");
202 wcscat(path, share);
203 link->lpVtbl->SetPath(link, path);
204
205 res = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, path);
206 if (FAILED(res))
207 {
208 persist->lpVtbl->Release(persist);
209 link->lpVtbl->Release(link);
210 return FALSE;
211 }
212
213 wsprintf(linkPath, L"%s\\Browse %s (VBox).lnk", path, share);
214 res = persist->lpVtbl->Save(persist, linkPath, TRUE);
215
216 persist->lpVtbl->Release(persist);
217 link->lpVtbl->Release(link);
218
219 return SUCCEEDED(res);
220 }
221
222 int autoStart(void)
223 {
224 short i;
225 BOOL ret;
226 DWORD outputBufferSize;
227 char outputBuffer[_MRX_MAX_DRIVE_LETTERS];
228
229 if (startVBoxSrv() != 0)
230 {
231 return 1;
232 }
233
234 outputBufferSize = sizeof(outputBuffer);
235 memset(outputBuffer, 0, outputBufferSize);
236 ret = performDevIoCtl(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, &outputBuffer, outputBufferSize);
237 if (ret == FALSE)
238 {
239 return 1;
240 }
241
242 CoInitialize(NULL);
243 for (i = 0; i < _MRX_MAX_DRIVE_LETTERS; ++i)
244 {
245 CHAR id = outputBuffer[i];
246 BOOL active = ((id & 0x80) == 0x80);
247 PCWSTR name = NULL;
248
249 if (active)
250 {
251 name = getGlobalConn(id);
252 }
253 if (name == NULL)
254 {
255 continue;
256 }
257
258 CreateUNCShortcut(name);
259 }
260
261 return 0;
262 }
263
264 void printUsage(void)
265 {
266 wprintf(L"ReactOS VBox Shared Folders Management\n");
267 wprintf(L"\tstart: start the VBox Shared folders (mandatory prior any operation!)\n");
268 wprintf(L"\taddconn <letter> <share name>: add a connection\n");
269 wprintf(L"\tgetlist: list connections\n");
270 wprintf(L"\tgetgloballist: list available shares\n");
271 wprintf(L"\tauto: automagically configure the VBox Shared folders and creates desktop folders\n");
272 }
273
274 int wmain(int argc, wchar_t *argv[])
275 {
276 PCWSTR cmd;
277
278 if (argc == 1)
279 {
280 printUsage();
281 return 0;
282 }
283
284 cmd = argv[1];
285
286 if (_wcsicmp(cmd, L"start") == 0)
287 {
288 return startVBoxSrv();
289 }
290 else if (_wcsicmp(cmd, L"addconn") == 0)
291 {
292 if (argc < 4)
293 {
294 printUsage();
295 return 0;
296 }
297
298 return addConn(argv[2], argv[3]);
299 }
300 else if (_wcsicmp(cmd, L"getlist") == 0)
301 {
302 return getList();
303 }
304 else if (_wcsicmp(cmd, L"getgloballist") == 0)
305 {
306 return getGlobalList();
307 }
308 else if (_wcsicmp(cmd, L"auto") == 0)
309 {
310 return autoStart();
311 }
312 else
313 {
314 printUsage();
315 return 0;
316 }
317 }