NeoMutt  2025-12-11-276-g10b23b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
file.c File Reference

File management functions. More...

#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
#include <wchar.h>
#include "file.h"
#include "buffer.h"
#include "charset.h"
#include "ctype2.h"
#include "date.h"
#include "logging2.h"
#include "memory.h"
#include "message.h"
#include "path.h"
#include "pool.h"
#include "string2.h"
+ Include dependency graph for file.c:

Go to the source code of this file.

Macros

#define MAX_LOCK_ATTEMPTS   5
 Maximum number of attempts to lock a file.
 

Functions

static bool stat_equal (struct stat *st_old, struct stat *st_new)
 Compare the struct stat's of two files/dirs.
 
int mutt_file_fclose_full (FILE **fp, const char *file, int line, const char *func)
 Close a FILE handle (and NULL the pointer)
 
int mutt_file_fsync_close (FILE **fp)
 Flush the data, before closing a file (and NULL the pointer)
 
void mutt_file_unlink (const char *s)
 Delete a file, carefully.
 
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.
 
int mutt_file_symlink (const char *oldpath, const char *newpath)
 Create a symlink.
 
int mutt_file_safe_rename (const char *src, const char *target)
 NFS-safe renaming of files.
 
int mutt_file_rmtree (const char *path)
 Recursively remove a directory.
 
const char * mutt_file_rotate (const char *path, int count)
 Rotate a set of numbered files.
 
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.
 
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.
 
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.
 
bool mutt_file_seek (FILE *fp, LOFF_T offset, int whence)
 Wrapper for fseeko with error handling.
 
char * mutt_file_read_line (char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
 Read a line from a file.
 
bool mutt_file_iter_line (struct MuttFileIter *iter, FILE *fp, ReadLineFlags flags)
 Iterate over the lines from an open file pointer.
 
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.
 
void buf_quote_filename (struct Buffer *buf, const char *filename, bool add_outer)
 Quote a filename to survive the shell's quoting rules.
 
int mutt_file_mkdir (const char *path, mode_t mode)
 Recursively create directories.
 
time_t mutt_file_decrease_mtime (const char *fp, struct stat *st)
 Decrease a file's modification time by 1 second.
 
void mutt_file_set_mtime (const char *from, const char *to)
 Set the modification time of one file from another.
 
void mutt_file_touch_atime (int fd)
 Set the access time to current time.
 
bool mutt_file_touch (const char *path)
 Make sure a file exists.
 
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_lock (int fd, bool excl, bool timeout)
 (Try to) Lock a file using fcntl()
 
int mutt_file_unlock (int fd)
 Unlock a file previously locked by mutt_file_lock()
 
void mutt_file_unlink_empty (const char *path)
 Delete a file if it's empty.
 
int mutt_file_rename (const char *oldfile, const char *newfile)
 Rename a file.
 
char * mutt_file_read_keyword (const char *file, char *buf, size_t buflen)
 Read a keyword from a file.
 
int mutt_file_check_empty (const char *path)
 Is the mailbox empty.
 
void buf_file_expand_fmt_quote (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename.
 
void mutt_file_expand_fmt (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename.
 
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.
 
int mutt_file_timespec_compare (struct timespec *a, struct timespec *b)
 Compare to time values.
 
void mutt_file_get_stat_timespec (struct timespec *dest, struct stat *st, enum MuttStatType type)
 Read the stat() time into a time value.
 
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_stat_compare (struct stat *st1, enum MuttStatType st1_type, struct stat *st2, enum MuttStatType st2_type)
 Compare two stat infos.
 
void mutt_file_resolve_symlink (struct Buffer *buf)
 Resolve a symlink in place.
 
size_t mutt_file_save_str (FILE *fp, const char *str)
 Save a string to a file.
 

Variables

static const char RxSpecialChars [] = "^.[$()|*+?{\\"
 These characters must be escaped in regular expressions.
 
const char FilenameSafeChars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"
 Set of characters <=0x7F that are safe to use in filenames.
 

Detailed Description

File management functions.

Authors
  • Reis Radomil
  • Richard Russon
  • Pietro Cerutti
  • Federico Kircheis
  • Ian Zimmerman
  • наб
  • Thomas Klausner

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.c.

Macro Definition Documentation

◆ MAX_LOCK_ATTEMPTS

#define MAX_LOCK_ATTEMPTS   5

Maximum number of attempts to lock a file.

Definition at line 74 of file file.c.

Function Documentation

◆ stat_equal()

static bool stat_equal ( struct stat * st_old,
struct stat * st_new )
static

Compare the struct stat's of two files/dirs.

Parameters
st_oldstruct stat of the first file/dir
st_newstruct stat of the second file/dir
Return values
trueThey match

This compares the device id (st_dev), inode number (st_ino) and special id (st_rdev) of the files/dirs.

Definition at line 85 of file file.c.

86{
87 return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
88 (st_old->st_rdev == st_new->st_rdev);
89}
+ Here is the caller graph for this function:

◆ 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_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:139
+ 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_RDWR | O_NOFOLLOW);
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_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 while (size > 0)
198 {
199 char buf[2048] = { 0 };
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 (fflush(fp_out) != 0)
211 return -1;
212 return 0;
213}
+ 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 222 of file file.c.

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

251{
252 struct stat st_old = { 0 };
253 struct stat st_new = { 0 };
254
255 if (!oldpath || !newpath)
256 return -1;
257
258 if ((unlink(newpath) == -1) && (errno != ENOENT))
259 return -1;
260
261 if (oldpath[0] == '/')
262 {
263 if (symlink(oldpath, newpath) == -1)
264 return -1;
265 }
266 else
267 {
268 struct Buffer *abs_oldpath = buf_pool_get();
269
270 if (!mutt_path_getcwd(abs_oldpath))
271 {
272 buf_pool_release(&abs_oldpath);
273 return -1;
274 }
275
276 buf_addch(abs_oldpath, '/');
277 buf_addstr(abs_oldpath, oldpath);
278 if (symlink(buf_string(abs_oldpath), newpath) == -1)
279 {
280 buf_pool_release(&abs_oldpath);
281 return -1;
282 }
283
284 buf_pool_release(&abs_oldpath);
285 }
286
287 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
288 !stat_equal(&st_old, &st_new))
289 {
290 unlink(newpath);
291 return -1;
292 }
293
294 return 0;
295}
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
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
static bool stat_equal(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
Definition file.c:85
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition path.c:476
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_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 306 of file file.c.

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

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

482{
483 if (!path)
484 return NULL;
485
486 struct Buffer *old_file = buf_pool_get();
487 struct Buffer *new_file = buf_pool_get();
488
489 /* rotate the old debug logs */
490 for (count -= 2; count >= 0; count--)
491 {
492 buf_printf(old_file, "%s%d", path, count);
493 buf_printf(new_file, "%s%d", path, count + 1);
494 (void) rename(buf_string(old_file), buf_string(new_file));
495 }
496
497 path = buf_strdup(old_file);
498 buf_pool_release(&old_file);
499 buf_pool_release(&new_file);
500
501 return path;
502}
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_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 512 of file file.c.

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

540{
541 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
542 {
543 return NULL;
544 }
545 errno = 0;
546 return opendir(path);
547}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:848
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition file.h:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

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

587{
588 if (!path)
589 return;
590
591 size_t size = strlen(path);
592
593 wchar_t c;
594 mbstate_t mbstate = { 0 };
595 for (size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
596 size -= consumed, path += consumed)
597 {
598 switch (consumed)
599 {
601 mbstate = (mbstate_t) { 0 };
602 consumed = 1;
603 memset(path, '_', consumed);
604 break;
605
607 consumed = size;
608 memset(path, '_', consumed);
609 break;
610
611 default:
612 if ((slash && (c == L'/')) || ((c <= 0x7F) && !strchr(FilenameSafeChars, c)))
613 {
614 memset(path, '_', consumed);
615 }
616 break;
617 }
618 }
619}
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 628 of file file.c.

629{
630 if (!dest || !src)
631 return -1;
632
633 buf_reset(dest);
634 while (*src != '\0')
635 {
636 if (strchr(RxSpecialChars, *src))
637 buf_addch(dest, '\\');
638 buf_addch(dest, *src++);
639 }
640
641 return 0;
642}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
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_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 652 of file file.c.

653{
654 if (!fp)
655 {
656 return false;
657 }
658
659 if (fseeko(fp, offset, whence) != 0)
660 {
661 mutt_perror(_("Failed to seek file: %s"), strerror(errno));
662 return false;
663 }
664
665 return true;
666}
#define mutt_perror(...)
Definition logging2.h:95
#define _(a)
Definition message.h:28
+ 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 682 of file file.c.

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

764{
765 if (!iter)
766 return false;
767
768 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
769 if (!p)
770 return false;
771 iter->line = p;
772 return true;
773}
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:682
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_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 784 of file file.c.

785{
786 if (!func || !fp)
787 return false;
788
789 struct MuttFileIter iter = { 0 };
790 while (mutt_file_iter_line(&iter, fp, flags))
791 {
792 if (!(*func)(iter.line, iter.line_num, user_data))
793 {
794 FREE(&iter.line);
795 return false;
796 }
797 }
798 return true;
799}
+ 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 807 of file file.c.

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

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

903{
904 if (!fp)
905 return -1;
906
907 struct utimbuf utim = { 0 };
908 struct stat st2 = { 0 };
909 time_t mtime;
910
911 if (!st)
912 {
913 if (stat(fp, &st2) == -1)
914 return -1;
915 st = &st2;
916 }
917
918 mtime = st->st_mtime;
919 if (mtime == mutt_date_now())
920 {
921 mtime -= 1;
922 utim.actime = mtime;
923 utim.modtime = mtime;
924 int rc;
925 do
926 {
927 rc = utime(fp, &utim);
928 } while ((rc == -1) && (errno == EINTR));
929
930 if (rc == -1)
931 return -1;
932 }
933
934 return mtime;
935}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_set_mtime()

void mutt_file_set_mtime ( const char * from,
const char * to )

Set the modification time of one file from another.

Parameters
fromFilename whose mtime should be copied
toFilename to update

Definition at line 942 of file file.c.

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

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

979{
980 FILE *fp = mutt_file_fopen(path, "w");
981 if (!fp)
982 {
983 return false;
984 }
985 mutt_file_fclose(&fp);
986 return true;
987}
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
+ 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 1006 of file file.c.

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

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

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

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

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

1226{
1227 if (!path)
1228 return;
1229
1230 struct stat st = { 0 };
1231
1232 int fd = open(path, O_RDWR);
1233 if (fd == -1)
1234 return;
1235
1236 if (mutt_file_lock(fd, true, true) == -1)
1237 {
1238 close(fd);
1239 return;
1240 }
1241
1242 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1243 unlink(path);
1244
1245 mutt_file_unlock(fd);
1246 close(fd);
1247}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition file.c:1092
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition file.c:1139
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_rename()

int mutt_file_rename ( const char * oldfile,
const char * newfile )

Rename a file.

Parameters
oldfileOld filename
newfileNew filename
Return values
0Success
1Old file doesn't exist
2New file already exists
3Some other error
Note
on access(2) use No dangling symlink problems here due to mutt_file_fopen().

Definition at line 1261 of file file.c.

1262{
1263 if (!oldfile || !newfile)
1264 return -1;
1265 if (access(oldfile, F_OK) != 0)
1266 return 1;
1267 if (access(newfile, F_OK) == 0)
1268 return 2;
1269
1270 FILE *fp_old = mutt_file_fopen(oldfile, "r");
1271 if (!fp_old)
1272 return 3;
1273 FILE *fp_new = mutt_file_fopen(newfile, "w");
1274 if (!fp_new)
1275 {
1276 mutt_file_fclose(&fp_old);
1277 return 3;
1278 }
1279 mutt_file_copy_stream(fp_old, fp_new);
1280 mutt_file_fclose(&fp_new);
1281 mutt_file_fclose(&fp_old);
1282 mutt_file_unlink(oldfile);
1283 return 0;
1284}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:222
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_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 1296 of file file.c.

1297{
1298 FILE *fp = mutt_file_fopen(file, "r");
1299 if (!fp)
1300 return NULL;
1301
1302 buf = fgets(buf, buflen, fp);
1303 mutt_file_fclose(&fp);
1304
1305 if (!buf)
1306 return NULL;
1307
1308 SKIPWS(buf);
1309 char *start = buf;
1310
1311 while ((*buf != '\0') && !mutt_isspace(*buf))
1312 buf++;
1313
1314 *buf = '\0';
1315
1316 return start;
1317}
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
#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_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 1326 of file file.c.

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

1347{
1348 struct Buffer *tmp = buf_pool_get();
1349
1350 buf_quote_filename(tmp, src, true);
1351 mutt_file_expand_fmt(dest, fmt, buf_string(tmp));
1352 buf_pool_release(&tmp);
1353}
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:807
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:1361
+ 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 1361 of file file.c.

1362{
1363 if (!dest || !fmt || !src)
1364 return;
1365
1366 const char *p = NULL;
1367 bool found = false;
1368
1369 buf_reset(dest);
1370
1371 for (p = fmt; *p; p++)
1372 {
1373 if (*p == '%')
1374 {
1375 switch (p[1])
1376 {
1377 case '%':
1378 buf_addch(dest, *p++);
1379 break;
1380 case 's':
1381 found = true;
1382 buf_addstr(dest, src);
1383 p++;
1384 break;
1385 default:
1386 buf_addch(dest, *p);
1387 break;
1388 }
1389 }
1390 else
1391 {
1392 buf_addch(dest, *p);
1393 }
1394 }
1395
1396 if (!found)
1397 {
1398 buf_addch(dest, ' ');
1399 buf_addstr(dest, src);
1400 }
1401}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_get_size()

long mutt_file_get_size ( const char * path)

Get the size of a file.

Parameters
pathFile to measure
Return values
numSize in bytes
0Error

Definition at line 1409 of file file.c.

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

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

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

1470{
1471 if (!dest || !st)
1472 return;
1473
1474 dest->tv_sec = 0;
1475 dest->tv_nsec = 0;
1476
1477 switch (type)
1478 {
1479 case MUTT_STAT_ATIME:
1480 dest->tv_sec = st->st_atime;
1481#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1482 dest->tv_nsec = st->st_atim.tv_nsec;
1483#endif
1484 break;
1485 case MUTT_STAT_MTIME:
1486 dest->tv_sec = st->st_mtime;
1487#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1488 dest->tv_nsec = st->st_mtim.tv_nsec;
1489#endif
1490 break;
1491 case MUTT_STAT_CTIME:
1492 dest->tv_sec = st->st_ctime;
1493#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1494 dest->tv_nsec = st->st_ctim.tv_nsec;
1495#endif
1496 break;
1497 }
1498}
@ 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
+ 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 1509 of file file.c.

1511{
1512 if (!st || !b)
1513 return 0;
1514
1515 struct timespec a = { 0 };
1516
1517 mutt_file_get_stat_timespec(&a, st, type);
1518 return mutt_file_timespec_compare(&a, b);
1519}
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:1469
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition file.c:1447
+ Here is the call graph for this function:
+ 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 1531 of file file.c.

1533{
1534 if (!st1 || !st2)
1535 return 0;
1536
1537 struct timespec a = { 0 };
1538 struct timespec b = { 0 };
1539
1540 mutt_file_get_stat_timespec(&a, st1, st1_type);
1541 mutt_file_get_stat_timespec(&b, st2, st2_type);
1542 return mutt_file_timespec_compare(&a, &b);
1543}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_resolve_symlink()

void mutt_file_resolve_symlink ( struct Buffer * buf)

Resolve a symlink in place.

Parameters
bufInput/output path

Definition at line 1549 of file file.c.

1550{
1551 struct stat st = { 0 };
1552 int rc = lstat(buf_string(buf), &st);
1553 if ((rc != -1) && S_ISLNK(st.st_mode))
1554 {
1555 char path[PATH_MAX] = { 0 };
1556 if (realpath(buf_string(buf), path))
1557 {
1558 buf_strcpy(buf, path);
1559 }
1560 }
1561}
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:

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

1570{
1571 if (!fp)
1572 return 0;
1573
1574 size_t len = mutt_str_len(str);
1575 if (len == 0)
1576 return 0;
1577
1578 return fwrite(str, 1, len, fp);
1579}
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:500
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ RxSpecialChars

const char RxSpecialChars[] = "^.[$()|*+?{\\"
static

These characters must be escaped in regular expressions.

Definition at line 68 of file file.c.

◆ FilenameSafeChars

const char FilenameSafeChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"

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

Definition at line 71 of file file.c.