filedup.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 "apr_arch_file_io.h"
  17. #include "apr_strings.h"
  18. #include "apr_portable.h"
  19. #include "apr_thread_mutex.h"
  20. #include "apr_arch_inherit.h"
  21. static apr_status_t file_dup(apr_file_t **new_file,
  22. apr_file_t *old_file, apr_pool_t *p,
  23. int which_dup)
  24. {
  25. int rv;
  26. #ifdef HAVE_DUP3
  27. int flags = 0;
  28. #endif
  29. if (which_dup == 2) {
  30. if ((*new_file) == NULL) {
  31. /* We can't dup2 unless we have a valid new_file */
  32. return APR_EINVAL;
  33. }
  34. #ifdef HAVE_DUP3
  35. if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT)))
  36. flags |= O_CLOEXEC;
  37. rv = dup3(old_file->filedes, (*new_file)->filedes, flags);
  38. #else
  39. rv = dup2(old_file->filedes, (*new_file)->filedes);
  40. if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT))) {
  41. int flags;
  42. if (rv == -1)
  43. return errno;
  44. if ((flags = fcntl((*new_file)->filedes, F_GETFD)) == -1)
  45. return errno;
  46. flags |= FD_CLOEXEC;
  47. if (fcntl((*new_file)->filedes, F_SETFD, flags) == -1)
  48. return errno;
  49. }
  50. #endif
  51. } else {
  52. rv = dup(old_file->filedes);
  53. }
  54. if (rv == -1)
  55. return errno;
  56. if (which_dup == 1) {
  57. (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
  58. (*new_file)->pool = p;
  59. (*new_file)->filedes = rv;
  60. }
  61. (*new_file)->fname = apr_pstrdup(p, old_file->fname);
  62. (*new_file)->buffered = old_file->buffered;
  63. /* If the existing socket in a dup2 is already buffered, we
  64. * have an existing and valid (hopefully) mutex, so we don't
  65. * want to create it again as we could leak!
  66. */
  67. #if APR_HAS_THREADS
  68. if ((*new_file)->buffered && !(*new_file)->thlock && old_file->thlock) {
  69. apr_thread_mutex_create(&((*new_file)->thlock),
  70. APR_THREAD_MUTEX_DEFAULT, p);
  71. }
  72. #endif
  73. /* As above, only create the buffer if we haven't already
  74. * got one.
  75. */
  76. if ((*new_file)->buffered && !(*new_file)->buffer) {
  77. (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
  78. (*new_file)->bufsize = old_file->bufsize;
  79. }
  80. /* this is the way dup() works */
  81. (*new_file)->blocking = old_file->blocking;
  82. /* make sure unget behavior is consistent */
  83. (*new_file)->ungetchar = old_file->ungetchar;
  84. /* apr_file_dup2() retains the original cleanup, reflecting
  85. * the existing inherit and nocleanup flags. This means,
  86. * that apr_file_dup2() cannot be called against an apr_file_t
  87. * already closed with apr_file_close, because the expected
  88. * cleanup was already killed.
  89. */
  90. if (which_dup == 2) {
  91. return APR_SUCCESS;
  92. }
  93. /* apr_file_dup() retains all old_file flags with the exceptions
  94. * of APR_INHERIT and APR_FOPEN_NOCLEANUP.
  95. * The user must call apr_file_inherit_set() on the dupped
  96. * apr_file_t when desired.
  97. */
  98. (*new_file)->flags = old_file->flags
  99. & ~(APR_INHERIT | APR_FOPEN_NOCLEANUP);
  100. apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
  101. apr_unix_file_cleanup,
  102. apr_unix_child_file_cleanup);
  103. #ifndef WAITIO_USES_POLL
  104. /* Start out with no pollset. apr_wait_for_io_or_timeout() will
  105. * initialize the pollset if needed.
  106. */
  107. (*new_file)->pollset = NULL;
  108. #endif
  109. return APR_SUCCESS;
  110. }
  111. APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file,
  112. apr_file_t *old_file, apr_pool_t *p)
  113. {
  114. return file_dup(new_file, old_file, p, 1);
  115. }
  116. APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
  117. apr_file_t *old_file, apr_pool_t *p)
  118. {
  119. return file_dup(&new_file, old_file, p, 2);
  120. }
  121. APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file,
  122. apr_file_t *old_file,
  123. apr_pool_t *p)
  124. {
  125. *new_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t));
  126. memcpy(*new_file, old_file, sizeof(apr_file_t));
  127. (*new_file)->pool = p;
  128. if (old_file->buffered) {
  129. (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
  130. (*new_file)->bufsize = old_file->bufsize;
  131. if (old_file->direction == 1) {
  132. memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
  133. }
  134. else {
  135. memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead);
  136. }
  137. #if APR_HAS_THREADS
  138. if (old_file->thlock) {
  139. apr_thread_mutex_create(&((*new_file)->thlock),
  140. APR_THREAD_MUTEX_DEFAULT, p);
  141. apr_thread_mutex_destroy(old_file->thlock);
  142. }
  143. #endif /* APR_HAS_THREADS */
  144. }
  145. if (old_file->fname) {
  146. (*new_file)->fname = apr_pstrdup(p, old_file->fname);
  147. }
  148. if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) {
  149. apr_pool_cleanup_register(p, (void *)(*new_file),
  150. apr_unix_file_cleanup,
  151. ((*new_file)->flags & APR_INHERIT)
  152. ? apr_pool_cleanup_null
  153. : apr_unix_child_file_cleanup);
  154. }
  155. old_file->filedes = -1;
  156. apr_pool_cleanup_kill(old_file->pool, (void *)old_file,
  157. apr_unix_file_cleanup);
  158. #ifndef WAITIO_USES_POLL
  159. (*new_file)->pollset = NULL;
  160. #endif
  161. return APR_SUCCESS;
  162. }