From d7e80c56ce283dc21392bc15a07f0e33525545a3 Mon Sep 17 00:00:00 2001 From: Insigma Research Institute Date: Mon, 31 Aug 2009 00:00:00 +0800 Subject: [PATCH 2/3] import original unifiedkernel-0.2.4.1/module just import: $ cp -r ~/unifiedkernel-0.2.4.1/module linux-2.6.30-uk/unifiedkernel --- unifiedkernel/Makefile | 49 + unifiedkernel/device/Makefile | 14 + unifiedkernel/device/clipboard.c | 234 ++ unifiedkernel/device/console.c | 1588 ++++++++ unifiedkernel/device/device.c | 516 +++ unifiedkernel/device/mailslot.c | 524 +++ unifiedkernel/device/named_pipe.c | 1128 ++++++ unifiedkernel/device/serial.c | 260 ++ unifiedkernel/device/snapshot.c | 290 ++ unifiedkernel/device/timer.c | 297 ++ unifiedkernel/fs/Makefile | 14 + unifiedkernel/fs/async.c | 336 ++ unifiedkernel/fs/change.c | 1105 ++++++ unifiedkernel/fs/completion.c | 244 ++ unifiedkernel/fs/directory.c | 383 ++ unifiedkernel/fs/fd.c | 1528 +++++++ unifiedkernel/fs/file.c | 505 +++ unifiedkernel/fs/mapping.c | 468 +++ unifiedkernel/fs/symlink.c | 231 ++ unifiedkernel/include/apc.h | 154 + unifiedkernel/include/area.h | 168 + unifiedkernel/include/attach.h | 54 + unifiedkernel/include/event.h | 85 + unifiedkernel/include/file.h | 428 ++ unifiedkernel/include/handle.h | 205 + unifiedkernel/include/io.h | 1304 ++++++ unifiedkernel/include/ke.h | 124 + unifiedkernel/include/mutex.h | 86 + unifiedkernel/include/ntstatus.h | 1104 ++++++ unifiedkernel/include/object.h | 840 ++++ unifiedkernel/include/objwait.h | 95 + unifiedkernel/include/pefile.h | 278 ++ unifiedkernel/include/process.h | 396 ++ unifiedkernel/include/section.h | 191 + unifiedkernel/include/semaphore.h | 75 + unifiedkernel/include/thread.h | 315 ++ unifiedkernel/include/unistr.h | 79 + unifiedkernel/include/virtual.h | 156 + unifiedkernel/include/w32syscall.h | 1504 +++++++ unifiedkernel/include/wcstr.h | 87 + unifiedkernel/include/win32.h | 1828 +++++++++ unifiedkernel/include/win32_process.h | 272 ++ unifiedkernel/include/wineserver/file.h | 191 + unifiedkernel/include/wineserver/info.h | 57 + unifiedkernel/include/wineserver/list.h | 184 + unifiedkernel/include/wineserver/reg.h | 233 ++ unifiedkernel/include/wineserver/request.h | 523 +++ unifiedkernel/include/wineserver/server.h | 53 + unifiedkernel/include/wineserver/uk_lib.h | 506 +++ unifiedkernel/include/wineserver/uk_protocol.h | 5061 ++++++++++++++++++++++++ unifiedkernel/include/wineserver/user.h | 168 + unifiedkernel/include/wineserver/wincon.h | 292 ++ unifiedkernel/include/wineserver/winerror.h | 2429 ++++++++++++ unifiedkernel/include/winuser.h | 1448 +++++++ unifiedkernel/include/wtypes.h | 543 +++ unifiedkernel/io/Makefile | 10 + unifiedkernel/io/dosdriver.c | 117 + unifiedkernel/io/file.c | 755 ++++ unifiedkernel/io/io.c | 215 + unifiedkernel/io/symlink.c | 59 + unifiedkernel/ke/Makefile | 22 + unifiedkernel/ke/apc.c | 550 +++ unifiedkernel/ke/binfmt_exeso.c | 854 ++++ unifiedkernel/ke/binfmt_pe.c | 832 ++++ unifiedkernel/ke/event.c | 570 +++ unifiedkernel/ke/misc.c | 81 + unifiedkernel/ke/mutex.c | 358 ++ unifiedkernel/ke/proc.c | 316 ++ unifiedkernel/ke/semaphore.c | 302 ++ unifiedkernel/ke/switch.S | 59 + unifiedkernel/ke/sysdll.c | 479 +++ unifiedkernel/ke/unistr.c | 300 ++ unifiedkernel/ke/w32entry.S | 516 +++ unifiedkernel/ke/w32init.c | 145 + unifiedkernel/ke/w32syscall.c | 2851 +++++++++++++ unifiedkernel/ke/wait.c | 477 +++ unifiedkernel/ke/wcstr.c | 268 ++ unifiedkernel/mm/Makefile | 12 + unifiedkernel/mm/attach.c | 187 + unifiedkernel/mm/datasection.c | 102 + unifiedkernel/mm/imagesection.c | 468 +++ unifiedkernel/mm/process.c | 383 ++ unifiedkernel/mm/section.c | 745 ++++ unifiedkernel/mm/virtual.c | 929 +++++ unifiedkernel/msg/Makefile | 14 + unifiedkernel/msg/atom.c | 484 +++ unifiedkernel/msg/class.c | 273 ++ unifiedkernel/msg/hook.c | 576 +++ unifiedkernel/msg/queue.c | 2188 ++++++++++ unifiedkernel/msg/region.c | 811 ++++ unifiedkernel/msg/user.c | 194 + unifiedkernel/msg/window.c | 2677 +++++++++++++ unifiedkernel/msg/winstation.c | 811 ++++ unifiedkernel/ob/Makefile | 14 + unifiedkernel/ob/dirobj.c | 356 ++ unifiedkernel/ob/display.c | 124 + unifiedkernel/ob/handle.c | 1095 +++++ unifiedkernel/ob/namespc.c | 261 ++ unifiedkernel/ob/ntobj.c | 371 ++ unifiedkernel/ob/object.c | 1676 ++++++++ unifiedkernel/ob/symlink.c | 328 ++ unifiedkernel/ob/wait.c | 282 ++ unifiedkernel/ps/Makefile | 15 + unifiedkernel/ps/cid.c | 202 + unifiedkernel/ps/flush.c | 212 + unifiedkernel/ps/kill.c | 166 + unifiedkernel/ps/process.c | 1051 +++++ unifiedkernel/ps/psmgr.c | 105 + unifiedkernel/ps/query.c | 640 +++ unifiedkernel/ps/suspend.c | 411 ++ unifiedkernel/ps/thread.c | 1345 +++++++ unifiedkernel/ps/token.c | 218 + unifiedkernel/pub/Makefile | 11 + unifiedkernel/pub/casemap.c | 1743 ++++++++ unifiedkernel/pub/error.c | 188 + unifiedkernel/pub/info.c | 195 + unifiedkernel/pub/request.c | 129 + unifiedkernel/pub/uk_lib.c | 1124 ++++++ unifiedkernel/reg/Makefile | 7 + unifiedkernel/reg/reg.c | 2275 +++++++++++ unifiedkernel/sock/Makefile | 7 + unifiedkernel/sock/sock.c | 1014 +++++ 122 files changed, 67785 insertions(+), 0 deletions(-) create mode 100644 unifiedkernel/Makefile create mode 100644 unifiedkernel/device/Makefile create mode 100644 unifiedkernel/device/clipboard.c create mode 100644 unifiedkernel/device/console.c create mode 100644 unifiedkernel/device/device.c create mode 100644 unifiedkernel/device/mailslot.c create mode 100644 unifiedkernel/device/named_pipe.c create mode 100644 unifiedkernel/device/serial.c create mode 100644 unifiedkernel/device/snapshot.c create mode 100644 unifiedkernel/device/timer.c create mode 100644 unifiedkernel/fs/Makefile create mode 100644 unifiedkernel/fs/async.c create mode 100644 unifiedkernel/fs/change.c create mode 100644 unifiedkernel/fs/completion.c create mode 100644 unifiedkernel/fs/directory.c create mode 100644 unifiedkernel/fs/fd.c create mode 100644 unifiedkernel/fs/file.c create mode 100644 unifiedkernel/fs/mapping.c create mode 100644 unifiedkernel/fs/symlink.c create mode 100644 unifiedkernel/include/apc.h create mode 100644 unifiedkernel/include/area.h create mode 100644 unifiedkernel/include/attach.h create mode 100644 unifiedkernel/include/event.h create mode 100644 unifiedkernel/include/file.h create mode 100644 unifiedkernel/include/handle.h create mode 100644 unifiedkernel/include/io.h create mode 100644 unifiedkernel/include/ke.h create mode 100644 unifiedkernel/include/mutex.h create mode 100644 unifiedkernel/include/ntstatus.h create mode 100644 unifiedkernel/include/object.h create mode 100644 unifiedkernel/include/objwait.h create mode 100644 unifiedkernel/include/pefile.h create mode 100644 unifiedkernel/include/process.h create mode 100644 unifiedkernel/include/section.h create mode 100644 unifiedkernel/include/semaphore.h create mode 100644 unifiedkernel/include/thread.h create mode 100644 unifiedkernel/include/unistr.h create mode 100644 unifiedkernel/include/virtual.h create mode 100644 unifiedkernel/include/w32syscall.h create mode 100644 unifiedkernel/include/wcstr.h create mode 100644 unifiedkernel/include/win32.h create mode 100644 unifiedkernel/include/win32_process.h create mode 100644 unifiedkernel/include/wineserver/file.h create mode 100644 unifiedkernel/include/wineserver/info.h create mode 100644 unifiedkernel/include/wineserver/list.h create mode 100644 unifiedkernel/include/wineserver/reg.h create mode 100644 unifiedkernel/include/wineserver/request.h create mode 100644 unifiedkernel/include/wineserver/server.h create mode 100644 unifiedkernel/include/wineserver/uk_lib.h create mode 100644 unifiedkernel/include/wineserver/uk_protocol.h create mode 100644 unifiedkernel/include/wineserver/user.h create mode 100644 unifiedkernel/include/wineserver/wincon.h create mode 100644 unifiedkernel/include/wineserver/winerror.h create mode 100644 unifiedkernel/include/winuser.h create mode 100644 unifiedkernel/include/wtypes.h create mode 100644 unifiedkernel/io/Makefile create mode 100644 unifiedkernel/io/dosdriver.c create mode 100644 unifiedkernel/io/file.c create mode 100644 unifiedkernel/io/io.c create mode 100644 unifiedkernel/io/symlink.c create mode 100644 unifiedkernel/ke/Makefile create mode 100644 unifiedkernel/ke/apc.c create mode 100644 unifiedkernel/ke/binfmt_exeso.c create mode 100644 unifiedkernel/ke/binfmt_pe.c create mode 100644 unifiedkernel/ke/event.c create mode 100644 unifiedkernel/ke/misc.c create mode 100644 unifiedkernel/ke/mutex.c create mode 100644 unifiedkernel/ke/proc.c create mode 100644 unifiedkernel/ke/semaphore.c create mode 100644 unifiedkernel/ke/switch.S create mode 100644 unifiedkernel/ke/sysdll.c create mode 100644 unifiedkernel/ke/unistr.c create mode 100644 unifiedkernel/ke/w32entry.S create mode 100644 unifiedkernel/ke/w32init.c create mode 100644 unifiedkernel/ke/w32syscall.c create mode 100644 unifiedkernel/ke/wait.c create mode 100644 unifiedkernel/ke/wcstr.c create mode 100644 unifiedkernel/mm/Makefile create mode 100644 unifiedkernel/mm/attach.c create mode 100644 unifiedkernel/mm/datasection.c create mode 100644 unifiedkernel/mm/imagesection.c create mode 100644 unifiedkernel/mm/process.c create mode 100644 unifiedkernel/mm/section.c create mode 100644 unifiedkernel/mm/virtual.c create mode 100644 unifiedkernel/msg/Makefile create mode 100644 unifiedkernel/msg/atom.c create mode 100644 unifiedkernel/msg/class.c create mode 100644 unifiedkernel/msg/hook.c create mode 100644 unifiedkernel/msg/queue.c create mode 100644 unifiedkernel/msg/region.c create mode 100644 unifiedkernel/msg/user.c create mode 100644 unifiedkernel/msg/window.c create mode 100644 unifiedkernel/msg/winstation.c create mode 100644 unifiedkernel/ob/Makefile create mode 100644 unifiedkernel/ob/dirobj.c create mode 100644 unifiedkernel/ob/display.c create mode 100644 unifiedkernel/ob/handle.c create mode 100644 unifiedkernel/ob/namespc.c create mode 100644 unifiedkernel/ob/ntobj.c create mode 100644 unifiedkernel/ob/object.c create mode 100644 unifiedkernel/ob/symlink.c create mode 100644 unifiedkernel/ob/wait.c create mode 100644 unifiedkernel/ps/Makefile create mode 100644 unifiedkernel/ps/cid.c create mode 100644 unifiedkernel/ps/flush.c create mode 100644 unifiedkernel/ps/kill.c create mode 100644 unifiedkernel/ps/process.c create mode 100644 unifiedkernel/ps/psmgr.c create mode 100644 unifiedkernel/ps/query.c create mode 100644 unifiedkernel/ps/suspend.c create mode 100644 unifiedkernel/ps/thread.c create mode 100644 unifiedkernel/ps/token.c create mode 100644 unifiedkernel/pub/Makefile create mode 100644 unifiedkernel/pub/casemap.c create mode 100644 unifiedkernel/pub/error.c create mode 100644 unifiedkernel/pub/info.c create mode 100644 unifiedkernel/pub/request.c create mode 100644 unifiedkernel/pub/uk_lib.c create mode 100644 unifiedkernel/reg/Makefile create mode 100644 unifiedkernel/reg/reg.c create mode 100644 unifiedkernel/sock/Makefile create mode 100644 unifiedkernel/sock/sock.c diff --git a/unifiedkernel/Makefile b/unifiedkernel/Makefile new file mode 100644 index 0000000..4d2e489 --- /dev/null +++ b/unifiedkernel/Makefile @@ -0,0 +1,49 @@ +# +# Makefile for unified kernel module in the top level directory +# + +SUB_DIRS:= ke/ \ + io/ \ + ob/ \ + ps/ \ + mm/ \ + pub/ \ + reg/ \ + msg/ \ + fs/ \ + sock/ \ + device/ + +MODULE = unifiedkernel +MOD_O = $(MODULE).o +MOD_KO = $(MODULE).ko +MOD_MOD = $(MODULE).mod +KERNEL_VER = `uname -r` +MKFILES = $(addprefix $(PWD)/, $(addsuffix Makefile, $(SUB_DIRS))) + +ifneq ($(KERNELRELEASE),) +include $(MKFILES) + obj-m := $(MODULE).o +else + KDIR := /lib/modules/$(KERNEL_VER)/build + PWD := `pwd` + + +default: + $(MAKE) -Wall -C $(KDIR) SUBDIRS=$(PWD) EXTRA_CFLAGS="-I$(PWD)/include" modules + +clean: + @echo CLEANING: Module files + @rm -rf $(MOD_O) .$(MOD_O).cmd \ + $(MOD_KO) .$(MOD_KO).cmd \ + $(MOD_MOD).c $(MOD_MOD).o .$(MOD_MOD).o.cmd\ + .tmp_versions Module.* modules.* + + @echo CLEANING: object files + @rm -f $(addsuffix *.o, $(SUB_DIRS)) + @rm -f $(addsuffix *.ko, $(SUB_DIRS)) + @rm -f $(addsuffix .*.o.cmd, $(SUB_DIRS)) + @echo make clean done! + +endif + diff --git a/unifiedkernel/device/Makefile b/unifiedkernel/device/Makefile new file mode 100644 index 0000000..da45f43 --- /dev/null +++ b/unifiedkernel/device/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for device management +# + +DEVICE_OBJS := clipboard.o \ + console.o \ + named_pipe.o \ + mailslot.o \ + device.o \ + timer.o \ + snapshot.o \ + serial.o + +$(MODULE)-objs += $(addprefix device/, $(DEVICE_OBJS)) diff --git a/unifiedkernel/device/clipboard.c b/unifiedkernel/device/clipboard.c new file mode 100644 index 0000000..ebd3860 --- /dev/null +++ b/unifiedkernel/device/clipboard.c @@ -0,0 +1,234 @@ +/* + * clipboard.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * clipboard.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct clipboard +{ + struct object obj; /* object header */ + struct w32thread *open_thread; /* thread id that has clipboard open */ + user_handle_t open_win; /* window that has clipboard open */ + struct w32thread *owner_thread; /* thread id that owns the clipboard */ + user_handle_t owner_win; /* window that owns the clipboard data */ + user_handle_t viewer; /* first window in clipboard viewer list */ + unsigned int seqno; /* clipboard change sequence number */ + time_t seqno_timestamp; /* time stamp of last seqno increment */ +}; + +static void clipboard_dump( struct object *obj, int verbose ); + +static const struct object_ops clipboard_ops = +{ + sizeof(struct clipboard), /* size */ + clipboard_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + + +#define MINUPDATELAPSE 2 + +/* dump a clipboard object */ +static void clipboard_dump( struct object *obj, int verbose ) +{ +#if 0 + struct clipboard *clipboard = (struct clipboard *)obj; + + fprintf( stderr, "Clipboard open_thread=%p open_win=%p owner_thread=%p owner_win=%p viewer=%p seq=%u\n", + clipboard->open_thread, clipboard->open_win, clipboard->owner_thread, + clipboard->owner_win, clipboard->viewer, clipboard->seqno ); +#endif +} + +/* retrieve the clipboard info for the current process, allocating it if needed */ +static struct clipboard *get_process_clipboard(void) +{ + struct clipboard *clipboard; + struct winstation *winstation = get_process_winstation( get_current_w32process(), WINSTA_ACCESSCLIPBOARD ); + + if (!winstation) + return NULL; + + if (!(clipboard = winstation->clipboard)) { + if ((clipboard = alloc_wine_object( &clipboard_ops ))) { + clipboard->open_thread = NULL; + clipboard->open_win = 0; + clipboard->owner_thread = NULL; + clipboard->owner_win = 0; + clipboard->viewer = 0; + clipboard->seqno = 0; + clipboard->seqno_timestamp = 0; + winstation->clipboard = clipboard; + } + } + release_object( winstation ); + return clipboard; +} + + +/* Called when thread terminates to allow release of clipboard */ +void cleanup_clipboard_thread(struct w32thread *thread) +{ + struct clipboard *clipboard; + struct winstation *winstation = get_process_winstation( thread->process, WINSTA_ACCESSCLIPBOARD ); + + if (!winstation) + return; + + if ((clipboard = winstation->clipboard)) { + if (thread == clipboard->open_thread) { + clipboard->open_win = 0; + clipboard->open_thread = NULL; + } + if (thread == clipboard->owner_thread) { + clipboard->owner_win = 0; + clipboard->owner_thread = NULL; + } + } + release_object( winstation ); +} + +static int set_clipboard_window( struct clipboard *clipboard, user_handle_t win, int clear ) +{ + if (clipboard->open_thread && clipboard->open_thread != current_thread) { + set_error(STATUS_WAS_LOCKED); + return 0; + } + else if (!clear) { + clipboard->open_win = win; + clipboard->open_thread = current_thread; + } + else { + clipboard->open_thread = NULL; + clipboard->open_win = 0; + } + return 1; +} + + +static int set_clipboard_owner( struct clipboard *clipboard, user_handle_t win, int clear ) +{ + if (clipboard->open_thread && clipboard->open_thread->process != get_current_w32process()) { + set_error(STATUS_WAS_LOCKED); + return 0; + } + else if (!clear) { + clipboard->owner_win = win; + clipboard->owner_thread = current_thread; + } + else { + clipboard->owner_win = 0; + clipboard->owner_thread = NULL; + } + return 1; +} + + +static int get_seqno( struct clipboard *clipboard ) +{ + time_t tm = time(NULL); + + if (!clipboard->owner_thread && (tm > (clipboard->seqno_timestamp + MINUPDATELAPSE))) { + clipboard->seqno_timestamp = tm; + clipboard->seqno++; + } + return clipboard->seqno; +} + + +DECL_HANDLER(set_clipboard_info) +{ + struct clipboard *clipboard = get_process_clipboard(); + + if (!clipboard) + return; + + reply->old_clipboard = clipboard->open_win; + reply->old_owner = clipboard->owner_win; + reply->old_viewer = clipboard->viewer; + + if (req->flags & SET_CB_OPEN) { + if (clipboard->open_thread) { + /* clipboard already opened */ + set_error(STATUS_WAS_LOCKED); + return; + } + + if (!set_clipboard_window( clipboard, req->clipboard, 0 )) return; + } + else if (req->flags & SET_CB_CLOSE) { + if (clipboard->open_thread != current_thread) { + set_win32_error(ERROR_CLIPBOARD_NOT_OPEN); + return; + } + + if (!set_clipboard_window( clipboard, 0, 1 )) return; + } + + if (req->flags & SET_CB_OWNER) { + if (!set_clipboard_owner( clipboard, req->owner, 0 )) return; + } + else if (req->flags & SET_CB_RELOWNER) { + if (!set_clipboard_owner( clipboard, 0, 1 )) return; + } + + if (req->flags & SET_CB_VIEWER) clipboard->viewer = req->viewer; + + if (req->flags & SET_CB_SEQNO) clipboard->seqno++; + + reply->seqno = get_seqno( clipboard ); + + if (clipboard->open_thread == current_thread) reply->flags |= CB_OPEN; + if (clipboard->owner_thread == current_thread) reply->flags |= CB_OWNER; + if (clipboard->owner_thread && clipboard->owner_thread->process == get_current_w32process()) + reply->flags |= CB_PROCESS; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/device/console.c b/unifiedkernel/device/console.c new file mode 100644 index 0000000..ae13878 --- /dev/null +++ b/unifiedkernel/device/console.c @@ -0,0 +1,1588 @@ +/* + * console.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * console.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/wincon.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* specific access rights (FIXME: should use finer-grained access rights) */ +#define CONSOLE_READ 0x01 +#define CONSOLE_WRITE 0x02 + +struct screen_buffer; +struct console_input_events; + +struct console_input +{ + struct object obj; /* object header */ + int num_proc; /* number of processes attached to this console */ + struct w32thread *renderer; /* console renderer thread */ + int mode; /* input mode */ + struct screen_buffer *active; /* active screen buffer */ + int recnum; /* number of input records */ + INPUT_RECORD *records; /* input records */ + struct console_input_events *evt; /* synchronization event with renderer */ + WCHAR *title; /* console title */ + WCHAR **history; /* lines history */ + int history_size; /* number of entries in history array */ + int history_index; /* number of used entries in history array */ + int history_mode; /* mode of history (non zero means remove doubled strings */ + int edition_mode; /* index to edition mode flavors */ + int input_cp; /* console input codepage */ + int output_cp; /* console output codepage */ + user_handle_t win; /* window handle if backend supports it */ + struct kevent *event; /* event to wait on for input queue */ +}; + +static unsigned int console_map_access( struct object *obj, unsigned int access ); + +static void console_input_dump( struct object *obj, int verbose ); +static void console_input_destroy( struct object *obj ); + +static const struct object_ops console_input_ops = +{ + sizeof(struct console_input), /* size */ + console_input_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + console_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + console_input_destroy /* destroy */ +}; + +static void console_input_events_dump( struct object *obj, int verbose ); +static void console_input_events_destroy( struct object *obj ); + +struct console_input_events +{ + struct object obj; /* object header */ + int num_alloc; /* number of allocated events */ + int num_used; /* number of actually used events */ + struct console_renderer_event* events; +}; + +static const struct object_ops console_input_events_ops = +{ + sizeof(struct console_input_events), /* size */ + console_input_events_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + console_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + console_input_events_destroy /* destroy */ +}; + +struct screen_buffer +{ + struct object obj; /* object header */ + struct list_head entry; /* entry in list of all screen buffers */ + struct console_input *input; /* associated console input */ + int mode; /* output mode */ + int cursor_size; /* size of cursor (percentage filled) */ + int cursor_visible;/* cursor visibility flag */ + int cursor_x; /* position of cursor */ + int cursor_y; /* position of cursor */ + int width; /* size (w-h) of the screen buffer */ + int height; + int max_width; /* size (w-h) of the window given font size */ + int max_height; + char_info_t *data; /* the data for each cell - a width x height matrix */ + unsigned short attr; /* default attribute for screen buffer */ + rectangle_t win; /* current visible window on the screen buffer * + * as seen in wineconsole */ +}; + +static void screen_buffer_dump( struct object *obj, int verbose ); +static void screen_buffer_destroy( struct object *obj ); + +static const struct object_ops screen_buffer_ops = +{ + sizeof(struct screen_buffer), /* size */ + screen_buffer_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + console_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + screen_buffer_destroy /* destroy */ +}; + +static struct list_head screen_buffer_list = LIST_INIT(screen_buffer_list); + +static const char_info_t empty_char_info = { ' ', 0x000f }; /* white on black space */ + +/* access mapping for all console objects */ +static unsigned int console_map_access( struct object *obj, unsigned int access ) +{ + if (access & GENERIC_READ) + access |= SYNCHRONIZE | STANDARD_RIGHTS_READ | CONSOLE_READ; + if (access & GENERIC_WRITE) + access |= SYNCHRONIZE | STANDARD_RIGHTS_WRITE | CONSOLE_WRITE; + if (access & GENERIC_EXECUTE) + access |= SYNCHRONIZE | STANDARD_RIGHTS_EXECUTE; + if (access & GENERIC_ALL) + access |= STANDARD_RIGHTS_ALL | CONSOLE_READ | CONSOLE_WRITE; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +/* dumps the renderer events of a console */ +static void console_input_events_dump( struct object *obj, int verbose ) +{ +#if 0 + struct console_input_events *evts = (struct console_input_events *)obj; + assert( obj->ops == &console_input_events_ops ); + fprintf( stderr, "Console input events: %d/%d events\n", + evts->num_used, evts->num_alloc ); +#endif +} + +/* destroys the renderer events of a console */ +static void console_input_events_destroy( struct object *obj ) +{ + struct console_input_events *evts = (struct console_input_events *)obj; +#if 0 + assert( obj->ops == &console_input_events_ops ); +#endif + free( evts->events ); +} + +/* add an event to the console's renderer events list */ +static void console_input_events_append( struct console_input_events* evts, + struct console_renderer_event* evt) +{ + int collapsed = FALSE; + + /* to be done even when evt has been generated by the rendere ? */ + + /* try to collapse evt into current queue's events */ + if (evts->num_used) { + struct console_renderer_event* last = &evts->events[evts->num_used - 1]; + + if (last->event == CONSOLE_RENDERER_UPDATE_EVENT && + evt->event == CONSOLE_RENDERER_UPDATE_EVENT) { + /* if two update events overlap, collapse them into a single one */ + if (last->u.update.bottom + 1 >= evt->u.update.top && + evt->u.update.bottom + 1 >= last->u.update.top) { + last->u.update.top = min(last->u.update.top, evt->u.update.top); + last->u.update.bottom = max(last->u.update.bottom, evt->u.update.bottom); + collapsed = TRUE; + } + } + } + if (!collapsed) { + if (evts->num_used == evts->num_alloc) { + int old_size = evts->num_alloc; + evts->num_alloc += 16; + evts->events = realloc( evts->events, evts->num_alloc * sizeof(*evt), old_size * sizeof(*evt) ); +#if 0 + assert(evts->events); +#endif + } + evts->events[evts->num_used++] = *evt; + } + uk_wake_up( &evts->obj, 0 ); +} + +/* retrieves events from the console's renderer events list */ +static void console_input_events_get( struct console_input_events* evts ) +{ + data_size_t num = get_reply_max_size() / sizeof(evts->events[0]); + + if (num > evts->num_used) + num = evts->num_used; + set_reply_data( evts->events, num * sizeof(evts->events[0]) ); + if (num < evts->num_used) { + memmove( &evts->events[0], &evts->events[num], + (evts->num_used - num) * sizeof(evts->events[0]) ); + } + evts->num_used -= num; +} + +static struct console_input_events *create_console_input_events(void) +{ + struct console_input_events* evt; + + if (!(evt = alloc_wine_object( &console_input_events_ops ))) + return NULL; + evt->num_alloc = evt->num_used = 0; + evt->events = NULL; + return evt; +} + +static struct object *create_console_input( struct w32thread* renderer ) +{ + struct console_input *console_input; + + if (!(console_input = alloc_wine_object( &console_input_ops ))) + return NULL; + console_input->renderer = renderer; + console_input->mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | + ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT; + console_input->num_proc = 0; + console_input->active = NULL; + console_input->recnum = 0; + console_input->records = NULL; + console_input->evt = create_console_input_events(); + console_input->title = NULL; + console_input->history_size = 50; + console_input->history = calloc( console_input->history_size, sizeof(WCHAR*) ); + console_input->history_index = 0; + console_input->history_mode = 0; + console_input->edition_mode = 0; + console_input->input_cp = 0; + console_input->output_cp = 0; + console_input->win = 0; + console_input->event = create_event( NULL, NULL, 0, 1, 0, NULL ); + + if (!console_input->history || !console_input->evt) { + release_object( console_input ); + return NULL; + } + return &console_input->obj; +} + +static void generate_sb_initial_events( struct console_input *console_input ) +{ + struct screen_buffer *screen_buffer = console_input->active; + struct console_renderer_event evt; + + evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT; + memset(&evt.u, 0, sizeof(evt.u)); + console_input_events_append( console_input->evt, &evt ); + + evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT; + evt.u.resize.width = screen_buffer->width; + evt.u.resize.height = screen_buffer->height; + console_input_events_append( console_input->evt, &evt ); + + evt.event = CONSOLE_RENDERER_DISPLAY_EVENT; + evt.u.display.left = screen_buffer->win.left; + evt.u.display.top = screen_buffer->win.top; + evt.u.display.width = screen_buffer->win.right - screen_buffer->win.left + 1; + evt.u.display.height = screen_buffer->win.bottom - screen_buffer->win.top + 1; + console_input_events_append( console_input->evt, &evt ); + + evt.event = CONSOLE_RENDERER_UPDATE_EVENT; + evt.u.update.top = 0; + evt.u.update.bottom = screen_buffer->height - 1; + console_input_events_append( console_input->evt, &evt ); + + evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT; + evt.u.cursor_geom.size = screen_buffer->cursor_size; + evt.u.cursor_geom.visible = screen_buffer->cursor_visible; + console_input_events_append( console_input->evt, &evt ); + + evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT; + evt.u.cursor_pos.x = screen_buffer->cursor_x; + evt.u.cursor_pos.y = screen_buffer->cursor_y; + console_input_events_append( console_input->evt, &evt ); +} + +static struct screen_buffer *create_console_output( struct console_input *console_input ) +{ + struct screen_buffer *screen_buffer; + int i; + + if (!(screen_buffer = alloc_wine_object( &screen_buffer_ops ))) + return NULL; + screen_buffer->mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; + screen_buffer->input = console_input; + screen_buffer->cursor_size = 100; + screen_buffer->cursor_visible = 1; + screen_buffer->width = 80; + screen_buffer->height = 150; + screen_buffer->max_width = 80; + screen_buffer->max_height = 25; + screen_buffer->cursor_x = 0; + screen_buffer->cursor_y = 0; + screen_buffer->attr = 0x0F; + screen_buffer->win.left = 0; + screen_buffer->win.right = screen_buffer->max_width - 1; + screen_buffer->win.top = 0; + screen_buffer->win.bottom = screen_buffer->max_height - 1; + + list_add_head( &screen_buffer_list, &screen_buffer->entry ); + + if (!(screen_buffer->data = malloc( screen_buffer->width * screen_buffer->height * + sizeof(*screen_buffer->data) ))) { + release_object( screen_buffer ); + return NULL; + } + /* clear the first row */ + for (i = 0; i < screen_buffer->width; i++) + screen_buffer->data[i] = empty_char_info; + /* and copy it to all other rows */ + for (i = 1; i < screen_buffer->height; i++) + memcpy( &screen_buffer->data[i * screen_buffer->width], screen_buffer->data, + screen_buffer->width * sizeof(char_info_t) ); + + if (!console_input->active) { + console_input->active = (struct screen_buffer*)grab_object( screen_buffer ); + generate_sb_initial_events( console_input ); + } + return screen_buffer; +} + +/* free the console for this process */ +int free_console( struct w32process *process ) +{ + struct console_input* console = process->console; + + if (!console || !console->renderer) + return 0; + + process->console = NULL; + if (--console->num_proc == 0) { + /* all processes have terminated... tell the renderer to terminate too */ + struct console_renderer_event evt; + evt.event = CONSOLE_RENDERER_EXIT_EVENT; + memset(&evt.u, 0, sizeof(evt.u)); + console_input_events_append( console->evt, &evt ); + } + release_object( console ); + + return 1; +} + +extern void clear_error(void); + +/* let process inherit the console from parent... this handle two cases : + * 1/ generic console inheritance + * 2/ parent is a renderer which launches process, and process should attach to the console + * renderered by parent + */ +void inherit_console(struct w32thread *parent_thread, struct w32process *process, obj_handle_t hconin) +{ + int done = 0; + struct w32process* parent = parent_thread->process; + + /* if parent is a renderer, then attach current process to its console + * a bit hacky.... + */ + if (hconin) { + struct console_input* console; + + /* FIXME: should we check some access rights ? */ + if ((console = (struct console_input*)get_wine_handle_obj( parent, hconin, + 0, &console_input_ops ))) { + if (console->renderer == parent_thread) { + process->console = (struct console_input*)grab_object( console ); + process->console->num_proc++; + done = 1; + } + release_object( console ); + } + else clear_error(); /* ignore error */ + } + /* otherwise, if parent has a console, attach child to this console */ + if (!done && parent->console) { +#if 0 + assert(parent->console->renderer); +#endif + process->console = (struct console_input*)grab_object( parent->console ); + process->console->num_proc++; + } +} + +struct w32thread *console_get_renderer( struct console_input *console ) +{ + return console->renderer; +} + +static struct console_input* console_input_get( obj_handle_t handle, unsigned access ) +{ + struct console_input* console = NULL; + + if (handle) + console = (struct console_input *)get_wine_handle_obj( get_current_w32process(), handle, + access, &console_input_ops ); + else if (get_current_w32process()->console) { +#if 0 + assert( current->process->console->renderer ); +#endif + console = (struct console_input *)grab_object( get_current_w32process()->console ); + } + + if (!console && !get_error()) + set_error(STATUS_INVALID_PARAMETER); + return console; +} + +struct console_signal_info +{ + struct console_input *console; + process_id_t group; + int signal; +}; + +extern struct ethread *thread2ethread(struct w32thread *); + +static int propagate_console_signal_cb(struct w32process *process, void *user) +{ + struct console_signal_info* csi = (struct console_signal_info*)user; + + if (process->console == csi->console && process->running_threads && + (!csi->group || process->group_id == csi->group)) { + /* find a suitable thread to signal */ +#ifndef SERVER_PM + struct w32thread *thread; + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct w32thread, proc_entry ) { + if (send_thread_signal( thread2ethread(thread), csi->signal )) + break; + } +#else + struct eprocess *eprocess = process2eprocess(process); + struct ethread * ethread; + LIST_FOR_EACH_ENTRY( ethread, &eprocess->thread_list_head, struct ethread, thread_list_entry) { + if (send_thread_signal( ethread, csi->signal )) + break; + } +#endif + } + return FALSE; +} + +static void propagate_console_signal( struct console_input *console, + int sig, process_id_t group_id ) +{ + struct console_signal_info csi; + + if (!console) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + /* FIXME: should support the other events (like CTRL_BREAK) */ + if (sig != CTRL_C_EVENT) { + set_error( STATUS_NOT_IMPLEMENTED ); + return; + } + csi.console = console; + csi.signal = SIGINT; + csi.group = group_id; + + enum_processes(propagate_console_signal_cb, &csi); +} + +static int get_console_mode( obj_handle_t handle ) +{ + struct object *obj; + int ret = 0; + + if ((obj = get_wine_handle_obj( get_current_w32process(), handle, CONSOLE_READ, NULL ))) { + if (BODY_TO_HEADER(obj)->ops == &console_input_ops) + ret = ((struct console_input *)obj)->mode; + else if (BODY_TO_HEADER(obj)->ops == &screen_buffer_ops) + ret = ((struct screen_buffer *)obj)->mode; + else + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + release_object( obj ); + } + return ret; +} + +/* changes the mode of either a console input or a screen buffer */ +static int set_console_mode( obj_handle_t handle, int mode ) +{ + struct object *obj; + int ret = 0; + + if (!(obj = get_wine_handle_obj( get_current_w32process(), handle, CONSOLE_WRITE, NULL ))) + return 0; + if (BODY_TO_HEADER(obj)->ops == &console_input_ops) { + /* FIXME: if we remove the edit mode bits, we need (???) to clean up the history */ + ((struct console_input *)obj)->mode = mode; + ret = 1; + } + else if (BODY_TO_HEADER(obj)->ops == &screen_buffer_ops) { + ((struct screen_buffer *)obj)->mode = mode; + ret = 1; + } + else set_error( STATUS_OBJECT_TYPE_MISMATCH ); + release_object( obj ); + return ret; +} + +/* add input events to a console input queue */ +static int write_console_input( struct console_input* console, int count, + const INPUT_RECORD *records ) +{ + INPUT_RECORD *new_rec; + + if (!count) + return 0; + if (!(new_rec = realloc( console->records, + (console->recnum + count) * sizeof(INPUT_RECORD),console->recnum * sizeof(INPUT_RECORD) ))) { + set_error( STATUS_NO_MEMORY ); + release_object( console ); + return -1; + } + console->records = new_rec; + memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) ); + + if (console->mode & ENABLE_PROCESSED_INPUT) { + int i = 0; + while (i < count) { + if (records[i].EventType == KEY_EVENT && + records[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 && + !(records[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY)) { + if (i != count - 1) + memcpy( &console->records[console->recnum + i], + &console->records[console->recnum + i + 1], + (count - i - 1) * sizeof(INPUT_RECORD) ); + count--; + if (records[i].Event.KeyEvent.bKeyDown) { + /* send SIGINT to all processes attached to this console */ + propagate_console_signal( console, CTRL_C_EVENT, 0 ); + } + } + else i++; + } + } + if (!console->recnum && count) + set_event( console->event, EVENT_INCREMENT, FALSE ); + console->recnum += count; + return count; +} + +/* retrieve a pointer to the console input records */ +static int read_console_input( obj_handle_t handle, int count, int flush ) +{ + struct console_input *console; + + if (!(console = (struct console_input *)get_wine_handle_obj( get_current_w32process(), handle, + CONSOLE_READ, &console_input_ops ))) + return -1; + + if (!count) { + /* special case: do not retrieve anything, but return + * the total number of records available */ + count = console->recnum; + } + else { + if (count > console->recnum) count = console->recnum; + set_reply_data( console->records, count * sizeof(INPUT_RECORD) ); + } + if (flush) { + int i, old_size; + for (i = count; i < console->recnum; i++) + console->records[i-count] = console->records[i]; + old_size = console->recnum; + if ((console->recnum -= count) > 0) { + INPUT_RECORD *new_rec = realloc( console->records, + console->recnum * sizeof(INPUT_RECORD), old_size * sizeof(INPUT_RECORD) ); + if (new_rec) + console->records = new_rec; + } + else { + free( console->records ); + console->records = NULL; + reset_event( console->event ); + } + } + release_object( console ); + return count; +} + +/* set misc console input information */ +static int set_console_input_info( const struct set_console_input_info_request *req, + const WCHAR *title, data_size_t len ) +{ + struct console_input *console; + struct console_renderer_event evt; + + if (!(console = console_input_get( req->handle, CONSOLE_WRITE ))) + goto error; + + memset(&evt.u, 0, sizeof(evt.u)); + if (req->mask & SET_CONSOLE_INPUT_INFO_ACTIVE_SB) { + struct screen_buffer *screen_buffer; + + screen_buffer = (struct screen_buffer *)get_wine_handle_obj( get_current_w32process(), req->active_sb, + CONSOLE_WRITE, &screen_buffer_ops ); + if (!screen_buffer || screen_buffer->input != console) { + set_error( STATUS_INVALID_HANDLE ); + if (screen_buffer) + release_object( screen_buffer ); + goto error; + } + + if (screen_buffer != console->active) { + if (console->active) + release_object( console->active ); + console->active = screen_buffer; + generate_sb_initial_events( console ); + } + else + release_object( screen_buffer ); + } + if (req->mask & SET_CONSOLE_INPUT_INFO_TITLE) { + WCHAR *new_title = mem_alloc( len + sizeof(WCHAR) ); + if (new_title) { + memcpy( new_title, title, len ); + new_title[len / sizeof(WCHAR)] = 0; + free( console->title ); + console->title = new_title; + evt.event = CONSOLE_RENDERER_TITLE_EVENT; + console_input_events_append( console->evt, &evt ); + } + } + if (req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_MODE) { + console->history_mode = req->history_mode; + } + if ((req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_SIZE) && + console->history_size != req->history_size) { + WCHAR** mem = NULL; + int i; + int delta; + + if (req->history_size) { + mem = mem_alloc( req->history_size * sizeof(WCHAR*) ); + if (!mem) + goto error; + memset( mem, 0, req->history_size * sizeof(WCHAR*) ); + } + + delta = (console->history_index > req->history_size) ? + (console->history_index - req->history_size) : 0; + + for (i = delta; i < console->history_index; i++) { + mem[i - delta] = console->history[i]; + console->history[i] = NULL; + } + console->history_index -= delta; + + for (i = 0; i < console->history_size; i++) + free( console->history[i] ); + free( console->history ); + console->history = mem; + console->history_size = req->history_size; + } + if (req->mask & SET_CONSOLE_INPUT_INFO_EDITION_MODE) { + console->edition_mode = req->edition_mode; + } + if (req->mask & SET_CONSOLE_INPUT_INFO_INPUT_CODEPAGE) { + console->input_cp = req->input_cp; + } + if (req->mask & SET_CONSOLE_INPUT_INFO_OUTPUT_CODEPAGE) { + console->output_cp = req->output_cp; + } + if (req->mask & SET_CONSOLE_INPUT_INFO_WIN) { + console->win = req->win; + } + release_object( console ); + return 1; +error: + if (console) + release_object( console ); + return 0; +} + +/* resize a screen buffer */ +static int change_screen_buffer_size( struct screen_buffer *screen_buffer, + int new_width, int new_height ) +{ + int i, old_width, old_height, copy_width, copy_height; + char_info_t *new_data; + + if (!(new_data = malloc( new_width * new_height * sizeof(*new_data) ))) { + set_error( STATUS_NO_MEMORY ); + return 0; + } + old_width = screen_buffer->width; + old_height = screen_buffer->height; + copy_width = min( old_width, new_width ); + copy_height = min( old_height, new_height ); + + /* copy all the rows */ + for (i = 0; i < copy_height; i++) { + memcpy( &new_data[i * new_width], &screen_buffer->data[i * old_width], + copy_width * sizeof(char_info_t) ); + } + + /* clear the end of each row */ + if (new_width > old_width) { + /* fill first row */ + for (i = old_width; i < new_width; i++) + new_data[i] = empty_char_info; + /* and blast it to the other rows */ + for (i = 1; i < copy_height; i++) + memcpy( &new_data[i * new_width + old_width], &new_data[old_width], + (new_width - old_width) * sizeof(char_info_t) ); + } + + /* clear remaining rows */ + if (new_height > old_height) { + /* fill first row */ + for (i = 0; i < new_width; i++) + new_data[old_height * new_width + i] = empty_char_info; + /* and blast it to the other rows */ + for (i = old_height+1; i < new_height; i++) + memcpy( &new_data[i * new_width], &new_data[old_height * new_width], + new_width * sizeof(char_info_t) ); + } + free( screen_buffer->data ); + screen_buffer->data = new_data; + screen_buffer->width = new_width; + screen_buffer->height = new_height; + return 1; +} + +/* set misc screen buffer information */ +static int set_console_output_info( struct screen_buffer *screen_buffer, + const struct set_console_output_info_request *req ) +{ + struct console_renderer_event evt; + + memset(&evt.u, 0, sizeof(evt.u)); + if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM) { + if (req->cursor_size < 1 || req->cursor_size > 100) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + if (screen_buffer->cursor_size != req->cursor_size || + screen_buffer->cursor_visible != req->cursor_visible) { + screen_buffer->cursor_size = req->cursor_size; + screen_buffer->cursor_visible = req->cursor_visible; + evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT; + evt.u.cursor_geom.size = req->cursor_size; + evt.u.cursor_geom.visible = req->cursor_visible; + console_input_events_append( screen_buffer->input->evt, &evt ); + } + } + if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_POS) { + if (req->cursor_x < 0 || req->cursor_x >= screen_buffer->width || + req->cursor_y < 0 || req->cursor_y >= screen_buffer->height) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + if (screen_buffer->cursor_x != req->cursor_x || screen_buffer->cursor_y != req->cursor_y) { + screen_buffer->cursor_x = req->cursor_x; + screen_buffer->cursor_y = req->cursor_y; + evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT; + evt.u.cursor_pos.x = req->cursor_x; + evt.u.cursor_pos.y = req->cursor_y; + console_input_events_append( screen_buffer->input->evt, &evt ); + } + } + if (req->mask & SET_CONSOLE_OUTPUT_INFO_SIZE) { + unsigned cc; + + /* new screen-buffer cannot be smaller than actual window */ + if (req->width < screen_buffer->win.right - screen_buffer->win.left + 1 || + req->height < screen_buffer->win.bottom - screen_buffer->win.top + 1) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + /* FIXME: there are also some basic minimum and max size to deal with */ + if (!change_screen_buffer_size( screen_buffer, req->width, req->height )) + return 0; + + evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT; + evt.u.resize.width = req->width; + evt.u.resize.height = req->height; + console_input_events_append( screen_buffer->input->evt, &evt ); + + evt.event = CONSOLE_RENDERER_UPDATE_EVENT; + evt.u.update.top = 0; + evt.u.update.bottom = screen_buffer->height - 1; + console_input_events_append( screen_buffer->input->evt, &evt ); + + /* scroll window to display sb */ + if (screen_buffer->win.right >= req->width) { + screen_buffer->win.right -= screen_buffer->win.left; + screen_buffer->win.left = 0; + } + if (screen_buffer->win.bottom >= req->height) { + screen_buffer->win.bottom -= screen_buffer->win.top; + screen_buffer->win.top = 0; + } + /* reset cursor if needed (normally, if cursor was outside of new sb, the + * window has been shifted so that the new position of the cursor will be + * visible */ + cc = 0; + if (screen_buffer->cursor_x >= req->width) { + screen_buffer->cursor_x = req->width - 1; + cc++; + } + if (screen_buffer->cursor_y >= req->height) { + screen_buffer->cursor_y = req->height - 1; + cc++; + } + if (cc) { + evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT; + evt.u.cursor_pos.x = req->cursor_x; + evt.u.cursor_pos.y = req->cursor_y; + console_input_events_append( screen_buffer->input->evt, &evt ); + } + + if (screen_buffer == screen_buffer->input->active && + screen_buffer->input->mode & ENABLE_WINDOW_INPUT) { + INPUT_RECORD ir; + ir.EventType = WINDOW_BUFFER_SIZE_EVENT; + ir.Event.WindowBufferSizeEvent.dwSize.X = req->width; + ir.Event.WindowBufferSizeEvent.dwSize.Y = req->height; + write_console_input( screen_buffer->input, 1, &ir ); + } + } + if (req->mask & SET_CONSOLE_OUTPUT_INFO_ATTR) { + screen_buffer->attr = req->attr; + } + if (req->mask & SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW) { + if (req->win_left < 0 || req->win_left > req->win_right || + req->win_right >= screen_buffer->width || + req->win_top < 0 || req->win_top > req->win_bottom || + req->win_bottom >= screen_buffer->height) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + if (screen_buffer->win.left != req->win_left || screen_buffer->win.top != req->win_top || + screen_buffer->win.right != req->win_right || screen_buffer->win.bottom != req->win_bottom) { + screen_buffer->win.left = req->win_left; + screen_buffer->win.top = req->win_top; + screen_buffer->win.right = req->win_right; + screen_buffer->win.bottom = req->win_bottom; + evt.event = CONSOLE_RENDERER_DISPLAY_EVENT; + evt.u.display.left = req->win_left; + evt.u.display.top = req->win_top; + evt.u.display.width = req->win_right - req->win_left + 1; + evt.u.display.height = req->win_bottom - req->win_top + 1; + console_input_events_append( screen_buffer->input->evt, &evt ); + } + } + if (req->mask & SET_CONSOLE_OUTPUT_INFO_MAX_SIZE) { + /* can only be done by renderer */ + if (get_current_w32process()->console != screen_buffer->input) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + + screen_buffer->max_width = req->max_width; + screen_buffer->max_height = req->max_height; + } + + return 1; +} + +/* appends a new line to history (history is a fixed size array) */ +static void console_input_append_hist( struct console_input* console, const WCHAR* buf, data_size_t len ) +{ + WCHAR* ptr = mem_alloc( (len + 1) * sizeof(WCHAR) ); + + if (!ptr) + return; + + if (!console || !console->history_size) { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + free( ptr ); + return; + } + + memcpy( ptr, buf, len * sizeof(WCHAR) ); + ptr[len] = 0; + + if (console->history_mode && console->history_index && + strncmpW( console->history[console->history_index - 1], ptr, len * sizeof(WCHAR) ) == 0) { + /* ok, mode ask us to not use twice the same string... + * * so just free mem and returns + */ + set_error( STATUS_ALIAS_EXISTS ); + free(ptr); + return; + } + + if (console->history_index < console->history_size) { + console->history[console->history_index++] = ptr; + } + else { + free( console->history[0]) ; + memmove( &console->history[0], &console->history[1], + (console->history_size - 1) * sizeof(WCHAR*) ); + console->history[console->history_size - 1] = ptr; + } +} + +/* returns a line from the cache */ +static data_size_t console_input_get_hist( struct console_input *console, int index ) +{ + data_size_t ret = 0; + + if (index >= console->history_index) + set_error( STATUS_INVALID_PARAMETER ); + else { + ret = strlenW( console->history[index] ) * sizeof(WCHAR); + set_reply_data( console->history[index], min( ret, get_reply_max_size() )); + } + return ret; +} + +/* dumb dump */ +static void console_input_dump( struct object *obj, int verbose ) +{ +#if 0 + struct console_input *console = (struct console_input *)obj; + assert( obj->ops == &console_input_ops ); + fprintf( stderr, "Console input active=%p evt=%p\n", + console->active, console->evt ); +#endif +} + +static void console_input_destroy( struct object *obj ) +{ + struct console_input* console_in = (struct console_input *)obj; + struct screen_buffer* curr; + int i; + +#if 0 + assert( obj->ops == &console_input_ops ); +#endif + free( console_in->title ); + free( console_in->records ); + + if (console_in->active) + release_object( console_in->active ); + console_in->active = NULL; + + LIST_FOR_EACH_ENTRY( curr, &screen_buffer_list, struct screen_buffer, entry ) { + if (curr->input == console_in) + curr->input = NULL; + } + + release_object( console_in->evt ); + console_in->evt = NULL; + release_object( console_in->event ); + + for (i = 0; i < console_in->history_size; i++) + free( console_in->history[i] ); + free( console_in->history ); +} + +static void screen_buffer_dump( struct object *obj, int verbose ) +{ +#if 0 + struct screen_buffer *screen_buffer = (struct screen_buffer *)obj; + assert( obj->ops == &screen_buffer_ops ); + + fprintf(stderr, "Console screen buffer input=%p\n", screen_buffer->input ); +#endif +} + +static void screen_buffer_destroy( struct object *obj ) +{ + struct screen_buffer *screen_buffer = (struct screen_buffer *)obj; + +#if 0 + assert( obj->ops == &screen_buffer_ops ); +#endif + + list_remove( &screen_buffer->entry ); + + if (screen_buffer->input && screen_buffer->input->active == screen_buffer) { + struct screen_buffer *sb; + + screen_buffer->input->active = NULL; + LIST_FOR_EACH_ENTRY( sb, &screen_buffer_list, struct screen_buffer, entry ) { + if (sb->input == screen_buffer->input) { + sb->input->active = sb; + break; + } + } + } + free( screen_buffer->data ); +} + +/* write data into a screen buffer */ +static int write_console_output( struct screen_buffer *screen_buffer, data_size_t size, + const void* data, enum char_info_mode mode, + int x, int y, int wrap ) +{ + unsigned int i; + char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x; + + if (y >= screen_buffer->height) + return 0; + + if (wrap) + end = screen_buffer->data + screen_buffer->height * screen_buffer->width; + else + end = screen_buffer->data + (y+1) * screen_buffer->width; + + switch(mode) { + case CHAR_INFO_MODE_TEXT: + { + const WCHAR *ptr = data; + for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) + dest->ch = ptr[i]; + } + break; + case CHAR_INFO_MODE_ATTR: + { + const unsigned short *ptr = data; + for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) + dest->attr = ptr[i]; + } + break; + case CHAR_INFO_MODE_TEXTATTR: + { + const char_info_t *ptr = data; + for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) + *dest = ptr[i]; + } + break; + case CHAR_INFO_MODE_TEXTSTDATTR: + { + const WCHAR *ptr = data; + for (i = 0; i < size/sizeof(*ptr) && dest < end; dest++, i++) { + dest->ch = ptr[i]; + dest->attr = screen_buffer->attr; + } + } + break; + default: + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + + if (i && screen_buffer == screen_buffer->input->active) { + struct console_renderer_event evt; + evt.event = CONSOLE_RENDERER_UPDATE_EVENT; + memset(&evt.u, 0, sizeof(evt.u)); + evt.u.update.top = y + x / screen_buffer->width; + evt.u.update.bottom = y + (x + i - 1) / screen_buffer->width; + console_input_events_append( screen_buffer->input->evt, &evt ); + } + return i; +} + +/* fill a screen buffer with uniform data */ +static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t data, + enum char_info_mode mode, int x, int y, int count, int wrap ) +{ + int i; + char_info_t *end, *dest = screen_buffer->data + y * screen_buffer->width + x; + + if (y >= screen_buffer->height) + return 0; + + if (wrap) + end = screen_buffer->data + screen_buffer->height * screen_buffer->width; + else + end = screen_buffer->data + (y+1) * screen_buffer->width; + + if (count > end - dest) + count = end - dest; + + switch(mode) { + case CHAR_INFO_MODE_TEXT: + for (i = 0; i < count; i++) + dest[i].ch = data.ch; + break; + case CHAR_INFO_MODE_ATTR: + for (i = 0; i < count; i++) + dest[i].attr = data.attr; + break; + case CHAR_INFO_MODE_TEXTATTR: + for (i = 0; i < count; i++) + dest[i] = data; + break; + case CHAR_INFO_MODE_TEXTSTDATTR: + for (i = 0; i < count; i++) { + dest[i].ch = data.ch; + dest[i].attr = screen_buffer->attr; + } + break; + default: + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + + if (count && screen_buffer == screen_buffer->input->active) { + struct console_renderer_event evt; + evt.event = CONSOLE_RENDERER_UPDATE_EVENT; + memset(&evt.u, 0, sizeof(evt.u)); + evt.u.update.top = y; + evt.u.update.bottom = (y * screen_buffer->width + x + count - 1) / screen_buffer->width; + console_input_events_append( screen_buffer->input->evt, &evt ); + } + return i; +} + +/* read data from a screen buffer */ +static void read_console_output( struct screen_buffer *screen_buffer, int x, int y, + enum char_info_mode mode, int wrap ) +{ + int i; + char_info_t *end, *src = screen_buffer->data + y * screen_buffer->width + x; + + if (y >= screen_buffer->height) + return; + + if (wrap) + end = screen_buffer->data + screen_buffer->height * screen_buffer->width; + else + end = screen_buffer->data + (y+1) * screen_buffer->width; + + switch(mode) { + case CHAR_INFO_MODE_TEXT: + { + WCHAR *data; + int count = min( (int)(end - src), (int)(get_reply_max_size() / sizeof(*data)) ); + if ((data = set_reply_data_size( count * sizeof(*data) ))) { + for (i = 0; i < count; i++) + data[i] = src[i].ch; + } + } + break; + case CHAR_INFO_MODE_ATTR: + { + unsigned short *data; + int count = min((int) (end - src),(int)( get_reply_max_size() / sizeof(*data)) ); + if ((data = set_reply_data_size( count * sizeof(*data) ))) { + for (i = 0; i < count; i++) + data[i] = src[i].attr; + } + } + break; + case CHAR_INFO_MODE_TEXTATTR: + { + char_info_t *data; + int count = min((int) (end - src), (int)(get_reply_max_size() / sizeof(*data)) ); + if ((data = set_reply_data_size( count * sizeof(*data) ))) { + for (i = 0; i < count; i++) + data[i] = src[i]; + } + } + break; + default: + set_error( STATUS_INVALID_PARAMETER ); + break; + } +} + +/* scroll parts of a screen buffer */ +static void scroll_console_output( obj_handle_t handle, int xsrc, int ysrc, int xdst, int ydst, + int w, int h ) +{ + struct screen_buffer *screen_buffer; + int j; + char_info_t *psrc, *pdst; + struct console_renderer_event evt; + + if (!(screen_buffer = (struct screen_buffer *)get_wine_handle_obj( get_current_w32process(), handle, + CONSOLE_READ, &screen_buffer_ops ))) + return; + if (xsrc < 0 || ysrc < 0 || xdst < 0 || ydst < 0 || + xsrc + w > screen_buffer->width || + xdst + w > screen_buffer->width || + ysrc + h > screen_buffer->height || + ydst + h > screen_buffer->height || + w == 0 || h == 0) { + set_error( STATUS_INVALID_PARAMETER ); + release_object( screen_buffer ); + return; + } + + if (ysrc < ydst) { + psrc = &screen_buffer->data[(ysrc + h - 1) * screen_buffer->width + xsrc]; + pdst = &screen_buffer->data[(ydst + h - 1) * screen_buffer->width + xdst]; + + for (j = h; j > 0; j--) { + memcpy(pdst, psrc, w * sizeof(*pdst) ); + pdst -= screen_buffer->width; + psrc -= screen_buffer->width; + } + } + else { + psrc = &screen_buffer->data[ysrc * screen_buffer->width + xsrc]; + pdst = &screen_buffer->data[ydst * screen_buffer->width + xdst]; + + for (j = 0; j < h; j++) { + /* we use memmove here because when psrc and pdst are the same, + * copies are done on the same row, so the dst and src blocks + * can overlap */ + memmove( pdst, psrc, w * sizeof(*pdst) ); + pdst += screen_buffer->width; + psrc += screen_buffer->width; + } + } + + /* FIXME: this could be enhanced, by signalling scroll */ + evt.event = CONSOLE_RENDERER_UPDATE_EVENT; + memset(&evt.u, 0, sizeof(evt.u)); + evt.u.update.top = min(ysrc, ydst); + evt.u.update.bottom = max(ysrc, ydst) + h - 1; + console_input_events_append( screen_buffer->input->evt, &evt ); + + release_object( screen_buffer ); +} + +extern struct w32process *eprocess2process(struct eprocess *); +extern struct eprocess *process2eprocess(struct w32process *); + +/* allocate a console for the renderer */ +DECL_HANDLER(alloc_console) +{ + obj_handle_t in = 0; + obj_handle_t evt = 0; + struct w32process *process; + struct w32process *renderer = get_current_w32process(); + struct console_input *console; + + if (req->pid) { + if (!(process = eprocess2process(get_process_from_id((HANDLE) req->pid )))) + return; + } + else { + if (!(process = renderer->parent)) { + set_error( STATUS_ACCESS_DENIED ); + return; + } + grab_object( process ); + } + + if (process != renderer && process->console) { + set_error( STATUS_ACCESS_DENIED ); + goto the_end; + } + if ((console = (struct console_input*)create_console_input( current_thread ))) { + if ((in = alloc_handle( renderer, console, req->access, req->attributes ))) { + if ((evt = alloc_handle( renderer, console->evt, SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, 0 ))) { + if (process != renderer) { + process->console = (struct console_input*)grab_object( console ); + console->num_proc++; + } + reply->handle_in = in; + reply->event = evt; + release_object( console ); + goto the_end; + } + close_handle( process2eprocess(renderer), in ); + } + free_console( process ); + } +the_end: + release_object( process ); +} + +/* free the console of the current process */ +DECL_HANDLER(free_console) +{ + free_console( get_current_w32process() ); +} + +/* let the renderer peek the events it's waiting on */ +DECL_HANDLER(get_console_renderer_events) +{ + struct console_input_events *evt; + + evt = (struct console_input_events *)get_wine_handle_obj( get_current_w32process(), req->handle, + CONSOLE_READ, &console_input_events_ops ); + if (!evt) + return; + console_input_events_get( evt ); + release_object( evt ); +} + +/* open a handle to the process console */ +DECL_HANDLER(open_console) +{ + struct object *obj = NULL; + + reply->handle = 0; + if (req->from == (obj_handle_t)0) { + if (get_current_w32process()->console && get_current_w32process()->console->renderer) + obj = grab_object( (struct object*)get_current_w32process()->console ); + } + else if (req->from == (obj_handle_t)1) { + if (get_current_w32process()->console && get_current_w32process()->console->renderer && + get_current_w32process()->console->active) + obj = grab_object( (struct object*)get_current_w32process()->console->active ); + } + else if ((obj = get_wine_handle_obj( get_current_w32process(), req->from, + CONSOLE_READ|CONSOLE_WRITE, &console_input_ops ))) { + struct console_input *console = (struct console_input *)obj; + obj = (console->active) ? grab_object( console->active ) : NULL; + release_object( console ); + } + + /* FIXME: req->share is not used (as in screen buffer creation) */ + if (obj) { + reply->handle = alloc_handle( get_current_w32process(), obj, req->access, req->attributes ); + release_object( obj ); + } + else if (!get_error()) + set_error( STATUS_ACCESS_DENIED ); +} + +/* set info about a console input */ +DECL_HANDLER(set_console_input_info) +{ + set_console_input_info( req, get_req_data(), get_req_data_size() ); +} + +/* get info about a console (output only) */ +DECL_HANDLER(get_console_input_info) +{ + struct console_input *console; + + if (!(console = console_input_get( req->handle, CONSOLE_READ ))) + return; + if (console->title) { + data_size_t len = strlenW( console->title ) * sizeof(WCHAR); + if (len > get_reply_max_size()) + len = get_reply_max_size(); + set_reply_data( console->title, len ); + } + reply->history_mode = console->history_mode; + reply->history_size = console->history_size; + reply->history_index = console->history_index; + reply->edition_mode = console->edition_mode; + reply->input_cp = console->input_cp; + reply->output_cp = console->output_cp; + reply->win = console->win; + + release_object( console ); +} + +/* get a console mode (input or output) */ +DECL_HANDLER(get_console_mode) +{ + reply->mode = get_console_mode( req->handle ); +} + +/* set a console mode (input or output) */ +DECL_HANDLER(set_console_mode) +{ + set_console_mode( req->handle, req->mode ); +} + +/* add input records to a console input queue */ +DECL_HANDLER(write_console_input) +{ + struct console_input *console; + + reply->written = 0; + if (!(console = (struct console_input *)get_wine_handle_obj( get_current_w32process(), req->handle, + CONSOLE_WRITE, &console_input_ops ))) + return; + reply->written = write_console_input( console, get_req_data_size() / sizeof(INPUT_RECORD), + get_req_data() ); + release_object( console ); +} + +/* fetch input records from a console input queue */ +DECL_HANDLER(read_console_input) +{ + int count = get_reply_max_size() / sizeof(INPUT_RECORD); + reply->read = read_console_input( req->handle, count, req->flush ); +} + +/* appends a string to console's history */ +DECL_HANDLER(append_console_input_history) +{ + struct console_input *console; + + if (!(console = console_input_get( req->handle, CONSOLE_WRITE ))) + return; + console_input_append_hist( console, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + release_object( console ); +} + +/* appends a string to console's history */ +DECL_HANDLER(get_console_input_history) +{ + struct console_input *console; + + if (!(console = console_input_get( req->handle, CONSOLE_WRITE ))) + return; + reply->total = console_input_get_hist( console, req->index ); + release_object( console ); +} + +/* creates a screen buffer */ +DECL_HANDLER(create_console_output) +{ + struct console_input* console; + struct screen_buffer* screen_buffer; + + if (!(console = console_input_get( req->handle_in, CONSOLE_WRITE ))) + return; + + screen_buffer = create_console_output( console ); + if (screen_buffer) { + /* FIXME: should store sharing and test it when opening the CONOUT$ device + * see file.c on how this could be done */ + reply->handle_out = alloc_handle( get_current_w32process(), screen_buffer, req->access, req->attributes ); + release_object( screen_buffer ); + } + release_object( console ); +} + +/* set info about a console screen buffer */ +DECL_HANDLER(set_console_output_info) +{ + struct screen_buffer *screen_buffer; + + if ((screen_buffer = (struct screen_buffer*)get_wine_handle_obj( get_current_w32process(), req->handle, + CONSOLE_WRITE, &screen_buffer_ops))) { + set_console_output_info( screen_buffer, req ); + release_object( screen_buffer ); + } +} + +/* get info about a console screen buffer */ +DECL_HANDLER(get_console_output_info) +{ + struct screen_buffer *screen_buffer; + + if ((screen_buffer = (struct screen_buffer *)get_wine_handle_obj( get_current_w32process(), req->handle, + CONSOLE_READ, &screen_buffer_ops))) { + reply->cursor_size = screen_buffer->cursor_size; + reply->cursor_visible = screen_buffer->cursor_visible; + reply->cursor_x = screen_buffer->cursor_x; + reply->cursor_y = screen_buffer->cursor_y; + reply->width = screen_buffer->width; + reply->height = screen_buffer->height; + reply->attr = screen_buffer->attr; + reply->win_left = screen_buffer->win.left; + reply->win_top = screen_buffer->win.top; + reply->win_right = screen_buffer->win.right; + reply->win_bottom = screen_buffer->win.bottom; + reply->max_width = screen_buffer->max_width; + reply->max_height = screen_buffer->max_height; + release_object( screen_buffer ); + } +} + +/* read data (chars & attrs) from a screen buffer */ +DECL_HANDLER(read_console_output) +{ + struct screen_buffer *screen_buffer; + + if ((screen_buffer = (struct screen_buffer*)get_wine_handle_obj( get_current_w32process(), req->handle, + CONSOLE_READ, &screen_buffer_ops ))) { + read_console_output( screen_buffer, req->x, req->y, req->mode, req->wrap ); + reply->width = screen_buffer->width; + reply->height = screen_buffer->height; + release_object( screen_buffer ); + } +} + +/* write data (char and/or attrs) to a screen buffer */ +DECL_HANDLER(write_console_output) +{ + struct screen_buffer *screen_buffer; + + if ((screen_buffer = (struct screen_buffer*)get_wine_handle_obj( get_current_w32process(), req->handle, + CONSOLE_WRITE, &screen_buffer_ops))) { + reply->written = write_console_output( screen_buffer, get_req_data_size(), get_req_data(), + req->mode, req->x, req->y, req->wrap ); + reply->width = screen_buffer->width; + reply->height = screen_buffer->height; + release_object( screen_buffer ); + } +} + +/* fill a screen buffer with constant data (chars and/or attributes) */ +DECL_HANDLER(fill_console_output) +{ + struct screen_buffer *screen_buffer; + + if ((screen_buffer = (struct screen_buffer*)get_wine_handle_obj( get_current_w32process(), req->handle, + CONSOLE_WRITE, &screen_buffer_ops))) { + reply->written = fill_console_output( screen_buffer, req->data, req->mode, + req->x, req->y, req->count, req->wrap ); + release_object( screen_buffer ); + } +} + +/* move a rect of data in a screen buffer */ +DECL_HANDLER(move_console_output) +{ + scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst, + req->w, req->h ); +} + +/* sends a signal to a console (process, group...) */ +DECL_HANDLER(send_console_signal) +{ + process_id_t group; + + group = req->group_id ? req->group_id : get_current_w32process()->group_id; + + if (!group) + set_error( STATUS_INVALID_PARAMETER ); + else + propagate_console_signal( get_current_w32process()->console, req->signal, group ); +} + +/* get console which renderer is 'current' */ +static int cgwe_enum( struct w32process* process, void* user) +{ + if (process->console && process->console->renderer == current_thread) { + *(struct console_input**)user = process->console; + return 1; + } + return 0; +} + +DECL_HANDLER(get_console_wait_event) +{ + struct console_input* console = NULL; + + if (get_current_w32process()->console && get_current_w32process()->console->renderer) + console = (struct console_input*)grab_object( (struct object*)get_current_w32process()->console ); + else enum_processes(cgwe_enum, &console); + + if (console) { + reply->handle = alloc_handle( get_current_w32process(), console->event, EVENT_ALL_ACCESS, 0 ); + release_object( console ); + } + else set_error( STATUS_INVALID_PARAMETER ); +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/device/device.c b/unifiedkernel/device/device.c new file mode 100644 index 0000000..dc36429 --- /dev/null +++ b/unifiedkernel/device/device.c @@ -0,0 +1,516 @@ +/* + * device.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * device.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" +#include "file.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct ioctl_call +{ + struct object obj; /* object header */ + struct list_head dev_entry; /* entry in device queue */ + struct list_head mgr_entry; /* entry in manager queue */ + struct device *device; /* device containing this ioctl */ + struct w32thread *thread; /* thread that queued the ioctl */ + void *user_arg; /* user arg used to identify the request */ + struct async *async; /* pending async op */ + ioctl_code_t code; /* ioctl code */ + unsigned int status; /* resulting status (or STATUS_PENDING) */ + data_size_t in_size; /* size of input data */ + void *in_data; /* input data */ + data_size_t out_size; /* size of output data */ + void *out_data; /* output data */ +}; + +static void ioctl_call_dump( struct object *obj, int verbose ); +static void ioctl_call_destroy( struct object *obj ); + +static const struct object_ops ioctl_call_ops = +{ + sizeof(struct ioctl_call), /* size */ + ioctl_call_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + ioctl_call_destroy /* destroy */ +}; + + +struct device_manager +{ + struct object obj; /* object header */ + struct list_head devices; /* list of devices */ + struct list_head requests; /* list of pending ioctls across all devices */ +}; + +static void device_manager_dump( struct object *obj, int verbose ); +static void device_manager_destroy( struct object *obj ); + +static const struct object_ops device_manager_ops = +{ + sizeof(struct device_manager), /* size */ + device_manager_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + device_manager_destroy /* destroy */ +}; + + +struct device +{ + struct object obj; /* object header */ + struct device_manager *manager; /* manager for this device (or NULL if deleted) */ + struct fd *fd; /* file descriptor for ioctl */ + void *user_ptr; /* opaque ptr for client side */ + struct list_head entry; /* entry in device manager list */ + struct list_head requests; /* list of pending ioctl requests */ +}; + +static void device_dump( struct object *obj, int verbose ); +static struct object_type *device_get_type( struct object *obj ); +static struct fd *device_get_fd( struct object *obj ); +static void device_destroy( struct object *obj ); +static struct object *device_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ); +static enum server_fd_type device_get_fd_type( struct fd *fd ); +static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, const void *data, data_size_t size ); +extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); + +static const struct object_ops device_ops = +{ + sizeof(struct device), /* size */ + device_dump, /* dump */ + device_get_type, /* get_type */ + device_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + device_open_file, /* open_file */ + no_close_handle, /* close_handle */ + device_destroy /* destroy */ +}; + +static const struct fd_ops device_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + device_get_fd_type, /* get_fd_type */ + device_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + +static void ioctl_call_dump( struct object *obj, int verbose ) +{ +#if 0 + struct ioctl_call *ioctl = (struct ioctl_call *)obj; + fprintf( stderr, "Ioctl call code=%08x device=%p\n", ioctl->code, ioctl->device ); +#endif +} + +static void ioctl_call_destroy( struct object *obj ) +{ + struct ioctl_call *ioctl = (struct ioctl_call *)obj; + + free( ioctl->in_data ); + free( ioctl->out_data ); + if (ioctl->async) { + async_terminate( ioctl->async, STATUS_CANCELLED ); + release_object( ioctl->async ); + } + if (ioctl->device) + release_object( ioctl->device ); + release_object( ioctl->thread ); +} + +static struct ioctl_call *create_ioctl( struct device *device, ioctl_code_t code, + const void *in_data, data_size_t in_size, + data_size_t out_size ) +{ + struct ioctl_call *ioctl; + + if ((ioctl = alloc_wine_object( &ioctl_call_ops ))) { + ioctl->device = (struct device *)grab_object( device ); + ioctl->code = code; + ioctl->async = NULL; + ioctl->status = STATUS_PENDING; + ioctl->in_size = in_size; + ioctl->in_data = NULL; + ioctl->out_size = out_size; + ioctl->out_data = NULL; + + if (ioctl->in_size && !(ioctl->in_data = memdup( in_data, in_size ))) { + release_object( ioctl ); + ioctl = NULL; + } + } + return ioctl; +} + +static void set_ioctl_result( struct ioctl_call *ioctl, unsigned int status, + const void *out_data, data_size_t out_size ) +{ + struct device *device = ioctl->device; + + if (!device) + return; /* already finished */ + + /* FIXME: handle the STATUS_PENDING case */ + ioctl->status = status; + ioctl->out_size = min( ioctl->out_size, out_size ); + if (ioctl->out_size && !(ioctl->out_data = memdup( out_data, ioctl->out_size ))) + ioctl->out_size = 0; + release_object( device ); + ioctl->device = NULL; + if (ioctl->async) { + if (ioctl->out_size) + status = STATUS_ALERTED; + async_terminate( ioctl->async, status ); + release_object( ioctl->async ); + ioctl->async = NULL; + } + uk_wake_up( &ioctl->obj, 0 ); + + if (status != STATUS_ALERTED) { + /* remove it from the device queue */ + /* (for STATUS_ALERTED this will be done in get_ioctl_result) */ + list_remove( &ioctl->dev_entry ); + release_object( ioctl ); /* no longer on the device queue */ + } +} + +static void device_dump( struct object *obj, int verbose ) +{ +#if 0 + struct device *device = (struct device *)obj; + + fprintf( stderr, "Device " ); + dump_object_name( &device->obj ); + fputc( '\n', stderr ); +#endif +} + +extern struct object_type *get_object_type( const struct unicode_str* ); + +static struct object_type *device_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'D','e','v','i','c','e'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +static struct fd *device_get_fd( struct object *obj ) +{ + struct device *device = (struct device *)obj; + + return (struct fd *)grab_object( device->fd ); +} + +static void device_destroy( struct object *obj ) +{ + struct device *device = (struct device *)obj; + struct ioctl_call *ioctl, *next; + + LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry ) { + list_remove( &ioctl->dev_entry ); + release_object( ioctl ); /* no longer on the device queue */ + } + if (device->fd) + release_object( device->fd ); + if (device->manager) + list_remove( &device->entry ); +} + +static struct object *device_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ) +{ + return grab_object( obj ); +} + +static enum server_fd_type device_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_DEVICE; +} + +static struct ioctl_call *find_ioctl_call( struct device *device, struct w32thread *thread, + void *user_arg ) +{ + struct ioctl_call *ioctl; + + LIST_FOR_EACH_ENTRY( ioctl, &device->requests, struct ioctl_call, dev_entry ) + if (ioctl->thread == thread && ioctl->user_arg == user_arg) + return ioctl; + + set_error( STATUS_INVALID_PARAMETER ); + return NULL; +} + +static obj_handle_t device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, + const void *data, data_size_t size ) +{ + struct device *device = get_fd_user( fd ); + struct ioctl_call *ioctl; + obj_handle_t handle; + + if (!device->manager) /* it has been deleted */ { + set_error( STATUS_FILE_DELETED ); + return 0; + } + + if (!(ioctl = create_ioctl( device, code, data, size, get_reply_max_size() ))) + return 0; + + ioctl->thread = (struct w32thread *)grab_object( current ); + ioctl->user_arg = async_data->arg; + + if (!(handle = alloc_handle( get_current_w32process(), ioctl, SYNCHRONIZE, 0 ))) { + release_object( ioctl ); + return 0; + } + + if (!(ioctl->async = fd_queue_async( device->fd, async_data, ASYNC_TYPE_WAIT, 0 ))) { + close_handle( get_current_eprocess(), handle ); + release_object( ioctl ); + return 0; + } + my_list_add_tail( &device->requests, &ioctl->dev_entry ); + my_list_add_tail( &device->manager->requests, &ioctl->mgr_entry ); + if (list_head( &device->manager->requests ) == &ioctl->mgr_entry) /* first one */ + uk_wake_up( &device->manager->obj, 0 ); + /* don't release ioctl since it is now queued in the device */ + set_error( STATUS_PENDING ); + return handle; +} + +static struct device *create_device( HANDLE root, const struct unicode_str *name, + struct device_manager *manager, unsigned int attr ) +{ + struct device *device; + + if ((device = create_named_object_dir( root, name, attr, &device_ops ))) { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) { + /* initialize it if it didn't already exist */ + device->manager = manager; + my_list_add_tail( &manager->devices, &device->entry ); + my_list_init( &device->requests ); + if (!(device->fd = alloc_pseudo_fd( &device_fd_ops, &device->obj, 0 ))) { + release_object( device ); + device = NULL; + } + } + } + return device; +} + +static void delete_device( struct device *device ) +{ + struct ioctl_call *ioctl, *next; + + if (!device->manager) + return; /* already deleted */ + + /* terminate all pending requests */ + LIST_FOR_EACH_ENTRY_SAFE( ioctl, next, &device->requests, struct ioctl_call, dev_entry ) { + list_remove( &ioctl->mgr_entry ); + set_ioctl_result( ioctl, STATUS_FILE_DELETED, NULL, 0 ); + } + unlink_named_object( &device->obj ); + list_remove( &device->entry ); + device->manager = NULL; +} + + +static void device_manager_dump( struct object *obj, int verbose ) +{ +#if 0 + fprintf( stderr, "Device manager\n" ); +#endif +} + +static void device_manager_destroy( struct object *obj ) +{ + struct device_manager *manager = (struct device_manager *)obj; + struct list_head *ptr; + + while ((ptr = list_head( &manager->devices ))) { + struct device *device = LIST_ENTRY( ptr, struct device, entry ); + delete_device( device ); + } +} + +static struct device_manager *create_device_manager(void) +{ + struct device_manager *manager; + + if ((manager = alloc_wine_object( &device_manager_ops ))) { + my_list_init( &manager->devices ); + my_list_init( &manager->requests ); + } + return manager; +} + + +/* create a device manager */ +DECL_HANDLER(create_device_manager) +{ + struct device_manager *manager = create_device_manager(); + + if (manager) { + reply->handle = alloc_handle( get_current_w32process(), manager, req->access, req->attributes ); + release_object( manager ); + } +} + +/* create a device */ +DECL_HANDLER(create_device) +{ + struct device *device; + struct unicode_str name; + struct device_manager *manager; + + if (!(manager = (struct device_manager *)get_wine_handle_obj( get_current_w32process(), req->manager, + 0, &device_manager_ops ))) + return; + + get_req_unicode_str( &name ); + + if ((device = create_device( req->rootdir, &name, manager, req->attributes ))) { + device->user_ptr = req->user_ptr; + reply->handle = alloc_handle( get_current_w32process(), device, req->access, req->attributes ); + release_object( device ); + } + + release_object( manager ); +} + + +/* delete a device */ +DECL_HANDLER(delete_device) +{ + struct device *device; + + if ((device = (struct device *)get_wine_handle_obj( get_current_w32process(), req->handle, 0, &device_ops ))) { + delete_device( device ); + release_object( device ); + } +} + +void clear_error(void); + +/* retrieve the next pending device ioctl request */ +DECL_HANDLER(get_next_device_request) +{ + struct ioctl_call *ioctl; + struct device_manager *manager; + struct list_head *ptr; + + if (!(manager = (struct device_manager *)get_wine_handle_obj( get_current_w32process(), req->manager, + 0, &device_manager_ops ))) + return; + + if (req->prev) { + if ((ioctl = (struct ioctl_call *)get_wine_handle_obj( get_current_w32process(), req->prev, + 0, &ioctl_call_ops ))) { + set_ioctl_result( ioctl, req->status, get_req_data(), get_req_data_size() ); + close_handle( get_current_eprocess(), req->prev ); /* avoid an extra round-trip for close */ + release_object( ioctl ); + } + clear_error(); + } + + if ((ptr = list_head( &manager->requests ))) { + ioctl = LIST_ENTRY( ptr, struct ioctl_call, mgr_entry ); + reply->code = ioctl->code; + reply->user_ptr = ioctl->device->user_ptr; + reply->in_size = ioctl->in_size; + reply->out_size = ioctl->out_size; + if (ioctl->in_size > get_reply_max_size()) + set_error( STATUS_BUFFER_OVERFLOW ); + else if ((reply->next = alloc_handle( get_current_w32process(), ioctl, 0, 0 ))) { + set_reply_data_ptr( ioctl->in_data, ioctl->in_size ); + ioctl->in_data = NULL; + ioctl->in_size = 0; + list_remove( &ioctl->mgr_entry ); + my_list_init( &ioctl->mgr_entry ); + } + } + else set_error( STATUS_PENDING ); + + release_object( manager ); +} + + +/* retrieve results of an async ioctl */ +DECL_HANDLER(get_ioctl_result) +{ + struct device *device; + struct ioctl_call *ioctl; + + if (!(device = (struct device *)get_wine_handle_obj( get_current_w32process(), req->handle, 0, &device_ops ))) + return; + + if ((ioctl = find_ioctl_call( device, current_thread, req->user_arg ))) { + if (ioctl->out_data) { + data_size_t size = min( ioctl->out_size, get_reply_max_size() ); + if (size) { + set_reply_data_ptr( ioctl->out_data, size ); + ioctl->out_data = NULL; + } + } + set_error( ioctl->status ); + list_remove( &ioctl->dev_entry ); + release_object( ioctl ); /* no longer on the device queue */ + } + release_object( device ); +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/device/mailslot.c b/unifiedkernel/device/mailslot.c new file mode 100644 index 0000000..f851da2 --- /dev/null +++ b/unifiedkernel/device/mailslot.c @@ -0,0 +1,524 @@ +/* + * mailslot.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * mailslot.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" +#include "file.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct mailslot +{ + struct object obj; + struct fd *fd; + int write_fd; + unsigned int max_msgsize; + timeout_t read_timeout; + struct list_head writers; +}; + +/* mailslot functions */ +static void mailslot_dump( struct object*, int ); +static struct fd *mailslot_get_fd( struct object * ); +static unsigned int mailslot_map_access( struct object *obj, unsigned int access ); +static struct object *mailslot_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ); +static void mailslot_destroy( struct object * ); + +static const struct object_ops mailslot_ops = +{ + sizeof(struct mailslot), /* size */ + mailslot_dump, /* dump */ + no_get_type, /* get_type */ + mailslot_get_fd, /* get_fd */ + mailslot_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + mailslot_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + mailslot_destroy /* destroy */ +}; + +static enum server_fd_type mailslot_get_fd_type( struct fd *fd ); +static void mailslot_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); + +static const struct fd_ops mailslot_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + mailslot_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ + mailslot_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + + +struct mail_writer +{ + struct object obj; + struct fd *fd; + struct mailslot *mailslot; + struct list_head entry; + unsigned int access; + unsigned int sharing; +}; + +static void mail_writer_dump( struct object *obj, int verbose ); +static struct fd *mail_writer_get_fd( struct object *obj ); +static unsigned int mail_writer_map_access( struct object *obj, unsigned int access ); +static void mail_writer_destroy( struct object *obj); + +static const struct object_ops mail_writer_ops = +{ + sizeof(struct mail_writer), /* size */ + mail_writer_dump, /* dump */ + no_get_type, /* get_type */ + mail_writer_get_fd, /* get_fd */ + mail_writer_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + mail_writer_destroy /* destroy */ +}; + +static enum server_fd_type mail_writer_get_fd_type( struct fd *fd ); + +static const struct fd_ops mail_writer_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + mail_writer_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + + +struct mailslot_device +{ + struct object obj; /* object header */ + struct fd *fd; /* pseudo-fd for ioctls */ + struct namespace *mailslots; /* mailslot namespace */ +}; + +static void mailslot_device_dump( struct object *obj, int verbose ); +static struct object_type *mailslot_device_get_type( struct object *obj ); +static struct fd *mailslot_device_get_fd( struct object *obj ); +static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ); +static struct object *mailslot_device_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ); +static void mailslot_device_destroy( struct object *obj ); +static enum server_fd_type mailslot_device_get_fd_type( struct fd *fd ); + +static const struct object_ops mailslot_device_ops = +{ + sizeof(struct mailslot_device), /* size */ + mailslot_device_dump, /* dump */ + mailslot_device_get_type, /* get_type */ + mailslot_device_get_fd, /* get_fd */ + no_map_access, /* map_access */ + mailslot_device_lookup_name, /* lookup_name */ + mailslot_device_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + mailslot_device_destroy /* destroy */ +}; + +static const struct fd_ops mailslot_device_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + mailslot_device_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + +extern int uk_shutdown(int s, int how); + +static void mailslot_destroy( struct object *obj) +{ + struct mailslot *mailslot = (struct mailslot *) obj; + +#if 0 + assert( mailslot->fd ); +#endif + + if (mailslot->write_fd != -1) { + uk_shutdown( mailslot->write_fd, SHUT_RDWR ); + uk_close( mailslot->write_fd ); + } + release_object( mailslot->fd ); +} + +static void mailslot_dump( struct object *obj, int verbose ) +{ +#if 0 + struct mailslot *mailslot = (struct mailslot *) obj; + + assert( obj->ops == &mailslot_ops ); + fprintf( stderr, "Mailslot max_msgsize=%d read_timeout=%s\n", + mailslot->max_msgsize, get_timeout_str(mailslot->read_timeout) ); +#endif +} + +static enum server_fd_type mailslot_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_MAILSLOT; +} + +static struct fd *mailslot_get_fd( struct object *obj ) +{ + struct mailslot *mailslot = (struct mailslot *) obj; + + return (struct fd *)grab_object( mailslot->fd ); +} + +static unsigned int mailslot_map_access( struct object *obj, unsigned int access ) +{ + /* mailslots can only be read */ + if (access & GENERIC_READ) + access |= FILE_GENERIC_READ; + if (access & GENERIC_ALL) + access |= FILE_GENERIC_READ; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +extern NTSTATUS errno2ntstatus(int error); +static struct object *mailslot_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ) +{ + struct mailslot *mailslot = (struct mailslot *)obj; + struct mail_writer *writer; + int unix_fd; + + if (!(sharing & FILE_SHARE_READ)) { + set_error( STATUS_SHARING_VIOLATION ); + return NULL; + } + + if (!my_list_empty( &mailslot->writers )) { + /* Readers and writers cannot be mixed. + * If there's more than one writer, all writers must open with FILE_SHARE_WRITE + */ + writer = LIST_ENTRY( list_head(&mailslot->writers), struct mail_writer, entry ); + + if (((access & (GENERIC_WRITE|FILE_WRITE_DATA)) || (writer->access & FILE_WRITE_DATA)) && + !((sharing & FILE_SHARE_WRITE) && (writer->sharing & FILE_SHARE_WRITE))) { + set_error( STATUS_SHARING_VIOLATION ); + return NULL; + } + } + + if ((unix_fd = uk_dup( mailslot->write_fd )) < 0) { + errno2ntstatus(-unix_fd); + return NULL; + } + if (!(writer = alloc_wine_object( &mail_writer_ops ))) { + uk_close( unix_fd ); + return NULL; + } + grab_object( mailslot ); + writer->mailslot = mailslot; + writer->access = mail_writer_map_access( &writer->obj, access ); + writer->sharing = sharing; + list_add_head( &mailslot->writers, &writer->entry ); + + if (!(writer->fd = create_anonymous_fd( &mail_writer_fd_ops, unix_fd, &writer->obj, options ))) { + release_object( writer ); + return NULL; + } + return &writer->obj; +} + +static void mailslot_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + struct async *async; + +#if 0 + assert(mailslot->obj.ops == &mailslot_ops); +#endif + + if ((async = fd_queue_async( fd, data, type, count ))) { + async_set_timeout( async, mailslot->read_timeout ? mailslot->read_timeout : -1, + STATUS_IO_TIMEOUT ); + release_object( async ); + set_error( STATUS_PENDING ); + } +} + +static void mailslot_device_dump( struct object *obj, int verbose ) +{ +#if 0 + assert( obj->ops == &mailslot_device_ops ); + fprintf( stderr, "Mail slot device\n" ); +#endif +} + +struct object_type *get_object_type( const struct unicode_str *name ); + +static struct object_type *mailslot_device_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'D','e','v','i','c','e'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +static struct fd *mailslot_device_get_fd( struct object *obj ) +{ + struct mailslot_device *device = (struct mailslot_device *)obj; + return (struct fd *)grab_object( device->fd ); +} + +static struct object *mailslot_device_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ) +{ + struct mailslot_device *device = (struct mailslot_device*)obj; + struct object *found; + +#if 0 + assert( obj->ops == &mailslot_device_ops ); +#endif + + if ((found = find_object( device->mailslots, name, attr | OBJ_CASE_INSENSITIVE ))) + name->len = 0; + + return found; +} + +static struct object *mailslot_device_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ) +{ + return grab_object( obj ); +} + +static void mailslot_device_destroy( struct object *obj ) +{ + struct mailslot_device *device = (struct mailslot_device*)obj; +#if 0 + assert( obj->ops == &mailslot_device_ops ); +#endif + if (device->fd) + release_object( device->fd ); + free( device->mailslots ); +} + +static enum server_fd_type mailslot_device_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_DEVICE; +} + +void create_mailslot_device( struct directory *root, const struct unicode_str *name ) +{ + struct mailslot_device *dev; + + if ((dev = create_named_object_dir( root, name, 0, &mailslot_device_ops )) && + get_error() != STATUS_OBJECT_NAME_EXISTS) { + dev->mailslots = NULL; + if (!(dev->fd = alloc_pseudo_fd( &mailslot_device_fd_ops, &dev->obj, 0 )) || + !(dev->mailslots = create_namespace( 7 ))) { + release_object( dev ); + dev = NULL; + } + } + if (dev) + make_object_static( &dev->obj ); +} + +extern int uk_socketpair(int d, int type, int protocol, int sv[]); +#define AF_UNIX 1 /* Unix domain sockets */ +#define PF_UNIX AF_UNIX +#define SOCK_DGRAM 2 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 + +static struct mailslot *create_mailslot( HANDLE root, + const struct unicode_str *name, unsigned int attr, + int max_msgsize, timeout_t read_timeout ) +{ + struct object *obj; + struct unicode_str new_name; + struct mailslot_device *dev; + struct mailslot *mailslot; + int fds[2]; + + if (!name || !name->len) + return alloc_wine_object( &mailslot_ops ); + + if (!(obj = find_object_dir( root, name, attr, &new_name ))) { + set_error( STATUS_OBJECT_NAME_INVALID ); + return NULL; + } + + if (!new_name.len) { + if (attr & OBJ_OPENIF && BODY_TO_HEADER(obj)->ops == &mailslot_ops) + /* it already exists - there can only be one mailslot to read from */ + set_error( STATUS_OBJECT_NAME_EXISTS ); + else if (attr & OBJ_OPENIF) + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + else + set_error( STATUS_OBJECT_NAME_COLLISION ); + release_object( obj ); + return NULL; + } + + if (BODY_TO_HEADER(obj)->ops != &mailslot_device_ops) { + set_error( STATUS_OBJECT_NAME_INVALID ); + release_object( obj ); + return NULL; + } + + dev = (struct mailslot_device *)obj; + mailslot = create_wine_object( dev->mailslots, &mailslot_ops, &new_name, NULL ); + release_object( dev ); + + if (!mailslot) + return NULL; + + mailslot->fd = NULL; + mailslot->write_fd = -1; + mailslot->max_msgsize = max_msgsize; + mailslot->read_timeout = read_timeout; + my_list_init( &mailslot->writers ); + + if (uk_socketpair( PF_UNIX, SOCK_DGRAM, 0, fds ) >= 0) { + uk_fcntl( fds[0], F_SETFL, O_NONBLOCK ); + uk_fcntl( fds[1], F_SETFL, O_NONBLOCK ); + uk_shutdown( fds[0], SHUT_RD ); + mailslot->write_fd = fds[0]; + mailslot->fd = create_anonymous_fd( &mailslot_fd_ops, fds[1], &mailslot->obj, + FILE_SYNCHRONOUS_IO_NONALERT ); + if (mailslot->fd) + return mailslot; + } +#if 0 + else file_set_error(); +#endif + + release_object( mailslot ); + return NULL; +} + +static void mail_writer_dump( struct object *obj, int verbose ) +{ +#if 0 + fprintf( stderr, "Mailslot writer\n" ); +#endif +} + +static void mail_writer_destroy( struct object *obj) +{ + struct mail_writer *writer = (struct mail_writer *) obj; + + if (writer->fd) + release_object( writer->fd ); + list_remove( &writer->entry ); + release_object( writer->mailslot ); +} + +static enum server_fd_type mail_writer_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_MAILSLOT; +} + +static struct fd *mail_writer_get_fd( struct object *obj ) +{ + struct mail_writer *writer = (struct mail_writer *) obj; + return (struct fd *)grab_object( writer->fd ); +} + +static unsigned int mail_writer_map_access( struct object *obj, unsigned int access ) +{ + /* mailslot writers can only get write access */ + if (access & GENERIC_WRITE) + access |= FILE_GENERIC_WRITE; + if (access & GENERIC_ALL) + access |= FILE_GENERIC_WRITE; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +static struct mailslot *get_mailslot_obj( struct w32process *process, obj_handle_t handle, + unsigned int access ) +{ + return (struct mailslot *)get_wine_handle_obj( process, handle, access, &mailslot_ops ); +} + + +/* create a mailslot */ +DECL_HANDLER(create_mailslot) +{ + struct mailslot *mailslot; + struct unicode_str name; + + reply->handle = 0; + get_req_unicode_str( &name ); + + if ((mailslot = create_mailslot( req->rootdir, &name, req->attributes, req->max_msgsize, + req->read_timeout ))) { + reply->handle = alloc_handle( get_current_w32process(), mailslot, req->access, req->attributes ); + release_object( mailslot ); + } + +} + + +/* set mailslot information */ +DECL_HANDLER(set_mailslot_info) +{ + struct mailslot *mailslot = get_mailslot_obj( get_current_w32process(), req->handle, 0 ); + + if (mailslot) { + if (req->flags & MAILSLOT_SET_READ_TIMEOUT) + mailslot->read_timeout = req->read_timeout; + reply->max_msgsize = mailslot->max_msgsize; + reply->read_timeout = mailslot->read_timeout; + release_object( mailslot ); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/device/named_pipe.c b/unifiedkernel/device/named_pipe.c new file mode 100644 index 0000000..c5c12a7 --- /dev/null +++ b/unifiedkernel/device/named_pipe.c @@ -0,0 +1,1128 @@ +/* + * named_pipe.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * named_pipe.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" +#include "file.h" + +#ifdef CONFIG_UNIFIED_KERNEL +enum pipe_state +{ + ps_idle_server, + ps_wait_open, + ps_connected_server, + ps_wait_disconnect, + ps_disconnected_server, + ps_wait_connect +}; + +struct named_pipe; + +struct pipe_server +{ + struct object obj; /* object header */ + struct fd *fd; /* pipe file descriptor */ + struct fd *ioctl_fd; /* file descriptor for ioctls when not connected */ + struct list_head entry; /* entry in named pipe servers list */ + enum pipe_state state; /* server state */ + struct pipe_client *client; /* client that this server is connected to */ + struct named_pipe *pipe; + struct timeout_user *flush_poll; + struct kevent *event; + unsigned int options; /* pipe options */ +}; + +struct pipe_client +{ + struct object obj; /* object header */ + struct fd *fd; /* pipe file descriptor */ + struct pipe_server *server; /* server that this client is connected to */ + unsigned int flags; /* file flags */ +}; + +struct named_pipe +{ + struct object obj; /* object header */ + unsigned int flags; + unsigned int maxinstances; + unsigned int outsize; + unsigned int insize; + unsigned int instances; + timeout_t timeout; + struct list_head servers; /* list of servers using this pipe */ + struct async_queue *waiters; /* list of clients waiting to connect */ +}; + +struct named_pipe_device +{ + struct object obj; /* object header */ + struct fd *fd; /* pseudo-fd for ioctls */ +#if 0 + struct namespace *pipes; /* named pipe namespace */ +#endif + obj_handle_t *pipes; /* named pipe namespace */ +}; + +static void named_pipe_dump( struct object *obj, int verbose ); +static unsigned int named_pipe_map_access( struct object *obj, unsigned int access ); +static struct object *named_pipe_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ); +static void named_pipe_destroy( struct object *obj ); + +static const struct object_ops named_pipe_ops = +{ + sizeof(struct named_pipe), /* size */ + named_pipe_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + named_pipe_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + named_pipe_open_file, /* open_file */ + no_close_handle, /* close_handle */ + named_pipe_destroy /* destroy */ +}; + +/* server end functions */ +static void pipe_server_dump( struct object *obj, int verbose ); +static struct fd *pipe_server_get_fd( struct object *obj ); +static void pipe_server_destroy( struct object *obj); +static void pipe_server_flush( struct fd *fd, struct kevent **event ); +static enum server_fd_type pipe_server_get_fd_type( struct fd *fd ); +static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, + const void *data, data_size_t size ); +extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); + +static const struct object_ops pipe_server_ops = +{ + sizeof(struct pipe_server), /* size */ + pipe_server_dump, /* dump */ + no_get_type, /* get_type */ + pipe_server_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + pipe_server_destroy /* destroy */ +}; + +static const struct fd_ops pipe_server_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + pipe_server_flush, /* flush */ + pipe_server_get_fd_type, /* get_fd_type */ + pipe_server_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async, /* cancel_async */ +}; + +/* client end functions */ +static void pipe_client_dump( struct object *obj, int verbose ); +static struct fd *pipe_client_get_fd( struct object *obj ); +static void pipe_client_destroy( struct object *obj ); +static void pipe_client_flush( struct fd *fd, struct kevent **event ); +static enum server_fd_type pipe_client_get_fd_type( struct fd *fd ); + +static const struct object_ops pipe_client_ops = +{ + sizeof(struct pipe_client), /* size */ + pipe_client_dump, /* dump */ + no_get_type, /* get_type */ + pipe_client_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + pipe_client_destroy /* destroy */ +}; + +static const struct fd_ops pipe_client_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + pipe_client_flush, /* flush */ + pipe_client_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + +static void named_pipe_device_dump( struct object *obj, int verbose ); +static struct object_type *named_pipe_device_get_type( struct object *obj ); +static struct fd *named_pipe_device_get_fd( struct object *obj ); +static struct object *named_pipe_device_lookup_name( struct object *obj, + struct unicode_str *name, unsigned int attr ); +static struct object *named_pipe_device_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ); +static void named_pipe_device_destroy( struct object *obj ); +static enum server_fd_type named_pipe_device_get_fd_type( struct fd *fd ); +static obj_handle_t named_pipe_device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, + const void *data, data_size_t size ); + +static const struct object_ops named_pipe_device_ops = +{ + sizeof(struct named_pipe_device), /* size */ + named_pipe_device_dump, /* dump */ + named_pipe_device_get_type, /* get_type */ + named_pipe_device_get_fd, /* get_fd */ + no_map_access, /* map_access */ + named_pipe_device_lookup_name, /* lookup_name */ + named_pipe_device_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + named_pipe_device_destroy /* destroy */ +}; + +static const struct fd_ops named_pipe_device_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + named_pipe_device_get_fd_type, /* get_fd_type */ + named_pipe_device_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + +static NTSTATUS +parse_named_pipe( + IN PVOID ParseObject, + IN PVOID ObjectType, + IN OUT PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN OUT PUNICODE_STRING CompleteName, + IN OUT PUNICODE_STRING RemainingName, + IN OUT PVOID Context OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + OUT PVOID *Object + ); + +#define NAMED_PIPE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) +static WCHAR NamedPipeName[] = {'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', 0}; +static WCHAR dir_named_pipe[] = {'\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', 0}; +static WCHAR link_pipe[] = {'\\', '?', '?', '\\', 'P', 'I', 'P', 'E', 0}; +static WCHAR named_pipe[] = {'N', 'a', 'm', 'e', 'd', 'P', 'i', 'p', 'e', 0}; +extern HANDLE device_handle; +POBJECT_TYPE namedpipe_object_type; + +void init_named_pipe(void) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name, LinkName; + OBJECT_ATTRIBUTES obj_attr; + PVOID object; + NTSTATUS status; + + ktrace("init_named_pipe\n"); + /* Initialize the File object type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)NamedPipeName); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(struct named_pipe_device); + ObjectTypeInitializer.ParseProcedure = parse_named_pipe; + create_type_object(&ObjectTypeInitializer, &Name, &namedpipe_object_type); + + init_unistr(&Name, (PWSTR)named_pipe); + INIT_OBJECT_ATTR(&obj_attr, &Name, 0, device_handle, NULL); + + status = create_object(KernelMode, + namedpipe_object_type, + &obj_attr, + KernelMode, + NULL, + named_pipe_device_ops.size, + 0, + 0, + (PVOID *)&object); + if (!NT_SUCCESS(status)) + return; + + status = insert_object(object, + NULL, + 0, + 0, + NULL, + NULL); + if (!NT_SUCCESS(status)) + return; + + BODY_TO_HEADER(object)->ops = &named_pipe_device_ops; + + init_unistr(&Name, (PWSTR)dir_named_pipe); + init_unistr(&LinkName, (PWSTR)link_pipe); + io_create_symbol_link(&LinkName, &Name); +} + +static void named_pipe_dump( struct object *obj, int verbose ) +{ +#if 0 + struct named_pipe *pipe = (struct named_pipe *) obj; + assert( obj->ops == &named_pipe_ops ); + fprintf( stderr, "Named pipe " ); + dump_object_name( &pipe->obj ); + fprintf( stderr, "\n" ); +#endif +} + +static unsigned int named_pipe_map_access( struct object *obj, unsigned int access ) +{ + if (access & GENERIC_READ) + access |= STANDARD_RIGHTS_READ; + if (access & GENERIC_WRITE) + access |= STANDARD_RIGHTS_WRITE | FILE_CREATE_PIPE_INSTANCE; + if (access & GENERIC_EXECUTE) + access |= STANDARD_RIGHTS_EXECUTE; + if (access & GENERIC_ALL) + access |= STANDARD_RIGHTS_ALL; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +static void pipe_server_dump( struct object *obj, int verbose ) +{ +#if 0 + struct pipe_server *server = (struct pipe_server *) obj; + assert( obj->ops == &pipe_server_ops ); + fprintf( stderr, "Named pipe server pipe=%p state=%d\n", server->pipe, server->state ); +#endif +} + +static void pipe_client_dump( struct object *obj, int verbose ) +{ +#if 0 + struct pipe_client *client = (struct pipe_client *) obj; + assert( obj->ops == &pipe_client_ops ); + fprintf( stderr, "Named pipe client server=%p\n", client->server ); +#endif +} + +static void named_pipe_destroy( struct object *obj) +{ + struct named_pipe *pipe = (struct named_pipe *) obj; + +#if 0 + assert( list_empty( &pipe->servers ) ); + assert( !pipe->instances ); +#endif + free_async_queue( pipe->waiters ); +} + +static struct fd *pipe_client_get_fd( struct object *obj ) +{ + struct pipe_client *client = (struct pipe_client *) obj; + if (client->fd) + return (struct fd *) grab_object( client->fd ); + set_error( STATUS_PIPE_DISCONNECTED ); + return NULL; +} + +static void set_server_state( struct pipe_server *server, enum pipe_state state ) +{ + server->state = state; + + switch(state) { + case ps_connected_server: + case ps_wait_disconnect: +#if 0 + assert( server->fd ); +#endif + break; + case ps_wait_open: + case ps_idle_server: +#if 0 + assert( !server->fd ); +#endif + set_no_fd_status( server->ioctl_fd, STATUS_PIPE_LISTENING ); + break; + case ps_disconnected_server: + case ps_wait_connect: +#if 0 + assert( !server->fd ); +#endif + set_no_fd_status( server->ioctl_fd, STATUS_PIPE_DISCONNECTED ); + break; + } +} + +static struct fd *pipe_server_get_fd( struct object *obj ) +{ + struct pipe_server *server = (struct pipe_server *) obj; + + return (struct fd *)grab_object( server->fd ? server->fd : server->ioctl_fd ); +} + + +static void notify_empty( struct pipe_server *server ) +{ + if (!server->flush_poll) + return; +#if 0 + assert( server->state == ps_connected_server ); + assert( server->event ); +#endif + remove_timeout_user( server->flush_poll ); + server->flush_poll = NULL; + set_event( server->event, EVENT_INCREMENT, FALSE ); + release_object( server->event ); + server->event = NULL; +} + +extern int uk_shutdown(int s, int how); + +static void do_disconnect( struct pipe_server *server ) +{ + /* we may only have a server fd, if the client disconnected */ + if (server->client) { +#if 0 + assert( server->client->server == server ); + assert( server->client->fd ); +#endif + release_object( server->client->fd ); + server->client->fd = NULL; + } +#if 0 + assert( server->fd ); +#endif + uk_shutdown( get_unix_fd( server->fd ), SHUT_RDWR ); + release_object( server->fd ); + server->fd = NULL; +} + +static void pipe_server_destroy( struct object *obj) +{ + struct pipe_server *server = (struct pipe_server *)obj; + +#if 0 + assert( obj->ops == &pipe_server_ops ); +#endif + + if (server->fd) { + notify_empty( server ); + do_disconnect( server ); + } + + if (server->client) { + server->client->server = NULL; + server->client = NULL; + } + +#if 0 + assert( server->pipe->instances ); +#endif + server->pipe->instances--; + + if (server->ioctl_fd) + release_object( server->ioctl_fd ); + list_remove( &server->entry ); + release_object( server->pipe ); +} + +static void pipe_client_destroy( struct object *obj) +{ + struct pipe_client *client = (struct pipe_client *)obj; + struct pipe_server *server = client->server; + +#if 0 + assert( obj->ops == &pipe_client_ops ); +#endif + + if (server) { + notify_empty( server ); + + switch(server->state) { + case ps_connected_server: + /* Don't destroy the server's fd here as we can't + do a successful flush without it. */ + set_server_state( server, ps_wait_disconnect ); + break; + case ps_disconnected_server: + set_server_state( server, ps_wait_connect ); + break; + case ps_idle_server: + case ps_wait_open: + case ps_wait_disconnect: + case ps_wait_connect: +#if 0 + assert( 0 ); /* D.M. TBD */ +#endif + ; + } +#if 0 + assert( server->client ); +#endif + server->client = NULL; + client->server = NULL; + } + if (client->fd) + release_object( client->fd ); +} + +static void named_pipe_device_dump( struct object *obj, int verbose ) +{ +#if 0 + assert( obj->ops == &named_pipe_device_ops ); + fprintf( stderr, "Named pipe device\n" ); +#endif +} + +extern struct object_type *get_object_type( const struct unicode_str* ); + +static struct object_type *named_pipe_device_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'D','e','v','i','c','e'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +static struct fd *named_pipe_device_get_fd( struct object *obj ) +{ + struct named_pipe_device *device = (struct named_pipe_device *)obj; + return (struct fd *)grab_object( device->fd ); +} + +static struct object *named_pipe_device_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ) +{ +#if 0 + struct named_pipe_device *device = (struct named_pipe_device*)obj; + struct object *found; + + assert( obj->ops == &named_pipe_device_ops ); + assert( device->pipes ); + + if ((found = find_object( device->pipes, name, attr | OBJ_CASE_INSENSITIVE ))) + name->len = 0; + + return found; +#endif + return NULL; +} + +static struct object *named_pipe_device_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ) +{ + return grab_object( obj ); +} + +static void named_pipe_device_destroy( struct object *obj ) +{ + struct named_pipe_device *device = (struct named_pipe_device*)obj; + +#if 0 + assert( obj->ops == &named_pipe_device_ops ); +#endif + if (device->fd) + release_object( device->fd ); + NtClose(device->pipes); +#if 0 + free( device->pipes ); +#endif +} + +static enum server_fd_type named_pipe_device_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_DEVICE; +} + +static WCHAR PipeRoot[] = {'P', 'i', 'p', 'e', 'R', 'o', 'o', 't', 0}; +static POBJECT_DIRECTORY PipeNameSpace; + +void create_named_pipe_device( struct directory *root, const struct unicode_str *name ) +{ + struct named_pipe_device *dev; + UNICODE_STRING pipe_root; + OBJECT_ATTRIBUTES ObjectAttributes; + + if ((dev = create_named_object_dir( root, name, 0, &named_pipe_device_ops )) && + get_error() != STATUS_OBJECT_NAME_EXISTS) { + init_unistr(&pipe_root, (PWSTR)PipeRoot); + INIT_OBJECT_ATTR(&ObjectAttributes, + &pipe_root, + 0, + NULL, + NULL); + create_object(KernelMode, + dir_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID *)&PipeNameSpace); + create_handle(NULL, + PipeNameSpace, + 0, + ObjectAttributes.Attributes & OBJ_INHERIT, + (PHANDLE)&dev->pipes); + + if (!dev->pipes || !(dev->fd = alloc_pseudo_fd( &named_pipe_device_fd_ops, &dev->obj, 0 ))) { + release_object( dev ); + dev = NULL; + } + } + if (dev) + make_object_static( &dev->obj ); +} + +extern int uk_poll(struct pollfd *ufds, int nfds, int timeout); + +static int pipe_data_remaining( struct pipe_server *server ) +{ + struct pollfd pfd; + int fd; + +#if 0 + assert( server->client ); +#endif + + fd = get_unix_fd( server->client->fd ); + if (fd < 0) + return 0; + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + + if (0 > uk_poll( &pfd, 1, 0 )) + return 0; + + return pfd.revents&POLLIN; +} + +static void check_flushed( void *arg ) +{ + struct pipe_server *server = (struct pipe_server*) arg; + +#if 0 + assert( server->event ); +#endif + if (pipe_data_remaining( server )) { + server->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, server ); + } + else { + /* notify_empty( server ); */ + server->flush_poll = NULL; + set_event( server->event, EVENT_INCREMENT, FALSE ); + release_object( server->event ); + server->event = NULL; + } +} + +static void pipe_server_flush( struct fd *fd, struct kevent **event ) +{ + struct pipe_server *server = get_fd_user( fd ); + + if (!server || server->state != ps_connected_server) + return; + + /* FIXME: if multiple threads flush the same pipe, + maybe should create a list of processes to notify */ + if (server->flush_poll) + return; + + if (pipe_data_remaining( server )) { + /* this kind of sux - + there's no unix way to be alerted when a pipe becomes empty */ + server->event = create_event( NULL, NULL, 0, 0, 0, NULL ); + if (!server->event) + return; + server->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, server ); + *event = server->event; + } +} + +static void pipe_client_flush( struct fd *fd, struct kevent **event ) +{ + /* FIXME: what do we have to do for this? */ +} + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 + +static inline int is_overlapped( unsigned int options ) +{ + return !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)); +} + +static enum server_fd_type pipe_server_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_PIPE; +} + +static enum server_fd_type pipe_client_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_PIPE; +} + +static obj_handle_t alloc_wait_event( struct w32process *process ) +{ + obj_handle_t handle = 0; + struct kevent *event = create_event( NULL, NULL, 0, 1, 0, NULL ); + + if (event) { + handle = alloc_handle( process, event, EVENT_ALL_ACCESS, 0 ); + release_object( event ); + } + return handle; +} + +static obj_handle_t pipe_server_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, + const void *data, data_size_t size ) +{ + struct pipe_server *server = get_fd_user( fd ); + struct async *async; + obj_handle_t wait_handle = 0; + + switch(code) { + case FSCTL_PIPE_LISTEN: + switch(server->state) { + case ps_idle_server: + case ps_wait_connect: + if (!async_data->event && !async_data->apc) { + async_data_t new_data = *async_data; + if (!(wait_handle = alloc_wait_event( get_current_w32process() ))) + break; + new_data.event = wait_handle; + if (!(async = fd_queue_async( server->ioctl_fd, &new_data, ASYNC_TYPE_WAIT, 0 ))) { + close_handle( get_current_eprocess(), wait_handle ); + break; + } + } + else async = fd_queue_async( server->ioctl_fd, async_data, ASYNC_TYPE_WAIT, 0 ); + + if (async) { + set_server_state( server, ps_wait_open ); + if (server->pipe->waiters) + async_wake_up( server->pipe->waiters, STATUS_SUCCESS ); + release_object( async ); + set_error( STATUS_PENDING ); + return wait_handle; + } + break; + case ps_connected_server: + set_error( STATUS_PIPE_CONNECTED ); + break; + case ps_disconnected_server: + set_error( STATUS_PIPE_BUSY ); + break; + case ps_wait_disconnect: + set_error( STATUS_NO_DATA_DETECTED ); + break; + case ps_wait_open: + set_error( STATUS_INVALID_HANDLE ); + break; + } + return 0; + + case FSCTL_PIPE_DISCONNECT: + switch(server->state) { + case ps_connected_server: +#if 0 + assert( server->client ); + assert( server->client->fd ); +#endif + + notify_empty( server ); + + /* dump the client and server fds, but keep the pointers + around - client loses all waiting data */ + do_disconnect( server ); + set_server_state( server, ps_disconnected_server ); + break; + case ps_wait_disconnect: +#if 0 + assert( !server->client ); +#endif + do_disconnect( server ); + set_server_state( server, ps_wait_connect ); + break; + case ps_idle_server: + case ps_wait_open: + set_error( STATUS_PIPE_LISTENING ); + break; + case ps_disconnected_server: + case ps_wait_connect: + set_error( STATUS_PIPE_DISCONNECTED ); + break; + } + return 0; + + default: + return default_fd_ioctl( fd, code, async_data, data, size ); + } +} + +extern void clear_error(void); + +static struct named_pipe *create_named_pipe( obj_handle_t root, const struct unicode_str *name, + unsigned int attr ) +{ + struct named_pipe *pipe = NULL; + + if (!name || !name->len) + return alloc_wine_object( &named_pipe_ops ); + + pipe = create_wine_object(root, &named_pipe_ops, name, NULL); + if (pipe) + clear_error(); + return pipe; +} + +static struct pipe_server *get_pipe_server_obj( struct w32process *process, + obj_handle_t handle, unsigned int access ) +{ + struct object *obj; + obj = get_wine_handle_obj( process, handle, access, &pipe_server_ops ); + return (struct pipe_server *) obj; +} + +static struct pipe_server *create_pipe_server( struct named_pipe *pipe, unsigned int options ) +{ + struct pipe_server *server; + + server = alloc_wine_object( &pipe_server_ops ); + if (!server) + return NULL; + + server->fd = NULL; + server->pipe = pipe; + server->client = NULL; + server->flush_poll = NULL; + server->options = options; + + list_add_head( &pipe->servers, &server->entry ); + grab_object( pipe ); + if (!(server->ioctl_fd = alloc_pseudo_fd( &pipe_server_fd_ops, &server->obj, options ))) { + release_object( server ); + return NULL; + } + set_server_state( server, ps_idle_server ); + return server; +} + +static struct pipe_client *create_pipe_client( unsigned int flags ) +{ + struct pipe_client *client; + + client = alloc_wine_object( &pipe_client_ops ); + if (!client) + return NULL; + + client->fd = NULL; + client->server = NULL; + client->flags = flags; + + return client; +} + +static struct pipe_server *find_available_server( struct named_pipe *pipe ) +{ + struct pipe_server *server; + + /* look for pipe servers that are listening */ + LIST_FOR_EACH_ENTRY( server, &pipe->servers, struct pipe_server, entry ) { + if (server->state == ps_wait_open) + return (struct pipe_server *)grab_object( server ); + } + + /* fall back to pipe servers that are idle */ + LIST_FOR_EACH_ENTRY( server, &pipe->servers, struct pipe_server, entry ) { + if (server->state == ps_idle_server) + return (struct pipe_server *)grab_object( server ); + } + + return NULL; +} + +extern int uk_socketpair(int d, int type, int protocol, int sv[]); +#define AF_UNIX 1 /* Unix domain sockets */ +#define PF_UNIX AF_UNIX +#define SOCK_STREAM 1 +#define SOL_SOCKET 0xffff +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 +extern int uk_setsockopt(int s, int level, int optname, const void *optval, int optlen); + +struct object *named_pipe_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ) +{ + struct named_pipe *pipe = (struct named_pipe *)obj; + struct pipe_server *server; + struct pipe_client *client; + int fds[2]; + + if (!(server = find_available_server( pipe ))) { + set_error( STATUS_PIPE_NOT_AVAILABLE ); + return NULL; + } + + if ((client = create_pipe_client( options ))) { + if (uk_socketpair( PF_UNIX, SOCK_STREAM, 0, fds ) >= 0) { +#if 0 + assert( !server->fd ); +#endif + + /* for performance reasons, only set nonblocking mode when using + * overlapped I/O. Otherwise, we will be doing too much busy + * looping */ + if (is_overlapped( options )) uk_fcntl( fds[1], F_SETFL, O_NONBLOCK ); + if (is_overlapped( server->options )) uk_fcntl( fds[0], F_SETFL, O_NONBLOCK ); + + if (pipe->insize) { + uk_setsockopt( fds[0], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) ); + uk_setsockopt( fds[1], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) ); + } + if (pipe->outsize) { + uk_setsockopt( fds[0], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) ); + uk_setsockopt( fds[1], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) ); + } + + client->fd = create_anonymous_fd( &pipe_client_fd_ops, fds[1], &client->obj, options ); + server->fd = create_anonymous_fd( &pipe_server_fd_ops, fds[0], &server->obj, server->options ); + if (client->fd && server->fd) { + if (server->state == ps_wait_open) + fd_async_wake_up( server->ioctl_fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS ); + set_server_state( server, ps_connected_server ); + server->client = client; + client->server = server; + } + else { + release_object( client ); + client = NULL; + } + } + else { +#if 0 + file_set_error(); +#endif + release_object( client ); + client = NULL; + } + } + release_object( server ); + return &client->obj; +} + +typedef struct _FILE_PIPE_WAIT_FOR_BUFFER { + LARGE_INTEGER Timeout; + ULONG NameLength; + BOOLEAN TimeoutSpecified; + WCHAR Name[1]; +} FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER; +typedef signed __int64 INT_PTR, *PINT_PTR; +#define FIELD_OFFSET(type, field) (/*(LONG)(INT_PTR)&*/(((type *)0)->field)) /* D.M. TBD */ + +static obj_handle_t named_pipe_device_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async_data, + const void *data, data_size_t size ) +{ + struct named_pipe_device *device = get_fd_user( fd ); + + switch(code) { + case FSCTL_PIPE_WAIT: + { + const FILE_PIPE_WAIT_FOR_BUFFER *buffer = data; + obj_handle_t wait_handle = 0; + struct named_pipe *pipe; + struct pipe_server *server; + struct unicode_str name; + + if (size < sizeof(*buffer) || + size < FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[buffer->NameLength/sizeof(WCHAR)])) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + name.str = buffer->Name; + name.len = (buffer->NameLength / sizeof(WCHAR)) * sizeof(WCHAR); + if (!(pipe = (struct named_pipe *)find_object( device->pipes, &name, OBJ_CASE_INSENSITIVE ))) { + set_error( STATUS_PIPE_NOT_AVAILABLE ); + return 0; + } + if (!(server = find_available_server( pipe ))) { + struct async *async; + + if (!pipe->waiters && !(pipe->waiters = create_async_queue( NULL ))) goto done; + + if (!async_data->event && !async_data->apc) { + async_data_t new_data = *async_data; + if (!(wait_handle = alloc_wait_event( get_current_w32process() ))) goto done; + new_data.event = wait_handle; + if (!(async = create_async( current_thread, pipe->waiters, &new_data ))) { + close_handle( get_current_eprocess(), wait_handle ); + wait_handle = 0; + } + } + else async = create_async( current_thread, pipe->waiters, async_data ); + + if (async) { + timeout_t when = buffer->TimeoutSpecified ? buffer->Timeout.QuadPart : pipe->timeout; + async_set_timeout( async, when, STATUS_IO_TIMEOUT ); + release_object( async ); + set_error( STATUS_PENDING ); + } + } + else release_object( server ); + + done: + release_object( pipe ); + return wait_handle; + } + + default: + return default_fd_ioctl( fd, code, async_data, data, size ); + } +} + +static NTSTATUS +parse_named_pipe( + IN PVOID ParseObject, + IN PVOID ObjectType, + IN OUT PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN OUT PUNICODE_STRING CompleteName, + IN OUT PUNICODE_STRING RemainingName, + IN OUT PVOID Context OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + OUT PVOID *Object + ) +{ + struct named_pipe_device *device = (struct named_pipe_device *)ParseObject; + NTSTATUS status; + + status = ref_object_by_handle( + device->pipes, + NAMED_PIPE_ALL_ACCESS, + NULL, + KernelMode, + Object, + NULL); + + return status; +} + +DECL_HANDLER(create_named_pipe) +{ + struct named_pipe *pipe; + struct pipe_server *server; + struct unicode_str name; + struct directory *root = NULL; + + reply->handle = 0; + get_req_unicode_str( &name ); + + pipe = create_named_pipe( req->rootdir, &name, req->attributes | OBJ_OPENIF ); + + if (root) + release_object( root ); + if (!pipe) + return; + + if (get_error() != STATUS_OBJECT_NAME_EXISTS) { + /* initialize it if it didn't already exist */ + pipe->instances = 0; + pipe->waiters = NULL; + INIT_LIST_HEAD( &pipe->servers ); + pipe->insize = req->insize; + pipe->outsize = req->outsize; + pipe->maxinstances = req->maxinstances; + pipe->timeout = req->timeout; + pipe->flags = req->flags; + } + else { + if (pipe->maxinstances <= pipe->instances) { + set_error( STATUS_INSTANCE_NOT_AVAILABLE ); + release_object( pipe ); + return; + } + if ((pipe->maxinstances != req->maxinstances) || + (pipe->timeout != req->timeout) || + (pipe->flags != req->flags)) { + set_error( STATUS_ACCESS_DENIED ); + release_object( pipe ); + return; + } + clear_error(); /* clear the name collision */ + } + + server = create_pipe_server( pipe, req->options ); + if (server) { + reply->handle = alloc_handle( get_current_w32process(), server, req->access, req->attributes ); + server->pipe->instances++; + release_object( server ); + } + + release_object( pipe ); +} + +DECL_HANDLER(get_named_pipe_info) +{ + struct pipe_server *server; + struct pipe_client *client = NULL; + + server = get_pipe_server_obj( get_current_w32process(), req->handle, FILE_READ_ATTRIBUTES ); + if (!server) { + clear_error(); + client = (struct pipe_client *)get_wine_handle_obj( get_current_w32process(), req->handle, + FILE_READ_ATTRIBUTES, &pipe_client_ops ); + if (!client) + return; + server = client->server; + } + + reply->flags = server->pipe->flags; + reply->maxinstances = server->pipe->maxinstances; + reply->instances = server->pipe->instances; + reply->insize = server->pipe->insize; + reply->outsize = server->pipe->outsize; + + if (client) + release_object(client); + else { + reply->flags |= NAMED_PIPE_SERVER_END; + release_object(server); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/device/serial.c b/unifiedkernel/device/serial.c new file mode 100644 index 0000000..e048d54 --- /dev/null +++ b/unifiedkernel/device/serial.c @@ -0,0 +1,260 @@ +/* + * serial.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * serial.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +static void serial_dump( struct object *obj, int verbose ); +static struct fd *serial_get_fd( struct object *obj ); +static void serial_destroy(struct object *obj); + +static enum server_fd_type serial_get_fd_type( struct fd *fd ); +static void serial_flush( struct fd *fd, struct kevent **event ); +static void serial_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +struct serial +{ + struct object obj; + struct fd *fd; + + /* timeout values */ + unsigned int readinterval; + unsigned int readconst; + unsigned int readmult; + unsigned int writeconst; + unsigned int writemult; + + unsigned int eventmask; + + struct termios original; + + /* FIXME: add dcb, comm status, handler module, sharing */ +}; + +extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); + +static const struct object_ops serial_ops = +{ + sizeof(struct serial), /* size */ + serial_dump, /* dump */ + no_get_type, /* get_type */ + serial_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + serial_destroy /* destroy */ +}; + +static const struct fd_ops serial_fd_ops = +{ + default_fd_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + serial_flush, /* flush */ + serial_get_fd_type, /* get_file_info */ + default_fd_ioctl, /* ioctl */ + serial_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + +/* check if the given fd is a serial port */ +int is_serial_fd( struct fd *fd ) +{ +#if 0 + struct termios tios; + + return !tcgetattr( get_unix_fd(fd), &tios ); /* D.M. TBD */ +#endif + return 0; +} + +/* create a serial object for a given fd */ +struct object *create_serial( struct fd *fd ) +{ + struct serial *serial; + + if (!(serial = alloc_wine_object( &serial_ops ))) + return NULL; + + serial->readinterval = 0; + serial->readmult = 0; + serial->readconst = 0; + serial->writemult = 0; + serial->writeconst = 0; + serial->eventmask = 0; + serial->fd = (struct fd *)grab_object( fd ); + set_fd_user( fd, &serial_fd_ops, &serial->obj ); + return &serial->obj; +} + +static struct fd *serial_get_fd( struct object *obj ) +{ + struct serial *serial = (struct serial *)obj; + return (struct fd *)grab_object( serial->fd ); +} + +static void serial_destroy( struct object *obj) +{ + struct serial *serial = (struct serial *)obj; + release_object( serial->fd ); +} + +static void serial_dump( struct object *obj, int verbose ) +{ +#if 0 + struct serial *serial = (struct serial *)obj; + assert( obj->ops == &serial_ops ); + fprintf( stderr, "Port fd=%p mask=%x\n", serial->fd, serial->eventmask ); +#endif +} + +static struct serial *get_serial_obj( struct w32process *process, obj_handle_t handle, unsigned int access ) +{ + return (struct serial *)get_wine_handle_obj( process, handle, access, &serial_ops ); +} + +static enum server_fd_type serial_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_SERIAL; +} + +static void serial_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) +{ + struct serial *serial = get_fd_user( fd ); + timeout_t timeout = 0; + struct async *async; + +#if 0 + assert(serial->obj.ops == &serial_ops); +#endif + + switch (type) { + case ASYNC_TYPE_READ: + timeout = serial->readconst + (timeout_t)serial->readmult*count; + break; + case ASYNC_TYPE_WRITE: + timeout = serial->writeconst + (timeout_t)serial->writemult*count; + break; + } + + if ((async = fd_queue_async( fd, data, type, count ))) { + if (timeout) + async_set_timeout( async, timeout * -10000, STATUS_TIMEOUT ); + release_object( async ); + set_error( STATUS_PENDING ); + } +} + +static void serial_flush( struct fd *fd, struct kevent **event ) +{ + /* MSDN says: If hFile is a handle to a communications device, + * the function only flushes the transmit buffer. + */ +#if 0 + if (tcflush( get_unix_fd(fd), TCOFLUSH ) == -1) + file_set_error(); /* D.M. TBD */ +#endif +} + +DECL_HANDLER(get_serial_info) +{ + struct serial *serial; + + if ((serial = get_serial_obj( get_current_w32process(), req->handle, 0 ))) { + /* timeouts */ + reply->readinterval = serial->readinterval; + reply->readconst = serial->readconst; + reply->readmult = serial->readmult; + reply->writeconst = serial->writeconst; + reply->writemult = serial->writemult; + + /* event mask */ + reply->eventmask = serial->eventmask; + + release_object( serial ); + } +} + +DECL_HANDLER(set_serial_info) +{ + struct serial *serial; + + if ((serial = get_serial_obj( get_current_w32process(), req->handle, 0 ))) { + /* timeouts */ + if (req->flags & SERIALINFO_SET_TIMEOUTS) { + serial->readinterval = req->readinterval; + serial->readconst = req->readconst; + serial->readmult = req->readmult; + serial->writeconst = req->writeconst; + serial->writemult = req->writemult; + } + + /* event mask */ + if (req->flags & SERIALINFO_SET_MASK) { + serial->eventmask = req->eventmask; + if (!serial->eventmask) { + fd_async_wake_up( serial->fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS ); + } + } + + release_object( serial ); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/device/snapshot.c b/unifiedkernel/device/snapshot.c new file mode 100644 index 0000000..a4bccdc --- /dev/null +++ b/unifiedkernel/device/snapshot.c @@ -0,0 +1,290 @@ +/* + * snapshot.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * snapshot.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +struct snapshot +{ + struct object obj; /* object header */ + struct w32process *process; /* process of this snapshot (for modules and heaps) */ + struct process_snapshot *processes; /* processes snapshot */ + int process_count; /* count of processes */ + int process_pos; /* current position in proc snapshot */ + struct thread_snapshot *threads; /* threads snapshot */ + int thread_count; /* count of threads */ + int thread_pos; /* current position in thread snapshot */ + struct module_snapshot *modules; /* modules snapshot */ + int module_count; /* count of modules */ + int module_pos; /* current position in module snapshot */ +}; + +static void snapshot_dump( struct object *obj, int verbose ); +static void snapshot_destroy( struct object *obj ); + +static const struct object_ops snapshot_ops = +{ + sizeof(struct snapshot), /* size */ + snapshot_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + snapshot_destroy /* destroy */ +}; + +extern struct w32process *eprocess2process(struct eprocess *); + +/* create a new snapshot */ +static struct snapshot *create_snapshot( process_id_t pid, int flags ) +{ + struct w32process *process = NULL; + struct snapshot *snapshot; + + /* need a process for modules and heaps */ + if (flags & (SNAP_MODULE|SNAP_HEAPLIST)) { + if (!pid) + process = (struct w32process *)grab_object( get_current_w32process() ); + else if (!(process = eprocess2process(get_process_from_id((HANDLE) pid )))) + return NULL; + } + + if (!(snapshot = alloc_wine_object( &snapshot_ops ))) { + if (process) + release_object( process ); + return NULL; + } + + snapshot->process = process; + + snapshot->process_pos = 0; + snapshot->process_count = 0; + if (flags & SNAP_PROCESS) + snapshot->processes = process_snap( &snapshot->process_count ); + + snapshot->thread_pos = 0; + snapshot->thread_count = 0; + if (flags & SNAP_THREAD) + snapshot->threads = thread_snap( &snapshot->thread_count ); + + snapshot->module_pos = 0; + snapshot->module_count = 0; + if (flags & SNAP_MODULE) + snapshot->modules = module_snap( process, &snapshot->module_count ); + + return snapshot; +} + +/* get the next process in the snapshot */ +static int snapshot_next_process( struct snapshot *snapshot, struct next_process_reply *reply ) +{ + struct process_snapshot *ptr; + struct process_dll *exe_module; + + if (!snapshot->process_count) { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return 0; + } + if (snapshot->process_pos >= snapshot->process_count) { + set_error( STATUS_NO_MORE_FILES ); + return 0; + } + ptr = &snapshot->processes[snapshot->process_pos++]; + reply->count = ptr->count; + reply->pid = get_process_id( ptr->process ); + reply->ppid = ptr->process->parent ? get_process_id( ptr->process->parent ) : 0; + reply->heap = NULL; /* FIXME */ + reply->module = NULL; /* FIXME */ + reply->threads = ptr->threads; + reply->priority = ptr->priority; + reply->handles = ptr->handles; + if ((exe_module = get_process_exe_module( ptr->process )) && exe_module->filename) { + data_size_t len = min( exe_module->namelen, get_reply_max_size() ); + set_reply_data( exe_module->filename, len ); + } + return 1; +} + +extern thread_id_t get_thread_id( struct w32thread *thread ); + +/* get the next thread in the snapshot */ +static int snapshot_next_thread( struct snapshot *snapshot, struct next_thread_reply *reply ) +{ + struct thread_snapshot *ptr; + + if (!snapshot->thread_count) { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return 0; + } + if (snapshot->thread_pos >= snapshot->thread_count) { + set_error( STATUS_NO_MORE_FILES ); + return 0; + } + ptr = &snapshot->threads[snapshot->thread_pos++]; + reply->count = ptr->count; + reply->pid = get_process_id( ptr->thread->process ); + reply->tid = get_thread_id( ptr->thread ); + reply->base_pri = ptr->priority; + reply->delta_pri = 0; /* FIXME */ + return 1; +} + +/* get the next module in the snapshot */ +static int snapshot_next_module( struct snapshot *snapshot, struct next_module_reply *reply ) +{ + struct module_snapshot *ptr; + + if (!snapshot->module_count) { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return 0; + } + if (snapshot->module_pos >= snapshot->module_count) { + set_error( STATUS_NO_MORE_FILES ); + return 0; + } + ptr = &snapshot->modules[snapshot->module_pos++]; + reply->pid = get_process_id( snapshot->process ); + reply->base = ptr->base; + reply->size = ptr->size; + if (ptr->filename) { + data_size_t len = min( ptr->namelen, get_reply_max_size() ); + set_reply_data( ptr->filename, len ); + } + return 1; +} + +static void snapshot_dump( struct object *obj, int verbose ) +{ +#if 0 + struct snapshot *snapshot = (struct snapshot *)obj; + assert( obj->ops == &snapshot_ops ); + fprintf( stderr, "Snapshot: %d procs %d threads %d modules\n", + snapshot->process_count, snapshot->thread_count, snapshot->module_count ); +#endif +} + +static void snapshot_destroy( struct object *obj ) +{ + int i; + struct snapshot *snapshot = (struct snapshot *)obj; +#if 0 + assert( obj->ops == &snapshot_ops ); +#endif + if (snapshot->process_count) { + for (i = 0; i < snapshot->process_count; i++) + release_object( snapshot->processes[i].process ); + free( snapshot->processes ); + } + if (snapshot->thread_count) { + for (i = 0; i < snapshot->thread_count; i++) + release_object( snapshot->threads[i].thread ); + free( snapshot->threads ); + } + if (snapshot->module_count) { + for (i = 0; i < snapshot->module_count; i++) + free( snapshot->modules[i].filename ); + free( snapshot->modules ); + } + if (snapshot->process) + release_object( snapshot->process ); +} + +/* create a snapshot */ +DECL_HANDLER(create_snapshot) +{ + struct snapshot *snapshot; + + reply->handle = 0; + if ((snapshot = create_snapshot( req->pid, req->flags ))) { + reply->handle = alloc_handle( get_current_w32process(), snapshot, 0, req->attributes ); + release_object( snapshot ); + } +} + +/* get the next process from a snapshot */ +DECL_HANDLER(next_process) +{ + struct snapshot *snapshot; + + if ((snapshot = (struct snapshot *)get_wine_handle_obj( get_current_w32process(), req->handle, + 0, &snapshot_ops ))) { + if (req->reset) + snapshot->process_pos = 0; + snapshot_next_process( snapshot, reply ); + release_object( snapshot ); + } +} + +/* get the next thread from a snapshot */ +DECL_HANDLER(next_thread) +{ + struct snapshot *snapshot; + + if ((snapshot = (struct snapshot *)get_wine_handle_obj( get_current_w32process(), req->handle, + 0, &snapshot_ops ))) { + if (req->reset) + snapshot->thread_pos = 0; + snapshot_next_thread( snapshot, reply ); + release_object( snapshot ); + } +} + +/* get the next module from a snapshot */ +DECL_HANDLER(next_module) +{ + struct snapshot *snapshot; + + if ((snapshot = (struct snapshot *)get_wine_handle_obj( get_current_w32process(), req->handle, + 0, &snapshot_ops ))) { + if (req->reset) + snapshot->module_pos = 0; + snapshot_next_module( snapshot, reply ); + release_object( snapshot ); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/device/timer.c b/unifiedkernel/device/timer.c new file mode 100644 index 0000000..b0d6835 --- /dev/null +++ b/unifiedkernel/device/timer.c @@ -0,0 +1,297 @@ +/* + * timer.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * timer.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +struct timer +{ + struct object obj; /* object header */ + int manual; /* manual reset */ + int signaled; /* current signaled state */ + unsigned int period; /* timer period in ms */ + timeout_t when; /* next expiration */ + struct timeout_user *timeout; /* timeout user */ + struct w32thread *thread; /* thread that set the APC function */ + void *callback; /* callback APC function */ + void *arg; /* callback argument */ +}; + +static void timer_dump( struct object *obj, int verbose ); +static struct object_type *timer_get_type( struct object *obj ); +static unsigned int timer_map_access( struct object *obj, unsigned int access ); +static void timer_destroy( struct object *obj ); + +static const struct object_ops timer_ops = +{ + sizeof(struct timer), /* size */ + timer_dump, /* dump */ + timer_get_type, /* get_type */ + no_get_fd, /* get_fd */ + timer_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + timer_destroy /* destroy */ +}; + + +/* create a timer object */ +static struct timer *create_timer( struct directory *root, const struct unicode_str *name, + unsigned int attr, int manual ) +{ + struct timer *timer; + + if ((timer = create_named_object_dir( root, name, attr, &timer_ops ))) { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) { + /* initialize it if it didn't already exist */ + timer->manual = manual; + timer->signaled = 0; + timer->when = 0; + timer->period = 0; + timer->timeout = NULL; + timer->thread = NULL; + } + } + return timer; +} + +/* callback on timer expiration */ +static void timer_callback( void *private ) +{ + struct timer *timer = (struct timer *)private; + + /* queue an APC */ + if (timer->thread) { + apc_call_t data; + + memset( &data, 0, sizeof(data) ); + if (timer->callback) { + data.type = APC_TIMER; + data.timer.func = timer->callback; + data.timer.time = timer->when; + data.timer.arg = timer->arg; + } + else data.type = APC_NONE; /* wake up only */ + + if (!thread_queue_apc( timer->thread, &timer->obj, &data )) { + release_object( timer->thread ); + timer->thread = NULL; + } + } + + if (timer->period) /* schedule the next expiration */ { + timer->when += (timeout_t)timer->period * 10000; + timer->timeout = add_timeout_user( timer->when, timer_callback, timer ); + } + else timer->timeout = NULL; + + /* wake up waiters */ + timer->signaled = 1; + uk_wake_up( &timer->obj, 0 ); +} + +/* cancel a running timer */ +static int cancel_timer( struct timer *timer ) +{ + int signaled = timer->signaled; + + if (timer->timeout) { + remove_timeout_user( timer->timeout ); + timer->timeout = NULL; + } + if (timer->thread) { + thread_cancel_apc( timer->thread, &timer->obj, APC_TIMER ); + release_object( timer->thread ); + timer->thread = NULL; + } + return signaled; +} + +/* set the timer expiration and period */ +static int set_timer( struct timer *timer, timeout_t expire, unsigned int period, + void *callback, void *arg ) +{ + int signaled = cancel_timer( timer ); + if (timer->manual) { + period = 0; /* period doesn't make any sense for a manual timer */ + timer->signaled = 0; + } + timer->when = (expire <= 0) ? current_time - expire : max( (unsigned int)expire, current_time ); + timer->period = period; + timer->callback = callback; + timer->arg = arg; + if (callback) + timer->thread = (struct w32thread *)grab_object( current ); + timer->timeout = add_timeout_user( timer->when, timer_callback, timer ); + return signaled; +} + +static void timer_dump( struct object *obj, int verbose ) +{ +#if 0 + struct timer *timer = (struct timer *)obj; + assert( obj->ops == &timer_ops ); + fprintf( stderr, "Timer manual=%d when=%s period=%u ", + timer->manual, get_timeout_str(timer->when), timer->period ); + dump_object_name( &timer->obj ); + fputc( '\n', stderr ); +#endif +} + +extern struct object_type *get_object_type( const struct unicode_str* ); + +static struct object_type *timer_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'T','i','m','e','r'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +#define TIMER_QUERY_STATE 0x0001 +#define TIMER_MODIFY_STATE 0x0002 +#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +static unsigned int timer_map_access( struct object *obj, unsigned int access ) +{ + if (access & GENERIC_READ) + access |= STANDARD_RIGHTS_READ | SYNCHRONIZE | TIMER_QUERY_STATE; + if (access & GENERIC_WRITE) + access |= STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE; + if (access & GENERIC_EXECUTE) + access |= STANDARD_RIGHTS_EXECUTE; + if (access & GENERIC_ALL) + access |= TIMER_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +static void timer_destroy( struct object *obj ) +{ + struct timer *timer = (struct timer *)obj; +#if 0 + assert( obj->ops == &timer_ops ); +#endif + + if (timer->timeout) + remove_timeout_user( timer->timeout ); + if (timer->thread) + release_object( timer->thread ); +} + +/* create a timer */ +DECL_HANDLER(create_timer) +{ + struct timer *timer; + struct unicode_str name; + struct directory *root = NULL; + + reply->handle = 0; + get_req_unicode_str( &name ); + + if ((timer = create_timer( req->rootdir, &name, req->attributes, req->manual ))) { + reply->handle = alloc_handle( get_current_w32process(), timer, req->access, req->attributes ); + release_object( timer ); + } + + if (root) + release_object( root ); +} + +/* open a handle to a timer */ +DECL_HANDLER(open_timer) +{ + struct unicode_str name; + struct directory *root = NULL; + struct timer *timer; + + get_req_unicode_str( &name ); + + if ((timer = open_object_dir( req->rootdir, &name, req->attributes, &timer_ops ))) { + reply->handle = alloc_handle( get_current_w32process(), &timer->obj, req->access, req->attributes ); + release_object( timer ); + } + + if (root) + release_object( root ); +} + +/* set a waitable timer */ +DECL_HANDLER(set_timer) +{ + struct timer *timer; + + if ((timer = (struct timer *)get_wine_handle_obj( get_current_w32process(), req->handle, + TIMER_MODIFY_STATE, &timer_ops ))) { + reply->signaled = set_timer( timer, req->expire, req->period, req->callback, req->arg ); + release_object( timer ); + } +} + +/* cancel a waitable timer */ +DECL_HANDLER(cancel_timer) +{ + struct timer *timer; + + if ((timer = (struct timer *)get_wine_handle_obj( get_current_w32process(), req->handle, + TIMER_MODIFY_STATE, &timer_ops ))) { + reply->signaled = cancel_timer( timer ); + release_object( timer ); + } +} + +/* Get information on a waitable timer */ +DECL_HANDLER(get_timer_info) +{ + struct timer *timer; + + if ((timer = (struct timer *)get_wine_handle_obj( get_current_w32process(), req->handle, + TIMER_QUERY_STATE, &timer_ops ))) { + reply->when = timer->when; + reply->signaled = timer->signaled; + release_object( timer ); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/Makefile b/unifiedkernel/fs/Makefile new file mode 100644 index 0000000..d7f1f36 --- /dev/null +++ b/unifiedkernel/fs/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for fs management +# + +FS_OBJS := fd.o \ + file.o \ + directory.o \ + change.o \ + completion.o \ + mapping.o \ + symlink.o \ + async.o + +$(MODULE)-objs += $(addprefix fs/, $(FS_OBJS)) diff --git a/unifiedkernel/fs/async.c b/unifiedkernel/fs/async.c new file mode 100644 index 0000000..200eeeb --- /dev/null +++ b/unifiedkernel/fs/async.c @@ -0,0 +1,336 @@ +/* + * async.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * async.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" +#include "file.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +struct uk_completion; + +struct async +{ + struct object obj; /* object header */ + struct w32thread *thread; /* owning thread */ + struct list_head queue_entry; /* entry in async queue list */ + struct async_queue *queue; /* queue containing this async */ + unsigned int status; /* current status */ + struct timeout_user *timeout; + unsigned int timeout_status; /* status to report upon timeout */ + struct kevent *event; + struct uk_completion *completion; + unsigned long comp_key; + async_data_t data; /* data for async I/O call */ +}; + +static void async_dump( struct object *obj, int verbose ); +static void async_destroy( struct object *obj ); + +static const struct object_ops async_ops = +{ + sizeof(struct async), /* size */ + async_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + async_destroy /* destroy */ +}; + + +struct async_queue +{ + struct object obj; /* object header */ + struct fd *fd; /* file descriptor owning this queue */ + struct list_head queue; /* queue of async objects */ +}; + +static void async_queue_dump( struct object *obj, int verbose ); + +static const struct object_ops async_queue_ops = +{ + sizeof(struct async_queue), /* size */ + async_queue_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + + +static inline void async_reselect( struct async *async ) +{ + if (async->queue->fd) fd_reselect_async( async->queue->fd, async->queue ); +} + +static void async_dump( struct object *obj, int verbose ) +{ +#if 0 + struct async *async = (struct async *)obj; + assert( obj->ops == &async_ops ); + fprintf( stderr, "Async thread=%p\n", async->thread ); +#endif +} + +static void async_destroy( struct object *obj ) +{ + struct async *async = (struct async *)obj; +#if 0 + assert( obj->ops == &async_ops ); +#endif + + list_del( &async->queue_entry ); + async_reselect( async ); + + if (async->timeout) + remove_timeout_user( async->timeout ); + if (async->event) + release_object( async->event ); + if (async->completion) + release_object( async->completion ); + release_object( async->queue ); + release_object( async->thread ); +} + +static void async_queue_dump( struct object *obj, int verbose ) +{ +#if 0 + struct async_queue *async_queue = (struct async_queue *)obj; + assert( obj->ops == &async_queue_ops ); + fprintf( stderr, "Async queue fd=%p\n", async_queue->fd ); +#endif +} + +/* notifies client thread of new status of its async request */ +void async_terminate( struct async *async, unsigned int status ) +{ + apc_call_t data; + +#if 0 + assert( status != STATUS_PENDING ); +#endif + + if (async->status != STATUS_PENDING) { + /* already terminated, just update status */ + async->status = status; + return; + } + + memset( &data, 0, sizeof(data) ); + data.type = APC_ASYNC_IO; + data.async_io.func = async->data.callback; + data.async_io.user = async->data.arg; + data.async_io.sb = async->data.iosb; + data.async_io.status = status; + thread_queue_apc( async->thread, &async->obj, &data ); + async->status = status; + async_reselect( async ); + release_object( async ); /* so that it gets destroyed when the async is done */ +} + +/* callback for timeout on an async request */ +static void async_timeout( void *private ) +{ + struct async *async = private; + + async->timeout = NULL; + async_terminate( async, async->timeout_status ); +} + +/* create a new async queue for a given fd */ +struct async_queue *create_async_queue( struct fd *fd ) +{ + struct async_queue *queue = alloc_wine_object( &async_queue_ops ); + + if (queue) { + queue->fd = fd; + INIT_LIST_HEAD( &queue->queue ); + INIT_DISP_HEADER(&queue->obj.header, 0, sizeof(struct async_queue), 0); + } + return queue; +} + +/* free an async queue, cancelling all async operations */ +void free_async_queue( struct async_queue *queue ) +{ + if (!queue) + return; + queue->fd = NULL; + async_wake_up( queue, STATUS_HANDLES_CLOSED ); + release_object( queue ); +} + +extern void fd_assign_completion( struct fd *fd, struct uk_completion **p_port, unsigned long *p_key ); + +/* create an async on a given queue of a fd */ +struct async *create_async( struct w32thread *thread, struct async_queue *queue, const async_data_t *data ) +{ + struct kevent *event = NULL; + struct async *async; + + if (data->event && !(event = get_event_obj( thread->process, data->event, EVENT_MODIFY_STATE ))) + return NULL; + + if (!(async = alloc_wine_object( &async_ops ))) { + if (event) + release_object( event ); + return NULL; + } + + INIT_DISP_HEADER(&async->obj.header, 0, sizeof(struct async), 0); + async->thread = (struct w32thread *)grab_object( thread ); + async->event = event; + async->status = STATUS_PENDING; + async->data = *data; + async->timeout = NULL; + async->queue = (struct async_queue *)grab_object( queue ); + async->completion = NULL; + if (queue->fd) + fd_assign_completion( queue->fd, &async->completion, &async->comp_key ); + + list_add_tail( &async->queue_entry, &queue->queue ); + grab_object( async ); + + if (queue->fd) + set_fd_signaled( queue->fd, 0 ); + if (event) + reset_event( event ); + return async; +} + +/* set the timeout of an async operation */ +void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ) +{ + if (async->timeout) + remove_timeout_user( async->timeout ); + if (timeout != TIMEOUT_INFINITE) + async->timeout = add_timeout_user( timeout, async_timeout, async ); + else async->timeout = NULL; + async->timeout_status = status; +} + +extern void add_completion( struct uk_completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information ); + +/* store the result of the client-side async callback */ +void async_set_result( struct object *obj, unsigned int status, unsigned long total ) +{ + struct async *async = (struct async *)obj; + + if (BODY_TO_HEADER(obj)->ops != &async_ops) + return; /* in case the client messed up the APC results */ + +#if 0 + assert( async->status != STATUS_PENDING ); /* it must have been woken up if we get a result */ +#endif + + if (status == STATUS_PENDING) { /* restart it */ + status = async->status; + async->status = STATUS_PENDING; + grab_object( async ); + + if (status != STATUS_ALERTED) /* it was terminated in the meantime */ + async_terminate( async, status ); + else + async_reselect( async ); + } + else { + if (async->timeout) + remove_timeout_user( async->timeout ); + async->timeout = NULL; + async->status = status; + if (async->completion && async->data.cvalue) + add_completion( async->completion, async->comp_key, async->data.cvalue, status, total ); + if (async->data.apc) { + apc_call_t data; + memset( &data, 0, sizeof(data) ); + data.type = APC_USER; + data.user.func = async->data.apc; + data.user.args[0] = (unsigned long)async->data.arg; + data.user.args[1] = (unsigned long)async->data.iosb; + data.user.args[2] = 0; + thread_queue_apc( async->thread, NULL, &data ); + } + if (async->event) + set_event( async->event, EVENT_INCREMENT, FALSE ); + else if (async->queue->fd) + set_fd_signaled( async->queue->fd, 1 ); + } +} + +/* check if an async operation is waiting to be alerted */ +int async_waiting( struct async_queue *queue ) +{ + struct list_head *ptr; + struct async *async; + + if (!queue) + return 0; + if (!(ptr = (((&queue->queue)->next == &queue->queue) ? NULL: (&queue->queue)->next))) + return 0; + async = list_entry( ptr, struct async, queue_entry ); + return async->status == STATUS_PENDING; +} + +/* wake up async operations on the queue */ +void async_wake_up( struct async_queue *queue, unsigned int status ) +{ + struct list_head *ptr, *next; + + if (!queue) + return; + + list_for_each_safe( ptr, next, &queue->queue ) { + struct async *async = list_entry( ptr, struct async, queue_entry ); + async_terminate( async, status ); + if (status == STATUS_ALERTED) + break; /* only wake up the first one */ + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/change.c b/unifiedkernel/fs/change.c new file mode 100644 index 0000000..a44c489 --- /dev/null +++ b/unifiedkernel/fs/change.c @@ -0,0 +1,1105 @@ +/* + * change.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * change.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* dnotify support */ + +#ifdef linux +#ifndef F_NOTIFY +#define F_NOTIFY 1026 +#define DN_ACCESS 0x00000001 /* File accessed */ +#define DN_MODIFY 0x00000002 /* File modified */ +#define DN_CREATE 0x00000004 /* File created */ +#define DN_DELETE 0x00000008 /* File removed */ +#define DN_RENAME 0x00000010 /* File renamed */ +#define DN_ATTRIB 0x00000020 /* File changed attributes */ +#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ +#endif +#endif + +/* inotify support */ + +#if defined(__linux__) && defined(__i386__) + +#define SYS_inotify_init 291 +#define SYS_inotify_add_watch 292 +#define SYS_inotify_rm_watch 293 + +struct inotify_event { + int wd; + unsigned int mask; + unsigned int cookie; + unsigned int len; + char name[1]; +}; + +#define IN_ACCESS 0x00000001 +#define IN_MODIFY 0x00000002 +#define IN_ATTRIB 0x00000004 +#define IN_CLOSE_WRITE 0x00000008 +#define IN_CLOSE_NOWRITE 0x00000010 +#define IN_OPEN 0x00000020 +#define IN_MOVED_FROM 0x00000040 +#define IN_MOVED_TO 0x00000080 +#define IN_CREATE 0x00000100 +#define IN_DELETE 0x00000200 +#define IN_DELETE_SELF 0x00000400 + +static inline int inotify_init( void ) +{ +#if 0 /* D.M. TBD */ + int ret; + __asm__ __volatile__( "int $0x80" + : "=a" (ret) + : "0" (SYS_inotify_init)); + if (ret<0) { errno = -ret; ret = -1; } + return ret; +#endif + return 0; +} + +static inline int inotify_add_watch( int fd, const char *name, unsigned int mask ) +{ +#if 0 /* D.M. TBD */ + int ret; + __asm__ __volatile__( "pushl %%ebx;\n\t" + "movl %2,%%ebx;\n\t" + "int $0x80;\n\t" + "popl %%ebx" + : "=a" (ret) : "0" (SYS_inotify_add_watch), + "r" (fd), "c" (name), "d" (mask) ); + if (ret<0) { errno = -ret; ret = -1; } + return ret; +#endif + return 0; +} + +static inline int inotify_remove_watch( int fd, int wd ) +{ +#if 0 /* D.M. TBD */ + int ret; + __asm__ __volatile__( "pushl %%ebx;\n\t" + "movl %2,%%ebx;\n\t" + "int $0x80;\n\t" + "popl %%ebx" + : "=a" (ret) : "0" (SYS_inotify_rm_watch), + "r" (fd), "c" (wd) ); + if (ret<0) { errno = -ret; ret = -1; } + return ret; +#endif + return 0; +} + +#define USE_INOTIFY + +#endif + +struct uk_inode; + +static void free_inode( struct uk_inode *inode ); + +static struct fd *inotify_fd; + +struct change_record { + struct list_head entry; + int action; + int len; + char name[1]; +}; + +struct dir +{ + struct object obj; /* object header */ + struct fd *fd; /* file descriptor to the directory */ + struct list_head entry; /* entry in global change notifications list */ + unsigned int filter; /* notification filter */ + int notified; /* SIGIO counter */ + int want_data; /* return change data */ + int subtree; /* do we want to watch subdirectories? */ + struct list_head change_records; /* data for the change */ + struct list_head in_entry; /* entry in the inode dirs list */ + struct uk_inode *inode; /* inode of the associated directory */ +}; + +static struct fd *dir_get_fd( struct object *obj ); +static void dir_dump( struct object *obj, int verbose ); +static void dir_destroy( struct object *obj ); +extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); + +static const struct object_ops dir_ops = +{ + sizeof(struct dir), /* size */ + dir_dump, /* dump */ + no_get_type, /* get_type */ + dir_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + dir_destroy /* destroy */ +}; + +static int dir_get_poll_events( struct fd *fd ); +static enum server_fd_type dir_get_fd_type( struct fd *fd ); + +static const struct fd_ops dir_fd_ops = +{ + dir_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + dir_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + +static struct list_head change_list = LIST_HEAD_INIT(change_list); + +static void dnotify_adjust_changes( struct dir *dir ) +{ +#if defined(F_SETSIG) && defined(F_NOTIFY) + int fd = get_unix_fd( dir->fd ); + unsigned int filter = dir->filter; + unsigned int val; + if ( 0 > uk_fcntl( fd, F_SETSIG, SIGIO) ) + return; + + val = DN_MULTISHOT; + if (filter & FILE_NOTIFY_CHANGE_FILE_NAME) + val |= DN_RENAME | DN_DELETE | DN_CREATE; + if (filter & FILE_NOTIFY_CHANGE_DIR_NAME) + val |= DN_RENAME | DN_DELETE | DN_CREATE; + if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) + val |= DN_ATTRIB; + if (filter & FILE_NOTIFY_CHANGE_SIZE) + val |= DN_MODIFY; + if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE) + val |= DN_MODIFY; + if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS) + val |= DN_ACCESS; + if (filter & FILE_NOTIFY_CHANGE_CREATION) + val |= DN_CREATE; + if (filter & FILE_NOTIFY_CHANGE_SECURITY) + val |= DN_ATTRIB; + uk_fcntl( fd, F_NOTIFY, val ); +#endif +} + +/* insert change in the global list */ +static inline void insert_change( struct dir *dir ) +{ + sigset_t sigset; + + sigemptyset( &sigset ); + sigaddset( &sigset, SIGIO ); + sigprocmask( SIG_BLOCK, &sigset, NULL ); + list_add( &dir->entry, &change_list ); + sigprocmask( SIG_UNBLOCK, &sigset, NULL ); +} + +/* remove change from the global list */ +static inline void remove_change( struct dir *dir ) +{ + sigset_t sigset; + + sigemptyset( &sigset ); + sigaddset( &sigset, SIGIO ); + sigprocmask( SIG_BLOCK, &sigset, NULL ); + list_del( &dir->entry ); + sigprocmask( SIG_UNBLOCK, &sigset, NULL ); +} + +static void dir_dump( struct object *obj, int verbose ) +{ +#if 0 + struct dir *dir = (struct dir *)obj; + assert( obj->ops == &dir_ops ); + fprintf( stderr, "Dirfile fd=%p filter=%08x\n", dir->fd, dir->filter ); +#endif +} + +extern int interlocked_xchg_add( int*, int ); +extern int interlocked_xchg( int*, int ); + +/* enter here directly from SIGIO signal handler */ +void do_change_notify( int unix_fd ) +{ + struct dir *dir; + + /* FIXME: this is O(n) ... probably can be improved */ + list_for_each_entry( dir, &change_list, entry ) { + if (get_unix_fd( dir->fd ) != unix_fd) + continue; + interlocked_xchg_add( &dir->notified, 1 ); + break; + } +} + +/* SIGIO callback, called synchronously with the poll loop */ +void sigio_callback(void) +{ + struct dir *dir; + + list_for_each_entry( dir, &change_list, entry ) { + if (interlocked_xchg( &dir->notified, 0 )) + fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_NOTIFY_ENUM_DIR ); + } +} + +static struct fd *dir_get_fd( struct object *obj ) +{ + struct dir *dir = (struct dir *)obj; +#if 0 + assert( obj->ops == &dir_ops ); +#endif + return (struct fd *)grab_object( dir->fd ); +} + +static struct change_record *get_first_change_record( struct dir *dir ) +{ + struct list_head *ptr = ((&dir->change_records)->next == &dir->change_records) ? NULL: (&dir->change_records)->next; + if (!ptr) + return NULL; + list_del( ptr ); + return list_entry( ptr, struct change_record, entry ); +} + +static void dir_destroy( struct object *obj ) +{ + struct change_record *record; + struct dir *dir = (struct dir *)obj; +#if 0 + assert (obj->ops == &dir_ops); +#endif + + if (dir->filter) + remove_change( dir ); + + if (dir->inode) { + list_del( &dir->in_entry ); + free_inode( dir->inode ); + } + + while ((record = get_first_change_record( dir ))) + free( record ); + + release_object( dir->fd ); + + if (inotify_fd && list_empty( &change_list )) { + release_object( inotify_fd ); + inotify_fd = NULL; + } +} + +static struct dir * +get_dir_obj( struct w32process *process, obj_handle_t handle, unsigned int access ) +{ + return (struct dir *)get_wine_handle_obj( process, handle, access, &dir_ops ); +} + +static int dir_get_poll_events( struct fd *fd ) +{ + return 0; +} + +static enum server_fd_type dir_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_DIR; +} + +#ifdef USE_INOTIFY + +#define HASH_SIZE 31 + +struct uk_inode { + struct list_head ch_entry; /* entry in the children list */ + struct list_head children; /* children of this inode */ + struct uk_inode *parent; /* parent of this inode */ + struct list_head dirs; /* directory handles watching this inode */ + struct list_head ino_entry; /* entry in the inode hash */ + struct list_head wd_entry; /* entry in the watch descriptor hash */ + dev_t dev; /* device number */ + ino_t ino; /* device's inode number */ + int wd; /* inotify's watch descriptor */ + char *name; /* basename name of the inode */ +}; + +struct list_head inode_hash[ HASH_SIZE ]; +struct list_head wd_hash[ HASH_SIZE ]; + +static int inotify_add_dir( char *path, unsigned int filter ); + +static struct uk_inode *inode_from_wd( int wd ) +{ + struct list_head *bucket = &wd_hash[ wd % HASH_SIZE ]; + struct uk_inode *inode; + + list_for_each_entry( inode, bucket, wd_entry ) + if (inode->wd == wd) + return inode; + + return NULL; +} + +static inline struct list_head *get_hash_list( dev_t dev, ino_t ino ) +{ + return &inode_hash[ (ino ^ dev) % HASH_SIZE ]; +} + +static struct uk_inode *find_inode( dev_t dev, ino_t ino ) +{ + struct list_head *bucket = get_hash_list( dev, ino ); + struct uk_inode *inode; + + list_for_each_entry( inode, bucket, ino_entry ) + if (inode->ino == ino && inode->dev == dev) + return inode; + + return NULL; +} + +static struct uk_inode *create_inode( dev_t dev, ino_t ino ) +{ + struct uk_inode *inode; + + inode = malloc( sizeof *inode ); + if (inode) { + INIT_LIST_HEAD( &inode->children ); + INIT_LIST_HEAD( &inode->dirs ); + inode->ino = ino; + inode->dev = dev; + inode->wd = -1; + inode->parent = NULL; + inode->name = NULL; + list_add_tail( &inode->ino_entry, get_hash_list( dev, ino ) ); + } + return inode; +} + +static struct uk_inode *get_inode( dev_t dev, ino_t ino ) +{ + struct uk_inode *inode; + + inode = find_inode( dev, ino ); + if (inode) + return inode; + return create_inode( dev, ino ); +} + +static void inode_set_wd( struct uk_inode *inode, int wd ) +{ + if (inode->wd != -1) + list_remove( &inode->wd_entry ); + inode->wd = wd; + list_add_tail( &inode->wd_entry, &wd_hash[ wd % HASH_SIZE ] ); +} + +static void inode_set_name( struct uk_inode *inode, const char *name ) +{ + free (inode->name); + inode->name = name ? strdup( name ) : NULL; +} + +static void free_inode( struct uk_inode *inode ) +{ + int subtree = 0, watches = 0; + struct uk_inode *tmp, *next; + struct dir *dir; + + list_for_each_entry( dir, &inode->dirs, in_entry ) { + subtree |= dir->subtree; + watches++; + } + + if (!subtree && !inode->parent) { + list_for_each_entry_safe( tmp, next, &inode->children, ch_entry ) { +#if 0 + assert( tmp != inode ); + assert( tmp->parent == inode ); +#endif + free_inode( tmp ); + } + } + + if (watches) + return; + + if (inode->parent) + list_del( &inode->ch_entry ); + + /* disconnect remaining children from the parent */ + list_for_each_entry_safe( tmp, next, &inode->children, ch_entry ) { + list_del( &tmp->ch_entry ); + tmp->parent = NULL; + } + + if (inode->wd != -1) { + inotify_remove_watch( get_unix_fd( inotify_fd ), inode->wd ); + list_del( &inode->wd_entry ); + } + list_del( &inode->ino_entry ); + + free( inode->name ); + free( inode ); +} + +static struct uk_inode *inode_add( struct uk_inode *parent, + dev_t dev, ino_t ino, const char *name ) +{ + struct uk_inode *inode; + + inode = get_inode( dev, ino ); + if (!inode) + return NULL; + + if (!inode->parent) { + list_add_tail( &inode->ch_entry, &parent->children ); + inode->parent = parent; +#if 0 + assert( inode != parent ); +#endif + } + inode_set_name( inode, name ); + + return inode; +} + +static struct uk_inode *inode_from_name( struct uk_inode *inode, const char *name ) +{ + struct uk_inode *i; + + list_for_each_entry( i, &inode->children, ch_entry ) + if (i->name && !strcmp( i->name, name )) + return i; + return NULL; +} + +static int inotify_get_poll_events( struct fd *fd ); +static void inotify_poll_event( struct fd *fd, int event ); + +static const struct fd_ops inotify_fd_ops = +{ + inotify_get_poll_events, /* get_poll_events */ + inotify_poll_event, /* poll_event */ + NULL, /* flush */ + NULL, /* get_fd_type */ + NULL, /* ioctl */ + NULL, /* queue_async */ + NULL, /* reselect_async */ + NULL, /* cancel_async */ +}; + +static int inotify_get_poll_events( struct fd *fd ) +{ + return POLLIN; +} + +static void inotify_do_change_notify( struct dir *dir, unsigned int action, + const char *relpath ) +{ + struct change_record *record; + +#if 0 + assert( dir->obj.ops == &dir_ops ); +#endif + + if (dir->want_data) { + size_t len = strlen(relpath); + record = malloc( offsetof(struct change_record, name[len]) ); + if (!record) + return; + + record->action = action; + memcpy( record->name, relpath, len ); + record->len = len; + + list_add_tail( &record->entry, &dir->change_records ); + } + + fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_ALERTED ); +} + +static unsigned int filter_from_event( struct inotify_event *ie ) +{ + unsigned int filter = 0; + + if (ie->mask & (IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_CREATE)) + filter |= FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME; + if (ie->mask & IN_MODIFY) + filter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; + if (ie->mask & IN_ATTRIB) + filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY; + if (ie->mask & IN_ACCESS) + filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; + if (ie->mask & IN_CREATE) + filter |= FILE_NOTIFY_CHANGE_CREATION; + + return filter; +} + +/* scan up the parent directories for watches */ +static unsigned int filter_from_inode( struct uk_inode *inode, int is_parent ) +{ + unsigned int filter = 0; + struct dir *dir; + + /* combine filters from parents watching subtrees */ + while (inode) { + list_for_each_entry( dir, &inode->dirs, in_entry ) + if (dir->subtree || !is_parent) + filter |= dir->filter; + is_parent = 1; + inode = inode->parent; + } + + return filter; +} + +static char *inode_get_path( struct uk_inode *inode, int sz ) +{ + struct list_head *head; + char *path; + int len; + + if (!inode) + return NULL; + + head = ((&inode->dirs)->next == &inode->dirs) ? NULL: (&inode->dirs)->next; + if (head) { + int unix_fd = get_unix_fd( LIST_ENTRY( head, struct dir, in_entry )->fd ); + path = malloc ( 32 + sz ); + if (path) + sprintf( path, "/proc/self/fd/%u/", unix_fd ); + return path; + } + + if (!inode->name) + return NULL; + + len = strlen( inode->name ); + path = inode_get_path( inode->parent, sz + len + 1 ); + if (!path) + return NULL; + + strcat( path, inode->name ); + strcat( path, "/" ); + + return path; +} + +static int inode_check_dir( struct uk_inode *parent, const char *name ) +{ + char *path; + unsigned int filter; + struct uk_inode *inode; + struct stat st; + int wd = -1, r = -1; + + path = inode_get_path( parent, strlen(name) ); + if (!path) + return r; + + strcat( path, name ); + + r = uk_stat( path, &st ); + if (r < 0) + goto end; + + if (!S_ISDIR(st.st_mode)) { + r = 0; + goto end; + } + + r = 1; + + filter = filter_from_inode( parent, 1 ); + if (!filter) + goto end; + + inode = inode_add( parent, st.st_dev, st.st_ino, name ); + if (!inode || inode->wd != -1) + goto end; + + wd = inotify_add_dir( path, filter ); + if (wd != -1) + inode_set_wd( inode, wd ); + else + free_inode( inode ); + +end: + free( path ); + return r; +} + +static int prepend( char **path, const char *segment ) +{ + int extra; + char *p; + + extra = strlen( segment ) + 1; + if (*path) { + int len = strlen( *path ) + 1; + p = realloc( *path, len + extra , len); + if (!p) + return 0; + memmove( &p[ extra ], p, len ); + p[ extra - 1 ] = '/'; + memcpy( p, segment, extra - 1 ); + } + else { + p = malloc( extra ); + if (!p) + return 0; + memcpy( p, segment, extra ); + } + + *path = p; + + return 1; +} + +#define FILE_ACTION_ADDED 0x00000001 +#define FILE_ACTION_REMOVED 0x00000002 +#define FILE_ACTION_MODIFIED 0x00000003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 +#define FILE_ACTION_ADDED_STREAM 0x00000006 +#define FILE_ACTION_REMOVED_STREAM 0x00000007 +#define FILE_ACTION_MODIFIED_STREAM 0x00000008 + +static void inotify_notify_all( struct inotify_event *ie ) +{ + unsigned int filter, action; + struct uk_inode *inode, *i; + char *path = NULL; + struct dir *dir; + + inode = inode_from_wd( ie->wd ); + if (!inode) { + ktrace( "no inode matches %d\n", ie->wd); + return; + } + + filter = filter_from_event( ie ); + + if (ie->mask & IN_CREATE) { + switch (inode_check_dir( inode, ie->name )) { + case 1: + filter &= ~FILE_NOTIFY_CHANGE_FILE_NAME; + break; + case 0: + filter &= ~FILE_NOTIFY_CHANGE_DIR_NAME; + break; + default: + break; + /* Maybe the file disappeared before we could check it? */ + } + action = FILE_ACTION_ADDED; + } + else if (ie->mask & IN_DELETE) + action = FILE_ACTION_REMOVED; + else + action = FILE_ACTION_MODIFIED; + + /* + * Work our way up the inode hierarchy + * extending the relative path as we go + * and notifying all recursive watches. + */ + if (!prepend( &path, ie->name )) + return; + + for (i = inode; i; i = i->parent) { + list_for_each_entry( dir, &i->dirs, in_entry ) + if ((filter & dir->filter) && (i==inode || dir->subtree)) + inotify_do_change_notify( dir, action, path ); + + if (!i->name || !prepend( &path, i->name )) + break; + } + + free( path ); + + if (ie->mask & IN_DELETE) { + i = inode_from_name( inode, ie->name ); + if (i) + free_inode( i ); + } +} + +static void inotify_poll_event( struct fd *fd, int event ) +{ + int r, ofs, unix_fd; + char buffer[0x1000]; + struct inotify_event *ie; + + unix_fd = get_unix_fd( fd ); + r = uk_read( unix_fd, buffer, sizeof buffer ); + if (r < 0) { + ktrace("inotify_poll_event(): inotify read failed!\n"); + return; + } + + for( ofs = 0; ofs < r - offsetof(struct inotify_event, name); ) { + ie = (struct inotify_event*) &buffer[ofs]; + if (!ie->len) + break; + ofs += offsetof( struct inotify_event, name[ie->len] ); + if (ofs > r) + break; + inotify_notify_all( ie ); + } +} + +static inline struct fd *create_inotify_fd( void ) +{ + int unix_fd; + + unix_fd = inotify_init(); + if (unix_fd<0) + return NULL; + return create_anonymous_fd( &inotify_fd_ops, unix_fd, NULL, 0 ); +} + +static int map_flags( unsigned int filter ) +{ + unsigned int mask; + + /* always watch these so we can track subdirectories in recursive watches */ + mask = (IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF); + + if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) + mask |= IN_ATTRIB; + if (filter & FILE_NOTIFY_CHANGE_SIZE) + mask |= IN_MODIFY; + if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE) + mask |= IN_MODIFY; + if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS) + mask |= IN_ACCESS; + if (filter & FILE_NOTIFY_CHANGE_SECURITY) + mask |= IN_ATTRIB; + + return mask; +} + +static int inotify_add_dir( char *path, unsigned int filter ) +{ + int wd = inotify_add_watch( get_unix_fd( inotify_fd ), + path, map_flags( filter ) ); + if (wd != -1) + set_fd_events( inotify_fd, POLLIN ); + return wd; +} + +static int init_inotify( void ) +{ + int i; + + if (inotify_fd) + return 1; + + inotify_fd = create_inotify_fd(); + if (!inotify_fd) + return 0; + + for (i=0; ifd ); + + inode = dir->inode; + if (!inode) { + /* check if this fd is already being watched */ + if (-1 == uk_fstat( unix_fd, &st )) + return 0; + + inode = get_inode( st.st_dev, st.st_ino ); + if (!inode) + inode = create_inode( st.st_dev, st.st_ino ); + if (!inode) + return 0; + list_add_tail( &dir->entry, &inode->dirs ); + dir->inode = inode; + } + + filter = filter_from_inode( inode, 0 ); + + sprintf( path, "/proc/self/fd/%u", unix_fd ); + wd = inotify_add_dir( path, filter ); + if (wd == -1) + return 0; + + inode_set_wd( inode, wd ); + + return 1; +} + +static char *get_basename( const char *link ) +{ + char *buffer, *name = NULL; + int r, n = 0x100; + + while (1) { + buffer = malloc( n ); + if (!buffer) + return NULL; + + r = uk_readlink( link, buffer, n ); + if (r < 0) + break; + + if (r < n) { + name = buffer; + break; + } + free( buffer ); + n *= 2; + } + + if (name) { + while (r > 0 && name[ r - 1 ] == '/' ) + r--; + name[ r ] = 0; + + name = strrchr( name, '/' ); + if (name) + name = strdup( &name[1] ); + } + + free( buffer ); + return name; +} + +static int dir_add_to_existing_notify( struct dir *dir ) +{ + struct uk_inode *inode, *parent; + unsigned int filter = 0; + struct stat st, st_new; + char link[35], *name; + int wd, unix_fd; + + if (!inotify_fd) + return 0; + + unix_fd = get_unix_fd( dir->fd ); + + /* check if it's in the list of inodes we want to watch */ + if (-1 == uk_fstat( unix_fd, &st_new )) + return 0; + inode = find_inode( st_new.st_dev, st_new.st_ino ); + if (inode) + return 0; + + /* lookup the parent */ + sprintf( link, "/proc/self/fd/%u/..", unix_fd ); + if (-1 == uk_stat( link, &st )) + return 0; + + /* + * If there's no parent, stop. We could keep going adding + * ../ to the path until we hit the root of the tree or + * find a recursively watched ancestor. + * Assume it's too expensive to search up the tree for now. + */ + parent = find_inode( st.st_dev, st.st_ino ); + if (!parent) + return 0; + + if (parent->wd == -1) + return 0; + + filter = filter_from_inode( parent, 1 ); + if (!filter) + return 0; + + sprintf( link, "/proc/self/fd/%u", unix_fd ); + name = get_basename( link ); + if (!name) + return 0; + inode = inode_add( parent, st_new.st_dev, st_new.st_ino, name ); + free( name ); + if (!inode) + return 0; + + /* Couldn't find this inode at the start of the function, must be new */ +#if 0 + assert( inode->wd == -1 ); +#endif + + wd = inotify_add_dir( link, filter ); + if (wd != -1) + inode_set_wd( inode, wd ); + + return 1; +} + +#else + +static int init_inotify( void ) +{ + return 0; +} + +static int inotify_adjust_changes( struct dir *dir ) +{ + return 0; +} + +static void free_inode( struct uk_inode *inode ) +{ + assert( 0 ); +} + +static int dir_add_to_existing_notify( struct dir *dir ) +{ + return 0; +} + +#endif /* USE_INOTIFY */ + +struct object *create_dir_obj( struct fd *fd ) +{ + struct dir *dir; + + dir = alloc_wine_object( &dir_ops ); + if (!dir) + return NULL; + + INIT_DISP_HEADER(&dir->obj.header, 0, sizeof(struct dir), 0); + INIT_LIST_HEAD( &dir->change_records ); + dir->filter = 0; + dir->notified = 0; + dir->want_data = 0; + dir->inode = NULL; + grab_object( fd ); + dir->fd = fd; + set_fd_user( fd, &dir_fd_ops, &dir->obj ); + + dir_add_to_existing_notify( dir ); + + return &dir->obj; +} + +/* enable change notifications for a directory */ +DECL_HANDLER(read_directory_changes) +{ + struct dir *dir; + struct async *async; + + if (!req->filter) { + set_error(STATUS_INVALID_PARAMETER); + return; + } + + dir = get_dir_obj( get_current_w32process(), req->handle, 0 ); + if (!dir) + return; + + /* requests don't timeout */ + if (!(async = fd_queue_async( dir->fd, &req->async, ASYNC_TYPE_WAIT, 0 ))) goto end; + + /* assign it once */ + if (!dir->filter) { + init_inotify(); + insert_change( dir ); + dir->filter = req->filter; + dir->subtree = req->subtree; + dir->want_data = req->want_data; + } + + /* if there's already a change in the queue, send it */ + if (!list_empty( &dir->change_records )) + fd_async_wake_up( dir->fd, ASYNC_TYPE_WAIT, STATUS_ALERTED ); + + /* setup the real notification */ + if (!inotify_adjust_changes( dir )) + dnotify_adjust_changes( dir ); + + release_object( async ); + set_error(STATUS_PENDING); + +end: + release_object( dir ); +} + +DECL_HANDLER(read_change) +{ + struct change_record *record; + struct dir *dir; + + dir = get_dir_obj( get_current_w32process(), req->handle, 0 ); + if (!dir) + return; + + if ((record = get_first_change_record( dir )) != NULL) { + reply->action = record->action; + set_reply_data( record->name, record->len ); + free( record ); + } + else + set_error( STATUS_NO_DATA_DETECTED ); + + release_object( dir ); +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/completion.c b/unifiedkernel/fs/completion.c new file mode 100644 index 0000000..d282c24 --- /dev/null +++ b/unifiedkernel/fs/completion.c @@ -0,0 +1,244 @@ +/* + * completion.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * completion.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct uk_completion +{ + struct object obj; + struct list_head queue; + unsigned int depth; +}; + +static void completion_dump(struct object*, int); +static struct object_type *completion_get_type(struct object *obj); +static void completion_destroy(struct object *); + +static const struct object_ops completion_ops = +{ + sizeof(struct uk_completion), /* size */ + completion_dump, /* dump */ + completion_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + completion_destroy /* destroy */ +}; + +struct comp_msg +{ + struct list_head queue_entry; + unsigned long ckey; + unsigned long cvalue; + unsigned long information; + unsigned int status; +}; + +static void completion_destroy(struct object *obj) +{ + struct uk_completion *completion = (struct uk_completion *) obj; + struct comp_msg *tmp, *next; + + LIST_FOR_EACH_ENTRY_SAFE(tmp, next, &completion->queue, struct comp_msg, queue_entry) { + free(tmp); + } +} + +static void completion_dump(struct object *obj, int verbose) +{ +#if 0 + struct uk_completion *completion = (struct uk_completion *) obj; + + assert(obj->ops == &completion_ops); + fprintf(stderr, "Completion "); + dump_object_name(&completion->obj); + fprintf(stderr, " (%u packets pending)\n", completion->depth); +#endif +} + +extern struct object_type *get_object_type(const struct unicode_str *name); + +static struct object_type *completion_get_type(struct object *obj) +{ + static const WCHAR name[] = {'C','o','m','p','l','e','t','i','o','n'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type(&str); +} + +static struct uk_completion *create_completion(struct directory *root, const struct unicode_str *name, unsigned int attr, unsigned int concurrent) +{ + struct uk_completion *completion; + + if ((completion = create_named_object_dir(root, name, attr, &completion_ops))) { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) { + INIT_LIST_HEAD(&completion->queue); + completion->depth = 0; + } + } + + return completion; +} + +struct uk_completion *get_completion_obj(struct w32process *process, obj_handle_t handle, unsigned int access) +{ + return (struct uk_completion *)get_wine_handle_obj(process, handle, access, &completion_ops); +} + +extern void uk_wake_up(struct object *obj, int max); + +void add_completion(struct uk_completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information) +{ + struct comp_msg *msg = mem_alloc(sizeof(*msg)); + + if (!msg) + return; + + msg->ckey = ckey; + msg->cvalue = cvalue; + msg->status = status; + msg->information = information; + list_add_tail(&completion->queue, &msg->queue_entry); + completion->depth++; + uk_wake_up(&completion->obj, 1); +} + +/* create a completion */ +DECL_HANDLER(create_completion) +{ + struct uk_completion *completion; + struct unicode_str name; + struct directory *root = NULL; + + reply->handle = 0; + + get_req_unicode_str(&name); + + if ((completion = create_completion(req->rootdir, &name, req->attributes, req->concurrent)) != NULL) { + reply->handle = alloc_handle(get_current_w32process(), completion, req->access, req->attributes); + release_object(completion); + } + + if (root) release_object(root); +} + +/* open a completion */ +DECL_HANDLER(open_completion) +{ + struct uk_completion *completion; + struct unicode_str name; + struct directory *root = NULL; + + reply->handle = 0; + + get_req_unicode_str(&name); + + if ((completion = open_object_dir(req->rootdir, &name, req->attributes, &completion_ops)) != NULL) { + reply->handle = alloc_handle(get_current_w32process(), completion, req->access, req->attributes); + release_object(completion); + } + + if (root) + release_object(root); +} + +#define IO_COMPLETION_QUERY_STATE 0x0001 +#define IO_COMPLETION_MODIFY_STATE 0x0002 +#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +/* add completion to completion port */ +DECL_HANDLER(add_completion) +{ + struct uk_completion* completion = get_completion_obj(get_current_w32process(), req->handle, IO_COMPLETION_MODIFY_STATE); + + if (!completion) + return; + + add_completion(completion, req->ckey, req->cvalue, req->status, req->information); + + release_object(completion); +} + +/* get completion from completion port */ +DECL_HANDLER(remove_completion) +{ + struct uk_completion* completion = get_completion_obj(get_current_w32process(), req->handle, IO_COMPLETION_MODIFY_STATE); + struct list_head *entry; + struct comp_msg *msg; + + if (!completion) + return; + + entry = list_head(&completion->queue); + if (!entry) + set_error(STATUS_PENDING); + else { + list_del(entry); + completion->depth--; + msg = LIST_ENTRY(entry, struct comp_msg, queue_entry); + reply->ckey = msg->ckey; + reply->cvalue = msg->cvalue; + reply->status = msg->status; + reply->information = msg->information; + free(msg); + } + + release_object(completion); +} + +/* get queue depth for completion port */ +DECL_HANDLER(query_completion) +{ + struct uk_completion* completion = get_completion_obj(get_current_w32process(), req->handle, IO_COMPLETION_QUERY_STATE); + + if (!completion) + return; + + reply->depth = completion->depth; + + release_object(completion); +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/directory.c b/unifiedkernel/fs/directory.c new file mode 100644 index 0000000..94f38de --- /dev/null +++ b/unifiedkernel/fs/directory.c @@ -0,0 +1,383 @@ +/* + * directory.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * directory.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +#define HASH_SIZE 7 /* default hash size */ + +struct object_type +{ + struct object obj; /* object header */ +}; + +static void object_type_dump( struct object *obj, int verbose ); +static struct object_type *object_type_get_type( struct object *obj ); + +static const struct object_ops object_type_ops = +{ + sizeof(struct object_type), /* size */ + object_type_dump, /* dump */ + object_type_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + + +struct directory +{ + struct object obj; /* object header */ + struct namespace *entries; /* directory's name space */ +}; + +extern HANDLE base_dir_handle; +static void directory_dump( struct object *obj, int verbose ); +static struct object_type *directory_get_type( struct object *obj ); +static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ); +static void directory_destroy( struct object *obj ); +extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); + +static const struct object_ops directory_ops = +{ + sizeof(struct directory), /* size */ + directory_dump, /* dump */ + directory_get_type, /* get_type */ + no_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ + directory_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + directory_destroy /* destroy */ +}; + +static struct directory *dir_objtype; + +static WCHAR link_local[] = {'\\', 'B', 'a', 's', 'e', 'N', 'a', 'm', 'e', 'd', 'O', 'b', 'j', 'e', 'c', 't', 's', '\\', 'L', 'o', 'c', 'a', 'l', 0}; +static WCHAR link_global1[] = {'\\', '?', '?', '\\', 'G', 'l', 'o', 'b', 'a', 'l', 0}; +static WCHAR link_global2[] = {'\\', 'B', 'a', 's', 'e', 'N', 'a', 'm', 'e', 'd', 'O', 'b', 'j', 'e', 'c', 't', 's', '\\', 'G', 'l', 'o', 'b', 'a', 'l', 0}; +static WCHAR base_dir[] = {'\\', 'B', 'a', 's', 'e', 'N', 'a', 'm', 'e', 'd', 'O', 'b', 'j', 'e', 'c', 't', 's', 0}; +static WCHAR dos_root[] = {'\\', '?', '?', 0}; + +void init_directories(void) +{ + UNICODE_STRING Name, LinkName; + + init_unistr(&Name, (PWSTR)base_dir); + init_unistr(&LinkName, (PWSTR)link_local); + io_create_symbol_link(&LinkName, &Name); + + init_unistr(&Name, (PWSTR)dos_root); + init_unistr(&LinkName, (PWSTR)link_global1); + io_create_symbol_link(&LinkName, &Name); + + init_unistr(&Name, (PWSTR)base_dir); + init_unistr(&LinkName, (PWSTR)link_global2); + io_create_symbol_link(&LinkName, &Name); +} + +static void object_type_dump( struct object *obj, int verbose ) +{ +#if 0 + assert( obj->ops == &object_type_ops ); + fputs( "Object type ", stderr ); + dump_object_name( obj ); + fputc( '\n', stderr ); +#endif +} + +struct object_type *get_object_type( const struct unicode_str *name ); + +static struct object_type *object_type_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'O','b','j','e','c','t','T','y','p','e'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +static void directory_dump( struct object *obj, int verbose ) +{ +#if 0 + assert( obj->ops == &directory_ops ); + fputs( "Directory ", stderr ); + dump_object_name( obj ); + fputc( '\n', stderr ); +#endif +} + +static struct object_type *directory_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'D','i','r','e','c','t','o','r','y'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +extern void clear_error(void); + +static struct object *directory_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ) +{ + POBJECT_DIRECTORY dir = (POBJECT_DIRECTORY)obj; + struct object *found; + UNICODE_STRING tmp; + const WCHAR *p; + +#if 0 + assert( obj->ops == &directory_ops ); +#endif + + if (!(p = memchrW( name->str, '\\', name->len / sizeof(WCHAR) ))) + /* Last element in the path name */ + tmp.Length = name->len; + else + tmp.Length = (p - name->str) * sizeof(WCHAR); + tmp.MaximumLength = tmp.Length + sizeof(WCHAR); + + tmp.Buffer = (PWSTR)name->str; + if ((found = lookup_obdir_entry(dir, &tmp, attr))) { + /* Skip trailing \\ */ + if (p) { + p++; + tmp.Length += sizeof(WCHAR); + } + /* Move to the next element*/ + name->str = p; + name->len -= tmp.Length; + return found; + } + + if (name->str) { + if (tmp.Length == 0) /* Double backslash */ + set_error( STATUS_OBJECT_NAME_INVALID ); + else if (p) /* Path still has backslashes */ + set_error( STATUS_OBJECT_PATH_NOT_FOUND ); + else + clear_error(); + } + return NULL; +} + +static void directory_destroy( struct object *obj ) +{ + POBJECT_DIRECTORY dir = (POBJECT_DIRECTORY)obj; +#if 0 + assert( obj->ops == &directory_ops ); + free( dir->entries ); +#endif + delete_obdir_entry(dir); +} + +static POBJECT_DIRECTORY create_directory( HANDLE root, const struct unicode_str *name, + unsigned int attr, unsigned int hash_size ) +{ + POBJECT_DIRECTORY dir; + + if ((dir = create_named_object_dir( root, name, attr, &directory_ops )) && + get_error() != STATUS_OBJECT_NAME_EXISTS) { +#if 0 + if (!(dir->entries = create_namespace( hash_size ))) { + release_object( dir ); + dir = NULL; + } +#endif + } + return dir; +} + + +/****************************************************************************** + * Find an object by its name in a given root object + * + * PARAMS + * root [I] directory to start search from or NULL to start from \\ + * name [I] object name to search for + * attr [I] OBJECT_ATTRIBUTES.Attributes + * name_left [O] [optional] leftover name if object is not found + * + * RETURNS + * NULL: If params are invalid + * Found: If object with exact name is found returns that object + * (name_left->len == 0). Object's refcount is incremented + * Not found: The last matched parent. (name_left->len > 0) + * Parent's refcount is incremented. + */ +struct object *find_object_dir( HANDLE root, const struct unicode_str *name, + unsigned int attr, struct unicode_str *name_left ) +{ + UNICODE_STRING obj_name; + PACCESS_STATE access = NULL; + BOOLEAN locked; + PVOID object = NULL; + NTSTATUS status; + + obj_name.Length = (USHORT)name->len; + obj_name.MaximumLength = obj_name.Length + sizeof(WCHAR); + obj_name.Buffer = (PWSTR)name->str; + + if (!IS_UK_HANDLE(root)) + root = base_dir_handle; + status = lookup_object_name(root, + &obj_name, + attr, + NULL, + KernelMode, + NULL, + NULL, + NULL, + &access, + &locked, + &object); + + if (!NT_SUCCESS(status)) { + return NULL; + } + + name_left = NULL; + + return (struct object *)object; +} + +/* create a named (if name is present) or unnamed object. */ +void *create_named_object_dir( HANDLE root, const struct unicode_str *name, + unsigned int attributes, const struct object_ops *ops ) +{ + return create_wine_object(root, ops, name, NULL); +} + +/* open a new handle to an existing object */ +void *open_object_dir( HANDLE root, const struct unicode_str *name, + unsigned int attr, const struct object_ops *ops ) +{ + UNICODE_STRING obj_name; + PACCESS_STATE access = NULL; + BOOLEAN locked; + PVOID object = NULL; + NTSTATUS status; + + obj_name.Length = (USHORT)name->len; + obj_name.MaximumLength = obj_name.Length + sizeof(WCHAR); + obj_name.Buffer = (PWSTR)kmalloc(obj_name.MaximumLength, GFP_KERNEL); + memcpy(obj_name.Buffer, name->str, obj_name.Length); + obj_name.Buffer[obj_name.Length / sizeof(WCHAR)] = 0; + + status = lookup_object_name(root, + &obj_name, + attr, + NULL, + (KPROCESSOR_MODE)KernelMode, + NULL, + NULL, + NULL, + access, + &locked, + &object); + kfree(obj_name.Buffer); + + if (!NT_SUCCESS(status)) + set_error(status); + if (!object) + set_error(STATUS_OBJECT_NAME_NOT_FOUND); + + return object; +} + +/* retrieve an object type, creating it if needed */ +struct object_type *get_object_type( const struct unicode_str *name ) +{ + struct object_type *type; + + if ((type = open_object_dir( dir_objtype, name, 0, &object_type_ops ))) + return type; + + if ((type = create_named_object_dir( dir_objtype, name, 0, &object_type_ops ))) + { + grab_object( type ); + make_object_static( &type->obj ); + clear_error(); + } + return type; +} + +/* create a directory object */ +DECL_HANDLER(create_directory) +{ + struct unicode_str name; + POBJECT_DIRECTORY dir; + + reply->handle = 0; + get_req_unicode_str( &name ); + + if ((dir = create_directory( req->rootdir, &name, req->attributes, HASH_SIZE ))) { + reply->handle = alloc_handle( get_current_w32process(), dir, req->access, req->attributes ); + release_object( dir ); + } +} + +/* open a directory object */ +DECL_HANDLER(open_directory) +{ + struct unicode_str name; + POBJECT_DIRECTORY dir; + + get_req_unicode_str( &name ); + + if ((dir = open_object_dir( req->rootdir, &name, req->attributes, &directory_ops ))) + { + reply->handle = alloc_handle( get_current_w32process(), dir, req->access, req->attributes ); + release_object( dir ); + } +} + +/* FIXME we don't need it */ +/* get a directory entry by index */ +DECL_HANDLER(get_directory_entry) +{ +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/fd.c b/unifiedkernel/fs/fd.c new file mode 100644 index 0000000..14086a5 --- /dev/null +++ b/unifiedkernel/fs/fd.c @@ -0,0 +1,1528 @@ +/* + * fd.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * fd.c: + * Refered to Wine code + */ +#include +#include +#include +#include +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "wineserver/info.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" +#include "file.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* Because of the stupid Posix locking semantics, we need to keep + * track of all file descriptors referencing a given file, and not + * close a single one until all the locks are gone (sigh). + */ + +/* file descriptor object */ + +/* closed_fd is used to keep track of the unix fd belonging to a closed fd object */ +struct closed_fd +{ + struct list_head entry; /* entry in inode closed list */ + struct file *unix_file; /* the unix file */ + char unlink[1]; /* name to unlink on close (if any) */ +}; + +struct fd +{ + struct object obj; /* object header */ + const struct fd_ops *fd_ops; /* file descriptor operations */ + struct uk_inode *inode; /* inode that this fd belongs to */ + struct list_head inode_entry; /* entry in inode fd list */ + struct closed_fd *closed; /* structure to store the unix fd at destroy time */ + struct object *user; /* object using this file descriptor */ + struct list_head locks; /* list of locks on this fd */ + unsigned int access; /* file access (FILE_READ_DATA etc.) */ + unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */ + unsigned int sharing; /* file sharing mode */ + struct file *unix_file; /* unix file struct */ + unsigned int no_fd_status;/* status to return when unix_file is NULL */ + int signaled :1; /* is the fd signaled? */ + int fs_locks :1; /* can we use filesystem locks for this fd? */ + int poll_index; /* index of fd in poll array */ + struct async_queue *read_q; /* async readers of this fd */ + struct async_queue *write_q; /* async writers of this fd */ + struct async_queue *wait_q; /* other async waiters of this fd */ + struct uk_completion *completion; /* completion object attached to this fd */ + unsigned long comp_key; /* completion key to set in completion events */ +}; + +static void fd_dump(struct object *obj, int verbose); +static void fd_destroy(struct object *obj); + +static const struct object_ops fd_ops = +{ + sizeof(struct fd), /* size */ + fd_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + fd_destroy /* destroy */ +}; + +/* device object */ + +#define DEVICE_HASH_SIZE 7 +#define INODE_HASH_SIZE 17 + +struct device +{ + struct object obj; /* object header */ + struct list_head entry; /* entry in device hash list */ + dev_t dev; /* device number */ + int removable; /* removable device? (or -1 if unknown) */ + struct list_head inode_hash[INODE_HASH_SIZE]; /* inodes hash table */ +}; + +static void device_dump(struct object *obj, int verbose); +static void device_destroy(struct object *obj); + +static const struct object_ops device_ops = +{ + sizeof(struct device), /* size */ + device_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + device_destroy /* destroy */ +}; + +/* inode object */ + +struct uk_inode +{ + struct object obj; /* object header */ + struct list_head entry; /* inode hash list entry */ + struct device *device; /* device containing this inode */ + ino_t ino; /* inode number */ + struct list_head open; /* list of open file descriptors */ + struct list_head locks; /* list of file locks */ + struct list_head closed; /* list of file descriptors to close at destroy time */ +}; + +static void inode_dump(struct object *obj, int verbose); +static void inode_destroy(struct object *obj); + +static const struct object_ops inode_ops = +{ + sizeof(struct uk_inode), /* size */ + inode_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + inode_destroy /* destroy */ +}; + +/* file lock object */ + +struct uk_file_lock +{ + struct object obj; /* object header */ + struct fd *fd; /* fd owning this lock */ + struct list_head fd_entry; /* entry in list of locks on a given fd */ + struct list_head inode_entry; /* entry in inode list of locks */ + int shared; /* shared lock? */ + file_pos_t start; /* locked region is interval [start;end) */ + file_pos_t end; + struct w32process *process; /* process owning this lock */ + struct list_head proc_entry; /* entry in list of locks owned by the process */ +}; + +static void file_lock_dump(struct object *obj, int verbose); + +static const struct object_ops file_lock_ops = +{ + sizeof(struct uk_file_lock), /* size */ + file_lock_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + + +#define OFF_T_MAX (~((file_pos_t)1 << (8*sizeof(off_t)-1))) +#define FILE_POS_T_MAX (~(file_pos_t)0) + +static file_pos_t max_unix_offset = OFF_T_MAX; + + +/****************************************************************/ +/* timeouts support */ + +struct timeout_user +{ + struct list_head entry; /* entry in sorted timeout list */ + timeout_t when; /* timeout expiry (absolute time) */ + timeout_callback callback; /* callback function */ + void *private; /* callback private data */ +}; + +static struct list_head timeout_list = LIST_INIT(timeout_list); /* sorted timeouts list */ + +/* add a timeout user */ +struct timeout_user *add_timeout_user(timeout_t when, timeout_callback func, void *private) +{ + struct timeout_user *user; + struct list_head *ptr; + + if (!(user = mem_alloc(sizeof(*user)))) + return NULL; + user->when = (when > 0) ? when : current_time - when; + user->callback = func; + user->private = private; + + /* Now insert it in the linked list */ + + LIST_FOR_EACH(ptr, &timeout_list) { + struct timeout_user *timeout = LIST_ENTRY(ptr, struct timeout_user, entry); + if (timeout->when >= user->when) + break; + } + list_add_before(ptr, &user->entry); + return user; +} + +/* remove a timeout user */ +void remove_timeout_user(struct timeout_user *user) +{ + list_del(&user->entry); + free(user); +} + +/* return a text description of a timeout for debugging purposes */ +const char *get_timeout_str(timeout_t timeout) +{ + return NULL; +} + +/****************************************************************/ +/* device functions */ + +static struct list_head device_hash[DEVICE_HASH_SIZE]; + +static inline int is_device_removable(dev_t dev, struct file *unix_file) +{ + struct kstatfs stfs; + + /* check for floppy disk */ + if (MAJOR(dev) == FLOPPY_MAJOR) + return 1; + + if (vfs_statfs(unix_file->f_path.dentry, &stfs) < 0) + return 0; + + return (stfs.f_type == 0x9660 || /* iso9660 */ + stfs.f_type == 0x9fa1 || /* supermount */ + stfs.f_type == 0x15013346); /* udf */ +} + +/* retrieve the device object for a given fd, creating it if needed */ +static struct device *get_device(dev_t dev, struct file *unix_file) +{ + struct device *device; + unsigned int i, hash = dev % DEVICE_HASH_SIZE; + + if (device_hash[hash].next) { + LIST_FOR_EACH_ENTRY(device, &device_hash[hash], struct device, entry) + if (device->dev == dev) + return (struct device *)grab_object(device); + } + else INIT_LIST_HEAD(&device_hash[hash]); + + /* not found, create it */ + + if (!unix_file) + return NULL; + if ((device = alloc_wine_object(&device_ops))) { + device->dev = dev; + device->removable = is_device_removable(dev, unix_file); + for (i = 0; i < INODE_HASH_SIZE; i++) + INIT_LIST_HEAD(&device->inode_hash[i]); + list_add_head(&device_hash[hash], &device->entry); + } + return device; +} + +static void device_dump(struct object *obj, int verbose) +{ +#if 0 + struct device *device = (struct device *)obj; + printk("Device dev="); + printk("%llx\n", device->dev); + printk("\n"); +#endif +} + +static void device_destroy(struct object *obj) +{ + struct device *device = (struct device *)obj; +#if 0 + unsigned int i; + for (i = 0; i < INODE_HASH_SIZE; i++) + assert(list_empty(&device->inode_hash[i])); +#endif + list_del(&device->entry); /* remove it from the hash table */ +} + + +/****************************************************************/ +/* inode functions */ + +/* close all pending file descriptors in the closed list */ +static void inode_close_pending(struct uk_inode *inode, int keep_unlinks) +{ + struct list_head *ptr = list_head(&inode->closed); + + while (ptr) { + struct closed_fd *fd = LIST_ENTRY(ptr, struct closed_fd, entry); + struct list_head *next = list_next(&inode->closed, ptr); + + if (fd->unix_file) { + fput(fd->unix_file); /* D.M. TBD */ + fd->unix_file = NULL; + } + if (!keep_unlinks || !fd->unlink[0]) { /* get rid of it unless there's an unlink pending on that file */ + list_del(ptr); + free(fd); + } + ptr = next; + } +} + +static void inode_dump(struct object *obj, int verbose) +{ +#if 0 + struct uk_inode *inode = (struct uk_inode *)obj; + printk("Inode device=%p ino=", inode->device); + printk("%llx\n", inode->ino); + printk("\n"); +#endif +} + +static void inode_destroy(struct object *obj) +{ + struct uk_inode *inode = (struct uk_inode *)obj; + struct list_head *ptr; + +#if 0 + assert(list_empty(&inode->open)); + assert(list_empty(&inode->locks)); +#endif + + list_del(&inode->entry); + + while ((ptr = list_head(&inode->closed))) { + struct closed_fd *fd = LIST_ENTRY(ptr, struct closed_fd, entry); + list_del(ptr); + if (fd->unlink[0] && fd->unix_file) { + struct dentry *dentry = fd->unix_file->f_path.dentry; + struct dentry *parent = dentry->d_parent; + struct inode *inode = dentry->d_inode; + + mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT); + dget(dentry); + if (S_ISDIR(inode->i_mode)) + vfs_rmdir(parent->d_inode, dentry); + else + vfs_unlink(parent->d_inode, dentry); + mutex_unlock(&parent->d_inode->i_mutex); + dput(dentry); + } + if (fd->unix_file) { + fput(fd->unix_file); + fd->unix_file = NULL; + } + free(fd); + } + release_object(inode->device); +} + +/* retrieve the inode object for a given fd, creating it if needed */ +static struct uk_inode *get_inode(dev_t dev, ino_t ino, struct file *unix_file) +{ + struct device *device; + struct uk_inode *inode; + unsigned int hash = ino % INODE_HASH_SIZE; + + if (!(device = get_device(dev, unix_file))) + return NULL; + + LIST_FOR_EACH_ENTRY(inode, &device->inode_hash[hash], struct uk_inode, entry) { + if (inode->ino == ino) { + release_object(device); + return (struct uk_inode *)grab_object(inode); + } + } + + /* not found, create it */ + if ((inode = alloc_wine_object(&inode_ops))) { + inode->device = device; + inode->ino = ino; + INIT_LIST_HEAD(&inode->open); + INIT_LIST_HEAD(&inode->locks); + INIT_LIST_HEAD(&inode->closed); + list_add_head(&device->inode_hash[hash], &inode->entry); + } + else release_object(device); + + return inode; +} + +/* add fd to the inode list of file descriptors to close */ +static void inode_add_closed_fd(struct uk_inode *inode, struct closed_fd *fd) +{ + if (!list_empty(&inode->locks)) { + list_add_head(&inode->closed, &fd->entry); + } else if (fd->unlink[0]) { /* close the fd but keep the structure around for unlink */ + list_add_head(&inode->closed, &fd->entry); + } else { /* no locks on this inode and no unlink, get rid of the fd */ + if (fd->unix_file) + fput(fd->unix_file); + free(fd); + } +} + + +/****************************************************************/ +/* file lock functions */ + +static void file_lock_dump(struct object *obj, int verbose) +{ +#if 0 + struct uk_file_lock *lock = (struct uk_file_lock *)obj; + printk("Lock %s fd=%p proc=%p start=", + lock->shared ? "shared" : "excl", lock->fd, lock->process); + printk("%llx\n", lock->start); + printk(" end="); + printk("%llx\n", lock->end); + printk("\n"); +#endif +} + +extern NTSTATUS errno2ntstatus(int error); + +/* set (or remove) a Unix lock if possible for the given range */ +static int set_unix_lock(struct fd *fd, file_pos_t start, file_pos_t end, int type) +{ + NTSTATUS status; + int error; + struct file_lock file_lock; + struct file *filp = fd->unix_file; + + if (!fd->fs_locks) + return 1; /* no fs locks possible for this fd */ + for (;;) { + if (start == end) + return 1; /* can't set zero-byte lock */ + if (start > max_unix_offset) + return 1; /* ignore it */ + switch (type) { + case F_RDLCK: + if (!(filp->f_mode & FMODE_READ)) + return 1; + break; + case F_WRLCK: + if (!(filp->f_mode & FMODE_WRITE)) + return 1; + break; + case F_UNLCK: + break; + default: + status = STATUS_INVALID_PARAMETER; + goto out; + } + if (start > end) { + status = STATUS_INVALID_PARAMETER; + goto out; + } + file_lock.fl_type = type; + file_lock.fl_start = start; + file_lock.fl_end = end - 1; + file_lock.fl_owner = current->files; + file_lock.fl_pid = current->tgid; + file_lock.fl_file = filp; + file_lock.fl_flags = FL_POSIX; + file_lock.fl_ops = NULL; + file_lock.fl_lmops = NULL; + + error = security_file_lock(filp, file_lock.fl_type); + if (error) { + status = errno2ntstatus(-error); + goto out; + } + + error = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); + if (!error) + return 1; + + switch (error) { + case -EACCES: + /* check whether locks work at all on this file system */ + if (vfs_test_lock(filp, &file_lock) >= 0 && (file_lock.fl_type != F_UNLCK)) { + status = STATUS_FILE_LOCK_CONFLICT; + goto out; + } + /* fall through */ + case -EIO: + case -ENOLCK: + /* no locking on this fs, just ignore it */ + fd->fs_locks = 0; + return 1; + case -EAGAIN: + status = STATUS_FILE_LOCK_CONFLICT; + goto out; + default: + status = errno2ntstatus(-error); + goto out; + } + } + +out: + set_error(status); + return 0; +} + +/* check if interval [start;end) overlaps the lock */ +static inline int lock_overlaps(struct uk_file_lock *lock, file_pos_t start, file_pos_t end) +{ + if (lock->end && start >= lock->end) + return 0; + if (end && lock->start >= end) + return 0; + return 1; +} + +/* remove Unix locks for all bytes in the specified area that are no longer locked */ +static void remove_unix_locks(struct fd *fd, file_pos_t start, file_pos_t end) +{ + struct hole + { + struct hole *next; + struct hole *prev; + file_pos_t start; + file_pos_t end; + } *first, *cur, *next, *buffer; + + struct list_head *ptr; + int count = 0; + + if (!fd->inode) + return; + if (!fd->fs_locks) + return; + if (start == end || start > max_unix_offset) + return; + if (!end || end > max_unix_offset) + end = max_unix_offset + 1; + + /* count the number of locks overlapping the specified area */ + + LIST_FOR_EACH(ptr, &fd->inode->locks) { + struct uk_file_lock *lock = LIST_ENTRY(ptr, struct uk_file_lock, inode_entry); + if (lock->start == lock->end) + continue; + if (lock_overlaps(lock, start, end)) + count++; + } + + if (!count) { /* no locks at all, we can unlock everything */ + set_unix_lock(fd, start, end, F_UNLCK); + return; + } + + /* allocate space for the list of holes */ + /* max. number of holes is number of locks + 1 */ + + if (!(buffer = malloc(sizeof(*buffer) * (count+1)))) + return; + first = buffer; + first->next = NULL; + first->prev = NULL; + first->start = start; + first->end = end; + next = first + 1; + + /* build a sorted list of unlocked holes in the specified area */ + + LIST_FOR_EACH(ptr, &fd->inode->locks) { + struct uk_file_lock *lock = LIST_ENTRY(ptr, struct uk_file_lock, inode_entry); + if (lock->start == lock->end) + continue; + if (!lock_overlaps(lock, start, end)) + continue; + + /* go through all the holes touched by this lock */ + for (cur = first; cur; cur = cur->next) { + if (cur->end <= lock->start) + continue; /* hole is before start of lock */ + if (lock->end && cur->start >= lock->end) + break; /* hole is after end of lock */ + + /* now we know that lock is overlapping hole */ + + if (cur->start >= lock->start) { /* lock starts before hole, shrink from start */ + cur->start = lock->end; + if (cur->start && cur->start < cur->end) + break; /* done with this lock */ + /* now hole is empty, remove it */ + if (cur->next) + cur->next->prev = cur->prev; + if (cur->prev) + cur->prev->next = cur->next; + else if (!(first = cur->next)) + goto done; /* no more holes at all */ + } + else if (!lock->end || cur->end <= lock->end) { /* lock larger than hole, shrink from end */ + cur->end = lock->start; +#if 0 + assert(cur->start < cur->end); +#endif + } + else { /* lock is in the middle of hole, split hole in two */ + next->prev = cur; + next->next = cur->next; + cur->next = next; + next->start = lock->end; + next->end = cur->end; + cur->end = lock->start; +#if 0 + assert(next->start < next->end); + assert(cur->end < next->start); +#endif + next++; + break; /* done with this lock */ + } + } + } + + /* clear Unix locks for all the holes */ + + for (cur = first; cur; cur = cur->next) + set_unix_lock(fd, cur->start, cur->end, F_UNLCK); + +done: + free(buffer); +} + +/* create a new lock on a fd */ +static struct uk_file_lock *add_lock(struct fd *fd, int shared, file_pos_t start, file_pos_t end) +{ + struct uk_file_lock *lock; + + if (!(lock = alloc_wine_object(&file_lock_ops))) + return NULL; + lock->shared = shared; + lock->start = start; + lock->end = end; + lock->fd = fd; + lock->process = get_current_w32process(); + + /* now try to set a Unix lock */ + if (!set_unix_lock(lock->fd, lock->start, lock->end, lock->shared ? F_RDLCK : F_WRLCK)) { + release_object(lock); + return NULL; + } + list_add_head(&fd->locks, &lock->fd_entry); + list_add_head(&fd->inode->locks, &lock->inode_entry); + list_add_head(&lock->process->locks, &lock->proc_entry); + return lock; +} + +/* remove an existing lock */ +static void remove_lock(struct uk_file_lock *lock, int remove_unix) +{ + struct uk_inode *inode = lock->fd->inode; + + list_del(&lock->fd_entry); + list_del(&lock->inode_entry); + list_del(&lock->proc_entry); + if (remove_unix) + remove_unix_locks(lock->fd, lock->start, lock->end); + if (list_empty(&inode->locks)) + inode_close_pending(inode, 1); + lock->process = NULL; + uk_wake_up(&lock->obj, 0); + release_object(lock); +} + +/* remove all locks owned by a given process */ +void remove_process_locks(struct w32process *process) +{ + struct list_head *ptr; + + while ((ptr = list_head(&process->locks))) { + struct uk_file_lock *lock = LIST_ENTRY(ptr, struct uk_file_lock, proc_entry); + remove_lock(lock, 1); /* this removes it from the list */ + } +} + +/* remove all locks on a given fd */ +static void remove_fd_locks(struct fd *fd) +{ + file_pos_t start = FILE_POS_T_MAX, end = 0; + struct list_head *ptr; + + while ((ptr = list_head(&fd->locks))) { + struct uk_file_lock *lock = LIST_ENTRY(ptr, struct uk_file_lock, fd_entry); + if (lock->start < start) + start = lock->start; + if (!lock->end || lock->end > end) + end = lock->end - 1; + remove_lock(lock, 0); + } + if (start < end) + remove_unix_locks(fd, start, end + 1); +} + +/* add a lock on an fd */ +/* returns handle to wait on */ +obj_handle_t lock_fd(struct fd *fd, file_pos_t start, file_pos_t count, int shared, int wait) +{ + struct list_head *ptr; + file_pos_t end = start + count; + + if (!fd->inode) { /* not a regular file */ + set_error(STATUS_INVALID_DEVICE_REQUEST); + return 0; + } + + /* don't allow wrapping locks */ + if (end && end < start) { + set_error(STATUS_INVALID_PARAMETER); + return 0; + } + + /* check if another lock on that file overlaps the area */ + LIST_FOR_EACH(ptr, &fd->inode->locks) { + struct uk_file_lock *lock = LIST_ENTRY(ptr, struct uk_file_lock, inode_entry); + if (!lock_overlaps(lock, start, end)) + continue; + if (lock->shared && shared) + continue; + /* found one */ + if (!wait) { + set_error(STATUS_FILE_LOCK_CONFLICT); + return 0; + } + set_error(STATUS_PENDING); + return alloc_handle(get_current_w32process(), lock, SYNCHRONIZE, 0); + } + + /* not found, add it */ + if (add_lock(fd, shared, start, end)) + return 0; + if (get_error() == STATUS_FILE_LOCK_CONFLICT) { + /* Unix lock conflict -> tell client to wait and retry */ + if (wait) + set_error(STATUS_PENDING); + } + return 0; +} + +/* remove a lock on an fd */ +void unlock_fd(struct fd *fd, file_pos_t start, file_pos_t count) +{ + struct list_head *ptr; + file_pos_t end = start + count; + + /* find an existing lock with the exact same parameters */ + LIST_FOR_EACH(ptr, &fd->locks) { + struct uk_file_lock *lock = LIST_ENTRY(ptr, struct uk_file_lock, fd_entry); + if ((lock->start == start) && (lock->end == end)) { + remove_lock(lock, 1); + return; + } + } + set_error(STATUS_FILE_LOCK_CONFLICT); +} + + +/****************************************************************/ +/* file descriptor functions */ + +static void fd_dump(struct object *obj, int verbose) +{ +} + +static void fd_destroy(struct object *obj) +{ + struct fd *fd = (struct fd *)obj; + + free_async_queue(fd->read_q); + free_async_queue(fd->write_q); + free_async_queue(fd->wait_q); + + if (fd->completion) + release_object(fd->completion); + remove_fd_locks(fd); + list_del(&fd->inode_entry); + + if (fd->unix_file) { + fput(fd->unix_file); + fd->unix_file = NULL; + } + + if (fd->inode) { + inode_add_closed_fd(fd->inode, fd->closed); + release_object(fd->inode); + } +} + +/* prepare an fd for unmounting its corresponding device */ +static inline void unmount_fd(struct fd *fd) +{ +#if 0 + assert(fd->inode); +#endif + + async_wake_up(fd->read_q, STATUS_VOLUME_DISMOUNTED); + async_wake_up(fd->write_q, STATUS_VOLUME_DISMOUNTED); + + if (fd->unix_file) { + fput(fd->unix_file); + fd->unix_file = NULL; + } + + fd->no_fd_status = STATUS_VOLUME_DISMOUNTED; + if (fd->closed->unix_file) { + fput(fd->closed->unix_file); /* hcz, modify it */ + fd->closed->unix_file = NULL; + } + fd->closed->unlink[0] = 0; + + /* stop using Unix locks on this fd (existing locks have been removed by close) */ + fd->fs_locks = 0; +} + +/* allocate an fd object, without setting the unix fd yet */ +static struct fd *alloc_fd_object(void) +{ + struct fd *fd = alloc_wine_object(&fd_ops); + + if (!fd) + return NULL; + + fd->fd_ops = NULL; + fd->user = NULL; + fd->inode = NULL; + fd->closed = NULL; + fd->access = 0; + fd->options = 0; + fd->sharing = 0; + fd->unix_file = NULL; + fd->signaled = 1; + fd->fs_locks = 1; + fd->read_q = NULL; + fd->write_q = NULL; + fd->wait_q = NULL; + fd->completion = NULL; + INIT_LIST_HEAD(&fd->inode_entry); + INIT_LIST_HEAD(&fd->locks); + return fd; +} + +/* allocate a pseudo fd object, for objects that need to behave like files but don't have a unix fd */ +struct fd *alloc_pseudo_fd(const struct fd_ops *fd_user_ops, struct object *user, unsigned int options) +{ + struct fd *fd = alloc_wine_object(&fd_ops); + + if (!fd) + return NULL; + + fd->fd_ops = fd_user_ops; + fd->user = user; + fd->inode = NULL; + fd->closed = NULL; + fd->access = 0; + fd->options = options; + fd->sharing = 0; + fd->unix_file = NULL; + fd->signaled = 0; + fd->fs_locks = 0; + fd->read_q = NULL; + fd->write_q = NULL; + fd->wait_q = NULL; + fd->completion = NULL; + fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; + INIT_LIST_HEAD(&fd->inode_entry); + INIT_LIST_HEAD(&fd->locks); + return fd; +} + +/* set the status to return when the fd has no associated unix fd */ +void set_no_fd_status(struct fd *fd, unsigned int status) +{ + fd->no_fd_status = status; +} + +/* check if the desired access is possible without violating */ +/* the sharing mode of other opens of the same file */ +static int check_sharing(struct fd *fd, unsigned int access, unsigned int sharing) +{ + unsigned int existing_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + unsigned int existing_access = 0; + struct list_head *ptr; + + /* if access mode is 0, sharing mode is ignored */ + if (!access) + sharing = existing_sharing; + fd->access = access; + fd->sharing = sharing; + + LIST_FOR_EACH(ptr, &fd->inode->open) { + struct fd *fd_ptr = LIST_ENTRY(ptr, struct fd, inode_entry); + if (fd_ptr != fd) { + existing_sharing &= fd_ptr->sharing; + existing_access |= fd_ptr->access; + } + } + + if ((access & FILE_UNIX_READ_ACCESS) && !(existing_sharing & FILE_SHARE_READ)) + return 0; + if ((access & FILE_UNIX_WRITE_ACCESS) && !(existing_sharing & FILE_SHARE_WRITE)) + return 0; + if ((access & DELETE) && !(existing_sharing & FILE_SHARE_DELETE)) + return 0; + if ((existing_access & FILE_UNIX_READ_ACCESS) && !(sharing & FILE_SHARE_READ)) + return 0; + if ((existing_access & FILE_UNIX_WRITE_ACCESS) && !(sharing & FILE_SHARE_WRITE)) + return 0; + if ((existing_access & DELETE) && !(sharing & FILE_SHARE_DELETE)) + return 0; + return 1; +} + +/* sets the user of an fd that previously had no user */ +void set_fd_user(struct fd *fd, const struct fd_ops *user_ops, struct object *user) +{ +#if 0 + assert(fd->fd_ops == NULL); +#endif + fd->fd_ops = user_ops; + fd->user = user; +} + +/* flags for NtCreateFile and NtOpenFile */ +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_TRANSACTED_MODE 0x00200000 +#define FILE_OPEN_OFFLINE_FILE 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + + +extern long filp_truncate(struct file *file, loff_t length, int small); + +/* open() wrapper that returns a struct fd with no fd user set */ +struct fd *open_fd(const char *name, int flags, mode_t *mode, + unsigned int access, unsigned int sharing, unsigned int options) +{ + struct kstat st; + struct closed_fd *closed_fd; + struct fd *fd; + const char *unlink_name = ""; + int rw_mode, ret; + + if ((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE)) { + set_error(STATUS_INVALID_PARAMETER); + return NULL; + } + + if (!(fd = alloc_fd_object())) + return NULL; + + fd->options = options; + if (options & FILE_DELETE_ON_CLOSE) + unlink_name = name; + if (!(closed_fd = mem_alloc(sizeof(*closed_fd) + strlen(unlink_name)))) { + release_object(fd); + return NULL; + } + + /* create the directory if needed */ + if ((options & FILE_DIRECTORY_FILE) && (flags & O_CREAT)) { + if ((ret = uk_mkdir(name, 0777))) { + if (ret != -EEXIST || (flags & O_EXCL)) { + set_error(errno2ntstatus(-ret)); + goto error; + } + } + flags &= ~(O_CREAT | O_EXCL | O_TRUNC); + } + + if ((access & FILE_UNIX_WRITE_ACCESS) && !(options & FILE_DIRECTORY_FILE)) { + if (access & FILE_UNIX_READ_ACCESS) + rw_mode = O_RDWR; + else rw_mode = O_WRONLY; + } + else rw_mode = O_RDONLY; + + if (IS_ERR(fd->unix_file = filp_open(name, rw_mode | (flags & ~O_TRUNC), *mode))) { + /* if we tried to open a directory for write access, retry read-only */ + if (PTR_ERR(fd->unix_file) != -EISDIR || + !(access & FILE_UNIX_WRITE_ACCESS) || + IS_ERR(fd->unix_file = filp_open(name, O_RDONLY | (flags & ~O_TRUNC), *mode))) { + set_error(errno2ntstatus(-PTR_ERR(fd->unix_file))); + fd->unix_file = NULL; + goto error; + } + } + + closed_fd->unlink[0] = 0; + vfs_getattr(fd->unix_file->f_path.mnt, fd->unix_file->f_path.dentry, &st); + *mode = st.mode; + + /* only bother with an inode for normal files and directories */ + if (S_ISREG(st.mode) || S_ISDIR(st.mode)) { + struct uk_inode *inode = get_inode(old_encode_dev(st.dev), st.ino, fd->unix_file); + + if (!inode) { + /* we can close the fd because there are no others open on the same file, + * otherwise we wouldn't have failed to allocate a new inode + */ + goto error; + } + fd->inode = inode; + fd->closed = closed_fd; + closed_fd->unix_file = fd->unix_file; + get_file(closed_fd->unix_file); + list_add_head(&inode->open, &fd->inode_entry); + + /* check directory options */ + if ((options & FILE_DIRECTORY_FILE) && !S_ISDIR(st.mode)) { + release_object(fd); + set_error(STATUS_NOT_A_DIRECTORY); + return NULL; + } + if ((options & FILE_NON_DIRECTORY_FILE) && S_ISDIR(st.mode)) { + release_object(fd); + set_error(STATUS_FILE_IS_A_DIRECTORY); + return NULL; + } + if (!check_sharing(fd, access, sharing)) { + release_object(fd); + set_error(STATUS_SHARING_VIOLATION); + return NULL; + } + strcpy(closed_fd->unlink, unlink_name); + if (flags & O_TRUNC) + filp_truncate(fd->unix_file, 0, 1); + } else { /* special file */ + if (options & FILE_DIRECTORY_FILE) { + set_error(STATUS_NOT_A_DIRECTORY); + goto error; + } + if (unlink_name[0]) { /* we can't unlink special files */ + set_error(STATUS_INVALID_PARAMETER); + goto error; + } + free(closed_fd); + } + return fd; + +error: + release_object(fd); + free(closed_fd); + return NULL; +} + +/* create an fd for an anonymous file */ +/* if the function fails the unix fd is closed */ +struct fd *create_anonymous_fd(const struct fd_ops *fd_user_ops, + int unix_fd, struct object *user, unsigned int options) +{ + struct fd *fd = alloc_fd_object(); + + if (fd) { + set_fd_user(fd, fd_user_ops, user); + fd->unix_file = fget(unix_fd); + fd->options = options; + return fd; + } + return NULL; +} + +struct fd *create_anon_fd_for_filp(const struct fd_ops *fd_user_ops, + struct file *filp, struct object *user, unsigned int options) +{ + struct fd *fd = alloc_fd_object(); + + if (fd) { + set_fd_user(fd, fd_user_ops, user); + get_file(filp); + fd->unix_file = filp; + fd->options = options; + return fd; + } + return NULL; +} + +/* retrieve the object that is using an fd */ +void *get_fd_user(struct fd *fd) +{ + return fd->user; +} + +/* retrieve the opening options for the fd */ +unsigned int get_fd_options(struct fd *fd) +{ + return fd->options; +} + +struct file *get_unix_file(struct fd *fd) +{ + return fd->unix_file; +} + +/* retrieve the unix fd for an handle */ +int get_unix_fd(obj_handle_t handle) +{ + return get_handle_fd(get_current_eprocess(), handle); +} + +/* check if two file descriptors point to the same file */ +int is_same_file_fd(struct fd *fd1, struct fd *fd2) +{ + return fd1->inode == fd2->inode; +} + +/* check if fd is on a removable device */ +int is_fd_removable(struct fd *fd) +{ + return (fd->inode && fd->inode->device->removable); +} + +/* set or clear the fd signaled state */ +void set_fd_signaled(struct fd *fd, int signaled) +{ + fd->signaled = signaled; + if (signaled) + uk_wake_up(fd->user, 0); +} + +/* handler for close_handle that refuses to close fd-associated handles in other processes */ +int fd_close_handle(struct object *obj, struct w32process *process, obj_handle_t handle) +{ + return (get_current_w32process() == process); +} + +/* check if events are pending and if yes return which one(s) */ +int check_fd_events(struct fd *fd, int events) +{ + return 0; +} + +/* default signaled() routine for objects that poll() on an fd */ +int default_fd_signaled(struct object *obj, struct w32thread *thread) +{ + struct fd *fd = get_obj_fd(obj); + int ret = fd->signaled; + release_object(fd); + return ret; +} + +#define FILE_READ_DATA 0x0001 /* file & pipe */ +#define FILE_LIST_DIRECTORY 0x0001 /* directory */ +#define FILE_WRITE_DATA 0x0002 /* file & pipe */ +#define FILE_ADD_FILE 0x0002 /* directory */ +#define FILE_APPEND_DATA 0x0004 /* file */ +#define FILE_ADD_SUBDIRECTORY 0x0004 /* directory */ +#define FILE_CREATE_PIPE_INSTANCE 0x0004 /* named pipe */ +#define FILE_READ_EA 0x0008 /* file & directory */ +#define FILE_READ_PROPERTIES FILE_READ_EA +#define FILE_WRITE_EA 0x0010 /* file & directory */ +#define FILE_WRITE_PROPERTIES FILE_WRITE_EA +#define FILE_EXECUTE 0x0020 /* file */ +#define FILE_TRAVERSE 0x0020 /* directory */ +#define FILE_DELETE_CHILD 0x0040 /* directory */ +#define FILE_READ_ATTRIBUTES 0x0080 /* all */ +#define FILE_WRITE_ATTRIBUTES 0x0100 /* all */ +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | \ + FILE_READ_ATTRIBUTES | FILE_READ_EA | \ + SYNCHRONIZE) +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | \ + FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | \ + FILE_APPEND_DATA | SYNCHRONIZE) +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_EXECUTE | \ + FILE_READ_ATTRIBUTES | SYNCHRONIZE) + +/* default map_access() routine for objects that behave like an fd */ +unsigned int default_fd_map_access(struct object *obj, unsigned int access) +{ + if (access & GENERIC_READ) + access |= FILE_GENERIC_READ; + if (access & GENERIC_WRITE) + access |= FILE_GENERIC_WRITE; + if (access & GENERIC_EXECUTE) + access |= FILE_GENERIC_EXECUTE; + if (access & GENERIC_ALL) + access |= FILE_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +int default_fd_get_poll_events(struct fd *fd) +{ + int events = 0; +#if 0 /* D.M. TBD */ + if (async_waiting(fd->read_q)) + events |= POLLIN; + if (async_waiting(fd->write_q)) + events |= POLLOUT; +#endif + return events; +} + +/* default handler for poll() events */ +void default_poll_event(struct fd *fd, int event) +{ +#if 0 + if (event & (POLLIN | POLLERR | POLLHUP)) + async_wake_up(fd->read_q, STATUS_ALERTED); + if (event & (POLLOUT | POLLERR | POLLHUP)) + async_wake_up(fd->write_q, STATUS_ALERTED); + + /* if an error occurred, stop polling this fd to avoid busy-looping */ + if (event & (POLLERR | POLLHUP)) + set_fd_events(fd, -1); + else if (!fd->inode) + set_fd_events(fd, fd->fd_ops->get_poll_events(fd)); +#endif +} + +struct async *fd_queue_async(struct fd *fd, const async_data_t *data, int type, int count) +{ + struct async_queue *queue; + struct async *async; + + switch (type) { + case ASYNC_TYPE_READ: + if (!fd->read_q && !(fd->read_q = create_async_queue(fd))) + return NULL; + queue = fd->read_q; + break; + case ASYNC_TYPE_WRITE: + if (!fd->write_q && !(fd->write_q = create_async_queue(fd))) + return NULL; + queue = fd->write_q; + break; + case ASYNC_TYPE_WAIT: + if (!fd->wait_q && !(fd->wait_q = create_async_queue(fd))) + return NULL; + queue = fd->wait_q; + break; + default: + queue = NULL; +#if 0 + assert(0); +#endif + } + + if ((async = create_async(current_thread, queue, data)) && type != ASYNC_TYPE_WAIT) { + if (!fd->inode) + set_fd_events(fd, fd->fd_ops->get_poll_events(fd)); + else /* regular files are always ready for read and write */ + async_wake_up(queue, STATUS_ALERTED); + } + return async; +} + +void fd_async_wake_up(struct fd *fd, int type, unsigned int status) +{ + switch (type) { + case ASYNC_TYPE_READ: + async_wake_up(fd->read_q, status); + break; + case ASYNC_TYPE_WRITE: + async_wake_up(fd->write_q, status); + break; + case ASYNC_TYPE_WAIT: + async_wake_up(fd->wait_q, status); + break; + default: + break; + } +} + +void fd_reselect_async(struct fd *fd, struct async_queue *queue) +{ + fd->fd_ops->reselect_async(fd, queue); +} + +void default_fd_queue_async(struct fd *fd, const async_data_t *data, int type, int count) +{ + struct async *async; + + if ((async = fd_queue_async(fd, data, type, count))) { + release_object(async); + set_error(STATUS_PENDING); + } +} + +/* default reselect_async() fd routine */ +void default_fd_reselect_async(struct fd *fd, struct async_queue *queue) +{ + if (queue != fd->wait_q) { + int poll_events = fd->fd_ops->get_poll_events(fd); + int events = check_fd_events(fd, poll_events); + if (events) + fd->fd_ops->poll_event(fd, events); + else + set_fd_events(fd, poll_events); + } +} + +/* default cancel_async() fd routine */ +void default_fd_cancel_async(struct fd *fd) +{ + async_wake_up(fd->read_q, STATUS_CANCELLED); + async_wake_up(fd->write_q, STATUS_CANCELLED); + async_wake_up(fd->wait_q, STATUS_CANCELLED); +} + +/* default ioctl() routine */ +obj_handle_t default_fd_ioctl(struct fd *fd, ioctl_code_t code, const async_data_t *async, + const void *data, data_size_t size) +{ + switch(code) { +#if 0 + case FSCTL_DISMOUNT_VOLUME: + unmount_device(fd); + return 0; +#endif + default: + set_error(STATUS_NOT_SUPPORTED); + return 0; + } +} + +void *get_wine_handle_obj(struct w32process *proc, HANDLE handle, unsigned int access, const struct object_ops* ops); + +/* same as get_handle_obj but retrieve the struct fd associated to the object */ +static struct fd *get_handle_fd_obj(struct w32process *process, obj_handle_t handle, + unsigned int access) +{ + struct fd *fd = NULL; + struct object *obj; + + if ((obj = get_wine_handle_obj(process, handle, access, NULL))) { + fd = get_obj_fd(obj); + release_object(obj); + } + return fd; +} + +void fd_assign_completion(struct fd *fd, struct uk_completion **p_port, unsigned long *p_key) +{ + *p_key = fd->comp_key; + *p_port = fd->completion ? (struct uk_completion *)grab_object(fd->completion) : NULL; +} + +/* flush a file buffers */ +DECL_HANDLER(flush_file) +{ + struct fd *fd = get_handle_fd_obj(get_current_w32process(), req->handle, 0); + struct kevent * event = NULL; + + if (fd) { + fd->fd_ops->flush(fd, &event); + if (event) { + reply->event = alloc_handle(get_current_w32process(), event, SYNCHRONIZE, 0); + } + release_object(fd); + } +} + +/* open a file object */ +DECL_HANDLER(open_file_object) +{ + struct unicode_str name; + struct object *obj, *result; + + get_req_unicode_str(&name); + if ((obj = open_object_dir(req->rootdir, &name, req->attributes, NULL))) { + if (BODY_TO_HEADER(obj)->ops) { + if ((result = BODY_TO_HEADER(obj)->ops->open_file(obj, req->access, req->sharing, req->options))) { + reply->handle = alloc_handle(get_current_w32process(), result, req->access, req->attributes); + release_object(result); + } + } + release_object(obj); + } +} + + +/* get a Unix fd to access a file */ +DECL_HANDLER(get_handle_fd) +{ + struct fd *fd; + + reply->fd = -1; + if ((fd = get_handle_fd_obj(get_current_w32process(), req->handle, 0))) { + int unix_fd = get_handle_fd(get_current_eprocess(), req->handle); + if (unix_fd != -1) { + reply->type = fd->fd_ops->get_fd_type(fd); + reply->removable = is_fd_removable(fd); + reply->options = fd->options; + reply->access = get_handle_access(current->ethread ? get_current_eprocess() : NULL, req->handle); + reply->fd = unix_fd; + } + release_object(fd); + } +} + +/* perform an ioctl on a file */ +DECL_HANDLER(ioctl) +{ + unsigned int access = (req->code >> 14) & (FILE_READ_DATA|FILE_WRITE_DATA); + struct fd *fd = get_handle_fd_obj(get_current_w32process(), req->handle, access); + + if (fd) { + reply->wait = fd->fd_ops->ioctl(fd, req->code, &req->async, + get_req_data(), get_req_data_size()); + reply->options = fd->options; + release_object(fd); + } +} + +/* create / reschedule an async I/O */ +DECL_HANDLER(register_async) +{ + unsigned int access; + struct fd *fd; + + switch(req->type) { + case ASYNC_TYPE_READ: + access = FILE_READ_DATA; + break; + case ASYNC_TYPE_WRITE: + access = FILE_WRITE_DATA; + break; + default: + set_error(STATUS_INVALID_PARAMETER); + return; + } + + if ((fd = get_handle_fd_obj(get_current_w32process(), req->handle, access))) { + if (fd->unix_file) + fd->fd_ops->queue_async(fd, &req->async, req->type, req->count); + release_object(fd); + } +} + +/* cancels all async I/O */ +DECL_HANDLER(cancel_async) +{ + struct fd *fd = get_handle_fd_obj(get_current_w32process(), req->handle, 0); + + if (fd) { + if (fd->unix_file) + fd->fd_ops->cancel_async(fd); + release_object(fd); + } +} + +extern struct uk_completion *get_completion_obj(struct w32process *process, obj_handle_t handle, unsigned int access); +extern void add_completion(struct uk_completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information); + +#define IO_COMPLETION_QUERY_STATE 0x0001 +#define IO_COMPLETION_MODIFY_STATE 0x0002 +#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3) + +/* attach completion object to a fd */ +DECL_HANDLER(set_completion_info) +{ + struct fd *fd = get_handle_fd_obj(get_current_w32process(), req->handle, 0); + + if (fd) { + if (!(fd->options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) && !fd->completion) { + fd->completion = get_completion_obj(get_current_w32process(), req->chandle, IO_COMPLETION_MODIFY_STATE); + fd->comp_key = req->ckey; + } + else set_error(STATUS_INVALID_PARAMETER); + release_object(fd); + } +} + +/* push new completion msg into a completion queue attached to the fd */ +DECL_HANDLER(add_fd_completion) +{ + struct fd *fd = get_handle_fd_obj(get_current_w32process(), req->handle, 0); + if (fd) { + if (fd->completion) + add_completion(fd->completion, fd->comp_key, req->cvalue, req->status, req->information); + release_object(fd); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/file.c b/unifiedkernel/fs/file.c new file mode 100644 index 0000000..9191243 --- /dev/null +++ b/unifiedkernel/fs/file.c @@ -0,0 +1,505 @@ +/* + * file.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * file.c: + * Refered to Wine code + */ +#include +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "wineserver/info.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct uk_file +{ + struct object obj; /* object header */ + struct fd *fd; /* file descriptor for this file */ + unsigned int access; /* file access (FILE_READ_DATA etc.) */ + mode_t mode; /* file stat.st_mode */ + uid_t uid; /* file stat.st_uid */ +}; + +static unsigned int generic_file_map_access(unsigned int access); + +static void file_dump(struct object *obj, int verbose); +static struct fd *file_get_fd(struct object *obj); +static void file_destroy(struct object *obj); + +static int file_get_poll_events(struct fd *fd); +static void file_flush(struct fd *fd, struct kevent **event); +static enum server_fd_type file_get_fd_type(struct fd *fd); + +extern unsigned int default_fd_map_access(struct object *obj, unsigned int access); +extern NTSTATUS errno2ntstatus(int error); + +static const struct object_ops file_ops = +{ + sizeof(struct uk_file), /* size */ + file_dump, /* dump */ + no_get_type, /* get_type */ + file_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + file_destroy /* destroy */ +}; + +static const struct fd_ops file_fd_ops = +{ + file_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + file_flush, /* flush */ + file_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ +}; + +/* flags for NtCreateFile and NtOpenFile */ +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_TRANSACTED_MODE 0x00200000 +#define FILE_OPEN_OFFLINE_FILE 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +#define FILE_ATTRIBUTE_VALID_FLAGS 0x00007fb7 +#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x000031a7 + +/* disposition for NtCreateFile */ +#define FILE_SUPERSEDE 0 + +extern struct fd *create_anon_fd_for_filp(const struct fd_ops *fd_user_ops, + struct file *filp, struct object *user, unsigned int options); +static inline int is_overlapped(const struct uk_file *file) +{ + return !(get_fd_options(file->fd) & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)); +} + +/* create a file from a file struct */ +/* if the function fails the fd is closed */ +static struct uk_file *create_file_for_filp(struct file *filp, unsigned int access, unsigned int sharing) +{ + struct uk_file *file; + + if ((file = alloc_wine_object(&file_ops))) { + INIT_DISP_HEADER(&file->obj.header, 0, sizeof(struct uk_file), 0); + file->mode = filp->f_path.dentry->d_inode->i_mode; + file->access = default_fd_map_access(&file->obj, access); + if (!(file->fd = create_anon_fd_for_filp(&file_fd_ops, filp, + &file->obj, FILE_SYNCHRONOUS_IO_NONALERT))) { + release_object(file); + return NULL; + } + } + return file; +} + +static struct object *create_file_obj(struct fd *fd, unsigned int access, mode_t mode) +{ + struct uk_file *file = alloc_wine_object(&file_ops); + + if (!file) + return NULL; + INIT_DISP_HEADER(&file->obj.header, 0, sizeof(struct uk_file), 0); + file->access = access; + file->mode = mode; + file->fd = fd; + grab_object(fd); + set_fd_user(fd, &file_fd_ops, &file->obj); + return &file->obj; +} + +extern struct file *get_unix_file(struct fd *fd); +static struct object *create_file(const char *nameptr, data_size_t len, unsigned int access, + unsigned int sharing, int create, unsigned int options, + unsigned int attrs, const struct security_descriptor *sd) +{ + struct object *obj = NULL; + struct fd *fd; + int flags; + char *name; + mode_t mode; + + if (!(name = mem_alloc(len + 1))) + return NULL; + memcpy(name, nameptr, len); + name[len] = 0; + + switch(create) { + case FILE_CREATE: flags = O_CREAT | O_EXCL; break; + case FILE_OVERWRITE_IF: /* FIXME: the difference is whether we trash existing attr or not */ + case FILE_SUPERSEDE: flags = O_CREAT | O_TRUNC; break; + case FILE_OPEN: flags = 0; break; + case FILE_OPEN_IF: flags = O_CREAT; break; + case FILE_OVERWRITE: flags = O_TRUNC; break; + default: set_error(STATUS_INVALID_PARAMETER); goto done; + } + + if (sd) { +#if 0 + const SID *owner = sd_get_owner(sd); + if (!owner) + owner = token_get_user(get_current_w32process()->token); + mode = sd_to_mode(sd, owner); +#endif + } + else + mode = (attrs & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666; + + if (len >= 4 && + (!strcasecmp(name + len - 4, ".exe") || !strcasecmp(name + len - 4, ".com"))) { + if (mode & S_IRUSR) + mode |= S_IXUSR; + if (mode & S_IRGRP) + mode |= S_IXGRP; + if (mode & S_IROTH) + mode |= S_IXOTH; + } + + access = generic_file_map_access(access); + + /* FIXME: should set error to STATUS_OBJECT_NAME_COLLISION if file existed before */ + fd = open_fd(name, flags | O_NONBLOCK | O_LARGEFILE, &mode, access, sharing, options); + if (!fd) + goto done; + + if (S_ISDIR(mode)) + obj = create_dir_obj(fd); + else if (S_ISCHR(mode) && is_serial_fd(fd)) + obj = create_serial(fd); + else + obj = create_file_obj(fd, access, mode); + + release_object(fd); + +done: + free(name); + return obj; +} + +extern int is_same_file(struct uk_file *file1, struct uk_file *file2); +extern struct uk_file *create_temp_file(int access); + +/* check if two file objects point to the same file */ +int is_same_file(struct uk_file *file1, struct uk_file *file2) +{ + return is_same_file_fd(file1->fd, file2->fd); +} + +/* create a temp file for anonymous mappings */ +struct uk_file *create_temp_file(int access) +{ + static char prefixfn[] = "anonmap."; + char tmpfn[16], *p; + struct file *filp; + struct uk_file *ret; + int value = current->tgid; + + memcpy(tmpfn, prefixfn, sizeof(prefixfn) - 1); + p = tmpfn + sizeof(prefixfn) - 1; + do { + struct timespec ts; + + getnstimeofday(&ts); + value += 7777777; + sprintf(p, "%07lx", (ts.tv_nsec + value) / 100); + filp = filp_open((const char *)tmpfn, O_RDWR | O_CREAT | O_EXCL, 0600); + } while (PTR_ERR(filp) == -EEXIST); + if (IS_ERR(filp)) { + set_error(errno2ntstatus(-PTR_ERR(filp))); + return NULL; + } + uk_unlink(tmpfn); + ret = create_file_for_filp(filp, access, 0); + fput(filp); + + return ret; +} + +static void file_dump(struct object *obj, int verbose) +{ +#if 0 + struct uk_file *file = (struct uk_file *)obj; + assert(obj->ops == &file_ops); + fprintf(stderr, "File fd=%p\n", file->fd); +#endif +} + +static int file_get_poll_events(struct fd *fd) +{ + struct uk_file *file = get_fd_user(fd); + int events = 0; +#if 0 + assert(file->obj.ops == &file_ops); +#endif + if (file->access & FILE_UNIX_READ_ACCESS) + events |= POLLIN; + if (file->access & FILE_UNIX_WRITE_ACCESS) + events |= POLLOUT; + return events; +} + +extern int uk_fsync(unsigned int); + +static void file_flush(struct fd *fd, struct kevent **event) +{ + struct file *file = get_unix_file(fd); + int ret; + + if (file && (ret = vfs_fsync(file, file->f_path.dentry, 0)) < 0) { + set_error(errno2ntstatus(-ret)); + } +} + +static enum server_fd_type file_get_fd_type(struct fd *fd) +{ + struct uk_file *file = get_fd_user(fd); + + if (S_ISREG(file->mode) || S_ISBLK(file->mode)) + return FD_TYPE_FILE; + if (S_ISDIR(file->mode)) + return FD_TYPE_DIR; + return FD_TYPE_CHAR; +} + +static struct fd *file_get_fd(struct object *obj) +{ + struct uk_file *file = (struct uk_file *)obj; +#if 0 + assert(obj->ops == &file_ops); +#endif + return (struct fd *)grab_object(file->fd); +} + +#define FILE_READ_DATA 0x0001 /* file & pipe */ +#define FILE_LIST_DIRECTORY 0x0001 /* directory */ +#define FILE_WRITE_DATA 0x0002 /* file & pipe */ +#define FILE_ADD_FILE 0x0002 /* directory */ +#define FILE_APPEND_DATA 0x0004 /* file */ +#define FILE_ADD_SUBDIRECTORY 0x0004 /* directory */ +#define FILE_CREATE_PIPE_INSTANCE 0x0004 /* named pipe */ +#define FILE_READ_EA 0x0008 /* file & directory */ +#define FILE_READ_PROPERTIES FILE_READ_EA +#define FILE_WRITE_EA 0x0010 /* file & directory */ +#define FILE_WRITE_PROPERTIES FILE_WRITE_EA +#define FILE_EXECUTE 0x0020 /* file */ +#define FILE_TRAVERSE 0x0020 /* directory */ +#define FILE_DELETE_CHILD 0x0040 /* directory */ +#define FILE_READ_ATTRIBUTES 0x0080 /* all */ +#define FILE_WRITE_ATTRIBUTES 0x0100 /* all */ +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | \ + FILE_READ_ATTRIBUTES | FILE_READ_EA | \ + SYNCHRONIZE) +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | \ + FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | \ + FILE_APPEND_DATA | SYNCHRONIZE) +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_EXECUTE | \ + FILE_READ_ATTRIBUTES | SYNCHRONIZE) +static unsigned int generic_file_map_access(unsigned int access) +{ + if (access & GENERIC_READ) + access |= FILE_GENERIC_READ; + if (access & GENERIC_WRITE) + access |= FILE_GENERIC_WRITE; + if (access & GENERIC_EXECUTE) + access |= FILE_GENERIC_EXECUTE; + if (access & GENERIC_ALL) + access |= FILE_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + + +static void file_destroy(struct object *obj) +{ + struct uk_file *file = (struct uk_file *)obj; +#if 0 + assert(obj->ops == &file_ops); +#endif + + if (file->fd) + release_object(file->fd); +} + +struct uk_file *get_file_obj(struct w32process *process, obj_handle_t handle, unsigned int access) +{ + return (struct uk_file *)get_wine_handle_obj(process, handle, access, &file_ops); +} + +struct file *get_file_unix_file(struct uk_file *file) +{ + return get_unix_file(file->fd); +} + +struct uk_file *grab_file_unless_removable(struct uk_file *file) +{ + if (is_fd_removable(file->fd)) + return NULL; + return (struct uk_file *)grab_object(file); +} + +extern long filp_truncate(struct file *file, loff_t length, int small); + +/* extend a file beyond the current end of file */ +static int extend_file(struct file *filp, file_pos_t new_size) +{ + int ret; + off_t size = new_size; + + if (sizeof(new_size) > sizeof(size) && size != new_size) { + set_error(STATUS_INVALID_PARAMETER); + return 0; + } + + if (!(ret = filp_truncate(filp, size, 1))) + return 1; + + set_error(errno2ntstatus(-ret)); + return 0; +} + +/* try to grow the file to the specified size */ +int grow_file(struct uk_file *file, file_pos_t size) +{ + struct file *filp = get_unix_file(file->fd); + + if (!filp) + return 0; + + if (get_file_size(filp) >= size) + return 1; /* already large enough */ + + return extend_file(filp, size); +} + +extern int objattr_is_valid(const struct object_attributes *, int); + +/* create a file */ +DECL_HANDLER(create_file) +{ + struct object *file; + const struct object_attributes *objattr = get_req_data(); + const struct security_descriptor *sd; + const char *name; + data_size_t name_len; + + reply->handle = 0; + + if (!objattr_is_valid(objattr, get_req_data_size())) + return; + /* name is transferred in the unix codepage outside of the objattr structure */ + if (objattr->name_len) { + set_error(STATUS_INVALID_PARAMETER); + return; + } + + sd = objattr->sd_len ? (const struct security_descriptor *)(objattr + 1) : NULL; + + name = (const char *)get_req_data() + sizeof(*objattr) + objattr->sd_len; + name_len = get_req_data_size() - sizeof(*objattr) - objattr->sd_len; + + reply->handle = 0; + if ((file = create_file(name, name_len, req->access, + req->sharing, req->create, req->options, + req->attrs, sd))) { + reply->handle = alloc_handle(get_current_w32process(), file, req->access, req->attributes); + release_object(file); + } +} + +/* allocate a file handle for a Unix fd */ +DECL_HANDLER(alloc_file_handle) +{ + struct uk_file *file; + struct file *filp = fget(req->fd); + + if (!filp) + return; + + reply->handle = 0; + if ((file = create_file_for_filp(filp, req->access, FILE_SHARE_READ | FILE_SHARE_WRITE))) { + reply->handle =(void*) alloc_handle(get_current_w32process(), file, req->access, req->attributes); + release_object(file); + } + + fput(filp); +} + +/* lock a region of a file */ +DECL_HANDLER(lock_file) +{ + struct uk_file *file; + + if ((file = get_file_obj(get_current_w32process(), req->handle, 0))) { + reply->handle = lock_fd(file->fd, req->offset, req->count, req->shared, req->wait); + reply->overlapped = is_overlapped(file); + release_object(file); + } +} + +/* unlock a region of a file */ +DECL_HANDLER(unlock_file) +{ + struct uk_file *file; + + if ((file = get_file_obj(get_current_w32process(), req->handle, 0))) { + unlock_fd(file->fd, req->offset, req->count); + release_object(file); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/mapping.c b/unifiedkernel/fs/mapping.c new file mode 100644 index 0000000..9b0f588 --- /dev/null +++ b/unifiedkernel/fs/mapping.c @@ -0,0 +1,468 @@ +/* + * mapping.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * mapping.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "wineserver/info.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "pefile.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct uk_file; + +struct mapping +{ + struct object obj; /* object header */ + file_pos_t size; /* mapping size */ + int protect; /* protection flags */ + struct uk_file *file; /* file mapped */ + int header_size; /* size of headers (for PE image mapping) */ + void *base; /* default base addr (for PE image mapping) */ + struct uk_file *shared_file; /* temp file for shared PE mapping */ + struct list_head shared_entry; /* entry in global shared PE mappings list */ +}; + +static void mapping_dump(struct object *obj, int verbose); +static struct object_type *mapping_get_type(struct object *obj); +static struct fd *mapping_get_fd(struct object *obj); +static unsigned int mapping_map_access(struct object *obj, unsigned int access); +static void mapping_destroy(struct object *obj); + +static const struct object_ops mapping_ops = +{ + sizeof(struct mapping), /* size */ + mapping_dump, /* dump */ + mapping_get_type, /* get_type */ + mapping_get_fd, /* get_fd */ + mapping_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + mapping_destroy /* destroy */ +}; + +static struct list_head shared_list = LIST_INIT(shared_list); + + +#define ROUND_SIZE(size) (((size) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1)) + +extern int is_same_file(void *file1, void *file2); + +/* find the shared PE mapping for a given mapping */ +static struct uk_file *get_shared_file(struct mapping *mapping) +{ + struct mapping *ptr; + + LIST_FOR_EACH_ENTRY(ptr, &shared_list, struct mapping, shared_entry) + if (is_same_file(ptr->file, mapping->file)) + return (struct uk_file *)grab_object(ptr->shared_file); + return NULL; +} + +/* return the size of the memory mapping and file range of a given section */ +static inline void get_section_sizes(const IMAGE_SECTION_HEADER *sec, size_t *map_size, + off_t *file_start, size_t *file_size) +{ + static const unsigned int sector_align = 0x1ff; + + if (!sec->Misc.VirtualSize) + *map_size = ROUND_SIZE(sec->SizeOfRawData); + else + *map_size = ROUND_SIZE(sec->Misc.VirtualSize); + + *file_start = sec->PointerToRawData & ~sector_align; + *file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align; + if (*file_size > *map_size) + *file_size = *map_size; +} + +extern struct uk_file *create_temp_file(int access); + +extern struct file *get_file_unix_file(struct uk_file *file); + +/* allocate and fill the temp file for a shared PE image mapping */ +static int build_shared_mapping(struct mapping *mapping, struct file *filp, + IMAGE_SECTION_HEADER *sec, unsigned int nb_sec) +{ + unsigned int i; + file_pos_t total_size; + size_t file_size, map_size, max_size; + off_t shared_pos, read_pos, write_pos; + char *buffer = NULL; + struct file *shared_filp; + long toread; + + /* compute the total size of the shared mapping */ + + total_size = max_size = 0; + for (i = 0; i < nb_sec; i++) { + if ((sec[i].Characteristics & IMAGE_SCN_MEM_SHARED) && + (sec[i].Characteristics & IMAGE_SCN_MEM_WRITE)) { + get_section_sizes(&sec[i], &map_size, &read_pos, &file_size); + if (file_size > max_size) + max_size = file_size; + total_size += map_size; + } + } + if (!total_size) + return 1; /* nothing to do */ + + if ((mapping->shared_file = get_shared_file(mapping))) + return 1; + + /* create a temp file for the mapping */ + if (!(mapping->shared_file = create_temp_file(FILE_GENERIC_READ|FILE_GENERIC_WRITE))) + return 0; + if (!grow_file(mapping->shared_file, total_size)) + goto error; + if (!(shared_filp = get_file_unix_file(mapping->shared_file))) + goto error; + + if (!(buffer = malloc(max_size))) + goto error; + + /* copy the shared sections data into the temp file */ + shared_pos = 0; + for (i = 0; i < nb_sec; i++) { + if (!(sec[i].Characteristics & IMAGE_SCN_MEM_SHARED)) + continue; + if (!(sec[i].Characteristics & IMAGE_SCN_MEM_WRITE)) + continue; + get_section_sizes(&sec[i], &map_size, &read_pos, &file_size); + write_pos = shared_pos; + shared_pos += map_size; + if (!sec[i].PointerToRawData || !file_size) + continue; + toread = file_size; + while (toread) { + long res = uk_filp_pread(filp, buffer + file_size - toread, toread, read_pos); + if (!res && toread < 0x200) { /* partial sector at EOF is not an error */ + file_size -= toread; + break; + } + if (res <= 0) + goto error; + toread -= res; + read_pos += res; + } + if (uk_filp_pwrite(shared_filp, buffer, file_size, write_pos) != file_size) + goto error; + } + free(buffer); + return 1; + + error: + release_object(mapping->shared_file); + mapping->shared_file = NULL; + free(buffer); + return 0; +} + +extern struct file *get_unix_file(struct fd *fd); + +/* retrieve the mapping parameters for an executable (PE) image */ +static int get_image_params(struct mapping *mapping) +{ + IMAGE_DOS_HEADER dos; + IMAGE_NT_HEADERS nt; + IMAGE_SECTION_HEADER *sec = NULL; + struct file *filp; + off_t pos; + int size, toread; + + /* load the headers */ + if (!(filp = get_file_unix_file(mapping->file))) + goto error; + if (uk_filp_pread(filp, (char *)&dos, sizeof(dos), 0) != sizeof(dos)) + goto error; + if (dos.e_magic != IMAGE_DOS_SIGNATURE) + goto error; + pos = dos.e_lfanew; + + if (uk_filp_pread(filp, (char *)&nt.Signature, sizeof(nt.Signature), pos) != sizeof(nt.Signature)) + goto error; + pos += sizeof(nt.Signature); + if (nt.Signature != IMAGE_NT_SIGNATURE) + goto error; + if (uk_filp_pread(filp, (char *)&nt.FileHeader, sizeof(nt.FileHeader), pos) != sizeof(nt.FileHeader)) + goto error; + pos += sizeof(nt.FileHeader); + /* zero out Optional header in the case it's not present or partial */ + memset(&nt.OptionalHeader, 0, sizeof(nt.OptionalHeader)); + toread = min((WORD)sizeof(nt.OptionalHeader), nt.FileHeader.SizeOfOptionalHeader); + if (uk_filp_pread(filp, (char *)&nt.OptionalHeader, toread, pos) != toread) + goto error; + pos += nt.FileHeader.SizeOfOptionalHeader; + + /* load the section headers */ + + size = sizeof(*sec) * nt.FileHeader.NumberOfSections; + if (!(sec = malloc(size))) + goto error; + if (uk_filp_pread(filp, (char *)sec, size, pos) != size) + goto error; + + if (!build_shared_mapping(mapping, filp, sec, nt.FileHeader.NumberOfSections)) + goto error; + + if (mapping->shared_file) + list_add_head(&shared_list, &mapping->shared_entry); + + mapping->size = ROUND_SIZE(nt.OptionalHeader.SizeOfImage); + mapping->base = (void *)nt.OptionalHeader.ImageBase; + mapping->header_size = max((unsigned int)(pos + size), nt.OptionalHeader.SizeOfHeaders); + mapping->protect = VPROT_IMAGE; + + /* sanity check */ + if (pos + size > mapping->size) + goto error; + + free(sec); + return 1; + + error: + free(sec); + set_error(STATUS_INVALID_FILE_FOR_SECTION); + return 0; +} + +extern struct uk_file *get_file_obj(struct w32process *process, obj_handle_t handle, unsigned int access); +static struct object *create_mapping(HANDLE root, const struct unicode_str *name, + unsigned int attr, file_pos_t size, int protect, + obj_handle_t handle, const struct security_descriptor *sd) +{ + struct mapping *mapping; + int access = 0; + + if (!(mapping = create_named_object_dir(root, name, attr, &mapping_ops))) + return NULL; + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + return &mapping->obj; /* Nothing else to do */ + + mapping->header_size = 0; + mapping->base = NULL; + mapping->shared_file = NULL; + + if (protect & VPROT_READ) + access |= FILE_READ_DATA; + if (protect & VPROT_WRITE) + access |= FILE_WRITE_DATA; + + if (handle) { + if (!(mapping->file = get_file_obj(get_current_w32process(), handle, access))) + goto error; + if (protect & VPROT_IMAGE) { + if (!get_image_params(mapping)) + goto error; + return &mapping->obj; + } + if (!size) { + size = get_file_size(get_file_unix_file(mapping->file)); + if (!size) { + set_error(STATUS_MAPPED_FILE_SIZE_ZERO); + goto error; + } + } + else { + if (!grow_file(mapping->file, size)) + goto error; + } + } + else { /* Anonymous mapping (no associated file) */ + if (!size || (protect & VPROT_IMAGE)) { + set_error(STATUS_INVALID_PARAMETER); + mapping->file = NULL; + goto error; + } + if (!(mapping->file = create_temp_file(access))) + goto error; + if (!grow_file(mapping->file, size)) + goto error; + } + mapping->size = ROUND_SIZE(size); + mapping->protect = protect; + return &mapping->obj; + + error: + release_object(mapping); + return NULL; +} + +static void mapping_dump(struct object *obj, int verbose) +{ +#if 0 + struct mapping *mapping = (struct mapping *)obj; + assert(obj->ops == &mapping_ops); + fprintf(stderr, "Mapping size=%08x%08x prot=%08x file=%p header_size=%08x base=%p " + "shared_file=%p ", + (unsigned int)(mapping->size >> 32), (unsigned int)mapping->size, + mapping->protect, mapping->file, mapping->header_size, + mapping->base, mapping->shared_file); + dump_object_name(&mapping->obj); + fputc('\n', stderr);a +#endif +} + +struct object_type *get_object_type(const struct unicode_str *name); + +static struct object_type *mapping_get_type(struct object *obj) +{ + static const WCHAR name[] = {'S','e','c','t','i','o','n'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type(&str); +} + +static struct fd *mapping_get_fd(struct object *obj) +{ + struct mapping *mapping = (struct mapping *)obj; + return get_obj_fd((struct object *)mapping->file); +} + +static unsigned int mapping_map_access(struct object *obj, unsigned int access) +{ + if (access & GENERIC_READ) + access |= STANDARD_RIGHTS_READ | SECTION_QUERY | SECTION_MAP_READ; + if (access & GENERIC_WRITE) + access |= STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE; + if (access & GENERIC_EXECUTE) + access |= STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE; + if (access & GENERIC_ALL) + access |= SECTION_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +static void mapping_destroy(struct object *obj) +{ + struct mapping *mapping = (struct mapping *)obj; +#if 0 + assert(obj->ops == &mapping_ops); +#endif + if (mapping->file) + release_object(mapping->file); + if (mapping->shared_file) { + release_object(mapping->shared_file); + list_remove(&mapping->shared_entry); + } +} + +extern int objattr_is_valid(const struct object_attributes *attrib, int size); +extern void objattr_get_name(const struct object_attributes *objattr, struct unicode_str *name); +extern obj_handle_t alloc_handle_no_access_check(struct w32process *process, void *ptr, unsigned int access, unsigned int attr); + +extern HANDLE base_dir_handle; +/* create a file mapping */ +DECL_HANDLER(create_mapping) +{ + struct object *obj; + struct unicode_str name; + struct directory *root = NULL; + struct object_attributes *objattr = get_req_data(); + const struct security_descriptor *sd; + + reply->handle = 0; + + if (!objattr_is_valid(objattr, get_req_data_size())) + return; + + sd = objattr->sd_len ? (const struct security_descriptor *)(objattr + 1) : NULL; + objattr_get_name(objattr, &name); + + if (objattr->rootdir) + objattr->rootdir = base_dir_handle; + if ((obj = create_mapping(objattr->rootdir, &name, req->attributes, req->size, req->protect, req->file_handle, sd))) { + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle(get_current_w32process(), obj, req->access, req->attributes); + else + reply->handle = alloc_handle_no_access_check(get_current_w32process(), obj, req->access, req->attributes); + release_object(obj); + } + + if (root) + release_object(root); +} + +/* open a handle to a mapping */ +DECL_HANDLER(open_mapping) +{ + struct unicode_str name; + struct directory *root = NULL; + struct mapping *mapping; + + get_req_unicode_str(&name); + + if ((mapping = open_object_dir(req->rootdir ? base_dir_handle : NULL, &name, req->attributes, &mapping_ops))) { + reply->handle = alloc_handle(get_current_w32process(), &mapping->obj, req->access, req->attributes); + release_object(mapping); + } + + if (root) + release_object(root); +} + +/* get a mapping information */ +DECL_HANDLER(get_mapping_info) +{ + struct mapping *mapping; + struct fd *fd; + + if ((mapping = (struct mapping *)get_wine_handle_obj(get_current_w32process(), req->handle, + 0, &mapping_ops))) { + reply->size = mapping->size; + reply->protect = mapping->protect; + reply->header_size = mapping->header_size; + reply->base = mapping->base; + reply->shared_file = 0; + if ((fd = get_obj_fd(&mapping->obj))) { + if (!is_fd_removable(fd)) + reply->mapping = alloc_handle(get_current_w32process(), mapping, 0, 0); + release_object(fd); + } + if (mapping->shared_file) { + if (!(reply->shared_file = alloc_handle(get_current_w32process(), mapping->shared_file, + GENERIC_READ|GENERIC_WRITE, 0))) { + if (reply->mapping) close_handle(get_current_eprocess(), reply->mapping); + } + } + release_object(mapping); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/fs/symlink.c b/unifiedkernel/fs/symlink.c new file mode 100644 index 0000000..68df438 --- /dev/null +++ b/unifiedkernel/fs/symlink.c @@ -0,0 +1,231 @@ +/* + * symlink.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * symlink.c: + * Refered to Wine code + */ +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +struct symlink +{ + struct object obj; /* object header */ + WCHAR *target; /* target of the symlink */ + data_size_t len; /* target len in bytes */ +}; + +static void symlink_dump( struct object *obj, int verbose ); +static struct object_type *symlink_get_type( struct object *obj ); +static unsigned int symlink_map_access( struct object *obj, unsigned int access ); +static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ); +static void symlink_destroy( struct object *obj ); + +static const struct object_ops symlink_ops = +{ + sizeof(struct symlink), /* size */ + symlink_dump, /* dump */ + symlink_get_type, /* get_type */ + no_get_fd, /* get_fd */ + symlink_map_access, /* map_access */ + symlink_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + symlink_destroy /* destroy */ +}; + +static void symlink_dump( struct object *obj, int verbose ) +{ +#if 0 + struct symlink *symlink = (struct symlink *)obj; + assert( obj->ops == &symlink_ops ); + + fprintf( stderr, "Symlink " ); + dump_object_name( obj ); + fprintf( stderr, " -> L\"" ); + dump_strW( symlink->target, symlink->len / sizeof(WCHAR), stderr, "\"\"" ); + fprintf( stderr, "\"\n" ); +#endif +} + +extern struct object_type *get_object_type( const struct unicode_str* ); + +static struct object_type *symlink_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'S','y','m','b','o','l','i','c','L','i','n','k'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +static struct object *symlink_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr ) +{ + struct symlink *symlink = (struct symlink *)obj; + struct unicode_str target_str, name_left; + struct object *target; + +#if 0 + assert( obj->ops == &symlink_ops ); +#endif + if (attr & OBJ_OPENLINK) + return NULL; + + target_str.str = symlink->target; + target_str.len = symlink->len; + if ((target = find_object_dir( NULL, &target_str, attr, &name_left ))) { + if (name_left.len) { + release_object( target ); + target = NULL; + set_error( STATUS_OBJECT_PATH_NOT_FOUND ); + } + } + return target; +} + +#define SYMBOLIC_LINK_QUERY 0x0001 +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) + +static unsigned int symlink_map_access( struct object *obj, unsigned int access ) +{ + if (access & GENERIC_READ) + access |= STANDARD_RIGHTS_READ | SYMBOLIC_LINK_QUERY; + if (access & GENERIC_WRITE) + access |= STANDARD_RIGHTS_WRITE; + if (access & GENERIC_EXECUTE) + access |= STANDARD_RIGHTS_EXECUTE; + if (access & GENERIC_ALL) + access |= SYMBOLIC_LINK_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +static void symlink_destroy( struct object *obj ) +{ + struct symlink *symlink = (struct symlink *)obj; +#if 0 + assert( obj->ops == &symlink_ops ); +#endif + free( symlink->target ); +} + +struct symlink *create_symlink( struct directory *root, const struct unicode_str *name, + unsigned int attr, const struct unicode_str *target ) +{ + struct symlink *symlink; + + if (!target->len) { + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + } + if ((symlink = create_named_object_dir( root, name, attr, &symlink_ops )) && + (get_error() != STATUS_OBJECT_NAME_EXISTS)) { + if ((symlink->target = memdup( target->str, target->len ))) + symlink->len = target->len; + else { + release_object( symlink ); + symlink = NULL; + } + } + return symlink; +} + + +/* create a symbolic link object */ +DECL_HANDLER(create_symlink) +{ + struct symlink *symlink; + struct unicode_str name, target; + struct directory *root = NULL; + + if (req->name_len > get_req_data_size()) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + name.str = get_req_data(); + target.str = name.str + req->name_len / sizeof(WCHAR); + name.len = (target.str - name.str) * sizeof(WCHAR); + target.len = ((get_req_data_size() - name.len) / sizeof(WCHAR)) * sizeof(WCHAR); + + if ((symlink = create_symlink( req->rootdir, &name, req->attributes, &target ))) { + reply->handle = alloc_handle( get_current_w32process(), symlink, req->access, req->attributes ); + release_object( symlink ); + } + + if (root) + release_object( root ); +} + +/* open a symbolic link object */ +DECL_HANDLER(open_symlink) +{ + struct unicode_str name; + struct directory *root = NULL; + struct symlink *symlink; + + get_req_unicode_str( &name ); + + if ((symlink = open_object_dir( req->rootdir, &name, req->attributes | OBJ_OPENLINK, &symlink_ops ))) { + reply->handle = alloc_handle( get_current_w32process(), &symlink->obj, req->access, req->attributes ); + release_object( symlink ); + } + + if (root) + release_object( root ); +} + +/* query a symbolic link object */ +DECL_HANDLER(query_symlink) +{ + struct symlink *symlink; + + symlink = (struct symlink *)get_wine_handle_obj( get_current_w32process(), req->handle, + SYMBOLIC_LINK_QUERY, &symlink_ops ); + if (!symlink) + return; + + if (get_reply_max_size() < symlink->len) + set_error( STATUS_BUFFER_TOO_SMALL ); + else + set_reply_data( symlink->target, symlink->len ); + release_object( symlink ); +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/include/apc.h b/unifiedkernel/include/apc.h new file mode 100644 index 0000000..6e1c5ec --- /dev/null +++ b/unifiedkernel/include/apc.h @@ -0,0 +1,154 @@ +/* + * apc.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * apc.h: + * Refered to ReactOS code + */ + +#ifndef _APC_H +#define _APC_H + +#include +#include +#include +#include +#include "ntstatus.h" +#include "win32.h" +#include "thread.h" +#include "process.h" +#include "ke.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#ifndef IO_NO_INCREMENT +#define IO_NO_INCREMENT 0 +#endif + +#define SystemDllApcDispatcher NULL /* No Used ? */ +#define ARGUMENT_PRESENT(ArgumentPointer) /* No Used ? */ \ + ((BOOLEAN) ((PVOID)ArgumentPointer != (PVOID)NULL)) /* No Used ? */ + +#define PKKERNEL_ROUTINE kernel_routine_t +#define PKRUNDOWN_ROUTINE rundown_routine_t +#define PKNORMAL_ROUTINE normal_routine_t +#define KPROCESSOR_MODE kprocessor_mode_t + +/* Values for contextflags */ +#define CONTEXT_i386 0x10000 +#define CONTEXT_CONTROL (CONTEXT_i386 | 1) +#define CONTEXT_INTEGER (CONTEXT_i386 | 2) +#define CONTEXT_SEGMENTS (CONTEXT_i386 | 4) +#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 8) +#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x10) +#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x20) +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS) + +#define MAXIMUM_SUPPORTED_EXTENSION 512 + +typedef struct pt_regs *PKTRAP_FRAME; +typedef struct kapc KAPC, *PKAPC; + +typedef enum _KAPC_ENVIRONMENT +{ + OriginalApcEnvironment, + AttachedApcEnvironment, + CurrentApcEnvironment +} KAPC_ENVIRONMENT; + +typedef struct _FXSAVE_FORMAT{ +}FXSAVE_FORMAT,*PFXSAVE_FORMAT; + +typedef struct _FNSAVE_FORMAT{ +}FNSAVE_FORMAT,*PFNSAVE_FORMAT; + +typedef struct _FX_SAVE_AREA { + union { + FNSAVE_FORMAT FnArea; + FXSAVE_FORMAT FxArea; + } U; + ULONG NpxSavedCpu; + ULONG Cr0NpxState; +} FX_SAVE_AREA, *PFX_SAVE_AREA; + +VOID +STDCALL +free_apc_routine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2); +BOOLEAN +STDCALL +__insert_queue_apc(PKAPC Apc, + KPRIORITY PriorityBoost); + +VOID +STDCALL +apc_init(IN PKAPC Apc, + IN struct kthread* Thread, + IN KAPC_ENVIRONMENT TargetEnvironment, + IN PKKERNEL_ROUTINE KernelRoutine, + IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, + IN PKNORMAL_ROUTINE NormalRoutine, + IN KPROCESSOR_MODE Mode, + IN PVOID Context); + +BOOLEAN +STDCALL +insert_queue_apc(PKAPC Apc, + PVOID SystemArgument1, + PVOID SystemArgument2, + KPRIORITY PriorityBoost); + +VOID +STDCALL +deliver_apc(KPROCESSOR_MODE DeliveryMode, + PVOID Reserved, + struct pt_regs * TrapFrame); + +BOOLEAN +STDCALL +test_alert_thread(IN KPROCESSOR_MODE AlertMode); + +VOID +STDCALL +init_user_apc(IN PVOID Reserved, + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) ; + +VOID +KeContextToTrapFrame(PContext Context, + PKTRAP_FRAME TrapFrame); + +VOID STDCALL +thread_special_apc(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _APC_H */ diff --git a/unifiedkernel/include/area.h b/unifiedkernel/include/area.h new file mode 100644 index 0000000..fad5c1a --- /dev/null +++ b/unifiedkernel/include/area.h @@ -0,0 +1,168 @@ +/* + * area.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jun 2008 - Created. + */ + +/* + * area.h: + * win32 area + */ + +#ifndef _AREA_H +#define _AREA_H + +#include "win32.h" +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +struct win32_area_struct { + struct list_head wa_list; + unsigned long start; + unsigned long end; + unsigned long prot; + void *section_object; +}; + +static inline void insert_win32_area(struct list_head *head, unsigned long start, + unsigned long end, unsigned long prot, void *object) +{ + struct list_head *pos; + struct win32_area_struct *wa; + + if (list_empty(head)) { + pos = head; + goto ready; + } + + list_for_each(pos, head) { + wa = list_entry(pos, struct win32_area_struct, wa_list); + if (wa->start >= end) + break; + } + +ready: + wa = kmalloc(sizeof(struct win32_area_struct), GFP_KERNEL); + wa->start = start; + wa->end = end; + wa->prot = prot; + if (object) + ref_object(object); + wa->section_object = object; + list_add_tail(&wa->wa_list, pos); +} + +static inline struct win32_area_struct *find_win32_area( + struct list_head *head, unsigned long start, unsigned long end) +{ + struct list_head *pos; + struct win32_area_struct *wa; + + if (list_empty(head)) + return NULL; + + list_for_each(pos, head) { + wa = list_entry(pos, struct win32_area_struct, wa_list); + if (wa->start <= start && wa->end >= end && wa->end > start) + return wa; + } + + return NULL; +} + +static inline void remove_win32_area(struct win32_area_struct *wa) +{ + list_del(&wa->wa_list); + if (wa->section_object) + deref_object(wa->section_object); + kfree(wa); +} + +static inline void remove_all_win32_area(struct list_head *head) +{ + struct list_head *pos = head->next; + struct win32_area_struct *wa; + + while (pos != head) { + wa = list_entry(pos, struct win32_area_struct, wa_list); + remove_win32_area(wa); + pos = head->next; + } +} + +static inline void insert_reserved_area(struct eprocess *process, + unsigned long start, unsigned long end, unsigned long prot) +{ + insert_win32_area(&process->ep_reserved_head, start, end, prot, NULL); +} + +static inline void insert_mapped_area(struct eprocess *process, + unsigned long start, unsigned long end, unsigned long prot, void *object) +{ + insert_win32_area(&process->ep_mapped_head, start, end, prot, object); +} + +static inline struct win32_area_struct *find_reserved_area( + struct eprocess *process, unsigned long start, unsigned long end) +{ + return find_win32_area(&process->ep_reserved_head, start, end); +} + +static inline struct win32_area_struct *find_mapped_area( + struct eprocess *process, unsigned long start, unsigned long end) +{ + return find_win32_area(&process->ep_mapped_head, start, end); +} + +/* address NOT in any reserved area and mapped area */ +static inline size_t get_free_area_size(struct eprocess *process, unsigned long address) +{ + struct list_head *pos, *head; + struct win32_area_struct *wa, *prev_wa = NULL; + int ntry = 0; + + head = &process->ep_reserved_head; + +retry: + if (list_empty(head)) + return 0; + + list_for_each(pos, head) { + wa = list_entry(pos, struct win32_area_struct, wa_list); + if (wa->start > address) + return prev_wa ? (wa->start - prev_wa->end) : wa->start; + prev_wa = wa; + } + + if (!ntry) { + head = &process->ep_mapped_head; + prev_wa = NULL; + ntry++; + goto retry; + } + + return 0; +} + +#endif /* CONFIG_UNIFIED_KERNEL */ + +#endif /* _AREA_H */ + diff --git a/unifiedkernel/include/attach.h b/unifiedkernel/include/attach.h new file mode 100644 index 0000000..08e069c --- /dev/null +++ b/unifiedkernel/include/attach.h @@ -0,0 +1,54 @@ +/* + * attach.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * attach.h + * Refered to ReactOS code + */ + +#ifndef _ATTACH_H +#define _ATTACH_H + +#include "win32.h" +#include "process.h" +#include "thread.h" +#include "apc.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define MM_STACK_SIZE (3 * 4096) + +VOID STDCALL +update_page_dir(struct mm_struct *mm, PVOID Address, ULONG Size); + +VOID STDCALL +move_apc_state(struct kapc_state *OldState, struct kapc_state *NewState); + +struct mm_struct * +attach_process(struct kprocess *Process); + +VOID STDCALL +detach_process (struct mm_struct *mm); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _ATTACH_H */ + diff --git a/unifiedkernel/include/event.h b/unifiedkernel/include/event.h new file mode 100644 index 0000000..16bf891 --- /dev/null +++ b/unifiedkernel/include/event.h @@ -0,0 +1,85 @@ +/* + * event.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * event.h: win32 event definition + * Refered to Kernel-win32 code + */ + +#ifndef _EVENT_H +#define _EVENT_H + +#include +#include "win32.h" +#include "thread.h" +#include "process.h" +#include "objwait.h" +#include "apc.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* + * event object definition + */ +#define EVENT_QUERY_STATE (0x0001) +#define EVENT_MODIFY_STATE (0x0002) +#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3) + +#define EVENT_INCREMENT 1 + +VOID init_event_implement(VOID); + +NTSTATUS SERVICECALL NtCreateEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState); + +NTSTATUS SERVICECALL NtOpenEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +LONG STDCALL set_event(struct kevent *Event, + KPRIORITY Icrement, + BOOLEAN Wait); + +NTSTATUS SERVICECALL NtSetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState); + +LONG STDCALL reset_event(struct kevent *Event); + +NTSTATUS SERVICECALL NtResetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState); + +LONG STDCALL pulse_event(IN struct kevent *Event, + IN KPRIORITY Increment, + IN BOOLEAN Wait); + +NTSTATUS SERVICECALL NtPulseEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState); + +VOID STDCALL event_init(struct kevent *event, + enum event_type type, + BOOLEAN state); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif + diff --git a/unifiedkernel/include/file.h b/unifiedkernel/include/file.h new file mode 100644 index 0000000..72804e6 --- /dev/null +++ b/unifiedkernel/include/file.h @@ -0,0 +1,428 @@ +/* + * file.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * file.h: win32 file definition + * Refered to Kernel-win32 code + */ + +#ifndef _FILE_H +#define _FILE_H + +#include +#include +#include "win32.h" +#include "process.h" +#include "wineserver/file.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#define FILE_DEVICE_NAMED_PIPE 0x00000011 +#define FILE_ANY_ACCESS 0 +#define METHOD_BUFFERED 0 + +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + (DWORD)((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ + ) + +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 + +#define FILE_FLAG_WRITE_THROUGH 0x80000000 +#define FILE_FLAG_OVERLAPPED 0x40000000 +#define FILE_FLAG_NO_BUFFERING 0x20000000 +#define FILE_FLAG_RANDOM_ACCESS 0x10000000 +#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000 +#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000 +#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000 +#define FILE_FLAG_POSIX_SEMANTICS 0x01000000 +#define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000 +#define FILE_FLAG_OPEN_NO_RECALL 0x00100000 + +#define FILE_ATTRIBUTE_READONLY 0x00000001L +#define FILE_ATTRIBUTE_HIDDEN 0x00000002L +#define FILE_ATTRIBUTE_SYSTEM 0x00000004L +#define FILE_ATTRIBUTE_LABEL 0x00000008L /* Not in Windows API */ +#define FILE_ATTRIBUTE_DIRECTORY 0x00000010L +#define FILE_ATTRIBUTE_ARCHIVE 0x00000020L +#define FILE_ATTRIBUTE_NORMAL 0x00000080L +#define FILE_ATTRIBUTE_TEMPORARY 0x00000100L +#define FILE_ATTRIBUTE_ATOMIC_WRITE 0x00000200L +#define FILE_ATTRIBUTE_XACTION_WRITE 0x00000400L +#define FILE_ATTRIBUTE_COMPRESSED 0x00000800L +#define FILE_ATTRIBUTE_OFFLINE 0x00001000L + +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 + +#define GENERIC_READ 0x80000000L +#define GENERIC_WRITE 0x40000000L +#define GENERIC_EXECUTE 0x20000000L +#define GENERIC_ALL 0x10000000L + +#define FILE_SHARE_READ 0x00000001 +#define FILE_SHARE_WRITE 0x00000002 +#define FILE_SHARE_DELETE 0x00000004 + +struct file_args { + IN ACCESS_MASK DesiredAccess; + IN POBJECT_ATTRIBUTES ObjectAttributes; + OUT PIO_STATUS_BLOCK IoStatusBlock; + IN PLARGE_INTEGER AllocationSize OPTIONAL; + IN ULONG FileAttributes; + IN ULONG ShareAccess; + IN ULONG CreateDisposition; + IN ULONG CreateOptions; + IN PVOID EaBuffer OPTIONAL; + IN ULONG EaLength; +}; + +typedef struct win32_file_ctrl win32_file_ctrl; + +/* + * process-access file object definition + */ +struct win32_file { + CSHORT Type; + CSHORT Size; + PVOID DeviceObject; + /* PDEVICE_OBJECT DeviceObject; */ + PVOID Vpb; + /* PVPB Vpb; */ + PVOID FsContext; + PVOID FsContext2; + PVOID SectionObjectPointer; + /* PSECTION_OBJECT_POINTERS SectionObjectPointer; */ + PVOID PrivateCacheMap; + NTSTATUS FinalStatus; + struct win32_file *RelatedFileObject; + BOOLEAN LockOperation; + BOOLEAN DeletePending; + BOOLEAN ReadAccess; + BOOLEAN WriteAccess; + BOOLEAN DeleteAccess; + BOOLEAN SharedRead; + BOOLEAN SharedWrite; + BOOLEAN SharedDelete; + ULONG Flags; + UNICODE_STRING FileName; + LARGE_INTEGER CurrentByteOffset; + ULONG Waiters; + ULONG Busy; + PVOID LastLock; + struct kevent Lock; + struct kevent Event; + PVOID CompletionContext; + /* PIO_COMPLETION_CONTEXT CompletionContext; */ + + struct list_head wf_ctllist; /* file control list next */ + win32_file_ctrl *wf_control; /* the file control object */ + + int wf_fd; + int wf_doc; /* delete on close, no longer needed, into Flags */ + char wf_unlink_name[MAX_PATH]; + + /* wf_file is considered deprecated, don't use it + * use wf_fd instead + * */ + struct file *wf_file; /* the Linux file */ + __u32 wf_access; /* file access mode */ + __u32 wf_sharing; /* sharing mode */ + __u32 wf_attrs; /* file open attributes */ +}; + +/* + * file-control object definition + * - links together win32_file objects that use the same file + */ +struct win32_file_ctrl { + struct list_head wfc_accessors; /* who's accessing this file */ + spinlock_t wfc_lock; /* govern access to list */ +}; + + +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 +#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 +#define FILE_NOTIFY_CHANGE_NAME 0x00000003 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 +#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 +#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 +#define FILE_NOTIFY_CHANGE_EA 0x00000080 +#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 +#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 +#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 +#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 +#define FILE_NOTIFY_VALID_MASK 0x00000fff +#define FILE_NOTIFY_ALL (FILE_NOTIFY_VALID_MASK) + +typedef struct _FILE_NOTIFY_INFORMATION { + DWORD NextEntryOffset; + DWORD Action; + DWORD FileNameLength; + WCHAR FileName[1]; +} FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION; + + +NTSTATUS +SERVICECALL +NtCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength); + +NTSTATUS +SERVICECALL +NtOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions + ); + +NTSTATUS +SERVICECALL +NtReadFile(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */ + IN PULONG Key OPTIONAL); + +NTSTATUS +SERVICECALL +NtWriteFile (IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */ + IN PULONG Key OPTIONAL); + +NTSTATUS SERVICECALL +NtSetInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +NTSTATUS SERVICECALL +NtQueryInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +NTSTATUS SERVICECALL +NtFlushBuffersFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock); + +NTSTATUS +SERVICECALL +NtFsControlFile( + IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferSize); + + +#define FSCTL_REQUEST_OPLOCK_LEVEL_1 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_OPLOCK_LEVEL_2 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_BATCH_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 3, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPBATCH_ACK_CLOSE_PENDING CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_NOTIFY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 5, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* decommissioned fsctl value 9 */ +#define FSCTL_IS_VOLUME_MOUNTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_IS_PATHNAME_VALID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_MARK_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* decommissioned fsctl value 13 */ +#define FSCTL_QUERY_RETRIEVAL_POINTERS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_GET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, \ + FILE_READ_DATA | FILE_WRITE_DATA) +/* decommissioned fsctl value 17 */ +/* decommissioned fsctl value 18 */ +#define FSCTL_MARK_AS_SYSTEM_HIVE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_OPLOCK_BREAK_ACK_NO_2 CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_INVALIDATE_VOLUMES CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_QUERY_FAT_BPB CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_REQUEST_FILTER_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_FILESYSTEM_GET_STATISTICS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* Start: _WIN32_WINNT >= 0x0400 */ +#define FSCTL_GET_NTFS_VOLUME_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_GET_NTFS_FILE_RECORD CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 26, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_GET_VOLUME_BITMAP CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_GET_RETRIEVAL_POINTERS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_MOVE_FILE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_IS_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_GET_HFS_INFORMATION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 31, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_ALLOW_EXTENDED_DASD_IO CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 32, METHOD_NEITHER, FILE_ANY_ACCESS) +/* End: _WIN32_WINNT >= 0x0400 */ + +/* Start: _WIN32_WINNT >= 0x0500 */ +#define FSCTL_READ_PROPERTY_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 33, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_WRITE_PROPERTY_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 34, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_FIND_FILES_BY_SID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 35, METHOD_NEITHER, FILE_ANY_ACCESS) +/* decommissioned fsctl value 36 */ +#define FSCTL_DUMP_PROPERTY_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 37, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_SET_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 38, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_GET_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DELETE_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 40, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_ENUM_USN_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 44, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_SECURITY_ID_CHECK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 45, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_READ_USN_JOURNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_SET_OBJECT_ID_EXTENDED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 47, METHOD_BUFFERED, FILE_WRITE_DATA +#define FSCTL_CREATE_OR_GET_OBJECT_ID CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_SET_ZERO_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_QUERY_ALLOCATED_RANGES CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_ENABLE_UPGRADE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 52, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_SET_ENCRYPTION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 53, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_ENCRYPTION_FSCTL_IO CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 54, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_WRITE_RAW_ENCRYPTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 55, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_READ_RAW_ENCRYPTED CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 56, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSCTL_CREATE_USN_JOURNAL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 57, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_READ_FILE_USN_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 58, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_WRITE_USN_CLOSE_RECORD CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 59, METHOD_NEITHER, FILE_READ_DATA) +#define FSCTL_EXTEND_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, FILE_ANY_ACCESS) +/* End: _WIN32_WINNT >= 0x0500 */ + +#define FSCTL_PIPE_ASSIGN_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_DISCONNECT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_PEEK CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_DATA) +#define FSCTL_PIPE_QUERY_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_TRANSCEIVE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER, \ + FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_PIPE_WAIT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_IMPERSONATE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_SET_CLIENT_PROCESS CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_QUERY_CLIENT_PROCESS CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_INTERNAL_READ CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2045, METHOD_BUFFERED, FILE_READ_DATA) +#define FSCTL_PIPE_INTERNAL_WRITE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2046, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_PIPE_INTERNAL_TRANSCEIVE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2047, METHOD_NEITHER, \ + FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_PIPE_INTERNAL_READ_OVFLOW CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2048, METHOD_BUFFERED, FILE_READ_DATA) + +#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE +#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_EJECTION_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_MCN_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_DISK_BASE FILE_DEVICE_DISK +#define IOCTL_DISK_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_DISK_BASE, 0x0000, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_GET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_PARTITION_INFO CTL_CODE(IOCTL_DISK_BASE, 0x0002, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_GET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_SET_DRIVE_LAYOUT CTL_CODE(IOCTL_DISK_BASE, 0x0004, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_REASSIGN_BLOCKS CTL_CODE(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_PERFORMANCE CTL_CODE(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_IS_WRITABLE CTL_CODE(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_LOGGING CTL_CODE(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_FORMAT_TRACKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_DISK_HISTOGRAM_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000c, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_DATA CTL_CODE(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_HISTOGRAM_RESET CTL_CODE(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_STRUCTURE CTL_CODE(IOCTL_DISK_BASE, 0x000f, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_REQUEST_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_DISK_CHECK_VERIFY CTL_CODE(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_MEDIA_REMOVAL CTL_CODE(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_EJECT_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_LOAD_MEDIA CTL_CODE(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RESERVE CTL_CODE(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_RELEASE CTL_CODE(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_FIND_NEW_DEVICES CTL_CODE(IOCTL_DISK_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_DISK_GET_MEDIA_TYPES CTL_CODE(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +/* Start: For _WIN32_WINNT >= 0x0400 */ +#define IOCTL_DISK_CONTROLLER_NUMBER CTL_CODE(IOCTL_DISK_BASE, 0x0011, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define SMART_GET_VERSION CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) +#define SMART_SEND_DRIVE_COMMAND CTL_CODE(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define SMART_RCV_DRIVE_DATA CTL_CODE(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, \ + FILE_READ_ACCESS | FILE_WRITE_ACCESS) +/* End: For _WIN32_WINNT >= 0x0400 */ + +#define IOCTL_SERIAL_LSRMST_INSERT CTL_CODE(FILE_DEVICE_SERIAL_PORT,31,METHOD_BUFFERED,FILE_ANY_ACCESS) + +static inline int get_fd_from_fo (const struct win32_file *fo) +{ + return fo->wf_fd; +} + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _FILE_H */ diff --git a/unifiedkernel/include/handle.h b/unifiedkernel/include/handle.h new file mode 100644 index 0000000..52cc84a --- /dev/null +++ b/unifiedkernel/include/handle.h @@ -0,0 +1,205 @@ +/* + * handle.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * handle.h: win32 handle definition + * Refered to ReactOS code + */ +#ifndef _HANDLE_H +#define _HANDLE_H + +#include "win32.h" +#include "object.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +#define UNICODE_NULL L'\0' +#define UNICODE_PATH_SEP L'\\' +#define UNICODE_NO_PATH L"..." + +#define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1)) +#define EX_HANDLE_ENTRY_PROTECTFROMCLOSE (1 << 0) +#define EX_HANDLE_ENTRY_INHERITABLE (1 << 1) +#define EX_HANDLE_ENTRY_AUDITONCLOSE (1 << 2) +#define EX_HANDLE_TABLE_CLOSING 0x1 +#define EX_INVALID_HANDLE (~0) +#define EX_HANDLE_ENTRY_FLAGSMASK (EX_HANDLE_ENTRY_LOCKED | \ + EX_HANDLE_ENTRY_PROTECTFROMCLOSE | \ + EX_HANDLE_ENTRY_INHERITABLE | \ + EX_HANDLE_ENTRY_AUDITONCLOSE) + +#define N_TLI_BITS 8 /* top level index */ +#define N_MLI_BITS 10 /* middle level index */ +#define N_EI_BITS 9 /* sub handle index */ +#define TLI_OFFSET (N_MLI_BITS + N_EI_BITS) +#define MLI_OFFSET N_EI_BITS +#define EI_OFFSET 0 + +#define N_TOPLEVEL_POINTERS (1 << N_TLI_BITS) +#define N_MIDDLELEVEL_POINTERS (1 << N_MLI_BITS) +#define N_SUBHANDLE_ENTRIES (1 << N_EI_BITS) +#define EX_MAX_HANDLES (N_TOPLEVEL_POINTERS * N_MIDDLELEVEL_POINTERS * N_SUBHANDLE_ENTRIES) + +#define VALID_HANDLE_MASK (((N_TOPLEVEL_POINTERS - 1) << TLI_OFFSET) | \ + ((N_MIDDLELEVEL_POINTERS - 1) << MLI_OFFSET) | ((N_SUBHANDLE_ENTRIES - 1) << EI_OFFSET)) +#define TLI_FROM_HANDLE(index) (ULONG)(((index) >> TLI_OFFSET) & (N_TOPLEVEL_POINTERS - 1)) +#define MLI_FROM_HANDLE(index) (ULONG)(((index) >> MLI_OFFSET) & (N_MIDDLELEVEL_POINTERS - 1)) +#define ELI_FROM_HANDLE(index) (ULONG)(((index) >> EI_OFFSET) & (N_SUBHANDLE_ENTRIES - 1)) + +#define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->u1.object) & \ + ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \ + EX_HANDLE_ENTRY_AUDITONCLOSE))) +#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \ + ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \ + EX_HANDLE_ENTRY_AUDITONCLOSE))) + +#define BUILD_HANDLE(tli, mli, eli) ((((tli) & (N_TOPLEVEL_POINTERS - 1)) << TLI_OFFSET) | \ + (((mli) & (N_MIDDLELEVEL_POINTERS - 1)) << MLI_OFFSET) | \ + (((eli) & (N_SUBHANDLE_ENTRIES - 1)) << EI_OFFSET)) + +#define IS_INVALID_EX_HANDLE(index) (((index) & ~VALID_HANDLE_MASK) != 0) +#define IS_VALID_EX_HANDLE(index) (((index) & ~VALID_HANDLE_MASK) == 0) + +#define KERNEL_HANDLE_FLAG (1 << ((sizeof(HANDLE) * 8) - 1)) +#define is_kernel_handle(Handle, ProcessorMode) \ + (((ULONG_PTR)(Handle) & KERNEL_HANDLE_FLAG) && ((ProcessorMode) == KernelMode)) +#define KERNEL_HANDLE_TO_HANDLE(Handle) \ + (HANDLE)((ULONG_PTR)(Handle) & ~KERNEL_HANDLE_FLAG) +#define HANDLE_TO_KERNEL_HANDLE(Handle) \ + (HANDLE)((ULONG_PTR)(Handle) | KERNEL_HANDLE_FLAG) + +#define UK_HANDLE /* temporary definition for coexistence of unified kernel handles and wine handles */ +#ifdef UK_HANDLE +/* + * if the handle value greater than (1<<15), it will fault when someone + * call it + */ +#define UK_HANDLE_FLAG (1 << 15) +#define HANDLE_TO_UK_HANDLE(handle) \ + (HANDLE)((ULONG_PTR)(handle) | UK_HANDLE_FLAG) +#define UK_HANDLE_TO_HANDLE(handle) \ + (HANDLE)((ULONG_PTR)(handle) & ~UK_HANDLE_FLAG) + +#define IS_UK_HANDLE(handle) \ + ((ULONG_PTR)(handle) & UK_HANDLE_FLAG) +#endif + +extern struct handle_table *cid_table; + +typedef VOID (STDCALL PEX_DESTROY_HANDLE_CALLBACK)( + struct handle_table *HandleTable, + PVOID Object, + ULONG GrantedAccess, + PVOID Context); + +typedef BOOLEAN (STDCALL PEX_DUPLICATE_HANDLE_CALLBACK)( + struct handle_table *HandleTable, + struct handle_table_entry *HandleTableEntry, + PVOID Context); + +VOID STDCALL +map_generic_mask(PACCESS_MASK AccessMask, + PGENERIC_MAPPING GenericMapping); + +NTSTATUS STDCALL +init_resource(struct eresource *Resource); + +NTSTATUS STDCALL +delete_resource(struct eresource *Resource); + +VOID +init_handle_tables(VOID); + +BOOLEAN +lock_handle_table_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry); + +VOID +unlock_handle_table_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry); + +struct handle_table * +__create_handle_table(IN struct eprocess *QuotaProcess OPTIONAL); + +struct handle_table * +dup_handle_table(IN struct eprocess *QuotaProcess OPTIONAL, + IN PEX_DUPLICATE_HANDLE_CALLBACK dup_handle_callback OPTIONAL, + IN PVOID Context OPTIONAL, + IN struct handle_table *SourceHandleTable); + +VOID +create_handle_table(struct eprocess *Parent, + BOOLEAN Inherit, + struct eprocess *Process); + +struct handle_table_entry * +alloc_handle_table_entry(IN struct handle_table *HandleTable, + OUT PLONG Handle); + +LONG +create_ex_handle(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry); + +NTSTATUS +create_handle(struct eprocess *Process, + PVOID ObjectBody, + ACCESS_MASK GrantedAccess, + BOOLEAN Inherit, + PHANDLE HandleReturn); + +struct handle_table_entry * +lookup_handle_table_entry(IN struct handle_table *HandleTable, + IN LONG Handle); + +struct handle_table_entry * +map_handle_to_pointer(IN struct handle_table *HandleTable, + IN LONG Handle); + +VOID +decrement_handle_count(PVOID ObjectBody); + +VOID +free_handle_table_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry, + IN LONG Handle); + +VOID +destroy_handle_by_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry, + IN LONG Handle); + +NTSTATUS +delete_handle(struct handle_table *HandleTable, + HANDLE Handle); + +BOOLEAN +destroy_handle(IN struct handle_table *HandleTable, + IN LONG Handle); + +VOID +__destroy_handle_table(IN struct handle_table *HandleTable, + IN PEX_DESTROY_HANDLE_CALLBACK DestroyHandleCallback OPTIONAL, + IN PVOID Context OPTIONAL); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _HANDLE_H */ diff --git a/unifiedkernel/include/io.h b/unifiedkernel/include/io.h new file mode 100644 index 0000000..f3ef65a --- /dev/null +++ b/unifiedkernel/include/io.h @@ -0,0 +1,1304 @@ +/* + * io.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * io.h: + * Refered to ReactOS code + */ +#ifndef _IO_H +#define _IO_H + +#include "win32.h" +#include "object.h" +#include "virtual.h" +#include "ke.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define MAXIMUM_VOLUME_LABEL_LENGTH (32 * sizeof(WCHAR)) +#define DEVICE_TYPE ULONG +#define RESTRICTED_POINTER +#define DUMMYSTRUCTNAME +#define DUMMYUNIONNAME +#define POINTER_ALIGNMENT +#define IRP_MJ_MAXIMUM_FUNCTION 0x1b +#define INITIAL_PRIVILEGE_COUNT 3 + +struct _IRP; +struct _DEVICE_OBJECT; +struct _DRIVER_OBJECT; + +typedef UCHAR KIRQL, *PKIRQL; + +typedef enum _DEVICE_POWER_STATE { + PowerDeviceUnspecified, + PowerDeviceD0, + PowerDeviceD1, + PowerDeviceD2, + PowerDeviceD3, + PowerDeviceMaximum +} DEVICE_POWER_STATE, *PDEVICE_POWER_STATE; + +typedef struct _SID_IDENTIFIER_AUTHORITY { + BYTE Value[6]; +} SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY,*LPSID_IDENTIFIER_AUTHORITY; + +typedef struct _SID { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[ANYSIZE_ARRAY]; +} SID, *PISID; + +typedef struct _PO_DEVICE_NOTIFY +{ + LIST_ENTRY Link; + struct _DEVICE_OBJECT* TargetDevice; + UCHAR WakeNeeded; + UCHAR OrderLevel; + struct _DEVICE_OBJECT* DeviceObject; + PVOID Node; + PUSHORT DeviceName; + PUSHORT DriverName; + ULONG ChildCount; + ULONG ActiveChild; +} PO_DEVICE_NOTIFY, *PPO_DEVICE_NOTIFY; + +typedef struct _DEVICE_RELATIONS { + ULONG Count; + struct _DEVICE_OBJECT* Objects[1]; +} DEVICE_RELATIONS, *PDEVICE_RELATIONS; + +typedef enum _PNP_DEVNODE_STATE +{ + DeviceNodeUnspecified = 0x300, + DeviceNodeUninitialized = 0x301, + DeviceNodeInitialized = 0x302, + DeviceNodeDriversAdded = 0x303, + DeviceNodeResourcesAssigned = 0x304, + DeviceNodeStartPending = 0x305, + DeviceNodeStartCompletion = 0x306, + DeviceNodeStartPostWork = 0x307, + DeviceNodeStarted = 0x308, + DeviceNodeQueryStopped = 0x309, + DeviceNodeStopped = 0x30a, + DeviceNodeRestartCompletion = 0x30b, + DeviceNodeEnumeratePending = 0x30c, + DeviceNodeEnumerateCompletion = 0x30d, + DeviceNodeAwaitingQueuedDeletion = 0x30e, + DeviceNodeAwaitingQueuedRemoval = 0x30f, + DeviceNodeQueryRemoved = 0x310, + DeviceNodeRemovePendingCloses = 0x311, + DeviceNodeRemoved = 0x312, + DeviceNodeDeletePendingCloses = 0x313, + DeviceNodeDeleted = 0x314, + MaxDeviceNodeState = 0x315, +} PNP_DEVNODE_STATE; + +typedef enum _INTERFACE_TYPE { + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + MaximumInterfaceType +} INTERFACE_TYPE, *PINTERFACE_TYPE; + +typedef struct _DEVICE_NODE +{ + /* A tree structure. */ + struct _DEVICE_NODE *Parent; + struct _DEVICE_NODE *PrevSibling; + struct _DEVICE_NODE *NextSibling; + struct _DEVICE_NODE *Child; + /* The level of deepness in the tree. */ + UINT Level; + PPO_DEVICE_NOTIFY Notify; + /* State machine. */ + PNP_DEVNODE_STATE State; + PNP_DEVNODE_STATE PreviousState; + PNP_DEVNODE_STATE StateHistory[20]; + UINT StateHistoryEntry; + /* ? */ + int CompletionStatus; + /* ? */ + struct _IRP * PendingIrp; + /* See DNF_* flags below (WinDBG documentation has WRONG values) */ + ULONG Flags; + /* See DNUF_* flags below (and IRP_MN_QUERY_PNP_DEVICE_STATE) */ + ULONG UserFlags; + /* See CM_PROB_* values are defined in cfg.h */ + ULONG Problem; + /* Pointer to the PDO corresponding to the device node. */ + struct _DEVICE_OBJECT* PhysicalDeviceObject; + /* Resource list as assigned by the PnP arbiter. See IRP_MN_START_DEVICE + and ARBITER_INTERFACE (not documented in DDK, but present in headers). */ + struct _CM_RESOURCE_LIST* ResourceList; + /* Resource list as assigned by the PnP arbiter (translated version). */ + struct _CM_RESOURCE_LIST* ResourceListTranslated; + /* Instance path relative to the Enum key in registry. */ + UNICODE_STRING InstancePath; + /* Name of the driver service. */ + UNICODE_STRING ServiceName; + /* ? */ + struct _DEVICE_OBJECT * DuplicatePDO; + /* See IRP_MN_QUERY_RESOURCE_REQUIREMENTS. */ + struct _IO_RESOURCE_REQUIREMENTS_LIST* ResourceRequirements; + /* Information about bus for bus drivers. */ + INTERFACE_TYPE InterfaceType; + ULONG BusNumber; + /* Information about underlying bus for child devices. */ + INTERFACE_TYPE ChildInterfaceType; + ULONG ChildBusNumber; + USHORT ChildBusTypeIndex; + /* ? */ + UCHAR RemovalPolicy; + UCHAR HardwareRemovalPolicy; + LIST_ENTRY TargetDeviceNotify; + LIST_ENTRY DeviceArbiterList; + LIST_ENTRY DeviceTranslatorList; + USHORT NoTranslatorMask; + USHORT QueryTranslatorMask; + USHORT NoArbiterMask; + USHORT QueryArbiterMask; + union + { + struct _DEVICE_NODE *LegacyDeviceNode; + PDEVICE_RELATIONS PendingDeviceRelations; + } OverUsed1; + union + { + struct _DEVICE_NODE *NextResourceDeviceNode; + } OverUsed2; + /* See IRP_MN_QUERY_RESOURCES/IRP_MN_FILTER_RESOURCES. */ + struct _CM_RESOURCE_LIST* BootResources; + /* See the bitfields in DEVICE_CAPABILITIES structure. */ + ULONG CapabilityFlags; + struct + { + ULONG DockStatus; + LIST_ENTRY ListEntry; + WCHAR *SerialNumber; + } DockInfo; + ULONG DisableableDepends; + LIST_ENTRY PendedSetInterfaceState; + LIST_ENTRY LegacyBusListEntry; + ULONG DriverUnloadRetryCount; + struct _DEVICE_NODE *PreviousParent; + ULONG DeletedChidren; + + /* FIXME: Not NT's */ + GUID BusTypeGuid; + ULONG Address; +} DEVICE_NODE, *PDEVICE_NODE; + +typedef struct _MAILSLOT_CREATE_PARAMETERS +{ + ULONG MailslotQuota; + ULONG MaximumMessageSize; + LARGE_INTEGER ReadTimeout; + BOOLEAN TimeoutSpecified; +} MAILSLOT_CREATE_PARAMETERS, *PMAILSLOT_CREATE_PARAMETERS; + +typedef struct _NAMED_PIPE_CREATE_PARAMETERS +{ + ULONG NamedPipeType; + ULONG ReadMode; + ULONG CompletionMode; + ULONG MaximumInstances; + ULONG InboundQuota; + ULONG OutboundQuota; + LARGE_INTEGER DefaultTimeout; + BOOLEAN TimeoutSpecified; +} NAMED_PIPE_CREATE_PARAMETERS, *PNAMED_PIPE_CREATE_PARAMETERS; + +typedef struct _SCSI_REQUEST_BLOCK { + USHORT Length; + UCHAR Function; + UCHAR SrbStatus; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR QueueTag; + UCHAR QueueAction; + UCHAR CdbLength; + UCHAR SenseInfoBufferLength; + ULONG SrbFlags; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + PVOID SenseInfoBuffer; + struct _SCSI_REQUEST_BLOCK *NextSrb; + PVOID OriginalRequest; + PVOID SrbExtension; + _ANONYMOUS_UNION union { + ULONG InternalStatus; + ULONG QueueSortKey; + } DUMMYUNIONNAME; +#if defined(_WIN64) + ULONG Reserved; +#endif + UCHAR Cdb[16]; +} SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK; + +typedef struct _DEVOBJ_EXTENSION +{ + CSHORT Type; + USHORT Size; + struct _DEVICE_OBJECT* DeviceObject; + ULONG PowerFlags; + struct DEVICE_OBJECT_POWER_EXTENSION *Dope; + ULONG ExtensionFlags; + struct _DEVICE_NODE *DeviceNode; + struct _DEVICE_OBJECT* AttachedTo; + LONG StartIoCount; + LONG StartIoKey; + ULONG StartIoFlags; + struct _VPB *Vpb; +} DEVOBJ_EXTENSION, *PDEVOBJ_EXTENSION; + +typedef enum _IO_ALLOCATION_ACTION { + KeepObject = 1, + DeallocateObject, + DeallocateObjectKeepRegisters +} IO_ALLOCATION_ACTION, *PIO_ALLOCATION_ACTION; + +typedef IO_ALLOCATION_ACTION +(DDKAPI *PDRIVER_CONTROL)( + IN struct _DEVICE_OBJECT *DeviceObject, + IN struct _IRP *Irp, + IN PVOID MapRegisterBase, + IN PVOID Context); + +typedef NTSTATUS +(DDKAPI *PDRIVER_ADD_DEVICE)( + IN struct _DRIVER_OBJECT *DriverObject, + IN struct _DEVICE_OBJECT *PhysicalDeviceObject); + +typedef NTSTATUS +(DDKAPI *PIO_COMPLETION_ROUTINE)( + IN struct _DEVICE_OBJECT *DeviceObject, + IN struct _IRP *Irp, + IN PVOID Context); + +typedef VOID +(DDKAPI *PDRIVER_CANCEL)( + IN struct _DEVICE_OBJECT *DeviceObject, + IN struct _IRP *Irp); + +typedef NTSTATUS +(DDKAPI *PDRIVER_DISPATCH)( + IN struct _DEVICE_OBJECT *DeviceObject, + IN struct _IRP *Irp); + +typedef NTSTATUS +(DDKAPI *PDRIVER_INITIALIZE)( + IN struct _DRIVER_OBJECT *DriverObject, + IN PUNICODE_STRING RegistryPath); + +typedef VOID +(DDKAPI *PIO_TIMER_ROUTINE)( + IN struct _DEVICE_OBJECT *DeviceObject, + IN PVOID Context); + +typedef struct _COMPRESSED_DATA_INFO { + USHORT CompressionFormatAndEngine; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved; + USHORT NumberOfChunks; + ULONG CompressedChunkSizes[ANYSIZE_ARRAY]; +} COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO; + +typedef VOID +(DDKAPI *PDRIVER_STARTIO)( + IN struct _DEVICE_OBJECT *DeviceObject, + IN struct _IRP *Irp); + +typedef VOID +(DDKAPI *PDRIVER_UNLOAD)( + IN struct _DRIVER_OBJECT *DriverObject); + +typedef VOID +(DDKAPI *PINTERFACE_REFERENCE)( + PVOID Context); + +typedef union _POWER_STATE { + SYSTEM_POWER_STATE SystemState; + DEVICE_POWER_STATE DeviceState; +} POWER_STATE, *PPOWER_STATE; + +typedef enum _POWER_STATE_TYPE { + SystemPowerState, + DevicePowerState +} POWER_STATE_TYPE, *PPOWER_STATE_TYPE; + +typedef VOID +(DDKAPI *PINTERFACE_DEREFERENCE)( + PVOID Context); + +typedef struct _DEVICE_CAPABILITIES { + USHORT Size; + USHORT Version; + ULONG DeviceD1 : 1; + ULONG DeviceD2 : 1; + ULONG LockSupported : 1; + ULONG EjectSupported : 1; + ULONG Removable : 1; + ULONG DockDevice : 1; + ULONG UniqueID : 1; + ULONG SilentInstall : 1; + ULONG RawDeviceOK : 1; + ULONG SurpriseRemovalOK : 1; + ULONG WakeFromD0 : 1; + ULONG WakeFromD1 : 1; + ULONG WakeFromD2 : 1; + ULONG WakeFromD3 : 1; + ULONG HardwareDisabled : 1; + ULONG NonDynamic : 1; + ULONG WarmEjectSupported : 1; + ULONG NoDisplayInUI : 1; + ULONG Reserved : 14; + ULONG Address; + ULONG UINumber; + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + SYSTEM_POWER_STATE SystemWake; + DEVICE_POWER_STATE DeviceWake; + ULONG D1Latency; + ULONG D2Latency; + ULONG D3Latency; +} DEVICE_CAPABILITIES, *PDEVICE_CAPABILITIES; + +typedef struct _INTERFACE { + USHORT Size; + USHORT Version; + PVOID Context; + PINTERFACE_REFERENCE InterfaceReference; + PINTERFACE_DEREFERENCE InterfaceDereference; +} INTERFACE, *PINTERFACE; + +typedef enum _BUS_QUERY_ID_TYPE { + BusQueryDeviceID, + BusQueryHardwareIDs, + BusQueryCompatibleIDs, + BusQueryInstanceID, + BusQueryDeviceSerialNumber +} BUS_QUERY_ID_TYPE, *PBUS_QUERY_ID_TYPE; + +typedef enum _DEVICE_TEXT_TYPE { + DeviceTextDescription, + DeviceTextLocationInformation +} DEVICE_TEXT_TYPE, *PDEVICE_TEXT_TYPE; + +typedef enum _DEVICE_USAGE_NOTIFICATION_TYPE { + DeviceUsageTypeUndefined, + DeviceUsageTypePaging, + DeviceUsageTypeHibernation, + DeviceUsageTypeDumpFile +} DEVICE_USAGE_NOTIFICATION_TYPE; + +typedef struct _POWER_SEQUENCE { + ULONG SequenceD1; + ULONG SequenceD2; + ULONG SequenceD3; +} POWER_SEQUENCE, *PPOWER_SEQUENCE; + +typedef struct _FILE_GET_QUOTA_INFORMATION { + ULONG NextEntryOffset; + ULONG SidLength; + SID Sid; +} FILE_GET_QUOTA_INFORMATION, *PFILE_GET_QUOTA_INFORMATION; + +typedef struct _KDEVICE_QUEUE { + CSHORT Type; + CSHORT Size; + LIST_ENTRY DeviceListHead; + spinlock_t Lock; + BOOLEAN Busy; +} KDEVICE_QUEUE, *PKDEVICE_QUEUE, *RESTRICTED_POINTER PRKDEVICE_QUEUE; + +typedef struct _KDEVICE_QUEUE_ENTRY { + LIST_ENTRY DeviceListEntry; + ULONG SortKey; + BOOLEAN Inserted; +} KDEVICE_QUEUE_ENTRY, *PKDEVICE_QUEUE_ENTRY, +*RESTRICTED_POINTER PRKDEVICE_QUEUE_ENTRY; + +typedef struct _WAIT_CONTEXT_BLOCK { + KDEVICE_QUEUE_ENTRY WaitQueueEntry; + PDRIVER_CONTROL DeviceRoutine; + PVOID DeviceContext; + ULONG NumberOfMapRegisters; + PVOID DeviceObject; + PVOID CurrentIrp; + struct kdpc* BufferChainingDpc; +} WAIT_CONTEXT_BLOCK, *PWAIT_CONTEXT_BLOCK; + +typedef struct _IRP { + CSHORT Type; + USHORT Size; + struct _MDL *MdlAddress; + ULONG Flags; + union { + struct _IRP *MasterIrp; + LONG IrpCount; + PVOID SystemBuffer; + } AssociatedIrp; + LIST_ENTRY ThreadListEntry; + IO_STATUS_BLOCK IoStatus; + KPROCESSOR_MODE RequestorMode; + BOOLEAN PendingReturned; + CHAR StackCount; + CHAR CurrentLocation; + BOOLEAN Cancel; + KIRQL CancelIrql; + CCHAR ApcEnvironment; + UCHAR AllocationFlags; + PIO_STATUS_BLOCK UserIosb; + struct kevent* UserEvent; + union { + struct { + PIO_APC_ROUTINE UserApcRoutine; + PVOID UserApcContext; + } AsynchronousParameters; + LARGE_INTEGER AllocationSize; + } Overlay; + PDRIVER_CANCEL CancelRoutine; + PVOID UserBuffer; + union { + struct { + _ANONYMOUS_UNION union { + KDEVICE_QUEUE_ENTRY DeviceQueueEntry; + _ANONYMOUS_STRUCT struct { + PVOID DriverContext[4]; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + struct ethread* Thread; + PCHAR AuxiliaryBuffer; + _ANONYMOUS_STRUCT struct { + LIST_ENTRY ListEntry; + _ANONYMOUS_UNION union { + struct _IO_STACK_LOCATION *CurrentStackLocation; + ULONG PacketType; + } DUMMYUNIONNAME; + } DUMMYSTRUCTNAME; + struct _FILE_OBJECT *OriginalFileObject; + } Overlay; + struct kapc Apc; + PVOID CompletionKey; + } Tail; +} IRP; +typedef struct _IRP *PIRP; + +typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR { + UCHAR Type; + UCHAR ShareDisposition; + USHORT Flags; + union { + struct { + PHYSICAL_ADDRESS Start; + ULONG Length; + } Generic; + struct { + PHYSICAL_ADDRESS Start; + ULONG Length; + } Port; + struct { + ULONG Level; + ULONG Vector; + ULONG Affinity; + } Interrupt; + struct { + PHYSICAL_ADDRESS Start; + ULONG Length; + } Memory; + struct { + ULONG Channel; + ULONG Port; + ULONG Reserved1; + } Dma; + struct { + ULONG Data[3]; + } DevicePrivate; + struct { + ULONG Start; + ULONG Length; + ULONG Reserved; + } BusNumber; + struct { + ULONG DataSize; + ULONG Reserved1; + ULONG Reserved2; + } DeviceSpecificData; + } u; +} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR; + +typedef struct _CM_PARTIAL_RESOURCE_LIST { + USHORT Version; + USHORT Revision; + ULONG Count; + CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]; +} CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST; + +typedef struct _CM_FULL_RESOURCE_DESCRIPTOR { + INTERFACE_TYPE InterfaceType; + ULONG BusNumber; + CM_PARTIAL_RESOURCE_LIST PartialResourceList; +} CM_FULL_RESOURCE_DESCRIPTOR, *PCM_FULL_RESOURCE_DESCRIPTOR; + +typedef struct _CM_RESOURCE_LIST { + ULONG Count; + CM_FULL_RESOURCE_DESCRIPTOR List[1]; +} CM_RESOURCE_LIST, *PCM_RESOURCE_LIST; + +typedef struct _IO_RESOURCE_DESCRIPTOR { + UCHAR Option; + UCHAR Type; + UCHAR ShareDisposition; + UCHAR Spare1; + USHORT Flags; + USHORT Spare2; + union { + struct { + ULONG Length; + ULONG Alignment; + PHYSICAL_ADDRESS MinimumAddress; + PHYSICAL_ADDRESS MaximumAddress; + } Port; + struct { + ULONG Length; + ULONG Alignment; + PHYSICAL_ADDRESS MinimumAddress; + PHYSICAL_ADDRESS MaximumAddress; + } Memory; + struct { + ULONG MinimumVector; + ULONG MaximumVector; + } Interrupt; + struct { + ULONG MinimumChannel; + ULONG MaximumChannel; + } Dma; + struct { + ULONG Length; + ULONG Alignment; + PHYSICAL_ADDRESS MinimumAddress; + PHYSICAL_ADDRESS MaximumAddress; + } Generic; + struct { + ULONG Data[3]; + } DevicePrivate; + struct { + ULONG Length; + ULONG MinBusNumber; + ULONG MaxBusNumber; + ULONG Reserved; + } BusNumber; + struct { + ULONG Priority; + ULONG Reserved1; + ULONG Reserved2; + } ConfigData; + } u; +} IO_RESOURCE_DESCRIPTOR, *PIO_RESOURCE_DESCRIPTOR; + +typedef struct _IO_RESOURCE_LIST { + USHORT Version; + USHORT Revision; + ULONG Count; + IO_RESOURCE_DESCRIPTOR Descriptors[1]; +} IO_RESOURCE_LIST, *PIO_RESOURCE_LIST; + +typedef struct _IO_RESOURCE_REQUIREMENTS_LIST { + ULONG ListSize; + INTERFACE_TYPE InterfaceType; + ULONG BusNumber; + ULONG SlotNumber; + ULONG Reserved[3]; + ULONG AlternativeLists; + IO_RESOURCE_LIST List[1]; +} IO_RESOURCE_REQUIREMENTS_LIST, *PIO_RESOURCE_REQUIREMENTS_LIST; + +typedef struct _VPB { + CSHORT Type; + CSHORT Size; + USHORT Flags; + USHORT VolumeLabelLength; + struct _DEVICE_OBJECT *DeviceObject; + struct _DEVICE_OBJECT *RealDevice; + ULONG SerialNumber; + ULONG ReferenceCount; + WCHAR VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH / sizeof(WCHAR)]; +} VPB, *PVPB; + +typedef struct _IO_TIMER +{ + USHORT Type; + USHORT TimerEnabled; + LIST_ENTRY IoTimerList; + PIO_TIMER_ROUTINE TimerRoutine; + PVOID Context; + struct _DEVICE_OBJECT* DeviceObject; +} IO_TIMER, *PIO_TIMER; + +typedef struct _DEVICE_OBJECT { + CSHORT Type; + USHORT Size; + LONG ReferenceCount; + struct _DRIVER_OBJECT *DriverObject; + struct _DEVICE_OBJECT *NextDevice; + struct _DEVICE_OBJECT *AttachedDevice; + struct _IRP *CurrentIrp; + PIO_TIMER Timer; + ULONG Flags; + ULONG Characteristics; + PVPB Vpb; + PVOID DeviceExtension; + DEVICE_TYPE DeviceType; + CCHAR StackSize; + union { + LIST_ENTRY ListEntry; + WAIT_CONTEXT_BLOCK Wcb; + } Queue; + ULONG AlignmentRequirement; + KDEVICE_QUEUE DeviceQueue; + struct kdpc Dpc; + ULONG ActiveThreadCount; + PSECURITY_DESCRIPTOR SecurityDescriptor; + struct kevent DeviceLock; + USHORT SectorSize; + USHORT Spare1; + struct _DEVOBJ_EXTENSION *DeviceObjectExtension; + PVOID Reserved; +} DEVICE_OBJECT, *PDEVICE_OBJECT; + +typedef enum _DEVICE_RELATION_TYPE { + BusRelations, + EjectionRelations, + PowerRelations, + RemovalRelations, + TargetDeviceRelation, + SingleBusRelations +} DEVICE_RELATION_TYPE, *PDEVICE_RELATION_TYPE; + +typedef struct _MDL { + struct _MDL *Next; + CSHORT Size; + CSHORT MdlFlags; + struct eprocess *Process; + PVOID MappedSystemVa; + PVOID StartVa; + ULONG ByteCount; + ULONG ByteOffset; +} MDL, *PMDL; + +typedef struct _DRIVER_EXTENSION { + struct _DRIVER_OBJECT *DriverObject; + PDRIVER_ADD_DEVICE AddDevice; + ULONG Count; + UNICODE_STRING ServiceKeyName; +} DRIVER_EXTENSION, *PDRIVER_EXTENSION; + +typedef BOOLEAN +(DDKAPI *PFAST_IO_CHECK_IF_POSSIBLE)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN BOOLEAN CheckForReadOperation, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_READ)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_WRITE)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_QUERY_BASIC_INFO)( + IN struct _FILE_OBJECT *FileObject, + IN BOOLEAN Wait, + OUT PFILE_BASIC_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_QUERY_STANDARD_INFO)( + IN struct _FILE_OBJECT *FileObject, + IN BOOLEAN Wait, + OUT PFILE_STANDARD_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_LOCK)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + struct eprocess* ProcessId, + ULONG Key, + BOOLEAN FailImmediately, + BOOLEAN ExclusiveLock, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_UNLOCK_SINGLE)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + struct eprocess* ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_UNLOCK_ALL)( + IN struct _FILE_OBJECT *FileObject, + struct eprocess* ProcessId, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_UNLOCK_ALL_BY_KEY)( + IN struct _FILE_OBJECT *FileObject, + struct eprocess* ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_DEVICE_CONTROL)( + IN struct _FILE_OBJECT *FileObject, + IN BOOLEAN Wait, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength, + IN ULONG IoControlCode, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef VOID +(DDKAPI *PFAST_IO_ACQUIRE_FILE)( + IN struct _FILE_OBJECT *FileObject); + +typedef VOID +(DDKAPI *PFAST_IO_RELEASE_FILE)( + IN struct _FILE_OBJECT *FileObject); + +typedef VOID +(DDKAPI *PFAST_IO_DETACH_DEVICE)( + IN struct _DEVICE_OBJECT *SourceDevice, + IN struct _DEVICE_OBJECT *TargetDevice); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_QUERY_NETWORK_OPEN_INFO)( + IN struct _FILE_OBJECT *FileObject, + IN BOOLEAN Wait, + OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer, + OUT struct _IO_STATUS_BLOCK *IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef NTSTATUS +(DDKAPI *PFAST_IO_ACQUIRE_FOR_MOD_WRITE)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT struct eresource **ResourceToRelease, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_MDL_READ)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_MDL_READ_COMPLETE)( + IN struct _FILE_OBJECT *FileObject, + IN PMDL MdlChain, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_PREPARE_MDL_WRITE)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_MDL_WRITE_COMPLETE)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_READ_COMPRESSED)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo, + IN ULONG CompressedDataInfoLength, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_WRITE_COMPRESSED)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo, + IN ULONG CompressedDataInfoLength, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_MDL_READ_COMPLETE_COMPRESSED)( + IN struct _FILE_OBJECT *FileObject, + IN PMDL MdlChain, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_MDL_WRITE_COMPLETE_COMPRESSED)( + IN struct _FILE_OBJECT *FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef BOOLEAN +(DDKAPI *PFAST_IO_QUERY_OPEN)( + IN struct _IRP *Irp, + OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef NTSTATUS +(DDKAPI *PFAST_IO_RELEASE_FOR_MOD_WRITE)( + IN struct _FILE_OBJECT *FileObject, + IN struct eresource *ResourceToRelease, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef NTSTATUS +(DDKAPI *PFAST_IO_ACQUIRE_FOR_CCFLUSH)( + IN struct _FILE_OBJECT *FileObject, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef NTSTATUS +(DDKAPI *PFAST_IO_RELEASE_FOR_CCFLUSH) ( + IN struct _FILE_OBJECT *FileObject, + IN struct _DEVICE_OBJECT *DeviceObject); + +typedef struct _FAST_IO_DISPATCH { + ULONG SizeOfFastIoDispatch; + PFAST_IO_CHECK_IF_POSSIBLE FastIoCheckIfPossible; + PFAST_IO_READ FastIoRead; + PFAST_IO_WRITE FastIoWrite; + PFAST_IO_QUERY_BASIC_INFO FastIoQueryBasicInfo; + PFAST_IO_QUERY_STANDARD_INFO FastIoQueryStandardInfo; + PFAST_IO_LOCK FastIoLock; + PFAST_IO_UNLOCK_SINGLE FastIoUnlockSingle; + PFAST_IO_UNLOCK_ALL FastIoUnlockAll; + PFAST_IO_UNLOCK_ALL_BY_KEY FastIoUnlockAllByKey; + PFAST_IO_DEVICE_CONTROL FastIoDeviceControl; + PFAST_IO_ACQUIRE_FILE AcquireFileForNtCreateSection; + PFAST_IO_RELEASE_FILE ReleaseFileForNtCreateSection; + PFAST_IO_DETACH_DEVICE FastIoDetachDevice; + PFAST_IO_QUERY_NETWORK_OPEN_INFO FastIoQueryNetworkOpenInfo; + PFAST_IO_ACQUIRE_FOR_MOD_WRITE AcquireForModWrite; + PFAST_IO_MDL_READ MdlRead; + PFAST_IO_MDL_READ_COMPLETE MdlReadComplete; + PFAST_IO_PREPARE_MDL_WRITE PrepareMdlWrite; + PFAST_IO_MDL_WRITE_COMPLETE MdlWriteComplete; + PFAST_IO_READ_COMPRESSED FastIoReadCompressed; + PFAST_IO_WRITE_COMPRESSED FastIoWriteCompressed; + PFAST_IO_MDL_READ_COMPLETE_COMPRESSED MdlReadCompleteCompressed; + PFAST_IO_MDL_WRITE_COMPLETE_COMPRESSED MdlWriteCompleteCompressed; + PFAST_IO_QUERY_OPEN FastIoQueryOpen; + PFAST_IO_RELEASE_FOR_MOD_WRITE ReleaseForModWrite; + PFAST_IO_ACQUIRE_FOR_CCFLUSH AcquireForCcFlush; + PFAST_IO_RELEASE_FOR_CCFLUSH ReleaseForCcFlush; +} FAST_IO_DISPATCH, *PFAST_IO_DISPATCH; + +typedef struct _DRIVER_OBJECT { + CSHORT Type; + CSHORT Size; + PDEVICE_OBJECT DeviceObject; + ULONG Flags; + PVOID DriverStart; + ULONG DriverSize; + PVOID DriverSection; + PDRIVER_EXTENSION DriverExtension; + UNICODE_STRING DriverName; + PUNICODE_STRING HardwareDatabase; + PFAST_IO_DISPATCH FastIoDispatch; + PDRIVER_INITIALIZE DriverInit; + PDRIVER_STARTIO DriverStartIo; + PDRIVER_UNLOAD DriverUnload; + PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; +} DRIVER_OBJECT; + +typedef struct _SECTION_OBJECT_POINTERS { + PVOID DataSectionObject; + PVOID SharedCacheMap; + PVOID ImageSectionObject; +} SECTION_OBJECT_POINTERS, *PSECTION_OBJECT_POINTERS; + +typedef struct _IO_COMPLETION_CONTEXT { + PVOID Port; + PVOID Key; +} IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT; + +typedef struct _FILE_OBJECT { + CSHORT Type; + CSHORT Size; + PDEVICE_OBJECT DeviceObject; + PVPB Vpb; + PVOID FsContext; + PVOID FsContext2; + PSECTION_OBJECT_POINTERS SectionObjectPointer; + PVOID PrivateCacheMap; + NTSTATUS FinalStatus; + struct _FILE_OBJECT *RelatedFileObject; + BOOLEAN LockOperation; + BOOLEAN DeletePending; + BOOLEAN ReadAccess; + BOOLEAN WriteAccess; + BOOLEAN DeleteAccess; + BOOLEAN SharedRead; + BOOLEAN SharedWrite; + BOOLEAN SharedDelete; + ULONG Flags; + UNICODE_STRING FileName; + LARGE_INTEGER CurrentByteOffset; + ULONG Waiters; + ULONG Busy; + PVOID LastLock; + struct kevent Lock; + struct kevent Event; + PIO_COMPLETION_CONTEXT CompletionContext; +} FILE_OBJECT; +typedef struct _FILE_OBJECT *PFILE_OBJECT; + +typedef struct _INITIAL_PRIVILEGE_SET { + ULONG PrivilegeCount; + ULONG Control; + LUID_AND_ATTRIBUTES Privilege[INITIAL_PRIVILEGE_COUNT]; +} INITIAL_PRIVILEGE_SET, * PINITIAL_PRIVILEGE_SET; + +typedef struct _SECURITY_SUBJECT_CONTEXT { + PACCESS_TOKEN ClientToken; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + PACCESS_TOKEN PrimaryToken; + PVOID ProcessAuditId; +} SECURITY_SUBJECT_CONTEXT, *PSECURITY_SUBJECT_CONTEXT; + +typedef struct _IO_SECURITY_CONTEXT { + PSECURITY_QUALITY_OF_SERVICE SecurityQos; + PACCESS_STATE AccessState; + ACCESS_MASK DesiredAccess; + ULONG FullCreateOptions; +} IO_SECURITY_CONTEXT, *PIO_SECURITY_CONTEXT; + +typedef struct _IO_STACK_LOCATION { + UCHAR MajorFunction; + UCHAR MinorFunction; + UCHAR Flags; + UCHAR Control; + union { + struct { + PIO_SECURITY_CONTEXT SecurityContext; + ULONG Options; + USHORT POINTER_ALIGNMENT FileAttributes; + USHORT ShareAccess; + ULONG POINTER_ALIGNMENT EaLength; + } Create; + /* FIXME: CreatePipe and CreateMailslot aren't defined in official + * DDK/IFS headers. */ + struct { + PIO_SECURITY_CONTEXT SecurityContext; + ULONG Options; + USHORT Reserved; + USHORT ShareAccess; + struct _NAMED_PIPE_CREATE_PARAMETERS *Parameters; + } CreatePipe; + struct { + PIO_SECURITY_CONTEXT SecurityContext; + ULONG Options; + USHORT Reserved; + USHORT ShareAccess; + struct _MAILSLOT_CREATE_PARAMETERS *Parameters; + } CreateMailslot; + struct { + ULONG Length; + ULONG POINTER_ALIGNMENT Key; + LARGE_INTEGER ByteOffset; + } Read; + struct { + ULONG Length; + ULONG POINTER_ALIGNMENT Key; + LARGE_INTEGER ByteOffset; + } Write; + struct { + ULONG Length; + PUNICODE_STRING FileName; + FILE_INFORMATION_CLASS FileInformationClass; + ULONG FileIndex; + } QueryDirectory; + struct { + ULONG Length; + ULONG CompletionFilter; + } NotifyDirectory; + struct { + ULONG Length; + FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass; + } QueryFile; + struct { + ULONG Length; + FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass; + PFILE_OBJECT FileObject; + _ANONYMOUS_UNION union { + _ANONYMOUS_STRUCT struct { + BOOLEAN ReplaceIfExists; + BOOLEAN AdvanceOnly; + } DUMMYSTRUCTNAME; + ULONG ClusterCount; + HANDLE DeleteHandle; + } DUMMYUNIONNAME; + } SetFile; + struct { + ULONG Length; + PVOID EaList; + ULONG EaListLength; + ULONG EaIndex; + } QueryEa; + struct { + ULONG Length; + } SetEa; + struct { + ULONG Length; + FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass; + } QueryVolume; + struct { + ULONG Length; + FS_INFORMATION_CLASS FsInformationClass; + } SetVolume; + struct { + ULONG OutputBufferLength; + ULONG InputBufferLength; + ULONG FsControlCode; + PVOID Type3InputBuffer; + } FileSystemControl; + struct { + PLARGE_INTEGER Length; + ULONG Key; + LARGE_INTEGER ByteOffset; + } LockControl; + struct { + ULONG OutputBufferLength; + ULONG POINTER_ALIGNMENT InputBufferLength; + ULONG POINTER_ALIGNMENT IoControlCode; + PVOID Type3InputBuffer; + } DeviceIoControl; + struct { + SECURITY_INFORMATION SecurityInformation; + ULONG POINTER_ALIGNMENT Length; + } QuerySecurity; + struct { + SECURITY_INFORMATION SecurityInformation; + PSECURITY_DESCRIPTOR SecurityDescriptor; + } SetSecurity; + struct { + PVPB Vpb; + PDEVICE_OBJECT DeviceObject; + } MountVolume; + struct { + PVPB Vpb; + PDEVICE_OBJECT DeviceObject; + } VerifyVolume; + struct { + struct _SCSI_REQUEST_BLOCK *Srb; + } Scsi; + struct { + ULONG Length; + PSID StartSid; + struct _FILE_GET_QUOTA_INFORMATION *SidList; + ULONG SidListLength; + } QueryQuota; + struct { + ULONG Length; + } SetQuota; + struct { + DEVICE_RELATION_TYPE Type; + } QueryDeviceRelations; + struct { + const GUID *InterfaceType; + USHORT Size; + USHORT Version; + PINTERFACE Interface; + PVOID InterfaceSpecificData; + } QueryInterface; + struct { + PDEVICE_CAPABILITIES Capabilities; + } DeviceCapabilities; + struct { + PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList; + } FilterResourceRequirements; + struct { + ULONG WhichSpace; + PVOID Buffer; + ULONG Offset; + ULONG POINTER_ALIGNMENT Length; + } ReadWriteConfig; + struct { + BOOLEAN Lock; + } SetLock; + struct { + BUS_QUERY_ID_TYPE IdType; + } QueryId; + struct { + DEVICE_TEXT_TYPE DeviceTextType; + LCID POINTER_ALIGNMENT LocaleId; + } QueryDeviceText; + struct { + BOOLEAN InPath; + BOOLEAN Reserved[3]; + DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type; + } UsageNotification; + struct { + SYSTEM_POWER_STATE PowerState; + } WaitWake; + struct { + PPOWER_SEQUENCE PowerSequence; + } PowerSequence; + struct { + ULONG SystemContext; + POWER_STATE_TYPE POINTER_ALIGNMENT Type; + POWER_STATE POINTER_ALIGNMENT State; + POWER_ACTION POINTER_ALIGNMENT ShutdownType; + } Power; + struct { + PCM_RESOURCE_LIST AllocatedResources; + PCM_RESOURCE_LIST AllocatedResourcesTranslated; + } StartDevice; + struct { + ULONG_PTR ProviderId; + PVOID DataPath; + ULONG BufferSize; + PVOID Buffer; + } WMI; + struct { + PVOID Argument1; + PVOID Argument2; + PVOID Argument3; + PVOID Argument4; + } Others; + } Parameters; + PDEVICE_OBJECT DeviceObject; + PFILE_OBJECT FileObject; + PIO_COMPLETION_ROUTINE CompletionRoutine; + PVOID Context; +} IO_STACK_LOCATION, *PIO_STACK_LOCATION; + +typedef struct _FILE_CONTROL_OBJECT { + struct list_head FileList; + ULONG Access; +} FILE_CONTROL_OBJECT, *PFILE_CONTROL_OBJECT; + +VOID init_io(VOID); + +VOID io_open_file(OB_OPEN_REASON OpenReason, + struct eprocess* Process OPTIONAL, + PVOID Object, + ACCESS_MASK GrantedAccess, + ULONG HandleCount); + +VOID io_close_file(struct eprocess* Process OPTIONAL, + PVOID Object, + ACCESS_MASK GrantedAccess, + ULONG ProcessHandleCount, + ULONG systemHandleCount); + +VOID io_delete_file(PVOID Object); + +VOID io_create_file(PVOID Object, PVOID Param); + +NTSTATUS +io_create_symbol_link(PUNICODE_STRING SymbolicLinkName, + PUNICODE_STRING TargetName); + +static inline BOOLEAN is_dos_driver(PUNICODE_STRING Name) +{ + /* "[A-Z]:" is Dos driver */ + return (Name->Length == 2 * sizeof(WCHAR) + && Name->Buffer[1] == (WCHAR)':' + && (*Name->Buffer >= (WCHAR)'A' && *Name->Buffer <= (WCHAR)'Z')) + ? TRUE + : FALSE; +} + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif diff --git a/unifiedkernel/include/ke.h b/unifiedkernel/include/ke.h new file mode 100644 index 0000000..52ffd7a --- /dev/null +++ b/unifiedkernel/include/ke.h @@ -0,0 +1,124 @@ +/* + * ke.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * ke.h: + * Refered to ReactOS code + */ + +#ifndef _KE_H +#define _KE_H + +#include +#if 0 +#include +#endif +#include "win32.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* + * get_pre_mode() should be defined like: + * #define get_pre_mode() get_current_ethread()->tcb.previous_mode + * + * Temporarily, we define it as "UserMode" + */ +#define get_pre_mode() UserMode + +typedef enum _KOBJECTS { + EventNotificationObject = 1, + EventSynchronizationObject = 0, + MutantObject = 2, + ProcessObject = 3, + QueueObject = 4, + SemaphoreObject = 5, + ThreadObject = 6, + GateObject = 7, + TimerNotificationObject = 8, + TimerSynchronizationObject = 9, + Spare2Object = 10, + Spare3Object = 11, + Spare4Object = 12, + Spare5Object = 13, + Spare6Object = 14, + Spare7Object = 15, + Spare8Object = 16, + Spare9Object = 17, + ApcObject = 18, + DpcObject = 19, + DeviceQueueObject = 20, + EventPairObject = 21, + InterruptObject = 22, + ProfileObject = 23, + ThreadedDpcObject = 24, + MaximumKernelObject = 25 +} KOBJECTS; + +typedef LONG KPRIORITY; + +static inline void enter_critical_region(void) +{ + struct ethread *thread = current->ethread; + + if (thread) + thread->tcb.kernel_apc_disable--; +} + +static inline void leave_critical_region(void) +{ + struct ethread *thread = current->ethread; + + /* FIXME: kernel apc check */ + if (thread && ++thread->tcb.kernel_apc_disable == 0) { +#if 0 + if (list_empty(&CurrentThread->apc_state.apc_list_head[KernelMode])) + KiKernelApcDeliveryCheck(); +#endif + } +} + +static inline BOOLEAN +is_object_signaled(struct dispatcher_header *Object, struct kthread *Thread) +{ + /* Mutants are...well...mutants! */ + if (Object->type == MutantObject) { + /* Because Cutler hates mutants, they are actually signaled if the Signal State is <= 0 + * Well, only if they are recursivly acquired (i.e if we own it right now). + * Of course, they are also signaled if their signal state is 1. */ + if ((Object->signal_state <= 0 && ((struct kmutant *)Object)->owner_thread == Thread) + || (Object->signal_state >= 1)) { + if(Object->signal_state >= 1) Object->signal_state =1; + /* Signaled Mutant */ + return true; + } else { + /* Unsignaled Mutant */ + return false; + } + } + + /* Any other object is not a mutated freak, so let's use logic */ + return (!Object->signal_state <= 0); +} + +extern void query_sys_time(large_integer_t *CurrentTime); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif diff --git a/unifiedkernel/include/mutex.h b/unifiedkernel/include/mutex.h new file mode 100644 index 0000000..fcc6641 --- /dev/null +++ b/unifiedkernel/include/mutex.h @@ -0,0 +1,86 @@ +/* + * mutex.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * mutex.h: win32 mutex definition + * Refered to Kernel-win32 code + */ + +#ifndef _MUTEX_H +#define _MUTEX_H + +#include +#include "win32_process.h" +#include "object.h" +#include "ke.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define MUTANT_QUERY_STATE 0x0001 +#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MUTANT_QUERY_STATE) +#define MUTANT_INCREMENT 1 + +#define init_fast_mutex(mutex) { \ + (mutex)->Count = 1; \ + (mutex)->Owner = NULL; \ + atomic_set(&(mutex)->Contention, 0); \ + event_init(&(mutex)->Event, SynchronizationEvent, FALSE); \ +} + +VOID STDCALL +mutant_init(IN struct kmutant* Mutant, + IN BOOLEAN InitialOwner); + +VOID +init_mutant_implement(VOID); + +NTSTATUS SERVICECALL +NtCreateMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN InitialOwner); + +NTSTATUS SERVICECALL +NtOpenMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +LONG STDCALL +release_mutant(IN struct kmutant *Mutant, + IN KPRIORITY Increment, + IN BOOLEAN Abandon, + IN BOOLEAN Wait); + +NTSTATUS SERVICECALL +NtReleaseMutant(IN HANDLE MutantHandle, + IN PLONG PreviousCount OPTIONAL); + +VOID +delete_mutant(PVOID ObjectBody); + +VOID +acquire_fmutex_unsafe(PFAST_MUTEX FastMutex); + +VOID +release_fmutex_unsafe(PFAST_MUTEX FastMutex); +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _MUTEX_H */ diff --git a/unifiedkernel/include/ntstatus.h b/unifiedkernel/include/ntstatus.h new file mode 100644 index 0000000..40d0e51 --- /dev/null +++ b/unifiedkernel/include/ntstatus.h @@ -0,0 +1,1104 @@ +/* + * ntstatus.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * ntstatus.h: + * Refered to ReactOS code + */ +#ifndef _NTSTATUS_H +#define _NTSTATUS_H + +#ifdef CONFIG_UNIFIED_KERNEL +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#if !defined(STATUS_SUCCESS) +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#endif /* !STATUS_SUCCESS */ + +#define FACILITY_DEBUGGER 0x1 +#define FACILITY_RPC_RUNTIME 0x2 +#define FACILITY_RPC_STUBS 0x3 +#define FACILITY_IO_ERROR_CODE 0x4 +#define FACILITY_TERMINAL_SERVER 0xA +#define FACILITY_USB_ERROR_CODE 0x10 +#define FACILITY_HID_ERROR_CODE 0x11 +#define FACILITY_FIREWIRE_ERROR_CODE 0x12 +#define FACILITY_CLUSTER_ERROR_CODE 0x13 +#define FACILITY_ACPI_ERROR_CODE 0x14 +#define FACILITY_SXS_ERROR_CODE 0x15 +#define STATUS_SEVERITY_SUCCESS 0x0 +#define STATUS_SEVERITY_INFORMATIONAL 0x1 +#define STATUS_SEVERITY_WARNING 0x2 +#define STATUS_SEVERITY_ERROR 0x3 +#define STATUS_WAIT_0 ((NTSTATUS)0x00000000L) +#define STATUS_WAIT_1 ((NTSTATUS)0x00000001L) +#define STATUS_WAIT_2 ((NTSTATUS)0x00000002L) +#define STATUS_WAIT_3 ((NTSTATUS)0x00000003L) +#define STATUS_WAIT_63 ((NTSTATUS)0x0000003FL) +#define STATUS_ABANDONED ((NTSTATUS)0x00000080L) +#define STATUS_ABANDONED_WAIT_0 ((NTSTATUS)0x00000080L) +#define STATUS_ABANDONED_WAIT_63 ((NTSTATUS)0x000000BFL) +#define STATUS_USER_APC ((NTSTATUS)0x000000C0L) +#define STATUS_KERNEL_APC ((NTSTATUS)0x00000100L) +#define STATUS_ALERTED ((NTSTATUS)0x00000101L) +#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L) +#define STATUS_PENDING ((NTSTATUS)0x00000103L) +#define STATUS_REPARSE ((NTSTATUS)0x00000104L) +#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L) +#define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS)0x00000106L) +#define STATUS_SOME_NOT_MAPPED ((NTSTATUS)0x00000107L) +#define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS)0x00000108L) +#define STATUS_VOLUME_MOUNTED ((NTSTATUS)0x00000109L) +#define STATUS_RXACT_COMMITTED ((NTSTATUS)0x0000010AL) +#define STATUS_NOTIFY_CLEANUP ((NTSTATUS)0x0000010BL) +#define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS)0x0000010CL) +#define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS)0x0000010DL) +#define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS)0x0000010EL) +#define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS)0x00000110L) +#define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS)0x00000111L) +#define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS)0x00000112L) +#define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS)0x00000113L) +#define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS)0x00000114L) +#define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS)0x00000115L) +#define STATUS_CRASH_DUMP ((NTSTATUS)0x00000116L) +#define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS)0x00000117L) +#define STATUS_REPARSE_OBJECT ((NTSTATUS)0x00000118L) +#define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS)0x00000119L) +#define STATUS_TRANSLATION_COMPLETE ((NTSTATUS)0x00000120L) +#define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS)0x00000121L) +#define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS)0x00000122L) +#define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS)0x00000123L) +#define STATUS_PROCESS_IN_JOB ((NTSTATUS)0x00000124L) +#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L) +#define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS)0x40000001L) +#define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS)0x40000002L) +#define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS)0x40000003L) +#define STATUS_RXACT_STATE_CREATED ((NTSTATUS)0x40000004L) +#define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS)0x40000005L) +#define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS)0x40000006L) +#define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS)0x40000007L) +#define STATUS_SERIAL_MORE_WRITES ((NTSTATUS)0x40000008L) +#define STATUS_REGISTRY_RECOVERED ((NTSTATUS)0x40000009L) +#define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS)0x4000000AL) +#define STATUS_FT_WRITE_RECOVERY ((NTSTATUS)0x4000000BL) +#define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS)0x4000000CL) +#define STATUS_NULL_LM_PASSWORD ((NTSTATUS)0x4000000DL) +#define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS)0x4000000EL) +#define STATUS_RECEIVE_PARTIAL ((NTSTATUS)0x4000000FL) +#define STATUS_RECEIVE_EXPEDITED ((NTSTATUS)0x40000010L) +#define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS)0x40000011L) +#define STATUS_EVENT_DONE ((NTSTATUS)0x40000012L) +#define STATUS_EVENT_PENDING ((NTSTATUS)0x40000013L) +#define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS)0x40000014L) +#define STATUS_FATAL_APP_EXIT ((NTSTATUS)0x40000015L) +#define STATUS_PREDEFINED_HANDLE ((NTSTATUS)0x40000016L) +#define STATUS_WAS_UNLOCKED ((NTSTATUS)0x40000017L) +#define STATUS_SERVICE_NOTIFICATION ((NTSTATUS)0x40000018L) +#define STATUS_WAS_LOCKED ((NTSTATUS)0x40000019L) +#define STATUS_LOG_HARD_ERROR ((NTSTATUS)0x4000001AL) +#define STATUS_ALREADY_WIN32 ((NTSTATUS)0x4000001BL) +#define STATUS_WX86_UNSIMULATE ((NTSTATUS)0x4000001CL) +#define STATUS_WX86_CONTINUE ((NTSTATUS)0x4000001DL) +#define STATUS_WX86_SINGLE_STEP ((NTSTATUS)0x4000001EL) +#define STATUS_WX86_BREAKPOINT ((NTSTATUS)0x4000001FL) +#define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS)0x40000020L) +#define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS)0x40000021L) +#define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS)0x40000022L) +#define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS)0x40000023L) +#define STATUS_NO_YIELD_PERFORMED ((NTSTATUS)0x40000024L) +#define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS)0x40000025L) +#define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS)0x40000026L) +#define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS)0x40000027L) +#define STATUS_WX86_CREATEWX86TIB ((NTSTATUS)0x40000028L) +#define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS)0x40000029L) +#define STATUS_HIBERNATED ((NTSTATUS)0x4000002AL) +#define STATUS_RESUME_HIBERNATION ((NTSTATUS)0x4000002BL) +#define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS)0x80000001L) +#define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS)0x80000002L) +#define STATUS_BREAKPOINT ((NTSTATUS)0x80000003L) +#define STATUS_SINGLE_STEP ((NTSTATUS)0x80000004L) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) +#define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS)0x80000007L) +#define STATUS_HANDLES_CLOSED ((NTSTATUS)0x8000000AL) +#define STATUS_NO_INHERITANCE ((NTSTATUS)0x8000000BL) +#define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS)0x8000000CL) +#define STATUS_PARTIAL_COPY ((NTSTATUS)0x8000000DL) +#define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS)0x8000000EL) +#define STATUS_DEVICE_POWERED_OFF ((NTSTATUS)0x8000000FL) +#define STATUS_DEVICE_OFF_LINE ((NTSTATUS)0x80000010L) +#define STATUS_DEVICE_BUSY ((NTSTATUS)0x80000011L) +#define STATUS_NO_MORE_EAS ((NTSTATUS)0x80000012L) +#define STATUS_INVALID_EA_NAME ((NTSTATUS)0x80000013L) +#define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS)0x80000014L) +#define STATUS_INVALID_EA_FLAG ((NTSTATUS)0x80000015L) +#define STATUS_VERIFY_REQUIRED ((NTSTATUS)0x80000016L) +#define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS)0x80000017L) +#define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS)0x80000018L) +#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL) +#define STATUS_FILEMARK_DETECTED ((NTSTATUS)0x8000001BL) +#define STATUS_MEDIA_CHANGED ((NTSTATUS)0x8000001CL) +#define STATUS_BUS_RESET ((NTSTATUS)0x8000001DL) +#define STATUS_END_OF_MEDIA ((NTSTATUS)0x8000001EL) +#define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS)0x8000001FL) +#define STATUS_MEDIA_CHECK ((NTSTATUS)0x80000020L) +#define STATUS_SETMARK_DETECTED ((NTSTATUS)0x80000021L) +#define STATUS_NO_DATA_DETECTED ((NTSTATUS)0x80000022L) +#define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS)0x80000023L) +#define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS)0x80000024L) +#define STATUS_ALREADY_DISCONNECTED ((NTSTATUS)0x80000025L) +#define STATUS_LONGJUMP ((NTSTATUS)0x80000026L) +#define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS)0x80000027L) +#define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS)0x80000028L) +#define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS)0x80000029L) +#define STATUS_CLUSTER_NODE_ALREADY_UP ((NTSTATUS)0x80130001L) +#define STATUS_CLUSTER_NODE_ALREADY_DOWN ((NTSTATUS)0x80130002L) +#define STATUS_CLUSTER_NETWORK_ALREADY_ONLINE ((NTSTATUS)0x80130003L) +#define STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE ((NTSTATUS)0x80130004L) +#define STATUS_CLUSTER_NODE_ALREADY_MEMBER ((NTSTATUS)0x80130005L) +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) +#define STATUS_INVALID_INFO_CLASS ((NTSTATUS)0xC0000003L) +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +#define STATUS_ACCESS_VIOLATION ((NTSTATUS)0xC0000005L) +#define STATUS_IN_PAGE_ERROR ((NTSTATUS)0xC0000006L) +#define STATUS_PAGEFILE_QUOTA ((NTSTATUS)0xC0000007L) +#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L) +#define STATUS_BAD_INITIAL_STACK ((NTSTATUS)0xC0000009L) +#define STATUS_BAD_INITIAL_PC ((NTSTATUS)0xC000000AL) +#define STATUS_INVALID_CID ((NTSTATUS)0xC000000BL) +#define STATUS_TIMER_NOT_CANCELED ((NTSTATUS)0xC000000CL) +#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#define STATUS_NO_SUCH_DEVICE ((NTSTATUS)0xC000000EL) +#define STATUS_NO_SUCH_FILE ((NTSTATUS)0xC000000FL) +#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L) +#define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011L) +#define STATUS_WRONG_VOLUME ((NTSTATUS)0xC0000012L) +#define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS)0xC0000013L) +#define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS)0xC0000014L) +#define STATUS_NONEXISTENT_SECTOR ((NTSTATUS)0xC0000015L) +#define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS)0xC0000016L) +#define STATUS_NO_MEMORY ((NTSTATUS)0xC0000017L) +#define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS)0xC0000018L) +#define STATUS_NOT_MAPPED_VIEW ((NTSTATUS)0xC0000019L) +#define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS)0xC000001AL) +#define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS)0xC000001BL) +#define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS)0xC000001CL) +#define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS)0xC000001DL) +#define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS)0xC000001EL) +#define STATUS_INVALID_VIEW_SIZE ((NTSTATUS)0xC000001FL) +#define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS)0xC0000020L) +#define STATUS_ALREADY_COMMITTED ((NTSTATUS)0xC0000021L) +#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) +#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) +#define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS)0xC0000024L) +#define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS)0xC0000025L) +#define STATUS_INVALID_DISPOSITION ((NTSTATUS)0xC0000026L) +#define STATUS_UNWIND ((NTSTATUS)0xC0000027L) +#define STATUS_BAD_STACK ((NTSTATUS)0xC0000028L) +#define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS)0xC0000029L) +#define STATUS_NOT_LOCKED ((NTSTATUS)0xC000002AL) +#define STATUS_PARITY_ERROR ((NTSTATUS)0xC000002BL) +#define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS)0xC000002CL) +#define STATUS_NOT_COMMITTED ((NTSTATUS)0xC000002DL) +#define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS)0xC000002EL) +#define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS)0xC000002FL) +#define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS)0xC0000030L) +#define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS)0xC0000031L) +#define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS)0xC0000032L) +#define STATUS_OBJECT_NAME_INVALID ((NTSTATUS)0xC0000033L) +#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) +#define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS)0xC0000035L) +#define STATUS_PORT_DISCONNECTED ((NTSTATUS)0xC0000037L) +#define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS)0xC0000038L) +#define STATUS_OBJECT_PATH_INVALID ((NTSTATUS)0xC0000039L) +#define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS)0xC000003AL) +#define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS)0xC000003BL) +#define STATUS_DATA_OVERRUN ((NTSTATUS)0xC000003CL) +#define STATUS_DATA_LATE_ERROR ((NTSTATUS)0xC000003DL) +#define STATUS_DATA_ERROR ((NTSTATUS)0xC000003EL) +#define STATUS_CRC_ERROR ((NTSTATUS)0xC000003FL) +#define STATUS_SECTION_TOO_BIG ((NTSTATUS)0xC0000040L) +#define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS)0xC0000041L) +#define STATUS_INVALID_PORT_HANDLE ((NTSTATUS)0xC0000042L) +#define STATUS_SHARING_VIOLATION ((NTSTATUS)0xC0000043L) +#define STATUS_QUOTA_EXCEEDED ((NTSTATUS)0xC0000044L) +#define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS)0xC0000045L) +#define STATUS_MUTANT_NOT_OWNED ((NTSTATUS)0xC0000046L) +#define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS)0xC0000047L) +#define STATUS_PORT_ALREADY_SET ((NTSTATUS)0xC0000048L) +#define STATUS_SECTION_NOT_IMAGE ((NTSTATUS)0xC0000049L) +#define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS)0xC000004AL) +#define STATUS_THREAD_IS_TERMINATING ((NTSTATUS)0xC000004BL) +#define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS)0xC000004CL) +#define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS)0xC000004DL) +#define STATUS_SECTION_PROTECTION ((NTSTATUS)0xC000004EL) +#define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS)0xC000004FL) +#define STATUS_EA_TOO_LARGE ((NTSTATUS)0xC0000050L) +#define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS)0xC0000051L) +#define STATUS_NO_EAS_ON_FILE ((NTSTATUS)0xC0000052L) +#define STATUS_EA_CORRUPT_ERROR ((NTSTATUS)0xC0000053L) +#define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS)0xC0000054L) +#define STATUS_LOCK_NOT_GRANTED ((NTSTATUS)0xC0000055L) +#define STATUS_DELETE_PENDING ((NTSTATUS)0xC0000056L) +#define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS)0xC0000057L) +#define STATUS_UNKNOWN_REVISION ((NTSTATUS)0xC0000058L) +#define STATUS_REVISION_MISMATCH ((NTSTATUS)0xC0000059L) +#define STATUS_INVALID_OWNER ((NTSTATUS)0xC000005AL) +#define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS)0xC000005BL) +#define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS)0xC000005CL) +#define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS)0xC000005DL) +#define STATUS_NO_LOGON_SERVERS ((NTSTATUS)0xC000005EL) +#define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS)0xC000005FL) +#define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS)0xC0000060L) +#define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS)0xC0000061L) +#define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS)0xC0000062L) +#define STATUS_USER_EXISTS ((NTSTATUS)0xC0000063L) +#define STATUS_NO_SUCH_USER ((NTSTATUS)0xC0000064L) +#define STATUS_GROUP_EXISTS ((NTSTATUS)0xC0000065L) +#define STATUS_NO_SUCH_GROUP ((NTSTATUS)0xC0000066L) +#define STATUS_MEMBER_IN_GROUP ((NTSTATUS)0xC0000067L) +#define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS)0xC0000068L) +#define STATUS_LAST_ADMIN ((NTSTATUS)0xC0000069L) +#define STATUS_WRONG_PASSWORD ((NTSTATUS)0xC000006AL) +#define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS)0xC000006BL) +#define STATUS_PASSWORD_RESTRICTION ((NTSTATUS)0xC000006CL) +#define STATUS_LOGON_FAILURE ((NTSTATUS)0xC000006DL) +#define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS)0xC000006EL) +#define STATUS_INVALID_LOGON_HOURS ((NTSTATUS)0xC000006FL) +#define STATUS_INVALID_WORKSTATION ((NTSTATUS)0xC0000070L) +#define STATUS_PASSWORD_EXPIRED ((NTSTATUS)0xC0000071L) +#define STATUS_ACCOUNT_DISABLED ((NTSTATUS)0xC0000072L) +#define STATUS_NONE_MAPPED ((NTSTATUS)0xC0000073L) +#define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS)0xC0000074L) +#define STATUS_LUIDS_EXHAUSTED ((NTSTATUS)0xC0000075L) +#define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS)0xC0000076L) +#define STATUS_INVALID_ACL ((NTSTATUS)0xC0000077L) +#define STATUS_INVALID_SID ((NTSTATUS)0xC0000078L) +#define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS)0xC0000079L) +#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) +#define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS)0xC000007BL) +#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) +#define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS)0xC000007DL) +#define STATUS_RANGE_NOT_LOCKED ((NTSTATUS)0xC000007EL) +#define STATUS_DISK_FULL ((NTSTATUS)0xC000007FL) +#define STATUS_SERVER_DISABLED ((NTSTATUS)0xC0000080L) +#define STATUS_SERVER_NOT_DISABLED ((NTSTATUS)0xC0000081L) +#define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS)0xC0000082L) +#define STATUS_GUIDS_EXHAUSTED ((NTSTATUS)0xC0000083L) +#define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS)0xC0000084L) +#define STATUS_AGENTS_EXHAUSTED ((NTSTATUS)0xC0000085L) +#define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS)0xC0000086L) +#define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS)0xC0000087L) +#define STATUS_NOT_MAPPED_DATA ((NTSTATUS)0xC0000088L) +#define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS)0xC0000089L) +#define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS)0xC000008AL) +#define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS)0xC000008BL) +#define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS)0xC000008CL) +#define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS)0xC000008DL) +#define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS)0xC000008EL) +#define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS)0xC000008FL) +#define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS)0xC0000090L) +#define STATUS_FLOAT_OVERFLOW ((NTSTATUS)0xC0000091L) +#define STATUS_FLOAT_STACK_CHECK ((NTSTATUS)0xC0000092L) +#define STATUS_FLOAT_UNDERFLOW ((NTSTATUS)0xC0000093L) +#define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS)0xC0000094L) +#define STATUS_INTEGER_OVERFLOW ((NTSTATUS)0xC0000095L) +#define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS)0xC0000096L) +#define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS)0xC0000097L) +#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) +#define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS)0xC0000099L) +#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) +#define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS)0xC000009BL) +#define STATUS_DEVICE_DATA_ERROR ((NTSTATUS)0xC000009CL) +#define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS)0xC000009DL) +#define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS)0xC000009EL) +#define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS)0xC000009FL) +#define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) +#define STATUS_WORKING_SET_QUOTA ((NTSTATUS)0xC00000A1L) +#define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS)0xC00000A2L) +#define STATUS_DEVICE_NOT_READY ((NTSTATUS)0xC00000A3L) +#define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS)0xC00000A4L) +#define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS)0xC00000A5L) +#define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS)0xC00000A6L) +#define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS)0xC00000A7L) +#define STATUS_BAD_TOKEN_TYPE ((NTSTATUS)0xC00000A8L) +#define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS)0xC00000A9L) +#define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS)0xC00000AAL) +#define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS)0xC00000ABL) +#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS)0xC00000ACL) +#define STATUS_INVALID_PIPE_STATE ((NTSTATUS)0xC00000ADL) +#define STATUS_PIPE_BUSY ((NTSTATUS)0xC00000AEL) +#define STATUS_ILLEGAL_FUNCTION ((NTSTATUS)0xC00000AFL) +#define STATUS_PIPE_DISCONNECTED ((NTSTATUS)0xC00000B0L) +#define STATUS_PIPE_CLOSING ((NTSTATUS)0xC00000B1L) +#define STATUS_PIPE_CONNECTED ((NTSTATUS)0xC00000B2L) +#define STATUS_PIPE_LISTENING ((NTSTATUS)0xC00000B3L) +#define STATUS_INVALID_READ_MODE ((NTSTATUS)0xC00000B4L) +#define STATUS_IO_TIMEOUT ((NTSTATUS)0xC00000B5L) +#define STATUS_FILE_FORCED_CLOSED ((NTSTATUS)0xC00000B6L) +#define STATUS_PROFILING_NOT_STARTED ((NTSTATUS)0xC00000B7L) +#define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS)0xC00000B8L) +#define STATUS_COULD_NOT_INTERPRET ((NTSTATUS)0xC00000B9L) +#define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL) +#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) +#define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS)0xC00000BCL) +#define STATUS_DUPLICATE_NAME ((NTSTATUS)0xC00000BDL) +#define STATUS_BAD_NETWORK_PATH ((NTSTATUS)0xC00000BEL) +#define STATUS_NETWORK_BUSY ((NTSTATUS)0xC00000BFL) +#define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS)0xC00000C0L) +#define STATUS_TOO_MANY_COMMANDS ((NTSTATUS)0xC00000C1L) +#define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS)0xC00000C2L) +#define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS)0xC00000C3L) +#define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS)0xC00000C4L) +#define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS)0xC00000C5L) +#define STATUS_PRINT_QUEUE_FULL ((NTSTATUS)0xC00000C6L) +#define STATUS_NO_SPOOL_SPACE ((NTSTATUS)0xC00000C7L) +#define STATUS_PRINT_CANCELLED ((NTSTATUS)0xC00000C8L) +#define STATUS_NETWORK_NAME_DELETED ((NTSTATUS)0xC00000C9L) +#define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS)0xC00000CAL) +#define STATUS_BAD_DEVICE_TYPE ((NTSTATUS)0xC00000CBL) +#define STATUS_BAD_NETWORK_NAME ((NTSTATUS)0xC00000CCL) +#define STATUS_TOO_MANY_NAMES ((NTSTATUS)0xC00000CDL) +#define STATUS_TOO_MANY_SESSIONS ((NTSTATUS)0xC00000CEL) +#define STATUS_SHARING_PAUSED ((NTSTATUS)0xC00000CFL) +#define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS)0xC00000D0L) +#define STATUS_REDIRECTOR_PAUSED ((NTSTATUS)0xC00000D1L) +#define STATUS_NET_WRITE_FAULT ((NTSTATUS)0xC00000D2L) +#define STATUS_PROFILING_AT_LIMIT ((NTSTATUS)0xC00000D3L) +#define STATUS_NOT_SAME_DEVICE ((NTSTATUS)0xC00000D4L) +#define STATUS_FILE_RENAMED ((NTSTATUS)0xC00000D5L) +#define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS)0xC00000D6L) +#define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS)0xC00000D7L) +#define STATUS_CANT_WAIT ((NTSTATUS)0xC00000D8L) +#define STATUS_PIPE_EMPTY ((NTSTATUS)0xC00000D9L) +#define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS)0xC00000DAL) +#define STATUS_CANT_TERMINATE_SELF ((NTSTATUS)0xC00000DBL) +#define STATUS_INVALID_SERVER_STATE ((NTSTATUS)0xC00000DCL) +#define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS)0xC00000DDL) +#define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS)0xC00000DEL) +#define STATUS_NO_SUCH_DOMAIN ((NTSTATUS)0xC00000DFL) +#define STATUS_DOMAIN_EXISTS ((NTSTATUS)0xC00000E0L) +#define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS)0xC00000E1L) +#define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS)0xC00000E2L) +#define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS)0xC00000E3L) +#define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS)0xC00000E4L) +#define STATUS_INTERNAL_ERROR ((NTSTATUS)0xC00000E5L) +#define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS)0xC00000E6L) +#define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS)0xC00000E7L) +#define STATUS_INVALID_USER_BUFFER ((NTSTATUS)0xC00000E8L) +#define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS)0xC00000E9L) +#define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS)0xC00000EAL) +#define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS)0xC00000EBL) +#define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS)0xC00000ECL) +#define STATUS_NOT_LOGON_PROCESS ((NTSTATUS)0xC00000EDL) +#define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS)0xC00000EEL) +#define STATUS_INVALID_PARAMETER_1 ((NTSTATUS)0xC00000EFL) +#define STATUS_INVALID_PARAMETER_2 ((NTSTATUS)0xC00000F0L) +#define STATUS_INVALID_PARAMETER_3 ((NTSTATUS)0xC00000F1L) +#define STATUS_INVALID_PARAMETER_4 ((NTSTATUS)0xC00000F2L) +#define STATUS_INVALID_PARAMETER_5 ((NTSTATUS)0xC00000F3L) +#define STATUS_INVALID_PARAMETER_6 ((NTSTATUS)0xC00000F4L) +#define STATUS_INVALID_PARAMETER_7 ((NTSTATUS)0xC00000F5L) +#define STATUS_INVALID_PARAMETER_8 ((NTSTATUS)0xC00000F6L) +#define STATUS_INVALID_PARAMETER_9 ((NTSTATUS)0xC00000F7L) +#define STATUS_INVALID_PARAMETER_10 ((NTSTATUS)0xC00000F8L) +#define STATUS_INVALID_PARAMETER_11 ((NTSTATUS)0xC00000F9L) +#define STATUS_INVALID_PARAMETER_12 ((NTSTATUS)0xC00000FAL) +#define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS)0xC00000FBL) +#define STATUS_REDIRECTOR_STARTED ((NTSTATUS)0xC00000FCL) +#define STATUS_STACK_OVERFLOW ((NTSTATUS)0xC00000FDL) +#define STATUS_NO_SUCH_PACKAGE ((NTSTATUS)0xC00000FEL) +#define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS)0xC00000FFL) +#define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS)0xC0000100L) +#define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS)0xC0000101L) +#define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS)0xC0000102L) +#define STATUS_NOT_A_DIRECTORY ((NTSTATUS)0xC0000103L) +#define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS)0xC0000104L) +#define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS)0xC0000105L) +#define STATUS_NAME_TOO_LONG ((NTSTATUS)0xC0000106L) +#define STATUS_FILES_OPEN ((NTSTATUS)0xC0000107L) +#define STATUS_CONNECTION_IN_USE ((NTSTATUS)0xC0000108L) +#define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS)0xC0000109L) +#define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS)0xC000010AL) +#define STATUS_INVALID_LOGON_TYPE ((NTSTATUS)0xC000010BL) +#define STATUS_NO_GUID_TRANSLATION ((NTSTATUS)0xC000010CL) +#define STATUS_CANNOT_IMPERSONATE ((NTSTATUS)0xC000010DL) +#define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS)0xC000010EL) +#define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS)0xC000010FL) +#define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS)0xC0000110L) +#define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS)0xC0000111L) +#define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS)0xC0000112L) +#define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS)0xC0000113L) +#define STATUS_ABIOS_INVALID_LID ((NTSTATUS)0xC0000114L) +#define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS)0xC0000115L) +#define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS)0xC0000116L) +#define STATUS_NO_LDT ((NTSTATUS)0xC0000117L) +#define STATUS_INVALID_LDT_SIZE ((NTSTATUS)0xC0000118L) +#define STATUS_INVALID_LDT_OFFSET ((NTSTATUS)0xC0000119L) +#define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS)0xC000011AL) +#define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS)0xC000011BL) +#define STATUS_RXACT_INVALID_STATE ((NTSTATUS)0xC000011CL) +#define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS)0xC000011DL) +#define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS)0xC000011EL) +#define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS)0xC000011FL) +#define STATUS_CANCELLED ((NTSTATUS)0xC0000120L) +#define STATUS_CANNOT_DELETE ((NTSTATUS)0xC0000121L) +#define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS)0xC0000122L) +#define STATUS_FILE_DELETED ((NTSTATUS)0xC0000123L) +#define STATUS_SPECIAL_ACCOUNT ((NTSTATUS)0xC0000124L) +#define STATUS_SPECIAL_GROUP ((NTSTATUS)0xC0000125L) +#define STATUS_SPECIAL_USER ((NTSTATUS)0xC0000126L) +#define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS)0xC0000127L) +#define STATUS_FILE_CLOSED ((NTSTATUS)0xC0000128L) +#define STATUS_TOO_MANY_THREADS ((NTSTATUS)0xC0000129L) +#define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS)0xC000012AL) +#define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS)0xC000012BL) +#define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS)0xC000012CL) +#define STATUS_COMMITMENT_LIMIT ((NTSTATUS)0xC000012DL) +#define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS)0xC000012EL) +#define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS)0xC000012FL) +#define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS)0xC0000130L) +#define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS)0xC0000131L) +#define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS)0xC0000132L) +#define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS)0xC0000133L) +#define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS)0xC0000134L) +#define STATUS_DLL_NOT_FOUND ((NTSTATUS)0xC0000135L) +#define STATUS_OPEN_FAILED ((NTSTATUS)0xC0000136L) +#define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS)0xC0000137L) +#define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS)0xC0000138L) +#define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS)0xC0000139L) +#define STATUS_CONTROL_C_EXIT ((NTSTATUS)0xC000013AL) +#define STATUS_LOCAL_DISCONNECT ((NTSTATUS)0xC000013BL) +#define STATUS_REMOTE_DISCONNECT ((NTSTATUS)0xC000013CL) +#define STATUS_REMOTE_RESOURCES ((NTSTATUS)0xC000013DL) +#define STATUS_LINK_FAILED ((NTSTATUS)0xC000013EL) +#define STATUS_LINK_TIMEOUT ((NTSTATUS)0xC000013FL) +#define STATUS_INVALID_CONNECTION ((NTSTATUS)0xC0000140L) +#define STATUS_INVALID_ADDRESS ((NTSTATUS)0xC0000141L) +#define STATUS_DLL_INIT_FAILED ((NTSTATUS)0xC0000142L) +#define STATUS_MISSING_SYSTEMFILE ((NTSTATUS)0xC0000143L) +#define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS)0xC0000144L) +#define STATUS_APP_INIT_FAILURE ((NTSTATUS)0xC0000145L) +#define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS)0xC0000146L) +#define STATUS_NO_PAGEFILE ((NTSTATUS)0xC0000147L) +#define STATUS_INVALID_LEVEL ((NTSTATUS)0xC0000148L) +#define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS)0xC0000149L) +#define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS)0xC000014AL) +#define STATUS_PIPE_BROKEN ((NTSTATUS)0xC000014BL) +#define STATUS_REGISTRY_CORRUPT ((NTSTATUS)0xC000014CL) +#define STATUS_REGISTRY_IO_FAILED ((NTSTATUS)0xC000014DL) +#define STATUS_NO_EVENT_PAIR ((NTSTATUS)0xC000014EL) +#define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS)0xC000014FL) +#define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS)0xC0000150L) +#define STATUS_NO_SUCH_ALIAS ((NTSTATUS)0xC0000151L) +#define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS)0xC0000152L) +#define STATUS_MEMBER_IN_ALIAS ((NTSTATUS)0xC0000153L) +#define STATUS_ALIAS_EXISTS ((NTSTATUS)0xC0000154L) +#define STATUS_LOGON_NOT_GRANTED ((NTSTATUS)0xC0000155L) +#define STATUS_TOO_MANY_SECRETS ((NTSTATUS)0xC0000156L) +#define STATUS_SECRET_TOO_LONG ((NTSTATUS)0xC0000157L) +#define STATUS_INTERNAL_DB_ERROR ((NTSTATUS)0xC0000158L) +#define STATUS_FULLSCREEN_MODE ((NTSTATUS)0xC0000159L) +#define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS)0xC000015AL) +#define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS)0xC000015BL) +#define STATUS_NOT_REGISTRY_FILE ((NTSTATUS)0xC000015CL) +#define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS)0xC000015DL) +#define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS)0xC000015EL) +#define STATUS_FT_MISSING_MEMBER ((NTSTATUS)0xC000015FL) +#define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS)0xC0000160L) +#define STATUS_ILLEGAL_CHARACTER ((NTSTATUS)0xC0000161L) +#define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS)0xC0000162L) +#define STATUS_UNDEFINED_CHARACTER ((NTSTATUS)0xC0000163L) +#define STATUS_FLOPPY_VOLUME ((NTSTATUS)0xC0000164L) +#define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS)0xC0000165L) +#define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS)0xC0000166L) +#define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS)0xC0000167L) +#define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS)0xC0000168L) +#define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS)0xC0000169L) +#define STATUS_DISK_OPERATION_FAILED ((NTSTATUS)0xC000016AL) +#define STATUS_DISK_RESET_FAILED ((NTSTATUS)0xC000016BL) +#define STATUS_SHARED_IRQ_BUSY ((NTSTATUS)0xC000016CL) +#define STATUS_FT_ORPHANING ((NTSTATUS)0xC000016DL) +#define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS)0xC000016EL) +#define STATUS_PARTITION_FAILURE ((NTSTATUS)0xC0000172L) +#define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS)0xC0000173L) +#define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS)0xC0000174L) +#define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS)0xC0000175L) +#define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS)0xC0000176L) +#define STATUS_EOM_OVERFLOW ((NTSTATUS)0xC0000177L) +#define STATUS_NO_MEDIA ((NTSTATUS)0xC0000178L) +#define STATUS_NO_SUCH_MEMBER ((NTSTATUS)0xC000017AL) +#define STATUS_INVALID_MEMBER ((NTSTATUS)0xC000017BL) +#define STATUS_KEY_DELETED ((NTSTATUS)0xC000017CL) +#define STATUS_NO_LOG_SPACE ((NTSTATUS)0xC000017DL) +#define STATUS_TOO_MANY_SIDS ((NTSTATUS)0xC000017EL) +#define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS)0xC000017FL) +#define STATUS_KEY_HAS_CHILDREN ((NTSTATUS)0xC0000180L) +#define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS)0xC0000181L) +#define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS)0xC0000182L) +#define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS)0xC0000183L) +#define STATUS_INVALID_DEVICE_STATE ((NTSTATUS)0xC0000184L) +#define STATUS_IO_DEVICE_ERROR ((NTSTATUS)0xC0000185L) +#define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS)0xC0000186L) +#define STATUS_BACKUP_CONTROLLER ((NTSTATUS)0xC0000187L) +#define STATUS_LOG_FILE_FULL ((NTSTATUS)0xC0000188L) +#define STATUS_TOO_LATE ((NTSTATUS)0xC0000189L) +#define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS)0xC000018AL) +#define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS)0xC000018BL) +#define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS)0xC000018CL) +#define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS)0xC000018DL) +#define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS)0xC000018EL) +#define STATUS_EVENTLOG_CANT_START ((NTSTATUS)0xC000018FL) +#define STATUS_TRUST_FAILURE ((NTSTATUS)0xC0000190L) +#define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS)0xC0000191L) +#define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS)0xC0000192L) +#define STATUS_ACCOUNT_EXPIRED ((NTSTATUS)0xC0000193L) +#define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS)0xC0000194L) +#define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS)0xC0000195L) +#define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS)0xC0000196L) +#define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS)0xC0000197L) +#define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS)0xC0000198L) +#define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS)0xC0000199L) +#define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS)0xC000019AL) +#define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS)0xC000019BL) +#define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS)0xC000019CL) +#define STATUS_NO_USER_SESSION_KEY ((NTSTATUS)0xC0000202L) +#define STATUS_USER_SESSION_DELETED ((NTSTATUS)0xC0000203L) +#define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS)0xC0000204L) +#define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS)0xC0000205L) +#define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS)0xC0000206L) +#define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS)0xC0000207L) +#define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS)0xC0000208L) +#define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS)0xC0000209L) +#define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS)0xC000020AL) +#define STATUS_ADDRESS_CLOSED ((NTSTATUS)0xC000020BL) +#define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS)0xC000020CL) +#define STATUS_CONNECTION_RESET ((NTSTATUS)0xC000020DL) +#define STATUS_TOO_MANY_NODES ((NTSTATUS)0xC000020EL) +#define STATUS_TRANSACTION_ABORTED ((NTSTATUS)0xC000020FL) +#define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS)0xC0000210L) +#define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS)0xC0000211L) +#define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS)0xC0000212L) +#define STATUS_TRANSACTION_RESPONDED ((NTSTATUS)0xC0000213L) +#define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS)0xC0000214L) +#define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS)0xC0000215L) +#define STATUS_NOT_SERVER_SESSION ((NTSTATUS)0xC0000216L) +#define STATUS_NOT_CLIENT_SESSION ((NTSTATUS)0xC0000217L) +#define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS)0xC0000218L) +#define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS)0xC0000219L) +#define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS)0xC000021AL) +#define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS)0xC000021BL) +#define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS)0xC000021CL) +#define STATUS_VDM_HARD_ERROR ((NTSTATUS)0xC000021DL) +#define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS)0xC000021EL) +#define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS)0xC000021FL) +#define STATUS_MAPPED_ALIGNMENT ((NTSTATUS)0xC0000220L) +#define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS)0xC0000221L) +#define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS)0xC0000222L) +#define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS)0xC0000223L) +#define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS)0xC0000224L) +#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) +#define STATUS_NOT_TINY_STREAM ((NTSTATUS)0xC0000226L) +#define STATUS_RECOVERY_FAILURE ((NTSTATUS)0xC0000227L) +#define STATUS_STACK_OVERFLOW_READ ((NTSTATUS)0xC0000228L) +#define STATUS_FAIL_CHECK ((NTSTATUS)0xC0000229L) +#define STATUS_DUPLICATE_OBJECTID ((NTSTATUS)0xC000022AL) +#define STATUS_OBJECTID_EXISTS ((NTSTATUS)0xC000022BL) +#define STATUS_CONVERT_TO_LARGE ((NTSTATUS)0xC000022CL) +#define STATUS_RETRY ((NTSTATUS)0xC000022DL) +#define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS)0xC000022EL) +#define STATUS_ALLOCATE_BUCKET ((NTSTATUS)0xC000022FL) +#define STATUS_PROPSET_NOT_FOUND ((NTSTATUS)0xC0000230L) +#define STATUS_MARSHALL_OVERFLOW ((NTSTATUS)0xC0000231L) +#define STATUS_INVALID_VARIANT ((NTSTATUS)0xC0000232L) +#define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS)0xC0000233L) +#define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS)0xC0000234L) +#define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS)0xC0000235L) +#define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L) +#define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS)0xC0000237L) +#define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS)0xC0000238L) +#define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS)0xC0000239L) +#define STATUS_CONNECTION_INVALID ((NTSTATUS)0xC000023AL) +#define STATUS_CONNECTION_ACTIVE ((NTSTATUS)0xC000023BL) +#define STATUS_NETWORK_UNREACHABLE ((NTSTATUS)0xC000023CL) +#define STATUS_HOST_UNREACHABLE ((NTSTATUS)0xC000023DL) +#define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS)0xC000023EL) +#define STATUS_PORT_UNREACHABLE ((NTSTATUS)0xC000023FL) +#define STATUS_REQUEST_ABORTED ((NTSTATUS)0xC0000240L) +#define STATUS_CONNECTION_ABORTED ((NTSTATUS)0xC0000241L) +#define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS)0xC0000242L) +#define STATUS_USER_MAPPED_FILE ((NTSTATUS)0xC0000243L) +#define STATUS_AUDIT_FAILED ((NTSTATUS)0xC0000244L) +#define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS)0xC0000245L) +#define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS)0xC0000246L) +#define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS)0xC0000247L) +#define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS)0xC0000248L) +#define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS)0xC0000249L) +#define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS)0xC0000250L) +#define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS)0xC0000251L) +#define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS)0xC0000252L) +#define STATUS_LPC_REPLY_LOST ((NTSTATUS)0xC0000253L) +#define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS)0xC0000254L) +#define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS)0xC0000255L) +#define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS)0xC0000256L) +#define STATUS_PATH_NOT_COVERED ((NTSTATUS)0xC0000257L) +#define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS)0xC0000258L) +#define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS)0xC0000259L) +#define STATUS_PWD_TOO_SHORT ((NTSTATUS)0xC000025AL) +#define STATUS_PWD_TOO_RECENT ((NTSTATUS)0xC000025BL) +#define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS)0xC000025CL) +#define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS)0xC000025EL) +#define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS)0xC000025FL) +#define STATUS_INVALID_HW_PROFILE ((NTSTATUS)0xC0000260L) +#define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS)0xC0000261L) +#define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS)0xC0000262L) +#define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS)0xC0000263L) +#define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS)0xC0000264L) +#define STATUS_TOO_MANY_LINKS ((NTSTATUS)0xC0000265L) +#define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS)0xC0000266L) +#define STATUS_FILE_IS_OFFLINE ((NTSTATUS)0xC0000267L) +#define STATUS_EVALUATION_EXPIRATION ((NTSTATUS)0xC0000268L) +#define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS)0xC0000269L) +#define STATUS_LICENSE_VIOLATION ((NTSTATUS)0xC000026AL) +#define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS)0xC000026BL) +#define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS)0xC000026CL) +#define STATUS_DFS_UNAVAILABLE ((NTSTATUS)0xC000026DL) +#define STATUS_VOLUME_DISMOUNTED ((NTSTATUS)0xC000026EL) +#define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS)0xC000026FL) +#define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS)0xC0000270L) +#define STATUS_VALIDATE_CONTINUE ((NTSTATUS)0xC0000271L) +#define STATUS_NO_MATCH ((NTSTATUS)0xC0000272L) +#define STATUS_NO_MORE_MATCHES ((NTSTATUS)0xC0000273L) +#define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS)0xC0000275L) +#define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS)0xC0000276L) +#define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS)0xC0000277L) +#define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS)0xC0000278L) +#define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS)0xC0000279L) +#define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS)0xC0000280L) +#define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS)0xC0000281L) +#define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS)0xC0000282L) +#define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS)0xC0000283L) +#define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS)0xC0000284L) +#define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS)0xC0000285L) +#define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS)0xC0000286L) +#define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS)0xC0000287L) +#define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS)0x80000288L) +#define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS)0x80000289L) +#define STATUS_ENCRYPTION_FAILED ((NTSTATUS)0xC000028AL) +#define STATUS_DECRYPTION_FAILED ((NTSTATUS)0xC000028BL) +#define STATUS_RANGE_NOT_FOUND ((NTSTATUS)0xC000028CL) +#define STATUS_NO_RECOVERY_POLICY ((NTSTATUS)0xC000028DL) +#define STATUS_NO_EFS ((NTSTATUS)0xC000028EL) +#define STATUS_WRONG_EFS ((NTSTATUS)0xC000028FL) +#define STATUS_NO_USER_KEYS ((NTSTATUS)0xC0000290L) +#define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS)0xC0000291L) +#define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS)0xC0000292L) +#define STATUS_FILE_ENCRYPTED ((NTSTATUS)0xC0000293L) +#define STATUS_WAKE_SYSTEM ((NTSTATUS)0x40000294L) +#define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS)0xC0000295L) +#define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS)0xC0000296L) +#define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS)0xC0000297L) +#define STATUS_WMI_TRY_AGAIN ((NTSTATUS)0xC0000298L) +#define STATUS_SHARED_POLICY ((NTSTATUS)0xC0000299L) +#define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS)0xC000029AL) +#define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS)0xC000029BL) +#define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS)0xC000029CL) +#define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS)0xC000029DL) +#define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS)0xC000029EL) +#define STATUS_NO_TRACKING_SERVICE ((NTSTATUS)0xC000029FL) +#define STATUS_SERVER_SID_MISMATCH ((NTSTATUS)0xC00002A0L) +#define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS)0xC00002A1L) +#define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS)0xC00002A2L) +#define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS)0xC00002A3L) +#define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS)0xC00002A4L) +#define STATUS_DS_BUSY ((NTSTATUS)0xC00002A5L) +#define STATUS_DS_UNAVAILABLE ((NTSTATUS)0xC00002A6L) +#define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS)0xC00002A7L) +#define STATUS_DS_NO_MORE_RIDS ((NTSTATUS)0xC00002A8L) +#define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS)0xC00002A9L) +#define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS)0xC00002AAL) +#define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS)0xC00002ABL) +#define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS)0xC00002ACL) +#define STATUS_DS_CANT_ON_RDN ((NTSTATUS)0xC00002ADL) +#define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS)0xC00002AEL) +#define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS)0xC00002AFL) +#define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS)0xC00002B0L) +#define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS)0xC00002B1L) +#define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS)0xC00002B2L) +#define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS)0xC00002B3L) +#define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS)0xC00002B4L) +#define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS)0xC00002B5L) +#define STATUS_DEVICE_REMOVED ((NTSTATUS)0xC00002B6L) +#define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS)0xC00002B7L) +#define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS)0xC00002B8L) +#define STATUS_NOINTERFACE ((NTSTATUS)0xC00002B9L) +#define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS)0xC00002C1L) +#define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS)0xC00002C2L) +#define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS)0xC00002C3L) +#define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS)0xC00002C4L) +#define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS)0xC00002C5L) +#define STATUS_WMI_READ_ONLY ((NTSTATUS)0xC00002C6L) +#define STATUS_WMI_SET_FAILURE ((NTSTATUS)0xC00002C7L) +#define STATUS_COMMITMENT_MINIMUM ((NTSTATUS)0xC00002C8L) +#define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS)0xC00002C9L) +#define STATUS_TRANSPORT_FULL ((NTSTATUS)0xC00002CAL) +#define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS)0xC00002CBL) +#define STATUS_ONLY_IF_CONNECTED ((NTSTATUS)0xC00002CCL) +#define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS)0xC00002CDL) +#define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS)0xC00002CEL) +#define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS)0xC00002CFL) +#define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS)0xC00002D0L) +#define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS)0xC00002D1L) +#define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS)0xC00002D2L) +#define STATUS_POWER_STATE_INVALID ((NTSTATUS)0xC00002D3L) +#define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS)0xC00002D4L) +#define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS)0xC00002D5L) +#define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS)0xC00002D6L) +#define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS)0xC00002D7L) +#define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS)0xC00002D8L) +#define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS)0xC00002D9L) +#define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS)0xC00002DAL) +#define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS)0xC00002DBL) +#define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS)0xC00002DCL) +#define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS)0xC00002DDL) +#define STATUS_INSUFFICIENT_POWER ((NTSTATUS)0xC00002DEL) +#define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS)0xC00002DFL) +#define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS)0xC00002E0L) +#define STATUS_DS_CANT_START ((NTSTATUS)0xC00002E1L) +#define STATUS_DS_INIT_FAILURE ((NTSTATUS)0xC00002E2L) +#define STATUS_SAM_INIT_FAILURE ((NTSTATUS)0xC00002E3L) +#define STATUS_DS_GC_REQUIRED ((NTSTATUS)0xC00002E4L) +#define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS)0xC00002E5L) +#define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS)0xC00002E6L) +#define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS)0xC00002E7L) +#define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS)0xC00002E8L) +#define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS)0xC00002E9L) +#define STATUS_CANNOT_MAKE ((NTSTATUS)0xC00002EAL) +#define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS)0xC00002EBL) +#define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS)0xC00002ECL) +#define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS)0xC00002EDL) +#define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS)0xC00002EEL) +#define STATUS_NO_TGT_REPLY ((NTSTATUS)0xC00002EFL) +#define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS)0xC00002F0L) +#define STATUS_NO_IP_ADDRESSES ((NTSTATUS)0xC00002F1L) +#define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS)0xC00002F2L) +#define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS)0xC00002F3L) +#define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS)0xC00002F4L) +#define STATUS_MUST_BE_KDC ((NTSTATUS)0xC00002F5L) +#define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS)0xC00002F6L) +#define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS)0xC00002F7L) +#define STATUS_NO_PA_DATA ((NTSTATUS)0xC00002F8L) +#define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS)0xC00002F9L) +#define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS)0xC00002FAL) +#define STATUS_KDC_INVALID_REQUEST ((NTSTATUS)0xC00002FBL) +#define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS)0xC00002FCL) +#define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS)0xC00002FDL) +#define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS)0xC00002FEL) +#define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS)0xC00002FFL) +#define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS)0xC0000300L) +#define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS)0xC0000301L) +#define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS)0xC0000302L) +#define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS)0xC0000303L) +#define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS)0xC0000304L) +#define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS)0xC0000305L) +#define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS)0xC0000306L) +#define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS)0xC0000307L) +#define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS)0xC0000308L) +#define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS)0xC0000309L) +#define STATUS_CSS_REGION_MISMATCH ((NTSTATUS)0xC000030AL) +#define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS)0xC000030BL) +#define STATUS_PKINIT_FAILURE ((NTSTATUS)0xC0000320L) +#define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS)0xC0000321L) +#define STATUS_NO_KERB_KEY ((NTSTATUS)0xC0000322L) +#define STATUS_HOST_DOWN ((NTSTATUS)0xC0000350L) +#define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS)0xC0000351L) +#define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS)0xC0000352L) +#define STATUS_PORT_NOT_SET ((NTSTATUS)0xC0000353L) +#define STATUS_DEBUGGER_INACTIVE ((NTSTATUS)0xC0000354L) +#define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS)0xC0000355L) +#define STATUS_AUDITING_DISABLED ((NTSTATUS)0xC0000356L) +#define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS)0xC0000357L) +#define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS)0xC0000358L) +#define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS)0xC0000359L) +#define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS)0xC000035AL) +#define STATUS_BAD_BINDINGS ((NTSTATUS)0xC000035BL) +#define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS)0xC000035CL) +#define STATUS_APPHELP_BLOCK ((NTSTATUS)0xC000035DL) +#define STATUS_ALL_SIDS_FILTERED ((NTSTATUS)0xC000035EL) +#define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS)0xC000035FL) +#define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS)0xC0000361L) +#define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS)0xC0000362L) +#define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS)0xC0000363L) +#define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS)0xC0000364L) +#define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS)0xC0000365L) +#define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS)0xC0000366L) +#define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS)0x00000367L) +#define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS)0xC0000368L) +#define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS)0xC0000369L) +#define STATUS_MCA_OCCURED ((NTSTATUS)0xC000036AL) +#define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS)0xC000036BL) +#define STATUS_DRIVER_BLOCKED ((NTSTATUS)0xC000036CL) +#define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS)0xC000036DL) +#define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS)0xC000036EL) +#define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS)0xC000036FL) +#define STATUS_DS_SHUTTING_DOWN ((NTSTATUS)0x40000370L) +#define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS)0xC0000380L) +#define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS)0xC0000381L) +#define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS)0xC0000382L) +#define STATUS_SMARTCARD_NO_CARD ((NTSTATUS)0xC0000383L) +#define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS)0xC0000384L) +#define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS)0xC0000385L) +#define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS)0xC0000386L) +#define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS)0xC0000387L) +#define STATUS_DOWNGRADE_DETECTED ((NTSTATUS)0xC0000388L) +#define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS)0xC0000389L) +#define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS)0xC000038AL) +#define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS)0xC000038BL) +#define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS)0xC000038CL) +#define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS)0xC000038DL) +#define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS)0xC000038EL) +#define STATUS_WOW_ASSERTION ((NTSTATUS)0xC0009898L) +#define RPC_NT_INVALID_STRING_BINDING ((NTSTATUS)0xC0020001L) +#define RPC_NT_WRONG_KIND_OF_BINDING ((NTSTATUS)0xC0020002L) +#define RPC_NT_INVALID_BINDING ((NTSTATUS)0xC0020003L) +#define RPC_NT_PROTSEQ_NOT_SUPPORTED ((NTSTATUS)0xC0020004L) +#define RPC_NT_INVALID_RPC_PROTSEQ ((NTSTATUS)0xC0020005L) +#define RPC_NT_INVALID_STRING_UUID ((NTSTATUS)0xC0020006L) +#define RPC_NT_INVALID_ENDPOINT_FORMAT ((NTSTATUS)0xC0020007L) +#define RPC_NT_INVALID_NET_ADDR ((NTSTATUS)0xC0020008L) +#define RPC_NT_NO_ENDPOINT_FOUND ((NTSTATUS)0xC0020009L) +#define RPC_NT_INVALID_TIMEOUT ((NTSTATUS)0xC002000AL) +#define RPC_NT_OBJECT_NOT_FOUND ((NTSTATUS)0xC002000BL) +#define RPC_NT_ALREADY_REGISTERED ((NTSTATUS)0xC002000CL) +#define RPC_NT_TYPE_ALREADY_REGISTERED ((NTSTATUS)0xC002000DL) +#define RPC_NT_ALREADY_LISTENING ((NTSTATUS)0xC002000EL) +#define RPC_NT_NO_PROTSEQS_REGISTERED ((NTSTATUS)0xC002000FL) +#define RPC_NT_NOT_LISTENING ((NTSTATUS)0xC0020010L) +#define RPC_NT_UNKNOWN_MGR_TYPE ((NTSTATUS)0xC0020011L) +#define RPC_NT_UNKNOWN_IF ((NTSTATUS)0xC0020012L) +#define RPC_NT_NO_BINDINGS ((NTSTATUS)0xC0020013L) +#define RPC_NT_NO_PROTSEQS ((NTSTATUS)0xC0020014L) +#define RPC_NT_CANT_CREATE_ENDPOINT ((NTSTATUS)0xC0020015L) +#define RPC_NT_OUT_OF_RESOURCES ((NTSTATUS)0xC0020016L) +#define RPC_NT_SERVER_UNAVAILABLE ((NTSTATUS)0xC0020017L) +#define RPC_NT_SERVER_TOO_BUSY ((NTSTATUS)0xC0020018L) +#define RPC_NT_INVALID_NETWORK_OPTIONS ((NTSTATUS)0xC0020019L) +#define RPC_NT_NO_CALL_ACTIVE ((NTSTATUS)0xC002001AL) +#define RPC_NT_CALL_FAILED ((NTSTATUS)0xC002001BL) +#define RPC_NT_CALL_FAILED_DNE ((NTSTATUS)0xC002001CL) +#define RPC_NT_PROTOCOL_ERROR ((NTSTATUS)0xC002001DL) +#define RPC_NT_UNSUPPORTED_TRANS_SYN ((NTSTATUS)0xC002001FL) +#define RPC_NT_UNSUPPORTED_TYPE ((NTSTATUS)0xC0020021L) +#define RPC_NT_INVALID_TAG ((NTSTATUS)0xC0020022L) +#define RPC_NT_INVALID_BOUND ((NTSTATUS)0xC0020023L) +#define RPC_NT_NO_ENTRY_NAME ((NTSTATUS)0xC0020024L) +#define RPC_NT_INVALID_NAME_SYNTAX ((NTSTATUS)0xC0020025L) +#define RPC_NT_UNSUPPORTED_NAME_SYNTAX ((NTSTATUS)0xC0020026L) +#define RPC_NT_UUID_NO_ADDRESS ((NTSTATUS)0xC0020028L) +#define RPC_NT_DUPLICATE_ENDPOINT ((NTSTATUS)0xC0020029L) +#define RPC_NT_UNKNOWN_AUTHN_TYPE ((NTSTATUS)0xC002002AL) +#define RPC_NT_MAX_CALLS_TOO_SMALL ((NTSTATUS)0xC002002BL) +#define RPC_NT_STRING_TOO_LONG ((NTSTATUS)0xC002002CL) +#define RPC_NT_PROTSEQ_NOT_FOUND ((NTSTATUS)0xC002002DL) +#define RPC_NT_PROCNUM_OUT_OF_RANGE ((NTSTATUS)0xC002002EL) +#define RPC_NT_BINDING_HAS_NO_AUTH ((NTSTATUS)0xC002002FL) +#define RPC_NT_UNKNOWN_AUTHN_SERVICE ((NTSTATUS)0xC0020030L) +#define RPC_NT_UNKNOWN_AUTHN_LEVEL ((NTSTATUS)0xC0020031L) +#define RPC_NT_INVALID_AUTH_IDENTITY ((NTSTATUS)0xC0020032L) +#define RPC_NT_UNKNOWN_AUTHZ_SERVICE ((NTSTATUS)0xC0020033L) +#define EPT_NT_INVALID_ENTRY ((NTSTATUS)0xC0020034L) +#define EPT_NT_CANT_PERFORM_OP ((NTSTATUS)0xC0020035L) +#define EPT_NT_NOT_REGISTERED ((NTSTATUS)0xC0020036L) +#define RPC_NT_NOTHING_TO_EXPORT ((NTSTATUS)0xC0020037L) +#define RPC_NT_INCOMPLETE_NAME ((NTSTATUS)0xC0020038L) +#define RPC_NT_INVALID_VERS_OPTION ((NTSTATUS)0xC0020039L) +#define RPC_NT_NO_MORE_MEMBERS ((NTSTATUS)0xC002003AL) +#define RPC_NT_NOT_ALL_OBJS_UNEXPORTED ((NTSTATUS)0xC002003BL) +#define RPC_NT_INTERFACE_NOT_FOUND ((NTSTATUS)0xC002003CL) +#define RPC_NT_ENTRY_ALREADY_EXISTS ((NTSTATUS)0xC002003DL) +#define RPC_NT_ENTRY_NOT_FOUND ((NTSTATUS)0xC002003EL) +#define RPC_NT_NAME_SERVICE_UNAVAILABLE ((NTSTATUS)0xC002003FL) +#define RPC_NT_INVALID_NAF_ID ((NTSTATUS)0xC0020040L) +#define RPC_NT_CANNOT_SUPPORT ((NTSTATUS)0xC0020041L) +#define RPC_NT_NO_CONTEXT_AVAILABLE ((NTSTATUS)0xC0020042L) +#define RPC_NT_INTERNAL_ERROR ((NTSTATUS)0xC0020043L) +#define RPC_NT_ZERO_DIVIDE ((NTSTATUS)0xC0020044L) +#define RPC_NT_ADDRESS_ERROR ((NTSTATUS)0xC0020045L) +#define RPC_NT_FP_DIV_ZERO ((NTSTATUS)0xC0020046L) +#define RPC_NT_FP_UNDERFLOW ((NTSTATUS)0xC0020047L) +#define RPC_NT_FP_OVERFLOW ((NTSTATUS)0xC0020048L) +#define RPC_NT_NO_MORE_ENTRIES ((NTSTATUS)0xC0030001L) +#define RPC_NT_SS_CHAR_TRANS_OPEN_FAIL ((NTSTATUS)0xC0030002L) +#define RPC_NT_SS_CHAR_TRANS_SHORT_FILE ((NTSTATUS)0xC0030003L) +#define RPC_NT_SS_IN_NULL_CONTEXT ((NTSTATUS)0xC0030004L) +#define RPC_NT_SS_CONTEXT_MISMATCH ((NTSTATUS)0xC0030005L) +#define RPC_NT_SS_CONTEXT_DAMAGED ((NTSTATUS)0xC0030006L) +#define RPC_NT_SS_HANDLES_MISMATCH ((NTSTATUS)0xC0030007L) +#define RPC_NT_SS_CANNOT_GET_CALL_HANDLE ((NTSTATUS)0xC0030008L) +#define RPC_NT_NULL_REF_POINTER ((NTSTATUS)0xC0030009L) +#define RPC_NT_ENUM_VALUE_OUT_OF_RANGE ((NTSTATUS)0xC003000AL) +#define RPC_NT_BYTE_COUNT_TOO_SMALL ((NTSTATUS)0xC003000BL) +#define RPC_NT_BAD_STUB_DATA ((NTSTATUS)0xC003000CL) +#define RPC_NT_CALL_IN_PROGRESS ((NTSTATUS)0xC0020049L) +#define RPC_NT_NO_MORE_BINDINGS ((NTSTATUS)0xC002004AL) +#define RPC_NT_GROUP_MEMBER_NOT_FOUND ((NTSTATUS)0xC002004BL) +#define EPT_NT_CANT_CREATE ((NTSTATUS)0xC002004CL) +#define RPC_NT_INVALID_OBJECT ((NTSTATUS)0xC002004DL) +#define RPC_NT_NO_INTERFACES ((NTSTATUS)0xC002004FL) +#define RPC_NT_CALL_CANCELLED ((NTSTATUS)0xC0020050L) +#define RPC_NT_BINDING_INCOMPLETE ((NTSTATUS)0xC0020051L) +#define RPC_NT_COMM_FAILURE ((NTSTATUS)0xC0020052L) +#define RPC_NT_UNSUPPORTED_AUTHN_LEVEL ((NTSTATUS)0xC0020053L) +#define RPC_NT_NO_PRINC_NAME ((NTSTATUS)0xC0020054L) +#define RPC_NT_NOT_RPC_ERROR ((NTSTATUS)0xC0020055L) +#define RPC_NT_UUID_LOCAL_ONLY ((NTSTATUS)0x40020056L) +#define RPC_NT_SEC_PKG_ERROR ((NTSTATUS)0xC0020057L) +#define RPC_NT_NOT_CANCELLED ((NTSTATUS)0xC0020058L) +#define RPC_NT_INVALID_ES_ACTION ((NTSTATUS)0xC0030059L) +#define RPC_NT_WRONG_ES_VERSION ((NTSTATUS)0xC003005AL) +#define RPC_NT_WRONG_STUB_VERSION ((NTSTATUS)0xC003005BL) +#define RPC_NT_INVALID_PIPE_OBJECT ((NTSTATUS)0xC003005CL) +#define RPC_NT_INVALID_PIPE_OPERATION ((NTSTATUS)0xC003005DL) +#define RPC_NT_WRONG_PIPE_VERSION ((NTSTATUS)0xC003005EL) +#define RPC_NT_PIPE_CLOSED ((NTSTATUS)0xC003005FL) +#define RPC_NT_PIPE_DISCIPLINE_ERROR ((NTSTATUS)0xC0030060L) +#define RPC_NT_PIPE_EMPTY ((NTSTATUS)0xC0030061L) +#define RPC_NT_INVALID_ASYNC_HANDLE ((NTSTATUS)0xC0020062L) +#define RPC_NT_INVALID_ASYNC_CALL ((NTSTATUS)0xC0020063L) +#define RPC_NT_SEND_INCOMPLETE ((NTSTATUS)0x400200AFL) +#define STATUS_ACPI_INVALID_OPCODE ((NTSTATUS)0xC0140001L) +#define STATUS_ACPI_STACK_OVERFLOW ((NTSTATUS)0xC0140002L) +#define STATUS_ACPI_ASSERT_FAILED ((NTSTATUS)0xC0140003L) +#define STATUS_ACPI_INVALID_INDEX ((NTSTATUS)0xC0140004L) +#define STATUS_ACPI_INVALID_ARGUMENT ((NTSTATUS)0xC0140005L) +#define STATUS_ACPI_FATAL ((NTSTATUS)0xC0140006L) +#define STATUS_ACPI_INVALID_SUPERNAME ((NTSTATUS)0xC0140007L) +#define STATUS_ACPI_INVALID_ARGTYPE ((NTSTATUS)0xC0140008L) +#define STATUS_ACPI_INVALID_OBJTYPE ((NTSTATUS)0xC0140009L) +#define STATUS_ACPI_INVALID_TARGETTYPE ((NTSTATUS)0xC014000AL) +#define STATUS_ACPI_INCORRECT_ARGUMENT_COUNT ((NTSTATUS)0xC014000BL) +#define STATUS_ACPI_ADDRESS_NOT_MAPPED ((NTSTATUS)0xC014000CL) +#define STATUS_ACPI_INVALID_EVENTTYPE ((NTSTATUS)0xC014000DL) +#define STATUS_ACPI_HANDLER_COLLISION ((NTSTATUS)0xC014000EL) +#define STATUS_ACPI_INVALID_DATA ((NTSTATUS)0xC014000FL) +#define STATUS_ACPI_INVALID_REGION ((NTSTATUS)0xC0140010L) +#define STATUS_ACPI_INVALID_ACCESS_SIZE ((NTSTATUS)0xC0140011L) +#define STATUS_ACPI_ACQUIRE_GLOBAL_LOCK ((NTSTATUS)0xC0140012L) +#define STATUS_ACPI_ALREADY_INITIALIZED ((NTSTATUS)0xC0140013L) +#define STATUS_ACPI_NOT_INITIALIZED ((NTSTATUS)0xC0140014L) +#define STATUS_ACPI_INVALID_MUTEX_LEVEL ((NTSTATUS)0xC0140015L) +#define STATUS_ACPI_MUTEX_NOT_OWNED ((NTSTATUS)0xC0140016L) +#define STATUS_ACPI_MUTEX_NOT_OWNER ((NTSTATUS)0xC0140017L) +#define STATUS_ACPI_RS_ACCESS ((NTSTATUS)0xC0140018L) +#define STATUS_ACPI_INVALID_TABLE ((NTSTATUS)0xC0140019L) +#define STATUS_ACPI_REG_HANDLER_FAILED ((NTSTATUS)0xC0140020L) +#define STATUS_ACPI_POWER_REQUEST_FAILED ((NTSTATUS)0xC0140021L) +#define STATUS_CTX_WINSTATION_NAME_INVALID ((NTSTATUS)0xC00A0001L) +#define STATUS_CTX_INVALID_PD ((NTSTATUS)0xC00A0002L) +#define STATUS_CTX_PD_NOT_FOUND ((NTSTATUS)0xC00A0003L) +#define STATUS_CTX_CDM_CONNECT ((NTSTATUS)0x400A0004L) +#define STATUS_CTX_CDM_DISCONNECT ((NTSTATUS)0x400A0005L) +#define STATUS_CTX_CLOSE_PENDING ((NTSTATUS)0xC00A0006L) +#define STATUS_CTX_NO_OUTBUF ((NTSTATUS)0xC00A0007L) +#define STATUS_CTX_MODEM_INF_NOT_FOUND ((NTSTATUS)0xC00A0008L) +#define STATUS_CTX_INVALID_MODEMNAME ((NTSTATUS)0xC00A0009L) +#define STATUS_CTX_RESPONSE_ERROR ((NTSTATUS)0xC00A000AL) +#define STATUS_CTX_MODEM_RESPONSE_TIMEOUT ((NTSTATUS)0xC00A000BL) +#define STATUS_CTX_MODEM_RESPONSE_NO_CARRIER ((NTSTATUS)0xC00A000CL) +#define STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE ((NTSTATUS)0xC00A000DL) +#define STATUS_CTX_MODEM_RESPONSE_BUSY ((NTSTATUS)0xC00A000EL) +#define STATUS_CTX_MODEM_RESPONSE_VOICE ((NTSTATUS)0xC00A000FL) +#define STATUS_CTX_TD_ERROR ((NTSTATUS)0xC00A0010L) +#define STATUS_CTX_LICENSE_CLIENT_INVALID ((NTSTATUS)0xC00A0012L) +#define STATUS_CTX_LICENSE_NOT_AVAILABLE ((NTSTATUS)0xC00A0013L) +#define STATUS_CTX_LICENSE_EXPIRED ((NTSTATUS)0xC00A0014L) +#define STATUS_CTX_WINSTATION_NOT_FOUND ((NTSTATUS)0xC00A0015L) +#define STATUS_CTX_WINSTATION_NAME_COLLISION ((NTSTATUS)0xC00A0016L) +#define STATUS_CTX_WINSTATION_BUSY ((NTSTATUS)0xC00A0017L) +#define STATUS_CTX_BAD_VIDEO_MODE ((NTSTATUS)0xC00A0018L) +#define STATUS_CTX_GRAPHICS_INVALID ((NTSTATUS)0xC00A0022L) +#define STATUS_CTX_NOT_CONSOLE ((NTSTATUS)0xC00A0024L) +#define STATUS_CTX_CLIENT_QUERY_TIMEOUT ((NTSTATUS)0xC00A0026L) +#define STATUS_CTX_CONSOLE_DISCONNECT ((NTSTATUS)0xC00A0027L) +#define STATUS_CTX_CONSOLE_CONNECT ((NTSTATUS)0xC00A0028L) +#define STATUS_CTX_SHADOW_DENIED ((NTSTATUS)0xC00A002AL) +#define STATUS_CTX_WINSTATION_ACCESS_DENIED ((NTSTATUS)0xC00A002BL) +#define STATUS_CTX_INVALID_WD ((NTSTATUS)0xC00A002EL) +#define STATUS_CTX_WD_NOT_FOUND ((NTSTATUS)0xC00A002FL) +#define STATUS_CTX_SHADOW_INVALID ((NTSTATUS)0xC00A0030L) +#define STATUS_CTX_SHADOW_DISABLED ((NTSTATUS)0xC00A0031L) +#define STATUS_RDP_PROTOCOL_ERROR ((NTSTATUS)0xC00A0032L) +#define STATUS_CTX_CLIENT_LICENSE_NOT_SET ((NTSTATUS)0xC00A0033L) +#define STATUS_CTX_CLIENT_LICENSE_IN_USE ((NTSTATUS)0xC00A0034L) +#define STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE ((NTSTATUS)0xC00A0035L) +#define STATUS_CTX_SHADOW_NOT_RUNNING ((NTSTATUS)0xC00A0036L) +#define STATUS_PNP_BAD_MPS_TABLE ((NTSTATUS)0xC0040035L) +#define STATUS_PNP_TRANSLATION_FAILED ((NTSTATUS)0xC0040036L) +#define STATUS_PNP_IRQ_TRANSLATION_FAILED ((NTSTATUS)0xC0040037L) +#define STATUS_SXS_SECTION_NOT_FOUND ((NTSTATUS)0xC0150001L) +#define STATUS_SXS_CANT_GEN_ACTCTX ((NTSTATUS)0xC0150002L) +#define STATUS_SXS_INVALID_ACTCTXDATA_FORMAT ((NTSTATUS)0xC0150003L) +#define STATUS_SXS_ASSEMBLY_NOT_FOUND ((NTSTATUS)0xC0150004L) +#define STATUS_SXS_MANIFEST_FORMAT_ERROR ((NTSTATUS)0xC0150005L) +#define STATUS_SXS_MANIFEST_PARSE_ERROR ((NTSTATUS)0xC0150006L) +#define STATUS_SXS_ACTIVATION_CONTEXT_DISABLED ((NTSTATUS)0xC0150007L) +#define STATUS_SXS_KEY_NOT_FOUND ((NTSTATUS)0xC0150008L) +#define STATUS_SXS_VERSION_CONFLICT ((NTSTATUS)0xC0150009L) +#define STATUS_SXS_WRONG_SECTION_TYPE ((NTSTATUS)0xC015000AL) +#define STATUS_SXS_THREAD_QUERIES_DISABLED ((NTSTATUS)0xC015000BL) +#define STATUS_SXS_ASSEMBLY_MISSING ((NTSTATUS)0xC015000CL) +#define STATUS_SXS_RELEASE_ACTIVATION_CONTEXT ((NTSTATUS)0x4015000DL) +#define STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET ((NTSTATUS)0xC015000EL) +#define STATUS_SXS_EARLY_DEACTIVATION ((NTSTATUS)0xC015000FL) +#define STATUS_SXS_INVALID_DEACTIVATION ((NTSTATUS)0xC0150010L) +#define STATUS_SXS_MULTIPLE_DEACTIVATION ((NTSTATUS)0xC0150011L) +#define STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY ((NTSTATUS)0xC0150012L) +#define STATUS_SXS_PROCESS_TERMINATION_REQUESTED ((NTSTATUS)0xC0150013L) +#define STATUS_CLUSTER_INVALID_NODE ((NTSTATUS)0xC0130001L) +#define STATUS_CLUSTER_NODE_EXISTS ((NTSTATUS)0xC0130002L) +#define STATUS_CLUSTER_JOIN_IN_PROGRESS ((NTSTATUS)0xC0130003L) +#define STATUS_CLUSTER_NODE_NOT_FOUND ((NTSTATUS)0xC0130004L) +#define STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND ((NTSTATUS)0xC0130005L) +#define STATUS_CLUSTER_NETWORK_EXISTS ((NTSTATUS)0xC0130006L) +#define STATUS_CLUSTER_NETWORK_NOT_FOUND ((NTSTATUS)0xC0130007L) +#define STATUS_CLUSTER_NETINTERFACE_EXISTS ((NTSTATUS)0xC0130008L) +#define STATUS_CLUSTER_NETINTERFACE_NOT_FOUND ((NTSTATUS)0xC0130009L) +#define STATUS_CLUSTER_INVALID_REQUEST ((NTSTATUS)0xC013000AL) +#define STATUS_CLUSTER_INVALID_NETWORK_PROVIDER ((NTSTATUS)0xC013000BL) +#define STATUS_CLUSTER_NODE_DOWN ((NTSTATUS)0xC013000CL) +#define STATUS_CLUSTER_NODE_UNREACHABLE ((NTSTATUS)0xC013000DL) +#define STATUS_CLUSTER_NODE_NOT_MEMBER ((NTSTATUS)0xC013000EL) +#define STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS ((NTSTATUS)0xC013000FL) +#define STATUS_CLUSTER_INVALID_NETWORK ((NTSTATUS)0xC0130010L) +#define STATUS_CLUSTER_NO_NET_ADAPTERS ((NTSTATUS)0xC0130011L) +#define STATUS_CLUSTER_NODE_UP ((NTSTATUS)0xC0130012L) +#define STATUS_CLUSTER_NODE_PAUSED ((NTSTATUS)0xC0130013L) +#define STATUS_CLUSTER_NODE_NOT_PAUSED ((NTSTATUS)0xC0130014L) +#define STATUS_CLUSTER_NO_SECURITY_CONTEXT ((NTSTATUS)0xC0130015L) +#define STATUS_CLUSTER_NETWORK_NOT_INTERNAL ((NTSTATUS)0xC0130016L) +#define STATUS_CLUSTER_POISONED ((NTSTATUS)0xC0130017L) + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif diff --git a/unifiedkernel/include/object.h b/unifiedkernel/include/object.h new file mode 100644 index 0000000..e9df0fa --- /dev/null +++ b/unifiedkernel/include/object.h @@ -0,0 +1,840 @@ +/* + * object.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2007 - Created. + */ + +/* + * object.h: win32 object definition + * Refered to ReactOS code + */ +#ifndef _OBJECT_H +#define _OBJECT_H + +#include +#include +#include "win32.h" +#include "ntstatus.h" + +#ifdef HAVE_SYS_POLL_H +#include +#endif + +#include "wineserver/list.h" +#include "wineserver/uk_protocol.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define POLL_NOTSIG 0 +#define POLL_SIG 1 + +#define OBJ_MAX_REPARSE_ATTEMPTS 16 + +#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\') + +/* Values for DosDeviceDriveType */ +#define DOSDEVICE_DRIVE_UNKNOWN 0 +#define DOSDEVICE_DRIVE_CALCULATE 1 +#define DOSDEVICE_DRIVE_REMOVABLE 2 +#define DOSDEVICE_DRIVE_FIXED 3 +#define DOSDEVICE_DRIVE_REMOTE 4 +#define DOSDEVICE_DRIVE_CDROM 5 +#define DOSDEVICE_DRIVE_RAMDISK 6 + +/* Object Flags */ +#define OB_FLAG_CREATE_INFO 0x01 +#define OB_FLAG_KERNEL_MODE 0x02 +#define OB_FLAG_CREATOR_INFO 0x04 +#define OB_FLAG_EXCLUSIVE 0x08 +#define OB_FLAG_PERMANENT 0x10 +#define OB_FLAG_SECURITY 0x20 +#define OB_FLAG_SINGLE_PROCESS 0x40 + +#define TRANSLATE_NAME 0x01 + +struct wait_table_entry; + +struct namespace; +struct object; +struct object_name; +struct w32thread; +struct w32process; +struct token; +struct file; +struct wait_queue_entry; +struct async; +struct async_queue; +struct winstation; +struct directory; + +struct unicode_str +{ + const WCHAR *str; + unsigned int len; +}; + +struct object_type; +extern struct object_type *no_get_type( struct object *obj ); + +/* operations valid on all objects */ +struct object_ops +{ + /* size of this object type */ + size_t size; + /* dump the object (for debugging) */ + void (*dump)(struct object *,int); + /* return the object type */ + struct object_type *(*get_type)(struct object *); + /* return an fd object that can be used to read/write from the object */ + struct fd *(*get_fd)(struct object *); + /* map access rights to the specific rights for this object */ + unsigned int (*map_access)(struct object *, unsigned int); + /* lookup a name if an object has a namespace */ + struct object *(*lookup_name)(struct object *, struct unicode_str *,unsigned int); + /* open a file object to access this object */ + struct object *(*open_file)(struct object *, unsigned int access, unsigned int sharing, + unsigned int options); + /* close a handle to this object */ + int (*close_handle)(struct object *,struct w32process *,obj_handle_t); + /* destroy on refcount == 0 */ + void (*destroy)(struct object *); +}; + +struct object +{ + struct dispatcher_header header; +#ifdef DEBUG_OBJECTS + struct list_head obj_list; +#endif +}; + +struct wait_queue_entry +{ + struct list_head entry; + void *obj; + struct w32thread *thread; +}; + +extern struct namespace *create_namespace( unsigned int hash_size ); + +extern void *create_named_object( HANDLE namespace, + const struct object_ops *ops, + const struct unicode_str *name, unsigned int attributes ); /* D.M. TBD */ +extern void unlink_named_object( struct object *obj ); +extern void *alloc_wine_object( const struct object_ops *ops ); +extern void make_object_static( struct object *obj ); + +extern struct object *find_object( HANDLE RootDirectory, const struct unicode_str *name, + unsigned int attributes ); +extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry ); +extern int no_satisfied( struct object *obj, struct w32thread *thread ); +extern int no_signal( struct object *obj, unsigned int access ); +extern struct fd *no_get_fd( struct object *obj ); +extern unsigned int no_map_access( struct object *obj, unsigned int access ); +extern struct object *no_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attributes ); +extern struct object *no_open_file( struct object *obj, unsigned int access, unsigned int sharing, unsigned int options ); +extern int no_close_handle( struct object *obj, struct w32process *process, obj_handle_t handle ); +extern void no_destroy( struct object *obj ); + +extern struct kevent *create_event( + struct directory *root, + const struct unicode_str *name, + unsigned int attr, + int manual_reset, + int initial_state, + const struct security_descriptor *sd + ); + +/* atom functions */ + +extern atom_t add_global_atom( struct winstation *winstation, const WCHAR *str, data_size_t len ); +extern atom_t find_global_atom( struct winstation *winstation, const WCHAR *str, data_size_t len ); +extern int grab_global_atom( struct winstation *winstation, atom_t atom ); +extern void release_global_atom( struct winstation *winstation, atom_t atom ); +extern void *open_object_dir( HANDLE root, const struct unicode_str *name, + unsigned int attr, const struct object_ops *ops ); +extern void *create_named_object_dir( HANDLE root, const struct unicode_str *name, + unsigned int attr, const struct object_ops *ops ); + +extern struct object *find_object_dir( HANDLE root, const struct unicode_str *name, unsigned int attr, struct unicode_str *name_left ); +extern obj_handle_t alloc_handle(struct w32process* proc, void* p, unsigned int access, int attr); + +/* symbolic link functions */ +extern struct symlink *create_symlink( struct directory *root, const struct unicode_str *name, + unsigned int attr, const struct unicode_str *target ); + +/* devices */ +extern void create_named_pipe_device( struct directory *root, const struct unicode_str *name ); +extern void create_mailslot_device( struct directory *root, const struct unicode_str *name ); + +enum kobject_type { + event_notification_object = 0, + event_synchronization_object = 1, + mutant_object = 2, + process_object = 3, + queue_object = 4, + semaphore_object = 5, + thread_object = 6, + gate_object = 7, + timer_notification_object = 8, + timer_synchronization_object = 9, + spare2_object = 10, + spare3_object = 11, + spare4_object = 12, + spare5_object = 13, + spare6_object = 14, + spare7_object = 15, + spare8_object = 16, + spare9_object = 17, + apc_object = 18, + dpc_object = 19, + device_queue_object = 20, + event_pair_object = 21, + interrupt_object = 22, + profile_object = 23, + threaded_dpc_object = 24, + max_kernel_object = 25 +}; + +/* FIXME */ +typedef PVOID PACCESS_STATE; + +/* System Initialization procedure for OB subcomponent */ +BOOLEAN init_object(VOID); + +VOID init_symbol_link(VOID); + +/* Object Manager types */ + +typedef struct _OBJECT_HANDLE_INFORMATION { + ULONG HandleAttributes; + ACCESS_MASK GrantedAccess; +} OBJECT_HANDLE_INFORMATION, *POBJECT_HANDLE_INFORMATION; + +typedef struct _OBJECT_DUMP_CONTROL { + PVOID Stream; + ULONG Detail; +} OB_DUMP_CONTROL, *POB_DUMP_CONTROL; + +typedef VOID (*OB_DUMP_METHOD)( + IN PVOID Object, + IN POB_DUMP_CONTROL Control OPTIONAL + ); + +typedef enum _OB_OPEN_REASON { + ObCreateHandle, + ObOpenHandle, + ObDuplicateHandle, + ObInheritHandle, + ObMaxOpenReason +} OB_OPEN_REASON; + +typedef VOID (*OB_CREATE_METHOD)( + IN PVOID Object, + IN PVOID Param + ); + +typedef VOID (*OB_OPEN_METHOD)( + IN OB_OPEN_REASON OpenReason, + IN struct eprocess* Process OPTIONAL, + IN PVOID Object, + IN ACCESS_MASK GrantedAccess, + IN ULONG HandleCount + ); + +typedef BOOLEAN (*OB_OKAYTOCLOSE_METHOD)( + IN struct eprocess* Process OPTIONAL, + IN PVOID Object, + IN HANDLE Handle + ); + +typedef VOID (*OB_CLOSE_METHOD)( + IN struct eprocess* Process OPTIONAL, + IN PVOID Object, + IN ACCESS_MASK GrantedAccess, + IN ULONG ProcessHandleCount, + IN ULONG SystemHandleCount + ); + +typedef VOID (*OB_DELETE_METHOD)( + IN PVOID Object + ); + +typedef NTSTATUS (*OB_PARSE_METHOD)( + IN PVOID ParseObject, + IN PVOID ObjectType, + IN OUT PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN OUT PUNICODE_STRING CompleteName, + IN OUT PUNICODE_STRING RemainingName, + IN OUT PVOID Context OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + OUT PVOID *Object + ); + +typedef NTSTATUS (*OB_POLL_METHOD)( + IN struct wait_table_entry *wte + ); + +typedef NTSTATUS (*OB_SECURITY_METHOD)( + IN PVOID Object, + IN SECURITY_OPERATION_CODE OperationCode, + IN PSECURITY_INFORMATION SecurityInformation, + IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN OUT PULONG CapturedLength, + IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, + IN POOL_TYPE PoolType, + IN PGENERIC_MAPPING GenericMapping + ); + +typedef NTSTATUS (*OB_QUERYNAME_METHOD)( + IN PVOID Object, + OUT POBJECT_NAME_INFORMATION ObjectNameInfo, + IN ULONG Length, + OUT PULONG ReturnLength + ); + +typedef struct object_type * (*OB_GETTYPE_METHOD)( + IN void *obj + ); + +typedef int (*OB_ADDQUEUE_METHOD)( + IN void *obj, + IN struct wait_queue_entry *entry + ); + +typedef void (*OB_RMQUEUE_METHOD)( + IN void *obj, + IN struct wait_queue_entry *entry + ); + +typedef int (*OB_SIGNALED_METHOD)( + IN void *obj, + IN struct w32thread *thread + ); + +typedef int (*OB_SATISFIED_METHOD)( + IN void *obj, + IN struct w32thread *thread + ); + +typedef int (*OB_SIGNAL_METHOD)( + IN void *obj, + IN unsigned int access + ); + +typedef struct fd * (*OB_GETFD_METHOD)( + IN void *obj + ); + +typedef unsigned int (*OB_MAPACCESS_METHOD)( + IN void *obj, + IN unsigned int access + ); + + +/* Object Type Structure */ + +typedef struct _OBJECT_TYPE_INITIALIZER { + USHORT Length; + BOOLEAN UseDefaultObject; + BOOLEAN Reserved; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + BOOLEAN MaintainTypeList; + POOL_TYPE PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; + OB_DUMP_METHOD DumpProcedure; + OB_OPEN_METHOD OpenProcedure; + OB_CLOSE_METHOD CloseProcedure; + OB_CREATE_METHOD CreateProcedure; + OB_DELETE_METHOD DeleteProcedure; + OB_PARSE_METHOD ParseProcedure; + OB_POLL_METHOD PollProcedure; + OB_SECURITY_METHOD SecurityProcedure; + OB_QUERYNAME_METHOD QueryNameProcedure; + OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure; + OB_GETTYPE_METHOD GetTypeProcedure; + OB_ADDQUEUE_METHOD AddQueueProcedure; + OB_RMQUEUE_METHOD RemoveQueueProcedure; + OB_SIGNALED_METHOD SignaledProcedure; + OB_SATISFIED_METHOD SatisfiedProcedure; + OB_SIGNAL_METHOD SignalProcedure; + OB_GETFD_METHOD GetFdProcedure; + OB_MAPACCESS_METHOD MapAccessProcedure; +} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; + +typedef struct _OBJECT_TYPE { + ERESOURCE Mutex; + LIST_ENTRY TypeList; + UNICODE_STRING Name; /* Copy from object header for convenience */ + PVOID DefaultObject; + ULONG Index; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + OBJECT_TYPE_INITIALIZER TypeInfo; +} OBJECT_TYPE, *POBJECT_TYPE; + + +/* Object Directory Structure */ + +#define NUMBER_HASH_BUCKETS 37 + +typedef struct _OBJECT_DIRECTORY { + struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[NUMBER_HASH_BUCKETS]; + struct _OBJECT_DIRECTORY_ENTRY **LookupBucket; + BOOLEAN LookupFound; + USHORT SymbolicLinkUsageCount; + struct _DEVICE_MAP *DeviceMap; +} OBJECT_DIRECTORY, *POBJECT_DIRECTORY; + +/* Object Directory Entry Structure */ + +typedef struct _OBJECT_DIRECTORY_ENTRY { + struct _OBJECT_DIRECTORY_ENTRY *ChainLink; + PVOID Object; +} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY; + +/* Object Directory */ + +typedef struct _OBJECT_DIRECTORY_INFORMATION { + UNICODE_STRING ObjectName; + UNICODE_STRING ObjectTypeName; +} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION; + +/* Symbolic Link Object Structure */ + +typedef struct _OBJECT_SYMBOLIC_LINK { + LARGE_INTEGER CreationTime; + UNICODE_STRING TargetName; + UNICODE_STRING LinkTargetRemaining; + PVOID LinkTargetObject; + ULONG DosDeviceDriveIndex; /* 1-based index into KUSER_SHARED_DATA.DosDeviceDriveType */ +} OBJECT_SYMBOLIC_LINK, *POBJECT_SYMBOLIC_LINK; + + +/* Device Map Structure */ + +typedef struct _DEVICE_MAP { + ULONG ReferenceCount; + POBJECT_DIRECTORY DosDevicesDirectory; + ULONG DriveMap; + UCHAR DriveType[32]; +} DEVICE_MAP, *PDEVICE_MAP; + +extern PDEVICE_MAP ObSystemDeviceMap; + +/* Object Handle Count Database */ + +typedef struct _OBJECT_HANDLE_COUNT_ENTRY { + struct eprocess* Process; + ULONG HandleCount; +} OBJECT_HANDLE_COUNT_ENTRY, *POBJECT_HANDLE_COUNT_ENTRY; + +typedef struct _OBJECT_HANDLE_COUNT_DATABASE { + ULONG CountEntries; + OBJECT_HANDLE_COUNT_ENTRY HandleCountEntries[1]; +} OBJECT_HANDLE_COUNT_DATABASE, *POBJECT_HANDLE_COUNT_DATABASE; + + + +/* Object Header Structure */ + +typedef struct _OBJECT_CREATE_INFORMATION { + ULONG Attributes; + HANDLE RootDirectory; + PVOID ParseContext; + KPROCESSOR_MODE ProbeMode; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG SecurityDescriptorCharge; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PSECURITY_QUALITY_OF_SERVICE SecurityQos; + SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; +} OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION; + +struct object_ops; +#define IS_WINE_OBJECT(obj_hdr) (obj_hdr->ops) + +typedef struct _OBJECT_HEADER { + atomic_t PointerCount; + union { + atomic_t HandleCount; + PSINGLE_LIST_ENTRY SEntry; + }; + POBJECT_TYPE Type; /* set to NULL for wine object */ + const struct object_ops *ops; /* set to NULL if not a wine object */ + UCHAR NameInfoOffset; + UCHAR HandleInfoOffset; + UCHAR QuotaInfoOffset; + UCHAR Flags; + union { + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + PVOID QuotaBlockCharged; + }; + + PSECURITY_DESCRIPTOR SecurityDescriptor; + QUAD Body; +} OBJECT_HEADER, *POBJECT_HEADER; + +typedef struct _OBJECT_HEADER_QUOTA_INFO { + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG SecurityDescriptorCharge; + struct eprocess* ExclusiveProcess; +} OBJECT_HEADER_QUOTA_INFO, *POBJECT_HEADER_QUOTA_INFO; + +typedef struct _OBJECT_HEADER_HANDLE_INFO { + union { + POBJECT_HANDLE_COUNT_DATABASE HandleCountDataBase; + OBJECT_HANDLE_COUNT_ENTRY SingleEntry; + }; +} OBJECT_HEADER_HANDLE_INFO, *POBJECT_HEADER_HANDLE_INFO; + +typedef struct _OBJECT_HEADER_NAME_INFO { + POBJECT_DIRECTORY Directory; + UNICODE_STRING Name; + ULONG Reserved; +} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO; + +typedef struct _OBJECT_HEADER_CREATOR_INFO { + LIST_ENTRY TypeList; + HANDLE CreatorUniqueProcess; + USHORT CreatorBackTraceIndex; + USHORT Reserved; +} OBJECT_HEADER_CREATOR_INFO, *POBJECT_HEADER_CREATOR_INFO; + +typedef struct _OBJECT_HANDLE_ATTRIBUTE_INFORMATION { + BOOLEAN Inherit; + BOOLEAN ProtectFromClose; +} OBJECT_HANDLE_ATTRIBUTE_INFORMATION, *POBJECT_HANDLE_ATTRIBUTE_INFORMATION; + +typedef struct _OBJECT_BASIC_INFORMATION { + ULONG Attributes; + ACCESS_MASK GrantedAccess; + atomic_t HandleCount; + atomic_t PointerCount; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; + ULONG Reserved[3]; + ULONG NameInformationLength; + ULONG TypeInformationLength; + ULONG SecurityDescriptorLength; + LARGE_INTEGER CreateTime; +} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION; + +typedef struct _SYMLINK_OBJECT { + CSHORT Type; + CSHORT Size; + UNICODE_STRING TargetName; + LARGE_INTEGER CreateTime; +} SYMLINK_OBJECT, *PSYMLINK_OBJECT; + +#define OB_FLAG_NEW_OBJECT 0x01 +#define OB_FLAG_KERNEL_OBJECT 0x02 +#define OB_FLAG_CREATOR_INFO 0x04 +#define OB_FLAG_EXCLUSIVE_OBJECT 0x08 +#define OB_FLAG_PERMANENT_OBJECT 0x10 +#define OB_FLAG_DEFAULT_SECURITY_QUOTA 0x20 +#define OB_FLAG_SINGLE_HANDLE_ENTRY 0x40 + +#define BODY_TO_HEADER(objbdy) \ + ((OBJECT_HEADER *)((char *)objbdy - offsetof(OBJECT_HEADER, Body))) + +#define HEADER_TO_WINE_OBJ(obj_header) \ + ((struct object*) ((char*)obj_header + offsetof(OBJECT_HEADER, Body))) + +#define HEADER_TO_OBJECT_NAME(objhdr) ((POBJECT_HEADER_NAME_INFO) \ + (!(objhdr)->NameInfoOffset ? NULL: ((PCHAR)(objhdr) - (objhdr)->NameInfoOffset))) + +#define HEADER_TO_HANDLE_INFO(objhdr) ((POBJECT_HEADER_HANDLE_INFO) \ + (!(objhdr)->HandleInfoOffset ? NULL: ((PCHAR)(objhdr) - (objhdr)->HandleInfoOffset))) + +#define HEADER_TO_CREATOR_INFO(objhdr) ((POBJECT_HEADER_CREATOR_INFO) \ + (!((objhdr)->Flags & OB_FLAG_CREATOR_INFO) ? NULL: ((PCHAR)(objhdr) - sizeof(OBJECT_HEADER_CREATOR_INFO)))) + +#define OBJECT_ALLOC_SIZE(ObjectSize) ((ObjectSize) + sizeof(OBJECT_HEADER)) + +#define HANDLE_TO_EX_HANDLE(handle) (LONG)(((LONG)(handle) >> 2) - 1) +#define EX_HANDLE_TO_HANDLE(exhandle) (HANDLE)(((exhandle) + 1) << 2) + +#define ref_object(Object) atomic_inc(&(BODY_TO_HEADER(Object))->PointerCount) + + +extern POBJECT_TYPE dir_object_type; +extern POBJECT_DIRECTORY name_space_root; + +NTSTATUS +create_object( + IN KPROCESSOR_MODE ProbeMode, + IN POBJECT_TYPE ObjectType, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN KPROCESSOR_MODE OwnershipMode, + IN OUT PVOID ParseContext OPTIONAL, + IN ULONG ObjectBodySize, + IN ULONG PagedPoolCharge, + IN ULONG NonPagedPoolCharge, + OUT PVOID *Object + ); + + +NTSTATUS +insert_object( + IN PVOID Object, + IN PACCESS_STATE PassedAccessState OPTIONAL, + IN ACCESS_MASK DesiredAccess OPTIONAL, + IN ULONG ObjectPointerBias, + OUT PVOID *NewObject OPTIONAL, + OUT PHANDLE Handle + ); + + +NTSTATUS +ref_object_by_handle( + IN HANDLE Handle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_TYPE ObjectType OPTIONAL, + IN KPROCESSOR_MODE AccessMode, + OUT PVOID *Object, + OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL + ); + + +NTSTATUS +open_object_by_name( + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN POBJECT_TYPE ObjectType, + IN OUT PVOID ParseContext OPTIONAL, + IN KPROCESSOR_MODE AccessMode, + IN ACCESS_MASK DesiredAccess OPTIONAL, + IN OUT PACCESS_STATE PassedAccessState OPTIONAL, + OUT PHANDLE Handle + ); + + +NTSTATUS +open_object_by_pointer( + IN PVOID Object, + IN ULONG HandleAttributes, + IN PACCESS_STATE PassedAccessState OPTIONAL, + IN ACCESS_MASK DesiredAccess OPTIONAL, + IN POBJECT_TYPE ObjectType OPTIONAL, + IN KPROCESSOR_MODE AccessMode, + OUT PHANDLE Handle + ); + +NTSTATUS +ObReferenceObjectByName( + IN PUNICODE_STRING ObjectName, + IN ULONG Attributes, + IN PACCESS_STATE PassedAccessState OPTIONAL, + IN ACCESS_MASK DesiredAccess OPTIONAL, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode, + IN OUT PVOID ParseContext OPTIONAL, + OUT PVOID *Object + ); + +VOID +make_temp_object( + IN PVOID Object + ); + + +BOOLEAN +ObFindHandleForObject( + IN struct eprocess* Process, + IN PVOID Object, + IN POBJECT_TYPE ObjectType OPTIONAL, + IN POBJECT_HANDLE_INFORMATION MatchCriteria OPTIONAL, + OUT PHANDLE Handle + ); + +BOOLEAN +insert_obdir_entry( + IN POBJECT_DIRECTORY Directory, + IN PVOID Object + ); + + + +NTSTATUS +ref_object_by_pointer( + IN PVOID Object, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode + ); + +VOID +ObfDereferenceObject( + IN PVOID Object + ); + + +NTSTATUS +query_name_string( + IN PVOID Object, + OUT POBJECT_NAME_INFORMATION ObjectNameInfo, + IN ULONG Length, + OUT PULONG ReturnLength + ); + +ULONG +ObGetObjectPointerCount( + IN PVOID Object + ); + + +NTSTATUS +ObQueryTypeName( + IN PVOID Object, + PUNICODE_STRING ObjectTypeName, + IN ULONG Length, + OUT PULONG ReturnLength + ); + + +NTSTATUS +ObDumpObjectByHandle( + IN HANDLE Handle, + IN POB_DUMP_CONTROL Control OPTIONAL + ); + + +NTSTATUS +ObDumpObjectByPointer( + IN PVOID Object, + IN POB_DUMP_CONTROL Control OPTIONAL + ); + +NTSTATUS +ObSetDeviceMap( + IN struct eprocess* TargetProcess, + IN HANDLE DirectoryHandle + ); + +VOID +ObInheritDeviceMap( + IN struct eprocess* NewProcess, + IN struct eprocess* ParentProcess + ); + +VOID +ObDereferenceDeviceMap( + IN struct eprocess* Process + ); + +NTSTATUS +ObQueryObjectAuditingByHandle( + IN HANDLE Handle, + OUT PBOOLEAN GenerateOnClose + ); + +NTSTATUS +STDCALL +create_type_object( + POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, + PUNICODE_STRING type_type_name, + POBJECT_TYPE *ObjectType); + +PVOID +lookup_obdir_entry( + IN POBJECT_DIRECTORY Directory, + IN PUNICODE_STRING Name, + IN ULONG Attributes + ); + +NTSTATUS +lookup_object_name( + IN HANDLE RootDirectoryHandle OPTIONAL, + IN PUNICODE_STRING ObjectName, + IN ULONG Attributes, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode, + IN PVOID ParseContext OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + IN PVOID InsertObject OPTIONAL, + IN OUT PACCESS_STATE AccessState, + OUT PBOOLEAN DirectoryLocked, + OUT PVOID *FoundObject + ); + +VOID +deref_object(IN PVOID Object); + +NTSTATUS +delete_object(POBJECT_HEADER Header); + +int alloc_object(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, + POBJECT_TYPE ObjectType, + ULONG ObjectSize, + POBJECT_HEADER *ObjectHeader); + +BOOLEAN +delete_obdir_entry (IN POBJECT_DIRECTORY Directory); + +NTSTATUS SERVICECALL +NtCreateDirectoryObject(OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +NTSTATUS +duplicate_object(struct eprocess *SourceProcess, + struct eprocess *TargetProcess, + HANDLE SourceHandle, + PHANDLE TargetHandle, + ACCESS_MASK DesiredAccess, + BOOLEAN InheritHandle, + ULONG Options); + +NTSTATUS +set_handle_attr(HANDLE Handle, + POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo); + +NTSTATUS +query_handle_attr(HANDLE Handle, + POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo); + +VOID +set_permanent_object(IN PVOID ObjectBody, IN BOOLEAN Permanent); + +NTSTATUS SERVICECALL +NtClose(IN HANDLE Handle); + +LONG +copy_object_attr_from_user( + POBJECT_ATTRIBUTES UserObjectAttr, + POBJECT_ATTRIBUTES *KernelObjectAttr + ); + +void release_object(void *object ); + +void *create_wine_object( HANDLE namespace, const struct object_ops *ops, + const struct unicode_str *name, struct object *parent ); +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif diff --git a/unifiedkernel/include/objwait.h b/unifiedkernel/include/objwait.h new file mode 100644 index 0000000..76be7a0 --- /dev/null +++ b/unifiedkernel/include/objwait.h @@ -0,0 +1,95 @@ +/* + * objwait.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * objwait.h: win32 wait table definition + * Refered to Kernel-win32 code + */ + +#ifndef _OBJWAIT_H +#define _OBJWAIT_H + +#include +#include "object.h" +#include "ke.h" +#include "ntstatus.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define MAXIMUM_WAIT_OBJECTS 64 + +#define WAIT_OBJECT_0 (STATUS_WAIT_0 + 0) +#define WAIT_ABANDONED (STATUS_ABANDONED_WAIT_0 + 0) +#define WAIT_ABANDONED_0 (STATUS_ABANDONED_WAIT_0 + 0) +#define WAIT_TIMEOUT STATUS_TIMEOUT + +#define DECLARE_SINGLE_WAIT(VAR,OBJ) \ + struct wait_table VAR = { \ + &VAR.wt_entries[1], \ + {{ __WAITQUEUE_INITIALIZER("InternalWait", current), \ + (OBJ), 0 }} \ + } + +struct wait_table_entry { + /* note wte_wait must always be _first_ */ + wait_queue_t wte_wait; /* link in queue waiting on object */ + void *wte_obj; /* object being waited upon */ + int wte_data; /* object specific data */ +}; + +struct wait_table { + struct wait_table_entry *wt_last; + struct wait_table_entry wt_entries[1]; +}; + +extern int do_wait_for_objects(struct ethread *, struct wait_table *, long *); + +NTSTATUS STDCALL +wait_for_single_object(PVOID Object, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout); + +NTSTATUS STDCALL +wait_for_multi_objs(ULONG Count, + PVOID Object[], + WAIT_TYPE WaitType, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout, + struct kwait_block *WaitBlockArray); + +NTSTATUS SERVICECALL NtWaitForMultipleObjects(ULONG,PHANDLE,WAIT_TYPE,BOOLEAN,PLARGE_INTEGER); + +VOID +wait_test(struct dispatcher_header * Object, + KPRIORITY Increment); + +VOID +abort_wait_thread(struct kthread *Thread, + NTSTATUS WaitStatus, + KPRIORITY Increment); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _OBJWAIT_H */ diff --git a/unifiedkernel/include/pefile.h b/unifiedkernel/include/pefile.h new file mode 100644 index 0000000..dd2dd3a --- /dev/null +++ b/unifiedkernel/include/pefile.h @@ -0,0 +1,278 @@ +/* + * pefile.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * pefile.h: + * Refered to Kernel-win32 code + */ + +#ifndef _PEFILE_H +#define _PEFILE_H + +#include + +#ifdef CONFIG_UNIFIED_KERNEL +#define MAX_FILE_NAME 256 + +#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ +#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ +#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ +#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ +#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ +#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ + +/* These defines describe the meanings of the bits in the Characteristics + * field + */ +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_16BIT_MACHINE 0x0040 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +/* These are the settings of the Machine field. */ +#define IMAGE_FILE_MACHINE_UNKNOWN 0 +#define IMAGE_FILE_MACHINE_I860 0x14d +#define IMAGE_FILE_MACHINE_I386 0x14c +#define IMAGE_FILE_MACHINE_R3000 0x162 +#define IMAGE_FILE_MACHINE_R4000 0x166 +#define IMAGE_FILE_MACHINE_R10000 0x168 +#define IMAGE_FILE_MACHINE_ALPHA 0x184 +#define IMAGE_FILE_MACHINE_POWERPC 0x1F0 + +#define IMAGE_SIZEOF_FILE_HEADER 20 + +/* Possible Magic values */ +#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +/* These are indexes into the DataDirectory array */ +#define IMAGE_FILE_EXPORT_DIRECTORY 0 +#define IMAGE_FILE_IMPORT_DIRECTORY 1 +#define IMAGE_FILE_RESOURCE_DIRECTORY 2 +#define IMAGE_FILE_EXCEPTION_DIRECTORY 3 +#define IMAGE_FILE_SECURITY_DIRECTORY 4 +#define IMAGE_FILE_BASE_RELOCATION_TABLE 5 +#define IMAGE_FILE_DEBUG_DIRECTORY 6 +#define IMAGE_FILE_DESCRIPTION_STRING 7 +#define IMAGE_FILE_MACHINE_VALUE 8 /* Mips */ +#define IMAGE_FILE_THREAD_LOCAL_STORAGE 9 +#define IMAGE_FILE_CALLBACK_DIRECTORY 10 + +/* Directory Entries, indices into the DataDirectory array */ + +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 +#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 + +/* Subsystem Values */ + +#define IMAGE_SUBSYSTEM_UNKNOWN 0 +#define IMAGE_SUBSYSTEM_NATIVE 1 +#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */ +#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem*/ +#define IMAGE_SUBSYSTEM_OS2_CUI 5 +#define IMAGE_SUBSYSTEM_POSIX_CUI 7 + +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +#define IMAGE_FIRST_SECTION(ntheader) \ + ((PIMAGE_SECTION_HEADER)((LPBYTE)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ + ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) + +/* These defines are for the Characteristics bitfield. */ +/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */ +/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */ +#define IMAGE_SCN_TYPE_NOLOAD 0x00000002 +/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */ +/* #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - Reserved */ +/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */ +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_LNK_OTHER 0x00000100 +#define IMAGE_SCN_LNK_INFO 0x00000200 +/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */ +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 +/* 0x00002000 - Reserved */ +/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */ +#define IMAGE_SCN_MEM_FARDATA 0x00008000 +/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */ +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */ +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +/* 0x00800000 - Unused */ +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 + +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +typedef struct _IMAGE_DOS_HEADER { + WORD e_magic; /* 00: MZ Header signature */ + WORD e_cblp; /* 02: Bytes on last page of file */ + WORD e_cp; /* 04: Pages in file */ + WORD e_crlc; /* 06: Relocations */ + WORD e_cparhdr; /* 08: Size of header in paragraphs */ + WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */ + WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */ + WORD e_ss; /* 0e: Initial (relative) SS value */ + WORD e_sp; /* 10: Initial SP value */ + WORD e_csum; /* 12: Checksum */ + WORD e_ip; /* 14: Initial IP value */ + WORD e_cs; /* 16: Initial (relative) CS value */ + WORD e_lfarlc; /* 18: File address of relocation table */ + WORD e_ovno; /* 1a: Overlay number */ + WORD e_res[4]; /* 1c: Reserved words */ + WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */ + WORD e_oeminfo; /* 26: OEM information; e_oemid specific */ + WORD e_res2[10]; /* 28: Reserved words */ + DWORD e_lfanew; /* 3c: Offset to extended header */ +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct _IMAGE_OPTIONAL_HEADER { + + /* Standard fields */ + + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + + /* NT additional fields */ + + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; +typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; + +typedef struct _IMAGE_NT_HEADERS { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#define IMAGE_SIZEOF_SHORT_NAME 8 + +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER; + +typedef struct _IMAGE_BASE_RELOCATION { + DWORD VirtualAddress; + DWORD SizeOfBlock; + WORD TypeOffset[]; /* size is (SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD) */ + /* lower 12 bit, is offset, need to add VirtualAddress */ + /* high 4 bit, 0 is not used, 3 is used */ +} IMAGE_BASE_RELOCATION; +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif diff --git a/unifiedkernel/include/process.h b/unifiedkernel/include/process.h new file mode 100644 index 0000000..625c9d7 --- /dev/null +++ b/unifiedkernel/include/process.h @@ -0,0 +1,396 @@ +/* + * process.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * process.h: + * Refered to Kernel-win32 code + */ + +#ifndef _PROCESS_H +#define _PROCESS_H + +#include +#include "win32_process.h" +#include +#include "win32.h" +#include "object.h" +#include "ke.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#define NtCurrentProcess() ((HANDLE)(ULONG_PTR)-1) +#define PEB_BASE 0x7FFDF000 + +#define MAX_PATH 256 +#define PROCESS_PRIO_NORMAL 6 +#define FREE_UNI(uni) { if (uni.Length) kfree(uni.Buffer); memset(&uni, 0, sizeof(uni)); } + +#define NORMALIZE(x, addr) if (x) x = (typeof(x))((void *)(x) + (void *)(addr)) +#define DENORMALIZE(x, addr) if (x) x = (typeof(x))((void *)(x) - (void *)(addr)) +#define ALIGN_TO_LONG(x) ALIGN((x), sizeof(LONG)) +#define PPF_NORMALIZED 1 + +#define DENORMALIZE_PARAMS(params) \ +{ \ + if ((params) && ((params)->Flags & PPF_NORMALIZED)) \ + { \ + DENORMALIZE((params)->CurrentDirectoryName.Buffer, (params)); \ + DENORMALIZE((params)->DllPath.Buffer, (params)); \ + DENORMALIZE((params)->ImagePathName.Buffer, (params)); \ + DENORMALIZE((params)->CommandLine.Buffer, (params)); \ + DENORMALIZE((params)->WindowTitle.Buffer, (params)); \ + DENORMALIZE((params)->DesktopInfo.Buffer, (params)); \ + DENORMALIZE((params)->ShellInfo.Buffer, (params)); \ + DENORMALIZE((params)->RuntimeInfo.Buffer, (params)); \ + \ + (params)->Flags &= ~PPF_NORMALIZED; \ + } \ +} + +#define NORMALIZE_PARAMS(params) \ +{ \ + if ((params) && !((params)->Flags & PPF_NORMALIZED)) \ + { \ + NORMALIZE((params)->CurrentDirectoryName.Buffer, (params)); \ + NORMALIZE((params)->DllPath.Buffer, (params)); \ + NORMALIZE((params)->ImagePathName.Buffer, (params)); \ + NORMALIZE((params)->CommandLine.Buffer, (params)); \ + NORMALIZE((params)->WindowTitle.Buffer, (params)); \ + NORMALIZE((params)->DesktopInfo.Buffer, (params)); \ + NORMALIZE((params)->ShellInfo.Buffer, (params)); \ + NORMALIZE((params)->RuntimeInfo.Buffer, (params)); \ + \ + (params)->Flags |= PPF_NORMALIZED; \ + } \ +} + +typedef VOID (STDCALL *PPEBLOCKROUTINE)(PVOID); + +typedef struct _PEB_LDR_DATA +{ + ULONG Length; + BOOLEAN Initialized; + PVOID SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + +typedef struct RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _RTL_USER_PROCESS_PARAMETERS +{ + ULONG AllocationSize; + ULONG Size; + ULONG Flags; + ULONG DebugFlags; + HANDLE hConsole; + ULONG ProcessGroup; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + UNICODE_STRING CurrentDirectoryName; + HANDLE CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PWSTR Environment; + ULONG dwX; + ULONG dwY; + ULONG dwXSize; + ULONG dwYSize; + ULONG dwXCountChars; + ULONG dwYCountChars; + ULONG dwFillAttribute; + ULONG dwFlags; + ULONG wShowWindow; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopInfo; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeInfo; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +typedef struct _PEB_FREE_BLOCK +{ + struct _PEB_FREE_BLOCK* Next; + ULONG Size; +} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK; + +typedef struct _PEB +{ + UCHAR InheritedAddressSpace; /* 00h */ + UCHAR ReadImageFileExecOptions; /* 01h */ + UCHAR BeingDebugged; /* 02h */ + BOOLEAN SpareBool; /* 03h */ + HANDLE Mutant; /* 04h */ + PVOID ImageBaseAddress; /* 08h */ + PPEB_LDR_DATA Ldr; /* 0Ch */ + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; /* 10h */ + PVOID SubSystemData; /* 14h */ + PVOID ProcessHeap; /* 18h */ + PVOID FastPebLock; /* 1Ch */ + PPEBLOCKROUTINE FastPebLockRoutine; /* 20h */ + PPEBLOCKROUTINE FastPebUnlockRoutine; /* 24h */ + ULONG EnvironmentUpdateCount; /* 28h */ + PVOID* KernelCallbackTable; /* 2Ch */ + PVOID EventLogSection; /* 30h */ + PVOID EventLog; /* 34h */ + PPEB_FREE_BLOCK FreeList; /* 38h */ + ULONG TlsExpansionCounter; /* 3Ch */ + PVOID TlsBitmap; /* 40h */ + ULONG TlsBitmapBits[0x2]; /* 44h */ + PVOID ReadOnlySharedMemoryBase; /* 4Ch */ + PVOID ReadOnlySharedMemoryHeap; /* 50h */ + PVOID* ReadOnlyStaticServerData; /* 54h */ + PVOID AnsiCodePageData; /* 58h */ + PVOID OemCodePageData; /* 5Ch */ + PVOID UnicodeCaseTableData; /* 60h */ + ULONG NumberOfProcessors; /* 64h */ + ULONG NtGlobalFlag; /* 68h */ + BYTE Spare2[4]; /* 6ch */ + LARGE_INTEGER CriticalSectionTimeout; /* 70h */ + ULONG HeapSegmentReserve; /* 78h */ + ULONG HeapSegmentCommit; /* 7Ch */ + ULONG HeapDeCommitTotalFreeThreshold; /* 80h */ + ULONG HeapDeCommitFreeBlockThreshold; /* 84h */ + ULONG NumberOfHeaps; /* 88h */ + ULONG MaximumNumberOfHeaps; /* 8Ch */ + PVOID* ProcessHeaps; /* 90h */ + PVOID GdiSharedHandleTable; /* 94h */ + PVOID ProcessStarterHelper; /* 98h */ + PVOID GdiDCAttributeList; /* 9Ch */ + PVOID LoaderLock; /* A0h */ + ULONG OSMajorVersion; /* A4h */ + ULONG OSMinorVersion; /* A8h */ + USHORT OSBuildNumber; /* ACh */ + USHORT OSCSDVersion; /* AEh */ + ULONG OSPlatformId; /* B0h */ + ULONG ImageSubSystem; /* B4h */ + ULONG ImageSubSystemMajorVersion; /* B8h */ + ULONG ImageSubSystemMinorVersion; /* BCh */ + ULONG ImageProcessAffinityMask; /* C0h */ + ULONG GdiHandleBuffer[0x22]; /* C4h */ + PVOID PostProcessInitRoutine; /* 14Ch */ + PVOID *TlsExpansionBitmap; /* 150h */ + ULONG TlsExpansionBitmapBits[0x20]; /* 154h */ + ULONG SessionId; /* 1D4h */ + PVOID AppCompatInfo; /* 1D8h */ + UNICODE_STRING CSDVersion; /* 1DCh */ +} PEB, *PPEB; + +/* process startup state */ +enum startup_state { STARTUP_IN_PROGRESS, STARTUP_DONE, STARTUP_ABORTED }; +#ifdef SERVER_PM +struct w32process +{ + struct w32process *parent; /* parent process */ + struct eprocess *eprocess; + struct w32thread *debugger; /* thread debugging this process */ + process_id_t group_id; /* group id of the process */ + struct timeout_user *sigkill_timeout; /* timeout for final SIGKILL */ + int running_threads; /* number of threads running in this process */ + timeout_t start_time; /* absolute time at process start */ + timeout_t end_time; /* absolute time at process end */ + int suspend; /* global process suspend count */ + int is_system; /* is it a system process? */ + unsigned int create_flags; /* process creation flags */ + struct list_head locks; /* list of file locks owned by the process */ + struct list_head classes; /* window classes owned by the process */ + struct console_input*console; /* console input */ + enum startup_state startup_state; /* startup state */ + struct startup_info *startup_info; /* startup info while init is in progress */ + struct kevent *idle_event; /* event for input idle */ + struct msg_queue *queue; /* main message queue */ + obj_handle_t winstation; /* main handle to process window station */ + obj_handle_t desktop; /* handle to desktop to use for new threads */ + struct list_head dlls; /* list of loaded dlls */ + void *ldt_copy; /* pointer to LDT copy in client addr space */ + unsigned int trace_data; /* opaque data used by the process tracing mechanism */ +}; +#else +struct w32process +{ + struct object obj; /* object header */ + struct list_head entry; /* entry in system-wide process list */ + struct w32process *parent; /* parent process */ + struct eprocess *eprocess; + struct list_head thread_list; /* thread list */ + struct w32thread *debugger; /* thread debugging this process */ + struct handle_table *handles; /* handle entries */ + process_id_t id; /* id of the process */ + process_id_t group_id; /* group id of the process */ + struct timeout_user *sigkill_timeout; /* timeout for final SIGKILL */ + int unix_pid; /* Unix pid for final SIGKILL */ + int exit_code; /* process exit code */ + int running_threads; /* number of threads running in this process */ + timeout_t start_time; /* absolute time at process start */ + timeout_t end_time; /* absolute time at process end */ + int priority; /* priority class */ + int affinity; /* process affinity mask */ + int suspend; /* global process suspend count */ + int is_system; /* is it a system process? */ + unsigned int create_flags; /* process creation flags */ + struct list_head locks; /* list of file locks owned by the process */ + struct list_head classes; /* window classes owned by the process */ + struct console_input*console; /* console input */ + enum startup_state startup_state; /* startup state */ + struct startup_info *startup_info; /* startup info while init is in progress */ + struct kevent *idle_event; /* event for input idle */ + struct msg_queue *queue; /* main message queue */ + obj_handle_t winstation; /* main handle to process window station */ + obj_handle_t desktop; /* handle to desktop to use for new threads */ + struct token *token; /* security token associated with this process */ + struct list_head dlls; /* list of loaded dlls */ + void *peb; /* PEB address in client address space */ + void *ldt_copy; /* pointer to LDT copy in client addr space */ + unsigned int trace_data; /* opaque data used by the process tracing mechanism */ +}; +#endif + +extern POBJECT_TYPE process_object_type; +void kprocess_init(struct kprocess *process, char prio, + unsigned long affinity, physical_address_t dir_table_base); +void eprocess_init(struct eprocess *process); +NTSTATUS STDCALL create_peb(struct eprocess *process); +void exit_process_threads(struct eprocess *process, NTSTATUS ExitStatus); +void exit_current_thread(struct task_struct *tsk, NTSTATUS ExitStatus); +VOID delete_process(PVOID Object); +int poll_process(struct wait_table_entry *wte); +int lookup_process_by_pid(HANDLE pid, struct eprocess** process); +NTSTATUS lookup_process_thread_by_cid(PCLIENT_ID cid, PEPROCESS *process, PETHREAD *thread); + +void __exit_process(struct eprocess * process); + +/* for server process/thread management migration */ +struct process_dll +{ + struct list_head entry; /* entry in per-process dll list */ + struct file *file; /* dll file */ + void *base; /* dll base address (in process addr space) */ + size_t size; /* dll size */ + void *name; /* ptr to ptr to name (in process addr space) */ + int dbg_offset; /* debug info offset */ + int dbg_size; /* debug info size */ + data_size_t namelen; /* length of dll file name */ + WCHAR *filename; /* dll file name */ +}; + +struct process_snapshot +{ + struct w32process *process; /* process ptr */ + int count; /* process refcount */ + int threads; /* number of threads */ + int priority; /* priority class */ + int handles; /* number of handles */ +}; + +struct module_snapshot +{ + void *base; /* module base addr */ + size_t size; /* module size */ + data_size_t namelen; /* length of file name */ + WCHAR *filename; /* module file name */ +}; + +extern void enum_processes( int (*cb)(struct w32process*, void*), void *user); +extern struct process_snapshot *process_snap( int *count ); +extern struct module_snapshot *module_snap( struct w32process *process, int *count ); +/* for server process/thread management migration */ + +static inline struct eprocess *process2eprocess(struct w32process *proc) +{ + return proc->eprocess; +} + +static inline struct w32process *eprocess2process(struct eprocess *eproc) +{ + return (struct w32process *)eproc->win32process; +} + +static inline struct eprocess *get_current_eprocess(void) +{ + return current->ethread ? current->ethread->threads_process : NULL; +} + +static inline struct w32process *get_current_w32process(void) +{ + return current->ethread ? current->ethread->threads_process->win32process : NULL; +} + +static inline void lock_process(struct eprocess *process) +{ + enter_critical_region(); + spin_lock(&process->process_lock); +} + +static inline void unlock_process(struct eprocess *process) +{ + spin_unlock(&process->process_lock); + leave_critical_region(); +} + +static inline unsigned int get_process_id( struct w32process *process ) { + return (unsigned int)process2eprocess(process)->unique_processid; +} + +static inline int is_process_init_done( struct w32process *process ) +{ + return process->startup_state == STARTUP_DONE; +} + +static inline struct process_dll *get_process_exe_module( struct w32process *process ) +{ + struct list_head *ptr = list_head( &process->dlls ); + return ptr ? LIST_ENTRY( ptr, struct process_dll, entry ) : NULL; +} +NTSTATUS create_ppb(PRTL_USER_PROCESS_PARAMETERS *ppb_res, + struct eprocess *process, + struct linux_binprm *bprm, + char *image_name, + char *dll_path, + char *current_dir, + PWSTR environ, + char *window_title, + char *desktop_info, + char *shell_info, + char *rt_info); + +NTSTATUS SERVICECALL +NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, + IN NTSTATUS ExitStatus); + +long init_cid_table(void); +void destroy_cid_table(void); +HANDLE create_cid_handle(PVOID object, POBJECT_TYPE obj_type); +int delete_cid_handle(HANDLE cid_handle, POBJECT_TYPE obj_type); + +int flush_old_exec_from_task(struct task_struct *task); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _PROCESS_H */ diff --git a/unifiedkernel/include/section.h b/unifiedkernel/include/section.h new file mode 100644 index 0000000..5f7fee6 --- /dev/null +++ b/unifiedkernel/include/section.h @@ -0,0 +1,191 @@ +/* + * section.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * section.h: section syscall functions + * Refered to Kernel-win32 code + */ + +#ifndef _SECTION_H +#define _SECTION_H + +#include +#include +#include "win32_process.h" +#include "file.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* + * BaseAddress need to aligned to 64k + */ +#define BASE_ADDRESS_ALIGN (PAGE_SIZE << 4) + +#define _SEC_FILE 0x00800000 +#define _SEC_IMAGE 0x01000000 +#define _SEC_VLM 0x02000000 +#define _SEC_RESERVE 0x04000000 +#define _SEC_COMMIT 0x08000000 +#define _SEC_NOCACHE 0x10000000 + +#define SECTION_EXTEND_SIZE 0x10 +#define SECTION_MAP_READ 0x04 +#define SECTION_MAP_WRITE 0x02 +#define SECTION_QUERY 0x01 +#define SECTION_MAP_EXECUTE 0x08 +#define SECTION_ALL_ACCESS 0xf001f + +/* + * PE Image File Section + * TODO. not implemented in this version + */ +struct win32_image_section +{ + unsigned long wis_rva; /* relative virtual address */ + off_t wis_fpos; /* file position */ + size_t wis_size; /* section size */ + size_t wis_rawsize; /* raw data size */ + unsigned long wis_padrva; /* padding RVA */ + unsigned long wis_flags; /* specific flags */ + unsigned long wis_protect; /* specific protects */ + unsigned long wis_character; /* characteristics */ +}; + +/* + * memory map section object definition + */ +struct win32_section { + struct win32_file *ws_wfile; /* the wine file object */ + struct file *ws_file; /* linux file struct */ + + unsigned long ws_alloctype; /* Allocation type */ + unsigned long ws_protect; /* page protect */ + unsigned long ws_access; /* Desired access */ + unsigned long ws_flags; /* MAP_PRIVATE etc. */ + unsigned long ws_len; /* section len */ + unsigned long ws_pagelen; /* page len, aligned to PAGE_SIZE */ + + int (*ws_mmap)(struct task_struct *tsk, struct win32_section *, + unsigned long *, unsigned long, unsigned long, unsigned long); /* mmap func */ + + /* TODO: this field used for PE Image */ + unsigned long ws_imagebase; + unsigned long ws_realbase; + int ws_nsecs; + struct win32_image_section *ws_sections; + struct win32_image_section *ws_sectend; + unsigned long ws_stackresv; + unsigned long ws_stackcommit; + unsigned short ws_subsystem; + unsigned short ws_majorver; + unsigned short ws_minorver; + unsigned short ws_executable; + unsigned long ws_entrypoint; + unsigned short ws_imagecharacter; + unsigned short ws_machine; + int ws_secoff; + + int (*ws_munmap)(struct win32_section *); +}; + +typedef struct _SECTION_BASIC_INFORMATION +{ + PVOID BaseAddress; + ULONG Attributes; + LARGE_INTEGER Size; +} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION; + +typedef struct _SECTION_IMAGE_INFORMATION +{ + ULONG EntryPoint; + ULONG Unknown1; + ULONG_PTR StackReserve; + ULONG_PTR StackCommit; + ULONG Subsystem; + USHORT MinorSubsystemVersion; + USHORT MajorSubsystemVersion; + ULONG Unknown2; + ULONG Characteristics; + USHORT ImageNumber; + BOOLEAN Executable; + UCHAR Unknown3; + ULONG Unknown4[3]; +} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; + +extern POBJECT_TYPE section_object_type; +int data_section_setup(struct win32_section *ws); +int image_section_setup(struct win32_section *ws); + +NTSTATUS +SERVICECALL +NtCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL + ); + +NTSTATUS +SERVICECALL +NtMapViewOfSection( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PSIZE_T ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Protect + ); + +NTSTATUS +SERVICECALL +NtUnmapViewOfSection( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress + ); + +NTSTATUS +STDCALL +map_section_view( + IN PVOID SectionObject, + IN struct eprocess* Process, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PSIZE_T ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Protect + ); + +NTSTATUS +STDCALL +unmap_section_view(struct eprocess *process, struct mm_struct *mm, unsigned long addr); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif diff --git a/unifiedkernel/include/semaphore.h b/unifiedkernel/include/semaphore.h new file mode 100644 index 0000000..ed7c7b5 --- /dev/null +++ b/unifiedkernel/include/semaphore.h @@ -0,0 +1,75 @@ +/* + * semaphore.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * semaphore.h: win32 semaphore definition + * Refered to Kernel-win32 code + */ + +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H + +#include "win32.h" +#include "io.h" +#include "ke.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define SEMAPHORE_QUERY_STATE (0x0001) +#define SEMAPHORE_MODIFY_STATE (0x0002) +#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3) + +#define SEMAPHORE_INCREMENT 1 + +VOID STDCALL +semaphore_init(struct ksemaphore* Semaphore, + LONG Count, + LONG Limit); + +VOID +init_semaphore_implement(VOID); + +NTSTATUS SERVICECALL +NtCreateSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN LONG InitialCount, + IN LONG MaximumCount); + +NTSTATUS SERVICECALL +NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +LONG STDCALL +release_semaphore(struct ksemaphore *Semaphore, + KPRIORITY Increment, + LONG Adjustment, + BOOLEAN Wait); + +NTSTATUS SERVICECALL +NtReleaseSemaphore(IN HANDLE SemaphoreHandle, + IN LONG ReleaseCount, + OUT PLONG PreviousCount OPTIONAL); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _SEMAPHORE_H */ diff --git a/unifiedkernel/include/thread.h b/unifiedkernel/include/thread.h new file mode 100644 index 0000000..3355c63 --- /dev/null +++ b/unifiedkernel/include/thread.h @@ -0,0 +1,315 @@ +/* + * thread.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * thread.h: + * Refered to Kernel-win32 code + */ + +#ifndef _THREAD_H +#define _THREAD_H + +#include +#include +#include + +#include "win32.h" +#include "object.h" +#include "process.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define NtCurrentThread() ((HANDLE)(ULONG_PTR) - 2) +#define TEB_BASE 0x7FFDE000 +#define TEB_SELECTOR 0x3b + +#define THREAD_ALERT 0x4 + +typedef void *PKSTART_ROUTINE; +typedef struct _NT_TIB { + struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; + PVOID StackBase; + PVOID StackLimit; + PVOID SubSystemTib; + union { + PVOID FiberData; + DWORD Version; + } DUMMYUNIONNAME; + PVOID ArbitraryUserPointer; + struct _NT_TIB *Self; +} NT_TIB,*PNT_TIB; + +typedef struct _GDI_TEB_BATCH +{ + ULONG Offset; + ULONG HDC; + ULONG Buffer[0x136]; +} GDI_TEB_BATCH, *PGDI_TEB_BATCH; + +/* descriptor for fds currently in flight from client to server */ +struct inflight_fd +{ + int client; /* fd on the client side (or -1 if entry is free) */ + int server; /* fd on the server side */ +}; +#define MAX_INFLIGHT_FDS 16 /* max number of fds in flight per thread */ + +enum run_state +{ + RUNNING, /* running normally */ + TERMINATED /* terminated */ +}; + +#ifdef SERVER_PM +typedef struct w32thread +{ + struct list_head entry; /* entry in system-wide thread list */ + struct w32process *process; + struct ethread *ethread; + struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */ + struct debug_event *debug_event; /* debug event being sent to debugger */ + int debug_break; /* debug breakpoint pending? */ + struct msg_queue *queue; /* message queue */ + unsigned int error; /* current error code */ + union generic_request req; /* current request */ + void *req_data; /* variable-size data for request */ + unsigned int req_toread; /* amount of data still to read in request */ + union generic_reply reply; /* UnifiedKernel FIXME*/ + void *reply_data; /* variable-size data for reply */ + unsigned int reply_size; /* size of reply data */ + unsigned int reply_towrite; /* amount of data still to write in reply */ + enum run_state state; /* running state */ + CONTEXT *context; /* current context if in an exception handler */ + CONTEXT *suspend_context; /* current context if suspended */ + obj_handle_t desktop; /* desktop handle */ + int desktop_users; /* number of objects using the thread desktop */ + timeout_t creation_time; /* Thread creation time */ + timeout_t exit_time; /* Thread exit time */ +} TSB, *PTSB, W32THREAD; +#else +typedef struct w32thread +{ + struct object obj; /* object header */ + struct list_head entry; /* entry in system-wide thread list */ + struct list_head proc_entry; /* entry in per-process thread list */ + struct w32process *process; + struct ethread *ethread; + thread_id_t id; /* thread id */ + struct list_head mutex_list; /* list of currently owned mutexes */ + struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */ + struct debug_event *debug_event; /* debug event being sent to debugger */ + int debug_break; /* debug breakpoint pending? */ + struct msg_queue *queue; /* message queue */ + unsigned int error; /* current error code */ + union generic_request req; /* current request */ + void *req_data; /* variable-size data for request */ + unsigned int req_toread; /* amount of data still to read in request */ + union generic_reply reply; /* UnifiedKernel FIXME*/ + void *reply_data; /* variable-size data for reply */ + unsigned int reply_size; /* size of reply data */ + unsigned int reply_towrite; /* amount of data still to write in reply */ + enum run_state state; /* running state */ + int exit_code; /* thread exit code */ + int unix_pid; /* Unix pid of client */ + int unix_tid; /* Unix tid of client */ + CONTEXT *context; /* current context if in an exception handler */ + CONTEXT *suspend_context; /* current context if suspended */ + void *teb; /* TEB address (in client address space) */ + int priority; /* priority level */ + int affinity; /* affinity mask */ + int suspend; /* suspend count */ + obj_handle_t desktop; /* desktop handle */ + int desktop_users; /* number of objects using the thread desktop */ + timeout_t creation_time; /* Thread creation time */ + timeout_t exit_time; /* Thread exit time */ + struct token *token; /* security token associated with this thread */ +} TSB, *PTSB, W32THREAD; +#endif + +struct thread_snapshot +{ + struct w32thread *thread; /* thread ptr */ + int count; /* thread refcount */ + int priority; /* priority class */ +}; + +typedef struct _TEB +{ + NT_TIB Tib; /* 00h */ + PVOID EnvironmentPointer; /* 1Ch */ + CLIENT_ID Cid; /* 20h */ + PVOID ActiveRpcInfo; /* 28h */ + PVOID ThreadLocalStoragePointer; /* 2Ch */ + PEB* Peb; /* 30h */ + ULONG LastErrorValue; /* 34h */ + ULONG CountOfOwnedCriticalSections; /* 38h */ + PVOID CsrClientThread; /* 3Ch */ + W32THREAD* Win32ThreadInfo; /* 40h */ + ULONG Win32ClientInfo[0x1F]; /* 44h */ + PVOID WOW32Reserved; /* C0h */ + LCID CurrentLocale; /* C4h */ + ULONG FpSoftwareStatusRegister; /* C8h */ + PVOID SystemReserved1[0x36]; /* CCh */ + PVOID Spare1; /* 1A4h */ + LONG ExceptionCode; /* 1A8h */ + UCHAR SpareBytes1[0x28]; /* 1ACh */ + PVOID SystemReserved2[0xA]; /* 1D4h */ + GDI_TEB_BATCH GdiTebBatch; /* 1FCh */ + ULONG gdiRgn; /* 6DCh */ + ULONG gdiPen; /* 6E0h */ + ULONG gdiBrush; /* 6E4h */ + CLIENT_ID RealClientId; /* 6E8h */ + PVOID GdiCachedProcessHandle; /* 6F0h */ + ULONG GdiClientPID; /* 6F4h */ + ULONG GdiClientTID; /* 6F8h */ + PVOID GdiThreadLocaleInfo; /* 6FCh */ + PVOID UserReserved[5]; /* 700h */ + PVOID glDispatchTable[0x118]; /* 714h */ + ULONG glReserved1[0x1A]; /* B74h */ + PVOID glReserved2; /* BDCh */ + PVOID glSectionInfo; /* BE0h */ + PVOID glSection; /* BE4h */ + PVOID glTable; /* BE8h */ + PVOID glCurrentRC; /* BECh */ + PVOID glContext; /* BF0h */ + NTSTATUS LastStatusValue; /* BF4h */ + UNICODE_STRING StaticUnicodeString; /* BF8h */ + WCHAR StaticUnicodeBuffer[0x105]; /* C00h */ + PVOID DeallocationStack; /* E0Ch */ + PVOID TlsSlots[0x40]; /* E10h */ + LIST_ENTRY TlsLinks; /* F10h */ + PVOID Vdm; /* F18h */ + PVOID ReservedForNtRpc; /* F1Ch */ + PVOID DbgSsReserved[0x2]; /* F20h */ + ULONG HardErrorDisabled; /* F28h */ + PVOID Instrumentation[0x10]; /* F2Ch */ + PVOID WinSockData; /* F6Ch */ + ULONG GdiBatchCount; /* F70h */ + USHORT _Spare2; /* F74h */ + BOOLEAN IsFiber; /* F76h */ + UCHAR Spare3; /* F77h */ + ULONG _Spare4; /* F78h */ + ULONG _Spare5; /* F7Ch */ + PVOID ReservedForOle; /* F80h */ + ULONG WaitingOnLoaderLock; /* F84h */ + ULONG _Unknown[11]; /* F88h */ + PVOID FlsSlots; /* FB4h */ +}TEB, *PTEB; + +#define LOW_PRIORITY 0 +#define LOW_REALTIME_PRIORITY 16 +#define HIGH_PRIORITY 31 +#define MAXIMUM_PRIORITY 32 + +extern POBJECT_TYPE thread_object_type; +int set_teb_selector(struct task_struct *tsk, long teb); +void kthread_init(struct kthread *thread, struct eprocess *process); +void ethread_init(struct ethread *thread, struct eprocess *process, struct task_struct *tsk); +VOID delete_thread(PVOID Object); +int poll_thread(struct wait_table_entry *wte); +int lookup_thread_by_tid(HANDLE tid, struct ethread** thread); + +ULONG STDCALL suspend_thread(PKTHREAD Thread); +ULONG STDCALL resume_thread(PKTHREAD Thread); +VOID STDCALL suspend_thread_kernel_routine(struct kapc *Apc, PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArguemnt2); +VOID STDCALL suspend_thread_normal_routine(PVOID NormalContext, PVOID SystemArgument1, + PVOID SystemArgument2); + +PTEB STDCALL create_teb(struct eprocess* Process, + PCLIENT_ID ClientId, PINITIAL_TEB InitialTeb); +VOID STDCALL delete_teb(PTEB Teb); + +typedef void (STDCALL *PKSYSTEM_ROUTINE)(PKSTART_ROUTINE StartRoutine, PVOID StartContext); + +extern int add_queue( struct object *obj, struct wait_queue_entry *entry ); +extern void remove_queue( struct object *obj, struct wait_queue_entry *entry ); + +extern struct w32thread *get_thread_from_id( unsigned int id ); +extern void uk_wake_up( struct object *obj, int max ); +extern int thread_get_inflight_fd( struct w32thread *thread, int client ); +extern int thread_queue_apc( struct w32thread *thread, struct object *owner, + const apc_call_t *call_data ); +extern void thread_cancel_apc( struct w32thread *thread, struct object *owner, enum apc_type type ); +extern struct thread_snapshot *thread_snap( int *count ); +#ifdef SERVER_PM +extern struct w32thread *create_w32thread(struct ethread *thread); +#endif + +VOID +STDCALL +initialize_thread(struct kprocess* Process, + struct kthread* Thread, + PKSYSTEM_ROUTINE SystemRoutine, + PKSTART_ROUTINE StartRoutine, /* FIXME */ + PVOID StartContext, /* FIXME */ + PCONTEXT Context, + PVOID Teb, + PVOID KernelStack); +VOID +STDCALL +init_thread_with_context(struct kthread* Thread, + PKSYSTEM_ROUTINE SystemRoutine, + PKSTART_ROUTINE StartRoutine, /* FIXME */ + PVOID StartContext, /* FIXME */ + PCONTEXT Context); +VOID +STDCALL +user_thread_startup(PKSTART_ROUTINE StartRoutine, + PVOID StartContext); + +static inline struct ethread *get_current_ethread(void) +{ + return current->ethread; +} + +static inline struct ethread *get_first_thread(struct eprocess *process) +{ + struct ethread *thread; + + local_irq_disable(); + thread = list_empty(&process->thread_list_head) ? + NULL : list_entry(process->thread_list_head.next, + struct ethread, thread_list_entry); + local_irq_enable(); + + return thread; +} + +static inline struct w32thread *get_current_w32thread(void) +{ + return current->ethread ? current->ethread->tcb.win32thread : NULL; +} + +#define current_thread current->ethread->tcb.win32thread + +static inline struct ethread *thread2ethread(struct w32thread *thread) +{ + return thread->ethread; +} + +static inline unsigned int get_thread_id(struct w32thread *thread) +{ + return (unsigned int) thread2ethread(thread)->cid.unique_thread; +} +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _THREAD_H */ diff --git a/unifiedkernel/include/unistr.h b/unifiedkernel/include/unistr.h new file mode 100644 index 0000000..2ceaf39 --- /dev/null +++ b/unifiedkernel/include/unistr.h @@ -0,0 +1,79 @@ +/* + * unistr.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * unistr.h: + * Refered to ReactOS code + */ +#ifndef _UNISTR_H +#define _UNISTR_H +#include "win32.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +int str2unistr(struct nls_table *nls, PUNICODE_STRING dst, char *src); + +int unistr2charstr(PWSTR unistr, LPCSTR chstr); + +VOID +STDCALL +init_unistr( + IN OUT PUNICODE_STRING DestinationString, + IN PWSTR SourceString + ); + +BOOLEAN +STDCALL +equal_unistr( + IN const UNICODE_STRING *String1, + IN const UNICODE_STRING *String2, + IN BOOLEAN CaseInsensitive); + +VOID +STDCALL +free_unistr( + IN PUNICODE_STRING UnicodeString); + +VOID +STDCALL +copy_unistr( + IN OUT PUNICODE_STRING DestinationString, + IN PUNICODE_STRING SourceString); + +NTSTATUS +capture_unistr(OUT PUNICODE_STRING Dest, + IN KPROCESSOR_MODE CurrentMode, + IN POOL_TYPE PoolType, + IN BOOLEAN CaptureIfKernel, + IN PUNICODE_STRING UnsafeSrc); + +VOID +release_unistr(IN PUNICODE_STRING CapturedString, + IN KPROCESSOR_MODE CurrentMode, + IN BOOLEAN CaptureIfKernel); + + +char *debug_unistr(PUNICODE_STRING us); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif + diff --git a/unifiedkernel/include/virtual.h b/unifiedkernel/include/virtual.h new file mode 100644 index 0000000..ec9a53a --- /dev/null +++ b/unifiedkernel/include/virtual.h @@ -0,0 +1,156 @@ +/* + * virtual.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * virtual.h: + * Refered to ReactOS code + */ + +#ifndef _VIRTUAL_H +#define _VIRTUAL_H + +#include "win32.h" +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +typedef struct _MEMORY_BASIC_INFORMATION { + PVOID BaseAddress; + PVOID AllocationBase; + DWORD AllocationProtect; + DWORD RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; +} MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION; + +typedef const int CINT; + +#define _PAGE_NOACCESS 0x00000001 +#define _PAGE_READONLY 0x00000002 +#define _PAGE_READWRITE 0x00000004 +#define _PAGE_WRITECOPY 0x00000008 +#define _PAGE_EXECUTE 0x00000010 +#define _PAGE_EXECUTE_READ 0x00000020 +#define _PAGE_EXECUTE_READWRITE 0x00000040 +#define _PAGE_EXECUTE_WRITECOPY 0x00000080 +#define _PAGE_GUARD 0x00000100 +#define _PAGE_NOCACHE 0x00000200 +#define _PAGE_WRITECOMBINE 0x00000400 + +#define MEM_COMMIT 0x00001000 +#define MEM_RESERVE 0x00002000 +#define MEM_DECOMMIT 0x00004000 +#define MEM_RELEASE 0x00008000 +#define MEM_FREE 0x00010000 +#define MEM_PRIVATE 0x00020000 +#define MEM_MAPPED 0x00040000 +#define MEM_RESET 0x00080000 +#define MEM_TOP_DOWN 0x00100000 +#define MEM_SYSTEM 0x80000000 +#define MEM_4MB_PAGES 0x80000000 +#define MEM_IMAGE _SEC_IMAGE + +#define MAP_RESERVE 0x10000000 +#define MAP_TOP_DOWN 0x20000000 + +#define WIN32_TASK_SIZE 0x80000000 +#define WIN32_STACK_LIMIT 0x200000 +#define WIN32_UNMAPPED_BASE 0x20000000 +#define WIN32_LOWEST_ADDR 0x100000 +#define WIN32_SYSTEM_HEAP_SIZE 0x1000000 + +#define PAGE_ALLOC_MASK \ + (_PAGE_NOACCESS | _PAGE_READONLY | _PAGE_READWRITE \ + | _PAGE_EXECUTE | _PAGE_EXECUTE_READ | _PAGE_EXECUTE_READWRITE) +#define PAGE_PROT_MASK \ + (_PAGE_NOACCESS | _PAGE_READONLY | _PAGE_READWRITE | _PAGE_WRITECOPY \ + | _PAGE_EXECUTE | _PAGE_EXECUTE_READ | _PAGE_EXECUTE_READWRITE | _PAGE_EXECUTE_WRITECOPY) +#define PAGE_ALL_MASK \ + (_PAGE_PROT_MASK | _PAGE_GUARD | _PAGE_NOCACHE | _PAGE_WRITECOMBINE) + +#define MEMORY_AREA_INVALID (0) +#define MEMORY_AREA_SECTION_VIEW (1) +#define MEMORY_AREA_CONTINUOUS_MEMORY (2) +#define MEMORY_AREA_NO_CACHE (3) +#define MEMORY_AREA_IO_MAPPING (4) +#define MEMORY_AREA_SYSTEM (5) +#define MEMORY_AREA_MDL_MAPPING (7) +#define MEMORY_AREA_VIRTUAL_MEMORY (8) +#define MEMORY_AREA_CACHE_SEGMENT (9) +#define MEMORY_AREA_SHARED_DATA (10) +#define MEMORY_AREA_KERNEL_STACK (11) +#define MEMORY_AREA_PAGED_POOL (12) +#define MEMORY_AREA_NO_ACCESS (13) +#define MEMORY_AREA_PEB_OR_TEB (14) + +#define RESERVE_PAGE_SIZE (16 * PAGE_SIZE) +#define RESERVE_PAGE_SHIFT (PAGE_SHIFT + 4) +#define RESERVE_PAGE_MASK (~(RESERVE_PAGE_SIZE - 1)) + +typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; + +unsigned long win32_do_mmap_pgoff(struct task_struct *task, struct file *filp, + unsigned long addr, unsigned long size, unsigned long prot, + unsigned long flags, unsigned long pgoff); + +NTSTATUS SERVICECALL +NtQueryVirtualMemory (IN HANDLE ProcessHandle, + IN PVOID Address, + IN CINT VirtualMemoryInformationClass, + OUT PVOID VirtualMemoryInformation, + IN ULONG Length, + OUT PULONG UnsafeResultLength); + +NTSTATUS SERVICECALL +NtAllocateVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID* UBaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG URegionSize, + IN ULONG AllocationType, + IN ULONG Protect); + +NTSTATUS SERVICECALL +NtWriteVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten OPTIONAL); + +NTSTATUS SERVICECALL +NtReadVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead OPTIONAL); + +NTSTATUS SERVICECALL +NtFreeVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID* PBaseAddress, + IN PULONG PRegionSize, + IN ULONG FreeType); + +#endif /* CONFIG_UNIFIED_KERNEL */ + +#endif /* _VIRTUAL_H */ + diff --git a/unifiedkernel/include/w32syscall.h b/unifiedkernel/include/w32syscall.h new file mode 100644 index 0000000..ed02dea --- /dev/null +++ b/unifiedkernel/include/w32syscall.h @@ -0,0 +1,1504 @@ +/* + * w32syscall.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * w32syscall.h: + * Refered to ReactOS code + */ + +#ifndef _W32SYSCALL_H +#define _W32SYSCALL_H + +#include +#include "win32.h" +#include "wineserver/server.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* 0 */ +NTSTATUS SERVICECALL +NtAcceptConnectPort (PHANDLE ServerPortHandle, + HANDLE NamedPortHandle, + PPORT_MESSAGE LpcMessage, + BOOLEAN AcceptIt, + PPORT_VIEW WriteMap, + PREMOTE_PORT_VIEW ReadMap); + +NTSTATUS SERVICECALL +NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE TokenHandle, + IN ACCESS_MASK DesiredAccess, + IN PGENERIC_MAPPING GenericMapping, + OUT PPRIVILEGE_SET PrivilegeSet, + OUT PULONG ReturnLength, + OUT PACCESS_MASK GrantedAccess, + OUT PNTSTATUS AccessStatus); + +NTSTATUS SERVICECALL +NtAccessCheckAndAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN PUNICODE_STRING ObjectName, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ACCESS_MASK DesiredAccess, + IN PGENERIC_MAPPING GenericMapping, + IN BOOLEAN ObjectCreation, + OUT PACCESS_MASK GrantedAccess, + OUT PNTSTATUS AccessStatus, + OUT PBOOLEAN GenerateOnClose); + +NTSTATUS SERVICECALL +NtAddAtom(IN PWSTR AtomName, + IN ULONG AtomNameLength, + OUT PRTL_ATOM Atom); + +NTSTATUS SERVICECALL +NtAddBootEntry(IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue); + +/* 5 */ +NTSTATUS SERVICECALL +NtAdjustGroupsToken(IN HANDLE TokenHandle, + IN BOOLEAN ResetToDefault, + IN PTOKEN_GROUPS NewState, + IN ULONG BufferLength, + OUT PTOKEN_GROUPS PreviousState OPTIONAL, + OUT PULONG ReturnLength); + +NTSTATUS SERVICECALL +NtAdjustPrivilegesToken (IN HANDLE TokenHandle, + IN BOOLEAN DisableAllPrivileges, + IN PTOKEN_PRIVILEGES NewState, + IN ULONG BufferLength, + OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL, + OUT PULONG ReturnLength OPTIONAL); + +NTSTATUS SERVICECALL +NtAlertResumeThread(IN HANDLE ThreadHandle, + OUT PULONG SuspendCount); + +NTSTATUS SERVICECALL +NtAlertThread (IN HANDLE ThreadHandle); + +NTSTATUS SERVICECALL +NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId); + +/* 10 */ +NTSTATUS SERVICECALL +NtAllocateUuids(OUT PULARGE_INTEGER Time, + OUT PULONG Range, + OUT PULONG Sequence, + OUT PUCHAR Seed); + +NTSTATUS SERVICECALL +NtAllocateVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID* UBaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG URegionSize, + IN ULONG AllocationType, + IN ULONG Protect); + +NTSTATUS SERVICECALL +NtAssignProcessToJobObject(HANDLE JobHandle, + HANDLE ProcessHandle); + +NTSTATUS SERVICECALL +NtCallbackReturn (PVOID Result, + ULONG ResultLength, + NTSTATUS Status); + +NTSTATUS SERVICECALL +NtCancelIoFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock); + +/* 15 */ +NTSTATUS SERVICECALL +NtCancelTimer(IN HANDLE TimerHandle, + OUT PBOOLEAN CurrentState OPTIONAL); + +NTSTATUS SERVICECALL +NtClearEvent(IN HANDLE EventHandle); + +NTSTATUS SERVICECALL +NtCloseObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose); + +NTSTATUS SERVICECALL +NtCompleteConnectPort (HANDLE hServerSideCommPort); + +/* 20 */ +NTSTATUS SERVICECALL +NtConnectPort (PHANDLE UnsafeConnectedPortHandle, + PUNICODE_STRING PortName, + PSECURITY_QUALITY_OF_SERVICE Qos, + PPORT_VIEW UnsafeWriteMap, + PREMOTE_PORT_VIEW UnsafeReadMap, + PULONG UnsafeMaximumMessageSize, + PVOID UnsafeConnectData, + PULONG UnsafeConnectDataLength); + +NTSTATUS SERVICECALL +NtContinue(IN PContext Context, + IN BOOLEAN TestAlert); + +NTSTATUS SERVICECALL +NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); +/* +NTSTATUS SERVICECALL +NtCreateEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState); +*/ + +NTSTATUS SERVICECALL +NtCreateEventPair(OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +/* 25 */ +/* +NTSTATUS SERVICECALL +NtCreateFile(PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + PLARGE_INTEGER AllocateSize, + ULONG FileAttributes, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions, + PVOID EaBuffer, + ULONG EaLength); +*/ + +NTSTATUS SERVICECALL +NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads); + +NTSTATUS SERVICECALL +NtCreateJobObject(PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes); + +NTSTATUS SERVICECALL +NtCreateKey(OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG TitleIndex, + IN PUNICODE_STRING Class, + IN ULONG CreateOptions, + OUT PULONG Disposition); + +NTSTATUS SERVICECALL +NtCreateMailslotFile(OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG CreateOptions, + IN ULONG MailslotQuota, + IN ULONG MaxMessageSize, + IN PLARGE_INTEGER TimeOut); + +/* 30 */ +/* +NTSTATUS SERVICECALL +NtCreateMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN InitialOwner); +*/ + +NTSTATUS SERVICECALL +NtCreateNamedPipeFile(PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions, + ULONG NamedPipeType, + ULONG ReadMode, + ULONG CompletionMode, + ULONG MaximumInstances, + ULONG InboundQuota, + ULONG OutboundQuota, + PLARGE_INTEGER DefaultTimeout); + +NTSTATUS SERVICECALL +NtCreatePagingFile(IN PUNICODE_STRING FileName, + IN PLARGE_INTEGER InitialSize, + IN PLARGE_INTEGER MaximumSize, + IN ULONG Reserved); + +NTSTATUS SERVICECALL +NtCreatePort (PHANDLE PortHandle, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG MaxConnectInfoLength, + ULONG MaxDataLength, + ULONG MaxPoolUsage); + +NTSTATUS SERVICECALL +NtCreateProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL); + +/* 35 */ +NTSTATUS SERVICECALL +NtCreateProfile(OUT PHANDLE ProfileHandle, + IN HANDLE Process OPTIONAL, + IN PVOID ImageBase, + IN ULONG ImageSize, + IN ULONG BucketSize, + IN PVOID Buffer, + IN ULONG BufferSize, + IN KPROFILE_SOURCE ProfileSource, + IN KAFFINITY Affinity); + +/* +NTSTATUS SERVICECALL +NtCreateSection (OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection OPTIONAL, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL); +*/ + +/* +NTSTATUS SERVICECALL +NtCreateSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN LONG InitialCount, + IN LONG MaximumCount); +*/ + +NTSTATUS SERVICECALL +NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING LinkTarget); + +NTSTATUS SERVICECALL +NtCreateThread(OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + OUT PCLIENT_ID ClientId, + IN PCONTEXT ThreadContext, + IN PINITIAL_TEB InitialTeb, + IN BOOLEAN CreateSuspended); + +/* 40 */ +NTSTATUS SERVICECALL +NtCreateTimer(OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN TIMER_TYPE TimerType); + +NTSTATUS SERVICECALL +NtCreateToken(OUT PHANDLE TokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN TOKEN_TYPE TokenType, + IN PLUID AuthenticationId, + IN PLARGE_INTEGER ExpirationTime, + IN PTOKEN_USER TokenUser, + IN PTOKEN_GROUPS TokenGroups, + IN PTOKEN_PRIVILEGES TokenPrivileges, + IN PTOKEN_OWNER TokenOwner, + IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, + IN PTOKEN_DEFAULT_DACL TokenDefaultDacl, + IN PTOKEN_SOURCE TokenSource); + +NTSTATUS SERVICECALL +NtCreateWaitablePort (OUT PHANDLE PortHandle, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG MaxConnectInfoLength, + IN ULONG MaxDataLength, + IN ULONG MaxPoolUsage); + +NTSTATUS SERVICECALL +NtDelayExecution(IN BOOLEAN Alertable, + IN PLARGE_INTEGER DelayInterval); + +NTSTATUS SERVICECALL +NtDeleteAtom(IN RTL_ATOM Atom); + +/* 45 */ +NTSTATUS SERVICECALL +NtDeleteBootEntry(IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue); + +NTSTATUS SERVICECALL +NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes); + +NTSTATUS SERVICECALL +NtDeleteKey(IN HANDLE KeyHandle); + +NTSTATUS SERVICECALL +NtDeleteObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose); + +NTSTATUS SERVICECALL +NtDeleteValueKey (IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName); + +/* 50 */ +NTSTATUS SERVICECALL +NtDeviceIoControlFile(IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength OPTIONAL, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength OPTIONAL); + +NTSTATUS SERVICECALL +NtDisplayString(IN PUNICODE_STRING DisplayString); + +NTSTATUS SERVICECALL +NtDuplicateObject (IN HANDLE SourceProcessHandle, + IN HANDLE SourceHandle, + IN HANDLE TargetProcessHandle, + OUT PHANDLE TargetHandle OPTIONAL, + IN ACCESS_MASK DesiredAccess, + IN ULONG InheritHandle, + IN ULONG Options); + +NTSTATUS SERVICECALL +NtDuplicateToken(IN HANDLE ExistingTokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN EffectiveOnly, + IN TOKEN_TYPE TokenType, + OUT PHANDLE NewTokenHandle); + +NTSTATUS SERVICECALL +NtEnumerateBootEntries(IN ULONG Unknown1, + IN ULONG Unknown2); + +/* 55 */ +NTSTATUS SERVICECALL +NtEnumerateKey(IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength); + +NTSTATUS SERVICECALL +NtEnumerateValueKey(IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength); + +NTSTATUS SERVICECALL +NtExtendSection(IN HANDLE SectionHandle, + IN PLARGE_INTEGER NewMaximumSize); + +NTSTATUS SERVICECALL +NtFindAtom(IN PWSTR AtomName, + IN ULONG AtomNameLength, + OUT PRTL_ATOM Atom); +/* +NTSTATUS SERVICECALL +NtFlushBuffersFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock); +*/ + +/* 60 */ +NTSTATUS SERVICECALL +NtFlushInstructionCache (IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN ULONG NumberOfBytesToFlush); + +NTSTATUS SERVICECALL +NtFlushKey(IN HANDLE KeyHandle); + +NTSTATUS SERVICECALL +NtFlushVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN OUT PSIZE_T RegionSize, + OUT PIO_STATUS_BLOCK IoStatus); + +NTSTATUS SERVICECALL +NtFlushWriteBuffer(VOID); + +NTSTATUS SERVICECALL +NtFreeVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID* PBaseAddress, + IN PULONG PRegionSize, + IN ULONG FreeType); + +/* 65 */ +NTSTATUS SERVICECALL +NtFsControlFile(IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength OPTIONAL, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength OPTIONAL); + +NTSTATUS SERVICECALL +NtGetContextThread(IN HANDLE ThreadHandle, + OUT PCONTEXT ThreadContext); + +NTSTATUS SERVICECALL +NtGetPlugPlayEvent(IN ULONG Reserved1, + IN ULONG Reserved2, + OUT PPLUGPLAY_EVENT_BLOCK Buffer, + IN ULONG BufferSize); + +NTSTATUS SERVICECALL +NtGetTickCount(VOID); + +NTSTATUS SERVICECALL +NtImpersonateClientOfPort (HANDLE PortHandle, + PPORT_MESSAGE ClientMessage); + +/* 70 */ +NTSTATUS SERVICECALL +NtImpersonateThread(IN HANDLE ThreadHandle, + IN HANDLE ThreadToImpersonateHandle, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService); + +NTSTATUS SERVICECALL +NtInitializeRegistry (IN BOOLEAN SetUpBoot); + +NTSTATUS SERVICECALL +NtInitiatePowerAction (IN POWER_ACTION SystemAction, + IN SYSTEM_POWER_STATE MinSystemState, + IN ULONG Flags, + IN BOOLEAN Asynchronous); + +NTSTATUS SERVICECALL +NtIsProcessInJob (IN HANDLE ProcessHandle, + IN HANDLE JobHandle OPTIONAL); + +NTSTATUS SERVICECALL +NtListenPort (IN HANDLE PortHandle, + IN PPORT_MESSAGE ConnectMsg); + +/* 75 */ +NTSTATUS SERVICECALL +NtLoadDriver(IN PUNICODE_STRING DriverServiceName); + +NTSTATUS SERVICECALL +NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes); + +NTSTATUS SERVICECALL +NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes, + IN ULONG Flags); + +NTSTATUS SERVICECALL +NtLockFile(IN HANDLE FileHandle, + IN HANDLE EventHandle OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Length, + IN ULONG Key, + IN BOOLEAN FailImmediately, + IN BOOLEAN ExclusiveLock); + +NTSTATUS SERVICECALL +NtLockVirtualMemory(HANDLE ProcessHandle, + PVOID BaseAddress, + ULONG NumberOfBytesToLock, + PULONG NumberOfBytesLocked); + +/* 80 */ +NTSTATUS SERVICECALL +NtMakePermanentObject(IN HANDLE ObjectHandle); + +NTSTATUS SERVICECALL +NtMakeTemporaryObject(IN HANDLE ObjectHandle); + +/* +NTSTATUS SERVICECALL +NtMapViewOfSection(IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID* BaseAddress OPTIONAL, + IN ULONG ZeroBits OPTIONAL, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PULONG ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType OPTIONAL, + IN ULONG Protect); +*/ + +NTSTATUS SERVICECALL +NtNotifyChangeDirectoryFile(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG BufferSize, + IN ULONG CompletionFilter, + IN BOOLEAN WatchTree); + +NTSTATUS SERVICECALL +NtNotifyChangeKey (IN HANDLE KeyHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG CompletionFilter, + IN BOOLEAN WatchSubtree, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN Asynchronous); + +/* 85 */ +NTSTATUS SERVICECALL +NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +/* +NTSTATUS SERVICECALL +NtOpenEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); +*/ + +NTSTATUS SERVICECALL +NtOpenEventPair(OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +/* +NTSTATUS SERVICECALL +NtOpenFile(PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, + ULONG OpenOptions); +*/ + +NTSTATUS SERVICECALL +NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +/* 90 */ +NTSTATUS SERVICECALL +NtOpenJobObject (PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes); + +NTSTATUS SERVICECALL +NtOpenKey(OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +/* +NTSTATUS SERVICECALL +NtOpenMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); +*/ + +NTSTATUS SERVICECALL +NtOpenObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN PUNICODE_STRING ObjectName, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN ULONG GrantedAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN ObjectCreation, + IN BOOLEAN AccessGranted, + OUT PBOOLEAN GenerateOnClose); + +NTSTATUS SERVICECALL +NtOpenProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId); + +/* 95 */ +NTSTATUS SERVICECALL +NtOpenProcessToken(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle); + +NTSTATUS SERVICECALL +NtOpenProcessTokenEx(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle); + +NTSTATUS SERVICECALL +NtOpenSection(PHANDLE SectionHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes); + +/* +NTSTATUS SERVICECALL +NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); +*/ + +NTSTATUS SERVICECALL +NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +/* 100 */ +NTSTATUS SERVICECALL +NtOpenThread(OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PCLIENT_ID ClientId OPTIONAL); + +NTSTATUS SERVICECALL +NtOpenThreadToken(IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + OUT PHANDLE TokenHandle); + +NTSTATUS SERVICECALL +NtOpenThreadTokenEx(IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle); + +NTSTATUS SERVICECALL +NtOpenTimer(OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes); + +NTSTATUS SERVICECALL +NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, + IN OUT PVOID Buffer, + IN ULONG BufferLength); + +/* 105 */ +NTSTATUS SERVICECALL +NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength); + +NTSTATUS SERVICECALL +NtPrivilegeCheck (IN HANDLE ClientToken, + IN PPRIVILEGE_SET RequiredPrivileges, + IN PBOOLEAN Result); + +NTSTATUS SERVICECALL +NtPrivilegedServiceAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PUNICODE_STRING ServiceName, + IN HANDLE ClientToken, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted); + +NTSTATUS SERVICECALL +NtPrivilegeObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted); + +NTSTATUS SERVICECALL +NtProtectVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *UnsafeBaseAddress, + IN OUT ULONG *UnsafeNumberOfBytesToProtect, + IN ULONG NewAccessProtection, + OUT PULONG UnsafeOldAccessProtection); + +/* 110 */ +/* +NTSTATUS SERVICECALL +NtPulseEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL); +*/ + +NTSTATUS SERVICECALL +NtQueryInformationAtom(RTL_ATOM Atom, + ATOM_INFORMATION_CLASS AtomInformationClass, + PVOID AtomInformation, + ULONG AtomInformationLength, + PULONG ReturnLength); + +NTSTATUS SERVICECALL +NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_BASIC_INFORMATION FileInformation); + +NTSTATUS SERVICECALL +NtQueryBootEntryOrder(IN ULONG Unknown1, + IN ULONG Unknown2); + +NTSTATUS SERVICECALL +NtQueryBootOptions(IN ULONG Unknown1, + IN ULONG Unknown2); + +/* 115 */ +NTSTATUS SERVICECALL +NtQueryDefaultLocale(IN BOOLEAN UserProfile, + OUT PLCID DefaultLocaleId); + +NTSTATUS SERVICECALL +NtQueryDefaultUILanguage(OUT PLANGID LanguageId); + +NTSTATUS SERVICECALL +NtQueryDirectoryFile(IN HANDLE FileHandle, + IN HANDLE PEvent OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan); + +NTSTATUS SERVICECALL +NtQueryDirectoryObject (IN HANDLE DirectoryHandle, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturnLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQueryEaFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID EaList OPTIONAL, + IN ULONG EaListLength, + IN PULONG EaIndex OPTIONAL, + IN BOOLEAN RestartScan); + +/* 120 */ +NTSTATUS SERVICECALL +NtQueryEvent(IN HANDLE EventHandle, + IN EVENT_INFORMATION_CLASS EventInformationClass, + OUT PVOID EventInformation, + IN ULONG EventInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation); + +/* +NTSTATUS SERVICECALL +NtQueryInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); +*/ + +NTSTATUS SERVICECALL +NtQueryInformationJobObject (HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength, + PULONG ReturnLength); + +NTSTATUS SERVICECALL +NtQueryInformationPort (IN HANDLE PortHandle, + IN PORT_INFORMATION_CLASS PortInformationClass, + OUT PVOID PortInformation, + IN ULONG PortInformationLength, + OUT PULONG ReturnLength); + +/* 125 */ +NTSTATUS SERVICECALL +NtQueryInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQueryInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQueryInformationToken(IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength, + OUT PULONG ReturnLength); + +NTSTATUS SERVICECALL +NtQueryInstallUILanguage(OUT PLANGID LanguageId); + +NTSTATUS SERVICECALL +NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource, + OUT PULONG Interval); + +/* 130 */ +NTSTATUS SERVICECALL +NtQueryIoCompletion(IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQueryKey(IN HANDLE KeyHandle, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength); + +NTSTATUS SERVICECALL +NtQueryMultipleValueKey (IN HANDLE KeyHandle, + IN OUT PKEY_VALUE_ENTRY ValueList, + IN ULONG NumberOfValues, + OUT PVOID Buffer, + IN OUT PULONG Length, + OUT PULONG ReturnLength); + +NTSTATUS SERVICECALL +NtQueryMutant(IN HANDLE MutantHandle, + IN MUTANT_INFORMATION_CLASS MutantInformationClass, + OUT PVOID MutantInformation, + IN ULONG MutantInformationLength, + OUT PULONG ResultLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQueryObject (IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL); + +/* 135 */ +NTSTATUS SERVICECALL +NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter, + OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL); + +NTSTATUS SERVICECALL +NtQueryQuotaInformationFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID SidList OPTIONAL, + IN ULONG SidListLength, + IN PSID StartSid OPTIONAL, + IN BOOLEAN RestartScan); + +NTSTATUS SERVICECALL +NtQuerySection(IN HANDLE SectionHandle, + IN SECTION_INFORMATION_CLASS SectionInformationClass, + OUT PVOID SectionInformation, + IN ULONG SectionInformationLength, + OUT PULONG ResultLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQuerySecurityObject(IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ULONG Length, + OUT PULONG ResultLength); + +NTSTATUS SERVICECALL +NtQuerySemaphore(IN HANDLE SemaphoreHandle, + IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + OUT PVOID SemaphoreInformation, + IN ULONG SemaphoreInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +/* 140 */ +NTSTATUS SERVICECALL +NtQuerySymbolicLinkObject(IN HANDLE LinkHandle, + OUT PUNICODE_STRING LinkTarget, + OUT PULONG ResultLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQuerySystemEnvironmentValue (IN PUNICODE_STRING VariableName, + OUT PWSTR ValueBuffer, + IN ULONG ValueBufferLength, + IN OUT PULONG ReturnLength OPTIONAL); + +NTSTATUS SERVICECALL +NtQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG Length, + OUT PULONG UnsafeResultLength); + +NTSTATUS SERVICECALL +NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime); + +NTSTATUS SERVICECALL +NtQueryTimer(IN HANDLE TimerHandle, + IN TIMER_INFORMATION_CLASS TimerInformationClass, + OUT PVOID TimerInformation, + IN ULONG TimerInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +/* 145 */ +NTSTATUS SERVICECALL +NtQueryTimerResolution(OUT PULONG MinimumResolution, + OUT PULONG MaximumResolution, + OUT PULONG ActualResolution); + +NTSTATUS SERVICECALL +NtQueryValueKey(IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength); + +NTSTATUS SERVICECALL +NtQueryVirtualMemory (IN HANDLE ProcessHandle, + IN PVOID Address, + IN LONG VirtualMemoryInformationClass, + OUT PVOID VirtualMemoryInformation, + IN ULONG Length, + OUT PULONG UnsafeResultLength); + +NTSTATUS SERVICECALL +NtQueryVolumeInformationFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass); + +NTSTATUS SERVICECALL +NtQueueApcThread(HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2); + +/* 150 */ +NTSTATUS SERVICECALL +NtRaiseException(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context, + IN BOOLEAN SearchFrames); + +NTSTATUS SERVICECALL +NtRaiseHardError(IN NTSTATUS ErrorStatus, + IN ULONG NumberOfParameters, + IN ULONG UnicodeStringParameterMask, + IN PULONG_PTR Parameters, + IN ULONG ValidResponseOptions, + OUT PULONG Response); + +/* +NTSTATUS SERVICECALL +NtReadFile(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL); +*/ + +NTSTATUS SERVICECALL +NtReadFileScatter(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription [], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL); + +NTSTATUS SERVICECALL +NtReadRequestData (HANDLE PortHandle, + PPORT_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG Returnlength); + +/* 155 */ +NTSTATUS SERVICECALL +NtReadVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead OPTIONAL); + +NTSTATUS SERVICECALL +NtRegisterThreadTerminatePort(HANDLE PortHandle); + +/* +NTSTATUS SERVICECALL +NtReleaseMutant(IN HANDLE MutantHandle, + IN PLONG PreviousCount OPTIONAL); +*/ + +/* +NTSTATUS SERVICECALL +NtReleaseSemaphore(IN HANDLE SemaphoreHandle, + IN LONG ReleaseCount, + OUT PLONG PreviousCount OPTIONAL); +*/ + +NTSTATUS SERVICECALL +NtRemoveIoCompletion(IN HANDLE IoCompletionHandle, + OUT PVOID *CompletionKey, + OUT PVOID *CompletionContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL); + +/* 160 */ +NTSTATUS SERVICECALL +NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes, + IN HANDLE Key, + IN POBJECT_ATTRIBUTES ReplacedObjectAttributes); + +NTSTATUS SERVICECALL +NtReplyPort (IN HANDLE PortHandle, + IN PPORT_MESSAGE LpcReply); + +NTSTATUS SERVICECALL +NtReplyWaitReceivePort(IN HANDLE PortHandle, + OUT PVOID *PortContext OPTIONAL, + IN PPORT_MESSAGE ReplyMessage OPTIONAL, + OUT PPORT_MESSAGE ReceiveMessage); + +NTSTATUS SERVICECALL +NtReplyWaitReplyPort (HANDLE PortHandle, + PPORT_MESSAGE ReplyMessage); + +NTSTATUS SERVICECALL +NtRequestPort (IN HANDLE PortHandle, + IN PPORT_MESSAGE LpcMessage); + +/* 165 */ +NTSTATUS SERVICECALL +NtRequestWaitReplyPort (IN HANDLE PortHandle, + PPORT_MESSAGE UnsafeLpcRequest, + PPORT_MESSAGE UnsafeLpcReply); + +/* +NTSTATUS SERVICECALL +NtResetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL); +*/ + +NTSTATUS SERVICECALL +NtRestoreKey (IN HANDLE KeyHandle, + IN HANDLE FileHandle, + IN ULONG RestoreFlags); + +NTSTATUS SERVICECALL +NtResumeThread(IN HANDLE ThreadHandle, + IN PULONG SuspendCount OPTIONAL); + +NTSTATUS SERVICECALL +NtSaveKey (IN HANDLE KeyHandle, + IN HANDLE FileHandle); + +/* 170 */ +NTSTATUS SERVICECALL +NtSaveKeyEx(IN HANDLE KeyHandle, + IN HANDLE FileHandle, + IN ULONG Flags); /* REG_STANDARD_FORMAT, etc.. */ + +NTSTATUS SERVICECALL +NtSetBootEntryOrder(IN ULONG Unknown1, + IN ULONG Unknown2); + +NTSTATUS SERVICECALL +NtSetBootOptions(ULONG Unknown1, + ULONG Unknown2); + +NTSTATUS SERVICECALL +NtSetIoCompletion(IN HANDLE IoCompletionPortHandle, + IN PVOID CompletionKey, + IN PVOID CompletionContext, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation); + +NTSTATUS SERVICECALL +NtSetContextThread(IN HANDLE ThreadHandle, + IN PCONTEXT ThreadContext); + +/* 175 */ +NTSTATUS SERVICECALL +NtSetDefaultHardErrorPort(IN HANDLE PortHandle); + +NTSTATUS SERVICECALL +NtSetDefaultLocale(IN BOOLEAN UserProfile, + IN LCID DefaultLocaleId); + +NTSTATUS SERVICECALL +NtSetDefaultUILanguage(IN LANGID LanguageId); + +NTSTATUS SERVICECALL +NtSetEaFile(IN HANDLE FileHandle, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID EaBuffer, + IN ULONG EaBufferSize); + +/* +NTSTATUS SERVICECALL +NtSetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL); +*/ + +/* 180 */ +NTSTATUS SERVICECALL +NtSetHighEventPair(IN HANDLE EventPairHandle); + +NTSTATUS SERVICECALL +NtSetHighWaitLowEventPair(IN HANDLE EventPairHandle); + +/* +NTSTATUS SERVICECALL +NtSetInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); +*/ + +NTSTATUS SERVICECALL +NtSetInformationKey (IN HANDLE KeyHandle, + IN KEY_SET_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG KeyInformationLength); + +NTSTATUS SERVICECALL +NtSetInformationJobObject (HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength); + +/* 185 */ +NTSTATUS SERVICECALL +NtSetInformationObject (IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + IN PVOID ObjectInformation, + IN ULONG Length); + +NTSTATUS SERVICECALL +NtSetInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength); + +NTSTATUS SERVICECALL +NtSetInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength); + +NTSTATUS SERVICECALL +NtSetInformationToken(IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength); + +NTSTATUS SERVICECALL +NtSetIntervalProfile(IN ULONG Interval, + IN KPROFILE_SOURCE Source); + +/* 190 */ +NTSTATUS SERVICECALL +NtSetLdtEntries (ULONG Selector1, + LDT_ENTRY LdtEntry1, + ULONG Selector2, + LDT_ENTRY LdtEntry2); + +NTSTATUS SERVICECALL +NtSetLowEventPair(IN HANDLE EventPairHandle); + +NTSTATUS SERVICECALL +NtSetLowWaitHighEventPair(IN HANDLE EventPairHandle); + +NTSTATUS SERVICECALL +NtSetQuotaInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID Buffer, + ULONG BufferLength); + +NTSTATUS SERVICECALL +NtSetSecurityObject(IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor); + +/* 195 */ +NTSTATUS SERVICECALL +NtSetSystemEnvironmentValue (IN PUNICODE_STRING VariableName, + IN PUNICODE_STRING Value); + +NTSTATUS SERVICECALL +NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + IN PVOID SystemInformation, + IN ULONG SystemInformationLength); + +NTSTATUS SERVICECALL +NtSetSystemPowerState(IN POWER_ACTION SystemAction, + IN SYSTEM_POWER_STATE MinSystemState, + IN ULONG Flags); + +NTSTATUS SERVICECALL +NtSetSystemTime(IN PLARGE_INTEGER SystemTime, + OUT PLARGE_INTEGER PreviousTime OPTIONAL); + +NTSTATUS SERVICECALL +NtSetTimer(IN HANDLE TimerHandle, + IN PLARGE_INTEGER DueTime, + IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL, + IN PVOID TimerContext OPTIONAL, + IN BOOLEAN WakeTimer, + IN LONG Period OPTIONAL, + OUT PBOOLEAN PreviousState OPTIONAL); + +/* 200 */ +NTSTATUS SERVICECALL +NtSetTimerResolution(IN ULONG DesiredResolution, + IN BOOLEAN SetResolution, + OUT PULONG CurrentResolution); + +NTSTATUS SERVICECALL +NtSetUuidSeed(IN PUCHAR Seed); + +NTSTATUS SERVICECALL +NtSetValueKey(IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN ULONG TitleIndex, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize); + +NTSTATUS SERVICECALL +NtSetVolumeInformationFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass); + +NTSTATUS SERVICECALL +NtShutdownSystem(IN SHUTDOWN_ACTION Action); + +/* 205*/ +NTSTATUS SERVICECALL +NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, + IN HANDLE WaitableObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL); + +NTSTATUS SERVICECALL +NtStartProfile(IN HANDLE ProfileHandle); + +NTSTATUS SERVICECALL +NtStopProfile(IN HANDLE ProfileHandle); + +NTSTATUS SERVICECALL +NtSuspendThread(IN HANDLE ThreadHandle, + IN PULONG PreviousSuspendCount OPTIONAL); + +NTSTATUS SERVICECALL +NtSystemDebugControl(DEBUG_CONTROL_CODE ControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength, + PULONG ReturnLength); + +/* 210 */ +NTSTATUS SERVICECALL +NtTerminateJobObject(HANDLE JobHandle, + NTSTATUS ExitStatus); + +NTSTATUS SERVICECALL +NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, + IN NTSTATUS ExitStatus); + +NTSTATUS SERVICECALL +NtTerminateThread(IN HANDLE ThreadHandle, + IN NTSTATUS ExitStatus); + +NTSTATUS SERVICECALL +NtTestAlert(VOID); + +NTSTATUS SERVICECALL +NtTraceEvent(IN ULONG TraceHandle, + IN ULONG Flags, + IN ULONG TraceHeaderLength, + IN struct _EVENT_TRACE_HEADER* TraceHeader); + +/* 215 */ +NTSTATUS SERVICECALL +NtTranslateFilePath(ULONG Unknown1, + ULONG Unknown2, + ULONG Unknown3); + +NTSTATUS SERVICECALL +NtUnloadDriver(IN PUNICODE_STRING DriverServiceName); + +NTSTATUS SERVICECALL +NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes); + +NTSTATUS SERVICECALL +NtUnlockFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Length, + OUT ULONG Key OPTIONAL); + +NTSTATUS SERVICECALL +NtUnlockVirtualMemory(HANDLE ProcessHandle, + PVOID BaseAddress, + ULONG NumberOfBytesToUnlock, + PULONG NumberOfBytesUnlocked OPTIONAL); + +/* 220 */ +/* +NTSTATUS SERVICECALL +NtUnmapViewOfSection (HANDLE ProcessHandle, + PVOID BaseAddress); +*/ + +NTSTATUS SERVICECALL +NtVdmControl(ULONG ControlCode,PVOID ControlData); + +/* +NTSTATUS SERVICECALL +NtWaitForMultipleObjects(IN ULONG ObjectCount, + IN PHANDLE HandleArray, + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL); +*/ + +NTSTATUS SERVICECALL +NtWaitForSingleObject(IN HANDLE ObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL); + +NTSTATUS SERVICECALL +NtWaitHighEventPair(IN HANDLE EventPairHandle); + +/* 225 */ +NTSTATUS SERVICECALL +NtWaitLowEventPair(IN HANDLE EventPairHandle); + +/* +NTSTATUS SERVICECALL +NtWriteFile (IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL); +*/ + +NTSTATUS SERVICECALL +NtWriteFileGather(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription [], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL); + +NTSTATUS SERVICECALL +NtWriteRequestData (HANDLE PortHandle, + PPORT_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnLength); + +NTSTATUS SERVICECALL +NtWriteVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten OPTIONAL); + +/* 230 */ +NTSTATUS SERVICECALL +NtW32Call(IN ULONG RoutineIndex, + IN PVOID Argument, + IN ULONG ArgumentLength, + OUT PVOID* Result OPTIONAL, + OUT PULONG ResultLength OPTIONAL); + +NTSTATUS SERVICECALL +NtYieldExecution(VOID); + +NTSTATUS SERVICECALL +NtWineService(PSERVER_REQUEST_INFO ReqMsg); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _W32SYSCALL_H */ + + + + diff --git a/unifiedkernel/include/wcstr.h b/unifiedkernel/include/wcstr.h new file mode 100644 index 0000000..009bf8e --- /dev/null +++ b/unifiedkernel/include/wcstr.h @@ -0,0 +1,87 @@ +/* + * wcstr.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + + +/* + * wcstr.h: wide char string functions + * Refered to Linux kernel code + */ + +#ifndef _WCSTR_H +#define _WCSTR_H + +#include +#include +#include +#include +#include +#include +#include "win32.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +/* + * Copy a null terminated wide string from userspace. + */ +#define __do_wstrncpy_from_user(dst,src,count,res) \ +do { \ + int __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " testl %1,%1\n" \ + " jz 2f\n" \ + "0: lodsw\n" \ + " stosw\n" \ + " testw %%ax,%%ax\n" \ + " jz 1f\n" \ + " decl %1\n" \ + " jnz 0b\n" \ + "1: subl %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %5,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + "=&D" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ + : "memory"); \ +} while (0) + +extern long wstrncpy_from_user(wchar_t *dst, const wchar_t *src, long count); +extern long wstrnlen_user(const wchar_t *s, long n); +extern wchar_t *getwname(const wchar_t __user *wname); +extern void putwname(const wchar_t *wname); +extern size_t wcslen(PWSTR ws); +extern WCHAR *wmemchr(const WCHAR *wcs, WCHAR wc, size_t count); +extern WCHAR *wcschr(const WCHAR *wcs, WCHAR wc); +extern WCHAR *wcsrchr(const char *wcs, WCHAR wc); +extern WCHAR *wcscpy(WCHAR *dest, const WCHAR *src); +extern int wcscmp(const WCHAR *wcs,const WCHAR *wct); +extern int wcsncmp(const WCHAR *wcs, const WCHAR *wct, size_t count); + +#endif + +#endif diff --git a/unifiedkernel/include/win32.h b/unifiedkernel/include/win32.h new file mode 100644 index 0000000..70af47d --- /dev/null +++ b/unifiedkernel/include/win32.h @@ -0,0 +1,1828 @@ +/* + * win32.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * win32.h includes the type definitions of W32 syscall functions. + * Refered to ReactOS code + */ + +#ifndef _WIN32_H +#define _WIN32_H + +#include +#include +#if 0 +#include +#endif +#include +#include "win32_process.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define EXE_SO + +#ifndef CREATE_THREAD +#define CREATE_THREAD 2 +#endif + +#define IN +#define OUT +#define ANYSIZE_ARRAY 1 +#define WINAPI __stdcall +#define NTAPI __stdcall +#define STDCALL __stdcall +#define DDKAPI /* TODO: that definition will be move to DDK header file */ +#ifndef __stdcall +#define __stdcall __attribute__((stdcall)) +#endif +#ifndef NULL +#define NULL 0 +#endif + +#ifdef KDEBUG +#define kdebug(FMT...) printk(FMT) +#else +#define kdebug(FMT...) +#endif + +#ifdef KTRACE +#define ktrace(FMT...) printk(FMT) +#else +#define ktrace(FMT...) +#endif + +#define _ANONYMOUS_UNION __extension__ + +#define NOREGPARM __attribute__((regparm(0))) +#define SERVICECALL STDCALL NOREGPARM + +#define NT_SUCCESS(st) ((st) == STATUS_SUCCESS) + +#define OPTIONAL +#define OBJ_INHERIT 0x00000002L +#define OBJ_PERMANENT 0x00000010L +#define OBJ_EXCLUSIVE 0x00000020L +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define OBJ_OPENIF 0x00000080L +#define OBJ_OPENLINK 0x00000100L +#define OBJ_KERNEL_HANDLE 0x00000200L +#define OBJ_VALID_ATTRIBUTES 0x000003F2L + +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 +#define DUPLICATE_SAME_ATTRIBUTES 0x00000004 + +#define IO_TYPE_FILE 0x0F5L /* Temp Hack */ + +#define MINLONG 0x80000000 + +#define __int64 long long +#define CONST const + +typedef void VOID, *PVOID; +typedef void *LPVOID; +typedef void *PVOID64; +typedef void *HANDLE; +typedef const void *LPCVOID; + +typedef char BOOLEAN, *PBOOLEAN; +typedef const char *LPCSTR; +typedef char CCHAR, *PCCHAR; +typedef signed char CHAR, *PCHAR, *LPSTR, *PSTR; +typedef unsigned short WORD, *LPWORD; +typedef unsigned char UCHAR, *PUCHAR; +typedef unsigned char BYTE; +typedef unsigned char UINT8; + +typedef unsigned short WCHAR; +typedef short SHORT, CSHORT; +typedef unsigned short USHORT, *PUSHORT; +typedef unsigned short UINT16; + +typedef signed int LONG, *PLONG; +typedef unsigned int UINT; +typedef unsigned int UINT32; +typedef unsigned int DWORD; +typedef unsigned int ULONG, *PULONG;; + +typedef unsigned long ULONG_PTR, *PULONG_PTR; + +typedef long long LONGLONG; +typedef unsigned long long ULONGLONG; + +typedef unsigned __int64 ULONG64, *PULONG64; + +typedef struct SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES; +typedef struct OFSTRUCT *LPOFSTRUCT; + +typedef BYTE BOOL; +typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE, *PSECURITY_CONTEXT_TRACKING_MODE; +typedef WORD *PSECURITY_DESCRIPTOR_CONTROL; +typedef DWORD *PDWORD, *LPDWORD; +typedef DWORD LCID; +typedef DWORD *PACCESS_MASK; +typedef DWORD SECURITY_INFORMATION, *PSECURITY_INFORMATION; +typedef PDWORD PLCID; + +typedef USHORT RTL_ATOM, *PRTL_ATOM; +typedef USHORT LANGID, *PLANGID; +typedef LONG NTSTATUS, *PNTSTATUS; +typedef ULONG_PTR KAFFINITY; +typedef ULONG_PTR SIZE_T, *PSIZE_T; +typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; + +typedef HANDLE *PHANDLE, *LPHANDLE; + +typedef UCHAR SSPT, *PSSPT; +typedef WCHAR *PWCHAR, *LPWCH, *PWCH, *NWPSTR, *LPWSTR, *PWSTR; +typedef const WCHAR *LPCWSTR, *PCWSTR; +typedef PVOID PSID; +typedef PVOID (NTAPI * SSDT)(VOID); +typedef PVOID PACCESS_TOKEN; +typedef SSDT *PSSDT; +typedef struct list_head LIST_ENTRY; + +#define LPC_SIZE_T SIZE_T +#define LPC_PVOID PVOID +#define LPC_HANDLE HANDLE +#define LPC_CLIENT_ID CLIENT_ID +#define EXCEPTION_MAXIMUM_PARAMETERS 15 +#define _ANONYMOUS_STRUCT + +#define FALSE false +#define false (BOOLEAN)0 +#define TRUE true +#define true (BOOLEAN)1 + +#define const_cpu_to_le16(x) __constant_cpu_to_le16(x) + + +#define PROCESS_TERMINATE 1 +#define PROCESS_CREATE_THREAD 2 +#define PROCESS_SET_SESSIONID 4 +#define PROCESS_VM_OPERATION 8 +#define PROCESS_VM_READ 16 +#define PROCESS_VM_WRITE 32 +#define PROCESS_DUP_HANDLE 64 +#define PROCESS_CREATE_PROCESS 128 +#define PROCESS_SET_QUOTA 256 +#define PROCESS_SET_INFORMATION 512 +#define PROCESS_QUERY_INFORMATION 1024 +#define PROCESS_SUSPEND_RESUME 2048 +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xFFF) +#define THREAD_TERMINATE 1 +#define THREAD_SUSPEND_RESUME 2 +#define THREAD_GET_CONTEXT 8 +#define THREAD_SET_CONTEXT 16 +#define THREAD_SET_INFORMATION 32 +#define THREAD_QUERY_INFORMATION 64 +#define THREAD_SET_THREAD_TOKEN 128 +#define THREAD_IMPERSONATE 256 +#define THREAD_DIRECT_IMPERSONATION 0x200 +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3FF) +#define THREAD_BASE_PRIORITY_LOWRT 15 +#define THREAD_BASE_PRIORITY_MAX 2 +#define THREAD_BASE_PRIORITY_MIN (-2) +#define THREAD_BASE_PRIORITY_IDLE (-15) + +#define TOKEN_ASSIGN_PRIMARY (0x0001) +#define TOKEN_DUPLICATE (0x0002) +#define TOKEN_IMPERSONATE (0x0004) +#define TOKEN_QUERY (0x0008) +#define TOKEN_QUERY_SOURCE (0x0010) +#define TOKEN_ADJUST_PRIVILEGES (0x0020) +#define TOKEN_ADJUST_GROUPS (0x0040) +#define TOKEN_ADJUST_DEFAULT (0x0080) +#define TOKEN_ADJUST_SESSIONID (0x0100) +#define TOKEN_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED |\ + TOKEN_ASSIGN_PRIMARY |\ + TOKEN_DUPLICATE |\ + TOKEN_IMPERSONATE |\ + TOKEN_QUERY |\ + TOKEN_QUERY_SOURCE |\ + TOKEN_ADJUST_PRIVILEGES |\ + TOKEN_ADJUST_GROUPS |\ + TOKEN_ADJUST_DEFAULT |\ + TOKEN_ADJUST_SESSIONID) +#define TOKEN_READ (STANDARD_RIGHTS_READ |\ + TOKEN_QUERY) +#define TOKEN_WRITE (STANDARD_RIGHTS_WRITE |\ + TOKEN_ADJUST_PRIVILEGES |\ + TOKEN_ADJUST_GROUPS |\ + TOKEN_ADJUST_DEFAULT) + +#define TOKEN_EXECUTE (STANDARD_RIGHTS_EXECUTE) +#define TOKEN_SOURCE_LENGTH 8 + +#ifdef SERVER_PM +#define MAXIMUM_SUSPEND_COUNT 127 +#endif + +typedef enum _MODE { + KernelMode, + UserMode, + MaxiumMode +} MODE; + +typedef enum _TIMER_TYPE +{ + NotificationTimer, + SynchronizationTimer +} TIMER_TYPE; + +typedef enum tagTOKEN_TYPE { + TokenPrimary = 1, + TokenImpersonation +} TOKEN_TYPE,*PTOKEN_TYPE; + +typedef enum _KPROFILE_SOURCE +{ + ProfileTime, + ProfileAlignmentFixup, + ProfileTotalIssues, + ProfilePipelineDry, + ProfileLoadInstructions, + ProfilePipelineFrozen, + ProfileBranchInstructions, + ProfileTotalNonissues, + ProfileDcacheMisses, + ProfileIcacheMisses, + ProfileCacheMisses, + ProfileBranchMispredictions, + ProfileStoreInstructions, + ProfileFpInstructions, + ProfileIntegerInstructions, + Profile2Issue, + Profile3Issue, + Profile4Issue, + ProfileSpecialInstructions, + ProfileTotalCycles, + ProfileIcacheIssues, + ProfileDcacheAccesses, + ProfileMemoryBarrierCycles, + ProfileLoadLinkedIssues, + ProfileMaximum +} KPROFILE_SOURCE; + +typedef enum _EVENT_TYPE +{ + SynchronizationEvent, + NotificationEvent +} EVENT_TYPE; + +typedef enum _PNP_VETO_TYPE { + PNP_VetoTypeUnknown, + PNP_VetoLegacyDevice, + PNP_VetoPendingClose, + PNP_VetoWindowsApp, + PNP_VetoWindowsService, + PNP_VetoOutstandingOpen, + PNP_VetoDevice, + PNP_VetoDriver, + PNP_VetoIllegalDeviceRequest, + PNP_VetoInsufficientPower, + PNP_VetoNonDisableable, + PNP_VetoLegacyDriver +} PNP_VETO_TYPE, *PPNP_VETO_TYPE; + +typedef enum _PLUGPLAY_EVENT_CATEGORY +{ + HardwareProfileChangeEvent, + TargetDeviceChangeEvent, + DeviceClassChangeEvent, + CustomDeviceEvent, + DeviceInstallEvent, + DeviceArrivalEvent, + PowerEvent, + VetoEvent, + BlockedDriverEvent, + MaxPlugEventCategory +} PLUGPLAY_EVENT_CATEGORY; + +typedef enum _SECURITY_IMPERSONATION_LEVEL { + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation +} SECURITY_IMPERSONATION_LEVEL,*PSECURITY_IMPERSONATION_LEVEL; + + +typedef enum { + SE_OWNER_DEFAULTED = const_cpu_to_le16(0x0001), + SE_GROUP_DEFAULTED = const_cpu_to_le16(0x0002), + SE_DACL_PRESENT = const_cpu_to_le16(0x0004), + SE_DACL_DEFAULTED = const_cpu_to_le16(0x0008), + SE_SACL_PRESENT = const_cpu_to_le16(0x0010), + SE_SACL_DEFAULTED = const_cpu_to_le16(0x0020), + SE_DACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0100), + SE_SACL_AUTO_INHERIT_REQ = const_cpu_to_le16(0x0200), + SE_DACL_AUTO_INHERITED = const_cpu_to_le16(0x0400), + SE_SACL_AUTO_INHERITED = const_cpu_to_le16(0x0800), + SE_DACL_PROTECTED = const_cpu_to_le16(0x1000), + SE_SACL_PROTECTED = const_cpu_to_le16(0x2000), + SE_RM_CONTROL_VALID = const_cpu_to_le16(0x4000), + SE_SELF_RELATIVE = const_cpu_to_le16(0x8000), +} __attribute__ ((__packed__)) SECURITY_DESCRIPTOR_CONTROL; + +#define const_cpu_to_le32(x) __constant_cpu_to_le32(x) + +typedef enum { + /* + * The specific rights (bits 0 to 15). Depend on the type of the + * object being secured by the ACE. + */ + + /* Specific rights for files and directories are as follows: */ + + /* Right to read data from the file. (FILE) */ + FILE_READ_DATA = const_cpu_to_le32(0x00000001), + /* Right to list contents of a directory. (DIRECTORY) */ + FILE_LIST_DIRECTORY = const_cpu_to_le32(0x00000001), + + /* Right to write data to the file. (FILE) */ + FILE_WRITE_DATA = const_cpu_to_le32(0x00000002), + /* Right to create a file in the directory. (DIRECTORY) */ + FILE_ADD_FILE = const_cpu_to_le32(0x00000002), + + /* Right to append data to the file. (FILE) */ + FILE_APPEND_DATA = const_cpu_to_le32(0x00000004), + /* Right to create a subdirectory. (DIRECTORY) */ + FILE_ADD_SUBDIRECTORY = const_cpu_to_le32(0x00000004), + + /* Right to read extended attributes. (FILE/DIRECTORY) */ + FILE_READ_EA = const_cpu_to_le32(0x00000008), + + /* Right to write extended attributes. (FILE/DIRECTORY) */ + FILE_WRITE_EA = const_cpu_to_le32(0x00000010), + + /* Right to execute a file. (FILE) */ + FILE_EXECUTE = const_cpu_to_le32(0x00000020), + /* Right to traverse the directory. (DIRECTORY) */ + FILE_TRAVERSE = const_cpu_to_le32(0x00000020), + + /* + * Right to delete a directory and all the files it contains (its + * children), even if the files are read-only. (DIRECTORY) + */ + FILE_DELETE_CHILD = const_cpu_to_le32(0x00000040), + + /* Right to read file attributes. (FILE/DIRECTORY) */ + FILE_READ_ATTRIBUTES = const_cpu_to_le32(0x00000080), + + /* Right to change file attributes. (FILE/DIRECTORY) */ + FILE_WRITE_ATTRIBUTES = const_cpu_to_le32(0x00000100), + + /* + * The standard rights (bits 16 to 23). Are independent of the type of + * object being secured. + */ + + /* Right to delete the object. */ + DELETE = const_cpu_to_le32(0x00010000), + + /* + * Right to read the information in the object's security descriptor, + * not including the information in the SACL. I.e. right to read the + * security descriptor and owner. + */ + READ_CONTROL = const_cpu_to_le32(0x00020000), + + /* Right to modify the DACL in the object's security descriptor. */ + WRITE_DAC = const_cpu_to_le32(0x00040000), + + /* Right to change the owner in the object's security descriptor. */ + WRITE_OWNER = const_cpu_to_le32(0x00080000), + + /* + * Right to use the object for synchronization. Enables a process to + * wait until the object is in the signalled state. Some object types + * do not support this access right. + */ + SYNCHRONIZE = const_cpu_to_le32(0x00100000), + + /* + * The following STANDARD_RIGHTS_* are combinations of the above for + * convenience and are defined by the Win32 API. + */ + + /* These are currently defined to READ_CONTROL. */ + STANDARD_RIGHTS_READ = const_cpu_to_le32(0x00020000), + STANDARD_RIGHTS_WRITE = const_cpu_to_le32(0x00020000), + STANDARD_RIGHTS_EXECUTE = const_cpu_to_le32(0x00020000), + + /* Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access. */ + STANDARD_RIGHTS_REQUIRED = const_cpu_to_le32(0x000f0000), + + /* + * Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and + * SYNCHRONIZE access. + */ + STANDARD_RIGHTS_ALL = const_cpu_to_le32(0x001f0000), + + /* + * The access system ACL and maximum allowed access types (bits 24 to + * 25, bits 26 to 27 are reserved). + */ + ACCESS_SYSTEM_SECURITY = const_cpu_to_le32(0x01000000), + MAXIMUM_ALLOWED = const_cpu_to_le32(0x02000000), + + /* + * The generic rights (bits 28 to 31). These map onto the standard and + * specific rights. + */ + + /* Read, write, and execute access. */ + GENERIC_ALL = const_cpu_to_le32(0x10000000), + + /* Execute access. */ + GENERIC_EXECUTE = const_cpu_to_le32(0x20000000), + + /* + * Write access. For files, this maps onto: + * FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | + * FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE + * For directories, the mapping has the same numberical value. See + * above for the descriptions of the rights granted. + */ + GENERIC_WRITE = const_cpu_to_le32(0x40000000), + + /* + * Read access. For files, this maps onto: + * FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA | + * STANDARD_RIGHTS_READ | SYNCHRONIZE + * For directories, the mapping has the same numberical value. See + * above for the descriptions of the rights granted. + */ + GENERIC_READ = const_cpu_to_le32(0x80000000), +} ACCESS_MASK; + +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation +} KEY_INFORMATION_CLASS; + +typedef enum _KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation, + KeyValueFullInformation, + KeyValuePartialInformation, + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64 +} KEY_VALUE_INFORMATION_CLASS; + +typedef enum { + PowerActionNone, + PowerActionReserved, + PowerActionSleep, + PowerActionHibernate, + PowerActionShutdown, + PowerActionShutdownReset, + PowerActionShutdownOff, + PowerActionWarmEject +} POWER_ACTION, *PPOWER_ACTION; + +typedef enum _SYSTEM_POWER_STATE { + PowerSystemUnspecified, + PowerSystemWorking, + PowerSystemSleeping1, + PowerSystemSleeping2, + PowerSystemSleeping3, + PowerSystemHibernate, + PowerSystemShutdown, + PowerSystemMaximum +} SYSTEM_POWER_STATE, *PSYSTEM_POWER_STATE; + +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT; + +typedef enum _PLUGPLAY_CONTROL_CLASS +{ + PlugPlayControlUserResponse = 0x07, + PlugPlayControlProperty = 0x0A, + PlugPlayControlGetRelatedDevice = 0x0C, + PlugPlayControlDeviceStatus = 0x0E, + PlugPlayControlGetDeviceDepth, + PlugPlayControlResetDevice = 0x14 +} PLUGPLAY_CONTROL_CLASS; + +typedef enum _POWER_INFORMATION_LEVEL { + SystemPowerPolicyAc, + SystemPowerPolicyDc, + VerifySystemPolicyAc, + VerifySystemPolicyDc, + SystemPowerCapabilities, + SystemBatteryState, + SystemPowerStateHandler, + ProcessorStateHandler, + SystemPowerPolicyCurrent, + AdministratorPowerPolicy, + SystemReserveHiberFile, + ProcessorInformation, + SystemPowerInformation, + ProcessorStateHandler2, + LastWakeTime, + LastSleepTime, + SystemExecutionState, + SystemPowerStateNotifyHandler, + ProcessorPowerPolicyAc, + ProcessorPowerPolicyDc, + VerifyProcessorPowerPolicyAc, + VerifyProcessorPowerPolicyDc, + ProcessorPowerPolicyCurrent +} POWER_INFORMATION_LEVEL; + +typedef enum _ATOM_INFORMATION_CLASS +{ + AtomBasicInformation, + AtomTableInformation, +} ATOM_INFORMATION_CLASS; + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +typedef enum _EVENT_INFORMATION_CLASS +{ + EventBasicInformation +} EVENT_INFORMATION_CLASS; + +typedef enum _JOBOBJECTINFOCLASS +{ + JobObjectBasicAccountingInformation = 1, + JobObjectBasicLimitInformation, + JobObjectBasicProcessIdList, + JobObjectBasicUIRestrictions, + JobObjectSecurityLimitInformation, + JobObjectEndOfJobTimeInformation, + JobObjectAssociateCompletionPortInformation, + JobObjectBasicAndIoAccountingInformation, + JobObjectExtendedLimitInformation, + JobObjectJobSetInformation, + MaxJobObjectInfoClass +} JOBOBJECTINFOCLASS; + +typedef enum _PORT_INFORMATION_CLASS +{ + PortNoInformation +} PORT_INFORMATION_CLASS; + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation, + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + ProcessWow64Information, + ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + ProcessBreakOnTermination, + ProcessDebugObjectHandle, + ProcessDebugFlags, + ProcessHandleTracing, + ProcessIoPriority, + ProcessExecuteFlags, + ProcessTlsInformation, + ProcessCookie, + ProcessImageInformation, + ProcessCycleTime, + ProcessPagePriority, + ProcessInstrumentationCallback, + MaxProcessInfoClass +} PROCESSINFOCLASS; + +typedef enum _THREADINFOCLASS +{ + ThreadBasicInformation, + ThreadTimes, + ThreadPriority, + ThreadBasePriority, + ThreadAffinityMask, + ThreadImpersonationToken, + ThreadDescriptorTableEntry, + ThreadEnableAlignmentFaultFixup, + ThreadEventPair_Reusable, + ThreadQuerySetWin32StartAddress, + ThreadZeroTlsCell, + ThreadPerformanceCount, + ThreadAmILastThread, + ThreadIdealProcessor, + ThreadPriorityBoost, + ThreadSetTlsArrayAddress, + ThreadIsIoPending, + ThreadHideFromDebugger, + ThreadBreakOnTermination, + ThreadSwitchLegacyState, + ThreadIsTerminated, + ThreadLastSystemCall, + ThreadIoPriority, + ThreadCycleTime, + ThreadPagePriority, + ThreadActualBasePriority, + MaxThreadInfoClass +} THREADINFOCLASS; + +typedef enum _TOKEN_INFORMATION_CLASS { + TokenUser=1,TokenGroups,TokenPrivileges,TokenOwner, + TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType, + TokenImpersonationLevel,TokenStatistics,TokenRestrictedSids, + TokenSessionId,TokenGroupsAndPrivileges,TokenSessionReference, + TokenSandBoxInert,TokenAuditPolicy,TokenOrigin, +} TOKEN_INFORMATION_CLASS; + +typedef enum _MUTANT_INFORMATION_CLASS +{ + MutantBasicInformation +} MUTANT_INFORMATION_CLASS; + +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation, + ObjectNameInformation, + ObjectTypeInformation, + ObjectAllTypesInformation, + ObjectHandleInformation +} OBJECT_INFORMATION_CLASS; + +typedef enum _IO_COMPLETION_INFORMATION_CLASS +{ + IoCompletionBasicInformation +} IO_COMPLETION_INFORMATION_CLASS; + +typedef enum _SECTION_INFORMATION_CLASS +{ + SectionBasicInformation, + SectionImageInformation, +} SECTION_INFORMATION_CLASS; + +typedef enum _SEMAPHORE_INFORMATION_CLASS +{ + SemaphoreBasicInformation +} SEMAPHORE_INFORMATION_CLASS; + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, /* OBSOLETE: USE KUSER_SHARED_DATA */ + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemNextEventIdInformation, + SystemEventIdsInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemPlugPlayBusInformation, + SystemDockInformation, + _SystemPowerInformation, /* FIXME */ + SystemProcessorSpeedInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation, + SystemTimeSlipNotification, + SystemSessionCreate, + SystemSessionDetach, + SystemSessionInformation, + SystemRangeStartInformation, + SystemVerifierInformation, + SystemAddVerifier, + SystemSessionProcessesInformation, + SystemInformationClassMax +} SYSTEM_INFORMATION_CLASS; + +typedef enum _TIMER_INFORMATION_CLASS +{ + TimerBasicInformation +} TIMER_INFORMATION_CLASS; + +typedef enum _MEMORY_INFORMATION_CLASS +{ + MemoryBasicInformation, + MemoryWorkingSetList, + MemorySectionName, + MemoryBasicVlmInformation +} MEMORY_INFORMATION_CLASS; + +typedef enum _FSINFOCLASS +{ + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsFullSizeInformation, + FileFsObjectIdInformation, + FileFsDriverPathInformation, + FileFsMaximumInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +typedef enum _KEY_SET_INFORMATION_CLASS +{ + KeyWriteTimeInformation, + KeyUserFlagsInformation, + MaxKeySetInfoClass +} KEY_SET_INFORMATION_CLASS; + +typedef enum _SHUTDOWN_ACTION +{ + ShutdownNoReboot, + ShutdownReboot, + ShutdownPowerOff +} SHUTDOWN_ACTION; + +typedef enum _DEBUG_CONTROL_CODE +{ + DebugGetTraceInformation = 1, + DebugSetInternalBreakpoint, + DebugSetSpecialCall, + DebugClearSpecialCalls, + DebugQuerySpecialCalls, + DebugDbgBreakPoint, + DebugDbgLoadSymbols +} DEBUG_CONTROL_CODE; + +typedef enum _WAIT_TYPE +{ + WaitAny, + WaitAll +} WAIT_TYPE; + +typedef enum _KWAIT_REASON +{ + Executive, + FreePage, + PageIn, + PoolAllocation, + DelayExecution, + Suspended, + UserRequest, + WrExecutive, + WrFreePage, + WrPageIn, + WrPoolAllocation, + WrDelayExecution, + WrSuspended, + WrUserRequest, + WrEventPair, + WrQueue, + WrLpcReceive, + WrLpcReply, + WrVirtualMemory, + WrPageOut, + WrRendezvous, + Spare2, + WrGuardedMutex, + Spare4, + Spare5, + Spare6, + WrKernel, + WrResource, + WrPushLock, + WrMutex, + WrQuantumEnd, + WrDispatchInt, + WrPreempted, + WrYieldExecution, + MaximumWaitReason +} KWAIT_REASON; + +typedef struct _LUID { + DWORD LowPart; + LONG HighPart; +} LUID, *PLUID; + +typedef struct _EXCEPTION_RECORD { + DWORD ExceptionCode; + DWORD ExceptionFlags; + struct _EXCEPTION_RECORD *ExceptionRecord; + PVOID ExceptionAddress; + DWORD NumberParameters; + DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; +} EXCEPTION_RECORD,*PEXCEPTION_RECORD,*LPEXCEPTION_RECORD; + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + + + +typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + } u; +#if ! defined(NONAMELESSUNION) || defined(__cplusplus) + _ANONYMOUS_STRUCT struct { + DWORD LowPart; + LONG HighPart; + }; +#endif /* NONAMELESSUNION */ + LONGLONG QuadPart; +} LARGE_INTEGER, *PLARGE_INTEGER; + +typedef struct { + unsigned int data1; /* The first eight hexadecimal digits of the GUID. */ + unsigned short data2; /* The first group of four hexadecimal digits. */ + unsigned short data3; /* The second group of four hexadecimal digits. */ + unsigned char data4[8];/* The first two bytes are the third group of four + hexadecimal digits. The remaining six bytes are the + final 12 hexadecimal digits. */ +} __attribute__ ((__packed__)) GUID; + +#define MAXIMUM_SUPPORTED_EXTENSION 512 +typedef struct _FLOATING_SAVE_AREA { + DWORD ControlWord; + DWORD StatusWord; + DWORD TagWord; + DWORD ErrorOffset; + DWORD ErrorSelector; + DWORD DataOffset; + DWORD DataSelector; + BYTE RegisterArea[80]; + DWORD Cr0NpxState; +} FLOATING_SAVE_AREA; +typedef struct _CONTEXT { + DWORD ContextFlags; + DWORD Dr0; + DWORD Dr1; + DWORD Dr2; + DWORD Dr3; + DWORD Dr6; + DWORD Dr7; + FLOATING_SAVE_AREA FloatSave; + DWORD SegGs; + DWORD SegFs; + DWORD SegEs; + DWORD SegDs; + DWORD Edi; + DWORD Esi; + DWORD Ebx; + DWORD Edx; + DWORD Ecx; + DWORD Eax; + DWORD Ebp; + DWORD Eip; + DWORD SegCs; + DWORD EFlags; + DWORD Esp; + DWORD SegSs; + BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; +} CONTEXT; + +typedef struct _GET_SET_CTX_CONTEXT { + struct kapc apc; + struct kevent event; + CONTEXT context; +} GET_SET_CTX_CONTEXT, *PGET_SET_CTX_CONTEXT; + +typedef struct pt_regs Context; +typedef Context *PContext,*LPContext; +typedef CONTEXT *PCONTEXT,*LPCONTEXT; + +typedef struct _LUID_AND_ATTRIBUTES { + LUID Luid; + DWORD Attributes; +} LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES; + +typedef struct _ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; +} ACL,*PACL; +typedef struct _SID_AND_ATTRIBUTES { + PSID Sid; + DWORD Attributes; +} SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES; + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _SECURITY_DESCRIPTOR { + BYTE Revision; + BYTE Sbz1; + SECURITY_DESCRIPTOR_CONTROL Control; + PSID Owner; + PSID Group; + PACL Sacl; + PACL Dacl; +} SECURITY_DESCRIPTOR, *PSECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR; + + +typedef struct _GENERIC_MAPPING { + ACCESS_MASK GenericRead; + ACCESS_MASK GenericWrite; + ACCESS_MASK GenericExecute; + ACCESS_MASK GenericAll; +} GENERIC_MAPPING, *PGENERIC_MAPPING; + + +typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + DWORD HighPart; + } u; +#if ! defined(NONAMELESSUNION) || defined(__cplusplus) + _ANONYMOUS_STRUCT struct { + DWORD LowPart; + DWORD HighPart; + }; +#endif /* NONAMELESSUNION */ + ULONGLONG QuadPart; +} ULARGE_INTEGER, *PULARGE_INTEGER; + + +typedef struct _SECURITY_QUALITY_OF_SERVICE { + DWORD Length; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode; + BOOLEAN EffectiveOnly; +} SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE; + +typedef struct _PORT_VIEW +{ + ULONG Length; + LPC_HANDLE SectionHandle; + ULONG SectionOffset; + LPC_SIZE_T ViewSize; + LPC_PVOID ViewBase; + LPC_PVOID ViewRemoteBase; +} PORT_VIEW, *PPORT_VIEW; + +typedef struct _REMOTE_PORT_VIEW +{ + ULONG Length; + LPC_SIZE_T ViewSize; + LPC_PVOID ViewBase; +} REMOTE_PORT_VIEW, *PREMOTE_PORT_VIEW; + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + + +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +typedef struct _INITIAL_TEB +{ + PVOID StackBase; + PVOID StackLimit; + PVOID StackCommit; + PVOID StackCommitMax; + PVOID StackReserved; +} INITIAL_TEB, *PINITIAL_TEB; + +typedef struct _TOKEN_USER { + SID_AND_ATTRIBUTES User; +} TOKEN_USER, *PTOKEN_USER; + +typedef struct _TOKEN_GROUPS { + DWORD GroupCount; + SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; +} TOKEN_GROUPS,*PTOKEN_GROUPS,*LPTOKEN_GROUPS; + +typedef struct _TOKEN_PRIVILEGES { + DWORD PrivilegeCount; + LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]; +} TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES,*LPTOKEN_PRIVILEGES; + +typedef struct _TOKEN_OWNER { + PSID Owner; +} TOKEN_OWNER,*PTOKEN_OWNER; + +typedef struct _TOKEN_PRIMARY_GROUP { + PSID PrimaryGroup; +} TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP; + + +typedef struct _TOKEN_DEFAULT_DACL { + PACL DefaultDacl; +} TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL; +#define TOKEN_SOURCE_LENGTH 8 +typedef struct _TOKEN_SOURCE { + CHAR SourceName[TOKEN_SOURCE_LENGTH]; + LUID SourceIdentifier; +} TOKEN_SOURCE,*PTOKEN_SOURCE; + +typedef struct _PLUGPLAY_EVENT_BLOCK +{ + GUID EventGuid; + PLUGPLAY_EVENT_CATEGORY EventCategory; + PULONG Result; + ULONG Flags; + ULONG TotalSize; + PVOID DeviceObject; + union + { + struct + { + GUID ClassGuid; + WCHAR SymbolicLinkName[ANYSIZE_ARRAY]; + } DeviceClass; + struct + { + WCHAR DeviceIds[ANYSIZE_ARRAY]; + } TargetDevice; + struct + { + WCHAR DeviceId[ANYSIZE_ARRAY]; + } InstallDevice; + struct + { + PVOID NotificationStructure; + WCHAR DeviceIds[ANYSIZE_ARRAY]; + } CustomNotification; + struct + { + PVOID Notification; + } ProfileNotification; + struct + { + ULONG NotificationCode; + ULONG NotificationData; + } PowerNotification; + struct + { + PNP_VETO_TYPE VetoType; + WCHAR DeviceIdVetoNameBuffer[ANYSIZE_ARRAY]; + } VetoNotification; + struct + { + GUID BlockedDriverGuid; + } BlockedDriverNotification; + }; +} PLUGPLAY_EVENT_BLOCK, *PPLUGPLAY_EVENT_BLOCK; + +typedef struct _PORT_MESSAGE +{ + union + { + struct + { + CSHORT DataLength; + CSHORT TotalLength; + } s1; + ULONG Length; + } u1; + union + { + struct + { + CSHORT Type; + CSHORT DataInfoOffset; + } s2; + ULONG ZeroInit; + } u2; + union + { + LPC_CLIENT_ID ClientId; + double DoNotUseThisField; + }; + ULONG MessageId; + union + { + LPC_SIZE_T ClientViewSize; + ULONG CallbackId; + }; +} PORT_MESSAGE, *PPORT_MESSAGE; + +typedef struct _PRIVILEGE_SET { + DWORD PrivilegeCount; + DWORD Control; + LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]; +} PRIVILEGE_SET,*PPRIVILEGE_SET; + +typedef struct _FILE_BASIC_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + + +typedef struct _FILE_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + +typedef struct _FILE_FULL_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[0]; +} FILE_FULL_DIRECTORY_INFORMATION, *PFILE_FULL_DIRECTORY_INFORMATION; + +typedef struct _FILE_BOTH_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[0]; +} FILE_BOTH_DIRECTORY_INFORMATION, *PFILE_BOTH_DIRECTORY_INFORMATION; + + +typedef struct _FILE_INTERNAL_INFORMATION { + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_EA_INFORMATION { + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_ACCESS_INFORMATION { + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION { + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + + +typedef struct _FILE_RENAME_INFORMATION { + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; + +typedef struct _FILE_NAMES_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; + + +typedef struct _FILE_DISPOSITION_INFORMATION { + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +typedef struct _FILE_FULL_EA_INFORMATION { + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; + + +typedef struct _FILE_MODE_INFORMATION { + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION { + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + + +typedef struct _FILE_ALLOCATION_INFORMATION { + LARGE_INTEGER AllocationSize; +} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION; + + +typedef struct _FILE_ALIGNMENT_INFORMATION { + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + + +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_STREAM_INFORMATION +{ + ULONG NextEntryOffset; + ULONG StreamNameLength; + LARGE_INTEGER StreamSize; + LARGE_INTEGER StreamAllocationSize; + WCHAR StreamName[1]; +} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION; + +typedef struct _FILE_MAILSLOT_QUERY_INFORMATION { + ULONG MaximumMessageSize; + ULONG MailslotQuota; + ULONG NextMessageSize; + ULONG MessagesAvailable; + LARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_QUERY_INFORMATION, *PFILE_MAILSLOT_QUERY_INFORMATION; + +typedef struct _FILE_ALL_INFORMATION { + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + + +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + +typedef struct _KEY_VALUE_ENTRY +{ + PUNICODE_STRING ValueName; + ULONG DataLength; + ULONG DataOffset; + ULONG Type; +} KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY; + +typedef union _FILE_SEGMENT_ELEMENT { + PVOID64 Buffer; + ULONGLONG Alignment; +}FILE_SEGMENT_ELEMENT, *PFILE_SEGMENT_ELEMENT; + +typedef struct _LDT_ENTRY +{ + USHORT LimitLow; + USHORT BaseLow; + union + { + struct + { + UCHAR BaseMid; + UCHAR Flags1; + UCHAR Flags2; + UCHAR BaseHi; + } Bytes; + struct + { + ULONG BaseMid : 8; + ULONG Type : 5; + ULONG Dpl : 2; + ULONG Pres : 1; + ULONG LimitHi : 4; + ULONG Sys : 1; + ULONG Reserved_0 : 1; + ULONG Default_Big : 1; + ULONG Granularity : 1; + ULONG BaseHi : 8; + } Bits; + } HighWord; +} LDT_ENTRY, *PLDT_ENTRY; + + + + +typedef struct _EVENT_TRACE_HEADER +{ + USHORT Size; + union { + USHORT FieldTypeFlags; + struct { + UCHAR HeaderType; + UCHAR MarkerFlags; + }; + }; + union { + ULONG Version; + struct { + UCHAR Type; + UCHAR Level; + USHORT Version; + } Class; + }; + ULONG ThreadId; + ULONG ProcessId; + LARGE_INTEGER TimeStamp; + union { + GUID Guid; + ULONGLONG GuidPtr; + }; + union { + struct { + ULONG ClientContext; + ULONG Flags; + }; + struct { + ULONG KernelTime; + ULONG UserTime; + }; + ULONG64 ProcessorTime; + }; +} EVENT_TRACE_HEADER, *PEVENT_TRACE_HEADER; + +typedef VOID +(NTAPI *PIO_APC_ROUTINE)( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved); + +typedef VOID +(NTAPI *PKNORMAL_ROUTINE)( + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +typedef VOID +(NTAPI *PTIMER_APC_ROUTINE)( + IN PVOID TimerContext, + IN ULONG TimerLowValue, + IN LONG TimerHighValue); + + +typedef struct _LPC_MESSAGE +{ + USHORT DataSize; + USHORT MessageSize; + USHORT MessageType; + USHORT VirtualRangesOffset; + CLIENT_ID ClientId; + ULONG MessageId; + ULONG SectionSize; +} LPC_MESSAGE, *PLPC_MESSAGE; + +typedef struct _LPC_SECTION_WRITE +{ + ULONG Length; + HANDLE SectionHandle; + ULONG SectionOffset; + ULONG ViewSize; + PVOID ViewBase; + PVOID TargetViewBase; +} LPC_SECTION_WRITE, *PLPC_SECTION_WRITE; + +typedef struct _LPC_SECTION_READ +{ + ULONG Length; + ULONG ViewSize; + PVOID ViewBase; +} LPC_SECTION_READ, *PLPC_SECTION_READ; + +typedef struct OVERLAPPED{ + DWORD Internal; + DWORD InternalHigh; + DWORD Offset; + DWORD OffsetHigh; + HANDLE hEvent; +}OVERLAPPED,*LPOVERLAPPED; + +/* From ReactOS, don't touch. */ + +typedef struct _SSDT_ENTRY { + PSSDT SSDT; + PULONG ServiceCounterTable; + ULONG NumberOfServices; + PSSPT SSPT; +} SSDT_ENTRY; + +extern HANDLE hBaseDir; + +/* for kernel */ +/* These are not exposed to drivers normally */ +#ifndef _NTOS_MODE_USER + #define JOB_OBJECT_ASSIGN_PROCESS (1) + #define JOB_OBJECT_SET_ATTRIBUTES (2) + #define JOB_OBJECT_QUERY (4) + #define JOB_OBJECT_TERMINATE (8) + #define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (16) + #define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|31) +#endif + +struct ps_impersonation_information +{ + void* token; + unsigned char copy_on_open; + unsigned char effective_only; + enum security_impersonation_level impersonation_level; +}; + + +struct termination_port { + struct termination_port* next; + void* port; +}; + +struct sid_and_attributes { + void* sid; + unsigned long attributes; +}; + +struct ps_job_token_filter +{ + unsigned int captured_sid_count; + struct sid_and_attributes captured_sids; + unsigned int captured_sids_length; + unsigned int captured_group_count; + struct sid_and_attributes captured_groups; + unsigned int captured_groups_length; + unsigned int captured_privilege_count; + struct sid_and_attributes captured_privileges; + unsigned int captured_privileges_length; +}; + +struct io_counters { + unsigned long long read_op_count; + unsigned long long write_opcount; + unsigned long long other_op_count; + unsigned long long read_transfer_count; + unsigned long long write_transfer_count; + unsigned long long other_transfer_count; +}; + +struct ejob +{ + struct kevent event; + struct list_head job_links; + struct list_head process_list_head; + struct eresource job_lock; + large_integer_t total_utime; + large_integer_t total_ktime; + large_integer_t this_period_total_utime; + large_integer_t this_period_total_ktime; + unsigned int total_page_fault_count; + unsigned int total_processes; + unsigned int active_processes; + unsigned int total_terminated_processes; + large_integer_t per_process_utime_limit; + large_integer_t per_job_utime_limit; + unsigned int limit_flags; + unsigned int min_workingset_size; + unsigned int max_workingset_size; + unsigned int active_process_limit; + unsigned int affinity; + unsigned char priority_class; + unsigned int ui_restrictions_class; + unsigned int security_limit_flags; + void* token; + struct ps_job_token_filter* filter; + unsigned int end_of_job_time_action; + void* completion_port; + void* completion_key; + unsigned int session_id; + unsigned int scheduling_class; + unsigned long long read_op_count; + unsigned long long write_op_count; + unsigned long long other_op_count; + unsigned long long read_transfer_count; + unsigned long long write_transfer_count; + unsigned long long other_transfer_count; + struct io_counters io_info; + unsigned int process_memory_limit; + unsigned int job_memory_limit; + unsigned int peak_proc_mem_used; + unsigned int peak_job_memused; + unsigned int current_job_mem_used; + struct kguarded_mutex memory_limits_lock; + unsigned long member_level; + unsigned long job_flags; +}; + +typedef struct _PROCESS_BASIC_INFORMATION { + DWORD ExitStatus; + DWORD PebBaseAddress; + DWORD AffinityMask; + DWORD BasePriority; + ULONG UniqueProcessId; + ULONG InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; + +typedef struct _KERNEL_USER_TIMES +{ + large_integer_t CreateTime; + large_integer_t ExitTime; + large_integer_t KernelTime; + large_integer_t UserTime; +} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES; + +typedef struct _PROCESS_SESSION_INFORMATION +{ + ULONG SessionId; +} PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION; + +typedef struct _VM_COUNTERS +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} VM_COUNTERS, *PVM_COUNTERS; + +typedef struct _PROCESS_PRIORITY_CLASS { + BOOLEAN Foreground; + UCHAR PriorityClass; +} PROCESS_PRIORITY_CLASS, *PPROCESS_PRIORITY_CLASS; + +typedef kprocessor_mode_t KPROCESSOR_MODE; + +typedef enum _SECURITY_OPERATION_CODE +{ + SetSecurityDescriptor, + QuerySecurityDescriptor, + DeleteSecurityDescriptor, + AssignSecurityDescriptor +} SECURITY_OPERATION_CODE; + +typedef enum _POOL_TYPE +{ + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS, + MaxPoolType, + NonPagedPoolSession = 32, + PagedPoolSession, + NonPagedPoolMustSucceedSession, + DontUseThisTypeSession, + NonPagedPoolCacheAlignedSession, + PagedPoolCacheAlignedSession, + NonPagedPoolCacheAlignedMustSSession +} POOL_TYPE; + +typedef struct _OBJECT_NAME_INFORMATION +{ + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +typedef struct _SINGLE_LIST_ENTRY +{ + struct _SINGLE_LIST_ENTRY *Next; +} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; + +typedef long long QUAD; + +typedef struct eresource ERESOURCE, *PERESOURCE; + +#define INIT_OBJECT_ATTR(p,n,a,r,s) { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = (r); \ + (p)->Attributes = (a); \ + (p)->ObjectName = (n); \ + (p)->SecurityDescriptor = (s); \ + (p)->SecurityQualityOfService = NULL; \ +} + +typedef struct _SEP_AUDIT_POLICY_CATEGORIES +{ + UCHAR System:4; + UCHAR Logon:4; + UCHAR ObjectAccess:4; + UCHAR PrivilegeUse:4; + UCHAR DetailedTracking:4; + UCHAR PolicyChange:4; + UCHAR AccountManagement:4; + UCHAR DirectoryServiceAccess:4; + UCHAR AccountLogon:4; +} SEP_AUDIT_POLICY_CATEGORIES, *PSEP_AUDIT_POLICY_CATEGORIES; + +typedef struct _SEP_AUDIT_POLICY_OVERLAY +{ + ULONGLONG PolicyBits:36; + UCHAR SetBit:1; +} SEP_AUDIT_POLICY_OVERLAY, *PSEP_AUDIT_POLICY_OVERLAY; + +typedef struct _SEP_AUDIT_POLICY +{ + union + { + SEP_AUDIT_POLICY_CATEGORIES PolicyElements; + SEP_AUDIT_POLICY_OVERLAY PolicyOverlay; + ULONGLONG Overlay; + }; +} SEP_AUDIT_POLICY, *PSEP_AUDIT_POLICY; + +typedef struct _TOKEN +{ + TOKEN_SOURCE TokenSource; /* 0x00 */ + LUID TokenId; /* 0x10 */ + LUID AuthenticationId; /* 0x18 */ + LUID ParentTokenId; /* 0x20 */ + LARGE_INTEGER ExpirationTime; /* 0x28 */ + ERESOURCE *TokenLock; /* 0x30 */ + SEP_AUDIT_POLICY AuditPolicy; /* 0x38 */ + LUID ModifiedId; /* 0x40 */ + ULONG SessionId; /* 0x48 */ + ULONG UserAndGroupCount; /* 0x4C */ + ULONG RestrictedSidCount; /* 0x50 */ + ULONG PrivilegeCount; /* 0x54 */ + ULONG VariableLength; /* 0x58 */ + ULONG DynamicCharged; /* 0x5C */ + ULONG DynamicAvailable; /* 0x60 */ + ULONG DefaultOwnerIndex; /* 0x64 */ + PSID_AND_ATTRIBUTES UserAndGroups; /* 0x68 */ + PSID_AND_ATTRIBUTES RestrictedSids; /* 0x6C */ + PSID PrimaryGroup; /* 0x70 */ + PLUID_AND_ATTRIBUTES Privileges; /* 0x74 */ + PULONG DynamicPart; /* 0x78 */ + PACL DefaultDacl; /* 0x7C */ + TOKEN_TYPE TokenType; /* 0x80 */ + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; /* 0x84 */ + ULONG TokenFlags; /* 0x88 */ + BOOLEAN TokenInUse; /* 0x8C */ + PVOID ProxyData; /* 0x90 */ + PVOID AuditData; /* 0x94 */ + LUID OriginatingLogonSession; /* 0x98 */ + ULONG VariablePart; /* 0xA0 */ +} TOKEN, *PTOKEN; + +typedef struct _FAST_MUTEX { + LONG Count; + struct kthread *Owner; + atomic_t Contention; + struct kevent Event; + ULONG OldIrql; +} FAST_MUTEX, *PFAST_MUTEX; + +typedef struct kthread *PKTHREAD; + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WIN32_H */ diff --git a/unifiedkernel/include/win32_process.h b/unifiedkernel/include/win32_process.h new file mode 100644 index 0000000..f673039 --- /dev/null +++ b/unifiedkernel/include/win32_process.h @@ -0,0 +1,272 @@ +/* + * win32_process.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +#ifndef _WIN32_PROCESS_H +#define _WIN32_PROCESS_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL +unsigned int get_current_time(void); +#define current_time get_current_time() + +/* Process state */ +#define PROCESS_STATE_TERMINATED 1 +#define PROCESS_STATE_ACTIVE 2 + +/* Process priority classes */ +#define PROCESS_PRIORITY_CLASS_HIGH (4) /* FIXME */ +#define PROCESS_PRIORITY_CLASS_IDLE (0) /* FIXME */ +#define PROCESS_PRIORITY_CLASS_NORMAL (2) /* FIXME */ +#define PROCESS_PRIORITY_CLASS_REALTIME (5) /* FIXME */ +#define PROCESS_PRIORITY_CLASS_BELOW_NORMAL (1) /* FIXME */ +#define PROCESS_PRIORITY_CLASS_ABOVE_NORMAL (3) /* FIXME */ + +static __inline__ struct eprocess *get_eprocess(struct ethread *thread) +{ + struct eprocess *ep = thread->threads_process; + + return ep; +} /* end get_eprocess() */ + +/* + * kprocess + */ +struct kprocess +{ + struct dispatcher_header header; /* 000 */ + struct list_head profile_list_head; /* 010 */ + physical_address_t directory_table_base; /* 018 */ +#if defined(_M_IX86) + struct kgd_entry ldt_descriptor; /* 020 */ + struct kidt_entry Int21_descriptor; /* 028 */ + unsigned short iopm_offset; /* 030 */ + unsigned char iopl; /* 032 */ + unsigned char unused; /* 033 */ +#endif + unsigned long active_processors; /* 034 */ + unsigned long kernel_time; /* 038 */ + unsigned long user_time; /* 03C */ + struct list_head ready_list_head; /* 040 */ + struct list_head swap_list_entry; /* 048 */ + void* vdm_trapc_handler; /* 04C */ + struct list_head thread_list_head; /* 050 */ + spinlock_t process_lock; /* 068 */ + unsigned long affinity; /* 06C */ + union + { + struct + { + unsigned long auto_alignment:1; /* 070.0 */ + unsigned long disable_boost:1; /* 070.1 */ + unsigned long disable_quantum:1; /* 070.2 */ + unsigned long reserved_flags:29; /* 070.3 */ + }; + unsigned long process_flags; /* 070 */ + }; + char base_priority; /* 074 */ + char quantum_reset; /* 075 */ + unsigned char state; /* 076 */ + unsigned char thread_seed; /* 077 */ + unsigned char power_state; /* 078 */ + unsigned char ideal_node; /* 079 */ + unsigned char visited; /* 07A */ + struct kexecute_options flags; /* 07B */ + unsigned long stack_count; /* 07C */ + struct list_head process_list_entry; /* 080 */ +}; + +struct eprocess +{ + struct kprocess pcb; /* 000 */ + unsigned long exit_status; /* 088 */ + spinlock_t process_lock; /* 08C */ + struct kevent lock_event; /* 0A4 */ + unsigned long lock_count; /* */ + struct kthread *lock_owner; /* */ + large_integer_t create_time; /* */ + large_integer_t exit_time; /* */ + void *rundown_protect; /* */ + void* unique_processid; /* */ + struct list_head active_process_links; /* */ + + /* quota fields */ + unsigned long quota_usage[3]; /* */ + unsigned long quota_peak[3]; /* */ + unsigned long commit_charge; /* */ + + /* vm */ + unsigned long peak_virtual_size; /* */ + unsigned long virtual_size; /* */ + + struct mmsupport vm; /* */ + struct list_head session_process_links; /* */ + + void* debug_port; /* */ + void* exception_port; /* */ + struct handle_table* object_table; /* */ + + /* security */ + struct ex_fast_ref token; /* */ + + unsigned long working_set_page; /* */ + struct kguarded_mutex address_creation_lock; /* */ + spinlock_t hyper_spacelock; /* */ + struct ethread* fork_in_progress; /* */ + unsigned long hardware_trigger; /* */ + void* pae_top; /* */ + unsigned long modified_page_count; /* */ + struct mm_avl_table vad_root; /* */ + void* vad_free_hint; /* */ + void* clone_root; /* */ + + struct mm_avl_table physical_vadroot; /* */ + + unsigned long number_of_private_pages; /* */ + unsigned long number_of_locked_pages; /* */ + unsigned short next_page_color; /* */ + + /* used by debug subsystem */ + void* section_object; /* */ + + /* peb */ + void* peb; /* */ + void* section_base_address; /* */ + + struct eprocess_quota_block* quota_block; /* */ + unsigned long last_thread_exit_status; /* */ + + struct pagefault_history* working_set_watch; /* */ + void* win32_window_station; /* */ + void * inherited_from_unique_pid; /* */ + access_mask_t granted_access; /* */ + unsigned long def_hard_error_processing; /* */ + void* ldt_information; /* */ + void* vdm_objects; /* */ + void* device_map; /* */ + + void* spare0[3]; /* */ + + union + { + struct hardware_pte_x86 pagedirectory_pte; /* */ + unsigned long long filler; /* */ + }; + char image_file_name[16]; /* */ + unsigned char priority_class; /* */ + union + { + struct + { + unsigned char subsystem_minor_version; /* */ + unsigned char subsystem_major_version; /* */ + }; + unsigned short subsystem_version; /* */ + }; + struct w32process* win32process; + struct ejob* job; /* */ + unsigned long job_status; /* */ + struct list_head job_links; /* */ + void* locked_pages_list; /* */ + + /* used by rdr/security for authentication */ + void* security_port; /* */ + + large_integer_t read_operation_count; /* */ + large_integer_t write_operation_count; /* */ + large_integer_t other_operation_count; /* */ + large_integer_t read_transfer_count; /* */ + large_integer_t write_transfer_count; /* */ + large_integer_t other_transfer_count; /* */ + + unsigned long commit_charge_limit; /* */ + unsigned long commit_charge_peak; /* */ + + struct list_head thread_list_head; /* */ + + union + { + struct + { + unsigned long create_reported:1; + unsigned long no_debug_inherit:1; + unsigned long process_exiting:1; + unsigned long process_delete:1; + unsigned long wow64_split_pages:1; + unsigned long vm_deleted:1; + unsigned long outswap_enabled:1; + unsigned long outswapped:1; + unsigned long fork_failed:1; + unsigned long wow64_va_space4Gb:1; + unsigned long address_space_initialized:2; + unsigned long set_timer_resolution:1; + unsigned long break_on_termination:1; + unsigned long session_creation_underway:1; + unsigned long write_watch:1; + unsigned long process_in_session:1; + unsigned long override_address_space:1; + unsigned long has_address_space:1; + unsigned long launch_prefetched:1; + unsigned long inject_inpage_errors:1; + unsigned long vm_top_down:1; + unsigned long image_notify_done:1; + unsigned long pde_update_needed:1; + unsigned long vdm_allowed:1; + unsigned long smap_allowed:1; + unsigned long create_failed:1; + unsigned long default_io_priority:3; + unsigned long spare1:1; + unsigned long spare2:1; + }; + unsigned long flags; /* */ + }; + + unsigned long cookie; /* */ + unsigned long session; /* */ + unsigned long active_threads; /* */ + struct ex_fast_ref prefetch_trace; /* */ + void* awe_info; /* */ + struct se_audit_proc_creation_info se_audit_proc_creation_info; /* */ + struct list_head mm_process_links; /* */ + + struct nls_table* ep_nls; /* unicode-ascii translation */ + rwlock_t ep_lock; + struct list_head ep_reserved_head; + struct list_head ep_mapped_head; + void *ep_handle_info_table; + + /*for NtNotifyDirectoryChange */ + spinlock_t watch_lock; + long watch_fd; + pid_t watch_thread; +}; /* struc eprocess */ + +typedef struct eprocess EPROCESS, *PEPROCESS; + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WIN32_PROCESS_H */ diff --git a/unifiedkernel/include/wineserver/file.h b/unifiedkernel/include/wineserver/file.h new file mode 100644 index 0000000..09778f3 --- /dev/null +++ b/unifiedkernel/include/wineserver/file.h @@ -0,0 +1,191 @@ +/* + * file.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * file.h: + * Refered to Wine code + */ + +#ifndef _WINESERVER_FILE_H +#define _WINESERVER_FILE_H + +#include "object.h" +#include "uk_protocol.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct fd; +struct async_queue; + +/* operations valid on file descriptor objects */ +struct fd_ops +{ + /* get the events we want to poll() for on this object */ + int (*get_poll_events)(struct fd *); + /* a poll() event occurred */ + void (*poll_event)(struct fd *,int event); + /* flush the object buffers */ + void (*flush)(struct fd *, struct kevent **); + /* get file information */ + enum server_fd_type (*get_fd_type)(struct fd *fd); + /* perform an ioctl on the file */ + obj_handle_t (*ioctl)(struct fd *fd, ioctl_code_t code, const async_data_t *async, + const void *data, data_size_t size); + /* queue an async operation */ + void (*queue_async)(struct fd *, const async_data_t *data, int type, int count); + /* selected events for async i/o need an update */ + void (*reselect_async)( struct fd *, struct async_queue *queue ); + /* cancel an async operation */ + void (*cancel_async)(struct fd *); +}; + +/* file descriptor functions */ + +extern struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *user, + unsigned int options ); +extern void set_no_fd_status( struct fd *fd, unsigned int status ); +extern struct fd *open_fd( const char *name, int flags, mode_t *mode, unsigned int access, + unsigned int sharing, unsigned int options ); +#if 0 +extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, + int unix_fd, struct object *user, unsigned int options ); +#endif +extern void *get_fd_user( struct fd *fd ); +extern void set_fd_user( struct fd *fd, const struct fd_ops *ops, struct object *user ); +extern unsigned int get_fd_options( struct fd *fd ); +extern int get_unix_fd(obj_handle_t handle); +#if 0 +extern int get_unix_fd( struct fd *fd ); +#endif +extern int is_same_file_fd( struct fd *fd1, struct fd *fd2 ); +extern int is_fd_removable( struct fd *fd ); +extern int fd_close_handle( struct object *obj, struct w32process *process, obj_handle_t handle ); +extern void fd_poll_event( struct fd *fd, int event ); +extern int check_fd_events( struct fd *fd, int events ); +extern void set_fd_events( struct fd *fd, int events ); +extern obj_handle_t lock_fd( struct fd *fd, file_pos_t offset, file_pos_t count, int shared, int wait ); +extern void unlock_fd( struct fd *fd, file_pos_t offset, file_pos_t count ); +extern void set_fd_signaled( struct fd *fd, int signaled ); + +extern int default_fd_signaled( struct object *obj, struct w32thread *thread ); +extern int default_fd_get_poll_events( struct fd *fd ); +extern void default_poll_event( struct fd *fd, int event ); +extern struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); +extern void fd_async_wake_up( struct fd *fd, int type, unsigned int status ); +extern void fd_reselect_async( struct fd *fd, struct async_queue *queue ); +extern obj_handle_t default_fd_ioctl( struct fd *fd, ioctl_code_t code, const async_data_t *async, + const void *data, data_size_t size ); +extern void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); +extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ); +extern void default_fd_cancel_async( struct fd *fd ); +extern void no_flush( struct fd *fd, struct kevent **event ); +extern void main_loop(void); +extern void remove_process_locks( struct w32process *process ); + +static inline struct fd *get_obj_fd( struct object *obj ) +{ + return BODY_TO_HEADER(obj)->ops ? BODY_TO_HEADER(obj)->ops->get_fd( obj ) : NULL; +} + +/* timeout functions */ + +struct timeout_user; +unsigned int get_current_time(void); +#define current_time get_current_time() + +#define TICKS_PER_SEC 10000000 +#define TICKS_1601_TO_1970 ((timeout_t)86400 * (369 * 365 + 89) * TICKS_PER_SEC) + +typedef void (*timeout_callback)( void *private ); + +extern struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private ); +extern void remove_timeout_user( struct timeout_user *user ); +extern const char *get_timeout_str( timeout_t timeout ); + +/* file functions */ +struct uk_file; + +extern struct uk_file *get_file_obj( struct w32process *process, obj_handle_t handle, unsigned int access ); +extern int get_file_unix_fd( struct uk_file *file ); +#if 0 +extern int is_same_file( struct uk_file *file1, struct uk_file *file2 ); +extern struct uk_file *grab_file_unless_removable( struct uk_file *file ); +extern struct uk_file *create_temp_file( int access ); +#endif +extern int grow_file( struct uk_file *file, file_pos_t size ); + +/* change notification functions */ + +extern void do_change_notify( int unix_fd ); +extern void sigio_callback(void); +extern struct object *create_dir_obj( struct fd *fd ); + +/* serial port functions */ + +extern int is_serial_fd( struct fd *fd ); +extern struct object *create_serial( struct fd *fd ); + +/* async I/O functions */ +extern struct async_queue *create_async_queue( struct fd *fd ); +extern void free_async_queue( struct async_queue *queue ); +extern struct async *create_async( struct w32thread *thread, struct async_queue *queue, + const async_data_t *data ); +extern void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ); +extern int async_waiting( struct async_queue *queue ); +extern void async_terminate( struct async *async, unsigned int status ); +extern void async_wake_up( struct async_queue *queue, unsigned int status ); +extern void *get_handle_obj_1(struct w32process *proc, HANDLE handle, unsigned int access, const struct object_ops* ops); +/* access rights that require Unix read permission */ +#define FILE_UNIX_READ_ACCESS (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA) + +/* access rights that require Unix write permission */ +#define FILE_UNIX_WRITE_ACCESS (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA) + + +#define FILE_READ_DATA 0x0001 /* file & pipe */ +#define FILE_LIST_DIRECTORY 0x0001 /* directory */ +#define FILE_WRITE_DATA 0x0002 /* file & pipe */ +#define FILE_ADD_FILE 0x0002 /* directory */ +#define FILE_APPEND_DATA 0x0004 /* file */ +#define FILE_ADD_SUBDIRECTORY 0x0004 /* directory */ +#define FILE_CREATE_PIPE_INSTANCE 0x0004 /* named pipe */ +#define FILE_READ_EA 0x0008 /* file & directory */ +#define FILE_READ_PROPERTIES FILE_READ_EA +#define FILE_WRITE_EA 0x0010 /* file & directory */ +#define FILE_WRITE_PROPERTIES FILE_WRITE_EA +#define FILE_EXECUTE 0x0020 /* file */ +#define FILE_TRAVERSE 0x0020 /* directory */ +#define FILE_DELETE_CHILD 0x0040 /* directory */ +#define FILE_READ_ATTRIBUTES 0x0080 /* all */ +#define FILE_WRITE_ATTRIBUTES 0x0100 /* all */ +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ | FILE_READ_DATA | \ + FILE_READ_ATTRIBUTES | FILE_READ_EA | \ + SYNCHRONIZE) +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | \ + FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | \ + FILE_APPEND_DATA | SYNCHRONIZE) +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE | FILE_EXECUTE | \ + FILE_READ_ATTRIBUTES | SYNCHRONIZE) + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WINESERVER_FILE_H */ diff --git a/unifiedkernel/include/wineserver/info.h b/unifiedkernel/include/wineserver/info.h new file mode 100644 index 0000000..ca9caa1 --- /dev/null +++ b/unifiedkernel/include/wineserver/info.h @@ -0,0 +1,57 @@ +/* + * info.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * info.h: + * Refered to Wine code + */ +#ifndef _WINESERVER_INFO_H +#define _WINESERVER_INFO_H + +#include "object.h" +#include "process.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL +struct handle_info +{ + void *obj; + int unix_fd; +}; + +int set_handle_info(struct eprocess *process, obj_handle_t handle, void *obj); +struct handle_info *get_handle_info(struct eprocess *process, obj_handle_t handle); +int get_handle_fd(struct eprocess *process, obj_handle_t handle); +void clear_handle_info(struct eprocess *process, obj_handle_t handle); +struct handle_info_table *alloc_handle_info_table(void); +void free_handle_info_table(struct handle_info_table *table); + +struct handle_info_table +{ + unsigned long used; /* used size */ + int order; /* page orders */ + unsigned long allocated; /* available size */ + struct handle_info *handles; +}; + +#endif +#endif /* _WINESERVER_INFO_H */ diff --git a/unifiedkernel/include/wineserver/list.h b/unifiedkernel/include/wineserver/list.h new file mode 100644 index 0000000..3a6b266 --- /dev/null +++ b/unifiedkernel/include/wineserver/list.h @@ -0,0 +1,184 @@ +/* + * list.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * list.h: + * Refered to Wine code + */ +#ifndef _WINESERVER_LIST_H +#define _WINESERVER_LIST_H + +#include + +#ifdef CONFIG_UNIFIED_KERNEL +/* add an element after the specified one */ +static inline void list_add_after( struct list_head *elem, struct list_head *to_add ) +{ + to_add->next = elem->next; + to_add->prev = elem; + elem->next->prev = to_add; + elem->next = to_add; +} + +/* add an element before the specified one */ +void list_add_before( struct list_head *elem, struct list_head *to_add ); + +/* add element at the head of the list */ +static inline void list_add_head( struct list_head *list, struct list_head *elem ) +{ + list_add_after( list, elem ); +} + +/* add element at the tail of the list */ +void my_list_add_tail( struct list_head *list, struct list_head *elem ); + +/* remove an element from its list */ +void list_remove( struct list_head *elem ); + +/* get the next element */ +static inline struct list_head *list_next( const struct list_head *list, const struct list_head *elem ) +{ + struct list_head *ret = elem->next; + if (elem->next == list) + ret = NULL; + return ret; +} + +/* get the previous element */ +static inline struct list_head *list_prev( const struct list_head *list, const struct list_head *elem ) +{ + struct list_head *ret = elem->prev; + if (elem->prev == list) + ret = NULL; + return ret; +} + +/* get the first element */ +static inline struct list_head *list_head( const struct list_head *list ) +{ + return list_next( list, list ); +} + +/* get the last element */ +struct list_head *list_tail( const struct list_head* ); + +/* check if a list is empty */ +int my_list_empty(const struct list_head*); + +/* initialize a list */ +void my_list_init(struct list_head *); + +#if 0 +/* count the elements of a list */ +static inline unsigned int list_count( const struct list_head *list ) +{ + unsigned count = 0; + const struct list_head *ptr; + for (ptr = list->next; ptr != list; ptr = ptr->next) + count++; + return count; +} + +/* move all elements from src to the tail of dst */ +static inline void list_move_tail( struct list_head *dst, struct list_head *src ) +{ + if (list_empty(src)) + return; + + dst->prev->next = src->next; + src->next->prev = dst->prev; + dst->prev = src->prev; + src->prev->next = dst; + my_list_init(src); +} + +/* move all elements from src to the head of dst */ +static inline void list_move_head( struct list_head *dst, struct list_head *src ) +{ + if (list_empty(src)) + return; + + dst->next->prev = src->prev; + src->prev->next = dst->next; + dst->next = src->next; + src->next->prev = dst; + my_list_init(src); +} +#endif + +/* iterate through the list */ +#define LIST_FOR_EACH(cursor,list) \ + for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next) + +/* iterate through the list, with safety against removal */ +#define LIST_FOR_EACH_SAFE(cursor, cursor2, list) \ + for ((cursor) = (list)->next, (cursor2) = (cursor)->next; \ + (cursor) != (list); \ + (cursor) = (cursor2), (cursor2) = (cursor)->next) + +/* iterate through the list using a list entry */ +#define LIST_FOR_EACH_ENTRY(elem, list, type, field) \ + for ((elem) = LIST_ENTRY((list)->next, type, field); \ + &(elem)->field != (list); \ + (elem) = LIST_ENTRY((elem)->field.next, type, field)) + +/* iterate through the list using a list entry, with safety against removal */ +#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field) \ + for ((cursor) = LIST_ENTRY((list)->next, type, field), \ + (cursor2) = LIST_ENTRY((cursor)->field.next, type, field); \ + &(cursor)->field != (list); \ + (cursor) = (cursor2), \ + (cursor2) = LIST_ENTRY((cursor)->field.next, type, field)) + +/* iterate through the list in reverse order */ +#define LIST_FOR_EACH_REV(cursor,list) \ + for ((cursor) = (list)->prev; (cursor) != (list); (cursor) = (cursor)->prev) + +/* iterate through the list in reverse order, with safety against removal */ +#define LIST_FOR_EACH_SAFE_REV(cursor, cursor2, list) \ + for ((cursor) = (list)->prev, (cursor2) = (cursor)->prev; \ + (cursor) != (list); \ + (cursor) = (cursor2), (cursor2) = (cursor)->prev) + +/* iterate through the list in reverse order using a list entry */ +#define LIST_FOR_EACH_ENTRY_REV(elem, list, type, field) \ + for ((elem) = LIST_ENTRY((list)->prev, type, field); \ + &(elem)->field != (list); \ + (elem) = LIST_ENTRY((elem)->field.prev, type, field)) + +/* iterate through the list in reverse order using a list entry, with safety against removal */ +#define LIST_FOR_EACH_ENTRY_SAFE_REV(cursor, cursor2, list, type, field) \ + for ((cursor) = LIST_ENTRY((list)->prev, type, field), \ + (cursor2) = LIST_ENTRY((cursor)->field.prev, type, field); \ + &(cursor)->field != (list); \ + (cursor) = (cursor2), \ + (cursor2) = LIST_ENTRY((cursor)->field.prev, type, field)) + +/* macros for statically initialized lists */ +#define LIST_INIT(list) { &(list), &(list) } + +/* get pointer to object containing list element */ +#define LIST_ENTRY(elem, type, field) \ + ((type *)((char *)(elem) - (unsigned int)(&((type *)0)->field))) + +#endif +#endif /* _WINESERVER_LIST_H */ diff --git a/unifiedkernel/include/wineserver/reg.h b/unifiedkernel/include/wineserver/reg.h new file mode 100644 index 0000000..bcb5450 --- /dev/null +++ b/unifiedkernel/include/wineserver/reg.h @@ -0,0 +1,233 @@ +/* + * reg.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * reg.h: + * Refered to Wine code + */ +#ifndef _WINESERVER_REG_H +#define _WINESERVER_REG_H + +#ifdef CONFIG_UNIFIED_KERNEL +#define REG_OPTION_RESERVED 0x00000000 +#define REG_OPTION_NON_VOLATILE 0x00000000 +#define REG_OPTION_VOLATILE 0x00000001 +#define REG_OPTION_CREATE_LINK 0x00000002 +#define REG_OPTION_BACKUP_RESTORE 0x00000004 /* FIXME */ +#define REG_OPTION_OPEN_LINK 0x00000008 +#define REG_LEGAL_OPTION (REG_OPTION_RESERVED| \ + REG_OPTION_NON_VOLATILE| \ + REG_OPTION_VOLATILE| \ + REG_OPTION_CREATE_LINK| \ + REG_OPTION_BACKUP_RESTORE| \ + REG_OPTION_OPEN_LINK) + + +#define REG_CREATED_NEW_KEY 0x00000001 +#define REG_OPENED_EXISTING_KEY 0x00000002 + +/* For RegNotifyChangeKeyValue */ +#define REG_NOTIFY_CHANGE_NAME 0x01 +#define REG_NOTIFY_CHANGE_ATTRIBUTES 0x02 +#define REG_NOTIFY_CHANGE_LAST_SET 0x04 +#define REG_NOTIFY_CHANGE_SECURITY 0x08 + +/* for RegKeyRestore flags */ +#define REG_WHOLE_HIVE_VOLATILE 0x00000001 +#define REG_REFRESH_HIVE 0x00000002 +#define REG_NO_LAZY_FLUSH 0x00000004 +#define REG_FORCE_RESTORE 0x00000008 + +/* key flags */ +#define KEY_VOLATILE 0x0001 /* key is volatile (not saved to disk) */ +#define KEY_DELETED 0x0002 /* key has been deleted */ +#define KEY_DIRTY 0x0004 /* key has been modified */ + +#define MIN_SUBKEYS 8 /* min. number of allocated subkeys per key */ +#define MIN_VALUES 8 /* min. number of allocated values per key */ + +#define MAX_NAME_LEN MAX_PATH /* max. length of a key name */ +#define MAX_VALUE_LEN MAX_PATH /* max. length of a value name */ + +#define REG_NONE 0 /* no type */ +#define REG_SZ 1 /* string type (ASCII) */ +#define REG_EXPAND_SZ 2 /* string, includes %ENVVAR% (expanded by caller) (ASCII) */ +#define REG_BINARY 3 /* binary format, callerspecific */ +/* YES, REG_DWORD == REG_DWORD_LITTLE_ENDIAN */ +#define REG_DWORD 4 /* DWORD in little endian format */ +#define REG_DWORD_LITTLE_ENDIAN 4 /* DWORD in little endian format */ +#define REG_DWORD_BIG_ENDIAN 5 /* DWORD in big endian format */ +#define REG_LINK 6 /* symbolic link (UNICODE) */ +#define REG_MULTI_SZ 7 /* multiple strings, delimited by \0, terminated by \0\0 (ASCII) */ +#define REG_RESOURCE_LIST 8 /* resource list? huh? */ +#define REG_FULL_RESOURCE_DESCRIPTOR 9 /* full resource descriptor? huh? */ +#define REG_RESOURCE_REQUIREMENTS_LIST 10 +#define REG_QWORD 11 /* QWORD in little endian format */ +#define REG_QWORD_LITTLE_ENDIAN 11 /* QWORD in little endian format */ + +/* security entities */ +#define SECURITY_NULL_RID (0x00000000L) +#define SECURITY_WORLD_RID (0x00000000L) +#define SECURITY_LOCAL_RID (0X00000000L) + +#define SECURITY_NULL_SID_AUTHORITY {0,0,0,0,0,0} + +/* S-1-1 */ +#define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} + +/* S-1-2 */ +#define SECURITY_LOCAL_SID_AUTHORITY {0,0,0,0,0,2} + +/* S-1-3 */ +#define SECURITY_CREATOR_SID_AUTHORITY {0,0,0,0,0,3} +#define SECURITY_CREATOR_OWNER_RID (0x00000000L) +#define SECURITY_CREATOR_GROUP_RID (0x00000001L) +#define SECURITY_CREATOR_OWNER_SERVER_RID (0x00000002L) +#define SECURITY_CREATOR_GROUP_SERVER_RID (0x00000003L) + +/* S-1-4 */ +#define SECURITY_NON_UNIQUE_AUTHORITY {0,0,0,0,0,4} + +/* S-1-5 */ +#define SECURITY_NT_AUTHORITY {0,0,0,0,0,5} +#define SECURITY_DIALUP_RID 0x00000001L +#define SECURITY_NETWORK_RID 0x00000002L +#define SECURITY_BATCH_RID 0x00000003L +#define SECURITY_INTERACTIVE_RID 0x00000004L +#define SECURITY_LOGON_IDS_RID 0x00000005L +#define SECURITY_SERVICE_RID 0x00000006L +#define SECURITY_ANONYMOUS_LOGON_RID 0x00000007L +#define SECURITY_PROXY_RID 0x00000008L +#define SECURITY_ENTERPRISE_CONTROLLERS_RID 0x00000009L +#define SECURITY_SERVER_LOGON_RID SECURITY_ENTERPRISE_CONTROLLERS_RID +#define SECURITY_PRINCIPAL_SELF_RID 0x0000000AL +#define SECURITY_AUTHENTICATED_USER_RID 0x0000000BL +#define SECURITY_RESTRICTED_CODE_RID 0x0000000CL +#define SECURITY_TERMINAL_SERVER_RID 0x0000000DL +#define SECURITY_REMOTE_LOGON_RID 0x0000000EL +#define SECURITY_THIS_ORGANIZATION_RID 0x0000000FL +#define SECURITY_LOCAL_SYSTEM_RID 0x00000012L +#define SECURITY_LOCAL_SERVICE_RID 0x00000013L +#define SECURITY_NETWORK_SERVICE_RID 0x00000014L +#define SECURITY_NT_NON_UNIQUE 0x00000015L +#define SECURITY_BUILTIN_DOMAIN_RID 0x00000020L + +#define SECURITY_PACKAGE_BASE_RID 0x00000040L +#define SECURITY_PACKAGE_NTLM_RID 0x0000000AL +#define SECURITY_PACKAGE_SCHANNEL_RID 0x0000000EL +#define SECURITY_PACKAGE_DIGEST_RID 0x00000015L +#define SECURITY_MAX_ALWAYS_FILTERED 0x000003E7L +#define SECURITY_MIN_NEVER_FILTERED 0x000003E8L +#define SECURITY_OTHER_ORGANIZATION_RID 0x000003E8L + +#define SID_REVISION (1) /* Current revision */ +#define SID_MAX_SUB_AUTHORITIES (15) /* current max subauths */ +#define SID_RECOMMENDED_SUB_AUTHORITIES (1) /* recommended subauths */ + +#define SECURITY_MAX_SID_SIZE (sizeof(SID) - sizeof(DWORD) + (SID_MAX_SUB_AUTHORITIES * sizeof(DWORD))) + +#define KEY_QUERY_VALUE 1 +#define KEY_SET_VALUE 2 +#define KEY_CREATE_SUB_KEY 4 +#define KEY_ENUMERATE_SUB_KEYS 8 +#define KEY_NOTIFY 16 +#define KEY_CREATE_LINK 32 +#define KEY_WRITE 0x20006 +#define KEY_EXECUTE 0x20019 +#define KEY_READ 0x20019 +#define KEY_ALL_ACCESS 0xf003f + + +#define MAKEWORD(low,high) ((WORD)(((BYTE)((DWORD_PTR)(low) & 0xFF)) \ + | ((WORD)((BYTE)((DWORD_PTR)(high) & 0xFF))) << 8)) +#define MAKELONG(low,high) ((LONG)(((WORD)((DWORD_PTR)(low) & 0xFFFF)) \ + | ((DWORD)((WORD)((DWORD_PTR)(high) & 0xFFFF))) << 16)) + +struct notify +{ + struct list_head entry; /* entry in list of notifications */ + struct kevent *event; /* event to set when changing this key */ + int subtree; /* true if subtree notification */ + unsigned int filter; /* which events to notify on */ + obj_handle_t hkey; /* hkey associated with this notification */ + struct eprocess *process; /* process in which the hkey is valid */ +}; + +/* information about a file being loaded */ +struct file_load_info +{ + const char *filename; /* input file name */ + struct LIBC_FILE *file; /* input file */ + char *buffer; /* line buffer */ + int len; /* buffer length */ + int line; /* current input line */ + WCHAR *tmp; /* temp buffer to use while parsing input */ + size_t tmplen; /* length of temp buffer */ +}; + +/* a key value */ +struct key_value +{ + WCHAR *name; /* value name */ + unsigned short namelen; /* length of value name */ + unsigned short type; /* value type */ + data_size_t len; /* value data length in bytes */ + void *data; /* pointer to value data */ +}; + +#define VALUES_PER_BLOCK 0x1000 + +struct reg_key +{ + WCHAR *name; /* key name */ + WCHAR *class; /* key class */ + unsigned short namelen; /* length of key name */ + unsigned short classlen; /* length of class name */ + struct reg_key *parent; /* parent key */ + int last_subkey; /* last in use subkey */ + int nb_subkeys; /* count of allocated subkeys */ + struct reg_key **subkeys; /* subkeys array */ + int last_value; /* last in use value */ + int nb_values; /* count of allocated values in array */ + struct key_value *values[4]; /* values array */ + unsigned int flags; /* flags */ + time_t modif; /* last modification time */ + struct list_head notify_list; /* list of notifications */ +}; + +#define MAX_SAVE_BRANCH_INFO 3 + +/* information about where to save a registry branch */ +struct save_branch_info +{ + struct reg_key *key; + char *path; +}; + +/* ch [0-9A-Fa-f] */ +static inline char to_hex(char ch) +{ + return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; +} + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WINESERVER_REG_H */ diff --git a/unifiedkernel/include/wineserver/request.h b/unifiedkernel/include/wineserver/request.h new file mode 100644 index 0000000..ae16189 --- /dev/null +++ b/unifiedkernel/include/wineserver/request.h @@ -0,0 +1,523 @@ +/* + * reguest.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * request.h: + * Refered to Wine code + */ + +#ifndef _WINESERVER_REQUEST_H +#define _WINESERVER_REQUEST_H + +#include "server.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* max request length */ +#define MAX_REQUEST_LENGTH 8192 + +/* request handler definition */ +#define DECL_HANDLER(name) \ + void req_##name( const struct name##_request *req, struct name##_reply *reply ) + + +/* Everything below this line is generated automatically by tools/make_requests */ +/* ### make_requests begin ### */ + +DECL_HANDLER(new_process); +DECL_HANDLER(get_new_process_info); +DECL_HANDLER(new_thread); +DECL_HANDLER(get_startup_info); +DECL_HANDLER(init_process_done); +DECL_HANDLER(init_thread); +DECL_HANDLER(terminate_process); +DECL_HANDLER(terminate_thread); +DECL_HANDLER(get_process_info); +DECL_HANDLER(set_process_info); +DECL_HANDLER(get_thread_info); +DECL_HANDLER(set_thread_info); +DECL_HANDLER(get_dll_info); +DECL_HANDLER(suspend_thread); +DECL_HANDLER(resume_thread); +DECL_HANDLER(load_dll); +DECL_HANDLER(unload_dll); +DECL_HANDLER(queue_apc); +DECL_HANDLER(get_apc_result); +DECL_HANDLER(close_handle); +DECL_HANDLER(set_handle_info); +DECL_HANDLER(dup_handle); +DECL_HANDLER(open_process); +DECL_HANDLER(open_thread); +DECL_HANDLER(select); +DECL_HANDLER(create_event); +DECL_HANDLER(event_op); +DECL_HANDLER(open_event); +DECL_HANDLER(create_mutex); +DECL_HANDLER(release_mutex); +DECL_HANDLER(open_mutex); +DECL_HANDLER(create_semaphore); +DECL_HANDLER(release_semaphore); +DECL_HANDLER(open_semaphore); +DECL_HANDLER(create_file); +DECL_HANDLER(open_file_object); +DECL_HANDLER(alloc_file_handle); +DECL_HANDLER(get_handle_fd); +DECL_HANDLER(flush_file); +DECL_HANDLER(lock_file); +DECL_HANDLER(unlock_file); +DECL_HANDLER(create_socket); +DECL_HANDLER(accept_socket); +DECL_HANDLER(set_socket_event); +DECL_HANDLER(get_socket_event); +DECL_HANDLER(enable_socket_event); +DECL_HANDLER(set_socket_deferred); +DECL_HANDLER(alloc_console); +DECL_HANDLER(free_console); +DECL_HANDLER(get_console_renderer_events); +DECL_HANDLER(open_console); +DECL_HANDLER(get_console_wait_event); +DECL_HANDLER(get_console_mode); +DECL_HANDLER(set_console_mode); +DECL_HANDLER(set_console_input_info); +DECL_HANDLER(get_console_input_info); +DECL_HANDLER(append_console_input_history); +DECL_HANDLER(get_console_input_history); +DECL_HANDLER(create_console_output); +DECL_HANDLER(set_console_output_info); +DECL_HANDLER(get_console_output_info); +DECL_HANDLER(write_console_input); +DECL_HANDLER(read_console_input); +DECL_HANDLER(write_console_output); +DECL_HANDLER(fill_console_output); +DECL_HANDLER(read_console_output); +DECL_HANDLER(move_console_output); +DECL_HANDLER(send_console_signal); +DECL_HANDLER(read_directory_changes); +DECL_HANDLER(read_change); +DECL_HANDLER(create_mapping); +DECL_HANDLER(open_mapping); +DECL_HANDLER(get_mapping_info); +DECL_HANDLER(create_snapshot); +DECL_HANDLER(next_process); +DECL_HANDLER(next_thread); +DECL_HANDLER(next_module); +DECL_HANDLER(wait_debug_event); +DECL_HANDLER(queue_exception_event); +DECL_HANDLER(get_exception_status); +DECL_HANDLER(output_debug_string); +DECL_HANDLER(continue_debug_event); +DECL_HANDLER(debug_process); +DECL_HANDLER(debug_break); +DECL_HANDLER(set_debugger_kill_on_exit); +DECL_HANDLER(read_process_memory); +DECL_HANDLER(write_process_memory); +DECL_HANDLER(create_key); +DECL_HANDLER(open_key); +DECL_HANDLER(delete_key); +DECL_HANDLER(flush_key); +DECL_HANDLER(enum_key); +DECL_HANDLER(set_key_value); +DECL_HANDLER(get_key_value); +DECL_HANDLER(enum_key_value); +DECL_HANDLER(delete_key_value); +DECL_HANDLER(load_registry); +DECL_HANDLER(unload_registry); +DECL_HANDLER(save_registry); +DECL_HANDLER(set_registry_notification); +DECL_HANDLER(create_timer); +DECL_HANDLER(open_timer); +DECL_HANDLER(set_timer); +DECL_HANDLER(cancel_timer); +DECL_HANDLER(get_timer_info); +DECL_HANDLER(get_thread_context); +DECL_HANDLER(set_thread_context); +DECL_HANDLER(get_selector_entry); +DECL_HANDLER(add_atom); +DECL_HANDLER(delete_atom); +DECL_HANDLER(find_atom); +DECL_HANDLER(get_atom_information); +DECL_HANDLER(set_atom_information); +DECL_HANDLER(empty_atom_table); +DECL_HANDLER(init_atom_table); +DECL_HANDLER(get_msg_queue); +DECL_HANDLER(set_queue_fd); +DECL_HANDLER(set_queue_mask); +DECL_HANDLER(get_queue_status); +DECL_HANDLER(get_process_idle_event); +DECL_HANDLER(send_message); +DECL_HANDLER(post_quit_message); +DECL_HANDLER(send_hardware_message); +DECL_HANDLER(get_message); +DECL_HANDLER(reply_message); +DECL_HANDLER(accept_hardware_message); +DECL_HANDLER(get_message_reply); +DECL_HANDLER(set_win_timer); +DECL_HANDLER(kill_win_timer); +DECL_HANDLER(is_window_hung); +DECL_HANDLER(get_serial_info); +DECL_HANDLER(set_serial_info); +DECL_HANDLER(register_async); +DECL_HANDLER(cancel_async); +DECL_HANDLER(ioctl); +DECL_HANDLER(get_ioctl_result); +DECL_HANDLER(create_named_pipe); +DECL_HANDLER(get_named_pipe_info); +DECL_HANDLER(create_window); +DECL_HANDLER(destroy_window); +DECL_HANDLER(get_desktop_window); +DECL_HANDLER(set_window_owner); +DECL_HANDLER(get_window_info); +DECL_HANDLER(set_window_info); +DECL_HANDLER(set_parent); +DECL_HANDLER(get_window_parents); +DECL_HANDLER(get_window_children); +DECL_HANDLER(get_window_children_from_point); +DECL_HANDLER(get_window_tree); +DECL_HANDLER(set_window_pos); +DECL_HANDLER(set_window_visible_rect); +DECL_HANDLER(get_window_rectangles); +DECL_HANDLER(get_window_text); +DECL_HANDLER(set_window_text); +DECL_HANDLER(get_windows_offset); +DECL_HANDLER(get_visible_region); +DECL_HANDLER(get_window_region); +DECL_HANDLER(set_window_region); +DECL_HANDLER(get_update_region); +DECL_HANDLER(update_window_zorder); +DECL_HANDLER(redraw_window); +DECL_HANDLER(set_window_property); +DECL_HANDLER(remove_window_property); +DECL_HANDLER(get_window_property); +DECL_HANDLER(get_window_properties); +DECL_HANDLER(create_winstation); +DECL_HANDLER(open_winstation); +DECL_HANDLER(close_winstation); +DECL_HANDLER(get_process_winstation); +DECL_HANDLER(set_process_winstation); +DECL_HANDLER(enum_winstation); +DECL_HANDLER(create_desktop); +DECL_HANDLER(open_desktop); +DECL_HANDLER(close_desktop); +DECL_HANDLER(get_thread_desktop); +DECL_HANDLER(set_thread_desktop); +DECL_HANDLER(enum_desktop); +DECL_HANDLER(set_user_object_info); +DECL_HANDLER(attach_thread_input); +DECL_HANDLER(get_thread_input); +DECL_HANDLER(get_last_input_time); +DECL_HANDLER(get_key_state); +DECL_HANDLER(set_key_state); +DECL_HANDLER(set_foreground_window); +DECL_HANDLER(set_focus_window); +DECL_HANDLER(set_active_window); +DECL_HANDLER(set_capture_window); +DECL_HANDLER(set_caret_window); +DECL_HANDLER(set_caret_info); +DECL_HANDLER(set_hook); +DECL_HANDLER(remove_hook); +DECL_HANDLER(start_hook_chain); +DECL_HANDLER(finish_hook_chain); +DECL_HANDLER(get_hook_info); +DECL_HANDLER(create_class); +DECL_HANDLER(destroy_class); +DECL_HANDLER(set_class_info); +DECL_HANDLER(set_clipboard_info); +DECL_HANDLER(open_token); +DECL_HANDLER(set_global_windows); +DECL_HANDLER(adjust_token_privileges); +DECL_HANDLER(get_token_privileges); +DECL_HANDLER(check_token_privileges); +DECL_HANDLER(duplicate_token); +DECL_HANDLER(access_check); +DECL_HANDLER(get_token_user); +DECL_HANDLER(get_token_groups); +DECL_HANDLER(set_security_object); +DECL_HANDLER(get_security_object); +DECL_HANDLER(create_mailslot); +DECL_HANDLER(set_mailslot_info); +DECL_HANDLER(create_directory); +DECL_HANDLER(open_directory); +DECL_HANDLER(get_directory_entry); +DECL_HANDLER(create_symlink); +DECL_HANDLER(open_symlink); +DECL_HANDLER(query_symlink); +DECL_HANDLER(get_object_info); +DECL_HANDLER(get_token_impersonation_level); +DECL_HANDLER(allocate_locally_unique_id); +DECL_HANDLER(create_device_manager); +DECL_HANDLER(create_device); +DECL_HANDLER(delete_device); +DECL_HANDLER(get_next_device_request); +DECL_HANDLER(make_process_system); +DECL_HANDLER(get_token_statistics); +DECL_HANDLER(create_completion); +DECL_HANDLER(open_completion); +DECL_HANDLER(add_completion); +DECL_HANDLER(remove_completion); +DECL_HANDLER(query_completion); +DECL_HANDLER(set_completion_info); +DECL_HANDLER(add_fd_completion); +DECL_HANDLER(load_init_registry); +DECL_HANDLER(save_branch); + +typedef void (*req_handler)( const void *req, void *reply ); +static const req_handler req_handlers[REQ_NB_REQUESTS] = +{ + (req_handler)req_new_process, + (req_handler)req_get_new_process_info, + (req_handler)req_new_thread, + (req_handler)req_get_startup_info, + (req_handler)req_init_process_done, + (req_handler)req_init_thread, + (req_handler)req_terminate_process, + (req_handler)req_terminate_thread, + (req_handler)req_get_process_info, + (req_handler)req_set_process_info, + (req_handler)req_get_thread_info, + (req_handler)req_set_thread_info, + (req_handler)req_get_dll_info, + (req_handler)req_suspend_thread, + (req_handler)req_resume_thread, + (req_handler)req_load_dll, + (req_handler)req_unload_dll, + (req_handler)req_queue_apc, + (req_handler)req_get_apc_result, + (req_handler)req_close_handle, + (req_handler)req_set_handle_info, + (req_handler)req_dup_handle, + (req_handler)req_open_process, + (req_handler)req_open_thread, + (req_handler)req_select, + (req_handler)req_create_event, + (req_handler)req_event_op, + (req_handler)req_open_event, + (req_handler)req_create_mutex, + (req_handler)req_release_mutex, + (req_handler)req_open_mutex, + (req_handler)req_create_semaphore, + (req_handler)req_release_semaphore, + (req_handler)req_open_semaphore, + (req_handler)req_create_file, + (req_handler)req_open_file_object, + (req_handler)req_alloc_file_handle, + (req_handler)req_get_handle_fd, + (req_handler)req_flush_file, + (req_handler)req_lock_file, + (req_handler)req_unlock_file, + (req_handler)req_create_socket, + (req_handler)req_accept_socket, + (req_handler)req_set_socket_event, + (req_handler)req_get_socket_event, + (req_handler)req_enable_socket_event, + (req_handler)req_set_socket_deferred, + (req_handler)req_alloc_console, + (req_handler)req_free_console, + (req_handler)req_get_console_renderer_events, + (req_handler)req_open_console, + (req_handler)req_get_console_wait_event, + (req_handler)req_get_console_mode, + (req_handler)req_set_console_mode, + (req_handler)req_set_console_input_info, + (req_handler)req_get_console_input_info, + (req_handler)req_append_console_input_history, + (req_handler)req_get_console_input_history, + (req_handler)req_create_console_output, + (req_handler)req_set_console_output_info, + (req_handler)req_get_console_output_info, + (req_handler)req_write_console_input, + (req_handler)req_read_console_input, + (req_handler)req_write_console_output, + (req_handler)req_fill_console_output, + (req_handler)req_read_console_output, + (req_handler)req_move_console_output, + (req_handler)req_send_console_signal, + (req_handler)req_read_directory_changes, + (req_handler)req_read_change, + (req_handler)req_create_mapping, + (req_handler)req_open_mapping, + (req_handler)req_get_mapping_info, + (req_handler)req_create_snapshot, + (req_handler)req_next_process, + (req_handler)req_next_thread, + (req_handler)req_next_module, + (req_handler)req_wait_debug_event, + (req_handler)req_queue_exception_event, + (req_handler)req_get_exception_status, + (req_handler)req_output_debug_string, + (req_handler)req_continue_debug_event, + (req_handler)req_debug_process, + (req_handler)req_debug_break, + (req_handler)req_set_debugger_kill_on_exit, + (req_handler)req_read_process_memory, + (req_handler)req_write_process_memory, + (req_handler)req_create_key, + (req_handler)req_open_key, + (req_handler)req_delete_key, + (req_handler)req_flush_key, + (req_handler)req_enum_key, + (req_handler)req_set_key_value, + (req_handler)req_get_key_value, + (req_handler)req_enum_key_value, + (req_handler)req_delete_key_value, + (req_handler)req_load_registry, + (req_handler)req_unload_registry, + (req_handler)req_save_registry, + (req_handler)req_set_registry_notification, + (req_handler)req_create_timer, + (req_handler)req_open_timer, + (req_handler)req_set_timer, + (req_handler)req_cancel_timer, + (req_handler)req_get_timer_info, + (req_handler)req_get_thread_context, + (req_handler)req_set_thread_context, + (req_handler)req_get_selector_entry, + (req_handler)req_add_atom, + (req_handler)req_delete_atom, + (req_handler)req_find_atom, + (req_handler)req_get_atom_information, + (req_handler)req_set_atom_information, + (req_handler)req_empty_atom_table, + (req_handler)req_init_atom_table, + (req_handler)req_get_msg_queue, + (req_handler)req_set_queue_fd, + (req_handler)req_set_queue_mask, + (req_handler)req_get_queue_status, + (req_handler)req_get_process_idle_event, + (req_handler)req_send_message, + (req_handler)req_post_quit_message, + (req_handler)req_send_hardware_message, + (req_handler)req_get_message, + (req_handler)req_reply_message, + (req_handler)req_accept_hardware_message, + (req_handler)req_get_message_reply, + (req_handler)req_set_win_timer, + (req_handler)req_kill_win_timer, + (req_handler)req_is_window_hung, + (req_handler)req_get_serial_info, + (req_handler)req_set_serial_info, + (req_handler)req_register_async, + (req_handler)req_cancel_async, + (req_handler)req_ioctl, + (req_handler)req_get_ioctl_result, + (req_handler)req_create_named_pipe, + (req_handler)req_get_named_pipe_info, + (req_handler)req_create_window, + (req_handler)req_destroy_window, + (req_handler)req_get_desktop_window, + (req_handler)req_set_window_owner, + (req_handler)req_get_window_info, + (req_handler)req_set_window_info, + (req_handler)req_set_parent, + (req_handler)req_get_window_parents, + (req_handler)req_get_window_children, + (req_handler)req_get_window_children_from_point, + (req_handler)req_get_window_tree, + (req_handler)req_set_window_pos, + (req_handler)req_set_window_visible_rect, + (req_handler)req_get_window_rectangles, + (req_handler)req_get_window_text, + (req_handler)req_set_window_text, + (req_handler)req_get_windows_offset, + (req_handler)req_get_visible_region, + (req_handler)req_get_window_region, + (req_handler)req_set_window_region, + (req_handler)req_get_update_region, + (req_handler)req_update_window_zorder, + (req_handler)req_redraw_window, + (req_handler)req_set_window_property, + (req_handler)req_remove_window_property, + (req_handler)req_get_window_property, + (req_handler)req_get_window_properties, + (req_handler)req_create_winstation, + (req_handler)req_open_winstation, + (req_handler)req_close_winstation, + (req_handler)req_get_process_winstation, + (req_handler)req_set_process_winstation, + (req_handler)req_enum_winstation, + (req_handler)req_create_desktop, + (req_handler)req_open_desktop, + (req_handler)req_close_desktop, + (req_handler)req_get_thread_desktop, + (req_handler)req_set_thread_desktop, + (req_handler)req_enum_desktop, + (req_handler)req_set_user_object_info, + (req_handler)req_attach_thread_input, + (req_handler)req_get_thread_input, + (req_handler)req_get_last_input_time, + (req_handler)req_get_key_state, + (req_handler)req_set_key_state, + (req_handler)req_set_foreground_window, + (req_handler)req_set_focus_window, + (req_handler)req_set_active_window, + (req_handler)req_set_capture_window, + (req_handler)req_set_caret_window, + (req_handler)req_set_caret_info, + (req_handler)req_set_hook, + (req_handler)req_remove_hook, + (req_handler)req_start_hook_chain, + (req_handler)req_finish_hook_chain, + (req_handler)req_get_hook_info, + (req_handler)req_create_class, + (req_handler)req_destroy_class, + (req_handler)req_set_class_info, + (req_handler)req_set_clipboard_info, + (req_handler)req_open_token, + (req_handler)req_set_global_windows, + (req_handler)req_adjust_token_privileges, + (req_handler)req_get_token_privileges, + (req_handler)req_check_token_privileges, + (req_handler)req_duplicate_token, + (req_handler)req_access_check, + (req_handler)req_get_token_user, + (req_handler)req_get_token_groups, + (req_handler)req_set_security_object, + (req_handler)req_get_security_object, + (req_handler)req_create_mailslot, + (req_handler)req_set_mailslot_info, + (req_handler)req_create_directory, + (req_handler)req_open_directory, + (req_handler)req_get_directory_entry, + (req_handler)req_create_symlink, + (req_handler)req_open_symlink, + (req_handler)req_query_symlink, + (req_handler)req_get_object_info, + (req_handler)req_get_token_impersonation_level, + (req_handler)req_allocate_locally_unique_id, + (req_handler)req_create_device_manager, + (req_handler)req_create_device, + (req_handler)req_delete_device, + (req_handler)req_get_next_device_request, + (req_handler)req_make_process_system, + (req_handler)req_get_token_statistics, + (req_handler)req_create_completion, + (req_handler)req_open_completion, + (req_handler)req_add_completion, + (req_handler)req_remove_completion, + (req_handler)req_query_completion, + (req_handler)req_set_completion_info, + (req_handler)req_add_fd_completion, + (req_handler)req_load_init_registry, + (req_handler)req_save_branch, +}; + +#endif +#endif /* _WINESERVER_REQUEST_H */ + diff --git a/unifiedkernel/include/wineserver/server.h b/unifiedkernel/include/wineserver/server.h new file mode 100644 index 0000000..331c408 --- /dev/null +++ b/unifiedkernel/include/wineserver/server.h @@ -0,0 +1,53 @@ +/* + * server.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * server.h: + * Refered to Wine code + */ + +#ifndef _WINESERVER_SERVER_H +#define _WINESERVER_SERVER_H +#include "uk_protocol.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct __server_iovec +{ + const void *ptr; + data_size_t size; +}; + +#define __SERVER_MAX_DATA 5 + +typedef struct __server_request_info +{ + union + { + union generic_request req; /* request structure */ + union generic_reply reply; /* reply structure */ + } u; + unsigned int data_count; /* count of request data pointers */ + void *reply_data; /* reply data pointer */ + struct __server_iovec data[__SERVER_MAX_DATA]; /* request variable size data */ +} *PSERVER_REQUEST_INFO; +#endif +#endif diff --git a/unifiedkernel/include/wineserver/uk_lib.h b/unifiedkernel/include/wineserver/uk_lib.h new file mode 100644 index 0000000..e2d2ff3 --- /dev/null +++ b/unifiedkernel/include/wineserver/uk_lib.h @@ -0,0 +1,506 @@ +/* + * uk_lib.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * uk_lib.h: + * Refered to Wine code + */ + +#ifndef _WINESERVER_UK_LIB_H +#define _WINESERVER_UK_LIB_H +#include +#include +#include +#include +#include +#include +#include +#if 0 +#include +#include +#include +#include +#endif + +/* FIXME */ +#include "win32.h" +#include "w32syscall.h" +#include "handle.h" +#include "event.h" + +#include "server.h" +#include "request.h" +#include "thread.h" +#include "winerror.h" +#include "object.h" +#include "objwait.h" +#include "user.h" +#include "file.h" +#include "wcstr.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#define errno get_error() + +struct LIBC_FILE +{ + struct file *filp; + loff_t pos; + char *buf; + long buflen; + long bufpos; + ssize_t validlen; +}; + +#if 0 +struct pipe_server +{ + int fd; + /* Depends on how pipe is implemented */ +}; +#endif + +time_t time(void* v); + +#define MAXSIZE_ALLOC (128 * 1024) + +void *malloc(size_t size); +void* calloc(size_t nmemb, size_t size); +void *mem_alloc(size_t size); +void *memdup(const void *data, size_t len); +void free(void* p); +void *realloc(void *ptr, size_t new_size, size_t old_size); + +WCHAR toupperW(WCHAR ch); +WCHAR tolowerW(WCHAR ch); +int memicmpW(const WCHAR *str1, const WCHAR *str2, int n); + +void no_flush(struct fd *fd, struct kevent **event); +int no_add_queue(struct object *obj, struct wait_queue_entry *entry); +int no_close_handle(struct object *o, struct w32process *p, obj_handle_t h); +struct object *no_lookup_name(struct object *obj, struct unicode_str *name, unsigned int attributes); +struct fd *no_get_fd(struct object *obj); +struct object *no_open_file(struct object *o, unsigned int d , unsigned int i , unsigned int u); +int no_satisfied(struct object *obj, struct w32thread *thread); +int no_signal(struct object *obj, unsigned int access); +unsigned int no_map_access(struct object *obj, unsigned int access); + +/* object */ +#if 0 +POBJECT_ATTRIBUTES get_attr(HANDLE RootDirectory, const struct unicode_str *name, + unsigned int attr, ULONG len, void *securitydes, void *securityqofs); + +void *create_named_object(HANDLE RootDirectory, POBJECT_TYPE Type, + const struct unicode_str *name, unsigned int attr, int obj_size); +#endif + +void dump_object_name(struct object *obj); + +HANDLE duplicate_handle(HANDLE src, HANDLE src_handle, HANDLE dst, + unsigned int access, unsigned int attr, unsigned int options); + +#define HANDLE_FLAG_INHERIT 0x00000001 + +#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 + +/* reserved handle access rights */ + +#define RESERVED_SHIFT 26 + +#define RESERVED_INHERIT (HANDLE_FLAG_INHERIT << RESERVED_SHIFT) + +#define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT) + +#define RESERVED_ALL (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT) + +unsigned int get_handle_access(struct eprocess *process, HANDLE handle); + +int close_handle(struct eprocess *process, HANDLE handle); + +extern long uk_close(unsigned int fd); +extern ssize_t uk_write(unsigned int fd, void *buf, size_t size); +extern ssize_t uk_filp_write(struct file *filp, void *buf, size_t size); +extern long uk_fcntl(unsigned int fd, int cmd, unsigned long arg /* struct flock *flock */); +extern long uk_fcntl_lock(unsigned int fd, int op, struct flock* flock); +extern long uk_dup(unsigned int fd); + +extern ssize_t uk_pread(unsigned int fd, char *buf, size_t count, off_t pos); +extern ssize_t uk_filp_pread(struct file *filp, char *buf, size_t count, off_t pos); +extern ssize_t uk_pwrite(unsigned int fd, const char *buf, size_t count, off_t pos); +extern ssize_t uk_filp_pwrite(struct file *filp, const char *buf, size_t count, off_t pos); +extern long uk_readlink(const char *path, char *buf, size_t bufsiz); +extern long uk_fcntl(unsigned int fd, int cmd, unsigned long arg); +extern long uk_stat(char *filename, struct stat *st); + +/* fd */ +void remove_timeout_user(struct timeout_user *user); + +/* FIXME fd not implemented */ +struct fd *create_anonymous_fd(const struct fd_ops *fd_user_ops, + int unix_fd, struct object *user, unsigned int options); +void *get_fd_user(struct fd *fd); +int get_unix_fd(HANDLE handle); +#if 0 +int get_file_unix_fd(struct file* f); +struct file *get_file_obj(struct w32process *p, user_handle_t h, unsigned int d); +#endif + +/* winstation */ +obj_handle_t find_inherited_handle(struct w32process *process, const struct object_ops *ops); +void cleanup_clipboard_thread(struct w32thread *thread); +void msg_queue_dump(struct object *obj, int verbose); +/* console */ +void kill_console_processes(struct w32thread *renderer, int exit_code); + +void get_req_path(struct unicode_str *str, int skip_root); + +/* add by solaris 2008/06/23 */ +int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist); + +int vsprintfW(WCHAR *str, const WCHAR *format, va_list valist); + +int snprintfW(WCHAR *str, size_t len, const WCHAR *format, ...); + +extern int sprintfW(WCHAR *str, const WCHAR *format, ...); + +extern void *uk_fgets(void *buf, int len, struct LIBC_FILE *fp); + + +extern long uk_fclose(struct LIBC_FILE* fp); + +extern struct LIBC_FILE *uk_fdopen(int fd, char *readwrite); +extern struct LIBC_FILE *uk_fopen(const char *filename, char *readwrite) ; +extern struct LIBC_FILE *uk_filp_open(struct file *filp, char *readwrite) ; + +extern void uk_perror(const char *s); +extern int uk_fprintf(struct LIBC_FILE *fp , char *fmt, ...); +extern ssize_t uk_fwrite(struct LIBC_FILE *fp, void *buf, size_t size); + +extern long uk_lstat(char *filename, struct stat *st); +extern long uk_fstatfs(unsigned int fd, struct statfs *st); +extern int uk_realpath(const char *path, char *real); +extern long uk_fstat(unsigned int fd, struct stat *st); +extern long uk_ftruncate(unsigned int fd, long tr); +extern long uk_open(const char *filename, int flags, int mode); +extern void uk_unlink(const char *filename); +extern int uk_rename(const char *oldpath, const char *newpath); +extern ssize_t uk_read(unsigned int fd, void *buf, size_t size); +extern long uk_mkdir(const char *name, int mode); + +extern POBJECT_TYPE event_object_type; + +static inline void set_error(unsigned int e) +{ + struct w32thread *w32thread = get_current_w32thread(); + + if (w32thread) + w32thread->error = e; +} + +static inline unsigned int get_error(void) +{ + struct w32thread *w32thread = get_current_w32thread(); + + return w32thread ? w32thread->error : 0; +} + +static inline void clear_error(void) +{ + set_error(STATUS_SUCCESS); +} + +static inline pid_t getpid(void) +{ + return current->tgid; +} + +static inline char *strdup(const char *src) +{ + char *ret; + + ret = kstrdup(src, GFP_KERNEL); + if (!ret) + set_error(STATUS_NO_MEMORY); + + return ret; +} + +static inline void *grab_object(void *obj) +{ + ref_object(obj); + return obj; +} + +static inline void *get_handle_obj(HANDLE handle, unsigned int access, POBJECT_TYPE Type) +{ + void *obj = NULL; + NTSTATUS ret; + + ret = ref_object_by_handle(handle, access, Type, KernelMode, &obj, NULL); + if (!NT_SUCCESS(ret)) { + set_error((unsigned int)ret); + return NULL; + } + + return obj; +} + +static inline void *get_wine_handle_obj(struct w32process *proc, HANDLE handle, + unsigned int access, const struct object_ops *ops) +{ + void *obj = NULL; + NTSTATUS ret; + + ret = ref_object_by_handle(handle, access, NULL, KernelMode, &obj, NULL); + if (!NT_SUCCESS(ret)) { + set_error((unsigned int)ret); + return NULL; + } + + return obj; +} + +static inline HANDLE alloc_key_handle(void *key, unsigned int access, unsigned int attr) +{ + HANDLE handle = NULL; + NTSTATUS ret; + + ret = create_handle(current->ethread ? get_current_eprocess() : NULL, + key, access, attr & OBJ_INHERIT, &handle); + if (!NT_SUCCESS(ret)) { + set_error((unsigned int)ret); + return NULL; + } + + return handle; +} + +static inline void *get_req_data(void) +{ + return get_current_w32thread() ? get_current_w32thread()->req_data : NULL; +} + +static inline unsigned int get_req_data_size(void) +{ + return get_current_w32thread() ? get_current_w32thread()->req.request_header.request_size : 0; +} + +static inline unsigned int get_reply_max_size(void) +{ + return get_current_w32thread() ? get_current_w32thread()->req.request_header.reply_size : 0; +} + +static inline void set_reply_data_ptr(void *data, unsigned int size) +{ + struct w32thread *thread = get_current_w32thread(); + + if (!thread) + return; + + if (size <= get_reply_max_size()) { + thread->reply_size = size; + thread->reply_data = data; + } else + kdebug("size large err\n"); /* TODO */ +} + +static inline void *set_reply_data_size(int size) +{ + struct w32thread *thread = get_current_w32thread(); + + if (!thread) + return NULL; + + if (size <= get_reply_max_size()) { + if (size && !(thread->reply_data = mem_alloc(size))) + size = 0; + thread->reply_size = size; + return thread->reply_data; + + } else { + kdebug("size large err\n"); /* TODO */ + return NULL; + } +} + +static inline void *set_reply_data(const void *data, unsigned int size) +{ + void *ret = set_reply_data_size(size); + + if (ret) + memcpy(ret, data, size); + + return ret; +} + +static inline void get_req_unicode_str(struct unicode_str *s) +{ + s->str = get_req_data(); + s->len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR); +} + +static inline int uk_fputc(char c, struct LIBC_FILE *f) +{ + return uk_fprintf(f,"%c",c);; +} + +static inline WCHAR *strcpyW(WCHAR *dst, const WCHAR *src) +{ + return wcscpy(dst, src); +} + +static inline int strlenW(const WCHAR *str) +{ + return wcslen((PWSTR)str) / sizeof(WCHAR); +} + +static inline WCHAR *memchrW(const WCHAR *ptr, WCHAR ch, size_t n) +{ + return wmemchr(ptr, ch, n); +} + +static inline int strncmpW(const WCHAR *str1, const WCHAR *str2, int n) +{ + return wcsncmp(str1, str2, n); +} + +static inline int isdigitW(WCHAR wc) +{ + return (wc >= '0') && (wc <= '9'); +} + +static inline struct kevent *get_event_obj(struct w32process *process, obj_handle_t handle, + unsigned int access) +{ + return (struct kevent *)get_handle_obj(handle, access, event_object_type); +} + +static inline void set_win32_error(int e) +{ + set_error(0xc0010000 | e); +} + +static inline void *get_ptid_entry(HANDLE pid) +{ + NTSTATUS ret; + struct eprocess *process = NULL; + + ret = lookup_process_by_pid(pid, &process); + if (!NT_SUCCESS(ret)) + set_error((unsigned int)ret); + + return process; +} + +static inline struct eprocess *get_process_from_id(HANDLE id) +{ + return get_ptid_entry(id); +} + +static inline void free_ptid(HANDLE pid) +{ + NTSTATUS ret; + + ret = delete_cid_handle(pid, process_object_type); + if (!NT_SUCCESS(ret)) + set_error((unsigned int)ret); + + return; +} + +static inline int send_thread_signal(struct ethread *thread, int sig) +{ + return send_sig_info(sig, (void *)2L, thread->et_task); +} + +static inline WCHAR *get_object_name(void *obj, data_size_t *len) +{ + POBJECT_HEADER_NAME_INFO name_info; + + name_info = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(obj)); + if (name_info) { + *len = name_info->Name.Length; + return name_info->Name.Buffer; + } else { + *len = 0; + return NULL; + } +} + +static inline int interlocked_xchg(int *dest, int val) +{ + int ret; + + asm volatile("lock; xchgl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (val) + : "memory"); + + return ret; +} +static inline int interlocked_xchg_add(int *dest, int incr) +{ + int ret; + + asm volatile("lock; xaddl %0,(%1)" + : "=r" (ret) + : "r" (dest), "0" (incr) + : "memory" ); + + return ret; +} + +static inline struct inode *get_file_inode(struct file *file) +{ + return file->f_path.dentry->d_inode; +} + +static inline loff_t get_file_size(struct file *file) +{ + return file->f_path.dentry->d_inode->i_size; +} + +enum +{ + SHUT_RD = 0, /* No more receptions. */ +#define SHUT_RD SHUT_RD + SHUT_WR, /* No more transmissions. */ +#define SHUT_WR SHUT_WR + SHUT_RDWR /* No more receptions or transmissions. */ +#define SHUT_RDWR SHUT_RDWR +}; + +#define POLLIN 0x001 /* There is data to read. */ +#define POLLPRI 0x002 /* There is urgent data to read. */ +#define POLLOUT 0x004 /* Writing now will not block. */ +#define POLLERR 0x008 /* Error condition. */ +#define POLLHUP 0x010 /* Hung up. */ +#define POLLNVAL 0x020 /* Invalid polling request. */ + +/* Data structure describing a polling request. */ +struct pollfd +{ + int fd; /* File descriptor to poll. */ + short int events; /* Types of events poller cares about. */ + short int revents; /* Types of events that actually occurred. */ +}; +#endif +#endif /* _WINESERVER_UK_LIB_H */ diff --git a/unifiedkernel/include/wineserver/uk_protocol.h b/unifiedkernel/include/wineserver/uk_protocol.h new file mode 100644 index 0000000..4f49722 --- /dev/null +++ b/unifiedkernel/include/wineserver/uk_protocol.h @@ -0,0 +1,5061 @@ +/* + * uk_protocol.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * uk_protocol.h: + * Refered to Wine code + */ +#ifndef _WINESERVER_UK_PROTOCOL_H +#define _WINESERVER_UK_PROTOCOL_H + +#include +#include "win32.h" + +#ifdef CONFIG_UNIFIED_KERNEL +typedef void *obj_handle_t; +typedef void *user_handle_t; +typedef unsigned short atom_t; +typedef unsigned int process_id_t; +typedef unsigned int thread_id_t; +typedef unsigned int data_size_t; +typedef unsigned int ioctl_code_t; +typedef unsigned __int64 file_pos_t; + +struct request_header +{ + int req; + data_size_t request_size; + data_size_t reply_size; +}; + +struct reply_header +{ + unsigned int error; + data_size_t reply_size; +}; + + + +struct request_max_size +{ + int pad[16]; +}; + +#define FIRST_USER_HANDLE 0x0020 +#define LAST_USER_HANDLE 0xffef + + + +struct debug_event_exception +{ + EXCEPTION_RECORD record; + int first; +}; +struct debug_event_create_thread +{ + obj_handle_t handle; + void *teb; + void *start; +}; +struct debug_event_create_process +{ + obj_handle_t file; + obj_handle_t process; + obj_handle_t thread; + void *base; + int dbg_offset; + int dbg_size; + void *teb; + void *start; + void *name; + int unicode; +}; +struct debug_event_exit +{ + int exit_code; +}; +struct debug_event_load_dll +{ + obj_handle_t handle; + void *base; + int dbg_offset; + int dbg_size; + void *name; + int unicode; +}; +struct debug_event_unload_dll +{ + void *base; +}; +struct debug_event_output_string +{ + void *string; + int unicode; + int length; +}; +struct debug_event_rip_info +{ + int error; + int type; +}; +union debug_event_data +{ + struct debug_event_exception exception; + struct debug_event_create_thread create_thread; + struct debug_event_create_process create_process; + struct debug_event_exit exit; + struct debug_event_load_dll load_dll; + struct debug_event_unload_dll unload_dll; + struct debug_event_output_string output_string; + struct debug_event_rip_info rip_info; +}; + + +typedef struct +{ + int code; + union debug_event_data info; +} debug_event_t; + + +struct send_fd +{ + thread_id_t tid; + int fd; +}; + + +struct wake_up_reply +{ + void *cookie; + int signaled; +}; + + +typedef long long timeout_t; +#define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff) + + +typedef struct +{ + atom_t atom; + short string; + obj_handle_t handle; +} property_data_t; + + +typedef struct +{ + int left; + int top; + int right; + int bottom; +} rectangle_t; + + +typedef struct +{ + void *callback; + void *iosb; + void *arg; + void *apc; + obj_handle_t event; + unsigned long cvalue; +} async_data_t; + + + +struct callback_msg_data +{ + void *callback; + unsigned long data; + unsigned long result; +}; + +struct winevent_msg_data +{ + user_handle_t hook; + thread_id_t tid; + void *hook_proc; + +}; + +typedef union +{ + unsigned char bytes[1]; + struct callback_msg_data callback; + struct winevent_msg_data winevent; +} message_data_t; + + +typedef struct +{ + WCHAR ch; + unsigned short attr; +} char_info_t; + +typedef struct +{ + unsigned int low_part; + int high_part; +} luid_t; + +#define MAX_ACL_LEN 65535 + +struct security_descriptor +{ + unsigned int control; + data_size_t owner_len; + data_size_t group_len; + data_size_t sacl_len; + data_size_t dacl_len; + + + + +}; + +struct object_attributes +{ + obj_handle_t rootdir; + data_size_t sd_len; + data_size_t name_len; + + +}; + +struct token_groups +{ + unsigned int count; + + +}; + +enum apc_type +{ + APC_NONE, + APC_USER, + APC_TIMER, + APC_ASYNC_IO, + APC_VIRTUAL_ALLOC, + APC_VIRTUAL_FREE, + APC_VIRTUAL_QUERY, + APC_VIRTUAL_PROTECT, + APC_VIRTUAL_FLUSH, + APC_VIRTUAL_LOCK, + APC_VIRTUAL_UNLOCK, + APC_MAP_VIEW, + APC_UNMAP_VIEW, + APC_CREATE_THREAD +}; + +typedef union +{ + enum apc_type type; + struct + { + enum apc_type type; + void (__stdcall *func)(unsigned long,unsigned long,unsigned long); + unsigned long args[3]; + } user; + struct + { + enum apc_type type; + void (__stdcall *func)(void*, unsigned int, unsigned int); + timeout_t time; + void *arg; + } timer; + struct + { + enum apc_type type; + unsigned int (*func)(void*, void*, unsigned int, unsigned long *); + void *user; + void *sb; + unsigned int status; + } async_io; + struct + { + enum apc_type type; + void *addr; + unsigned long size; + unsigned int zero_bits; + unsigned int op_type; + unsigned int prot; + } virtual_alloc; + struct + { + enum apc_type type; + void *addr; + unsigned long size; + unsigned int op_type; + } virtual_free; + struct + { + enum apc_type type; + const void *addr; + } virtual_query; + struct + { + enum apc_type type; + void *addr; + unsigned long size; + unsigned int prot; + } virtual_protect; + struct + { + enum apc_type type; + const void *addr; + unsigned long size; + } virtual_flush; + struct + { + enum apc_type type; + void *addr; + unsigned long size; + } virtual_lock; + struct + { + enum apc_type type; + void *addr; + unsigned long size; + } virtual_unlock; + struct + { + enum apc_type type; + obj_handle_t handle; + void *addr; + unsigned long size; + file_pos_t offset; + unsigned int zero_bits; + unsigned int alloc_type; + unsigned int prot; + } map_view; + struct + { + enum apc_type type; + void *addr; + } unmap_view; + struct + { + enum apc_type type; + void (__stdcall *func)(void*); + void *arg; + unsigned long reserve; + unsigned long commit; + int suspend; + } create_thread; +} apc_call_t; + +typedef union +{ + enum apc_type type; + struct + { + enum apc_type type; + unsigned int status; + unsigned long total; + } async_io; + struct + { + enum apc_type type; + unsigned int status; + void *addr; + unsigned long size; + } virtual_alloc; + struct + { + enum apc_type type; + unsigned int status; + void *addr; + unsigned long size; + } virtual_free; + struct + { + enum apc_type type; + unsigned int status; + void *base; + void *alloc_base; + unsigned long size; + unsigned int state; + unsigned int prot; + unsigned int alloc_prot; + unsigned int alloc_type; + } virtual_query; + struct + { + enum apc_type type; + unsigned int status; + void *addr; + unsigned long size; + unsigned int prot; + } virtual_protect; + struct + { + enum apc_type type; + unsigned int status; + const void *addr; + unsigned long size; + } virtual_flush; + struct + { + enum apc_type type; + unsigned int status; + void *addr; + unsigned long size; + } virtual_lock; + struct + { + enum apc_type type; + unsigned int status; + void *addr; + unsigned long size; + } virtual_unlock; + struct + { + enum apc_type type; + unsigned int status; + void *addr; + unsigned long size; + } map_view; + struct + { + enum apc_type type; + unsigned int status; + } unmap_view; + struct + { + enum apc_type type; + unsigned int status; + thread_id_t tid; + obj_handle_t handle; + } create_thread; +} apc_result_t; + + + + + +struct new_process_request +{ + struct request_header __header; + int inherit_all; + unsigned int create_flags; + int socket_fd; + obj_handle_t exe_file; + obj_handle_t hstdin; + obj_handle_t hstdout; + obj_handle_t hstderr; + unsigned int process_access; + unsigned int process_attr; + unsigned int thread_access; + unsigned int thread_attr; + /* VARARG(info,startup_info); */ + /* VARARG(env,unicode_str); */ +}; +struct new_process_reply +{ + struct reply_header __header; + obj_handle_t info; + process_id_t pid; + obj_handle_t phandle; + thread_id_t tid; + obj_handle_t thandle; +}; + + + +struct get_new_process_info_request +{ + struct request_header __header; + obj_handle_t info; +}; +struct get_new_process_info_reply +{ + struct reply_header __header; + int success; + int exit_code; +}; + + + +struct new_thread_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + int suspend; + int request_fd; +#ifdef UNIFIED_KERNEL + int tid; +#endif +}; +struct new_thread_reply +{ + struct reply_header __header; + thread_id_t tid; + obj_handle_t handle; +}; + + + +struct get_startup_info_request +{ + struct request_header __header; +}; +struct get_startup_info_reply +{ + struct reply_header __header; + obj_handle_t exe_file; + obj_handle_t hstdin; + obj_handle_t hstdout; + obj_handle_t hstderr; + /* VARARG(info,startup_info); */ + /* VARARG(env,unicode_str); */ +}; + + + +struct init_process_done_request +{ + struct request_header __header; + void* module; + void* entry; + int gui; +}; +struct init_process_done_reply +{ + struct reply_header __header; +}; + + + +struct init_thread_request +{ + struct request_header __header; + int unix_pid; + int unix_tid; + int debug_level; + void* teb; + void* peb; + void* entry; + void* ldt_copy; + int reply_fd; + int wait_fd; +#ifdef UNIFIED_KERNEL + int pid; + int tid; +#endif +}; +struct init_thread_reply +{ + struct reply_header __header; + process_id_t pid; + thread_id_t tid; + data_size_t info_size; + timeout_t server_start; + int version; +}; + + + +struct terminate_process_request +{ + struct request_header __header; + obj_handle_t handle; + int exit_code; +}; +struct terminate_process_reply +{ + struct reply_header __header; + int self; +}; + + + +struct terminate_thread_request +{ + struct request_header __header; + obj_handle_t handle; + int exit_code; +}; +struct terminate_thread_reply +{ + struct reply_header __header; + int self; + int last; +}; + + + +struct get_process_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_process_info_reply +{ + struct reply_header __header; + process_id_t pid; + process_id_t ppid; + int exit_code; + int priority; + unsigned int affinity; + void* peb; + timeout_t start_time; + timeout_t end_time; +}; + + + +struct set_process_info_request +{ + struct request_header __header; + obj_handle_t handle; + int mask; + int priority; + unsigned int affinity; +}; +struct set_process_info_reply +{ + struct reply_header __header; +}; +#define SET_PROCESS_INFO_PRIORITY 0x01 +#define SET_PROCESS_INFO_AFFINITY 0x02 + + + +struct get_thread_info_request +{ + struct request_header __header; + obj_handle_t handle; + thread_id_t tid_in; +}; +struct get_thread_info_reply +{ + struct reply_header __header; + process_id_t pid; + thread_id_t tid; + void* teb; + int exit_code; + int priority; + unsigned int affinity; + timeout_t creation_time; + timeout_t exit_time; + int last; +}; + + + +struct set_thread_info_request +{ + struct request_header __header; + obj_handle_t handle; + int mask; + int priority; + unsigned int affinity; + obj_handle_t token; +}; +struct set_thread_info_reply +{ + struct reply_header __header; +}; +#define SET_THREAD_INFO_PRIORITY 0x01 +#define SET_THREAD_INFO_AFFINITY 0x02 +#define SET_THREAD_INFO_TOKEN 0x04 + + + +struct get_dll_info_request +{ + struct request_header __header; + obj_handle_t handle; + void* base_address; +}; +struct get_dll_info_reply +{ + struct reply_header __header; + size_t size; + void* entry_point; + data_size_t filename_len; + /* VARARG(filename,unicode_str); */ +}; + + + +struct suspend_thread_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct suspend_thread_reply +{ + struct reply_header __header; + int count; +}; + + + +struct resume_thread_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct resume_thread_reply +{ + struct reply_header __header; + int count; +}; + + + +struct load_dll_request +{ + struct request_header __header; + obj_handle_t handle; + void* base; + size_t size; + int dbg_offset; + int dbg_size; + void* name; + /* VARARG(filename,unicode_str); */ +}; +struct load_dll_reply +{ + struct reply_header __header; +}; + + + +struct unload_dll_request +{ + struct request_header __header; + void* base; +}; +struct unload_dll_reply +{ + struct reply_header __header; +}; + + + +struct queue_apc_request +{ + struct request_header __header; + obj_handle_t thread; + obj_handle_t process; + apc_call_t call; +}; +struct queue_apc_reply +{ + struct reply_header __header; + obj_handle_t handle; + int self; +}; + + + +struct get_apc_result_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_apc_result_reply +{ + struct reply_header __header; + apc_result_t result; +}; + + + +struct close_handle_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct close_handle_reply +{ + struct reply_header __header; +}; + + + +struct set_handle_info_request +{ + struct request_header __header; + obj_handle_t handle; + int flags; + int mask; +}; +struct set_handle_info_reply +{ + struct reply_header __header; + int old_flags; +}; + + + +struct dup_handle_request +{ + struct request_header __header; + obj_handle_t src_process; + obj_handle_t src_handle; + obj_handle_t dst_process; + unsigned int access; + unsigned int attributes; + unsigned int options; +}; +struct dup_handle_reply +{ + struct reply_header __header; + obj_handle_t handle; + int self; + int closed; +}; +#define DUP_HANDLE_CLOSE_SOURCE DUPLICATE_CLOSE_SOURCE +#define DUP_HANDLE_SAME_ACCESS DUPLICATE_SAME_ACCESS +#define DUP_HANDLE_MAKE_GLOBAL 0x80000000 + + + +struct open_process_request +{ + struct request_header __header; + process_id_t pid; + unsigned int access; + unsigned int attributes; +}; +struct open_process_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_thread_request +{ + struct request_header __header; + thread_id_t tid; + unsigned int access; + unsigned int attributes; +}; +struct open_thread_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct select_request +{ + struct request_header __header; + int flags; + void* cookie; + obj_handle_t signal; + obj_handle_t prev_apc; + timeout_t timeout; + /* VARARG(result,apc_result); */ + /* VARARG(handles,handles); */ +}; +struct select_reply +{ + struct reply_header __header; + obj_handle_t apc_handle; + timeout_t timeout; + apc_call_t call; +}; +#define SELECT_ALL 1 +#define SELECT_ALERTABLE 2 +#define SELECT_INTERRUPTIBLE 4 + + + +struct create_event_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + int manual_reset; + int initial_state; + /* VARARG(objattr,object_attributes); */ +}; +struct create_event_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + +struct event_op_request +{ + struct request_header __header; + obj_handle_t handle; + int op; +}; +struct event_op_reply +{ + struct reply_header __header; +}; +enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT }; + + + +struct open_event_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(name,unicode_str); */ +}; +struct open_event_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct create_mutex_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + int owned; + /* VARARG(objattr,object_attributes); */ +}; +struct create_mutex_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct release_mutex_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct release_mutex_reply +{ + struct reply_header __header; + unsigned int prev_count; +}; + + + +struct open_mutex_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(name,unicode_str); */ +}; +struct open_mutex_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct create_semaphore_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + unsigned int initial; + unsigned int max; + /* VARARG(objattr,object_attributes); */ +}; +struct create_semaphore_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct release_semaphore_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int count; +}; +struct release_semaphore_reply +{ + struct reply_header __header; + unsigned int prev_count; +}; + + + +struct open_semaphore_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(name,unicode_str); */ +}; +struct open_semaphore_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct create_file_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + unsigned int sharing; + int create; + unsigned int options; + unsigned int attrs; + /* VARARG(objattr,object_attributes); */ + /* VARARG(filename,string); */ +}; +struct create_file_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_file_object_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + unsigned int sharing; + unsigned int options; + /* VARARG(filename,unicode_str); */ +}; +struct open_file_object_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct alloc_file_handle_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + int fd; +}; +struct alloc_file_handle_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct get_handle_fd_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_handle_fd_reply +{ + struct reply_header __header; + int type; + int removable; + unsigned int access; + unsigned int options; + int fd; /* D.M. added for unified kernel */ +}; +enum server_fd_type +{ + FD_TYPE_INVALID, + FD_TYPE_FILE, + FD_TYPE_DIR, + FD_TYPE_SOCKET, + FD_TYPE_SERIAL, + FD_TYPE_PIPE, + FD_TYPE_MAILSLOT, + FD_TYPE_CHAR, + FD_TYPE_DEVICE, + FD_TYPE_NB_TYPES +}; + + + +struct flush_file_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct flush_file_reply +{ + struct reply_header __header; + obj_handle_t event; +}; + + + +struct lock_file_request +{ + struct request_header __header; + obj_handle_t handle; + file_pos_t offset; + file_pos_t count; + int shared; + int wait; +}; +struct lock_file_reply +{ + struct reply_header __header; + obj_handle_t handle; + int overlapped; +}; + + + +struct unlock_file_request +{ + struct request_header __header; + obj_handle_t handle; + file_pos_t offset; + file_pos_t count; +}; +struct unlock_file_reply +{ + struct reply_header __header; +}; + + + +struct create_socket_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + int family; + int type; + int protocol; + unsigned int flags; +}; +struct create_socket_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct accept_socket_request +{ + struct request_header __header; + obj_handle_t lhandle; + unsigned int access; + unsigned int attributes; +}; +struct accept_socket_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct set_socket_event_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int mask; + obj_handle_t event; + user_handle_t window; + unsigned int msg; +}; +struct set_socket_event_reply +{ + struct reply_header __header; +}; + + + +struct get_socket_event_request +{ + struct request_header __header; + obj_handle_t handle; + int service; + obj_handle_t c_event; +}; +struct get_socket_event_reply +{ + struct reply_header __header; + unsigned int mask; + unsigned int pmask; + unsigned int state; + /* VARARG(errors,ints); */ +}; + + + +struct enable_socket_event_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int mask; + unsigned int sstate; + unsigned int cstate; +}; +struct enable_socket_event_reply +{ + struct reply_header __header; +}; + +struct set_socket_deferred_request +{ + struct request_header __header; + obj_handle_t handle; + obj_handle_t deferred; +}; +struct set_socket_deferred_reply +{ + struct reply_header __header; +}; + + +struct alloc_console_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + process_id_t pid; +}; +struct alloc_console_reply +{ + struct reply_header __header; + obj_handle_t handle_in; + obj_handle_t event; +}; + + + +struct free_console_request +{ + struct request_header __header; +}; +struct free_console_reply +{ + struct reply_header __header; +}; + + +#define CONSOLE_RENDERER_NONE_EVENT 0x00 +#define CONSOLE_RENDERER_TITLE_EVENT 0x01 +#define CONSOLE_RENDERER_ACTIVE_SB_EVENT 0x02 +#define CONSOLE_RENDERER_SB_RESIZE_EVENT 0x03 +#define CONSOLE_RENDERER_UPDATE_EVENT 0x04 +#define CONSOLE_RENDERER_CURSOR_POS_EVENT 0x05 +#define CONSOLE_RENDERER_CURSOR_GEOM_EVENT 0x06 +#define CONSOLE_RENDERER_DISPLAY_EVENT 0x07 +#define CONSOLE_RENDERER_EXIT_EVENT 0x08 +struct console_renderer_event +{ + short event; + union + { + struct update + { + short top; + short bottom; + } update; + struct resize + { + short width; + short height; + } resize; + struct cursor_pos + { + short x; + short y; + } cursor_pos; + struct cursor_geom + { + short visible; + short size; + } cursor_geom; + struct display + { + short left; + short top; + short width; + short height; + } display; + } u; +}; + + +struct get_console_renderer_events_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_console_renderer_events_reply +{ + struct reply_header __header; + /* VARARG(data,bytes); */ +}; + + + +struct open_console_request +{ + struct request_header __header; + obj_handle_t from; + + unsigned int access; + unsigned int attributes; + int share; +}; +struct open_console_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct get_console_wait_event_request +{ + struct request_header __header; +}; +struct get_console_wait_event_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + +struct get_console_mode_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_console_mode_reply +{ + struct reply_header __header; + int mode; +}; + + + +struct set_console_mode_request +{ + struct request_header __header; + obj_handle_t handle; + int mode; +}; +struct set_console_mode_reply +{ + struct reply_header __header; +}; + + + +struct set_console_input_info_request +{ + struct request_header __header; + obj_handle_t handle; + int mask; + obj_handle_t active_sb; + int history_mode; + int history_size; + int edition_mode; + int input_cp; + int output_cp; + user_handle_t win; + /* VARARG(title,unicode_str); */ +}; +struct set_console_input_info_reply +{ + struct reply_header __header; +}; +#define SET_CONSOLE_INPUT_INFO_ACTIVE_SB 0x01 +#define SET_CONSOLE_INPUT_INFO_TITLE 0x02 +#define SET_CONSOLE_INPUT_INFO_HISTORY_MODE 0x04 +#define SET_CONSOLE_INPUT_INFO_HISTORY_SIZE 0x08 +#define SET_CONSOLE_INPUT_INFO_EDITION_MODE 0x10 +#define SET_CONSOLE_INPUT_INFO_INPUT_CODEPAGE 0x20 +#define SET_CONSOLE_INPUT_INFO_OUTPUT_CODEPAGE 0x40 +#define SET_CONSOLE_INPUT_INFO_WIN 0x80 + + + +struct get_console_input_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_console_input_info_reply +{ + struct reply_header __header; + int history_mode; + int history_size; + int history_index; + int edition_mode; + int input_cp; + int output_cp; + user_handle_t win; + /* VARARG(title,unicode_str); */ +}; + + + +struct append_console_input_history_request +{ + struct request_header __header; + obj_handle_t handle; + /* VARARG(line,unicode_str); */ +}; +struct append_console_input_history_reply +{ + struct reply_header __header; +}; + + + +struct get_console_input_history_request +{ + struct request_header __header; + obj_handle_t handle; + int index; +}; +struct get_console_input_history_reply +{ + struct reply_header __header; + int total; + /* VARARG(line,unicode_str); */ +}; + + + +struct create_console_output_request +{ + struct request_header __header; + obj_handle_t handle_in; + unsigned int access; + unsigned int attributes; + unsigned int share; +}; +struct create_console_output_reply +{ + struct reply_header __header; + obj_handle_t handle_out; +}; + + + +struct set_console_output_info_request +{ + struct request_header __header; + obj_handle_t handle; + int mask; + short int cursor_size; + short int cursor_visible; + short int cursor_x; + short int cursor_y; + short int width; + short int height; + short int attr; + short int win_left; + short int win_top; + short int win_right; + short int win_bottom; + short int max_width; + short int max_height; +}; +struct set_console_output_info_reply +{ + struct reply_header __header; +}; +#define SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM 0x01 +#define SET_CONSOLE_OUTPUT_INFO_CURSOR_POS 0x02 +#define SET_CONSOLE_OUTPUT_INFO_SIZE 0x04 +#define SET_CONSOLE_OUTPUT_INFO_ATTR 0x08 +#define SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW 0x10 +#define SET_CONSOLE_OUTPUT_INFO_MAX_SIZE 0x20 + + + +struct get_console_output_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_console_output_info_reply +{ + struct reply_header __header; + short int cursor_size; + short int cursor_visible; + short int cursor_x; + short int cursor_y; + short int width; + short int height; + short int attr; + short int win_left; + short int win_top; + short int win_right; + short int win_bottom; + short int max_width; + short int max_height; +}; + + +struct write_console_input_request +{ + struct request_header __header; + obj_handle_t handle; + /* VARARG(rec,input_records); */ +}; +struct write_console_input_reply +{ + struct reply_header __header; + int written; +}; + + + +struct read_console_input_request +{ + struct request_header __header; + obj_handle_t handle; + int flush; +}; +struct read_console_input_reply +{ + struct reply_header __header; + int read; + /* VARARG(rec,input_records); */ +}; + + + +struct write_console_output_request +{ + struct request_header __header; + obj_handle_t handle; + int x; + int y; + int mode; + int wrap; + /* VARARG(data,bytes); */ +}; +struct write_console_output_reply +{ + struct reply_header __header; + int written; + int width; + int height; +}; +enum char_info_mode +{ + CHAR_INFO_MODE_TEXT, + CHAR_INFO_MODE_ATTR, + CHAR_INFO_MODE_TEXTATTR, + CHAR_INFO_MODE_TEXTSTDATTR +}; + + + +struct fill_console_output_request +{ + struct request_header __header; + obj_handle_t handle; + int x; + int y; + int mode; + int count; + int wrap; + char_info_t data; +}; +struct fill_console_output_reply +{ + struct reply_header __header; + int written; +}; + + + +struct read_console_output_request +{ + struct request_header __header; + obj_handle_t handle; + int x; + int y; + int mode; + int wrap; +}; +struct read_console_output_reply +{ + struct reply_header __header; + int width; + int height; + /* VARARG(data,bytes); */ +}; + + + +struct move_console_output_request +{ + struct request_header __header; + obj_handle_t handle; + short int x_src; + short int y_src; + short int x_dst; + short int y_dst; + short int w; + short int h; +}; +struct move_console_output_reply +{ + struct reply_header __header; +}; + + + +struct send_console_signal_request +{ + struct request_header __header; + int signal; + process_id_t group_id; +}; +struct send_console_signal_reply +{ + struct reply_header __header; +}; + + + +struct read_directory_changes_request +{ + struct request_header __header; + unsigned int filter; + obj_handle_t handle; + int subtree; + int want_data; + async_data_t async; +}; +struct read_directory_changes_reply +{ + struct reply_header __header; +}; + + +struct read_change_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct read_change_reply +{ + struct reply_header __header; + int action; + /* VARARG(name,string); */ +}; + + + +struct create_mapping_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + file_pos_t size; + int protect; + obj_handle_t file_handle; + /* VARARG(objattr,object_attributes); */ +}; +struct create_mapping_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + +#define VPROT_READ 0x01 +#define VPROT_WRITE 0x02 +#define VPROT_EXEC 0x04 +#define VPROT_WRITECOPY 0x08 +#define VPROT_GUARD 0x10 +#define VPROT_NOCACHE 0x20 +#define VPROT_COMMITTED 0x40 +#define VPROT_IMAGE 0x80 + + + +struct open_mapping_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(name,unicode_str); */ +}; +struct open_mapping_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct get_mapping_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_mapping_info_reply +{ + struct reply_header __header; + file_pos_t size; + int protect; + int header_size; + void* base; + obj_handle_t mapping; + obj_handle_t shared_file; +}; + + +#define SNAP_HEAPLIST 0x00000001 +#define SNAP_PROCESS 0x00000002 +#define SNAP_THREAD 0x00000004 +#define SNAP_MODULE 0x00000008 + +struct create_snapshot_request +{ + struct request_header __header; + unsigned int attributes; + int flags; + process_id_t pid; +}; +struct create_snapshot_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct next_process_request +{ + struct request_header __header; + obj_handle_t handle; + int reset; +}; +struct next_process_reply +{ + struct reply_header __header; + int count; + process_id_t pid; + process_id_t ppid; + void* heap; + void* module; + int threads; + int priority; + int handles; + /* VARARG(filename,unicode_str); */ +}; + + + +struct next_thread_request +{ + struct request_header __header; + obj_handle_t handle; + int reset; +}; +struct next_thread_reply +{ + struct reply_header __header; + int count; + process_id_t pid; + thread_id_t tid; + int base_pri; + int delta_pri; +}; + + + +struct next_module_request +{ + struct request_header __header; + obj_handle_t handle; + int reset; +}; +struct next_module_reply +{ + struct reply_header __header; + process_id_t pid; + void* base; + size_t size; + /* VARARG(filename,unicode_str); */ +}; + + + +struct wait_debug_event_request +{ + struct request_header __header; + int get_handle; +}; +struct wait_debug_event_reply +{ + struct reply_header __header; + process_id_t pid; + thread_id_t tid; + obj_handle_t wait; + /* VARARG(event,debug_event); */ +}; + + + +struct queue_exception_event_request +{ + struct request_header __header; + int first; + /* VARARG(record,exc_event); */ +}; +struct queue_exception_event_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct get_exception_status_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_exception_status_reply +{ + struct reply_header __header; + /* VARARG(context,context); */ +}; + + + +struct output_debug_string_request +{ + struct request_header __header; + void* string; + int unicode; + int length; +}; +struct output_debug_string_reply +{ + struct reply_header __header; +}; + + + +struct continue_debug_event_request +{ + struct request_header __header; + process_id_t pid; + thread_id_t tid; + int status; +}; +struct continue_debug_event_reply +{ + struct reply_header __header; +}; + + + +struct debug_process_request +{ + struct request_header __header; + process_id_t pid; + int attach; +}; +struct debug_process_reply +{ + struct reply_header __header; +}; + + + +struct debug_break_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct debug_break_reply +{ + struct reply_header __header; + int self; +}; + + + +struct set_debugger_kill_on_exit_request +{ + struct request_header __header; + int kill_on_exit; +}; +struct set_debugger_kill_on_exit_reply +{ + struct reply_header __header; +}; + + + +struct read_process_memory_request +{ + struct request_header __header; + obj_handle_t handle; + void* addr; +}; +struct read_process_memory_reply +{ + struct reply_header __header; + /* VARARG(data,bytes); */ +}; + + + +struct write_process_memory_request +{ + struct request_header __header; + obj_handle_t handle; + void* addr; + /* VARARG(data,bytes); */ +}; +struct write_process_memory_reply +{ + struct reply_header __header; +}; + + + +struct create_key_request +{ + struct request_header __header; + obj_handle_t parent; + unsigned int access; + unsigned int attributes; + unsigned int options; + time_t modif; + data_size_t namelen; + /* VARARG(name,unicode_str,namelen); */ + /* VARARG(class,unicode_str); */ +}; +struct create_key_reply +{ + struct reply_header __header; + obj_handle_t hkey; + int created; +}; + + +struct open_key_request +{ + struct request_header __header; + obj_handle_t parent; + unsigned int access; + unsigned int attributes; + /* VARARG(name,unicode_str); */ +}; +struct open_key_reply +{ + struct reply_header __header; + obj_handle_t hkey; +}; + + + +struct delete_key_request +{ + struct request_header __header; + obj_handle_t hkey; +}; +struct delete_key_reply +{ + struct reply_header __header; +}; + + + +struct flush_key_request +{ + struct request_header __header; + obj_handle_t hkey; +}; +struct flush_key_reply +{ + struct reply_header __header; +}; + + + +struct enum_key_request +{ + struct request_header __header; + obj_handle_t hkey; + int index; + int info_class; +}; +struct enum_key_reply +{ + struct reply_header __header; + int subkeys; + int max_subkey; + int max_class; + int values; + int max_value; + int max_data; + time_t modif; + data_size_t total; + data_size_t namelen; + /* VARARG(name,unicode_str,namelen); */ + /* VARARG(class,unicode_str); */ +}; + + + +struct set_key_value_request +{ + struct request_header __header; + obj_handle_t hkey; + int type; + data_size_t namelen; + /* VARARG(name,unicode_str,namelen); */ + /* VARARG(data,bytes); */ +}; +struct set_key_value_reply +{ + struct reply_header __header; +}; + + + +struct get_key_value_request +{ + struct request_header __header; + obj_handle_t hkey; + /* VARARG(name,unicode_str); */ +}; +struct get_key_value_reply +{ + struct reply_header __header; + int type; + data_size_t total; + /* VARARG(data,bytes); */ +}; + + + +struct enum_key_value_request +{ + struct request_header __header; + obj_handle_t hkey; + int index; + int info_class; +}; +struct enum_key_value_reply +{ + struct reply_header __header; + int type; + data_size_t total; + data_size_t namelen; + /* VARARG(name,unicode_str,namelen); */ + /* VARARG(data,bytes); */ +}; + + + +struct delete_key_value_request +{ + struct request_header __header; + obj_handle_t hkey; + /* VARARG(name,unicode_str); */ +}; +struct delete_key_value_reply +{ + struct reply_header __header; +}; + + + +struct load_registry_request +{ + struct request_header __header; + obj_handle_t hkey; + obj_handle_t file; + /* VARARG(name,unicode_str); */ +}; +struct load_registry_reply +{ + struct reply_header __header; +}; + + + +struct unload_registry_request +{ + struct request_header __header; + obj_handle_t hkey; +}; +struct unload_registry_reply +{ + struct reply_header __header; +}; + + + +struct save_registry_request +{ + struct request_header __header; + obj_handle_t hkey; + obj_handle_t file; +}; +struct save_registry_reply +{ + struct reply_header __header; +}; + + + +struct set_registry_notification_request +{ + struct request_header __header; + obj_handle_t hkey; + obj_handle_t event; + int subtree; + unsigned int filter; +}; +struct set_registry_notification_reply +{ + struct reply_header __header; +}; + + + +struct create_timer_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + int manual; + /* VARARG(name,unicode_str); */ +}; +struct create_timer_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_timer_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(name,unicode_str); */ +}; +struct open_timer_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + +struct set_timer_request +{ + struct request_header __header; + obj_handle_t handle; + timeout_t expire; + int period; + void* callback; + void* arg; +}; +struct set_timer_reply +{ + struct reply_header __header; + int signaled; +}; + + +struct cancel_timer_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct cancel_timer_reply +{ + struct reply_header __header; + int signaled; +}; + + +struct get_timer_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_timer_info_reply +{ + struct reply_header __header; + timeout_t when; + int signaled; +}; + + + +struct get_thread_context_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int flags; + int suspend; +}; +struct get_thread_context_reply +{ + struct reply_header __header; + int self; + /* VARARG(context,context); */ +}; + + + +struct set_thread_context_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int flags; + int suspend; + /* VARARG(context,context); */ +}; +struct set_thread_context_reply +{ + struct reply_header __header; + int self; +}; + + + +struct get_selector_entry_request +{ + struct request_header __header; + obj_handle_t handle; + int entry; +}; +struct get_selector_entry_reply +{ + struct reply_header __header; + unsigned int base; + unsigned int limit; + unsigned char flags; +}; + + + +struct add_atom_request +{ + struct request_header __header; + obj_handle_t table; + /* VARARG(name,unicode_str); */ +}; +struct add_atom_reply +{ + struct reply_header __header; + atom_t atom; +}; + + + +struct delete_atom_request +{ + struct request_header __header; + obj_handle_t table; + atom_t atom; +}; +struct delete_atom_reply +{ + struct reply_header __header; +}; + + + +struct find_atom_request +{ + struct request_header __header; + obj_handle_t table; + /* VARARG(name,unicode_str); */ +}; +struct find_atom_reply +{ + struct reply_header __header; + atom_t atom; +}; + + + +struct get_atom_information_request +{ + struct request_header __header; + obj_handle_t table; + atom_t atom; +}; +struct get_atom_information_reply +{ + struct reply_header __header; + int count; + int pinned; + data_size_t total; + /* VARARG(name,unicode_str); */ +}; + + + +struct set_atom_information_request +{ + struct request_header __header; + obj_handle_t table; + atom_t atom; + int pinned; +}; +struct set_atom_information_reply +{ + struct reply_header __header; +}; + + + +struct empty_atom_table_request +{ + struct request_header __header; + obj_handle_t table; + int if_pinned; +}; +struct empty_atom_table_reply +{ + struct reply_header __header; +}; + + + +struct init_atom_table_request +{ + struct request_header __header; + int entries; +}; +struct init_atom_table_reply +{ + struct reply_header __header; + obj_handle_t table; +}; + + + +struct get_msg_queue_request +{ + struct request_header __header; +}; +struct get_msg_queue_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct set_queue_fd_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct set_queue_fd_reply +{ + struct reply_header __header; +}; + + + +struct set_queue_mask_request +{ + struct request_header __header; + unsigned int wake_mask; + unsigned int changed_mask; + int skip_wait; +}; +struct set_queue_mask_reply +{ + struct reply_header __header; + unsigned int wake_bits; + unsigned int changed_bits; +}; + + + +struct get_queue_status_request +{ + struct request_header __header; + int clear; +}; +struct get_queue_status_reply +{ + struct reply_header __header; + unsigned int wake_bits; + unsigned int changed_bits; +}; + + + +struct get_process_idle_event_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_process_idle_event_reply +{ + struct reply_header __header; + obj_handle_t event; +}; + + + +struct send_message_request +{ + struct request_header __header; + thread_id_t id; + int type; + int flags; + user_handle_t win; + unsigned int msg; + unsigned long wparam; + unsigned long lparam; + timeout_t timeout; + /* VARARG(data,message_data); */ +}; +struct send_message_reply +{ + struct reply_header __header; +}; + +struct post_quit_message_request +{ + struct request_header __header; + int exit_code; +}; +struct post_quit_message_reply +{ + struct reply_header __header; +}; + +enum message_type +{ + MSG_ASCII, + MSG_UNICODE, + MSG_NOTIFY, + MSG_CALLBACK, + MSG_CALLBACK_RESULT, + MSG_OTHER_PROCESS, + MSG_POSTED, + MSG_HARDWARE, + MSG_WINEVENT +}; +#define SEND_MSG_ABORT_IF_HUNG 0x01 + + + +struct send_hardware_message_request +{ + struct request_header __header; + thread_id_t id; + user_handle_t win; + unsigned int msg; + unsigned int time; + unsigned long wparam; + unsigned long lparam; + unsigned long info; + int x; + int y; +}; +struct send_hardware_message_reply +{ + struct reply_header __header; +}; + + + +struct get_message_request +{ + struct request_header __header; + unsigned int flags; + user_handle_t get_win; + unsigned int get_first; + unsigned int get_last; + unsigned int hw_id; + unsigned int wake_mask; + unsigned int changed_mask; +}; +struct get_message_reply +{ + struct reply_header __header; + user_handle_t win; + int type; + unsigned int msg; + unsigned long wparam; + unsigned long lparam; + unsigned long info; + int x; + int y; + unsigned int time; + unsigned int hw_id; + unsigned int active_hooks; + data_size_t total; + /* VARARG(data,message_data); */ +}; + + + +struct reply_message_request +{ + struct request_header __header; + unsigned long result; + int remove; + /* VARARG(data,bytes); */ +}; +struct reply_message_reply +{ + struct reply_header __header; +}; + + + +struct accept_hardware_message_request +{ + struct request_header __header; + unsigned int hw_id; + int remove; + user_handle_t new_win; +}; +struct accept_hardware_message_reply +{ + struct reply_header __header; +}; + + + +struct get_message_reply_request +{ + struct request_header __header; + int cancel; +}; +struct get_message_reply_reply +{ + struct reply_header __header; + unsigned long result; + /* VARARG(data,bytes); */ +}; + + + +struct set_win_timer_request +{ + struct request_header __header; + user_handle_t win; + unsigned int msg; + unsigned int rate; + unsigned long id; + unsigned long lparam; +}; +struct set_win_timer_reply +{ + struct reply_header __header; + unsigned long id; +}; + + + +struct kill_win_timer_request +{ + struct request_header __header; + user_handle_t win; + unsigned int msg; + unsigned long id; +}; +struct kill_win_timer_reply +{ + struct reply_header __header; +}; + + + +struct is_window_hung_request +{ + struct request_header __header; + user_handle_t win; +}; +struct is_window_hung_reply +{ + struct reply_header __header; + int is_hung; +}; + + + +struct get_serial_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_serial_info_reply +{ + struct reply_header __header; + unsigned int readinterval; + unsigned int readconst; + unsigned int readmult; + unsigned int writeconst; + unsigned int writemult; + unsigned int eventmask; +}; + + + +struct set_serial_info_request +{ + struct request_header __header; + obj_handle_t handle; + int flags; + unsigned int readinterval; + unsigned int readconst; + unsigned int readmult; + unsigned int writeconst; + unsigned int writemult; + unsigned int eventmask; +}; +struct set_serial_info_reply +{ + struct reply_header __header; +}; +#define SERIALINFO_SET_TIMEOUTS 0x01 +#define SERIALINFO_SET_MASK 0x02 + + + +struct register_async_request +{ + struct request_header __header; + obj_handle_t handle; + int type; + int count; + async_data_t async; +}; +struct register_async_reply +{ + struct reply_header __header; +}; +#define ASYNC_TYPE_READ 0x01 +#define ASYNC_TYPE_WRITE 0x02 +#define ASYNC_TYPE_WAIT 0x03 + + + +struct cancel_async_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct cancel_async_reply +{ + struct reply_header __header; +}; + + + +struct ioctl_request +{ + struct request_header __header; + obj_handle_t handle; + ioctl_code_t code; + async_data_t async; + /* VARARG(in_data,bytes); */ +}; +struct ioctl_reply +{ + struct reply_header __header; + obj_handle_t wait; + unsigned int options; + /* VARARG(out_data,bytes); */ +}; + + + +struct get_ioctl_result_request +{ + struct request_header __header; + obj_handle_t handle; + void* user_arg; +}; +struct get_ioctl_result_reply +{ + struct reply_header __header; + /* VARARG(out_data,bytes); */ +}; + + + +struct create_named_pipe_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + unsigned int options; + unsigned int flags; + unsigned int maxinstances; + unsigned int outsize; + unsigned int insize; + timeout_t timeout; + /* VARARG(name,unicode_str); */ +}; +struct create_named_pipe_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + +#define NAMED_PIPE_MESSAGE_STREAM_WRITE 0x0001 +#define NAMED_PIPE_MESSAGE_STREAM_READ 0x0002 +#define NAMED_PIPE_NONBLOCKING_MODE 0x0004 +#define NAMED_PIPE_SERVER_END 0x8000 + + +struct get_named_pipe_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_named_pipe_info_reply +{ + struct reply_header __header; + unsigned int flags; + unsigned int maxinstances; + unsigned int instances; + unsigned int outsize; + unsigned int insize; +}; + + + +struct create_window_request +{ + struct request_header __header; + user_handle_t parent; + user_handle_t owner; + atom_t atom; + void* instance; + /* VARARG(class,unicode_str); */ +}; +struct create_window_reply +{ + struct reply_header __header; + user_handle_t handle; + user_handle_t parent; + user_handle_t owner; + int extra; + void* class_ptr; +}; + + + +struct destroy_window_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct destroy_window_reply +{ + struct reply_header __header; +}; + + + +struct get_desktop_window_request +{ + struct request_header __header; + int force; +}; +struct get_desktop_window_reply +{ + struct reply_header __header; + user_handle_t handle; +}; + + + +struct set_window_owner_request +{ + struct request_header __header; + user_handle_t handle; + user_handle_t owner; +}; +struct set_window_owner_reply +{ + struct reply_header __header; + user_handle_t full_owner; + user_handle_t prev_owner; +}; + + + +struct get_window_info_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_window_info_reply +{ + struct reply_header __header; + user_handle_t full_handle; + user_handle_t last_active; + process_id_t pid; + thread_id_t tid; + atom_t atom; + int is_unicode; +}; + + + +struct set_window_info_request +{ + struct request_header __header; + unsigned int flags; + user_handle_t handle; + unsigned int style; + unsigned int ex_style; + unsigned int id; + int is_unicode; + void* instance; + unsigned long user_data; + int extra_offset; + data_size_t extra_size; + unsigned long extra_value; +}; +struct set_window_info_reply +{ + struct reply_header __header; + unsigned int old_style; + unsigned int old_ex_style; + unsigned int old_id; + void* old_instance; + unsigned long old_user_data; + unsigned long old_extra_value; +}; +#define SET_WIN_STYLE 0x01 +#define SET_WIN_EXSTYLE 0x02 +#define SET_WIN_ID 0x04 +#define SET_WIN_INSTANCE 0x08 +#define SET_WIN_USERDATA 0x10 +#define SET_WIN_EXTRA 0x20 +#define SET_WIN_UNICODE 0x40 + + + +struct set_parent_request +{ + struct request_header __header; + user_handle_t handle; + user_handle_t parent; +}; +struct set_parent_reply +{ + struct reply_header __header; + user_handle_t old_parent; + user_handle_t full_parent; +}; + + + +struct get_window_parents_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_window_parents_reply +{ + struct reply_header __header; + int count; + /* VARARG(parents,user_handles); */ +}; + + + +struct get_window_children_request +{ + struct request_header __header; + obj_handle_t desktop; + user_handle_t parent; + atom_t atom; + thread_id_t tid; + /* VARARG(class,unicode_str); */ +}; +struct get_window_children_reply +{ + struct reply_header __header; + int count; + /* VARARG(children,user_handles); */ +}; + + + +struct get_window_children_from_point_request +{ + struct request_header __header; + user_handle_t parent; + int x; + int y; +}; +struct get_window_children_from_point_reply +{ + struct reply_header __header; + int count; + /* VARARG(children,user_handles); */ +}; + + + +struct get_window_tree_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_window_tree_reply +{ + struct reply_header __header; + user_handle_t parent; + user_handle_t owner; + user_handle_t next_sibling; + user_handle_t prev_sibling; + user_handle_t first_sibling; + user_handle_t last_sibling; + user_handle_t first_child; + user_handle_t last_child; +}; + + +struct set_window_pos_request +{ + struct request_header __header; + unsigned int flags; + user_handle_t handle; + user_handle_t previous; + rectangle_t window; + rectangle_t client; + /* VARARG(valid,rectangles); */ +}; +struct set_window_pos_reply +{ + struct reply_header __header; + unsigned int new_style; + unsigned int new_ex_style; + rectangle_t visible; +}; + + + +struct set_window_visible_rect_request +{ + struct request_header __header; + unsigned int flags; + user_handle_t handle; + rectangle_t visible; +}; +struct set_window_visible_rect_reply +{ + struct reply_header __header; +}; + + + +struct get_window_rectangles_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_window_rectangles_reply +{ + struct reply_header __header; + rectangle_t window; + rectangle_t visible; + rectangle_t client; +}; + + + +struct get_window_text_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct get_window_text_reply +{ + struct reply_header __header; + /* VARARG(text,unicode_str); */ +}; + + + +struct set_window_text_request +{ + struct request_header __header; + user_handle_t handle; + /* VARARG(text,unicode_str); */ +}; +struct set_window_text_reply +{ + struct reply_header __header; +}; + + + +struct get_windows_offset_request +{ + struct request_header __header; + user_handle_t from; + user_handle_t to; +}; +struct get_windows_offset_reply +{ + struct reply_header __header; + int x; + int y; +}; + + + +struct get_visible_region_request +{ + struct request_header __header; + user_handle_t window; + unsigned int flags; +}; +struct get_visible_region_reply +{ + struct reply_header __header; + user_handle_t top_win; + rectangle_t top_rect; + rectangle_t win_rect; + data_size_t total_size; + /* VARARG(region,rectangles); */ +}; + + + +struct get_window_region_request +{ + struct request_header __header; + user_handle_t window; +}; +struct get_window_region_reply +{ + struct reply_header __header; + data_size_t total_size; + /* VARARG(region,rectangles); */ +}; + + + +struct set_window_region_request +{ + struct request_header __header; + user_handle_t window; + int redraw; + /* VARARG(region,rectangles); */ +}; +struct set_window_region_reply +{ + struct reply_header __header; +}; + + + +struct get_update_region_request +{ + struct request_header __header; + user_handle_t window; + user_handle_t from_child; + unsigned int flags; +}; +struct get_update_region_reply +{ + struct reply_header __header; + user_handle_t child; + unsigned int flags; + data_size_t total_size; + /* VARARG(region,rectangles); */ +}; +#define UPDATE_NONCLIENT 0x01 +#define UPDATE_ERASE 0x02 +#define UPDATE_PAINT 0x04 +#define UPDATE_INTERNALPAINT 0x08 +#define UPDATE_ALLCHILDREN 0x10 +#define UPDATE_NOCHILDREN 0x20 +#define UPDATE_NOREGION 0x40 +#define UPDATE_DELAYED_ERASE 0x80 + + + +struct update_window_zorder_request +{ + struct request_header __header; + user_handle_t window; + rectangle_t rect; +}; +struct update_window_zorder_reply +{ + struct reply_header __header; +}; + + + +struct redraw_window_request +{ + struct request_header __header; + user_handle_t window; + unsigned int flags; + /* VARARG(region,rectangles); */ +}; +struct redraw_window_reply +{ + struct reply_header __header; +}; + + + +struct set_window_property_request +{ + struct request_header __header; + user_handle_t window; + atom_t atom; + obj_handle_t handle; + /* VARARG(name,unicode_str); */ +}; +struct set_window_property_reply +{ + struct reply_header __header; +}; + + + +struct remove_window_property_request +{ + struct request_header __header; + user_handle_t window; + atom_t atom; + /* VARARG(name,unicode_str); */ +}; +struct remove_window_property_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct get_window_property_request +{ + struct request_header __header; + user_handle_t window; + atom_t atom; + /* VARARG(name,unicode_str); */ +}; +struct get_window_property_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct get_window_properties_request +{ + struct request_header __header; + user_handle_t window; +}; +struct get_window_properties_reply +{ + struct reply_header __header; + int total; + /* VARARG(props,properties); */ +}; + + + +struct create_winstation_request +{ + struct request_header __header; + unsigned int flags; + unsigned int access; + unsigned int attributes; + /* VARARG(name,unicode_str); */ +}; +struct create_winstation_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_winstation_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + /* VARARG(name,unicode_str); */ +}; +struct open_winstation_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct close_winstation_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct close_winstation_reply +{ + struct reply_header __header; +}; + + + +struct get_process_winstation_request +{ + struct request_header __header; +}; +struct get_process_winstation_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct set_process_winstation_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct set_process_winstation_reply +{ + struct reply_header __header; +}; + + + +struct enum_winstation_request +{ + struct request_header __header; + unsigned int index; +}; +struct enum_winstation_reply +{ + struct reply_header __header; + unsigned int next; + /* VARARG(name,unicode_str); */ +}; + + + +struct create_desktop_request +{ + struct request_header __header; + unsigned int flags; + unsigned int access; + unsigned int attributes; + /* VARARG(name,unicode_str); */ +}; +struct create_desktop_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_desktop_request +{ + struct request_header __header; + obj_handle_t winsta; + unsigned int flags; + unsigned int access; + unsigned int attributes; + /* VARARG(name,unicode_str); */ +}; +struct open_desktop_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct close_desktop_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct close_desktop_reply +{ + struct reply_header __header; +}; + + + +struct get_thread_desktop_request +{ + struct request_header __header; + thread_id_t tid; +}; +struct get_thread_desktop_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct set_thread_desktop_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct set_thread_desktop_reply +{ + struct reply_header __header; +}; + + + +struct enum_desktop_request +{ + struct request_header __header; + obj_handle_t winstation; + unsigned int index; +}; +struct enum_desktop_reply +{ + struct reply_header __header; + unsigned int next; + /* VARARG(name,unicode_str); */ +}; + + + +struct set_user_object_info_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int flags; + unsigned int obj_flags; +}; +struct set_user_object_info_reply +{ + struct reply_header __header; + int is_desktop; + unsigned int old_obj_flags; + /* VARARG(name,unicode_str); */ +}; +#define SET_USER_OBJECT_FLAGS 1 + + + +struct attach_thread_input_request +{ + struct request_header __header; + thread_id_t tid_from; + thread_id_t tid_to; + int attach; +}; +struct attach_thread_input_reply +{ + struct reply_header __header; +}; + + + +struct get_thread_input_request +{ + struct request_header __header; + thread_id_t tid; +}; +struct get_thread_input_reply +{ + struct reply_header __header; + user_handle_t focus; + user_handle_t capture; + user_handle_t active; + user_handle_t foreground; + user_handle_t menu_owner; + user_handle_t move_size; + user_handle_t caret; + rectangle_t rect; +}; + + + +struct get_last_input_time_request +{ + struct request_header __header; +}; +struct get_last_input_time_reply +{ + struct reply_header __header; + unsigned int time; +}; + + + +struct get_key_state_request +{ + struct request_header __header; + thread_id_t tid; + int key; +}; +struct get_key_state_reply +{ + struct reply_header __header; + unsigned char state; + /* VARARG(keystate,bytes); */ +}; + + +struct set_key_state_request +{ + struct request_header __header; + thread_id_t tid; + /* VARARG(keystate,bytes); */ +}; +struct set_key_state_reply +{ + struct reply_header __header; +}; + + +struct set_foreground_window_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct set_foreground_window_reply +{ + struct reply_header __header; + user_handle_t previous; + int send_msg_old; + int send_msg_new; +}; + + +struct set_focus_window_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct set_focus_window_reply +{ + struct reply_header __header; + user_handle_t previous; +}; + + +struct set_active_window_request +{ + struct request_header __header; + user_handle_t handle; +}; +struct set_active_window_reply +{ + struct reply_header __header; + user_handle_t previous; +}; + + +struct set_capture_window_request +{ + struct request_header __header; + user_handle_t handle; + unsigned int flags; +}; +struct set_capture_window_reply +{ + struct reply_header __header; + user_handle_t previous; + user_handle_t full_handle; +}; +#define CAPTURE_MENU 0x01 +#define CAPTURE_MOVESIZE 0x02 + + + +struct set_caret_window_request +{ + struct request_header __header; + user_handle_t handle; + int width; + int height; +}; +struct set_caret_window_reply +{ + struct reply_header __header; + user_handle_t previous; + rectangle_t old_rect; + int old_hide; + int old_state; +}; + + + +struct set_caret_info_request +{ + struct request_header __header; + unsigned int flags; + user_handle_t handle; + int x; + int y; + int hide; + int state; +}; +struct set_caret_info_reply +{ + struct reply_header __header; + user_handle_t full_handle; + rectangle_t old_rect; + int old_hide; + int old_state; +}; +#define SET_CARET_POS 0x01 +#define SET_CARET_HIDE 0x02 +#define SET_CARET_STATE 0x04 + + + +struct set_hook_request +{ + struct request_header __header; + int id; + process_id_t pid; + thread_id_t tid; + int event_min; + int event_max; + int flags; + void* proc; + int unicode; + /* VARARG(module,unicode_str); */ +}; +struct set_hook_reply +{ + struct reply_header __header; + user_handle_t handle; + unsigned int active_hooks; +}; + + + +struct remove_hook_request +{ + struct request_header __header; + user_handle_t handle; + int id; + void* proc; +}; +struct remove_hook_reply +{ + struct reply_header __header; + unsigned int active_hooks; +}; + + + +struct start_hook_chain_request +{ + struct request_header __header; + int id; + int event; + user_handle_t window; + int object_id; + int child_id; +}; +struct start_hook_chain_reply +{ + struct reply_header __header; + user_handle_t handle; + process_id_t pid; + thread_id_t tid; + void* proc; + int unicode; + unsigned int active_hooks; + /* VARARG(module,unicode_str); */ +}; + + + +struct finish_hook_chain_request +{ + struct request_header __header; + int id; +}; +struct finish_hook_chain_reply +{ + struct reply_header __header; +}; + + + +struct get_hook_info_request +{ + struct request_header __header; + user_handle_t handle; + int get_next; + int event; + user_handle_t window; + int object_id; + int child_id; +}; +struct get_hook_info_reply +{ + struct reply_header __header; + user_handle_t handle; + int id; + process_id_t pid; + thread_id_t tid; + void* proc; + int unicode; + /* VARARG(module,unicode_str); */ +}; + + + +struct create_class_request +{ + struct request_header __header; + int local; + atom_t atom; + unsigned int style; + void* instance; + int extra; + int win_extra; + void* client_ptr; + /* VARARG(name,unicode_str); */ +}; +struct create_class_reply +{ + struct reply_header __header; + atom_t atom; +}; + + + +struct destroy_class_request +{ + struct request_header __header; + atom_t atom; + void* instance; + /* VARARG(name,unicode_str); */ +}; +struct destroy_class_reply +{ + struct reply_header __header; + void* client_ptr; +}; + + + +struct set_class_info_request +{ + struct request_header __header; + user_handle_t window; + unsigned int flags; + atom_t atom; + unsigned int style; + int win_extra; + void* instance; + int extra_offset; + data_size_t extra_size; + unsigned long extra_value; +}; +struct set_class_info_reply +{ + struct reply_header __header; + atom_t old_atom; + unsigned int old_style; + int old_extra; + int old_win_extra; + void* old_instance; + unsigned long old_extra_value; +}; +#define SET_CLASS_ATOM 0x0001 +#define SET_CLASS_STYLE 0x0002 +#define SET_CLASS_WINEXTRA 0x0004 +#define SET_CLASS_INSTANCE 0x0008 +#define SET_CLASS_EXTRA 0x0010 + + + +struct set_clipboard_info_request +{ + struct request_header __header; + unsigned int flags; + user_handle_t clipboard; + user_handle_t owner; + user_handle_t viewer; + unsigned int seqno; +}; +struct set_clipboard_info_reply +{ + struct reply_header __header; + unsigned int flags; + user_handle_t old_clipboard; + user_handle_t old_owner; + user_handle_t old_viewer; + unsigned int seqno; +}; + +#define SET_CB_OPEN 0x001 +#define SET_CB_OWNER 0x002 +#define SET_CB_VIEWER 0x004 +#define SET_CB_SEQNO 0x008 +#define SET_CB_RELOWNER 0x010 +#define SET_CB_CLOSE 0x020 +#define CB_OPEN 0x040 +#define CB_OWNER 0x080 +#define CB_PROCESS 0x100 + + + +struct open_token_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int access; + unsigned int attributes; + unsigned int flags; +}; +struct open_token_reply +{ + struct reply_header __header; + obj_handle_t token; +}; +#define OPEN_TOKEN_THREAD 1 +#define OPEN_TOKEN_AS_SELF 2 + + + +struct set_global_windows_request +{ + struct request_header __header; + unsigned int flags; + user_handle_t shell_window; + user_handle_t shell_listview; + user_handle_t progman_window; + user_handle_t taskman_window; +}; +struct set_global_windows_reply +{ + struct reply_header __header; + user_handle_t old_shell_window; + user_handle_t old_shell_listview; + user_handle_t old_progman_window; + user_handle_t old_taskman_window; +}; +#define SET_GLOBAL_SHELL_WINDOWS 0x01 +#define SET_GLOBAL_PROGMAN_WINDOW 0x02 +#define SET_GLOBAL_TASKMAN_WINDOW 0x04 + + +struct adjust_token_privileges_request +{ + struct request_header __header; + obj_handle_t handle; + int disable_all; + int get_modified_state; + /* VARARG(privileges,LUID_AND_ATTRIBUTES); */ +}; +struct adjust_token_privileges_reply +{ + struct reply_header __header; + unsigned int len; + /* VARARG(privileges,LUID_AND_ATTRIBUTES); */ +}; + + +struct get_token_privileges_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_token_privileges_reply +{ + struct reply_header __header; + unsigned int len; + /* VARARG(privileges,LUID_AND_ATTRIBUTES); */ +}; + + +struct check_token_privileges_request +{ + struct request_header __header; + obj_handle_t handle; + int all_required; + /* VARARG(privileges,LUID_AND_ATTRIBUTES); */ +}; +struct check_token_privileges_reply +{ + struct reply_header __header; + int has_privileges; + /* VARARG(privileges,LUID_AND_ATTRIBUTES); */ +}; + +struct duplicate_token_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int access; + unsigned int attributes; + int primary; + int impersonation_level; +}; +struct duplicate_token_reply +{ + struct reply_header __header; + obj_handle_t new_handle; +}; + +struct access_check_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int desired_access; + unsigned int mapping_read; + unsigned int mapping_write; + unsigned int mapping_execute; + unsigned int mapping_all; + /* VARARG(sd,security_descriptor); */ +}; +struct access_check_reply +{ + struct reply_header __header; + unsigned int access_granted; + unsigned int access_status; + unsigned int privileges_len; + /* VARARG(privileges,LUID_AND_ATTRIBUTES); */ +}; + +struct get_token_user_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_token_user_reply +{ + struct reply_header __header; + data_size_t user_len; + /* VARARG(user,SID); */ +}; + +struct get_token_groups_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_token_groups_reply +{ + struct reply_header __header; + data_size_t user_len; + /* VARARG(user,token_groups); */ +}; + +struct set_security_object_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int security_info; + /* VARARG(sd,security_descriptor); */ +}; +struct set_security_object_reply +{ + struct reply_header __header; +}; + +struct get_security_object_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int security_info; +}; +struct get_security_object_reply +{ + struct reply_header __header; + unsigned int sd_len; + /* VARARG(sd,security_descriptor); */ +}; + + +struct create_mailslot_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + unsigned int max_msgsize; + timeout_t read_timeout; + /* VARARG(name,unicode_str); */ +}; +struct create_mailslot_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct set_mailslot_info_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int flags; + timeout_t read_timeout; +}; +struct set_mailslot_info_reply +{ + struct reply_header __header; + unsigned int max_msgsize; + timeout_t read_timeout; +}; +#define MAILSLOT_SET_READ_TIMEOUT 1 + + + +struct create_directory_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(directory_name,unicode_str); */ +}; +struct create_directory_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_directory_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(directory_name,unicode_str); */ +}; +struct open_directory_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct get_directory_entry_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int index; +}; +struct get_directory_entry_reply +{ + struct reply_header __header; + size_t name_len; + /* VARARG(name,unicode_str,name_len); */ + /* VARARG(type,unicode_str); */ +}; + + + +struct create_symlink_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + data_size_t name_len; + /* VARARG(name,unicode_str,name_len); */ + /* VARARG(target_name,unicode_str); */ +}; +struct create_symlink_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_symlink_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(name,unicode_str); */ +}; +struct open_symlink_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct query_symlink_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct query_symlink_reply +{ + struct reply_header __header; + /* VARARG(target_name,unicode_str); */ +}; + + + +struct get_object_info_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_object_info_reply +{ + struct reply_header __header; + unsigned int access; + unsigned int ref_count; +}; + + +struct get_token_impersonation_level_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_token_impersonation_level_reply +{ + struct reply_header __header; + int impersonation_level; +}; + + +struct allocate_locally_unique_id_request +{ + struct request_header __header; +}; +struct allocate_locally_unique_id_reply +{ + struct reply_header __header; + luid_t luid; +}; + + + +struct create_device_manager_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; +}; +struct create_device_manager_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct create_device_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + obj_handle_t manager; + void* user_ptr; + /* VARARG(name,unicode_str); */ +}; +struct create_device_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct delete_device_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct delete_device_reply +{ + struct reply_header __header; +}; + + + +struct get_next_device_request_request +{ + struct request_header __header; + obj_handle_t manager; + obj_handle_t prev; + unsigned int status; + /* VARARG(prev_data,bytes); */ +}; +struct get_next_device_request_reply +{ + struct reply_header __header; + obj_handle_t next; + ioctl_code_t code; + void* user_ptr; + data_size_t in_size; + data_size_t out_size; + /* VARARG(next_data,bytes); */ +}; + + + +struct make_process_system_request +{ + struct request_header __header; +}; +struct make_process_system_reply +{ + struct reply_header __header; + obj_handle_t event; +}; + + + +struct get_token_statistics_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_token_statistics_reply +{ + struct reply_header __header; + luid_t token_id; + luid_t modified_id; + int primary; + int impersonation_level; + int group_count; + int privilege_count; +}; + + + +struct create_completion_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + unsigned int concurrent; + obj_handle_t rootdir; + /* VARARG(filename,string); */ +}; +struct create_completion_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct open_completion_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + /* VARARG(filename,string); */ +}; +struct open_completion_reply +{ + struct reply_header __header; + obj_handle_t handle; +}; + + + +struct add_completion_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned long ckey; + unsigned long cvalue; + unsigned long information; + unsigned int status; +}; +struct add_completion_reply +{ + struct reply_header __header; +}; + + + +struct remove_completion_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct remove_completion_reply +{ + struct reply_header __header; + unsigned long ckey; + unsigned long cvalue; + unsigned long information; + unsigned int status; +}; + + + +struct query_completion_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct query_completion_reply +{ + struct reply_header __header; + unsigned int depth; +}; + + + +struct set_completion_info_request +{ + struct request_header __header; + obj_handle_t handle; + obj_handle_t chandle; + unsigned long ckey; +}; +struct set_completion_info_reply +{ + struct reply_header __header; +}; + + + +struct add_fd_completion_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned long cvalue; + unsigned int status; + unsigned long information; +}; +struct add_fd_completion_reply +{ + struct reply_header __header; +}; + +struct load_init_registry_request +{ + struct request_header __header; + /*FIXME */ + + WCHAR * keyname; + int keylen; + char * filename; + int filelen; +}; +struct save_branch_request +{ + struct request_header __header; + /*FIXME */ + int branch_num; +}; + +struct load_init_registry_reply +{ + struct reply_header __header; + /*FIXME */ +}; + +struct save_branch_reply +{ + struct reply_header __header; + /*FIXME */ +}; + + +enum request +{ + REQ_new_process, + REQ_get_new_process_info, + REQ_new_thread, + REQ_get_startup_info, + REQ_init_process_done, + REQ_init_thread, + REQ_terminate_process, + REQ_terminate_thread, + REQ_get_process_info, + REQ_set_process_info, + REQ_get_thread_info, + REQ_set_thread_info, + REQ_get_dll_info, + REQ_suspend_thread, + REQ_resume_thread, + REQ_load_dll, + REQ_unload_dll, + REQ_queue_apc, + REQ_get_apc_result, + REQ_close_handle, + REQ_set_handle_info, + REQ_dup_handle, + REQ_open_process, + REQ_open_thread, + REQ_select, + REQ_create_event, + REQ_event_op, + REQ_open_event, + REQ_create_mutex, + REQ_release_mutex, + REQ_open_mutex, + REQ_create_semaphore, + REQ_release_semaphore, + REQ_open_semaphore, + REQ_create_file, + REQ_open_file_object, + REQ_alloc_file_handle, + REQ_get_handle_fd, + REQ_flush_file, + REQ_lock_file, + REQ_unlock_file, + REQ_create_socket, + REQ_accept_socket, + REQ_set_socket_event, + REQ_get_socket_event, + REQ_enable_socket_event, + REQ_set_socket_deferred, + REQ_alloc_console, + REQ_free_console, + REQ_get_console_renderer_events, + REQ_open_console, + REQ_get_console_wait_event, + REQ_get_console_mode, + REQ_set_console_mode, + REQ_set_console_input_info, + REQ_get_console_input_info, + REQ_append_console_input_history, + REQ_get_console_input_history, + REQ_create_console_output, + REQ_set_console_output_info, + REQ_get_console_output_info, + REQ_write_console_input, + REQ_read_console_input, + REQ_write_console_output, + REQ_fill_console_output, + REQ_read_console_output, + REQ_move_console_output, + REQ_send_console_signal, + REQ_read_directory_changes, + REQ_read_change, + REQ_create_mapping, + REQ_open_mapping, + REQ_get_mapping_info, + REQ_create_snapshot, + REQ_next_process, + REQ_next_thread, + REQ_next_module, + REQ_wait_debug_event, + REQ_queue_exception_event, + REQ_get_exception_status, + REQ_output_debug_string, + REQ_continue_debug_event, + REQ_debug_process, + REQ_debug_break, + REQ_set_debugger_kill_on_exit, + REQ_read_process_memory, + REQ_write_process_memory, + REQ_create_key, + REQ_open_key, + REQ_delete_key, + REQ_flush_key, + REQ_enum_key, + REQ_set_key_value, + REQ_get_key_value, + REQ_enum_key_value, + REQ_delete_key_value, + REQ_load_registry, + REQ_unload_registry, + REQ_save_registry, + REQ_set_registry_notification, + REQ_create_timer, + REQ_open_timer, + REQ_set_timer, + REQ_cancel_timer, + REQ_get_timer_info, + REQ_get_thread_context, + REQ_set_thread_context, + REQ_get_selector_entry, + REQ_add_atom, + REQ_delete_atom, + REQ_find_atom, + REQ_get_atom_information, + REQ_set_atom_information, + REQ_empty_atom_table, + REQ_init_atom_table, + REQ_get_msg_queue, + REQ_set_queue_fd, + REQ_set_queue_mask, + REQ_get_queue_status, + REQ_get_process_idle_event, + REQ_send_message, + REQ_post_quit_message, + REQ_send_hardware_message, + REQ_get_message, + REQ_reply_message, + REQ_accept_hardware_message, + REQ_get_message_reply, + REQ_set_win_timer, + REQ_kill_win_timer, + REQ_is_window_hung, + REQ_get_serial_info, + REQ_set_serial_info, + REQ_register_async, + REQ_cancel_async, + REQ_ioctl, + REQ_get_ioctl_result, + REQ_create_named_pipe, + REQ_get_named_pipe_info, + REQ_create_window, + REQ_destroy_window, + REQ_get_desktop_window, + REQ_set_window_owner, + REQ_get_window_info, + REQ_set_window_info, + REQ_set_parent, + REQ_get_window_parents, + REQ_get_window_children, + REQ_get_window_children_from_point, + REQ_get_window_tree, + REQ_set_window_pos, + REQ_set_window_visible_rect, + REQ_get_window_rectangles, + REQ_get_window_text, + REQ_set_window_text, + REQ_get_windows_offset, + REQ_get_visible_region, + REQ_get_window_region, + REQ_set_window_region, + REQ_get_update_region, + REQ_update_window_zorder, + REQ_redraw_window, + REQ_set_window_property, + REQ_remove_window_property, + REQ_get_window_property, + REQ_get_window_properties, + REQ_create_winstation, + REQ_open_winstation, + REQ_close_winstation, + REQ_get_process_winstation, + REQ_set_process_winstation, + REQ_enum_winstation, + REQ_create_desktop, + REQ_open_desktop, + REQ_close_desktop, + REQ_get_thread_desktop, + REQ_set_thread_desktop, + REQ_enum_desktop, + REQ_set_user_object_info, + REQ_attach_thread_input, + REQ_get_thread_input, + REQ_get_last_input_time, + REQ_get_key_state, + REQ_set_key_state, + REQ_set_foreground_window, + REQ_set_focus_window, + REQ_set_active_window, + REQ_set_capture_window, + REQ_set_caret_window, + REQ_set_caret_info, + REQ_set_hook, + REQ_remove_hook, + REQ_start_hook_chain, + REQ_finish_hook_chain, + REQ_get_hook_info, + REQ_create_class, + REQ_destroy_class, + REQ_set_class_info, + REQ_set_clipboard_info, + REQ_open_token, + REQ_set_global_windows, + REQ_adjust_token_privileges, + REQ_get_token_privileges, + REQ_check_token_privileges, + REQ_duplicate_token, + REQ_access_check, + REQ_get_token_user, + REQ_get_token_groups, + REQ_set_security_object, + REQ_get_security_object, + REQ_create_mailslot, + REQ_set_mailslot_info, + REQ_create_directory, + REQ_open_directory, + REQ_get_directory_entry, + REQ_create_symlink, + REQ_open_symlink, + REQ_query_symlink, + REQ_get_object_info, + REQ_get_token_impersonation_level, + REQ_allocate_locally_unique_id, + REQ_create_device_manager, + REQ_create_device, + REQ_delete_device, + REQ_get_next_device_request, + REQ_make_process_system, + REQ_get_token_statistics, + REQ_create_completion, + REQ_open_completion, + REQ_add_completion, + REQ_remove_completion, + REQ_query_completion, + REQ_set_completion_info, + REQ_add_fd_completion, + REQ_load_init_registry, + REQ_save_branch, + REQ_NB_REQUESTS +}; + +union generic_request +{ + struct request_max_size max_size; + struct request_header request_header; + struct new_process_request new_process_request; + struct get_new_process_info_request get_new_process_info_request; + struct new_thread_request new_thread_request; + struct get_startup_info_request get_startup_info_request; + struct init_process_done_request init_process_done_request; + struct init_thread_request init_thread_request; + struct terminate_process_request terminate_process_request; + struct terminate_thread_request terminate_thread_request; + struct get_process_info_request get_process_info_request; + struct set_process_info_request set_process_info_request; + struct get_thread_info_request get_thread_info_request; + struct set_thread_info_request set_thread_info_request; + struct get_dll_info_request get_dll_info_request; + struct suspend_thread_request suspend_thread_request; + struct resume_thread_request resume_thread_request; + struct load_dll_request load_dll_request; + struct unload_dll_request unload_dll_request; + struct queue_apc_request queue_apc_request; + struct get_apc_result_request get_apc_result_request; + struct close_handle_request close_handle_request; + struct set_handle_info_request set_handle_info_request; + struct dup_handle_request dup_handle_request; + struct open_process_request open_process_request; + struct open_thread_request open_thread_request; + struct select_request select_request; + struct create_event_request create_event_request; + struct event_op_request event_op_request; + struct open_event_request open_event_request; + struct create_mutex_request create_mutex_request; + struct release_mutex_request release_mutex_request; + struct open_mutex_request open_mutex_request; + struct create_semaphore_request create_semaphore_request; + struct release_semaphore_request release_semaphore_request; + struct open_semaphore_request open_semaphore_request; + struct create_file_request create_file_request; + struct open_file_object_request open_file_object_request; + struct alloc_file_handle_request alloc_file_handle_request; + struct get_handle_fd_request get_handle_fd_request; + struct flush_file_request flush_file_request; + struct lock_file_request lock_file_request; + struct unlock_file_request unlock_file_request; + struct create_socket_request create_socket_request; + struct accept_socket_request accept_socket_request; + struct set_socket_event_request set_socket_event_request; + struct get_socket_event_request get_socket_event_request; + struct enable_socket_event_request enable_socket_event_request; + struct set_socket_deferred_request set_socket_deferred_request; + struct alloc_console_request alloc_console_request; + struct free_console_request free_console_request; + struct get_console_renderer_events_request get_console_renderer_events_request; + struct open_console_request open_console_request; + struct get_console_wait_event_request get_console_wait_event_request; + struct get_console_mode_request get_console_mode_request; + struct set_console_mode_request set_console_mode_request; + struct set_console_input_info_request set_console_input_info_request; + struct get_console_input_info_request get_console_input_info_request; + struct append_console_input_history_request append_console_input_history_request; + struct get_console_input_history_request get_console_input_history_request; + struct create_console_output_request create_console_output_request; + struct set_console_output_info_request set_console_output_info_request; + struct get_console_output_info_request get_console_output_info_request; + struct write_console_input_request write_console_input_request; + struct read_console_input_request read_console_input_request; + struct write_console_output_request write_console_output_request; + struct fill_console_output_request fill_console_output_request; + struct read_console_output_request read_console_output_request; + struct move_console_output_request move_console_output_request; + struct send_console_signal_request send_console_signal_request; + struct read_directory_changes_request read_directory_changes_request; + struct read_change_request read_change_request; + struct create_mapping_request create_mapping_request; + struct open_mapping_request open_mapping_request; + struct get_mapping_info_request get_mapping_info_request; + struct create_snapshot_request create_snapshot_request; + struct next_process_request next_process_request; + struct next_thread_request next_thread_request; + struct next_module_request next_module_request; + struct wait_debug_event_request wait_debug_event_request; + struct queue_exception_event_request queue_exception_event_request; + struct get_exception_status_request get_exception_status_request; + struct output_debug_string_request output_debug_string_request; + struct continue_debug_event_request continue_debug_event_request; + struct debug_process_request debug_process_request; + struct debug_break_request debug_break_request; + struct set_debugger_kill_on_exit_request set_debugger_kill_on_exit_request; + struct read_process_memory_request read_process_memory_request; + struct write_process_memory_request write_process_memory_request; + struct create_key_request create_key_request; + struct open_key_request open_key_request; + struct delete_key_request delete_key_request; + struct flush_key_request flush_key_request; + struct enum_key_request enum_key_request; + struct set_key_value_request set_key_value_request; + struct get_key_value_request get_key_value_request; + struct enum_key_value_request enum_key_value_request; + struct delete_key_value_request delete_key_value_request; + struct load_registry_request load_registry_request; + struct unload_registry_request unload_registry_request; + struct save_registry_request save_registry_request; + struct set_registry_notification_request set_registry_notification_request; + struct create_timer_request create_timer_request; + struct open_timer_request open_timer_request; + struct set_timer_request set_timer_request; + struct cancel_timer_request cancel_timer_request; + struct get_timer_info_request get_timer_info_request; + struct get_thread_context_request get_thread_context_request; + struct set_thread_context_request set_thread_context_request; + struct get_selector_entry_request get_selector_entry_request; + struct add_atom_request add_atom_request; + struct delete_atom_request delete_atom_request; + struct find_atom_request find_atom_request; + struct get_atom_information_request get_atom_information_request; + struct set_atom_information_request set_atom_information_request; + struct empty_atom_table_request empty_atom_table_request; + struct init_atom_table_request init_atom_table_request; + struct get_msg_queue_request get_msg_queue_request; + struct set_queue_fd_request set_queue_fd_request; + struct set_queue_mask_request set_queue_mask_request; + struct get_queue_status_request get_queue_status_request; + struct get_process_idle_event_request get_process_idle_event_request; + struct send_message_request send_message_request; + struct post_quit_message_request post_quit_message_request; + struct send_hardware_message_request send_hardware_message_request; + struct get_message_request get_message_request; + struct reply_message_request reply_message_request; + struct accept_hardware_message_request accept_hardware_message_request; + struct get_message_reply_request get_message_reply_request; + struct set_win_timer_request set_win_timer_request; + struct kill_win_timer_request kill_win_timer_request; + struct is_window_hung_request is_window_hung_request; + struct get_serial_info_request get_serial_info_request; + struct set_serial_info_request set_serial_info_request; + struct register_async_request register_async_request; + struct cancel_async_request cancel_async_request; + struct ioctl_request ioctl_request; + struct get_ioctl_result_request get_ioctl_result_request; + struct create_named_pipe_request create_named_pipe_request; + struct get_named_pipe_info_request get_named_pipe_info_request; + struct create_window_request create_window_request; + struct destroy_window_request destroy_window_request; + struct get_desktop_window_request get_desktop_window_request; + struct set_window_owner_request set_window_owner_request; + struct get_window_info_request get_window_info_request; + struct set_window_info_request set_window_info_request; + struct set_parent_request set_parent_request; + struct get_window_parents_request get_window_parents_request; + struct get_window_children_request get_window_children_request; + struct get_window_children_from_point_request get_window_children_from_point_request; + struct get_window_tree_request get_window_tree_request; + struct set_window_pos_request set_window_pos_request; + struct set_window_visible_rect_request set_window_visible_rect_request; + struct get_window_rectangles_request get_window_rectangles_request; + struct get_window_text_request get_window_text_request; + struct set_window_text_request set_window_text_request; + struct get_windows_offset_request get_windows_offset_request; + struct get_visible_region_request get_visible_region_request; + struct get_window_region_request get_window_region_request; + struct set_window_region_request set_window_region_request; + struct get_update_region_request get_update_region_request; + struct update_window_zorder_request update_window_zorder_request; + struct redraw_window_request redraw_window_request; + struct set_window_property_request set_window_property_request; + struct remove_window_property_request remove_window_property_request; + struct get_window_property_request get_window_property_request; + struct get_window_properties_request get_window_properties_request; + struct create_winstation_request create_winstation_request; + struct open_winstation_request open_winstation_request; + struct close_winstation_request close_winstation_request; + struct get_process_winstation_request get_process_winstation_request; + struct set_process_winstation_request set_process_winstation_request; + struct enum_winstation_request enum_winstation_request; + struct create_desktop_request create_desktop_request; + struct open_desktop_request open_desktop_request; + struct close_desktop_request close_desktop_request; + struct get_thread_desktop_request get_thread_desktop_request; + struct set_thread_desktop_request set_thread_desktop_request; + struct enum_desktop_request enum_desktop_request; + struct set_user_object_info_request set_user_object_info_request; + struct attach_thread_input_request attach_thread_input_request; + struct get_thread_input_request get_thread_input_request; + struct get_last_input_time_request get_last_input_time_request; + struct get_key_state_request get_key_state_request; + struct set_key_state_request set_key_state_request; + struct set_foreground_window_request set_foreground_window_request; + struct set_focus_window_request set_focus_window_request; + struct set_active_window_request set_active_window_request; + struct set_capture_window_request set_capture_window_request; + struct set_caret_window_request set_caret_window_request; + struct set_caret_info_request set_caret_info_request; + struct set_hook_request set_hook_request; + struct remove_hook_request remove_hook_request; + struct start_hook_chain_request start_hook_chain_request; + struct finish_hook_chain_request finish_hook_chain_request; + struct get_hook_info_request get_hook_info_request; + struct create_class_request create_class_request; + struct destroy_class_request destroy_class_request; + struct set_class_info_request set_class_info_request; + struct set_clipboard_info_request set_clipboard_info_request; + struct open_token_request open_token_request; + struct set_global_windows_request set_global_windows_request; + struct adjust_token_privileges_request adjust_token_privileges_request; + struct get_token_privileges_request get_token_privileges_request; + struct check_token_privileges_request check_token_privileges_request; + struct duplicate_token_request duplicate_token_request; + struct access_check_request access_check_request; + struct get_token_user_request get_token_user_request; + struct get_token_groups_request get_token_groups_request; + struct set_security_object_request set_security_object_request; + struct get_security_object_request get_security_object_request; + struct create_mailslot_request create_mailslot_request; + struct set_mailslot_info_request set_mailslot_info_request; + struct create_directory_request create_directory_request; + struct open_directory_request open_directory_request; + struct get_directory_entry_request get_directory_entry_request; + struct create_symlink_request create_symlink_request; + struct open_symlink_request open_symlink_request; + struct query_symlink_request query_symlink_request; + struct get_object_info_request get_object_info_request; + struct get_token_impersonation_level_request get_token_impersonation_level_request; + struct allocate_locally_unique_id_request allocate_locally_unique_id_request; + struct create_device_manager_request create_device_manager_request; + struct create_device_request create_device_request; + struct delete_device_request delete_device_request; + struct get_next_device_request_request get_next_device_request_request; + struct make_process_system_request make_process_system_request; + struct get_token_statistics_request get_token_statistics_request; + struct create_completion_request create_completion_request; + struct open_completion_request open_completion_request; + struct add_completion_request add_completion_request; + struct remove_completion_request remove_completion_request; + struct query_completion_request query_completion_request; + struct set_completion_info_request set_completion_info_request; + struct add_fd_completion_request add_fd_completion_request; + struct load_init_registry_request load_init_registry_request; + struct save_branch_request save_branch_request; +}; +union generic_reply +{ + struct request_max_size max_size; + struct reply_header reply_header; + struct new_process_reply new_process_reply; + struct get_new_process_info_reply get_new_process_info_reply; + struct new_thread_reply new_thread_reply; + struct get_startup_info_reply get_startup_info_reply; + struct init_process_done_reply init_process_done_reply; + struct init_thread_reply init_thread_reply; + struct terminate_process_reply terminate_process_reply; + struct terminate_thread_reply terminate_thread_reply; + struct get_process_info_reply get_process_info_reply; + struct set_process_info_reply set_process_info_reply; + struct get_thread_info_reply get_thread_info_reply; + struct set_thread_info_reply set_thread_info_reply; + struct get_dll_info_reply get_dll_info_reply; + struct suspend_thread_reply suspend_thread_reply; + struct resume_thread_reply resume_thread_reply; + struct load_dll_reply load_dll_reply; + struct unload_dll_reply unload_dll_reply; + struct queue_apc_reply queue_apc_reply; + struct get_apc_result_reply get_apc_result_reply; + struct close_handle_reply close_handle_reply; + struct set_handle_info_reply set_handle_info_reply; + struct dup_handle_reply dup_handle_reply; + struct open_process_reply open_process_reply; + struct open_thread_reply open_thread_reply; + struct select_reply select_reply; + struct create_event_reply create_event_reply; + struct event_op_reply event_op_reply; + struct open_event_reply open_event_reply; + struct create_mutex_reply create_mutex_reply; + struct release_mutex_reply release_mutex_reply; + struct open_mutex_reply open_mutex_reply; + struct create_semaphore_reply create_semaphore_reply; + struct release_semaphore_reply release_semaphore_reply; + struct open_semaphore_reply open_semaphore_reply; + struct create_file_reply create_file_reply; + struct open_file_object_reply open_file_object_reply; + struct alloc_file_handle_reply alloc_file_handle_reply; + struct get_handle_fd_reply get_handle_fd_reply; + struct flush_file_reply flush_file_reply; + struct lock_file_reply lock_file_reply; + struct unlock_file_reply unlock_file_reply; + struct create_socket_reply create_socket_reply; + struct accept_socket_reply accept_socket_reply; + struct set_socket_event_reply set_socket_event_reply; + struct get_socket_event_reply get_socket_event_reply; + struct enable_socket_event_reply enable_socket_event_reply; + struct set_socket_deferred_reply set_socket_deferred_reply; + struct alloc_console_reply alloc_console_reply; + struct free_console_reply free_console_reply; + struct get_console_renderer_events_reply get_console_renderer_events_reply; + struct open_console_reply open_console_reply; + struct get_console_wait_event_reply get_console_wait_event_reply; + struct get_console_mode_reply get_console_mode_reply; + struct set_console_mode_reply set_console_mode_reply; + struct set_console_input_info_reply set_console_input_info_reply; + struct get_console_input_info_reply get_console_input_info_reply; + struct append_console_input_history_reply append_console_input_history_reply; + struct get_console_input_history_reply get_console_input_history_reply; + struct create_console_output_reply create_console_output_reply; + struct set_console_output_info_reply set_console_output_info_reply; + struct get_console_output_info_reply get_console_output_info_reply; + struct write_console_input_reply write_console_input_reply; + struct read_console_input_reply read_console_input_reply; + struct write_console_output_reply write_console_output_reply; + struct fill_console_output_reply fill_console_output_reply; + struct read_console_output_reply read_console_output_reply; + struct move_console_output_reply move_console_output_reply; + struct send_console_signal_reply send_console_signal_reply; + struct read_directory_changes_reply read_directory_changes_reply; + struct read_change_reply read_change_reply; + struct create_mapping_reply create_mapping_reply; + struct open_mapping_reply open_mapping_reply; + struct get_mapping_info_reply get_mapping_info_reply; + struct create_snapshot_reply create_snapshot_reply; + struct next_process_reply next_process_reply; + struct next_thread_reply next_thread_reply; + struct next_module_reply next_module_reply; + struct wait_debug_event_reply wait_debug_event_reply; + struct queue_exception_event_reply queue_exception_event_reply; + struct get_exception_status_reply get_exception_status_reply; + struct output_debug_string_reply output_debug_string_reply; + struct continue_debug_event_reply continue_debug_event_reply; + struct debug_process_reply debug_process_reply; + struct debug_break_reply debug_break_reply; + struct set_debugger_kill_on_exit_reply set_debugger_kill_on_exit_reply; + struct read_process_memory_reply read_process_memory_reply; + struct write_process_memory_reply write_process_memory_reply; + struct create_key_reply create_key_reply; + struct open_key_reply open_key_reply; + struct delete_key_reply delete_key_reply; + struct flush_key_reply flush_key_reply; + struct enum_key_reply enum_key_reply; + struct set_key_value_reply set_key_value_reply; + struct get_key_value_reply get_key_value_reply; + struct enum_key_value_reply enum_key_value_reply; + struct delete_key_value_reply delete_key_value_reply; + struct load_registry_reply load_registry_reply; + struct unload_registry_reply unload_registry_reply; + struct save_registry_reply save_registry_reply; + struct set_registry_notification_reply set_registry_notification_reply; + struct create_timer_reply create_timer_reply; + struct open_timer_reply open_timer_reply; + struct set_timer_reply set_timer_reply; + struct cancel_timer_reply cancel_timer_reply; + struct get_timer_info_reply get_timer_info_reply; + struct get_thread_context_reply get_thread_context_reply; + struct set_thread_context_reply set_thread_context_reply; + struct get_selector_entry_reply get_selector_entry_reply; + struct add_atom_reply add_atom_reply; + struct delete_atom_reply delete_atom_reply; + struct find_atom_reply find_atom_reply; + struct get_atom_information_reply get_atom_information_reply; + struct set_atom_information_reply set_atom_information_reply; + struct empty_atom_table_reply empty_atom_table_reply; + struct init_atom_table_reply init_atom_table_reply; + struct get_msg_queue_reply get_msg_queue_reply; + struct set_queue_fd_reply set_queue_fd_reply; + struct set_queue_mask_reply set_queue_mask_reply; + struct get_queue_status_reply get_queue_status_reply; + struct get_process_idle_event_reply get_process_idle_event_reply; + struct send_message_reply send_message_reply; + struct post_quit_message_reply post_quit_message_reply; + struct send_hardware_message_reply send_hardware_message_reply; + struct get_message_reply get_message_reply; + struct reply_message_reply reply_message_reply; + struct accept_hardware_message_reply accept_hardware_message_reply; + struct get_message_reply_reply get_message_reply_reply; + struct set_win_timer_reply set_win_timer_reply; + struct kill_win_timer_reply kill_win_timer_reply; + struct is_window_hung_reply is_window_hung_reply; + struct get_serial_info_reply get_serial_info_reply; + struct set_serial_info_reply set_serial_info_reply; + struct register_async_reply register_async_reply; + struct cancel_async_reply cancel_async_reply; + struct ioctl_reply ioctl_reply; + struct get_ioctl_result_reply get_ioctl_result_reply; + struct create_named_pipe_reply create_named_pipe_reply; + struct get_named_pipe_info_reply get_named_pipe_info_reply; + struct create_window_reply create_window_reply; + struct destroy_window_reply destroy_window_reply; + struct get_desktop_window_reply get_desktop_window_reply; + struct set_window_owner_reply set_window_owner_reply; + struct get_window_info_reply get_window_info_reply; + struct set_window_info_reply set_window_info_reply; + struct set_parent_reply set_parent_reply; + struct get_window_parents_reply get_window_parents_reply; + struct get_window_children_reply get_window_children_reply; + struct get_window_children_from_point_reply get_window_children_from_point_reply; + struct get_window_tree_reply get_window_tree_reply; + struct set_window_pos_reply set_window_pos_reply; + struct set_window_visible_rect_reply set_window_visible_rect_reply; + struct get_window_rectangles_reply get_window_rectangles_reply; + struct get_window_text_reply get_window_text_reply; + struct set_window_text_reply set_window_text_reply; + struct get_windows_offset_reply get_windows_offset_reply; + struct get_visible_region_reply get_visible_region_reply; + struct get_window_region_reply get_window_region_reply; + struct set_window_region_reply set_window_region_reply; + struct get_update_region_reply get_update_region_reply; + struct update_window_zorder_reply update_window_zorder_reply; + struct redraw_window_reply redraw_window_reply; + struct set_window_property_reply set_window_property_reply; + struct remove_window_property_reply remove_window_property_reply; + struct get_window_property_reply get_window_property_reply; + struct get_window_properties_reply get_window_properties_reply; + struct create_winstation_reply create_winstation_reply; + struct open_winstation_reply open_winstation_reply; + struct close_winstation_reply close_winstation_reply; + struct get_process_winstation_reply get_process_winstation_reply; + struct set_process_winstation_reply set_process_winstation_reply; + struct enum_winstation_reply enum_winstation_reply; + struct create_desktop_reply create_desktop_reply; + struct open_desktop_reply open_desktop_reply; + struct close_desktop_reply close_desktop_reply; + struct get_thread_desktop_reply get_thread_desktop_reply; + struct set_thread_desktop_reply set_thread_desktop_reply; + struct enum_desktop_reply enum_desktop_reply; + struct set_user_object_info_reply set_user_object_info_reply; + struct attach_thread_input_reply attach_thread_input_reply; + struct get_thread_input_reply get_thread_input_reply; + struct get_last_input_time_reply get_last_input_time_reply; + struct get_key_state_reply get_key_state_reply; + struct set_key_state_reply set_key_state_reply; + struct set_foreground_window_reply set_foreground_window_reply; + struct set_focus_window_reply set_focus_window_reply; + struct set_active_window_reply set_active_window_reply; + struct set_capture_window_reply set_capture_window_reply; + struct set_caret_window_reply set_caret_window_reply; + struct set_caret_info_reply set_caret_info_reply; + struct set_hook_reply set_hook_reply; + struct remove_hook_reply remove_hook_reply; + struct start_hook_chain_reply start_hook_chain_reply; + struct finish_hook_chain_reply finish_hook_chain_reply; + struct get_hook_info_reply get_hook_info_reply; + struct create_class_reply create_class_reply; + struct destroy_class_reply destroy_class_reply; + struct set_class_info_reply set_class_info_reply; + struct set_clipboard_info_reply set_clipboard_info_reply; + struct open_token_reply open_token_reply; + struct set_global_windows_reply set_global_windows_reply; + struct adjust_token_privileges_reply adjust_token_privileges_reply; + struct get_token_privileges_reply get_token_privileges_reply; + struct check_token_privileges_reply check_token_privileges_reply; + struct duplicate_token_reply duplicate_token_reply; + struct access_check_reply access_check_reply; + struct get_token_user_reply get_token_user_reply; + struct get_token_groups_reply get_token_groups_reply; + struct set_security_object_reply set_security_object_reply; + struct get_security_object_reply get_security_object_reply; + struct create_mailslot_reply create_mailslot_reply; + struct set_mailslot_info_reply set_mailslot_info_reply; + struct create_directory_reply create_directory_reply; + struct open_directory_reply open_directory_reply; + struct get_directory_entry_reply get_directory_entry_reply; + struct create_symlink_reply create_symlink_reply; + struct open_symlink_reply open_symlink_reply; + struct query_symlink_reply query_symlink_reply; + struct get_object_info_reply get_object_info_reply; + struct get_token_impersonation_level_reply get_token_impersonation_level_reply; + struct allocate_locally_unique_id_reply allocate_locally_unique_id_reply; + struct create_device_manager_reply create_device_manager_reply; + struct create_device_reply create_device_reply; + struct delete_device_reply delete_device_reply; + struct get_next_device_request_reply get_next_device_request_reply; + struct make_process_system_reply make_process_system_reply; + struct get_token_statistics_reply get_token_statistics_reply; + struct create_completion_reply create_completion_reply; + struct open_completion_reply open_completion_reply; + struct add_completion_reply add_completion_reply; + struct remove_completion_reply remove_completion_reply; + struct query_completion_reply query_completion_reply; + struct set_completion_info_reply set_completion_info_reply; + struct add_fd_completion_reply add_fd_completion_reply; + struct load_init_registry_reply load_init_registry_reply; + struct save_branch_reply save_branch_reply; +}; + +#define SERVER_PROTOCOL_VERSION 341 + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WINESERVER_UK_PROTOCOL_H */ diff --git a/unifiedkernel/include/wineserver/user.h b/unifiedkernel/include/wineserver/user.h new file mode 100644 index 0000000..774b489 --- /dev/null +++ b/unifiedkernel/include/wineserver/user.h @@ -0,0 +1,168 @@ +/* + * user.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * user.h: + * Refered to Wine code + */ + +#ifndef _WINESERVER_USER_H +#define _WINESERVER_USER_H + +#ifdef CONFIG_UNIFIED_KERNEL +struct w32thread; +struct region; +struct window; +struct msg_queue; +struct hook_table; +struct window_class; +struct atom_table; +struct clipboard; + +enum user_object +{ + USER_WINDOW = 1, + USER_HOOK +}; + +#define DESKTOP_ATOM ((atom_t)32769) + +struct winstation +{ + struct object obj; /* object header */ + unsigned int flags; /* winstation flags */ + struct list_head entry; /* entry in global winstation list */ + struct list_head desktops; /* list of desktops of this winstation */ + struct clipboard *clipboard; /* clipboard information */ + struct atom_table *atom_table; /* global atom table */ +}; + +struct desktop +{ + struct object obj; /* object header */ + unsigned int flags; /* desktop flags */ + struct winstation *winstation; /* winstation this desktop belongs to */ + struct list_head entry; /* entry in winstation list of desktops */ + struct window *top_window; /* desktop window for this desktop */ + struct hook_table *global_hooks; /* table of global hooks on this desktop */ + struct timeout_user *close_timeout; /* timeout before closing the desktop */ + unsigned int users; /* processes and threads using this desktop */ +}; + +/* user handles functions */ + +extern user_handle_t alloc_user_handle( void *ptr, enum user_object type ); +extern void *get_user_object( user_handle_t handle, enum user_object type ); +extern void *get_user_object_handle( user_handle_t *handle, enum user_object type ); +extern user_handle_t get_user_full_handle( user_handle_t handle ); +extern void *free_user_handle( user_handle_t handle ); +extern void *next_user_handle( user_handle_t *handle, enum user_object type ); + +/* clipboard functions */ + +extern void cleanup_clipboard_thread( struct w32thread *thread ); + +/* hook functions */ + +extern void remove_thread_hooks( struct w32thread *thread ); +extern unsigned int get_active_hooks(void); + +/* queue functions */ + +extern void free_msg_queue( struct w32thread *thread ); +extern struct hook_table *get_queue_hooks( struct w32thread *thread ); +extern void set_queue_hooks( struct w32thread *thread, struct hook_table *hooks ); +extern void inc_queue_paint_count( struct w32thread *thread, int incr ); +extern void queue_cleanup_window( struct w32thread *thread, user_handle_t win ); +extern int init_thread_queue( struct w32thread *thread ); +extern int attach_thread_input( struct w32thread *thread_from, struct w32thread *thread_to ); +extern void detach_thread_input( struct w32thread *thread_from ); +extern void post_message( user_handle_t win, unsigned int message, + unsigned long wparam, unsigned long lparam ); +extern void post_win_event( struct w32thread *thread, unsigned int event, + user_handle_t win, unsigned int object_id, + unsigned int child_id, void *proc, + const WCHAR *module, data_size_t module_size, + user_handle_t handle ); + +/* region functions */ + +extern struct region *create_empty_region(void); +extern struct region *create_region_from_req_data( const void *data, data_size_t size ); +extern void free_region( struct region *region ); +extern void set_region_rect( struct region *region, const rectangle_t *rect ); +extern rectangle_t *get_region_data( const struct region *region, data_size_t max_size, + data_size_t *total_size ); +extern rectangle_t *get_region_data_and_free( struct region *region, data_size_t max_size, + data_size_t *total_size ); +extern int is_region_empty( const struct region *region ); +extern void get_region_extents( const struct region *region, rectangle_t *rect ); +extern void offset_region( struct region *region, int x, int y ); +extern struct region *copy_region( struct region *dst, const struct region *src ); +extern struct region *intersect_region( struct region *dst, const struct region *src1, + const struct region *src2 ); +extern struct region *subtract_region( struct region *dst, const struct region *src1, + const struct region *src2 ); +extern struct region *union_region( struct region *dst, const struct region *src1, + const struct region *src2 ); +extern struct region *xor_region( struct region *dst, const struct region *src1, + const struct region *src2 ); +extern int point_in_region( struct region *region, int x, int y ); +extern int rect_in_region( struct region *region, const rectangle_t *rect ); + +/* window functions */ + +extern struct w32process *get_top_window_owner( struct desktop *desktop ); +extern void close_desktop_window( struct desktop *desktop ); +extern void destroy_window( struct window *win ); +extern void destroy_thread_windows( struct w32thread *thread ); +extern int is_child_window( user_handle_t parent, user_handle_t child ); +extern int is_top_level_window( user_handle_t window ); +extern int is_window_visible( user_handle_t window ); +extern int make_window_active( user_handle_t window ); +extern struct w32thread *get_window_thread( user_handle_t handle ); +extern user_handle_t window_from_point( struct desktop *desktop, int x, int y ); +extern user_handle_t find_window_to_repaint( user_handle_t parent, struct w32thread *thread ); +extern struct window_class *get_window_class( user_handle_t window ); + +/* window class functions */ + +extern void destroy_process_classes( struct w32process *process ); +extern struct window_class *grab_class( struct w32process *process, atom_t atom, + void *instance, int *extra_bytes ); +extern void release_class( struct window_class *class ); +extern int is_desktop_class( struct window_class *class ); +extern atom_t get_class_atom( struct window_class *class ); +extern void *get_class_client_ptr( struct window_class *class ); + +/* windows station functions */ + +extern struct winstation *get_process_winstation( struct w32process *process, unsigned int access ); +extern struct desktop *get_thread_desktop( struct w32thread *thread, unsigned int access ); +extern void connect_process_winstation( struct w32process *process, struct w32thread *parent ); +extern void set_process_default_desktop( struct w32process *process, struct desktop *desktop, + obj_handle_t handle ); +extern void close_process_desktop( struct w32process *process ); +extern void close_thread_desktop( struct w32thread *thread ); + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WINESERVER_USER_H */ diff --git a/unifiedkernel/include/wineserver/wincon.h b/unifiedkernel/include/wineserver/wincon.h new file mode 100644 index 0000000..6f16d52 --- /dev/null +++ b/unifiedkernel/include/wineserver/wincon.h @@ -0,0 +1,292 @@ +/* + * wincon.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * wincon.h: + * Refered to Wine code + */ + +#ifndef _WINESERVER_WINCON_H +#define _WINESERVER_WINCON_H + +#include "win32.h" +#ifdef CONFIG_UNIFIED_KERNEL +#ifdef __cplusplus +extern "C" { +#endif + +#define CTRL_C_EVENT 0 +#define CTRL_BREAK_EVENT 1 +#define CTRL_CLOSE_EVENT 2 +#define CTRL_LOGOFF_EVENT 5 +#define CTRL_SHUTDOWN_EVENT 6 + +/* Console Mode flags */ +#define ENABLE_PROCESSED_INPUT 0x01 +#define ENABLE_LINE_INPUT 0x02 +#define ENABLE_ECHO_INPUT 0x04 +#define ENABLE_WINDOW_INPUT 0x08 +#define ENABLE_MOUSE_INPUT 0x10 + +#define ENABLE_PROCESSED_OUTPUT 0x01 +#define ENABLE_WRAP_AT_EOL_OUTPUT 0x02 + + +typedef BOOL (WINAPI *PHANDLER_ROUTINE)(DWORD dwCtrlType); + +/* Attributes flags: */ + +#define FOREGROUND_BLUE 0x0001 /* text color contains blue. */ +#define FOREGROUND_GREEN 0x0002 /* text color contains green. */ +#define FOREGROUND_RED 0x0004 /* text color contains red. */ +#define FOREGROUND_INTENSITY 0x0008 /* text color is intensified. */ +#define BACKGROUND_BLUE 0x0010 /* background color contains blue. */ +#define BACKGROUND_GREEN 0x0020 /* background color contains green. */ +#define BACKGROUND_RED 0x0040 /* background color contains red. */ +#define BACKGROUND_INTENSITY 0x0080 /* background color is intensified. */ + +typedef struct _CONSOLE_CURSOR_INFO { + DWORD dwSize; /* Between 1 & 100 for percentage of cell filled */ + BOOL bVisible; /* Visibility of cursor */ +} CONSOLE_CURSOR_INFO, *LPCONSOLE_CURSOR_INFO; + +typedef struct tagCOORD +{ + SHORT X; + SHORT Y; +} COORD, *LPCOORD; + +typedef struct tagSMALL_RECT +{ + SHORT Left; + SHORT Top; + SHORT Right; + SHORT Bottom; +} SMALL_RECT,*LPSMALL_RECT; + +typedef struct tagCONSOLE_SCREEN_BUFFER_INFO +{ + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; +} CONSOLE_SCREEN_BUFFER_INFO,*LPCONSOLE_SCREEN_BUFFER_INFO; + +typedef struct tagCHAR_INFO +{ + union + { + WCHAR UnicodeChar; + CHAR AsciiChar; + } Char; + WORD Attributes; +} CHAR_INFO,*LPCHAR_INFO; + +typedef struct tagKEY_EVENT_RECORD +{ + BOOL bKeyDown; /* 04 */ + WORD wRepeatCount; /* 08 */ + WORD wVirtualKeyCode; /* 0A */ + WORD wVirtualScanCode; /* 0C */ + union /* 0E */ + { + WCHAR UnicodeChar; /* 0E */ + CHAR AsciiChar; /* 0E */ + } uChar; + DWORD dwControlKeyState; /* 10 */ +} KEY_EVENT_RECORD,*LPKEY_EVENT_RECORD; + +/* dwControlKeyState bitmask */ +#define RIGHT_ALT_PRESSED 0x0001 +#define LEFT_ALT_PRESSED 0x0002 +#define RIGHT_CTRL_PRESSED 0x0004 +#define LEFT_CTRL_PRESSED 0x0008 +#define SHIFT_PRESSED 0x0010 +#define NUMLOCK_ON 0x0020 +#define SCROLLLOCK_ON 0x0040 +#define CAPSLOCK_ON 0x0080 +#define ENHANCED_KEY 0x0100 + +typedef struct tagMOUSE_EVENT_RECORD +{ + COORD dwMousePosition; + DWORD dwButtonState; + DWORD dwControlKeyState; + DWORD dwEventFlags; +} MOUSE_EVENT_RECORD,*LPMOUSE_EVENT_RECORD; + +#define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001 +#define RIGHTMOST_BUTTON_PRESSED 0x0002 +#define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004 +#define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008 +#define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010 + +#define MOUSE_MOVED 0x0001 +#define DOUBLE_CLICK 0x0002 +#define MOUSE_WHEELED 0x0004 + +typedef struct tagWINDOW_BUFFER_SIZE_RECORD +{ + COORD dwSize; +} WINDOW_BUFFER_SIZE_RECORD,*LPWINDOW_BUFFER_SIZE_RECORD; + +typedef struct tagMENU_EVENT_RECORD +{ + UINT dwCommandId; /* perhaps UINT16 ??? */ +} MENU_EVENT_RECORD,*LPMENU_EVENT_RECORD; + +typedef struct tagFOCUS_EVENT_RECORD +{ + BOOL bSetFocus; /* perhaps BOOL16 ??? */ +} FOCUS_EVENT_RECORD,*LPFOCUS_EVENT_RECORD; + +typedef struct tagINPUT_RECORD +{ + WORD EventType; /* 00 */ + union + { + KEY_EVENT_RECORD KeyEvent; + MOUSE_EVENT_RECORD MouseEvent; + WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; + MENU_EVENT_RECORD MenuEvent; + FOCUS_EVENT_RECORD FocusEvent; + } Event; +} INPUT_RECORD,*PINPUT_RECORD; + +/* INPUT_RECORD.wEventType */ +#define KEY_EVENT 0x01 +#define MOUSE_EVENT 0x02 +#define WINDOW_BUFFER_SIZE_EVENT 0x04 +#define MENU_EVENT 0x08 +#define FOCUS_EVENT 0x10 + +#define CONSOLE_TEXTMODE_BUFFER 1 + +#ifdef __i386__ +#define WINBASEAPI +/* Note: this should return a COORD, but calling convention for returning + * structures is different between Windows and gcc on i386. */ +DWORD WINAPI GetLargestConsoleWindowSize(HANDLE); + +static inline COORD __wine_GetLargestConsoleWindowSize_wrapper(HANDLE h) +{ + union { + COORD c; + DWORD dw; + } u; + u.dw = GetLargestConsoleWindowSize(h); + return u.c; +} +#define GetLargestConsoleWindowSize(h) __wine_GetLargestConsoleWindowSize_wrapper(h) + +#else /* __i386__ */ +WINBASEAPI COORD WINAPI GetLargestConsoleWindowSize(HANDLE); +#endif /* __i386__ */ + +WINBASEAPI BOOL WINAPI AllocConsole(VOID); +WINBASEAPI HANDLE WINAPI CreateConsoleScreenBuffer( DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES sa, DWORD dwFlags, + LPVOID lpScreenBufferData); +WINBASEAPI BOOL WINAPI FillConsoleOutputAttribute( HANDLE hConsoleOutput, WORD wAttribute, DWORD nLength, + COORD dwCoord, LPDWORD lpNumAttrsWritten); +WINBASEAPI BOOL WINAPI FillConsoleOutputCharacterA(HANDLE,CHAR,DWORD,COORD,LPDWORD); +WINBASEAPI BOOL WINAPI FillConsoleOutputCharacterW(HANDLE,WCHAR,DWORD,COORD,LPDWORD); +#define FillConsoleOutputCharacter WINELIB_NAME_AW(FillConsoleOutputCharacter) +WINBASEAPI BOOL WINAPI FlushConsoleInputBuffer( HANDLE handle); +WINBASEAPI BOOL WINAPI FreeConsole(VOID); +WINBASEAPI BOOL WINAPI GenerateConsoleCtrlEvent( DWORD dwCtrlEvent, DWORD dwProcessGroupID); +WINBASEAPI UINT WINAPI GetConsoleCP(VOID); +WINBASEAPI BOOL WINAPI GetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo); +WINBASEAPI BOOL WINAPI GetConsoleMode( HANDLE hcon,LPDWORD mode); +WINBASEAPI UINT WINAPI GetConsoleOutputCP(VOID); +WINBASEAPI BOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, + LPCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); +WINBASEAPI DWORD WINAPI GetConsoleTitleA(LPSTR title,DWORD size); +WINBASEAPI DWORD WINAPI GetConsoleTitleW(LPWSTR title, DWORD size); +#define GetConsoleTitle WINELIB_NAME_AW(GetConsoleTitle) +WINBASEAPI HWND WINAPI GetConsoleWindow(void); +WINBASEAPI BOOL WINAPI GetNumberOfConsoleInputEvents( HANDLE hcon,LPDWORD nrofevents); +WINBASEAPI BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons); +WINBASEAPI BOOL WINAPI PeekConsoleInputA( HANDLE handle, PINPUT_RECORD buffer, DWORD count, LPDWORD read ); +WINBASEAPI BOOL WINAPI PeekConsoleInputW( HANDLE handle, PINPUT_RECORD buffer, DWORD count, LPDWORD read ); +#define PeekConsoleInput WINELIB_NAME_AW(PeekConsoleInput) +WINBASEAPI BOOL WINAPI ReadConsoleA(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, + LPDWORD lpNumberOfCharsRead, LPVOID lpReserved); +WINBASEAPI BOOL WINAPI ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, + LPDWORD lpNumberOfCharsRead, LPVOID lpReserved); +#define ReadConsole WINELIB_NAME_AW(ReadConsole) +WINBASEAPI BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD nLength, + LPDWORD lpNumberOfEventsRead); +WINBASEAPI BOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput, PINPUT_RECORD lpBuffer, DWORD nLength, + LPDWORD lpNumberOfEventsRead); +#define ReadConsoleInput WINELIB_NAME_AW(ReadConsoleInput) +WINBASEAPI BOOL WINAPI ReadConsoleOutputA( HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD dwBufferSize, + COORD dwBufferCoord, LPSMALL_RECT lpReadRegion ); +WINBASEAPI BOOL WINAPI ReadConsoleOutputW( HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD dwBufferSize, + COORD dwBufferCoord, LPSMALL_RECT lpReadRegion ); +#define ReadConsoleOutput WINELIB_NAME_AW(ReadConsoleOutput) +WINBASEAPI BOOL WINAPI ReadConsoleOutputAttribute( HANDLE hConsoleOutput, LPWORD lpAttribute, DWORD nLength, + COORD dwReadCoord, LPDWORD lpNumberOfAttrsRead); +WINBASEAPI BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE,LPSTR,DWORD,COORD,LPDWORD); +WINBASEAPI BOOL WINAPI ReadConsoleOutputCharacterW(HANDLE,LPWSTR,DWORD,COORD,LPDWORD); +#define ReadConsoleOutputCharacter WINELIB_NAME_AW(ReadConsoleOutputCharacter) +WINBASEAPI BOOL WINAPI ScrollConsoleScreenBufferA( HANDLE hConsoleOutput, LPSMALL_RECT lpScrollRect, + LPSMALL_RECT lpClipRect, COORD dwDestOrigin, + LPCHAR_INFO lpFill); +WINBASEAPI BOOL WINAPI ScrollConsoleScreenBufferW( HANDLE hConsoleOutput, LPSMALL_RECT lpScrollRect, + LPSMALL_RECT lpClipRect, COORD dwDestOrigin, + LPCHAR_INFO lpFill); +#define ScrollConsoleScreenBuffer WINELIB_NAME_AW(ScrollConsoleScreenBuffer) +WINBASEAPI BOOL WINAPI SetConsoleActiveScreenBuffer( HANDLE hConsoleOutput); +WINBASEAPI BOOL WINAPI SetConsoleCP(UINT cp); +WINBASEAPI BOOL WINAPI SetConsoleCtrlHandler( PHANDLER_ROUTINE func, BOOL add); +WINBASEAPI BOOL WINAPI SetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo); +WINBASEAPI BOOL WINAPI SetConsoleCursorPosition(HANDLE,COORD); +WINBASEAPI BOOL WINAPI SetConsoleMode( HANDLE hcon, DWORD mode); +WINBASEAPI BOOL WINAPI SetConsoleOutputCP(UINT cp); +WINBASEAPI BOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize); +WINBASEAPI BOOL WINAPI SetConsoleTextAttribute( HANDLE hConsoleOutput,WORD wAttr); +WINBASEAPI BOOL WINAPI SetConsoleTitleA(LPCSTR title); +WINBASEAPI BOOL WINAPI SetConsoleTitleW(LPCWSTR title); +#define SetConsoleTitle WINELIB_NAME_AW(SetConsoleTitle) +WINBASEAPI BOOL WINAPI SetConsoleWindowInfo( HANDLE hcon, BOOL bAbsolute, LPSMALL_RECT window); +WINBASEAPI BOOL WINAPI WriteConsoleA(HANDLE, CONST VOID *,DWORD,LPDWORD,LPVOID); +WINBASEAPI BOOL WINAPI WriteConsoleW(HANDLE, CONST VOID *lpBuffer, DWORD,LPDWORD,LPVOID); +#define WriteConsole WINELIB_NAME_AW(WriteConsole) +WINBASEAPI BOOL WINAPI WriteConsoleInputA(HANDLE,const INPUT_RECORD *,DWORD,LPDWORD); +WINBASEAPI BOOL WINAPI WriteConsoleInputW(HANDLE,const INPUT_RECORD *,DWORD,LPDWORD); +#define WriteConsoleInput WINELIB_NAME_AW(WriteConsoleInput) +WINBASEAPI BOOL WINAPI WriteConsoleOutputA(HANDLE,const CHAR_INFO*,COORD,COORD,LPSMALL_RECT); +WINBASEAPI BOOL WINAPI WriteConsoleOutputW(HANDLE,const CHAR_INFO*,COORD,COORD,LPSMALL_RECT); +#define WriteConsoleOutput WINELIB_NAME_AW(WriteConsoleOutput) +WINBASEAPI BOOL WINAPI WriteConsoleOutputAttribute(HANDLE,CONST WORD *,DWORD,COORD,LPDWORD); +WINBASEAPI BOOL WINAPI WriteConsoleOutputCharacterA(HANDLE,LPCSTR,DWORD,COORD,LPDWORD); +WINBASEAPI BOOL WINAPI WriteConsoleOutputCharacterW(HANDLE,LPCWSTR,DWORD,COORD,LPDWORD); +#define WriteConsoleOutputCharacter WINELIB_NAME_AW(WriteConsoleOutputCharacter) + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WINESERVER_WINCON_H */ diff --git a/unifiedkernel/include/wineserver/winerror.h b/unifiedkernel/include/wineserver/winerror.h new file mode 100644 index 0000000..1ccd189 --- /dev/null +++ b/unifiedkernel/include/wineserver/winerror.h @@ -0,0 +1,2429 @@ +/* + * winerror.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * winerror.h: + * Refered to Wine code + */ + +#ifndef _WINESERVER_WINERROR_H +#define _WINESERVER_WINERROR_H + +#ifdef CONFIG_UNIFIED_KERNEL +#define FACILITY_NULL 0 +#define FACILITY_RPC 1 +#define FACILITY_DISPATCH 2 +#define FACILITY_STORAGE 3 +#define FACILITY_ITF 4 +#define FACILITY_WIN32 7 +#define FACILITY_WINDOWS 8 +#define FACILITY_SSPI 9 +#define FACILITY_SECURITY FACILITY_SSPI +#define FACILITY_CONTROL 10 +#define FACILITY_CERT 11 +#define FACILITY_INTERNET 12 +#define FACILITY_MEDIASERVER 13 +#define FACILITY_MSMQ 14 +#define FACILITY_SETUPAPI 15 +#define FACILITY_SCARD 16 +#define FACILITY_COMPLUS 17 +#define FACILITY_AAF 18 +#define FACILITY_URT 19 +#define FACILITY_ACS 20 +#define FACILITY_DPLAY 21 +#define FACILITY_UMI 22 +#define FACILITY_SXS 23 +#define FACILITY_WINDOWS_CE 24 +#define FACILITY_HTTP 25 +#define FACILITY_COMMONLOG 26 +#define FACILITY_USERMODE_FILTER_MANAGER 31 +#define FACILITY_BACKGROUNDCOPY 32 +#define FACILITY_CONFIGURATION 33 +#define FACILITY_STATE_MANAGEMENT 34 +#define FACILITY_METADIRECTORY 35 +#define FACILITY_WINDOWSUPDATE 36 +#define FACILITY_DIRECTORYSERVICE 37 +#define FACILITY_GRAPHICS 38 +#define FACILITY_SHELL 39 +#define FACILITY_TPM_SERVICES 40 +#define FACILITY_TPM_SOFTWARE 41 +#define FACILITY_PLA 48 +#define FACILITY_FVE 49 +#define FACILITY_WINDOWS_DEFENDER 80 + +#define SEVERITY_SUCCESS 0 +#define SEVERITY_ERROR 1 + + +#define MAKE_HRESULT(sev,fac,code) \ + ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) +#define MAKE_SCODE(sev,fac,code) \ + ((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) +#define SUCCEEDED(stat) ((HRESULT)(stat)>=0) +#define FAILED(stat) ((HRESULT)(stat)<0) +#define IS_ERROR(stat) (((unsigned long)(stat)>>31) == SEVERITY_ERROR) + +#define HRESULT_CODE(hr) ((hr) & 0xFFFF) +#define SCODE_CODE(sc) ((sc) & 0xFFFF) + +#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1FFF) +#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1FFF) + +#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1) +#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1) + +#define __HRESULT_FROM_WIN32(x) ((x) ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000)) : 0 ) +#ifndef _HRESULT_DEFINED +#define _HRESULT_DEFINED +# ifdef _MSC_VER +typedef long HRESULT; +# else +typedef int HRESULT; +# endif +#endif +static inline HRESULT HRESULT_FROM_WIN32(unsigned long x) +{ + return x ? ((HRESULT) ((x & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000)) : 0; +} +#define FACILITY_NT_BIT 0x10000000 +#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT)) + +/* SCODE <-> HRESULT functions */ +/* This macros is obsolete and should not be used in new apps. */ +#define GetScode(hr) ((SCODE)(hr)) +/* This macros is obsolete and should not be used in new apps. */ +#define ResultFromScode(sc) ((HRESULT)(sc)) + +#define NO_ERROR 0 +#define ERROR_SUCCESS 0 +#define ERROR_INVALID_FUNCTION 1 +#define ERROR_FILE_NOT_FOUND 2 +#define ERROR_PATH_NOT_FOUND 3 +#define ERROR_TOO_MANY_OPEN_FILES 4 +#define ERROR_ACCESS_DENIED 5 +#define ERROR_INVALID_HANDLE 6 +#define ERROR_ARENA_TRASHED 7 +#define ERROR_NOT_ENOUGH_MEMORY 8 +#define ERROR_INVALID_BLOCK 9 +#define ERROR_BAD_ENVIRONMENT 10 +#define ERROR_BAD_FORMAT 11 +#define ERROR_INVALID_ACCESS 12 +#define ERROR_INVALID_DATA 13 +#define ERROR_OUTOFMEMORY 14 +#define ERROR_INVALID_DRIVE 15 +#define ERROR_CURRENT_DIRECTORY 16 +#define ERROR_NOT_SAME_DEVICE 17 +#define ERROR_NO_MORE_FILES 18 +#define ERROR_WRITE_PROTECT 19 +#define ERROR_BAD_UNIT 20 +#define ERROR_NOT_READY 21 +#define ERROR_BAD_COMMAND 22 +#define ERROR_CRC 23 +#define ERROR_BAD_LENGTH 24 +#define ERROR_SEEK 25 +#define ERROR_NOT_DOS_DISK 26 +#define ERROR_SECTOR_NOT_FOUND 27 +#define ERROR_OUT_OF_PAPER 28 +#define ERROR_WRITE_FAULT 29 +#define ERROR_READ_FAULT 30 +#define ERROR_GEN_FAILURE 31 +#define ERROR_SHARING_VIOLATION 32 +#define ERROR_LOCK_VIOLATION 33 +#define ERROR_WRONG_DISK 34 +/* FIXME: 35 gets returned for some unsuccessful DeviceIoControl calls */ +#define ERROR_UNKNOWN_NAME_01 35 +#define ERROR_SHARING_BUFFER_EXCEEDED 36 +#define ERROR_HANDLE_EOF 38 +#define ERROR_HANDLE_DISK_FULL 39 +#define ERROR_NOT_SUPPORTED 50 +#define ERROR_REM_NOT_LIST 51 +#define ERROR_DUP_NAME 52 +#define ERROR_BAD_NETPATH 53 +#define ERROR_NETWORK_BUSY 54 +#define ERROR_DEV_NOT_EXIST 55 +#define ERROR_TOO_MANY_CMDS 56 +#define ERROR_ADAP_HDW_ERR 57 +#define ERROR_BAD_NET_RESP 58 +#define ERROR_UNEXP_NET_ERR 59 +#define ERROR_BAD_REM_ADAP 60 +#define ERROR_PRINTQ_FULL 61 +#define ERROR_NO_SPOOL_SPACE 62 +#define ERROR_PRINT_CANCELLED 63 +#define ERROR_NETNAME_DELETED 64 +#define ERROR_NETWORK_ACCESS_DENIED 65 +#define ERROR_BAD_DEV_TYPE 66 +#define ERROR_BAD_NET_NAME 67 +#define ERROR_TOO_MANY_NAMES 68 +#define ERROR_TOO_MANY_SESS 69 +#define ERROR_SHARING_PAUSED 70 +#define ERROR_REQ_NOT_ACCEP 71 +#define ERROR_REDIR_PAUSED 72 +#define ERROR_FILE_EXISTS 80 +#define ERROR_CANNOT_MAKE 82 +#define ERROR_FAIL_I24 83 +#define ERROR_OUT_OF_STRUCTURES 84 +#define ERROR_ALREADY_ASSIGNED 85 +#define ERROR_INVALID_PASSWORD 86 +#define ERROR_INVALID_PARAMETER 87 +#define ERROR_NET_WRITE_FAULT 88 +#define ERROR_NO_PROC_SLOTS 89 +#define ERROR_TOO_MANY_SEMAPHORES 100 +#define ERROR_EXCL_SEM_ALREADY_OWNED 101 +#define ERROR_SEM_IS_SET 102 +#define ERROR_TOO_MANY_SEM_REQUESTS 103 +#define ERROR_INVALID_AT_INTERRUPT_TIME 104 +#define ERROR_SEM_OWNER_DIED 105 +#define ERROR_SEM_USER_LIMIT 106 +#define ERROR_DISK_CHANGE 107 +#define ERROR_DRIVE_LOCKED 108 +#define ERROR_BROKEN_PIPE 109 +#define ERROR_OPEN_FAILED 110 +#define ERROR_BUFFER_OVERFLOW 111 +#define ERROR_DISK_FULL 112 +#define ERROR_NO_MORE_SEARCH_HANDLES 113 +#define ERROR_INVALID_TARGET_HANDLE 114 +#define ERROR_INVALID_CATEGORY 117 +#define ERROR_INVALID_VERIFY_SWITCH 118 +#define ERROR_BAD_DRIVER_LEVEL 119 +#define ERROR_CALL_NOT_IMPLEMENTED 120 +#define ERROR_SEM_TIMEOUT 121 +#define ERROR_INSUFFICIENT_BUFFER 122 +#define ERROR_INVALID_NAME 123 +#define ERROR_INVALID_LEVEL 124 +#define ERROR_NO_VOLUME_LABEL 125 +#define ERROR_MOD_NOT_FOUND 126 +#define ERROR_PROC_NOT_FOUND 127 +#define ERROR_WAIT_NO_CHILDREN 128 +#define ERROR_CHILD_NOT_COMPLETE 129 +#define ERROR_DIRECT_ACCESS_HANDLE 130 +#define ERROR_NEGATIVE_SEEK 131 +#define ERROR_SEEK_ON_DEVICE 132 +#define ERROR_IS_JOIN_TARGET 133 +#define ERROR_IS_JOINED 134 +#define ERROR_IS_SUBSTED 135 +#define ERROR_NOT_JOINED 136 +#define ERROR_NOT_SUBSTED 137 +#define ERROR_JOIN_TO_JOIN 138 +#define ERROR_SUBST_TO_SUBST 139 +#define ERROR_JOIN_TO_SUBST 140 +#define ERROR_SUBST_TO_JOIN 141 +#define ERROR_BUSY_DRIVE 142 +#define ERROR_SAME_DRIVE 143 +#define ERROR_DIR_NOT_ROOT 144 +#define ERROR_DIR_NOT_EMPTY 145 +#define ERROR_IS_SUBST_PATH 146 +#define ERROR_IS_JOIN_PATH 147 +#define ERROR_PATH_BUSY 148 +#define ERROR_IS_SUBST_TARGET 149 +#define ERROR_SYSTEM_TRACE 150 +#define ERROR_INVALID_EVENT_COUNT 151 +#define ERROR_TOO_MANY_MUXWAITERS 152 +#define ERROR_INVALID_LIST_FORMAT 153 +#define ERROR_LABEL_TOO_LONG 154 +#define ERROR_TOO_MANY_TCBS 155 +#define ERROR_SIGNAL_REFUSED 156 +#define ERROR_DISCARDED 157 +#define ERROR_NOT_LOCKED 158 +#define ERROR_BAD_THREADID_ADDR 159 +#define ERROR_BAD_ARGUMENTS 160 +#define ERROR_BAD_PATHNAME 161 +#define ERROR_SIGNAL_PENDING 162 +#define ERROR_MAX_THRDS_REACHED 164 +#define ERROR_LOCK_FAILED 167 +#define ERROR_BUSY 170 +#define ERROR_CANCEL_VIOLATION 173 +#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174 +#define ERROR_INVALID_SEGMENT_NUMBER 180 +#define ERROR_INVALID_ORDINAL 182 +#define ERROR_ALREADY_EXISTS 183 +#define ERROR_INVALID_FLAG_NUMBER 186 +#define ERROR_SEM_NOT_FOUND 187 +#define ERROR_INVALID_STARTING_CODESEG 188 +#define ERROR_INVALID_STACKSEG 189 +#define ERROR_INVALID_MODULETYPE 190 +#define ERROR_INVALID_EXE_SIGNATURE 191 +#define ERROR_EXE_MARKED_INVALID 192 +#define ERROR_BAD_EXE_FORMAT 193 +#define ERROR_ITERATED_DATA_EXCEEDS_64k 194 +#define ERROR_INVALID_MINALLOCSIZE 195 +#define ERROR_DYNLINK_FROM_INVALID_RING 196 +#define ERROR_IOPL_NOT_ENABLED 197 +#define ERROR_INVALID_SEGDPL 198 +#define ERROR_AUTODATASEG_EXCEEDS_64k 199 +#define ERROR_RING2SEG_MUST_BE_MOVABLE 200 +#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201 +#define ERROR_INFLOOP_IN_RELOC_CHAIN 202 +#define ERROR_ENVVAR_NOT_FOUND 203 +#define ERROR_NO_SIGNAL_SENT 205 +#define ERROR_FILENAME_EXCED_RANGE 206 +#define ERROR_RING2_STACK_IN_USE 207 +#define ERROR_META_EXPANSION_TOO_LONG 208 +#define ERROR_INVALID_SIGNAL_NUMBER 209 +#define ERROR_THREAD_1_INACTIVE 210 +#define ERROR_LOCKED 212 +#define ERROR_TOO_MANY_MODULES 214 +#define ERROR_NESTING_NOT_ALLOWED 215 +#define ERROR_EXE_MACHINE_TYPE_MISMATCH 216 +#define ERROR_BAD_PIPE 230 +#define ERROR_PIPE_BUSY 231 +#define ERROR_NO_DATA 232 +#define ERROR_PIPE_NOT_CONNECTED 233 +#define ERROR_MORE_DATA 234 +#define ERROR_VC_DISCONNECTED 240 +#define ERROR_INVALID_EA_NAME 254 +#define ERROR_EA_LIST_INCONSISTENT 255 +#define ERROR_NO_MORE_ITEMS 259 +#define ERROR_CANNOT_COPY 266 +#define ERROR_DIRECTORY 267 +#define ERROR_EAS_DIDNT_FIT 275 +#define ERROR_EA_FILE_CORRUPT 276 +#define ERROR_EA_TABLE_FULL 277 +#define ERROR_INVALID_EA_HANDLE 278 +#define ERROR_EAS_NOT_SUPPORTED 282 +#define ERROR_NOT_OWNER 288 +#define ERROR_TOO_MANY_POSTS 298 +#define ERROR_PARTIAL_COPY 299 +#define ERROR_OPLOCK_NOT_GRANTED 300 +#define ERROR_INVALID_OPLOCK_PROTOCOL 301 +#define ERROR_DISK_TOO_FRAGMENTED 302 +#define ERROR_MR_MID_NOT_FOUND 317 +#define ERROR_SCOPE_NOT_FOUND 318 +#define ERROR_FAIL_NOACTION_REBOOT 350 +#define ERROR_FAIL_SHUTDOWN 351 +#define ERROR_FAIL_RESTART 352 +#define ERROR_MAX_SESSIONS_REACHED 353 +#define ERROR_INVALID_ADDRESS 487 +#define ERROR_USER_PROFILE_LOAD 500 +#define ERROR_ARITHMETIC_OVERFLOW 534 +#define ERROR_PIPE_CONNECTED 535 +#define ERROR_PIPE_LISTENING 536 +#define ERROR_EA_ACCESS_DENIED 994 +#define ERROR_OPERATION_ABORTED 995 +#define ERROR_IO_INCOMPLETE 996 +#define ERROR_IO_PENDING 997 +#define ERROR_NOACCESS 998 +#define ERROR_SWAPERROR 999 +#define ERROR_STACK_OVERFLOW 1001 +#define ERROR_INVALID_MESSAGE 1002 +#define ERROR_CAN_NOT_COMPLETE 1003 +#define ERROR_INVALID_FLAGS 1004 +#define ERROR_UNRECOGNIZED_VOLUME 1005 +#define ERROR_FILE_INVALID 1006 +#define ERROR_FULLSCREEN_MODE 1007 +#define ERROR_NO_TOKEN 1008 +#define ERROR_BADDB 1009 +#define ERROR_BADKEY 1010 +#define ERROR_CANTOPEN 1011 +#define ERROR_CANTREAD 1012 +#define ERROR_CANTWRITE 1013 +#define ERROR_REGISTRY_RECOVERED 1014 +#define ERROR_REGISTRY_CORRUPT 1015 +#define ERROR_REGISTRY_IO_FAILED 1016 +#define ERROR_NOT_REGISTRY_FILE 1017 +#define ERROR_KEY_DELETED 1018 +#define ERROR_NO_LOG_SPACE 1019 +#define ERROR_KEY_HAS_CHILDREN 1020 +#define ERROR_CHILD_MUST_BE_VOLATILE 1021 +#define ERROR_NOTIFY_ENUM_DIR 1022 +#define ERROR_DEPENDENT_SERVICES_RUNNING 1051 +#define ERROR_INVALID_SERVICE_CONTROL 1052 +#define ERROR_SERVICE_REQUEST_TIMEOUT 1053 +#define ERROR_SERVICE_NO_THREAD 1054 +#define ERROR_SERVICE_DATABASE_LOCKED 1055 +#define ERROR_SERVICE_ALREADY_RUNNING 1056 +#define ERROR_INVALID_SERVICE_ACCOUNT 1057 +#define ERROR_SERVICE_DISABLED 1058 +#define ERROR_CIRCULAR_DEPENDENCY 1059 +#define ERROR_SERVICE_DOES_NOT_EXIST 1060 +#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061 +#define ERROR_SERVICE_NOT_ACTIVE 1062 +#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063 +#define ERROR_EXCEPTION_IN_SERVICE 1064 +#define ERROR_DATABASE_DOES_NOT_EXIST 1065 +#define ERROR_SERVICE_SPECIFIC_ERROR 1066 +#define ERROR_PROCESS_ABORTED 1067 +#define ERROR_SERVICE_DEPENDENCY_FAIL 1068 +#define ERROR_SERVICE_LOGON_FAILED 1069 +#define ERROR_SERVICE_START_HANG 1070 +#define ERROR_INVALID_SERVICE_LOCK 1071 +#define ERROR_SERVICE_MARKED_FOR_DELETE 1072 +#define ERROR_SERVICE_EXISTS 1073 +#define ERROR_ALREADY_RUNNING_LKG 1074 +#define ERROR_SERVICE_DEPENDENCY_DELETED 1075 +#define ERROR_BOOT_ALREADY_ACCEPTED 1076 +#define ERROR_SERVICE_NEVER_STARTED 1077 +#define ERROR_DUPLICATE_SERVICE_NAME 1078 +#define ERROR_DIFFERENT_SERVICE_ACCOUNT 1079 +#define ERROR_CANNOT_DETECT_DRIVER_FAILURE 1080 +#define ERROR_CANNOT_DETECT_PROCESS_ABORT 1081 +#define ERROR_NO_RECOVERY_PROGRAM 1082 +#define ERROR_SERVICE_NOT_IN_EXE 1083 +#define ERROR_END_OF_MEDIA 1100 +#define ERROR_FILEMARK_DETECTED 1101 +#define ERROR_BEGINNING_OF_MEDIA 1102 +#define ERROR_SETMARK_DETECTED 1103 +#define ERROR_NO_DATA_DETECTED 1104 +#define ERROR_PARTITION_FAILURE 1105 +#define ERROR_INVALID_BLOCK_LENGTH 1106 +#define ERROR_DEVICE_NOT_PARTITIONED 1107 +#define ERROR_UNABLE_TO_LOCK_MEDIA 1108 +#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109 +#define ERROR_MEDIA_CHANGED 1110 +#define ERROR_BUS_RESET 1111 +#define ERROR_NO_MEDIA_IN_DRIVE 1112 +#define ERROR_NO_UNICODE_TRANSLATION 1113 +#define ERROR_DLL_INIT_FAILED 1114 +#define ERROR_SHUTDOWN_IN_PROGRESS 1115 +#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116 +#define ERROR_IO_DEVICE 1117 +#define ERROR_SERIAL_NO_DEVICE 1118 +#define ERROR_IRQ_BUSY 1119 +#define ERROR_MORE_WRITES 1120 +#define ERROR_COUNTER_TIMEOUT 1121 +#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122 +#define ERROR_FLOPPY_WRONG_CYLINDER 1123 +#define ERROR_FLOPPY_UNKNOWN_ERROR 1124 +#define ERROR_FLOPPY_BAD_REGISTERS 1125 +#define ERROR_DISK_RECALIBRATE_FAILED 1126 +#define ERROR_DISK_OPERATION_FAILED 1127 +#define ERROR_DISK_RESET_FAILED 1128 +#define ERROR_EOM_OVERFLOW 1129 +#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130 +#define ERROR_POSSIBLE_DEADLOCK 1131 +#define ERROR_MAPPED_ALIGNMENT 1132 +#define ERROR_SET_POWER_STATE_VETOED 1140 +#define ERROR_SET_POWER_STATE_FAILED 1141 +#define ERROR_TOO_MANY_LINKS 1142 +#define ERROR_OLD_WIN_VERSION 1150 +#define ERROR_APP_WRONG_OS 1151 +#define ERROR_SINGLE_INSTANCE_APP 1152 +#define ERROR_RMODE_APP 1153 +#define ERROR_INVALID_DLL 1154 +#define ERROR_NO_ASSOCIATION 1155 +#define ERROR_DDE_FAIL 1156 +#define ERROR_DLL_NOT_FOUND 1157 +#define ERROR_NO_MORE_USER_HANDLES 1158 +#define ERROR_MESSAGE_SYNC_ONLY 1159 +#define ERROR_SOURCE_ELEMENT_EMPTY 1160 +#define ERROR_DESTINATION_ELEMENT_FULL 1161 +#define ERROR_ILLEGAL_ELEMENT_ADDRESS 1162 +#define ERROR_MAGAZINE_NOT_PRESENT 1163 +#define ERROR_DEVICE_REINITIALIZATION_NEEDED 1164 +#define ERROR_DEVICE_REQUIRES_CLEANING 1165 +#define ERROR_DEVICE_DOOR_OPEN 1166 +#define ERROR_DEVICE_NOT_CONNECTED 1167 +#define ERROR_NOT_FOUND 1168 +#define ERROR_NO_MATCH 1169 +#define ERROR_SET_NOT_FOUND 1170 +#define ERROR_POINT_NOT_FOUND 1171 +#define ERROR_NO_TRACKING_SERVICE 1172 +#define ERROR_NO_VOLUME_ID 1173 +#define ERROR_UNABLE_TO_REMOVE_REPLACED 1175 +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT 1176 +#define ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 1177 +#define ERROR_JOURNAL_DELETE_IN_PROGRESS 1178 +#define ERROR_JOURNAL_NOT_ACTIVE 1179 +#define ERROR_POTENTIAL_FILE_FOUND 1180 +#define ERROR_JOURNAL_ENTRY_DELETED 1181 +#define ERROR_BAD_DEVICE 1200 +#define ERROR_CONNECTION_UNAVAIL 1201 +#define ERROR_DEVICE_ALREADY_REMEMBERED 1202 +#define ERROR_NO_NET_OR_BAD_PATH 1203 +#define ERROR_BAD_PROVIDER 1204 +#define ERROR_CANNOT_OPEN_PROFILE 1205 +#define ERROR_BAD_PROFILE 1206 +#define ERROR_NOT_CONTAINER 1207 +#define ERROR_EXTENDED_ERROR 1208 +#define ERROR_INVALID_GROUPNAME 1209 +#define ERROR_INVALID_COMPUTERNAME 1210 +#define ERROR_INVALID_EVENTNAME 1211 +#define ERROR_INVALID_DOMAINNAME 1212 +#define ERROR_INVALID_SERVICENAME 1213 +#define ERROR_INVALID_NETNAME 1214 +#define ERROR_INVALID_SHARENAME 1215 +#define ERROR_INVALID_PASSWORDNAME 1216 +#define ERROR_INVALID_MESSAGENAME 1217 +#define ERROR_INVALID_MESSAGEDEST 1218 +#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219 +#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220 +#define ERROR_DUP_DOMAINNAME 1221 +#define ERROR_NO_NETWORK 1222 +#define ERROR_CANCELLED 1223 +#define ERROR_USER_MAPPED_FILE 1224 +#define ERROR_CONNECTION_REFUSED 1225 +#define ERROR_GRACEFUL_DISCONNECT 1226 +#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227 +#define ERROR_ADDRESS_NOT_ASSOCIATED 1228 +#define ERROR_CONNECTION_INVALID 1229 +#define ERROR_CONNECTION_ACTIVE 1230 +#define ERROR_NETWORK_UNREACHABLE 1231 +#define ERROR_HOST_UNREACHABLE 1232 +#define ERROR_PROTOCOL_UNREACHABLE 1233 +#define ERROR_PORT_UNREACHABLE 1234 +#define ERROR_REQUEST_ABORTED 1235 +#define ERROR_CONNECTION_ABORTED 1236 +#define ERROR_RETRY 1237 +#define ERROR_CONNECTION_COUNT_LIMIT 1238 +#define ERROR_LOGIN_TIME_RESTRICTION 1239 +#define ERROR_LOGIN_WKSTA_RESTRICTION 1240 +#define ERROR_INCORRECT_ADDRESS 1241 +#define ERROR_ALREADY_REGISTERED 1242 +#define ERROR_SERVICE_NOT_FOUND 1243 +#define ERROR_NOT_AUTHENTICATED 1244 +#define ERROR_NOT_LOGGED_ON 1245 +#define ERROR_CONTINUE 1246 +#define ERROR_ALREADY_INITIALIZED 1247 +#define ERROR_NO_MORE_DEVICES 1248 +#define ERROR_NO_SUCH_SITE 1249 +#define ERROR_DOMAIN_CONTROLLER_EXISTS 1250 +#define ERROR_ONLY_IF_CONNECTED 1251 +#define ERROR_OVERRIDE_NOCHANGES 1252 +#define ERROR_BAD_USER_PROFILE 1253 +#define ERROR_NOT_SUPPORTED_ON_SBS 1254 +#define ERROR_SERVER_SHUTDOWN_IN_PROGRESS 1255 +#define ERROR_HOST_DOWN 1256 +#define ERROR_ACCESS_DISABLED_BY_POLICY 1260 +#define ERROR_REG_NAT_CONSUMPTION 1261 +#define ERROR_PKINIT_FAILURE 1263 +#define ERROR_SMARTCARD_SUBSYSTEM_FAILURE 1264 +#define ERROR_DOWNGRADE_DETECTED 1265 +#define ERROR_MACHINE_LOCKED 1271 +#define ERROR_CALLBACK_SUPPLIED_INVALID_DATA 1273 +#define ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED 1274 +#define ERROR_DRIVER_BLOCKED 1275 +#define ERROR_INVALID_IMPORT_OF_NON_DLL 1276 +#define ERROR_NOT_ALL_ASSIGNED 1300 +#define ERROR_SOME_NOT_MAPPED 1301 +#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302 +#define ERROR_LOCAL_USER_SESSION_KEY 1303 +#define ERROR_NULL_LM_PASSWORD 1304 +#define ERROR_UNKNOWN_REVISION 1305 +#define ERROR_REVISION_MISMATCH 1306 +#define ERROR_INVALID_OWNER 1307 +#define ERROR_INVALID_PRIMARY_GROUP 1308 +#define ERROR_NO_IMPERSONATION_TOKEN 1309 +#define ERROR_CANT_DISABLE_MANDATORY 1310 +#define ERROR_NO_LOGON_SERVERS 1311 +#define ERROR_NO_SUCH_LOGON_SESSION 1312 +#define ERROR_NO_SUCH_PRIVILEGE 1313 +#define ERROR_PRIVILEGE_NOT_HELD 1314 +#define ERROR_INVALID_ACCOUNT_NAME 1315 +#define ERROR_USER_EXISTS 1316 +#define ERROR_NO_SUCH_USER 1317 +#define ERROR_GROUP_EXISTS 1318 +#define ERROR_NO_SUCH_GROUP 1319 +#define ERROR_MEMBER_IN_GROUP 1320 +#define ERROR_MEMBER_NOT_IN_GROUP 1321 +#define ERROR_LAST_ADMIN 1322 +#define ERROR_WRONG_PASSWORD 1323 +#define ERROR_ILL_FORMED_PASSWORD 1324 +#define ERROR_PASSWORD_RESTRICTION 1325 +#define ERROR_LOGON_FAILURE 1326 +#define ERROR_ACCOUNT_RESTRICTION 1327 +#define ERROR_INVALID_LOGON_HOURS 1328 +#define ERROR_INVALID_WORKSTATION 1329 +#define ERROR_PASSWORD_EXPIRED 1330 +#define ERROR_ACCOUNT_DISABLED 1331 +#define ERROR_NONE_MAPPED 1332 +#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333 +#define ERROR_LUIDS_EXHAUSTED 1334 +#define ERROR_INVALID_SUB_AUTHORITY 1335 +#define ERROR_INVALID_ACL 1336 +#define ERROR_INVALID_SID 1337 +#define ERROR_INVALID_SECURITY_DESCR 1338 +#define ERROR_BAD_INHERITANCE_ACL 1340 +#define ERROR_SERVER_DISABLED 1341 +#define ERROR_SERVER_NOT_DISABLED 1342 +#define ERROR_INVALID_ID_AUTHORITY 1343 +#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344 +#define ERROR_INVALID_GROUP_ATTRIBUTES 1345 +#define ERROR_BAD_IMPERSONATION_LEVEL 1346 +#define ERROR_CANT_OPEN_ANONYMOUS 1347 +#define ERROR_BAD_VALIDATION_CLASS 1348 +#define ERROR_BAD_TOKEN_TYPE 1349 +#define ERROR_NO_SECURITY_ON_OBJECT 1350 +#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351 +#define ERROR_INVALID_SERVER_STATE 1352 +#define ERROR_INVALID_DOMAIN_STATE 1353 +#define ERROR_INVALID_DOMAIN_ROLE 1354 +#define ERROR_NO_SUCH_DOMAIN 1355 +#define ERROR_DOMAIN_EXISTS 1356 +#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357 +#define ERROR_INTERNAL_DB_CORRUPTION 1358 +#define ERROR_INTERNAL_ERROR 1359 +#define ERROR_GENERIC_NOT_MAPPED 1360 +#define ERROR_BAD_DESCRIPTOR_FORMAT 1361 +#define ERROR_NOT_LOGON_PROCESS 1362 +#define ERROR_LOGON_SESSION_EXISTS 1363 +#define ERROR_NO_SUCH_PACKAGE 1364 +#define ERROR_BAD_LOGON_SESSION_STATE 1365 +#define ERROR_LOGON_SESSION_COLLISION 1366 +#define ERROR_INVALID_LOGON_TYPE 1367 +#define ERROR_CANNOT_IMPERSONATE 1368 +#define ERROR_RXACT_INVALID_STATE 1369 +#define ERROR_RXACT_COMMIT_FAILURE 1370 +#define ERROR_SPECIAL_ACCOUNT 1371 +#define ERROR_SPECIAL_GROUP 1372 +#define ERROR_SPECIAL_USER 1373 +#define ERROR_MEMBERS_PRIMARY_GROUP 1374 +#define ERROR_TOKEN_ALREADY_IN_USE 1375 +#define ERROR_NO_SUCH_ALIAS 1376 +#define ERROR_MEMBER_NOT_IN_ALIAS 1377 +#define ERROR_MEMBER_IN_ALIAS 1378 +#define ERROR_ALIAS_EXISTS 1379 +#define ERROR_LOGON_NOT_GRANTED 1380 +#define ERROR_TOO_MANY_SECRETS 1381 +#define ERROR_SECRET_TOO_LONG 1382 +#define ERROR_INTERNAL_DB_ERROR 1383 +#define ERROR_TOO_MANY_CONTEXT_IDS 1384 +#define ERROR_LOGON_TYPE_NOT_GRANTED 1385 +#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386 +#define ERROR_NO_SUCH_MEMBER 1387 +#define ERROR_INVALID_MEMBER 1388 +#define ERROR_TOO_MANY_SIDS 1389 +#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390 +#define ERROR_NO_INHERITANCE 1391 +#define ERROR_FILE_CORRUPT 1392 +#define ERROR_DISK_CORRUPT 1393 +#define ERROR_NO_USER_SESSION_KEY 1394 +#define ERROR_LICENSE_QUOTA_EXCEEDED 1395 +#define ERROR_WRONG_TARGET_NAME 1396 +#define ERROR_MUTUAL_AUTH_FAILED 1397 +#define ERROR_TIME_SKEW 1398 +#define ERROR_CURRENT_DOMAIN_NOT_ALLOWED 1399 +#define ERROR_INVALID_WINDOW_HANDLE 1400 +#define ERROR_INVALID_MENU_HANDLE 1401 +#define ERROR_INVALID_CURSOR_HANDLE 1402 +#define ERROR_INVALID_ACCEL_HANDLE 1403 +#define ERROR_INVALID_HOOK_HANDLE 1404 +#define ERROR_INVALID_DWP_HANDLE 1405 +#define ERROR_TLW_WITH_WSCHILD 1406 +#define ERROR_CANNOT_FIND_WND_CLASS 1407 +#define ERROR_WINDOW_OF_OTHER_THREAD 1408 +#define ERROR_HOTKEY_ALREADY_REGISTERED 1409 +#define ERROR_CLASS_ALREADY_EXISTS 1410 +#define ERROR_CLASS_DOES_NOT_EXIST 1411 +#define ERROR_CLASS_HAS_WINDOWS 1412 +#define ERROR_INVALID_INDEX 1413 +#define ERROR_INVALID_ICON_HANDLE 1414 +#define ERROR_PRIVATE_DIALOG_INDEX 1415 +#define ERROR_LISTBOX_ID_NOT_FOUND 1416 +#define ERROR_NO_WILDCARD_CHARACTERS 1417 +#define ERROR_CLIPBOARD_NOT_OPEN 1418 +#define ERROR_HOTKEY_NOT_REGISTERED 1419 +#define ERROR_WINDOW_NOT_DIALOG 1420 +#define ERROR_CONTROL_ID_NOT_FOUND 1421 +#define ERROR_INVALID_COMBOBOX_MESSAGE 1422 +#define ERROR_WINDOW_NOT_COMBOBOX 1423 +#define ERROR_INVALID_EDIT_HEIGHT 1424 +#define ERROR_DC_NOT_FOUND 1425 +#define ERROR_INVALID_HOOK_FILTER 1426 +#define ERROR_INVALID_FILTER_PROC 1427 +#define ERROR_HOOK_NEEDS_HMOD 1428 +#define ERROR_GLOBAL_ONLY_HOOK 1429 +#define ERROR_JOURNAL_HOOK_SET 1430 +#define ERROR_HOOK_NOT_INSTALLED 1431 +#define ERROR_INVALID_LB_MESSAGE 1432 +#define ERROR_SETCOUNT_ON_BAD_LB 1433 +#define ERROR_LB_WITHOUT_TABSTOPS 1434 +#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435 +#define ERROR_CHILD_WINDOW_MENU 1436 +#define ERROR_NO_SYSTEM_MENU 1437 +#define ERROR_INVALID_MSGBOX_STYLE 1438 +#define ERROR_INVALID_SPI_VALUE 1439 +#define ERROR_SCREEN_ALREADY_LOCKED 1440 +#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441 +#define ERROR_NOT_CHILD_WINDOW 1442 +#define ERROR_INVALID_GW_COMMAND 1443 +#define ERROR_INVALID_THREAD_ID 1444 +#define ERROR_NON_MDICHILD_WINDOW 1445 +#define ERROR_POPUP_ALREADY_ACTIVE 1446 +#define ERROR_NO_SCROLLBARS 1447 +#define ERROR_INVALID_SCROLLBAR_RANGE 1448 +#define ERROR_INVALID_SHOWWIN_COMMAND 1449 +#define ERROR_NO_SYSTEM_RESOURCES 1450 +#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451 +#define ERROR_PAGED_SYSTEM_RESOURCES 1452 +#define ERROR_WORKING_SET_QUOTA 1453 +#define ERROR_PAGEFILE_QUOTA 1454 +#define ERROR_COMMITMENT_LIMIT 1455 +#define ERROR_MENU_ITEM_NOT_FOUND 1456 +#define ERROR_INVALID_KEYBOARD_HANDLE 1457 +#define ERROR_HOOK_TYPE_NOT_ALLOWED 1458 +#define ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION 1459 +#define ERROR_TIMEOUT 1460 +#define ERROR_INVALID_MONITOR_HANDLE 1461 +#define ERROR_EVENTLOG_FILE_CORRUPT 1500 +#define ERROR_EVENTLOG_CANT_START 1501 +#define ERROR_LOG_FILE_FULL 1502 +#define ERROR_EVENTLOG_FILE_CHANGED 1503 +#define ERROR_INSTALL_SERVICE_FAILURE 1601 +#define ERROR_INSTALL_USEREXIT 1602 +#define ERROR_INSTALL_FAILURE 1603 +#define ERROR_INSTALL_SUSPEND 1604 +#define ERROR_UNKNOWN_PRODUCT 1605 +#define ERROR_UNKNOWN_FEATURE 1606 +#define ERROR_UNKNOWN_COMPONENT 1607 +#define ERROR_UNKNOWN_PROPERTY 1608 +#define ERROR_INVALID_HANDLE_STATE 1609 +#define ERROR_BAD_CONFIGURATION 1610 +#define ERROR_INDEX_ABSENT 1611 +#define ERROR_INSTALL_SOURCE_ABSENT 1612 +#define ERROR_INSTALL_PACKAGE_VERSION 1613 +#define ERROR_PRODUCT_UNINSTALLED 1614 +#define ERROR_BAD_QUERY_SYNTAX 1615 +#define ERROR_INVALID_FIELD 1616 +#define ERROR_DEVICE_REMOVED 1617 +#define ERROR_INSTALL_ALREADY_RUNNING 1618 +#define ERROR_INSTALL_PACKAGE_OPEN_FAILED 1619 +#define ERROR_INSTALL_PACKAGE_INVALID 1620 +#define ERROR_INSTALL_UI_FAILURE 1621 +#define ERROR_INSTALL_LOG_FAILURE 1622 +#define ERROR_INSTALL_LANGUAGE_UNSUPPORTED 1623 +#define ERROR_INSTALL_TRANSFORM_FAILURE 1624 +#define ERROR_INSTALL_PACKAGE_REJECTED 1625 +#define ERROR_FUNCTION_NOT_CALLED 1626 +#define ERROR_FUNCTION_FAILED 1627 +#define ERROR_INVALID_TABLE 1628 +#define ERROR_DATATYPE_MISMATCH 1629 +#define ERROR_UNSUPPORTED_TYPE 1630 +#define ERROR_CREATE_FAILED 1631 +#define ERROR_INSTALL_TEMP_UNWRITABLE 1632 +#define ERROR_INSTALL_PLATFORM_UNSUPPORTED 1633 +#define ERROR_INSTALL_NOTUSED 1634 +#define ERROR_PATCH_PACKAGE_OPEN_FAILED 1635 +#define ERROR_PATCH_PACKAGE_INVALID 1636 +#define ERROR_PATCH_PACKAGE_UNSUPPORTED 1637 +#define ERROR_PRODUCT_VERSION 1638 +#define ERROR_INVALID_COMMAND_LINE 1639 +#define ERROR_INSTALL_REMOTE_DISALLOWED 1640 +#define ERROR_SUCCESS_REBOOT_INITIATED 1641 +#define ERROR_UNKNOWN_PATCH 1647 +#define RPC_S_INVALID_STRING_BINDING 1700 +#define RPC_S_WRONG_KIND_OF_BINDING 1701 +#define RPC_S_INVALID_BINDING 1702 +#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703 +#define RPC_S_INVALID_RPC_PROTSEQ 1704 +#define RPC_S_INVALID_STRING_UUID 1705 +#define RPC_S_INVALID_ENDPOINT_FORMAT 1706 +#define RPC_S_INVALID_NET_ADDR 1707 +#define RPC_S_NO_ENDPOINT_FOUND 1708 +#define RPC_S_INVALID_TIMEOUT 1709 +#define RPC_S_OBJECT_NOT_FOUND 1710 +#define RPC_S_ALREADY_REGISTERED 1711 +#define RPC_S_TYPE_ALREADY_REGISTERED 1712 +#define RPC_S_ALREADY_LISTENING 1713 +#define RPC_S_NO_PROTSEQS_REGISTERED 1714 +#define RPC_S_NOT_LISTENING 1715 +#define RPC_S_UNKNOWN_MGR_TYPE 1716 +#define RPC_S_UNKNOWN_IF 1717 +#define RPC_S_NO_BINDINGS 1718 +#define RPC_S_NO_PROTSEQS 1719 +#define RPC_S_CANT_CREATE_ENDPOINT 1720 +#define RPC_S_OUT_OF_RESOURCES 1721 +#define RPC_S_SERVER_UNAVAILABLE 1722 +#define RPC_S_SERVER_TOO_BUSY 1723 +#define RPC_S_INVALID_NETWORK_OPTIONS 1724 +#define RPC_S_NO_CALL_ACTIVE 1725 +#define RPC_S_CALL_FAILED 1726 +#define RPC_S_CALL_FAILED_DNE 1727 +#define RPC_S_PROTOCOL_ERROR 1728 +#define RPC_S_UNSUPPORTED_TRANS_SYN 1730 +#define RPC_S_UNSUPPORTED_TYPE 1732 +#define RPC_S_INVALID_TAG 1733 +#define RPC_S_INVALID_BOUND 1734 +#define RPC_S_NO_ENTRY_NAME 1735 +#define RPC_S_INVALID_NAME_SYNTAX 1736 +#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737 +#define RPC_S_UUID_NO_ADDRESS 1739 +#define RPC_S_DUPLICATE_ENDPOINT 1740 +#define RPC_S_UNKNOWN_AUTHN_TYPE 1741 +#define RPC_S_MAX_CALLS_TOO_SMALL 1742 +#define RPC_S_STRING_TOO_LONG 1743 +#define RPC_S_PROTSEQ_NOT_FOUND 1744 +#define RPC_S_PROCNUM_OUT_OF_RANGE 1745 +#define RPC_S_BINDING_HAS_NO_AUTH 1746 +#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747 +#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748 +#define RPC_S_INVALID_AUTH_IDENTITY 1749 +#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750 +#define EPT_S_INVALID_ENTRY 1751 +#define EPT_S_CANT_PERFORM_OP 1752 +#define EPT_S_NOT_REGISTERED 1753 +#define RPC_S_NOTHING_TO_EXPORT 1754 +#define RPC_S_INCOMPLETE_NAME 1755 +#define RPC_S_INVALID_VERS_OPTION 1756 +#define RPC_S_NO_MORE_MEMBERS 1757 +#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758 +#define RPC_S_INTERFACE_NOT_FOUND 1759 +#define RPC_S_ENTRY_ALREADY_EXISTS 1760 +#define RPC_S_ENTRY_NOT_FOUND 1761 +#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762 +#define RPC_S_INVALID_NAF_ID 1763 +#define RPC_S_CANNOT_SUPPORT 1764 +#define RPC_S_NO_CONTEXT_AVAILABLE 1765 +#define RPC_S_INTERNAL_ERROR 1766 +#define RPC_S_ZERO_DIVIDE 1767 +#define RPC_S_ADDRESS_ERROR 1768 +#define RPC_S_FP_DIV_ZERO 1769 +#define RPC_S_FP_UNDERFLOW 1770 +#define RPC_S_FP_OVERFLOW 1771 +#define RPC_X_NO_MORE_ENTRIES 1772 +#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773 +#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774 +#define RPC_X_SS_IN_NULL_CONTEXT 1775 +#define RPC_X_SS_CONTEXT_DAMAGED 1777 +#define RPC_X_SS_HANDLES_MISMATCH 1778 +#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779 +#define RPC_X_NULL_REF_POINTER 1780 +#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781 +#define RPC_X_BYTE_COUNT_TOO_SMALL 1782 +#define RPC_X_BAD_STUB_DATA 1783 +#define ERROR_INVALID_USER_BUFFER 1784 +#define ERROR_UNRECOGNIZED_MEDIA 1785 +#define ERROR_NO_TRUST_LSA_SECRET 1786 +#define ERROR_NO_TRUST_SAM_ACCOUNT 1787 +#define ERROR_TRUSTED_DOMAIN_FAILURE 1788 +#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789 +#define ERROR_TRUST_FAILURE 1790 +#define RPC_S_CALL_IN_PROGRESS 1791 +#define ERROR_NETLOGON_NOT_STARTED 1792 +#define ERROR_ACCOUNT_EXPIRED 1793 +#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794 +#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795 +#define ERROR_UNKNOWN_PORT 1796 +#define ERROR_UNKNOWN_PRINTER_DRIVER 1797 +#define ERROR_UNKNOWN_PRINTPROCESSOR 1798 +#define ERROR_INVALID_SEPARATOR_FILE 1799 +#define ERROR_INVALID_PRIORITY 1800 +#define ERROR_INVALID_PRINTER_NAME 1801 +#define ERROR_PRINTER_ALREADY_EXISTS 1802 +#define ERROR_INVALID_PRINTER_COMMAND 1803 +#define ERROR_INVALID_DATATYPE 1804 +#define ERROR_INVALID_ENVIRONMENT 1805 +#define RPC_S_NO_MORE_BINDINGS 1806 +#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807 +#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808 +#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809 +#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810 +#define ERROR_SERVER_HAS_OPEN_HANDLES 1811 +#define ERROR_RESOURCE_DATA_NOT_FOUND 1812 +#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813 +#define ERROR_RESOURCE_NAME_NOT_FOUND 1814 +#define ERROR_RESOURCE_LANG_NOT_FOUND 1815 +#define ERROR_NOT_ENOUGH_QUOTA 1816 +#define RPC_S_NO_INTERFACES 1817 +#define RPC_S_CALL_CANCELLED 1818 +#define RPC_S_BINDING_INCOMPLETE 1819 +#define RPC_S_COMM_FAILURE 1820 +#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821 +#define RPC_S_NO_PRINC_NAME 1822 +#define RPC_S_NOT_RPC_ERROR 1823 +#define RPC_S_UUID_LOCAL_ONLY 1824 +#define RPC_S_SEC_PKG_ERROR 1825 +#define RPC_S_NOT_CANCELLED 1826 +#define RPC_X_INVALID_ES_ACTION 1827 +#define RPC_X_WRONG_ES_VERSION 1828 +#define RPC_X_WRONG_STUB_VERSION 1829 +#define RPC_X_INVALID_PIPE_OBJECT 1830 +#define RPC_X_WRONG_PIPE_ORDER 1831 +#define RPC_X_WRONG_PIPE_VERSION 1832 +#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898 +#define EPT_S_CANT_CREATE 1899 +#define RPC_S_INVALID_OBJECT 1900 +#define ERROR_INVALID_TIME 1901 +#define ERROR_INVALID_FORM_NAME 1902 +#define ERROR_INVALID_FORM_SIZE 1903 +#define ERROR_ALREADY_WAITING 1904 +#define ERROR_PRINTER_DELETED 1905 +#define ERROR_INVALID_PRINTER_STATE 1906 +#define ERROR_PASSWORD_MUST_CHANGE 1907 +#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908 +#define ERROR_ACCOUNT_LOCKED_OUT 1909 +#define OR_INVALID_OXID 1910 +#define OR_INVALID_OID 1911 +#define OR_INVALID_SET 1912 +#define RPC_S_SEND_INCOMPLETE 1913 +#define RPC_S_INVALID_ASYNC_HANDLE 1914 +#define RPC_S_INVALID_ASYNC_CALL 1915 +#define RPC_X_PIPE_CLOSED 1916 +#define RPC_X_PIPE_DISCIPLINE_ERROR 1917 +#define RPC_X_PIPE_EMPTY 1918 +#define ERROR_NO_SITENAME 1919 +#define ERROR_CANT_ACCESS_FILE 1920 +#define ERROR_CANT_RESOLVE_FILENAME 1921 +#define RPC_S_ENTRY_TYPE_MISMATCH 1922 +#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923 +#define RPC_S_INTERFACE_NOT_EXPORTED 1924 +#define RPC_S_PROFILE_NOT_ADDED 1925 +#define RPC_S_PRF_ELT_NOT_ADDED 1926 +#define RPC_S_PRF_ELT_NOT_REMOVED 1927 +#define RPC_S_GRP_ELT_NOT_ADDED 1928 +#define RPC_S_GRP_ELT_NOT_REMOVED 1929 +#define ERROR_KM_DRIVER_BLOCKED 1930 +#define ERROR_CONTEXT_EXPIRED 1931 +#define ERROR_PER_USER_TRUST_QUOTA_EXCEEDED 1932 +#define ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED 1933 +#define ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED 1934 +#define ERROR_AUTHENTICATION_FIREWALL_FAILED 1935 +#define ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED 1936 +#define ERROR_INVALID_PIXEL_FORMAT 2000 +#define ERROR_BAD_DRIVER 2001 +#define ERROR_INVALID_WINDOW_STYLE 2002 +#define ERROR_METAFILE_NOT_SUPPORTED 2003 +#define ERROR_TRANSFORM_NOT_SUPPORTED 2004 +#define ERROR_CLIPPING_NOT_SUPPORTED 2005 +#define ERROR_INVALID_CMM 2010 +#define ERROR_INVALID_PROFILE 2011 +#define ERROR_TAG_NOT_FOUND 2012 +#define ERROR_TAG_NOT_PRESENT 2013 +#define ERROR_DUPLICATE_TAG 2014 +#define ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE 2015 +#define ERROR_PROFILE_NOT_FOUND 2016 +#define ERROR_INVALID_COLORSPACE 2017 +#define ERROR_ICM_NOT_ENABLED 2018 +#define ERROR_DELETING_ICM_XFORM 2019 +#define ERROR_INVALID_TRANSFORM 2020 +#define ERROR_COLORSPACE_MISMATCH 2021 +#define ERROR_INVALID_COLORINDEX 2022 +#define ERROR_CONNECTED_OTHER_PASSWORD 2108 +#define ERROR_BAD_USERNAME 2202 +#define ERROR_NOT_CONNECTED 2250 +#define ERROR_OPEN_FILES 2401 +#define ERROR_ACTIVE_CONNECTIONS 2402 +#define ERROR_DEVICE_IN_USE 2404 +#define ERROR_UNKNOWN_PRINT_MONITOR 3000 +#define ERROR_PRINTER_DRIVER_IN_USE 3001 +#define ERROR_SPOOL_FILE_NOT_FOUND 3002 +#define ERROR_SPL_NO_STARTDOC 3003 +#define ERROR_SPL_NO_ADDJOB 3004 +#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005 +#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006 +#define ERROR_INVALID_PRINT_MONITOR 3007 +#define ERROR_PRINT_MONITOR_IN_USE 3008 +#define ERROR_PRINTER_HAS_JOBS_QUEUED 3009 +#define ERROR_SUCCESS_REBOOT_REQUIRED 3010 +#define ERROR_SUCCESS_RESTART_REQUIRED 3011 +#define ERROR_PRINTER_NOT_FOUND 3012 +#define ERROR_PRINTER_DRIVER_WARNED 3013 +#define ERROR_PRINTER_DRIVER_BLOCKED 3014 +#define ERROR_WINS_INTERNAL 4000 +#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001 +#define ERROR_STATIC_INIT 4002 +#define ERROR_INC_BACKUP 4003 +#define ERROR_FULL_BACKUP 4004 +#define ERROR_REC_NON_EXISTENT 4005 +#define ERROR_RPL_NOT_ALLOWED 4006 +#define ERROR_DHCP_ADDRESS_CONFLICT 4100 +#define ERROR_WMI_GUID_NOT_FOUND 4200 +#define ERROR_WMI_INSTANCE_NOT_FOUND 4201 +#define ERROR_WMI_ITEMID_NOT_FOUND 4202 +#define ERROR_WMI_TRY_AGAIN 4203 +#define ERROR_WMI_DP_NOT_FOUND 4204 +#define ERROR_WMI_UNRESOLVED_INSTANCE_REF 4205 +#define ERROR_WMI_ALREADY_ENABLED 4206 +#define ERROR_WMI_GUID_DISCONNECTED 4207 +#define ERROR_WMI_SERVER_UNAVAILABLE 4208 +#define ERROR_WMI_DP_FAILED 4209 +#define ERROR_WMI_INVALID_MOF 4210 +#define ERROR_WMI_INVALID_REGINFO 4211 +#define ERROR_WMI_ALREADY_DISABLED 4212 +#define ERROR_WMI_READ_ONLY 4213 +#define ERROR_WMI_SET_FAILURE 4214 +#define ERROR_INVALID_MEDIA 4300 +#define ERROR_INVALID_LIBRARY 4301 +#define ERROR_INVALID_MEDIA_POOL 4302 +#define ERROR_DRIVE_MEDIA_MISMATCH 4303 +#define ERROR_MEDIA_OFFLINE 4304 +#define ERROR_LIBRARY_OFFLINE 4305 +#define ERROR_EMPTY 4306 +#define ERROR_NOT_EMPTY 4307 +#define ERROR_MEDIA_UNAVAILABLE 4308 +#define ERROR_RESOURCE_DISABLED 4309 +#define ERROR_INVALID_CLEANER 4310 +#define ERROR_UNABLE_TO_CLEAN 4311 +#define ERROR_OBJECT_NOT_FOUND 4312 +#define ERROR_DATABASE_FAILURE 4313 +#define ERROR_DATABASE_FULL 4314 +#define ERROR_MEDIA_INCOMPATIBLE 4315 +#define ERROR_RESOURCE_NOT_PRESENT 4316 +#define ERROR_INVALID_OPERATION 4317 +#define ERROR_MEDIA_NOT_AVAILABLE 4318 +#define ERROR_DEVICE_NOT_AVAILABLE 4319 +#define ERROR_REQUEST_REFUSED 4320 +#define ERROR_INVALID_DRIVE_OBJECT 4321 +#define ERROR_LIBRARY_FULL 4322 +#define ERROR_MEDIUM_NOT_ACCESSIBLE 4323 +#define ERROR_UNABLE_TO_LOAD_MEDIUM 4324 +#define ERROR_UNABLE_TO_INVENTORY_DRIVE 4325 +#define ERROR_UNABLE_TO_INVENTORY_SLOT 4326 +#define ERROR_UNABLE_TO_INVENTORY_TRANSPORT 4327 +#define ERROR_TRANSPORT_FULL 4328 +#define ERROR_CONTROLLING_IEPORT 4329 +#define ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA 4330 +#define ERROR_CLEANER_SLOT_SET 4331 +#define ERROR_CLEANER_SLOT_NOT_SET 4332 +#define ERROR_CLEANER_CARTRIDGE_SPENT 4333 +#define ERROR_UNEXPECTED_OMID 4334 +#define ERROR_CANT_DELETE_LAST_ITEM 4335 +#define ERROR_MESSAGE_EXCEEDS_MAX_SIZE 4336 +#define ERROR_VOLUME_CONTAINS_SYS_FILES 4337 +#define ERROR_INDIGENOUS_TYPE 4338 +#define ERROR_NO_SUPPORTING_DRIVES 4339 +#define ERROR_CLEANER_CARTRIDGE_INSTALLED 4340 +#define ERROR_FILE_OFFLINE 4350 +#define ERROR_REMOTE_STORAGE_NOT_ACTIVE 4351 +#define ERROR_REMOTE_STORAGE_MEDIA_ERROR 4352 +#define ERROR_NOT_A_REPARSE_POINT 4390 +#define ERROR_REPARSE_ATTRIBUTE_CONFLICT 4391 +#define ERROR_INVALID_REPARSE_DATA 4392 +#define ERROR_REPARSE_TAG_INVALID 4393 +#define ERROR_REPARSE_TAG_MISMATCH 4394 +#define ERROR_VOLUME_NOT_SIS_ENABLED 4500 +#define ERROR_DEPENDENT_RESOURCE_EXISTS 5001 +#define ERROR_DEPENDENCY_NOT_FOUND 5002 +#define ERROR_DEPENDENCY_ALREADY_EXISTS 5003 +#define ERROR_RESOURCE_NOT_ONLINE 5004 +#define ERROR_HOST_NODE_NOT_AVAILABLE 5005 +#define ERROR_RESOURCE_NOT_AVAILABLE 5006 +#define ERROR_RESOURCE_NOT_FOUND 5007 +#define ERROR_SHUTDOWN_CLUSTER 5008 +#define ERROR_CANT_EVICT_ACTIVE_NODE 5009 +#define ERROR_OBJECT_ALREADY_EXISTS 5010 +#define ERROR_OBJECT_IN_LIST 5011 +#define ERROR_GROUP_NOT_AVAILABLE 5012 +#define ERROR_GROUP_NOT_FOUND 5013 +#define ERROR_GROUP_NOT_ONLINE 5014 +#define ERROR_HOST_NODE_NOT_RESOURCE_OWNER 5015 +#define ERROR_HOST_NODE_NOT_GROUP_OWNER 5016 +#define ERROR_RESMON_CREATE_FAILED 5017 +#define ERROR_RESMON_ONLINE_FAILED 5018 +#define ERROR_RESOURCE_ONLINE 5019 +#define ERROR_QUORUM_RESOURCE 5020 +#define ERROR_NOT_QUORUM_CAPABLE 5021 +#define ERROR_CLUSTER_SHUTTING_DOWN 5022 +#define ERROR_INVALID_STATE 5023 +#define ERROR_RESOURCE_PROPERTIES_STORED 5024 +#define ERROR_NOT_QUORUM_CLASS 5025 +#define ERROR_CORE_RESOURCE 5026 +#define ERROR_QUORUM_RESOURCE_ONLINE_FAILED 5027 +#define ERROR_QUORUMLOG_OPEN_FAILED 5028 +#define ERROR_CLUSTERLOG_CORRUPT 5029 +#define ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE 5030 +#define ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE 5031 +#define ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND 5032 +#define ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE 5033 +#define ERROR_QUORUM_OWNER_ALIVE 5034 +#define ERROR_NETWORK_NOT_AVAILABLE 5035 +#define ERROR_NODE_NOT_AVAILABLE 5036 +#define ERROR_ALL_NODES_NOT_AVAILABLE 5037 +#define ERROR_RESOURCE_FAILED 5038 +#define ERROR_CLUSTER_INVALID_NODE 5039 +#define ERROR_CLUSTER_NODE_EXISTS 5040 +#define ERROR_CLUSTER_JOIN_IN_PROGRESS 5041 +#define ERROR_CLUSTER_NODE_NOT_FOUND 5042 +#define ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND 5043 +#define ERROR_CLUSTER_NETWORK_EXISTS 5044 +#define ERROR_CLUSTER_NETWORK_NOT_FOUND 5045 +#define ERROR_CLUSTER_NETINTERFACE_EXISTS 5046 +#define ERROR_CLUSTER_NETINTERFACE_NOT_FOUND 5047 +#define ERROR_CLUSTER_INVALID_REQUEST 5048 +#define ERROR_CLUSTER_INVALID_NETWORK_PROVIDER 5049 +#define ERROR_CLUSTER_NODE_DOWN 5050 +#define ERROR_CLUSTER_NODE_UNREACHABLE 5051 +#define ERROR_CLUSTER_NODE_NOT_MEMBER 5052 +#define ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS 5053 +#define ERROR_CLUSTER_INVALID_NETWORK 5054 +#define ERROR_CLUSTER_NODE_UP 5056 +#define ERROR_CLUSTER_IPADDR_IN_USE 5057 +#define ERROR_CLUSTER_NODE_NOT_PAUSED 5058 +#define ERROR_CLUSTER_NO_SECURITY_CONTEXT 5059 +#define ERROR_CLUSTER_NETWORK_NOT_INTERNAL 5060 +#define ERROR_CLUSTER_NODE_ALREADY_UP 5061 +#define ERROR_CLUSTER_NODE_ALREADY_DOWN 5062 +#define ERROR_CLUSTER_NETWORK_ALREADY_ONLINE 5063 +#define ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE 5064 +#define ERROR_CLUSTER_NODE_ALREADY_MEMBER 5065 +#define ERROR_CLUSTER_LAST_INTERNAL_NETWORK 5066 +#define ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS 5067 +#define ERROR_INVALID_OPERATION_ON_QUORUM 5068 +#define ERROR_DEPENDENCY_NOT_ALLOWED 5069 +#define ERROR_CLUSTER_NODE_PAUSED 5070 +#define ERROR_NODE_CANT_HOST_RESOURCE 5071 +#define ERROR_CLUSTER_NODE_NOT_READY 5072 +#define ERROR_CLUSTER_NODE_SHUTTING_DOWN 5073 +#define ERROR_CLUSTER_JOIN_ABORTED 5074 +#define ERROR_CLUSTER_INCOMPATIBLE_VERSIONS 5075 +#define ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED 5076 +#define ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED 5077 +#define ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND 5078 +#define ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED 5079 +#define ERROR_CLUSTER_RESNAME_NOT_FOUND 5080 +#define ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED 5081 +#define ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST 5082 +#define ERROR_CLUSTER_DATABASE_SEQMISMATCH 5083 +#define ERROR_RESMON_INVALID_STATE 5084 +#define ERROR_CLUSTER_GUM_NOT_LOCKER 5085 +#define ERROR_QUORUM_DISK_NOT_FOUND 5086 +#define ERROR_DATABASE_BACKUP_CORRUPT 5087 +#define ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT 5088 +#define ERROR_RESOURCE_PROPERTY_UNCHANGEABLE 5089 +#define ERROR_ENCRYPTION_FAILED 6000 +#define ERROR_DECRYPTION_FAILED 6001 +#define ERROR_FILE_ENCRYPTED 6002 +#define ERROR_NO_RECOVERY_POLICY 6003 +#define ERROR_NO_EFS 6004 +#define ERROR_WRONG_EFS 6005 +#define ERROR_NO_USER_KEYS 6006 +#define ERROR_FILE_NOT_ENCRYPTED 6007 +#define ERROR_NOT_EXPORT_FORMAT 6008 +#define ERROR_FILE_READ_ONLY 6009 +#define ERROR_DIR_EFS_DISALLOWED 6010 +#define ERROR_EFS_SERVER_NOT_TRUSTED 6011 +#define ERROR_EFS_ALG_BLOB_TOO_BIG 6013 +#define ERROR_NO_BROWSER_SERVERS_FOUND 6118 +#define SCHED_E_SERVICE_NOT_LOCALSYSTEM 6200 +#define ERROR_CTX_WINSTATION_NAME_INVALID 7001 +#define ERROR_CTX_INVALID_PD 7002 +#define ERROR_CTX_PD_NOT_FOUND 7003 +#define ERROR_CTX_WD_NOT_FOUND 7004 +#define ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY 7005 +#define ERROR_CTX_SERVICE_NAME_COLLISION 7006 +#define ERROR_CTX_CLOSE_PENDING 7007 +#define ERROR_CTX_NO_OUTBUF 7008 +#define ERROR_CTX_MODEM_INF_NOT_FOUND 7009 +#define ERROR_CTX_INVALID_MODEMNAME 7010 +#define ERROR_CTX_MODEM_RESPONSE_ERROR 7011 +#define ERROR_CTX_MODEM_RESPONSE_TIMEOUT 7012 +#define ERROR_CTX_MODEM_RESPONSE_NO_CARRIER 7013 +#define ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE 7014 +#define ERROR_CTX_MODEM_RESPONSE_BUSY 7015 +#define ERROR_CTX_MODEM_RESPONSE_VOICE 7016 +#define ERROR_CTX_TD_ERROR 7017 +#define ERROR_CTX_WINSTATION_NOT_FOUND 7022 +#define ERROR_CTX_WINSTATION_ALREADY_EXISTS 7023 +#define ERROR_CTX_WINSTATION_BUSY 7024 +#define ERROR_CTX_BAD_VIDEO_MODE 7025 +#define ERROR_CTX_GRAPHICS_INVALID 7035 +#define ERROR_CTX_LOGON_DISABLED 7037 +#define ERROR_CTX_NOT_CONSOLE 7038 +#define ERROR_CTX_CLIENT_QUERY_TIMEOUT 7040 +#define ERROR_CTX_CONSOLE_DISCONNECT 7041 +#define ERROR_CTX_CONSOLE_CONNECT 7042 +#define ERROR_CTX_SHADOW_DENIED 7044 +#define ERROR_CTX_WINSTATION_ACCESS_DENIED 7045 +#define ERROR_CTX_INVALID_WD 7049 +#define ERROR_CTX_SHADOW_INVALID 7050 +#define ERROR_CTX_SHADOW_DISABLED 7051 +#define ERROR_CTX_CLIENT_LICENSE_IN_USE 7052 +#define ERROR_CTX_CLIENT_LICENSE_NOT_SET 7053 +#define ERROR_CTX_LICENSE_NOT_AVAILABLE 7054 +#define ERROR_CTX_LICENSE_CLIENT_INVALID 7055 +#define ERROR_CTX_LICENSE_EXPIRED 7056 +#define ERROR_CTX_SHADOW_NOT_RUNNING 7057 +#define ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE 7058 +#define FRS_ERR_INVALID_API_SEQUENCE 8001 +#define FRS_ERR_STARTING_SERVICE 8002 +#define FRS_ERR_STOPPING_SERVICE 8003 +#define FRS_ERR_INTERNAL_API 8004 +#define FRS_ERR_INTERNAL 8005 +#define FRS_ERR_SERVICE_COMM 8006 +#define FRS_ERR_INSUFFICIENT_PRIV 8007 +#define FRS_ERR_AUTHENTICATION 8008 +#define FRS_ERR_PARENT_INSUFFICIENT_PRIV 8009 +#define FRS_ERR_PARENT_AUTHENTICATION 8010 +#define FRS_ERR_CHILD_TO_PARENT_COMM 8011 +#define FRS_ERR_PARENT_TO_CHILD_COMM 8012 +#define FRS_ERR_SYSVOL_POPULATE 8013 +#define FRS_ERR_SYSVOL_POPULATE_TIMEOUT 8014 +#define FRS_ERR_SYSVOL_IS_BUSY 8015 +#define FRS_ERR_SYSVOL_DEMOTE 8016 +#define FRS_ERR_INVALID_SERVICE_PARAMETER 8017 +#define ERROR_DS_NOT_INSTALLED 8200 +#define ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY 8201 +#define ERROR_DS_NO_ATTRIBUTE_OR_VALUE 8202 +#define ERROR_DS_INVALID_ATTRIBUTE_SYNTAX 8203 +#define ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED 8204 +#define ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS 8205 +#define ERROR_DS_BUSY 8206 +#define ERROR_DS_UNAVAILABLE 8207 +#define ERROR_DS_NO_RIDS_ALLOCATED 8208 +#define ERROR_DS_NO_MORE_RIDS 8209 +#define ERROR_DS_INCORRECT_ROLE_OWNER 8210 +#define ERROR_DS_RIDMGR_INIT_ERROR 8211 +#define ERROR_DS_OBJ_CLASS_VIOLATION 8212 +#define ERROR_DS_CANT_ON_NON_LEAF 8213 +#define ERROR_DS_CANT_ON_RDN 8214 +#define ERROR_DS_CANT_MOD_OBJ_CLASS 8215 +#define ERROR_DS_CROSS_DOM_MOVE_ERROR 8216 +#define ERROR_DS_GC_NOT_AVAILABLE 8217 +#define ERROR_SHARED_POLICY 8218 +#define ERROR_POLICY_OBJECT_NOT_FOUND 8219 +#define ERROR_POLICY_ONLY_IN_DS 8220 +#define ERROR_PROMOTION_ACTIVE 8221 +#define ERROR_NO_PROMOTION_ACTIVE 8222 +#define ERROR_DS_OPERATIONS_ERROR 8224 +#define ERROR_DS_PROTOCOL_ERROR 8225 +#define ERROR_DS_TIMELIMIT_EXCEEDED 8226 +#define ERROR_DS_SIZELIMIT_EXCEEDED 8227 +#define ERROR_DS_ADMIN_LIMIT_EXCEEDED 8228 +#define ERROR_DS_COMPARE_FALSE 8229 +#define ERROR_DS_COMPARE_TRUE 8230 +#define ERROR_DS_AUTH_METHOD_NOT_SUPPORTED 8231 +#define ERROR_DS_STRONG_AUTH_REQUIRED 8232 +#define ERROR_DS_INAPPROPRIATE_AUTH 8233 +#define ERROR_DS_AUTH_UNKNOWN 8234 +#define ERROR_DS_REFERRAL 8235 +#define ERROR_DS_UNAVAILABLE_CRIT_EXTENSION 8236 +#define ERROR_DS_CONFIDENTIALITY_REQUIRED 8237 +#define ERROR_DS_INAPPROPRIATE_MATCHING 8238 +#define ERROR_DS_CONSTRAINT_VIOLATION 8239 +#define ERROR_DS_NO_SUCH_OBJECT 8240 +#define ERROR_DS_ALIAS_PROBLEM 8241 +#define ERROR_DS_INVALID_DN_SYNTAX 8242 +#define ERROR_DS_IS_LEAF 8243 +#define ERROR_DS_ALIAS_DEREF_PROBLEM 8244 +#define ERROR_DS_UNWILLING_TO_PERFORM 8245 +#define ERROR_DS_LOOP_DETECT 8246 +#define ERROR_DS_NAMING_VIOLATION 8247 +#define ERROR_DS_OBJECT_RESULTS_TOO_LARGE 8248 +#define ERROR_DS_AFFECTS_MULTIPLE_DSAS 8249 +#define ERROR_DS_SERVER_DOWN 8250 +#define ERROR_DS_LOCAL_ERROR 8251 +#define ERROR_DS_ENCODING_ERROR 8252 +#define ERROR_DS_DECODING_ERROR 8253 +#define ERROR_DS_FILTER_UNKNOWN 8254 +#define ERROR_DS_PARAM_ERROR 8255 +#define ERROR_DS_NOT_SUPPORTED 8256 +#define ERROR_DS_NO_RESULTS_RETURNED 8257 +#define ERROR_DS_CONTROL_NOT_FOUND 8258 +#define ERROR_DS_CLIENT_LOOP 8259 +#define ERROR_DS_REFERRAL_LIMIT_EXCEEDED 8260 +#define ERROR_DS_ROOT_MUST_BE_NC 8301 +#define ERROR_DS_ADD_REPLICA_INHIBITED 8302 +#define ERROR_DS_ATT_NOT_DEF_IN_SCHEMA 8303 +#define ERROR_DS_MAX_OBJ_SIZE_EXCEEDED 8304 +#define ERROR_DS_OBJ_STRING_NAME_EXISTS 8305 +#define ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA 8306 +#define ERROR_DS_RDN_DOESNT_MATCH_SCHEMA 8307 +#define ERROR_DS_NO_REQUESTED_ATTS_FOUND 8308 +#define ERROR_DS_USER_BUFFER_TO_SMALL 8309 +#define ERROR_DS_ATT_IS_NOT_ON_OBJ 8310 +#define ERROR_DS_ILLEGAL_MOD_OPERATION 8311 +#define ERROR_DS_OBJ_TOO_LARGE 8312 +#define ERROR_DS_BAD_INSTANCE_TYPE 8313 +#define ERROR_DS_MASTERDSA_REQUIRED 8314 +#define ERROR_DS_OBJECT_CLASS_REQUIRED 8315 +#define ERROR_DS_MISSING_REQUIRED_ATT 8316 +#define ERROR_DS_ATT_NOT_DEF_FOR_CLASS 8317 +#define ERROR_DS_ATT_ALREADY_EXISTS 8318 +#define ERROR_DS_CANT_ADD_ATT_VALUES 8320 +#define ERROR_DS_SINGLE_VALUE_CONSTRAINT 8321 +#define ERROR_DS_RANGE_CONSTRAINT 8322 +#define ERROR_DS_ATT_VAL_ALREADY_EXISTS 8323 +#define ERROR_DS_CANT_REM_MISSING_ATT 8324 +#define ERROR_DS_CANT_REM_MISSING_ATT_VAL 8325 +#define ERROR_DS_ROOT_CANT_BE_SUBREF 8326 +#define ERROR_DS_NO_CHAINING 8327 +#define ERROR_DS_NO_CHAINED_EVAL 8328 +#define ERROR_DS_NO_PARENT_OBJECT 8329 +#define ERROR_DS_PARENT_IS_AN_ALIAS 8330 +#define ERROR_DS_CANT_MIX_MASTER_AND_REPS 8331 +#define ERROR_DS_CHILDREN_EXIST 8332 +#define ERROR_DS_OBJ_NOT_FOUND 8333 +#define ERROR_DS_ALIASED_OBJ_MISSING 8334 +#define ERROR_DS_BAD_NAME_SYNTAX 8335 +#define ERROR_DS_ALIAS_POINTS_TO_ALIAS 8336 +#define ERROR_DS_CANT_DEREF_ALIAS 8337 +#define ERROR_DS_OUT_OF_SCOPE 8338 +#define ERROR_DS_CANT_DELETE_DSA_OBJ 8340 +#define ERROR_DS_GENERIC_ERROR 8341 +#define ERROR_DS_DSA_MUST_BE_INT_MASTER 8342 +#define ERROR_DS_CLASS_NOT_DSA 8343 +#define ERROR_DS_INSUFF_ACCESS_RIGHTS 8344 +#define ERROR_DS_ILLEGAL_SUPERIOR 8345 +#define ERROR_DS_ATTRIBUTE_OWNED_BY_SAM 8346 +#define ERROR_DS_NAME_TOO_MANY_PARTS 8347 +#define ERROR_DS_NAME_TOO_LONG 8348 +#define ERROR_DS_NAME_VALUE_TOO_LONG 8349 +#define ERROR_DS_NAME_UNPARSEABLE 8350 +#define ERROR_DS_NAME_TYPE_UNKNOWN 8351 +#define ERROR_DS_NOT_AN_OBJECT 8352 +#define ERROR_DS_SEC_DESC_TOO_SHORT 8353 +#define ERROR_DS_SEC_DESC_INVALID 8354 +#define ERROR_DS_NO_DELETED_NAME 8355 +#define ERROR_DS_SUBREF_MUST_HAVE_PARENT 8356 +#define ERROR_DS_NCNAME_MUST_BE_NC 8357 +#define ERROR_DS_CANT_ADD_SYSTEM_ONLY 8358 +#define ERROR_DS_CLASS_MUST_BE_CONCRETE 8359 +#define ERROR_DS_INVALID_DMD 8360 +#define ERROR_DS_OBJ_GUID_EXISTS 8361 +#define ERROR_DS_NOT_ON_BACKLINK 8362 +#define ERROR_DS_NO_CROSSREF_FOR_NC 8363 +#define ERROR_DS_SHUTTING_DOWN 8364 +#define ERROR_DS_UNKNOWN_OPERATION 8365 +#define ERROR_DS_INVALID_ROLE_OWNER 8366 +#define ERROR_DS_COULDNT_CONTACT_FSMO 8367 +#define ERROR_DS_CROSS_NC_DN_RENAME 8368 +#define ERROR_DS_CANT_MOD_SYSTEM_ONLY 8369 +#define ERROR_DS_REPLICATOR_ONLY 8370 +#define ERROR_DS_OBJ_CLASS_NOT_DEFINED 8371 +#define ERROR_DS_OBJ_CLASS_NOT_SUBCLASS 8372 +#define ERROR_DS_NAME_REFERENCE_INVALID 8373 +#define ERROR_DS_CROSS_REF_EXISTS 8374 +#define ERROR_DS_CANT_DEL_MASTER_CROSSREF 8375 +#define ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD 8376 +#define ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX 8377 +#define ERROR_DS_DUP_RDN 8378 +#define ERROR_DS_DUP_OID 8379 +#define ERROR_DS_DUP_MAPI_ID 8380 +#define ERROR_DS_DUP_SCHEMA_ID_GUID 8381 +#define ERROR_DS_DUP_LDAP_DISPLAY_NAME 8382 +#define ERROR_DS_SEMANTIC_ATT_TEST 8383 +#define ERROR_DS_SYNTAX_MISMATCH 8384 +#define ERROR_DS_EXISTS_IN_MUST_HAVE 8385 +#define ERROR_DS_EXISTS_IN_MAY_HAVE 8386 +#define ERROR_DS_NONEXISTENT_MAY_HAVE 8387 +#define ERROR_DS_NONEXISTENT_MUST_HAVE 8388 +#define ERROR_DS_AUX_CLS_TEST_FAIL 8389 +#define ERROR_DS_NONEXISTENT_POSS_SUP 8390 +#define ERROR_DS_SUB_CLS_TEST_FAIL 8391 +#define ERROR_DS_BAD_RDN_ATT_ID_SYNTAX 8392 +#define ERROR_DS_EXISTS_IN_AUX_CLS 8393 +#define ERROR_DS_EXISTS_IN_SUB_CLS 8394 +#define ERROR_DS_EXISTS_IN_POSS_SUP 8395 +#define ERROR_DS_RECALCSCHEMA_FAILED 8396 +#define ERROR_DS_TREE_DELETE_NOT_FINISHED 8397 +#define ERROR_DS_CANT_DELETE 8398 +#define ERROR_DS_ATT_SCHEMA_REQ_ID 8399 +#define ERROR_DS_BAD_ATT_SCHEMA_SYNTAX 8400 +#define ERROR_DS_CANT_CACHE_ATT 8401 +#define ERROR_DS_CANT_CACHE_CLASS 8402 +#define ERROR_DS_CANT_REMOVE_ATT_CACHE 8403 +#define ERROR_DS_CANT_REMOVE_CLASS_CACHE 8404 +#define ERROR_DS_CANT_RETRIEVE_DN 8405 +#define ERROR_DS_MISSING_SUPREF 8406 +#define ERROR_DS_CANT_RETRIEVE_INSTANCE 8407 +#define ERROR_DS_CODE_INCONSISTENCY 8408 +#define ERROR_DS_DATABASE_ERROR 8409 +#define ERROR_DS_GOVERNSID_MISSING 8410 +#define ERROR_DS_MISSING_EXPECTED_ATT 8411 +#define ERROR_DS_NCNAME_MISSING_CR_REF 8412 +#define ERROR_DS_SECURITY_CHECKING_ERROR 8413 +#define ERROR_DS_SCHEMA_NOT_LOADED 8414 +#define ERROR_DS_SCHEMA_ALLOC_FAILED 8415 +#define ERROR_DS_ATT_SCHEMA_REQ_SYNTAX 8416 +#define ERROR_DS_GCVERIFY_ERROR 8417 +#define ERROR_DS_DRA_SCHEMA_MISMATCH 8418 +#define ERROR_DS_CANT_FIND_DSA_OBJ 8419 +#define ERROR_DS_CANT_FIND_EXPECTED_NC 8420 +#define ERROR_DS_CANT_FIND_NC_IN_CACHE 8421 +#define ERROR_DS_CANT_RETRIEVE_CHILD 8422 +#define ERROR_DS_SECURITY_ILLEGAL_MODIFY 8423 +#define ERROR_DS_CANT_REPLACE_HIDDEN_REC 8424 +#define ERROR_DS_BAD_HIERARCHY_FILE 8425 +#define ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED 8426 +#define ERROR_DS_CONFIG_PARAM_MISSING 8427 +#define ERROR_DS_COUNTING_AB_INDICES_FAILED 8428 +#define ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED 8429 +#define ERROR_DS_INTERNAL_FAILURE 8430 +#define ERROR_DS_UNKNOWN_ERROR 8431 +#define ERROR_DS_ROOT_REQUIRES_CLASS_TOP 8432 +#define ERROR_DS_REFUSING_FSMO_ROLES 8433 +#define ERROR_DS_MISSING_FSMO_SETTINGS 8434 +#define ERROR_DS_UNABLE_TO_SURRENDER_ROLES 8435 +#define ERROR_DS_DRA_GENERIC 8436 +#define ERROR_DS_DRA_INVALID_PARAMETER 8437 +#define ERROR_DS_DRA_BUSY 8438 +#define ERROR_DS_DRA_BAD_DN 8439 +#define ERROR_DS_DRA_BAD_NC 8440 +#define ERROR_DS_DRA_DN_EXISTS 8441 +#define ERROR_DS_DRA_INTERNAL_ERROR 8442 +#define ERROR_DS_DRA_INCONSISTENT_DIT 8443 +#define ERROR_DS_DRA_CONNECTION_FAILED 8444 +#define ERROR_DS_DRA_BAD_INSTANCE_TYPE 8445 +#define ERROR_DS_DRA_OUT_OF_MEM 8446 +#define ERROR_DS_DRA_MAIL_PROBLEM 8447 +#define ERROR_DS_DRA_REF_ALREADY_EXISTS 8448 +#define ERROR_DS_DRA_REF_NOT_FOUND 8449 +#define ERROR_DS_DRA_OBJ_IS_REP_SOURCE 8450 +#define ERROR_DS_DRA_DB_ERROR 8451 +#define ERROR_DS_DRA_NO_REPLICA 8452 +#define ERROR_DS_DRA_ACCESS_DENIED 8453 +#define ERROR_DS_DRA_NOT_SUPPORTED 8454 +#define ERROR_DS_DRA_RPC_CANCELLED 8455 +#define ERROR_DS_DRA_SOURCE_DISABLED 8456 +#define ERROR_DS_DRA_SINK_DISABLED 8457 +#define ERROR_DS_DRA_NAME_COLLISION 8458 +#define ERROR_DS_DRA_SOURCE_REINSTALLED 8459 +#define ERROR_DS_DRA_MISSING_PARENT 8460 +#define ERROR_DS_DRA_PREEMPTED 8461 +#define ERROR_DS_DRA_ABANDON_SYNC 8462 +#define ERROR_DS_DRA_SHUTDOWN 8463 +#define ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET 8464 +#define ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA 8465 +#define ERROR_DS_DRA_EXTN_CONNECTION_FAILED 8466 +#define ERROR_DS_INSTALL_SCHEMA_MISMATCH 8467 +#define ERROR_DS_DUP_LINK_ID 8468 +#define ERROR_DS_NAME_ERROR_RESOLVING 8469 +#define ERROR_DS_NAME_ERROR_NOT_FOUND 8470 +#define ERROR_DS_NAME_ERROR_NOT_UNIQUE 8471 +#define ERROR_DS_NAME_ERROR_NO_MAPPING 8472 +#define ERROR_DS_NAME_ERROR_DOMAIN_ONLY 8473 +#define ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING 8474 +#define ERROR_DS_CONSTRUCTED_ATT_MOD 8475 +#define ERROR_DS_WRONG_OM_OBJ_CLASS 8476 +#define ERROR_DS_DRA_REPL_PENDING 8477 +#define ERROR_DS_DS_REQUIRED 8478 +#define ERROR_DS_INVALID_LDAP_DISPLAY_NAME 8479 +#define ERROR_DS_NON_BASE_SEARCH 8480 +#define ERROR_DS_CANT_RETRIEVE_ATTS 8481 +#define ERROR_DS_BACKLINK_WITHOUT_LINK 8482 +#define ERROR_DS_EPOCH_MISMATCH 8483 +#define ERROR_DS_SRC_NAME_MISMATCH 8484 +#define ERROR_DS_SRC_AND_DST_NC_IDENTICAL 8485 +#define ERROR_DS_DST_NC_MISMATCH 8486 +#define ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC 8487 +#define ERROR_DS_SRC_GUID_MISMATCH 8488 +#define ERROR_DS_CANT_MOVE_DELETED_OBJECT 8489 +#define ERROR_DS_PDC_OPERATION_IN_PROGRESS 8490 +#define ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD 8491 +#define ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION 8492 +#define ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS 8493 +#define ERROR_DS_NC_MUST_HAVE_NC_PARENT 8494 +#define ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE 8495 +#define ERROR_DS_DST_DOMAIN_NOT_NATIVE 8496 +#define ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER 8497 +#define ERROR_DS_CANT_MOVE_ACCOUNT_GROUP 8498 +#define ERROR_DS_CANT_MOVE_RESOURCE_GROUP 8499 +#define ERROR_DS_INVALID_SEARCH_FLAG 8500 +#define ERROR_DS_NO_TREE_DELETE_ABOVE_NC 8501 +#define ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE 8502 +#define ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE 8503 +#define ERROR_DS_SAM_INIT_FAILURE 8504 +#define ERROR_DS_SENSITIVE_GROUP_VIOLATION 8505 +#define ERROR_DS_CANT_MOD_PRIMARYGROUPID 8506 +#define ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD 8507 +#define ERROR_DS_NONSAFE_SCHEMA_CHANGE 8508 +#define ERROR_DS_SCHEMA_UPDATE_DISALLOWED 8509 +#define ERROR_DS_CANT_CREATE_UNDER_SCHEMA 8510 +#define ERROR_DS_INSTALL_NO_SRC_SCH_VERSION 8511 +#define ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE 8512 +#define ERROR_DS_INVALID_GROUP_TYPE 8513 +#define ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN 8514 +#define ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN 8515 +#define ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER 8516 +#define ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER 8517 +#define ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER 8518 +#define ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER 8519 +#define ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER 8520 +#define ERROR_DS_HAVE_PRIMARY_MEMBERS 8521 +#define ERROR_DS_STRING_SD_CONVERSION_FAILED 8522 +#define ERROR_DS_NAMING_MASTER_GC 8523 +#define ERROR_DS_LOOKUP_FAILURE 8524 +#define ERROR_DS_COULDNT_UPDATE_SPNS 8525 +#define ERROR_DS_CANT_RETRIEVE_SD 8526 +#define ERROR_DS_KEY_NOT_UNIQUE 8527 +#define ERROR_DS_WRONG_LINKED_ATT_SYNTAX 8528 +#define ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD 8529 +#define ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY 8530 +#define ERROR_DS_CANT_START 8531 +#define ERROR_DS_INIT_FAILURE 8532 +#define ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION 8533 +#define ERROR_DS_SOURCE_DOMAIN_IN_FOREST 8534 +#define ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST 8535 +#define ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED 8536 +#define ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN 8537 +#define ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER 8538 +#define ERROR_DS_SRC_SID_EXISTS_IN_FOREST 8539 +#define ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH 8540 +#define ERROR_SAM_INIT_FAILURE 8541 +#define ERROR_DS_DRA_SCHEMA_INFO_SHIP 8542 +#define ERROR_DS_DRA_SCHEMA_CONFLICT 8543 +#define ERROR_DS_DRA_EARLIER_SCHEMA_CONLICT 8544 +#define ERROR_DS_DRA_OBJ_NC_MISMATCH 8545 +#define ERROR_DS_NC_STILL_HAS_DSAS 8546 +#define ERROR_DS_GC_REQUIRED 8547 +#define ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY 8548 +#define ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS 8549 +#define ERROR_DS_CANT_ADD_TO_GC 8550 +#define ERROR_DS_NO_CHECKPOINT_WITH_PDC 8551 +#define ERROR_DS_SOURCE_AUDITING_NOT_ENABLED 8552 +#define ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC 8553 +#define ERROR_DS_INVALID_NAME_FOR_SPN 8554 +#define ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS 8555 +#define ERROR_DS_UNICODEPWD_NOT_IN_QUOTES 8556 +#define ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED 8557 +#define ERROR_DS_MUST_BE_RUN_ON_DST_DC 8558 +#define ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER 8559 +#define ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ 8560 +#define ERROR_DS_INIT_FAILURE_CONSOLE 8561 +#define ERROR_DS_SAM_INIT_FAILURE_CONSOLE 8562 +#define ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4 8572 +#define ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER 8578 +#define DNS_ERROR_RCODE_FORMAT_ERROR 9001 +#define DNS_ERROR_RCODE_SERVER_FAILURE 9002 +#define DNS_ERROR_RCODE_NAME_ERROR 9003 +#define DNS_ERROR_RCODE_NOT_IMPLEMENTED 9004 +#define DNS_ERROR_RCODE_REFUSED 9005 +#define DNS_ERROR_RCODE_YXDOMAIN 9006 +#define DNS_ERROR_RCODE_YXRRSET 9007 +#define DNS_ERROR_RCODE_NXRRSET 9008 +#define DNS_ERROR_RCODE_NOTAUTH 9009 +#define DNS_ERROR_RCODE_NOTZONE 9010 +#define DNS_ERROR_RCODE_BADSIG 9016 +#define DNS_ERROR_RCODE_BADKEY 9017 +#define DNS_ERROR_RCODE_BADTIME 9018 +#define DNS_INFO_NO_RECORDS 9501 +#define DNS_ERROR_BAD_PACKET 9502 +#define DNS_ERROR_NO_PACKET 9503 +#define DNS_ERROR_RCODE 9504 +#define DNS_ERROR_UNSECURE_PACKET 9505 +#define DNS_ERROR_INVALID_TYPE 9551 +#define DNS_ERROR_INVALID_IP_ADDRESS 9552 +#define DNS_ERROR_INVALID_PROPERTY 9553 +#define DNS_ERROR_TRY_AGAIN_LATER 9554 +#define DNS_ERROR_NOT_UNIQUE 9555 +#define DNS_ERROR_NON_RFC_NAME 9556 +#define DNS_STATUS_FQDN 9557 +#define DNS_STATUS_DOTTED_NAME 9558 +#define DNS_STATUS_SINGLE_PART_NAME 9559 +#define DNS_ERROR_INVALID_NAME_CHAR 9560 +#define DNS_ERROR_NUMERIC_NAME 9561 +#define DNS_ERROR_ZONE_DOES_NOT_EXIST 9601 +#define DNS_ERROR_NO_ZONE_INFO 9602 +#define DNS_ERROR_INVALID_ZONE_OPERATION 9603 +#define DNS_ERROR_ZONE_CONFIGURATION_ERROR 9604 +#define DNS_ERROR_ZONE_HAS_NO_SOA_RECORD 9605 +#define DNS_ERROR_ZONE_HAS_NO_NS_RECORDS 9606 +#define DNS_ERROR_ZONE_LOCKED 9607 +#define DNS_ERROR_ZONE_CREATION_FAILED 9608 +#define DNS_ERROR_ZONE_ALREADY_EXISTS 9609 +#define DNS_ERROR_AUTOZONE_ALREADY_EXISTS 9610 +#define DNS_ERROR_INVALID_ZONE_TYPE 9611 +#define DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP 9612 +#define DNS_ERROR_ZONE_NOT_SECONDARY 9613 +#define DNS_ERROR_NEED_SECONDARY_ADDRESSES 9614 +#define DNS_ERROR_WINS_INIT_FAILED 9615 +#define DNS_ERROR_NEED_WINS_SERVERS 9616 +#define DNS_ERROR_NBSTAT_INIT_FAILED 9617 +#define DNS_ERROR_SOA_DELETE_INVALID 9618 +#define DNS_ERROR_PRIMARY_REQUIRES_DATAFILE 9651 +#define DNS_ERROR_INVALID_DATAFILE_NAME 9652 +#define DNS_ERROR_DATAFILE_OPEN_FAILURE 9653 +#define DNS_ERROR_FILE_WRITEBACK_FAILED 9654 +#define DNS_ERROR_DATAFILE_PARSING 9655 +#define DNS_ERROR_RECORD_DOES_NOT_EXIST 9701 +#define DNS_ERROR_RECORD_FORMAT 9702 +#define DNS_ERROR_NODE_CREATION_FAILED 9703 +#define DNS_ERROR_UNKNOWN_RECORD_TYPE 9704 +#define DNS_ERROR_RECORD_TIMED_OUT 9705 +#define DNS_ERROR_NAME_NOT_IN_ZONE 9706 +#define DNS_ERROR_CNAME_LOOP 9707 +#define DNS_ERROR_NODE_IS_CNAME 9708 +#define DNS_ERROR_CNAME_COLLISION 9709 +#define DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT 9710 +#define DNS_ERROR_RECORD_ALREADY_EXISTS 9711 +#define DNS_ERROR_SECONDARY_DATA 9712 +#define DNS_ERROR_NO_CREATE_CACHE_DATA 9713 +#define DNS_ERROR_NAME_DOES_NOT_EXIST 9714 +#define DNS_WARNING_PTR_CREATE_FAILED 9715 +#define DNS_WARNING_DOMAIN_UNDELETED 9716 +#define DNS_ERROR_DS_UNAVAILABLE 9717 +#define DNS_ERROR_DS_ZONE_ALREADY_EXISTS 9718 +#define DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE 9719 +#define DNS_INFO_AXFR_COMPLETE 9751 +#define DNS_ERROR_AXFR 9752 +#define DNS_INFO_ADDED_LOCAL_WINS 9753 +#define DNS_STATUS_CONTINUE_NEEDED 9801 +#define DNS_ERROR_NO_TCPIP 9851 +#define DNS_ERROR_NO_DNS_SERVERS 9852 +#define ERROR_SXS_SECTION_NOT_FOUND 14000 +#define ERROR_SXS_CANT_GEN_ACTCTX 14001 +#define ERROR_SXS_INVALID_ACTCTXDATA_FORMAT 14002 +#define ERROR_SXS_ASSEMBLY_NOT_FOUND 14003 +#define ERROR_SXS_MANIFEST_FORMAT_ERROR 14004 +#define ERROR_SXS_MANIFEST_PARSE_ERROR 14005 +#define ERROR_SXS_ACTIVATION_CONTEXT_DISABLED 14006 +#define ERROR_SXS_KEY_NOT_FOUND 14007 +#define ERROR_SXS_WRONG_SECTION_TYPE 14009 +#define ERROR_SXS_THREAD_QUERIES_DISABLED 14010 +#define ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET 14011 + +/* HRESULT values for OLE, SHELL and other Interface stuff */ +/* the codes 4000-40ff are reserved for OLE */ +#undef NOERROR /* arpa/nameser_compat.h defines this */ + +#ifdef RC_INVOKED +#define _HRESULT_TYPEDEF_(x) (x) +#else +#define _HRESULT_TYPEDEF_(x) ((HRESULT)x) +#endif + +#define NOERROR _HRESULT_TYPEDEF_(0L) +#define S_OK _HRESULT_TYPEDEF_(0L) +#define SEC_E_OK _HRESULT_TYPEDEF_(0L) +#define S_FALSE _HRESULT_TYPEDEF_(1L) + +#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL) + + +#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) +#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) +#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) +#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) +#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L) + + +#define CO_E_INIT_TLS _HRESULT_TYPEDEF_(0x80004006L) +#define CO_E_INIT_SHARED_ALLOCATOR _HRESULT_TYPEDEF_(0x80004007L) +#define CO_E_INIT_MEMORY_ALLOCATOR _HRESULT_TYPEDEF_(0x80004008L) +#define CO_E_INIT_CLASS_CACHE _HRESULT_TYPEDEF_(0x80004009L) +#define CO_E_INIT_RPC_CHANNEL _HRESULT_TYPEDEF_(0x8000400AL) +#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400BL) +#define CO_E_INIT_TLS_CHANNEL_CONTROL _HRESULT_TYPEDEF_(0x8000400CL) +#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR _HRESULT_TYPEDEF_(0x8000400DL) +#define CO_E_INIT_SCM_MUTEX_EXISTS _HRESULT_TYPEDEF_(0x8000400EL) +#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS _HRESULT_TYPEDEF_(0x8000400FL) +#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE _HRESULT_TYPEDEF_(0x80004010L) +#define CO_E_INIT_SCM_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80004011L) +#define CO_E_INIT_ONLY_SINGLE_THREADED _HRESULT_TYPEDEF_(0x80004012L) +#define CO_E_CANT_REMOTE _HRESULT_TYPEDEF_(0x80004013L) +#define CO_E_BAD_SERVER_NAME _HRESULT_TYPEDEF_(0x80004014L) +#define CO_E_WRONG_SERVER_IDENTITY _HRESULT_TYPEDEF_(0x80004015L) +#define CO_E_OLE1DDE_DISABLED _HRESULT_TYPEDEF_(0x80004016L) +#define CO_E_RUNAS_SYNTAX _HRESULT_TYPEDEF_(0x80004017L) +#define CO_E_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004018L) +#define CO_E_RUNAS_CREATEPROCESS_FAILURE _HRESULT_TYPEDEF_(0x80004019L) +#define CO_E_RUNAS_LOGON_FAILURE _HRESULT_TYPEDEF_(0x8000401AL) +#define CO_E_LAUNCH_PERMISSION_DENIED _HRESULT_TYPEDEF_(0x8000401BL) +#define CO_E_START_SERVICE_FAILURE _HRESULT_TYPEDEF_(0x8000401CL) +#define CO_E_REMOTE_COMMUNICATION_FAILURE _HRESULT_TYPEDEF_(0x8000401DL) +#define CO_E_SERVER_START_TIMEOUT _HRESULT_TYPEDEF_(0x8000401EL) +#define CO_E_CLSREG_INCONSISTENT _HRESULT_TYPEDEF_(0x8000401FL) +#define CO_E_IIDREG_INCONSISTENT _HRESULT_TYPEDEF_(0x80004020L) +#define CO_E_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80004021L) +#define CO_E_RELOAD_DLL _HRESULT_TYPEDEF_(0x80004022L) +#define CO_E_MSI_ERROR _HRESULT_TYPEDEF_(0x80004023L) +#define CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT _HRESULT_TYPEDEF_(0x80004024L) +#define CO_E_SERVER_PAUSED _HRESULT_TYPEDEF_(0x80004025L) +#define CO_E_SERVER_NOT_PAUSED _HRESULT_TYPEDEF_(0x80004026L) +#define CO_E_CLASS_DISABLED _HRESULT_TYPEDEF_(0x80004027L) +#define CO_E_CLRNOTAVAILABLE _HRESULT_TYPEDEF_(0x80004028L) +#define CO_E_ASYNC_WORK_REJECTED _HRESULT_TYPEDEF_(0x80004029L) +#define CO_E_SERVER_INIT_TIMEOUT _HRESULT_TYPEDEF_(0x8000402AL) +#define CO_E_NO_SECCTX_IN_ACTIVATE _HRESULT_TYPEDEF_(0x8000402BL) +#define CO_E_TRACKER_CONFIG _HRESULT_TYPEDEF_(0x80004030L) +#define CO_E_THREADPOOL_CONFIG _HRESULT_TYPEDEF_(0x80004031L) +#define CO_E_SXS_CONFIG _HRESULT_TYPEDEF_(0x80004032L) +#define CO_E_MALFORMED_SPN _HRESULT_TYPEDEF_(0x80004033L) + +#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL) + +#define RPC_E_CALL_REJECTED _HRESULT_TYPEDEF_(0x80010001L) +#define RPC_E_CALL_CANCELED _HRESULT_TYPEDEF_(0x80010002L) +#define RPC_E_CANTPOST_INSENDCALL _HRESULT_TYPEDEF_(0x80010003L) +#define RPC_E_CANTCALLOUT_INASYNCCALL _HRESULT_TYPEDEF_(0x80010004L) +#define RPC_E_CANTCALLOUT_INEXTERNALCALL _HRESULT_TYPEDEF_(0x80010005L) +#define RPC_E_CONNECTION_TERMINATED _HRESULT_TYPEDEF_(0x80010006L) +#define RPC_E_SERVER_DIED _HRESULT_TYPEDEF_(0x80010007L) +#define RPC_E_CLIENT_DIED _HRESULT_TYPEDEF_(0x80010008L) +#define RPC_E_INVALID_DATAPACKET _HRESULT_TYPEDEF_(0x80010009L) +#define RPC_E_CANTTRANSMIT_CALL _HRESULT_TYPEDEF_(0x8001000AL) +#define RPC_E_CLIENT_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000BL) +#define RPC_E_CLIENT_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000CL) +#define RPC_E_SERVER_CANTMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000DL) +#define RPC_E_SERVER_CANTUNMARSHAL_DATA _HRESULT_TYPEDEF_(0x8001000EL) +#define RPC_E_INVALID_DATA _HRESULT_TYPEDEF_(0x8001000FL) +#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L) +#define RPC_E_CANTCALLOUT_AGAIN _HRESULT_TYPEDEF_(0x80010011L) +#define RPC_E_SERVER_DIED_DNE _HRESULT_TYPEDEF_(0x80010012L) +#define RPC_E_SYS_CALL_FAILED _HRESULT_TYPEDEF_(0x80010100L) +#define RPC_E_OUT_OF_RESOURCES _HRESULT_TYPEDEF_(0x80010101L) +#define RPC_E_ATTEMPTED_MULTITHREAD _HRESULT_TYPEDEF_(0x80010102L) +#define RPC_E_NOT_REGISTERED _HRESULT_TYPEDEF_(0x80010103L) +#define RPC_E_FAULT _HRESULT_TYPEDEF_(0x80010104L) +#define RPC_E_SERVERFAULT _HRESULT_TYPEDEF_(0x80010105L) +#define RPC_E_CHANGED_MODE _HRESULT_TYPEDEF_(0x80010106L) +#define RPC_E_INVALIDMETHOD _HRESULT_TYPEDEF_(0x80010107L) +#define RPC_E_DISCONNECTED _HRESULT_TYPEDEF_(0x80010108L) +#define RPC_E_RETRY _HRESULT_TYPEDEF_(0x80010109L) +#define RPC_E_SERVERCALL_RETRYLATER _HRESULT_TYPEDEF_(0x8001010AL) +#define RPC_E_SERVERCALL_REJECTED _HRESULT_TYPEDEF_(0x8001010BL) +#define RPC_E_INVALID_CALLDATA _HRESULT_TYPEDEF_(0x8001010CL) +#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL _HRESULT_TYPEDEF_(0x8001010DL) +#define RPC_E_WRONG_THREAD _HRESULT_TYPEDEF_(0x8001010EL) +#define RPC_E_THREAD_NOT_INIT _HRESULT_TYPEDEF_(0x8001010FL) +#define RPC_E_VERSION_MISMATCH _HRESULT_TYPEDEF_(0x80010110L) +#define RPC_E_INVALID_HEADER _HRESULT_TYPEDEF_(0x80010111L) +#define RPC_E_INVALID_EXTENSION _HRESULT_TYPEDEF_(0x80010112L) +#define RPC_E_INVALID_IPID _HRESULT_TYPEDEF_(0x80010113L) +#define RPC_E_INVALID_OBJECT _HRESULT_TYPEDEF_(0x80010114L) +#define RPC_S_CALLPENDING _HRESULT_TYPEDEF_(0x80010115L) +#define RPC_S_WAITONTIMER _HRESULT_TYPEDEF_(0x80010116L) +#define RPC_E_CALL_COMPLETE _HRESULT_TYPEDEF_(0x80010117L) +#define RPC_E_UNSECURE_CALL _HRESULT_TYPEDEF_(0x80010118L) +#define RPC_E_TOO_LATE _HRESULT_TYPEDEF_(0x80010119L) +#define RPC_E_NO_GOOD_SECURITY_PACKAGES _HRESULT_TYPEDEF_(0x8001011AL) +#define RPC_E_ACCESS_DENIED _HRESULT_TYPEDEF_(0x8001011BL) +#define RPC_E_REMOTE_DISABLED _HRESULT_TYPEDEF_(0x8001011CL) +#define RPC_E_INVALID_OBJREF _HRESULT_TYPEDEF_(0x8001011DL) +#define RPC_E_NO_CONTEXT _HRESULT_TYPEDEF_(0x8001011EL) +#define RPC_E_TIMEOUT _HRESULT_TYPEDEF_(0x8001011FL) +#define RPC_E_NO_SYNC _HRESULT_TYPEDEF_(0x80010120L) +#define RPC_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8001FFFFL) + +#define DISP_E_UNKNOWNINTERFACE _HRESULT_TYPEDEF_(0x80020001L) +#define DISP_E_MEMBERNOTFOUND _HRESULT_TYPEDEF_(0x80020003L) +#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L) +#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) +#define DISP_E_UNKNOWNNAME _HRESULT_TYPEDEF_(0x80020006L) +#define DISP_E_NONAMEDARGS _HRESULT_TYPEDEF_(0x80020007L) +#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L) +#define DISP_E_EXCEPTION _HRESULT_TYPEDEF_(0x80020009L) +#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) +#define DISP_E_BADINDEX _HRESULT_TYPEDEF_(0x8002000BL) +#define DISP_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002000CL) +#define DISP_E_ARRAYISLOCKED _HRESULT_TYPEDEF_(0x8002000DL) +#define DISP_E_BADPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL) +#define DISP_E_PARAMNOTOPTIONAL _HRESULT_TYPEDEF_(0x8002000FL) +#define DISP_E_BADCALLEE _HRESULT_TYPEDEF_(0x80020010L) +#define DISP_E_NOTACOLLECTION _HRESULT_TYPEDEF_(0x80020011L) +#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L) + +#define TYPE_E_BUFFERTOOSMALL _HRESULT_TYPEDEF_(0x80028016L) +#define TYPE_E_FIELDNOTFOUND _HRESULT_TYPEDEF_(0x80028017L) +#define TYPE_E_INVDATAREAD _HRESULT_TYPEDEF_(0x80028018L) +#define TYPE_E_UNSUPFORMAT _HRESULT_TYPEDEF_(0x80028019L) +#define TYPE_E_REGISTRYACCESS _HRESULT_TYPEDEF_(0x8002801CL) +#define TYPE_E_LIBNOTREGISTERED _HRESULT_TYPEDEF_(0x8002801DL) +#define TYPE_E_UNDEFINEDTYPE _HRESULT_TYPEDEF_(0x80028027L) +#define TYPE_E_QUALIFIEDNAMEDISALLOWED _HRESULT_TYPEDEF_(0x80028028L) +#define TYPE_E_INVALIDSTATE _HRESULT_TYPEDEF_(0x80028029L) +#define TYPE_E_WRONGTYPEKIND _HRESULT_TYPEDEF_(0x8002802AL) +#define TYPE_E_ELEMENTNOTFOUND _HRESULT_TYPEDEF_(0x8002802BL) +#define TYPE_E_AMBIGUOUSNAME _HRESULT_TYPEDEF_(0x8002802CL) +#define TYPE_E_NAMECONFLICT _HRESULT_TYPEDEF_(0x8002802DL) +#define TYPE_E_UNKNOWNLCID _HRESULT_TYPEDEF_(0x8002802EL) +#define TYPE_E_DLLFUNCTIONNOTFOUND _HRESULT_TYPEDEF_(0x8002802FL) +#define TYPE_E_BADMODULEKIND _HRESULT_TYPEDEF_(0x800288BDL) +#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L) +#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L) +#define TYPE_E_INVALIDID _HRESULT_TYPEDEF_(0x800288CFL) +#define TYPE_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80028CA0L) +#define TYPE_E_OUTOFBOUNDS _HRESULT_TYPEDEF_(0x80028CA1L) +#define TYPE_E_IOERROR _HRESULT_TYPEDEF_(0x80028CA2L) +#define TYPE_E_CANTCREATETMPFILE _HRESULT_TYPEDEF_(0x80028CA3L) +#define TYPE_E_CANTLOADLIBRARY _HRESULT_TYPEDEF_(0x80029C4AL) +#define TYPE_E_INCONSISTENTPROPFUNCS _HRESULT_TYPEDEF_(0x80029C83L) +#define TYPE_E_CIRCULARTYPE _HRESULT_TYPEDEF_(0x80029C84L) + +#define STG_S_CONVERTED _HRESULT_TYPEDEF_(0x00030200L) +#define STG_S_BLOCK _HRESULT_TYPEDEF_(0x00030201L) +#define STG_S_RETRYNOW _HRESULT_TYPEDEF_(0x00030202L) +#define STG_S_MONITORING _HRESULT_TYPEDEF_(0x00030203L) +#define STG_S_MULTIPLEOPENS _HRESULT_TYPEDEF_(0x00030204L) +#define STG_S_CONSOLIDATIONFAILED _HRESULT_TYPEDEF_(0x00030205L) +#define STG_S_CANNOTCONSOLIDATE _HRESULT_TYPEDEF_(0x00030206L) + +#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L) +#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L) +#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L) +#define STG_E_TOOMANYOPENFILES _HRESULT_TYPEDEF_(0x80030004L) +#define STG_E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80030005L) +#define STG_E_INVALIDHANDLE _HRESULT_TYPEDEF_(0x80030006L) +#define STG_E_INSUFFICIENTMEMORY _HRESULT_TYPEDEF_(0x80030008L) +#define STG_E_INVALIDPOINTER _HRESULT_TYPEDEF_(0x80030009L) +#define STG_E_NOMOREFILES _HRESULT_TYPEDEF_(0x80030012L) +#define STG_E_DISKISWRITEPROTECTED _HRESULT_TYPEDEF_(0x80030013L) +#define STG_E_SEEKERROR _HRESULT_TYPEDEF_(0x80030019L) +#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL) +#define STG_E_READFAULT _HRESULT_TYPEDEF_(0x8003001EL) +#define STG_E_SHAREVIOLATION _HRESULT_TYPEDEF_(0x80030020L) +#define STG_E_LOCKVIOLATION _HRESULT_TYPEDEF_(0x80030021L) +#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L) +#define STG_E_INVALIDPARAMETER _HRESULT_TYPEDEF_(0x80030057L) +#define STG_E_MEDIUMFULL _HRESULT_TYPEDEF_(0x80030070L) +#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL) +#define STG_E_INVALIDHEADER _HRESULT_TYPEDEF_(0x800300FBL) +#define STG_E_INVALIDNAME _HRESULT_TYPEDEF_(0x800300FCL) +#define STG_E_UNKNOWN _HRESULT_TYPEDEF_(0x800300FDL) +#define STG_E_UNIMPLEMENTEDFUNCTION _HRESULT_TYPEDEF_(0x800300FEL) +#define STG_E_INVALIDFLAG _HRESULT_TYPEDEF_(0x800300FFL) +#define STG_E_INUSE _HRESULT_TYPEDEF_(0x80030100L) +#define STG_E_NOTCURRENT _HRESULT_TYPEDEF_(0x80030101L) +#define STG_E_REVERTED _HRESULT_TYPEDEF_(0x80030102L) +#define STG_E_CANTSAVE _HRESULT_TYPEDEF_(0x80030103L) +#define STG_E_OLDFORMAT _HRESULT_TYPEDEF_(0x80030104L) +#define STG_E_OLDDLL _HRESULT_TYPEDEF_(0x80030105L) +#define STG_E_SHAREREQUIRED _HRESULT_TYPEDEF_(0x80030106L) +#define STG_E_NOTFILEBASEDSTORAGE _HRESULT_TYPEDEF_(0x80030107L) +#define STG_E_EXTANTMARSHALLINGS _HRESULT_TYPEDEF_(0x80030108L) +#define STG_E_DOCFILECORRUPT _HRESULT_TYPEDEF_(0x80030109L) + +#define STG_E_STATUS_COPY_PROTECTION_FAILURE _HRESULT_TYPEDEF_(0x80030305L) +#define STG_E_CSS_AUTHENTICATION_FAILURE _HRESULT_TYPEDEF_(0x80030306L) +#define STG_E_CSS_KEY_NOT_PRESENT _HRESULT_TYPEDEF_(0x80030307L) +#define STG_E_CSS_KEY_NOT_ESTABLISHED _HRESULT_TYPEDEF_(0x80030308L) +#define STG_E_CSS_SCRAMBLED_SECTOR _HRESULT_TYPEDEF_(0x80030309L) +#define STG_E_CSS_REGION_MISMATCH _HRESULT_TYPEDEF_(0x8003030AL) +#define STG_E_RESETS_EXHAUSTED _HRESULT_TYPEDEF_(0x8003030BL) + +#define OLE_S_FIRST _HRESULT_TYPEDEF_(0x00040000L) +#define OLE_S_USEREG _HRESULT_TYPEDEF_(0x00040000L) +#define OLE_S_STATIC _HRESULT_TYPEDEF_(0x00040001L) +#define OLE_S_MAC_CLIPFORMAT _HRESULT_TYPEDEF_(0x00040002L) +#define OLE_S_LAST _HRESULT_TYPEDEF_(0x000400FFL) + +#define OLE_E_FIRST _HRESULT_TYPEDEF_(0x80040000L) +#define OLE_E_OLEVERB _HRESULT_TYPEDEF_(0x80040000L) +#define OLE_E_ADVF _HRESULT_TYPEDEF_(0x80040001L) +#define OLE_E_ENUM_NOMORE _HRESULT_TYPEDEF_(0x80040002L) +#define OLE_E_ADVISENOTSUPPORTED _HRESULT_TYPEDEF_(0x80040003L) +#define OLE_E_NOCONNECTION _HRESULT_TYPEDEF_(0x80040004L) +#define OLE_E_NOTRUNNING _HRESULT_TYPEDEF_(0x80040005L) +#define OLE_E_NOCACHE _HRESULT_TYPEDEF_(0x80040006L) +#define OLE_E_BLANK _HRESULT_TYPEDEF_(0x80040007L) +#define OLE_E_CLASSDIFF _HRESULT_TYPEDEF_(0x80040008L) +#define OLE_E_CANT_GETMONIKER _HRESULT_TYPEDEF_(0x80040009L) +#define OLE_E_CANT_BINDTOSOURCE _HRESULT_TYPEDEF_(0x8004000AL) +#define OLE_E_STATIC _HRESULT_TYPEDEF_(0x8004000BL) +#define OLE_E_PROMPTSAVECANCELLED _HRESULT_TYPEDEF_(0x8004000CL) +#define OLE_E_INVALIDRECT _HRESULT_TYPEDEF_(0x8004000DL) +#define OLE_E_WRONGCOMPOBJ _HRESULT_TYPEDEF_(0x8004000EL) +#define OLE_E_INVALIDHWND _HRESULT_TYPEDEF_(0x8004000FL) +#define OLE_E_NOT_INPLACEACTIVE _HRESULT_TYPEDEF_(0x80040010L) +#define OLE_E_CANTCONVERT _HRESULT_TYPEDEF_(0x80040011L) +#define OLE_E_NOSTORAGE _HRESULT_TYPEDEF_(0x80040012L) +#define DV_E_FORMATETC _HRESULT_TYPEDEF_(0x80040064L) +#define DV_E_DVTARGETDEVICE _HRESULT_TYPEDEF_(0x80040065L) +#define DV_E_STGMEDIUM _HRESULT_TYPEDEF_(0x80040066L) +#define DV_E_STATDATA _HRESULT_TYPEDEF_(0x80040067L) +#define DV_E_LINDEX _HRESULT_TYPEDEF_(0x80040068L) +#define DV_E_TYMED _HRESULT_TYPEDEF_(0x80040069L) +#define DV_E_CLIPFORMAT _HRESULT_TYPEDEF_(0x8004006AL) +#define DV_E_DVASPECT _HRESULT_TYPEDEF_(0x8004006BL) +#define DV_E_DVTARGETDEVICE_SIZE _HRESULT_TYPEDEF_(0x8004006CL) +#define DV_E_NOIVIEWOBJECT _HRESULT_TYPEDEF_(0x8004006DL) +#define OLE_E_LAST _HRESULT_TYPEDEF_(0x800400FFL) + +#define DRAGDROP_S_FIRST _HRESULT_TYPEDEF_(0x00040100L) +#define DRAGDROP_S_DROP _HRESULT_TYPEDEF_(0x00040100L) +#define DRAGDROP_S_CANCEL _HRESULT_TYPEDEF_(0x00040101L) +#define DRAGDROP_S_USEDEFAULTCURSORS _HRESULT_TYPEDEF_(0x00040102L) +#define DRAGDROP_S_LAST _HRESULT_TYPEDEF_(0x0004010FL) + +#define DRAGDROP_E_FIRST _HRESULT_TYPEDEF_(0x80040100L) +#define DRAGDROP_E_NOTREGISTERED _HRESULT_TYPEDEF_(0x80040100L) +#define DRAGDROP_E_ALREADYREGISTERED _HRESULT_TYPEDEF_(0x80040101L) +#define DRAGDROP_E_INVALIDHWND _HRESULT_TYPEDEF_(0x80040102L) +#define DRAGDROP_E_LAST _HRESULT_TYPEDEF_(0x8004010FL) + + +#define CLASSFACTORY_S_FIRST _HRESULT_TYPEDEF_(0x00040110L) +#define CLASSFACTORY_S_LAST _HRESULT_TYPEDEF_(0x0004011FL) + +#define CLASSFACTORY_E_FIRST _HRESULT_TYPEDEF_(0x80040110L) +#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L) +#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L) +#define CLASS_E_NOTLICENSED _HRESULT_TYPEDEF_(0x80040112L) +#define CLASSFACTORY_E_LAST _HRESULT_TYPEDEF_(0x8004011FL) + +#define MARSHAL_S_FIRST _HRESULT_TYPEDEF_(0x00040120L) +#define MARSHAL_S_LAST _HRESULT_TYPEDEF_(0x0004012FL) + +#define MARSHAL_E_FIRST _HRESULT_TYPEDEF_(0x80040120L) +#define MARSHAL_E_LAST _HRESULT_TYPEDEF_(0x8004012FL) + +#define DATA_S_FIRST _HRESULT_TYPEDEF_(0x00040130L) +#define DATA_S_SAMEFORMATETC _HRESULT_TYPEDEF_(0x00040130L) +#define DATA_S_LAST _HRESULT_TYPEDEF_(0x0004013FL) + +#define DATA_E_FIRST _HRESULT_TYPEDEF_(0x80040130L) +#define DATA_E_LAST _HRESULT_TYPEDEF_(0x8004013FL) + +#define VIEW_S_FIRST _HRESULT_TYPEDEF_(0x00040140L) +#define VIEW_S_ALREADY_FROZEN _HRESULT_TYPEDEF_(0x00040140L) +#define VIEW_S_LAST _HRESULT_TYPEDEF_(0x0004014FL) + +#define VIEW_E_FIRST _HRESULT_TYPEDEF_(0x80040140L) +#define VIEW_E_DRAW _HRESULT_TYPEDEF_(0x80040140L) +#define VIEW_E_LAST _HRESULT_TYPEDEF_(0x8004014FL) + +#define REGDB_S_FIRST _HRESULT_TYPEDEF_(0x00040150L) +#define REGDB_S_LAST _HRESULT_TYPEDEF_(0x0004015FL) + +#define REGDB_E_FIRST _HRESULT_TYPEDEF_(0x80040150L) +#define REGDB_E_READREGDB _HRESULT_TYPEDEF_(0x80040150L) +#define REGDB_E_WRITEREGDB _HRESULT_TYPEDEF_(0x80040151L) +#define REGDB_E_KEYMISSING _HRESULT_TYPEDEF_(0x80040152L) +#define REGDB_E_INVALIDVALUE _HRESULT_TYPEDEF_(0x80040153L) +#define REGDB_E_CLASSNOTREG _HRESULT_TYPEDEF_(0x80040154L) +#define REGDB_E_IIDNOTREG _HRESULT_TYPEDEF_(0x80040155L) +#define REGDB_E_LAST _HRESULT_TYPEDEF_(0x8004015FL) + +#define CAT_E_FIRST _HRESULT_TYPEDEF_(0x80040160L) +#define CAT_E_CATIDNOEXIST _HRESULT_TYPEDEF_(0x80040160L) +#define CAT_E_NODESCRIPTION _HRESULT_TYPEDEF_(0x80040161L) +#define CAT_E_LAST _HRESULT_TYPEDEF_(0x80040161L) + +#define CACHE_S_FIRST _HRESULT_TYPEDEF_(0x00040170L) +#define CACHE_S_FORMATETC_NOTSUPPORTED _HRESULT_TYPEDEF_(0x00040170L) +#define CACHE_S_SAMECACHE _HRESULT_TYPEDEF_(0x00040171L) +#define CACHE_S_SOMECACHES_NOTUPDATED _HRESULT_TYPEDEF_(0x00040172L) +#define CACHE_S_LAST _HRESULT_TYPEDEF_(0x0004017FL) + +#define CACHE_E_FIRST _HRESULT_TYPEDEF_(0x80040170L) +#define CACHE_E_NOCACHE_UPDATED _HRESULT_TYPEDEF_(0x80040170L) +#define CACHE_E_LAST _HRESULT_TYPEDEF_(0x8004017FL) + +#define OLEOBJ_S_FIRST _HRESULT_TYPEDEF_(0x00040180L) +#define OLEOBJ_S_INVALIDVERB _HRESULT_TYPEDEF_(0x00040180L) +#define OLEOBJ_S_CANNOT_DOVERB_NOW _HRESULT_TYPEDEF_(0x00040181L) +#define OLEOBJ_S_INVALIDHWND _HRESULT_TYPEDEF_(0x00040182L) +#define OLEOBJ_S_LAST _HRESULT_TYPEDEF_(0x0004018FL) + +#define OLEOBJ_E_FIRST _HRESULT_TYPEDEF_(0x80040180L) +#define OLEOBJ_E_NOVERBS _HRESULT_TYPEDEF_(0x80040180L) +#define OLEOBJ_E_INVALIDVERB _HRESULT_TYPEDEF_(0x80040181L) +#define OLEOBJ_E_LAST _HRESULT_TYPEDEF_(0x8004018FL) + +#define CLIENTSITE_S_FIRST _HRESULT_TYPEDEF_(0x00040190L) +#define CLIENTSITE_S_LAST _HRESULT_TYPEDEF_(0x0004019FL) + +#define CLIENTSITE_E_FIRST _HRESULT_TYPEDEF_(0x80040190L) +#define CLIENTSITE_E_LAST _HRESULT_TYPEDEF_(0x8004019FL) + +#define INPLACE_S_FIRST _HRESULT_TYPEDEF_(0x000401A0L) +#define INPLACE_S_TRUNCATED _HRESULT_TYPEDEF_(0x000401A0L) +#define INPLACE_S_LAST _HRESULT_TYPEDEF_(0x000401AFL) + +#define INPLACE_E_FIRST _HRESULT_TYPEDEF_(0x800401A0L) +#define INPLACE_E_NOTUNDOABLE _HRESULT_TYPEDEF_(0x800401A0L) +#define INPLACE_E_NOTOOLSPACE _HRESULT_TYPEDEF_(0x800401A1L) +#define INPLACE_E_LAST _HRESULT_TYPEDEF_(0x800401AFL) + +#define ENUM_S_FIRST _HRESULT_TYPEDEF_(0x000401B0L) +#define ENUM_S_LAST _HRESULT_TYPEDEF_(0x000401BFL) + +#define ENUM_E_FIRST _HRESULT_TYPEDEF_(0x800401B0L) +#define ENUM_E_LAST _HRESULT_TYPEDEF_(0x800401BFL) + +#define CONVERT10_S_FIRST _HRESULT_TYPEDEF_(0x000401C0L) +#define CONVERT10_S_NO_PRESENTATION _HRESULT_TYPEDEF_(0x000401C0L) +#define CONVERT10_S_LAST _HRESULT_TYPEDEF_(0x000401CFL) + +#define CONVERT10_E_FIRST _HRESULT_TYPEDEF_(0x800401C0L) +#define CONVERT10_E_OLESTREAM_GET _HRESULT_TYPEDEF_(0x800401C0L) +#define CONVERT10_E_OLESTREAM_PUT _HRESULT_TYPEDEF_(0x800401C1L) +#define CONVERT10_E_OLESTREAM_FMT _HRESULT_TYPEDEF_(0x800401C2L) +#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB _HRESULT_TYPEDEF_(0x800401C3L) +#define CONVERT10_E_STG_FMT _HRESULT_TYPEDEF_(0x800401C4L) +#define CONVERT10_E_STG_NO_STD_STREAM _HRESULT_TYPEDEF_(0x800401C5L) +#define CONVERT10_E_STG_DIB_TO_BITMAP _HRESULT_TYPEDEF_(0x800401C6L) +#define CONVERT10_E_LAST _HRESULT_TYPEDEF_(0x800401CFL) + +#define CLIPBRD_S_FIRST _HRESULT_TYPEDEF_(0x000401D0L) +#define CLIPBRD_S_LAST _HRESULT_TYPEDEF_(0x000401DFL) + +#define CLIPBRD_E_FIRST _HRESULT_TYPEDEF_(0x800401D0L) +#define CLIPBRD_E_LAST _HRESULT_TYPEDEF_(0x800401DFL) +#define CLIPBRD_E_CANT_OPEN _HRESULT_TYPEDEF_(0x800401D0L) +#define CLIPBRD_E_CANT_EMPTY _HRESULT_TYPEDEF_(0x800401D1L) +#define CLIPBRD_E_CANT_SET _HRESULT_TYPEDEF_(0x800401D2L) +#define CLIPBRD_E_BAD_DATA _HRESULT_TYPEDEF_(0x800401D3L) +#define CLIPBRD_E_CANT_CLOSE _HRESULT_TYPEDEF_(0x800401D4L) + +#define MK_S_FIRST _HRESULT_TYPEDEF_(0x000401E0L) +#define MK_S_REDUCED_TO_SELF _HRESULT_TYPEDEF_(0x000401E2L) +#define MK_S_ME _HRESULT_TYPEDEF_(0x000401E4L) +#define MK_S_HIM _HRESULT_TYPEDEF_(0x000401E5L) +#define MK_S_US _HRESULT_TYPEDEF_(0x000401E6L) +#define MK_S_MONIKERALREADYREGISTERED _HRESULT_TYPEDEF_(0x000401E7L) +#define MK_S_LAST _HRESULT_TYPEDEF_(0x000401EFL) + +#define MK_E_FIRST _HRESULT_TYPEDEF_(0x800401E0L) +#define MK_E_CONNECTMANUALLY _HRESULT_TYPEDEF_(0x800401E0L) +#define MK_E_EXCEEDEDDEADLINE _HRESULT_TYPEDEF_(0x800401E1L) +#define MK_E_NEEDGENERIC _HRESULT_TYPEDEF_(0x800401E2L) +#define MK_E_UNAVAILABLE _HRESULT_TYPEDEF_(0x800401E3L) +#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L) +#define MK_E_NOOBJECT _HRESULT_TYPEDEF_(0x800401E5L) +#define MK_E_INVALIDEXTENSION _HRESULT_TYPEDEF_(0x800401E6L) +#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED _HRESULT_TYPEDEF_(0x800401E7L) +#define MK_E_NOTBINDABLE _HRESULT_TYPEDEF_(0x800401E8L) +#define MK_E_NOTBOUND _HRESULT_TYPEDEF_(0x800401E9L) +#define MK_E_CANTOPENFILE _HRESULT_TYPEDEF_(0x800401EAL) +#define MK_E_MUSTBOTHERUSER _HRESULT_TYPEDEF_(0x800401EBL) +#define MK_E_NOINVERSE _HRESULT_TYPEDEF_(0x800401ECL) +#define MK_E_NOSTORAGE _HRESULT_TYPEDEF_(0x800401EDL) +#define MK_E_NOPREFIX _HRESULT_TYPEDEF_(0x800401EEL) +#define MK_E_ENUMERATION_FAILED _HRESULT_TYPEDEF_(0x800401EFL) +#define MK_E_LAST _HRESULT_TYPEDEF_(0x800401EFL) + +#define CO_S_FIRST _HRESULT_TYPEDEF_(0x000401F0L) +#define CO_S_LAST _HRESULT_TYPEDEF_(0x000401FFL) + +#define CO_E_FIRST _HRESULT_TYPEDEF_(0x800401F0L) +#define CO_E_NOTINITIALIZED _HRESULT_TYPEDEF_(0x800401F0L) +#define CO_E_ALREADYINITIALIZED _HRESULT_TYPEDEF_(0x800401F1L) +#define CO_E_CANTDETERMINECLASS _HRESULT_TYPEDEF_(0x800401F2L) +#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L) +#define CO_E_IIDSTRING _HRESULT_TYPEDEF_(0x800401F4L) +#define CO_E_APPNOTFOUND _HRESULT_TYPEDEF_(0x800401F5L) +#define CO_E_APPSINGLEUSE _HRESULT_TYPEDEF_(0x800401F6L) +#define CO_E_ERRORINAPP _HRESULT_TYPEDEF_(0x800401F7L) +#define CO_E_DLLNOTFOUND _HRESULT_TYPEDEF_(0x800401F8L) +#define CO_E_ERRORINDLL _HRESULT_TYPEDEF_(0x800401F9L) +#define CO_E_WRONGOSFORAPP _HRESULT_TYPEDEF_(0x800401FAL) +#define CO_E_OBJNOTREG _HRESULT_TYPEDEF_(0x800401FBL) +#define CO_E_OBJISREG _HRESULT_TYPEDEF_(0x800401FCL) +#define CO_E_OBJNOTCONNECTED _HRESULT_TYPEDEF_(0x800401FDL) +#define CO_E_APPDIDNTREG _HRESULT_TYPEDEF_(0x800401FEL) +#define CO_E_RELEASED _HRESULT_TYPEDEF_(0x800401FFL) +#define CO_E_LAST _HRESULT_TYPEDEF_(0x800401FFL) +#define CO_E_FAILEDTOIMPERSONATE _HRESULT_TYPEDEF_(0x80040200L) +#define CO_E_FAILEDTOGETSECCTX _HRESULT_TYPEDEF_(0x80040201L) +#define CO_E_FAILEDTOOPENTHREADTOKEN _HRESULT_TYPEDEF_(0x80040202L) +#define CO_E_FAILEDTOGETTOKENINFO _HRESULT_TYPEDEF_(0x80040203L) +#define CO_E_TRUSTEEDOESNTMATCHCLIENT _HRESULT_TYPEDEF_(0x80040204L) +#define CO_E_FAILEDTOQUERYCLIENTBLANKET _HRESULT_TYPEDEF_(0x80040205L) +#define CO_E_FAILEDTOSETDACL _HRESULT_TYPEDEF_(0x80040206L) +#define CO_E_ACCESSCHECKFAILED _HRESULT_TYPEDEF_(0x80040207L) +#define CO_E_NETACCESSAPIFAILED _HRESULT_TYPEDEF_(0x80040208L) +#define CO_E_WRONGTRUSTEENAMESYNTAX _HRESULT_TYPEDEF_(0x80040209L) +#define CO_E_INVALIDSID _HRESULT_TYPEDEF_(0x8004020AL) +#define CO_E_CONVERSIONFAILED _HRESULT_TYPEDEF_(0x8004020BL) +#define CO_E_NOMATCHINGSIDFOUND _HRESULT_TYPEDEF_(0x8004020CL) +#define CO_E_LOOKUPACCSIDFAILED _HRESULT_TYPEDEF_(0x8004020DL) +#define CO_E_NOMATCHINGNAMEFOUND _HRESULT_TYPEDEF_(0x8004020EL) +#define CO_E_LOOKUPACCNAMEFAILED _HRESULT_TYPEDEF_(0x8004020FL) +#define CO_E_SETSERLHNDLFAILED _HRESULT_TYPEDEF_(0x80040210L) +#define CO_E_FAILEDTOGETWINDIR _HRESULT_TYPEDEF_(0x80040211L) +#define CO_E_PATHTOOLONG _HRESULT_TYPEDEF_(0x80040212L) +#define CO_E_FAILEDTOGENUUID _HRESULT_TYPEDEF_(0x80040213L) +#define CO_E_FAILEDTOCREATEFILE _HRESULT_TYPEDEF_(0x80040214L) +#define CO_E_FAILEDTOCLOSEHANDLE _HRESULT_TYPEDEF_(0x80040215L) +#define CO_E_EXCEEDSYSACLLIMIT _HRESULT_TYPEDEF_(0x80040216L) +#define CO_E_ACESINWRONGORDER _HRESULT_TYPEDEF_(0x80040217L) +#define CO_E_INCOMPATIBLESTREAMVERSION _HRESULT_TYPEDEF_(0x80040218L) +#define CO_E_FAILEDTOOPENPROCESSTOKEN _HRESULT_TYPEDEF_(0x80040219L) +#define CO_E_DECODEFAILED _HRESULT_TYPEDEF_(0x8004021AL) +#define CO_E_ACNOTINITIALIZED _HRESULT_TYPEDEF_(0x8004021BL) + +#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L) +#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L) +#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) +#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) + +#define CO_S_NOTALLINTERFACES _HRESULT_TYPEDEF_(0x00080012L) + +#define CO_E_CLASS_CREATE_FAILED _HRESULT_TYPEDEF_(0x80080001L) +#define CO_E_SCM_ERROR _HRESULT_TYPEDEF_(0x80080002L) +#define CO_E_SCM_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080003L) +#define CO_E_BAD_PATH _HRESULT_TYPEDEF_(0x80080004L) +#define CO_E_SERVER_EXEC_FAILURE _HRESULT_TYPEDEF_(0x80080005L) +#define CO_E_OBJSRV_RPC_FAILURE _HRESULT_TYPEDEF_(0x80080006L) +#define MK_E_NO_NORMALIZED _HRESULT_TYPEDEF_(0x80080007L) +#define CO_E_SERVER_STOPPING _HRESULT_TYPEDEF_(0x80080008L) +#define MEM_E_INVALID_ROOT _HRESULT_TYPEDEF_(0x80080009L) +#define MEM_E_INVALID_LINK _HRESULT_TYPEDEF_(0x80080010L) +#define MEM_E_INVALID_SIZE _HRESULT_TYPEDEF_(0x80080011L) + +/*Cryptographic Error Codes */ +#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L) +#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L) +#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L) +#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L) +#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L) +#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L) +#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L) +#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L) +#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L) +#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL) +#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL) +#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL) +#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL) +#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL) +#define NTE_EXISTS _HRESULT_TYPEDEF_(0x8009000FL) +#define NTE_PERM _HRESULT_TYPEDEF_(0x80090010L) +#define NTE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090011L) +#define NTE_DOUBLE_ENCRYPT _HRESULT_TYPEDEF_(0x80090012L) +#define NTE_BAD_PROVIDER _HRESULT_TYPEDEF_(0x80090013L) +#define NTE_BAD_PROV_TYPE _HRESULT_TYPEDEF_(0x80090014L) +#define NTE_BAD_PUBLIC_KEY _HRESULT_TYPEDEF_(0x80090015L) +#define NTE_BAD_KEYSET _HRESULT_TYPEDEF_(0x80090016L) +#define NTE_PROV_TYPE_NOT_DEF _HRESULT_TYPEDEF_(0x80090017L) +#define NTE_PROV_TYPE_ENTRY_BAD _HRESULT_TYPEDEF_(0x80090018L) +#define NTE_KEYSET_NOT_DEF _HRESULT_TYPEDEF_(0x80090019L) +#define NTE_KEYSET_ENTRY_BAD _HRESULT_TYPEDEF_(0x8009001AL) +#define NTE_PROV_TYPE_NO_MATCH _HRESULT_TYPEDEF_(0x8009001BL) +#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL) +#define NTE_PROVIDER_DLL_FAIL _HRESULT_TYPEDEF_(0x8009001DL) +#define NTE_PROV_DLL_NOT_FOUND _HRESULT_TYPEDEF_(0x8009001EL) +#define NTE_BAD_KEYSET_PARAM _HRESULT_TYPEDEF_(0x8009001FL) +#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L) +#define NTE_SYS_ERR _HRESULT_TYPEDEF_(0x80090021L) +#define NTE_OP_OK _HRESULT_TYPEDEF_(0) + +#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L) +#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L) +#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) +#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) +#define SEC_E_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80090304L) +#define SEC_E_SECPKG_NOT_FOUND _HRESULT_TYPEDEF_(0x80090305L) +#define SEC_E_NOT_OWNER _HRESULT_TYPEDEF_(0x80090306L) +#define SEC_E_CANNOT_INSTALL _HRESULT_TYPEDEF_(0x80090307L) +#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) +#define SEC_E_CANNOT_PACK _HRESULT_TYPEDEF_(0x80090309L) +#define SEC_E_QOP_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009030AL) +#define SEC_E_NO_IMPERSONATION _HRESULT_TYPEDEF_(0x8009030BL) +#define SEC_E_LOGON_DENIED _HRESULT_TYPEDEF_(0x8009030CL) +#define SEC_E_UNKNOWN_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030DL) +#define SEC_E_NO_CREDENTIALS _HRESULT_TYPEDEF_(0x8009030EL) +#define SEC_E_MESSAGE_ALTERED _HRESULT_TYPEDEF_(0x8009030FL) +#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) +#define SEC_E_NO_AUTHENTICATING_AUTHORITY _HRESULT_TYPEDEF_(0x80090311L) +#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) +#define SEC_I_COMPLETE_NEEDED _HRESULT_TYPEDEF_(0x00090313L) +#define SEC_I_COMPLETE_AND_CONTINUE _HRESULT_TYPEDEF_(0x00090314L) +#define SEC_E_BAD_PKGID _HRESULT_TYPEDEF_(0x80090316L) +#define SEC_E_CONTEXT_EXPIRED _HRESULT_TYPEDEF_(0x80090317L) +#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) +#define SEC_E_INCOMPLETE_CREDENTIALS _HRESULT_TYPEDEF_(0x80090320L) +#define SEC_E_BUFFER_TOO_SMALL _HRESULT_TYPEDEF_(0x80090321L) +#define SEC_E_WRONG_PRINCIPAL _HRESULT_TYPEDEF_(0x80090322L) +#define SEC_E_TIME_SKEW _HRESULT_TYPEDEF_(0x80090324L) +#define SEC_E_UNTRUSTED_ROOT _HRESULT_TYPEDEF_(0x80090325L) +#define SEC_E_ILLEGAL_MESSAGE _HRESULT_TYPEDEF_(0x80090326L) +#define SEC_E_CERT_UNKNOWN _HRESULT_TYPEDEF_(0x80090327L) +#define SEC_E_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090328L) +#define SEC_E_ENCRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090329L) +#define SEC_E_DECRYPT_FAILURE _HRESULT_TYPEDEF_(0x80090330L) +#define SEC_E_ALGORITHM_MISMATCH _HRESULT_TYPEDEF_(0x80090331L) +#define SEC_E_SECURITY_QOS_FAILED _HRESULT_TYPEDEF_(0x80090332L) +#define SEC_E_UNFINISHED_CONTEXT_DELETED _HRESULT_TYPEDEF_(0x80090333L) +#define SEC_E_NO_TGT_REPLY _HRESULT_TYPEDEF_(0x80090334L) +#define SEC_E_NO_IP_ADDRESSES _HRESULT_TYPEDEF_(0x80090335L) +#define SEC_E_WRONG_CREDENTIAL_HANDLE _HRESULT_TYPEDEF_(0x80090336L) +#define SEC_E_CRYPTO_SYSTEM_INVALID _HRESULT_TYPEDEF_(0x80090337L) +#define SEC_E_MAX_REFERRALS_EXCEEDED _HRESULT_TYPEDEF_(0x80090338L) +#define SEC_E_MUST_BE_KDC _HRESULT_TYPEDEF_(0x80090339L) +#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009033AL) +#define SEC_E_TOO_MANY_PRINCIPALS _HRESULT_TYPEDEF_(0x8009033BL) +#define SEC_E_NO_PA_DATA _HRESULT_TYPEDEF_(0x8009033CL) +#define SEC_E_PKINIT_NAME_MISMATCH _HRESULT_TYPEDEF_(0x8009033DL) +#define SEC_E_SMARTCARD_LOGON_REQUIRED _HRESULT_TYPEDEF_(0x8009033EL) +#define SEC_E_SHUTDOWN_IN_PROGRESS _HRESULT_TYPEDEF_(0x8009033FL) +#define SEC_E_KDC_INVALID_REQUEST _HRESULT_TYPEDEF_(0x80090340L) +#define SEC_E_KDC_UNABLE_TO_REFER _HRESULT_TYPEDEF_(0x80090341L) +#define SEC_E_KDC_UNKNOWN_ETYPE _HRESULT_TYPEDEF_(0x80090342L) +#define SEC_E_UNSUPPORTED_PREAUTH _HRESULT_TYPEDEF_(0x80090343L) +#define SEC_E_DELEGATION_REQUIRED _HRESULT_TYPEDEF_(0x80090345L) +#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) +#define SEC_E_MULTIPLE_ACCOUNTS _HRESULT_TYPEDEF_(0x80090347L) +#define SEC_E_NO_KERB_KEY _HRESULT_TYPEDEF_(0x80090348L) +#define SEC_E_CERT_WRONG_USAGE _HRESULT_TYPEDEF_(0x80090349L) +#define SEC_E_DOWNGRADE_DETECTED _HRESULT_TYPEDEF_(0x80090350L) +#define SEC_E_SMARTCARD_CERT_REVOKED _HRESULT_TYPEDEF_(0x80090351L) +#define SEC_E_ISSUING_CA_UNTRUSTED _HRESULT_TYPEDEF_(0x80090352L) +#define SEC_E_REVOCATION_OFFLINE_C _HRESULT_TYPEDEF_(0x80090353L) +#define SEC_E_PKINIT_CLIENT_FAILURE _HRESULT_TYPEDEF_(0x80090354L) +#define SEC_E_SMARTCARD_CERT_EXPIRED _HRESULT_TYPEDEF_(0x80090355L) +#define SEC_E_NO_S4U_PROT_SUPPORT _HRESULT_TYPEDEF_(0x80090356L) +#define SEC_E_CROSSREALM_DELEGATION_FAILURE _HRESULT_TYPEDEF_(0x80090357L) +#define SEC_E_REVOCATION_OFFLINE_KDC _HRESULT_TYPEDEF_(0x80090358L) +#define SEC_E_ISSUING_CA_UNTRUSTED_KDC _HRESULT_TYPEDEF_(0x80090359L) +#define SEC_E_KDC_CERT_EXPIRED _HRESULT_TYPEDEF_(0x8009035AL) +#define SEC_E_KDC_CERT_REVOKED _HRESULT_TYPEDEF_(0x8009035BL) + +#define CRYPT_E_MSG_ERROR _HRESULT_TYPEDEF_(0x80091001L) +#define CRYPT_E_UNKNOWN_ALGO _HRESULT_TYPEDEF_(0x80091002L) +#define CRYPT_E_OID_FORMAT _HRESULT_TYPEDEF_(0x80091003L) +#define CRYPT_E_INVALID_MSG_TYPE _HRESULT_TYPEDEF_(0x80091004L) +#define CRYPT_E_UNEXPECTED_ENCODING _HRESULT_TYPEDEF_(0x80091005L) +#define CRYPT_E_AUTH_ATTR_MISSING _HRESULT_TYPEDEF_(0x80091006L) +#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L) +#define CRYPT_E_INVALID_INDEX _HRESULT_TYPEDEF_(0x80091008L) +#define CRYPT_E_ALREADY_DECRYPTED _HRESULT_TYPEDEF_(0x80091009L) +#define CRYPT_E_NOT_DECRYPTED _HRESULT_TYPEDEF_(0x8009100AL) +#define CRYPT_E_RECIPIENT_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100BL) +#define CRYPT_E_CONTROL_TYPE _HRESULT_TYPEDEF_(0x8009100CL) +#define CRYPT_E_ISSUER_SERIALNUMBER _HRESULT_TYPEDEF_(0x8009100DL) +#define CRYPT_E_SIGNER_NOT_FOUND _HRESULT_TYPEDEF_(0x8009100EL) +#define CRYPT_E_ATTRIBUTES_MISSING _HRESULT_TYPEDEF_(0x8009100FL) +#define CRYPT_E_STREAM_MSG_NOT_READY _HRESULT_TYPEDEF_(0x80091010L) +#define CRYPT_E_STREAM_INSUFFICIENT_DATA _HRESULT_TYPEDEF_(0x80091011L) +#define CRYPT_I_NEW_PROTECTION_REQUIRED _HRESULT_TYPEDEF_(0x80091012L) + +#define CRYPT_E_BAD_LEN _HRESULT_TYPEDEF_(0x80092001L) +#define CRYPT_E_BAD_ENCODE _HRESULT_TYPEDEF_(0x80092002L) +#define CRYPT_E_FILE_ERROR _HRESULT_TYPEDEF_(0x80092003L) +#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) +#define CRYPT_E_EXISTS _HRESULT_TYPEDEF_(0x80092005L) +#define CRYPT_E_NO_PROVIDER _HRESULT_TYPEDEF_(0x80092006L) +#define CRYPT_E_SELF_SIGNED _HRESULT_TYPEDEF_(0x80092007L) +#define CRYPT_E_DELETED_PREV _HRESULT_TYPEDEF_(0x80092008L) +#define CRYPT_E_NO_MATCH _HRESULT_TYPEDEF_(0x80092009L) +#define CRYPT_E_UNEXPECTED_MSG_TYPE _HRESULT_TYPEDEF_(0x8009200AL) +#define CRYPT_E_NO_KEY_PROPERTY _HRESULT_TYPEDEF_(0x8009200BL) +#define CRYPT_E_NO_DECRYPT_CERT _HRESULT_TYPEDEF_(0x8009200CL) +#define CRYPT_E_BAD_MSG _HRESULT_TYPEDEF_(0x8009200DL) +#define CRYPT_E_NO_SIGNER _HRESULT_TYPEDEF_(0x8009200EL) +#define CRYPT_E_PENDING_CLOSE _HRESULT_TYPEDEF_(0x8009200FL) +#define CRYPT_E_REVOKED _HRESULT_TYPEDEF_(0x80092010L) +#define CRYPT_E_NO_REVOCATION_DLL _HRESULT_TYPEDEF_(0x80092011L) +#define CRYPT_E_NO_REVOCATION_CHECK _HRESULT_TYPEDEF_(0x80092012L) +#define CRYPT_E_REVOCATION_OFFLINE _HRESULT_TYPEDEF_(0x80092013L) +#define CRYPT_E_NOT_IN_REVOCATION_DATABASE _HRESULT_TYPEDEF_(0x80092014L) +#define CRYPT_E_INVALID_NUMERIC_STRING _HRESULT_TYPEDEF_(0x80092020L) +#define CRYPT_E_INVALID_PRINTABLE_STRING _HRESULT_TYPEDEF_(0x80092021L) +#define CRYPT_E_INVALID_IA5_STRING _HRESULT_TYPEDEF_(0x80092022L) +#define CRYPT_E_INVALID_X500_STRING _HRESULT_TYPEDEF_(0x80092023L) +#define CRYPT_E_NOT_CHAR_STRING _HRESULT_TYPEDEF_(0x80092024L) +#define CRYPT_E_FILERESIZED _HRESULT_TYPEDEF_(0x80092025L) +#define CRYPT_E_SECURITY_SETTINGS _HRESULT_TYPEDEF_(0x80092026L) +#define CRYPT_E_NO_VERIFY_USAGE_DLL _HRESULT_TYPEDEF_(0x80092027L) +#define CRYPT_E_NO_VERIFY_USAGE_CHECK _HRESULT_TYPEDEF_(0x80092028L) +#define CRYPT_E_VERIFY_USAGE_OFFLINE _HRESULT_TYPEDEF_(0x80092029L) +#define CRYPT_E_NOT_IN_CTL _HRESULT_TYPEDEF_(0x8009202AL) +#define CRYPT_E_NO_TRUSTED_SIGNER _HRESULT_TYPEDEF_(0x8009202BL) +#define CRYPT_E_MISSING_PUBKEY_PARA _HRESULT_TYPEDEF_(0x8009202CL) +#define CRYPT_E_OSS_ERROR _HRESULT_TYPEDEF_(0x80093000L) +#define OSS_MORE_BUF _HRESULT_TYPEDEF_(0x80093001L) +#define OSS_NEGATIVE_UINTEGER _HRESULT_TYPEDEF_(0x80093002L) +#define OSS_PDU_RANGE _HRESULT_TYPEDEF_(0x80093003L) +#define OSS_MORE_INPUT _HRESULT_TYPEDEF_(0x80093004L) +#define OSS_DATA_ERROR _HRESULT_TYPEDEF_(0x80093005L) +#define OSS_BAD_ARG _HRESULT_TYPEDEF_(0x80093006L) +#define OSS_BAD_VERSION _HRESULT_TYPEDEF_(0x80093007L) +#define OSS_OUT_MEMORY _HRESULT_TYPEDEF_(0x80093008L) +#define OSS_PDU_MISMATCH _HRESULT_TYPEDEF_(0x80093009L) +#define OSS_LIMITED _HRESULT_TYPEDEF_(0x8009300AL) +#define OSS_BAD_PTR _HRESULT_TYPEDEF_(0x8009300BL) +#define OSS_BAD_TIME _HRESULT_TYPEDEF_(0x8009300CL) +#define OSS_INDEFINITE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009300DL) +#define OSS_MEM_ERROR _HRESULT_TYPEDEF_(0x8009300EL) +#define OSS_BAD_TABLE _HRESULT_TYPEDEF_(0x8009300FL) +#define OSS_TOO_LONG _HRESULT_TYPEDEF_(0x80093010L) +#define OSS_CONSTRAINT_VIOLATED _HRESULT_TYPEDEF_(0x80093011L) +#define OSS_FATAL_ERROR _HRESULT_TYPEDEF_(0x80093012L) +#define OSS_ACCESS_SERIALIZATION_ERROR _HRESULT_TYPEDEF_(0x80093013L) +#define OSS_NULL_TBL _HRESULT_TYPEDEF_(0x80093014L) +#define OSS_NULL_FCN _HRESULT_TYPEDEF_(0x80093015L) +#define OSS_BAD_ENCRULES _HRESULT_TYPEDEF_(0x80093016L) +#define OSS_UNAVAIL_ENCRULES _HRESULT_TYPEDEF_(0x80093017L) +#define OSS_CANT_OPEN_TRACE_WINDOW _HRESULT_TYPEDEF_(0x80093018L) +#define OSS_UNIMPLEMENTED _HRESULT_TYPEDEF_(0x80093019L) +#define OSS_OID_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301AL) +#define OSS_CANT_OPEN_TRACE_FILE _HRESULT_TYPEDEF_(0x8009301BL) +#define OSS_TRACE_FILE_ALREADY_OPEN _HRESULT_TYPEDEF_(0x8009301CL) +#define OSS_TABLE_MISMATCH _HRESULT_TYPEDEF_(0x8009301DL) +#define OSS_TYPE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x8009301EL) +#define OSS_REAL_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009301FL) +#define OSS_REAL_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093020L) +#define OSS_OUT_OF_RANGE _HRESULT_TYPEDEF_(0x80093021L) +#define OSS_COPIER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093022L) +#define OSS_CONSTRAINT_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093023L) +#define OSS_COMPARATOR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093024L) +#define OSS_COMPARATOR_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093025L) +#define OSS_MEM_MGR_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093026L) +#define OSS_PDV_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093027L) +#define OSS_PDV_CODE_NOT_LINKED _HRESULT_TYPEDEF_(0x80093028L) +#define OSS_API_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x80093029L) +#define OSS_BERDER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302AL) +#define OSS_PER_DLL_NOT_LINKED _HRESULT_TYPEDEF_(0x8009302BL) +#define OSS_OPEN_TYPE_ERROR _HRESULT_TYPEDEF_(0x8009302CL) +#define OSS_MUTEX_NOT_CREATED _HRESULT_TYPEDEF_(0x8009302DL) +#define OSS_CANT_CLOSE_TRACE_FILE _HRESULT_TYPEDEF_(0x8009302EL) +#define CRYPT_E_ASN1_ERROR _HRESULT_TYPEDEF_(0x80093100L) +#define CRYPT_E_ASN1_INTERNAL _HRESULT_TYPEDEF_(0x80093101L) +#define CRYPT_E_ASN1_EOD _HRESULT_TYPEDEF_(0x80093102L) +#define CRYPT_E_ASN1_CORRUPT _HRESULT_TYPEDEF_(0x80093103L) +#define CRYPT_E_ASN1_LARGE _HRESULT_TYPEDEF_(0x80093104L) +#define CRYPT_E_ASN1_CONSTRAINT _HRESULT_TYPEDEF_(0x80093105L) +#define CRYPT_E_ASN1_MEMORY _HRESULT_TYPEDEF_(0x80093106L) +#define CRYPT_E_ASN1_OVERFLOW _HRESULT_TYPEDEF_(0x80093107L) +#define CRYPT_E_ASN1_BADPDU _HRESULT_TYPEDEF_(0x80093108L) +#define CRYPT_E_ASN1_BADARGS _HRESULT_TYPEDEF_(0x80093109L) +#define CRYPT_E_ASN1_BADREAL _HRESULT_TYPEDEF_(0x8009310AL) +#define CRYPT_E_ASN1_BADTAG _HRESULT_TYPEDEF_(0x8009310BL) +#define CRYPT_E_ASN1_CHOICE _HRESULT_TYPEDEF_(0x8009310CL) +#define CRYPT_E_ASN1_RULE _HRESULT_TYPEDEF_(0x8009310DL) +#define CRYPT_E_ASN1_UTF8 _HRESULT_TYPEDEF_(0x8009310EL) +#define CRYPT_E_ASN1_PDU_TYPE _HRESULT_TYPEDEF_(0x80093133L) +#define CRYPT_E_ASN1_NYI _HRESULT_TYPEDEF_(0x80093134L) +#define CRYPT_E_ASN1_EXTENDED _HRESULT_TYPEDEF_(0x80093201L) +#define CRYPT_E_ASN1_NOEOD _HRESULT_TYPEDEF_(0x80093202L) + +#define TRUST_E_SYSTEM_ERROR _HRESULT_TYPEDEF_(0x80096001L) +#define TRUST_E_NO_SIGNER_CERT _HRESULT_TYPEDEF_(0x80096002L) +#define TRUST_E_COUNTER_SIGNER _HRESULT_TYPEDEF_(0x80096003L) +#define TRUST_E_CERT_SIGNATURE _HRESULT_TYPEDEF_(0x80096004L) +#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) +#define TRUST_E_BAD_DIGEST _HRESULT_TYPEDEF_(0x80096010L) +#define TRUST_E_BASIC_CONSTRAINTS _HRESULT_TYPEDEF_(0x80096019L) +#define TRUST_E_FINANCIAL_CRITERIA _HRESULT_TYPEDEF_(0x8009601EL) +#define TRUST_E_PROVIDER_UNKNOWN _HRESULT_TYPEDEF_(0x800B0001L) +#define TRUST_E_ACTION_UNKNOWN _HRESULT_TYPEDEF_(0x800B0002L) +#define TRUST_E_SUBJECT_FORM_UNKNOWN _HRESULT_TYPEDEF_(0x800B0003L) +#define TRUST_E_SUBJECT_NOT_TRUSTED _HRESULT_TYPEDEF_(0x800B0004L) +#define TRUST_E_NOSIGNATURE _HRESULT_TYPEDEF_(0x800B0100L) + +#define SPAPI_E_EXPECTED_SECTION_NAME _HRESULT_TYPEDEF_(0x800F0000L) +#define SPAPI_E_BAD_SECTION_NAME_LINE _HRESULT_TYPEDEF_(0x800F0001L) +#define SPAPI_E_SECTION_NAME_TOO_LONG _HRESULT_TYPEDEF_(0x800F0002L) +#define SPAPI_E_GENERAL_SYNTAX _HRESULT_TYPEDEF_(0x800F0003L) +#define SPAPI_E_WRONG_INF_STYLE _HRESULT_TYPEDEF_(0x800F0100L) +#define SPAPI_E_SECTION_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0101L) +#define SPAPI_E_LINE_NOT_FOUND _HRESULT_TYPEDEF_(0x800F0102L) +#define SPAPI_E_NO_BACKUP _HRESULT_TYPEDEF_(0x800F0103L) +#define SPAPI_E_NO_ASSOCIATED_CLASS _HRESULT_TYPEDEF_(0x800F0200L) +#define SPAPI_E_CLASS_MISMATCH _HRESULT_TYPEDEF_(0x800F0201L) +#define SPAPI_E_DUPLICATE_FOUND _HRESULT_TYPEDEF_(0x800F0202L) +#define SPAPI_E_NO_DRIVER_SELECTED _HRESULT_TYPEDEF_(0x800F0203L) +#define SPAPI_E_KEY_DOES_NOT_EXIST _HRESULT_TYPEDEF_(0x800F0204L) +#define SPAPI_E_INVALID_DEVINST_NAME _HRESULT_TYPEDEF_(0x800F0205L) +#define SPAPI_E_INVALID_CLASS _HRESULT_TYPEDEF_(0x800F0206L) +#define SPAPI_E_DEVINST_ALREADY_EXISTS _HRESULT_TYPEDEF_(0x800F0207L) +#define SPAPI_E_DEVINFO_NOT_REGISTERED _HRESULT_TYPEDEF_(0x800F0208L) +#define SPAPI_E_INVALID_REG_PROPERTY _HRESULT_TYPEDEF_(0x800F0209L) +#define SPAPI_E_NO_INF _HRESULT_TYPEDEF_(0x800F020AL) +#define SPAPI_E_NO_SUCH_DEVINST _HRESULT_TYPEDEF_(0x800F020BL) +#define SPAPI_E_CANT_LOAD_CLASS_ICON _HRESULT_TYPEDEF_(0x800F020CL) +#define SPAPI_E_INVALID_CLASS_INSTALLER _HRESULT_TYPEDEF_(0x800F020DL) +#define SPAPI_E_DI_DO_DEFAULT _HRESULT_TYPEDEF_(0x800F020EL) +#define SPAPI_E_DI_NOFILECOPY _HRESULT_TYPEDEF_(0x800F020FL) +#define SPAPI_E_INVALID_HWPROFILE _HRESULT_TYPEDEF_(0x800F0210L) +#define SPAPI_E_NO_DEVICE_SELECTED _HRESULT_TYPEDEF_(0x800F0211L) +#define SPAPI_E_DEVINFO_LIST_LOCKED _HRESULT_TYPEDEF_(0x800F0212L) +#define SPAPI_E_DEVINFO_DATA_LOCKED _HRESULT_TYPEDEF_(0x800F0213L) +#define SPAPI_E_DI_BAD_PATH _HRESULT_TYPEDEF_(0x800F0214L) +#define SPAPI_E_NO_CLASSINSTALL_PARAMS _HRESULT_TYPEDEF_(0x800F0215L) +#define SPAPI_E_FILEQUEUE_LOCKED _HRESULT_TYPEDEF_(0x800F0216L) +#define SPAPI_E_BAD_SERVICE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F0217L) +#define SPAPI_E_NO_CLASS_DRIVER_LIST _HRESULT_TYPEDEF_(0x800F0218L) +#define SPAPI_E_NO_ASSOCIATED_SERVICE _HRESULT_TYPEDEF_(0x800F0219L) +#define SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F021AL) +#define SPAPI_E_DEVICE_INTERFACE_ACTIVE _HRESULT_TYPEDEF_(0x800F021BL) +#define SPAPI_E_DEVICE_INTERFACE_REMOVED _HRESULT_TYPEDEF_(0x800F021CL) +#define SPAPI_E_BAD_INTERFACE_INSTALLSECT _HRESULT_TYPEDEF_(0x800F021DL) +#define SPAPI_E_NO_SUCH_INTERFACE_CLASS _HRESULT_TYPEDEF_(0x800F021EL) +#define SPAPI_E_INVALID_REFERENCE_STRING _HRESULT_TYPEDEF_(0x800F021FL) +#define SPAPI_E_INVALID_MACHINENAME _HRESULT_TYPEDEF_(0x800F0220L) +#define SPAPI_E_REMOTE_COMM_FAILURE _HRESULT_TYPEDEF_(0x800F0221L) +#define SPAPI_E_MACHINE_UNAVAILABLE _HRESULT_TYPEDEF_(0x800F0222L) +#define SPAPI_E_NO_CONFIGMGR_SERVICES _HRESULT_TYPEDEF_(0x800F0223L) +#define SPAPI_E_INVALID_PROPPAGE_PROVIDER _HRESULT_TYPEDEF_(0x800F0224L) +#define SPAPI_E_NO_SUCH_DEVICE_INTERFACE _HRESULT_TYPEDEF_(0x800F0225L) +#define SPAPI_E_DI_POSTPROCESSING_REQUIRED _HRESULT_TYPEDEF_(0x800F0226L) +#define SPAPI_E_INVALID_COINSTALLER _HRESULT_TYPEDEF_(0x800F0227L) +#define SPAPI_E_NO_COMPAT_DRIVERS _HRESULT_TYPEDEF_(0x800F0228L) +#define SPAPI_E_NO_DEVICE_ICON _HRESULT_TYPEDEF_(0x800F0229L) +#define SPAPI_E_INVALID_INF_LOGCONFIG _HRESULT_TYPEDEF_(0x800F022AL) +#define SPAPI_E_DI_DONT_INSTALL _HRESULT_TYPEDEF_(0x800F022BL) +#define SPAPI_E_INVALID_FILTER_DRIVER _HRESULT_TYPEDEF_(0x800F022CL) +#define SPAPI_E_NON_WINDOWS_NT_DRIVER _HRESULT_TYPEDEF_(0x800F022DL) +#define SPAPI_E_NON_WINDOWS_DRIVER _HRESULT_TYPEDEF_(0x800F022EL) +#define SPAPI_E_NO_CATALOG_FOR_OEM_INF _HRESULT_TYPEDEF_(0x800F022FL) +#define SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE _HRESULT_TYPEDEF_(0x800F0230L) +#define SPAPI_E_NOT_DISABLEABLE _HRESULT_TYPEDEF_(0x800F0231L) +#define SPAPI_E_CANT_REMOVE_DEVINST _HRESULT_TYPEDEF_(0x800F0232L) +#define SPAPI_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x800F0233L) +#define SPAPI_E_DRIVER_NONNATIVE _HRESULT_TYPEDEF_(0x800F0234L) +#define SPAPI_E_IN_WOW64 _HRESULT_TYPEDEF_(0x800F0235L) +#define SPAPI_E_SET_SYSTEM_RESTORE_POINT _HRESULT_TYPEDEF_(0x800F0236L) +#define SPAPI_E_INCORRECTLY_COPIED_INF _HRESULT_TYPEDEF_(0x800F0237L) +#define SPAPI_E_SCE_DISABLED _HRESULT_TYPEDEF_(0x800F0238L) +#define SPAPI_E_ERROR_NOT_INSTALLED _HRESULT_TYPEDEF_(0x800F1000L) + +/* Smart card management error codes */ +#define SCARD_S_SUCCESS NO_ERROR +#define SCARD_F_INTERNAL_ERROR _HRESULT_TYPEDEF_(0x80100001L) +#define SCARD_E_CANCELLED _HRESULT_TYPEDEF_(0x80100002L) +#define SCARD_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80100003L) +#define SCARD_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80100004L) +#define SCARD_E_INVALID_TARGET _HRESULT_TYPEDEF_(0x80100005L) +#define SCARD_E_NO_MEMORY _HRESULT_TYPEDEF_(0x80100006L) +#define SCARD_F_WAITED_TOO_LONG _HRESULT_TYPEDEF_(0x80100007L) +#define SCARD_E_INSUFFICIENT_BUFFER _HRESULT_TYPEDEF_(0x80100008L) +#define SCARD_E_UNKNOWN_READER _HRESULT_TYPEDEF_(0x80100009L) +#define SCARD_E_TIMEOUT _HRESULT_TYPEDEF_(0x8010000AL) +#define SCARD_E_SHARING_VIOLATION _HRESULT_TYPEDEF_(0x8010000BL) +#define SCARD_E_NO_SMARTCARD _HRESULT_TYPEDEF_(0x8010000CL) +#define SCARD_E_UNKNOWN_CARD _HRESULT_TYPEDEF_(0x8010000DL) +#define SCARD_E_CANT_DISPOSE _HRESULT_TYPEDEF_(0x8010000EL) +#define SCARD_E_PROTO_MISMATCH _HRESULT_TYPEDEF_(0x8010000FL) +#define SCARD_E_NOT_READY _HRESULT_TYPEDEF_(0x80100010L) +#define SCARD_E_INVALID_VALUE _HRESULT_TYPEDEF_(0x80100011L) +#define SCARD_E_SYSTEM_CANCELLED _HRESULT_TYPEDEF_(0x80100012L) +#define SCARD_F_COMM_ERROR _HRESULT_TYPEDEF_(0x80100013L) +#define SCARD_F_UNKNOWN_ERROR _HRESULT_TYPEDEF_(0x80100014L) +#define SCARD_E_INVALID_ATR _HRESULT_TYPEDEF_(0x80100015L) +#define SCARD_E_NOT_TRANSACTED _HRESULT_TYPEDEF_(0x80100016L) +#define SCARD_E_READER_UNAVAILABLE _HRESULT_TYPEDEF_(0x80100017L) +#define SCARD_P_SHUTDOWN _HRESULT_TYPEDEF_(0x80100018L) +#define SCARD_E_PCI_TOO_SMALL _HRESULT_TYPEDEF_(0x80100019L) +#define SCARD_E_READER_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001AL) +#define SCARD_E_DUPLICATE_READER _HRESULT_TYPEDEF_(0x8010001BL) +#define SCARD_E_CARD_UNSUPPORTED _HRESULT_TYPEDEF_(0x8010001CL) +#define SCARD_E_NO_SERVICE _HRESULT_TYPEDEF_(0x8010001DL) +#define SCARD_E_SERVICE_STOPPED _HRESULT_TYPEDEF_(0x8010001EL) +#define SCARD_E_UNEXPECTED _HRESULT_TYPEDEF_(0x8010001FL) +#define SCARD_E_ICC_INSTALLATION _HRESULT_TYPEDEF_(0x80100020L) +#define SCARD_E_ICC_CREATEORDER _HRESULT_TYPEDEF_(0x80100021L) +#define SCARD_E_UNSUPPORTED_FEATURE _HRESULT_TYPEDEF_(0x80100022L) +#define SCARD_E_DIR_NOT_FOUND _HRESULT_TYPEDEF_(0x80100023L) +#define SCARD_E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80100024L) +#define SCARD_E_NO_DIR _HRESULT_TYPEDEF_(0x80100025L) +#define SCARD_E_NO_FILE _HRESULT_TYPEDEF_(0x80100026L) +#define SCARD_E_NO_ACCESS _HRESULT_TYPEDEF_(0x80100027L) +#define SCARD_E_WRITE_TOO_MANY _HRESULT_TYPEDEF_(0x80100028L) +#define SCARD_E_BAD_SEEK _HRESULT_TYPEDEF_(0x80100029L) +#define SCARD_E_INVALID_CHV _HRESULT_TYPEDEF_(0x8010002AL) +#define SCARD_E_UNKNOWN_RES_MNG _HRESULT_TYPEDEF_(0x8010002BL) +#define SCARD_E_NO_SUCH_CERTIFICATE _HRESULT_TYPEDEF_(0x8010002CL) +#define SCARD_E_CERTIFICATE_UNAVAILABLE _HRESULT_TYPEDEF_(0x8010002DL) +#define SCARD_E_NO_READERS_AVAILABLE _HRESULT_TYPEDEF_(0x8010002EL) +#define SCARD_E_COMM_DATA_LOST _HRESULT_TYPEDEF_(0x8010002FL) +#define SCARD_E_NO_KEY_CONTAINER _HRESULT_TYPEDEF_(0x80100030L) +#define SCARD_E_SERVER_TOO_BUSY _HRESULT_TYPEDEF_(0x80100031L) +#define SCARD_W_UNSUPPORTED_CARD _HRESULT_TYPEDEF_(0x80100065L) +#define SCARD_W_UNRESPONSIVE_CARD _HRESULT_TYPEDEF_(0x80100066L) +#define SCARD_W_UNPOWERED_CARD _HRESULT_TYPEDEF_(0x80100067L) +#define SCARD_W_RESET_CARD _HRESULT_TYPEDEF_(0x80100068L) +#define SCARD_W_REMOVED_CARD _HRESULT_TYPEDEF_(0x80100069L) +#define SCARD_W_SECURITY_VIOLATION _HRESULT_TYPEDEF_(0x8010006AL) +#define SCARD_W_WRONG_CHV _HRESULT_TYPEDEF_(0x8010006BL) +#define SCARD_W_CHV_BLOCKED _HRESULT_TYPEDEF_(0x8010006CL) +#define SCARD_W_EOF _HRESULT_TYPEDEF_(0x8010006DL) +#define SCARD_W_CANCELLED_BY_USER _HRESULT_TYPEDEF_(0x8010006EL) +#define SCARD_W_CARD_NOT_AUTHENTICATED _HRESULT_TYPEDEF_(0x8010006FL) +#define SCARD_W_CACHE_ITEM_NOT_FOUND _HRESULT_TYPEDEF_(0x80100070L) +#define SCARD_W_CACHE_ITEM_STALE _HRESULT_TYPEDEF_(0x80100071L) +#define SCARD_W_CACHE_ITEM_TOO_BIG _HRESULT_TYPEDEF_(0x80100072L) + +#define ERROR_AUDITING_DISABLED _HRESULT_TYPEDEF_(0xC0090001L) +#define ERROR_ALL_SIDS_FILTERED _HRESULT_TYPEDEF_(0xC0090002L) + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WINESERVER_WINERROR_H */ diff --git a/unifiedkernel/include/winuser.h b/unifiedkernel/include/winuser.h new file mode 100644 index 0000000..aa72e67 --- /dev/null +++ b/unifiedkernel/include/winuser.h @@ -0,0 +1,1448 @@ +/* + * winuser.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2008 - Created. + */ + +#ifndef _WINUSER_H +#define _WINUSER_H + +#if !defined(_USER32_) +#define WINUSERAPI DECLSPEC_IMPORT +#else +#define WINUSERAPI +#endif + +#ifndef RC_INVOKED +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "wtypes.h" + +#ifdef CONFIG_UNIFIED_KERNEL +typedef HANDLE HDWP; + +#define UOI_FLAGS 1 +#define UOI_NAME 2 +#define UOI_TYPE 3 +#define UOI_USER_SID 4 + +#define WSF_VISIBLE 1 +#define DF_ALLOWOTHERACCOUNTHOOK 1 + +typedef struct tagUSEROBJECTFLAGS { + BOOL fInherit; + BOOL fReserved; + DWORD dwFlags; +} USEROBJECTFLAGS, *PUSEROBJECTFLAGS; + +#define HDESK unsigned int +#define HWND unsigned int + +typedef struct tagBSMINFO { + UINT cbSize; + HDESK hdesk; + HWND hwnd; + LUID luid; +} BSMINFO, *PBSMINFO; + +/* Window stations */ +#define WINSTA_ENUMDESKTOPS 0x0001 +#define WINSTA_READATTRIBUTES 0x0002 +#define WINSTA_ACCESSCLIPBOARD 0x0004 +#define WINSTA_CREATEDESKTOP 0x0008 +#define WINSTA_WRITEATTRIBUTES 0x0010 +#define WINSTA_ACCESSGLOBALATOMS 0x0020 +#define WINSTA_EXITWINDOWS 0x0040 +#define WINSTA_ENUMERATE 0x0100 +#define WINSTA_READSCREEN 0x0200 +#define WINSTA_ALL_ACCESS 0x037f + +/* Desktops */ +#define DESKTOP_READOBJECTS 0x0001 +#define DESKTOP_CREATEWINDOW 0x0002 +#define DESKTOP_CREATEMENU 0x0004 +#define DESKTOP_HOOKCONTROL 0x0008 +#define DESKTOP_JOURNALRECORD 0x0010 +#define DESKTOP_JOURNALPLAYBACK 0x0020 +#define DESKTOP_ENUMERATE 0x0040 +#define DESKTOP_WRITEOBJECTS 0x0080 +#define DESKTOP_SWITCHDESKTOP 0x0100 + + +/* flags for FILTERKEYS dwFlags field */ +#define FKF_AVAILABLE 0x00000002 +#define FKF_CLICKON 0x00000040 +#define FKF_FILTERKEYSON 0x00000001 +#define FKF_HOTKEYACTIVE 0x00000004 +#define FKF_HOTKEYSOUND 0x00000010 +#define FKF_CONFIRMHOTKEY 0x00000008 +#define FKF_INDICATOR 0x00000020 + +typedef struct tagFILTERKEYS +{ + UINT cbSize; + DWORD dwFlags; + DWORD iWaitMSec; + DWORD iDelayMSec; + DWORD iRepeatMSec; + DWORD iBounceMSec; +} FILTERKEYS, *LPFILTERKEYS; + +/* flags for TOGGLEKEYS dwFlags field */ +#define TKF_AVAILABLE 0x00000002 +#define TKF_CONFIRMHOTKEY 0x00000008 +#define TKF_HOTKEYACTIVE 0x00000004 +#define TKF_HOTKEYSOUND 0x00000010 +#define TKF_TOGGLEKEYSON 0x00000001 + +typedef struct tagTOGGLEKEYS +{ + DWORD cbSize; + DWORD dwFlags; +} TOGGLEKEYS, *LPTOGGLEKEYS; + +/* flags for MOUSEKEYS dwFlags field */ +#define MKF_AVAILABLE 0x00000002 +#define MKF_CONFIRMHOTKEY 0x00000008 +#define MKF_HOTKEYACTIVE 0x00000004 +#define MKF_HOTKEYSOUND 0x00000010 +#define MKF_INDICATOR 0x00000020 +#define MKF_MOUSEKEYSON 0x00000001 +#define MKF_MODIFIERS 0x00000040 +#define MKF_REPLACENUMBERS 0x00000080 + +typedef struct tagMOUSEKEYS +{ + UINT cbSize; + DWORD dwFlags; + DWORD iMaxSpeed; + DWORD iTimeToMaxSpeed; + DWORD iCtrlSpeed; + DWORD dwReserved1; + DWORD dwReserved2; +} MOUSEKEYS, *LPMOUSEKEYS; + +/* struct and defines for GetMouseMovePointsEx */ +#define GMMP_USE_DISPLAY_POINTS 1 +#define GMMP_USE_HIGH_RESOLUTION_POINTS 2 + +typedef struct tagMOUSEMOVEPOINT { + int x; + int y; + DWORD time; + ULONG_PTR dwExtraInfo; +} MOUSEMOVEPOINT,*PMOUSEMOVEPOINT,*LPMOUSEMOVEPOINT; + +/* flags for STICKYKEYS dwFlags field */ +#define SKF_AUDIBLEFEEDBACK 0x00000040 +#define SKF_AVAILABLE 0x00000002 +#define SKF_CONFIRMHOTKEY 0x00000008 +#define SKF_HOTKEYACTIVE 0x00000004 +#define SKF_HOTKEYSOUND 0x00000010 +#define SKF_INDICATOR 0x00000020 +#define SKF_STICKYKEYSON 0x00000001 +#define SKF_TRISTATE 0x00000080 +#define SKF_TWOKEYSOFF 0x00000100 + +typedef struct tagSTICKYKEYS +{ + DWORD cbSize; + DWORD dwFlags; +} STICKYKEYS, *LPSTICKYKEYS; + +/* flags for ACCESSTIMEOUT dwFlags field */ +#define ATF_ONOFFFEEDBACK 0x00000002 +#define ATF_AVAILABLE 0x00000004 +#define ATF_TIMEOUTON 0x00000001 + +typedef struct tagACCESSTIMEOUT +{ + UINT cbSize; + DWORD dwFlags; + DWORD iTimeOutMSec; +} ACCESSTIMEOUT, *LPACCESSTIMEOUT; + +/* flags for SERIALKEYS dwFlags field */ +#define SERKF_ACTIVE 0x00000008 +#define SERKF_AVAILABLE 0x00000002 +#define SERKF_INDICATOR 0x00000004 +#define SERKF_SERIALKEYSON 0x00000001 + +typedef struct tagSERIALKEYSA +{ + UINT cbSize; + DWORD dwFlags; + LPSTR lpszActivePort; + LPSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; +} SERIALKEYSA, *LPSERIALKEYSA; + +typedef struct tagSERIALKEYSW { + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszActivePort; + LPWSTR lpszPort; + UINT iBaudRate; + UINT iPortState; + UINT iActive; +} SERIALKEYSW,*LPSERIALKEYSW; + +#if 0 +DECL_WINELIB_TYPE_AW(SERIALKEYS) +DECL_WINELIB_TYPE_AW(LPSERIALKEYS) +#endif + +/* flags for SOUNDSENTRY dwFlags field */ +#define SSF_AVAILABLE 0x00000002 +#define SSF_SOUNDSENTRYON 0x00000001 + +#define SSTF_BORDER 0x00000002 +#define SSTF_CHARS 0x00000001 +#define SSTF_DISPLAY 0x00000003 +#define SSTF_NONE 0x00000000 + +#define SSGF_DISPLAY 0x00000003 +#define SSGF_NONE 0x00000000 + +#define SSWF_DISPLAY 0x00000003 +#define SSWF_NONE 0x00000000 +#define SSWF_TITLE 0x00000001 +#define SSWF_WINDOW 0x00000002 + +typedef struct tagSOUNDSENTRYA +{ + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; +} SOUNDSENTRYA, *LPSOUNDSENTRYA; + +typedef struct tagSOUNDSENTRYW +{ + UINT cbSize; + DWORD dwFlags; + DWORD iFSTextEffect; + DWORD iFSTextEffectMSec; + DWORD iFSTextEffectColorBits; + DWORD iFSGrafEffect; + DWORD iFSGrafEffectMSec; + DWORD iFSGrafEffectColor; + DWORD iWindowsEffect; + DWORD iWindowsEffectMSec; + LPWSTR lpszWindowsEffectDLL; + DWORD iWindowsEffectOrdinal; +} SOUNDSENTRYW, *LPSOUNDSENTRYW; + +/* flags for HIGHCONTRAST dwFlags field */ +#define HCF_HIGHCONTRASTON 0x00000001 +#define HCF_AVAILABLE 0x00000002 +#define HCF_HOTKEYACTIVE 0x00000004 +#define HCF_CONFIRMHOTKEY 0x00000008 +#define HCF_HOTKEYSOUND 0x00000010 +#define HCF_INDICATOR 0x00000020 +#define HCF_HOTKEYAVAILABLE 0x00000040 + +typedef struct tagHIGHCONTRASTA +{ + UINT cbSize; + DWORD dwFlags; + LPSTR lpszDefaultScheme; +} HIGHCONTRASTA, *LPHIGHCONTRASTA; + +typedef struct tagHIGHCONTRASTW +{ + UINT cbSize; + DWORD dwFlags; + LPWSTR lpszDefaultScheme; +} HIGHCONTRASTW, *LPHIGHCONTRASTW; + +typedef struct tagEVENTMSG +{ + UINT message; + UINT paramL; + UINT paramH; + DWORD time; + HWND hwnd; +} EVENTMSG, *PEVENTMSG, *LPEVENTMSG; + +/* WH_KEYBOARD_LL structure */ +typedef struct tagKBDLLHOOKSTRUCT +{ + DWORD vkCode; + DWORD scanCode; + DWORD flags; + DWORD time; + ULONG_PTR dwExtraInfo; +} KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT; + +#define LLKHF_EXTENDED (KF_EXTENDED >> 8) +#define LLKHF_INJECTED 0x00000010 +#define LLKHF_ALTDOWN (KF_ALTDOWN >> 8) +#define LLKHF_UP (KF_UP >> 8) + +#define LLMHF_INJECTED 0x00000001 + +#define HKL_PREV 0 +#define HKL_NEXT 1 + +#define KLF_ACTIVATE 0x00000001 +#define KLF_SUBSTITUTE_OK 0x00000002 +#define KLF_UNLOADPREVIOUS 0x00000004 +#define KLF_REORDER 0x00000008 +#define KLF_REPLACELANG 0x00000010 +#define KLF_NOTELLSHELL 0x00000080 +#define KLF_SETFORPROCESS 0x00000100 +#define KLF_SHIFTLOCK 0x00010000 +#define KLF_RESET 0x40000000 + +#define KL_NAMELENGTH 9 + +typedef struct tagMOUSEINPUT +{ + LONG dx; + LONG dy; + DWORD mouseData; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; +} MOUSEINPUT, *PMOUSEINPUT, *LPMOUSEINPUT; + +typedef struct tagKEYBDINPUT +{ + WORD wVk; + WORD wScan; + DWORD dwFlags; + DWORD time; + ULONG_PTR dwExtraInfo; +} KEYBDINPUT, *PKEYBDINPUT, *LPKEYBDINPUT; + +typedef struct tagHARDWAREINPUT +{ + DWORD uMsg; + WORD wParamL; + WORD wParamH; +} HARDWAREINPUT, *PHARDWAREINPUT, *LPHARDWAREINPUT; + +#define INPUT_MOUSE 0 +#define INPUT_KEYBOARD 1 +#define INPUT_HARDWARE 2 + +typedef struct tagINPUT +{ + DWORD type; + union + { + MOUSEINPUT mi; + KEYBDINPUT ki; + HARDWAREINPUT hi; + } DUMMYUNIONNAME; +} INPUT, *PINPUT, *LPINPUT; + +typedef struct tagRAWHID { + DWORD dwSizeHid; + DWORD dwCount; + BYTE bRawData; +} RAWHID, *LPRAWHID; + +typedef struct tagRAWKEYBOARD { + USHORT MakeCode; + USHORT Flags; + USHORT Reserved; + USHORT VKey; + UINT Message; + ULONG ExtraInformation; +} RAWKEYBOARD, *PRAWKEYBOARD, *LPRAWKEYBOARD; + +typedef struct tagRAWMOUSE { + USHORT usFlags; + union { + ULONG ulButtons; + struct { + USHORT usButtonFlags; + USHORT usButtonData; + } DUMMYSTRUCTNAME; + } DUMMYUNIONNAME; + ULONG ulRawButtons; + LONG lLastX; + LONG lLastY; + ULONG ulExtraInformation; +} RAWMOUSE, *PRAWMOUSE, *LPRAWMOUSE; + +/* Messages */ +#define WM_NULL 0x0000 +#define WM_CREATE 0x0001 +#define WM_DESTROY 0x0002 +#define WM_MOVE 0x0003 +#define WM_SIZEWAIT 0x0004 +#define WM_SIZE 0x0005 +#define WM_ACTIVATE 0x0006 +#define WM_SETFOCUS 0x0007 +#define WM_KILLFOCUS 0x0008 +#define WM_SETVISIBLE 0x0009 +#define WM_ENABLE 0x000a +#define WM_SETREDRAW 0x000b +#define WM_SETTEXT 0x000c +#define WM_GETTEXT 0x000d +#define WM_GETTEXTLENGTH 0x000e +#define WM_PAINT 0x000f +#define WM_CLOSE 0x0010 +#define WM_QUERYENDSESSION 0x0011 +#define WM_QUIT 0x0012 +#define WM_QUERYOPEN 0x0013 +#define WM_ERASEBKGND 0x0014 +#define WM_SYSCOLORCHANGE 0x0015 +#define WM_ENDSESSION 0x0016 +#define WM_SYSTEMERROR 0x0017 +#define WM_SHOWWINDOW 0x0018 +#define WM_CTLCOLOR 0x0019 +#define WM_WININICHANGE 0x001a +#define WM_SETTINGCHANGE WM_WININICHANGE +#define WM_DEVMODECHANGE 0x001b +#define WM_ACTIVATEAPP 0x001c +#define WM_FONTCHANGE 0x001d +#define WM_TIMECHANGE 0x001e +#define WM_CANCELMODE 0x001f +#define WM_SETCURSOR 0x0020 +#define WM_MOUSEACTIVATE 0x0021 +#define WM_CHILDACTIVATE 0x0022 +#define WM_QUEUESYNC 0x0023 +#define WM_GETMINMAXINFO 0x0024 + +#define WM_PAINTICON 0x0026 +#define WM_ICONERASEBKGND 0x0027 +#define WM_NEXTDLGCTL 0x0028 +#define WM_ALTTABACTIVE 0x0029 +#define WM_SPOOLERSTATUS 0x002a +#define WM_DRAWITEM 0x002b +#define WM_MEASUREITEM 0x002c +#define WM_DELETEITEM 0x002d +#define WM_VKEYTOITEM 0x002e +#define WM_CHARTOITEM 0x002f +#define WM_SETFONT 0x0030 +#define WM_GETFONT 0x0031 +#define WM_SETHOTKEY 0x0032 +#define WM_GETHOTKEY 0x0033 +#define WM_FILESYSCHANGE 0x0034 +#define WM_ISACTIVEICON 0x0035 +#define WM_QUERYPARKICON 0x0036 +#define WM_QUERYDRAGICON 0x0037 +#define WM_QUERYSAVESTATE 0x0038 +#define WM_COMPAREITEM 0x0039 +#define WM_TESTING 0x003a + +#define WM_GETOBJECT 0x003d + +#define WM_ACTIVATESHELLWINDOW 0x003e + +#define WM_COMPACTING 0x0041 + +#define WM_COMMNOTIFY 0x0044 +#define WM_WINDOWPOSCHANGING 0x0046 +#define WM_WINDOWPOSCHANGED 0x0047 +#define WM_POWER 0x0048 + + /* Win32 4.0 messages */ +#define WM_COPYDATA 0x004a +#define WM_CANCELJOURNAL 0x004b +#define WM_KEYF1 0x004d +#define WM_NOTIFY 0x004e +#define WM_INPUTLANGCHANGEREQUEST 0x0050 +#define WM_INPUTLANGCHANGE 0x0051 +#define WM_TCARD 0x0052 +#define WM_HELP 0x0053 +#define WM_USERCHANGED 0x0054 +#define WM_NOTIFYFORMAT 0x0055 + +#define WM_CONTEXTMENU 0x007b +#define WM_STYLECHANGING 0x007c +#define WM_STYLECHANGED 0x007d +#define WM_DISPLAYCHANGE 0x007e +#define WM_GETICON 0x007f +#define WM_SETICON 0x0080 + + /* Non-client system messages */ +#define WM_NCCREATE 0x0081 +#define WM_NCDESTROY 0x0082 +#define WM_NCCALCSIZE 0x0083 +#define WM_NCHITTEST 0x0084 +#define WM_NCPAINT 0x0085 +#define WM_NCACTIVATE 0x0086 + +#define WM_GETDLGCODE 0x0087 +#define WM_SYNCPAINT 0x0088 +#define WM_SYNCTASK 0x0089 + + /* Non-client mouse messages */ +#define WM_NCMOUSEMOVE 0x00a0 +#define WM_NCLBUTTONDOWN 0x00a1 +#define WM_NCLBUTTONUP 0x00a2 +#define WM_NCLBUTTONDBLCLK 0x00a3 +#define WM_NCRBUTTONDOWN 0x00a4 +#define WM_NCRBUTTONUP 0x00a5 +#define WM_NCRBUTTONDBLCLK 0x00a6 +#define WM_NCMBUTTONDOWN 0x00a7 +#define WM_NCMBUTTONUP 0x00a8 +#define WM_NCMBUTTONDBLCLK 0x00a9 + +#define WM_NCXBUTTONDOWN 0x00ab +#define WM_NCXBUTTONUP 0x00ac +#define WM_NCXBUTTONDBLCLK 0x00ad + + /* Raw input */ +#define WM_INPUT_DEVICE_CHANGE 0x00fe +#define WM_INPUT 0x00ff + + /* Keyboard messages */ +#define WM_KEYDOWN 0x0100 +#define WM_KEYUP 0x0101 +#define WM_CHAR 0x0102 +#define WM_DEADCHAR 0x0103 +#define WM_SYSKEYDOWN 0x0104 +#define WM_SYSKEYUP 0x0105 +#define WM_SYSCHAR 0x0106 +#define WM_SYSDEADCHAR 0x0107 +#define WM_UNICHAR 0x0109 +#define WM_KEYFIRST WM_KEYDOWN +#define WM_KEYLAST 0x0109 + +/* Win32 4.0 messages for IME */ +#define WM_IME_STARTCOMPOSITION 0x010d +#define WM_IME_ENDCOMPOSITION 0x010e +#define WM_IME_COMPOSITION 0x010f +#define WM_IME_KEYLAST 0x010f + +#define WM_INITDIALOG 0x0110 +#define WM_COMMAND 0x0111 +#define WM_SYSCOMMAND 0x0112 +#define WM_TIMER 0x0113 + + /* scroll messages */ +#define WM_HSCROLL 0x0114 +#define WM_VSCROLL 0x0115 + +/* Menu messages */ +#define WM_INITMENU 0x0116 +#define WM_INITMENUPOPUP 0x0117 + +#define WM_MENUSELECT 0x011F +#define WM_MENUCHAR 0x0120 +#define WM_ENTERIDLE 0x0121 + +#define WM_MENURBUTTONUP 0x0122 +#define WM_MENUDRAG 0x0123 +#define WM_MENUGETOBJECT 0x0124 +#define WM_UNINITMENUPOPUP 0x0125 +#define WM_MENUCOMMAND 0x0126 + +#define WM_CHANGEUISTATE 0x0127 +#define WM_UPDATEUISTATE 0x0128 +#define WM_QUERYUISTATE 0x0129 + +/* UI flags for WM_*UISTATE */ +/* for low-order word of wparam */ +#define UIS_SET 1 +#define UIS_CLEAR 2 +#define UIS_INITIALIZE 3 +/* for hi-order word of wparam */ +#define UISF_HIDEFOCUS 0x1 +#define UISF_HIDEACCEL 0x2 +#define UISF_ACTIVE 0x4 + +#define WM_LBTRACKPOINT 0x0131 + + /* Win32 CTLCOLOR messages */ +#define WM_CTLCOLORMSGBOX 0x0132 +#define WM_CTLCOLOREDIT 0x0133 +#define WM_CTLCOLORLISTBOX 0x0134 +#define WM_CTLCOLORBTN 0x0135 +#define WM_CTLCOLORDLG 0x0136 +#define WM_CTLCOLORSCROLLBAR 0x0137 +#define WM_CTLCOLORSTATIC 0x0138 + +#define MN_GETHMENU 0x01E1 + + /* Mouse messages */ +#define WM_MOUSEMOVE 0x0200 +#define WM_LBUTTONDOWN 0x0201 +#define WM_LBUTTONUP 0x0202 +#define WM_LBUTTONDBLCLK 0x0203 +#define WM_RBUTTONDOWN 0x0204 +#define WM_RBUTTONUP 0x0205 +#define WM_RBUTTONDBLCLK 0x0206 +#define WM_MBUTTONDOWN 0x0207 +#define WM_MBUTTONUP 0x0208 +#define WM_MBUTTONDBLCLK 0x0209 +#define WM_MOUSEWHEEL 0x020A +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_MOUSEHWHEEL 0x020E + +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 + +#define WM_MOUSEFIRST 0x0200 +#define WM_MOUSELAST 0x020E + +#define WHEEL_DELTA 120 +#define WHEEL_PAGESCROLL (UINT_MAX) +#define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam)) + +#define WM_PARENTNOTIFY 0x0210 +#define WM_ENTERMENULOOP 0x0211 +#define WM_EXITMENULOOP 0x0212 +#define WM_NEXTMENU 0x0213 + + /* Win32 4.0 messages */ +#define WM_SIZING 0x0214 +#define WM_CAPTURECHANGED 0x0215 +#define WM_MOVING 0x0216 +#define WM_POWERBROADCAST 0x0218 +#define WM_DEVICECHANGE 0x0219 + +/* wParam for WM_SIZING message */ +#define WMSZ_LEFT 1 +#define WMSZ_RIGHT 2 +#define WMSZ_TOP 3 +#define WMSZ_TOPLEFT 4 +#define WMSZ_TOPRIGHT 5 +#define WMSZ_BOTTOM 6 +#define WMSZ_BOTTOMLEFT 7 +#define WMSZ_BOTTOMRIGHT 8 + +/* wParam for WM_POWERBROADCAST */ +#define PBT_APMQUERYSUSPEND 0x0000 +#define PBT_APMQUERYSTANDBY 0x0001 +#define PBT_APMQUERYSUSPENDFAILED 0x0002 +#define PBT_APMQUERYSTANDBYFAILED 0x0003 +#define PBT_APMSUSPEND 0x0004 +#define PBT_APMSTANDBY 0x0005 +#define PBT_APMRESUMECRITICAL 0x0006 +#define PBT_APMRESUMESUSPEND 0x0007 +#define PBT_APMRESUMESTANDBY 0x0008 +#define PBT_APMBATTERYLOW 0x0009 +#define PBT_APMPOWERSTATUSCHANGE 0x000A +#define PBT_APMOEMEVENT 0x000B +#define PBT_APMRESUMEAUTOMATIC 0x0012 + +#define PBTF_APMRESUMEFROMFAILURE 0x00000001 + + /* MDI messages */ +#define WM_MDICREATE 0x0220 +#define WM_MDIDESTROY 0x0221 +#define WM_MDIACTIVATE 0x0222 +#define WM_MDIRESTORE 0x0223 +#define WM_MDINEXT 0x0224 +#define WM_MDIMAXIMIZE 0x0225 +#define WM_MDITILE 0x0226 +#define WM_MDICASCADE 0x0227 +#define WM_MDIICONARRANGE 0x0228 +#define WM_MDIGETACTIVE 0x0229 +#define WM_MDIREFRESHMENU 0x0234 + + /* D&D messages */ +#define WM_DROPOBJECT 0x022A +#define WM_QUERYDROPOBJECT 0x022B +#define WM_BEGINDRAG 0x022C +#define WM_DRAGLOOP 0x022D +#define WM_DRAGSELECT 0x022E +#define WM_DRAGMOVE 0x022F +#define WM_MDISETMENU 0x0230 + +#define WM_ENTERSIZEMOVE 0x0231 +#define WM_EXITSIZEMOVE 0x0232 +#define WM_DROPFILES 0x0233 + + +/* Win32 4.0 messages for IME */ +#define WM_IME_SETCONTEXT 0x0281 +#define WM_IME_NOTIFY 0x0282 +#define WM_IME_CONTROL 0x0283 +#define WM_IME_COMPOSITIONFULL 0x0284 +#define WM_IME_SELECT 0x0285 +#define WM_IME_CHAR 0x0286 +/* Win32 5.0 messages for IME */ +#define WM_IME_REQUEST 0x0288 + +/* Win32 4.0 messages for IME */ +#define WM_IME_KEYDOWN 0x0290 +#define WM_IME_KEYUP 0x0291 + +#define WM_NCMOUSEHOVER 0x02A0 +#define WM_MOUSEHOVER 0x02A1 +#define WM_MOUSELEAVE 0x02A3 +#define WM_NCMOUSELEAVE 0x02A2 + +#define WM_WTSSESSION_CHANGE 0x02B1 + +#define WM_TABLET_FIRST 0x02c0 +#define WM_TABLET_LAST 0x02df + +/* Clipboard command messages */ +#define WM_CUT 0x0300 +#define WM_COPY 0x0301 +#define WM_PASTE 0x0302 +#define WM_CLEAR 0x0303 +#define WM_UNDO 0x0304 + +/* Clipboard owner messages */ +#define WM_RENDERFORMAT 0x0305 +#define WM_RENDERALLFORMATS 0x0306 +#define WM_DESTROYCLIPBOARD 0x0307 + +/* Clipboard viewer messages */ +#define WM_DRAWCLIPBOARD 0x0308 +#define WM_PAINTCLIPBOARD 0x0309 +#define WM_VSCROLLCLIPBOARD 0x030A +#define WM_SIZECLIPBOARD 0x030B +#define WM_ASKCBFORMATNAME 0x030C +#define WM_CHANGECBCHAIN 0x030D +#define WM_HSCROLLCLIPBOARD 0x030E + +#define WM_QUERYNEWPALETTE 0x030F +#define WM_PALETTEISCHANGING 0x0310 +#define WM_PALETTECHANGED 0x0311 +#define WM_HOTKEY 0x0312 + +#define WM_PRINT 0x0317 +#define WM_PRINTCLIENT 0x0318 +#define WM_APPCOMMAND 0x0319 +#define WM_THEMECHANGED 0x031A +#define WM_CLIPBOARDUPDATE 0x031D + +#define WM_DWMCOMPOSITIONCHANGED 0x031E +#define WM_DWMNCRENDERINGCHANGED 0x031F +#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 +#define WM_DWMWINDOWMAXIMIZEDCHANGE 0x0321 + +#define WM_GETTITLEBARINFOEX 0x033F + +#define WM_HANDHELDFIRST 0x0358 +#define WM_HANDHELDLAST 0x035F + +#define WM_AFXFIRST 0x0360 +#define WM_AFXLAST 0x037F + +#define WM_PENWINFIRST 0x0380 +#define WM_PENWINLAST 0x038F + +#define WM_APP 0x8000 + +#define UNICODE_NOCHAR 0xFFFF + +/* MsgWaitForMultipleObjectsEx flags */ +#define MWMO_WAITALL 0x0001 +#define MWMO_ALERTABLE 0x0002 +#define MWMO_INPUTAVAILABLE 0x0004 + +/* WM_GETDLGCODE values */ +#define DLGC_WANTARROWS 0x0001 +#define DLGC_WANTTAB 0x0002 +#define DLGC_WANTALLKEYS 0x0004 +#define DLGC_WANTMESSAGE 0x0004 +#define DLGC_HASSETSEL 0x0008 +#define DLGC_DEFPUSHBUTTON 0x0010 +#define DLGC_UNDEFPUSHBUTTON 0x0020 +#define DLGC_RADIOBUTTON 0x0040 +#define DLGC_WANTCHARS 0x0080 +#define DLGC_STATIC 0x0100 +#define DLGC_BUTTON 0x2000 + +/* Standard dialog button IDs */ +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 +#define IDCLOSE 8 +#define IDHELP 9 +#define IDTRYAGAIN 10 +#define IDCONTINUE 11 + +#ifndef IDTIMEOUT +#define IDTIMEOUT 32000 +#endif + +/* Used for EnumDisplaySettingsEx */ +#define ENUM_CURRENT_SETTINGS ((DWORD) -1) +#define ENUM_REGISTRY_SETTINGS ((DWORD) -2) + +/***** Window hooks *****/ + + /* Hook values */ +#define WH_MIN (-1) +#define WH_MSGFILTER (-1) +#define WH_JOURNALRECORD 0 +#define WH_JOURNALPLAYBACK 1 +#define WH_KEYBOARD 2 +#define WH_GETMESSAGE 3 +#define WH_CALLWNDPROC 4 +#define WH_CBT 5 +#define WH_SYSMSGFILTER 6 +#define WH_MOUSE 7 +#define WH_HARDWARE 8 +#define WH_DEBUG 9 +#define WH_SHELL 10 +#define WH_FOREGROUNDIDLE 11 +#define WH_CALLWNDPROCRET 12 +#define WH_KEYBOARD_LL 13 +#define WH_MOUSE_LL 14 +#define WH_MAX 14 + +#define WH_MINHOOK WH_MIN +#define WH_MAXHOOK WH_MAX + + /* Hook action codes */ +#define HC_ACTION 0 +#define HC_GETNEXT 1 +#define HC_SKIP 2 +#define HC_NOREMOVE 3 +#define HC_NOREM HC_NOREMOVE +#define HC_SYSMODALON 4 +#define HC_SYSMODALOFF 5 + + /* CallMsgFilter() values */ +#define MSGF_DIALOGBOX 0 +#define MSGF_MESSAGEBOX 1 +#define MSGF_MENU 2 +#define MSGF_MOVE 3 +#define MSGF_SIZE 4 +#define MSGF_SCROLLBAR 5 +#define MSGF_NEXTWINDOW 6 +#define MSGF_MAX 8 +#define MSGF_USER 0x1000 +#define MSGF_DDEMGR 0x8001 + +/* WM_KEYUP/DOWN/CHAR HIWORD(lParam) flags */ +#define KF_EXTENDED 0x0100 +#define KF_DLGMODE 0x0800 +#define KF_MENUMODE 0x1000 +#define KF_ALTDOWN 0x2000 +#define KF_REPEAT 0x4000 +#define KF_UP 0x8000 + +/* Virtual key codes */ +#define VK_LBUTTON 0x01 +#define VK_RBUTTON 0x02 +#define VK_CANCEL 0x03 +#define VK_MBUTTON 0x04 +#define VK_XBUTTON1 0x05 +#define VK_XBUTTON2 0x06 +/* 0x07 Undefined */ +#define VK_BACK 0x08 +#define VK_TAB 0x09 +/* 0x0A-0x0B Undefined */ +#define VK_CLEAR 0x0C +#define VK_RETURN 0x0D +/* 0x0E-0x0F Undefined */ +#define VK_SHIFT 0x10 +#define VK_CONTROL 0x11 +#define VK_MENU 0x12 +#define VK_PAUSE 0x13 +#define VK_CAPITAL 0x14 + +#define VK_KANA 0x15 +#define VK_HANGEUL 0x15 +#define VK_HANGUL 0x15 +#define VK_JUNJA 0x17 +#define VK_FINAL 0x18 +#define VK_HANJA 0x19 +#define VK_KANJI 0x19 + +/* 0x1A Undefined */ +#define VK_ESCAPE 0x1B + +#define VK_CONVERT 0x1C +#define VK_NONCONVERT 0x1D +#define VK_ACCEPT 0x1E +#define VK_MODECHANGE 0x1F + +#define VK_SPACE 0x20 +#define VK_PRIOR 0x21 +#define VK_NEXT 0x22 +#define VK_END 0x23 +#define VK_HOME 0x24 +#define VK_LEFT 0x25 +#define VK_UP 0x26 +#define VK_RIGHT 0x27 +#define VK_DOWN 0x28 +#define VK_SELECT 0x29 +#define VK_PRINT 0x2A /* OEM specific in Windows 3.1 SDK */ +#define VK_EXECUTE 0x2B +#define VK_SNAPSHOT 0x2C +#define VK_INSERT 0x2D +#define VK_DELETE 0x2E +#define VK_HELP 0x2F +/* VK_0 - VK-9 0x30-0x39 Use ASCII instead */ +/* 0x3A-0x40 Undefined */ +/* VK_A - VK_Z 0x41-0x5A Use ASCII instead */ +#define VK_LWIN 0x5B +#define VK_RWIN 0x5C +#define VK_APPS 0x5D +/* 0x5E Unassigned */ +#define VK_SLEEP 0x5F +#define VK_NUMPAD0 0x60 +#define VK_NUMPAD1 0x61 +#define VK_NUMPAD2 0x62 +#define VK_NUMPAD3 0x63 +#define VK_NUMPAD4 0x64 +#define VK_NUMPAD5 0x65 +#define VK_NUMPAD6 0x66 +#define VK_NUMPAD7 0x67 +#define VK_NUMPAD8 0x68 +#define VK_NUMPAD9 0x69 +#define VK_MULTIPLY 0x6A +#define VK_ADD 0x6B +#define VK_SEPARATOR 0x6C +#define VK_SUBTRACT 0x6D +#define VK_DECIMAL 0x6E +#define VK_DIVIDE 0x6F +#define VK_F1 0x70 +#define VK_F2 0x71 +#define VK_F3 0x72 +#define VK_F4 0x73 +#define VK_F5 0x74 +#define VK_F6 0x75 +#define VK_F7 0x76 +#define VK_F8 0x77 +#define VK_F9 0x78 +#define VK_F10 0x79 +#define VK_F11 0x7A +#define VK_F12 0x7B +#define VK_F13 0x7C +#define VK_F14 0x7D +#define VK_F15 0x7E +#define VK_F16 0x7F +#define VK_F17 0x80 +#define VK_F18 0x81 +#define VK_F19 0x82 +#define VK_F20 0x83 +#define VK_F21 0x84 +#define VK_F22 0x85 +#define VK_F23 0x86 +#define VK_F24 0x87 +/* 0x88-0x8F Unassigned */ +#define VK_NUMLOCK 0x90 +#define VK_SCROLL 0x91 +#define VK_OEM_NEC_EQUAL 0x92 +#define VK_OEM_FJ_JISHO 0x92 +#define VK_OEM_FJ_MASSHOU 0x93 +#define VK_OEM_FJ_TOUROKU 0x94 +#define VK_OEM_FJ_LOYA 0x95 +#define VK_OEM_FJ_ROYA 0x96 +/* 0x97-0x9F Unassigned */ +/* + * differencing between right and left shift/control/alt key. + * Used only by GetAsyncKeyState() and GetKeyState(). + */ +#define VK_LSHIFT 0xA0 +#define VK_RSHIFT 0xA1 +#define VK_LCONTROL 0xA2 +#define VK_RCONTROL 0xA3 +#define VK_LMENU 0xA4 +#define VK_RMENU 0xA5 + +#define VK_BROWSER_BACK 0xA6 +#define VK_BROWSER_FORWARD 0xA7 +#define VK_BROWSER_REFRESH 0xA8 +#define VK_BROWSER_STOP 0xA9 +#define VK_BROWSER_SEARCH 0xAA +#define VK_BROWSER_FAVORITES 0xAB +#define VK_BROWSER_HOME 0xAC +#define VK_VOLUME_MUTE 0xAD +#define VK_VOLUME_DOWN 0xAE +#define VK_VOLUME_UP 0xAF +#define VK_MEDIA_NEXT_TRACK 0xB0 +#define VK_MEDIA_PREV_TRACK 0xB1 +#define VK_MEDIA_STOP 0xB2 +#define VK_MEDIA_PLAY_PAUSE 0xB3 +#define VK_LAUNCH_MAIL 0xB4 +#define VK_LAUNCH_MEDIA_SELECT 0xB5 +#define VK_LAUNCH_APP1 0xB6 +#define VK_LAUNCH_APP2 0xB7 + +/* 0xB8-0xB9 Unassigned */ +#define VK_OEM_1 0xBA +#define VK_OEM_PLUS 0xBB +#define VK_OEM_COMMA 0xBC +#define VK_OEM_MINUS 0xBD +#define VK_OEM_PERIOD 0xBE +#define VK_OEM_2 0xBF +#define VK_OEM_3 0xC0 +/* 0xC1-0xDA Unassigned */ +#define VK_OEM_4 0xDB +#define VK_OEM_5 0xDC +#define VK_OEM_6 0xDD +#define VK_OEM_7 0xDE +#define VK_OEM_8 0xDF +/* 0xE0 OEM specific */ +#define VK_OEM_AX 0xE1 /* "AX" key on Japanese AX keyboard */ +#define VK_OEM_102 0xE2 /* "<>" or "\|" on RT 102-key keyboard */ +#define VK_ICO_HELP 0xE3 /* Help key on ICO */ +#define VK_ICO_00 0xE4 /* 00 key on ICO */ +#define VK_PROCESSKEY 0xE5 + +/* 0xE6 OEM specific */ +/* 0xE7-0xE8 Unassigned */ +/* 0xE9-0xF5 OEM specific */ + +#define VK_ATTN 0xF6 +#define VK_CRSEL 0xF7 +#define VK_EXSEL 0xF8 +#define VK_EREOF 0xF9 +#define VK_PLAY 0xFA +#define VK_ZOOM 0xFB +#define VK_NONAME 0xFC +#define VK_PA1 0xFD +#define VK_OEM_CLEAR 0xFE + +/* MapVirtualKey translation types */ +#define MAPVK_VK_TO_VSC 0 +#define MAPVK_VSC_TO_VK 1 +#define MAPVK_VK_TO_CHAR 2 +#define MAPVK_VSC_TO_VK_EX 3 +#define MAPVK_VK_TO_VSC_EX 4 + + /* Key status flags for mouse events */ +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 +#define MK_XBUTTON1 0x0020 +#define MK_XBUTTON2 0x0040 + + +#define TME_HOVER 0x00000001 +#define TME_LEAVE 0x00000002 +#define TME_NONCLIENT 0x00000010 +#define TME_QUERY 0x40000000 +#define TME_CANCEL 0x80000000 + +#define HOVER_DEFAULT 0xFFFFFFFF + +typedef struct tagTRACKMOUSEEVENT { + DWORD cbSize; + DWORD dwFlags; + HWND hwndTrack; + DWORD dwHoverTime; +} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT; + + /* Queue status flags */ +#define QS_KEY 0x0001 +#define QS_MOUSEMOVE 0x0002 +#define QS_MOUSEBUTTON 0x0004 +#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON) +#define QS_POSTMESSAGE 0x0008 +#define QS_TIMER 0x0010 +#define QS_PAINT 0x0020 +#define QS_SENDMESSAGE 0x0040 +#define QS_HOTKEY 0x0080 +#define QS_ALLPOSTMESSAGE 0x0100 +#define QS_RAWINPUT 0x0400 +#define QS_INPUT (QS_MOUSE | QS_KEY | QS_RAWINPUT) +#define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) +#define QS_ALLINPUT (QS_ALLEVENTS | QS_SENDMESSAGE) + +/* Extra (undocumented) queue wake bits - see "Undoc. Windows" */ +#define QS_SMRESULT 0x8000 + +/* InSendMessageEx flags */ +#define ISMEX_NOSEND 0x00000000 +#define ISMEX_SEND 0x00000001 +#define ISMEX_NOTIFY 0x00000002 +#define ISMEX_CALLBACK 0x00000004 +#define ISMEX_REPLIED 0x00000008 + +#define DDL_READWRITE 0x0000 +#define DDL_READONLY 0x0001 +#define DDL_HIDDEN 0x0002 +#define DDL_SYSTEM 0x0004 +#define DDL_DIRECTORY 0x0010 +#define DDL_ARCHIVE 0x0020 + +#define DDL_POSTMSGS 0x2000 +#define DDL_DRIVES 0x4000 +#define DDL_EXCLUSIVE 0x8000 + + /* Shell hook values */ +#define HSHELL_WINDOWCREATED 1 +#define HSHELL_WINDOWDESTROYED 2 +#define HSHELL_ACTIVATESHELLWINDOW 3 +#define HSHELL_WINDOWACTIVATED 4 +#define HSHELL_GETMINRECT 5 +#define HSHELL_REDRAW 6 +#define HSHELL_TASKMAN 7 +#define HSHELL_LANGUAGE 8 +#define HSHELL_SYSMENU 9 +#define HSHELL_ENDTASK 10 +#define HSHELL_ACCESSIBILITYSTATE 11 +#define HSHELL_APPCOMMAND 12 +#define HSHELL_WINDOWREPLACED 13 +#define HSHELL_WINDOWREPLACING 14 + +#define HSHELL_HIGHBIT 0x8000 +#define HSHELL_FLASH (HSHELL_REDRAW|HSHELL_HIGHBIT) +#define HSHELL_RUDEAPPACTIVATED (HSHELL_WINDOWACTIVATED|HSHELL_HIGHBIT) + +/* App commands */ +#define APPCOMMAND_BROWSER_BACKWARD 1 +#define APPCOMMAND_BROWSER_FORWARD 2 +#define APPCOMMAND_BROWSER_REFRESH 3 +#define APPCOMMAND_BROWSER_STOP 4 +#define APPCOMMAND_BROWSER_SEARCH 5 +#define APPCOMMAND_BROWSER_FAVORITES 6 +#define APPCOMMAND_BROWSER_HOME 7 +#define APPCOMMAND_VOLUME_MUTE 8 +#define APPCOMMAND_VOLUME_DOWN 9 +#define APPCOMMAND_VOLUME_UP 10 +#define APPCOMMAND_MEDIA_NEXTTRACK 11 +#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 +#define APPCOMMAND_MEDIA_STOP 13 +#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 +#define APPCOMMAND_LAUNCH_MAIL 15 +#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 +#define APPCOMMAND_LAUNCH_APP1 17 +#define APPCOMMAND_LAUNCH_APP2 18 +#define APPCOMMAND_BASS_DOWN 19 +#define APPCOMMAND_BASS_BOOST 20 +#define APPCOMMAND_BASS_UP 21 +#define APPCOMMAND_TREBLE_DOWN 22 +#define APPCOMMAND_TREBLE_UP 23 +#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 +#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 +#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 +#define APPCOMMAND_HELP 27 +#define APPCOMMAND_FIND 28 +#define APPCOMMAND_NEW 29 +#define APPCOMMAND_OPEN 30 +#define APPCOMMAND_CLOSE 31 +#define APPCOMMAND_SAVE 32 +#define APPCOMMAND_PRINT 33 +#define APPCOMMAND_UNDO 34 +#define APPCOMMAND_REDO 35 +#define APPCOMMAND_COPY 36 +#define APPCOMMAND_CUT 37 +#define APPCOMMAND_PASTE 38 +#define APPCOMMAND_REPLY_TO_MAIL 39 +#define APPCOMMAND_FORWARD_MAIL 40 +#define APPCOMMAND_SEND_MAIL 41 +#define APPCOMMAND_SPELL_CHECK 42 +#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 +#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 +#define APPCOMMAND_CORRECTION_LIST 45 +#define APPCOMMAND_MEDIA_PLAY 46 +#define APPCOMMAND_MEDIA_PAUSE 47 +#define APPCOMMAND_MEDIA_RECORD 48 +#define APPCOMMAND_MEDIA_FAST_FORWARD 49 +#define APPCOMMAND_MEDIA_REWIND 50 +#define APPCOMMAND_MEDIA_CHANNEL_UP 51 +#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 +#define APPCOMMAND_DELETE 53 +#define APPCOMMAND_DWM_FLIP3D 54 + +#define FAPPCOMMAND_MOUSE 0x8000 +#define FAPPCOMMAND_KEY 0 +#define FAPPCOMMAND_OEM 0x1000 +#define FAPPCOMMAND_MASK 0xF000 + +#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK)) +#define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK)) +#define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM +#define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam)) +#define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam) + +/* Predefined Clipboard Formats */ +#define CF_TEXT 1 +#define CF_BITMAP 2 +#define CF_METAFILEPICT 3 +#define CF_SYLK 4 +#define CF_DIF 5 +#define CF_TIFF 6 +#define CF_OEMTEXT 7 +#define CF_DIB 8 +#define CF_PALETTE 9 +#define CF_PENDATA 10 +#define CF_RIFF 11 +#define CF_WAVE 12 +#define CF_UNICODETEXT 13 +#define CF_ENHMETAFILE 14 +#define CF_HDROP 15 +#define CF_LOCALE 16 +#define CF_DIBV5 17 +#define CF_MAX 18 + +#define CF_OWNERDISPLAY 0x0080 +#define CF_DSPTEXT 0x0081 +#define CF_DSPBITMAP 0x0082 +#define CF_DSPMETAFILEPICT 0x0083 +#define CF_DSPENHMETAFILE 0x008E + +/* "Private" formats don't get GlobalFree()'d */ +#define CF_PRIVATEFIRST 0x0200 +#define CF_PRIVATELAST 0x02FF + +/* "GDIOBJ" formats do get DeleteObject()'d */ +#define CF_GDIOBJFIRST 0x0300 +#define CF_GDIOBJLAST 0x03FF + + +/* types of LoadImage */ +#define IMAGE_BITMAP 0 +#define IMAGE_ICON 1 +#define IMAGE_CURSOR 2 +#define IMAGE_ENHMETAFILE 3 + +/* loadflags to LoadImage */ +#define LR_DEFAULTCOLOR 0x0000 +#define LR_MONOCHROME 0x0001 +#define LR_COLOR 0x0002 +#define LR_COPYRETURNORG 0x0004 +#define LR_COPYDELETEORG 0x0008 +#define LR_LOADFROMFILE 0x0010 +#define LR_LOADTRANSPARENT 0x0020 +#define LR_DEFAULTSIZE 0x0040 +#define LR_VGA_COLOR 0x0080 +#define LR_LOADMAP3DCOLORS 0x1000 +#define LR_CREATEDIBSECTION 0x2000 +#define LR_COPYFROMRESOURCE 0x4000 +#define LR_SHARED 0x8000 + +/* Flags for DrawIconEx. */ +#define DI_MASK 0x0001 +#define DI_IMAGE 0x0002 +#define DI_NORMAL (DI_MASK | DI_IMAGE) +#define DI_COMPAT 0x0004 +#define DI_DEFAULTSIZE 0x0008 +#define DI_NOMIRROR 0x0010 + +/* WM_NOTIFYFORMAT commands and return values */ +#define NFR_ANSI 1 +#define NFR_UNICODE 2 +#define NF_QUERY 3 +#define NF_REQUERY 4 + +/* RegisterDeviceNotification stuff */ +typedef PVOID HDEVNOTIFY; +typedef HDEVNOTIFY *PHDEVNOTIFY; + +#define DEVICE_NOTIFY_WINDOW_HANDLE 0x00000000 + +/* used for GetWindowInfo() */ + +#define WS_ACTIVECAPTION 0x0001 + +/* SetWinEventHook() flags */ +#define WINEVENT_OUTOFCONTEXT 0x0 +#define WINEVENT_SKIPOWNTHREAD 0x1 +#define WINEVENT_SKIPOWNPROCESS 0x2 +#define WINEVENT_INCONTEXT 0x4 + +#define ENDSESSION_LOGOFF 0x80000000 + +/* Object Id's */ +#define CHILDID_SELF 0 +#define INDEXID_OBJECT 0 +#define INDEXID_CONTAINER 0 + +/* System object Id's */ +#define OBJID_WINDOW 0 +#define OBJID_SYSMENU -1 +#define OBJID_TITLEBAR -2 +#define OBJID_MENU -3 +#define OBJID_CLIENT -4 +#define OBJID_VSCROLL -5 +#define OBJID_HSCROLL -6 +#define OBJID_SIZEGRIP -7 +#define OBJID_CARET -8 +#define OBJID_CURSOR -9 +#define OBJID_ALERT -10 +#define OBJID_SOUND -11 +#define OBJID_QUERYCLASSNAMEIDX -12 +#define OBJID_NATIVEOM -16 + +/* User event Id limits */ +#define EVENT_MIN 0x00000001 +#define EVENT_MAX 0x7FFFFFFF + +/* System events */ +#define EVENT_SYSTEM_SOUND 0x01 +#define EVENT_SYSTEM_ALERT 0x02 +#define EVENT_SYSTEM_FOREGROUND 0x03 +#define EVENT_SYSTEM_MENUSTART 0x04 +#define EVENT_SYSTEM_MENUEND 0x05 +#define EVENT_SYSTEM_MENUPOPUPSTART 0x06 +#define EVENT_SYSTEM_MENUPOPUPEND 0x07 +#define EVENT_SYSTEM_CAPTURESTART 0x08 +#define EVENT_SYSTEM_CAPTUREEND 0x09 +#define EVENT_SYSTEM_MOVESIZESTART 0x0A +#define EVENT_SYSTEM_MOVESIZEEND 0x0B +#define EVENT_SYSTEM_CONTEXTHELPSTART 0x0C +#define EVENT_SYSTEM_CONTEXTHELPEND 0x0D +#define EVENT_SYSTEM_DRAGDROPSTART 0x0E +#define EVENT_SYSTEM_DRAGDROPEND 0x0F +#define EVENT_SYSTEM_DIALOGSTART 0x10 +#define EVENT_SYSTEM_DIALOGEND 0x11 +#define EVENT_SYSTEM_SCROLLINGSTART 0x12 +#define EVENT_SYSTEM_SCROLLINGEND 0x13 +#define EVENT_SYSTEM_SWITCHSTART 0x14 +#define EVENT_SYSTEM_SWITCHEND 0x15 +#define EVENT_SYSTEM_MINIMIZESTART 0x16 +#define EVENT_SYSTEM_MINIMIZEEND 0x17 + +/* Console events */ +#define EVENT_CONSOLE_CARET 0x4001 +#define EVENT_CONSOLE_UPDATE_REGION 0x4002 +#define EVENT_CONSOLE_UPDATE_SIMPLE 0x4003 +#define EVENT_CONSOLE_UPDATE_SCROLL 0x4004 +#define EVENT_CONSOLE_LAYOUT 0x4005 +#define EVENT_CONSOLE_START_APPLICATION 0x4006 +#define EVENT_CONSOLE_END_APPLICATION 0x4007 + +#define CONSOLE_APPLICATION_16BIT 0x1 +#define CONSOLE_CARET_SELECTION 0x1 +#define CONSOLE_CARET_VISIBLE 0x2 + +/* Object events */ +#define EVENT_OBJECT_CREATE 0x8000 +#define EVENT_OBJECT_DESTROY 0x8001 +#define EVENT_OBJECT_SHOW 0x8002 +#define EVENT_OBJECT_HIDE 0x8003 +#define EVENT_OBJECT_REORDER 0x8004 +#define EVENT_OBJECT_FOCUS 0x8005 +#define EVENT_OBJECT_SELECTION 0x8006 +#define EVENT_OBJECT_SELECTIONADD 0x8007 +#define EVENT_OBJECT_SELECTIONREMOVE 0x8008 +#define EVENT_OBJECT_SELECTIONWITHIN 0x8009 +#define EVENT_OBJECT_STATECHANGE 0x800A +#define EVENT_OBJECT_LOCATIONCHANGE 0x800B +#define EVENT_OBJECT_NAMECHANGE 0x800C +#define EVENT_OBJECT_DESCRIPTIONCHANGE 0x800D +#define EVENT_OBJECT_VALUECHANGE 0x800E +#define EVENT_OBJECT_PARENTCHANGE 0x800F +#define EVENT_OBJECT_HELPCHANGE 0x8010 +#define EVENT_OBJECT_DEFACTIONCHANGE 0x8011 +#define EVENT_OBJECT_ACCELERATORCHANGE 0x8012 + +/* Sound events */ +#define SOUND_SYSTEM_STARTUP 1 +#define SOUND_SYSTEM_SHUTDOWN 2 +#define SOUND_SYSTEM_BEEP 3 +#define SOUND_SYSTEM_ERROR 4 +#define SOUND_SYSTEM_QUESTION 5 +#define SOUND_SYSTEM_WARNING 6 +#define SOUND_SYSTEM_INFORMATION 7 +#define SOUND_SYSTEM_MAXIMIZE 8 +#define SOUND_SYSTEM_MINIMIZE 9 +#define SOUND_SYSTEM_RESTOREUP 10 +#define SOUND_SYSTEM_RESTOREDOWN 11 +#define SOUND_SYSTEM_APPSTART 12 +#define SOUND_SYSTEM_FAULT 13 +#define SOUND_SYSTEM_APPEND 14 +#define SOUND_SYSTEM_MENUCOMMAND 15 +#define SOUND_SYSTEM_MENUPOPUP 16 +#define CSOUND_SYSTEM 16 + +/* Alert events */ +#define ALERT_SYSTEM_INFORMATIONAL 1 +#define ALERT_SYSTEM_WARNING 2 +#define ALERT_SYSTEM_ERROR 3 +#define ALERT_SYSTEM_QUERY 4 +#define ALERT_SYSTEM_CRITICAL 5 +#define CALERT_SYSTEM 6 + +/* System state flags */ +#define STATE_SYSTEM_UNAVAILABLE 0x00000001 +#define STATE_SYSTEM_SELECTED 0x00000002 +#define STATE_SYSTEM_FOCUSED 0x00000004 +#define STATE_SYSTEM_PRESSED 0x00000008 +#define STATE_SYSTEM_CHECKED 0x00000010 +#define STATE_SYSTEM_MIXED 0x00000020 +#define STATE_SYSTEM_INDETERMINATE STATE_SYSTEM_MIXED +#define STATE_SYSTEM_READONLY 0x00000040 +#define STATE_SYSTEM_HOTTRACKED 0x00000080 +#define STATE_SYSTEM_DEFAULT 0x00000100 +#define STATE_SYSTEM_EXPANDED 0x00000200 +#define STATE_SYSTEM_COLLAPSED 0x00000400 +#define STATE_SYSTEM_BUSY 0x00000800 +#define STATE_SYSTEM_FLOATING 0x00001000 +#define STATE_SYSTEM_MARQUEED 0x00002000 +#define STATE_SYSTEM_ANIMATED 0x00004000 +#define STATE_SYSTEM_INVISIBLE 0x00008000 +#define STATE_SYSTEM_OFFSCREEN 0x00010000 +#define STATE_SYSTEM_SIZEABLE 0x00020000 +#define STATE_SYSTEM_MOVEABLE 0x00040000 +#define STATE_SYSTEM_SELFVOICING 0x00080000 +#define STATE_SYSTEM_FOCUSABLE 0x00100000 +#define STATE_SYSTEM_SELECTABLE 0x00200000 +#define STATE_SYSTEM_LINKED 0x00400000 +#define STATE_SYSTEM_TRAVERSED 0x00800000 +#define STATE_SYSTEM_MULTISELECTABLE 0x01000000 +#define STATE_SYSTEM_EXTSELECTABLE 0x02000000 +#define STATE_SYSTEM_ALERT_LOW 0x04000000 +#define STATE_SYSTEM_ALERT_MEDIUM 0x08000000 +#define STATE_SYSTEM_ALERT_HIGH 0x10000000 +#define STATE_SYSTEM_PROTECTED 0x20000000 +#define STATE_SYSTEM_VALID 0x3FFFFFFF + +/* Lock codes for LockSetForegroundWindow */ +#define LSFW_LOCK 1 +#define LSFW_UNLOCK 2 + +/* Values for AllowSetForegroundWindow */ +#define ASFW_ANY ((DWORD)-1) + +#define EnumTaskWindows(handle,proc,lparam) \ + EnumThreadWindows(handle,proc,lparam) +#define OemToAnsiA OemToCharA +#define OemToAnsiW OemToCharW +#define OemToAnsi WINELIB_NAME_AW(OemToAnsi) +#define OemToAnsiBuffA OemToCharBuffA +#define OemToAnsiBuffW OemToCharBuffW +#define OemToAnsiBuff WINELIB_NAME_AW(OemToAnsiBuff) +#define AnsiToOemA CharToOemA +#define AnsiToOemW CharToOemW +#define AnsiToOem WINELIB_NAME_AW(AnsiToOem) +#define AnsiToOemBuffA CharToOemBuffA +#define AnsiToOemBuffW CharToOemBuffW +#define AnsiToOemBuff WINELIB_NAME_AW(AnsiToOemBuff) + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WINUSER_H */ diff --git a/unifiedkernel/include/wtypes.h b/unifiedkernel/include/wtypes.h new file mode 100644 index 0000000..304b2de --- /dev/null +++ b/unifiedkernel/include/wtypes.h @@ -0,0 +1,543 @@ +/* + * wtype.h + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/*** Autogenerated by WIDL 1.0-uk from wtypes.idl - Do not edit ***/ + +#ifndef _WTYPES_H +#define _WTYPES_H + +#ifdef CONFIG_UNIFIED_KERNEL +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +typedef double DOUBLE; +#else +typedef double DOUBLE; +#endif +#ifndef _PALETTEENTRY_DEFINED +#define _PALETTEENTRY_DEFINED +typedef struct tagPALETTEENTRY { + BYTE peRed; + BYTE peGreen; + BYTE peBlue; + BYTE peFlags; +} PALETTEENTRY; +typedef struct tagPALETTEENTRY *PPALETTEENTRY; +typedef struct tagPALETTEENTRY *LPPALETTEENTRY; +#endif +#ifndef _LOGPALETTE_DEFINED +#define _LOGPALETTE_DEFINED +typedef struct tagLOGPALETTE { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[1]; +} LOGPALETTE; +typedef struct tagLOGPALETTE *PLOGPALETTE; +typedef struct tagLOGPALETTE *LPLOGPALETTE; +#endif +#ifndef _FILETIME_ +#define _FILETIME_ +typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME; +typedef struct _FILETIME *PFILETIME; +typedef struct _FILETIME *LPFILETIME; +#endif +#ifndef _TEXTMETRIC_DEFINED +#define _TEXTMETRIC_DEFINED +typedef struct tagTEXTMETRICA { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + BYTE tmFirstChar; + BYTE tmLastChar; + BYTE tmDefaultChar; + BYTE tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; +} TEXTMETRICA; +typedef struct tagTEXTMETRICA *LPTEXTMETRICA; +typedef struct tagTEXTMETRICA *PTEXTMETRICA; +typedef struct tagTEXTMETRICW { + LONG tmHeight; + LONG tmAscent; + LONG tmDescent; + LONG tmInternalLeading; + LONG tmExternalLeading; + LONG tmAveCharWidth; + LONG tmMaxCharWidth; + LONG tmWeight; + LONG tmOverhang; + LONG tmDigitizedAspectX; + LONG tmDigitizedAspectY; + WCHAR tmFirstChar; + WCHAR tmLastChar; + WCHAR tmDefaultChar; + WCHAR tmBreakChar; + BYTE tmItalic; + BYTE tmUnderlined; + BYTE tmStruckOut; + BYTE tmPitchAndFamily; + BYTE tmCharSet; +} TEXTMETRICW; +typedef struct tagTEXTMETRICW *LPTEXTMETRICW; +typedef struct tagTEXTMETRICW *PTEXTMETRICW; +#endif +typedef WCHAR OLECHAR; +typedef OLECHAR *LPOLESTR; +typedef const OLECHAR *LPCOLESTR; +#ifndef __WINESRC__ +#define OLESTR(str) L##str +#endif +typedef LONG SCODE; +typedef struct _COAUTHIDENTITY { + USHORT *User; + ULONG UserLength; + USHORT *Domain; + ULONG DomainLength; + USHORT *Password; + ULONG PasswordLength; + ULONG Flags; +} COAUTHIDENTITY; +typedef struct _COAUTHINFO { + DWORD dwAuthnSvc; + DWORD dwAuthzSvc; + LPWSTR pwszServerPrincName; + DWORD dwAuthnLevel; + DWORD dwImpersonationLevel; + COAUTHIDENTITY *pAuthIdentityData; + DWORD dwCapabilities; +} COAUTHINFO; +typedef enum tagMEMCTX { + MEMCTX_TASK = 1, + MEMCTX_SHARED = 2, + MEMCTX_MACSYSTEM = 3, + MEMCTX_UNKNOWN = -1, + MEMCTX_SAME = -2 +} MEMCTX; +#ifndef _ROT_COMPARE_MAX_DEFINED +#define _ROT_COMPARE_MAX_DEFINED +#define ROT_COMPARE_MAX 2048 +#endif +#ifndef _ROTFLAGS_DEFINED +#define _ROTFLAGS_DEFINED +#define ROTFLAGS_REGISTRATIONKEEPSALIVE 0x1 +#define ROTFLAGS_ALLOWANYCLIENT 0x2 +#endif +typedef enum tagCLSCTX { + CLSCTX_INPROC_SERVER = 0x1, + CLSCTX_INPROC_HANDLER = 0x2, + CLSCTX_LOCAL_SERVER = 0x4, + CLSCTX_INPROC_SERVER16 = 0x8, + CLSCTX_REMOTE_SERVER = 0x10, + CLSCTX_INPROC_HANDLER16 = 0x20, + CLSCTX_INPROC_SERVERX86 = 0x40, + CLSCTX_INPROC_HANDLERX86 = 0x80, + CLSCTX_ESERVER_HANDLER = 0x100, + CLSCTX_NO_CODE_DOWNLOAD = 0x400, + CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, + CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, + CLSCTX_NO_FAILURE_LOG = 0x4000, + CLSCTX_DISABLE_AAA = 0x8000, + CLSCTX_ENABLE_AAA = 0x10000, + CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000 +} CLSCTX; +#define CLSCTX_INPROC (CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) +#define CLSCTX_ALL (CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER) +#define CLSCTX_SERVER (CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER) +typedef enum tagMSHLFLAGS { + MSHLFLAGS_NORMAL = 0, + MSHLFLAGS_TABLESTRONG = 1, + MSHLFLAGS_TABLEWEAK = 2, + MSHLFLAGS_NOPING = 4 +} MSHLFLAGS; +typedef enum tagMSHCTX { + MSHCTX_LOCAL = 0, + MSHCTX_NOSHAREDMEM = 1, + MSHCTX_DIFFERENTMACHINE = 2, + MSHCTX_INPROC = 3, + MSHCTX_CROSSCTX = 4 +} MSHCTX; + +typedef unsigned char byte; + +typedef struct _BYTE_BLOB { + unsigned long clSize; + byte abData[1]; +} BYTE_BLOB; +typedef BYTE_BLOB *UP_BYTE_BLOB; +typedef struct _FLAGGED_BYTE_BLOB { + unsigned long fFlags; + unsigned long clSize; + byte abData[1]; +} FLAGGED_BYTE_BLOB; +typedef FLAGGED_BYTE_BLOB *UP_FLAGGED_BYTE_BLOB; +typedef struct _FLAGGED_WORD_BLOB { + unsigned long fFlags; + unsigned long clSize; + unsigned short asData[1]; +} FLAGGED_WORD_BLOB; +typedef FLAGGED_WORD_BLOB *UP_FLAGGED_WORD_BLOB; +typedef struct _BYTE_SIZEDARR { + unsigned long clSize; + byte *pData; +} BYTE_SIZEDARR; +typedef struct _SHORT_SIZEDARR { + unsigned long clSize; + unsigned short *pData; +} WORD_SIZEDARR; +typedef struct _LONG_SIZEDARR { + unsigned long clSize; + unsigned long *pData; +} DWORD_SIZEDARR; +typedef struct _userCLIPFORMAT { + long fContext; + union { + DWORD dwValue; + LPWSTR pwszName; + } u; +} userCLIPFORMAT; +typedef userCLIPFORMAT *wireCLIPFORMAT; +typedef WORD CLIPFORMAT; +typedef struct tagRemHGLOBAL { + long fNullHGlobal; + unsigned long cbData; + byte data[1]; +} RemHGLOBAL; +typedef struct _userHGLOBAL { + long fContext; + union { + long hInproc; + FLAGGED_BYTE_BLOB *hRemote; + long hGlobal; + } u; +} userHGLOBAL; +typedef userHGLOBAL *wireHGLOBAL; +typedef struct tagRemHMETAFILEPICT { + long mm; + long xExt; + long yExt; + unsigned long cbData; + byte data[1]; +} RemHMETAFILEPICT; +typedef struct _userHMETAFILE { + long fContext; + union { + long hInproc; + BYTE_BLOB *hRemote; + long hGlobal; + } u; +} userHMETAFILE; +typedef userHMETAFILE *wireHMETAFILE; +typedef struct _remoteMETAFILEPICT { + long mm; + long xExt; + long yExt; + userHMETAFILE *hMF; +} remoteMETAFILEPICT; +typedef struct _userHMETAFILEPICT { + long fContext; + union { + long hInproc; + remoteMETAFILEPICT *hRemote; + long hGlobal; + } u; +} userHMETAFILEPICT; +typedef userHMETAFILEPICT *wireHMETAFILEPICT; +typedef struct tagRemHENHMETAFILE { + unsigned long cbData; + byte data[1]; +} RemHENHMETAFILE; +typedef struct _userHENHMETAFILE { + long fContext; + union { + long hInproc; + BYTE_BLOB *hRemote; + long hGlobal; + } u; +} userHENHMETAFILE; +typedef userHENHMETAFILE *wireHENHMETAFILE; +typedef struct tagRemHBITMAP { + unsigned long cbData; + byte data[1]; +} RemHBITMAP; +typedef struct _userBITMAP { + LONG bmType; + LONG bmWidth; + LONG bmHeight; + LONG bmWidthBytes; + WORD bmPlanes; + WORD bmBitsPixel; + ULONG cbSize; + byte pBuffer[1]; +} userBITMAP; +typedef struct _userHBITMAP { + long fContext; + union { + long hInproc; + userBITMAP *hRemote; + long hGlobal; + } u; +} userHBITMAP; +typedef userHBITMAP *wireHBITMAP; +typedef struct tagRemHPALETTE { + unsigned long cbData; + byte data[1]; +} RemHPALETTE; +typedef struct tagrpcLOGPALETTE { + WORD palVersion; + WORD palNumEntries; + PALETTEENTRY palPalEntry[1]; +} rpcLOGPALETTE; +typedef struct _userHPALETTE { + long fContext; + union { + long hInproc; + rpcLOGPALETTE *hRemote; + long hGlobal; + } u; +} userHPALETTE; +typedef userHPALETTE *wireHPALETTE; +typedef void *HMETAFILEPICT; +typedef struct _RemotableHandle { + long fContext; + union { + long hInproc; + long hRemote; + } u; +} RemotableHandle; +typedef RemotableHandle *wireHACCEL; +typedef RemotableHandle *wireHBRUSH; +typedef RemotableHandle *wireHDC; +typedef RemotableHandle *wireHFONT; +typedef RemotableHandle *wireHICON; +typedef RemotableHandle *wireHMENU; +typedef RemotableHandle *wireHWND; +typedef enum tagDVASPECT { + DVASPECT_CONTENT = 1, + DVASPECT_THUMBNAIL = 2, + DVASPECT_ICON = 4, + DVASPECT_DOCPRINT = 8 +} DVASPECT; +typedef enum tagSTGC { + STGC_DEFAULT = 0, + STGC_OVERWRITE = 1, + STGC_ONLYIFCURRENT = 2, + STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4, + STGC_CONSOLIDATE = 8 +} STGC; +typedef enum tagSTGMOVE { + STGMOVE_MOVE = 0, + STGMOVE_COPY = 1, + STGMOVE_SHALLOWCOPY = 2 +} STGMOVE; +typedef enum tagSTATFLAG { + STATFLAG_DEFAULT = 0, + STATFLAG_NONAME = 1, + STATFLAG_NOOPEN = 2 +} STATFLAG; +#ifdef _MSC_VER +typedef double DATE; +#else +typedef double DATE; +#endif +#ifndef _tagCY_DEFINED +#define _tagCY_DEFINED +typedef union tagCY { + struct { +#ifdef WORDS_BIGENDIAN + LONG Hi; + ULONG Lo; +#else + ULONG Lo; + LONG Hi; +#endif + } DUMMYSTRUCTNAME; + LONGLONG int64; +} CY; +#endif +typedef CY *LPCY; +typedef struct tagDEC { + USHORT wReserved; + union { + struct { + BYTE scale; + BYTE sign; + } DUMMYSTRUCTNAME; + USHORT signscale; + } DUMMYUNIONNAME; + ULONG Hi32; + union { + struct { +#ifdef WORDS_BIGENDIAN + ULONG Mid32; + ULONG Lo32; +#else + ULONG Lo32; + ULONG Mid32; +#endif + } DUMMYSTRUCTNAME1; + ULONGLONG Lo64; + } DUMMYUNIONNAME1; +} DECIMAL; +#define DECIMAL_NEG ((BYTE)0x80) +#define DECIMAL_SETZERO(d) do{ memset(((char*)&(d)) + sizeof(USHORT), 0, sizeof(ULONG) * 3u + sizeof(USHORT)); }while (0) +typedef DECIMAL *LPDECIMAL; +typedef FLAGGED_WORD_BLOB *wireBSTR; +typedef OLECHAR *BSTR; +typedef BSTR *LPBSTR; +typedef short VARIANT_BOOL; +typedef VARIANT_BOOL _VARIANT_BOOL; +#define VARIANT_TRUE ((VARIANT_BOOL)0xFFFF) +#define VARIANT_FALSE ((VARIANT_BOOL)0x0000) +typedef struct tagBSTRBLOB { + ULONG cbSize; + BYTE *pData; +} BSTRBLOB; +typedef struct tagBSTRBLOB *LPBSTRBLOB; +#ifndef _tagBLOB_DEFINED +#define _tagBLOB_DEFINED +#define _BLOB_DEFINED +#define _LPBLOB_DEFINED +typedef struct tagBLOB { + ULONG cbSize; + BYTE *pBlobData; +} BLOB; +typedef struct tagBLOB *LPBLOB; +#endif +typedef struct tagCLIPDATA { + ULONG cbSize; + long ulClipFmt; + BYTE *pClipData; +} CLIPDATA; +#define CBPCLIPDATA(cb) ((cb).cbSize - sizeof((cb).ulClipFmt)) +typedef ULONG PROPID; +typedef unsigned short VARTYPE; +enum VARENUM { + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_PTR = 26, + VT_SAFEARRAY = 27, + VT_CARRAY = 28, + VT_USERDEFINED = 29, + VT_LPSTR = 30, + VT_LPWSTR = 31, + VT_RECORD = 36, + VT_INT_PTR = 37, + VT_UINT_PTR = 38, + VT_FILETIME = 64, + VT_BLOB = 65, + VT_STREAM = 66, + VT_STORAGE = 67, + VT_STREAMED_OBJECT = 68, + VT_STORED_OBJECT = 69, + VT_BLOB_OBJECT = 70, + VT_CF = 71, + VT_CLSID = 72, + VT_VERSIONED_STREAM = 73, + VT_BSTR_BLOB = 0xfff, + VT_VECTOR = 0x1000, + VT_ARRAY = 0x2000, + VT_BYREF = 0x4000, + VT_RESERVED = 0x8000, + VT_ILLEGAL = 0xffff, + VT_ILLEGALMASKED = 0xfff, + VT_TYPEMASK = 0xfff +}; + +typedef struct tagCSPLATFORM { + DWORD dwPlatformId; + DWORD dwVersionHi; + DWORD dwVersionLo; + DWORD dwProcessorArch; +} CSPLATFORM; +typedef struct tagQUERYCONTEXT { + DWORD dwContext; + CSPLATFORM Platform; + LCID Locale; + DWORD dwVersionHi; + DWORD dwVersionLo; +} QUERYCONTEXT; +typedef enum tagTYSPEC { + TYSPEC_CLSID = 0, + TYSPEC_FILEEXT = 1, + TYSPEC_MIMETYPE = 2, + TYSPEC_PROGID = 3, + TYSPEC_FILENAME = 4, + TYSPEC_PACKAGENAME = 5, + TYSPEC_OBJECTID = 6 +} TYSPEC; +/***************************************************************************** + * IWinTypes interface (v0.1) + */ +#ifndef __IWinTypes_INTERFACE_DEFINED__ +#define __IWinTypes_INTERFACE_DEFINED__ +#endif /* __IWinTypes_INTERFACE_DEFINED__ */ + +/* Begin additional prototypes for all interfaces */ + + +/* End additional prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_UNIFIED_KERNEL */ +#endif /* _WTYPES_H */ diff --git a/unifiedkernel/io/Makefile b/unifiedkernel/io/Makefile new file mode 100644 index 0000000..3554beb --- /dev/null +++ b/unifiedkernel/io/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for io operations +# + +IO_OBJS += io.o \ + file.o \ + dosdriver.o \ + symlink.o + +$(MODULE)-objs += $(addprefix io/, $(IO_OBJS)) diff --git a/unifiedkernel/io/dosdriver.c b/unifiedkernel/io/dosdriver.c new file mode 100644 index 0000000..ba17698 --- /dev/null +++ b/unifiedkernel/io/dosdriver.c @@ -0,0 +1,117 @@ +/* + * dosdriver.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * dosdriver.c: DOS driver operation for /proc + */ +#include +#include +#include "object.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define MAX_DOSDRIVERS 26 + +char *dosdriver_symlink[MAX_DOSDRIVERS]; +EXPORT_SYMBOL(dosdriver_symlink); + +extern void create_dosdriver_symlink(int index, char *target_str); +extern void display_object_dir(POBJECT_DIRECTORY DirectoryObject, LONG Depth); + +/* add it in proc.c */ +void free_dosdriver(void) +{ + int i; + + for (i = 0; i < MAX_DOSDRIVERS; i++) + if (dosdriver_symlink[i]) + kfree(dosdriver_symlink[i]); +} +EXPORT_SYMBOL(free_dosdriver); + +size_t print_dosdriver(char *buf) +{ + int i; + size_t ret = 0; + + for (i = 0; i < MAX_DOSDRIVERS; i++) + ret += sprintf(buf + ret, "%c: %s\n", i + 'A', dosdriver_symlink[i]); + + return ret; +} +EXPORT_SYMBOL(print_dosdriver); + +int parse_dosdriver(char *buf, size_t count, int append) +{ + int index, len; + char *p, *head; + char new[MAX_DOSDRIVERS]; + + memset(new, 0, sizeof(new)); + if (!append) + memset(dosdriver_symlink, 0, sizeof(dosdriver_symlink)); + + if (count == PAGE_SIZE) + buf[PAGE_SIZE - 1] = '\0'; + else + buf[count++] = '\0'; + + head = buf; + while (head < buf + count) { + while (*head == ' ' || *head == '\t' || *head == '\r' || *head == '\n') + head++; + if (((*head >= 'A' && *head <= 'Z') || (*head >= 'a' && *head <= 'z')) + && *(head + 1) == ':' && *(head + 2) == ' ') { + index = *head - ((*head <= 'Z') ? 'A' : 'a'); + head += 3; + while (*head == ' ' || *head == '\t') + head++; + p = head; + while (*p != '\n' && *p) + p++; + len = p - head - (*(p - 1) == '\r' ? 1 : 0); + if (dosdriver_symlink[index]) + kfree(dosdriver_symlink[index]); + dosdriver_symlink[index] = (char *)kmalloc(len + 1, GFP_KERNEL); + memcpy(dosdriver_symlink[index], head, len); + dosdriver_symlink[index][len++] = '\0'; + new[index] = 1; + head = p + 1; + } + else { + p = strchr(head, '\n'); + if (!p) + break; + head = p + 1; + } + } + + for (index = 0; index < MAX_DOSDRIVERS; index++) { + if ((p = dosdriver_symlink[index]) && new[index]) + create_dosdriver_symlink(index, p); + } + + display_object_dir(NULL, 1); + return count; +} +EXPORT_SYMBOL(parse_dosdriver); +#endif diff --git a/unifiedkernel/io/file.c b/unifiedkernel/io/file.c new file mode 100644 index 0000000..4085d5f --- /dev/null +++ b/unifiedkernel/io/file.c @@ -0,0 +1,755 @@ +/* + * file.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * file.c: file syscall functions + * Refered to Kernel-win32 code + */ +#include +#include "file.h" +#include "objwait.h" +#include "process.h" +#include "thread.h" +#include +#include +#include +#include +#include "object.h" +#include "unistr.h" + + +#ifdef CONFIG_UNIFIED_KERNEL + +POBJECT_TYPE file_object_type = NULL; +EXPORT_SYMBOL(file_object_type); +POBJECT_TYPE file_ctrl_object_type = NULL; +EXPORT_SYMBOL(file_ctrl_object_type); +POBJECT_DIRECTORY file_ctrl_root = NULL; +EXPORT_SYMBOL(file_ctrl_root); +HANDLE file_ctrl_root_handle = NULL; +EXPORT_SYMBOL(file_ctrl_root_handle); + +static int file_check_sharing(struct win32_file *, struct win32_file_ctrl *); + +extern int unistr2charstr(PWSTR unistr, LPCSTR chstr); +extern NTSTATUS translate_object_name(PUNICODE_STRING ObjectName); + +/* + * open a file object, maybe creating if non-existent + */ +NTSTATUS +SERVICECALL +NtCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength + ) +{ + HANDLE hFile; + int flags; + char *filename; + NTSTATUS ret = STATUS_SUCCESS; + struct win32_file *Object; + struct win32_file_ctrl *ControlObject, *TempObject = NULL; + struct ethread *thread; + POBJECT_ATTRIBUTES obj_attr = NULL; + IO_STATUS_BLOCK io_status; + LARGE_INTEGER alloc_size; + OBJECT_ATTRIBUTES ControlObjectAttributes; + MODE previous_mode; + int fd; + struct file *f; + + /* FIXME */ + previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; + + ktrace("NtCreateFile\n"); + thread = get_current_ethread(); + if (!thread) + return STATUS_UNSUCCESSFUL; + + if (!ObjectAttributes) + return STATUS_INVALID_PARAMETER; + + if (!IoStatusBlock) + return STATUS_INVALID_PARAMETER; + + memset(&ControlObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES)); + if (previous_mode == UserMode) { + /* copy Object Attributes from user space */ + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) { + return STATUS_NO_MEMORY; + } + ObjectAttributes = obj_attr; + + if (copy_from_user(&io_status, IoStatusBlock, sizeof(io_status))) + goto cleanup_object_attr; + IoStatusBlock = &io_status; + + if (AllocationSize) { + if (copy_from_user(&alloc_size, AllocationSize, sizeof(alloc_size))) + goto cleanup_object_attr; + AllocationSize = &alloc_size; + } + } + + ret = translate_object_name(ObjectAttributes->ObjectName); + if (!NT_SUCCESS(ret)) + goto cleanup_object_attr; + + memcpy(&ControlObjectAttributes, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)); + ControlObjectAttributes.RootDirectory = file_ctrl_root_handle; + + /* create and insert FileControl Object */ + ret = create_object(KernelMode, + file_ctrl_object_type, + &ControlObjectAttributes, + KernelMode, + NULL, + sizeof(struct win32_file_ctrl), + 0, + 0, + (PVOID *)&ControlObject); + if (!NT_SUCCESS(ret)) + goto cleanup_object_attr; + + INIT_LIST_HEAD(&ControlObject->wfc_accessors); + spin_lock_init(&ControlObject->wfc_lock); + + ret = insert_object(ControlObject, + NULL, + STANDARD_RIGHTS_REQUIRED, + 0, + (PVOID *)&TempObject, + NULL); + if (ret == STATUS_OBJECT_NAME_EXISTS) { + deref_object(ControlObject); + ControlObject = TempObject; + } + + /* create and insert File Object */ + ObjectAttributes->ObjectName = NULL; + ret = create_object(KernelMode, + file_object_type, + ObjectAttributes, + KernelMode, + NULL, + sizeof(struct win32_file), + 0, + 0, + (PVOID *)&Object); + if (!NT_SUCCESS(ret)) + goto cleanup_ctrl_obj; + + ret = insert_object(Object, + NULL, + STANDARD_RIGHTS_REQUIRED, + 0, + NULL, + &hFile); + deref_object(Object); + if (!NT_SUCCESS(ret)) + goto cleanup_ctrl_obj; + + Object->wf_access = DesiredAccess; + Object->wf_sharing = ShareAccess; + Object->wf_attrs = FileAttributes; + Object->wf_control = ControlObject; + ref_object(ControlObject); + + spin_lock(&ControlObject->wfc_lock); + + /* check that we can share access */ + ret = file_check_sharing(Object, ControlObject); + if (ret < 0) + goto cleanup_ctrl_lock; + + /* determine Linux file open parameters */ + switch (CreateDisposition) { + case FILE_CREATE: + flags = O_CREAT | O_EXCL; + break; + case FILE_OVERWRITE_IF: + flags = O_CREAT | O_TRUNC; + break; + case FILE_OPEN_IF: + flags = O_CREAT; + break; + case FILE_OVERWRITE: + flags = O_TRUNC; + break; + case FILE_OPEN: + flags = 0; + break; + default: + ret = STATUS_INVALID_PARAMETER; + goto cleanup_ctrl_lock; + } + + switch (DesiredAccess & (GENERIC_READ | GENERIC_WRITE)) { + case GENERIC_READ: + flags |= O_RDONLY; + break; + case GENERIC_WRITE: + flags |= O_WRONLY; + break; + case GENERIC_READ | GENERIC_WRITE: + flags |= O_RDWR; + break; + default: + break; + } + + /* open the Linux file */ + filename = (char *)kmalloc(ControlObjectAttributes.ObjectName->MaximumLength, GFP_KERNEL); + ret = STATUS_NO_MEMORY; + if (!filename) + goto cleanup_ctrl_lock; + + unistr2charstr((PWSTR)ControlObjectAttributes.ObjectName->Buffer, (LPCSTR)filename); + + fd = get_unused_fd(); + if (fd >= 0) { + f = filp_open(filename, flags, (FileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666); + if (IS_ERR(f)) { + put_unused_fd(fd); + Object->wf_control = NULL; + /* fd = PTR_ERR(f); */ + goto cleanup_filename; + } else { + /* fsnotify_open(f->f_dentry); */ + fd_install(fd, f); + } + } + else goto cleanup_filename; + + Object->wf_fd = fd; + Object->wf_file = NULL; + + + Object->wf_file = filp_open(filename, flags, + (FileAttributes & FILE_ATTRIBUTE_READONLY) ? 0444 : 0666); + if (IS_ERR(Object->wf_file)) { + ret = PTR_ERR(Object->wf_file); + Object->wf_file = NULL; + Object->wf_control = NULL; + goto cleanup_filename; + } + + /* don't permit a directory to be opened */ + if (S_ISDIR (f->f_dentry->d_inode->i_mode)) { + ret = STATUS_FILE_IS_A_DIRECTORY; + goto cleanup_file; + } + + list_add(&Object->wf_ctllist, &ControlObject->wfc_accessors); + spin_unlock(&ControlObject->wfc_lock); + + ret = STATUS_NO_MEMORY; + if (copy_to_user(FileHandle, &hFile, sizeof(HANDLE))) + goto cleanup_file; + + ret = STATUS_SUCCESS; + + kfree(filename); + goto cleanup_ctrl_obj; + + /* clean up on error */ +cleanup_file: + fput(Object->wf_file); + +cleanup_filename: + kfree(filename); + +cleanup_ctrl_lock: + spin_unlock(&ControlObject->wfc_lock); + NtClose(hFile); + +cleanup_ctrl_obj: + deref_object(ControlObject); + +cleanup_object_attr: + if (obj_attr) { + if (ControlObjectAttributes.ObjectName && ControlObjectAttributes.ObjectName->Buffer) + kfree(ControlObjectAttributes.ObjectName->Buffer); + kfree(obj_attr); + } + + return ret; +} /* end NtCreateFile() */ +EXPORT_SYMBOL(NtCreateFile); + +/* + * open a file object, failing if non-existent + * TODO: not implemented, used NtCreateFile instead + */ +NTSTATUS +SERVICECALL +NtOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions + ) +{ + return NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, + IoStatusBlock, NULL, 0, ShareAccess, FILE_OPEN, OpenOptions, NULL, 0); +} /* end NtOpenFile() */ +EXPORT_SYMBOL(NtOpenFile); + +/* + * read from a file + */ +NTSTATUS +SERVICECALL +NtReadFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */ + IN PULONG Key OPTIONAL + ) +{ + struct win32_file *wf; + struct file *file; + loff_t pos; + struct ethread *thread; + IO_STATUS_BLOCK io_status; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + ktrace("NtReadFile(%p)\n", FileHandle); + + thread = get_current_ethread(); + if (!thread) + goto cleanup_nobj; + + if (!IoStatusBlock) + return STATUS_INVALID_PARAMETER; + + status = ref_object_by_handle(FileHandle, + STANDARD_RIGHTS_REQUIRED, + NULL, + KernelMode, + (PVOID *)&wf, + NULL); + if (!NT_SUCCESS(status)) + return status; + + file = wf->wf_file; + + /* check the file can actually be read */ + if (!(wf->wf_access & GENERIC_READ)) + goto cleanup; + + status = STATUS_ACCESS_VIOLATION; + if (!(file->f_mode & FMODE_READ)) + goto cleanup; + + /* read from file */ + pos = file->f_pos; + if ((unsigned long)Buffer < TASK_SIZE) { /* FIXME */ + status = vfs_read(file, Buffer, Length, &pos); + file->f_pos = pos; + } + else + status = kernel_read(file, pos, Buffer, Length); + if (status >= 0) { + /* write _ReadBytes_ to user space */ + io_status.Information = (ULONG_PTR)status; + if ((unsigned long)Buffer < TASK_SIZE) /* FIXME */ + status = copy_to_user(IoStatusBlock, &io_status, sizeof(io_status)) + ? STATUS_NO_MEMORY: STATUS_SUCCESS; + } + +cleanup: + deref_object((PVOID)wf); + +cleanup_nobj: + ktrace("*** NtReadFile = %d\n", status); + return status; +} /* end NtReadFile() */ +EXPORT_SYMBOL(NtReadFile); + +/* + * write to a file + */ +NTSTATUS +SERVICECALL +NtWriteFile ( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */ + IN PULONG Key OPTIONAL + ) +{ + struct file *file; + struct win32_file *wf; + struct ethread *thread; + loff_t pos; + IO_STATUS_BLOCK io_status; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + ktrace("NtWriteFile(%p)\n", FileHandle); + + thread = get_current_ethread(); + if (!thread) + goto cleanup_nobj; + + if (!IoStatusBlock) + return STATUS_INVALID_PARAMETER; + + status = ref_object_by_handle(FileHandle, + STANDARD_RIGHTS_REQUIRED, + NULL, + KernelMode, + (PVOID *)&wf, + NULL); + if (!NT_SUCCESS(status)) + return status; + + file = wf->wf_file; + + /* check the file can actually be written */ + if (!(wf->wf_access & GENERIC_WRITE)) + goto cleanup; + + status = STATUS_ACCESS_VIOLATION; + if (!(file->f_mode & FMODE_WRITE)) + goto cleanup; + + /* write to file */ + pos = file->f_pos; + status = vfs_write(file, Buffer, Length, &pos); + file->f_pos = pos; + if (status >= 0) { + /* copy _WRITEDBYTES_ to user space */ + io_status.Information = (ULONG_PTR)status; + if(copy_to_user(IoStatusBlock, &io_status, sizeof(io_status))) + status = STATUS_NO_MEMORY; + else + status = STATUS_SUCCESS; + } + +cleanup: + deref_object((PVOID)wf); + +cleanup_nobj: + ktrace("*** NtWriteFile = %d\n", status); + return status; +} /* end NtWriteFile() */ +EXPORT_SYMBOL(NtWriteFile); + +/* + * set a file information + */ +NTSTATUS +SERVICECALL +NtSetInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass + ) +{ + struct file *file; + struct win32_file *wf; + struct ethread *thread; + loff_t (*fn)(struct file *, loff_t, int); + loff_t offset; + NTSTATUS status = 0; + + ktrace("*** NtSetInformationFile (%p)\n", FileHandle); + + thread = get_current_ethread(); + if (!thread) + return STATUS_UNSUCCESSFUL; + + status = ref_object_by_handle(FileHandle, + STANDARD_RIGHTS_REQUIRED, + NULL, + KernelMode, + (PVOID *)&wf, + NULL); + if (!NT_SUCCESS(status)) + return status; + + file = wf->wf_file; + + switch (FileInformationClass) { + case FilePositionInformation: + { + FILE_POSITION_INFORMATION PosInfo; + + if (Length < sizeof(PosInfo)) + status = STATUS_INVALID_PARAMETER; + + status = copy_from_user(&PosInfo, FileInformation, sizeof(PosInfo)); + + /* set the seek function pointer */ + fn = default_llseek; + if (file->f_op && file->f_op->llseek) + fn = file->f_op->llseek; + + lock_kernel(); + /* do the seek operation */ + offset = fn(file, PosInfo.CurrentByteOffset.LowPart, 0); + unlock_kernel(); + if (offset < 0) { + status = offset; + goto cleanup; + } + + status = STATUS_SUCCESS; + + break; + } + default: + break; + } + +cleanup: + deref_object((PVOID)wf); + ktrace("*** NtSetInformationFile = %d\n", status); + return status; +} /* end NtSetInformationFile() */ +EXPORT_SYMBOL(NtSetInformationFile); + +/* + * Query File Information + */ +NTSTATUS +SERVICECALL +NtQueryInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass + ) +{ + struct file *file; + struct win32_file *wf; + struct ethread *thread; + loff_t (*fn)(struct file *, loff_t, int); + NTSTATUS status = 0; + + ktrace("NtQueryInformationFile (%p)\n", FileHandle); + + thread = get_current_ethread(); + if (!thread) + return STATUS_UNSUCCESSFUL; + + status = ref_object_by_handle(FileHandle, + STANDARD_RIGHTS_REQUIRED, + NULL, + KernelMode, + (PVOID *)&wf, + NULL); + if (!NT_SUCCESS(status)) + return status; + + file = wf->wf_file; + + switch (FileInformationClass) { + case FilePositionInformation: + { + FILE_POSITION_INFORMATION PosInfo; + + if (Length < sizeof(PosInfo)) + status = STATUS_INVALID_PARAMETER; + + /* set the seek function pointer */ + fn = default_llseek; + if (file->f_op && file->f_op->llseek) + fn = file->f_op->llseek; + + lock_kernel(); + /* get current file position */ + PosInfo.CurrentByteOffset.LowPart = fn(file, 0, 1); + unlock_kernel(); + if (PosInfo.CurrentByteOffset.LowPart < 0) { + status = PosInfo.CurrentByteOffset.LowPart; + goto cleanup; + } + + /* copy the information to user space */ + if(copy_to_user(FileInformation, &PosInfo, sizeof(PosInfo))) + status = STATUS_NO_MEMORY; + else + status = STATUS_SUCCESS; + break; + } + default: + break; + } + +cleanup: + deref_object((PVOID)wf); + ktrace("*** NtQueryInformationFile = %d\n", status); + return status; +} /* end NtQueryInformationFile() */ +EXPORT_SYMBOL(NtQueryInformationFile); + +/* + * flush the buffers of a file + */ +NTSTATUS +SERVICECALL +NtFlushBuffersFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock + ) +{ + /* FIXME */ + return STATUS_INVALID_SYSTEM_SERVICE; +} /* end NtFlushBuffersFile() */ +EXPORT_SYMBOL(NtFlushBuffersFile); + + +/* + * check if the desired access is possible without violating the sharing mode + * of other opens of the same file + * - must call with a lock held on the file control struct + */ +static int file_check_sharing(struct win32_file *wf, struct win32_file_ctrl *wfc) +{ + struct list_head *flist; + __u32 extant_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; + __u32 extant_access = 0; + + /* scan the file access points */ + list_for_each(flist, &wfc->wfc_accessors) { + struct win32_file *wf = + list_entry(flist, struct win32_file, wf_ctllist); + + /* build up a picture of current sharing and access modes */ + extant_sharing &= wf->wf_sharing; + extant_access |= wf->wf_access; + } + + if ((wf->wf_access & GENERIC_READ) && + !(extant_sharing & FILE_SHARE_READ)) + goto sharing_violation; + + if ((wf->wf_access & GENERIC_WRITE) && + !(extant_sharing & FILE_SHARE_WRITE)) + goto sharing_violation; + + if ((extant_access & GENERIC_READ) && + !(wf->wf_sharing & FILE_SHARE_READ)) + goto sharing_violation; + + if ((extant_access & GENERIC_WRITE) && + !(wf->wf_sharing & FILE_SHARE_WRITE)) + goto sharing_violation; + + return 0; + +sharing_violation: + return STATUS_ACCESS_VIOLATION; + +} /* end file_check_sharing() */ + +/* FIXME */ +#if 0 +VOID +io_create_file(PVOID ObjectBody, PVOID Param) +{ + /* FIXME */ + return; +} + +VOID +io_open_file(OB_OPEN_REASON OpenReason, + struct eprocess* Process OPTIONAL, + PVOID Object, + ACCESS_MASK GrantedAccess, + ULONG HandleCount) +{ + /* FIXME */ + return; +} + +VOID io_close_file(struct eprocess* Process OPTIONAL, + PVOID Object, + ACCESS_MASK GrantedAccess, + ULONG ProcessHandleCount, + ULONG systemHandleCount) +{ + struct win32_file *wf = Object; + + if (ProcessHandleCount > 1) + return; + + ktrace("io_close_file(%p)\n", Object); + + /* discard my association with the Linux file */ + fput(wf->wf_file); + + if (wf->wf_control) { + /* unlink from the controlling object */ + list_del(&wf->wf_ctllist); + deref_object((PVOID)wf->wf_control); + } + return; +} +#endif + +VOID +io_delete_file(PVOID ObjectBody) +{ + struct win32_file *wf = ObjectBody; + + /* discard my association with the Linux file */ + if (wf->wf_file) + fput(wf->wf_file); + + if (wf->wf_control) { + /* unlink from the controlling object */ + list_del(&wf->wf_ctllist); + deref_object((PVOID)wf->wf_control); + } + + return; +} + +#endif diff --git a/unifiedkernel/io/io.c b/unifiedkernel/io/io.c new file mode 100644 index 0000000..e6ca681 --- /dev/null +++ b/unifiedkernel/io/io.c @@ -0,0 +1,215 @@ +/* + * io.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * io.c: IO functions + */ +#include "io.h" +#include "object.h" +#include "handle.h" +#include "win32.h" +#include "unistr.h" +#include "wcstr.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +extern POBJECT_TYPE file_object_type; +extern POBJECT_TYPE file_ctrl_object_type; +extern POBJECT_TYPE dir_object_type; +extern POBJECT_DIRECTORY file_ctrl_root; +extern POBJECT_TYPE symbol_link_type; +extern HANDLE file_ctrl_root_handle; + +#define DOSDRIVER_NAME_LEN 16 +#define DOSDRIVER_LETTER_OFF 4 +static WCHAR dosdriver_link_name[DOSDRIVER_NAME_LEN] = {'\\', '?', '?', '\\', ' ', ':', 0}; +static WCHAR dosdriver_target_name[PAGE_SIZE]; + +static WCHAR FileName[] = {'F', 'i', 'l', 'e', 0}; +static WCHAR FileRoot[] = {'\\', 'F', 'i', 'l', 'e', 'S', 'y', 's', 't', 'e', 'm', 0}; +static WCHAR DosRoot[] = {'\\', '?', '?', 0}; +static WCHAR DosDeviceLink[] = {'\\', 'D', 'o', 's', 'D', 'e', 'v', 'i', 'c', 'e', 's', 0}; + +static WCHAR FileControlTypeName[] = {'F', 'i', 'l', 'e', 'C', 'o', 'n', 't', 'r', 'o', 'l', 0}; +static WCHAR FileControlRootName[] = {'F', 'i', 'l', 'e', 'C', 'o', 'n', 't', 'r', 'o', 'l', 0}; + +static WCHAR DosCLinkName[] = {'\\', '?', '?', '\\', 'C', ':', 0}; +static WCHAR DriveC[] = {'/', 'd', 'r', 'i', 'v', 'e', '_', 'c', '/', 0}; +static WCHAR DosZLinkName[] = {'\\', '?', '?', '\\', 'Z', ':', 0}; +static WCHAR DosZTargetName[] = {'/', 0}; + +extern char *rootdir; + +VOID +init_io(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING dir_type_name; + UNICODE_STRING LinkName; + HANDLE Handle; + LONG i, len; + PWCHAR DosCTargetName; + + ktrace("init_io\n"); + /* Initialize the File object type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)FileName); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FILE_OBJECT); + ObjectTypeInitializer.OpenProcedure = NULL; /* FIXME: io_open_file*/ + ObjectTypeInitializer.CloseProcedure = NULL; /* FIXME: io_close_file */ + ObjectTypeInitializer.DeleteProcedure = io_delete_file; + ObjectTypeInitializer.CreateProcedure = NULL; /* FIXME: io_create_file */ + ObjectTypeInitializer.SecurityProcedure = NULL; /* FIXME: io_security_fil */ + ObjectTypeInitializer.QueryNameProcedure = NULL; /* FIXME: io_query_name_file */ + create_type_object(&ObjectTypeInitializer, &Name, &file_object_type); + + /* Initialize the File Control object type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)FileControlTypeName); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FILE_CONTROL_OBJECT); +#if 0 + ObjectTypeInitializer.OpenProcedure = io_open_file; + ObjectTypeInitializer.CloseProcedure = io_close_file; + ObjectTypeInitializer.DeleteProcedure = io_delete_file; + ObjectTypeInitializer.CreateProcedure = io_create_file; +#endif + ObjectTypeInitializer.SecurityProcedure = NULL; /* io_security_fil */ + ObjectTypeInitializer.QueryNameProcedure = NULL; /* io_query_name_file */ + create_type_object(&ObjectTypeInitializer, &Name, &file_ctrl_object_type); + + /* + * Create the '\FileSystem' object directory + */ + init_unistr(&dir_type_name, (PWSTR)FileRoot); + INIT_OBJECT_ATTR(&ObjectAttributes, + &dir_type_name, + 0, + NULL, + NULL); + NtCreateDirectoryObject(&Handle, 0, &ObjectAttributes); + /* + * Create the '\??' directory + */ + init_unistr(&dir_type_name, (PWSTR)DosRoot); + INIT_OBJECT_ATTR(&ObjectAttributes, + &dir_type_name, + 0, + NULL, + NULL); + NtCreateDirectoryObject(&Handle, 0, &ObjectAttributes); + + /* + * Create link from '\DosDevices' to '\??' directory + */ + init_unistr(&dir_type_name, (PWSTR)DosRoot); + init_unistr(&LinkName, (PWSTR)DosDeviceLink); + io_create_symbol_link(&LinkName, &dir_type_name); + + + init_unistr(&dir_type_name, (PWSTR)FileControlRootName); + INIT_OBJECT_ATTR(&ObjectAttributes, + &dir_type_name, + 0, + NULL, + NULL); + create_object(KernelMode, + dir_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID *)&file_ctrl_root); + create_handle(NULL, + file_ctrl_root, + 0, + ObjectAttributes.Attributes & OBJ_INHERIT, + &file_ctrl_root_handle); + + /* Create link from '\\??\\C:' to '\\root\\.wine\\driver_c' directory */ + len = strlen(rootdir); + DosCTargetName = (PWCHAR)kmalloc(len * 2 + 32, GFP_KERNEL); + for (i = 0; i < len; i++) + DosCTargetName[i] = (WCHAR)rootdir[i]; + if (rootdir[i - 1] == '/') + i--; + wcscpy(DosCTargetName + i, DriveC); + init_unistr(&dir_type_name, (PWSTR)DosCTargetName); + init_unistr(&LinkName, (PWSTR)DosCLinkName); + io_create_symbol_link(&LinkName, &dir_type_name); + + /* Create link from '\\??\\Z:' to '\\root' directory */ + init_unistr(&dir_type_name, (PWSTR)DosZTargetName); + init_unistr(&LinkName, (PWSTR)DosZLinkName); + io_create_symbol_link(&LinkName, &dir_type_name); +} + +void create_dosdriver_symlink(int index, char *target_str) +{ + char *p = target_str; + WCHAR *q = dosdriver_target_name; + BOOLEAN locked; + NTSTATUS status; + unsigned long access; + UNICODE_STRING target, link; + POBJECT_SYMBOLIC_LINK object = NULL; + + while (*p) + *q++ = (WCHAR)*p++; + *q = '\0'; + + dosdriver_link_name[DOSDRIVER_LETTER_OFF] = (WCHAR)(index + 'A'); + + init_unistr(&link, (PWSTR)dosdriver_link_name); + init_unistr(&target, (PWSTR)dosdriver_target_name); + + status = lookup_object_name(NULL, + &link, + 0, + symbol_link_type, + KernelMode, + NULL, + NULL, + NULL, + (PACCESS_STATE)&access, + &locked, + (PVOID *)&object); + + if (status == STATUS_OBJECT_NAME_NOT_FOUND) { + /* not found object */ + io_create_symbol_link(&link, &target); + } + else if (status == STATUS_SUCCESS && object ) { + /* found object, replace target */ + kfree(object->TargetName.Buffer); + object->TargetName.Buffer = (WCHAR *)kmalloc(target.MaximumLength, GFP_KERNEL); + copy_unistr(&object->TargetName, &target); + deref_object(object); + } +} +EXPORT_SYMBOL(create_dosdriver_symlink); +#endif diff --git a/unifiedkernel/io/symlink.c b/unifiedkernel/io/symlink.c new file mode 100644 index 0000000..d80a882 --- /dev/null +++ b/unifiedkernel/io/symlink.c @@ -0,0 +1,59 @@ +/* + * symlink.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * symlink.c: symbol link functions + */ +#include "win32.h" +#include "object.h" +#include "ntstatus.h" +#include "w32syscall.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +NTSTATUS +io_create_symbol_link(PUNICODE_STRING SymbolicLinkName, + PUNICODE_STRING TargetName) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle; + NTSTATUS Status; + + INIT_OBJECT_ATTR(&ObjectAttributes, + SymbolicLinkName, + OBJ_PERMANENT, + NULL, + NULL); + + Status = NtCreateSymbolicLinkObject(&Handle, + STANDARD_RIGHTS_REQUIRED | 0x1, + &ObjectAttributes, + TargetName); + if (Status != STATUS_SUCCESS) { + return(Status); + } + + NtClose(Handle); + + return STATUS_SUCCESS; +} +#endif diff --git a/unifiedkernel/ke/Makefile b/unifiedkernel/ke/Makefile new file mode 100644 index 0000000..a700e22 --- /dev/null +++ b/unifiedkernel/ke/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for kernel execute +# + +KE_OBJS += wait.o \ + misc.o \ + binfmt_pe.o \ + binfmt_exeso.o \ + apc.o \ + unistr.o \ + wcstr.o \ + switch.o \ + w32syscall.o \ + w32entry.o \ + w32init.o \ + sysdll.o \ + event.o \ + mutex.o \ + semaphore.o \ + proc.o + +$(MODULE)-objs += $(addprefix ke/, $(KE_OBJS)) diff --git a/unifiedkernel/ke/apc.c b/unifiedkernel/ke/apc.c new file mode 100644 index 0000000..67a1966 --- /dev/null +++ b/unifiedkernel/ke/apc.c @@ -0,0 +1,550 @@ +/* + * apc.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * apc.c: apc implementation + * Refered to ReactOS code + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL +unsigned long get_apc_dispatcher(void); + +/* + * free_apc_routine + * Free apc + */ +VOID +STDCALL +free_apc_routine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2) +{ + /* Free the APC */ + kfree(Apc); +} /* end free_apc_routine */ +EXPORT_SYMBOL(free_apc_routine); + +/* exit_special_apc*/ +VOID +STDCALL +exit_special_apc(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArguemnt2) +{ + int exit_status = (int) Apc->normal_routine; + + ktrace("exit_special_apc called to exit thread: 0x%p\n",get_current_ethread()); + /* Free the APC */ + kfree(Apc); + + /* Terminate the Thread */ + do_exit(exit_status); +} /* end exit_special_apc */ +EXPORT_SYMBOL(exit_special_apc); + +/* + * FUNCTION: Tests whether there are any pending APCs for the current thread + * and if so the APCs will be delivered on exit from kernel mode + */ +BOOLEAN +STDCALL +test_alert_thread(IN KPROCESSOR_MODE AlertMode) +{ + /* FIXME */ + return 0; +} +EXPORT_SYMBOL(test_alert_thread); + +/* + * apc_init + * Initialize Apc + */ +VOID +STDCALL +apc_init(IN PKAPC Apc, + IN struct kthread* Thread, + IN KAPC_ENVIRONMENT TargetEnvironment, + IN PKKERNEL_ROUTINE KernelRoutine, + IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, + IN PKNORMAL_ROUTINE NormalRoutine, + IN KPROCESSOR_MODE Mode, + IN PVOID Context) +{ + ktrace("apc_init(Apc %p, Thread %p, Environment %d, KernelRoutine %p, \ + RundownRoutine %p, NormalRoutine %p, Mode %d, Context %p)\n", + Apc, &Thread, TargetEnvironment, KernelRoutine, + RundownRoutine, NormalRoutine, Mode, Context); + + Apc->type = ApcObject; + Apc->size = sizeof(struct kapc); + if (TargetEnvironment == CurrentApcEnvironment) + Apc->apc_state_index = Thread->apc_state_index; + else Apc->apc_state_index = TargetEnvironment; + + /* Set the Thread and Routines */ + Apc->thread = Thread; + Apc->kernel_routine = KernelRoutine; + Apc->rundown_routine = NULL; /*rundown routine hasn't been implemented*/ + Apc->normal_routine = NormalRoutine; + + /* Check if this is a Special APC, in which case we use KernelMode and no Context */ + if (NormalRoutine!=NULL) { + Apc->apc_mode = Mode; + Apc->normal_context = Context; + } else Apc->apc_mode = KernelMode; + + Apc->inserted = 0; + return; +} /* end apc_init */ +EXPORT_SYMBOL(apc_init); + +/* + * __insert_queue_apc + * Insert apc to apc queue + */ +BOOLEAN +STDCALL +__insert_queue_apc(PKAPC Apc, KPRIORITY PriorityBoost) +{ + struct kthread *thread = Apc->thread; + struct list_head *head, *apc_listentry; + struct kapc *queued_apc; + struct kapc_state *apc_state; + + ktrace("__insert_queue_apc\n"); + /* Don't do anything if the APC is already inserted */ + if (Apc->inserted) return 0; + + /* + * Three scenarios: + * 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List + * 2) User APC which is exit_special_apc = Put it at the front of the List + * 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine + * Kernel APC list + */ + apc_state = thread->apc_state_pointer[(int)Apc->apc_state_index]; + head = &apc_state->apc_list_head[(int)(Apc->apc_mode)]; + if ((Apc->apc_mode != KernelMode) && + (Apc->kernel_routine == (PKKERNEL_ROUTINE)exit_special_apc)) { /* 2) */ + list_add(&Apc->apc_list_entry, head); + } else if (!Apc->normal_routine) { /* 3) */ + for (apc_listentry = head->next; + apc_listentry != head; + apc_listentry = apc_listentry->next) { + queued_apc = list_entry(apc_listentry, struct kapc, apc_list_entry); + if (queued_apc->normal_routine != NULL) break; + } + /* We found the first "Normal" APC, so write right before it */ + apc_listentry = apc_listentry->prev; + list_add(&Apc->apc_list_entry, apc_listentry); + } else { /* 1) */ + list_add_tail(&Apc->apc_list_entry, head); + } + + /* FIXME + * Three possibilites here again: + * 1) Kernel APC, The thread is Running: Request an Interrupt + * 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled + * and not in progress: Unwait the Thread + * 3) User APC, Unwait the Thread if it is alertable + */ + + /* Confirm Insertion */ + Apc->inserted = 1; + if (Apc->apc_mode == KernelMode) thread->apc_state.kapc_pending = 1; + else thread->apc_state.uapc_pending = 1; + + return 1; +} /* end __insert_queue_apc */ +EXPORT_SYMBOL(__insert_queue_apc); + +/* + * insert_queue_apc + */ +BOOLEAN +STDCALL +insert_queue_apc(PKAPC Apc, + PVOID SystemArgument1, + PVOID SystemArgument2, + KPRIORITY PriorityBoost) +{ + BOOL inserted; + struct kthread *thread; + + ktrace("insert_queue_apc(Apc %p, SystemArgument1 %p, SystemArgument2 %p)\n", + Apc, SystemArgument1, SystemArgument2); + /* Get the Thread specified in the APC */ + thread = Apc->thread; + + /* Disable interrupt and lock shared resource */ + spin_lock_irq(&thread->apc_queue_lock); + + if (!thread->apc_queueable) { + spin_unlock_irq(&thread->apc_queue_lock); + return 0; + } + + Apc->system_argument1 = SystemArgument1; + Apc->system_argument2 = SystemArgument2; + inserted = __insert_queue_apc(Apc, PriorityBoost); + + /* Enable interrupt and unlock shared resource */ + spin_unlock_irq(&thread->apc_queue_lock); + + return inserted; +} /* end insert_queue_apc */ +EXPORT_SYMBOL(insert_queue_apc); + +/* + * NtQueueApcThread + * system call NtQueueApcThread + * which called from user + */ +NTSTATUS SERVICECALL +NtQueueApcThread(HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + struct kapc *apc; + struct ethread *thread; + NTSTATUS status; + + ktrace("NtQueueApcThread\n"); + if (!(thread = get_current_ethread())) { + return STATUS_UNSUCCESSFUL; + } + + /* Set thread_info's flag */ + set_tsk_thread_flag(thread->et_task, TIF_APC); + if (!(apc = kmalloc(sizeof(struct kapc),GFP_KERNEL))) { + return STATUS_NO_MEMORY; + } + + apc_init(apc, + &thread->tcb, + OriginalApcEnvironment, + free_apc_routine, + NULL, + ApcRoutine, + UserMode, + NormalContext); + if (!insert_queue_apc(apc, SystemArgument1, SystemArgument2, IO_NO_INCREMENT)) { + kfree(apc); + status = STATUS_UNSUCCESSFUL; + } else status = STATUS_SUCCESS; + + return status; +} /* end NtQueueApcThread */ +EXPORT_SYMBOL(NtQueueApcThread); + +/* + * deliver_apc + * Dequeue the apc queue , and call apc function one by one + */ +VOID +STDCALL +deliver_apc(KPROCESSOR_MODE DeliveryMode, + PVOID Reserved, + struct pt_regs * TrapFrame) +{ + struct ethread *thread; + struct list_head * apc_listentry; + struct kapc *apc = NULL; + kernel_routine_t kernel_routine; + void * normal_context; + normal_routine_t normal_routine; + void *system_argument1; + void *system_argument2; + + ktrace("deliver_apc(DeliverMode 0x%x, Reserved 0x%p, TrapFrame 0x%p)\n", + DeliveryMode, Reserved, TrapFrame); + if (!(thread = get_current_ethread())) { + clear_tsk_thread_flag(current, TIF_APC); + return; + } + + /* Disable interrupt and lock shared resource */ + spin_lock_irq(&thread->tcb.apc_queue_lock); + + /* Clear APC Pending */ + thread->tcb.apc_state.kapc_pending = 0; + + /* Do the Kernel APCs first */ + while (!list_empty(&thread->tcb.apc_state.apc_list_head[KernelMode])) { + /* Clear APC Pending */ + thread->tcb.apc_state.kapc_pending = 0; + + /* Get the next Entry */ + apc_listentry = thread->tcb.apc_state.apc_list_head[KernelMode].next; + apc = list_entry(apc_listentry, struct kapc, apc_list_entry); + + /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ + normal_routine = apc->normal_routine; + kernel_routine = apc->kernel_routine; + normal_context = apc->normal_context; + system_argument1 = apc->system_argument1; + system_argument2 = apc->system_argument2; + + if (!normal_routine) { + /* Remove the APC from the list */ + apc->inserted= 0; + list_del(apc_listentry); + + /* Enable interrupt and unlock shared resource */ + spin_unlock_irq(&thread->tcb.apc_queue_lock); + + /* Call the Special APC */ + kernel_routine(apc, + &normal_routine, + &normal_context, + &system_argument1, + &system_argument2); + + /* Disable interrupt and lock shared resource again */ + spin_lock_irq(&thread->tcb.apc_queue_lock); + } else { + + /* FIXME + * DeliveryMode must be KernelMode in this case, since one may not + * return to umode while being inside a critical section or while + * a regular kmode apc is running (the latter should be impossible btw). + */ + + /* Dequeue the APC */ + list_del(apc_listentry); + apc->inserted = 0; + + /* Enable interrupt and unlock shared resource */ + spin_unlock_irq(&thread->tcb.apc_queue_lock); + + /* Call the Kernel APC */ + kernel_routine(apc, + &normal_routine, + &normal_context, + &system_argument1, + &system_argument2); + + /* If There still is a Normal Routine, then we need to call it */ + if (normal_routine) { + /* which is unplemented for premting by special apc */ + thread->tcb.apc_state.kapc_inprogress = 1; + + normal_routine(&normal_context, &system_argument1, &system_argument2); + } + + /* Disable interrupt and lock shared resource again */ + spin_lock_irq(&thread->tcb.apc_queue_lock); + + thread->tcb.apc_state.kapc_inprogress = 0; + } + } + + /* Now we do the User APCs */ + if ((!list_empty(&thread->tcb.apc_state.apc_list_head[UserMode])) && + (thread->tcb.apc_state.uapc_pending)) { /* && (DeliveryMode == UserMode) */ + + /* Get the APC Object */ + apc_listentry = thread->tcb.apc_state.apc_list_head[UserMode].next; + apc = list_entry(apc_listentry, struct kapc, apc_list_entry); + + /* Save Parameters so that it's safe to free the Object in Kernel Routine*/ + normal_routine = apc->normal_routine; + kernel_routine = apc->kernel_routine; + normal_context = apc->normal_context; + system_argument1 = apc->system_argument1; + system_argument2 = apc->system_argument2; + + /* Remove the APC from Queue, call the APC */ + list_del(apc_listentry); + apc->inserted = 0; + + /* Enable interrupt and unlock shared resource */ + spin_unlock_irq(&thread->tcb.apc_queue_lock); + + kernel_routine(apc, + &normal_routine, + &normal_context, + &system_argument1, + &system_argument2); + + if (!normal_routine) { + test_alert_thread(UserMode); /* Unimplemented */ + } else { + /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */ + init_user_apc(Reserved, + TrapFrame, + normal_routine, + normal_context, + system_argument1, + system_argument2); + } + } else { + /* It's not pending anymore */ + thread->tcb.apc_state.uapc_pending = 0; + + /* Enable interrupt and unlock shared resource */ + spin_unlock_irq(&thread->tcb.apc_queue_lock); + + /* Clear thread_info's flag */ + clear_tsk_thread_flag(thread->et_task,TIF_APC); + } + return; +} /* end deliver_apc */ +EXPORT_SYMBOL(deliver_apc); + +/* + * init_user_apc + * Save the trapframe and set the esp for returning to user space to call apc function + */ +VOID +STDCALL +init_user_apc(IN PVOID Reserved, + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2) +{ + PContext context; + PULONG esp; + + ktrace("init_user_apc, ESP 0x%lx\n", TrapFrame->sp); + /* + * Save the thread's current context (in other words the registers + * that will be restored when it returns to user mode) so the + * APC dispatcher can restore them later + */ + context = (PContext)(((PUCHAR)TrapFrame->sp) - sizeof(*context)); + memcpy(context, TrapFrame, sizeof(*context)); + + /* + * Setup the trap frame so the thread will start executing at the + * APC Dispatcher when it returns to user-mode + */ + esp = (PULONG)(((PUCHAR)TrapFrame->sp) - (sizeof(CONTEXT) + (6 * sizeof(ULONG)))); + esp[0] = 0xdeadbeef; + esp[1] = (ULONG)NormalRoutine; + esp[2] = (ULONG)NormalContext; + esp[3] = (ULONG)SystemArgument1; + esp[4] = (ULONG)SystemArgument2; + esp[5] = (ULONG)context; + TrapFrame->ip = get_apc_dispatcher(); + TrapFrame->sp = (ULONG)esp; +} /* end init_user_apc */ + +/* + * thread_special_apc + */ +void +STDCALL +thread_special_apc(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2) +{ + ktrace("thread_special_apc\n"); + kfree(Apc); +} /* end thread_special_apc */ +EXPORT_SYMBOL(thread_special_apc); + +/* + * NtContinue + * Go back to kernel space + */ +NTSTATUS +SERVICECALL +NtContinue(IN PContext Context, + IN BOOLEAN TestAlert) +{ + PKTRAP_FRAME trap_frame = (PKTRAP_FRAME)current->ethread->tcb.trap_frame; + + /* + * Copy the supplied context over the register information that was saved + * on entry to kernel mode, it will then be restored on exit + * FIXME: Validate the context + */ + memcpy(trap_frame, Context, sizeof(*trap_frame)); + + /* FIXME + * Copy floating point context into the thread's FX_SAVE_AREA + */ + + __asm__( + "andl %%esp, %%ecx;\n\t" + "movl %%ecx, %%ebp;\n\t" + "movl %%ebx, %%esp;\n\t" + "jmp w32syscall_exit\n\t" + : + : "b" (trap_frame), "c" (-THREAD_SIZE)); + + /* This doesn't actually happen b/c KeRosTrapReturn() won't return */ + return STATUS_SUCCESS; +} /* NtContinue */ +EXPORT_SYMBOL(NtContinue); + +/* do_apc */ +__attribute__((regparm(3))) +void do_apc(struct pt_regs *regs, sigset_t *oldset, + __u32 thread_info_flags) +{ + struct ethread *thread; + ktrace("Do Apc\n"); + + /* Get the Current Thread */ + if (!(thread = get_current_ethread())) { + clear_tsk_thread_flag(thread->et_task, TIF_APC); + return; + } + deliver_apc(0, 0, regs); /* first parament is kernelMode or UserMode or 0 for both*/ +}/* end do_apc */ + + +#endif diff --git a/unifiedkernel/ke/binfmt_exeso.c b/unifiedkernel/ke/binfmt_exeso.c new file mode 100644 index 0000000..f08d466 --- /dev/null +++ b/unifiedkernel/ke/binfmt_exeso.c @@ -0,0 +1,854 @@ +/* + * binfmt_exeso.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * binfmt_exeso.c: + * support running built-in exe for Wine application + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "win32_process.h" +#include + +#include "win32.h" +#include "pefile.h" +#include "process.h" +#include "thread.h" +#include "object.h" +#include "process.h" +#include "event.h" +#include "virtual.h" +#include "unistr.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#ifdef EXE_SO + +extern char builtin_dll_path[MAX_PATH]; +extern char ntdll_name[MAX_PATH + 16]; + +extern asmlinkage void w32syscall_exit(void); + +extern POBJECT_TYPE process_object_type; +extern POBJECT_TYPE thread_object_type; + +#define NTDLL_SO + +#define ELF_HWCAP (boot_cpu_data.x86_capability[0]) +#define ELF_EXEC_PAGESIZE 4096 + +#ifdef NTDLL_SO + +#ifndef elf_addr_t +#define elf_addr_t unsigned long +#endif + +#if ELF_EXEC_PAGESIZE > PAGE_SIZE +# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE +#else +# define ELF_MIN_ALIGN PAGE_SIZE +#endif + +#ifndef ELF_CORE_EFLAGS +#define ELF_CORE_EFLAGS 0 +#endif + +#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) +#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) +#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) + +#ifdef CONFIG_STACK_GROWSUP +#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items)) +#define STACK_ROUND(sp, items) \ + ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) +#define STACK_ALLOC(sp, len) ({ elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; old_sp; }) +#else +#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items)) +#define STACK_ROUND(sp, items) \ + (((unsigned long) (sp - items)) &~ 15UL) +#define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) +#endif + +#if ELF_CLASS == ELFCLASS32 +#define elf_shdr Elf32_Shdr +#define elf_sym elf32_sym +#define elf_off_t Elf32_Off +#define elf_half_t Elf32_Half +#else +#define elf_shdr Elf64_Shdr +#define elf_sym elf64_sym +#define elf_off_t Elf64_Off +#define elf_half_t Elf64_Half +#endif + +#endif + +extern unsigned long get_ntdll_entry(void); +extern unsigned long get_apc_dispatcher(void); +extern unsigned long get_pe_entry(void); +extern unsigned long get_interp_entry(void); +extern unsigned long get_start_thunk(void); +extern unsigned long get_ntdll_start_thunk(void); +extern unsigned long get_exeso_start_thunk(void); +extern NTSTATUS STDCALL map_system_dll(struct task_struct *tsk, char *name, + unsigned long *ntdll_load_addr, unsigned long *interp_load_addr); +extern char *search_ntdll(void); +extern int unshare_files(struct files_struct **displaced); +extern void put_files_struct(struct files_struct *files); + +static void dump_vma(void); +int STDCALL UkDebug(unsigned long arg1, unsigned long arg2, unsigned long arg3); +static int load_exeso_binary(struct linux_binprm * bprm, struct pt_regs * regs); + +static struct linux_binfmt exeso_format = { + .module = THIS_MODULE, + .load_binary = load_exeso_binary, + .load_shlib = NULL, + .core_dump = NULL, + .min_coredump = ELF_EXEC_PAGESIZE +}; + + +#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE) + +static unsigned long find_symbol_in_file(struct elf_phdr *elf_phdata, int phnum, + elf_shdr *elf_shdata, int shnum, char *sym, unsigned long base_addr) +{ + int sym_count = 0; + int link = -1; + int str_tab_size = 0; + char *str_tab = NULL; + elf_shdr *elf_spnt; + struct elf_sym *sympnt, *sym_tab = NULL; + unsigned long sym_addr = -EINVAL; + struct elf_phdr * elf_ppnt; + + for (elf_spnt = elf_shdata; elf_spnt < elf_shdata + shnum; elf_spnt++) { + if (elf_spnt->sh_type == SHT_SYMTAB) { + sym_tab = (struct elf_sym *)((unsigned long)elf_spnt->sh_offset + base_addr); + link = elf_spnt->sh_link; + sym_count = elf_spnt->sh_size / sizeof(struct elf_sym); + } + } + + if (link >= 0) { + elf_spnt = elf_shdata + link; + if (elf_spnt->sh_type != SHT_STRTAB) + return -ENOEXEC; + + str_tab = (char *)(elf_spnt->sh_offset) + base_addr; + str_tab_size = elf_spnt->sh_size; + } + + if (sym_tab && str_tab) { + for (sympnt = sym_tab; sympnt < sym_tab + sym_count; sympnt++) { + if (sympnt->st_name > str_tab_size) + break; + + if (!strcmp(sympnt->st_name + str_tab, sym)) { + sym_addr = sympnt->st_value; + break; + } + } + } + + if (sym_addr != -EINVAL) { + for (elf_ppnt = elf_phdata; elf_ppnt < elf_phdata + phnum; elf_ppnt++) { + if (sym_addr >= elf_ppnt->p_vaddr && sym_addr < elf_ppnt->p_vaddr + elf_ppnt->p_filesz) { + sym_addr -= elf_ppnt->p_vaddr - elf_ppnt->p_offset; + sym_addr += base_addr; + break; + } + } + } + + return sym_addr; +} /* end find_symbol_in_file */ + +int check_exeso(struct linux_binprm * bprm) +{ + struct elfhdr *elf_ex; + struct elf_phdr *elf_phdata = NULL; + elf_shdr *elf_shdata = NULL; + int retval = 1; + unsigned long map_addr; + size_t len; + unsigned long sym; + IMAGE_NT_HEADERS *nt; + + elf_ex = (struct elfhdr *)bprm->buf; + + if(!bprm->file->f_dentry || !bprm->file->f_dentry->d_inode) + return 0; + + if(!current->mm) + return 0; + + len = bprm->file->f_dentry->d_inode->i_size; + down_write(¤t->mm->mmap_sem); + map_addr = do_mmap(bprm->file, + 0, + len, + PROT_READ, + MAP_PRIVATE | MAP_DENYWRITE, + 0); + up_write(¤t->mm->mmap_sem); + if(map_addr >= (unsigned long)TASK_SIZE) + return 0; + + elf_phdata = (struct elf_phdr *)(map_addr + elf_ex->e_phoff); + elf_shdata = (elf_shdr *)(map_addr + elf_ex->e_shoff); + + sym = find_symbol_in_file(elf_phdata, elf_ex->e_phnum, elf_shdata, elf_ex->e_shnum, + "__wine_spec_nt_header", map_addr); + + if(sym >= (unsigned long)TASK_SIZE) { + down_write(¤t->mm->mmap_sem); + do_munmap(current->mm, map_addr, len); + up_write(¤t->mm->mmap_sem); + return 0; + } + + nt = (IMAGE_NT_HEADERS *)sym; + if(nt->Signature != 0x4550 || (nt->OptionalHeader.Magic != 0x10b && nt->OptionalHeader.Magic != 0x107)) + retval = 0; + else + retval = 1; + + down_write(¤t->mm->mmap_sem); + do_munmap(current->mm, map_addr, len); + up_write(¤t->mm->mmap_sem); + + return retval; +} + +#ifdef NTDLL_SO + +extern elf_off_t ntdll_phoff; +extern elf_half_t ntdll_phnum; + + +/* + * create_elf_tables + */ +static int +create_elf_tables_aux(struct linux_binprm *bprm, + unsigned long ntdll_load_addr, elf_off_t ntdll_phoff, elf_half_t ntdll_phnum, unsigned long ntdll_start_thunk, + unsigned long exeso_load_addr, elf_off_t exeso_phoff, elf_half_t exeso_phnum, unsigned long exeso_start_thunk, + unsigned long interp_load_addr, unsigned long interp_entry, unsigned long init_entry) +{ + unsigned long p = bprm->p; + int argc = bprm->argc; + int envc = bprm->envc; + elf_addr_t __user *argv; + elf_addr_t __user *envp; + elf_addr_t __user *sp; + elf_addr_t __user *u_platform; + const char *k_platform = ELF_PLATFORM; + int items; + elf_addr_t *elf_info; + elf_addr_t *elf_info2; + int ei_index = 0; + const struct cred *cred = current_cred(); + + /* + * If this architecture has a platform capability string, copy it + * to userspace. In some cases (Sparc), this info is impossible + * for userspace to get any other way, in others (i386) it is + * merely difficult. + */ + + u_platform = NULL; + if (k_platform) { + size_t len = strlen(k_platform) + 1; + + /* + * In some cases (e.g. Hyper-Threading), we want to avoid L1 + * evictions by the processes running on the same package. One + * thing we can do is to shuffle the initial stack for them. + */ + + p = arch_align_stack(p); + + u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); + if (__copy_to_user(u_platform, k_platform, len)) + return -EFAULT; + } + + /* Create the ELF interpreter info */ + elf_info = (elf_addr_t *) current->mm->saved_auxv; +#define NEW_AUX_ENT(id, val) \ + do { elf_info[ei_index++] = id; elf_info[ei_index++] = val; } while (0) + +#ifdef ARCH_DLINFO11 + /* + * ARCH_DLINFO must come first so PPC can do its special alignment of + * AUXV. + */ + ARCH_DLINFO; +#endif + NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); + NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); + NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); + NEW_AUX_ENT(AT_PHDR, ntdll_load_addr + ntdll_phoff); + NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); + NEW_AUX_ENT(AT_PHNUM, ntdll_phnum); + NEW_AUX_ENT(AT_BASE, interp_load_addr); + NEW_AUX_ENT(AT_FLAGS, 0); + NEW_AUX_ENT(AT_ENTRY, ntdll_start_thunk); + NEW_AUX_ENT(AT_UID, cred->uid); + NEW_AUX_ENT(AT_EUID, cred->euid); + NEW_AUX_ENT(AT_GID, cred->gid); + NEW_AUX_ENT(AT_EGID, cred->egid); + NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm)); +#if 0 + if (k_platform) { + /* FIXME */ + NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform); + } +#endif + if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { + NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data); + } +#undef NEW_AUX_ENT + /* AT_NULL is zero; clear the rest too */ + memset(&elf_info[ei_index], 0, + sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); + + /* And advance past the AT_NULL entry. */ + ei_index += 2; + + sp = STACK_ADD(p, ei_index * 2); + + items = (argc + 1) + (envc + 1); + items += 1; /* ELF interpreters only put argc on the stack */ + items += 3; /* interp entry address & _init address & load_base */ + bprm->p = STACK_ROUND(sp, items); + + /* Point sp at the lowest address on the stack */ +#ifdef CONFIG_STACK_GROWSUP + sp = (elf_addr_t __user *)bprm->p - items - ei_index; + bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */ +#else + sp = (elf_addr_t __user *)bprm->p; +#endif + + /* Now, let's put argc (and argv, envp if appropriate) on the stack */ + if (__put_user(argc, sp)) + return -EFAULT; + ++sp; + argv = sp; + envp = argv + argc + 1; + + /* Populate argv and envp */ + p = current->mm->arg_end = current->mm->arg_start; + while (argc-- > 0) { + size_t len; + __put_user((elf_addr_t)p, argv); + ++argv; + len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) + return 0; + p += len; + } + if (__put_user(0, argv)) + return -EFAULT; + current->mm->arg_end = current->mm->env_start = p; + while (envc-- > 0) { + size_t len; + __put_user((elf_addr_t)p, envp); + ++envp; + len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) + return 0; + p += len; + } + if (__put_user(0, envp)) + return -EFAULT; + current->mm->env_end = p; + + /* Put the elf_info on the stack in the right place. */ + sp = (elf_addr_t __user *)envp + 1; + if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) + return -EFAULT; + sp += ei_index; + + + elf_info2 = (elf_addr_t *)kmalloc(sizeof(current->mm->saved_auxv), GFP_KERNEL); + if(!elf_info2) + return -ENOMEM; + + ei_index = 0; +#define NEW_AUX_ENT(id, val) \ + do { elf_info2[ei_index++] = id; elf_info2[ei_index++] = val; } while (0) + +#ifdef ARCH_DLINFO11 + /* + * ARCH_DLINFO must come first so PPC can do its special alignment of + * AUXV. + */ + ARCH_DLINFO; +#endif + NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); + NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); + NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); + NEW_AUX_ENT(AT_PHDR, exeso_load_addr + exeso_phoff); + NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); + NEW_AUX_ENT(AT_PHNUM, exeso_phnum); + NEW_AUX_ENT(AT_BASE, interp_load_addr); + NEW_AUX_ENT(AT_FLAGS, 0); + NEW_AUX_ENT(AT_ENTRY, exeso_start_thunk); + NEW_AUX_ENT(AT_UID, cred->uid); + NEW_AUX_ENT(AT_EUID, cred->euid); + NEW_AUX_ENT(AT_GID, cred->gid); + NEW_AUX_ENT(AT_EGID, cred->egid); + NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm)); +#if 0 + if (k_platform) { + /* FIXME */ + NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform); + } +#endif + if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { + NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data); + } +#undef NEW_AUX_ENT + /* AT_NULL is zero; clear the rest too */ + memset(&elf_info2[ei_index], 0, + sizeof(current->mm->saved_auxv) - ei_index * sizeof elf_info2[0]); + ei_index += 2; + if (copy_to_user(sp, elf_info2, ei_index * sizeof(elf_addr_t))) { + kfree(elf_info2); + return -EFAULT; + } + kfree(elf_info2); + sp += ei_index; + + __put_user(interp_entry, sp); + ++sp; + __put_user(init_entry, sp); + ++sp; + __put_user(exeso_load_addr, sp); + + memset(current->mm->saved_auxv, 0, sizeof(current->mm->saved_auxv)); + + return 0; +} /* end create_elf_tables */ + +#else /* NTDLL_SO */ + +#endif + +static void dump_vma(void) +{ + struct vm_area_struct *vma = current->mm->mmap; + while(vma) { + struct vm_area_struct *next = vma->vm_next; + vma = next; + } +} + +int STDCALL +UkDebug(unsigned long arg1, unsigned long arg2, unsigned long arg3) +{ + dump_vma(); + return 0; +} + +static int load_exeso_binary(struct linux_binprm *bprm, struct pt_regs *regs) +{ + struct elfhdr *elf_ex; + struct elf_phdr *elf_phdata = NULL; + struct mm_struct *mm; + unsigned long load_addr = 0; + unsigned long error; + int retval = 0; + unsigned long pe_entry, ntdll_load_addr = 0; + unsigned long start_code, end_code, start_data, end_data; + unsigned long ntdll_entry; + /* FIXME */ +#if 0 + struct files_struct *files; + struct files_struct *displaced = NULL; +#endif + int executable_stack = EXSTACK_DEFAULT; + unsigned long def_flags = 0; + unsigned long stack_top; +#ifdef NTDLL_SO + unsigned long interp_load_addr; + unsigned long interp_entry; +#endif + struct eprocess *process; + struct ethread *thread; + PRTL_USER_PROCESS_PARAMETERS ppb; + OBJECT_ATTRIBUTES ObjectAttributes; + INITIAL_TEB init_teb; + + elf_ex = (struct elfhdr *)bprm->buf; + retval = -ENOEXEC; + /* First of all, some simple consistency checks */ + if (memcmp(elf_ex->e_ident, ELFMAG, SELFMAG) != 0) + goto out; + if (elf_ex->e_type != ET_EXEC && elf_ex->e_type != ET_DYN) + goto out; + if (!elf_check_arch(elf_ex)) + goto out; + if (!bprm->file->f_op||!bprm->file->f_op->mmap) + goto out; + + if (elf_ex->e_phentsize != sizeof(struct elf_phdr)) + goto out; + if (elf_ex->e_phnum < 1 || + elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) + goto out; + + if(!check_exeso(bprm)) + goto out; + + +#if 0 + if (!*win32_root) + search_win32_root(bprm); +#endif + +#if 0 + files = current->files; /* Refcounted so ok */ + retval = unshare_files(&displaced); + if (retval < 0) { + goto out; + } + + if (files == current->files) { + put_files_struct(files); + files = NULL; + } +#endif + + start_code = ~0UL; + end_code = 0; + start_data = 0; + end_data = 0; + + /* Flush all traces of the currently running executable */ + retval = flush_old_exec(bprm); + if (retval) { + goto out; + } + + /* Discard our unneeded old files struct */ +/* + if (files) { + put_files_struct(files); + files = NULL; + } +*/ + + /* OK, This is the point of no return */ + mm = current->mm; + current->flags &= ~PF_FORKNOEXEC; + mm->def_flags = def_flags; + + current->signal->rlim[RLIMIT_STACK].rlim_cur = WIN32_STACK_LIMIT; + current->signal->rlim[RLIMIT_STACK].rlim_max = WIN32_STACK_LIMIT; + current->personality |= ADDR_COMPAT_LAYOUT; + arch_pick_mmap_layout(mm); + + /* Do this so that we can load the ntdll, if need be. We will + change some of these later */ + mm->free_area_cache = mm->mmap_base = WIN32_UNMAPPED_BASE; + mm->cached_hole_size = 0; + stack_top = WIN32_STACK_LIMIT + WIN32_LOWEST_ADDR; + retval = setup_arg_pages(bprm, stack_top, executable_stack); + if (retval < 0) + goto out_free_file; + + down_write(&mm->mmap_sem); + /* reserve first 0x100000 */ + do_mmap_pgoff(NULL, 0, WIN32_LOWEST_ADDR, PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + /* reserve first 0x7fff0000 - 0x80000000 */ + do_mmap_pgoff(NULL, WIN32_TASK_SIZE - 0x10000, 0x10000, + PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + /* reserve first 0x81000000 - 0xc0000000 + * 0x80000000 - 0x81000000 used for wine SYSTEM_HEAP */ + do_mmap_pgoff(NULL, WIN32_TASK_SIZE + WIN32_SYSTEM_HEAP_SIZE, + TASK_SIZE - WIN32_TASK_SIZE - WIN32_SYSTEM_HEAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + up_write(&mm->mmap_sem); + +#ifdef NTDLL_SO + /* search ntdll.dll.so in $PATH, default is /usr/local/lib/wine/ntdll.dll.so */ + if (!*ntdll_name) + search_ntdll(); + + /* map ntdll.dll.so */ + map_system_dll(current, ntdll_name, &ntdll_load_addr, &interp_load_addr); + + pe_entry = get_pe_entry(); + ntdll_entry = get_ntdll_entry(); + interp_entry = get_interp_entry(); +#endif + + set_binfmt(&exeso_format); + +#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES + retval = arch_setup_additional_pages(bprm, executable_stack); + if (retval < 0) { +#if 0 + send_sig(SIGKILL, current, 0); +#endif + goto out_free_file; + } +#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ + + install_exec_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; + +#ifdef NTDLL_SO + /* copy argv, env, and auxvec to stack, all for interpreter */ + create_elf_tables_aux(bprm, + ntdll_load_addr, ntdll_phoff, ntdll_phnum, get_ntdll_start_thunk(), + load_addr, elf_ex->e_phoff, elf_ex->e_phnum, 0, + interp_load_addr, interp_entry, 0); +#endif + + mm->end_code = end_code; + mm->start_code = start_code; + mm->start_data = start_data; + mm->end_data = end_data; + mm->start_stack = bprm->p; + + if (current->personality & MMAP_PAGE_ZERO) { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + down_write(&mm->mmap_sem); + error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + up_write(&mm->mmap_sem); + } + + + /* create win-related structure */ + INIT_OBJECT_ATTR(&ObjectAttributes, NULL, 0, NULL, NULL); + + /* Create EPROCESS */ + retval = create_object(KernelMode, + process_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(struct eprocess), + 0, + 0, + (PVOID *)&process); + if (retval != STATUS_SUCCESS) { + goto out_free_file; + } + + /* init eprocess */ + eprocess_init(process); + process->unique_processid = create_cid_handle(process, process_object_type); + if (!process->unique_processid) + goto out_free_eproc; + + /* initialize EProcess and KProcess */ + process->section_base_address = (void *)load_addr; + + /* FIXME: PsCreateCidHandle */ + + /* Create PEB */ + if ((retval = create_peb(process))) + goto out_free_process_cid; + + /* Create PPB */ + create_ppb(&ppb, process, bprm, bprm->filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + ((PEB *)process->peb)->ProcessParameters = ppb; + + /* allocate a Win32 thread object */ + retval = create_object(KernelMode, + thread_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(struct ethread), + 0, + 0, + (PVOID *)&thread); + if (retval) { + goto out_free_process_cid; + } + + thread->cid.unique_thread = create_cid_handle(thread, thread_object_type); + thread->cid.unique_process = process->unique_processid; + if (!thread->cid.unique_thread) + goto out_free_ethread; + + /* set the teb */ + init_teb.StackBase = (PVOID)stack_top; + init_teb.StackLimit = (PVOID)stack_top - WIN32_STACK_LIMIT; + thread->tcb.teb = create_teb(process, (PCLIENT_ID)&thread->cid, &init_teb); + if (IS_ERR(thread->tcb.teb)) { + retval = PTR_ERR(thread->tcb.teb); + goto out_free_thread_cid; + } + + /* Init KThreaad */ + ethread_init(thread, process, current); + + deref_object(process); + deref_object(thread); + + set_teb_selector(current, (long)thread->tcb.teb); + + thread->start_address = (void *)pe_entry; /* FIXME */ + + /* save current trap frame */ + thread->tcb.trap_frame = (struct ktrap_frame *)regs; + + /* init apc, to call LdrInitializeThunk */ +#if 0 + thread_apc = kmalloc(sizeof(KAPC), GFP_KERNEL); + if (!thread_apc) { + retval = -ENOMEM; + goto out_free_thread_cid; + } + apc_init(thread_apc, + &thread->tcb, + OriginalApcEnvironment, + thread_special_apc, + NULL, + (PKNORMAL_ROUTINE)ntdll_entry, + UserMode, + (void *)(bprm->p + 12)); + insert_queue_apc(thread_apc, (void *)interp_entry, (void *)extra_page, IO_NO_INCREMENT); +#ifndef TIF_APC +#define TIF_APC 13 +#endif + set_tsk_thread_flag(current, TIF_APC); +#endif + +#ifdef ELF_PLAT_INIT + /* + * The ABI may specify that certain registers be set up in special + * ways (on i386 %edx is the address of a DT_FINI function, for + * example. In addition, it may also specify (eg, PowerPC64 ELF) + * that the e_entry field is the address of the function descriptor + * for the startup routine, rather than the address of the startup + * routine itself. This macro performs whatever initialization to + * the regs structure is required as well as any relocations to the + * function descriptor entries when executing dynamically links apps. + */ + ELF_PLAT_INIT(regs, reloc_func_desc); +#endif + + start_thread(regs, interp_entry, bprm->p); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } + + retval = 0; + + try_module_get(THIS_MODULE); + + /* return from w32syscall_exit, not syscall_exit */ + ((unsigned long *)regs)[-1] = (unsigned long)w32syscall_exit; + regs->fs = TEB_SELECTOR; + +out: + if(elf_phdata) + kfree(elf_phdata); +#if 0 + if (displaced) + put_files_struct(displaced); +#endif + return retval; + + /* error cleanup */ +out_free_thread_cid: + delete_cid_handle(thread->cid.unique_thread, thread_object_type); +out_free_ethread: + deref_object(thread); +out_free_process_cid: + delete_cid_handle(process->unique_processid, process_object_type); +out_free_eproc: + deref_object(process); +out_free_file: +#if 0 + if (files) { + put_files_struct(current->files); + current->files = files; + } +#endif + send_sig(SIGKILL, current, 0); + goto out; +} + +int init_exeso_binfmt(void) +{ + return insert_binfmt(&exeso_format); +} + +void exit_exeso_binfmt(void) +{ + unregister_binfmt(&exeso_format); +} + +#endif +#endif + diff --git a/unifiedkernel/ke/binfmt_pe.c b/unifiedkernel/ke/binfmt_pe.c new file mode 100644 index 0000000..63dd4b0 --- /dev/null +++ b/unifiedkernel/ke/binfmt_pe.c @@ -0,0 +1,832 @@ +/* + * binfmt_pe.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * binfmt_pe.c: + * Refered to Linux Kernel code + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "win32_process.h" +#include + +#include "win32.h" +#include "pefile.h" +#include "section.h" +#include "process.h" +#include "thread.h" +#include "apc.h" +#include "object.h" +#include "process.h" +#include "area.h" +#include "virtual.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +char builtin_dll_path[MAX_PATH] = {0x0}; +char ntdll_name[MAX_PATH + 16] = {0x0}; + +unsigned long extra_page = 0; +extern asmlinkage void w32syscall_exit(void); + +extern POBJECT_TYPE process_object_type; +extern POBJECT_TYPE thread_object_type; + +#define NTDLL_SO + +#define ELF_HWCAP (boot_cpu_data.x86_capability[0]) +#define ELF_EXEC_PAGESIZE 4096 + +#ifdef NTDLL_SO + +#ifndef elf_addr_t +#define elf_addr_t unsigned long +#endif + +#if ELF_EXEC_PAGESIZE > PAGE_SIZE +# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE +#else +# define ELF_MIN_ALIGN PAGE_SIZE +#endif + +#ifndef ELF_CORE_EFLAGS +#define ELF_CORE_EFLAGS 0 +#endif + +#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) +#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) +#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) + +#ifdef CONFIG_STACK_GROWSUP +#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) + (items)) +#define STACK_ROUND(sp, items) \ + ((15 + (unsigned long) ((sp) + (items))) &~ 15UL) +#define STACK_ALLOC(sp, len) ({ elf_addr_t __user *old_sp = (elf_addr_t __user *)sp; sp += len; old_sp; }) +#else +#define STACK_ADD(sp, items) ((elf_addr_t __user *)(sp) - (items)) +#define STACK_ROUND(sp, items) \ + (((unsigned long) (sp - items)) &~ 15UL) +#define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) +#endif + +#if ELF_CLASS == ELFCLASS32 +#define elf_off_t Elf32_Off +#define elf_half_t Elf32_Half +#else +#define elf_off_t Elf64_Off +#define elf_half_t Elf64_Half +#endif + +#endif + +extern unsigned long get_ntdll_entry(void); +extern unsigned long get_apc_dispatcher(void); +extern unsigned long get_pe_entry(void); +extern unsigned long get_interp_entry(void); +extern unsigned long get_start_thunk(void); +extern LONG STDCALL map_system_dll(struct task_struct *tsk, char *name, + unsigned long *ntdll_load_addr, unsigned long *interp_load_addr); +extern int unshare_files(struct files_struct **displaced); +extern void put_files_struct(struct files_struct *files); + +void +STDCALL +thread_special_apc(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2); + +static int load_pe_binary(struct linux_binprm * bprm, struct pt_regs * regs); + +static struct linux_binfmt pe_format = { + .module = THIS_MODULE, + .load_binary = load_pe_binary, + .load_shlib = NULL, + .core_dump = NULL, + .min_coredump = ELF_EXEC_PAGESIZE +}; + +#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE) + + +#ifdef NTDLL_SO + +extern elf_off_t ntdll_phoff; +extern elf_half_t ntdll_phnum; +#ifndef ELF_BASE_PLATFORM +#define ELF_BASE_PLATFORM NULL +#endif + +/* + * create_elf_tables + */ +static int +create_elf_tables(struct linux_binprm *bprm, unsigned long load_addr, + elf_off_t phoff, elf_half_t phnum, unsigned long entry) +{ + unsigned long p = bprm->p; + int argc = bprm->argc; + int envc = bprm->envc; + elf_addr_t __user *argv; + elf_addr_t __user *envp; + elf_addr_t __user *sp; + elf_addr_t __user *u_platform; + elf_addr_t __user *u_base_platform; + elf_addr_t __user *u_rand_bytes; + const char *k_platform = ELF_PLATFORM; + const char *k_base_platform = ELF_BASE_PLATFORM; + unsigned char k_rand_bytes[16]; + int items; + elf_addr_t *elf_info; + int ei_index = 0; + const struct cred *cred = current_cred(); + struct vm_area_struct *vma; + + /* + * In some cases (e.g. Hyper-Threading), we want to avoid L1 + * evictions by the processes running on the same package. One + * thing we can do is to shuffle the initial stack for them. + */ + + p = arch_align_stack(p); + + /* + * If this architecture has a platform capability string, copy it + * to userspace. In some cases (Sparc), this info is impossible + * for userspace to get any other way, in others (i386) it is + * merely difficult. + */ + u_platform = NULL; + if (k_platform) { + size_t len = strlen(k_platform) + 1; + + u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); + if (__copy_to_user(u_platform, k_platform, len)) + return -EFAULT; + } + + /* + * If this architecture has a "base" platform capability + * string, copy it to userspace. + */ + u_base_platform = NULL; + if (k_base_platform) { + size_t len = strlen(k_base_platform) + 1; + + u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); + if (__copy_to_user(u_base_platform, k_base_platform, len)) + return -EFAULT; + } + + /* + * Generate 16 random bytes for userspace PRNG seeding. + */ + get_random_bytes(k_rand_bytes, sizeof(k_rand_bytes)); + u_rand_bytes = (elf_addr_t __user *) + STACK_ALLOC(p, sizeof(k_rand_bytes)); + if (__copy_to_user(u_rand_bytes, k_rand_bytes, sizeof(k_rand_bytes))) + return -EFAULT; + + /* Create the ELF interpreter info */ + elf_info = (elf_addr_t *) current->mm->saved_auxv; + /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ +#define NEW_AUX_ENT(id, val) \ + do { \ + elf_info[ei_index++] = id; \ + elf_info[ei_index++] = val; \ + } while (0) + +#ifdef ARCH_DLINFO11 + /* + * ARCH_DLINFO must come first so PPC can do its special alignment of + * AUXV. + * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in + * ARCH_DLINFO changes + */ + ARCH_DLINFO; +#endif + NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); + NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); + NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); + NEW_AUX_ENT(AT_PHDR, load_addr + phoff); + NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); + NEW_AUX_ENT(AT_PHNUM, phnum); + NEW_AUX_ENT(AT_BASE, 0); + NEW_AUX_ENT(AT_FLAGS, 0); + NEW_AUX_ENT(AT_ENTRY, entry); + NEW_AUX_ENT(AT_UID, cred->uid); + NEW_AUX_ENT(AT_EUID, cred->euid); + NEW_AUX_ENT(AT_GID, cred->gid); + NEW_AUX_ENT(AT_EGID, cred->egid); + NEW_AUX_ENT(AT_SECURE, (elf_addr_t) security_bprm_secureexec(bprm)); + NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes); + NEW_AUX_ENT(AT_EXECFN, bprm->exec); +#if 0 + if (k_platform) { + NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(unsigned long)u_platform); + } + if (k_base_platform) { + NEW_AUX_ENT(AT_BASE_PLATFORM, (elf_addr_t)(unsigned long)u_base_platform); + } +#endif + if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { + NEW_AUX_ENT(AT_EXECFD, (elf_addr_t) bprm->interp_data); + } +#undef NEW_AUX_ENT + /* AT_NULL is zero; clear the rest too */ + memset(&elf_info[ei_index], 0, + sizeof current->mm->saved_auxv - ei_index * sizeof elf_info[0]); + + /* And advance past the AT_NULL entry. */ + ei_index += 2; + + sp = STACK_ADD(p, ei_index); + + items = (argc + 1) + (envc + 1) + 1; + bprm->p = STACK_ROUND(sp, items); + + /* Point sp at the lowest address on the stack */ +#ifdef CONFIG_STACK_GROWSUP + sp = (elf_addr_t __user *)bprm->p - items - ei_index; + bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */ +#else + sp = (elf_addr_t __user *)bprm->p; +#endif + + /* + * Grow the stack manually; some architectures have a limit on how + * far ahead a user-space access may be in order to grow the stack. + */ + vma = find_extend_vma(current->mm, bprm->p); + if (!vma) + return -EFAULT; + + /* Now, let's put argc (and argv, envp if appropriate) on the stack */ + if (__put_user(argc, sp++)) + return -EFAULT; + argv = sp; + envp = argv + argc + 1; + + /* Populate argv and envp */ + p = current->mm->arg_end = current->mm->arg_start; + while (argc-- > 0) { + size_t len; + if (__put_user((elf_addr_t)p, argv++)) + return -EFAULT; + len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) + return 0; + p += len; + } + if (__put_user(0, argv)) + return -EFAULT; + current->mm->arg_end = current->mm->env_start = p; + while (envc-- > 0) { + size_t len; + if (__put_user((elf_addr_t)p, envp++)) + return -EFAULT; + len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); + if (!len || len > MAX_ARG_STRLEN) + return 0; + p += len; + } + if (__put_user(0, envp)) + return -EFAULT; + current->mm->env_end = p; + + /* Put the elf_info on the stack in the right place. */ + sp = (elf_addr_t __user *)envp + 1; + if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) + return -EFAULT; + return 0; +} /* end create_elf_tables */ + +/* + * search_ntdll + */ +char *search_ntdll(void) +{ + int len; + + if (!*builtin_dll_path) { + len = strlen("/usr/local/lib/wine/"); + memcpy(builtin_dll_path, "/usr/local/lib/wine/", len + 1); + } else + len = strlen(builtin_dll_path); + memcpy(ntdll_name, builtin_dll_path, len); + strcpy(ntdll_name + len, "ntdll.dll.so"); + + return ntdll_name; +} /* end search_ntdll */ + +#else /* NTDLL_SO */ + +/* + * create_pe_tables + */ +int +create_pe_tables(struct linux_binprm *bprm, struct win32_section *ws, + unsigned long load_addr, unsigned long interp_load_addr) +{ + return 0; +} /* end create_pe_tables */ +EXPORT_SYMBOL(create_pe_tables); + +/* + * load_pe_interp + */ +static unsigned long load_pe_interp(void *interp_hdr, + struct file *interpreter, + unsigned long *interp_load_addr) +{ + return 0; +} /* end load_pe_interp */ + +#endif + +static void adjust_stack(unsigned long start_stack) +{ + struct vm_area_struct *vma = find_vma(current->mm, start_stack); + + if (!vma) + return; + + if (WIN32_STACK_LIMIT > vma->vm_end - vma->vm_start) + vma->vm_start = WIN32_LOWEST_ADDR; + + sys_mprotect(vma->vm_start, PAGE_SIZE, PROT_NONE); +} + +/* + * load_pe_binary + */ +static int load_pe_binary(struct linux_binprm *bprm, struct pt_regs *regs) +{ + IMAGE_DOS_HEADER *dos_hdr; + struct win32_section *ws = NULL; + struct win32_image_section *wis; + unsigned long error; + unsigned long pe_addr = 0; + int retval = 0; + unsigned long pe_entry, ntdll_load_addr = 0; + unsigned long start_code, end_code, start_data, end_data; + unsigned long reloc_func_desc = 0; + unsigned long ntdll_entry; + /* FIXME */ +#if 0 + struct files_struct *files; + struct files_struct *displaced = NULL; +#endif + struct mm_struct *mm; + int executable_stack = EXSTACK_DEFAULT; + unsigned long def_flags = 0; + unsigned long stack_top; + unsigned long ret_addr = 0xdeadbeef; + unsigned long start_address; + unsigned long pe_brk = 0; +#ifdef NTDLL_SO + unsigned long interp_load_addr; + unsigned long interp_entry; +#endif + int maped = 0; + struct eprocess *process; + struct ethread *thread; + PRTL_USER_PROCESS_PARAMETERS ppb; + PKAPC thread_apc; + OBJECT_ATTRIBUTES ObjectAttributes; + INITIAL_TEB init_teb; + + /* check the DOS header */ + retval = -ENOEXEC; + dos_hdr = (IMAGE_DOS_HEADER *)bprm->buf; + if (dos_hdr->e_magic != IMAGE_DOS_SIGNATURE || dos_hdr->e_lfanew <= 0) + goto out; + + retval = -ENOMEM; + ws = (struct win32_section *)kmalloc(sizeof(struct win32_section), GFP_KERNEL); + if (!ws) + goto out; + memset(ws, 0, sizeof(*ws)); + +#if 0 + files = current->files; /* Refcounted so ok */ + retval = unshare_files(&displaced); + if (retval < 0) { + kfree(ws); + goto out; + } + if (files == current->files) { + put_files_struct(files); + files = NULL; + } +#endif + + start_code = ~0UL; + end_code = 0; + start_data = 0; + end_data = 0; + + /* Flush all traces of the currently running executable */ + retval = flush_old_exec(bprm); + if (retval) { + kfree(ws); + goto out; + } + +#if 0 + /* Discard our unneeded old files struct */ + if (files) { + put_files_struct(files); + files = NULL; + } +#endif + + /* OK, This is the point of no return */ + mm = current->mm; + current->flags &= ~PF_FORKNOEXEC; + mm->def_flags = def_flags; + + current->signal->rlim[RLIMIT_STACK].rlim_cur = WIN32_STACK_LIMIT; + current->signal->rlim[RLIMIT_STACK].rlim_max = WIN32_STACK_LIMIT; + current->personality |= ADDR_COMPAT_LAYOUT; + arch_pick_mmap_layout(mm); + + mm->free_area_cache = mm->mmap_base = WIN32_UNMAPPED_BASE; + mm->cached_hole_size = 0; + stack_top = WIN32_STACK_LIMIT + WIN32_LOWEST_ADDR; + retval = setup_arg_pages(bprm, stack_top, executable_stack); + if (retval < 0) + goto out_free_file; + + /* map PE image */ + ws->ws_file = bprm->file; + image_section_setup(ws); + ws->ws_mmap(current, ws, &pe_addr, 0, 0, 0); + maped = 1; + + down_write(&mm->mmap_sem); + /* reserve first 0x100000 */ + do_mmap_pgoff(NULL, 0, WIN32_LOWEST_ADDR, PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + /* reserve first 0x7fff0000 - 0x80000000 */ + do_mmap_pgoff(NULL, WIN32_TASK_SIZE - 0x10000, 0x10000, + PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + /* reserve first 0x81000000 - 0xc0000000 + * 0x80000000 - 0x81000000 used for wine SYSTEM_HEAP */ + do_mmap_pgoff(NULL, WIN32_TASK_SIZE + WIN32_SYSTEM_HEAP_SIZE, + TASK_SIZE - WIN32_TASK_SIZE - WIN32_SYSTEM_HEAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + up_write(&mm->mmap_sem); + + /* adjust stack in 0x100000 - 0x300000 + * 0x100000 - 0x101000 is not access */ + adjust_stack(bprm->p); + + /* Now we do a little grungy work by mmaping the PE image into + the correct location in memory. At this point, we assume that + the image should be loaded at fixed address, not at a variable + address. */ + for (wis = ws->ws_sections; wis < ws->ws_sections + ws->ws_nsecs; wis++) { + unsigned long k; + + if (wis->wis_character & IMAGE_SCN_TYPE_NOLOAD) + continue; + + k = ws->ws_realbase + wis->wis_rva; + + /* + * Check to see if the section's size will overflow the + * allowed task size. Note that p_filesz must always be + * <= p_memsz so it is only necessary to check p_memsz. + */ + if (k > TASK_SIZE || TASK_SIZE - wis->wis_size < k) /* Avoid overflows. */ + goto out_free_file; + + if (wis->wis_character & IMAGE_SCN_MEM_EXECUTE) { + start_code = k; + end_code = k + wis->wis_rawsize; + } + else { + if (!start_data) + start_data = k; + end_data = k + wis->wis_rawsize; + } + + k += wis->wis_size; + if (pe_brk < k) /* pe_brk used set mm->brk */ + pe_brk = k; + + /* TODO: start_data and end_data, diff to ELF */ + } + + mm->brk = pe_brk; + + /* extra page, used for interpreter ld-linux.so */ + down_write(&mm->mmap_sem); + if ((extra_page = do_brk(pe_brk, PAGE_SIZE)) != pe_brk) { + up_write(&mm->mmap_sem); + goto out_free_file; + } + up_write(&mm->mmap_sem); + mm->brk = pe_brk + PAGE_SIZE; + + ws->ws_entrypoint += ws->ws_realbase; + +#ifdef NTDLL_SO + /* search ntdll.dll.so in $PATH, default is /usr/local/lib/wine/ntdll.dll.so */ + if (!*ntdll_name) + search_ntdll(); + + /* map ntdll.dll.so */ + map_system_dll(current, ntdll_name, &ntdll_load_addr, &interp_load_addr); + + pe_entry = get_pe_entry(); + ntdll_entry = get_ntdll_entry(); + interp_entry = get_interp_entry(); +#endif + reloc_func_desc = 0; + + set_binfmt(&pe_format); + + INIT_OBJECT_ATTR(&ObjectAttributes, NULL, 0, NULL, NULL); + + /* Create EPROCESS */ + retval = create_object(KernelMode, + process_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(struct eprocess), + 0, + 0, + (PVOID *)&process); + if (retval != STATUS_SUCCESS) { + goto out_free_file; + } + + /* init eprocess */ + eprocess_init(process); + process->unique_processid = create_cid_handle(process, process_object_type); + if (!process->unique_processid) + goto out_free_eproc; + + insert_reserved_area(process, WIN32_LOWEST_ADDR, + WIN32_LOWEST_ADDR + WIN32_STACK_LIMIT, _PAGE_READWRITE); + + /* initialize EProcess and KProcess */ + process->section_base_address = (void *)ws->ws_realbase; + insert_mapped_area(process, ws->ws_realbase, ws->ws_realbase + ws->ws_pagelen, _PAGE_READONLY, NULL); + + /* Create PEB */ + if ((retval = create_peb(process))) + goto out_free_process_cid; + + /* Create PPB */ + create_ppb(&ppb, process, bprm, bprm->filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + ((PEB *)process->peb)->ProcessParameters = ppb; + +#ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES + retval = arch_setup_additional_pages(bprm, executable_stack); + if (retval < 0) { + send_sig(SIGKILL, current, 0); + goto out_free_process_cid; + } +#endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ + + install_exec_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; +#ifdef NTDLL_SO + /* copy argv, env, and auxvec to stack, all for interpreter */ + create_elf_tables(bprm, ntdll_load_addr, ntdll_phoff, ntdll_phnum, get_start_thunk()); +#endif + + /* Set the Esp */ +#ifdef CONFIG_STACK_GROWSUP + /* FIXME */ +#else + /* setup user stack */ + /* ------------- ----------- + param PEB_BASE + ------------- ----------- + start_address entry point + ------------- ----------- + ret_addr 0xdeadbeef + ------------- ----------- + */ + bprm->p = bprm->p /* stack_top */ + - sizeof(ret_addr) /* return address, BAD address */ + - sizeof(start_address) /* image entry point */ + - sizeof(unsigned long); /* paramters for entry point */ + start_address = ws->ws_entrypoint; + *(unsigned long *)bprm->p = ret_addr; + *(unsigned long *)(bprm->p + sizeof(ret_addr)) = start_address; + *(unsigned long *)(bprm->p + sizeof(ret_addr) + sizeof(start_address)) = PEB_BASE; +#endif + + mm->end_code = end_code; + mm->start_code = start_code; + mm->start_data = start_data; + mm->end_data = end_data; + mm->start_stack = bprm->p; + + if (current->personality & MMAP_PAGE_ZERO) { + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + down_write(&mm->mmap_sem); + error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + up_write(&mm->mmap_sem); + } + + /* allocate a Win32 thread object */ + retval = create_object(KernelMode, + thread_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(struct ethread), + 0, + 0, + (PVOID *)&thread); + if (retval) { + goto out_free_process_cid; + } + + thread->cid.unique_thread = create_cid_handle(thread, thread_object_type); + thread->cid.unique_process = process->unique_processid; + if (!thread->cid.unique_thread) + goto out_free_ethread; + + /* set the teb */ + init_teb.StackBase = (PVOID)stack_top; + init_teb.StackLimit = (PVOID)WIN32_LOWEST_ADDR + PAGE_SIZE; + thread->tcb.teb = create_teb(process, (PCLIENT_ID)&thread->cid, &init_teb); + if (IS_ERR(thread->tcb.teb)) { + retval = PTR_ERR(thread->tcb.teb); + goto out_free_thread_cid; + } + + /* Init KThreaad */ + ethread_init(thread, process, current); + + deref_object(process); + deref_object(thread); + + set_teb_selector(current, (long)thread->tcb.teb); + + thread->start_address = (void *)pe_entry; /* FIXME */ + + /* init apc, to call LdrInitializeThunk */ + thread_apc = kmalloc(sizeof(KAPC), GFP_KERNEL); + if (!thread_apc) { + retval = -ENOMEM; + goto out_free_thread_cid; + } + apc_init(thread_apc, + &thread->tcb, + OriginalApcEnvironment, + thread_special_apc, + NULL, + (PKNORMAL_ROUTINE)ntdll_entry, + UserMode, + (void *)(bprm->p + 12)); + insert_queue_apc(thread_apc, (void *)interp_entry, (void *)extra_page, IO_NO_INCREMENT); + set_tsk_thread_flag(current, TIF_APC); + +#ifdef ELF_PLAT_INIT + /* + * The ABI may specify that certain registers be set up in special + * ways (on i386 %edx is the address of a DT_FINI function, for + * example. In addition, it may also specify (eg, PowerPC64 ELF) + * that the e_entry field is the address of the function descriptor + * for the startup routine, rather than the address of the startup + * routine itself. This macro performs whatever initialization to + * the regs structure is required as well as any relocations to the + * function descriptor entries when executing dynamically links apps. + */ + ELF_PLAT_INIT(regs, reloc_func_desc); +#endif + + start_thread(regs, pe_entry, bprm->p); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } + + /* save current trap frame */ + thread->tcb.trap_frame = (struct ktrap_frame *)regs; + retval = 0; + + try_module_get(THIS_MODULE); + /* return from w32syscall_exit, not syscall_exit */ + ((unsigned long *)regs)[-1] = (unsigned long)w32syscall_exit; + regs->fs = TEB_SELECTOR; + +out: +#if 0 + if (displaced) + put_files_struct(displaced); +#endif + return retval; + + /* error cleanup */ +out_free_thread_cid: + delete_cid_handle(thread->cid.unique_thread, thread_object_type); +out_free_ethread: + deref_object(thread); +out_free_process_cid: + delete_cid_handle(process->unique_processid, process_object_type); +out_free_eproc: + deref_object(process); +out_free_file: +#if 0 + if (files) { + put_files_struct(current->files); + current->files = files; + } +#endif + + /* free win32_section, if not mapped */ + if (!maped && ws) { + if (ws->ws_sections) + kfree(ws->ws_sections); + kfree(ws); + } + send_sig(SIGKILL, current, 0); +#if 0 + if (displaced) + put_files_struct(displaced); +#endif + goto out; +} /* end load_pe_binary */ + + +int init_pe_binfmt(void) +{ + return insert_binfmt(&pe_format); +} + +void exit_pe_binfmt(void) +{ + /* Remove the COFF and ELF loaders. */ + unregister_binfmt(&pe_format); +} + +#endif diff --git a/unifiedkernel/ke/event.c b/unifiedkernel/ke/event.c new file mode 100644 index 0000000..a60f7d9 --- /dev/null +++ b/unifiedkernel/ke/event.c @@ -0,0 +1,570 @@ +/* + * event.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * event.c: event syscall functions + * Refered to Kernel-win32 code + */ + +#include +#include "event.h" +#include "process.h" +#include "thread.h" +#include "objwait.h" +#include "object.h" +#include "unistr.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +POBJECT_TYPE event_object_type = NULL; +EXPORT_SYMBOL(event_object_type); + +static GENERIC_MAPPING event_mapping = { + STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE, + STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE, + EVENT_ALL_ACCESS}; + +static WCHAR event_type_name[] = {'E', 'v', 'e', 'n', 't', 0}; + +extern VOID STDCALL event_init(struct kevent *event, enum event_type type, BOOLEAN state); + +extern void display_object_dir(POBJECT_DIRECTORY DirectoryObject, LONG Depth); + +extern HANDLE base_dir_handle; + +VOID +init_event_implement(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)event_type_name); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(struct kevent); + ObjectTypeInitializer.GenericMapping = event_mapping; + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = TRUE; + create_type_object(&ObjectTypeInitializer, &Name, &event_object_type); +} + +VOID +STDCALL +event_init(struct kevent *event, + enum event_type type, + BOOLEAN state) +{ + /* Initialize the Dispatcher Header */ + INIT_DISP_HEADER(&event->header, type, sizeof(event) / sizeof(ULONG), state); +} /* end event_init */ +EXPORT_SYMBOL(event_init); + +#if 0 +/* + * notify all waiters of event signal + * - returns 1 if no new waiter found (no change made) + */ +extern inline int event_notify_waiters(struct dispatcher_header *header) +{ + struct list_head *waiter; + int i = 0; + + ktrace("event_notify_waiters\n"); + spin_lock(&header->wait.lock); + + list_for_each(waiter, &header->wait.task_list) { + struct wait_table_entry *wte = + list_entry(waiter, + struct wait_table_entry, + wte_wait.task_list); + + /* set i to 1 if we change a bit */ + i |= test_and_set_bit(0, (unsigned long *)&wte->wte_data) ^ 1; + } + spin_unlock(&header->wait.lock); + + return ~i & 1; +} /* end event_notify_waiters() */ +#endif + +/* + * open a event object, creating if non-existent + */ +NTSTATUS +SERVICECALL +NtCreateEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState) + +{ + HANDLE Handle; + struct kevent *Event; + POBJECT_ATTRIBUTES obj_attr = NULL; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtCreateEvent\n"); + if (ObjectAttributes) { + if ((ULONG)ObjectAttributes < TASK_SIZE) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else { + obj_attr = ObjectAttributes; + } + } + + if (obj_attr) { + if (obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + } + + status = create_object(KernelMode, + event_object_type, + obj_attr, + KernelMode, + NULL, + sizeof(struct kevent), + 0, + 0, + (PVOID *)&Event); + + if (ObjectAttributes && (ULONG)ObjectAttributes < TASK_SIZE) + kfree(obj_attr); + + if (!NT_SUCCESS(status)) + return status; + + event_init(Event, EventType, InitialState); + + status = insert_object((PVOID)Event, + NULL, + DesiredAccess, + 0, + NULL, + &Handle); + + if (status == STATUS_OBJECT_NAME_EXISTS) { + goto event_exists; + } + + if (!NT_SUCCESS(status)) + return status; + +event_exists: + deref_object(Event); + + if (EventHandle) { + if ((ULONG)EventHandle < TASK_SIZE) { + if (copy_to_user(EventHandle, &Handle, sizeof(HANDLE))) + return STATUS_NO_MEMORY; + } + else + *EventHandle = Handle; + } + + return status; +} /* end NtCreateEvent() */ +EXPORT_SYMBOL(NtCreateEvent); + +/* + * open a event object, failing if non-existent + */ +NTSTATUS +SERVICECALL +NtOpenEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE handle; + POBJECT_ATTRIBUTES obj_attr = NULL; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtOpenEvent\n"); + if (ObjectAttributes) { + if ((ULONG)ObjectAttributes < TASK_SIZE) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else { + obj_attr = ObjectAttributes; + } + } + + if (obj_attr) { + if (obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + } + + status = open_object_by_name(obj_attr, + event_object_type, + NULL, + KernelMode, + DesiredAccess, + NULL, + &handle); + + if (ObjectAttributes && (ULONG)ObjectAttributes < TASK_SIZE) + kfree(obj_attr); + + if (!NT_SUCCESS(status)) + return status; + + if (EventHandle) { + if ((ULONG)EventHandle < TASK_SIZE) { + if (copy_to_user(EventHandle, &handle, sizeof(HANDLE))) + return STATUS_NO_MEMORY; + } + else + *EventHandle = &handle; + } + + return status; +}/* end NtOpenEvent() */ +EXPORT_SYMBOL(NtOpenEvent); + +LONG +STDCALL +set_event(struct kevent *Event, + KPRIORITY Increment, + BOOLEAN Wait) +{ + struct ethread *thread = get_current_ethread(); + LONG prev; + struct kwait_block *block; + + local_irq_disable(); + + prev = Event->header.signal_state; + + if (list_empty(&Event->header.wait_list_head)) + Event->header.signal_state = 1; + else { + block = list_entry(Event->header.wait_list_head.next, struct kwait_block, wait_list_entry); + + /* FIXME */ + if (prev == 0) { + Event->header.signal_state = 1; + wait_test(&Event->header, Increment); + } + } + + if (Wait == FALSE) + local_irq_enable(); + else + thread->tcb.wait_next = TRUE; + + return prev; +} +EXPORT_SYMBOL(set_event); + +/* + * set an event + */ +NTSTATUS +SERVICECALL +NtSetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState) +{ + struct kevent *event; + LONG prev; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtSetEvent, handle %p\n", EventHandle); + status = ref_object_by_handle(EventHandle, + EVENT_MODIFY_STATE, + event_object_type, + KernelMode, + (PVOID *)&event, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + prev = set_event(event, EVENT_INCREMENT, FALSE); + deref_object(event); + + if (PreviousState) { + if ((ULONG)PreviousState < TASK_SIZE) { + if (copy_to_user(PreviousState, &prev, sizeof(LONG))) + return STATUS_NO_MEMORY; + } + else + *PreviousState = prev; + } + + return status; +}/* end NtSetEvent() */ +EXPORT_SYMBOL(NtSetEvent); + +LONG +STDCALL +reset_event(struct kevent *Event) +{ + LONG prev; + + local_irq_disable(); + + prev = Event->header.signal_state; + Event->header.signal_state = 0; + + local_irq_enable(); + + return prev; +} +EXPORT_SYMBOL(reset_event); + +/* + * reset an event + */ +NTSTATUS +SERVICECALL +NtResetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState) +{ + struct kevent *event; + LONG prev; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtResetEvent, handle %p \n" ,EventHandle); + status = ref_object_by_handle(EventHandle, + EVENT_MODIFY_STATE, + event_object_type, + KernelMode, + (PVOID *)&event, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + prev = reset_event(event); + deref_object(event); + + if (PreviousState) { + if ((ULONG)PreviousState < TASK_SIZE) { + if (copy_to_user(PreviousState, &prev, sizeof(LONG))) + return STATUS_NO_MEMORY; + } + else + *PreviousState = prev; + } + + return STATUS_SUCCESS; +}/* end NtResetEvent() */ +EXPORT_SYMBOL(NtResetEvent); + +LONG +STDCALL +pulse_event(IN struct kevent *Event, + IN KPRIORITY Increment, + IN BOOLEAN Wait) +{ + struct ethread *thread = get_current_ethread(); + LONG prev; + + local_irq_disable(); + + prev = Event->header.signal_state; + + if (prev == 0 && !list_empty(&Event->header.wait_list_head)) { + Event->header.signal_state = 1; + wait_test(&Event->header, Increment); + } + + Event->header.signal_state = 0; + + if (Wait == FALSE) + local_irq_enable(); + else + thread->tcb.wait_next = TRUE; + + return prev; +} +EXPORT_SYMBOL(pulse_event); + +/* + * pulse an event + */ +NTSTATUS +SERVICECALL +NtPulseEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState) +{ + struct kevent *event; + long prev; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtPulseEvent\n"); + status = ref_object_by_handle(EventHandle, + EVENT_MODIFY_STATE, + event_object_type, + KernelMode, + (PVOID *)&event, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + prev = pulse_event(event, EVENT_INCREMENT, FALSE); + deref_object(event); + + if (PreviousState) { + if ((ULONG)PreviousState < TASK_SIZE) { + if (copy_to_user(PreviousState, &prev, sizeof(LONG))) + return STATUS_NO_MEMORY; + } + else + *PreviousState = prev; + } + + return status; +}/* end NtPulseEvent() */ +EXPORT_SYMBOL(NtPulseEvent); + +/* contributed by Welfear */ +VOID +STDCALL +clear_event(struct kevent *Event) +{ + Event->header.signal_state = 0; +} +EXPORT_SYMBOL(clear_event); + +NTSTATUS +SERVICECALL +NtClearEvent(IN HANDLE EventHandle + ) +{ + struct kevent *event; + NTSTATUS status; + + ktrace("NtClearEvent\n"); + + status = ref_object_by_handle(EventHandle, + EVENT_MODIFY_STATE, + event_object_type, + KernelMode, + (PVOID *)&event, + NULL); + if (NT_SUCCESS(status)) { + clear_event(event); + deref_object(event); + } + + return status; +} +EXPORT_SYMBOL(NtClearEvent); + +typedef struct _EVENT_BASIC_INFORMATION +{ + EVENT_TYPE EventType; + LONG EventState; +} EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION; + +LONG +STDCALL +query_event(IN struct kevent *Event + ) +{ + return Event->header.signal_state; +} +EXPORT_SYMBOL(query_event); + +NTSTATUS +SERVICECALL +NtQueryEvent(IN HANDLE EventHandle, + IN EVENT_INFORMATION_CLASS EventInformationClass, + OUT PVOID EventInformation, + IN ULONG EventInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + struct kevent *event; + NTSTATUS status; + ULONG return_length; + EVENT_BASIC_INFORMATION basic_info; + + + ktrace("NtQueryEvent, handle %p\n", EventHandle); + + if (EventInformationClass != 0 /*EventBasicInformation*/) { + return STATUS_INVALID_INFO_CLASS; + } + + if (EventInformationLength != sizeof(EVENT_BASIC_INFORMATION)) { + return STATUS_INFO_LENGTH_MISMATCH; + } + + if (EventInformation == NULL) { + return STATUS_INVALID_PARAMETER; /* may be exception code */ + } + + status = ref_object_by_handle(EventHandle, + EVENT_QUERY_STATE, + event_object_type, + KernelMode, + (PVOID *)&event, + NULL); + if (!NT_SUCCESS(status)) + return status; + + basic_info.EventState = query_event(event); + basic_info.EventType = event->header.type; + + return_length = sizeof(EVENT_BASIC_INFORMATION); + + deref_object(event); + + if ((ULONG)EventInformation < TASK_SIZE) { + if (copy_to_user(EventInformation, &basic_info, sizeof(EVENT_BASIC_INFORMATION))) + return STATUS_NO_MEMORY; + } else { + memcpy(EventInformation, &basic_info, sizeof(EVENT_BASIC_INFORMATION)); + } + + if (ReturnLength != NULL) { + if ((ULONG)ReturnLength < TASK_SIZE) { + if (copy_to_user(ReturnLength, &return_length, sizeof(ReturnLength))) + return STATUS_NO_MEMORY; + } else { + *ReturnLength = return_length; + } + } + + return status; +} +EXPORT_SYMBOL(NtQueryEvent); +/* contributed by Welfear */ + +/* stubs from Wine server */ +struct kevent *create_event( struct directory *root, const struct unicode_str *name, unsigned int attr, int manual_reset, int initial_state, const struct security_descriptor *sd ) +{ + return NULL; +} + +void set_fd_events( struct fd *fd, int events ) +{ +} +#endif diff --git a/unifiedkernel/ke/misc.c b/unifiedkernel/ke/misc.c new file mode 100644 index 0000000..19c0b8a --- /dev/null +++ b/unifiedkernel/ke/misc.c @@ -0,0 +1,81 @@ +/* + * misc.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * misc.c: + */ + +#include +#include +#include "win32.h" +#include "object.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#define WINNT_DAY_BEFORE 134774 /* days from 1601.1.1 to 1970.1.1 */ + +void query_sys_time(large_integer_t *CurrentTime) +{ + struct timespec unix_time; + long long temp; + + /* need EXPORT_SYMBOL. kernel/posix-timers.c */ + do_posix_clock_monotonic_gettime(&unix_time); + + temp = WINNT_DAY_BEFORE * 24; + CurrentTime->quad = (temp * 3600 + unix_time.tv_sec) * 10000000; + CurrentTime->quad += unix_time.tv_nsec / 100; +} +EXPORT_SYMBOL(query_sys_time); + + +/* stubs from Wine server */ +struct process_snapshot *process_snap( int *count ) +{ + return NULL; +} + +struct module_snapshot *module_snap( struct w32process *process, int *count ) +{ + return NULL; +} + +struct thread_snapshot *thread_snap( int *count ) +{ + return NULL; +} + +void enum_processes(int (*cb)(struct w32process*, void*), void *user) +{ +} + +struct object_type *no_get_type( struct object *obj ) +{ + kdebug("ERR: no_get_type() gets called!\n"); + return NULL; +} + +void no_destroy( struct object *obj ) +{ + kdebug("ERR: no_destroy() gets called!\n"); +} + +#endif diff --git a/unifiedkernel/ke/mutex.c b/unifiedkernel/ke/mutex.c new file mode 100644 index 0000000..0893550 --- /dev/null +++ b/unifiedkernel/ke/mutex.c @@ -0,0 +1,358 @@ +/* + * mutex.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * mutex.c: mutex syscall functions + * Refered to Kernel-win32 code + */ + +#include +#include "mutex.h" +#include "event.h" +#include "process.h" +#include "thread.h" +#include "objwait.h" +#include "object.h" +#include "unistr.h" +#include "apc.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +POBJECT_TYPE mutant_object_type = NULL; +EXPORT_SYMBOL(mutant_object_type); + +static GENERIC_MAPPING mutant_mapping = { + STANDARD_RIGHTS_READ | SYNCHRONIZE | MUTANT_QUERY_STATE, + STANDARD_RIGHTS_WRITE | SYNCHRONIZE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | MUTANT_QUERY_STATE, + MUTANT_ALL_ACCESS}; + +static WCHAR mutant_type_name[] = {'M', 'u', 't', 'a', 'n', 't', 0}; + +extern void display_object_dir(POBJECT_DIRECTORY DirectoryObject, LONG Depth); + +extern HANDLE base_dir_handle; + +VOID +init_mutant_implement(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)mutant_type_name); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(struct kmutant); + ObjectTypeInitializer.GenericMapping = mutant_mapping; + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = TRUE; + ObjectTypeInitializer.DeleteProcedure = delete_mutant; + create_type_object(&ObjectTypeInitializer, &Name, &mutant_object_type); +} + +VOID +STDCALL +mutant_init(IN struct kmutant* Mutant, + IN BOOLEAN InitialOwner) +{ + ULONG Signaled = TRUE; + struct ethread* thread = NULL; + + if (InitialOwner == TRUE) { + Signaled = FALSE; + + thread = get_current_ethread(); + + local_irq_disable(); + list_add_tail(&Mutant->mutant_list_entry, &thread->tcb.mutant_list_head); + local_irq_enable(); + } + + INIT_DISP_HEADER(&Mutant->header, + MutantObject, + sizeof(struct kmutant) / sizeof(ULONG), + Signaled); + + Mutant->owner_thread = (struct kthread *)thread; + Mutant->abandoned = FALSE; + Mutant->apc_disable = 0; +} +EXPORT_SYMBOL(mutant_init); + +/* + * open a mutex object, creating if non-existent + */ +NTSTATUS +SERVICECALL +NtCreateMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN InitialOwner) +{ + HANDLE hMutant; + struct kmutant* Mutant; + NTSTATUS Status = STATUS_SUCCESS; + POBJECT_ATTRIBUTES obj_attr = NULL; + + ktrace("NtCreateMutant\n"); + if (ObjectAttributes) { + if ((ULONG)ObjectAttributes < TASK_SIZE) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else { + obj_attr = ObjectAttributes; + } + } + + if (obj_attr) { + if (obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + } + + Status = create_object(KernelMode, + mutant_object_type, + obj_attr, + KernelMode, + NULL, + sizeof(struct kmutant), + 0, + 0, + (PVOID *)&Mutant); + + if (ObjectAttributes && (ULONG)ObjectAttributes < TASK_SIZE) + kfree(obj_attr); + + if (!NT_SUCCESS(Status)) + return Status; + + mutant_init(Mutant, InitialOwner); + + Status = insert_object((PVOID)Mutant, + NULL, + DesiredAccess, + 0, + NULL, + &hMutant); + + if (Status == STATUS_OBJECT_NAME_EXISTS) { + goto mutant_exists; + } + + if (!NT_SUCCESS(Status)) + return Status; + +mutant_exists: + deref_object(Mutant); + + if (MutantHandle) { + if ((ULONG)MutantHandle < TASK_SIZE) { + if (copy_to_user(MutantHandle, &hMutant, sizeof(HANDLE))) + Status = STATUS_NO_MEMORY; + } + else + *MutantHandle = hMutant; + } + + return Status; +} /* end NtCreateMutant() */ +EXPORT_SYMBOL(NtCreateMutant); + +/* + * open a mutex object, failing if non-existent + */ +NTSTATUS +SERVICECALL +NtOpenMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hMutant; + POBJECT_ATTRIBUTES obj_attr = NULL; + NTSTATUS Status = STATUS_SUCCESS; + + ktrace("NtOpenMutant\n"); + if (ObjectAttributes) { + if ((ULONG)ObjectAttributes < TASK_SIZE) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else { + obj_attr = ObjectAttributes; + } + } + + if (obj_attr) { + if (obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + } + + Status = open_object_by_name(obj_attr, + mutant_object_type, + NULL, + KernelMode, + DesiredAccess, + NULL, + &hMutant); + + if (ObjectAttributes && (ULONG)ObjectAttributes < TASK_SIZE) + kfree(obj_attr); + + if (!NT_SUCCESS(Status)) + return Status; + + if (MutantHandle) { + if ((ULONG)MutantHandle < TASK_SIZE) { + if ((copy_to_user(MutantHandle, &hMutant, sizeof(HANDLE)))) + return STATUS_NO_MEMORY; + } + else + *MutantHandle = hMutant; + } + + return Status; +} /* end NtOpenMutant() */ +EXPORT_SYMBOL(NtOpenMutant); + +LONG +STDCALL +release_mutant(IN struct kmutant *Mutant, + IN KPRIORITY Increment, + IN BOOLEAN Abandon, + IN BOOLEAN Wait) +{ + struct ethread *thread = get_current_ethread(); + LONG prev; + + local_irq_disable(); + prev = Mutant->header.signal_state; + + if (Abandon == FALSE) + Mutant->header.signal_state++; + else { + Mutant->header.signal_state = 1; + Mutant->abandoned = TRUE; + } + + if (Mutant->header.signal_state == 1) { + if (prev <= 0) { + list_del(&Mutant->mutant_list_entry); + + thread->tcb.kernel_apc_disable += Mutant->apc_disable; + } + + Mutant->owner_thread = NULL; + + if (!list_empty(&Mutant->header.wait_list_head)) + wait_test(&Mutant->header, Increment); + } + + if (Wait == FALSE) + local_irq_enable(); + else + thread->tcb.wait_next = TRUE; + + return prev; +} +EXPORT_SYMBOL(release_mutant); + +/* + * release the state of a mutex + */ +NTSTATUS +SERVICECALL +NtReleaseMutant(IN HANDLE MutantHandle, + OUT PLONG PreviousCount OPTIONAL) +{ + struct ethread *thread = get_current_ethread(); + struct kmutant *mutant; + LONG prev; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtReleaseMutant\n"); + if(!thread) + return STATUS_UNSUCCESSFUL; + + status = ref_object_by_handle(MutantHandle, + MUTANT_QUERY_STATE, + mutant_object_type, + KernelMode, + (PVOID *)&mutant, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + prev = release_mutant(mutant, + MUTANT_INCREMENT, + FALSE, + FALSE); + deref_object(mutant); + + if (PreviousCount) { + if ((ULONG)PreviousCount < TASK_SIZE) { + if ((copy_to_user(PreviousCount, &prev, sizeof(ULONG)))) + return STATUS_NO_MEMORY; + } + else + *PreviousCount = prev; + } + + return status; +} /* end NtReleaseMutant() */ +EXPORT_SYMBOL(NtReleaseMutant); + +VOID +delete_mutant(PVOID ObjectBody) +{ + release_mutant((struct kmutant *)ObjectBody, + MUTANT_INCREMENT, + TRUE, + FALSE); +} +EXPORT_SYMBOL(delete_mutant); + +VOID +acquire_fmutex_unsafe(PFAST_MUTEX FastMutex) +{ + atomic_inc(&FastMutex->Contention); + while (xchg(&FastMutex->Count, 0) == 0) + wait_for_single_object(&FastMutex->Event, + Executive, + KernelMode, + FALSE, + NULL); + atomic_dec(&FastMutex->Contention); + FastMutex->Owner = (struct kthread *)get_current_ethread(); +} + +VOID +release_fmutex_unsafe(PFAST_MUTEX FastMutex) +{ + FastMutex->Owner = NULL; + xchg(&FastMutex->Count, 1); + if (atomic_read(&FastMutex->Contention) > 0) + set_event(&FastMutex->Event, 0, FALSE); +} +#endif diff --git a/unifiedkernel/ke/proc.c b/unifiedkernel/ke/proc.c new file mode 100644 index 0000000..1dee30e --- /dev/null +++ b/unifiedkernel/ke/proc.c @@ -0,0 +1,316 @@ +/* + * proc.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * proc.c: proc functions + * Refered to ReactOS code + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "process.h" + +#if defined(CONFIG_EXPRESS_IPC) || defined(CONFIG_UNIFIED_KERNEL) + +static int uk_proc_calc_metrics(char *page, char **start, + off_t off, int count, int *eof, int len) +{ + if (len <= off+count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +#endif + + +#ifdef CONFIG_EXPRESS_IPC + +struct proc_vip_file { + struct list_head entry; + char *filename; +}; + +LIST_HEAD(vip_file_list); + +static struct proc_dir_entry *proc_vip_dir = NULL; + +extern struct dentry *proc_eipc_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd); +extern void set_eipc(char *filename, int set); +extern int print_eipc_entry(char *filename, char *buf); +extern int add_vip_entry(char *filename); +extern int del_vip_entry(char *filename); + +static int vip_read_proc(char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + int len; + struct proc_vip_file *vip_file = (struct proc_vip_file *)data; + + len = print_eipc_entry(vip_file->filename, page); + return uk_proc_calc_metrics(page, start, off, count, eof, len); +} + +static int create_proc_vip_entry(char *filename) +{ + struct proc_dir_entry *proc_vip_entry; + struct proc_vip_file *vip_file; + + vip_file = (struct proc_vip_file *)kmalloc(sizeof(*vip_file), GFP_KERNEL); + if (!vip_file) + return -ENOMEM; + vip_file->filename = filename; + list_add_tail(&vip_file->entry, &vip_file_list); + + proc_vip_entry = create_proc_read_entry(filename, 0, proc_vip_dir, vip_read_proc, vip_file); + if (!proc_vip_entry) + return -ENOMEM; + + proc_vip_entry->owner = THIS_MODULE; + + return 0; +} + +static int proc_vip_create(struct inode *ip, struct dentry *dp, int mode, struct nameidata *nd) +{ + int ret = create_proc_vip_entry((char *)dp->d_name.name); + + if (!ret) { + add_vip_entry((char *)dp->d_name.name); + set_eipc((char *)dp->d_name.name, 1); + } + return ret; +} + +static int proc_vip_unlink(struct inode *ip, struct dentry *dp) +{ + struct proc_dir_entry *pde = PDE(ip); + struct proc_vip_file *vip_file; + + vip_file = (struct proc_vip_file *)pde->data; + list_del(&vip_file->entry); + + set_eipc((char *)dp->d_name.name, 0); + del_vip_entry((char *)dp->d_name.name); + remove_proc_entry(dp->d_name.name, proc_vip_dir); + + return 0; +} + +static struct inode_operations proc_vip_inode_operations = { + .create = proc_vip_create, + .lookup = proc_eipc_lookup, + .unlink = proc_vip_unlink +}; + +int proc_vip_init(void) +{ + proc_vip_dir = proc_mkdir_mode("eipc", S_IALLUGO, NULL); /* create "/proc/eipc" */ + if (!proc_vip_dir) + return -ENOMEM; + proc_vip_dir->owner = THIS_MODULE; + proc_vip_dir->proc_iops = &proc_vip_inode_operations; + + return 0; +} + +void proc_vip_exit(void) +{ + struct list_head *pos; + struct proc_vip_file *vip_file; + + if (proc_vip_dir) { + if (!list_empty_careful(&vip_file_list)) { + pos = vip_file_list.next; + list_del(pos); + vip_file = list_entry(pos, struct proc_vip_file, entry); + remove_proc_entry(vip_file->filename, proc_vip_dir); + } + remove_proc_entry("eipc", NULL); + } +} + +#endif /* CONFIG_EXPRESS_IPC */ + +#ifdef CONFIG_UNIFIED_KERNEL + +static struct proc_dir_entry *proc_uk = NULL; +static struct proc_dir_entry *proc_uk_io = NULL; +static struct proc_dir_entry *proc_uk_mm = NULL; + +/* built-in so path */ +extern char builtin_dll_path[MAX_PATH]; +/* built-in so path */ + +extern size_t print_dosdriver(char *buf); +extern int parse_dosdriver(char *buf, size_t count, int append); + +static int dosdriver_read_proc(char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + int len; + + len = print_dosdriver(page); + return uk_proc_calc_metrics(page, start, off, count, eof, len); +} + +static int dosdriver_write_proc(struct file *file, const char __user *buf, unsigned long count, void *data) +{ + int append; + int ret = count; + char *page; + + if (count > PAGE_SIZE) + return -EINVAL; + + page = (char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + if (copy_from_user(page, buf, count)) { + ret = -EFAULT; + goto out; + } + + append = file->f_flags & O_APPEND; + parse_dosdriver(page, count, append); + +out: + free_page((unsigned long)page); + return ret; +} + +/* built-in so path */ +static int builtin_dll_read_proc(char *page, char **start, + off_t off, int count, int *eof, void *data) +{ + int len = strlen(builtin_dll_path); + char ent[] = {'\n', 0}; + + memcpy(page, builtin_dll_path, len); + memcpy(page + len, ent, strlen(ent)); + return uk_proc_calc_metrics(page, start, off, count, eof, len + 1); +} + +static int builtin_dll_write_proc(struct file *file, const char __user *buf, unsigned long count, void *data) +{ + int ret = count; + char *page; + + if (count > MAX_PATH) + return -EINVAL; + + page = (char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + if (copy_from_user(page, buf, count)) { + ret = -EFAULT; + goto out; + } + + memcpy(builtin_dll_path, page, count); +out: + free_page((unsigned long)page); + return ret; +} +/* built-in so path */ + +int proc_uk_init(void) +{ + struct proc_dir_entry *dosdriver_entry; + /* built-in so path */ + struct proc_dir_entry *builtin_dll_entry; + /* built-in so path */ + + proc_uk = proc_mkdir("unifiedkernel", NULL); /* create "/proc/unifiedkernel" */ + if (!proc_uk) + goto out; + + proc_uk_io = proc_mkdir("unifiedkernel/io", NULL); + if (!proc_uk_io) + goto out_free_proc_uk; + + proc_uk_mm = proc_mkdir("unifiedkernel/mm", NULL); + if (!proc_uk_mm) + goto out_free_proc_uk_io; + + dosdriver_entry = create_proc_entry("dosdriver", S_IRUSR | S_IWUSR, proc_uk_io); + if (!dosdriver_entry) + goto out_free_proc_uk_mm; + dosdriver_entry->read_proc = dosdriver_read_proc; + dosdriver_entry->write_proc = dosdriver_write_proc; + + /* built-in so path */ + builtin_dll_entry = create_proc_entry("builtin_dll", S_IRUSR | S_IWUSR, proc_uk); + if (!builtin_dll_entry) + goto out_free_dosdriver; + builtin_dll_entry->read_proc = builtin_dll_read_proc; + builtin_dll_entry->write_proc = builtin_dll_write_proc; + /* built-in so path */ + + return 0; + +out_free_dosdriver: + remove_proc_entry("dosdriver", proc_uk_io); +out_free_proc_uk_mm: + remove_proc_entry("unifiedkernel/mm", NULL); +out_free_proc_uk_io: + remove_proc_entry("unifiedkernel/io", NULL); +out_free_proc_uk: + remove_proc_entry("unifiedkernel", NULL); +out: + return -ENOMEM; +} + +void proc_uk_exit(void) +{ + if (proc_uk_io) { + remove_proc_entry("dosdriver", proc_uk_io); + remove_proc_entry("unifiedkernel/io", NULL); + } + + if (proc_uk_mm) + remove_proc_entry("unifiedkernel/mm", NULL); + + if (proc_uk) { + /* built-in so path */ + remove_proc_entry("builtin_dll", proc_uk); + /* built-in so path */ + remove_proc_entry("unifiedkernel", NULL); + } +} + +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/ke/semaphore.c b/unifiedkernel/ke/semaphore.c new file mode 100644 index 0000000..9bc2900 --- /dev/null +++ b/unifiedkernel/ke/semaphore.c @@ -0,0 +1,302 @@ +/* + * semaphore.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * semaphore.c: semaphore syscall functions + * Refered to Kernel-win32 code + */ + +#include "semaphore.h" +#include "unistr.h" +#include "apc.h" +#include "object.h" +#include "objwait.h" +#include "ntstatus.h" +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +POBJECT_TYPE semaphore_object_type = NULL; +EXPORT_SYMBOL(semaphore_object_type); + +static GENERIC_MAPPING semaphore_mapping = { + STANDARD_RIGHTS_READ | SEMAPHORE_QUERY_STATE, + STANDARD_RIGHTS_WRITE | SEMAPHORE_MODIFY_STATE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | SEMAPHORE_QUERY_STATE, + SEMAPHORE_ALL_ACCESS}; + +static WCHAR semaphore_type_name[] = {'S', 'e', 'm', 'a', 'p', 'h', 'o', 'r', 'e', 0}; + +extern HANDLE base_dir_handle; + +VOID +init_semaphore_implement(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)semaphore_type_name); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(struct ksemaphore); + ObjectTypeInitializer.GenericMapping = semaphore_mapping; + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.ValidAccessMask = SEMAPHORE_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = TRUE; + create_type_object(&ObjectTypeInitializer, &Name, &semaphore_object_type); +} + +VOID +STDCALL +semaphore_init(struct ksemaphore* Semaphore, + LONG Count, + LONG Limit) +{ + INIT_DISP_HEADER(&Semaphore->header, + SemaphoreObject, + sizeof(struct ksemaphore) / sizeof(ULONG), + Count); + + Semaphore->limit = Limit; +} +EXPORT_SYMBOL(semaphore_init); + +/* + * open a semaphore object, creating if non-existent + */ +NTSTATUS +SERVICECALL +NtCreateSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN LONG InitialCount, + IN LONG MaximumCount) +{ + HANDLE hSemaphore; + struct ksemaphore* Semaphore; + POBJECT_ATTRIBUTES obj_attr = NULL; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtCreateSemaphore\n"); + if (ObjectAttributes) { + if ((ULONG)ObjectAttributes < TASK_SIZE) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else { + obj_attr = ObjectAttributes; + } + } + + if (obj_attr) { + if (obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + } + + status = create_object(KernelMode, + semaphore_object_type, + obj_attr, + KernelMode, + NULL, + sizeof(struct ksemaphore), + 0, + 0, + (PVOID *)&Semaphore); + + if (ObjectAttributes && (ULONG)ObjectAttributes < TASK_SIZE) + kfree(obj_attr); + + if (!NT_SUCCESS(status)) + return status; + + semaphore_init(Semaphore, + InitialCount, + MaximumCount); + + status = insert_object((PVOID)Semaphore, + NULL, + DesiredAccess, + 0, + NULL, + &hSemaphore); + + if (status == STATUS_OBJECT_NAME_EXISTS) { + goto semaphore_exists; + } + + if (!NT_SUCCESS(status)) + return status; + +semaphore_exists: + deref_object(Semaphore); + + if (SemaphoreHandle) { + if ((ULONG)SemaphoreHandle < TASK_SIZE) { + if((copy_to_user(SemaphoreHandle, &hSemaphore, sizeof(HANDLE)))) + return STATUS_NO_MEMORY; + } + else + *SemaphoreHandle = hSemaphore; + } + + ktrace("*** [%d] CreateSemaphore(%d,%d) = %p\n", + current->pid, InitialCount, MaximumCount, hSemaphore); + + return status; +} +EXPORT_SYMBOL(NtCreateSemaphore); + +/* + * open a semaphore object, failing if non-existent + */ +NTSTATUS +SERVICECALL +NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hSemaphore; + POBJECT_ATTRIBUTES obj_attr = NULL; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtOpenSemaphore\n"); + if (ObjectAttributes) { + if ((ULONG)ObjectAttributes < TASK_SIZE) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else { + obj_attr = ObjectAttributes; + } + } + + if (obj_attr) { + if (obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + } + + status = open_object_by_name(obj_attr, + semaphore_object_type, + NULL, + KernelMode, + DesiredAccess, + NULL, + &hSemaphore); + + if (ObjectAttributes && (ULONG)ObjectAttributes < TASK_SIZE) + kfree(obj_attr); + + if (!NT_SUCCESS(status)) + return status; + + if (SemaphoreHandle) { + if ((ULONG)SemaphoreHandle < TASK_SIZE) { + if ((copy_to_user(SemaphoreHandle, &hSemaphore, sizeof(HANDLE)))) + return STATUS_NO_MEMORY; + } + else + *SemaphoreHandle = hSemaphore; + } + + return status; +} +EXPORT_SYMBOL(NtOpenSemaphore); + +LONG +STDCALL +release_semaphore(struct ksemaphore *Semaphore, + KPRIORITY Increment, + LONG Adjustment, + BOOLEAN Wait) +{ + struct ethread *thread = get_current_ethread(); + LONG old; + + local_irq_disable(); + + old = Semaphore->header.signal_state; + Semaphore->header.signal_state = old + Adjustment; + if (Semaphore->header.signal_state > Semaphore->limit) + { + Semaphore->header.signal_state = Semaphore->limit; + } + + if (old == 0 && !list_empty(&Semaphore->header.wait_list_head)) + wait_test(&Semaphore->header, Increment); + + if (Wait == FALSE) + local_irq_enable(); + else + thread->tcb.wait_next = TRUE; + + /* FIXME: shouldn't return a NTSTATUS here */ + if (old + Adjustment > Semaphore->limit || Adjustment <= 0) return STATUS_SEMAPHORE_LIMIT_EXCEEDED; + else return old; +} +EXPORT_SYMBOL(release_semaphore); + +/* + * release a semaphore (increment count up to max limit) + */ +NTSTATUS +SERVICECALL +NtReleaseSemaphore(IN HANDLE SemaphoreHandle, + IN LONG ReleaseCount, + OUT PLONG PreviousCount OPTIONAL) +{ + struct ksemaphore* semaphore; + LONG old; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtReleaseSemaphore\n"); + if (ReleaseCount <= 0 || ReleaseCount > 0x7FFFFFFF) + return STATUS_UNSUCCESSFUL; + status = ref_object_by_handle(SemaphoreHandle, + SEMAPHORE_MODIFY_STATE, + semaphore_object_type, + KernelMode, + (PVOID *)&semaphore, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + old = release_semaphore(semaphore, + IO_NO_INCREMENT, + ReleaseCount, + FALSE); + deref_object(semaphore); + + if (PreviousCount) { + if ((ULONG)PreviousCount < TASK_SIZE) { + if ((copy_to_user(PreviousCount, &old, sizeof(LONG)))) + return STATUS_NO_MEMORY; + } + else + *PreviousCount = old; + } + + return status; +} +EXPORT_SYMBOL(NtReleaseSemaphore); +#endif diff --git a/unifiedkernel/ke/switch.S b/unifiedkernel/ke/switch.S new file mode 100644 index 0000000..ab41a16 --- /dev/null +++ b/unifiedkernel/ke/switch.S @@ -0,0 +1,59 @@ +/* + * switch.S + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * switch.S: switch to new waken thread + */ + +#include +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +ENTRY(thread_startup) + CFI_STARTPROC + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + call schedule_tail + CFI_ADJUST_CFA_OFFSET 4 + popl %eax # used? + CFI_ADJUST_CFA_OFFSET 4 + popl %ebx # popup SystemRoutine + CFI_ADJUST_CFA_OFFSET 4 + popl %eax # popup StartRoutine + CFI_ADJUST_CFA_OFFSET 4 + popl %edx # popup StartContext + CFI_ADJUST_CFA_OFFSET 4 + call *%ebx + CFI_ADJUST_CFA_OFFSET 4 + GET_THREAD_INFO(%ebp) + CFI_ADJUST_CFA_OFFSET -4 + pushl $0x0202 # Reset kernel eflags + CFI_ADJUST_CFA_OFFSET 4 + popfl + CFI_ADJUST_CFA_OFFSET -4 + jmp w32syscall_exit + CFI_ENDPROC +END(thread_startup) + +#endif diff --git a/unifiedkernel/ke/sysdll.c b/unifiedkernel/ke/sysdll.c new file mode 100644 index 0000000..b671419 --- /dev/null +++ b/unifiedkernel/ke/sysdll.c @@ -0,0 +1,479 @@ +/* + * sysdll.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * sysdll.c: + * Refered to Reactos Kernel code + */ +#include "win32_process.h" +#include +#include +#include +#include +#include +#include +#include "win32.h" +#include "thread.h" +#include "pefile.h" +#include "file.h" +#include "section.h" +#include "attach.h" +#include "virtual.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), (s) } +#define INIT_OBJECT_ATTR(p,n,a,r,s) { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = (r); \ + (p)->Attributes = (a); \ + (p)->ObjectName = (n); \ + (p)->SecurityDescriptor = (s); \ + (p)->SecurityQualityOfService = NULL; \ +} + +#if ELF_CLASS == ELFCLASS32 +#define elf_shdr Elf32_Shdr +#define elf_sym elf32_sym +#define elf_off_t Elf32_Off +#define elf_half_t Elf32_Half +#else +#define elf_shdr Elf64_Shdr +#define elf_sym elf64_sym +#define elf_off_t Elf64_Off +#define elf_half_t Elf64_Half +#endif + +elf_off_t ntdll_phoff; +elf_half_t ntdll_phnum; + +#define ELF_EXEC_PAGESIZE 4096 + +#if ELF_EXEC_PAGESIZE > PAGE_SIZE +# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE +#else +# define ELF_MIN_ALIGN PAGE_SIZE +#endif + +#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) +#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) +#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) + +static int sym_count = 0; + +static unsigned long ntdll_entry; +static unsigned long interp_entry; +static unsigned long pe_entry; +static unsigned long start_thunk; +static unsigned long apc_dispatcher; +static unsigned long thread_entry; +#ifdef EXE_SO +static unsigned long ntdll_start_thunk; +static unsigned long exeso_start_thunk; +#endif + +static int padzero(struct task_struct *tsk, unsigned long bss) +{ + int ret = 0; + unsigned long nbyte; + struct mm_struct *mm = NULL; + + nbyte = ELF_PAGEOFFSET(bss); + if (nbyte) { + nbyte = ELF_MIN_ALIGN - nbyte; + if (tsk == current) { + if (clear_user((void __user *) bss, nbyte)) + ret = -EFAULT; + } + else { + struct eprocess *process = tsk->ethread->threads_process; + mm = attach_process(&process->pcb); + if (clear_user((void __user *) bss, nbyte)) + ret = -EFAULT; + detach_process(mm); + } + } + + return ret; +} + +static inline unsigned long win32_do_mmap(struct task_struct *tsk, + struct file *file, unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flag, unsigned long offset) +{ + unsigned long ret = -EINVAL; + + if ((offset + PAGE_ALIGN(len)) < offset) + goto out; + if (!(offset & ~PAGE_MASK)) + ret = win32_do_mmap_pgoff(tsk, file, addr, len, prot, flag, offset >> PAGE_SHIFT); + +out: + return ret; +} /* end win32_do_mmap */ + +static inline unsigned long elf_map(struct task_struct *tsk, struct file *filep, + unsigned long addr, struct elf_phdr *eppnt, int prot, int type) +{ + return win32_do_mmap(tsk, filep, ELF_PAGESTART(addr), + eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, + eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); +} /* end elf_map */ + +static unsigned long load_elf_interp(struct task_struct *tsk, + struct elfhdr * interp_elf_ex, + struct file * interpreter, + unsigned long *interp_load_addr, + char *ld_name) +{ + struct elf_phdr *elf_phdata; + struct elf_phdr *eppnt; + unsigned long load_addr = 0; + int load_addr_set = 0; + unsigned long last_bss = 0, elf_bss = 0; + unsigned long error = ~0UL; + int retval, i, size; + + /* First of all, some simple consistency checks */ + if (interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) + goto out; + if (!elf_check_arch(interp_elf_ex)) + goto out; + if (!interpreter->f_op || !interpreter->f_op->mmap) + goto out; + + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) + goto out; + if (interp_elf_ex->e_phnum < 1 || + interp_elf_ex->e_phnum > 65536U / sizeof(struct elf_phdr)) + goto out; + + /* Now read in all of the header information */ + + size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum; + if (size > ELF_MIN_ALIGN) + goto out; + elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL); + if (!elf_phdata) + goto out; + + retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size); + error = -EIO; + if (retval != size) { + if (retval < 0) + error = retval; + goto out_close; + } + + eppnt = elf_phdata; + for (i=0; ie_phnum; i++, eppnt++) { + if (eppnt->p_type == PT_INTERP && ld_name) + kernel_read(interpreter, eppnt->p_offset, ld_name, eppnt->p_filesz); + + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + unsigned long k, map_addr; + + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ | PROT_WRITE; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + vaddr = eppnt->p_vaddr; + if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) + elf_type |= MAP_FIXED; + + map_addr = elf_map(tsk, interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); + error = map_addr; + if (map_addr > (unsigned long)TASK_SIZE) + goto out_close; + + if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { + load_addr = map_addr - ELF_PAGESTART(vaddr); + *interp_load_addr = map_addr - eppnt->p_offset; + load_addr_set = 1; + } + + /* + * Check to see if the section's size will overflow the + * allowed task size. Note that p_filesz must always be + * <= p_memsize so it is only necessary to check p_memsz. + */ + k = load_addr + eppnt->p_vaddr; + if (k > TASK_SIZE || eppnt->p_filesz > eppnt->p_memsz || + eppnt->p_memsz > TASK_SIZE || TASK_SIZE - eppnt->p_memsz < k) { + error = -ENOMEM; + goto out_close; + } + + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) + last_bss = k; + } + } + + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zero-mapped pages up to and including the + * last bss page. + */ + if (padzero(tsk, elf_bss)) { + error = -EFAULT; + goto out_close; + } + + elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) { + error = win32_do_mmap_pgoff(tsk, NULL, elf_bss, last_bss - elf_bss, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0); + if (error > (unsigned long)TASK_SIZE) + goto out_close; + } + + error = ((unsigned long) interp_elf_ex->e_entry) + load_addr; + +out_close: + kfree(elf_phdata); +out: + return error; +} /* end load_elf_interp */ + +unsigned long uk_find_symbol(elf_shdr *elf_shdata, int shnum, char *sym) +{ + int link = -1; + int str_tab_size = 0; + char *str_tab = NULL; + elf_shdr *elf_spnt; + struct elf_sym *sympnt, *sym_tab = NULL; + unsigned long sym_addr = -EINVAL; + + for (elf_spnt = elf_shdata; elf_spnt < elf_shdata + shnum; elf_spnt++) { + if (elf_spnt->sh_type == SHT_DYNSYM) { + sym_tab = (struct elf_sym *)(elf_spnt->sh_addr); + link = elf_spnt->sh_link; + sym_count = elf_spnt->sh_size / sizeof(struct elf_sym); + } + } + + if (link >= 0) { + elf_spnt = elf_shdata + link; + if (elf_spnt->sh_type != SHT_STRTAB) + return -ENOEXEC; + + str_tab = (char *)(elf_spnt->sh_addr); + str_tab_size = elf_spnt->sh_size; + } + + if (sym_tab && str_tab) { + for (sympnt = sym_tab; sympnt < sym_tab + sym_count; sympnt++) { + if (sympnt->st_name > str_tab_size) + break; + if (!strcmp(sympnt->st_name + str_tab, sym)) { + sym_addr = sympnt->st_value; + break; + } + } + } + + return sym_addr; +} /* end uk_find_symbol */ +EXPORT_SYMBOL(uk_find_symbol); + +unsigned long get_ntdll_entry(void) +{ + return ntdll_entry; +} +EXPORT_SYMBOL(get_ntdll_entry); + +unsigned long get_thread_entry(void) +{ + return thread_entry; +} +EXPORT_SYMBOL(get_thread_entry); + +unsigned long get_apc_dispatcher(void) +{ + return apc_dispatcher; +} +EXPORT_SYMBOL(get_apc_dispatcher); + +unsigned long get_pe_entry(void) +{ + return pe_entry; +} +EXPORT_SYMBOL(get_pe_entry); + +unsigned long get_interp_entry(void) +{ + return interp_entry; +} +EXPORT_SYMBOL(get_interp_entry); + +unsigned long get_start_thunk(void) +{ + return start_thunk; +} +EXPORT_SYMBOL(get_start_thunk); + +#ifdef EXE_SO +unsigned long get_ntdll_start_thunk(void) +{ + return ntdll_start_thunk; +} + +unsigned long get_exeso_start_thunk(void) +{ + return exeso_start_thunk; +} +#endif + +LONG STDCALL map_system_dll(struct task_struct *tsk, char *name, + unsigned long *ntdll_load_addr, unsigned long *interp_load_addr) +{ + NTSTATUS retval; + struct file *interpreter = NULL, *ntdll = NULL; + struct elfhdr ntdll_elf_ex, interp_elf_ex; + char buf[BINPRM_BUF_SIZE]; + char ld_name[32]; + + ntdll = open_exec(name); + retval = PTR_ERR(ntdll); + if (IS_ERR(ntdll)) + goto out; + + /* read 128 Byte ELF header */ + retval = kernel_read(ntdll, 0, buf, BINPRM_BUF_SIZE); + if (retval != BINPRM_BUF_SIZE) { + if (retval >= 0) + retval = -EIO; + goto out_free_ntdll; + } + + /* Get the exec headers */ + ntdll_elf_ex = *((struct elfhdr *)buf); + ntdll_phoff = ntdll_elf_ex.e_phoff; + ntdll_phnum = ntdll_elf_ex.e_phnum; + + load_elf_interp(tsk, &ntdll_elf_ex, ntdll, ntdll_load_addr, ld_name); + + if (tsk == current) { + int elf_shnum; + int elf_shsize; + elf_shdr *elf_shdata = NULL; + + /* section header is not mapped to memory, need read it */ + /* load section header list for ntdll */ + elf_shnum = ntdll_elf_ex.e_shnum; + elf_shsize = elf_shnum * ntdll_elf_ex.e_shentsize; + elf_shdata = (elf_shdr *)kmalloc(elf_shsize, GFP_KERNEL); + if (!elf_shdata) { + retval = -ENOMEM; + goto out_free_ntdll; + } + + retval = kernel_read(ntdll, ntdll_elf_ex.e_shoff, (void *)elf_shdata, elf_shsize); + if (retval != elf_shsize) { + if (retval >= 0) + retval = -EIO; + kfree(elf_shdata); + goto out_free_ntdll; + } + + /* LdrInitializeThunk is used to load dll for PE exe file */ + ntdll_entry = uk_find_symbol(elf_shdata, elf_shnum, "LdrInitializeThunk"); + /* when interpreter done, jump to StartThunk */ + start_thunk = uk_find_symbol(elf_shdata, elf_shnum, "StartThunk"); + /* KiUserApcDispatcher is APC Dispatcher */ + apc_dispatcher = uk_find_symbol(elf_shdata, elf_shnum, "KiUserApcDispatcher"); + /* a forward function , will call BaseProcessStart in kernel32.dll.so */ + pe_entry = uk_find_symbol(elf_shdata, elf_shnum, "ProcessStartForward"); + thread_entry = uk_find_symbol(elf_shdata, elf_shnum, "start_thread"); +#ifdef EXE_SO + ntdll_start_thunk = uk_find_symbol(elf_shdata, elf_shnum, "ntdll_start_thunk"); + exeso_start_thunk = uk_find_symbol(elf_shdata, elf_shnum, "exeso_start_thunk"); +#endif + + kfree(elf_shdata); + } + + allow_write_access(ntdll); + fput(ntdll); + + interpreter = open_exec(ld_name); + retval = PTR_ERR(interpreter); + if (IS_ERR(interpreter)) + goto out; + + retval = kernel_read(interpreter, 0, buf, BINPRM_BUF_SIZE); + if (retval != BINPRM_BUF_SIZE) { + if (retval >= 0) + retval = -EIO; + goto out_free_interp; + } + + /* Get the exec headers */ + interp_elf_ex = *((struct elfhdr *)buf); + interp_entry = load_elf_interp(tsk, &interp_elf_ex, interpreter, interp_load_addr, NULL); + + allow_write_access(interpreter); + fput(interpreter); + + retval = 0; + +out: + return retval; + +out_free_ntdll: + allow_write_access(ntdll); + if (ntdll) + fput(ntdll); + goto out; + +out_free_interp: + allow_write_access(interpreter); + if (interpreter) + fput(interpreter); + goto out; +} /* end map_system_dll */ +EXPORT_SYMBOL(map_system_dll); + +#endif diff --git a/unifiedkernel/ke/unistr.c b/unifiedkernel/ke/unistr.c new file mode 100644 index 0000000..7688366 --- /dev/null +++ b/unifiedkernel/ke/unistr.c @@ -0,0 +1,300 @@ +/* + * unistr.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * unistr.c: + * Refered to ReactOS code + */ +#include +#include +#include +#include "win32_process.h" +#include "win32.h" +#include "ntstatus.h" +#include "object.h" +#include "thread.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* FIXME */ +#define UpcaseUnicodeChar(wc) wc + +static char debug_buf[1024]; + +extern size_t wcslen(PWSTR ws); + +int str2unistr(struct nls_table *nls, PUNICODE_STRING dst, char *src) +{ + int len, i; + int ret = -ENOMEM; + char *ksrc, *p; + wchar_t *wc; + + if ((unsigned int) src > TASK_SIZE) { + ksrc = src; + len = strlen(src) + 1; + goto ksrc_ready; + } + + if (!src || !(len = strlen_user(src))) { + dst->Length = 0; + dst->MaximumLength = sizeof(wchar_t); + dst->Buffer = (PWSTR)L""; + return 0; + } + + if (!(ksrc = kmalloc(len, GFP_KERNEL))) + return ret; + + ret = -EFAULT; + if (copy_from_user(ksrc, src, len)) + goto out_free_src; + +ksrc_ready: + dst->Length = 0; + dst->MaximumLength = len * sizeof(wchar_t); + dst->Buffer = kmalloc(dst->MaximumLength, GFP_KERNEL); + ret = -ENOMEM; + if (!dst->Buffer) + goto out_free_src; + + wc = dst->Buffer; + p = ksrc; + while (p < ksrc + len - 1) { + i = nls->char2uni(p, sizeof(wchar_t), wc++); + if (i < 0) { + ret = -EINVAL; + goto out_free_dst; + } + p += i; + dst->Length += sizeof(wchar_t); + } + *wc = L'\0'; + + ret = 0; + goto out_free_src; + +out_free_dst: + kfree(dst->Buffer); +out_free_src: + if (ksrc != src) + kfree(ksrc); + + return ret; +} +EXPORT_SYMBOL(str2unistr); + +int unistr2charstr(PWSTR unistr, LPCSTR chstr) +{ + struct ethread *thread; + struct nls_table *nls; + UCHAR *pch; + WCHAR *wc; + int retval = -EFAULT; + int charlen=0; + + thread = get_current_ethread(); + + nls = thread ? thread->threads_process->ep_nls : load_nls("cp936"); + + pch = (UCHAR *)chstr; + if(nls){ + for(wc = unistr; *wc != 0; wc++){ + retval = nls->uni2char(*wc, pch, 2); + if(retval>0){ + charlen += retval; + pch += retval; + } + else + goto out; + } + *pch = 0; + retval = charlen; + goto out; + } + +out: + if (!thread && nls) + unload_nls(nls); + return retval; +} /* end unistr2charstr() */ +EXPORT_SYMBOL(unistr2charstr); + +VOID +STDCALL +init_unistr( + IN OUT PUNICODE_STRING Dest, + IN PWSTR Src) +{ + if (Src) { + Dest->Length = wcslen((PWSTR)Src); + Dest->MaximumLength = Dest->Length + sizeof(WCHAR); + } + else { + Dest->Length = 0; + Dest->MaximumLength = 0; + } + Dest->Buffer = (PWSTR)Src; +} +EXPORT_SYMBOL(init_unistr); + +BOOLEAN +STDCALL +equal_unistr( + IN const UNICODE_STRING *String1, + IN const UNICODE_STRING *String2, + IN BOOLEAN CaseInsensitive) +{ + ULONG i; + WCHAR wc1, wc2; + PWCHAR pw1, pw2; + + if (String1->Length != String2->Length) + return FALSE; + + pw1 = String1->Buffer; + pw2 = String2->Buffer; + + for (i = 0; i < String1->Length / sizeof(WCHAR); i++) { + if (CaseInsensitive == TRUE) { + wc1 = UpcaseUnicodeChar (*pw1); + wc2 = UpcaseUnicodeChar (*pw2); + } + else { + wc1 = *pw1; + wc2 = *pw2; + } + + if (wc1 != wc2) + return FALSE; + + pw1++; + pw2++; + } + + return TRUE; +} +EXPORT_SYMBOL(equal_unistr); + +VOID +STDCALL +free_unistr(IN PUNICODE_STRING UnicodeString) +{ + if (!UnicodeString->Buffer) + return; + + kfree(UnicodeString->Buffer); + memset(UnicodeString, 0, sizeof(UNICODE_STRING)); +} +EXPORT_SYMBOL(free_unistr); + +VOID +STDCALL +copy_unistr( + IN OUT PUNICODE_STRING DestinationString, + IN PUNICODE_STRING SourceString) +{ + ULONG CopyLen; + + if (!SourceString) { + DestinationString->Length = 0; + return; + } + + CopyLen = min(DestinationString->MaximumLength, SourceString->Length); + memcpy(DestinationString->Buffer, SourceString->Buffer, CopyLen); + if (DestinationString->MaximumLength >= CopyLen + sizeof(WCHAR)) + DestinationString->Buffer[CopyLen / sizeof(WCHAR)] = 0; + DestinationString->Length = CopyLen; +} +EXPORT_SYMBOL(copy_unistr); + +char *debug_unistr(PUNICODE_STRING us) +{ + int ret; + + if (!us || !us->Buffer) + return "(null)"; + + ret = unistr2charstr(us->Buffer, debug_buf); + return ret > 0 ? debug_buf : "(invalid unicode string)"; +} +EXPORT_SYMBOL(debug_unistr); + +NTSTATUS +capture_unistr(OUT PUNICODE_STRING Dest, + IN KPROCESSOR_MODE CurrentMode, + IN POOL_TYPE PoolType, + IN BOOLEAN CaptureIfKernel, + IN PUNICODE_STRING UnsafeSrc) +{ + UNICODE_STRING Src; + + /* + * Copy the source string structure to kernel space. + */ + + /* FIXME User Mode */ + + /* Kernel Mode */ + if (!CaptureIfKernel) { + /* just copy the UNICODE_STRING structure, the pointers are considered valid */ + *Dest = *UnsafeSrc; + return STATUS_SUCCESS; + } + else + Src = *UnsafeSrc; + + /* + * Initialize the destination string. + */ + Dest->Length = Src.Length; + if (Src.Length > 0) { + Dest->MaximumLength = Src.Length + sizeof(WCHAR); + Dest->Buffer = kmalloc(Dest->MaximumLength, GFP_KERNEL); + if (!Dest->Buffer) { + memset(Dest, 0, sizeof(UNICODE_STRING)); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the source string to kernel space. */ + memcpy(Dest->Buffer, Src.Buffer, Src.Length); + Dest->Buffer[Src.Length / sizeof(WCHAR)] = L'\0'; + } + else { + Dest->MaximumLength = 0; + Dest->Buffer = NULL; + } + + return STATUS_SUCCESS; +} +EXPORT_SYMBOL(capture_unistr); + +VOID +release_unistr(IN PUNICODE_STRING CapturedString, + IN KPROCESSOR_MODE CurrentMode, + IN BOOLEAN CaptureIfKernel) +{ + if (CurrentMode != KernelMode || CaptureIfKernel) + kfree(CapturedString->Buffer); +} +EXPORT_SYMBOL(release_unistr); +#endif diff --git a/unifiedkernel/ke/w32entry.S b/unifiedkernel/ke/w32entry.S new file mode 100644 index 0000000..10d6aae --- /dev/null +++ b/unifiedkernel/ke/w32entry.S @@ -0,0 +1,516 @@ +/* + * w32entry.S + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + + /* + * Implements the w32 system call mechanism. The code is basically + * a merge of the related code in entry.S from Linux 2.6.30 and + * in syscall.S from Reactos 0.2.6. It is for i386 only. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CF_MASK = 0x00000001 +TF_MASK = 0x00000100 +IF_MASK = 0x00000200 +DF_MASK = 0x00000400 +NT_MASK = 0x00004000 +VM_MASK = 0x00020000 + +.macro TRACE_IRQS_IRET +#ifdef CONFIG_TRACE_IRQFLAGS + testl $X86_EFLAGS_IF,PT_EFLAGS(%esp) # interrupts off? + jz 1f + TRACE_IRQS_ON +1: +#endif +.endm + +#ifdef CONFIG_VM86 +#define w32resume_userspace_sig w32check_userspace +#else +#define w32resume_userspace_sig w32resume_userspace +#endif + +#ifdef CONFIG_X86_32_LAZY_GS +.macro PUSH_GS + pushl $0 + CFI_ADJUST_CFA_OFFSET 4 +.endm +.macro POP_GS pop=0 + addl $(4 + \pop), %esp + CFI_ADJUST_CFA_OFFSET -(4 + \pop) +.endm +.macro POP_GS_EX +.endm +.macro SET_KERNEL_GS reg +.endm + +#else /* CONFIG_X86_32_LAZY_GS */ + +.macro PUSH_GS + pushl %gs + CFI_ADJUST_CFA_OFFSET 4 +.endm +.macro POP_GS pop=0 +98: popl %gs + CFI_ADJUST_CFA_OFFSET -4 + .if \pop <> 0 + add $\pop, %esp + CFI_ADJUST_CFA_OFFSET -\pop + .endif +.endm +.macro POP_GS_EX +.pushsection .fixup, "ax" +99: movl $0, (%esp) + jmp 98b +.section __ex_table, "a" + .align 4 + .long 98b, 99b +.popsection +.endm +.macro SET_KERNEL_GS reg + movl $(__KERNEL_STACK_CANARY), \reg + movl \reg, %gs +.endm + +#endif /* CONFIG_X86_32_LAZY_GS */ + +.macro SAVE_ALL + cld + PUSH_GS + pushl %fs + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET fs, 0;*/ + pushl %es + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET es, 0;*/ + pushl %ds + CFI_ADJUST_CFA_OFFSET 4 + /*CFI_REL_OFFSET ds, 0;*/ + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET eax, 0 + pushl %ebp + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ebp, 0 + pushl %edi + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET edi, 0 + pushl %esi + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET esi, 0 + pushl %edx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET edx, 0 + pushl %ecx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ecx, 0 + pushl %ebx + CFI_ADJUST_CFA_OFFSET 4 + CFI_REL_OFFSET ebx, 0 + movl $(__USER_DS), %edx + movl %edx, %ds + movl %edx, %es + movl $(__KERNEL_PERCPU), %edx + movl %edx, %fs + SET_KERNEL_GS %edx +.endm + +.macro RESTORE_INT_REGS + popl %ebx + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE ebx + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE ecx + popl %edx + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE edx + popl %esi + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE esi + popl %edi + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE edi + popl %ebp + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE ebp + popl %eax + CFI_ADJUST_CFA_OFFSET -4 + CFI_RESTORE eax +.endm + +.macro RESTORE_REGS pop=0 + RESTORE_INT_REGS +1: popl %ds + CFI_ADJUST_CFA_OFFSET -4 + /*CFI_RESTORE ds;*/ +2: popl %es + CFI_ADJUST_CFA_OFFSET -4 + /*CFI_RESTORE es;*/ +3: popl %fs + CFI_ADJUST_CFA_OFFSET -4 + /*CFI_RESTORE fs;*/ + POP_GS \pop +.pushsection .fixup, "ax" +4: movl $0, (%esp) + jmp 1b +5: movl $0, (%esp) + jmp 2b +6: movl $0, (%esp) + jmp 3b +.section __ex_table, "a" + .align 4 + .long 1b, 4b + .long 2b, 5b + .long 3b, 6b +.popsection + POP_GS_EX +.endm + +.macro RING0_INT_FRAME + CFI_STARTPROC simple + CFI_SIGNAL_FRAME + CFI_DEF_CFA esp, 3*4 + /*CFI_OFFSET cs, -2*4;*/ + CFI_OFFSET eip, -3*4 +.endm + +.macro RING0_EC_FRAME + CFI_STARTPROC simple + CFI_SIGNAL_FRAME + CFI_DEF_CFA esp, 4*4 + /*CFI_OFFSET cs, -2*4;*/ + CFI_OFFSET eip, -3*4 +.endm + +.macro RING0_PTREGS_FRAME + CFI_STARTPROC simple + CFI_SIGNAL_FRAME + CFI_DEF_CFA esp, PT_OLDESP-PT_EBX + /*CFI_OFFSET cs, PT_CS-PT_OLDESP;*/ + CFI_OFFSET eip, PT_EIP-PT_OLDESP + /*CFI_OFFSET es, PT_ES-PT_OLDESP;*/ + /*CFI_OFFSET ds, PT_DS-PT_OLDESP;*/ + CFI_OFFSET eax, PT_EAX-PT_OLDESP + CFI_OFFSET ebp, PT_EBP-PT_OLDESP + CFI_OFFSET edi, PT_EDI-PT_OLDESP + CFI_OFFSET esi, PT_ESI-PT_OLDESP + CFI_OFFSET edx, PT_EDX-PT_OLDESP + CFI_OFFSET ecx, PT_ECX-PT_OLDESP + CFI_OFFSET ebx, PT_EBX-PT_OLDESP +.endm + +#ifdef CONFIG_UNIFIED_KERNEL + +ENTRY(w32system_call) + RING0_INT_FRAME # can't unwind into user space anyway + pushl %eax # save orig_eax + CFI_ADJUST_CFA_OFFSET 4 + SAVE_ALL + GET_THREAD_INFO(%ebp) + + movl %esp, %eax + movl (%ebp), %edx # get task_struct + call set_trap_frame + movl PT_EAX(%esp), %eax + + # system call tracing in operation / emulation + /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */ + testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) + jnz w32syscall_trace_entry + + /* + * Find out which syscall table (basic or extended) to use, + * and get the offset to the table. + * The offset is related to the Table Index as such: + * offset = TableIndex x 0x10. (see the typedef for SSDT_ENTRY) + * For example, if %eax is 0x1124, then the offset is 0x10. + */ + movl %eax, %edi + shrl $8, %edi + andl $0x10, %edi + + /* Now add the base system table to the offset */ + addl $(KeServiceDescriptorTable), %edi + + /* Get the true syscall ID and check it */ + andl $0x0FFF, %eax + cmpl 8(%edi), %eax + + /* Invalid ID, try to load Win32K Table */ + jnb w32syscall_badsys + +w32syscall_call: + /* For w32syscall_trace_back */ + /* Users's current stack frame pointer is source */ + movl PT_EDX(%esp), %esi + + /* Allocate room for argument list from kernel stack */ + movl 12(%edi), %ecx + movb (%ecx, %eax), %cl + movzx %cl, %ecx + shll $2,%ecx + + /* Allocate new Kernel stack frame */ + pushl %ebp + movl %esp,%ebp + + /* Allocate space on our stack */ + subl %ecx, %esp + + /* Get pointer to function */ + movl (%edi), %edi + movl (%edi, %eax, 4), %eax + + /* Copy the arguments from the user stack to our stack */ + shr $2, %ecx + movl %esp, %edi + cld + rep movsd + + cmp $(NtContinue), %eax + jnz do_syscall +#ud2 + +do_syscall: + /* Do the System Call */ + call *%eax + + /* Deallocate the kernel stack frame */ + movl %ebp, %esp + popl %ebp + movl %eax,PT_EAX(%esp) # store the return value + +ENTRY(w32syscall_exit) + LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret + TRACE_IRQS_OFF + movl TI_flags(%ebp), %ecx + testl $_TIF_ALLWORK_MASK, %ecx # current->work + jne w32syscall_exit_work + +w32restore_all: + movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS + # Warning: PT_OLDSS(%esp) contains the wrong/random values if we + # are returning to the kernel. + # See comments in process.c:copy_thread() for details. + movb PT_OLDSS(%esp), %ah + movb PT_CS(%esp), %al + andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax + cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax + CFI_REMEMBER_STATE + je w32ldt_ss # returning to user-space with LDT SS + +w32restore_nocheck: + TRACE_IRQS_IRET +w32restore_nocheck_notrace: + RESTORE_REGS 4 # skip orig_eax/error_code + CFI_ADJUST_CFA_OFFSET -4 +irq_return: + INTERRUPT_RETURN +#if 0 +.section .fixup,"ax" +w32iret_exc: + pushl $0 # no error code + pushl $do_iret_error + jmp error_code +.previous +.section __ex_table,"a" + .align 4 + .long irq_return,w32iret_exc +.previous +#endif + + CFI_RESTORE_STATE +w32ldt_ss: + larl PT_OLDSS(%esp), %eax + jnz w32restore_nocheck + testl $0x00400000, %eax # returning to 32bit stack? + jnz w32restore_nocheck # allright, normal return + +#ifdef CONFIG_PARAVIRT + /* + * The kernel can't run on a non-flat stack if paravirt mode + * is active. Rather than try to fixup the high bits of + * ESP, bypass this code entirely. This may break DOSemu + * and/or Wine support in a paravirt VM, although the option + * is still available to implement the setting of the high + * 16-bits in the INTERRUPT_RETURN paravirt-op. + */ + cmpl $0, pv_info+PARAVIRT_enabled + jne w32restore_nocheck +#endif + + /* If returning to userspace with 16bit stack, + * try to fix the higher word of ESP, as the CPU + * won't restore it. + * This is an "official" bug of all the x86-compatible + * CPUs, which we can try to work around to make + * dosemu and wine happy. */ + movl PT_OLDESP(%esp), %eax + movl %esp, %edx + call patch_espfix_desc + pushl $__ESPFIX_SS + CFI_ADJUST_CFA_OFFSET 4 + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + DISABLE_INTERRUPTS(CLBR_EAX) + TRACE_IRQS_OFF + lss (%esp), %esp + CFI_ADJUST_CFA_OFFSET -8 + jmp w32restore_nocheck + CFI_ENDPROC +ENDPROC(w32system_call) + + # perform work that needs to be done immediately before resumption + ALIGN + RING0_PTREGS_FRAME # can't unwind into user space anyway +w32work_pending: + testb $_TIF_NEED_RESCHED, %cl + jz w32work_notifysig + +w32work_resched: + call schedule + LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret + TRACE_IRQS_OFF + movl TI_flags(%ebp), %ecx + andl $_TIF_WORK_MASK, %ecx # is there any work to be done other + # than syscall tracing? + jz w32restore_all + testb $_TIF_NEED_RESCHED, %cl + jnz w32work_resched + +w32work_notifysig: # deal with pending signals and + # notify-resume requests +#ifdef CONFIG_VM86 + testl $X86_EFLAGS_VM, PT_EFLAGS(%esp) + movl %esp, %eax + je w32apc # returning to kernel-space or + # vm86-space + ALIGN +w32work_notifysig_v86: + pushl %ecx # save ti_flags for do_notify_resume + CFI_ADJUST_CFA_OFFSET 4 + call save_v86_state # %eax contains pt_regs pointer + popl %ecx + CFI_ADJUST_CFA_OFFSET -4 + movl %eax, %esp +#else + movl %esp, %eax +#endif + +w32apc: + xorl %edx, %edx + testw $_TIF_APC, %cx + jz w32signal + + call do_apc # for Windows Apc + movl TI_flags(%ebp), %ecx + testw $(_TIF_WORK_MASK & ~_TIF_APC), %cx + jz w32resume_userspace_sig + xorl %edx, %edx + movl %esp, %eax + +w32signal: + call do_notify_resume + jmp w32resume_userspace_sig + +END(w32work_pending) + + # perform syscall exit tracing + ALIGN +w32syscall_trace_entry: + movl $-ENOSYS,PT_EAX(%esp) + movl %esp, %eax + call syscall_trace_enter + + /* back to w32syscall_call */ + movl %eax, %edi + shrl $8, %edi + andl $0x10, %edi + + addl $(KeServiceDescriptorTable), %edi + + andl $0x0FFF, %eax + cmpl 8(%edi), %eax + jb w32syscall_call + + jmp w32syscall_exit + + # perform syscall exit tracing + ALIGN +w32syscall_exit_work: + testl $_TIF_WORK_SYSCALL_EXIT, %ecx + jz w32work_pending + TRACE_IRQS_ON + ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call + # schedule() instead + movl %esp, %eax + call syscall_trace_leave + jmp w32resume_userspace +END(w32syscall_exit_work) + CFI_ENDPROC + + ALIGN +w32syscall_badsys: + movl $-ENOSYS,PT_EAX(%esp) + jmp w32resume_userspace + +w32check_userspace: + movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS + movb PT_CS(%esp), %al + andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax + cmpl $USER_RPL, %eax + jb w32restore_nocheck # not returning to v8086 or userspace + +w32resume_userspace: + LOCKDEP_SYS_EXIT + DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt + # setting need_resched or sigpending + # between sampling and the iret + TRACE_IRQS_OFF + movl TI_flags(%ebp), %ecx + andl $_TIF_WORK_MASK, %ecx # is there any work to be done on + # int/exception return? + jne w32work_pending + jmp w32restore_all + +#endif diff --git a/unifiedkernel/ke/w32init.c b/unifiedkernel/ke/w32init.c new file mode 100644 index 0000000..43d2327 --- /dev/null +++ b/unifiedkernel/ke/w32init.c @@ -0,0 +1,145 @@ +/* + * w32init.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * w32init.c: initiliase w32systemcall and some object classes + */ +#include +#include +#include +#include + +#include "mutex.h" +#include "event.h" +#include "semaphore.h" +#include "section.h" +#include "file.h" +#include "thread.h" +#include "process.h" +#include "apc.h" +#include "handle.h" +#include "io.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +char *rootdir = "/root/.wine/"; + +extern SSDT_ENTRY KeServiceDescriptorTable[]; +asmlinkage int w32system_call(void); +int set_w32system_gate(unsigned int, void *); +int backup_idt_entry(unsigned int n, unsigned long *a, unsigned long *b); +int restore_idt_entry(unsigned int n, unsigned long a, unsigned long b); +unsigned long orig_idt_2e_a, orig_idt_2e_b; +int init_pe_binfmt(void); +void exit_pe_binfmt(void); +#ifdef EXE_SO +int init_exeso_binfmt(void); +void exit_exeso_binfmt(void); +#endif + +struct proc_dir_entry *unifiedkernel_proc; +struct list_head object_class_list; + +extern int proc_uk_init(void); +extern void proc_uk_exit(void); + +extern void kernel_init_registry(void); +extern void init_process_manager(void); +extern void init_section_implement(void); +extern void display_object_dir(POBJECT_DIRECTORY DirectoryObject, LONG Depth); +extern void display_name_info(void); +extern void exit_object(void); +extern void init_named_pipe(void); +extern void init_directories(void); +extern struct task_struct* save_kernel_task; +extern int kthread_stop(struct task_struct*); + +/* w32_init */ +static int w32_init(void) +{ + ktrace("Unifiedkernel loading...\n"); + /* store the original address that the 0x2E points */ + if (backup_idt_entry(0x2E, &orig_idt_2e_a, &orig_idt_2e_b) == -1) { + kdebug("Module not loaded. backup_idt_entry error: bad idt entry\n"); + return -1; + } + + /* initialize 0x2E */ + if (set_w32system_gate(0x2E, &w32system_call) == -1) { + kdebug("Module not loaded. set_w32system_gate error: bad idt entry\n"); + return -1; + } + + proc_uk_init(); + + /* initialise the internal bits */ + INIT_LIST_HEAD(&object_class_list); + init_pe_binfmt(); +#ifdef EXE_SO + init_exeso_binfmt(); +#endif + init_handle_tables(); + init_object(); + init_symbol_link(); + init_io(); + init_directories(); + init_named_pipe(); + init_cid_table(); + init_process_manager(); + init_section_implement(); + init_semaphore_implement(); + init_event_implement(); + init_mutant_implement(); + kernel_init_registry(); + display_object_dir(name_space_root, 1); + + register_binfmt(NULL); + return 0; +} /* end w32_exit */ +/* w32_exit */ +static void w32_exit(void) +{ + int ret; + + destroy_cid_table(); + exit_object(); +#ifdef EXE_SO + exit_exeso_binfmt(); +#endif + exit_pe_binfmt(); + proc_uk_exit(); + ret=wake_up_process(save_kernel_task); + kthread_stop(save_kernel_task); + + + /* restore 0x2E */ + restore_idt_entry(0x2E, orig_idt_2e_a, orig_idt_2e_b); + + ktrace("Module w32 Off!\n"); +} /*end w32_exit */ + +module_init(w32_init); +module_exit(w32_exit); +module_param(rootdir, charp, S_IRUGO); +MODULE_LICENSE("GPL"); +#endif + diff --git a/unifiedkernel/ke/w32syscall.c b/unifiedkernel/ke/w32syscall.c new file mode 100644 index 0000000..4ac973a --- /dev/null +++ b/unifiedkernel/ke/w32syscall.c @@ -0,0 +1,2851 @@ +/* + * w32syscall.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * w32syscall.c: win32 syscall definition + * It also includes the W32 syscall function table and other data structures + * (from ReactOS) + * Refered to ReactOS code + */ + +#include +#include "w32syscall.h" +#include "win32.h" +#include "objwait.h" +#include "process.h" +#include "thread.h" +#include "file.h" +#include "event.h" +#include "mutex.h" +#include "section.h" +#include "semaphore.h" +#include "handle.h" +#include + +#include "wineserver/winerror.h" +#include "wineserver/uk_lib.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +extern void debug_gdt(void); + +/* 0 */ + NTSTATUS SERVICECALL +NtAcceptConnectPort (PHANDLE ServerPortHandle, + HANDLE NamedPortHandle, + PPORT_MESSAGE LpcMessage, + BOOLEAN AcceptIt, + PPORT_VIEW WriteMap, + PREMOTE_PORT_VIEW ReadMap) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAcceptConnectPort); + + NTSTATUS SERVICECALL +NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE TokenHandle, + IN ACCESS_MASK DesiredAccess, + IN PGENERIC_MAPPING GenericMapping, + OUT PPRIVILEGE_SET PrivilegeSet, + OUT PULONG ReturnLength, + OUT PACCESS_MASK GrantedAccess, + OUT PNTSTATUS AccessStatus) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAccessCheck); + + NTSTATUS SERVICECALL +NtAccessCheckAndAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN PUNICODE_STRING ObjectName, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ACCESS_MASK DesiredAccess, + IN PGENERIC_MAPPING GenericMapping, + IN BOOLEAN ObjectCreation, + OUT PACCESS_MASK GrantedAccess, + OUT PNTSTATUS AccessStatus, + OUT PBOOLEAN GenerateOnClose) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAccessCheckAndAuditAlarm); + + NTSTATUS SERVICECALL +NtAddAtom(IN PWSTR AtomName, + IN ULONG AtomNameLength, + OUT PRTL_ATOM Atom) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAddAtom); + + NTSTATUS SERVICECALL +NtAddBootEntry(IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAddBootEntry); + +/* 5 */ + NTSTATUS SERVICECALL +NtAdjustGroupsToken(IN HANDLE TokenHandle, + IN BOOLEAN ResetToDefault, + IN PTOKEN_GROUPS NewState, + IN ULONG BufferLength, + OUT PTOKEN_GROUPS PreviousState OPTIONAL, + OUT PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAdjustGroupsToken); + + NTSTATUS SERVICECALL +NtAdjustPrivilegesToken (IN HANDLE TokenHandle, + IN BOOLEAN DisableAllPrivileges, + IN PTOKEN_PRIVILEGES NewState, + IN ULONG BufferLength, + OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL, + OUT PULONG ReturnLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAdjustPrivilegesToken); + +/* + NTSTATUS SERVICECALL + NtAlertResumeThread(IN HANDLE ThreadHandle, + OUT PULONG SuspendCount) + { + return -ENOSYS; + } + */ + +/* + NTSTATUS SERVICECALL + NtAlertThread (IN HANDLE ThreadHandle) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAllocateLocallyUniqueId); + +/* 10 */ + NTSTATUS SERVICECALL +NtAllocateUuids(OUT PULARGE_INTEGER Time, + OUT PULONG Range, + OUT PULONG Sequence, + OUT PUCHAR Seed) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAllocateUuids); +/* + NTSTATUS SERVICECALL + NtAllocateVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID* UBaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG URegionSize, + IN ULONG AllocationType, + IN ULONG Protect) + { + return -ENOSYS; + } + */ + NTSTATUS SERVICECALL +NtAssignProcessToJobObject(HANDLE JobHandle, + HANDLE ProcessHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtAssignProcessToJobObject); + + NTSTATUS SERVICECALL +NtCallbackReturn (PVOID Result, + ULONG ResultLength, + NTSTATUS Status) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCallbackReturn); + + NTSTATUS SERVICECALL +NtCancelIoFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCancelIoFile); + +/* 15 */ + NTSTATUS SERVICECALL +NtCancelTimer(IN HANDLE TimerHandle, + OUT PBOOLEAN CurrentState OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCancelTimer); + + +/* + NTSTATUS SERVICECALL + NtClearEvent(IN HANDLE EventHandle) + { + return -ENOSYS; + } + EXPORT_SYMBOL(NtClearEvent); + + NTSTATUS + SERVICECALL + NtClose(IN HANDLE Handle) + { + + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtCloseObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCloseObjectAuditAlarm); + + NTSTATUS SERVICECALL +NtCompleteConnectPort (HANDLE hServerSideCommPort) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCompleteConnectPort); + +/* 20 */ + NTSTATUS SERVICECALL +NtConnectPort (PHANDLE UnsafeConnectedPortHandle, + PUNICODE_STRING PortName, + PSECURITY_QUALITY_OF_SERVICE Qos, + PPORT_VIEW UnsafeWriteMap, + PREMOTE_PORT_VIEW UnsafeReadMap, + PULONG UnsafeMaximumMessageSize, + PVOID UnsafeConnectData, + PULONG UnsafeConnectDataLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtConnectPort); + +/* + NTSTATUS SERVICECALL + NtContinue(IN Pcontext Context, + IN BOOLEAN TestAlert) + { + return -ENOSYS; + } + + NTSTATUS SERVICECALL + NtCreateDirectoryObject (OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) + { + return -ENOSYS; + } + + NTSTATUS SERVICECALL + NtCreateEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtCreateEventPair(OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateEventPair); + +/* 25 */ +/* + NTSTATUS SERVICECALL + NtCreateFile(PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + PLARGE_INTEGER AllocateSize, + ULONG FileAttributes, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions, + PVOID EaBuffer, + ULONG EaLength) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateIoCompletion); + + NTSTATUS SERVICECALL +NtCreateJobObject(PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateJobObject); + + NTSTATUS SERVICECALL +NtCreateKey(OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG TitleIndex, + IN PUNICODE_STRING Class, + IN ULONG CreateOptions, + OUT PULONG Disposition) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateKey); + + NTSTATUS SERVICECALL +NtCreateMailslotFile(OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG CreateOptions, + IN ULONG MailslotQuota, + IN ULONG MaxMessageSize, + IN PLARGE_INTEGER TimeOut) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateMailslotFile); + +/* 30 */ +/* + NTSTATUS SERVICECALL + NtCreateMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN InitialOwner) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtCreateNamedPipeFile(PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions, + ULONG NamedPipeType, + ULONG ReadMode, + ULONG CompletionMode, + ULONG MaximumInstances, + ULONG InboundQuota, + ULONG OutboundQuota, + PLARGE_INTEGER DefaultTimeout) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateNamedPipeFile); + + NTSTATUS SERVICECALL +NtCreatePagingFile(IN PUNICODE_STRING FileName, + IN PLARGE_INTEGER InitialSize, + IN PLARGE_INTEGER MaximumSize, + IN ULONG Reserved) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreatePagingFile); + + NTSTATUS SERVICECALL +NtCreatePort (PHANDLE PortHandle, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG MaxConnectInfoLength, + ULONG MaxDataLength, + ULONG MaxPoolUsage) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreatePort); + +/* + NTSTATUS SERVICECALL + NtCreateProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL) + { + return -ENOSYS; + } + */ + +/* 35 */ + NTSTATUS SERVICECALL +NtCreateProfile(OUT PHANDLE ProfileHandle, + IN HANDLE Process OPTIONAL, + IN PVOID ImageBase, + IN ULONG ImageSize, + IN ULONG BucketSize, + IN PVOID Buffer, + IN ULONG BufferSize, + IN KPROFILE_SOURCE ProfileSource, + IN KAFFINITY Affinity) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateProfile); + +/* + NTSTATUS SERVICECALL + NtCreateSection (OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection OPTIONAL, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL) + { + return -ENOSYS; + } + */ + +/* + NTSTATUS + SERVICECALL + NtCreateSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN LONG InitialCount, + IN LONG MaximumCount) + { + return -ENOSYS; + } + + NTSTATUS SERVICECALL + NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING LinkTarget) + { + return -ENOSYS; + } + + NTSTATUS SERVICECALL + NtCreateThread(OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + OUT PCLIENT_ID ClientId, + IN PCONTEXT ThreadContext, + IN PINITIAL_TEB InitialTeb, + IN BOOLEAN CreateSuspended) + { + return -ENOSYS; + } + */ + +/* 40 */ + NTSTATUS SERVICECALL +NtCreateTimer(OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN TIMER_TYPE TimerType) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateTimer); + + NTSTATUS SERVICECALL +NtCreateToken(OUT PHANDLE TokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN TOKEN_TYPE TokenType, + IN PLUID AuthenticationId, + IN PLARGE_INTEGER ExpirationTime, + IN PTOKEN_USER TokenUser, + IN PTOKEN_GROUPS TokenGroups, + IN PTOKEN_PRIVILEGES TokenPrivileges, + IN PTOKEN_OWNER TokenOwner, + IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, + IN PTOKEN_DEFAULT_DACL TokenDefaultDacl, + IN PTOKEN_SOURCE TokenSource) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateToken); + + + NTSTATUS SERVICECALL +NtCreateWaitablePort (OUT PHANDLE PortHandle, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG MaxConnectInfoLength, + IN ULONG MaxDataLength, + IN ULONG MaxPoolUsage) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtCreateWaitablePort); + +/* + NTSTATUS SERVICECALL + NtDelayExecution(IN BOOLEAN Alertable, + IN PLARGE_INTEGER DelayInterval) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtDeleteAtom(IN RTL_ATOM Atom) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDeleteAtom); + +/* 45 */ + NTSTATUS SERVICECALL +NtDeleteBootEntry(IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDeleteBootEntry); + + + NTSTATUS SERVICECALL +NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDeleteFile); + + NTSTATUS SERVICECALL +NtDeleteKey(IN HANDLE KeyHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDeleteKey); + + NTSTATUS SERVICECALL +NtDeleteObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDeleteObjectAuditAlarm); + + NTSTATUS SERVICECALL +NtDeleteValueKey (IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDeleteValueKey); + +/* 50 */ + NTSTATUS SERVICECALL +NtDeviceIoControlFile(IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength OPTIONAL, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDeviceIoControlFile); + + NTSTATUS SERVICECALL +NtDisplayString(IN PUNICODE_STRING DisplayString) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDisplayString); + +/* + NTSTATUS SERVICECALL + NtDuplicateObject (IN HANDLE SourceProcessHandle, + IN HANDLE SourceHandle, + IN HANDLE TargetProcessHandle, + OUT PHANDLE TargetHandle OPTIONAL, + IN ACCESS_MASK DesiredAccess, + IN ULONG InheritHandle, + IN ULONG Options) + { + return -ENOSYS; + }*/ + + NTSTATUS SERVICECALL +NtDuplicateToken(IN HANDLE ExistingTokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN EffectiveOnly, + IN TOKEN_TYPE TokenType, + OUT PHANDLE NewTokenHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtDuplicateToken); + + NTSTATUS SERVICECALL +NtEnumerateBootEntries(IN ULONG Unknown1, + IN ULONG Unknown2) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtEnumerateBootEntries); + +/* 55 */ + NTSTATUS SERVICECALL +NtEnumerateKey(IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtEnumerateKey); + + NTSTATUS SERVICECALL +NtEnumerateValueKey(IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtEnumerateValueKey); + +/* + NTSTATUS SERVICECALL + NtExtendSection(IN HANDLE SectionHandle, + IN PLARGE_INTEGER NewMaximumSize) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtFindAtom(IN PWSTR AtomName, + IN ULONG AtomNameLength, + OUT PRTL_ATOM Atom) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtFindAtom); + +/* + NTSTATUS SERVICECALL + NtFlushBuffersFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock) + { + return -ENOSYS; + } + */ + +/* 60 */ + NTSTATUS SERVICECALL +NtFlushInstructionCache (IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN ULONG NumberOfBytesToFlush) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtFlushInstructionCache); + + NTSTATUS SERVICECALL +NtFlushKey(IN HANDLE KeyHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtFlushKey); +/* + NTSTATUS SERVICECALL + NtFlushVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN ULONG NumberOfBytesToFlush, + OUT PULONG NumberOfBytesFlushed OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtFlushWriteBuffer(VOID) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtFlushWriteBuffer); + +/* + NTSTATUS SERVICECALL + NtFreeVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID* PBaseAddress, + IN PULONG PRegionSize, + IN ULONG FreeType) + { + return -ENOSYS; + } + */ + +/* 65 */ + NTSTATUS SERVICECALL +NtFsControlFile(IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength OPTIONAL, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtFsControlFile); + +/* + NTSTATUS SERVICECALL + NtGetContextThread(IN HANDLE ThreadHandle, + OUT PCONTEXT ThreadContext) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtGetPlugPlayEvent(IN ULONG Reserved1, + IN ULONG Reserved2, + OUT PPLUGPLAY_EVENT_BLOCK Buffer, + IN ULONG BufferSize) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtGetPlugPlayEvent); + + NTSTATUS SERVICECALL +NtGetTickCount(VOID) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtGetTickCount); + + NTSTATUS SERVICECALL +NtImpersonateClientOfPort (HANDLE PortHandle, + PPORT_MESSAGE ClientMessage) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtImpersonateClientOfPort); + +/* 70 */ + NTSTATUS SERVICECALL +NtImpersonateThread(IN HANDLE ThreadHandle, + IN HANDLE ThreadToImpersonateHandle, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtImpersonateThread); + + NTSTATUS SERVICECALL +NtInitializeRegistry (IN BOOLEAN SetUpBoot) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtInitializeRegistry); + + NTSTATUS SERVICECALL +NtInitiatePowerAction (IN POWER_ACTION SystemAction, + IN SYSTEM_POWER_STATE MinSystemState, + IN ULONG Flags, + IN BOOLEAN Asynchronous) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtInitiatePowerAction); + + NTSTATUS SERVICECALL +NtIsProcessInJob (IN HANDLE ProcessHandle, + IN HANDLE JobHandle OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtIsProcessInJob); + + NTSTATUS SERVICECALL +NtListenPort (IN HANDLE PortHandle, + IN PPORT_MESSAGE ConnectMsg) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtListenPort); + +/* 75 */ + NTSTATUS SERVICECALL +NtLoadDriver(IN PUNICODE_STRING DriverServiceName) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtLoadDriver); + + NTSTATUS SERVICECALL +NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtLoadKey); + + + NTSTATUS SERVICECALL +NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes, + IN ULONG Flags) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtLoadKey2); + + NTSTATUS SERVICECALL +NtLockFile(IN HANDLE FileHandle, + IN HANDLE EventHandle OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Length, + IN ULONG Key, + IN BOOLEAN FailImmediately, + IN BOOLEAN ExclusiveLock) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtLockFile); + + NTSTATUS SERVICECALL +NtLockVirtualMemory(HANDLE ProcessHandle, + PVOID BaseAddress, + ULONG NumberOfBytesToLock, + PULONG NumberOfBytesLocked) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtLockVirtualMemory); + +/* 80 */ +/* + NTSTATUS SERVICECALL + NtMakePermanentObject(IN HANDLE ObjectHandle) + { + return -ENOSYS; + } + + NTSTATUS SERVICECALL + NtMakeTemporaryObject(IN HANDLE ObjectHandle) + { + return -ENOSYS; + } + */ +/* + NTSTATUS SERVICECALL + NtMapViewOfSection(IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID* BaseAddress OPTIONAL, + IN ULONG ZeroBits OPTIONAL, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PULONG ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType OPTIONAL, + IN ULONG Protect) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtNotifyChangeDirectoryFile(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG BufferSize, + IN ULONG CompletionFilter, + IN BOOLEAN WatchTree) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtNotifyChangeDirectoryFile); + + NTSTATUS SERVICECALL +NtNotifyChangeKey (IN HANDLE KeyHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG CompletionFilter, + IN BOOLEAN WatchSubtree, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN Asynchronous) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtNotifyChangeKey); + +/* 85 */ +/* + NTSTATUS SERVICECALL + NtOpenDirectoryObject (OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) + { + return -ENOSYS; + } + */ +/* + NTSTATUS SERVICECALL + NtOpenEvent(OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtOpenEventPair(OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtOpenEventPair); + +/* + NTSTATUS SERVICECALL + NtOpenFile(PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, + ULONG OpenOptions) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtOpenIoCompletion); + +/* 90 */ + NTSTATUS SERVICECALL +NtOpenJobObject (PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtOpenJobObject); + + + NTSTATUS SERVICECALL +NtOpenKey(OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtOpenKey); + +/* + NTSTATUS SERVICECALL + NtOpenMutant(OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtOpenObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN PUNICODE_STRING ObjectName, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN ULONG GrantedAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN ObjectCreation, + IN BOOLEAN AccessGranted, + OUT PBOOLEAN GenerateOnClose) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtOpenObjectAuditAlarm); +/* + NTSTATUS SERVICECALL + NtOpenProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId) + { + return -ENOSYS; + } + */ +/* 95 */ +/* + NTSTATUS SERVICECALL + NtOpenProcessToken(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle) + { + return -ENOSYS; + } + */ + +/* + NTSTATUS SERVICECALL + NtOpenProcessTokenEx(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle) + { + return -ENOSYS; + } + */ +/* + NTSTATUS SERVICECALL + NtOpenSection(PHANDLE SectionHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes) + { + return -ENOSYS; + } + */ +/* + NTSTATUS + SERVICECALL + NtOpenSemaphore(OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) + { + return -ENOSYS; + } + + NTSTATUS SERVICECALL + NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) + { + return -ENOSYS; + } + */ +/* 100 */ +/* + NTSTATUS SERVICECALL + NtOpenThread(OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PCLIENT_ID ClientId OPTIONAL) + { + return -ENOSYS; + } + */ +/* + NTSTATUS SERVICECALL + NtOpenThreadToken(IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + OUT PHANDLE TokenHandle) + { + return -ENOSYS; + } + */ +/* + NTSTATUS SERVICECALL + NtOpenThreadTokenEx(IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle) + { + return -ENOSYS; + } + */ + NTSTATUS SERVICECALL +NtOpenTimer(OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtOpenTimer); + + NTSTATUS SERVICECALL +NtPlugPlayControl(IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, + IN OUT PVOID Buffer, + IN ULONG BufferLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtPlugPlayControl); + +/* 105 */ + NTSTATUS SERVICECALL +NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtPowerInformation); + + NTSTATUS SERVICECALL +NtPrivilegeCheck (IN HANDLE ClientToken, + IN PPRIVILEGE_SET RequiredPrivileges, + IN PBOOLEAN Result) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtPrivilegeCheck); + + NTSTATUS SERVICECALL +NtPrivilegedServiceAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PUNICODE_STRING ServiceName, + IN HANDLE ClientToken, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtPrivilegedServiceAuditAlarm); + + NTSTATUS SERVICECALL +NtPrivilegeObjectAuditAlarm(IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtPrivilegeObjectAuditAlarm); +/* + NTSTATUS SERVICECALL + NtProtectVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *UnsafeBaseAddress, + IN OUT ULONG *UnsafeNumberOfBytesToProtect, + IN ULONG NewAccessProtection, + OUT PULONG UnsafeOldAccessProtection) + { + return -ENOSYS; + } + */ +/* 110 */ +/* + NTSTATUS SERVICECALL + NtPulseEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtQueryInformationAtom(RTL_ATOM Atom, + ATOM_INFORMATION_CLASS AtomInformationClass, + PVOID AtomInformation, + ULONG AtomInformationLength, + PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryInformationAtom); + + NTSTATUS SERVICECALL +NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_BASIC_INFORMATION FileInformation) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryAttributesFile); + + NTSTATUS SERVICECALL +NtQueryBootEntryOrder(IN ULONG Unknown1, + IN ULONG Unknown2) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryBootEntryOrder); + + NTSTATUS SERVICECALL +NtQueryBootOptions(IN ULONG Unknown1, + IN ULONG Unknown2) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryBootOptions); + +/* 115 */ + NTSTATUS SERVICECALL +NtQueryDefaultLocale(IN BOOLEAN UserProfile, + OUT PLCID DefaultLocaleId) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryDefaultLocale); + + NTSTATUS SERVICECALL +NtQueryDefaultUILanguage(OUT PLANGID LanguageId) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryDefaultUILanguage); + + NTSTATUS SERVICECALL +NtQueryDirectoryFile(IN HANDLE FileHandle, + IN HANDLE PEvent OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryDirectoryFile); +/* + NTSTATUS SERVICECALL + NtQueryDirectoryObject (IN HANDLE DirectoryHandle, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturnLength OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtQueryEaFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID EaList OPTIONAL, + IN ULONG EaListLength, + IN PULONG EaIndex OPTIONAL, + IN BOOLEAN RestartScan) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryEaFile); + +/* 120 */ +/* + NTSTATUS SERVICECALL + NtQueryEvent(IN HANDLE EventHandle, + IN EVENT_INFORMATION_CLASS EventInformationClass, + OUT PVOID EventInformation, + IN ULONG EventInformationLength, + OUT PULONG ReturnLength OPTIONAL) + { + return -ENOSYS; + } + EXPORT_SYMBOL(NtQueryEvent); + */ + + NTSTATUS SERVICECALL +NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryFullAttributesFile); + +/* + NTSTATUS SERVICECALL + NtQueryInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtQueryInformationJobObject (HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength, + PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryInformationJobObject); + + NTSTATUS SERVICECALL +NtQueryInformationPort (IN HANDLE PortHandle, + IN PORT_INFORMATION_CLASS PortInformationClass, + OUT PVOID PortInformation, + IN ULONG PortInformationLength, + OUT PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryInformationPort); + +/* 125 */ +/* + NTSTATUS SERVICECALL + NtQueryInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL) + { + return -ENOSYS; + } + */ + +/* + NTSTATUS SERVICECALL + NtQueryInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtQueryInformationToken(IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength, + OUT PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryInformationToken); + + NTSTATUS SERVICECALL +NtQueryInstallUILanguage(OUT PLANGID LanguageId) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryInstallUILanguage); + + NTSTATUS SERVICECALL +NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource, + OUT PULONG Interval) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryIntervalProfile); + +/* 130 */ + NTSTATUS SERVICECALL +NtQueryIoCompletion(IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryIoCompletion); + + NTSTATUS SERVICECALL +NtQueryKey(IN HANDLE KeyHandle, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryKey); + + NTSTATUS SERVICECALL +NtQueryMultipleValueKey (IN HANDLE KeyHandle, + IN OUT PKEY_VALUE_ENTRY ValueList, + IN ULONG NumberOfValues, + OUT PVOID Buffer, + IN OUT PULONG Length, + OUT PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryMultipleValueKey); + + NTSTATUS SERVICECALL +NtQueryMutant(IN HANDLE MutantHandle, + IN MUTANT_INFORMATION_CLASS MutantInformationClass, + OUT PVOID MutantInformation, + IN ULONG MutantInformationLength, + OUT PULONG ResultLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryMutant); +/* + NTSTATUS SERVICECALL + NtQueryObject (IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL) + { + return -ENOSYS; + } + */ +/* 135 */ + NTSTATUS SERVICECALL +NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter, + OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryPerformanceCounter); + + NTSTATUS SERVICECALL +NtQueryQuotaInformationFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID SidList OPTIONAL, + IN ULONG SidListLength, + IN PSID StartSid OPTIONAL, + IN BOOLEAN RestartScan) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryQuotaInformationFile); + +/* + NTSTATUS SERVICECALL + NtQuerySection(IN HANDLE SectionHandle, + IN SECTION_INFORMATION_CLASS SectionInformationClass, + OUT PVOID SectionInformation, + IN ULONG SectionInformationLength, + OUT PULONG ResultLength OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtQuerySecurityObject(IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ULONG Length, + OUT PULONG ResultLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQuerySecurityObject); + + NTSTATUS SERVICECALL +NtQuerySemaphore(IN HANDLE SemaphoreHandle, + IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + OUT PVOID SemaphoreInformation, + IN ULONG SemaphoreInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQuerySemaphore); + +/* 140 */ +/* + NTSTATUS SERVICECALL + NtQuerySymbolicLinkObject(IN HANDLE LinkHandle, + OUT PUNICODE_STRING LinkTarget, + OUT PULONG ResultLength OPTIONAL) + { + return -ENOSYS; + } + */ + NTSTATUS SERVICECALL +NtQuerySystemEnvironmentValue (IN PUNICODE_STRING VariableName, + OUT PWSTR ValueBuffer, + IN ULONG ValueBufferLength, + IN OUT PULONG ReturnLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQuerySystemEnvironmentValue); + + NTSTATUS SERVICECALL +NtQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG Length, + OUT PULONG UnsafeResultLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQuerySystemInformation); + + NTSTATUS SERVICECALL +NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQuerySystemTime); + + NTSTATUS SERVICECALL +NtQueryTimer(IN HANDLE TimerHandle, + IN TIMER_INFORMATION_CLASS TimerInformationClass, + OUT PVOID TimerInformation, + IN ULONG TimerInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryTimer); + +/* 145 */ + NTSTATUS SERVICECALL +NtQueryTimerResolution(OUT PULONG MinimumResolution, + OUT PULONG MaximumResolution, + OUT PULONG ActualResolution) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryTimerResolution); + + NTSTATUS SERVICECALL +NtQueryValueKey(IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryValueKey); + +/* + NTSTATUS SERVICECALL + NtQueryVirtualMemory (IN HANDLE ProcessHandle, + IN PVOID Address, + IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass, + OUT PVOID VirtualMemoryInformation, + IN ULONG Length, + OUT PULONG UnsafeResultLength) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtQueryVolumeInformationFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtQueryVolumeInformationFile); + +/* + NTSTATUS SERVICECALL + NtQueueApcThread(HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2) + { + return -ENOSYS; + } + */ + +/* 150 */ + NTSTATUS SERVICECALL +NtRaiseException(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context, + IN BOOLEAN SearchFrames) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtRaiseException); + + NTSTATUS SERVICECALL +NtRaiseHardError(IN NTSTATUS ErrorStatus, + IN ULONG NumberOfParameters, + IN ULONG UnicodeStringParameterMask, + IN PULONG_PTR Parameters, + IN ULONG ValidResponseOptions, + OUT PULONG Response) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtRaiseHardError); + +/* + NTSTATUS SERVICECALL + NtReadFile(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtReadFileScatter(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription [], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtReadFileScatter); + + NTSTATUS SERVICECALL +NtReadRequestData (HANDLE PortHandle, + PPORT_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG Returnlength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtReadRequestData); + +/* 155 */ +/* + NTSTATUS SERVICECALL + NtReadVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtRegisterThreadTerminatePort(HANDLE PortHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtRegisterThreadTerminatePort); + +/* + NTSTATUS SERVICECALL + NtReleaseMutant(IN HANDLE MutantHandle, + IN PLONG PreviousCount OPTIONAL) + { + return -ENOSYS; + } + */ + +/* + NTSTATUS SERVICECALL + NtReleaseSemaphore(IN HANDLE SemaphoreHandle, + IN LONG ReleaseCount, + OUT PLONG PreviousCount OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtRemoveIoCompletion(IN HANDLE IoCompletionHandle, + OUT PVOID *CompletionKey, + OUT PVOID *CompletionContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtRemoveIoCompletion); + +/* 160 */ + NTSTATUS SERVICECALL +NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes, + IN HANDLE Key, + IN POBJECT_ATTRIBUTES ReplacedObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtReplaceKey); + + NTSTATUS SERVICECALL +NtReplyPort (IN HANDLE PortHandle, + IN PPORT_MESSAGE LpcReply) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtReplyPort); + + NTSTATUS SERVICECALL +NtReplyWaitReceivePort(IN HANDLE PortHandle, + OUT PVOID *PortContext OPTIONAL, + IN PPORT_MESSAGE ReplyMessage OPTIONAL, + OUT PPORT_MESSAGE ReceiveMessage) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtReplyWaitReceivePort); + + NTSTATUS SERVICECALL +NtReplyWaitReplyPort (HANDLE PortHandle, + PPORT_MESSAGE ReplyMessage) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtReplyWaitReplyPort); + + NTSTATUS SERVICECALL +NtRequestPort (IN HANDLE PortHandle, + IN PPORT_MESSAGE LpcMessage) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtRequestPort); + +/* 165 */ + NTSTATUS SERVICECALL +NtRequestWaitReplyPort (IN HANDLE PortHandle, + PPORT_MESSAGE UnsafeLpcRequest, + PPORT_MESSAGE UnsafeLpcReply) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtRequestWaitReplyPort); + +/* + NTSTATUS SERVICECALL + NtResetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtRestoreKey (IN HANDLE KeyHandle, + IN HANDLE FileHandle, + IN ULONG RestoreFlags) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtRestoreKey); + +/* + NTSTATUS SERVICECALL + NtResumeThread(IN HANDLE ThreadHandle, + IN PULONG SuspendCount OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtSaveKey (IN HANDLE KeyHandle, + IN HANDLE FileHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSaveKey); + +/* 170 */ + NTSTATUS SERVICECALL +NtSaveKeyEx(IN HANDLE KeyHandle, + IN HANDLE FileHandle, + IN ULONG Flags) /* REG_STANDARD_FORMAT, etc.. */ +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSaveKeyEx); + + NTSTATUS SERVICECALL +NtSetBootEntryOrder(IN ULONG Unknown1, + IN ULONG Unknown2) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetBootEntryOrder); + + NTSTATUS SERVICECALL +NtSetBootOptions(ULONG Unknown1, + ULONG Unknown2) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetBootOptions); + + NTSTATUS SERVICECALL +NtSetIoCompletion(IN HANDLE IoCompletionPortHandle, + IN PVOID CompletionKey, + IN PVOID CompletionContext, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetIoCompletion); +/* + NTSTATUS SERVICECALL + NtSetContextThread(IN HANDLE ThreadHandle, + IN PCONTEXT ThreadContext) + { + return -ENOSYS; + } + */ + +/* 175 */ + NTSTATUS SERVICECALL +NtSetDefaultHardErrorPort(IN HANDLE PortHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetDefaultHardErrorPort); + + NTSTATUS SERVICECALL +NtSetDefaultLocale(IN BOOLEAN UserProfile, + IN LCID DefaultLocaleId) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetDefaultLocale); + + NTSTATUS SERVICECALL +NtSetDefaultUILanguage(IN LANGID LanguageId) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetDefaultUILanguage); + + NTSTATUS SERVICECALL +NtSetEaFile(IN HANDLE FileHandle, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID EaBuffer, + IN ULONG EaBufferSize) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetEaFile); + +/* + NTSTATUS SERVICECALL + NtSetEvent(IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL) + { + return -ENOSYS; + } + */ + +/* 180 */ + NTSTATUS SERVICECALL +NtSetHighEventPair(IN HANDLE EventPairHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetHighEventPair); + + NTSTATUS SERVICECALL +NtSetHighWaitLowEventPair(IN HANDLE EventPairHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetHighWaitLowEventPair); + +/* + NTSTATUS SERVICECALL + NtSetInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtSetInformationKey (IN HANDLE KeyHandle, + IN KEY_SET_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG KeyInformationLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetInformationKey); + + + NTSTATUS SERVICECALL +NtSetInformationJobObject (HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetInformationJobObject); + +/* 185 */ +/* + NTSTATUS SERVICECALL + NtSetInformationObject (IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + IN PVOID ObjectInformation, + IN ULONG Length) + { + return -ENOSYS; + } + */ +/* + NTSTATUS SERVICECALL + NtSetInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength) + { + return -ENOSYS; + } + */ + +/* + NTSTATUS SERVICECALL + NtSetInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength) + { + return -ENOSYS; + } + */ + NTSTATUS SERVICECALL +NtSetInformationToken(IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetInformationToken); + +NTSTATUS + SERVICECALL +NtSetIntervalProfile(IN ULONG Interval, + IN KPROFILE_SOURCE Source) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetIntervalProfile); + +/* 190 */ + NTSTATUS SERVICECALL +NtSetLdtEntries (ULONG Selector1, + LDT_ENTRY LdtEntry1, + ULONG Selector2, + LDT_ENTRY LdtEntry2) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetLdtEntries); + + NTSTATUS SERVICECALL +NtSetLowEventPair(IN HANDLE EventPairHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetLowEventPair); + + NTSTATUS SERVICECALL +NtSetLowWaitHighEventPair(IN HANDLE EventPairHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetLowWaitHighEventPair); + + NTSTATUS SERVICECALL +NtSetQuotaInformationFile(HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID Buffer, + ULONG BufferLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetQuotaInformationFile); + + NTSTATUS SERVICECALL +NtSetSecurityObject(IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetSecurityObject); + +/* 195 */ + NTSTATUS SERVICECALL +NtSetSystemEnvironmentValue (IN PUNICODE_STRING VariableName, + IN PUNICODE_STRING Value) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetSystemEnvironmentValue); + + NTSTATUS SERVICECALL +NtSetSystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + IN PVOID SystemInformation, + IN ULONG SystemInformationLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetSystemInformation); + + NTSTATUS SERVICECALL +NtSetSystemPowerState(IN POWER_ACTION SystemAction, + IN SYSTEM_POWER_STATE MinSystemState, + IN ULONG Flags) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetSystemPowerState); + + NTSTATUS SERVICECALL +NtSetSystemTime(IN PLARGE_INTEGER SystemTime, + OUT PLARGE_INTEGER PreviousTime OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetSystemTime); + + NTSTATUS SERVICECALL +NtSetTimer(IN HANDLE TimerHandle, + IN PLARGE_INTEGER DueTime, + IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL, + IN PVOID TimerContext OPTIONAL, + IN BOOLEAN WakeTimer, + IN LONG Period OPTIONAL, + OUT PBOOLEAN PreviousState OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetTimer); + +/* 200 */ + NTSTATUS SERVICECALL +NtSetTimerResolution(IN ULONG DesiredResolution, + IN BOOLEAN SetResolution, + OUT PULONG CurrentResolution) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetTimerResolution); + + NTSTATUS SERVICECALL +NtSetUuidSeed(IN PUCHAR Seed) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetUuidSeed); + + NTSTATUS SERVICECALL +NtSetValueKey(IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN ULONG TitleIndex, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetValueKey); + + NTSTATUS SERVICECALL +NtSetVolumeInformationFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSetVolumeInformationFile); + + NTSTATUS SERVICECALL +NtShutdownSystem(IN SHUTDOWN_ACTION Action) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtShutdownSystem); + +/* 205*/ +/* + NTSTATUS SERVICECALL + NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, + IN HANDLE WaitableObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) + { + return -ENOSYS; + } + */ + NTSTATUS SERVICECALL +NtStartProfile(IN HANDLE ProfileHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtStartProfile); + + NTSTATUS SERVICECALL +NtStopProfile(IN HANDLE ProfileHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtStopProfile); + +/* + NTSTATUS SERVICECALL + NtSuspendThread(IN HANDLE ThreadHandle, + IN PULONG PreviousSuspendCount OPTIONAL) + { + return -ENOSYS; + } + */ + + + NTSTATUS SERVICECALL +NtSystemDebugControl(DEBUG_CONTROL_CODE ControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength, + PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtSystemDebugControl); + +/* 210 */ + NTSTATUS SERVICECALL +NtTerminateJobObject(HANDLE JobHandle, + NTSTATUS ExitStatus) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtTerminateJobObject); + +/* + NTSTATUS SERVICECALL + NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, + IN NTSTATUS ExitStatus) + { + return -ENOSYS; + } + */ + +/* + NTSTATUS SERVICECALL + NtTerminateThread(IN HANDLE ThreadHandle, + IN NTSTATUS ExitStatus) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtTestAlert(VOID) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtTestAlert); + + NTSTATUS SERVICECALL +NtTraceEvent(IN ULONG TraceHandle, + IN ULONG Flags, + IN ULONG TraceHeaderLength, + IN struct _EVENT_TRACE_HEADER* TraceHeader) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtTraceEvent); + +/* 215 */ + NTSTATUS SERVICECALL +NtTranslateFilePath(ULONG Unknown1, + ULONG Unknown2, + ULONG Unknown3) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtTranslateFilePath); + + NTSTATUS SERVICECALL +NtUnloadDriver(IN PUNICODE_STRING DriverServiceName) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtUnloadDriver); + + NTSTATUS SERVICECALL +NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtUnloadKey); + + NTSTATUS SERVICECALL +NtUnlockFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Length, + OUT ULONG Key OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtUnlockFile); + + NTSTATUS SERVICECALL +NtUnlockVirtualMemory(HANDLE ProcessHandle, + PVOID BaseAddress, + ULONG NumberOfBytesToUnlock, + PULONG NumberOfBytesUnlocked OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtUnlockVirtualMemory); + +/* 220 */ +/* + NTSTATUS SERVICECALL + NtUnmapViewOfSection (HANDLE ProcessHandle, + PVOID BaseAddress) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtVdmControl(ULONG ControlCode, + PVOID ControlData) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtVdmControl); + +/* + NTSTATUS + SERVICECALL + NtWaitForMultipleObjects(IN ULONG ObjectCount, + IN PHANDLE HandleArray, + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) + { + + return -ENOSYS; + } + + NTSTATUS SERVICECALL + NtWaitForSingleObject(IN HANDLE ObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) + { + return -ENOSYS; + } + */ + NTSTATUS SERVICECALL +NtWaitHighEventPair(IN HANDLE EventPairHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtWaitHighEventPair); + +/* 225 */ + NTSTATUS SERVICECALL +NtWaitLowEventPair(IN HANDLE EventPairHandle) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtWaitLowEventPair); + +/* + NTSTATUS SERVICECALL + NtWriteFile (IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL) + { + return -ENOSYS; + } + */ + + NTSTATUS SERVICECALL +NtWriteFileGather(IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription [], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtWriteFileGather); + + NTSTATUS SERVICECALL +NtWriteRequestData (HANDLE PortHandle, + PPORT_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnLength) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtWriteRequestData); + +/* + NTSTATUS SERVICECALL + NtWriteVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten OPTIONAL) + { + return -ENOSYS; + } + */ + +/* 230 */ + NTSTATUS SERVICECALL +NtW32Call(IN ULONG RoutineIndex, + IN PVOID Argument, + IN ULONG ArgumentLength, + OUT PVOID* Result OPTIONAL, + OUT PULONG ResultLength OPTIONAL) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtW32Call); + + NTSTATUS SERVICECALL +NtYieldExecution(VOID) +{ + return -ENOSYS; +} +EXPORT_SYMBOL(NtYieldExecution); + +/* not win32 syscall, just for wine service use */ +NTSTATUS call_req_handler(struct w32thread * thread) +{ + enum request req = thread->req.request_header.req; + + thread->reply_size = 0; + set_error(STATUS_SUCCESS); + memset(&thread->reply, 0, sizeof(thread->reply)); + + if (req < REQ_NB_REQUESTS) { + req_handlers[req](&thread->req, &thread->reply); + } else { + set_error(STATUS_NOT_IMPLEMENTED); + return STATUS_NOT_IMPLEMENTED ; + } + + thread->reply.reply_header.error = thread->error; + thread->reply.reply_header.reply_size = thread->reply_size; +#if 0 + if (req == REQ_create_key) { + PRINTK_REPLY(&thread->reply); + } +#endif + + return (NTSTATUS)thread->error; +} + +/* not win32 syscall, just for wine service use */ + NTSTATUS SERVICECALL +NtWineService( PSERVER_REQUEST_INFO ReqMsg) +{ + struct w32thread * thread = (PTSB)get_current_w32thread(); + struct __server_request_info req_msg; + NTSTATUS status = STATUS_SUCCESS; + int i; + + ktrace("NtWineService\n"); + + set_error(STATUS_SUCCESS); + + if(!ReqMsg || !thread) + return STATUS_UNSUCCESSFUL; + + if (copy_from_user(&req_msg, ReqMsg, sizeof(req_msg))) + return STATUS_UNSUCCESSFUL; + + memcpy(&thread->req, &req_msg, sizeof(thread->req)); + + if((thread->req_toread = thread->req.request_header.request_size)) { +#if 0 + if(!(thread->req_data = kmalloc(thread->req_toread, GFP_KERNEL))) + return STATUS_UNSUCCESSFUL; +#endif + if (!(thread->req_data = malloc(thread->req_toread))) + return STATUS_UNSUCCESSFUL; + + + for (i=0; ireq_data + thread->req.request_header.request_size - thread->req_toread, + req_msg.data[i].ptr, req_msg.data[i].size)) { + + status = STATUS_UNSUCCESSFUL; + goto out; + } + + thread->req_toread -= req_msg.data[i].size; + + } + } + + status = call_req_handler(thread); + + /*FIXME*/ + if (copy_to_user(ReqMsg, &thread->reply, sizeof(thread->reply))) { + status = STATUS_UNSUCCESSFUL; + goto out; + } + + if (thread->reply_size) { + if (copy_to_user(req_msg.reply_data, thread->reply_data, thread->reply_size)) { + status = STATUS_UNSUCCESSFUL; + goto out; + } + } + +out: + if (thread->req_data) { + kfree(thread->req_data); + thread->req_data = NULL; + } + + return status; +} +EXPORT_SYMBOL(NtWineService); +/* Syscall function table. Currently only 2 functions are stubbed for + testing, and to be used as a prototype */ + +SSDT MainSSDT[] = { + (SSDT)NtAcceptConnectPort, /* 0 */ + (SSDT)NtAccessCheck, /* 1 */ + (SSDT)NtAccessCheckAndAuditAlarm, + (SSDT)NtAddAtom, + (SSDT)NtAddBootEntry, + (SSDT)NtAdjustGroupsToken, /* 5 */ + (SSDT)NtAdjustPrivilegesToken, + (SSDT)NtAlertResumeThread, + (SSDT)NtAlertThread, + (SSDT)NtAllocateLocallyUniqueId, + (SSDT)NtAllocateUuids, /* 10 */ + (SSDT)NtAllocateVirtualMemory, + (SSDT)NtAssignProcessToJobObject, + (SSDT)NtCallbackReturn, + (SSDT)NtCancelIoFile, + (SSDT)NtCancelTimer, /* 15 */ + (SSDT)NtClearEvent, + (SSDT)NtClose, + (SSDT)NtCloseObjectAuditAlarm, + (SSDT)NtCompleteConnectPort, + (SSDT)NtConnectPort, /* 20 */ + (SSDT)NtContinue, + (SSDT)NtCreateDirectoryObject, + (SSDT)NtCreateEvent, + (SSDT)NtCreateEventPair, + (SSDT)NtCreateFile, /* 25 */ + (SSDT)NtCreateIoCompletion, + (SSDT)NtCreateJobObject, + (SSDT)NtCreateKey, + (SSDT)NtCreateMailslotFile, + (SSDT)NtCreateMutant, /* 30 */ + (SSDT)NtCreateNamedPipeFile, + (SSDT)NtCreatePagingFile, + (SSDT)NtCreatePort, + (SSDT)NtCreateProcess, + (SSDT)NtCreateProfile, /* 35 */ + (SSDT)NtCreateSection, + (SSDT)NtCreateSemaphore, + (SSDT)NtCreateSymbolicLinkObject, + (SSDT)NtCreateThread, + (SSDT)NtCreateTimer, /* 40 */ + (SSDT)NtCreateToken, + (SSDT)NtCreateWaitablePort, + (SSDT)NtDelayExecution, + (SSDT)NtDeleteAtom, + (SSDT)NtDeleteBootEntry, /* 45 */ + (SSDT)NtDeleteFile, + (SSDT)NtDeleteKey, + (SSDT)NtDeleteObjectAuditAlarm, + (SSDT)NtDeleteValueKey, + (SSDT)NtDeviceIoControlFile, /* 50 */ + (SSDT)NtDisplayString, + (SSDT)NtDuplicateObject, + (SSDT)NtDuplicateToken, + (SSDT)NtEnumerateBootEntries, + (SSDT)NtEnumerateKey, /* 55 */ + (SSDT)NtEnumerateValueKey, + (SSDT)NtExtendSection, + (SSDT)NtFindAtom, + (SSDT)NtFlushBuffersFile, + (SSDT)NtFlushInstructionCache, /* 60 */ + (SSDT)NtFlushKey, + (SSDT)NtFlushVirtualMemory, + (SSDT)NtFlushWriteBuffer, + (SSDT)NtFreeVirtualMemory, + (SSDT)NtFsControlFile, /* 65 */ + (SSDT)NtGetContextThread, + (SSDT)NtGetPlugPlayEvent, + (SSDT)NtGetTickCount, + (SSDT)NtImpersonateClientOfPort, + (SSDT)NtImpersonateThread, /* 70 */ + (SSDT)NtInitializeRegistry, + (SSDT)NtInitiatePowerAction, + (SSDT)NtIsProcessInJob, + (SSDT)NtListenPort, + (SSDT)NtLoadDriver, /* 75 */ + (SSDT)NtLoadKey, + (SSDT)NtLoadKey2, + (SSDT)NtLockFile, + (SSDT)NtLockVirtualMemory, + (SSDT)NtMakePermanentObject, /* 80 */ + (SSDT)NtMakeTemporaryObject, + (SSDT)NtMapViewOfSection, + (SSDT)NtNotifyChangeDirectoryFile, + (SSDT)NtNotifyChangeKey, + (SSDT)NtOpenDirectoryObject, /* 85 */ + (SSDT)NtOpenEvent, + (SSDT)NtOpenEventPair, + (SSDT)NtOpenFile, + (SSDT)NtOpenIoCompletion, + (SSDT)NtOpenJobObject, /* 90 */ + (SSDT)NtOpenKey, + (SSDT)NtOpenMutant, + (SSDT)NtOpenObjectAuditAlarm, + (SSDT)NtOpenProcess, + (SSDT)NtOpenProcessToken, /* 95 */ + (SSDT)NtOpenProcessTokenEx, + (SSDT)NtOpenSection, + (SSDT)NtOpenSemaphore, + (SSDT)NtOpenSymbolicLinkObject, + (SSDT)NtOpenThread, /* 100 */ + (SSDT)NtOpenThreadToken, + (SSDT)NtOpenThreadTokenEx, + (SSDT)NtOpenTimer, + (SSDT)NtPlugPlayControl, + (SSDT)NtPowerInformation, /* 105 */ + (SSDT)NtPrivilegeCheck, + (SSDT)NtPrivilegedServiceAuditAlarm, + (SSDT)NtPrivilegeObjectAuditAlarm, + (SSDT)NtProtectVirtualMemory, + (SSDT)NtPulseEvent, /* 110 */ + (SSDT)NtQueryInformationAtom, + (SSDT)NtQueryAttributesFile, + (SSDT)NtQueryBootEntryOrder, + (SSDT)NtQueryBootOptions, + (SSDT)NtQueryDefaultLocale, /* 115 */ + (SSDT)NtQueryDefaultUILanguage, + (SSDT)NtQueryDirectoryFile, + (SSDT)NtQueryDirectoryObject, + (SSDT)NtQueryEaFile, + (SSDT)NtQueryEvent, /* 120 */ + (SSDT)NtQueryFullAttributesFile, + (SSDT)NtQueryInformationFile, + (SSDT)NtQueryInformationJobObject, + (SSDT)NtQueryInformationPort, + (SSDT)NtQueryInformationProcess, /* 125 */ + (SSDT)NtQueryInformationThread, + (SSDT)NtQueryInformationToken, + (SSDT)NtQueryInstallUILanguage, + (SSDT)NtQueryIntervalProfile, + (SSDT)NtQueryIoCompletion, /* 130 */ + (SSDT)NtQueryKey, + (SSDT)NtQueryMultipleValueKey, + (SSDT)NtQueryMutant, + (SSDT)NtQueryObject, + (SSDT)NtQueryPerformanceCounter, /* 135 */ + (SSDT)NtQueryQuotaInformationFile, + (SSDT)NtQuerySection, + (SSDT)NtQuerySecurityObject, + (SSDT)NtQuerySemaphore, + (SSDT)NtQuerySymbolicLinkObject, /* 140 */ + (SSDT)NtQuerySystemEnvironmentValue, + (SSDT)NtQuerySystemInformation, + (SSDT)NtQuerySystemTime, + (SSDT)NtQueryTimer, + (SSDT)NtQueryTimerResolution, /* 145 */ + (SSDT)NtQueryValueKey, + (SSDT)NtQueryVirtualMemory, + (SSDT)NtQueryVolumeInformationFile, + (SSDT)NtQueueApcThread, + (SSDT)NtRaiseException, /* 150 */ + (SSDT)NtRaiseHardError, + (SSDT)NtReadFile, + (SSDT)NtReadFileScatter, + (SSDT)NtReadRequestData, + (SSDT)NtReadVirtualMemory, /* 155 */ + (SSDT)NtRegisterThreadTerminatePort, + (SSDT)NtReleaseMutant, + (SSDT)NtReleaseSemaphore, + (SSDT)NtRemoveIoCompletion, + (SSDT)NtReplaceKey, /* 160 */ + (SSDT)NtReplyPort, + (SSDT)NtReplyWaitReceivePort, + (SSDT)NtReplyWaitReplyPort, + (SSDT)NtRequestPort, + (SSDT)NtRequestWaitReplyPort, /* 165 */ + (SSDT)NtResetEvent, + (SSDT)NtRestoreKey, + (SSDT)NtResumeThread, + (SSDT)NtSaveKey, + (SSDT)NtSaveKeyEx, /* 170 */ + (SSDT)NtSetBootEntryOrder, + (SSDT)NtSetBootOptions, + (SSDT)NtSetIoCompletion, + (SSDT)NtSetContextThread, + (SSDT)NtSetDefaultHardErrorPort, /* 175 */ + (SSDT)NtSetDefaultLocale, + (SSDT)NtSetDefaultUILanguage, + (SSDT)NtSetEaFile, + (SSDT)NtSetEvent, + (SSDT)NtSetHighEventPair, /* 180 */ + (SSDT)NtSetHighWaitLowEventPair, + (SSDT)NtSetInformationFile, + (SSDT)NtSetInformationKey, + (SSDT)NtSetInformationJobObject, + (SSDT)NtSetInformationObject, /* 185 */ + (SSDT)NtSetInformationProcess, + (SSDT)NtSetInformationThread, + (SSDT)NtSetInformationToken, + (SSDT)NtSetIntervalProfile, + (SSDT)NtSetLdtEntries, /* 190 */ + (SSDT)NtSetLowEventPair, + (SSDT)NtSetLowWaitHighEventPair, + (SSDT)NtSetQuotaInformationFile, + (SSDT)NtSetSecurityObject, + (SSDT)NtSetSystemEnvironmentValue, /* 195 */ + (SSDT)NtSetSystemInformation, + (SSDT)NtSetSystemPowerState, + (SSDT)NtSetSystemTime, + (SSDT)NtSetTimer, + (SSDT)NtSetTimerResolution, /* 200 */ + (SSDT)NtSetUuidSeed, + (SSDT)NtSetValueKey, + (SSDT)NtSetVolumeInformationFile, + (SSDT)NtShutdownSystem, + (SSDT)NtSignalAndWaitForSingleObject, /* 205 */ + (SSDT)NtStartProfile, + (SSDT)NtStopProfile, + (SSDT)NtSuspendThread, + (SSDT)NtSystemDebugControl, + (SSDT)NtTerminateJobObject, /* 210 */ + (SSDT)NtTerminateProcess, + (SSDT)NtTerminateThread, + (SSDT)NtTestAlert, + (SSDT)NtTraceEvent, + (SSDT)NtTranslateFilePath, /* 215 */ + (SSDT)NtUnloadDriver, + (SSDT)NtUnloadKey, + (SSDT)NtUnlockFile, + (SSDT)NtUnlockVirtualMemory, + (SSDT)NtUnmapViewOfSection, /* 220 */ + (SSDT)NtVdmControl, + (SSDT)NtWaitForMultipleObjects, + (SSDT)NtWaitForSingleObject, + (SSDT)NtWaitHighEventPair, + (SSDT)NtWaitLowEventPair, /* 225 */ + (SSDT)NtWriteFile, + (SSDT)NtWriteFileGather, + (SSDT)NtWriteRequestData, + (SSDT)NtWriteVirtualMemory, + (SSDT)NtW32Call, /* 230 */ + (SSDT)NtYieldExecution, + (SSDT)NtWineService, +}; +EXPORT_SYMBOL(MainSSDT); + +/* number of parameters for each function */ + +SSPT MainSSPT[] = { + 6, 8, 11, 3, 2, /* 0 */ + 6, 6, 2, 1, 1, + 4, 6, 2, 3, 2, /* 10 */ + 2, 1, 1, 3, 1, + 8, 2, 3, 5, 3, /* 20 */ + 11, 4, 3, 7, 8, + 4, 14, 4, 5, 8, /* 30 */ + 9, 7, 5, 4, 8, + 4, 13, 5, 2, 1, /* 40 */ + 2, 1, 1, 3, 2, + 10, 1, 7, 6, 2, /* 50 */ + 6, 6, 2, 3, 2, + 3, 1, 4, 0, 4, /* 60 */ + 10, 2, 4, 0, 2, + 3, 1, 4, 2, 2, /* 70 */ + 1, 2, 3, 10, 4, + 1, 1, 10, 9, 10,/* 80 */ + 3, 3, 3, 6, 3, + 3, 3, 3, 12, 4, /* 90 */ + 3, 4, 3, 3, 3, + 4, 4, 5, 3, 3, /* 100 */ + 5, 3, 5, 6, 5, + 2, 5, 2, 2, 2, /* 110 */ + 2, 1, 11, 7, 9, + 5, 2, 5, 5, 5, /* 120 */ + 5, 5, 5, 1, 2, + 5, 5, 6, 5, 5, /* 130 */ + 2, 9, 5, 5, 5, + 3, 4, 4, 1, 5, /* 140 */ + 3, 6, 6, 5, 5, + 3, 6, 9, 9, 6, /* 150 */ + 5, 1, 2, 3, 5, + 3, 2, 4, 2, 2, /* 160 */ + 3, 2, 3, 2, 2, + 3, 2, 2, 5, 2, /* 170 */ + 1, 2, 1, 4, 2, + 1, 1, 5, 4, 4, /* 180 */ + 4, 4, 4, 4, 2, + 4, 1, 1, 4, 3, /* 190 */ + 2, 3, 3, 2, 7, + 3, 1, 6, 5, 1, /* 200 */ + 4, 1, 1, 2, 6, + 2, 2, 2, 0, 4, /* 210 */ + 3, 1, 1, 5, 4, + 2, 2, 5, 3, 1, /* 220 */ + 1, 9, 9, 6, 5, + 5, 0, 1 /* 230 */ +}; +EXPORT_SYMBOL(MainSSPT); + + +#define MIN_SYSCALL_NUMBER 0 +#define MAX_SYSCALL_NUMBER 232 +#define NUMBER_OF_SYSCALLS 233 + +/* From ReactOS, don't touch. */ + +SSDT_ENTRY +KeServiceDescriptorTable[4] = { + { MainSSDT, NULL, NUMBER_OF_SYSCALLS, MainSSPT }, + { NULL, NULL, 0, NULL }, + { NULL, NULL, 0, NULL }, + { NULL, NULL, 0, NULL } +}; +EXPORT_SYMBOL(KeServiceDescriptorTable); +#endif diff --git a/unifiedkernel/ke/wait.c b/unifiedkernel/ke/wait.c new file mode 100644 index 0000000..91c47b3 --- /dev/null +++ b/unifiedkernel/ke/wait.c @@ -0,0 +1,477 @@ +/* + * wait.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * wait.c: thread wait on object + * Refered to Kernel-win32 code + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +/* Tells us if the Timer or Event is a Syncronization or Notification Object */ +#define TIMER_OR_EVENT_TYPE 0x7L + +/* One of the Reserved Wait Blocks, this one is for the Thread's Timer */ +#define TIMER_WAIT_BLOCK 0x3L + +void call_kapc(void){ + /* FIXME */ +} +EXPORT_SYMBOL(call_kapc); + +VOID +STDCALL +block_thread(PNTSTATUS Status, + UCHAR Alertable, + ULONG WaitMode, + UCHAR WaitReason, + PULONG_PTR Timeout) +{ + struct kthread * thread = (struct kthread *)get_current_ethread(); + struct kwait_block * wait_block; + + ktrace("block thread\n"); + if (thread->apc_state.kapc_pending) { + /* Remove Waits */ + wait_block = thread->wait_block_list; + do { + list_del(&wait_block->wait_list_entry); + wait_block = wait_block->next_wait_block; + } while (wait_block!= thread->wait_block_list); + thread->wait_block_list = NULL; + + /* Ready Dispatch it and return status */ + call_kapc(); + + if (Status != NULL) *Status = STATUS_KERNEL_APC; + + } else { + /* Set the Thread Data as Requested */ + thread->alertable = Alertable; + thread->wait_mode = (UCHAR)WaitMode; + thread->wait_reason = WaitReason; + + local_irq_enable(); + set_current_state(TASK_INTERRUPTIBLE); + *Timeout = schedule_timeout(*Timeout); + local_irq_disable(); + + /* Dispatch it and return status */ + if (signal_pending(current)) { + /* thread is signaled + * Remove Waits */ + wait_block = thread->wait_block_list; + do { + list_del(&wait_block->wait_list_entry); + wait_block = wait_block->next_wait_block; + } while (wait_block!= thread->wait_block_list); + thread->wait_block_list = NULL; + *Status = -EINTR; /* Linux error code for special check */ + return; + } + + if(Status) { + if (!(*Timeout)){ + /* thread is signaled + * Remove Waits */ + wait_block = thread->wait_block_list; + do { + list_del(&wait_block->wait_list_entry); + wait_block = wait_block->next_wait_block; + } while (wait_block!= thread->wait_block_list); + thread->wait_block_list = NULL; + *Status = STATUS_TIMEOUT; + } else *Status = ((struct kthread * )current->ethread)->wait_status; + } + } + + /* FIXME */ +#if 0 + KfLowerIrql(Thread->WaitIrql); +#endif +} +EXPORT_SYMBOL(block_thread); + +VOID +inline +check_alert(BOOLEAN Alertable, + struct kthread *CurrentThread, + KPROCESSOR_MODE WaitMode, + PNTSTATUS Status) +{ + /* At this point, we have to do a wait, so make sure we can make the thread Alertable if requested */ + if (Alertable) { + + /* If the Thread is Alerted, set the Wait Status accordingly */ + if (CurrentThread->alerted[(int)WaitMode]) { + CurrentThread->alerted[(int)WaitMode] = false; + *Status = STATUS_ALERTED; + + /* If there are User APCs Pending, then we can't really be alertable */ + } else if ((!list_empty(&CurrentThread->apc_state.apc_list_head[UserMode])) && + (WaitMode == UserMode)) { + CurrentThread->apc_state.uapc_pending= true; + *Status = STATUS_USER_APC; + } + + /* If there are User APCs Pending and we are waiting in usermode, then we must notify the caller */ + } else if ((CurrentThread->apc_state.uapc_pending) && (WaitMode == UserMode)) { + *Status = STATUS_USER_APC; + } + + *Status = STATUS_WAIT_0; +} +EXPORT_SYMBOL(check_alert); + + +VOID +satisfy_object_wait(struct dispatcher_header * Object, + struct kthread *Thread) +{ + /* Special case for Mutants */ + if (Object->type == MutantObject) { + Object->signal_state--; + + /* Check if it's now non-signaled */ + if (Object->signal_state == 0) + { + ((struct kmutant *)Object)->owner_thread = Thread; + Thread->kernel_apc_disable -= ((struct kmutant *)Object)->apc_disable; + + /* Check if it's abandoned */ + if (((struct kmutant *)Object)->abandoned) { + /* Unabandon it */ + ((struct kmutant *)Object)->abandoned = FALSE; + Thread->wait_status = STATUS_ABANDONED; + } + + list_add(&((struct kmutant *)Object)->mutant_list_entry, &Thread->mutant_list_head); + } + } else if ((Object->type & TIMER_OR_EVENT_TYPE) == EventSynchronizationObject) { + Object->signal_state= 0; + } else if (Object->type == SemaphoreObject) { + Object->signal_state--; + } +} + +void +satisfy_multi_obj_waits(struct kwait_block * WaitBlock) +{ + struct kwait_block * first_block = WaitBlock; + struct kthread * wait_thread = WaitBlock->thread; + + /* Loop through all the Wait Blocks, and wake each Object */ + do { + /* Wake the Object */ + satisfy_object_wait(WaitBlock->object, wait_thread); + WaitBlock = WaitBlock->next_wait_block; + } while (WaitBlock != first_block); +} + +NTSTATUS +STDCALL +wait_for_single_object(PVOID Object, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout) +{ + NTSTATUS status; + struct kwait_block wait_block[MAXIMUM_WAIT_OBJECTS]; + + status = wait_for_multi_objs(1, + &Object, + WaitAll, + UserRequest, + WaitMode, + Alertable, + Timeout, + wait_block); + return status; +} +EXPORT_SYMBOL(wait_for_single_object); + +BOOL +is_object_waitable(PVOID Object) +{ + return 0; +} + + +VOID +wait_test(struct dispatcher_header * Object, + KPRIORITY Increment) +{ + struct list_head * wait_entry; + struct list_head * wait_list; + struct kwait_block * cur_wait_block; + struct kwait_block * next_wait_block; + struct kthread * wait_thread; + + wait_list = &Object->wait_list_head; /* TODO kernel */ + wait_entry = wait_list->next; + while ((wait_entry != wait_list) && (Object->signal_state > 0)) { + /* Get the current wait block */ + cur_wait_block = list_entry(wait_entry, struct kwait_block, wait_list_entry); + wait_thread = cur_wait_block->thread; + + if (cur_wait_block->wait_type == WaitAny) { + + wait_entry = wait_entry->prev; + satisfy_object_wait(Object, wait_thread); + } else { + + next_wait_block = cur_wait_block->next_wait_block; + + /* Loop first to make sure they are valid */ + while (next_wait_block != cur_wait_block) { + if (!is_object_signaled(next_wait_block->object, wait_thread)) { + /* It's not, move to the next one */ + goto SkipUnwait; + } + + next_wait_block = next_wait_block->next_wait_block; + } + + /* All the objects are signaled, we can satisfy */ + wait_entry = wait_entry->prev; + satisfy_multi_obj_waits(cur_wait_block); + } + + /* All waits satisfied, unwait the thread */ + abort_wait_thread(wait_thread, cur_wait_block->wait_key, Increment); + +SkipUnwait: + wait_entry = wait_entry->next; + } + +} +EXPORT_SYMBOL(wait_test); + +NTSTATUS +STDCALL +wait_for_multi_objs(ULONG Count, + PVOID Object[], + WAIT_TYPE WaitType, + KWAIT_REASON WaitReason, + KPROCESSOR_MODE WaitMode, + BOOLEAN Alertable, + PLARGE_INTEGER Timeout, + struct kwait_block *WaitBlockArray) +{ + struct dispatcher_header * cur_obj; + struct kwait_block * wait_block; + struct kthread * cur_thread = (struct kthread *)get_current_ethread(); + unsigned long all_objects_signaled; + unsigned long wait_index; + NTSTATUS status, wait_status; + struct timespec ts; + long timeout; + + if (Timeout) { + s32 rem; + ts.tv_sec = div_s64_rem(-Timeout->QuadPart * 100, 1000000000, &rem); + ts.tv_nsec = rem; + timeout = timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec); + } + else + timeout = MAX_SCHEDULE_TIMEOUT; + + /* Check if the lock is already held */ + if (cur_thread->wait_next) { + /* Lock is held, disable Wait Next */ + cur_thread->wait_next = false; + } else { + local_irq_disable(); + /* FIXME Lock not held, acquire it */ + } + + /* Make sure the Wait Count is valid for the Thread and Maximum Wait Objects */ + if (!WaitBlockArray) { + /* FIXME Debug Check in regards to the Thread Object Limit */ + + /* Use the Thread's Wait Block */ + WaitBlockArray = &cur_thread->wait_block[0]; + } else { + /* FIXME Using our own Block Array. Check in regards to System Object Limit */ + } + + /* Start the actual Loop */ + do { + wait_status = cur_thread->wait_status; + cur_thread->wait_block_list = wait_block = WaitBlockArray; + all_objects_signaled = true; + + /* First, we'll try to satisfy the wait directly */ + for (wait_index = 0; wait_index < Count; wait_index++) { + cur_obj = (struct dispatcher_header * )Object[wait_index]; + + if (cur_obj->type == IO_TYPE_FILE) { + cur_obj = (struct dispatcher_header *)(&((PFILE_OBJECT)cur_obj)->Event); + } + + if (is_object_signaled(cur_obj, cur_thread)) { + if (WaitType == WaitAny) { + if (cur_obj->signal_state!= (LONG)MINLONG) { + /* It has a normal signal state, so unwait it and return */ + satisfy_object_wait(cur_obj, cur_thread); + if(STATUS_ABANDONED == cur_thread->wait_status) + status = cur_thread->wait_status = (STATUS_ABANDONED | wait_index); + else + status = STATUS_WAIT_0 | wait_index; + goto WaitDone; + + } else { + /* Is this a Mutant? */ + if (cur_obj->type == MutantObject) { + /* FIXME exception*/ + } + } + } + + } else { + /* One of the objects isn't signaled... if this is a WaitAll, we will fail later */ + all_objects_signaled = false; + } + + /* Set up a Wait Block for this Object */ + wait_block->object = cur_obj; + wait_block->thread = cur_thread; + if(WaitAny == WaitType) + wait_block->wait_key = (USHORT)(STATUS_WAIT_0 + wait_index); + else + wait_block->wait_key = (USHORT)(STATUS_WAIT_0); + wait_block->wait_type = (USHORT)WaitType; + wait_block->next_wait_block = wait_block + 1; + + wait_block = wait_block->next_wait_block; + } + + /* Return to the Root Wait Block */ + wait_block--; + wait_block->next_wait_block = WaitBlockArray; + + if ((WaitType == WaitAll) && (all_objects_signaled)) { + wait_block = cur_thread->wait_block_list; + + satisfy_multi_obj_waits(wait_block); + if(STATUS_ABANDONED == cur_thread->wait_status) + status = STATUS_ABANDONED_WAIT_0; + else status = STATUS_WAIT_0; + goto WaitDone; + } + + /* Make sure we can satisfy the Alertable request */ + check_alert(Alertable, cur_thread, WaitMode, &status); + + cur_thread->wait_status = status; + wait_block = cur_thread->wait_block_list; + + do { + cur_obj = wait_block->object; + list_add(&wait_block->wait_list_entry, &cur_obj->wait_list_head); + wait_block = wait_block->next_wait_block; + } while (wait_block != WaitBlockArray); + + /* Handle Kernel Queues */ + + block_thread(&status, + Alertable, + WaitMode, + (UCHAR)WaitReason, + &timeout); + + /* Check if we were executing an APC */ + if (status != STATUS_KERNEL_APC) { + local_irq_enable(); + return status; + } + + } while (true); + +WaitDone: + local_irq_enable(); + /* Release the Lock, we are done */ + if (Timeout) { + jiffies_to_timespec(timeout, &ts); + Timeout->QuadPart = -(ts.tv_sec * 10000000L + ts.tv_nsec / 100); + } + + return status; +} +EXPORT_SYMBOL(wait_for_multi_objs); + +/* Must be called with the dispatcher lock held */ +VOID +abort_wait_thread(struct kthread *Thread, + NTSTATUS WaitStatus, + KPRIORITY Increment) +{ + struct kwait_block * wait_block; + + /* If we are blocked, we must be waiting on something also */ + if(!((((struct ethread *) Thread)->et_task->state & + (TASK_STOPPED | TASK_TRACED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)) + && Thread->wait_block_list != NULL)) + return; + + wait_block = Thread->wait_block_list; + do { + list_del(&wait_block->wait_list_entry); + wait_block = wait_block->next_wait_block; + } while (wait_block != Thread->wait_block_list); + + if(STATUS_ABANDONED == Thread->wait_status) Thread->wait_status += WaitStatus - STATUS_WAIT_0; + else Thread->wait_status = WaitStatus; + + /* FIXME : Check if there's a Thread Timer */ + + /* Reschedule the Thread */ + set_tsk_need_resched(current); + wake_up_process(((struct ethread *)Thread)->et_task); +} +EXPORT_SYMBOL(abort_wait_thread); +#endif + diff --git a/unifiedkernel/ke/wcstr.c b/unifiedkernel/ke/wcstr.c new file mode 100644 index 0000000..5730505 --- /dev/null +++ b/unifiedkernel/ke/wcstr.c @@ -0,0 +1,268 @@ +/* + * wcstr.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * wcstr.c: wide char string functions + * Refered to Linux kernel code + */ + +#include "wcstr.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +/* + * copy a wide string into kernel-space + */ +long wstrncpy_from_user(wchar_t *dst, const wchar_t *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 2)) + __do_wstrncpy_from_user(dst, src, count, res); + return res; +} /* end wcsncpy_from_user() */ +EXPORT_SYMBOL(wstrncpy_from_user); + +/* + * return the size of a wide string (including the ending NUL) + * - return 0 on exception, a value greater than N if too long + */ +long wstrnlen_user(const wchar_t *s, long n) +{ + unsigned long mask = -__addr_ok(s); + unsigned long res, tmp; + + __asm__ __volatile__( + " andl %0,%%ecx\n" + "0: repne; scasw\n" + " setne %%al\n" + " subl %%ecx,%0\n" + " addl %0,%%eax\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: xorl %%eax,%%eax\n" + " jmp 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,2b\n" + ".previous" + :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp) + :"0" (n), "1" (s), "2" (0), "3" (mask) + :"cc"); + return res & mask; +} /* end wcsnlen_user() */ +EXPORT_SYMBOL(wstrnlen_user); + +static inline int do_getwname(const wchar_t __user *wname, wchar_t *page) +{ + int retval; + unsigned long len = PATH_MAX; + + if (!segment_eq(get_fs(), KERNEL_DS)) { + if ((unsigned long) wname >= TASK_SIZE) + return -EFAULT; + if (TASK_SIZE - (unsigned long) wname < PATH_MAX) + len = TASK_SIZE - (unsigned long) wname; + } + + retval = wstrncpy_from_user(page, wname, len); + if (retval > 0) { + if (retval < len) + return 0; + return -ENAMETOOLONG; + } else if (!retval) + retval = -ENOENT; + return retval; +} /* end do_getwname() */ + +wchar_t *getwname(const wchar_t __user *wname) +{ + wchar_t *tmp, *result; + + result = ERR_PTR(-ENOMEM); + tmp = __getname(); + if (tmp) { + int retval = do_getwname(wname, tmp); + result = tmp; + if (retval < 0) { + putwname(tmp); + result = ERR_PTR(retval); + } + } + return result; +} /* end getwname() */ +EXPORT_SYMBOL(getwname); + + +void putwname(const wchar_t *wname) +{ + __putname(wname); +} /* end putwname */ +EXPORT_SYMBOL(putwname); + +size_t wcslen(PWSTR ws) +{ + int d0; + register int __res; + + __asm__ __volatile__( + "repne\n\t" + "scasw\n\t" + "notl %0\n\t" + "decl %0" + : "=c"(__res), "=&D"(d0) + : "1"(ws), "a"(0), "0"(0xffffffffu) + : "memory"); + + return __res * sizeof(WCHAR); +} +EXPORT_SYMBOL(wcslen); + +WCHAR *wmemchr(const WCHAR *wcs, WCHAR wc, size_t count) +{ + int d0; + WCHAR *res; + + if (!count) + return NULL; + + asm volatile("repne\n\t" + "scasw\n\t" + "je 1f\n\t" + "movl $1,%0\n" + "1:\tdecl %0" + : "=D"(res), "=&c"(d0) + : "a"(wc), "0"(wcs), "1"(count) + : "memory"); + + return res; +} +EXPORT_SYMBOL(wmemchr); + +WCHAR *wcschr(const WCHAR *wcs, WCHAR wc) +{ + int d0; + WCHAR *res; + + asm volatile("movw %%ax,%%bx\n" + "1:\tlodsw\n\t" + "cmpw %%bx,%%ax\n\t" + "je 2f\n\t" + "testw %%ax,%%ax\n\t" + "jne 1b\n\t" + "movl $1,%1\n" + "2:\tmovl %1,%0\n\t" + "decl %0" + : "=a"(res), "=&S"(d0) + : "1"(wcs), "0"(wc) + : "memory"); + + return res; +} +EXPORT_SYMBOL(wcschr); + +WCHAR *wcsrchr(const char *wcs, WCHAR wc) +{ + int d0, d1; + WCHAR *res; + + asm volatile("movw %%ax,%%bx\n" + "1:\tlodsw\n\t" + "cmpw %%bx,%%ax\n\t" + "jne 2f\n\t" + "leal -2(%%esi),%0\n" + "2:\ttestw %%ax,%%ax\n\t" + "jne 1b" + : "=g"(res), "=&S"(d0), "=&a"(d1) + : "0"(0), "1"(wcs), "2"(wc) + : "memory"); + + return res; +} +EXPORT_SYMBOL(wcsrchr); + +WCHAR *wcscpy(WCHAR *dest, const WCHAR *src) +{ + int d0, d1, d2; + + asm volatile("1:\tlodsw\n\t" + "stosw\n\t" + "testw %%ax, %%ax\n\t" + "jne 1b" + : "=&S"(d0), "=&D"(d1), "=&a"(d2) + : "0"(src), "1"(dest) + : "memory"); + + return dest; +} +EXPORT_SYMBOL(wcscpy); + +int wcscmp(const WCHAR *wcs, const WCHAR *wct) +{ + int d0, d1; + int res; + + asm volatile("1:\tlodsw\n\t" + "scasw\n\t" + "jne 2f\n\t" + "testw %%ax,%%ax\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "jmp 3f\n" + "2:\tsbbl %%eax,%%eax\n\t" + "orb $1,%%al\n" + "3:" + : "=a"(res), "=&S"(d0), "=&D"(d1) + : "1"(wcs), "2"(wct) + : "memory"); + + return res; +} +EXPORT_SYMBOL(wcscmp); + +int wcsncmp(const WCHAR *wcs, const WCHAR *wct, size_t count) +{ + int res; + int d0, d1, d2; + + asm volatile("1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsw\n\t" + "scasw\n\t" + "jne 3f\n\t" + "testw %%ax,%%ax\n\t" + "jne 1b\n" + "2:\txorl %%eax,%%eax\n\t" + "jmp 4f\n" + "3:\tsbbl %%eax,%%eax\n\t" + "orb $1,%%al\n" + "4:" + : "=a"(res), "=&S"(d0), "=&D"(d1), "=&c"(d2) + : "1"(wcs), "2"(wct), "3"(count) + : "memory"); + + return res; +} +EXPORT_SYMBOL(wcsncmp); + +#endif + diff --git a/unifiedkernel/mm/Makefile b/unifiedkernel/mm/Makefile new file mode 100644 index 0000000..886d0af --- /dev/null +++ b/unifiedkernel/mm/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for memory management +# + +MM_OBJS := attach.o \ + process.o \ + section.o \ + virtual.o \ + datasection.o \ + imagesection.o + +$(MODULE)-objs += $(addprefix mm/, $(MM_OBJS)) diff --git a/unifiedkernel/mm/attach.c b/unifiedkernel/mm/attach.c new file mode 100644 index 0000000..ac8fd64 --- /dev/null +++ b/unifiedkernel/mm/attach.c @@ -0,0 +1,187 @@ +/* + * attach.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * attach.c: attach to another process + * Refered to ReactOS code + */ +#include "attach.h" +#include "process.h" +#include "thread.h" +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +VOID set_page_table_dir(long X) +{ + __asm__ __volatile__( + "movl %0, %%cr3\n\t" + : + :"r"(X)); +} /* end set_page_table_dir */ +EXPORT_SYMBOL(set_page_table_dir); + +/* + * update_page_dir + */ +VOID +STDCALL +update_page_dir(struct mm_struct *mm, PVOID Address, ULONG Size) +{ + ULONG offset, start_offset, end_offset; + struct mm_struct *current_mm = current->mm; + + if (Address < (PVOID)TASK_SIZE) { + return; + } + + spin_lock(&mm->page_table_lock); + + start_offset = pgd_index((ULONG)Address); + end_offset = pgd_index((ULONG)Address+ Size); + + for (offset = start_offset; offset <= end_offset; offset++) { + pgd_t *pgd = (pgd_t *)(mm->pgd + offset); + if (!pgd->pgd) + pgd->pgd = ((pgd_t *)(current_mm->pgd + offset))->pgd; + } + spin_unlock(&mm->page_table_lock); +} /* end update_page_dir */ +EXPORT_SYMBOL(update_page_dir); + +/* + * repair_list + */ +VOID repair_list(struct list_head *Original, + struct list_head *Copy, + KPROCESSOR_MODE Mode) +{ + /* Copy Source to Desination */ + if (list_empty(&Original[(int)Mode])) + INIT_LIST_HEAD(&Copy[(int)Mode]); + else { + Copy[(int)Mode].next = Original[(int)Mode].next; + Copy[(int)Mode].prev = Original[(int)Mode].prev; + Original[(int)Mode].next->prev = &Copy[(int)Mode]; + Original[(int)Mode].prev->next = &Copy[(int)Mode]; + } +} /* end repair_list */ +EXPORT_SYMBOL(repair_list); + +/* + * move_apc_state + */ +VOID +STDCALL +move_apc_state(struct kapc_state *OldState, + struct kapc_state *NewState) +{ + /* Restore backup of Original Environment */ + *NewState = *OldState; + + /* Repair Lists */ + repair_list(NewState->apc_list_head, OldState->apc_list_head, KernelMode); + repair_list(NewState->apc_list_head, OldState->apc_list_head, UserMode); +} /* end move_apc_state */ + +/* + * attach_process + */ +struct mm_struct * +attach_process(struct kprocess *Process) +{ + struct ethread *current_ethread = get_current_ethread(); + struct ethread *thread; + struct kthread *tcb; + struct mm_struct *mm, *old_mm; + + thread = get_first_thread((struct eprocess *)Process); + mm = thread ? thread->et_task->mm : current->mm; + + tcb = ¤t_ethread->tcb; + + /* Make sure that we are in the right page directory */ + update_page_dir(mm, (PVOID)tcb->stack_limit, MM_STACK_SIZE); + update_page_dir(mm, (PVOID)thread, sizeof(struct ethread)); + + local_irq_disable(); + + /* Increase Stack Count */ + Process->stack_count++; + + /* Swap the APC Environment */ + move_apc_state(&tcb->apc_state, &tcb->saved_apc_state); + + /* Reinitialize APC State */ + INIT_LIST_HEAD(&tcb->apc_state.apc_list_head[KernelMode]); + INIT_LIST_HEAD(&tcb->apc_state.apc_list_head[UserMode]); + tcb->apc_state.process = Process; + tcb->apc_state.kapc_inprogress = FALSE; + tcb->apc_state.kapc_pending = FALSE; + tcb->apc_state.uapc_pending = FALSE; + + /* Update Environment Pointers */ + tcb->apc_state_pointer[OriginalApcEnvironment] = &tcb->saved_apc_state; + tcb->apc_state_pointer[AttachedApcEnvironment] = &tcb->apc_state; + tcb->apc_state_index = AttachedApcEnvironment; + + /* Swap the Processes */ + set_page_table_dir(__pa(mm->pgd)); + + old_mm = current->mm; + current->mm = mm; + + local_irq_enable(); + return old_mm; +} /* end attach_process */ +EXPORT_SYMBOL(attach_process); + +/* + * detach_process + */ +VOID +STDCALL +detach_process (struct mm_struct *mm) +{ + struct ethread *thread = get_current_ethread(); + + local_irq_disable(); + + /* Decrease Stack Count */ + thread->threads_process->pcb.stack_count--; + + /* Restrore the APC State */ + move_apc_state(&thread->tcb.saved_apc_state, &thread->tcb.apc_state); + thread->tcb.saved_apc_state.process = NULL; + thread->tcb.apc_state_pointer[OriginalApcEnvironment] = &thread->tcb.apc_state; + thread->tcb.apc_state_pointer[AttachedApcEnvironment] = &thread->tcb.saved_apc_state; + thread->tcb.apc_state_index = OriginalApcEnvironment; + + /* Swap Processes */ + set_page_table_dir(__pa(mm->pgd)); + + current->mm = mm; + local_irq_enable(); +} /* end detach_process */ +EXPORT_SYMBOL(detach_process); +#endif diff --git a/unifiedkernel/mm/datasection.c b/unifiedkernel/mm/datasection.c new file mode 100644 index 0000000..97588bb --- /dev/null +++ b/unifiedkernel/mm/datasection.c @@ -0,0 +1,102 @@ +/* + * datasection.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * datasection.c: data section handling implementation + */ +#include +#include "section.h" +#include "objwait.h" +#include "object.h" +#include "virtual.h" +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +extern int unistr2charstr(PWSTR unistr, LPCSTR chstr); + +static int data_section_map(struct task_struct *tsk, struct win32_section *, + unsigned long *, unsigned long, unsigned long, unsigned long); + +/* + * setup a data section + * - if not map a file, creates a file in the shmem filesystem + */ +int data_section_setup(struct win32_section *ws) +{ + char *name, prefix[] = "win32_"; + + /* set the mmap function */ + ws->ws_mmap = data_section_map; + ws->ws_sections = NULL; + + if (!ws->ws_wfile) { + int prefix_len = sizeof(prefix); + PUNICODE_STRING obj_name; + + obj_name = &(HEADER_TO_OBJECT_NAME(BODY_TO_HEADER((PVOID)ws))->Name); + + /* determine the name to use for the SHMEM file */ + + name = (char *)kmalloc(obj_name->MaximumLength + prefix_len, GFP_KERNEL); + if (!name) + return STATUS_NO_MEMORY; + + memcpy(name, prefix, prefix_len - 1); + unistr2charstr((PWSTR)obj_name->Buffer, name + prefix_len - 1); + + /* create a SHMEM file */ + ws->ws_file = shmem_file_setup(name, ws->ws_len, 0); + if (IS_ERR(ws->ws_file)) { + kfree(name); + return PTR_ERR(ws->ws_file); + } + + kfree(name); + } + else + ws->ws_file = ws->ws_wfile->wf_file; + return 0; +} /* end data_section_setup */ +EXPORT_SYMBOL(data_section_setup); + +/* + * map a data section + * mapped address is returned from addr + */ +static int data_section_map(struct task_struct *tsk, struct win32_section *ws, + unsigned long *addr, unsigned long len, unsigned long flags, unsigned long offset) +{ + struct file *file = ws->ws_file; + unsigned long ret; + + ret = win32_do_mmap_pgoff(tsk, file, *addr, len, ws->ws_protect, flags, offset); + + if (IS_ERR((void *)ret)) + return (int)ret; + + *addr = ret; + return 0; +} /* end data_section_map */ + +#endif diff --git a/unifiedkernel/mm/imagesection.c b/unifiedkernel/mm/imagesection.c new file mode 100644 index 0000000..f25b98b --- /dev/null +++ b/unifiedkernel/mm/imagesection.c @@ -0,0 +1,468 @@ +/* + * imagesection.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * imagesection.c: + * Refered to Linux Kernel code + */ + +#include "virtual.h" +#include "section.h" +#include "pefile.h" +#include "objwait.h" +#include "attach.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +static int image_section_map(struct task_struct *tsk, struct win32_section *ws, + unsigned long *addr, unsigned long len, unsigned long flags, unsigned long offset); + +static int image_section_munmap(struct win32_section *ws); + +static unsigned long character2prot[] = { + PROT_NONE, + PROT_EXEC, /* IMAGE_SCN_MEM_EXECUTE */ + PROT_READ, /* IMAGE_SCN_MEM_READ */ + PROT_READ | PROT_EXEC, + PROT_WRITE, /* IMAGE_SCN_MEM_WRITE */ + PROT_WRITE | PROT_EXEC, + PROT_WRITE | PROT_READ, + PROT_WRITE | PROT_READ | PROT_WRITE +}; + +#ifdef UNALIGNED_MMAP +static struct page *filemap_pe_nopage(struct vm_area_struct *area, + unsigned long address, int *type); + +static struct vm_operations_struct file_pe_shared_mmap = { + .nopage = filemap_pe_nopage, +}; + +static struct vm_operations_struct file_pe_private_mmap = { + .nopage = filemap_pe_nopage, +}; +#endif + +/* origin in kernel-win32 */ +static inline int is_power_of2(unsigned long addr) +{ + if (!addr) + return 0; + + return !(addr & (addr - 1)); +} /* end is_power_of2 */ + +/* + * parse a PE image and build a set of VM areas and a relocation table index + * - performs a cursory check of the image's validity + * - ignores the fact that file sections may _not_ be page aligned! + */ +#define ALIGN_UP(addr, align) (((addr) + (align) - 1) & ~((align) - 1)) +int image_section_setup(struct win32_section *ws) +{ + IMAGE_DOS_HEADER *dos_hdr; + IMAGE_NT_HEADERS *nt_hdr; + IMAGE_OPTIONAL_HEADER *opt_hdr; + IMAGE_SECTION_HEADER *sec_hdr, *ps; + struct win32_image_section *wis; + struct file *file; + size_t hdr_len, nt_hdr_size, sec_hdr_size, total_hdr_size; + void *hdr_buf; + DWORD rva; + int sec_align, file_align, sec_mask, file_mask; + int tmp, err; + + ws->ws_mmap = image_section_map; + ws->ws_munmap = image_section_munmap ; + + /* check that we can map the file into the VM */ + if (!ws->ws_file && ws->ws_wfile) + ws->ws_file = ws->ws_wfile->wf_file; + file = ws->ws_file; + if (!file->f_op || !file->f_op->mmap) + return STATUS_NOT_MAPPED_VIEW; + + /* check we can read the file */ + if (!(file->f_mode & FMODE_READ)) + return STATUS_ACCESS_DENIED; + + /* get the image header and find the offset of the extended header */ + /* alloc 2 pages to store file header */ + hdr_buf = (void *)__get_free_pages(GFP_KERNEL, 1); + if (!hdr_buf) + return STATUS_NO_MEMORY; + + /* read 2 pages to hdr_buf */ + hdr_len = kernel_read(file, 0, hdr_buf, PAGE_SIZE << 1); + if (hdr_len < 0) { + err = hdr_len; + goto free_hdr; + } + + err = STATUS_UNSUCCESSFUL; + if (hdr_len < sizeof(IMAGE_DOS_HEADER)) + goto free_hdr; + + /* check the DOS header */ + dos_hdr = (IMAGE_DOS_HEADER *)hdr_buf; + if (dos_hdr->e_magic != IMAGE_DOS_SIGNATURE || dos_hdr->e_lfanew <= 0) + goto free_hdr; + + /* get the NT header and OPTIONAL header */ + nt_hdr = (IMAGE_NT_HEADERS *)(hdr_buf + dos_hdr->e_lfanew); + opt_hdr = (IMAGE_OPTIONAL_HEADER *)&nt_hdr->OptionalHeader; + + if (hdr_len < dos_hdr->e_lfanew + sizeof(IMAGE_NT_HEADERS) + || nt_hdr->Signature != IMAGE_NT_SIGNATURE + || nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386 + || !(nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) + || opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC + || opt_hdr->ImageBase & 0xffff /* ImageBase need aligned to 64KB */ + || !is_power_of2(opt_hdr->SectionAlignment) + || !is_power_of2(opt_hdr->FileAlignment) + || opt_hdr->SectionAlignment < opt_hdr->FileAlignment + || opt_hdr->SectionAlignment < PAGE_SIZE) + goto free_hdr; + + /* section alignment and file alignment */ + sec_align = opt_hdr->SectionAlignment; + sec_mask = sec_align - 1; + file_align = opt_hdr->FileAlignment; + file_mask = file_align - 1; + + /* fill section for global */ + ws->ws_imagebase = opt_hdr->ImageBase; + ws->ws_nsecs = nt_hdr->FileHeader.NumberOfSections + 1; + ws->ws_stackresv = opt_hdr->SizeOfStackReserve; + ws->ws_stackcommit = opt_hdr->SizeOfStackCommit; + ws->ws_subsystem = opt_hdr->Subsystem; + ws->ws_majorver = opt_hdr->MajorSubsystemVersion; + ws->ws_minorver = opt_hdr->MinorSubsystemVersion; + ws->ws_entrypoint = opt_hdr->AddressOfEntryPoint; + ws->ws_executable = opt_hdr->SizeOfCode != 0; + ws->ws_imagecharacter = nt_hdr->FileHeader.Characteristics; + ws->ws_machine = nt_hdr->FileHeader.Machine; + + /* locate section header */ + nt_hdr_size = sizeof(*nt_hdr) - sizeof(*opt_hdr) + nt_hdr->FileHeader.SizeOfOptionalHeader; + sec_hdr = (IMAGE_SECTION_HEADER *)((char *)nt_hdr + nt_hdr_size); + sec_hdr_size = nt_hdr->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); + total_hdr_size = dos_hdr->e_lfanew + nt_hdr_size + sec_hdr_size; + if (total_hdr_size > hdr_len) + goto free_hdr; + + ws->ws_secoff = (char *)sec_hdr - (char *)hdr_buf; + + /* allocate my section table (with a dummy section on the end) */ + err = STATUS_NO_MEMORY; + tmp = sizeof(struct win32_image_section) * ws->ws_nsecs; + ws->ws_sections = (struct win32_image_section *)kmalloc(tmp, GFP_KERNEL); + if (!ws->ws_sections) + goto free_hdr; + + /* create a virtual section to map the image header */ + wis = ws->ws_sections; + ps = sec_hdr; + + wis->wis_rva = 0; + wis->wis_fpos = 0; + wis->wis_size = ALIGN_UP(total_hdr_size, sec_align); + wis->wis_rawsize = ALIGN_UP(total_hdr_size, file_align); + wis->wis_flags = MAP_DENYWRITE | MAP_PRIVATE; + wis->wis_protect = PROT_READ; + wis->wis_character = 0; + + /* validate the section table */ + err = STATUS_UNSUCCESSFUL; + rva = wis->wis_size; + for (wis++; wis < ws->ws_sections + ws->ws_nsecs; ps++, wis++) { + unsigned long characteristics; + + /* not alignment */ + if (ps->VirtualAddress & sec_mask) + goto free_section; + + wis->wis_rva = ps->VirtualAddress; /* relate virtual address */ + if (wis->wis_rva < rva) /* rva = relate virtual address of previous section end */ + goto free_section; + + characteristics = ps->Characteristics; + /* check the IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE */ + if (!(characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))) { + /* no explicit protection */ + if (characteristics & IMAGE_SCN_CNT_CODE) + characteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; + + if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) + characteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + + if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + characteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + } + if ((ws->ws_entrypoint >= ws->ws_imagebase + wis->wis_rva) + && (ws->ws_entrypoint < ws->ws_imagebase + wis->wis_rva + wis->wis_size)) { + characteristics |= IMAGE_SCN_MEM_EXECUTE; + } + wis->wis_character = characteristics; + + /* get segement size, aligned to SectionAlignment */ + if (!ps->Misc.VirtualSize || ps->Misc.VirtualSize < ps->SizeOfRawData) + wis->wis_size = ALIGN_UP(ps->SizeOfRawData, sec_align); + else + wis->wis_size = ALIGN_UP(ps->Misc.VirtualSize, sec_align); + if (wis->wis_size > TASK_SIZE) + goto free_section; + + wis->wis_fpos = ps->PointerToRawData; /* file postion */ + wis->wis_rawsize = ALIGN_UP(ps->SizeOfRawData, file_align); + + if (wis->wis_size < wis->wis_rawsize) + goto free_section; + + /* calc this section end */ + rva = wis->wis_rva + wis->wis_size; + + /* determine the specific VM flags for this section */ + wis->wis_flags = MAP_DENYWRITE | MAP_EXECUTABLE; + if (characteristics & IMAGE_SCN_MEM_SHARED) + wis->wis_flags |= MAP_SHARED; + else + wis->wis_flags |= MAP_PRIVATE; + + /* section protect, get highest 3 bits */ + wis->wis_protect = character2prot[characteristics >> 29]; + + if ((wis->wis_flags & MAP_SHARED) + && (wis->wis_protect & (PROT_WRITE | PROT_EXEC))) + goto free_section; + } + + /* total segements len */ + ws->ws_len = rva; + ws->ws_pagelen = PAGE_ALIGN(rva); + err = 0; + goto free_hdr; + +free_section: + ws->ws_nsecs = 0; + kfree(ws->ws_sections); + ws->ws_sections = NULL; + +free_hdr: + free_pages((unsigned long)hdr_buf, 1); + return err; +} /* end image_section_setup */ +EXPORT_SYMBOL(image_section_setup); + +/* + * map the PE image into the process's VM space + */ +static int image_section_map(struct task_struct *tsk, struct win32_section *ws, + unsigned long *addr, unsigned long len, unsigned long flags, unsigned long offset) +{ + int load_addr_set = 0; + unsigned long ret, base; + struct file *file = ws->ws_file; + struct win32_image_section *wis; +#ifndef UNALIGNED_MMAP + loff_t pos; + ssize_t readed; + struct mm_struct *current_mm = current->mm; +#else + struct vm_area_struct *vma; + struct vm_operations_struct *vmops; +#endif + + base = *addr; + if (!base) + base = ws->ws_imagebase; + + /* iterate through all the chunks */ + for (wis = ws->ws_sections; wis < ws->ws_sections + ws->ws_nsecs; wis++) { + if (wis->wis_character & IMAGE_SCN_TYPE_NOLOAD) + continue; + + /* set vmops */ + flags = 0; + if (ws->ws_imagecharacter & IMAGE_FILE_EXECUTABLE_IMAGE || load_addr_set) + flags = MAP_FIXED; + +#ifndef UNALIGNED_MMAP + ret = win32_do_mmap_pgoff(tsk, NULL, base + wis->wis_rva, wis->wis_size, + PROT_READ | PROT_WRITE, wis->wis_flags | flags, 0); +#else + if ((wis->wis_flags & MAP_SHARED) && (wis->wis_protect & PROT_WRITE)) + vmops = &file_pe_shared_mmap; + else + vmops = &file_pe_private_mmap; + + /* map a section */ + ret = win32_do_mmap_pgoff(tsk, file, base + wis->wis_rva, wis->wis_size, + wis->wis_protect, wis->wis_flags | flags, wis->wis_rva >> PAGE_SHIFT); + + /* fixup vma */ + vma = find_vma(tsk->mm, ret); + if (vma) { + vma->vm_private_data = (void *)ws; + vma->vm_ops = vmops; + } +#endif + + if (IS_ERR((void *)ret)) + goto failed; + +#ifndef UNALIGNED_MMAP + if (tsk != current) + current_mm = attach_process((struct kprocess *)tsk->ethread->threads_process); + + pos = (loff_t)wis->wis_fpos; + readed = vfs_read(file, (char *)ret, wis->wis_rawsize, &pos); + sys_mprotect(ret, wis->wis_size, wis->wis_protect); + + if (tsk != current) + detach_process(current_mm); +#endif + + if (!load_addr_set) { + load_addr_set = 1; + if (ws->ws_imagecharacter & IMAGE_FILE_DLL) + ws->ws_realbase = ret - wis->wis_rva; + else + ws->ws_realbase = base; + + base = ws->ws_realbase; + } + } + + *addr = base; + return 0; + + /* clean up on error */ +failed: + return PTR_ERR((void *)ret); +} /* end image_section_map () */ + + +static int image_section_munmap(struct win32_section *ws) +{ + int err, ret = 0; + struct win32_image_section *wis; + struct mm_struct *mm = current->mm; + + /* grab the process's memory mapping semaphore */ + down_write(&mm->mmap_sem); + + for (wis = ws->ws_sections; wis < ws->ws_sections + ws->ws_nsecs; wis++) { + if (wis->wis_character & IMAGE_SCN_TYPE_NOLOAD) + continue; + + err = do_munmap(mm, ws->ws_realbase + wis->wis_rva, wis->wis_size); + + if (err) { + ret = err; + } + } + + /* release the process's memory mapping semaphore */ + up_write(&mm->mmap_sem); + + kfree(ws); + + return ret; +} /* image_section_munmap */ + +#ifdef UNALIGNED_MMAP +static struct page *filemap_pe_nopage(struct vm_area_struct *area, + unsigned long address, int *type) +{ + int error; + void *pgbuf; + unsigned long pgoff, floff, voff, size; + struct page *page; + struct file *file = area->vm_file; + struct win32_section *ws; + struct win32_image_section *wis; + + if (!(ws = (struct win32_section *)area->vm_private_data)) + return NULL; + for (wis = ws->ws_sections; wis < ws->ws_sections + ws->ws_nsecs; wis++) + if ((address < ws->ws_realbase + wis->wis_rva + wis->wis_size) + && (address >= ws->ws_realbase + wis->wis_rva)) + break; + + /* get page offset and virtual offset */ + voff = address - area->vm_start; + pgoff = (voff >> PAGE_CACHE_SHIFT) + area->vm_pgoff; + voff += area->vm_start - ws->ws_realbase - wis->wis_rva; + + if (pgoff >= ((wis->wis_rva + wis->wis_size) >> PAGE_CACHE_SHIFT)) + if (area->vm_mm == current->mm) + return NULL; + + page = alloc_pages(GFP_ATOMIC, 0); + if (!page) + return NOPAGE_OOM; + + pgbuf = kmap(page); + if (pgbuf) { + if (voff > wis->wis_rawsize) + memset(pgbuf, 0, PAGE_SIZE); + else { + floff = voff + wis->wis_fpos; + size = wis->wis_rawsize - voff; + size = size < PAGE_SIZE ? size : PAGE_SIZE; + error = kernel_read(file, floff, pgbuf, size); + if (size < PAGE_SIZE) + memset(pgbuf + size, 0, PAGE_SIZE - size); + + if (error < 0) + goto cleanup; + + grab_swap_token(); + } + + kunmap(page); + return page; + } + +cleanup: + kunmap(page); + __free_pages(page, 0); + return NULL; +} /* end filemap_pe_nopage */ +#endif + +#endif diff --git a/unifiedkernel/mm/process.c b/unifiedkernel/mm/process.c new file mode 100644 index 0000000..3742177 --- /dev/null +++ b/unifiedkernel/mm/process.c @@ -0,0 +1,383 @@ +/* + * process.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * process.c: + * Refered to Reactos Kernel code + */ +#include "win32_process.h" +#include +#include +#include "win32.h" +#include "section.h" +#include "area.h" +#include "process.h" +#include "thread.h" +#include "pefile.h" +#include "virtual.h" +#include "attach.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +extern unsigned long MmUserProbeAddress; +static unsigned long extra_page = 0; + +extern int unistr2charstr(PWSTR unistr, LPCSTR chstr); + +#define USER_SHARED_DATA (0x7FFE0000) +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +/* +* alloc_peb_or_teb +* called for alloc peb or teb +*/ +PVOID +STDCALL +alloc_peb_or_teb(struct eprocess* Process, + PVOID BaseAddress) /* peb or teb base */ +{ + unsigned long addr; + unsigned long ret; + size_t size = PAGE_SIZE; + struct ethread *first_thread = get_first_thread(Process); + struct task_struct *tsk = first_thread ? first_thread->et_task : current; + struct vm_area_struct *vma; + + addr = (unsigned long)BaseAddress; + if (PEB_BASE != (unsigned long )BaseAddress) { + size = RESERVE_PAGE_SIZE; + addr &= RESERVE_PAGE_MASK; + do { + vma = find_vma(tsk->mm, addr); + if (!vma || vma->vm_start >= addr + size) + break; + addr -= size; + } while (addr > 0); + } + + ret = win32_do_mmap_pgoff(tsk, NULL, addr, size, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 0); + + if (IS_ERR((void *)ret)) + return NULL; + + insert_reserved_area(Process, ret, ret + size, _PAGE_READWRITE); + + return (PVOID)ret; +} /* end alloc_peb_or_teb */ + +/* + * create_peb + * called for create peb + */ +NTSTATUS STDCALL +create_peb(struct eprocess *Process) +{ + struct eprocess *curr_eprocess = get_current_eprocess(); + BOOL attached = false; + PPEB peb = NULL; + PPEB kpeb; + NTSTATUS ret = STATUS_SUCCESS; + struct mm_struct *mm = NULL; + + if (curr_eprocess && curr_eprocess != Process) { + mm = attach_process(&Process->pcb); + attached = true; + } + + kpeb = kmalloc(sizeof(PEB), GFP_KERNEL); + if (!kpeb) { + ret = STATUS_NO_MEMORY; + goto out_detach; + } + memset(kpeb, 0, sizeof(PEB)); + + kpeb->ImageBaseAddress = Process->section_base_address; + kpeb->OSMajorVersion = 5; + kpeb->OSMinorVersion = 0; + kpeb->OSBuildNumber = 13; + kpeb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */ + kpeb->OSCSDVersion = 0; /* NtOSCSDVersion */ + kpeb->AnsiCodePageData = 0; /* FIXME */ + kpeb->OemCodePageData = 0; /* FIXME */ + kpeb->UnicodeCaseTableData = 0; /* FIXME */ + kpeb->NumberOfProcessors = 1; /* FIXME */ + kpeb->BeingDebugged = (BOOLEAN)(Process->debug_port ? TRUE : FALSE); + + /* Allocate the PEB */ + peb = alloc_peb_or_teb(Process, (PVOID)PEB_BASE); + if (!peb) { + ret = STATUS_NO_MEMORY; + goto out_free_kpeb; + } + + /* Initialize the PEB */ + memset(peb, 0, sizeof(PEB)); + + /* Set up data */ + if ((copy_to_user(peb, kpeb, sizeof(PEB)))) { + ret = STATUS_NO_MEMORY; + goto out_free_kpeb; + } + + Process->peb = peb; + + ret = STATUS_SUCCESS; + +out_free_kpeb: + kfree(kpeb); + +out_detach: + if (attached) + detach_process(mm); + + ktrace("end create_peb: Peb created at %p\n", peb); + return ret; +} /* end create_peb */ + +/* + * create_teb + * called for create teb + */ +PTEB +STDCALL +create_teb(struct eprocess* Process, + PCLIENT_ID ClientId, + PINITIAL_TEB InitialTeb) +{ + struct eprocess *curr_eprocess = get_current_eprocess(); + BOOL attached = false; + PTEB teb; + PTEB kteb; + struct mm_struct *mm = NULL; + + kteb = kmalloc(sizeof(TEB), GFP_KERNEL); + if (!kteb) + return ERR_PTR(STATUS_NO_MEMORY); + + /* Allocate the TEB */ + if (!(teb = alloc_peb_or_teb(Process, (void *)TEB_BASE))){ + goto out_free_kteb; + } + + memset(kteb, 0, sizeof(TEB)); + + /* Set TIB Data */ + kteb->Tib.ExceptionList = (PVOID)0xFFFFFFFF; + kteb->Tib.DUMMYUNIONNAME.Version = 0; + kteb->Tib.Self = (PNT_TIB)teb; + + /* Set TEB Data */ + if (ClientId) { + kteb->RealClientId = *ClientId; + } + else { + memset(&kteb->RealClientId, 0, sizeof(CLIENT_ID)); + } + + memset(&kteb->Cid, 0, sizeof(CLIENT_ID)); + + kteb->Peb = Process->peb; + kteb->CurrentLocale = 0; /* FIXME: PsDefaultThreadLocaleId; */ + + kteb->Tib.StackBase = (PVOID)InitialTeb->StackBase; + kteb->Tib.StackLimit = (PVOID)InitialTeb->StackLimit; + kteb->DeallocationStack = kteb->Tib.StackLimit - PAGE_SIZE; + + if (curr_eprocess && curr_eprocess != Process) { + mm = attach_process(&Process->pcb); + attached = true; + } + + if (copy_to_user(teb, kteb, sizeof(TEB))) { + teb = ERR_PTR(STATUS_NO_MEMORY); + } + + if (attached) + detach_process(mm); + +out_free_kteb: + kfree(kteb); + + ktrace("end create_teb: Teb created at %p\n", teb); + return teb; +} /* end create_teb */ + +void set_task_name(struct task_struct *tsk, + struct eprocess *process, struct win32_section *section) +{ + POBJECT_HEADER_NAME_INFO name_info; + UCHAR *name, *p; + int len; + + /* Determine the image file name and save it to EPROCESS */ + name_info = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(section->ws_wfile->wf_control)); + if (!name_info) + return; + + name = (UCHAR *)kmalloc(name_info->Name.MaximumLength, GFP_KERNEL); + unistr2charstr((PWSTR)name_info->Name.Buffer, (LPCSTR)name); + + p = strrchr(name, '\\'); + if (!p) + p = strrchr(name, '/'); + + if (p) + p++; + else + p = name; + len = strlen(p); + len = MIN(len, sizeof(process->image_file_name)); + + memcpy(process->image_file_name, p, len); + task_lock(tsk); + strlcpy(tsk->comm, p, sizeof(tsk->comm)); + task_unlock(tsk); + + kfree(name); +} + +/* + * create_process_space + */ +NTSTATUS +STDCALL +create_process_space(struct eprocess *process, + struct win32_section *section) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG ViewSize = 0; + PVOID ImageBase = NULL; + unsigned long start_code = 0, start_data = 0, end_code = 0, end_data = 0; + unsigned long pe_brk = 0; + struct win32_image_section *wis; + struct mm_struct *mm; + struct task_struct *tsk; + struct ethread *thread = get_first_thread(process); + + tsk = thread ? thread->et_task : current; + mm = tsk->mm; + + if (!section) + goto out_set_tls; + + /* Check if there's a Section Object */ + status = map_section_view(section, + process, + (PVOID*)&ImageBase, + 0, + 0, + NULL, + (PSIZE_T)&ViewSize, + 0, + MEM_COMMIT, + _PAGE_READWRITE); + if (!NT_SUCCESS(status)) + return status; + + for (wis = section->ws_sections; wis < section->ws_sections + section->ws_nsecs; wis++) { + unsigned long k; + + if (wis->wis_character & IMAGE_SCN_TYPE_NOLOAD) + continue; + + k = section->ws_realbase + wis->wis_rva; + + /* + * Check to see if the section's size will overflow the + * allowed task size. Note that p_filesz must always be + * <= p_memsz so it is only necessary to check p_memsz. + */ + status = STATUS_INVALID_IMAGE_WIN_32; + if (k > TASK_SIZE || TASK_SIZE - wis->wis_size < k) /* Avoid overflows. */ + goto out_unmap_section; + + if (wis->wis_character & IMAGE_SCN_MEM_EXECUTE) { + start_code = k; + end_code = k + wis->wis_rawsize; + } + else { + if (!start_data) + start_data = k; + end_data = k + wis->wis_rawsize; + } + + k += wis->wis_size; + if (pe_brk < k) /* pe_brk used set mm->brk */ + pe_brk = k; + + /* TODO: start_data and end_data, diff to ELF */ + } + + mm->brk = pe_brk; + mm->start_code = start_code; + mm->start_data = start_data; + mm->end_code = end_code; + mm->end_data = end_data; + + /* extra page, used for interpreter ld-linux.so */ + extra_page = win32_do_mmap_pgoff(tsk, NULL, pe_brk, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0); + if (extra_page != pe_brk) + goto out_unmap_section; + mm->brk = pe_brk + PAGE_SIZE; + process->spare0[0] = (void *)extra_page; + + section->ws_entrypoint += section->ws_realbase; + process->section_base_address = ImageBase; + + /* reserve first 0x100000 */ + win32_do_mmap_pgoff(tsk, NULL, 0, WIN32_LOWEST_ADDR, PROT_NONE, + MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + /* reserve first 0x7fff0000 - 0x80000000 */ + win32_do_mmap_pgoff(tsk, NULL, WIN32_TASK_SIZE - 0x10000, 0x10000, + PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + /* reserve first 0x81000000 - 0xc0000000 + * 0x80000000 - 0x81000000 used for wine SYSTEM_HEAP */ + win32_do_mmap_pgoff(tsk, NULL, WIN32_TASK_SIZE + WIN32_SYSTEM_HEAP_SIZE, + TASK_SIZE - WIN32_TASK_SIZE - WIN32_SYSTEM_HEAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0); + + set_task_name(tsk, process, section); + +out_set_tls: + memset(&tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); +#if 1 + /* FIXME: use parent's tls instead temporarily */ + /* use parent's TLS */ + { + struct task_struct *parent = tsk->parent; + int idx = (parent->thread.gs >> 3) - GDT_ENTRY_TLS_MIN; + + memcpy(&tsk->thread.tls_array[idx], &parent->thread.tls_array[idx], + sizeof(struct desc_struct)); + } +#endif + + return STATUS_SUCCESS; + +out_unmap_section: + unmap_section_view(process, mm, (unsigned long)ImageBase); + return status; +} /* end create_process_space */ + +#endif diff --git a/unifiedkernel/mm/section.c b/unifiedkernel/mm/section.c new file mode 100644 index 0000000..15eee89 --- /dev/null +++ b/unifiedkernel/mm/section.c @@ -0,0 +1,745 @@ +/* + * section.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * section.c: section syscall functions + * Refered to Kernel-win32 code + */ +#include +#include "section.h" +#include "thread.h" +#include "objwait.h" +#include "object.h" +#include "unistr.h" +#include "virtual.h" +#include "area.h" +#include +#include +#include +#include "win32_process.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +extern int data_section_map(struct win32_section *, unsigned long *, + unsigned long, unsigned long, unsigned long); + +extern unsigned long prot_to_linux(unsigned long win); + +static WCHAR section_type_name[] = {'S', 'e', 'c', 't', 'i', 'o', 'n', 0}; +POBJECT_TYPE section_object_type = NULL; +EXPORT_SYMBOL(section_object_type); +extern POBJECT_TYPE file_object_type; +extern POBJECT_TYPE process_object_type; +extern HANDLE base_dir_handle; + +static GENERIC_MAPPING section_mapping = { + STANDARD_RIGHTS_READ | SECTION_MAP_READ | SECTION_QUERY, + STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE, + STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE, + SECTION_ALL_ACCESS}; + +static void delete_section(PVOID section); + +VOID +init_section_implement(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + + /* Initialize the Section object type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)section_type_name); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(struct win32_section); + ObjectTypeInitializer.PoolType = PagedPool; + ObjectTypeInitializer.UseDefaultObject = TRUE; + ObjectTypeInitializer.GenericMapping = section_mapping; + ObjectTypeInitializer.DeleteProcedure = delete_section; + create_type_object(&ObjectTypeInitializer, &Name, §ion_object_type); +} /* end init_section_implement */ + +/* + * open a section object, maybe creating if non-existent + */ +NTSTATUS SERVICECALL +NtCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG Protect, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL + ) +{ + HANDLE hSection; + size_t size = 0; + struct win32_file *wfile = NULL; + struct win32_section *section; + struct ethread *thread; + POBJECT_ATTRIBUTES obj_attr = NULL; + LARGE_INTEGER max_size; + NTSTATUS Status; + MODE previous_mode; + + if (!(thread = get_current_ethread())) + return STATUS_UNSUCCESSFUL; + + /* FIXME */ + previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; + + if (ObjectAttributes) { + if (previous_mode == UserMode) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else + obj_attr = ObjectAttributes; + } + + if (obj_attr && obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + + if (MaximumSize) { + if (previous_mode == UserMode) { + Status = STATUS_NO_MEMORY; + if (copy_from_user(&max_size, MaximumSize, sizeof(max_size))) + goto cleanup_object_attr; + MaximumSize = &max_size; + } + Status = STATUS_INVALID_PARAMETER; + if (MaximumSize->u.HighPart) + goto cleanup_object_attr; + size = MaximumSize->u.LowPart; + } + + /* gain access to the file */ + if (FileHandle) { + Status = ref_object_by_handle( + FileHandle, + DesiredAccess, + file_object_type, + KernelMode, + (PVOID *)&wfile, + NULL + ); + if (!NT_SUCCESS(Status)) + goto cleanup_object_attr; + } + + /* create a section object */ + Status = create_object( + KernelMode, + section_object_type, + obj_attr, + KernelMode, + NULL, + sizeof(struct win32_section), + 0, + 0, + (PVOID *)§ion + ); + if (Status) + goto cleanup_wfile; + + Status = insert_object( + (PVOID)section, + NULL, + 0, + 0, + NULL, + &hSection + ); + if (Status == STATUS_OBJECT_NAME_EXISTS) { + deref_object(section); + goto section_exists; + } + + deref_object(section); + if (Status) + goto cleanup_wfile; + + /* setup section */ + if (wfile) + ref_object(wfile); + section->ws_wfile = wfile; /* attach file */ + section->ws_len = size; + + section->ws_flags = 0; + section->ws_alloctype = AllocationAttributes; + if (AllocationAttributes & _SEC_IMAGE) { + if (!wfile || image_section_setup(section) < 0) { + Status = STATUS_NO_SUCH_FILE; + goto cleanup_handle; + } + } + else { + if ((Protect & PAGE_PROT_MASK) != Protect || !(Protect & PAGE_PROT_MASK)) { + Status = STATUS_INVALID_PAGE_PROTECTION; + kdebug("FIXME: some protect not implemention! Protect %x\n", Protect); + goto cleanup_handle; + } + + section->ws_protect = prot_to_linux(Protect); + + /* anonymous map, map len is need */ + if (!wfile && !section->ws_len) { + Status = STATUS_NOT_MAPPED_VIEW; + goto cleanup_handle; + } + if (!wfile && (!obj_attr->ObjectName || !obj_attr->ObjectName->Length)) { + Status = STATUS_OBJECT_NAME_INVALID; + goto cleanup_handle; + } + + if (!wfile && (AllocationAttributes & _SEC_RESERVE)) + section->ws_flags |= MAP_RESERVE; + + if ((Protect & _PAGE_WRITECOPY) || (Protect & _PAGE_EXECUTE_WRITECOPY)) + /* copy on write */ + section->ws_flags |= MAP_PRIVATE; + else + /* shared map */ + section->ws_flags |= MAP_SHARED; + + /* get the file size, when paramter len is 0 */ + if (!section->ws_len && wfile) + section->ws_len = wfile->wf_file->f_dentry->d_inode->i_size; + section->ws_pagelen = PAGE_ALIGN(section->ws_len); + + /* TODO + if (section->ws_len < wfile->wf_file->f_dentry->d_inode->i_size) + grow_file(wfile); + */ + + if (data_section_setup(section) < 0) { + Status = STATUS_NOT_MAPPED_VIEW; + goto cleanup_handle; + } + } + + Status = STATUS_SUCCESS; + +section_exists: + if (previous_mode == UserMode) { + if (copy_to_user(SectionHandle, &hSection, sizeof(hSection))) { + Status = STATUS_INVALID_ADDRESS; + goto cleanup_handle; + } + } + else + *SectionHandle = hSection; + + goto cleanup_wfile; + +cleanup_handle: + NtClose(hSection); +cleanup_wfile: + if (wfile) + deref_object((PVOID)wfile); +cleanup_object_attr: + if (obj_attr && previous_mode == UserMode) + kfree(obj_attr); + + return Status; +} /* end NtCreateSection() */ +EXPORT_SYMBOL(NtCreateSection); + +/* + * map a view of the section to the process's address space + */ +NTSTATUS +SERVICECALL +NtMapViewOfSection( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PSIZE_T ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Protect + ) +{ + NTSTATUS Status; + size_t size = 0; + MODE previous_mode; + unsigned long addr = 0L; + struct win32_section *section; + struct ethread *thread; + struct eprocess *process; + LARGE_INTEGER sec_off = { .QuadPart = 0LL }; + + if (!(thread = get_current_ethread())) + return STATUS_UNSUCCESSFUL; + + /* FIXME */ + previous_mode = (unsigned long)BaseAddress > TASK_SIZE ? KernelMode : UserMode; + + if (!BaseAddress) + return STATUS_INVALID_PARAMETER; + if (!ViewSize) + return STATUS_INVALID_PARAMETER; + + if (previous_mode == UserMode) { + if (copy_from_user(&addr, BaseAddress, sizeof(PVOID))) + return STATUS_INVALID_ADDRESS; + if (copy_from_user(&size, ViewSize, sizeof(size))) + return STATUS_INVALID_ADDRESS; + if (SectionOffset && copy_from_user(&sec_off, SectionOffset, sizeof(sec_off))) + return STATUS_INVALID_ADDRESS; + } + else { + addr = (unsigned long)*BaseAddress; + size = (size_t)*ViewSize; + if (SectionOffset) + sec_off = *SectionOffset; + } + + if (addr > WIN32_TASK_SIZE || size > WIN32_TASK_SIZE) + return STATUS_INVALID_PARAMETER; + + /* TODO: not support 64bit offset */ + if (sec_off.u.HighPart) + return STATUS_INVALID_PARAMETER; + + /* access the section object */ + Status = ref_object_by_handle( + SectionHandle, + SECTION_ALL_ACCESS, + section_object_type, + KernelMode, + (PVOID *)§ion, + NULL + ); + if (Status) + return Status; + + if (!ProcessHandle || ProcessHandle == NtCurrentProcess()) { + process = thread->threads_process; + ref_object((PVOID)process); + } + else { + Status = ref_object_by_handle( + ProcessHandle, + PROCESS_ALL_ACCESS, + process_object_type, + KernelMode, + (PVOID *)&process, + NULL + ); + if (Status) + goto cleanup_section; + } + + Status = map_section_view( + (PVOID)section, + process, + (PVOID *)&addr, + ZeroBits, + CommitSize, + SectionOffset ? (PLARGE_INTEGER)&sec_off : NULL, + (PSIZE_T)&size, + InheritDisposition, + AllocationType, + Protect + ); + + if (!NT_SUCCESS(Status)) + goto cleanup_process; + + Status = STATUS_INVALID_ADDRESS; + if (previous_mode == UserMode) { + if (copy_to_user(BaseAddress, &addr, sizeof(PVOID))) + goto cleanup_process; + if (copy_to_user(ViewSize, &size, sizeof(PVOID))) + goto cleanup_process; + } + else { + *BaseAddress = (PVOID)addr; + *ViewSize = size; + } + + Status = STATUS_SUCCESS; + +cleanup_process: + deref_object(process); + +cleanup_section: + deref_object(section); + + return Status; +} /* end NtMapViewOfSection() */ +EXPORT_SYMBOL(NtMapViewOfSection); + +/* + * unmap a mapped view of the file + * - the view must start _exactly_ on the address + */ +NTSTATUS SERVICECALL +NtUnmapViewOfSection( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress + ) +{ + struct mm_struct *mm; + struct eprocess *process; + struct ethread *thread; + NTSTATUS ret; + + if (!ProcessHandle || ProcessHandle == NtCurrentProcess()) { + mm = current->mm; + process = get_current_eprocess(); + ref_object((PVOID)process); + } else { + ret = ref_object_by_handle( + ProcessHandle, + PROCESS_ALL_ACCESS, + process_object_type, + KernelMode, + (PVOID *)&process, + NULL + ); + if (!NT_SUCCESS(ret)) + return ret; + thread = get_first_thread(process); + if (!thread) { + ret = STATUS_THREAD_NOT_IN_PROCESS; + goto out; + } + mm = thread->et_task->mm; + } + + ret = unmap_section_view(process, mm, (unsigned long)BaseAddress); + +out: + deref_object(process); + return ret; +} /* NtUnmapViewOfSection() */ +EXPORT_SYMBOL(NtUnmapViewOfSection); + +NTSTATUS SERVICECALL +NtOpenSection(PHANDLE SectionHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hSection; + POBJECT_ATTRIBUTES obj_attr = NULL; + MODE previous_mode; + NTSTATUS Status = STATUS_SUCCESS; + + previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; + if (ObjectAttributes) { + if (previous_mode == UserMode) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else + obj_attr = ObjectAttributes; + } + + if (obj_attr && obj_attr->RootDirectory) + obj_attr->RootDirectory = base_dir_handle; + + Status = open_object_by_name(obj_attr, + section_object_type, + NULL, + KernelMode, + DesiredAccess, + NULL, + &hSection); + + if (!NT_SUCCESS(Status)) + goto cleanup; + + if (previous_mode == UserMode) { + if (copy_to_user(SectionHandle, &hSection, sizeof(HANDLE))) { + Status = STATUS_INVALID_ADDRESS; + goto cleanup; + } + } + else + *SectionHandle = hSection; + +cleanup: + if (obj_attr && previous_mode == UserMode) + kfree(obj_attr); + return Status; +} /* end NtOpenSection */ +EXPORT_SYMBOL(NtOpenSection); + +NTSTATUS SERVICECALL +NtExtendSection(IN HANDLE SectionHandle, + IN PLARGE_INTEGER NewMaximumSize) +{ + return STATUS_NOT_IMPLEMENTED; +} /* end NtExtendSection */ +EXPORT_SYMBOL(NtExtendSection); + +/* + * NtQuerySection + */ +NTSTATUS SERVICECALL +NtQuerySection(IN HANDLE SectionHandle, + IN SECTION_INFORMATION_CLASS SectionInformationClass, + OUT PVOID SectionInformation, + IN ULONG SectionInformationLength, + OUT PULONG ResultLength OPTIONAL) +{ + struct win32_section *ws; + struct ethread *thread; + long len; + NTSTATUS Status; + MODE previous_mode; + PSECTION_IMAGE_INFORMATION sii = NULL; + PSECTION_BASIC_INFORMATION sbi = NULL; + + previous_mode = (unsigned long)SectionInformation > TASK_SIZE ? KernelMode : UserMode; + + if (!(thread = get_current_ethread())) { + return STATUS_UNSUCCESSFUL; + } + + Status = ref_object_by_handle( + SectionHandle, + SECTION_ALL_ACCESS, + section_object_type, + KernelMode, + (PVOID *)&ws, + NULL + ); + if (!NT_SUCCESS(Status)) + return Status; + + switch (SectionInformationClass) { + case SectionBasicInformation: + if (!(sbi = kmalloc(sizeof(SECTION_BASIC_INFORMATION), GFP_KERNEL))) { + Status = STATUS_NO_MEMORY; + goto cleanup_section; + } + + sbi->Attributes = ws->ws_alloctype; + if (ws->ws_alloctype & _SEC_IMAGE) { + sbi->BaseAddress = 0; + sbi->Size.QuadPart = 0LL; + } + else { + sbi->BaseAddress = (void *)ws->ws_sections->wis_rva; + sbi->Size.QuadPart = (long long)ws->ws_sections->wis_size; + } + + if (ResultLength) { + len = sizeof(SECTION_BASIC_INFORMATION); + if (copy_to_user(ResultLength, &len, sizeof(long))) { + Status = STATUS_INVALID_ADDRESS; + goto cleanup_sbi; + } + else + *ResultLength = len; + } + + if (copy_to_user(SectionInformation, sbi, sizeof(*sbi))) { + Status = STATUS_INVALID_ADDRESS; + goto cleanup_sbi; + } + else + memcpy(SectionInformation, sbi, sizeof(*sbi)); + + break; + case SectionImageInformation: + if (!(sii = kmalloc(sizeof(SECTION_IMAGE_INFORMATION), GFP_KERNEL))) { + Status = STATUS_NO_MEMORY; + goto cleanup_section; + } + + if(ws->ws_alloctype & _SEC_IMAGE) { + sii->EntryPoint = ws->ws_entrypoint; + sii->StackReserve = ws->ws_stackresv; + sii->StackCommit = ws->ws_stackcommit; + sii->Subsystem= ws->ws_subsystem; + sii->MinorSubsystemVersion = ws->ws_minorver; + sii->MajorSubsystemVersion = ws->ws_majorver; + sii->Characteristics = ws->ws_imagecharacter; + sii->ImageNumber = ws->ws_machine; + sii->Executable = ws->ws_executable; + } + + if (ResultLength) { + len = sizeof(SECTION_IMAGE_INFORMATION); + if (previous_mode == UserMode) { + if (copy_to_user(ResultLength, &len, sizeof(long))){ + Status = STATUS_INVALID_ADDRESS; + goto cleanup_sii; + } + } + else + *ResultLength = len; + } + if (previous_mode == UserMode) { + if (copy_to_user(SectionInformation, sii, sizeof(*sii))) { + Status = STATUS_INVALID_ADDRESS; + goto cleanup_sii; + } + } + else + memcpy(SectionInformation, sii, sizeof(*sii)); + break; + default: + break; + } + +cleanup_sii: + if (sii) + kfree(sii); + goto cleanup_section; + +cleanup_sbi: + if (sbi) + kfree(sbi); + +cleanup_section: + deref_object((PVOID)ws); + + return Status; +} /* end NtQuerySection */ +EXPORT_SYMBOL(NtQuerySection); + +/* + * destroy a section (discard its private data) + */ +static void delete_section(PVOID section) +{ + struct win32_section *ws = section; + + /* discard the association with the file object */ + if (ws->ws_wfile) + deref_object(ws->ws_wfile); + + if (ws->ws_sections) + kfree(ws->ws_sections); +} /* end SectionDestructor() */ + +/* + * map_section_view + * map a view of the section to the process's address space + */ +NTSTATUS +STDCALL +map_section_view( + IN PVOID SectionObject, + IN struct eprocess* Process, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PSIZE_T ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Protect + ) +{ + NTSTATUS status; + size_t size; + unsigned long offset; + unsigned long addr; + unsigned long flags = 0; + struct win32_section *section = SectionObject; + struct vm_area_struct *vma; + struct ethread *thread; + struct task_struct *tsk; + + if (!(thread = get_first_thread(Process))) + return STATUS_THREAD_NOT_IN_PROCESS; + + /* map offset, aligned to PAGE_SIZE */ + if ((offset = SectionOffset ? SectionOffset->u.LowPart : 0)) + offset &= PAGE_MASK; + + /* map size */ + size = PAGE_ALIGN(*ViewSize); + + tsk = thread->et_task; + + /* get the win32_section struct */ + flags |= section->ws_flags; + + if (offset >= section->ws_len || offset + size > section->ws_pagelen) { + status = STATUS_INVALID_PARAMETER; + goto out; + } + + /* map total section len */ + if (!size) + size = section->ws_pagelen - offset; + + if ((addr = (unsigned long)*BaseAddress)) { + /* fixed address map, align to 64k */ + addr = (addr + BASE_ADDRESS_ALIGN - 1) & ~(BASE_ADDRESS_ALIGN - 1); + if ((vma = find_vma(tsk->mm, addr)) && vma->vm_start < addr + size) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + flags |= MAP_FIXED; + } + + if (section->ws_mmap) { + /* do the mmap operation */ + status = section->ws_mmap(tsk, section, &addr, size, flags, offset >> PAGE_SHIFT); + if (NT_SUCCESS(status)) { + *BaseAddress = (PVOID)addr; + insert_mapped_area(Process, addr, addr + size, Protect, section); + } + } else + status = STATUS_UNSUCCESSFUL; + +out: + return status; +} /* end map_section_view() */ +EXPORT_SYMBOL(map_section_view); + +NTSTATUS STDCALL +unmap_section_view(struct eprocess *process, struct mm_struct *mm, unsigned long addr) +{ + struct win32_area_struct *ma; + struct win32_section *ws; + NTSTATUS ret; + + if (!(ma = find_mapped_area(process, addr, addr)) || ma->start != addr) + return STATUS_NOT_MAPPED_VIEW; + + ws = (struct win32_section *)ma->section_object; + if (ws && ws->ws_munmap) + ret = ws->ws_munmap(ws); + else { + down_write(&mm->mmap_sem); + ret = do_munmap(mm, addr, ws ? ws->ws_pagelen : ma->end - addr); + up_write(&mm->mmap_sem); + } + + remove_win32_area(ma); + + return STATUS_SUCCESS; +} +#endif diff --git a/unifiedkernel/mm/virtual.c b/unifiedkernel/mm/virtual.c new file mode 100644 index 0000000..d77b641 --- /dev/null +++ b/unifiedkernel/mm/virtual.c @@ -0,0 +1,929 @@ +/* + * virtual.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * virtual.c: virtual memory handling + * Refered to ReactOS code + */ +#include "virtual.h" +#include "attach.h" +#include "thread.h" +#include "process.h" +#include "section.h" +#include "object.h" +#include "w32syscall.h" +#include "area.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +#define IS_COW(prot) (((prot) == _PAGE_WRITECOPY) || ((prot) == _PAGE_EXECUTE_WRITECOPY)) + +static unsigned long prot_table_wtol[] = { + PROT_NONE, /* _PAGE_NOACCESS */ + PROT_READ, /* _PAGE_READONLY */ + PROT_READ | PROT_WRITE, /* _PAGE_READWRITE */ + PROT_READ | PROT_WRITE, /* _PAGE_WRITECOPY */ + PROT_EXEC, /* _PAGE_EXECUTE */ + PROT_EXEC | PROT_READ, /* _PAGE_EXECUTE_READ */ + PROT_EXEC | PROT_READ | PROT_WRITE, /* _PAGE_EXECUTE_READWRITE */ + PROT_EXEC | PROT_READ | PROT_WRITE, /* _PAGE_EXECUTE_WRITECOPY */ +}; + +static unsigned long prot_table_ltow[] = { + _PAGE_NOACCESS, /* MAP_PRIVATE, PROT_NONE */ + _PAGE_READONLY, /* MAP_PRIVATE, PROT_READ */ + _PAGE_WRITECOPY, /* MAP_PRIVATE, PROT_WRITE */ + _PAGE_WRITECOPY, /* MAP_PRIVATE, PROT_READ | PROT_WRITE */ + _PAGE_EXECUTE, /* MAP_PRIVATE, PROT_EXEC */ + _PAGE_EXECUTE_READ, /* MAP_PRIVATE, PROT_READ | PROT_EXEC */ + _PAGE_EXECUTE_WRITECOPY, /* MAP_PRIVATE, PROT_WRITE | PROT_EXEC */ + _PAGE_EXECUTE_WRITECOPY, /* MAP_PRIVATE, PROT_READ | PROT_WRITE | PROT_EXEC */ + _PAGE_NOACCESS, /* MAP_SHARED, PROT_NONE */ + _PAGE_READONLY, /* MAP_SHARED, PROT_READ */ + _PAGE_READWRITE, /* MAP_SHARED, PROT_WRITE */ + _PAGE_READWRITE, /* MAP_SHARED, PROT_READ | PROT_WRITE */ + _PAGE_EXECUTE, /* MAP_SHARED, PROT_EXEC */ + _PAGE_EXECUTE_READ, /* MAP_SHARED, PROT_READ | PROT_EXEC */ + _PAGE_EXECUTE_READWRITE, /* MAP_SHARED, PROT_WRITE | PROT_EXEC */ + _PAGE_EXECUTE_READWRITE /* MAP_SHARED, PROT_READ | PROT_WRITE | PROT_EXEC */ +}; + +unsigned long prot_to_linux(unsigned long win) +{ + return prot_table_wtol[ffs(win & 0xff) - 1]; +} + +unsigned long prot_to_win(struct vm_area_struct *vma) +{ + unsigned long vmflags; + + vmflags = vma->vm_file ? (vma->vm_flags & 0xf) : ((vma->vm_flags & 0x7) | 0x8); + return prot_table_ltow[vmflags]; +} + +static inline long uk_mprotect(struct mm_struct *mm, + unsigned long addr, size_t size, unsigned long prot) +{ + struct mm_struct *cur_mm; + long ret; + + cur_mm = current->mm; + current->mm = mm; + ret = sys_mprotect(addr, size, prot); + current->mm = cur_mm; + + return ret; +} + +static inline long uk_msync(struct mm_struct *mm, + unsigned long addr, size_t size, int flags) +{ + struct mm_struct *cur_mm; + long ret; + + cur_mm = current->mm; + current->mm = mm; + ret = sys_msync(addr, size, flags); + current->mm = cur_mm; + + return ret; +} + +/* + * NtQueryVirtualMemory + * Get the information of the virtual memory + */ +NTSTATUS SERVICECALL +NtQueryVirtualMemory (IN HANDLE ProcessHandle, + IN PVOID Address, + IN CINT VirtualMemoryInformationClass, + OUT PVOID VirtualMemoryInformation, + IN ULONG Length, + OUT PULONG UnsafeResultLength) +{ + NTSTATUS status; + ULONG result_len, addr; + struct ethread *first_thread; + struct eprocess *process; + struct mm_struct *mm; + struct vm_area_struct *vma; + struct win32_area_struct *ra, *ma; + MEMORY_BASIC_INFORMATION info; + MODE previous_mode; + + ktrace("NtQueryVirtualMemory %p:%p:%d:%p:%x:%p\n", + ProcessHandle, Address, VirtualMemoryInformationClass, + VirtualMemoryInformation, Length, UnsafeResultLength); + + previous_mode = (unsigned long)VirtualMemoryInformation > TASK_SIZE ? KernelMode : UserMode; + + status = ref_object_by_handle(ProcessHandle, + PROCESS_QUERY_INFORMATION, + NULL, + UserMode, + (PVOID *)(&process), + NULL); + if (!NT_SUCCESS(status)) + return status; + + first_thread = get_first_thread(process); + mm = first_thread->et_task->mm; + + addr = (ULONG)Address & PAGE_MASK; + + switch (VirtualMemoryInformationClass) { + case MemoryBasicInformation: + if (Length != sizeof(MEMORY_BASIC_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + goto out; + } + + result_len = sizeof(MEMORY_BASIC_INFORMATION); + + if ((ra = find_reserved_area(process, addr, addr))) { + info.Type = MEM_PRIVATE; + info.AllocationProtect = ra->prot; + info.BaseAddress = (PVOID)addr; + info.AllocationBase = (PVOID)ra->start; + info.RegionSize = ra->end - ra->start; + + vma = find_vma(mm, addr); + if (!vma) { + info.State = MEM_RESERVE; + info.Protect = 0; + } else { + info.Protect = prot_to_win(vma); + info.State = info.Protect == _PAGE_NOACCESS ? MEM_RESERVE : MEM_COMMIT; + } + } else if ((ma = find_mapped_area(process, addr, addr))) { + struct win32_section *ws = ma->section_object; + + info.Type = (ws && !ws->ws_sections) ? MEM_MAPPED : MEM_IMAGE; + info.AllocationProtect = ma->prot; + info.BaseAddress = (PVOID)addr; + info.AllocationBase = (PVOID)ma->start; + info.RegionSize = ma->end - ma->start; + + vma = find_vma(mm, addr); + if (!vma || vma->vm_start > addr) { + info.State = MEM_RESERVE; + info.Protect = 0; + } else { + info.Protect = prot_to_win(vma); + info.State = info.Protect == _PAGE_NOACCESS ? MEM_RESERVE : MEM_COMMIT; + info.RegionSize = vma->vm_end - addr; + } + } else { + info.Type = MEM_FREE; + info.RegionSize = get_free_area_size(process, addr); + info.BaseAddress = (PVOID)addr; + } + + break; + default: + status = STATUS_INVALID_INFO_CLASS; + goto out; + } + + status = STATUS_INVALID_ADDRESS;; + if (previous_mode == UserMode) { + if (copy_to_user(VirtualMemoryInformation, &info, sizeof(MEMORY_BASIC_INFORMATION))) + goto out; + if (UnsafeResultLength && copy_to_user(UnsafeResultLength, &result_len, sizeof(ULONG))) + goto out; + } + else { + *(PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation = info; + if (UnsafeResultLength) + *UnsafeResultLength = result_len; + } + + status = STATUS_SUCCESS; + +out: + deref_object(process); + return status; +} /* end NtQueryVirtualMemory */ +EXPORT_SYMBOL(NtQueryVirtualMemory); + +/* + * win32_do_mmap_pgoff + */ +unsigned long win32_do_mmap_pgoff(struct task_struct *task, struct file *filp, + unsigned long addr0, unsigned long size, unsigned long prot, + unsigned long flags, unsigned long pgoff) +{ + struct mm_struct *current_mm = current->mm; + unsigned long address; + + if (task != current) + current->mm = task->mm; + + down_write(¤t->mm->mmap_sem); + address = do_mmap_pgoff(filp, addr0, size, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (task != current) + current->mm = current_mm; + + return address; +} /* end win32_do_mmap_pgoff */ +EXPORT_SYMBOL(win32_do_mmap_pgoff); + +/* + * NtAllocateVirtualMemory + * Allocate a block of virtual memory in the process address space + */ +NTSTATUS SERVICECALL +NtAllocateVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG RegionSize, + IN ULONG AllocationType, + IN ULONG Protect) +{ + struct ethread *first_thread; + struct eprocess *process; + struct win32_area_struct *ra, *ma = NULL; + struct vm_area_struct *vma; + unsigned long prot, flags; + ULONG address; + ULONG size; + NTSTATUS status = STATUS_SUCCESS; + MODE previous_mode; + + ktrace("NtAllocateVirtualMemory: ProcessHandle %p, BaseAddress %p, Size %x, Type %x, Protect %x\n", + ProcessHandle, *BaseAddress, *RegionSize, AllocationType, Protect); + + /* Check the validity of the parameters */ + if ((Protect & PAGE_PROT_MASK) != Protect + || !(Protect & PAGE_PROT_MASK)) { + kdebug("FIXME: some protect not implemention! Protect %lx\n", Protect); + return STATUS_INVALID_PAGE_PROTECTION; + } + + if (!(AllocationType & (MEM_COMMIT | MEM_RESERVE)) && !(AllocationType & MEM_SYSTEM)) + return STATUS_INVALID_PARAMETER; + + previous_mode = (unsigned long)BaseAddress > TASK_SIZE ? KernelMode : UserMode; + if (previous_mode == UserMode) { + if (copy_from_user(&address, BaseAddress, sizeof(PVOID))) + return STATUS_INVALID_ADDRESS; + if (copy_from_user(&size, RegionSize,sizeof(ULONG))) + return STATUS_INVALID_ADDRESS; + } + else { + address = (ULONG)*BaseAddress; + size = *RegionSize; + } + + if (address > WIN32_TASK_SIZE) + return STATUS_INVALID_ADDRESS; + if (size > WIN32_TASK_SIZE || !size) + return STATUS_INVALID_PARAMETER; + size = (size + PAGE_SIZE - 1) & PAGE_MASK; + + if (!address && ((AllocationType & (MEM_RESERVE | MEM_COMMIT)) == MEM_COMMIT)) + AllocationType |= MEM_RESERVE; /* need allocate virtual memory */ + + status = ref_object_by_handle(ProcessHandle, + PROCESS_VM_OPERATION, + NULL, + UserMode, + (PVOID *)(&process), + NULL); + if (!NT_SUCCESS(status)) + return status; + + first_thread = get_first_thread(process); + + if (AllocationType & MEM_SYSTEM) { + struct vm_area_struct *prev; + + if (!(AllocationType & MEM_IMAGE)) { + insert_mapped_area(process, address, address + size, Protect, NULL); + return STATUS_SUCCESS; + } + + prev = find_vma(first_thread->et_task->mm, address - PAGE_SIZE); + vma = prev ? prev->vm_next : NULL; + if (prev && vma) + insert_mapped_area(process, prev->vm_start, + vma->vm_start + size, Protect, NULL); + kdebug("address %x, prev: start %lx, flags %lx, vma: start %lx, flags %lx\n", + address, prev ? prev->vm_start : 0, prev ? prev->vm_flags : 0, + vma ? vma->vm_start : 0, vma ? vma->vm_flags : 0); + status = STATUS_SUCCESS; + goto out; + } + + switch (AllocationType & (MEM_RESERVE | MEM_COMMIT)) { + case MEM_COMMIT: /* commit some reserved memory */ + status = STATUS_INVALID_ADDRESS; + address &= PAGE_MASK; + if (!(ra = find_reserved_area(process, address, address + size)) + && (!(ma = find_mapped_area(process, address, address + size)))) + goto out; + if (IS_COW(Protect)) { + status = STATUS_INVALID_PAGE_PROTECTION; + if (ra && ra->prot != Protect) + goto out; + if (ma && ma->prot != Protect) + goto out; + } + prot = prot_to_linux(Protect); + uk_mprotect(first_thread->et_task->mm, address, size, prot); + goto allocated; + case MEM_RESERVE: + address &= RESERVE_PAGE_MASK; + prot = PROT_NONE; + flags = MAP_PRIVATE | MAP_RESERVE; + break; + case MEM_RESERVE | MEM_COMMIT: + default: + address &= RESERVE_PAGE_MASK; + prot = prot_table_wtol[ffs(Protect & 0xff) - 1]; + flags = MAP_PRIVATE | MAP_RESERVE; + break; + } + + if (address) { + vma = find_vma(first_thread->et_task->mm, address); + if (vma && vma->vm_start < address + ((size + RESERVE_PAGE_SIZE - 1) & RESERVE_PAGE_MASK)) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + flags |= MAP_FIXED; + } + + address = win32_do_mmap_pgoff(first_thread->et_task, NULL, + address, size, prot, flags, 0); + if (IS_ERR((void *)address)) { + status = (NTSTATUS)address; + goto out; + } + + insert_reserved_area(process, address, address + size, Protect); + +allocated: + status = STATUS_INVALID_ADDRESS; + if (previous_mode == UserMode) { + if (copy_to_user(BaseAddress, &address, sizeof(PVOID))) + goto out; + if (copy_to_user(RegionSize, &size, sizeof(ULONG))) + goto out; + } + else { + *BaseAddress = (PVOID)address; + *RegionSize = size; + } + + status = STATUS_SUCCESS; + +out: + deref_object(process); + + return status; +} /* end NtAllocateVirtualMemory */ +EXPORT_SYMBOL(NtAllocateVirtualMemory); + +/* + * NtWriteVirtualMemory + * Write to memory + */ +NTSTATUS SERVICECALL +NtWriteVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten OPTIONAL) +{ + struct ethread *first_thread; + struct eprocess *process; + struct mm_struct *mm = NULL; + struct mm_struct *cur_mm = NULL; + struct vm_area_struct *vma; + PVOID kbuf; + MODE previous_mode; + NTSTATUS status; + + ktrace("NtWriteVirtualMemory: ProcessHandle %p, BaseAddress %p, Buffer %p, NumberOfBytesToWrite %d\n", + ProcessHandle, BaseAddress, Buffer, NumberOfBytesToWrite); + + previous_mode = (unsigned long)Buffer > TASK_SIZE ? KernelMode : UserMode; + + if (previous_mode == KernelMode) { + /* TODO */ + } + + if (NumberOfBytesToWrite > WIN32_TASK_SIZE) + return STATUS_INVALID_PARAMETER; + if ((ULONG)BaseAddress > WIN32_TASK_SIZE || (ULONG)Buffer > WIN32_TASK_SIZE) + return STATUS_INVALID_ADDRESS; + + status = ref_object_by_handle(ProcessHandle, + PROCESS_VM_WRITE, + NULL, + UserMode, + (PVOID *)(&process), + NULL); + if (!NT_SUCCESS(status)) + return status; + + first_thread = get_first_thread(process); + mm = first_thread->et_task->mm; + + vma = find_vma(mm, (ULONG)BaseAddress); + if (!vma || vma->vm_start > (ULONG)BaseAddress + || vma->vm_end < (ULONG)BaseAddress + NumberOfBytesToWrite) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + + if (!(vma->vm_flags & VM_WRITE)) { + status = STATUS_ACCESS_VIOLATION; + goto out; + } + + kbuf = kmalloc(NumberOfBytesToWrite, GFP_KERNEL); + if (!kbuf) { + status = STATUS_NO_MEMORY; + goto out; + } + + status = STATUS_INVALID_ADDRESS; + if (copy_from_user(kbuf, Buffer, NumberOfBytesToWrite)) + goto out_free_kbuf; + + /* Write memory */ + if (process == get_current_eprocess()) { + if (copy_to_user(BaseAddress, kbuf, NumberOfBytesToWrite)) + goto out_free_kbuf; + } + else { + cur_mm = attach_process(&process->pcb); + if (copy_to_user(BaseAddress, kbuf, NumberOfBytesToWrite)) { + detach_process(cur_mm); + goto out_free_kbuf; + } + detach_process(cur_mm); + } + + if (previous_mode == UserMode && NumberOfBytesWritten) { + if (copy_to_user(NumberOfBytesWritten, &NumberOfBytesToWrite, sizeof(ULONG))) + goto out_free_kbuf; + } + /* TODO + else *NumberOfBytesWritten = NumberOfBytesToWrite; + */ + status = STATUS_SUCCESS; + +out_free_kbuf: + kfree(kbuf); + +out: + deref_object(process); + return status; + +} /* end NtWriteVirtualMemory */ +EXPORT_SYMBOL(NtWriteVirtualMemory); + +/* + * NtReadVirtualMemory + * Read from memory + */ +NTSTATUS SERVICECALL +NtReadVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead OPTIONAL) +{ + struct eprocess *process; + struct ethread *first_thread; + PVOID kbuf; + struct mm_struct *mm, *cur_mm; + struct vm_area_struct *vma; + MODE previous_mode; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtReadVirtualMemory: ProcessHandle %p, BaseAddress %p, Buffer %p, NumberOfBytesToRead %d\n", + ProcessHandle, BaseAddress, Buffer, NumberOfBytesToRead); + + previous_mode = (unsigned long)Buffer > TASK_SIZE ? KernelMode : UserMode; + + if (previous_mode == KernelMode) { + /* TODO */ + } + + if (NumberOfBytesToRead > WIN32_TASK_SIZE) + return STATUS_INVALID_PARAMETER; + if ((ULONG)BaseAddress > WIN32_TASK_SIZE || (ULONG)Buffer > WIN32_TASK_SIZE) + return STATUS_INVALID_ADDRESS; + + status = ref_object_by_handle(ProcessHandle, + PROCESS_VM_READ, + NULL, + UserMode, + (PVOID *)(&process), + NULL); + if (!NT_SUCCESS(status)) + return status; + + first_thread = get_first_thread(process); + mm = first_thread->et_task->mm; + + vma = find_vma(mm, (ULONG)BaseAddress); + if (!vma || vma->vm_start > (ULONG)BaseAddress + || vma->vm_end < (ULONG)BaseAddress + NumberOfBytesToRead) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + + if (!(vma->vm_flags & VM_READ)) { + status = STATUS_ACCESS_VIOLATION; + goto out; + } + + kbuf = kmalloc(NumberOfBytesToRead, GFP_KERNEL); + if (!kbuf) { + status = STATUS_NO_MEMORY; + goto out; + } + + status = STATUS_INVALID_ADDRESS; + + /* Read memory */ + if (process == get_current_eprocess()) { + if (copy_from_user(kbuf, BaseAddress, NumberOfBytesToRead)) + goto out_free_kbuf; + } + else { + cur_mm = attach_process(&process->pcb); + if(copy_from_user(kbuf, BaseAddress, NumberOfBytesToRead)) { + detach_process(cur_mm); + goto out_free_kbuf; + } + detach_process(cur_mm); + } + + if (copy_to_user(Buffer, kbuf, NumberOfBytesToRead)) + goto out_free_kbuf; + + if (previous_mode == UserMode && NumberOfBytesRead) { + if (copy_to_user(NumberOfBytesRead, &NumberOfBytesToRead, sizeof(ULONG))) { + goto out_free_kbuf; + } + } + /* TODO + else *NumberOfBytesRead = NumberOfBytesToRead; + */ + status = STATUS_SUCCESS; + +out_free_kbuf: + kfree(kbuf); + +out: + deref_object(process); + return status; +} /* end NtReadVirtualMemory */ +EXPORT_SYMBOL(NtReadVirtualMemory); + +/* + * NtFreeVirtualMemory + * Free a range of virtual memory + */ +NTSTATUS SERVICECALL +NtFreeVirtualMemory(IN HANDLE ProcessHandle, + IN PVOID *BaseAddress, + IN PULONG RegionSize, + IN ULONG FreeType) +{ + struct ethread *first_thread; + struct eprocess *process; + struct mm_struct *mm; + struct win32_area_struct *ra; + struct win32_area_struct *ma = NULL; + ULONG address; + ULONG size; + MODE previous_mode; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtFreeVirtualMemory: ProcessHandle %p, BaseAddress %p, Size %x, FreeType %x\n", + ProcessHandle, *BaseAddress, *RegionSize, FreeType); + + if (((FreeType & (MEM_RELEASE | MEM_DECOMMIT)) == (MEM_RELEASE | MEM_DECOMMIT)) + || (!(FreeType & (MEM_RELEASE | MEM_DECOMMIT | MEM_SYSTEM)))) + return STATUS_INVALID_PARAMETER; + + previous_mode = (unsigned long)BaseAddress > TASK_SIZE ? KernelMode : UserMode; + if (previous_mode == UserMode) { + if (copy_from_user(&address, BaseAddress, sizeof(PVOID))) + return STATUS_INVALID_ADDRESS; + if (copy_from_user(&size, RegionSize, sizeof(ULONG))) + return STATUS_INVALID_ADDRESS; + } + else { + address = (ULONG)*BaseAddress; + size = *RegionSize; + } + + if (size && (FreeType & MEM_RELEASE)) + return STATUS_INVALID_PARAMETER; + + if (size > WIN32_TASK_SIZE) + return STATUS_INVALID_PARAMETER; + + status = ref_object_by_handle(ProcessHandle, + PROCESS_VM_OPERATION, + NULL, + UserMode, + (PVOID *)(&process), + NULL); + if (!NT_SUCCESS(status)) + return status; + + first_thread = get_first_thread(process); + mm = first_thread->et_task->mm; + + if (FreeType & MEM_SYSTEM) { + ma = find_mapped_area(process, address, address + size); + if (!ma) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + remove_win32_area(ma); + status = STATUS_SUCCESS; + goto out; + } + + ra = find_reserved_area(process, address, address + size); + if (!ra) { + ma = find_mapped_area(process, address, address + size); + if ((FreeType & MEM_RELEASE) || !ma) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + } + + if (FreeType & MEM_DECOMMIT) { + uk_mprotect(mm, address, size, PROT_NONE); + } else { + if (address != ra->start) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + + size = ra->end - ra->start; + remove_win32_area(ra); + + down_write(&mm->mmap_sem); + if (do_munmap(mm, (ULONG)address, size)) { + up_write(&mm->mmap_sem); + status = STATUS_NO_MEMORY; + goto out; + } + up_write(&mm->mmap_sem); + } + + status = STATUS_INVALID_ADDRESS; + if (previous_mode == UserMode) { + if (copy_to_user(BaseAddress, &address, sizeof(PVOID))) + goto out; + if (copy_to_user(RegionSize, &size, sizeof(ULONG))) + goto out; + } + else { + *BaseAddress = (PVOID)address; + *RegionSize = size; + } + + status = STATUS_SUCCESS; + +out: + deref_object(process); + return status; +} /* end NtFreeVirtualMemory */ +EXPORT_SYMBOL(NtFreeVirtualMemory); + +/* + * NtProtectVirtualMemory + * Change the protection + */ +NTSTATUS SERVICECALL +NtProtectVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *UnsafeBaseAddress, + IN OUT ULONG *UnsafeNumberOfBytesToProtect, + IN ULONG NewProtection, + OUT PULONG UnsafeOldProtection) +{ + struct eprocess *process; + struct ethread *first_thread; + struct mm_struct *mm; + struct vm_area_struct *vma; + ULONG address, addr_no_aligned; + ULONG size; + ULONG new_prot, old_prot; + MODE previous_mode; + NTSTATUS status; + + ktrace("NtProtectVirtualMemory: ProcessHandle %p, BaseAddress %p, BytesToProtect %x, NewProtection %x\n", + ProcessHandle, *UnsafeBaseAddress, *UnsafeNumberOfBytesToProtect, NewProtection); + + if ((NewProtection & PAGE_PROT_MASK) != NewProtection + || !(NewProtection & PAGE_PROT_MASK)) { + kdebug("FIXME: some protect not implemention! Protect %lx\n", NewProtection); + return STATUS_INVALID_PAGE_PROTECTION; + } + + previous_mode = (unsigned long)UnsafeBaseAddress > TASK_SIZE ? KernelMode : UserMode; + if (previous_mode == UserMode) { + if (copy_from_user(&address, UnsafeBaseAddress, sizeof(PVOID))) + return STATUS_INVALID_ADDRESS; + if (copy_from_user(&size, UnsafeNumberOfBytesToProtect, sizeof(ULONG))) + return STATUS_INVALID_ADDRESS; + } + else { + address = (ULONG)*UnsafeBaseAddress; + size = *UnsafeNumberOfBytesToProtect; + } + + if (size > WIN32_TASK_SIZE) + return STATUS_INVALID_ADDRESS; + + status = ref_object_by_handle(ProcessHandle, + PROCESS_VM_OPERATION, + NULL, + UserMode, + (PVOID *)(&process), + NULL); + if (!NT_SUCCESS(status)) + return status; + + first_thread = get_first_thread(process); + mm = first_thread->et_task->mm; + + addr_no_aligned = address; + address &= PAGE_MASK; + size = PAGE_ALIGN(addr_no_aligned + size) - address; + + vma = find_vma(mm, address); + if (!vma || vma->vm_start > address) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + + if (UnsafeOldProtection) { + old_prot = prot_to_win(vma); + if (previous_mode == KernelMode) + *UnsafeOldProtection = old_prot; + else if (copy_to_user(UnsafeOldProtection, &old_prot, sizeof(ULONG))) { + status = STATUS_INVALID_ADDRESS; + goto out; + } + } + + new_prot = prot_to_linux(NewProtection); + if (IS_COW(NewProtection) && (vma->vm_flags & VM_SHARED)) { + status = STATUS_INVALID_PAGE_PROTECTION; + goto out; + } + + status = uk_mprotect(mm, address, size, new_prot); + if (!NT_SUCCESS(status)) { +/* status = get_ntstatus(status); */ + goto out; + } + + status = STATUS_INVALID_ADDRESS; + if (previous_mode == UserMode) { + if (copy_to_user(UnsafeBaseAddress, &address, sizeof(PVOID))) + goto out; + if (copy_to_user(UnsafeNumberOfBytesToProtect, &size, sizeof(ULONG))) + goto out; + } else { + *UnsafeBaseAddress = (PVOID)address; + *UnsafeNumberOfBytesToProtect = size; + } + + status = STATUS_SUCCESS; + +out: + deref_object(process); + return status; +} /*end NtProtectVirtualMemory */ +EXPORT_SYMBOL(NtProtectVirtualMemory); + +/* + * NtFlushVirtualMemory + * Flush a range of virtual memory + */ +NTSTATUS SERVICECALL +NtFlushVirtualMemory(IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN OUT PSIZE_T RegionSize, + OUT PIO_STATUS_BLOCK IoStatus) +{ + struct eprocess *process; + struct ethread *first_thread; + struct mm_struct *mm; + struct win32_area_struct *ma; + ULONG address, addr_no_aligned; + SIZE_T size; + MODE previous_mode; + NTSTATUS status; + + ktrace("NtFlushVirtualMemory: ProcessHandle %p, BaseAddress %p, RegionSize %lx\n", + ProcessHandle, *BaseAddress, *RegionSize); + + previous_mode = (unsigned long)BaseAddress > TASK_SIZE ? KernelMode : UserMode; + if (previous_mode == UserMode) { + if (copy_from_user(&address, BaseAddress, sizeof(PVOID))) + return STATUS_INVALID_ADDRESS; + if (copy_from_user(&size, RegionSize, sizeof(SIZE_T))) + return STATUS_INVALID_ADDRESS; + } else { + address = (ULONG)*BaseAddress; + size = *RegionSize; + } + + if (size > WIN32_TASK_SIZE) + return STATUS_INVALID_PARAMETER; + + status = ref_object_by_handle(ProcessHandle, + PROCESS_VM_OPERATION, + NULL, + UserMode, + (PVOID *)&process, + NULL); + if (!NT_SUCCESS(status)) + return status; + + first_thread = get_first_thread(process); + mm = first_thread->et_task->mm; + + addr_no_aligned = address; + address &= PAGE_MASK; + size = PAGE_ALIGN(addr_no_aligned + size) - address; + + ma = find_mapped_area(process, address, address + size); + if (!ma) { + status = STATUS_NOT_MAPPED_VIEW; + goto out; + } + + if (!size) + size = ma->end - address; + + status = uk_msync(mm, address, size, MS_SYNC); +/* status = get_nt_status(status); */ + if (!NT_SUCCESS(status)) + goto out; + + status = STATUS_INVALID_ADDRESS; + if (previous_mode == UserMode) { + if (copy_to_user(BaseAddress, &address, sizeof(PVOID))) + goto out; + if (copy_to_user(RegionSize, &size, sizeof(SIZE_T))) + goto out; + } else { + *BaseAddress = (PVOID)address; + *RegionSize = size; + } + + status = STATUS_SUCCESS; + +out: + deref_object(process); + return status; +} /* end NtFlushVirtualMemory */ +EXPORT_SYMBOL(NtFlushVirtualMemory); +#endif diff --git a/unifiedkernel/msg/Makefile b/unifiedkernel/msg/Makefile new file mode 100644 index 0000000..0c73fe3 --- /dev/null +++ b/unifiedkernel/msg/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for msg management +# + +MSG_OBJS := queue.o \ + window.o \ + winstation.o \ + region.o \ + atom.o \ + hook.o \ + class.o \ + user.o + +$(MODULE)-objs += $(addprefix msg/, $(MSG_OBJS)) diff --git a/unifiedkernel/msg/atom.c b/unifiedkernel/msg/atom.c new file mode 100644 index 0000000..e73d37a --- /dev/null +++ b/unifiedkernel/msg/atom.c @@ -0,0 +1,484 @@ +/* + * atom.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * atom.c: + * Refered to Wine code + */ +#include +#include +#include + +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +#define HASH_SIZE 37 +#define MIN_HASH_SIZE 4 +#define MAX_HASH_SIZE 0x200 + +#define MAX_ATOM_LEN 255 +#define MIN_STR_ATOM 0xc000 +#define MAX_ATOMS 0x4000 + +struct atom_entry +{ + struct atom_entry *next; /* hash table list */ + struct atom_entry *prev; /* hash table list */ + int count; /* reference count */ + short pinned; /* whether the atom is pinned or not */ + atom_t atom; /* atom handle */ + unsigned short hash; /* string hash */ + unsigned short len; /* string len */ + WCHAR str[1]; /* atom string */ +}; + +struct atom_table +{ + struct object obj; /* object header */ + int count; /* count of atom handles */ + int last; /* last handle in-use */ + struct atom_entry **handles; /* atom handles */ + int entries_count; /* number of hash entries */ + struct atom_entry **entries; /* hash table entries */ +}; + +static void atom_table_dump( struct object *obj, int verbose ); +static void atom_table_destroy( struct object *obj ); + +static const struct object_ops atom_table_ops = +{ + sizeof(struct atom_table), /* size */ + atom_table_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + atom_table_destroy /* destroy */ +}; + +static struct atom_table *global_table; + +/* create an atom table */ +static struct atom_table *create_table(int entries_count) +{ + struct atom_table *table; + + if ((table = alloc_wine_object( &atom_table_ops ))) { + if ((entries_count < MIN_HASH_SIZE) || + (entries_count > MAX_HASH_SIZE)) entries_count = HASH_SIZE; + table->entries_count = entries_count; + if (!(table->entries = malloc( sizeof(*table->entries) * table->entries_count ))) { + set_error( STATUS_NO_MEMORY ); + goto fail; + } + memset( table->entries, 0, sizeof(*table->entries) * table->entries_count ); + table->count = 64; + table->last = -1; + if ((table->handles = mem_alloc( sizeof(*table->handles) * table->count ))) + return table; +fail: + release_object( table ); + table = NULL; + } + return table; +} + +/* retrieve an entry pointer from its atom */ +static struct atom_entry *get_atom_entry( struct atom_table *table, atom_t atom ) +{ + struct atom_entry *entry = NULL; + if (table && (atom >= MIN_STR_ATOM) && (atom <= MIN_STR_ATOM + table->last)) + entry = table->handles[atom - MIN_STR_ATOM]; + if (!entry) + set_error( STATUS_INVALID_HANDLE ); + return entry; +} + +/* add an atom entry in the table and return its handle */ +static atom_t add_atom_entry( struct atom_table *table, struct atom_entry *entry ) +{ + int i; + for (i = 0; i <= table->last; i++) + if (!table->handles[i]) + goto found; + if (i == table->count) { + struct atom_entry **new_table = NULL; + int new_size = table->count + table->count / 2; + if (new_size > MAX_ATOMS) new_size = MAX_ATOMS; + if (new_size > table->count) + new_table = realloc( table->handles, sizeof(*table->handles) * new_size, sizeof(*table->handles) * table->count ); + if (!new_table) { + set_error( STATUS_NO_MEMORY ); + return 0; + } + table->count = new_size; + table->handles = new_table; + } + table->last = i; + found: + table->handles[i] = entry; + entry->atom = i + MIN_STR_ATOM; + return entry->atom; +} + +/* compute the hash code for a string */ +static unsigned short atom_hash( struct atom_table *table, const WCHAR *str, data_size_t len ) +{ + unsigned int i; + unsigned short hash = 0; + for (i = 0; i < len; i++) + hash ^= toupperW(str[i]) + i; + return hash % table->entries_count; +} + +/* dump an atom table */ +static void atom_table_dump( struct object *obj, int verbose ) +{ + int i; + struct atom_table *table = (struct atom_table *)obj; +#if 0 + assert( obj->ops == &atom_table_ops ); +#endif + + ktrace( "Atom table size=%d entries=%d\n", + table->last + 1, table->entries_count ); + if (!verbose) + return; + for (i = 0; i <= table->last; i++) { + struct atom_entry *entry = table->handles[i]; + if (!entry) + continue; + ktrace( " %04x: ref=%d pinned=%c hash=%d \"", + entry->atom, entry->count, entry->pinned ? 'Y' : 'N', entry->hash ); +#if 0 + dump_strW( entry->str, entry->len, stderr, "\"\""); /* D.M. TBD */ +#endif + ktrace( "\"\n" ); + } +} + +/* destroy the atom table */ +static void atom_table_destroy( struct object *obj ) +{ + int i; + struct atom_table *table = (struct atom_table *)obj; +#if 0 + assert( obj->ops == &atom_table_ops ); +#endif + if (table->handles) { + for (i = 0; i <= table->last; i++) + free( table->handles[i] ); + free( table->handles ); + } + free( table->entries ); +} + +/* find an atom entry in its hash list */ +static struct atom_entry *find_atom_entry( struct atom_table *table, const WCHAR *str, + data_size_t len, unsigned short hash ) +{ + struct atom_entry *entry = table->entries[hash]; + while (entry) { + if (entry->len == len && !memicmpW( entry->str, str, len )) + break; + entry = entry->next; + } + return entry; +} + +/* add an atom to the table */ +static atom_t add_atom( struct atom_table *table, const WCHAR *str, data_size_t len ) +{ + struct atom_entry *entry; + unsigned short hash = atom_hash( table, str, len ); + atom_t atom = 0; + + if (!len) { + set_error( STATUS_OBJECT_NAME_INVALID ); + return 0; + } + if (len > MAX_ATOM_LEN) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + if ((entry = find_atom_entry( table, str, len, hash ))) { /* exists already */ + entry->count++; + return entry->atom; + } + + if ((entry = mem_alloc( sizeof(*entry) + (len - 1) * sizeof(WCHAR) ))) { + if ((atom = add_atom_entry( table, entry ))) { + entry->prev = NULL; + if ((entry->next = table->entries[hash])) + entry->next->prev = entry; + table->entries[hash] = entry; + entry->count = 1; + entry->pinned = 0; + entry->hash = hash; + entry->len = len; + memcpy( entry->str, str, len * sizeof(WCHAR) ); + } + else free( entry ); + } + else set_error( STATUS_NO_MEMORY ); + return atom; +} + +/* delete an atom from the table */ +static void delete_atom( struct atom_table *table, atom_t atom, int if_pinned ) +{ + struct atom_entry *entry = get_atom_entry( table, atom ); + if (!entry) + return; + if (entry->pinned && !if_pinned) + set_error( STATUS_WAS_LOCKED ); + else if (!--entry->count) { + if (entry->next) + entry->next->prev = entry->prev; + if (entry->prev) + entry->prev->next = entry->next; + else table->entries[entry->hash] = entry->next; + table->handles[atom - MIN_STR_ATOM] = NULL; + free( entry ); + } +} + +/* find an atom in the table */ +static atom_t find_atom( struct atom_table *table, const WCHAR *str, data_size_t len ) +{ + struct atom_entry *entry; + + if (!len) { + set_error( STATUS_OBJECT_NAME_INVALID ); + return 0; + } + if (len > MAX_ATOM_LEN) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + if (table && (entry = find_atom_entry( table, str, len, atom_hash(table, str, len) ))) + return entry->atom; + set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + return 0; +} + +static struct atom_table *get_global_table( struct winstation *winstation, int create ) +{ + struct atom_table *table = winstation ? winstation->atom_table : global_table; + if (!table) { + if (create) { + table = create_table( HASH_SIZE ); + if (winstation) + winstation->atom_table = table; + else { + global_table = table; + make_object_static( &global_table->obj ); + } + } + else set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + } + return table; +} + +static struct atom_table *get_table( obj_handle_t h, int create ) +{ + struct atom_table *table = NULL; + + if (h) { + table = (struct atom_table *)get_wine_handle_obj( get_current_w32process(), h, 0, &atom_table_ops ); + } + else { + table = get_global_table( NULL, 1 ); + if (table) + grab_object( table ); + } + return table; +} + +/* add an atom in the global table; used for window properties */ +atom_t add_global_atom( struct winstation *winstation, const WCHAR *str, data_size_t len ) +{ + struct atom_table *global_table = get_global_table( winstation, 1 ); + if (!global_table) + return 0; + return add_atom( global_table, str, len ); +} + +/* find an atom in the global table; used for window properties */ +atom_t find_global_atom( struct winstation *winstation, const WCHAR *str, data_size_t len ) +{ + struct atom_table *global_table = get_global_table( winstation, 0 ); + struct atom_entry *entry; + + if (!len || len > MAX_ATOM_LEN || !global_table) + return 0; + if ((entry = find_atom_entry( global_table, str, len, atom_hash(global_table, str, len) ))) + return entry->atom; + return 0; +} + +/* increment the ref count of a global atom; used for window properties */ +int grab_global_atom( struct winstation *winstation, atom_t atom ) +{ + if (atom >= MIN_STR_ATOM) { + struct atom_table *global_table = get_global_table( winstation, 0 ); + if (global_table) { + struct atom_entry *entry = get_atom_entry( global_table, atom ); + if (entry) + entry->count++; + return (entry != NULL); + } + else return 0; + } + else return 1; +} + +/* decrement the ref count of a global atom; used for window properties */ +void release_global_atom( struct winstation *winstation, atom_t atom ) +{ + if (atom >= MIN_STR_ATOM) { + struct atom_table *global_table = get_global_table( winstation, 0 ); + if (global_table) + delete_atom( global_table, atom, 1 ); + } +} + +/* add a global atom */ +DECL_HANDLER(add_atom) +{ + struct atom_table *table = get_table( req->table, 1 ); + if (table) { + reply->atom = add_atom( table, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + release_object( table ); + } +} + +/* delete a global atom */ +DECL_HANDLER(delete_atom) +{ + struct atom_table *table = get_table( req->table, 0 ); + if (table) { + delete_atom( table, req->atom, 0 ); + release_object( table ); + } +} + +/* find a global atom */ +DECL_HANDLER(find_atom) +{ + struct atom_table *table = get_table( req->table, 0 ); + if (table) { + reply->atom = find_atom( table, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + release_object( table ); + } +} + +/* get global atom name */ +DECL_HANDLER(get_atom_information) +{ + struct atom_table *table = get_table( req->table, 0 ); + if (table) { + struct atom_entry *entry; + + if ((entry = get_atom_entry( table, req->atom ))) { + data_size_t len = entry->len * sizeof(WCHAR); + if (get_reply_max_size()) + set_reply_data( entry->str, min( len, get_reply_max_size())); + reply->count = entry->count; + reply->pinned = entry->pinned; + reply->total = len; + } + else reply->count = -1; + release_object( table ); + } +} + +/* set global atom name */ +DECL_HANDLER(set_atom_information) +{ + struct atom_table *table = get_table( req->table, 0 ); + if (table) { + struct atom_entry *entry; + + if ((entry = get_atom_entry( table, req->atom ))) { + if (req->pinned) + entry->pinned = 1; + } + release_object( table ); + } +} + +/* init a (local) atom table */ +DECL_HANDLER(init_atom_table) +{ + struct atom_table* table = create_table( req->entries ); + + if (table) { + reply->table = alloc_handle( get_current_w32process(), table, 0, 0 ); + release_object( table ); + } +} + +/* set global atom name */ +DECL_HANDLER(empty_atom_table) +{ + struct atom_table *table = get_table( req->table, 1 ); + if (table) { + int i; + struct atom_entry *entry; + + for (i = 0; i <= table->last; i++) { + entry = table->handles[i]; + if (entry && (!entry->pinned || req->if_pinned)) { + if (entry->next) + entry->next->prev = entry->prev; + if (entry->prev) + entry->prev->next = entry->next; + else table->entries[entry->hash] = entry->next; + table->handles[i] = NULL; + free( entry ); + } + } + release_object( table ); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/msg/class.c b/unifiedkernel/msg/class.c new file mode 100644 index 0000000..de909f1 --- /dev/null +++ b/unifiedkernel/msg/class.c @@ -0,0 +1,273 @@ +/* + * class.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * class.c: + * Refered to Wine code + */ +#define WIN32_NO_STATUS + +#include +#include +#include + +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +struct window_class +{ + struct list_head entry; /* entry in process list */ + struct w32process *process; /* process owning the class */ + int count; /* reference count */ + int local; /* local class? */ + atom_t atom; /* class atom */ + void *instance; /* module instance */ + unsigned int style; /* class style */ + int win_extra; /* number of window extra bytes */ + void *client_ptr; /* pointer to class in client address space */ + int nb_extra_bytes; /* number of extra bytes */ + char extra_bytes[1]; /* extra bytes storage */ +}; + +static struct window_class *create_class( struct w32process *process, int extra_bytes, int local ) +{ + struct window_class *class; + + if (!(class = mem_alloc( sizeof(*class) + extra_bytes - 1 ))) + return NULL; + + class->process = (struct w32process *)grab_object( process ); + class->count = 0; + class->local = local; + class->nb_extra_bytes = extra_bytes; + memset( class->extra_bytes, 0, extra_bytes ); + /* other fields are initialized by caller */ + + /* local classes have priority so we put them first in the list */ + if (local) + list_add_head( &process->classes, &class->entry ); + else + my_list_add_tail( &process->classes, &class->entry ); + return class; +} + +static void destroy_class( struct window_class *class ) +{ + list_remove( &class->entry ); + release_object( class->process ); + free( class ); +} + +void destroy_process_classes( struct w32process *process ) +{ + struct list_head *ptr; + + while ((ptr = list_head( &process->classes ))) { + struct window_class *class = LIST_ENTRY( ptr, struct window_class, entry ); + destroy_class( class ); + } +} + +static struct window_class *find_class( struct w32process *process, atom_t atom, void *instance ) +{ + struct list_head *ptr; + + LIST_FOR_EACH( ptr, &process->classes ) { + struct window_class *class = LIST_ENTRY( ptr, struct window_class, entry ); + if (class->atom != atom) + continue; + if (!instance || !class->local || class->instance == instance) + return class; + } + return NULL; +} + +struct window_class *grab_class( struct w32process *process, atom_t atom, + void *instance, int *extra_bytes ) +{ + struct window_class *class = find_class( process, atom, instance ); + if (class) { + class->count++; + *extra_bytes = class->win_extra; + } + else + set_error( STATUS_INVALID_HANDLE ); + return class; +} + +void release_class( struct window_class *class ) +{ +#if 0 + assert( class->count > 0 ); +#endif + class->count--; +} + +int is_desktop_class( struct window_class *class ) +{ + return (class->atom == DESKTOP_ATOM && !class->local); +} + +atom_t get_class_atom( struct window_class *class ) +{ + return class->atom; +} + +void *get_class_client_ptr( struct window_class *class ) +{ + return class->client_ptr; +} + +/* create a window class */ +DECL_HANDLER(create_class) +{ + struct window_class *class; + atom_t atom; + + if (get_req_data_size()) { + atom = add_global_atom( NULL, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + if (!atom) + return; + } + else { + atom = req->atom; + if (!grab_global_atom( NULL, atom )) + return; + } + + class = find_class( get_current_w32process(), atom, req->instance ); + if (class && !class->local == !req->local) { + set_win32_error( ERROR_CLASS_ALREADY_EXISTS ); + release_global_atom( NULL, atom ); + return; + } + if (req->extra < 0 || req->extra > 4096 || req->win_extra < 0 || req->win_extra > 4096) { + /* don't allow stupid values here */ + set_error( STATUS_INVALID_PARAMETER ); + release_global_atom( NULL, atom ); + return; + } + + if (!(class = create_class( get_current_w32process(), req->extra, req->local ))) { + release_global_atom( NULL, atom ); + return; + } + class->atom = atom; + class->instance = req->instance; + class->style = req->style; + class->win_extra = req->win_extra; + class->client_ptr = req->client_ptr; + reply->atom = atom; +} + +/* destroy a window class */ +DECL_HANDLER(destroy_class) +{ + struct window_class *class; + atom_t atom = req->atom; + + if (get_req_data_size()) + atom = find_global_atom( NULL, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + + if (!(class = find_class( get_current_w32process(), atom, req->instance ))) + set_win32_error( ERROR_CLASS_DOES_NOT_EXIST ); + else if (class->count) + set_win32_error( ERROR_CLASS_HAS_WINDOWS ); + else { + reply->client_ptr = class->client_ptr; + destroy_class( class ); + } +} + + +/* set some information in a class */ +DECL_HANDLER(set_class_info) +{ + struct window_class *class = get_window_class( req->window ); + + if (!class) + return; + + if (req->flags && class->process != get_current_w32process()) { + set_error( STATUS_ACCESS_DENIED ); + return; + } + + if (req->extra_size > sizeof(req->extra_value) || + req->extra_offset < -1 || + req->extra_offset > class->nb_extra_bytes - (int)req->extra_size) { + set_win32_error( ERROR_INVALID_INDEX ); + return; + } + if ((req->flags & SET_CLASS_WINEXTRA) && (req->win_extra < 0 || req->win_extra > 4096)) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (req->extra_offset != -1) { + memcpy( &reply->old_extra_value, class->extra_bytes + req->extra_offset, req->extra_size ); + } + else if (req->flags & SET_CLASS_EXTRA) { + set_win32_error( ERROR_INVALID_INDEX ); + return; + } + + reply->old_atom = class->atom; + reply->old_style = class->style; + reply->old_extra = class->nb_extra_bytes; + reply->old_win_extra = class->win_extra; + reply->old_instance = class->instance; + + if (req->flags & SET_CLASS_ATOM) { + if (!grab_global_atom( NULL, req->atom )) + return; + release_global_atom( NULL, class->atom ); + class->atom = req->atom; + } + if (req->flags & SET_CLASS_STYLE) + class->style = req->style; + if (req->flags & SET_CLASS_WINEXTRA) + class->win_extra = req->win_extra; + if (req->flags & SET_CLASS_INSTANCE) + class->instance = req->instance; + if (req->flags & SET_CLASS_EXTRA) + memcpy( class->extra_bytes + req->extra_offset, + &req->extra_value, req->extra_size ); +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/msg/hook.c b/unifiedkernel/msg/hook.c new file mode 100644 index 0000000..830646d --- /dev/null +++ b/unifiedkernel/msg/hook.c @@ -0,0 +1,576 @@ +/* + * hook.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * hook.c: + * Refered to Wine code + */ +#define WIN32_NO_STATUS + +#include +#include +#include + +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct hook_table; + +struct hook +{ + struct list_head chain; /* hook chain entry */ + user_handle_t handle; /* user handle for this hook */ + struct w32process *process; /* process the hook is set to */ + struct w32thread *thread; /* thread the hook is set to */ + struct w32thread *owner; /* owner of the out of context hook */ + struct hook_table *table; /* hook table that contains this hook */ + int index; /* hook table index */ + int event_min; + int event_max; + int flags; + void *proc; /* hook function */ + int unicode; /* is it a unicode hook? */ + WCHAR *module; /* module name for global hooks */ + data_size_t module_size; +}; + +#define WH_WINEVENT (WH_MAXHOOK+1) + +#define NB_HOOKS (WH_WINEVENT-WH_MINHOOK+1) +#define HOOK_ENTRY(p) LIST_ENTRY( (p), struct hook, chain ) + +struct hook_table +{ + struct object obj; /* object header */ + struct list_head hooks[NB_HOOKS]; /* array of hook chains */ + int counts[NB_HOOKS]; /* use counts for each hook chain */ +}; + +static void hook_table_dump( struct object *obj, int verbose ); +static void hook_table_destroy( struct object *obj ); + +static const struct object_ops hook_table_ops = +{ + sizeof(struct hook_table), /* size */ + hook_table_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + hook_table_destroy /* destroy */ +}; + +/* create a new hook table */ +static struct hook_table *alloc_hook_table(void) +{ + struct hook_table *table; + int i; + + if ((table = alloc_wine_object( &hook_table_ops ))) { + for (i = 0; i < NB_HOOKS; i++) { + my_list_init( &table->hooks[i] ); + table->counts[i] = 0; + } + } + return table; +} + +static struct hook_table *get_global_hooks( struct w32thread *thread ) +{ + struct hook_table *table; + struct desktop *desktop = get_thread_desktop( thread, 0 ); + + if (!desktop) + return NULL; + table = desktop->global_hooks; + release_object( desktop ); + return table; +} + +/* create a new hook and add it to the specified table */ +static struct hook *add_hook( struct desktop *desktop, struct w32thread *thread, int index, int global ) +{ + struct hook *hook; + struct hook_table *table = global ? desktop->global_hooks : get_queue_hooks(thread); + + if (!table) { + if (!(table = alloc_hook_table())) + return NULL; + if (global) + desktop->global_hooks = table; + else + set_queue_hooks( thread, table ); + } + if (!(hook = mem_alloc( sizeof(*hook) ))) + return NULL; + + if (!(hook->handle = alloc_user_handle( hook, USER_HOOK ))) { + free( hook ); + return NULL; + } + hook->thread = thread ? (struct w32thread *)grab_object( thread ) : NULL; + hook->table = table; + hook->index = index; + list_add_head( &table->hooks[index], &hook->chain ); + if (thread) + thread->desktop_users++; + return hook; +} + +/* free a hook, removing it from its chain */ +static void free_hook( struct hook *hook ) +{ + free_user_handle( hook->handle ); + free( hook->module ); + if (hook->thread) { +#if 0 + assert( hook->thread->desktop_users > 0 ); +#endif + hook->thread->desktop_users--; + release_object( hook->thread ); + } + if (hook->process) + release_object( hook->process ); + release_object( hook->owner ); + list_remove( &hook->chain ); + free( hook ); +} + +/* find a hook from its index and proc */ +static struct hook *find_hook( struct w32thread *thread, int index, void *proc ) +{ + struct list_head *p; + struct hook_table *table = get_queue_hooks( thread ); + + if (table) { + LIST_FOR_EACH( p, &table->hooks[index] ) { + struct hook *hook = HOOK_ENTRY( p ); + if (hook->proc == proc) + return hook; + } + } + return NULL; +} + +/* get the first hook in the chain */ +static inline struct hook *get_first_hook( struct hook_table *table, int index ) +{ + struct list_head *elem = list_head( &table->hooks[index] ); + return elem ? HOOK_ENTRY( elem ) : NULL; +} + +/* check if a given hook should run in the current thread */ +static inline int run_hook_in_current_thread( struct hook *hook ) +{ + if ((!hook->process || hook->process == /*current->process*/NULL) && + (!(hook->flags & WINEVENT_SKIPOWNPROCESS) || hook->process != get_current_w32process())) { + if ((!hook->thread || hook->thread == /*current*/NULL) && + (!(hook->flags & WINEVENT_SKIPOWNTHREAD) || hook->thread != current_thread)) + return 1; + } + return 0; +} + +/* check if a given hook should run in the owner thread instead of the current thread */ +static inline int run_hook_in_owner_thread( struct hook *hook ) +{ + if ((hook->index == WH_MOUSE_LL - WH_MINHOOK || + hook->index == WH_KEYBOARD_LL - WH_MINHOOK)) + return hook->owner != current_thread; + return 0; +} + +/* find the first non-deleted hook in the chain */ +static inline struct hook *get_first_valid_hook( struct hook_table *table, int index, + int event, user_handle_t win, + int object_id, int child_id ) +{ + struct hook *hook = get_first_hook( table, index ); + + while (hook) { + if (hook->proc && run_hook_in_current_thread( hook )) { + if (event >= hook->event_min && event <= hook->event_max) { + if (hook->flags & WINEVENT_INCONTEXT) + return hook; + + /* only winevent hooks may be out of context */ +#if 0 + assert(hook->index + WH_MINHOOK == WH_WINEVENT); +#endif + post_win_event( hook->owner, event, win, object_id, child_id, + hook->proc, hook->module, hook->module_size, + hook->handle ); + } + } + hook = HOOK_ENTRY( list_next( &table->hooks[index], &hook->chain ) ); + } + return hook; +} + +/* find the next hook in the chain, skipping the deleted ones */ +static struct hook *get_next_hook( struct w32thread *thread, struct hook *hook, int event, + user_handle_t win, int object_id, int child_id ) +{ + struct hook_table *global_hooks, *table = hook->table; + int index = hook->index; + + while ((hook = HOOK_ENTRY( list_next( &table->hooks[index], &hook->chain ) ))) { + if (hook->proc && run_hook_in_current_thread( hook )) { + if (event >= hook->event_min && event <= hook->event_max) { + if (hook->flags & WINEVENT_INCONTEXT) + return hook; + + /* only winevent hooks may be out of context */ +#if 0 + assert(hook->index + WH_MINHOOK == WH_WINEVENT); +#endif + post_win_event( hook->owner, event, win, object_id, child_id, + hook->proc, hook->module, hook->module_size, + hook->handle ); + } + } + } + global_hooks = get_global_hooks( thread ); + if (global_hooks && table != global_hooks) { /* now search through the global table */ + hook = get_first_valid_hook( global_hooks, index, event, win, object_id, child_id ); + } + return hook; +} + +static void hook_table_dump( struct object *obj, int verbose ) +{ + /* struct hook_table *table = (struct hook_table *)obj; */ + ktrace( "Hook table\n" ); +} + +static void hook_table_destroy( struct object *obj ) +{ + int i; + struct hook *hook; + struct hook_table *table = (struct hook_table *)obj; + + for (i = 0; i < NB_HOOKS; i++) { + while ((hook = get_first_hook( table, i )) != NULL) + free_hook( hook ); + } +} + +/* remove a hook, freeing it if the chain is not in use */ +static void remove_hook( struct hook *hook ) +{ + if (hook->table->counts[hook->index]) + hook->proc = NULL; /* chain is in use, just mark it and return */ + else + free_hook( hook ); +} + +/* release a hook chain, removing deleted hooks if the use count drops to 0 */ +static void release_hook_chain( struct hook_table *table, int index ) +{ + if (!table->counts[index]) { /* use count shouldn't already be 0 */ + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (!--table->counts[index]) { + struct hook *hook = get_first_hook( table, index ); + while (hook) { + struct hook *next = HOOK_ENTRY( list_next( &table->hooks[hook->index], &hook->chain ) ); + if (!hook->proc) + free_hook( hook ); + hook = next; + } + } +} + +/* remove all global hooks owned by a given thread */ +void remove_thread_hooks( struct w32thread *thread ) +{ + struct hook_table *global_hooks = get_global_hooks( thread ); + int index; + + if (!global_hooks) + return; + + /* only low-level keyboard/mouse global hooks can be owned by a thread */ + for (index = WH_KEYBOARD_LL - WH_MINHOOK; index <= WH_MOUSE_LL - WH_MINHOOK; index++) { + struct hook *hook = get_first_hook( global_hooks, index ); + while (hook) { + struct hook *next = HOOK_ENTRY( list_next( &global_hooks->hooks[index], &hook->chain ) ); + if (hook->thread == thread) + remove_hook( hook ); + hook = next; + } + } +} + +/* get a bitmap of active hooks in a hook table */ +static int is_hook_active( struct hook_table *table, int index ) +{ + struct hook *hook = get_first_hook( table, index ); + + while (hook) { + if (hook->proc && run_hook_in_current_thread( hook )) + return 1; + hook = HOOK_ENTRY( list_next( &table->hooks[index], &hook->chain ) ); + } + return 0; +} + +/* get a bitmap of all active hooks for the current thread */ +unsigned int get_active_hooks(void) +{ + struct hook_table *table = get_queue_hooks( current_thread ); + struct hook_table *global_hooks = get_global_hooks( current_thread ); + unsigned int ret = 1 << 31; /* set high bit to indicate that the bitmap is valid */ + int id; + + for (id = WH_MINHOOK; id <= WH_WINEVENT; id++) { + if ((table && is_hook_active( table, id - WH_MINHOOK )) || + (global_hooks && is_hook_active( global_hooks, id - WH_MINHOOK ))) + ret |= 1 << (id - WH_MINHOOK); + } + return ret; +} + +/* set a window hook */ +DECL_HANDLER(set_hook) +{ + struct w32process *process = NULL; + struct w32thread *thread = NULL; + struct desktop *desktop; + struct hook *hook; + WCHAR *module; + int global; + data_size_t module_size = get_req_data_size(); + + if (!req->proc || req->id < WH_MINHOOK || req->id > WH_WINEVENT) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (!(desktop = get_thread_desktop( current_thread, DESKTOP_HOOKCONTROL ))) + return; + + if (req->pid && !(process = (void*)get_process_from_id((void*) req->pid ))) + goto done; /* D.M. TBD */ + + if (req->tid) { + if (!(thread = get_thread_from_id( req->tid ))) + goto done; + if (process && process != thread->process) { + set_error( STATUS_INVALID_PARAMETER ); + goto done; + } + } + + if (req->id == WH_KEYBOARD_LL || req->id == WH_MOUSE_LL) { + /* low-level hardware hooks are special: always global, but without a module */ + if (thread) { + set_error( STATUS_INVALID_PARAMETER ); + goto done; + } + module = NULL; + global = 1; + } + else if (!req->tid) { + /* out of context hooks do not need a module handle */ + if (!module_size && (req->flags & WINEVENT_INCONTEXT)) { + set_error( STATUS_INVALID_PARAMETER ); + goto done; + } + if (!(module = memdup( get_req_data(), module_size ))) + goto done; + global = 1; + } + else { + /* module is optional only if hook is in current process */ + if (!module_size) { + module = NULL; + if (thread->process != get_current_w32process()) { + set_error( STATUS_INVALID_PARAMETER ); + goto done; + } + } + else if (!(module = memdup( get_req_data(), module_size ))) + goto done; + global = 0; + } + + if ((hook = add_hook( desktop, thread, req->id - WH_MINHOOK, global ))) { + hook->owner = (struct w32thread *)grab_object( current ); + hook->process = process ? (struct w32process *)grab_object( process ) : NULL; + hook->event_min = req->event_min; + hook->event_max = req->event_max; + hook->flags = req->flags; + hook->proc = req->proc; + hook->unicode = req->unicode; + hook->module = module; + hook->module_size = module_size; + reply->handle = hook->handle; + reply->active_hooks = get_active_hooks(); + } + else + free( module ); + +done: + if (process) + release_object( process ); + if (thread) + release_object( thread ); + release_object( desktop ); +} + + +/* remove a window hook */ +DECL_HANDLER(remove_hook) +{ + struct hook *hook; + + if (req->handle) { + if (!(hook = get_user_object( req->handle, USER_HOOK ))) { + set_error( STATUS_INVALID_HANDLE ); + return; + } + } + else { + if (!req->proc || req->id < WH_MINHOOK || req->id > WH_WINEVENT) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (!(hook = find_hook( current_thread, req->id - WH_MINHOOK, req->proc ))) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + } + remove_hook( hook ); + reply->active_hooks = get_active_hooks(); +} + +extern thread_id_t get_thread_id( struct w32thread *thread ); + +/* start calling a hook chain */ +DECL_HANDLER(start_hook_chain) +{ + struct hook *hook; + struct hook_table *table = get_queue_hooks( current_thread ); + + if (req->id < WH_MINHOOK || req->id > WH_WINEVENT) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + reply->active_hooks = get_active_hooks(); + + if (!table || !(hook = get_first_valid_hook( table, req->id - WH_MINHOOK, req->event, + req->window, req->object_id, req->child_id ))) { + /* try global table */ + if (!(table = get_global_hooks( current_thread )) || + !(hook = get_first_valid_hook( table, req->id - WH_MINHOOK, req->event, + req->window, req->object_id, req->child_id ))) + return; /* no hook set */ + } + + if (run_hook_in_owner_thread( hook )) { + reply->pid = get_process_id( hook->owner->process ); + reply->tid = get_thread_id( hook->owner ); + } + else { + reply->pid = 0; + reply->tid = 0; + } + reply->proc = hook->proc; + reply->handle = hook->handle; + reply->unicode = hook->unicode; + table->counts[hook->index]++; + if (hook->module) + set_reply_data( hook->module, hook->module_size ); +} + + +/* finished calling a hook chain */ +DECL_HANDLER(finish_hook_chain) +{ + struct hook_table *table = get_queue_hooks( current_thread ); + struct hook_table *global_hooks = get_global_hooks( current_thread ); + int index = req->id - WH_MINHOOK; + + if (req->id < WH_MINHOOK || req->id > WH_WINEVENT) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + if (table) + release_hook_chain( table, index ); + if (global_hooks) + release_hook_chain( global_hooks, index ); +} + + +/* get the hook information */ +DECL_HANDLER(get_hook_info) +{ + struct hook *hook; + + if (!(hook = get_user_object( req->handle, USER_HOOK ))) + return; + if (hook->thread && (hook->thread != current_thread)) { + set_error( STATUS_INVALID_HANDLE ); + return; + } + if (req->get_next && !(hook = get_next_hook( current_thread, hook, req->event, req->window, + req->object_id, req->child_id ))) + return; + + reply->handle = hook->handle; + reply->id = hook->index + WH_MINHOOK; + reply->unicode = hook->unicode; + if (hook->module) + set_reply_data( hook->module, min(hook->module_size,get_reply_max_size()) ); + if (run_hook_in_owner_thread( hook )) { + reply->pid = get_process_id( hook->owner->process ); + reply->tid = get_thread_id( hook->owner ); + } + else { + reply->pid = 0; + reply->tid = 0; + } + reply->proc = hook->proc; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/msg/queue.c b/unifiedkernel/msg/queue.c new file mode 100644 index 0000000..05a4cd2 --- /dev/null +++ b/unifiedkernel/msg/queue.c @@ -0,0 +1,2188 @@ +/* + * queue.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * queue.c: + * Refered to Wine code + */ +#include +#include +#include + +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "wineserver/info.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE +#define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST)) + +enum message_kind { SEND_MESSAGE, POST_MESSAGE }; +#define NB_MSG_KINDS (POST_MESSAGE+1) + + +struct message_result +{ + struct list_head sender_entry; /* entry in sender list */ + struct message *msg; /* message the result is for */ + struct message_result *recv_next; /* next in receiver list */ + struct msg_queue *sender; /* sender queue */ + struct msg_queue *receiver; /* receiver queue */ + int replied; /* has it been replied to? */ + unsigned int error; /* error code to pass back to sender */ + unsigned long result; /* reply result */ + struct message *callback_msg; /* message to queue for callback */ + void *data; /* message reply data */ + unsigned int data_size; /* size of message reply data */ + struct timeout_user *timeout; /* result timeout */ +}; + +struct message +{ + struct list_head entry; /* entry in message list */ + enum message_type type; /* message type */ + user_handle_t win; /* window handle */ + unsigned int msg; /* message code */ + unsigned long wparam; /* parameters */ + unsigned long lparam; /* parameters */ + unsigned long info; /* extra info */ + int x; /* x position */ + int y; /* y position */ + unsigned int time; /* message time */ + void *data; /* message data for sent messages */ + unsigned int data_size; /* size of message data */ + unsigned int unique_id; /* unique id for nested hw message waits */ + struct message_result *result; /* result in sender queue */ +}; + +struct timer +{ + struct list_head entry; /* entry in timer list */ + timeout_t when; /* next expiration */ + unsigned int rate; /* timer rate in ms */ + user_handle_t win; /* window handle */ + unsigned int msg; /* message to post */ + unsigned long id; /* timer id */ + unsigned long lparam; /* lparam for message */ +}; + +struct thread_input +{ + struct object obj; /* object header */ + struct desktop *desktop; /* desktop that this thread input belongs to */ + user_handle_t focus; /* focus window */ + user_handle_t capture; /* capture window */ + user_handle_t active; /* active window */ + user_handle_t menu_owner; /* current menu owner window */ + user_handle_t move_size; /* current moving/resizing window */ + user_handle_t caret; /* caret window */ + rectangle_t caret_rect; /* caret rectangle */ + int caret_hide; /* caret hide count */ + int caret_state; /* caret on/off state */ + struct list_head msg_list; /* list of hardware messages */ + unsigned char keystate[256]; /* state of each key */ +}; + +struct msg_queue +{ + struct object obj; /* object header */ + struct fd *fd; /* optional file descriptor to poll */ + unsigned int wake_bits; /* wakeup bits */ + unsigned int wake_mask; /* wakeup mask */ + unsigned int changed_bits; /* changed wakeup bits */ + unsigned int changed_mask; /* changed wakeup mask */ + int paint_count; /* pending paint messages count */ + int quit_message; /* is there a pending quit message? */ + int exit_code; /* exit code of pending quit message */ + struct list_head msg_list[NB_MSG_KINDS]; /* lists of messages */ + struct list_head send_result; /* stack of sent messages waiting for result */ + struct list_head callback_result; /* list of callback messages waiting for result */ + struct message_result *recv_result; /* stack of received messages waiting for result */ + struct list_head pending_timers; /* list of pending timers */ + struct list_head expired_timers; /* list of expired timers */ + unsigned long next_timer_id; /* id for the next timer with a 0 window */ + struct timeout_user *timeout; /* timeout for next timer to expire */ + struct thread_input *input; /* thread input descriptor */ + struct hook_table *hooks; /* hook table */ + timeout_t last_get_msg; /* time of last get message call */ +}; + +static void msg_queue_destroy( struct object *obj ); +static void msg_queue_poll_event( struct fd *fd, int event ); +static void thread_input_dump( struct object *obj, int verbose ); +static void thread_input_destroy( struct object *obj ); +static void timer_callback( void *private ); + +static const struct object_ops msg_queue_ops = +{ + sizeof(struct msg_queue), /* size */ + msg_queue_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + msg_queue_destroy /* destroy */ +}; + +static const struct fd_ops msg_queue_fd_ops = +{ + NULL, /* get_poll_events */ + msg_queue_poll_event, /* poll_event */ + NULL, /* flush */ + NULL, /* get_fd_type */ + NULL, /* ioctl */ + NULL, /* queue_async */ + NULL, /* reselect_async */ + NULL /* cancel async */ +}; + + +static const struct object_ops thread_input_ops = +{ + sizeof(struct thread_input), /* size */ + thread_input_dump, /* dump */ + no_get_type, /* get_type */ + no_get_fd, /* get_fd */ + no_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + no_close_handle, /* close_handle */ + thread_input_destroy /* destroy */ +}; + +/* pointer to input structure of foreground thread */ +static struct thread_input *foreground_input; +static unsigned int last_input_time; + +static void free_message( struct message *msg ); + +/* set the caret window in a given thread input */ +static void set_caret_window( struct thread_input *input, user_handle_t win ) +{ + if (!win || win != input->caret) { + input->caret_rect.left = 0; + input->caret_rect.top = 0; + input->caret_rect.right = 0; + input->caret_rect.bottom = 0; + } + input->caret = win; + input->caret_hide = 1; + input->caret_state = 0; +} + +/* create a thread input object */ +static struct thread_input *create_thread_input( struct w32thread *thread ) +{ + struct thread_input *input; + + if ((input = alloc_wine_object( &thread_input_ops ))) { + input->focus = 0; + input->capture = 0; + input->active = 0; + input->menu_owner = 0; + input->move_size = 0; + my_list_init( &input->msg_list ); + set_caret_window( input, 0 ); + memset( input->keystate, 0, sizeof(input->keystate) ); + + if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) { + release_object( input ); + return NULL; + } + } + return input; +} + +/* release the thread input data of a given thread */ +static inline void release_thread_input( struct w32thread *thread ) +{ + struct thread_input *input = thread->queue->input; + + if (!input) + return; + release_object( input ); + thread->queue->input = NULL; +} + +/* create a message queue object */ +static struct msg_queue *create_msg_queue( struct w32thread *thread, struct thread_input *input ) +{ + struct msg_queue *queue; + int i; + + if (!input && !(input = create_thread_input( thread ))) + return NULL; + if ((queue = alloc_wine_object( &msg_queue_ops ))) { + queue->fd = NULL; + queue->wake_bits = 0; + queue->wake_mask = 0; + queue->changed_bits = 0; + queue->changed_mask = 0; + queue->paint_count = 0; + queue->quit_message = 0; + queue->recv_result = NULL; + queue->next_timer_id = 0x7fff; + queue->timeout = NULL; + queue->input = (struct thread_input *)grab_object( input ); + queue->hooks = NULL; + queue->last_get_msg = current_time; + my_list_init( &queue->send_result ); + my_list_init( &queue->callback_result ); + my_list_init( &queue->pending_timers ); + my_list_init( &queue->expired_timers ); + for (i = 0; i < NB_MSG_KINDS; i++) + my_list_init( &queue->msg_list[i] ); + + thread->queue = queue; + if (!thread->process->queue) + thread->process->queue = (struct msg_queue *)grab_object( queue ); + } + release_object( input ); + return queue; +} + +/* free the message queue of a thread at thread exit */ +void free_msg_queue( struct w32thread *thread ) +{ + struct w32process *process = thread->process; + + remove_thread_hooks( thread ); + if (!thread->queue) + return; + if (process->queue == thread->queue) { /* is it the process main queue? */ + release_object( process->queue ); + process->queue = NULL; + if (process->idle_event) { + set_event( process->idle_event, EVENT_INCREMENT, FALSE ); + release_object( process->idle_event ); + process->idle_event = NULL; + } + } + release_object( thread->queue ); + thread->queue = NULL; +} + +/* get the hook table for a given thread */ +struct hook_table *get_queue_hooks( struct w32thread *thread ) +{ + if (!thread->queue) + return NULL; + return thread->queue->hooks; +} + +/* set the hook table for a given thread, allocating the queue if needed */ +void set_queue_hooks( struct w32thread *thread, struct hook_table *hooks ) +{ + struct msg_queue *queue = thread->queue; + if (!queue && !(queue = create_msg_queue( thread, NULL ))) + return; + if (queue->hooks) + release_object( queue->hooks ); + queue->hooks = hooks; +} + +/* check the queue status */ +static inline int is_signaled( struct msg_queue *queue ) +{ + return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask)); +} + +extern void uk_wake_up( struct object *obj, int max ); + +/* set some queue bits */ +static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits ) +{ + queue->wake_bits |= bits; + queue->changed_bits |= bits; + if (is_signaled( queue )) + uk_wake_up( &queue->obj, 0 ); +} + +/* clear some queue bits */ +static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits ) +{ + queue->wake_bits &= ~bits; + queue->changed_bits &= ~bits; +} + +/* check whether msg is a keyboard message */ +static inline int is_keyboard_msg( struct message *msg ) +{ + return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST); +} + +/* check if message is matched by the filter */ +static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last ) +{ + return (msg >= first && msg <= last); +} + +/* check whether a message filter contains at least one potential hardware message */ +static inline int filter_contains_hw_range( unsigned int first, unsigned int last ) +{ + /* hardware message ranges are (in numerical order): + * WM_NCMOUSEFIRST .. WM_NCMOUSELAST + * WM_KEYFIRST .. WM_KEYLAST + * WM_MOUSEFIRST .. WM_MOUSELAST + */ + if (last < WM_NCMOUSEFIRST) + return 0; + if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) + return 0; + if (first > WM_KEYLAST && last < WM_MOUSEFIRST) + return 0; + if (first > WM_MOUSELAST) + return 0; + return 1; +} + +/* get the QS_* bit corresponding to a given hardware message */ +static inline int get_hardware_msg_bit( struct message *msg ) +{ + if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) + return QS_MOUSEMOVE; + if (is_keyboard_msg( msg )) + return QS_KEY; + return QS_MOUSEBUTTON; +} + +/* get the current thread queue, creating it if needed */ +struct msg_queue *get_current_queue(void) +{ + struct msg_queue *queue = current->ethread->lpc_reply_message; /* D.M. TBD Temp hack */ + if (!queue) + queue = create_msg_queue( current_thread, NULL ); + return queue; +} + +/* get a (pseudo-)unique id to tag hardware messages */ +static inline unsigned int get_unique_id(void) +{ + static unsigned int id; + if (!++id) + id = 1; /* avoid an id of 0 */ + return id; +} + +/* try to merge a message with the last in the list; return 1 if successful */ +static int merge_message( struct thread_input *input, const struct message *msg ) +{ + struct message *prev; + struct list_head *ptr = list_tail( &input->msg_list ); + + if (!ptr) + return 0; + prev = LIST_ENTRY( ptr, struct message, entry ); + if (prev->result) + return 0; + if (prev->win && msg->win && prev->win != msg->win) + return 0; + if (prev->msg != msg->msg) + return 0; + if (prev->type != msg->type) + return 0; + /* now we can merge it */ + prev->wparam = msg->wparam; + prev->lparam = msg->lparam; + prev->x = msg->x; + prev->y = msg->y; + prev->time = msg->time; + prev->info = msg->info; + return 1; +} + + +/* free a result structure */ +static void free_result( struct message_result *result ) +{ + if (result->timeout) + remove_timeout_user( result->timeout ); + free( result->data ); + if (result->callback_msg) + free_message( result->callback_msg ); + free( result ); +} + +/* remove the result from the sender list it is on */ +static inline void remove_result_from_sender( struct message_result *result ) +{ +#if 0 + assert( result->sender ); +#endif + + list_remove( &result->sender_entry ); + result->sender = NULL; + if (!result->receiver) + free_result( result ); +} + +/* store the message result in the appropriate structure */ +static void store_message_result( struct message_result *res, unsigned long result, + unsigned int error ) +{ + res->result = result; + res->error = error; + res->replied = 1; + if (res->timeout) { + remove_timeout_user( res->timeout ); + res->timeout = NULL; + } + if (res->sender) { + if (res->callback_msg) { + /* queue the callback message in the sender queue */ + struct callback_msg_data *data = res->callback_msg->data; + data->result = result; + my_list_add_tail( &res->sender->msg_list[SEND_MESSAGE], &res->callback_msg->entry ); + set_queue_bits( res->sender, QS_SENDMESSAGE ); + res->callback_msg = NULL; + remove_result_from_sender( res ); + } + else { + /* wake sender queue if waiting on this result */ + if (list_head(&res->sender->send_result) == &res->sender_entry) + set_queue_bits( res->sender, QS_SMRESULT ); + } + } +} + +/* free a message when deleting a queue or window */ +static void free_message( struct message *msg ) +{ + struct message_result *result = msg->result; + if (result) { + result->msg = NULL; + if (result->sender) { + result->receiver = NULL; + store_message_result( result, 0, STATUS_ACCESS_DENIED /*FIXME*/ ); + } + else + free_result( result ); + } + free( msg->data ); + free( msg ); +} + +/* remove (and free) a message from a message list */ +static void remove_queue_message( struct msg_queue *queue, struct message *msg, + enum message_kind kind ) +{ + list_remove( &msg->entry ); + switch(kind) { + case SEND_MESSAGE: + if (my_list_empty( &queue->msg_list[kind] )) + clear_queue_bits( queue, QS_SENDMESSAGE ); + break; + case POST_MESSAGE: + if (my_list_empty( &queue->msg_list[kind] ) && !queue->quit_message) + clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE ); + break; + } + free_message( msg ); +} + +/* message timed out without getting a reply */ +static void result_timeout( void *private ) +{ + struct message_result *result = private; + +#if 0 + assert( !result->replied ); +#endif + + result->timeout = NULL; + + if (result->msg) { /* not received yet */ + struct message *msg = result->msg; + + result->msg = NULL; + msg->result = NULL; + remove_queue_message( result->receiver, msg, SEND_MESSAGE ); + result->receiver = NULL; + if (!result->sender) { + free_result( result ); + return; + } + } + + store_message_result( result, 0, STATUS_TIMEOUT ); +} + +extern int get_tick_count(void); + +/* allocate and fill a message result structure */ +static struct message_result *alloc_message_result( struct msg_queue *send_queue, + struct msg_queue *recv_queue, + struct message *msg, timeout_t timeout ) +{ + struct message_result *result = mem_alloc( sizeof(*result) ); + if (result) { + result->msg = msg; + result->sender = send_queue; + result->receiver = recv_queue; + result->replied = 0; + result->data = NULL; + result->data_size = 0; + result->timeout = NULL; + + if (msg->type == MSG_CALLBACK) { + struct message *callback_msg = mem_alloc( sizeof(*callback_msg) ); + + if (!callback_msg) { + free( result ); + return NULL; + } + callback_msg->type = MSG_CALLBACK_RESULT; + callback_msg->win = msg->win; + callback_msg->msg = msg->msg; + callback_msg->wparam = 0; + callback_msg->lparam = 0; + callback_msg->time = get_tick_count(); + callback_msg->x = 0; + callback_msg->y = 0; + callback_msg->info = 0; + callback_msg->result = NULL; + /* steal the data from the original message */ + callback_msg->data = msg->data; + callback_msg->data_size = msg->data_size; + msg->data = NULL; + msg->data_size = 0; + + result->callback_msg = callback_msg; + list_add_head( &send_queue->callback_result, &result->sender_entry ); + } + else { + result->callback_msg = NULL; + list_add_head( &send_queue->send_result, &result->sender_entry ); + } + + if (timeout != TIMEOUT_INFINITE) + result->timeout = add_timeout_user( timeout, result_timeout, result ); + } + return result; +} + +/* receive a message, removing it from the sent queue */ +static void receive_message( struct msg_queue *queue, struct message *msg, + struct get_message_reply *reply ) +{ + struct message_result *result = msg->result; + + reply->total = msg->data_size; + if (msg->data_size > get_reply_max_size()) { + set_error( STATUS_BUFFER_OVERFLOW ); + return; + } + reply->type = msg->type; + reply->win = msg->win; + reply->msg = msg->msg; + reply->wparam = msg->wparam; + reply->lparam = msg->lparam; + reply->x = msg->x; + reply->y = msg->y; + reply->time = msg->time; + reply->info = msg->info; + + if (msg->data) + set_reply_data_ptr( msg->data, msg->data_size ); + + list_remove( &msg->entry ); + /* put the result on the receiver result stack */ + if (result) { + result->msg = NULL; + result->recv_next = queue->recv_result; + queue->recv_result = result; + } + free( msg ); + if (my_list_empty( &queue->msg_list[SEND_MESSAGE] )) + clear_queue_bits( queue, QS_SENDMESSAGE ); +} + +/* set the result of the current received message */ +static void reply_message( struct msg_queue *queue, unsigned long result, + unsigned int error, int remove, const void *data, data_size_t len ) +{ + struct message_result *res = queue->recv_result; + + if (remove) { + queue->recv_result = res->recv_next; + res->receiver = NULL; + if (!res->sender) { /* no one waiting for it */ + free_result( res ); + return; + } + } + if (!res->replied) { + if (len && (res->data = memdup( data, len ))) + res->data_size = len; + store_message_result( res, result, error ); + } +} + + /* PeekMessage() options */ +#define PM_NOREMOVE 0x0000 +#define PM_REMOVE 0x0001 +#define PM_NOYIELD 0x0002 +#define PM_QS_INPUT (QS_INPUT << 16) +#define PM_QS_POSTMESSAGE ((QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16) +#define PM_QS_PAINT (QS_PAINT << 16) +#define PM_QS_SENDMESSAGE (QS_SENDMESSAGE << 16) + + +/* retrieve a posted message */ +static int get_posted_message( struct msg_queue *queue, user_handle_t win, + unsigned int first, unsigned int last, unsigned int flags, + struct get_message_reply *reply ) +{ + struct message *msg; + + /* check against the filters */ + LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[POST_MESSAGE], struct message, entry ) { + if (win && msg->win && msg->win != win && !is_child_window( win, msg->win )) + continue; + if (!check_msg_filter( msg->msg, first, last )) + continue; + goto found; /* found one */ + } + return 0; + + /* return it to the app */ +found: + reply->total = msg->data_size; + if (msg->data_size > get_reply_max_size()) { + set_error( STATUS_BUFFER_OVERFLOW ); + return 1; + } + reply->type = msg->type; + reply->win = msg->win; + reply->msg = msg->msg; + reply->wparam = msg->wparam; + reply->lparam = msg->lparam; + reply->x = msg->x; + reply->y = msg->y; + reply->time = msg->time; + reply->info = msg->info; + + if (flags & PM_REMOVE) { + if (msg->data) { + set_reply_data_ptr( msg->data, msg->data_size ); + msg->data = NULL; + msg->data_size = 0; + } + remove_queue_message( queue, msg, POST_MESSAGE ); + } + else if (msg->data) + set_reply_data( msg->data, msg->data_size ); + + return 1; +} + +static int get_quit_message( struct msg_queue *queue, unsigned int flags, + struct get_message_reply *reply ) +{ + if (queue->quit_message) { + reply->total = 0; + reply->type = MSG_POSTED; + reply->win = NULL; + reply->msg = WM_QUIT; + reply->wparam = queue->exit_code; + reply->lparam = 0; + reply->x = 0; + reply->y = 0; + reply->time = get_tick_count(); + reply->info = 0; + + if (flags & PM_REMOVE) { + queue->quit_message = 0; + if (my_list_empty( &queue->msg_list[POST_MESSAGE] )) + clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE ); + } + return 1; + } + else + return 0; +} + +/* empty a message list and free all the messages */ +static void empty_msg_list( struct list_head *list ) +{ + struct list_head *ptr; + + while ((ptr = list_head( list )) != NULL) { + struct message *msg = LIST_ENTRY( ptr, struct message, entry ); + list_remove( &msg->entry ); + free_message( msg ); + } +} + +/* cleanup all pending results when deleting a queue */ +static void cleanup_results( struct msg_queue *queue ) +{ + struct list_head *entry; + + while ((entry = list_head( &queue->send_result )) != NULL) { + remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) ); + } + + while ((entry = list_head( &queue->callback_result )) != NULL) { + remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) ); + } + + while (queue->recv_result) + reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 ); +} + +/* check if the thread owning the queue is hung (not checking for messages) */ +static int is_queue_hung( struct msg_queue *queue ) +{ +#if 0 + struct wait_queue_entry *entry; + + if (current_time - queue->last_get_msg <= 5 * TICKS_PER_SEC) + return 0; /* less than 5 seconds since last get message -> not hung */ + + LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry ) { + if (entry->thread->queue == queue) + return 0; /* thread is waiting on queue -> not hung */ + } +#endif + return 1; +} + +void msg_queue_dump( struct object *obj, int verbose ) +{ +#if 0 + struct msg_queue *queue = (struct msg_queue *)obj; + ktrace("Msg queue bits=%x mask=%x\n", + queue->wake_bits, queue->wake_mask ); +#endif +} + +static int msg_queue_satisfied( struct object *obj, struct w32thread *thread ) +{ + struct msg_queue *queue = (struct msg_queue *)obj; + queue->wake_mask = 0; + queue->changed_mask = 0; + return 0; /* Not abandoned */ +} + +static void msg_queue_destroy( struct object *obj ) +{ + struct msg_queue *queue = (struct msg_queue *)obj; + struct list_head *ptr; + int i; + + cleanup_results( queue ); + for (i = 0; i < NB_MSG_KINDS; i++) + empty_msg_list( &queue->msg_list[i] ); + + while ((ptr = list_head( &queue->pending_timers ))) { + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + list_remove( &timer->entry ); + free( timer ); + } + while ((ptr = list_head( &queue->expired_timers ))) { + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + list_remove( &timer->entry ); + free( timer ); + } + if (queue->timeout) + remove_timeout_user( queue->timeout ); + if (queue->input) + release_object( queue->input ); + if (queue->hooks) + release_object( queue->hooks ); + if (queue->fd) + release_object( queue->fd ); +} + +static void msg_queue_poll_event( struct fd *fd, int event ) +{ + struct msg_queue *queue = get_fd_user( fd ); +#if 0 + assert( queue->obj.ops == &msg_queue_ops ); +#endif + + if (event & (POLLERR | POLLHUP)) + set_fd_events( fd, -1 ); + uk_wake_up( &queue->obj, 0 ); +} + +static void thread_input_dump( struct object *obj, int verbose ) +{ +#if 0 + struct thread_input *input = (struct thread_input *)obj; + ktrace("Thread input focus=%p capture=%p active=%p\n", + input->focus, input->capture, input->active ); +#endif +} + +static void thread_input_destroy( struct object *obj ) +{ + struct thread_input *input = (struct thread_input *)obj; + + if (foreground_input == input) + foreground_input = NULL; + empty_msg_list( &input->msg_list ); + if (input->desktop) + release_object( input->desktop ); +} + +/* fix the thread input data when a window is destroyed */ +static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window ) +{ + struct thread_input *input = queue->input; + + if (window == input->focus) + input->focus = 0; + if (window == input->capture) + input->capture = 0; + if (window == input->active) + input->active = 0; + if (window == input->menu_owner) + input->menu_owner = 0; + if (window == input->move_size) + input->move_size = 0; + if (window == input->caret) + set_caret_window( input, 0 ); +} + +/* check if the specified window can be set in the input data of a given queue */ +static int check_queue_input_window( struct msg_queue *queue, user_handle_t window ) +{ + struct w32thread *thread; + int ret = 0; + + if (!window) + return 1; /* we can always clear the data */ + + if ((thread = get_window_thread( window ))) { + ret = (queue->input == thread->queue->input); + if (!ret) + set_error( STATUS_ACCESS_DENIED ); + release_object( thread ); + } + else + set_error( STATUS_INVALID_HANDLE ); + + return ret; +} + +/* make sure the specified thread has a queue */ +int init_thread_queue( struct w32thread *thread ) +{ + if (thread->queue) + return 1; + return (create_msg_queue( thread, NULL ) != NULL); +} + +/* attach two thread input data structures */ +int attach_thread_input( struct w32thread *thread_from, struct w32thread *thread_to ) +{ + struct desktop *desktop; + struct thread_input *input; + + if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) + return 0; + if (!(desktop = get_thread_desktop( thread_from, 0 ))) + return 0; + input = (struct thread_input *)grab_object( thread_to->queue->input ); + if (input->desktop != desktop) { + set_error( STATUS_ACCESS_DENIED ); + release_object( input ); + release_object( desktop ); + return 0; + } + release_object( desktop ); + + if (thread_from->queue) { + release_thread_input( thread_from ); + thread_from->queue->input = input; + } + else { + if (!(thread_from->queue = create_msg_queue( thread_from, input ))) + return 0; + } + memset( input->keystate, 0, sizeof(input->keystate) ); + return 1; +} + +/* detach two thread input data structures */ +void detach_thread_input( struct w32thread *thread_from ) +{ + struct thread_input *input; + + if ((input = create_thread_input( thread_from ))) { + release_thread_input( thread_from ); + thread_from->queue->input = input; + } +} + + +/* set the next timer to expire */ +static void set_next_timer( struct msg_queue *queue ) +{ + struct list_head *ptr; + + if (queue->timeout) { + remove_timeout_user( queue->timeout ); + queue->timeout = NULL; + } + if ((ptr = list_head( &queue->pending_timers ))) { + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + queue->timeout = add_timeout_user( timer->when, timer_callback, queue ); + } + /* set/clear QS_TIMER bit */ + if (my_list_empty( &queue->expired_timers )) + clear_queue_bits( queue, QS_TIMER ); + else + set_queue_bits( queue, QS_TIMER ); +} + +/* find a timer from its window and id */ +static struct timer *find_timer( struct msg_queue *queue, user_handle_t win, + unsigned int msg, unsigned long id ) +{ + struct list_head *ptr; + + /* we need to search both lists */ + + LIST_FOR_EACH( ptr, &queue->pending_timers ) { + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + if (timer->win == win && timer->msg == msg && timer->id == id) + return timer; + } + LIST_FOR_EACH( ptr, &queue->expired_timers ) { + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + if (timer->win == win && timer->msg == msg && timer->id == id) + return timer; + } + return NULL; +} + +/* callback for the next timer expiration */ +static void timer_callback( void *private ) +{ + struct msg_queue *queue = private; + struct list_head *ptr; + + queue->timeout = NULL; + /* move on to the next timer */ + ptr = list_head( &queue->pending_timers ); + list_remove( ptr ); + my_list_add_tail( &queue->expired_timers, ptr ); + set_next_timer( queue ); +} + +/* link a timer at its rightful place in the queue list */ +static void link_timer( struct msg_queue *queue, struct timer *timer ) +{ + struct list_head *ptr; + + for (ptr = queue->pending_timers.next; ptr != &queue->pending_timers; ptr = ptr->next) { + struct timer *t = LIST_ENTRY( ptr, struct timer, entry ); + if (t->when >= timer->when) + break; + } + list_add_before( ptr, &timer->entry ); +} + +/* remove a timer from the queue timer list and free it */ +static void free_timer( struct msg_queue *queue, struct timer *timer ) +{ + list_remove( &timer->entry ); + free( timer ); + set_next_timer( queue ); +} + +/* restart an expired timer */ +static void restart_timer( struct msg_queue *queue, struct timer *timer ) +{ + list_remove( &timer->entry ); + while (timer->when <= current_time) + timer->when += (timeout_t)timer->rate * 10000; + link_timer( queue, timer ); + set_next_timer( queue ); +} + +/* find an expired timer matching the filtering parameters */ +static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t win, + unsigned int get_first, unsigned int get_last, + int remove ) +{ + struct list_head *ptr; + + LIST_FOR_EACH( ptr, &queue->expired_timers ) { + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + if (win && timer->win != win) + continue; + if (check_msg_filter( timer->msg, get_first, get_last )) { + if (remove) + restart_timer( queue, timer ); + return timer; + } + } + return NULL; +} + +/* add a timer */ +static struct timer *set_timer( struct msg_queue *queue, unsigned int rate ) +{ + struct timer *timer = mem_alloc( sizeof(*timer) ); + if (timer) { + timer->rate = max( rate, (unsigned int)1 ); + timer->when = current_time + (timeout_t)timer->rate * 10000; + link_timer( queue, timer ); + /* check if we replaced the next timer */ + if (list_head( &queue->pending_timers ) == &timer->entry) + set_next_timer( queue ); + } + return timer; +} + +/* change the input key state for a given key */ +static void set_input_key_state( struct thread_input *input, unsigned char key, int down ) +{ + if (down) { + if (!(input->keystate[key] & 0x80)) input->keystate[key] ^= 0x01; + input->keystate[key] |= 0x80; + } + else + input->keystate[key] &= ~0x80; +} + +/* update the input key state for a keyboard message */ +static void update_input_key_state( struct thread_input *input, const struct message *msg ) +{ + unsigned char key; + int down = 0; + + switch (msg->msg) { + case WM_LBUTTONDOWN: + down = 1; + /* fall through */ + case WM_LBUTTONUP: + set_input_key_state( input, VK_LBUTTON, down ); + break; + case WM_MBUTTONDOWN: + down = 1; + /* fall through */ + case WM_MBUTTONUP: + set_input_key_state( input, VK_MBUTTON, down ); + break; + case WM_RBUTTONDOWN: + down = 1; + /* fall through */ + case WM_RBUTTONUP: + set_input_key_state( input, VK_RBUTTON, down ); + break; + case WM_XBUTTONDOWN: + down = 1; + /* fall through */ + case WM_XBUTTONUP: + if (msg->wparam == XBUTTON1) + set_input_key_state( input, VK_XBUTTON1, down ); + else if (msg->wparam == XBUTTON2) + set_input_key_state( input, VK_XBUTTON2, down ); + break; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + down = 1; + /* fall through */ + case WM_KEYUP: + case WM_SYSKEYUP: + key = (unsigned char)msg->wparam; + set_input_key_state( input, key, down ); + switch(key) { + case VK_LCONTROL: + case VK_RCONTROL: + down = (input->keystate[VK_LCONTROL] | input->keystate[VK_RCONTROL]) & 0x80; + set_input_key_state( input, VK_CONTROL, down ); + break; + case VK_LMENU: + case VK_RMENU: + down = (input->keystate[VK_LMENU] | input->keystate[VK_RMENU]) & 0x80; + set_input_key_state( input, VK_MENU, down ); + break; + case VK_LSHIFT: + case VK_RSHIFT: + down = (input->keystate[VK_LSHIFT] | input->keystate[VK_RSHIFT]) & 0x80; + set_input_key_state( input, VK_SHIFT, down ); + break; + } + break; + } +} + +/* release the hardware message currently being processed by the given thread */ +static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id, + int remove, user_handle_t new_win ) +{ + struct thread_input *input = queue->input; + struct message *msg; + + LIST_FOR_EACH_ENTRY( msg, &input->msg_list, struct message, entry ) { + if (msg->unique_id == hw_id) + break; + } + if (&msg->entry == &input->msg_list) + return; /* not found */ + + /* clear the queue bit for that message */ + if (remove || new_win) { + struct message *other; + int clr_bit; + + clr_bit = get_hardware_msg_bit( msg ); + LIST_FOR_EACH_ENTRY( other, &input->msg_list, struct message, entry ) { + if (other != msg && get_hardware_msg_bit( other ) == clr_bit) { + clr_bit = 0; + break; + } + } + if (clr_bit) + clear_queue_bits( queue, clr_bit ); + } + + if (new_win) { /* set the new window */ + struct w32thread *owner = get_window_thread( new_win ); + if (owner) { + msg->win = new_win; + if (owner->queue->input != input) { + list_remove( &msg->entry ); + if (msg->msg == WM_MOUSEMOVE && merge_message( owner->queue->input, msg )) { + free_message( msg ); + release_object( owner ); + return; + } + my_list_add_tail( &owner->queue->input->msg_list, &msg->entry ); + } + set_queue_bits( owner->queue, get_hardware_msg_bit( msg )); + remove = 0; + release_object( owner ); + } + } + if (remove) { + update_input_key_state( input, msg ); + list_remove( &msg->entry ); + free_message( msg ); + } +} + +/* find the window that should receive a given hardware message */ +static user_handle_t find_hardware_message_window( struct thread_input *input, struct message *msg, + unsigned int *msg_code ) +{ + user_handle_t win = 0; + + *msg_code = msg->msg; + if (is_keyboard_msg( msg )) { + if (input && !(win = input->focus)) { + win = input->active; + if (*msg_code < WM_SYSKEYDOWN) + *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; + } + } + else { /* mouse message */ + if (!input || !(win = input->capture)) { + if (!(win = msg->win) || !is_window_visible( win )) { + if (input) + win = window_from_point( input->desktop, msg->x, msg->y ); + } + } + } + return win; +} + +/* queue a hardware message into a given thread input */ +static void queue_hardware_message( struct msg_queue *queue, struct message *msg ) +{ + user_handle_t win; + struct w32thread *thread; + struct thread_input *input = queue ? queue->input : foreground_input; + unsigned int msg_code; + + last_input_time = get_tick_count(); + win = find_hardware_message_window( input, msg, &msg_code ); + if (!win || !(thread = get_window_thread(win))) { + if (input) + update_input_key_state( input, msg ); + free( msg ); + return; + } + input = thread->queue->input; + + if (msg->msg == WM_MOUSEMOVE && merge_message( input, msg )) + free( msg ); + else { + msg->unique_id = 0; /* will be set once we return it to the app */ + my_list_add_tail( &input->msg_list, &msg->entry ); + set_queue_bits( thread->queue, get_hardware_msg_bit(msg) ); + } + release_object( thread ); +} + +/* check message filter for a hardware message */ +static int check_hw_message_filter( user_handle_t win, unsigned int msg_code, + user_handle_t filter_win, unsigned int first, unsigned int last ) +{ + if (msg_code >= WM_KEYFIRST && msg_code <= WM_KEYLAST) { + /* we can only test the window for a keyboard message since the + * dest window for a mouse message depends on hittest */ + if (filter_win && win != filter_win && !is_child_window( filter_win, win )) + return 0; + /* the message code is final for a keyboard message, we can simply check it */ + return check_msg_filter( msg_code, first, last ); + } + else { /* mouse message */ + /* we need to check all possible values that the message can have in the end */ + + if (check_msg_filter( msg_code, first, last )) + return 1; + if (msg_code == WM_MOUSEWHEEL) + return 0; /* no other possible value for this one */ + + /* all other messages can become non-client messages */ + if (check_msg_filter( msg_code + (WM_NCMOUSEFIRST - WM_MOUSEFIRST), first, last )) + return 1; + + /* clicks can become double-clicks or non-client double-clicks */ + if (msg_code == WM_LBUTTONDOWN || msg_code == WM_MBUTTONDOWN || + msg_code == WM_RBUTTONDOWN || msg_code == WM_XBUTTONDOWN) { + if (check_msg_filter( msg_code + (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN), first, last )) + return 1; + if (check_msg_filter( msg_code + (WM_NCLBUTTONDBLCLK - WM_LBUTTONDOWN), first, last )) + return 1; + } + return 0; + } +} + + +/* find a hardware message for the given queue */ +static int get_hardware_message( struct w32thread *thread, unsigned int hw_id, user_handle_t filter_win, + unsigned int first, unsigned int last, struct get_message_reply *reply ) +{ + struct thread_input *input = thread->queue->input; + struct w32thread *win_thread; + struct list_head *ptr; + user_handle_t win; + int clear_bits, got_one = 0; + unsigned int msg_code; + + ptr = list_head( &input->msg_list ); + if (hw_id) { + while (ptr) { + struct message *msg = LIST_ENTRY( ptr, struct message, entry ); + if (msg->unique_id == hw_id) + break; + ptr = list_next( &input->msg_list, ptr ); + } + if (!ptr) + ptr = list_head( &input->msg_list ); + else + ptr = list_next( &input->msg_list, ptr ); /* start from the next one */ + } + + if (ptr == list_head( &input->msg_list )) + clear_bits = QS_KEY | QS_MOUSEMOVE | QS_MOUSEBUTTON; + else + clear_bits = 0; /* don't clear bits if we don't go through the whole list */ + + while (ptr) { + struct message *msg = LIST_ENTRY( ptr, struct message, entry ); + ptr = list_next( &input->msg_list, ptr ); + win = find_hardware_message_window( input, msg, &msg_code ); + if (!win || !(win_thread = get_window_thread( win ))) { + /* no window at all, remove it */ + update_input_key_state( input, msg ); + list_remove( &msg->entry ); + free_message( msg ); + continue; + } + if (win_thread != thread) { + if (win_thread->queue->input == input) { + /* wake the other thread */ + set_queue_bits( win_thread->queue, get_hardware_msg_bit(msg) ); + got_one = 1; + } + else { + /* for another thread input, drop it */ + update_input_key_state( input, msg ); + list_remove( &msg->entry ); + free_message( msg ); + } + release_object( win_thread ); + continue; + } + release_object( win_thread ); + + /* if we already got a message for another thread, or if it doesn't + * match the filter we skip it */ + if (got_one || !check_hw_message_filter( win, msg_code, filter_win, first, last )) { + clear_bits &= ~get_hardware_msg_bit( msg ); + continue; + } + /* now we can return it */ + if (!msg->unique_id) + msg->unique_id = get_unique_id(); + reply->type = MSG_HARDWARE; + reply->win = win; + reply->msg = msg_code; + reply->wparam = msg->wparam; + reply->lparam = msg->lparam; + reply->x = msg->x; + reply->y = msg->y; + reply->time = msg->time; + reply->info = msg->info; + reply->hw_id = msg->unique_id; + return 1; + } + /* nothing found, clear the hardware queue bits */ + clear_queue_bits( thread->queue, clear_bits ); + return 0; +} + +/* increment (or decrement if 'incr' is negative) the queue paint count */ +void inc_queue_paint_count( struct w32thread *thread, int incr ) +{ + struct msg_queue *queue = thread->queue; + +#if 0 + assert( queue ); +#endif + + if ((queue->paint_count += incr) < 0) + queue->paint_count = 0; + + if (queue->paint_count) + set_queue_bits( queue, QS_PAINT ); + else + clear_queue_bits( queue, QS_PAINT ); +} + +/* remove all messages and timers belonging to a certain window */ +void queue_cleanup_window( struct w32thread *thread, user_handle_t win ) +{ + struct msg_queue *queue = thread->queue; + struct list_head *ptr; + int i; + + if (!queue) + return; + + /* remove timers */ + + ptr = list_head( &queue->pending_timers ); + while (ptr) { + struct list_head *next = list_next( &queue->pending_timers, ptr ); + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + if (timer->win == win) + free_timer( queue, timer ); + ptr = next; + } + ptr = list_head( &queue->expired_timers ); + while (ptr) { + struct list_head *next = list_next( &queue->expired_timers, ptr ); + struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); + if (timer->win == win) + free_timer( queue, timer ); + ptr = next; + } + + /* remove messages */ + for (i = 0; i < NB_MSG_KINDS; i++) { + struct list_head *ptr, *next; + + LIST_FOR_EACH_SAFE( ptr, next, &queue->msg_list[i] ) { + struct message *msg = LIST_ENTRY( ptr, struct message, entry ); + if (msg->win == win) + remove_queue_message( queue, msg, i ); + } + } + + thread_input_cleanup_window( queue, win ); +} + +/* post a message to a window; used by socket handling */ +void post_message( user_handle_t win, unsigned int message, + unsigned long wparam, unsigned long lparam ) +{ + struct message *msg; + struct w32thread *thread = get_window_thread( win ); + + if (!thread) + return; + + if (thread->queue && (msg = mem_alloc( sizeof(*msg) ))) { + msg->type = MSG_POSTED; + msg->win = get_user_full_handle( win ); + msg->msg = message; + msg->wparam = wparam; + msg->lparam = lparam; + msg->time = get_tick_count(); + msg->x = 0; + msg->y = 0; + msg->info = 0; + msg->result = NULL; + msg->data = NULL; + msg->data_size = 0; + + my_list_add_tail( &thread->queue->msg_list[POST_MESSAGE], &msg->entry ); + set_queue_bits( thread->queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE ); + } + release_object( thread ); +} + +extern thread_id_t get_thread_id( struct w32thread *thread ); + +/* post a win event */ +void post_win_event( struct w32thread *thread, unsigned int event, + user_handle_t win, unsigned int object_id, + unsigned int child_id, void *hook_proc, + const WCHAR *module, data_size_t module_size, + user_handle_t hook) +{ + struct message *msg; + + if (thread->queue && (msg = mem_alloc( sizeof(*msg) ))) { + struct winevent_msg_data *data; + + msg->type = MSG_WINEVENT; + msg->win = get_user_full_handle( win ); + msg->msg = event; + msg->wparam = object_id; + msg->lparam = child_id; + msg->time = get_tick_count(); + msg->x = 0; + msg->y = 0; + msg->info = 0; + msg->result = NULL; + + if ((data = malloc( sizeof(*data) + module_size ))) { + data->hook = hook; + data->tid = get_thread_id( current_thread ); + data->hook_proc = hook_proc; + memcpy( data + 1, module, module_size ); + + msg->data = data; + msg->data_size = sizeof(*data) + module_size; +#if 0 + if (debug_level > 1) + fprintf( stderr, "post_win_event: tid %04x event %04x win %p object_id %d child_id %d\n", + get_thread_id(thread), event, win, object_id, child_id ); +#endif + my_list_add_tail( &thread->queue->msg_list[SEND_MESSAGE], &msg->entry ); + set_queue_bits( thread->queue, QS_SENDMESSAGE ); + } + else + free( msg ); + } +} + +/* check if the thread owning the window is hung */ +DECL_HANDLER(is_window_hung) +{ + struct w32thread *thread; + + thread = get_window_thread( req->win ); + if (thread) { + reply->is_hung = is_queue_hung( thread->queue ); + release_object( thread ); + } + else + reply->is_hung = 0; +} + +/* get the message queue of the current thread */ +DECL_HANDLER(get_msg_queue) +{ + struct msg_queue *queue = get_current_queue(); + + reply->handle = 0; + if (queue) + reply->handle = alloc_handle( get_current_w32process(), queue, SYNCHRONIZE, 0 ); +} + +extern NTSTATUS errno2ntstatus(int error); +/* set the file descriptor associated to the current thread queue */ +DECL_HANDLER(set_queue_fd) +{ + struct msg_queue *queue = get_current_queue(); + int unix_fd; + + if (queue->fd) { /* fd can only be set once */ + set_error( STATUS_ACCESS_DENIED ); + return; + } + if ((unix_fd = get_handle_fd(get_current_eprocess(), req->handle)) >= 0) { + if ((unix_fd = uk_dup( unix_fd )) != -1) + queue->fd = create_anonymous_fd( &msg_queue_fd_ops, unix_fd, &queue->obj, 0 ); + else + errno2ntstatus(-unix_fd); + } +} + + +/* set the current message queue wakeup mask */ +DECL_HANDLER(set_queue_mask) +{ + struct msg_queue *queue = get_current_queue(); + + if (queue) { + queue->wake_mask = req->wake_mask; + queue->changed_mask = req->changed_mask; + reply->wake_bits = queue->wake_bits; + reply->changed_bits = queue->changed_bits; + if (is_signaled( queue )) { + /* if skip wait is set, do what would have been done in the subsequent wait */ + if (req->skip_wait) + msg_queue_satisfied( &queue->obj, NULL); /* D.M. TBD */ + else + uk_wake_up( &queue->obj, 0 ); + } + } +} + + +/* get the current message queue status */ +DECL_HANDLER(get_queue_status) +{ + struct msg_queue *queue = /*current->queue;*/get_current_queue(); /* D.M. TBD */ + if (queue) { + reply->wake_bits = queue->wake_bits; + reply->changed_bits = queue->changed_bits; + if (req->clear) + queue->changed_bits = 0; + } + else + reply->wake_bits = reply->changed_bits = 0; +} + +/* send a message to a thread queue */ +DECL_HANDLER(send_message) +{ + struct message *msg; + struct msg_queue *send_queue = get_current_queue(); + struct msg_queue *recv_queue = NULL; + struct w32thread *thread = NULL; + + if (!(thread = get_thread_from_id( req->id ))) + return; + + if (!(recv_queue = thread->queue)) { + set_error( STATUS_INVALID_PARAMETER ); + release_object( thread ); + return; + } + if ((req->flags & SEND_MSG_ABORT_IF_HUNG) && is_queue_hung(recv_queue)) { + set_error( STATUS_TIMEOUT ); + release_object( thread ); + return; + } + + if ((msg = mem_alloc( sizeof(*msg) ))) { + msg->type = req->type; + msg->win = get_user_full_handle( req->win ); + msg->msg = req->msg; + msg->wparam = req->wparam; + msg->lparam = req->lparam; + msg->time = get_tick_count(); + msg->x = 0; + msg->y = 0; + msg->info = 0; + msg->result = NULL; + msg->data = NULL; + msg->data_size = get_req_data_size(); + + if (msg->data_size && !(msg->data = memdup( get_req_data(), msg->data_size ))) { + free( msg ); + release_object( thread ); + return; + } + + switch(msg->type) { + case MSG_OTHER_PROCESS: + case MSG_ASCII: + case MSG_UNICODE: + case MSG_CALLBACK: + if (!(msg->result = alloc_message_result( send_queue, recv_queue, msg, req->timeout ))) { + free_message( msg ); + break; + } + /* fall through */ + case MSG_NOTIFY: + my_list_add_tail( &recv_queue->msg_list[SEND_MESSAGE], &msg->entry ); + set_queue_bits( recv_queue, QS_SENDMESSAGE ); + break; + case MSG_POSTED: + my_list_add_tail( &recv_queue->msg_list[POST_MESSAGE], &msg->entry ); + set_queue_bits( recv_queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE ); + break; + case MSG_HARDWARE: /* should use send_hardware_message instead */ + case MSG_CALLBACK_RESULT: /* cannot send this one */ + default: + set_error( STATUS_INVALID_PARAMETER ); + free( msg ); + break; + } + } + release_object( thread ); +} + +/* send a hardware message to a thread queue */ +DECL_HANDLER(send_hardware_message) +{ + struct message *msg; + struct msg_queue *recv_queue = NULL; + struct w32thread *thread = NULL; + + if (req->id) { + if (!(thread = get_thread_from_id( req->id ))) + return; + } + + if (thread && !(recv_queue = thread->queue)) { + set_error( STATUS_INVALID_PARAMETER ); + release_object( thread ); + return; + } + + if ((msg = mem_alloc( sizeof(*msg) ))) { + msg->type = MSG_HARDWARE; + msg->win = get_user_full_handle( req->win ); + msg->msg = req->msg; + msg->wparam = req->wparam; + msg->lparam = req->lparam; + msg->time = req->time; + msg->x = req->x; + msg->y = req->y; + msg->info = req->info; + msg->result = NULL; + msg->data = NULL; + msg->data_size = 0; + queue_hardware_message( recv_queue, msg ); + } + if (thread) + release_object( thread ); +} + +/* post a quit message to the current queue */ +DECL_HANDLER(post_quit_message) +{ + struct msg_queue *queue = get_current_queue(); + + if (!queue) + return; + + queue->quit_message = 1; + queue->exit_code = req->exit_code; + set_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE ); +} + +/* get a message from the current queue */ +DECL_HANDLER(get_message) +{ + struct timer *timer; + struct list_head *ptr; + struct msg_queue *queue = get_current_queue(); + user_handle_t get_win = get_user_full_handle( req->get_win ); + unsigned int filter = req->flags >> 16; + + reply->active_hooks = get_active_hooks(); + + if (!queue) + return; + queue->last_get_msg = current_time; + if (!filter) + filter = QS_ALLINPUT; + + /* first check for sent messages */ + if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] ))) { + struct message *msg = LIST_ENTRY( ptr, struct message, entry ); + receive_message( queue, msg, reply ); + return; + } + + /* clear changed bits so we can wait on them if we don't find a message */ + if (filter & QS_POSTMESSAGE) { + queue->changed_bits &= ~(QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER); + if (req->get_first == 0 && req->get_last == ~0U) + queue->changed_bits &= ~QS_ALLPOSTMESSAGE; + } + if (filter & QS_INPUT) + queue->changed_bits &= ~QS_INPUT; + if (filter & QS_PAINT) + queue->changed_bits &= ~QS_PAINT; + + /* then check for posted messages */ + if ((filter & QS_POSTMESSAGE) && + get_posted_message( queue, get_win, req->get_first, req->get_last, req->flags, reply )) + return; + + /* only check for quit messages if not posted messages pending. + * note: the quit message isn't filtered */ + if (get_quit_message( queue, req->flags, reply )) + return; + + /* then check for any raw hardware message */ + if ((filter & QS_INPUT) && + filter_contains_hw_range( req->get_first, req->get_last ) && + get_hardware_message( current_thread, req->hw_id, get_win, req->get_first, req->get_last, reply )); + return; + + /* now check for WM_PAINT */ + if ((filter & QS_PAINT) && + queue->paint_count && + check_msg_filter( WM_PAINT, req->get_first, req->get_last ) && + (reply->win = find_window_to_repaint( get_win, current_thread ))) { + reply->type = MSG_POSTED; + reply->msg = WM_PAINT; + reply->wparam = 0; + reply->lparam = 0; + reply->x = 0; + reply->y = 0; + reply->time = get_tick_count(); + reply->info = 0; + return; + } + + /* now check for timer */ + if ((filter & QS_TIMER) && + (timer = find_expired_timer( queue, get_win, req->get_first, + req->get_last, (req->flags & PM_REMOVE) ))) { + reply->type = MSG_POSTED; + reply->win = timer->win; + reply->msg = timer->msg; + reply->wparam = timer->id; + reply->lparam = timer->lparam; + reply->x = 0; + reply->y = 0; + reply->time = get_tick_count(); + reply->info = 0; + return; + } + + queue->wake_mask = req->wake_mask; + queue->changed_mask = req->changed_mask; + set_error( STATUS_PENDING ); /* FIXME */ +} + + +/* reply to a sent message */ +DECL_HANDLER(reply_message) +{ + if (!get_current_queue()/*current->queue*/) + set_error( STATUS_ACCESS_DENIED ); /* D.M. TBD */ + else if (current_thread->queue->recv_result) /* D.M. TBD */ + reply_message( current_thread->queue, req->result, 0, req->remove, + get_req_data(), get_req_data_size() ); /* D.M. TBD */ +} + + +/* accept the current hardware message */ +DECL_HANDLER(accept_hardware_message) +{ + if (get_current_queue() /*current->queue*/) /* D.M. TBD */ + release_hardware_message( current_thread->queue, req->hw_id, req->remove, req->new_win ); /* D.M. TBD */ + else + set_error( STATUS_ACCESS_DENIED ); +} + + +/* retrieve the reply for the last message sent */ +DECL_HANDLER(get_message_reply) +{ + struct message_result *result; + struct list_head *entry; + struct msg_queue *queue = get_current_queue()/*current->queue*/; /* D.M. TBD */ + + if (queue) { + set_error( STATUS_PENDING ); + reply->result = 0; + + if (!(entry = list_head( &queue->send_result ))) + return; /* no reply ready */ + + result = LIST_ENTRY( entry, struct message_result, sender_entry ); + if (result->replied || req->cancel) { + if (result->replied) { + reply->result = result->result; + set_error( result->error ); + if (result->data) { + data_size_t data_len = min( result->data_size, get_reply_max_size() ); + set_reply_data_ptr( result->data, data_len ); + result->data = NULL; + result->data_size = 0; + } + } + remove_result_from_sender( result ); + + entry = list_head( &queue->send_result ); + if (!entry) + clear_queue_bits( queue, QS_SMRESULT ); + else { + result = LIST_ENTRY( entry, struct message_result, sender_entry ); + if (!result->replied) clear_queue_bits( queue, QS_SMRESULT ); + } + } + } + else + set_error( STATUS_ACCESS_DENIED ); +} + + +/* set a window timer */ +DECL_HANDLER(set_win_timer) +{ + struct timer *timer; + struct msg_queue *queue; + struct w32thread *thread = NULL; + user_handle_t win = 0; + unsigned long id = req->id; + + if (req->win) { + if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win ))) { + set_error( STATUS_INVALID_HANDLE ); + return; + } + if (thread->process != /*current->process*/ (void*)current->ethread) { + release_object( thread ); + set_error( STATUS_ACCESS_DENIED ); + return; + } + queue = thread->queue; + /* remove it if it existed already */ + if ((timer = find_timer( queue, win, req->msg, id ))) free_timer( queue, timer ); + } + else { + queue = get_current_queue(); + /* look for a timer with this id */ + if (id && (timer = find_timer( queue, NULL, req->msg, id ))) { + /* free and reuse id */ + free_timer( queue, timer ); + } + else { + /* find a free id for it */ + do { + id = queue->next_timer_id; + if (--queue->next_timer_id <= 0x100) + queue->next_timer_id = 0x7fff; + } + while (find_timer( queue, 0, req->msg, id )); + } + } + + if ((timer = set_timer( queue, req->rate ))) { + timer->win = win; + timer->msg = req->msg; + timer->id = id; + timer->lparam = req->lparam; + reply->id = id; + } + if (thread) + release_object( thread ); +} + +/* kill a window timer */ +DECL_HANDLER(kill_win_timer) +{ + struct timer *timer; + struct w32thread *thread; + user_handle_t win = 0; + + if (req->win) { + if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win ))) { + set_error( STATUS_INVALID_HANDLE ); + return; + } + if (thread->process != get_current_w32process()) { + release_object( thread ); + set_error( STATUS_ACCESS_DENIED ); + return; + } + } + else thread = (struct w32thread *)grab_object( current ); + + if (thread->queue && (timer = find_timer( thread->queue, win, req->msg, req->id ))) + free_timer( thread->queue, timer ); + else + set_error( STATUS_INVALID_PARAMETER ); + + release_object( thread ); +} + + +/* attach (or detach) thread inputs */ +DECL_HANDLER(attach_thread_input) +{ + struct w32thread *thread_from = get_thread_from_id( req->tid_from ); + struct w32thread *thread_to = get_thread_from_id( req->tid_to ); + + if (!thread_from || !thread_to) { + if (thread_from) + release_object( thread_from ); + if (thread_to) + release_object( thread_to ); + return; + } + if (thread_from != thread_to) { + if (req->attach) + attach_thread_input( thread_from, thread_to ); + else { + if (thread_from->queue && thread_to->queue && + thread_from->queue->input == thread_to->queue->input) + detach_thread_input( thread_from ); + else + set_error( STATUS_ACCESS_DENIED ); + } + } + else + set_error( STATUS_ACCESS_DENIED ); + release_object( thread_from ); + release_object( thread_to ); +} + + +/* get thread input data */ +DECL_HANDLER(get_thread_input) +{ + struct w32thread *thread = NULL; + struct thread_input *input; + + if (req->tid) { + if (!(thread = get_thread_from_id( req->tid ))) + return; + input = thread->queue ? thread->queue->input : NULL; + } + else + input = foreground_input; /* get the foreground thread info */ + + if (input) { + reply->focus = input->focus; + reply->capture = input->capture; + reply->active = input->active; + reply->menu_owner = input->menu_owner; + reply->move_size = input->move_size; + reply->caret = input->caret; + reply->rect = input->caret_rect; + } + else { + reply->focus = 0; + reply->capture = 0; + reply->active = 0; + reply->menu_owner = 0; + reply->move_size = 0; + reply->caret = 0; + reply->rect.left = reply->rect.top = reply->rect.right = reply->rect.bottom = 0; + } + /* foreground window is active window of foreground thread */ + reply->foreground = foreground_input ? foreground_input->active : 0; + if (thread) + release_object( thread ); +} + +/* retrieve queue keyboard state for a given thread */ +DECL_HANDLER(get_key_state) +{ + struct w32thread *thread; + struct thread_input *input; + + if (!(thread = get_thread_from_id( req->tid ))) + return; + input = thread->queue ? thread->queue->input : NULL; + if (input) { + if (req->key >= 0) + reply->state = input->keystate[req->key & 0xff]; + set_reply_data( input->keystate, min( get_reply_max_size(), sizeof(input->keystate) )); + } + release_object( thread ); +} + + +/* set queue keyboard state for a given thread */ +DECL_HANDLER(set_key_state) +{ + struct w32thread *thread = NULL; + struct thread_input *input; + + if (!(thread = get_thread_from_id( req->tid ))) + return; + input = thread->queue ? thread->queue->input : NULL; + if (input) { + data_size_t size = min( sizeof(input->keystate), get_req_data_size() ); + if (size) + memcpy( input->keystate, get_req_data(), size ); + } + release_object( thread ); +} + + +/* set the system foreground window */ +DECL_HANDLER(set_foreground_window) +{ + struct w32thread *thread; + struct msg_queue *queue = get_current_queue(); + + reply->previous = foreground_input ? foreground_input->active : 0; + reply->send_msg_old = (reply->previous && foreground_input != queue->input); + reply->send_msg_new = FALSE; + + if (is_top_level_window( req->handle ) && + ((thread = get_window_thread( req->handle )))) { + foreground_input = thread->queue->input; + reply->send_msg_new = (foreground_input != queue->input); + release_object( thread ); + } + else + set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); +} + + +/* set the current thread focus window */ +DECL_HANDLER(set_focus_window) +{ + struct msg_queue *queue = get_current_queue(); + + reply->previous = 0; + if (queue && check_queue_input_window( queue, req->handle )) { + reply->previous = queue->input->focus; + queue->input->focus = get_user_full_handle( req->handle ); + } +} + + +/* set the current thread active window */ +DECL_HANDLER(set_active_window) +{ + struct msg_queue *queue = get_current_queue(); + + reply->previous = 0; + if (queue && check_queue_input_window( queue, req->handle )) { + if (!req->handle || make_window_active( req->handle )) { + reply->previous = queue->input->active; + queue->input->active = get_user_full_handle( req->handle ); + } + else + set_error( STATUS_INVALID_HANDLE ); + } +} + + +/* set the current thread capture window */ +DECL_HANDLER(set_capture_window) +{ + struct msg_queue *queue = get_current_queue(); + + reply->previous = reply->full_handle = 0; + if (queue && check_queue_input_window( queue, req->handle )) { + struct thread_input *input = queue->input; + + reply->previous = input->capture; + input->capture = get_user_full_handle( req->handle ); + input->menu_owner = (req->flags & CAPTURE_MENU) ? input->capture : 0; + input->move_size = (req->flags & CAPTURE_MOVESIZE) ? input->capture : 0; + reply->full_handle = input->capture; + } +} + + +/* Set the current thread caret window */ +DECL_HANDLER(set_caret_window) +{ + struct msg_queue *queue = get_current_queue(); + + reply->previous = 0; + if (queue && check_queue_input_window( queue, req->handle )) { + struct thread_input *input = queue->input; + + reply->previous = input->caret; + reply->old_rect = input->caret_rect; + reply->old_hide = input->caret_hide; + reply->old_state = input->caret_state; + + set_caret_window( input, get_user_full_handle(req->handle) ); + input->caret_rect.right = input->caret_rect.left + req->width; + input->caret_rect.bottom = input->caret_rect.top + req->height; + } +} + + +/* Set the current thread caret information */ +DECL_HANDLER(set_caret_info) +{ + struct msg_queue *queue = get_current_queue(); + struct thread_input *input; + + if (!queue) + return; + input = queue->input; + reply->full_handle = input->caret; + reply->old_rect = input->caret_rect; + reply->old_hide = input->caret_hide; + reply->old_state = input->caret_state; + + if (req->handle && get_user_full_handle(req->handle) != input->caret) { + set_error( STATUS_ACCESS_DENIED ); + return; + } + if (req->flags & SET_CARET_POS) { + input->caret_rect.right += req->x - input->caret_rect.left; + input->caret_rect.bottom += req->y - input->caret_rect.top; + input->caret_rect.left = req->x; + input->caret_rect.top = req->y; + } + if (req->flags & SET_CARET_HIDE) { + input->caret_hide += req->hide; + if (input->caret_hide < 0) + input->caret_hide = 0; + } + if (req->flags & SET_CARET_STATE) { + if (req->state == -1) + input->caret_state = !input->caret_state; + else + input->caret_state = !!req->state; + } +} + + +DECL_HANDLER(get_last_input_time) +{ + reply->time = last_input_time; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/msg/region.c b/unifiedkernel/msg/region.c new file mode 100644 index 0000000..3835dfb --- /dev/null +++ b/unifiedkernel/msg/region.c @@ -0,0 +1,811 @@ +/* + * region.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * region.c: + * Refered to Wine code + */ +#include +#include +#include +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + + +#ifdef CONFIG_UNIFIED_KERNEL +struct region +{ + int size; + int num_rects; + rectangle_t *rects; + rectangle_t extents; +}; + + +#define RGN_DEFAULT_RECTS 2 + +#define EXTENTCHECK(r1, r2) \ + ((r1)->right > (r2)->left && \ + (r1)->left < (r2)->right && \ + (r1)->bottom > (r2)->top && \ + (r1)->top < (r2)->bottom) + +typedef int (*overlap_func_t)( struct region *reg, const rectangle_t *r1, const rectangle_t *r1End, + const rectangle_t *r2, const rectangle_t *r2End, int top, int bottom ); +typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r, + const rectangle_t *rEnd, int top, int bottom ); + +static const rectangle_t empty_rect; /* all-zero rectangle for empty regions */ + +/* add a rectangle to a region */ +static inline rectangle_t *add_rect( struct region *reg ) +{ + if (reg->num_rects >= reg->size - 1) { + rectangle_t *new_rect = realloc( reg->rects, 2 * sizeof(rectangle_t) * reg->size, sizeof(rectangle_t) * reg->size ); + if (!new_rect) { + set_error( STATUS_NO_MEMORY ); + return NULL; + } + reg->rects = new_rect; + reg->size *= 2; + } + return reg->rects + reg->num_rects++; +} + +/* make sure all the rectangles are valid and that the region is properly y-x-banded */ +static inline int validate_rectangles( const rectangle_t *rects, unsigned int nb_rects ) +{ + const rectangle_t *ptr, *end; + + for (ptr = rects, end = rects + nb_rects; ptr < end; ptr++) { + if (ptr->left >= ptr->right || ptr->top >= ptr->bottom) + return 0; /* empty rectangle */ + if (ptr == end - 1) + break; + if (ptr[0].top == ptr[1].top) { /* same band */ + if (ptr[0].bottom != ptr[1].bottom) + return 0; /* not same y extent */ + if (ptr[0].right >= ptr[1].left) + return 0; /* not properly x ordered */ + } + else { /* new band */ + if (ptr[0].bottom > ptr[1].top) + return 0; /* not properly y ordered */ + } + } + return 1; +} + +/* attempt to merge the rects in the current band with those in the */ +/* previous one. Used only by region_op. */ +static int coalesce_region( struct region *pReg, int prevStart, int curStart ) +{ + int curNumRects; + rectangle_t *pRegEnd = &pReg->rects[pReg->num_rects]; + rectangle_t *pPrevRect = &pReg->rects[prevStart]; + rectangle_t *pCurRect = &pReg->rects[curStart]; + int prevNumRects = curStart - prevStart; + int bandtop = pCurRect->top; + + for (curNumRects = 0; + (pCurRect != pRegEnd) && (pCurRect->top == bandtop); + curNumRects++) { + pCurRect++; + } + + if (pCurRect != pRegEnd) { + pRegEnd--; + while (pRegEnd[-1].top == pRegEnd->top) + pRegEnd--; + curStart = pRegEnd - pReg->rects; + pRegEnd = pReg->rects + pReg->num_rects; + } + + if ((curNumRects == prevNumRects) && (curNumRects != 0)) { + pCurRect -= curNumRects; + if (pPrevRect->bottom == pCurRect->top) { + do { + if ((pPrevRect->left != pCurRect->left) || + (pPrevRect->right != pCurRect->right)) + return curStart; + pPrevRect++; + pCurRect++; + prevNumRects -= 1; + } while (prevNumRects != 0); + + pReg->num_rects -= curNumRects; + pCurRect -= curNumRects; + pPrevRect -= curNumRects; + + do { + pPrevRect->bottom = pCurRect->bottom; + pPrevRect++; + pCurRect++; + curNumRects -= 1; + } while (curNumRects != 0); + + if (pCurRect == pRegEnd) + curStart = prevStart; + else + do { + *pPrevRect++ = *pCurRect++; + } while (pCurRect != pRegEnd); + + } + } + return curStart; +} + +/* apply an operation to two regions */ +/* check the GDI version of the code for explanations */ +static int region_op( struct region *newReg, const struct region *reg1, const struct region *reg2, + overlap_func_t overlap_func, + non_overlap_func_t non_overlap1_func, + non_overlap_func_t non_overlap2_func ) +{ + int ybot, ytop, top, bot, prevBand, curBand; + const rectangle_t *r1BandEnd, *r2BandEnd; + + const rectangle_t *r1 = reg1->rects; + const rectangle_t *r2 = reg2->rects; + const rectangle_t *r1End = r1 + reg1->num_rects; + const rectangle_t *r2End = r2 + reg2->num_rects; + + rectangle_t *new_rects, *old_rects = newReg->rects; + int new_size, ret = 0; + + new_size = max( reg1->num_rects, reg2->num_rects ) * 2; + if (!(new_rects = mem_alloc( new_size * sizeof(*newReg->rects) ))) + return 0; + + newReg->size = new_size; + newReg->rects = new_rects; + newReg->num_rects = 0; + + if (reg1->extents.top < reg2->extents.top) + ybot = reg1->extents.top; + else + ybot = reg2->extents.top; + + prevBand = 0; + + do { + curBand = newReg->num_rects; + + r1BandEnd = r1; + while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top)) + r1BandEnd++; + + r2BandEnd = r2; + while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top)) + r2BandEnd++; + + if (r1->top < r2->top) { + top = max(r1->top,ybot); + bot = min(r1->bottom,r2->top); + + if ((top != bot) && non_overlap1_func) { + if (!non_overlap1_func( newReg, r1, r1BandEnd, top, bot )) + goto done; + } + + ytop = r2->top; + } + else if (r2->top < r1->top) { + top = max(r2->top,ybot); + bot = min(r2->bottom,r1->top); + + if ((top != bot) && non_overlap2_func) { + if (!non_overlap2_func( newReg, r2, r2BandEnd, top, bot )) + goto done; + } + + ytop = r1->top; + } + else { + ytop = r1->top; + } + + if (newReg->num_rects != curBand) + prevBand = coalesce_region(newReg, prevBand, curBand); + + ybot = min(r1->bottom, r2->bottom); + curBand = newReg->num_rects; + if (ybot > ytop) { + if (!overlap_func( newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot )) + goto done; + } + + if (newReg->num_rects != curBand) + prevBand = coalesce_region(newReg, prevBand, curBand); + + if (r1->bottom == ybot) + r1 = r1BandEnd; + if (r2->bottom == ybot) + r2 = r2BandEnd; + } while ((r1 != r1End) && (r2 != r2End)); + + curBand = newReg->num_rects; + if (r1 != r1End) { + if (non_overlap1_func) { + do { + r1BandEnd = r1; + while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top)) + r1BandEnd++; + if (!non_overlap1_func( newReg, r1, r1BandEnd, max(r1->top,ybot), r1->bottom )) + goto done; + r1 = r1BandEnd; + } while (r1 != r1End); + } + } + else if ((r2 != r2End) && non_overlap2_func) { + do { + r2BandEnd = r2; + while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top)) + r2BandEnd++; + if (!non_overlap2_func( newReg, r2, r2BandEnd, max(r2->top,ybot), r2->bottom )) + goto done; + r2 = r2BandEnd; + } while (r2 != r2End); + } + + if (newReg->num_rects != curBand) + coalesce_region(newReg, prevBand, curBand); + + if ((newReg->num_rects < (newReg->size / 2)) && (newReg->size > 2)) { + new_size = max( newReg->num_rects, RGN_DEFAULT_RECTS ); + if ((new_rects = realloc( newReg->rects, sizeof(*newReg->rects) * new_size, sizeof(*newReg->rects) * newReg->size ))) { + newReg->rects = new_rects; + newReg->size = new_size; + } + } + ret = 1; +done: + free( old_rects ); + return ret; +} + +/* recalculate the extents of a region */ +static void set_region_extents( struct region *region ) +{ + rectangle_t *pRect, *pRectEnd; + + if (region->num_rects == 0) { + region->extents.left = 0; + region->extents.top = 0; + region->extents.right = 0; + region->extents.bottom = 0; + return; + } + + pRect = region->rects; + pRectEnd = &pRect[region->num_rects - 1]; + + region->extents.left = pRect->left; + region->extents.top = pRect->top; + region->extents.right = pRectEnd->right; + region->extents.bottom = pRectEnd->bottom; + + while (pRect <= pRectEnd) { + if (pRect->left < region->extents.left) + region->extents.left = pRect->left; + if (pRect->right > region->extents.right) + region->extents.right = pRect->right; + pRect++; + } +} + +/* handle an overlapping band for intersect_region */ +static int intersect_overlapping( struct region *pReg, + const rectangle_t *r1, const rectangle_t *r1End, + const rectangle_t *r2, const rectangle_t *r2End, + int top, int bottom ) + +{ + int left, right; + + while ((r1 != r1End) && (r2 != r2End)) { + left = max(r1->left, r2->left); + right = min(r1->right, r2->right); + + if (left < right) { + rectangle_t *rect = add_rect( pReg ); + if (!rect) + return 0; + rect->left = left; + rect->top = top; + rect->right = right; + rect->bottom = bottom; + } + + if (r1->right < r2->right) + r1++; + else if (r2->right < r1->right) + r2++; + else { + r1++; + r2++; + } + } + return 1; +} + +/* handle a non-overlapping band for subtract_region */ +static int subtract_non_overlapping( struct region *pReg, const rectangle_t *r, + const rectangle_t *rEnd, int top, int bottom ) +{ + while (r != rEnd) { + rectangle_t *rect = add_rect( pReg ); + if (!rect) + return 0; + rect->left = r->left; + rect->top = top; + rect->right = r->right; + rect->bottom = bottom; + r++; + } + return 1; +} + +/* handle an overlapping band for subtract_region */ +static int subtract_overlapping( struct region *pReg, + const rectangle_t *r1, const rectangle_t *r1End, + const rectangle_t *r2, const rectangle_t *r2End, + int top, int bottom ) +{ + int left = r1->left; + + while ((r1 != r1End) && (r2 != r2End)) { + if (r2->right <= left) + r2++; + else if (r2->left <= left) { + left = r2->right; + if (left >= r1->right) { + r1++; + if (r1 != r1End) + left = r1->left; + } + else + r2++; + } + else if (r2->left < r1->right) { + rectangle_t *rect = add_rect( pReg ); + if (!rect) + return 0; + rect->left = left; + rect->top = top; + rect->right = r2->left; + rect->bottom = bottom; + left = r2->right; + if (left >= r1->right) { + r1++; + if (r1 != r1End) + left = r1->left; + } + else + r2++; + } + else { + if (r1->right > left) { + rectangle_t *rect = add_rect( pReg ); + if (!rect) + return 0; + rect->left = left; + rect->top = top; + rect->right = r1->right; + rect->bottom = bottom; + } + r1++; + left = r1->left; + } + } + + while (r1 != r1End) { + rectangle_t *rect = add_rect( pReg ); + if (!rect) + return 0; + rect->left = left; + rect->top = top; + rect->right = r1->right; + rect->bottom = bottom; + r1++; + if (r1 != r1End) + left = r1->left; + } + return 1; +} + +/* handle a non-overlapping band for union_region */ +static int union_non_overlapping( struct region *pReg, const rectangle_t *r, + const rectangle_t *rEnd, int top, int bottom ) +{ + while (r != rEnd) { + rectangle_t *rect = add_rect( pReg ); + if (!rect) + return 0; + rect->left = r->left; + rect->top = top; + rect->right = r->right; + rect->bottom = bottom; + r++; + } + return 1; +} + +/* handle an overlapping band for union_region */ +static int union_overlapping( struct region *pReg, + const rectangle_t *r1, const rectangle_t *r1End, + const rectangle_t *r2, const rectangle_t *r2End, + int top, int bottom ) +{ +#define MERGERECT(r) \ + if ((pReg->num_rects != 0) && \ + (pReg->rects[pReg->num_rects-1].top == top) && \ + (pReg->rects[pReg->num_rects-1].bottom == bottom) && \ + (pReg->rects[pReg->num_rects-1].right >= r->left)) \ + { \ + if (pReg->rects[pReg->num_rects-1].right < r->right) \ + { \ + pReg->rects[pReg->num_rects-1].right = r->right; \ + } \ + } \ + else \ + { \ + rectangle_t *rect = add_rect( pReg ); \ + if (!rect) return 0; \ + rect->top = top; \ + rect->bottom = bottom; \ + rect->left = r->left; \ + rect->right = r->right; \ + } \ + r++; + + while ((r1 != r1End) && (r2 != r2End)) { + if (r1->left < r2->left) { + MERGERECT(r1); + } + else { + MERGERECT(r2); + } + } + + if (r1 != r1End) { + do { + MERGERECT(r1); + } while (r1 != r1End); + } + else while (r2 != r2End) { + MERGERECT(r2); + } + return 1; +#undef MERGERECT +} + + +/* create an empty region */ +struct region *create_empty_region(void) +{ + struct region *region; + + if (!(region = mem_alloc( sizeof(*region) ))) + return NULL; + if (!(region->rects = mem_alloc( RGN_DEFAULT_RECTS * sizeof(*region->rects) ))) { + free( region ); + return NULL; + } + region->size = RGN_DEFAULT_RECTS; + region->num_rects = 0; + region->extents.left = 0; + region->extents.top = 0; + region->extents.right = 0; + region->extents.bottom = 0; + return region; +} + +/* create a region from request data */ +struct region *create_region_from_req_data( const void *data, data_size_t size ) +{ + unsigned int alloc_rects; + struct region *region; + const rectangle_t *rects = data; + int nb_rects = size / sizeof(rectangle_t); + + /* special case: empty region can be specified by a single all-zero rectangle */ + if (nb_rects == 1 && !memcmp( rects, &empty_rect, sizeof(empty_rect) )) + nb_rects = 0; + + if (!validate_rectangles( rects, nb_rects )) { + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + } + + if (!(region = mem_alloc( sizeof(*region) ))) + return NULL; + + alloc_rects = max( nb_rects, RGN_DEFAULT_RECTS ); + if (!(region->rects = mem_alloc( alloc_rects * sizeof(*region->rects) ))) { + free( region ); + return NULL; + } + region->size = alloc_rects; + region->num_rects = nb_rects; + memcpy( region->rects, rects, nb_rects * sizeof(*rects) ); + set_region_extents( region ); + return region; +} + +/* free a region */ +void free_region( struct region *region ) +{ + free( region->rects ); + free( region ); +} + +/* set region to a simple rectangle */ +void set_region_rect( struct region *region, const rectangle_t *rect ) +{ + if (rect->left < rect->right && rect->top < rect->bottom) { + region->num_rects = 1; + region->rects[0] = region->extents = *rect; + } + else { + region->num_rects = 0; + region->extents.left = 0; + region->extents.top = 0; + region->extents.right = 0; + region->extents.bottom = 0; + } +} + +/* retrieve the region data for sending to the client */ +rectangle_t *get_region_data( const struct region *region, data_size_t max_size, data_size_t *total_size ) +{ + const rectangle_t *data = region->rects; + + if (!(*total_size = region->num_rects * sizeof(rectangle_t))) { + /* return a single empty rect for empty regions */ + *total_size = sizeof(empty_rect); + data = &empty_rect; + } + if (max_size >= *total_size) + return memdup( data, *total_size ); + set_error( STATUS_BUFFER_OVERFLOW ); + return NULL; +} + +/* retrieve the region data for sending to the client and free the region at the same time */ +rectangle_t *get_region_data_and_free( struct region *region, data_size_t max_size, data_size_t *total_size ) +{ + rectangle_t *ret = region->rects; + + if (!(*total_size = region->num_rects * sizeof(rectangle_t))) { + /* return a single empty rect for empty regions */ + *total_size = sizeof(empty_rect); + if (max_size >= sizeof(empty_rect)) { + ret = memdup( &empty_rect, sizeof(empty_rect) ); + free( region->rects ); + } + } + + if (max_size < *total_size) { + free( region->rects ); + set_error( STATUS_BUFFER_OVERFLOW ); + ret = NULL; + } + free( region ); + return ret; +} + +/* check if a given region is empty */ +int is_region_empty( const struct region *region ) +{ + return region->num_rects == 0; +} + + +/* get the extents rect of a region */ +void get_region_extents( const struct region *region, rectangle_t *rect ) +{ + *rect = region->extents; +} + +/* add an offset to a region */ +void offset_region( struct region *region, int x, int y ) +{ + rectangle_t *rect, *end; + + if (!region->num_rects) + return; + for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++) { + rect->left += x; + rect->right += x; + rect->top += y; + rect->bottom += y; + } + region->extents.left += x; + region->extents.right += x; + region->extents.top += y; + region->extents.bottom += y; +} + +/* make a copy of a region; returns dst or NULL on error */ +struct region *copy_region( struct region *dst, const struct region *src ) +{ + if (dst == src) + return dst; + + if (dst->size < src->num_rects) { + rectangle_t *rect = realloc( dst->rects, src->num_rects * sizeof(*rect) , dst->size * sizeof(*rect) ); + if (!rect) { + set_error( STATUS_NO_MEMORY ); + return NULL; + } + dst->rects = rect; + dst->size = src->num_rects; + } + dst->num_rects = src->num_rects; + dst->extents = src->extents; + memcpy( dst->rects, src->rects, src->num_rects * sizeof(*dst->rects) ); + return dst; +} + +/* compute the intersection of two regions into dst, which can be one of the source regions */ +struct region *intersect_region( struct region *dst, const struct region *src1, + const struct region *src2 ) +{ + if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents)) { + dst->num_rects = 0; + dst->extents.left = 0; + dst->extents.top = 0; + dst->extents.right = 0; + dst->extents.bottom = 0; + return dst; + } + if (!region_op( dst, src1, src2, intersect_overlapping, NULL, NULL )) + return NULL; + set_region_extents( dst ); + return dst; +} + +/* compute the subtraction of two regions into dst, which can be one of the source regions */ +struct region *subtract_region( struct region *dst, const struct region *src1, + const struct region *src2 ) +{ + if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents)) + return copy_region( dst, src1 ); + + if (!region_op( dst, src1, src2, subtract_overlapping, + subtract_non_overlapping, NULL )) + return NULL; + set_region_extents( dst ); + return dst; +} + +/* compute the union of two regions into dst, which can be one of the source regions */ +struct region *union_region( struct region *dst, const struct region *src1, + const struct region *src2 ) +{ + if (src1 == src2) + return copy_region( dst, src1 ); + if (!src1->num_rects) + return copy_region( dst, src2 ); + if (!src2->num_rects) + return copy_region( dst, src1 ); + + if ((src1->num_rects == 1) && + (src1->extents.left <= src2->extents.left) && + (src1->extents.top <= src2->extents.top) && + (src1->extents.right >= src2->extents.right) && + (src1->extents.bottom >= src2->extents.bottom)) + return copy_region( dst, src1 ); + + if ((src2->num_rects == 1) && + (src2->extents.left <= src1->extents.left) && + (src2->extents.top <= src1->extents.top) && + (src2->extents.right >= src1->extents.right) && + (src2->extents.bottom >= src1->extents.bottom)) + return copy_region( dst, src2 ); + + if (!region_op( dst, src1, src2, union_overlapping, + union_non_overlapping, union_non_overlapping )) + return NULL; + + dst->extents.left = min(src1->extents.left, src2->extents.left); + dst->extents.top = min(src1->extents.top, src2->extents.top); + dst->extents.right = max(src1->extents.right, src2->extents.right); + dst->extents.bottom = max(src1->extents.bottom, src2->extents.bottom); + return dst; +} + +/* compute the exclusive or of two regions into dst, which can be one of the source regions */ +struct region *xor_region( struct region *dst, const struct region *src1, + const struct region *src2 ) +{ + struct region *tmp = create_empty_region(); + + if (!tmp) + return NULL; + + if (!subtract_region( tmp, src1, src2 ) || + !subtract_region( dst, src2, src1 ) || + !union_region( dst, dst, tmp )) + dst = NULL; + + free_region( tmp ); + return dst; +} + +/* check if the given point is inside the region */ +int point_in_region( struct region *region, int x, int y ) +{ + const rectangle_t *ptr, *end; + + for (ptr = region->rects, end = region->rects + region->num_rects; ptr < end; ptr++) { + if (ptr->top > y) + return 0; + if (ptr->bottom <= y) + continue; + /* now we are in the correct band */ + if (ptr->left > x) + return 0; + if (ptr->right <= x) + continue; + return 1; + } + return 0; +} + +/* check if the given rectangle is (at least partially) inside the region */ +int rect_in_region( struct region *region, const rectangle_t *rect ) +{ + const rectangle_t *ptr, *end; + + for (ptr = region->rects, end = region->rects + region->num_rects; ptr < end; ptr++) { + if (ptr->top >= rect->bottom) + return 0; + if (ptr->bottom <= rect->top) + continue; + if (ptr->left >= rect->right) + continue; + if (ptr->right <= rect->left) + continue; + return 1; + } + return 0; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/msg/user.c b/unifiedkernel/msg/user.c new file mode 100644 index 0000000..faebf65 --- /dev/null +++ b/unifiedkernel/msg/user.c @@ -0,0 +1,194 @@ +/* + * user.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * user.c: + * Refered to Wine code + */ +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" + +#ifdef CONFIG_UNIFIED_KERNEL +struct user_handle +{ + void *ptr; /* pointer to object */ + unsigned short type; /* object type (0 if free) */ + unsigned short generation; /* generation counter */ +}; + +static struct user_handle *handles; +static struct user_handle *freelist; +static int nb_handles; +static int allocated_handles; + +static struct user_handle *handle_to_entry( user_handle_t handle ) +{ + unsigned short generation; + int index = (((unsigned long)handle & 0xffff) - FIRST_USER_HANDLE) >> 1; + if (index < 0 || index >= nb_handles) + return NULL; + if (!handles[index].type) + return NULL; + generation = (unsigned long)handle >> 16; + if (generation == handles[index].generation || !generation || generation == 0xffff) + return &handles[index]; + return NULL; +} + +static inline user_handle_t entry_to_handle( struct user_handle *ptr ) +{ + int index = ptr - handles; + return (user_handle_t)((((unsigned long)index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16)); +} + +static inline struct user_handle *alloc_user_entry(void) +{ + struct user_handle *handle; + + if (freelist) { + handle = freelist; + freelist = handle->ptr; + return handle; + } + if (nb_handles >= allocated_handles) { /* need to grow the array */ + struct user_handle *new_handles; + /* grow array by 50% (but at minimum 32 entries) */ + int growth = max( 32, allocated_handles / 2 ); + int new_size = min( allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 ); + if (new_size <= allocated_handles) + return NULL; + if (!(new_handles = realloc( handles, new_size * sizeof(*handles), allocated_handles * sizeof(*handles) ))) + return NULL; + handles = new_handles; + allocated_handles = new_size; + } + handle = &handles[nb_handles++]; + handle->generation = 0; + return handle; +} + +static inline void *free_user_entry( struct user_handle *ptr ) +{ + void *ret; + ret = ptr->ptr; + ptr->ptr = freelist; + ptr->type = 0; + freelist = ptr; + return ret; +} + +/* allocate a user handle for a given object */ +user_handle_t alloc_user_handle( void *ptr, enum user_object type ) +{ + struct user_handle *entry = alloc_user_entry(); + if (!entry) + return 0; + entry->ptr = ptr; + entry->type = type; + if (++entry->generation >= 0xffff) + entry->generation = 1; + return entry_to_handle( entry ); +} + +/* return a pointer to a user object from its handle */ +void *get_user_object( user_handle_t handle, enum user_object type ) +{ + struct user_handle *entry; + + if (!(entry = handle_to_entry( handle )) || entry->type != type) + return NULL; + return entry->ptr; +} + +/* get the full handle for a possibly truncated handle */ +user_handle_t get_user_full_handle( user_handle_t handle ) +{ + struct user_handle *entry; + + if ((unsigned long)handle >> 16) + return handle; + if (!(entry = handle_to_entry( handle ))) + return handle; + return entry_to_handle( entry ); +} + +/* same as get_user_object plus set the handle to the full 32-bit value */ +void *get_user_object_handle( user_handle_t *handle, enum user_object type ) +{ + struct user_handle *entry; + + if (!(entry = handle_to_entry( *handle )) || entry->type != type) + return NULL; + *handle = entry_to_handle( entry ); + return entry->ptr; +} + +/* free a user handle and return a pointer to the object */ +void *free_user_handle( user_handle_t handle ) +{ + struct user_handle *entry; + + if (!(entry = handle_to_entry( handle ))) { + set_error( STATUS_INVALID_HANDLE ); + return NULL; + } + return free_user_entry( entry ); +} + +/* return the next user handle after 'handle' that is of a given type */ +void *next_user_handle( user_handle_t *handle, enum user_object type ) +{ + struct user_handle *entry; + + if (!*handle) + entry = handles; + else { + int index = (((unsigned long)*handle & 0xffff) - FIRST_USER_HANDLE) >> 1; + if (index < 0 || index >= nb_handles) + return NULL; + entry = handles + index + 1; /* start from the next one */ + } + while (entry < handles + nb_handles) { + if (!type || entry->type == type) { + *handle = entry_to_handle( entry ); + return entry->ptr; + } + entry++; + } + return NULL; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/msg/window.c b/unifiedkernel/msg/window.c new file mode 100644 index 0000000..7541ee9 --- /dev/null +++ b/unifiedkernel/msg/window.c @@ -0,0 +1,2677 @@ +/* + * window.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * window.c: + * Refered to Wine code + */ +#include +#include +#include + +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +extern void *get_user_object( user_handle_t handle, enum user_object type ); + +/* a window property */ +struct property +{ + unsigned short type; /* property type (see below) */ + atom_t atom; /* property atom */ + obj_handle_t handle; /* property handle (user-defined storage) */ +}; + +enum property_type +{ + PROP_TYPE_FREE, /* free entry */ + PROP_TYPE_STRING, /* atom that was originally a string */ + PROP_TYPE_ATOM /* plain atom */ +}; + + +struct window +{ + struct window *parent; /* parent window */ + user_handle_t owner; /* owner of this window */ + struct list_head children; /* list of children in Z-order */ + struct list_head unlinked; /* list of children not linked in the Z-order list */ + struct list_head entry; /* entry in parent's children list */ + user_handle_t handle; /* full handle for this window */ + struct w32thread *thread; /* thread owning the window */ + struct desktop *desktop; /* desktop that the window belongs to */ + struct window_class *class; /* window class */ + atom_t atom; /* class atom */ + user_handle_t last_active; /* last active popup */ + rectangle_t window_rect; /* window rectangle (relative to parent client area) */ + rectangle_t visible_rect; /* visible part of window rect (relative to parent client area) */ + rectangle_t client_rect; /* client rectangle (relative to parent client area) */ + struct region *win_region; /* region for shaped windows (relative to window rect) */ + struct region *update_region; /* update region (relative to window rect) */ + unsigned int style; /* window style */ + unsigned int ex_style; /* window extended style */ + unsigned int id; /* window id */ + void* instance; /* creator instance */ + unsigned int is_unicode : 1; /* ANSI or unicode */ + unsigned int is_linked : 1; /* is it linked into the parent z-order list? */ + unsigned long user_data; /* user-specific data */ + WCHAR *text; /* window caption text */ + unsigned int paint_flags; /* various painting flags */ + int prop_inuse; /* number of in-use window properties */ + int prop_alloc; /* number of allocated window properties */ + struct property *properties; /* window properties array */ + int nb_extra_bytes; /* number of extra bytes */ + char extra_bytes[1]; /* extra bytes storage */ +}; + +#define PAINT_INTERNAL 0x01 /* internal WM_PAINT pending */ +#define PAINT_ERASE 0x02 /* needs WM_ERASEBKGND */ +#define PAINT_NONCLIENT 0x04 /* needs WM_NCPAINT */ +#define PAINT_DELAYED_ERASE 0x08 /* still needs erase after WM_ERASEBKGND */ + +/* growable array of user handles */ +struct user_handle_array +{ + user_handle_t *handles; + int count; + int total; +}; + +/* global window pointers */ +static struct window *shell_window; +static struct window *shell_listview; +static struct window *progman_window; +static struct window *taskman_window; + +/* magic HWND_TOP etc. pointers */ +#define WINPTR_TOP ((struct window *)1L) +#define WINPTR_BOTTOM ((struct window *)2L) +#define WINPTR_TOPMOST ((struct window *)3L) +#define WINPTR_NOTOPMOST ((struct window *)4L) + +/* retrieve a pointer to a window from its handle */ +static inline struct window *get_window( user_handle_t handle ) +{ + struct window *ret = get_user_object( handle, USER_WINDOW ); + if (!ret) + set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); + return ret; +} + +/* check if window is the desktop */ +static inline int is_desktop_window( const struct window *win ) +{ + return !win->parent; /* only desktop windows have no parent */ +} + +/* get next window in Z-order list */ +static inline struct window *get_next_window( struct window *win ) +{ + struct list_head *ptr = list_next( &win->parent->children, &win->entry ); + return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL; +} + +/* get previous window in Z-order list */ +static inline struct window *get_prev_window( struct window *win ) +{ + struct list_head *ptr = list_prev( &win->parent->children, &win->entry ); + return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL; +} + +/* get first child in Z-order list */ +static inline struct window *get_first_child( struct window *win ) +{ + struct list_head *ptr = list_head( &win->children ); + return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL; +} + +/* get last child in Z-order list */ +static inline struct window *get_last_child( struct window *win ) +{ + struct list_head *ptr = list_tail( &win->children ); + return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL; +} + +#define WS_EX_TOPMOST 0x00000008L + +/* link a window at the right place in the siblings list */ +static void link_window( struct window *win, struct window *previous ) +{ + if (previous == WINPTR_NOTOPMOST) { + if (!(win->ex_style & WS_EX_TOPMOST) && win->is_linked) + return; /* nothing to do */ + win->ex_style &= ~WS_EX_TOPMOST; + previous = WINPTR_TOP; /* fallback to the HWND_TOP case */ + } + + list_remove( &win->entry ); /* unlink it from the previous location */ + + if (previous == WINPTR_BOTTOM) { + my_list_add_tail( &win->parent->children, &win->entry ); + win->ex_style &= ~WS_EX_TOPMOST; + } + else if (previous == WINPTR_TOPMOST) { + list_add_head( &win->parent->children, &win->entry ); + win->ex_style |= WS_EX_TOPMOST; + } + else if (previous == WINPTR_TOP) { + struct list_head *entry = win->parent->children.next; + if (!(win->ex_style & WS_EX_TOPMOST)) { /* put it above the first non-topmost window */ + while (entry != &win->parent->children && + LIST_ENTRY( entry, struct window, entry )->ex_style & WS_EX_TOPMOST) + entry = entry->next; + } + list_add_before( entry, &win->entry ); + } + else { + list_add_after( &previous->entry, &win->entry ); + if (!(previous->ex_style & WS_EX_TOPMOST)) + win->ex_style &= ~WS_EX_TOPMOST; + else { + struct window *next = get_next_window( win ); + if (next && (next->ex_style & WS_EX_TOPMOST)) + win->ex_style |= WS_EX_TOPMOST; + } + } + + win->is_linked = 1; +} + +/* change the parent of a window (or unlink the window if the new parent is NULL) */ +static int set_parent_window( struct window *win, struct window *parent ) +{ + struct window *ptr; + + /* make sure parent is not a child of window */ + for (ptr = parent; ptr; ptr = ptr->parent) { + if (ptr == win) { + set_error( STATUS_INVALID_PARAMETER ); + return 0; + } + } + + if (parent) { + win->parent = parent; + link_window( win, WINPTR_TOP ); + + /* if parent belongs to a different thread and the window isn't */ + /* top-level, attach the two threads */ + if (parent->thread && parent->thread != win->thread && !is_desktop_window(parent)) + attach_thread_input( win->thread, parent->thread ); + } + else { /* move it to parent unlinked list */ + list_remove( &win->entry ); /* unlink it from the previous location */ + list_add_head( &win->parent->unlinked, &win->entry ); + win->is_linked = 0; + } + return 1; +} + +/* append a user handle to a handle array */ +static int add_handle_to_array( struct user_handle_array *array, user_handle_t handle ) +{ + if (array->count >= array->total) { + int new_total = max( array->total * 2, 32 ); + user_handle_t *new_array = realloc( array->handles, new_total * sizeof(*new_array), array->total * sizeof(*new_array) ); + if (!new_array) { + free( array->handles ); + set_error( STATUS_NO_MEMORY ); + return 0; + } + array->handles = new_array; + array->total = new_total; + } + array->handles[array->count++] = handle; + return 1; +} + +/* set a window property */ +static void set_property( struct window *win, atom_t atom, obj_handle_t handle, enum property_type type ) +{ + int i, free = -1; + struct property *new_props; + + /* check if it exists already */ + for (i = 0; i < win->prop_inuse; i++) { + if (win->properties[i].type == PROP_TYPE_FREE) { + free = i; + continue; + } + if (win->properties[i].atom == atom) { + win->properties[i].type = type; + win->properties[i].handle = handle; + return; + } + } + + /* need to add an entry */ + if (!grab_global_atom( NULL, atom )) + return; + if (free == -1) { + /* no free entry */ + if (win->prop_inuse >= win->prop_alloc) { + /* need to grow the array */ + if (!(new_props = realloc( win->properties, + sizeof(*new_props) * (win->prop_alloc + 16) , sizeof(*new_props) * win->prop_alloc))) { + set_error( STATUS_NO_MEMORY ); + release_global_atom( NULL, atom ); + return; + } + win->prop_alloc += 16; + win->properties = new_props; + } + free = win->prop_inuse++; + } + win->properties[free].atom = atom; + win->properties[free].type = type; + win->properties[free].handle = handle; +} + +/* remove a window property */ +static obj_handle_t remove_property( struct window *win, atom_t atom ) +{ + int i; + + for (i = 0; i < win->prop_inuse; i++) { + if (win->properties[i].type == PROP_TYPE_FREE) + continue; + if (win->properties[i].atom == atom) { + release_global_atom( NULL, atom ); + win->properties[i].type = PROP_TYPE_FREE; + return win->properties[i].handle; + } + } + /* FIXME: last error? */ + return 0; +} + +/* find a window property */ +static obj_handle_t get_property( struct window *win, atom_t atom ) +{ + int i; + + for (i = 0; i < win->prop_inuse; i++) { + if (win->properties[i].type == PROP_TYPE_FREE) + continue; + if (win->properties[i].atom == atom) + return win->properties[i].handle; + } + /* FIXME: last error? */ + return 0; +} + +/* destroy all properties of a window */ +static inline void destroy_properties( struct window *win ) +{ + int i; + + if (!win->properties) + return; + for (i = 0; i < win->prop_inuse; i++) { + if (win->properties[i].type == PROP_TYPE_FREE) + continue; + release_global_atom( NULL, win->properties[i].atom ); + } + free( win->properties ); +} + +/* detach a window from its owner thread but keep the window around */ +static void detach_window_thread( struct window *win ) +{ + struct w32thread *thread = win->thread; + + if (!thread) + return; + if (thread->queue) { + if (win->update_region) + inc_queue_paint_count( thread, -1 ); + if (win->paint_flags & PAINT_INTERNAL) + inc_queue_paint_count( thread, -1 ); + queue_cleanup_window( thread, win->handle ); + } +#if 0 + assert( thread->desktop_users > 0 ); +#endif + thread->desktop_users--; + release_class( win->class ); + win->class = NULL; + + /* don't hold a reference to the desktop so that the desktop window can be */ + /* destroyed when the desktop ref count reaches zero */ + release_object( win->desktop ); + win->thread = NULL; +} + +/* destroy a window */ +void destroy_window( struct window *win ) +{ + /* destroy all children */ + while (!my_list_empty(&win->children)) + destroy_window( LIST_ENTRY( list_head(&win->children), struct window, entry )); + while (!my_list_empty(&win->unlinked)) + destroy_window( LIST_ENTRY( list_head(&win->unlinked), struct window, entry )); + + /* reset global window pointers, if the corresponding window is destroyed */ + if (win == shell_window) + shell_window = NULL; + if (win == shell_listview) + shell_listview = NULL; + if (win == progman_window) + progman_window = NULL; + if (win == taskman_window) + taskman_window = NULL; + free_user_handle( win->handle ); + destroy_properties( win ); + list_remove( &win->entry ); + if (is_desktop_window(win)) { +#if 0 + assert( win->desktop->top_window == win ); +#endif + win->desktop->top_window = NULL; + } + detach_window_thread( win ); + if (win->win_region) + free_region( win->win_region ); + if (win->update_region) + free_region( win->update_region ); + if (win->class) + release_class( win->class ); + free( win->text ); + memset( win, 0x55, sizeof(*win) + win->nb_extra_bytes - 1 ); + free( win ); +} + +/* get the process owning the top window of a given desktop */ +struct w32process *get_top_window_owner( struct desktop *desktop ) +{ + struct window *win = desktop->top_window; + if (!win || !win->thread) + return NULL; + return win->thread->process; +} + +/* attempt to close the desktop window when the last process using it is gone */ +void close_desktop_window( struct desktop *desktop ) +{ + struct window *win = desktop->top_window; + if (win && win->thread) + post_message( win->handle, WM_CLOSE, 0, 0 ); +} + +extern struct msg_queue *get_current_queue(void); + +/* create a new window structure (note: the window is not linked in the window tree) */ +static struct window *create_window( struct window *parent, struct window *owner, + atom_t atom, void *instance ) +{ + static const rectangle_t empty_rect; + int extra_bytes; + struct window *win; + struct desktop *desktop; + struct window_class *class; + + if (!(desktop = get_thread_desktop( current_thread, DESKTOP_CREATEWINDOW ))) + return NULL; + + if (!(class = grab_class( get_current_w32process(), atom, instance, &extra_bytes ))) { + release_object( desktop ); + return NULL; + } + + if (!(win = mem_alloc( sizeof(*win) + extra_bytes - 1 ))) + goto failed; + if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) + goto failed; + + win->parent = parent; + win->owner = owner ? owner->handle : 0; + win->thread = current_thread; + win->desktop = desktop; + win->class = class; + win->atom = atom; + win->last_active = win->handle; + win->win_region = NULL; + win->update_region = NULL; + win->style = 0; + win->ex_style = 0; + win->id = 0; + win->instance = NULL; + win->is_unicode = 1; + win->is_linked = 0; + win->user_data = 0; + win->text = NULL; + win->paint_flags = 0; + win->prop_inuse = 0; + win->prop_alloc = 0; + win->properties = NULL; + win->nb_extra_bytes = extra_bytes; + win->window_rect = win->visible_rect = win->client_rect = empty_rect; + memset( win->extra_bytes, 0, extra_bytes ); + my_list_init( &win->children ); + my_list_init( &win->unlinked ); + + /* parent must be on the same desktop */ + if (parent && parent->desktop != desktop) { + set_error( STATUS_ACCESS_DENIED ); + goto failed; + } + + /* if no parent, class must be the desktop */ + if (!parent && !is_desktop_class( class )) { + set_error( STATUS_ACCESS_DENIED ); + goto failed; + } + + /* if parent belongs to a different thread and the window isn't */ + /* top-level, attach the two threads */ + if (parent && parent->thread && parent->thread != current_thread && !is_desktop_window(parent)) { + if (!attach_thread_input( current_thread, parent->thread )) + goto failed; + } + else { /* otherwise just make sure that the thread has a message queue */ + if (!/*current_thread->queue*/get_current_queue() && !init_thread_queue( current_thread )) + goto failed; + } + + /* put it on parent unlinked list */ + if (parent) + list_add_head( &parent->unlinked, &win->entry ); + else { + my_list_init( &win->entry ); +#if 0 + assert( !desktop->top_window ); +#endif + desktop->top_window = win; + set_process_default_desktop( get_current_w32process(), desktop, current_thread->desktop ); + } + + current_thread->desktop_users++; + return win; + +failed: + if (win) { + if (win->handle) + free_user_handle( win->handle ); + free( win ); + } + release_object( desktop ); + release_class( class ); + return NULL; +} + +/* destroy all windows belonging to a given thread */ +void destroy_thread_windows( struct w32thread *thread ) +{ + user_handle_t handle = 0; + struct window *win; + + while ((win = next_user_handle( &handle, USER_WINDOW ))) { + if (win->thread != thread) + continue; + if (is_desktop_window( win )) + detach_window_thread( win ); + else + destroy_window( win ); + } +} + +/* Window Styles */ +#define WS_OVERLAPPED 0x00000000L +#define WS_POPUP 0x80000000L +#define WS_CHILD 0x40000000L +#define WS_MINIMIZE 0x20000000L +#define WS_VISIBLE 0x10000000L +#define WS_DISABLED 0x08000000L +#define WS_CLIPSIBLINGS 0x04000000L +#define WS_CLIPCHILDREN 0x02000000L +#define WS_MAXIMIZE 0x01000000L +#define WS_CAPTION 0x00C00000L +#define WS_BORDER 0x00800000L +#define WS_DLGFRAME 0x00400000L +#define WS_VSCROLL 0x00200000L +#define WS_HSCROLL 0x00100000L +#define WS_SYSMENU 0x00080000L +#define WS_THICKFRAME 0x00040000L +#define WS_GROUP 0x00020000L +#define WS_TABSTOP 0x00010000L +#define WS_MINIMIZEBOX 0x00020000L +#define WS_MAXIMIZEBOX 0x00010000L +#define WS_TILED WS_OVERLAPPED +#define WS_ICONIC WS_MINIMIZE +#define WS_SIZEBOX WS_THICKFRAME +#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME| WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) +#define WS_CHILDWINDOW (WS_CHILD) +#define WS_TILEDWINDOW (WS_OVERLAPPEDWINDOW) + +/* Window extended styles */ +#define WS_EX_DLGMODALFRAME 0x00000001L +#define WS_EX_DRAGDETECT 0x00000002L +#define WS_EX_NOPARENTNOTIFY 0x00000004L +#define WS_EX_TOPMOST 0x00000008L +#define WS_EX_ACCEPTFILES 0x00000010L +#define WS_EX_TRANSPARENT 0x00000020L +#define WS_EX_MDICHILD 0x00000040L +#define WS_EX_TOOLWINDOW 0x00000080L +#define WS_EX_WINDOWEDGE 0x00000100L +#define WS_EX_CLIENTEDGE 0x00000200L +#define WS_EX_CONTEXTHELP 0x00000400L +#define WS_EX_RIGHT 0x00001000L +#define WS_EX_LEFT 0x00000000L +#define WS_EX_RTLREADING 0x00002000L +#define WS_EX_LTRREADING 0x00000000L +#define WS_EX_LEFTSCROLLBAR 0x00004000L +#define WS_EX_RIGHTSCROLLBAR 0x00000000L +#define WS_EX_CONTROLPARENT 0x00010000L +#define WS_EX_STATICEDGE 0x00020000L +#define WS_EX_APPWINDOW 0x00040000L +#define WS_EX_LAYERED 0x00080000L +#define WS_EX_NOINHERITLAYOUT 0x00100000L +#define WS_EX_LAYOUTRTL 0x00400000L +#define WS_EX_COMPOSITED 0x02000000L +#define WS_EX_NOACTIVATE 0x08000000L + +#define WS_EX_OVERLAPPEDWINDOW (WS_EX_WINDOWEDGE|WS_EX_CLIENTEDGE) +#define WS_EX_PALETTEWINDOW (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_TOPMOST) + +/* get the desktop window */ +static struct window *get_desktop_window( struct w32thread *thread, int create ) +{ + struct window *top_window; + struct desktop *desktop = get_thread_desktop( thread, 0 ); + + if (!desktop) + return NULL; + + if (!(top_window = desktop->top_window) && create) { + if ((top_window = create_window( NULL, NULL, DESKTOP_ATOM, 0 ))) { + detach_window_thread( top_window ); + top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + } + } + release_object( desktop ); + return top_window; +} + +/* check whether child is a descendant of parent */ +int is_child_window( user_handle_t parent, user_handle_t child ) +{ + struct window *child_ptr = get_user_object( child, USER_WINDOW ); + struct window *parent_ptr = get_user_object( parent, USER_WINDOW ); + + if (!child_ptr || !parent_ptr) + return 0; + while (child_ptr->parent) { + if (child_ptr->parent == parent_ptr) + return 1; + child_ptr = child_ptr->parent; + } + return 0; +} + +/* check whether window is a top-level window */ +int is_top_level_window( user_handle_t window ) +{ + struct window *win = get_user_object( window, USER_WINDOW ); + return (win && (is_desktop_window(win) || is_desktop_window(win->parent))); +} + +/* make a window active if possible */ +int make_window_active( user_handle_t window ) +{ + struct window *owner, *win = get_window( window ); + + if (!win) + return 0; + + /* set last active for window and its owner */ + win->last_active = win->handle; + if ((owner = get_user_object( win->owner, USER_WINDOW ))) + owner->last_active = win->handle; + return 1; +} + +/* increment (or decrement) the window paint count */ +static inline void inc_window_paint_count( struct window *win, int incr ) +{ + if (win->thread) + inc_queue_paint_count( win->thread, incr ); +} + +/* check if window and all its ancestors are visible */ +static int is_visible( const struct window *win ) +{ + while (win && win->parent) { + if (!(win->style & WS_VISIBLE)) + return 0; + win = win->parent; + /* if parent is minimized children are not visible */ + if (win && (win->style & WS_MINIMIZE)) + return 0; + } + return 1; +} + +/* same as is_visible but takes a window handle */ +int is_window_visible( user_handle_t window ) +{ + struct window *win = get_user_object( window, USER_WINDOW ); + if (!win) + return 0; + return is_visible( win ); +} + +/* check if point is inside the window */ +static inline int is_point_in_window( struct window *win, int x, int y ) +{ + if (!(win->style & WS_VISIBLE)) + return 0; /* not visible */ + if ((win->style & (WS_POPUP|WS_CHILD|WS_DISABLED)) == (WS_CHILD|WS_DISABLED)) + return 0; /* disabled child */ + if ((win->ex_style & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT)) + return 0; /* transparent */ + if (x < win->visible_rect.left || x >= win->visible_rect.right || + y < win->visible_rect.top || y >= win->visible_rect.bottom) + return 0; /* not in window */ + if (win->win_region && + !point_in_region( win->win_region, x - win->window_rect.left, y - win->window_rect.top )) + return 0; /* not in window region */ + return 1; +} + +/* find child of 'parent' that contains the given point (in parent-relative coords) */ +static struct window *child_window_from_point( struct window *parent, int x, int y ) +{ + struct window *ptr; + + LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry ) { + if (!is_point_in_window( ptr, x, y )) + continue; /* skip it */ + + /* if window is minimized or disabled, return at once */ + if (ptr->style & (WS_MINIMIZE|WS_DISABLED)) + return ptr; + + /* if point is not in client area, return at once */ + if (x < ptr->client_rect.left || x >= ptr->client_rect.right || + y < ptr->client_rect.top || y >= ptr->client_rect.bottom) + return ptr; + + return child_window_from_point( ptr, x - ptr->client_rect.left, y - ptr->client_rect.top ); + } + return parent; /* not found any child */ +} + +/* find all children of 'parent' that contain the given point */ +static int get_window_children_from_point( struct window *parent, int x, int y, + struct user_handle_array *array ) +{ + struct window *ptr; + + LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry ) { + if (!is_point_in_window( ptr, x, y )) + continue; /* skip it */ + + /* if point is in client area, and window is not minimized or disabled, check children */ + if (!(ptr->style & (WS_MINIMIZE|WS_DISABLED)) && + x >= ptr->client_rect.left && x < ptr->client_rect.right && + y >= ptr->client_rect.top && y < ptr->client_rect.bottom) { + if (!get_window_children_from_point( ptr, x - ptr->client_rect.left, + y - ptr->client_rect.top, array )) + return 0; + } + + /* now add window to the array */ + if (!add_handle_to_array( array, ptr->handle )) + return 0; + } + return 1; +} + +/* find window containing point (in absolute coords) */ +user_handle_t window_from_point( struct desktop *desktop, int x, int y ) +{ + struct window *ret; + + if (!desktop->top_window) + return 0; + ret = child_window_from_point( desktop->top_window, x, y ); + return ret->handle; +} + +/* return list of all windows containing point (in absolute coords) */ +static int all_windows_from_point( struct window *top, int x, int y, struct user_handle_array *array ) +{ + struct window *ptr; + + /* make point relative to top window */ + for (ptr = top->parent; ptr && !is_desktop_window(ptr); ptr = ptr->parent) { + x -= ptr->client_rect.left; + y -= ptr->client_rect.top; + } + + if (!is_point_in_window( top, x, y )) + return 1; + + /* if point is in client area, and window is not minimized or disabled, check children */ + if (!(top->style & (WS_MINIMIZE|WS_DISABLED)) && + x >= top->client_rect.left && x < top->client_rect.right && + y >= top->client_rect.top && y < top->client_rect.bottom) { + if (!is_desktop_window(top)) { + x -= top->client_rect.left; + y -= top->client_rect.top; + } + if (!get_window_children_from_point( top, x, y, array )) + return 0; + } + /* now add window to the array */ + if (!add_handle_to_array( array, top->handle )) + return 0; + return 1; +} + + +/* return the thread owning a window */ +struct w32thread *get_window_thread( user_handle_t handle ) +{ + struct window *win = get_user_object( handle, USER_WINDOW ); + if (!win || !win->thread) + return NULL; + return (struct w32thread *)grab_object( win->thread ); +} + + +/* check if any area of a window needs repainting */ +static inline int win_needs_repaint( struct window *win ) +{ + return win->update_region || (win->paint_flags & PAINT_INTERNAL); +} + + +/* find a child of the specified window that needs repainting */ +static struct window *find_child_to_repaint( struct window *parent, struct w32thread *thread ) +{ + struct window *ptr, *ret = NULL; + + LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry ) { + if (!(ptr->style & WS_VISIBLE)) + continue; + if (ptr->thread == thread && win_needs_repaint( ptr )) + ret = ptr; + else if (!(ptr->style & WS_MINIMIZE)) /* explore its children */ + ret = find_child_to_repaint( ptr, thread ); + if (ret) + break; + } + + if (ret && (ret->ex_style & WS_EX_TRANSPARENT)) { + /* transparent window, check for non-transparent sibling to paint first */ + for (ptr = get_next_window(ret); ptr; ptr = get_next_window(ptr)) { + if (!(ptr->style & WS_VISIBLE)) + continue; + if (ptr->ex_style & WS_EX_TRANSPARENT) + continue; + if (ptr->thread != thread) + continue; + if (win_needs_repaint( ptr )) + return ptr; + } + } + return ret; +} + + +/* find a window that needs to receive a WM_PAINT; also clear its internal paint flag */ +user_handle_t find_window_to_repaint( user_handle_t parent, struct w32thread *thread ) +{ + struct window *ptr, *win, *top_window = get_desktop_window( thread, 0 ); + + if (!top_window) + return 0; + + if (top_window->thread == thread && win_needs_repaint( top_window )) + win = top_window; + else + win = find_child_to_repaint( top_window, thread ); + + if (win && parent) { + /* check that it is a child of the specified parent */ + for (ptr = win; ptr; ptr = ptr->parent) + if (ptr->handle == parent) + break; + /* otherwise don't return any window, we don't repaint a child before its parent */ + if (!ptr) + win = NULL; + } + if (!win) + return 0; + win->paint_flags &= ~PAINT_INTERNAL; + return win->handle; +} + + +/* intersect the window region with the specified region, relative to the window parent */ +static struct region *intersect_window_region( struct region *region, struct window *win ) +{ + /* make region relative to window rect */ + offset_region( region, -win->window_rect.left, -win->window_rect.top ); + if (!intersect_region( region, region, win->win_region )) + return NULL; + /* make region relative to parent again */ + offset_region( region, win->window_rect.left, win->window_rect.top ); + return region; +} + + +/* convert coordinates from client to screen coords */ +static inline void client_to_screen( struct window *win, int *x, int *y ) +{ + for ( ; win && !is_desktop_window(win); win = win->parent) { + *x += win->client_rect.left; + *y += win->client_rect.top; + } +} + +/* convert coordinates from client to screen coords */ +static inline void client_to_screen_rect( struct window *win, rectangle_t *rect ) +{ + for ( ; win && !is_desktop_window(win); win = win->parent) { + rect->left += win->client_rect.left; + rect->right += win->client_rect.left; + rect->top += win->client_rect.top; + rect->bottom += win->client_rect.top; + } +} + +/* map the region from window to screen coordinates */ +static inline void map_win_region_to_screen( struct window *win, struct region *region ) +{ + if (!is_desktop_window(win)) { + int x = win->window_rect.left; + int y = win->window_rect.top; + client_to_screen( win->parent, &x, &y ); + offset_region( region, x, y ); + } +} + + +/* clip all children of a given window out of the visible region */ +static struct region *clip_children( struct window *parent, struct window *last, + struct region *region, int offset_x, int offset_y ) +{ + struct window *ptr; + struct region *tmp = create_empty_region(); + + if (!tmp) + return NULL; + LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry ) { + if (ptr == last) + break; + if (!(ptr->style & WS_VISIBLE)) + continue; + if (ptr->ex_style & WS_EX_TRANSPARENT) + continue; + set_region_rect( tmp, &ptr->visible_rect ); + if (ptr->win_region && !intersect_window_region( tmp, ptr )) { + free_region( tmp ); + return NULL; + } + offset_region( tmp, offset_x, offset_y ); + if (!(region = subtract_region( region, region, tmp ))) + break; + if (is_region_empty( region )) + break; + } + free_region( tmp ); + return region; +} + + +/* compute the intersection of two rectangles; return 0 if the result is empty */ +static inline int intersect_rect( rectangle_t *dst, const rectangle_t *src1, const rectangle_t *src2 ) +{ + dst->left = max( src1->left, src2->left ); + dst->top = max( src1->top, src2->top ); + dst->right = min( src1->right, src2->right ); + dst->bottom = min( src1->bottom, src2->bottom ); + return (dst->left < dst->right && dst->top < dst->bottom); +} + + +/* offset the coordinates of a rectangle */ +static inline void offset_rect( rectangle_t *rect, int offset_x, int offset_y ) +{ + rect->left += offset_x; + rect->top += offset_y; + rect->right += offset_x; + rect->bottom += offset_y; +} + + +/* set the region to the client rect clipped by the window rect, in parent-relative coordinates */ +static void set_region_client_rect( struct region *region, struct window *win ) +{ + rectangle_t rect; + + intersect_rect( &rect, &win->window_rect, &win->client_rect ); + set_region_rect( region, &rect ); +} + + +/* get the top-level window to clip against for a given window */ +static inline struct window *get_top_clipping_window( struct window *win ) +{ + while (win->parent && !is_desktop_window(win->parent)) + win = win->parent; + return win; +} + +/* GetDCEx flags */ +#define DCX_WINDOW 0x00000001 +#define DCX_CACHE 0x00000002 +#define DCX_NORESETATTRS 0x00000004 +#define DCX_CLIPCHILDREN 0x00000008 +#define DCX_CLIPSIBLINGS 0x00000010 +#define DCX_PARENTCLIP 0x00000020 +#define DCX_EXCLUDERGN 0x00000040 +#define DCX_INTERSECTRGN 0x00000080 +#define DCX_EXCLUDEUPDATE 0x00000100 +#define DCX_INTERSECTUPDATE 0x00000200 +#define DCX_LOCKWINDOWUPDATE 0x00000400 +#define DCX_USESTYLE 0x00010000 +#define DCX_NORECOMPUTE 0x00100000 +#define DCX_VALIDATE 0x00200000 + + /* RedrawWindow() flags */ +#define RDW_INVALIDATE 0x0001 +#define RDW_INTERNALPAINT 0x0002 +#define RDW_ERASE 0x0004 +#define RDW_VALIDATE 0x0008 +#define RDW_NOINTERNALPAINT 0x0010 +#define RDW_NOERASE 0x0020 +#define RDW_NOCHILDREN 0x0040 +#define RDW_ALLCHILDREN 0x0080 +#define RDW_UPDATENOW 0x0100 +#define RDW_ERASENOW 0x0200 +#define RDW_FRAME 0x0400 +#define RDW_NOFRAME 0x0800 + +/* SetWindowPos() and WINDOWPOS flags */ +#define SWP_NOSIZE 0x0001 +#define SWP_NOMOVE 0x0002 +#define SWP_NOZORDER 0x0004 +#define SWP_NOREDRAW 0x0008 +#define SWP_NOACTIVATE 0x0010 +#define SWP_FRAMECHANGED 0x0020 /* The frame changed: send WM_NCCALCSIZE */ +#define SWP_SHOWWINDOW 0x0040 +#define SWP_HIDEWINDOW 0x0080 +#define SWP_NOCOPYBITS 0x0100 +#define SWP_NOOWNERZORDER 0x0200 /* Don't do owner Z ordering */ + +#define SWP_DRAWFRAME SWP_FRAMECHANGED +#define SWP_NOREPOSITION SWP_NOOWNERZORDER + +#define SWP_NOSENDCHANGING 0x0400 +#define SWP_DEFERERASE 0x2000 +#define SWP_ASYNCWINDOWPOS 0x4000 + +/* undocumented SWP flags - from SDK 3.1 */ +#define SWP_NOCLIENTSIZE 0x0800 +#define SWP_NOCLIENTMOVE 0x1000 +#define SWP_STATECHANGED 0x8000 + +#define HWND_DESKTOP ((HWND)0) +#define HWND_BROADCAST ((HWND)0xffff) + +/* SetWindowPos() hwndInsertAfter field values */ +#define HWND_TOP ((HWND)0) +#define HWND_BOTTOM ((HWND)1) +#define HWND_TOPMOST ((HWND)-1) +#define HWND_NOTOPMOST ((HWND)-2) +#define HWND_MESSAGE ((HWND)-3) + +/* compute the visible region of a window, in window coordinates */ +static struct region *get_visible_region( struct window *win, unsigned int flags ) +{ + struct region *tmp = NULL, *region; + int offset_x, offset_y; + + if (!(region = create_empty_region())) + return NULL; + + /* first check if all ancestors are visible */ + + if (!is_visible( win )) + return region; /* empty region */ + + /* create a region relative to the window itself */ + + if ((flags & DCX_PARENTCLIP) && win->parent && !is_desktop_window(win->parent)) { + set_region_client_rect( region, win->parent ); + offset_region( region, -win->parent->client_rect.left, -win->parent->client_rect.top ); + } + else if (flags & DCX_WINDOW) { + set_region_rect( region, &win->visible_rect ); + if (win->win_region && !intersect_window_region( region, win )) + goto error; + } + else { + set_region_client_rect( region, win ); + if (win->win_region && !intersect_window_region( region, win )) + goto error; + } + + /* clip children */ + + if (flags & DCX_CLIPCHILDREN) { + if (is_desktop_window(win)) + offset_x = offset_y = 0; + else { + offset_x = win->client_rect.left; + offset_y = win->client_rect.top; + } + if (!clip_children( win, NULL, region, offset_x, offset_y )) + goto error; + } + + /* clip siblings of ancestors */ + + if (is_desktop_window(win)) + offset_x = offset_y = 0; + else { + offset_x = win->window_rect.left; + offset_y = win->window_rect.top; + } + + if ((tmp = create_empty_region()) != NULL) { + while (win->parent) { + /* we don't clip out top-level siblings as that's up to the native windowing system */ + if ((win->style & WS_CLIPSIBLINGS) && !is_desktop_window( win->parent )) { + if (!clip_children( win->parent, win, region, 0, 0 )) + goto error; + if (is_region_empty( region )) + break; + } + /* clip to parent client area */ + win = win->parent; + if (!is_desktop_window(win)) { + offset_x += win->client_rect.left; + offset_y += win->client_rect.top; + offset_region( region, win->client_rect.left, win->client_rect.top ); + } + set_region_client_rect( tmp, win ); + if (win->win_region && !intersect_window_region( tmp, win )) + goto error; + if (!intersect_region( region, region, tmp )) + goto error; + if (is_region_empty( region )) + break; + } + free_region( tmp ); + } + offset_region( region, -offset_x, -offset_y ); /* make it relative to target window */ + return region; + +error: + if (tmp) + free_region( tmp ); + free_region( region ); + return NULL; +} + + +/* get the window class of a window */ +struct window_class* get_window_class( user_handle_t window ) +{ + struct window *win; + if (!(win = get_window( window ))) + return NULL; + if (!win->class) + set_error( STATUS_ACCESS_DENIED ); + return win->class; +} + +/* determine the window visible rectangle, i.e. window or client rect cropped by parent rects */ +/* the returned rectangle is in window coordinates; return 0 if rectangle is empty */ +static int get_window_visible_rect( struct window *win, rectangle_t *rect, int frame ) +{ + int offset_x = 0, offset_y = 0; + + if (!(win->style & WS_VISIBLE)) + return 0; + + *rect = frame ? win->window_rect : win->client_rect; + if (!is_desktop_window(win)) { + offset_x = win->window_rect.left; + offset_y = win->window_rect.top; + } + + while (win->parent) { + win = win->parent; + if (!(win->style & WS_VISIBLE) || win->style & WS_MINIMIZE) + return 0; + if (!is_desktop_window(win)) { + offset_x += win->client_rect.left; + offset_y += win->client_rect.top; + offset_rect( rect, win->client_rect.left, win->client_rect.top ); + } + if (!intersect_rect( rect, rect, &win->client_rect )) + return 0; + if (!intersect_rect( rect, rect, &win->window_rect )) + return 0; + } + offset_rect( rect, -offset_x, -offset_y ); + return 1; +} + +/* return a copy of the specified region cropped to the window client or frame rectangle, */ +/* and converted from client to window coordinates. Helper for (in)validate_window. */ +static struct region *crop_region_to_win_rect( struct window *win, struct region *region, int frame ) +{ + rectangle_t rect; + struct region *tmp; + + if (!get_window_visible_rect( win, &rect, frame )) + return NULL; + if (!(tmp = create_empty_region())) + return NULL; + set_region_rect( tmp, &rect ); + + if (region) { + /* map it to client coords */ + offset_region( tmp, win->window_rect.left - win->client_rect.left, + win->window_rect.top - win->client_rect.top ); + + /* intersect specified region with bounding rect */ + if (!intersect_region( tmp, region, tmp )) + goto done; + if (is_region_empty( tmp )) + goto done; + + /* map it back to window coords */ + offset_region( tmp, win->client_rect.left - win->window_rect.left, + win->client_rect.top - win->window_rect.top ); + } + return tmp; + +done: + free_region( tmp ); + return NULL; +} + + +/* set a region as new update region for the window */ +static void set_update_region( struct window *win, struct region *region ) +{ + if (region && !is_region_empty( region )) { + if (!win->update_region) + inc_window_paint_count( win, 1 ); + else + free_region( win->update_region ); + win->update_region = region; + } + else { + if (win->update_region) { + inc_window_paint_count( win, -1 ); + free_region( win->update_region ); + } + win->paint_flags &= ~(PAINT_ERASE | PAINT_DELAYED_ERASE | PAINT_NONCLIENT); + win->update_region = NULL; + if (region) + free_region( region ); + } +} + + +/* add a region to the update region; the passed region is freed or reused */ +static int add_update_region( struct window *win, struct region *region ) +{ + if (win->update_region && !union_region( region, win->update_region, region )) { + free_region( region ); + return 0; + } + set_update_region( win, region ); + return 1; +} + + +/* crop the update region of children to the specified rectangle, in client coords */ +static void crop_children_update_region( struct window *win, rectangle_t *rect ) +{ + struct window *child; + struct region *tmp; + rectangle_t child_rect; + + LIST_FOR_EACH_ENTRY( child, &win->children, struct window, entry ) { + if (!(child->style & WS_VISIBLE)) + continue; + if (!rect) { /* crop everything out */ + crop_children_update_region( child, NULL ); + set_update_region( child, NULL ); + continue; + } + + /* nothing to do if child is completely inside rect */ + if (child->window_rect.left >= rect->left && + child->window_rect.top >= rect->top && + child->window_rect.right <= rect->right && + child->window_rect.bottom <= rect->bottom) + continue; + + /* map to child client coords and crop grand-children */ + child_rect = *rect; + offset_rect( &child_rect, -child->client_rect.left, -child->client_rect.top ); + crop_children_update_region( child, &child_rect ); + + /* now crop the child itself */ + if (!child->update_region) + continue; + if (!(tmp = create_empty_region())) + continue; + set_region_rect( tmp, rect ); + offset_region( tmp, -child->window_rect.left, -child->window_rect.top ); + if (intersect_region( tmp, child->update_region, tmp )) + set_update_region( child, tmp ); + else + free_region( tmp ); + } +} + + +/* validate the non client area of a window */ +static void validate_non_client( struct window *win ) +{ + struct region *tmp; + rectangle_t rect; + + if (!win->update_region) + return; /* nothing to do */ + + /* get client rect in window coords */ + rect.left = win->client_rect.left - win->window_rect.left; + rect.top = win->client_rect.top - win->window_rect.top; + rect.right = win->client_rect.right - win->window_rect.left; + rect.bottom = win->client_rect.bottom - win->window_rect.top; + + if ((tmp = create_empty_region())) { + set_region_rect( tmp, &rect ); + if (intersect_region( tmp, win->update_region, tmp )) + set_update_region( win, tmp ); + else + free_region( tmp ); + } + win->paint_flags &= ~PAINT_NONCLIENT; +} + + +/* validate a window completely so that we don't get any further paint messages for it */ +static void validate_whole_window( struct window *win ) +{ + set_update_region( win, NULL ); + + if (win->paint_flags & PAINT_INTERNAL) { + win->paint_flags &= ~PAINT_INTERNAL; + inc_window_paint_count( win, -1 ); + } +} + + +/* validate a window's children so that we don't get any further paint messages for it */ +static void validate_children( struct window *win ) +{ + struct window *child; + + LIST_FOR_EACH_ENTRY( child, &win->children, struct window, entry ) { + if (!(child->style & WS_VISIBLE)) + continue; + validate_children(child); + validate_whole_window(child); + } +} + + +/* validate the update region of a window on all parents; helper for get_update_region */ +static void validate_parents( struct window *child ) +{ + int offset_x = 0, offset_y = 0; + struct window *win = child; + struct region *tmp = NULL; + + if (!child->update_region) + return; + + while (win->parent) { + /* map to parent client coords */ + offset_x += win->window_rect.left; + offset_y += win->window_rect.top; + + win = win->parent; + + /* and now map to window coords */ + offset_x += win->client_rect.left - win->window_rect.left; + offset_y += win->client_rect.top - win->window_rect.top; + + if (win->update_region && !(win->style & WS_CLIPCHILDREN)) { + if (!tmp && !(tmp = create_empty_region())) + return; + offset_region( child->update_region, offset_x, offset_y ); + if (subtract_region( tmp, win->update_region, child->update_region )) { + set_update_region( win, tmp ); + tmp = NULL; + } + /* restore child coords */ + offset_region( child->update_region, -offset_x, -offset_y ); + } + } + if (tmp) + free_region( tmp ); +} + + +/* add/subtract a region (in client coordinates) to the update region of the window */ +static void redraw_window( struct window *win, struct region *region, int frame, unsigned int flags ) +{ + struct region *tmp; + struct window *child; + + if (flags & RDW_INVALIDATE) { + if (!(tmp = crop_region_to_win_rect( win, region, frame ))) + return; + + if (!add_update_region( win, tmp )) + return; + + if (flags & RDW_FRAME) + win->paint_flags |= PAINT_NONCLIENT; + if (flags & RDW_ERASE) + win->paint_flags |= PAINT_ERASE; + } + else if (flags & RDW_VALIDATE) { + if (!region && (flags & RDW_NOFRAME)) { /* shortcut: validate everything */ + set_update_region( win, NULL ); + } + else if (win->update_region) { + if ((tmp = crop_region_to_win_rect( win, region, frame ))) { + if (!subtract_region( tmp, win->update_region, tmp )) { + free_region( tmp ); + return; + } + set_update_region( win, tmp ); + } + if (flags & RDW_NOFRAME) + validate_non_client( win ); + if (flags & RDW_NOERASE) + win->paint_flags &= ~(PAINT_ERASE | PAINT_DELAYED_ERASE); + } + } + + if ((flags & RDW_INTERNALPAINT) && !(win->paint_flags & PAINT_INTERNAL)) { + win->paint_flags |= PAINT_INTERNAL; + inc_window_paint_count( win, 1 ); + } + else if ((flags & RDW_NOINTERNALPAINT) && (win->paint_flags & PAINT_INTERNAL)) { + win->paint_flags &= ~PAINT_INTERNAL; + inc_window_paint_count( win, -1 ); + } + + /* now process children recursively */ + + if (flags & RDW_NOCHILDREN) + return; + if (win->style & WS_MINIMIZE) + return; + if ((win->style & WS_CLIPCHILDREN) && !(flags & RDW_ALLCHILDREN)) + return; + + if (!(tmp = crop_region_to_win_rect( win, region, 0 ))) + return; + + /* map to client coordinates */ + offset_region( tmp, win->window_rect.left - win->client_rect.left, + win->window_rect.top - win->client_rect.top ); + + if (flags & RDW_INVALIDATE) + flags |= RDW_FRAME | RDW_ERASE; + + LIST_FOR_EACH_ENTRY( child, &win->children, struct window, entry ) { + if (!(child->style & WS_VISIBLE)) + continue; + if (!rect_in_region( tmp, &child->window_rect )) + continue; + offset_region( tmp, -child->client_rect.left, -child->client_rect.top ); + redraw_window( child, tmp, 1, flags ); + offset_region( tmp, child->client_rect.left, child->client_rect.top ); + } + free_region( tmp ); +} + + +/* retrieve the update flags for a window depending on the state of the update region */ +static unsigned int get_update_flags( struct window *win, unsigned int flags ) +{ + unsigned int ret = 0; + + if (flags & UPDATE_NONCLIENT) { + if ((win->paint_flags & PAINT_NONCLIENT) && win->update_region) + ret |= UPDATE_NONCLIENT; + } + if (flags & UPDATE_ERASE) { + if ((win->paint_flags & PAINT_ERASE) && win->update_region) + ret |= UPDATE_ERASE; + } + if (flags & UPDATE_PAINT) { + if (win->update_region) { + if (win->paint_flags & PAINT_DELAYED_ERASE) + ret |= UPDATE_DELAYED_ERASE; + ret |= UPDATE_PAINT; + } + } + if (flags & UPDATE_INTERNALPAINT) { + if (win->paint_flags & PAINT_INTERNAL) { + ret |= UPDATE_INTERNALPAINT; + if (win->paint_flags & PAINT_DELAYED_ERASE) + ret |= UPDATE_DELAYED_ERASE; + } + } + return ret; +} + + +/* iterate through the children of the given window until we find one with some update flags */ +static unsigned int get_child_update_flags( struct window *win, struct window *from_child, + unsigned int flags, struct window **child ) +{ + struct window *ptr; + unsigned int ret = 0; + + /* first make sure we want to iterate children at all */ + + if (win->style & WS_MINIMIZE) + return 0; + + /* note: the WS_CLIPCHILDREN test is the opposite of the invalidation case, + * here we only want to repaint children of windows that clip them, others + * need to wait for WM_PAINT to be done in the parent first. + */ + if (!(flags & UPDATE_ALLCHILDREN) && !(win->style & WS_CLIPCHILDREN)) + return 0; + + LIST_FOR_EACH_ENTRY( ptr, &win->children, struct window, entry ) { + if (from_child) { /* skip all children until from_child is found */ + if (ptr == from_child) + from_child = NULL; + continue; + } + if (!(ptr->style & WS_VISIBLE)) + continue; + if ((ret = get_update_flags( ptr, flags )) != 0) { + *child = ptr; + break; + } + if ((ret = get_child_update_flags( ptr, NULL, flags, child ))) + break; + } + return ret; +} + +/* iterate through children and siblings of the given window until we find one with some update flags */ +static unsigned int get_window_update_flags( struct window *win, struct window *from_child, + unsigned int flags, struct window **child ) +{ + unsigned int ret; + struct window *ptr, *from_sibling = NULL; + + /* if some parent is not visible start from the next sibling */ + + if (!is_visible( win )) + return 0; + for (ptr = from_child; ptr; ptr = ptr->parent) { + if (!(ptr->style & WS_VISIBLE) || (ptr->style & WS_MINIMIZE)) + from_sibling = ptr; + if (ptr == win) + break; + } + + /* non-client painting must be delayed if one of the parents is going to + * be repainted and doesn't clip children */ + + if ((flags & UPDATE_NONCLIENT) && !(flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT))) { + for (ptr = win->parent; ptr; ptr = ptr->parent) { + if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) + return 0; + } + if (from_child && !(flags & UPDATE_ALLCHILDREN)) { + for (ptr = from_sibling ? from_sibling : from_child; ptr; ptr = ptr->parent) { + if (!(ptr->style & WS_CLIPCHILDREN) && win_needs_repaint( ptr )) + from_sibling = ptr; + if (ptr == win) + break; + } + } + } + + + /* check window itself (only if not restarting from a child) */ + + if (!from_child) { + if ((ret = get_update_flags( win, flags ))) { + *child = win; + return ret; + } + from_child = win; + } + + /* now check children */ + + if (flags & UPDATE_NOCHILDREN) + return 0; + if (!from_sibling) { + if ((ret = get_child_update_flags( from_child, NULL, flags, child ))) + return ret; + from_sibling = from_child; + } + + /* then check siblings and parent siblings */ + + while (from_sibling->parent && from_sibling != win) { + if ((ret = get_child_update_flags( from_sibling->parent, from_sibling, flags, child ))) + return ret; + from_sibling = from_sibling->parent; + } + return 0; +} + + +/* expose the areas revealed by a vis region change on the window parent */ +/* returns the region exposed on the window itself (in client coordinates) */ +static struct region *expose_window( struct window *win, const rectangle_t *old_window_rect, + struct region *old_vis_rgn ) +{ + struct region *new_vis_rgn, *exposed_rgn; + + if (!(new_vis_rgn = get_visible_region( win, DCX_WINDOW ))) + return NULL; + + if ((exposed_rgn = create_empty_region())) { + if (subtract_region( exposed_rgn, new_vis_rgn, old_vis_rgn ) && !is_region_empty( exposed_rgn )) { + /* make it relative to the new client area */ + offset_region( exposed_rgn, win->window_rect.left - win->client_rect.left, + win->window_rect.top - win->client_rect.top ); + } + else { + free_region( exposed_rgn ); + exposed_rgn = NULL; + } + } + + if (win->parent) { + /* make it relative to the old window pos for subtracting */ + offset_region( new_vis_rgn, win->window_rect.left - old_window_rect->left, + win->window_rect.top - old_window_rect->top ); + + if ((win->parent->style & WS_CLIPCHILDREN) ? + subtract_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ) : + xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn )) { + if (!is_region_empty( new_vis_rgn )) { + /* make it relative to parent */ + offset_region( new_vis_rgn, old_window_rect->left, old_window_rect->top ); + redraw_window( win->parent, new_vis_rgn, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN ); + } + } + } + free_region( new_vis_rgn ); + return exposed_rgn; +} + + +/* set the window and client rectangles, updating the update region if necessary */ +extern void clear_error(void); + +static void set_window_pos( struct window *win, struct window *previous, + unsigned int swp_flags, const rectangle_t *window_rect, + const rectangle_t *client_rect, const rectangle_t *valid_rects ) +{ + struct region *old_vis_rgn = NULL, *exposed_rgn = NULL; + const rectangle_t old_window_rect = win->window_rect; + const rectangle_t old_client_rect = win->client_rect; + rectangle_t rect; + int client_changed, frame_changed; + int visible = (win->style & WS_VISIBLE) || (swp_flags & SWP_SHOWWINDOW); + + if (win->parent && !is_visible( win->parent )) + visible = 0; + + if (visible && !(old_vis_rgn = get_visible_region( win, DCX_WINDOW ))) + return; + + /* set the new window info before invalidating anything */ + + win->window_rect = *window_rect; + win->client_rect = *client_rect; + if (!(swp_flags & SWP_NOZORDER) && win->parent) + link_window( win, previous ); + if (swp_flags & SWP_SHOWWINDOW) + win->style |= WS_VISIBLE; + else if (swp_flags & SWP_HIDEWINDOW) + win->style &= ~WS_VISIBLE; + + /* assume the visible rect stays at the same offset from the window rect */ + win->visible_rect.left += window_rect->left - old_window_rect.left; + win->visible_rect.top += window_rect->top - old_window_rect.top; + win->visible_rect.right += window_rect->right - old_window_rect.right; + win->visible_rect.bottom += window_rect->bottom - old_window_rect.bottom; + /* but don't make it smaller than the client rect */ + if (win->visible_rect.left > client_rect->left) + win->visible_rect.left = max( window_rect->left, client_rect->left ); + if (win->visible_rect.top > client_rect->top) + win->visible_rect.top = max( window_rect->top, client_rect->top ); + if (win->visible_rect.right < client_rect->right) + win->visible_rect.right = min( window_rect->right, client_rect->right ); + if (win->visible_rect.bottom < client_rect->bottom) + win->visible_rect.bottom = min( window_rect->bottom, client_rect->bottom ); + + /* if the window is not visible, everything is easy */ + if (!visible) + return; + + /* expose anything revealed by the change */ + + if (!(swp_flags & SWP_NOREDRAW)) + exposed_rgn = expose_window( win, &old_window_rect, old_vis_rgn ); + + if (!(win->style & WS_VISIBLE)) { + /* clear the update region since the window is no longer visible */ + validate_whole_window( win ); + validate_children( win ); + goto done; + } + + /* crop update region to the new window rect */ + + if (win->update_region) { + if (get_window_visible_rect( win, &rect, 1 )) { + struct region *tmp = create_empty_region(); + if (tmp) { + set_region_rect( tmp, &rect ); + if (intersect_region( tmp, win->update_region, tmp )) + set_update_region( win, tmp ); + else + free_region( tmp ); + } + } + else set_update_region( win, NULL ); /* visible rect is empty */ + } + + /* crop children regions to the new window rect */ + + if (get_window_visible_rect( win, &rect, 0 )) { + /* map to client coords */ + offset_rect( &rect, win->window_rect.left - win->client_rect.left, + win->window_rect.top - win->client_rect.top ); + crop_children_update_region( win, &rect ); + } + else + crop_children_update_region( win, NULL ); + + if (swp_flags & SWP_NOREDRAW) + goto done; /* do not repaint anything */ + + /* expose the whole non-client area if it changed in any way */ + + if (swp_flags & SWP_NOCOPYBITS) { + frame_changed = ((swp_flags & SWP_FRAMECHANGED) || + memcmp( window_rect, &old_window_rect, sizeof(old_window_rect) )); + client_changed = memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) ); + } + else { + /* assume the bits have been moved to follow the window rect */ + int x_offset = window_rect->left - old_window_rect.left; + int y_offset = window_rect->top - old_window_rect.top; + frame_changed = ((swp_flags & SWP_FRAMECHANGED) || + window_rect->right - old_window_rect.right != x_offset || + window_rect->bottom - old_window_rect.bottom != y_offset); + client_changed = (client_rect->left - old_client_rect.left != x_offset || + client_rect->right - old_client_rect.right != x_offset || + client_rect->top - old_client_rect.top != y_offset || + client_rect->bottom - old_client_rect.bottom != y_offset || + !valid_rects || + memcmp( &valid_rects[0], client_rect, sizeof(*client_rect) )); + } + + if (frame_changed || client_changed) { + struct region *win_rgn = old_vis_rgn; /* reuse previous region */ + + set_region_rect( win_rgn, window_rect ); + if (valid_rects) { + /* subtract the valid portion of client rect from the total region */ + struct region *tmp = create_empty_region(); + if (tmp) { + set_region_rect( tmp, &valid_rects[0] ); + if (subtract_region( tmp, win_rgn, tmp )) + win_rgn = tmp; + else + free_region( tmp ); + } + } + if (!is_desktop_window(win)) + offset_region( win_rgn, -client_rect->left, -client_rect->top ); + if (exposed_rgn) { + union_region( exposed_rgn, exposed_rgn, win_rgn ); + if (win_rgn != old_vis_rgn) + free_region( win_rgn ); + } + else { + exposed_rgn = win_rgn; + if (win_rgn == old_vis_rgn) + old_vis_rgn = NULL; + } + } + + if (exposed_rgn) + redraw_window( win, exposed_rgn, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN ); + +done: + if (old_vis_rgn) + free_region( old_vis_rgn ); + if (exposed_rgn) + free_region( exposed_rgn ); + clear_error(); /* we ignore out of memory errors once the new rects have been set */ +} + +/* set the window visible rect */ +static void set_window_visible_rect( struct window *win, const rectangle_t *visible_rect, + unsigned int swp_flags ) +{ + struct region *old_vis_rgn = NULL, *exposed_rgn = NULL; + const rectangle_t old_visible_rect = win->visible_rect; + + if (!memcmp( visible_rect, &old_visible_rect, sizeof(old_visible_rect) )) + return; + + /* if the window is not visible, everything is easy */ + if (!is_visible( win ) || (swp_flags & SWP_NOREDRAW)) { + win->visible_rect = *visible_rect; + return; + } + + if (!(old_vis_rgn = get_visible_region( win, DCX_WINDOW ))) + return; + win->visible_rect = *visible_rect; + + /* expose anything revealed by the change */ + + exposed_rgn = expose_window( win, &win->window_rect, old_vis_rgn ); + if (exposed_rgn) { + /* subtract the client rect from the total window rect */ + set_region_rect( exposed_rgn, &win->window_rect ); + set_region_rect( old_vis_rgn, &win->client_rect ); + if (subtract_region( exposed_rgn, exposed_rgn, old_vis_rgn )) { + if (!is_desktop_window(win)) + offset_region( exposed_rgn, -win->client_rect.left, -win->client_rect.top ); + redraw_window( win, exposed_rgn, 1, RDW_INVALIDATE | RDW_FRAME | RDW_NOCHILDREN ); + } + free_region( exposed_rgn ); + } + free_region( old_vis_rgn ); + clear_error(); /* we ignore out of memory errors once the new rect has been set */ +} + + +/* set the window region, updating the update region if necessary */ +static void set_window_region( struct window *win, struct region *region, int redraw ) +{ + struct region *old_vis_rgn = NULL, *exposed_rgn; + + /* no need to redraw if window is not visible */ + if (redraw && !is_visible( win )) + redraw = 0; + + if (redraw) + old_vis_rgn = get_visible_region( win, DCX_WINDOW ); + + if (win->win_region) + free_region( win->win_region ); + win->win_region = region; + + /* expose anything revealed by the change */ + if (old_vis_rgn && ((exposed_rgn = expose_window( win, &win->window_rect, old_vis_rgn )))) { + redraw_window( win, exposed_rgn, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN ); + free_region( exposed_rgn ); + } + + if (old_vis_rgn) + free_region( old_vis_rgn ); + clear_error(); /* we ignore out of memory errors since the region has been set */ +} + + +/* create a window */ +DECL_HANDLER(create_window) +{ + struct window *win, *parent, *owner = NULL; + atom_t atom; + + reply->handle = 0; + + if (!req->parent) + parent = get_desktop_window( current_thread, 0 ); + else if (!(parent = get_window( req->parent ))) + return; + + if (req->owner) { + if (!(owner = get_window( req->owner ))) + return; + if (is_desktop_window(owner)) + owner = NULL; + else if (!is_desktop_window(parent)) { + /* an owned window must be created as top-level */ + set_error( STATUS_ACCESS_DENIED ); + return; + } + else /* owner must be a top-level window */ + while (!is_desktop_window(owner->parent)) + owner = owner->parent; + } + + if (get_req_data_size()) + atom = find_global_atom( NULL, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + else + atom = req->atom; + + if (!(win = create_window( parent, owner, atom, req->instance ))) + return; + + reply->handle = win->handle; + reply->parent = win->parent ? win->parent->handle : 0; + reply->owner = win->owner; + reply->extra = win->nb_extra_bytes; + reply->class_ptr = get_class_client_ptr( win->class ); +} + + +/* set the parent of a window */ +DECL_HANDLER(set_parent) +{ + struct window *win, *parent = NULL; + + if (!(win = get_window( req->handle ))) + return; + if (req->parent && !(parent = get_window( req->parent ))) + return; + + if (is_desktop_window(win)) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + reply->old_parent = win->parent->handle; + reply->full_parent = parent ? parent->handle : 0; + set_parent_window( win, parent ); +} + + +/* destroy a window */ +DECL_HANDLER(destroy_window) +{ + struct window *win = get_window( req->handle ); + if (win) { + if (!is_desktop_window(win)) + destroy_window( win ); + else if (win->thread == current_thread) + detach_window_thread( win ); + else + set_error( STATUS_ACCESS_DENIED ); + } +} + + +/* retrieve the desktop window for the current thread */ +DECL_HANDLER(get_desktop_window) +{ + struct window *win = get_desktop_window( current_thread, req->force ); + + if (win) + reply->handle = win->handle; +} + + +/* set a window owner */ +DECL_HANDLER(set_window_owner) +{ + struct window *win = get_window( req->handle ); + struct window *owner = NULL; + + if (!win) + return; + if (req->owner && !(owner = get_window( req->owner ))) + return; + if (is_desktop_window(win)) { + set_error( STATUS_ACCESS_DENIED ); + return; + } + reply->prev_owner = win->owner; + reply->full_owner = win->owner = owner ? owner->handle : 0; +} + +extern thread_id_t get_thread_id( struct w32thread *thread ); + +/* get information from a window handle */ +DECL_HANDLER(get_window_info) +{ + struct window *win = get_window( req->handle ); + + reply->full_handle = 0; + reply->tid = reply->pid = 0; + if (win) { + reply->full_handle = win->handle; + reply->last_active = win->handle; + reply->is_unicode = win->is_unicode; + if (get_user_object( win->last_active, USER_WINDOW )) + reply->last_active = win->last_active; + if (win->thread) { + reply->tid = get_thread_id( win->thread ); + reply->pid = get_process_id( win->thread->process ); + reply->atom = win->class ? get_class_atom( win->class ) : DESKTOP_ATOM; + } + } +} + + +/* set some information in a window */ +DECL_HANDLER(set_window_info) +{ + struct window *win = get_window( req->handle ); + + if (!win) + return; + if (req->flags && is_desktop_window(win) && win->thread != current_thread) { + set_error( STATUS_ACCESS_DENIED ); + return; + } + if (req->extra_size > sizeof(req->extra_value) || + req->extra_offset < -1 || + req->extra_offset > win->nb_extra_bytes - (int)req->extra_size) { + set_win32_error( ERROR_INVALID_INDEX ); + return; + } + if (req->extra_offset != -1) { + memcpy( &reply->old_extra_value, win->extra_bytes + req->extra_offset, req->extra_size ); + } + else if (req->flags & SET_WIN_EXTRA) { + set_win32_error( ERROR_INVALID_INDEX ); + return; + } + reply->old_style = win->style; + reply->old_ex_style = win->ex_style; + reply->old_id = win->id; + reply->old_instance = win->instance; + reply->old_user_data = win->user_data; + if (req->flags & SET_WIN_STYLE) + win->style = req->style; + if (req->flags & SET_WIN_EXSTYLE) { + /* WS_EX_TOPMOST can only be changed for unlinked windows */ + if (!win->is_linked) + win->ex_style = req->ex_style; + else + win->ex_style = (req->ex_style & ~WS_EX_TOPMOST) | (win->ex_style & WS_EX_TOPMOST); + } + if (req->flags & SET_WIN_ID) + win->id = req->id; + if (req->flags & SET_WIN_INSTANCE) + win->instance = req->instance; + if (req->flags & SET_WIN_UNICODE) + win->is_unicode = req->is_unicode; + if (req->flags & SET_WIN_USERDATA) + win->user_data = req->user_data; + if (req->flags & SET_WIN_EXTRA) + memcpy( win->extra_bytes + req->extra_offset, + &req->extra_value, req->extra_size ); + + /* changing window style triggers a non-client paint */ + if (req->flags & SET_WIN_STYLE) + win->paint_flags |= PAINT_NONCLIENT; +} + + +/* get a list of the window parents, up to the root of the tree */ +DECL_HANDLER(get_window_parents) +{ + struct window *ptr, *win = get_window( req->handle ); + int total = 0; + user_handle_t *data; + data_size_t len; + + if (win) + for (ptr = win->parent; ptr; ptr = ptr->parent) + total++; + + reply->count = total; + len = min( get_reply_max_size(), total * sizeof(user_handle_t) ); + if (len && ((data = set_reply_data_size( len )))) { + for (ptr = win->parent; ptr && len; ptr = ptr->parent, len -= sizeof(*data)) + *data++ = ptr->handle; + } +} + +extern struct desktop *get_desktop_obj( struct w32process *process, obj_handle_t handle, unsigned int access ); + +/* get a list of the window children */ +DECL_HANDLER(get_window_children) +{ + struct window *ptr, *parent; + int total = 0; + user_handle_t *data; + data_size_t len; + atom_t atom = req->atom; + + if (req->desktop) { + struct desktop *desktop = get_desktop_obj( get_current_w32process(), req->desktop, DESKTOP_ENUMERATE ); + if (!desktop) + return; + parent = desktop->top_window; + release_object( desktop ); + } + else + parent = get_window( req->parent ); + + if (!parent) + return; + + if (get_req_data_size()) { + atom = find_global_atom( NULL, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + if (!atom) + return; + } + + LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry ) { + if (atom && get_class_atom(ptr->class) != atom) + continue; + if (req->tid && get_thread_id(ptr->thread) != req->tid) + continue; + total++; + } + reply->count = total; + len = min( get_reply_max_size(), total * sizeof(user_handle_t) ); + if (len && ((data = set_reply_data_size( len )))) { + LIST_FOR_EACH_ENTRY( ptr, &parent->children, struct window, entry ) { + if (len < sizeof(*data)) + break; + if (atom && get_class_atom(ptr->class) != atom) + continue; + if (req->tid && get_thread_id(ptr->thread) != req->tid) + continue; + *data++ = ptr->handle; + len -= sizeof(*data); + } + } +} + + +/* get a list of the window children that contain a given point */ +DECL_HANDLER(get_window_children_from_point) +{ + struct user_handle_array array; + struct window *parent = get_window( req->parent ); + data_size_t len; + + if (!parent) + return; + + array.handles = NULL; + array.count = 0; + array.total = 0; + if (!all_windows_from_point( parent, req->x, req->y, &array )) + return; + + reply->count = array.count; + len = min( get_reply_max_size(), array.count * sizeof(user_handle_t) ); + if (len) + set_reply_data_ptr( array.handles, len ); + else + free( array.handles ); +} + + +/* get window tree information from a window handle */ +DECL_HANDLER(get_window_tree) +{ + struct window *ptr, *win = get_window( req->handle ); + + if (!win) + return; + + reply->parent = 0; + reply->owner = 0; + reply->next_sibling = 0; + reply->prev_sibling = 0; + reply->first_sibling = 0; + reply->last_sibling = 0; + reply->first_child = 0; + reply->last_child = 0; + + if (win->parent) { + struct window *parent = win->parent; + reply->parent = parent->handle; + reply->owner = win->owner; + if (win->is_linked) { + if ((ptr = get_next_window( win ))) + reply->next_sibling = ptr->handle; + if ((ptr = get_prev_window( win ))) + reply->prev_sibling = ptr->handle; + } + if ((ptr = get_first_child( parent ))) + reply->first_sibling = ptr->handle; + if ((ptr = get_last_child( parent ))) + reply->last_sibling = ptr->handle; + } + if ((ptr = get_first_child( win ))) + reply->first_child = ptr->handle; + if ((ptr = get_last_child( win ))) + reply->last_child = ptr->handle; +} + + +/* set the position and Z order of a window */ +DECL_HANDLER(set_window_pos) +{ + const rectangle_t *valid_rects = NULL; + struct window *previous = NULL; + struct window *win = get_window( req->handle ); + unsigned int flags = req->flags; + + if (!win) + return; + if (!win->parent) + flags |= SWP_NOZORDER; /* no Z order for the desktop */ + + if (!(flags & SWP_NOZORDER)) { + switch ((int)(unsigned long)req->previous) { + case 0: /* HWND_TOP */ + previous = WINPTR_TOP; + break; + case 1: /* HWND_BOTTOM */ + previous = WINPTR_BOTTOM; + break; + case -1: /* HWND_TOPMOST */ + previous = WINPTR_TOPMOST; + break; + case -2: /* HWND_NOTOPMOST */ + previous = WINPTR_NOTOPMOST; + break; + default: + if (!(previous = get_window( req->previous ))) + return; + /* previous must be a sibling */ + if (previous->parent != win->parent) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + break; + } + if (previous == win) + flags |= SWP_NOZORDER; /* nothing to do */ + } + + /* window rectangle must be ordered properly */ + if (req->window.right < req->window.left || req->window.bottom < req->window.top) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (get_req_data_size() >= 2 * sizeof(rectangle_t)) + valid_rects = get_req_data(); + set_window_pos( win, previous, flags, &req->window, &req->client, valid_rects ); + reply->new_style = win->style; + reply->new_ex_style = win->ex_style; + reply->visible = win->visible_rect; +} + + +/* set the visible rectangle of a window */ +DECL_HANDLER(set_window_visible_rect) +{ + struct window *win = get_window( req->handle ); + if (win) + set_window_visible_rect( win, &req->visible, req->flags ); +} + + +/* get the window and client rectangles of a window */ +DECL_HANDLER(get_window_rectangles) +{ + struct window *win = get_window( req->handle ); + + if (win) { + reply->window = win->window_rect; + reply->visible = win->visible_rect; + reply->client = win->client_rect; + } +} + + +/* get the window text */ +DECL_HANDLER(get_window_text) +{ + struct window *win = get_window( req->handle ); + + if (win && win->text) { + data_size_t len = strlenW( win->text ) * sizeof(WCHAR); + if (len > get_reply_max_size()) + len = get_reply_max_size(); + set_reply_data( win->text, len ); + } +} + + +/* set the window text */ +DECL_HANDLER(set_window_text) +{ + struct window *win = get_window( req->handle ); + + if (win) { + WCHAR *text = NULL; + data_size_t len = get_req_data_size() / sizeof(WCHAR); + if (len) { + if (!(text = mem_alloc( (len+1) * sizeof(WCHAR) ))) + return; + memcpy( text, get_req_data(), len * sizeof(WCHAR) ); + text[len] = 0; + } + free( win->text ); + win->text = text; + } +} + + +/* get the coordinates offset between two windows */ +DECL_HANDLER(get_windows_offset) +{ + struct window *win; + + reply->x = reply->y = 0; + if (req->from) { + if (!(win = get_window( req->from ))) + return; + while (win && !is_desktop_window(win)) { + reply->x += win->client_rect.left; + reply->y += win->client_rect.top; + win = win->parent; + } + } + if (req->to) { + if (!(win = get_window( req->to ))) + return; + while (win && !is_desktop_window(win)) { + reply->x -= win->client_rect.left; + reply->y -= win->client_rect.top; + win = win->parent; + } + } +} + + +/* get the visible region of a window */ +DECL_HANDLER(get_visible_region) +{ + struct region *region; + struct window *top, *win = get_window( req->window ); + + if (!win) + return; + + top = get_top_clipping_window( win ); + if ((region = get_visible_region( win, req->flags ))) { + rectangle_t *data; + map_win_region_to_screen( win, region ); + data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size ); + if (data) + set_reply_data_ptr( data, reply->total_size ); + } + reply->top_win = top->handle; + reply->top_rect = (top == win && (req->flags & DCX_WINDOW)) ? top->visible_rect : top->client_rect; + + if (!is_desktop_window(win)) { + reply->win_rect = (req->flags & DCX_WINDOW) ? win->window_rect : win->client_rect; + client_to_screen_rect( top->parent, &reply->top_rect ); + client_to_screen_rect( win->parent, &reply->win_rect ); + } + else { + reply->win_rect.left = 0; + reply->win_rect.top = 0; + reply->win_rect.right = win->client_rect.right - win->client_rect.left; + reply->win_rect.bottom = win->client_rect.bottom - win->client_rect.top; + } +} + + +/* get the window region */ +DECL_HANDLER(get_window_region) +{ + struct window *win = get_window( req->window ); + + if (!win) + return; + + if (win->win_region) { + rectangle_t *data = get_region_data( win->win_region, get_reply_max_size(), &reply->total_size ); + if (data) + set_reply_data_ptr( data, reply->total_size ); + } +} + + +/* set the window region */ +DECL_HANDLER(set_window_region) +{ + struct region *region = NULL; + struct window *win = get_window( req->window ); + + if (!win) + return; + + if (get_req_data_size()) { /* no data means remove the region completely */ + if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() ))) + return; + } + set_window_region( win, region, req->redraw ); +} + + +/* get a window update region */ +DECL_HANDLER(get_update_region) +{ + rectangle_t *data; + unsigned int flags = req->flags; + struct window *from_child = NULL; + struct window *win = get_window( req->window ); + + reply->flags = 0; + if (!win) + return; + + if (req->from_child) { + struct window *ptr; + + if (!(from_child = get_window( req->from_child ))) + return; + + /* make sure from_child is a child of win */ + ptr = from_child; + while (ptr && ptr != win) + ptr = ptr->parent; + if (!ptr) { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + } + + if (flags & UPDATE_DELAYED_ERASE) { /* this means that the previous call didn't erase */ + if (from_child) + from_child->paint_flags |= PAINT_DELAYED_ERASE; + else + win->paint_flags |= PAINT_DELAYED_ERASE; + } + + reply->flags = get_window_update_flags( win, from_child, flags, &win ); + reply->child = win->handle; + + if (flags & UPDATE_NOREGION) + return; + + if (win->update_region) { + /* convert update region to screen coordinates */ + struct region *region = create_empty_region(); + + if (!region) + return; + if (!copy_region( region, win->update_region )) { + free_region( region ); + return; + } + map_win_region_to_screen( win, region ); + if (!(data = get_region_data_and_free( region, get_reply_max_size(), + &reply->total_size ))) + return; + set_reply_data_ptr( data, reply->total_size ); + } + + if (reply->flags & (UPDATE_PAINT|UPDATE_INTERNALPAINT)) { /* validate everything */ + validate_parents( win ); + validate_whole_window( win ); + } + else { + if (reply->flags & UPDATE_NONCLIENT) + validate_non_client( win ); + if (reply->flags & UPDATE_ERASE) { + win->paint_flags &= ~(PAINT_ERASE | PAINT_DELAYED_ERASE); + /* desktop window only gets erased, not repainted */ + if (is_desktop_window(win)) + validate_whole_window( win ); + } + } +} + + +/* update the z order of a window so that a given rectangle is fully visible */ +DECL_HANDLER(update_window_zorder) +{ + rectangle_t tmp; + struct window *ptr, *win = get_window( req->window ); + + if (!win || !win->parent || !is_visible( win )) + return; /* nothing to do */ + + LIST_FOR_EACH_ENTRY( ptr, &win->parent->children, struct window, entry ) { + if (ptr == win) + break; + if (!(ptr->style & WS_VISIBLE)) + continue; + if (ptr->ex_style & WS_EX_TRANSPARENT) + continue; + if (!intersect_rect( &tmp, &ptr->visible_rect, &req->rect )) + continue; + if (ptr->win_region && !rect_in_region( ptr->win_region, &req->rect )) + continue; + /* found a window obscuring the rectangle, now move win above this one */ + /* making sure to not violate the topmost rule */ + if (!(ptr->ex_style & WS_EX_TOPMOST) || (win->ex_style & WS_EX_TOPMOST)) { + list_remove( &win->entry ); + list_add_before( &ptr->entry, &win->entry ); + } + break; + } +} + +/* mark parts of a window as needing a redraw */ +DECL_HANDLER(redraw_window) +{ + struct region *region = NULL; + struct window *win = get_window( req->window ); + + if (!win) + return; + if (!is_visible( win )) + return; /* nothing to do */ + + if (req->flags & (RDW_VALIDATE|RDW_INVALIDATE)) { + if (get_req_data_size()) { /* no data means whole rectangle */ + if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() ))) + return; + } + } + + redraw_window( win, region, (req->flags & RDW_INVALIDATE) && (req->flags & RDW_FRAME), + req->flags ); + if (region) + free_region( region ); +} + + +/* set a window property */ +DECL_HANDLER(set_window_property) +{ + struct window *win = get_window( req->window ); + + if (!win) + return; + + if (get_req_data_size()) { + atom_t atom = add_global_atom( NULL, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + if (atom) { + set_property( win, atom, req->handle, PROP_TYPE_STRING ); + release_global_atom( NULL, atom ); + } + } + else + set_property( win, req->atom, req->handle, PROP_TYPE_ATOM ); +} + + +/* remove a window property */ +DECL_HANDLER(remove_window_property) +{ + struct window *win = get_window( req->window ); + + if (win) { + atom_t atom = req->atom; + if (get_req_data_size()) + atom = find_global_atom( NULL, get_req_data(), + get_req_data_size() / sizeof(WCHAR) ); + if (atom) + reply->handle = remove_property( win, atom ); + } +} + + +/* get a window property */ +DECL_HANDLER(get_window_property) +{ + struct window *win = get_window( req->window ); + + if (win) { + atom_t atom = req->atom; + if (get_req_data_size()) + atom = find_global_atom( NULL, get_req_data(), + get_req_data_size() / sizeof(WCHAR) ); + if (atom) + reply->handle = get_property( win, atom ); + } +} + + +/* get the list of properties of a window */ +DECL_HANDLER(get_window_properties) +{ + property_data_t *data; + int i, count, max = get_reply_max_size() / sizeof(*data); + struct window *win = get_window( req->window ); + + reply->total = 0; + if (!win) + return; + + for (i = count = 0; i < win->prop_inuse; i++) + if (win->properties[i].type != PROP_TYPE_FREE) + count++; + reply->total = count; + + if (count > max) + count = max; + if (!count || !(data = set_reply_data_size( count * sizeof(*data) ))) + return; + + for (i = 0; i < win->prop_inuse && count; i++) { + if (win->properties[i].type == PROP_TYPE_FREE) + continue; + data->atom = win->properties[i].atom; + data->string = (win->properties[i].type == PROP_TYPE_STRING); + data->handle = win->properties[i].handle; + data++; + count--; + } +} + +/* get the new window pointer for a global window, checking permissions */ +/* helper for set_global_windows request */ +static int get_new_global_window( struct window **win, user_handle_t handle ) +{ + if (!handle) { + *win = NULL; + return 1; + } + else if (*win) { + set_error( STATUS_ACCESS_DENIED ); + return 0; + } + *win = get_window( handle ); + return (*win != NULL); +} + +/* Set/get the global windows */ +DECL_HANDLER(set_global_windows) +{ + struct window *new_shell_window = shell_window; + struct window *new_shell_listview = shell_listview; + struct window *new_progman_window = progman_window; + struct window *new_taskman_window = taskman_window; + + reply->old_shell_window = shell_window ? shell_window->handle : 0; + reply->old_shell_listview = shell_listview ? shell_listview->handle : 0; + reply->old_progman_window = progman_window ? progman_window->handle : 0; + reply->old_taskman_window = taskman_window ? taskman_window->handle : 0; + + if (req->flags & SET_GLOBAL_SHELL_WINDOWS) { + if (!get_new_global_window( &new_shell_window, req->shell_window )) + return; + if (!get_new_global_window( &new_shell_listview, req->shell_listview )) + return; + } + if (req->flags & SET_GLOBAL_PROGMAN_WINDOW) { + if (!get_new_global_window( &new_progman_window, req->progman_window )) + return; + } + if (req->flags & SET_GLOBAL_TASKMAN_WINDOW) { + if (!get_new_global_window( &new_taskman_window, req->taskman_window )) + return; + } + shell_window = new_shell_window; + shell_listview = new_shell_listview; + progman_window = new_progman_window; + taskman_window = new_taskman_window; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/msg/winstation.c b/unifiedkernel/msg/winstation.c new file mode 100644 index 0000000..3ed2fd6 --- /dev/null +++ b/unifiedkernel/msg/winstation.c @@ -0,0 +1,811 @@ +/* + * winstation.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * winstation.c: + * Refered to Wine code + */ +#define WIN32_NO_STATUS + +#include +#include +#include + +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +static struct list_head winstation_list = LIST_INIT(winstation_list); +static struct namespace *winstation_namespace; + +static void winstation_dump( struct object *obj, int verbose ); +static struct object_type *winstation_get_type( struct object *obj ); +static int winstation_close_handle( struct object *obj, struct w32process *process, obj_handle_t handle ); +static void winstation_destroy( struct object *obj ); +static unsigned int winstation_map_access( struct object *obj, unsigned int access ); +static void desktop_dump( struct object *obj, int verbose ); +static struct object_type *desktop_get_type( struct object *obj ); +static int desktop_close_handle( struct object *obj, struct w32process *process, obj_handle_t handle ); +static void desktop_destroy( struct object *obj ); +static unsigned int desktop_map_access( struct object *obj, unsigned int access ); + +static const struct object_ops winstation_ops = +{ + sizeof(struct winstation), /* size */ + winstation_dump, /* dump */ + winstation_get_type, /* get_type */ + no_get_fd, /* get_fd */ + winstation_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + winstation_close_handle, /* close_handle */ + winstation_destroy /* destroy */ +}; + + +static const struct object_ops desktop_ops = +{ + sizeof(struct desktop), /* size */ + desktop_dump, /* dump */ + desktop_get_type, /* get_type */ + no_get_fd, /* get_fd */ + desktop_map_access, /* map_access */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + desktop_close_handle, /* close_handle */ + desktop_destroy /* destroy */ +}; + +#define DESKTOP_ALL_ACCESS 0x01ff + +/* create a winstation object */ +static struct winstation *create_winstation( const struct unicode_str *name, unsigned int attr, + unsigned int flags ) +{ + struct winstation *winstation; + + if (!winstation_namespace && !(winstation_namespace = create_namespace( 7 ))) + return NULL; + + if (memchrW( name->str, '\\', name->len / sizeof(WCHAR) )) { /* no backslash allowed in name */ + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + } + + if ((winstation = create_named_object( winstation_namespace, &winstation_ops, name, attr ))) { /* D.M. TBD */ + if (get_error() != STATUS_OBJECT_NAME_EXISTS) { + /* initialize it if it didn't already exist */ + winstation->flags = flags; + winstation->clipboard = NULL; + winstation->atom_table = NULL; + my_list_add_tail( &winstation_list, &winstation->entry ); + my_list_init( &winstation->desktops ); + } + } + return winstation; +} + +static void winstation_dump( struct object *obj, int verbose ) +{ + struct winstation *winstation = (struct winstation *)obj; + + ktrace( "Winstation flags=%x clipboard=%p atoms=%p ", + winstation->flags, winstation->clipboard, winstation->atom_table ); + dump_object_name( &winstation->obj ); + ktrace( "\n"); +} + +extern struct object_type *get_object_type( const struct unicode_str* ); + +static struct object_type *winstation_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'W','i','n','d','o','w','S','t','a','t','i','o','n'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +static int winstation_close_handle( struct object *obj, struct w32process *process, obj_handle_t handle ) +{ + return (process->winstation != handle); +} + +static void winstation_destroy( struct object *obj ) +{ + struct winstation *winstation = (struct winstation *)obj; + + list_remove( &winstation->entry ); + if (winstation->clipboard) + release_object( winstation->clipboard ); + if (winstation->atom_table) + release_object( winstation->atom_table ); +} + +static unsigned int winstation_map_access( struct object *obj, unsigned int access ) +{ + if (access & GENERIC_READ) + access |= STANDARD_RIGHTS_READ | WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | + WINSTA_ENUMERATE | WINSTA_READSCREEN; + if (access & GENERIC_WRITE) + access |= STANDARD_RIGHTS_WRITE | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | + WINSTA_WRITEATTRIBUTES; + if (access & GENERIC_EXECUTE) + access |= STANDARD_RIGHTS_EXECUTE | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS; + if (access & GENERIC_ALL) + access |= STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +extern void *get_wine_handle_obj(struct w32process*, HANDLE, unsigned int, const struct object_ops* ); /* D.M. TBD */ + +/* retrieve the process window station, checking the handle access rights */ +struct winstation *get_process_winstation( struct w32process *process, unsigned int access ) +{ + return (struct winstation *)get_wine_handle_obj( process, process->winstation, + access, &winstation_ops ); +} + +/* build the full name of a desktop object */ +static WCHAR *build_desktop_name( const struct unicode_str *name, + struct winstation *winstation, struct unicode_str *res ) +{ + const WCHAR *winstation_name; + WCHAR *full_name; + data_size_t winstation_len; + + if (memchrW( name->str, '\\', name->len / sizeof(WCHAR) )) { + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + } + + if (!(winstation_name = get_object_name( &winstation->obj, &winstation_len ))) + winstation_len = 0; + + res->len = winstation_len + name->len + sizeof(WCHAR); + if (!(full_name = mem_alloc( res->len ))) + return NULL; + memcpy( full_name, winstation_name, winstation_len ); + full_name[winstation_len / sizeof(WCHAR)] = '\\'; + memcpy( full_name + winstation_len / sizeof(WCHAR) + 1, name->str, name->len ); + res->str = full_name; + return full_name; +} + +/* retrieve a pointer to a desktop object */ +struct desktop *get_desktop_obj( struct w32process *process, obj_handle_t handle, unsigned int access ) +{ + return (struct desktop *)get_wine_handle_obj( process, handle, access, &desktop_ops ); +} + +/* create a desktop object */ +static struct desktop *create_desktop( const struct unicode_str *name, unsigned int attr, + unsigned int flags, struct winstation *winstation ) +{ + struct desktop *desktop; + struct unicode_str full_str; + WCHAR *full_name; + + if (!(full_name = build_desktop_name( name, winstation, &full_str ))) + return NULL; + + if ((desktop = create_named_object( winstation_namespace, &desktop_ops, &full_str, attr ))) { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) { + /* initialize it if it didn't already exist */ + desktop->flags = flags; + desktop->winstation = (struct winstation *)grab_object( winstation ); + desktop->top_window = NULL; + desktop->global_hooks = NULL; + desktop->close_timeout = NULL; + desktop->users = 0; + my_list_add_tail( &winstation->desktops, &desktop->entry ); + } + } + free( full_name ); + return desktop; +} + +static void desktop_dump( struct object *obj, int verbose ) +{ + struct desktop *desktop = (struct desktop *)obj; + + ktrace( "Desktop flags=%x winstation=%p top_win=%p hooks=%p ", + desktop->flags, desktop->winstation, desktop->top_window, desktop->global_hooks ); + dump_object_name( &desktop->obj ); + ktrace( "\n"); +} + +static struct object_type *desktop_get_type( struct object *obj ) +{ + static const WCHAR name[] = {'D','e','s','k','t','o','p'}; + static const struct unicode_str str = { name, sizeof(name) }; + return get_object_type( &str ); +} + +static int desktop_close_handle( struct object *obj, struct w32process *process, obj_handle_t handle ) +{ + struct w32thread *thread; +#ifdef SERVER_PM + struct eprocess *eprocess = process2eprocess(process); + struct ethread * ethread; +#endif + + /* check if the handle is currently used by the process or one of its threads */ + if (process->desktop == handle) + return 0; +#ifndef SERVER_PM + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct w32thread, proc_entry ) + if (thread->desktop == handle) + return 0; +#else + LIST_FOR_EACH_ENTRY( ethread, &eprocess->thread_list_head, struct ethread, thread_list_entry) { + thread = ethread->tcb.win32thread; + if (thread->desktop == handle) + return 0; + } +#endif + return 1; +} + +static void desktop_destroy( struct object *obj ) +{ + struct desktop *desktop = (struct desktop *)obj; + + if (desktop->top_window) + destroy_window( desktop->top_window ); + if (desktop->global_hooks) + release_object( desktop->global_hooks ); + if (desktop->close_timeout) + remove_timeout_user( desktop->close_timeout ); + list_remove( &desktop->entry ); + release_object( desktop->winstation ); +} + +static unsigned int desktop_map_access( struct object *obj, unsigned int access ) +{ + if (access & GENERIC_READ) + access |= STANDARD_RIGHTS_READ | DESKTOP_READOBJECTS | DESKTOP_ENUMERATE; + if (access & GENERIC_WRITE) + access |= STANDARD_RIGHTS_WRITE | DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | + DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | + DESKTOP_WRITEOBJECTS; + if (access & GENERIC_EXECUTE) + access |= STANDARD_RIGHTS_EXECUTE | DESKTOP_SWITCHDESKTOP; + if (access & GENERIC_ALL) + access |= STANDARD_RIGHTS_REQUIRED | DESKTOP_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +/* retrieve the thread desktop, checking the handle access rights */ +struct desktop *get_thread_desktop( struct w32thread *thread, unsigned int access ) +{ + return get_desktop_obj( thread->process, thread->desktop, access ); +} + +extern void clear_error(void); + +/* set the process default desktop handle */ +void set_process_default_desktop( struct w32process *process, struct desktop *desktop, + obj_handle_t handle ) +{ + struct w32thread *thread; + struct desktop *old_desktop; +#ifdef SERVER_PM + struct eprocess *eprocess = process2eprocess(process); + struct ethread * ethread; +#endif + + if (process->desktop == handle) + return; /* nothing to do */ + + if (!(old_desktop = get_desktop_obj( process, process->desktop, 0 ))) + clear_error(); + process->desktop = handle; + + /* set desktop for threads that don't have one yet */ +#ifndef SERVER_PM + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct w32thread, proc_entry ) + if (!thread->desktop) + thread->desktop = handle; +#else + LIST_FOR_EACH_ENTRY( ethread, &eprocess->thread_list_head, struct ethread, thread_list_entry) { + thread = ethread->tcb.win32thread; + if (!thread->desktop) thread->desktop = handle; + } +#endif + + if (!process->is_system) { + desktop->users++; + if (desktop->close_timeout) { + remove_timeout_user( desktop->close_timeout ); + desktop->close_timeout = NULL; + } + if (old_desktop) + old_desktop->users--; + } + + if (old_desktop) + release_object( old_desktop ); +} + +/* connect a process to its window station */ +void connect_process_winstation( struct w32process *process, struct w32thread *parent ) +{ + struct winstation *winstation = NULL; + struct desktop *desktop = NULL; + obj_handle_t handle; + + /* check for an inherited winstation handle (don't ask...) */ + if ((handle = find_inherited_handle( process, &winstation_ops ))) { + winstation = (struct winstation *)get_wine_handle_obj( process, handle, 0, &winstation_ops ); + } + else if (parent && parent->process->winstation) { + handle = duplicate_handle( parent->process, parent->process->winstation, + process, 0, 0, DUP_HANDLE_SAME_ACCESS ); + winstation = (struct winstation *)get_wine_handle_obj( process, handle, 0, &winstation_ops ); + } + if (!winstation) + goto done; + process->winstation = handle; + + if ((handle = find_inherited_handle( process, &desktop_ops ))) { + desktop = get_desktop_obj( process, handle, 0 ); + if (!desktop || desktop->winstation != winstation) + goto done; + } + else if (parent && parent->desktop) { + desktop = get_desktop_obj( parent->process, parent->desktop, 0 ); + if (!desktop || desktop->winstation != winstation) + goto done; + handle = duplicate_handle( parent->process, parent->desktop, + process, 0, 0, DUP_HANDLE_SAME_ACCESS ); + } + + if (handle) + set_process_default_desktop( process, desktop, handle ); + +done: + if (desktop) + release_object( desktop ); + if (winstation) + release_object( winstation ); + clear_error(); +} + +static void close_desktop_timeout( void *private ) +{ + struct desktop *desktop = private; + + desktop->close_timeout = NULL; + unlink_named_object( &desktop->obj ); /* make sure no other process can open it */ + close_desktop_window( desktop ); /* and signal the owner to quit */ +} + +/* close the desktop of a given process */ +void close_process_desktop( struct w32process *process ) +{ + struct desktop *desktop; + + if (process->desktop && (desktop = get_desktop_obj( process, process->desktop, 0 ))) { +#if 0 + assert( desktop->users > 0 ); +#endif + desktop->users--; + /* if we have one remaining user, it has to be the manager of the desktop window */ + if (desktop->users == 1 && get_top_window_owner( desktop )) { +#if 0 + assert( !desktop->close_timeout ); +#endif + desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop ); + } + release_object( desktop ); + } + clear_error(); /* ignore errors */ +} + +/* close the desktop of a given thread */ +void close_thread_desktop( struct w32thread *thread ) +{ + obj_handle_t handle = thread->desktop; + + thread->desktop = 0; + if (handle) + close_handle( /*thread->process*/NULL, handle ); /* D.M. TBD */ + clear_error(); /* ignore errors */ +} + +/* set the reply data from the object name */ +static void set_reply_data_obj_name( struct object *obj ) +{ + data_size_t len; + const WCHAR *ptr, *name = get_object_name( obj, &len ); + + /* if there is a backslash return the part of the name after it */ + if (name && (ptr = memchrW( name, '\\', len/sizeof(WCHAR) ))) { + len -= (ptr + 1 - name) * sizeof(WCHAR); + name = ptr + 1; + } + if (name) + set_reply_data( name, min( len, get_reply_max_size() )); +} + +/* create a window station */ +DECL_HANDLER(create_winstation) +{ + struct winstation *winstation; + struct unicode_str name; + + reply->handle = 0; + get_req_unicode_str( &name ); + if ((winstation = create_winstation( &name, req->attributes, req->flags ))) { + reply->handle = alloc_handle( get_current_w32process(), winstation, req->access, req->attributes ); + release_object( winstation ); + } +} + +extern HANDLE open_object(HANDLE RootDirectory, const struct unicode_str *name, + const struct object_ops*, unsigned int access, unsigned int attr); + +/* open a handle to a window station */ +DECL_HANDLER(open_winstation) +{ + struct unicode_str name; + + get_req_unicode_str( &name ); + if (winstation_namespace) + reply->handle = open_object( winstation_namespace, &name, &winstation_ops, req->access, + req->attributes ); + else + set_error( STATUS_OBJECT_NAME_NOT_FOUND ); +} + + +/* close a window station */ +DECL_HANDLER(close_winstation) +{ + struct winstation *winstation; + + if ((winstation = (struct winstation *)get_wine_handle_obj( get_current_w32process(), req->handle, + 0, &winstation_ops ))) { + if (!close_handle( /*get_current_w32process()*/NULL, req->handle )) + set_error( STATUS_ACCESS_DENIED ); /* D.M. TBD */ + release_object( winstation ); + } +} + + +/* get the process current window station */ +DECL_HANDLER(get_process_winstation) +{ + reply->handle = get_current_w32process()->winstation; +} + + +/* set the process current window station */ +DECL_HANDLER(set_process_winstation) +{ + struct winstation *winstation; + + if ((winstation = (struct winstation *)get_wine_handle_obj( get_current_w32process(), req->handle, + 0, &winstation_ops ))) { + /* FIXME: should we close the old one? */ + get_current_w32process()->winstation = req->handle; + release_object( winstation ); + } +} + +/* create a desktop */ +DECL_HANDLER(create_desktop) +{ + struct desktop *desktop; + struct winstation *winstation; + struct unicode_str name; + + reply->handle = 0; + get_req_unicode_str( &name ); + if ((winstation = get_process_winstation( get_current_w32process(), WINSTA_CREATEDESKTOP ))) { + if ((desktop = create_desktop( &name, req->attributes, req->flags, winstation ))) { + reply->handle = alloc_handle( get_current_w32process(), desktop, req->access, req->attributes ); + release_object( desktop ); + } + release_object( winstation ); + } +} + +/* open a handle to a desktop */ +DECL_HANDLER(open_desktop) +{ + struct winstation *winstation; + struct unicode_str name; + + get_req_unicode_str( &name ); + + /* FIXME: check access rights */ + if (!req->winsta) + winstation = get_process_winstation( get_current_w32process(), 0 ); + else + winstation = (struct winstation *)get_wine_handle_obj( get_current_w32process(), req->winsta, 0, &winstation_ops ); + + if (winstation) { + struct unicode_str full_str; + WCHAR *full_name; + + if ((full_name = build_desktop_name( &name, winstation, &full_str ))) { + reply->handle = open_object( winstation_namespace, &full_str, &desktop_ops, req->access, + req->attributes ); + free( full_name ); + } + release_object( winstation ); + } +} + + +/* close a desktop */ +DECL_HANDLER(close_desktop) +{ + struct desktop *desktop; + + /* make sure it is a desktop handle */ + if ((desktop = (struct desktop *)get_wine_handle_obj( get_current_w32process(), req->handle, + 0, &desktop_ops ))) { + if (!close_handle( /*current->process*/NULL, req->handle )) + set_error( STATUS_DEVICE_BUSY ); /* D.M. TBD */ + release_object( desktop ); + } +} + + +/* get the thread current desktop */ +DECL_HANDLER(get_thread_desktop) +{ + struct w32thread *thread; + + if (!(thread = get_thread_from_id( req->tid ))) + return; + reply->handle = thread->desktop; + release_object( thread ); +} + +extern struct msg_queue *get_current_queue(void); + +/* set the thread current desktop */ +DECL_HANDLER(set_thread_desktop) +{ + struct desktop *old_desktop, *new_desktop; + struct winstation *winstation; + + if (!(winstation = get_process_winstation( get_current_w32process(), 0 /* FIXME: access rights? */ ))) + return; + + if (!(new_desktop = get_desktop_obj( get_current_w32process(), req->handle, 0 ))) { + release_object( winstation ); + return; + } + if (new_desktop->winstation != winstation) { + set_error( STATUS_ACCESS_DENIED ); + release_object( new_desktop ); + release_object( winstation ); + return; + } + + /* check if we are changing to a new desktop */ + + if (!(old_desktop = get_desktop_obj( get_current_w32process(), /*current->desktop*/0, 0))) + clear_error(); /* ignore error */ + + /* when changing desktop, we can't have any users on the current one */ + if (old_desktop != new_desktop && current_thread->desktop_users > 0) + set_error( STATUS_DEVICE_BUSY ); + else { + current_thread->desktop = req->handle; /* FIXME: should we close the old one? */ + } + + if (!get_current_w32process()->desktop) + set_process_default_desktop( get_current_w32process(), new_desktop, req->handle ); + + if (old_desktop != new_desktop && /* current->queue */ get_current_queue()) + detach_thread_input( current_thread ); /* D.M. TBD */ + + if (old_desktop) + release_object( old_desktop ); + release_object( new_desktop ); + release_object( winstation ); +} + + +/* get/set information about a user object (window station or desktop) */ +DECL_HANDLER(set_user_object_info) +{ + struct object *obj; + + if (!(obj = get_wine_handle_obj( get_current_w32process(), req->handle, 0, NULL ))) + return; + + if (BODY_TO_HEADER(obj)->ops == &desktop_ops) { + struct desktop *desktop = (struct desktop *)obj; + reply->is_desktop = 1; + reply->old_obj_flags = desktop->flags; + if (req->flags & SET_USER_OBJECT_FLAGS) + desktop->flags = req->obj_flags; + } + else if (BODY_TO_HEADER(obj)->ops == &winstation_ops) { + struct winstation *winstation = (struct winstation *)obj; + reply->is_desktop = 0; + reply->old_obj_flags = winstation->flags; + if (req->flags & SET_USER_OBJECT_FLAGS) + winstation->flags = req->obj_flags; + } + else { + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + release_object( obj ); + return; + } + if (get_reply_max_size()) + set_reply_data_obj_name( obj ); + release_object( obj ); +} + +extern BOOL check_object_access(struct object*, unsigned int*); + +/* enumerate window stations */ +DECL_HANDLER(enum_winstation) +{ + unsigned int index = 0; + struct winstation *winsta; + + LIST_FOR_EACH_ENTRY( winsta, &winstation_list, struct winstation, entry ) { + unsigned int access = WINSTA_ENUMERATE; + if (req->index > index++) + continue; + if (!check_object_access( &winsta->obj, &access )) + continue; + set_reply_data_obj_name( &winsta->obj ); + clear_error(); + reply->next = index; + return; + } + set_error( STATUS_NO_MORE_ENTRIES ); +} + + +/* enumerate desktops */ +DECL_HANDLER(enum_desktop) +{ + struct winstation *winstation; + struct desktop *desktop; + unsigned int index = 0; + + if (!(winstation = (struct winstation *)get_wine_handle_obj( get_current_w32process(), req->winstation, + WINSTA_ENUMDESKTOPS, &winstation_ops ))) + return; + + LIST_FOR_EACH_ENTRY( desktop, &winstation->desktops, struct desktop, entry ) { + unsigned int access = DESKTOP_ENUMERATE; + if (req->index > index++) + continue; + if (!HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(desktop))) + continue; + if (!check_object_access( &desktop->obj, &access )) + continue; + set_reply_data_obj_name( &desktop->obj ); + release_object( winstation ); + clear_error(); + reply->next = index; + return; + } + + release_object( winstation ); + set_error( STATUS_NO_MORE_ENTRIES ); +} + +struct namespace +{ + unsigned int hash_size; /* size of hash table */ + struct list_head names[1]; /* array of hash entry lists */ +}; + + +/* allocate a namespace */ +struct namespace *create_namespace( unsigned int hash_size ) +{ + struct namespace *namespace; + unsigned int i; + + namespace = (struct namespace*)mem_alloc( sizeof(*namespace) + (hash_size - 1) * sizeof(namespace->names[0]) ); + if (namespace) { + namespace->hash_size = hash_size; + for (i = 0; i < hash_size; i++) + my_list_init( &namespace->names[i] ); + } + return namespace; +} + +struct object_name +{ + struct list_head entry; /* entry in the hash list */ + struct object *obj; /* object owning this name */ + struct object *parent; /* parent object */ + data_size_t len; /* name length in bytes */ + WCHAR name[1]; +}; + +#if 0 +static void free_name( struct object *obj ) +{ + struct object_name *ptr = obj->name; + list_remove( &ptr->entry ); + if (ptr->parent) + release_object( ptr->parent ); + free( ptr ); +} +#endif + +/* unlink a named object from its namespace, without freeing the object itself */ +void unlink_named_object( struct object *obj ) +{ +#if 0 + if (obj->name) + free_name( obj ); + obj->name = NULL; +#endif +} + +void *create_named_object( HANDLE namespace, const struct object_ops *ops, + const struct unicode_str *name, unsigned int attributes ) +{ + struct object *obj; + + if (!name || !name->len) + return alloc_wine_object( ops ); + + if ((obj = find_object( namespace, name, attributes ))) { + if (attributes & OBJ_OPENIF && BODY_TO_HEADER(obj)->ops == ops) + set_error( STATUS_OBJECT_NAME_EXISTS ); + else { + release_object( obj ); + obj = NULL; + if (attributes & OBJ_OPENIF) + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + else + set_error( STATUS_OBJECT_NAME_COLLISION ); + } + return obj; + } + if ((obj = create_wine_object( namespace, ops, name, NULL ))) + clear_error(); + return obj; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/ob/Makefile b/unifiedkernel/ob/Makefile new file mode 100644 index 0000000..2b437cd --- /dev/null +++ b/unifiedkernel/ob/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for object management +# + +OB_OBJS += wait.o \ + dirobj.o \ + display.o \ + handle.o \ + namespc.o \ + object.o \ + symlink.o \ + ntobj.o + +$(MODULE)-objs += $(addprefix ob/, $(OB_OBJS)) diff --git a/unifiedkernel/ob/dirobj.c b/unifiedkernel/ob/dirobj.c new file mode 100644 index 0000000..803ddb0 --- /dev/null +++ b/unifiedkernel/ob/dirobj.c @@ -0,0 +1,356 @@ +/* + * dirobj.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * dirobj.c: + * Refered to ReactOS code + */ +#include "object.h" +#include "handle.h" +#include "unistr.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +#define DIRECTORY_QUERY (0x0001) + +NTSTATUS SERVICECALL +NtCreateDirectoryObject(OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + POBJECT_DIRECTORY Directory; + HANDLE hDirectory; + OBJECT_ATTRIBUTES obj_attr; + UNICODE_STRING obj_name; + KPROCESSOR_MODE PreviousMode = KernelMode; + NTSTATUS Status = STATUS_SUCCESS; + + if ((ULONG)ObjectAttributes < TASK_SIZE) { + if ((copy_from_user(&obj_attr, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)))) + return STATUS_NO_MEMORY; + if ((copy_from_user(&obj_name, ObjectAttributes->ObjectName, sizeof(UNICODE_STRING)))) + return STATUS_NO_MEMORY; + } else { + obj_attr = *ObjectAttributes; + obj_name = *ObjectAttributes->ObjectName; + } + obj_attr.ObjectName = &obj_name; + + *DirectoryHandle = NULL; + + Status = create_object(PreviousMode, + dir_object_type, + &obj_attr, + PreviousMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID*)&Directory); + + if (NT_SUCCESS(Status)) { + Status = insert_object((PVOID)Directory, + NULL, + DesiredAccess, + 0, + NULL, + &hDirectory); + deref_object(Directory); + + if (NT_SUCCESS(Status)) { + if ((ULONG)DirectoryHandle < TASK_SIZE) { + if (copy_to_user(DirectoryHandle, &hDirectory, sizeof(HANDLE))) + return STATUS_NO_MEMORY; + } else + *DirectoryHandle = hDirectory; + } + } + + return Status; +} /* end NtCreateDirectoryObject */ +EXPORT_SYMBOL(NtCreateDirectoryObject); + +NTSTATUS +SERVICECALL +NtOpenDirectoryObject(OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hDirectory; + OBJECT_ATTRIBUTES obj_attr; + UNICODE_STRING obj_name; + MODE previous_mode; + NTSTATUS status = STATUS_SUCCESS; + + previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; + if (previous_mode == UserMode) { + if ((copy_from_user(&obj_attr, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)))) + return STATUS_NO_MEMORY; + if ((copy_from_user(&obj_name, ObjectAttributes->ObjectName, sizeof(UNICODE_STRING)))) + return STATUS_NO_MEMORY; + } else { + obj_attr = *ObjectAttributes; + obj_name = *ObjectAttributes->ObjectName; + } + obj_attr.ObjectName = &obj_name; + + status = open_object_by_name(&obj_attr, + dir_object_type, + NULL, + KernelMode, + DesiredAccess, + NULL, + &hDirectory); + if (!NT_SUCCESS(status)) + return status; + + if (previous_mode == UserMode) { + if ((copy_to_user(DirectoryHandle, &hDirectory, sizeof(HANDLE)))) + return STATUS_NO_MEMORY; + } else + *DirectoryHandle = hDirectory; + + return status; +} /* end NtOpenDirectoryObject */ +EXPORT_SYMBOL(NtOpenDirectoryObject); + +NTSTATUS +SERVICECALL +NtQueryDirectoryObject(IN HANDLE DirectoryHandle, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturnLength OPTIONAL) +{ + PVOID TempBuffer; + ULONG SkipEntries, SkipEntries2, Bucket, EntrySize; + ULONG RequiredSize = 0; + ULONG NextEntry = 0; + ULONG EntriesFound = 0; + POBJECT_DIRECTORY Directory; + POBJECT_DIRECTORY_ENTRY DirectoryEntry; + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER_NAME_INFO NameInfo; + UNICODE_STRING ObjectName; + POBJECT_DIRECTORY_INFORMATION DirInfo; + NTSTATUS Status = STATUS_SUCCESS; + MODE previous_mode; + + previous_mode = (unsigned long)Buffer > TASK_SIZE ? KernelMode : UserMode; + if (RestartScan) { + if (previous_mode == UserMode) { + if (copy_from_user(&SkipEntries, Context, sizeof(ULONG))) + return STATUS_NO_MEMORY; + } else + SkipEntries = *Context; + } else + SkipEntries = 0; + SkipEntries2 = SkipEntries; + + Status = ref_object_by_handle(DirectoryHandle, + DIRECTORY_QUERY, + dir_object_type, + KernelMode, + (PVOID *)&Directory, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + for (Bucket = 0; Bucket < NUMBER_HASH_BUCKETS; Bucket++) { + DirectoryEntry = Directory->HashBuckets[Bucket]; + + while (DirectoryEntry) { + if (SkipEntries == NextEntry++) { + EntriesFound ++; + + if (ReturnSingleEntry) + goto found; + else + SkipEntries++; + } + DirectoryEntry = DirectoryEntry->ChainLink; + } + } + + if (EntriesFound == 0) { + *Context = 0; + deref_object(Directory); + return STATUS_NO_MORE_ENTRIES; + } + +found: + TempBuffer = kmalloc(EntriesFound * sizeof(OBJECT_DIRECTORY_INFORMATION), GFP_KERNEL); + if (!TempBuffer) { + deref_object(Directory); + return STATUS_NO_MEMORY; + } + + if (previous_mode == UserMode) { + if (copy_from_user(TempBuffer, Buffer, EntriesFound * sizeof(OBJECT_DIRECTORY_INFORMATION))) { + deref_object(Directory); + return STATUS_NO_MEMORY; + } + } + else + TempBuffer = Buffer; + + DirInfo = (POBJECT_DIRECTORY_INFORMATION)TempBuffer; + + Status = STATUS_NO_MORE_ENTRIES; + NextEntry = 0; + for (Bucket = 0; Bucket < NUMBER_HASH_BUCKETS; Bucket++) { + DirectoryEntry = Directory->HashBuckets[Bucket]; + + while (DirectoryEntry) { + if (SkipEntries2 == NextEntry++) { + ObjectHeader = BODY_TO_HEADER(DirectoryEntry->Object); + NameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + + if (NameInfo) + ObjectName = NameInfo->Name; + else + init_unistr(&ObjectName, NULL); + + EntrySize = sizeof(OBJECT_DIRECTORY_INFORMATION) + + (ObjectName.Length + sizeof(WCHAR)) + + (ObjectHeader->Type->Name.Length + sizeof(WCHAR)); + + if (RequiredSize + EntrySize > BufferLength) { + if (ReturnSingleEntry) { + RequiredSize += EntrySize; + Status = STATUS_BUFFER_TOO_SMALL; + } else + Status = STATUS_MORE_ENTRIES; + + NextEntry--; + goto done; + } + + DirInfo->ObjectName.Length = ObjectName.Length; + DirInfo->ObjectName.MaximumLength = + (USHORT)(ObjectName.Length + sizeof(WCHAR)); + memcpy(DirInfo->ObjectName.Buffer, ObjectName.Buffer, ObjectName.Length); + + DirInfo->ObjectTypeName.Length = ObjectHeader->Type->Name.Length; + DirInfo->ObjectTypeName.MaximumLength = + (USHORT)(ObjectHeader->Type->Name.Length + sizeof(WCHAR)); + memcpy(DirInfo->ObjectTypeName.Buffer, ObjectHeader->Type->Name.Buffer, + ObjectHeader->Type->Name.Length); + + Status = STATUS_SUCCESS; + + RequiredSize += EntrySize; + DirInfo++; + + if (ReturnSingleEntry) + goto done; + else + SkipEntries2++; + } + + DirectoryEntry = DirectoryEntry->ChainLink; + } + } + +done: + if (!NT_SUCCESS(Status)) + goto out; + + if (previous_mode == UserMode) { + if (copy_to_user(Buffer, + TempBuffer, + NextEntry * sizeof(OBJECT_DIRECTORY_INFORMATION))) { + Status = STATUS_NO_MEMORY; + goto out; + } + } else + memcpy(Buffer, TempBuffer, NextEntry * sizeof(OBJECT_DIRECTORY_INFORMATION)); + + if (previous_mode == UserMode) { + if (copy_to_user(Context, &NextEntry, sizeof(ULONG))) { + Status = STATUS_NO_MEMORY; + goto out; + } + } else + *Context = NextEntry; + + if (ReturnLength) { + if (previous_mode == UserMode) { + if (copy_to_user(ReturnLength, &RequiredSize, sizeof(ULONG))) { + Status = STATUS_NO_MEMORY; + goto out; + } + } else + *ReturnLength = RequiredSize; + } + +out: + deref_object(Directory); + kfree(TempBuffer); + return Status; +} /* end NtQueryDirectoryObject */ +EXPORT_SYMBOL(NtQueryDirectoryObject); + +NTSTATUS delete_object_dir(PVOID dir) +{ + int i; + NTSTATUS ret = STATUS_SUCCESS; + POBJECT_DIRECTORY_ENTRY head_entry; + POBJECT_DIRECTORY_ENTRY entry; + + if (!dir) + dir = name_space_root; + + if (BODY_TO_HEADER(dir)->Type != dir_object_type) + return STATUS_INVALID_PARAMETER; + + for (i = 0; i < NUMBER_HASH_BUCKETS; i++) { + head_entry = (POBJECT_DIRECTORY_ENTRY)((POBJECT_DIRECTORY)dir)->HashBuckets[i]; + + /* + * Walk the chain of directory entries for this hash bucket, looking + * for either a match, or the insertion point if no match in the chain. + */ + while ((entry = head_entry)) { + POBJECT_HEADER header = BODY_TO_HEADER(entry->Object); + POBJECT_HEADER_NAME_INFO name_info = HEADER_TO_OBJECT_NAME(header); + + if (name_info) + name_info->Directory = NULL; + + if (BODY_TO_HEADER(entry->Object)->Type != dir_object_type) + delete_object(header); + else + ret = delete_object_dir(entry->Object); + + head_entry = entry->ChainLink; + kfree(entry); + } + } + delete_object(BODY_TO_HEADER(dir)); + + return ret; +} /* end delete_object_dir */ +#endif diff --git a/unifiedkernel/ob/display.c b/unifiedkernel/ob/display.c new file mode 100644 index 0000000..0e323c5 --- /dev/null +++ b/unifiedkernel/ob/display.c @@ -0,0 +1,124 @@ +/* + * display.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * display.c: + * Refered to ReactOS code + */ +#include "object.h" +#include "win32.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +extern POBJECT_TYPE dir_object_type; +extern POBJECT_TYPE symbol_link_type; +extern POBJECT_DIRECTORY name_space_root; + +void display_object(PVOID Object, LONG Depth, BOOLEAN IsDisplayType) +{ + LONG Length; + PCHAR Buffer, p; + PWCHAR wc; + POBJECT_HEADER Header; + POBJECT_TYPE Type; + POBJECT_HEADER_NAME_INFO NameInfo; + + Header = BODY_TO_HEADER(Object); + Type = Header->Type; + NameInfo = HEADER_TO_OBJECT_NAME(Header); + if (!NameInfo) + return; + + Length = Type->Name.Length + 64; + + p = Buffer = (PCHAR)kmalloc(Length, GFP_KERNEL); + while (p < Buffer + Depth * 2 + 1) + *p++ = ' '; + + if (Depth) { + *p++ = '\\'; + *p++ = '_'; + *p++ = ' '; + } + + for (wc = NameInfo->Name.Buffer; + wc < NameInfo->Name.Buffer + NameInfo->Name.Length / sizeof(WCHAR); + wc++) + *p++ = (char)*wc; + + if (!Depth) { + *p++ = 'R'; + *p++ = 'o'; + *p++ = 'o'; + *p++ = 't'; + } + + if (Type == symbol_link_type) { + PUNICODE_STRING us = &((POBJECT_SYMBOLIC_LINK)Object)->TargetName; + + memcpy(p, " --> ", sizeof(" --> ") - 1); + p += sizeof(" --> ") - 1; + for (wc = us->Buffer; wc < us->Buffer + us->Length / sizeof(WCHAR); wc++) + *p++ = (char)*wc; + } + + if (!IsDisplayType) + goto ready; + + while (p < Buffer + 64) + *p++ = ' '; + + for (wc = Type->Name.Buffer; + wc < Type->Name.Buffer + Type->Name.Length / sizeof(WCHAR); + wc++) + *p++ = (char)*wc; + +ready: + *p = 0; + + kfree(Buffer); +} /* end display_object */ +EXPORT_SYMBOL(display_object); + +void display_object_dir(POBJECT_DIRECTORY DirectoryObject, LONG Depth) +{ + int i; + POBJECT_DIRECTORY_ENTRY DirectoryEntry; + POBJECT_DIRECTORY_ENTRY *HeadDirectoryEntry; + + if (!DirectoryObject) + DirectoryObject = name_space_root; + display_object((PVOID)DirectoryObject, Depth - 1, FALSE); + for (i = 0; i < NUMBER_HASH_BUCKETS; i++) { + HeadDirectoryEntry = &DirectoryObject->HashBuckets[i]; + while ((DirectoryEntry = *HeadDirectoryEntry) != NULL) { + if (BODY_TO_HEADER(DirectoryEntry->Object)->Type == dir_object_type) + display_object_dir((POBJECT_DIRECTORY)DirectoryEntry->Object, Depth + 1); + else + display_object(DirectoryEntry->Object, Depth, TRUE); + + HeadDirectoryEntry = &DirectoryEntry->ChainLink; + } + } +} /* display_object_dir */ +EXPORT_SYMBOL(display_object_dir); +#endif diff --git a/unifiedkernel/ob/handle.c b/unifiedkernel/ob/handle.c new file mode 100644 index 0000000..ee4c85e --- /dev/null +++ b/unifiedkernel/ob/handle.c @@ -0,0 +1,1095 @@ +/* + * handle.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * handle.c: + * Refered to ReactOS code + */ +#include "handle.h" +#include "object.h" +#include "process.h" +#include "apc.h" +#include "semaphore.h" +#include "objwait.h" +#include "event.h" +#include "mutex.h" +#include +#include +#include "unistr.h" +#include "thread.h" +#include "wineserver/uk_lib.h" +#include "wineserver/info.h" + +#ifdef CONFIG_UNIFIED_KERNEL +static BOOLEAN initialized = FALSE; +static struct list_head handle_table_head; +static FAST_MUTEX handle_table_lock; +static LARGE_INTEGER handle_short_wait; +struct handle_table *kernel_handle_table = NULL; +EXPORT_SYMBOL(kernel_handle_table); + +extern POBJECT_TYPE process_object_type; +extern POBJECT_TYPE thread_object_type; + +#define acquire_handle_table_lock() acquire_fmutex_unsafe(&handle_table_lock) +#define release_handle_table_lock() release_fmutex_unsafe(&handle_table_lock) + +#define GENERIC_ANY (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL) + +extern VOID STDCALL event_init(struct kevent *event, enum event_type type, BOOLEAN state); + +VOID +memory_barrier(VOID) +{ + volatile long barrier; + __asm__ __volatile__ ("xchg %%eax, %0": :"m"(barrier): "%eax"); +} /*end memory_barrier */ + +VOID +STDCALL +map_generic_mask(PACCESS_MASK AccessMask, + PGENERIC_MAPPING GenericMapping) +{ + if (*AccessMask & GENERIC_READ) + *AccessMask |= GenericMapping->GenericRead; + + if (*AccessMask & GENERIC_WRITE) + *AccessMask |= GenericMapping->GenericWrite; + + if (*AccessMask & GENERIC_EXECUTE) + *AccessMask |= GenericMapping->GenericExecute; + + if (*AccessMask & GENERIC_ALL) + *AccessMask |= GenericMapping->GenericAll; + + *AccessMask &= ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} /* end map_generic_mask */ +EXPORT_SYMBOL(map_generic_mask); + +NTSTATUS +STDCALL +init_resource(struct eresource *Resource) +{ + memset(Resource, 0, sizeof(struct eresource)); + Resource->number_of_shared_waiters = 0; + Resource->number_of_exclusive_waiters = 0; + spin_lock_init(&Resource->spinlock); + Resource->flag = 0; + Resource->exclusive_waiters = kmalloc(sizeof(struct kevent), GFP_KERNEL); + event_init(Resource->exclusive_waiters, SynchronizationEvent, FALSE); + Resource->shared_waiters = kmalloc(sizeof(struct ksemaphore), GFP_KERNEL); + semaphore_init(Resource->shared_waiters, 0, 0x7fffffff); + Resource->active_count = 0; + return 0; +} /* init_resource */ +EXPORT_SYMBOL(init_resource); + +NTSTATUS +STDCALL +delete_resource(struct eresource *Resource) +{ + if (Resource->owner_table) + kfree(Resource->owner_table); + + if (Resource->shared_waiters) + kfree(Resource->shared_waiters); + + if (Resource->exclusive_waiters) + kfree(Resource->exclusive_waiters); + + return STATUS_SUCCESS; +} /* end delete_resource */ +EXPORT_SYMBOL(delete_resource); + +VOID +init_handle_tables(VOID) +{ + handle_short_wait.QuadPart = -50000; + INIT_LIST_HEAD(&handle_table_head); + init_fast_mutex(&handle_table_lock); + initialized = TRUE; +} /* init_handle_tables */ + +static BOOLEAN +lock_entry_no_check(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry) +{ + ULONG_PTR Current, New; + + if (!HandleTable || !Entry) + return FALSE; + + for (;;) { + Current = (ULONG_PTR)Entry->u1.object; + + if (!Current) + break; + + if (!(Current & EX_HANDLE_ENTRY_LOCKED)) { + New = Current | EX_HANDLE_ENTRY_LOCKED; + __xchg(New, &Entry->u1.object, sizeof(Entry->u1.object)); + return TRUE; + } + + wait_for_single_object(&HandleTable->handle_contention_event, + Executive, + KernelMode, + FALSE, + &handle_short_wait); + } + + return FALSE; +} /* end lock_entry_no_check */ + +BOOLEAN +lock_handle_table_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry) +{ + ULONG_PTR Current, New; + + if (!HandleTable || !Entry) + return FALSE; + + for (;;) { + Current = (ULONG_PTR)Entry->u1.object; + + if (!Current || (HandleTable->flags & EX_HANDLE_TABLE_CLOSING)) + break; + + if (!(Current & EX_HANDLE_ENTRY_LOCKED)) { + New = Current | EX_HANDLE_ENTRY_LOCKED; + __xchg(New, &Entry->u1.object, sizeof(Entry->u1.object)); + return TRUE; + } + + wait_for_single_object(&HandleTable->handle_contention_event, + Executive, + KernelMode, + FALSE, + &handle_short_wait); + } + + return FALSE; +} /* end lock_handle_table_entry */ + +VOID +unlock_handle_table_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry) +{ + ULONG_PTR Current, New; + + if (!HandleTable || !Entry) + return; + + Current = (ULONG_PTR)Entry->u1.object; + + if (Current & EX_HANDLE_ENTRY_LOCKED) { + New = Current &~EX_HANDLE_ENTRY_LOCKED; + __xchg(New, &Entry->u1.object, sizeof(Entry->u1.object)); + + pulse_event(&HandleTable->handle_contention_event, + 0, + FALSE); + } +} /* end unlock_handle_table_entry */ + +struct handle_table * +__create_handle_table(IN struct eprocess *QuotaProcess OPTIONAL) +{ + struct handle_table *handle_table; + + if (!initialized) + return NULL; + + handle_table = kmalloc(sizeof(handle_table) + (N_TOPLEVEL_POINTERS * + sizeof(struct handle_table_entry **)), GFP_KERNEL); + if (!handle_table) + return handle_table; + + /* Initialize the handle table */ + handle_table->flags = 0; + handle_table->handle_count = 0; + handle_table->table = (struct handle_table_entry ***)(handle_table + 1); + handle_table->quota_process = QuotaProcess; + handle_table->first_free_table_entry = -1; + handle_table->next_index_needing_pool = 0; + handle_table->unique_processid = (QuotaProcess ? QuotaProcess->unique_processid : NULL); + + init_resource(&handle_table->handle_table_lock); + event_init(&handle_table->handle_contention_event, NotificationEvent, FALSE); + + memset(handle_table->table, 0, N_TOPLEVEL_POINTERS * sizeof(struct handle_table_entry **)); + + enter_critical_region(); + acquire_handle_table_lock(); + + /* Insert it into the global handle table list */ + list_add_tail(&handle_table->handle_table_list, &handle_table_head); + + release_handle_table_lock(); + leave_critical_region(); + + return handle_table; +} /* __create_handle_table */ +EXPORT_SYMBOL(__create_handle_table); + +static BOOLEAN STDCALL +dup_handle_callback(struct handle_table *HandleTable, + struct handle_table_entry *HandleTableEntry, + PVOID Context) +{ + POBJECT_HEADER object_header; + + if (HandleTableEntry->u1.obattributes & EX_HANDLE_ENTRY_INHERITABLE) { + object_header = EX_HTE_TO_HDR(HandleTableEntry); + atomic_inc(&object_header->HandleCount); + ref_object(&object_header->Body); + return TRUE; + } + else return FALSE; +} /* end dup_handle_callback */ + +VOID STDCALL +delete_handle_callback(struct handle_table *HandleTable, + PVOID Object, + ULONG GrantedAccess, + PVOID Context) +{ + POBJECT_HEADER object_header; + PVOID object_body; + + object_header = EX_OBJ_TO_HDR(Object); + object_body = &object_header->Body; + + if (IS_WINE_OBJECT(object_header)) + release_object( object_body ); + else /* not a wine object */ + decrement_handle_count(object_body); +} /* end delete_handle_callback */ + +VOID +__destroy_handle_table(IN struct handle_table *HandleTable, + IN PEX_DESTROY_HANDLE_CALLBACK DestroyHandleCallback OPTIONAL, + IN PVOID Context OPTIONAL) +{ + struct handle_table_entry ***tlp, ***lasttlp, **mlp, **lastmlp; + + if (!HandleTable) + return; + + enter_critical_region(); + + spin_lock(&HandleTable->handle_table_lock.spinlock); + + if (HandleTable->flags & EX_HANDLE_TABLE_CLOSING) + return; + + HandleTable->flags |= EX_HANDLE_TABLE_CLOSING; + + pulse_event(&HandleTable->handle_contention_event, 0, FALSE); + + acquire_handle_table_lock(); + list_del(&HandleTable->handle_table_list); + release_handle_table_lock(); + + /* Call the callback function to cleanup the objects */ + lasttlp = HandleTable->table + N_TOPLEVEL_POINTERS; + if (DestroyHandleCallback) { + for (tlp = HandleTable->table; tlp != lasttlp; tlp++) { + if (*tlp) { + lastmlp = *tlp + N_MIDDLELEVEL_POINTERS; + for (mlp = *tlp; mlp != lastmlp; mlp++) { + if (*mlp) { + struct handle_table_entry *cure, *laste; + + laste = *mlp + N_SUBHANDLE_ENTRIES; + for(cure = *mlp; cure != laste; cure++) { + if (cure->u1.object && + lock_entry_no_check(HandleTable, cure)) { + DestroyHandleCallback(HandleTable, + cure->u1.object, + cure->u2.granted_access, + Context); + unlock_handle_table_entry(HandleTable, cure); + } + } + } + } + } + } + } + + /* Free the table if necessary */ + for (tlp = HandleTable->table; tlp != lasttlp; tlp++) { + if (*tlp) { + lastmlp = *tlp + N_MIDDLELEVEL_POINTERS; + for (mlp = *tlp; mlp != lastmlp; mlp++) { + if (*mlp) + kfree(*mlp); + } + kfree(*tlp); + } + } + + spin_unlock(&HandleTable->handle_table_lock.spinlock); + + leave_critical_region(); + + delete_resource(&HandleTable->handle_table_lock); + kfree(HandleTable); +} /* end __destroy_handle_table */ +EXPORT_SYMBOL(__destroy_handle_table); + +struct handle_table * +dup_handle_table(IN struct eprocess *QuotaProcess OPTIONAL, + IN PEX_DUPLICATE_HANDLE_CALLBACK dup_handle_callback OPTIONAL, + IN PVOID Context OPTIONAL, + IN struct handle_table *SourceHandleTable) +{ + struct handle_table *handle_table; + struct handle_table_entry ***srctlp, **srcmlp, *srcstbl; + struct handle_table_entry ***tlp, **mlp, *stbl; + struct handle_table_entry ***etlp, **emlp, *estbl; + LONG tli, mli, eli; + tli = mli = eli = 0; + + if (!SourceHandleTable) + return NULL; + + /* Create a handle table for the quota process */ + handle_table = __create_handle_table(QuotaProcess); + if (!handle_table) + return handle_table; + + spin_lock(&SourceHandleTable->handle_table_lock.spinlock); + + /* Duplicate the handles from the parent */ + handle_table->handle_count = SourceHandleTable->handle_count; + handle_table->first_free_table_entry = SourceHandleTable->first_free_table_entry; + handle_table->next_index_needing_pool = SourceHandleTable->next_index_needing_pool; + + srctlp = SourceHandleTable->table; + tlp = handle_table->table; + etlp = SourceHandleTable->table + N_TOPLEVEL_POINTERS; + for (; srctlp != etlp; srctlp++, tlp++, tli++) { + if (*srctlp) { + /* Allocate a top level entry if the parent has one */ + *tlp = kmalloc(sizeof(struct handle_table_entry *) * N_MIDDLELEVEL_POINTERS, GFP_KERNEL); + if (!*tlp) + goto out; + + memset(*tlp, 0, sizeof(struct handle_table_entry *) * N_MIDDLELEVEL_POINTERS); + memory_barrier(); + + emlp = *srctlp + N_MIDDLELEVEL_POINTERS; + for (srcmlp = *srctlp, mlp = *tlp; srcmlp != emlp; srcmlp++, mlp++, mli++){ + if (*srcmlp) { + /* Allocate a middle level entry if the parent has one */ + *mlp = kmalloc(sizeof(struct handle_table_entry) * + N_SUBHANDLE_ENTRIES, GFP_KERNEL); + if (!*mlp) + goto out; + + memset(*mlp, 0, sizeof(struct handle_table_entry) * N_SUBHANDLE_ENTRIES); + + /* Walk all handle entries and duplicate them if wanted */ + estbl = *srcmlp + N_SUBHANDLE_ENTRIES; + for (srcstbl = *srcmlp, stbl = *mlp; srcstbl != estbl; + srcstbl++, stbl++, eli++) { + if (srcstbl->u1.object && + lock_handle_table_entry(SourceHandleTable, srcstbl)) { + /* Ask the caller if this handle should be duplicated */ + if (dup_handle_callback && + !dup_handle_callback(handle_table, srcstbl, Context)) { + /* The handle is not inheritable, free it */ + handle_table->handle_count--; + stbl->u1.object = NULL; + stbl->u2.next_free_table_entry = + handle_table->first_free_table_entry; + handle_table->first_free_table_entry = + BUILD_HANDLE(tli, mli, eli); + } + else { + stbl->u2.granted_access = srcstbl->u2.granted_access; + stbl->u1.obattributes = srcstbl->u1.obattributes & + ~EX_HANDLE_ENTRY_LOCKED; + } + unlock_handle_table_entry(SourceHandleTable, srcstbl); + } + else *stbl = *srcstbl; + } + } + else *mlp = NULL; + } + } + else *tlp = NULL; + } + spin_unlock(&SourceHandleTable->handle_table_lock.spinlock); + + return handle_table; +out: + spin_unlock(&SourceHandleTable->handle_table_lock.spinlock); + + __destroy_handle_table(handle_table, NULL, NULL); + return __create_handle_table(QuotaProcess); +} /* end dup_handle_table */ + +VOID +create_handle_table(struct eprocess *Parent, + BOOLEAN Inherit, + struct eprocess *Process) +{ + if (Inherit && Parent) + /* If it has a parent, duplicate the handle table */ + Process->object_table = dup_handle_table(Process, + dup_handle_callback, + NULL, + Parent->object_table); + else if (Process) + Process->object_table = __create_handle_table(Process); + + else + kernel_handle_table = __create_handle_table(NULL); +} /* end create_handle_table */ +EXPORT_SYMBOL(create_handle_table); + +struct handle_table_entry * +alloc_handle_table_entry(IN struct handle_table *HandleTable, + OUT PLONG Handle) +{ + struct handle_table_entry *entry = NULL; + ULONG tli, mli, eli; + + if (!HandleTable || !Handle) + return NULL; + + if (HandleTable->handle_count >= EX_MAX_HANDLES) + return NULL; + + if (HandleTable->first_free_table_entry != -1) { + /* There is a free entry we can use */ + tli = TLI_FROM_HANDLE(HandleTable->first_free_table_entry); + mli = MLI_FROM_HANDLE(HandleTable->first_free_table_entry); + eli = ELI_FROM_HANDLE(HandleTable->first_free_table_entry); + + /* Get the entry and the handle */ + entry = &HandleTable->table[tli][mli][eli]; + *Handle = HandleTable->first_free_table_entry; + + /* Set the first free table entry for the next time */ + HandleTable->first_free_table_entry = entry->u2.next_free_table_entry; + entry->u2.next_free_table_entry = 0; + entry->u1.object = NULL; + + HandleTable->handle_count++; + } + else { + /* We need to allocate a new subhandle table first */ + struct handle_table_entry **nmtbl, *ntbl, *laste, *cure; + BOOLEAN allocated = FALSE; + ULONG i; + + tli = TLI_FROM_HANDLE(HandleTable->next_index_needing_pool); + mli = MLI_FROM_HANDLE(HandleTable->next_index_needing_pool); + + nmtbl = HandleTable->table[tli]; + if (!nmtbl) { + /* Allocate a middle level entry */ + if (!(nmtbl = kmalloc(sizeof(struct handle_table_entry *) * + N_MIDDLELEVEL_POINTERS, GFP_KERNEL))) + return NULL; + + memset(nmtbl, 0, sizeof(struct handle_table_entry *) * N_MIDDLELEVEL_POINTERS); + memory_barrier(); + + /* We have allocated a middle level entry */ + allocated = TRUE; + } + + if (!(ntbl = kmalloc(sizeof(struct handle_table_entry) * N_SUBHANDLE_ENTRIES, GFP_KERNEL))) { + if (allocated) + kfree(nmtbl); + return NULL; + } + + entry = ntbl; + entry->u1.obattributes = EX_HANDLE_ENTRY_LOCKED; + entry->u2.next_free_table_entry = 0; + + /* next_index_needing_pool has been set to 0 in __create_handle_table() */ + *Handle = HandleTable->next_index_needing_pool; + HandleTable->handle_count++; + + /* Set the first free entry */ + HandleTable->first_free_table_entry = HandleTable->next_index_needing_pool + 1; + laste = entry + N_SUBHANDLE_ENTRIES; + i = HandleTable->first_free_table_entry + 1; + /* Set all of the next_free_table_entry members of the index */ + for (cure = entry + 1; cure != laste; cure++, i++) { + cure->u1.object = NULL; + cure->u2.next_free_table_entry = i; + } + /* truncate the free entry list */ + (cure - 1)->u2.next_free_table_entry = -1; + + __xchg((unsigned long)ntbl, &nmtbl[mli], sizeof(nmtbl[mli])); + if (allocated) + __xchg((unsigned long)nmtbl, &HandleTable->table[tli], sizeof(HandleTable->table[tli])); + + /* Set the next index needing pool to the next index */ + HandleTable->next_index_needing_pool += N_SUBHANDLE_ENTRIES; + } + + return entry; +} /* end alloc_handle_table_entry */ + +LONG +create_ex_handle(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry) +{ + struct handle_table_entry *new_entry; + LONG handle = EX_INVALID_HANDLE; + + if (!HandleTable || !Entry) + return 0; + + if (!((ULONG_PTR)Entry->u1.object & EX_HANDLE_ENTRY_LOCKED)) + return 0; + + enter_critical_region(); + spin_lock(&HandleTable->handle_table_lock.spinlock); + + /* Allocate an entry of the handle table */ + new_entry = alloc_handle_table_entry(HandleTable, &handle); + + if (new_entry) { + *new_entry = *Entry; + unlock_handle_table_entry(HandleTable, new_entry); + } + + spin_unlock(&HandleTable->handle_table_lock.spinlock); + leave_critical_region(); + + return handle; +} /* end create_ex_handle */ +EXPORT_SYMBOL(create_ex_handle); + +NTSTATUS +create_handle(struct eprocess *Process, + PVOID ObjectBody, + ACCESS_MASK GrantedAccess, + BOOLEAN Inherit, + PHANDLE HandleReturn) +{ + struct handle_table_entry new_entry; + struct handle_table *handle_table; + BOOLEAN kernel_handle = FALSE; + LONG ex_handle; + HANDLE new_handle; + POBJECT_HEADER object_header; + + if (!ObjectBody) + return STATUS_INVALID_PARAMETER; + + object_header = BODY_TO_HEADER(ObjectBody); + if (!((ULONG_PTR)object_header & EX_HANDLE_ENTRY_LOCKED)) + return STATUS_WAS_LOCKED; + + if (GrantedAccess & MAXIMUM_ALLOWED) { + GrantedAccess &= ~MAXIMUM_ALLOWED; + GrantedAccess |= GENERIC_ALL; + } + + if ((GrantedAccess & GENERIC_ANY) && object_header->Type) + map_generic_mask(&GrantedAccess, &object_header->Type->TypeInfo.GenericMapping); + + new_entry.u1.object = object_header; + if (Inherit) + new_entry.u1.obattributes |= EX_HANDLE_ENTRY_INHERITABLE; + else + new_entry.u1.obattributes &= ~EX_HANDLE_ENTRY_INHERITABLE; + new_entry.u2.granted_access = GrantedAccess; + + /* Create an ex_handle */ + if (Process) + handle_table = Process->object_table; + else { + handle_table = kernel_handle_table; + kernel_handle = TRUE; + } + ex_handle = create_ex_handle(handle_table, &new_entry); + + if (ex_handle != EX_INVALID_HANDLE) { + NTSTATUS status; + + atomic_inc(&object_header->HandleCount); + status = ref_object_by_pointer(ObjectBody, 0, NULL, UserMode); + if (!NT_SUCCESS(status)) + return status; + + new_handle = EX_HANDLE_TO_HANDLE(ex_handle); +#ifdef UK_HANDLE + new_handle = HANDLE_TO_UK_HANDLE(new_handle); +#endif + if (kernel_handle) + new_handle = HANDLE_TO_KERNEL_HANDLE(new_handle); + + *HandleReturn = new_handle; + return STATUS_SUCCESS; + } + else + return STATUS_UNSUCCESSFUL; +} /* end create_handle */ +EXPORT_SYMBOL(create_handle); + +struct handle_table_entry * +lookup_handle_table_entry(IN struct handle_table *HandleTable, + IN LONG Handle) +{ + struct handle_table_entry *entry = NULL; + + if (!HandleTable) + return NULL; + + if (IS_VALID_EX_HANDLE(Handle)) { + struct handle_table_entry **mlp; + ULONG tli, mli, eli; + + tli = TLI_FROM_HANDLE(Handle); + mli = MLI_FROM_HANDLE(Handle); + eli = ELI_FROM_HANDLE(Handle); + + mlp = HandleTable->table[tli]; + + if (Handle < HandleTable->next_index_needing_pool && mlp && mlp[mli] && mlp[mli][eli].u1.object) + entry = &mlp[mli][eli]; + } + + return entry; +} /* end lookup_handle_table_entry */ +EXPORT_SYMBOL(lookup_handle_table_entry); + +struct handle_table_entry * +map_handle_to_pointer(IN struct handle_table *HandleTable, + IN LONG Handle) +{ + struct handle_table_entry *entry; + + if (!HandleTable) + return NULL; + + entry = lookup_handle_table_entry(HandleTable, Handle); + + if (entry && entry->u1.object && lock_handle_table_entry(HandleTable, entry)) + return entry; + + return NULL; +} /* end map_handle_to_pointer */ +EXPORT_SYMBOL(map_handle_to_pointer); + +NTSTATUS +ref_object_by_handle(HANDLE Handle, + ACCESS_MASK DesiredAccess, + POBJECT_TYPE ObjectType, + KPROCESSOR_MODE AccessMode, + PVOID *Object, + POBJECT_HANDLE_INFORMATION HandleInformation) +{ + struct ethread *thread = NULL; + struct eprocess *process = NULL; + struct handle_table *handle_table; + struct handle_table_entry *handle_entry; + LONG ex_handle; + POBJECT_HEADER object_header; + PVOID object_body; + ACCESS_MASK access; + ULONG attributes; + + if (!Handle) + return STATUS_INVALID_HANDLE; + + thread = get_current_ethread(); + process = get_current_eprocess(); + + /* If it's a process handle */ + if (Handle == NtCurrentProcess()) { + if (ObjectType == process_object_type || ObjectType == NULL) { + if (!process) + return STATUS_UNSUCCESSFUL; + ref_object(process); + + if (HandleInformation) { + HandleInformation->HandleAttributes = 0; + HandleInformation->GrantedAccess = PROCESS_ALL_ACCESS; + } + + *Object = process; + return STATUS_SUCCESS; + } + else return STATUS_OBJECT_TYPE_MISMATCH; + } + + /* If it's a thread handle */ + if (Handle == NtCurrentThread()) { + if (ObjectType == thread_object_type || ObjectType == NULL) { + if (!thread) + return STATUS_UNSUCCESSFUL; + ref_object(thread); + + if (HandleInformation) { + HandleInformation->HandleAttributes = 0; + HandleInformation->GrantedAccess = THREAD_ALL_ACCESS; + } + + *Object = thread; + return STATUS_SUCCESS; + } + else return STATUS_OBJECT_TYPE_MISMATCH; + } + + if (DesiredAccess & MAXIMUM_ALLOWED) { + DesiredAccess &= ~MAXIMUM_ALLOWED; + DesiredAccess |= GENERIC_ALL; + } + + if (is_kernel_handle(Handle, KernelMode)) { + handle_table = kernel_handle_table; +#ifdef UK_HANDLE + Handle = UK_HANDLE_TO_HANDLE(Handle); +#endif + ex_handle = HANDLE_TO_EX_HANDLE(KERNEL_HANDLE_TO_HANDLE(Handle)); + } + else { + if (!process) + return STATUS_UNSUCCESSFUL; + + handle_table = process->object_table; +#ifdef UK_HANDLE + Handle = UK_HANDLE_TO_HANDLE(Handle); +#endif + ex_handle = HANDLE_TO_EX_HANDLE(Handle); + } + + enter_critical_region(); + + /* Lookup the entry from the handle table */ + handle_entry = map_handle_to_pointer(handle_table, ex_handle); + + if (!handle_entry) { + leave_critical_region(); + return STATUS_INVALID_HANDLE; + } + + object_header = EX_HTE_TO_HDR(handle_entry); + object_body = &object_header->Body; + + if (ObjectType && ObjectType != object_header->Type && !object_header->ops) { + unlock_handle_table_entry(handle_table, handle_entry); + leave_critical_region(); + return STATUS_OBJECT_TYPE_MISMATCH; + } + + if ((DesiredAccess & GENERIC_ANY) && BODY_TO_HEADER(object_body)->Type) + map_generic_mask(&DesiredAccess, &BODY_TO_HEADER(object_body)->Type->TypeInfo.GenericMapping); + + access = handle_entry->u2.granted_access; + + if (AccessMode != KernelMode && (~access & DesiredAccess)) { + unlock_handle_table_entry(handle_table, handle_entry); + leave_critical_region(); + return STATUS_ACCESS_DENIED; + } + + ref_object(object_body); + + access = handle_entry->u2.granted_access; + attributes = handle_entry->u1.obattributes & (EX_HANDLE_ENTRY_PROTECTFROMCLOSE | + EX_HANDLE_ENTRY_INHERITABLE | + EX_HANDLE_ENTRY_AUDITONCLOSE); + + unlock_handle_table_entry(handle_table, handle_entry); + leave_critical_region(); + + if (HandleInformation) { + HandleInformation->HandleAttributes = attributes; + HandleInformation->GrantedAccess = access; + } + + *Object = object_body; + + return STATUS_SUCCESS; +} /* end ref_object_by_handle */ +EXPORT_SYMBOL(ref_object_by_handle); + +VOID +decrement_handle_count(PVOID ObjectBody) +{ + POBJECT_HEADER object_header; + POBJECT_HEADER_NAME_INFO object_name; + POBJECT_HEADER_CREATOR_INFO creator_info; + LONG new_count; + + object_header = BODY_TO_HEADER(ObjectBody); + object_name = HEADER_TO_OBJECT_NAME(object_header); + new_count = atomic_dec_return(&object_header->HandleCount); + + if (object_header->Type && object_header->Type->TypeInfo.CloseProcedure) + object_header->Type->TypeInfo.CloseProcedure(NULL, + ObjectBody, + 0, + 0, + new_count + 1); + + if (new_count == 0) { + if (object_name && object_name->Directory && !(object_header->Flags & OB_FLAG_PERMANENT)) { + /* Delete the directory when the last handle got closed */ + lookup_obdir_entry(object_name->Directory, &object_name->Name, OBJ_CASE_INSENSITIVE); + delete_obdir_entry(object_name->Directory); + } + + creator_info = HEADER_TO_CREATOR_INFO(object_header); + if (creator_info && !list_empty(&creator_info->TypeList)) { + list_del(&creator_info->TypeList); + INIT_LIST_HEAD(&creator_info->TypeList); + } + } + deref_object(ObjectBody); +} /* end decrement_handle_count */ + +VOID +free_handle_table_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry, + IN LONG Handle) +{ + if (!HandleTable || !Entry || !IS_VALID_EX_HANDLE(Handle)) + return; + + __xchg(0, &Entry->u1.object, sizeof(Entry->u1.object)); + + Entry->u2.next_free_table_entry = HandleTable->first_free_table_entry; + HandleTable->first_free_table_entry = Handle; + HandleTable->handle_count--; +} /* end free_handle_table_entry */ + +VOID +destroy_handle_by_entry(IN struct handle_table *HandleTable, + IN struct handle_table_entry *Entry, + IN LONG Handle) +{ + if (!HandleTable || !Entry) + return; + + if (!((ULONG_PTR)Entry->u1.object & EX_HANDLE_ENTRY_LOCKED)) + return; + + enter_critical_region(); + spin_lock(&HandleTable->handle_table_lock.spinlock); + + free_handle_table_entry(HandleTable, Entry, Handle); + + spin_unlock(&HandleTable->handle_table_lock.spinlock); + leave_critical_region(); +} /* end destroy_handle_by_entry */ + +NTSTATUS +delete_handle(struct handle_table *HandleTable, + HANDLE Handle) +{ + struct handle_table_entry *handle_entry; + POBJECT_HEADER object_header; + LONG ex_handle; + +#ifdef UK_HANDLE + Handle = UK_HANDLE_TO_HANDLE(Handle); +#endif + ex_handle = HANDLE_TO_EX_HANDLE(Handle); + enter_critical_region(); + + handle_entry = map_handle_to_pointer(HandleTable, ex_handle); + if (!handle_entry) { + leave_critical_region(); + return STATUS_INVALID_HANDLE; + } + + if (handle_entry->u1.obattributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) { + unlock_handle_table_entry(HandleTable, handle_entry); + leave_critical_region(); + return STATUS_HANDLE_NOT_CLOSABLE; + } + + object_header = EX_HTE_TO_HDR(handle_entry); + if (IS_WINE_OBJECT(object_header)) + release_object( &object_header->Body ); + else /* not a wine object */ + decrement_handle_count(&object_header->Body); + + /* Destroy the handle entry */ + destroy_handle_by_entry(HandleTable, handle_entry, ex_handle); + leave_critical_region(); + return STATUS_SUCCESS; +} /*end delete_handle */ + +BOOLEAN +destroy_handle(IN struct handle_table *HandleTable, + IN LONG Handle) +{ + struct handle_table_entry *entry; + BOOLEAN ret = FALSE; + + if (!HandleTable) + return ret; + + enter_critical_region(); + spin_lock(&HandleTable->handle_table_lock.spinlock); + + entry = lookup_handle_table_entry(HandleTable, Handle); + + if (entry && lock_handle_table_entry(HandleTable, entry)) { + free_handle_table_entry(HandleTable, entry, Handle); + ret = TRUE; + } + + spin_unlock(&HandleTable->handle_table_lock.spinlock); + leave_critical_region(); + + return ret; +} /* end destroy_handle */ +EXPORT_SYMBOL(destroy_handle); + + +NTSTATUS SERVICECALL +NtClose(HANDLE handle) +{ + struct handle_table *handle_table; + struct eprocess *process = NULL; + NTSTATUS status; + + if (!current->ethread) { + /* use kernel handle table if we have no ethread now */ + handle_table = kernel_handle_table; + handle = KERNEL_HANDLE_TO_HANDLE(handle); + } + else { + process = get_current_eprocess(); + handle_table = process->object_table; + } + + status = delete_handle(handle_table, handle); + + clear_handle_info(process, handle); + + return status; +} /* end NtClose */ +EXPORT_SYMBOL(NtClose); + +obj_handle_t alloc_handle(struct w32process* proc, void* p, unsigned int access, int attr) +{ + struct object *obj = p; + HANDLE handle = NULL; + NTSTATUS ret; + + if (BODY_TO_HEADER(obj)->ops) + access = BODY_TO_HEADER(obj)->ops->map_access(obj, access); + + ret = create_handle(current->ethread ? get_current_eprocess() : NULL, + p, access, attr & OBJ_INHERIT, &handle); + if (!NT_SUCCESS(ret)) { + set_error((unsigned int)ret); + return NULL; + } + + set_handle_info(proc ? proc->eprocess : NULL, handle, p); + + return handle; +} + +obj_handle_t alloc_handle_no_access_check( struct w32process *process, void *ptr, unsigned int access, unsigned int attr ) +{ + return alloc_handle(process, ptr, access, attr); +} + +HANDLE duplicate_handle(HANDLE src, HANDLE src_handle, HANDLE dst, + unsigned int access, unsigned int attr, unsigned int options) +{ + NTSTATUS ret; + HANDLE dst_handle; + + ret = NtDuplicateObject(src, src_handle, dst, &dst_handle, access, attr, options); + if (!NT_SUCCESS(ret)) { + set_error((unsigned int)ret); + return NULL; + } + + return dst_handle; +} + +unsigned int get_handle_access(struct eprocess *process, HANDLE handle) +{ + LONG ex_handle; + struct handle_table *handle_table; + struct handle_table_entry *entry; + +#ifdef UK_HANDLE + handle = UK_HANDLE_TO_HANDLE(handle); +#endif + + if (process) { + handle_table = process->object_table; + ex_handle = HANDLE_TO_EX_HANDLE(handle); + } else { + handle_table = kernel_handle_table; + ex_handle = HANDLE_TO_EX_HANDLE(KERNEL_HANDLE_TO_HANDLE(handle)); + } + + enter_critical_region(); + + entry = map_handle_to_pointer(handle_table, ex_handle); + if (!entry) { + leave_critical_region(); + set_error(STATUS_INVALID_HANDLE); + return 0; + } + + unlock_handle_table_entry(handle_table, entry); + leave_critical_region(); + + return entry->u2.granted_access; /* FIXME: & ~RESERVED_ALL; */ +} + +int close_handle(struct eprocess *process, HANDLE handle) +{ + struct handle_table *handle_table; + NTSTATUS status; + + if (process) + handle_table = process->object_table; + else { + handle_table = kernel_handle_table; + handle = KERNEL_HANDLE_TO_HANDLE(handle); + } + + status = delete_handle(handle_table, handle); + + return status; +} + +#endif diff --git a/unifiedkernel/ob/namespc.c b/unifiedkernel/ob/namespc.c new file mode 100644 index 0000000..7918739 --- /dev/null +++ b/unifiedkernel/ob/namespc.c @@ -0,0 +1,261 @@ +/* + * namespc.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * namespc.c: + * Refered to ReactOS code + */ +#include +#include "object.h" +#include "handle.h" +#include "win32.h" +#include "unistr.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define OBJECT_TYPE_CREATE 0x0001 +#define OBJECT_TYPE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) + +#define DIRECTORY_QUERY (0x0001) +#define DIRECTORY_TRAVERSE (0x0002) +#define DIRECTORY_CREATE_OBJECT (0x0004) +#define DIRECTORY_CREATE_SUBDIRECTORY (0x0008) +#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) +#define EVENT_QUERY_STATE (0x0001) +#define SEMAPHORE_QUERY_STATE (0x0001) +#define SYMBOLIC_LINK_QUERY 0x0001 +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) + +POBJECT_TYPE dir_object_type = NULL; +EXPORT_SYMBOL(dir_object_type); +POBJECT_TYPE type_object_type = NULL; +EXPORT_SYMBOL(type_object_type); + +POBJECT_DIRECTORY name_space_root = NULL; +EXPORT_SYMBOL(name_space_root); +POBJECT_DIRECTORY type_object_dir = NULL; +EXPORT_SYMBOL(type_object_dir); + +HANDLE base_dir_handle = NULL; +EXPORT_SYMBOL(base_dir_handle); + +HANDLE device_handle = NULL; +EXPORT_SYMBOL(device_handle); + +extern struct handle_table *kernel_handle_table; +extern NTSTATUS delete_object_dir(PVOID dir); + +static GENERIC_MAPPING dir_mapping = +{ + STANDARD_RIGHTS_READ | DIRECTORY_QUERY | DIRECTORY_TRAVERSE, + STANDARD_RIGHTS_WRITE | DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_SUBDIRECTORY, + STANDARD_RIGHTS_EXECUTE | DIRECTORY_QUERY | DIRECTORY_TRAVERSE, + DIRECTORY_ALL_ACCESS +}; + +static GENERIC_MAPPING type_mapping = +{ + STANDARD_RIGHTS_READ, + STANDARD_RIGHTS_WRITE, + STANDARD_RIGHTS_EXECUTE, + 0x000F0001 +}; + +static WCHAR type_type_name[] = {'T', 'y', 'p', 'e', 0}; +static WCHAR dir_type_name[] = {'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 0}; +static WCHAR root_dir_name[] = {'\\', 0}; +static WCHAR type_dir_name[] = {'\\', 'O', 'b', 'j', 'e', 'c', 't', 'T', 'y', 'p', 'e', 's', 0}; +static WCHAR base_dir_name[] = {'\\', 'B', 'a', 's', 'e', 'N', 'a', 'm', 'e', 'd', 'O', 'b', 'j', 'e', 'c', 't', 's', 0}; +static WCHAR dir_driver[] = {'\\', 'D', 'r', 'i', 'v', 'e', 'r', 0}; +static WCHAR dir_device[] = {'\\', 'D', 'e', 'v', 'i', 'c', 'e', 0}; + +UNICODE_STRING TypeObjectTypeNameInfo; + +BOOLEAN init_object() +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle; + + create_handle_table(NULL, 0, NULL); + + /* Create the Type Type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)type_type_name); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = TRUE; + ObjectTypeInitializer.MaintainTypeList = TRUE; + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.GenericMapping = type_mapping; + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE); + create_type_object(&ObjectTypeInitializer, &Name, &type_object_type); + + /* Create the Directory Type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)dir_type_name); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = FALSE; + ObjectTypeInitializer.MaintainTypeList = FALSE; + ObjectTypeInitializer.GenericMapping = dir_mapping; + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_DIRECTORY); + create_type_object(&ObjectTypeInitializer, &Name, &dir_object_type); + + /* FIXME Initialize the resource that protects the object name space directory structure */ +#if 0 + ExInitializeResourceLite(&ObpRootDirectoryMutex); +#endif + + /* Create an directory object for the root directory */ + init_unistr(&Name, (PWSTR)root_dir_name); + INIT_OBJECT_ATTR(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, + NULL, + NULL); + create_object(KernelMode, + dir_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID*)&name_space_root); + insert_object((PVOID)name_space_root, + NULL, + DIRECTORY_ALL_ACCESS, + 0, + NULL, + NULL); + + /* Create an directory object for the directory of object types */ + init_unistr(&Name, (PWSTR)type_dir_name); + INIT_OBJECT_ATTR(&ObjectAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, + NULL, + NULL); + create_object(KernelMode, + dir_object_type, + &ObjectAttributes, + KernelMode, + NULL, + sizeof(OBJECT_DIRECTORY), + 0, + 0, + (PVOID*)&type_object_dir); + insert_object((PVOID)type_object_dir, + NULL, + DIRECTORY_ALL_ACCESS, + 0, + NULL, + NULL); + + init_unistr(&Name, (PWSTR)type_type_name); + lookup_obdir_entry(type_object_dir, &Name, 0); + insert_obdir_entry(type_object_dir, type_object_type); + init_unistr(&Name, (PWSTR)dir_type_name); + lookup_obdir_entry(type_object_dir, &Name, 0); + insert_obdir_entry(type_object_dir, dir_object_type); + + init_unistr(&Name, (PWSTR)base_dir_name); + INIT_OBJECT_ATTR(&ObjectAttributes, + &Name, + 0, + NULL, + NULL); + NtCreateDirectoryObject(&Handle, 0, &ObjectAttributes); + base_dir_handle = Handle; + + init_unistr(&Name, (PWSTR)dir_driver); + INIT_OBJECT_ATTR(&ObjectAttributes, + &Name, + 0, + NULL, + NULL); + NtCreateDirectoryObject(&Handle, 0, &ObjectAttributes); + + init_unistr(&Name, (PWSTR)dir_device); + INIT_OBJECT_ATTR(&ObjectAttributes, + &Name, + 0, + NULL, + NULL); + NtCreateDirectoryObject(&Handle, 0, &ObjectAttributes); + device_handle = Handle; + + return TRUE; +} /* end init_object */ + +void exit_object(void) +{ + delete_object_dir(name_space_root); +} /* end exit_object */ + +NTSTATUS +STDCALL +create_type_object(POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, + PUNICODE_STRING type_type_name, + POBJECT_TYPE *ObjectType) +{ + POBJECT_HEADER Header; + POBJECT_TYPE LocalObjectType; + NTSTATUS Status; + + /* Allocate the Object */ + Status = alloc_object(NULL, + type_type_name, + type_object_type, + OBJECT_ALLOC_SIZE(sizeof(OBJECT_TYPE)), + &Header); + if (!NT_SUCCESS(Status)) { + return Status; + } + + LocalObjectType = (POBJECT_TYPE)&Header->Body; + + /* Check if this is the first Object Type */ + if (!type_object_type) { + type_object_type = LocalObjectType; + Header->Type = type_object_type; + } + + /* Set it up */ + LocalObjectType->TypeInfo = *ObjectTypeInitializer; + LocalObjectType->Name = *type_type_name; + + /* Insert it into the Object Directory */ + if (type_object_dir) { + lookup_obdir_entry(type_object_dir, type_type_name, 0); + insert_obdir_entry(type_object_dir, LocalObjectType); + ref_object(type_object_dir); + } + + *ObjectType = LocalObjectType; + + return Status; +} /* end create_type_object */ +EXPORT_SYMBOL(create_type_object); +#endif diff --git a/unifiedkernel/ob/ntobj.c b/unifiedkernel/ob/ntobj.c new file mode 100644 index 0000000..34d4e15 --- /dev/null +++ b/unifiedkernel/ob/ntobj.c @@ -0,0 +1,371 @@ +/* + * ntobj.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * ntobj.c: + * Refered to ReactOS code + */ +#include "object.h" +#include "handle.h" +#include "thread.h" +#include "process.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL +extern POBJECT_TYPE process_object_type; +extern POBJECT_TYPE thread_object_type; +extern POBJECT_TYPE symbol_link_type; + +NTSTATUS +SERVICECALL +NtDuplicateObject(IN HANDLE SourceProcessHandle, + IN HANDLE SourceHandle, + IN HANDLE TargetProcessHandle, + OUT PHANDLE TargetHandle OPTIONAL, + IN ACCESS_MASK DesiredAccess, + IN ULONG InheritHandle, + IN ULONG Options) +{ + struct eprocess *SourceProcess, *TargetProcess; + HANDLE hTarget; + MODE previous_mode; + NTSTATUS Status; + + Status = ref_object_by_handle(SourceProcessHandle, + PROCESS_DUP_HANDLE, + NULL, + KernelMode, + (PVOID *)&SourceProcess, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + Status = ref_object_by_handle(TargetProcessHandle, + PROCESS_DUP_HANDLE, + NULL, + KernelMode, + (PVOID *)&TargetProcess, + NULL); + if (!NT_SUCCESS(Status)) + goto cleanup_source; + + if (SourceHandle == NtCurrentThread() || SourceHandle == NtCurrentProcess()) { + PVOID ObjectBody; + POBJECT_TYPE ObjectType; + + ObjectType = (SourceHandle == NtCurrentThread()) ? thread_object_type : process_object_type; + + Status = ref_object_by_handle(SourceHandle, + 0, + ObjectType, + KernelMode, + &ObjectBody, + NULL); + if (!NT_SUCCESS(Status)) + goto cleanup_target; + + if (Options & DUPLICATE_SAME_ACCESS) + DesiredAccess = ((ObjectType == thread_object_type) ? THREAD_ALL_ACCESS : PROCESS_ALL_ACCESS); + else { + /* FIXME */ +#if 0 + if (DesiredAccess & GENERIC_ANY) + RtlMapGenericMask(&DesiredAccess, &ObjectType->TypeInfo.GenericMapping); +#endif + } + + Status = create_handle(TargetProcess, + ObjectBody, + DesiredAccess, + InheritHandle, + &hTarget); + + deref_object(ObjectBody); + if (!NT_SUCCESS(Status)) + goto cleanup_target; + + if (Options & DUPLICATE_CLOSE_SOURCE) + delete_handle(SourceProcess->object_table, SourceHandle); + } + else { + Status = duplicate_object(SourceProcess, + TargetProcess, + SourceHandle, + &hTarget, + DesiredAccess, + InheritHandle, + Options); + if (!NT_SUCCESS(Status)) + goto cleanup_target; + } + + if (TargetHandle) { + previous_mode = (unsigned long)TargetHandle > TASK_SIZE ? KernelMode: UserMode; + if (previous_mode == UserMode) { + if (copy_to_user(TargetHandle, &hTarget, sizeof(HANDLE))) { + Status = STATUS_NO_MEMORY; + goto cleanup_target; + } + } + else + *TargetHandle = hTarget; + } + +cleanup_target: + deref_object(TargetProcess); +cleanup_source: + deref_object(SourceProcess); + return Status; +} /* end NtDuplicateObject */ +EXPORT_SYMBOL(NtDuplicateObject); + +NTSTATUS +SERVICECALL +NtSetInformationObject(IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + IN PVOID ObjectInformation, + IN ULONG Length) +{ + PVOID ObjectBody; + OBJECT_HANDLE_ATTRIBUTE_INFORMATION Information; + NTSTATUS Status; + + if (ObjectInformationClass != ObjectHandleInformation || + Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) + return STATUS_INVALID_PARAMETER; + + if ((ULONG)ObjectInformation < TASK_SIZE) { + if (copy_from_user(&Information, ObjectInformation, + sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION))) + return STATUS_NO_MEMORY; + } + else + Information = *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)ObjectInformation; + + Status = ref_object_by_handle(ObjectHandle, + 0, + NULL, + KernelMode, + &ObjectBody, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + Status = set_handle_attr(ObjectHandle, &Information); + + deref_object(ObjectBody); + + return Status; +} /* end NtSetInformationObject */ +EXPORT_SYMBOL(NtSetInformationObject); + +NTSTATUS +SERVICECALL +NtQueryObject(IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL) +{ + OBJECT_HANDLE_INFORMATION HandleInfo; + POBJECT_HEADER ObjectHeader; + ULONG InfoLength; + PVOID ObjectBody; + MODE previous_mode; + NTSTATUS Status; + + previous_mode = (unsigned long)ObjectInformation > TASK_SIZE ? KernelMode : UserMode; + + Status = ref_object_by_handle(ObjectHandle, + 0, + NULL, + KernelMode, + &ObjectBody, + &HandleInfo); + if (!NT_SUCCESS(Status)) + return Status; + + ObjectHeader = BODY_TO_HEADER(ObjectBody); + + switch (ObjectInformationClass) { + case ObjectBasicInformation: + if (Length != sizeof(OBJECT_BASIC_INFORMATION)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto out; + } + else { + OBJECT_BASIC_INFORMATION BasicInfo; + + BasicInfo.Attributes = HandleInfo.HandleAttributes; + BasicInfo.GrantedAccess = HandleInfo.GrantedAccess; + BasicInfo.HandleCount = ObjectHeader->HandleCount; + BasicInfo.PointerCount = ObjectHeader->PointerCount; + BasicInfo.PagedPoolUsage = 0; + BasicInfo.NonPagedPoolUsage = 0; + BasicInfo.NameInformationLength = 0; + BasicInfo.TypeInformationLength = 0; + BasicInfo.SecurityDescriptorLength = 0; + if (ObjectHeader->Type == symbol_link_type) + BasicInfo.CreateTime.QuadPart = + ((POBJECT_SYMBOLIC_LINK)ObjectBody)->CreationTime.QuadPart; + else + BasicInfo.CreateTime.QuadPart = (ULONGLONG)0; + InfoLength = sizeof(OBJECT_BASIC_INFORMATION); + + if (previous_mode == UserMode) { + if (copy_to_user(ObjectInformation, &BasicInfo, InfoLength)) { + Status = STATUS_NO_MEMORY; + goto out; + } + } + else + *(POBJECT_BASIC_INFORMATION)ObjectInformation = BasicInfo; + } + break; + + case ObjectNameInformation: + if (Length < 0) { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto out; + } + else { + OBJECT_NAME_INFORMATION NameInfo; + + if (previous_mode == UserMode) { + if (copy_from_user(&NameInfo, ObjectInformation, + sizeof(OBJECT_NAME_INFORMATION))) { + Status = STATUS_NO_MEMORY; + goto out; + } + } + + Status = query_name_string(ObjectBody, + &NameInfo, + Length, + &InfoLength); + + if (previous_mode == UserMode) { + if (copy_to_user(ObjectInformation, &NameInfo, sizeof(NameInfo))) { + Status = STATUS_NO_MEMORY; + goto out; + } + } + else + *(POBJECT_NAME_INFORMATION)ObjectInformation = NameInfo; + } + break; + + case ObjectHandleInformation: + if (Length != sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION)) { + Status = STATUS_INFO_LENGTH_MISMATCH; + goto out; + } + else { + OBJECT_HANDLE_ATTRIBUTE_INFORMATION ObjectInfo; + + Status = query_handle_attr(ObjectHandle, &ObjectInfo); + + InfoLength = sizeof(OBJECT_HANDLE_ATTRIBUTE_INFORMATION); + + if (previous_mode == UserMode) { + if (copy_to_user(ObjectInformation, &ObjectInfo, InfoLength)) { + Status = STATUS_NO_MEMORY; + goto out; + } + } + else + *(POBJECT_HANDLE_ATTRIBUTE_INFORMATION)ObjectInformation = ObjectInfo; + } + break; + + default: + Status = STATUS_NOT_IMPLEMENTED; + goto out; + } + + deref_object(ObjectBody); + + if (ResultLength) { + if (previous_mode == UserMode) { + if (copy_to_user(ResultLength, &InfoLength, sizeof(ULONG))) + return STATUS_NO_MEMORY; + } + else + *ResultLength = InfoLength; + } + + return Status; + +out: + deref_object(ObjectBody); + return Status; +} /* end NtQueryObject */ +EXPORT_SYMBOL(NtQueryObject); + +NTSTATUS +SERVICECALL +NtMakeTemporaryObject(IN HANDLE ObjectHandle) +{ + PVOID ObjectBody; + NTSTATUS Status; + + Status = ref_object_by_handle(ObjectHandle, + 0, + NULL, + KernelMode, + &ObjectBody, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + set_permanent_object(ObjectBody, FALSE); + + deref_object(ObjectBody); + + return Status; +} /* end NtMakeTemporaryObject */ +EXPORT_SYMBOL(NtMakeTemporaryObject); + +NTSTATUS +SERVICECALL +NtMakePermanentObject(IN HANDLE ObjectHandle) +{ + PVOID ObjectBody; + NTSTATUS Status; + + Status = ref_object_by_handle(ObjectHandle, + 0, + NULL, + KernelMode, + &ObjectBody, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + set_permanent_object(ObjectBody, TRUE); + + deref_object(ObjectBody); + + return Status; +} /* end NtMakePermanentObject */ +EXPORT_SYMBOL(NtMakePermanentObject); +#endif diff --git a/unifiedkernel/ob/object.c b/unifiedkernel/ob/object.c new file mode 100644 index 0000000..733a839 --- /dev/null +++ b/unifiedkernel/ob/object.c @@ -0,0 +1,1676 @@ +/* + * object.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * object.c: + * Refered to ReactOS code + */ +#include "object.h" +#include "handle.h" +#include "process.h" +#include "thread.h" +#include "unistr.h" +#include "wineserver/uk_lib.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +extern POBJECT_TYPE file_ctrl_object_type; +extern POBJECT_DIRECTORY file_ctrl_root; + +#define GetCurrentProcess() (HANDLE)-1 + +extern POBJECT_TYPE symbol_link_type; +extern POBJECT_TYPE type_object_type; +extern struct handle_table *kernel_handle_table; + +extern NTSTATUS +parse_symbol_link( + IN PVOID ParseObject, + IN PVOID ObjectType, + IN OUT PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN OUT PUNICODE_STRING CompleteName, + IN OUT PUNICODE_STRING RemainingName, + IN OUT PVOID Context OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + OUT PVOID *Object + ); + +NTSTATUS translate_object_name(PUNICODE_STRING ObjectName) +{ + PWCHAR wc, buf; + BOOLEAN Locked; + PVOID NullObject = NULL; + NTSTATUS Status; + unsigned long Context = TRANSLATE_NAME; + + if ((ULONG)ObjectName->Buffer == (ULONG)ObjectName + sizeof(UNICODE_STRING)) { + buf = (PWSTR)kmalloc(ObjectName->MaximumLength, GFP_KERNEL); + memcpy(buf, ObjectName->Buffer, ObjectName->MaximumLength); + ObjectName->Buffer = buf; + } + + Status = lookup_object_name(NULL, + ObjectName, + OBJ_CASE_INSENSITIVE, + file_ctrl_object_type, + (KPROCESSOR_MODE)UserMode, + (void *)Context, + NULL, + NULL, + NULL, + &Locked, + &NullObject); + if (Status) + return Status; + + /* change ObjectName from \root\file to /root/file */ + for (wc = ObjectName->Buffer; + wc < ObjectName->Buffer + ObjectName->Length / sizeof(WCHAR); + wc++) { + if (*wc == (WCHAR)'\\') + *wc = (WCHAR)'/'; + } + return STATUS_SUCCESS; +} /*end translate_object_name */ +EXPORT_SYMBOL(translate_object_name); + +NTSTATUS +lookup_object_name( + IN HANDLE RootDirectoryHandle OPTIONAL, + IN PUNICODE_STRING ObjectName, + IN ULONG Attributes, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode, + IN PVOID ParseContext OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + IN PVOID InsertObject OPTIONAL, + IN OUT PACCESS_STATE AccessState, + OUT PBOOLEAN DirectoryLocked, + OUT PVOID *FoundObject + ) +{ + POBJECT_DIRECTORY RootDirectory; + POBJECT_DIRECTORY Directory = NULL; + POBJECT_DIRECTORY ParentDirectory = NULL; + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER_NAME_INFO NameInfo; + PVOID Object; + UNICODE_STRING RemainingName; + UNICODE_STRING ComponentName; + PWCH NewName; + NTSTATUS Status; + BOOLEAN Reparse; + ULONG MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS; + OB_PARSE_METHOD ParseProcedure; + extern POBJECT_TYPE file_object_type; + + ktrace("lookup_object_name, root %p, insert object %p, name %d\n", + RootDirectoryHandle, InsertObject, ObjectName->Length); + *DirectoryLocked = FALSE; + *FoundObject = NULL; + Status = STATUS_SUCCESS; + Object = NULL; + + /* Check if the caller has given us a directory to search. + * Otherwise we'll search the root object directory */ + if (RootDirectoryHandle) { + /* reference the directory object */ + Status = ref_object_by_handle(RootDirectoryHandle, + 0, + NULL, + AccessMode, + (PVOID *)&RootDirectory, + NULL); + + if (!NT_SUCCESS(Status)) + return Status; + + ObjectHeader = BODY_TO_HEADER(RootDirectory); + + /* if the name starts with a "\" and it does not file_object_type, the syntax is bad */ + if (ObjectName->Buffer + && *ObjectName->Buffer == OBJ_NAME_PATH_SEPARATOR + && ObjectHeader->Type != file_object_type) { + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + goto DereferenceRoot; + } + + if (ObjectHeader->Type && ObjectHeader->Type != dir_object_type) { + /* do not have the directory of the object types */ + if (!ObjectHeader->Type->TypeInfo.ParseProcedure) { + /* if it doesn't have a parse routine, nothing we can do */ + Status = STATUS_INVALID_HANDLE; + goto DereferenceRoot; + } else { + MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS; + while (TRUE) { + RemainingName = *ObjectName; + + /* call parse routine */ + Status = ObjectHeader->Type->TypeInfo.ParseProcedure( + RootDirectory, + ObjectType, + AccessState, + AccessMode, + Attributes, + ObjectName, + &RemainingName, + ParseContext, + SecurityQos, + &Object); + + if (Status != STATUS_REPARSE) { + /* the status was not to do a reparse */ + if (Status != STATUS_SUCCESS) /* parse error */ + Object = NULL; + else if (!Object) /* parse ok, but object not found */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + + *FoundObject = Object; + goto DereferenceRoot; + } else if (!ObjectName->Length + || !ObjectName->Buffer + || *ObjectName->Buffer == OBJ_NAME_PATH_SEPARATOR) { + /* reparse. Restart the parse relative to the root directory. */ + deref_object(RootDirectory); + RootDirectory = name_space_root; + RootDirectoryHandle = NULL; + + break; + } else if (--MaxReparse) { + continue; + } else { + *FoundObject = Object; + if (!Object) + Status = STATUS_OBJECT_NAME_NOT_FOUND; + + goto DereferenceRoot; + } + } + } + } else if (!ObjectName->Length || !ObjectName->Buffer) { + /* if the caller has given us the directory of object types. + * And the caller didn't specify a name, return the root object directroy. */ + Status = ref_object_by_pointer(RootDirectory, + 0, + ObjectType, + AccessMode); + if (NT_SUCCESS(Status)) + *FoundObject = RootDirectory; + + goto DereferenceRoot; + } + } else { + /* Otherwise the caller did not specify a directory to search. + * So we'll default to the object root directory */ + RootDirectory = name_space_root; + + /* name is empty or not start with a "\", it is illformed. */ + if (!ObjectName->Length || !ObjectName->Buffer + || *ObjectName->Buffer != OBJ_NAME_PATH_SEPARATOR) + return STATUS_OBJECT_PATH_SYNTAX_BAD; + + if (ObjectName->Length == sizeof(OBJ_NAME_PATH_SEPARATOR)) { + /* search for root directory */ + if (!RootDirectory) { +#if 0 + /* If there is not a root directory. return InsertObject */ + if (InsertObject) { + Status = ref_object_by_pointer(InsertObject, + 0, + ObjectType, + AccessMode); + + if (NT_SUCCESS(Status)) + *FoundObject = InsertObject; + + return Status; + } else + return STATUS_INVALID_PARAMETER; +#endif + } else { + /* return RootDirectory */ + Status = ref_object_by_pointer(RootDirectory, + 0, + ObjectType, + AccessMode); + if (NT_SUCCESS(Status)) + *FoundObject = RootDirectory; + + return Status; + } + } + } + + /* + * At this point either + * + * the user specified a directory that is not the object + * type directory and got repase back to the root directory + * + * the user specified the object type directory and gave us + * a name to actually look up + * + * the user did not specify a search directory (default + * to root object directory) and if the name did start off + * with the dos device prefix we've munged outselves back to + * it to the dos device directory for the process + */ + Reparse = TRUE; + MaxReparse = OBJ_MAX_REPARSE_ATTEMPTS; + while (Reparse) { + RemainingName = *ObjectName; + Reparse = FALSE; + + while (TRUE) { + Object = NULL; + + /* trim leader "\" */ + if (RemainingName.Length + && *RemainingName.Buffer == OBJ_NAME_PATH_SEPARATOR) { + RemainingName.Buffer++; + RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); + } + + /* calculate the first component of the remaining name. */ + ComponentName = RemainingName; + while (RemainingName.Length) { + if (*RemainingName.Buffer == OBJ_NAME_PATH_SEPARATOR) + break; + + RemainingName.Buffer++; + RemainingName.Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); + } + + ComponentName.Length -= RemainingName.Length; + if (!ComponentName.Length) { + Status = STATUS_OBJECT_NAME_INVALID; + break; + } + + /* lock root directory */ + if (!*DirectoryLocked) { + *DirectoryLocked = TRUE; + Directory = RootDirectory; + } + + /* look the object in this directory, if not find it, return NULL. */ + Object = lookup_obdir_entry(Directory, &ComponentName, Attributes); + + if (!Object) { + /* We didn't find the object */ + if (RemainingName.Length) { + /* for search path */ + Status = STATUS_OBJECT_PATH_NOT_FOUND; + break; + } + + if (!InsertObject) { + /* for search object */ + Status = STATUS_OBJECT_NAME_NOT_FOUND; + break; + } + + /* The object does not exist and are allowed to create one. */ + NewName = kmalloc(ComponentName.Length + sizeof(WCHAR), GFP_KERNEL); + if ((!NewName) || !insert_obdir_entry(Directory, InsertObject)) { + if (NewName) + kfree(NewName); + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + ref_object(Directory); + /* FIXME */ +#if 0 + ref_object(InsertObject); +#endif + ObjectHeader = BODY_TO_HEADER(InsertObject); + NameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + + /* copy object name info */ + memcpy(NewName, ComponentName.Buffer, ComponentName.Length); + if (NameInfo->Name.Buffer) + kfree(NameInfo->Name.Buffer); + NameInfo->Name.Buffer = NewName; + NameInfo->Name.Length = ComponentName.Length; + NameInfo->Name.MaximumLength = ComponentName.Length + sizeof(WCHAR); + + Object = InsertObject; + Status = STATUS_SUCCESS; + + break; + } + + /* found the component name within the directory. */ + ObjectHeader = BODY_TO_HEADER(Object); + if (ObjectHeader->Type) + ParseProcedure = ObjectHeader->Type->TypeInfo.ParseProcedure; + else + ParseProcedure = NULL; + + if (ParseProcedure == (OB_PARSE_METHOD)parse_symbol_link && !RemainingName.Length) { + ref_object(Object); + Status = STATUS_SUCCESS; + break; + } + + /* if parse routine is exist and find object + * the parse routine is for symbolic links, actually call the parse routine */ + if (ParseProcedure && (!InsertObject || (ParseProcedure == (OB_PARSE_METHOD)parse_symbol_link))) { + /* Reference the object and then free the directory lock */ + ref_object(Object); + + *DirectoryLocked = FALSE; + + Status = ParseProcedure( + Object, + (PVOID)ObjectType, + AccessState, + AccessMode, + Attributes, + ObjectName, + &RemainingName, + ParseContext, + SecurityQos, + &Object); + + /* We can now decrement the object reference count */ + deref_object(&ObjectHeader->Body); + + /* Check if we have some reparsing to do */ + if (Status == STATUS_REPARSE) { + if (--MaxReparse) { + Reparse = TRUE; + + /* Check if we have a reparse object or the name + * starts with a "\" */ + if (*ObjectName->Buffer == OBJ_NAME_PATH_SEPARATOR) { + /* reparse from RootDirectoryObject */ + if (RootDirectoryHandle) { + deref_object(RootDirectory); + RootDirectoryHandle = NULL; + } + + /* And where we start is the root directory object */ + ParentDirectory = NULL; + RootDirectory = name_space_root; + } else if (RootDirectory == name_space_root) { + Object = NULL; + Status = STATUS_OBJECT_NAME_NOT_FOUND; + Reparse = FALSE; + } + } else { + Object = NULL; + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + } else if (Status == STATUS_REPARSE_OBJECT) { + Object = InsertObject; + } else if (!NT_SUCCESS(Status)) { + Object = NULL; + } else if (!Object) { + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + + break; + } else { + /* At this point we do not have a parse routine or if there + * is a parse routine it is not for symbolic links or there + * may not be a specified insert object */ + if (!RemainingName.Length) { + if (!InsertObject) { + /* opening an existing object. */ + Status = ref_object_by_pointer(Object, + 0, + ObjectType, + AccessMode); + + if (!NT_SUCCESS(Status)) + Object = NULL; + } + + break; + } else { + /* the find object is a Directroy, search in this Directory */ + if (ObjectHeader->Type == dir_object_type) { + ParentDirectory = Directory; + Directory = (POBJECT_DIRECTORY)Object; + } else { + /* there has been a mismatch */ + Status = STATUS_OBJECT_TYPE_MISMATCH; + Object = NULL; + + break; + } + } + } + } + } + + /* + * At this point we've parsed the object name as much as possible + * going through symbolic links as necessary. So now set the + * output object pointer, and if we really did not find an object + * then we might need to modify the error status. If the + * status was repase or some success status then translate it + * to name not found. + */ + if (!(*FoundObject = Object)) { + if (Status == STATUS_REPARSE) + Status = STATUS_OBJECT_NAME_NOT_FOUND; + else if (Status == STATUS_REPARSE_OBJECT) + Status = STATUS_SUCCESS; + else if (NT_SUCCESS(Status)) + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* + * If the caller gave us a root directory to search (and we didn't + * zero out this value) then free up our reference + */ + if (RootDirectoryHandle) { + deref_object(RootDirectory); + RootDirectoryHandle = NULL; + } + +out: + return Status; + +DereferenceRoot: + deref_object(RootDirectory); + goto out; +} /* end lookup_object_name */ +EXPORT_SYMBOL(lookup_object_name); + +/* FIXME: SD function + * Not implemented and temporarily put here */ +int release_sec_descpt( + IN PSECURITY_DESCRIPTOR CapturedSecurityDescriptor, + IN KPROCESSOR_MODE CurrentMode, + IN BOOLEAN CaptureIfKernelMode + ) +{ + /* TODO: + * Now, there is nothing to be done */ + return 0; +} /* end release_sec_descpt */ +EXPORT_SYMBOL(release_sec_descpt); + +/* FIXME: SD function + * Not implemented and temporarily put here */ +int capture_sec_descpt( + IN PSECURITY_DESCRIPTOR OriginalSecurityDescriptor, + IN KPROCESSOR_MODE CurrentMode, + IN BOOLEAN CaptureIfKernel, + OUT PSECURITY_DESCRIPTOR *CapturedSecurityDescriptor + ) +{ + /* TODO: + * Now, there is nothing to be done */ + return 0; +} /* end capture_sec_descpt */ +EXPORT_SYMBOL(capture_sec_descpt); + +int capture_object_name(IN OUT PUNICODE_STRING CapturedName, + IN PUNICODE_STRING ObjectName, + IN KPROCESSOR_MODE AccessMode) +{ + if(ObjectName->Length) { + CapturedName->Length = ObjectName->Length; + CapturedName->MaximumLength = ObjectName->Length + sizeof(WCHAR); + CapturedName->Buffer = (WCHAR *)kmalloc(CapturedName->MaximumLength, GFP_KERNEL); + + memcpy(CapturedName->Buffer, ObjectName->Buffer, ObjectName->Length); + CapturedName->Buffer[ObjectName->Length / sizeof(WCHAR)] = 0; + } + + return 0; +} /* end capture_object_name */ + +void release_captured_attr(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo) +{ + /* Release the SD, it's the only thing we allocated */ + if(ObjectCreateInfo->SecurityDescriptor) { + release_sec_descpt(ObjectCreateInfo->SecurityDescriptor, + ObjectCreateInfo->ProbeMode, + TRUE); + ObjectCreateInfo->SecurityDescriptor = NULL; + } +} /* end release_captured_attr */ +EXPORT_SYMBOL(release_captured_attr); + +int capture_object_attr(IN POBJECT_ATTRIBUTES ObjectAttributes, + IN KPROCESSOR_MODE AccessMode, + IN POBJECT_TYPE ObjectType, + IN POBJECT_CREATE_INFORMATION ObjectCreateInfo, + OUT PUNICODE_STRING ObjectName) +{ + int ret = 0; + PSECURITY_DESCRIPTOR sec_descriptor; + PUNICODE_STRING obj_name = NULL; + + /* Zero out object create information */ + memset(ObjectCreateInfo, 0, sizeof(OBJECT_CREATE_INFORMATION)); + + /* Check and set attributes */ + if (ObjectAttributes) { + if(ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) + return STATUS_INVALID_PARAMETER; + + /* Set some create information */ + ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory; + ObjectCreateInfo->Attributes = ObjectAttributes->Attributes; + obj_name = ObjectAttributes->ObjectName; + sec_descriptor = ObjectAttributes->SecurityDescriptor; + + /* Validate the security descriptor */ + if(sec_descriptor) { + ret = capture_sec_descpt(sec_descriptor, + AccessMode, + TRUE, + &ObjectCreateInfo->SecurityDescriptor); + if (ret) { + ObjectCreateInfo->SecurityDescriptor = NULL; + release_captured_attr(ObjectCreateInfo); + return ret; + } + ObjectCreateInfo->SecurityDescriptorCharge = 0; + ObjectCreateInfo->ProbeMode = AccessMode; + } + + /* Validate the QoS*/ + if(ObjectAttributes->SecurityQualityOfService) { + ObjectCreateInfo->SecurityQualityOfService = + *(PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService; + ObjectCreateInfo->SecurityQos = + &ObjectCreateInfo->SecurityQualityOfService; + } + } + + /* Capture name */ + if (obj_name) { + if ((ret = capture_object_name(ObjectName, obj_name, AccessMode))) + release_captured_attr(ObjectCreateInfo); + } + else { + if(ObjectCreateInfo->RootDirectory) + ret = STATUS_OBJECT_NAME_INVALID; + } + + return ret; +} /* capture_object_attr */ +EXPORT_SYMBOL(capture_object_attr); + +int alloc_object(POBJECT_CREATE_INFORMATION ObjectCreateInfo, + PUNICODE_STRING ObjectName, + POBJECT_TYPE ObjectType, + ULONG ObjectSize, + POBJECT_HEADER *ObjectHeader) +{ + ULONG size = ObjectSize; + BOOLEAN has_name_info = false, has_handle_info = false, has_creator_info = false; + POBJECT_HEADER header; + POBJECT_HEADER_HANDLE_INFO handle_info; + POBJECT_HEADER_NAME_INFO name_info; + POBJECT_HEADER_CREATOR_INFO creator_info; + + /* Determine the header size */ + if(ObjectName->Buffer) { + size += sizeof(OBJECT_HEADER_NAME_INFO); + has_name_info = TRUE; + } + + if(ObjectType) { + if(ObjectType->TypeInfo.MaintainHandleCount) { + size += sizeof(OBJECT_HEADER_HANDLE_INFO); + has_handle_info = TRUE; + } + if(ObjectType->TypeInfo.MaintainTypeList) { + size += sizeof(OBJECT_HEADER_CREATOR_INFO); + has_creator_info = TRUE; + } + } + + header = (POBJECT_HEADER)kmalloc(size, GFP_KERNEL); + if(!header) + return STATUS_NO_MEMORY; + + /* Initialize the optional Info */ + if(has_handle_info) { + handle_info = (POBJECT_HEADER_HANDLE_INFO)header; + handle_info->SingleEntry.HandleCount = 0; + header = (POBJECT_HEADER)(handle_info + 1); + } + + if(has_name_info) { + name_info = (POBJECT_HEADER_NAME_INFO)header; + name_info->Name = *ObjectName; + name_info->Directory = NULL; + header = (POBJECT_HEADER)(name_info + 1); + } + + if(has_creator_info) { + creator_info = (POBJECT_HEADER_CREATOR_INFO)header; + INIT_LIST_HEAD(&creator_info->TypeList); + header = (POBJECT_HEADER)(creator_info + 1); + } + + /* Initialize the object header */ + memset(header, 0, ObjectSize); + + atomic_set(&header->HandleCount, 0); + atomic_set(&header->PointerCount, 1); + header->Type = ObjectType; + header->Flags = OB_FLAG_CREATE_INFO; + + /* Set the offset for the Info */ + if(has_handle_info) { + header->HandleInfoOffset = sizeof(OBJECT_HEADER_HANDLE_INFO) + + has_name_info * sizeof(OBJECT_HEADER_NAME_INFO) + + has_creator_info * sizeof(OBJECT_HEADER_CREATOR_INFO); + } + + if(has_name_info) { + header->NameInfoOffset = sizeof(OBJECT_HEADER_NAME_INFO) + + has_creator_info * sizeof(OBJECT_HEADER_CREATOR_INFO); + } + + if(has_creator_info) + header->Flags |= OB_FLAG_CREATE_INFO; + + if(ObjectCreateInfo && (ObjectCreateInfo->Attributes & OBJ_PERMANENT)) + header->Flags |= OB_FLAG_PERMANENT; + if(ObjectCreateInfo && (ObjectCreateInfo->Attributes & OBJ_EXCLUSIVE)) + header->Flags |= OB_FLAG_EXCLUSIVE; + + header->ObjectCreateInfo = ObjectCreateInfo; + + *ObjectHeader = header; + return 0; +} /* end alloc_object */ + +int create_object(IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL, + IN POBJECT_TYPE Type, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN KPROCESSOR_MODE AccessMode, + IN OUT PVOID ParseContext OPTIONAL, + IN ULONG ObjectSize, + IN ULONG PagedPoolCharge OPTIONAL, + IN ULONG NonPagedPoolCharge OPTIONAL, + OUT PVOID *Object) +{ + int ret; + POBJECT_CREATE_INFORMATION obj_create_info; + UNICODE_STRING obj_name = {0, 0, NULL}; + POBJECT_HEADER header; + + ktrace("create_object\n"); + /* Allocate a buffer for the object create information */ + obj_create_info = (POBJECT_CREATE_INFORMATION)kmalloc(sizeof(OBJECT_CREATE_INFORMATION), + GFP_KERNEL); + if (!obj_create_info) + return STATUS_NO_MEMORY; + + /* Capture Attributes */ + ret = capture_object_attr(ObjectAttributes, + AccessMode, + Type, + obj_create_info, + &obj_name); + + /* Allocate a generic object */ + if(!ret) { + ret = alloc_object(obj_create_info, + &obj_name, + Type, + OBJECT_ALLOC_SIZE(ObjectSize), + &header); + + if(!ret) { + *Object = &header->Body; + return ret; + } + release_captured_attr(obj_create_info); + if(obj_name.Buffer) + kfree(obj_name.Buffer); + } + + /* Free buffer */ + kfree(obj_create_info); + return ret; +} /* end create_object */ +EXPORT_SYMBOL(create_object); + +NTSTATUS open_object_by_pointer(IN PVOID Object, + IN ULONG HandleAttributes, + IN PACCESS_STATE PassedAccessState, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode, + OUT PHANDLE Handle) +{ + NTSTATUS ret; + + ret = ref_object_by_pointer(Object, 0, ObjectType, AccessMode); + if (!NT_SUCCESS(ret)) + return ret; + + ret = create_handle(current->ethread ? get_current_eprocess() : NULL, + Object, + DesiredAccess, + (BOOLEAN)(HandleAttributes & OBJ_INHERIT), + Handle); + + deref_object(Object); + + return ret; +} /* end open_object_by_pointer */ +EXPORT_SYMBOL(open_object_by_pointer); + +NTSTATUS open_object_by_name(IN POBJECT_ATTRIBUTES ObjectAttributes, + IN POBJECT_TYPE ObjectType, + IN OUT PVOID ParseContext, + IN KPROCESSOR_MODE AccessMode, + IN ACCESS_MASK DesiredAccess, + IN PACCESS_STATE PassedAccessState, + OUT PHANDLE Handle) +{ + NTSTATUS ret; + UNICODE_STRING obj_name; + PVOID object = NULL; + OBJECT_CREATE_INFORMATION obj_create_info; + BOOLEAN locked; + PACCESS_STATE access = NULL; + + /* search object */ + ret = capture_object_attr(ObjectAttributes, + AccessMode, + ObjectType, + &obj_create_info, + &obj_name); + if (!NT_SUCCESS(ret)) + return ret; /* error */ + + ret = lookup_object_name( + obj_create_info.RootDirectory, + &obj_name, + obj_create_info.Attributes, + ObjectType, + (KPROCESSOR_MODE)KernelMode, + NULL, + NULL, + NULL, + access, + &locked, + &object + ); + release_captured_attr(&obj_create_info); + if (obj_name.Buffer) + kfree(obj_name.Buffer); + + if (!NT_SUCCESS(ret)) + return ret; + + if (!object) + return STATUS_OBJECT_NAME_NOT_FOUND; + + ret = create_handle(current->ethread ? get_current_eprocess() : NULL, + object, + DesiredAccess, + FALSE, + Handle); + + deref_object(object); + + return ret; +} /* end open_object_by_name */ +EXPORT_SYMBOL(open_object_by_name); + +PVOID +lookup_obdir_entry( + IN POBJECT_DIRECTORY Directory, + IN PUNICODE_STRING Name, + IN ULONG Attributes + ) +{ + POBJECT_DIRECTORY_ENTRY *HeadDirectoryEntry; + POBJECT_DIRECTORY_ENTRY DirectoryEntry; + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER_NAME_INFO NameInfo; + PWCH Buffer; + WCHAR Wchar; + ULONG HashIndex; + ULONG WcharLength; + BOOLEAN CaseInSensitive; + + if (!Directory || !Name) + return NULL; + + CaseInSensitive = (Attributes & OBJ_CASE_INSENSITIVE) ? TRUE : FALSE; + + /* check object name */ + Buffer = Name->Buffer; + WcharLength = Name->Length / sizeof( *Buffer ); + if (!WcharLength || !Buffer) + return NULL; + + /* Compute the HASH value */ + HashIndex = 0; + while (WcharLength--) { + Wchar = *Buffer++; + HashIndex += (HashIndex << 1) + (HashIndex >> 1); + + if (Wchar < 'a') + HashIndex += Wchar; + else if (Wchar > 'z') + HashIndex += Wchar; /* FIXME: RtlUpcaseUnicodeChar(Wchar); */ + else + HashIndex += (Wchar - ('a'-'A')); + } + + HashIndex %= NUMBER_HASH_BUCKETS; + HeadDirectoryEntry = (POBJECT_DIRECTORY_ENTRY *)&Directory->HashBuckets[HashIndex]; + Directory->LookupBucket = HeadDirectoryEntry; + + /* Walk the chain of directory entries for this hash bucket, looking + * for either a match, or the insertion point if no match in the chain. */ + while ((DirectoryEntry = *HeadDirectoryEntry) != NULL) { + ObjectHeader = BODY_TO_HEADER(DirectoryEntry->Object); + NameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + + if (NameInfo) { + /* Compare strings using appropriate function. */ + if ((Name->Length == NameInfo->Name.Length) && + equal_unistr(Name, &NameInfo->Name, CaseInSensitive)) + break; /* match */ + } + + HeadDirectoryEntry = &DirectoryEntry->ChainLink; + } + + if (DirectoryEntry) { + /* found an entry that matched and DirectoryEntry points to that entry. */ + Directory->LookupFound = TRUE; + if (HeadDirectoryEntry != Directory->LookupBucket) { + *HeadDirectoryEntry = DirectoryEntry->ChainLink; + DirectoryEntry->ChainLink = *(Directory->LookupBucket); + *(Directory->LookupBucket) = DirectoryEntry; + } + + return DirectoryEntry->Object; + } else { + /* did not find an entry that matched and DirectoryEntry is NULL. */ + Directory->LookupFound = FALSE; + + return NULL; + } +} /* end lookup_obdir_entry */ +EXPORT_SYMBOL(lookup_obdir_entry); + +BOOLEAN +insert_obdir_entry( + IN POBJECT_DIRECTORY Directory, + IN PVOID Object + ) +{ + POBJECT_DIRECTORY_ENTRY *HeadDirectoryEntry; + POBJECT_DIRECTORY_ENTRY NewDirectoryEntry; + POBJECT_HEADER_NAME_INFO NameInfo; + + /* have a directory and that the last search was successful */ + if (!Directory || Directory->LookupFound) + return FALSE; + + HeadDirectoryEntry = Directory->LookupBucket; + if (!HeadDirectoryEntry) + return FALSE; + + /* check the object name */ + if (!(NameInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Object)))) + return FALSE; + + NewDirectoryEntry = (POBJECT_DIRECTORY_ENTRY)kmalloc(sizeof(OBJECT_DIRECTORY_ENTRY), GFP_KERNEL); + if (!NewDirectoryEntry) + return FALSE; + + /* insert at the bucket chain head */ + NewDirectoryEntry->ChainLink = *HeadDirectoryEntry; + *HeadDirectoryEntry = NewDirectoryEntry; + NewDirectoryEntry->Object = Object; + + NameInfo->Directory = Directory; + + Directory->LookupFound = TRUE; + + return TRUE; +} /* end insert_obdir_entry */ +EXPORT_SYMBOL(insert_obdir_entry); + +NTSTATUS +insert_object( + IN PVOID Object, + IN PACCESS_STATE AccessState OPTIONAL, + IN ACCESS_MASK DesiredAccess OPTIONAL, + IN ULONG ObjectPointerBias, + OUT PVOID *NewObject OPTIONAL, + OUT PHANDLE Handle + ) +{ + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + POBJECT_HEADER ObjectHeader; + PUNICODE_STRING ObjectName; + POBJECT_TYPE ObjectType; + POBJECT_HEADER_NAME_INFO NameInfo; + PVOID InsertObject; + HANDLE NewHandle; + BOOLEAN DirectoryLocked; + OB_OPEN_REASON OpenReason; + NTSTATUS Status = STATUS_SUCCESS; + NTSTATUS ReturnStatus; + + ktrace("insert_object\n"); + ObjectHeader = BODY_TO_HEADER(Object); + ObjectCreateInfo = ObjectHeader->ObjectCreateInfo; + ObjectType = ObjectHeader->Type; + NameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + + ObjectName = NULL; + if (NameInfo && NameInfo->Name.Buffer) + ObjectName = &NameInfo->Name; + + /* Set some local state variables */ + DirectoryLocked = FALSE; + InsertObject = Object; + OpenReason = ObCreateHandle; + + /* Check if we have an object name. If so then lookup the name */ + if (ObjectName) { + /* for file_ctrl_object_type, rename */ + if (ObjectType == file_ctrl_object_type) { + PWCHAR wc; + + /* change ObjectName from \root\file to /root/file */ + for (wc = ObjectName->Buffer; + wc < ObjectName->Buffer + ObjectName->Length / sizeof(WCHAR); + wc++) { + if (*wc == (WCHAR)'\\') + *wc = (WCHAR)'/'; + } + } + + Status = lookup_object_name(ObjectCreateInfo->RootDirectory, + ObjectName, + ObjectCreateInfo->Attributes, + ObjectType, + (KPROCESSOR_MODE)(ObjectHeader->Flags & OB_FLAG_KERNEL_OBJECT + ? KernelMode : UserMode), + ObjectCreateInfo->ParseContext, + ObjectCreateInfo->SecurityQos, + Object, + AccessState, + &DirectoryLocked, + &InsertObject); + + if (NT_SUCCESS(Status) && InsertObject && InsertObject != Object) { + if (ObjectType == BODY_TO_HEADER(InsertObject)->Type) { + if (NewObject) + *NewObject = InsertObject; /* return the found object */ + Status = STATUS_OBJECT_NAME_EXISTS; + } else + Status = STATUS_OBJECT_TYPE_MISMATCH; + } + } + + ReturnStatus = Status; + /* FIXME: ObjectHeader->ObjectCreateInfo = NULL; */ + + if (!Handle) + return ReturnStatus; + + /* Create a named handle for the object */ + Status = create_handle(current->ethread ? get_current_eprocess() : NULL, + InsertObject, + DesiredAccess, + ObjectCreateInfo->Attributes & OBJ_INHERIT, + &NewHandle); + + /* release_captured_attr(ObjectCreateInfo); */ + + if (!NT_SUCCESS(Status)) { + *Handle = NULL; + ReturnStatus = Status; + } else + *Handle = NewHandle; + + return ReturnStatus; +} /* end insert_object */ +EXPORT_SYMBOL(insert_object); + +BOOLEAN +delete_obdir_entry ( + IN POBJECT_DIRECTORY Directory + ) +{ + POBJECT_DIRECTORY_ENTRY *HeadDirectoryEntry; + POBJECT_DIRECTORY_ENTRY DirectoryEntry; + + if (!Directory || !Directory->LookupFound) + return FALSE; + + /* Also make sure that the lookup bucket is valid */ + HeadDirectoryEntry = Directory->LookupBucket; + if (!HeadDirectoryEntry) + return FALSE; + DirectoryEntry = *HeadDirectoryEntry; + if (!DirectoryEntry) + return FALSE; + + /* Unlink the entry from the head of the bucket chain and free the memory for the entry. */ + *HeadDirectoryEntry = DirectoryEntry->ChainLink; + DirectoryEntry->ChainLink = NULL; + + kfree(DirectoryEntry); + deref_object(Directory); + + return TRUE; +} /* end delete_obdir_entry */ +EXPORT_SYMBOL(delete_obdir_entry); + +VOID +deref_object(IN PVOID Object) +{ + POBJECT_HEADER header = BODY_TO_HEADER(Object); + + if (atomic_dec_return(&header->PointerCount) == 0 && !(header->Flags & OB_FLAG_PERMANENT)) + delete_object(header); +} /* end deref_object */ +EXPORT_SYMBOL(deref_object); + +NTSTATUS +delete_object(POBJECT_HEADER Header) +{ + PVOID header_location = Header; + POBJECT_HEADER_CREATOR_INFO creator_info; + POBJECT_HEADER_NAME_INFO name_info; + POBJECT_HEADER_HANDLE_INFO handle_info; + + if (Header->Type && Header->Type->TypeInfo.DeleteProcedure) + Header->Type->TypeInfo.DeleteProcedure(&Header->Body); + + name_info = HEADER_TO_OBJECT_NAME(Header); +#if 0 + if (name_info && name_info->Directory) { + lookup_obdir_entry(name_info->Directory, &name_info->Name, OBJ_CASE_INSENSITIVE); + delete_obdir_entry(name_info->Directory); + } +#endif + + if (name_info && name_info->Name.Buffer && Header->Type != type_object_type) + kfree(name_info->Name.Buffer); + + if (Header->ObjectCreateInfo) { + release_captured_attr(Header->ObjectCreateInfo); + kfree(Header->ObjectCreateInfo); + } + + /* To find the header, walk backwards from how we allocated */ + if ((creator_info = HEADER_TO_CREATOR_INFO(Header))) + header_location = creator_info; + if (name_info) + header_location = name_info; + if ((handle_info = HEADER_TO_HANDLE_INFO(Header))) + header_location = handle_info; + + kfree(header_location); + + return STATUS_SUCCESS; +} /* end delete_object */ + +NTSTATUS +ref_object_by_pointer(IN PVOID Object, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_TYPE ObjectType, + IN KPROCESSOR_MODE AccessMode) +{ + POBJECT_HEADER header = BODY_TO_HEADER(Object); + + if (ObjectType && header->Type != ObjectType) + return STATUS_OBJECT_TYPE_MISMATCH; + + if (atomic_read(&header->PointerCount) == 0 && !(header->Flags & OB_FLAG_PERMANENT)) + return STATUS_UNSUCCESSFUL; + + atomic_inc(&header->PointerCount); + + return STATUS_SUCCESS; +} /* end ref_object_by_pointer */ +EXPORT_SYMBOL(ref_object_by_pointer); + +NTSTATUS +duplicate_object(struct eprocess *SourceProcess, + struct eprocess *TargetProcess, + HANDLE SourceHandle, + PHANDLE TargetHandle, + ACCESS_MASK DesiredAccess, + BOOLEAN InheritHandle, + ULONG Options) +{ + struct handle_table *SourceHandleTable; + struct handle_table_entry *SourceHandleEntry; + struct handle_table_entry NewHandleEntry; + POBJECT_HEADER ObjectHeader; + PVOID ObjectBody; + LONG ExSourceHandle; + LONG ExTargetHandle; + + if (is_kernel_handle(SourceHandle, KernelMode)) { + SourceHandleTable = kernel_handle_table; + SourceHandle = KERNEL_HANDLE_TO_HANDLE(SourceHandle); + } + else + SourceHandleTable = SourceProcess->object_table; + +#ifdef UK_HANDLE + SourceHandle = UK_HANDLE_TO_HANDLE(SourceHandle); +#endif + ExSourceHandle = HANDLE_TO_EX_HANDLE(SourceHandle); + SourceHandleEntry = map_handle_to_pointer(SourceHandleTable, ExSourceHandle); + if (!SourceHandleEntry) + return STATUS_INVALID_HANDLE; + + ObjectHeader = EX_HTE_TO_HDR(SourceHandleEntry); + ObjectBody = &ObjectHeader->Body; + + NewHandleEntry.u1.object = SourceHandleEntry->u1.object; + if (InheritHandle) + NewHandleEntry.u1.obattributes |= EX_HANDLE_ENTRY_INHERITABLE; + else + NewHandleEntry.u1.obattributes &= ~EX_HANDLE_ENTRY_INHERITABLE; + + if (Options & DUPLICATE_SAME_ACCESS) + NewHandleEntry.u2.granted_access = SourceHandleEntry->u2.granted_access; + else { + /* FIXME */ +/* if (DesiredAccess & GENERIC_ANY) { + RtlMapGenericMask(&DesiredAccess, &ObjectHeader->Type->TypeInfo.GenericMapping); + } +*/ + NewHandleEntry.u2.granted_access = SourceHandleEntry->u2.granted_access; + } + + if (atomic_inc_return(&ObjectHeader->HandleCount) < 2) + return STATUS_UNSUCCESSFUL; + + ref_object(ObjectBody); + + unlock_handle_table_entry(SourceHandleTable, SourceHandleEntry); + + ExTargetHandle = create_ex_handle(TargetProcess->object_table, &NewHandleEntry); + if (ExTargetHandle != EX_INVALID_HANDLE) { + if (Options & DUPLICATE_CLOSE_SOURCE) + delete_handle(SourceHandleTable, SourceHandle); + + *TargetHandle = EX_HANDLE_TO_HANDLE(ExTargetHandle); +#ifdef UK_HANDLE + *TargetHandle = HANDLE_TO_UK_HANDLE(*TargetHandle); +#endif + + return STATUS_SUCCESS; + } + else { + atomic_dec_return(&ObjectHeader->HandleCount); + + deref_object(ObjectBody); + return STATUS_INSUFFICIENT_RESOURCES; + } +} /* end duplicate_object */ + +NTSTATUS +set_handle_attr(HANDLE Handle, + POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo) +{ + struct handle_table *HandleTable; + struct handle_table_entry *HandleTableEntry; + LONG ExHandle; + + if (is_kernel_handle(Handle, KernelMode)) { + HandleTable = kernel_handle_table; +#ifdef UK_HANDLE + Handle = UK_HANDLE_TO_HANDLE(Handle); +#endif + ExHandle = HANDLE_TO_EX_HANDLE(KERNEL_HANDLE_TO_HANDLE(Handle)); + } + else { + struct eprocess *process = get_current_eprocess(); + + HandleTable = process->object_table; +#ifdef UK_HANDLE + Handle = UK_HANDLE_TO_HANDLE(Handle); +#endif + ExHandle = HANDLE_TO_EX_HANDLE(Handle); + } + + HandleTableEntry = map_handle_to_pointer(HandleTable, ExHandle); + if (!HandleTableEntry) + return STATUS_INVALID_HANDLE; + + if (HandleInfo->Inherit) + HandleTableEntry->u1.obattributes |= EX_HANDLE_ENTRY_INHERITABLE; + else + HandleTableEntry->u1.obattributes &= ~EX_HANDLE_ENTRY_INHERITABLE; + + if (HandleInfo->ProtectFromClose) + HandleTableEntry->u1.obattributes |= EX_HANDLE_ENTRY_PROTECTFROMCLOSE; + else + HandleTableEntry->u1.obattributes &= ~EX_HANDLE_ENTRY_PROTECTFROMCLOSE; + + unlock_handle_table_entry(HandleTable, HandleTableEntry); + + return STATUS_SUCCESS; +} /* end set_handle_attr */ + +NTSTATUS +query_handle_attr(HANDLE Handle, + POBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo) +{ + struct handle_table *HandleTable; + struct handle_table_entry *HandleTableEntry; + LONG ExHandle; + + if (is_kernel_handle(Handle, KernelMode)) { + HandleTable = kernel_handle_table; +#ifdef UK_HANDLE + Handle = UK_HANDLE_TO_HANDLE(Handle); +#endif + ExHandle = HANDLE_TO_EX_HANDLE(KERNEL_HANDLE_TO_HANDLE(Handle)); + } + else { + struct eprocess *process = get_current_eprocess(); + + HandleTable = process->object_table; +#ifdef UK_HANDLE + Handle = UK_HANDLE_TO_HANDLE(Handle); +#endif + ExHandle = HANDLE_TO_EX_HANDLE(Handle); + } + + HandleTableEntry = map_handle_to_pointer(HandleTable, ExHandle); + if (!HandleTableEntry) + return STATUS_INVALID_HANDLE; + + HandleInfo->Inherit = (HandleTableEntry->u1.obattributes & EX_HANDLE_ENTRY_INHERITABLE) != 0; + HandleInfo->ProtectFromClose = (HandleTableEntry->u1.obattributes & EX_HANDLE_ENTRY_PROTECTFROMCLOSE) != 0; + + unlock_handle_table_entry(HandleTable, HandleTableEntry); + + return STATUS_SUCCESS; +} /* end query_handle_attr */ + +VOID +set_permanent_object(IN PVOID ObjectBody, IN BOOLEAN Permanent) +{ + POBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody); + + if (atomic_read(&ObjectHeader->PointerCount) < 0) + return; + + if (Permanent) + ObjectHeader->Flags |= OB_FLAG_PERMANENT; + else { + POBJECT_HEADER_NAME_INFO name_info = HEADER_TO_OBJECT_NAME(ObjectHeader); + + ObjectHeader->Flags &= ~OB_FLAG_PERMANENT; + if (atomic_read(&ObjectHeader->HandleCount) == 0 && + name_info && name_info->Directory) { + lookup_obdir_entry(name_info->Directory, &name_info->Name, OBJ_CASE_INSENSITIVE); + delete_obdir_entry(name_info->Directory); + } + } +} /* end set_permanent_object */ +EXPORT_SYMBOL(set_permanent_object); + +VOID +make_temp_object(IN PVOID ObjectBody) +{ + set_permanent_object(ObjectBody, FALSE); +} /* end make_temp_object */ +EXPORT_SYMBOL(make_temp_object); + +NTSTATUS +query_name_string(IN PVOID Object, + OUT POBJECT_NAME_INFORMATION ObjectNameInfo, + IN ULONG Length, + OUT PULONG ReturnLength) +{ + POBJECT_HEADER ObjectHeader; + POBJECT_HEADER_NAME_INFO NameInfo; + POBJECT_DIRECTORY Directory; + ULONG NameSize, NewLength; + PWSTR ObjectName; + NTSTATUS Status = STATUS_SUCCESS; + + ObjectHeader = BODY_TO_HEADER(Object); + NameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + + if (ObjectHeader->Type->TypeInfo.QueryNameProcedure) { + Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object, + ObjectNameInfo, + Length, + ReturnLength); + + return Status; + } + + if (!NameInfo || !NameInfo->Name.Buffer) { + *ReturnLength = sizeof(OBJECT_NAME_INFORMATION); + + if (*ReturnLength > Length) + return STATUS_INFO_LENGTH_MISMATCH; + + ObjectNameInfo->Name.Length = 0; + ObjectNameInfo->Name.MaximumLength = 0; + ObjectNameInfo->Name.Buffer = NULL; + + return Status; + } + + if (Object == name_space_root) + NameSize = sizeof(UNICODE_PATH_SEP); + else { + Directory = NameInfo->Directory; + NameSize = sizeof(UNICODE_PATH_SEP) + NameInfo->Name.Length; + + while (Directory && Directory != name_space_root) { + NameInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Directory)); + + if (NameInfo && NameInfo->Directory) { + NameSize += sizeof(UNICODE_PATH_SEP) + NameInfo->Name.Length; + + Directory = NameInfo->Directory; + } else { + NameSize += sizeof(UNICODE_NO_PATH) + sizeof(UNICODE_PATH_SEP); + break; + } + } + } + NewLength = NameSize + sizeof(UNICODE_NULL) + sizeof(OBJECT_NAME_INFORMATION); + if (NewLength > Length) + return STATUS_INFO_LENGTH_MISMATCH; + + NameInfo = HEADER_TO_OBJECT_NAME(ObjectHeader); + ObjectName = (PWSTR)((ULONG_PTR)ObjectNameInfo + NewLength); + *--ObjectName = UNICODE_NULL; + + *ReturnLength = NewLength; + + if (Object == name_space_root) { + *--ObjectName = UNICODE_PATH_SEP; + ObjectNameInfo->Name.Length = (USHORT)NameSize; + ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL)); + ObjectNameInfo->Name.Buffer = ObjectName; + + return Status; + } else { + ObjectName = (PWSTR)((ULONG_PTR)ObjectName - NameInfo->Name.Length); + ObjectName = NameInfo->Name.Buffer; + + Directory = NameInfo->Directory; + while (Directory && Directory != name_space_root) { + NameInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Directory)); + + *--ObjectName = UNICODE_PATH_SEP; + + if (NameInfo && NameInfo->Name.Buffer) { + ObjectName = (PWSTR)((ULONG_PTR)ObjectName - NameInfo->Name.Length); + memmove(ObjectName, NameInfo->Name.Buffer, NameInfo->Name.Length); + + Directory = NameInfo->Directory; + } else { + ObjectName -= sizeof(UNICODE_NO_PATH); + ObjectName = (PWSTR)UNICODE_NO_PATH; + break; + } + } + + *--ObjectName = UNICODE_PATH_SEP; + ObjectNameInfo->Name.Length = (USHORT)NameSize; + ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL)); + memcpy(ObjectNameInfo->Name.Buffer, ObjectName, ObjectNameInfo->Name.Length); + } + + return Status; +} /* query_name_string */ +EXPORT_SYMBOL(query_name_string); + +LONG +copy_object_attr_from_user( + POBJECT_ATTRIBUTES UserObjectAttr, + POBJECT_ATTRIBUTES *KernelObjectAttr + ) +{ + LONG Length; + NTSTATUS Status; + BOOLEAN HaveName; + POBJECT_ATTRIBUTES Local; + + if ((ULONG)UserObjectAttr >= TASK_SIZE || *KernelObjectAttr) + return STATUS_INVALID_PARAMETER; + + HaveName = UserObjectAttr->ObjectName ? TRUE : FALSE; + + Length = sizeof(OBJECT_ATTRIBUTES) + sizeof(UNICODE_STRING); + Length += HaveName ? UserObjectAttr->ObjectName->MaximumLength : 0; + Local = (POBJECT_ATTRIBUTES)kmalloc(Length, GFP_KERNEL); + if (!Local) + return STATUS_NO_MEMORY; + + Status = STATUS_NO_MEMORY; + if (copy_from_user(Local, UserObjectAttr, sizeof(*Local))) + goto cleanup; + + if (HaveName) { + Local->ObjectName = (PUNICODE_STRING)(Local + 1); + if (copy_from_user(Local->ObjectName, UserObjectAttr->ObjectName, sizeof(UNICODE_STRING))) + goto cleanup; + + Local->ObjectName->Buffer = (PWSTR)(Local->ObjectName + 1); + if (copy_from_user(Local->ObjectName->Buffer, + UserObjectAttr->ObjectName->Buffer, + UserObjectAttr->ObjectName->MaximumLength)) + goto cleanup; + } + + *KernelObjectAttr = Local; + return STATUS_SUCCESS; + +cleanup: + kfree(Local); + return Status; +} +EXPORT_SYMBOL(copy_object_attr_from_user); + +/* release an object (i.e. decrement its refcount) */ +void release_object(void *object ) +{ + struct object *obj = (struct object *)object; + POBJECT_HEADER obj_header = BODY_TO_HEADER(object); + POBJECT_HEADER_NAME_INFO obj_name = HEADER_TO_OBJECT_NAME(obj_header); +#if 0 + assert( obj->refcount ); +#endif + if (atomic_dec_return(&obj_header->PointerCount) == 0 && !(obj_header->Flags & OB_FLAG_PERMANENT)) { + /* if the refcount is 0, nobody can be in the wait queue */ +#if 0 + assert( list_empty( &obj->wait_queue )); +#endif + if (obj_header->ops) + obj_header->ops->destroy(obj); +#ifdef DEBUG_OBJECTS + list_remove( &obj->obj_list ); + if (obj_header->ops) + memset( obj, 0xaa, BODY_TO_HEADER(obj)->ops->size ); +#endif +#if 0 + kfree( obj ); /* how to free OBJECT_HEADER? + should we close the fd in kernel? */ +#endif + if (obj_name && obj_name->Directory && !(obj_header->Flags & OB_FLAG_PERMANENT)) { + lookup_obdir_entry(obj_name->Directory, &obj_name->Name, OBJ_CASE_INSENSITIVE); + delete_obdir_entry(obj_name->Directory); + } + delete_object(obj_header); + } +} + +void *alloc_wine_object( const struct object_ops *ops ) +{ + UNICODE_STRING name = {0, 0, NULL}; + POBJECT_HEADER ObjectHeader; + + alloc_object(NULL /*ObjectCreateInfo*/, &name, NULL /*ObjectType*/, + OBJECT_ALLOC_SIZE(ops->size), &ObjectHeader); + ObjectHeader->ops = ops; + return &ObjectHeader->Body; +} + +void objattr_get_name( const struct object_attributes *objattr, struct unicode_str *name ) +{ + name->len = ((objattr->name_len) / sizeof(WCHAR)) * sizeof(WCHAR); + name->str = (const WCHAR *)objattr + (sizeof(*objattr) + objattr->sd_len) / sizeof(WCHAR); +} + +void *create_wine_object( HANDLE namespace, const struct object_ops *ops, + const struct unicode_str *name, struct object *parent ) +{ + PVOID object, new_object; + UNICODE_STRING obj_name; + OBJECT_ATTRIBUTES obj_attr; + int ret; + + obj_name.Length = (USHORT)name->len; + obj_name.MaximumLength = obj_name.Length + sizeof(WCHAR); + obj_name.Buffer = (PWSTR)name->str; + INIT_OBJECT_ATTR(&obj_attr, &obj_name, 0, namespace, NULL); + + ret = create_object(KernelMode, + NULL, + &obj_attr, + KernelMode, + NULL, + ops->size, + 0, + 0, + (PVOID *)&object); + if (!NT_SUCCESS(ret)) + return NULL; + + ret = insert_object(object, + NULL, + 0, + 0, + &new_object, + NULL); + if (ret == STATUS_OBJECT_NAME_EXISTS) { + release_object(object); + grab_object(new_object); + + set_error(STATUS_OBJECT_NAME_EXISTS); + return new_object; + } + if (!NT_SUCCESS(ret)) + return NULL; + + BODY_TO_HEADER(object)->ops = ops; + if (parent) grab_object(parent); + + return object; +} + +struct object *find_object( HANDLE RootDirectory, const struct unicode_str *name, unsigned int attributes ) +{ + UNICODE_STRING obj_name; + void *object; + + obj_name.Length = (USHORT)name->len; + obj_name.MaximumLength = obj_name.Length + sizeof(WCHAR); + obj_name.Buffer = (PWSTR)name->str; + lookup_object_name( + RootDirectory, + &obj_name, + attributes, + NULL, + (KPROCESSOR_MODE)KernelMode, + NULL, + NULL, + NULL, + NULL, + NULL, + &object + ); + + return object; +} + +HANDLE open_object(HANDLE RootDirectory, const struct unicode_str *name, + const struct object_ops* ops, unsigned int access, unsigned int attr) +{ + UNICODE_STRING obj_name; + OBJECT_ATTRIBUTES obj_attr; + HANDLE handle; + + obj_name.Length = (USHORT)name->len; + obj_name.MaximumLength = obj_name.Length + sizeof(WCHAR); + obj_name.Buffer = (PWSTR)name->str; + INIT_OBJECT_ATTR(&obj_attr, &obj_name, 0, RootDirectory, NULL); + open_object_by_name(&obj_attr, + NULL, + NULL, + KernelMode, + attr, + NULL, + &handle); + return handle; +} + +/* stubs from Wine server */ +struct object *find_object_index( const struct namespace *namespace, unsigned int index ) +{ + return NULL; +} + +BOOL check_object_access(struct object* obj, unsigned int* access) +{ + return 0; +} + +int objattr_is_valid( const struct object_attributes *attrib, int size) +{ + return TRUE; +} + +void make_object_static( struct object *obj ) +{ +} + +#endif diff --git a/unifiedkernel/ob/symlink.c b/unifiedkernel/ob/symlink.c new file mode 100644 index 0000000..a59d9eb --- /dev/null +++ b/unifiedkernel/ob/symlink.c @@ -0,0 +1,328 @@ +/* + * symlink.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * symlink.c: + * Refered to ReactOS code + */ +#include "object.h" +#include "unistr.h" +#include "io.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +#define SYMBOLIC_LINK_QUERY 0x0001 +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) + +extern BOOLEAN is_dos_driver(PUNICODE_STRING Name); + +POBJECT_TYPE symbol_link_type = NULL; +EXPORT_SYMBOL(symbol_link_type); + +static GENERIC_MAPPING symbol_link_mapping = { + STANDARD_RIGHTS_READ | SYMBOLIC_LINK_QUERY, + STANDARD_RIGHTS_WRITE, + STANDARD_RIGHTS_EXECUTE | SYMBOLIC_LINK_QUERY, + SYMBOLIC_LINK_ALL_ACCESS}; +extern VOID STDCALL init_unistr(PUNICODE_STRING, PWSTR); +static WCHAR LinkName[] = {'S', 'y', 'm', 'b', 'o', 'l', 'i', 'c', 'L', 'i', 'n', 'k', 0}; + + +VOID +delete_symbol_link(PVOID ObjectBody) +{ + POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody; + + if (SymlinkObject->TargetName.Buffer) { + kfree(SymlinkObject->TargetName.Buffer); + SymlinkObject->TargetName.Buffer = NULL; + } +} /* end delete_symbol_link */ + +NTSTATUS +parse_symbol_link( + IN PVOID ParseObject, + IN PVOID ObjectType, + IN PACCESS_STATE AccessState, + IN KPROCESSOR_MODE AccessMode, + IN ULONG Attributes, + IN OUT PUNICODE_STRING CompleteName, + IN OUT PUNICODE_STRING RemainingPath, + IN OUT PVOID Context OPTIONAL, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, + OUT PVOID *NextObject + ) +{ + POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ParseObject; + UNICODE_STRING TargetPath; + POBJECT_HEADER_NAME_INFO NameInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParseObject)); + + if (!RemainingPath) { + return STATUS_INVALID_PARAMETER; + } + + /* Stop parsing if the entire path has been parsed and + * the desired object is a symbolic link object. */ + if (!RemainingPath->Length && (Attributes & OBJ_OPENLINK)) { + return STATUS_SUCCESS; + } + + /* build the expanded path */ + TargetPath.MaximumLength = SymlinkObject->TargetName.MaximumLength; + TargetPath.MaximumLength += RemainingPath->MaximumLength; + TargetPath.Length = SymlinkObject->TargetName.Length + RemainingPath->Length; + TargetPath.Buffer = kmalloc(TargetPath.MaximumLength, GFP_KERNEL); + memcpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer, SymlinkObject->TargetName.Length); + TargetPath.Buffer[TargetPath.Length / sizeof(WCHAR)] = (WCHAR)'\0'; + if (RemainingPath->Length) { + WCHAR *wc; + + memcpy((char *)TargetPath.Buffer + SymlinkObject->TargetName.Length, + RemainingPath->Buffer, RemainingPath->Length); + if (Context) { + for (wc = (WCHAR *)((char *)TargetPath.Buffer + SymlinkObject->TargetName.Length); *wc; wc++) + if (*wc == (WCHAR)'\\') + *wc = (WCHAR)'/'; + } + } + + /* transfer target path buffer into FullPath */ + kfree(CompleteName->Buffer); + *CompleteName = TargetPath; + + /* reinitialize RemainingPath for reparsing */ + *RemainingPath = TargetPath; + + if (NameInfo && is_dos_driver(&NameInfo->Name)) { + *NextObject = ParseObject; + return STATUS_REPARSE_OBJECT; + } else { + return STATUS_REPARSE; + } +} /* end parse_symbol_link */ + +VOID +init_symbol_link(VOID) +{ + UNICODE_STRING Name; + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + + /* Create the object type for the "SymbolicLink" object. */ + memset(&ObjectTypeInitializer, 0, sizeof(OBJECT_TYPE_INITIALIZER)); + init_unistr(&Name, (PWSTR)LinkName); + ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(OBJECT_SYMBOLIC_LINK); + ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS; + ObjectTypeInitializer.GenericMapping = symbol_link_mapping; + ObjectTypeInitializer.DeleteProcedure = delete_symbol_link; + ObjectTypeInitializer.ParseProcedure = parse_symbol_link; + create_type_object(&ObjectTypeInitializer, &Name, &symbol_link_type); +} /* end init_symbol_link */ + +NTSTATUS SERVICECALL +NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING LinkTarget) +{ + HANDLE hLink; + POBJECT_SYMBOLIC_LINK SymbolicLink; + UNICODE_STRING CapturedLinkTarget; + POBJECT_ATTRIBUTES obj_attr = NULL; + MODE previous_mode; + NTSTATUS Status = STATUS_SUCCESS; + + previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; + if (ObjectAttributes) { + if (previous_mode == UserMode) { + if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) + return STATUS_NO_MEMORY; + } + else + obj_attr = ObjectAttributes; + } + + Status = capture_unistr(&CapturedLinkTarget, + KernelMode, + PagedPool, + FALSE, + LinkTarget); + if (!NT_SUCCESS(Status)) { + goto cleanup; + } + + Status = create_object(KernelMode, + symbol_link_type, + obj_attr, + KernelMode, + NULL, + sizeof(OBJECT_SYMBOLIC_LINK), + 0, + 0, + (PVOID*)&SymbolicLink); + if (NT_SUCCESS(Status)) { + SymbolicLink->TargetName.Length = 0; + SymbolicLink->TargetName.MaximumLength = LinkTarget->Length + sizeof(WCHAR); + SymbolicLink->TargetName.Buffer = + kmalloc(SymbolicLink->TargetName.MaximumLength, GFP_KERNEL); + copy_unistr(&SymbolicLink->TargetName, &CapturedLinkTarget); + + Status = insert_object((PVOID)SymbolicLink, + NULL, + DesiredAccess, + 0, + NULL, + &hLink); + if (NT_SUCCESS(Status)) { + if (previous_mode == UserMode) { + if (copy_to_user(LinkHandle, &hLink, sizeof(HANDLE))) { + Status = STATUS_NO_MEMORY; + goto cleanup; + } + } + else + *LinkHandle = hLink; + } + deref_object(SymbolicLink); + } + + release_unistr(&CapturedLinkTarget, + KernelMode, + FALSE); + +cleanup: + if (obj_attr && previous_mode == UserMode) + kfree(obj_attr); + + return Status; +} /* end NtCreateSymbolicLinkObject */ +EXPORT_SYMBOL(NtCreateSymbolicLinkObject); + +NTSTATUS SERVICECALL +NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + HANDLE hLink; + OBJECT_ATTRIBUTES Attributes; + UNICODE_STRING Name; + NTSTATUS Status = STATUS_SUCCESS; + MODE previous_mode; + + previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; + if (previous_mode == UserMode) { + if ((copy_from_user(&Attributes, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)))) + return STATUS_NO_MEMORY; + if ((copy_from_user(&Name, ObjectAttributes->ObjectName, sizeof(UNICODE_STRING)))) + return STATUS_NO_MEMORY; + } + else { + Attributes = *ObjectAttributes; + Name = *ObjectAttributes->ObjectName; + } + Attributes.ObjectName = &Name; + + Status = open_object_by_name(&Attributes, + symbol_link_type, + NULL, + KernelMode, + DesiredAccess, + NULL, + &hLink); + if (NT_SUCCESS(Status)) { + if (LinkHandle) { + if (previous_mode == UserMode) { + if (copy_to_user(LinkHandle, &hLink, sizeof(HANDLE))) + return STATUS_NO_MEMORY; + } + else + *LinkHandle = hLink; + } + } + + return Status; +} /* end NtOpenSymbolicLinkObject */ +EXPORT_SYMBOL(NtOpenSymbolicLinkObject); + +NTSTATUS SERVICECALL +NtQuerySymbolicLinkObject(IN HANDLE LinkHandle, + OUT PUNICODE_STRING LinkTarget, + OUT PULONG ResultLength OPTIONAL) +{ + UNICODE_STRING SafeLinkTarget; + POBJECT_SYMBOLIC_LINK SymlinkObject; + NTSTATUS Status = STATUS_SUCCESS; + MODE previous_mode; + + previous_mode = (unsigned long)LinkTarget > TASK_SIZE ? KernelMode : UserMode; + if (previous_mode == UserMode) { + if (copy_from_user(&SafeLinkTarget, LinkTarget, sizeof(UNICODE_STRING))) + return STATUS_NO_MEMORY; + } + else + SafeLinkTarget = *LinkTarget; + + Status = ref_object_by_handle(LinkHandle, + SYMBOLIC_LINK_QUERY, + symbol_link_type, + KernelMode, + (PVOID *)&SymlinkObject, + NULL); + if (NT_SUCCESS(Status)) { + ULONG LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR); + + if (SafeLinkTarget.MaximumLength >= LengthRequired) { + /* don't pass TargetLink to copy_unistr here because the caller + might have modified the structure which could lead to a copy into + kernel memory! */ + copy_unistr(&SafeLinkTarget, &SymlinkObject->TargetName); + SafeLinkTarget.Buffer[SafeLinkTarget.Length / sizeof(WCHAR)] = L'\0'; + /* copy back the new UNICODE_STRING structure */ + if (previous_mode == UserMode) { + if (copy_to_user(LinkTarget, &SafeLinkTarget, sizeof(SafeLinkTarget))) { + deref_object(SymlinkObject); + return STATUS_NO_MEMORY; + } + } + else + *LinkTarget = SafeLinkTarget; + } + else + Status = STATUS_BUFFER_TOO_SMALL; + + if (ResultLength) { + if (previous_mode == UserMode) { + if (copy_to_user(ResultLength, &LengthRequired, sizeof(ULONG))) { + deref_object(SymlinkObject); + return STATUS_NO_MEMORY; + } + } + else + *ResultLength = LengthRequired; + } + deref_object(SymlinkObject); + } + + return Status; +} /* end NtQuerySymbolicLinkObject */ +EXPORT_SYMBOL(NtQuerySymbolicLinkObject); +#endif diff --git a/unifiedkernel/ob/wait.c b/unifiedkernel/ob/wait.c new file mode 100644 index 0000000..91e135b --- /dev/null +++ b/unifiedkernel/ob/wait.c @@ -0,0 +1,282 @@ +/* + * objwait.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * objwait.c: + * Refered to Kernel-win32 code + */ + +#include +#include "objwait.h" +#include "thread.h" +#include "object.h" +#include "apc.h" +#include "event.h" +#include "mutex.h" +#include "semaphore.h" +#include + +#ifdef CONFIG_UNIFIED_KERNEL + +NTSTATUS SERVICECALL +NtWaitForSingleObject(IN HANDLE ObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) +{ + PVOID object; + LARGE_INTEGER _timeout; + MODE previous_mode; + NTSTATUS status; + + ktrace("NtWaitForSingleObject: ObjectHandle %p, Alertable %d\n", ObjectHandle, Alertable); + previous_mode = (unsigned long)TimeOut > TASK_SIZE ? KernelMode : UserMode; + if(TimeOut){ + if (previous_mode == UserRequest) { + if (copy_from_user(&_timeout, TimeOut, sizeof(_timeout))) + return STATUS_NO_MEMORY; + } else + _timeout = *TimeOut; + } + + status = ref_object_by_handle(ObjectHandle, + SYNCHRONIZE, + NULL, + KernelMode, + &object, + NULL); + if (!NT_SUCCESS(status)) + return status; + + if(TimeOut){ + status = wait_for_single_object(object, + UserRequest, + KernelMode, + Alertable, + &_timeout); + } else { + status = wait_for_single_object(object, + UserRequest, + KernelMode, + Alertable, + NULL); + } + + if (!NT_SUCCESS(status)) + goto out; + + if (previous_mode == UserMode) { + if (copy_to_user(TimeOut, &_timeout, sizeof(_timeout))) { + status = STATUS_NO_MEMORY; + goto out; + } + } + else + *TimeOut = _timeout; + +out: + deref_object(object); + return status; +} /* end NtWaitForSingleObject */ +EXPORT_SYMBOL(NtWaitForSingleObject); + +NTSTATUS SERVICECALL +NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, + IN HANDLE WaitableObjectHandle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) +{ + PVOID signal_obj, wait_obj; + struct dispatcher_header *signal_header; + LARGE_INTEGER _timeout; + MODE previous_mode; + NTSTATUS status; + + ktrace("NtSignalAndWaitForSingleObject: ObjectHandleToSignal %p, WaitableObjectHandle %p, Alertable %d\n", + ObjectHandleToSignal, WaitableObjectHandle, Alertable); + previous_mode = (unsigned long)TimeOut > TASK_SIZE ? KernelMode : UserMode; + if(TimeOut){ + if (previous_mode == UserMode) { + if (copy_from_user(&_timeout, TimeOut, sizeof(_timeout))) + return STATUS_NO_MEMORY; + } else + _timeout = *TimeOut; + } + + status = ref_object_by_handle(ObjectHandleToSignal, + 0, + NULL, + KernelMode, + &signal_obj, + NULL); + if (!NT_SUCCESS(status)) + return status; + + status = ref_object_by_handle(WaitableObjectHandle, + SYNCHRONIZE, + NULL, + KernelMode, + &wait_obj, + NULL); + if (!NT_SUCCESS(status)) { + deref_object(signal_obj); + return status; + } + + signal_header = (struct dispatcher_header *)signal_obj; + + switch (signal_header->type) { + case EventNotificationObject: + case EventSynchronizationObject: + set_event(signal_obj, + EVENT_INCREMENT, + TRUE); + break; + + case MutantObject: + release_mutant(signal_obj, + IO_NO_INCREMENT, + FALSE, + TRUE); + break; + + case SemaphoreObject: + release_semaphore(signal_obj, + SEMAPHORE_INCREMENT, + 1, + TRUE); + break; + + default: + deref_object(signal_obj); + deref_object(wait_obj); + return STATUS_OBJECT_TYPE_MISMATCH; + } + + + if(TimeOut){ + status = wait_for_single_object(wait_obj, + UserRequest, + KernelMode, + Alertable, + &_timeout); + } else { + status = wait_for_single_object(wait_obj, + UserRequest, + KernelMode, + Alertable, + NULL); + } + + if (!NT_SUCCESS(status)) + goto out; + + if (previous_mode == UserMode) { + if (copy_to_user(TimeOut, &_timeout, sizeof(_timeout))) { + status = STATUS_NO_MEMORY; + goto out; + } + } else + *TimeOut = _timeout; + +out: + deref_object(signal_obj); + deref_object(wait_obj); + + return status; +} /* end NtSignalAndWaitForSingleObject */ +EXPORT_SYMBOL(NtSignalAndWaitForSingleObject); + +NTSTATUS SERVICECALL +NtWaitForMultipleObjects(IN ULONG ObjectCount, + IN PHANDLE ObjectsArray, + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER TimeOut OPTIONAL) +{ + int i; + struct kwait_block *wait_block; + LARGE_INTEGER _timeout; + NTSTATUS status; + PVOID object[ObjectCount]; + HANDLE hobj[ObjectCount]; + MODE previous_mode; + + ktrace("NtWaitForMultipleObjects %d, %p\n", ObjectCount, ObjectsArray); + previous_mode = (unsigned long)ObjectsArray > TASK_SIZE ? KernelMode : UserMode; + if(TimeOut){ + if (previous_mode == UserMode) { + if (copy_from_user(&_timeout, TimeOut, sizeof(_timeout))) + return STATUS_NO_MEMORY; + } else + _timeout = *TimeOut; + } + if(previous_mode == UserMode) { + if(copy_from_user(hobj, ObjectsArray, sizeof(HANDLE)*ObjectCount)) + return STATUS_NO_MEMORY; + } else { + memcpy(ObjectsArray, hobj, sizeof(HANDLE)*ObjectCount); + } + + for (i = 0; i < ObjectCount; i++) { + status = ref_object_by_handle(hobj[i], + SYNCHRONIZE, + NULL, + KernelMode, + &object[i], + NULL); + if (!NT_SUCCESS(status)) { + ObjectCount = i; + goto out; + } + if (BODY_TO_HEADER(object[i])->Type == thread_object_type + && object[i] == get_current_ethread()) { + status = STATUS_INVALID_PARAMETER; + ObjectCount = i + 1; + goto out; + } + } + + wait_block = (struct kwait_block *)kmalloc(MAXIMUM_WAIT_OBJECTS * sizeof(struct kwait_block), GFP_KERNEL); + if (!wait_block) { + status = STATUS_NO_MEMORY; + goto out; + } + + status = wait_for_multi_objs(ObjectCount, + object, + WaitType, + UserRequest, + KernelMode, + Alertable, + TimeOut ? &_timeout : NULL, + wait_block); + + kfree(wait_block); + +out: + for (i = 0; i < ObjectCount; i++) + deref_object(object[i]); + + return status; +} /* end NtWaitForMultipleObjects */ +EXPORT_SYMBOL(NtWaitForMultipleObjects); +#endif diff --git a/unifiedkernel/ps/Makefile b/unifiedkernel/ps/Makefile new file mode 100644 index 0000000..c75f76a --- /dev/null +++ b/unifiedkernel/ps/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for process structure +# + +PS_OBJS = process.o \ + kill.o \ + token.o \ + suspend.o \ + thread.o \ + psmgr.o \ + query.o \ + cid.o \ + flush.o + +$(MODULE)-objs += $(addprefix ps/, $(PS_OBJS)) diff --git a/unifiedkernel/ps/cid.c b/unifiedkernel/ps/cid.c new file mode 100644 index 0000000..d41e189 --- /dev/null +++ b/unifiedkernel/ps/cid.c @@ -0,0 +1,202 @@ +/* + * cid.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * cid.c: + * Refered to ReactOS code + */ + +#include "win32.h" +#include "handle.h" +#include "process.h" +#include "thread.h" +#include "ke.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +struct handle_table *cid_table = NULL; +EXPORT_SYMBOL(cid_table); + +#define CID_FLAG_PROCESS 0x1 +#define CID_FLAG_THREAD 0x2 +#define CID_FLAG_MASK (CID_FLAG_PROCESS | CID_FLAG_THREAD) + +#define CID_RESERVE_OFFSET 32 + +long init_cid_table(void) +{ + return (long) (cid_table = __create_handle_table(NULL)); +} +EXPORT_SYMBOL(init_cid_table); + + +void destroy_cid_table(void) +{ + __destroy_handle_table(cid_table, NULL, NULL); +} +EXPORT_SYMBOL(destroy_cid_table); + + +HANDLE create_cid_handle(PVOID object, POBJECT_TYPE obj_type) +{ + struct handle_table_entry entry; + long exhandle; + + entry.u1.object = object; + + if (obj_type == process_object_type) + entry.u2.granted_access = CID_FLAG_PROCESS; + else if (obj_type == thread_object_type) + entry.u2.granted_access = CID_FLAG_THREAD; + else + goto error; + + exhandle = create_ex_handle(cid_table, &entry); + if (exhandle != EX_INVALID_HANDLE) + return EX_HANDLE_TO_HANDLE(exhandle + CID_RESERVE_OFFSET); + +error: + return NULL; +} +EXPORT_SYMBOL(create_cid_handle); + + +int delete_cid_handle(HANDLE cid_handle, POBJECT_TYPE obj_type) +{ + struct handle_table_entry * entry; + long ex_handle = HANDLE_TO_EX_HANDLE(cid_handle) - CID_RESERVE_OFFSET; + + enter_critical_region(); + + if (!(entry = map_handle_to_pointer(cid_table, ex_handle))) + goto invalid; + + if (((obj_type == thread_object_type) && + ((entry->u2.granted_access & CID_FLAG_MASK) == CID_FLAG_THREAD)) || + ((obj_type == process_object_type) && + ((entry->u2.granted_access & CID_FLAG_MASK) == CID_FLAG_PROCESS))) { + destroy_handle_by_entry(cid_table, entry, ex_handle); + leave_critical_region(); + return 0; + } else + unlock_handle_table_entry(cid_table, entry); + +invalid: + leave_critical_region(); + return STATUS_INVALID_PARAMETER; +} +EXPORT_SYMBOL(delete_cid_handle); + + +struct handle_table_entry* lookup_cid_handle(HANDLE cid_handle, POBJECT_TYPE obj_type, PVOID *object) +{ + struct handle_table_entry *entry; + + enter_critical_region(); + if (!(entry = map_handle_to_pointer(cid_table, + HANDLE_TO_EX_HANDLE(cid_handle) - CID_RESERVE_OFFSET))) + goto no_target; + + if (((obj_type == thread_object_type) && + ((entry->u2.granted_access & CID_FLAG_MASK) == CID_FLAG_THREAD)) || + ((obj_type == process_object_type) && + ((entry->u2.granted_access & CID_FLAG_MASK) == CID_FLAG_PROCESS))) { + *object = entry->u1.object; + leave_critical_region(); + return entry; + } else + unlock_handle_table_entry(cid_table, entry); + +no_target: + leave_critical_region(); + return NULL; +} +EXPORT_SYMBOL(lookup_cid_handle); + + +int lookup_process_by_pid(HANDLE pid, struct eprocess** process) +{ + struct handle_table_entry* entry; + struct eprocess* found_process; + + if (!process) + goto invalid_parameter; + + if ((entry = lookup_cid_handle(pid, process_object_type, (PVOID *) &found_process))) { + ref_object(found_process); + unlock_handle_table_entry(cid_table, entry); + *process = found_process; + return 0; + } + +invalid_parameter: + return STATUS_INVALID_PARAMETER; +} +EXPORT_SYMBOL(lookup_process_by_pid); + + +int lookup_thread_by_tid(HANDLE tid, struct ethread** thread) +{ + struct handle_table_entry* entry; + struct ethread* found_thread; + + if (!thread) + goto invalid_parameter; + + if ((entry = lookup_cid_handle(tid, thread_object_type, (PVOID *) &found_thread))) { + ref_object(found_thread); + unlock_handle_table_entry(cid_table, entry); + *thread = found_thread; + return 0; + } + +invalid_parameter: + return STATUS_INVALID_PARAMETER; +} +EXPORT_SYMBOL(lookup_thread_by_tid); + +NTSTATUS lookup_process_thread_by_cid(PCLIENT_ID cid, PEPROCESS *process, PETHREAD *thread) +{ + struct handle_table_entry* entry = NULL; + struct ethread* found_thread = NULL; + + if (!thread) + return STATUS_INVALID_PARAMETER; + + if ((entry = lookup_cid_handle(cid->UniqueThread, thread_object_type, (PVOID *)&found_thread))) { + if (found_thread->cid.unique_process == cid->UniqueProcess) { + ref_object(found_thread); + *thread = found_thread; + + if (process) { + *process = found_thread->threads_process; + ref_object(*process); + } + + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_CID; + +} +#endif diff --git a/unifiedkernel/ps/flush.c b/unifiedkernel/ps/flush.c new file mode 100644 index 0000000..0193fa4 --- /dev/null +++ b/unifiedkernel/ps/flush.c @@ -0,0 +1,212 @@ +/* + * flush.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Mar 2009 - Created. + */ + +/* + * flush.c: + * Refered to Wine code + */ +#include "process.h" + +#include +#include +#include +#include +#include + +#ifdef CONFIG_UNIFIED_KERNEL +extern int de_thread(struct task_struct *tsk); +extern int copy_files(unsigned long clone_flags, struct task_struct *tsk); + +#if 0 +static int unshare_fd_from_task(struct task_struct *task, unsigned long unshare_flags, struct files_struct **new_fdp) +{ + struct files_struct *fd = task->files; + int error = 0; + + if ((unshare_flags & CLONE_FILES) && + (fd && atomic_read(&fd->count) > 1)) { + *new_fdp = dup_fd(fd, &error); + if (!*new_fdp) + return error; + } + + return 0; +} +static int unshare_files_from_task(struct task_struct *task, struct files_struct **displaced) +{ + struct files_struct *copy = NULL; + int error; + + error = unshare_fd_from_task(task, CLONE_FILES, ©); + if (error || !copy) { + *displaced = NULL; + return error; + } + *displaced = task->files; + task_lock(task); + task->files = copy; + task_unlock(task); + return 0; +} +#endif + +static void __put_unused_fd(struct files_struct *files, unsigned int fd) +{ + struct fdtable *fdt = files_fdtable(files); + __FD_CLR(fd, fdt->open_fds); + if (fd < files->next_fd) + files->next_fd = fd; +} + +/* Modified from sys_close */ +static long close_fd_from_task(struct task_struct *task, unsigned int fd) +{ + struct file * filp; + struct files_struct *files = task->files; + struct fdtable *fdt; + int retval; + + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + if (fd >= fdt->max_fds) + goto out_unlock; + filp = fdt->fd[fd]; + if (!filp) + goto out_unlock; + rcu_assign_pointer(fdt->fd[fd], NULL); + FD_CLR(fd, fdt->close_on_exec); + __put_unused_fd(files, fd); + spin_unlock(&files->file_lock); + retval = filp_close(filp, files); + + /* can't restart close syscall because file table entry was cleared */ + if (unlikely(retval == -ERESTARTSYS || + retval == -ERESTARTNOINTR || + retval == -ERESTARTNOHAND || + retval == -ERESTART_RESTARTBLOCK)) + retval = -EINTR; + + return retval; + +out_unlock: + spin_unlock(&files->file_lock); + return -EBADF; +} + +static void flush_thread_from_task(struct task_struct *tsk) +{ + clear_tsk_thread_flag(tsk, TIF_DEBUG); + + tsk->thread.debugreg0 = 0; + tsk->thread.debugreg1 = 0; + tsk->thread.debugreg2 = 0; + tsk->thread.debugreg3 = 0; + tsk->thread.debugreg6 = 0; + tsk->thread.debugreg7 = 0; + memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); + /* + * Forget coprocessor state.. + */ + tsk->fpu_counter = 0; + clear_fpu(tsk); + clear_used_math(); +} + +static void flush_signal_handlers_from_task(struct task_struct *t, int force_default) +{ + int i; + struct k_sigaction *ka = &t->sighand->action[0]; + for (i = _NSIG ; i != 0 ; i--) { + if (force_default || ka->sa.sa_handler != SIG_IGN) + ka->sa.sa_handler = SIG_DFL; + ka->sa.sa_flags = 0; + sigemptyset(&ka->sa.sa_mask); + ka++; + } +} + +static void flush_old_files_from_task(struct task_struct *task) +{ + long j = -1; + struct fdtable *fdt; + struct files_struct *files = task->files; + + spin_lock(&files->file_lock); + for (;;) { + unsigned long set, i; + + j++; + i = j * __NFDBITS; + fdt = files_fdtable(files); + if (i >= fdt->max_fds) + break; + set = fdt->close_on_exec->fds_bits[j]; + if (!set) + continue; + fdt->close_on_exec->fds_bits[j] = 0; + spin_unlock(&files->file_lock); + for ( ; set ; i++,set >>= 1) { + if (set & 1) { + close_fd_from_task(task, i); + } + } + spin_lock(&files->file_lock); + } + spin_unlock(&files->file_lock); +} + +int flush_old_exec_from_task(struct task_struct *task) +{ + int retval; + + retval = de_thread(task); + if(retval) + goto out; + + ethread_notify_execve(task); + + task->sas_ss_sp = task->sas_ss_size = 0; + + if (task->cred->euid == task->cred->uid && task->cred->egid == task->cred->gid) + set_dumpable(current->mm, 1); + else + set_dumpable(current->mm, 0); + + task->flags &= ~PF_RANDOMIZE; + flush_thread_from_task(task); + + /* Set the new mm task size. We have to do that late because it may + * depend on TIF_32BIT which is only updated in flush_thread() on + * some architectures like powerpc + */ + task->mm->task_size = 0x80000000; + + task->self_exec_id++; + + flush_signal_handlers_from_task(task, 0); + flush_old_files_from_task(task); + + return 0; +out: + return retval; +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/ps/kill.c b/unifiedkernel/ps/kill.c new file mode 100644 index 0000000..77b03bf --- /dev/null +++ b/unifiedkernel/ps/kill.c @@ -0,0 +1,166 @@ +/* + * kill.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * kill.c: + * Refered to ReactOS code + */ +#include "win32_process.h" +#include +#include +#include +#include "ke.h" +#include "win32.h" +#include "thread.h" +#include "object.h" +#include "process.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "virtual.h" +#include "handle.h" +#include "event.h" +#include "w32syscall.h" +#include "attach.h" +#include "area.h" +#include "wineserver/info.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +extern VOID STDCALL +delete_handle_callback(struct handle_table *HandleTable, + PVOID Object, + ULONG GrantedAccess, + PVOID Context); + +VOID STDCALL +delete_teb(PTEB Teb) +{ + unsigned long len = PAGE_SIZE; + + ktrace("delete_teb %p\n", Teb); + NtFreeVirtualMemory((HANDLE)-1, (PVOID *)&Teb, (PULONG)&len, MEM_RELEASE); +} + +void __exit_process(struct eprocess * process) +{ + unsigned long old_state; + + /* close all handles associated with our process, this needs to be done + * when the last thread still runs */ + __destroy_handle_table(process->object_table, delete_handle_callback, process); + + /* remove all reserved area and mapped area */ + remove_all_win32_area(&process->ep_reserved_head); + remove_all_win32_area(&process->ep_mapped_head); + + /* FIXME: spin_lock_irq(&t); */ + local_irq_disable(); + + if (process->win32process) + kfree(process->win32process); + + if (process->ep_handle_info_table) { + free_handle_info_table(process->ep_handle_info_table); + kfree(process->ep_handle_info_table); + process->ep_handle_info_table = NULL; + } + + old_state = process->pcb.header.signal_state; + process->pcb.header.signal_state = true; + if ((!old_state) && !list_empty(&process->pcb.header.wait_list_head)) { + /* Satisfy waits */ + wait_test((struct dispatcher_header *)&process->pcb,IO_NO_INCREMENT); + } + + local_irq_enable(); + /* FIXME: spin_unlock_irq(&t); */ +} +EXPORT_SYMBOL(__exit_process); + + +static inline void terminate_thread_by_pointer(struct ethread *thread, NTSTATUS exit_code) +{ + thread->exit_status = exit_code; + send_sig_info(SIGKILL, SEND_SIG_FORCED, thread->et_task); +} + + +void exit_process_threads(struct eprocess *process, NTSTATUS ExitStatus) +{ + struct list_head *cur_entry; + struct ethread *thread; + + /* process is locked by caller */ + cur_entry = process->thread_list_head.next; + while (cur_entry != &process->thread_list_head) { + thread = list_entry(cur_entry, struct ethread, thread_list_entry); + cur_entry = cur_entry->next; + if (thread != get_current_ethread()) + terminate_thread_by_pointer(thread, ExitStatus); + } +} +EXPORT_SYMBOL(exit_process_threads); + + +NTSTATUS +SERVICECALL +NtTerminateThread(IN HANDLE ThreadHandle, + IN NTSTATUS ExitStatus) +{ + struct ethread * thread; + NTSTATUS status; + + ktrace("NtTerminateThread handle %p\n", ThreadHandle); + + status = ref_object_by_handle(ThreadHandle, + THREAD_TERMINATE, + thread_object_type, + get_pre_mode(), + (PVOID *)&thread, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + if (!thread->et_task){ + deref_object(thread); + return STATUS_THREAD_IS_TERMINATING; + } + + /* FIXME Make sure this is not a system thread */ + + if (thread != get_current_ethread()) { + terminate_thread_by_pointer(thread, ExitStatus); + deref_object(thread); + } else { + deref_object(thread); + thread->exit_status = ExitStatus; + do_exit((ExitStatus & 0xff) << 8); + } + + return STATUS_SUCCESS; +} +EXPORT_SYMBOL(NtTerminateThread); + +#endif + diff --git a/unifiedkernel/ps/process.c b/unifiedkernel/ps/process.c new file mode 100644 index 0000000..65597b1 --- /dev/null +++ b/unifiedkernel/ps/process.c @@ -0,0 +1,1051 @@ +/* + * process.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * process.c: + * Refered to ReactOS code + */ +#include "win32_process.h" +#include +#include +#include +#include +#include +#include +#include "ke.h" +#include "win32.h" +#include "unistr.h" +#include "thread.h" +#include "event.h" +#include "object.h" +#include "process.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "wineserver/info.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +POBJECT_TYPE process_object_type = NULL; +EXPORT_SYMBOL(process_object_type); + +extern char ntdll_name[]; + +extern long do_fork_from_task(struct task_struct *ptsk, + unsigned long process_flags, + unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size, + int __user *parent_tidptr, + int __user *child_tidptr); +extern void do_exit_task(struct task_struct *tsk, long code); +extern void do_group_exit(int exit_code); +extern NTSTATUS STDCALL map_system_dll(struct task_struct *tsk, char *name, + unsigned long *ntdll_load_addr, unsigned long *interp_load_addr); + +extern NTSTATUS STDCALL create_process_space(struct eprocess *, struct win32_section *); + +extern void *mem_alloc(size_t size); + +#ifdef SERVER_PM +/* process startup info */ +struct startup_info +{ + struct object obj; /* object header */ + obj_handle_t hstdin; /* handle for stdin */ + obj_handle_t hstdout; /* handle for stdout */ + obj_handle_t hstderr; /* handle for stderr */ + struct file *exe_file; /* file handle for main exe */ + struct process *process; /* created process */ + data_size_t data_size; /* size of startup data */ + void *data; /* data for startup info */ +}; +#endif + +/* create a new w32process struct, but no w32thread will be created in this function */ +struct w32process *create_w32process(struct eprocess *eproc) /* TBD, D.M. */ +{ + struct w32process *w32proc = NULL; + + if ( !(w32proc = kmalloc(sizeof(struct w32process), GFP_KERNEL)) ) + return NULL; + memset(w32proc, 0, sizeof(struct w32process)); + + w32proc->parent = NULL; + w32proc->debugger = NULL; + w32proc->sigkill_timeout = NULL; + w32proc->running_threads = 0; + w32proc->suspend = 0; + w32proc->is_system = 0; + w32proc->create_flags = 0; + w32proc->console = NULL; + w32proc->startup_state = STARTUP_IN_PROGRESS; + w32proc->startup_info = NULL; + w32proc->idle_event = NULL; + w32proc->queue = NULL; + w32proc->ldt_copy = NULL; + w32proc->winstation = 0; + w32proc->desktop = 0; + w32proc->trace_data = 0; + + INIT_LIST_HEAD(&w32proc->locks); + INIT_LIST_HEAD(&w32proc->classes); + INIT_LIST_HEAD(&w32proc->dlls); + w32proc->eprocess = eproc; + + w32proc->start_time = current_time; + w32proc->end_time = 0; + +#if 0 +#ifndef UNIFIED_KERNEL + if (!(process->id = process->group_id = alloc_ptid( process ))) + { + close( fd ); + goto error; + } +#else + process->id = process->group_id = 0; +#endif + if (!(process->msg_fd = create_anonymous_fd( &process_fd_ops, fd, &process->obj, 0 ))) goto error; + + /* create the handle table */ + if (!parent_thread) + { + process->handles = alloc_handle_table( process, 0 ); + process->token = token_create_admin(); + } + else + { + struct process *parent = parent_thread->process; + process->parent = (struct process *)grab_object( parent ); + process->handles = inherit_all ? copy_handle_table( process, parent ) + : alloc_handle_table( process, 0 ); + /* Note: for security reasons, starting a new process does not attempt + * to use the current impersonation token for the new process */ + process->token = token_duplicate( parent->token, TRUE, 0 ); + } + if (!process->handles || !process->token) goto error; + + /* create the main thread */ + if (pipe( request_pipe ) == -1) + { + file_set_error(); + goto error; + } + fprintf(stderr, "%s \n", __func__); + if (send_client_fd( process, request_pipe[1], 0 ) == -1) + { + close( request_pipe[0] ); + close( request_pipe[1] ); + goto error; + } + close( request_pipe[1] ); + + if (!(thread = create_thread( request_pipe[0], process ))) goto error; + + set_fd_events( process->msg_fd, POLLIN ); /* start listening to events */ + release_object( process ); +#endif + + return w32proc; +#if 0 +error: + kfree( w32proc ); + return NULL; +#endif +} + +/* + * poll the state of a process for WaitFor*() functions + * - if signalled, sets to non-signalled before returning + */ +int poll_process(struct wait_table_entry *wte) +{ + struct eprocess * process = (struct eprocess *)(wte->wte_obj); + + return (process->pcb.state == PROCESS_STATE_ACTIVE) ? POLL_NOTSIG : POLL_SIG; +} /* end poll_process() */ + +VOID delete_process(PVOID Object) +{ + struct eprocess *process = Object; + + ktrace("delete_process\n"); + + if (process->unique_processid) + delete_cid_handle(process->unique_processid, process_object_type); + + if (process->ep_nls) + unload_nls(process->ep_nls); +} + +/* initialize kprocess */ +void kprocess_init(struct kprocess *process, char prio, + unsigned long affinity, physical_address_t dir_table_base) +{ + ktrace("kprocess_init\n"); + + INIT_DISP_HEADER(&process->header, process_object, sizeof(struct kprocess), false); + + /* Initialize Scheduler Data, Disable Alignment Faults and Set the PDE */ + process->affinity = affinity; + process->base_priority = prio; + process->quantum_reset = 6; + process->directory_table_base = dir_table_base; + process->auto_alignment = true; + process->state = PROCESS_STATE_ACTIVE; + + /* Initialize the Thread List */ + INIT_LIST_HEAD(&process->thread_list_head); +} /* end kprocess_init */ + +/* initialize eprocess */ +void eprocess_init(struct eprocess *process) +{ + physical_address_t dir_table_base = { .quad = 0LL }; + + ktrace("eprocess_init\n"); + + process->ep_nls = load_nls("cp936"); + + INIT_LIST_HEAD(&process->thread_list_head); + rwlock_init(&process->ep_lock); + + process->debug_port = NULL; /* FIXME */ + process->exception_port = NULL; /* FIXME */ + process->section_base_address = 0; /* FIXME */ + /* FIXME: event_init(&Process->LockEvent, SynchronizationEvent, FALSE); */ + /* FIXME: process->object_table = process->default_object_table; */ + /* FIXME: Status = PspInitializeProcessSecurity(Process, pParentProcess); */ + + /* init handle table */ + create_handle_table(NULL, FALSE, process); + + /* + * FIXME: + * affinity == active processors, used 1 here + * directory_table_base, used 0 here + */ + kprocess_init(&process->pcb, PROCESS_PRIO_NORMAL, 1, dir_table_base); + + INIT_LIST_HEAD(&process->ep_reserved_head); + INIT_LIST_HEAD(&process->ep_mapped_head); + + process->watch_fd = -1; + process->watch_thread = 0; + process->win32process = create_w32process(process); + process->ep_handle_info_table = alloc_handle_info_table(); +} + + +/* + * create_process + */ +NTSTATUS STDCALL create_process(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcessHandle OPTIONAL, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL) +{ + HANDLE hProcess = NULL; + struct eprocess *child_eprocess; + struct eprocess *parent_eprocess = NULL; + NTSTATUS Status = STATUS_SUCCESS; + char *system_dll_name = ntdll_name; + long cpid; + struct task_struct *child_task = NULL, *parent_task = NULL; + struct ethread *current_ethread = get_current_ethread(); + struct ethread *parent_ethread = NULL; + struct ethread *child_ethread = NULL; + struct ktrap_frame *trap_frame = NULL; + struct win32_section *section = NULL; + unsigned long system_dll_load_addr, interp_load_addr; + + if (!ProcessHandle) + return STATUS_INVALID_PARAMETER; + + if (!current_ethread) + return STATUS_INVALID_PARAMETER; + + /* Reference the Parent if there is one */ + if (ParentProcessHandle == NtCurrentProcess()) { + parent_eprocess = current_ethread->threads_process; + parent_ethread = current_ethread; + ref_object((PVOID)parent_eprocess); + } + else { + Status = ref_object_by_handle(ParentProcessHandle, + PROCESS_ALL_ACCESS, + process_object_type, + KernelMode, + (PVOID *)&parent_eprocess, + NULL); + if (!NT_SUCCESS(Status)) { + return Status; + } + parent_ethread = get_first_thread(parent_eprocess); + } + + trap_frame = parent_ethread->tcb.trap_frame; + parent_task = parent_ethread->et_task; + + cpid = do_fork_from_task(parent_task, CREATE_PROCESS, + SIGCHLD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, /* SIGCHLD ????? */ + trap_frame->esp, (struct pt_regs *)trap_frame, 0, NULL, NULL); + + if (parent_eprocess) + deref_object((PVOID)parent_eprocess); + + if (cpid < 0) { + Status = STATUS_INVALID_PARAMETER; + goto out; + } + + child_task = find_task_by_vpid(cpid); + + /* Create EPROCESS */ + Status = create_object(KernelMode, + process_object_type, + ObjectAttributes, + KernelMode, + NULL, + sizeof(struct eprocess), + 0, + 0, + (PVOID *)&child_eprocess); + if (!NT_SUCCESS(Status)) + goto cleanup_child_task; + + eprocess_init(child_eprocess); + + /* Insert Process into Handle Table */ + Status = insert_object(child_eprocess, + NULL, + DesiredAccess, + 0, + NULL, + &hProcess); + if (!NT_SUCCESS(Status)) + goto cleanup_child_eprocess; + + /* allocate a Win32 thread object */ + Status = create_object(KernelMode, + thread_object_type, + ObjectAttributes, + KernelMode, + NULL, + sizeof(struct ethread), + 0, + 0, + (PVOID *)&child_ethread); + if (!NT_SUCCESS(Status)) + goto cleanup_proc_handle; + + ethread_init(child_ethread, child_eprocess, child_task); + + child_eprocess->fork_in_progress = child_ethread; + + /* Inherit stuff from the Parent since we now have the object created */ + if (parent_eprocess) { + child_eprocess->inherited_from_unique_pid = parent_eprocess->unique_processid; + child_eprocess->session = parent_eprocess->session; + } + + /* FIXME: Set up the Quota Block from the Parent + * PspInheritQuota(Parent, child_eprocess); + */ + + /* FIXME: Set up Dos Device Map from the Parent + * ObInheritDeviceMap(Parent, child_eprocess) + */ + + /* Set the Process' LPC Ports */ + + /* Setup the Lock Event */ + event_init(&child_eprocess->lock_event, synchronization_event, FALSE); + + /* Add the Section */ + if (SectionHandle) { + Status = ref_object_by_handle(SectionHandle, + 0, + section_object_type, + KernelMode, + (PVOID *)§ion, + NULL); + if (!NT_SUCCESS(Status)) + goto cleanup_child_ethread; + } + + /* Create the Process' Address Space */ + Status = create_process_space(child_eprocess, section); + if (!NT_SUCCESS(Status)) + goto cleanup_section; + + /* Do what exec should do */ + flush_old_exec_from_task(child_task); + + if (section) { + /* Map the System Dll */ + map_system_dll(child_task, system_dll_name, + &system_dll_load_addr, &interp_load_addr); + } + + child_eprocess->unique_processid = create_cid_handle(child_eprocess, process_object_type); + if (!(child_eprocess->unique_processid)) + goto cleanup_section; + + /* Create PEB only for User-Mode Processes */ + if (parent_eprocess) { + Status = create_peb(child_eprocess); + if (!NT_SUCCESS(Status)) + goto cleanup_section; + } + + /* Let's take advantage of this time to kill the reference too */ + parent_eprocess = NULL; + + /* Set the Creation Time */ + if (copy_to_user(ProcessHandle, &hProcess, sizeof(hProcess))) { + Status = STATUS_UNSUCCESSFUL; + goto cleanup_section; + } + + deref_object(child_eprocess); + deref_object(child_ethread); + + return STATUS_SUCCESS; + +cleanup_section: + deref_object((PVOID)section); + +cleanup_child_ethread: + deref_object((PVOID)child_ethread); + +cleanup_proc_handle: + if (hProcess) + NtClose(hProcess); + +cleanup_child_eprocess: + deref_object(child_eprocess); + +cleanup_child_task: + do_exit_task(child_task, 0); + +out: + return Status; +} /* end create_process */ + +NTSTATUS SERVICECALL +NtCreateProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcessHandle, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL) +{ + return ParentProcessHandle + ? create_process(ProcessHandle, + DesiredAccess, + ObjectAttributes, + ParentProcessHandle, + InheritObjectTable, + SectionHandle, + DebugPort, + ExceptionPort) + : STATUS_INVALID_PARAMETER; +} /* end NtCreateProcess */ +EXPORT_SYMBOL(NtCreateProcess); + +NTSTATUS SERVICECALL +NtOpenProcess(OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId) +{ + /* FIXME: combine Ke and Ex into the one */ + KPROCESSOR_MODE pre_mode = (KPROCESSOR_MODE)get_pre_mode(); + struct eprocess *process = NULL; + struct ethread *thread = NULL; + NTSTATUS status = STATUS_INVALID_PARAMETER; + CLIENT_ID cid; + + ktrace("NtOpenProcess\n"); + + if (ObjectAttributes->ObjectName) { + return open_object_by_name(ObjectAttributes, + process_object_type, + NULL, + pre_mode, + DesiredAccess, + NULL, + ProcessHandle); + } else if (ClientId) { + if (copy_from_user(&cid, ClientId, sizeof(cid))) + return STATUS_INVALID_ADDRESS; + if (cid.UniqueProcess) { + if (lookup_process_by_pid(cid.UniqueProcess, &process)) + return status; + } else if (cid.UniqueThread) { + if (lookup_process_thread_by_cid(&cid, &process, &thread)) + return status; + } else + return status; + + status = open_object_by_pointer(process, + ObjectAttributes->Attributes, + NULL, + DesiredAccess, + process_object_type, + pre_mode, + ProcessHandle); + + if (thread) + deref_object(thread); + + deref_object(process); + } + return status; +} +EXPORT_SYMBOL(NtOpenProcess); + +NTSTATUS SERVICECALL +NtTerminateProcess(IN HANDLE ProcessHandle, + IN NTSTATUS ExitStatus) +{ + struct eprocess *process; + struct ethread *cur_thread; + NTSTATUS status; + + ktrace("NtTerminateProcess\n"); + + if ((status = ref_object_by_handle(ProcessHandle ? ProcessHandle : NtCurrentProcess(), + PROCESS_TERMINATE, + process_object_type, + get_pre_mode(), + (PVOID *) &process, + NULL))) + return status; + + cur_thread = (struct ethread *) get_current_ethread(); + + lock_process(process); + + if (process->exit_time.quad) { + unlock_process(process); + deref_object(process); + return STATUS_PROCESS_IS_TERMINATING; + } + + query_sys_time(&process->exit_time); + process->exit_status = (unsigned long)ExitStatus; + + unlock_process(process); + deref_object(process); + + if (process == get_current_eprocess()) { + cur_thread->exit_status = ExitStatus; + do_group_exit((ExitStatus & 0xff) << 8); + } else { + struct ethread *first_thread = get_first_thread(process); + + first_thread->exit_status = ExitStatus; + send_sig_info(SIGKILL, SEND_SIG_FORCED, first_thread->et_task->group_leader); + } + + return STATUS_SUCCESS; +} +EXPORT_SYMBOL(NtTerminateProcess); + +/* copy unicode string to PPB */ +static inline int +copy_param_str(void *ptr, PUNICODE_STRING dst, PUNICODE_STRING src) +{ + int ret = 0; + + dst->Length = src->Length; + dst->MaximumLength = src->MaximumLength; + dst->Buffer = (PWSTR)ptr; + if (src->Length) + ret = copy_to_user(dst->Buffer, src->Buffer, src->Length + sizeof(wchar_t)); + + return ret ? -EFAULT : ALIGN_TO_LONG(dst->MaximumLength); +} + +static int copy_env(struct nls_table *nls, PWSTR *pwcs, char *src, int len) +{ + char *ksrc, *p; + PWSTR wcs = *pwcs; + wchar_t *wc; + int ret = -ENOMEM; + int i = 0; + + if (wcs) + return -EINVAL; + + ksrc = kmalloc(len + 1, GFP_KERNEL); + if (!ksrc) + return ret; + + ret = -EFAULT; + if (copy_from_user(ksrc, src, len)) + goto out_free_src; + ksrc[len++] = 0; + + wcs = kmalloc(len * sizeof(wchar_t), GFP_KERNEL); + ret = -ENOMEM; + if (!wcs) + goto out_free_src; + + ret = -EINVAL; + p = ksrc; + wc = wcs; + while (p < ksrc + len) { + i = nls->char2uni(p, sizeof(wchar_t), wc++); + if (i < 0) + goto out_free_wcs; + p += i; + } + + ret = (char *)wc - (char *)wcs; + *pwcs = wcs; + goto out_free_src; + +out_free_wcs: + kfree(wcs); +out_free_src: + kfree(ksrc); + + return ret; +} + +long wcslen_user(const wchar_t *s) +{ + long res = 0; + wchar_t c = 0; + + for (;;) { + if (get_user(c, s)) + return 0; + if (!c) + return res + sizeof(wchar_t); + + res += sizeof(wchar_t); + s++; + } +} +EXPORT_SYMBOL(wcslen_user); + +static int copy_cmdline(struct nls_table *nls, PUNICODE_STRING dst, int argc, char **argv, int total_len) +{ + int i, n, len; + char *p, *kargv; + int ret = -ENOMEM; + wchar_t *wc; + + if (!(kargv = kmalloc(total_len, GFP_KERNEL))) + return ret; + + dst->Length = 0; + dst->MaximumLength = total_len * sizeof(wchar_t) + argc * 2 * sizeof(wchar_t); + dst->Buffer = kmalloc(dst->MaximumLength, GFP_KERNEL); + if (!dst->Buffer) + goto out_free_src; + + wc = dst->Buffer; + + for (i = 0; i < argc; i++) { + len = (i == argc - 1) ? strlen_user(argv[i]) : argv[i + 1] - argv[i]; + ret = -EFAULT; + if (copy_from_user(kargv, argv[i], len)) + goto out_free_src; + p = kargv; + + if (*p != '"') { + dst->Length += sizeof(wchar_t); + *wc++ = L'"'; + } + while (p < kargv + len - 1) { + n = nls->char2uni(p, sizeof(wchar_t), wc++); + if (n < 0) { + ret = -EINVAL; + goto out_free_dst; + } + p += n; + dst->Length += sizeof(wchar_t); + } + + if (*kargv != '"') { + dst->Length += sizeof(wchar_t); + *wc++ = L'"'; + } + if (i == argc - 1) { + *wc++ = L'\0'; + dst->Length += sizeof(wchar_t); + } else { + *wc++ = L' '; + dst->Length += sizeof(wchar_t); + } + } + + ret = 0; + goto out_free_src; + +out_free_dst: + kfree(dst->Buffer); + memset(dst, 0, sizeof(UNICODE_STRING)); +out_free_src: + kfree(kargv); + return ret; +} + +/* create ppb */ +NTSTATUS +create_ppb(PRTL_USER_PROCESS_PARAMETERS *ppb_res, + struct eprocess *process, + struct linux_binprm *bprm, + char *image_name, + char *dll_path, + char *current_dir, + PWSTR environ, + char *window_title, + char *desktop_info, + char *shell_info, + char *rt_info) +{ + PRTL_USER_PROCESS_PARAMETERS ppb = NULL; + HANDLE current_dir_handle; + HANDLE console_handle; + int i, env_size, len, brk_size; + int ret = -EINVAL; + unsigned long console_flags; + unsigned long addr; +#ifndef EXE_SO + unsigned long pos = bprm->p; +#else + unsigned long pos = current->mm->arg_start; +#endif + unsigned long argv_start, envp_start; + unsigned long brk_res; + char **argv, **envp; + char *p, *cdir; + char *native_app = NULL, *native_cmdline = NULL; + char *desktop = NULL; + int cdir_len; + void *ptr; + UNICODE_STRING dll_path_uni = {0, 2, NULL}; + UNICODE_STRING current_dir_uni; + UNICODE_STRING window_title_uni = {0, 2, NULL}; + UNICODE_STRING desktop_info_uni = {0, 2, NULL}; + UNICODE_STRING shell_info_uni = {0, 2, NULL}; + UNICODE_STRING rt_info_uni = {0, 2, NULL}; + UNICODE_STRING image_name_uni; + UNICODE_STRING cmd_line_uni; + PWSTR kenv = NULL; + struct nls_table *nls = process->ep_nls; + + cdir = (char *)kmalloc(0x400, GFP_KERNEL); + argv = (char **)kmalloc(bprm->argc * sizeof(char *), GFP_KERNEL); + envp = (char **)kmalloc(bprm->envc * sizeof(char *), GFP_KERNEL); + + argv_start = pos; + for (i = 0; i < bprm->argc; i++) { + argv[i] = (char *)pos; + pos += strlen_user(argv[i]); + } + + envp_start = pos; + for (i = 0; i < bprm->envc; i++) { + envp[i] = (char *)pos; + pos += strlen_user(envp[i]); + } + + for (i = 0; i < bprm->envc; i++) { + if (!native_app && !strncmp(envp[i], "NATIVEAPP=", strlen("NATIVEAPP="))) { + len = strlen_user(envp[i]); + native_app = (char *)kmalloc(len, GFP_KERNEL); + if (!native_app) { + ret = -ENOMEM; + if (native_cmdline) + kfree(native_cmdline); + goto out_free_envp; + } + if (copy_from_user(native_app, envp[i] + strlen("NATIVEAPP="), + len - strlen("NATIVEAPP="))) { + ret = -EFAULT; + kfree(native_app); + if (native_cmdline) + kfree(native_cmdline); + goto out_free_envp; + } + continue; + } + + if (!native_cmdline && !strncmp(envp[i], "NATIVECMDLINE=", + strlen("NATIVECMDLINE="))) { + len = strlen_user(envp[i]); + native_cmdline = (char *)kmalloc(len, GFP_KERNEL); + if (!native_cmdline) { + ret = -ENOMEM; + if (native_app) + kfree(native_app); + goto out_free_envp; + } + if (copy_from_user(native_cmdline, envp[i] + strlen("NATIVECMDLINE="), + len - strlen("NATIVECMDLINE="))) { + ret = -EFAULT; + kfree(native_cmdline); + if (native_app) + kfree(native_app); + goto out_free_envp; + } + continue; + } + + if (!desktop && !strncmp(envp[i], "DESKTOP=", strlen("DESKTOP="))) { + len = strlen_user(envp[i]); + desktop = (char *)kmalloc(len, GFP_KERNEL); + if (!desktop) { + ret = -ENOMEM; + goto out_free_envp; + } + if (copy_from_user(desktop, envp[i] + strlen("DESKTOP="), + len - strlen("DESKTOP="))) { + ret = -EFAULT; + kfree(desktop); + goto out_free_envp; + } + continue; + } + } + + if ((ret = copy_cmdline(nls, &cmd_line_uni, bprm->argc, argv, pos - argv_start))) + goto out_free_envp; + + if (native_cmdline) { + str2unistr(nls, &cmd_line_uni, native_cmdline); + kfree(native_cmdline); + } + + /* copy environment from user to kernel */ + env_size = copy_env(nls, &kenv, (char *)envp_start, pos - envp_start); + if ((ret = env_size) < 0) + goto out_free_cmd; + + if (*image_name == '/') + strcpy(cdir, image_name); + else { + for (i = 0; i < bprm->envc; i++) { + if (strncmp(envp[i], "PWD", strlen("PWD"))) + continue; + + p = envp[i] + strlen("PWD"); + while (*p && *p != '=') + p++; + + if (*p) + current_dir = p + 1; + + cdir_len = strlen_user(current_dir) - 1; + ret = -EFAULT; + if (copy_from_user(cdir, current_dir, cdir_len)) + goto out_free_kenv; + if (cdir[cdir_len - 1] != '/') + cdir[cdir_len++] = '/'; + + if (*image_name == '.' && image_name[1] == '/') + strcpy(cdir + cdir_len, image_name + 2); + else + strcpy(cdir + cdir_len, image_name); + strcpy(image_name, cdir); + } + } + + p = strrchr(cdir, '/'); + if (!p) + goto out_free_kenv; + *++p = '\0'; + + len = p - cdir; + current_dir = (char *)((bprm->p - len - 1) & ~3); + ret = -EFAULT; + if (copy_to_user(current_dir, cdir, len)) + goto out_free_kenv; + + if ((ret = sys_chdir(current_dir))) { + goto out_free_kenv; + } + + ret = -EINVAL; + if (str2unistr(nls, ¤t_dir_uni, current_dir)) + goto out_free_kenv; + + if (str2unistr(nls, &image_name_uni, image_name)) + goto out_free_cwd; + + if (native_app) { + str2unistr(nls, &image_name_uni, native_app); + kfree(native_app); + } + + if (desktop && !desktop_info) { + str2unistr(nls, &desktop_info_uni, desktop); + kfree(desktop); + } + + current_dir_handle = NULL; + console_handle = NULL; + console_flags = 0; + + len = sizeof(RTL_USER_PROCESS_PARAMETERS) /* size of process parameter block */ + + MAX_PATH * sizeof(wchar_t) /* size of current directory buffer */ + + ALIGN_TO_LONG(dll_path_uni.MaximumLength) + + ALIGN_TO_LONG(image_name_uni.MaximumLength) + + ALIGN_TO_LONG(cmd_line_uni.MaximumLength) + + ALIGN_TO_LONG(window_title_uni.MaximumLength) + + ALIGN_TO_LONG(desktop_info_uni.MaximumLength) + + ALIGN_TO_LONG(shell_info_uni.MaximumLength) + + ALIGN_TO_LONG(rt_info_uni.MaximumLength) + + ALIGN_TO_LONG(env_size); + /* FIXME: just for pass the socket fd, may be unused in the future */ + len += sizeof(int); + + /* Calculate the required block size */ + brk_size = ALIGN(len, PAGE_SIZE); + + addr = 0x20000000UL - brk_size; + down_write(¤t->mm->mmap_sem); + brk_res = do_brk(addr, brk_size); + up_write(¤t->mm->mmap_sem); + if (brk_res != addr) + goto out_free_image; + + ppb = (PRTL_USER_PROCESS_PARAMETERS)addr; + memset(ppb, 0, sizeof(*ppb)); + ppb->AllocationSize = brk_size; + ppb->Size = len; + ppb->Flags = PPF_NORMALIZED; + ppb->CurrentDirectoryHandle = current_dir_handle; + ppb->hConsole = console_handle; + ppb->ProcessGroup = console_flags; + + ptr = (void *)(ppb + 1); + + /* FIXME: just for pass the socket fd, may be unused in the future */ + memset(ppb + 1, 0, sizeof(int)); + ptr += 4; + + /* copy current directory */ + ret = copy_param_str(ptr, &ppb->CurrentDirectoryName, ¤t_dir_uni); + if (ret < 0) + goto out_free_image; + + /* copy dll path */ + ptr += ret; + ret = copy_param_str(ptr, &ppb->DllPath, &dll_path_uni); + if (ret < 0) + goto out_free_image; + + /* copy image path name */ + ptr += ret; + ret = copy_param_str(ptr, &ppb->ImagePathName, &image_name_uni); + if (ret < 0) + goto out_free_image; + + /* copy command line */ + ptr += ret; + ret = copy_param_str(ptr, &ppb->CommandLine, &cmd_line_uni); + if (ret < 0) + goto out_free_image; + + /* copy title */ + ptr += ret; + ret = copy_param_str(ptr, &ppb->WindowTitle, &window_title_uni); + if (ret < 0) + goto out_free_image; + + /* copy desktop */ + ptr += ret; + ret = copy_param_str(ptr, &ppb->DesktopInfo, &desktop_info_uni); + if (ret < 0) + goto out_free_image; + + /* copy shell info */ + ptr += ret; + ret = copy_param_str(ptr, &ppb->ShellInfo, &shell_info_uni); + if (ret < 0) + goto out_free_image; + + /* copy runtime info */ + ptr += ret; + ret = copy_param_str(ptr, &ppb->RuntimeInfo, &rt_info_uni); + if (ret < 0) + goto out_free_image; + + /* copy Environment */ + ptr += ret; + ret = copy_to_user(ppb->Environment = ptr, kenv, env_size); + if (ret) + goto out_free_image; + + *ppb_res = ppb; + ret = STATUS_SUCCESS; + +out_free_image: + FREE_UNI(image_name_uni); +out_free_cwd: + FREE_UNI(current_dir_uni); +out_free_kenv: + kfree(kenv); +out_free_cmd: + FREE_UNI(cmd_line_uni); +out_free_envp: + kfree(envp); + kfree(argv); + kfree(cdir); + + return ret; +} + +#ifdef SERVER_PM +void server_get_new_process_info(void) +{ + /* in dlls/kernel32/process.c + * RunBuiltinApp() + * and this request will be not used */ +} + +struct startup_info *server_get_startup_info(void) +{ + struct w32process *process = get_current_eprocess()->win32process; + struct startup_info *info = process->startup_info; + return info; +} +#endif + +#endif + diff --git a/unifiedkernel/ps/psmgr.c b/unifiedkernel/ps/psmgr.c new file mode 100644 index 0000000..af179e9 --- /dev/null +++ b/unifiedkernel/ps/psmgr.c @@ -0,0 +1,105 @@ +/* + * psmgr.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * psmgr.c: + * Refered to ReactOS code + */ +#include "object.h" +#include "handle.h" +#include "process.h" +#include "thread.h" +#include "unistr.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +static WCHAR ProcessTypeName[] = {'P', 'r', 'o', 'c', 'e', 's', 's', 0}; +static WCHAR ThreadTypeName[] = {'T', 'h', 'r', 'e', 'a', 'd', 0}; + +static GENERIC_MAPPING PiProcessMapping = { + STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + STANDARD_RIGHTS_WRITE | PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD | + PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE | + PROCESS_TERMINATE | PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION | + PROCESS_SUSPEND_RESUME, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, + PROCESS_ALL_ACCESS}; + +static GENERIC_MAPPING PiThreadMapping = { + STANDARD_RIGHTS_READ | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, + STANDARD_RIGHTS_WRITE | THREAD_TERMINATE | THREAD_SUSPEND_RESUME | + THREAD_ALERT | THREAD_SET_INFORMATION | THREAD_SET_CONTEXT, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, + THREAD_ALL_ACCESS}; + +VOID +init_process_mgmt(VOID) +{ + UNICODE_STRING Name; + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + + ktrace("Creating Process Object Type\n"); + + /* Initialize the Thread type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)ProcessTypeName); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(struct eprocess); + ObjectTypeInitializer.GenericMapping = PiProcessMapping; + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = TRUE; + ObjectTypeInitializer.DeleteProcedure = delete_process; + ObjectTypeInitializer.PollProcedure = poll_process; + create_type_object(&ObjectTypeInitializer, &Name, &process_object_type); +} + +VOID +init_thread_mgmt(VOID) +{ + UNICODE_STRING Name; + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + + ktrace("Creating Thread Object Type\n"); + + /* Initialize the Thread type */ + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)ThreadTypeName); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(struct ethread); + ObjectTypeInitializer.GenericMapping = PiThreadMapping; + ObjectTypeInitializer.PoolType = NonPagedPool; + ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS; + ObjectTypeInitializer.UseDefaultObject = TRUE; + ObjectTypeInitializer.DeleteProcedure = delete_thread; + ObjectTypeInitializer.PollProcedure = poll_thread; + create_type_object(&ObjectTypeInitializer, &Name, &thread_object_type); +} + +VOID +init_process_manager(VOID) +{ + init_process_mgmt(); + init_thread_mgmt(); +} + +#endif diff --git a/unifiedkernel/ps/query.c b/unifiedkernel/ps/query.c new file mode 100644 index 0000000..fb7e6df --- /dev/null +++ b/unifiedkernel/ps/query.c @@ -0,0 +1,640 @@ +/* + * query.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * queue.c: + * Refered to ReactOS code + */ +#include "win32_process.h" +#include +#include +#include "win32.h" +#include "ke.h" +#include "object.h" +#include "process.h" +#include "thread.h" + +#ifdef CONFIG_UNIFIED_KERNEL +extern void security_set_thread_token(struct w32thread *thread, HANDLE handle); +/* + * FIXME: + * Remove the Implemented value if all functions are implemented. + */ +typedef struct _THREAD_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PVOID TebBaseAddress; + CLIENT_ID ClientId; + KAFFINITY AffinityMask; + KPRIORITY Priority; + KPRIORITY BasePriority; +} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; + +static const struct +{ + BOOLEAN Implemented; + ULONG Size; +} QueryInformationData[MaxThreadInfoClass + 1] = { + {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, /* ThreadBasicInformation */ + {TRUE, sizeof(KERNEL_USER_TIMES)}, /* ThreadTimes */ + {TRUE, sizeof(CHAR)}, /* ThreadPriority */ + {TRUE, sizeof(CHAR)}, /* ThreadBasePriority */ + {TRUE, sizeof(KAFFINITY)}, /* ThreadAffinityMask */ + {TRUE, sizeof(PACCESS_TOKEN)}, /* ThreadImpersonationToken */ + {FALSE, 0}, /* ThreadDescriptorTableEntry */ + {TRUE, 0}, /* ThreadEnableAlignmentFaultFixup */ + {TRUE, 0}, /* ThreadEventPair */ + {TRUE, sizeof(PVOID)}, /* ThreadQuerySetWin32StartAddress */ + {TRUE, 0}, /* ThreadZeroTlsCell */ + {TRUE, sizeof(LARGE_INTEGER)}, /* ThreadPerformanceCount */ + {TRUE, sizeof(BOOLEAN)}, /* ThreadAmILastThread */ + {TRUE, sizeof(UCHAR)}, /* ThreadIdealProcessor */ + {FALSE, 0}, /* ThreadPriorityBoost */ + {TRUE, 0}, /* ThreadSetTlsArrayAddress */ + {FALSE, 0}, /* ThreadIsIoPending */ + {TRUE, 0} /* ThreadHideFromDebugger */ +}; + +static const struct +{ + BOOLEAN Implemented; + ULONG Size; +} SetInformationData[MaxThreadInfoClass + 1] = { + {TRUE, 0}, /* ThreadBasicInformation */ + {TRUE, 0}, /* ThreadTimes */ + {TRUE, sizeof(KPRIORITY)}, /* ThreadPriority */ + {TRUE, sizeof(LONG)}, /* ThreadBasePriority */ + {TRUE, sizeof(KAFFINITY)}, /* ThreadAffinityMask */ + {TRUE, sizeof(HANDLE)}, /* ThreadImpersonationToken */ + {TRUE, 0}, /* ThreadDescriptorTableEntry */ + {FALSE, 0}, /* ThreadEnableAlignmentFaultFixup */ + {FALSE, 0}, /* ThreadEventPair */ + {TRUE, sizeof(PVOID)}, /* ThreadQuerySetWin32StartAddress */ + {FALSE, 0}, /* ThreadZeroTlsCell */ + {TRUE, 0}, /* ThreadPerformanceCount */ + {TRUE, 0}, /* ThreadAmILastThread */ + {FALSE, 0}, /* ThreadIdealProcessor */ + {FALSE, 0}, /* ThreadPriorityBoost */ + {FALSE, 0}, /* ThreadSetTlsArrayAddress */ + {TRUE, 0}, /* ThreadIsIoPending */ + {FALSE, 0} /* ThreadHideFromDebugger */ +}; + +NTSTATUS SERVICECALL +NtQueryInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + PEPROCESS Process; + KPROCESSOR_MODE PreviousMode = + (ULONG)ProcessInformation < TASK_SIZE ? UserMode : KernelMode; /* TODO ... */ + union + { + PROCESS_BASIC_INFORMATION BasicInformation; + KERNEL_USER_TIMES Time; + ULONG HandleCount; + PROCESS_SESSION_INFORMATION SessionInfo; + VM_COUNTERS VMCounters; + ULONG HardErrMode; + ULONG BoostEnabled; + USHORT Priority; + }u; + ULONG Length = 0; + NTSTATUS Status = STATUS_SUCCESS; + + if (ProcessInformationClass != ProcessCookie) { + Status = ref_object_by_handle(ProcessHandle, + PROCESS_QUERY_INFORMATION, + process_object_type, + PreviousMode, + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + } + else if (ProcessHandle != NtCurrentProcess()) { + /* retreiving the process cookie is only allowed for the calling process + itself! XP only allowes NtCurrentProcess() as process handles even if a + real handle actually represents the current process. */ + return STATUS_INVALID_PARAMETER; + } + + switch (ProcessInformationClass) { + case ProcessBasicInformation: + if (ProcessInformationLength < sizeof(PROCESS_BASIC_INFORMATION)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.BasicInformation.ExitStatus = Process->exit_status; + u.BasicInformation.PebBaseAddress = (DWORD)Process->peb; + u.BasicInformation.AffinityMask = Process->pcb.affinity; + u.BasicInformation.UniqueProcessId = + (ULONG)Process->unique_processid; + u.BasicInformation.InheritedFromUniqueProcessId = + (ULONG)Process->inherited_from_unique_pid; + u.BasicInformation.BasePriority = + Process->pcb.base_priority; + if (ReturnLength) + Length = sizeof(PROCESS_BASIC_INFORMATION); + } + break; + case ProcessQuotaLimits: + case ProcessIoCounters: + /* TODO : take time from linux task_struct ? */ + Status = STATUS_NOT_IMPLEMENTED; + break; + case ProcessTimes: + if (ProcessInformationLength < sizeof(KERNEL_USER_TIMES)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.Time.CreateTime = Process->create_time; + u.Time.UserTime.quad = Process->pcb.user_time * 100000LL; + u.Time.KernelTime.quad = Process->pcb.kernel_time * 100000LL; + u.Time.ExitTime = Process->exit_time; + if (ReturnLength) + Length = sizeof(KERNEL_USER_TIMES); + } + break; + case ProcessDebugPort: + if (ProcessInformationLength == 4) { + memset(ProcessInformation, 0, ProcessInformationLength); + Length = 4; + } else + Status = STATUS_INFO_LENGTH_MISMATCH; + break; + case ProcessLdtInformation: + case ProcessWorkingSetWatch: + case ProcessWx86Information: + Status = STATUS_NOT_IMPLEMENTED; + break; + case ProcessHandleCount: + if (ProcessInformationLength < sizeof(ULONG)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.HandleCount = Process->object_table->handle_count; + if (ReturnLength) + Length = sizeof(ULONG); + } + break; + case ProcessSessionInformation: + if (ProcessInformationLength < sizeof(PROCESS_SESSION_INFORMATION)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.SessionInfo.SessionId = Process->session; + if (ReturnLength) + Length = sizeof(PROCESS_SESSION_INFORMATION); + } + break; + case ProcessWow64Information: + Status = STATUS_NOT_IMPLEMENTED; + break; + case ProcessVmCounters: + if (ProcessInformationLength < sizeof(VM_COUNTERS)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.VMCounters.PeakVirtualSize = Process->peak_virtual_size; + u.VMCounters.VirtualSize = (ULONG)Process->virtual_size; + u.VMCounters.PageFaultCount = Process->vm.page_fault_count; + u.VMCounters.PeakWorkingSetSize = Process->vm.peak_working_set_size; + u.VMCounters.WorkingSetSize = Process->vm.working_set_size; + u.VMCounters.QuotaPeakPagedPoolUsage = Process->quota_peak[0]; /* TODO: Verify! */ + u.VMCounters.QuotaPagedPoolUsage = Process->quota_usage[0]; /* TODO: Verify! */ + u.VMCounters.QuotaPeakNonPagedPoolUsage = Process->quota_peak[1]; /* TODO: Verify! */ + u.VMCounters.QuotaNonPagedPoolUsage = Process->quota_usage[1]; /* TODO: Verify! */ + u.VMCounters.PagefileUsage = Process->quota_usage[2]; + u.VMCounters.PeakPagefileUsage = Process->quota_peak[2]; + if (ReturnLength) + Length = sizeof(VM_COUNTERS); + } + break; + case ProcessDefaultHardErrorMode: + if (ProcessInformationLength < sizeof(ULONG)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.HardErrMode = Process->def_hard_error_processing; + if (ReturnLength) + Length = sizeof(ULONG); + } + break; + case ProcessPriorityBoost: + if (ProcessInformationLength < sizeof(ULONG)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.BoostEnabled = Process->pcb.disable_boost ? FALSE : TRUE; + if (ReturnLength) + Length = sizeof(ULONG); + } + break; + case ProcessDeviceMap: + /* TODO ... */ + Status = STATUS_NOT_IMPLEMENTED; + break; + case ProcessPriorityClass: + if (ProcessInformationLength < sizeof(USHORT)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + u.Priority = Process->priority_class; + + if (ReturnLength) + Length = sizeof(USHORT); + } + break; + case ProcessImageFileName: + /* TODO ... */ + case ProcessCookie: + /* TODO ... */ + Status = STATUS_NOT_IMPLEMENTED; + break; + + /* + * Note: The following 10 information classes are verified to not be + * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS; + */ + case ProcessBasePriority: + case ProcessRaisePriority: + case ProcessExceptionPort: + case ProcessAccessToken: + case ProcessLdtSize: + case ProcessIoPortHandlers: + case ProcessUserModeIOPL: + case ProcessEnableAlignmentFaultFixup: + case ProcessAffinityMask: + case ProcessForegroundInformation: + default: + Status = STATUS_INVALID_INFO_CLASS; + break; + } + + if (ProcessInformationClass != ProcessCookie) + deref_object(Process); + + if (Status != STATUS_SUCCESS) + return Status; + + if (PreviousMode != KernelMode) { + if(copy_to_user(ProcessInformation, &u.BasicInformation, Length)) + return STATUS_UNSUCCESSFUL; + if (ReturnLength != NULL) { + if(copy_to_user(ReturnLength, &Length, sizeof(ULONG))) + return STATUS_UNSUCCESSFUL; + } + } + else { + memcpy(ProcessInformation, &u.BasicInformation, Length); + *ReturnLength = Length; + } + + return Status; +} +EXPORT_SYMBOL(NtQueryInformationProcess); + +NTSTATUS SERVICECALL +NtSetInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength) +{ + PEPROCESS Process; + KPROCESSOR_MODE PreviousMode = + (ULONG)ProcessInformation < TASK_SIZE ? UserMode : KernelMode; /* TODO ... */ + ACCESS_MASK Access; + NTSTATUS Status = STATUS_SUCCESS; + + switch (ProcessInformationClass) { + case ProcessSessionInformation: + Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID; + break; + case ProcessExceptionPort: + Access = PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME; + break; + default: + Access = PROCESS_SET_INFORMATION; + break; + } + + Status = ref_object_by_handle(ProcessHandle, + Access, + process_object_type, + PreviousMode, + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + switch (ProcessInformationClass) { + case ProcessPriorityClass: + if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + PROCESS_PRIORITY_CLASS ppc; + + if (PreviousMode != KernelMode) { + if (copy_from_user(&ppc, ProcessInformation, sizeof(PROCESS_PRIORITY_CLASS))) + Status = STATUS_UNSUCCESSFUL; + } + else + ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation; + + Process->priority_class = ppc.PriorityClass; + } + break; + case ProcessAffinityMask: + if (ProcessInformationLength != sizeof(DWORD_PTR)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + DWORD_PTR affinity; + + if (PreviousMode != KernelMode) { + if (copy_from_user(&affinity, ProcessInformation, sizeof(DWORD_PTR))) + Status = STATUS_UNSUCCESSFUL; + } + else + affinity = *(PDWORD_PTR)ProcessInformation; + + if (affinity != 1) + Status = STATUS_UNSUCCESSFUL; + else + Process->pcb.affinity = affinity; + } + break; + case ProcessDefaultHardErrorMode: + if (ProcessInformationLength != sizeof(LONG)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + LONG error; + + if (PreviousMode != KernelMode) { + if (copy_from_user(&error, ProcessInformation, sizeof(LONG))) + Status = STATUS_UNSUCCESSFUL; + } + else + error = *(PLONG)ProcessInformation; + + (void)xchg(&Process->def_hard_error_processing, error); + } + break; + case ProcessSessionInformation: + if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION)) + Status = STATUS_INFO_LENGTH_MISMATCH; + else { + PROCESS_SESSION_INFORMATION session; + + if (PreviousMode != KernelMode) { + if (copy_from_user(&session, ProcessInformation, + sizeof(PROCESS_SESSION_INFORMATION))) + Status = STATUS_UNSUCCESSFUL; + } + else + session = *(PPROCESS_SESSION_INFORMATION)ProcessInformation; + + Process->session = session.SessionId; + } + break; + case ProcessQuotaLimits: + case ProcessBasePriority: + case ProcessRaisePriority: + case ProcessExceptionPort: + case ProcessAccessToken: + case ProcessLdtInformation: + case ProcessLdtSize: + case ProcessIoPortHandlers: + case ProcessWorkingSetWatch: + case ProcessUserModeIOPL: + case ProcessEnableAlignmentFaultFixup: + /* TODO */ + Status = STATUS_NOT_IMPLEMENTED; + break; + case ProcessBasicInformation: + case ProcessIoCounters: + case ProcessTimes: + case ProcessPooledUsageAndLimits: + case ProcessWx86Information: + case ProcessHandleCount: + case ProcessWow64Information: + case ProcessDebugPort: + /* TODO */ + default: + Status = STATUS_INVALID_INFO_CLASS; + break; + } + deref_object(Process); + + return Status; +} +EXPORT_SYMBOL(NtSetInformationProcess); + +NTSTATUS SERVICECALL +NtQueryInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + struct ethread *cur_thread, *thread; + NTSTATUS status = STATUS_SUCCESS; + union + { + THREAD_BASIC_INFORMATION TBI; + KERNEL_USER_TIMES TTI; + PVOID Address; + LARGE_INTEGER Count; + BOOLEAN Last; + } u; + KPROCESSOR_MODE PreviousMode = + (ULONG)ThreadInformation < TASK_SIZE ? UserMode : KernelMode; /* TODO ... */ + + ktrace("NtQueryInformationThread, hthread %p\n", ThreadHandle); + + if (ThreadInformationClass <= MaxThreadInfoClass && + !QueryInformationData[ThreadInformationClass].Implemented) + return STATUS_NOT_IMPLEMENTED; + + if (ThreadInformationClass > MaxThreadInfoClass || + QueryInformationData[ThreadInformationClass].Size == 0) + return STATUS_INVALID_INFO_CLASS; + + if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size) + return STATUS_INFO_LENGTH_MISMATCH; + + cur_thread = get_current_ethread(); + if (!cur_thread){ + return -EINVAL; + } + + status = ref_object_by_handle(ThreadHandle, + THREAD_ALL_ACCESS, + thread_object_type, + KernelMode, + (PVOID *)&thread, + NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + switch (ThreadInformationClass) { + case ThreadBasicInformation: + u.TBI.ExitStatus = thread->et_task ? STATUS_PENDING : 0; + u.TBI.TebBaseAddress = (PVOID)thread->tcb.teb; + u.TBI.ClientId.UniqueProcess = (HANDLE)thread->cid.unique_process; + u.TBI.ClientId.UniqueThread = (HANDLE)thread->cid.unique_thread; + u.TBI.AffinityMask = (kaffinity_t)thread->tcb.affinity; + u.TBI.Priority = (KPRIORITY)thread->tcb.priority; + u.TBI.BasePriority = (KPRIORITY)thread->tcb.priority; + break; + case ThreadTimes: +#ifdef SERVER_PM + /* TODO */ +#endif + break; + case ThreadQuerySetWin32StartAddress: + u.Address = thread->win32_start_address; + break; + case ThreadPerformanceCount: + /* Nebbett says this class is always zero */ + u.Count.QuadPart = 0; + break; + case ThreadAmILastThread: + u.Last = list_empty(thread->threads_process->thread_list_head.next) ? TRUE : FALSE; + break; + default: + status = STATUS_INVALID_INFO_CLASS; + break; + } + + deref_object(thread); + + if (PreviousMode == UserMode) { + if (ThreadInformationLength) { + if (copy_to_user(ThreadInformation, + &u.TBI, + ThreadInformationLength)) + return STATUS_UNSUCCESSFUL; + } + if (ReturnLength) { + if(copy_to_user(ReturnLength, + &ThreadInformationLength, + sizeof(ULONG))) + return STATUS_UNSUCCESSFUL; + } + } + else { + memcpy(ThreadInformation, &u.TBI, ThreadInformationLength); + *ReturnLength = ThreadInformationLength; + } + + return status; +} +EXPORT_SYMBOL(NtQueryInformationThread); + +NTSTATUS SERVICECALL +NtSetInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength) +{ + PETHREAD Thread; + union + { + KPRIORITY Priority; + LONG Increment; + KAFFINITY Affinity; + HANDLE Handle; + PVOID Address; + }u; + KPROCESSOR_MODE PreviousMode = + (ULONG)ThreadInformation < TASK_SIZE ? UserMode : KernelMode; /* TODO ... */ + NTSTATUS Status = STATUS_SUCCESS; + + ktrace("NtSetInformationThread\n"); + if (ThreadInformationClass <= MaxThreadInfoClass && + !SetInformationData[ThreadInformationClass].Implemented) + return STATUS_NOT_IMPLEMENTED; + if (ThreadInformationClass > MaxThreadInfoClass || + SetInformationData[ThreadInformationClass].Size == 0) + return STATUS_INVALID_INFO_CLASS; + if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size) + return STATUS_INFO_LENGTH_MISMATCH; + + if (PreviousMode == UserMode) { + if (copy_from_user(&u.Priority, + ThreadInformation, + ThreadInformationLength)) + return STATUS_UNSUCCESSFUL; + } else + memcpy(&u.Priority, ThreadInformation, ThreadInformationLength); + + /* FIXME: This is REALLY wrong. Some types don't need THREAD_SET_INFORMATION */ + /* FIXME: We should also check for certain things before doing the reference */ + Status = ref_object_by_handle (ThreadHandle, + THREAD_SET_INFORMATION, + thread_object_type, + PreviousMode, + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) + return Status; + + switch (ThreadInformationClass) { + case ThreadPriority: + if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY) { + Status = STATUS_INVALID_PARAMETER; + break; + } + /* TODO: KeSetPriorityThread(&Thread->tcb, u.Priority); */ + break; + case ThreadBasePriority: + /* TODO: KeSetBasePriorityThread (&Thread->tcb, u.Increment); */ +#ifdef SERVER_PM + Thread->tcb.priority = u.Priority; +#endif + break; + case ThreadAffinityMask: + if ((Thread->threads_process->pcb.affinity & u.Affinity) != u.Affinity) { + Status = STATUS_INVALID_PARAMETER; + break; + } + /* TODO: Status = KeSetAffinityThread(&Thread->tcb, u.Affinity); */ +#ifdef SERVER_PM + Thread->tcb.affinity = u.Affinity; +#endif + break; + case ThreadImpersonationToken: + /* TODO: Status = PsAssignImpersonationToken (Thread, u.Handle); */ +#ifdef SERVER_PM + security_set_thread_token( Thread->tcb.win32thread, u.Handle ); +#endif + break; + case ThreadQuerySetWin32StartAddress: + Thread->win32_start_address = u.Address; + break; + default: + Status = STATUS_INVALID_INFO_CLASS; + break; + } + deref_object(Thread); + + return Status; +} +EXPORT_SYMBOL(NtSetInformationThread); + +#endif diff --git a/unifiedkernel/ps/suspend.c b/unifiedkernel/ps/suspend.c new file mode 100644 index 0000000..11769ca --- /dev/null +++ b/unifiedkernel/ps/suspend.c @@ -0,0 +1,411 @@ +/* + * suspend.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * suspend.c: + * Refered to ReactOS code + */ +#include "win32_process.h" +#include +#include +#include +#include "apc.h" +#include "file.h" +#include "io.h" +#include "mutex.h" +#include "object.h" +#include "pefile.h" +#include "unistr.h" +#include "attach.h" +#include "event.h" +#include "handle.h" +#include "ke.h" +#include "ntstatus.h" +#include "objwait.h" +#include "process.h" +#include "section.h" +#include "semaphore.h" +#include "virtual.h" +#include "win32.h" +#include "thread.h" +#include "w32syscall.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#define THREAD_ALERT_INCREMENT 2 + +extern VOID +abort_wait_thread(struct kthread *Thread, + NTSTATUS WaitStatus, + KPRIORITY Increment); + +VOID STDCALL +suspend_thread_kernel_routine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArguemnt2) +{ + return; +} + +VOID STDCALL +suspend_thread_normal_routine(PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + struct kthread *cur_thread = (struct kthread *)get_current_ethread(); + + ktrace("suspend thread\n"); + /* Non-alertable kernel-mode suspended wait */ + wait_for_single_object(&cur_thread->suspend_semaphore, + 0, /* Suspended debuging aid */ + KernelMode, + FALSE, + NULL); +} + +/* + * @implemented + */ +/* The Increment Argument seems to be ignored by NT and always 0 when called */ +VOID STDCALL +terminate_thread(IN KPRIORITY Increment) +{ + struct kthread * thread = (struct kthread * )get_current_ethread(); + + local_irq_disable(); + list_del(&thread->thread_list_entry); + thread->header.signal_state = true; + if (!list_empty(&thread->header.wait_list_head)) { + /* Satisfy waits */ + wait_test((struct dispatcher_header *)thread, IO_NO_INCREMENT); + } + local_irq_enable(); + + do_exit(0); + /* NOTREACHED */ +} +EXPORT_SYMBOL(terminate_thread); + +ULONG STDCALL +resume_thread(PKTHREAD Thread) +{ + unsigned long previous_count; + + ktrace("resume_thread (Thread %p called). %x, %x\n", Thread, Thread->suspend_count, Thread->freeze_count); + + /* Lock the Dispatcher */ + spin_lock_irq(&((struct ethread * ) Thread)->thread_lock); + + /* Save the Old Count */ + previous_count = Thread->suspend_count; + + /* Check if it existed */ + if (previous_count) { + Thread->suspend_count--; + /* Decrease the current Suspend Count and Check Freeze Count */ + if ((!Thread->suspend_count) && (!Thread->freeze_count)) { + /*TODO Signal the Suspend Semaphore */ + Thread->suspend_semaphore.header.signal_state++; + wait_test(&Thread->suspend_semaphore.header, IO_NO_INCREMENT); + } + } + + /* Release Lock and return the Old State */ + spin_unlock_irq(&((struct ethread * ) Thread)->thread_lock); + + return previous_count; +} +EXPORT_SYMBOL(resume_thread); + +ULONG STDCALL +suspend_thread(PKTHREAD Thread) +{ + unsigned long previous_count; + /* FIXME: KIRQL old_irql; */ + + spin_lock_irq(&((struct ethread * ) Thread)->thread_lock); + + /* Save the Old Count */ + previous_count = Thread->suspend_count; + + /* Increment it */ + Thread->suspend_count++; + + /* Check if we should suspend it */ + if (!previous_count && !Thread->freeze_count) { + + /* Insert the APC */ + if (!__insert_queue_apc(&Thread->suspend_apc, IO_NO_INCREMENT)) { + /* FIXME Unsignal the Semaphore, the APC already got inserted */ + Thread->suspend_semaphore.header.signal_state--; + } + } + + /* Release Lock and return the Old State */ + spin_unlock_irq(&((struct ethread * ) Thread)->thread_lock); + + return previous_count; +} +EXPORT_SYMBOL(suspend_thread); + +BOOLEAN STDCALL +alert_thread(PKTHREAD Thread, KPROCESSOR_MODE AlertMode) +{ + /* KIRQL OldIrql; */ + BOOLEAN previous_state; + + /* Acquire the Dispatcher Database Lock */ + spin_lock_irq(&((struct ethread * ) Thread)->thread_lock); + + /* Save the Previous State */ + previous_state = Thread->alerted[(int)AlertMode]; + + /* Return if Thread is already alerted. */ + if (previous_state == false) { + /* If it's Blocked, unblock if it we should */ + if (Thread->state == Waiting && + (AlertMode == KernelMode || Thread->wait_mode == AlertMode) && Thread->alertable) { + abort_wait_thread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); + + } else { + /* If not, simply Alert it */ + Thread->alerted[(int)AlertMode] = true; + } + } + + /* Release the Dispatcher Lock */ + spin_unlock_irq(&((struct ethread * ) Thread)->thread_lock); + + /* Return the old state */ + return previous_state; +} +EXPORT_SYMBOL(alert_thread); + +ULONG STDCALL +alert_resume_thread(IN PKTHREAD Thread) +{ + unsigned long previous_count; + + /* Lock the Dispatcher Database and the APC Queue */ + spin_lock_irq(&((struct ethread * ) Thread)->thread_lock); + spin_lock(&Thread->apc_queue_lock);/* TODO consider again */ + + /* Return if Thread is already alerted. */ + if (Thread->alerted[KernelMode] == false) { + /* If it's Blocked, unblock if it we should */ + if (Thread->state == Waiting && Thread->alertable) { + abort_wait_thread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); + + } else { + /* If not, simply Alert it */ + Thread->alerted[KernelMode] = true; + } + } + + /* Save the old Suspend Count */ + previous_count = Thread->suspend_count; + + /* If the thread is suspended, decrease one of the suspend counts */ + if (previous_count) { + /* Decrease count. If we are now zero, unwait it completely */ + if (--Thread->suspend_count) { + /* Signal and satisfy */ + Thread->suspend_semaphore.header.signal_state++; + wait_test(&Thread->suspend_semaphore.header, IO_NO_INCREMENT); + } + } + + /* Release Locks and return the Old State */ + spin_unlock(&Thread->apc_queue_lock);/* TODO consider again */ + spin_lock_irq(&((struct ethread * ) Thread)->thread_lock); + + return previous_count; +} +EXPORT_SYMBOL(alert_resume_thread); + +NTSTATUS SERVICECALL +NtResumeThread(IN HANDLE ThreadHandle, + IN PULONG SuspendCount OPTIONAL) +{ + struct ethread * thread; + ULONG prev; + KPROCESSOR_MODE previous_mode = (KPROCESSOR_MODE)get_pre_mode(); + NTSTATUS status = STATUS_SUCCESS; + + /* Get the Thread Object */ + status = ref_object_by_handle(ThreadHandle, + THREAD_SUSPEND_RESUME, + thread_object_type, + previous_mode, + (PVOID*)&thread, + NULL); + if (status) + return status; + + /* Call the Kernel Function */ + prev = resume_thread(&thread->tcb); + + /* Return it */ + if (SuspendCount) { + if (UserMode == previous_mode) { + if (copy_to_user(SuspendCount, &prev, sizeof(ULONG))) { + status = STATUS_UNSUCCESSFUL; + goto out; + } + } else + *SuspendCount = prev; + } + +out: + /* Dereference and Return */ + deref_object((PVOID)thread); + return status; +} +EXPORT_SYMBOL(NtResumeThread); + +NTSTATUS SERVICECALL +NtSuspendThread(IN HANDLE ThreadHandle, + IN PULONG PreviousSuspendCount OPTIONAL) +{ + struct ethread * thread; + ULONG prev; + KPROCESSOR_MODE previous_mode = (KPROCESSOR_MODE)get_pre_mode(); + NTSTATUS status = STATUS_SUCCESS; + + /* Get the Thread Object */ + status = ref_object_by_handle(ThreadHandle, + THREAD_SUSPEND_RESUME, + thread_object_type, + previous_mode, + (PVOID*)&thread, + NULL); + if (status) + return status; + + /* Call the Kernel Function */ + prev = suspend_thread(&thread->tcb); + + set_tsk_thread_flag(thread->et_task, TIF_APC); + + /* Return it */ + if (PreviousSuspendCount){ + if (UserMode == previous_mode) { + if (copy_to_user(PreviousSuspendCount, &prev, sizeof(ULONG))) { + status = STATUS_UNSUCCESSFUL; + goto out; + } + } else + *PreviousSuspendCount = prev; + } + +out: + /* Dereference and Return */ + deref_object((PVOID)thread); + return status; +} +EXPORT_SYMBOL(NtSuspendThread); + +NTSTATUS SERVICECALL +NtAlertThread (IN HANDLE ThreadHandle) +{ + + KPROCESSOR_MODE previous_mode = (KPROCESSOR_MODE)get_pre_mode(); + struct ethread * thread; + NTSTATUS status; + + /* Reference the Object */ + status = ref_object_by_handle(ThreadHandle, + THREAD_SUSPEND_RESUME, + thread_object_type, + previous_mode, + (PVOID*)&thread, + NULL); + if (status) + return status; + + /* + * Do an alert depending on the processor mode. If some kmode code wants to + * enforce a umode alert it should call KeAlertThread() directly. If kmode + * code wants to do a kmode alert it's sufficient to call it with Zw or just + * use KeAlertThread() directly + */ + alert_thread(&thread->tcb, previous_mode); + + /* Dereference Object */ + deref_object(thread); + + /* Return status */ + return status; + +} +EXPORT_SYMBOL(NtAlertThread); + +NTSTATUS SERVICECALL +NtAlertResumeThread(IN HANDLE ThreadHandle, + OUT PULONG SuspendCount) +{ + KPROCESSOR_MODE previous_mode = (KPROCESSOR_MODE)get_pre_mode(); + struct ethread * thread; + NTSTATUS status; + ULONG previous_state; + + /* Reference the Object */ + status = ref_object_by_handle(ThreadHandle, + THREAD_SUSPEND_RESUME, + thread_object_type, + previous_mode, + (PVOID*)&thread, + NULL); + if (status) + return status; + + /* Call the Kernel Function */ + previous_state = alert_resume_thread(&thread->tcb); + + /* Dereference Object */ + deref_object(thread); + + if (SuspendCount) { + if (UserMode == previous_mode) { + if(copy_to_user(SuspendCount, &previous_state, sizeof(ULONG))) + return STATUS_UNSUCCESSFUL; + } else + *SuspendCount = previous_state; + } + + return status; +} +EXPORT_SYMBOL(NtAlertResumeThread); + +NTSTATUS SERVICECALL +NtDelayExecution(IN BOOLEAN Alertable, + IN PLARGE_INTEGER DelayInterval) +{ + /* TODO */ + return 0; +} +EXPORT_SYMBOL(NtDelayExecution); + +#endif + diff --git a/unifiedkernel/ps/thread.c b/unifiedkernel/ps/thread.c new file mode 100644 index 0000000..22ede0b --- /dev/null +++ b/unifiedkernel/ps/thread.c @@ -0,0 +1,1345 @@ +/* + * thread.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * thread.c: thread implementation + * Refered to ReactOS code + */ +#include "win32_process.h" +#include +#include +#include +#include +#include +#include +#include +#include "apc.h" +#include "file.h" +#include "io.h" +#include "mutex.h" +#include "object.h" +#include "pefile.h" +#include "unistr.h" +#include "attach.h" +#include "event.h" +#include "handle.h" +#include "ke.h" +#include "ntstatus.h" +#include "objwait.h" +#include "process.h" +#include "section.h" +#include "semaphore.h" +#include "virtual.h" +#include "win32.h" +#include "thread.h" +#include "w32syscall.h" + +#include "wineserver/uk_lib.h" +#include "wineserver/list.h" +#include "wineserver/user.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +#ifdef SERVER_PM +static struct list_head w32thread_list = LIST_INIT(w32thread_list); +#endif +POBJECT_TYPE thread_object_type = NULL; +EXPORT_SYMBOL(thread_object_type); + +static void thread_close(struct ethread *); +static int thread_signal(struct ethread *, int); +static void thread_exit(struct ethread *, int); +static void thread_execve(struct ethread *); +static void thread_fork(struct ethread *, + struct task_struct *, + struct task_struct *, + unsigned long); + +extern void do_exit_task(struct task_struct *tsk, long code); +extern long do_fork_from_task(struct task_struct *ptsk, + unsigned long process_flags, + unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size, + int __user *parent_tidptr, + int __user *child_tidptr); + +extern asmlinkage void thread_startup(void); + +extern unsigned long get_ntdll_entry(void); +extern unsigned long get_interp_entry(void); +extern unsigned long get_thread_entry(void); + +#define arch_init_thread i386_init_thread +#define i386_init_thread(th, ctx) do { } while (0) + +static const struct ethread_operations ethread_ops = { + name: "ethread", + owner: THIS_MODULE, + close: thread_close, + exit: thread_exit, + signal: thread_signal, + execve: thread_execve, + fork: thread_fork +}; + +void __attribute__((regparm(3))) +set_trap_frame(unsigned long esp, struct task_struct *tsk) +{ + if (tsk->ethread) + tsk->ethread->tcb.trap_frame = (struct ktrap_frame *)esp; +} + +int set_tls_array(struct thread_struct *t, int idx, unsigned long addr, unsigned int limit) +{ + struct user_desc info; + struct desc_struct *desc; + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN; + + info.entry_number = idx; + info.base_addr = addr; + info.limit = limit; + info.contents = 0; + info.read_exec_only = 0; + info.seg_not_present = 0; + info.seg_32bit = 1; + info.limit_in_pages = 1; + info.useable = 0; + +/* FIXME */ + fill_ldt(desc, &info); +/* + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); +*/ + + return 0; +} + +#ifdef SERVER_PM +/* copy a context structure according to the flags */ +void copy_context( CONTEXT *to, const CONTEXT *from, unsigned int flags ) +{ + flags &= ~CONTEXT_i386; /* get rid of CPU id */ + if (flags & CONTEXT_CONTROL) { + to->Ebp = from->Ebp; + to->Eip = from->Eip; + to->Esp = from->Esp; + to->SegCs = from->SegCs; + to->SegSs = from->SegSs; + to->EFlags = from->EFlags; + } + if (flags & CONTEXT_INTEGER) { + to->Eax = from->Eax; + to->Ebx = from->Ebx; + to->Ecx = from->Ecx; + to->Edx = from->Edx; + to->Esi = from->Esi; + to->Edi = from->Edi; + } + if (flags & CONTEXT_SEGMENTS) { + to->SegDs = from->SegDs; + to->SegEs = from->SegEs; + to->SegFs = from->SegFs; + to->SegGs = from->SegGs; + } + if (flags & CONTEXT_FLOATING_POINT) { + to->FloatSave = from->FloatSave; + } + if (flags & CONTEXT_EXTENDED_REGISTERS) { + memcpy( to->ExtendedRegisters, from->ExtendedRegisters, sizeof(to->ExtendedRegisters) ); + } + if (flags & CONTEXT_DEBUG_REGISTERS) { + to->Dr0 = from->Dr0; + to->Dr1 = from->Dr1; + to->Dr2 = from->Dr2; + to->Dr3 = from->Dr3; + to->Dr6 = from->Dr6; + to->Dr7 = from->Dr7; + } + to->ContextFlags |= flags; +} + +/* retrieve the current instruction pointer of a context */ +static inline void *get_context_ip( const CONTEXT *context ) +{ + return (void *)context->Eip; +} + +/* return the context flag that contains the CPU id */ +static inline unsigned int get_context_cpu_flag(void) +{ + return CONTEXT_i386; +} + +/* return only the context flags that correspond to system regs */ +/* (system regs are the ones we can't access on the client side) */ +static inline unsigned int get_context_system_regs( unsigned int flags ) +{ + return flags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386); +} + +/* Temporarily add just for compiling + * These functions shouldn't be here */ +void set_thread_context( struct w32thread *thread, const CONTEXT *context, unsigned int flags ) +{ +} +void get_thread_context( struct w32thread *thread, CONTEXT *context, unsigned int flags ) +{ +} +void security_set_thread_token(struct w32thread *thread, obj_handle_t handle) +{ +} +void remove_process_thread( struct w32process *process, struct w32thread *thread ) +{ +} +/* Temporarily add just for compiling */ + +/* initialize the structure for a newly allocated w32thread */ +static inline void init_w32thread_structure( struct w32thread *thread ) +{ + thread->debug_ctx = NULL; + thread->debug_event = NULL; + thread->debug_break = 0; + thread->queue = NULL; + thread->error = 0; + thread->req_data = NULL; + thread->req_toread = 0; + thread->reply_data = NULL; + thread->reply_towrite = 0; + thread->state = RUNNING; + thread->context = NULL; + thread->suspend_context = NULL; + thread->desktop_users = 0; + + thread->creation_time = current_time; + thread->exit_time = 0; +} + +static void cleanup_thread( struct w32thread *thread ) +{ + kfree( thread->req_data ); + kfree( thread->reply_data ); + kfree( thread->suspend_context ); + free_msg_queue( thread ); + cleanup_clipboard_thread(thread); + destroy_thread_windows( thread ); + close_thread_desktop( thread ); + thread->req_data = NULL; + thread->reply_data = NULL; + thread->context = NULL; + thread->suspend_context = NULL; + thread->desktop = 0; +} + +static inline void free_w32thread(struct w32thread *thread) +{ + ktrace("%s\n", __FUNCTION__); + cleanup_thread(thread); + kfree(thread); +} + +/* create a new w32thread */ +struct w32thread *create_w32thread( struct ethread *ethread ) +{ + struct w32thread *w32thread; + struct w32process *w32process = ethread->threads_process->win32process; + + ktrace("%s\n", __FUNCTION__); + w32thread = mem_alloc(sizeof(struct w32thread)); + if (!w32thread) + return NULL; + + init_w32thread_structure( w32thread ); + + w32thread->process = w32process; + w32thread->ethread = ethread; + w32thread->desktop = w32process->desktop; + if (!current_thread) + current_thread = w32thread; + + list_add_head( &w32thread_list, &w32thread->entry ); + + return w32thread; +} + +void kill_w32thread( struct w32thread *thread ) +{ + if (thread->state == TERMINATED) + return; /* already killed */ + thread->state = TERMINATED; + thread->exit_time = current_time; + if (current_thread == thread) + current_thread = NULL; + + kill_console_processes( thread, 0 ); + cleanup_thread( thread ); + remove_process_thread( thread->process, thread ); +} + +/* terminate a thread */ +NTSTATUS server_terminate_thread(struct ethread *ethread) +{ + struct w32thread *thread; + + if (!ethread) + return STATUS_INVALID_PARAMETER; + + thread = ethread->tcb.win32thread; + if (thread != current_thread) + kill_w32thread( thread ); + return STATUS_SUCCESS; +} + +/* retrieve the current context of a thread */ +int server_get_thread_context(struct ethread *ethread, int suspend, unsigned int context_flags) +{ + struct w32thread *thread = ethread->tcb.win32thread; + CONTEXT *context; + + if (suspend) { + if (thread != current_thread || !thread->suspend_context) + set_error( STATUS_INVALID_PARAMETER ); /* not suspended, shouldn't happen */ + else { + if (thread->context == thread->suspend_context) + thread->context = NULL; + set_reply_data_ptr( thread->suspend_context, sizeof(CONTEXT) ); + thread->suspend_context = NULL; + } + } else if (thread != current_thread && !thread->context) { + /* thread is not suspended, retry (if it's still running) */ + if (thread->state != RUNNING) + set_error( STATUS_ACCESS_DENIED ); + else + set_error( STATUS_PENDING ); + } + else if ((context = set_reply_data_size( sizeof(CONTEXT) ))) { + unsigned int flags = get_context_system_regs( context_flags ); + + memset( context, 0, sizeof(CONTEXT) ); + context->ContextFlags = get_context_cpu_flag(); + if (thread->context) + copy_context( context, thread->context, context_flags & ~flags ); + if (flags) + get_thread_context( thread, context, flags ); + } + return (thread == current_thread); +} + +/* set the current context of a thread */ +int server_set_thread_context(struct ethread *ethread, int suspend, unsigned int context_flags) +{ + struct w32thread *thread = ethread->tcb.win32thread; + + if (suspend) { + if (thread != current_thread || thread->context) + set_error( STATUS_INVALID_PARAMETER ); /* nested suspend or exception, shouldn't happen */ + else if ((thread->suspend_context = mem_alloc( sizeof(CONTEXT) ))) { + memcpy( thread->suspend_context, get_req_data(), sizeof(CONTEXT) ); + thread->context = thread->suspend_context; + } + } + else if (thread != current_thread && !thread->context) { + /* thread is not suspended, retry (if it's still running) */ + if (thread->state != RUNNING) + set_error( STATUS_ACCESS_DENIED ); + else + set_error( STATUS_PENDING ); + } + else { + const CONTEXT *context = get_req_data(); + unsigned int flags = get_context_system_regs( context_flags ); + + if (flags) + set_thread_context( thread, context, flags ); + if (thread->context && !get_error()) + copy_context( thread->context, context, context_flags & ~flags ); + } + return (thread == current_thread); +} +#endif + +/* + * thread object destructor + */ +static void thread_close(struct ethread *thread) +{ + struct eprocess *process; + + process = thread->threads_process; + thread->threads_process = NULL; + + /* detach the thread record from the Linux task */ + ktrace("thread_close, obj %p\n", thread); + thread->et_task = NULL; + thread->tcb.state = Terminated; + + deref_object((PVOID)thread); + + /* detach from the containing process */ + deref_object(process); +} /* end thread_close() */ + +void rundown_thread(void) +{ + struct kthread * thread = (struct kthread *) get_current_ethread(); + struct kmutant * mutant; + struct list_head * cur_entry; + + ktrace("rundown thread\n"); + + local_irq_disable(); + while (!list_empty(&thread->mutant_list_head)) { + /* Get the Mutant */ + cur_entry = thread->mutant_list_head.next; + mutant = list_entry(cur_entry, struct kmutant, mutant_list_entry); + + /* check apc disable */ + + mutant->header.signal_state = 1; + mutant->abandoned = 1; + mutant->owner_thread = NULL; + list_del(&mutant->mutant_list_entry); + + if(!list_empty(&mutant->header.wait_list_head)) { + wait_test(&mutant->header, MUTANT_INCREMENT); + } + } + local_irq_enable(); +} + +/* + * notification of exit + * - the exit_status is as sys_wait() would return + * - notification includes fatal signals + */ +static void thread_exit(struct ethread *thread, int exit_status) +{ + struct eprocess *process = thread->threads_process; + BOOLEAN last; + + /* if Terminated, do nothing */ + ktrace("thread %p, exit_status %d\n", thread, thread->exit_status); + + thread->terminated = 1; + + /* Can't terminate a thread if it attached another process */ + if (thread->tcb.apc_state_index) { + return; + } + + /* TODO: Lower to Passive Level */ + + /* Lock the Process before we modify its thread entries */ + lock_process(process); + + list_del(&thread->thread_list_entry); + + /* TODO: close port */ + + /* TODO: Rundown Win32 Structures */ + + /* Set the last Thread Exit Status */ + process->last_thread_exit_status = thread->exit_status; + + /* The last Thread shuts down the Process */ + if ((last = list_empty(&process->thread_list_head))) { + /* Save the Exit Time if not already done by NtTerminateProcess. This + happens when the last thread just terminates without explicitly + terminating the process. TODO */ +#if 0 + process->exit_time = thread->exit_time; +#endif + __exit_process(process); + } + + if (thread->tcb.win32thread) { +#ifndef SERVER_PM + kfree(thread->tcb.win32thread); +#else + free_w32thread(thread->tcb.win32thread); +#endif + thread->tcb.win32thread = NULL; + } + + /* Free the TEB, if last thread, teb is freed by exit() */ + if (thread->tcb.teb && !last) { + delete_teb(thread->tcb.teb); + thread->tcb.teb = NULL; + } + + list_del(&thread->tcb.thread_list_entry); + + /* Unlock the Process */ + unlock_process(process); + + /* Rundown Mutexes */ + rundown_thread(); + + /* Satisfy waits */ + local_irq_disable(); + thread->tcb.header.signal_state = true; + if (!list_empty(&thread->tcb.header.wait_list_head)) + wait_test((struct dispatcher_header *)&thread->tcb, IO_NO_INCREMENT); + local_irq_enable(); + + ktrace("exit thread done\n"); +} /* end thread_exit() */ + +/* + * notification of signal + */ +static int thread_signal(struct ethread *thread, int signal) +{ + return WIN32_THREAD_SIGNAL_OKAY; +} /* end thread_signal() */ + +/* + * notification of execve + * - if this is NULL, a thread object will be destroyed on execve + */ +static void thread_execve(struct ethread *thread) +{ + /* TODO */ +} /* end thread_execve() */ + +/* + * notification that fork/clone has set up the new process and + * is just about to dispatch it + * - no threads will have been copied by default + */ +static void thread_fork(struct ethread *thread, + struct task_struct *parent, + struct task_struct *child, + unsigned long clone_flags) +{ + /* TODO */ +} /* end thread_fork() */ + +VOID delete_thread(PVOID Object) +{ + struct ethread * thread = Object; + + ktrace("delete_thread, obj %p\n", Object); + + if (thread->cid.unique_thread) + delete_cid_handle(thread->cid.unique_thread, thread_object_type); + + /* TODO: release stack mem */ +} + +/* FIXME */ +int poll_thread(struct wait_table_entry *wte) +{ + struct ethread * thread = (struct ethread * )wte->wte_obj; + int ret; + + ret = (thread->tcb.state == Running) ? POLL_NOTSIG : POLL_SIG; + + return ret; +} + +/* + * set teb on fs + */ +int set_teb_selector(struct task_struct *tsk, long teb) +{ + int cpu; + + set_tls_array(&tsk->thread, TEB_SELECTOR >> 3, teb, 1); + cpu = get_cpu(); + load_TLS(&tsk->thread, cpu); + put_cpu(); + + return 0; +} /* end set_teb_selector */ + +/* initialize kthread */ +void kthread_init(struct kthread *thread, struct eprocess *process) +{ + ktrace("kthread_init\n"); + + INIT_DISP_HEADER(&thread->header, thread_object, sizeof(struct ethread), false); + + /* initialize the mutant list */ + INIT_LIST_HEAD(&thread->mutant_list_head); + + /* setup apc fields */ + INIT_LIST_HEAD(&thread->apc_state.apc_list_head[0]); + INIT_LIST_HEAD(&thread->apc_state.apc_list_head[1]); + INIT_LIST_HEAD(&thread->saved_apc_state.apc_list_head[0]); + INIT_LIST_HEAD(&thread->saved_apc_state.apc_list_head[1]); + thread->apc_state.process = (struct kprocess *)process; + thread->apc_state_pointer[OriginalApcEnvironment] = &thread->apc_state; + thread->apc_state_pointer[AttachedApcEnvironment] = &thread->saved_apc_state; + thread->apc_state_index = OriginalApcEnvironment; + thread->apc_queue_lock = SPIN_LOCK_UNLOCKED; + thread->apc_queueable = true; + + /*NOW FIXME Initialize the Suspend APC */ + apc_init(&thread->suspend_apc, + thread, + OriginalApcEnvironment, + suspend_thread_kernel_routine, + NULL, + suspend_thread_normal_routine, + KernelMode, + NULL); + + + /* Initialize the Suspend Semaphore */ + semaphore_init(&thread->suspend_semaphore, 0, 128); + + /* initialize the suspend semaphore */ + /* FIXME: sema_init(&thread->suspend_semaphore, 0); */ + /* FIXME: keinitializetimer(&thread->timer); */ + + arch_init_thread(thread, context); + + thread->base_priority = process->pcb.base_priority; + thread->quantum = process->pcb.quantum_reset; + thread->quantum_reset = process->pcb.quantum_reset; + thread->affinity = process->pcb.affinity; + thread->priority = process->pcb.base_priority; + thread->user_affinity = process->pcb.affinity; + thread->disable_boost = process->pcb.disable_boost; + thread->auto_alignment = process->pcb.auto_alignment; + + /* set the thread to initalized */ + thread->state = Initialized; + + lock_process(process); + list_add_tail(&thread->thread_list_entry, &process->pcb.thread_list_head); + unlock_process(process); +#ifdef SERVER_PM + thread->win32thread = create_w32thread((struct ethread *)thread); +#endif +} /* end kthread_init */ + +/* initialize ethread */ +void ethread_init(struct ethread *thread, struct eprocess *process, struct task_struct *tsk) +{ + ktrace("ethread_init\n"); + + /* attach to the containing process */ + ref_object((PVOID)process); + write_lock(&process->ep_lock); + thread->threads_process = process; + write_unlock(&process->ep_lock); + + /* FIXME create a thread object and hook in to the Linux task */ + thread->et_task = tsk; + + atomic_set(&thread->et_count, 0); + + /* FIXME */ + thread->et_ops = (struct ethread_operations *)ðread_ops; + + INIT_LIST_HEAD(&thread->lpc_reply_chain); + INIT_LIST_HEAD(&thread->irp_list); + INIT_LIST_HEAD(&thread->active_timer_list_head); + thread->active_timer_list_lock = SPIN_LOCK_UNLOCKED; + thread->thread_lock = SPIN_LOCK_UNLOCKED; + + /* FIXME: semaphore_init */ + + thread->cid.unique_process = process->unique_processid; + + thread->win32_start_address = 0; /* context->Eax, default is 0 */ + lock_process(process); + list_add_tail(&thread->thread_list_entry, &process->thread_list_head); + unlock_process(process); + + add_ethread(thread->et_task, thread); + if (atomic_read(&thread->et_count) == 1) /* FIXME: add this to win32_thread.c */ + ref_object(thread); + +#ifndef SERVER_PM + if ((thread->tcb.win32thread = kmalloc(sizeof(struct w32thread), GFP_KERNEL))) + memset(thread->tcb.win32thread, 0, sizeof(struct w32thread)); +#endif + + kthread_init(&thread->tcb, process); +} /* end ethread_init */ + +/* + * user_thread_startup + * prepare for jumping to userspace to execute after new thread waken + */ +VOID +STDCALL +user_thread_startup(PKSTART_ROUTINE StartRoutine, + PVOID StartContext) +{ + struct ethread *thread; + PKAPC thread_apc; + void * start_stack; + + ktrace("user_thread_startup, pid %x, tgid %x\n",current->pid, current->tgid); + + if (!(thread = get_current_ethread())) { + return; + } + + if (!(thread_apc = kmalloc(sizeof(struct kapc),GFP_KERNEL))) { + return; + } + + start_stack = (void *)thread->tcb.stack_base; /* user stack base */ + + if (thread->threads_process->fork_in_progress) { + apc_init(thread_apc, + &thread->tcb, + OriginalApcEnvironment, + thread_special_apc, + NULL, + (PKNORMAL_ROUTINE)get_ntdll_entry(), + UserMode, + start_stack); + insert_queue_apc(thread_apc, + (void *)get_interp_entry(), + thread->threads_process->spare0[0], + IO_NO_INCREMENT); + + thread->threads_process->fork_in_progress = NULL; + } else { + apc_init(thread_apc, + &thread->tcb, + OriginalApcEnvironment, + thread_special_apc, + NULL, + (PKNORMAL_ROUTINE)get_thread_entry(), + UserMode, + start_stack); + insert_queue_apc(thread_apc, NULL,NULL, IO_NO_INCREMENT); + } + thread->tcb.apc_state.uapc_pending = 1; + set_tsk_thread_flag(current, TIF_APC); + + try_module_get(THIS_MODULE); + + return; +} /* end user_thread_startup */ + +/* + * init_thread_with_context + * init context for thread + */ +VOID +STDCALL +init_thread_with_context(struct kthread* Thread, + PKSYSTEM_ROUTINE SystemRoutine, + PKSTART_ROUTINE StartRoutine, /* FIXME */ + PVOID StartContext, /* FIXME */ + PCONTEXT Context) +{ + struct thread_info *info; + struct task_struct *p; + unsigned long * trapframe; + struct pt_regs * regs; + PCONTEXT context; + + if (!(context = kmalloc(sizeof(*context),GFP_KERNEL))) { + return; + } + + if (copy_from_user(context, Context, sizeof(*context))) { + kfree(context); + return; + } + + info = (struct thread_info *)((unsigned long)Thread->kernel_stack- THREAD_SIZE); + p = info->task; + set_tls_array(&p->thread, TEB_SELECTOR >> 3, (unsigned long)Thread->teb, 1); + + /* set for switch */ + trapframe = (unsigned long *)((unsigned long)Thread->kernel_stack - 8 - sizeof(struct pt_regs) - 12); + regs = (struct pt_regs *)(trapframe + 3); + + Thread->trap_frame = (struct ktrap_frame *)regs; + + trapframe[0] = (unsigned long)SystemRoutine; + trapframe[1] = (unsigned long)StartRoutine; + trapframe[2] = (unsigned long)StartContext; + + p->thread.ip = (unsigned long)thread_startup; + p->thread.sp = (unsigned long)trapframe; + p->thread.sp0 = (unsigned long)(regs+1); + p->thread.fs = TEB_SELECTOR; + + /* set for userspace */ + regs->sp = context->Esp; + regs->ip = context->Eip; + + kfree(context); + return; +} /* end init_thread_with_context */ + +/* + * initialize_thread + * initialize kthread + */ +VOID +STDCALL +initialize_thread(struct kprocess* Process, + struct kthread* Thread, + PKSYSTEM_ROUTINE SystemRoutine, + PKSTART_ROUTINE StartRoutine, /* FIXME */ + PVOID StartContext, /* FIXME */ + PCONTEXT Context, + PVOID Teb, + PVOID KernelStack) +{ + ktrace("initialize_thread kprocess %p, kthread %p, systemroutine %p, context %p, teb %p, kernelstack %p\n", + Process, Thread, SystemRoutine, Context, Teb, KernelStack); + + /* Set the TEB */ + Thread->teb = Teb; + + /* Allocate Stack use linux task stack and init + * Set the Thread Stacks + */ + Thread->kernel_stack = (PCHAR)KernelStack + THREAD_SIZE; + + /* FIXME + * Establish the pde's for the new stack and the thread structure within the + * address space of the new process. They are accessed while taskswitching or + * while handling page faults. At this point it isn't possible to call the + * page fault handler for the missing pde's. + */ + update_page_dir(((struct ethread *)Thread)->et_task->mm, (void *)Thread->stack_limit, THREAD_SIZE); + update_page_dir(((struct ethread *)Thread)->et_task->mm, Thread, sizeof(struct ethread)); + + init_thread_with_context(Thread, + SystemRoutine, + StartRoutine, + StartContext, + Context); +} /* end initialize_thread */ + +/* + * create_thread + */ +NTSTATUS +STDCALL +create_thread(OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + IN struct eprocess* TargetProcess, /* FIXME */ + OUT PCLIENT_ID ClientId, + IN PCONTEXT ThreadContext, + IN PINITIAL_TEB InitialTeb, + IN BOOLEAN CreateSuspended, + IN PKSTART_ROUTINE StartRoutine OPTIONAL, /* FIXME */ + IN PVOID StartContext OPTIONAL) /* FIXME */ +{ + struct eprocess * process; + struct ethread * thread, *first_thread, *cur_thread; + struct task_struct *new_tsk = NULL; + unsigned clone_flags = 0; + PTEB teb_base; + long cpid; + HANDLE hthread; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("create_thread\n"); + + if (!(cur_thread = get_current_ethread())) { + return STATUS_INVALID_PARAMETER; + } + + /* current still be regarded */ + if (ProcessHandle && ProcessHandle != NtCurrentProcess()) { + status = ref_object_by_handle(ProcessHandle, + PROCESS_ALL_ACCESS, + process_object_type, + KernelMode, + (PVOID *)&process, + NULL); + if (!NT_SUCCESS(status)) + return status; + } else { + if (TargetProcess) + process = (struct eprocess * )TargetProcess; + else + process = cur_thread->threads_process; + ref_object(process); + } + + if (!process->fork_in_progress) { + /* second and after */ + if (!ProcessHandle || ProcessHandle == NtCurrentProcess()) + first_thread = cur_thread; + else + first_thread = get_first_thread(process); + if (!first_thread) { + status = STATUS_INVALID_PARAMETER; + goto cleanup_process; + } + + clone_flags = SIGCHLD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD; + cpid = do_fork_from_task(first_thread->et_task, CREATE_THREAD, clone_flags, + first_thread->tcb.trap_frame->esp, (struct pt_regs *)first_thread->tcb.trap_frame, + 0, NULL, NULL); + if (cpid < 0) { + status = STATUS_INVALID_PARAMETER; + goto cleanup_process; + } + + new_tsk = find_task_by_vpid(cpid); + + memset(&new_tsk->thread.tls_array, 0, sizeof(new_tsk->thread.tls_array)); + set_tls_array(&new_tsk->thread, first_thread->et_task->thread.gs >> 3, + (unsigned long)InitialTeb->StackBase + 0x800, 0xfffff); + + /* allocate a Win32 thread object */ + status = create_object(KernelMode, + thread_object_type, + ObjectAttributes, + KernelMode, + NULL, + sizeof(struct ethread), + 0, + 0, + (PVOID *)&thread); + if (!NT_SUCCESS(status)) + goto cleanup_tsk; + + ethread_init(thread, process, new_tsk); + deref_object(thread); + + } else { + /* for first thread */ + thread = process->fork_in_progress; + new_tsk = thread->et_task; + } + + thread->cid.unique_thread = create_cid_handle(thread, thread_object_type); + thread->cid.unique_process = process->unique_processid; + if (!thread->cid.unique_thread) { + goto cleanup_tsk; + } + + if (ClientId) { + if (copy_to_user(&ClientId->UniqueThread, &thread->cid.unique_thread, sizeof(HANDLE))) + goto cleanup_tsk; + if (copy_to_user(&ClientId->UniqueProcess, &thread->cid.unique_process, sizeof(HANDLE))) + goto cleanup_tsk; + } + + /* set user stack base */ + thread->tcb.stack_base = InitialTeb->StackBase; + + if (ThreadContext) { + /* Create Teb */ + teb_base = create_teb(process, (PCLIENT_ID)&thread->cid, InitialTeb); + + /* Set the Start Addresses */ + thread->start_address = (PVOID)ThreadContext->Eip; + thread->win32_start_address = (PVOID)ThreadContext->Eax; /*FIXME */ + + /* intialize kthread */ + initialize_thread(&process->pcb, + &thread->tcb, + user_thread_startup, + NULL, + NULL, + ThreadContext, + teb_base, + task_thread_info(new_tsk)); + } else { + /* FIXME PsCreateSystemThread */ + } + + /* Insert Thread into Handle Table */ + status = insert_object(thread, + NULL, + DesiredAccess, + 0, + NULL, + &hthread); + if (!NT_SUCCESS(status)) + goto cleanup_tsk; + + if (copy_to_user(ThreadHandle, &hthread, sizeof(hthread))) { + status = STATUS_UNSUCCESSFUL; + goto cleanup_thread; + } + + clear_tsk_need_resched(new_tsk); + sched_fork(new_tsk, clone_flags); + wake_up_new_task(new_tsk, CLONE_VM | CLONE_FS | CLONE_FILES| CLONE_SIGHAND); + + /* FIXME Notify Thread Creation */ + + /* NOW FIXME Suspend the Thread if we have to */ + if (CreateSuspended) + suspend_thread(&thread->tcb); + + /* FIXME: SECURITY */ + + /* FIXME Dispatch thread */ + status = STATUS_SUCCESS; + goto cleanup_process; + +cleanup_thread: + deref_object(thread); + +cleanup_tsk: + if (new_tsk) + do_exit_task(new_tsk,0); + +cleanup_process: + deref_object(process); + + return status; +} /* end create_thread */ + +/* + * NtCreateThread + */ +NTSTATUS +SERVICECALL +NtCreateThread(OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + OUT PCLIENT_ID ClientId, + IN PCONTEXT ThreadContext, + IN PINITIAL_TEB InitialTeb, + IN BOOLEAN CreateSuspended) +{ + PINITIAL_TEB safe_initial_teb; + NTSTATUS status; + + ktrace("NtCreateThread\n"); + + if (!(safe_initial_teb = kmalloc(sizeof(INITIAL_TEB), GFP_KERNEL))) { + return STATUS_NO_MEMORY; + } + + status = STATUS_UNSUCCESSFUL; + if (copy_from_user(safe_initial_teb, InitialTeb, sizeof(INITIAL_TEB))) + goto out; + + /* Call the shared function */ + status = create_thread(ThreadHandle, + DesiredAccess, + ObjectAttributes, + ProcessHandle, + NULL, + ClientId, + ThreadContext, + safe_initial_teb, + CreateSuspended, + NULL, + NULL); + +out: + kfree(safe_initial_teb); + return status; +} /* end NtCreateThread */ +EXPORT_SYMBOL(NtCreateThread); + +NTSTATUS +SERVICECALL +NtOpenThread(OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PCLIENT_ID ClientId OPTIONAL) +{ + KPROCESSOR_MODE pre_mode = (KPROCESSOR_MODE)get_pre_mode(); + struct ethread *thread = NULL; + NTSTATUS status = STATUS_INVALID_PARAMETER; + + ktrace("NtOpenThread\n"); + if (ObjectAttributes->ObjectName) { + return open_object_by_name(ObjectAttributes, + thread_object_type, + NULL, + pre_mode, + DesiredAccess, + NULL, + ThreadHandle); + } else if (ClientId && ClientId->UniqueThread) { + if ((status = lookup_thread_by_tid(ClientId->UniqueThread, &thread))) + return status; + + status = open_object_by_pointer(thread, + ObjectAttributes->Attributes, + NULL, + DesiredAccess, + thread_object_type, + pre_mode, + ThreadHandle); + + deref_object(thread); + } + + return status; +} +EXPORT_SYMBOL(NtOpenThread); + +void trapframe_to_context(struct ethread * thread, PCONTEXT context) +{ + struct pt_regs * trap_frame = (struct pt_regs * )thread->tcb.trap_frame; + + if ((context->ContextFlags & CONTEXT_CONTROL ) == CONTEXT_CONTROL) { + context->Esp = trap_frame->sp; + context->SegSs = trap_frame->ss; + context->SegCs = trap_frame->cs; + context->Eip = trap_frame->ip; + context->EFlags = trap_frame->flags; + context->Ebp = trap_frame->bp; + } + + + if ((context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { + context->Eax = trap_frame->ax; + context->Ebx = trap_frame->bx; + context->Ecx = trap_frame->cx; + context->Edx = trap_frame->dx; + context->Esi = trap_frame->si; + context->Edi = trap_frame->di; + } + + if ((context->ContextFlags & CONTEXT_SEGMENTS ) == CONTEXT_SEGMENTS) { + context->SegDs = trap_frame->ds; + context->SegEs = trap_frame->es; + context->SegFs = thread->et_task->thread.fs; + context->SegGs = thread->et_task->thread.gs; + } + + if ((context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) { + context->Dr0 = thread->et_task->thread.debugreg0; + context->Dr1 = thread->et_task->thread.debugreg1; + context->Dr2 = thread->et_task->thread.debugreg2; + context->Dr3 = thread->et_task->thread.debugreg3; + context->Dr6 = thread->et_task->thread.debugreg6; + context->Dr7 = thread->et_task->thread.debugreg7; + } +} + +void context_to_trapframe(PCONTEXT context , struct ethread * thread) +{ + struct pt_regs * trap_frame = (struct pt_regs * )thread->tcb.trap_frame; + + if ((context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { + trap_frame->sp = context->Esp; + trap_frame->ss = context->SegSs; + trap_frame->cs = context->SegCs; + trap_frame->ip = context->Eip; + trap_frame->flags = context->EFlags; + trap_frame->bp = context->Ebp; + } + + if ((context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { + trap_frame->ax = context->Eax; + trap_frame->bx = context->Ebx; + trap_frame->cx = context->Ecx; + trap_frame->dx = context->Edx; + trap_frame->si = context->Esi; + trap_frame->di = context->Edi; + } + + if ((context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) { + trap_frame->ds = context->SegDs; + trap_frame->es = context->SegEs; + thread->et_task->thread.fs = context->SegFs; + thread->et_task->thread.gs = context->SegGs; + } + + if ((context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) { + thread->et_task->thread.debugreg0 = context->Dr0; + thread->et_task->thread.debugreg1 = context->Dr1; + thread->et_task->thread.debugreg2 = context->Dr2; + thread->et_task->thread.debugreg3 = context->Dr3; + thread->et_task->thread.debugreg6 = context->Dr6; + thread->et_task->thread.debugreg7 = context->Dr7; + } + + /* TODO: float register */ +} + +VOID +STDCALL +get_set_kernel_context_routine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2) +{ + PGET_SET_CTX_CONTEXT get_set_context; + struct kevent * event; + PCONTEXT context; + + get_set_context = (PGET_SET_CTX_CONTEXT) Apc; + event = &get_set_context->event; + context = &get_set_context->context; + + if (*SystemArgument1) + trapframe_to_context(get_current_ethread(), context); + else + context_to_trapframe(context, get_current_ethread()); + + set_event(event, EVENT_INCREMENT, FALSE); + suspend_thread(¤t->ethread->tcb); +} + +NTSTATUS SERVICECALL +NtGetContextThread(IN HANDLE ThreadHandle, + OUT PCONTEXT ThreadContext) +{ + struct ethread * thread; + GET_SET_CTX_CONTEXT ctx_context; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtGetContextThread %p, %p\n",ThreadHandle, ThreadContext); + + status = ref_object_by_handle(ThreadHandle, + THREAD_ALL_ACCESS, + thread_object_type, + KernelMode, + (PVOID *)&thread, + NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (thread == get_current_ethread()) { + trapframe_to_context(thread, &ctx_context.context); + } else { + event_init(&ctx_context.event, notification_event, 0); + + apc_init(&ctx_context.apc, + &thread->tcb, + OriginalApcEnvironment, + get_set_kernel_context_routine, + NULL, + NULL, + KernelMode, + NULL); + insert_queue_apc(&ctx_context.apc, (PVOID)1, NULL, IO_NO_INCREMENT); + + resume_thread(&thread->tcb); + status = wait_for_single_object(&ctx_context.event, + 0, + KernelMode, + FALSE, + NULL); + } + deref_object(thread); + + if (copy_to_user(ThreadContext, &ctx_context.context, sizeof(CONTEXT))) + status = STATUS_UNSUCCESSFUL; + + ktrace("NtGetContextThread return %x\n", status); + return status; +} +EXPORT_SYMBOL(NtGetContextThread); + +NTSTATUS SERVICECALL +NtSetContextThread(IN HANDLE ThreadHandle, + IN PCONTEXT ThreadContext) +{ + struct ethread * thread; + GET_SET_CTX_CONTEXT ctx_context; + NTSTATUS status = STATUS_SUCCESS; + + ktrace("NtSetContextThread %p, %p\n",ThreadHandle, ThreadContext); + + if (copy_from_user(&ctx_context.context, ThreadContext, sizeof(CONTEXT))) + return STATUS_UNSUCCESSFUL; + + status = ref_object_by_handle(ThreadHandle, + THREAD_ALL_ACCESS, + thread_object_type, + KernelMode, + (PVOID *)&thread, + NULL); + if (!NT_SUCCESS(status)) { + return status; + } + + + if (thread == get_current_ethread()) { + context_to_trapframe(&ctx_context.context, thread); + } else { + event_init(&ctx_context.event, notification_event, 0); + + apc_init(&ctx_context.apc, + &thread->tcb, + OriginalApcEnvironment, + get_set_kernel_context_routine, + NULL, + NULL, + KernelMode, + NULL); + insert_queue_apc(&ctx_context.apc, (PVOID)0, NULL, IO_NO_INCREMENT); + + resume_thread(&thread->tcb); + wait_for_single_object(&ctx_context.event, + 0, + KernelMode, + FALSE, + NULL); + } + + deref_object(thread); + + ktrace("NtSetContextThread return %x\n", status); + return status; +} +EXPORT_SYMBOL(NtSetContextThread); + +/* stubs from Wine server */ +int thread_queue_apc( struct w32thread *thread, struct object *owner, const apc_call_t *call_data ) +{ + return 0; +} + +void thread_cancel_apc( struct w32thread *thread, struct object *owner, enum apc_type type ) +{ +} + +struct w32thread *get_thread_from_id( thread_id_t id ) +{ + return NULL; +} + +int thread_get_inflight_fd( struct w32thread *thread, int client ) +{ + return 0; +} + +void send_client_fd( struct w32process* proc, unsigned int fd, void* hndl) +{ +} + +#endif + diff --git a/unifiedkernel/ps/token.c b/unifiedkernel/ps/token.c new file mode 100644 index 0000000..df1eb9b --- /dev/null +++ b/unifiedkernel/ps/token.c @@ -0,0 +1,218 @@ +/* + * token.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Jan 2006 - Created. + */ + +/* + * token.c: token implementation + * Refered to ReactOS code + */ +#include "win32_process.h" +#include +#include +#include +#include +#include +#include "objwait.h" +#include "thread.h" +#include "apc.h" +#include "process.h" +#include "win32.h" +#include "virtual.h" +#include "handle.h" +#include "attach.h" +#include "w32syscall.h" +#include "object.h" +#include "ke.h" +#include "objwait.h" + +#ifdef CONFIG_UNIFIED_KERNEL + +POBJECT_TYPE token_object_type = NULL; +EXPORT_SYMBOL(token_object_type); + +NTSTATUS SERVICECALL +NtOpenThreadToken(IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + OUT PHANDLE TokenHandle) +{ + ktrace("NtOpenThreadToken\n"); + return NtOpenThreadTokenEx(ThreadHandle, + DesiredAccess, + OpenAsSelf, + 0, + TokenHandle); +} +EXPORT_SYMBOL(NtOpenThreadToken); + +PACCESS_TOKEN +ref_impersonation_token(IN struct ethread *Thread, + OUT PBOOLEAN CopyOnOpen, + OUT PBOOLEAN EffectiveOnly, + OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) +{ + + if (Thread->active_impersonation_info == FALSE) + return NULL; + + *ImpersonationLevel = Thread->impersonation_info->impersonation_level; + *CopyOnOpen = Thread->impersonation_info->copy_on_open; + *EffectiveOnly = Thread->impersonation_info->effective_only; + + ref_object(Thread->impersonation_info->token); + + return Thread->impersonation_info->token; +} +EXPORT_SYMBOL(ref_impersonation_token); + +NTSTATUS SERVICECALL +NtOpenThreadTokenEx(IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle) +{ + struct ethread *thread; + PTOKEN token; /* TODO */ + BOOLEAN copy_on_open, effective_only; + SECURITY_IMPERSONATION_LEVEL impersonation = 0; + KPROCESSOR_MODE pre_mode = (KPROCESSOR_MODE)get_pre_mode(); + HANDLE htoken; + NTSTATUS status; + + ktrace("NtOpenThreadTokenEx\n"); + status = ref_object_by_handle(ThreadHandle, + THREAD_QUERY_INFORMATION, /* TODO */ + thread_object_type, + pre_mode, + (PVOID *) &thread, + NULL); + if (status) + return status; + + token = ref_impersonation_token(thread, + ©_on_open, + &effective_only, + &impersonation); + deref_object(thread); + + if (!token) + return STATUS_NO_TOKEN; + + if (impersonation == SecurityAnonymous) { + deref_object(token); + return STATUS_CANT_OPEN_ANONYMOUS; + } + + if (OpenAsSelf) { + /* TODO: disable impersonation */ + } + + /* FIXME: copy_on_open is set to be 0 before the following TODO is done*/ + copy_on_open = 0; + if (copy_on_open) { + /* TODO */ + } else { + status = open_object_by_pointer(token, + HandleAttributes, + NULL, + DesiredAccess, + token_object_type, + pre_mode, + &htoken); + } + + if (OpenAsSelf) { + /* TODO: restore impersonation */ + } + + if (NT_SUCCESS(status)) + if (copy_to_user(TokenHandle, &htoken, sizeof(htoken))) + status = STATUS_UNSUCCESSFUL; + + return status; +} +EXPORT_SYMBOL(NtOpenThreadTokenEx); + +NTSTATUS +open_process_token(HANDLE ProcessHandle, + PACCESS_TOKEN *Token) +{ + struct eprocess *process; + NTSTATUS status; + + status = ref_object_by_handle(ProcessHandle, + PROCESS_QUERY_INFORMATION, /* TODO */ + process_object_type, + get_pre_mode(), + (PVOID *)&process, + NULL); + + if (NT_SUCCESS(status)) { + ref_object(&process->token); + *Token = process->token.object; + deref_object(process); + } + return status; +} + +NTSTATUS SERVICECALL +NtOpenProcessTokenEx(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle) +{ + PACCESS_TOKEN token; + NTSTATUS status; + HANDLE htoken; + + ktrace("NtOpenProcessTokenEx\n"); + status = open_process_token(ProcessHandle, &token); + + if (NT_SUCCESS(status)) { + status = create_handle((struct eprocess * )get_current_eprocess(), /* TODO */ + (void *)token, + DesiredAccess, + FALSE, + &htoken); + deref_object(token); + if (NT_SUCCESS(status)) + if (copy_to_user(TokenHandle, &htoken, sizeof(htoken))) + status = STATUS_UNSUCCESSFUL; + } + + return status; +} +EXPORT_SYMBOL(NtOpenProcessTokenEx); + +NTSTATUS SERVICECALL +NtOpenProcessToken(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle) +{ + ktrace("NtOpenProcessToken\n"); + return NtOpenProcessTokenEx(ProcessHandle, + DesiredAccess, + 0, + TokenHandle); +} +EXPORT_SYMBOL(NtOpenProcessToken); +#endif diff --git a/unifiedkernel/pub/Makefile b/unifiedkernel/pub/Makefile new file mode 100644 index 0000000..ab4661b --- /dev/null +++ b/unifiedkernel/pub/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for pub +# + +PUB_OBJS := request.o \ + casemap.o \ + uk_lib.o \ + info.o \ + error.o + +$(MODULE)-objs += $(addprefix pub/, $(PUB_OBJS)) diff --git a/unifiedkernel/pub/casemap.c b/unifiedkernel/pub/casemap.c new file mode 100644 index 0000000..41d9889 --- /dev/null +++ b/unifiedkernel/pub/casemap.c @@ -0,0 +1,1743 @@ +/* + * casemap.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * casemap.c: + * Refered to Wine code + */ + +/* Unicode case mappings */ + +#include "win32.h" + +#ifdef CONFIG_UNIFIED_KERNEL +const WCHAR wine_casemap_lower[3318] = +{ + /* index */ + 0x01bf, 0x02bf, 0x03bf, 0x0439, 0x0539, 0x0639, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0699, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0799, 0x0892, + 0x0100, 0x098f, 0x0100, 0x0100, 0x0a13, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0b13, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0bf6, + /* defaults */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0041 .. 0x00ff */ + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0100 .. 0x01ff */ + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0xff39, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0xff87, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, + 0x0000, 0x00d2, 0x0001, 0x0000, 0x0001, 0x0000, 0x00ce, 0x0001, + 0x0000, 0x00cd, 0x00cd, 0x0001, 0x0000, 0x0000, 0x004f, 0x00ca, + 0x00cb, 0x0001, 0x0000, 0x00cd, 0x00cf, 0x0000, 0x00d3, 0x00d1, + 0x0001, 0x0000, 0x0000, 0x0000, 0x00d3, 0x00d5, 0x0000, 0x00d6, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x00da, 0x0001, + 0x0000, 0x00da, 0x0000, 0x0000, 0x0001, 0x0000, 0x00da, 0x0001, + 0x0000, 0x00d9, 0x00d9, 0x0001, 0x0000, 0x0001, 0x0000, 0x00db, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0002, 0x0001, 0x0000, 0x0002, + 0x0001, 0x0000, 0x0002, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0000, 0x0002, 0x0001, 0x0000, 0x0001, 0x0000, 0xff9f, 0xffc8, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + /* 0x0200 .. 0x02ff */ + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0xff7e, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x2a2b, 0x0001, 0x0000, 0xff5d, 0x2a28, 0x0000, + 0x0000, 0x0001, 0x0000, 0xff3d, 0x0045, 0x0047, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0386 .. 0x03ff */ + 0x0026, 0x0000, 0x0025, 0x0025, 0x0025, 0x0000, 0x0040, 0x0000, + 0x003f, 0x003f, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffc4, 0x0000, + 0x0000, 0x0001, 0x0000, 0xfff9, 0x0001, 0x0000, 0x0000, 0xff7e, + 0xff7e, 0xff7e, + /* 0x0400 .. 0x04ff */ + 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, + 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x000f, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + /* 0x0500 .. 0x05ff */ + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x10a0 .. 0x10ff */ + 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, + 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, + 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, + 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, + 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x1c60, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1e00 .. 0x1eff */ + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1f07 .. 0x1fff */ + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000, 0xfff8, 0x0000, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, 0xfff8, + 0xfff8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xffb6, 0xffb6, 0xfff7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xffaa, 0xffaa, 0xffaa, 0xffaa, 0xfff7, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xff9c, 0xff9c, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xfff8, 0xfff8, 0xff90, 0xff90, 0xfff9, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xff80, 0xff80, 0xff82, 0xff82, 0xfff7, 0x0000, 0x0000, + 0x0000, + /* 0x2103 .. 0x21ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xe2a3, 0x0000, 0x0000, 0x0000, 0xdf41, + 0xdfba, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001c, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x247c .. 0x24ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, + 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, + 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a, + 0x001a, 0x001a, 0x001a, 0x001a, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x2c00 .. 0x2cff */ + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0000, 0xd609, 0xf11a, 0xd619, 0x0000, 0x0000, 0x0001, + 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, 0x0001, 0x0000, + 0x0001, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xff1d .. 0xffff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, + 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000 +}; +const WCHAR wine_casemap_upper[3582] = +{ + /* index */ + 0x019f, 0x029f, 0x039f, 0x045a, 0x0556, 0x0656, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x06dd, 0x07dc, 0x08dc, + 0x0100, 0x09d0, 0x0100, 0x0100, 0x0a55, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0b3f, 0x0c3f, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0cfe, + /* defaults */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0061 .. 0x00ff */ + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x02e7, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0x0000, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0x0079, + /* 0x0100 .. 0x01ff */ + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xff18, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xfed4, + 0x00c3, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0061, 0x0000, 0x0000, + 0x0000, 0xffff, 0x00a3, 0x0000, 0x0000, 0x0000, 0x0082, 0x0000, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0038, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xfffe, 0x0000, + 0xffff, 0xfffe, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0xffb1, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0x0000, 0xffff, 0xfffe, 0x0000, 0xffff, 0x0000, 0x0000, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + /* 0x0200 .. 0x02ff */ + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0x0000, 0x0000, 0xff2e, 0xff32, 0x0000, 0xff33, 0xff33, + 0x0000, 0xff36, 0x0000, 0xff35, 0x0000, 0x0000, 0x0000, 0x0000, + 0xff33, 0x0000, 0x0000, 0xff31, 0x0000, 0x0000, 0x0000, 0x0000, + 0xff2f, 0xff2d, 0x0000, 0x29f7, 0x0000, 0x0000, 0x0000, 0xff2d, + 0x0000, 0x0000, 0xff2b, 0x0000, 0x0000, 0xff2a, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x29e7, 0x0000, 0x0000, + 0xff26, 0x0000, 0x0000, 0xff26, 0x0000, 0x0000, 0x0000, 0x0000, + 0xff26, 0xffbb, 0xff27, 0xff27, 0xffb9, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xff25, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0345 .. 0x03ff */ + 0x0054, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0082, 0x0082, + 0x0082, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffda, + 0xffdb, 0xffdb, 0xffdb, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe1, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffc0, + 0xffc1, 0xffc1, 0x0000, 0xffc2, 0xffc7, 0x0000, 0x0000, 0x0000, + 0xffd1, 0xffca, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0xffaa, 0xffb0, 0x0007, 0x0000, 0x0000, + 0xffa0, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, + 0x0000, 0x0000, 0x0000, + /* 0x0404 .. 0x04ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, + 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0xffb0, + 0xffb0, 0xffb0, 0xffb0, 0xffb0, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0xfff1, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, + /* 0x0500 .. 0x05ff */ + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1d79 .. 0x1dff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0ee6, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1e01 .. 0x1eff */ + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xffc5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1f00 .. 0x1fff */ + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0008, 0x0000, 0x0008, 0x0000, 0x0008, 0x0000, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x004a, 0x004a, 0x0056, 0x0056, 0x0056, 0x0056, 0x0064, 0x0064, + 0x0080, 0x0080, 0x0070, 0x0070, 0x007e, 0x007e, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xe3db, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0008, 0x0000, 0x0000, 0x0000, 0x0007, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x210c .. 0x21ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xffe4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xfff0, 0xfff0, 0xfff0, 0xfff0, + 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0xfff0, + 0xfff0, 0xfff0, 0xfff0, 0xfff0, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x247b .. 0x24ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffe6, 0xffe6, 0xffe6, + 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, + 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, + 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0xffe6, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x2c16 .. 0x2cff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, 0xffd0, + 0xffd0, 0x0000, 0x0000, 0xffff, 0x0000, 0x0000, 0x0000, 0xd5d5, + 0xd5d8, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, + 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0x2d00 .. 0x2dff */ + 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, + 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, + 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, + 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, + 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0xe3a0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xff41 .. 0xffff */ + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, 0xffe0, + 0xffe0, 0xffe0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; +const WCHAR wine_digitmap[4619] = +{ + /* index */ + 0x01d0, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x028a, 0x0384, + 0x0100, 0x044e, 0x053e, 0x062e, 0x071e, 0x080e, 0x08be, 0x099e, + 0x0a5e, 0x0100, 0x0100, 0x0af5, 0x0100, 0x0100, 0x0100, 0x0b67, + 0x0c57, 0x0d11, 0x0100, 0x0deb, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0e7b, 0x0100, 0x0100, 0x0100, 0x0f1b, 0x0100, 0x0100, 0x101b, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x110b, + /* defaults */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0030 .. 0x00ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xff80, 0xff80, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xff78, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0646 .. 0x06ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xf9d0, 0xf9d0, 0xf9d0, 0xf9d0, 0xf9d0, 0xf9d0, + 0xf9d0, 0xf9d0, 0xf9d0, 0xf9d0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xf940, 0xf940, 0xf940, 0xf940, 0xf940, 0xf940, + 0xf940, 0xf940, 0xf940, 0xf940, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0x0706 .. 0x07ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xf870, 0xf870, 0xf870, 0xf870, 0xf870, 0xf870, + 0xf870, 0xf870, 0xf870, 0xf870, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0x0936 .. 0x09ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xf6ca, 0xf6ca, 0xf6ca, 0xf6ca, 0xf6ca, 0xf6ca, 0xf6ca, 0xf6ca, + 0xf6ca, 0xf6ca, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xf64a, 0xf64a, 0xf64a, 0xf64a, 0xf64a, 0xf64a, 0xf64a, 0xf64a, + 0xf64a, 0xf64a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0x0a10 .. 0x0aff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf5ca, 0xf5ca, + 0xf5ca, 0xf5ca, 0xf5ca, 0xf5ca, 0xf5ca, 0xf5ca, 0xf5ca, 0xf5ca, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf54a, 0xf54a, + 0xf54a, 0xf54a, 0xf54a, 0xf54a, 0xf54a, 0xf54a, 0xf54a, 0xf54a, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0b10 .. 0x0bff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf4ca, 0xf4ca, + 0xf4ca, 0xf4ca, 0xf4ca, 0xf4ca, 0xf4ca, 0xf4ca, 0xf4ca, 0xf4ca, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf44a, 0xf44a, + 0xf44a, 0xf44a, 0xf44a, 0xf44a, 0xf44a, 0xf44a, 0xf44a, 0xf44a, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0c10 .. 0x0cff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf3ca, 0xf3ca, + 0xf3ca, 0xf3ca, 0xf3ca, 0xf3ca, 0xf3ca, 0xf3ca, 0xf3ca, 0xf3ca, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf34a, 0xf34a, + 0xf34a, 0xf34a, 0xf34a, 0xf34a, 0xf34a, 0xf34a, 0xf34a, 0xf34a, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0d10 .. 0x0dff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf2ca, 0xf2ca, + 0xf2ca, 0xf2ca, 0xf2ca, 0xf2ca, 0xf2ca, 0xf2ca, 0xf2ca, 0xf2ca, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0e50 .. 0x0eff */ + 0xf1e0, 0xf1e0, 0xf1e0, 0xf1e0, 0xf1e0, 0xf1e0, 0xf1e0, 0xf1e0, + 0xf1e0, 0xf1e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xf160, 0xf160, 0xf160, 0xf160, 0xf160, 0xf160, 0xf160, 0xf160, + 0xf160, 0xf160, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x0f20 .. 0x0fff */ + 0xf110, 0xf110, 0xf110, 0xf110, 0xf110, 0xf110, 0xf110, 0xf110, + 0xf110, 0xf110, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1040 .. 0x10ff */ + 0xeff0, 0xeff0, 0xeff0, 0xeff0, 0xeff0, 0xeff0, 0xeff0, 0xeff0, + 0xeff0, 0xeff0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1369 .. 0x13ff */ + 0xecc8, 0xecc8, 0xecc8, 0xecc8, 0xecc8, 0xecc8, 0xecc8, 0xecc8, + 0xecc8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x178e .. 0x17ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xe850, 0xe850, 0xe850, 0xe850, 0xe850, 0xe850, + 0xe850, 0xe850, 0xe850, 0xe850, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0x1810 .. 0x18ff */ + 0xe820, 0xe820, 0xe820, 0xe820, 0xe820, 0xe820, 0xe820, 0xe820, + 0xe820, 0xe820, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x1946 .. 0x19ff */ + 0xe6ea, 0xe6ea, 0xe6ea, 0xe6ea, 0xe6ea, 0xe6ea, 0xe6ea, 0xe6ea, + 0xe6ea, 0xe6ea, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xe660, 0xe660, 0xe660, 0xe660, 0xe660, 0xe660, + 0xe660, 0xe660, 0xe660, 0xe660, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0x1b26 .. 0x1bff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xe4e0, 0xe4e0, 0xe4e0, 0xe4e0, 0xe4e0, 0xe4e0, + 0xe4e0, 0xe4e0, 0xe4e0, 0xe4e0, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0x2070 .. 0x20ff */ + 0xdfc0, 0x0000, 0x0000, 0x0000, 0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0, + 0xdfc0, 0xdfc0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xdfb0, 0xdfb0, 0xdfb0, 0xdfb0, 0xdfb0, 0xdfb0, 0xdfb0, 0xdfb0, + 0xdfb0, 0xdfb0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0x2460 .. 0x24ff */ + 0xdbd1, 0xdbd1, 0xdbd1, 0xdbd1, 0xdbd1, 0xdbd1, 0xdbd1, 0xdbd1, + 0xdbd1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0xdbbd, 0xdbbd, 0xdbbd, 0xdbbd, + 0xdbbd, 0xdbbd, 0xdbbd, 0xdbbd, 0xdbbd, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xdba9, 0xdba9, 0xdba9, 0xdba9, 0xdba9, 0xdba9, 0xdba9, 0xdba9, + 0xdba9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xdb46, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xdb3c, 0xdb3c, 0xdb3c, + 0xdb3c, 0xdb3c, 0xdb3c, 0xdb3c, 0xdb3c, 0xdb3c, 0x0000, 0xdb31, + /* 0x2700 .. 0x27ff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd8bb, 0xd8bb, + 0xd8bb, 0xd8bb, 0xd8bb, 0xd8bb, 0xd8bb, 0xd8bb, 0xd8bb, 0x0000, + 0xd8b1, 0xd8b1, 0xd8b1, 0xd8b1, 0xd8b1, 0xd8b1, 0xd8b1, 0xd8b1, + 0xd8b1, 0x0000, 0xd8a7, 0xd8a7, 0xd8a7, 0xd8a7, 0xd8a7, 0xd8a7, + 0xd8a7, 0xd8a7, 0xd8a7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xff10 .. 0xffff */ + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; +const WCHAR wine_compatmap[1497] = +{ + /* index */ + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, + 0x0100, 0x0200, 0x0300, 0x0100, 0x0100, 0x0100, 0x03da, 0x04d9, + /* defaults */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xf900 .. 0xf9ff */ + 0x9348, 0x6df3, 0x95c8, 0x93c5, 0x75cd, 0x552d, 0x5adf, 0xa695, + 0xa694, 0x6048, 0x98c7, 0x5c7c, 0x603c, 0x68e9, 0x7d5b, 0x8676, + 0x8d2f, 0x8ea9, 0x8fe6, 0x977c, 0x70ee, 0x7406, 0x77c3, 0x7ac7, + 0x8b25, 0x9851, 0xa0d7, 0x5567, 0x5a59, 0x71e7, 0x78fd, 0x8d0e, + 0xa4fe, 0x642f, 0x76c9, 0x8caa, 0x9040, 0x69a4, 0x88b2, 0x8ef8, + 0x65a2, 0x6dee, 0x7440, 0x79d1, 0x97a2, 0x5659, 0x5889, 0x59af, + 0x6b94, 0x71a2, 0x78de, 0x7db4, 0x86cd, 0x8cd1, 0x8d26, 0x94b8, + 0x9dfa, 0xa236, 0xa4c0, 0x7f51, 0x8043, 0x8463, 0x8a8b, 0x99c5, + 0xa53f, 0x9195, 0x5f9d, 0x65c1, 0x831c, 0x8739, 0x791c, 0x7f83, + 0x937a, 0x9dae, 0x5f8e, 0x6317, 0x70c7, 0x748d, 0x75c1, 0x83e0, + 0x84e7, 0x9cfa, 0x5980, 0x8738, 0x5888, 0x5877, 0x80c6, 0x8467, + 0x8a99, 0x9d1c, 0x9226, 0x6974, 0x70a6, 0x91a1, 0x54db, 0x6288, + 0x66b2, 0x7a26, 0x7c0e, 0x59b4, 0x7f97, 0x565a, 0x6643, 0x54a6, + 0x7364, 0x6c0f, 0x83b8, 0x5a58, 0x5ef2, 0x7d94, 0x8adb, 0x913b, + 0x724a, 0x963f, 0x7316, 0x698b, 0x8971, 0x6a2b, 0x7bef, 0x5537, + 0x57f1, 0x5850, 0x6f07, 0x836c, 0x88f3, 0x9155, 0x9851, 0x5976, + 0x5ac2, 0x5ff2, 0x656a, 0x6c42, 0x767a, 0x7fa5, 0x9c27, 0xa0e3, + 0xa50f, 0xa545, 0x5911, 0x6d3b, 0x71eb, 0x95d5, 0x64e6, 0x6801, + 0x6870, 0x6b09, 0x7591, 0x77b6, 0x7af5, 0x8035, 0x845e, 0x86d8, + 0x958e, 0x8b55, 0x9689, 0x99af, 0x587b, 0x5906, 0x5b1f, 0x7729, + 0x8f22, 0x9109, 0x6527, 0x6652, 0x69d7, 0x7209, 0x8298, 0x79ce, + 0x553c, 0x5d50, 0x623d, 0x640f, 0x6670, 0x7a05, 0x7abb, 0x85eb, + 0x8696, 0x9883, 0x9d44, 0x9d95, 0x9e64, 0x55d6, 0x7ff8, 0x97fd, + 0x9d00, 0x6728, 0x54cc, 0x571f, 0x6232, 0x6282, 0x6bdb, 0x7043, + 0x780e, 0x7c81, 0x8b3a, 0x96b9, 0xa5c9, 0x6cc3, 0x9c68, 0x58c2, + 0x6db3, 0x6e2a, 0x7377, 0x74d1, 0x7a3d, 0x7b8c, 0x7e9d, 0x8341, + 0x9e8e, 0x579c, 0x685c, 0x9ca5, 0x5657, 0x6344, 0x7414, 0x9553, + 0x65b3, 0x676b, 0x6e3d, 0x79ac, 0x9caa, 0x584c, 0x5a31, 0x6286, + 0x6c33, 0x6d6d, 0x6ec6, 0x7302, 0x7a22, 0x7bfd, 0x8593, 0x8ee8, + 0x8ef9, 0x97e3, 0x9cf8, 0x5954, 0x74ce, 0x5a30, 0x77e2, 0x7aa9, + 0x8c0a, 0x9cb2, 0xa265, 0xa4ac, 0x6da3, 0x73d6, 0x87f2, 0x80d4, + 0x8128, 0x8299, 0x78c6, 0x769e, 0x915c, 0x54c3, 0x8938, 0x583b, + /* 0xfa00 .. 0xfaff */ + 0x5807, 0x64a5, 0x68d1, 0x82d3, 0x6181, 0x7319, 0x6cae, 0x9534, + 0x8e44, 0x9c44, 0x8f81, 0x64c8, 0x5734, 0x5bb3, 0x0000, 0x0000, + 0x5e4a, 0x0000, 0x6c62, 0x0000, 0x0000, 0x57c9, 0x7914, 0x7cb3, + 0x7f24, 0x7f45, 0x7f4b, 0x7f74, 0x9d3a, 0x82a1, 0x859f, 0x0000, + 0x8bf2, 0x0000, 0x90d6, 0x0000, 0x0000, 0x9613, 0x96d7, 0x0000, + 0x0000, 0x0000, 0x9ec5, 0x9ed1, 0x9efc, 0xa387, 0x0000, 0x0000, + 0x557e, 0x56b6, 0x571b, 0x5896, 0x58b0, 0x591c, 0x5b67, 0x5bcf, + 0x5c30, 0x5e07, 0x5e6e, 0x6229, 0x6232, 0x6657, 0x672a, 0x674f, + 0x67b2, 0x6b0e, 0x6ba0, 0x6c4e, 0x6e41, 0x7332, 0x73d4, 0x74db, + 0x7726, 0x77e2, 0x79d8, 0x7e46, 0x7ef2, 0x7efc, 0x7efa, 0x7f01, + 0x7f06, 0x7f0c, 0x7f3b, 0x7f3b, 0x7fec, 0x802c, 0x816a, 0x839d, + 0x83b1, 0x83e8, 0x8518, 0x85aa, 0x8791, 0x881c, 0x881b, 0x89f8, + 0x8eb0, 0x8f35, 0x909f, 0x90d6, 0x926f, 0x92a3, 0x9550, 0x95d1, + 0x9c7b, 0x9d96, 0x9dd1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x53b6, 0x5744, 0x56f6, 0x550d, 0x56d1, 0x570b, 0x5851, 0x5883, + 0x5b25, 0x5adc, 0x5b1f, 0x5b67, 0x5dde, 0x5e36, 0x5ec6, 0x5ed5, + 0x5fe2, 0x60a7, 0x6450, 0x6456, 0x64e5, 0x6528, 0x6652, 0x66c7, + 0x6680, 0x6705, 0x66d6, 0x6767, 0x67a8, 0x6937, 0x698e, 0x69c3, + 0x6ac6, 0x6be3, 0x6c85, 0x6c88, 0x6cc2, 0x70e4, 0x7124, 0x72aa, + 0x7443, 0x7432, 0x7488, 0x7583, 0x76d2, 0x7d0a, 0x7797, 0x7810, + 0x788a, 0x79d0, 0x7a64, 0x7a98, 0x7b79, 0x7b7a, 0x7c24, 0x7c34, + 0x7c4c, 0x7ca1, 0x7c96, 0x7e21, 0x8005, 0x8113, 0x81cd, 0x82ac, + 0x8344, 0x848d, 0x8553, 0x889f, 0x893b, 0x8cc4, 0x8e8b, 0x8ecf, + 0x8ede, 0x9006, 0x903e, 0x9010, 0x9045, 0x9041, 0x902f, 0x907a, + 0x90ca, 0x9247, 0x9476, 0x95af, 0x96d5, 0x97b1, 0x9bb6, 0x9c1c, + 0x9c8e, 0x9d12, 0x9d35, 0x9d40, 0x9d6f, 0xa045, 0xa4ce, 0x2d7b, + 0x2d74, 0x3904, 0x40cb, 0x4545, 0x4565, 0x5774, 0x61fa, 0x83fc, + 0xa46b, 0xa4b5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* 0xfe26 .. 0xfeff */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x21f5, 0x21e3, 0x21e1, 0x022c, 0x022b, 0x01f3, + 0x01f3, 0x0244, 0x0245, 0x31db, 0x31db, 0x31d5, 0x31d5, 0x31cd, + 0x31cd, 0x31c9, 0x31c9, 0x31cb, 0x31cb, 0x31cb, 0x31cb, 0x0000, + 0x0000, 0x0214, 0x0215, 0x21f5, 0x21f4, 0x21f3, 0x21f2, 0x0212, + 0x0211, 0x0210, 0x01dc, 0x31b0, 0x01dc, 0x0000, 0x01e7, 0x01e5, + 0x01e9, 0x01ca, 0x21bc, 0x01cf, 0x01cf, 0x0220, 0x0221, 0x31b7, + 0x31b7, 0x01c4, 0x01c6, 0x01c9, 0x01c9, 0x01ca, 0x01d8, 0x01d9, + 0x01d7, 0x0000, 0x01f4, 0x01bb, 0x01bb, 0x01d5, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x07a1, 0x07a1, 0x07a0, 0x07a0, 0x079f, 0x079f, + 0x079e, 0x079e, 0x079d, 0x079d, 0x079c, 0x079b, 0x079a, 0x079a, + 0x0799, 0x0799, 0x0798, 0x0797, 0x0796, 0x0796, 0x0795, 0x0795, + 0x0794, 0x0793, 0x0792, 0x0792, 0x0791, 0x0790, 0x078f, 0x078f, + 0x078e, 0x078d, 0x078c, 0x078c, 0x078b, 0x078a, 0x0789, 0x0789, + 0x0788, 0x0787, 0x0786, 0x0786, 0x0785, 0x0785, 0x0784, 0x0784, + 0x0783, 0x0783, 0x0782, 0x0782, 0x0781, 0x0780, 0x077f, 0x077f, + 0x077e, 0x077d, 0x077c, 0x077c, 0x077b, 0x077a, 0x0779, 0x0779, + 0x0778, 0x0777, 0x0776, 0x0776, 0x0775, 0x0774, 0x0773, 0x0773, + 0x0772, 0x0771, 0x0770, 0x0770, 0x076f, 0x076e, 0x076d, 0x076d, + 0x076c, 0x076b, 0x076a, 0x0770, 0x076f, 0x076e, 0x076d, 0x076d, + 0x076c, 0x076b, 0x076a, 0x076a, 0x0769, 0x0768, 0x0767, 0x0767, + 0x0766, 0x0765, 0x0764, 0x0764, 0x0763, 0x0762, 0x0761, 0x0761, + 0x0760, 0x075f, 0x075e, 0x075e, 0x075d, 0x075c, 0x075b, 0x075b, + 0x075a, 0x075a, 0x0759, 0x0759, 0x0758, 0x0757, 0x0756, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, + /* 0xff01 .. 0xffff */ + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, + 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x0120, 0x2a26, 0x2a26, + 0x30a1, 0x30aa, 0x30aa, 0x309d, 0x3196, 0x318c, 0x313a, 0x313b, + 0x313c, 0x313d, 0x313e, 0x3177, 0x3178, 0x3179, 0x3154, 0x318c, + 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3135, 0x3136, 0x3137, + 0x3138, 0x3139, 0x313a, 0x313b, 0x313c, 0x313d, 0x313e, 0x313f, + 0x3140, 0x3142, 0x3143, 0x3144, 0x3145, 0x3145, 0x3145, 0x3145, + 0x3145, 0x3145, 0x3147, 0x3149, 0x314b, 0x314d, 0x314f, 0x314f, + 0x314f, 0x314f, 0x314f, 0x3150, 0x3151, 0x3152, 0x3152, 0x3152, + 0x3152, 0x3152, 0x3152, 0x3153, 0x3156, 0x30fb, 0x30fb, 0x31c4, + 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, + 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, + 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, + 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x3190, 0x0000, 0x0000, + 0x0000, 0x318d, 0x318d, 0x318d, 0x318d, 0x318d, 0x318d, 0x0000, + 0x0000, 0x318b, 0x318b, 0x318b, 0x318b, 0x318b, 0x318b, 0x0000, + 0x0000, 0x3189, 0x3189, 0x3189, 0x3189, 0x3189, 0x3189, 0x0000, + 0x0000, 0x3187, 0x3187, 0x3187, 0x0000, 0x0000, 0x0000, 0x00c2, + 0x00c2, 0x00ca, 0x00cc, 0x00c2, 0x00c0, 0x20c3, 0x0000, 0x251a, + 0x21a7, 0x21a7, 0x21a7, 0x21a7, 0x25b3, 0x25dd, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; +#endif diff --git a/unifiedkernel/pub/error.c b/unifiedkernel/pub/error.c new file mode 100644 index 0000000..cede645 --- /dev/null +++ b/unifiedkernel/pub/error.c @@ -0,0 +1,188 @@ +/* + * error.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * translate Linux errno to Windows NTSTATUS + */ + +#include "win32.h" +#include "ntstatus.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#define MAX_BASE_ERROR 131 + +static NTSTATUS error_table_base[MAX_BASE_ERROR] = { + STATUS_ACCESS_DENIED, /* EPERM 1 Operation not permitted */ + STATUS_NO_SUCH_FILE, /* ENOENT 2 No such file or directory */ + STATUS_ACCESS_DENIED, /* ESRCH 3 No such process */ + STATUS_UNSUCCESSFUL, /* EINTR 4 Interrupted system call */ + STATUS_ACCESS_VIOLATION, /* EIO 5 I/O error */ + STATUS_NO_SUCH_DEVICE, /* ENXIO 6 No such device or address */ + STATUS_UNSUCCESSFUL, /* E2BIG 7 Argument list too long */ + STATUS_UNSUCCESSFUL, /* ENOEXEC 8 Exec format error */ + STATUS_INVALID_HANDLE, /* EBADF 9 Bad file number */ + STATUS_UNSUCCESSFUL, /* ECHILD 10 No child processes */ + STATUS_SHARING_VIOLATION, /* EAGAIN 11 Try again */ + STATUS_NO_MEMORY, /* ENOMEM 12 Out of memory */ + STATUS_ACCESS_DENIED, /* EACCES 13 Permission denied */ + STATUS_INVALID_ADDRESS, /* EFAULT 14 Bad address */ + STATUS_UNSUCCESSFUL, /* ENOTBLK 15 Block device required */ + STATUS_DEVICE_BUSY, /* EBUSY 16 Device or resource busy */ + STATUS_OBJECT_NAME_COLLISION, /* EEXIST 17 File exists */ + STATUS_UNSUCCESSFUL, /* EXDEV 18 Cross-device link */ + STATUS_NO_SUCH_DEVICE, /* ENODEV 19 No such device */ + STATUS_NOT_A_DIRECTORY, /* ENOTDIR 20 Not a directory */ + STATUS_FILE_IS_A_DIRECTORY, /* EISDIR 21 Is a directory */ + STATUS_INVALID_PARAMETER, /* EINVAL 22 Invalid argument */ + STATUS_UNSUCCESSFUL, /* ENFILE 23 File table overflow */ + STATUS_TOO_MANY_OPENED_FILES, /* EMFILE 24 Too many open files */ + STATUS_UNSUCCESSFUL, /* ENOTTY 25 Not a typewriter */ + STATUS_UNSUCCESSFUL, /* ETXTBSY 26 Text file busy */ + STATUS_SECTION_TOO_BIG, /* EFBIG 27 File too large */ + STATUS_DISK_FULL, /* ENOSPC 28 No space left on device */ + STATUS_ILLEGAL_FUNCTION, /* ESPIPE 29 Illegal seek */ + STATUS_MEDIA_WRITE_PROTECTED, /* EROFS 30 Read-only file system */ + STATUS_UNSUCCESSFUL, /* EMLINK 31 Too many links */ + STATUS_UNSUCCESSFUL, /* EPIPE 32 Broken pipe */ + STATUS_UNSUCCESSFUL, /* EDOM 33 Math argument out of domain of func */ + STATUS_UNSUCCESSFUL, /* ERANGE 34 Math result not representable */ + STATUS_UNSUCCESSFUL, /* EDEADLK/EDEADLOCK 35 Resource deadlock would occur */ + STATUS_UNSUCCESSFUL, /* ENAMETOOLONG 36 File name too long */ + STATUS_UNSUCCESSFUL, /* ENOLCK 37 No record locks available */ + STATUS_UNSUCCESSFUL, /* ENOSYS 38 Function not implemented */ + STATUS_DIRECTORY_NOT_EMPTY, /* ENOTEMPTY 39 Directory not empty */ + STATUS_UNSUCCESSFUL, /* ELOOP 40 Too many symbolic links encountered */ + STATUS_UNSUCCESSFUL, /* EWOULDBLOCK/EAGAIN Operation would block */ + STATUS_UNSUCCESSFUL, /* ENOMSG 42 No message of desired type */ + STATUS_UNSUCCESSFUL, /* EIDRM 43 Identifier removed */ + STATUS_UNSUCCESSFUL, /* ECHRNG 44 Channel number out of range */ + STATUS_UNSUCCESSFUL, /* EL2NSYNC 45 Level 2 not synchronized */ + STATUS_UNSUCCESSFUL, /* EL3HLT 46 Level 3 halted */ + STATUS_UNSUCCESSFUL, /* EL3RST 47 Level 3 reset */ + STATUS_UNSUCCESSFUL, /* ELNRNG 48 Link number out of range */ + STATUS_UNSUCCESSFUL, /* EUNATCH 49 Protocol driver not attached */ + STATUS_UNSUCCESSFUL, /* ENOCSI 50 No CSI structure available */ + STATUS_UNSUCCESSFUL, /* EL2HLT 51 Level 2 halted */ + STATUS_UNSUCCESSFUL, /* EBADE 52 Invalid exchange */ + STATUS_UNSUCCESSFUL, /* EBADR 53 Invalid request descriptor */ + STATUS_UNSUCCESSFUL, /* EXFULL 54 Exchange full */ + STATUS_UNSUCCESSFUL, /* ENOANO 55 No anode */ + STATUS_UNSUCCESSFUL, /* EBADRQC 56 Invalid request code */ + STATUS_UNSUCCESSFUL, /* EBADSLT 57 Invalid slot */ + STATUS_UNSUCCESSFUL, /* 58 not used */ + STATUS_UNSUCCESSFUL, /* EBFONT 59 Bad font file format */ + STATUS_UNSUCCESSFUL, /* ENOSTR 60 Device not a stream */ + STATUS_UNSUCCESSFUL, /* ENODATA 61 No data available */ + STATUS_UNSUCCESSFUL, /* ETIME 62 Timer expired */ + STATUS_UNSUCCESSFUL, /* ENOSR 63 Out of streams resources */ + STATUS_UNSUCCESSFUL, /* ENONET 64 Machine is not on the network */ + STATUS_UNSUCCESSFUL, /* ENOPKG 65 Package not installed */ + STATUS_UNSUCCESSFUL, /* EREMOTE 66 Object is remote */ + STATUS_UNSUCCESSFUL, /* ENOLINK 67 Link has been severed */ + STATUS_UNSUCCESSFUL, /* EADV 68 Advertise error */ + STATUS_UNSUCCESSFUL, /* ESRMNT 69 Srmount error */ + STATUS_UNSUCCESSFUL, /* ECOMM 70 Communication error on send */ + STATUS_UNSUCCESSFUL, /* EPROTO 71 Protocol error */ + STATUS_UNSUCCESSFUL, /* EMULTIHOP 72 Multihop attempted */ + STATUS_UNSUCCESSFUL, /* EDOTDOT 73 RFS specific error */ + STATUS_UNSUCCESSFUL, /* EBADMSG 74 Not a data message */ + STATUS_INVALID_PARAMETER, /* EOVERFLOW 75 Value too large for defined data type */ + STATUS_UNSUCCESSFUL, /* ENOTUNIQ 76 Name not unique on network */ + STATUS_UNSUCCESSFUL, /* EBADFD 77 File descriptor in bad state */ + STATUS_UNSUCCESSFUL, /* EREMCHG 78 Remote address changed */ + STATUS_UNSUCCESSFUL, /* ELIBACC 79 Can not access a needed shared library */ + STATUS_UNSUCCESSFUL, /* ELIBBAD 80 Accessing a corrupted shared library */ + STATUS_UNSUCCESSFUL, /* ELIBSCN 81 .lib section in a.out corrupted */ + STATUS_UNSUCCESSFUL, /* ELIBMAX 82 Attempting to link in too many shared libraries */ + STATUS_UNSUCCESSFUL, /* ELIBEXEC 83 Cannot exec a shared library directly */ + STATUS_UNSUCCESSFUL, /* EILSEQ 84 Illegal byte sequence */ + STATUS_UNSUCCESSFUL, /* ERESTART 85 Interrupted system call should be restarted */ + STATUS_UNSUCCESSFUL, /* ESTRPIPE 86 Streams pipe error */ + STATUS_UNSUCCESSFUL, /* EUSERS 87 Too many users */ + STATUS_UNSUCCESSFUL, /* ENOTSOCK 88 Socket operation on non-socket */ + STATUS_UNSUCCESSFUL, /* EDESTADDRREQ 89 Destination address required */ + STATUS_UNSUCCESSFUL, /* EMSGSIZE 90 Message too long */ + STATUS_UNSUCCESSFUL, /* EPROTOTYPE 91 Protocol wrong type for socket */ + STATUS_UNSUCCESSFUL, /* ENOPROTOOPT 92 Protocol not available */ + STATUS_UNSUCCESSFUL, /* EPROTONOSUPPORT 93 Protocol not supported */ + STATUS_UNSUCCESSFUL, /* ESOCKTNOSUPPORT 94 Socket type not supported */ + STATUS_UNSUCCESSFUL, /* EOPNOTSUPP 95 Operation not supported on transport endpoint */ + STATUS_UNSUCCESSFUL, /* EPFNOSUPPORT 96 Protocol family not supported */ + STATUS_UNSUCCESSFUL, /* EAFNOSUPPORT 97 Address family not supported by protocol */ + STATUS_UNSUCCESSFUL, /* EADDRINUSE 98 Address already in use */ + STATUS_UNSUCCESSFUL, /* EADDRNOTAVAIL 99 Cannot assign requested address */ + STATUS_UNSUCCESSFUL, /* ENETDOWN 100 Network is down */ + STATUS_UNSUCCESSFUL, /* ENETUNREACH 101 Network is unreachable */ + STATUS_UNSUCCESSFUL, /* ENETRESET 102 Network dropped connection because of reset */ + STATUS_UNSUCCESSFUL, /* ECONNABORTED 103 Software caused connection abort */ + STATUS_UNSUCCESSFUL, /* ECONNRESET 104 Connection reset by peer */ + STATUS_UNSUCCESSFUL, /* ENOBUFS 105 No buffer space available */ + STATUS_UNSUCCESSFUL, /* EISCONN 106 Transport endpoint is already connected */ + STATUS_UNSUCCESSFUL, /* ENOTCONN 107 Transport endpoint is not connected */ + STATUS_UNSUCCESSFUL, /* ESHUTDOWN 108 Cannot send after transport endpoint shutdown */ + STATUS_UNSUCCESSFUL, /* ETOOMANYREFS 109 Too many references: cannot splice */ + STATUS_UNSUCCESSFUL, /* ETIMEDOUT 110 Connection timed out */ + STATUS_UNSUCCESSFUL, /* ECONNREFUSED 111 Connection refused */ + STATUS_UNSUCCESSFUL, /* EHOSTDOWN 112 Host is down */ + STATUS_UNSUCCESSFUL, /* EHOSTUNREACH 113 No route to host */ + STATUS_UNSUCCESSFUL, /* EALREADY 114 Operation already in progress */ + STATUS_UNSUCCESSFUL, /* EINPROGRESS 115 Operation now in progress */ + STATUS_UNSUCCESSFUL, /* ESTALE 116 Stale NFS file handle */ + STATUS_UNSUCCESSFUL, /* EUCLEAN 117 Structure needs cleaning */ + STATUS_UNSUCCESSFUL, /* ENOTNAM 118 Not a XENIX named type file */ + STATUS_UNSUCCESSFUL, /* ENAVAIL 119 No XENIX semaphores available */ + STATUS_UNSUCCESSFUL, /* EISNAM 120 Is a named type file */ + STATUS_UNSUCCESSFUL, /* EREMOTEIO 121 Remote I/O error */ + STATUS_UNSUCCESSFUL, /* EDQUOT 122 Quota exceeded */ + STATUS_UNSUCCESSFUL, /* ENOMEDIUM 123 No medium found */ + STATUS_UNSUCCESSFUL, /* EMEDIUMTYPE 124 Wrong medium type */ + STATUS_UNSUCCESSFUL, /* ECANCELED 125 Operation Canceled */ + STATUS_UNSUCCESSFUL, /* ENOKEY 126 Required key not available */ + STATUS_UNSUCCESSFUL, /* EKEYEXPIRED 127 Key has expired */ + STATUS_UNSUCCESSFUL, /* EKEYREVOKED 128 Key has been revoked */ + STATUS_UNSUCCESSFUL, /* EKEYREJECTED 129 Key was rejected by service */ + STATUS_UNSUCCESSFUL, /* EOWNERDEAD 130 Owner died */ + STATUS_UNSUCCESSFUL /* ENOTRECOVERABLE 131 State not recoverable */ +}; + +#define MAX_EX_ERROR 5 +#define TABLE_EX_START 512 + +static NTSTATUS error_table_ex[MAX_EX_ERROR] = { + STATUS_UNSUCCESSFUL, /* ERESTARTSYS 512 */ + STATUS_UNSUCCESSFUL, /* ERESTARTNOINTR 513 */ + STATUS_UNSUCCESSFUL, /* ERESTARTNOHAND 514 restart if no handler.. */ + STATUS_UNSUCCESSFUL, /* ENOIOCTLCMD 515 No ioctl command */ + STATUS_UNSUCCESSFUL /* ERESTART_RESTARTBLOCK 516 restart by calling sys_restart_syscall */ +}; + + +NTSTATUS errno2ntstatus(int error) +{ + if (error >= TABLE_EX_START) { + error -= TABLE_EX_START; + return error >= MAX_EX_ERROR ? STATUS_UNSUCCESSFUL : error_table_ex[error]; + } else { + return error >= MAX_BASE_ERROR ? STATUS_UNSUCCESSFUL : error_table_base[error]; + } +} +#endif diff --git a/unifiedkernel/pub/info.c b/unifiedkernel/pub/info.c new file mode 100644 index 0000000..6866477 --- /dev/null +++ b/unifiedkernel/pub/info.c @@ -0,0 +1,195 @@ +/* + * info.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * info.c: + * Refered to Wine code + */ + +#include +#include "win32_process.h" +#include "wineserver/info.h" +#include "wineserver/uk_lib.h" +#include "wineserver/file.h" + +#ifdef CONFIG_UNIFIED_KERNEL +#define IS_HANDLE_VALID(handle) (((ULONG_PTR)handle & UK_HANDLE_FLAG) \ + && !((ULONG_PTR)handle & KERNEL_HANDLE_FLAG)) + +struct fd; +struct file *get_unix_file(struct fd *fd); + +static inline unsigned long get_handle_index(obj_handle_t handle) +{ + if (!IS_HANDLE_VALID(handle)) + return 0; + + return ((unsigned long)UK_HANDLE_TO_HANDLE(handle) >> 2); +} + +struct handle_info_table *alloc_handle_info_table(void) +{ + struct handle_info_table *table; + + table = (struct handle_info_table *)kmalloc(sizeof(struct handle_info_table), GFP_KERNEL); + if (!table) + return NULL; + + table->used = 0; + table->order = 0; + table->allocated = PAGE_SIZE; + table->handles = (struct handle_info *)__get_free_page(GFP_KERNEL); + if (!table->handles) { + kfree(table); + return NULL; + } + + memset(table->handles, 0, PAGE_SIZE); + + return table; +} + +int expand_handle_info_table(struct handle_info_table *table, unsigned long new_size) +{ + int order; + unsigned long new_alloc; + struct handle_info *new_handles; + + new_alloc = table->allocated; + order = table->order; + while (new_alloc < new_size) { + new_alloc <<= 1; + order++; + } + + new_handles = (struct handle_info *)__get_free_pages(GFP_KERNEL, order); + if (!new_handles) + return -ENOMEM; + + memcpy(new_handles, table->handles, table->allocated); + free_pages((unsigned long)table->handles, table->order); + + table->used = new_size; + table->order = order; + table->allocated = new_alloc; + table->handles = new_handles; + + return 0; +} + +void free_handle_info_table(struct handle_info_table *table) +{ + free_pages((unsigned long)table->handles, table->order); +} + +int set_handle_info(struct eprocess *process, obj_handle_t handle, void *obj) +{ + int unix_fd; + struct handle_info *info; + struct fd *fd; + struct file *unix_file; + unsigned long index; + struct handle_info_table *table; + + if (!process || !process->ep_handle_info_table) + return -EINVAL; + table = process->ep_handle_info_table; + + index = get_handle_index(handle); + if (!index) + return -EINVAL; + + if ((((index + 1) << 3) > table->allocated) + && expand_handle_info_table(table, (index + 1) << 3)) + return -ENOMEM; + + info = &table->handles[index]; + + fd = get_obj_fd(obj); + if (fd) { + unix_fd = get_unused_fd(); + if (unix_fd < 0) { + release_object(fd); + return unix_fd; + } + + unix_file = get_unix_file(fd); + get_file(unix_file); + fd_install(unix_fd, unix_file); + + release_object(fd); + + info->unix_fd = unix_fd + 1; + info->obj = obj; + } + + if (table->used <= (index << 3)) + table->used += sizeof(struct handle_info); + + return 0; +} + +struct handle_info *get_handle_info(struct eprocess *process, obj_handle_t handle) +{ + unsigned long index; + struct handle_info_table *table; + + if (!process || !process->ep_handle_info_table) + return NULL; + + index = get_handle_index(handle); + table = process->ep_handle_info_table; + + return index ? &table->handles[index] : NULL; +} + +void clear_handle_info(struct eprocess *process, obj_handle_t handle) +{ + unsigned long index; + struct handle_info_table *table; + struct handle_info *info; + + if (!process || !process->ep_handle_info_table) + return; + + index = get_handle_index(handle); + if (!index) + return; + + table = process->ep_handle_info_table; + info = &table->handles[index]; + + if (info->unix_fd) + uk_close(info->unix_fd - 1); + memset(info, 0, sizeof(struct handle_info)); + + if (((index + 1) << 3) >= table->used) + table->used -= sizeof(struct handle_info); +} + +int get_handle_fd(struct eprocess *process, obj_handle_t handle) +{ + struct handle_info *info = get_handle_info(process, handle); + + return info ? info->unix_fd - 1 : -1; +} +#endif diff --git a/unifiedkernel/pub/request.c b/unifiedkernel/pub/request.c new file mode 100644 index 0000000..3d73633 --- /dev/null +++ b/unifiedkernel/pub/request.c @@ -0,0 +1,129 @@ +/* + * request.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * request.c: + * Refered to Wine code + */ + +/* FIXME */ +#include "win32.h" +#include "thread.h" +#include "wineserver/request.h" +#include "wineserver/server.h" +#include "wineserver/uk_lib.h" + +#ifdef CONFIG_UNIFIED_KERNEL +DECL_HANDLER(new_process){ } +DECL_HANDLER(get_new_process_info){ } +DECL_HANDLER(new_thread){ } +DECL_HANDLER(get_startup_info){ } +DECL_HANDLER(init_process_done){ } +DECL_HANDLER(init_thread){ } +DECL_HANDLER(terminate_process){ } +DECL_HANDLER(terminate_thread){ } +DECL_HANDLER(get_process_info){ } +DECL_HANDLER(set_process_info){ } +DECL_HANDLER(get_thread_info){ } +DECL_HANDLER(set_thread_info){ } +DECL_HANDLER(suspend_thread){ } +DECL_HANDLER(resume_thread){ } +DECL_HANDLER(open_process){ } +DECL_HANDLER(open_thread){ } +DECL_HANDLER(queue_apc){ } +DECL_HANDLER(get_apc_result){ } + +DECL_HANDLER(get_dll_info){ } /* NtQueryInformationProcess() */ +DECL_HANDLER(load_dll){ } +DECL_HANDLER(unload_dll){ } + +DECL_HANDLER(close_handle){ } +DECL_HANDLER(set_handle_info){ } +DECL_HANDLER(dup_handle){ } +DECL_HANDLER(get_object_info){ } +DECL_HANDLER(allocate_locally_unique_id){ } + +DECL_HANDLER(select){ } +DECL_HANDLER(create_event){ } +DECL_HANDLER(event_op){ } +DECL_HANDLER(open_event){ } +DECL_HANDLER(create_mutex){ } +DECL_HANDLER(release_mutex){ } +DECL_HANDLER(open_mutex){ } +DECL_HANDLER(create_semaphore){ } +DECL_HANDLER(release_semaphore){ } +DECL_HANDLER(open_semaphore){ } + +#if 0 +DECL_HANDLER(create_snapshot){ } /* NtQuerySystemInformation(), snapshot.c */ +DECL_HANDLER(next_process){ } +DECL_HANDLER(next_thread){ } +DECL_HANDLER(next_module){ } +#endif +DECL_HANDLER(read_process_memory){ } /* NtReadVirtualMemory() */ +DECL_HANDLER(write_process_memory){ } + +DECL_HANDLER(queue_exception_event){ } +DECL_HANDLER(get_exception_status){ } + +DECL_HANDLER(output_debug_string){ } +DECL_HANDLER(wait_debug_event){ } +DECL_HANDLER(continue_debug_event){ } +DECL_HANDLER(debug_process){ } +DECL_HANDLER(debug_break){ } +DECL_HANDLER(set_debugger_kill_on_exit){ } + +#if 0 +DECL_HANDLER(create_timer){ } /* NtCreateTimer() */ +DECL_HANDLER(open_timer){ } /* NtOpenTimer() */ +DECL_HANDLER(set_timer){ } /* NtSetTimer() */ +DECL_HANDLER(cancel_timer){ } /* NtCancelTimer() */ +DECL_HANDLER(get_timer_info){ } /* NtQueryTimer() */ +#endif + +DECL_HANDLER(get_thread_context){ } /* NtGetContextThread(), usr1_handler() */ +DECL_HANDLER(set_thread_context){ } +DECL_HANDLER(get_selector_entry){ } /* NtQueryInformationThread() */ + +DECL_HANDLER(get_process_idle_event){ } + +#if 0 +DECL_HANDLER(get_serial_info){ } +DECL_HANDLER(set_serial_info){ } +#endif + +DECL_HANDLER(open_token){ } +DECL_HANDLER(adjust_token_privileges){ } +DECL_HANDLER(get_token_privileges){ } +DECL_HANDLER(check_token_privileges){ } +DECL_HANDLER(duplicate_token){ } +DECL_HANDLER(access_check){ } +DECL_HANDLER(get_token_user){ } +DECL_HANDLER(get_token_groups){ } +DECL_HANDLER(set_security_object){ } +DECL_HANDLER(get_token_impersonation_level){ } +DECL_HANDLER(get_token_statistics){ } +DECL_HANDLER(get_security_object){ } /* NtQuerySecurityObject() */ + +DECL_HANDLER(make_process_system){ } /* service_run_main_thread(), for wine_device server */ + +#endif diff --git a/unifiedkernel/pub/uk_lib.c b/unifiedkernel/pub/uk_lib.c new file mode 100644 index 0000000..5a44881 --- /dev/null +++ b/unifiedkernel/pub/uk_lib.c @@ -0,0 +1,1124 @@ +/* + * uk_lib.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * uk_lib.c: + * Refered to Wine code + */ + +#include "win32.h" +#include "wineserver/uk_lib.h" + +#ifdef CONFIG_UNIFIED_KERNEL +extern struct handle_table *kernel_handle_table; +extern NTSTATUS errno2ntstatus(int); + +void uk_perror(const char *s) +{ + kdebug(s); + /* FIXME */ + kdebug(": %d\n", errno); +} + +time_t time(void* v) +{ + return 0; +} + +void *malloc(size_t size) +{ + void *addr; + + if (size > MAXSIZE_ALLOC || !(addr = kmalloc(size, GFP_KERNEL))) { + kdebug("kmalloc size %x err, too large\n", size); + set_error(STATUS_NO_MEMORY); + return NULL; + } + + return addr; +} + +void *calloc(size_t nmemb, size_t size) +{ + void *addr; + size_t total = nmemb * size; + + if (total > MAXSIZE_ALLOC || !(addr = kmalloc(total, GFP_KERNEL))) { + kdebug("kmalloc size %x err, too large\n", total); + set_error(STATUS_NO_MEMORY); + return NULL; + } + + memset(addr, 0, total); + + return addr; +} + +void *mem_alloc(size_t size) +{ + void *addr = malloc(size); + + if (addr) + memset(addr, 0x55, size); + + return addr; +} + +void *memdup(const void *data, size_t len) +{ + void *ptr = malloc(len); + + if (ptr) + memcpy(ptr, data, len); + + return ptr; +} + +void free(void *p) +{ + if (p) + kfree(p); +} + +void *realloc(void *ptr, size_t new_size, size_t old_size) +{ + void *new_ptr; + + if (!new_size) { + free(ptr); + return ptr; + } + + if (!ptr) + return malloc(new_size); + + new_ptr = malloc(new_size); + if (new_ptr) { + memcpy(new_ptr, ptr, new_size > old_size ? old_size : new_size); + free(ptr); + } + + return new_ptr; +} + +WCHAR toupperW(WCHAR ch) +{ + extern const WCHAR wine_casemap_upper[]; + + return ch + wine_casemap_upper[wine_casemap_upper[ch >> 8] + (ch & 0xff)]; +} + +WCHAR tolowerW(WCHAR ch) +{ + extern const WCHAR wine_casemap_lower[]; + + return ch + wine_casemap_lower[wine_casemap_lower[ch >> 8] + (ch & 0xff)]; +} + +int memicmpW(const WCHAR *str1, const WCHAR *str2, int n) +{ + int ret = 0; + + for (; n > 0; n--, str1++, str2++) + if ((ret = tolowerW(*str1) - tolowerW(*str2))) + break; + + return ret; +} + +void no_flush(struct fd *fd, struct kevent **event) +{ + set_error(STATUS_OBJECT_TYPE_MISMATCH); + return; +} + +int no_add_queue(struct object *obj, struct wait_queue_entry *entry) +{ + set_error(STATUS_OBJECT_TYPE_MISMATCH); + return 0; +} + +int no_close_handle(struct object *o, struct w32process *p, obj_handle_t h) +{ + return 1; /* ok to close */ +} + +struct object *no_lookup_name(struct object *obj, struct unicode_str *name, unsigned int attributes) +{ + return NULL; +} + +struct fd *no_get_fd(struct object *obj) +{ + set_error(STATUS_OBJECT_TYPE_MISMATCH); + return NULL; +} + +struct object *no_open_file(struct object *o, unsigned int d , unsigned int i , unsigned int u) +{ + set_error(STATUS_OBJECT_TYPE_MISMATCH); + return NULL; +} + +int no_satisfied(struct object *obj, struct w32thread *thread) +{ + return 0; /* not abandoned */ +} + +int no_signal(struct object *obj, unsigned int access) +{ + set_error(STATUS_OBJECT_TYPE_MISMATCH); + return 0; +} + +unsigned int no_map_access(struct object *obj, unsigned int access) +{ + if (access & GENERIC_READ) + access |= STANDARD_RIGHTS_READ; + if (access & GENERIC_WRITE) + access |= STANDARD_RIGHTS_WRITE; + if (access & GENERIC_EXECUTE) + access |= STANDARD_RIGHTS_EXECUTE; + if (access & GENERIC_ALL) + access |= STANDARD_RIGHTS_ALL; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +/* object */ +#if 0 +POBJECT_ATTRIBUTES get_attr(HANDLE RootDirectory, const struct unicode_str *name, + unsigned int attr, void *securitydes, void *securityqofs) +{ + LONG Length; + BOOLEAN HaveName; + POBJECT_ATTRIBUTES Local = NULL; + + if(!(!RootDirectory && !name && !attr && !len && !securitydes && ! securityqofs)) { + HaveName = name? TRUE : FALSE; + + Length = sizeof(OBJECT_ATTRIBUTES) + sizeof(UNICODE_STRING); + Length += HaveName ? name->len: 0; + Local = (POBJECT_ATTRIBUTES)kmalloc(Length, GFP_KERNEL); + if (!Local) + return NULL; + + if (HaveName) { + Local->ObjectName = (PUNICODE_STRING)(Local + 1); + Local->ObjectName->Length = name->len; + Local->ObjectName->MaximumLength = name->len; + + Local->ObjectName->Buffer = (PWSTR)(Local->ObjectName + 1); + memcpy(Local->ObjectName->Buffer, name->str, name->len); + } + + Local->Length = sizeof(OBJECT_ATTRIBUTES); + Local->RootDirectory = RootDirectory; + Local->Attributes = attr; + Local->SecurityDescriptor = securitydes; + Local->SecurityQualityOfService = securityqofs; + } + return Local; + +} +#endif + +#define GET_ATTR(p, n, a, r, sd, sq) \ + do { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = (PUNICODE_STRING)n; \ + (p)->SecurityDescriptor = sd; \ + (p)->SecurityQualityOfService = sq; \ + } while (0) + +void dump_object_name(struct object *obj) +{ +} + +#if 0 +/* TODO: fd */ +void remove_timeout_user(struct timeout_user *user) +{ +} +#endif + +#if 0 +/* FIXME fd not implemented */ +struct fd *create_anonymous_fd(const struct fd_ops *fd_user_ops, + int unix_fd, struct object *user, unsigned int options) +{ + return NULL; +} +#endif + +#if 0 +void *get_fd_user(struct fd *fd) +{ + return NULL; +} +#endif + +#if 0 +int get_unix_fd(struct fd *fd) +{ + return 0; +} +#endif + +/* winstation */ +obj_handle_t find_inherited_handle(struct w32process *process, const struct object_ops *ops) +{ + return 0; +} + +/* console */ +void kill_console_processes(struct w32thread *renderer, int exit_code) +{ +} + + +void get_req_path(struct unicode_str *str, int skip_root) +{ + static const WCHAR root_name[] = { '\\','R','e','g','i','s','t','r','y','\\' }; + + str->str = get_req_data(); + str->len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR); + + if (skip_root && str->len >= sizeof(root_name) && + !memicmpW(str->str, root_name, sizeof(root_name) / sizeof(WCHAR))) { + str->str += sizeof(root_name) / sizeof(WCHAR); + str->len -= sizeof(root_name); + } +} + +int vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist) +{ + unsigned int written = 0; + const WCHAR *iter = format; + char bufa[256], fmtbufa[64], *fmta; + + while (*iter) { + while (*iter && *iter != '%') { + if (written++ >= len) + return -1; + *str++ = *iter++; + } + if (*iter == '%') { + if (iter[1] == '%') { + if (written++ >= len) + return -1; + *str++ = '%'; /* "%%"->'%' */ + iter += 2; + continue; + } + + fmta = fmtbufa; + *fmta++ = *iter++; + while (*iter == '0' || *iter == '+' || + *iter == '-' || *iter == ' ' || + *iter == '*' || *iter == '#') { + if (*iter == '*') { + char *buffiter = bufa; + int fieldlen = va_arg(valist, int); + sprintf(buffiter, "%d", fieldlen); + while (*buffiter) + *fmta++ = *buffiter++; + } + else + *fmta++ = *iter; + iter++; + } + + while (isdigitW(*iter)) + *fmta++ = *iter++; + + if (*iter == '.') { + *fmta++ = *iter++; + if (*iter == '*') { + char *buffiter = bufa; + int fieldlen = va_arg(valist, int); + sprintf(buffiter, "%d", fieldlen); + while (*buffiter) + *fmta++ = *buffiter++; + } + else + while (isdigitW(*iter)) + *fmta++ = *iter++; + } + if (*iter == 'h' || *iter == 'l') + *fmta++ = *iter++; + + switch (*iter) { + case 's': + { + static const WCHAR none[] = { '(','n','u','l','l',')',0 }; + const WCHAR *wstr = va_arg(valist, const WCHAR *); + const WCHAR *striter = wstr ? wstr : none; + while (*striter) { + if (written++ >= len) + return -1; + *str++ = *striter++; + } + iter++; + break; + } + + case 'c': + if (written++ >= len) + return -1; + *str++ = (WCHAR)va_arg(valist, int); + iter++; + break; + + default: + { + /* For non wc types, use system sprintf and append to wide char output */ + /* FIXME: for unrecognised types, should ignore % when printing */ + char *bufaiter = bufa; + if (*iter == 'p') + sprintf(bufaiter, "%08lX", va_arg(valist, long)); + else { + *fmta++ = *iter; + *fmta = '\0'; + if (*iter == 'a' || *iter == 'A' || + *iter == 'e' || *iter == 'E' || + *iter == 'f' || *iter == 'F' || + *iter == 'g' || *iter == 'G') + sprintf(bufaiter, fmtbufa, va_arg(valist, double)); + else { + sprintf(bufaiter, fmtbufa, va_arg(valist, void *)); + } + } + while (*bufaiter) { + if (written++ >= len) + return -1; + *str++ = *bufaiter++; + } + iter++; + break; + } + } + } + } + if (written >= len) + return -1; + *str++ = 0; + return (int)written; +} + +int vsprintfW(WCHAR *str, const WCHAR *format, va_list valist) +{ + return vsnprintfW(str, INT_MAX, format, valist); +} + +int snprintfW(WCHAR *str, size_t len, const WCHAR *format, ...) +{ + int retval; + va_list valist; + va_start(valist, format); + retval = vsnprintfW(str, len, format, valist); + va_end(valist); + return retval; +} + +int sprintfW(WCHAR *str, const WCHAR *format, ...) +{ + int retval; + va_list valist; + va_start(valist, format); + retval = vsnprintfW(str, INT_MAX, format, valist); + va_end(valist); + return retval; +} + + +/***********************************************************************************/ +/* file operation function begin . */ +#define PREPARE_KERNEL_CALL \ + mm_segment_t oldfs; \ +oldfs = get_fs(); \ +set_fs(KERNEL_DS); +#define END_KERNEL_CALL set_fs(oldfs); + +#define DEFAULT_FILE_MODE (0666) + +/* need PREPARE_KERNEL_CALL ? */ +long uk_close(unsigned int fd) +{ + long ret; + + PREPARE_KERNEL_CALL; + if (!current->files) /* in this case, uk_close is called after do_exit */ + ret = 0; + else + ret = sys_close(fd); + END_KERNEL_CALL; + + return ret; +} + +long uk_fclose(struct LIBC_FILE *fp) +{ + int ret; + if (fp) { + if (fp->buf) { + ret=uk_filp_write(fp->filp,(fp->buf+fp->bufpos-fp->validlen),fp->validlen); + free_pages((unsigned long)fp->buf,1); + fp->buf=NULL; + fp->validlen=0; + } + fput(fp->filp); + + kfree(fp); + return 0; + } + + return -1; +} + +ssize_t uk_read(unsigned int fd, void *buf, size_t size) +{ + ssize_t ret; + + PREPARE_KERNEL_CALL; + ret = sys_read(fd, buf, size); + END_KERNEL_CALL; + + return ret; +} + +ssize_t uk_filp_read(struct file *filp, void *buf, size_t size) +{ + ssize_t ret; + loff_t pos; + + PREPARE_KERNEL_CALL; + pos = filp->f_pos; + ret = vfs_read(filp, buf, size, &pos); + filp->f_pos = pos; + END_KERNEL_CALL; + + return ret; +} + +ssize_t uk_write(unsigned int fd, void *buf, size_t size) +{ + ssize_t ret; + + PREPARE_KERNEL_CALL; + ret = sys_write(fd, buf, size); + END_KERNEL_CALL; + + return ret; +} + +ssize_t uk_filp_write(struct file *filp, void *buf, size_t size) +{ + ssize_t ret; + loff_t pos; + + PREPARE_KERNEL_CALL; + pos = filp->f_pos; + ret = vfs_write(filp, buf, size, &pos); + filp->f_pos = pos; + END_KERNEL_CALL; + + return ret; +} + +ssize_t uk_fwrite(struct LIBC_FILE *fp, void *buf, size_t size) +{ + unsigned int ret=0; + size_t len=size; + int pos; + + if(fp->buf == NULL){ + fp->buf = (char *)__get_free_pages(GFP_KERNEL,1); + fp->buflen = PAGE_SIZE*2; + fp->validlen = 0; + fp->bufpos = 0; + if (!fp->buf) { + set_error(STATUS_NO_MEMORY); + uk_perror("no memory"); + return 0; + } + } + if(len < 0) + return 0; + pos = 0; + while (len > 0) { + if (fp->bufpos + len < PAGE_SIZE) { + memcpy(fp->buf + fp->bufpos, buf + pos, len); + fp->bufpos += len; + fp->validlen +=len ; + break; + } + + if (!fp->bufpos) { + ret = uk_filp_write(fp->filp, buf + pos, PAGE_SIZE); + if (ret != PAGE_SIZE) { + set_error(errno2ntstatus(-ret)); + return ret; + } + pos += PAGE_SIZE; + len -= PAGE_SIZE; + } else { + memcpy(fp->buf + fp->bufpos, buf + pos, PAGE_SIZE - fp->bufpos); + ret = uk_filp_write(fp->filp, fp->buf, PAGE_SIZE); + if (ret != PAGE_SIZE) { + set_error(errno2ntstatus(-ret)); + return ret; + } + pos += PAGE_SIZE - fp->bufpos; + len -= PAGE_SIZE - fp->bufpos; + fp->bufpos = 0; + fp->validlen = 0; + } + } + + + + return ret; +} + +long uk_dup(unsigned int fd) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_dup(fd); + END_KERNEL_CALL; + + return ret; +} + +int uk_fprintf(struct LIBC_FILE *fp , char *fmt, ...) +{ + int ret; + va_list args; + if(fp->buf==NULL){ + fp->buf = (char *)__get_free_pages(GFP_KERNEL,1); + fp->buflen=PAGE_SIZE*2; + fp->validlen=0; + fp->bufpos=0; + if (!fp->buf) { + set_error(STATUS_NO_MEMORY); + uk_perror("no memory"); + return 0; + } + } + + va_start(args, fmt); + ret = vsnprintf(fp->buf+fp->bufpos, 2*PAGE_SIZE-fp->bufpos, fmt, args); + va_end(args); + + if (ret <= 0) { + set_error(STATUS_INVALID_PARAMETER); + uk_perror("vsnprintf error"); + return ret; + } + fp->validlen+=(long)ret; + fp->bufpos+=(long)ret; + if(fp->validlen>=PAGE_SIZE){ + ret = uk_filp_write(fp->filp, fp->buf, PAGE_SIZE); + if (ret < 0){ + set_error(ret); + return ret; + } + fp->validlen -= ret; + memcpy(fp->buf,fp->buf+ret,fp->validlen); + fp->bufpos =fp->validlen ; + } + + + return ret; +} + +long uk_open(const char *filename, int flags, int mode) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_open(filename, flags, mode); + END_KERNEL_CALL; + return ret; +} + +long uk_fstat(unsigned int fd, struct stat *st) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_newfstat(fd, st); + END_KERNEL_CALL; + + return ret; +} + +long uk_lstat(char *filename, struct stat *st) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_newlstat(filename, st); + END_KERNEL_CALL; + + return ret; +} + +long uk_fstatfs(unsigned int fd, struct statfs *st) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_fstatfs(fd, st); + END_KERNEL_CALL; + + return ret; +} + +/* need PREPARE_KERNEL_CALL ? */ +long uk_ftruncate(unsigned int fd, long tr) +{ + int ret; + + PREPARE_KERNEL_CALL; + ret = sys_ftruncate(fd, tr); + END_KERNEL_CALL; + return ret; +} + +void uk_unlink(const char *filename) +{ + PREPARE_KERNEL_CALL; + sys_unlink(filename); + END_KERNEL_CALL; +} + +int uk_rename(const char *oldpath, const char *newpath) +{ + int ret; + + PREPARE_KERNEL_CALL; + ret = sys_rename(oldpath, newpath); + END_KERNEL_CALL; + + return ret; +} + +/* TODO */ +int uk_realpath(const char *path, char *real) +{ + return 0; +} + +struct LIBC_FILE *uk_filp_open(struct file *filp, char *readwrite) +{ + struct LIBC_FILE *ret; + + ret = (struct LIBC_FILE *)malloc(sizeof(struct LIBC_FILE)); + if (!ret) { + uk_perror("no memory!\n"); + return NULL; + } + + memset(ret, 0, sizeof(struct LIBC_FILE)); + ret->filp = filp; + ret->buf=NULL; + ret->bufpos=0; + + + return ret; +} + +struct LIBC_FILE *uk_fopen(const char *filename, char *readwrite) +{ + int flags = 0; + int seek_to_end = 0; + char *p = readwrite; + struct LIBC_FILE *ret; + + ret = (struct LIBC_FILE *)malloc(sizeof(struct LIBC_FILE)); + if (!ret) { + kdebug("no enough memory in uk_fopen!.\n"); + return NULL; + } + + while (*p) { + switch (*p) { + case 'r': + if (flags & O_WRONLY) + flags = (flags | O_RDWR) & (~O_WRONLY); + else + flags = O_RDONLY; + break; + case 'w': + if (flags & O_RDONLY) + flags = (flags | O_RDWR) & (~O_RDONLY); + else + flags = O_WRONLY; + flags |= O_CREAT | O_TRUNC; + break; + case '+': + if (flags & O_WRONLY) + flags = (flags | O_RDWR) & (~O_WRONLY); + else + flags = O_RDONLY; + break; + case 'a': + if (flags & O_RDONLY) + flags = (flags | O_RDWR) & (~O_RDONLY); + else + flags = O_WRONLY; + flags |= O_CREAT | O_TRUNC; + seek_to_end = 1; + break; + default: + kdebug("bad mode in kernel fopen\n"); + break; + } + p++; + } + + memset(ret, 0, sizeof(struct LIBC_FILE)); + ret->filp = filp_open(filename, flags, DEFAULT_FILE_MODE); + ret->buf=NULL; + ret->bufpos=0; + if (IS_ERR(ret->filp)) + goto out; + + if (seek_to_end) + ret->pos = vfs_llseek(ret->filp, 0, SEEK_END); + + return ret; + +out: + free(ret); + return NULL; +} + +void *uk_fgets(void *buf, int len, struct LIBC_FILE *fp) +{ + char *p; + ssize_t nread; + struct file *file; + + if (!len) + return NULL; + + file = fp->filp; + nread = kernel_read(file, file->f_pos, buf, (size_t)len - 1); + + if (nread <= 0) + return NULL; + + p = memchr(buf, '\n', nread); + if (!p) { + *((char *)buf + nread) = 0; + file->f_pos += nread; + } + else { + *++p = 0; + file->f_pos += ((void *)p - buf); + } + + return buf; +} + +ssize_t uk_pread(unsigned int fd, char *buf, size_t count, off_t pos) +{ + ssize_t ret; + + PREPARE_KERNEL_CALL; + ret = sys_pread64(fd, buf, count, (loff_t)pos); + END_KERNEL_CALL; + + return ret; +} + +ssize_t uk_filp_pread(struct file *filp, char *buf, size_t count, off_t pos) +{ + ssize_t ret; + loff_t lpos = (loff_t)pos; + + PREPARE_KERNEL_CALL; + ret = vfs_read(filp, buf, count, &lpos); + END_KERNEL_CALL; + + return ret; +} + +ssize_t uk_pwrite(unsigned int fd, const char *buf, size_t count, off_t pos) +{ + ssize_t ret; + + PREPARE_KERNEL_CALL; + ret = sys_pwrite64(fd, buf, count, (loff_t)pos); + END_KERNEL_CALL; + + return ret; +} + +ssize_t uk_filp_pwrite(struct file *filp, const char *buf, size_t count, off_t pos) +{ + ssize_t ret; + loff_t lpos = (loff_t)pos; + + PREPARE_KERNEL_CALL; + ret = vfs_write(filp, buf, count, &lpos); + END_KERNEL_CALL; + + return ret; +} + +long uk_readlink(const char *path, char *buf, size_t bufsiz) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_readlink(path, buf, bufsiz); + END_KERNEL_CALL; + + return ret; +} + +long uk_fcntl(unsigned int fd, int cmd, unsigned long arg) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_fcntl(fd, cmd, arg); + END_KERNEL_CALL; + + return ret; +} + +long uk_stat(char *filename, struct stat *st) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_newstat(filename, st); + END_KERNEL_CALL; + + return ret; +} + +long uk_poll(struct pollfd *fds, unsigned int nfds, long timeout_msecs) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_poll(fds, nfds, timeout_msecs); + END_KERNEL_CALL; + + return ret; +} + +long uk_socket(int family, int type, int protocol) +{ + return sys_socket(family, type, protocol); +} + +long uk_socketpair(int family, int type, int protocol, int *sockvec) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_socketpair(family, type, protocol, sockvec); + END_KERNEL_CALL; + + return ret; +} + +long uk_accept(int fd, struct sockaddr *peer_sockaddr, int *peer_addrlen) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_accept(fd, peer_sockaddr, peer_addrlen); + END_KERNEL_CALL; + + return ret; +} + +long uk_recv(int fd, void *buf, size_t size, unsigned flags) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_recvfrom(fd, buf, size, flags, NULL, NULL); + END_KERNEL_CALL; + + return ret; +} + +long uk_getsockopt(int fd, int level, int optname, void *optval, unsigned int *optlen) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_getsockopt(fd, level, optname, optval, optlen); + END_KERNEL_CALL; + + return ret; +} + +int uk_setsockopt(int fd, int level, int optname, const void *optval, int optlen) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_setsockopt(fd, level, optname, (char *)optval, optlen); + END_KERNEL_CALL; + + return ret; +} + +long uk_mkdir(const char *name, int mode) +{ + long ret; + + PREPARE_KERNEL_CALL; + ret = sys_mkdir(name, mode); + END_KERNEL_CALL; + + return ret; +} + +long uk_shutdown(int fd, int how) +{ + return sys_shutdown(fd, how); +} + +int uk_fsync(unsigned int fd) +{ + return sys_fsync(fd); +} + +long filp_truncate(struct file *file, loff_t length, int small) +{ + struct inode * inode; + struct dentry *dentry; + int error; + + error = -EINVAL; + if (length < 0) + goto out; + if (!file) + goto out; + + /* explicitly opened as large or we are on 64-bit box */ + if (file->f_flags & O_LARGEFILE) + small = 0; + + dentry = file->f_path.dentry; + inode = dentry->d_inode; + error = -EINVAL; + if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) + goto out; + + error = -EINVAL; + /* Cannot ftruncate over 2^31 bytes without large file support */ + if (small && length > MAX_NON_LFS) + goto out; + + error = -EPERM; + if (IS_APPEND(inode)) + goto out; + + error = locks_verify_truncate(inode, file, length); + if (!error) + error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file); + +out: + return error; +} + +/* initialize a list */ +void my_list_init(struct list_head *list) +{ + list->next = list->prev = list; +} + +/* check if a list is empty */ +int my_list_empty(const struct list_head *list) +{ + return list->next == list; +} + +/* get the last element */ +struct list_head *list_tail(const struct list_head *list) +{ + return list_prev(list, list); +} + +/* remove an element from its list */ +void list_remove(struct list_head *elem) +{ + elem->next->prev = elem->prev; + elem->prev->next = elem->next; +} + +/* add an element before the specified one */ +void list_add_before(struct list_head *elem, struct list_head *to_add) +{ + to_add->next = elem; + to_add->prev = elem->prev; + elem->prev->next = to_add; + elem->prev = to_add; +} + +/* add element at the tail of the list */ +void my_list_add_tail(struct list_head *list, struct list_head *elem) +{ + list_add_before(list, elem); +} + +timeout_t uk_start_time; + +/*********** 2 for time **************/ +/* uk_start_time set in w32_init */ +int get_tick_count(void) +{ + int rem; + return div_s64_rem((get_current_time() - uk_start_time), 10000, &rem); +} + +unsigned int get_current_time(void) +{ + struct timespec ts; + + getnstimeofday(&ts); + return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100 + TICKS_1601_TO_1970; +} + +void uk_wake_up( struct object *obj, int max ) +{ + if (!max) { + wait_test((struct dispatcher_header *)obj, IO_NO_INCREMENT); + } else { + /* TODO */ + } +} +#endif diff --git a/unifiedkernel/reg/Makefile b/unifiedkernel/reg/Makefile new file mode 100644 index 0000000..b52b17d --- /dev/null +++ b/unifiedkernel/reg/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for registry management +# + +REG_OBJS := reg.o + +$(MODULE)-objs += $(addprefix reg/, $(REG_OBJS)) diff --git a/unifiedkernel/reg/reg.c b/unifiedkernel/reg/reg.c new file mode 100644 index 0000000..c01d518 --- /dev/null +++ b/unifiedkernel/reg/reg.c @@ -0,0 +1,2275 @@ +/* + * reg.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * reg.c: + * Refered to Wine code + */ + +#include +#include +#include +#include +#include + +/* FIXME */ +#include "win32.h" +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" + +#include "unistr.h" +#include "event.h" +#include "wineserver/info.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "wineserver/request.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" +#include "wineserver/reg.h" + +#ifdef CONFIG_UNIFIED_KERNEL +static const SID world_sid = { SID_REVISION, 1, { SECURITY_WORLD_SID_AUTHORITY }, + { SECURITY_WORLD_RID } }; +static const SID local_sid = { SID_REVISION, 1, { SECURITY_LOCAL_SID_AUTHORITY }, + { SECURITY_LOCAL_RID } }; +static const SID interactive_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, + { SECURITY_INTERACTIVE_RID } }; +static const SID authenticated_user_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, + { SECURITY_AUTHENTICATED_USER_RID } }; +static const SID local_system_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, + { SECURITY_LOCAL_SYSTEM_RID } }; +static const PSID security_world_sid = (PSID)&world_sid; +static const PSID security_local_sid = (PSID)&local_sid; +const PSID security_interactive_sid = (PSID)&interactive_sid; +static const PSID security_authenticated_user_sid = (PSID)&authenticated_user_sid; +static const PSID security_local_system_sid = (PSID)&local_system_sid; + +static struct reg_key *root_key; + +struct task_struct* save_kernel_task=NULL; +EXPORT_SYMBOL(save_kernel_task); +extern int kthread_should_stop(void); +extern struct task_struct* kthread_create(int (*fn)(void* data),void* data, + const char namefmt[],...); +#define DEFAULT_FILE_MODE (0666) + +/* save a registry branch to a file */ + +static WCHAR key_type_name[] = {'K', 'e', 'y', 0}; +POBJECT_TYPE key_object_type = NULL; +EXPORT_SYMBOL(key_object_type); + +static GENERIC_MAPPING key_mapping = {KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS}; + +static int save_branch_count; +static struct save_branch_info save_branch_info[MAX_SAVE_BRANCH_INFO]; +struct reg_key *sys_key, *user_key, *udef_key; +void write_back_branches(void); +void write_registry(void); + +extern char* rootdir; +extern int unistr2charstr(PWSTR unistr, LPCSTR chstr); +static char debug_buf[1024]; +char *wcsdebug(WCHAR *wcs) +{ + int ret; + + if (!wcs) + return "null"; + ret = unistr2charstr((PWSTR)wcs, debug_buf); + if (ret > 0) { + debug_buf[ret] = 0; + return debug_buf; + } else + return "(invalid wchar string)"; +} + +static void delete_reg_key(PVOID key) +{ + kdebug("delete key %p\n", key); +} + + VOID +init_key_implement(VOID) +{ + OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; + UNICODE_STRING Name; + + memset(&ObjectTypeInitializer, 0, sizeof(ObjectTypeInitializer)); + init_unistr(&Name, (PWSTR)key_type_name); + ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); + ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(struct reg_key); + ObjectTypeInitializer.GenericMapping = key_mapping; + ObjectTypeInitializer.PoolType = PagedPool; + ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS; + ObjectTypeInitializer.DeleteProcedure = delete_reg_key; + /*FIXME*/ + ObjectTypeInitializer.ParseProcedure = NULL; + ObjectTypeInitializer.SecurityProcedure = NULL; + ObjectTypeInitializer.QueryNameProcedure = NULL; + ObjectTypeInitializer.UseDefaultObject = TRUE; + create_type_object(&ObjectTypeInitializer, &Name, &key_object_type); +} + +/* notify waiter and maybe delete the notification */ +void do_notification(struct reg_key *key, struct notify *notify, int del) +{ + if (notify->event) { + set_event(notify->event, EVENT_INCREMENT, FALSE); + release_object(notify->event); + notify->event = NULL; + } + if (del) { + list_del(¬ify->entry); + free(notify); + } +} + +/* go through all the notifications and send them if necessary */ +void check_notify(struct reg_key *key, unsigned int change, int not_subtree) +{ + struct list_head *ptr, *next; + + for (ptr = key->notify_list.next, next = ptr->next; + ptr != &key->notify_list; + ptr = next, next = ptr->next) { + struct notify *notify = list_entry(ptr, struct notify, entry); + + if ((not_subtree || notify->subtree) && (change & notify->filter)) + do_notification(key, notify, 0); + } +} + +/* parse an escaped string back into Unicode */ +/* return the number of chars read from the input, or -1 on output overflow */ +int parse_strW(WCHAR *buffer, data_size_t *len, const char *src, char endchar) +{ + WCHAR *dest = buffer; + WCHAR *end = buffer + *len / sizeof(WCHAR); + const char *p = src; + unsigned char ch; + + while (*p && *p != endchar && dest < end) { + if (*p == '\\') { + p++; + if (!*p) + break; + switch (*p) { + case 'a': *dest++ = '\a'; p++; continue; + case 'b': *dest++ = '\b'; p++; continue; + case 'e': *dest++ = '\e'; p++; continue; + case 'f': *dest++ = '\f'; p++; continue; + case 'n': *dest++ = '\n'; p++; continue; + case 'r': *dest++ = '\r'; p++; continue; + case 't': *dest++ = '\t'; p++; continue; + case 'v': *dest++ = '\v'; p++; continue; + case 'x': /* hex escape */ + p++; + if (!isxdigit(*p)) + *dest = 'x'; + else { + *dest = to_hex(*p++); + if (isxdigit(*p)) *dest = (*dest * 16) + to_hex(*p++); + if (isxdigit(*p)) *dest = (*dest * 16) + to_hex(*p++); + if (isxdigit(*p)) *dest = (*dest * 16) + to_hex(*p++); + } + dest++; + continue; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': /* octal escape */ + *dest = *p++ - '0'; + if (*p >= '0' && *p <= '7') *dest = (*dest * 8) + (*p++ - '0'); + if (*p >= '0' && *p <= '7') *dest = (*dest * 8) + (*p++ - '0'); + dest++; + continue; + } + /* unrecognized escape: fall through to normal char handling */ + } + + ch = *p++; + *dest++ = ch; + /* FIXME: */ +#if 0 + if (ch < 0x80) + *dest++ = ch; + else /* parse utf8 char */ { + int charlen = utf8_length[ch-0x80]; + unsigned int res = ch & utf8_mask[charlen]; + + switch(charlen) + { + case 3: + if ((ch = *p ^ 0x80) >= 0x40) + break; + res = (res << 6) | ch; + p++; + case 2: + if ((ch = *p ^ 0x80) >= 0x40) + break; + res = (res << 6) | ch; + p++; + case 1: + if ((ch = *p ^ 0x80) >= 0x40) + break; + res = (res << 6) | ch; + p++; + if (res < utf8_minval[charlen]) + break; + if (res > 0x10ffff) + break; + if (res <= 0xffff) + *dest++ = res; + else /* we need surrogates */ { + res -= 0x10000; + *dest++ = 0xd800 | (res >> 10); + if (dest < end) + *dest++ = 0xdc00 | (res & 0x3ff); + } + continue; + } + /* ignore invalid char */ + } +#endif + } + if (dest >= end) + return -1; /* overflow */ + *dest++ = 0; + if (!*p) + return -1; /* delimiter not found */ + *len = (dest - buffer) * sizeof(WCHAR); + return p + 1 - src; +} + +/* convert a data type tag to a value type */ +int get_data_type(const char *buffer, int *type, int *parse_type) +{ + struct data_type { const char *tag; int len; int type; int parse_type; }; + + static const struct data_type data_types[] = { + /* actual type */ /* type to assume for parsing */ + { "\"", 1, REG_SZ, REG_SZ }, + { "str:\"", 5, REG_SZ, REG_SZ }, + { "str(2):\"", 8, REG_EXPAND_SZ, REG_SZ }, + { "str(7):\"", 8, REG_MULTI_SZ, REG_SZ }, + { "hex:", 4, REG_BINARY, REG_BINARY }, + { "dword:", 6, REG_DWORD, REG_DWORD }, + { "hex(", 4, -1, REG_BINARY }, + { NULL, 0, 0, 0 } + }; + + const struct data_type *ptr; + char *end; + + for (ptr = data_types; ptr->tag; ptr++) { + if (memcmp(ptr->tag, buffer, ptr->len)) + continue; + *parse_type = ptr->parse_type; + if ((*type = ptr->type) != -1) + return ptr->len; + *type = (int)simple_strtoul(buffer + 4, &end, 16); + if ((end <= buffer) || memcmp(end, "):", 2)) + return 0; + return end + 2 - buffer; + } + return 0; +} + +/* mark a key and all its parents as dirty (modified) */ +void make_dirty(struct reg_key *key) +{ + while (key) { + if (key->flags & (KEY_DIRTY | KEY_VOLATILE)) + return; /* nothing to do */ + key->flags |= KEY_DIRTY; + key = key->parent; + } +} + +/* mark a key and all its subkeys as clean (not modified) */ +void make_clean(struct reg_key *key) +{ + int i; + + if (key->flags & KEY_VOLATILE) + return; + if (!(key->flags & KEY_DIRTY)) + return; + key->flags &= ~KEY_DIRTY; + for (i = 0; i <= key->last_subkey; i++) + make_clean(key->subkeys[i]); +} + +/* return the next token in a given path */ +/* token->str must point inside the path, or be NULL for the first call */ +struct unicode_str *get_path_token(const struct unicode_str *path, struct unicode_str *token) +{ + data_size_t i = 0, len = path->len / sizeof(WCHAR); + + if (!token->str) { /* first time */ + /* path cannot start with a backslash */ + if (len && path->str[0] == '\\') { + set_error(STATUS_OBJECT_PATH_INVALID); + return NULL; + } + } else { + i = token->str - path->str; + i += token->len / sizeof(WCHAR); + while (i < len && path->str[i] == '\\') + i++; + } + token->str = path->str + i; + while (i < len && path->str[i] != '\\') + i++; + token->len = (path->str + i - token->str) * sizeof(WCHAR); + + return token; +} + +/* find the named child of a given key and return its index */ +struct reg_key *find_subkey(const struct reg_key *key, const struct unicode_str *name, int *index) +{ + int i, min, max, res; + data_size_t len; + + min = 0; + max = key->last_subkey; + while (min <= max) { + i = (min + max) / 2; + len = min((int)key->subkeys[i]->namelen, (int)name->len); + res = memicmpW(key->subkeys[i]->name, name->str, len / sizeof(WCHAR)); + if (!res) + res = key->subkeys[i]->namelen - name->len; + if (!res) { + *index = i; + return key->subkeys[i]; + } + if (res > 0) + max = i - 1; + else + min = i + 1; + } + *index = min; /* this is where we should insert it */ + + /* not found */ + return NULL; +} + +/* try to grow the array of subkeys; return 1 if OK, 0 on error */ +int grow_subkeys(struct reg_key *key) +{ + struct reg_key **new_subkeys; + int nb_subkeys; + + if (key->nb_subkeys) { + nb_subkeys = key->nb_subkeys + (key->nb_subkeys / 2); /* grow by 50% */ + if (!(new_subkeys = realloc(key->subkeys, + nb_subkeys * sizeof(*new_subkeys), + key->nb_subkeys * sizeof(*new_subkeys)))) + return 0; + } else { + nb_subkeys = MIN_VALUES; + if (!(new_subkeys = mem_alloc(nb_subkeys * sizeof(*new_subkeys)))) + return 0; + } + key->subkeys = new_subkeys; + key->nb_subkeys = nb_subkeys; + + return 1; +} + +static struct reg_key *alloc_key(const struct unicode_str *name, time_t modif) +{ + NTSTATUS status; + struct reg_key *key = NULL; + UNICODE_STRING KeyName; + OBJECT_ATTRIBUTES obj_attr; + + KeyName.Length = (USHORT)name->len; + KeyName.MaximumLength = KeyName.Length + sizeof(WCHAR); + KeyName.Buffer = (PWSTR)name->str; + INIT_OBJECT_ATTR(&obj_attr, &KeyName, 0, NULL, NULL); + status = create_object(KernelMode, + key_object_type, + &obj_attr, + KernelMode, + 0, + sizeof(struct reg_key), + 0, + 0, + (PVOID *)&key); + + if (NT_SUCCESS(status)) { + key->name = NULL; + key->class = NULL; + key->namelen = name->len; + key->classlen = 0; + key->flags = 0; + key->last_subkey = -1; + key->nb_subkeys = 0; + key->subkeys = NULL; + key->nb_values = 0; + key->last_value = -1; + key->values[0] = key->values[1] = key->values[2] = key->values[3] = NULL; + key->modif = modif; + key->parent = NULL; + INIT_LIST_HEAD(&key->notify_list); + if (name->len && !(key->name = memdup(name->str, name->len))) { + release_object(key); + key = NULL; + } + } + + return key; +} + +/* allocate a subkey for a given key, and return its index */ +struct reg_key *alloc_subkey(struct reg_key *parent, const struct unicode_str *name, + int index, time_t modif) +{ + struct reg_key *key; + int i; + + if (name->len > MAX_NAME_LEN * sizeof(WCHAR)) { + set_error(STATUS_NAME_TOO_LONG); + return NULL; + } + if (parent->last_subkey + 1 == parent->nb_subkeys) /* need to grow the array */ + if (!grow_subkeys(parent)) + return NULL; + + if ((key = alloc_key(name, modif))) { + key->parent = parent; + for (i = ++parent->last_subkey; i > index; i--) + parent->subkeys[i] = parent->subkeys[i - 1]; + parent->subkeys[index] = key; + } + + return key; +} + +/* free a subkey of a given key */ +void free_subkey(struct reg_key *parent, int index) +{ + struct reg_key *key; + int i; + + key = parent->subkeys[index]; + for (i = index; i < parent->last_subkey; i++) + parent->subkeys[i] = parent->subkeys[i + 1]; + parent->last_subkey--; + key->flags |= KEY_DELETED; + key->parent = NULL; + release_object(key); /* TODO */ + +#if 0 + /* try to shrink the array */ + nb_subkeys = parent->nb_subkeys; + if (nb_subkeys > MIN_SUBKEYS && parent->last_subkey < nb_subkeys / 2) { + struct reg_key **new_subkeys; + nb_subkeys -= nb_subkeys / 3; /* shrink by 33% */ + if (nb_subkeys < MIN_SUBKEYS) nb_subkeys = MIN_SUBKEYS; + kdebug("free_subkeys %x\n", nb_subkeys); + if (!(new_subkeys = realloc(parent->subkeys, nb_subkeys * sizeof(*new_subkeys), + parent->nb_subkeys* sizeof(*new_subkeys)))) + return; + parent->subkeys = new_subkeys; + parent->nb_subkeys = nb_subkeys; + } +#endif +} + +/* create a subkey */ +struct reg_key *create_key(struct reg_key *key, const struct unicode_str *name, + const struct unicode_str *class, int flags, time_t modif, int *created) +{ + struct reg_key *base; + int index; + struct unicode_str token; + + /* we cannot create a subkey under a deleted key */ + if (key->flags & KEY_DELETED) { + set_error(STATUS_KEY_DELETED); + return NULL; + } + + if (!(flags & KEY_VOLATILE) && (key->flags & KEY_VOLATILE)) { + set_error(STATUS_CHILD_MUST_BE_VOLATILE); + return NULL; + } + + if (!modif) + modif = time(NULL); + + token.str = NULL; + if (!get_path_token(name, &token)) + return NULL; + *created = 0; + + while (token.len) { + struct reg_key *subkey; + + if (!(subkey = find_subkey(key, &token, &index))) + break; + key = subkey; + get_path_token(name, &token); + } + + if (!token.len) + goto done; + + /* create the remaining part */ + *created = 1; + if (flags & KEY_DIRTY) + make_dirty(key); + if (!(key = alloc_subkey(key, &token, index, modif))) + return NULL; + base = key; + + for (;;) { + key->flags |= flags; + get_path_token(name, &token); + if (!token.len) + break; + + /* we know the index is always 0 in a new key */ + if (!(key = alloc_subkey(key, &token, 0, modif))) { + free_subkey(base, index); + return NULL; + } + } + +done: + if (class && class->len) { + key->classlen = class->len; + free(key->class); + if (!(key->class = memdup(class->str, key->classlen))) + key->classlen = 0; + } + grab_object(key); + + return key; +} + +/* update key modification time */ +void touch_key(struct reg_key *key, unsigned int change) +{ + struct reg_key *k; + + key->modif = time(NULL); + make_dirty(key); + + /* do notifications */ + check_notify(key, change, 1); + for (k = key->parent; k; k = k->parent) + check_notify(k, change & ~REG_NOTIFY_CHANGE_LAST_SET, 0); +} + +/* delete a key and its values */ +int delete_key(struct reg_key *key, int recurse) +{ + int index; + struct reg_key *parent; + + /* must find parent and index */ + if (key == root_key) { + set_error(STATUS_ACCESS_DENIED); + return -1; + } + + if (!(parent = key->parent) || (key->flags & KEY_DELETED)) { + set_error(STATUS_KEY_DELETED); + return -1; + } + + while (recurse && (key->last_subkey >= 0)) + if (delete_key(key->subkeys[key->last_subkey], 1) == -1) + return -1; + + for (index = 0; index <= parent->last_subkey; index++) + if (parent->subkeys[index] == key) + break; + + /* we can only delete a key that has no subkeys */ + if (key->last_subkey >= 0) { + set_error(STATUS_ACCESS_DENIED); + return -1; + } + + free_subkey(parent, index); + touch_key(parent, REG_NOTIFY_CHANGE_NAME); + + set_error(STATUS_SUCCESS); + return 0; +} + +/* query information about a key or a subkey */ +void enum_key(const struct reg_key *key, int index, int info_class, + struct enum_key_reply *reply) +{ + int i; + data_size_t len, namelen, classlen; + data_size_t max_subkey = 0, max_class = 0; + data_size_t max_value = 0, max_data = 0; + char *data; + + if (index != -1) { /* -1 means use the specified key directly */ + if ((index < 0) || (index > key->last_subkey)) { + set_error(STATUS_NO_MORE_ENTRIES); + return; + } + key = key->subkeys[index]; + } + + namelen = key->namelen; + classlen = key->classlen; + + switch (info_class) { + case KeyBasicInformation: + classlen = 0; /* only return the name */ + /* fall through */ + case KeyNodeInformation: + reply->max_subkey = 0; + reply->max_class = 0; + reply->max_value = 0; + reply->max_data = 0; + break; + case KeyFullInformation: + for (i = 0; i <= key->last_subkey; i++) { + struct reg_key *subkey = key->subkeys[i]; + + len = subkey->namelen / sizeof(WCHAR); + if (len > max_subkey) + max_subkey = len; + len = subkey->classlen / sizeof(WCHAR); + if (len > max_class) + max_class = len; + } + for (i = 0; i <= key->last_value; i++) { + int m = i / VALUES_PER_BLOCK, n = i % VALUES_PER_BLOCK; + + len = key->values[m][n].namelen / sizeof(WCHAR); + if (len > max_value) + max_value = len; + len = key->values[m][n].len; + if (len > max_data) + max_data = len; + } + reply->max_subkey = max_subkey; + reply->max_class = max_class; + reply->max_value = max_value; + reply->max_data = max_data; + namelen = 0; /* only return the class */ + break; + default: + set_error(STATUS_INVALID_PARAMETER); + return; + } + reply->subkeys = key->last_subkey + 1; + reply->values = key->last_value + 1; + reply->modif = key->modif; + reply->total = namelen + classlen; + + len = min(reply->total, get_reply_max_size()); + if (len && (data = set_reply_data_size(len))) { + if (len > namelen) { + reply->namelen = namelen; + memcpy(data, key->name, namelen); + memcpy(data + namelen, key->class, len - namelen); + } else { + reply->namelen = len; + memcpy(data, key->name, len); + } + } + set_error(STATUS_SUCCESS); +} + +/* try to grow the array of values; return 1 if OK, 0 on error */ +int grow_values(struct reg_key *key) +{ + struct key_value *new_val; + int nb_values, m; + + nb_values = key->nb_values; + if (key->nb_values) { + if (key->nb_values < (VALUES_PER_BLOCK)) { + if (key->nb_values < (VALUES_PER_BLOCK / 2)) + nb_values = key->nb_values + (key->nb_values / 2); /* grow by 50% */ + else + nb_values = VALUES_PER_BLOCK; + + if (!(new_val = realloc(key->values[0], + nb_values * sizeof(*new_val), key->nb_values * sizeof(*new_val)))) { + kdebug("grow_values fails\n"); + return 0; + } + } else { + nb_values += VALUES_PER_BLOCK; + if (!(new_val = mem_alloc(VALUES_PER_BLOCK * sizeof(*new_val)))) + return 0; + } + } else { + nb_values = MIN_VALUES; + if (!(new_val = mem_alloc(nb_values * sizeof(*new_val)))) + return 0; + } + m = (nb_values - 1) / VALUES_PER_BLOCK; + key->values[m] = new_val; + key->nb_values = nb_values; + + return 1; +} + +/* find the named value of a given key and return its index in the array */ +struct key_value *find_value(const struct reg_key *key, const struct unicode_str *name, int *index) +{ + int i, min, max, res; + int m, n; + data_size_t len; + + min = 0; + max = key->last_value; + while (min <= max) { + i = (min + max) / 2; + m = i / VALUES_PER_BLOCK; + n = i % VALUES_PER_BLOCK; + len = min((int)key->values[m][n].namelen, (int)name->len); + res = memicmpW(key->values[m][n].name, name->str, len / sizeof(WCHAR)); + if (!res) + res = key->values[m][n].namelen - name->len; + if (!res) { + *index = i; + return &key->values[m][n]; + } + if (res > 0) + max = i - 1; + else + min = i + 1; + } + + *index = min; /* this is where we should insert it */ + return NULL; +} + +/* insert a new value; the index must have been returned by find_value */ +struct key_value *insert_value(struct reg_key *key, const struct unicode_str *name, int index) +{ + struct key_value *value; + WCHAR *new_name = NULL; + int i; + + if (name->len > MAX_VALUE_LEN * sizeof(WCHAR)) { + set_error(STATUS_NAME_TOO_LONG); + return NULL; + } + if (key->last_value + 1 == key->nb_values) { + if (!grow_values(key)) + return NULL; + } + if (name->len && !(new_name = memdup(name->str, name->len))) + return NULL; + for (i = ++key->last_value; i > index; i--) { + int m = i / VALUES_PER_BLOCK, n = i % VALUES_PER_BLOCK; + int j = (i - 1) / VALUES_PER_BLOCK, k = (i - 1) % VALUES_PER_BLOCK; + key->values[m][n] = key->values[j][k]; + } + value = &key->values[index / VALUES_PER_BLOCK][index % VALUES_PER_BLOCK]; + value->name = new_name; + value->namelen = name->len; + value->len = 0; + value->data = NULL; + return value; +} + +/* set a key value */ +void set_value(struct reg_key *key, const struct unicode_str *name, + int type, const void *data, data_size_t len) +{ + struct key_value *value; + void *ptr = NULL; + int index; + + if ((value = find_value(key, name, &index))) { + /* check if the new value is identical to the existing one */ + if (value->type == type && value->len == len && + value->data && !memcmp(value->data, data, len)) { + return; + } + } + + if (len && !(ptr = memdup(data, len))) + return; + + if (!value) { + if (!(value = insert_value(key, name, index))) { + free(ptr); + return; + } + } else + free(value->data); /* already existing, free previous data */ + + value->type = type; + value->len = len; + value->data = ptr; + touch_key(key, REG_NOTIFY_CHANGE_LAST_SET); + set_error(STATUS_SUCCESS); +} + +/* enumerate a key value */ +void enum_value(struct reg_key *key, int i, int info_class, struct enum_key_value_reply *reply) +{ + struct key_value *value; + + if (i < 0 || i > key->last_value) + set_error(STATUS_NO_MORE_ENTRIES); + else { + void *data; + data_size_t namelen, maxlen; + int m = i / VALUES_PER_BLOCK; + int n = i % VALUES_PER_BLOCK; + + value = &key->values[m][n]; + reply->type = value->type; + namelen = value->namelen; + + switch (info_class) { + case KeyValueBasicInformation: + reply->total = namelen; + break; + case KeyValueFullInformation: + reply->total = namelen + value->len; + break; + case KeyValuePartialInformation: + reply->total = value->len; + namelen = 0; + break; + default: + set_error(STATUS_INVALID_PARAMETER); + return; + } + + maxlen = min(reply->total, get_reply_max_size()); + if (maxlen && ((data = set_reply_data_size(maxlen)))) { + if (maxlen > namelen) { + reply->namelen = namelen; + memcpy(data, value->name, namelen); + memcpy((char *)data + namelen, value->data, maxlen - namelen); + } else { + reply->namelen = maxlen; + memcpy(data, value->name, maxlen); + } + } + set_error(STATUS_SUCCESS); + } +} + +/* get a key value */ +void get_value(struct reg_key *key, const struct unicode_str *name, int *type, data_size_t *len) +{ + struct key_value *value; + int index; + + if ((value = find_value(key, name, &index))) { + *type = value->type; + *len = value->len; + if (value->data) + set_reply_data(value->data, min(value->len, get_reply_max_size())); + set_error(STATUS_SUCCESS); + } else { + kdebug("get_value: not found\n"); + *type = -1; + set_error(STATUS_OBJECT_NAME_NOT_FOUND); + } +} + +/* delete a value */ +void delete_value(struct reg_key *key, const struct unicode_str *name) +{ + struct key_value *value; + int i, index; + + if (!(value = find_value(key, name, &index))) { + set_error(STATUS_OBJECT_NAME_NOT_FOUND); + return; + } + + free(value->name); + free(value->data); + for (i = index; i < key->last_value; i++) { + int m = i / VALUES_PER_BLOCK, n = i % VALUES_PER_BLOCK; + int j = (i + 1) / VALUES_PER_BLOCK, k = (i + 1) % VALUES_PER_BLOCK; + + key->values[m][n] = key->values[j][k]; + } + key->last_value--; + touch_key(key, REG_NOTIFY_CHANGE_LAST_SET); + set_error(STATUS_SUCCESS); + +#if 0 + nb_values = key->nb_values; + if (nb_values > MIN_VALUES) { + struct key_value *new_val; + int m, n; + + if (nb_values < VALUES_PER_BLOCK && key->last_value < (nb_values / 2)) { + nb_values -= (nb_values / 3); /* shrink by 33% */ + if (nb_values < MIN_VALUES) nb_values = MIN_VALUES; + m = (nb_values-1)/VALUES_PER_BLOCK; + if (!(new_val = realloc(key->values[m], nb_values * sizeof(*new_val), + key->nb_values* sizeof(*new_val)))) + return; + key->values[m] = new_val; + key->nb_values = nb_values; + } else { + m = (key->nb_values-1)/VALUES_PER_BLOCK; + n = (key->last_value)/VALUES_PER_BLOCK; + while (m > n) { + if (key->values[m]) { + kdebug("shrink by 1 block\n"); + free(key->values[m]); + key->values[m] = NULL; + key->nb_values -= VALUES_PER_BLOCK; + m--; + } + } + } + } +#endif +} + +/* read a line from the input file */ +int read_next_line(struct file_load_info *info) +{ + char *newbuf; + int newlen, pos = 0; + + info->line++; + for (;;) { + if (!uk_fgets(info->buffer + pos, info->len - pos, info->file)) + return (pos != 0); /* EOF */ + + pos = strlen(info->buffer); + + if (info->buffer[pos - 1] == '\n') { + /* got a full line */ + info->buffer[--pos] = 0; + if (pos > 0 && info->buffer[pos-1] == '\r') + info->buffer[pos - 1] = 0; + return 1; + } + + if (pos < info->len - 1) { + kdebug("line %d, pos %x, len %x\n", info->line, pos, info->len); + return 1; /* EOF but something was read */ + } + + /* need to enlarge the buffer */ + newlen = info->len + info->len / 2; + if (!(newbuf = realloc(info->buffer, newlen,pos))) { + return -1; + } + info->buffer = newbuf; + info->len = newlen; + } +} + +/* report an error while loading an input file */ +void file_read_error(const char *err, struct file_load_info *info) +{ + if (info->filename) + kdebug("%s:%d: %s '%s'\n", info->filename, info->line, err, info->buffer); + else + kdebug(":%d: %s '%s'\n", info->line, err, info->buffer); +} + +/* make sure the temp buffer holds enough space */ +int get_file_tmp_space(struct file_load_info *info, size_t size) +{ + WCHAR *tmp; + + if (info->tmplen >= size) + return 1; + + if (!(tmp = realloc(info->tmp, size ,info->tmplen))) + return 0; + + info->tmp = tmp; + info->tmplen = size; + + return 1; +} + +/* return the length (in path elements) of name that is part of the key name */ +/* for instance if key is USER\foo\bar and name is foo\bar\baz, return 2 */ +int get_prefix_len(struct reg_key *key, const char *name, struct file_load_info *info) +{ + WCHAR *p; + int res; + data_size_t len = strlen(name) * sizeof(WCHAR); + + if (!get_file_tmp_space(info, len)) + return 0; + + if ((res = parse_strW(info->tmp, &len, name, ']')) == -1) { + file_read_error("Malformed key", info); + return 0; + } + + for (p = info->tmp; *p; p++) + if (*p == '\\') + break; + len = (p - info->tmp) * sizeof(WCHAR); + for (res = 1; key != root_key; res++) { + if (len == key->namelen && !memicmpW(info->tmp, key->name, len / sizeof(WCHAR))) break; + key = key->parent; + } + if (key == root_key) + res = 0; /* no matching name */ + + return res; +} + +struct reg_key *load_key(struct reg_key *base, const char *buffer, int flags, + int prefix_len, struct file_load_info *info, int default_modif) +{ + WCHAR *p; + struct unicode_str name; + int res, modif; + data_size_t len = strlen(buffer) * sizeof(WCHAR); + + if (!get_file_tmp_space(info, len)) + return NULL; + + if ((res = parse_strW(info->tmp, &len, buffer, ']')) == -1) { + file_read_error("Malformed key", info); + return NULL; + } + if (sscanf(buffer + res, " %d", &modif) != 1) + modif = default_modif; + + p = info->tmp; + while (prefix_len && *p) { + if (*p++ == '\\') + prefix_len--; + } + + if (!*p) { + if (prefix_len > 1) { + file_read_error("Malformed key", info); + return NULL; + } + /* empty key name, return base key */ + return (struct reg_key *)grab_object(base); + } + + name.str = p; + name.len = len - (p - info->tmp + 1) * sizeof(WCHAR); + return create_key(base, &name, NULL, flags, modif, &res); +} + +/* parse a value name and create the corresponding value */ +struct key_value *parse_value_name(struct reg_key *key, const char *buffer, + data_size_t *len, struct file_load_info *info) +{ + struct key_value *value; + struct unicode_str name; + int index; + data_size_t maxlen = strlen(buffer) * sizeof(WCHAR); + + if (!get_file_tmp_space(info, maxlen)) + return NULL; + + name.str = info->tmp; + if (buffer[0] == '@') { + name.len = 0; + *len = 1; + } else { + int r = parse_strW(info->tmp, &maxlen, buffer + 1, '\"'); + if (r == -1) + goto error; + *len = r + 1; /* for initial quote */ + name.len = maxlen - sizeof(WCHAR); + } + + while (isspace(buffer[*len])) + (*len)++; + if (buffer[*len] != '=') + goto error; + (*len)++; + while (isspace(buffer[*len])) + (*len)++; + if (!(value = find_value(key, &name, &index))) + value = insert_value(key, &name, index); + return value; + +error: + file_read_error("Malformed value name", info); + return NULL; +} + +/* load and create a key from the input file */ +/* parse a comma-separated list of hex digits */ +int parse_hex(unsigned char *dest, data_size_t *len, const char *buffer) +{ + const char *p = buffer; + data_size_t count = 0; + + while (isxdigit(*p)) { + int val; + char buf[3]; + + memcpy(buf, p, 2); + buf[2] = 0; + sscanf(buf, "%x", &val); + if (count++ >= *len) + return -1; /* dest buffer overflow */ + *dest++ = (unsigned char)val; + p += 2; + if (*p == ',') p++; + } + *len = count; + return p - buffer; +} + +/* load a value from the input file */ +int load_value(struct reg_key *key, const char *buffer, struct file_load_info *info) +{ + DWORD dw; + void *ptr, *newptr; + int res, type, parse_type; + data_size_t maxlen, len; + struct key_value *value; + + if (!(value = parse_value_name(key, buffer, &len, info))) + return 0; + + if (!(res = get_data_type(buffer + len, &type, &parse_type))) + goto error; + buffer += len + res; + + switch (parse_type) { + case REG_SZ: + len = strlen(buffer) * sizeof(WCHAR); + if (!get_file_tmp_space(info, len)) + return 0; + if ((res = parse_strW(info->tmp, &len, buffer, '"')) == -1) + goto error; + ptr = info->tmp; + break; + case REG_DWORD: + dw = simple_strtoul(buffer, NULL, 16); + ptr = &dw; + len = sizeof(dw); + break; + case REG_BINARY: /* hex digits */ + len = 0; + for (;;) { + maxlen = 1 + strlen(buffer)/3; /* 3 chars for one hex byte */ + if (!get_file_tmp_space(info, len + maxlen)) + return 0; + if ((res = parse_hex((unsigned char *)info->tmp + len, &maxlen, buffer)) == -1) + goto error; + len += maxlen; + buffer += res; + while (isspace(*buffer)) + buffer++; + if (!*buffer) + break; + if (*buffer != '\\') + goto error; + if (read_next_line(info) != 1) + goto error; + buffer = info->buffer; + while (isspace(*buffer)) + buffer++; + } + ptr = info->tmp; + break; + default: + ptr = NULL; /* keep compiler quiet */ + break; + } + + if (!len) + newptr = NULL; + else if (!(newptr = memdup(ptr, len))) + return 0; + + free(value->data); + value->data = newptr; + value->len = len; + value->type = type; + make_dirty(key); + return 1; + +error: + file_read_error("Malformed value", info); + return 0; +} + +struct file_load_info info; + +void load_keys(struct reg_key *key, const char *filename, struct LIBC_FILE *fp, int prefix_len) +{ + struct reg_key *subkey = NULL; + char *p; + int default_modif = time(NULL); + int flags = (key->flags & KEY_VOLATILE) ? KEY_VOLATILE : KEY_DIRTY; + + ktrace("load_keys begin, file %s\n", filename); + + info.filename = filename; + info.file = fp; + info.len = 511; + info.tmplen = 511; + info.line = 0; + if (!(info.buffer = mem_alloc(info.len + 1))) + return; + if (!(info.tmp = mem_alloc(info.tmplen + 1))) { + free(info.buffer); + return; + } + + if ((read_next_line(&info) != 1) || strcmp(info.buffer, "WINE REGISTRY Version 2")) { + set_error(STATUS_NOT_REGISTRY_FILE); + kdebug("%s is not a valid registry file\n", filename); + goto done; + } + + while (read_next_line(&info) == 1) { + p = info.buffer; + while (*p && isspace(*p)) + p++; + switch (*p) { + case '[': /* new key */ + if (subkey) + release_object(subkey); + if (prefix_len == -1) + prefix_len = get_prefix_len(key, p + 1, &info); + if (!(subkey = load_key(key, p + 1, flags, prefix_len, &info, default_modif))) + file_read_error("Error creating key", &info); + break; + case '@': /* default value */ + case '"': /* value */ + if (subkey) + load_value(subkey, p, &info); + else + file_read_error("Value without key", &info); + break; + case '#': /* comment */ + case ';': /* comment */ + case 0: /* empty line */ + break; + default: + file_read_error("Unrecognized input", &info); + break; + } + } + +done: + ktrace("load_keys done, line %d\n", info.line); + if (subkey) + release_object(subkey); + + free(info.buffer); + free(info.tmp); +} + +/* load one of the initial registry files */ +void load_init_registry_from_file(const char *filename, struct reg_key *key) +{ + struct LIBC_FILE *fp; + struct file* filp; + + ktrace("load_init_registry_from_file file %s\n", filename); + + filp = filp_open(filename,O_RDONLY | O_CREAT ,DEFAULT_FILE_MODE); + if(IS_ERR(filp)){ + kdebug("filp_open error:%s\n",filename); + return; + } + + + + if ((fp = uk_filp_open(filp, "r"))) { + load_keys(key, filename, fp, 0); + uk_fclose(fp); + } + + if ((save_branch_info[save_branch_count].path = strdup(filename))) + save_branch_info[save_branch_count++].key = (struct reg_key *)grab_object(key); +} + +WCHAR *format_user_registry_path(const SID *sid, struct unicode_str *path) +{ + static const WCHAR prefixW[] = {'U','s','e','r','\\','S',0}; + static const WCHAR formatW[] = {'-','%','u',0}; + WCHAR buffer[7 + 10 + 10 + 10 * SID_MAX_SUB_AUTHORITIES]; + WCHAR *p = buffer; + unsigned int i; + + strcpyW(p, prefixW); + p += strlenW(prefixW); + p += sprintfW(p, formatW, sid->Revision); + p += sprintfW(p, formatW, MAKELONG(MAKEWORD(sid->IdentifierAuthority.Value[5], + sid->IdentifierAuthority.Value[4]), + MAKEWORD(sid->IdentifierAuthority.Value[3], + sid->IdentifierAuthority.Value[2]))); + for (i = 0; i < sid->SubAuthorityCount; i++) + p += sprintfW(p, formatW, sid->SubAuthority[i]); + + path->len = (p - buffer) * sizeof(WCHAR); + path->str = p = memdup(buffer, path->len); + return p; +} + +void free_registry(void) +{ + release_object(root_key); +} + +void kernel_init_registry(void) +{ + static const WCHAR HKLM[] = { 'M','a','c','h','i','n','e' }; + static const WCHAR HKU_default[] = { 'U','s','e','r','\\','.','D','e','f','a','u','l','t' }; + static const struct unicode_str root_name = { NULL, 0 }; + static const struct unicode_str HKLM_name = { HKLM, sizeof(HKLM) }; + static const struct unicode_str HKU_name = { HKU_default, sizeof(HKU_default) }; + + WCHAR *current_user_path = NULL; + struct unicode_str current_user_str; + int dummy, prefix_len; + + const char *config = rootdir; + char *p, *filename; + int ret; + + + ret = uk_mkdir(config,0777); + if(ret && ret != -EEXIST) + kdebug("sys_mkdir error\n"); + + init_key_implement(); + + prefix_len = strlen(config); + filename = (char *)malloc(prefix_len + 16); + memcpy(filename, config, prefix_len); + p = filename + prefix_len; + kdebug("filename %s\n", filename); + + /* create the root key */ + root_key = alloc_key(&root_name, time(NULL)); + /* FIXME: if (!root_key) */ + kdebug("rootkey %p\n", root_key); + + /* create sys_key */ + if (!(sys_key = create_key(root_key, &HKLM_name, NULL, KEY_DIRTY, time(NULL), &dummy))) + kdebug("could not create Machine registry key\n"); /* FIXME: */ + memcpy(p, "/system.reg", sizeof("/system.reg")); + load_init_registry_from_file(filename, sys_key); + release_object(sys_key); /* FIXME: */ + + /* create udef_key */ + if (!(udef_key = create_key(root_key, &HKU_name, NULL, KEY_DIRTY, time(NULL), &dummy))) + kdebug("could not create User\\.Default registry key\n"); /* FIXME: */ + memcpy(p, "/userdef.reg", sizeof("/userdef.reg")); + load_init_registry_from_file(filename, udef_key); + release_object(udef_key); /* FIXME: */ + + /* FIXME: match default user in token.c. should get from process token instead */ + current_user_path = format_user_registry_path(security_interactive_sid, ¤t_user_str); + if (!current_user_path || + !(user_key = create_key(root_key, ¤t_user_str, NULL, KEY_DIRTY, time(NULL), &dummy))) + kdebug("could not create HKEY_CURRENT_USER registry key\n"); + memcpy(p, "/user.reg", sizeof("/user.reg")); + load_init_registry_from_file(filename, user_key); + release_object(user_key); /* FIXME: */ + + save_kernel_task=kthread_create((void*)write_registry,NULL,"save_thread"); + if(!IS_ERR(save_kernel_task)) + wake_up_process(save_kernel_task); + + free(current_user_path); + free(filename); +} + +static struct reg_key *get_parent_key_obj(obj_handle_t hkey) +{ + if (!hkey) + return (struct reg_key *)grab_object(root_key); + + return (struct reg_key *)get_handle_obj(hkey, 0, key_object_type); +} + +static inline struct reg_key *get_key_obj(obj_handle_t hkey, unsigned int access) +{ + return (struct reg_key *)get_handle_obj(hkey, access, key_object_type); +} + +static struct notify *find_notify(struct reg_key *key, struct eprocess *process, obj_handle_t hkey) +{ + struct notify *notify; + + for (notify = list_entry((&key->notify_list)->next, struct notify, entry); + ¬ify->entry != &key->notify_list; + notify = list_entry(notify->entry.next, struct notify, entry)) { + if (notify->process == process && notify->hkey == hkey) + return notify; + } + + return NULL; +} + +/* open a subkey */ +struct reg_key *open_key(struct reg_key *key, const struct unicode_str *name) +{ + int index; + struct unicode_str token; + + token.str = NULL; + if (!get_path_token(name, &token)) + return NULL; + while (token.len) { + WCHAR *wcs = kmalloc(token.len + sizeof(WCHAR), GFP_KERNEL); + if (!wcs) { + set_error(STATUS_NO_MEMORY); + break; + } + memcpy(wcs, token.str, token.len); + wcs[token.len / sizeof(WCHAR)] = 0; + if (!(key = find_subkey(key, &token, &index))) { + set_error(STATUS_OBJECT_NAME_NOT_FOUND); + break; + } + get_path_token(name, &token); + } + + if (key) + grab_object(key); + + return key; +} + +/* dump a Unicode string with proper escaping */ +int dump_strW(const WCHAR *str, size_t len, struct LIBC_FILE *fp, const char escape[2]) +{ + static const char escapes[32] = ".......abtnvfr.............e...."; + char buffer[256]; + char *pos = buffer; + int count = 0; + + for (; len; str++, len--) { + if (pos > buffer + sizeof(buffer) - 8) { + uk_fwrite(fp, buffer, pos - buffer); + count += pos - buffer; + pos = buffer; + } + if (*str > 127) { /* hex escape */ + if (len > 1 && str[1] < 128 && isxdigit((char)str[1])) + pos += sprintf(pos, "\\x%04x", *str); + else + pos += sprintf(pos, "\\x%x", *str); + continue; + } + if (*str < 32) { /* octal or C escape */ + if (!*str && len == 1) + continue; /* do not output terminating NULL */ + if (escapes[*str] != '.') + pos += sprintf(pos, "\\%c", escapes[*str]); + else if (len > 1 && str[1] >= '0' && str[1] <= '7') + pos += sprintf(pos, "\\%03o", *str); + else + pos += sprintf(pos, "\\%o", *str); + continue; + } + if (*str == '\\' || *str == escape[0] || *str == escape[1]) + *pos++ = '\\'; + *pos++ = *str; + } + + uk_fwrite(fp, buffer, pos - buffer); + count += pos - buffer; + return count; +} + +/* dump the full path of a key */ +void dump_path(const struct reg_key *key, const struct reg_key *base, struct LIBC_FILE *fp) +{ + if (key->parent && key->parent != base) { + dump_path(key->parent, base, fp); + uk_fprintf(fp, "\\\\"); + } + dump_strW(key->name, key->namelen / sizeof(WCHAR), fp, "[]"); +} + +/* dump a value to a text file */ +void dump_value(const struct key_value *value, struct LIBC_FILE *fp) +{ + unsigned int i; + int count; + + if (value->namelen) { + uk_fputc('\"', fp); + count = 1 + dump_strW(value->name, value->namelen / sizeof(WCHAR), fp, "\"\""); + count += uk_fprintf(fp, "\"="); + } + else + count = uk_fprintf(fp, "@="); + + switch (value->type) { + case REG_SZ: + case REG_EXPAND_SZ: + case REG_MULTI_SZ: + if (value->type != REG_SZ) + uk_fprintf(fp, "str(%d):", value->type); + uk_fputc('\"', fp); + if (value->data) + dump_strW((WCHAR *)value->data, value->len / sizeof(WCHAR), fp, "\"\""); + uk_fputc('\"', fp); + break; + case REG_DWORD: + if (value->len == sizeof(DWORD)) { + DWORD dw; + memcpy(&dw, value->data, sizeof(DWORD)); + uk_fprintf(fp, "dword:%08x", dw); + break; + } + /* else fall through */ + default: + if (value->type == REG_BINARY) + count += uk_fprintf(fp, "hex:"); + else + count += uk_fprintf(fp, "hex(%x):", value->type); + for (i = 0; i < value->len; i++) { + count += uk_fprintf(fp, "%02x", *((unsigned char *)value->data + i)); + if (i < value->len-1) { + uk_fputc(',', fp); + if (++count > 76) { + uk_fprintf(fp, "\\\n "); + count = 2; + } + } + } + break; + } + uk_fputc('\n', fp); +} + + +/* save a registry and all its subkeys to a text file */ +static void save_subkeys(const struct reg_key *key, const struct reg_key *base,struct LIBC_FILE *fp) +{ + int i, m, n; + + if (key->flags & KEY_VOLATILE) + return; + + if ((key->last_value >= 0) || (key->last_subkey == -1)) { + uk_fprintf(fp, "\n["); + if (key != base) + dump_path(key, base, fp); + uk_fprintf(fp, "] %ld\n", (long)key->modif); + for (i = 0; i <= key->last_value; i++) { + m = i / VALUES_PER_BLOCK; + n = i % VALUES_PER_BLOCK; + dump_value(&key->values[m][n], fp); + } + } + + for (i = 0; i <= key->last_subkey; i++) + save_subkeys(key->subkeys[i], base, fp); +} + +unsigned int key_map_access(struct object *obj, unsigned int access) +{ + if (access & GENERIC_READ) + access |= KEY_READ; + if (access & GENERIC_WRITE) + access |= KEY_WRITE; + if (access & GENERIC_EXECUTE) + access |= KEY_EXECUTE; + if (access & GENERIC_ALL) + access |= KEY_ALL_ACCESS; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + +/* close the notification associated with a handle */ +int key_close_handle(struct object *obj, struct eprocess *process, obj_handle_t handle) +{ + struct reg_key *key = (struct reg_key *)obj; + struct notify *notify = find_notify(key, process, handle); + + if (notify) + do_notification(key, notify, 1); + return 1; /* ok to close */ +} + +void key_destroy(struct object *obj) +{ + int i; + struct list_head *ptr; + struct reg_key *key = (struct reg_key *)obj; + /*assert(obj->ops == &key_ops);*/ + + free(key->name); + free(key->class); + for (i = 0; i <= key->last_value; i++) { + int m = i / VALUES_PER_BLOCK, n = i % VALUES_PER_BLOCK; + if (key->values[m][n].name) + free(key->values[m][n].name); + if (key->values[m][n].data) + free(key->values[m][n].data); + } + if (key->values[3]) + free(key->values[3]); + if (key->values[2]) + free(key->values[2]); + if (key->values[1]) + free(key->values[1]); + if (key->values[0]) + free(key->values[0]); + for (i = 0; i <= key->last_subkey; i++) { + key->subkeys[i]->parent = NULL; + release_object(key->subkeys[i]); + } + free(key->subkeys); + /* unconditionally notify everything waiting on this key */ + while ((ptr = (((&key->notify_list)->next == &key->notify_list) ? (&key->notify_list)->next : NULL))) { + struct notify *notify = list_entry(ptr, struct notify, entry); + + do_notification(key, notify, 1); + } +} + +/* load a part of the registry from a file */ +void load_registry(struct reg_key *key, obj_handle_t handle) +{ + struct file *filp; + + ktrace("load_registry\n"); + /* file handle replaced to name */ + filp = fget(get_handle_fd(get_current_eprocess(), handle)); + if (filp) { + struct LIBC_FILE *fp = uk_filp_open(filp, "r"); + if (fp) { + load_keys(key, NULL, fp, -1); + uk_fclose(fp); + } else { + fput(filp); + } + } else + set_error(STATUS_INVALID_HANDLE); +} + +/* save a registry branch to a file */ +void save_all_subkeys(struct reg_key *key, struct LIBC_FILE *fp) +{ + uk_fprintf(fp, "WINE REGISTRY Version 2\n"); + uk_fprintf(fp, ";; All keys relative to "); + dump_path(key, NULL, fp); + uk_fprintf(fp, "\n"); + save_subkeys(key, key, fp); +} + +/* save a registry branch to a file handle */ +void save_registry(struct reg_key *key, obj_handle_t handle) +{ + struct file *filp; + + if (key->flags & KEY_DELETED) { + set_error(STATUS_KEY_DELETED); + return; + } + + /*FIXME*/ + filp = fget(get_handle_fd(get_current_eprocess(), handle)); + if (filp) { + struct LIBC_FILE *fp = uk_filp_open(filp, "w"); + if (fp) { + save_all_subkeys(key, fp); + uk_fclose(fp); + } else { + fput(filp); + } + } else + set_error(STATUS_INVALID_HANDLE); +} + +#if 0 +/* save a registry branch to a file */ +int save_branch(struct reg_key *key, const char *path) +{ + struct stat st; + char *p, *real, *tmp = NULL; + int fd, count = 0, ret = 0, by_symlink; + struct LIBC_FILE *fp; + + kdebug("save_branch reg_key %p, path %s\n", key,path); + + if (!(key->flags & KEY_DIRTY)) { + kdebug("clean, do nothing\n"); + return 1; + } + + /* get the real path */ + + by_symlink = (!lstat(path, &st) && S_ISLNK (st.st_mode)); + if (!(real = malloc(PATH_MAX))) + return 0; + if (!realpath(path, real) { + free(real); + real = NULL; + } + else path = real; + + /* test the file type */ + + if ((fd = open(path, O_WRONLY)) != -1) { + /* if file is not a regular file or has multiple links or is accessed + * via symbolic links, write directly into it; otherwise use a temp file */ + if (by_symlink || + (!fstat(fd, &st) && (!S_ISREG(st.st_mode) || st.st_nlink > 1))) { + ftruncate(fd, 0); + goto save; + } + uk_close(fd); + } + + + /* create a temp file in the same directory */ + + if (!(tmp = malloc(strlen(path) + 20))) + goto done; + strcpy(tmp, path); + if ((p = strrchr(tmp, '/'))) + p++; + else p = tmp; + for (;;) { + sprintf(p, "reg%lx%04x.tmp", (long) getpid(), count++); + if ((fd = uk_open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0666)) != -1) + break; + if (errno != EEXIST) + goto done; + uk_close(fd); + } + + /* now save to it */ + +save: + + if (!(fp = uk_fdopen(fd, "w"))) { + if (tmp) unlink(tmp); + uk_close(fd); + goto done; + } + +#if 0 + if (debug_level > 1) { + fprintf(stderr, "%s: ", path); + dump_operation(key, NULL, "saving"); + } +#endif + + save_all_subkeys(key, fp); + ret = !fclose(fp); + + if (tmp) { + /* if successfully written, rename to final name */ + if (ret) + ret = !rename(tmp, path); + if (!ret) + unlink(tmp); + } + +done: + free(tmp); + free(real); + if (ret) + make_clean(key); + return ret; +} +#endif + +/* save a registry branch to a file */ +int save_branch(struct reg_key *key, const char *path) +{ + char *p, *tmp = NULL; + int count = 0, ret = 0; + struct LIBC_FILE *fp; + struct file *filp; + + ktrace("save_branch reg_key %p, path %s\n", key, path); + + if (!(key->flags & KEY_DIRTY)) + return 1; + + /* create a temp file in the same directory */ + if (!(tmp = malloc(strlen(path) + 20))) + return 0; + strcpy(tmp, path); + if ((p = strrchr(tmp, '/'))) + p++; + else + p = tmp; + for (;;) { + sprintf(p, "reg%lx%04x.tmp", (long)getpid(), count++); + if (!IS_ERR(filp = filp_open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0666))) + break; + if (PTR_ERR(filp) != -EEXIST) + goto done; + } + + if (!(fp = uk_filp_open(filp, "w"))) { + fput(filp); + uk_unlink(tmp); + goto done; + } + save_all_subkeys(key, fp); + ret = uk_fclose(fp); + /* if successfully written, rename to final name */ + if (!ret) + ret = uk_rename(tmp, path /* "./system_reg.new"*/); + if (ret) + uk_unlink(tmp); + else + make_clean(key); + + ret = !ret; + +done: + free(tmp); + return ret; +} + +void flush_registry(void) +{ + int i; + + for (i = 0; i < save_branch_count; i++) { + if (!save_branch(save_branch_info[i].key, save_branch_info[i].path)) { + kdebug("could not save registry branch to %s\n", save_branch_info[i].path); + } + } +} + +void write_registry(void) +{ + int i,j,dirty_count,k=1,write_num=200; + unsigned int msecs,timeout; + msecs = 10000; + timeout = msecs_to_jiffies(msecs)+1; + + ktrace("%s start\n",__FUNCTION__); + while(1){ + dirty_count = 0; + for(i=0;i < save_branch_count;i++){ + if(save_branch_info[i].key->flags & KEY_DIRTY) + dirty_count++; + for(j = 0;j < save_branch_info[i].key->last_subkey;j++) + if((*(save_branch_info[i].key->subkeys + j))->flags&KEY_DIRTY) + dirty_count++; + } + + if(kthread_should_stop()){ + for (i = 0; i < save_branch_count; i++) { + if (!save_branch(save_branch_info[i].key, save_branch_info[i].path)) { + kdebug("could not save registry branch to %s\n", save_branch_info[i].path); + } + } + return; + } + k = k*2; + if(k > (2*write_num)) + k = k/2; + if(dirty_count < write_num/k || dirty_count == 0){ + goto sleep; + } + k = k/2; + if(k == 0) + k = 1; + + for (i = 0; i < save_branch_count; i++) { + if (!save_branch(save_branch_info[i].key, save_branch_info[i].path)) { + kdebug("could not save registry branch to %s\n", save_branch_info[i].path); + } + } +sleep: + schedule_timeout_interruptible(timeout); + } +} + +void write_back_branches(void) +{ + save_branch(sys_key, "./system_reg.new"/*"/root/.wine/system_reg.new"*/); + save_branch(user_key, "./user_reg.new"/*"/root/.wine/system_reg.new"*/); + save_branch(udef_key, "./udef_reg.new"/*"/root/.wine/system_reg.new"*/); +} + +DECL_HANDLER(load_init_registry) +{ + struct reg_key *key; + struct unicode_str keyname; + int dummy; + char *filename; + + keyname.len = req->keylen; + keyname.str = malloc(keyname.len); + if (copy_from_user((void *)keyname.str, req->keyname, keyname.len)) + return; + + filename = malloc(MAX_PATH); + if (!filename) + goto out_free_keyname; + if (copy_from_user((void *)filename, req->filename, req->filelen)) { + set_error(STATUS_INVALID_ADDRESS); + goto out_free_filename; + } + + key = create_key(root_key, &keyname, NULL, 0, time(NULL), &dummy); + + load_init_registry_from_file(req->filename, key); + +out_free_filename: + free((void *)filename); + +out_free_keyname: + free((void *)keyname.str); +} + +DECL_HANDLER(save_branch) +{ + ktrace("save_branch\n"); + + save_branch(save_branch_info[req->branch_num].key, + save_branch_info[req->branch_num].path); +} + +DECL_HANDLER(create_key) +{ + struct reg_key *key = NULL, *parent; + struct unicode_str name, class; + unsigned int access = req->access; + + ktrace("create_key\n"); + + reply->hkey = NULL; + + if (req->namelen > get_req_data_size()) { + set_error(STATUS_INVALID_PARAMETER); + kdebug("create_key fail, name to long\n"); + return; + } + + class.str = (const WCHAR *)get_req_data() + req->namelen / sizeof(WCHAR); + class.len = ((get_req_data_size() - req->namelen) / sizeof(WCHAR)) * sizeof(WCHAR); + get_req_path(&name, !req->parent); + + if (name.str > class.str) { + set_error(STATUS_INVALID_PARAMETER); + kdebug("create_key fail, name > class\n"); + return; + } + + name.len = (class.str - name.str) * sizeof(WCHAR); + + /* NOTE: no access rights are required from the parent handle to create a key */ + if ((parent = get_parent_key_obj(req->parent))) { + int flags = (req->options & REG_OPTION_VOLATILE) ? KEY_VOLATILE : KEY_DIRTY; + + if ((key = create_key(parent, &name, &class, flags, req->modif, &reply->created))) { + reply->hkey = alloc_key_handle(key, access, req->attributes); + release_object(key); + } + release_object(parent); + } + ktrace("create_key done, status %x\n", get_error()); +} + +/* open a registry key */ +DECL_HANDLER(open_key) +{ + struct reg_key *key, *parent; + struct unicode_str name; + unsigned int access = req->access; + + ktrace("open_key\n"); + + reply->hkey = 0; + + /* NOTE: no access rights are required to open the parent key, only the child key */ + if ((parent = get_parent_key_obj(req->parent))) { + get_req_path(&name, !req->parent); + + if ((key = open_key(parent, &name))) { + reply->hkey = alloc_key_handle(key, access, req->attributes); + release_object(key); + } + release_object(parent); + } +} + + +/* delete a registry key */ +DECL_HANDLER(delete_key) +{ + struct reg_key *key; + + ktrace("delete_key\n"); + if ((key = get_key_obj(req->hkey, KEY_ALL_ACCESS))) { + delete_key(key, 0); + release_object(key); + } +} + + +/* flush a registry key */ +DECL_HANDLER(flush_key) +{ + struct reg_key *key = get_key_obj(req->hkey, KEY_WRITE); + + ktrace("flush_key\n"); + + if (key) { + /* FIXME we don't need to do anything here with the current implementation */ + release_object(key); + } +} + +/* enumerate registry subkeys */ +DECL_HANDLER(enum_key) +{ + struct reg_key *key; + int access = req->index == -1 ? KEY_QUERY_VALUE : KEY_ENUMERATE_SUB_KEYS; + + ktrace("enum_key\n"); + + if ((key = get_key_obj(req->hkey, access))) { + enum_key(key, req->index, req->info_class, reply); + release_object(key); + } +} + + +/* set a value of a registry key */ +DECL_HANDLER(set_key_value) +{ + struct reg_key *key; + struct unicode_str name; + + ktrace("set_key_value\n"); + + if (req->namelen > get_req_data_size()) { + set_error(STATUS_INVALID_PARAMETER); + return; + } + name.str = get_req_data(); + name.len = (req->namelen / sizeof(WCHAR)) * sizeof(WCHAR); + + if ((key = get_key_obj(req->hkey, KEY_SET_VALUE))) { + data_size_t datalen = get_req_data_size() - req->namelen; + const char *data = (const char *)get_req_data() + req->namelen; + + set_value(key, &name, req->type, data, datalen); + release_object(key); + } +} + + +/* retrieve the value of a registry key */ +DECL_HANDLER(get_key_value) +{ + struct reg_key *key; + struct unicode_str name; + + ktrace("get_key_value\n"); + + reply->total = 0; + if ((key = get_key_obj(req->hkey, KEY_QUERY_VALUE))) { + get_req_unicode_str(&name); + get_value(key, &name, &reply->type, &reply->total); + release_object(key); + } +} + +/* enumerate the value of a registry key */ +DECL_HANDLER(enum_key_value) +{ + struct reg_key *key; + + ktrace("enum_key_value\n"); + + if ((key = get_key_obj(req->hkey, KEY_QUERY_VALUE))) { + enum_value(key, req->index, req->info_class, reply); + release_object(key); + } +} + + +/* delete a value of a registry key */ +DECL_HANDLER(delete_key_value) +{ + struct reg_key *key; + struct unicode_str name; + + ktrace("delete_key_value\n"); + + if ((key = get_key_obj(req->hkey, KEY_SET_VALUE))) { + get_req_unicode_str(&name); + delete_value(key, &name); + release_object(key); + } +} + + +/* load a registry branch from a file */ +DECL_HANDLER(load_registry) +{ + struct reg_key *key, *parent; + struct unicode_str name; +#if 0 + struct token *token = thread_get_impersonation_token(current); + + const LUID_AND_ATTRIBUTES privs[] = + { + { SeBackupPrivilege, 0 }, + { SeRestorePrivilege, 0 }, + }; + + if (!token || !token_check_privileges(token, TRUE, privs, + sizeof(privs)/sizeof(privs[0]), NULL)) { + set_error(STATUS_PRIVILEGE_NOT_HELD); + return; + } +#endif + + ktrace("load_registry\n"); + if ((parent = get_parent_key_obj(req->hkey))) { + int dummy; + + get_req_path(&name, !req->hkey); + if ((key = create_key(parent, &name, NULL, KEY_DIRTY, time(NULL), &dummy))) { + load_registry(key, req->file); + release_object(key); + } + release_object(parent); + } +} + + +DECL_HANDLER(unload_registry) +{ + struct reg_key *key; + + /* FIXME */ +#if 0 + struct token *token = thread_get_impersonation_token(current); + + const LUID_AND_ATTRIBUTES privs[] = + { + { SeBackupPrivilege, 0 }, + { SeRestorePrivilege, 0 }, + }; + + if (!token || !token_check_privileges(token, TRUE, privs, + sizeof(privs)/sizeof(privs[0]), NULL)) { + set_error(STATUS_PRIVILEGE_NOT_HELD); + return; + } +#endif + + ktrace("unload_registry\n"); + if ((key = get_key_obj(req->hkey, 0))) { + delete_key(key, 1); /* FIXME */ + release_object(key); + } +} + + +/* save a registry branch to a file */ +DECL_HANDLER(save_registry) +{ + struct reg_key *key; + + ktrace("save_registry\n"); + + /*FIXME*/ +#if 0 + if (!thread_single_check_privilege(current, &SeBackupPrivilege)) { + set_error(STATUS_PRIVILEGE_NOT_HELD); + return; + } +#endif + if ((key = get_key_obj(req->hkey, 0))) { + save_registry(key, req->file); + release_object(key); + } +} + + +/* add a registry key change notification */ +DECL_HANDLER(set_registry_notification) +{ + struct reg_key *key; + struct kevent *event; + struct notify *notify; + + ktrace("set_registry_notification\n"); + key = get_key_obj(req->hkey, KEY_NOTIFY); + if (key) { + event = get_event_obj(NULL, req->event, SYNCHRONIZE); + if (event) { + notify = find_notify(key, get_current_eprocess(), req->hkey); + if (notify) { + if (notify->event) + release_object(notify->event); + grab_object(event); + notify->event = event; + } else { + notify = mem_alloc(sizeof(*notify)); + if (notify) { + grab_object(event); + notify->event = event; + notify->subtree = req->subtree; + notify->filter = req->filter; + notify->hkey = req->hkey; + notify->process = get_current_eprocess(); + list_add_head(&key->notify_list, ¬ify->entry); + } + } + release_object(event); + } + release_object(key); + } +} +#endif /* CONFIG_UNIFIED_KERNEL */ diff --git a/unifiedkernel/sock/Makefile b/unifiedkernel/sock/Makefile new file mode 100644 index 0000000..2cdd136 --- /dev/null +++ b/unifiedkernel/sock/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for socket +# + +SOCK_OBJS := sock.o \ + +$(MODULE)-objs += $(addprefix sock/, $(SOCK_OBJS)) diff --git a/unifiedkernel/sock/sock.c b/unifiedkernel/sock/sock.c new file mode 100644 index 0000000..1d3b57e --- /dev/null +++ b/unifiedkernel/sock/sock.c @@ -0,0 +1,1014 @@ +/* + * sock.c + * + * Copyright (C) 2006 Insigme Co., Ltd + * + * This software has been developed while working on the Linux Unified Kernel + * project (http://www.longene.org) in the Insigma Research Institute, + * which is a subdivision of Insigma Co., Ltd (http://www.insigma.com.cn). + * + * The project is sponsored by Insigma Co., Ltd. + * + * The authors can be reached at linux@insigma.com.cn. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Revision History: + * Dec 2008 - Created. + */ + +/* + * sock.c: + * Refered to Wine code + */ + +#include +#include + +#include "wineserver/server.h" +#include "wineserver/request.h" +#include "wineserver/uk_lib.h" +#include "io.h" +#include "object.h" +#include "unistr.h" +#include "event.h" +#include "object.h" +#include "section.h" +#include "handle.h" +#include "objwait.h" +#include "winuser.h" +#include "wineserver/winerror.h" +#include "thread.h" +#include "wineserver/file.h" +#include "wineserver/user.h" +#include "wineserver/winerror.h" + +#ifdef CONFIG_UNIFIED_KERNEL +/* To avoid conflicts with the Unix socket headers. Plus we only need a few + * macros anyway. + */ +#define USE_WS_PREFIX + +#define FD_MAX_EVENTS 10 + +struct uk_sock +{ + struct object obj; /* object header */ + struct fd *fd; /* socket file descriptor */ + unsigned int state; /* status bits */ + unsigned int mask; /* event mask */ + unsigned int hmask; /* held (blocked) events */ + unsigned int pmask; /* pending events */ + unsigned int flags; /* socket flags */ + int polling; /* is socket being polled? */ + unsigned short type; /* socket type */ + unsigned short family; /* socket family */ + struct kevent *event; /* event object */ + user_handle_t window; /* window to send the message to */ + unsigned int message; /* message to send */ + obj_handle_t wparam; /* message wparam (socket handle) */ + int errors[FD_MAX_EVENTS]; /* event errors */ + struct uk_sock *deferred; /* socket that waits for a deferred accept */ + struct async_queue *read_q; /* queue for asynchronous reads */ + struct async_queue *write_q; /* queue for asynchronous writes */ +}; + +static void sock_dump( struct object *obj, int verbose ); +#if 0 +static int sock_signaled( struct object *obj, struct w32thread *thread ); +#endif +static struct fd *sock_get_fd( struct object *obj ); +static void sock_destroy( struct object *obj ); + +static int sock_get_poll_events( struct fd *fd ); +static void sock_poll_event( struct fd *fd, int event ); +static enum server_fd_type sock_get_fd_type( struct fd *fd ); +static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); +static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); +static void sock_cancel_async( struct fd *fd ); + +static int sock_get_error( int err ); +static void sock_set_error(void); +extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); + +static const struct object_ops sock_ops = +{ + sizeof(struct uk_sock), /* size */ + sock_dump, /* dump */ + no_get_type, /* get_type */ +#if 0 + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + sock_signaled, /* signaled */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ +#endif + sock_get_fd, /* get_fd */ + default_fd_map_access, /* map_access */ +#if 0 + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ +#endif + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ + fd_close_handle, /* close_handle */ + sock_destroy /* destroy */ +}; + +static const struct fd_ops sock_fd_ops = +{ + sock_get_poll_events, /* get_poll_events */ + sock_poll_event, /* poll_event */ + no_flush, /* flush */ + sock_get_fd_type, /* get_file_info */ + default_fd_ioctl, /* ioctl */ + sock_queue_async, /* queue_async */ + sock_reselect_async, /* reselect_async */ + sock_cancel_async /* cancel_async */ +}; + +/* option flags per socket */ + +#define FD_MAX_EVENTS 10 +#define FD_READ_BIT 0 +#define FD_WRITE_BIT 1 +#define FD_OOB_BIT 2 +#define FD_ACCEPT_BIT 3 +#define FD_CONNECT_BIT 4 +#define FD_CLOSE_BIT 5 + +/* Permutation of 0..FD_MAX_EVENTS - 1 representing the order in which + * we post messages if there are multiple events. Used to send + * messages. The problem is if there is both a FD_CONNECT event and, + * say, an FD_READ event available on the same socket, we want to + * notify the app of the connect event first. Otherwise it may + * discard the read event because it thinks it hasn't connected yet. + */ +static const int event_bitorder[FD_MAX_EVENTS] = +{ + FD_CONNECT_BIT, + FD_ACCEPT_BIT, + FD_OOB_BIT, + FD_WRITE_BIT, + FD_READ_BIT, + FD_CLOSE_BIT, + 6, 7, 8, 9 /* leftovers */ +}; + +/* Flags that make sense only for SOCK_STREAM sockets */ +#define STREAM_FLAG_MASK \ + ((unsigned int) (FD_CONNECT | FD_ACCEPT | FD_WINE_LISTENING | FD_WINE_CONNECTED)) + +typedef enum { + SOCK_SHUTDOWN_ERROR = -1, + SOCK_SHUTDOWN_EOF = 0, + SOCK_SHUTDOWN_POLLHUP = 1 +} sock_shutdown_t; + +static sock_shutdown_t sock_shutdown_type = SOCK_SHUTDOWN_ERROR; + +#if 0 +/* Data structure describing a polling request. */ +struct pollfd +{ + int fd; /* File descriptor to poll. */ + short int events; /* Types of events poller cares about. */ + short int revents; /* Types of events that actually occurred. */ +}; +#endif + +extern int uk_socketpair(int d, int type, int protocol, int sv[2]); +extern int uk_poll(struct pollfd *ufds, int nfds, int timeout); +extern int uk_shutdown(int s, int how); +extern int uk_recv(int s, void *buf, int len, int flags); + +#define AF_UNIX 1 /* Unix domain sockets */ + +/* Types of sockets. */ +enum __socket_type +{ + SOCK_STREAM = 1, /* Sequenced, reliable, connection-based + byte streams. */ +#define SOCK_STREAM SOCK_STREAM + SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams + of fixed maximum length. */ +#define SOCK_DGRAM SOCK_DGRAM + SOCK_RAW = 3, /* Raw protocol interface. */ +#define SOCK_RAW SOCK_RAW + SOCK_RDM = 4, /* Reliably-delivered messages. */ +#define SOCK_RDM SOCK_RDM + SOCK_SEQPACKET = 5, /* Sequenced, reliable, connection-based, + datagrams of fixed maximum length. */ +#define SOCK_SEQPACKET SOCK_SEQPACKET + SOCK_PACKET = 10 /* Linux specific way of getting packets + at the dev level. For writing rarp and + other similar things on the user level. */ +#define SOCK_PACKET SOCK_PACKET +}; + +#define FD_WINE_LISTENING 0x10000000 +#define FD_WINE_NONBLOCKING 0x20000000 +#define FD_WINE_CONNECTED 0x40000000 +#define FD_WINE_RAW 0x80000000 +#define FD_WINE_INTERNAL 0xFFFF0000 + +#define SOL_SOCKET 0xffff +#define SO_ERROR 0x1007 + +#define WSA_FLAG_OVERLAPPED 0x01 + +/* + * * Define flags to be used with the WSAAsyncSelect() call. + */ +#define FD_READ 0x00000001 +#define FD_WRITE 0x00000002 +#define FD_OOB 0x00000004 +#define FD_ACCEPT 0x00000008 +#define FD_CONNECT 0x00000010 +#define FD_CLOSE 0x00000020 + +#define MSG_PEEK 0x0002 + +static sock_shutdown_t sock_check_pollhup(void) +{ + sock_shutdown_t ret = SOCK_SHUTDOWN_ERROR; + int fd[2], n; + struct pollfd pfd; + char dummy; + + if ( uk_socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) ) + goto out; + if ( uk_shutdown( fd[0], 1 ) ) + goto out; + + pfd.fd = fd[1]; + pfd.events = POLLIN; + pfd.revents = 0; + + n = uk_poll( &pfd, 1, 0 ); + if ( n != 1 ) + goto out; /* error or timeout */ + if ( pfd.revents & POLLHUP ) + ret = SOCK_SHUTDOWN_POLLHUP; + else if ( pfd.revents & POLLIN && uk_read( fd[1], &dummy, 1 ) == 0 ) + ret = SOCK_SHUTDOWN_EOF; + +out: + uk_close( fd[0] ); + uk_close( fd[1] ); + return ret; +} + +void sock_init(void) +{ + sock_shutdown_type = sock_check_pollhup(); + + switch ( sock_shutdown_type ) { + case SOCK_SHUTDOWN_EOF: + ktrace( "sock_init: shutdown() causes EOF\n" ); + break; + case SOCK_SHUTDOWN_POLLHUP: + ktrace( "sock_init: shutdown() causes POLLHUP\n" ); + break; + default: + ktrace( "sock_init: ERROR in sock_check_pollhup()\n" ); + sock_shutdown_type = SOCK_SHUTDOWN_EOF; + } +} + +static int sock_reselect( struct uk_sock *sock ) +{ + int ev = sock_get_poll_events( sock->fd ); + + ktrace("sock_reselect(%p): new mask %x\n", sock, ev); + + if (!sock->polling) /* FIXME: should find a better way to do this */ { + /* previously unconnected socket, is this reselect supposed to connect it? */ + if (!(sock->state & ~FD_WINE_NONBLOCKING)) + return 0; + /* ok, it is, attach it to the wineserver's main poll loop */ + sock->polling = 1; + } + /* update condition mask */ + set_fd_events( sock->fd, ev ); + return ev; +} + +/* After POLLHUP is received, the socket will no longer be in the main select loop. + This function is used to signal pending events nevertheless */ +static void sock_try_event( struct uk_sock *sock, int event ) +{ + event = check_fd_events( sock->fd, event ); + if (event) { + ktrace( "sock_try_event: %x\n", event ); + sock_poll_event( sock->fd, event ); + } +} + +/* wake anybody waiting on the socket event or send the associated message */ +static void sock_wake_up( struct uk_sock *sock, int pollev ) +{ + unsigned int events = sock->pmask & sock->mask; + int i; + int async_active = 0; + + if ( pollev & (POLLIN|POLLPRI) && async_waiting( sock->read_q )) { + ktrace( "activating read queue for socket %p\n", sock ); + async_wake_up( sock->read_q, STATUS_ALERTED ); + async_active = 1; + } + if ( pollev & POLLOUT && async_waiting( sock->write_q )) { + ktrace( "activating write queue for socket %p\n", sock ); + async_wake_up( sock->write_q, STATUS_ALERTED ); + async_active = 1; + } + + /* Do not signal events if there are still pending asynchronous IO requests */ + /* We need this to delay FD_CLOSE events until all pending overlapped requests are processed */ + if ( !events || async_active ) + return; + + if (sock->event) { + ktrace( "signalling events %x ptr %p\n", events, sock->event ); + set_event( sock->event, EVENT_INCREMENT, FALSE ); + } + if (sock->window) { + ktrace( "signalling events %x win %p\n", events, sock->window ); + for (i = 0; i < FD_MAX_EVENTS; i++) { + int event = event_bitorder[i]; + if (sock->pmask & (1 << event)) { + unsigned int lparam = (1 << event) | (sock->errors[event] << 16); + post_message( sock->window, sock->message, (unsigned long)sock->wparam, lparam ); + } + } + sock->pmask = 0; + sock_reselect( sock ); + } +} + +extern int uk_getsockopt(int s, int level, int optname, void *optval, unsigned int *optlen); + +static inline int sock_error( struct fd *fd ) +{ + unsigned int optval = 0, optlen; + + optlen = sizeof(optval); + uk_getsockopt( get_unix_fd(fd), SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen); + return optval ? sock_get_error(optval) : 0; +} + +static void sock_poll_event( struct fd *fd, int event ) +{ + struct uk_sock *sock = get_fd_user( fd ); + int hangup_seen = 0; + + ktrace( "socket %p select event: %x\n", sock, event); + if (sock->state & FD_CONNECT) { + /* connecting */ + if (event & POLLOUT) { + /* we got connected */ + sock->state |= FD_WINE_CONNECTED|FD_READ|FD_WRITE; + sock->state &= ~FD_CONNECT; + sock->pmask |= FD_CONNECT; + sock->errors[FD_CONNECT_BIT] = 0; + ktrace( "socket %p connection success\n", sock); + } else if (event & (POLLERR|POLLHUP)) { + /* we didn't get connected? */ + sock->state &= ~FD_CONNECT; + sock->pmask |= FD_CONNECT; + sock->errors[FD_CONNECT_BIT] = sock_error( fd ); + ktrace( "socket %p connection failure\n", sock); + } + } else if (sock->state & FD_WINE_LISTENING) { + /* listening */ + if (event & POLLIN) { + /* incoming connection */ + sock->pmask |= FD_ACCEPT; + sock->errors[FD_ACCEPT_BIT] = 0; + sock->hmask |= FD_ACCEPT; + } + else if (event & (POLLERR|POLLHUP)) { + /* failed incoming connection? */ + sock->pmask |= FD_ACCEPT; + sock->errors[FD_ACCEPT_BIT] = sock_error( fd ); + sock->hmask |= FD_ACCEPT; + } + } else { + /* normal data flow */ + if ( sock->type == SOCK_STREAM && ( event & POLLIN ) ) { + char dummy; + int nr; + + /* Linux 2.4 doesn't report POLLHUP if only one side of the socket + * has been closed, so we need to check for it explicitly here */ + nr = uk_recv( get_unix_fd( fd ), &dummy, 1, MSG_PEEK ); + if ( nr > 0 ) { + /* incoming data */ + sock->pmask |= FD_READ; + sock->hmask |= (FD_READ|FD_CLOSE); + sock->errors[FD_READ_BIT] = 0; + ktrace( "socket %p is readable\n", sock ); + } + else if ( nr == 0 ) + hangup_seen = 1; + else { + /* EAGAIN can happen if an async recv() falls between the server's poll() + call and the invocation of this routine */ + if ( errno == EAGAIN ) + event &= ~POLLIN; + else { + ktrace( "recv error on socket %p: %d\n", sock, errno ); + event = POLLERR; + } + } + + } else if ( sock_shutdown_type == SOCK_SHUTDOWN_POLLHUP && (event & POLLHUP) ) + hangup_seen = 1; + else if ( event & POLLIN ) /* POLLIN for non-stream socket */ { + sock->pmask |= FD_READ; + sock->hmask |= (FD_READ|FD_CLOSE); + sock->errors[FD_READ_BIT] = 0; + ktrace( "socket %p is readable\n", sock ); + } + + if (event & POLLOUT) { + sock->pmask |= FD_WRITE; + sock->hmask |= FD_WRITE; + sock->errors[FD_WRITE_BIT] = 0; + ktrace("socket %p is writable\n", sock); + } + if (event & POLLPRI) { + sock->pmask |= FD_OOB; + sock->hmask |= FD_OOB; + sock->errors[FD_OOB_BIT] = 0; + ktrace("socket %p got OOB data\n", sock); + } + /* According to WS2 specs, FD_CLOSE is only delivered when there is + no more data to be read (i.e. hangup_seen = 1) */ + else if ( hangup_seen && (sock->state & (FD_READ|FD_WRITE) )) { + sock->errors[FD_CLOSE_BIT] = sock_error( fd ); + if ( (event & POLLERR) || ( sock_shutdown_type == SOCK_SHUTDOWN_EOF && (event & POLLHUP) )) + sock->state &= ~FD_WRITE; + sock->pmask |= FD_CLOSE; + sock->hmask |= FD_CLOSE; + ktrace("socket %p aborted by error %d, event: %x - removing from select loop\n", + sock, sock->errors[FD_CLOSE_BIT], event); + } + } + + if ( sock->pmask & FD_CLOSE || event & (POLLERR|POLLHUP) ) { + ktrace( "removing socket %p from select loop\n", sock ); + set_fd_events( sock->fd, -1 ); + } + else + sock_reselect( sock ); + + /* wake up anyone waiting for whatever just happened */ + if ( sock->pmask & sock->mask || sock->flags & WSA_FLAG_OVERLAPPED ) + sock_wake_up( sock, event ); + + /* if anyone is stupid enough to wait on the socket object itself, + * maybe we should wake them up too, just in case? */ + uk_wake_up( &sock->obj, 0 ); +} + +static void sock_dump( struct object *obj, int verbose ) +{ +#if 0 + struct uk_sock *sock = (struct uk_sock *)obj; + assert( obj->ops == &sock_ops ); + ktrace( "Socket fd=%p, state=%x, mask=%x, pending=%x, held=%x\n", + sock->fd, sock->state, + sock->mask, sock->pmask, sock->hmask ); +#endif +} + +#if 0 +static int sock_signaled( struct object *obj, struct w32thread *thread ) +{ + struct uk_sock *sock = (struct uk_sock *)obj; + assert( obj->ops == &sock_ops ); + + return check_fd_events( sock->fd, sock_get_poll_events( sock->fd ) ) != 0; +} +#endif + +static int sock_get_poll_events( struct fd *fd ) +{ + struct uk_sock *sock = get_fd_user( fd ); + unsigned int mask = sock->mask & sock->state & ~sock->hmask; + int ev = 0; + + + if (sock->state & FD_CONNECT) + /* connecting, wait for writable */ + return POLLOUT; + if (sock->state & FD_WINE_LISTENING) + /* listening, wait for readable */ + return (sock->hmask & FD_ACCEPT) ? 0 : POLLIN; + + if (mask & FD_READ || async_waiting( sock->read_q )) + ev |= POLLIN | POLLPRI; + if (mask & FD_WRITE || async_waiting( sock->write_q )) + ev |= POLLOUT; + /* We use POLLIN with 0 bytes recv() as FD_CLOSE indication for stream sockets. */ + if ( sock->type == SOCK_STREAM && ( sock->mask & ~sock->hmask & FD_CLOSE) ) + ev |= POLLIN; + + return ev; +} + +static enum server_fd_type sock_get_fd_type( struct fd *fd ) +{ + return FD_TYPE_SOCKET; +} + +static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) +{ + struct uk_sock *sock = get_fd_user( fd ); + struct async_queue *queue; + int pollev; + + switch (type) { + case ASYNC_TYPE_READ: + if (!sock->read_q && !(sock->read_q = create_async_queue( sock->fd ))) + return; + queue = sock->read_q; + sock->hmask &= ~FD_CLOSE; + break; + case ASYNC_TYPE_WRITE: + if (!sock->write_q && !(sock->write_q = create_async_queue( sock->fd ))) + return; + queue = sock->write_q; + break; + default: + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if ( ( !( sock->state & FD_READ ) && type == ASYNC_TYPE_READ ) || + ( !( sock->state & FD_WRITE ) && type == ASYNC_TYPE_WRITE ) ) { + set_error( STATUS_PIPE_DISCONNECTED ); + } else { + struct async *async; + if (!(async = create_async( current_thread, queue, data ))) + return; + release_object( async ); + set_error( STATUS_PENDING ); + } + + pollev = sock_reselect( sock ); + if ( pollev ) + sock_try_event( sock, pollev ); +} + +static void sock_reselect_async( struct fd *fd, struct async_queue *queue ) +{ + struct uk_sock *sock = get_fd_user( fd ); + int events = sock_reselect( sock ); + if (events) + sock_try_event( sock, events ); +} + +static void sock_cancel_async( struct fd *fd ) +{ + struct uk_sock *sock = get_fd_user( fd ); + + async_wake_up( sock->read_q, STATUS_CANCELLED ); + async_wake_up( sock->write_q, STATUS_CANCELLED ); +} + +static struct fd *sock_get_fd( struct object *obj ) +{ + struct uk_sock *sock = (struct uk_sock *)obj; + return (struct fd *)grab_object( sock->fd ); +} + +#if 0 +enum +{ + SHUT_RD = 0, /* No more receptions. */ +#define SHUT_RD SHUT_RD + SHUT_WR, /* No more transmissions. */ +#define SHUT_WR SHUT_WR + SHUT_RDWR /* No more receptions or transmissions. */ +#define SHUT_RDWR SHUT_RDWR +}; +#endif + +static void sock_destroy( struct object *obj ) +{ + struct uk_sock *sock = (struct uk_sock *)obj; + + /* FIXME: special socket shutdown stuff? */ + + if ( sock->deferred ) + release_object( sock->deferred ); + + free_async_queue( sock->read_q ); + free_async_queue( sock->write_q ); + if (sock->event) + release_object( sock->event ); + if (sock->fd) { + /* shut the socket down to force pending poll() calls in the client to return */ + uk_shutdown( get_unix_fd(sock->fd), SHUT_RDWR ); + release_object( sock->fd ); + } +} + +extern void clear_error(void); +extern int uk_socket(int domain, int type, int protocol); +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 + +/* create a new and unconnected socket */ +static struct object *create_socket( int family, int type, int protocol, unsigned int flags ) +{ + struct uk_sock *sock; + int sockfd; + + sockfd = uk_socket( family, type, protocol ); + ktrace("socket(%d,%d,%d)=%d\n",family,type,protocol,sockfd); + if (sockfd == -1) { + sock_set_error(); + return NULL; + } + uk_fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ + if (!(sock = alloc_wine_object( &sock_ops ))) { + uk_close( sockfd ); + return NULL; + } + sock->state = (type != SOCK_STREAM) ? (FD_READ|FD_WRITE) : 0; + sock->mask = 0; + sock->hmask = 0; + sock->pmask = 0; + sock->polling = 0; + sock->flags = flags; + sock->type = type; + sock->family = family; + sock->event = NULL; + sock->window = 0; + sock->message = 0; + sock->wparam = 0; + sock->deferred = NULL; + sock->read_q = NULL; + sock->write_q = NULL; + if (!(sock->fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj, + (flags & WSA_FLAG_OVERLAPPED) ? 0 : FILE_SYNCHRONOUS_IO_NONALERT ))) { + release_object( sock ); + return NULL; + } + sock_reselect( sock ); + clear_error(); + return &sock->obj; +} + +typedef unsigned short sa_family_t; + +struct sockaddr { + sa_family_t sa_family; /* address family, AF_xxx */ + char sa_data[14]; /* 14 bytes of protocol address */ +}; +extern int uk_accept(int sockfd, struct sockaddr *addr, int *addrlen); + +/* accept a socket (creates a new fd) */ +static struct uk_sock *accept_socket( obj_handle_t handle ) +{ + struct uk_sock *acceptsock; + struct uk_sock *sock; + int acceptfd; + struct sockaddr saddr; + + sock = (struct uk_sock *)get_wine_handle_obj( get_current_w32process(), handle, + FILE_READ_DATA, &sock_ops ); + if (!sock) + return NULL; + + if ( sock->deferred ) { + acceptsock = sock->deferred; + sock->deferred = NULL; + } else { + /* Try to accept(2). We can't be safe that this an already connected socket + * or that accept() is allowed on it. In those cases we will get -1/errno + * return. + */ + unsigned int slen = sizeof(saddr); + acceptfd = uk_accept( get_unix_fd(sock->fd), &saddr, &slen); + if (acceptfd==-1) { + sock_set_error(); + release_object( sock ); + return NULL; + } + if (!(acceptsock = alloc_wine_object( &sock_ops ))) { + uk_close( acceptfd ); + release_object( sock ); + return NULL; + } + + /* newly created socket gets the same properties of the listening socket */ + uk_fcntl(acceptfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */ + acceptsock->state = FD_WINE_CONNECTED|FD_READ|FD_WRITE; + if (sock->state & FD_WINE_NONBLOCKING) + acceptsock->state |= FD_WINE_NONBLOCKING; + acceptsock->mask = sock->mask; + acceptsock->hmask = 0; + acceptsock->pmask = 0; + acceptsock->polling = 0; + acceptsock->type = sock->type; + acceptsock->family = sock->family; + acceptsock->event = NULL; + acceptsock->window = sock->window; + acceptsock->message = sock->message; + acceptsock->wparam = 0; + if (sock->event) + acceptsock->event = (struct kevent *)grab_object( sock->event ); + acceptsock->flags = sock->flags; + acceptsock->deferred = NULL; + acceptsock->read_q = NULL; + acceptsock->write_q = NULL; + if (!(acceptsock->fd = create_anonymous_fd( &sock_fd_ops, acceptfd, &acceptsock->obj, + get_fd_options( sock->fd ) ))) { + release_object( acceptsock ); + release_object( sock ); + return NULL; + } + } + clear_error(); + sock->pmask &= ~FD_ACCEPT; + sock->hmask &= ~FD_ACCEPT; + sock_reselect( sock ); + release_object( sock ); + return acceptsock; +} + +#define WSABASEERR 10000 +#define WSAEINTR (WSABASEERR+4) +#define WSAEBADF (WSABASEERR+9) +#define WSAEACCES (WSABASEERR+13) +#define WSAEFAULT (WSABASEERR+14) +#define WSAEINVAL (WSABASEERR+22) +#define WSAEMFILE (WSABASEERR+24) + +#define WSAEWOULDBLOCK (WSABASEERR+35) +#define WSAEINPROGRESS (WSABASEERR+36) +#define WSAEALREADY (WSABASEERR+37) +#define WSAENOTSOCK (WSABASEERR+38) +#define WSAEDESTADDRREQ (WSABASEERR+39) +#define WSAEMSGSIZE (WSABASEERR+40) +#define WSAEPROTOTYPE (WSABASEERR+41) +#define WSAENOPROTOOPT (WSABASEERR+42) +#define WSAEPROTONOSUPPORT (WSABASEERR+43) +#define WSAESOCKTNOSUPPORT (WSABASEERR+44) +#define WSAEOPNOTSUPP (WSABASEERR+45) +#define WSAEPFNOSUPPORT (WSABASEERR+46) +#define WSAEAFNOSUPPORT (WSABASEERR+47) +#define WSAEADDRINUSE (WSABASEERR+48) +#define WSAEADDRNOTAVAIL (WSABASEERR+49) +#define WSAENETDOWN (WSABASEERR+50) +#define WSAENETUNREACH (WSABASEERR+51) +#define WSAENETRESET (WSABASEERR+52) +#define WSAECONNABORTED (WSABASEERR+53) +#define WSAECONNRESET (WSABASEERR+54) +#define WSAENOBUFS (WSABASEERR+55) +#define WSAEISCONN (WSABASEERR+56) +#define WSAENOTCONN (WSABASEERR+57) +#define WSAESHUTDOWN (WSABASEERR+58) +#define WSAETOOMANYREFS (WSABASEERR+59) +#define WSAETIMEDOUT (WSABASEERR+60) +#define WSAECONNREFUSED (WSABASEERR+61) +#define WSAELOOP (WSABASEERR+62) +#define WSAENAMETOOLONG (WSABASEERR+63) +#define WSAEHOSTDOWN (WSABASEERR+64) +#define WSAEHOSTUNREACH (WSABASEERR+65) +#define WSAENOTEMPTY (WSABASEERR+66) +#define WSAEPROCLIM (WSABASEERR+67) +#define WSAEUSERS (WSABASEERR+68) +#define WSAEDQUOT (WSABASEERR+69) +#define WSAESTALE (WSABASEERR+70) +#define WSAEREMOTE (WSABASEERR+71) + + +/* set the last error depending on errno */ +static int sock_get_error( int err ) +{ + switch (err) + { + case EINTR: return WSAEINTR; + case EBADF: return WSAEBADF; + case EPERM: + case EACCES: return WSAEACCES; + case EFAULT: return WSAEFAULT; + case EINVAL: return WSAEINVAL; + case EMFILE: return WSAEMFILE; + case EWOULDBLOCK: return WSAEWOULDBLOCK; + case EINPROGRESS: return WSAEINPROGRESS; + case EALREADY: return WSAEALREADY; + case ENOTSOCK: return WSAENOTSOCK; + case EDESTADDRREQ: return WSAEDESTADDRREQ; + case EMSGSIZE: return WSAEMSGSIZE; + case EPROTOTYPE: return WSAEPROTOTYPE; + case ENOPROTOOPT: return WSAENOPROTOOPT; + case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT; + case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT; + case EOPNOTSUPP: return WSAEOPNOTSUPP; + case EPFNOSUPPORT: return WSAEPFNOSUPPORT; + case EAFNOSUPPORT: return WSAEAFNOSUPPORT; + case EADDRINUSE: return WSAEADDRINUSE; + case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL; + case ENETDOWN: return WSAENETDOWN; + case ENETUNREACH: return WSAENETUNREACH; + case ENETRESET: return WSAENETRESET; + case ECONNABORTED: return WSAECONNABORTED; + case EPIPE: + case ECONNRESET: return WSAECONNRESET; + case ENOBUFS: return WSAENOBUFS; + case EISCONN: return WSAEISCONN; + case ENOTCONN: return WSAENOTCONN; + case ESHUTDOWN: return WSAESHUTDOWN; + case ETOOMANYREFS: return WSAETOOMANYREFS; + case ETIMEDOUT: return WSAETIMEDOUT; + case ECONNREFUSED: return WSAECONNREFUSED; + case ELOOP: return WSAELOOP; + case ENAMETOOLONG: return WSAENAMETOOLONG; + case EHOSTDOWN: return WSAEHOSTDOWN; + case EHOSTUNREACH: return WSAEHOSTUNREACH; + case ENOTEMPTY: return WSAENOTEMPTY; +#ifdef EPROCLIM + case EPROCLIM: return WSAEPROCLIM; +#endif +#ifdef EUSERS + case EUSERS: return WSAEUSERS; +#endif +#ifdef EDQUOT + case EDQUOT: return WSAEDQUOT; +#endif +#ifdef ESTALE + case ESTALE: return WSAESTALE; +#endif +#ifdef EREMOTE + case EREMOTE: return WSAEREMOTE; +#endif + default: +#if 0 + errno = err; + perror("wineserver: sock_get_error() can't map error"); +#endif + return WSAEFAULT; + } +} + +/* set the last error depending on errno */ +static void sock_set_error(void) +{ + set_error( sock_get_error( errno ) ); +} + +/* create a socket */ +DECL_HANDLER(create_socket) +{ + struct object *obj; + + reply->handle = 0; + if ((obj = create_socket( req->family, req->type, req->protocol, req->flags )) != NULL) { + reply->handle = alloc_handle( get_current_w32process(), obj, req->access, req->attributes ); + release_object( obj ); + } +} + +/* accept a socket */ +DECL_HANDLER(accept_socket) +{ + struct uk_sock *sock; + + reply->handle = 0; + if ((sock = accept_socket( req->lhandle )) != NULL) { + reply->handle = alloc_handle( get_current_w32process(), &sock->obj, req->access, req->attributes ); + sock->wparam = reply->handle; /* wparam for message is the socket handle */ + sock_reselect( sock ); + release_object( &sock->obj ); + } +} + +/* set socket event parameters */ +DECL_HANDLER(set_socket_event) +{ + struct uk_sock *sock; + struct kevent *old_event; + int pollev; + + if (!(sock = (struct uk_sock *)get_wine_handle_obj( get_current_w32process(), req->handle, + FILE_WRITE_ATTRIBUTES, &sock_ops))) + return; + old_event = sock->event; + sock->mask = req->mask; + sock->hmask &= ~req->mask; /* re-enable held events */ + sock->event = NULL; + sock->window = req->window; + sock->message = req->msg; + sock->wparam = req->handle; /* wparam is the socket handle */ + if (req->event) + sock->event = get_event_obj( get_current_w32process(), req->event, EVENT_MODIFY_STATE ); + + if (sock->event) + ktrace("event ptr: %p\n", sock->event); + + pollev = sock_reselect( sock ); + if ( pollev ) + sock_try_event( sock, pollev ); + + if (sock->mask) + sock->state |= FD_WINE_NONBLOCKING; + + /* if a network event is pending, signal the event object + it is possible that FD_CONNECT or FD_ACCEPT network events has happened + before a WSAEventSelect() was done on it. + (when dealing with Asynchronous socket) */ + if (sock->pmask & sock->mask) + sock_wake_up( sock, pollev ); + + if (old_event) + release_object( old_event ); /* we're through with it */ + release_object( &sock->obj ); +} + +/* get socket event parameters */ +DECL_HANDLER(get_socket_event) +{ + struct uk_sock *sock; + + sock = (struct uk_sock *)get_wine_handle_obj( get_current_w32process(), req->handle, + FILE_READ_ATTRIBUTES, &sock_ops ); + if (!sock) { + reply->mask = 0; + reply->pmask = 0; + reply->state = 0; + set_error( WSAENOTSOCK ); + return; + } + reply->mask = sock->mask; + reply->pmask = sock->pmask; + reply->state = sock->state; + set_reply_data( sock->errors, min( get_reply_max_size(), sizeof(sock->errors) )); + + if (req->service) { + if (req->c_event) { + struct kevent *cevent = get_event_obj( get_current_w32process(), req->c_event, + EVENT_MODIFY_STATE ); + if (cevent) { + reset_event( cevent ); + release_object( cevent ); + } + } + sock->pmask = 0; + sock_reselect( sock ); + } + release_object( &sock->obj ); +} + +/* re-enable pending socket events */ +DECL_HANDLER(enable_socket_event) +{ + struct uk_sock *sock; + int pollev; + + if (!(sock = (struct uk_sock*)get_wine_handle_obj( get_current_w32process(), req->handle, + FILE_WRITE_ATTRIBUTES, &sock_ops))) + return; + + sock->pmask &= ~req->mask; /* is this safe? */ + sock->hmask &= ~req->mask; + if ( req->mask & FD_READ ) + sock->hmask &= ~FD_CLOSE; + sock->state |= req->sstate; + sock->state &= ~req->cstate; + if ( sock->type != SOCK_STREAM ) sock->state &= ~STREAM_FLAG_MASK; + + pollev = sock_reselect( sock ); + if ( pollev ) sock_try_event( sock, pollev ); + + release_object( &sock->obj ); +} + +DECL_HANDLER(set_socket_deferred) +{ + struct uk_sock *sock, *acceptsock; + + sock=(struct uk_sock *)get_wine_handle_obj( get_current_w32process(), req->handle, + FILE_WRITE_ATTRIBUTES, &sock_ops ); + if ( !sock ) { + set_error( WSAENOTSOCK ); + return; + } + acceptsock = (struct uk_sock *)get_wine_handle_obj( get_current_w32process(), req->deferred, + 0, &sock_ops ); + if ( !acceptsock ) { + release_object( sock ); + set_error( WSAENOTSOCK ); + return; + } + sock->deferred = acceptsock; + release_object( sock ); +} +#endif /* CONFIG_UNIFIED_KERNEL */ -- 1.6.4.2