JNIEXPORT jstring JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsRegistryFunctions_getStringValue(JNIEnv *env, jclass target, jint keyNum, jstring subkey, jstring valueName, jobject result) { HKEY key = get_key_from_ordinal(keyNum); wchar_t* subkeyStr = java_to_wchar(env, subkey, result); wchar_t* valueNameStr = java_to_wchar(env, valueName, result); DWORD size = 0; LONG retval = SHRegGetValueW(key, subkeyStr, valueNameStr, SRRF_RT_REG_SZ, NULL, NULL, &size); if (retval != ERROR_SUCCESS) { free(subkeyStr); free(valueNameStr); if (retval != ERROR_FILE_NOT_FOUND) { mark_failed_with_code(env, "could not determine size of registry value", retval, NULL, result); } return NULL; } wchar_t* value = (wchar_t*)malloc(sizeof(wchar_t) * (size+1)); retval = SHRegGetValueW(key, subkeyStr, valueNameStr, SRRF_RT_REG_SZ, NULL, value, &size); free(subkeyStr); free(valueNameStr); if (retval != ERROR_SUCCESS) { free(value); mark_failed_with_code(env, "could not get registry value", retval, NULL, result); return NULL; } jstring jvalue = wchar_to_java(env, value, wcslen(value), result); free(value); return jvalue; }
JNIEXPORT jstring JNICALL Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getEnvironmentVariable(JNIEnv *env, jclass target, jstring var, jobject result) { wchar_t* varStr = java_to_wchar(env, var, result); DWORD len = GetEnvironmentVariableW(varStr, NULL, 0); if (len == 0) { if (GetLastError() != ERROR_ENVVAR_NOT_FOUND) { mark_failed_with_errno(env, "could not determine length of environment variable", result); } free(varStr); return NULL; } wchar_t* valueStr = (wchar_t*)malloc(sizeof(wchar_t) * len); DWORD copied = GetEnvironmentVariableW(varStr, valueStr, len); if (copied == 0) { if (len > 1) { // If the value is empty, then copied will be 0 mark_failed_with_errno(env, "could not get environment variable", result); } free(varStr); free(valueStr); return NULL; } free(varStr); jstring value = wchar_to_java(env, valueStr, copied, result); free(valueStr); return value; }
JNIEXPORT jstring JNICALL Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getWorkingDirectory(JNIEnv *env, jclass target, jobject result) { DWORD size = GetCurrentDirectoryW(0, NULL); if (size == 0) { mark_failed_with_errno(env, "could not determine length of working directory path", result); return NULL; } size = size+1; // Needs to include null character wchar_t* path = (wchar_t*)malloc(sizeof(wchar_t) * size); DWORD copied = GetCurrentDirectoryW(size, path); if (copied == 0) { free(path); mark_failed_with_errno(env, "could get working directory path", result); return NULL; } jstring dirName = wchar_to_java(env, path, copied, result); free(path); return dirName; }
JNIEXPORT jboolean JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsRegistryFunctions_getValueNames(JNIEnv *env, jclass target, jint keyNum, jstring subkey, jobject names, jobject result) { wchar_t* subkeyStr = java_to_wchar(env, subkey, result); jclass names_class = env->GetObjectClass(names); jmethodID method = env->GetMethodID(names_class, "add", "(Ljava/lang/Object;)Z"); HKEY key; LONG retval = RegOpenKeyExW(get_key_from_ordinal(keyNum), subkeyStr, 0, KEY_READ, &key); if (retval != ERROR_SUCCESS) { free(subkeyStr); if (retval != ERROR_FILE_NOT_FOUND) { mark_failed_with_code(env, "could open registry key", retval, NULL, result); } return false; } DWORD valueCount; DWORD maxValueNameLen; retval = RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, &maxValueNameLen, NULL, NULL, NULL); if (retval != ERROR_SUCCESS) { mark_failed_with_code(env, "could query registry key", retval, NULL, result); } else { wchar_t* valueNameStr = (wchar_t*)malloc(sizeof(wchar_t) * (maxValueNameLen+1)); for (int i = 0; i < valueCount; i++) { DWORD valueNameLen = maxValueNameLen + 1; retval = RegEnumValueW(key, i, valueNameStr, &valueNameLen, NULL, NULL, NULL, NULL); if (retval != ERROR_SUCCESS) { mark_failed_with_code(env, "could enumerate registry value name", retval, NULL, result); break; } env->CallVoidMethod(names, method, wchar_to_java(env, valueNameStr, wcslen(valueNameStr), result)); } free(valueNameStr); } RegCloseKey(key); free(subkeyStr); return true; }
JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsFileFunctions_readdir(JNIEnv *env, jclass target, jstring path, jobject contents, jobject result) { jclass contentsClass = env->GetObjectClass(contents); jmethodID mid = env->GetMethodID(contentsClass, "addFile", "(Ljava/lang/String;IJJ)V"); if (mid == NULL) { mark_failed_with_message(env, "could not find method", result); return; } WIN32_FIND_DATAW entry; wchar_t* pathStr = java_to_wchar(env, path, result); HANDLE dirHandle = FindFirstFileW(pathStr, &entry); free(pathStr); if (dirHandle == INVALID_HANDLE_VALUE) { mark_failed_with_errno(env, "could not open directory", result); return; } do { if (wcscmp(L".", entry.cFileName) == 0 || wcscmp(L"..", entry.cFileName) == 0) { continue; } jstring childName = wchar_to_java(env, entry.cFileName, wcslen(entry.cFileName), result); jint type = (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_TYPE_DIRECTORY : FILE_TYPE_FILE; jlong lastModified = lastModifiedNanos(&entry.ftLastWriteTime); jlong size = ((jlong)entry.nFileSizeHigh << 32) | entry.nFileSizeLow; env->CallVoidMethod(contents, mid, childName, type, size, lastModified); } while (FindNextFileW(dirHandle, &entry) != 0); DWORD error = GetLastError(); if (error != ERROR_NO_MORE_FILES ) { mark_failed_with_errno(env, "could not read next directory entry", result); } FindClose(dirHandle); }
/* * File system functions */ JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions_listFileSystems(JNIEnv *env, jclass target, jobject info, jobject result) { wchar_t* volumeName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); jclass info_class = env->GetObjectClass(info); jmethodID method = env->GetMethodID(info_class, "add", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V"); HANDLE handle = FindFirstVolumeW(volumeName, MAX_PATH+1); if (handle == INVALID_HANDLE_VALUE) { free(volumeName); mark_failed_with_errno(env, "could not find first volume", result); return; } wchar_t* deviceName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); wchar_t* pathNames = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); wchar_t* fsName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH+1)); while(true) { // Chop off the trailing '\' size_t len = wcslen(volumeName); if (len < 5) { mark_failed_with_message(env, "volume name is too short", result); break; } volumeName[len-1] = L'\0'; if (QueryDosDeviceW(&volumeName[4], deviceName, MAX_PATH+1) == 0) { mark_failed_with_errno(env, "could not query dos device", result); break; } volumeName[len-1] = L'\\'; DWORD used; if (GetVolumePathNamesForVolumeNameW(volumeName, pathNames, MAX_PATH+1, &used) == 0) { // TODO - try again if the buffer is too small mark_failed_with_errno(env, "could not query volume paths", result); break; } wchar_t* cur = pathNames; if (cur[0] != L'\0') { // TODO - use GetDriveTypeW() to determine if removable, remote, etc if(GetVolumeInformationW(cur, NULL, 0, NULL, NULL, NULL, fsName, MAX_PATH+1) == 0) { if (GetLastError() != ERROR_NOT_READY) { mark_failed_with_errno(env, "could not query volume information", result); break; } wcscpy(fsName, L"unknown"); } for (;cur[0] != L'\0'; cur += wcslen(cur) + 1) { env->CallVoidMethod(info, method, wchar_to_java(env, cur, wcslen(cur), result), wchar_to_java(env, fsName, wcslen(fsName), result), wchar_to_java(env, deviceName, wcslen(deviceName), result), JNI_FALSE); } } if (FindNextVolumeW(handle, volumeName, MAX_PATH) == 0) { if (GetLastError() != ERROR_NO_MORE_FILES) { mark_failed_with_errno(env, "could find next volume", result); } break; } } free(volumeName); free(deviceName); free(pathNames); free(fsName); FindVolumeClose(handle); }
JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions_listFileSystems(JNIEnv *env, jclass target, jobject info, jobject result) { jclass info_class = env->GetObjectClass(info); jmethodID method = env->GetMethodID(info_class, "add", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZ)V"); DWORD required = GetLogicalDriveStringsW(0, NULL); if (required == 0) { mark_failed_with_errno(env, "could not determine logical drive buffer size", result); return; } wchar_t* buffer = (wchar_t*)malloc(sizeof(wchar_t) * (required + 1)); wchar_t* deviceName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH + 1)); wchar_t* fileSystemName = (wchar_t*)malloc(sizeof(wchar_t) * (MAX_PATH + 1)); if (GetLogicalDriveStringsW(required, buffer) == 0) { mark_failed_with_errno(env, "could not determine logical drives", result); } else { wchar_t* cur = buffer; for (;cur[0] != L'\0'; cur += wcslen(cur) + 1) { DWORD type = GetDriveTypeW(cur); jboolean remote = type == DRIVE_REMOTE; // chop off trailing '\' size_t len = wcslen(cur); cur[len-1] = L'\0'; // create device name \\.\C: wchar_t devPath[7]; swprintf(devPath, 7, L"\\\\.\\%s", cur); if (QueryDosDeviceW(cur, deviceName, MAX_PATH+1) == 0) { mark_failed_with_errno(env, "could not map device for logical drive", result); break; } cur[len-1] = L'\\'; DWORD available = 1; if (!remote) { HANDLE hDevice = CreateFileW(devPath, // like "\\.\E:" FILE_READ_ATTRIBUTES, // read access to the attributes FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // share mode NULL, OPEN_EXISTING, 0, NULL); if (hDevice != INVALID_HANDLE_VALUE) { DWORD cbBytesReturned; DWORD bSuccess = DeviceIoControl (hDevice, // device to be queried IOCTL_STORAGE_CHECK_VERIFY2, NULL, 0, // no input buffer NULL, 0, // no output buffer &cbBytesReturned, // # bytes returned (LPOVERLAPPED) NULL); // synchronous I/O if (!bSuccess) { available = 0; } CloseHandle(hDevice); } } jboolean casePreserving = JNI_TRUE; if (available) { DWORD flags; if (GetVolumeInformationW(cur, NULL, 0, NULL, NULL, &flags, fileSystemName, MAX_PATH+1) == 0) { mark_failed_with_errno(env, "could not get volume information", result); break; } casePreserving = (flags & FILE_CASE_PRESERVED_NAMES) != 0; } else { if (type == DRIVE_CDROM) { swprintf(fileSystemName, MAX_PATH+1, L"cdrom"); } else { swprintf(fileSystemName, MAX_PATH+1, L"unknown"); } } env->CallVoidMethod(info, method, wchar_to_java(env, cur, wcslen(cur), result), wchar_to_java(env, fileSystemName, wcslen(fileSystemName), result), wchar_to_java(env, deviceName, wcslen(deviceName), result), remote, JNI_FALSE, casePreserving); } } free(buffer); free(deviceName); free(fileSystemName); }