Coverage Report

Created: 2022-02-19 20:31

/src/php-src/Zend/zend_stream.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend Engine                                                          |
4
   +----------------------------------------------------------------------+
5
   | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to version 2.00 of the Zend license,     |
8
   | that is bundled with this package in the file LICENSE, and is        |
9
   | available through the world-wide-web at the following url:           |
10
   | http://www.zend.com/license/2_00.txt.                                |
11
   | If you did not receive a copy of the Zend license and are unable to  |
12
   | obtain it through the world-wide-web, please send a note to          |
13
   | license@zend.com so we can mail you a copy immediately.              |
14
   +----------------------------------------------------------------------+
15
   | Authors: Wez Furlong <wez@thebrainroom.com>                          |
16
   |          Scott MacVicar <scottmac@php.net>                           |
17
   |          Nuno Lopes <nlopess@php.net>                                |
18
   |          Marcus Boerger <helly@php.net>                              |
19
   +----------------------------------------------------------------------+
20
*/
21
22
#include "zend.h"
23
#include "zend_compile.h"
24
#include "zend_stream.h"
25
26
ZEND_DLIMPORT int isatty(int fd);
27
28
static ssize_t zend_stream_stdio_reader(void *handle, char *buf, size_t len) /* {{{ */
29
0
{
30
0
  return fread(buf, 1, len, (FILE*)handle);
31
0
} /* }}} */
32
33
static void zend_stream_stdio_closer(void *handle) /* {{{ */
34
0
{
35
0
  if (handle && (FILE*)handle != stdin) {
36
0
    fclose((FILE*)handle);
37
0
  }
38
0
} /* }}} */
39
40
static size_t zend_stream_stdio_fsizer(void *handle) /* {{{ */
41
0
{
42
0
  zend_stat_t buf;
43
0
  if (handle && zend_fstat(fileno((FILE*)handle), &buf) == 0) {
44
0
#ifdef S_ISREG
45
0
    if (!S_ISREG(buf.st_mode)) {
46
0
      return 0;
47
0
    }
48
0
#endif
49
0
    return buf.st_size;
50
0
  }
51
0
  return -1;
52
0
} /* }}} */
53
54
static size_t zend_stream_fsize(zend_file_handle *file_handle) /* {{{ */
55
839
{
56
839
  ZEND_ASSERT(file_handle->type == ZEND_HANDLE_STREAM);
57
839
  if (file_handle->handle.stream.isatty) {
58
0
    return 0;
59
0
  }
60
839
  return file_handle->handle.stream.fsizer(file_handle->handle.stream.handle);
61
839
} /* }}} */
62
63
0
ZEND_API void zend_stream_init_fp(zend_file_handle *handle, FILE *fp, const char *filename) {
64
0
  memset(handle, 0, sizeof(zend_file_handle));
65
0
  handle->type = ZEND_HANDLE_FP;
66
0
  handle->handle.fp = fp;
67
0
  handle->filename = filename;
68
0
}
69
70
953k
ZEND_API void zend_stream_init_filename(zend_file_handle *handle, const char *filename) {
71
953k
  memset(handle, 0, sizeof(zend_file_handle));
72
953k
  handle->type = ZEND_HANDLE_FILENAME;
73
953k
  handle->filename = filename;
74
953k
}
75
76
ZEND_API zend_result zend_stream_open(const char *filename, zend_file_handle *handle) /* {{{ */
77
16.6k
{
78
16.6k
  zend_string *opened_path;
79
16.6k
  if (zend_stream_open_function) {
80
16.6k
    return zend_stream_open_function(filename, handle);
81
16.6k
  }
82
83
0
  zend_stream_init_fp(handle, zend_fopen(filename, &opened_path), filename);
84
0
  handle->opened_path = opened_path;
85
0
  return handle->handle.fp ? SUCCESS : FAILURE;
86
0
} /* }}} */
87
88
static int zend_stream_getc(zend_file_handle *file_handle) /* {{{ */
89
0
{
90
0
  char buf;
91
92
0
  if (file_handle->handle.stream.reader(file_handle->handle.stream.handle, &buf, sizeof(buf))) {
93
0
    return (int)buf;
94
0
  }
95
0
  return EOF;
96
0
} /* }}} */
97
98
static ssize_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len) /* {{{ */
99
13.5k
{
100
13.5k
  if (file_handle->handle.stream.isatty) {
101
0
    int c = '*';
102
0
    size_t n;
103
104
0
    for (n = 0; n < len && (c = zend_stream_getc(file_handle)) != EOF && c != '\n'; ++n)  {
105
0
      buf[n] = (char)c;
106
0
    }
107
0
    if (c == '\n') {
108
0
      buf[n++] = (char)c;
109
0
    }
110
111
0
    return n;
112
0
  }
113
13.5k
  return file_handle->handle.stream.reader(file_handle->handle.stream.handle, buf, len);
114
13.5k
} /* }}} */
115
116
ZEND_API zend_result zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len) /* {{{ */
117
953k
{
118
953k
  size_t file_size;
119
120
953k
  if (file_handle->buf) {
121
939k
    *buf = file_handle->buf;
122
939k
    *len = file_handle->len;
123
939k
    return SUCCESS;
124
939k
  }
125
126
14.6k
  if (file_handle->type == ZEND_HANDLE_FILENAME) {
127
14.6k
    if (zend_stream_open(file_handle->filename, file_handle) == FAILURE) {
128
13.8k
      return FAILURE;
129
13.8k
    }
130
839
  }
131
132
839
  if (file_handle->type == ZEND_HANDLE_FP) {
133
0
    if (!file_handle->handle.fp) {
134
0
      return FAILURE;
135
0
    }
136
137
0
    file_handle->type = ZEND_HANDLE_STREAM;
138
0
    file_handle->handle.stream.handle = file_handle->handle.fp;
139
0
    file_handle->handle.stream.isatty = isatty(fileno((FILE *)file_handle->handle.stream.handle));
140
0
    file_handle->handle.stream.reader = (zend_stream_reader_t)zend_stream_stdio_reader;
141
0
    file_handle->handle.stream.closer = (zend_stream_closer_t)zend_stream_stdio_closer;
142
0
    file_handle->handle.stream.fsizer = (zend_stream_fsizer_t)zend_stream_stdio_fsizer;
143
0
  }
144
145
839
  file_size = zend_stream_fsize(file_handle);
146
839
  if (file_size == (size_t)-1) {
147
0
    return FAILURE;
148
0
  }
149
150
839
  if (file_size) {
151
356
    ssize_t read;
152
356
    size_t size = 0;
153
356
    *buf = safe_emalloc(1, file_size, ZEND_MMAP_AHEAD);
154
1.39k
    while ((read = zend_stream_read(file_handle, *buf + size, file_size - size)) > 0) {
155
1.04k
      size += read;
156
1.04k
    }
157
356
    if (read < 0) {
158
69
      efree(*buf);
159
69
      return FAILURE;
160
69
    }
161
287
    file_handle->buf = *buf;
162
287
    file_handle->len = size;
163
483
  } else {
164
483
    size_t size = 0, remain = 4*1024;
165
483
    ssize_t read;
166
483
    *buf = emalloc(remain);
167
168
12.1k
    while ((read = zend_stream_read(file_handle, *buf + size, remain)) > 0) {
169
11.6k
      size   += read;
170
11.6k
      remain -= read;
171
172
11.6k
      if (remain == 0) {
173
800
        *buf   = safe_erealloc(*buf, size, 2, 0);
174
800
        remain = size;
175
800
      }
176
11.6k
    }
177
483
    if (read < 0) {
178
114
      efree(*buf);
179
114
      return FAILURE;
180
114
    }
181
182
369
    file_handle->len = size;
183
369
    if (size && remain < ZEND_MMAP_AHEAD) {
184
5
      *buf = safe_erealloc(*buf, size, 1, ZEND_MMAP_AHEAD);
185
5
    }
186
369
    file_handle->buf = *buf;
187
369
  }
188
189
656
  if (file_handle->len == 0) {
190
114
    *buf = erealloc(*buf, ZEND_MMAP_AHEAD);
191
114
    file_handle->buf = *buf;
192
114
  }
193
194
656
  memset(file_handle->buf + file_handle->len, 0, ZEND_MMAP_AHEAD);
195
196
656
  *buf = file_handle->buf;
197
656
  *len = file_handle->len;
198
199
656
  return SUCCESS;
200
839
} /* }}} */
201
202
ZEND_API void zend_file_handle_dtor(zend_file_handle *fh) /* {{{ */
203
952k
{
204
952k
  switch (fh->type) {
205
0
    case ZEND_HANDLE_FP:
206
0
      fclose(fh->handle.fp);
207
0
      break;
208
667
    case ZEND_HANDLE_STREAM:
209
667
      if (fh->handle.stream.closer && fh->handle.stream.handle) {
210
667
        fh->handle.stream.closer(fh->handle.stream.handle);
211
667
      }
212
667
      fh->handle.stream.handle = NULL;
213
667
      break;
214
952k
    case ZEND_HANDLE_FILENAME:
215
      /* We're only supposed to get here when destructing the used_files hash,
216
       * which doesn't really contain open files, but references to their names/paths
217
       */
218
952k
      break;
219
952k
  }
220
952k
  if (fh->opened_path) {
221
0
    zend_string_release_ex(fh->opened_path, 0);
222
0
    fh->opened_path = NULL;
223
0
  }
224
952k
  if (fh->buf) {
225
939k
    efree(fh->buf);
226
939k
    fh->buf = NULL;
227
939k
  }
228
952k
  if (fh->free_filename && fh->filename) {
229
0
    efree((char*)fh->filename);
230
0
    fh->filename = NULL;
231
0
  }
232
952k
}
233
/* }}} */
234
235
/* return int to be compatible with Zend linked list API */
236
ZEND_API int zend_compare_file_handles(zend_file_handle *fh1, zend_file_handle *fh2) /* {{{ */
237
27.9k
{
238
27.9k
  if (fh1->type != fh2->type) {
239
667
    return 0;
240
667
  }
241
27.2k
  switch (fh1->type) {
242
26.5k
    case ZEND_HANDLE_FILENAME:
243
26.5k
      return strcmp(fh1->filename, fh2->filename) == 0;
244
0
    case ZEND_HANDLE_FP:
245
0
      return fh1->handle.fp == fh2->handle.fp;
246
667
    case ZEND_HANDLE_STREAM:
247
667
      return fh1->handle.stream.handle == fh2->handle.stream.handle;
248
0
    default:
249
0
      return 0;
250
0
  }
251
0
  return 0;
252
0
} /* }}} */