cachedFiles = new ArrayList<>();
+
+ public FileRedirect(String pathname) {
+ super(pathname);
+ System.out.println(pathname);
+ }
+
+ public FileRedirect(String parent, String child) {
+ super(parent, child);
+ sout(parent);
+ sout(child);
+ }
+
+ public FileRedirect(File parent, String child) {
+ super(parent, child);
+ sout(parent.toString());
+ sout(child);
+ }
+
+ public FileRedirect(URI uri) {
+ super(uri);
+ sout(uri.toString());
+ }
+
+ public static boolean exists(File file){
+ sout(file.toString());
+ return file.exists();
+ }
+
+ public static boolean isFile(File file){
+ sout(file.toString());
+ return file.isFile();
+ }
+
+ public static long length(File file){
+ sout(file.toString());
+ return file.length();
+ }
+
+ public static boolean mkdirs(File file){
+ sout(file.toString());
+ return file.mkdirs();
+ }
+
+ public static boolean mkdir(File file){
+ sout(file.toString());
+ return file.mkdir();
+ }
+
+ public static boolean isDirectory(File file){
+ sout(file.toString());
+ return file.isDirectory();
+ }
+
+ public static String getAbsolutePath(File file){
+ sout(file.toString());
+ return file.getAbsolutePath();
+ }
+
+ public static File getAbsoluteFile(File file){
+ sout(file.toString());
+ return file.getAbsoluteFile();
+ }
+
+ public static File[] listFiles(File file){
+ sout(file.toString());
+ return file.listFiles();
+ }
+
+ public static String getName(File file){
+ sout(file.getName());
+ return file.getName();
+ }
+
+ private static void sout(String s){
+ if (!cachedFiles.contains(s)) {
+ System.out.println("Requesting file: " + s);
+ cachedFiles.add(s);
+ }
+ }
+
+}
diff --git a/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java b/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java
index b9c35fe..092b920 100644
--- a/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java
+++ b/src/main/java/org/parabot/core/asm/redirect/RuntimeRedirect.java
@@ -2,6 +2,8 @@ package org.parabot.core.asm.redirect;
import org.parabot.core.asm.RedirectClassAdapter;
+import java.io.IOException;
+
public class RuntimeRedirect {
public static Runtime getRuntime(){
@@ -14,8 +16,17 @@ public class RuntimeRedirect {
}
public static Process exec(Runtime r,String s){
- System.out.println("Blocked attempted command:" + s);
- throw RedirectClassAdapter.createSecurityException();
+ if (s.contains("ping")){
+ System.out.println("Faked attempted command: " + s);
+ try {
+ return r.exec("ping 127.0.0.1");
+ } catch (IOException e) {
+ throw RedirectClassAdapter.createSecurityException();
+ }
+ }else{
+ System.out.println("Blocked attempted command: " + s);
+ throw RedirectClassAdapter.createSecurityException();
+ }
}
}
diff --git a/src/main/java/org/parabot/environment/api/utils/StringUtils.java b/src/main/java/org/parabot/environment/api/utils/StringUtils.java
index 7eeb18d..573d5a1 100644
--- a/src/main/java/org/parabot/environment/api/utils/StringUtils.java
+++ b/src/main/java/org/parabot/environment/api/utils/StringUtils.java
@@ -1,12 +1,13 @@
package org.parabot.environment.api.utils;
/**
- *
- * @author mkyong
- *
+ * @author mkyong, JKetelaar
*/
public class StringUtils {
+ private static java.util.Random random = new java.util.Random();
+ private static char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray();
+
public static String convertHexToString(String hex) {
StringBuilder sb = new StringBuilder();
@@ -27,4 +28,12 @@ public class StringUtils {
return sb.toString();
}
+ public static String randomString(final int length) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ char c = chars[random.nextInt(chars.length)];
+ sb.append(c);
+ }
+ return sb.toString();
+ }
}
diff --git a/src/main/java/org/parabot/environment/api/utils/WindowsPreferences.java b/src/main/java/org/parabot/environment/api/utils/WindowsPreferences.java
new file mode 100644
index 0000000..7cf72ed
--- /dev/null
+++ b/src/main/java/org/parabot/environment/api/utils/WindowsPreferences.java
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.parabot.environment.api.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.util.StringTokenizer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+
+/**
+ * Windows registry based implementation of Preferences.
+ * Preferences' systemRoot and userRoot are stored in
+ * HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs and
+ * HKEY_CURRENT_USER\Software\JavaSoft\Prefs correspondingly.
+ *
+ * @author Konstantin Kladko
+ * @see Preferences
+ * @see PreferencesFactory
+ * @since 1.4
+ */
+
+public class WindowsPreferences extends AbstractPreferences {
+
+ /**
+ * Logger for error messages
+ */
+ private static Logger logger;
+
+ /**
+ * Windows registry path to Preferences's root nodes.
+ */
+ private static final byte[] WINDOWS_ROOT_PATH
+ = stringToByteArray("Software\\JavaSoft\\Prefs");
+
+ /**
+ * Windows handles to HKEY_CURRENT_USER and
+ * HKEY_LOCAL_MACHINE hives.
+ */
+ private static final int HKEY_CURRENT_USER = 0x80000001;
+ private static final int HKEY_LOCAL_MACHINE = 0x80000002;
+
+ /**
+ * Mount point for Preferences' user root.
+ */
+ private static final int USER_ROOT_NATIVE_HANDLE = HKEY_CURRENT_USER;
+
+ /**
+ * Mount point for Preferences' system root.
+ */
+ private static final int SYSTEM_ROOT_NATIVE_HANDLE = HKEY_LOCAL_MACHINE;
+
+ /**
+ * Maximum byte-encoded path length for Windows native functions,
+ * ending null character not included.
+ */
+ private static final int MAX_WINDOWS_PATH_LENGTH = 256;
+
+ /**
+ * User root node.
+ */
+ static final Preferences userRoot =
+ new WindowsPreferences(USER_ROOT_NATIVE_HANDLE, WINDOWS_ROOT_PATH);
+
+ /**
+ * System root node.
+ */
+ static final Preferences systemRoot =
+ new WindowsPreferences(SYSTEM_ROOT_NATIVE_HANDLE, WINDOWS_ROOT_PATH);
+
+ /* Windows error codes. */
+ private static final int ERROR_SUCCESS = 0;
+ private static final int ERROR_FILE_NOT_FOUND = 2;
+ private static final int ERROR_ACCESS_DENIED = 5;
+
+ /* Constants used to interpret returns of native functions */
+ private static final int NATIVE_HANDLE = 0;
+ private static final int ERROR_CODE = 1;
+ private static final int SUBKEYS_NUMBER = 0;
+ private static final int VALUES_NUMBER = 2;
+ private static final int MAX_KEY_LENGTH = 3;
+ private static final int MAX_VALUE_NAME_LENGTH = 4;
+ private static final int DISPOSITION = 2;
+ private static final int REG_CREATED_NEW_KEY = 1;
+ private static final int REG_OPENED_EXISTING_KEY = 2;
+ private static final int NULL_NATIVE_HANDLE = 0;
+
+ /* Windows security masks */
+ private static final int DELETE = 0x10000;
+ private static final int KEY_QUERY_VALUE = 1;
+ private static final int KEY_SET_VALUE = 2;
+ private static final int KEY_CREATE_SUB_KEY = 4;
+ private static final int KEY_ENUMERATE_SUB_KEYS = 8;
+ private static final int KEY_READ = 0x20019;
+ private static final int KEY_WRITE = 0x20006;
+ private static final int KEY_ALL_ACCESS = 0xf003f;
+
+ /**
+ * Initial time between registry access attempts, in ms. The time is doubled
+ * after each failing attempt (except the first).
+ */
+ private static int INIT_SLEEP_TIME = 50;
+
+ /**
+ * Maximum number of registry access attempts.
+ */
+ private static int MAX_ATTEMPTS = 5;
+
+ /**
+ * BackingStore availability flag.
+ */
+ private boolean isBackingStoreAvailable = true;
+
+ /**
+ * Java wrapper for Windows registry API RegOpenKey()
+ */
+ private static native int[] WindowsRegOpenKey(int hKey, byte[] subKey,
+ int securityMask);
+ /**
+ * Retries RegOpenKey() MAX_ATTEMPTS times before giving up.
+ */
+ private static int[] WindowsRegOpenKey1(int hKey, byte[] subKey,
+ int securityMask) {
+ int[] result = WindowsRegOpenKey(hKey, subKey, securityMask);
+ if (result[ERROR_CODE] == ERROR_SUCCESS) {
+ return result;
+ } else if (result[ERROR_CODE] == ERROR_FILE_NOT_FOUND) {
+// logger().warning("Trying to recreate Windows registry node " +
+// byteArrayToString(subKey) + " at root 0x" +
+// Integer.toHexString(hKey) + ".");
+ // Try recreation
+ int handle = WindowsRegCreateKeyEx(hKey, subKey)[NATIVE_HANDLE];
+ WindowsRegCloseKey(handle);
+ return WindowsRegOpenKey(hKey, subKey, securityMask);
+ } else if (result[ERROR_CODE] != ERROR_ACCESS_DENIED) {
+ long sleepTime = INIT_SLEEP_TIME;
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch(InterruptedException e) {
+ return result;
+ }
+ sleepTime *= 2;
+ result = WindowsRegOpenKey(hKey, subKey, securityMask);
+ if (result[ERROR_CODE] == ERROR_SUCCESS) {
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Java wrapper for Windows registry API RegCloseKey()
+ */
+ private static native int WindowsRegCloseKey(int hKey);
+
+ /**
+ * Java wrapper for Windows registry API RegCreateKeyEx()
+ */
+ private static native int[] WindowsRegCreateKeyEx(int hKey, byte[] subKey);
+
+ /**
+ * Retries RegCreateKeyEx() MAX_ATTEMPTS times before giving up.
+ */
+ private static int[] WindowsRegCreateKeyEx1(int hKey, byte[] subKey) {
+ int[] result = WindowsRegCreateKeyEx(hKey, subKey);
+ if (result[ERROR_CODE] == ERROR_SUCCESS) {
+ return result;
+ } else {
+ long sleepTime = INIT_SLEEP_TIME;
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch(InterruptedException e) {
+ return result;
+ }
+ sleepTime *= 2;
+ result = WindowsRegCreateKeyEx(hKey, subKey);
+ if (result[ERROR_CODE] == ERROR_SUCCESS) {
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+ /**
+ * Java wrapper for Windows registry API RegDeleteKey()
+ */
+ private static native int WindowsRegDeleteKey(int hKey, byte[] subKey);
+
+ /**
+ * Java wrapper for Windows registry API RegFlushKey()
+ */
+ private static native int WindowsRegFlushKey(int hKey);
+
+ /**
+ * Retries RegFlushKey() MAX_ATTEMPTS times before giving up.
+ */
+ private static int WindowsRegFlushKey1(int hKey) {
+ int result = WindowsRegFlushKey(hKey);
+ if (result == ERROR_SUCCESS) {
+ return result;
+ } else {
+ long sleepTime = INIT_SLEEP_TIME;
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch(InterruptedException e) {
+ return result;
+ }
+ sleepTime *= 2;
+ result = WindowsRegFlushKey(hKey);
+ if (result == ERROR_SUCCESS) {
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Java wrapper for Windows registry API RegQueryValueEx()
+ */
+ private static native byte[] WindowsRegQueryValueEx(int hKey,
+ byte[] valueName);
+ /**
+ * Java wrapper for Windows registry API RegSetValueEx()
+ */
+ private static native int WindowsRegSetValueEx(int hKey, byte[] valueName,
+ byte[] value);
+ /**
+ * Retries RegSetValueEx() MAX_ATTEMPTS times before giving up.
+ */
+ private static int WindowsRegSetValueEx1(int hKey, byte[] valueName,
+ byte[] value) {
+ int result = WindowsRegSetValueEx(hKey, valueName, value);
+ if (result == ERROR_SUCCESS) {
+ return result;
+ } else {
+ long sleepTime = INIT_SLEEP_TIME;
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch(InterruptedException e) {
+ return result;
+ }
+ sleepTime *= 2;
+ result = WindowsRegSetValueEx(hKey, valueName, value);
+ if (result == ERROR_SUCCESS) {
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Java wrapper for Windows registry API RegDeleteValue()
+ */
+ private static native int WindowsRegDeleteValue(int hKey, byte[] valueName);
+
+ /**
+ * Java wrapper for Windows registry API RegQueryInfoKey()
+ */
+ private static native int[] WindowsRegQueryInfoKey(int hKey);
+
+ /**
+ * Retries RegQueryInfoKey() MAX_ATTEMPTS times before giving up.
+ */
+ private static int[] WindowsRegQueryInfoKey1(int hKey) {
+ int[] result = WindowsRegQueryInfoKey(hKey);
+ if (result[ERROR_CODE] == ERROR_SUCCESS) {
+ return result;
+ } else {
+ long sleepTime = INIT_SLEEP_TIME;
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch(InterruptedException e) {
+ return result;
+ }
+ sleepTime *= 2;
+ result = WindowsRegQueryInfoKey(hKey);
+ if (result[ERROR_CODE] == ERROR_SUCCESS) {
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Java wrapper for Windows registry API RegEnumKeyEx()
+ */
+ private static native byte[] WindowsRegEnumKeyEx(int hKey, int subKeyIndex,
+ int maxKeyLength);
+
+ /**
+ * Retries RegEnumKeyEx() MAX_ATTEMPTS times before giving up.
+ */
+ private static byte[] WindowsRegEnumKeyEx1(int hKey, int subKeyIndex,
+ int maxKeyLength) {
+ byte[] result = WindowsRegEnumKeyEx(hKey, subKeyIndex, maxKeyLength);
+ if (result != null) {
+ return result;
+ } else {
+ long sleepTime = INIT_SLEEP_TIME;
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch(InterruptedException e) {
+ return result;
+ }
+ sleepTime *= 2;
+ result = WindowsRegEnumKeyEx(hKey, subKeyIndex, maxKeyLength);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Java wrapper for Windows registry API RegEnumValue()
+ */
+ private static native byte[] WindowsRegEnumValue(int hKey, int valueIndex,
+ int maxValueNameLength);
+ /**
+ * Retries RegEnumValueEx() MAX_ATTEMPTS times before giving up.
+ */
+ private static byte[] WindowsRegEnumValue1(int hKey, int valueIndex,
+ int maxValueNameLength) {
+ byte[] result = WindowsRegEnumValue(hKey, valueIndex,
+ maxValueNameLength);
+ if (result != null) {
+ return result;
+ } else {
+ long sleepTime = INIT_SLEEP_TIME;
+ for (int i = 0; i < MAX_ATTEMPTS; i++) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch(InterruptedException e) {
+ return result;
+ }
+ sleepTime *= 2;
+ result = WindowsRegEnumValue(hKey, valueIndex,
+ maxValueNameLength);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Constructs a WindowsPreferences node, creating underlying
+ * Windows registry node and all its Windows parents, if they are not yet
+ * created.
+ * Logs a warning message, if Windows Registry is unavailable.
+ */
+ private WindowsPreferences(WindowsPreferences parent, String name) {
+ super(parent, name);
+ int parentNativeHandle = parent.openKey(KEY_CREATE_SUB_KEY, KEY_READ);
+ if (parentNativeHandle == NULL_NATIVE_HANDLE) {
+ // if here, openKey failed and logged
+ isBackingStoreAvailable = false;
+ return;
+ }
+ int[] result =
+ WindowsRegCreateKeyEx1(parentNativeHandle, toWindowsName(name));
+ if (result[ERROR_CODE] != ERROR_SUCCESS) {
+// logger().warning("Could not create windows registry "
+// + "node " + byteArrayToString(windowsAbsolutePath()) +
+// " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+// ". Windows RegCreateKeyEx(...) returned error code " +
+// result[ERROR_CODE] + ".");
+ isBackingStoreAvailable = false;
+ return;
+ }
+ newNode = (result[DISPOSITION] == REG_CREATED_NEW_KEY);
+ closeKey(parentNativeHandle);
+ closeKey(result[NATIVE_HANDLE]);
+ }
+
+ /**
+ * Constructs a root node creating the underlying
+ * Windows registry node and all of its parents, if they have not yet been
+ * created.
+ * Logs a warning message, if Windows Registry is unavailable.
+ * @param rootNativeHandle Native handle to one of Windows top level keys.
+ * @param rootDirectory Path to root directory, as a byte-encoded string.
+ */
+ private WindowsPreferences(int rootNativeHandle, byte[] rootDirectory) {
+ super(null,"");
+ int[] result =
+ WindowsRegCreateKeyEx1(rootNativeHandle, rootDirectory);
+ if (result[ERROR_CODE] != ERROR_SUCCESS) {
+// logger().warning("Could not open/create prefs root node " +
+// byteArrayToString(windowsAbsolutePath()) + " at root 0x" +
+// Integer.toHexString(rootNativeHandle()) +
+// ". Windows RegCreateKeyEx(...) returned error code " +
+// result[ERROR_CODE] + ".");
+ isBackingStoreAvailable = false;
+ return;
+ }
+ // Check if a new node
+ newNode = (result[DISPOSITION] == REG_CREATED_NEW_KEY);
+ closeKey(result[NATIVE_HANDLE]);
+ }
+
+ /**
+ * Returns Windows absolute path of the current node as a byte array.
+ * Java "/" separator is transformed into Windows "\".
+ * @see Preferences#absolutePath()
+ */
+ private byte[] windowsAbsolutePath() {
+ ByteArrayOutputStream bstream = new ByteArrayOutputStream();
+ bstream.write(WINDOWS_ROOT_PATH, 0, WINDOWS_ROOT_PATH.length-1);
+ StringTokenizer tokenizer = new StringTokenizer(absolutePath(),"/");
+ while (tokenizer.hasMoreTokens()) {
+ bstream.write((byte)'\\');
+ String nextName = tokenizer.nextToken();
+ byte[] windowsNextName = toWindowsName(nextName);
+ bstream.write(windowsNextName, 0, windowsNextName.length-1);
+ }
+ bstream.write(0);
+ return bstream.toByteArray();
+ }
+
+ /**
+ * Opens current node's underlying Windows registry key using a
+ * given security mask.
+ * @param securityMask Windows security mask.
+ * @return Windows registry key's handle.
+ * @see #openKey(byte[], int)
+ * @see #openKey(int, byte[], int)
+ * @see #closeKey(int)
+ */
+ private int openKey(int securityMask) {
+ return openKey(securityMask, securityMask);
+ }
+
+ /**
+ * Opens current node's underlying Windows registry key using a
+ * given security mask.
+ * @param mask1 Preferred Windows security mask.
+ * @param mask2 Alternate Windows security mask.
+ * @return Windows registry key's handle.
+ * @see #openKey(byte[], int)
+ * @see #openKey(int, byte[], int)
+ * @see #closeKey(int)
+ */
+ private int openKey(int mask1, int mask2) {
+ return openKey(windowsAbsolutePath(), mask1, mask2);
+ }
+
+ /**
+ * Opens Windows registry key at a given absolute path using a given
+ * security mask.
+ * @param windowsAbsolutePath Windows absolute path of the
+ * key as a byte-encoded string.
+ * @param mask1 Preferred Windows security mask.
+ * @param mask2 Alternate Windows security mask.
+ * @return Windows registry key's handle.
+ * @see #openKey(int)
+ * @see #openKey(int, byte[],int)
+ * @see #closeKey(int)
+ */
+ private int openKey(byte[] windowsAbsolutePath, int mask1, int mask2) {
+ /* Check if key's path is short enough be opened at once
+ otherwise use a path-splitting procedure */
+ if (windowsAbsolutePath.length <= MAX_WINDOWS_PATH_LENGTH + 1) {
+ int[] result = WindowsRegOpenKey1(rootNativeHandle(),
+ windowsAbsolutePath, mask1);
+ if (result[ERROR_CODE] == ERROR_ACCESS_DENIED && mask2 != mask1)
+ result = WindowsRegOpenKey1(rootNativeHandle(),
+ windowsAbsolutePath, mask2);
+
+ if (result[ERROR_CODE] != ERROR_SUCCESS) {
+// logger().warning("Could not open windows "
+// + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+// " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+// ". Windows RegOpenKey(...) returned error code " +
+// result[ERROR_CODE] + ".");
+ result[NATIVE_HANDLE] = NULL_NATIVE_HANDLE;
+ if (result[ERROR_CODE] == ERROR_ACCESS_DENIED) {
+ throw new SecurityException("Could not open windows "
+ + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+ ": Access denied");
+ }
+ }
+ return result[NATIVE_HANDLE];
+ } else {
+ return openKey(rootNativeHandle(), windowsAbsolutePath, mask1, mask2);
+ }
+ }
+
+ /**
+ * Opens Windows registry key at a given relative path
+ * with respect to a given Windows registry key.
+ * @param windowsAbsolutePath Windows relative path of the
+ * key as a byte-encoded string.
+ * @param nativeHandle handle to the base Windows key.
+ * @param mask1 Preferred Windows security mask.
+ * @param mask2 Alternate Windows security mask.
+ * @return Windows registry key's handle.
+ * @see #openKey(int)
+ * @see #openKey(byte[],int)
+ * @see #closeKey(int)
+ */
+ private int openKey(int nativeHandle, byte[] windowsRelativePath,
+ int mask1, int mask2) {
+ /* If the path is short enough open at once. Otherwise split the path */
+ if (windowsRelativePath.length <= MAX_WINDOWS_PATH_LENGTH + 1 ) {
+ int[] result = WindowsRegOpenKey1(nativeHandle,
+ windowsRelativePath, mask1);
+ if (result[ERROR_CODE] == ERROR_ACCESS_DENIED && mask2 != mask1)
+ result = WindowsRegOpenKey1(nativeHandle,
+ windowsRelativePath, mask2);
+
+ if (result[ERROR_CODE] != ERROR_SUCCESS) {
+// logger().warning("Could not open windows "
+// + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+// " at root 0x" + Integer.toHexString(nativeHandle) +
+// ". Windows RegOpenKey(...) returned error code " +
+// result[ERROR_CODE] + ".");
+ result[NATIVE_HANDLE] = NULL_NATIVE_HANDLE;
+ }
+ return result[NATIVE_HANDLE];
+ } else {
+ int separatorPosition = -1;
+ // Be greedy - open the longest possible path
+ for (int i = MAX_WINDOWS_PATH_LENGTH; i > 0; i--) {
+ if (windowsRelativePath[i] == ((byte)'\\')) {
+ separatorPosition = i;
+ break;
+ }
+ }
+ // Split the path and do the recursion
+ byte[] nextRelativeRoot = new byte[separatorPosition+1];
+ System.arraycopy(windowsRelativePath, 0, nextRelativeRoot,0,
+ separatorPosition);
+ nextRelativeRoot[separatorPosition] = 0;
+ byte[] nextRelativePath = new byte[windowsRelativePath.length -
+ separatorPosition - 1];
+ System.arraycopy(windowsRelativePath, separatorPosition+1,
+ nextRelativePath, 0, nextRelativePath.length);
+ int nextNativeHandle = openKey(nativeHandle, nextRelativeRoot,
+ mask1, mask2);
+ if (nextNativeHandle == NULL_NATIVE_HANDLE) {
+ return NULL_NATIVE_HANDLE;
+ }
+ int result = openKey(nextNativeHandle, nextRelativePath,
+ mask1,mask2);
+ closeKey(nextNativeHandle);
+ return result;
+ }
+ }
+
+ /**
+ * Closes Windows registry key.
+ * Logs a warning if Windows registry is unavailable.
+ * @param key's Windows registry handle.
+ * @see #openKey(int)
+ * @see #openKey(byte[],int)
+ * @see #openKey(int, byte[],int)
+ */
+ private void closeKey(int nativeHandle) {
+ int result = WindowsRegCloseKey(nativeHandle);
+ if (result != ERROR_SUCCESS) {
+// logger().warning("Could not close windows "
+// + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+// " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+// ". Windows RegCloseKey(...) returned error code " + result + ".");
+ }
+ }
+
+ /**
+ * Implements AbstractPreferences putSpi() method.
+ * Puts name-value pair into the underlying Windows registry node.
+ * Logs a warning, if Windows registry is unavailable.
+ * @see #getSpi(String)
+ */
+ protected void putSpi(String javaName, String value) {
+ int nativeHandle = openKey(KEY_SET_VALUE);
+ if (nativeHandle == NULL_NATIVE_HANDLE) {
+ isBackingStoreAvailable = false;
+ return;
+ }
+ int result = WindowsRegSetValueEx1(nativeHandle,
+ toWindowsName(javaName), toWindowsValueString(value));
+ if (result != ERROR_SUCCESS) {
+// logger().warning("Could not assign value to key " +
+// byteArrayToString(toWindowsName(javaName))+ " at Windows registry node "
+// + byteArrayToString(windowsAbsolutePath()) + " at root 0x"
+// + Integer.toHexString(rootNativeHandle()) +
+// ". Windows RegSetValueEx(...) returned error code " + result + ".");
+ isBackingStoreAvailable = false;
+ }
+ closeKey(nativeHandle);
+ }
+
+ /**
+ * Implements AbstractPreferences getSpi() method.
+ * Gets a string value from the underlying Windows registry node.
+ * Logs a warning, if Windows registry is unavailable.
+ * @see #putSpi(String, String)
+ */
+ protected String getSpi(String javaName) {
+ int nativeHandle = openKey(KEY_QUERY_VALUE);
+ if (nativeHandle == NULL_NATIVE_HANDLE) {
+ return null;
+ }
+ Object resultObject = WindowsRegQueryValueEx(nativeHandle,
+ toWindowsName(javaName));
+ if (resultObject == null) {
+ closeKey(nativeHandle);
+ return null;
+ }
+ closeKey(nativeHandle);
+ return toJavaValueString((byte[]) resultObject);
+ }
+
+ /**
+ * Implements AbstractPreferences removeSpi() method.
+ * Deletes a string name-value pair from the underlying Windows registry
+ * node, if this value still exists.
+ * Logs a warning, if Windows registry is unavailable or key has already
+ * been deleted.
+ */
+ protected void removeSpi(String key) {
+ int nativeHandle = openKey(KEY_SET_VALUE);
+ if (nativeHandle == NULL_NATIVE_HANDLE) {
+ return;
+ }
+ int result =
+ WindowsRegDeleteValue(nativeHandle, toWindowsName(key));
+ if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
+// logger().warning("Could not delete windows registry "
+// + "value " + byteArrayToString(windowsAbsolutePath())+ "\\" +
+// toWindowsName(key) + " at root 0x" +
+// Integer.toHexString(rootNativeHandle()) +
+// ". Windows RegDeleteValue(...) returned error code " +
+// result + ".");
+ isBackingStoreAvailable = false;
+ }
+ closeKey(nativeHandle);
+ }
+
+ /**
+ * Implements AbstractPreferences keysSpi() method.
+ * Gets value names from the underlying Windows registry node.
+ * Throws a BackingStoreException and logs a warning, if
+ * Windows registry is unavailable.
+ */
+ protected String[] keysSpi() throws BackingStoreException {
+ // Find out the number of values
+ int nativeHandle = openKey(KEY_QUERY_VALUE);
+ if (nativeHandle == NULL_NATIVE_HANDLE) {
+ throw new BackingStoreException("Could not open windows"
+ + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) + ".");
+ }
+ int[] result = WindowsRegQueryInfoKey1(nativeHandle);
+ if (result[ERROR_CODE] != ERROR_SUCCESS) {
+ String info = "Could not query windows"
+ + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+ ". Windows RegQueryInfoKeyEx(...) returned error code " +
+ result[ERROR_CODE] + ".";
+// logger().warning(info);
+ throw new BackingStoreException(info);
+ }
+ int maxValueNameLength = result[MAX_VALUE_NAME_LENGTH];
+ int valuesNumber = result[VALUES_NUMBER];
+ if (valuesNumber == 0) {
+ closeKey(nativeHandle);
+ return new String[0];
+ }
+ // Get the values
+ String[] valueNames = new String[valuesNumber];
+ for (int i = 0; i < valuesNumber; i++) {
+ byte[] windowsName = WindowsRegEnumValue1(nativeHandle, i,
+ maxValueNameLength+1);
+ if (windowsName == null) {
+ String info =
+ "Could not enumerate value #" + i + " of windows node " +
+ byteArrayToString(windowsAbsolutePath()) + " at root 0x" +
+ Integer.toHexString(rootNativeHandle()) + ".";
+// logger().warning(info);
+ throw new BackingStoreException(info);
+ }
+ valueNames[i] = toJavaName(windowsName);
+ }
+ closeKey(nativeHandle);
+ return valueNames;
+ }
+
+ /**
+ * Implements AbstractPreferences childrenNamesSpi() method.
+ * Calls Windows registry to retrive children of this node.
+ * Throws a BackingStoreException and logs a warning message,
+ * if Windows registry is not available.
+ */
+ protected String[] childrenNamesSpi() throws BackingStoreException {
+ // Open key
+ int nativeHandle = openKey(KEY_ENUMERATE_SUB_KEYS| KEY_QUERY_VALUE);
+ if (nativeHandle == NULL_NATIVE_HANDLE) {
+ throw new BackingStoreException("Could not open windows"
+ + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) + ".");
+ }
+ // Get number of children
+ int[] result = WindowsRegQueryInfoKey1(nativeHandle);
+ if (result[ERROR_CODE] != ERROR_SUCCESS) {
+ String info = "Could not query windows"
+ + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+ ". Windows RegQueryInfoKeyEx(...) returned error code " +
+ result[ERROR_CODE] + ".";
+// logger().warning(info);
+ throw new BackingStoreException(info);
+ }
+ int maxKeyLength = result[MAX_KEY_LENGTH];
+ int subKeysNumber = result[SUBKEYS_NUMBER];
+ if (subKeysNumber == 0) {
+ closeKey(nativeHandle);
+ return new String[0];
+ }
+ String[] subkeys = new String[subKeysNumber];
+ String[] children = new String[subKeysNumber];
+ // Get children
+ for (int i = 0; i < subKeysNumber; i++) {
+ byte[] windowsName = WindowsRegEnumKeyEx1(nativeHandle, i,
+ maxKeyLength+1);
+ if (windowsName == null) {
+ String info =
+ "Could not enumerate key #" + i + " of windows node " +
+ byteArrayToString(windowsAbsolutePath()) + " at root 0x" +
+ Integer.toHexString(rootNativeHandle()) + ". ";
+// logger().warning(info);
+ throw new BackingStoreException(info);
+ }
+ String javaName = toJavaName(windowsName);
+ children[i] = javaName;
+ }
+ closeKey(nativeHandle);
+ return children;
+ }
+
+ /**
+ * Implements Preferences flush() method.
+ * Flushes Windows registry changes to disk.
+ * Throws a BackingStoreException and logs a warning message if Windows
+ * registry is not available.
+ */
+ public void flush() throws BackingStoreException{
+
+ if (isRemoved()) {
+ return;
+ }
+ if (!isBackingStoreAvailable) {
+ throw new BackingStoreException(
+ "flush(): Backing store not available.");
+ }
+ int nativeHandle = openKey(KEY_READ);
+ if (nativeHandle == NULL_NATIVE_HANDLE) {
+ throw new BackingStoreException("Could not open windows"
+ + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) + ".");
+ }
+ int result = WindowsRegFlushKey1(nativeHandle);
+ if (result != ERROR_SUCCESS) {
+ String info = "Could not flush windows "
+ + "registry node " + byteArrayToString(windowsAbsolutePath())
+ + " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+ ". Windows RegFlushKey(...) returned error code " + result + ".";
+// logger().warning(info);
+ throw new BackingStoreException(info);
+ }
+ closeKey(nativeHandle);
+ }
+
+
+ /**
+ * Implements Preferences sync() method.
+ * Flushes Windows registry changes to disk. Equivalent to flush().
+ * @see flush()
+ */
+ public void sync() throws BackingStoreException{
+ if (isRemoved())
+ throw new IllegalStateException("Node has been removed");
+ flush();
+ }
+
+ /**
+ * Implements AbstractPreferences childSpi() method.
+ * Constructs a child node with a
+ * given name and creates its underlying Windows registry node,
+ * if it does not exist.
+ * Logs a warning message, if Windows Registry is unavailable.
+ */
+ protected AbstractPreferences childSpi(String name) {
+ return new WindowsPreferences(this, name);
+ }
+
+ /**
+ * Implements AbstractPreferences removeNodeSpi() method.
+ * Deletes underlying Windows registry node.
+ * Throws a BackingStoreException and logs a warning, if Windows registry
+ * is not available.
+ */
+ public void removeNodeSpi() throws BackingStoreException {
+ int parentNativeHandle =
+ ((WindowsPreferences)parent()).openKey(DELETE);
+ if (parentNativeHandle == NULL_NATIVE_HANDLE) {
+ throw new BackingStoreException("Could not open parent windows"
+ + "registry node of " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) + ".");
+ }
+ int result =
+ WindowsRegDeleteKey(parentNativeHandle, toWindowsName(name()));
+ if (result != ERROR_SUCCESS) {
+ String info = "Could not delete windows "
+ + "registry node " + byteArrayToString(windowsAbsolutePath()) +
+ " at root 0x" + Integer.toHexString(rootNativeHandle()) +
+ ". Windows RegDeleteKeyEx(...) returned error code " +
+ result + ".";
+// logger().warning(info);
+ throw new BackingStoreException(info);
+ }
+ closeKey(parentNativeHandle);
+ }
+
+ /**
+ * Converts value's or node's name from its byte array representation to
+ * java string. Two encodings, simple and altBase64 are used. See
+ * {@link #toWindowsName(String) toWindowsName()} for a detailed
+ * description of encoding conventions.
+ * @param windowsNameArray Null-terminated byte array.
+ */
+ private static String toJavaName(byte[] windowsNameArray) {
+ String windowsName = byteArrayToString(windowsNameArray);
+ // check if Alt64
+ if ((windowsName.length()>1) &&
+ (windowsName.substring(0,2).equals("/!"))) {
+ return toJavaAlt64Name(windowsName);
+ }
+ StringBuffer javaName = new StringBuffer();
+ char ch;
+ // Decode from simple encoding
+ for (int i = 0; i < windowsName.length(); i++){
+ if ((ch = windowsName.charAt(i)) == '/') {
+ char next = ' ';
+ if ((windowsName.length() > i + 1) &&
+ ((next = windowsName.charAt(i+1)) >= 'A') && (next <= 'Z')) {
+ ch = next;
+ i++;
+ } else if ((windowsName.length() > i + 1) && (next == '/')) {
+ ch = '\\';
+ i++;
+ }
+ } else if (ch == '\\') {
+ ch = '/';
+ }
+ javaName.append(ch);
+ }
+ return javaName.toString();
+ }
+
+ /**
+ * Converts value's or node's name from its Windows representation to java
+ * string, using altBase64 encoding. See
+ * {@link #toWindowsName(String) toWindowsName()} for a detailed
+ * description of encoding conventions.
+ */
+
+ private static String toJavaAlt64Name(String windowsName) {
+ StringBuffer result = new StringBuffer();
+ return result.toString();
+ }
+
+ /**
+ * Converts value's or node's name to its Windows representation
+ * as a byte-encoded string.
+ * Two encodings, simple and altBase64 are used.
+ *
+ * Simple encoding is used, if java string does not contain
+ * any characters less, than 0x0020, or greater, than 0x007f.
+ * Simple encoding adds "/" character to capital letters, i.e.
+ * "A" is encoded as "/A". Character '\' is encoded as '//',
+ * '/' is encoded as '\'.
+ * The constructed string is converted to byte array by truncating the
+ * highest byte and adding the terminating null character.
+ *
+ * altBase64 encoding is used, if java string does contain at least
+ * one character less, than 0x0020, or greater, than 0x007f.
+ * This encoding is marked by setting first two bytes of the
+ * Windows string to '/!'. The java name is then encoded using
+ * byteArrayToAltBase64() method from
+ * Base64 class.
+ */
+ private static byte[] toWindowsName(String javaName) {
+ StringBuffer windowsName = new StringBuffer();
+ for (int i = 0; i < javaName.length(); i++) {
+ char ch =javaName.charAt(i);
+ if ((ch < 0x0020)||(ch > 0x007f)) {
+ // If a non-trivial character encountered, use altBase64
+ return toWindowsAlt64Name(javaName);
+ }
+ if (ch == '\\') {
+ windowsName.append("//");
+ } else if (ch == '/') {
+ windowsName.append('\\');
+ } else if ((ch >= 'A') && (ch <='Z')) {
+ windowsName.append("/" + ch);
+ } else {
+ windowsName.append(ch);
+ }
+ }
+ return stringToByteArray(windowsName.toString());
+ }
+
+ /**
+ * Converts value's or node's name to its Windows representation
+ * as a byte-encoded string, using altBase64 encoding. See
+ * {@link #toWindowsName(String) toWindowsName()} for a detailed
+ * description of encoding conventions.
+ */
+ private static byte[] toWindowsAlt64Name(String javaName) {
+ byte[] javaNameArray = new byte[2*javaName.length()];
+ // Convert to byte pairs
+ int counter = 0;
+ for (int i = 0; i < javaName.length();i++) {
+ int ch = javaName.charAt(i);
+ javaNameArray[counter++] = (byte)(ch >>> 8);
+ javaNameArray[counter++] = (byte)ch;
+ }
+
+ return javaNameArray;
+ }
+
+ /**
+ * Converts value string from its Windows representation
+ * to java string. See
+ * {@link #toWindowsValueString(String) toWindowsValueString()} for the
+ * description of the encoding algorithm.
+ */
+ private static String toJavaValueString(byte[] windowsNameArray) {
+ // Use modified native2ascii algorithm
+ String windowsName = byteArrayToString(windowsNameArray);
+ StringBuffer javaName = new StringBuffer();
+ char ch;
+ for (int i = 0; i < windowsName.length(); i++){
+ if ((ch = windowsName.charAt(i)) == '/') {
+ char next = ' ';
+
+ if (windowsName.length() > i + 1 &&
+ (next = windowsName.charAt(i + 1)) == 'u') {
+ if (windowsName.length() < i + 6){
+ break;
+ } else {
+ ch = (char)Integer.parseInt
+ (windowsName.substring(i + 2, i + 6), 16);
+ i += 5;
+ }
+ } else
+ if ((windowsName.length() > i + 1) &&
+ ((windowsName.charAt(i+1)) >= 'A') && (next <= 'Z')) {
+ ch = next;
+ i++;
+ } else if ((windowsName.length() > i + 1) &&
+ (next == '/')) {
+ ch = '\\';
+ i++;
+ }
+ } else if (ch == '\\') {
+ ch = '/';
+ }
+ javaName.append(ch);
+ }
+ return javaName.toString();
+ }
+
+ /**
+ * Converts value string to it Windows representation.
+ * as a byte-encoded string.
+ * Encoding algorithm adds "/" character to capital letters, i.e.
+ * "A" is encoded as "/A". Character '\' is encoded as '//',
+ * '/' is encoded as '\'.
+ * Then encoding scheme similar to jdk's native2ascii converter is used
+ * to convert java string to a byte array of ASCII characters.
+ */
+ private static byte[] toWindowsValueString(String javaName) {
+ StringBuffer windowsName = new StringBuffer();
+ for (int i = 0; i < javaName.length(); i++) {
+ char ch =javaName.charAt(i);
+ if ((ch < 0x0020)||(ch > 0x007f)){
+ // write \udddd
+ windowsName.append("/u");
+ String hex = Integer.toHexString(javaName.charAt(i));
+ StringBuffer hex4 = new StringBuffer(hex);
+ hex4.reverse();
+ int len = 4 - hex4.length();
+ for (int j = 0; j < len; j++){
+ hex4.append('0');
+ }
+ for (int j = 0; j < 4; j++){
+ windowsName.append(hex4.charAt(3 - j));
+ }
+ } else if (ch == '\\') {
+ windowsName.append("//");
+ } else if (ch == '/') {
+ windowsName.append('\\');
+ } else if ((ch >= 'A') && (ch <='Z')) {
+ windowsName.append("/" + ch);
+ } else {
+ windowsName.append(ch);
+ }
+ }
+ return stringToByteArray(windowsName.toString());
+ }
+
+ /**
+ * Returns native handle for the top Windows node for this node.
+ */
+ private int rootNativeHandle() {
+ return (isUserNode()? USER_ROOT_NATIVE_HANDLE :
+ SYSTEM_ROOT_NATIVE_HANDLE);
+ }
+
+ /**
+ * Returns this java string as a null-terminated byte array
+ */
+ private static byte[] stringToByteArray(String str) {
+ byte[] result = new byte[str.length()+1];
+ for (int i = 0; i < str.length(); i++) {
+ result[i] = (byte) str.charAt(i);
+ }
+ result[str.length()] = 0;
+ return result;
+ }
+
+ /**
+ * Converts a null-terminated byte array to java string
+ */
+ private static String byteArrayToString(byte[] array) {
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < array.length - 1; i++) {
+ result.append((char)array[i]);
+ }
+ return result.toString();
+ }
+
+ /**
+ * Empty, never used implementation of AbstractPreferences.flushSpi().
+ */
+ protected void flushSpi() throws BackingStoreException {
+ // assert false;
+ }
+
+ /**
+ * Empty, never used implementation of AbstractPreferences.flushSpi().
+ */
+ protected void syncSpi() throws BackingStoreException {
+ // assert false;
+ }
+
+ private static synchronized Logger logger() {
+ if (logger == null) {
+ logger = Logger.getLogger("org.parabot.logger");
+ }
+ logger.setLevel(Level.OFF);
+ return logger;
+ }
+}
\ No newline at end of file