70const char FilenameSafeChars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
72#define MAX_LOCK_ATTEMPTS 5
88static bool stat_equal(
struct stat *st_old,
struct stat *st_new)
90 return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
91 (st_old->st_rdev == st_new->st_rdev);
108 int fd = fileno(*fp);
109 int rc = fclose(*fp);
118 fd, errno, strerror(errno));
138 if (fflush(*fp) || fsync(fileno(*fp)))
140 int save_errno = errno;
164 struct stat st = { 0 };
167 const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
168 if (!is_regular_file)
175 struct stat st2 = { 0 };
176 if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
177 (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
197 if (!fp_in || !fp_out)
202 char buf[2048] = { 0 };
203 size_t chunk = (size >
sizeof(buf)) ?
sizeof(buf) : size;
204 chunk = fread(buf, 1, chunk, fp_in);
207 if (fwrite(buf, 1, chunk, fp_out) != chunk)
213 if (fflush(fp_out) != 0)
227 if (!fp_in || !fp_out)
232 char buf[1024] = { 0 };
234 while ((l = fread(buf, 1,
sizeof(buf), fp_in)) > 0)
236 if (fwrite(buf, 1, l, fp_out) != l)
241 if (fflush(fp_out) != 0)
255 struct stat st_old = { 0 };
256 struct stat st_new = { 0 };
258 if (!oldpath || !newpath)
261 if ((unlink(newpath) == -1) && (errno != ENOENT))
264 if (oldpath[0] ==
'/')
266 if (symlink(oldpath, newpath) == -1)
281 if (symlink(
buf_string(abs_oldpath), newpath) == -1)
290 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
311 struct stat st_src = { 0 };
312 struct stat st_target = { 0 };
318 if (link(src, target) != 0)
331 if ((lstat(src, &st_src) == 0) && (lstat(target, &st_target) == 0) &&
335 src, target, strerror(errno), errno);
350 strerror(errno), errno);
354 if ((errno == EXDEV) || (errno == ENOSYS) || errno == EPERM
359 || errno == EOPNOTSUPP
364 if (rename(src, target) == -1)
367 strerror(errno), errno);
385 if (lstat(src, &st_src) == -1)
391 if (lstat(target, &st_target) == -1)
401 mutt_debug(
LL_DEBUG1,
"stat blocks for %s and %s diverge; pretending EEXIST\n", src, target);
410 if (unlink(src) == -1)
429 struct dirent *de = NULL;
430 struct stat st = { 0 };
444 while ((de = readdir(dir)))
458 if (S_ISDIR(st.st_mode))
493 for (count -= 2; count >= 0; count--)
496 buf_printf(new_file,
"%s%d", path, count + 1);
520 int fd = open(path, flags & ~O_EXCL, 0600);
525 struct stat st = { 0 };
526 if ((lstat(path, &st) < 0) || S_ISLNK(st.st_mode))
549 return opendir(path);
564 const char *file,
int line,
const char *func)
569 FILE *fp = fopen(path, mode);
578 errno, strerror(errno), path);
594 size_t size = strlen(path);
597 mbstate_t mbstate = { 0 };
598 for (
size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
599 size -= consumed, path += consumed)
604 mbstate = (mbstate_t) { 0 };
606 memset(path,
'_', consumed);
611 memset(path,
'_', consumed);
617 memset(path,
'_', consumed);
662 if (fseeko(fp, offset, whence) != 0)
664 mutt_perror(
_(
"Failed to seek file: %s"), strerror(errno));
701 if (!fgets(line + offset, *size - offset, fp))
706 ch = strchr(line + offset,
'\n');
714 if ((ch > line) && (*(ch - 1) ==
'\r'))
716 if (!(flags &
MUTT_RL_CONT) || (ch == line) || (*(ch - 1) !=
'\\'))
718 offset = ch - line - 1;
812 if (!buf || !filename)
819 for (; *filename !=
'\0'; filename++)
821 if ((*filename ==
'\'') || (*filename ==
'`'))
853 if (!path || (*path ==
'\0'))
861 const size_t len = strlen(path);
863 if (len >=
sizeof(tmp_path))
865 errno = ENAMETOOLONG;
869 struct stat st = { 0 };
870 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
876 for (
char *p = tmp_path + 1; *p; p++)
884 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
890 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
910 struct utimbuf utim = { 0 };
911 struct stat st2 = { 0 };
916 if (stat(fp, &st2) == -1)
921 mtime = st->st_mtime;
926 utim.modtime = mtime;
930 rc = utime(fp, &utim);
931 }
while ((rc == -1) && (errno == EINTR));
950 struct utimbuf utim = { 0 };
951 struct stat st = { 0 };
953 if (stat(from, &st) != -1)
955 utim.actime = st.st_mtime;
956 utim.modtime = st.st_mtime;
971 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1037 struct stat st2 = { 0 };
1041 if (stat(path, &st2) == -1)
1045 return chmod(path, st->st_mode | mode);
1071 struct stat st2 = { 0 };
1075 if (stat(path, &st2) == -1)
1079 return chmod(path, st->st_mode & ~mode);
1082#if defined(USE_FCNTL)
1097 struct stat st = { 0 }, prev_sb = { 0 };
1101 struct flock lck = { 0 };
1102 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1103 lck.l_whence = SEEK_SET;
1105 while (fcntl(fd, F_SETLK, &lck) == -1)
1108 if ((errno != EAGAIN) && (errno != EACCES))
1114 if (fstat(fd, &st) != 0)
1121 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1124 mutt_error(
_(
"Timeout exceeded while attempting fcntl lock"));
1144 struct flock unlockit = { 0 };
1145 unlockit.l_type = F_UNLCK;
1146 unlockit.l_whence = SEEK_SET;
1147 (void) fcntl(fd, F_SETLK, &unlockit);
1151#elif defined(USE_FLOCK)
1166 struct stat st = { 0 }, prev_sb = { 0 };
1171 while (flock(fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1)
1173 if (errno != EWOULDBLOCK)
1180 if (fstat(fd, &st) != 0)
1187 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1190 mutt_error(
_(
"Timeout exceeded while attempting flock lock"));
1197 mutt_message(
_(
"Waiting for flock attempt... %d"), ++attempt);
1221#error "You must select a locking mechanism via USE_FCNTL or USE_FLOCK"
1233 struct stat st = { 0 };
1235 int fd = open(path, O_RDWR);
1245 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1266 if (!oldfile || !newfile)
1268 if (access(oldfile, F_OK) != 0)
1270 if (access(newfile, F_OK) == 0)
1305 buf = fgets(buf, buflen, fp);
1314 while ((*buf !=
'\0') && !isspace(*buf))
1334 struct stat st = { 0 };
1335 if (stat(path, &st) == -1)
1338 return st.st_size == 0;
1366 if (!dest || !fmt || !src)
1369 const char *p = NULL;
1374 for (p = fmt; *p; p++)
1417 struct stat st = { 0 };
1418 if (stat(path, &st) != 0)
1435 struct stat st = { 0 };
1436 if (fstat(fileno(fp), &st) != 0)
1454 if (a->tv_sec < b->tv_sec)
1456 if (a->tv_sec > b->tv_sec)
1459 if (a->tv_nsec < b->tv_nsec)
1461 if (a->tv_nsec > b->tv_nsec)
1483 dest->tv_sec = st->st_atime;
1484#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1485 dest->tv_nsec = st->st_atim.tv_nsec;
1489 dest->tv_sec = st->st_mtime;
1490#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1491 dest->tv_nsec = st->st_mtim.tv_nsec;
1495 dest->tv_sec = st->st_ctime;
1496#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1497 dest->tv_nsec = st->st_ctim.tv_nsec;
1518 struct timespec a = { 0 };
1540 struct timespec a = { 0 };
1541 struct timespec b = { 0 };
1554 struct stat st = { 0 };
1556 if ((rc != -1) && S_ISLNK(st.st_mode))
1581 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.
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.
bool mutt_file_touch(const char *path)
Make sure a file exists.
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.
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.
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.
Memory management wrappers.
#define MUTT_MEM_REALLOC(pptr, n, type)
#define MUTT_MEM_MALLOC(n, type)
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.
State record for mutt_file_iter_line()
size_t size
allocated size of line data