1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-25 06:04:04 +03:00
Jelmer Vernooij 85d60d2d09 registry: Improve error codes and update tests.
Rather than map the error returned by the registry to the correct error,
return the correct error in the first place.

Also deal with the fact that the right error code is now returned in a
couple of places.
(This used to be commit 1e31fcb8a097810a97e2d4bb1f243f1b34cc2415)
2008-01-18 03:41:59 +01:00

362 lines
8.3 KiB
C

/*
Unix SMB/CIFS implementation.
Registry interface
Copyright (C) Jelmer Vernooij 2004-2007.
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 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "hive.h"
#include "system/dir.h"
#include "system/filesys.h"
struct dir_key {
struct hive_key key;
const char *path;
};
static struct hive_operations reg_backend_dir;
static WERROR reg_dir_add_key(TALLOC_CTX *mem_ctx,
const struct hive_key *parent,
const char *name, const char *classname,
struct security_descriptor *desc,
struct hive_key **result)
{
struct dir_key *dk = talloc_get_type(parent, struct dir_key);
char *path;
int ret;
path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
ret = mkdir(path, 0700);
if (ret == 0) {
struct dir_key *key = talloc(mem_ctx, struct dir_key);
key->key.ops = &reg_backend_dir;
key->path = talloc_steal(key, path);
*result = (struct hive_key *)key;
return WERR_OK;
}
if (errno == EEXIST)
return WERR_ALREADY_EXISTS;
printf("FAILED %s BECAUSE: %s\n", path, strerror(errno));
return WERR_GENERAL_FAILURE;
}
static WERROR reg_dir_del_key(const struct hive_key *k, const char *name)
{
struct dir_key *dk = talloc_get_type(k, struct dir_key);
char *child = talloc_asprintf(NULL, "%s/%s", dk->path, name);
WERROR ret;
if (rmdir(child) == 0)
ret = WERR_OK;
else if (errno == ENOENT)
ret = WERR_NOT_FOUND;
else
ret = WERR_GENERAL_FAILURE;
talloc_free(child);
return ret;
}
static WERROR reg_dir_open_key(TALLOC_CTX *mem_ctx,
const struct hive_key *parent,
const char *name, struct hive_key **subkey)
{
DIR *d;
char *fullpath;
const struct dir_key *p = talloc_get_type(parent, struct dir_key);
struct dir_key *ret;
if (name == NULL) {
DEBUG(0, ("NULL pointer passed as directory name!"));
return WERR_INVALID_PARAM;
}
fullpath = talloc_asprintf(mem_ctx, "%s/%s", p->path, name);
d = opendir(fullpath);
if (d == NULL) {
DEBUG(3,("Unable to open '%s': %s\n", fullpath,
strerror(errno)));
return WERR_BADFILE;
}
closedir(d);
ret = talloc(mem_ctx, struct dir_key);
ret->key.ops = &reg_backend_dir;
ret->path = talloc_steal(ret, fullpath);
*subkey = (struct hive_key *)ret;
return WERR_OK;
}
static WERROR reg_dir_key_by_index(TALLOC_CTX *mem_ctx,
const struct hive_key *k, uint32_t idx,
const char **name,
const char **classname,
NTTIME *last_mod_time)
{
struct dirent *e;
const struct dir_key *dk = talloc_get_type(k, struct dir_key);
int i = 0;
DIR *d;
d = opendir(dk->path);
if (d == NULL)
return WERR_INVALID_PARAM;
while((e = readdir(d))) {
if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
struct stat stbuf;
char *thispath;
/* Check if file is a directory */
asprintf(&thispath, "%s/%s", dk->path, e->d_name);
stat(thispath, &stbuf);
if (!S_ISDIR(stbuf.st_mode)) {
SAFE_FREE(thispath);
continue;
}
if (i == idx) {
struct stat st;
*name = talloc_strdup(mem_ctx, e->d_name);
*classname = NULL;
stat(thispath, &st);
unix_to_nt_time(last_mod_time, st.st_mtime);
SAFE_FREE(thispath);
closedir(d);
return WERR_OK;
}
i++;
SAFE_FREE(thispath);
}
}
closedir(d);
return WERR_NO_MORE_ITEMS;
}
WERROR reg_open_directory(TALLOC_CTX *parent_ctx,
const char *location, struct hive_key **key)
{
struct dir_key *dk;
if (location == NULL)
return WERR_INVALID_PARAM;
dk = talloc(parent_ctx, struct dir_key);
dk->key.ops = &reg_backend_dir;
dk->path = talloc_strdup(dk, location);
*key = (struct hive_key *)dk;
return WERR_OK;
}
WERROR reg_create_directory(TALLOC_CTX *parent_ctx,
const char *location, struct hive_key **key)
{
if (mkdir(location, 0700) != 0) {
*key = NULL;
return WERR_GENERAL_FAILURE;
}
return reg_open_directory(parent_ctx, location, key);
}
static WERROR reg_dir_get_info(TALLOC_CTX *ctx, const struct hive_key *key,
const char **classname,
uint32_t *num_subkeys,
uint32_t *num_values,
NTTIME *lastmod,
uint32_t *max_subkeynamelen,
uint32_t *max_valnamelen,
uint32_t *max_valbufsize)
{
DIR *d;
const struct dir_key *dk = talloc_get_type(key, struct dir_key);
struct dirent *e;
struct stat st;
SMB_ASSERT(key != NULL);
if (classname != NULL)
*classname = NULL;
d = opendir(dk->path);
if (d == NULL)
return WERR_INVALID_PARAM;
if (num_subkeys != NULL)
*num_subkeys = 0;
if (num_values != NULL)
*num_values = 0;
if (max_subkeynamelen != NULL)
*max_subkeynamelen = 0;
if (max_valnamelen != NULL)
*max_valnamelen = 0;
if (max_valbufsize != NULL)
*max_valbufsize = 0;
while((e = readdir(d))) {
if(!ISDOT(e->d_name) && !ISDOTDOT(e->d_name)) {
char *path = talloc_asprintf(ctx, "%s/%s",
dk->path, e->d_name);
if (stat(path, &st) < 0) {
DEBUG(0, ("Error statting %s: %s\n", path,
strerror(errno)));
continue;
}
if (S_ISDIR(st.st_mode)) {
if (num_subkeys != NULL)
(*num_subkeys)++;
if (max_subkeynamelen != NULL)
*max_subkeynamelen = MAX(*max_subkeynamelen, strlen(e->d_name));
}
if (!S_ISDIR(st.st_mode)) {
if (num_values != NULL)
(*num_values)++;
if (max_valnamelen != NULL)
*max_valnamelen = MAX(*max_valnamelen, strlen(e->d_name));
if (max_valbufsize != NULL)
*max_valbufsize = MAX(*max_valbufsize, st.st_size);
}
talloc_free(path);
}
}
closedir(d);
if (lastmod != NULL)
*lastmod = 0;
return WERR_OK;
}
static WERROR reg_dir_set_value(struct hive_key *key, const char *name,
uint32_t type, const DATA_BLOB data)
{
const struct dir_key *dk = talloc_get_type(key, struct dir_key);
char *path = talloc_asprintf(dk, "%s/%s", dk->path, name);
if (!file_save(path, data.data, data.length))
return WERR_GENERAL_FAILURE;
/* FIXME: Type */
return WERR_OK;
}
static WERROR reg_dir_get_value(TALLOC_CTX *mem_ctx,
struct hive_key *key, const char *name,
uint32_t *type, DATA_BLOB *data)
{
const struct dir_key *dk = talloc_get_type(key, struct dir_key);
char *path = talloc_asprintf(mem_ctx, "%s/%s", dk->path, name);
size_t size;
char *contents;
contents = file_load(path, &size, mem_ctx);
talloc_free(path);
if (contents == NULL)
return WERR_BADFILE;
if (type != NULL)
*type = 4; /* FIXME */
data->data = (uint8_t *)contents;
data->length = size;
return WERR_OK;
}
static WERROR reg_dir_enum_value(TALLOC_CTX *mem_ctx,
struct hive_key *key, int idx,
const char **name,
uint32_t *type, DATA_BLOB *data)
{
const struct dir_key *dk = talloc_get_type(key, struct dir_key);
DIR *d;
struct dirent *e;
int i;
d = opendir(dk->path);
if (d == NULL) {
DEBUG(3,("Unable to open '%s': %s\n", dk->path,
strerror(errno)));
return WERR_BADFILE;
}
i = 0;
while((e = readdir(d))) {
if (ISDOT(e->d_name) || ISDOTDOT(e->d_name))
continue;
if (i == idx) {
if (name != NULL)
*name = talloc_strdup(mem_ctx, e->d_name);
W_ERROR_NOT_OK_RETURN(reg_dir_get_value(mem_ctx, key,
*name, type,
data));
return WERR_OK;
}
i++;
}
closedir(d);
return WERR_NO_MORE_ITEMS;
}
static WERROR reg_dir_del_value (struct hive_key *key, const char *name)
{
const struct dir_key *dk = talloc_get_type(key, struct dir_key);
char *path = talloc_asprintf(key, "%s/%s", dk->path, name);
if (unlink(path) < 0) {
talloc_free(path);
if (errno == ENOENT)
return WERR_NOT_FOUND;
return WERR_GENERAL_FAILURE;
}
talloc_free(path);
return WERR_OK;
}
static struct hive_operations reg_backend_dir = {
.name = "dir",
.get_key_by_name = reg_dir_open_key,
.get_key_info = reg_dir_get_info,
.add_key = reg_dir_add_key,
.del_key = reg_dir_del_key,
.enum_key = reg_dir_key_by_index,
.set_value = reg_dir_set_value,
.get_value_by_name = reg_dir_get_value,
.enum_value = reg_dir_enum_value,
.delete_value = reg_dir_del_value,
};