1 /*
2   LibRCC - interface to BerkleyDB
3 
4   Copyright (C) 2005-2008 Suren A. Chilingaryan <csa@dside.dyndns.org>
5 
6   This library is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License version 2.1 or later
8   as published by the Free Software Foundation.
9 
10   This library is distributed in the hope that it will be useful, but WITHOUT
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
13   for more details.
14 
15   You should have received a copy of the GNU Lesser General Public License
16   along with this program; if not, write to the Free Software Foundation, Inc.,
17   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "../config.h"
25 
26 #include "internal.h"
27 #include "rcchome.h"
28 #include "rccdb4.h"
29 
30 #define DATABASE "autolearn.db"
31 
rccDb4CreateContext(const char * dbpath,rcc_db4_flags flags)32 db4_context rccDb4CreateContext(const char *dbpath, rcc_db4_flags flags) {
33     db4_context ctx;
34 
35     if (!dbpath) return NULL;
36 
37     ctx = (db4_context)malloc(sizeof(db4_context_s));
38     if (!ctx) return NULL;
39 
40     memset(ctx, 0, sizeof(db4_context_s));
41     ctx->dbpath = strdup(dbpath);
42     ctx->flags = flags;
43 
44     if (!ctx->dbpath) {
45         free(ctx);
46         return NULL;
47     }
48 
49     return ctx;
50 }
51 
rccDb4InitContext(db4_context ctx,const char * dbpath,rcc_db4_flags flags)52 static int rccDb4InitContext(db4_context ctx, const char *dbpath, rcc_db4_flags flags) {
53 #ifdef HAVE_DB_H
54     int err;
55 
56 # ifdef DB_VERSION_MISMATCH
57     char stmp[160];
58 # endif /* DB_VERSION_MISMATCH */
59 
60     if (ctx->initialized) {
61         if ((ctx->dbe)&&(ctx->db)) return 0;
62         return -1;
63     }
64 
65     err = rccLock();
66     if (err) return -1;
67 
68     if (ctx->initialized) {
69         if ((ctx->dbe)&&(ctx->db)) return 0;
70         return -1;
71     }
72 
73     ctx->initialized = 1;
74     rccUnLock();
75 
76     DB_ENV *dbe;
77     DB *db;
78 
79     err = db_env_create(&dbe, 0);
80     if (err) return -1;
81 
82 # if defined(DB_LOG_AUTOREMOVE)
83     dbe->set_flags(dbe, DB_LOG_AUTOREMOVE, 1);
84     dbe->set_lg_max(dbe, 131072);
85 # elif defined(DB_LOG_AUTO_REMOVE)
86 	// Starting from berkeleydb 4.7 API has changed
87     dbe->log_set_config(dbe, DB_LOG_AUTO_REMOVE, 1);
88     dbe->set_lg_max(dbe, 131072);
89 # endif /* DB_LOG_AUTOREMOVE */
90 
91     err = rccLock();
92     if (err) {
93         dbe->close(dbe, 0);
94         return -1;
95     }
96 
97     err = dbe->open(dbe, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL|DB_THREAD, 00644);
98     if (err) {
99 	err = dbe->open(dbe, dbpath, DB_CREATE|DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN|DB_USE_ENVIRON|DB_PRIVATE|DB_RECOVER|DB_THREAD, 0);
100 	dbe->close(dbe, 0);
101 
102 	if (err) {
103 	    err = db_env_create(&dbe, 0);
104 	    if (err) {
105 	        rccUnLock();
106 	        return -1;
107 	    }
108 	    dbe->remove(dbe, dbpath, 0);
109 	}
110 
111 	if (strlen(dbpath)<128) {
112 	    sprintf(stmp, "%s/log.0000000001", dbpath);
113 	    remove(stmp);
114 	}
115 
116 	err = db_env_create(&dbe, 0);
117 	if (err) {
118 	    rccUnLock();
119 	    return -1;
120 	}
121 
122 	err = dbe->open(dbe, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL|DB_THREAD, 00644);
123     }
124     rccUnLock();
125 
126     if (err) {
127 //	fprintf(stderr, "BerkelyDB initialization failed: %i (%s)\n", err, db_strerror(err));
128 	dbe->close(dbe, 0);
129 	return -1;
130     }
131 
132     err = db_create(&db, dbe, 0);
133     if (err) {
134 	dbe->close(dbe, 0);
135 	return -1;
136     }
137 
138 
139     err = db->open(db, NULL, DATABASE, NULL, DB_BTREE, DB_CREATE|DB_THREAD, 0);
140     if (err) {
141 	db->close(db, 0);
142 	dbe->close(dbe, 0);
143 	return -1;
144     }
145 #endif /* HAVE_DB_H */
146 
147 #ifdef HAVE_DB_H
148     ctx->db = db;
149     ctx->dbe = dbe;
150 #endif /* HAVE_DB_H */
151 
152     return 0;
153 }
154 
rccDb4FreeContext(db4_context ctx)155 void rccDb4FreeContext(db4_context ctx) {
156     if (ctx) {
157 #ifdef HAVE_DB_H
158 	if (ctx->db) ctx->db->close(ctx->db, 0);
159 	if (ctx->dbe) ctx->dbe->close(ctx->dbe, 0);
160 #endif /* HAVE_DB_H */
161 	if (ctx->dbpath) free(ctx->dbpath);
162 	free(ctx);
163     }
164 }
165 
166 #ifdef HAVE_DB_H
rccDb4Strip(DBT * key)167 static void rccDb4Strip(DBT *key) {
168     size_t size;
169     char *str;
170 
171     str = (char*)key->data;
172     size = key->size;
173 
174     while ((size > 0)&&((*str==' ')||(*str=='\n')||(*str==0))) {
175 	str++;
176 	size--;
177     }
178     while ((size > 0)&&((str[size-1]==' ')||(str[size-1]=='\n')||(str[size-1]==0))) {
179 	size--;
180     }
181 
182     key->size = size;
183     key->data = str;
184 }
185 #endif /* HAVE_DB_H */
186 
rccDb4SetKey(db4_context ctx,const char * orig,size_t olen,const char * string)187 int rccDb4SetKey(db4_context ctx, const char *orig, size_t olen, const char *string) {
188 #ifdef HAVE_DB_H
189     DBT key, data;
190 
191     if ((!ctx)||(!orig)||(!string)) return -1;
192     if (rccDb4InitContext(ctx, ctx->dbpath, ctx->flags)) return -1;
193 
194     memset(&key, 0, sizeof(key));
195     memset(&data, 0, sizeof(data));
196 
197     key.data = (char*)orig;
198     key.size = olen?olen:strlen(orig); /* No ending zero */
199     data.data = (char*)string;
200     data.size = strlen(string)+1;
201 
202     rccDb4Strip(&key);
203     if (key.size < RCC_MIN_DB4_CHARS) return -1;
204 
205     if (!ctx->db->put(ctx->db, NULL, &key, &data, 0)) return 0;
206 #endif /* HAVE_DB_H */
207 
208     return 1;
209 }
210 
rccDb4GetKey(db4_context ctx,const char * orig,size_t olen)211 char *rccDb4GetKey(db4_context ctx, const char *orig, size_t olen) {
212 #ifdef HAVE_DB_H
213     DBT key, data;
214 
215     if ((!ctx)||(!orig)) return NULL;
216     if (rccDb4InitContext(ctx, ctx->dbpath, ctx->flags)) return NULL;
217 
218     memset(&key, 0, sizeof(key));
219     memset(&data, 0, sizeof(data));
220 
221     key.data = (char*)orig;
222     key.size = olen?olen:strlen(orig); /* No ending zero */
223 
224     data.flags = DB_DBT_REALLOC;
225 
226     rccDb4Strip(&key);
227     if (key.size < RCC_MIN_DB4_CHARS) return NULL;
228 
229     if (!ctx->db->get(ctx->db, NULL, &key, &data, 0)) return data.data;
230 #endif /* HAVE_DB_H */
231 
232     return NULL;
233 }
234