/* * Copyright (C) 2012 STRATO. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "qgroup.h" #include "ctree.h" u64 parse_qgroupid(char *p) { char *s = strchr(p, '/'); char *ptr_src_end = p + strlen(p); char *ptr_parse_end = NULL; u64 level; u64 id; if (!s) { id = strtoull(p, &ptr_parse_end, 10); if (ptr_parse_end != ptr_src_end) goto err; return id; } level = strtoull(p, &ptr_parse_end, 10); if (ptr_parse_end != s) goto err; id = strtoull(s+1, &ptr_parse_end, 10); if (ptr_parse_end != ptr_src_end) goto err; return (level << 48) | id; err: fprintf(stderr, "ERROR:invalid qgroupid\n"); exit(-1); } int qgroup_inherit_size(struct btrfs_qgroup_inherit *p) { return sizeof(*p) + sizeof(p->qgroups[0]) * (p->num_qgroups + 2 * p->num_ref_copies + 2 * p->num_excl_copies); } int qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos) { struct btrfs_qgroup_inherit *out; int nitems = 0; if (*inherit) { nitems = (*inherit)->num_qgroups + (*inherit)->num_ref_copies + (*inherit)->num_excl_copies; } out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1); if (out == NULL) { fprintf(stderr, "ERROR: Not enough memory\n"); return 13; } if (*inherit) { struct btrfs_qgroup_inherit *i = *inherit; int s = sizeof(out->qgroups); out->num_qgroups = i->num_qgroups; out->num_ref_copies = i->num_ref_copies; out->num_excl_copies = i->num_excl_copies; memcpy(out->qgroups, i->qgroups, pos * s); memcpy(out->qgroups + pos + n, i->qgroups + pos, (nitems - pos) * s); } free(*inherit); *inherit = out; return 0; } int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg) { int ret; u64 qgroupid = parse_qgroupid(arg); int pos = 0; if (qgroupid == 0) { fprintf(stderr, "ERROR: bad qgroup specification\n"); return 12; } if (*inherit) pos = (*inherit)->num_qgroups; ret = qgroup_inherit_realloc(inherit, 1, pos); if (ret) return ret; (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid; return 0; } int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg, int type) { int ret; u64 qgroup_src; u64 qgroup_dst; char *p; int pos = 0; p = strchr(arg, ':'); if (!p) { bad: fprintf(stderr, "ERROR: bad copy specification\n"); return 12; } *p = 0; qgroup_src = parse_qgroupid(arg); qgroup_dst = parse_qgroupid(p + 1); *p = ':'; if (!qgroup_src || !qgroup_dst) goto bad; if (*inherit) pos = (*inherit)->num_qgroups + (*inherit)->num_ref_copies * 2 * type; ret = qgroup_inherit_realloc(inherit, 2, pos); if (ret) return ret; (*inherit)->qgroups[pos++] = qgroup_src; (*inherit)->qgroups[pos++] = qgroup_dst; if (!type) ++(*inherit)->num_ref_copies; else ++(*inherit)->num_excl_copies; return 0; }