Tests successful creation (using readlink() to verify the contents), EEXIST, ENOENT cases. Signed-off-by: Dmitry Kadashev <dkadashev@xxxxxxxxx> --- .gitignore | 1 + test/Makefile | 2 + test/symlink.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 test/symlink.c diff --git a/.gitignore b/.gitignore index a9ae5bb..0b336d6 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,7 @@ /test/statx /test/stdout /test/submit-reuse +/test/symlink /test/teardowns /test/thread-exit /test/timeout diff --git a/test/Makefile b/test/Makefile index 86437d5..4fc78ea 100644 --- a/test/Makefile +++ b/test/Makefile @@ -108,6 +108,7 @@ test_targets += \ sq-space_left \ stdout \ submit-reuse \ + symlink \ teardowns \ thread-exit \ timeout \ @@ -248,6 +249,7 @@ test_srcs := \ statx.c \ stdout.c \ submit-reuse.c \ + symlink.c \ teardowns.c \ thread-exit.c \ timeout-new.c \ diff --git a/test/symlink.c b/test/symlink.c new file mode 100644 index 0000000..8b5e04a --- /dev/null +++ b/test/symlink.c @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Description: test io_uring symlinkat handling + */ +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "liburing.h" + + +static int do_symlinkat(struct io_uring *ring, const char *oldname, const char *newname) +{ + int ret; + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "sqe get failed\n"); + goto err; + } + io_uring_prep_symlinkat(sqe, oldname, AT_FDCWD, newname); + + ret = io_uring_submit(ring); + if (ret != 1) { + fprintf(stderr, "submit failed: %d\n", ret); + goto err; + } + + ret = io_uring_wait_cqes(ring, &cqe, 1, 0, 0); + if (ret) { + fprintf(stderr, "wait_cqe failed: %d\n", ret); + goto err; + } + ret = cqe->res; + io_uring_cqe_seen(ring, cqe); + return ret; +err: + return 1; +} + +int test_link_contents(const char* linkname, const char *expected_contents) +{ + char buf[128]; + int ret = readlink(linkname, buf, 127); + if (ret < 0) { + perror("readlink"); + return ret; + } + buf[ret] = 0; + if (strncmp(buf, expected_contents, 128)) { + fprintf(stderr, "link contents differs from expected: '%s' vs '%s'", + buf, expected_contents); + return -1; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + static const char target[] = "io_uring-symlinkat-test-target"; + static const char linkname[] = "io_uring-symlinkat-test-link"; + int ret; + struct io_uring ring; + + ret = io_uring_queue_init(8, &ring, 0); + if (ret) { + fprintf(stderr, "queue init failed: %d\n", ret); + return ret; + } + + ret = do_symlinkat(&ring, target, linkname); + if (ret < 0) { + if (ret == -EBADF || ret == -EINVAL) { + fprintf(stdout, "symlinkat not supported, skipping\n"); + goto out; + } + fprintf(stderr, "symlinkat: %s\n", strerror(-ret)); + goto err; + } else if (ret) { + goto err; + } + + ret = test_link_contents(linkname, target); + if (ret < 0) + goto err1; + + ret = do_symlinkat(&ring, target, linkname); + if (ret != -EEXIST) { + fprintf(stderr, "test_symlinkat linkname already exists failed: %d\n", ret); + goto err1; + } + + ret = do_symlinkat(&ring, target, "surely/this/does/not/exist"); + if (ret != -ENOENT) { + fprintf(stderr, "test_symlinkat no parent failed: %d\n", ret); + goto err1; + } + +out: + unlinkat(AT_FDCWD, linkname, 0); + io_uring_queue_exit(&ring); + return 0; +err1: + unlinkat(AT_FDCWD, linkname, 0); +err: + io_uring_queue_exit(&ring); + return 1; +} -- 2.30.2