NeoMutt  2021-10-29-225-gb9986f
Teaching an old dog new tricks
DOXYGEN
file.h File Reference

File management functions. More...

#include "config.h"
#include <stdbool.h>
#include <stdint.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_RL_NO_FLAGS   0
 No flags are set. More...
 
#define MUTT_RL_CONT   (1 << 0)
 -continuation More...
 
#define MUTT_RL_EOL   (1 << 1)
 don't strip \n / \r\n More...
 
#define mutt_file_mkstemp()   mutt_file_mkstemp_full(__FILE__, __LINE__, __func__)
 

Typedefs

typedef uint8_t ReadLineFlags
 Flags for mutt_file_read_line(), e.g. MUTT_RL_CONT. More...
 
typedef bool(* mutt_file_map_t) (char *line, int line_num, void *user_data)
 

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...
 
long mutt_file_get_size_fp (FILE *fp)
 Get the size of a file. More...
 
void mutt_file_get_stat_timespec (struct timespec *dest, struct stat *st, enum MuttStatType type)
 Read the stat() time into a time value. More...
 
bool mutt_file_iter_line (struct MuttFileIter *iter, FILE *fp, ReadLineFlags 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, ReadLineFlags 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, uint32_t 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, ReadLineFlags 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...
 
bool mutt_file_seek (FILE *fp, LOFF_T offset, int whence)
 Wrapper for fseeko with error handling. 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 *st1, enum MuttStatType st1_type, struct stat *st2, enum MuttStatType st2_type)
 Compare two stat infos. More...
 
int mutt_file_stat_timespec_compare (struct stat *st, enum MuttStatType type, struct timespec *b)
 Compare stat info with a time value. More...
 
int mutt_file_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

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_RL_NO_FLAGS

#define MUTT_RL_NO_FLAGS   0

No flags are set.

Definition at line 38 of file file.h.

◆ MUTT_RL_CONT

#define MUTT_RL_CONT   (1 << 0)

-continuation

Definition at line 39 of file file.h.

◆ MUTT_RL_EOL

#define MUTT_RL_EOL   (1 << 1)

don't strip \n / \r\n

Definition at line 40 of file file.h.

◆ mutt_file_mkstemp

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

Definition at line 112 of file file.h.

Typedef Documentation

◆ ReadLineFlags

typedef uint8_t ReadLineFlags

Flags for mutt_file_read_line(), e.g. MUTT_RL_CONT.

Definition at line 37 of file file.h.

◆ mutt_file_map_t

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

Definition at line 88 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 60 of file file.h.

61 {
65 };
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:64
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition: file.h:62
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:63

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

1444 {
1445  if (!path)
1446  return -1;
1447 
1448  struct stat st = { 0 };
1449  if (stat(path, &st) == -1)
1450  return -1;
1451 
1452  return st.st_size == 0;
1453 }
+ 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 1073 of file file.c.

1074 {
1075  if (!path)
1076  return -1;
1077 
1078  return chmod(path, mode);
1079 }

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

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

1122 {
1123  if (!path)
1124  return -1;
1125 
1126  struct stat st2 = { 0 };
1127 
1128  if (!st)
1129  {
1130  if (stat(path, &st2) == -1)
1131  return -1;
1132  st = &st2;
1133  }
1134  return chmod(path, st->st_mode | mode);
1135 }
+ 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 1154 of file file.c.

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

1178 {
1179  if (!path)
1180  return -1;
1181 
1182  struct stat st2 = { 0 };
1183 
1184  if (!st)
1185  {
1186  if (stat(path, &st2) == -1)
1187  return -1;
1188  st = &st2;
1189  }
1190  return chmod(path, st->st_mode & ~mode);
1191 }
+ 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 994 of file file.c.

995 {
996  if (!fp)
997  return -1;
998 
999  struct utimbuf utim;
1000  struct stat st2 = { 0 };
1001  time_t mtime;
1002 
1003  if (!st)
1004  {
1005  if (stat(fp, &st2) == -1)
1006  return -1;
1007  st = &st2;
1008  }
1009 
1010  mtime = st->st_mtime;
1011  if (mtime == mutt_date_epoch())
1012  {
1013  mtime -= 1;
1014  utim.actime = mtime;
1015  utim.modtime = mtime;
1016  int rc;
1017  do
1018  {
1019  rc = utime(fp, &utim);
1020  } while ((rc == -1) && (errno == EINTR));
1021 
1022  if (rc == -1)
1023  return -1;
1024  }
1025 
1026  return mtime;
1027 }
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

1479 {
1480  if (!dest || !fmt || !src)
1481  return;
1482 
1483  const char *p = NULL;
1484  bool found = false;
1485 
1486  mutt_buffer_reset(dest);
1487 
1488  for (p = fmt; *p; p++)
1489  {
1490  if (*p == '%')
1491  {
1492  switch (p[1])
1493  {
1494  case '%':
1495  mutt_buffer_addch(dest, *p++);
1496  break;
1497  case 's':
1498  found = true;
1499  mutt_buffer_addstr(dest, src);
1500  p++;
1501  break;
1502  default:
1503  mutt_buffer_addch(dest, *p);
1504  break;
1505  }
1506  }
1507  else
1508  {
1509  mutt_buffer_addch(dest, *p);
1510  }
1511  }
1512 
1513  if (!found)
1514  {
1515  mutt_buffer_addch(dest, ' ');
1516  mutt_buffer_addstr(dest, src);
1517  }
1518 }
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
+ 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 593 of file file.c.

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

1527 {
1528  if (!path)
1529  return 0;
1530 
1531  struct stat st = { 0 };
1532  if (stat(path, &st) != 0)
1533  return 0;
1534 
1535  return st.st_size;
1536 }
+ Here is the caller graph for this function:

◆ mutt_file_get_size_fp()

long mutt_file_get_size_fp ( FILE *  fp)

Get the size of a file.

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

Definition at line 1544 of file file.c.

1545 {
1546  if (!fp)
1547  return 0;
1548 
1549  struct stat st = { 0 };
1550  if (fstat(fileno(fp), &st) != 0)
1551  return 0;
1552 
1553  return st.st_size;
1554 }
+ Here is the caller graph for this function:

◆ mutt_file_get_stat_timespec()

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

Read the stat() time into a time value.

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

Definition at line 1586 of file file.c.

1587 {
1588  if (!dest || !st)
1589  return;
1590 
1591  dest->tv_sec = 0;
1592  dest->tv_nsec = 0;
1593 
1594  switch (type)
1595  {
1596  case MUTT_STAT_ATIME:
1597  dest->tv_sec = st->st_atime;
1598 #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1599  dest->tv_nsec = st->st_atim.tv_nsec;
1600 #endif
1601  break;
1602  case MUTT_STAT_MTIME:
1603  dest->tv_sec = st->st_mtime;
1604 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1605  dest->tv_nsec = st->st_mtim.tv_nsec;
1606 #endif
1607  break;
1608  case MUTT_STAT_CTIME:
1609  dest->tv_sec = st->st_ctime;
1610 #ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1611  dest->tv_nsec = st->st_ctim.tv_nsec;
1612 #endif
1613  break;
1614  }
1615 }
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:51
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:50
+ Here is the caller graph for this function:

◆ mutt_file_iter_line()

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

Iterate over the lines from an open file pointer.

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

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

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

Definition at line 776 of file file.c.

777 {
778  if (!iter)
779  return false;
780 
781  char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
782  if (!p)
783  return false;
784  iter->line = p;
785  return true;
786 }
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:695
size_t size
allocated size of line data
Definition: file.h:73
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

1207 {
1208  struct stat st = { 0 }, prev_sb = { 0 };
1209  int count = 0;
1210  int attempt = 0;
1211 
1212  struct flock lck;
1213  memset(&lck, 0, sizeof(struct flock));
1214  lck.l_type = excl ? F_WRLCK : F_RDLCK;
1215  lck.l_whence = SEEK_SET;
1216 
1217  while (fcntl(fd, F_SETLK, &lck) == -1)
1218  {
1219  mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1220  if ((errno != EAGAIN) && (errno != EACCES))
1221  {
1222  mutt_perror("fcntl");
1223  return -1;
1224  }
1225 
1226  if (fstat(fd, &st) != 0)
1227  st.st_size = 0;
1228 
1229  if (count == 0)
1230  prev_sb = st;
1231 
1232  /* only unlock file if it is unchanged */
1233  if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1234  {
1235  if (timeout)
1236  mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1237  return -1;
1238  }
1239 
1240  prev_sb = st;
1241 
1242  mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1243  sleep(1);
1244  }
1245 
1246  return 0;
1247 }
#define MAX_LOCK_ATTEMPTS
Definition: file.c:64
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define _(a)
Definition: message.h:28
+ Here is the caller graph for this function:

◆ mutt_file_map_lines()

bool mutt_file_map_lines ( mutt_file_map_t  func,
void *  user_data,
FILE *  fp,
ReadLineFlags  flags 
)

Process lines of text read from a file pointer.

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

Definition at line 797 of file file.c.

798 {
799  if (!func || !fp)
800  return false;
801 
802  struct MuttFileIter iter = { 0 };
803  while (mutt_file_iter_line(&iter, fp, flags))
804  {
805  if (!(*func)(iter.line, iter.line_num, user_data))
806  {
807  FREE(&iter.line);
808  return false;
809  }
810  }
811  return true;
812 }
#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 905 of file file.c.

906 {
907  if (!path || (*path == '\0'))
908  {
909  errno = EINVAL;
910  return -1;
911  }
912 
913  errno = 0;
914  char tmp_path[PATH_MAX];
915  const size_t len = strlen(path);
916 
917  if (len >= sizeof(tmp_path))
918  {
919  errno = ENAMETOOLONG;
920  return -1;
921  }
922 
923  struct stat st = { 0 };
924  if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
925  return 0;
926 
927  /* Create a mutable copy */
928  mutt_str_copy(tmp_path, path, sizeof(tmp_path));
929 
930  for (char *p = tmp_path + 1; *p; p++)
931  {
932  if (*p != '/')
933  continue;
934 
935  /* Temporarily truncate the path */
936  *p = '\0';
937 
938  if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
939  return -1;
940 
941  *p = '/';
942  }
943 
944  if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
945  return -1;
946 
947  return 0;
948 }
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:560
#define PATH_MAX
Definition: mutt.h:40
+ 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 960 of file file.c.

961 {
962  char name[PATH_MAX];
963 
964  const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
965  int n = snprintf(name, sizeof(name), "%s/neomutt-XXXXXX", NONULL(c_tmpdir));
966  if (n < 0)
967  return NULL;
968 
969  int fd = mkstemp(name);
970  if (fd == -1)
971  return NULL;
972 
973  FILE *fp = fdopen(fd, "w+");
974 
975  if ((unlink(name) != 0) && (errno != ENOENT))
976  {
977  mutt_file_fclose(&fp);
978  return NULL;
979  }
980 
981  MuttLogger(0, file, line, func, 1, "created temp file '%s'\n", name);
982  return fp;
983 }
log_dispatcher_t MuttLogger
The log dispatcher -.
Definition: logging.c:52
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define NONULL(x)
Definition: string2.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:

◆ mutt_file_open()

int mutt_file_open ( const char *  path,
uint32_t  flags 
)

Open a file.

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

Definition at line 524 of file file.c.

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

824 {
825  if (!buf)
826  return 0;
827 
828  if (!filename)
829  {
830  *buf = '\0';
831  return 0;
832  }
833 
834  size_t j = 0;
835 
836  /* leave some space for the trailing characters. */
837  buflen -= 6;
838 
839  buf[j++] = '\'';
840 
841  for (size_t i = 0; (j < buflen) && filename[i]; i++)
842  {
843  if ((filename[i] == '\'') || (filename[i] == '`'))
844  {
845  buf[j++] = '\'';
846  buf[j++] = '\\';
847  buf[j++] = filename[i];
848  buf[j++] = '\'';
849  }
850  else
851  buf[j++] = filename[i];
852  }
853 
854  buf[j++] = '\'';
855  buf[j] = '\0';
856 
857  return j;
858 }
+ 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 1413 of file file.c.

1414 {
1415  FILE *fp = mutt_file_fopen(file, "r");
1416  if (!fp)
1417  return NULL;
1418 
1419  buf = fgets(buf, buflen, fp);
1420  mutt_file_fclose(&fp);
1421 
1422  if (!buf)
1423  return NULL;
1424 
1425  SKIPWS(buf);
1426  char *start = buf;
1427 
1428  while ((*buf != '\0') && !isspace(*buf))
1429  buf++;
1430 
1431  *buf = '\0';
1432 
1433  return start;
1434 }
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:593
#define SKIPWS(ch)
Definition: string2.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_read_line()

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

Read a line from a file.

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

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

Definition at line 695 of file file.c.

696 {
697  if (!size || !fp)
698  return NULL;
699 
700  size_t offset = 0;
701  char *ch = NULL;
702 
703  if (!line)
704  {
705  *size = 256;
706  line = mutt_mem_malloc(*size);
707  }
708 
709  while (true)
710  {
711  if (!fgets(line + offset, *size - offset, fp))
712  {
713  FREE(&line);
714  return NULL;
715  }
716  ch = strchr(line + offset, '\n');
717  if (ch)
718  {
719  if (line_num)
720  (*line_num)++;
721  if (flags & MUTT_RL_EOL)
722  return line;
723  *ch = '\0';
724  if ((ch > line) && (*(ch - 1) == '\r'))
725  *--ch = '\0';
726  if (!(flags & MUTT_RL_CONT) || (ch == line) || (*(ch - 1) != '\\'))
727  return line;
728  offset = ch - line - 1;
729  }
730  else
731  {
732  int c;
733  c = getc(fp); /* This is kind of a hack. We want to know if the
734  char at the current point in the input stream is EOF.
735  feof() will only tell us if we've already hit EOF, not
736  if the next character is EOF. So, we need to read in
737  the next character and manually check if it is EOF. */
738  if (c == EOF)
739  {
740  /* The last line of fp isn't \n terminated */
741  if (line_num)
742  (*line_num)++;
743  return line;
744  }
745  else
746  {
747  ungetc(c, fp); /* undo our damage */
748  /* There wasn't room for the line -- increase "line" */
749  offset = *size - 1; /* overwrite the terminating 0 */
750  *size += 256;
751  mutt_mem_realloc(&line, *size);
752  }
753  }
754  }
755 }
#define MUTT_RL_CONT
-continuation
Definition: file.h:39
#define MUTT_RL_EOL
don't strip \n / \r\n
Definition: file.h:40
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
+ 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 1378 of file file.c.

1379 {
1380  if (!oldfile || !newfile)
1381  return -1;
1382  if (access(oldfile, F_OK) != 0)
1383  return 1;
1384  if (access(newfile, F_OK) == 0)
1385  return 2;
1386 
1387  FILE *fp_old = fopen(oldfile, "r");
1388  if (!fp_old)
1389  return 3;
1390  FILE *fp_new = mutt_file_fopen(newfile, "w");
1391  if (!fp_new)
1392  {
1393  mutt_file_fclose(&fp_old);
1394  return 3;
1395  }
1396  mutt_file_copy_stream(fp_old, fp_new);
1397  mutt_file_fclose(&fp_new);
1398  mutt_file_fclose(&fp_old);
1399  mutt_file_unlink(oldfile);
1400  return 0;
1401 }
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_rmtree()

int mutt_file_rmtree ( const char *  path)

Recursively remove a directory.

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

Definition at line 470 of file file.c.

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

◆ mutt_file_safe_rename()

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

NFS-safe renaming of files.

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

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

Definition at line 355 of file file.c.

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

◆ mutt_file_sanitize_filename()

void mutt_file_sanitize_filename ( char *  path,
bool  slash 
)

Replace unsafe characters in a filename.

Parameters
pathFilename to make safe
slashReplace '/' characters too

Definition at line 622 of file file.c.

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

◆ mutt_file_sanitize_regex()

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

Escape any regex-magic characters in a string.

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

Definition at line 641 of file file.c.

642 {
643  if (!dest || !src)
644  return -1;
645 
646  mutt_buffer_reset(dest);
647  while (*src != '\0')
648  {
649  if (strchr(rx_special_chars, *src))
650  mutt_buffer_addch(dest, '\\');
651  mutt_buffer_addch(dest, *src++);
652  }
653 
654  return 0;
655 }
static const char rx_special_chars[]
Definition: file.c:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_seek()

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

Wrapper for fseeko with error handling.

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

Definition at line 665 of file file.c.

666 {
667  if (!fp)
668  {
669  return false;
670  }
671 
672  if (fseeko(fp, offset, whence) != 0)
673  {
674  mutt_perror(_("Failed to seek file: %s"), strerror(errno));
675  return false;
676  }
677 
678  return true;
679 }
+ 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 1034 of file file.c.

1035 {
1036  if (!from || !to)
1037  return;
1038 
1039  struct utimbuf utim;
1040  struct stat st = { 0 };
1041 
1042  if (stat(from, &st) != -1)
1043  {
1044  utim.actime = st.st_mtime;
1045  utim.modtime = st.st_mtime;
1046  utime(to, &utim);
1047  }
1048 }
+ Here is the caller graph for this function:

◆ mutt_file_stat_compare()

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

Compare two stat infos.

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

Definition at line 1648 of file file.c.

1650 {
1651  if (!st1 || !st2)
1652  return 0;
1653 
1654  struct timespec a = { 0 };
1655  struct timespec b = { 0 };
1656 
1657  mutt_file_get_stat_timespec(&a, st1, st1_type);
1658  mutt_file_get_stat_timespec(&b, st2, st2_type);
1659  return mutt_file_timespec_compare(&a, &b);
1660 }
void mutt_file_get_stat_timespec(struct timespec *dest, struct stat *st, enum MuttStatType type)
Read the stat() time into a time value.
Definition: file.c:1586
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1564
Time value with nanosecond precision.
Definition: file.h:49
+ Here is the call graph for this function:

◆ mutt_file_stat_timespec_compare()

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

Compare stat info with a time value.

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

Definition at line 1626 of file file.c.

1628 {
1629  if (!st || !b)
1630  return 0;
1631 
1632  struct timespec a = { 0 };
1633 
1634  mutt_file_get_stat_timespec(&a, st, type);
1635  return mutt_file_timespec_compare(&a, b);
1636 }
+ 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 st_old = { 0 };
302  struct stat st_new = { 0 };
303 
304  if (!oldpath || !newpath)
305  return -1;
306 
307  if ((unlink(newpath) == -1) && (errno != ENOENT))
308  return -1;
309 
310  if (oldpath[0] == '/')
311  {
312  if (symlink(oldpath, newpath) == -1)
313  return -1;
314  }
315  else
316  {
317  struct Buffer abs_oldpath = mutt_buffer_make(PATH_MAX);
318 
319  if (!mutt_path_getcwd(&abs_oldpath))
320  {
321  mutt_buffer_dealloc(&abs_oldpath);
322  return -1;
323  }
324 
325  mutt_buffer_addch(&abs_oldpath, '/');
326  mutt_buffer_addstr(&abs_oldpath, oldpath);
327  if (symlink(mutt_buffer_string(&abs_oldpath), newpath) == -1)
328  {
329  mutt_buffer_dealloc(&abs_oldpath);
330  return -1;
331  }
332 
333  mutt_buffer_dealloc(&abs_oldpath);
334  }
335 
336  if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
337  !compare_stat(&st_old, &st_new))
338  {
339  unlink(newpath);
340  return -1;
341  }
342 
343  return 0;
344 }
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:561
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

1565 {
1566  if (!a || !b)
1567  return 0;
1568  if (a->tv_sec < b->tv_sec)
1569  return -1;
1570  if (a->tv_sec > b->tv_sec)
1571  return 1;
1572 
1573  if (a->tv_nsec < b->tv_nsec)
1574  return -1;
1575  if (a->tv_nsec > b->tv_nsec)
1576  return 1;
1577  return 0;
1578 }
+ 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 1057 of file file.c.

1058 {
1059 #ifdef HAVE_FUTIMENS
1060  struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1061  futimens(fd, times);
1062 #endif
1063 }
+ Here is the caller graph for this function:

◆ mutt_file_unlink()

void mutt_file_unlink ( const char *  s)

Delete a file, carefully.

Parameters
sFilename

This won't follow symlinks.

Definition at line 195 of file file.c.

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

◆ mutt_file_unlink_empty()

void mutt_file_unlink_empty ( const char *  path)

Delete a file if it's empty.

Parameters
pathFile to delete

Definition at line 1342 of file file.c.

1343 {
1344  if (!path)
1345  return;
1346 
1347  struct stat st = { 0 };
1348 
1349  int fd = open(path, O_RDWR);
1350  if (fd == -1)
1351  return;
1352 
1353  if (mutt_file_lock(fd, true, true) == -1)
1354  {
1355  close(fd);
1356  return;
1357  }
1358 
1359  if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1360  unlink(path);
1361 
1362  mutt_file_unlock(fd);
1363  close(fd);
1364 }
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1206
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1254
+ Here is the call 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 1254 of file file.c.

1255 {
1256  struct flock unlockit;
1257 
1258  memset(&unlockit, 0, sizeof(struct flock));
1259  unlockit.l_type = F_UNLCK;
1260  unlockit.l_whence = SEEK_SET;
1261  (void) fcntl(fd, F_SETLK, &unlockit);
1262 
1263  return 0;
1264 }
+ 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 1666 of file file.c.

1667 {
1668  struct stat st = { 0 };
1669  int rc = lstat(mutt_buffer_string(buf), &st);
1670  if ((rc != -1) && S_ISLNK(st.st_mode))
1671  {
1672  char path[PATH_MAX];
1673  if (realpath(mutt_buffer_string(buf), path))
1674  {
1675  mutt_buffer_strcpy(buf, path);
1676  }
1677  }
1678 }
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 866 of file file.c.

867 {
868  if (!buf || !filename)
869  return;
870 
871  mutt_buffer_reset(buf);
872  if (add_outer)
873  mutt_buffer_addch(buf, '\'');
874 
875  for (; *filename != '\0'; filename++)
876  {
877  if ((*filename == '\'') || (*filename == '`'))
878  {
879  mutt_buffer_addch(buf, '\'');
880  mutt_buffer_addch(buf, '\\');
881  mutt_buffer_addch(buf, *filename);
882  mutt_buffer_addch(buf, '\'');
883  }
884  else
885  mutt_buffer_addch(buf, *filename);
886  }
887 
888  if (add_outer)
889  mutt_buffer_addch(buf, '\'');
890 }
+ 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 1463 of file file.c.

1464 {
1465  struct Buffer tmp = mutt_buffer_make(PATH_MAX);
1466 
1467  mutt_buffer_quote_filename(&tmp, src, true);
1468  mutt_file_expand_fmt(dest, fmt, mutt_buffer_string(&tmp));
1469  mutt_buffer_dealloc(&tmp);
1470 }
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:866
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:1478
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ filename_safe_chars

const char filename_safe_chars[]
extern

Definition at line 61 of file file.c.