NeoMutt  2018-07-16 +2481-68dcde
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/file.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 61 of file file.c.

◆ O_NOFOLLOW

#define O_NOFOLLOW   0

Definition at line 65 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 77 of file file.c.

78 {
79  return (osb->st_dev == nsb->st_dev) && (osb->st_ino == nsb->st_ino) &&
80  (osb->st_rdev == nsb->st_rdev);
81 }
+ 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 91 of file file.c.

92 {
93  const char *basename = NULL;
94  int rc = 0;
95 
96  struct Buffer parent = mutt_buffer_make(PATH_MAX);
97  mutt_buffer_strcpy(&parent, NONULL(path));
98 
99  char *p = strrchr(parent.data, '/');
100  if (p)
101  {
102  *p = '\0';
103  basename = p + 1;
104  }
105  else
106  {
107  mutt_buffer_strcpy(&parent, ".");
108  basename = path;
109  }
110 
111  mutt_buffer_printf(newdir, "%s/%s", mutt_b2s(&parent), ".muttXXXXXX");
112  if (!mkdtemp(newdir->data))
113  {
114  mutt_debug(LL_DEBUG1, "mkdtemp() failed\n");
115  rc = -1;
116  goto cleanup;
117  }
118 
119  mutt_buffer_printf(newfile, "%s/%s", newdir->data, NONULL(basename));
120 
121 cleanup:
122  mutt_buffer_dealloc(&parent);
123  return rc;
124 }
#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:293
#define mutt_b2s(buf)
Definition: buffer.h:41
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
#define PATH_MAX
Definition: mutt.h:52
char * data
Pointer to data.
Definition: buffer.h:35
Log at debug level 1.
Definition: logging.h:56
#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 134 of file file.c.

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

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

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

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

193 {
194  if (!s)
195  return;
196 
197  struct stat sb;
198  /* Defend against symlink attacks */
199 
200  const bool is_regular_file = (lstat(s, &sb) == 0) && S_ISREG(sb.st_mode);
201  if (!is_regular_file)
202  return;
203 
204  const int fd = open(s, O_RDWR | O_NOFOLLOW);
205  if (fd < 0)
206  return;
207 
208  struct stat sb2;
209  if ((fstat(fd, &sb2) != 0) || !S_ISREG(sb2.st_mode) ||
210  (sb.st_dev != sb2.st_dev) || (sb.st_ino != sb2.st_ino))
211  {
212  close(fd);
213  return;
214  }
215 
216  FILE *fp = fdopen(fd, "r+");
217  if (fp)
218  {
219  unlink(s);
220  char buf[2048] = { 0 };
221  while (sb.st_size > 0)
222  {
223  fwrite(buf, 1, MIN(sizeof(buf), sb.st_size), fp);
224  sb.st_size -= MIN(sizeof(buf), sb.st_size);
225  }
226  mutt_file_fclose(&fp);
227  }
228 }
#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:150
#define O_NOFOLLOW
Definition: file.c:65
+ 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 238 of file file.c.

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

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

295 {
296  struct stat osb, nsb;
297 
298  if (!oldpath || !newpath)
299  return -1;
300 
301  if ((unlink(newpath) == -1) && (errno != ENOENT))
302  return -1;
303 
304  if (oldpath[0] == '/')
305  {
306  if (symlink(oldpath, newpath) == -1)
307  return -1;
308  }
309  else
310  {
311  struct Buffer abs_oldpath = mutt_buffer_make(PATH_MAX);
312 
313  if (!mutt_path_getcwd(&abs_oldpath))
314  {
315  mutt_buffer_dealloc(&abs_oldpath);
316  return -1;
317  }
318 
319  mutt_buffer_addch(&abs_oldpath, '/');
320  mutt_buffer_addstr(&abs_oldpath, oldpath);
321  if (symlink(mutt_b2s(&abs_oldpath), newpath) == -1)
322  {
323  mutt_buffer_dealloc(&abs_oldpath);
324  return -1;
325  }
326 
327  mutt_buffer_dealloc(&abs_oldpath);
328  }
329 
330  if ((stat(oldpath, &osb) == -1) || (stat(newpath, &nsb) == -1) ||
331  !compare_stat(&osb, &nsb))
332  {
333  unlink(newpath);
334  return -1;
335  }
336 
337  return 0;
338 }
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:77
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:293
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:599
#define PATH_MAX
Definition: mutt.h:52
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 349 of file file.c.

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

464 {
465  if (!path)
466  return -1;
467 
468  struct dirent *de = NULL;
469  struct stat statbuf;
470  int rc = 0;
471 
472  DIR *dirp = opendir(path);
473  if (!dirp)
474  {
475  mutt_debug(LL_DEBUG1, "error opening directory %s\n", path);
476  return -1;
477  }
478 
479  /* We avoid using the buffer pool for this function, because it
480  * invokes recursively to an unknown depth. */
481  struct Buffer cur = mutt_buffer_make(PATH_MAX);
482 
483  while ((de = readdir(dirp)))
484  {
485  if ((strcmp(".", de->d_name) == 0) || (strcmp("..", de->d_name) == 0))
486  continue;
487 
488  mutt_buffer_printf(&cur, "%s/%s", path, de->d_name);
489  /* XXX make nonrecursive version */
490 
491  if (stat(mutt_b2s(&cur), &statbuf) == -1)
492  {
493  rc = 1;
494  continue;
495  }
496 
497  if (S_ISDIR(statbuf.st_mode))
498  rc |= mutt_file_rmtree(mutt_b2s(&cur));
499  else
500  rc |= unlink(mutt_b2s(&cur));
501  }
502  closedir(dirp);
503 
504  rc |= rmdir(path);
505 
506  mutt_buffer_dealloc(&cur);
507  return rc;
508 }
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:463
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:293
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:52
Log at debug level 1.
Definition: logging.h:56
#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 517 of file file.c.

518 {
519  if (!path)
520  return -1;
521 
522  struct stat osb, nsb;
523  int fd;
524  struct Buffer safe_file = mutt_buffer_make(0);
525  struct Buffer safe_dir = mutt_buffer_make(0);
526 
527  if (flags & O_EXCL)
528  {
529  mutt_buffer_alloc(&safe_file, PATH_MAX);
530  mutt_buffer_alloc(&safe_dir, PATH_MAX);
531 
532  if (mkwrapdir(path, &safe_file, &safe_dir) == -1)
533  {
534  fd = -1;
535  goto cleanup;
536  }
537 
538  fd = open(mutt_b2s(&safe_file), flags, 0600);
539  if (fd < 0)
540  {
541  rmdir(mutt_b2s(&safe_dir));
542  goto cleanup;
543  }
544 
545  /* NFS and I believe cygwin do not handle movement of open files well */
546  close(fd);
547  if (put_file_in_place(path, mutt_b2s(&safe_file), mutt_b2s(&safe_dir)) == -1)
548  {
549  fd = -1;
550  goto cleanup;
551  }
552  }
553 
554  fd = open(path, flags & ~O_EXCL, 0600);
555  if (fd < 0)
556  goto cleanup;
557 
558  /* make sure the file is not symlink */
559  if (((lstat(path, &osb) < 0) || (fstat(fd, &nsb) < 0)) || !compare_stat(&osb, &nsb))
560  {
561  close(fd);
562  fd = -1;
563  goto cleanup;
564  }
565 
566 cleanup:
567  mutt_buffer_dealloc(&safe_file);
568  mutt_buffer_dealloc(&safe_dir);
569 
570  return fd;
571 }
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:77
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
Definition: file.c:91
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:293
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:52
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:134
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 583 of file file.c.

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

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

633 {
634  if (!dest || !src)
635  return -1;
636 
637  mutt_buffer_reset(dest);
638  while (*src != '\0')
639  {
640  if (strchr(rx_special_chars, *src))
641  mutt_buffer_addch(dest, '\\');
642  mutt_buffer_addch(dest, *src++);
643  }
644 
645  return 0;
646 }
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static const char rx_special_chars[]
Definition: file.c:56
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 662 of file file.c.

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

743 {
744  if (!iter)
745  return false;
746 
747  char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
748  if (!p)
749  return false;
750  iter->line = p;
751  return true;
752 }
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:662
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 762 of file file.c.

763 {
764  if (!func || !fp)
765  return false;
766 
767  struct MuttFileIter iter = { 0 };
768  while (mutt_file_iter_line(&iter, fp, flags))
769  {
770  if (!(*func)(iter.line, iter.line_num, user_data))
771  {
772  FREE(&iter.line);
773  return false;
774  }
775  }
776  return true;
777 }
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:742
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 788 of file file.c.

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

833 {
834  if (!buf || !filename)
835  return;
836 
837  mutt_buffer_reset(buf);
838  if (add_outer)
839  mutt_buffer_addch(buf, '\'');
840 
841  for (; *filename != '\0'; filename++)
842  {
843  if ((*filename == '\'') || (*filename == '`'))
844  {
845  mutt_buffer_addch(buf, '\'');
846  mutt_buffer_addch(buf, '\\');
847  mutt_buffer_addch(buf, *filename);
848  mutt_buffer_addch(buf, '\'');
849  }
850  else
851  mutt_buffer_addch(buf, *filename);
852  }
853 
854  if (add_outer)
855  mutt_buffer_addch(buf, '\'');
856 }
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 871 of file file.c.

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

927 {
928  char name[PATH_MAX];
929 
930  int n = snprintf(name, sizeof(name), "%s/neomutt-XXXXXX", NONULL(C_Tmpdir));
931  if (n < 0)
932  return NULL;
933 
934  int fd = mkstemp(name);
935  if (fd == -1)
936  return NULL;
937 
938  FILE *fp = fdopen(fd, "w+");
939 
940  if ((unlink(name) != 0) && (errno != ENOENT))
941  {
942  mutt_file_fclose(&fp);
943  return NULL;
944  }
945 
946  MuttLogger(0, file, line, func, 1, "created temp file '%s'\n", name);
947  return fp;
948 }
#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:150
const char * name
Definition: pgpmicalg.c:45
const char * line
Definition: common.c:36
#define PATH_MAX
Definition: mutt.h:52
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:53
+ 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 959 of file file.c.

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

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

1016 {
1017 #ifdef HAVE_FUTIMENS
1018  struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1019  futimens(fd, times);
1020 #endif
1021 }
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 1031 of file file.c.

1032 {
1033  if (!path)
1034  return -1;
1035 
1036  return chmod(path, mode);
1037 }
+ 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)
See also
mutt_file_chmod_add_stat()

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.

Definition at line 1055 of file file.c.

1056 {
1057  return mutt_file_chmod_add_stat(path, mode, NULL);
1058 }
int mutt_file_chmod_add_stat(const char *path, mode_t mode, struct stat *st)
Add permissions to a file.
Definition: file.c:1077
+ 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)
See also
mutt_file_chmod_add()

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);

Definition at line 1077 of file file.c.

1078 {
1079  if (!path)
1080  return -1;
1081 
1082  struct stat st2;
1083 
1084  if (!st)
1085  {
1086  if (stat(path, &st2) == -1)
1087  return -1;
1088  st = &st2;
1089  }
1090  return chmod(path, st->st_mode | mode);
1091 }
+ 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)
See also
mutt_file_chmod_rm_stat()

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.

Definition at line 1109 of file file.c.

1110 {
1111  return mutt_file_chmod_rm_stat(path, mode, NULL);
1112 }
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
Definition: file.c:1131
+ 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)
See also
mutt_file_chmod_rm()

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);

Definition at line 1131 of file file.c.

1132 {
1133  if (!path)
1134  return -1;
1135 
1136  struct stat st2;
1137 
1138  if (!st)
1139  {
1140  if (stat(path, &st2) == -1)
1141  return -1;
1142  st = &st2;
1143  }
1144  return chmod(path, st->st_mode & ~mode);
1145 }
+ 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 1296 of file file.c.

1297 {
1298  if (!path)
1299  return;
1300 
1301  struct stat sb;
1302 
1303  int fd = open(path, O_RDWR);
1304  if (fd == -1)
1305  return;
1306 
1307  if (mutt_file_lock(fd, true, true) == -1)
1308  {
1309  close(fd);
1310  return;
1311  }
1312 
1313  if ((fstat(fd, &sb) == 0) && (sb.st_size == 0))
1314  unlink(path);
1315 
1316  mutt_file_unlock(fd);
1317  close(fd);
1318 }
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 1332 of file file.c.

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

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

1398 {
1399  if (!path)
1400  return -1;
1401 
1402  struct stat st;
1403  if (stat(path, &st) == -1)
1404  return -1;
1405 
1406  return st.st_size == 0;
1407 }
+ 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 1417 of file file.c.

1418 {
1419  struct Buffer tmp = mutt_buffer_make(PATH_MAX);
1420 
1421  mutt_buffer_quote_filename(&tmp, src, true);
1422  mutt_file_expand_fmt(dest, fmt, mutt_b2s(&tmp));
1423  mutt_buffer_dealloc(&tmp);
1424 }
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:832
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:293
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:52
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:1432
+ 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 1432 of file file.c.

1433 {
1434  if (!dest || !fmt || !src)
1435  return;
1436 
1437  const char *p = NULL;
1438  bool found = false;
1439 
1440  mutt_buffer_reset(dest);
1441 
1442  for (p = fmt; *p; p++)
1443  {
1444  if (*p == '%')
1445  {
1446  switch (p[1])
1447  {
1448  case '%':
1449  mutt_buffer_addch(dest, *p++);
1450  break;
1451  case 's':
1452  found = true;
1453  mutt_buffer_addstr(dest, src);
1454  p++;
1455  break;
1456  default:
1457  mutt_buffer_addch(dest, *p);
1458  break;
1459  }
1460  }
1461  else
1462  {
1463  mutt_buffer_addch(dest, *p);
1464  }
1465  }
1466 
1467  if (!found)
1468  {
1469  mutt_buffer_addch(dest, ' ');
1470  mutt_buffer_addstr(dest, src);
1471  }
1472 }
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 1480 of file file.c.

1481 {
1482  if (!path)
1483  return 0;
1484 
1485  struct stat sb;
1486  if (stat(path, &sb) != 0)
1487  return 0;
1488 
1489  return sb.st_size;
1490 }
+ 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 1500 of file file.c.

1501 {
1502  if (!a || !b)
1503  return 0;
1504  if (a->tv_sec < b->tv_sec)
1505  return -1;
1506  if (a->tv_sec > b->tv_sec)
1507  return 1;
1508 
1509  if (a->tv_nsec < b->tv_nsec)
1510  return -1;
1511  if (a->tv_nsec > b->tv_nsec)
1512  return 1;
1513  return 0;
1514 }
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 1522 of file file.c.

1523 {
1524  if (!dest || !sb)
1525  return;
1526 
1527  dest->tv_sec = 0;
1528  dest->tv_nsec = 0;
1529 
1530  switch (type)
1531  {
1532  case MUTT_STAT_ATIME:
1533  dest->tv_sec = sb->st_atime;
1534 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1535  dest->tv_nsec = sb->st_atim.tv_nsec;
1536 #endif
1537  break;
1538  case MUTT_STAT_MTIME:
1539  dest->tv_sec = sb->st_mtime;
1540 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1541  dest->tv_nsec = sb->st_mtim.tv_nsec;
1542 #endif
1543  break;
1544  case MUTT_STAT_CTIME:
1545  dest->tv_sec = sb->st_ctime;
1546 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1547  dest->tv_nsec = sb->st_ctim.tv_nsec;
1548 #endif
1549  break;
1550  }
1551 }
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 1562 of file file.c.

1564 {
1565  if (!sba || !b)
1566  return 0;
1567 
1568  struct timespec a = { 0 };
1569 
1570  mutt_file_get_stat_timespec(&a, sba, type);
1571  return mutt_file_timespec_compare(&a, b);
1572 }
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1500
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:1522
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 1584 of file file.c.

1586 {
1587  if (!sba || !sbb)
1588  return 0;
1589 
1590  struct timespec a = { 0 };
1591  struct timespec b = { 0 };
1592 
1593  mutt_file_get_stat_timespec(&a, sba, sba_type);
1594  mutt_file_get_stat_timespec(&b, sbb, sbb_type);
1595  return mutt_file_timespec_compare(&a, &b);
1596 }
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1500
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:1522
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 53 of file file.c.

◆ rx_special_chars

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

Definition at line 56 of file file.c.

◆ filename_safe_chars

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

Definition at line 58 of file file.c.