Package: trn
Version: 3.6-18.1
Tags: patch
Trn's technique for rewriting a local KILL file (kfile.c::rewrite_kfile())
is as follows:
* unlink old KILL file (still open)
* open new KILL file
* read lines from old KILL file, writing into new KILL file
* close both files
This is unsafe, in that any crash between the first and last steps will
lose the contents of the file.
The attached patch fixes this problem by writing the KILL file under a new
name, and then renaming it into place (atomically if possible). I've only
minimally tested it so far.
[ I actually noticed this because I was running trn on a system where
unlinked files aren't readable at all, so all my lovely rules got eaten,
but I appreciate that such systems aren't relevant to Debian. ]
--
Ben Harris, University of Cambridge Computing Service.
--- kfile.c.orig 1994-11-19 06:01:19.000000000 +0000
+++ kfile.c 2008-10-29 22:27:40.000000000 +0000
@@ -339,6 +339,7 @@
ART_NUM thru;
{
bool no_kills = 0, has_star_commands = FALSE;
+ char *oldkf, *newkf;
if (localkfp) {
fseek(localkfp,0L,0); /* rewind current file */
@@ -352,12 +353,16 @@
no_kills = 1;
}
strcpy(buf,filexp(getval("KILLLOCAL",killlocal)));
+ oldkf = savestr(buf);
+ strcat(buf, ".tmp");
+ newkf = savestr(buf);
if (!localkfp)
- makedir(buf,MD_FILE);
- UNLINK(buf); /* to prevent file reuse */
- if (no_kills)
+ makedir(newkf,MD_FILE);
+ if (no_kills) {
+ UNLINK(buf);
open_kfile(KF_LOCAL); /* close file and reset open flag */
- else if (newkfp = fopen(buf,"w")) {
+ }
+ else if (newkfp = fopen(newkf,"w")) {
fprintf(newkfp,"THRU %ld\n",(long)thru);
while (localkfp && fgets(buf,LBUFLEN,localkfp) != Nullch) {
if (strnEQ(buf,"THRU",4))
@@ -381,12 +386,21 @@
/* Append all the still-valid thread commands */
hashwalk(msgid_hash, write_thread_commands, 0);
fclose(newkfp);
+#ifdef HAS_RENAME
+ rename(newkf, oldkf);
+#else
+ UNLINK(oldkf);
+ safelink(newkf, oldkf);
+ UNLINK(newkf);
+#endif
open_kfile(KF_LOCAL); /* and reopen local file */
}
else
- printf(cantcreate,buf) FLUSH;
+ printf(cantcreate,newkf) FLUSH;
localkf_changes = 0;
has_normal_kills = FALSE;
+ free(newkf);
+ free(oldkf);
}
/* edit KILL file for newsgroup */