diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc new file mode 100644 index 000000000..dd4af7ec5 --- /dev/null +++ b/winsup/cygwin/fhandler_proc.cc @@ -0,0 +1,313 @@ +/* fhandler_proc.cc: fhandler for /proc 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. */ + +#include "winsup.h" +#include +#include +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "path.h" +#include "sigproc.h" +#include "pinfo.h" +#include +#include + +#define _COMPILING_NEWLIB +#include + +/* offsets in proc_listing */ +static const int PROC_REGISTRY = 0; // /proc/registry +static const int PROC_VERSION = 1; // /proc/version +static const int PROC_UPTIME = 2; // /proc/uptime + +/* names of objects in /proc */ +static const char *proc_listing[] = { + "registry", + "version", + "uptime", + NULL +}; + +static const int PROC_LINK_COUNT = (sizeof(proc_listing) / sizeof(const char *)) - 1; + +/* FH_PROC in the table below means the file/directory is handles by + * fhandler_proc. + */ +static const DWORD proc_fhandlers[] = { + FH_REGISTRY, + FH_PROC, + FH_PROC +}; + +/* name of the /proc filesystem */ +const char proc[] = "/proc"; +const int proc_len = sizeof (proc) - 1; + +/* auxillary function that returns the fhandler associated with the given path + * this is where it would be nice to have pattern matching in C - polymorphism + * just doesn't cut it + */ +DWORD +fhandler_proc::get_proc_fhandler (const char *path) +{ + debug_printf ("get_proc_fhandler(%s)", path); + path += proc_len; + /* Since this method is called from path_conv::check we can't rely on + * it being normalised and therefore the path may have runs of slashes + * in it. + */ + while (SLASH_P (*path)) + path++; + + /* Check if this is the root of the virtual filesystem (i.e. /proc). */ + if (*path == 0) + return FH_PROC; + + for (int i = 0; proc_listing[i]; i++) + { + if (path_prefix_p (proc_listing[i], path, strlen (proc_listing[i]))) + return proc_fhandlers[i]; + } + + int pid = atoi (path); + winpids pids; + for (unsigned i = 0; i < pids.npids; i++) + { + _pinfo *p = pids[i]; + + if (!proc_exists (p)) + continue; + + if (p->pid == pid) + return FH_PROCESS; + } + return FH_BAD; +} + +/* Returns 0 if path doesn't exist, >0 if path is a directory, + * <0 if path is a file. + */ +int +fhandler_proc::exists (const char *path) +{ + debug_printf ("exists (%s)", path); + path += proc_len; + if (*path == 0) + return 2; + for (int i = 0; proc_listing[i]; i++) + if (pathmatch (path + 1, proc_listing[i])) + return (proc_fhandlers[i] == FH_PROC) ? -1 : 1; + return 0; +} + +fhandler_proc::fhandler_proc (): + fhandler_virtual (FH_PROC) +{ +} + +fhandler_proc::fhandler_proc (DWORD devtype): + fhandler_virtual (devtype) +{ +} + +int +fhandler_proc::fstat (struct __stat64 *buf, path_conv *pc) +{ + debug_printf ("fstat (%s)", (char *) *pc); + const char *path = get_name (); + path += proc_len; + (void) fhandler_base::fstat (buf, pc); + + buf->st_mode &= ~_IFMT & NO_W; + + if (!*path) + { + buf->st_nlink = PROC_LINK_COUNT; + buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + return 0; + } + else + { + path++; + for (int i = 0; proc_listing[i]; i++) + if (pathmatch (path, proc_listing[i])) + { + if (proc_fhandlers[i] != FH_PROC) + buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else + { + buf->st_mode &= NO_X; + buf->st_mode |= S_IFREG; + } + return 0; + } + } + set_errno (ENOENT); + return -1; +} + +struct dirent * +fhandler_proc::readdir (DIR * dir) +{ + if (dir->__d_position >= PROC_LINK_COUNT) + { + winpids pids; + int found = 0; + for (unsigned i = 0; i < pids.npids; i++) + { + _pinfo *p = pids[i]; + + if (!proc_exists (p)) + continue; + + if (found == dir->__d_position - PROC_LINK_COUNT) + { + __small_sprintf (dir->__d_dirent->d_name, "%d", p->pid); + dir->__d_position++; + return dir->__d_dirent; + } + found++; + } + return NULL; + } + + strcpy (dir->__d_dirent->d_name, proc_listing[dir->__d_position++]); + syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, + dir->__d_dirent->d_name); + return dir->__d_dirent; +} + +int +fhandler_proc::open (path_conv *pc, int flags, mode_t mode) +{ + int proc_file_no = -1; + + int res = fhandler_virtual::open (pc, flags, mode); + if (!res) + goto out; + + const char *path; + + path = (char *) *pc + proc_len; + + if (!*path) + { + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + res = 0; + goto out; + } + else if (mode & O_WRONLY) + { + set_errno (EISDIR); + res = 0; + goto out; + } + else + { + flags |= O_DIROPEN; + goto success; + } + } + + proc_file_no = -1; + for (int i = 0; proc_listing[i]; i++) + if (path_prefix_p (proc_listing[i], path + 1, strlen (proc_listing[i]))) + { + proc_file_no = i; + if (proc_fhandlers[i] != FH_PROC) + { + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + res = 0; + goto out; + } + else if (mode & O_WRONLY) + { + set_errno (EISDIR); + res = 0; + goto out; + } + else + { + flags |= O_DIROPEN; + goto success; + } + } + } + + if (proc_file_no == -1) + { + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EROFS); + res = 0; + goto out; + } + else + { + set_errno (ENOENT); + res = 0; + goto out; + } + } + if (mode & O_WRONLY) + { + set_errno (EROFS); + res = 0; + goto out; + } + switch (proc_file_no) + { + case PROC_VERSION: + { + struct utsname uts_name; + uname (&uts_name); + filesize = bufalloc = strlen (uts_name.sysname) + 1 + + strlen (uts_name.release) + 1 + strlen (uts_name.version) + 2; + filebuf = new char[bufalloc]; + __small_sprintf (filebuf, "%s %s %s\n", uts_name.sysname, + uts_name.release, uts_name.version); + break; + } + case PROC_UPTIME: + { + /* GetTickCount() wraps after 49 days - on WinNT/2000/XP, should use + * perfomance counters but I don't know Redhat's policy on + * NT only dependancies. + */ + DWORD ticks = GetTickCount (); + filebuf = new char[bufalloc = 40]; + __small_sprintf (filebuf, "%d.%02d\n", ticks / 1000, + (ticks / 10) % 100); + filesize = strlen (filebuf); + break; + } + } + + if (flags & O_APPEND) + position = filesize; + else + position = 0; + +success: + res = 1; + set_open_status (); + set_flags (flags); +out: + syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode); + return res; +} diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc new file mode 100644 index 000000000..32812c5b8 --- /dev/null +++ b/winsup/cygwin/fhandler_process.cc @@ -0,0 +1,294 @@ +/* fhandler_process.cc: fhandler for /proc/ 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. */ + +#include "winsup.h" +#include +#include +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "sigproc.h" +#include "pinfo.h" +#include "path.h" +#include "shared_info.h" +#include + +#define _COMPILING_NEWLIB +#include + +static const int PROCESS_PPID = 0; +static const int PROCESS_EXENAME = 1; +static const int PROCESS_WINPID = 2; +static const int PROCESS_WINEXENAME = 3; +static const int PROCESS_STATUS = 4; +static const int PROCESS_UID = 5; +static const int PROCESS_GID = 6; +static const int PROCESS_PGID = 7; +static const int PROCESS_SID = 8; +static const int PROCESS_CTTY = 9; + +static const char *process_listing[] = { + "ppid", + "exename", + "winpid", + "winexename", + "status", + "uid", + "gid", + "pgid", + "sid", + "ctty", + NULL +}; + +static const int PROCESS_LINK_COUNT = (sizeof(process_listing) / sizeof(const char *)) - 1; + +/* Returns 0 if path doesn't exist, >0 if path is a directory, + * <0 if path is a file. + */ +int +fhandler_process::exists (const char *path) +{ + debug_printf ("exists (%s)", path); + path += proc_len + 1; + while (*path != 0 && !SLASH_P (*path)) + path++; + if (*path == 0) + return 2; + + for (int i = 0; process_listing[i]; i++) + if (pathmatch (path + 1, process_listing[i])) + return -1; + return 1; +} + +fhandler_process::fhandler_process (): + fhandler_proc (FH_PROCESS) +{ +} + +int +fhandler_process::fstat (struct __stat64 *buf, path_conv *path) +{ + int file_type = exists ((const char *) get_name ()); + switch (file_type) + { + case 0: + set_errno (ENOENT); + return -1; + case 1: + buf->st_mode = S_IFDIR | 0555; + buf->st_nlink = 1; + return 0; + case 2: + buf->st_mode = S_IFDIR | 0555; + buf->st_nlink = PROCESS_LINK_COUNT; + return 0; + default: + case -1: + buf->st_mode = S_IFREG | 0444; + buf->st_nlink = 1; + return 0; + } +} + +struct dirent * +fhandler_process::readdir (DIR * dir) +{ + if (dir->__d_position >= PROCESS_LINK_COUNT) + return NULL; + strcpy (dir->__d_dirent->d_name, process_listing[dir->__d_position++]); + syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir, + dir->__d_dirent->d_name); + return dir->__d_dirent; +} + +int +fhandler_process::open (path_conv *pc, int flags, mode_t mode) +{ + int process_file_no = -1, pid; + winpids pids; + _pinfo *p; + + int res = fhandler_virtual::open (pc, flags, mode); + if (!res) + goto out; + + const char *path; + path = (const char *) *pc + proc_len + 1; + pid = atoi (path); + while (*path != 0 && !SLASH_P (*path)) + path++; + + if (*path == 0) + { + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + res = 0; + goto out; + } + else if (mode & O_WRONLY) + { + set_errno (EISDIR); + res = 0; + goto out; + } + else + { + flags |= O_DIROPEN; + goto success; + } + } + + process_file_no = -1; + for (int i = 0; process_listing[i]; i++) + { + if (path_prefix_p + (process_listing[i], path + 1, strlen (process_listing[i]))) + process_file_no = i; + } + if (process_file_no == -1) + { + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EROFS); + res = 0; + goto out; + } + else + { + set_errno (ENOENT); + res = 0; + goto out; + } + } + if (mode & O_WRONLY) + { + set_errno (EROFS); + res = 0; + goto out; + } + for (unsigned i = 0; i < pids.npids; i++) + { + p = pids[i]; + + if (!proc_exists (p)) + continue; + + if (p->pid == pid) + goto found; + } + set_errno (ENOENT); + res = 0; + goto out; +found: + switch (process_file_no) + { + case PROCESS_UID: + case PROCESS_GID: + case PROCESS_PGID: + case PROCESS_SID: + case PROCESS_CTTY: + case PROCESS_PPID: + { + filebuf = new char[bufalloc = 40]; + int num; + switch (process_file_no) + { + case PROCESS_PPID: + num = p->ppid; + break; + case PROCESS_UID: + num = p->uid; + break; + case PROCESS_PGID: + num = p->pgid; + break; + case PROCESS_SID: + num = p->sid; + break; + default: + case PROCESS_CTTY: + num = p->ctty; + break; + } + __small_sprintf (filebuf, "%d\n", num); + filesize = strlen (filebuf); + break; + } + case PROCESS_EXENAME: + { + filebuf = new char[bufalloc = MAX_PATH]; + if (p->process_state & (PID_ZOMBIE | PID_EXITED)) + strcpy (filebuf, ""); + else + { + mount_table->conv_to_posix_path (p->progname, filebuf, 1); + int len = strlen (filebuf); + if (len > 4) + { + char *s = filebuf + len - 4; + if (strcasecmp (s, ".exe") == 0) + *s = 0; + } + } + filesize = strlen (filebuf); + break; + } + case PROCESS_WINPID: + { + filebuf = new char[bufalloc = 40]; + __small_sprintf (filebuf, "%d\n", p->dwProcessId); + filesize = strlen (filebuf); + break; + } + case PROCESS_WINEXENAME: + { + int len = strlen (p->progname); + filebuf = new char[len + 2]; + strcpy (filebuf, p->progname); + filebuf[len] = '\n'; + filesize = len + 1; + break; + } + case PROCESS_STATUS: + { + filebuf = new char[bufalloc = 3]; + filebuf[0] = ' '; + filebuf[1] = '\n'; + filebuf[2] = 0; + if (p->process_state & PID_STOPPED) + filebuf[0] = 'S'; + else if (p->process_state & PID_TTYIN) + filebuf[0] = 'I'; + else if (p->process_state & PID_TTYOU) + filebuf[0] = 'O'; + filesize = 2; + break; + } + } + + if (flags & O_APPEND) + position = filesize; + else + position = 0; + +success: + res = 1; + set_open_status (); + set_flags (flags); +out: + syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode); + return res; +} diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc new file mode 100644 index 000000000..6de3308f6 --- /dev/null +++ b/winsup/cygwin/fhandler_registry.cc @@ -0,0 +1,511 @@ +/* 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 +#include +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "path.h" +#include + +#define _COMPILING_NEWLIB +#include + +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; + +/* 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_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); + +/* Name given to default values */ +static const char *DEFAULT_VALUE_NAME = "@"; + +/* 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 (const char *path) +{ + 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; + + debug_printf ("exists (%s)", path); + path += proc_len + 1 + registry_len; + + while (SLASH_P (*path)) + path++; + 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, 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 *path) +{ + this->fhandler_base::fstat (buf, path); + buf->st_mode &= ~_IFMT & NO_W; + int file_type = exists (get_name ()); + 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; + } + 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); + dir->__d_u.__d_data.__handle = handle;; + } + if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) + 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, + 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; + if (error != ERROR_NO_MORE_ITEMS) + 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) (%s)", &dir->__d_dirent, dir, buf); + return res; +} + +__off64_t +fhandler_registry::telldir (DIR * dir) +{ + return dir->__d_position & REG_ENUM_VALUES_MASK; +} + +void +fhandler_registry::seekdir (DIR * dir, __off32_t loc) +{ + /* Unfortunately cannot simply set __d_position due to transition from sub-keys to + * values. + */ + rewinddir (dir); + while (loc > dir->__d_position) + 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) +{ + DWORD type, size; + LONG error; + HKEY hKey = (HKEY) INVALID_HANDLE_VALUE; + int pathlen; + const char *file; + + int res = fhandler_virtual::open (pc, flags, mode); + if (!res) + goto out; + + const char *path; + path = (const char *) *pc + proc_len + 1 + registry_len; + if (!*path) + { + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + res = 0; + goto out; + } + else if (mode & 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 ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + res = 0; + goto out; + } + else if (mode & O_WRONLY) + { + set_errno (EISDIR); + res = 0; + goto out; + } + else + { + flags |= O_DIROPEN; + goto success; + } + } + + if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EROFS); + res = 0; + goto out; + } + else + { + set_errno (ENOENT); + res = 0; + goto out; + } + } + + hKey = open_key (path, KEY_READ, true); + if (hKey == (HKEY) INVALID_HANDLE_VALUE) + { + res = 0; + goto out; + } + if (mode & O_WRONLY) + { + set_errno (EROFS); + res = 0; + goto out; + } + if (pathmatch (file, DEFAULT_VALUE_NAME)) + file = ""; + + if (hKey != HKEY_PERFORMANCE_DATA) + { + error = RegQueryValueEx (hKey, file, NULL, &type, NULL, &size); + if (error != ERROR_SUCCESS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + res = -1; + goto out; + } + bufalloc = size; + filebuf = new char[bufalloc]; + error = + RegQueryValueEx (hKey, file, NULL, NULL, (BYTE *) filebuf, &size); + if (error != ERROR_SUCCESS) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + res = 0; + goto out; + } + filesize = size; + } + else + { + bufalloc = 0; + do + { + bufalloc += 1000; + if (filebuf) + { + delete filebuf; + filebuf = new char[bufalloc]; + } + error = + RegQueryValueEx (hKey, file, NULL, &type, (BYTE *) filebuf, + &size); + if (error != ERROR_SUCCESS && res != ERROR_MORE_DATA) + { + seterrno_from_win_error (__FILE__, __LINE__, error); + res = 0; + goto out; + } + } + while (error == ERROR_MORE_DATA); + filesize = size; + } + + if (flags & O_APPEND) + position = filesize; + else + position = 0; + +success: + res = 1; + set_open_status (); + set_flags (flags); +out: + if (hKey != (HKEY) INVALID_HANDLE_VALUE) + RegCloseKey (hKey); + syscall_printf ("%d = fhandler_registry::open (%p, %d)", res, flags, mode); + return res; +} + +/* Auxillary member function to open registry keys. */ +HKEY +fhandler_registry::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) + { + hKey = (HKEY) INVALID_HANDLE_VALUE; + LONG error = RegOpenKeyEx (hParentKey, component, 0, access, &hKey); + if (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; +} diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc new file mode 100644 index 000000000..32798b373 --- /dev/null +++ b/winsup/cygwin/fhandler_virtual.cc @@ -0,0 +1,207 @@ +/* fhandler_virtual.cc: base fhandler class for virtual filesystems + + 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. */ + +#include "winsup.h" +#include +#include +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "fhandler.h" +#include "path.h" +#include "dtable.h" +#include "cygheap.h" +#include "shared_info.h" +#include + +#define _COMPILING_NEWLIB +#include + +fhandler_virtual::fhandler_virtual (DWORD devtype): + fhandler_base (devtype), filebuf (NULL), bufalloc (-1) +{ +} + +fhandler_virtual::~fhandler_virtual () +{ + if (filebuf) + delete filebuf; + filebuf = NULL; +} + +DIR * +fhandler_virtual::opendir (path_conv& pc) +{ + DIR *dir; + DIR *res = NULL; + size_t len; + + if (exists (pc) <= 0) + set_errno (ENOTDIR); + else if ((len = strlen (pc)) > MAX_PATH - 3) + set_errno (ENAMETOOLONG); + else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL) + set_errno (ENOMEM); + else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL) + { + free (dir); + set_errno (ENOMEM); + } + else if ((dir->__d_dirent = + (struct dirent *) malloc (sizeof (struct dirent))) == NULL) + { + free (dir); + set_errno (ENOMEM); + } + else + { + strcpy (dir->__d_dirname, pc); + dir->__d_dirent->d_version = __DIRENT_VERSION; + cygheap_fdnew fd; + fd = this; + fd->set_nohandle (true); + dir->__d_dirent->d_fd = fd; + dir->__d_u.__d_data.__fh = this; + dir->__d_cookie = __DIRENT_COOKIE; + dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + dir->__d_position = 0; + dir->__d_dirhash = get_namehash (); + + res = dir; + } + + syscall_printf ("%p = opendir (%s)", res, get_name ()); + return res; +} + +__off64_t fhandler_virtual::telldir (DIR * dir) +{ + return dir->__d_position; +} + +void +fhandler_virtual::seekdir (DIR * dir, __off32_t loc) +{ + dir->__d_position = loc; + return; +} + +void +fhandler_virtual::rewinddir (DIR * dir) +{ + dir->__d_position = 0; + return; +} + +int +fhandler_virtual::closedir (DIR * dir) +{ + return 0; +} + +__off64_t +fhandler_virtual::lseek (__off32_t offset, int whence) +{ + switch (whence) + { + case SEEK_SET: + position = offset; + break; + case SEEK_CUR: + position += offset; + break; + case SEEK_END: + position = filesize + offset; + break; + default: + set_errno (EINVAL); + return (__off32_t) -1; + } + return position; +} + +int +fhandler_virtual::dup (fhandler_base * child) +{ + fhandler_virtual *fhproc_child = (fhandler_virtual *) child; + fhproc_child->filebuf = new char[filesize]; + fhproc_child->bufalloc = fhproc_child->filesize = filesize; + fhproc_child->position = position; + return 0; +} + +int +fhandler_virtual::close () +{ + if (filebuf) + delete[]filebuf; + filebuf = NULL; + bufalloc = -1; + cygwin_shared->delqueue.process_queue (); + return 0; +} + +int +fhandler_virtual::read (void *ptr, size_t len) +{ + if (len == 0) + return 0; + if (openflags & O_DIROPEN) + { + set_errno (EISDIR); + return -1; + } + if (!filebuf) + return 0; + int read = len; + if (read > filesize - position) + read = filesize - position; + if (read < 0) + read = 0; + else + memcpy (ptr, filebuf + position, read); + position += read; + return read; +} + +int +fhandler_virtual::write (const void *ptr, size_t len) +{ + set_errno (EROFS); + return -1; +} + +/* low-level open for all proc files */ +int +fhandler_virtual::open (path_conv *, int flags, mode_t mode) +{ + set_r_binary (1); + set_w_binary (1); + + set_has_acls (false); + set_isremote (false); + + /* what to do about symlinks? */ + set_symlink_p (false); + set_execable_p (not_executable); + set_socket_p (false); + + set_flags (flags); + + return 1; +} + +int +fhandler_virtual::exists (const char *path) +{ + return 0; +}