NeoMutt  2022-04-29-81-g9c5a59
Teaching an old dog new tricks
DOXYGEN
file.c File Reference

File management functions. More...

#include "config.h"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <utime.h>
#include "config/lib.h"
#include "core/lib.h"
#include "file.h"
#include "buffer.h"
#include "date.h"
#include "logging.h"
#include "memory.h"
#include "message.h"
#include "path.h"
#include "pool.h"
#include "string2.h"
+ Include dependency graph for file.c:

Go to the source code of this file.

Macros

#define MAX_LOCK_ATTEMPTS   5
 
#define O_NOFOLLOW   0
 

Functions

static bool compare_stat (struct stat *st_old, struct stat *st_new)
 Compare the struct stat's of two files/dirs. More...
 
static int mkwrapdir (const char *path, struct Buffer *newfile, struct Buffer *newdir)
 Create a temporary directory next to a file name. More...
 
static int put_file_in_place (const char *path, const char *safe_file, const char *safe_dir)
 Move a file into place. More...
 
int mutt_file_fclose (FILE **fp)
 Close a FILE handle (and NULL the pointer) More...
 
int mutt_file_fsync_close (FILE **fp)
 Flush the data, before closing a file (and NULL the pointer) More...
 
void mutt_file_unlink (const char *s)
 Delete a file, carefully. More...
 
int mutt_file_copy_bytes (FILE *fp_in, FILE *fp_out, size_t size)
 Copy some content from one file to another. More...
 
int mutt_file_copy_stream (FILE *fp_in, FILE *fp_out)
 Copy the contents of one file into another. More...
 
int mutt_file_symlink (const char *oldpath, const char *newpath)
 Create a symlink. More...
 
int mutt_file_safe_rename (const char *src, const char *target)
 NFS-safe renaming of files. More...
 
int mutt_file_rmtree (const char *path)
 Recursively remove a directory. More...
 
const char * mutt_file_rotate (const char *path, int count)
 Rotate a set of numbered files. More...
 
int mutt_file_open (const char *path, uint32_t flags)
 Open a file. More...
 
FILE * mutt_file_fopen (const char *path, const char *mode)
 Call fopen() safely. More...
 
void mutt_file_sanitize_filename (char *path, bool slash)
 Replace unsafe characters in a filename. More...
 
int mutt_file_sanitize_regex (struct Buffer *dest, const char *src)
 Escape any regex-magic characters in a string. More...
 
bool mutt_file_seek (FILE *fp, LOFF_T offset, int whence)
 Wrapper for fseeko with error handling. More...
 
char * mutt_file_read_line (char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
 Read a line from a file. More...
 
bool mutt_file_iter_line (struct MuttFileIter *iter, FILE *fp, ReadLineFlags flags)
 Iterate over the lines from an open file pointer. More...
 
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. More...
 
size_t mutt_file_quote_filename (const char *filename, char *buf, size_t buflen)
 Quote a filename to survive the shell's quoting rules. More...
 
void mutt_buffer_quote_filename (struct Buffer *buf, const char *filename, bool add_outer)
 Quote a filename to survive the shell's quoting rules. More...
 
int mutt_file_mkdir (const char *path, mode_t mode)
 Recursively create directories. More...
 
FILE * mutt_file_mkstemp_full (const char *file, int line, const char *func)
 Create temporary file safely. More...
 
time_t mutt_file_decrease_mtime (const char *fp, struct stat *st)
 Decrease a file's modification time by 1 second. More...
 
void mutt_file_set_mtime (const char *from, const char *to)
 Set the modification time of one file from another. More...
 
void mutt_file_touch_atime (int fd)
 Set the access time to current time. More...
 
int mutt_file_chmod (const char *path, mode_t mode)
 Set permissions of a file. More...
 
int mutt_file_chmod_add (const char *path, mode_t mode)
 Add permissions to a file. More...
 
int mutt_file_chmod_add_stat (const char *path, mode_t mode, struct stat *st)
 Add permissions to a file. More...
 
int mutt_file_chmod_rm (const char *path, mode_t mode)
 Remove permissions from a file. More...
 
int mutt_file_chmod_rm_stat (const char *path, mode_t mode, struct stat *st)
 Remove permissions from a file. More...
 
int mutt_file_lock (int fd, bool excl, bool timeout)
 (Try to) Lock a file using fcntl() More...
 
int mutt_file_unlock (int fd)
 Unlock a file previously locked by mutt_file_lock() More...
 
void mutt_file_unlink_empty (const char *path)
 Delete a file if it's empty. More...
 
int mutt_file_rename (const char *oldfile, const char *newfile)
 Rename a file. More...
 
char * mutt_file_read_keyword (const char *file, char *buf, size_t buflen)
 Read a keyword from a file. More...
 
int mutt_file_check_empty (const char *path)
 Is the mailbox empty. More...
 
void mutt_buffer_file_expand_fmt_quote (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename. More...
 
void mutt_file_expand_fmt (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename. More...
 
long mutt_file_get_size (const char *path)
 Get the size of a file. More...
 
long mutt_file_get_size_fp (FILE *fp)
 Get the size of a file. More...
 
int mutt_file_timespec_compare (struct timespec *a, struct timespec *b)
 Compare to time values. More...
 
void mutt_file_get_stat_timespec (struct timespec *dest, struct stat *st, enum MuttStatType type)
 Read the stat() time into a time value. More...
 
int mutt_file_stat_timespec_compare (struct stat *st, enum MuttStatType type, struct timespec *b)
 Compare stat info with a time value. More...
 
int mutt_file_stat_compare (struct stat *st1, enum MuttStatType st1_type, struct stat *st2, enum MuttStatType st2_type)
 Compare two stat infos. More...
 
void mutt_file_resolve_symlink (struct Buffer *buf)
 Resolve a symlink in place. More...
 

Variables

static const char rx_special_chars [] = "^.[$()|*+?{\\"
 
const char filename_safe_chars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"
 

Detailed Description

File management functions.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file file.c.

Macro Definition Documentation

◆ MAX_LOCK_ATTEMPTS

#define MAX_LOCK_ATTEMPTS   5

Definition at line 63 of file file.c.

◆ O_NOFOLLOW

#define O_NOFOLLOW   0

Definition at line 67 of file file.c.

Function Documentation

◆ compare_stat()

static bool compare_stat ( struct stat *  st_old,
struct stat *  st_new 
)
static

Compare the struct stat's of two files/dirs.

Parameters
st_oldstruct stat of the first file/dir
st_newstruct stat of the second file/dir
Return values
trueThey match

This compares the device id (st_dev), inode number (st_ino) and special id (st_rdev) of the files/dirs.

Definition at line 79 of file file.c.

80 {
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);
83 }
+ Here is the caller graph for this function:

◆ mkwrapdir()

static int mkwrapdir ( const char *  path,
struct Buffer newfile,
struct Buffer newdir 
)
static

Create a temporary directory next to a file name.

Parameters
pathExisting filename
newfileNew filename
newdirNew directory name
Return values
0Success
-1Error

Definition at line 93 of file file.c.

94 {
95  const char *basename = NULL;
96  int rc = 0;
97 
98  struct Buffer parent = mutt_buffer_make(PATH_MAX);
99  mutt_buffer_strcpy(&parent, NONULL(path));
100 
101  char *p = strrchr(parent.data, '/');
102  if (p)
103  {
104  *p = '\0';
105  basename = p + 1;
106  }
107  else
108  {
109  mutt_buffer_strcpy(&parent, ".");
110  basename = path;
111  }
112 
113  mutt_buffer_printf(newdir, "%s/%s", mutt_buffer_string(&parent), ".muttXXXXXX");
114  if (!mkdtemp(newdir->data))
115  {
116  mutt_debug(LL_DEBUG1, "mkdtemp() failed\n");
117  rc = -1;
118  goto cleanup;
119  }
120 
121  mutt_buffer_printf(newfile, "%s/%s", newdir->data, NONULL(basename));
122 
123 cleanup:
124  mutt_buffer_dealloc(&parent);
125  return rc;
126 }
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define PATH_MAX
Definition: mutt.h:40
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ put_file_in_place()

static int put_file_in_place ( const char *  path,
const char *  safe_file,
const char *  safe_dir 
)
static

Move a file into place.

Parameters
pathDestination path
safe_fileCurrent filename
safe_dirCurrent directory name
Return values
0Success
-1Error, see errno

Definition at line 136 of file file.c.

137 {
138  int rc;
139 
140  rc = mutt_file_safe_rename(safe_file, path);
141  unlink(safe_file);
142  rmdir(safe_dir);
143  return rc;
144 }
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:344
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_fclose()

int mutt_file_fclose ( FILE **  fp)

Close a FILE handle (and NULL the pointer)

Parameters
[out]fpFILE handle to close
Return values
0Success
EOFError, see errno

Definition at line 152 of file file.c.

153 {
154  if (!fp || !*fp)
155  return 0;
156 
157  int rc = fclose(*fp);
158  *fp = NULL;
159  return rc;
160 }

◆ mutt_file_fsync_close()

int mutt_file_fsync_close ( FILE **  fp)

Flush the data, before closing a file (and NULL the pointer)

Parameters
[out]fpFILE handle to close
Return values
0Success
EOFError, see errno

Definition at line 168 of file file.c.

169 {
170  if (!fp || !*fp)
171  return 0;
172 
173  int rc = 0;
174 
175  if (fflush(*fp) || fsync(fileno(*fp)))
176  {
177  int save_errno = errno;
178  rc = -1;
179  mutt_file_fclose(fp);
180  errno = save_errno;
181  }
182  else
183  rc = mutt_file_fclose(fp);
184 
185  return rc;
186 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_unlink()

void mutt_file_unlink ( const char *  s)

Delete a file, carefully.

Parameters
sFilename

This won't follow symlinks.

Definition at line 194 of file file.c.

195 {
196  if (!s)
197  return;
198 
199  struct stat st = { 0 };
200  /* Defend against symlink attacks */
201 
202  const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
203  if (!is_regular_file)
204  return;
205 
206  const int fd = open(s, O_RDWR | O_NOFOLLOW);
207  if (fd < 0)
208  return;
209 
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))
213  {
214  close(fd);
215  return;
216  }
217 
218  unlink(s);
219  close(fd);
220 }
#define O_NOFOLLOW
Definition: file.c:67
+ Here is the caller graph for this function:

◆ mutt_file_copy_bytes()

int mutt_file_copy_bytes ( FILE *  fp_in,
FILE *  fp_out,
size_t  size 
)

Copy some content from one file to another.

Parameters
fp_inSource file
fp_outDestination file
sizeMaximum number of bytes to copy
Return values
0Success
-1Error, see errno

Definition at line 230 of file file.c.

231 {
232  if (!fp_in || !fp_out)
233  return -1;
234 
235  while (size > 0)
236  {
237  char buf[2048];
238  size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size;
239  chunk = fread(buf, 1, chunk, fp_in);
240  if (chunk < 1)
241  break;
242  if (fwrite(buf, 1, chunk, fp_out) != chunk)
243  return -1;
244 
245  size -= chunk;
246  }
247 
248  if (fflush(fp_out) != 0)
249  return -1;
250  return 0;
251 }
+ Here is the caller graph for this function:

◆ mutt_file_copy_stream()

int mutt_file_copy_stream ( FILE *  fp_in,
FILE *  fp_out 
)

Copy the contents of one file into another.

Parameters
fp_inSource file
fp_outDestination file
Return values
nSuccess, number of bytes copied
-1Error, see errno

Definition at line 260 of file file.c.

261 {
262  if (!fp_in || !fp_out)
263  return -1;
264 
265  size_t total = 0;
266  size_t l;
267  char buf[1024];
268 
269  while ((l = fread(buf, 1, sizeof(buf), fp_in)) > 0)
270  {
271  if (fwrite(buf, 1, l, fp_out) != l)
272  return -1;
273  total += l;
274  }
275 
276  if (fflush(fp_out) != 0)
277  return -1;
278  return total;
279 }
+ Here is the caller graph for this function:

◆ mutt_file_symlink()

int mutt_file_symlink ( const char *  oldpath,
const char *  newpath 
)

Create a symlink.

Parameters
oldpathExisting pathname
newpathNew pathname
Return values
0Success
-1Error, see errno

Definition at line 288 of file file.c.

289 {
290  struct stat st_old = { 0 };
291  struct stat st_new = { 0 };
292 
293  if (!oldpath || !newpath)
294  return -1;
295 
296  if ((unlink(newpath) == -1) && (errno != ENOENT))
297  return -1;
298 
299  if (oldpath[0] == '/')
300  {
301  if (symlink(oldpath, newpath) == -1)
302  return -1;
303  }
304  else
305  {
306  struct Buffer abs_oldpath = mutt_buffer_make(PATH_MAX);
307 
308  if (!mutt_path_getcwd(&abs_oldpath))
309  {
310  mutt_buffer_dealloc(&abs_oldpath);
311  return -1;
312  }
313 
314  mutt_buffer_addch(&abs_oldpath, '/');
315  mutt_buffer_addstr(&abs_oldpath, oldpath);
316  if (symlink(mutt_buffer_string(&abs_oldpath), newpath) == -1)
317  {
318  mutt_buffer_dealloc(&abs_oldpath);
319  return -1;
320  }
321 
322  mutt_buffer_dealloc(&abs_oldpath);
323  }
324 
325  if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
326  !compare_stat(&st_old, &st_new))
327  {
328  unlink(newpath);
329  return -1;
330  }
331 
332  return 0;
333 }
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
static bool compare_stat(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
Definition: file.c:79
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:561
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_safe_rename()

int mutt_file_safe_rename ( const char *  src,
const char *  target 
)

NFS-safe renaming of files.

Parameters
srcOriginal filename
targetNew filename
Return values
0Success
-1Error, see errno

Warning: We don't check whether src and target are equal.

Definition at line 344 of file file.c.

345 {
346  struct stat st_src = { 0 };
347  struct stat st_target = { 0 };
348  int link_errno;
349 
350  if (!src || !target)
351  return -1;
352 
353  if (link(src, target) != 0)
354  {
355  link_errno = errno;
356 
357  /* It is historically documented that link can return -1 if NFS
358  * dies after creating the link. In that case, we are supposed
359  * to use stat to check if the link was created.
360  *
361  * Derek Martin notes that some implementations of link() follow a
362  * source symlink. It might be more correct to use stat() on src.
363  * I am not doing so to minimize changes in behavior: the function
364  * used lstat() further below for 20 years without issue, and I
365  * believe was never intended to be used on a src symlink. */
366  if ((lstat(src, &st_src) == 0) && (lstat(target, &st_target) == 0) &&
367  (compare_stat(&st_src, &st_target) == 0))
368  {
369  mutt_debug(LL_DEBUG1, "link (%s, %s) reported failure: %s (%d) but actually succeeded\n",
370  src, target, strerror(errno), errno);
371  goto success;
372  }
373 
374  errno = link_errno;
375 
376  /* Coda does not allow cross-directory links, but tells
377  * us it's a cross-filesystem linking attempt.
378  *
379  * However, the Coda rename call is allegedly safe to use.
380  *
381  * With other file systems, rename should just fail when
382  * the files reside on different file systems, so it's safe
383  * to try it here. */
384  mutt_debug(LL_DEBUG1, "link (%s, %s) failed: %s (%d)\n", src, target,
385  strerror(errno), errno);
386 
387  /* FUSE may return ENOSYS. VFAT may return EPERM. FreeBSD's
388  * msdosfs may return EOPNOTSUPP. ENOTSUP can also appear. */
389  if ((errno == EXDEV) || (errno == ENOSYS) || errno == EPERM
390 #ifdef ENOTSUP
391  || errno == ENOTSUP
392 #endif
393 #ifdef EOPNOTSUPP
394  || errno == EOPNOTSUPP
395 #endif
396  )
397  {
398  mutt_debug(LL_DEBUG1, "trying rename\n");
399  if (rename(src, target) == -1)
400  {
401  mutt_debug(LL_DEBUG1, "rename (%s, %s) failed: %s (%d)\n", src, target,
402  strerror(errno), errno);
403  return -1;
404  }
405  mutt_debug(LL_DEBUG1, "rename succeeded\n");
406 
407  return 0;
408  }
409 
410  return -1;
411  }
412 
413  /* Remove the compare_stat() check, because it causes problems with maildir
414  * on filesystems that don't properly support hard links, such as sshfs. The
415  * filesystem creates the link, but the resulting file is given a different
416  * inode number by the sshfs layer. This results in an infinite loop
417  * creating links. */
418 #if 0
419  /* Stat both links and check if they are equal. */
420  if (lstat(src, &st_src) == -1)
421  {
422  mutt_debug(LL_DEBUG1, "#1 can't stat %s: %s (%d)\n", src, strerror(errno), errno);
423  return -1;
424  }
425 
426  if (lstat(target, &st_target) == -1)
427  {
428  mutt_debug(LL_DEBUG1, "#2 can't stat %s: %s (%d)\n", src, strerror(errno), errno);
429  return -1;
430  }
431 
432  /* pretend that the link failed because the target file did already exist. */
433 
434  if (!compare_stat(&st_src, &st_target))
435  {
436  mutt_debug(LL_DEBUG1, "stat blocks for %s and %s diverge; pretending EEXIST\n", src, target);
437  errno = EEXIST;
438  return -1;
439  }
440 #endif
441 
442 success:
443  /* Unlink the original link.
444  * Should we really ignore the return value here? XXX */
445  if (unlink(src) == -1)
446  {
447  mutt_debug(LL_DEBUG1, "unlink (%s) failed: %s (%d)\n", src, strerror(errno), errno);
448  }
449 
450  return 0;
451 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_rmtree()

int mutt_file_rmtree ( const char *  path)

Recursively remove a directory.

Parameters
pathDirectory to delete
Return values
0Success
-1Error, see errno

Definition at line 459 of file file.c.

460 {
461  if (!path)
462  return -1;
463 
464  struct dirent *de = NULL;
465  struct stat st = { 0 };
466  int rc = 0;
467 
468  DIR *dirp = opendir(path);
469  if (!dirp)
470  {
471  mutt_debug(LL_DEBUG1, "error opening directory %s\n", path);
472  return -1;
473  }
474 
475  /* We avoid using the buffer pool for this function, because it
476  * invokes recursively to an unknown depth. */
477  struct Buffer cur = mutt_buffer_make(PATH_MAX);
478 
479  while ((de = readdir(dirp)))
480  {
481  if ((strcmp(".", de->d_name) == 0) || (strcmp("..", de->d_name) == 0))
482  continue;
483 
484  mutt_buffer_printf(&cur, "%s/%s", path, de->d_name);
485  /* XXX make nonrecursive version */
486 
487  if (stat(mutt_buffer_string(&cur), &st) == -1)
488  {
489  rc = 1;
490  continue;
491  }
492 
493  if (S_ISDIR(st.st_mode))
495  else
496  rc |= unlink(mutt_buffer_string(&cur));
497  }
498  closedir(dirp);
499 
500  rc |= rmdir(path);
501 
502  mutt_buffer_dealloc(&cur);
503  return rc;
504 }
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:459
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_rotate()

const char* mutt_file_rotate ( const char *  path,
int  count 
)

Rotate a set of numbered files.

Parameters
pathTemplate filename
countMaximum number of files
Return values
ptrName of the 0'th file

Given a template 'temp', rename files numbered 0 to (count-1).

Rename:

  • ...
  • temp1 -> temp2
  • temp0 -> temp1

Definition at line 519 of file file.c.

520 {
521  if (!path)
522  return NULL;
523 
524  struct Buffer *old_file = mutt_buffer_pool_get();
525  struct Buffer *new_file = mutt_buffer_pool_get();
526 
527  /* rotate the old debug logs */
528  for (count -= 2; count >= 0; count--)
529  {
530  mutt_buffer_printf(old_file, "%s%d", path, count);
531  mutt_buffer_printf(new_file, "%s%d", path, count + 1);
532  (void) rename(mutt_buffer_string(old_file), mutt_buffer_string(new_file));
533  }
534 
535  path = mutt_buffer_strdup(old_file);
536  mutt_buffer_pool_release(&old_file);
537  mutt_buffer_pool_release(&new_file);
538 
539  return path;
540 }
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:432
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_open()

int mutt_file_open ( const char *  path,
uint32_t  flags 
)

Open a file.

Parameters
pathPathname to open
flagsFlags, e.g. O_EXCL
Return values
>0Success, file handle
-1Error

Definition at line 549 of file file.c.

550 {
551  if (!path)
552  return -1;
553 
554  int fd;
555  struct Buffer safe_file = mutt_buffer_make(0);
556  struct Buffer safe_dir = mutt_buffer_make(0);
557 
558  if (flags & O_EXCL)
559  {
560  mutt_buffer_alloc(&safe_file, PATH_MAX);
561  mutt_buffer_alloc(&safe_dir, PATH_MAX);
562 
563  if (mkwrapdir(path, &safe_file, &safe_dir) == -1)
564  {
565  fd = -1;
566  goto cleanup;
567  }
568 
569  fd = open(mutt_buffer_string(&safe_file), flags, 0600);
570  if (fd < 0)
571  {
572  rmdir(mutt_buffer_string(&safe_dir));
573  goto cleanup;
574  }
575 
576  /* NFS and I believe cygwin do not handle movement of open files well */
577  close(fd);
578  if (put_file_in_place(path, mutt_buffer_string(&safe_file),
579  mutt_buffer_string(&safe_dir)) == -1)
580  {
581  fd = -1;
582  goto cleanup;
583  }
584  }
585 
586  fd = open(path, flags & ~O_EXCL, 0600);
587  if (fd < 0)
588  goto cleanup;
589 
590  /* make sure the file is not symlink */
591  struct stat st_old = { 0 };
592  struct stat st_new = { 0 };
593  if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
594  !compare_stat(&st_old, &st_new))
595  {
596  close(fd);
597  fd = -1;
598  goto cleanup;
599  }
600 
601 cleanup:
602  mutt_buffer_dealloc(&safe_file);
603  mutt_buffer_dealloc(&safe_dir);
604 
605  return fd;
606 }
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
static int put_file_in_place(const char *path, const char *safe_file, const char *safe_dir)
Move a file into place.
Definition: file.c:136
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
Definition: file.c:93
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_fopen()

FILE* mutt_file_fopen ( const char *  path,
const char *  mode 
)

Call fopen() safely.

Parameters
pathFilename
modeMode e.g. "r" readonly; "w" read-write
Return values
ptrFILE handle
NULLError, see errno

When opening files for writing, make sure the file doesn't already exist to avoid race conditions.

Definition at line 618 of file file.c.

619 {
620  if (!path || !mode)
621  return NULL;
622 
623  if (mode[0] == 'w')
624  {
625  uint32_t flags = O_CREAT | O_EXCL | O_NOFOLLOW;
626 
627  if (mode[1] == '+')
628  flags |= O_RDWR;
629  else
630  flags |= O_WRONLY;
631 
632  int fd = mutt_file_open(path, flags);
633  if (fd < 0)
634  return NULL;
635 
636  return fdopen(fd, mode);
637  }
638  else
639  return fopen(path, mode);
640 }
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:549
+ Here is the call graph for this function:

◆ mutt_file_sanitize_filename()

void mutt_file_sanitize_filename ( char *  path,
bool  slash 
)

Replace unsafe characters in a filename.

Parameters
pathFilename to make safe
slashReplace '/' characters too

Definition at line 647 of file file.c.

648 {
649  if (!path)
650  return;
651 
652  for (; *path; path++)
653  {
654  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
655  *path = '_';
656  }
657 }
const char filename_safe_chars[]
Definition: file.c:61
+ Here is the caller graph for this function:

◆ mutt_file_sanitize_regex()

int mutt_file_sanitize_regex ( struct Buffer dest,
const char *  src 
)

Escape any regex-magic characters in a string.

Parameters
destBuffer for result
srcString to transform
Return values
0Success
-1Error

Definition at line 666 of file file.c.

667 {
668  if (!dest || !src)
669  return -1;
670 
671  mutt_buffer_reset(dest);
672  while (*src != '\0')
673  {
674  if (strchr(rx_special_chars, *src))
675  mutt_buffer_addch(dest, '\\');
676  mutt_buffer_addch(dest, *src++);
677  }
678 
679  return 0;
680 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static const char rx_special_chars[]
Definition: file.c:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_seek()

bool mutt_file_seek ( FILE *  fp,
LOFF_T  offset,
int  whence 
)

Wrapper for fseeko with error handling.

Parameters
[in]fpFile to seek
[in]offsetOffset
[in]whenceSeek mode
Return values
trueSeek was successful
falseSeek failed

Definition at line 690 of file file.c.

691 {
692  if (!fp)
693  {
694  return false;
695  }
696 
697  if (fseeko(fp, offset, whence) != 0)
698  {
699  mutt_perror(_("Failed to seek file: %s"), strerror(errno));
700  return false;
701  }
702 
703  return true;
704 }
#define mutt_perror(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
+ Here is the caller graph for this function:

◆ mutt_file_read_line()

char* mutt_file_read_line ( char *  line,
size_t *  size,
FILE *  fp,
int *  line_num,
ReadLineFlags  flags 
)

Read a line from a file.

Parameters
[out]lineBuffer allocated on the head (optional)
[in]sizeLength of buffer
[in]fpFile to read
[out]line_numCurrent line number (optional)
[in]flagsFlags, e.g. MUTT_RL_CONT
Return values
ptrThe allocated string

Read a line from "fp" into the dynamically allocated "line", increasing "line" if necessary. The ending "\n" or "\r\n" is removed. If a line ends with "\", this char and the linefeed is removed, and the next line is read too.

Definition at line 720 of file file.c.

721 {
722  if (!size || !fp)
723  return NULL;
724 
725  size_t offset = 0;
726  char *ch = NULL;
727 
728  if (!line)
729  {
730  *size = 256;
731  line = mutt_mem_malloc(*size);
732  }
733 
734  while (true)
735  {
736  if (!fgets(line + offset, *size - offset, fp))
737  {
738  FREE(&line);
739  return NULL;
740  }
741  ch = strchr(line + offset, '\n');
742  if (ch)
743  {
744  if (line_num)
745  (*line_num)++;
746  if (flags & MUTT_RL_EOL)
747  return line;
748  *ch = '\0';
749  if ((ch > line) && (*(ch - 1) == '\r'))
750  *--ch = '\0';
751  if (!(flags & MUTT_RL_CONT) || (ch == line) || (*(ch - 1) != '\\'))
752  return line;
753  offset = ch - line - 1;
754  }
755  else
756  {
757  int c;
758  c = getc(fp); /* This is kind of a hack. We want to know if the
759  char at the current point in the input stream is EOF.
760  feof() will only tell us if we've already hit EOF, not
761  if the next character is EOF. So, we need to read in
762  the next character and manually check if it is EOF. */
763  if (c == EOF)
764  {
765  /* The last line of fp isn't \n terminated */
766  if (line_num)
767  (*line_num)++;
768  return line;
769  }
770  else
771  {
772  ungetc(c, fp); /* undo our damage */
773  /* There wasn't room for the line -- increase "line" */
774  offset = *size - 1; /* overwrite the terminating 0 */
775  *size += 256;
776  mutt_mem_realloc(&line, *size);
777  }
778  }
779  }
780 }
#define MUTT_RL_CONT
-continuation
Definition: file.h:39
#define MUTT_RL_EOL
don't strip \n / \r\n
Definition: file.h:40
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_iter_line()

bool mutt_file_iter_line ( struct MuttFileIter iter,
FILE *  fp,
ReadLineFlags  flags 
)

Iterate over the lines from an open file pointer.

Parameters
iterState of iteration including ptr to line
fpFile pointer to read from
flagsSame as mutt_file_read_line()
Return values
trueData read
falseOn eof

This is a slightly cleaner interface for mutt_file_read_line() which avoids the eternal C loop initialization ugliness. Use like this:

struct MuttFileIter iter = { 0 };
while (mutt_file_iter_line(&iter, fp, flags))
{
do_stuff(iter.line, iter.line_num);
}
bool mutt_file_iter_line(struct MuttFileIter *iter, FILE *fp, ReadLineFlags flags)
Iterate over the lines from an open file pointer.
Definition: file.c:801
State record for mutt_file_iter_line()
Definition: file.h:71
char * line
the line data
Definition: file.h:72
int line_num
line number
Definition: file.h:74

Definition at line 801 of file file.c.

802 {
803  if (!iter)
804  return false;
805 
806  char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
807  if (!p)
808  return false;
809  iter->line = p;
810  return true;
811 }
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:720
size_t size
allocated size of line data
Definition: file.h:73
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_map_lines()

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.

Parameters
funcCallback function to call for each line, see mutt_file_map_t
user_dataArbitrary data passed to "func"
fpFile pointer to read from
flagsSame as mutt_file_read_line()
Return values
trueAll data mapped
false"func" returns false

Definition at line 822 of file file.c.

823 {
824  if (!func || !fp)
825  return false;
826 
827  struct MuttFileIter iter = { 0 };
828  while (mutt_file_iter_line(&iter, fp, flags))
829  {
830  if (!(*func)(iter.line, iter.line_num, user_data))
831  {
832  FREE(&iter.line);
833  return false;
834  }
835  }
836  return true;
837 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_quote_filename()

size_t mutt_file_quote_filename ( const char *  filename,
char *  buf,
size_t  buflen 
)

Quote a filename to survive the shell's quoting rules.

Parameters
filenameString to convert
bufBuffer for the result
buflenLength of buffer
Return values
numBytes written to the buffer

From the Unix programming FAQ by way of Liviu.

Definition at line 848 of file file.c.

849 {
850  if (!buf)
851  return 0;
852 
853  if (!filename)
854  {
855  *buf = '\0';
856  return 0;
857  }
858 
859  size_t j = 0;
860 
861  /* leave some space for the trailing characters. */
862  buflen -= 6;
863 
864  buf[j++] = '\'';
865 
866  for (size_t i = 0; (j < buflen) && filename[i]; i++)
867  {
868  if ((filename[i] == '\'') || (filename[i] == '`'))
869  {
870  buf[j++] = '\'';
871  buf[j++] = '\\';
872  buf[j++] = filename[i];
873  buf[j++] = '\'';
874  }
875  else
876  buf[j++] = filename[i];
877  }
878 
879  buf[j++] = '\'';
880  buf[j] = '\0';
881 
882  return j;
883 }
+ Here is the caller graph for this function:

◆ mutt_buffer_quote_filename()

void mutt_buffer_quote_filename ( struct Buffer buf,
const char *  filename,
bool  add_outer 
)

Quote a filename to survive the shell's quoting rules.

Parameters
bufBuffer for the result
filenameString to convert
add_outerIf true, add 'single quotes' around the result

Definition at line 891 of file file.c.

892 {
893  if (!buf || !filename)
894  return;
895 
896  mutt_buffer_reset(buf);
897  if (add_outer)
898  mutt_buffer_addch(buf, '\'');
899 
900  for (; *filename != '\0'; filename++)
901  {
902  if ((*filename == '\'') || (*filename == '`'))
903  {
904  mutt_buffer_addch(buf, '\'');
905  mutt_buffer_addch(buf, '\\');
906  mutt_buffer_addch(buf, *filename);
907  mutt_buffer_addch(buf, '\'');
908  }
909  else
910  mutt_buffer_addch(buf, *filename);
911  }
912 
913  if (add_outer)
914  mutt_buffer_addch(buf, '\'');
915 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_mkdir()

int mutt_file_mkdir ( const char *  path,
mode_t  mode 
)

Recursively create directories.

Parameters
pathDirectories to create
modePermissions for final directory
Return values
0Success
-1Error (errno set)

Create a directory, creating the parents if necessary. (like mkdir -p)

Note
The permissions are only set on the final directory. The permissions of any parent directories are determined by the umask. (This is how "mkdir -p" behaves)

Definition at line 930 of file file.c.

931 {
932  if (!path || (*path == '\0'))
933  {
934  errno = EINVAL;
935  return -1;
936  }
937 
938  errno = 0;
939  char tmp_path[PATH_MAX];
940  const size_t len = strlen(path);
941 
942  if (len >= sizeof(tmp_path))
943  {
944  errno = ENAMETOOLONG;
945  return -1;
946  }
947 
948  struct stat st = { 0 };
949  if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
950  return 0;
951 
952  /* Create a mutable copy */
953  mutt_str_copy(tmp_path, path, sizeof(tmp_path));
954 
955  for (char *p = tmp_path + 1; *p; p++)
956  {
957  if (*p != '/')
958  continue;
959 
960  /* Temporarily truncate the path */
961  *p = '\0';
962 
963  if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
964  return -1;
965 
966  *p = '/';
967  }
968 
969  if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
970  return -1;
971 
972  return 0;
973 }
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:629
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_mkstemp_full()

FILE* mutt_file_mkstemp_full ( const char *  file,
int  line,
const char *  func 
)

Create temporary file safely.

Parameters
fileSource file of caller
lineSource line number of caller
funcFunction name of caller
Return values
ptrFILE handle
NULLError, see errno

Create and immediately unlink a temp file using mkstemp().

Definition at line 985 of file file.c.

986 {
987  char name[PATH_MAX];
988 
989  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
990  int n = snprintf(name, sizeof(name), "%s/neomutt-XXXXXX", NONULL(c_tmpdir));
991  if (n < 0)
992  return NULL;
993 
994  int fd = mkstemp(name);
995  if (fd == -1)
996  return NULL;
997 
998  FILE *fp = fdopen(fd, "w+");
999 
1000  if ((unlink(name) != 0) && (errno != ENOENT))
1001  {
1002  mutt_file_fclose(&fp);
1003  return NULL;
1004  }
1005 
1006  MuttLogger(0, file, line, func, 1, "created temp file '%s'\n", name);
1007  return fp;
1008 }
log_dispatcher_t MuttLogger
The log dispatcher -.
Definition: logging.c:52
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:

◆ mutt_file_decrease_mtime()

time_t mutt_file_decrease_mtime ( const char *  fp,
struct stat *  st 
)

Decrease a file's modification time by 1 second.

Parameters
fpFilename
ststruct stat for the file (optional)
Return values
numUpdated Unix mtime
-1Error, see errno

If a file's mtime is NOW, then set it to 1 second in the past.

Definition at line 1019 of file file.c.

1020 {
1021  if (!fp)
1022  return -1;
1023 
1024  struct utimbuf utim;
1025  struct stat st2 = { 0 };
1026  time_t mtime;
1027 
1028  if (!st)
1029  {
1030  if (stat(fp, &st2) == -1)
1031  return -1;
1032  st = &st2;
1033  }
1034 
1035  mtime = st->st_mtime;
1036  if (mtime == mutt_date_epoch())
1037  {
1038  mtime -= 1;
1039  utim.actime = mtime;
1040  utim.modtime = mtime;
1041  int rc;
1042  do
1043  {
1044  rc = utime(fp, &utim);
1045  } while ((rc == -1) && (errno == EINTR));
1046 
1047  if (rc == -1)
1048  return -1;
1049  }
1050 
1051  return mtime;
1052 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_set_mtime()

void mutt_file_set_mtime ( const char *  from,
const char *  to 
)

Set the modification time of one file from another.

Parameters
fromFilename whose mtime should be copied
toFilename to update

Definition at line 1059 of file file.c.

1060 {
1061  if (!from || !to)
1062  return;
1063 
1064  struct utimbuf utim;
1065  struct stat st = { 0 };
1066 
1067  if (stat(from, &st) != -1)
1068  {
1069  utim.actime = st.st_mtime;
1070  utim.modtime = st.st_mtime;
1071  utime(to, &utim);
1072  }
1073 }
+ Here is the caller graph for this function:

◆ mutt_file_touch_atime()

void mutt_file_touch_atime ( int  fd)

Set the access time to current time.

Parameters
fdFile descriptor of the file to alter

This is just as read() would do on !noatime. Silently ignored if futimens() isn't supported.

Definition at line 1082 of file file.c.

1083 {
1084 #ifdef HAVE_FUTIMENS
1085  struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1086  futimens(fd, times);
1087 #endif
1088 }
Time value with nanosecond precision.
Definition: file.h:49
+ Here is the caller graph for this function:

◆ mutt_file_chmod()

int mutt_file_chmod ( const char *  path,
mode_t  mode 
)

Set permissions of a file.

Parameters
pathFilename
modethe permissions to set
Return values
numSame as chmod(2)

This is essentially chmod(path, mode), see chmod(2).

Definition at line 1098 of file file.c.

1099 {
1100  if (!path)
1101  return -1;
1102 
1103  return chmod(path, mode);
1104 }

◆ mutt_file_chmod_add()

int mutt_file_chmod_add ( const char *  path,
mode_t  mode 
)

Add permissions to a file.

Parameters
pathFilename
modethe permissions to add
Return values
numSame as chmod(2)

Adds the given permissions to the file. Permissions not mentioned in mode will stay as they are. This function resembles the chmod ugoa+rwxXst command family. Example:

mutt_file_chmod_add(path, S_IWUSR | S_IWGRP | S_IWOTH);

will add write permissions to path but does not alter read and other permissions.

See also
mutt_file_chmod_add_stat()

Definition at line 1123 of file file.c.

1124 {
1125  return mutt_file_chmod_add_stat(path, mode, NULL);
1126 }
int mutt_file_chmod_add_stat(const char *path, mode_t mode, struct stat *st)
Add permissions to a file.
Definition: file.c:1146
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_chmod_add_stat()

int mutt_file_chmod_add_stat ( const char *  path,
mode_t  mode,
struct stat *  st 
)

Add permissions to a file.

Parameters
pathFilename
modethe permissions to add
ststruct stat for the file (optional)
Return values
numSame as chmod(2)

Same as mutt_file_chmod_add() but saves a system call to stat() if a non-NULL stat structure is given. Useful if the stat structure of the file was retrieved before by the calling code. Example:

struct stat st;
stat(path, &st);
// ... do something else with st ...
mutt_file_chmod_add_stat(path, S_IWUSR | S_IWGRP | S_IWOTH, st);
See also
mutt_file_chmod_add()

Definition at line 1146 of file file.c.

1147 {
1148  if (!path)
1149  return -1;
1150 
1151  struct stat st2 = { 0 };
1152 
1153  if (!st)
1154  {
1155  if (stat(path, &st2) == -1)
1156  return -1;
1157  st = &st2;
1158  }
1159  return chmod(path, st->st_mode | mode);
1160 }
+ Here is the caller graph for this function:

◆ mutt_file_chmod_rm()

int mutt_file_chmod_rm ( const char *  path,
mode_t  mode 
)

Remove permissions from a file.

Parameters
pathFilename
modethe permissions to remove
Return values
numSame as chmod(2)

Removes the given permissions from the file. Permissions not mentioned in mode will stay as they are. This function resembles the chmod ugoa-rwxXst command family. Example:

mutt_file_chmod_rm(path, S_IWUSR | S_IWGRP | S_IWOTH);

will remove write permissions from path but does not alter read and other permissions.

See also
mutt_file_chmod_rm_stat()

Definition at line 1179 of file file.c.

1180 {
1181  return mutt_file_chmod_rm_stat(path, mode, NULL);
1182 }
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
Definition: file.c:1202
+ Here is the call graph for this function:

◆ mutt_file_chmod_rm_stat()

int mutt_file_chmod_rm_stat ( const char *  path,
mode_t  mode,
struct stat *  st 
)

Remove permissions from a file.

Parameters
pathFilename
modethe permissions to remove
ststruct stat for the file (optional)
Return values
numSame as chmod(2)

Same as mutt_file_chmod_rm() but saves a system call to stat() if a non-NULL stat structure is given. Useful if the stat structure of the file was retrieved before by the calling code. Example:

struct stat st;
stat(path, &st);
// ... do something else with st ...
mutt_file_chmod_rm_stat(path, S_IWUSR | S_IWGRP | S_IWOTH, st);
See also
mutt_file_chmod_rm()

Definition at line 1202 of file file.c.

1203 {
1204  if (!path)
1205  return -1;
1206 
1207  struct stat st2 = { 0 };
1208 
1209  if (!st)
1210  {
1211  if (stat(path, &st2) == -1)
1212  return -1;
1213  st = &st2;
1214  }
1215  return chmod(path, st->st_mode & ~mode);
1216 }
+ Here is the caller graph for this function:

◆ mutt_file_lock()

int mutt_file_lock ( int  fd,
bool  excl,
bool  timeout 
)

(Try to) Lock a file using fcntl()

Parameters
fdFile descriptor to file
exclIf true, try to lock exclusively
timeoutIf true, Retry MAX_LOCK_ATTEMPTS times
Return values
0Success
-1Failure

Use fcntl() to lock a file.

Use mutt_file_unlock() to unlock the file.

Definition at line 1231 of file file.c.

1232 {
1233  struct stat st = { 0 }, prev_sb = { 0 };
1234  int count = 0;
1235  int attempt = 0;
1236 
1237  struct flock lck;
1238  memset(&lck, 0, sizeof(struct flock));
1239  lck.l_type = excl ? F_WRLCK : F_RDLCK;
1240  lck.l_whence = SEEK_SET;
1241 
1242  while (fcntl(fd, F_SETLK, &lck) == -1)
1243  {
1244  mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1245  if ((errno != EAGAIN) && (errno != EACCES))
1246  {
1247  mutt_perror("fcntl");
1248  return -1;
1249  }
1250 
1251  if (fstat(fd, &st) != 0)
1252  st.st_size = 0;
1253 
1254  if (count == 0)
1255  prev_sb = st;
1256 
1257  /* only unlock file if it is unchanged */
1258  if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1259  {
1260  if (timeout)
1261  mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1262  return -1;
1263  }
1264 
1265  prev_sb = st;
1266 
1267  mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1268  sleep(1);
1269  }
1270 
1271  return 0;
1272 }
#define MAX_LOCK_ATTEMPTS
Definition: file.c:63
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
+ Here is the caller graph for this function:

◆ mutt_file_unlock()

int mutt_file_unlock ( int  fd)

Unlock a file previously locked by mutt_file_lock()

Parameters
fdFile descriptor to file
Return values
0Always

Definition at line 1279 of file file.c.

1280 {
1281  struct flock unlockit;
1282 
1283  memset(&unlockit, 0, sizeof(struct flock));
1284  unlockit.l_type = F_UNLCK;
1285  unlockit.l_whence = SEEK_SET;
1286  (void) fcntl(fd, F_SETLK, &unlockit);
1287 
1288  return 0;
1289 }
+ Here is the caller graph for this function:

◆ mutt_file_unlink_empty()

void mutt_file_unlink_empty ( const char *  path)

Delete a file if it's empty.

Parameters
pathFile to delete

Definition at line 1367 of file file.c.

1368 {
1369  if (!path)
1370  return;
1371 
1372  struct stat st = { 0 };
1373 
1374  int fd = open(path, O_RDWR);
1375  if (fd == -1)
1376  return;
1377 
1378  if (mutt_file_lock(fd, true, true) == -1)
1379  {
1380  close(fd);
1381  return;
1382  }
1383 
1384  if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1385  unlink(path);
1386 
1387  mutt_file_unlock(fd);
1388  close(fd);
1389 }
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1231
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1279
+ Here is the call graph for this function:

◆ mutt_file_rename()

int mutt_file_rename ( const char *  oldfile,
const char *  newfile 
)

Rename a file.

Parameters
oldfileOld filename
newfileNew filename
Return values
0Success
1Old file doesn't exist
2New file already exists
3Some other error
Note
on access(2) use No dangling symlink problems here due to mutt_file_fopen().

Definition at line 1403 of file file.c.

1404 {
1405  if (!oldfile || !newfile)
1406  return -1;
1407  if (access(oldfile, F_OK) != 0)
1408  return 1;
1409  if (access(newfile, F_OK) == 0)
1410  return 2;
1411 
1412  FILE *fp_old = fopen(oldfile, "r");
1413  if (!fp_old)
1414  return 3;
1415  FILE *fp_new = mutt_file_fopen(newfile, "w");
1416  if (!fp_new)
1417  {
1418  mutt_file_fclose(&fp_old);
1419  return 3;
1420  }
1421  mutt_file_copy_stream(fp_old, fp_new);
1422  mutt_file_fclose(&fp_new);
1423  mutt_file_fclose(&fp_old);
1424  mutt_file_unlink(oldfile);
1425  return 0;
1426 }
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:260
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_read_keyword()

char* mutt_file_read_keyword ( const char *  file,
char *  buf,
size_t  buflen 
)

Read a keyword from a file.

Parameters
fileFile to read
bufBuffer to store the keyword
buflenLength of the buf
Return values
ptrStart of the keyword

Read one line from the start of a file. Skip any leading whitespace and extract the first token.

Definition at line 1438 of file file.c.

1439 {
1440  FILE *fp = mutt_file_fopen(file, "r");
1441  if (!fp)
1442  return NULL;
1443 
1444  buf = fgets(buf, buflen, fp);
1445  mutt_file_fclose(&fp);
1446 
1447  if (!buf)
1448  return NULL;
1449 
1450  SKIPWS(buf);
1451  char *start = buf;
1452 
1453  while ((*buf != '\0') && !isspace(*buf))
1454  buf++;
1455 
1456  *buf = '\0';
1457 
1458  return start;
1459 }
#define SKIPWS(ch)
Definition: string2.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_check_empty()

int mutt_file_check_empty ( const char *  path)

Is the mailbox empty.

Parameters
pathPath to mailbox
Return values
1Mailbox is empty
0Mailbox is not empty
-1Error

Definition at line 1468 of file file.c.

1469 {
1470  if (!path)
1471  return -1;
1472 
1473  struct stat st = { 0 };
1474  if (stat(path, &st) == -1)
1475  return -1;
1476 
1477  return st.st_size == 0;
1478 }
+ Here is the caller graph for this function:

◆ mutt_buffer_file_expand_fmt_quote()

void mutt_buffer_file_expand_fmt_quote ( struct Buffer dest,
const char *  fmt,
const char *  src 
)

Replace s in a string with a filename.

Parameters
destBuffer for the result
fmtprintf-like format string
srcFilename to substitute

This function also quotes the file to prevent shell problems.

Definition at line 1488 of file file.c.

1489 {
1490  struct Buffer tmp = mutt_buffer_make(PATH_MAX);
1491 
1492  mutt_buffer_quote_filename(&tmp, src, true);
1493  mutt_file_expand_fmt(dest, fmt, mutt_buffer_string(&tmp));
1494  mutt_buffer_dealloc(&tmp);
1495 }
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:891
void mutt_file_expand_fmt(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1503
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_expand_fmt()

void mutt_file_expand_fmt ( struct Buffer dest,
const char *  fmt,
const char *  src 
)

Replace s in a string with a filename.

Parameters
destBuffer for the result
fmtprintf-like format string
srcFilename to substitute

Definition at line 1503 of file file.c.

1504 {
1505  if (!dest || !fmt || !src)
1506  return;
1507 
1508  const char *p = NULL;
1509  bool found = false;
1510 
1511  mutt_buffer_reset(dest);
1512 
1513  for (p = fmt; *p; p++)
1514  {
1515  if (*p == '%')
1516  {
1517  switch (p[1])
1518  {
1519  case '%':
1520  mutt_buffer_addch(dest, *p++);
1521  break;
1522  case 's':
1523  found = true;
1524  mutt_buffer_addstr(dest, src);
1525  p++;
1526  break;
1527  default:
1528  mutt_buffer_addch(dest, *p);
1529  break;
1530  }
1531  }
1532  else
1533  {
1534  mutt_buffer_addch(dest, *p);
1535  }
1536  }
1537 
1538  if (!found)
1539  {
1540  mutt_buffer_addch(dest, ' ');
1541  mutt_buffer_addstr(dest, src);
1542  }
1543 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_get_size()

long mutt_file_get_size ( const char *  path)

Get the size of a file.

Parameters
pathFile to measure
Return values
numSize in bytes
0Error

Definition at line 1551 of file file.c.

1552 {
1553  if (!path)
1554  return 0;
1555 
1556  struct stat st = { 0 };
1557  if (stat(path, &st) != 0)
1558  return 0;
1559 
1560  return st.st_size;
1561 }
+ Here is the caller graph for this function:

◆ mutt_file_get_size_fp()

long mutt_file_get_size_fp ( FILE *  fp)

Get the size of a file.

Parameters
fpFILE* to measure
Return values
numSize in bytes
0Error

Definition at line 1569 of file file.c.

1570 {
1571  if (!fp)
1572  return 0;
1573 
1574  struct stat st = { 0 };
1575  if (fstat(fileno(fp), &st) != 0)
1576  return 0;
1577 
1578  return st.st_size;
1579 }
+ Here is the caller graph for this function:

◆ mutt_file_timespec_compare()

int mutt_file_timespec_compare ( struct timespec a,
struct timespec b 
)

Compare to time values.

Parameters
aFirst time value
bSecond time value
Return values
-1a precedes b
0a and b are identical
1b precedes a

Definition at line 1589 of file file.c.

1590 {
1591  if (!a || !b)
1592  return 0;
1593  if (a->tv_sec < b->tv_sec)
1594  return -1;
1595  if (a->tv_sec > b->tv_sec)
1596  return 1;
1597 
1598  if (a->tv_nsec < b->tv_nsec)
1599  return -1;
1600  if (a->tv_nsec > b->tv_nsec)
1601  return 1;
1602  return 0;
1603 }
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:51
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:50
+ Here is the caller graph for this function:

◆ mutt_file_get_stat_timespec()

void mutt_file_get_stat_timespec ( struct timespec dest,
struct stat *  st,
enum MuttStatType  type 
)

Read the stat() time into a time value.

Parameters
destTime value to populate
ststat info
typeType of stat info to read, e.g. MUTT_STAT_ATIME

Definition at line 1611 of file file.c.

1612 {
1613  if (!dest || !st)
1614  return;
1615 
1616  dest->tv_sec = 0;
1617  dest->tv_nsec = 0;
1618 
1619  switch (type)
1620  {
1621  case MUTT_STAT_ATIME:
1622  dest->tv_sec = st->st_atime;
1623 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1624  dest->tv_nsec = st->st_atim.tv_nsec;
1625 #endif
1626  break;
1627  case MUTT_STAT_MTIME:
1628  dest->tv_sec = st->st_mtime;
1629 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1630  dest->tv_nsec = st->st_mtim.tv_nsec;
1631 #endif
1632  break;
1633  case MUTT_STAT_CTIME:
1634  dest->tv_sec = st->st_ctime;
1635 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1636  dest->tv_nsec = st->st_ctim.tv_nsec;
1637 #endif
1638  break;
1639  }
1640 }
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:64
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition: file.h:62
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:63
+ Here is the caller graph for this function:

◆ mutt_file_stat_timespec_compare()

int mutt_file_stat_timespec_compare ( struct stat *  st,
enum MuttStatType  type,
struct timespec b 
)

Compare stat info with a time value.

Parameters
ststat info
typeType of stat info, e.g. MUTT_STAT_ATIME
bTime value
Return values
-1a precedes b
0a and b are identical
1b precedes a

Definition at line 1651 of file file.c.

1653 {
1654  if (!st || !b)
1655  return 0;
1656 
1657  struct timespec a = { 0 };
1658 
1659  mutt_file_get_stat_timespec(&a, st, type);
1660  return mutt_file_timespec_compare(&a, b);
1661 }
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *st, enum MuttStatType type)
Read the stat() time into a time value.
Definition: file.c:1611
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1589
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_stat_compare()

int mutt_file_stat_compare ( struct stat *  st1,
enum MuttStatType  st1_type,
struct stat *  st2,
enum MuttStatType  st2_type 
)

Compare two stat infos.

Parameters
st1First stat info
st1_typeType of first stat info, e.g. MUTT_STAT_ATIME
st2Second stat info
st2_typeType of second stat info, e.g. MUTT_STAT_ATIME
Return values
-1a precedes b
0a and b are identical
1b precedes a

Definition at line 1673 of file file.c.

1675 {
1676  if (!st1 || !st2)
1677  return 0;
1678 
1679  struct timespec a = { 0 };
1680  struct timespec b = { 0 };
1681 
1682  mutt_file_get_stat_timespec(&a, st1, st1_type);
1683  mutt_file_get_stat_timespec(&b, st2, st2_type);
1684  return mutt_file_timespec_compare(&a, &b);
1685 }
+ Here is the call graph for this function:

◆ mutt_file_resolve_symlink()

void mutt_file_resolve_symlink ( struct Buffer buf)

Resolve a symlink in place.

Parameters
bufInput/output path

Definition at line 1691 of file file.c.

1692 {
1693  struct stat st = { 0 };
1694  int rc = lstat(mutt_buffer_string(buf), &st);
1695  if ((rc != -1) && S_ISLNK(st.st_mode))
1696  {
1697  char path[PATH_MAX];
1698  if (realpath(mutt_buffer_string(buf), path))
1699  {
1700  mutt_buffer_strcpy(buf, path);
1701  }
1702  }
1703 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ rx_special_chars

const char rx_special_chars[] = "^.[$()|*+?{\\"
static

Definition at line 59 of file file.c.

◆ filename_safe_chars

const char filename_safe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"

Definition at line 61 of file file.c.