fileio: introduce xfopenat_full()
This unifies call of various xfopenat() variants. No functional change, just refactoring.
This commit is contained in:
+86
-65
@@ -44,20 +44,6 @@
|
||||
* can detect EOFs. */
|
||||
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U)
|
||||
|
||||
int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret) {
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = xfopenat(dir_fd, path, options, flags, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) __fsetlocking(*ret, FSETLOCKING_BYCALLER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdopen_unlocked(int fd, const char *options, FILE **ret) {
|
||||
assert(ret);
|
||||
|
||||
@@ -759,60 +745,19 @@ int read_full_file_full(
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
XfopenFlags xflags = XFOPEN_UNLOCKED;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(ret_contents);
|
||||
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0) {
|
||||
_cleanup_close_ int sk = -EBADF;
|
||||
if (FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET) && /* If this is enabled, let's try to connect to it */
|
||||
offset == UINT64_MAX) /* Seeking is not supported on AF_UNIX sockets */
|
||||
xflags |= XFOPEN_SOCKET;
|
||||
|
||||
/* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
|
||||
if (r != -ENXIO)
|
||||
return r;
|
||||
|
||||
/* If this is enabled, let's try to connect to it */
|
||||
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
|
||||
return -ENXIO;
|
||||
|
||||
/* Seeking is not supported on AF_UNIX sockets */
|
||||
if (offset != UINT64_MAX)
|
||||
return -ENXIO;
|
||||
|
||||
sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||
if (sk < 0)
|
||||
return -errno;
|
||||
|
||||
if (bind_name) {
|
||||
/* If the caller specified a socket name to bind to, do so before connecting. This is
|
||||
* useful to communicate some minor, short meta-information token from the client to
|
||||
* the server. */
|
||||
union sockaddr_union bsa;
|
||||
|
||||
r = sockaddr_un_set_path(&bsa.un, bind_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (bind(sk, &bsa.sa, r) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = connect_unix_path(sk, dir_fd, filename);
|
||||
if (IN_SET(r, -ENOTSOCK, -EINVAL)) /* propagate original error if this is not a socket after all */
|
||||
return -ENXIO;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (shutdown(sk, SHUT_WR) < 0)
|
||||
return -errno;
|
||||
|
||||
f = take_fdopen(&sk, "r");
|
||||
if (!f)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
r = xfopenat_full(dir_fd, filename, "re", 0, xflags, bind_name, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
|
||||
}
|
||||
@@ -979,7 +924,7 @@ int fopen_mode_to_flags(const char *mode) {
|
||||
return flags;
|
||||
}
|
||||
|
||||
int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
|
||||
static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
|
||||
FILE *f;
|
||||
|
||||
/* A combination of fopen() with openat() */
|
||||
@@ -989,7 +934,7 @@ int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **r
|
||||
assert(mode);
|
||||
assert(ret);
|
||||
|
||||
if (dir_fd == AT_FDCWD && flags == 0)
|
||||
if (dir_fd == AT_FDCWD && open_flags == 0)
|
||||
f = fopen(path, mode);
|
||||
else {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
@@ -999,7 +944,7 @@ int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **r
|
||||
if (mode_flags < 0)
|
||||
return mode_flags;
|
||||
|
||||
fd = openat(dir_fd, path, mode_flags | flags);
|
||||
fd = openat(dir_fd, path, mode_flags | open_flags);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
@@ -1012,6 +957,82 @@ int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **r
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xfopenat_unix_socket(int dir_fd, const char *path, const char *bind_name, FILE **ret) {
|
||||
_cleanup_close_ int sk = -EBADF;
|
||||
FILE *f;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||
if (sk < 0)
|
||||
return -errno;
|
||||
|
||||
if (bind_name) {
|
||||
/* If the caller specified a socket name to bind to, do so before connecting. This is
|
||||
* useful to communicate some minor, short meta-information token from the client to
|
||||
* the server. */
|
||||
union sockaddr_union bsa;
|
||||
|
||||
r = sockaddr_un_set_path(&bsa.un, bind_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (bind(sk, &bsa.sa, r) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = connect_unix_path(sk, dir_fd, path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (shutdown(sk, SHUT_WR) < 0)
|
||||
return -errno;
|
||||
|
||||
f = take_fdopen(&sk, "r");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
*ret = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xfopenat_full(
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
const char *mode,
|
||||
int open_flags,
|
||||
XfopenFlags flags,
|
||||
const char *bind_name,
|
||||
FILE **ret) {
|
||||
|
||||
FILE *f = NULL; /* avoid false maybe-uninitialized warning */
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
assert(mode);
|
||||
assert(ret);
|
||||
|
||||
r = xfopenat_regular(dir_fd, path, mode, open_flags, &f);
|
||||
if (r == -ENXIO && FLAGS_SET(flags, XFOPEN_SOCKET)) {
|
||||
/* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
|
||||
r = xfopenat_unix_socket(dir_fd, path, bind_name, &f);
|
||||
if (IN_SET(r, -ENOTSOCK, -EINVAL))
|
||||
return -ENXIO; /* propagate original error if this is not a socket after all */
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (FLAGS_SET(flags, XFOPEN_UNLOCKED))
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
|
||||
*ret = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdopen_independent(int fd, const char *mode, FILE **ret) {
|
||||
_cleanup_close_ int copy_fd = -EBADF;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
+23
-5
@@ -43,10 +43,6 @@ typedef enum {
|
||||
READ_FULL_FILE_FAIL_WHEN_LARGER = 1 << 5, /* fail loading if file is larger than specified size */
|
||||
} ReadFullFileFlags;
|
||||
|
||||
int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret);
|
||||
static inline int fopen_unlocked(const char *path, const char *options, FILE **ret) {
|
||||
return fopen_unlocked_at(AT_FDCWD, path, options, 0, ret);
|
||||
}
|
||||
int fdopen_unlocked(int fd, const char *options, FILE **ret);
|
||||
int take_fdopen_unlocked(int *fd, const char *options, FILE **ret);
|
||||
FILE* take_fdopen(int *fd, const char *options);
|
||||
@@ -104,7 +100,29 @@ 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);
|
||||
|
||||
typedef enum XfopenFlags {
|
||||
XFOPEN_UNLOCKED = 1 << 0, /* call __fsetlocking(FSETLOCKING_BYCALLER) after opened */
|
||||
XFOPEN_SOCKET = 1 << 1, /* also try to open unix socket */
|
||||
} XfopenFlags;
|
||||
|
||||
int xfopenat_full(
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
const char *mode,
|
||||
int open_flags,
|
||||
XfopenFlags flags,
|
||||
const char *bind_name,
|
||||
FILE **ret);
|
||||
static inline int xfopenat(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
|
||||
return xfopenat_full(dir_fd, path, mode, open_flags, 0, NULL, ret);
|
||||
}
|
||||
static inline int fopen_unlocked_at(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
|
||||
return xfopenat_full(dir_fd, path, mode, open_flags, XFOPEN_UNLOCKED, NULL, ret);
|
||||
}
|
||||
static inline int fopen_unlocked(const char *path, const char *mode, FILE **ret) {
|
||||
return fopen_unlocked_at(AT_FDCWD, path, mode, 0, ret);
|
||||
}
|
||||
|
||||
int fdopen_independent(int fd, const char *mode, FILE **ret);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user