diff options
Diffstat (limited to 'ext/dba/dba_cdb.c')
-rw-r--r-- | ext/dba/dba_cdb.c | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/ext/dba/dba_cdb.c b/ext/dba/dba_cdb.c new file mode 100644 index 0000000..a4a7314 --- /dev/null +++ b/ext/dba/dba_cdb.c @@ -0,0 +1,350 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Sascha Schumann <sascha@schumann.cx> | + | Marcus Boerger <helly@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" + +#if DBA_CDB +#include "php_cdb.h" + +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> + +#if DBA_CDB_BUILTIN +# include "libcdb/cdb.h" +# include "libcdb/cdb_make.h" +# include "libcdb/uint32.h" +#else +# ifdef CDB_INCLUDE_FILE +# include CDB_INCLUDE_FILE +# endif +#endif + +#define CDB_INFO \ + dba_cdb *cdb = (dba_cdb *) info->dbf + +typedef struct { + struct cdb c; +#if DBA_CDB_BUILTIN + struct cdb_make m; + php_stream *file; + int make; +#else + int file; +#endif + uint32 eod; /* size of constant database */ + uint32 pos; /* current position for traversing */ +} dba_cdb; + +DBA_OPEN_FUNC(cdb) +{ +#if DBA_CDB_BUILTIN + php_stream* file = 0; + int make; +#else + int file = 0; +#endif + dba_cdb *cdb; + dba_info *pinfo = (dba_info *) info; + + switch (info->mode) { + case DBA_READER: +#if DBA_CDB_BUILTIN + make = 0; + file = info->fp; +#else + file = VCWD_OPEN(info->path, O_RDONLY); + if (file < 0) { + *error = "Unable to open file"; + return FAILURE; + } +#endif + break; +#if DBA_CDB_BUILTIN + case DBA_TRUNC: + make = 1; + file = info->fp; + break; + case DBA_CREAT: + case DBA_WRITER: + *error = "Update operations are not supported"; + return FAILURE; /* not supported */ +#endif + default: + *error = "Currently not supported"; + return FAILURE; + } + + cdb = pemalloc(sizeof(dba_cdb), info->flags&DBA_PERSISTENT); + memset(cdb, 0, sizeof(dba_cdb)); + +#if DBA_CDB_BUILTIN + if (make) { + cdb_make_start(&cdb->m, file TSRMLS_CC); + } else { + cdb_init(&cdb->c, file TSRMLS_CC); + } + cdb->make = make; +#else + cdb_init(&cdb->c, file); +#endif + cdb->file = file; + + pinfo->dbf = cdb; + return SUCCESS; +} + +DBA_CLOSE_FUNC(cdb) +{ + CDB_INFO; + + /* cdb_free does not close associated file */ +#if DBA_CDB_BUILTIN + if (cdb->make) { + cdb_make_finish(&cdb->m TSRMLS_CC); + } else { + cdb_free(&cdb->c TSRMLS_CC); + } +#else + cdb_free(&cdb->c); + close(cdb->file); +#endif + pefree(cdb, info->flags&DBA_PERSISTENT); +} + +#if DBA_CDB_BUILTIN +# define php_cdb_read(cdb, buf, len, pos) cdb_read(cdb, buf, len, pos TSRMLS_CC) +# define php_cdb_findnext(cdb, key, len) cdb_findnext(cdb, key, len TSRMLS_CC) +# define php_cdb_find(cdb, key, len) cdb_find(cdb, key, len TSRMLS_CC) +#else +# define php_cdb_read(cdb, buf, len, pos) cdb_read(cdb, buf, len, pos) +# define php_cdb_findnext(cdb, key, len) cdb_findnext(cdb, key, len) +# define php_cdb_find(cdb, key, len) cdb_find(cdb, key, len) +#endif + +DBA_FETCH_FUNC(cdb) +{ + CDB_INFO; + unsigned int len; + char *new_entry = NULL; + +#if DBA_CDB_BUILTIN + if (cdb->make) + return NULL; /* database was opened writeonly */ +#endif + if (php_cdb_find(&cdb->c, key, keylen) == 1) { + while(skip--) { + if (php_cdb_findnext(&cdb->c, key, keylen) != 1) { + return NULL; + } + } + len = cdb_datalen(&cdb->c); + new_entry = safe_emalloc(len, 1, 1); + + if (php_cdb_read(&cdb->c, new_entry, len, cdb_datapos(&cdb->c)) == -1) { + efree(new_entry); + return NULL; + } + new_entry[len] = 0; + if (newlen) + *newlen = len; + } + + return new_entry; +} + +DBA_UPDATE_FUNC(cdb) +{ +#if DBA_CDB_BUILTIN + CDB_INFO; + + if (!cdb->make) + return FAILURE; /* database was opened readonly */ + if (!mode) + return FAILURE; /* cdb_make dosn't know replace */ + if (cdb_make_add(&cdb->m, key, keylen, val, vallen TSRMLS_CC) != -1) + return SUCCESS; +#endif + return FAILURE; +} + +DBA_EXISTS_FUNC(cdb) +{ + CDB_INFO; + +#if DBA_CDB_BUILTIN + if (cdb->make) + return FAILURE; /* database was opened writeonly */ +#endif + if (php_cdb_find(&cdb->c, key, keylen) == 1) + return SUCCESS; + return FAILURE; +} + +DBA_DELETE_FUNC(cdb) +{ + return FAILURE; /* cdb doesn't support delete */ +} + +/* {{{ cdb_file_read */ +#if DBA_CDB_BUILTIN +# define cdb_file_read(fildes, buf, size) php_stream_read(fildes, buf, size) +#else +# define cdb_file_read(fildes, buf, size) read(fildes, buf, size) +#endif +/* }}} */ + +#define CREAD(n) do { \ + if (cdb_file_read(cdb->file, buf, n) < n) return NULL; \ +} while (0) + +/* {{{ cdb_file_lseek + php_stream_seek does not return actual position */ +#if DBA_CDB_BUILTIN +int cdb_file_lseek(php_stream *fp, off_t offset, int whence TSRMLS_DC) { + php_stream_seek(fp, offset, whence); + return php_stream_tell(fp); +} +#else +int cdb_file_lseek(int fd, off_t offset, int whence TSRMLS_DC) { + return lseek(fd, offset, whence); +} +#endif +/* }}} */ + +#define CSEEK(n) do { \ + if (n >= cdb->eod) return NULL; \ + if (cdb_file_lseek(cdb->file, (off_t)n, SEEK_SET TSRMLS_CC) != (off_t) n) return NULL; \ +} while (0) + + +DBA_FIRSTKEY_FUNC(cdb) +{ + CDB_INFO; + uint32 klen, dlen; + char buf[8]; + char *key; + +#if DBA_CDB_BUILTIN + if (cdb->make) + return NULL; /* database was opened writeonly */ +#endif + + cdb->eod = -1; + CSEEK(0); + CREAD(4); + + /* Total length of file in bytes */ + uint32_unpack(buf, &cdb->eod); + + CSEEK(2048); + CREAD(8); + + /* The first four bytes contain the length of the key */ + uint32_unpack(buf, &klen); + uint32_unpack(buf + 4, &dlen); + + key = safe_emalloc(klen, 1, 1); + if (cdb_file_read(cdb->file, key, klen) < klen) { + efree(key); + key = NULL; + } else { + key[klen] = '\0'; + if (newlen) *newlen = klen; + } + + /* header + klenlen + dlenlen + klen + dlen */ + cdb->pos = 2048 + 4 + 4 + klen + dlen; + + return key; +} + +DBA_NEXTKEY_FUNC(cdb) +{ + CDB_INFO; + uint32 klen, dlen; + char buf[8]; + char *key; + +#if DBA_CDB_BUILTIN + if (cdb->make) + return NULL; /* database was opened writeonly */ +#endif + + CSEEK(cdb->pos); + CREAD(8); + uint32_unpack(buf, &klen); + uint32_unpack(buf + 4, &dlen); + + key = safe_emalloc(klen, 1, 1); + if (cdb_file_read(cdb->file, key, klen) < klen) { + efree(key); + key = NULL; + } else { + key[klen] = '\0'; + if (newlen) *newlen = klen; + } + + cdb->pos += 8 + klen + dlen; + + return key; +} + +DBA_OPTIMIZE_FUNC(cdb) +{ + return SUCCESS; +} + +DBA_SYNC_FUNC(cdb) +{ + /* this is read-only */ + return SUCCESS; +} + +DBA_INFO_FUNC(cdb) +{ +#if DBA_CDB_BUILTIN + if (!strcmp(hnd->name, "cdb")) { + return estrdup(cdb_version()); + } else { + return estrdup(cdb_make_version()); + } +#else + return estrdup("External"); +#endif +} + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ |