X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-lib%2Ffile.c;h=ed74aada186c8e75f576645b2e984707b3902df2;hp=985015f0da26fb904e350b4f4fef0017d8481d8b;hb=6d838d9aef36d95fa439b3f7cc06d4e81c8581bd;hpb=ac813896ca32d850febc2d95065ac4fa040f11f9 diff --git a/lib-lib/file.c b/lib-lib/file.c index 985015f..ed74aad 100644 --- a/lib-lib/file.c +++ b/lib-lib/file.c @@ -26,18 +26,9 @@ * 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 "debug.h" +#include "lib-lib.h" + +#include #ifndef O_NOFOLLOW # define O_NOFOLLOW 0 @@ -75,12 +66,11 @@ int safe_open(const char *path, int flags) 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); + return fd; } @@ -212,7 +202,7 @@ void mutt_unlink(const char *s) fwrite(buf, 1, MIN(ssizeof(buf), sb.st_size), f); sb.st_size -= MIN(ssizeof(buf), sb.st_size); } - fclose (f); + m_fclose(&f); } } } @@ -236,7 +226,7 @@ FILE *safe_fopen(const char *path, const char *mode) flags |= (mode[1] == '+' ? O_RDWR : O_WRONLY); if ((fd = safe_open(path, flags)) < 0) - return (NULL); + return NULL; return fdopen (fd, mode); } @@ -244,14 +234,41 @@ FILE *safe_fopen(const char *path, const char *mode) return fopen(path, mode); } -int safe_fclose(FILE **f) +/* If rfc1524_expand_command() is used on a recv'd message, then + * the filename doesn't exist yet, but if its used while sending a message, + * then we need to rename the existing file. + * + * This function returns 0 on successful move, 1 on old file doesn't exist, + * 2 on new file already exists, and 3 on other failure. + */ + +/* note on access(2) use: No dangling symlink problems here due to + * safe_fopen(). + */ +int mutt_rename_file(char *oldfile, char *newfile) { - int r = 0; + FILE *ofp, *nfp; + + if (access(oldfile, F_OK) != 0) + return 1; + if (access(newfile, F_OK) == 0) + return 2; + + ofp = fopen(oldfile, "r"); + if (!ofp) + return 3; + + nfp = safe_fopen(newfile, "w"); + if (!nfp) { + m_fclose(&ofp); + return 3; + } - if (*f) - r = fclose (*f); - *f = NULL; - return r; + mutt_copy_stream(ofp, nfp); + m_fclose(&nfp); + m_fclose(&ofp); + mutt_unlink(oldfile); + return 0; } /* Read a line from ``fp'' into the dynamically allocated ``s'', @@ -328,7 +345,6 @@ int mutt_copy_bytes(FILE *in, FILE *out, ssize_t 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; @@ -339,7 +355,7 @@ int mutt_copy_bytes(FILE *in, FILE *out, ssize_t size) /****************************************************************************/ -/* ligben-like funcs */ +/* path manipulations */ /****************************************************************************/ const char *mutt_basename(const char *f) @@ -348,6 +364,26 @@ const char *mutt_basename(const char *f) return p ? p + 1 : f; } +ssize_t m_dirname(char *dst, ssize_t dlen, const char *path) +{ + ssize_t plen = m_strlen(path); + + while (plen > 0 && path[plen - 1] == '/') + plen--; + + while (plen > 0 && path[plen - 1] != '/') + plen--; + + while (plen > 0 && path[plen - 1] == '/') + plen--; + + if (plen) + return m_strncpy(dst, dlen, path, plen); + + if (*path == '/') + return m_strcpy(dst, dlen, "/"); + return m_strcpy(dst, dlen, "."); +} char * mutt_concat_path(char *d, ssize_t n, const char *dir, const char *fname) @@ -415,3 +451,123 @@ ssize_t mutt_quote_filename(char *d, ssize_t l, const char *s) return j; } + +ssize_t m_file_fmt(char *dst, ssize_t n, const char *fmt, const char *src) +{ + ssize_t pos = 0; + const char *p; + int hadfname = 0; + + for (p = strchr(fmt, '%'); p; p = strchr(fmt, '%')) { + if (p[1] == 's') { + pos += m_strncpy(dst + pos, n - pos, fmt, p - fmt); + pos += m_strcpy(dst + pos, n - pos, src); + fmt = p + 2; + hadfname = 1; + } else { + pos += m_strncpy(dst + pos, n - pos, fmt, p + 1 - fmt); + fmt = p + 1 + (p[1] == '%'); + } + } + pos += m_strcpy(dst + pos, n - pos, fmt); + + if (!hadfname) + pos += snprintf(dst + pos, n - pos, " %s", src); + + return pos; +} + +ssize_t +m_quotefile_fmt(char *dst, ssize_t n, const char *fmt, const char *src) +{ + char tmp[LONG_STRING]; + mutt_quote_filename(tmp, sizeof(tmp), src); + return m_file_fmt(dst, n, fmt, tmp); +} + +static ssize_t +m_tempftplize(char *dst, ssize_t dlen, const char *fmt, const char *s) +{ + const char *p; + + while ((p = strchr(fmt, '/'))) { + fmt = p + 1; + } + + if (!*fmt) + return m_strcpy(dst, dlen, s); + + for (p = strchr(fmt, '%'); p; p = strchr(p, '%')) { + if (p[1] == 's') + return m_file_fmt(dst, dlen, fmt, s); + + p += 1 + (p[1] == '%'); + } + + p = strrchr(fmt, '.'); + if (p) { + return snprintf(dst, dlen, "%s%s", s, p); + } else { + return snprintf(dst, dlen, "%s.%s", s, fmt); + } +} + +int m_tempfd(char *dst, ssize_t n, const char *dir, const char *fmt) +{ + char raw[_POSIX_PATH_MAX], tpl[_POSIX_PATH_MAX]; + const char *path = fmt ? tpl : raw; + int fd; + + rand_again: + snprintf(raw, sizeof(raw), "%s/madmutt-%04x-%04x-%08x", + dir, (int)getuid(), (int)getpid(), (int)rand()); + + if (fmt) { + m_tempftplize(tpl, sizeof(tpl), fmt, raw); + } + + fd = open(path, O_CREAT | O_EXCL | O_RDWR | O_NOFOLLOW, 0600); + + if (fd < 0) { + if (errno == EEXIST) + goto rand_again; + return -1; + } + + m_strcpy(dst, n, path); + return fd; +} + +FILE *m_tempfile(char *dst, ssize_t n, const char *dir, const char *fmt) +{ + int fd = m_tempfd(dst, n, dir, fmt); + return fd < 0 ? NULL : fdopen(fd, "w+"); +} + +/****************************************************************************/ +/* misc */ +/****************************************************************************/ + +/* Decrease a file's modification time by 1 second */ +time_t m_decrease_mtime(const char *path, struct stat *st) +{ + struct utimbuf utim; + struct stat _st; + time_t mtime; + + if (!st) { + if (stat(path, &_st) == -1) + return -1; + st = &_st; + } + + if ((mtime = st->st_mtime) == time(NULL)) { + mtime -= 1; + utim.actime = mtime; + utim.modtime = mtime; + utime(path, &utim); + } + + return mtime; +} +