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