Btrfs-progs: fix possible memory leak related to subvolume/snapshot creation
[platform/upstream/btrfs-progs.git] / qgroup.c
1 /*
2  * Copyright (C) 2012 STRATO.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include "qgroup.h"
20 #include "ctree.h"
21
22 u64 parse_qgroupid(char *p)
23 {
24         char *s = strchr(p, '/');
25         char *ptr_src_end = p + strlen(p);
26         char *ptr_parse_end = NULL;
27         u64 level;
28         u64 id;
29
30         if (!s) {
31                 id = strtoull(p, &ptr_parse_end, 10);
32                 if (ptr_parse_end != ptr_src_end)
33                         goto err;
34                 return id;
35         }
36         level = strtoull(p, &ptr_parse_end, 10);
37         if (ptr_parse_end != s)
38                 goto err;
39
40         id = strtoull(s+1, &ptr_parse_end, 10);
41         if (ptr_parse_end != ptr_src_end)
42                 goto  err;
43
44         return (level << 48) | id;
45 err:
46         fprintf(stderr, "ERROR:invalid qgroupid\n");
47         exit(-1);
48 }
49
50 int qgroup_inherit_size(struct btrfs_qgroup_inherit *p)
51 {
52         return sizeof(*p) + sizeof(p->qgroups[0]) *
53                             (p->num_qgroups + 2 * p->num_ref_copies +
54                              2 * p->num_excl_copies);
55 }
56
57 int qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n,
58                            int pos)
59 {
60         struct btrfs_qgroup_inherit *out;
61         int nitems = 0;
62
63         if (*inherit) {
64                 nitems = (*inherit)->num_qgroups +
65                          (*inherit)->num_ref_copies +
66                          (*inherit)->num_excl_copies;
67         }
68
69         out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1);
70         if (out == NULL) {
71                 fprintf(stderr, "ERROR: Not enough memory\n");
72                 return 13;
73         }
74
75         if (*inherit) {
76                 struct btrfs_qgroup_inherit *i = *inherit;
77                 int s = sizeof(out->qgroups);
78
79                 out->num_qgroups = i->num_qgroups;
80                 out->num_ref_copies = i->num_ref_copies;
81                 out->num_excl_copies = i->num_excl_copies;
82                 memcpy(out->qgroups, i->qgroups, pos * s);
83                 memcpy(out->qgroups + pos + n, i->qgroups + pos,
84                        (nitems - pos) * s);
85         }
86         free(*inherit);
87         *inherit = out;
88
89         return 0;
90 }
91
92 int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg)
93 {
94         int ret;
95         u64 qgroupid = parse_qgroupid(arg);
96         int pos = 0;
97
98         if (qgroupid == 0) {
99                 fprintf(stderr, "ERROR: bad qgroup specification\n");
100                 return 12;
101         }
102
103         if (*inherit)
104                 pos = (*inherit)->num_qgroups;
105         ret = qgroup_inherit_realloc(inherit, 1, pos);
106         if (ret)
107                 return ret;
108
109         (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid;
110
111         return 0;
112 }
113
114 int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg,
115                             int type)
116 {
117         int ret;
118         u64 qgroup_src;
119         u64 qgroup_dst;
120         char *p;
121         int pos = 0;
122
123         p = strchr(arg, ':');
124         if (!p) {
125 bad:
126                 fprintf(stderr, "ERROR: bad copy specification\n");
127                 return 12;
128         }
129         *p = 0;
130         qgroup_src = parse_qgroupid(arg);
131         qgroup_dst = parse_qgroupid(p + 1);
132         *p = ':';
133
134         if (!qgroup_src || !qgroup_dst)
135                 goto bad;
136
137         if (*inherit)
138                 pos = (*inherit)->num_qgroups +
139                       (*inherit)->num_ref_copies * 2 * type;
140
141         ret = qgroup_inherit_realloc(inherit, 2, pos);
142         if (ret)
143                 return ret;
144
145         (*inherit)->qgroups[pos++] = qgroup_src;
146         (*inherit)->qgroups[pos++] = qgroup_dst;
147
148         if (!type)
149                 ++(*inherit)->num_ref_copies;
150         else
151                 ++(*inherit)->num_excl_copies;
152
153         return 0;
154 }