59const char FilenameSafeChars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
61#define MAX_LOCK_ATTEMPTS 5
79 return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
80 (st_old->st_rdev == st_new->st_rdev);
93 const char *basename = NULL;
99 char *p = strrchr(parent.
data,
'/');
112 if (!mkdtemp(newdir->
data))
155 int rc = fclose(*fp);
173 if (fflush(*fp) || fsync(fileno(*fp)))
175 int save_errno = errno;
199 struct stat st = { 0 };
202 const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
203 if (!is_regular_file)
210 struct stat st2 = { 0 };
211 if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
212 (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
232 if (!fp_in || !fp_out)
237 char buf[2048] = { 0 };
238 size_t chunk = (size >
sizeof(buf)) ?
sizeof(buf) : size;
239 chunk = fread(buf, 1, chunk, fp_in);
242 if (fwrite(buf, 1, chunk, fp_out) != chunk)
248 if (fflush(fp_out) != 0)
262 if (!fp_in || !fp_out)
267 char buf[1024] = { 0 };
269 while ((l = fread(buf, 1,
sizeof(buf), fp_in)) > 0)
271 if (fwrite(buf, 1, l, fp_out) != l)
276 if (fflush(fp_out) != 0)
290 struct stat st_old = { 0 };
291 struct stat st_new = { 0 };
293 if (!oldpath || !newpath)
296 if ((unlink(newpath) == -1) && (errno != ENOENT))
299 if (oldpath[0] ==
'/')
301 if (symlink(oldpath, newpath) == -1)
316 if (symlink(
buf_string(&abs_oldpath), newpath) == -1)
325 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
346 struct stat st_src = { 0 };
347 struct stat st_target = { 0 };
353 if (link(src, target) != 0)
366 if ((lstat(src, &st_src) == 0) && (lstat(target, &st_target) == 0) &&
370 src, target, strerror(errno), errno);
385 strerror(errno), errno);
389 if ((errno == EXDEV) || (errno == ENOSYS) || errno == EPERM
394 || errno == EOPNOTSUPP
399 if (rename(src, target) == -1)
402 strerror(errno), errno);
420 if (lstat(src, &st_src) == -1)
426 if (lstat(target, &st_target) == -1)
436 mutt_debug(
LL_DEBUG1,
"stat blocks for %s and %s diverge; pretending EEXIST\n", src, target);
445 if (unlink(src) == -1)
464 struct dirent *de = NULL;
465 struct stat st = { 0 };
479 while ((de = readdir(dir)))
493 if (S_ISDIR(st.st_mode))
528 for (count -= 2; count >= 0; count--)
531 buf_printf(new_file,
"%s%d", path, count + 1);
563 if (
mkwrapdir(path, &safe_file, &safe_dir) == -1)
569 fd = open(
buf_string(&safe_file), flags, 0600);
585 fd = open(path, flags & ~O_EXCL, 0600);
590 struct stat st_old = { 0 };
591 struct stat st_new = { 0 };
592 if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
621 return opendir(path);
641 uint32_t flags = O_CREAT | O_EXCL |
O_NOFOLLOW;
652 return fdopen(fd, mode);
656 return fopen(path, mode);
670 for (; *path; path++)
715 if (fseeko(fp, offset, whence) != 0)
717 mutt_perror(
_(
"Failed to seek file: %s"), strerror(errno));
754 if (!fgets(line + offset, *size - offset, fp))
759 ch = strchr(line + offset,
'\n');
767 if ((ch > line) && (*(ch - 1) ==
'\r'))
769 if (!(flags &
MUTT_RL_CONT) || (ch == line) || (*(ch - 1) !=
'\\'))
771 offset = ch - line - 1;
884 for (
size_t i = 0; (j < buflen) && filename[i]; i++)
886 if ((filename[i] ==
'\'') || (filename[i] ==
'`'))
890 buf[j++] = filename[i];
895 buf[j++] = filename[i];
913 if (!buf || !filename)
920 for (; *filename !=
'\0'; filename++)
922 if ((*filename ==
'\'') || (*filename ==
'`'))
954 if (!path || (*path ==
'\0'))
962 const size_t len = strlen(path);
964 if (len >=
sizeof(tmp_path))
966 errno = ENAMETOOLONG;
970 struct stat st = { 0 };
971 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
977 for (
char *p = tmp_path + 1; *p; p++)
985 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
991 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
1011 struct utimbuf utim;
1012 struct stat st2 = { 0 };
1017 if (stat(fp, &st2) == -1)
1022 mtime = st->st_mtime;
1026 utim.actime = mtime;
1027 utim.modtime = mtime;
1031 rc = utime(fp, &utim);
1032 }
while ((rc == -1) && (errno == EINTR));
1051 struct utimbuf utim;
1052 struct stat st = { 0 };
1054 if (stat(from, &st) != -1)
1056 utim.actime = st.st_mtime;
1057 utim.modtime = st.st_mtime;
1072 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1073 futimens(fd, times);
1090 return chmod(path, mode);
1138 struct stat st2 = { 0 };
1142 if (stat(path, &st2) == -1)
1146 return chmod(path, st->st_mode | mode);
1194 struct stat st2 = { 0 };
1198 if (stat(path, &st2) == -1)
1202 return chmod(path, st->st_mode & ~mode);
1205#if defined(USE_FCNTL)
1220 struct stat st = { 0 }, prev_sb = { 0 };
1225 memset(&lck, 0,
sizeof(
struct flock));
1226 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1227 lck.l_whence = SEEK_SET;
1229 while (fcntl(fd, F_SETLK, &lck) == -1)
1232 if ((errno != EAGAIN) && (errno != EACCES))
1238 if (fstat(fd, &st) != 0)
1245 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1248 mutt_error(
_(
"Timeout exceeded while attempting fcntl lock"));
1268 struct flock unlockit;
1270 memset(&unlockit, 0,
sizeof(
struct flock));
1271 unlockit.l_type = F_UNLCK;
1272 unlockit.l_whence = SEEK_SET;
1273 (void) fcntl(fd, F_SETLK, &unlockit);
1277#elif defined(USE_FLOCK)
1292 struct stat st = { 0 }, prev_sb = { 0 };
1297 while (flock(fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1)
1299 if (errno != EWOULDBLOCK)
1306 if (fstat(fd, &st) != 0)
1313 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1316 mutt_error(
_(
"Timeout exceeded while attempting flock lock"));
1323 mutt_message(
_(
"Waiting for flock attempt... %d"), ++attempt);
1347#error "You must select a locking mechanism via USE_FCNTL or USE_FLOCK"
1359 struct stat st = { 0 };
1361 int fd = open(path, O_RDWR);
1371 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1392 if (!oldfile || !newfile)
1394 if (access(oldfile, F_OK) != 0)
1396 if (access(newfile, F_OK) == 0)
1399 FILE *fp_old = fopen(oldfile,
"r");
1431 buf = fgets(buf, buflen, fp);
1440 while ((*buf !=
'\0') && !isspace(*buf))
1460 struct stat st = { 0 };
1461 if (stat(path, &st) == -1)
1464 return st.st_size == 0;
1492 if (!dest || !fmt || !src)
1495 const char *p = NULL;
1500 for (p = fmt; *p; p++)
1543 struct stat st = { 0 };
1544 if (stat(path, &st) != 0)
1561 struct stat st = { 0 };
1562 if (fstat(fileno(fp), &st) != 0)
1609 dest->
tv_sec = st->st_atime;
1610#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1611 dest->
tv_nsec = st->st_atim.tv_nsec;
1615 dest->
tv_sec = st->st_mtime;
1616#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1617 dest->
tv_nsec = st->st_mtim.tv_nsec;
1621 dest->
tv_sec = st->st_ctime;
1622#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1623 dest->
tv_nsec = st->st_ctim.tv_nsec;
1680 struct stat st = { 0 };
1682 if ((rc != -1) && S_ISLNK(st.st_mode))
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
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.
void buf_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
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 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.
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
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()
int mutt_file_chmod_rm(const char *path, mode_t mode)
Remove permissions from a file.
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.
size_t mutt_file_quote_filename(const char *filename, char *buf, size_t buflen)
Quote a filename to survive the shell's quoting rules.
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.
long mutt_file_get_size(const char *path)
Get the size of a file.
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions 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.
static bool compare_stat(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
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.
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.
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
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,...)
@ 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.
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.
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Path manipulation functions.
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
Time value with nanosecond precision.
long tv_nsec
Number of nanosecond, on top.
time_t tv_sec
Number of seconds since the epoch.