/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS VBox Shared Folders Management * FILE: cmdutils/hackssign/client.c * PURPOSE: Communicate with VBox mini redirector to deal with shared folders * PROGRAMMERS: Pierre Schweitzer */ #include #include #include #include #include #include /* DON'T CHANGE ORDER!!!! */ PCWSTR devices[3] = { L"\\\\.\\VBoxMiniRdrDN", L"\\??\\VBoxMiniRdrDN", L"\\Device\\VBoxMiniRdr" }; #define MAX_LEN 255 /* Taken from VBox header */ #define _MRX_MAX_DRIVE_LETTERS 26 #define IOCTL_MRX_VBOX_BASE FILE_DEVICE_NETWORK_FILE_SYSTEM #define _MRX_VBOX_CONTROL_CODE(request, method, access) \ CTL_CODE(IOCTL_MRX_VBOX_BASE, request, method, access) #define IOCTL_MRX_VBOX_ADDCONN _MRX_VBOX_CONTROL_CODE(100, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_MRX_VBOX_GETLIST _MRX_VBOX_CONTROL_CODE(103, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_MRX_VBOX_GETGLOBALLIST _MRX_VBOX_CONTROL_CODE(104, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_MRX_VBOX_GETGLOBALCONN _MRX_VBOX_CONTROL_CODE(105, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_MRX_VBOX_START _MRX_VBOX_CONTROL_CODE(106, METHOD_BUFFERED, FILE_ANY_ACCESS) BOOL performDevIoCtl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize) { short i; BOOL ret; DWORD lpBytesReturned; HANDLE dev = INVALID_HANDLE_VALUE; wprintf(L"Trying to open a VBoxSRV device\n"); for (i = 0; i < 3; ++i) { dev = CreateFile(devices[i], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (dev != INVALID_HANDLE_VALUE) { break; } } if (dev == INVALID_HANDLE_VALUE) { return FALSE; } wprintf(L"%s opened.\n", devices[i]); ret = DeviceIoControl(dev, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, &lpBytesReturned, NULL); wprintf(L"Done: it %s with error: %lx\n", (ret != 0 ? L"succeed" : L"failed"), (ret != 0 ? ERROR_SUCCESS : GetLastError())); CloseHandle(dev); return ret; } int startVBoxSrv(void) { return (performDevIoCtl(IOCTL_MRX_VBOX_START, NULL, 0, NULL, 0) == FALSE); } int addConn(PCWSTR letter, PCWSTR path) { BOOL ret; PWSTR inputBuffer; DWORD inputBufferSize; if (iswalpha(letter[0]) == 0) { wprintf(L"Invalid letter provided\n"); return 1; } if (wcschr(path, L'\\') != NULL) { wprintf(L"Only give the name of a share\n"); return 1; } inputBufferSize = (wcslen(path) + wcslen(devices[2]) + wcslen(L"\\;Z:\\vboxsvr\\")) * sizeof(WCHAR) + sizeof(UNICODE_NULL); inputBuffer = malloc(inputBufferSize); if (inputBuffer == NULL) { wprintf(L"Memory failure\n"); return 1; } swprintf(inputBuffer, L"%s\\;%c:\\vboxsvr\\%s", devices[2], towupper(letter[0]), path); wprintf(L"Will create the following connection: %s\n", inputBuffer); ret = performDevIoCtl(IOCTL_MRX_VBOX_ADDCONN, inputBuffer, inputBufferSize, NULL, 0); free(inputBuffer); return (ret == FALSE); } int getList(void) { short i; BOOL ret; DWORD outputBufferSize; char outputBuffer[_MRX_MAX_DRIVE_LETTERS]; outputBufferSize = sizeof(outputBuffer); ret = performDevIoCtl(IOCTL_MRX_VBOX_GETLIST, NULL, 0, &outputBuffer, outputBufferSize); if (ret == FALSE) { return 1; } for (i = 0; i < _MRX_MAX_DRIVE_LETTERS; i += 2) { wprintf(L"%c: %s\t%c: %s\n", 'A' + i, (outputBuffer[i] == 0 ? L"FALSE" : L"TRUE"), 'A' + (i + 1), (outputBuffer[i + 1] == 0 ? L"FALSE" : L"TRUE")); } return 0; } PCWSTR getGlobalConn(CHAR id) { BOOL ret; static WCHAR name[MAX_LEN]; ret = performDevIoCtl(IOCTL_MRX_VBOX_GETGLOBALCONN, &id, sizeof(id), name, sizeof(name)); if (ret == FALSE) { return NULL; } name[MAX_LEN - 1] = 0; return name; } int getGlobalList(void) { short i; BOOL ret; DWORD outputBufferSize; char outputBuffer[_MRX_MAX_DRIVE_LETTERS]; outputBufferSize = sizeof(outputBuffer); memset(outputBuffer, 0, outputBufferSize); ret = performDevIoCtl(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, &outputBuffer, outputBufferSize); if (ret == FALSE) { return 1; } for (i = 0; i < _MRX_MAX_DRIVE_LETTERS; ++i) { CHAR id = outputBuffer[i]; BOOL active = ((id & 0x80) == 0x80); PCWSTR name = NULL; if (active) { name = getGlobalConn(id); } if (name == NULL) { name = L"None"; } wprintf(L"%c: %s (%s)%c", 'A' + i, (active ? L"Active" : L"Inactive"), name, (i & 1 ? '\n' : '\t')); } return 0; } BOOL createUNCShortcut(PCWSTR share) { HRESULT res; IShellLink *link; IPersistFile *persist; WCHAR path[MAX_PATH]; WCHAR linkPath[MAX_PATH]; res = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (void**)&link); if (FAILED(res)) { return FALSE; } res = link->lpVtbl->QueryInterface(link, &IID_IPersistFile, (void **)&persist); if (FAILED(res)) { link->lpVtbl->Release(link); return FALSE; } wcscpy(path, L"\\\\vboxsvr\\"); wcscat(path, share); link->lpVtbl->SetPath(link, path); res = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, path); if (FAILED(res)) { persist->lpVtbl->Release(persist); link->lpVtbl->Release(link); return FALSE; } wsprintf(linkPath, L"%s\\Browse %s (VBox).lnk", path, share); res = persist->lpVtbl->Save(persist, linkPath, TRUE); persist->lpVtbl->Release(persist); link->lpVtbl->Release(link); return SUCCEEDED(res); } BOOL assignDriveLetter(PCWSTR share) { DWORD driveMap; char drive; wchar_t cmdLine[MAX_PATH]; STARTUPINFOW startupInfo; PROCESS_INFORMATION processInformation; BOOL ok = FALSE; driveMap = GetLogicalDrives(); for (drive = _MRX_MAX_DRIVE_LETTERS - 1; drive >= 0; ++drive) { if (!(driveMap & (1 << drive))) { break; } } if (drive < 0) { wprintf(L"Failed finding an appropriate drive for shared folder\n"); return 1; } drive += 'A'; wsprintf(cmdLine, L"hackssign_client.exe assign %c %s", drive, share); RtlZeroMemory(&startupInfo, sizeof(startupInfo)); startupInfo.cb = sizeof(STARTUPINFOW); if (!CreateProcessW(NULL, (PVOID)cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation)) { wprintf(L"Failed starting hackssign_client.exe\n"); return 1; } ok = (WaitForSingleObject(processInformation.hProcess, -1) == WAIT_OBJECT_0); CloseHandle(processInformation.hProcess); CloseHandle(processInformation.hThread); wprintf(L"%c assigned to %s\n", drive, share); return ok; } int autoStart(BOOL assign) { short i; BOOL ret; DWORD outputBufferSize; char outputBuffer[_MRX_MAX_DRIVE_LETTERS]; OFSTRUCT ofs; if (startVBoxSrv() != 0) { return 1; } outputBufferSize = sizeof(outputBuffer); memset(outputBuffer, 0, outputBufferSize); ret = performDevIoCtl(IOCTL_MRX_VBOX_GETGLOBALLIST, NULL, 0, &outputBuffer, outputBufferSize); if (ret == FALSE) { return 1; } if (assign) { wchar_t path[MAX_PATH]; if (GetModuleFileName(NULL, path, ARRAYSIZE(path)) != 0) { *(wcsrchr(path, '\\')) = 0; wprintf(L"Switching to %s\n", path); SetCurrentDirectory(path); } if (OpenFile("hackssign_client.exe", &ofs, OF_EXIST) != 1) { wprintf(L"hackssign_client.exe not found, falling back to links\n"); assign = FALSE; } } if (!assign) { CoInitialize(NULL); } for (i = 0; i < _MRX_MAX_DRIVE_LETTERS; ++i) { CHAR id = outputBuffer[i]; BOOL active = ((id & 0x80) == 0x80); PCWSTR name = NULL; if (active) { name = getGlobalConn(id); } if (name == NULL) { continue; } if (!assign) { createUNCShortcut(name); } else { assignDriveLetter(name); } } return 0; } void printUsage(void) { wprintf(L"ReactOS VBox Shared Folders Management\n"); wprintf(L"\tstart: start the VBox Shared folders (mandatory prior any operation!)\n"); wprintf(L"\taddconn : add a connection\n"); wprintf(L"\tgetlist: list connections\n"); wprintf(L"\tgetgloballist: list available shares\n"); wprintf(L"\tautolink: automagically configure the VBox Shared folders and creates desktop folders\n"); wprintf(L"\tautoassign: automagically configure the VBox Shared folders and assigns drive letters\n"); } int wmain(int argc, wchar_t *argv[]) { PCWSTR cmd; if (argc == 1) { printUsage(); return 0; } cmd = argv[1]; if (_wcsicmp(cmd, L"start") == 0) { return startVBoxSrv(); } else if (_wcsicmp(cmd, L"addconn") == 0) { if (argc < 4) { printUsage(); return 0; } return addConn(argv[2], argv[3]); } else if (_wcsicmp(cmd, L"getlist") == 0) { return getList(); } else if (_wcsicmp(cmd, L"getgloballist") == 0) { return getGlobalList(); } else if (_wcsicmp(cmd, L"autolink") == 0) { return autoStart(FALSE); } else if (_wcsicmp(cmd, L"autoassign") == 0) { return autoStart(TRUE); } else { printUsage(); return 0; } }