add new files
This commit is contained in:
parent
7a90892d0c
commit
c477dccfa8
|
@ -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 <sys/fcntl.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 "sigproc.h"
|
||||
#include "pinfo.h"
|
||||
#include <assert.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define _COMPILING_NEWLIB
|
||||
#include <dirent.h>
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
/* fhandler_process.cc: fhandler for /proc/<pid> 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 <sys/fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/cygwin.h>
|
||||
#include "cygerrno.h"
|
||||
#include "security.h"
|
||||
#include "fhandler.h"
|
||||
#include "sigproc.h"
|
||||
#include "pinfo.h"
|
||||
#include "path.h"
|
||||
#include "shared_info.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define _COMPILING_NEWLIB
|
||||
#include <dirent.h>
|
||||
|
||||
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, "<defunct>");
|
||||
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;
|
||||
}
|
|
@ -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 <sys/fcntl.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 <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;
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -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 <sys/fcntl.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 "shared_info.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define _COMPILING_NEWLIB
|
||||
#include <dirent.h>
|
||||
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue