-/**/
+/*
+ * cdb, cdb-wr - Tcl bindings for tinycdb and a journalling write extension
+ * Copyright 2006 Ian Jackson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
#include "chiark_tcl_cdb.h"
+#define KEYLEN_MAX (INT_MAX/2)
+
#define ftello ftell
#define fseeko fseek
#define MAX_SUFFIX 5
static void pathbuf_init(Pathbuf *pb, const char *pathb) {
- int l= strlen(pathb);
+ size_t l= strlen(pathb);
+ assert(l < INT_MAX);
pb->buf= TALLOC(l + MAX_SUFFIX + 1);
memcpy(pb->buf, pathb, l);
pb->sfx= pb->buf + l;
*p= 0;
errno=0; ul= strtoul(numbuf, &ep, 10);
- if (*ep || errno || ul >= INT_MAX/2) return -2;
+ if (*ep || errno || ul >= KEYLEN_MAX) return -2;
*num_r= ul;
return 0;
}
static int writerecord(FILE *f, const char *key, const HashValue *val) {
int r;
- r= fprintf(f, "+%d,%d:%s->", strlen(key), val->len, key);
+ r= fprintf(f, "+%d,%d:%s->", (int)strlen(key), val->len, key);
if (r<0) return -1;
r= fwrite(val->data, 1, val->len, f);
int cht_do_cdbwr_create_empty(ClientData cd, Tcl_Interp *ip,
const char *pathb) {
- static const char *const toremoves[]= { ".cdb", ".log", ".tmp", 0 };
+ static const char *const toremoves[]= { ".cdb", ".jrn", ".tmp", 0 };
Pathbuf pb, pbmain;
int lock_fd=-1, rc, r;
PE("open .cdb");
}
- rw->logfile= fopen(pathbuf_sfx(&rw->pbsome,".log"), "r+");
+ rw->logfile= fopen(pathbuf_sfx(&rw->pbsome,".jrn"), "r+");
if (!rw->logfile) {
- if (errno != ENOENT) PE("failed to open .log during open");
+ if (errno != ENOENT) PE("failed to open .jrn during open");
rw->logfile= fopen(rw->pbsome.buf, "w");
- if (!rw->logfile) PE("create .log during (clean) open");
+ if (!rw->logfile) PE("create .jrn during (clean) open");
} else { /* rw->logfile */
r= fstat(fileno(rw->logfile), &stab);
- if (r==-1) PE("fstat .log during open");
+ if (r==-1) PE("fstat .jrn during open");
rc= infocb(ip, rw, "open-dirty-start", "log=%luby",
(unsigned long)stab.st_size);
if (rc) goto x_rc;
for (;;) {
logrecstart= ftello(rw->logfile);
- if (logrecstart < 0) PE("ftello .log during (dirty) open");
+ if (logrecstart < 0) PE("ftello .jrn during (dirty) open");
r= readstorelogrecord(rw->logfile, &rw->logincore, 0,0, ht_update);
if (ferror(rw->logfile)) {
- rc= cht_posixerr(ip, errno, "error reading .log during (dirty) open");
+ rc= cht_posixerr(ip, errno, "error reading .jrn during (dirty) open");
goto x_rc;
}
if (r==-1) {
} else if (r==-2 || r==-3) {
char buf[100];
logjunkpos= ftello(rw->logfile);
- if(logjunkpos<0) PE("ftello .log during report of junk in dirty open");
+ if(logjunkpos<0) PE("ftello .jrn during report of junk in dirty open");
snprintf(buf,sizeof(buf), "CDB SYNTAX LOG %lu %lu",
(unsigned long)logjunkpos, (unsigned long)logrecstart);
Tcl_SetObjErrorCode(ip, Tcl_NewStringObj(buf,-1));
snprintf(buf,sizeof(buf),"%lu",(unsigned long)logjunkpos);
Tcl_ResetResult(ip);
- Tcl_AppendResult(ip, "syntax error (junk) in .log during"
+ Tcl_AppendResult(ip, "syntax error (junk) in .jrn during"
" (dirty) open, at file position ", buf, (char*)0);
rc= TCL_ERROR;
goto x_rc;
if (rc) goto x_rc;
r= fseeko(rw->logfile, logrecstart, SEEK_SET);
- if (r) PE("failed to fseeko .log before junk during dirty open");
+ if (r) PE("failed to fseeko .jrn before junk during dirty open");
r= ftruncate(fileno(rw->logfile), logrecstart);
- if (r) PE("ftruncate .log to chop junk during dirty open");
+ if (r) PE("ftruncate .jrn to chop junk during dirty open");
} else {
assert(!r);
}
long *reccount_r) {
/* creates new .cdb and .main
* closes logfile
- * leaves .log with old data
+ * leaves .jrn with old data
* leaves cdb fd open onto old db
* leaves logincore full of crap
*/
rc= compact_core(ip, rw, logsz, reccount_r); if (rc) goto x_rc;
- r= remove(pathbuf_sfx(&rw->pbsome,".log"));
- if (r) PE("remove .log (during tidy close)");
+ r= remove(pathbuf_sfx(&rw->pbsome,".jrn"));
+ if (r) PE("remove .jrn (during tidy close)");
return TCL_OK;
int rc, r;
logsz= ftello(rw->logfile);
- if (logsz < 0) return cht_posixerr(ip, errno, "ftell .log"
+ if (logsz < 0) return cht_posixerr(ip, errno, "ftell .jrn"
" during compact check or force");
if (!force && logsz < rw->mainsz / 3 + 1000) return TCL_OK;
rc= cdbinit(ip, rw); if (rc) goto x_rc;
- rw->logfile= fopen(pathbuf_sfx(&rw->pbsome,".log"), "w");
- if (!rw->logfile) PE("reopen .log after compact");
+ rw->logfile= fopen(pathbuf_sfx(&rw->pbsome,".jrn"), "w");
+ if (!rw->logfile) PE("reopen .jrn after compact");
- r= fsync(fileno(rw->logfile)); if (r) PE("fsync .log after compact reopen");
+ r= fsync(fileno(rw->logfile)); if (r) PE("fsync .jrn after compact reopen");
return TCL_OK;
HashValue *val;
int rc, r;
+ if (strlen(key) >= KEYLEN_MAX)
+ return cht_staticerr(ip, "key too long", "CDB KEYOVERFLOW");
+
if (!rw->logfile) return cht_staticerr
(ip, "previous compact failed; cdbwr must be closed and reopened "
"before any further updates", "CDB BROKEN");
return cht_cdb_donesomelookup(ip, rw_v, def, result, data, dlen,
cht_cdb_storeanswer_hb);
}
-
-int cht_do_cdbtoplevel_cdb_wr(ClientData cd, Tcl_Interp *ip,
- const Cdbwr_SubCommand* subcmd,
- int objc, Tcl_Obj *const *objv) {
- return subcmd->func((void*)subcmd,ip,objc,objv);
-}