NeoMutt  2021-10-22-8-g9cb437
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 <time.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 "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...
 
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...
 
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 []
 

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 64 of file file.c.

◆ O_NOFOLLOW

#define O_NOFOLLOW   0

Definition at line 68 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 80 of file file.c.

81 {
82  return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
83  (st_old->st_rdev == st_new->st_rdev);
84 }
+ 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 94 of file file.c.

95 {
96  const char *basename = NULL;
97  int rc = 0;
98 
99  struct Buffer parent = mutt_buffer_make(PATH_MAX);
100  mutt_buffer_strcpy(&parent, NONULL(path));
101 
102  char *p = strrchr(parent.data, '/');
103  if (p)
104  {
105  *p = '\0';
106  basename = p + 1;
107  }
108  else
109  {
110  mutt_buffer_strcpy(&parent, ".");
111  basename = path;
112  }
113 
114  mutt_buffer_printf(newdir, "%s/%s", mutt_buffer_string(&parent), ".muttXXXXXX");
115  if (!mkdtemp(newdir->data))
116  {
117  mutt_debug(LL_DEBUG1, "mkdtemp() failed\n");
118  rc = -1;
119  goto cleanup;
120  }
121 
122  mutt_buffer_printf(newfile, "%s/%s", newdir->data, NONULL(basename));
123 
124 cleanup:
125  mutt_buffer_dealloc(&parent);
126  return rc;
127 }
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 137 of file file.c.

138 {
139  int rc;
140 
141  rc = mutt_file_safe_rename(safe_file, path);
142  unlink(safe_file);
143  rmdir(safe_dir);
144  return rc;
145 }
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:355
+ 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 153 of file file.c.

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

◆ 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 169 of file file.c.

170 {
171  if (!fp || !*fp)
172  return 0;
173 
174  int rc = 0;
175 
176  if (fflush(*fp) || fsync(fileno(*fp)))
177  {
178  int save_errno = errno;
179  rc = -1;
180  mutt_file_fclose(fp);
181  errno = save_errno;
182  }
183  else
184  rc = mutt_file_fclose(fp);
185 
186  return rc;
187 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
+ 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 195 of file file.c.

196 {
197  if (!s)
198  return;
199 
200  struct stat st = { 0 };
201  /* Defend against symlink attacks */
202 
203  const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
204  if (!is_regular_file)
205  return;
206 
207  const int fd = open(s, O_RDWR | O_NOFOLLOW);
208  if (fd < 0)
209  return;
210 
211  struct stat st2 = { 0 };
212  if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
213  (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
214  {
215  close(fd);
216  return;
217  }
218 
219  FILE *fp = fdopen(fd, "r+");
220  if (fp)
221  {
222  unlink(s);
223  char buf[2048] = { 0 };
224  while (st.st_size > 0)
225  {
226  fwrite(buf, 1, MIN(sizeof(buf), st.st_size), fp);
227  st.st_size -= MIN(sizeof(buf), st.st_size);
228  }
229  mutt_file_fclose(&fp);
230  }
231 }
#define O_NOFOLLOW
Definition: file.c:68
#define MIN(a, b)
Definition: memory.h:31
+ Here is the call graph for this function:
+ 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 241 of file file.c.

242 {
243  if (!fp_in || !fp_out)
244  return -1;
245 
246  while (size > 0)
247  {
248  char buf[2048];
249  size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size;
250  chunk = fread(buf, 1, chunk, fp_in);
251  if (chunk < 1)
252  break;
253  if (fwrite(buf, 1, chunk, fp_out) != chunk)
254  return -1;
255 
256  size -= chunk;
257  }
258 
259  if (fflush(fp_out) != 0)
260  return -1;
261  return 0;
262 }
+ 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 271 of file file.c.

272 {
273  if (!fp_in || !fp_out)
274  return -1;
275 
276  size_t total = 0;
277  size_t l;
278  char buf[1024];
279 
280  while ((l = fread(buf, 1, sizeof(buf), fp_in)) > 0)
281  {
282  if (fwrite(buf, 1, l, fp_out) != l)
283  return -1;
284  total += l;
285  }
286 
287  if (fflush(fp_out) != 0)
288  return -1;
289  return total;
290 }
+ 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 299 of file file.c.

300 {
301  struct stat st_old = { 0 };
302  struct stat st_new = { 0 };
303 
304  if (!oldpath || !newpath)
305  return -1;
306 
307  if ((unlink(newpath) == -1) && (errno != ENOENT))
308  return -1;
309 
310  if (oldpath[0] == '/')
311  {
312  if (symlink(oldpath, newpath) == -1)
313  return -1;
314  }
315  else
316  {
317  struct Buffer abs_oldpath = mutt_buffer_make(PATH_MAX);
318 
319  if (!mutt_path_getcwd(&abs_oldpath))
320  {
321  mutt_buffer_dealloc(&abs_oldpath);
322  return -1;
323  }
324 
325  mutt_buffer_addch(&abs_oldpath, '/');
326  mutt_buffer_addstr(&abs_oldpath, oldpath);
327  if (symlink(mutt_buffer_string(&abs_oldpath), newpath) == -1)
328  {
329  mutt_buffer_dealloc(&abs_oldpath);
330  return -1;
331  }
332 
333  mutt_buffer_dealloc(&abs_oldpath);
334  }
335 
336  if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
337  !compare_stat(&st_old, &st_new))
338  {
339  unlink(newpath);
340  return -1;
341  }
342 
343  return 0;
344 }
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:80
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 355 of file file.c.

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

471 {
472  if (!path)
473  return -1;
474 
475  struct dirent *de = NULL;
476  struct stat st = { 0 };
477  int rc = 0;
478 
479  DIR *dirp = opendir(path);
480  if (!dirp)
481  {
482  mutt_debug(LL_DEBUG1, "error opening directory %s\n", path);
483  return -1;
484  }
485 
486  /* We avoid using the buffer pool for this function, because it
487  * invokes recursively to an unknown depth. */
488  struct Buffer cur = mutt_buffer_make(PATH_MAX);
489 
490  while ((de = readdir(dirp)))
491  {
492  if ((strcmp(".", de->d_name) == 0) || (strcmp("..", de->d_name) == 0))
493  continue;
494 
495  mutt_buffer_printf(&cur, "%s/%s", path, de->d_name);
496  /* XXX make nonrecursive version */
497 
498  if (stat(mutt_buffer_string(&cur), &st) == -1)
499  {
500  rc = 1;
501  continue;
502  }
503 
504  if (S_ISDIR(st.st_mode))
506  else
507  rc |= unlink(mutt_buffer_string(&cur));
508  }
509  closedir(dirp);
510 
511  rc |= rmdir(path);
512 
513  mutt_buffer_dealloc(&cur);
514  return rc;
515 }
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:470
+ 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 524 of file file.c.

525 {
526  if (!path)
527  return -1;
528 
529  int fd;
530  struct Buffer safe_file = mutt_buffer_make(0);
531  struct Buffer safe_dir = mutt_buffer_make(0);
532 
533  if (flags & O_EXCL)
534  {
535  mutt_buffer_alloc(&safe_file, PATH_MAX);
536  mutt_buffer_alloc(&safe_dir, PATH_MAX);
537 
538  if (mkwrapdir(path, &safe_file, &safe_dir) == -1)
539  {
540  fd = -1;
541  goto cleanup;
542  }
543 
544  fd = open(mutt_buffer_string(&safe_file), flags, 0600);
545  if (fd < 0)
546  {
547  rmdir(mutt_buffer_string(&safe_dir));
548  goto cleanup;
549  }
550 
551  /* NFS and I believe cygwin do not handle movement of open files well */
552  close(fd);
553  if (put_file_in_place(path, mutt_buffer_string(&safe_file),
554  mutt_buffer_string(&safe_dir)) == -1)
555  {
556  fd = -1;
557  goto cleanup;
558  }
559  }
560 
561  fd = open(path, flags & ~O_EXCL, 0600);
562  if (fd < 0)
563  goto cleanup;
564 
565  /* make sure the file is not symlink */
566  struct stat st_old = { 0 };
567  struct stat st_new = { 0 };
568  if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
569  !compare_stat(&st_old, &st_new))
570  {
571  close(fd);
572  fd = -1;
573  goto cleanup;
574  }
575 
576 cleanup:
577  mutt_buffer_dealloc(&safe_file);
578  mutt_buffer_dealloc(&safe_dir);
579 
580  return fd;
581 }
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:137
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
Definition: file.c:94
+ 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 593 of file file.c.

594 {
595  if (!path || !mode)
596  return NULL;
597 
598  if (mode[0] == 'w')
599  {
600  uint32_t flags = O_CREAT | O_EXCL | O_NOFOLLOW;
601 
602  if (mode[1] == '+')
603  flags |= O_RDWR;
604  else
605  flags |= O_WRONLY;
606 
607  int fd = mutt_file_open(path, flags);
608  if (fd < 0)
609  return NULL;
610 
611  return fdopen(fd, mode);
612  }
613  else
614  return fopen(path, mode);
615 }
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:524
+ 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 622 of file file.c.

623 {
624  if (!path)
625  return;
626 
627  for (; *path; path++)
628  {
629  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
630  *path = '_';
631  }
632 }
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 641 of file file.c.

642 {
643  if (!dest || !src)
644  return -1;
645 
646  mutt_buffer_reset(dest);
647  while (*src != '\0')
648  {
649  if (strchr(rx_special_chars, *src))
650  mutt_buffer_addch(dest, '\\');
651  mutt_buffer_addch(dest, *src++);
652  }
653 
654  return 0;
655 }
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_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 671 of file file.c.

672 {
673  if (!size || !fp)
674  return NULL;
675 
676  size_t offset = 0;
677  char *ch = NULL;
678 
679  if (!line)
680  {
681  *size = 256;
682  line = mutt_mem_malloc(*size);
683  }
684 
685  while (true)
686  {
687  if (!fgets(line + offset, *size - offset, fp))
688  {
689  FREE(&line);
690  return NULL;
691  }
692  ch = strchr(line + offset, '\n');
693  if (ch)
694  {
695  if (line_num)
696  (*line_num)++;
697  if (flags & MUTT_RL_EOL)
698  return line;
699  *ch = '\0';
700  if ((ch > line) && (*(ch - 1) == '\r'))
701  *--ch = '\0';
702  if (!(flags & MUTT_RL_CONT) || (ch == line) || (*(ch - 1) != '\\'))
703  return line;
704  offset = ch - line - 1;
705  }
706  else
707  {
708  int c;
709  c = getc(fp); /* This is kind of a hack. We want to know if the
710  char at the current point in the input stream is EOF.
711  feof() will only tell us if we've already hit EOF, not
712  if the next character is EOF. So, we need to read in
713  the next character and manually check if it is EOF. */
714  if (c == EOF)
715  {
716  /* The last line of fp isn't \n terminated */
717  if (line_num)
718  (*line_num)++;
719  return line;
720  }
721  else
722  {
723  ungetc(c, fp); /* undo our damage */
724  /* There wasn't room for the line -- increase "line" */
725  offset = *size - 1; /* overwrite the terminating 0 */
726  *size += 256;
727  mutt_mem_realloc(&line, *size);
728  }
729  }
730  }
731 }
#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:752
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 752 of file file.c.

753 {
754  if (!iter)
755  return false;
756 
757  char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
758  if (!p)
759  return false;
760  iter->line = p;
761  return true;
762 }
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:671
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 773 of file file.c.

774 {
775  if (!func || !fp)
776  return false;
777 
778  struct MuttFileIter iter = { 0 };
779  while (mutt_file_iter_line(&iter, fp, flags))
780  {
781  if (!(*func)(iter.line, iter.line_num, user_data))
782  {
783  FREE(&iter.line);
784  return false;
785  }
786  }
787  return true;
788 }
+ 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 799 of file file.c.

800 {
801  if (!buf)
802  return 0;
803 
804  if (!filename)
805  {
806  *buf = '\0';
807  return 0;
808  }
809 
810  size_t j = 0;
811 
812  /* leave some space for the trailing characters. */
813  buflen -= 6;
814 
815  buf[j++] = '\'';
816 
817  for (size_t i = 0; (j < buflen) && filename[i]; i++)
818  {
819  if ((filename[i] == '\'') || (filename[i] == '`'))
820  {
821  buf[j++] = '\'';
822  buf[j++] = '\\';
823  buf[j++] = filename[i];
824  buf[j++] = '\'';
825  }
826  else
827  buf[j++] = filename[i];
828  }
829 
830  buf[j++] = '\'';
831  buf[j] = '\0';
832 
833  return j;
834 }
+ 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 842 of file file.c.

843 {
844  if (!buf || !filename)
845  return;
846 
847  mutt_buffer_reset(buf);
848  if (add_outer)
849  mutt_buffer_addch(buf, '\'');
850 
851  for (; *filename != '\0'; filename++)
852  {
853  if ((*filename == '\'') || (*filename == '`'))
854  {
855  mutt_buffer_addch(buf, '\'');
856  mutt_buffer_addch(buf, '\\');
857  mutt_buffer_addch(buf, *filename);
858  mutt_buffer_addch(buf, '\'');
859  }
860  else
861  mutt_buffer_addch(buf, *filename);
862  }
863 
864  if (add_outer)
865  mutt_buffer_addch(buf, '\'');
866 }
+ 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 881 of file file.c.

882 {
883  if (!path || (*path == '\0'))
884  {
885  errno = EINVAL;
886  return -1;
887  }
888 
889  errno = 0;
890  char tmp_path[PATH_MAX];
891  const size_t len = strlen(path);
892 
893  if (len >= sizeof(tmp_path))
894  {
895  errno = ENAMETOOLONG;
896  return -1;
897  }
898 
899  struct stat st = { 0 };
900  if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
901  return 0;
902 
903  /* Create a mutable copy */
904  mutt_str_copy(tmp_path, path, sizeof(tmp_path));
905 
906  for (char *p = tmp_path + 1; *p; p++)
907  {
908  if (*p != '/')
909  continue;
910 
911  /* Temporarily truncate the path */
912  *p = '\0';
913 
914  if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
915  return -1;
916 
917  *p = '/';
918  }
919 
920  if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
921  return -1;
922 
923  return 0;
924 }
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:749
+ 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 936 of file file.c.

937 {
938  char name[PATH_MAX];
939 
940  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
941  int n = snprintf(name, sizeof(name), "%s/neomutt-XXXXXX", NONULL(c_tmpdir));
942  if (n < 0)
943  return NULL;
944 
945  int fd = mkstemp(name);
946  if (fd == -1)
947  return NULL;
948 
949  FILE *fp = fdopen(fd, "w+");
950 
951  if ((unlink(name) != 0) && (errno != ENOENT))
952  {
953  mutt_file_fclose(&fp);
954  return NULL;
955  }
956 
957  MuttLogger(0, file, line, func, 1, "created temp file '%s'\n", name);
958  return fp;
959 }
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 970 of file file.c.

971 {
972  if (!fp)
973  return -1;
974 
975  struct utimbuf utim;
976  struct stat st2 = { 0 };
977  time_t mtime;
978 
979  if (!st)
980  {
981  if (stat(fp, &st2) == -1)
982  return -1;
983  st = &st2;
984  }
985 
986  mtime = st->st_mtime;
987  if (mtime == mutt_date_epoch())
988  {
989  mtime -= 1;
990  utim.actime = mtime;
991  utim.modtime = mtime;
992  int rc;
993  do
994  {
995  rc = utime(fp, &utim);
996  } while ((rc == -1) && (errno == EINTR));
997 
998  if (rc == -1)
999  return -1;
1000  }
1001 
1002  return mtime;
1003 }
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 1010 of file file.c.

1011 {
1012  if (!from || !to)
1013  return;
1014 
1015  struct utimbuf utim;
1016  struct stat st = { 0 };
1017 
1018  if (stat(from, &st) != -1)
1019  {
1020  utim.actime = st.st_mtime;
1021  utim.modtime = st.st_mtime;
1022  utime(to, &utim);
1023  }
1024 }
+ 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 1033 of file file.c.

1034 {
1035 #ifdef HAVE_FUTIMENS
1036  struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1037  futimens(fd, times);
1038 #endif
1039 }
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 1049 of file file.c.

1050 {
1051  if (!path)
1052  return -1;
1053 
1054  return chmod(path, mode);
1055 }

◆ 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 1074 of file file.c.

1075 {
1076  return mutt_file_chmod_add_stat(path, mode, NULL);
1077 }
int mutt_file_chmod_add_stat(const char *path, mode_t mode, struct stat *st)
Add permissions to a file.
Definition: file.c:1097
+ 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 1097 of file file.c.

1098 {
1099  if (!path)
1100  return -1;
1101 
1102  struct stat st2 = { 0 };
1103 
1104  if (!st)
1105  {
1106  if (stat(path, &st2) == -1)
1107  return -1;
1108  st = &st2;
1109  }
1110  return chmod(path, st->st_mode | mode);
1111 }
+ 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 1130 of file file.c.

1131 {
1132  return mutt_file_chmod_rm_stat(path, mode, NULL);
1133 }
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
Definition: file.c:1153
+ 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 1153 of file file.c.

1154 {
1155  if (!path)
1156  return -1;
1157 
1158  struct stat st2 = { 0 };
1159 
1160  if (!st)
1161  {
1162  if (stat(path, &st2) == -1)
1163  return -1;
1164  st = &st2;
1165  }
1166  return chmod(path, st->st_mode & ~mode);
1167 }
+ 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 1182 of file file.c.

1183 {
1184  struct stat st = { 0 }, prev_sb = { 0 };
1185  int count = 0;
1186  int attempt = 0;
1187 
1188  struct flock lck;
1189  memset(&lck, 0, sizeof(struct flock));
1190  lck.l_type = excl ? F_WRLCK : F_RDLCK;
1191  lck.l_whence = SEEK_SET;
1192 
1193  while (fcntl(fd, F_SETLK, &lck) == -1)
1194  {
1195  mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1196  if ((errno != EAGAIN) && (errno != EACCES))
1197  {
1198  mutt_perror("fcntl");
1199  return -1;
1200  }
1201 
1202  if (fstat(fd, &st) != 0)
1203  st.st_size = 0;
1204 
1205  if (count == 0)
1206  prev_sb = st;
1207 
1208  /* only unlock file if it is unchanged */
1209  if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1210  {
1211  if (timeout)
1212  mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1213  return -1;
1214  }
1215 
1216  prev_sb = st;
1217 
1218  mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1219  sleep(1);
1220  }
1221 
1222  return 0;
1223 }
#define MAX_LOCK_ATTEMPTS
Definition: file.c:64
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_perror(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
+ 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 1230 of file file.c.

1231 {
1232  struct flock unlockit;
1233 
1234  memset(&unlockit, 0, sizeof(struct flock));
1235  unlockit.l_type = F_UNLCK;
1236  unlockit.l_whence = SEEK_SET;
1237  (void) fcntl(fd, F_SETLK, &unlockit);
1238 
1239  return 0;
1240 }
+ 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 1318 of file file.c.

1319 {
1320  if (!path)
1321  return;
1322 
1323  struct stat st = { 0 };
1324 
1325  int fd = open(path, O_RDWR);
1326  if (fd == -1)
1327  return;
1328 
1329  if (mutt_file_lock(fd, true, true) == -1)
1330  {
1331  close(fd);
1332  return;
1333  }
1334 
1335  if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1336  unlink(path);
1337 
1338  mutt_file_unlock(fd);
1339  close(fd);
1340 }
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1182
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1230
+ 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 1354 of file file.c.

1355 {
1356  if (!oldfile || !newfile)
1357  return -1;
1358  if (access(oldfile, F_OK) != 0)
1359  return 1;
1360  if (access(newfile, F_OK) == 0)
1361  return 2;
1362 
1363  FILE *fp_old = fopen(oldfile, "r");
1364  if (!fp_old)
1365  return 3;
1366  FILE *fp_new = mutt_file_fopen(newfile, "w");
1367  if (!fp_new)
1368  {
1369  mutt_file_fclose(&fp_old);
1370  return 3;
1371  }
1372  mutt_file_copy_stream(fp_old, fp_new);
1373  mutt_file_fclose(&fp_new);
1374  mutt_file_fclose(&fp_old);
1375  mutt_file_unlink(oldfile);
1376  return 0;
1377 }
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
+ 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 1389 of file file.c.

1390 {
1391  FILE *fp = mutt_file_fopen(file, "r");
1392  if (!fp)
1393  return NULL;
1394 
1395  buf = fgets(buf, buflen, fp);
1396  mutt_file_fclose(&fp);
1397 
1398  if (!buf)
1399  return NULL;
1400 
1401  SKIPWS(buf);
1402  char *start = buf;
1403 
1404  while ((*buf != '\0') && !isspace(*buf))
1405  buf++;
1406 
1407  *buf = '\0';
1408 
1409  return start;
1410 }
#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 1419 of file file.c.

1420 {
1421  if (!path)
1422  return -1;
1423 
1424  struct stat st = { 0 };
1425  if (stat(path, &st) == -1)
1426  return -1;
1427 
1428  return st.st_size == 0;
1429 }
+ 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 1439 of file file.c.

1440 {
1441  struct Buffer tmp = mutt_buffer_make(PATH_MAX);
1442 
1443  mutt_buffer_quote_filename(&tmp, src, true);
1444  mutt_file_expand_fmt(dest, fmt, mutt_buffer_string(&tmp));
1445  mutt_buffer_dealloc(&tmp);
1446 }
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:842
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:1454
+ 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 1454 of file file.c.

1455 {
1456  if (!dest || !fmt || !src)
1457  return;
1458 
1459  const char *p = NULL;
1460  bool found = false;
1461 
1462  mutt_buffer_reset(dest);
1463 
1464  for (p = fmt; *p; p++)
1465  {
1466  if (*p == '%')
1467  {
1468  switch (p[1])
1469  {
1470  case '%':
1471  mutt_buffer_addch(dest, *p++);
1472  break;
1473  case 's':
1474  found = true;
1475  mutt_buffer_addstr(dest, src);
1476  p++;
1477  break;
1478  default:
1479  mutt_buffer_addch(dest, *p);
1480  break;
1481  }
1482  }
1483  else
1484  {
1485  mutt_buffer_addch(dest, *p);
1486  }
1487  }
1488 
1489  if (!found)
1490  {
1491  mutt_buffer_addch(dest, ' ');
1492  mutt_buffer_addstr(dest, src);
1493  }
1494 }
+ 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 1502 of file file.c.

1503 {
1504  if (!path)
1505  return 0;
1506 
1507  struct stat st = { 0 };
1508  if (stat(path, &st) != 0)
1509  return 0;
1510 
1511  return st.st_size;
1512 }
+ 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 1520 of file file.c.

1521 {
1522  if (!fp)
1523  return 0;
1524 
1525  struct stat st = { 0 };
1526  if (fstat(fileno(fp), &st) != 0)
1527  return 0;
1528 
1529  return st.st_size;
1530 }
+ 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 1540 of file file.c.

1541 {
1542  if (!a || !b)
1543  return 0;
1544  if (a->tv_sec < b->tv_sec)
1545  return -1;
1546  if (a->tv_sec > b->tv_sec)
1547  return 1;
1548 
1549  if (a->tv_nsec < b->tv_nsec)
1550  return -1;
1551  if (a->tv_nsec > b->tv_nsec)
1552  return 1;
1553  return 0;
1554 }
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 1562 of file file.c.

1563 {
1564  if (!dest || !st)
1565  return;
1566 
1567  dest->tv_sec = 0;
1568  dest->tv_nsec = 0;
1569 
1570  switch (type)
1571  {
1572  case MUTT_STAT_ATIME:
1573  dest->tv_sec = st->st_atime;
1574 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1575  dest->tv_nsec = st->st_atim.tv_nsec;
1576 #endif
1577  break;
1578  case MUTT_STAT_MTIME:
1579  dest->tv_sec = st->st_mtime;
1580 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1581  dest->tv_nsec = st->st_mtim.tv_nsec;
1582 #endif
1583  break;
1584  case MUTT_STAT_CTIME:
1585  dest->tv_sec = st->st_ctime;
1586 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1587  dest->tv_nsec = st->st_ctim.tv_nsec;
1588 #endif
1589  break;
1590  }
1591 }
@ 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 1602 of file file.c.

1604 {
1605  if (!st || !b)
1606  return 0;
1607 
1608  struct timespec a = { 0 };
1609 
1610  mutt_file_get_stat_timespec(&a, st, type);
1611  return mutt_file_timespec_compare(&a, b);
1612 }
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:1562
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1540
+ 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 1624 of file file.c.

1626 {
1627  if (!st1 || !st2)
1628  return 0;
1629 
1630  struct timespec a = { 0 };
1631  struct timespec b = { 0 };
1632 
1633  mutt_file_get_stat_timespec(&a, st1, st1_type);
1634  mutt_file_get_stat_timespec(&b, st2, st2_type);
1635  return mutt_file_timespec_compare(&a, &b);
1636 }
+ 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 1642 of file file.c.

1643 {
1644  struct stat st = { 0 };
1645  int rc = lstat(mutt_buffer_string(buf), &st);
1646  if ((rc != -1) && S_ISLNK(st.st_mode))
1647  {
1648  char path[PATH_MAX];
1649  if (realpath(mutt_buffer_string(buf), path))
1650  {
1651  mutt_buffer_strcpy(buf, path);
1652  }
1653  }
1654 }
+ 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[]
Initial value:
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"

Definition at line 61 of file file.c.