1 /* fhandler_registry.cc: fhandler for /proc/registry virtual filesystem
3 Copyright 2002, 2003, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 /* FIXME: Access permissions are ignored at the moment. */
23 #define _COMPILING_NEWLIB
26 /* If this bit is set in __d_position then we are enumerating values,
27 * else sub-keys. keeping track of where we are is horribly messy
28 * the bottom 16 bits are the absolute position and the top 15 bits
29 * make up the value index if we are enuerating values.
31 static const _off_t REG_ENUM_VALUES_MASK
= 0x8000000;
32 static const _off_t REG_POSITION_MASK
= 0xffff;
34 /* List of root keys in /proc/registry.
35 * Possibly we should filter out those not relevant to the flavour of Windows
36 * Cygwin is running on.
38 static const char *registry_listing
[] =
43 "HKEY_CURRENT_CONFIG",
47 "HKEY_PERFORMANCE_DATA", // NT/2000/XP
51 static const HKEY registry_keys
[] =
53 (HKEY
) INVALID_HANDLE_VALUE
,
54 (HKEY
) INVALID_HANDLE_VALUE
,
63 static const int ROOT_KEY_COUNT
= sizeof (registry_keys
) / sizeof (HKEY
);
65 /* These get added to each subdirectory in /proc/registry.
66 * If we wanted to implement writing, we could maybe add a '.writable' entry or
69 static const char *special_dot_files
[] =
76 static const int SPECIAL_DOT_FILE_COUNT
=
77 (sizeof (special_dot_files
) / sizeof (const char *)) - 1;
79 /* Value names for HKEY_PERFORMANCE_DATA.
81 * CAUTION: Never call RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Add", ...).
82 * It WRITES data and may destroy the perfc009.dat file. Same applies to
83 * name prefixes "Ad" and "A".
85 static const char * const perf_data_files
[] =
92 static const int PERF_DATA_FILE_COUNT
=
93 sizeof (perf_data_files
) / sizeof (perf_data_files
[0]);
95 static HKEY
open_key (const char *name
, REGSAM access
, DWORD wow64
, bool isValue
);
97 /* Return true if char must be encoded.
100 must_encode (wchar_t c
)
102 return (iswdirsep (c
) || c
== L
':' || c
== L
'%');
105 /* Encode special chars in registry key or value name.
106 * Returns 0: success, -1: error.
109 encode_regname (char *dst
, const wchar_t *src
, bool add_val
)
113 dst
[di
++] = '@'; // Default value.
115 for (int si
= 0; src
[si
]; si
++)
118 if (must_encode (c
) ||
119 (si
== 0 && ((c
== L
'.'
120 && (!src
[1] || (src
[1] == L
'.' && !src
[2])))
121 || (c
== L
'@' && !src
[1]))))
123 if (di
+ 3 >= NAME_MAX
+ 1)
125 __small_sprintf (dst
+ di
, "%%%02x", c
);
129 di
+= sys_wcstombs (dst
+ di
, NAME_MAX
+ 1 - di
, &c
, 1);
134 if (di
+ 4 >= NAME_MAX
+ 1)
136 memcpy (dst
+ di
, "%val", 4);
144 /* Decode special chars in registry key or value name.
145 * Returns 0: success, 1: "%val" detected, -1: error.
148 decode_regname (wchar_t *wdst
, const char *src
, int len
= -1)
155 if (len
> 4 && !memcmp (src
+ len
- 4, "%val", 4))
162 if (len
== 1 && src
[0] == '@')
165 for (int si
= 0; si
< len
; si
++)
172 char s
[] = {src
[si
+1], src
[si
+2], '\0'};
174 c
= strtoul (s
, &p
, 16);
175 if (!(must_encode ((wchar_t) c
) ||
176 (si
== 0 && ((c
== '.' && (len
== 3 || (src
[3] == '.' && len
== 4))) ||
177 (c
== '@' && len
== 3)))))
187 sys_mbstowcs (wdst
, NAME_MAX
+ 1, dst
);
192 /* Hash table to limit calls to key_exists ().
199 memset (table
, 0, sizeof(table
));
202 void set (unsigned h
)
204 table
[(h
>> 3) & (HASH_SIZE
- 1)] |= (1 << (h
& 0x3));
207 bool is_set (unsigned h
) const
209 return (table
[(h
>> 3) & (HASH_SIZE
- 1)] & (1 << (h
& 0x3))) != 0;
213 enum { HASH_SIZE
= 1024 };
214 unsigned char table
[HASH_SIZE
];
217 #define d_hash(d) ((__DIR_hash *) (d)->__d_internal)
220 /* Return true if subkey NAME exists in key PARENT.
223 key_exists (HKEY parent
, const wchar_t *name
, DWORD wow64
)
225 HKEY hKey
= (HKEY
) INVALID_HANDLE_VALUE
;
226 LONG error
= RegOpenKeyExW (parent
, name
, 0, KEY_READ
| wow64
, &hKey
);
227 if (error
== ERROR_SUCCESS
)
230 return (error
== ERROR_SUCCESS
|| error
== ERROR_ACCESS_DENIED
);
233 /* Returns 0 if path doesn't exist, >0 if path is a directory,
234 * <0 if path is a file.
236 * We open the last key but one and then enum it's sub-keys and values to see if the
237 * final component is there. This gets round the problem of not having security access
238 * to the final key in the path.
241 fhandler_registry::exists ()
243 int file_type
= 0, index
= 0, pathlen
;
244 DWORD buf_size
= NAME_MAX
+ 1;
246 wchar_t buf
[buf_size
];
248 HKEY hKey
= (HKEY
) INVALID_HANDLE_VALUE
;
250 const char *path
= get_name ();
251 debug_printf ("exists (%s)", path
);
252 path
+= proc_len
+ prefix_len
+ 1;
260 pathlen
= strlen (path
);
261 file
= path
+ pathlen
- 1;
262 if (isdirsep (*file
) && pathlen
> 1)
264 while (!isdirsep (*file
))
270 for (int i
= 0; registry_listing
[i
]; i
++)
271 if (path_prefix_p (registry_listing
[i
], path
,
272 strlen (registry_listing
[i
]), true))
280 wchar_t dec_file
[NAME_MAX
+ 1];
282 int val_only
= decode_regname (dec_file
, file
);
287 hKey
= open_key (path
, KEY_READ
, wow64
, false);
288 if (hKey
!= (HKEY
) INVALID_HANDLE_VALUE
|| get_errno () == EACCES
)
292 hKey
= open_key (path
, KEY_READ
, wow64
, true);
293 if (hKey
== (HKEY
) INVALID_HANDLE_VALUE
)
296 if (hKey
== HKEY_PERFORMANCE_DATA
)
298 /* RegEnumValue () returns garbage for this key.
299 RegQueryValueEx () returns a PERF_DATA_BLOCK even
300 if a value does not contain any counter objects.
301 So allow access to the generic names and to
302 (blank separated) lists of counter numbers.
303 Never allow access to "Add", see above comment. */
304 for (int i
= 0; i
< PERF_DATA_FILE_COUNT
&& file_type
== 0; i
++)
306 if (strcasematch (perf_data_files
[i
], file
))
309 if (file_type
== 0 && !file
[strspn (file
, " 0123456789")])
314 if (!val_only
&& dec_file
[0])
316 while (ERROR_SUCCESS
==
317 (error
= RegEnumKeyExW (hKey
, index
++, buf
, &buf_size
,
318 NULL
, NULL
, NULL
, NULL
))
319 || (error
== ERROR_MORE_DATA
))
321 if (!wcscasecmp (buf
, dec_file
))
326 buf_size
= NAME_MAX
+ 1;
328 if (error
!= ERROR_NO_MORE_ITEMS
)
330 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
334 buf_size
= NAME_MAX
+ 1;
337 while (ERROR_SUCCESS
==
338 (error
= RegEnumValueW (hKey
, index
++, buf
, &buf_size
,
339 NULL
, NULL
, NULL
, NULL
))
340 || (error
== ERROR_MORE_DATA
))
342 if (!wcscasecmp (buf
, dec_file
))
347 buf_size
= NAME_MAX
+ 1;
349 if (error
!= ERROR_NO_MORE_ITEMS
)
351 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
357 if (hKey
!= (HKEY
) INVALID_HANDLE_VALUE
)
363 fhandler_registry::set_name (path_conv
&in_pc
)
365 if (strncasematch (in_pc
.normalized_path
, "/proc/registry32", 16))
367 wow64
= KEY_WOW64_32KEY
;
370 else if (strncasematch (in_pc
.normalized_path
, "/proc/registry64", 16))
372 wow64
= KEY_WOW64_64KEY
;
375 fhandler_base::set_name (in_pc
);
378 fhandler_registry::fhandler_registry ():
382 prefix_len
= sizeof ("registry") - 1;
386 fhandler_registry::fstat (struct __stat64
*buf
)
388 fhandler_base::fstat (buf
);
389 buf
->st_mode
&= ~_IFMT
& NO_W
;
390 int file_type
= exists ();
397 buf
->st_mode
|= S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
400 buf
->st_mode
|= S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
401 buf
->st_nlink
= ROOT_KEY_COUNT
;
405 buf
->st_mode
|= S_IFREG
;
406 buf
->st_mode
&= NO_X
;
409 if (file_type
!= 0 && file_type
!= 2)
412 const char *path
= get_name () + proc_len
+ prefix_len
+ 2;
414 open_key (path
, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
, wow64
,
415 (file_type
< 0) ? true : false);
417 if (hKey
== HKEY_PERFORMANCE_DATA
)
418 /* RegQueryInfoKey () always returns write time 0,
419 RegQueryValueEx () does not return required buffer size. */
421 else if (hKey
!= (HKEY
) INVALID_HANDLE_VALUE
)
423 FILETIME ftLastWriteTime
;
426 RegQueryInfoKey (hKey
, NULL
, NULL
, NULL
, &subkey_count
, NULL
,
427 NULL
, NULL
, NULL
, NULL
, NULL
,
430 to_timestruc_t (&ftLastWriteTime
, &buf
->st_mtim
);
431 buf
->st_ctim
= buf
->st_birthtim
= buf
->st_mtim
;
432 time_as_timestruc_t (&buf
->st_atim
);
434 buf
->st_nlink
= subkey_count
+ 2;
437 int pathlen
= strlen (path
);
438 const char *value_name
= path
+ pathlen
- 1;
439 if (isdirsep (*value_name
) && pathlen
> 1)
441 while (!isdirsep (*value_name
))
444 wchar_t dec_value_name
[NAME_MAX
+ 1];
447 if (decode_regname (dec_value_name
, value_name
) >= 0
448 && RegQueryValueExW (hKey
, dec_value_name
, NULL
, &type
,
449 NULL
, &dwSize
) == ERROR_SUCCESS
450 && (type
== REG_SZ
|| type
== REG_EXPAND_SZ
451 || type
== REG_MULTI_SZ
|| type
== REG_LINK
))
453 PBYTE tmpbuf
= (PBYTE
) malloc (dwSize
);
455 || RegQueryValueExW (hKey
, dec_value_name
,
456 NULL
, NULL
, tmpbuf
, &dwSize
)
458 buf
->st_size
= dwSize
/ sizeof (wchar_t);
460 buf
->st_size
= sys_wcstombs (NULL
, 0,
462 dwSize
/ sizeof (wchar_t));
466 buf
->st_size
= dwSize
;
470 if (get_reg_attribute (hKey
, &buf
->st_mode
, &uid
, &gid
) == 0)
474 buf
->st_mode
&= ~(S_IWUSR
| S_IWGRP
| S_IWOTH
);
476 buf
->st_mode
|= S_IFDIR
;
478 buf
->st_mode
&= NO_X
;
485 /* Here's the problem: If we can't open the key, we don't know
486 nothing at all about the key/value. It's only clear that
487 the current user has no read access. At this point it's
488 rather unlikely that the user has write or execute access
489 and it's also rather unlikely that the user is the owner.
490 Therefore it's probably most safe to assume unknown ownership
491 and no permissions for nobody. */
492 buf
->st_uid
= UNKNOWN_UID
;
493 buf
->st_gid
= UNKNOWN_GID
;
494 buf
->st_mode
&= ~0777;
501 fhandler_registry::readdir (DIR *dir
, dirent
*de
)
503 DWORD buf_size
= NAME_MAX
+ 1;
504 wchar_t buf
[buf_size
];
506 const char *path
= dir
->__d_dirname
+ proc_len
+ 1 + prefix_len
;
510 dir
->__flags
|= dirent_saw_dot
| dirent_saw_dot_dot
;
513 if (dir
->__d_position
>= ROOT_KEY_COUNT
)
515 strcpy (de
->d_name
, registry_listing
[dir
->__d_position
++]);
519 if (dir
->__handle
== INVALID_HANDLE_VALUE
)
521 if (dir
->__d_position
!= 0)
523 handle
= open_key (path
+ 1, KEY_READ
, wow64
, false);
524 dir
->__handle
= handle
;
525 if (dir
->__handle
== INVALID_HANDLE_VALUE
)
527 dir
->__d_internal
= (unsigned) new __DIR_hash ();
529 if (dir
->__d_position
< SPECIAL_DOT_FILE_COUNT
)
531 strcpy (de
->d_name
, special_dot_files
[dir
->__d_position
++]);
535 if ((HKEY
) dir
->__handle
== HKEY_PERFORMANCE_DATA
)
537 /* RegEnumValue () returns garbage for this key,
538 simulate only a minimal listing of the generic names. */
539 if (dir
->__d_position
>= SPECIAL_DOT_FILE_COUNT
+ PERF_DATA_FILE_COUNT
)
541 strcpy (de
->d_name
, perf_data_files
[dir
->__d_position
- SPECIAL_DOT_FILE_COUNT
]);
548 if (dir
->__d_position
& REG_ENUM_VALUES_MASK
)
549 /* For the moment, the type of key is ignored here. when write access is added,
550 * maybe add an extension for the type of each value?
552 error
= RegEnumValueW ((HKEY
) dir
->__handle
,
553 (dir
->__d_position
& ~REG_ENUM_VALUES_MASK
) >> 16,
554 buf
, &buf_size
, NULL
, NULL
, NULL
, NULL
);
557 RegEnumKeyExW ((HKEY
) dir
->__handle
, dir
->__d_position
-
558 SPECIAL_DOT_FILE_COUNT
, buf
, &buf_size
,
559 NULL
, NULL
, NULL
, NULL
);
560 if (error
== ERROR_NO_MORE_ITEMS
561 && (dir
->__d_position
& REG_ENUM_VALUES_MASK
) == 0)
563 /* If we're finished with sub-keys, start on values under this key. */
564 dir
->__d_position
|= REG_ENUM_VALUES_MASK
;
565 buf_size
= NAME_MAX
+ 1;
568 if (error
!= ERROR_SUCCESS
&& error
!= ERROR_MORE_DATA
)
570 RegCloseKey ((HKEY
) dir
->__handle
);
571 dir
->__handle
= INVALID_HANDLE_VALUE
;
572 if (error
!= ERROR_NO_MORE_ITEMS
)
573 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
577 /* We get here if `buf' contains valid data. */
579 if (dir
->__d_position
& REG_ENUM_VALUES_MASK
)
580 dir
->__d_position
+= 0x10000;
583 /* Append "%val" if value name is identical to a previous key name. */
584 unsigned h
= hash_path_name (1, buf
);
585 bool add_val
= false;
586 if (! (dir
->__d_position
& REG_ENUM_VALUES_MASK
))
587 d_hash (dir
)->set (h
);
588 else if (d_hash (dir
)->is_set (h
)
589 && key_exists ((HKEY
) dir
->__handle
, buf
, wow64
))
592 if (encode_regname (de
->d_name
, buf
, add_val
))
594 buf_size
= NAME_MAX
+ 1;
599 if (dir
->__d_position
& REG_ENUM_VALUES_MASK
)
606 syscall_printf ("%d = readdir (%p, %p)", res
, dir
, de
);
611 fhandler_registry::telldir (DIR * dir
)
613 return dir
->__d_position
& REG_POSITION_MASK
;
617 fhandler_registry::seekdir (DIR * dir
, _off64_t loc
)
619 /* Unfortunately cannot simply set __d_position due to transition from sub-keys to
623 while (loc
> (dir
->__d_position
& REG_POSITION_MASK
))
624 if (!readdir (dir
, dir
->__d_dirent
))
629 fhandler_registry::rewinddir (DIR * dir
)
631 if (dir
->__handle
!= INVALID_HANDLE_VALUE
)
633 RegCloseKey ((HKEY
) dir
->__handle
);
634 dir
->__handle
= INVALID_HANDLE_VALUE
;
636 dir
->__d_position
= 0;
637 dir
->__flags
= dirent_saw_dot
| dirent_saw_dot_dot
;
641 fhandler_registry::closedir (DIR * dir
)
644 if (dir
->__handle
!= INVALID_HANDLE_VALUE
)
647 if (RegCloseKey ((HKEY
) dir
->__handle
) != ERROR_SUCCESS
)
653 syscall_printf ("%d = closedir (%p)", res
, dir
);
658 fhandler_registry::open (int flags
, mode_t mode
)
662 HKEY handle
= (HKEY
) INVALID_HANDLE_VALUE
;
664 int res
= fhandler_virtual::open (flags
, mode
);
669 path
= get_name () + proc_len
+ 1 + prefix_len
;
672 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
678 else if (flags
& O_WRONLY
)
687 /* Marking as nohandle allows to call dup. */
693 pathlen
= strlen (path
);
694 file
= path
+ pathlen
- 1;
695 if (isdirsep (*file
) && pathlen
> 1)
697 while (!isdirsep (*file
))
703 for (int i
= 0; registry_listing
[i
]; i
++)
704 if (path_prefix_p (registry_listing
[i
], path
,
705 strlen (registry_listing
[i
]), true))
707 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
713 else if (flags
& O_WRONLY
)
721 set_io_handle (registry_keys
[i
]);
722 /* Marking as nohandle allows to call dup on pseudo registry
743 if (flags
& O_WRONLY
)
750 wchar_t dec_file
[NAME_MAX
+ 1];
751 int val_only
= decode_regname (dec_file
, file
);
760 handle
= open_key (path
, KEY_READ
, wow64
, false);
761 if (handle
== (HKEY
) INVALID_HANDLE_VALUE
)
763 if (get_errno () != EACCES
)
764 handle
= open_key (path
, KEY_READ
, wow64
, true);
765 if (handle
== (HKEY
) INVALID_HANDLE_VALUE
)
774 set_io_handle (handle
);
775 set_close_on_exec (!!(flags
& O_CLOEXEC
));
776 value_name
= cwcsdup (dec_file
);
778 if (!(flags
& O_DIROPEN
) && !fill_filebuf ())
780 RegCloseKey (handle
);
785 if (flags
& O_APPEND
)
793 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
796 syscall_printf ("%d = fhandler_registry::open (%p, %d)", res
, flags
, mode
);
801 fhandler_registry::close ()
803 int res
= fhandler_virtual::close ();
806 HKEY handle
= (HKEY
) get_handle ();
807 if (handle
!= (HKEY
) INVALID_HANDLE_VALUE
&& handle
< HKEY_CLASSES_ROOT
)
809 if (RegCloseKey (handle
) != ERROR_SUCCESS
)
815 if (!hExeced
&& value_name
)
824 fhandler_registry::fill_filebuf ()
828 HKEY handle
= (HKEY
) get_handle ();
831 if (handle
!= HKEY_PERFORMANCE_DATA
)
833 error
= RegQueryValueExW (handle
, value_name
, NULL
, &type
, NULL
, &size
);
834 if (error
!= ERROR_SUCCESS
)
836 if (error
!= ERROR_FILE_NOT_FOUND
)
838 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
841 goto value_not_found
;
843 PBYTE tmpbuf
= (PBYTE
) cmalloc_abort (HEAP_BUF
, size
);
845 RegQueryValueExW (handle
, value_name
, NULL
, NULL
, tmpbuf
, &size
);
846 if (error
!= ERROR_SUCCESS
)
848 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
851 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
|| type
== REG_MULTI_SZ
853 bufalloc
= sys_wcstombs (NULL
, 0, (wchar_t *) tmpbuf
,
854 size
/ sizeof (wchar_t));
857 filebuf
= (char *) cmalloc_abort (HEAP_BUF
, bufalloc
);
858 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
|| type
== REG_MULTI_SZ
860 sys_wcstombs (filebuf
, bufalloc
, (wchar_t *) tmpbuf
,
861 size
/ sizeof (wchar_t));
863 memcpy (filebuf
, tmpbuf
, bufalloc
);
871 bufalloc
+= 16 * 1024;
872 filebuf
= (char *) crealloc_abort (filebuf
, bufalloc
);
874 error
= RegQueryValueExW (handle
, value_name
, NULL
, &type
,
875 (PBYTE
) filebuf
, &size
);
876 if (error
!= ERROR_SUCCESS
&& error
!= ERROR_MORE_DATA
)
878 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
882 while (error
== ERROR_MORE_DATA
);
884 /* RegQueryValueEx () opens HKEY_PERFORMANCE_DATA. */
885 RegCloseKey (handle
);
889 DWORD buf_size
= NAME_MAX
+ 1;
890 wchar_t buf
[buf_size
];
892 while (ERROR_SUCCESS
==
893 (error
= RegEnumKeyExW (handle
, index
++, buf
, &buf_size
, NULL
, NULL
,
894 NULL
, NULL
)) || (error
== ERROR_MORE_DATA
))
896 if (!wcscasecmp (buf
, value_name
))
901 buf_size
= NAME_MAX
+ 1;
903 if (error
!= ERROR_NO_MORE_ITEMS
)
905 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
912 /* Auxillary member function to open registry keys. */
914 open_key (const char *name
, REGSAM access
, DWORD wow64
, bool isValue
)
916 HKEY hKey
= (HKEY
) INVALID_HANDLE_VALUE
;
917 HKEY hParentKey
= (HKEY
) INVALID_HANDLE_VALUE
;
918 bool parentOpened
= false;
919 wchar_t component
[NAME_MAX
+ 1];
923 const char *anchor
= name
;
924 while (*name
&& !isdirsep (*name
))
926 int val_only
= decode_regname (component
, anchor
, name
- anchor
);
931 RegCloseKey (hParentKey
);
932 hKey
= (HKEY
) INVALID_HANDLE_VALUE
;
937 if (*name
== 0 && isValue
== true)
940 if (val_only
|| !component
[0] || hKey
== HKEY_PERFORMANCE_DATA
)
944 RegCloseKey (hParentKey
);
945 hKey
= (HKEY
) INVALID_HANDLE_VALUE
;
949 if (hParentKey
!= (HKEY
) INVALID_HANDLE_VALUE
)
951 REGSAM effective_access
= KEY_READ
;
952 if ((strchr (name
, '/') == NULL
&& isValue
== true) || *name
== 0)
953 effective_access
= access
;
954 LONG error
= RegOpenKeyExW (hParentKey
, component
, 0,
955 effective_access
| wow64
, &hKey
);
956 if (error
== ERROR_ACCESS_DENIED
) /* Try opening with backup intent */
957 error
= RegCreateKeyExW (hParentKey
, component
, 0, NULL
,
958 REG_OPTION_BACKUP_RESTORE
,
959 effective_access
| wow64
, NULL
,
962 RegCloseKey (hParentKey
);
963 if (error
!= ERROR_SUCCESS
)
965 hKey
= (HKEY
) INVALID_HANDLE_VALUE
;
966 seterrno_from_win_error (__FILE__
, __LINE__
, error
);
974 for (int i
= 0; registry_listing
[i
]; i
++)
975 if (strncasematch (anchor
, registry_listing
[i
], name
- anchor
- 1))
976 hKey
= registry_keys
[i
];
977 if (hKey
== (HKEY
) INVALID_HANDLE_VALUE
)
986 fhandler_registry::dup (fhandler_base
*child
)
988 int ret
= fhandler_virtual::dup (child
);
989 /* Pseudo registry handles can't be duplicated using DuplicateHandle.
990 Therefore those fhandlers are marked with the nohandle flag. This
991 allows fhandler_base::dup to succeed as usual for nohandle fhandlers.
992 Here we just have to fix up by copying the pseudo handle value. */
993 if ((HKEY
) get_handle () >= HKEY_CLASSES_ROOT
)
994 child
->set_io_handle (get_handle ());