diff options
Diffstat (limited to 'win32/registry.c')
-rw-r--r-- | win32/registry.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/win32/registry.c b/win32/registry.c new file mode 100644 index 0000000..685a09d --- /dev/null +++ b/win32/registry.c @@ -0,0 +1,297 @@ +#include "php.h" +#include "php_ini.h" +#include "php_win32_globals.h" + +#define PHP_REGISTRY_KEY "SOFTWARE\\PHP" + +#define PHP_VER1(V1) #V1 +#define PHP_VER2(V1,V2) #V1"."#V2 +#define PHP_VER3(V1,V2,V3) #V1"."#V2"."#V3 + +#define PHP_REGISTRY_KEYV(VER) PHP_REGISTRY_KEY"\\"VER +#define PHP_REGISTRY_KEY1(V1) PHP_REGISTRY_KEY"\\"PHP_VER1(V1) +#define PHP_REGISTRY_KEY2(V1,V2) PHP_REGISTRY_KEY"\\"PHP_VER2(V1,V2) +#define PHP_REGISTRY_KEY3(V1,V2,V3) PHP_REGISTRY_KEY"\\"PHP_VER3(V1,V2,V3) + +static const char* registry_keys[] = { + PHP_REGISTRY_KEYV(PHP_VERSION), + PHP_REGISTRY_KEY3(PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION), + PHP_REGISTRY_KEY2(PHP_MAJOR_VERSION, PHP_MINOR_VERSION), + PHP_REGISTRY_KEY1(PHP_MAJOR_VERSION), + PHP_REGISTRY_KEY, + NULL +}; + +static int OpenPhpRegistryKey(char* sub_key, HKEY *hKey) +{ + const char **key_name = registry_keys; + + if (sub_key) { + int main_key_len; + int sub_key_len = strlen(sub_key); + char *reg_key; + + while (*key_name) { + LONG ret; + + main_key_len = strlen(*key_name); + reg_key = emalloc(main_key_len + sub_key_len + 1); + memcpy(reg_key, *key_name, main_key_len); + memcpy(reg_key + main_key_len, sub_key, sub_key_len + 1); + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_key, 0, KEY_READ, hKey); + efree(reg_key); + + if (ret == ERROR_SUCCESS) { + return 1; + } + ++key_name; + } + } else { + while (*key_name) { + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, *key_name, 0, KEY_READ, hKey) == ERROR_SUCCESS) { + return 1; + } + ++key_name; + } + } + return 0; +} + +static int LoadDirectory(HashTable *directories, HKEY key, char *path, int path_len, HashTable *parent_ht) +{ + DWORD keys, values, max_key, max_name, max_value; + int ret = 0; + HashTable *ht = NULL; + + if (RegQueryInfoKey(key, NULL, NULL, NULL, &keys, &max_key, NULL, &values, &max_name, &max_value, NULL, NULL) == ERROR_SUCCESS) { + + if (values) { + DWORD i; + char *name = (char*)emalloc(max_name+1); + char *value = (char*)emalloc(max_value+1); + DWORD name_len, type, value_len; + zval *data; + + for (i = 0; i < values; i++) { + name_len = max_name+1; + value_len = max_value+1; + if (RegEnumValue(key, i, name, &name_len, NULL, &type, value, &value_len) == ERROR_SUCCESS) { + if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) { + if (!ht) { + ht = (HashTable*)malloc(sizeof(HashTable)); + if (!ht) { + return ret; + } + zend_hash_init(ht, 0, NULL, ZVAL_INTERNAL_PTR_DTOR, 1); + } + data = (zval*)malloc(sizeof(zval)); + if (!data) { + return ret; + } + INIT_PZVAL(data); + Z_STRVAL_P(data) = zend_strndup(value, value_len-1); + Z_STRLEN_P(data) = value_len-1; + Z_TYPE_P(data) = IS_STRING; + zend_hash_update(ht, name, name_len+1, &data, sizeof(zval*), NULL); + } + } + } + if (ht) { + if (parent_ht) { + HashPosition pos; + char *index; + uint index_len; + ulong num; + zval **tmpdata; + + for (zend_hash_internal_pointer_reset_ex(parent_ht, &pos); + zend_hash_get_current_data_ex(parent_ht, (void**)&tmpdata, &pos) == SUCCESS && + zend_hash_get_current_key_ex(parent_ht, &index, &index_len, &num, 0, &pos) == HASH_KEY_IS_STRING; + zend_hash_move_forward_ex(parent_ht, &pos)) { + if (zend_hash_add(ht, index, index_len, tmpdata, sizeof(zval*), NULL) == SUCCESS) { + Z_ADDREF_PP(tmpdata); + } + } + } + zend_hash_update(directories, path, path_len+1, &ht, sizeof(HashTable*), NULL); + ret = 1; + } + + efree(name); + efree(value); + } + + if (ht == NULL) { + ht = parent_ht; + } + + if (keys) { + DWORD i; + char *name = (char*)emalloc(max_key+1); + char *new_path = (char*)emalloc(path_len+max_key+2); + DWORD name_len; + FILETIME t; + HKEY subkey; + + for (i = 0; i < keys; i++) { + name_len = max_key+1; + if (RegEnumKeyEx(key, i, name, &name_len, NULL, NULL, NULL, &t) == ERROR_SUCCESS) { + if (RegOpenKeyEx(key, name, 0, KEY_READ, &subkey) == ERROR_SUCCESS) { + if (path_len) { + memcpy(new_path, path, path_len); + new_path[path_len] = '/'; + memcpy(new_path+path_len+1, name, name_len+1); + zend_str_tolower(new_path, path_len+name_len+1); + name_len += path_len+1; + } else { + memcpy(new_path, name, name_len+1); + zend_str_tolower(new_path, name_len); + } + if (LoadDirectory(directories, subkey, new_path, name_len, ht)) { + ret = 1; + } + RegCloseKey(subkey); + } + } + } + efree(new_path); + efree(name); + } + } + return ret; +} + +static void delete_internal_hashtable(void *data) +{ + zend_hash_destroy(*(HashTable**)data); + free(*(HashTable**)data); +} + +#define RegNotifyFlags (REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET) + +void UpdateIniFromRegistry(char *path TSRMLS_DC) +{ + char *p, *orig_path; + int path_len; + HashTable **pht; + + if(!path) { + return; + } + + if (!PW32G(registry_directories)) { + PW32G(registry_directories) = (HashTable*)malloc(sizeof(HashTable)); + if (!PW32G(registry_directories)) { + return; + } + zend_hash_init(PW32G(registry_directories), 0, NULL, delete_internal_hashtable, 1); + if (!OpenPhpRegistryKey("\\Per Directory Values", &PW32G(registry_key))) { + PW32G(registry_key) = NULL; + return; + } + PW32G(registry_event) = CreateEvent(NULL, TRUE, FALSE, NULL); + if (PW32G(registry_event)) { + RegNotifyChangeKeyValue(PW32G(registry_key), TRUE, RegNotifyFlags, PW32G(registry_event), TRUE); + } + if (!LoadDirectory(PW32G(registry_directories), PW32G(registry_key), "", 0, NULL)) { + return; + } + } else if (PW32G(registry_event) && WaitForSingleObject(PW32G(registry_event), 0) == WAIT_OBJECT_0) { + RegNotifyChangeKeyValue(PW32G(registry_key), TRUE, RegNotifyFlags, PW32G(registry_event), TRUE); + zend_hash_clean(PW32G(registry_directories)); + if (!LoadDirectory(PW32G(registry_directories), PW32G(registry_key), "", 0, NULL)) { + return; + } + } else if (zend_hash_num_elements(PW32G(registry_directories)) == 0) { + return; + } + + orig_path = path = estrdup(path); + + /* Get rid of C:, if exists */ + p = strchr(path, ':'); + if (p) { + *p = path[0]; /* replace the colon with the drive letter */ + path = p; /* make path point to the drive letter */ + } else { + if (path[0] != '\\' && path[0] != '/') { + char tmp_buf[MAXPATHLEN], *cwd; + char drive_letter; + + /* get current working directory and prepend it to the path */ + if (!VCWD_GETCWD(tmp_buf, MAXPATHLEN)) { + efree(orig_path); + return; + } + cwd = strchr(tmp_buf, ':'); + if (!cwd) { + drive_letter = 'C'; + cwd = tmp_buf; + } else { + drive_letter = tmp_buf[0]; + cwd++; + } + while (*cwd == '\\' || *cwd == '/') { + cwd++; + } + spprintf(&path, 0, "%c\\%s\\%s", drive_letter, cwd, orig_path); + efree(orig_path); + orig_path = path; + } + } + + path_len = 0; + while (path[path_len] != 0) { + if (path[path_len] == '\\') { + path[path_len] = '/'; + } + path_len++; + } + zend_str_tolower(path, path_len); + while (path_len >= 0) { + if (zend_hash_find(PW32G(registry_directories), path, path_len+1, (void**)&pht) == SUCCESS) { + HashTable *ht = *pht; + HashPosition pos; + char *index; + uint index_len; + ulong num; + zval **data; + + for (zend_hash_internal_pointer_reset_ex(ht, &pos); + zend_hash_get_current_data_ex(ht, (void**)&data, &pos) == SUCCESS && + zend_hash_get_current_key_ex(ht, &index, &index_len, &num, 0, &pos) == HASH_KEY_IS_STRING; + zend_hash_move_forward_ex(ht, &pos)) { + zend_alter_ini_entry(index, index_len, Z_STRVAL_PP(data), Z_STRLEN_PP(data), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); + } + break; + } + if (--path_len > 0) { + while (path_len > 0 && path[path_len] != '/') { + path_len--; + } + } + path[path_len] = 0; + } + + efree(orig_path); +} + +#define PHPRC_REGISTRY_NAME "IniFilePath" + +char *GetIniPathFromRegistry() +{ + char *reg_location = NULL; + HKEY hKey; + + if (OpenPhpRegistryKey(NULL, &hKey)) { + DWORD buflen = MAXPATHLEN; + reg_location = emalloc(MAXPATHLEN+1); + if(RegQueryValueEx(hKey, PHPRC_REGISTRY_NAME, 0, NULL, reg_location, &buflen) != ERROR_SUCCESS) { + efree(reg_location); + reg_location = NULL; + return reg_location; + } + RegCloseKey(hKey); + } + return reg_location; +} |