NeoMutt  2025-12-11-980-ge38c27
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  MuttFileIter
 State record for mutt_file_iter_line() More...
 

Macros

#define mutt_file_fopen(PATH, MODE)
 
#define mutt_file_fclose(FP)
 

Typedefs

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

Enumerations

enum  ReadLineFlag { MUTT_RL_NONE = 0 , MUTT_RL_CONT = 1U << 0 , MUTT_RL_EOL = 1U << 1 }
 Flags for mutt_file_read_line(), e.g. More...
 
enum  MuttStatType { MUTT_STAT_ATIME , MUTT_STAT_MTIME , MUTT_STAT_CTIME }
 File timestamp selectors 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 mode_t perms, const char *file, int line, const char *func)
 Call fopen() safely.
 
FILE * mutt_file_fopen_masked_full (const char *path, const char *mode, const char *file, int line, const char *func)
 Wrapper around mutt_file_fopen_full()
 
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, mode_t mode)
 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.
 
bool mutt_file_touch (const char *path)
 Make sure a file exists.
 
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_file_fopen

#define mutt_file_fopen ( PATH,
MODE )
Value:
mutt_file_fopen_full(PATH, MODE, 0600, __FILE__, __LINE__, __func__)
FILE * mutt_file_fopen_full(const char *path, const char *mode, const mode_t perms, const char *file, int line, const char *func)
Call fopen() safely.
Definition file.c:556
#define PATH

Definition at line 143 of file file.h.

◆ mutt_file_fclose

#define mutt_file_fclose ( FP)
Value:
mutt_file_fclose_full(FP, __FILE__, __LINE__, __func__)
int mutt_file_fclose_full(FILE **fp, const char *file, int line, const char *func)
Close a FILE handle (and NULL the pointer)
Definition file.c:100

Definition at line 144 of file file.h.

Typedef Documentation

◆ ReadLineFlags

typedef uint8_t ReadLineFlags

Definition at line 47 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 93 of file file.h.

Enumeration Type Documentation

◆ ReadLineFlag

Flags for mutt_file_read_line(), e.g.

MUTT_RL_CONT

Enumerator
MUTT_RL_NONE 

No flags are set.

MUTT_RL_CONT 

-continuation

MUTT_RL_EOL 

don't strip \n / \r\n

Definition at line 41 of file file.h.

42{
43 MUTT_RL_NONE = 0,
44 MUTT_RL_CONT = 1U << 0,
45 MUTT_RL_EOL = 1U << 1,
46};
@ MUTT_RL_EOL
don't strip \n / \r\n
Definition file.h:45
@ MUTT_RL_CONT
-continuation
Definition file.h:44
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43

◆ MuttStatType

File timestamp selectors 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 - last status change time.

Definition at line 56 of file file.h.

57{
61};
@ MUTT_STAT_CTIME
File/dir's ctime - last status change time.
Definition file.h:60
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition file.h:58
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition file.h:59

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

67{
70};
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition file.h:69
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition file.h:68

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

1333{
1334 if (!path)
1335 return -1;
1336
1337 struct stat st = { 0 };
1338 if (stat(path, &st) == -1)
1339 return -1;
1340
1341 return st.st_size == 0;
1342}
+ 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 1002 of file file.c.

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

1026{
1027 if (!path)
1028 return -1;
1029
1030 struct stat st2 = { 0 };
1031
1032 if (!st)
1033 {
1034 if (stat(path, &st2) == -1)
1035 return -1;
1036 st = &st2;
1037 }
1038 return chmod(path, st->st_mode | mode);
1039}
+ 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 1059 of file file.c.

1060{
1061 if (!path)
1062 return -1;
1063
1064 struct stat st2 = { 0 };
1065
1066 if (!st)
1067 {
1068 if (stat(path, &st2) == -1)
1069 return -1;
1070 st = &st2;
1071 }
1072 return chmod(path, st->st_mode & ~mode);
1073}
+ 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 192 of file file.c.

193{
194 if (!fp_in || !fp_out)
195 return -1;
196
197 char buf[2048] = { 0 };
198 while (size > 0)
199 {
200 size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size;
201 chunk = fread(buf, 1, chunk, fp_in);
202 if (chunk < 1)
203 break;
204 if (fwrite(buf, 1, chunk, fp_out) != chunk)
205 return -1;
206
207 size -= chunk;
208 }
209
210 if (ferror(fp_in))
211 return -1;
212 if (fflush(fp_out) != 0)
213 return -1;
214 return 0;
215}
+ 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 224 of file file.c.

225{
226 if (!fp_in || !fp_out)
227 return -1;
228
229 size_t total = 0;
230 size_t l;
231 char buf[2048] = { 0 };
232
233 while ((l = fread(buf, 1, sizeof(buf), fp_in)) > 0)
234 {
235 if (fwrite(buf, 1, l, fp_out) != l)
236 return -1;
237 total += l;
238 }
239
240 if (ferror(fp_in))
241 return -1;
242 if (fflush(fp_out) != 0)
243 return -1;
244 return total;
245}
+ 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 898 of file file.c.

899{
900 if (!fp)
901 return -1;
902
903 struct utimbuf utim = { 0 };
904 struct stat st2 = { 0 };
905 time_t mtime;
906
907 if (!st)
908 {
909 if (stat(fp, &st2) == -1)
910 return -1;
911 st = &st2;
912 }
913
914 mtime = st->st_mtime;
915 if (mtime == mutt_date_now())
916 {
917 mtime -= 1;
918 utim.actime = mtime;
919 utim.modtime = mtime;
920 int rc;
921 do
922 {
923 rc = utime(fp, &utim);
924 } while ((rc == -1) && (errno == EINTR));
925
926 if (rc == -1)
927 return -1;
928 }
929
930 return mtime;
931}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
+ 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 1367 of file file.c.

1368{
1369 if (!dest || !fmt || !src)
1370 return;
1371
1372 const char *p = NULL;
1373 bool found = false;
1374
1375 buf_reset(dest);
1376
1377 for (p = fmt; *p; p++)
1378 {
1379 if (*p == '%')
1380 {
1381 switch (p[1])
1382 {
1383 case '%':
1384 buf_addch(dest, *p++);
1385 break;
1386 case 's':
1387 found = true;
1388 buf_addstr(dest, src);
1389 p++;
1390 break;
1391 default:
1392 buf_addch(dest, *p);
1393 break;
1394 }
1395 }
1396 else
1397 {
1398 buf_addch(dest, *p);
1399 }
1400 }
1401
1402 if (!found)
1403 {
1404 buf_addch(dest, ' ');
1405 buf_addstr(dest, src);
1406 }
1407}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
+ 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 100 of file file.c.

101{
102 if (!fp || !*fp)
103 return 0;
104
105 int fd = fileno(*fp);
106 int rc = fclose(*fp);
107
108 if (rc == 0)
109 {
110 MuttLogger(0, file, line, func, LL_DEBUG2, "File closed (fd=%d)\n", fd);
111 }
112 else
113 {
114 MuttLogger(0, file, line, func, LL_DEBUG2, "File close failed (fd=%d), errno=%d, %s\n",
115 fd, errno, strerror(errno));
116 }
117
118 *fp = NULL;
119 return rc;
120}
int log_dispatcher_t MuttLogger
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46

◆ mutt_file_fopen_full()

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

Call fopen() safely.

Parameters
pathFilename
modeMode e.g. "r" readonly; "w" write-only; "a" append; "w+" read-write
permsPermissions of the file (Relevant only when writing or appending)
fileSource file
lineSource line number
funcSource function
Return values
ptrFILE handle
NULLError, see errno

Definition at line 556 of file file.c.

558{
559 if (!path || !mode)
560 return NULL;
561
562 FILE *fp = fopen(path, mode);
563 if (fp)
564 {
565 MuttLogger(0, file, line, func, LL_DEBUG2, "File opened (fd=%d): %s\n",
566 fileno(fp), path);
567 }
568 else
569 {
570 MuttLogger(0, file, line, func, LL_DEBUG2, "File open failed (errno=%d, %s): %s\n",
571 errno, strerror(errno), path);
572 }
573
574 return fp;
575}
+ Here is the caller graph for this function:

◆ mutt_file_fopen_masked_full()

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

Wrapper around mutt_file_fopen_full()

Parameters
pathFilename
modeMode e.g. "r" readonly; "w" read-write
fileSource file
lineSource line number
funcSource function
Return values
ptrFILE handle
NULLError, see errno

Apply the user's umask, then call mutt_file_fopen_full().

Definition at line 644 of file neomutt.c.

646{
647 // Set the user's umask (saved on startup)
648 mode_t old_umask = umask(NeoMutt->user_default_umask);
649 mutt_debug(LL_DEBUG3, "umask set to %03o\n", NeoMutt->user_default_umask);
650
651 // The permissions will be limited by the umask
652 FILE *fp = mutt_file_fopen_full(path, mode, 0666, file, line, func);
653
654 umask(old_umask); // Immediately restore the umask
655 mutt_debug(LL_DEBUG3, "umask set to %03o\n", old_umask);
656
657 return fp;
658}
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
Container for Accounts, Notifications.
Definition neomutt.h:41
mode_t user_default_umask
User's default file writing permissions (inferred from umask)
Definition neomutt.h:52
+ 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 128 of file file.c.

129{
130 if (!fp || !*fp)
131 return 0;
132
133 int rc = 0;
134
135 if (fflush(*fp) || fsync(fileno(*fp)))
136 {
137 int save_errno = errno;
138 rc = -1;
140 errno = save_errno;
141 }
142 else
143 {
144 rc = mutt_file_fclose(fp);
145 }
146
147 return rc;
148}
#define mutt_file_fclose(FP)
Definition file.h:144
+ 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 1415 of file file.c.

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

1434{
1435 if (!fp)
1436 return 0;
1437
1438 struct stat st = { 0 };
1439 if (fstat(fileno(fp), &st) != 0)
1440 return 0;
1441
1442 return st.st_size;
1443}
+ 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 1475 of file file.c.

1476{
1477 if (!dest || !st)
1478 return;
1479
1480 dest->tv_sec = 0;
1481 dest->tv_nsec = 0;
1482
1483 switch (type)
1484 {
1485 case MUTT_STAT_ATIME:
1486 dest->tv_sec = st->st_atime;
1487#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1488 dest->tv_nsec = st->st_atim.tv_nsec;
1489#endif
1490 break;
1491 case MUTT_STAT_MTIME:
1492 dest->tv_sec = st->st_mtime;
1493#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1494 dest->tv_nsec = st->st_mtim.tv_nsec;
1495#endif
1496 break;
1497 case MUTT_STAT_CTIME:
1498 dest->tv_sec = st->st_ctime;
1499#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1500 dest->tv_nsec = st->st_ctim.tv_nsec;
1501#endif
1502 break;
1503 }
1504}
+ 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:759
State record for mutt_file_iter_line()
Definition file.h:76
char * line
the line data
Definition file.h:77
int line_num
line number
Definition file.h:79

Definition at line 759 of file file.c.

760{
761 if (!iter)
762 return false;
763
764 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
765 if (!p)
766 return false;
767 iter->line = p;
768 return true;
769}
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:678
size_t size
allocated size of line data
Definition file.h:78
+ 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 1088 of file file.c.

1089{
1090 struct stat st = { 0 };
1091 struct stat prev_sb = { 0 };
1092 int count = 0;
1093 int attempt = 0;
1094
1095 struct flock lck = { 0 };
1096 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1097 lck.l_whence = SEEK_SET;
1098
1099 while (fcntl(fd, F_SETLK, &lck) == -1)
1100 {
1101 mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1102 if ((errno != EAGAIN) && (errno != EACCES))
1103 {
1104 mutt_perror("fcntl");
1105 return -1;
1106 }
1107
1108 if (fstat(fd, &st) != 0)
1109 st.st_size = 0;
1110
1111 if (count == 0)
1112 prev_sb = st;
1113
1114 /* only unlock file if it is unchanged */
1115 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1116 {
1117 if (timeout)
1118 mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1119 return -1;
1120 }
1121
1122 prev_sb = st;
1123
1124 mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1125 sleep(1);
1126 }
1127
1128 return 0;
1129}
#define MAX_LOCK_ATTEMPTS
Maximum number of attempts to lock a file.
Definition file.c:74
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_perror(...)
Definition logging2.h:95
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#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 780 of file file.c.

781{
782 if (!func || !fp)
783 return false;
784
785 struct MuttFileIter iter = { 0 };
786 while (mutt_file_iter_line(&iter, fp, flags))
787 {
788 if (!(*func)(iter.line, iter.line_num, user_data))
789 {
790 FREE(&iter.line);
791 return false;
792 }
793 }
794 return true;
795}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
+ 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 844 of file file.c.

845{
846 if (!path || (*path == '\0'))
847 {
848 errno = EINVAL;
849 return -1;
850 }
851
852 errno = 0;
853 char tmp_path[PATH_MAX] = { 0 };
854 const size_t len = strlen(path);
855
856 if (len >= sizeof(tmp_path))
857 {
858 errno = ENAMETOOLONG;
859 return -1;
860 }
861
862 struct stat st = { 0 };
863 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
864 return 0;
865
866 /* Create a mutable copy */
867 mutt_str_copy(tmp_path, path, sizeof(tmp_path));
868
869 for (char *p = tmp_path + 1; *p; p++)
870 {
871 if (*p != '/')
872 continue;
873
874 /* Temporarily truncate the path */
875 *p = '\0';
876
877 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
878 return -1;
879
880 *p = '/';
881 }
882
883 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
884 return -1;
885
886 return 0;
887}
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:587
#define PATH_MAX
Definition mutt.h:49
+ 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,
mode_t mode )

Open a file.

Parameters
pathPathname to open
flagsFlags, e.g. O_EXCL
modePermissions of the file (Relevant only when writing or appending)
Return values
>0Success, file handle
-1Error

Definition at line 516 of file file.c.

517{
518 if (!path)
519 return -1;
520
521 int fd = open(path, flags | O_NOFOLLOW | O_CLOEXEC, mode);
522 if (fd < 0)
523 return -1;
524
525 return fd;
526}
+ 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 535 of file file.c.

536{
537 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
538 {
539 return NULL;
540 }
541 errno = 0;
542 return opendir(path);
543}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:844
+ 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 1299 of file file.c.

1300{
1301 if (!buf || (buflen == 0))
1302 return NULL;
1303
1304 FILE *fp = mutt_file_fopen(file, "r");
1305 if (!fp)
1306 return NULL;
1307
1308 buf = fgets(buf, buflen, fp);
1309 mutt_file_fclose(&fp);
1310
1311 if (!buf)
1312 return NULL;
1313
1314 SKIPWS(buf);
1315 char *start = buf;
1316
1317 while ((*buf != '\0') && !mutt_isspace(*buf))
1318 buf++;
1319
1320 *buf = '\0';
1321
1322 return start;
1323}
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
#define SKIPWS(ch)
Definition string2.h:52
+ 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 678 of file file.c.

679{
680 if (!size || !fp)
681 return NULL;
682
683 size_t offset = 0;
684 char *ch = NULL;
685
686 if (!line)
687 {
688 *size = 256;
689 line = MUTT_MEM_MALLOC(*size, char);
690 }
691
692 while (true)
693 {
694 if (!fgets(line + offset, *size - offset, fp))
695 {
696 FREE(&line);
697 return NULL;
698 }
699 ch = strchr(line + offset, '\n');
700 if (ch)
701 {
702 if (line_num)
703 (*line_num)++;
704 if (flags & MUTT_RL_EOL)
705 return line;
706 *ch = '\0';
707 if ((ch > line) && (*(ch - 1) == '\r'))
708 *--ch = '\0';
709 if (!(flags & MUTT_RL_CONT) || (ch == line) || (*(ch - 1) != '\\'))
710 return line;
711 offset = ch - line - 1;
712 }
713 else
714 {
715 int c;
716 c = getc(fp); /* This is kind of a hack. We want to know if the
717 char at the current point in the input stream is EOF.
718 feof() will only tell us if we've already hit EOF, not
719 if the next character is EOF. So, we need to read in
720 the next character and manually check if it is EOF. */
721 if (c == EOF)
722 {
723 /* The last line of fp isn't \n terminated */
724 if (line_num)
725 (*line_num)++;
726 return line;
727 }
728 else
729 {
730 ungetc(c, fp); /* undo our damage */
731 /* There wasn't room for the line -- increase "line" */
732 offset = *size - 1; /* overwrite the terminating 0 */
733 *size += 256;
734 MUTT_MEM_REALLOC(&line, *size, char);
735 }
736 }
737 }
738}
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:53
+ 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 1258 of file file.c.

1259{
1260 if (!oldfile || !newfile)
1261 return -1;
1262 if (access(oldfile, F_OK) != 0)
1263 return 1;
1264 if (access(newfile, F_OK) == 0)
1265 return 2;
1266
1267 FILE *fp_old = mutt_file_fopen(oldfile, "r");
1268 if (!fp_old)
1269 return 3;
1270 FILE *fp_new = mutt_file_fopen(newfile, "w");
1271 if (!fp_new)
1272 {
1273 mutt_file_fclose(&fp_old);
1274 return 3;
1275 }
1276 if (mutt_file_copy_stream(fp_old, fp_new) == -1)
1277 {
1278 mutt_file_fclose(&fp_new);
1279 mutt_file_fclose(&fp_old);
1280 mutt_file_unlink(newfile);
1281 return 3;
1282 }
1283 mutt_file_fclose(&fp_new);
1284 mutt_file_fclose(&fp_old);
1285 mutt_file_unlink(oldfile);
1286 return 0;
1287}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
+ 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 425 of file file.c.

426{
427 if (!path)
428 return -1;
429
430 struct dirent *de = NULL;
431 struct stat st = { 0 };
432 int rc = 0;
433
434 DIR *dir = mutt_file_opendir(path, MUTT_OPENDIR_NONE);
435 if (!dir)
436 {
437 mutt_debug(LL_DEBUG1, "error opening directory %s\n", path);
438 return -1;
439 }
440
441 /* We avoid using the buffer pool for this function, because it
442 * invokes recursively to an unknown depth. */
443 struct Buffer *cur = buf_pool_get();
444
445 while ((de = readdir(dir)))
446 {
447 if ((mutt_str_equal(".", de->d_name)) || (mutt_str_equal("..", de->d_name)))
448 continue;
449
450 buf_printf(cur, "%s/%s", path, de->d_name);
451 /* XXX make nonrecursive version */
452
453 if (stat(buf_string(cur), &st) == -1)
454 {
455 rc = 1;
456 continue;
457 }
458
459 if (S_ISDIR(st.st_mode))
460 rc |= mutt_file_rmtree(buf_string(cur));
461 else
462 rc |= unlink(buf_string(cur));
463 }
464 closedir(dir);
465
466 rc |= rmdir(path);
467
468 buf_pool_release(&cur);
469 return rc;
470}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition file.c:535
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition file.c:425
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
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_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 485 of file file.c.

486{
487 if (!path)
488 return NULL;
489
490 struct Buffer *old_file = buf_pool_get();
491 struct Buffer *new_file = buf_pool_get();
492
493 /* rotate the old debug logs */
494 for (count -= 2; count >= 0; count--)
495 {
496 buf_printf(old_file, "%s%d", path, count);
497 buf_printf(new_file, "%s%d", path, count + 1);
498 (void) rename(buf_string(old_file), buf_string(new_file));
499 }
500
501 path = buf_strdup(old_file);
502 buf_pool_release(&old_file);
503 buf_pool_release(&new_file);
504
505 return path;
506}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
+ 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 310 of file file.c.

311{
312 struct stat st_src = { 0 };
313 struct stat st_target = { 0 };
314 int link_errno;
315
316 if (!src || !target)
317 return -1;
318
319 if (link(src, target) != 0)
320 {
321 link_errno = errno;
322
323 /* It is historically documented that link can return -1 if NFS
324 * dies after creating the link. In that case, we are supposed
325 * to use stat to check if the link was created.
326 *
327 * Derek Martin notes that some implementations of link() follow a
328 * source symlink. It might be more correct to use stat() on src.
329 * I am not doing so to minimize changes in behavior: the function
330 * used lstat() further below for 20 years without issue, and I
331 * believe was never intended to be used on a src symlink. */
332 if ((lstat(src, &st_src) == 0) && (lstat(target, &st_target) == 0) &&
333 (stat_equal(&st_src, &st_target) == 0))
334 {
335 mutt_debug(LL_DEBUG1, "link (%s, %s) reported failure: %s (%d) but actually succeeded\n",
336 src, target, strerror(errno), errno);
337 goto success;
338 }
339
340 errno = link_errno;
341
342 /* Coda does not allow cross-directory links, but tells
343 * us it's a cross-filesystem linking attempt.
344 *
345 * However, the Coda rename call is allegedly safe to use.
346 *
347 * With other file systems, rename should just fail when
348 * the files reside on different file systems, so it's safe
349 * to try it here. */
350 mutt_debug(LL_DEBUG1, "link (%s, %s) failed: %s (%d)\n", src, target,
351 strerror(errno), errno);
352
353 /* FUSE may return ENOSYS. VFAT may return EPERM. FreeBSD's
354 * msdosfs may return EOPNOTSUPP. ENOTSUP can also appear. */
355 if ((errno == EXDEV) || (errno == ENOSYS) || errno == EPERM
356#ifdef ENOTSUP
357 || errno == ENOTSUP
358#endif
359#ifdef EOPNOTSUPP
360 || errno == EOPNOTSUPP
361#endif
362 )
363 {
364 mutt_debug(LL_DEBUG1, "trying rename\n");
365 if (rename(src, target) == -1)
366 {
367 mutt_debug(LL_DEBUG1, "rename (%s, %s) failed: %s (%d)\n", src, target,
368 strerror(errno), errno);
369 return -1;
370 }
371 mutt_debug(LL_DEBUG1, "rename succeeded\n");
372
373 return 0;
374 }
375
376 return -1;
377 }
378
379 /* Remove the stat_equal() check, because it causes problems with maildir
380 * on filesystems that don't properly support hard links, such as sshfs. The
381 * filesystem creates the link, but the resulting file is given a different
382 * inode number by the sshfs layer. This results in an infinite loop
383 * creating links. */
384#if 0
385 /* Stat both links and check if they are equal. */
386 if (lstat(src, &st_src) == -1)
387 {
388 mutt_debug(LL_DEBUG1, "#1 can't stat %s: %s (%d)\n", src, strerror(errno), errno);
389 return -1;
390 }
391
392 if (lstat(target, &st_target) == -1)
393 {
394 mutt_debug(LL_DEBUG1, "#2 can't stat %s: %s (%d)\n", src, strerror(errno), errno);
395 return -1;
396 }
397
398 /* pretend that the link failed because the target file did already exist. */
399
400 if (!stat_equal(&st_src, &st_target))
401 {
402 mutt_debug(LL_DEBUG1, "stat blocks for %s and %s diverge; pretending EEXIST\n", src, target);
403 errno = EEXIST;
404 return -1;
405 }
406#endif
407
408success:
409 /* Unlink the original link.
410 * Should we really ignore the return value here? XXX */
411 if (unlink(src) == -1)
412 {
413 mutt_debug(LL_DEBUG1, "unlink (%s) failed: %s (%d)\n", src, strerror(errno), errno);
414 }
415
416 return 0;
417}
static bool stat_equal(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
Definition file.c:85
+ 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 582 of file file.c.

583{
584 if (!path)
585 return;
586
587 size_t size = strlen(path);
588
589 wchar_t c = 0;
590 mbstate_t mbstate = { 0 };
591 for (size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
592 size -= consumed, path += consumed)
593 {
594 switch (consumed)
595 {
597 mbstate = (mbstate_t) { 0 };
598 consumed = 1;
599 memset(path, '_', consumed);
600 break;
601
603 consumed = size;
604 memset(path, '_', consumed);
605 break;
606
607 default:
608 if ((slash && (c == L'/')) || ((c <= 0x7F) && !strchr(FilenameSafeChars, c)))
609 {
610 memset(path, '_', consumed);
611 }
612 break;
613 }
614 }
615}
const char FilenameSafeChars[]
Set of characters <=0x7F that are safe to use in filenames.
Definition file.c:71
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition charset.h:116
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition charset.h:114
+ 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 624 of file file.c.

625{
626 if (!dest || !src)
627 return -1;
628
629 buf_reset(dest);
630 while (*src != '\0')
631 {
632 if (strchr(RxSpecialChars, *src))
633 buf_addch(dest, '\\');
634 buf_addch(dest, *src++);
635 }
636
637 return 0;
638}
static const char RxSpecialChars[]
These characters must be escaped in regular expressions.
Definition file.c:68
+ 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 1575 of file file.c.

1576{
1577 if (!fp)
1578 return 0;
1579
1580 size_t len = mutt_str_len(str);
1581 if (len == 0)
1582 return 0;
1583
1584 return fwrite(str, 1, len, fp);
1585}
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
+ 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 648 of file file.c.

649{
650 if (!fp)
651 {
652 return false;
653 }
654
655 if (fseeko(fp, offset, whence) != 0)
656 {
657 mutt_perror(_("Failed to seek file: %s"), strerror(errno));
658 return false;
659 }
660
661 return true;
662}
+ 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 938 of file file.c.

939{
940 if (!from || !to)
941 return;
942
943 struct utimbuf utim = { 0 };
944 struct stat st = { 0 };
945
946 if (stat(from, &st) != -1)
947 {
948 utim.actime = st.st_mtime;
949 utim.modtime = st.st_mtime;
950 utime(to, &utim);
951 }
952}
+ 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 1537 of file file.c.

1539{
1540 if (!st1 || !st2)
1541 return 0;
1542
1543 struct timespec a = { 0 };
1544 struct timespec b = { 0 };
1545
1546 mutt_file_get_stat_timespec(&a, st1, st1_type);
1547 mutt_file_get_stat_timespec(&b, st2, st2_type);
1548 return mutt_file_timespec_compare(&a, &b);
1549}
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:1475
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition file.c:1453
+ 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 1515 of file file.c.

1517{
1518 if (!st || !b)
1519 return 0;
1520
1521 struct timespec a = { 0 };
1522
1523 mutt_file_get_stat_timespec(&a, st, type);
1524 return mutt_file_timespec_compare(&a, b);
1525}
+ 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 254 of file file.c.

255{
256 struct stat st_old = { 0 };
257 struct stat st_new = { 0 };
258
259 if (!oldpath || !newpath)
260 return -1;
261
262 if ((unlink(newpath) == -1) && (errno != ENOENT))
263 return -1;
264
265 if (oldpath[0] == '/')
266 {
267 if (symlink(oldpath, newpath) == -1)
268 return -1;
269 }
270 else
271 {
272 struct Buffer *abs_oldpath = buf_pool_get();
273
274 if (!mutt_path_getcwd(abs_oldpath))
275 {
276 buf_pool_release(&abs_oldpath);
277 return -1;
278 }
279
280 buf_addch(abs_oldpath, '/');
281 buf_addstr(abs_oldpath, oldpath);
282 if (symlink(buf_string(abs_oldpath), newpath) == -1)
283 {
284 buf_pool_release(&abs_oldpath);
285 return -1;
286 }
287
288 buf_pool_release(&abs_oldpath);
289 }
290
291 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
292 !stat_equal(&st_old, &st_new))
293 {
294 unlink(newpath);
295 return -1;
296 }
297
298 return 0;
299}
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition path.c:476
+ 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 1453 of file file.c.

1454{
1455 if (!a || !b)
1456 return 0;
1457 if (a->tv_sec < b->tv_sec)
1458 return -1;
1459 if (a->tv_sec > b->tv_sec)
1460 return 1;
1461
1462 if (a->tv_nsec < b->tv_nsec)
1463 return -1;
1464 if (a->tv_nsec > b->tv_nsec)
1465 return 1;
1466 return 0;
1467}
+ Here is the caller graph for this function:

◆ mutt_file_touch()

bool mutt_file_touch ( const char * path)

Make sure a file exists.

Parameters
pathFilename
Return values
trueif succeeded

Definition at line 974 of file file.c.

975{
976 FILE *fp = mutt_file_fopen(path, "w");
977 if (!fp)
978 {
979 return false;
980 }
981 mutt_file_fclose(&fp);
982 return true;
983}
+ 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 961 of file file.c.

962{
963#ifdef HAVE_FUTIMENS
964 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
965 futimens(fd, times);
966#endif
967}
+ 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 156 of file file.c.

157{
158 if (!s)
159 return;
160
161 struct stat st = { 0 };
162 /* Defend against symlink attacks */
163
164 const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
165 if (!is_regular_file)
166 return;
167
168 const int fd = open(s, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
169 if (fd < 0)
170 return;
171
172 struct stat st2 = { 0 };
173 if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
174 (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
175 {
176 close(fd);
177 return;
178 }
179
180 unlink(s);
181 close(fd);
182}
+ 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 1222 of file file.c.

1223{
1224 if (!path)
1225 return;
1226
1227 struct stat st = { 0 };
1228
1229 int fd = open(path, O_RDWR | O_NOFOLLOW | O_CLOEXEC);
1230 if (fd == -1)
1231 return;
1232
1233 if (mutt_file_lock(fd, true, true) == -1)
1234 {
1235 close(fd);
1236 return;
1237 }
1238
1239 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1240 unlink(path);
1241
1242 mutt_file_unlock(fd);
1243 close(fd);
1244}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition file.c:1088
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition file.c:1136
+ 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 1136 of file file.c.

1137{
1138 struct flock unlockit = { 0 };
1139 unlockit.l_type = F_UNLCK;
1140 unlockit.l_whence = SEEK_SET;
1141 (void) fcntl(fd, F_SETLK, &unlockit);
1142
1143 return 0;
1144}
+ 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 1555 of file file.c.

1556{
1557 struct stat st = { 0 };
1558 int rc = lstat(buf_string(buf), &st);
1559 if ((rc != -1) && S_ISLNK(st.st_mode))
1560 {
1561 char path[PATH_MAX] = { 0 };
1562 if (realpath(buf_string(buf), path))
1563 {
1564 buf_strcpy(buf, path);
1565 }
1566 }
1567}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
+ 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 803 of file file.c.

804{
805 if (!buf || !filename)
806 return;
807
808 buf_reset(buf);
809 if (add_outer)
810 buf_addch(buf, '\'');
811
812 for (; *filename != '\0'; filename++)
813 {
814 if ((*filename == '\'') || (*filename == '`'))
815 {
816 buf_addch(buf, '\'');
817 buf_addch(buf, '\\');
818 buf_addch(buf, *filename);
819 buf_addch(buf, '\'');
820 }
821 else
822 {
823 buf_addch(buf, *filename);
824 }
825 }
826
827 if (add_outer)
828 buf_addch(buf, '\'');
829}
+ 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 1352 of file file.c.

1353{
1354 struct Buffer *tmp = buf_pool_get();
1355
1356 buf_quote_filename(tmp, src, true);
1357 mutt_file_expand_fmt(dest, fmt, buf_string(tmp));
1358 buf_pool_release(&tmp);
1359}
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:803
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:1367
+ 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 71 of file file.c.