71const char FilenameSafeChars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
73#define MAX_LOCK_ATTEMPTS 5
89static bool stat_equal(
struct stat *st_old,
struct stat *st_new)
91 return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
92 (st_old->st_rdev == st_new->st_rdev);
105 const char *basename = NULL;
124 if (!mkdtemp(newdir->
data))
170 int fd = fileno(*fp);
171 int rc = fclose(*fp);
180 fd, errno, strerror(errno));
200 if (fflush(*fp) || fsync(fileno(*fp)))
202 int save_errno = errno;
226 struct stat st = { 0 };
229 const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
230 if (!is_regular_file)
237 struct stat st2 = { 0 };
238 if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
239 (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
259 if (!fp_in || !fp_out)
264 char buf[2048] = { 0 };
265 size_t chunk = (size >
sizeof(buf)) ?
sizeof(buf) : size;
266 chunk = fread(buf, 1, chunk, fp_in);
269 if (fwrite(buf, 1, chunk, fp_out) != chunk)
275 if (fflush(fp_out) != 0)
289 if (!fp_in || !fp_out)
294 char buf[1024] = { 0 };
296 while ((l = fread(buf, 1,
sizeof(buf), fp_in)) > 0)
298 if (fwrite(buf, 1, l, fp_out) != l)
303 if (fflush(fp_out) != 0)
317 struct stat st_old = { 0 };
318 struct stat st_new = { 0 };
320 if (!oldpath || !newpath)
323 if ((unlink(newpath) == -1) && (errno != ENOENT))
326 if (oldpath[0] ==
'/')
328 if (symlink(oldpath, newpath) == -1)
343 if (symlink(
buf_string(abs_oldpath), newpath) == -1)
352 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
373 struct stat st_src = { 0 };
374 struct stat st_target = { 0 };
380 if (link(src, target) != 0)
393 if ((lstat(src, &st_src) == 0) && (lstat(target, &st_target) == 0) &&
397 src, target, strerror(errno), errno);
412 strerror(errno), errno);
416 if ((errno == EXDEV) || (errno == ENOSYS) || errno == EPERM
421 || errno == EOPNOTSUPP
426 if (rename(src, target) == -1)
429 strerror(errno), errno);
447 if (lstat(src, &st_src) == -1)
453 if (lstat(target, &st_target) == -1)
463 mutt_debug(
LL_DEBUG1,
"stat blocks for %s and %s diverge; pretending EEXIST\n", src, target);
472 if (unlink(src) == -1)
491 struct dirent *de = NULL;
492 struct stat st = { 0 };
506 while ((de = readdir(dir)))
520 if (S_ISDIR(st.st_mode))
555 for (count -= 2; count >= 0; count--)
558 buf_printf(new_file,
"%s%d", path, count + 1);
591 if (
mkwrapdir(path, safe_file, safe_dir) == -1)
597 fd = open(
buf_string(safe_file), flags, mode);
613 fd = open(path, flags & ~O_EXCL, 0600);
618 struct stat st_old = { 0 };
619 struct stat st_new = { 0 };
620 if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
649 return opendir(path);
667 const char *file,
int line,
const char *func)
675 uint32_t flags = O_CREAT | O_EXCL |
O_NOFOLLOW;
685 fp = fdopen(fd, mode);
690 fp = fopen(path, mode);
701 errno, strerror(errno), path);
717 size_t size = strlen(path);
720 mbstate_t mbstate = { 0 };
721 for (
size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
722 size -= consumed, path += consumed)
727 mbstate = (mbstate_t) { 0 };
729 memset(path,
'_', consumed);
734 memset(path,
'_', consumed);
740 memset(path,
'_', consumed);
785 if (fseeko(fp, offset, whence) != 0)
787 mutt_perror(
_(
"Failed to seek file: %s"), strerror(errno));
824 if (!fgets(line + offset, *size - offset, fp))
829 ch = strchr(line + offset,
'\n');
837 if ((ch > line) && (*(ch - 1) ==
'\r'))
839 if (!(flags &
MUTT_RL_CONT) || (ch == line) || (*(ch - 1) !=
'\\'))
841 offset = ch - line - 1;
935 if (!buf || !filename)
942 for (; *filename !=
'\0'; filename++)
944 if ((*filename ==
'\'') || (*filename ==
'`'))
976 if (!path || (*path ==
'\0'))
984 const size_t len = strlen(path);
986 if (len >=
sizeof(tmp_path))
988 errno = ENAMETOOLONG;
992 struct stat st = { 0 };
993 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
999 for (
char *p = tmp_path + 1; *p; p++)
1007 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
1013 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
1033 struct utimbuf utim = { 0 };
1034 struct stat st2 = { 0 };
1039 if (stat(fp, &st2) == -1)
1044 mtime = st->st_mtime;
1048 utim.actime = mtime;
1049 utim.modtime = mtime;
1053 rc = utime(fp, &utim);
1054 }
while ((rc == -1) && (errno == EINTR));
1073 struct utimbuf utim = { 0 };
1074 struct stat st = { 0 };
1076 if (stat(from, &st) != -1)
1078 utim.actime = st.st_mtime;
1079 utim.modtime = st.st_mtime;
1094 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1095 futimens(fd, times);
1144 struct stat st2 = { 0 };
1148 if (stat(path, &st2) == -1)
1152 return chmod(path, st->st_mode | mode);
1178 struct stat st2 = { 0 };
1182 if (stat(path, &st2) == -1)
1186 return chmod(path, st->st_mode & ~mode);
1189#if defined(USE_FCNTL)
1204 struct stat st = { 0 }, prev_sb = { 0 };
1208 struct flock lck = { 0 };
1209 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1210 lck.l_whence = SEEK_SET;
1212 while (fcntl(fd, F_SETLK, &lck) == -1)
1215 if ((errno != EAGAIN) && (errno != EACCES))
1221 if (fstat(fd, &st) != 0)
1228 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1231 mutt_error(
_(
"Timeout exceeded while attempting fcntl lock"));
1251 struct flock unlockit = { 0 };
1252 unlockit.l_type = F_UNLCK;
1253 unlockit.l_whence = SEEK_SET;
1254 (void) fcntl(fd, F_SETLK, &unlockit);
1258#elif defined(USE_FLOCK)
1273 struct stat st = { 0 }, prev_sb = { 0 };
1278 while (flock(fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1)
1280 if (errno != EWOULDBLOCK)
1287 if (fstat(fd, &st) != 0)
1294 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1297 mutt_error(
_(
"Timeout exceeded while attempting flock lock"));
1304 mutt_message(
_(
"Waiting for flock attempt... %d"), ++attempt);
1328#error "You must select a locking mechanism via USE_FCNTL or USE_FLOCK"
1340 struct stat st = { 0 };
1342 int fd = open(path, O_RDWR);
1352 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1373 if (!oldfile || !newfile)
1375 if (access(oldfile, F_OK) != 0)
1377 if (access(newfile, F_OK) == 0)
1412 buf = fgets(buf, buflen, fp);
1421 while ((*buf !=
'\0') && !isspace(*buf))
1441 struct stat st = { 0 };
1442 if (stat(path, &st) == -1)
1445 return st.st_size == 0;
1473 if (!dest || !fmt || !src)
1476 const char *p = NULL;
1481 for (p = fmt; *p; p++)
1524 struct stat st = { 0 };
1525 if (stat(path, &st) != 0)
1542 struct stat st = { 0 };
1543 if (fstat(fileno(fp), &st) != 0)
1561 if (a->tv_sec < b->tv_sec)
1563 if (a->tv_sec > b->tv_sec)
1566 if (a->tv_nsec < b->tv_nsec)
1568 if (a->tv_nsec > b->tv_nsec)
1590 dest->tv_sec = st->st_atime;
1591#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1592 dest->tv_nsec = st->st_atim.tv_nsec;
1596 dest->tv_sec = st->st_mtime;
1597#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1598 dest->tv_nsec = st->st_mtim.tv_nsec;
1602 dest->tv_sec = st->st_ctime;
1603#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1604 dest->tv_nsec = st->st_ctim.tv_nsec;
1625 struct timespec a = { 0 };
1647 struct timespec a = { 0 };
1648 struct timespec b = { 0 };
1661 struct stat st = { 0 };
1663 if ((rc != -1) && S_ISLNK(st.st_mode))
1688 return fwrite(str, 1, len, fp);
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
General purpose object for storing and parsing strings.
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Time and date handling routines.
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *st, enum MuttStatType type)
Read the stat() time into a time value.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
FILE * mutt_file_fopen_full(const char *path, const char *mode, const mode_t perms, const char *file, int line, const char *func)
Call fopen() safely.
void buf_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
const char FilenameSafeChars[]
Set of characters <=0x7F that are safe to use in filenames.
int mutt_file_stat_compare(struct stat *st1, enum MuttStatType st1_type, struct stat *st2, enum MuttStatType st2_type)
Compare two stat infos.
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
#define MAX_LOCK_ATTEMPTS
void buf_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
void mutt_file_touch_atime(int fd)
Set the access time to current time.
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
int mutt_file_check_empty(const char *path)
Is the mailbox empty.
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
bool mutt_file_map_lines(mutt_file_map_t func, void *user_data, FILE *fp, ReadLineFlags flags)
Process lines of text read from a file pointer.
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
int mutt_file_fclose_full(FILE **fp, const char *file, int line, const char *func)
Close a FILE handle (and NULL the pointer)
static bool stat_equal(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
long mutt_file_get_size(const char *path)
Get the size of a file.
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
bool mutt_file_iter_line(struct MuttFileIter *iter, FILE *fp, ReadLineFlags flags)
Iterate over the lines from an open file pointer.
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
int mutt_file_chmod_add_stat(const char *path, mode_t mode, struct stat *st)
Add permissions to a file.
static int put_file_in_place(const char *path, const char *safe_file, const char *safe_dir)
Move a file into place.
void mutt_file_expand_fmt(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
void mutt_file_resolve_symlink(struct Buffer *buf)
Resolve a symlink in place.
static const char RxSpecialChars[]
These characters must be escaped in regular expressions.
void mutt_file_set_mtime(const char *from, const char *to)
Set the modification time of one file from another.
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
int mutt_file_stat_timespec_compare(struct stat *st, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
const char * mutt_file_rotate(const char *path, int count)
Rotate a set of numbered files.
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
int mutt_file_open(const char *path, uint32_t flags, mode_t mode)
Open a file.
void mutt_file_unlink(const char *s)
Delete a file, carefully.
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
size_t mutt_file_save_str(FILE *fp, const char *str)
Save a string to a file.
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
File management functions.
MuttOpenDirMode
Mode flag for mutt_file_opendir()
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
@ MUTT_OPENDIR_NONE
Plain opendir()
#define MUTT_RL_CONT
-continuation
#define mutt_file_fclose(FP)
#define mutt_file_fopen(PATH, MODE)
bool(* mutt_file_map_t)(char *line, int line_num, void *user_data)
#define MUTT_RL_EOL
don't strip \n / \r\n
MuttStatType
Flags for mutt_file_get_stat_timespec.
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
uint8_t ReadLineFlags
Flags for mutt_file_read_line(), e.g. MUTT_RL_CONT.
#define mutt_message(...)
#define mutt_debug(LEVEL,...)
int(*) log_dispatcher_ MuttLogger)
@ LL_DEBUG2
Log at debug level 2.
@ LL_DEBUG1
Log at debug level 1.
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Memory management wrappers.
Conversion between different character encodings.
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Path manipulation functions.
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
A global pool of Buffers.
String manipulation functions.
String manipulation buffer.
char * data
Pointer to data.
State record for mutt_file_iter_line()
size_t size
allocated size of line data