NeoMutt  2019-12-07
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 "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 *osb, struct stat *nsb)
 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, int 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, int flags)
 Read a line from a file. More...
 
bool mutt_file_iter_line (struct MuttFileIter *iter, FILE *fp, int 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, int 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...
 
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...
 
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 *sb, enum MuttStatType type)
 Read the stat() time into a time value. More...
 
int mutt_file_stat_timespec_compare (struct stat *sba, enum MuttStatType type, struct timespec *b)
 Compare stat info with a time value. More...
 
int mutt_file_stat_compare (struct stat *sba, enum MuttStatType sba_type, struct stat *sbb, enum MuttStatType sbb_type)
 Compare two stat infos. More...
 

Variables

char * C_Tmpdir
 Config: Directory for temporary files. More...
 
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 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 *  osb,
struct stat *  nsb 
)
static

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

Parameters
osbstruct stat of the first file/dir
nsbstruct 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 (osb->st_dev == nsb->st_dev) && (osb->st_ino == nsb->st_ino) &&
82  (osb->st_rdev == nsb->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_b2s(&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 }
#define NONULL(x)
Definition: string2.h:37
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:50
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ 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:351
+ 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 sb;
200  /* Defend against symlink attacks */
201 
202  const bool is_regular_file = (lstat(s, &sb) == 0) && S_ISREG(sb.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 sb2;
211  if ((fstat(fd, &sb2) != 0) || !S_ISREG(sb2.st_mode) ||
212  (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino))
213  {
214  close(fd);
215  return;
216  }
217 
218  FILE *fp = fdopen(fd, "r+");
219  if (fp)
220  {
221  unlink(s);
222  char buf[2048] = { 0 };
223  while (sb.st_size > 0)
224  {
225  fwrite(buf, 1, MIN(sizeof(buf), sb.st_size), fp);
226  sb.st_size -= MIN(sizeof(buf), sb.st_size);
227  }
228  mutt_file_fclose(&fp);
229  }
230 }
#define MIN(a, b)
Definition: memory.h:31
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define O_NOFOLLOW
Definition: file.c:67
+ 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 240 of file file.c.

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

Definition at line 270 of file file.c.

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

297 {
298  struct stat osb, nsb;
299 
300  if (!oldpath || !newpath)
301  return -1;
302 
303  if ((unlink(newpath) == -1) && (errno != ENOENT))
304  return -1;
305 
306  if (oldpath[0] == '/')
307  {
308  if (symlink(oldpath, newpath) == -1)
309  return -1;
310  }
311  else
312  {
313  struct Buffer abs_oldpath = mutt_buffer_make(PATH_MAX);
314 
315  if (!mutt_path_getcwd(&abs_oldpath))
316  {
317  mutt_buffer_dealloc(&abs_oldpath);
318  return -1;
319  }
320 
321  mutt_buffer_addch(&abs_oldpath, '/');
322  mutt_buffer_addstr(&abs_oldpath, oldpath);
323  if (symlink(mutt_b2s(&abs_oldpath), newpath) == -1)
324  {
325  mutt_buffer_dealloc(&abs_oldpath);
326  return -1;
327  }
328 
329  mutt_buffer_dealloc(&abs_oldpath);
330  }
331 
332  if ((stat(oldpath, &osb) == -1) || (stat(newpath, &nsb) == -1) ||
333  !compare_stat(&osb, &nsb))
334  {
335  unlink(newpath);
336  return -1;
337  }
338 
339  return 0;
340 }
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
static bool compare_stat(struct stat *osb, struct stat *nsb)
Compare the struct stat&#39;s of two files/dirs.
Definition: file.c:79
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
#define mutt_b2s(buf)
Definition: buffer.h:41
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:541
#define PATH_MAX
Definition: mutt.h:50
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
+ 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 351 of file file.c.

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

466 {
467  if (!path)
468  return -1;
469 
470  struct dirent *de = NULL;
471  struct stat statbuf;
472  int rc = 0;
473 
474  DIR *dirp = opendir(path);
475  if (!dirp)
476  {
477  mutt_debug(LL_DEBUG1, "error opening directory %s\n", path);
478  return -1;
479  }
480 
481  /* We avoid using the buffer pool for this function, because it
482  * invokes recursively to an unknown depth. */
483  struct Buffer cur = mutt_buffer_make(PATH_MAX);
484 
485  while ((de = readdir(dirp)))
486  {
487  if ((strcmp(".", de->d_name) == 0) || (strcmp("..", de->d_name) == 0))
488  continue;
489 
490  mutt_buffer_printf(&cur, "%s/%s", path, de->d_name);
491  /* XXX make nonrecursive version */
492 
493  if (stat(mutt_b2s(&cur), &statbuf) == -1)
494  {
495  rc = 1;
496  continue;
497  }
498 
499  if (S_ISDIR(statbuf.st_mode))
500  rc |= mutt_file_rmtree(mutt_b2s(&cur));
501  else
502  rc |= unlink(mutt_b2s(&cur));
503  }
504  closedir(dirp);
505 
506  rc |= rmdir(path);
507 
508  mutt_buffer_dealloc(&cur);
509  return rc;
510 }
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:465
String manipulation buffer.
Definition: buffer.h:33
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:50
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ 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,
int  flags 
)

Open a file.

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

Definition at line 519 of file file.c.

520 {
521  if (!path)
522  return -1;
523 
524  struct stat osb, nsb;
525  int fd;
526  struct Buffer safe_file = mutt_buffer_make(0);
527  struct Buffer safe_dir = mutt_buffer_make(0);
528 
529  if (flags & O_EXCL)
530  {
531  mutt_buffer_alloc(&safe_file, PATH_MAX);
532  mutt_buffer_alloc(&safe_dir, PATH_MAX);
533 
534  if (mkwrapdir(path, &safe_file, &safe_dir) == -1)
535  {
536  fd = -1;
537  goto cleanup;
538  }
539 
540  fd = open(mutt_b2s(&safe_file), flags, 0600);
541  if (fd < 0)
542  {
543  rmdir(mutt_b2s(&safe_dir));
544  goto cleanup;
545  }
546 
547  /* NFS and I believe cygwin do not handle movement of open files well */
548  close(fd);
549  if (put_file_in_place(path, mutt_b2s(&safe_file), mutt_b2s(&safe_dir)) == -1)
550  {
551  fd = -1;
552  goto cleanup;
553  }
554  }
555 
556  fd = open(path, flags & ~O_EXCL, 0600);
557  if (fd < 0)
558  goto cleanup;
559 
560  /* make sure the file is not symlink */
561  if (((lstat(path, &osb) < 0) || (fstat(fd, &nsb) < 0)) || !compare_stat(&osb, &nsb))
562  {
563  close(fd);
564  fd = -1;
565  goto cleanup;
566  }
567 
568 cleanup:
569  mutt_buffer_dealloc(&safe_file);
570  mutt_buffer_dealloc(&safe_dir);
571 
572  return fd;
573 }
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
static bool compare_stat(struct stat *osb, struct stat *nsb)
Compare the struct stat&#39;s of two files/dirs.
Definition: file.c:79
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
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:50
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
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
+ 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 585 of file file.c.

586 {
587  if (!path || !mode)
588  return NULL;
589 
590  if (mode[0] == 'w')
591  {
592  int fd;
593  int flags = O_CREAT | O_EXCL | O_NOFOLLOW;
594 
595  if (mode[1] == '+')
596  flags |= O_RDWR;
597  else
598  flags |= O_WRONLY;
599 
600  fd = mutt_file_open(path, flags);
601  if (fd < 0)
602  return NULL;
603 
604  return fdopen(fd, mode);
605  }
606  else
607  return fopen(path, mode);
608 }
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:519
#define O_NOFOLLOW
Definition: file.c:67
+ 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 615 of file file.c.

616 {
617  if (!path)
618  return;
619 
620  for (; *path; path++)
621  {
622  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
623  *path = '_';
624  }
625 }
const char filename_safe_chars[]
Definition: file.c:60
+ 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 634 of file file.c.

635 {
636  if (!dest || !src)
637  return -1;
638 
639  mutt_buffer_reset(dest);
640  while (*src != '\0')
641  {
642  if (strchr(rx_special_chars, *src))
643  mutt_buffer_addch(dest, '\\');
644  mutt_buffer_addch(dest, *src++);
645  }
646 
647  return 0;
648 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static const char rx_special_chars[]
Definition: file.c:58
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
+ 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,
int  flags 
)

Read a line from a file.

Parameters
[out]lineBuffer allocated on the head (optional)
[in]sizeLength of buffer (optional)
[in]fpFile to read
[out]line_numCurrent line number
[in]flagsFlags, e.g. MUTT_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 664 of file file.c.

665 {
666  if (!size || !fp)
667  return NULL;
668 
669  size_t offset = 0;
670  char *ch = NULL;
671 
672  if (!line)
673  {
674  *size = 256;
675  line = mutt_mem_malloc(*size);
676  }
677 
678  while (true)
679  {
680  if (!fgets(line + offset, *size - offset, fp))
681  {
682  FREE(&line);
683  return NULL;
684  }
685  ch = strchr(line + offset, '\n');
686  if (ch)
687  {
688  if (line_num)
689  (*line_num)++;
690  if (flags & MUTT_EOL)
691  return line;
692  *ch = '\0';
693  if ((ch > line) && (*(ch - 1) == '\r'))
694  *--ch = '\0';
695  if (!(flags & MUTT_CONT) || (ch == line) || (*(ch - 1) != '\\'))
696  return line;
697  offset = ch - line - 1;
698  }
699  else
700  {
701  int c;
702  c = getc(fp); /* This is kind of a hack. We want to know if the
703  char at the current point in the input stream is EOF.
704  feof() will only tell us if we've already hit EOF, not
705  if the next character is EOF. So, we need to read in
706  the next character and manually check if it is EOF. */
707  if (c == EOF)
708  {
709  /* The last line of fp isn't \n terminated */
710  if (line_num)
711  (*line_num)++;
712  return line;
713  }
714  else
715  {
716  ungetc(c, fp); /* undo our damage */
717  /* There wasn't room for the line -- increase "line" */
718  offset = *size - 1; /* overwrite the terminating 0 */
719  *size += 256;
720  mutt_mem_realloc(&line, *size);
721  }
722  }
723  }
724 }
#define MUTT_CONT
-continuation
Definition: file.h:38
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
const char * line
Definition: common.c:36
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:40
#define MUTT_EOL
don&#39;t strip \n / \r\n
Definition: file.h:39
+ 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,
int  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
trueif data read, false on 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);
}

Definition at line 744 of file file.c.

745 {
746  if (!iter)
747  return false;
748 
749  char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
750  if (!p)
751  return false;
752  iter->line = p;
753  return true;
754 }
char * line
the line data
Definition: file.h:69
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, int flags)
Read a line from a file.
Definition: file.c:664
int line_num
line number
Definition: file.h:71
size_t size
allocated size of line data
Definition: file.h:70
+ 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,
int  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
trueif all data mapped, false if "func" returns false

Definition at line 764 of file file.c.

765 {
766  if (!func || !fp)
767  return false;
768 
769  struct MuttFileIter iter = { 0 };
770  while (mutt_file_iter_line(&iter, fp, flags))
771  {
772  if (!(*func)(iter.line, iter.line_num, user_data))
773  {
774  FREE(&iter.line);
775  return false;
776  }
777  }
778  return true;
779 }
char * line
the line data
Definition: file.h:69
bool mutt_file_iter_line(struct MuttFileIter *iter, FILE *fp, int flags)
iterate over the lines from an open file pointer
Definition: file.c:744
int line_num
line number
Definition: file.h:71
State record for mutt_file_iter_line()
Definition: file.h:67
#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_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 790 of file file.c.

791 {
792  if (!buf)
793  return 0;
794 
795  if (!filename)
796  {
797  *buf = '\0';
798  return 0;
799  }
800 
801  size_t j = 0;
802 
803  /* leave some space for the trailing characters. */
804  buflen -= 6;
805 
806  buf[j++] = '\'';
807 
808  for (size_t i = 0; (j < buflen) && filename[i]; i++)
809  {
810  if ((filename[i] == '\'') || (filename[i] == '`'))
811  {
812  buf[j++] = '\'';
813  buf[j++] = '\\';
814  buf[j++] = filename[i];
815  buf[j++] = '\'';
816  }
817  else
818  buf[j++] = filename[i];
819  }
820 
821  buf[j++] = '\'';
822  buf[j] = '\0';
823 
824  return j;
825 }
+ 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
Return values
numBytes written to the buffer

Definition at line 834 of file file.c.

835 {
836  if (!buf || !filename)
837  return;
838 
839  mutt_buffer_reset(buf);
840  if (add_outer)
841  mutt_buffer_addch(buf, '\'');
842 
843  for (; *filename != '\0'; filename++)
844  {
845  if ((*filename == '\'') || (*filename == '`'))
846  {
847  mutt_buffer_addch(buf, '\'');
848  mutt_buffer_addch(buf, '\\');
849  mutt_buffer_addch(buf, *filename);
850  mutt_buffer_addch(buf, '\'');
851  }
852  else
853  mutt_buffer_addch(buf, *filename);
854  }
855 
856  if (add_outer)
857  mutt_buffer_addch(buf, '\'');
858 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
+ 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 873 of file file.c.

874 {
875  if (!path || !*path)
876  {
877  errno = EINVAL;
878  return -1;
879  }
880 
881  errno = 0;
882  char tmp_path[PATH_MAX];
883  const size_t len = strlen(path);
884 
885  if (len >= sizeof(tmp_path))
886  {
887  errno = ENAMETOOLONG;
888  return -1;
889  }
890 
891  struct stat sb;
892  if ((stat(path, &sb) == 0) && S_ISDIR(sb.st_mode))
893  return 0;
894 
895  /* Create a mutable copy */
896  mutt_str_strfcpy(tmp_path, path, sizeof(tmp_path));
897 
898  for (char *p = tmp_path + 1; *p; p++)
899  {
900  if (*p != '/')
901  continue;
902 
903  /* Temporarily truncate the path */
904  *p = '\0';
905 
906  if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
907  return -1;
908 
909  *p = '/';
910  }
911 
912  if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
913  return -1;
914 
915  return 0;
916 }
#define PATH_MAX
Definition: mutt.h:50
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
+ 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 928 of file file.c.

929 {
930  char name[PATH_MAX];
931 
932  int n = snprintf(name, sizeof(name), "%s/neomutt-XXXXXX", NONULL(C_Tmpdir));
933  if (n < 0)
934  return NULL;
935 
936  int fd = mkstemp(name);
937  if (fd == -1)
938  return NULL;
939 
940  FILE *fp = fdopen(fd, "w+");
941 
942  if ((unlink(name) != 0) && (errno != ENOENT))
943  {
944  mutt_file_fclose(&fp);
945  return NULL;
946  }
947 
948  MuttLogger(0, file, line, func, 1, "created temp file '%s'\n", name);
949  return fp;
950 }
#define NONULL(x)
Definition: string2.h:37
log_dispatcher_t MuttLogger
The log dispatcher.
Definition: logging.c:52
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
const char * name
Definition: pgpmicalg.c:46
const char * line
Definition: common.c:36
#define PATH_MAX
Definition: mutt.h:50
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:55
+ Here is the call graph for this function:
+ Here is the caller 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 961 of file file.c.

962 {
963  if (!fp)
964  return -1;
965 
966  struct utimbuf utim;
967  struct stat st2;
968  time_t mtime;
969 
970  if (!st)
971  {
972  if (stat(fp, &st2) == -1)
973  return -1;
974  st = &st2;
975  }
976 
977  mtime = st->st_mtime;
978  if (mtime == mutt_date_epoch())
979  {
980  mtime -= 1;
981  utim.actime = mtime;
982  utim.modtime = mtime;
983  utime(fp, &utim);
984  }
985 
986  return mtime;
987 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:411
+ 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 994 of file file.c.

995 {
996  if (!from || !to)
997  return;
998 
999  struct utimbuf utim;
1000  struct stat st;
1001 
1002  if (stat(from, &st) != -1)
1003  {
1004  utim.actime = st.st_mtime;
1005  utim.modtime = st.st_mtime;
1006  utime(to, &utim);
1007  }
1008 }
+ 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 1017 of file file.c.

1018 {
1019 #ifdef HAVE_FUTIMENS
1020  struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1021  futimens(fd, times);
1022 #endif
1023 }
Time value with nanosecond precision.
Definition: file.h:45
+ 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 1033 of file file.c.

1034 {
1035  if (!path)
1036  return -1;
1037 
1038  return chmod(path, mode);
1039 }
+ Here is the caller graph for this function:

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

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

1082 {
1083  if (!path)
1084  return -1;
1085 
1086  struct stat st2;
1087 
1088  if (!st)
1089  {
1090  if (stat(path, &st2) == -1)
1091  return -1;
1092  st = &st2;
1093  }
1094  return chmod(path, st->st_mode | mode);
1095 }
+ 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 1114 of file file.c.

1115 {
1116  return mutt_file_chmod_rm_stat(path, mode, NULL);
1117 }
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
Definition: file.c:1137
+ Here is the call graph for this function:
+ Here is the caller 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 1137 of file file.c.

1138 {
1139  if (!path)
1140  return -1;
1141 
1142  struct stat st2;
1143 
1144  if (!st)
1145  {
1146  if (stat(path, &st2) == -1)
1147  return -1;
1148  st = &st2;
1149  }
1150  return chmod(path, st->st_mode & ~mode);
1151 }
+ Here is the call graph for this function:
+ 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 1302 of file file.c.

1303 {
1304  if (!path)
1305  return;
1306 
1307  struct stat sb;
1308 
1309  int fd = open(path, O_RDWR);
1310  if (fd == -1)
1311  return;
1312 
1313  if (mutt_file_lock(fd, true, true) == -1)
1314  {
1315  close(fd);
1316  return;
1317  }
1318 
1319  if ((fstat(fd, &sb) == 0) && (sb.st_size == 0))
1320  unlink(path);
1321 
1322  mutt_file_unlock(fd);
1323  close(fd);
1324 }
int mutt_file_lock(int fd, bool excl, bool timeout)
int mutt_file_unlock(int fd)
+ Here is the call graph for this function:
+ Here is the caller 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 1338 of file file.c.

1339 {
1340  if (!oldfile || !newfile)
1341  return -1;
1342  if (access(oldfile, F_OK) != 0)
1343  return 1;
1344  if (access(newfile, F_OK) == 0)
1345  return 2;
1346 
1347  FILE *fp_old = fopen(oldfile, "r");
1348  if (!fp_old)
1349  return 3;
1350  FILE *fp_new = mutt_file_fopen(newfile, "w");
1351  if (!fp_new)
1352  {
1353  mutt_file_fclose(&fp_old);
1354  return 3;
1355  }
1356  mutt_file_copy_stream(fp_old, fp_new);
1357  mutt_file_fclose(&fp_new);
1358  mutt_file_fclose(&fp_old);
1359  mutt_file_unlink(oldfile);
1360  return 0;
1361 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
+ 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 1373 of file file.c.

1374 {
1375  FILE *fp = mutt_file_fopen(file, "r");
1376  if (!fp)
1377  return NULL;
1378 
1379  buf = fgets(buf, buflen, fp);
1380  mutt_file_fclose(&fp);
1381 
1382  if (!buf)
1383  return NULL;
1384 
1385  SKIPWS(buf);
1386  char *start = buf;
1387 
1388  while ((*buf != '\0') && !isspace(*buf))
1389  buf++;
1390 
1391  *buf = '\0';
1392 
1393  return start;
1394 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define SKIPWS(ch)
Definition: string2.h:47
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
+ 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 1403 of file file.c.

1404 {
1405  if (!path)
1406  return -1;
1407 
1408  struct stat st;
1409  if (stat(path, &st) == -1)
1410  return -1;
1411 
1412  return st.st_size == 0;
1413 }
+ 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 1423 of file file.c.

1424 {
1425  struct Buffer tmp = mutt_buffer_make(PATH_MAX);
1426 
1427  mutt_buffer_quote_filename(&tmp, src, true);
1428  mutt_file_expand_fmt(dest, fmt, mutt_b2s(&tmp));
1429  mutt_buffer_dealloc(&tmp);
1430 }
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell&#39;s quoting rules.
Definition: file.c:834
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
String manipulation buffer.
Definition: buffer.h:33
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:50
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:1438
+ 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 1438 of file file.c.

1439 {
1440  if (!dest || !fmt || !src)
1441  return;
1442 
1443  const char *p = NULL;
1444  bool found = false;
1445 
1446  mutt_buffer_reset(dest);
1447 
1448  for (p = fmt; *p; p++)
1449  {
1450  if (*p == '%')
1451  {
1452  switch (p[1])
1453  {
1454  case '%':
1455  mutt_buffer_addch(dest, *p++);
1456  break;
1457  case 's':
1458  found = true;
1459  mutt_buffer_addstr(dest, src);
1460  p++;
1461  break;
1462  default:
1463  mutt_buffer_addch(dest, *p);
1464  break;
1465  }
1466  }
1467  else
1468  {
1469  mutt_buffer_addch(dest, *p);
1470  }
1471  }
1472 
1473  if (!found)
1474  {
1475  mutt_buffer_addch(dest, ' ');
1476  mutt_buffer_addstr(dest, src);
1477  }
1478 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
+ 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 1486 of file file.c.

1487 {
1488  if (!path)
1489  return 0;
1490 
1491  struct stat sb;
1492  if (stat(path, &sb) != 0)
1493  return 0;
1494 
1495  return sb.st_size;
1496 }
+ 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 1506 of file file.c.

1507 {
1508  if (!a || !b)
1509  return 0;
1510  if (a->tv_sec < b->tv_sec)
1511  return -1;
1512  if (a->tv_sec > b->tv_sec)
1513  return 1;
1514 
1515  if (a->tv_nsec < b->tv_nsec)
1516  return -1;
1517  if (a->tv_nsec > b->tv_nsec)
1518  return 1;
1519  return 0;
1520 }
time_t tv_sec
Definition: file.h:47
long tv_nsec
Definition: file.h:48
+ Here is the caller graph for this function:

◆ mutt_file_get_stat_timespec()

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

Read the stat() time into a time value.

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

Definition at line 1528 of file file.c.

1529 {
1530  if (!dest || !sb)
1531  return;
1532 
1533  dest->tv_sec = 0;
1534  dest->tv_nsec = 0;
1535 
1536  switch (type)
1537  {
1538  case MUTT_STAT_ATIME:
1539  dest->tv_sec = sb->st_atime;
1540 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1541  dest->tv_nsec = sb->st_atim.tv_nsec;
1542 #endif
1543  break;
1544  case MUTT_STAT_MTIME:
1545  dest->tv_sec = sb->st_mtime;
1546 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1547  dest->tv_nsec = sb->st_mtim.tv_nsec;
1548 #endif
1549  break;
1550  case MUTT_STAT_CTIME:
1551  dest->tv_sec = sb->st_ctime;
1552 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1553  dest->tv_nsec = sb->st_ctim.tv_nsec;
1554 #endif
1555  break;
1556  }
1557 }
File/dir&#39;s ctime - creation time.
Definition: file.h:61
time_t tv_sec
Definition: file.h:47
File/dir&#39;s mtime - last modified time.
Definition: file.h:60
long tv_nsec
Definition: file.h:48
File/dir&#39;s atime - last accessed time.
Definition: file.h:59
+ Here is the caller graph for this function:

◆ mutt_file_stat_timespec_compare()

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

Compare stat info with a time value.

Parameters
sbastat 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 1568 of file file.c.

1570 {
1571  if (!sba || !b)
1572  return 0;
1573 
1574  struct timespec a = { 0 };
1575 
1576  mutt_file_get_stat_timespec(&a, sba, type);
1577  return mutt_file_timespec_compare(&a, b);
1578 }
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1506
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *sb, enum MuttStatType type)
Read the stat() time into a time value.
Definition: file.c:1528
Time value with nanosecond precision.
Definition: file.h:45
+ 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 *  sba,
enum MuttStatType  sba_type,
struct stat *  sbb,
enum MuttStatType  sbb_type 
)

Compare two stat infos.

Parameters
sbaFirst stat info
sba_typeType of first stat info, e.g. MUTT_STAT_ATIME
sbbSecond stat info
sbb_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 1590 of file file.c.

1592 {
1593  if (!sba || !sbb)
1594  return 0;
1595 
1596  struct timespec a = { 0 };
1597  struct timespec b = { 0 };
1598 
1599  mutt_file_get_stat_timespec(&a, sba, sba_type);
1600  mutt_file_get_stat_timespec(&b, sbb, sbb_type);
1601  return mutt_file_timespec_compare(&a, &b);
1602 }
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1506
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *sb, enum MuttStatType type)
Read the stat() time into a time value.
Definition: file.c:1528
Time value with nanosecond precision.
Definition: file.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_Tmpdir

char* C_Tmpdir

Config: Directory for temporary files.

Definition at line 55 of file file.c.

◆ rx_special_chars

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

Definition at line 58 of file file.c.

◆ filename_safe_chars

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

Definition at line 60 of file file.c.