strops.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /* Copyright (C) 1993-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <https://www.gnu.org/licenses/>.
  14. As a special exception, if you link the code in this file with
  15. files compiled with a GNU compiler to produce an executable,
  16. that does not cause the resulting executable to be covered by
  17. the GNU Lesser General Public License. This exception does not
  18. however invalidate any other reasons why the executable file
  19. might be covered by the GNU Lesser General Public License.
  20. This exception applies to code released by its copyright holders
  21. in files containing the exception. */
  22. #include <assert.h>
  23. #include "strfile.h"
  24. #include "libioP.h"
  25. #include <string.h>
  26. #include <stdio_ext.h>
  27. void
  28. _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, size_t size,
  29. char *pstart)
  30. {
  31. FILE *fp = &sf->_sbf._f;
  32. char *end;
  33. if (size == 0)
  34. end = ptr + strlen (ptr);
  35. else if ((size_t) ptr + size > (size_t) ptr)
  36. end = ptr + size;
  37. else
  38. end = (char *) -1;
  39. _IO_setb (fp, ptr, end, 0);
  40. fp->_IO_write_base = ptr;
  41. fp->_IO_read_base = ptr;
  42. fp->_IO_read_ptr = ptr;
  43. if (pstart)
  44. {
  45. fp->_IO_write_ptr = pstart;
  46. fp->_IO_write_end = end;
  47. fp->_IO_read_end = pstart;
  48. }
  49. else
  50. {
  51. fp->_IO_write_ptr = ptr;
  52. fp->_IO_write_end = ptr;
  53. fp->_IO_read_end = end;
  54. }
  55. /* A null _allocate_buffer function flags the strfile as being static. */
  56. sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
  57. }
  58. void
  59. _IO_str_init_static (_IO_strfile *sf, char *ptr, int size, char *pstart)
  60. {
  61. return _IO_str_init_static_internal (sf, ptr, size < 0 ? -1 : size, pstart);
  62. }
  63. void
  64. _IO_str_init_readonly (_IO_strfile *sf, const char *ptr, int size)
  65. {
  66. _IO_str_init_static_internal (sf, (char *) ptr, size < 0 ? -1 : size, NULL);
  67. sf->_sbf._f._flags |= _IO_NO_WRITES;
  68. }
  69. int
  70. _IO_str_overflow (FILE *fp, int c)
  71. {
  72. int flush_only = c == EOF;
  73. size_t pos;
  74. if (fp->_flags & _IO_NO_WRITES)
  75. return flush_only ? 0 : EOF;
  76. if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
  77. {
  78. fp->_flags |= _IO_CURRENTLY_PUTTING;
  79. fp->_IO_write_ptr = fp->_IO_read_ptr;
  80. fp->_IO_read_ptr = fp->_IO_read_end;
  81. }
  82. pos = fp->_IO_write_ptr - fp->_IO_write_base;
  83. if (pos >= (size_t) (_IO_blen (fp) + flush_only))
  84. {
  85. if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
  86. return EOF;
  87. else
  88. {
  89. char *new_buf;
  90. char *old_buf = fp->_IO_buf_base;
  91. size_t old_blen = _IO_blen (fp);
  92. size_t new_size = 2 * old_blen + 100;
  93. if (new_size < old_blen)
  94. return EOF;
  95. new_buf = malloc (new_size);
  96. if (new_buf == NULL)
  97. {
  98. /* __ferror(fp) = 1; */
  99. return EOF;
  100. }
  101. if (old_buf)
  102. {
  103. memcpy (new_buf, old_buf, old_blen);
  104. free (old_buf);
  105. /* Make sure _IO_setb won't try to delete _IO_buf_base. */
  106. fp->_IO_buf_base = NULL;
  107. }
  108. memset (new_buf + old_blen, '\0', new_size - old_blen);
  109. _IO_setb (fp, new_buf, new_buf + new_size, 1);
  110. fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
  111. fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
  112. fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
  113. fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);
  114. fp->_IO_write_base = new_buf;
  115. fp->_IO_write_end = fp->_IO_buf_end;
  116. }
  117. }
  118. if (!flush_only)
  119. *fp->_IO_write_ptr++ = (unsigned char) c;
  120. if (fp->_IO_write_ptr > fp->_IO_read_end)
  121. fp->_IO_read_end = fp->_IO_write_ptr;
  122. if (flush_only)
  123. return 0;
  124. else
  125. return c;
  126. }
  127. libc_hidden_def (_IO_str_overflow)
  128. int
  129. _IO_str_underflow (FILE *fp)
  130. {
  131. if (fp->_IO_write_ptr > fp->_IO_read_end)
  132. fp->_IO_read_end = fp->_IO_write_ptr;
  133. if ((fp->_flags & _IO_TIED_PUT_GET) && (fp->_flags & _IO_CURRENTLY_PUTTING))
  134. {
  135. fp->_flags &= ~_IO_CURRENTLY_PUTTING;
  136. fp->_IO_read_ptr = fp->_IO_write_ptr;
  137. fp->_IO_write_ptr = fp->_IO_write_end;
  138. }
  139. if (fp->_IO_read_ptr < fp->_IO_read_end)
  140. return *((unsigned char *) fp->_IO_read_ptr);
  141. else
  142. return EOF;
  143. }
  144. libc_hidden_def (_IO_str_underflow)
  145. /* The size of the valid part of the buffer. */
  146. ssize_t
  147. _IO_str_count (FILE *fp)
  148. {
  149. return ((fp->_IO_write_ptr > fp->_IO_read_end
  150. ? fp->_IO_write_ptr : fp->_IO_read_end)
  151. - fp->_IO_read_base);
  152. }
  153. static int
  154. enlarge_userbuf (FILE *fp, off64_t offset, int reading)
  155. {
  156. if ((ssize_t) offset <= _IO_blen (fp))
  157. return 0;
  158. ssize_t oldend = fp->_IO_write_end - fp->_IO_write_base;
  159. /* Try to enlarge the buffer. */
  160. if (fp->_flags & _IO_USER_BUF)
  161. /* User-provided buffer. */
  162. return 1;
  163. size_t newsize = offset + 100;
  164. char *oldbuf = fp->_IO_buf_base;
  165. char *newbuf = malloc (newsize);
  166. if (newbuf == NULL)
  167. return 1;
  168. if (oldbuf != NULL)
  169. {
  170. memcpy (newbuf, oldbuf, _IO_blen (fp));
  171. free (oldbuf);
  172. /* Make sure _IO_setb won't try to delete
  173. _IO_buf_base. */
  174. fp->_IO_buf_base = NULL;
  175. }
  176. _IO_setb (fp, newbuf, newbuf + newsize, 1);
  177. if (reading)
  178. {
  179. fp->_IO_write_base = newbuf + (fp->_IO_write_base - oldbuf);
  180. fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
  181. fp->_IO_write_end = newbuf + (fp->_IO_write_end - oldbuf);
  182. fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
  183. fp->_IO_read_base = newbuf;
  184. fp->_IO_read_end = fp->_IO_buf_end;
  185. }
  186. else
  187. {
  188. fp->_IO_read_base = newbuf + (fp->_IO_read_base - oldbuf);
  189. fp->_IO_read_ptr = newbuf + (fp->_IO_read_ptr - oldbuf);
  190. fp->_IO_read_end = newbuf + (fp->_IO_read_end - oldbuf);
  191. fp->_IO_write_ptr = newbuf + (fp->_IO_write_ptr - oldbuf);
  192. fp->_IO_write_base = newbuf;
  193. fp->_IO_write_end = fp->_IO_buf_end;
  194. }
  195. /* Clear the area between the last write position and th
  196. new position. */
  197. assert (offset >= oldend);
  198. if (reading)
  199. memset (fp->_IO_read_base + oldend, '\0', offset - oldend);
  200. else
  201. memset (fp->_IO_write_base + oldend, '\0', offset - oldend);
  202. return 0;
  203. }
  204. static void
  205. _IO_str_switch_to_get_mode (FILE *fp)
  206. {
  207. if (_IO_in_backup (fp))
  208. fp->_IO_read_base = fp->_IO_backup_base;
  209. else
  210. {
  211. fp->_IO_read_base = fp->_IO_buf_base;
  212. if (fp->_IO_write_ptr > fp->_IO_read_end)
  213. fp->_IO_read_end = fp->_IO_write_ptr;
  214. }
  215. fp->_IO_read_ptr = fp->_IO_read_end = fp->_IO_write_ptr;
  216. fp->_flags &= ~_IO_CURRENTLY_PUTTING;
  217. }
  218. off64_t
  219. _IO_str_seekoff (FILE *fp, off64_t offset, int dir, int mode)
  220. {
  221. off64_t new_pos;
  222. if (mode == 0 && (fp->_flags & _IO_TIED_PUT_GET))
  223. mode = (fp->_flags & _IO_CURRENTLY_PUTTING ? _IOS_OUTPUT : _IOS_INPUT);
  224. bool was_writing = (fp->_IO_write_ptr > fp->_IO_write_base
  225. || _IO_in_put_mode (fp));
  226. if (was_writing)
  227. _IO_str_switch_to_get_mode (fp);
  228. if (mode == 0)
  229. {
  230. new_pos = fp->_IO_read_ptr - fp->_IO_read_base;
  231. }
  232. else
  233. {
  234. ssize_t cur_size = _IO_str_count(fp);
  235. new_pos = EOF;
  236. /* Move the get pointer, if requested. */
  237. if (mode & _IOS_INPUT)
  238. {
  239. ssize_t base;
  240. switch (dir)
  241. {
  242. case _IO_seek_set:
  243. base = 0;
  244. break;
  245. case _IO_seek_cur:
  246. base = fp->_IO_read_ptr - fp->_IO_read_base;
  247. break;
  248. default: /* case _IO_seek_end: */
  249. base = cur_size;
  250. break;
  251. }
  252. ssize_t maxval = SSIZE_MAX - base;
  253. if (offset < -base || offset > maxval)
  254. {
  255. __set_errno (EINVAL);
  256. return EOF;
  257. }
  258. base += offset;
  259. if (base > cur_size
  260. && enlarge_userbuf (fp, base, 1) != 0)
  261. return EOF;
  262. fp->_IO_read_ptr = fp->_IO_read_base + base;
  263. fp->_IO_read_end = fp->_IO_read_base + cur_size;
  264. new_pos = base;
  265. }
  266. /* Move the put pointer, if requested. */
  267. if (mode & _IOS_OUTPUT)
  268. {
  269. ssize_t base;
  270. switch (dir)
  271. {
  272. case _IO_seek_set:
  273. base = 0;
  274. break;
  275. case _IO_seek_cur:
  276. base = fp->_IO_write_ptr - fp->_IO_write_base;
  277. break;
  278. default: /* case _IO_seek_end: */
  279. base = cur_size;
  280. break;
  281. }
  282. ssize_t maxval = SSIZE_MAX - base;
  283. if (offset < -base || offset > maxval)
  284. {
  285. __set_errno (EINVAL);
  286. return EOF;
  287. }
  288. base += offset;
  289. if (base > cur_size
  290. && enlarge_userbuf (fp, base, 0) != 0)
  291. return EOF;
  292. fp->_IO_write_ptr = fp->_IO_write_base + base;
  293. new_pos = base;
  294. }
  295. }
  296. return new_pos;
  297. }
  298. libc_hidden_def (_IO_str_seekoff)
  299. int
  300. _IO_str_pbackfail (FILE *fp, int c)
  301. {
  302. if ((fp->_flags & _IO_NO_WRITES) && c != EOF)
  303. return EOF;
  304. return _IO_default_pbackfail (fp, c);
  305. }
  306. libc_hidden_def (_IO_str_pbackfail)
  307. void
  308. _IO_str_finish (FILE *fp, int dummy)
  309. {
  310. if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
  311. free (fp->_IO_buf_base);
  312. fp->_IO_buf_base = NULL;
  313. _IO_default_finish (fp, 0);
  314. }