NeoMutt  2024-04-25-76-g20fe7b
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.
 
static int mkwrapdir (const char *path, struct Buffer *newfile, struct Buffer *newdir)
 Create a temporary directory next to a file name.
 
static int put_file_in_place (const char *path, const char *safe_file, const char *safe_dir)
 Move a file into place.
 
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.
 
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:

◆ mkwrapdir()

static int mkwrapdir ( const char *  path,
struct Buffer newfile,
struct Buffer newdir 
)
static

Create a temporary directory next to a file name.

Parameters
pathExisting filename
newfileNew filename
newdirNew directory name
Return values
0Success
-1Error

Definition at line 103 of file file.c.

104{
105 const char *basename = NULL;
106 int rc = 0;
107
108 struct Buffer *parent = buf_pool_get();
109 buf_strcpy(parent, path);
110
111 char *p = strrchr(buf_string(parent), '/');
112 if (p)
113 {
114 *p = '\0';
115 basename = p + 1;
116 }
117 else
118 {
119 buf_strcpy(parent, ".");
120 basename = path;
121 }
122
123 buf_printf(newdir, "%s/%s", buf_string(parent), ".muttXXXXXX");
124 if (!mkdtemp(newdir->data))
125 {
126 mutt_debug(LL_DEBUG1, "mkdtemp() failed\n");
127 rc = -1;
128 goto cleanup;
129 }
130
131 buf_printf(newfile, "%s/%s", buf_string(newdir), NONULL(basename));
132
133cleanup:
134 buf_pool_release(&parent);
135 return rc;
136}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ put_file_in_place()

static int put_file_in_place ( const char *  path,
const char *  safe_file,
const char *  safe_dir 
)
static

Move a file into place.

Parameters
pathDestination path
safe_fileCurrent filename
safe_dirCurrent directory name
Return values
0Success
-1Error, see errno

Definition at line 146 of file file.c.

147{
148 int rc;
149
150 rc = mutt_file_safe_rename(safe_file, path);
151 unlink(safe_file);
152 rmdir(safe_dir);
153 return rc;
154}
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:371
+ Here is the call graph for this function:
+ 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 165 of file file.c.

166{
167 if (!fp || !*fp)
168 return 0;
169
170 int fd = fileno(*fp);
171 int rc = fclose(*fp);
172
173 if (rc == 0)
174 {
175 MuttLogger(0, file, line, func, LL_DEBUG2, "File closed (fd=%d)\n", fd);
176 }
177 else
178 {
179 MuttLogger(0, file, line, func, LL_DEBUG2, "File close failed (fd=%d), errno=%d, %s\n",
180 fd, errno, strerror(errno));
181 }
182
183 *fp = NULL;
184 return rc;
185}
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 193 of file file.c.

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

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

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

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

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

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

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

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

578{
579 if (!path)
580 return -1;
581
582 int fd;
583 struct Buffer *safe_file = buf_pool_get();
584 struct Buffer *safe_dir = buf_pool_get();
585
586 if (flags & O_EXCL)
587 {
588 buf_alloc(safe_file, PATH_MAX);
589 buf_alloc(safe_dir, PATH_MAX);
590
591 if (mkwrapdir(path, safe_file, safe_dir) == -1)
592 {
593 fd = -1;
594 goto cleanup;
595 }
596
597 fd = open(buf_string(safe_file), flags, mode);
598 if (fd < 0)
599 {
600 rmdir(buf_string(safe_dir));
601 goto cleanup;
602 }
603
604 /* NFS and I believe cygwin do not handle movement of open files well */
605 close(fd);
606 if (put_file_in_place(path, buf_string(safe_file), buf_string(safe_dir)) == -1)
607 {
608 fd = -1;
609 goto cleanup;
610 }
611 }
612
613 fd = open(path, flags & ~O_EXCL, 0600);
614 if (fd < 0)
615 goto cleanup;
616
617 /* make sure the file is not symlink */
618 struct stat st_old = { 0 };
619 struct stat st_new = { 0 };
620 if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
621 !stat_equal(&st_old, &st_new))
622 {
623 close(fd);
624 fd = -1;
625 goto cleanup;
626 }
627
628cleanup:
629 buf_pool_release(&safe_file);
630 buf_pool_release(&safe_dir);
631
632 return fd;
633}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:337
static int put_file_in_place(const char *path, const char *safe_file, const char *safe_dir)
Move a file into place.
Definition: file.c:146
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
Definition: file.c:103
#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_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 642 of file file.c.

643{
644 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
645 {
646 return NULL;
647 }
648 errno = 0;
649 return opendir(path);
650}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:974
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:75
+ 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" 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

When opening files for writing, make sure the file doesn't already exist to avoid race conditions.

Definition at line 666 of file file.c.

668{
669 if (!path || !mode)
670 return NULL;
671
672 FILE *fp = NULL;
673 if (mode[0] == 'w')
674 {
675 uint32_t flags = O_CREAT | O_EXCL | O_NOFOLLOW;
676
677 if (mode[1] == '+')
678 flags |= O_RDWR;
679 else
680 flags |= O_WRONLY;
681
682 int fd = mutt_file_open(path, flags, perms);
683 if (fd >= 0)
684 {
685 fp = fdopen(fd, mode);
686 }
687 }
688 else
689 {
690 fp = fopen(path, mode);
691 }
692
693 if (fp)
694 {
695 MuttLogger(0, file, line, func, LL_DEBUG2, "File opened (fd=%d): %s\n",
696 fileno(fp), path);
697 }
698 else
699 {
700 MuttLogger(0, file, line, func, LL_DEBUG2, "File open failed (errno=%d, %s): %s\n",
701 errno, strerror(errno), path);
702 }
703
704 return fp;
705}
int mutt_file_open(const char *path, uint32_t flags, mode_t mode)
Open a file.
Definition: file.c:577
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_sanitize_filename()

void mutt_file_sanitize_filename ( char *  path,
bool  slash 
)

Replace unsafe characters in a filename.

Parameters
pathFilename to make safe
slashReplace '/' characters too

Definition at line 712 of file file.c.

713{
714 if (!path)
715 return;
716
717 size_t size = strlen(path);
718
719 wchar_t c;
720 mbstate_t mbstate = { 0 };
721 for (size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
722 size -= consumed, path += consumed)
723 {
724 switch (consumed)
725 {
727 mbstate = (mbstate_t){ 0 };
728 consumed = 1;
729 memset(path, '_', consumed);
730 break;
731
733 consumed = size;
734 memset(path, '_', consumed);
735 break;
736
737 default:
738 if ((slash && (c == L'/')) || ((c <= 0x7F) && !strchr(FilenameSafeChars, c)))
739 {
740 memset(path, '_', consumed);
741 }
742 break;
743 }
744 }
745}
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:107
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:105
+ 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 754 of file file.c.

755{
756 if (!dest || !src)
757 return -1;
758
759 buf_reset(dest);
760 while (*src != '\0')
761 {
762 if (strchr(RxSpecialChars, *src))
763 buf_addch(dest, '\\');
764 buf_addch(dest, *src++);
765 }
766
767 return 0;
768}
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 778 of file file.c.

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

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

◆ mutt_file_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:889
State record for mutt_file_iter_line()
Definition: file.h:82
char * line
the line data
Definition: file.h:83
int line_num
line number
Definition: file.h:85

Definition at line 889 of file file.c.

890{
891 if (!iter)
892 return false;
893
894 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
895 if (!p)
896 return false;
897 iter->line = p;
898 return true;
899}
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:808
size_t size
allocated size of line data
Definition: file.h:84
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

911{
912 if (!func || !fp)
913 return false;
914
915 struct MuttFileIter iter = { 0 };
916 while (mutt_file_iter_line(&iter, fp, flags))
917 {
918 if (!(*func)(iter.line, iter.line_num, user_data))
919 {
920 FREE(&iter.line);
921 return false;
922 }
923 }
924 return true;
925}
+ 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 933 of file file.c.

934{
935 if (!buf || !filename)
936 return;
937
938 buf_reset(buf);
939 if (add_outer)
940 buf_addch(buf, '\'');
941
942 for (; *filename != '\0'; filename++)
943 {
944 if ((*filename == '\'') || (*filename == '`'))
945 {
946 buf_addch(buf, '\'');
947 buf_addch(buf, '\\');
948 buf_addch(buf, *filename);
949 buf_addch(buf, '\'');
950 }
951 else
952 {
953 buf_addch(buf, *filename);
954 }
955 }
956
957 if (add_outer)
958 buf_addch(buf, '\'');
959}
+ 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 974 of file file.c.

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

1029{
1030 if (!fp)
1031 return -1;
1032
1033 struct utimbuf utim = { 0 };
1034 struct stat st2 = { 0 };
1035 time_t mtime;
1036
1037 if (!st)
1038 {
1039 if (stat(fp, &st2) == -1)
1040 return -1;
1041 st = &st2;
1042 }
1043
1044 mtime = st->st_mtime;
1045 if (mtime == mutt_date_now())
1046 {
1047 mtime -= 1;
1048 utim.actime = mtime;
1049 utim.modtime = mtime;
1050 int rc;
1051 do
1052 {
1053 rc = utime(fp, &utim);
1054 } while ((rc == -1) && (errno == EINTR));
1055
1056 if (rc == -1)
1057 return -1;
1058 }
1059
1060 return mtime;
1061}
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 1068 of file file.c.

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

1092{
1093#ifdef HAVE_FUTIMENS
1094 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1095 futimens(fd, times);
1096#endif
1097}
Time value with nanosecond precision.
Definition: file.h:51
+ 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 1116 of file file.c.

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

1140{
1141 if (!path)
1142 return -1;
1143
1144 struct stat st2 = { 0 };
1145
1146 if (!st)
1147 {
1148 if (stat(path, &st2) == -1)
1149 return -1;
1150 st = &st2;
1151 }
1152 return chmod(path, st->st_mode | mode);
1153}
+ 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 1173 of file file.c.

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

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

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

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

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

1407{
1408 FILE *fp = mutt_file_fopen(file, "r");
1409 if (!fp)
1410 return NULL;
1411
1412 buf = fgets(buf, buflen, fp);
1413 mutt_file_fclose(&fp);
1414
1415 if (!buf)
1416 return NULL;
1417
1418 SKIPWS(buf);
1419 char *start = buf;
1420
1421 while ((*buf != '\0') && !isspace(*buf))
1422 buf++;
1423
1424 *buf = '\0';
1425
1426 return start;
1427}
#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 1436 of file file.c.

1437{
1438 if (!path)
1439 return -1;
1440
1441 struct stat st = { 0 };
1442 if (stat(path, &st) == -1)
1443 return -1;
1444
1445 return st.st_size == 0;
1446}
+ 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 1456 of file file.c.

1457{
1458 struct Buffer *tmp = buf_pool_get();
1459
1460 buf_quote_filename(tmp, src, true);
1461 mutt_file_expand_fmt(dest, fmt, buf_string(tmp));
1462 buf_pool_release(&tmp);
1463}
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:933
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:1471
+ 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 1471 of file file.c.

1472{
1473 if (!dest || !fmt || !src)
1474 return;
1475
1476 const char *p = NULL;
1477 bool found = false;
1478
1479 buf_reset(dest);
1480
1481 for (p = fmt; *p; p++)
1482 {
1483 if (*p == '%')
1484 {
1485 switch (p[1])
1486 {
1487 case '%':
1488 buf_addch(dest, *p++);
1489 break;
1490 case 's':
1491 found = true;
1492 buf_addstr(dest, src);
1493 p++;
1494 break;
1495 default:
1496 buf_addch(dest, *p);
1497 break;
1498 }
1499 }
1500 else
1501 {
1502 buf_addch(dest, *p);
1503 }
1504 }
1505
1506 if (!found)
1507 {
1508 buf_addch(dest, ' ');
1509 buf_addstr(dest, src);
1510 }
1511}
+ 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 1519 of file file.c.

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

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

1558{
1559 if (!a || !b)
1560 return 0;
1561 if (a->tv_sec < b->tv_sec)
1562 return -1;
1563 if (a->tv_sec > b->tv_sec)
1564 return 1;
1565
1566 if (a->tv_nsec < b->tv_nsec)
1567 return -1;
1568 if (a->tv_nsec > b->tv_nsec)
1569 return 1;
1570 return 0;
1571}
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:53
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:52
+ Here is the caller graph for this function:

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

1580{
1581 if (!dest || !st)
1582 return;
1583
1584 dest->tv_sec = 0;
1585 dest->tv_nsec = 0;
1586
1587 switch (type)
1588 {
1589 case MUTT_STAT_ATIME:
1590 dest->tv_sec = st->st_atime;
1591#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1592 dest->tv_nsec = st->st_atim.tv_nsec;
1593#endif
1594 break;
1595 case MUTT_STAT_MTIME:
1596 dest->tv_sec = st->st_mtime;
1597#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1598 dest->tv_nsec = st->st_mtim.tv_nsec;
1599#endif
1600 break;
1601 case MUTT_STAT_CTIME:
1602 dest->tv_sec = st->st_ctime;
1603#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1604 dest->tv_nsec = st->st_ctim.tv_nsec;
1605#endif
1606 break;
1607 }
1608}
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:66
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition: file.h:64
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:65
+ 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 1619 of file file.c.

1621{
1622 if (!st || !b)
1623 return 0;
1624
1625 struct timespec a = { 0 };
1626
1627 mutt_file_get_stat_timespec(&a, st, type);
1628 return mutt_file_timespec_compare(&a, b);
1629}
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:1579
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1557
+ 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 1641 of file file.c.

1643{
1644 if (!st1 || !st2)
1645 return 0;
1646
1647 struct timespec a = { 0 };
1648 struct timespec b = { 0 };
1649
1650 mutt_file_get_stat_timespec(&a, st1, st1_type);
1651 mutt_file_get_stat_timespec(&b, st2, st2_type);
1652 return mutt_file_timespec_compare(&a, &b);
1653}
+ 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 1659 of file file.c.

1660{
1661 struct stat st = { 0 };
1662 int rc = lstat(buf_string(buf), &st);
1663 if ((rc != -1) && S_ISLNK(st.st_mode))
1664 {
1665 char path[PATH_MAX] = { 0 };
1666 if (realpath(buf_string(buf), path))
1667 {
1668 buf_strcpy(buf, path);
1669 }
1670 }
1671}
+ 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 1679 of file file.c.

1680{
1681 if (!fp)
1682 return 0;
1683
1684 size_t len = mutt_str_len(str);
1685 if (len == 0)
1686 return 0;
1687
1688 return fwrite(str, 1, len, fp);
1689}
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.