61const char FilenameSafeChars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
63#define MAX_LOCK_ATTEMPTS 5
79static bool stat_equal(
struct stat *st_old,
struct stat *st_new)
81 return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
82 (st_old->st_rdev == st_new->st_rdev);
95 const char *basename = NULL;
101 char *p = strrchr(parent.
data,
'/');
114 if (!mkdtemp(newdir->
data))
157 int rc = fclose(*fp);
175 if (fflush(*fp) || fsync(fileno(*fp)))
177 int save_errno = errno;
201 struct stat st = { 0 };
204 const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
205 if (!is_regular_file)
212 struct stat st2 = { 0 };
213 if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
214 (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
234 if (!fp_in || !fp_out)
239 char buf[2048] = { 0 };
240 size_t chunk = (size >
sizeof(buf)) ?
sizeof(buf) : size;
241 chunk = fread(buf, 1, chunk, fp_in);
244 if (fwrite(buf, 1, chunk, fp_out) != chunk)
250 if (fflush(fp_out) != 0)
264 if (!fp_in || !fp_out)
269 char buf[1024] = { 0 };
271 while ((l = fread(buf, 1,
sizeof(buf), fp_in)) > 0)
273 if (fwrite(buf, 1, l, fp_out) != l)
278 if (fflush(fp_out) != 0)
292 struct stat st_old = { 0 };
293 struct stat st_new = { 0 };
295 if (!oldpath || !newpath)
298 if ((unlink(newpath) == -1) && (errno != ENOENT))
301 if (oldpath[0] ==
'/')
303 if (symlink(oldpath, newpath) == -1)
318 if (symlink(
buf_string(&abs_oldpath), newpath) == -1)
327 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
348 struct stat st_src = { 0 };
349 struct stat st_target = { 0 };
355 if (link(src, target) != 0)
368 if ((lstat(src, &st_src) == 0) && (lstat(target, &st_target) == 0) &&
372 src, target, strerror(errno), errno);
387 strerror(errno), errno);
391 if ((errno == EXDEV) || (errno == ENOSYS) || errno == EPERM
396 || errno == EOPNOTSUPP
401 if (rename(src, target) == -1)
404 strerror(errno), errno);
422 if (lstat(src, &st_src) == -1)
428 if (lstat(target, &st_target) == -1)
438 mutt_debug(
LL_DEBUG1,
"stat blocks for %s and %s diverge; pretending EEXIST\n", src, target);
447 if (unlink(src) == -1)
466 struct dirent *de = NULL;
467 struct stat st = { 0 };
481 while ((de = readdir(dir)))
495 if (S_ISDIR(st.st_mode))
530 for (count -= 2; count >= 0; count--)
533 buf_printf(new_file,
"%s%d", path, count + 1);
565 if (
mkwrapdir(path, &safe_file, &safe_dir) == -1)
571 fd = open(
buf_string(&safe_file), flags, 0600);
587 fd = open(path, flags & ~O_EXCL, 0600);
592 struct stat st_old = { 0 };
593 struct stat st_new = { 0 };
594 if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
623 return opendir(path);
643 uint32_t flags = O_CREAT | O_EXCL |
O_NOFOLLOW;
654 return fdopen(fd, mode);
658 return fopen(path, mode);
672 size_t size = strlen(path);
675 mbstate_t mbstate = { 0 };
676 for (
size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
677 size -= consumed, path += consumed)
682 mbstate = (mbstate_t){ 0 };
684 memset(path,
'_', consumed);
689 memset(path,
'_', consumed);
695 memset(path,
'_', consumed);
740 if (fseeko(fp, offset, whence) != 0)
742 mutt_perror(
_(
"Failed to seek file: %s"), strerror(errno));
779 if (!fgets(line + offset, *size - offset, fp))
784 ch = strchr(line + offset,
'\n');
792 if ((ch > line) && (*(ch - 1) ==
'\r'))
794 if (!(flags &
MUTT_RL_CONT) || (ch == line) || (*(ch - 1) !=
'\\'))
796 offset = ch - line - 1;
909 for (
size_t i = 0; (j < buflen) && filename[i]; i++)
911 if ((filename[i] ==
'\'') || (filename[i] ==
'`'))
915 buf[j++] = filename[i];
920 buf[j++] = filename[i];
938 if (!buf || !filename)
945 for (; *filename !=
'\0'; filename++)
947 if ((*filename ==
'\'') || (*filename ==
'`'))
979 if (!path || (*path ==
'\0'))
987 const size_t len = strlen(path);
989 if (len >=
sizeof(tmp_path))
991 errno = ENAMETOOLONG;
995 struct stat st = { 0 };
996 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
1002 for (
char *p = tmp_path + 1; *p; p++)
1010 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
1016 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
1036 struct utimbuf utim = { 0 };
1037 struct stat st2 = { 0 };
1042 if (stat(fp, &st2) == -1)
1047 mtime = st->st_mtime;
1051 utim.actime = mtime;
1052 utim.modtime = mtime;
1056 rc = utime(fp, &utim);
1057 }
while ((rc == -1) && (errno == EINTR));
1076 struct utimbuf utim = { 0 };
1077 struct stat st = { 0 };
1079 if (stat(from, &st) != -1)
1081 utim.actime = st.st_mtime;
1082 utim.modtime = st.st_mtime;
1097 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1098 futimens(fd, times);
1115 return chmod(path, mode);
1163 struct stat st2 = { 0 };
1167 if (stat(path, &st2) == -1)
1171 return chmod(path, st->st_mode | mode);
1219 struct stat st2 = { 0 };
1223 if (stat(path, &st2) == -1)
1227 return chmod(path, st->st_mode & ~mode);
1230#if defined(USE_FCNTL)
1245 struct stat st = { 0 }, prev_sb = { 0 };
1249 struct flock lck = { 0 };
1250 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1251 lck.l_whence = SEEK_SET;
1253 while (fcntl(fd, F_SETLK, &lck) == -1)
1256 if ((errno != EAGAIN) && (errno != EACCES))
1262 if (fstat(fd, &st) != 0)
1269 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1272 mutt_error(
_(
"Timeout exceeded while attempting fcntl lock"));
1292 struct flock unlockit = { 0 };
1293 unlockit.l_type = F_UNLCK;
1294 unlockit.l_whence = SEEK_SET;
1295 (void) fcntl(fd, F_SETLK, &unlockit);
1299#elif defined(USE_FLOCK)
1314 struct stat st = { 0 }, prev_sb = { 0 };
1319 while (flock(fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1)
1321 if (errno != EWOULDBLOCK)
1328 if (fstat(fd, &st) != 0)
1335 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1338 mutt_error(
_(
"Timeout exceeded while attempting flock lock"));
1345 mutt_message(
_(
"Waiting for flock attempt... %d"), ++attempt);
1369#error "You must select a locking mechanism via USE_FCNTL or USE_FLOCK"
1381 struct stat st = { 0 };
1383 int fd = open(path, O_RDWR);
1393 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1414 if (!oldfile || !newfile)
1416 if (access(oldfile, F_OK) != 0)
1418 if (access(newfile, F_OK) == 0)
1421 FILE *fp_old = fopen(oldfile,
"r");
1453 buf = fgets(buf, buflen, fp);
1462 while ((*buf !=
'\0') && !isspace(*buf))
1482 struct stat st = { 0 };
1483 if (stat(path, &st) == -1)
1486 return st.st_size == 0;
1514 if (!dest || !fmt || !src)
1517 const char *p = NULL;
1522 for (p = fmt; *p; p++)
1565 struct stat st = { 0 };
1566 if (stat(path, &st) != 0)
1583 struct stat st = { 0 };
1584 if (fstat(fileno(fp), &st) != 0)
1631 dest->
tv_sec = st->st_atime;
1632#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1633 dest->
tv_nsec = st->st_atim.tv_nsec;
1637 dest->
tv_sec = st->st_mtime;
1638#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1639 dest->
tv_nsec = st->st_mtim.tv_nsec;
1643 dest->
tv_sec = st->st_ctime;
1644#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1645 dest->
tv_nsec = st->st_ctim.tv_nsec;
1702 struct stat st = { 0 };
1704 if ((rc != -1) && S_ISLNK(st.st_mode))
1729 return fwrite(str, 1, len, fp);
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 <=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.
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.
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_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.
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.
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
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.
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.
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)
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.