NeoMutt  2025-01-09-41-g086358
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_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, 0600, __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 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_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, 0600, __FILE__, __LINE__, __func__)

Definition at line 138 of file file.h.

◆ mutt_file_fclose

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

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

Enumeration Type Documentation

◆ MuttStatType

Flags for mutt_file_get_stat_timespec.

These represent filesystem timestamps returned by stat()

Enumerator
MUTT_STAT_ATIME 

File/dir's atime - last accessed time.

MUTT_STAT_MTIME 

File/dir's mtime - last modified time.

MUTT_STAT_CTIME 

File/dir's ctime - creation time.

Definition at line 51 of file file.h.

52{
56};
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:55
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition: file.h:53
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:54

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

62{
65};
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:64
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:63

Function Documentation

◆ mutt_file_check_empty()

int mutt_file_check_empty ( const char *  path)

Is the mailbox empty.

Parameters
pathPath to mailbox
Return values
1Mailbox is empty
0Mailbox is not empty
-1Error

Definition at line 1329 of file file.c.

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

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

1033{
1034 if (!path)
1035 return -1;
1036
1037 struct stat st2 = { 0 };
1038
1039 if (!st)
1040 {
1041 if (stat(path, &st2) == -1)
1042 return -1;
1043 st = &st2;
1044 }
1045 return chmod(path, st->st_mode | mode);
1046}
+ 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 1066 of file file.c.

1067{
1068 if (!path)
1069 return -1;
1070
1071 struct stat st2 = { 0 };
1072
1073 if (!st)
1074 {
1075 if (stat(path, &st2) == -1)
1076 return -1;
1077 st = &st2;
1078 }
1079 return chmod(path, st->st_mode & ~mode);
1080}
+ 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 195 of file file.c.

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

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

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

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

104{
105 if (!fp || !*fp)
106 return 0;
107
108 int fd = fileno(*fp);
109 int rc = fclose(*fp);
110
111 if (rc == 0)
112 {
113 MuttLogger(0, file, line, func, LL_DEBUG2, "File closed (fd=%d)\n", fd);
114 }
115 else
116 {
117 MuttLogger(0, file, line, func, LL_DEBUG2, "File close failed (fd=%d), errno=%d, %s\n",
118 fd, errno, strerror(errno));
119 }
120
121 *fp = NULL;
122 return rc;
123}
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 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 563 of file file.c.

565{
566 if (!path || !mode)
567 return NULL;
568
569 FILE *fp = fopen(path, mode);
570 if (fp)
571 {
572 MuttLogger(0, file, line, func, LL_DEBUG2, "File opened (fd=%d): %s\n",
573 fileno(fp), path);
574 }
575 else
576 {
577 MuttLogger(0, file, line, func, LL_DEBUG2, "File open failed (errno=%d, %s): %s\n",
578 errno, strerror(errno), path);
579 }
580
581 return fp;
582}
+ 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 230 of file neomutt.c.

232{
233 // Set the user's umask (saved on startup)
234 mode_t old_umask = umask(NeoMutt->user_default_umask);
235 mutt_debug(LL_DEBUG3, "umask set to %03o\n", NeoMutt->user_default_umask);
236
237 // The permissions will be limited by the umask
238 FILE *fp = mutt_file_fopen_full(path, mode, 0666, file, line, func);
239
240 umask(old_umask); // Immediately restore the umask
241 mutt_debug(LL_DEBUG3, "umask set to %03o\n", old_umask);
242
243 return fp;
244}
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:563
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
Container for Accounts, Notifications.
Definition: neomutt.h:42
mode_t user_default_umask
User's default file writing permissions (inferred from umask)
Definition: neomutt.h:49
+ 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 131 of file file.c.

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

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

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

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

Definition at line 766 of file file.c.

767{
768 if (!iter)
769 return false;
770
771 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
772 if (!p)
773 return false;
774 iter->line = p;
775 return true;
776}
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:685
size_t size
allocated size of line data
Definition: file.h:73
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_lock()

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

(Try to) Lock a file using fcntl()

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

Use fcntl() to lock a file.

Use mutt_file_unlock() to unlock the file.

Definition at line 1095 of file file.c.

1096{
1097 struct stat st = { 0 }, prev_sb = { 0 };
1098 int count = 0;
1099 int attempt = 0;
1100
1101 struct flock lck = { 0 };
1102 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1103 lck.l_whence = SEEK_SET;
1104
1105 while (fcntl(fd, F_SETLK, &lck) == -1)
1106 {
1107 mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1108 if ((errno != EAGAIN) && (errno != EACCES))
1109 {
1110 mutt_perror("fcntl");
1111 return -1;
1112 }
1113
1114 if (fstat(fd, &st) != 0)
1115 st.st_size = 0;
1116
1117 if (count == 0)
1118 prev_sb = st;
1119
1120 /* only unlock file if it is unchanged */
1121 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1122 {
1123 if (timeout)
1124 mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1125 return -1;
1126 }
1127
1128 prev_sb = st;
1129
1130 mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1131 sleep(1);
1132 }
1133
1134 return 0;
1135}
#define MAX_LOCK_ATTEMPTS
Definition: file.c:72
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#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 787 of file file.c.

788{
789 if (!func || !fp)
790 return false;
791
792 struct MuttFileIter iter = { 0 };
793 while (mutt_file_iter_line(&iter, fp, flags))
794 {
795 if (!(*func)(iter.line, iter.line_num, user_data))
796 {
797 FREE(&iter.line);
798 return false;
799 }
800 }
801 return true;
802}
#define FREE(x)
Definition: memory.h:55
+ 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 851 of file file.c.

852{
853 if (!path || (*path == '\0'))
854 {
855 errno = EINVAL;
856 return -1;
857 }
858
859 errno = 0;
860 char tmp_path[PATH_MAX] = { 0 };
861 const size_t len = strlen(path);
862
863 if (len >= sizeof(tmp_path))
864 {
865 errno = ENAMETOOLONG;
866 return -1;
867 }
868
869 struct stat st = { 0 };
870 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
871 return 0;
872
873 /* Create a mutable copy */
874 mutt_str_copy(tmp_path, path, sizeof(tmp_path));
875
876 for (char *p = tmp_path + 1; *p; p++)
877 {
878 if (*p != '/')
879 continue;
880
881 /* Temporarily truncate the path */
882 *p = '\0';
883
884 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
885 return -1;
886
887 *p = '/';
888 }
889
890 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
891 return -1;
892
893 return 0;
894}
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:581
#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,
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 515 of file file.c.

516{
517 if (!path)
518 return -1;
519
520 int fd = open(path, flags & ~O_EXCL, 0600);
521 if (fd < 0)
522 return -1;
523
524 /* make sure the file is not symlink */
525 struct stat st = { 0 };
526 if ((lstat(path, &st) < 0) || S_ISLNK(st.st_mode))
527 {
528 close(fd);
529 return -1;
530 }
531
532 return fd;
533}
+ 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 542 of file file.c.

543{
544 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
545 {
546 return NULL;
547 }
548 errno = 0;
549 return opendir(path);
550}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:851
+ 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 FILE *fp = mutt_file_fopen(file, "r");
1302 if (!fp)
1303 return NULL;
1304
1305 buf = fgets(buf, buflen, fp);
1306 mutt_file_fclose(&fp);
1307
1308 if (!buf)
1309 return NULL;
1310
1311 SKIPWS(buf);
1312 char *start = buf;
1313
1314 while ((*buf != '\0') && !isspace(*buf))
1315 buf++;
1316
1317 *buf = '\0';
1318
1319 return start;
1320}
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
#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 685 of file file.c.

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

1265{
1266 if (!oldfile || !newfile)
1267 return -1;
1268 if (access(oldfile, F_OK) != 0)
1269 return 1;
1270 if (access(newfile, F_OK) == 0)
1271 return 2;
1272
1273 FILE *fp_old = mutt_file_fopen(oldfile, "r");
1274 if (!fp_old)
1275 return 3;
1276 FILE *fp_new = mutt_file_fopen(newfile, "w");
1277 if (!fp_new)
1278 {
1279 mutt_file_fclose(&fp_old);
1280 return 3;
1281 }
1282 mutt_file_copy_stream(fp_old, fp_new);
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:225
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:159
+ 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 424 of file file.c.

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

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

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

590{
591 if (!path)
592 return;
593
594 size_t size = strlen(path);
595
596 wchar_t c;
597 mbstate_t mbstate = { 0 };
598 for (size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
599 size -= consumed, path += consumed)
600 {
601 switch (consumed)
602 {
604 mbstate = (mbstate_t) { 0 };
605 consumed = 1;
606 memset(path, '_', consumed);
607 break;
608
610 consumed = size;
611 memset(path, '_', consumed);
612 break;
613
614 default:
615 if ((slash && (c == L'/')) || ((c <= 0x7F) && !strchr(FilenameSafeChars, c)))
616 {
617 memset(path, '_', consumed);
618 }
619 break;
620 }
621 }
622}
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:98
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:96
+ 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 631 of file file.c.

632{
633 if (!dest || !src)
634 return -1;
635
636 buf_reset(dest);
637 while (*src != '\0')
638 {
639 if (strchr(RxSpecialChars, *src))
640 buf_addch(dest, '\\');
641 buf_addch(dest, *src++);
642 }
643
644 return 0;
645}
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 1572 of file file.c.

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

656{
657 if (!fp)
658 {
659 return false;
660 }
661
662 if (fseeko(fp, offset, whence) != 0)
663 {
664 mutt_perror(_("Failed to seek file: %s"), strerror(errno));
665 return false;
666 }
667
668 return true;
669}
+ 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 945 of file file.c.

946{
947 if (!from || !to)
948 return;
949
950 struct utimbuf utim = { 0 };
951 struct stat st = { 0 };
952
953 if (stat(from, &st) != -1)
954 {
955 utim.actime = st.st_mtime;
956 utim.modtime = st.st_mtime;
957 utime(to, &utim);
958 }
959}
+ 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 1534 of file file.c.

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

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

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

1451{
1452 if (!a || !b)
1453 return 0;
1454 if (a->tv_sec < b->tv_sec)
1455 return -1;
1456 if (a->tv_sec > b->tv_sec)
1457 return 1;
1458
1459 if (a->tv_nsec < b->tv_nsec)
1460 return -1;
1461 if (a->tv_nsec > b->tv_nsec)
1462 return 1;
1463 return 0;
1464}
+ 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 981 of file file.c.

982{
983 FILE *fp = mutt_file_fopen(path, "w");
984 if (!fp)
985 {
986 return false;
987 }
988 mutt_file_fclose(&fp);
989 return true;
990}
+ 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 968 of file file.c.

969{
970#ifdef HAVE_FUTIMENS
971 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
972 futimens(fd, times);
973#endif
974}
+ 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 159 of file file.c.

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

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

1143{
1144 struct flock unlockit = { 0 };
1145 unlockit.l_type = F_UNLCK;
1146 unlockit.l_whence = SEEK_SET;
1147 (void) fcntl(fd, F_SETLK, &unlockit);
1148
1149 return 0;
1150}
+ 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 1552 of file file.c.

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

811{
812 if (!buf || !filename)
813 return;
814
815 buf_reset(buf);
816 if (add_outer)
817 buf_addch(buf, '\'');
818
819 for (; *filename != '\0'; filename++)
820 {
821 if ((*filename == '\'') || (*filename == '`'))
822 {
823 buf_addch(buf, '\'');
824 buf_addch(buf, '\\');
825 buf_addch(buf, *filename);
826 buf_addch(buf, '\'');
827 }
828 else
829 {
830 buf_addch(buf, *filename);
831 }
832 }
833
834 if (add_outer)
835 buf_addch(buf, '\'');
836}
+ 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 1349 of file file.c.

1350{
1351 struct Buffer *tmp = buf_pool_get();
1352
1353 buf_quote_filename(tmp, src, true);
1354 mutt_file_expand_fmt(dest, fmt, buf_string(tmp));
1355 buf_pool_release(&tmp);
1356}
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:810
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:1364
+ 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.