NeoMutt  2024-12-12-29-gecf7a5
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
file.c File Reference

File management functions. More...

#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.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 "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
 
#define O_NOFOLLOW   0
 

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
  • наб

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

Definition at line 73 of file file.c.

◆ O_NOFOLLOW

#define O_NOFOLLOW   0

Definition at line 77 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 89 of file file.c.

90{
91 return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
92 (st_old->st_rdev == st_new->st_rdev);
93}
+ 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 104 of file file.c.

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

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

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

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

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

227{
228 if (!fp_in || !fp_out)
229 return -1;
230
231 size_t total = 0;
232 size_t l;
233 char buf[1024] = { 0 };
234
235 while ((l = fread(buf, 1, sizeof(buf), fp_in)) > 0)
236 {
237 if (fwrite(buf, 1, l, fp_out) != l)
238 return -1;
239 total += l;
240 }
241
242 if (fflush(fp_out) != 0)
243 return -1;
244 return total;
245}
+ Here is the caller graph for this function:

◆ mutt_file_symlink()

int mutt_file_symlink ( const char *  oldpath,
const char *  newpath 
)

Create a symlink.

Parameters
oldpathExisting pathname
newpathNew pathname
Return values
0Success
-1Error, see errno

Definition at line 254 of file file.c.

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

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

NFS-safe renaming of files.

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

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

Definition at line 310 of file file.c.

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

◆ mutt_file_rmtree()

int mutt_file_rmtree ( const char *  path)

Recursively remove a directory.

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

Definition at line 425 of file file.c.

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

◆ mutt_file_rotate()

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

Rotate a set of numbered files.

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

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

Rename:

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

Definition at line 485 of file file.c.

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

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

544{
545 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
546 {
547 return NULL;
548 }
549 errno = 0;
550 return opendir(path);
551}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:852
@ 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 564 of file file.c.

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

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

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

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

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

768{
769 if (!iter)
770 return false;
771
772 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
773 if (!p)
774 return false;
775 iter->line = p;
776 return true;
777}
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:686
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 788 of file file.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1301{
1302 FILE *fp = mutt_file_fopen(file, "r");
1303 if (!fp)
1304 return NULL;
1305
1306 buf = fgets(buf, buflen, fp);
1307 mutt_file_fclose(&fp);
1308
1309 if (!buf)
1310 return NULL;
1311
1312 SKIPWS(buf);
1313 char *start = buf;
1314
1315 while ((*buf != '\0') && !isspace(*buf))
1316 buf++;
1317
1318 *buf = '\0';
1319
1320 return start;
1321}
#define SKIPWS(ch)
Definition: string2.h:45
+ 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 1330 of file file.c.

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

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

1366{
1367 if (!dest || !fmt || !src)
1368 return;
1369
1370 const char *p = NULL;
1371 bool found = false;
1372
1373 buf_reset(dest);
1374
1375 for (p = fmt; *p; p++)
1376 {
1377 if (*p == '%')
1378 {
1379 switch (p[1])
1380 {
1381 case '%':
1382 buf_addch(dest, *p++);
1383 break;
1384 case 's':
1385 found = true;
1386 buf_addstr(dest, src);
1387 p++;
1388 break;
1389 default:
1390 buf_addch(dest, *p);
1391 break;
1392 }
1393 }
1394 else
1395 {
1396 buf_addch(dest, *p);
1397 }
1398 }
1399
1400 if (!found)
1401 {
1402 buf_addch(dest, ' ');
1403 buf_addstr(dest, src);
1404 }
1405}
+ 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 1413 of file file.c.

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

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

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

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

1515{
1516 if (!st || !b)
1517 return 0;
1518
1519 struct timespec a = { 0 };
1520
1521 mutt_file_get_stat_timespec(&a, st, type);
1522 return mutt_file_timespec_compare(&a, b);
1523}
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:1473
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1451
+ 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 1535 of file file.c.

1537{
1538 if (!st1 || !st2)
1539 return 0;
1540
1541 struct timespec a = { 0 };
1542 struct timespec b = { 0 };
1543
1544 mutt_file_get_stat_timespec(&a, st1, st1_type);
1545 mutt_file_get_stat_timespec(&b, st2, st2_type);
1546 return mutt_file_timespec_compare(&a, &b);
1547}
+ 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 1553 of file file.c.

1554{
1555 struct stat st = { 0 };
1556 int rc = lstat(buf_string(buf), &st);
1557 if ((rc != -1) && S_ISLNK(st.st_mode))
1558 {
1559 char path[PATH_MAX] = { 0 };
1560 if (realpath(buf_string(buf), path))
1561 {
1562 buf_strcpy(buf, path);
1563 }
1564 }
1565}
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 1573 of file file.c.

1574{
1575 if (!fp)
1576 return 0;
1577
1578 size_t len = mutt_str_len(str);
1579 if (len == 0)
1580 return 0;
1581
1582 return fwrite(str, 1, len, fp);
1583}
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:

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.