From: ian Date: Sat, 21 Oct 2006 13:03:47 +0000 (+0000) Subject: @@ -2,9 +2,13 @@ X-Git-Tag: debian/1.1.1~27 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-tcl.git;a=commitdiff_plain;h=29fc9adb0f9c6ade500203bfda4359cba1d59ff7;ds=sidebyside @@ -2,9 +2,13 @@ Bugfixes: + * cdb: When cdbwr update writerecord fails, try to recover the + situation to sanity so we don't corrupt the log later; if this + fails, mark the cdb broken. Closes #393970. (Bug exists only where int and ssize_t differ.) + * Do not coredump if fclose journal fails during compact. --- diff --git a/cdb/writeable.c b/cdb/writeable.c index 9eefb22..02c98cb 100644 --- a/cdb/writeable.c +++ b/cdb/writeable.c @@ -163,7 +163,7 @@ typedef struct Rw { int ix, autocompact; int cdb_fd, lock_fd; struct cdb cdb; /* valid iff cdb_fd >= 0 */ - FILE *logfile; + FILE *logfile; /* may be 0; if so, is broken */ HashTable logincore; Pathbuf pbsome, pbother; off_t mainsz; @@ -611,9 +611,9 @@ static int compact_core(Tcl_Interp *ip, Rw *rw, unsigned long logsz, a.reccount= reccount_r; r= fclose(rw->logfile); + rw->logfile= 0; if (r) { rc= cht_posixerr(ip, errno, "probable data loss! failed to fclose" " logfile during compact"); goto x_rc; } - rw->logfile= 0; rc= infocb(ip, rw, "compact-start", "log=%luby main=%luby", logsz, (unsigned long)rw->mainsz); @@ -860,15 +860,22 @@ int cht_do_cdbwr_compact_auto(ClientData cd, Tcl_Interp *ip, void *rw_v) { static int update(Tcl_Interp *ip, Rw *rw, const char *key, const Byte *data, int dlen) { HashValue *val; + const char *failed; int rc, r; + off_t recstart; 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"); + (ip, "failure during previous compact or error recovery;" + " cdbwr must be closed and reopened before any further updates", + "CDB BROKEN"); + recstart= ftello(rw->logfile); + if (recstart < 0) + return cht_posixerr(ip, errno, "failed to ftello .jrn during update"); + val= htv_prep(dlen); assert(val); memcpy(htv_fillptr(val), data, dlen); @@ -883,6 +890,33 @@ static int update(Tcl_Interp *ip, Rw *rw, const char *key, x_rc: TFREE(val); + assert(rc); + + /* Now, we have to try to sort out the journal so that it's + * truncated and positioned to where this abortively-written record + * started, with no buffered output and the error indicator clear. + * + * There seems to be no portable way to ensure the buffered unwritten + * output is discarded, so we close and reopen the stream. + */ + fclose(rw->logfile); + + rw->logfile= fopen(pathbuf_sfx(&rw->pbsome,".jrn"), "r+"); + if (!rw->logfile) { failed= "fopen"; goto reset_fail; } + + r= ftruncate(fileno(rw->logfile), recstart); + if (r) { failed= "ftruncate"; goto reset_fail; } + + r= fseeko(rw->logfile, recstart, SEEK_SET); + if (r) { failed= "fseeko"; goto reset_fail; } + + return rc; + + reset_fail: + Tcl_AppendResult(ip, " (additionally, ", failed, " failed" + " in error recovery: ", strerror(errno), ")", (char*)0); + if (rw->logfile) { fclose(rw->logfile); rw->logfile= 0; } + return rc; } diff --git a/debian/changelog b/debian/changelog index a79232e..6c2f860 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,9 +2,13 @@ chiark-tcl (1.0.2) unstable; urgency=low Bugfixes: * Do not adns_cancel in the middle of adns_forallqueries. + * cdb: When cdbwr update writerecord fails, try to recover the + situation to sanity so we don't corrupt the log later; if this + fails, mark the cdb broken. * strlen returns size_t, not int; fixed up everywhere relevant. Closes #393970. (Bug exists only where int and ssize_t differ.) * Use correct errno value for error writing to new .main during compact. + * Do not coredump if fclose journal fails during compact. Portability fixes: * Remove unecessary assertion of val<=0xffffffffUL where uint32_t val;