Return to php_fopen_wrapper.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 The PHP Group | ! 6: +----------------------------------------------------------------------+ ! 7: | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | ! 11: | If you did not receive a copy of the PHP license and are unable to | ! 12: | obtain it through the world-wide-web, please send a note to | ! 13: | license@php.net so we can mail you a copy immediately. | ! 14: +----------------------------------------------------------------------+ ! 15: | Authors: Rasmus Lerdorf <rasmus@php.net> | ! 16: | Jim Winstead <jimw@php.net> | ! 17: | Hartmut Holzgraefe <hholzgra@php.net> | ! 18: +----------------------------------------------------------------------+ ! 19: */ ! 20: /* $Id: php_fopen_wrapper.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 21: ! 22: #include <stdio.h> ! 23: #include <stdlib.h> ! 24: #if HAVE_UNISTD_H ! 25: #include <unistd.h> ! 26: #endif ! 27: ! 28: #include "php.h" ! 29: #include "php_globals.h" ! 30: #include "php_standard.h" ! 31: #include "php_fopen_wrappers.h" ! 32: #include "SAPI.h" ! 33: ! 34: static size_t php_stream_output_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ ! 35: { ! 36: PHPWRITE(buf, count); ! 37: return count; ! 38: } ! 39: /* }}} */ ! 40: ! 41: static size_t php_stream_output_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ ! 42: { ! 43: stream->eof = 1; ! 44: return 0; ! 45: } ! 46: /* }}} */ ! 47: ! 48: static int php_stream_output_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ ! 49: { ! 50: return 0; ! 51: } ! 52: /* }}} */ ! 53: ! 54: php_stream_ops php_stream_output_ops = { ! 55: php_stream_output_write, ! 56: php_stream_output_read, ! 57: php_stream_output_close, ! 58: NULL, /* flush */ ! 59: "Output", ! 60: NULL, /* seek */ ! 61: NULL, /* cast */ ! 62: NULL, /* stat */ ! 63: NULL /* set_option */ ! 64: }; ! 65: ! 66: static size_t php_stream_input_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ ! 67: { ! 68: return -1; ! 69: } ! 70: /* }}} */ ! 71: ! 72: static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ ! 73: { ! 74: off_t *position = (off_t*)stream->abstract; ! 75: size_t read_bytes = 0; ! 76: ! 77: if (!stream->eof) { ! 78: if (SG(request_info).raw_post_data) { /* data has already been read by a post handler */ ! 79: read_bytes = SG(request_info).raw_post_data_length - *position; ! 80: if (read_bytes <= count) { ! 81: stream->eof = 1; ! 82: } else { ! 83: read_bytes = count; ! 84: } ! 85: if (read_bytes) { ! 86: memcpy(buf, SG(request_info).raw_post_data + *position, read_bytes); ! 87: } ! 88: } else if (sapi_module.read_post) { ! 89: read_bytes = sapi_module.read_post(buf, count TSRMLS_CC); ! 90: if (read_bytes <= 0) { ! 91: stream->eof = 1; ! 92: read_bytes = 0; ! 93: } ! 94: /* Increment SG(read_post_bytes) only when something was actually read. */ ! 95: SG(read_post_bytes) += read_bytes; ! 96: } else { ! 97: stream->eof = 1; ! 98: } ! 99: } ! 100: ! 101: *position += read_bytes; ! 102: ! 103: return read_bytes; ! 104: } ! 105: /* }}} */ ! 106: ! 107: static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ ! 108: { ! 109: efree(stream->abstract); ! 110: ! 111: return 0; ! 112: } ! 113: /* }}} */ ! 114: ! 115: static int php_stream_input_flush(php_stream *stream TSRMLS_DC) /* {{{ */ ! 116: { ! 117: return -1; ! 118: } ! 119: /* }}} */ ! 120: ! 121: php_stream_ops php_stream_input_ops = { ! 122: php_stream_input_write, ! 123: php_stream_input_read, ! 124: php_stream_input_close, ! 125: php_stream_input_flush, ! 126: "Input", ! 127: NULL, /* seek */ ! 128: NULL, /* cast */ ! 129: NULL, /* stat */ ! 130: NULL /* set_option */ ! 131: }; ! 132: ! 133: static void php_stream_apply_filter_list(php_stream *stream, char *filterlist, int read_chain, int write_chain TSRMLS_DC) /* {{{ */ ! 134: { ! 135: char *p, *token; ! 136: php_stream_filter *temp_filter; ! 137: ! 138: p = php_strtok_r(filterlist, "|", &token); ! 139: while (p) { ! 140: php_url_decode(p, strlen(p)); ! 141: if (read_chain) { ! 142: if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) { ! 143: php_stream_filter_append(&stream->readfilters, temp_filter); ! 144: } else { ! 145: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p); ! 146: } ! 147: } ! 148: if (write_chain) { ! 149: if ((temp_filter = php_stream_filter_create(p, NULL, php_stream_is_persistent(stream) TSRMLS_CC))) { ! 150: php_stream_filter_append(&stream->writefilters, temp_filter); ! 151: } else { ! 152: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create filter (%s)", p); ! 153: } ! 154: } ! 155: p = php_strtok_r(NULL, "|", &token); ! 156: } ! 157: } ! 158: /* }}} */ ! 159: ! 160: php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */ ! 161: { ! 162: int fd = -1; ! 163: int mode_rw = 0; ! 164: php_stream * stream = NULL; ! 165: char *p, *token, *pathdup; ! 166: long max_memory; ! 167: FILE *file = NULL; ! 168: ! 169: if (!strncasecmp(path, "php://", 6)) { ! 170: path += 6; ! 171: } ! 172: ! 173: if (!strncasecmp(path, "temp", 4)) { ! 174: path += 4; ! 175: max_memory = PHP_STREAM_MAX_MEM; ! 176: if (!strncasecmp(path, "/maxmemory:", 11)) { ! 177: path += 11; ! 178: max_memory = strtol(path, NULL, 10); ! 179: if (max_memory < 0) { ! 180: php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Max memory must be >= 0"); ! 181: return NULL; ! 182: } ! 183: } ! 184: if (strpbrk(mode, "wa+")) { ! 185: mode_rw = TEMP_STREAM_DEFAULT; ! 186: } else { ! 187: mode_rw = TEMP_STREAM_READONLY; ! 188: } ! 189: return php_stream_temp_create(mode_rw, max_memory); ! 190: } ! 191: ! 192: if (!strcasecmp(path, "memory")) { ! 193: if (strpbrk(mode, "wa+")) { ! 194: mode_rw = TEMP_STREAM_DEFAULT; ! 195: } else { ! 196: mode_rw = TEMP_STREAM_READONLY; ! 197: } ! 198: return php_stream_memory_create(mode_rw); ! 199: } ! 200: ! 201: if (!strcasecmp(path, "output")) { ! 202: return php_stream_alloc(&php_stream_output_ops, NULL, 0, "wb"); ! 203: } ! 204: ! 205: if (!strcasecmp(path, "input")) { ! 206: if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { ! 207: if (options & REPORT_ERRORS) { ! 208: php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration"); ! 209: } ! 210: return NULL; ! 211: } ! 212: return php_stream_alloc(&php_stream_input_ops, ecalloc(1, sizeof(off_t)), 0, "rb"); ! 213: } ! 214: ! 215: if (!strcasecmp(path, "stdin")) { ! 216: if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { ! 217: if (options & REPORT_ERRORS) { ! 218: php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration"); ! 219: } ! 220: return NULL; ! 221: } ! 222: if (!strcmp(sapi_module.name, "cli")) { ! 223: static int cli_in = 0; ! 224: fd = STDIN_FILENO; ! 225: if (cli_in) { ! 226: fd = dup(fd); ! 227: } else { ! 228: cli_in = 1; ! 229: file = stdin; ! 230: } ! 231: } else { ! 232: fd = dup(STDIN_FILENO); ! 233: } ! 234: } else if (!strcasecmp(path, "stdout")) { ! 235: if (!strcmp(sapi_module.name, "cli")) { ! 236: static int cli_out = 0; ! 237: fd = STDOUT_FILENO; ! 238: if (cli_out++) { ! 239: fd = dup(fd); ! 240: } else { ! 241: cli_out = 1; ! 242: file = stdout; ! 243: } ! 244: } else { ! 245: fd = dup(STDOUT_FILENO); ! 246: } ! 247: } else if (!strcasecmp(path, "stderr")) { ! 248: if (!strcmp(sapi_module.name, "cli")) { ! 249: static int cli_err = 0; ! 250: fd = STDERR_FILENO; ! 251: if (cli_err++) { ! 252: fd = dup(fd); ! 253: } else { ! 254: cli_err = 1; ! 255: file = stderr; ! 256: } ! 257: } else { ! 258: fd = dup(STDERR_FILENO); ! 259: } ! 260: } else if (!strncasecmp(path, "fd/", 3)) { ! 261: char *start, ! 262: *end; ! 263: long fildes_ori; ! 264: int dtablesize; ! 265: ! 266: start = &path[3]; ! 267: fildes_ori = strtol(start, &end, 10); ! 268: if (end == start || *end != '\0') { ! 269: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, ! 270: "php://fd/ stream must be specified in the form php://fd/<orig fd>"); ! 271: return NULL; ! 272: } ! 273: ! 274: #if HAVE_UNISTD_H ! 275: dtablesize = getdtablesize(); ! 276: #else ! 277: dtablesize = INT_MAX; ! 278: #endif ! 279: ! 280: if (fildes_ori < 0 || fildes_ori >= dtablesize) { ! 281: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, ! 282: "The file descriptors must be non-negative numbers smaller than %d", dtablesize); ! 283: return NULL; ! 284: } ! 285: ! 286: fd = dup(fildes_ori); ! 287: if (fd == -1) { ! 288: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, ! 289: "Error duping file descriptor %ld; possibly it doesn't exist: " ! 290: "[%d]: %s", fildes_ori, errno, strerror(errno)); ! 291: return NULL; ! 292: } ! 293: } else if (!strncasecmp(path, "filter/", 7)) { ! 294: /* Save time/memory when chain isn't specified */ ! 295: if (strchr(mode, 'r') || strchr(mode, '+')) { ! 296: mode_rw |= PHP_STREAM_FILTER_READ; ! 297: } ! 298: if (strchr(mode, 'w') || strchr(mode, '+') || strchr(mode, 'a')) { ! 299: mode_rw |= PHP_STREAM_FILTER_WRITE; ! 300: } ! 301: pathdup = estrndup(path + 6, strlen(path + 6)); ! 302: p = strstr(pathdup, "/resource="); ! 303: if (!p) { ! 304: php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "No URL resource specified"); ! 305: efree(pathdup); ! 306: return NULL; ! 307: } ! 308: if (!(stream = php_stream_open_wrapper(p + 10, mode, options, opened_path))) { ! 309: efree(pathdup); ! 310: return NULL; ! 311: } ! 312: ! 313: *p = '\0'; ! 314: ! 315: p = php_strtok_r(pathdup + 1, "/", &token); ! 316: while (p) { ! 317: if (!strncasecmp(p, "read=", 5)) { ! 318: php_stream_apply_filter_list(stream, p + 5, 1, 0 TSRMLS_CC); ! 319: } else if (!strncasecmp(p, "write=", 6)) { ! 320: php_stream_apply_filter_list(stream, p + 6, 0, 1 TSRMLS_CC); ! 321: } else { ! 322: php_stream_apply_filter_list(stream, p, mode_rw & PHP_STREAM_FILTER_READ, mode_rw & PHP_STREAM_FILTER_WRITE TSRMLS_CC); ! 323: } ! 324: p = php_strtok_r(NULL, "/", &token); ! 325: } ! 326: efree(pathdup); ! 327: ! 328: return stream; ! 329: } else { ! 330: /* invalid php://thingy */ ! 331: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid php:// URL specified"); ! 332: return NULL; ! 333: } ! 334: ! 335: /* must be stdin, stderr or stdout */ ! 336: if (fd == -1) { ! 337: /* failed to dup */ ! 338: return NULL; ! 339: } ! 340: ! 341: #if defined(S_IFSOCK) && !defined(WIN32) && !defined(__BEOS__) ! 342: do { ! 343: struct stat st; ! 344: memset(&st, 0, sizeof(st)); ! 345: if (fstat(fd, &st) == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { ! 346: stream = php_stream_sock_open_from_socket(fd, NULL); ! 347: if (stream) { ! 348: stream->ops = &php_stream_socket_ops; ! 349: return stream; ! 350: } ! 351: } ! 352: } while (0); ! 353: #endif ! 354: ! 355: if (file) { ! 356: stream = php_stream_fopen_from_file(file, mode); ! 357: } else { ! 358: stream = php_stream_fopen_from_fd(fd, mode, NULL); ! 359: if (stream == NULL) { ! 360: close(fd); ! 361: } ! 362: } ! 363: ! 364: return stream; ! 365: } ! 366: /* }}} */ ! 367: ! 368: static php_stream_wrapper_ops php_stdio_wops = { ! 369: php_stream_url_wrap_php, ! 370: NULL, /* close */ ! 371: NULL, /* fstat */ ! 372: NULL, /* stat */ ! 373: NULL, /* opendir */ ! 374: "PHP", ! 375: NULL, /* unlink */ ! 376: NULL, /* rename */ ! 377: NULL, /* mkdir */ ! 378: NULL /* rmdir */ ! 379: }; ! 380: ! 381: php_stream_wrapper php_stream_php_wrapper = { ! 382: &php_stdio_wops, ! 383: NULL, ! 384: 0, /* is_url */ ! 385: }; ! 386: ! 387: ! 388: /* ! 389: * Local variables: ! 390: * tab-width: 4 ! 391: * c-basic-offset: 4 ! 392: * End: ! 393: * vim600: sw=4 ts=4 fdm=marker ! 394: * vim<600: sw=4 ts=4 ! 395: */