NeoMutt  2024-04-16-36-g75b6fb
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
file.h File Reference

File management functions. More...

#include "config.h"
#include <dirent.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.
 
#define MUTT_RL_CONT   (1 << 0)
 -continuation
 
#define MUTT_RL_EOL   (1 << 1)
 don't strip \n / \r\n
 
#define mutt_file_fopen(PATH, MODE)   mutt_file_fopen_full(PATH, MODE, __FILE__, __LINE__, __func__)
 
#define mutt_file_fclose(FP)   mutt_file_fclose_full(FP, __FILE__, __LINE__, __func__)
 

Typedefs

typedef uint8_t ReadLineFlags
 Flags for mutt_file_read_line(), e.g. MUTT_RL_CONT.
 
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...
 
enum  MuttOpenDirMode { MUTT_OPENDIR_NONE , MUTT_OPENDIR_CREATE }
 Mode flag for mutt_file_opendir() More...
 

Functions

int mutt_file_check_empty (const char *path)
 Is the mailbox empty.
 
int mutt_file_chmod_add (const char *path, mode_t mode)
 Add permissions to a file.
 
int mutt_file_chmod_add_stat (const char *path, mode_t mode, struct stat *st)
 Add permissions to a file.
 
int mutt_file_chmod_rm_stat (const char *path, mode_t mode, struct stat *st)
 Remove permissions from a file.
 
int mutt_file_copy_bytes (FILE *fp_in, FILE *fp_out, size_t size)
 Copy some content from one file to another.
 
int mutt_file_copy_stream (FILE *fp_in, FILE *fp_out)
 Copy the contents of one file into another.
 
time_t mutt_file_decrease_mtime (const char *fp, struct stat *st)
 Decrease a file's modification time by 1 second.
 
void mutt_file_expand_fmt (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename.
 
void mutt_file_expand_fmt_quote (char *dest, size_t destlen, const char *fmt, const char *src)
 
int mutt_file_fclose_full (FILE **fp, const char *file, int line, const char *func)
 Close a FILE handle (and NULL the pointer)
 
FILE * mutt_file_fopen_full (const char *path, const char *mode, const char *file, int line, const char *func)
 Call fopen() safely.
 
int mutt_file_fsync_close (FILE **fp)
 Flush the data, before closing a file (and NULL the pointer)
 
long mutt_file_get_size (const char *path)
 Get the size of a file.
 
long mutt_file_get_size_fp (FILE *fp)
 Get the size of a file.
 
void mutt_file_get_stat_timespec (struct timespec *dest, struct stat *st, enum MuttStatType type)
 Read the stat() time into a time value.
 
bool mutt_file_iter_line (struct MuttFileIter *iter, FILE *fp, ReadLineFlags flags)
 Iterate over the lines from an open file pointer.
 
int mutt_file_lock (int fd, bool excl, bool timeout)
 (Try to) Lock a file using fcntl()
 
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.
 
int mutt_file_mkdir (const char *path, mode_t mode)
 Recursively create directories.
 
int mutt_file_open (const char *path, uint32_t flags)
 Open a file.
 
DIR * mutt_file_opendir (const char *path, enum MuttOpenDirMode mode)
 Open a directory.
 
char * mutt_file_read_keyword (const char *file, char *buf, size_t buflen)
 Read a keyword from a file.
 
char * mutt_file_read_line (char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
 Read a line from a file.
 
int mutt_file_rename (const char *oldfile, const char *newfile)
 Rename a file.
 
int mutt_file_rmtree (const char *path)
 Recursively remove a directory.
 
const char * mutt_file_rotate (const char *path, int num)
 Rotate a set of numbered files.
 
int mutt_file_safe_rename (const char *src, const char *target)
 NFS-safe renaming of files.
 
void mutt_file_sanitize_filename (char *path, bool slash)
 Replace unsafe characters in a filename.
 
int mutt_file_sanitize_regex (struct Buffer *dest, const char *src)
 Escape any regex-magic characters in a string.
 
size_t mutt_file_save_str (FILE *fp, const char *str)
 Save a string to a file.
 
bool mutt_file_seek (FILE *fp, LOFF_T offset, int whence)
 Wrapper for fseeko with error handling.
 
void mutt_file_set_mtime (const char *from, const char *to)
 Set the modification time of one file from another.
 
int mutt_file_stat_compare (struct stat *st1, enum MuttStatType st1_type, struct stat *st2, enum MuttStatType st2_type)
 Compare two stat infos.
 
int mutt_file_stat_timespec_compare (struct stat *st, enum MuttStatType type, struct timespec *b)
 Compare stat info with a time value.
 
int mutt_file_symlink (const char *oldpath, const char *newpath)
 Create a symlink.
 
int mutt_file_timespec_compare (struct timespec *a, struct timespec *b)
 Compare to time values.
 
void mutt_file_touch_atime (int fd)
 Set the access time to current time.
 
void mutt_file_unlink (const char *s)
 Delete a file, carefully.
 
void mutt_file_unlink_empty (const char *path)
 Delete a file if it's empty.
 
int mutt_file_unlock (int fd)
 Unlock a file previously locked by mutt_file_lock()
 
void mutt_file_resolve_symlink (struct Buffer *buf)
 Resolve a symlink in place.
 
void buf_quote_filename (struct Buffer *buf, const char *filename, bool add_outer)
 Quote a filename to survive the shell's quoting rules.
 
void buf_file_expand_fmt_quote (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename.
 

Variables

const char FilenameSafeChars []
 Set of characters <=0x7F that are safe to use in filenames.
 

Detailed Description

File management functions.

Authors
  • Richard Russon
  • Pietro Cerutti

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 40 of file file.h.

◆ MUTT_RL_CONT

#define MUTT_RL_CONT   (1 << 0)

-continuation

Definition at line 41 of file file.h.

◆ MUTT_RL_EOL

#define MUTT_RL_EOL   (1 << 1)

don't strip \n / \r\n

Definition at line 42 of file file.h.

◆ mutt_file_fopen

#define mutt_file_fopen (   PATH,
  MODE 
)    mutt_file_fopen_full(PATH, MODE, __FILE__, __LINE__, __func__)

Definition at line 146 of file file.h.

◆ mutt_file_fclose

#define mutt_file_fclose (   FP)    mutt_file_fclose_full(FP, __FILE__, __LINE__, __func__)

Definition at line 147 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 39 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 99 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 62 of file file.h.

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

◆ MuttOpenDirMode

Mode flag for mutt_file_opendir()

Enumerator
MUTT_OPENDIR_NONE 

Plain opendir()

MUTT_OPENDIR_CREATE 

Create the directory if it doesn't exist.

Definition at line 72 of file file.h.

73{
76};
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:75
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:74

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

1434{
1435 if (!path)
1436 return -1;
1437
1438 struct stat st = { 0 };
1439 if (stat(path, &st) == -1)
1440 return -1;
1441
1442 return st.st_size == 0;
1443}
+ Here is the caller graph for this function:

◆ mutt_file_chmod_add()

int mutt_file_chmod_add ( const char *  path,
mode_t  mode 
)

Add permissions to a file.

Parameters
pathFilename
modethe permissions to add
Return values
numSame as chmod(2)

Adds the given permissions to the file. Permissions not mentioned in mode will stay as they are. This function resembles the chmod ugoa+rwxXst command family. Example:

mutt_file_chmod_add(path, S_IWUSR | S_IWGRP | S_IWOTH);

will add write permissions to path but does not alter read and other permissions.

See also
mutt_file_chmod_add_stat()

Definition at line 1113 of file file.c.

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

1137{
1138 if (!path)
1139 return -1;
1140
1141 struct stat st2 = { 0 };
1142
1143 if (!st)
1144 {
1145 if (stat(path, &st2) == -1)
1146 return -1;
1147 st = &st2;
1148 }
1149 return chmod(path, st->st_mode | mode);
1150}
+ Here is the caller graph for this function:

◆ mutt_file_chmod_rm_stat()

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

Remove permissions from a file.

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

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

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

Definition at line 1170 of file file.c.

1171{
1172 if (!path)
1173 return -1;
1174
1175 struct stat st2 = { 0 };
1176
1177 if (!st)
1178 {
1179 if (stat(path, &st2) == -1)
1180 return -1;
1181 st = &st2;
1182 }
1183 return chmod(path, st->st_mode & ~mode);
1184}
+ 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 256 of file file.c.

257{
258 if (!fp_in || !fp_out)
259 return -1;
260
261 while (size > 0)
262 {
263 char buf[2048] = { 0 };
264 size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size;
265 chunk = fread(buf, 1, chunk, fp_in);
266 if (chunk < 1)
267 break;
268 if (fwrite(buf, 1, chunk, fp_out) != chunk)
269 return -1;
270
271 size -= chunk;
272 }
273
274 if (fflush(fp_out) != 0)
275 return -1;
276 return 0;
277}
+ 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
numSuccess, number of bytes copied
-1Error, see errno

Definition at line 286 of file file.c.

287{
288 if (!fp_in || !fp_out)
289 return -1;
290
291 size_t total = 0;
292 size_t l;
293 char buf[1024] = { 0 };
294
295 while ((l = fread(buf, 1, sizeof(buf), fp_in)) > 0)
296 {
297 if (fwrite(buf, 1, l, fp_out) != l)
298 return -1;
299 total += l;
300 }
301
302 if (fflush(fp_out) != 0)
303 return -1;
304 return total;
305}
+ 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 1025 of file file.c.

1026{
1027 if (!fp)
1028 return -1;
1029
1030 struct utimbuf utim = { 0 };
1031 struct stat st2 = { 0 };
1032 time_t mtime;
1033
1034 if (!st)
1035 {
1036 if (stat(fp, &st2) == -1)
1037 return -1;
1038 st = &st2;
1039 }
1040
1041 mtime = st->st_mtime;
1042 if (mtime == mutt_date_now())
1043 {
1044 mtime -= 1;
1045 utim.actime = mtime;
1046 utim.modtime = mtime;
1047 int rc;
1048 do
1049 {
1050 rc = utime(fp, &utim);
1051 } while ((rc == -1) && (errno == EINTR));
1052
1053 if (rc == -1)
1054 return -1;
1055 }
1056
1057 return mtime;
1058}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
+ 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 1468 of file file.c.

1469{
1470 if (!dest || !fmt || !src)
1471 return;
1472
1473 const char *p = NULL;
1474 bool found = false;
1475
1476 buf_reset(dest);
1477
1478 for (p = fmt; *p; p++)
1479 {
1480 if (*p == '%')
1481 {
1482 switch (p[1])
1483 {
1484 case '%':
1485 buf_addch(dest, *p++);
1486 break;
1487 case 's':
1488 found = true;
1489 buf_addstr(dest, src);
1490 p++;
1491 break;
1492 default:
1493 buf_addch(dest, *p);
1494 break;
1495 }
1496 }
1497 else
1498 {
1499 buf_addch(dest, *p);
1500 }
1501 }
1502
1503 if (!found)
1504 {
1505 buf_addch(dest, ' ');
1506 buf_addstr(dest, src);
1507 }
1508}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
+ 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_full()

int mutt_file_fclose_full ( FILE **  fp,
const char *  file,
int  line,
const char *  func 
)

Close a FILE handle (and NULL the pointer)

Parameters
[out]fpFILE handle to close
[in]fileSource file
[in]lineSource line number
[in]funcSource function
Return values
0Success
EOFError, see errno

Definition at line 164 of file file.c.

165{
166 if (!fp || !*fp)
167 return 0;
168
169 int fd = fileno(*fp);
170 int rc = fclose(*fp);
171
172 if (rc == 0)
173 {
174 MuttLogger(0, file, line, func, LL_DEBUG2, "File closed (fd=%d)\n", fd);
175 }
176 else
177 {
178 MuttLogger(0, file, line, func, LL_DEBUG2, "File close failed (fd=%d), errno=%d, %s\n",
179 fd, errno, strerror(errno));
180 }
181
182 *fp = NULL;
183 return rc;
184}
int(*) log_dispatcher_ MuttLogger)
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44

◆ mutt_file_fopen_full()

FILE * mutt_file_fopen_full ( const char *  path,
const char *  mode,
const char *  file,
int  line,
const char *  func 
)

Call fopen() safely.

Parameters
pathFilename
modeMode e.g. "r" readonly; "w" read-write
fileSource file
lineSource line number
funcSource function
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 663 of file file.c.

665{
666 if (!path || !mode)
667 return NULL;
668
669 FILE *fp = NULL;
670 if (mode[0] == 'w')
671 {
672 uint32_t flags = O_CREAT | O_EXCL | O_NOFOLLOW;
673
674 if (mode[1] == '+')
675 flags |= O_RDWR;
676 else
677 flags |= O_WRONLY;
678
679 int fd = mutt_file_open(path, flags);
680 if (fd >= 0)
681 {
682 fp = fdopen(fd, mode);
683 }
684 }
685 else
686 {
687 fp = fopen(path, mode);
688 }
689
690 if (fp)
691 {
692 MuttLogger(0, file, line, func, LL_DEBUG2, "File opened (fd=%d): %s\n",
693 fileno(fp), path);
694 }
695 else
696 {
697 MuttLogger(0, file, line, func, LL_DEBUG2, "File open failed (errno=%d, %s): %s\n",
698 errno, strerror(errno), path);
699 }
700
701 return fp;
702}
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:575
#define O_NOFOLLOW
Definition: file.c:76
+ 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 192 of file file.c.

193{
194 if (!fp || !*fp)
195 return 0;
196
197 int rc = 0;
198
199 if (fflush(*fp) || fsync(fileno(*fp)))
200 {
201 int save_errno = errno;
202 rc = -1;
204 errno = save_errno;
205 }
206 else
207 {
208 rc = mutt_file_fclose(fp);
209 }
210
211 return rc;
212}
#define mutt_file_fclose(FP)
Definition: file.h:147
+ 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 1516 of file file.c.

1517{
1518 if (!path)
1519 return 0;
1520
1521 struct stat st = { 0 };
1522 if (stat(path, &st) != 0)
1523 return 0;
1524
1525 return st.st_size;
1526}
+ 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 1534 of file file.c.

1535{
1536 if (!fp)
1537 return 0;
1538
1539 struct stat st = { 0 };
1540 if (fstat(fileno(fp), &st) != 0)
1541 return 0;
1542
1543 return st.st_size;
1544}
+ 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 1576 of file file.c.

1577{
1578 if (!dest || !st)
1579 return;
1580
1581 dest->tv_sec = 0;
1582 dest->tv_nsec = 0;
1583
1584 switch (type)
1585 {
1586 case MUTT_STAT_ATIME:
1587 dest->tv_sec = st->st_atime;
1588#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1589 dest->tv_nsec = st->st_atim.tv_nsec;
1590#endif
1591 break;
1592 case MUTT_STAT_MTIME:
1593 dest->tv_sec = st->st_mtime;
1594#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1595 dest->tv_nsec = st->st_mtim.tv_nsec;
1596#endif
1597 break;
1598 case MUTT_STAT_CTIME:
1599 dest->tv_sec = st->st_ctime;
1600#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1601 dest->tv_nsec = st->st_ctim.tv_nsec;
1602#endif
1603 break;
1604 }
1605}
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:53
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:52
+ 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:886
State record for mutt_file_iter_line()
Definition: file.h:82
char * line
the line data
Definition: file.h:83
int line_num
line number
Definition: file.h:85

Definition at line 886 of file file.c.

887{
888 if (!iter)
889 return false;
890
891 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
892 if (!p)
893 return false;
894 iter->line = p;
895 return true;
896}
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:805
size_t size
allocated size of line data
Definition: file.h:84
+ 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 1199 of file file.c.

1200{
1201 struct stat st = { 0 }, prev_sb = { 0 };
1202 int count = 0;
1203 int attempt = 0;
1204
1205 struct flock lck = { 0 };
1206 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1207 lck.l_whence = SEEK_SET;
1208
1209 while (fcntl(fd, F_SETLK, &lck) == -1)
1210 {
1211 mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1212 if ((errno != EAGAIN) && (errno != EACCES))
1213 {
1214 mutt_perror("fcntl");
1215 return -1;
1216 }
1217
1218 if (fstat(fd, &st) != 0)
1219 st.st_size = 0;
1220
1221 if (count == 0)
1222 prev_sb = st;
1223
1224 /* only unlock file if it is unchanged */
1225 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1226 {
1227 if (timeout)
1228 mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1229 return -1;
1230 }
1231
1232 prev_sb = st;
1233
1234 mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1235 sleep(1);
1236 }
1237
1238 return 0;
1239}
#define MAX_LOCK_ATTEMPTS
Definition: file.c:72
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#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 907 of file file.c.

908{
909 if (!func || !fp)
910 return false;
911
912 struct MuttFileIter iter = { 0 };
913 while (mutt_file_iter_line(&iter, fp, flags))
914 {
915 if (!(*func)(iter.line, iter.line_num, user_data))
916 {
917 FREE(&iter.line);
918 return false;
919 }
920 }
921 return true;
922}
#define FREE(x)
Definition: memory.h:45
+ 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 971 of file file.c.

972{
973 if (!path || (*path == '\0'))
974 {
975 errno = EINVAL;
976 return -1;
977 }
978
979 errno = 0;
980 char tmp_path[PATH_MAX] = { 0 };
981 const size_t len = strlen(path);
982
983 if (len >= sizeof(tmp_path))
984 {
985 errno = ENAMETOOLONG;
986 return -1;
987 }
988
989 struct stat st = { 0 };
990 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
991 return 0;
992
993 /* Create a mutable copy */
994 mutt_str_copy(tmp_path, path, sizeof(tmp_path));
995
996 for (char *p = tmp_path + 1; *p; p++)
997 {
998 if (*p != '/')
999 continue;
1000
1001 /* Temporarily truncate the path */
1002 *p = '\0';
1003
1004 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
1005 return -1;
1006
1007 *p = '/';
1008 }
1009
1010 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
1011 return -1;
1012
1013 return 0;
1014}
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:575
#define PATH_MAX
Definition: mutt.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_open()

int mutt_file_open ( const char *  path,
uint32_t  flags 
)

Open a file.

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

Definition at line 575 of file file.c.

576{
577 if (!path)
578 return -1;
579
580 int fd;
581 struct Buffer *safe_file = buf_pool_get();
582 struct Buffer *safe_dir = buf_pool_get();
583
584 if (flags & O_EXCL)
585 {
586 buf_alloc(safe_file, PATH_MAX);
587 buf_alloc(safe_dir, PATH_MAX);
588
589 if (mkwrapdir(path, safe_file, safe_dir) == -1)
590 {
591 fd = -1;
592 goto cleanup;
593 }
594
595 fd = open(buf_string(safe_file), flags, 0600);
596 if (fd < 0)
597 {
598 rmdir(buf_string(safe_dir));
599 goto cleanup;
600 }
601
602 /* NFS and I believe cygwin do not handle movement of open files well */
603 close(fd);
604 if (put_file_in_place(path, buf_string(safe_file), buf_string(safe_dir)) == -1)
605 {
606 fd = -1;
607 goto cleanup;
608 }
609 }
610
611 fd = open(path, flags & ~O_EXCL, 0600);
612 if (fd < 0)
613 goto cleanup;
614
615 /* make sure the file is not symlink */
616 struct stat st_old = { 0 };
617 struct stat st_new = { 0 };
618 if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
619 !stat_equal(&st_old, &st_new))
620 {
621 close(fd);
622 fd = -1;
623 goto cleanup;
624 }
625
626cleanup:
627 buf_pool_release(&safe_file);
628 buf_pool_release(&safe_dir);
629
630 return fd;
631}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:336
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
static bool stat_equal(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
Definition: file.c:88
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:145
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
Definition: file.c:102
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
String manipulation buffer.
Definition: buffer.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_opendir()

DIR * mutt_file_opendir ( const char *  path,
enum MuttOpenDirMode  mode 
)

Open a directory.

Parameters
pathDirectory path
modeSee MuttOpenDirMode
Return values
ptrDIR handle
NULLError, see errno

Definition at line 640 of file file.c.

641{
642 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
643 {
644 return NULL;
645 }
646 errno = 0;
647 return opendir(path);
648}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:971
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_read_keyword()

char * mutt_file_read_keyword ( const char *  file,
char *  buf,
size_t  buflen 
)

Read a keyword from a file.

Parameters
fileFile to read
bufBuffer to store the keyword
buflenLength of the buf
Return values
ptrStart of the keyword

Read one line from the start of a file. Skip any leading whitespace and extract the first token.

Definition at line 1403 of file file.c.

1404{
1405 FILE *fp = mutt_file_fopen(file, "r");
1406 if (!fp)
1407 return NULL;
1408
1409 buf = fgets(buf, buflen, fp);
1410 mutt_file_fclose(&fp);
1411
1412 if (!buf)
1413 return NULL;
1414
1415 SKIPWS(buf);
1416 char *start = buf;
1417
1418 while ((*buf != '\0') && !isspace(*buf))
1419 buf++;
1420
1421 *buf = '\0';
1422
1423 return start;
1424}
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
#define SKIPWS(ch)
Definition: string2.h:45
+ 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 805 of file file.c.

806{
807 if (!size || !fp)
808 return NULL;
809
810 size_t offset = 0;
811 char *ch = NULL;
812
813 if (!line)
814 {
815 *size = 256;
816 line = mutt_mem_malloc(*size);
817 }
818
819 while (true)
820 {
821 if (!fgets(line + offset, *size - offset, fp))
822 {
823 FREE(&line);
824 return NULL;
825 }
826 ch = strchr(line + offset, '\n');
827 if (ch)
828 {
829 if (line_num)
830 (*line_num)++;
831 if (flags & MUTT_RL_EOL)
832 return line;
833 *ch = '\0';
834 if ((ch > line) && (*(ch - 1) == '\r'))
835 *--ch = '\0';
836 if (!(flags & MUTT_RL_CONT) || (ch == line) || (*(ch - 1) != '\\'))
837 return line;
838 offset = ch - line - 1;
839 }
840 else
841 {
842 int c;
843 c = getc(fp); /* This is kind of a hack. We want to know if the
844 char at the current point in the input stream is EOF.
845 feof() will only tell us if we've already hit EOF, not
846 if the next character is EOF. So, we need to read in
847 the next character and manually check if it is EOF. */
848 if (c == EOF)
849 {
850 /* The last line of fp isn't \n terminated */
851 if (line_num)
852 (*line_num)++;
853 return line;
854 }
855 else
856 {
857 ungetc(c, fp); /* undo our damage */
858 /* There wasn't room for the line -- increase "line" */
859 offset = *size - 1; /* overwrite the terminating 0 */
860 *size += 256;
861 mutt_mem_realloc(&line, *size);
862 }
863 }
864 }
865}
#define MUTT_RL_CONT
-continuation
Definition: file.h:41
#define MUTT_RL_EOL
don't strip \n / \r\n
Definition: file.h:42
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 1368 of file file.c.

1369{
1370 if (!oldfile || !newfile)
1371 return -1;
1372 if (access(oldfile, F_OK) != 0)
1373 return 1;
1374 if (access(newfile, F_OK) == 0)
1375 return 2;
1376
1377 FILE *fp_old = mutt_file_fopen(oldfile, "r");
1378 if (!fp_old)
1379 return 3;
1380 FILE *fp_new = mutt_file_fopen(newfile, "w");
1381 if (!fp_new)
1382 {
1383 mutt_file_fclose(&fp_old);
1384 return 3;
1385 }
1386 mutt_file_copy_stream(fp_old, fp_new);
1387 mutt_file_fclose(&fp_new);
1388 mutt_file_fclose(&fp_old);
1389 mutt_file_unlink(oldfile);
1390 return 0;
1391}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:286
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:220
+ 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 485 of file file.c.

486{
487 if (!path)
488 return -1;
489
490 struct dirent *de = NULL;
491 struct stat st = { 0 };
492 int rc = 0;
493
494 DIR *dir = mutt_file_opendir(path, MUTT_OPENDIR_NONE);
495 if (!dir)
496 {
497 mutt_debug(LL_DEBUG1, "error opening directory %s\n", path);
498 return -1;
499 }
500
501 /* We avoid using the buffer pool for this function, because it
502 * invokes recursively to an unknown depth. */
503 struct Buffer *cur = buf_pool_get();
504
505 while ((de = readdir(dir)))
506 {
507 if ((mutt_str_equal(".", de->d_name)) || (mutt_str_equal("..", de->d_name)))
508 continue;
509
510 buf_printf(cur, "%s/%s", path, de->d_name);
511 /* XXX make nonrecursive version */
512
513 if (stat(buf_string(cur), &st) == -1)
514 {
515 rc = 1;
516 continue;
517 }
518
519 if (S_ISDIR(st.st_mode))
520 rc |= mutt_file_rmtree(buf_string(cur));
521 else
522 rc |= unlink(buf_string(cur));
523 }
524 closedir(dir);
525
526 rc |= rmdir(path);
527
528 buf_pool_release(&cur);
529 return rc;
530}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:640
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:485
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:654
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_rotate()

const char * mutt_file_rotate ( const char *  path,
int  count 
)

Rotate a set of numbered files.

Parameters
pathTemplate filename
countMaximum number of files
Return values
ptrName of the 0'th file

Given a template 'temp', rename files numbered 0 to (count-1).

Rename:

  • ...
  • temp1 -> temp2
  • temp0 -> temp1

Definition at line 545 of file file.c.

546{
547 if (!path)
548 return NULL;
549
550 struct Buffer *old_file = buf_pool_get();
551 struct Buffer *new_file = buf_pool_get();
552
553 /* rotate the old debug logs */
554 for (count -= 2; count >= 0; count--)
555 {
556 buf_printf(old_file, "%s%d", path, count);
557 buf_printf(new_file, "%s%d", path, count + 1);
558 (void) rename(buf_string(old_file), buf_string(new_file));
559 }
560
561 path = buf_strdup(old_file);
562 buf_pool_release(&old_file);
563 buf_pool_release(&new_file);
564
565 return path;
566}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
+ 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 370 of file file.c.

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

710{
711 if (!path)
712 return;
713
714 size_t size = strlen(path);
715
716 wchar_t c;
717 mbstate_t mbstate = { 0 };
718 for (size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
719 size -= consumed, path += consumed)
720 {
721 switch (consumed)
722 {
724 mbstate = (mbstate_t){ 0 };
725 consumed = 1;
726 memset(path, '_', consumed);
727 break;
728
730 consumed = size;
731 memset(path, '_', consumed);
732 break;
733
734 default:
735 if ((slash && (c == L'/')) || ((c <= 0x7F) && !strchr(FilenameSafeChars, c)))
736 {
737 memset(path, '_', consumed);
738 }
739 break;
740 }
741 }
742}
const char FilenameSafeChars[]
Set of characters <=0x7F that are safe to use in filenames.
Definition: file.c:70
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:106
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:104
+ 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 751 of file file.c.

752{
753 if (!dest || !src)
754 return -1;
755
756 buf_reset(dest);
757 while (*src != '\0')
758 {
759 if (strchr(RxSpecialChars, *src))
760 buf_addch(dest, '\\');
761 buf_addch(dest, *src++);
762 }
763
764 return 0;
765}
static const char RxSpecialChars[]
These characters must be escaped in regular expressions.
Definition: file.c:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_save_str()

size_t mutt_file_save_str ( FILE *  fp,
const char *  str 
)

Save a string to a file.

Parameters
fpOpen file to save to
strString to save
Return values
numBytes written to file

Definition at line 1676 of file file.c.

1677{
1678 if (!fp)
1679 return 0;
1680
1681 size_t len = mutt_str_len(str);
1682 if (len == 0)
1683 return 0;
1684
1685 return fwrite(str, 1, len, fp);
1686}
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:490
+ 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 775 of file file.c.

776{
777 if (!fp)
778 {
779 return false;
780 }
781
782 if (fseeko(fp, offset, whence) != 0)
783 {
784 mutt_perror(_("Failed to seek file: %s"), strerror(errno));
785 return false;
786 }
787
788 return true;
789}
+ 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 1065 of file file.c.

1066{
1067 if (!from || !to)
1068 return;
1069
1070 struct utimbuf utim = { 0 };
1071 struct stat st = { 0 };
1072
1073 if (stat(from, &st) != -1)
1074 {
1075 utim.actime = st.st_mtime;
1076 utim.modtime = st.st_mtime;
1077 utime(to, &utim);
1078 }
1079}
+ 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 1638 of file file.c.

1640{
1641 if (!st1 || !st2)
1642 return 0;
1643
1644 struct timespec a = { 0 };
1645 struct timespec b = { 0 };
1646
1647 mutt_file_get_stat_timespec(&a, st1, st1_type);
1648 mutt_file_get_stat_timespec(&b, st2, st2_type);
1649 return mutt_file_timespec_compare(&a, &b);
1650}
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:1576
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1554
Time value with nanosecond precision.
Definition: file.h:51
+ 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 *  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 1616 of file file.c.

1618{
1619 if (!st || !b)
1620 return 0;
1621
1622 struct timespec a = { 0 };
1623
1624 mutt_file_get_stat_timespec(&a, st, type);
1625 return mutt_file_timespec_compare(&a, b);
1626}
+ 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 314 of file file.c.

315{
316 struct stat st_old = { 0 };
317 struct stat st_new = { 0 };
318
319 if (!oldpath || !newpath)
320 return -1;
321
322 if ((unlink(newpath) == -1) && (errno != ENOENT))
323 return -1;
324
325 if (oldpath[0] == '/')
326 {
327 if (symlink(oldpath, newpath) == -1)
328 return -1;
329 }
330 else
331 {
332 struct Buffer *abs_oldpath = buf_pool_get();
333
334 if (!mutt_path_getcwd(abs_oldpath))
335 {
336 buf_pool_release(&abs_oldpath);
337 return -1;
338 }
339
340 buf_addch(abs_oldpath, '/');
341 buf_addstr(abs_oldpath, oldpath);
342 if (symlink(buf_string(abs_oldpath), newpath) == -1)
343 {
344 buf_pool_release(&abs_oldpath);
345 return -1;
346 }
347
348 buf_pool_release(&abs_oldpath);
349 }
350
351 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
352 !stat_equal(&st_old, &st_new))
353 {
354 unlink(newpath);
355 return -1;
356 }
357
358 return 0;
359}
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:469
+ 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 1554 of file file.c.

1555{
1556 if (!a || !b)
1557 return 0;
1558 if (a->tv_sec < b->tv_sec)
1559 return -1;
1560 if (a->tv_sec > b->tv_sec)
1561 return 1;
1562
1563 if (a->tv_nsec < b->tv_nsec)
1564 return -1;
1565 if (a->tv_nsec > b->tv_nsec)
1566 return 1;
1567 return 0;
1568}
+ 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 1088 of file file.c.

1089{
1090#ifdef HAVE_FUTIMENS
1091 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1092 futimens(fd, times);
1093#endif
1094}
+ 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 220 of file file.c.

221{
222 if (!s)
223 return;
224
225 struct stat st = { 0 };
226 /* Defend against symlink attacks */
227
228 const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
229 if (!is_regular_file)
230 return;
231
232 const int fd = open(s, O_RDWR | O_NOFOLLOW);
233 if (fd < 0)
234 return;
235
236 struct stat st2 = { 0 };
237 if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
238 (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
239 {
240 close(fd);
241 return;
242 }
243
244 unlink(s);
245 close(fd);
246}
+ 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 1332 of file file.c.

1333{
1334 if (!path)
1335 return;
1336
1337 struct stat st = { 0 };
1338
1339 int fd = open(path, O_RDWR);
1340 if (fd == -1)
1341 return;
1342
1343 if (mutt_file_lock(fd, true, true) == -1)
1344 {
1345 close(fd);
1346 return;
1347 }
1348
1349 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1350 unlink(path);
1351
1352 mutt_file_unlock(fd);
1353 close(fd);
1354}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1199
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1246
+ 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 1246 of file file.c.

1247{
1248 struct flock unlockit = { 0 };
1249 unlockit.l_type = F_UNLCK;
1250 unlockit.l_whence = SEEK_SET;
1251 (void) fcntl(fd, F_SETLK, &unlockit);
1252
1253 return 0;
1254}
+ 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 1656 of file file.c.

1657{
1658 struct stat st = { 0 };
1659 int rc = lstat(buf_string(buf), &st);
1660 if ((rc != -1) && S_ISLNK(st.st_mode))
1661 {
1662 char path[PATH_MAX] = { 0 };
1663 if (realpath(buf_string(buf), path))
1664 {
1665 buf_strcpy(buf, path);
1666 }
1667 }
1668}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buf_quote_filename()

void buf_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 930 of file file.c.

931{
932 if (!buf || !filename)
933 return;
934
935 buf_reset(buf);
936 if (add_outer)
937 buf_addch(buf, '\'');
938
939 for (; *filename != '\0'; filename++)
940 {
941 if ((*filename == '\'') || (*filename == '`'))
942 {
943 buf_addch(buf, '\'');
944 buf_addch(buf, '\\');
945 buf_addch(buf, *filename);
946 buf_addch(buf, '\'');
947 }
948 else
949 {
950 buf_addch(buf, *filename);
951 }
952 }
953
954 if (add_outer)
955 buf_addch(buf, '\'');
956}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buf_file_expand_fmt_quote()

void buf_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 1453 of file file.c.

1454{
1455 struct Buffer *tmp = buf_pool_get();
1456
1457 buf_quote_filename(tmp, src, true);
1458 mutt_file_expand_fmt(dest, fmt, buf_string(tmp));
1459 buf_pool_release(&tmp);
1460}
void buf_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:930
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:1468
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ FilenameSafeChars

const char FilenameSafeChars[]
extern

Set of characters <=0x7F that are safe to use in filenames.

Definition at line 70 of file file.c.