* please see the file GPL in the top level source directory.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
+#include "lib-lib.h"
-#include "macros.h"
-#include "mem.h"
-#include "str.h"
-#include "file.h"
-
-#include "../lib/debug.h"
-#include "../lib/str.h"
+#include <utime.h>
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0
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 -1;
len = m_strcat(abs_oldpath, sizeof(abs_oldpath), "/");
- if (len >= sizeof(abs_oldpath))
+ if (len >= ssizeof(abs_oldpath))
return -1;
len += m_strcpy(abs_oldpath + len, sizeof(abs_oldpath) - len, oldpath);
- if (len >= sizeof(abs_oldpath))
+ if (len >= ssizeof(abs_oldpath))
return -1;
if (symlink (abs_oldpath, newpath) < 0)
char buf[BUFSIZ];
unlink(s);
- p_clear(buf, sizeof(buf));
+ p_clear(buf, countof(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);
+ fwrite(buf, 1, MIN(ssizeof(buf), sb.st_size), f);
+ sb.st_size -= MIN(ssizeof(buf), sb.st_size);
}
- fclose (f);
+ m_fclose(&f);
}
}
}
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'',
* 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)
+char *mutt_read_line(char *s, ssize_t *size, FILE * fp, int *line)
{
- size_t offset = 0;
+ ssize_t offset = 0;
char *ch;
if (!s) {
int mutt_copy_stream(FILE *fin, FILE *fout)
{
char buf[BUFSIZ];
- ssize_t l;
+ size_t l;
- while ((l = fread(buf, 1, sizeof (buf), fin)) > 0) {
+ 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)
+int mutt_copy_bytes(FILE *in, FILE *out, ssize_t size)
{
char buf[BUFSIZ];
while (size > 0) {
- ssize_t chunk = MIN(size, sizeof(buf));
+ size_t chunk = MIN(size, ssizeof(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;
/****************************************************************************/
-/* ligben-like funcs */
+/* path manipulations */
/****************************************************************************/
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)
{
- const char *fmt = "%s/%s";
+ int pos;
+
+ pos = m_strcpy(d, n, dir);
+ if (pos >= n - 1)
+ return d;
- if (!*fname || (*dir && dir[m_strlen(dir) - 1] == '/'))
- fmt = "%s%s";
+ if (pos && d[pos - 1] != '/')
+ d[pos++] = '/';
- snprintf(d, n, fmt, dir, fname);
+ m_strcpy(d + pos, n - pos, fname);
return d;
}
/* FIXME: API is very wrong */
ssize_t mutt_quote_filename(char *d, ssize_t l, const char *s)
{
- size_t i, j = 0;
+ ssize_t i, j = 0;
if (!s) {
*d = '\0';
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;
+}
+