logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git

fs.c (2406B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. // For copy_file_range
  5. #define _GNU_SOURCE // musl, glibc
  6. #define _DEFAULT_SOURCE // FreeBSD
  7. #include "./fs.h"
  8. #include <errno.h>
  9. #include <stdio.h> // BUFSIZ
  10. #include <string.h> // strrchr
  11. #include <unistd.h> // copy_file_range
  12. #ifdef HAS_SENDFILE
  13. #include <sys/sendfile.h>
  14. #endif
  15. char *
  16. static_basename(char *p)
  17. {
  18. if(!p || !*p) return p;
  19. size_t i = strlen(p) - 1;
  20. for(; i && p[i] == '/'; i--)
  21. ;
  22. for(; i && p[i - 1] != '/'; i--)
  23. ;
  24. return p + i;
  25. }
  26. char *
  27. path_split_static(char *path, bool trim)
  28. {
  29. char *child = NULL;
  30. size_t path_len = strlen(path);
  31. // delete trailing slashes
  32. if(trim)
  33. for(int i = path_len - 1; i > 0 && path[i] == '/'; i--)
  34. path[i] = 0;
  35. for(int i = path_len - 1; i > 0; i--)
  36. if(path[i] == '/')
  37. {
  38. path[i] = 0;
  39. child = &path[i + 1];
  40. break;
  41. }
  42. return child;
  43. }
  44. #ifndef MIN
  45. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  46. #endif
  47. ssize_t
  48. manual_file_copy(int fd_in, int fd_out, off_t len, int flags)
  49. {
  50. ssize_t wrote = 0;
  51. do
  52. {
  53. char buf[BUFSIZ];
  54. ssize_t nread = read(fd_in, buf, MIN(BUFSIZ, len));
  55. if(nread < 0) return nread;
  56. if(nread == 0) return wrote;
  57. ssize_t nwrite = write(fd_out, buf, (size_t)nread);
  58. if(nwrite < 0) return nwrite;
  59. len -= nwrite;
  60. wrote += nwrite;
  61. } while(len > 0);
  62. return wrote;
  63. }
  64. #ifdef HAS_COPY_FILE_RANGE
  65. ssize_t
  66. auto_file_copy(int fd_in, int fd_out, off_t len, int flags)
  67. {
  68. ssize_t wrote = 0;
  69. off_t ret = -1;
  70. do
  71. {
  72. ret = copy_file_range(fd_in, NULL, fd_out, NULL, len, 0);
  73. if(ret < 0)
  74. {
  75. if(errno == EXDEV || errno == EINVAL)
  76. {
  77. errno = 0;
  78. return manual_file_copy(fd_in, fd_out, len, flags);
  79. }
  80. return ret;
  81. }
  82. len -= ret;
  83. wrote += ret;
  84. } while(len > 0 && ret > 0);
  85. return wrote;
  86. }
  87. #endif
  88. #ifdef HAS_SENDFILE
  89. ssize_t
  90. auto_fd_copy(int fd_in, int fd_out, size_t len)
  91. {
  92. off_t *off = NULL;
  93. ssize_t wrote = 0;
  94. while(1)
  95. {
  96. ssize_t ret = sendfile(fd_out, fd_in, off, len);
  97. if(ret < 0)
  98. {
  99. switch(errno)
  100. {
  101. case EINVAL:
  102. errno = 0;
  103. return manual_file_copy(fd_in, fd_out, len, 0);
  104. case EAGAIN:
  105. errno = 0;
  106. continue;
  107. default:
  108. return ret;
  109. }
  110. }
  111. wrote += ret;
  112. len -= ret;
  113. if(ret == 0) return wrote;
  114. }
  115. return -1;
  116. }
  117. #endif // HAS_SENDFILE