hardlink.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test io_uring linkat handling
  5. */
  6. #include <fcntl.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <sys/stat.h>
  10. #include <sys/types.h>
  11. #include <unistd.h>
  12. #include "liburing.h"
  13. #include "helpers.h"
  14. static int do_linkat(struct io_uring *ring, const char *oldname, const char *newname)
  15. {
  16. int ret;
  17. struct io_uring_sqe *sqe;
  18. struct io_uring_cqe *cqe;
  19. sqe = io_uring_get_sqe(ring);
  20. if (!sqe) {
  21. fprintf(stderr, "sqe get failed\n");
  22. goto err;
  23. }
  24. io_uring_prep_linkat(sqe, AT_FDCWD, oldname, AT_FDCWD, newname, 0);
  25. ret = io_uring_submit(ring);
  26. if (ret != 1) {
  27. fprintf(stderr, "submit failed: %d\n", ret);
  28. goto err;
  29. }
  30. ret = io_uring_wait_cqes(ring, &cqe, 1, 0, 0);
  31. if (ret) {
  32. fprintf(stderr, "wait_cqe failed: %d\n", ret);
  33. goto err;
  34. }
  35. ret = cqe->res;
  36. io_uring_cqe_seen(ring, cqe);
  37. return ret;
  38. err:
  39. return 1;
  40. }
  41. static int files_linked_ok(const char* fn1, const char *fn2)
  42. {
  43. struct stat s1, s2;
  44. if (stat(fn1, &s1)) {
  45. fprintf(stderr, "stat(%s): %s\n", fn1, strerror(errno));
  46. return 0;
  47. }
  48. if (stat(fn2, &s2)) {
  49. fprintf(stderr, "stat(%s): %s\n", fn2, strerror(errno));
  50. return 0;
  51. }
  52. if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino) {
  53. fprintf(stderr, "linked files have different device / inode numbers\n");
  54. return 0;
  55. }
  56. if (s1.st_nlink != 2 || s2.st_nlink != 2) {
  57. fprintf(stderr, "linked files have unexpected links count\n");
  58. return 0;
  59. }
  60. return 1;
  61. }
  62. int main(int argc, char *argv[])
  63. {
  64. static const char target[] = "io_uring-linkat-test-target";
  65. static const char linkname[] = "io_uring-linkat-test-link";
  66. int ret;
  67. struct io_uring ring;
  68. if (argc > 1)
  69. return T_EXIT_SKIP;
  70. ret = io_uring_queue_init(8, &ring, 0);
  71. if (ret) {
  72. fprintf(stderr, "queue init failed: %d\n", ret);
  73. return ret;
  74. }
  75. ret = open(target, O_CREAT | O_RDWR | O_EXCL, 0600);
  76. if (ret < 0) {
  77. perror("open");
  78. goto err;
  79. }
  80. if (write(ret, "linktest", 8) != 8) {
  81. close(ret);
  82. goto err1;
  83. }
  84. close(ret);
  85. ret = do_linkat(&ring, target, linkname);
  86. if (ret < 0) {
  87. if (ret == -EBADF || ret == -EINVAL) {
  88. fprintf(stdout, "linkat not supported, skipping\n");
  89. goto skip;
  90. }
  91. fprintf(stderr, "linkat: %s\n", strerror(-ret));
  92. goto err1;
  93. } else if (ret) {
  94. goto err1;
  95. }
  96. if (!files_linked_ok(linkname, target))
  97. goto err2;
  98. ret = do_linkat(&ring, target, linkname);
  99. if (ret != -EEXIST) {
  100. fprintf(stderr, "test_linkat linkname already exists failed: %d\n", ret);
  101. goto err2;
  102. }
  103. ret = do_linkat(&ring, target, "surely/this/does/not/exist");
  104. if (ret != -ENOENT) {
  105. fprintf(stderr, "test_linkat no parent failed: %d\n", ret);
  106. goto err2;
  107. }
  108. unlinkat(AT_FDCWD, linkname, 0);
  109. unlinkat(AT_FDCWD, target, 0);
  110. io_uring_queue_exit(&ring);
  111. return T_EXIT_PASS;
  112. skip:
  113. unlinkat(AT_FDCWD, linkname, 0);
  114. unlinkat(AT_FDCWD, target, 0);
  115. io_uring_queue_exit(&ring);
  116. return T_EXIT_SKIP;
  117. err2:
  118. unlinkat(AT_FDCWD, linkname, 0);
  119. err1:
  120. unlinkat(AT_FDCWD, target, 0);
  121. err:
  122. io_uring_queue_exit(&ring);
  123. return T_EXIT_FAIL;
  124. }