xref: /PHP-8.1/ext/dba/dba_db3.c (revision 01b3fc03)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Sascha Schumann <sascha@schumann.cx>                         |
14    +----------------------------------------------------------------------+
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "php.h"
22 
23 #if DBA_DB3
24 #include "php_db3.h"
25 #include <sys/stat.h>
26 
27 #include <string.h>
28 #ifdef DB3_INCLUDE_FILE
29 #include DB3_INCLUDE_FILE
30 #else
31 #include <db.h>
32 #endif
33 
php_dba_db3_errcall_fcn(const DB_ENV * dbenv,const char * errpfx,const char * msg)34 static void php_dba_db3_errcall_fcn(
35 #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3))
36 	const DB_ENV *dbenv,
37 #endif
38 	const char *errpfx, const char *msg)
39 {
40 
41 	php_error_docref(NULL, E_NOTICE, "%s%s", errpfx?errpfx:"", msg);
42 }
43 
44 #define DB3_DATA dba_db3_data *dba = info->dbf
45 #define DB3_GKEY \
46 	DBT gkey; \
47 	memset(&gkey, 0, sizeof(gkey)); \
48 	gkey.data = (char *) key; gkey.size = keylen
49 
50 typedef struct {
51 	DB *dbp;
52 	DBC *cursor;
53 } dba_db3_data;
54 
DBA_OPEN_FUNC(db3)55 DBA_OPEN_FUNC(db3)
56 {
57 	DB *dbp = NULL;
58 	DBTYPE type;
59 	int gmode = 0, err;
60 	int filemode = 0644;
61 	struct stat check_stat;
62 	int s = VCWD_STAT(info->path, &check_stat);
63 
64 	if (!s && !check_stat.st_size) {
65 		info->mode = DBA_TRUNC; /* force truncate */
66 	}
67 
68 	type = info->mode == DBA_READER ? DB_UNKNOWN :
69 		info->mode == DBA_TRUNC ? DB_BTREE :
70 		s ? DB_BTREE : DB_UNKNOWN;
71 
72 	gmode = info->mode == DBA_READER ? DB_RDONLY :
73 		(info->mode == DBA_CREAT && s) ? DB_CREATE :
74 		(info->mode == DBA_CREAT && !s) ? 0 :
75 		info->mode == DBA_WRITER ? 0         :
76 		info->mode == DBA_TRUNC ? DB_CREATE | DB_TRUNCATE : -1;
77 
78 	if (gmode == -1) {
79 		return FAILURE; /* not possible */
80 	}
81 
82 	if (info->argc > 0) {
83 		filemode = zval_get_long(&info->argv[0]);
84 	}
85 
86 #ifdef DB_FCNTL_LOCKING
87 	gmode |= DB_FCNTL_LOCKING;
88 #endif
89 
90 	if ((err=db_create(&dbp, NULL, 0)) == 0) {
91 	    dbp->set_errcall(dbp, php_dba_db3_errcall_fcn);
92 		if(
93 #if (DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1))
94 			(err=dbp->open(dbp, 0, info->path, NULL, type, gmode, filemode)) == 0) {
95 #else
96 			(err=dbp->open(dbp, info->path, NULL, type, gmode, filemode)) == 0) {
97 #endif
98 			dba_db3_data *data;
99 
100 			data = pemalloc(sizeof(*data), info->flags&DBA_PERSISTENT);
101 			data->dbp = dbp;
102 			data->cursor = NULL;
103 			info->dbf = data;
104 
105 			return SUCCESS;
106 		} else {
107 			dbp->close(dbp, 0);
108 			*error = db_strerror(err);
109 		}
110 	} else {
111 		*error = db_strerror(err);
112 	}
113 
114 	return FAILURE;
115 }
116 
117 DBA_CLOSE_FUNC(db3)
118 {
119 	DB3_DATA;
120 
121 	if (dba->cursor) dba->cursor->c_close(dba->cursor);
122 	dba->dbp->close(dba->dbp, 0);
123 	pefree(dba, info->flags&DBA_PERSISTENT);
124 }
125 
126 DBA_FETCH_FUNC(db3)
127 {
128 	DBT gval;
129 	char *new = NULL;
130 	DB3_DATA;
131 	DB3_GKEY;
132 
133 	memset(&gval, 0, sizeof(gval));
134 	if (!dba->dbp->get(dba->dbp, NULL, &gkey, &gval, 0)) {
135 		if (newlen) *newlen = gval.size;
136 		new = estrndup(gval.data, gval.size);
137 	}
138 	return new;
139 }
140 
141 DBA_UPDATE_FUNC(db3)
142 {
143 	DBT gval;
144 	DB3_DATA;
145 	DB3_GKEY;
146 
147 	memset(&gval, 0, sizeof(gval));
148 	gval.data = (char *) val;
149 	gval.size = vallen;
150 
151 	if (!dba->dbp->put(dba->dbp, NULL, &gkey, &gval,
152 				mode == 1 ? DB_NOOVERWRITE : 0)) {
153 		return SUCCESS;
154 	}
155 	return FAILURE;
156 }
157 
158 DBA_EXISTS_FUNC(db3)
159 {
160 	DBT gval;
161 	DB3_DATA;
162 	DB3_GKEY;
163 
164 	memset(&gval, 0, sizeof(gval));
165 	if (!dba->dbp->get(dba->dbp, NULL, &gkey, &gval, 0)) {
166 		return SUCCESS;
167 	}
168 	return FAILURE;
169 }
170 
171 DBA_DELETE_FUNC(db3)
172 {
173 	DB3_DATA;
174 	DB3_GKEY;
175 
176 	return dba->dbp->del(dba->dbp, NULL, &gkey, 0) ? FAILURE : SUCCESS;
177 }
178 
179 DBA_FIRSTKEY_FUNC(db3)
180 {
181 	DB3_DATA;
182 
183 	if (dba->cursor) {
184 		dba->cursor->c_close(dba->cursor);
185 	}
186 
187 	dba->cursor = NULL;
188 	if (dba->dbp->cursor(dba->dbp, NULL, &dba->cursor, 0) != 0) {
189 		return NULL;
190 	}
191 
192 	/* we should introduce something like PARAM_PASSTHRU... */
193 	return dba_nextkey_db3(info, newlen);
194 }
195 
196 DBA_NEXTKEY_FUNC(db3)
197 {
198 	DB3_DATA;
199 	DBT gkey, gval;
200 	char *nkey = NULL;
201 
202 	memset(&gkey, 0, sizeof(gkey));
203 	memset(&gval, 0, sizeof(gval));
204 
205 	if (dba->cursor->c_get(dba->cursor, &gkey, &gval, DB_NEXT) == 0) {
206 		if (gkey.data) {
207 			nkey = estrndup(gkey.data, gkey.size);
208 			if (newlen) *newlen = gkey.size;
209 		}
210 	}
211 
212 	return nkey;
213 }
214 
215 DBA_OPTIMIZE_FUNC(db3)
216 {
217 	return SUCCESS;
218 }
219 
220 DBA_SYNC_FUNC(db3)
221 {
222 	DB3_DATA;
223 
224 	return dba->dbp->sync(dba->dbp, 0) ? FAILURE : SUCCESS;
225 }
226 
227 DBA_INFO_FUNC(db3)
228 {
229 	return estrdup(DB_VERSION_STRING);
230 }
231 
232 #endif
233