]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/cdb.cc
Better (actual) fix for leak reported by Coverity.
[thirdparty/pdns.git] / pdns / cdb.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
ddee6d08 25
b4aac52a
RG
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30
31#include "cdb.hh"
ddee6d08
PD
32
33CDB::CDB(const string &cdbfile)
34{
9153c7cf
AT
35 d_fd = open(cdbfile.c_str(), O_RDONLY);
36 if (d_fd < 0)
37 {
90fe8ae6 38 throw std::runtime_error("Failed to open cdb database file '"+cdbfile+"': " + stringerror());
9153c7cf
AT
39 }
40
d9b78c0a 41 memset(&d_cdbf,0,sizeof(struct cdb_find));
9153c7cf
AT
42 int cdbinit = cdb_init(&d_cdb, d_fd);
43 if (cdbinit < 0)
44 {
b4aac52a
RG
45 close(d_fd);
46 d_fd = -1;
90fe8ae6 47 throw std::runtime_error("Failed to initialize cdb structure for database '+cdbfile+': '" + std::to_string(cdbinit) + "'");
9153c7cf 48 }
ddee6d08
PD
49}
50
51CDB::~CDB() {
9153c7cf
AT
52 cdb_free(&d_cdb);
53 close(d_fd);
ddee6d08
PD
54}
55
56int CDB::searchKey(const string &key) {
9153c7cf 57 d_searchType = SearchKey;
ddee6d08 58
9153c7cf
AT
59 // A 'bug' in tinycdb (the lib used for reading the CDB files) means we have to copy the key because the cdb_find struct
60 // keeps a pointer to it.
b4aac52a
RG
61 d_key = key;
62 return cdb_findinit(&d_cdbf, &d_cdb, d_key.c_str(), d_key.size());
ddee6d08
PD
63}
64
65bool CDB::searchSuffix(const string &key) {
9153c7cf 66 d_searchType = SearchSuffix;
ddee6d08 67
9153c7cf 68 //See CDB::searchKey()
b4aac52a 69 d_key = key;
ddee6d08 70
9153c7cf 71 // We are ok with a search on things, but we do want to know if a record with that key exists.........
b4aac52a 72 bool hasDomain = (cdb_find(&d_cdb, d_key.c_str(), d_key.size()) == 1);
9153c7cf
AT
73 if (hasDomain) {
74 cdb_seqinit(&d_seqPtr, &d_cdb);
75 }
ddee6d08 76
9153c7cf 77 return hasDomain;
ddee6d08
PD
78}
79
80void CDB::searchAll() {
9153c7cf
AT
81 d_searchType = SearchAll;
82 cdb_seqinit(&d_seqPtr, &d_cdb);
ddee6d08
PD
83}
84
85bool CDB::moveToNext() {
9153c7cf
AT
86 int hasNext = 0;
87 if (d_searchType == SearchKey) {
88 hasNext = cdb_findnext(&d_cdbf);
89 } else {
90 hasNext = cdb_seqnext(&d_seqPtr, &d_cdb);
91 }
92 return (hasNext > 0);
ddee6d08
PD
93}
94
95bool CDB::readNext(pair<string, string> &value) {
9153c7cf
AT
96 while (moveToNext()) {
97 unsigned int pos;
98 unsigned int len;
99
100 pos = cdb_keypos(&d_cdb);
101 len = cdb_keylen(&d_cdb);
102
b4aac52a
RG
103 std::string key;
104 key.resize(len);
90fe8ae6
RG
105 int ret = cdb_read(&d_cdb, &key[0], len, pos);
106 if (ret < 0) {
107 throw std::runtime_error("Error while reading key for key '" + key + "' from CDB database: " + std::to_string(ret));
108 }
9153c7cf
AT
109
110 if (d_searchType == SearchSuffix) {
b4aac52a
RG
111 char *p = strstr(const_cast<char*>(key.c_str()), d_key.c_str());
112 if (p == nullptr) {
9153c7cf
AT
113 continue;
114 }
115 }
9153c7cf
AT
116
117 pos = cdb_datapos(&d_cdb);
118 len = cdb_datalen(&d_cdb);
b4aac52a
RG
119 std::string val;
120 val.resize(len);
90fe8ae6
RG
121 ret = cdb_read(&d_cdb, &val[0], len, pos);
122 if (ret < 0) {
123 throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(ret));
124 }
9153c7cf 125
b4aac52a 126 value = make_pair(std::move(key), std::move(val));
9153c7cf
AT
127 return true;
128 }
b4aac52a 129
9153c7cf
AT
130 // We're done searching, so we can clean up d_key
131 if (d_searchType != SearchAll) {
b4aac52a 132 d_key.clear();
9153c7cf 133 }
b4aac52a 134
9153c7cf 135 return false;
ddee6d08
PD
136}
137
ddee6d08
PD
138vector<string> CDB::findall(string &key)
139{
9153c7cf
AT
140 vector<string> ret;
141 struct cdb_find cdbf;
142
90fe8ae6
RG
143 int res = cdb_findinit(&cdbf, &d_cdb, key.c_str(), key.size());
144 if (res < 0) {
145 throw std::runtime_error("Error looking up key '" + key + "' from CDB database: " + std::to_string(res));
146 }
147
9153c7cf
AT
148 int x=0;
149 while(cdb_findnext(&cdbf) > 0) {
150 x++;
151 unsigned int vpos = cdb_datapos(&d_cdb);
152 unsigned int vlen = cdb_datalen(&d_cdb);
b4aac52a
RG
153 std::string val;
154 val.resize(vlen);
90fe8ae6
RG
155 res = cdb_read(&d_cdb, &val[0], vlen, vpos);
156 if (res < 0) {
157 throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(res));
158 }
b4aac52a 159 ret.push_back(std::move(val));
9153c7cf 160 }
b4aac52a 161
9153c7cf 162 return ret;
ddee6d08 163}
90fe8ae6 164
73e1f0c5 165bool CDB::keyExists(const string& key)
90fe8ae6
RG
166{
167 int ret = cdb_find(&d_cdb, key.c_str(), key.size());
168 if (ret < 0) {
169 throw std::runtime_error("Error while looking up key '" + key + "' from CDB database: " + std::to_string(ret));
170 }
171 if (ret == 0) {
172 /* no such key */
173 return false;
174 }
175
73e1f0c5
RG
176 return true;
177}
178
179bool CDB::findOne(const string& key, string& value)
180{
181 if (!keyExists(key)) {
182 return false;
183 }
184
90fe8ae6
RG
185 unsigned int vpos = cdb_datapos(&d_cdb);
186 unsigned int vlen = cdb_datalen(&d_cdb);
187 value.resize(vlen);
73e1f0c5 188 int ret = cdb_read(&d_cdb, &value[0], vlen, vpos);
90fe8ae6
RG
189 if (ret < 0) {
190 throw std::runtime_error("Error while reading value for key '" + key + "' from CDB database: " + std::to_string(ret));
191 }
192
193 return true;
194}
195
196CDBWriter::CDBWriter(int fd): d_fd(fd)
197{
198 cdb_make_start(&d_cdbm, d_fd);
199}
200
201CDBWriter::~CDBWriter()
202{
203 close();
204}
205
206void CDBWriter::close()
207{
208 if (d_fd >= 0) {
209 cdb_make_finish(&d_cdbm);
210 ::close(d_fd);
211 d_fd = -1;
212 }
213}
214
215bool CDBWriter::addEntry(const std::string& key, const std::string& value)
216{
217 if (d_fd < 0) {
218 throw std::runtime_error("Can't add an entry to a closed CDB database");
219 }
220
221 int ret = cdb_make_add(&d_cdbm, key.c_str(), key.size(), value.c_str(), value.size());
222 if (ret != 0) {
223 throw std::runtime_error("Error adding key '" + key + "' to CDB database: " + std::to_string(ret));
224 }
225
226 return true;
227}