2009-07-30 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / corlib / Microsoft.Win32 / UnixRegistryApi.cs
index ded84ed9bc7cf73c91d0675b21d519d7f7ad0f1f..39d5d2e3bbc2f638f93062c27802bfe20800b272 100644 (file)
@@ -1,16 +1,19 @@
 //
-// Microsoft.Win32/IRegistryApi.cs
+// Microsoft.Win32/UnixRegistryApi.cs
 //
 // Authors:
 //     Miguel de Icaza (miguel@gnome.org)
+//     Gert Driesen (drieseng@users.sourceforge.net)
 //
-// (C) 2005 Novell, Inc (http://www.novell.com)
+// (C) 2005, 2006 Novell, Inc (http://www.novell.com)
 // 
 // MISSING:
-//   Someone could the same subkey twice: once read/write once readonly,
-//   currently since we use a unique hash based on the file name, we are unable
-//   to have two versions of the same key and hence unable to throw an exception
-//   if the user tries to write to a read-only key.
+//   It would be useful if we do case-insensitive expansion of variables,
+//   the registry is very windows specific, so we probably should default to
+//   those semantics in expanding environment variables, for example %path%
+//
+//   We should use an ordered collection for storing the values (instead of
+//   a Hashtable).
 //
 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
 //
@@ -34,6 +37,8 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+#if !NET_2_1
+
 using System;
 using System.Collections;
 using System.Globalization;
@@ -46,23 +51,64 @@ using System.Threading;
 
 namespace Microsoft.Win32 {
 
-       class KeyHandler {
+       class ExpandString {
+               string value;
+               
+               public ExpandString (string s)
+               {
+                       value = s;
+               }
+
+               public override string ToString ()
+               {
+                       return value;
+               }
+
+               public string Expand ()
+               {
+                       StringBuilder sb = new StringBuilder ();
+
+                       for (int i = 0; i < value.Length; i++){
+                               if (value [i] == '%'){
+                                       int j = i + 1;
+                                       for (; j < value.Length; j++){
+                                               if (value [j] == '%'){
+                                                       string key = value.Substring (i + 1, j - i - 1);
+
+                                                       sb.Append (Environment.GetEnvironmentVariable (key));
+                                                       i += j;
+                                                       break;
+                                               }
+                                       }
+                                       if (j == value.Length){
+                                               sb.Append ('%');
+                                       }
+                               } else {
+                                       sb.Append (value [i]);
+                               }
+                       }
+                       return sb.ToString ();
+               }
+       }
+
+       class KeyHandler
+       {
                static Hashtable key_to_handler = new Hashtable ();
-               static Hashtable dir_to_key = new Hashtable ();
+               static Hashtable dir_to_handler = new Hashtable (
+                       new CaseInsensitiveHashCodeProvider (), new CaseInsensitiveComparer ());
                public string Dir;
-               public IntPtr Handle;
 
-               public Hashtable values;
+               Hashtable values;
                string file;
                bool dirty;
-               
+
                KeyHandler (RegistryKey rkey, string basedir)
                {
                        if (!Directory.Exists (basedir)){
                                try {
                                        Directory.CreateDirectory (basedir);
-                               } catch (Exception e){
-                                       Console.Error.WriteLine ("KeyHandler error while creating directory {0}:\n{1}", basedir, e);
+                               } catch (UnauthorizedAccessException){
+                                       throw new SecurityException ("No access to the given key");
                                }
                        }
                        Dir = basedir;
@@ -84,7 +130,7 @@ namespace Microsoft.Win32 {
                                                return;
                                        
                                        SecurityElement tree = SecurityElement.FromString (xml);
-                                       if (tree.Tag == "values"){
+                                       if (tree.Tag == "values" && tree.Children != null){
                                                foreach (SecurityElement value in tree.Children){
                                                        if (value.Tag == "value"){
                                                                LoadKey (value);
@@ -92,6 +138,9 @@ namespace Microsoft.Win32 {
                                                }
                                        }
                                }
+                       } catch (UnauthorizedAccessException){
+                               values.Clear ();
+                               throw new SecurityException ("No access to the given key");
                        } catch (Exception e){
                                Console.Error.WriteLine ("While loading registry key at {0}: {1}", file, e);
                                values.Clear ();
@@ -114,11 +163,17 @@ namespace Microsoft.Win32 {
                                        values [name] = Int32.Parse (se.Text);
                                        break;
                                case "bytearray":
-                                       Convert.FromBase64String (se.Text);
+                                       values [name] = Convert.FromBase64String (se.Text);
                                        break;
                                case "string":
                                        values [name] = se.Text;
                                        break;
+                               case "expand":
+                                       values [name] = new ExpandString (se.Text);
+                                       break;
+                               case "qword":
+                                       values [name] = Int64.Parse (se.Text);
+                                       break;
                                case "string-array":
                                        ArrayList sa = new ArrayList ();
                                        if (se.Children != null){
@@ -134,35 +189,39 @@ namespace Microsoft.Win32 {
                        }
                }
                
-               public RegistryKey Ensure (RegistryKey rkey, string extra)
+               public RegistryKey Ensure (RegistryKey rkey, string extra, bool writable)
                {
                        lock (typeof (KeyHandler)){
                                string f = Path.Combine (Dir, extra);
-                               if (dir_to_key.Contains (f))
-                                       return (RegistryKey) dir_to_key [f];
-
-                               KeyHandler kh = new KeyHandler (rkey, f);
-                               RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
+                               KeyHandler kh = (KeyHandler) dir_to_handler [f];
+                               if (kh == null)
+                                       kh = new KeyHandler (rkey, f);
+                               RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra), writable);
                                key_to_handler [rk] = kh;
-                               dir_to_key [f] = rk;
+                               dir_to_handler [f] = kh;
                                return rk;
                        }
                }
 
-               public RegistryKey Probe (RegistryKey rkey, string extra, bool write)
+               public RegistryKey Probe (RegistryKey rkey, string extra, bool writable)
                {
+                       RegistryKey rk = null;
+
                        lock (typeof (KeyHandler)){
                                string f = Path.Combine (Dir, extra);
-                               if (dir_to_key.Contains (f))
-                                       return (RegistryKey) dir_to_key [f];
-                               if (Directory.Exists (f)){
-                                       KeyHandler kh = new KeyHandler (rkey, f);
-                                       RegistryKey rk = new RegistryKey (kh, CombineName (rkey, extra));
-                                       dir_to_key [f] = rk;
+                               KeyHandler kh = (KeyHandler) dir_to_handler [f];
+                               if (kh != null) {
+                                       rk = new RegistryKey (kh, CombineName (rkey,
+                                               extra), writable);
+                                       key_to_handler [rk] = kh;
+                               } else if (Directory.Exists (f)) {
+                                       kh = new KeyHandler (rkey, f);
+                                       rk = new RegistryKey (kh, CombineName (rkey, extra),
+                                               writable);
+                                       dir_to_handler [f] = kh;
                                        key_to_handler [rk] = kh;
-                                       return rk;
                                }
-                               return null;
+                               return rk;
                        }
                }
 
@@ -174,27 +233,34 @@ namespace Microsoft.Win32 {
                        return String.Concat (rkey.Name, "\\", extra);
                }
                
-               public static KeyHandler Lookup (RegistryKey rkey)
+               public static KeyHandler Lookup (RegistryKey rkey, bool createNonExisting)
                {
                        lock (typeof (KeyHandler)){
                                KeyHandler k = (KeyHandler) key_to_handler [rkey];
                                if (k != null)
                                        return k;
 
-                               RegistryHive x = (RegistryHive) rkey.Data;
+                               // when a non-root key is requested for no keyhandler exist
+                               // then that key must have been marked for deletion
+                               if (!rkey.IsRoot || !createNonExisting)
+                                       return null;
+
+                               RegistryHive x = (RegistryHive) rkey.Hive;
                                switch (x){
-                               case RegistryHive.ClassesRoot:
-                               case RegistryHive.CurrentConfig:
                                case RegistryHive.CurrentUser:
+                                       string userDir = Path.Combine (UserStore, x.ToString ());
+                                       k = new KeyHandler (rkey, userDir);
+                                       dir_to_handler [userDir] = k;
+                                       break;
+                               case RegistryHive.CurrentConfig:
+                               case RegistryHive.ClassesRoot:
                                case RegistryHive.DynData:
                                case RegistryHive.LocalMachine:
                                case RegistryHive.PerformanceData:
                                case RegistryHive.Users:
-                                       string d = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), ".mono/registry");
-                                       d = Path.Combine (d, x.ToString ());
-                                       
-                                       k = new KeyHandler (rkey, d);
-                                       key_to_handler [rkey] = k;
+                                       string machine_dir = Path.Combine (MachineStore, x.ToString ());
+                                       k = new KeyHandler (rkey, machine_dir);
+                                       dir_to_handler [machine_dir] = k;
                                        break;
                                default:
                                        throw new Exception ("Unknown RegistryHive");
@@ -206,27 +272,155 @@ namespace Microsoft.Win32 {
 
                public static void Drop (RegistryKey rkey)
                {
-                       KeyHandler k = (KeyHandler) key_to_handler [rkey];
-                       if (k == null)
-                               return;
-                       dir_to_key.Remove (k.Dir);
-                       key_to_handler.Remove (rkey);
+                       lock (typeof (KeyHandler)) {
+                               KeyHandler k = (KeyHandler) key_to_handler [rkey];
+                               if (k == null)
+                                       return;
+                               key_to_handler.Remove (rkey);
+
+                               // remove cached KeyHandler if no other keys reference it
+                               int refCount = 0;
+                               foreach (DictionaryEntry de in key_to_handler)
+                                       if (de.Value == k)
+                                               refCount++;
+                               if (refCount == 0)
+                                       dir_to_handler.Remove (k.Dir);
+                       }
                }
 
                public static void Drop (string dir)
                {
-                       if (dir_to_key.Contains (dir)){
-                               key_to_handler.Remove (dir_to_key [dir]); 
-                               dir_to_key.Remove (dir);
+                       lock (typeof (KeyHandler)) {
+                               KeyHandler kh = (KeyHandler) dir_to_handler [dir];
+                               if (kh == null)
+                                       return;
+
+                               dir_to_handler.Remove (dir);
+
+                               // remove (other) references to keyhandler
+                               ArrayList keys = new ArrayList ();
+                               foreach (DictionaryEntry de in key_to_handler)
+                                       if (de.Value == kh)
+                                               keys.Add (de.Key);
+
+                               foreach (object key in keys)
+                                       key_to_handler.Remove (key);
                        }
                }
 
+               public object GetValue (string name, RegistryValueOptions options)
+               {
+                       if (IsMarkedForDeletion)
+                               return null;
+
+                       if (name == null)
+                               name = string.Empty;
+                       object value = values [name];
+                       ExpandString exp = value as ExpandString;
+                       if (exp == null)
+                               return value;
+                       if ((options & RegistryValueOptions.DoNotExpandEnvironmentNames) == 0)
+                               return exp.Expand ();
+
+                       return exp.ToString ();
+               }
+
                public void SetValue (string name, object value)
                {
-                       values [name] = value;
+                       AssertNotMarkedForDeletion ();
+
+                       if (name == null)
+                               name = string.Empty;
+
+                       // immediately convert non-native registry values to string to avoid
+                       // returning it unmodified in calls to UnixRegistryApi.GetValue
+                       if (value is int || value is string || value is byte[] || value is string[])
+                               values[name] = value;
+                       else
+                               values[name] = value.ToString ();
                        SetDirty ();
                }
 
+               public string [] GetValueNames ()
+               {
+                       AssertNotMarkedForDeletion ();
+
+                       ICollection keys = values.Keys;
+
+                       string [] vals = new string [keys.Count];
+                       keys.CopyTo (vals, 0);
+                       return vals;
+               }
+
+#if NET_2_0
+               //
+               // This version has to do argument validation based on the valueKind
+               //
+               public void SetValue (string name, object value, RegistryValueKind valueKind)
+               {
+                       SetDirty ();
+
+                       if (name == null)
+                               name = string.Empty;
+
+                       switch (valueKind){
+                       case RegistryValueKind.String:
+                               if (value is string){
+                                       values [name] = value;
+                                       return;
+                               }
+                               break;
+                       case RegistryValueKind.ExpandString:
+                               if (value is string){
+                                       values [name] = new ExpandString ((string)value);
+                                       return;
+                               }
+                               break;
+                               
+                       case RegistryValueKind.Binary:
+                               if (value is byte []){
+                                       values [name] = value;
+                                       return;
+                               }
+                               break;
+                               
+                       case RegistryValueKind.DWord:
+                               if (value is long &&
+                                   (((long) value) < Int32.MaxValue) &&
+                                   (((long) value) > Int32.MinValue)){
+                                       values [name] = (int) ((long)value);
+                                       return;
+                               }
+                               if (value is int){
+                                       values [name] = value;
+                                       return;
+                               }
+                               break;
+                               
+                       case RegistryValueKind.MultiString:
+                               if (value is string []){
+                                       values [name] = value;
+                                       return;
+                               }
+                               break;
+                               
+                       case RegistryValueKind.QWord:
+                               if (value is int){
+                                       values [name] = (long) ((int) value);
+                                       return;
+                               }
+                               if (value is long){
+                                       values [name] = value;
+                                       return;
+                               }
+                               break;
+                       default:
+                               throw new ArgumentException ("unknown value", "valueKind");
+                       }
+                       throw new ArgumentException ("Value could not be converted to specified type", "valueKind");
+               }
+#endif
+
                void SetDirty ()
                {
                        lock (typeof (KeyHandler)){
@@ -241,15 +435,45 @@ namespace Microsoft.Win32 {
                {
                        Flush ();
                }
-               
+
                public void Flush ()
                {
-                       lock (typeof (KeyHandler)){
-                               dirty = false;
-                               Save ();
+                       lock (typeof (KeyHandler)) {
+                               if (dirty) {
+                                       Save ();
+                                       dirty = false;
+                               }
                        }
                }
 
+               public bool ValueExists (string name)
+               {
+                       if (name == null)
+                               name = string.Empty;
+
+                       return values.Contains (name);
+               }
+
+               public int ValueCount {
+                       get {
+                               return values.Keys.Count;
+                       }
+               }
+
+               public bool IsMarkedForDeletion {
+                       get {
+                               return !dir_to_handler.Contains (Dir);
+                       }
+               }
+
+               public void RemoveValue (string name)
+               {
+                       AssertNotMarkedForDeletion ();
+
+                       values.Remove (name);
+                       SetDirty ();
+               }
+
                ~KeyHandler ()
                {
                        Flush ();
@@ -257,46 +481,79 @@ namespace Microsoft.Win32 {
                
                void Save ()
                {
+                       if (IsMarkedForDeletion)
+                               return;
+
                        if (!File.Exists (file) && values.Count == 0)
                                return;
-                       
+
                        SecurityElement se = new SecurityElement ("values");
                        
+                       // With SecurityElement.Text = value, and SecurityElement.AddAttribute(key, value)
+                       // the values must be escaped prior to being assigned. 
                        foreach (DictionaryEntry de in values){
                                object val = de.Value;
                                SecurityElement value = new SecurityElement ("value");
-                               value.AddAttribute ("name", (string) de.Key);
+                               value.AddAttribute ("name", SecurityElement.Escape ((string) de.Key));
                                
                                if (val is string){
                                        value.AddAttribute ("type", "string");
-                                       value.Text = (string) val;
+                                       value.Text = SecurityElement.Escape ((string) val);
                                } else if (val is int){
                                        value.AddAttribute ("type", "int");
                                        value.Text = val.ToString ();
+                               } else if (val is long) {
+                                       value.AddAttribute ("type", "qword");
+                                       value.Text = val.ToString ();
                                } else if (val is byte []){
                                        value.AddAttribute ("type", "bytearray");
                                        value.Text = Convert.ToBase64String ((byte[]) val);
+                               } else if (val is ExpandString){
+                                       value.AddAttribute ("type", "expand");
+                                       value.Text = SecurityElement.Escape (val.ToString ());
                                } else if (val is string []){
                                        value.AddAttribute ("type", "string-array");
 
                                        foreach (string ss in (string[]) val){
                                                SecurityElement str = new SecurityElement ("string");
-                                               str.Text = ss
+                                               str.Text = SecurityElement.Escape (ss)
                                                value.AddChild (str);
                                        }
                                }
                                se.AddChild (value);
                        }
 
-                       try {
-                               using (FileStream fs = File.Create (file)){
-                                       StreamWriter sw = new StreamWriter (fs);
+                       using (FileStream fs = File.Create (file)){
+                               StreamWriter sw = new StreamWriter (fs);
 
-                                       sw.Write (se.ToString ());
-                                       sw.Flush ();
-                               }
-                       } catch (Exception e){
-                               Console.Error.WriteLine ("When saving {0} got {1}", file, e);
+                               sw.Write (se.ToString ());
+                               sw.Flush ();
+                       }
+               }
+
+               private void AssertNotMarkedForDeletion ()
+               {
+                       if (IsMarkedForDeletion)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+               }
+
+               private static string UserStore {
+                       get {
+                               return Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal),
+                                       ".mono/registry");
+                       }
+               }
+
+               private static string MachineStore {
+                       get {
+                               string s;
+
+                               s = Environment.GetEnvironmentVariable ("MONO_REGISTRY_PATH");
+                               if (s != null)
+                                       return s;
+                               s = Environment.GetMachineConfigPath ();
+                               int p = s.IndexOf ("machine.config");
+                               return Path.Combine (Path.Combine (s.Substring (0, p-1), ".."), "registry");
                        }
                }
        }
@@ -310,24 +567,38 @@ namespace Microsoft.Win32 {
                        return keyname.ToLower ();
                }
 
-               static bool IsWellKnownKey (string keyname)
+               static bool IsWellKnownKey (string parentKeyName, string keyname)
                {
                        // FIXME: Add more keys if needed
-                       return (0 == String.Compare ("software", keyname, true, CultureInfo.InvariantCulture));
+                       if (parentKeyName == Registry.CurrentUser.Name ||
+                               parentKeyName == Registry.LocalMachine.Name)
+                               return (0 == String.Compare ("software", keyname, true, CultureInfo.InvariantCulture));
+
+                       return false;
                }
 
                public RegistryKey CreateSubKey (RegistryKey rkey, string keyname)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       return self.Ensure (rkey, ToUnix (keyname));
+                       return CreateSubKey (rkey, keyname, true);
+               }
+
+               public RegistryKey OpenRemoteBaseKey (RegistryHive hKey, string machineName)
+               {
+                       throw new NotImplementedException ();
                }
 
-               public RegistryKey OpenSubKey (RegistryKey rkey, string keyname, bool writtable)
+               public RegistryKey OpenSubKey (RegistryKey rkey, string keyname, bool writable)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       RegistryKey result = self.Probe (rkey, ToUnix (keyname), writtable);
-                       if (result == null && IsWellKnownKey (keyname)) {
-                               result = CreateSubKey (rkey, keyname);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // return null if parent is marked for deletion
+                               return null;
+                       }
+
+                       RegistryKey result = self.Probe (rkey, ToUnix (keyname), writable);
+                       if (result == null && IsWellKnownKey (rkey.Name, keyname)) {
+                               // create the subkey even if its parent was opened read-only
+                               result = CreateSubKey (rkey, keyname, writable);
                        }
 
                        return result;
@@ -335,7 +606,11 @@ namespace Microsoft.Win32 {
                
                public void Flush (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, false);
+                       if (self == null) {
+                               // we do not need to flush changes as key is marked for deletion
+                               return;
+                       }
                        self.Flush ();
                }
                
@@ -343,86 +618,123 @@ namespace Microsoft.Win32 {
                {
                        KeyHandler.Drop (rkey);
                }
-               
-               public object GetValue (RegistryKey rkey, string name, bool return_default_value, object default_value)
-               {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
 
-                       if (self.values.Contains (name))
-                               return self.values [name];
-                       if (return_default_value)
+               public object GetValue (RegistryKey rkey, string name, object default_value, RegistryValueOptions options)
+               {
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // key was removed since it was opened
                                return default_value;
-                       return null;
+                       }
+
+                       if (self.ValueExists (name))
+                               return self.GetValue (name, options);
+                       return default_value;
                }
                
                public void SetValue (RegistryKey rkey, string name, object value)
                {
-                       if (!((value is int) || (value is string) || (value is string []) || (value is byte [])))
-                               throw new ArgumentException ("The value is not int, string, string[] or byte[]", "value");
-                       
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
                        self.SetValue (name, value);
                }
 
-               public int SubKeyCount (RegistryKey rkey)
+#if NET_2_0
+               public void SetValue (RegistryKey rkey, string name, object value, RegistryValueKind valueKind)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+                       self.SetValue (name, value, valueKind);
+               }
+#endif
 
+               public int SubKeyCount (RegistryKey rkey)
+               {
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
                        return Directory.GetDirectories (self.Dir).Length;
                }
                
                public int ValueCount (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-
-                       return self.values.Keys.Count;
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+                       return self.ValueCount;
                }
                
-               public void DeleteValue (RegistryKey rkey, string value, bool throw_if_missing)
+               public void DeleteValue (RegistryKey rkey, string name, bool throw_if_missing)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-
-                       foreach (DictionaryEntry de in self.values){
-                               if ((string)de.Value == value){
-                                       self.values.Remove (de.Key);
-                                       return;
-                               }
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // if key is marked for deletion, report success regardless of
+                               // throw_if_missing
+                               return;
                        }
-                       if (throw_if_missing)
-                               throw new ArgumentException ("the given value does not exist", "value");
+
+                       if (throw_if_missing && !self.ValueExists (name))
+                               throw new ArgumentException ("the given value does not exist");
+
+                       self.RemoveValue (name);
                }
                
                public void DeleteKey (RegistryKey rkey, string keyname, bool throw_if_missing)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       string dir = Path.Combine (self.Dir, keyname);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null) {
+                               // key is marked for deletion
+                               if (!throw_if_missing)
+                                       return;
+                               throw new ArgumentException ("the given value does not exist");
+                       }
+
+                       string dir = Path.Combine (self.Dir, ToUnix (keyname));
                        
                        if (Directory.Exists (dir)){
                                Directory.Delete (dir, true);
                                KeyHandler.Drop (dir);
                        } else if (throw_if_missing)
-                               throw new ArgumentException ("the given value does not exist", "value");
+                               throw new ArgumentException ("the given value does not exist");
                }
                
                public string [] GetSubKeyNames (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       return Directory.GetDirectories (self.Dir);
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       DirectoryInfo selfDir = new DirectoryInfo (self.Dir);
+                       DirectoryInfo[] subDirs = selfDir.GetDirectories ();
+                       string[] subKeyNames = new string[subDirs.Length];
+                       for (int i = 0; i < subDirs.Length; i++) {
+                               DirectoryInfo subDir = subDirs[i];
+                               subKeyNames[i] = subDir.Name;
+                       }
+                       return subKeyNames;
                }
                
                public string [] GetValueNames (RegistryKey rkey)
                {
-                       KeyHandler self = KeyHandler.Lookup (rkey);
-                       ICollection keys = self.values.Keys;
-
-                       string [] vals = new string [keys.Count];
-                       keys.CopyTo (vals, 0);
-                       return vals;
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+                       return self.GetValueNames ();
                }
 
                public string ToString (RegistryKey rkey)
                {
                        return rkey.Name;
                }
+
+               private RegistryKey CreateSubKey (RegistryKey rkey, string keyname, bool writable)
+               {
+                       KeyHandler self = KeyHandler.Lookup (rkey, true);
+                       if (self == null)
+                               throw RegistryKey.CreateMarkedForDeletionException ();
+                       return self.Ensure (rkey, ToUnix (keyname), writable);
+               }
        }
 }
+
+#endif // NET_2_1
+