fopencookie.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #define _GNU_SOURCE
  2. #include "stdio_impl.h"
  3. #include <stdlib.h>
  4. #include <sys/ioctl.h>
  5. #include <fcntl.h>
  6. #include <errno.h>
  7. #include <string.h>
  8. struct fcookie {
  9. void *cookie;
  10. cookie_io_functions_t iofuncs;
  11. };
  12. struct cookie_FILE {
  13. FILE f;
  14. struct fcookie fc;
  15. unsigned char buf[UNGET+BUFSIZ];
  16. };
  17. static size_t cookieread(FILE *f, unsigned char *buf, size_t len)
  18. {
  19. struct fcookie *fc = f->cookie;
  20. ssize_t ret = -1;
  21. size_t remain = len, readlen = 0;
  22. size_t len2 = len - !!f->buf_size;
  23. if (!fc->iofuncs.read) goto bail;
  24. if (len2) {
  25. ret = fc->iofuncs.read(fc->cookie, (char *) buf, len2);
  26. if (ret <= 0) goto bail;
  27. readlen += ret;
  28. remain -= ret;
  29. }
  30. if (!f->buf_size || remain > !!f->buf_size) return readlen;
  31. f->rpos = f->buf;
  32. ret = fc->iofuncs.read(fc->cookie, (char *) f->rpos, f->buf_size);
  33. if (ret <= 0) goto bail;
  34. f->rend = f->rpos + ret;
  35. buf[readlen++] = *f->rpos++;
  36. return readlen;
  37. bail:
  38. f->flags |= ret == 0 ? F_EOF : F_ERR;
  39. f->rpos = f->rend = f->buf;
  40. return readlen;
  41. }
  42. static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len)
  43. {
  44. struct fcookie *fc = f->cookie;
  45. ssize_t ret;
  46. size_t len2 = f->wpos - f->wbase;
  47. if (!fc->iofuncs.write) return len;
  48. if (len2) {
  49. f->wpos = f->wbase;
  50. if (cookiewrite(f, f->wpos, len2) < len2) return 0;
  51. }
  52. ret = fc->iofuncs.write(fc->cookie, (const char *) buf, len);
  53. if (ret < 0) {
  54. f->wpos = f->wbase = f->wend = 0;
  55. f->flags |= F_ERR;
  56. return 0;
  57. }
  58. return ret;
  59. }
  60. static off_t cookieseek(FILE *f, off_t off, int whence)
  61. {
  62. struct fcookie *fc = f->cookie;
  63. int res;
  64. if (whence > 2U) {
  65. errno = EINVAL;
  66. return -1;
  67. }
  68. if (!fc->iofuncs.seek) {
  69. errno = ENOTSUP;
  70. return -1;
  71. }
  72. res = fc->iofuncs.seek(fc->cookie, &off, whence);
  73. if (res < 0)
  74. return res;
  75. return off;
  76. }
  77. static int cookieclose(FILE *f)
  78. {
  79. struct fcookie *fc = f->cookie;
  80. if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie);
  81. return 0;
  82. }
  83. FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs)
  84. {
  85. struct cookie_FILE *f;
  86. /* Check for valid initial mode character */
  87. if (!strchr("rwa", *mode)) {
  88. errno = EINVAL;
  89. return 0;
  90. }
  91. /* Allocate FILE+fcookie+buffer or fail */
  92. if (!(f=malloc(sizeof *f))) return 0;
  93. /* Zero-fill only the struct, not the buffer */
  94. memset(&f->f, 0, sizeof f->f);
  95. /* Impose mode restrictions */
  96. if (!strchr(mode, '+')) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD;
  97. /* Set up our fcookie */
  98. f->fc.cookie = cookie;
  99. f->fc.iofuncs.read = iofuncs.read;
  100. f->fc.iofuncs.write = iofuncs.write;
  101. f->fc.iofuncs.seek = iofuncs.seek;
  102. f->fc.iofuncs.close = iofuncs.close;
  103. f->f.fd = -1;
  104. f->f.cookie = &f->fc;
  105. f->f.buf = f->buf + UNGET;
  106. f->f.buf_size = BUFSIZ;
  107. f->f.lbf = EOF;
  108. /* Initialize op ptrs. No problem if some are unneeded. */
  109. f->f.read = cookieread;
  110. f->f.write = cookiewrite;
  111. f->f.seek = cookieseek;
  112. f->f.close = cookieclose;
  113. /* Add new FILE to open file list */
  114. return __ofl_add(&f->f);
  115. }