NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
file.h File Reference

File management functions. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
+ Include dependency graph for file.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  timespec
 Time value with nanosecond precision. More...
 
struct  MuttFileIter
 State record for mutt_file_iter_line() More...
 

Macros

#define MUTT_CONT   (1 << 0)
 -continuation More...
 
#define MUTT_EOL   (1 << 1)
 don't strip \n / \r\n More...
 
#define mutt_file_mkstemp()   mutt_file_mkstemp_full(__FILE__, __LINE__, __func__)
 

Typedefs

typedef bool(* mutt_file_map_t) (char *line, int line_num, void *user_data)
 Callback function for mutt_file_map_lines() More...
 

Enumerations

enum  MuttStatType { MUTT_STAT_ATIME, MUTT_STAT_MTIME, MUTT_STAT_CTIME }
 Flags for mutt_file_get_stat_timespec. More...
 

Functions

int mutt_file_check_empty (const char *path)
 Is the mailbox empty. More...
 
int mutt_file_chmod (const char *path, mode_t mode)
 Set permissions of a file. More...
 
int mutt_file_chmod_add (const char *path, mode_t mode)
 Add permissions to a file. More...
 
int mutt_file_chmod_add_stat (const char *path, mode_t mode, struct stat *st)
 Add permissions to a file. More...
 
int mutt_file_chmod_rm (const char *path, mode_t mode)
 Remove permissions from a file. More...
 
int mutt_file_chmod_rm_stat (const char *path, mode_t mode, struct stat *st)
 Remove permissions from a file. More...
 
int mutt_file_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...
 
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_expand_fmt (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename. More...
 
void mutt_file_expand_fmt_quote (char *dest, size_t destlen, const char *fmt, const char *src)
 
int mutt_file_fclose (FILE **fp)
 Close a FILE handle (and NULL the pointer) More...
 
FILE * mutt_file_fopen (const char *path, const char *mode)
 Call fopen() safely. More...
 
int mutt_file_fsync_close (FILE **fp)
 Flush the data, before closing a file (and NULL the pointer) More...
 
long mutt_file_get_size (const char *path)
 Get the size of a file. 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...
 
bool mutt_file_iter_line (struct MuttFileIter *iter, FILE *fp, int flags)
 iterate over the lines from an open file pointer More...
 
int mutt_file_lock (int fd, bool excl, bool timeout)
 (try to) lock a file using fcntl() 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...
 
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...
 
int mutt_file_open (const char *path, int flags)
 Open a file. 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...
 
char * mutt_file_read_keyword (const char *file, char *buf, size_t buflen)
 Read a keyword from a file. 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...
 
int mutt_file_rename (const char *oldfile, const char *newfile)
 Rename a file. More...
 
int mutt_file_rmtree (const char *path)
 Recursively remove a directory. More...
 
int mutt_file_safe_rename (const char *src, const char *target)
 NFS-safe renaming of files. 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...
 
void mutt_file_set_mtime (const char *from, const char *to)
 Set the modification time of one file from another. 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...
 
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_symlink (const char *oldpath, const char *newpath)
 Create a symlink. More...
 
int mutt_file_timespec_compare (struct timespec *a, struct timespec *b)
 Compare to time values. More...
 
void mutt_file_touch_atime (int fd)
 Set the access time to current time. More...
 
void mutt_file_unlink (const char *s)
 Delete a file, carefully. More...
 
void mutt_file_unlink_empty (const char *path)
 Delete a file if it's empty. More...
 
int mutt_file_unlock (int fd)
 Unlock a file previously locked by mutt_file_lock() More...
 
void mutt_file_resolve_symlink (struct Buffer *buf)
 Resolve a symlink in place. 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...
 
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...
 

Variables

char * C_Tmpdir
 Config: Directory for temporary files. More...
 
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.h.

Macro Definition Documentation

◆ MUTT_CONT

#define MUTT_CONT   (1 << 0)

-continuation

Definition at line 37 of file file.h.

◆ MUTT_EOL

#define MUTT_EOL   (1 << 1)

don't strip \n / \r\n

Definition at line 38 of file file.h.

◆ mutt_file_mkstemp

#define mutt_file_mkstemp ( )    mutt_file_mkstemp_full(__FILE__, __LINE__, __func__)

Definition at line 106 of file file.h.

Typedef Documentation

◆ mutt_file_map_t

typedef bool(* mutt_file_map_t) (char *line, int line_num, void *user_data)

Callback function for mutt_file_map_lines()

Parameters
lineLine of text read
line_numLine number
user_dataData to pass to the callback function
Return values
trueRead was successful
falseAbort the reading and free the string

Definition at line 83 of file file.h.

Enumeration Type Documentation

◆ MuttStatType

Flags for mutt_file_get_stat_timespec.

These represent filesystem timestamps returned by stat()

Enumerator
MUTT_STAT_ATIME 

File/dir's atime - last accessed time.

MUTT_STAT_MTIME 

File/dir's mtime - last modified time.

MUTT_STAT_CTIME 

File/dir's ctime - creation time.

Definition at line 58 of file file.h.

59 {
63 };
File/dir&#39;s ctime - creation time.
Definition: file.h:62
File/dir&#39;s mtime - last modified time.
Definition: file.h:61
File/dir&#39;s atime - last accessed time.
Definition: file.h:60

Function Documentation

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

1413 {
1414  if (!path)
1415  return -1;
1416 
1417  struct stat st;
1418  if (stat(path, &st) == -1)
1419  return -1;
1420 
1421  return st.st_size == 0;
1422 }
+ 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 1042 of file file.c.

1043 {
1044  if (!path)
1045  return -1;
1046 
1047  return chmod(path, mode);
1048 }

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

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

1091 {
1092  if (!path)
1093  return -1;
1094 
1095  struct stat st2;
1096 
1097  if (!st)
1098  {
1099  if (stat(path, &st2) == -1)
1100  return -1;
1101  st = &st2;
1102  }
1103  return chmod(path, st->st_mode | mode);
1104 }
+ 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 1123 of file file.c.

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

◆ mutt_file_chmod_rm_stat()

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

Remove permissions from a file.

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

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

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

Definition at line 1146 of file file.c.

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

◆ mutt_file_copy_bytes()

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

Copy some content from one file to another.

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

Definition at line 241 of file file.c.

242 {
243  if (!fp_in || !fp_out)
244  return -1;
245 
246  while (size > 0)
247  {
248  char buf[2048];
249  size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size;
250  chunk = fread(buf, 1, chunk, fp_in);
251  if (chunk < 1)
252  break;
253  if (fwrite(buf, 1, chunk, fp_out) != chunk)
254  return -1;
255 
256  size -= chunk;
257  }
258 
259  if (fflush(fp_out) != 0)
260  return -1;
261  return 0;
262 }
+ Here is the caller graph for this function:

◆ mutt_file_copy_stream()

int mutt_file_copy_stream ( FILE *  fp_in,
FILE *  fp_out 
)

Copy the contents of one file into another.

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

Definition at line 271 of file file.c.

272 {
273  if (!fp_in || !fp_out)
274  return -1;
275 
276  size_t total = 0;
277  size_t l;
278  char buf[1024];
279 
280  while ((l = fread(buf, 1, sizeof(buf), fp_in)) > 0)
281  {
282  if (fwrite(buf, 1, l, fp_out) != l)
283  return -1;
284  total += l;
285  }
286 
287  if (fflush(fp_out) != 0)
288  return -1;
289  return total;
290 }
+ Here is the caller graph for this function:

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

964 {
965  if (!fp)
966  return -1;
967 
968  struct utimbuf utim;
969  struct stat st2;
970  time_t mtime;
971 
972  if (!st)
973  {
974  if (stat(fp, &st2) == -1)
975  return -1;
976  st = &st2;
977  }
978 
979  mtime = st->st_mtime;
980  if (mtime == mutt_date_epoch())
981  {
982  mtime -= 1;
983  utim.actime = mtime;
984  utim.modtime = mtime;
985  int rc;
986  do
987  {
988  rc = utime(fp, &utim);
989  } while ((rc == -1) && (errno == EINTR));
990 
991  if (rc == -1)
992  return -1;
993  }
994 
995  return mtime;
996 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
+ 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 1447 of file file.c.

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

void mutt_file_expand_fmt_quote ( char *  dest,
size_t  destlen,
const char *  fmt,
const char *  src 
)

◆ mutt_file_fclose()

int mutt_file_fclose ( FILE **  fp)

Close a FILE handle (and NULL the pointer)

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

Definition at line 153 of file file.c.

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

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

589 {
590  if (!path || !mode)
591  return NULL;
592 
593  if (mode[0] == 'w')
594  {
595  int fd;
596  int flags = O_CREAT | O_EXCL | O_NOFOLLOW;
597 
598  if (mode[1] == '+')
599  flags |= O_RDWR;
600  else
601  flags |= O_WRONLY;
602 
603  fd = mutt_file_open(path, flags);
604  if (fd < 0)
605  return NULL;
606 
607  return fdopen(fd, mode);
608  }
609  else
610  return fopen(path, mode);
611 }
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:522
#define O_NOFOLLOW
Definition: file.c:68
+ Here is the call graph for this function:

◆ mutt_file_fsync_close()

int mutt_file_fsync_close ( FILE **  fp)

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

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

Definition at line 169 of file file.c.

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

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

1496 {
1497  if (!path)
1498  return 0;
1499 
1500  struct stat sb;
1501  if (stat(path, &sb) != 0)
1502  return 0;
1503 
1504  return sb.st_size;
1505 }
+ 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 1537 of file file.c.

1538 {
1539  if (!dest || !sb)
1540  return;
1541 
1542  dest->tv_sec = 0;
1543  dest->tv_nsec = 0;
1544 
1545  switch (type)
1546  {
1547  case MUTT_STAT_ATIME:
1548  dest->tv_sec = sb->st_atime;
1549 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1550  dest->tv_nsec = sb->st_atim.tv_nsec;
1551 #endif
1552  break;
1553  case MUTT_STAT_MTIME:
1554  dest->tv_sec = sb->st_mtime;
1555 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1556  dest->tv_nsec = sb->st_mtim.tv_nsec;
1557 #endif
1558  break;
1559  case MUTT_STAT_CTIME:
1560  dest->tv_sec = sb->st_ctime;
1561 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1562  dest->tv_nsec = sb->st_ctim.tv_nsec;
1563 #endif
1564  break;
1565  }
1566 }
File/dir&#39;s ctime - creation time.
Definition: file.h:62
time_t tv_sec
Definition: file.h:48
File/dir&#39;s mtime - last modified time.
Definition: file.h:61
long tv_nsec
Definition: file.h:49
File/dir&#39;s atime - last accessed time.
Definition: file.h:60
+ 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 747 of file file.c.

748 {
749  if (!iter)
750  return false;
751 
752  char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
753  if (!p)
754  return false;
755  iter->line = p;
756  return true;
757 }
char * line
the line data
Definition: file.h:70
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:667
int line_num
line number
Definition: file.h:72
size_t size
allocated size of line data
Definition: file.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_lock()

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

(try to) lock a file using fcntl()

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

Use fcntl() to lock a file.

Use mutt_file_unlock() to unlock the file.

Definition at line 1175 of file file.c.

1176 {
1177  struct stat sb = { 0 }, prev_sb = { 0 };
1178  int count = 0;
1179  int attempt = 0;
1180 
1181  struct flock lck;
1182  memset(&lck, 0, sizeof(struct flock));
1183  lck.l_type = excl ? F_WRLCK : F_RDLCK;
1184  lck.l_whence = SEEK_SET;
1185 
1186  while (fcntl(fd, F_SETLK, &lck) == -1)
1187  {
1188  mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1189  if ((errno != EAGAIN) && (errno != EACCES))
1190  {
1191  mutt_perror("fcntl");
1192  return -1;
1193  }
1194 
1195  if (fstat(fd, &sb) != 0)
1196  sb.st_size = 0;
1197 
1198  if (count == 0)
1199  prev_sb = sb;
1200 
1201  /* only unlock file if it is unchanged */
1202  if ((prev_sb.st_size == sb.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1203  {
1204  if (timeout)
1205  mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1206  return -1;
1207  }
1208 
1209  prev_sb = sb;
1210 
1211  mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1212  sleep(1);
1213  }
1214 
1215  return 0;
1216 }
#define MAX_LOCK_ATTEMPTS
Definition: file.c:64
#define mutt_perror(...)
Definition: logging.h:85
#define mutt_message(...)
Definition: logging.h:83
#define _(a)
Definition: message.h:28
Log at debug level 1.
Definition: logging.h:40
#define mutt_error(...)
Definition: logging.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ 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 767 of file file.c.

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

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

931 {
932  char name[PATH_MAX];
933 
934  int n = snprintf(name, sizeof(name), "%s/neomutt-XXXXXX", NONULL(C_Tmpdir));
935  if (n < 0)
936  return NULL;
937 
938  int fd = mkstemp(name);
939  if (fd == -1)
940  return NULL;
941 
942  FILE *fp = fdopen(fd, "w+");
943 
944  if ((unlink(name) != 0) && (errno != ENOENT))
945  {
946  mutt_file_fclose(&fp);
947  return NULL;
948  }
949 
950  MuttLogger(0, file, line, func, 1, "created temp file '%s'\n", name);
951  return fp;
952 }
#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:153
#define PATH_MAX
Definition: mutt.h:44
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:56
+ Here is the call 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 522 of file file.c.

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

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

1383 {
1384  FILE *fp = mutt_file_fopen(file, "r");
1385  if (!fp)
1386  return NULL;
1387 
1388  buf = fgets(buf, buflen, fp);
1389  mutt_file_fclose(&fp);
1390 
1391  if (!buf)
1392  return NULL;
1393 
1394  SKIPWS(buf);
1395  char *start = buf;
1396 
1397  while ((*buf != '\0') && !isspace(*buf))
1398  buf++;
1399 
1400  *buf = '\0';
1401 
1402  return start;
1403 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define SKIPWS(ch)
Definition: string2.h:46
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
+ 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
[in]fpFile to read
[out]line_numCurrent line number (optional)
[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 667 of file file.c.

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

1348 {
1349  if (!oldfile || !newfile)
1350  return -1;
1351  if (access(oldfile, F_OK) != 0)
1352  return 1;
1353  if (access(newfile, F_OK) == 0)
1354  return 2;
1355 
1356  FILE *fp_old = fopen(oldfile, "r");
1357  if (!fp_old)
1358  return 3;
1359  FILE *fp_new = mutt_file_fopen(newfile, "w");
1360  if (!fp_new)
1361  {
1362  mutt_file_fclose(&fp_old);
1363  return 3;
1364  }
1365  mutt_file_copy_stream(fp_old, fp_new);
1366  mutt_file_fclose(&fp_new);
1367  mutt_file_fclose(&fp_old);
1368  mutt_file_unlink(oldfile);
1369  return 0;
1370 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
+ 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 468 of file file.c.

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

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

619 {
620  if (!path)
621  return;
622 
623  for (; *path; path++)
624  {
625  if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
626  *path = '_';
627  }
628 }
const char filename_safe_chars[]
Definition: file.c:61
+ Here is the caller graph for this function:

◆ mutt_file_sanitize_regex()

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

Escape any regex-magic characters in a string.

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

Definition at line 637 of file file.c.

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

1004 {
1005  if (!from || !to)
1006  return;
1007 
1008  struct utimbuf utim;
1009  struct stat st;
1010 
1011  if (stat(from, &st) != -1)
1012  {
1013  utim.actime = st.st_mtime;
1014  utim.modtime = st.st_mtime;
1015  utime(to, &utim);
1016  }
1017 }
+ 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 1599 of file file.c.

1601 {
1602  if (!sba || !sbb)
1603  return 0;
1604 
1605  struct timespec a = { 0 };
1606  struct timespec b = { 0 };
1607 
1608  mutt_file_get_stat_timespec(&a, sba, sba_type);
1609  mutt_file_get_stat_timespec(&b, sbb, sbb_type);
1610  return mutt_file_timespec_compare(&a, &b);
1611 }
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1515
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:1537
Time value with nanosecond precision.
Definition: file.h:46
+ Here is the call graph for this function:
+ 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 1577 of file file.c.

1579 {
1580  if (!sba || !b)
1581  return 0;
1582 
1583  struct timespec a = { 0 };
1584 
1585  mutt_file_get_stat_timespec(&a, sba, type);
1586  return mutt_file_timespec_compare(&a, b);
1587 }
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1515
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:1537
Time value with nanosecond precision.
Definition: file.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_symlink()

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

Create a symlink.

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

Definition at line 299 of file file.c.

300 {
301  struct stat osb, nsb;
302 
303  if (!oldpath || !newpath)
304  return -1;
305 
306  if ((unlink(newpath) == -1) && (errno != ENOENT))
307  return -1;
308 
309  if (oldpath[0] == '/')
310  {
311  if (symlink(oldpath, newpath) == -1)
312  return -1;
313  }
314  else
315  {
316  struct Buffer abs_oldpath = mutt_buffer_make(PATH_MAX);
317 
318  if (!mutt_path_getcwd(&abs_oldpath))
319  {
320  mutt_buffer_dealloc(&abs_oldpath);
321  return -1;
322  }
323 
324  mutt_buffer_addch(&abs_oldpath, '/');
325  mutt_buffer_addstr(&abs_oldpath, oldpath);
326  if (symlink(mutt_b2s(&abs_oldpath), newpath) == -1)
327  {
328  mutt_buffer_dealloc(&abs_oldpath);
329  return -1;
330  }
331 
332  mutt_buffer_dealloc(&abs_oldpath);
333  }
334 
335  if ((stat(oldpath, &osb) == -1) || (stat(newpath, &nsb) == -1) ||
336  !compare_stat(&osb, &nsb))
337  {
338  unlink(newpath);
339  return -1;
340  }
341 
342  return 0;
343 }
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:80
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:563
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
#define PATH_MAX
Definition: mutt.h:44
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_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 1515 of file file.c.

1516 {
1517  if (!a || !b)
1518  return 0;
1519  if (a->tv_sec < b->tv_sec)
1520  return -1;
1521  if (a->tv_sec > b->tv_sec)
1522  return 1;
1523 
1524  if (a->tv_nsec < b->tv_nsec)
1525  return -1;
1526  if (a->tv_nsec > b->tv_nsec)
1527  return 1;
1528  return 0;
1529 }
time_t tv_sec
Definition: file.h:48
long tv_nsec
Definition: file.h:49
+ 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 1026 of file file.c.

1027 {
1028 #ifdef HAVE_FUTIMENS
1029  struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1030  futimens(fd, times);
1031 #endif
1032 }
Time value with nanosecond precision.
Definition: file.h:46
+ Here is the caller graph for this function:

◆ mutt_file_unlink()

void mutt_file_unlink ( const char *  s)

Delete a file, carefully.

Parameters
sFilename

This won't follow symlinks.

Definition at line 195 of file file.c.

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

1312 {
1313  if (!path)
1314  return;
1315 
1316  struct stat sb;
1317 
1318  int fd = open(path, O_RDWR);
1319  if (fd == -1)
1320  return;
1321 
1322  if (mutt_file_lock(fd, true, true) == -1)
1323  {
1324  close(fd);
1325  return;
1326  }
1327 
1328  if ((fstat(fd, &sb) == 0) && (sb.st_size == 0))
1329  unlink(path);
1330 
1331  mutt_file_unlock(fd);
1332  close(fd);
1333 }
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1223
int mutt_file_lock(int fd, bool excl, bool timeout)
(try to) lock a file using fcntl()
Definition: file.c:1175
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_unlock()

int mutt_file_unlock ( int  fd)

Unlock a file previously locked by mutt_file_lock()

Parameters
fdFile descriptor to file
Return values
0Always

Definition at line 1223 of file file.c.

1224 {
1225  struct flock unlockit;
1226 
1227  memset(&unlockit, 0, sizeof(struct flock));
1228  unlockit.l_type = F_UNLCK;
1229  unlockit.l_whence = SEEK_SET;
1230  fcntl(fd, F_SETLK, &unlockit);
1231 
1232  return 0;
1233 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_resolve_symlink()

void mutt_file_resolve_symlink ( struct Buffer buf)

Resolve a symlink in place.

Parameters
bufInput/output path

Definition at line 1617 of file file.c.

1618 {
1619  struct stat st;
1620  int rc = lstat(mutt_b2s(buf), &st);
1621  if ((rc != -1) && S_ISLNK(st.st_mode))
1622  {
1623  char path[PATH_MAX];
1624  if (realpath(mutt_b2s(buf), path))
1625  {
1626  mutt_buffer_strcpy(buf, path);
1627  }
1628  }
1629 }
#define mutt_b2s(buf)
Definition: buffer.h:41
#define PATH_MAX
Definition: mutt.h:44
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_buffer_quote_filename()

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

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

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

Definition at line 836 of file file.c.

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

1433 {
1434  struct Buffer tmp = mutt_buffer_make(PATH_MAX);
1435 
1436  mutt_buffer_quote_filename(&tmp, src, true);
1437  mutt_file_expand_fmt(dest, fmt, mutt_b2s(&tmp));
1438  mutt_buffer_dealloc(&tmp);
1439 }
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:836
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:44
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:1447
+ 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 56 of file file.c.

◆ filename_safe_chars

const char filename_safe_chars[]

Definition at line 61 of file file.c.