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.

215 lines
5.4 KiB

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