/*
Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#include "glusterfs/dict.h"
#include "glusterfs/logging.h"
#include "glusterfs/byte-order.h"
#include "glusterfs/quota-common-utils.h"
#include "glusterfs/common-utils.h"
#include "glusterfs/libglusterfs-messages.h"
gf_boolean_t
quota_meta_is_null(const quota_meta_t *meta)
{
if (meta->size == 0 && meta->file_count == 0 && meta->dir_count == 0)
return _gf_true;
return _gf_false;
}
int32_t
quota_data_to_meta(data_t *data, quota_meta_t *meta)
{
int32_t ret = -1;
quota_meta_t *value = NULL;
int64_t *size = NULL;
if (!data || !meta)
goto out;
if (data->len > sizeof(int64_t)) {
value = (quota_meta_t *)data->data;
meta->size = ntoh64(value->size);
meta->file_count = ntoh64(value->file_count);
if (data->len > (sizeof(int64_t)) * 2)
meta->dir_count = ntoh64(value->dir_count);
else
meta->dir_count = 0;
} else {
size = (int64_t *)data->data;
meta->size = ntoh64(*size);
meta->file_count = 0;
meta->dir_count = 0;
/* This can happen during software upgrade.
* Older version of glusterfs will not have inode count.
* Return failure, this will be healed as part of lookup
*/
gf_msg_callingfn("quota", GF_LOG_DEBUG, 0, LG_MSG_QUOTA_XATTRS_MISSING,
"Object quota "
"xattrs missing: len = %d",
data->len);
ret = -2;
goto out;
}
ret = 0;
out:
return ret;
}
int32_t
quota_dict_get_inode_meta(dict_t *dict, char *key, const int keylen,
quota_meta_t *meta)
{
int32_t ret = -1;
data_t *data = NULL;
if (!dict || !key || !meta)
goto out;
data = dict_getn(dict, key, keylen);
if (!data || !data->data)
goto out;
ret = quota_data_to_meta(data, meta);
out:
return ret;
}
int32_t
quota_dict_get_meta(dict_t *dict, char *key, const int keylen,
quota_meta_t *meta)
{
int32_t ret = -1;
ret = quota_dict_get_inode_meta(dict, key, keylen, meta);
if (ret == -2)
ret = 0;
return ret;
}
int32_t
quota_dict_set_meta(dict_t *dict, char *key, const quota_meta_t *meta,
ia_type_t ia_type)
{
int32_t ret = -ENOMEM;
quota_meta_t *value = NULL;
value = GF_MALLOC(sizeof(quota_meta_t), gf_common_quota_meta_t);
if (value == NULL) {
goto out;
}
value->size = hton64(meta->size);
value->file_count = hton64(meta->file_count);
value->dir_count = hton64(meta->dir_count);
if (ia_type == IA_IFDIR) {
ret = dict_set_bin(dict, key, value, sizeof(*value));
} else {
/* For a file we don't need to store dir_count in the
* quota size xattr, so we set the len of the data in the dict
* as 128bits, so when the posix xattrop reads the dict, it only
* performs operations on size and file_count
*/
ret = dict_set_bin(dict, key, value, sizeof(*value) - sizeof(int64_t));
}
if (ret < 0) {
gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_DICT_SET_FAILED,
"dict set failed");
GF_FREE(value);
}
out:
return ret;
}
int32_t
quota_conf_read_header(int fd, char *buf)
{
int ret = 0;
const int header_len = SLEN(QUOTA_CONF_HEADER);
ret = gf_nread(fd, buf, header_len);
if (ret <= 0) {
goto out;
} else if (ret > 0 && ret != header_len) {
ret = -1;
goto out;
}
buf[header_len - 1] = 0;
out:
if (ret < 0)
gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR,
"failed to read "
"header from a quota conf");
return ret;
}
int32_t
quota_conf_read_version(int fd, float *version)
{
int ret = 0;
char buf[PATH_MAX] = "";
char *tail = NULL;
float value = 0.0f;
ret = quota_conf_read_header(fd, buf);
if (ret == 0) {
/* quota.conf is empty */
value = GF_QUOTA_CONF_VERSION;
goto out;
} else if (ret < 0) {
goto out;
}
value = strtof((buf + strlen(buf) - 3), &tail);
if (tail[0] != '\0') {
ret = -1;
gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR,
"invalid quota conf"
" version");
goto out;
}
ret = 0;
out:
if (ret >= 0)
*version = value;
else
gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR,
"failed to "
"read version from a quota conf header");
return ret;
}
int32_t
quota_conf_read_gfid(int fd, void *buf, char *type, float version)
{
int ret = 0;
ret = gf_nread(fd, buf, 16);
if (ret <= 0)
goto out;
if (ret != 16) {
ret = -1;
goto out;
}
if (version >= 1.2f) {
ret = gf_nread(fd, type, 1);
if (ret != 1) {
ret = -1;
goto out;
}
ret = 17;
} else {
*type = GF_QUOTA_CONF_TYPE_USAGE;
}
out:
if (ret < 0)
gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR,
"failed to "
"read gfid from a quota conf");
return ret;
}
int32_t
quota_conf_skip_header(int fd)
{
return gf_skip_header_section(fd, strlen(QUOTA_CONF_HEADER));
}