mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-25 23:21:33 +03:00
fd-util: add new helper fd_reopen_conditional()
This is a wrapper around fd_reopen() that will reopen an fd if the F_GETFL flags indicate this is necessary, and otherwise not. This is useful for various utility calls that shall be able to operate on O_PATH and without it, and might need to convert between the two depending on what's passed in.
This commit is contained in:
parent
0461375326
commit
5f5865f0ad
@ -780,6 +780,37 @@ int fd_reopen(int fd, int flags) {
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
int fd_reopen_condition(
|
||||
int fd,
|
||||
int flags,
|
||||
int mask,
|
||||
int *ret_new_fd) {
|
||||
|
||||
int r, new_fd;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
/* Invokes fd_reopen(fd, flags), but only if the existing F_GETFL flags don't match the specified
|
||||
* flags (masked by the specified mask). This is useful for converting O_PATH fds into real fds if
|
||||
* needed, but only then. */
|
||||
|
||||
r = fcntl(fd, F_GETFL);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if ((r & mask) == (flags & mask)) {
|
||||
*ret_new_fd = -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
new_fd = fd_reopen(fd, flags);
|
||||
if (new_fd < 0)
|
||||
return new_fd;
|
||||
|
||||
*ret_new_fd = new_fd;
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
int read_nr_open(void) {
|
||||
_cleanup_free_ char *nr_open = NULL;
|
||||
int r;
|
||||
|
@ -108,6 +108,7 @@ static inline int make_null_stdio(void) {
|
||||
})
|
||||
|
||||
int fd_reopen(int fd, int flags);
|
||||
int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
|
||||
int read_nr_open(void);
|
||||
int fd_get_diskseq(int fd, uint64_t *ret);
|
||||
|
||||
|
@ -483,6 +483,53 @@ TEST(fd_reopen) {
|
||||
fd1 = -1;
|
||||
}
|
||||
|
||||
TEST(fd_reopen_condition) {
|
||||
_cleanup_close_ int fd1 = -1, fd3 = -1;
|
||||
int fd2, fl;
|
||||
|
||||
/* Open without O_PATH */
|
||||
fd1 = open("/usr/", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
assert_se(fd1 >= 0);
|
||||
|
||||
fl = fcntl(fd1, F_GETFL);
|
||||
assert_se(FLAGS_SET(fl, O_DIRECTORY));
|
||||
assert_se(!FLAGS_SET(fl, O_PATH));
|
||||
|
||||
fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
|
||||
assert_se(fd2 == fd1);
|
||||
assert_se(fd3 < 0);
|
||||
|
||||
/* Switch on O_PATH */
|
||||
fd2 = fd_reopen_condition(fd1, O_DIRECTORY|O_PATH, O_DIRECTORY|O_PATH, &fd3);
|
||||
assert_se(fd2 != fd1);
|
||||
assert_se(fd3 == fd2);
|
||||
|
||||
fl = fcntl(fd2, F_GETFL);
|
||||
assert_se(FLAGS_SET(fl, O_DIRECTORY));
|
||||
assert_se(FLAGS_SET(fl, O_PATH));
|
||||
|
||||
close_and_replace(fd1, fd3);
|
||||
|
||||
fd2 = fd_reopen_condition(fd1, O_DIRECTORY|O_PATH, O_DIRECTORY|O_PATH, &fd3);
|
||||
assert_se(fd2 == fd1);
|
||||
assert_se(fd3 < 0);
|
||||
|
||||
/* Switch off O_PATH again */
|
||||
fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
|
||||
assert_se(fd2 != fd1);
|
||||
assert_se(fd3 == fd2);
|
||||
|
||||
fl = fcntl(fd2, F_GETFL);
|
||||
assert_se(FLAGS_SET(fl, O_DIRECTORY));
|
||||
assert_se(!FLAGS_SET(fl, O_PATH));
|
||||
|
||||
close_and_replace(fd1, fd3);
|
||||
|
||||
fd2 = fd_reopen_condition(fd1, O_DIRECTORY, O_DIRECTORY|O_PATH, &fd3);
|
||||
assert_se(fd2 == fd1);
|
||||
assert_se(fd3 < 0);
|
||||
}
|
||||
|
||||
TEST(take_fd) {
|
||||
_cleanup_close_ int fd1 = -1, fd2 = -1;
|
||||
int array[2] = { -1, -1 }, i = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user