diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3cd6e76 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.*.swp +*~ +/ID +/tags +/Makefile +/config.log +/config.status +/po/Makefile +/po/Makefile.in +/po/POTFILES +/src/Makefile +/src/objs/ +/src/config.h +/src/slrnfeat.h +/src/sysconf.h + diff --git a/src/Makefile.in b/src/Makefile.in index ce4aa94..07a11bc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -101,7 +101,7 @@ version_O_DEP = version.h slrnpull_O_DEP = score.c xover.c hash.c version.h $(CONFIG_H) slrnpull_DEPS = $(OBJDIR)/util.o $(OBJDIR)/strutil.o $(OBJDIR)/sortdate.o \ $(OBJDIR)/sltcp.o $(OBJDIR)/nntplib.o $(OBJDIR)/slrndir.o $(OBJDIR)/ranges.o \ - $(OBJDIR)/vfile.o + $(OBJDIR)/vfile.o $(OBJDIR)/snprintf.o slrnpull_LIBS = $(slrnpull_DEPS) diff --git a/src/art.c b/src/art.c index 48cf56e..a5b4c52 100644 --- a/src/art.c +++ b/src/art.c @@ -203,7 +203,7 @@ static Slrn_Header_Type *Last_Read_Header; static int Article_Visible; /* non-zero if article window is visible */ static char Output_Filename[SLRN_MAX_PATH_LEN]; -#define HEADER_TABLE_SIZE 1250 +#define HEADER_TABLE_SIZE 16384 static Slrn_Header_Type *Header_Table[HEADER_TABLE_SIZE]; static int Do_Rot13; static int Perform_Scoring; @@ -2284,7 +2284,7 @@ static int prepare_article (Slrn_Article_Type *a) } /* Downloads an article and returns it; header lines are marked */ -static Slrn_Article_Type *read_article (Slrn_Header_Type *h, int kill_refs) /*{{{*/ +static Slrn_Article_Type *read_article (Slrn_Header_Type *h, int kill_refs, int *read_status) /*{{{*/ { Slrn_Article_Type *retval; Slrn_Article_Line_Type *cline, *l; @@ -2297,6 +2297,7 @@ static Slrn_Article_Type *read_article (Slrn_Header_Type *h, int kill_refs) /*{{ gettimeofday(&start_time, NULL); #endif + *read_status = ARTICLE_OK; if (h->tag_number) slrn_message_now (_("#%2d/%-2d: Retrieving... %s"), h->tag_number, Num_Tag_List.len, h->subject); @@ -2308,9 +2309,11 @@ static Slrn_Article_Type *read_article (Slrn_Header_Type *h, int kill_refs) /*{{ if (status == -1) { slrn_error ("%s", _("Server failed to return the article.")); + *read_status = ARTICLE_TEMPERROR; return NULL; } + *read_status = ARTICLE_PERMERROR; slrn_error (_("Article " NNTP_FMT_ARTNUM " is unavailable."), h->number); if (kill_refs && ((h->flags & HEADER_READ) == 0) && @@ -2332,7 +2335,10 @@ static Slrn_Article_Type *read_article (Slrn_Header_Type *h, int kill_refs) /*{{ } retval = (Slrn_Article_Type*) slrn_malloc (sizeof(Slrn_Article_Type), 1, 1); - if (retval == NULL) return NULL; + if (retval == NULL) { + *read_status = ARTICLE_TEMPERROR; + return NULL; + } cline = NULL; total_lines = 0; @@ -2428,6 +2434,7 @@ static Slrn_Article_Type *read_article (Slrn_Header_Type *h, int kill_refs) /*{{ { slrn_error (_("Server sent empty article.")); slrn_art_free_article (retval); + *read_status = ARTICLE_PERMERROR; return NULL; } @@ -2435,6 +2442,7 @@ static Slrn_Article_Type *read_article (Slrn_Header_Type *h, int kill_refs) /*{{ if (retval->raw_lines == NULL) { slrn_art_free_article (retval); + *read_status = ARTICLE_TEMPERROR; return NULL; } retval->cline = retval->lines; @@ -2495,6 +2503,7 @@ static int select_header (Slrn_Header_Type *h, int kill_refs) /*{{{*/ Slrn_Article_Type *a; Slrn_Header_Type *last_header_showing; char *subj, *from; + int ret; last_header_showing = Header_Showing; @@ -2505,7 +2514,7 @@ static int select_header (Slrn_Header_Type *h, int kill_refs) /*{{{*/ } free_article (); - if (NULL == (a = read_article (h, kill_refs))) + if (NULL == (a = read_article (h, kill_refs, &ret))) return -1; At_End_Of_Article = NULL; @@ -3734,7 +3743,11 @@ static void supersede (void) /*{{{*/ if (slrn_case_strcmp ( from_buf, me_buf)) { - slrn_error (_("Failed: Your name: '%s' is not '%s'"), me_buf, from_buf); + if (slrn_get_yesno (1, _("Failed: Your name is not '%s', really supersede"), from) == 0) + return; + } else { + if ((Slrn_User_Wants_Confirmation & SLRN_CONFIRM_POST) + && (slrn_get_yesno (1, _("Are you sure you want to supersede")) == 0)) return; } @@ -4292,7 +4305,7 @@ int slrn_save_current_article (char *file) /*{{{*/ /*}}}*/ -static int save_article_as_unix_mail (Slrn_Header_Type *h, FILE *fp) /*{{{*/ +static int save_article_as_unix_mail (Slrn_Header_Type *h, FILE *fp, int *read_status) /*{{{*/ { int is_wrapped = 0; Slrn_Article_Line_Type *l = NULL; @@ -4300,11 +4313,14 @@ static int save_article_as_unix_mail (Slrn_Header_Type *h, FILE *fp) /*{{{*/ char *from; char from_buf[256]; time_t now; + int ret; if ((Header_Showing != h) || (a == NULL)) { - if (NULL == (a = read_article (h, Slrn_Del_Article_Upon_Read))) + if (NULL == (a = read_article (h, Slrn_Del_Article_Upon_Read, &ret))) { + *read_status = ret; return -1; + } } l = a->raw_lines; @@ -4350,6 +4366,7 @@ static char *save_article_to_file (char *defdir, int for_decoding) /*{{{*/ int save_thread = 0; int save_simple; FILE *fp; + int ret; if (-1 == slrn_check_batch ()) return NULL; @@ -4470,26 +4487,33 @@ static char *save_article_to_file (char *defdir, int for_decoding) /*{{{*/ Slrn_Header_Type *h; if (NULL != (h = affected_header ())) - save_article_as_unix_mail (h, fp); + save_article_as_unix_mail (h, fp, &ret); } else if (save_tagged) { unsigned int i; unsigned int num_saved = 0; - for (i = 0; i < Num_Tag_List.len; i++) + for (i = 0; i < Num_Tag_List.len; ) { - if (-1 == save_article_as_unix_mail (Num_Tag_List.headers[i], fp)) + if (-1 == save_article_as_unix_mail (Num_Tag_List.headers[i], fp, &ret)) { slrn_smg_refresh (); if (SLang_get_error() == SL_USER_BREAK) break; SLang_set_error (0); - (void) SLang_input_pending (5); /* half second delay */ + if (ret == ARTICLE_TEMPERROR) { + slrn_sleep(3); + } else { + i++; + } + (void) SLang_input_pending (1); /* 0.1 second delay */ slrn_clear_message (); + } else { + num_saved++; + i++; } - else num_saved++; } if (num_saved == 0) { @@ -4503,11 +4527,11 @@ static char *save_article_to_file (char *defdir, int for_decoding) /*{{{*/ unsigned int num_saved = 0; do { - if (-1 == save_article_as_unix_mail (h, fp)) + if (-1 == save_article_as_unix_mail (h, fp, &ret)) { slrn_smg_refresh (); SLang_set_error (0); - (void) SLang_input_pending (5); /* half second delay */ + (void) SLang_input_pending (1); /* 0.1 second delay */ } else num_saved++; @@ -7005,15 +7029,15 @@ static void cancel_article (void) /*{{{*/ if (slrn_case_strcmp ( from_buf, me_buf)) { - slrn_error (_("Failed: Your name: '%s' is not '%s'"), me_buf, from_buf); - slrn_free(me); - return; - } - - if (slrn_get_yesno (0, _("Are you sure that you want to cancel this article")) <= 0) - { - slrn_free(me); - return; + if (slrn_get_yesno (0, _("Failed: Your name is not '%s', really cancel"), from) == 0) { + slrn_free(me); + return; + } + } else { + if (slrn_get_yesno (0, _("Are you sure that you want to cancel this article")) <= 0) { + slrn_free(me); + return; + } } slrn_message_now (_("Cancelling...")); diff --git a/src/art.h b/src/art.h index fa7a2f6..6fe6691 100644 --- a/src/art.h +++ b/src/art.h @@ -211,6 +211,12 @@ typedef struct } Slrn_Article_Type; +enum Slrn_article_fetch_status { + ARTICLE_OK = 0, + ARTICLE_TEMPERROR, + ARTICLE_PERMERROR +}; + extern Slrn_Article_Type *Slrn_Current_Article; extern Slrn_Header_Type *slrn_find_header_with_msgid (char *); diff --git a/src/group.c b/src/group.c index 21fc18a..1260d68 100644 --- a/src/group.c +++ b/src/group.c @@ -44,6 +44,7 @@ # include #endif +#include #include #include "jdmacros.h" @@ -98,7 +99,7 @@ int *Slrn_Prefix_Arg_Ptr; /*}}}*/ /*{{{ Static Variables */ -#define GROUP_HASH_TABLE_SIZE 1250 +#define GROUP_HASH_TABLE_SIZE 8192 static Slrn_Group_Type *Group_Hash_Table [GROUP_HASH_TABLE_SIZE]; static unsigned int Last_Cursor_Row; @@ -2738,6 +2739,8 @@ int slrn_write_newsrc (int auto_save) /*{{{*/ struct stat filestat; int stat_worked = 0; int have_backup = 0; + int tmpfd; + char *tmpfn; slrn_init_hangup_signals (0); @@ -2799,10 +2802,11 @@ int slrn_write_newsrc (int auto_save) /*{{{*/ have_backup = (0 == slrn_create_backup (newsrc_filename)); } - if (NULL == (fp = fopen (newsrc_filename, "w"))) + tmpfn = slrn_strdup_printf ("%s.tmp.XXXXXX", newsrc_filename); + tmpfd = mkstemp(tmpfn); + if ((tmpfd == -1) || (NULL == (fp = fdopen (tmpfd, "w")))) { - slrn_error (_("Unable to open file %s for writing."), newsrc_filename); - if (have_backup) slrn_restore_backup (newsrc_filename); + slrn_error (_("Unable to open file %s for writing."), tmpfn); slrn_init_hangup_signals (1); return -1; } @@ -2817,10 +2821,10 @@ int slrn_write_newsrc (int auto_save) /*{{{*/ # endif if (stat_worked) { - if (-1 == chmod (newsrc_filename, filestat.st_mode & (S_IRUSR | S_IWUSR | S_IXUSR))) - (void) chmod (newsrc_filename, S_IWUSR | S_IRUSR); + if (-1 == chmod (tmpfn, filestat.st_mode & (S_IRUSR | S_IWUSR | S_IXUSR))) + (void) chmod (tmpfn, S_IWUSR | S_IRUSR); - (void) chown (newsrc_filename, filestat.st_uid, filestat.st_gid); + (void) chown (tmpfn, filestat.st_uid, filestat.st_gid); } # endif #endif @@ -2873,8 +2877,12 @@ int slrn_write_newsrc (int auto_save) /*{{{*/ g = g->next; } - if (-1 == slrn_fclose (fp)) - goto write_error; + if (Slrn_TT_Initialized & SLRN_TTY_INIT) + slrn_message_now (_("Closing and fsyncing %s ..."), newsrc_filename); + if (-1 == slrn_fclose_fsync (fp)) { + fp = NULL; + goto write_error2; + } fp = NULL; if (Slrn_No_Backups) @@ -2888,19 +2896,26 @@ int slrn_write_newsrc (int auto_save) /*{{{*/ if (Slrn_No_Autosave == 0) slrn_delete_file (autosave_file); } + + if (rename (tmpfn, newsrc_filename) == -1) { + slrn_error (_("Renaming %s to %s failed: %s"), + tmpfn, newsrc_filename, strerror(errno)); + goto write_error3; + } + if (Slrn_TT_Initialized & SLRN_TTY_INIT) - slrn_message (_("Writing %s ... done."), newsrc_filename); + slrn_message_now (_("Closing and fsyncing %s ... done."), newsrc_filename); slrn_init_hangup_signals (1); return 0; - write_error: - +write_error: slrn_fclose (fp); fp = NULL; - slrn_error (_("Write to %s failed! Disk Full?"), newsrc_filename); - /* Put back orginal file */ - if (have_backup) slrn_restore_backup (newsrc_filename); +write_error2: + slrn_error (_("Write to %s failed: %s"), newsrc_filename, strerror(errno)); +write_error3: + unlink(tmpfn); slrn_init_hangup_signals (1); return -1; diff --git a/src/hash.c b/src/hash.c index 8dc5b60..300894a 100644 --- a/src/hash.c +++ b/src/hash.c @@ -24,6 +24,8 @@ #include #include +#include +#include #include #include "jdmacros.h" @@ -32,23 +34,75 @@ #include "snprintf.h" #include "strutil.h" -unsigned long slrn_compute_hash (unsigned char *s, unsigned char *smax) -{ - register unsigned long h = 0, g; - register unsigned long sum = 0; +#define ROTATE(v,n) (((v) << (n)) | ((v) >> (32 - (n)))) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (((v) + (w))) + +#define __jhash_mix(a, b, c) \ +{ \ + a = XOR(a,ROTATE(PLUS(b, c), 7)); \ + b = XOR(b,ROTATE(PLUS(a, c), 9)); \ + c = XOR(c,ROTATE(PLUS(a, b), 13)); \ + \ + a = XOR(a,ROTATE(PLUS(b, c), 18)); \ + b = XOR(b,ROTATE(PLUS(a, c), 5)); \ + c = XOR(c,ROTATE(PLUS(a, b), 11)); \ + \ + a = XOR(a,ROTATE(PLUS(b, c), 15)); \ + b = XOR(b,ROTATE(PLUS(a, c), 19)); \ + c = XOR(c,ROTATE(PLUS(a, b), 24)); \ +} - while (s < smax) - { - sum += *s++ | 0x20; /* case-insensitive */ +/* The golden ration: an arbitrary value */ +#define JHASH_GOLDEN_RATIO (0x9e3779b9) - h = sum + (h << 3); - if ((g = h & 0xE0000000U) != 0) - { - h = h ^ (g >> 24); - h = h ^ g; - } - } - return h; +unsigned long slrn_compute_hash (unsigned char *k, unsigned char *kmax) +{ + uint32_t a, b, c, len, length; + static int rndinit; + static uint32_t cstatic; + len = length = (kmax - k); + a = b = JHASH_GOLDEN_RATIO; + if (!rndinit) { + struct timeval tv; + + rndinit = 1; + gettimeofday(&tv, NULL); + cstatic = tv.tv_sec ^ tv.tv_usec; + } + c = cstatic; + + /*---------------------------------------- handle most of the key */ + while (len >= 12) + { + a += ((k[0]|0x20) +((uint32_t)(k[1]|0x20)<<8) +((uint32_t)(k[2]|0x20)<<16) +((uint32_t)(k[3]|0x20)<<24)); + b += ((k[4]|0x20) +((uint32_t)(k[5]|0x20)<<8) +((uint32_t)(k[6]|0x20)<<16) +((uint32_t)(k[7]|0x20)<<24)); + c += ((k[8]|0x20) +((uint32_t)(k[9]|0x20)<<8) +((uint32_t)(k[10]|0x20)<<16)+((uint32_t)(k[11]|0x20)<<24)); + __jhash_mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((uint32_t)(k[10]|0x20)<<24); + case 10: c+=((uint32_t)(k[9]|0x20)<<16); + case 9 : c+=((uint32_t)(k[8]|0x20)<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((uint32_t)(k[7]|0x20)<<24); + case 7 : b+=((uint32_t)(k[6]|0x20)<<16); + case 6 : b+=((uint32_t)(k[5]|0x20)<<8); + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)(k[3]|0x20)<<24); + case 3 : a+=((uint32_t)(k[2]|0x20)<<16); + case 2 : a+=((uint32_t)(k[1]<0x20)<<8); + case 1 : a+=(k[0]|0x20); + /* case 0: nothing left to add */ + } + __jhash_mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; } #if SLRN_HAS_MSGID_CACHE @@ -70,25 +124,12 @@ typedef struct Newsgroup_Cache_Type } Newsgroup_Cache_Type; -#define MAX_MSGID_HASH 8017 -#define MAX_NG_HASH 2909 +#define MAX_MSGID_HASH 32768 +#define MAX_NG_HASH 8192 static Msg_Id_Cache_Type *Msg_Id_Cache [MAX_MSGID_HASH]; static Newsgroup_Cache_Type *Newsgroup_Cache [MAX_NG_HASH]; -static unsigned int simple_hash (unsigned char *s, unsigned char *smax, - unsigned int mod) -{ - register unsigned int h = 0; - - while (s < smax) - { - h = ((h << 5) + *s) % mod; - s++; - } - return h; -} - static char *allocate_newsgroup (char *newsgroup) { Newsgroup_Cache_Type *node; @@ -97,9 +138,8 @@ static char *allocate_newsgroup (char *newsgroup) len = strlen (newsgroup); - hash_index = simple_hash ((unsigned char *) newsgroup, - (unsigned char *) newsgroup + len, - MAX_NG_HASH); + hash_index = slrn_compute_hash ((unsigned char *) newsgroup, + (unsigned char *) newsgroup + len) % MAX_NG_HASH; node = Newsgroup_Cache [hash_index]; @@ -163,10 +203,8 @@ static Msg_Id_Cache_Type *is_msgid_cached (char *msgid, char *newsgroup, #endif msgid_len = strlen (msgid); - - hash_index = simple_hash ((unsigned char *) msgid, - (unsigned char *) msgid + msgid_len, - MAX_MSGID_HASH); + hash_index = slrn_compute_hash ((unsigned char *) msgid, + (unsigned char *) msgid + msgid_len) % MAX_MSGID_HASH; node = Msg_Id_Cache [hash_index]; diff --git a/src/misc.c b/src/misc.c index d6b1886..c8912df 100644 --- a/src/misc.c +++ b/src/misc.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef HAVE_STDLIB_H # include @@ -201,6 +202,43 @@ void slrn_redraw (void) /*{{{*/ /*}}}*/ +void Slrn_random_buf(void *buf, size_t len) +{ + ssize_t written; + uint8_t *p = buf; + + if (len > INT_MAX) { + slrn_exit_error("Slrn_random_buf: requested %zu bytes\n", len); + } + while (len > 0) { + do { + errno = 0; + written = getrandom(p, len, 0); + } while ((written == -1) && (errno == EINTR)); + if (written <= 0) { + slrn_exit_error("Slrn_random_buf: getrandom failed: %s\n", strerror(errno)); + } + p += written; + len -= written; + } +} + +uint32_t Slrn_random_u32(void) +{ + uint32_t ret; + + Slrn_random_buf(&ret, sizeof(ret)); + return ret; +} + +uint64_t Slrn_random_u64(void) +{ + uint64_t ret; + + Slrn_random_buf(&ret, sizeof(ret)); + return ret; +} + /* theoretically, buf needs at least space for 66 characters */ char *slrn_print_percent (char *buf, SLscroll_Window_Type *w, int lines) /*{{{*/ { @@ -958,33 +996,6 @@ void slrn_make_home_dirname (char *name, char *dir, size_t n) /*{{{*/ return; } -/*}}}*/ - -static unsigned int make_random (void) -{ - static unsigned long s; - static int init; - - if (init == 0) - { - s = (unsigned long) time (NULL) + (unsigned long) getpid (); - init = 1; - } - - s = s * 69069UL + 1013904243UL; - - /* The time has been added to make this number somewhat unpredictable - * based on the previous number. The whole point of this is to foil - * any attempt of a hacker to determine the name of the _next_ temp - * file that slrn will create. - */ - return (unsigned int) (s + (unsigned long) time (NULL)); -} - -/* Note: This function should not create a file that is deleted when it - * is closed. - */ - FILE *slrn_open_tmpfile_in_dir (char *dir, char *file, size_t n) { FILE *fp; @@ -997,11 +1008,13 @@ FILE *slrn_open_tmpfile_in_dir (char *dir, char *file, size_t n) return NULL; #endif + slrn_snprintf (buf, sizeof (buf), "SLRN%" #if defined(IBMPC_SYSTEM) - slrn_snprintf (buf, sizeof (buf), "SLRN%04u", make_random ()); + "04u" #else - slrn_snprintf (buf, sizeof (buf), "SLRN%X", make_random ()); + "X" #endif + , Slrn_random_u32 ()); if (-1 == slrn_dircat (dir, buf, file, n)) return NULL; diff --git a/src/misc.h b/src/misc.h index ff97a57..aec43be 100644 --- a/src/misc.h +++ b/src/misc.h @@ -23,9 +23,11 @@ #include #include #include +#include #include "ttymsg.h" #include "vfile.h" +#include "config.h" extern void slrn_make_home_filename (char *, char *, size_t); extern void slrn_make_home_dirname (char *, char *, size_t); @@ -151,4 +153,8 @@ extern char *Slrn_Top_Status_Line; extern int Slrn_Abort_Unmodified; +void Slrn_random_buf(void *buf, size_t len); +uint32_t Slrn_random_u32(); +uint64_t Slrn_random_u64(); + #endif /* _SLRN_MISC_H */ diff --git a/src/post.c b/src/post.c index 4289daa..7a444ef 100644 --- a/src/post.c +++ b/src/post.c @@ -98,13 +98,13 @@ static int postpone_file (char *); /* This function needs to be called directly after po_start! */ static int create_message_id (char **msgidp)/*{{{*/ { - char *t, *msgid; + char *msgid; #if SLRN_HAS_GEN_MSGID - unsigned long pid, now; - char baseid[64]; - char *b, tmp[32]; - char *chars32 = "0123456789abcdefghijklmnopqrstuv"; - static unsigned long last_now; +#define BASEIDLEN 16 + uint8_t baseid[BASEIDLEN+1]; + int i; + uint8_t *b; + static const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567"; size_t malloc_len; #endif @@ -119,72 +119,21 @@ static int create_message_id (char **msgidp)/*{{{*/ return 0; #else - if (Slrn_Generate_Message_Id == 0) + if ((Slrn_Generate_Message_Id == 0) || (Slrn_User_Info.posting_host == NULL)) return 0; - while (1) - { - if ((Slrn_User_Info.posting_host == NULL) - || ((time_t) -1 == time ((time_t *)&now))) - return 0; - - if (now != last_now) break; - slrn_sleep (1); - } - last_now = now; - - pid = (unsigned long) getpid (); - now -= 0x28000000; - b = baseid; - t = tmp; - while (now) - { - *t++ = chars32[now & 0x1F]; - now = now >> 5; - } - while (t > tmp) - { - t--; - *b++ = *t; - } - *b++ = '.'; - - t = tmp; - while (pid) - { - *t++ = chars32[pid & 0x1F]; - pid = pid >> 5; - } - while (t > tmp) - { - t--; - *b++ = *t; - } - - t = Slrn_User_Info.username; - if (t != NULL && *t != 0) - { - unsigned char ch = 0; - - *b++ = '.'; - while ((*t != 0) && (b < baseid + sizeof(baseid) - 2)) - { - if (((ch = *t) > ' ') && ((ch & 0x80) == 0) - && (NULL == slrn_strbyte ("<>()@,;:\\\"[]", ch))) - *b++ = ch; - t++; - } - if (*(b-1) == '.') /* may not be last character, so append '_' */ - *b++ = '_'; - } - *b = 0; + Slrn_random_buf(baseid, sizeof(baseid)); + for (i = 0; i < BASEIDLEN; i++) { + b[i] = base32[b[i] % (sizeof(base32) - 1)]; + } + b[i] = 0; - malloc_len=(strlen(baseid)+strlen(Slrn_User_Info.posting_host)+8); + malloc_len=(strlen(baseid)+strlen(Slrn_User_Info.posting_host)+9); if (NULL == (msgid=slrn_malloc (malloc_len,0,1))) return -1; - (void) SLsnprintf (msgid, malloc_len, "", baseid, Slrn_User_Info.posting_host); + (void) SLsnprintf (msgid, malloc_len, "", baseid, Slrn_User_Info.posting_host); *msgidp = msgid; return 0; @@ -227,7 +176,7 @@ int slrn_add_signature (FILE *fp) /*{{{*/ { FILE *sfp; char file[SLRN_MAX_PATH_LEN]; - char buf [256]; + char buf [4096]; if ((NULL != Slrn_Signoff_String) && (*Slrn_Signoff_String != 0)) { diff --git a/src/slrnpull.c b/src/slrnpull.c index e32b0a0..2d4bcc5 100644 --- a/src/slrnpull.c +++ b/src/slrnpull.c @@ -23,6 +23,7 @@ #define SLRNPULL_CODE #include "slrnfeat.h" +#include "misc.h" /*{{{ System Includes */ diff --git a/src/sltcp.c b/src/sltcp.c index 40ada13..0502323 100644 --- a/src/sltcp.c +++ b/src/sltcp.c @@ -21,6 +21,7 @@ */ #include "config.h" #include "slrnfeat.h" +#include "misc.h" /*{{{ Include Files */ @@ -508,46 +509,6 @@ static void dump_ssl_error_0 (void) print_error ("%s\n", ERR_error_string(err, 0)); } -#if !SLTCP_HAS_NSS_COMPAT -static unsigned long Fast_Random; -static unsigned long fast_random (void) -{ - return (Fast_Random = Fast_Random * 69069U + 1013904243U); -} -#endif - -static int init_ssl_random (void) -{ -#if !SLTCP_HAS_NSS_COMPAT - time_t t; - pid_t pid; - unsigned int count; - - if (RAND_status ()) - return 0; - - time (&t); - pid = getpid (); - RAND_seed ((unsigned char *) &pid, sizeof (time_t)); - RAND_seed ((unsigned char *) &t, sizeof (pid_t)); - - RAND_bytes ((unsigned char *) &Fast_Random, sizeof(long)); - - count = 0; - while ((count < 10000) - && (0 == RAND_status ())) - { - unsigned long r = fast_random (); - RAND_seed (&r, sizeof (unsigned long)); - } -#endif /* !SLTCP_HAS_NSS_COMPAT */ - if (RAND_status ()) - return 0; - - print_error (_("Unable to generate enough entropy\n")); - return -1; -} - #if SLTCP_HAS_GNUTLS_SUPPORT static void tls_log_func (int level, const char *str) { @@ -562,6 +523,7 @@ static SSL *alloc_ssl (void) if (This_SSL_Ctx == NULL) { SSL_CTX *c; + char rnd; SSLeay_add_ssl_algorithms (); c = SSL_CTX_new(SSLv23_client_method()); @@ -581,8 +543,9 @@ static SSL *alloc_ssl (void) This_SSL_Ctx = c; atexit (deinit_ssl); - if (-1 == init_ssl_random ()) - return NULL; + if (RAND_bytes(&rnd, sizeof(rnd)) != 1) { + slrn_exit_error (_("RAND_bytes failed.\n")); + } } #if SLTCP_HAS_GNUTLS_SUPPORT diff --git a/src/startup.c b/src/startup.c index 4e4cf22..ff084f9 100644 --- a/src/startup.c +++ b/src/startup.c @@ -33,6 +33,7 @@ #include #include +#include #include "jdmacros.h" @@ -1792,8 +1793,6 @@ int slrn_get_authorization (char *host, int reqd, char **name, char **pass) /*{{ /*}}}*/ -/*}}}*/ - static void slrn_init_modes (void) /*{{{*/ { slrn_init_group_mode (); diff --git a/src/ttymsg.h b/src/ttymsg.h index 6d62021..420982c 100644 --- a/src/ttymsg.h +++ b/src/ttymsg.h @@ -22,6 +22,8 @@ #include #include +#include "jdmacros.h" + extern void slrn_tty_vmessage (FILE *, char *, va_list); extern void slrn_tty_error (char *, ...) ATTRIBUTE_PRINTF(1,2); extern void slrn_tty_message (char *, ...) ATTRIBUTE_PRINTF(1,2); diff --git a/src/util.c b/src/util.c index 53ad204..7801088 100644 --- a/src/util.c +++ b/src/util.c @@ -20,6 +20,7 @@ */ #include "config.h" #include "slrnfeat.h" +#include "snprintf.h" #include #include @@ -403,15 +404,39 @@ int slrn_delete_file (char *f) /*{{{*/ /*}}}*/ -int slrn_fclose (FILE *fp) /*{{{*/ -{ +static int __slrn_fclose_fsync (FILE *fp, int do_fsync) /*{{{*/ + { + if (EOF == fflush (fp)) { + slrn_error (_("Error writing file. (errno = %d: %s)"), errno, strerror(errno)); + fclose (fp); + return -1; + } + if (do_fsync && fsync (fileno (fp)) == -1) { + slrn_error (_("Error fsyncing file. (errno = %d: %s)"), errno, strerror(errno)); + fclose (fp); + return -1; + } if (0 == fclose (fp)) return 0; - slrn_error (_("Error closing file. File system full? (errno = %d)"), errno); + slrn_error (_("Error closing file: %s)"), strerror(errno)); return -1; } /*}}}*/ +int slrn_fclose (FILE *fp) /*{{{*/ +{ + return __slrn_fclose_fsync (fp, 0); +} + +/*}}}*/ + +int slrn_fclose_fsync (FILE *fp) /*{{{*/ +{ + return __slrn_fclose_fsync (fp, 1); +} + +/*}}}*/ + int slrn_file_exists (char *file) /*{{{*/ { struct stat st; @@ -513,6 +538,10 @@ int slrn_copy_file (char *infile, char *outfile) FILE *in, *out; int ch; int ret; + char *tmpfn; + int tmpfd; + char inbuf[8192]; + size_t nread; if ((infile == NULL) || (outfile == NULL)) return -1; @@ -526,28 +555,38 @@ int slrn_copy_file (char *infile, char *outfile) return -1; } - if (NULL == (out = fopen (outfile, "wb"))) + tmpfn = slrn_strdup_printf ("%s.tmp.XXXXXX", outfile); + tmpfd = mkstemp(tmpfn); + if ((-1 == tmpfd) || (NULL == (out = fdopen (tmpfd, "wb")))) { fclose (in); - slrn_error (_("Error opening %s"), outfile); + slrn_error (_("Error opening %s: %s"), outfile, strerror(errno)); + SLfree(tmpfn); return -1; } ret = 0; - while (EOF != (ch = getc (in))) - { - if (EOF == putc (ch, out)) - { - slrn_error (_("Write Error: %s"), outfile); - ret = -1; - break; - } + + while (!feof(in) && !ferror(in)) { + nread = fread(inbuf, 1, sizeof(inbuf), in); + if (nread > 0) { + if (fwrite(inbuf, 1, nread, out) != nread) { + slrn_error (_("Write Error: %s: %s"), outfile, strerror(errno)); + ret = -1; + break; + } } + } fclose (in); - if (-1 == slrn_fclose (out)) + if (-1 == slrn_fclose_fsync (out)) ret = -1; + if (rename (tmpfn, outfile) == -1) + ret = -1; + + SLfree(tmpfn); + return ret; } @@ -559,7 +598,6 @@ int slrn_move_file (char *infile, char *outfile) if (file_eqs (infile, outfile)) return 0; - (void) slrn_delete_file (outfile); if (-1 == rename (infile, outfile)) { if (-1 == slrn_copy_file (infile, outfile)) @@ -609,9 +647,8 @@ int slrn_create_backup (char *filename) if (0 == lstat (filename, &st)) { - do_copy = (st.st_nlink > 1) # ifdef S_ISLNK - || (S_ISLNK(st.st_mode)) + do_copy = (S_ISLNK(st.st_mode)) # endif ; } @@ -619,8 +656,10 @@ int slrn_create_backup (char *filename) if (slrn_file_exists(filename)) { - if (!do_copy) - retval = rename (filename, backup_file); + if (!do_copy) { + unlink (backup_file); + retval = link (filename, backup_file); + } if (retval == -1) retval = slrn_copy_file (filename, backup_file); } @@ -649,9 +688,8 @@ int slrn_restore_backup (char *filename) if (0 == lstat (filename, &st)) { - do_copy = (st.st_nlink > 1) # ifdef S_ISLNK - || (S_ISLNK(st.st_mode)) + do_copy = (S_ISLNK(st.st_mode)) # endif ; } diff --git a/src/util.h b/src/util.h index d9ce014..8255c55 100644 --- a/src/util.h +++ b/src/util.h @@ -34,6 +34,7 @@ extern char *slrn_spool_dircat (char *, char *, int); extern int slrn_copy_file (char *, char *); extern int slrn_move_file (char *, char *); extern int slrn_fclose (FILE *); +extern int slrn_fclose_fsync (FILE *); extern int slrn_delete_file (char *); extern int slrn_file_exists (char *); extern int slrn_file_size (char *);