From ae0ce4dfcafa0c3820f107c5bfa8bd06e5272b57 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 30 Oct 2006 00:32:31 +0100 Subject: [PATCH] revamp lib.[hc] functions into lib-lib/file.[hc]. also add some useful and safe m_str* functions --- alias.c | 1 + attach.c | 1 + browser.c | 21 +-- commands.c | 2 +- complete.c | 5 +- compose.c | 4 +- compress.c | 1 + copy.c | 2 + crypt-gpgme.c | 1 + crypt.c | 1 + curs_lib.c | 1 + edit.c | 1 + editmsg.c | 1 + enter.c | 4 +- getdomain.c | 1 + handler.c | 1 + headers.c | 1 + help.c | 1 + hook.c | 3 +- imap/message.c | 1 + imap/mx_imap.c | 1 + init.c | 7 +- keymap.c | 6 +- lib-lib/Makefile.am | 6 +- lib-lib/file.c | 415 ++++++++++++++++++++++++++++++++++++++++++++ lib-lib/file.h | 70 ++++++++ lib-lib/macros.h | 9 + lib-lib/str.c | 15 ++ lib-lib/str.h | 13 ++ lib.c | 367 +-------------------------------------- lib.h | 26 --- lib/debug.c | 1 + main.c | 1 + mbox.c | 1 + mh.c | 1 + mutt_sasl.h | 2 +- mutt_ssl_gnutls.c | 1 + muttlib.c | 5 +- mx.c | 1 + nntp/newsrc.c | 8 +- nntp/nntp.c | 1 + pattern.c | 1 + pgp.c | 1 + pgpinvoke.c | 1 + pgpkey.c | 1 + pgpmicalg.c | 1 + pop/pop.c | 1 + postpone.c | 1 + query.c | 1 + recvattach.c | 5 +- recvcmd.c | 1 + remailer.c | 1 + rfc1524.c | 1 + rfc3676.c | 1 + send.c | 1 + sendlib.c | 1 + smime.c | 1 + 57 files changed, 605 insertions(+), 426 deletions(-) create mode 100644 lib-lib/file.c create mode 100644 lib-lib/file.h diff --git a/alias.c b/alias.c index b1acd23..f791206 100644 --- a/alias.c +++ b/alias.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "lib/rx.h" diff --git a/attach.c b/attach.c index 96867b9..8b9cb82 100644 --- a/attach.c +++ b/attach.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "mutt.h" diff --git a/browser.c b/browser.c index 12506b3..3fd3563 100644 --- a/browser.c +++ b/browser.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" @@ -154,7 +155,7 @@ static int link_is_dir (const char *folder, const char *path) struct stat st; char fullpath[_POSIX_PATH_MAX]; - mutt_concat_path (fullpath, folder, path, sizeof (fullpath)); + mutt_concat_path(fullpath, sizeof(fullpath), folder, path); if (stat (fullpath, &st) == 0) return (S_ISDIR (st.st_mode)); @@ -539,7 +540,7 @@ static int examine_directory (MUTTMENU * menu, struct browser_state *state, if (!((regexec (Mask.rx, de->d_name, 0, NULL, 0) == 0) ^ Mask.not)) continue; - mutt_concat_path (buffer, d, de->d_name, sizeof (buffer)); + mutt_concat_path(buffer, sizeof(buffer), d, de->d_name); if (lstat (buffer, &s) == -1) continue; @@ -879,8 +880,8 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, } #endif else - mutt_concat_path (buf, LastDir, state.entry[menu->current].name, - sizeof (buf)); + mutt_concat_path(buf, sizeof(buf), LastDir, + state.entry[menu->current].name); if ((mx_get_magic (buf) <= 0) #ifdef USE_IMAP @@ -936,8 +937,8 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, else { char tmp[_POSIX_PATH_MAX]; - mutt_concat_path (tmp, LastDir, state.entry[menu->current].name, - sizeof (tmp)); + mutt_concat_path(tmp, sizeof(tmp), LastDir, + state.entry[menu->current].name); strfcpy (LastDir, tmp, sizeof (LastDir)); } @@ -986,7 +987,7 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, strfcpy (f, state.entry[menu->current].name, flen); #endif else - mutt_concat_path (f, LastDir, state.entry[menu->current].name, flen); + mutt_concat_path(f, flen, LastDir, state.entry[menu->current].name); /* Fall through to OP_EXIT */ @@ -1004,7 +1005,7 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, char full[_POSIX_PATH_MAX]; if (ff.tagged) { - mutt_concat_path (full, LastDir, ff.name, sizeof (full)); + mutt_concat_path(full, sizeof(full), LastDir, ff.name); mutt_expand_path (full, sizeof (full)); tfiles[j++] = m_strdup(full); } @@ -1358,8 +1359,8 @@ void _mutt_select_file (char *f, size_t flen, int flags, char ***files, BODY *b; char buf[_POSIX_PATH_MAX]; - mutt_concat_path (buf, LastDir, state.entry[menu->current].name, - sizeof (buf)); + mutt_concat_path(buf, sizeof(buf), LastDir, + state.entry[menu->current].name); b = mutt_make_file_attach (buf); if (b != NULL) { mutt_view_attachment (NULL, b, M_REGULAR, NULL, NULL, 0); diff --git a/commands.c b/commands.c index eaf2249..2cfb5e8 100644 --- a/commands.c +++ b/commands.c @@ -13,7 +13,7 @@ #endif #include - +#include #include #include diff --git a/complete.c b/complete.c index 491d897..649fa0a 100644 --- a/complete.c +++ b/complete.c @@ -21,6 +21,7 @@ #endif #include +#include #include "lib/debug.h" #include @@ -104,7 +105,7 @@ int mutt_complete (char *s, size_t slen) /* we can use '/' as a delimiter, imap_complete rewrites it */ if (*s == '=' || *s == '+' || *s == '!') { const char *q = NONULL(*s == '!' ? Spoolfile : Maildir); - mutt_concat_path (imap_path, q, s + 1, sizeof (imap_path)); + mutt_concat_path(imap_path, sizeof(imap_path), q, s + 1); } else strfcpy (imap_path, s, sizeof (imap_path)); @@ -124,7 +125,7 @@ int mutt_complete (char *s, size_t slen) char buf[_POSIX_PATH_MAX]; *p++ = 0; - mutt_concat_path (buf, exp_dirpart, s + 1, sizeof (buf)); + mutt_concat_path(buf, sizeof(buf), exp_dirpart, s + 1); strfcpy (exp_dirpart, buf, sizeof (exp_dirpart)); snprintf (buf, sizeof (buf), "%s%s/", dirpart, s + 1); strfcpy (dirpart, buf, sizeof (dirpart)); diff --git a/compose.c b/compose.c index 5a9c76a..d2942ea 100644 --- a/compose.c +++ b/compose.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" @@ -709,7 +710,8 @@ int mutt_compose_menu (HEADER * msg, /* structure for new message */ if (m_strcmp("builtin", Editor) != 0 && (op == OP_COMPOSE_EDIT_HEADERS || (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS)))) { - const char *tag = NULL, *err = NULL; + const char *tag = NULL; + char *err = NULL; mutt_env_to_local (msg->env); mutt_edit_headers (NONULL (Editor), msg->content->filename, msg, diff --git a/compress.c b/compress.c index 14910a8..01be9d3 100644 --- a/compress.c +++ b/compress.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "mutt.h" diff --git a/copy.c b/copy.c index b265b66..717265b 100644 --- a/copy.c +++ b/copy.c @@ -11,8 +11,10 @@ # include "config.h" #endif +#include #include #include +#include #include #include "mutt.h" diff --git a/crypt-gpgme.c b/crypt-gpgme.c index 18ca2a5..9728bcc 100644 --- a/crypt-gpgme.c +++ b/crypt-gpgme.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "mutt.h" #include "mutt_crypt.h" diff --git a/crypt.c b/crypt.c index 83ab1ad..923b8d7 100644 --- a/crypt.c +++ b/crypt.c @@ -17,6 +17,7 @@ #endif #include +#include #include #include #include diff --git a/curs_lib.c b/curs_lib.c index 002c063..3e9f31a 100644 --- a/curs_lib.c +++ b/curs_lib.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" diff --git a/edit.c b/edit.c index 4360c1f..07bc98d 100644 --- a/edit.c +++ b/edit.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" diff --git a/editmsg.c b/editmsg.c index 347b6ae..cb6616f 100644 --- a/editmsg.c +++ b/editmsg.c @@ -14,6 +14,7 @@ #endif #include +#include #include #include "mutt.h" diff --git a/enter.c b/enter.c index 95c26bd..cc3b379 100644 --- a/enter.c +++ b/enter.c @@ -120,7 +120,7 @@ static void my_wcstombs (char *dest, size_t dlen, const wchar_t * src, } } -size_t my_mbstowcs (wchar_t ** pwbuf, size_t * pwbuflen, size_t i, char *buf) +size_t my_mbstowcs (wchar_t ** pwbuf, size_t * pwbuflen, size_t i, const char *buf) { wchar_t wc; mbstate_t st; @@ -155,7 +155,7 @@ static void replace_part (ENTER_STATE *state, size_t from, const char *buf) memcpy (savebuf, state->wbuf + state->curpos, savelen * sizeof (wchar_t)); /* Convert to wide characters */ - state->curpos = my_mbstowcs (&state->wbuf, &state->wbuflen, from, buf); + state->curpos = my_mbstowcs(&state->wbuf, &state->wbuflen, from, buf); /* Make space for suffix */ if (state->curpos + savelen > state->wbuflen) { diff --git a/getdomain.c b/getdomain.c index ee711cc..1ffd40c 100644 --- a/getdomain.c +++ b/getdomain.c @@ -15,6 +15,7 @@ #include #include +#include #include "mutt.h" #ifndef STDC_HEADERS diff --git a/handler.c b/handler.c index 553ff29..a118df7 100644 --- a/handler.c +++ b/handler.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "mutt.h" #include "recvattach.h" diff --git a/headers.c b/headers.c index 1c928fa..3f64694 100644 --- a/headers.c +++ b/headers.c @@ -13,6 +13,7 @@ #include #include +#include #include "mutt.h" #include "mutt_crypt.h" diff --git a/help.c b/help.c index 72d0610..f01bbea 100644 --- a/help.c +++ b/help.c @@ -14,6 +14,7 @@ #endif #include +#include #include #include "mutt.h" diff --git a/hook.c b/hook.c index 1f8fc1e..6432787 100644 --- a/hook.c +++ b/hook.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "mutt.h" #include "mx.h" @@ -407,7 +408,7 @@ void mutt_select_fcc (char *path, size_t pathlen, HEADER * hdr) (env->to || env->cc || env->bcc)) { adr = env->to ? env->to : (env->cc ? env->cc : env->bcc); mutt_safe_path (buf, sizeof (buf), adr); - mutt_concat_path (path, NONULL (Maildir), buf, pathlen); + mutt_concat_path(path, pathlen, NONULL(Maildir), buf); if (!option (OPTFORCENAME) && mx_access (path, W_OK) != 0) strfcpy (path, NONULL (Outbox), pathlen); } diff --git a/imap/message.c b/imap/message.c index 89cf1a0..1dddd52 100644 --- a/imap/message.c +++ b/imap/message.c @@ -34,6 +34,7 @@ #endif #include +#include #include "lib/debug.h" #if HAVE_STDINT_H diff --git a/imap/mx_imap.c b/imap/mx_imap.c index a851537..f3bb4f3 100644 --- a/imap/mx_imap.c +++ b/imap/mx_imap.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "mutt.h" diff --git a/init.c b/init.c index 88d3423..a456c16 100644 --- a/init.c +++ b/init.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -1619,7 +1620,7 @@ static struct option_t* add_user_option (const char* name) { /* free()'s option_t* */ static void del_option (void* p) { - struct option_t* ptr = (struct option_t*) p; + struct option_t *ptr = (struct option_t*) p; char* s = (char*) ptr->data; debug_print (1, ("removing option '%s' from table\n", NONULL (ptr->option))); p_delete(&ptr->option); @@ -2685,9 +2686,9 @@ void mutt_init (int skip_sys_rc, LIST * commands) Spoolfile = m_strdup(p); else { #ifdef HOMESPOOL - mutt_concat_path (buffer, NONULL (Homedir), MAILPATH, sizeof(buffer)); + mutt_concat_path(buffer, sizeof(buffer), NONULL(Homedir), MAILPATH); #else - mutt_concat_path (buffer, MAILPATH, NONULL (Username), sizeof(buffer)); + mutt_concat_path(buffer, sizeof(buffer), MAILPATH, NONULL(Username)); #endif Spoolfile = m_strdup(buffer); } diff --git a/keymap.c b/keymap.c index 29e0dcd..0c450f7 100644 --- a/keymap.c +++ b/keymap.c @@ -272,9 +272,9 @@ static const char *get_func (struct binding_t *bindings, int op) return NULL; } -static void push_string (char *s) +static void push_string(const char *s) { - char *pp, *p = s + m_strlen(s) - 1; + const char *pp, *p = s + m_strlen(s) - 1; size_t l; int i, op = OP_NULL; @@ -403,7 +403,7 @@ int km_dokey (int menu) /* careful not to feed the <..> as one token. otherwise * push_string() will push the bogus op right back! */ mutt_ungetch ('>', 0); - push_string (func); + push_string(func); mutt_ungetch ('<', 0); break; } diff --git a/lib-lib/Makefile.am b/lib-lib/Makefile.am index a11995b..c6c6da1 100644 --- a/lib-lib/Makefile.am +++ b/lib-lib/Makefile.am @@ -1,7 +1,7 @@ noinst_LIBRARIES = liblib.a -liblib_a_SOURCES = mem.h str.h ascii.h buffer.h hash.h list.h \ - str.c ascii.c buffer.c hash.c list.c +liblib_a_SOURCES = mem.h str.h ascii.h buffer.h hash.h list.h file.h \ + str.c ascii.c buffer.c hash.c list.c file.c -noinst_HEADERS = mem.h str.h ascii.h buffer.h hash.h list.h +noinst_HEADERS = mem.h str.h ascii.h buffer.h hash.h list.h file.h diff --git a/lib-lib/file.c b/lib-lib/file.c new file mode 100644 index 0000000..793ac10 --- /dev/null +++ b/lib-lib/file.c @@ -0,0 +1,415 @@ +/* + * 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * Copyright © 2006 Pierre Habouzit + */ +/* + * Copyright notice from original mutt: + * Copyright (C) 1996-2000 Michael R. Elkins + * Copyright (C) 1999-2000 Thomas Roessler + * + * This file is part of mutt-ng, see http://www.muttng.org/. + * It's licensed under the GNU General Public License, + * please see the file GPL in the top level source directory. + */ + +#include +#include +#include +#include +#include +#include + +#include "macros.h" +#include "mem.h" +#include "str.h" +#include "file.h" + +#include "../lib/debug.h" +#include "../lib/str.h" + +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif + +/* FIXME: ugly to the max */ +extern short Umask; + +static int compare_stat(struct stat *osb, struct stat *nsb) +{ + if (osb->st_dev != nsb->st_dev || osb->st_ino != nsb->st_ino + || osb->st_rdev != nsb->st_rdev) + { + return -1; + } + + return 0; +} + +/****************************************************************************/ +/* fd ops */ +/****************************************************************************/ + +int safe_open(const char *path, int flags) +{ + struct stat osb, nsb; + int fd; + + umask(Umask); + + if ((fd = open(path, flags, 0666)) < 0) + return fd; + + /* make sure the file is not symlink */ + if (lstat (path, &osb) < 0 || fstat(fd, &nsb) < 0 + || compare_stat(&osb, &nsb) == -1) + { + debug_print(1, ("%s is a symlink!\n", path)); + close(fd); + return -1; + } + + return (fd); +} + + +int safe_symlink(const char *oldpath, const char *newpath) +{ + struct stat osb, nsb; + + if (!oldpath || !newpath) + return -1; + + if (unlink(newpath) < 0 && errno != ENOENT) + return -1; + + if (oldpath[0] == '/') { + if (symlink(oldpath, newpath) < 0) + return -1; + } else { + char abs_oldpath[_POSIX_PATH_MAX]; + ssize_t len; + + if (!getcwd(abs_oldpath, sizeof(abs_oldpath))) + return -1; + + len = m_strcat(abs_oldpath, sizeof(abs_oldpath), "/"); + if (len >= sizeof(abs_oldpath)) + return -1; + + len += m_strcpy(abs_oldpath + len, sizeof(abs_oldpath) - len, oldpath); + if (len >= sizeof(abs_oldpath)) + return -1; + + if (symlink (abs_oldpath, newpath) < 0) + return -1; + } + + if (stat(oldpath, &osb) < 0 + || stat(newpath, &nsb) < 0 + || compare_stat(&osb, &nsb) < 0) + { + unlink (newpath); + return -1; + } + + return 0; +} + +/* + * This function is supposed to do nfs-safe renaming of files. + * + * Warning: We don't check whether src and target are equal. + */ +int safe_rename(const char *src, const char *target) +{ + struct stat ssb, tsb; + + if (!src || !target) + return -1; + + if (link(src, target) != 0) { + /* + * Coda does not allow cross-directory links, but tells + * us it's a cross-filesystem linking attempt. + * + * However, the Coda rename call is allegedly safe to use. + * + * With other file systems, rename should just fail when + * the files reside on different file systems, so it's safe + * to try it here. + * + */ + + if (errno == EXDEV) + return rename(src, target); + + return -1; + } + + /* Stat both links and check if they are equal. */ + + if (stat(src, &ssb) < 0 || stat(target, &tsb) < 0) { + return -1; + } + + /* + * pretend that the link failed because the target file + * did already exist. + */ + + if (compare_stat(&ssb, &tsb) == -1) { + errno = EEXIST; + return -1; + } + + /* + * Unlink the original link. Should we really ignore the return + * value here? XXX + */ + + unlink(src); + return 0; +} + +void mutt_unlink(const char *s) +{ + struct stat sb, sb2; + + if (lstat(s, &sb) == 0 && S_ISREG(sb.st_mode)) { + int fd; + FILE *f; + + /* Defend against symlink attacks */ + + if ((fd = open(s, O_RDWR | O_NOFOLLOW)) < 0) + return; + + if ((fstat(fd, &sb2) != 0) || !S_ISREG(sb2.st_mode) + || (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino)) + { + close (fd); + return; + } + + if ((f = fdopen(fd, "r+"))) { + char buf[BUFSIZ]; + unlink(s); + + p_clear(buf, sizeof(buf)); + while (sb.st_size > 0) { + fwrite(buf, 1, MIN(sizeof(buf), sb.st_size), f); + sb.st_size -= MIN(sizeof(buf), sb.st_size); + } + fclose (f); + } + } +} + + +/****************************************************************************/ +/* FILE* ops */ +/****************************************************************************/ + +/* when opening files for writing, make sure the file doesn't already exist + to avoid race conditions. */ +FILE *safe_fopen(const char *path, const char *mode) +{ + /* first set the current umask */ + umask(Umask); + + if (mode[0] == 'w') { + int fd; + int flags = O_CREAT | O_EXCL | O_NOFOLLOW; + + flags |= (mode[1] == '+' ? O_RDWR : O_WRONLY); + + if ((fd = safe_open(path, flags)) < 0) + return (NULL); + + return fdopen (fd, mode); + } + + return fopen(path, mode); +} + +int safe_fclose(FILE **f) +{ + int r = 0; + + if (*f) + r = fclose (*f); + *f = NULL; + return r; +} + +/* Read a line from ``fp'' into the dynamically allocated ``s'', + * increasing ``s'' if necessary. The ending "\n" or "\r\n" is removed. + * If a line ends with "\", this char and the linefeed is removed, + * and the next line is read too. + */ +char *mutt_read_line(char *s, size_t *size, FILE * fp, int *line) +{ + size_t offset = 0; + char *ch; + + if (!s) { + s = p_new(char, STRING); + *size = STRING; + } + + for (;;) { + if (fgets(s + offset, *size - offset, fp) == NULL) { + p_delete(&s); + return NULL; + } + if ((ch = strchr(s + offset, '\n')) != NULL) { + (*line)++; + *ch = 0; + if (ch > s && *(ch - 1) == '\r') + *--ch = 0; + if (ch == s || *(ch - 1) != '\\') + return s; + offset = ch - s - 1; + } else { + int c; + + c = getc (fp); /* This is kind of a hack. We want to know if the + char at the current point in the input stream is EOF. + feof() will only tell us if we've already hit EOF, not + if the next character is EOF. So, we need to read in + the next character and manually check if it is EOF. */ + if (c == EOF) { + /* The last line of fp isn't \n terminated */ + (*line)++; + return s; + } else { + ungetc (c, fp); /* undo our dammage */ + /* There wasn't room for the line -- increase ``s'' */ + offset = *size - 1; /* overwrite the terminating 0 */ + *size += STRING; + p_realloc(&s, *size); + } + } + } +} + +int mutt_copy_stream(FILE *fin, FILE *fout) +{ + char buf[BUFSIZ]; + ssize_t l; + + while ((l = fread(buf, 1, sizeof (buf), fin)) > 0) { + if (fwrite(buf, 1, l, fout) != l) + return -1; + } + + return 0; +} + +int mutt_copy_bytes(FILE *in, FILE *out, size_t size) +{ + char buf[BUFSIZ]; + + while (size > 0) { + ssize_t chunk = MIN(size, sizeof(buf)); + + if ((chunk = fread(buf, 1, chunk, in)) < 1) + break; + if (fwrite(buf, 1, chunk, out) != chunk) { + debug_print(1, ("fwrite() returned short byte count\n")); + return -1; + } + size -= chunk; + } + + return 0; +} + + +/****************************************************************************/ +/* ligben-like funcs */ +/****************************************************************************/ + +const char *mutt_basename(const char *f) +{ + const char *p = strrchr(f, '/'); + return p ? p + 1 : f; +} + + +char * +mutt_concat_path(char *d, ssize_t n, const char *dir, const char *fname) +{ + const char *fmt = "%s/%s"; + + if (!*fname || (*dir && dir[m_strlen(dir) - 1] == '/')) + fmt = "%s%s"; + + snprintf(d, n, fmt, dir, fname); + return d; +} + + +void mutt_sanitize_filename(char *s, short slash) +{ + static char safe_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"; + + if (!s) + return; + + for (; *s; s++) { + if ((slash && *s == '/') || !strchr (safe_chars, *s)) + *s = '_'; + } +} + +/* prepare a file name to survive the shell's quoting rules. + * From the Unix programming FAQ by way of Liviu. + */ + +/* FIXME: API is very wrong */ +ssize_t mutt_quote_filename(char *d, ssize_t l, const char *s) +{ + size_t i, j = 0; + + if (!s) { + *d = '\0'; + return 0; + } + + /* leave some space for the trailing characters. */ + l -= 6; + + d[j++] = '\''; + + for (i = 0; j < l && s[i]; i++) { + if (s[i] == '\'' || s[i] == '`') { + d[j++] = '\''; + d[j++] = '\\'; + d[j++] = s[i]; + d[j++] = '\''; + } else { + d[j++] = s[i]; + } + } + + d[j++] = '\''; + d[j] = '\0'; + + return j; +} diff --git a/lib-lib/file.h b/lib-lib/file.h new file mode 100644 index 0000000..2f168e3 --- /dev/null +++ b/lib-lib/file.h @@ -0,0 +1,70 @@ +/* + * 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * Copyright © 2006 Pierre Habouzit + */ +/* + * Copyright notice from original mutt: + * Copyright (C) 1996-2000 Michael R. Elkins + * Copyright (C) 1999-2000 Thomas Roessler + * + * This file is part of mutt-ng, see http://www.muttng.org/. + * It's licensed under the GNU General Public License, + * please see the file GPL in the top level source directory. + */ + +/* + * File manipulations + saner libgen functions + */ + +#ifndef MUTT_LIB_LIB_FILE_H +#define MUTT_LIB_LIB_FILE_H + +#include +#include + +/****************************************************************************/ +/* fd ops */ +/****************************************************************************/ + +int safe_open(const char *, int); +int safe_symlink(const char *, const char *); +int safe_rename(const char *, const char *); +void mutt_unlink(const char *); + +/****************************************************************************/ +/* FILE* ops */ +/****************************************************************************/ + +FILE *safe_fopen(const char *, const char *); +int safe_fclose(FILE **); + +char *mutt_read_line(char *, size_t *, FILE *, int *); + +int mutt_copy_stream(FILE *, FILE *); +int mutt_copy_bytes(FILE *, FILE *, size_t); + +/****************************************************************************/ +/* ligben-like funcs */ +/****************************************************************************/ + +const char *mutt_basename(const char *); +char *mutt_concat_path(char *, ssize_t, const char *, const char *); + +void mutt_sanitize_filename(char *, short); +ssize_t mutt_quote_filename(char *, ssize_t, const char *); + +#endif /* MUTT_LIB_LIB_FILE_H */ diff --git a/lib-lib/macros.h b/lib-lib/macros.h index 8eaf0ee..1867d7b 100644 --- a/lib-lib/macros.h +++ b/lib-lib/macros.h @@ -41,4 +41,13 @@ # define N_(a) (a) #endif + +#define TRUE 1 +#define FALSE 0 + +#undef MAX +#undef MIN +#define MAX(a,b) ((a) < (b) ? (b) : (a)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + #endif /* MUTT_LIB_LIB_MACROS_H */ diff --git a/lib-lib/str.c b/lib-lib/str.c index ca0aff7..fd5fbce 100644 --- a/lib-lib/str.c +++ b/lib-lib/str.c @@ -17,4 +17,19 @@ * Copyright © 2006 Pierre Habouzit */ +#include "macros.h" #include "str.h" + +ssize_t m_strcpy(char *dst, ssize_t n, const char *src) +{ + ssize_t len = m_strlen(src); + + if (dst && n > 0) { + ssize_t dlen = MIN(n - 1, len); + memcpy(dst, src, dlen); + dst[dlen] = '\0'; + } + + return len; +} + diff --git a/lib-lib/str.h b/lib-lib/str.h index d21e120..3694371 100644 --- a/lib-lib/str.h +++ b/lib-lib/str.h @@ -31,6 +31,11 @@ static inline ssize_t m_strlen(const char *s) { return s ? strlen(s) : 0; } +static inline ssize_t m_strnlen(const char *s, ssize_t n) { + const char *p = memchr(s, '\0', n); + return p ? p - s : n; +} + static inline char *m_strdup(const char *s) { return p_dupstr(s, m_strlen(s)); } @@ -39,4 +44,12 @@ static inline int m_strcmp(const char *a, const char *b) { return strcmp(NONULL(a), NONULL(b)); } + +ssize_t m_strcpy(char *dst, ssize_t n, const char *src); + +static inline ssize_t m_strcat(char *dst, ssize_t n, const char *src) { + ssize_t dlen = m_strnlen(dst, n); + return dlen + m_strcpy(dst + dlen, n - dlen, src); +} + #endif /* MUTT_LIB_LIB_STR_H */ diff --git a/lib.c b/lib.c index 974f5ba..33d377f 100644 --- a/lib.c +++ b/lib.c @@ -34,6 +34,7 @@ #define EX_OK 0 #endif +#include #include #include @@ -41,8 +42,6 @@ #include "lib/debug.h" -extern short Umask; - static struct sysexits { int v; @@ -109,261 +108,6 @@ void mutt_nocurses_error (const char *fmt, ...) fputc ('\n', stderr); } -int safe_fclose (FILE ** f) -{ - int r = 0; - - if (*f) - r = fclose (*f); - - *f = NULL; - return r; -} - -void mutt_unlink (const char *s) -{ - int fd; - int flags; - FILE *f; - struct stat sb, sb2; - char buf[2048]; - - /* Defend against symlink attacks */ - -#ifdef O_NOFOLLOW - flags = O_RDWR | O_NOFOLLOW; -#else - flags = O_RDWR; -#endif - - if (lstat (s, &sb) == 0 && S_ISREG (sb.st_mode)) { - if ((fd = open (s, flags)) < 0) - return; - - if ((fstat (fd, &sb2) != 0) || !S_ISREG (sb2.st_mode) - || (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino)) { - close (fd); - return; - } - - if ((f = fdopen (fd, "r+"))) { - unlink (s); - p_clear(buf, sizeof(buf)); - while (sb.st_size > 0) { - fwrite (buf, 1, MIN (sizeof (buf), sb.st_size), f); - sb.st_size -= MIN (sizeof (buf), sb.st_size); - } - fclose (f); - } - } -} - -int mutt_copy_bytes (FILE * in, FILE * out, size_t size) -{ - char buf[2048]; - size_t chunk; - - while (size > 0) { - chunk = (size > sizeof (buf)) ? sizeof (buf) : size; - if ((chunk = fread (buf, 1, chunk, in)) < 1) - break; - if (fwrite (buf, 1, chunk, out) != chunk) { - debug_print (1, ("fwrite() returned short byte count\n")); - return (-1); - } - size -= chunk; - } - - return 0; -} - -int mutt_copy_stream (FILE * fin, FILE * fout) -{ - size_t l; - char buf[LONG_STRING]; - - while ((l = fread (buf, 1, sizeof (buf), fin)) > 0) { - if (fwrite (buf, 1, l, fout) != l) - return (-1); - } - - return 0; -} - -static int compare_stat (struct stat *osb, struct stat *nsb) -{ - if (osb->st_dev != nsb->st_dev || osb->st_ino != nsb->st_ino || - osb->st_rdev != nsb->st_rdev) { - return -1; - } - - return 0; -} - -int safe_symlink (const char *oldpath, const char *newpath) -{ - struct stat osb, nsb; - - if (!oldpath || !newpath) - return -1; - - if (unlink (newpath) == -1 && errno != ENOENT) - return -1; - - if (oldpath[0] == '/') { - if (symlink (oldpath, newpath) == -1) - return -1; - } - else { - char abs_oldpath[_POSIX_PATH_MAX]; - - if ((getcwd (abs_oldpath, sizeof abs_oldpath) == NULL) || - (m_strlen(abs_oldpath) + 1 + m_strlen(oldpath) + 1 > - sizeof abs_oldpath)) - return -1; - - strcat (abs_oldpath, "/"); /* __STRCAT_CHECKED__ */ - strcat (abs_oldpath, oldpath); /* __STRCAT_CHECKED__ */ - if (symlink (abs_oldpath, newpath) == -1) - return -1; - } - - if (stat (oldpath, &osb) == -1 || stat (newpath, &nsb) == -1 - || compare_stat (&osb, &nsb) == -1) { - unlink (newpath); - return -1; - } - - return 0; -} - -/* - * This function is supposed to do nfs-safe renaming of files. - * - * Warning: We don't check whether src and target are equal. - */ - -int safe_rename (const char *src, const char *target) -{ - struct stat ssb, tsb; - - if (!src || !target) - return -1; - - if (link (src, target) != 0) { - - /* - * Coda does not allow cross-directory links, but tells - * us it's a cross-filesystem linking attempt. - * - * However, the Coda rename call is allegedly safe to use. - * - * With other file systems, rename should just fail when - * the files reside on different file systems, so it's safe - * to try it here. - * - */ - - if (errno == EXDEV) - return rename (src, target); - - return -1; - } - - /* - * Stat both links and check if they are equal. - */ - - if (stat (src, &ssb) == -1) { - return -1; - } - - if (stat (target, &tsb) == -1) { - return -1; - } - - /* - * pretend that the link failed because the target file - * did already exist. - */ - - if (compare_stat (&ssb, &tsb) == -1) { - errno = EEXIST; - return -1; - } - - /* - * Unlink the original link. Should we really ignore the return - * value here? XXX - */ - - unlink (src); - - return 0; -} - -int safe_open (const char *path, int flags) -{ - struct stat osb, nsb; - int fd; - - umask (Umask); - if ((fd = open (path, flags, 0666)) < 0) - return fd; - - /* make sure the file is not symlink */ - if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 || - compare_stat (&osb, &nsb) == -1) { - debug_print (1, ("%s is a symlink!\n", path)); - close (fd); - return (-1); - } - - return (fd); -} - -/* when opening files for writing, make sure the file doesn't already exist - * to avoid race conditions. - */ -FILE *safe_fopen (const char *path, const char *mode) -{ - /* first set the current umask */ - umask (Umask); - if (mode[0] == 'w') { - int fd; - int flags = O_CREAT | O_EXCL; - -#ifdef O_NOFOLLOW - flags |= O_NOFOLLOW; -#endif - - if (mode[1] == '+') - flags |= O_RDWR; - else - flags |= O_WRONLY; - - if ((fd = safe_open (path, flags)) < 0) - return (NULL); - - return (fdopen (fd, mode)); - } - else - return (fopen (path, mode)); -} - -static char safe_chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"; - -void mutt_sanitize_filename (char *f, short slash) -{ - if (!f) - return; - - for (; *f; f++) { - if ((slash && *f == '/') || !strchr (safe_chars, *f)) - *f = '_'; - } -} /* these characters must be escaped in regular expressions */ @@ -387,115 +131,6 @@ int mutt_rx_sanitize_string (char *dest, size_t destlen, const char *src) return 0; } -/* Read a line from ``fp'' into the dynamically allocated ``s'', - * increasing ``s'' if necessary. The ending "\n" or "\r\n" is removed. - * If a line ends with "\", this char and the linefeed is removed, - * and the next line is read too. - */ -char *mutt_read_line(char *s, size_t * size, FILE * fp, int *line) -{ - size_t offset = 0; - char *ch; - - if (!s) { - s = p_new(char, STRING); - *size = STRING; - } - - for (;;) { - if (fgets (s + offset, *size - offset, fp) == NULL) { - p_delete(&s); - return NULL; - } - if ((ch = strchr (s + offset, '\n')) != NULL) { - (*line)++; - *ch = 0; - if (ch > s && *(ch - 1) == '\r') - *--ch = 0; - if (ch == s || *(ch - 1) != '\\') - return s; - offset = ch - s - 1; - } - else { - int c; - - c = getc (fp); /* This is kind of a hack. We want to know if the - char at the current point in the input stream is EOF. - feof() will only tell us if we've already hit EOF, not - if the next character is EOF. So, we need to read in - the next character and manually check if it is EOF. */ - if (c == EOF) { - /* The last line of fp isn't \n terminated */ - (*line)++; - return s; - } - else { - ungetc (c, fp); /* undo our dammage */ - /* There wasn't room for the line -- increase ``s'' */ - offset = *size - 1; /* overwrite the terminating 0 */ - *size += STRING; - p_realloc(&s, *size); - } - } - } -} - -/* prepare a file name to survive the shell's quoting rules. - * From the Unix programming FAQ by way of Liviu. - */ - -size_t mutt_quote_filename (char *d, size_t l, const char *f) -{ - size_t i, j = 0; - - if (!f) { - *d = '\0'; - return 0; - } - - /* leave some space for the trailing characters. */ - l -= 6; - - d[j++] = '\''; - - for (i = 0; j < l && f[i]; i++) { - if (f[i] == '\'' || f[i] == '`') { - d[j++] = '\''; - d[j++] = '\\'; - d[j++] = f[i]; - d[j++] = '\''; - } - else - d[j++] = f[i]; - } - - d[j++] = '\''; - d[j] = '\0'; - - return j; -} - -char *mutt_concat_path (char *d, const char *dir, const char *fname, size_t l) -{ - const char *fmt = "%s/%s"; - - if (!*fname || (*dir && dir[m_strlen(dir) - 1] == '/')) - fmt = "%s%s"; - - snprintf (d, l, fmt, dir, fname); - return d; -} - -const char *mutt_basename (const char *f) -{ - const char *p = strrchr (f, '/'); - - if (p) - return p + 1; - else - return f; -} - const char * mutt_strsysexit(int e) { diff --git a/lib.h b/lib.h index 3ff4a38..457ab92 100644 --- a/lib.h +++ b/lib.h @@ -29,14 +29,6 @@ # include # endif -# define TRUE 1 -# define FALSE 0 - -# undef MAX -# undef MIN -# define MAX(a,b) ((a) < (b) ? (b) : (a)) -# define MIN(a,b) ((a) < (b) ? (a) : (b)) - void mutt_exit (int); /* Exit values used in send_msg() */ @@ -45,27 +37,9 @@ void mutt_exit (int); /* The actual library functions. */ -FILE *safe_fopen (const char *, const char *); - -char *mutt_concat_path (char *, const char *, const char *, size_t); -char *mutt_read_line (char *, size_t *, FILE *, int *); - -const char *mutt_basename (const char *); - -int mutt_copy_stream (FILE *, FILE *); -int mutt_copy_bytes (FILE *, FILE *, size_t); int mutt_rx_sanitize_string (char *, size_t, const char *); -int safe_open (const char *, int); -int safe_symlink (const char *, const char *); -int safe_rename (const char *, const char *); -int safe_fclose (FILE **); - -size_t mutt_quote_filename (char *, size_t, const char *); - void mutt_nocurses_error (const char *, ...); -void mutt_sanitize_filename (char *, short); -void mutt_unlink (const char *); const char *mutt_strsysexit(int e); diff --git a/lib/debug.c b/lib/debug.c index beefe12..523d7c6 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -17,6 +17,7 @@ #include #include +#include #include "debug.h" #include "mutt.h" diff --git a/main.c b/main.c index 66c5f7a..3435941 100644 --- a/main.c +++ b/main.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "mutt.h" #include "mutt_curses.h" diff --git a/mbox.c b/mbox.c index d7d37e8..cab71ac 100644 --- a/mbox.c +++ b/mbox.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "mutt.h" #include "mx.h" diff --git a/mh.c b/mh.c index 5a84bec..bba47ae 100644 --- a/mh.c +++ b/mh.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "mutt.h" #include "mx.h" diff --git a/mutt_sasl.h b/mutt_sasl.h index ca69bb8..763c8d9 100644 --- a/mutt_sasl.h +++ b/mutt_sasl.h @@ -28,7 +28,7 @@ typedef struct { const unsigned int *pbufsize; /* read buffer */ - const char *buf; + char *buf; unsigned int blen; unsigned int bpos; diff --git a/mutt_ssl_gnutls.c b/mutt_ssl_gnutls.c index 1efbbbe..2b44e26 100644 --- a/mutt_ssl_gnutls.c +++ b/mutt_ssl_gnutls.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "mutt.h" #include "mutt_socket.h" diff --git a/muttlib.c b/muttlib.c index 7dc21d6..a168093 100644 --- a/muttlib.c +++ b/muttlib.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" @@ -852,10 +853,10 @@ int mutt_check_overwrite (const char *attname, const char *path, if (mutt_get_field (_("File under directory: "), tmp, sizeof (tmp), M_FILE | M_CLEAR) != 0 || !tmp[0]) return (-1); - mutt_concat_path (fname, path, tmp, flen); + mutt_concat_path(fname, flen, path, tmp); } else - mutt_concat_path (fname, path, mutt_basename (attname), flen); + mutt_concat_path(fname, flen, path, mutt_basename(attname)); } if (*append == 0 && access (fname, F_OK) == 0) { diff --git a/mx.c b/mx.c index b25d841..370bb9f 100644 --- a/mx.c +++ b/mx.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "mutt.h" #include "buffy.h" diff --git a/nntp/newsrc.c b/nntp/newsrc.c index 22b6cf3..1f9bd5b 100644 --- a/nntp/newsrc.c +++ b/nntp/newsrc.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "mutt.h" @@ -629,7 +630,7 @@ void newsrc_gen_entries (CONTEXT * ctx) } static int mutt_update_list_file (char *filename, char *section, - char *key, char *line) { + const char *key, char *line) { FILE *ifp; FILE *ofp; char buf[HUGE_STRING]; @@ -764,7 +765,7 @@ int mutt_newsrc_update (NNTP_SERVER * news) } /* newrc being fully rewritten */ if (news->newsrc && - (r = mutt_update_list_file (news->newsrc, NULL, "", buf)) == 0) { + (r = mutt_update_list_file(news->newsrc, NULL, "", buf)) == 0) { struct stat st; stat (news->newsrc, &st); @@ -796,8 +797,9 @@ static FILE *mutt_mkname (char *s) /* Updates info into .index file: ALL or about selected newsgroup */ static int nntp_update_cacheindex (NNTP_SERVER * serv, NNTP_DATA * data) { - char buf[LONG_STRING], *key = "ALL"; + char buf[LONG_STRING]; char file[_POSIX_PATH_MAX]; + const char *key = "ALL"; if (!serv || !serv->conn || !serv->conn->account.host) return -1; diff --git a/nntp/nntp.c b/nntp/nntp.c index 46a53eb..3a1e626 100644 --- a/nntp/nntp.c +++ b/nntp/nntp.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "mutt.h" diff --git a/pattern.c b/pattern.c index bb818f0..03b3940 100644 --- a/pattern.c +++ b/pattern.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "mutt.h" diff --git a/pgp.c b/pgp.c index d40d8cb..13104bc 100644 --- a/pgp.c +++ b/pgp.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" diff --git a/pgpinvoke.c b/pgpinvoke.c index ada68ed..2fb8917 100644 --- a/pgpinvoke.c +++ b/pgpinvoke.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "mutt.h" #include "mutt_curses.h" diff --git a/pgpkey.c b/pgpkey.c index 05ca27a..d995bc8 100644 --- a/pgpkey.c +++ b/pgpkey.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" diff --git a/pgpmicalg.c b/pgpmicalg.c index 1b6ecc9..e63c943 100644 --- a/pgpmicalg.c +++ b/pgpmicalg.c @@ -27,6 +27,7 @@ #include #include +#include #include "lib/debug.h" static struct { diff --git a/pop/pop.c b/pop/pop.c index 2abedd7..365b772 100644 --- a/pop/pop.c +++ b/pop/pop.c @@ -12,6 +12,7 @@ #endif #include +#include #include #include diff --git a/postpone.c b/postpone.c index d63c146..f0ef950 100644 --- a/postpone.c +++ b/postpone.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" diff --git a/query.c b/query.c index 1e1937d..76eca91 100644 --- a/query.c +++ b/query.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "mutt.h" #include "mutt_menu.h" diff --git a/recvattach.c b/recvattach.c index d1c7117..885c528 100644 --- a/recvattach.c +++ b/recvattach.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" @@ -408,8 +409,8 @@ static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr, if (body->filename) { if (directory && *directory) - mutt_concat_path (buf, *directory, mutt_basename (body->filename), - sizeof (buf)); + mutt_concat_path(buf, sizeof(buf), *directory, + mutt_basename(body->filename)); else strfcpy (buf, body->filename, sizeof (buf)); } diff --git a/recvcmd.c b/recvcmd.c index 68ad462..17ced5a 100644 --- a/recvcmd.c +++ b/recvcmd.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" diff --git a/remailer.c b/remailer.c index f4cf7ce..428e1ba 100644 --- a/remailer.c +++ b/remailer.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "mutt.h" #include "recvattach.h" diff --git a/rfc1524.c b/rfc1524.c index 35a2a95..882f583 100644 --- a/rfc1524.c +++ b/rfc1524.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "mutt.h" #include "rfc1524.h" diff --git a/rfc3676.c b/rfc3676.c index a7144c2..de9e0b6 100644 --- a/rfc3676.c +++ b/rfc3676.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "mutt.h" #include "mutt_curses.h" diff --git a/send.c b/send.c index d2c2c2a..bc84b6b 100644 --- a/send.c +++ b/send.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" diff --git a/sendlib.c b/sendlib.c index 7674a32..a07b87d 100644 --- a/sendlib.c +++ b/sendlib.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "mutt.h" #include "handler.h" diff --git a/smime.c b/smime.c index eb68c18..0498122 100644 --- a/smime.c +++ b/smime.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "mutt.h" #include "enter.h" -- 2.20.1