NeoMutt  2024-02-01-23-g345d7b
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 <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)
 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 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.
 
size_t mutt_file_quote_filename (const char *filename, char *buf, size_t buflen)
 Quote a filename to survive the shell's quoting rules.
 
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 72 of file file.c.

◆ O_NOFOLLOW

#define O_NOFOLLOW   0

Definition at line 76 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 88 of file file.c.

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

103{
104 const char *basename = NULL;
105 int rc = 0;
106
107 struct Buffer parent = buf_make(PATH_MAX);
108 buf_strcpy(&parent, NONULL(path));
109
110 char *p = strrchr(parent.data, '/');
111 if (p)
112 {
113 *p = '\0';
114 basename = p + 1;
115 }
116 else
117 {
118 buf_strcpy(&parent, ".");
119 basename = path;
120 }
121
122 buf_printf(newdir, "%s/%s", buf_string(&parent), ".muttXXXXXX");
123 if (!mkdtemp(newdir->data))
124 {
125 mutt_debug(LL_DEBUG1, "mkdtemp() failed\n");
126 rc = -1;
127 goto cleanup;
128 }
129
130 buf_printf(newfile, "%s/%s", newdir->data, NONULL(basename));
131
132cleanup:
133 buf_dealloc(&parent);
134 return rc;
135}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:178
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:394
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:75
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define PATH_MAX
Definition: mutt.h:42
#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 145 of file file.c.

146{
147 int rc;
148
149 rc = mutt_file_safe_rename(safe_file, path);
150 unlink(safe_file);
151 rmdir(safe_dir);
152 return rc;
153}
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:366
+ 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 164 of file file.c.

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

189{
190 if (!fp || !*fp)
191 return 0;
192
193 int rc = 0;
194
195 if (fflush(*fp) || fsync(fileno(*fp)))
196 {
197 int save_errno = errno;
198 rc = -1;
200 errno = save_errno;
201 }
202 else
203 {
204 rc = mutt_file_fclose(fp);
205 }
206
207 return rc;
208}
#define mutt_file_fclose(FP)
Definition: file.h:148
+ 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 216 of file file.c.

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

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

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

311{
312 struct stat st_old = { 0 };
313 struct stat st_new = { 0 };
314
315 if (!oldpath || !newpath)
316 return -1;
317
318 if ((unlink(newpath) == -1) && (errno != ENOENT))
319 return -1;
320
321 if (oldpath[0] == '/')
322 {
323 if (symlink(oldpath, newpath) == -1)
324 return -1;
325 }
326 else
327 {
328 struct Buffer abs_oldpath = buf_make(PATH_MAX);
329
330 if (!mutt_path_getcwd(&abs_oldpath))
331 {
332 buf_dealloc(&abs_oldpath);
333 return -1;
334 }
335
336 buf_addch(&abs_oldpath, '/');
337 buf_addstr(&abs_oldpath, oldpath);
338 if (symlink(buf_string(&abs_oldpath), newpath) == -1)
339 {
340 buf_dealloc(&abs_oldpath);
341 return -1;
342 }
343
344 buf_dealloc(&abs_oldpath);
345 }
346
347 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
348 !stat_equal(&st_old, &st_new))
349 {
350 unlink(newpath);
351 return -1;
352 }
353
354 return 0;
355}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:258
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
static bool stat_equal(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
Definition: file.c:88
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:472
+ 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 366 of file file.c.

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

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

542{
543 if (!path)
544 return NULL;
545
546 struct Buffer *old_file = buf_pool_get();
547 struct Buffer *new_file = buf_pool_get();
548
549 /* rotate the old debug logs */
550 for (count -= 2; count >= 0; count--)
551 {
552 buf_printf(old_file, "%s%d", path, count);
553 buf_printf(new_file, "%s%d", path, count + 1);
554 (void) rename(buf_string(old_file), buf_string(new_file));
555 }
556
557 path = buf_strdup(old_file);
558 buf_pool_release(&old_file);
559 buf_pool_release(&new_file);
560
561 return path;
562}
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:588
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
+ 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 
)

Open a file.

Parameters
pathPathname to open
flagsFlags, e.g. O_EXCL
Return values
>0Success, file handle
-1Error

Definition at line 571 of file file.c.

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

637{
638 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
639 {
640 return NULL;
641 }
642 errno = 0;
643 return opendir(path);
644}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:1015
@ 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 char *  file,
int  line,
const char *  func 
)

Call fopen() safely.

Parameters
pathFilename
modeMode e.g. "r" readonly; "w" read-write
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 659 of file file.c.

661{
662 if (!path || !mode)
663 return NULL;
664
665 FILE *fp = NULL;
666 if (mode[0] == 'w')
667 {
668 uint32_t flags = O_CREAT | O_EXCL | O_NOFOLLOW;
669
670 if (mode[1] == '+')
671 flags |= O_RDWR;
672 else
673 flags |= O_WRONLY;
674
675 int fd = mutt_file_open(path, flags);
676 if (fd >= 0)
677 {
678 fp = fdopen(fd, mode);
679 }
680 }
681 else
682 {
683 fp = fopen(path, mode);
684 }
685
686 if (fp)
687 {
688 MuttLogger(0, file, line, func, LL_DEBUG2, "File opened (fd=%d): %s\n",
689 fileno(fp), path);
690 }
691 else
692 {
693 MuttLogger(0, file, line, func, LL_DEBUG2, "File open failed (errno=%d, %s): %s\n",
694 errno, strerror(errno), path);
695 }
696
697 return fp;
698}
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:571
+ Here is the call 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 705 of file file.c.

706{
707 if (!path)
708 return;
709
710 size_t size = strlen(path);
711
712 wchar_t c;
713 mbstate_t mbstate = { 0 };
714 for (size_t consumed; size && (consumed = mbrtowc(&c, path, size, &mbstate));
715 size -= consumed, path += consumed)
716 {
717 switch (consumed)
718 {
720 mbstate = (mbstate_t){ 0 };
721 consumed = 1;
722 memset(path, '_', consumed);
723 break;
724
726 consumed = size;
727 memset(path, '_', consumed);
728 break;
729
730 default:
731 if ((slash && (c == L'/')) || ((c <= 0x7F) && !strchr(FilenameSafeChars, c)))
732 {
733 memset(path, '_', consumed);
734 }
735 break;
736 }
737 }
738}
const char FilenameSafeChars[]
Set of characters <=0x7F that are safe to use in filenames.
Definition: file.c:70
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:106
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:104
+ 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 747 of file file.c.

748{
749 if (!dest || !src)
750 return -1;
751
752 buf_reset(dest);
753 while (*src != '\0')
754 {
755 if (strchr(RxSpecialChars, *src))
756 buf_addch(dest, '\\');
757 buf_addch(dest, *src++);
758 }
759
760 return 0;
761}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
static const char RxSpecialChars[]
These characters must be escaped in regular expressions.
Definition: file.c:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

772{
773 if (!fp)
774 {
775 return false;
776 }
777
778 if (fseeko(fp, offset, whence) != 0)
779 {
780 mutt_perror(_("Failed to seek file: %s"), strerror(errno));
781 return false;
782 }
783
784 return true;
785}
#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 801 of file file.c.

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

883{
884 if (!iter)
885 return false;
886
887 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
888 if (!p)
889 return false;
890 iter->line = p;
891 return true;
892}
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:801
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 903 of file file.c.

904{
905 if (!func || !fp)
906 return false;
907
908 struct MuttFileIter iter = { 0 };
909 while (mutt_file_iter_line(&iter, fp, flags))
910 {
911 if (!(*func)(iter.line, iter.line_num, user_data))
912 {
913 FREE(&iter.line);
914 return false;
915 }
916 }
917 return true;
918}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_quote_filename()

size_t mutt_file_quote_filename ( const char *  filename,
char *  buf,
size_t  buflen 
)

Quote a filename to survive the shell's quoting rules.

Parameters
filenameString to convert
bufBuffer for the result
buflenLength of buffer
Return values
numBytes written to the buffer

From the Unix programming FAQ by way of Liviu.

Definition at line 929 of file file.c.

930{
931 if (!buf)
932 return 0;
933
934 if (!filename)
935 {
936 *buf = '\0';
937 return 0;
938 }
939
940 size_t j = 0;
941
942 /* leave some space for the trailing characters. */
943 buflen -= 6;
944
945 buf[j++] = '\'';
946
947 for (size_t i = 0; (j < buflen) && filename[i]; i++)
948 {
949 if ((filename[i] == '\'') || (filename[i] == '`'))
950 {
951 buf[j++] = '\'';
952 buf[j++] = '\\';
953 buf[j++] = filename[i];
954 buf[j++] = '\'';
955 }
956 else
957 {
958 buf[j++] = filename[i];
959 }
960 }
961
962 buf[j++] = '\'';
963 buf[j] = '\0';
964
965 return j;
966}
+ 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 974 of file file.c.

975{
976 if (!buf || !filename)
977 return;
978
979 buf_reset(buf);
980 if (add_outer)
981 buf_addch(buf, '\'');
982
983 for (; *filename != '\0'; filename++)
984 {
985 if ((*filename == '\'') || (*filename == '`'))
986 {
987 buf_addch(buf, '\'');
988 buf_addch(buf, '\\');
989 buf_addch(buf, *filename);
990 buf_addch(buf, '\'');
991 }
992 else
993 {
994 buf_addch(buf, *filename);
995 }
996 }
997
998 if (add_outer)
999 buf_addch(buf, '\'');
1000}
+ 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 1015 of file file.c.

1016{
1017 if (!path || (*path == '\0'))
1018 {
1019 errno = EINVAL;
1020 return -1;
1021 }
1022
1023 errno = 0;
1024 char tmp_path[PATH_MAX] = { 0 };
1025 const size_t len = strlen(path);
1026
1027 if (len >= sizeof(tmp_path))
1028 {
1029 errno = ENAMETOOLONG;
1030 return -1;
1031 }
1032
1033 struct stat st = { 0 };
1034 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
1035 return 0;
1036
1037 /* Create a mutable copy */
1038 mutt_str_copy(tmp_path, path, sizeof(tmp_path));
1039
1040 for (char *p = tmp_path + 1; *p; p++)
1041 {
1042 if (*p != '/')
1043 continue;
1044
1045 /* Temporarily truncate the path */
1046 *p = '\0';
1047
1048 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
1049 return -1;
1050
1051 *p = '/';
1052 }
1053
1054 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
1055 return -1;
1056
1057 return 0;
1058}
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:630
+ 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 1069 of file file.c.

1070{
1071 if (!fp)
1072 return -1;
1073
1074 struct utimbuf utim = { 0 };
1075 struct stat st2 = { 0 };
1076 time_t mtime;
1077
1078 if (!st)
1079 {
1080 if (stat(fp, &st2) == -1)
1081 return -1;
1082 st = &st2;
1083 }
1084
1085 mtime = st->st_mtime;
1086 if (mtime == mutt_date_now())
1087 {
1088 mtime -= 1;
1089 utim.actime = mtime;
1090 utim.modtime = mtime;
1091 int rc;
1092 do
1093 {
1094 rc = utime(fp, &utim);
1095 } while ((rc == -1) && (errno == EINTR));
1096
1097 if (rc == -1)
1098 return -1;
1099 }
1100
1101 return mtime;
1102}
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
+ 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 1109 of file file.c.

1110{
1111 if (!from || !to)
1112 return;
1113
1114 struct utimbuf utim = { 0 };
1115 struct stat st = { 0 };
1116
1117 if (stat(from, &st) != -1)
1118 {
1119 utim.actime = st.st_mtime;
1120 utim.modtime = st.st_mtime;
1121 utime(to, &utim);
1122 }
1123}
+ 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 1132 of file file.c.

1133{
1134#ifdef HAVE_FUTIMENS
1135 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1136 futimens(fd, times);
1137#endif
1138}
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 1157 of file file.c.

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

1181{
1182 if (!path)
1183 return -1;
1184
1185 struct stat st2 = { 0 };
1186
1187 if (!st)
1188 {
1189 if (stat(path, &st2) == -1)
1190 return -1;
1191 st = &st2;
1192 }
1193 return chmod(path, st->st_mode | mode);
1194}
+ 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 1214 of file file.c.

1215{
1216 if (!path)
1217 return -1;
1218
1219 struct stat st2 = { 0 };
1220
1221 if (!st)
1222 {
1223 if (stat(path, &st2) == -1)
1224 return -1;
1225 st = &st2;
1226 }
1227 return chmod(path, st->st_mode & ~mode);
1228}
+ 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 1243 of file file.c.

1244{
1245 struct stat st = { 0 }, prev_sb = { 0 };
1246 int count = 0;
1247 int attempt = 0;
1248
1249 struct flock lck = { 0 };
1250 lck.l_type = excl ? F_WRLCK : F_RDLCK;
1251 lck.l_whence = SEEK_SET;
1252
1253 while (fcntl(fd, F_SETLK, &lck) == -1)
1254 {
1255 mutt_debug(LL_DEBUG1, "fcntl errno %d\n", errno);
1256 if ((errno != EAGAIN) && (errno != EACCES))
1257 {
1258 mutt_perror("fcntl");
1259 return -1;
1260 }
1261
1262 if (fstat(fd, &st) != 0)
1263 st.st_size = 0;
1264
1265 if (count == 0)
1266 prev_sb = st;
1267
1268 /* only unlock file if it is unchanged */
1269 if ((prev_sb.st_size == st.st_size) && (++count >= (timeout ? MAX_LOCK_ATTEMPTS : 0)))
1270 {
1271 if (timeout)
1272 mutt_error(_("Timeout exceeded while attempting fcntl lock"));
1273 return -1;
1274 }
1275
1276 prev_sb = st;
1277
1278 mutt_message(_("Waiting for fcntl lock... %d"), ++attempt);
1279 sleep(1);
1280 }
1281
1282 return 0;
1283}
#define MAX_LOCK_ATTEMPTS
Definition: file.c:72
#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 1290 of file file.c.

1291{
1292 struct flock unlockit = { 0 };
1293 unlockit.l_type = F_UNLCK;
1294 unlockit.l_whence = SEEK_SET;
1295 (void) fcntl(fd, F_SETLK, &unlockit);
1296
1297 return 0;
1298}
+ 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 1376 of file file.c.

1377{
1378 if (!path)
1379 return;
1380
1381 struct stat st = { 0 };
1382
1383 int fd = open(path, O_RDWR);
1384 if (fd == -1)
1385 return;
1386
1387 if (mutt_file_lock(fd, true, true) == -1)
1388 {
1389 close(fd);
1390 return;
1391 }
1392
1393 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1394 unlink(path);
1395
1396 mutt_file_unlock(fd);
1397 close(fd);
1398}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1243
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1290
+ 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 1412 of file file.c.

1413{
1414 if (!oldfile || !newfile)
1415 return -1;
1416 if (access(oldfile, F_OK) != 0)
1417 return 1;
1418 if (access(newfile, F_OK) == 0)
1419 return 2;
1420
1421 FILE *fp_old = mutt_file_fopen(oldfile, "r");
1422 if (!fp_old)
1423 return 3;
1424 FILE *fp_new = mutt_file_fopen(newfile, "w");
1425 if (!fp_new)
1426 {
1427 mutt_file_fclose(&fp_old);
1428 return 3;
1429 }
1430 mutt_file_copy_stream(fp_old, fp_new);
1431 mutt_file_fclose(&fp_new);
1432 mutt_file_fclose(&fp_old);
1433 mutt_file_unlink(oldfile);
1434 return 0;
1435}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:282
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:216
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:147
+ 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 1447 of file file.c.

1448{
1449 FILE *fp = mutt_file_fopen(file, "r");
1450 if (!fp)
1451 return NULL;
1452
1453 buf = fgets(buf, buflen, fp);
1454 mutt_file_fclose(&fp);
1455
1456 if (!buf)
1457 return NULL;
1458
1459 SKIPWS(buf);
1460 char *start = buf;
1461
1462 while ((*buf != '\0') && !isspace(*buf))
1463 buf++;
1464
1465 *buf = '\0';
1466
1467 return start;
1468}
#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 1477 of file file.c.

1478{
1479 if (!path)
1480 return -1;
1481
1482 struct stat st = { 0 };
1483 if (stat(path, &st) == -1)
1484 return -1;
1485
1486 return st.st_size == 0;
1487}
+ 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 1497 of file file.c.

1498{
1499 struct Buffer tmp = buf_make(PATH_MAX);
1500
1501 buf_quote_filename(&tmp, src, true);
1502 mutt_file_expand_fmt(dest, fmt, buf_string(&tmp));
1503 buf_dealloc(&tmp);
1504}
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:974
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:1512
+ 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 1512 of file file.c.

1513{
1514 if (!dest || !fmt || !src)
1515 return;
1516
1517 const char *p = NULL;
1518 bool found = false;
1519
1520 buf_reset(dest);
1521
1522 for (p = fmt; *p; p++)
1523 {
1524 if (*p == '%')
1525 {
1526 switch (p[1])
1527 {
1528 case '%':
1529 buf_addch(dest, *p++);
1530 break;
1531 case 's':
1532 found = true;
1533 buf_addstr(dest, src);
1534 p++;
1535 break;
1536 default:
1537 buf_addch(dest, *p);
1538 break;
1539 }
1540 }
1541 else
1542 {
1543 buf_addch(dest, *p);
1544 }
1545 }
1546
1547 if (!found)
1548 {
1549 buf_addch(dest, ' ');
1550 buf_addstr(dest, src);
1551 }
1552}
+ 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 1560 of file file.c.

1561{
1562 if (!path)
1563 return 0;
1564
1565 struct stat st = { 0 };
1566 if (stat(path, &st) != 0)
1567 return 0;
1568
1569 return st.st_size;
1570}
+ 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 1578 of file file.c.

1579{
1580 if (!fp)
1581 return 0;
1582
1583 struct stat st = { 0 };
1584 if (fstat(fileno(fp), &st) != 0)
1585 return 0;
1586
1587 return st.st_size;
1588}
+ 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 1598 of file file.c.

1599{
1600 if (!a || !b)
1601 return 0;
1602 if (a->tv_sec < b->tv_sec)
1603 return -1;
1604 if (a->tv_sec > b->tv_sec)
1605 return 1;
1606
1607 if (a->tv_nsec < b->tv_nsec)
1608 return -1;
1609 if (a->tv_nsec > b->tv_nsec)
1610 return 1;
1611 return 0;
1612}
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 1620 of file file.c.

1621{
1622 if (!dest || !st)
1623 return;
1624
1625 dest->tv_sec = 0;
1626 dest->tv_nsec = 0;
1627
1628 switch (type)
1629 {
1630 case MUTT_STAT_ATIME:
1631 dest->tv_sec = st->st_atime;
1632#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1633 dest->tv_nsec = st->st_atim.tv_nsec;
1634#endif
1635 break;
1636 case MUTT_STAT_MTIME:
1637 dest->tv_sec = st->st_mtime;
1638#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1639 dest->tv_nsec = st->st_mtim.tv_nsec;
1640#endif
1641 break;
1642 case MUTT_STAT_CTIME:
1643 dest->tv_sec = st->st_ctime;
1644#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1645 dest->tv_nsec = st->st_ctim.tv_nsec;
1646#endif
1647 break;
1648 }
1649}
@ 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 1660 of file file.c.

1662{
1663 if (!st || !b)
1664 return 0;
1665
1666 struct timespec a = { 0 };
1667
1668 mutt_file_get_stat_timespec(&a, st, type);
1669 return mutt_file_timespec_compare(&a, b);
1670}
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:1620
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1598
+ 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 1682 of file file.c.

1684{
1685 if (!st1 || !st2)
1686 return 0;
1687
1688 struct timespec a = { 0 };
1689 struct timespec b = { 0 };
1690
1691 mutt_file_get_stat_timespec(&a, st1, st1_type);
1692 mutt_file_get_stat_timespec(&b, st2, st2_type);
1693 return mutt_file_timespec_compare(&a, &b);
1694}
+ 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 1700 of file file.c.

1701{
1702 struct stat st = { 0 };
1703 int rc = lstat(buf_string(buf), &st);
1704 if ((rc != -1) && S_ISLNK(st.st_mode))
1705 {
1706 char path[PATH_MAX] = { 0 };
1707 if (realpath(buf_string(buf), path))
1708 {
1709 buf_strcpy(buf, path);
1710 }
1711 }
1712}
+ 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 1720 of file file.c.

1721{
1722 if (!fp)
1723 return 0;
1724
1725 size_t len = mutt_str_len(str);
1726 if (len == 0)
1727 return 0;
1728
1729 return fwrite(str, 1, len, fp);
1730}
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
+ 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 67 of file file.c.

◆ FilenameSafeChars

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

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

Definition at line 70 of file file.c.