fileio: add an openat() flavour for fopen()

This adds xfopenat() which is to fopen() what xopendirat() is to
opendir(), i.e. the "at" counterpart to fopen().

(Similar to the xopendir() case, we prefix this with "x", in case libc
gains this natively eventually.)
This commit is contained in:
Lennart Poettering 2019-01-08 18:23:40 +01:00
parent 6d8f06368b
commit 0a38e6b9a3
2 changed files with 76 additions and 0 deletions

View file

@ -680,6 +680,81 @@ DIR *xopendirat(int fd, const char *name, int flags) {
return d;
}
static int mode_to_flags(const char *mode) {
const char *p;
int flags;
if ((p = startswith(mode, "r+")))
flags = O_RDWR;
else if ((p = startswith(mode, "r")))
flags = O_RDONLY;
else if ((p = startswith(mode, "w+")))
flags = O_RDWR|O_CREAT|O_TRUNC;
else if ((p = startswith(mode, "w")))
flags = O_WRONLY|O_CREAT|O_TRUNC;
else if ((p = startswith(mode, "a+")))
flags = O_RDWR|O_CREAT|O_APPEND;
else if ((p = startswith(mode, "a")))
flags = O_WRONLY|O_CREAT|O_APPEND;
else
return -EINVAL;
for (; *p != 0; p++) {
switch (*p) {
case 'e':
flags |= O_CLOEXEC;
break;
case 'x':
flags |= O_EXCL;
break;
case 'm':
/* ignore this here, fdopen() might care later though */
break;
case 'c': /* not sure what to do about this one */
default:
return -EINVAL;
}
}
return flags;
}
int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
FILE *f;
/* A combination of fopen() with openat() */
if (dir_fd == AT_FDCWD && flags == 0) {
f = fopen(path, mode);
if (!f)
return -errno;
} else {
int fd, mode_flags;
mode_flags = mode_to_flags(mode);
if (mode_flags < 0)
return mode_flags;
fd = openat(dir_fd, path, mode_flags | flags);
if (fd < 0)
return -errno;
f = fdopen(fd, mode);
if (!f) {
safe_close(fd);
return -errno;
}
}
*ret = f;
return 0;
}
static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
char **i;

View file

@ -69,6 +69,7 @@ int executable_is_script(const char *path, char **interpreter);
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
DIR *xopendirat(int dirfd, const char *name, int flags);
int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret);
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);