NeoMutt  2022-04-29-323-g5fcc6c
Teaching an old dog new tricks
DOXYGEN
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 "config/lib.h"
#include "core/lib.h"
#include "file.h"
#include "buffer.h"
#include "date.h"
#include "logging.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 compare_stat (struct stat *st_old, struct stat *st_new)
 Compare the struct stat's of two files/dirs. More...
 
static int mkwrapdir (const char *path, struct Buffer *newfile, struct Buffer *newdir)
 Create a temporary directory next to a file name. More...
 
static int put_file_in_place (const char *path, const char *safe_file, const char *safe_dir)
 Move a file into place. More...
 
int mutt_file_fclose (FILE **fp)
 Close a FILE handle (and NULL the pointer) More...
 
int mutt_file_fsync_close (FILE **fp)
 Flush the data, before closing a file (and NULL the pointer) More...
 
void mutt_file_unlink (const char *s)
 Delete a file, carefully. More...
 
int mutt_file_copy_bytes (FILE *fp_in, FILE *fp_out, size_t size)
 Copy some content from one file to another. More...
 
int mutt_file_copy_stream (FILE *fp_in, FILE *fp_out)
 Copy the contents of one file into another. More...
 
int mutt_file_symlink (const char *oldpath, const char *newpath)
 Create a symlink. More...
 
int mutt_file_safe_rename (const char *src, const char *target)
 NFS-safe renaming of files. More...
 
int mutt_file_rmtree (const char *path)
 Recursively remove a directory. More...
 
const char * mutt_file_rotate (const char *path, int count)
 Rotate a set of numbered files. More...
 
int mutt_file_open (const char *path, uint32_t flags)
 Open a file. More...
 
DIR * mutt_file_opendir (const char *path, enum MuttOpenDirMode mode)
 Open a directory. More...
 
FILE * mutt_file_fopen (const char *path, const char *mode)
 Call fopen() safely. More...
 
void mutt_file_sanitize_filename (char *path, bool slash)
 Replace unsafe characters in a filename. More...
 
int mutt_file_sanitize_regex (struct Buffer *dest, const char *src)
 Escape any regex-magic characters in a string. More...
 
bool mutt_file_seek (FILE *fp, LOFF_T offset, int whence)
 Wrapper for fseeko with error handling. More...
 
char * mutt_file_read_line (char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
 Read a line from a file. More...
 
bool mutt_file_iter_line (struct MuttFileIter *iter, FILE *fp, ReadLineFlags flags)
 Iterate over the lines from an open file pointer. More...
 
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. More...
 
size_t mutt_file_quote_filename (const char *filename, char *buf, size_t buflen)
 Quote a filename to survive the shell's quoting rules. More...
 
void mutt_buffer_quote_filename (struct Buffer *buf, const char *filename, bool add_outer)
 Quote a filename to survive the shell's quoting rules. More...
 
int mutt_file_mkdir (const char *path, mode_t mode)
 Recursively create directories. More...
 
FILE * mutt_file_mkstemp_full (const char *file, int line, const char *func)
 Create temporary file safely. More...
 
time_t mutt_file_decrease_mtime (const char *fp, struct stat *st)
 Decrease a file's modification time by 1 second. More...
 
void mutt_file_set_mtime (const char *from, const char *to)
 Set the modification time of one file from another. More...
 
void mutt_file_touch_atime (int fd)
 Set the access time to current time. More...
 
int mutt_file_chmod (const char *path, mode_t mode)
 Set permissions of a file. More...
 
int mutt_file_chmod_add (const char *path, mode_t mode)
 Add permissions to a file. More...
 
int mutt_file_chmod_add_stat (const char *path, mode_t mode, struct stat *st)
 Add permissions to a file. More...
 
int mutt_file_chmod_rm (const char *path, mode_t mode)
 Remove permissions from a file. More...
 
int mutt_file_chmod_rm_stat (const char *path, mode_t mode, struct stat *st)
 Remove permissions from a file. More...
 
int mutt_file_lock (int fd, bool excl, bool timeout)
 (Try to) Lock a file using fcntl() More...
 
int mutt_file_unlock (int fd)
 Unlock a file previously locked by mutt_file_lock() More...
 
void mutt_file_unlink_empty (const char *path)
 Delete a file if it's empty. More...
 
int mutt_file_rename (const char *oldfile, const char *newfile)
 Rename a file. More...
 
char * mutt_file_read_keyword (const char *file, char *buf, size_t buflen)
 Read a keyword from a file. More...
 
int mutt_file_check_empty (const char *path)
 Is the mailbox empty. More...
 
void mutt_buffer_file_expand_fmt_quote (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename. More...
 
void mutt_file_expand_fmt (struct Buffer *dest, const char *fmt, const char *src)
 Replace s in a string with a filename. More...
 
long mutt_file_get_size (const char *path)
 Get the size of a file. More...
 
long mutt_file_get_size_fp (FILE *fp)
 Get the size of a file. More...
 
int mutt_file_timespec_compare (struct timespec *a, struct timespec *b)
 Compare to time values. More...
 
void mutt_file_get_stat_timespec (struct timespec *dest, struct stat *st, enum MuttStatType type)
 Read the stat() time into a time value. More...
 
int mutt_file_stat_timespec_compare (struct stat *st, enum MuttStatType type, struct timespec *b)
 Compare stat info with a time value. More...
 
int mutt_file_stat_compare (struct stat *st1, enum MuttStatType st1_type, struct stat *st2, enum MuttStatType st2_type)
 Compare two stat infos. More...
 
void mutt_file_resolve_symlink (struct Buffer *buf)
 Resolve a symlink in place. More...
 

Variables

static const char rx_special_chars [] = "^.[$()|*+?{\\"
 
const char filename_safe_chars [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/"
 

Detailed Description

File management functions.

Authors
  • Richard Russon

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

◆ O_NOFOLLOW

#define O_NOFOLLOW   0

Definition at line 66 of file file.c.

Function Documentation

◆ compare_stat()

static bool compare_stat ( 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 78 of file file.c.

79{
80 return (st_old->st_dev == st_new->st_dev) && (st_old->st_ino == st_new->st_ino) &&
81 (st_old->st_rdev == st_new->st_rdev);
82}
+ 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 92 of file file.c.

93{
94 const char *basename = NULL;
95 int rc = 0;
96
97 struct Buffer parent = mutt_buffer_make(PATH_MAX);
98 mutt_buffer_strcpy(&parent, NONULL(path));
99
100 char *p = strrchr(parent.data, '/');
101 if (p)
102 {
103 *p = '\0';
104 basename = p + 1;
105 }
106 else
107 {
108 mutt_buffer_strcpy(&parent, ".");
109 basename = path;
110 }
111
112 mutt_buffer_printf(newdir, "%s/%s", mutt_buffer_string(&parent), ".muttXXXXXX");
113 if (!mkdtemp(newdir->data))
114 {
115 mutt_debug(LL_DEBUG1, "mkdtemp() failed\n");
116 rc = -1;
117 goto cleanup;
118 }
119
120 mutt_buffer_printf(newfile, "%s/%s", newdir->data, NONULL(basename));
121
122cleanup:
123 mutt_buffer_dealloc(&parent);
124 return rc;
125}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
#define PATH_MAX
Definition: mutt.h:40
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
+ 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 135 of file file.c.

136{
137 int rc;
138
139 rc = mutt_file_safe_rename(safe_file, path);
140 unlink(safe_file);
141 rmdir(safe_dir);
142 return rc;
143}
int mutt_file_safe_rename(const char *src, const char *target)
NFS-safe renaming of files.
Definition: file.c:343
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_fclose()

int mutt_file_fclose ( FILE **  fp)

Close a FILE handle (and NULL the pointer)

Parameters
[out]fpFILE handle to close
Return values
0Success
EOFError, see errno

Definition at line 151 of file file.c.

152{
153 if (!fp || !*fp)
154 return 0;
155
156 int rc = fclose(*fp);
157 *fp = NULL;
158 return rc;
159}

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

168{
169 if (!fp || !*fp)
170 return 0;
171
172 int rc = 0;
173
174 if (fflush(*fp) || fsync(fileno(*fp)))
175 {
176 int save_errno = errno;
177 rc = -1;
179 errno = save_errno;
180 }
181 else
182 rc = mutt_file_fclose(fp);
183
184 return rc;
185}
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
+ Here is the call graph for this function:
+ 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 193 of file file.c.

194{
195 if (!s)
196 return;
197
198 struct stat st = { 0 };
199 /* Defend against symlink attacks */
200
201 const bool is_regular_file = (lstat(s, &st) == 0) && S_ISREG(st.st_mode);
202 if (!is_regular_file)
203 return;
204
205 const int fd = open(s, O_RDWR | O_NOFOLLOW);
206 if (fd < 0)
207 return;
208
209 struct stat st2 = { 0 };
210 if ((fstat(fd, &st2) != 0) || !S_ISREG(st2.st_mode) ||
211 (st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino))
212 {
213 close(fd);
214 return;
215 }
216
217 unlink(s);
218 close(fd);
219}
#define O_NOFOLLOW
Definition: file.c:66
+ 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 229 of file file.c.

230{
231 if (!fp_in || !fp_out)
232 return -1;
233
234 while (size > 0)
235 {
236 char buf[2048] = { 0 };
237 size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size;
238 chunk = fread(buf, 1, chunk, fp_in);
239 if (chunk < 1)
240 break;
241 if (fwrite(buf, 1, chunk, fp_out) != chunk)
242 return -1;
243
244 size -= chunk;
245 }
246
247 if (fflush(fp_out) != 0)
248 return -1;
249 return 0;
250}
+ 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
nSuccess, number of bytes copied
-1Error, see errno

Definition at line 259 of file file.c.

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

288{
289 struct stat st_old = { 0 };
290 struct stat st_new = { 0 };
291
292 if (!oldpath || !newpath)
293 return -1;
294
295 if ((unlink(newpath) == -1) && (errno != ENOENT))
296 return -1;
297
298 if (oldpath[0] == '/')
299 {
300 if (symlink(oldpath, newpath) == -1)
301 return -1;
302 }
303 else
304 {
305 struct Buffer abs_oldpath = mutt_buffer_make(PATH_MAX);
306
307 if (!mutt_path_getcwd(&abs_oldpath))
308 {
309 mutt_buffer_dealloc(&abs_oldpath);
310 return -1;
311 }
312
313 mutt_buffer_addch(&abs_oldpath, '/');
314 mutt_buffer_addstr(&abs_oldpath, oldpath);
315 if (symlink(mutt_buffer_string(&abs_oldpath), newpath) == -1)
316 {
317 mutt_buffer_dealloc(&abs_oldpath);
318 return -1;
319 }
320
321 mutt_buffer_dealloc(&abs_oldpath);
322 }
323
324 if ((stat(oldpath, &st_old) == -1) || (stat(newpath, &st_new) == -1) ||
325 !compare_stat(&st_old, &st_new))
326 {
327 unlink(newpath);
328 return -1;
329 }
330
331 return 0;
332}
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
static bool compare_stat(struct stat *st_old, struct stat *st_new)
Compare the struct stat's of two files/dirs.
Definition: file.c:78
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:561
+ 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 343 of file file.c.

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

459{
460 if (!path)
461 return -1;
462
463 struct dirent *de = NULL;
464 struct stat st = { 0 };
465 int rc = 0;
466
467 DIR *dirp = mutt_file_opendir(path, MUTT_OPENDIR_NONE);
468 if (!dirp)
469 {
470 mutt_debug(LL_DEBUG1, "error opening directory %s\n", path);
471 return -1;
472 }
473
474 /* We avoid using the buffer pool for this function, because it
475 * invokes recursively to an unknown depth. */
476 struct Buffer cur = mutt_buffer_make(PATH_MAX);
477
478 while ((de = readdir(dirp)))
479 {
480 if ((strcmp(".", de->d_name) == 0) || (strcmp("..", de->d_name) == 0))
481 continue;
482
483 mutt_buffer_printf(&cur, "%s/%s", path, de->d_name);
484 /* XXX make nonrecursive version */
485
486 if (stat(mutt_buffer_string(&cur), &st) == -1)
487 {
488 rc = 1;
489 continue;
490 }
491
492 if (S_ISDIR(st.st_mode))
494 else
495 rc |= unlink(mutt_buffer_string(&cur));
496 }
497 closedir(dirp);
498
499 rc |= rmdir(path);
500
502 return rc;
503}
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:614
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:458
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:73
+ 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 518 of file file.c.

519{
520 if (!path)
521 return NULL;
522
523 struct Buffer *old_file = mutt_buffer_pool_get();
524 struct Buffer *new_file = mutt_buffer_pool_get();
525
526 /* rotate the old debug logs */
527 for (count -= 2; count >= 0; count--)
528 {
529 mutt_buffer_printf(old_file, "%s%d", path, count);
530 mutt_buffer_printf(new_file, "%s%d", path, count + 1);
531 (void) rename(mutt_buffer_string(old_file), mutt_buffer_string(new_file));
532 }
533
534 path = mutt_buffer_strdup(old_file);
535 mutt_buffer_pool_release(&old_file);
536 mutt_buffer_pool_release(&new_file);
537
538 return path;
539}
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
+ 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 548 of file file.c.

549{
550 if (!path)
551 return -1;
552
553 int fd;
554 struct Buffer safe_file = mutt_buffer_make(0);
555 struct Buffer safe_dir = mutt_buffer_make(0);
556
557 if (flags & O_EXCL)
558 {
559 mutt_buffer_alloc(&safe_file, PATH_MAX);
560 mutt_buffer_alloc(&safe_dir, PATH_MAX);
561
562 if (mkwrapdir(path, &safe_file, &safe_dir) == -1)
563 {
564 fd = -1;
565 goto cleanup;
566 }
567
568 fd = open(mutt_buffer_string(&safe_file), flags, 0600);
569 if (fd < 0)
570 {
571 rmdir(mutt_buffer_string(&safe_dir));
572 goto cleanup;
573 }
574
575 /* NFS and I believe cygwin do not handle movement of open files well */
576 close(fd);
577 if (put_file_in_place(path, mutt_buffer_string(&safe_file),
578 mutt_buffer_string(&safe_dir)) == -1)
579 {
580 fd = -1;
581 goto cleanup;
582 }
583 }
584
585 fd = open(path, flags & ~O_EXCL, 0600);
586 if (fd < 0)
587 goto cleanup;
588
589 /* make sure the file is not symlink */
590 struct stat st_old = { 0 };
591 struct stat st_new = { 0 };
592 if (((lstat(path, &st_old) < 0) || (fstat(fd, &st_new) < 0)) ||
593 !compare_stat(&st_old, &st_new))
594 {
595 close(fd);
596 fd = -1;
597 goto cleanup;
598 }
599
600cleanup:
601 mutt_buffer_dealloc(&safe_file);
602 mutt_buffer_dealloc(&safe_dir);
603
604 return fd;
605}
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:275
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:135
static int mkwrapdir(const char *path, struct Buffer *newfile, struct Buffer *newdir)
Create a temporary directory next to a file name.
Definition: file.c:92
+ 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 614 of file file.c.

615{
616 if ((mode == MUTT_OPENDIR_CREATE) && (mutt_file_mkdir(path, S_IRWXU) == -1))
617 {
618 return NULL;
619 }
620 errno = 0;
621 return opendir(path);
622}
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:946
@ MUTT_OPENDIR_CREATE
Create the directory if it doesn't exist.
Definition: file.h:74
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_fopen()

FILE * mutt_file_fopen ( const char *  path,
const char *  mode 
)

Call fopen() safely.

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

635{
636 if (!path || !mode)
637 return NULL;
638
639 if (mode[0] == 'w')
640 {
641 uint32_t flags = O_CREAT | O_EXCL | O_NOFOLLOW;
642
643 if (mode[1] == '+')
644 flags |= O_RDWR;
645 else
646 flags |= O_WRONLY;
647
648 int fd = mutt_file_open(path, flags);
649 if (fd < 0)
650 return NULL;
651
652 return fdopen(fd, mode);
653 }
654 else
655 return fopen(path, mode);
656}
int mutt_file_open(const char *path, uint32_t flags)
Open a file.
Definition: file.c:548
+ 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 663 of file file.c.

664{
665 if (!path)
666 return;
667
668 for (; *path; path++)
669 {
670 if ((slash && (*path == '/')) || !strchr(filename_safe_chars, *path))
671 *path = '_';
672 }
673}
const char filename_safe_chars[]
Definition: file.c:60
+ 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 682 of file file.c.

683{
684 if (!dest || !src)
685 return -1;
686
687 mutt_buffer_reset(dest);
688 while (*src != '\0')
689 {
690 if (strchr(rx_special_chars, *src))
691 mutt_buffer_addch(dest, '\\');
692 mutt_buffer_addch(dest, *src++);
693 }
694
695 return 0;
696}
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static const char rx_special_chars[]
Definition: file.c:58
+ 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 706 of file file.c.

707{
708 if (!fp)
709 {
710 return false;
711 }
712
713 if (fseeko(fp, offset, whence) != 0)
714 {
715 mutt_perror(_("Failed to seek file: %s"), strerror(errno));
716 return false;
717 }
718
719 return true;
720}
#define mutt_perror(...)
Definition: logging.h:88
#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 736 of file file.c.

737{
738 if (!size || !fp)
739 return NULL;
740
741 size_t offset = 0;
742 char *ch = NULL;
743
744 if (!line)
745 {
746 *size = 256;
747 line = mutt_mem_malloc(*size);
748 }
749
750 while (true)
751 {
752 if (!fgets(line + offset, *size - offset, fp))
753 {
754 FREE(&line);
755 return NULL;
756 }
757 ch = strchr(line + offset, '\n');
758 if (ch)
759 {
760 if (line_num)
761 (*line_num)++;
762 if (flags & MUTT_RL_EOL)
763 return line;
764 *ch = '\0';
765 if ((ch > line) && (*(ch - 1) == '\r'))
766 *--ch = '\0';
767 if (!(flags & MUTT_RL_CONT) || (ch == line) || (*(ch - 1) != '\\'))
768 return line;
769 offset = ch - line - 1;
770 }
771 else
772 {
773 int c;
774 c = getc(fp); /* This is kind of a hack. We want to know if the
775 char at the current point in the input stream is EOF.
776 feof() will only tell us if we've already hit EOF, not
777 if the next character is EOF. So, we need to read in
778 the next character and manually check if it is EOF. */
779 if (c == EOF)
780 {
781 /* The last line of fp isn't \n terminated */
782 if (line_num)
783 (*line_num)++;
784 return line;
785 }
786 else
787 {
788 ungetc(c, fp); /* undo our damage */
789 /* There wasn't room for the line -- increase "line" */
790 offset = *size - 1; /* overwrite the terminating 0 */
791 *size += 256;
792 mutt_mem_realloc(&line, *size);
793 }
794 }
795 }
796}
#define MUTT_RL_CONT
-continuation
Definition: file.h:40
#define MUTT_RL_EOL
don't strip \n / \r\n
Definition: file.h:41
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:43
+ 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:817
State record for mutt_file_iter_line()
Definition: file.h:81
char * line
the line data
Definition: file.h:82
int line_num
line number
Definition: file.h:84

Definition at line 817 of file file.c.

818{
819 if (!iter)
820 return false;
821
822 char *p = mutt_file_read_line(iter->line, &iter->size, fp, &iter->line_num, flags);
823 if (!p)
824 return false;
825 iter->line = p;
826 return true;
827}
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:736
size_t size
allocated size of line data
Definition: file.h:83
+ 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 838 of file file.c.

839{
840 if (!func || !fp)
841 return false;
842
843 struct MuttFileIter iter = { 0 };
844 while (mutt_file_iter_line(&iter, fp, flags))
845 {
846 if (!(*func)(iter.line, iter.line_num, user_data))
847 {
848 FREE(&iter.line);
849 return false;
850 }
851 }
852 return true;
853}
+ 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 864 of file file.c.

865{
866 if (!buf)
867 return 0;
868
869 if (!filename)
870 {
871 *buf = '\0';
872 return 0;
873 }
874
875 size_t j = 0;
876
877 /* leave some space for the trailing characters. */
878 buflen -= 6;
879
880 buf[j++] = '\'';
881
882 for (size_t i = 0; (j < buflen) && filename[i]; i++)
883 {
884 if ((filename[i] == '\'') || (filename[i] == '`'))
885 {
886 buf[j++] = '\'';
887 buf[j++] = '\\';
888 buf[j++] = filename[i];
889 buf[j++] = '\'';
890 }
891 else
892 buf[j++] = filename[i];
893 }
894
895 buf[j++] = '\'';
896 buf[j] = '\0';
897
898 return j;
899}
+ Here is the caller graph for this function:

◆ mutt_buffer_quote_filename()

void mutt_buffer_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 907 of file file.c.

908{
909 if (!buf || !filename)
910 return;
911
913 if (add_outer)
914 mutt_buffer_addch(buf, '\'');
915
916 for (; *filename != '\0'; filename++)
917 {
918 if ((*filename == '\'') || (*filename == '`'))
919 {
920 mutt_buffer_addch(buf, '\'');
921 mutt_buffer_addch(buf, '\\');
922 mutt_buffer_addch(buf, *filename);
923 mutt_buffer_addch(buf, '\'');
924 }
925 else
926 mutt_buffer_addch(buf, *filename);
927 }
928
929 if (add_outer)
930 mutt_buffer_addch(buf, '\'');
931}
+ 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 946 of file file.c.

947{
948 if (!path || (*path == '\0'))
949 {
950 errno = EINVAL;
951 return -1;
952 }
953
954 errno = 0;
955 char tmp_path[PATH_MAX] = { 0 };
956 const size_t len = strlen(path);
957
958 if (len >= sizeof(tmp_path))
959 {
960 errno = ENAMETOOLONG;
961 return -1;
962 }
963
964 struct stat st = { 0 };
965 if ((stat(path, &st) == 0) && S_ISDIR(st.st_mode))
966 return 0;
967
968 /* Create a mutable copy */
969 mutt_str_copy(tmp_path, path, sizeof(tmp_path));
970
971 for (char *p = tmp_path + 1; *p; p++)
972 {
973 if (*p != '/')
974 continue;
975
976 /* Temporarily truncate the path */
977 *p = '\0';
978
979 if ((mkdir(tmp_path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) && (errno != EEXIST))
980 return -1;
981
982 *p = '/';
983 }
984
985 if ((mkdir(tmp_path, mode) != 0) && (errno != EEXIST))
986 return -1;
987
988 return 0;
989}
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:652
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_mkstemp_full()

FILE * mutt_file_mkstemp_full ( const char *  file,
int  line,
const char *  func 
)

Create temporary file safely.

Parameters
fileSource file of caller
lineSource line number of caller
funcFunction name of caller
Return values
ptrFILE handle
NULLError, see errno

Create and immediately unlink a temp file using mkstemp().

Definition at line 1001 of file file.c.

1002{
1003 char name[PATH_MAX] = { 0 };
1004
1005 const char *const c_tmpdir = cs_subset_path(NeoMutt->sub, "tmpdir");
1006 int n = snprintf(name, sizeof(name), "%s/neomutt-XXXXXX", NONULL(c_tmpdir));
1007 if (n < 0)
1008 return NULL;
1009
1010 int fd = mkstemp(name);
1011 if (fd == -1)
1012 return NULL;
1013
1014 FILE *fp = fdopen(fd, "w+");
1015
1016 if ((unlink(name) != 0) && (errno != ENOENT))
1017 {
1018 mutt_file_fclose(&fp);
1019 return NULL;
1020 }
1021
1022 MuttLogger(0, file, line, func, 1, "created temp file '%s'\n", name);
1023 return fp;
1024}
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
log_dispatcher_t MuttLogger
The log dispatcher -.
Definition: logging.c:52
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call 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 1035 of file file.c.

1036{
1037 if (!fp)
1038 return -1;
1039
1040 struct utimbuf utim;
1041 struct stat st2 = { 0 };
1042 time_t mtime;
1043
1044 if (!st)
1045 {
1046 if (stat(fp, &st2) == -1)
1047 return -1;
1048 st = &st2;
1049 }
1050
1051 mtime = st->st_mtime;
1052 if (mtime == mutt_date_epoch())
1053 {
1054 mtime -= 1;
1055 utim.actime = mtime;
1056 utim.modtime = mtime;
1057 int rc;
1058 do
1059 {
1060 rc = utime(fp, &utim);
1061 } while ((rc == -1) && (errno == EINTR));
1062
1063 if (rc == -1)
1064 return -1;
1065 }
1066
1067 return mtime;
1068}
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
+ 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 1075 of file file.c.

1076{
1077 if (!from || !to)
1078 return;
1079
1080 struct utimbuf utim;
1081 struct stat st = { 0 };
1082
1083 if (stat(from, &st) != -1)
1084 {
1085 utim.actime = st.st_mtime;
1086 utim.modtime = st.st_mtime;
1087 utime(to, &utim);
1088 }
1089}
+ 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 1098 of file file.c.

1099{
1100#ifdef HAVE_FUTIMENS
1101 struct timespec times[2] = { { 0, UTIME_NOW }, { 0, UTIME_OMIT } };
1102 futimens(fd, times);
1103#endif
1104}
Time value with nanosecond precision.
Definition: file.h:50
+ Here is the caller graph for this function:

◆ mutt_file_chmod()

int mutt_file_chmod ( const char *  path,
mode_t  mode 
)

Set permissions of a file.

Parameters
pathFilename
modethe permissions to set
Return values
numSame as chmod(2)

This is essentially chmod(path, mode), see chmod(2).

Definition at line 1114 of file file.c.

1115{
1116 if (!path)
1117 return -1;
1118
1119 return chmod(path, mode);
1120}

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

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

1163{
1164 if (!path)
1165 return -1;
1166
1167 struct stat st2 = { 0 };
1168
1169 if (!st)
1170 {
1171 if (stat(path, &st2) == -1)
1172 return -1;
1173 st = &st2;
1174 }
1175 return chmod(path, st->st_mode | mode);
1176}
+ Here is the caller graph for this function:

◆ mutt_file_chmod_rm()

int mutt_file_chmod_rm ( const char *  path,
mode_t  mode 
)

Remove permissions from a file.

Parameters
pathFilename
modethe permissions to remove
Return values
numSame as chmod(2)

Removes the given permissions from 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_rm(path, S_IWUSR | S_IWGRP | S_IWOTH);

will remove write permissions from path but does not alter read and other permissions.

See also
mutt_file_chmod_rm_stat()

Definition at line 1195 of file file.c.

1196{
1197 return mutt_file_chmod_rm_stat(path, mode, NULL);
1198}
int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st)
Remove permissions from a file.
Definition: file.c:1218
+ Here is the call 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 1218 of file file.c.

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

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

1296{
1297 struct flock unlockit;
1298
1299 memset(&unlockit, 0, sizeof(struct flock));
1300 unlockit.l_type = F_UNLCK;
1301 unlockit.l_whence = SEEK_SET;
1302 (void) fcntl(fd, F_SETLK, &unlockit);
1303
1304 return 0;
1305}
+ 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 1383 of file file.c.

1384{
1385 if (!path)
1386 return;
1387
1388 struct stat st = { 0 };
1389
1390 int fd = open(path, O_RDWR);
1391 if (fd == -1)
1392 return;
1393
1394 if (mutt_file_lock(fd, true, true) == -1)
1395 {
1396 close(fd);
1397 return;
1398 }
1399
1400 if ((fstat(fd, &st) == 0) && (st.st_size == 0))
1401 unlink(path);
1402
1403 mutt_file_unlock(fd);
1404 close(fd);
1405}
int mutt_file_lock(int fd, bool excl, bool timeout)
(Try to) Lock a file using fcntl()
Definition: file.c:1247
int mutt_file_unlock(int fd)
Unlock a file previously locked by mutt_file_lock()
Definition: file.c:1295
+ 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 1419 of file file.c.

1420{
1421 if (!oldfile || !newfile)
1422 return -1;
1423 if (access(oldfile, F_OK) != 0)
1424 return 1;
1425 if (access(newfile, F_OK) == 0)
1426 return 2;
1427
1428 FILE *fp_old = fopen(oldfile, "r");
1429 if (!fp_old)
1430 return 3;
1431 FILE *fp_new = mutt_file_fopen(newfile, "w");
1432 if (!fp_new)
1433 {
1434 mutt_file_fclose(&fp_old);
1435 return 3;
1436 }
1437 mutt_file_copy_stream(fp_old, fp_new);
1438 mutt_file_fclose(&fp_new);
1439 mutt_file_fclose(&fp_old);
1440 mutt_file_unlink(oldfile);
1441 return 0;
1442}
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:259
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:193
+ 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 1454 of file file.c.

1455{
1456 FILE *fp = mutt_file_fopen(file, "r");
1457 if (!fp)
1458 return NULL;
1459
1460 buf = fgets(buf, buflen, fp);
1461 mutt_file_fclose(&fp);
1462
1463 if (!buf)
1464 return NULL;
1465
1466 SKIPWS(buf);
1467 char *start = buf;
1468
1469 while ((*buf != '\0') && !isspace(*buf))
1470 buf++;
1471
1472 *buf = '\0';
1473
1474 return start;
1475}
#define SKIPWS(ch)
Definition: string2.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_file_check_empty()

int mutt_file_check_empty ( const char *  path)

Is the mailbox empty.

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

Definition at line 1484 of file file.c.

1485{
1486 if (!path)
1487 return -1;
1488
1489 struct stat st = { 0 };
1490 if (stat(path, &st) == -1)
1491 return -1;
1492
1493 return st.st_size == 0;
1494}
+ Here is the caller graph for this function:

◆ mutt_buffer_file_expand_fmt_quote()

void mutt_buffer_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 1504 of file file.c.

1505{
1506 struct Buffer tmp = mutt_buffer_make(PATH_MAX);
1507
1508 mutt_buffer_quote_filename(&tmp, src, true);
1509 mutt_file_expand_fmt(dest, fmt, mutt_buffer_string(&tmp));
1510 mutt_buffer_dealloc(&tmp);
1511}
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:907
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:1519
+ 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 1519 of file file.c.

1520{
1521 if (!dest || !fmt || !src)
1522 return;
1523
1524 const char *p = NULL;
1525 bool found = false;
1526
1527 mutt_buffer_reset(dest);
1528
1529 for (p = fmt; *p; p++)
1530 {
1531 if (*p == '%')
1532 {
1533 switch (p[1])
1534 {
1535 case '%':
1536 mutt_buffer_addch(dest, *p++);
1537 break;
1538 case 's':
1539 found = true;
1540 mutt_buffer_addstr(dest, src);
1541 p++;
1542 break;
1543 default:
1544 mutt_buffer_addch(dest, *p);
1545 break;
1546 }
1547 }
1548 else
1549 {
1550 mutt_buffer_addch(dest, *p);
1551 }
1552 }
1553
1554 if (!found)
1555 {
1556 mutt_buffer_addch(dest, ' ');
1557 mutt_buffer_addstr(dest, src);
1558 }
1559}
+ 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 1567 of file file.c.

1568{
1569 if (!path)
1570 return 0;
1571
1572 struct stat st = { 0 };
1573 if (stat(path, &st) != 0)
1574 return 0;
1575
1576 return st.st_size;
1577}
+ 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 1585 of file file.c.

1586{
1587 if (!fp)
1588 return 0;
1589
1590 struct stat st = { 0 };
1591 if (fstat(fileno(fp), &st) != 0)
1592 return 0;
1593
1594 return st.st_size;
1595}
+ 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 1605 of file file.c.

1606{
1607 if (!a || !b)
1608 return 0;
1609 if (a->tv_sec < b->tv_sec)
1610 return -1;
1611 if (a->tv_sec > b->tv_sec)
1612 return 1;
1613
1614 if (a->tv_nsec < b->tv_nsec)
1615 return -1;
1616 if (a->tv_nsec > b->tv_nsec)
1617 return 1;
1618 return 0;
1619}
long tv_nsec
Number of nanosecond, on top.
Definition: file.h:52
time_t tv_sec
Number of seconds since the epoch.
Definition: file.h:51
+ 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 1627 of file file.c.

1628{
1629 if (!dest || !st)
1630 return;
1631
1632 dest->tv_sec = 0;
1633 dest->tv_nsec = 0;
1634
1635 switch (type)
1636 {
1637 case MUTT_STAT_ATIME:
1638 dest->tv_sec = st->st_atime;
1639#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
1640 dest->tv_nsec = st->st_atim.tv_nsec;
1641#endif
1642 break;
1643 case MUTT_STAT_MTIME:
1644 dest->tv_sec = st->st_mtime;
1645#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1646 dest->tv_nsec = st->st_mtim.tv_nsec;
1647#endif
1648 break;
1649 case MUTT_STAT_CTIME:
1650 dest->tv_sec = st->st_ctime;
1651#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
1652 dest->tv_nsec = st->st_ctim.tv_nsec;
1653#endif
1654 break;
1655 }
1656}
@ MUTT_STAT_CTIME
File/dir's ctime - creation time.
Definition: file.h:65
@ MUTT_STAT_ATIME
File/dir's atime - last accessed time.
Definition: file.h:63
@ MUTT_STAT_MTIME
File/dir's mtime - last modified time.
Definition: file.h:64
+ 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 1667 of file file.c.

1669{
1670 if (!st || !b)
1671 return 0;
1672
1673 struct timespec a = { 0 };
1674
1675 mutt_file_get_stat_timespec(&a, st, type);
1676 return mutt_file_timespec_compare(&a, b);
1677}
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:1627
int mutt_file_timespec_compare(struct timespec *a, struct timespec *b)
Compare to time values.
Definition: file.c:1605
+ 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 1689 of file file.c.

1691{
1692 if (!st1 || !st2)
1693 return 0;
1694
1695 struct timespec a = { 0 };
1696 struct timespec b = { 0 };
1697
1698 mutt_file_get_stat_timespec(&a, st1, st1_type);
1699 mutt_file_get_stat_timespec(&b, st2, st2_type);
1700 return mutt_file_timespec_compare(&a, &b);
1701}
+ 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 1707 of file file.c.

1708{
1709 struct stat st = { 0 };
1710 int rc = lstat(mutt_buffer_string(buf), &st);
1711 if ((rc != -1) && S_ISLNK(st.st_mode))
1712 {
1713 char path[PATH_MAX] = { 0 };
1714 if (realpath(mutt_buffer_string(buf), path))
1715 {
1716 mutt_buffer_strcpy(buf, path);
1717 }
1718 }
1719}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ rx_special_chars

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

Definition at line 58 of file file.c.

◆ filename_safe_chars

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

Definition at line 60 of file file.c.