/* Copyright (c) 2015 Red Hat, Inc. 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)); }