readwrite.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "fspr_arch_file_io.h"
  17. #include "fspr_strings.h"
  18. #include "fspr_thread_mutex.h"
  19. #include "fspr_support.h"
  20. /* The only case where we don't use wait_for_io_or_timeout is on
  21. * pre-BONE BeOS, so this check should be sufficient and simpler */
  22. #if !BEOS_R5
  23. #define USE_WAIT_FOR_IO
  24. #endif
  25. APR_DECLARE(fspr_status_t) fspr_file_read(fspr_file_t *thefile, void *buf, fspr_size_t *nbytes)
  26. {
  27. fspr_ssize_t rv;
  28. fspr_size_t bytes_read;
  29. if (*nbytes <= 0) {
  30. *nbytes = 0;
  31. return APR_SUCCESS;
  32. }
  33. if (thefile->buffered) {
  34. char *pos = (char *)buf;
  35. fspr_uint64_t blocksize;
  36. fspr_uint64_t size = *nbytes;
  37. #if APR_HAS_THREADS
  38. if (thefile->thlock) {
  39. fspr_thread_mutex_lock(thefile->thlock);
  40. }
  41. #endif
  42. if (thefile->direction == 1) {
  43. rv = fspr_file_flush(thefile);
  44. if (rv) {
  45. #if APR_HAS_THREADS
  46. if (thefile->thlock) {
  47. fspr_thread_mutex_unlock(thefile->thlock);
  48. }
  49. #endif
  50. return rv;
  51. }
  52. thefile->bufpos = 0;
  53. thefile->direction = 0;
  54. thefile->dataRead = 0;
  55. }
  56. rv = 0;
  57. if (thefile->ungetchar != -1) {
  58. *pos = (char)thefile->ungetchar;
  59. ++pos;
  60. --size;
  61. thefile->ungetchar = -1;
  62. }
  63. while (rv == 0 && size > 0) {
  64. if (thefile->bufpos >= thefile->dataRead) {
  65. int bytesread = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE);
  66. if (bytesread == 0) {
  67. thefile->eof_hit = TRUE;
  68. rv = APR_EOF;
  69. break;
  70. }
  71. else if (bytesread == -1) {
  72. rv = errno;
  73. break;
  74. }
  75. thefile->dataRead = bytesread;
  76. thefile->filePtr += thefile->dataRead;
  77. thefile->bufpos = 0;
  78. }
  79. blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
  80. memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
  81. thefile->bufpos += blocksize;
  82. pos += blocksize;
  83. size -= blocksize;
  84. }
  85. *nbytes = pos - (char *)buf;
  86. if (*nbytes) {
  87. rv = 0;
  88. }
  89. #if APR_HAS_THREADS
  90. if (thefile->thlock) {
  91. fspr_thread_mutex_unlock(thefile->thlock);
  92. }
  93. #endif
  94. return rv;
  95. }
  96. else {
  97. bytes_read = 0;
  98. if (thefile->ungetchar != -1) {
  99. bytes_read = 1;
  100. *(char *)buf = (char)thefile->ungetchar;
  101. buf = (char *)buf + 1;
  102. (*nbytes)--;
  103. thefile->ungetchar = -1;
  104. if (*nbytes == 0) {
  105. *nbytes = bytes_read;
  106. return APR_SUCCESS;
  107. }
  108. }
  109. do {
  110. rv = read(thefile->filedes, buf, *nbytes);
  111. } while (rv == -1 && errno == EINTR);
  112. #ifdef USE_WAIT_FOR_IO
  113. if (rv == -1 &&
  114. (errno == EAGAIN || errno == EWOULDBLOCK) &&
  115. thefile->timeout != 0) {
  116. fspr_status_t arv = fspr_wait_for_io_or_timeout(thefile, NULL, 1);
  117. if (arv != APR_SUCCESS) {
  118. *nbytes = bytes_read;
  119. return arv;
  120. }
  121. else {
  122. do {
  123. rv = read(thefile->filedes, buf, *nbytes);
  124. } while (rv == -1 && errno == EINTR);
  125. }
  126. }
  127. #endif
  128. *nbytes = bytes_read;
  129. if (rv == 0) {
  130. thefile->eof_hit = TRUE;
  131. return APR_EOF;
  132. }
  133. if (rv > 0) {
  134. *nbytes += rv;
  135. return APR_SUCCESS;
  136. }
  137. return errno;
  138. }
  139. }
  140. APR_DECLARE(fspr_status_t) fspr_file_write(fspr_file_t *thefile, const void *buf, fspr_size_t *nbytes)
  141. {
  142. fspr_size_t rv;
  143. if (thefile->buffered) {
  144. char *pos = (char *)buf;
  145. int blocksize;
  146. int size = *nbytes;
  147. #if APR_HAS_THREADS
  148. if (thefile->thlock) {
  149. fspr_thread_mutex_lock(thefile->thlock);
  150. }
  151. #endif
  152. if ( thefile->direction == 0 ) {
  153. /* Position file pointer for writing at the offset we are
  154. * logically reading from
  155. */
  156. fspr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
  157. if (offset != thefile->filePtr)
  158. lseek(thefile->filedes, offset, SEEK_SET);
  159. thefile->bufpos = thefile->dataRead = 0;
  160. thefile->direction = 1;
  161. }
  162. rv = 0;
  163. while (rv == 0 && size > 0) {
  164. if (thefile->bufpos == APR_FILE_BUFSIZE) /* write buffer is full*/
  165. rv = fspr_file_flush(thefile);
  166. blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ?
  167. APR_FILE_BUFSIZE - thefile->bufpos : size;
  168. memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
  169. thefile->bufpos += blocksize;
  170. pos += blocksize;
  171. size -= blocksize;
  172. }
  173. #if APR_HAS_THREADS
  174. if (thefile->thlock) {
  175. fspr_thread_mutex_unlock(thefile->thlock);
  176. }
  177. #endif
  178. return rv;
  179. }
  180. else {
  181. do {
  182. rv = write(thefile->filedes, buf, *nbytes);
  183. } while (rv == (fspr_size_t)-1 && errno == EINTR);
  184. #ifdef USE_WAIT_FOR_IO
  185. if (rv == (fspr_size_t)-1 &&
  186. (errno == EAGAIN || errno == EWOULDBLOCK) &&
  187. thefile->timeout != 0) {
  188. fspr_status_t arv = fspr_wait_for_io_or_timeout(thefile, NULL, 0);
  189. if (arv != APR_SUCCESS) {
  190. *nbytes = 0;
  191. return arv;
  192. }
  193. else {
  194. do {
  195. do {
  196. rv = write(thefile->filedes, buf, *nbytes);
  197. } while (rv == (fspr_size_t)-1 && errno == EINTR);
  198. if (rv == (fspr_size_t)-1 &&
  199. (errno == EAGAIN || errno == EWOULDBLOCK)) {
  200. *nbytes /= 2; /* yes, we'll loop if kernel lied
  201. * and we can't even write 1 byte
  202. */
  203. }
  204. else {
  205. break;
  206. }
  207. } while (1);
  208. }
  209. }
  210. #endif
  211. if (rv == (fspr_size_t)-1) {
  212. (*nbytes) = 0;
  213. return errno;
  214. }
  215. *nbytes = rv;
  216. return APR_SUCCESS;
  217. }
  218. }
  219. APR_DECLARE(fspr_status_t) fspr_file_writev(fspr_file_t *thefile, const struct iovec *vec,
  220. fspr_size_t nvec, fspr_size_t *nbytes)
  221. {
  222. #ifdef HAVE_WRITEV
  223. int bytes;
  224. if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
  225. *nbytes = 0;
  226. return errno;
  227. }
  228. else {
  229. *nbytes = bytes;
  230. return APR_SUCCESS;
  231. }
  232. #else
  233. /**
  234. * The problem with trying to output the entire iovec is that we cannot
  235. * maintain the behavoir that a real writev would have. If we iterate
  236. * over the iovec one at a time, we loose the atomic properties of
  237. * writev(). The other option is to combine the entire iovec into one
  238. * buffer that we could then send in one call to write(). This is not
  239. * reasonable since we do not know how much data an iovec could contain.
  240. *
  241. * The only reasonable option, that maintains the semantics of a real
  242. * writev(), is to only write the first iovec. Callers of file_writev()
  243. * must deal with partial writes as they normally would. If you want to
  244. * ensure an entire iovec is written, use fspr_file_writev_full().
  245. */
  246. *nbytes = vec[0].iov_len;
  247. return fspr_file_write(thefile, vec[0].iov_base, nbytes);
  248. #endif
  249. }
  250. APR_DECLARE(fspr_status_t) fspr_file_putc(char ch, fspr_file_t *thefile)
  251. {
  252. fspr_size_t nbytes = 1;
  253. return fspr_file_write(thefile, &ch, &nbytes);
  254. }
  255. APR_DECLARE(fspr_status_t) fspr_file_ungetc(char ch, fspr_file_t *thefile)
  256. {
  257. thefile->ungetchar = (unsigned char)ch;
  258. return APR_SUCCESS;
  259. }
  260. APR_DECLARE(fspr_status_t) fspr_file_getc(char *ch, fspr_file_t *thefile)
  261. {
  262. fspr_size_t nbytes = 1;
  263. return fspr_file_read(thefile, ch, &nbytes);
  264. }
  265. APR_DECLARE(fspr_status_t) fspr_file_puts(const char *str, fspr_file_t *thefile)
  266. {
  267. return fspr_file_write_full(thefile, str, strlen(str), NULL);
  268. }
  269. APR_DECLARE(fspr_status_t) fspr_file_flush(fspr_file_t *thefile)
  270. {
  271. if (thefile->buffered) {
  272. fspr_int64_t written = 0;
  273. if (thefile->direction == 1 && thefile->bufpos) {
  274. do {
  275. written = write(thefile->filedes, thefile->buffer, thefile->bufpos);
  276. } while (written == (fspr_int64_t)-1 && errno == EINTR);
  277. if (written == (fspr_int64_t)-1) {
  278. return errno;
  279. }
  280. thefile->filePtr += written;
  281. thefile->bufpos = 0;
  282. }
  283. }
  284. /* There isn't anything to do if we aren't buffering the output
  285. * so just return success.
  286. */
  287. return APR_SUCCESS;
  288. }
  289. APR_DECLARE(fspr_status_t) fspr_file_gets(char *str, int len, fspr_file_t *thefile)
  290. {
  291. fspr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */
  292. fspr_size_t nbytes;
  293. const char *str_start = str;
  294. char *final = str + len - 1;
  295. if (len <= 1) {
  296. /* sort of like fgets(), which returns NULL and stores no bytes
  297. */
  298. return APR_SUCCESS;
  299. }
  300. /* If we have an underlying buffer, we can be *much* more efficient
  301. * and skip over the fspr_file_read calls.
  302. */
  303. if (thefile->buffered) {
  304. #if APR_HAS_THREADS
  305. if (thefile->thlock) {
  306. fspr_thread_mutex_lock(thefile->thlock);
  307. }
  308. #endif
  309. if (thefile->direction == 1) {
  310. rv = fspr_file_flush(thefile);
  311. if (rv) {
  312. #if APR_HAS_THREADS
  313. if (thefile->thlock) {
  314. fspr_thread_mutex_unlock(thefile->thlock);
  315. }
  316. #endif
  317. return rv;
  318. }
  319. thefile->direction = 0;
  320. thefile->bufpos = 0;
  321. thefile->dataRead = 0;
  322. }
  323. while (str < final) { /* leave room for trailing '\0' */
  324. /* Force ungetc leftover to call fspr_file_read. */
  325. if (thefile->bufpos < thefile->dataRead &&
  326. thefile->ungetchar == -1) {
  327. *str = thefile->buffer[thefile->bufpos++];
  328. }
  329. else {
  330. nbytes = 1;
  331. rv = fspr_file_read(thefile, str, &nbytes);
  332. if (rv != APR_SUCCESS) {
  333. break;
  334. }
  335. }
  336. if (*str == '\n') {
  337. ++str;
  338. break;
  339. }
  340. ++str;
  341. }
  342. #if APR_HAS_THREADS
  343. if (thefile->thlock) {
  344. fspr_thread_mutex_unlock(thefile->thlock);
  345. }
  346. #endif
  347. }
  348. else {
  349. while (str < final) { /* leave room for trailing '\0' */
  350. nbytes = 1;
  351. rv = fspr_file_read(thefile, str, &nbytes);
  352. if (rv != APR_SUCCESS) {
  353. break;
  354. }
  355. if (*str == '\n') {
  356. ++str;
  357. break;
  358. }
  359. ++str;
  360. }
  361. }
  362. /* We must store a terminating '\0' if we've stored any chars. We can
  363. * get away with storing it if we hit an error first.
  364. */
  365. *str = '\0';
  366. if (str > str_start) {
  367. /* we stored chars; don't report EOF or any other errors;
  368. * the app will find out about that on the next call
  369. */
  370. return APR_SUCCESS;
  371. }
  372. return rv;
  373. }
  374. struct fspr_file_printf_data {
  375. fspr_vformatter_buff_t vbuff;
  376. fspr_file_t *fptr;
  377. char *buf;
  378. };
  379. static int file_printf_flush(fspr_vformatter_buff_t *buff)
  380. {
  381. struct fspr_file_printf_data *data = (struct fspr_file_printf_data *)buff;
  382. if (fspr_file_write_full(data->fptr, data->buf,
  383. data->vbuff.curpos - data->buf, NULL)) {
  384. return -1;
  385. }
  386. data->vbuff.curpos = data->buf;
  387. return 0;
  388. }
  389. APR_DECLARE_NONSTD(int) fspr_file_printf(fspr_file_t *fptr,
  390. const char *format, ...)
  391. {
  392. struct fspr_file_printf_data data;
  393. va_list ap;
  394. int count;
  395. /* don't really need a HUGE_STRING_LEN anymore */
  396. data.buf = malloc(HUGE_STRING_LEN);
  397. if (data.buf == NULL) {
  398. return -1;
  399. }
  400. data.vbuff.curpos = data.buf;
  401. data.vbuff.endpos = data.buf + HUGE_STRING_LEN;
  402. data.fptr = fptr;
  403. va_start(ap, format);
  404. count = fspr_vformatter(file_printf_flush,
  405. (fspr_vformatter_buff_t *)&data, format, ap);
  406. /* fspr_vformatter does not call flush for the last bits */
  407. if (count >= 0) file_printf_flush((fspr_vformatter_buff_t *)&data);
  408. va_end(ap);
  409. free(data.buf);
  410. return count;
  411. }