62 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
64 #define MAX_LOCK_ATTEMPTS 5 82 return (osb->st_dev == nsb->st_dev) && (osb->st_ino == nsb->st_ino) &&
83 (osb->st_rdev == nsb->st_rdev);
96 const char *basename = NULL;
102 char *p = strrchr(parent.
data,
'/');
115 if (!mkdtemp(newdir->
data))
158 int rc = fclose(*fp);
176 if (fflush(*fp) || fsync(fileno(*fp)))
178 int save_errno = errno;
203 const bool is_regular_file = (lstat(s, &sb) == 0) && S_ISREG(sb.st_mode);
204 if (!is_regular_file)
212 if ((fstat(fd, &sb2) != 0) || !S_ISREG(sb2.st_mode) ||
213 (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino))
219 FILE *fp = fdopen(fd,
"r+");
223 char buf[2048] = { 0 };
224 while (sb.st_size > 0)
226 fwrite(buf, 1,
MIN(
sizeof(buf), sb.st_size), fp);
227 sb.st_size -=
MIN(
sizeof(buf), sb.st_size);
243 if (!fp_in || !fp_out)
249 size_t chunk = (size >
sizeof(buf)) ?
sizeof(buf) : size;
250 chunk = fread(buf, 1, chunk, fp_in);
253 if (fwrite(buf, 1, chunk, fp_out) != chunk)
259 if (fflush(fp_out) != 0)
273 if (!fp_in || !fp_out)
280 while ((l = fread(buf, 1,
sizeof(buf), fp_in)) > 0)
282 if (fwrite(buf, 1, l, fp_out) != l)
287 if (fflush(fp_out) != 0)
301 struct stat osb, nsb;
303 if (!oldpath || !newpath)
306 if ((unlink(newpath) == -1) && (errno != ENOENT))
309 if (oldpath[0] ==
'/')
311 if (symlink(oldpath, newpath) == -1)
326 if (symlink(
mutt_b2s(&abs_oldpath), newpath) == -1)
335 if ((stat(oldpath, &osb) == -1) || (stat(newpath, &nsb) == -1) ||
356 struct stat ssb, tsb;
362 if (link(src, target) != 0)
375 if ((lstat(src, &ssb) == 0) && (lstat(target, &tsb) == 0) &&
379 src, target, strerror(errno), errno);
394 strerror(errno), errno);
398 if ((errno == EXDEV) || (errno == ENOSYS) || errno == EPERM
403 || errno == EOPNOTSUPP
408 if (rename(src, target) == -1)
411 strerror(errno), errno);
429 if (lstat(src, &ssb) == -1)
435 if (lstat(target, &tsb) == -1)
445 mutt_debug(
LL_DEBUG1,
"stat blocks for %s and %s diverge; pretending EEXIST\n", src, target);
454 if (unlink(src) == -1)
473 struct dirent *de = NULL;
477 DIR *dirp = opendir(path);
488 while ((de = readdir(dirp)))
490 if ((strcmp(
".", de->d_name) == 0) || (strcmp(
"..", de->d_name) == 0))
496 if (stat(
mutt_b2s(&cur), &statbuf) == -1)
502 if (S_ISDIR(statbuf.st_mode))
527 struct stat osb, nsb;
537 if (
mkwrapdir(path, &safe_file, &safe_dir) == -1)
543 fd = open(
mutt_b2s(&safe_file), flags, 0600);
559 fd = open(path, flags & ~O_EXCL, 0600);
564 if (((lstat(path, &osb) < 0) || (fstat(fd, &nsb) < 0)) || !
compare_stat(&osb, &nsb))
607 return fdopen(fd, mode);
610 return fopen(path, mode);
623 for (; *path; path++)
683 if (!fgets(line + offset, *size - offset, fp))
688 ch = strchr(line + offset,
'\n');
696 if ((ch > line) && (*(ch - 1) ==
'\r'))
698 if (!(flags &
MUTT_CONT) || (ch == line) || (*(ch - 1) !=
'\\'))
700 offset = ch - line - 1;
811 for (
size_t i = 0; (j < buflen) && filename[i]; i++)
813 if ((filename[i] ==
'\'') || (filename[i] ==
'`'))
817 buf[j++] = filename[i];
821 buf[j++] = filename[i];
838 if (!buf || !filename)
845 for (; *filename !=
'\0'; filename++)
847 if ((*filename ==
'\'') || (*filename ==
'`'))
877 if (!path || (*path ==
'\0'))
885 const size_t len = strlen(path);
887 if (len >=
sizeof(tmp_path))
889 errno = ENAMETOOLONG;
894 if ((stat(path, &sb) == 0) && S_ISDIR(sb.st_mode))
900 for (
char *p = tmp_path + 1; *p; p++)
908 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
914 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
934 int n = snprintf(name,
sizeof(name),
"%s/neomutt-XXXXXX",
NONULL(
C_Tmpdir));
938 int fd = mkstemp(name);
942 FILE *fp = fdopen(fd,
"w+");
944 if ((unlink(name) != 0) && (errno != ENOENT))
950 MuttLogger(0, file, line, func, 1,
"created temp file '%s'\n", name);
974 if (stat(fp, &st2) == -1)
979 mtime = st->st_mtime;
984 utim.modtime = mtime;
988 rc = utime(fp, &utim);
989 }
while ((rc == -1) && (errno == EINTR));
1008 struct utimbuf utim;
1011 if (stat(from, &st) != -1)
1013 utim.actime = st.st_mtime;
1014 utim.modtime = st.st_mtime;
1028 #ifdef HAVE_FUTIMENS 1029 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1030 futimens(fd, times);
1047 return chmod(path, mode);
1099 if (stat(path, &st2) == -1)
1103 return chmod(path, st->st_mode | mode);
1155 if (stat(path, &st2) == -1)
1159 return chmod(path, st->st_mode & ~mode);
1162 #if defined(USE_FCNTL) 1177 struct stat sb = { 0 }, prev_sb = { 0 };
1182 memset(&lck, 0,
sizeof(
struct flock));
1183 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1184 lck.l_whence = SEEK_SET;
1186 while (fcntl(fd, F_SETLK, &lck) == -1)
1189 if ((errno != EAGAIN) && (errno != EACCES))
1195 if (fstat(fd, &sb) != 0)
1202 if ((prev_sb.st_size == sb.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1205 mutt_error(
_(
"Timeout exceeded while attempting fcntl lock"));
1225 struct flock unlockit;
1227 memset(&unlockit, 0,
sizeof(
struct flock));
1228 unlockit.l_type = F_UNLCK;
1229 unlockit.l_whence = SEEK_SET;
1230 fcntl(fd, F_SETLK, &unlockit);
1234 #elif defined(USE_FLOCK) 1249 struct stat sb = { 0 }, prev_sb = { 0 };
1254 while (flock(fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1)
1256 if (errno != EWOULDBLOCK)
1263 if (fstat(fd, &sb) != 0)
1270 if ((prev_sb.st_size == sb.st_size) && (++count >= (timeout ?
MAX_LOCK_ATTEMPTS : 0)))
1273 mutt_error(
_(
"Timeout exceeded while attempting flock lock"));
1280 mutt_message(
_(
"Waiting for flock attempt... %d"), ++attempt);
1304 #error "You must select a locking mechanism via USE_FCNTL or USE_FLOCK" 1318 int fd = open(path, O_RDWR);
1328 if ((fstat(fd, &sb) == 0) && (sb.st_size == 0))
1349 if (!oldfile || !newfile)
1351 if (access(oldfile, F_OK) != 0)
1353 if (access(newfile, F_OK) == 0)
1356 FILE *fp_old = fopen(oldfile,
"r");
1388 buf = fgets(buf, buflen, fp);
1397 while ((*buf !=
'\0') && !isspace(*buf))
1418 if (stat(path, &st) == -1)
1421 return st.st_size == 0;
1449 if (!dest || !fmt || !src)
1452 const char *p = NULL;
1457 for (p = fmt; *p; p++)
1501 if (stat(path, &sb) != 0)
1548 dest->
tv_sec = sb->st_atime;
1549 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1550 dest->
tv_nsec = sb->st_atim.tv_nsec;
1554 dest->
tv_sec = sb->st_mtime;
1555 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1556 dest->
tv_nsec = sb->st_mtim.tv_nsec;
1560 dest->
tv_sec = sb->st_ctime;
1561 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC 1562 dest->
tv_nsec = sb->st_ctim.tv_nsec;
1620 int rc = lstat(
mutt_b2s(buf), &st);
1621 if ((rc != -1) && S_ISLNK(st.st_mode))
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
#define MAX_LOCK_ATTEMPTS
void mutt_file_touch_atime(int fd)
Set the access time to current time.
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Memory management wrappers.
long mutt_file_get_size(const char *path)
Get the size of a file.
File/dir's ctime - creation time.
void mutt_file_set_mtime(const char *from, const char *to)
Set the modification time of one file from another.
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
#define mutt_message(...)
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *sb, enum MuttStatType type)
Read the stat() time into a time value.
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
void mutt_file_unlink(const char *s)
Delete a file, carefully.
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
String manipulation buffer.
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
static bool compare_stat(struct stat *osb, struct stat *nsb)
Compare the struct stat's of two files/dirs.
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
int mutt_file_chmod_add_stat(const char *path, mode_t mode, struct stat *st)
Add permissions to a file.
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
log_dispatcher_t MuttLogger
The log dispatcher.
File management functions.
#define MUTT_CONT
-continuation
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.
String manipulation functions.
int mutt_file_lock(int fd, bool excl, bool timeout)
(try to) lock a file using fcntl()
void mutt_file_unlink_empty(const char *path)
Delete a file if it's empty.
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
MuttStatType
Flags for mutt_file_get_stat_timespec.
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
File/dir's mtime - last modified time.
bool mutt_file_map_lines(mutt_file_map_t func, void *user_data, FILE *fp, int flags)
Process lines of text read from a file pointer.
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions of a file.
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
bool mutt_file_iter_line(struct MuttFileIter *iter, FILE *fp, int flags)
iterate over the lines from an open file pointer
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
int mutt_file_sanitize_regex(struct Buffer *dest, const char *src)
Escape any regex-magic characters in a string.
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
void mutt_file_expand_fmt(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
static const char rx_special_chars[]
char * data
Pointer to data.
size_t size
allocated size of line data
void mutt_file_resolve_symlink(struct Buffer *buf)
Resolve a symlink in place.
size_t mutt_file_quote_filename(const char *filename, char *buf, size_t buflen)
Quote a filename to survive the shell's quoting rules.
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
State record for mutt_file_iter_line()
Path manipulation functions.
int mutt_file_stat_timespec_compare(struct stat *sba, enum MuttStatType type, struct timespec *b)
Compare stat info with a time value.
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
char * mutt_file_read_keyword(const char *file, char *buf, size_t buflen)
Read a keyword from a file.
int mutt_file_stat_compare(struct stat *sba, enum MuttStatType sba_type, struct stat *sbb, enum MuttStatType sbb_type)
Compare two stat infos.
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
static int put_file_in_place(const char *path, const char *safe_file, const char *safe_dir)
Move a file into place.
bool(* mutt_file_map_t)(char *line, int line_num, void *user_data)
Callback function for mutt_file_map_lines()
General purpose object for storing and parsing strings.
int mutt_file_open(const char *path, int flags)
Open a file.
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
char * C_Tmpdir
Config: Directory for temporary files.
int mutt_file_check_empty(const char *path)
Is the mailbox empty.
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
Time value with nanosecond precision.
#define MUTT_EOL
don't strip \n / \r\n
const char filename_safe_chars[]
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
#define mutt_debug(LEVEL,...)
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Time and date handling routines.
FILE * mutt_file_mkstemp_full(const char *file, int line, const char *func)
Create temporary file safely.
File/dir's atime - last accessed time.
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.