fmemopen.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* fmemopen implementation.
  2. Copyright (C) 2015-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. /* fmemopen() from 2.22 and forward works as defined by POSIX. It also
  16. provides an older symbol, version 2.2.5, that behaves different regarding
  17. SEEK_END (libio/oldfmemopen.c). */
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <stdint.h>
  22. #include <string.h>
  23. #include <sys/types.h>
  24. #include "libioP.h"
  25. typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
  26. struct fmemopen_cookie_struct
  27. {
  28. char *buffer; /* memory buffer. */
  29. int mybuffer; /* allocated my buffer? */
  30. int append; /* buffer open for append? */
  31. size_t size; /* buffer length in bytes. */
  32. off64_t pos; /* current position at the buffer. */
  33. size_t maxpos; /* max position in buffer. */
  34. };
  35. static ssize_t
  36. fmemopen_read (void *cookie, char *b, size_t s)
  37. {
  38. fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
  39. if (c->pos + s > c->maxpos)
  40. {
  41. s = c->maxpos - c->pos;
  42. if ((size_t) c->pos > c->maxpos)
  43. s = 0;
  44. }
  45. memcpy (b, &(c->buffer[c->pos]), s);
  46. c->pos += s;
  47. return s;
  48. }
  49. static ssize_t
  50. fmemopen_write (void *cookie, const char *b, size_t s)
  51. {
  52. fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
  53. off64_t pos = c->append ? c->maxpos : c->pos;
  54. int addnullc = (s == 0 || b[s - 1] != '\0');
  55. if (pos + s > c->size)
  56. {
  57. if ((size_t) (c->pos + addnullc) >= c->size)
  58. {
  59. __set_errno (ENOSPC);
  60. return 0;
  61. }
  62. s = c->size - pos;
  63. }
  64. memcpy (&(c->buffer[pos]), b, s);
  65. c->pos = pos + s;
  66. if ((size_t) c->pos > c->maxpos)
  67. {
  68. c->maxpos = c->pos;
  69. if (c->maxpos < c->size && addnullc)
  70. c->buffer[c->maxpos] = '\0';
  71. /* A null byte is written in a stream open for update iff it fits. */
  72. else if (c->append == 0 && addnullc != 0)
  73. c->buffer[c->size-1] = '\0';
  74. }
  75. return s;
  76. }
  77. static int
  78. fmemopen_seek (void *cookie, off64_t *p, int w)
  79. {
  80. off64_t np;
  81. fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
  82. switch (w)
  83. {
  84. case SEEK_SET:
  85. np = *p;
  86. break;
  87. case SEEK_CUR:
  88. np = c->pos + *p;
  89. break;
  90. case SEEK_END:
  91. np = c->maxpos + *p;
  92. break;
  93. default:
  94. return -1;
  95. }
  96. if (np < 0 || (size_t) np > c->size)
  97. {
  98. __set_errno (EINVAL);
  99. return -1;
  100. }
  101. *p = c->pos = np;
  102. return 0;
  103. }
  104. static int
  105. fmemopen_close (void *cookie)
  106. {
  107. fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
  108. if (c->mybuffer)
  109. free (c->buffer);
  110. free (c);
  111. return 0;
  112. }
  113. FILE *
  114. __fmemopen (void *buf, size_t len, const char *mode)
  115. {
  116. cookie_io_functions_t iof;
  117. fmemopen_cookie_t *c;
  118. FILE *result;
  119. c = (fmemopen_cookie_t *) calloc (sizeof (fmemopen_cookie_t), 1);
  120. if (c == NULL)
  121. return NULL;
  122. c->mybuffer = (buf == NULL);
  123. if (c->mybuffer)
  124. {
  125. c->buffer = (char *) malloc (len);
  126. if (c->buffer == NULL)
  127. {
  128. free (c);
  129. return NULL;
  130. }
  131. c->buffer[0] = '\0';
  132. }
  133. else
  134. {
  135. if (__glibc_unlikely ((uintptr_t) len > -(uintptr_t) buf))
  136. {
  137. free (c);
  138. __set_errno (EINVAL);
  139. return NULL;
  140. }
  141. c->buffer = buf;
  142. /* POSIX states that w+ mode should truncate the buffer. */
  143. if (mode[0] == 'w' && mode[1] == '+')
  144. c->buffer[0] = '\0';
  145. if (mode[0] == 'a')
  146. c->maxpos = strnlen (c->buffer, len);
  147. }
  148. /* Mode | starting position (cookie::pos) | size (cookie::size)
  149. ------ |----------------------------------|-----------------------------
  150. read | beginning of the buffer | size argument
  151. write | beginning of the buffer | zero
  152. append | first null or size buffer + 1 | first null or size argument
  153. */
  154. c->size = len;
  155. if (mode[0] == 'r')
  156. c->maxpos = len;
  157. c->append = mode[0] == 'a';
  158. if (c->append)
  159. c->pos = c->maxpos;
  160. else
  161. c->pos = 0;
  162. iof.read = fmemopen_read;
  163. iof.write = fmemopen_write;
  164. iof.seek = fmemopen_seek;
  165. iof.close = fmemopen_close;
  166. result = _IO_fopencookie (c, mode, iof);
  167. if (__glibc_unlikely (result == NULL))
  168. {
  169. if (c->mybuffer)
  170. free (c->buffer);
  171. free (c);
  172. }
  173. return result;
  174. }
  175. libc_hidden_def (__fmemopen)
  176. versioned_symbol (libc, __fmemopen, fmemopen, GLIBC_2_22);