registry_drv.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 534 行
C
534 行
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ *//* * Purpose: Interface to the registry API. */#include <windows.h>#include "erl_driver.h"#include "sys.h"/* * Commands recognised by this driver. */#define CMD_GET_CURRENT 0#define CMD_OPEN_KEY 1#define CMD_CREATE_KEY 2#define CMD_GET_ALL_SUBKEYS 3#define CMD_GET_VALUE 4#define CMD_GET_ALL_VALUES 5#define CMD_SET_VALUE 6#define CMD_DELETE_KEY 7#define CMD_DELETE_VALUE 8/* * Microsoft-specific function to map a WIN32 error code to a Posix errno. */extern void _dosmaperr(DWORD);/* * Information kept for a registry port (since there is no controlling * Erlang process, all state must be kept here). */typedef struct { ErlDrvPort port; /* Port handle. */ REGSAM sam; /* Access for handles. */ HKEY hkey; /* Handle to open key. */ HKEY hkey_root; /* Root handle for current key. */ char* key; /* Name of key. */ DWORD key_size; /* Size of key. */ LPSTR name_buf; /* Buffer for names. */ DWORD name_buf_size; /* Size of name buffer. */ LPSTR value_buf; /* Buffer for values. */ DWORD value_buf_size; /* Size of value buffer. */} RegPort;/* * Local functions. */static void reply(RegPort* rp, LONG result);static BOOL fix_value_result(RegPort* rp, LONG result, DWORD type, LPSTR name, DWORD nameSize, LPSTR value, DWORD valueSize);static int key_reply(RegPort* rp, LPSTR name, DWORD nameSize);static int value_reply(RegPort* rp, DWORD type, LPSTR name, DWORD nameSize, LPSTR value, DWORD valueSize);static int state_reply(RegPort* rp, HKEY root, LPSTR name, DWORD nameSize);static int maperror(DWORD error);/* * Local variables. */static int reg_init(void);static ErlDrvData reg_start(ErlDrvPort, char*);static void reg_stop(ErlDrvData);static void reg_from_erlang(ErlDrvData, char*, int);struct erl_drv_entry registry_driver_entry = { reg_init, reg_start, reg_stop, reg_from_erlang, NULL, NULL, "registry__drv__", NULL, NULL, NULL, NULL, NULL};static intreg_init(void){ DEBUGF(("reg_init()\n")); return 0;}static ErlDrvDatareg_start(ErlDrvPort port, char* buf){ RegPort* rp; char* s; REGSAM sam = KEY_READ; if ((s = strchr(buf, ' ')) != NULL) { while (isspace(*s)) s++; while (*s != '\0') { if (*s == 'r') { sam |= KEY_READ; } else if (*s == 'w') { sam |= KEY_WRITE; } s++; } } rp = driver_alloc(sizeof(RegPort)); if (rp == NULL) { return ERL_DRV_ERROR_GENERAL; } rp->port = port; rp->hkey = rp->hkey_root = HKEY_CLASSES_ROOT; rp->sam = sam; rp->key = driver_alloc(1); rp->key_size = 0; rp->name_buf_size = 64; rp->name_buf = driver_alloc(rp->name_buf_size); rp->value_buf_size = 64; rp->value_buf = driver_alloc(rp->value_buf_size); return (ErlDrvData) rp;}static voidreg_stop(ErlDrvData clientData){ RegPort* rp = (RegPort *) clientData; (void) RegCloseKey(rp->hkey); driver_free(rp->name_buf); driver_free(rp->value_buf); driver_free(rp->key); driver_free(rp); /* return 1; */}static voidreg_from_erlang(ErlDrvData clientData, char* buf, int count){ RegPort* rp = (RegPort *) clientData; int cmd; HKEY hkey; LONG result; DWORD nameSize; DWORD type; /* Type of data in buffer. */ DWORD valueSize; /* Size of value buffer. */ cmd = buf[0]; buf++, count--; switch (cmd) { case CMD_GET_CURRENT: state_reply(rp, rp->hkey_root, rp->key, rp->key_size); break; case CMD_OPEN_KEY: { char* key; HKEY newKey; /* * [HKEY(DWORD), KeyString(string)] */ hkey = (HKEY) get_int32(buf+0); rp->hkey_root = hkey; key = buf+4; result = RegOpenKeyEx(hkey, key, 0, rp->sam, &newKey); if (result == ERROR_SUCCESS) { RegCloseKey(rp->hkey); rp->hkey = newKey; driver_free(rp->key); rp->key_size = strlen(key); rp->key = driver_alloc(rp->key_size+1); strcpy(rp->key, key); } reply(rp, result); return; } break; case CMD_CREATE_KEY: { char* key; HKEY newKey; DWORD disposition; hkey = (HKEY) get_int32(buf+0); rp->hkey_root = hkey; key = buf+4; result = RegCreateKeyEx(hkey, key, 0, "", 0, rp->sam, NULL, &newKey, &disposition); if (result == ERROR_SUCCESS) { RegCloseKey(rp->hkey); rp->hkey = newKey; driver_free(rp->key); rp->key_size = strlen(key); rp->key = driver_alloc(rp->key_size+1); strcpy(rp->key, key); } reply(rp, result); return; } break; case CMD_GET_ALL_SUBKEYS: { int i; i = 0; for (;;) { nameSize = rp->name_buf_size; result = RegEnumKeyEx(rp->hkey, i, rp->name_buf, &nameSize, NULL, NULL, NULL, NULL); if (result == ERROR_MORE_DATA) { rp->name_buf_size *= 2; rp->name_buf = driver_realloc(rp->name_buf, rp->name_buf_size); continue; } else if (result == ERROR_NO_MORE_ITEMS) { reply(rp, ERROR_SUCCESS); return; } else if (result != ERROR_SUCCESS) { reply(rp, result); return; } key_reply(rp, rp->name_buf, nameSize); i++; } } break; case CMD_GET_VALUE: do { valueSize = rp->value_buf_size; result = RegQueryValueEx(rp->hkey, buf, NULL, &type, rp->value_buf, &valueSize); } while (!fix_value_result(rp, result, type, buf, strlen(buf), rp->value_buf, valueSize)); break; case CMD_GET_ALL_VALUES: { int i; i = 0; for (;;) { nameSize = rp->name_buf_size; valueSize = rp->value_buf_size; result = RegEnumValue(rp->hkey, i, rp->name_buf, &nameSize, NULL, &type, rp->value_buf, &valueSize); if (result == ERROR_NO_MORE_ITEMS) { reply(rp, ERROR_SUCCESS); return; } if (fix_value_result(rp, result, type, rp->name_buf, nameSize, rp->value_buf, valueSize)) { i++; } } } break; case CMD_SET_VALUE: { LPSTR name; DWORD dword; /* * [Type(DWORD), Name(string), Value(bytes)] */ type = get_int32(buf); buf += 4; count -= 4; name = buf; nameSize = strlen(buf) + 1; buf += nameSize; count -= nameSize; if (type == REG_DWORD) { /* * Must pass a pointer to a DWORD in host byte order. */ dword = get_int32(buf); buf = (char *) &dword; ASSERT(count == 4); } result = RegSetValueEx(rp->hkey, name, 0, type, buf, count); reply(rp, result); } break; case CMD_DELETE_KEY: result = RegDeleteKey(rp->hkey, NULL); reply(rp, result); break; case CMD_DELETE_VALUE: result = RegDeleteValue(rp->hkey, buf); reply(rp, result); break; } /* return 1; */}static BOOLfix_value_result(RegPort* rp, LONG result, DWORD type, LPSTR name, DWORD nameSize, LPSTR value, DWORD valueSize){ if (result == ERROR_MORE_DATA) { DWORD max_name1; DWORD max_name2; DWORD max_value; int ok; ok = RegQueryInfoKey(rp->hkey, NULL, NULL, NULL, NULL, &max_name1, NULL, NULL, &max_name2, &max_value, NULL, NULL);#ifdef DEBUG if (ok != ERROR_SUCCESS) { char buff[256]; sprintf(buff,"Failure in registry_drv line %d, error = %d", __LINE__, GetLastError()); MessageBox(NULL, buff, "Internal error", MB_OK); ASSERT(ok == ERROR_SUCCESS); }#endif rp->name_buf_size = (max_name1 > max_name2 ? max_name1 : max_name2) + 1; rp->value_buf_size = max_value + 1; rp->name_buf = driver_realloc(rp->name_buf, rp->name_buf_size); rp->value_buf = driver_realloc(rp->value_buf, rp->value_buf_size); return FALSE; } else if (result != ERROR_SUCCESS) { reply(rp, result); return TRUE; } /* * Do some data conversion which is easier to do here * than in Erlang. */ switch (type) { case REG_SZ: case REG_EXPAND_SZ: valueSize--; /* No reason to send the '\0' to Erlang. */ break; case REG_DWORD_LITTLE_ENDIAN: case REG_DWORD_BIG_ENDIAN: /* * The value is a DWORD stored in host byte order. * We must retrieve it and store it in network byte order. */ { DWORD dword = * ((DWORD *) value); put_int32(dword, value); type = REG_DWORD; /* Simplify life for Erlang code. */ break; } } return value_reply(rp, type, name, nameSize, value, valueSize);}/* * Sends one of the following replies back to Erlang, * depending on result: * * [$e|Posix error(string)] Error * [$o] Ok */static voidreply(RegPort* rp, LONG result){ char sbuf[256]; if (result == ERROR_SUCCESS) { sbuf[0] = 'o'; driver_output(rp->port, sbuf, 1); } else { char* s; char* t; int err; sbuf[0] = 'e'; err = maperror(result); for (s = erl_errno_id(err), t = sbuf+1; *s; s++, t++) { *t = tolower(*s); } driver_output(rp->port, sbuf, t-sbuf); } /* return 1; */}/* * Sends a key to Erlang: * * [$k, Keyname(string)] */static intkey_reply(RegPort* rp, /* Pointer to port structure. */ LPSTR name, /* Pointer to name. */ DWORD nameSize) /* Length of name. */{ char sbuf[512]; char* s = sbuf; int needed = 1+nameSize; if (sizeof sbuf < needed) { s = driver_alloc(needed); } s[0] = 'k'; memcpy(s+1, name, nameSize); driver_output(rp->port, s, needed); if (s != sbuf) { driver_free(s); } return 1;}/* * Sends a value to Erlang: * * [$v, Type(DWORD), Valuename(string), 0, Value(bytes)] */static intvalue_reply(RegPort* rp, /* Pointer to port structure. */ DWORD type, /* Type of value */ LPSTR name, /* Pointer to name. */ DWORD nameSize, /* Length of name. */ LPSTR value, /* Pointer to value. */ DWORD valueSize) /* Size of value. */{ char sbuf[512]; char* s = sbuf; int needed = 1+4+nameSize+1+valueSize; int i; if (sizeof sbuf < needed) { s = driver_alloc(needed); } s[0] = 'v'; i = 1; put_int32(type, s+i); i += 4; memcpy(s+i, name, nameSize); i += nameSize; s[i++] = '\0'; memcpy(s+i, value, valueSize); ASSERT(i+valueSize == needed); driver_output(rp->port, s, needed); if (s != sbuf) { driver_free(s); } return 1;}/* * Sends a key to Erlang: * * [$s, HKEY(DWORD), Keyname(string)] State */static intstate_reply(RegPort* rp, /* Pointer to port structure. */ HKEY root, /* Handle to root key for this key. */ LPSTR name, /* Pointer to name. */ DWORD nameSize) /* Length of name. */{ char sbuf[512]; char* s = sbuf; int needed = 1+4+nameSize; int i; if (sizeof sbuf < needed) { s = driver_alloc(needed); } s[0] = 's'; i = 1; put_int32((DWORD) root, s+i); i += 4; memcpy(s+i, name, nameSize); ASSERT(i+nameSize == needed); driver_output(rp->port, s, needed); if (s != sbuf) { driver_free(s); } return 1;}static intmaperror(DWORD error){ DEBUGF(("Mapping %d\n", error)); switch (error) { case ERROR_BADDB: case ERROR_BADKEY: case ERROR_CANTOPEN: case ERROR_CANTWRITE: case ERROR_REGISTRY_RECOVERED: case ERROR_REGISTRY_CORRUPT: case ERROR_REGISTRY_IO_FAILED: case ERROR_NOT_REGISTRY_FILE: return EIO; case ERROR_KEY_DELETED: return EINVAL; default: _dosmaperr(error); return errno; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?