diff options
author | cvs2svn <> | 2002-09-22 16:04:16 +0400 |
---|---|---|
committer | cvs2svn <> | 2002-09-22 16:04:16 +0400 |
commit | b9fbe9492e000511d0b2b7db6b81c0fc98ab6f80 (patch) | |
tree | 9bc675d4928360fc4998eb5a43727fd1a4ce427d /winsup/cygwin/fhandler_registry.cc | |
parent | 9783ce28caf426c5ab39d1d6aefa31cfdb1b8234 (diff) |
This commit was manufactured by cvs2svn to create tag 'ZZ-cygwin_daemon_merge-new_HEAD
-cygwin_daemon_merge-new_HEAD'.
Sprout from cygwin_daemon 2002-01-02 00:06:36 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.'
Cherrypick from cygwin_daemon 2002-02-25 17:47:52 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.':
winsup/cygwin/how-spawn-works.txt
winsup/cygwin/wsock_event.h
Cherrypick from cygwin_daemon 2002-06-06 15:35:10 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.':
winsup/cygwin/include/netinet/udp.h
winsup/cygwin/stackdump.sgml
Cherrypick from cygwin_daemon 2002-01-17 10:39:38 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.':
winsup/cygwin/libc/fnmatch.c
Cherrypick from cygwin_daemon 2002-07-03 20:31:40 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.':
winsup/cygwin/include/sys/statfs.h
Cherrypick from cygwin_daemon 2002-09-04 15:17:25 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin_daemon'.':
winsup/cygwin/how-autoload-works.txt
Cherrypick from master 2002-09-22 12:04:15 UTC Conrad Scott <conrad.scott@dsl.pipex.com> '2002-09-22 Conrad Scott <conrad.scott@dsl.pipex.com>':
winsup/cygserver/threaded_queue.cc
winsup/cygserver/woutsup.h
winsup/cygwin/CYGWIN_LICENSE
winsup/cygwin/ChangeLog
winsup/cygwin/ChangeLog-1998
winsup/cygwin/ChangeLog-1999
winsup/cygwin/ChangeLog-2000
winsup/cygwin/Makefile.in
winsup/cygwin/assert.cc
winsup/cygwin/autoload.cc
winsup/cygwin/child_info.h
winsup/cygwin/configure
winsup/cygwin/configure.in
winsup/cygwin/cygerrno.h
winsup/cygwin/cygheap.cc
winsup/cygwin/cygheap.h
winsup/cygwin/cygmagic
winsup/cygwin/cygmalloc.h
winsup/cygwin/cygrun.c
winsup/cygwin/cygserver.cc
winsup/cygwin/cygserver_client.cc
winsup/cygwin/cygserver_ipc.h
winsup/cygwin/cygserver_process.cc
winsup/cygwin/cygserver_shm.cc
winsup/cygwin/cygserver_shm.h
winsup/cygwin/cygserver_transport.cc
winsup/cygwin/cygserver_transport_pipes.cc
winsup/cygwin/cygserver_transport_sockets.cc
winsup/cygwin/cygthread.cc
winsup/cygwin/cygthread.h
winsup/cygwin/cygwin.din
winsup/cygwin/cygwin.sc
winsup/cygwin/dcrt0.cc
winsup/cygwin/debug.cc
winsup/cygwin/debug.h
winsup/cygwin/dir.cc
winsup/cygwin/dlfcn.cc
winsup/cygwin/dll_init.cc
winsup/cygwin/dll_init.h
winsup/cygwin/dlmalloc.c
winsup/cygwin/dtable.cc
winsup/cygwin/dtable.h
winsup/cygwin/environ.cc
winsup/cygwin/environ.h
winsup/cygwin/errno.cc
winsup/cygwin/exceptions.cc
winsup/cygwin/exec.cc
winsup/cygwin/external.cc
winsup/cygwin/fcntl.cc
winsup/cygwin/fhandler.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_clipboard.cc
winsup/cygwin/fhandler_console.cc
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/fhandler_dsp.cc
winsup/cygwin/fhandler_floppy.cc
winsup/cygwin/fhandler_mem.cc
winsup/cygwin/fhandler_proc.cc
winsup/cygwin/fhandler_process.cc
winsup/cygwin/fhandler_random.cc
winsup/cygwin/fhandler_raw.cc
winsup/cygwin/fhandler_registry.cc
winsup/cygwin/fhandler_serial.cc
winsup/cygwin/fhandler_socket.cc
winsup/cygwin/fhandler_tape.cc
winsup/cygwin/fhandler_termios.cc
winsup/cygwin/fhandler_tty.cc
winsup/cygwin/fhandler_virtual.cc
winsup/cygwin/fhandler_windows.cc
winsup/cygwin/fhandler_zero.cc
winsup/cygwin/fork.cc
winsup/cygwin/glob.c
winsup/cygwin/gmon.c
winsup/cygwin/grp.cc
winsup/cygwin/heap.cc
winsup/cygwin/heap.h
winsup/cygwin/hires.h
winsup/cygwin/how-cygheap-works.txt
winsup/cygwin/how-fhandlers-work.txt
winsup/cygwin/how-signals-work.txt
winsup/cygwin/how-to-debug-cygwin.txt
winsup/cygwin/include/cygwin/acl.h
winsup/cygwin/include/cygwin/cygserver.h
winsup/cygwin/include/cygwin/cygserver_process.h
winsup/cygwin/include/cygwin/cygserver_transport.h
winsup/cygwin/include/cygwin/cygserver_transport_pipes.h
winsup/cygwin/include/cygwin/cygserver_transport_sockets.h
winsup/cygwin/include/cygwin/grp.h
winsup/cygwin/include/cygwin/if.h
winsup/cygwin/include/cygwin/ipc.h
winsup/cygwin/include/cygwin/msg.h
winsup/cygwin/include/cygwin/mtio.h
winsup/cygwin/include/cygwin/sem.h
winsup/cygwin/include/cygwin/shm.h
winsup/cygwin/include/cygwin/socket.h
winsup/cygwin/include/cygwin/stat.h
winsup/cygwin/include/cygwin/types.h
winsup/cygwin/include/cygwin/version.h
winsup/cygwin/include/fnmatch.h
winsup/cygwin/include/getopt.h
winsup/cygwin/include/glob.h
winsup/cygwin/include/limits.h
winsup/cygwin/include/netdb.h
winsup/cygwin/include/netinet/ip.h
winsup/cygwin/include/netinet/tcp.h
winsup/cygwin/include/pthread.h
winsup/cygwin/include/sys/cygwin.h
winsup/cygwin/include/sys/ioctl.h
winsup/cygwin/include/sys/mount.h
winsup/cygwin/include/sys/resource.h
winsup/cygwin/include/sys/socket.h
winsup/cygwin/include/sys/soundcard.h
winsup/cygwin/include/sys/strace.h
winsup/cygwin/include/sys/sysmacros.h
winsup/cygwin/include/sys/termios.h
winsup/cygwin/include/sys/uio.h
winsup/cygwin/include/sys/un.h
winsup/cygwin/include/sys/vfs.h
winsup/cygwin/init.cc
winsup/cygwin/ioctl.cc
winsup/cygwin/ipc.cc
winsup/cygwin/lib/cygwin_crt0.c
winsup/cygwin/lib/dll_main.cc
winsup/cygwin/lib/getopt.c
winsup/cygwin/localtime.cc
winsup/cygwin/malloc.cc
winsup/cygwin/malloc_wrapper.cc
winsup/cygwin/miscfuncs.cc
winsup/cygwin/mkvers.sh
winsup/cygwin/mmap.cc
winsup/cygwin/msg.cc
winsup/cygwin/net.cc
winsup/cygwin/ntdll.h
winsup/cygwin/ntea.cc
winsup/cygwin/passwd.cc
winsup/cygwin/path.cc
winsup/cygwin/path.h
winsup/cygwin/perthread.h
winsup/cygwin/pinfo.cc
winsup/cygwin/pinfo.h
winsup/cygwin/pipe.cc
winsup/cygwin/poll.cc
winsup/cygwin/pthread.cc
winsup/cygwin/pwdgrp.h
winsup/cygwin/regex/regcomp.c
winsup/cygwin/registry.cc
winsup/cygwin/resource.cc
winsup/cygwin/safe_memory.h
winsup/cygwin/sched.cc
winsup/cygwin/sec_acl.cc
winsup/cygwin/sec_helper.cc
winsup/cygwin/security.cc
winsup/cygwin/security.h
winsup/cygwin/select.cc
winsup/cygwin/sem.cc
winsup/cygwin/shared.cc
winsup/cygwin/shared_info.h
winsup/cygwin/shm.cc
winsup/cygwin/signal.cc
winsup/cygwin/sigproc.cc
winsup/cygwin/sigproc.h
winsup/cygwin/smallprint.c
winsup/cygwin/spawn.cc
winsup/cygwin/speclib
winsup/cygwin/strace.cc
winsup/cygwin/sync.cc
winsup/cygwin/sync.h
winsup/cygwin/syscalls.cc
winsup/cygwin/sysconf.cc
winsup/cygwin/syslog.cc
winsup/cygwin/termios.cc
winsup/cygwin/thread.cc
winsup/cygwin/thread.h
winsup/cygwin/threaded_queue.cc
winsup/cygwin/threaded_queue.h
winsup/cygwin/times.cc
winsup/cygwin/tty.cc
winsup/cygwin/tty.h
winsup/cygwin/uinfo.cc
winsup/cygwin/uname.cc
winsup/cygwin/wait.cc
winsup/cygwin/winbase.h
winsup/cygwin/wincap.cc
winsup/cygwin/wincap.h
winsup/cygwin/window.cc
winsup/cygwin/winsup.h
winsup/cygwin/winver.rc
winsup/cygwin/woutsup.h
Delete:
winsup/cygwin/include/cygwin/ip.h
winsup/cygwin/include/sys/ipc.h
winsup/cygwin/include/sys/shm.h
winsup/cygwin/include/wchar.h
winsup/cygwin/lib/_cygwin_S_IEXEC.cc
winsup/cygwin/regexp/regerror.c
winsup/cygwin/regexp/regexp.3
winsup/cygwin/regexp/regexp.c
winsup/cygwin/regexp/regsub.c
winsup/cygwin/shortcut.c
winsup/cygwin/shortcut.h
winsup/cygwin/test.c
Diffstat (limited to 'winsup/cygwin/fhandler_registry.cc')
-rw-r--r-- | winsup/cygwin/fhandler_registry.cc | 673 |
1 files changed, 673 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc new file mode 100644 index 000000000..f2e5e2145 --- /dev/null +++ b/winsup/cygwin/fhandler_registry.cc @@ -0,0 +1,673 @@ +/* fhandler_registry.cc: fhandler for /proc/registry virtual filesystem + + Copyright 2002 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* FIXME: Access permissions are ignored at the moment. */ + +#include "winsup.h" +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/cygwin.h> +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "path.h" +#include "dtable.h" +#include "cygheap.h" +#include <assert.h> + +#define _COMPILING_NEWLIB +#include <dirent.h> + +static const int registry_len = sizeof ("registry") - 1; +/* If this bit is set in __d_position then we are enumerating values, + * else sub-keys. keeping track of where we are is horribly messy + * the bottom 16 bits are the absolute position and the top 15 bits + * make up the value index if we are enuerating values. + */ +static const __off32_t REG_ENUM_VALUES_MASK = 0x8000000; +static const __off32_t REG_POSITION_MASK = 0xffff; + +/* List of root keys in /proc/registry. + * Possibly we should filter out those not relevant to the flavour of Windows + * Cygwin is running on. + */ +static const char *registry_listing[] = +{ + ".", + "..", + "HKEY_CLASSES_ROOT", + "HKEY_CURRENT_CONFIG", + "HKEY_CURRENT_USER", + "HKEY_LOCAL_MACHINE", + "HKEY_USERS", + "HKEY_DYN_DATA", // 95/98/Me + "HKEY_PERFOMANCE_DATA", // NT/2000/XP + NULL +}; + +static const HKEY registry_keys[] = +{ + (HKEY) INVALID_HANDLE_VALUE, + (HKEY) INVALID_HANDLE_VALUE, + HKEY_CLASSES_ROOT, + HKEY_CURRENT_CONFIG, + HKEY_CURRENT_USER, + HKEY_LOCAL_MACHINE, + HKEY_USERS, + HKEY_DYN_DATA, + HKEY_PERFORMANCE_DATA +}; + +static const int ROOT_KEY_COUNT = sizeof (registry_keys) / sizeof (HKEY); + +/* These get added to each subdirectory in /proc/registry. + * If we wanted to implement writing, we could maybe add a '.writable' entry or + * suchlike. + */ +static const char *special_dot_files[] = +{ + ".", + "..", + NULL +}; + +static const int SPECIAL_DOT_FILE_COUNT = + (sizeof (special_dot_files) / sizeof (const char *)) - 1; + +/* Name given to default values */ +static const char *DEFAULT_VALUE_NAME = "@"; + +static HKEY open_key (const char *name, REGSAM access, bool isValue); + +/* Returns 0 if path doesn't exist, >0 if path is a directory, + * <0 if path is a file. + * + * We open the last key but one and then enum it's sub-keys and values to see if the + * final component is there. This gets round the problem of not having security access + * to the final key in the path. + */ +int +fhandler_registry::exists () +{ + int file_type = 0, index = 0, pathlen; + DWORD buf_size = MAX_PATH; + LONG error; + char buf[buf_size]; + const char *file; + HKEY hKey = (HKEY) INVALID_HANDLE_VALUE; + + const char *path = get_name (); + debug_printf ("exists (%s)", path); + path += proc_len + registry_len + 2; + if (*path == 0) + { + file_type = 2; + goto out; + } + pathlen = strlen (path); + file = path + pathlen - 1; + if (SLASH_P (*file) && pathlen > 1) + file--; + while (!SLASH_P (*file)) + file--; + file++; + + if (file == path) + { + for (int i = 0; registry_listing[i]; i++) + if (path_prefix_p + (registry_listing[i], path, strlen (registry_listing[i]))) + { + file_type = 1; + goto out; + } + goto out; + } + + hKey = open_key (path, KEY_READ, false); + if (hKey != (HKEY) INVALID_HANDLE_VALUE) + file_type = 1; + else + { + hKey = open_key (path, KEY_READ, true); + if (hKey == (HKEY) INVALID_HANDLE_VALUE) + return 0; + + while (ERROR_SUCCESS == + (error = RegEnumKeyEx (hKey, index++, buf, &buf_size, NULL, NULL, + NULL, NULL)) + || (error == ERROR_MORE_DATA)) + { + if (pathmatch (buf, file)) + { + file_type = 1; + goto out; + } + buf_size = MAX_PATH; + } + if (error != ERROR_NO_MORE_ITEMS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + goto out; + } + index = 0; + buf_size = MAX_PATH; + while (ERROR_SUCCESS == + (error = RegEnumValue (hKey, index++, buf, &buf_size, NULL, NULL, + NULL, NULL)) + || (error == ERROR_MORE_DATA)) + { + if (pathmatch (buf, file) || (buf[0] == '\0' && + pathmatch (file, DEFAULT_VALUE_NAME))) + { + file_type = -1; + goto out; + } + buf_size = MAX_PATH; + } + if (error != ERROR_NO_MORE_ITEMS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + goto out; + } + } +out: + if (hKey != (HKEY) INVALID_HANDLE_VALUE) + RegCloseKey (hKey); + return file_type; +} + +fhandler_registry::fhandler_registry (): +fhandler_proc (FH_REGISTRY) +{ +} + +int +fhandler_registry::fstat (struct __stat64 *buf, path_conv *pc) +{ + this->fhandler_base::fstat (buf, pc); + buf->st_mode &= ~_IFMT & NO_W; + int file_type = exists (); + switch (file_type) + { + case 0: + set_errno (ENOENT); + return -1; + case 1: + buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + break; + case 2: + buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + buf->st_nlink = ROOT_KEY_COUNT; + break; + default: + case -1: + buf->st_mode |= S_IFREG; + buf->st_mode &= NO_X; + break; + } + if (file_type != 0 && file_type != 2) + { + HKEY hKey; + const char *path = get_name () + proc_len + registry_len + 2; + hKey = + open_key (path, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, + (file_type < 0) ? true : false); + + if (hKey != (HKEY) INVALID_HANDLE_VALUE) + { + FILETIME ftLastWriteTime; + DWORD subkey_count; + if (ERROR_SUCCESS == + RegQueryInfoKey (hKey, NULL, NULL, NULL, &subkey_count, NULL, + NULL, NULL, NULL, NULL, NULL, + &ftLastWriteTime)) + { + to_timestruc_t (&ftLastWriteTime, &buf->st_mtim); + buf->st_ctim = buf->st_mtim; + time_as_timestruc_t (&buf->st_atim); + if (file_type > 0) + buf->st_nlink = subkey_count; + else + { + int pathlen = strlen (path); + const char *value_name = path + pathlen - 1; + if (SLASH_P (*value_name) && pathlen > 1) + value_name--; + while (!SLASH_P (*value_name)) + value_name--; + value_name++; + DWORD dwSize; + if (ERROR_SUCCESS == + RegQueryValueEx (hKey, value_name, NULL, NULL, NULL, + &dwSize)) + buf->st_size = dwSize; + } + __uid32_t uid; + __gid32_t gid; + if (get_object_attribute + ((HANDLE) hKey, SE_REGISTRY_KEY, &buf->st_mode, &uid, + &gid) == 0) + { + buf->st_uid = uid; + buf->st_gid = gid; + buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + if (file_type > 0) + buf->st_mode |= S_IFDIR; + else + buf->st_mode &= NO_X; + } + } + RegCloseKey (hKey); + } + } + return 0; +} + +struct dirent * +fhandler_registry::readdir (DIR * dir) +{ + DWORD buf_size = MAX_PATH; + char buf[buf_size]; + HANDLE handle; + struct dirent *res = NULL; + const char *path = dir->__d_dirname + proc_len + 1 + registry_len; + LONG error; + + if (*path == 0) + { + if (dir->__d_position >= ROOT_KEY_COUNT) + goto out; + strcpy (dir->__d_dirent->d_name, registry_listing[dir->__d_position++]); + res = dir->__d_dirent; + goto out; + } + if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE + && dir->__d_position == 0) + { + handle = open_key (path + 1, KEY_READ, false); + dir->__d_u.__d_data.__handle = handle; + } + if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) + goto out; + if (dir->__d_position < SPECIAL_DOT_FILE_COUNT) + { + strcpy (dir->__d_dirent->d_name, + special_dot_files[dir->__d_position++]); + res = dir->__d_dirent; + goto out; + } +retry: + if (dir->__d_position & REG_ENUM_VALUES_MASK) + /* For the moment, the type of key is ignored here. when write access is added, + * maybe add an extension for the type of each value? + */ + error = RegEnumValue ((HKEY) dir->__d_u.__d_data.__handle, + (dir->__d_position & ~REG_ENUM_VALUES_MASK) >> 16, + buf, &buf_size, NULL, NULL, NULL, NULL); + else + error = + RegEnumKeyEx ((HKEY) dir->__d_u.__d_data.__handle, dir->__d_position - + SPECIAL_DOT_FILE_COUNT, buf, &buf_size, NULL, NULL, NULL, + NULL); + if (error == ERROR_NO_MORE_ITEMS + && (dir->__d_position & REG_ENUM_VALUES_MASK) == 0) + { + /* If we're finished with sub-keys, start on values under this key. */ + dir->__d_position |= REG_ENUM_VALUES_MASK; + buf_size = MAX_PATH; + goto retry; + } + if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA) + { + RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle); + dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + seterrno_from_win_error (__FILE__, __LINE__, error); + goto out; + } + + /* We get here if `buf' contains valid data. */ + if (*buf == 0) + strcpy (dir->__d_dirent->d_name, DEFAULT_VALUE_NAME); + else + strcpy (dir->__d_dirent->d_name, buf); + + dir->__d_position++; + if (dir->__d_position & REG_ENUM_VALUES_MASK) + dir->__d_position += 0x10000; + res = dir->__d_dirent; +out: + syscall_printf ("%p = readdir (%p)", &dir->__d_dirent, dir); + return res; +} + +__off64_t +fhandler_registry::telldir (DIR * dir) +{ + return dir->__d_position & REG_POSITION_MASK; +} + +void +fhandler_registry::seekdir (DIR * dir, __off64_t loc) +{ + /* Unfortunately cannot simply set __d_position due to transition from sub-keys to + * values. + */ + rewinddir (dir); + while (loc > (dir->__d_position & REG_POSITION_MASK)) + if (!readdir (dir)) + break; +} + +void +fhandler_registry::rewinddir (DIR * dir) +{ + if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE) + { + (void) RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle); + dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + } + dir->__d_position = 0; + return; +} + +int +fhandler_registry::closedir (DIR * dir) +{ + int res = 0; + if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE && + RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle) != ERROR_SUCCESS) + { + __seterrno (); + res = -1; + } + syscall_printf ("%d = closedir (%p)", res, dir); + return 0; +} + +int +fhandler_registry::open (path_conv * pc, int flags, mode_t mode) +{ + int pathlen; + const char *file; + HKEY handle; + + int res = fhandler_virtual::open (pc, flags, mode); + if (!res) + goto out; + + const char *path; + path = get_name () + proc_len + 1 + registry_len; + if (!*path) + { + if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + res = 0; + goto out; + } + else if (flags & O_WRONLY) + { + set_errno (EISDIR); + res = 0; + goto out; + } + else + { + flags |= O_DIROPEN; + goto success; + } + } + path++; + pathlen = strlen (path); + file = path + pathlen - 1; + if (SLASH_P (*file) && pathlen > 1) + file--; + while (!SLASH_P (*file)) + file--; + file++; + + if (file == path) + { + for (int i = 0; registry_listing[i]; i++) + if (path_prefix_p + (registry_listing[i], path, strlen (registry_listing[i]))) + { + if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + res = 0; + goto out; + } + else if (flags & O_WRONLY) + { + set_errno (EISDIR); + res = 0; + goto out; + } + else + { + flags |= O_DIROPEN; + goto success; + } + } + + if (flags & O_CREAT) + { + set_errno (EROFS); + res = 0; + goto out; + } + else + { + set_errno (ENOENT); + res = 0; + goto out; + } + } + + if (flags & O_WRONLY) + { + set_errno (EROFS); + res = 0; + goto out; + } + + handle = open_key (path, KEY_READ, true); + if (handle == (HKEY) INVALID_HANDLE_VALUE) + { + res = 0; + goto out; + } + + set_io_handle (handle); + + if (pathmatch (file, DEFAULT_VALUE_NAME)) + value_name = cstrdup (""); + else + value_name = cstrdup (file); + + if (!fill_filebuf ()) + { + RegCloseKey (handle); + res = 0; + goto out; + } + + if (flags & O_APPEND) + position = filesize; + else + position = 0; + +success: + res = 1; + set_flags ((flags & ~O_TEXT) | O_BINARY); + set_open_status (); +out: + syscall_printf ("%d = fhandler_registry::open (%p, %d)", res, flags, mode); + return res; +} + +int +fhandler_registry::close () +{ + int res = fhandler_virtual::close (); + if (res != 0) + return res; + HKEY handle = (HKEY) get_handle (); + if (handle != (HKEY) INVALID_HANDLE_VALUE) + { + if (RegCloseKey (handle) != ERROR_SUCCESS) + { + __seterrno (); + res = -1; + } + } + if (value_name) + cfree (value_name); + return res; +} + +bool +fhandler_registry::fill_filebuf () +{ + DWORD type, size; + LONG error; + HKEY handle = (HKEY) get_handle (); + if (handle != HKEY_PERFORMANCE_DATA) + { + error = RegQueryValueEx (handle, value_name, NULL, &type, NULL, &size); + if (error != ERROR_SUCCESS) + { + if (error != ERROR_FILE_NOT_FOUND) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + return false; + } + goto value_not_found; + } + bufalloc = size; + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc); + error = + RegQueryValueEx (handle, value_name, NULL, NULL, (BYTE *) filebuf, + &size); + if (error != ERROR_SUCCESS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + return true; + } + filesize = size; + } + else + { + bufalloc = 0; + do + { + bufalloc += 1000; + if (filebuf) + { + cfree (filebuf); + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc); + } + error = + RegQueryValueEx (handle, value_name, NULL, &type, + (BYTE *) filebuf, &size); + if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA) + { + if (error != ERROR_FILE_NOT_FOUND) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + return true; + } + goto value_not_found; + } + } + while (error == ERROR_MORE_DATA); + filesize = size; + } + return true; +value_not_found: + DWORD buf_size = MAX_PATH; + char buf[buf_size]; + int index = 0; + while (ERROR_SUCCESS == + (error = RegEnumKeyEx (handle, index++, buf, &buf_size, NULL, NULL, + NULL, NULL)) || (error == ERROR_MORE_DATA)) + { + if (pathmatch (buf, value_name)) + { + set_errno (EISDIR); + return false; + } + buf_size = MAX_PATH; + } + if (error != ERROR_NO_MORE_ITEMS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + return false; + } + set_errno (ENOENT); + return false; +} + +/* Auxillary member function to open registry keys. */ +static HKEY +open_key (const char *name, REGSAM access, bool isValue) +{ + HKEY hKey = (HKEY) INVALID_HANDLE_VALUE; + HKEY hParentKey = (HKEY) INVALID_HANDLE_VALUE; + bool parentOpened = false; + char component[MAX_PATH]; + + while (*name) + { + const char *anchor = name; + while (*name && !SLASH_P (*name)) + name++; + strncpy (component, anchor, name - anchor); + component[name - anchor] = '\0'; + if (*name) + name++; + if (*name == 0 && isValue == true) + goto out; + + if (hParentKey != (HKEY) INVALID_HANDLE_VALUE) + { + REGSAM effective_access = KEY_READ; + if ((strchr (name, '/') == NULL && isValue == true) || *name == 0) + effective_access = access; + LONG + error = + RegOpenKeyEx (hParentKey, component, 0, effective_access, &hKey); + if (error != ERROR_SUCCESS) + { + hKey = (HKEY) INVALID_HANDLE_VALUE; + seterrno_from_win_error (__FILE__, __LINE__, error); + return hKey; + } + if (parentOpened) + RegCloseKey (hParentKey); + hParentKey = hKey; + parentOpened = true; + } + else + { + for (int i = 0; registry_listing[i]; i++) + if (pathmatch (component, registry_listing[i])) + hKey = registry_keys[i]; + if (hKey == (HKEY) INVALID_HANDLE_VALUE) + return hKey; + hParentKey = hKey; + } + } +out: + return hKey; +} |