You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
5.5 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2012-2014, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <stdio.h>
  12. #include <unistd.h>
  13. #include <sys/types.h>
  14. #include "libcork/ds/stream.h"
  15. #include "libcork/helpers/errors.h"
  16. #include "libcork/helpers/posix.h"
  17. #define BUFFER_SIZE 4096
  18. /*-----------------------------------------------------------------------
  19. * Producers
  20. */
  21. int
  22. cork_consume_fd(struct cork_stream_consumer *consumer, int fd)
  23. {
  24. char buf[BUFFER_SIZE];
  25. ssize_t bytes_read;
  26. bool first = true;
  27. while (true) {
  28. while ((bytes_read = read(fd, buf, BUFFER_SIZE)) > 0) {
  29. rii_check(cork_stream_consumer_data
  30. (consumer, buf, bytes_read, first));
  31. first = false;
  32. }
  33. if (bytes_read == 0) {
  34. return cork_stream_consumer_eof(consumer);
  35. } else if (errno != EINTR) {
  36. cork_system_error_set();
  37. return -1;
  38. }
  39. }
  40. }
  41. int
  42. cork_consume_file(struct cork_stream_consumer *consumer, FILE *fp)
  43. {
  44. char buf[BUFFER_SIZE];
  45. size_t bytes_read;
  46. bool first = true;
  47. while (true) {
  48. while ((bytes_read = fread(buf, 1, BUFFER_SIZE, fp)) > 0) {
  49. rii_check(cork_stream_consumer_data
  50. (consumer, buf, bytes_read, first));
  51. first = false;
  52. }
  53. if (feof(fp)) {
  54. return cork_stream_consumer_eof(consumer);
  55. } else if (errno != EINTR) {
  56. cork_system_error_set();
  57. return -1;
  58. }
  59. }
  60. }
  61. int
  62. cork_consume_file_from_path(struct cork_stream_consumer *consumer,
  63. const char *path, int flags)
  64. {
  65. int fd;
  66. rii_check_posix(fd = open(path, flags));
  67. ei_check(cork_consume_fd(consumer, fd));
  68. rii_check_posix(close(fd));
  69. return 0;
  70. error:
  71. rii_check_posix(close(fd));
  72. return -1;
  73. }
  74. /*-----------------------------------------------------------------------
  75. * Consumers
  76. */
  77. struct cork_file_consumer {
  78. struct cork_stream_consumer parent;
  79. FILE *fp;
  80. };
  81. static int
  82. cork_file_consumer__data(struct cork_stream_consumer *vself,
  83. const void *buf, size_t size, bool is_first)
  84. {
  85. struct cork_file_consumer *self =
  86. cork_container_of(vself, struct cork_file_consumer, parent);
  87. size_t bytes_written = fwrite(buf, 1, size, self->fp);
  88. /* If there was an error writing to the file, then signal this to
  89. * the producer */
  90. if (bytes_written == size) {
  91. return 0;
  92. } else {
  93. cork_system_error_set();
  94. return -1;
  95. }
  96. }
  97. static int
  98. cork_file_consumer__eof(struct cork_stream_consumer *vself)
  99. {
  100. /* We never close the file with this version of the consumer, so there's
  101. * nothing special to do at end-of-stream. */
  102. return 0;
  103. }
  104. static void
  105. cork_file_consumer__free(struct cork_stream_consumer *vself)
  106. {
  107. struct cork_file_consumer *self =
  108. cork_container_of(vself, struct cork_file_consumer, parent);
  109. cork_delete(struct cork_file_consumer, self);
  110. }
  111. struct cork_stream_consumer *
  112. cork_file_consumer_new(FILE *fp)
  113. {
  114. struct cork_file_consumer *self = cork_new(struct cork_file_consumer);
  115. self->parent.data = cork_file_consumer__data;
  116. self->parent.eof = cork_file_consumer__eof;
  117. self->parent.free = cork_file_consumer__free;
  118. self->fp = fp;
  119. return &self->parent;
  120. }
  121. struct cork_fd_consumer {
  122. struct cork_stream_consumer parent;
  123. int fd;
  124. };
  125. static int
  126. cork_fd_consumer__data(struct cork_stream_consumer *vself,
  127. const void *buf, size_t size, bool is_first)
  128. {
  129. struct cork_fd_consumer *self =
  130. cork_container_of(vself, struct cork_fd_consumer, parent);
  131. size_t bytes_left = size;
  132. while (bytes_left > 0) {
  133. ssize_t rc = write(self->fd, buf, bytes_left);
  134. if (rc == -1 && errno != EINTR) {
  135. cork_system_error_set();
  136. return -1;
  137. } else {
  138. bytes_left -= rc;
  139. buf += rc;
  140. }
  141. }
  142. return 0;
  143. }
  144. static int
  145. cork_fd_consumer__eof_close(struct cork_stream_consumer *vself)
  146. {
  147. int rc;
  148. struct cork_fd_consumer *self =
  149. cork_container_of(vself, struct cork_fd_consumer, parent);
  150. rii_check_posix(rc = close(self->fd));
  151. return 0;
  152. }
  153. static void
  154. cork_fd_consumer__free(struct cork_stream_consumer *vself)
  155. {
  156. struct cork_fd_consumer *self =
  157. cork_container_of(vself, struct cork_fd_consumer, parent);
  158. cork_delete(struct cork_fd_consumer, self);
  159. }
  160. struct cork_stream_consumer *
  161. cork_fd_consumer_new(int fd)
  162. {
  163. struct cork_fd_consumer *self = cork_new(struct cork_fd_consumer);
  164. self->parent.data = cork_fd_consumer__data;
  165. /* We don't want to close fd, so we reuse file_consumer's eof method */
  166. self->parent.eof = cork_file_consumer__eof;
  167. self->parent.free = cork_fd_consumer__free;
  168. self->fd = fd;
  169. return &self->parent;
  170. }
  171. struct cork_stream_consumer *
  172. cork_file_from_path_consumer_new(const char *path, int flags)
  173. {
  174. int fd;
  175. struct cork_fd_consumer *self;
  176. rpi_check_posix(fd = open(path, flags));
  177. self = cork_new(struct cork_fd_consumer);
  178. self->parent.data = cork_fd_consumer__data;
  179. self->parent.eof = cork_fd_consumer__eof_close;
  180. self->parent.free = cork_fd_consumer__free;
  181. self->fd = fd;
  182. return &self->parent;
  183. }