xref: /php-src/ext/spl/spl_directory.c (revision a5cacba6)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Marcus Boerger <helly@php.net>                               |
14    +----------------------------------------------------------------------+
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
20 
21 #include "php.h"
22 #include "ext/standard/file.h"
23 #include "ext/standard/php_filestat.h"
24 #include "ext/standard/flock_compat.h"
25 #include "ext/standard/scanf.h"
26 #include "ext/standard/php_string.h"
27 #include "zend_exceptions.h"
28 #include "zend_interfaces.h"
29 
30 #include "php_spl.h"
31 #include "spl_functions.h"
32 #include "spl_iterators.h"
33 #include "spl_directory.h"
34 #include "spl_directory_arginfo.h"
35 #include "spl_exceptions.h"
36 
37 #define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0)
38 
39 /* declare the class handlers */
40 static zend_object_handlers spl_filesystem_object_handlers;
41 /* includes handler to validate object state when retrieving methods */
42 static zend_object_handlers spl_filesystem_object_check_handlers;
43 
44 /* decalre the class entry */
45 PHPAPI zend_class_entry *spl_ce_SplFileInfo;
46 PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
47 PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
48 PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
49 PHPAPI zend_class_entry *spl_ce_GlobIterator;
50 PHPAPI zend_class_entry *spl_ce_SplFileObject;
51 PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
52 
53 /* Object helper */
spl_filesystem_from_obj(zend_object * obj)54 static inline spl_filesystem_object *spl_filesystem_from_obj(zend_object *obj) /* {{{ */ {
55 	return (spl_filesystem_object*)((char*)(obj) - XtOffsetOf(spl_filesystem_object, std));
56 }
57 /* }}} */
58 
59 /* define an overloaded iterator structure */
60 typedef struct {
61 	zend_object_iterator  intern;
62 	zval                  current;
63 	void                 *object;
64 } spl_filesystem_iterator;
65 
spl_filesystem_object_to_iterator(spl_filesystem_object * obj)66 static inline spl_filesystem_iterator* spl_filesystem_object_to_iterator(spl_filesystem_object *obj)
67 {
68 	spl_filesystem_iterator    *it;
69 
70 	it = ecalloc(1, sizeof(spl_filesystem_iterator));
71 	it->object = (void *)obj;
72 	zend_iterator_init(&it->intern);
73 	return it;
74 }
75 
spl_filesystem_iterator_to_object(spl_filesystem_iterator * it)76 static inline spl_filesystem_object* spl_filesystem_iterator_to_object(spl_filesystem_iterator *it)
77 {
78 	return (spl_filesystem_object*)it->object;
79 }
80 
81 #define CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(spl_filesystem_object_pointer) \
82 	if (!(spl_filesystem_object_pointer)->u.file.stream) { \
83 		zend_throw_error(NULL, "Object not initialized"); \
84 		RETURN_THROWS(); \
85 	}
86 
87 #define CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern) \
88 	if (!(intern)->u.dir.dirp) { \
89 		zend_throw_error(NULL, "Object not initialized"); \
90 		RETURN_THROWS(); \
91 	}
92 
spl_filesystem_file_free_line(spl_filesystem_object * intern)93 static void spl_filesystem_file_free_line(spl_filesystem_object *intern) /* {{{ */
94 {
95 	if (intern->u.file.current_line) {
96 		efree(intern->u.file.current_line);
97 		intern->u.file.current_line = NULL;
98 	}
99 	if (!Z_ISUNDEF(intern->u.file.current_zval)) {
100 		zval_ptr_dtor(&intern->u.file.current_zval);
101 		ZVAL_UNDEF(&intern->u.file.current_zval);
102 	}
103 } /* }}} */
104 
spl_filesystem_object_destroy_object(zend_object * object)105 static void spl_filesystem_object_destroy_object(zend_object *object) /* {{{ */
106 {
107 	spl_filesystem_object *intern = spl_filesystem_from_obj(object);
108 
109 	zend_objects_destroy_object(object);
110 
111 	switch(intern->type) {
112 	case SPL_FS_DIR:
113 		if (intern->u.dir.dirp) {
114 			php_stream_close(intern->u.dir.dirp);
115 			intern->u.dir.dirp = NULL;
116 		}
117 		break;
118 	case SPL_FS_FILE:
119 		if (intern->u.file.stream) {
120 			/*
121 			if (intern->u.file.zcontext) {
122 			   zend_list_delref(Z_RESVAL_P(intern->zcontext));
123 			}
124 			*/
125 			if (!intern->u.file.stream->is_persistent) {
126 				php_stream_close(intern->u.file.stream);
127 			} else {
128 				php_stream_pclose(intern->u.file.stream);
129 			}
130 			intern->u.file.stream = NULL;
131 			ZVAL_UNDEF(&intern->u.file.zresource);
132 		}
133 		break;
134 	default:
135 		break;
136 	}
137 } /* }}} */
138 
spl_filesystem_object_free_storage(zend_object * object)139 static void spl_filesystem_object_free_storage(zend_object *object) /* {{{ */
140 {
141 	spl_filesystem_object *intern = spl_filesystem_from_obj(object);
142 
143 	if (intern->oth_handler && intern->oth_handler->dtor) {
144 		intern->oth_handler->dtor(intern);
145 	}
146 
147 	zend_object_std_dtor(&intern->std);
148 
149 	if (intern->path) {
150 		zend_string_release(intern->path);
151 	}
152 	if (intern->file_name) {
153 		zend_string_release(intern->file_name);
154 	}
155 	switch(intern->type) {
156 	case SPL_FS_INFO:
157 		break;
158 	case SPL_FS_DIR:
159 		if (intern->u.dir.sub_path) {
160 			zend_string_release(intern->u.dir.sub_path);
161 		}
162 		break;
163 	case SPL_FS_FILE:
164 		if (intern->u.file.open_mode) {
165 			zend_string_release(intern->u.file.open_mode);
166 		}
167 		if (intern->orig_path) {
168 			zend_string_release(intern->orig_path);
169 		}
170 		spl_filesystem_file_free_line(intern);
171 		break;
172 	}
173 } /* }}} */
174 
175 /* {{{ spl_ce_dir_object_new */
176 /* creates the object by
177    - allocating memory
178    - initializing the object members
179    - storing the object
180    - setting it's handlers
181 
182    called from
183    - clone
184    - new
185  */
spl_filesystem_object_new_ex(zend_class_entry * class_type)186 static zend_object *spl_filesystem_object_new_ex(zend_class_entry *class_type)
187 {
188 	spl_filesystem_object *intern;
189 
190 	intern = emalloc(sizeof(spl_filesystem_object) + zend_object_properties_size(class_type));
191 	memset(intern, 0,
192 		MAX(XtOffsetOf(spl_filesystem_object, u.dir.entry),
193 			XtOffsetOf(spl_filesystem_object, u.file.escape) + sizeof(int)));
194 	/* intern->type = SPL_FS_INFO; done by set 0 */
195 	intern->file_class = spl_ce_SplFileObject;
196 	intern->info_class = spl_ce_SplFileInfo;
197 
198 	zend_object_std_init(&intern->std, class_type);
199 	object_properties_init(&intern->std, class_type);
200 
201 	return &intern->std;
202 }
203 /* }}} */
204 
205 /* {{{ spl_filesystem_object_new */
206 /* See spl_filesystem_object_new_ex */
spl_filesystem_object_new(zend_class_entry * class_type)207 static zend_object *spl_filesystem_object_new(zend_class_entry *class_type)
208 {
209 	return spl_filesystem_object_new_ex(class_type);
210 }
211 /* }}} */
212 
spl_filesystem_object_get_path(spl_filesystem_object * intern)213 PHPAPI zend_string *spl_filesystem_object_get_path(spl_filesystem_object *intern) /* {{{ */
214 {
215 #ifdef HAVE_GLOB
216 	if (intern->type == SPL_FS_DIR && php_stream_is(intern->u.dir.dirp, &php_glob_stream_ops)) {
217 		size_t len = 0;
218 		char *tmp = php_glob_stream_get_path(intern->u.dir.dirp, &len);
219 		if (len == 0) {
220 			return NULL;
221 		}
222 		return zend_string_init(tmp, len, /* persistent */ false);
223 	}
224 #endif
225 	if (!intern->path) {
226 		return NULL;
227 	}
228 	return zend_string_copy(intern->path);
229 } /* }}} */
230 
spl_filesystem_object_get_file_name(spl_filesystem_object * intern)231 static inline zend_result spl_filesystem_object_get_file_name(spl_filesystem_object *intern) /* {{{ */
232 {
233 	if (intern->file_name) {
234 		/* already known */
235 		return SUCCESS;
236 	}
237 
238 	switch (intern->type) {
239 		case SPL_FS_INFO:
240 		case SPL_FS_FILE:
241 			zend_throw_error(NULL, "Object not initialized");
242 			return FAILURE;
243 		case SPL_FS_DIR: {
244 			size_t name_len;
245 			zend_string *path;
246 			char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
247 
248 			path = spl_filesystem_object_get_path(intern);
249 			/* if there is parent path, amend it, otherwise just use the given path as is */
250 			name_len = strlen(intern->u.dir.entry.d_name);
251 			if (!path) {
252 				intern->file_name = zend_string_init(intern->u.dir.entry.d_name, name_len, 0);
253 				return SUCCESS;
254 			}
255 
256 			ZEND_ASSERT(ZSTR_LEN(path) != 0);
257 			intern->file_name = zend_string_concat3(
258 				ZSTR_VAL(path), ZSTR_LEN(path), &slash, 1, intern->u.dir.entry.d_name, name_len);
259 			zend_string_release_ex(path, /* persistent */ false);
260 			break;
261 		}
262 	}
263 	return SUCCESS;
264 } /* }}} */
265 
266 /* TODO Make void or have callers check return value */
spl_filesystem_dir_read(spl_filesystem_object * intern)267 static bool spl_filesystem_dir_read(spl_filesystem_object *intern) /* {{{ */
268 {
269 	if (intern->file_name) {
270 		/* invalidate */
271 		zend_string_release(intern->file_name);
272 		intern->file_name = NULL;
273 	}
274 	if (!intern->u.dir.dirp || !php_stream_readdir(intern->u.dir.dirp, &intern->u.dir.entry)) {
275 		intern->u.dir.entry.d_name[0] = '\0';
276 		return 0;
277 	} else {
278 		return 1;
279 	}
280 }
281 /* }}} */
282 
283 #define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos]))
284 
spl_filesystem_is_dot(const char * d_name)285 static inline bool spl_filesystem_is_dot(const char * d_name) /* {{{ */
286 {
287 	return !strcmp(d_name, ".") || !strcmp(d_name, "..");
288 }
289 /* }}} */
290 
291 /* {{{ spl_filesystem_dir_open */
292 /* open a directory resource
293  * Can emit an E_WARNING as it reports errors from php_stream_opendir() */
spl_filesystem_dir_open(spl_filesystem_object * intern,zend_string * path)294 static void spl_filesystem_dir_open(spl_filesystem_object* intern, zend_string *path)
295 {
296 	bool skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
297 
298 	intern->type = SPL_FS_DIR;
299 	intern->u.dir.dirp = php_stream_opendir(ZSTR_VAL(path), REPORT_ERRORS, FG(default_context));
300 
301 	if (ZSTR_LEN(path) > 1 && IS_SLASH_AT(ZSTR_VAL(path), ZSTR_LEN(path)-1)) {
302 		intern->path = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path)-1, 0);
303 	} else {
304 		intern->path = zend_string_copy(path);
305 	}
306 	intern->u.dir.index = 0;
307 
308 	if (EG(exception) || intern->u.dir.dirp == NULL) {
309 		intern->u.dir.entry.d_name[0] = '\0';
310 		if (!EG(exception)) {
311 			/* open failed w/out notice (turned to exception due to EH_THROW) */
312 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
313 				"Failed to open directory \"%s\"", ZSTR_VAL(path));
314 		}
315 	} else {
316 		do {
317 			spl_filesystem_dir_read(intern);
318 		} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
319 	}
320 }
321 /* }}} */
322 
323 /* Can generate E_WARNINGS as we report errors from stream initialized via
324  * php_stream_open_wrapper_ex() */
spl_filesystem_file_open(spl_filesystem_object * intern,bool use_include_path)325 static zend_result spl_filesystem_file_open(spl_filesystem_object *intern, bool use_include_path) /* {{{ */
326 {
327 	zval tmp;
328 
329 	intern->type = SPL_FS_FILE;
330 	php_stat(intern->file_name, FS_IS_DIR, &tmp);
331 	if (Z_TYPE(tmp) == IS_TRUE) {
332 		zend_string_release(intern->u.file.open_mode);
333 		intern->u.file.open_mode = NULL;
334 		intern->file_name = NULL;
335 		zend_throw_exception_ex(spl_ce_LogicException, 0, "Cannot use SplFileObject with directories");
336 		return FAILURE;
337 	}
338 
339 	intern->u.file.context = php_stream_context_from_zval(intern->u.file.zcontext, 0);
340 	intern->u.file.stream = php_stream_open_wrapper_ex(ZSTR_VAL(intern->file_name), ZSTR_VAL(intern->u.file.open_mode), (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, intern->u.file.context);
341 
342 	if (!ZSTR_LEN(intern->file_name) || !intern->u.file.stream) {
343 		if (!EG(exception)) {
344 			zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot open file '%s'", ZSTR_VAL(intern->file_name));
345 		}
346 		zend_string_release(intern->u.file.open_mode);
347 		intern->u.file.open_mode = NULL;
348 		intern->file_name = NULL; /* until here it is not a copy */
349 		return FAILURE;
350 	}
351 
352 	/* prevent closing the stream outside of SplFileObject */
353 	intern->u.file.stream->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
354 
355 	/*
356 	if (intern->u.file.zcontext) {
357 		//zend_list_addref(Z_RES_VAL(intern->u.file.zcontext));
358 		Z_ADDREF_P(intern->u.file.zcontext);
359 	}
360 	*/
361 
362 	if (ZSTR_LEN(intern->file_name) > 1 && IS_SLASH_AT(ZSTR_VAL(intern->file_name), ZSTR_LEN(intern->file_name)-1)) {
363 		intern->file_name = zend_string_init(ZSTR_VAL(intern->file_name), ZSTR_LEN(intern->file_name)-1, 0);
364 	} else {
365 		intern->file_name = zend_string_copy(intern->file_name);
366 	}
367 
368 	intern->orig_path = zend_string_init(intern->u.file.stream->orig_path, strlen(intern->u.file.stream->orig_path), 0);
369 
370 	/* avoid reference counting in debug mode, thus do it manually */
371 	ZVAL_RES(&intern->u.file.zresource, intern->u.file.stream->res);
372 	/*!!! TODO: maybe bug?
373 	Z_SET_REFCOUNT(intern->u.file.zresource, 1);
374 	*/
375 
376 	intern->u.file.delimiter = ',';
377 	intern->u.file.enclosure = '"';
378 	intern->u.file.escape = (unsigned char) '\\';
379 
380 	intern->u.file.func_getCurr = zend_hash_str_find_ptr(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline") - 1);
381 
382 	return SUCCESS;
383 } /* }}} */
384 
385 /* {{{ spl_filesystem_object_clone */
386 /* Local zend_object creation (on stack)
387    Load the 'other' object
388    Create a new empty object (See spl_filesystem_object_new_ex)
389    Open the directory
390    Clone other members (properties)
391  */
spl_filesystem_object_clone(zend_object * old_object)392 static zend_object *spl_filesystem_object_clone(zend_object *old_object)
393 {
394 	zend_object *new_object;
395 	spl_filesystem_object *intern;
396 	spl_filesystem_object *source;
397 
398 	source = spl_filesystem_from_obj(old_object);
399 	new_object = spl_filesystem_object_new_ex(old_object->ce);
400 	intern = spl_filesystem_from_obj(new_object);
401 
402 	intern->flags = source->flags;
403 
404 	switch (source->type) {
405 		case SPL_FS_INFO:
406 			if (source->path != NULL) {
407 				intern->path = zend_string_copy(source->path);
408 			}
409 			if (source->file_name != NULL) {
410 				intern->file_name = zend_string_copy(source->file_name);
411 			}
412 			break;
413 		case SPL_FS_DIR: {
414 			spl_filesystem_dir_open(intern, source->path);
415 			/* read until we hit the position in which we were before */
416 			bool skip_dots = SPL_HAS_FLAG(source->flags, SPL_FILE_DIR_SKIPDOTS);
417 			int index;
418 			for (index = 0; index < source->u.dir.index; ++index) {
419 				do {
420 					spl_filesystem_dir_read(intern);
421 				} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
422 			}
423 			intern->u.dir.index = index;
424 			break;
425 		}
426 		case SPL_FS_FILE:
427 			ZEND_UNREACHABLE();
428 	}
429 
430 	intern->file_class = source->file_class;
431 	intern->info_class = source->info_class;
432 	intern->oth = source->oth;
433 	intern->oth_handler = source->oth_handler;
434 
435 	zend_objects_clone_members(new_object, old_object);
436 
437 	if (intern->oth_handler && intern->oth_handler->clone) {
438 		intern->oth_handler->clone(source, intern);
439 	}
440 
441 	return new_object;
442 }
443 /* }}} */
444 
spl_filesystem_info_set_filename(spl_filesystem_object * intern,zend_string * path)445 static void spl_filesystem_info_set_filename(spl_filesystem_object *intern, zend_string *path) /* {{{ */
446 {
447 	size_t path_len;
448 
449 	if (intern->file_name) {
450 		zend_string_release(intern->file_name);
451 	}
452 
453 	path_len = ZSTR_LEN(path);
454 	if (path_len > 1 && IS_SLASH_AT(ZSTR_VAL(path), path_len-1)) {
455 		do {
456 			path_len--;
457 		} while (path_len > 1 && IS_SLASH_AT(ZSTR_VAL(path), path_len - 1));
458 		intern->file_name = zend_string_init(ZSTR_VAL(path), path_len, 0);
459 	} else {
460 		intern->file_name = zend_string_copy(path);
461 	}
462 	while (path_len > 1 && !IS_SLASH_AT(ZSTR_VAL(path), path_len-1)) {
463 		path_len--;
464 	}
465 	if (path_len) {
466 		path_len--;
467 	}
468 
469 	if (intern->path) {
470 		zend_string_release(intern->path);
471 	}
472 	intern->path = zend_string_init(ZSTR_VAL(path), path_len, 0);
473 } /* }}} */
474 
spl_filesystem_object_create_info(spl_filesystem_object * source,zend_string * file_path,zend_class_entry * ce,zval * return_value)475 static spl_filesystem_object *spl_filesystem_object_create_info(spl_filesystem_object *source, zend_string *file_path, zend_class_entry *ce, zval *return_value) /* {{{ */
476 {
477 	spl_filesystem_object *intern;
478 	zval arg1;
479 
480 	if (!file_path || !ZSTR_LEN(file_path)) {
481 #ifdef PHP_WIN32
482 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot create SplFileInfo for empty path");
483 #endif
484 		return NULL;
485 	}
486 
487 	ce = ce ? ce : source->info_class;
488 
489 	intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
490 	RETVAL_OBJ(&intern->std);
491 
492 	if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
493 		ZVAL_STR_COPY(&arg1, file_path);
494 		zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1);
495 		zval_ptr_dtor(&arg1);
496 	} else {
497 		spl_filesystem_info_set_filename(intern, file_path);
498 	}
499 
500 	return intern;
501 } /* }}} */
502 
spl_filesystem_object_create_type(int num_args,spl_filesystem_object * source,int type,zend_class_entry * ce,zval * return_value)503 static spl_filesystem_object *spl_filesystem_object_create_type(int num_args, spl_filesystem_object *source, int type, zend_class_entry *ce, zval *return_value) /* {{{ */
504 {
505 	spl_filesystem_object *intern;
506 	bool use_include_path = 0;
507 	zval arg1, arg2;
508 	zend_error_handling error_handling;
509 
510 	switch (source->type) {
511 		case SPL_FS_INFO:
512 		case SPL_FS_FILE:
513 			break;
514 		case SPL_FS_DIR:
515 			if (!source->u.dir.entry.d_name[0]) {
516 				zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Could not open file");
517 				return NULL;
518 			}
519 	}
520 
521 	switch (type) {
522 		case SPL_FS_INFO:
523 			ce = ce ? ce : source->info_class;
524 
525 			intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
526 			RETVAL_OBJ(&intern->std);
527 
528 			if (spl_filesystem_object_get_file_name(source) == FAILURE) {
529 				return NULL;
530 			}
531 
532 			if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
533 				ZVAL_STR_COPY(&arg1, source->file_name);
534 				zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1);
535 				zval_ptr_dtor(&arg1);
536 			} else {
537 				intern->file_name = zend_string_copy(source->file_name);
538 				intern->path = spl_filesystem_object_get_path(source);
539 			}
540 			break;
541 		case SPL_FS_FILE:
542 		{
543 			ce = ce ? ce : source->file_class;
544 
545 			zend_string *open_mode = ZSTR_CHAR('r');
546 			zval *resource = NULL;
547 
548 			if (zend_parse_parameters(num_args, "|Sbr!",
549 				&open_mode, &use_include_path, &resource) == FAILURE
550 			) {
551 				return NULL;
552 			}
553 
554 			intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
555 			RETVAL_OBJ(&intern->std);
556 
557 			if (spl_filesystem_object_get_file_name(source) == FAILURE) {
558 				return NULL;
559 			}
560 
561 			if (ce->constructor->common.scope != spl_ce_SplFileObject) {
562 				ZVAL_STR_COPY(&arg1, source->file_name);
563 				ZVAL_STR_COPY(&arg2, open_mode);
564 				zend_call_method_with_2_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1, &arg2);
565 				zval_ptr_dtor(&arg1);
566 				zval_ptr_dtor(&arg2);
567 			} else {
568 				intern->file_name = source->file_name;
569 				intern->path = spl_filesystem_object_get_path(source);
570 				intern->u.file.open_mode = zend_string_copy(open_mode);
571 				intern->u.file.zcontext = resource;
572 
573 				/* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */
574 				zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
575 				if (spl_filesystem_file_open(intern, use_include_path) == FAILURE) {
576 					zend_restore_error_handling(&error_handling);
577 					zval_ptr_dtor(return_value);
578 					ZVAL_NULL(return_value);
579 					return NULL;
580 				}
581 				zend_restore_error_handling(&error_handling);
582 			}
583 			break;
584 		}
585 		case SPL_FS_DIR:
586 			zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Operation not supported");
587 			return NULL;
588 	}
589 	return NULL;
590 } /* }}} */
591 
spl_filesystem_is_invalid_or_dot(const char * d_name)592 static bool spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */
593 {
594 	return d_name[0] == '\0' || spl_filesystem_is_dot(d_name);
595 }
596 /* }}} */
597 
spl_filesystem_object_get_pathname(spl_filesystem_object * intern)598 static zend_string *spl_filesystem_object_get_pathname(spl_filesystem_object *intern) { /* {{{ */
599 	switch (intern->type) {
600 		case SPL_FS_INFO:
601 		case SPL_FS_FILE:
602 			return intern->file_name;
603 		case SPL_FS_DIR:
604 			if (intern->u.dir.entry.d_name[0]) {
605 				spl_filesystem_object_get_file_name(intern);
606 				return intern->file_name;
607 			}
608 	}
609 	return NULL;
610 }
611 /* }}} */
612 
spl_filesystem_object_get_debug_info(zend_object * object)613 static inline HashTable *spl_filesystem_object_get_debug_info(zend_object *object) /* {{{ */
614 {
615 	spl_filesystem_object *intern = spl_filesystem_from_obj(object);
616 	zval tmp;
617 	HashTable *rv;
618 	zend_string *pnstr;
619 	zend_string *path;
620 	char stmp[2];
621 
622 	if (!intern->std.properties) {
623 		rebuild_object_properties(&intern->std);
624 	}
625 
626 	rv = zend_array_dup(intern->std.properties);
627 
628 	pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1);
629 	path = spl_filesystem_object_get_pathname(intern);
630 	if (path) {
631 		ZVAL_STR_COPY(&tmp, path);
632 	} else {
633 		ZVAL_EMPTY_STRING(&tmp);
634 	}
635 	zend_symtable_update(rv, pnstr, &tmp);
636 	zend_string_release_ex(pnstr, 0);
637 
638 	if (intern->file_name) {
639 		zend_string *path;
640 
641 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1);
642 		path = spl_filesystem_object_get_path(intern);
643 
644 		if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
645 			/* +1 to skip the trailing / of the path in the file name */
646 			ZVAL_STRINGL(&tmp, ZSTR_VAL(intern->file_name) + ZSTR_LEN(path) + 1, ZSTR_LEN(intern->file_name) - (ZSTR_LEN(path) + 1));
647 		} else {
648 			ZVAL_STR_COPY(&tmp, intern->file_name);
649 		}
650 		zend_symtable_update(rv, pnstr, &tmp);
651 		zend_string_release_ex(pnstr, /* persistent */ false);
652 		if (path) {
653 			zend_string_release_ex(path, /* persistent */ false);
654 		}
655 	}
656 	if (intern->type == SPL_FS_DIR) {
657 #ifdef HAVE_GLOB
658 		pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1);
659 		if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
660 			ZVAL_STR_COPY(&tmp, intern->path);
661 		} else {
662 			ZVAL_FALSE(&tmp);
663 		}
664 		zend_symtable_update(rv, pnstr, &tmp);
665 		zend_string_release_ex(pnstr, 0);
666 #endif
667 		pnstr = spl_gen_private_prop_name(spl_ce_RecursiveDirectoryIterator, "subPathName", sizeof("subPathName")-1);
668 		if (intern->u.dir.sub_path) {
669 			ZVAL_STR_COPY(&tmp, intern->u.dir.sub_path);
670 		} else {
671 			ZVAL_EMPTY_STRING(&tmp);
672 		}
673 		zend_symtable_update(rv, pnstr, &tmp);
674 		zend_string_release_ex(pnstr, 0);
675 	}
676 	if (intern->type == SPL_FS_FILE) {
677 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "openMode", sizeof("openMode")-1);
678 		ZVAL_STR_COPY(&tmp, intern->u.file.open_mode);
679 		zend_symtable_update(rv, pnstr, &tmp);
680 		zend_string_release_ex(pnstr, 0);
681 		stmp[1] = '\0';
682 		stmp[0] = intern->u.file.delimiter;
683 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "delimiter", sizeof("delimiter")-1);
684 		ZVAL_STRINGL(&tmp, stmp, 1);
685 		zend_symtable_update(rv, pnstr, &tmp);
686 		zend_string_release_ex(pnstr, 0);
687 		stmp[0] = intern->u.file.enclosure;
688 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "enclosure", sizeof("enclosure")-1);
689 		ZVAL_STRINGL(&tmp, stmp, 1);
690 		zend_symtable_update(rv, pnstr, &tmp);
691 		zend_string_release_ex(pnstr, 0);
692 	}
693 
694 	return rv;
695 }
696 /* }}} */
697 
spl_filesystem_object_get_method_check(zend_object ** object,zend_string * method,const zval * key)698 static zend_function *spl_filesystem_object_get_method_check(zend_object **object, zend_string *method, const zval *key) /* {{{ */
699 {
700 	spl_filesystem_object *fsobj = spl_filesystem_from_obj(*object);
701 
702 	if (fsobj->u.dir.dirp == NULL && fsobj->orig_path == NULL) {
703 		zend_throw_error(NULL, "The parent constructor was not called: the object is in an invalid state");
704 		return NULL;
705 	}
706 
707 	return zend_std_get_method(object, method, key);
708 }
709 /* }}} */
710 
711 #define DIT_CTOR_FLAGS  0x00000001
712 #define DIT_CTOR_GLOB   0x00000002
713 
spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS,zend_long ctor_flags)714 static void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_long ctor_flags) /* {{{ */
715 {
716 	spl_filesystem_object *intern;
717 	zend_string *path;
718 	zend_result parsed;
719 	zend_long flags = (ctor_flags & ~DIT_CTOR_FLAGS);
720 	zend_error_handling error_handling;
721 
722 	if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) {
723 		flags |= SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO;
724 		parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "P|l", &path, &flags);
725 	} else {
726 		flags |= SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF;
727 		parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "P", &path);
728 	}
729 	if (parsed == FAILURE) {
730 		RETURN_THROWS();
731 	}
732 
733 	if (ZSTR_LEN(path) == 0) {
734 		zend_argument_value_error(1, "cannot be empty");
735 		RETURN_THROWS();
736 	}
737 
738 	intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
739 	if (intern->path) {
740 		/* object is already initialized */
741 		zend_throw_error(NULL, "Directory object is already initialized");
742 		RETURN_THROWS();
743 	}
744 	intern->flags = flags;
745 
746 	/* spl_filesystem_dir_open() may emit an E_WARNING */
747 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
748 #ifdef HAVE_GLOB
749 	if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && !zend_string_starts_with_literal(path, "glob://")) {
750 		path = zend_strpprintf(0, "glob://%s", ZSTR_VAL(path));
751 		spl_filesystem_dir_open(intern, path);
752 		zend_string_release(path);
753 	} else
754 #endif
755 	{
756 		spl_filesystem_dir_open(intern, path);
757 
758 	}
759 	zend_restore_error_handling(&error_handling);
760 }
761 /* }}} */
762 
763 /* {{{ Cronstructs a new dir iterator from a path. */
PHP_METHOD(DirectoryIterator,__construct)764 PHP_METHOD(DirectoryIterator, __construct)
765 {
766 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
767 }
768 /* }}} */
769 
770 /* {{{ Rewind dir back to the start */
PHP_METHOD(DirectoryIterator,rewind)771 PHP_METHOD(DirectoryIterator, rewind)
772 {
773 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
774 
775 	if (zend_parse_parameters_none() == FAILURE) {
776 		RETURN_THROWS();
777 	}
778 
779 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
780 	intern->u.dir.index = 0;
781 	php_stream_rewinddir(intern->u.dir.dirp);
782 	spl_filesystem_dir_read(intern);
783 }
784 /* }}} */
785 
786 /* {{{ Return current dir entry */
PHP_METHOD(DirectoryIterator,key)787 PHP_METHOD(DirectoryIterator, key)
788 {
789 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
790 
791 	if (zend_parse_parameters_none() == FAILURE) {
792 		RETURN_THROWS();
793 	}
794 
795 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
796 	RETURN_LONG(intern->u.dir.index);
797 }
798 /* }}} */
799 
800 /* {{{ Return this (needed for Iterator interface) */
PHP_METHOD(DirectoryIterator,current)801 PHP_METHOD(DirectoryIterator, current)
802 {
803 	if (zend_parse_parameters_none() == FAILURE) {
804 		RETURN_THROWS();
805 	}
806 
807 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)));
808 	RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS));
809 }
810 /* }}} */
811 
812 /* {{{ Move to next entry */
PHP_METHOD(DirectoryIterator,next)813 PHP_METHOD(DirectoryIterator, next)
814 {
815 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
816 	bool skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
817 
818 	if (zend_parse_parameters_none() == FAILURE) {
819 		RETURN_THROWS();
820 	}
821 
822 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
823 	intern->u.dir.index++;
824 	do {
825 		spl_filesystem_dir_read(intern);
826 	} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
827 	if (intern->file_name) {
828 		zend_string_release(intern->file_name);
829 		intern->file_name = NULL;
830 	}
831 }
832 /* }}} */
833 
834 /* {{{ Seek to the given position */
PHP_METHOD(DirectoryIterator,seek)835 PHP_METHOD(DirectoryIterator, seek)
836 {
837 	spl_filesystem_object *intern    = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
838 	zval retval;
839 	zend_long pos;
840 
841 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &pos) == FAILURE) {
842 		RETURN_THROWS();
843 	}
844 
845 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
846 	if (intern->u.dir.index > pos) {
847 		/* we first rewind */
848 		zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_rewind, "rewind", NULL);
849 	}
850 
851 	while (intern->u.dir.index < pos) {
852 		bool valid = false;
853 		zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_valid, "valid", &retval);
854 		valid = zend_is_true(&retval);
855 		zval_ptr_dtor(&retval);
856 		if (!valid) {
857 			zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", pos);
858 			RETURN_THROWS();
859 		}
860 		zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_next, "next", NULL);
861 	}
862 } /* }}} */
863 
864 /* {{{ Check whether dir contains more entries */
PHP_METHOD(DirectoryIterator,valid)865 PHP_METHOD(DirectoryIterator, valid)
866 {
867 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
868 
869 	if (zend_parse_parameters_none() == FAILURE) {
870 		RETURN_THROWS();
871 	}
872 
873 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
874 	RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0');
875 }
876 /* }}} */
877 
878 /* {{{ Return the path */
PHP_METHOD(SplFileInfo,getPath)879 PHP_METHOD(SplFileInfo, getPath)
880 {
881 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
882 	zend_string *path;
883 
884 	if (zend_parse_parameters_none() == FAILURE) {
885 		RETURN_THROWS();
886 	}
887 
888   	path = spl_filesystem_object_get_path(intern);
889 	if (path) {
890 		RETURN_STR(path);
891 	} else {
892 		RETURN_EMPTY_STRING();
893 	}
894 }
895 /* }}} */
896 
897 /* {{{ Return filename only */
PHP_METHOD(SplFileInfo,getFilename)898 PHP_METHOD(SplFileInfo, getFilename)
899 {
900 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
901 	zend_string *path;
902 
903 	if (zend_parse_parameters_none() == FAILURE) {
904 		RETURN_THROWS();
905 	}
906 
907 	if (!intern->file_name) {
908 		zend_throw_error(NULL, "Object not initialized");
909 		RETURN_THROWS();
910 	}
911 
912 	path = spl_filesystem_object_get_path(intern);
913 
914 	if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
915 		/* +1 to skip the trailing / of the path in the file name */
916 		size_t path_len = ZSTR_LEN(path) + 1;
917 		RETVAL_STRINGL(ZSTR_VAL(intern->file_name) + path_len, ZSTR_LEN(intern->file_name) - path_len);
918 	} else {
919 		RETVAL_STR_COPY(intern->file_name);
920 	}
921 	if (path) {
922 		zend_string_release_ex(path, /* persistent */ false);
923 	}
924 }
925 /* }}} */
926 
927 /* {{{ Return filename of current dir entry */
PHP_METHOD(DirectoryIterator,getFilename)928 PHP_METHOD(DirectoryIterator, getFilename)
929 {
930 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
931 
932 	if (zend_parse_parameters_none() == FAILURE) {
933 		RETURN_THROWS();
934 	}
935 
936 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
937 	RETURN_STRING(intern->u.dir.entry.d_name);
938 }
939 /* }}} */
940 
941 /* {{{ Returns file extension component of path */
PHP_METHOD(SplFileInfo,getExtension)942 PHP_METHOD(SplFileInfo, getExtension)
943 {
944 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
945 	char *fname = NULL;
946 	const char *p;
947 	size_t flen;
948 	zend_string *path;
949 	size_t idx;
950 	zend_string *ret;
951 
952 	if (zend_parse_parameters_none() == FAILURE) {
953 		RETURN_THROWS();
954 	}
955 
956 	if (!intern->file_name) {
957 		zend_throw_error(NULL, "Object not initialized");
958 		RETURN_THROWS();
959 	}
960 
961 	path = spl_filesystem_object_get_path(intern);
962 
963 	if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
964 		fname = ZSTR_VAL(intern->file_name) + ZSTR_LEN(path) + 1;
965 		flen = ZSTR_LEN(intern->file_name) - (ZSTR_LEN(path) + 1);
966 	} else {
967 		fname = ZSTR_VAL(intern->file_name);
968 		flen = ZSTR_LEN(intern->file_name);
969 	}
970 	if (path) {
971 		zend_string_release_ex(path, /* persistent */ false);
972 	}
973 
974 	ret = php_basename(fname, flen, NULL, 0);
975 
976 	p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
977 	if (p) {
978 		idx = p - ZSTR_VAL(ret);
979 		RETVAL_STRINGL(ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
980 		zend_string_release_ex(ret, 0);
981 		return;
982 	} else {
983 		zend_string_release_ex(ret, 0);
984 		RETURN_EMPTY_STRING();
985 	}
986 }
987 /* }}}*/
988 
989 /* {{{ Returns the file extension component of path */
PHP_METHOD(DirectoryIterator,getExtension)990 PHP_METHOD(DirectoryIterator, getExtension)
991 {
992 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
993 	const char *p;
994 	size_t idx;
995 	zend_string *fname;
996 
997 	if (zend_parse_parameters_none() == FAILURE) {
998 		RETURN_THROWS();
999 	}
1000 
1001 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
1002 	fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), NULL, 0);
1003 
1004 	p = zend_memrchr(ZSTR_VAL(fname), '.', ZSTR_LEN(fname));
1005 	if (p) {
1006 		idx = p - ZSTR_VAL(fname);
1007 		RETVAL_STRINGL(ZSTR_VAL(fname) + idx + 1, ZSTR_LEN(fname) - idx - 1);
1008 		zend_string_release_ex(fname, 0);
1009 	} else {
1010 		zend_string_release_ex(fname, 0);
1011 		RETURN_EMPTY_STRING();
1012 	}
1013 }
1014 /* }}} */
1015 
1016 /* {{{ Returns filename component of path */
PHP_METHOD(SplFileInfo,getBasename)1017 PHP_METHOD(SplFileInfo, getBasename)
1018 {
1019 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1020 	char *fname, *suffix = 0;
1021 	size_t flen;
1022 	size_t slen = 0;
1023 	zend_string *path;
1024 
1025 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
1026 		RETURN_THROWS();
1027 	}
1028 
1029 	if (!intern->file_name) {
1030 		zend_throw_error(NULL, "Object not initialized");
1031 		RETURN_THROWS();
1032 	}
1033 
1034 	path = spl_filesystem_object_get_path(intern);
1035 
1036 	if (path && ZSTR_LEN(path) && ZSTR_LEN(path) < ZSTR_LEN(intern->file_name)) {
1037 		/* +1 to skip the trailing / of the path in the file name */
1038 		fname = ZSTR_VAL(intern->file_name) + ZSTR_LEN(path) + 1;
1039 		flen = ZSTR_LEN(intern->file_name) - (ZSTR_LEN(path) + 1);
1040 	} else {
1041 		fname = ZSTR_VAL(intern->file_name);
1042 		flen = ZSTR_LEN(intern->file_name);
1043 	}
1044 	if (path) {
1045 		zend_string_release_ex(path, /* persistent */ false);
1046 	}
1047 
1048 	RETURN_STR(php_basename(fname, flen, suffix, slen));
1049 }
1050 /* }}}*/
1051 
1052 /* {{{ Returns filename component of current dir entry */
PHP_METHOD(DirectoryIterator,getBasename)1053 PHP_METHOD(DirectoryIterator, getBasename)
1054 {
1055 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1056 	char *suffix = 0;
1057 	size_t slen = 0;
1058 	zend_string *fname;
1059 
1060 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
1061 		RETURN_THROWS();
1062 	}
1063 
1064 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
1065 	fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), suffix, slen);
1066 
1067 	RETURN_STR(fname);
1068 }
1069 /* }}} */
1070 
1071 /* {{{ Return path and filename */
PHP_METHOD(SplFileInfo,getPathname)1072 PHP_METHOD(SplFileInfo, getPathname)
1073 {
1074 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1075 	zend_string *path;
1076 
1077 	if (zend_parse_parameters_none() == FAILURE) {
1078 		RETURN_THROWS();
1079 	}
1080 	path = spl_filesystem_object_get_pathname(intern);
1081 	if (path) {
1082 		RETURN_STR_COPY(path);
1083 	} else {
1084 		RETURN_EMPTY_STRING();
1085 	}
1086 }
1087 /* }}} */
1088 
1089 /* {{{ Return getPathname() or getFilename() depending on flags */
PHP_METHOD(FilesystemIterator,key)1090 PHP_METHOD(FilesystemIterator, key)
1091 {
1092 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1093 
1094 	if (zend_parse_parameters_none() == FAILURE) {
1095 		RETURN_THROWS();
1096 	}
1097 
1098 	if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) {
1099 		RETURN_STRING(intern->u.dir.entry.d_name);
1100 	} else {
1101 		if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
1102 			RETURN_THROWS();
1103 		}
1104 		RETURN_STR_COPY(intern->file_name);
1105 	}
1106 }
1107 /* }}} */
1108 
1109 /* {{{ Return getFilename(), getFileInfo() or $this depending on flags */
PHP_METHOD(FilesystemIterator,current)1110 PHP_METHOD(FilesystemIterator, current)
1111 {
1112 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1113 
1114 	if (zend_parse_parameters_none() == FAILURE) {
1115 		RETURN_THROWS();
1116 	}
1117 
1118 	if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
1119 		if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
1120 			RETURN_THROWS();
1121 		}
1122 		RETURN_STR_COPY(intern->file_name);
1123 	} else if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
1124 		if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
1125 			RETURN_THROWS();
1126 		}
1127 		spl_filesystem_object_create_type(0, intern, SPL_FS_INFO, NULL, return_value);
1128 	} else {
1129 		RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS));
1130 	}
1131 }
1132 /* }}} */
1133 
1134 /* {{{ Returns true if current entry is '.' or  '..' */
PHP_METHOD(DirectoryIterator,isDot)1135 PHP_METHOD(DirectoryIterator, isDot)
1136 {
1137 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1138 
1139 	if (zend_parse_parameters_none() == FAILURE) {
1140 		RETURN_THROWS();
1141 	}
1142 
1143 	CHECK_DIRECTORY_ITERATOR_IS_INITIALIZED(intern);
1144 	RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name));
1145 }
1146 /* }}} */
1147 
1148 /* {{{ Constructs a new SplFileInfo from a path. */
1149 /* When the constructor gets called the object is already created
1150    by the engine, so we must only call 'additional' initializations.
1151  */
PHP_METHOD(SplFileInfo,__construct)1152 PHP_METHOD(SplFileInfo, __construct)
1153 {
1154 	spl_filesystem_object *intern;
1155 	zend_string *path;
1156 
1157 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &path) == FAILURE) {
1158 		RETURN_THROWS();
1159 	}
1160 
1161 	intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1162 
1163 	spl_filesystem_info_set_filename(intern, path);
1164 
1165 	/* intern->type = SPL_FS_INFO; already set */
1166 }
1167 /* }}} */
1168 
1169 /* {{{ FileInfoFunction */
1170 #define FileInfoFunction(func_name, func_num) \
1171 PHP_METHOD(SplFileInfo, func_name) \
1172 { \
1173 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS)); \
1174 	zend_error_handling error_handling; \
1175 	if (zend_parse_parameters_none() == FAILURE) { \
1176 		RETURN_THROWS(); \
1177 	} \
1178 	if (spl_filesystem_object_get_file_name(intern) == FAILURE) { \
1179 		RETURN_THROWS(); \
1180 	} \
1181 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);\
1182 	php_stat(intern->file_name, func_num, return_value); \
1183 	zend_restore_error_handling(&error_handling); \
1184 }
1185 /* }}} */
1186 
1187 /* {{{ Get file permissions */
FileInfoFunction(getPerms,FS_PERMS)1188 FileInfoFunction(getPerms, FS_PERMS)
1189 /* }}} */
1190 
1191 /* {{{ Get file inode */
1192 FileInfoFunction(getInode, FS_INODE)
1193 /* }}} */
1194 
1195 /* {{{ Get file size */
1196 FileInfoFunction(getSize, FS_SIZE)
1197 /* }}} */
1198 
1199 /* {{{ Get file owner */
1200 FileInfoFunction(getOwner, FS_OWNER)
1201 /* }}} */
1202 
1203 /* {{{ Get file group */
1204 FileInfoFunction(getGroup, FS_GROUP)
1205 /* }}} */
1206 
1207 /* {{{ Get last access time of file */
1208 FileInfoFunction(getATime, FS_ATIME)
1209 /* }}} */
1210 
1211 /* {{{ Get last modification time of file */
1212 FileInfoFunction(getMTime, FS_MTIME)
1213 /* }}} */
1214 
1215 /* {{{ Get inode modification time of file */
1216 FileInfoFunction(getCTime, FS_CTIME)
1217 /* }}} */
1218 
1219 /* {{{ Get file type */
1220 FileInfoFunction(getType, FS_TYPE)
1221 /* }}} */
1222 
1223 /* {{{ Returns true if file can be written */
1224 FileInfoFunction(isWritable, FS_IS_W)
1225 /* }}} */
1226 
1227 /* {{{ Returns true if file can be read */
1228 FileInfoFunction(isReadable, FS_IS_R)
1229 /* }}} */
1230 
1231 /* {{{ Returns true if file is executable */
1232 FileInfoFunction(isExecutable, FS_IS_X)
1233 /* }}} */
1234 
1235 /* {{{ Returns true if file is a regular file */
1236 FileInfoFunction(isFile, FS_IS_FILE)
1237 /* }}} */
1238 
1239 /* {{{ Returns true if file is directory */
1240 FileInfoFunction(isDir, FS_IS_DIR)
1241 /* }}} */
1242 
1243 /* {{{ Returns true if file is symbolic link */
1244 FileInfoFunction(isLink, FS_IS_LINK)
1245 /* }}} */
1246 
1247 /* {{{ Return the target of a symbolic link */
1248 PHP_METHOD(SplFileInfo, getLinkTarget)
1249 {
1250 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1251 	ssize_t ret;
1252 	char buff[MAXPATHLEN];
1253 
1254 	if (zend_parse_parameters_none() == FAILURE) {
1255 		RETURN_THROWS();
1256 	}
1257 
1258 	if (intern->file_name == NULL) {
1259 		if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
1260 			RETURN_THROWS();
1261 		}
1262 	}
1263 #if defined(PHP_WIN32) || defined(HAVE_SYMLINK)
1264 	if (intern->file_name == NULL) {
1265 		zend_value_error("Filename cannot be empty");
1266 		RETURN_THROWS();
1267 	}
1268 	if (!IS_ABSOLUTE_PATH(ZSTR_VAL(intern->file_name), ZSTR_LEN(intern->file_name))) {
1269 		char expanded_path[MAXPATHLEN];
1270 		if (!expand_filepath_with_mode(ZSTR_VAL(intern->file_name), expanded_path, NULL, 0, CWD_EXPAND )) {
1271 			php_error_docref(NULL, E_WARNING, "No such file or directory");
1272 			RETURN_FALSE;
1273 		}
1274 		ret = php_sys_readlink(expanded_path, buff, MAXPATHLEN - 1);
1275 	} else {
1276 		ret = php_sys_readlink(ZSTR_VAL(intern->file_name), buff,  MAXPATHLEN-1);
1277 	}
1278 #else
1279 	ret = -1; /* always fail if not implemented */
1280 #endif
1281 
1282 	if (ret == -1) {
1283 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to read link %s, error: %s", ZSTR_VAL(intern->file_name), strerror(errno));
1284 		RETVAL_FALSE;
1285 	} else {
1286 		/* Append NULL to the end of the string */
1287 		buff[ret] = '\0';
1288 
1289 		RETVAL_STRINGL(buff, ret);
1290 	}
1291 }
1292 /* }}} */
1293 
1294 /* {{{ Return the resolved path */
PHP_METHOD(SplFileInfo,getRealPath)1295 PHP_METHOD(SplFileInfo, getRealPath)
1296 {
1297 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1298 	char buff[MAXPATHLEN];
1299 	char *filename;
1300 
1301 	if (zend_parse_parameters_none() == FAILURE) {
1302 		RETURN_THROWS();
1303 	}
1304 
1305 	if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) {
1306 		if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
1307 			RETURN_THROWS();
1308 		}
1309 	}
1310 
1311 	if (intern->orig_path) {
1312 		filename = ZSTR_VAL(intern->orig_path);
1313 	} else {
1314 		filename = intern->file_name ? ZSTR_VAL(intern->file_name) : NULL;
1315 	}
1316 
1317 
1318 	if (filename && VCWD_REALPATH(filename, buff)) {
1319 #ifdef ZTS
1320 		if (VCWD_ACCESS(buff, F_OK)) {
1321 			RETURN_FALSE;
1322 		} else
1323 #endif
1324 		RETURN_STRING(buff);
1325 	} else {
1326 		RETURN_FALSE;
1327 	}
1328 }
1329 /* }}} */
1330 
1331 /* {{{ Open the current file */
PHP_METHOD(SplFileInfo,openFile)1332 PHP_METHOD(SplFileInfo, openFile)
1333 {
1334 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1335 
1336 	spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_FILE, NULL, return_value);
1337 }
1338 /* }}} */
1339 
1340 /* {{{ Class to use in openFile() */
PHP_METHOD(SplFileInfo,setFileClass)1341 PHP_METHOD(SplFileInfo, setFileClass)
1342 {
1343 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1344 	zend_class_entry *ce = spl_ce_SplFileObject;
1345 
1346 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
1347 		RETURN_THROWS();
1348 	}
1349 
1350 	intern->file_class = ce;
1351 }
1352 /* }}} */
1353 
1354 /* {{{ Class to use in getFileInfo(), getPathInfo() */
PHP_METHOD(SplFileInfo,setInfoClass)1355 PHP_METHOD(SplFileInfo, setInfoClass)
1356 {
1357 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1358 	zend_class_entry *ce = spl_ce_SplFileInfo;
1359 
1360 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
1361 		RETURN_THROWS();
1362 	}
1363 
1364 	intern->info_class = ce;
1365 }
1366 /* }}} */
1367 
1368 /* {{{ Get/copy file info */
PHP_METHOD(SplFileInfo,getFileInfo)1369 PHP_METHOD(SplFileInfo, getFileInfo)
1370 {
1371 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1372 	zend_class_entry *ce = intern->info_class;
1373 
1374 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C!", &ce) == FAILURE) {
1375 		RETURN_THROWS();
1376 	}
1377 
1378 	spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_INFO, ce, return_value);
1379 }
1380 /* }}} */
1381 
1382 /* {{{ Get/copy file info */
PHP_METHOD(SplFileInfo,getPathInfo)1383 PHP_METHOD(SplFileInfo, getPathInfo)
1384 {
1385 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1386 	zend_class_entry *ce = intern->info_class;
1387 	zend_string *path;
1388 
1389 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C!", &ce) == FAILURE) {
1390 		RETURN_THROWS();
1391 	}
1392 
1393 	path = spl_filesystem_object_get_pathname(intern);
1394 	if (path && ZSTR_LEN(path)) {
1395 		zend_string *dpath = zend_string_init(ZSTR_VAL(path), ZSTR_LEN(path), 0);
1396 		ZSTR_LEN(dpath) = php_dirname(ZSTR_VAL(dpath), ZSTR_LEN(path));
1397 		spl_filesystem_object_create_info(intern, dpath, ce, return_value);
1398 		zend_string_release(dpath);
1399 	}
1400 }
1401 /* }}} */
1402 
1403 /* {{{ */
PHP_METHOD(SplFileInfo,__debugInfo)1404 PHP_METHOD(SplFileInfo, __debugInfo)
1405 {
1406 	if (zend_parse_parameters_none() == FAILURE) {
1407 		RETURN_THROWS();
1408 	}
1409 
1410 	RETURN_ARR(spl_filesystem_object_get_debug_info(Z_OBJ_P(ZEND_THIS)));
1411 } /* }}} */
1412 
1413 /* {{{ */
PHP_METHOD(SplFileInfo,_bad_state_ex)1414 PHP_METHOD(SplFileInfo, _bad_state_ex)
1415 {
1416 	if (zend_parse_parameters_none() == FAILURE) {
1417 		RETURN_THROWS();
1418 	}
1419 	zend_throw_error(NULL, "The parent constructor was not called: the object is in an invalid state");
1420 	RETURN_THROWS();
1421 }
1422 /* }}} */
1423 
1424 /* {{{ Constructs a new dir iterator from a path. */
PHP_METHOD(FilesystemIterator,__construct)1425 PHP_METHOD(FilesystemIterator, __construct)
1426 {
1427 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS);
1428 }
1429 /* }}} */
1430 
1431 /* {{{ Rewind dir back to the start */
PHP_METHOD(FilesystemIterator,rewind)1432 PHP_METHOD(FilesystemIterator, rewind)
1433 {
1434 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1435 	bool skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
1436 
1437 	if (zend_parse_parameters_none() == FAILURE) {
1438 		RETURN_THROWS();
1439 	}
1440 
1441 	intern->u.dir.index = 0;
1442 	if (intern->u.dir.dirp) {
1443 		php_stream_rewinddir(intern->u.dir.dirp);
1444 	}
1445 	do {
1446 		spl_filesystem_dir_read(intern);
1447 	} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
1448 }
1449 /* }}} */
1450 
1451 /* {{{ Get handling flags */
PHP_METHOD(FilesystemIterator,getFlags)1452 PHP_METHOD(FilesystemIterator, getFlags)
1453 {
1454 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1455 
1456 	if (zend_parse_parameters_none() == FAILURE) {
1457 		RETURN_THROWS();
1458 	}
1459 
1460 	RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK));
1461 } /* }}} */
1462 
1463 /* {{{ Set handling flags */
PHP_METHOD(FilesystemIterator,setFlags)1464 PHP_METHOD(FilesystemIterator, setFlags)
1465 {
1466 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1467 	zend_long flags;
1468 
1469 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
1470 		RETURN_THROWS();
1471 	}
1472 
1473 	intern->flags &= ~(SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK);
1474 	intern->flags |= ((SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK) & flags);
1475 } /* }}} */
1476 
1477 /* {{{ Returns whether current entry is a directory and not '.' or '..' */
PHP_METHOD(RecursiveDirectoryIterator,hasChildren)1478 PHP_METHOD(RecursiveDirectoryIterator, hasChildren)
1479 {
1480 	bool allow_links = 0;
1481 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1482 
1483 	ZEND_PARSE_PARAMETERS_START(0, 1)
1484 		Z_PARAM_OPTIONAL
1485 		Z_PARAM_BOOL(allow_links)
1486 	ZEND_PARSE_PARAMETERS_END();
1487 
1488 	if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
1489 		RETURN_FALSE;
1490 	} else {
1491 		if (intern->u.dir.entry.d_type == DT_DIR) {
1492 			RETURN_TRUE;
1493 		} else if (intern->u.dir.entry.d_type == DT_REG) {
1494 			RETURN_FALSE;
1495 		}
1496 		if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
1497 			RETURN_THROWS();
1498 		}
1499 		php_stat(intern->file_name, FS_LPERMS, return_value);
1500 		if (Z_TYPE_P(return_value) == IS_FALSE) {
1501 			return;
1502 		} else if (!S_ISLNK(Z_LVAL_P(return_value))) {
1503 			RETURN_BOOL(S_ISDIR(Z_LVAL_P(return_value)));
1504 		} else {
1505 			if (!allow_links
1506 			 && !(intern->flags & SPL_FILE_DIR_FOLLOW_SYMLINKS)) {
1507 				RETURN_FALSE;
1508 			}
1509 			php_stat(intern->file_name, FS_IS_DIR, return_value);
1510 		}
1511     }
1512 }
1513 /* }}} */
1514 
1515 /* {{{ Returns an iterator for the current entry if it is a directory */
PHP_METHOD(RecursiveDirectoryIterator,getChildren)1516 PHP_METHOD(RecursiveDirectoryIterator, getChildren)
1517 {
1518 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1519 	spl_filesystem_object *subdir;
1520 	char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
1521 
1522 	if (zend_parse_parameters_none() == FAILURE) {
1523 		RETURN_THROWS();
1524 	}
1525 
1526 	if (spl_filesystem_object_get_file_name(intern) == FAILURE) {
1527 		RETURN_THROWS();
1528 	}
1529 
1530 	zval params[2];
1531 	ZVAL_STR_COPY(&params[0], intern->file_name);
1532 	ZVAL_LONG(&params[1], intern->flags);
1533 
1534 	zend_result is_initialized = object_init_with_constructor(return_value, Z_OBJCE_P(ZEND_THIS), 2, params, NULL);
1535 	zval_ptr_dtor_str(&params[0]);
1536 	if (is_initialized == FAILURE) {
1537 		RETURN_THROWS();
1538 	}
1539 
1540 	subdir = spl_filesystem_from_obj(Z_OBJ_P(return_value));
1541 	if (subdir) {
1542 		size_t name_len = strlen(intern->u.dir.entry.d_name);
1543 		if (intern->u.dir.sub_path && ZSTR_LEN(intern->u.dir.sub_path)) {
1544 			zend_string *sub_path = zend_string_alloc(ZSTR_LEN(intern->u.dir.sub_path) + 1 + name_len, 0);
1545 			memcpy(ZSTR_VAL(sub_path), ZSTR_VAL(intern->u.dir.sub_path), ZSTR_LEN(intern->u.dir.sub_path));
1546 			ZSTR_VAL(sub_path)[ZSTR_LEN(intern->u.dir.sub_path)] = slash;
1547 			memcpy(ZSTR_VAL(sub_path) + ZSTR_LEN(intern->u.dir.sub_path) + 1, intern->u.dir.entry.d_name, name_len);
1548 			ZSTR_VAL(sub_path)[ZSTR_LEN(intern->u.dir.sub_path) + 1 + name_len] = 0;
1549 			subdir->u.dir.sub_path = sub_path;
1550 		} else {
1551 			subdir->u.dir.sub_path = zend_string_init(intern->u.dir.entry.d_name, name_len, 0);
1552 		}
1553 		subdir->info_class = intern->info_class;
1554 		subdir->file_class = intern->file_class;
1555 		subdir->oth = intern->oth;
1556 	}
1557 }
1558 /* }}} */
1559 
1560 /* {{{ Get sub path */
PHP_METHOD(RecursiveDirectoryIterator,getSubPath)1561 PHP_METHOD(RecursiveDirectoryIterator, getSubPath)
1562 {
1563 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1564 
1565 	if (zend_parse_parameters_none() == FAILURE) {
1566 		RETURN_THROWS();
1567 	}
1568 
1569 	if (intern->u.dir.sub_path) {
1570 		RETURN_STR_COPY(intern->u.dir.sub_path);
1571 	} else {
1572 		RETURN_EMPTY_STRING();
1573 	}
1574 }
1575 /* }}} */
1576 
1577 /* {{{ Get sub path and file name */
PHP_METHOD(RecursiveDirectoryIterator,getSubPathname)1578 PHP_METHOD(RecursiveDirectoryIterator, getSubPathname)
1579 {
1580 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1581 	char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
1582 
1583 	if (zend_parse_parameters_none() == FAILURE) {
1584 		RETURN_THROWS();
1585 	}
1586 
1587 	if (intern->u.dir.sub_path) {
1588 		RETURN_NEW_STR(strpprintf(0, "%s%c%s", ZSTR_VAL(intern->u.dir.sub_path), slash, intern->u.dir.entry.d_name));
1589 	} else {
1590 		RETURN_STRING(intern->u.dir.entry.d_name);
1591 	}
1592 }
1593 /* }}} */
1594 
1595 /* {{{ Cronstructs a new dir iterator from a path. */
PHP_METHOD(RecursiveDirectoryIterator,__construct)1596 PHP_METHOD(RecursiveDirectoryIterator, __construct)
1597 {
1598 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS);
1599 }
1600 /* }}} */
1601 
1602 #ifdef HAVE_GLOB
1603 /* {{{ Cronstructs a new dir iterator from a glob expression (no glob:// needed). */
PHP_METHOD(GlobIterator,__construct)1604 PHP_METHOD(GlobIterator, __construct)
1605 {
1606 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS|DIT_CTOR_GLOB);
1607 }
1608 /* }}} */
1609 
1610 /* {{{ Return the number of directories and files found by globbing */
PHP_METHOD(GlobIterator,count)1611 PHP_METHOD(GlobIterator, count)
1612 {
1613 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
1614 
1615 	if (zend_parse_parameters_none() == FAILURE) {
1616 		RETURN_THROWS();
1617 	}
1618 
1619 	if (intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
1620 		RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL));
1621 	} else {
1622 		/* should not happen */
1623 		// TODO ZEND_ASSERT ?
1624 		php_error_docref(NULL, E_ERROR, "GlobIterator lost glob state");
1625 	}
1626 }
1627 /* }}} */
1628 #endif /* HAVE_GLOB */
1629 
1630 /* {{{ forward declarations to the iterator handlers */
1631 static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter);
1632 static zend_result spl_filesystem_dir_it_valid(zend_object_iterator *iter);
1633 static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter);
1634 static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key);
1635 static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter);
1636 static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter);
1637 
1638 /* iterator handler table */
1639 static const zend_object_iterator_funcs spl_filesystem_dir_it_funcs = {
1640 	spl_filesystem_dir_it_dtor,
1641 	spl_filesystem_dir_it_valid,
1642 	spl_filesystem_dir_it_current_data,
1643 	spl_filesystem_dir_it_current_key,
1644 	spl_filesystem_dir_it_move_forward,
1645 	spl_filesystem_dir_it_rewind,
1646 	NULL,
1647 	NULL, /* get_gc */
1648 };
1649 /* }}} */
1650 
1651 /* {{{ spl_ce_dir_get_iterator */
spl_filesystem_dir_get_iterator(zend_class_entry * ce,zval * object,int by_ref)1652 static zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
1653 {
1654 	spl_filesystem_iterator *iterator;
1655 	spl_filesystem_object *dir_object;
1656 
1657 	if (by_ref) {
1658 		zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
1659 		return NULL;
1660 	}
1661 	dir_object = spl_filesystem_from_obj(Z_OBJ_P(object));
1662 	iterator = spl_filesystem_object_to_iterator(dir_object);
1663 	ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
1664 	iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
1665 	/* ->current must be initialized; rewind doesn't set it and valid
1666 	 * doesn't check whether it's set */
1667 	iterator->current = *object;
1668 
1669 	return &iterator->intern;
1670 }
1671 /* }}} */
1672 
1673 /* {{{ spl_filesystem_dir_it_dtor */
spl_filesystem_dir_it_dtor(zend_object_iterator * iter)1674 static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter)
1675 {
1676 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1677 	zval_ptr_dtor(&iterator->intern.data);
1678 }
1679 /* }}} */
1680 
1681 /* {{{ spl_filesystem_dir_it_valid */
spl_filesystem_dir_it_valid(zend_object_iterator * iter)1682 static zend_result spl_filesystem_dir_it_valid(zend_object_iterator *iter)
1683 {
1684 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1685 
1686 	return object->u.dir.entry.d_name[0] != '\0' ? SUCCESS : FAILURE;
1687 }
1688 /* }}} */
1689 
1690 /* {{{ spl_filesystem_dir_it_current_data */
spl_filesystem_dir_it_current_data(zend_object_iterator * iter)1691 static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter)
1692 {
1693 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1694 
1695 	return &iterator->current;
1696 }
1697 /* }}} */
1698 
1699 /* {{{ spl_filesystem_dir_it_current_key */
spl_filesystem_dir_it_current_key(zend_object_iterator * iter,zval * key)1700 static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key)
1701 {
1702 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1703 
1704 	ZVAL_LONG(key, object->u.dir.index);
1705 }
1706 /* }}} */
1707 
1708 /* {{{ spl_filesystem_dir_it_move_forward */
spl_filesystem_dir_it_move_forward(zend_object_iterator * iter)1709 static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter)
1710 {
1711 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1712 
1713 	object->u.dir.index++;
1714 	spl_filesystem_dir_read(object);
1715 	if (object->file_name) {
1716 		zend_string_release(object->file_name);
1717 		object->file_name = NULL;
1718 	}
1719 }
1720 /* }}} */
1721 
1722 /* {{{ spl_filesystem_dir_it_rewind */
spl_filesystem_dir_it_rewind(zend_object_iterator * iter)1723 static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter)
1724 {
1725 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1726 
1727 	object->u.dir.index = 0;
1728 	if (object->u.dir.dirp) {
1729 		php_stream_rewinddir(object->u.dir.dirp);
1730 	}
1731 	spl_filesystem_dir_read(object);
1732 }
1733 /* }}} */
1734 
1735 /* {{{ spl_filesystem_tree_it_dtor */
spl_filesystem_tree_it_dtor(zend_object_iterator * iter)1736 static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter)
1737 {
1738 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1739 	zval_ptr_dtor(&iterator->intern.data);
1740 	zval_ptr_dtor(&iterator->current);
1741 }
1742 /* }}} */
1743 
1744 /* {{{ spl_filesystem_tree_it_current_data */
spl_filesystem_tree_it_current_data(zend_object_iterator * iter)1745 static zval *spl_filesystem_tree_it_current_data(zend_object_iterator *iter)
1746 {
1747 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1748 	spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
1749 
1750 	if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
1751 		if (Z_ISUNDEF(iterator->current)) {
1752 			if (spl_filesystem_object_get_file_name(object) == FAILURE) {
1753 				return NULL;
1754 			}
1755 			ZVAL_STR_COPY(&iterator->current, object->file_name);
1756 		}
1757 		return &iterator->current;
1758 	} else if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
1759 		if (Z_ISUNDEF(iterator->current)) {
1760 			if (spl_filesystem_object_get_file_name(object) == FAILURE) {
1761 				return NULL;
1762 			}
1763 			spl_filesystem_object_create_type(0, object, SPL_FS_INFO, NULL, &iterator->current);
1764 		}
1765 		return &iterator->current;
1766 	} else {
1767 		return &iterator->intern.data;
1768 	}
1769 }
1770 /* }}} */
1771 
1772 /* {{{ spl_filesystem_tree_it_current_key */
spl_filesystem_tree_it_current_key(zend_object_iterator * iter,zval * key)1773 static void spl_filesystem_tree_it_current_key(zend_object_iterator *iter, zval *key)
1774 {
1775 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1776 
1777 	if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) {
1778 		ZVAL_STRING(key, object->u.dir.entry.d_name);
1779 	} else {
1780 		if (spl_filesystem_object_get_file_name(object) == FAILURE) {
1781 			return;
1782 		}
1783 		ZVAL_STR_COPY(key, object->file_name);
1784 	}
1785 }
1786 /* }}} */
1787 
1788 /* {{{ spl_filesystem_tree_it_move_forward */
spl_filesystem_tree_it_move_forward(zend_object_iterator * iter)1789 static void spl_filesystem_tree_it_move_forward(zend_object_iterator *iter)
1790 {
1791 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1792 	spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
1793 	bool skip_dots = SPL_HAS_FLAG(object->flags, SPL_FILE_DIR_SKIPDOTS);
1794 
1795 	object->u.dir.index++;
1796 	do {
1797 		spl_filesystem_dir_read(object);
1798 	} while (skip_dots && spl_filesystem_is_dot(object->u.dir.entry.d_name));
1799 	if (object->file_name) {
1800 		zend_string_release(object->file_name);
1801 		object->file_name = NULL;
1802 	}
1803 	if (!Z_ISUNDEF(iterator->current)) {
1804 		zval_ptr_dtor(&iterator->current);
1805 		ZVAL_UNDEF(&iterator->current);
1806 	}
1807 }
1808 /* }}} */
1809 
1810 /* {{{ spl_filesystem_tree_it_rewind */
spl_filesystem_tree_it_rewind(zend_object_iterator * iter)1811 static void spl_filesystem_tree_it_rewind(zend_object_iterator *iter)
1812 {
1813 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1814 	spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
1815 	bool skip_dots = SPL_HAS_FLAG(object->flags, SPL_FILE_DIR_SKIPDOTS);
1816 
1817 	object->u.dir.index = 0;
1818 	if (object->u.dir.dirp) {
1819 		php_stream_rewinddir(object->u.dir.dirp);
1820 	}
1821 	do {
1822 		spl_filesystem_dir_read(object);
1823 	} while (skip_dots && spl_filesystem_is_dot(object->u.dir.entry.d_name));
1824 	if (!Z_ISUNDEF(iterator->current)) {
1825 		zval_ptr_dtor(&iterator->current);
1826 		ZVAL_UNDEF(&iterator->current);
1827 	}
1828 }
1829 /* }}} */
1830 
1831 /* {{{ iterator handler table */
1832 static const zend_object_iterator_funcs spl_filesystem_tree_it_funcs = {
1833 	spl_filesystem_tree_it_dtor,
1834 	spl_filesystem_dir_it_valid,
1835 	spl_filesystem_tree_it_current_data,
1836 	spl_filesystem_tree_it_current_key,
1837 	spl_filesystem_tree_it_move_forward,
1838 	spl_filesystem_tree_it_rewind,
1839 	NULL,
1840 	NULL, /* get_gc */
1841 };
1842 /* }}} */
1843 
1844 /* {{{ spl_ce_dir_get_iterator */
spl_filesystem_tree_get_iterator(zend_class_entry * ce,zval * object,int by_ref)1845 static zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
1846 {
1847 	spl_filesystem_iterator *iterator;
1848 	spl_filesystem_object *dir_object;
1849 
1850 	if (by_ref) {
1851 		zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
1852 		return NULL;
1853 	}
1854 	dir_object = spl_filesystem_from_obj(Z_OBJ_P(object));
1855 	iterator = spl_filesystem_object_to_iterator(dir_object);
1856 
1857 	ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
1858 	iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
1859 
1860 	return &iterator->intern;
1861 }
1862 /* }}} */
1863 
spl_filesystem_file_cannot_read(spl_filesystem_object * intern)1864 static ZEND_COLD void spl_filesystem_file_cannot_read(spl_filesystem_object *intern)
1865 {
1866 	zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", ZSTR_VAL(intern->file_name));
1867 }
1868 
spl_filesystem_file_read_ex(spl_filesystem_object * intern,bool silent,zend_long line_add,bool csv)1869 static zend_result spl_filesystem_file_read_ex(spl_filesystem_object *intern, bool silent, zend_long line_add, bool csv)
1870 {
1871 	char *buf;
1872 	size_t line_len = 0;
1873 
1874 	spl_filesystem_file_free_line(intern);
1875 
1876 	if (php_stream_eof(intern->u.file.stream)) {
1877 		if (!silent) {
1878 			spl_filesystem_file_cannot_read(intern);
1879 		}
1880 		return FAILURE;
1881 	}
1882 
1883 	if (intern->u.file.max_line_len > 0) {
1884 		buf = safe_emalloc((intern->u.file.max_line_len + 1), sizeof(char), 0);
1885 		if (php_stream_get_line(intern->u.file.stream, buf, intern->u.file.max_line_len + 1, &line_len) == NULL) {
1886 			efree(buf);
1887 			buf = NULL;
1888 		} else {
1889 			buf[line_len] = '\0';
1890 		}
1891 	} else {
1892 		buf = php_stream_get_line(intern->u.file.stream, NULL, 0, &line_len);
1893 	}
1894 
1895 	if (!buf) {
1896 		intern->u.file.current_line = estrdup("");
1897 		intern->u.file.current_line_len = 0;
1898 	} else {
1899 		if (!csv && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) {
1900 			if (line_len > 0 && buf[line_len - 1] == '\n') {
1901 				line_len--;
1902 				if (line_len > 0 && buf[line_len - 1] == '\r') {
1903 					line_len--;
1904 				}
1905 				buf[line_len] = '\0';
1906 			}
1907 		}
1908 
1909 		intern->u.file.current_line = buf;
1910 		intern->u.file.current_line_len = line_len;
1911 	}
1912 	intern->u.file.current_line_num += line_add;
1913 
1914 	return SUCCESS;
1915 } /* }}} */
1916 
spl_filesystem_file_read(spl_filesystem_object * intern,bool silent,bool csv)1917 static inline zend_result spl_filesystem_file_read(spl_filesystem_object *intern, bool silent, bool csv)
1918 {
1919 	zend_long line_add = (intern->u.file.current_line) ? 1 : 0;
1920 	return spl_filesystem_file_read_ex(intern, silent, line_add, csv);
1921 }
1922 
is_line_empty(spl_filesystem_object * intern)1923 static bool is_line_empty(spl_filesystem_object *intern)
1924 {
1925 	char *current_line = intern->u.file.current_line;
1926 	size_t current_line_len = intern->u.file.current_line_len;
1927 	return current_line_len == 0
1928 		|| ((SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)
1929 			&& ((current_line_len == 1 && current_line[0] == '\n')
1930 				|| (current_line_len == 2 && current_line[0] == '\r' && current_line[1] == '\n'))));
1931 }
1932 
spl_filesystem_file_read_csv(spl_filesystem_object * intern,char delimiter,char enclosure,int escape,zval * return_value,bool silent)1933 static zend_result spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, int escape, zval *return_value, bool silent) /* {{{ */
1934 {
1935 	do {
1936 		zend_result ret = spl_filesystem_file_read(intern, silent, /* csv */ true);
1937 		if (ret != SUCCESS) {
1938 			return ret;
1939 		}
1940 	} while (is_line_empty(intern) && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY));
1941 
1942 	size_t buf_len = intern->u.file.current_line_len;
1943 	char *buf = estrndup(intern->u.file.current_line, buf_len);
1944 
1945 	if (!Z_ISUNDEF(intern->u.file.current_zval)) {
1946 		zval_ptr_dtor(&intern->u.file.current_zval);
1947 		ZVAL_UNDEF(&intern->u.file.current_zval);
1948 	}
1949 
1950 	HashTable *values = php_fgetcsv(intern->u.file.stream, delimiter, enclosure, escape, buf_len, buf);
1951 	if (values == NULL) {
1952 		values = php_bc_fgetcsv_empty_line();
1953 	}
1954 	ZVAL_ARR(&intern->u.file.current_zval, values);
1955 	if (return_value) {
1956 		ZVAL_COPY(return_value, &intern->u.file.current_zval);
1957 	}
1958 	return SUCCESS;
1959 }
1960 /* }}} */
1961 
spl_filesystem_file_read_line_ex(zval * this_ptr,spl_filesystem_object * intern,bool silent)1962 static zend_result spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, bool silent) /* {{{ */
1963 {
1964 	zval retval;
1965 
1966 	/* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
1967 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) {
1968 		return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL, silent);
1969 	}
1970 	if (intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
1971 		spl_filesystem_file_free_line(intern);
1972 
1973 		if (php_stream_eof(intern->u.file.stream)) {
1974 			if (!silent) {
1975 				spl_filesystem_file_cannot_read(intern);
1976 			}
1977 			return FAILURE;
1978 		}
1979 		zend_call_method_with_0_params(Z_OBJ_P(this_ptr), Z_OBJCE_P(this_ptr), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
1980 		if (Z_ISUNDEF(retval)) {
1981 			return FAILURE;
1982 		}
1983 
1984 		if (Z_TYPE(retval) != IS_STRING) {
1985 			zend_type_error("%s::getCurrentLine(): Return value must be of type string, %s returned",
1986 				ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), zend_zval_value_name(&retval));
1987 			zval_ptr_dtor(&retval);
1988 			return FAILURE;
1989 		}
1990 
1991 		if (intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval)) {
1992 			intern->u.file.current_line_num++;
1993 		}
1994 		spl_filesystem_file_free_line(intern);
1995 		intern->u.file.current_line = estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
1996 		intern->u.file.current_line_len = Z_STRLEN(retval);
1997 		zval_ptr_dtor(&retval);
1998 		return SUCCESS;
1999 	} else {
2000 		return spl_filesystem_file_read(intern, silent, /* csv */ false);
2001 	}
2002 } /* }}} */
2003 
spl_filesystem_file_read_line(zval * this_ptr,spl_filesystem_object * intern,bool silent)2004 static zend_result spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, bool silent) /* {{{ */
2005 {
2006 	zend_result ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent);
2007 
2008 	while (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && is_line_empty(intern)) {
2009 		spl_filesystem_file_free_line(intern);
2010 		ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent);
2011 	}
2012 
2013 	return ret;
2014 }
2015 /* }}} */
2016 
spl_filesystem_file_rewind(zval * this_ptr,spl_filesystem_object * intern)2017 static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern) /* {{{ */
2018 {
2019 	if (!intern->u.file.stream) {
2020 		zend_throw_error(NULL, "Object not initialized");
2021 		return;
2022 	}
2023 	if (-1 == php_stream_rewind(intern->u.file.stream)) {
2024 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot rewind file %s", ZSTR_VAL(intern->file_name));
2025 		return;
2026 	}
2027 
2028 	spl_filesystem_file_free_line(intern);
2029 	intern->u.file.current_line_num = 0;
2030 
2031 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2032 		spl_filesystem_file_read_line(this_ptr, intern, true);
2033 	}
2034 } /* }}} */
2035 
2036 /* {{{ Construct a new file object */
PHP_METHOD(SplFileObject,__construct)2037 PHP_METHOD(SplFileObject, __construct)
2038 {
2039 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2040 	zend_string *open_mode = ZSTR_CHAR('r');
2041 	bool use_include_path = 0;
2042 	size_t path_len;
2043 	zend_error_handling error_handling;
2044 
2045 	intern->u.file.open_mode = ZSTR_CHAR('r');
2046 
2047 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|Sbr!",
2048 			&intern->file_name, &open_mode,
2049 			&use_include_path, &intern->u.file.zcontext) == FAILURE) {
2050 		intern->u.file.open_mode = NULL;
2051 		intern->file_name = NULL;
2052 		RETURN_THROWS();
2053 	}
2054 
2055 	intern->u.file.open_mode = zend_string_copy(open_mode);
2056 
2057 	/* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */
2058 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
2059 	zend_result retval = spl_filesystem_file_open(intern, use_include_path);
2060 	zend_restore_error_handling(&error_handling);
2061 	if (retval == FAILURE) {
2062 		RETURN_THROWS();
2063 	}
2064 
2065 	path_len = strlen(intern->u.file.stream->orig_path);
2066 
2067 	if (path_len > 1 && IS_SLASH_AT(intern->u.file.stream->orig_path, path_len-1)) {
2068 		path_len--;
2069 	}
2070 
2071 	while (path_len > 1 && !IS_SLASH_AT(intern->u.file.stream->orig_path, path_len-1)) {
2072 		path_len--;
2073 	}
2074 
2075 	if (path_len) {
2076 		path_len--;
2077 	}
2078 
2079 	intern->path = zend_string_init(intern->u.file.stream->orig_path, path_len, 0);
2080 } /* }}} */
2081 
2082 /* {{{ Construct a new temp file object */
PHP_METHOD(SplTempFileObject,__construct)2083 PHP_METHOD(SplTempFileObject, __construct)
2084 {
2085 	zend_string *file_name;
2086 	zend_long max_memory = PHP_STREAM_MAX_MEM;
2087 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2088 	zend_error_handling error_handling;
2089 
2090 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &max_memory) == FAILURE) {
2091 		RETURN_THROWS();
2092 	}
2093 
2094 	if (max_memory < 0) {
2095 		file_name = ZSTR_INIT_LITERAL("php://memory", 0);
2096 	} else if (ZEND_NUM_ARGS()) {
2097 		file_name = zend_strpprintf(0, "php://temp/maxmemory:" ZEND_LONG_FMT, max_memory);
2098 	} else {
2099 		file_name = ZSTR_INIT_LITERAL("php://temp", 0);
2100 	}
2101 	intern->file_name = file_name;
2102 	intern->u.file.open_mode = ZSTR_INIT_LITERAL("wb", 0);
2103 
2104 	/* spl_filesystem_file_open() can generate E_WARNINGs which we want to promote to exceptions */
2105 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
2106 	if (spl_filesystem_file_open(intern, /* use_include_path */ false) == SUCCESS) {
2107 		intern->path = ZSTR_EMPTY_ALLOC();
2108 	}
2109 	zend_string_release(file_name);
2110 	zend_restore_error_handling(&error_handling);
2111 } /* }}} */
2112 
2113 /* {{{ Rewind the file and read the first line */
PHP_METHOD(SplFileObject,rewind)2114 PHP_METHOD(SplFileObject, rewind)
2115 {
2116 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2117 
2118 	if (zend_parse_parameters_none() == FAILURE) {
2119 		RETURN_THROWS();
2120 	}
2121 
2122 	spl_filesystem_file_rewind(ZEND_THIS, intern);
2123 } /* }}} */
2124 
2125 /* {{{ Return whether end of file is reached */
PHP_METHOD(SplFileObject,eof)2126 PHP_METHOD(SplFileObject, eof)
2127 {
2128 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2129 
2130 	if (zend_parse_parameters_none() == FAILURE) {
2131 		RETURN_THROWS();
2132 	}
2133 
2134 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2135 
2136 	RETURN_BOOL(php_stream_eof(intern->u.file.stream));
2137 } /* }}} */
2138 
2139 /* {{{ Return !eof() */
PHP_METHOD(SplFileObject,valid)2140 PHP_METHOD(SplFileObject, valid)
2141 {
2142 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2143 
2144 	if (zend_parse_parameters_none() == FAILURE) {
2145 		RETURN_THROWS();
2146 	}
2147 
2148 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2149 		RETURN_BOOL(intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval));
2150 	}
2151 	if (!intern->u.file.stream) {
2152 		RETURN_FALSE;
2153 	}
2154 	RETURN_BOOL(!php_stream_eof(intern->u.file.stream));
2155 } /* }}} */
2156 
2157 /* {{{ Return next line from file */
PHP_METHOD(SplFileObject,fgets)2158 PHP_METHOD(SplFileObject, fgets)
2159 {
2160 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2161 
2162 	if (zend_parse_parameters_none() == FAILURE) {
2163 		RETURN_THROWS();
2164 	}
2165 
2166 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2167 
2168 	if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1, /* csv */ false) == FAILURE) {
2169 		RETURN_THROWS();
2170 	}
2171 	RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len);
2172 } /* }}} */
2173 
2174 /* {{{ Return current line from file */
PHP_METHOD(SplFileObject,current)2175 PHP_METHOD(SplFileObject, current)
2176 {
2177 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2178 
2179 	if (zend_parse_parameters_none() == FAILURE) {
2180 		RETURN_THROWS();
2181 	}
2182 
2183 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2184 
2185 	if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) {
2186 		spl_filesystem_file_read_line(ZEND_THIS, intern, true);
2187 	}
2188 	if (intern->u.file.current_line && (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || Z_ISUNDEF(intern->u.file.current_zval))) {
2189 		RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len);
2190 	} else if (!Z_ISUNDEF(intern->u.file.current_zval)) {
2191 		ZEND_ASSERT(!Z_ISREF(intern->u.file.current_zval));
2192 		ZEND_ASSERT(Z_TYPE(intern->u.file.current_zval) == IS_ARRAY);
2193 		RETURN_COPY(&intern->u.file.current_zval);
2194 	}
2195 	RETURN_FALSE;
2196 } /* }}} */
2197 
2198 /* {{{ Return line number */
PHP_METHOD(SplFileObject,key)2199 PHP_METHOD(SplFileObject, key)
2200 {
2201 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2202 
2203 	if (zend_parse_parameters_none() == FAILURE) {
2204 		RETURN_THROWS();
2205 	}
2206 
2207 	/* Do not read the next line to support correct counting with fgetc()
2208 	if (!intern->u.file.current_line) {
2209 		spl_filesystem_file_read_line(ZEND_THIS, intern);
2210 	} */
2211 	RETURN_LONG(intern->u.file.current_line_num);
2212 } /* }}} */
2213 
2214 /* {{{ Read next line */
PHP_METHOD(SplFileObject,next)2215 PHP_METHOD(SplFileObject, next)
2216 {
2217 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2218 
2219 	if (zend_parse_parameters_none() == FAILURE) {
2220 		RETURN_THROWS();
2221 	}
2222 
2223 	spl_filesystem_file_free_line(intern);
2224 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2225 		spl_filesystem_file_read_line(ZEND_THIS, intern, true);
2226 	}
2227 	intern->u.file.current_line_num++;
2228 } /* }}} */
2229 
2230 /* {{{ Set file handling flags */
PHP_METHOD(SplFileObject,setFlags)2231 PHP_METHOD(SplFileObject, setFlags)
2232 {
2233 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2234 
2235 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &intern->flags) == FAILURE) {
2236 		RETURN_THROWS();
2237 	}
2238 } /* }}} */
2239 
2240 /* {{{ Get file handling flags */
PHP_METHOD(SplFileObject,getFlags)2241 PHP_METHOD(SplFileObject, getFlags)
2242 {
2243 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2244 
2245 	if (zend_parse_parameters_none() == FAILURE) {
2246 		RETURN_THROWS();
2247 	}
2248 
2249 	RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK);
2250 } /* }}} */
2251 
2252 /* {{{ Set maximum line length */
PHP_METHOD(SplFileObject,setMaxLineLen)2253 PHP_METHOD(SplFileObject, setMaxLineLen)
2254 {
2255 	zend_long max_len;
2256 
2257 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2258 
2259 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &max_len) == FAILURE) {
2260 		RETURN_THROWS();
2261 	}
2262 
2263 	if (max_len < 0) {
2264 		zend_argument_value_error(1, "must be greater than or equal to 0");
2265 		RETURN_THROWS();
2266 	}
2267 
2268 	intern->u.file.max_line_len = max_len;
2269 } /* }}} */
2270 
2271 /* {{{ Get maximum line length */
PHP_METHOD(SplFileObject,getMaxLineLen)2272 PHP_METHOD(SplFileObject, getMaxLineLen)
2273 {
2274 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2275 
2276 	if (zend_parse_parameters_none() == FAILURE) {
2277 		RETURN_THROWS();
2278 	}
2279 
2280 	RETURN_LONG((zend_long)intern->u.file.max_line_len);
2281 } /* }}} */
2282 
2283 /* {{{ Return false */
PHP_METHOD(SplFileObject,hasChildren)2284 PHP_METHOD(SplFileObject, hasChildren)
2285 {
2286 	if (zend_parse_parameters_none() == FAILURE) {
2287 		RETURN_THROWS();
2288 	}
2289 
2290 	RETURN_FALSE;
2291 } /* }}} */
2292 
2293 /* {{{ Read NULL */
PHP_METHOD(SplFileObject,getChildren)2294 PHP_METHOD(SplFileObject, getChildren)
2295 {
2296 	if (zend_parse_parameters_none() == FAILURE) {
2297 		RETURN_THROWS();
2298 	}
2299 	/* return NULL */
2300 } /* }}} */
2301 
2302 /* {{{ Return current line as CSV */
PHP_METHOD(SplFileObject,fgetcsv)2303 PHP_METHOD(SplFileObject, fgetcsv)
2304 {
2305 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2306 	char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
2307 	int escape = intern->u.file.escape;
2308 	char *delim = NULL, *enclo = NULL, *esc = NULL;
2309 	size_t d_len = 0, e_len = 0, esc_len = 0;
2310 
2311 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == FAILURE) {
2312 		RETURN_THROWS();
2313 	}
2314 
2315 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2316 
2317 	if (delim) {
2318 		if (d_len != 1) {
2319 			zend_argument_value_error(1, "must be a single character");
2320 			RETURN_THROWS();
2321 		}
2322 		delimiter = delim[0];
2323 	}
2324 	if (enclo) {
2325 		if (e_len != 1) {
2326 			zend_argument_value_error(2, "must be a single character");
2327 			RETURN_THROWS();
2328 		}
2329 		enclosure = enclo[0];
2330 	}
2331 	if (esc) {
2332 		if (esc_len > 1) {
2333 			zend_argument_value_error(3, "must be empty or a single character");
2334 			RETURN_THROWS();
2335 		}
2336 		if (esc_len == 0) {
2337 			escape = PHP_CSV_NO_ESCAPE;
2338 		} else {
2339 			escape = (unsigned char) esc[0];
2340 		}
2341 	}
2342 
2343 	if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value, true) == FAILURE) {
2344 		RETURN_FALSE;
2345 	}
2346 }
2347 /* }}} */
2348 
2349 /* {{{ Output a field array as a CSV line */
PHP_METHOD(SplFileObject,fputcsv)2350 PHP_METHOD(SplFileObject, fputcsv)
2351 {
2352 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2353 	char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure;
2354 	int escape = intern->u.file.escape;
2355 	char *delim = NULL, *enclo = NULL, *esc = NULL;
2356 	size_t d_len = 0, e_len = 0, esc_len = 0;
2357 	zend_long ret;
2358 	zval *fields = NULL;
2359 	zend_string *eol = NULL;
2360 
2361 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|sssS", &fields, &delim, &d_len, &enclo, &e_len, &esc, &esc_len, &eol) == FAILURE) {
2362 		RETURN_THROWS();
2363 	}
2364 
2365 	if (delim) {
2366 		if (d_len != 1) {
2367 			zend_argument_value_error(2, "must be a single character");
2368 			RETURN_THROWS();
2369 		}
2370 		delimiter = delim[0];
2371 	}
2372 	if (enclo) {
2373 		if (e_len != 1) {
2374 			zend_argument_value_error(3, "must be a single character");
2375 			RETURN_THROWS();
2376 		}
2377 		enclosure = enclo[0];
2378 	}
2379 	if (esc) {
2380 		if (esc_len > 1) {
2381 			zend_argument_value_error(4, "must be empty or a single character");
2382 			RETURN_THROWS();
2383 		}
2384 		if (esc_len == 0) {
2385 			escape = PHP_CSV_NO_ESCAPE;
2386 		} else {
2387 			escape = (unsigned char) esc[0];
2388 		}
2389 	}
2390 
2391 	ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape, eol);
2392 	if (ret < 0) {
2393 		RETURN_FALSE;
2394 	}
2395 	RETURN_LONG(ret);
2396 }
2397 /* }}} */
2398 
2399 /* {{{ Set the delimiter, enclosure and escape character used in fgetcsv */
PHP_METHOD(SplFileObject,setCsvControl)2400 PHP_METHOD(SplFileObject, setCsvControl)
2401 {
2402 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2403 	char delimiter = ',', enclosure = '"';
2404 	int escape = (unsigned char) '\\';
2405 	char *delim = NULL, *enclo = NULL, *esc = NULL;
2406 	size_t d_len = 0, e_len = 0, esc_len = 0;
2407 
2408 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == FAILURE) {
2409 		RETURN_THROWS();
2410 	}
2411 
2412 	if (delim) {
2413 		if (d_len != 1) {
2414 			zend_argument_value_error(1, "must be a single character");
2415 			RETURN_THROWS();
2416 		}
2417 		delimiter = delim[0];
2418 	}
2419 	if (enclo) {
2420 		if (e_len != 1) {
2421 			zend_argument_value_error(2, "must be a single character");
2422 			RETURN_THROWS();
2423 		}
2424 		enclosure = enclo[0];
2425 	}
2426 	if (esc) {
2427 		if (esc_len > 1) {
2428 			zend_argument_value_error(3, "must be empty or a single character");
2429 			RETURN_THROWS();
2430 		}
2431 		if (esc_len == 0) {
2432 			escape = PHP_CSV_NO_ESCAPE;
2433 		} else {
2434 			escape = (unsigned char) esc[0];
2435 		}
2436 	}
2437 
2438 	intern->u.file.delimiter = delimiter;
2439 	intern->u.file.enclosure = enclosure;
2440 	intern->u.file.escape    = escape;
2441 }
2442 /* }}} */
2443 
2444 /* {{{ Get the delimiter, enclosure and escape character used in fgetcsv */
PHP_METHOD(SplFileObject,getCsvControl)2445 PHP_METHOD(SplFileObject, getCsvControl)
2446 {
2447 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2448 	char delimiter[2], enclosure[2], escape[2];
2449 
2450 	if (zend_parse_parameters_none() == FAILURE) {
2451 		RETURN_THROWS();
2452 	}
2453 
2454 	array_init(return_value);
2455 
2456 	delimiter[0] = intern->u.file.delimiter;
2457 	delimiter[1] = '\0';
2458 	enclosure[0] = intern->u.file.enclosure;
2459 	enclosure[1] = '\0';
2460 	if (intern->u.file.escape == PHP_CSV_NO_ESCAPE) {
2461 		escape[0] = '\0';
2462 	} else {
2463 		escape[0] = (unsigned char) intern->u.file.escape;
2464 		escape[1] = '\0';
2465 	}
2466 
2467 	add_next_index_string(return_value, delimiter);
2468 	add_next_index_string(return_value, enclosure);
2469 	add_next_index_string(return_value, escape);
2470 }
2471 /* }}} */
2472 
2473 /* {{{ Portable file locking */
PHP_METHOD(SplFileObject,flock)2474 PHP_METHOD(SplFileObject, flock)
2475 {
2476 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2477 	zval *wouldblock = NULL;
2478 	zend_long operation = 0;
2479 
2480 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z", &operation, &wouldblock) == FAILURE) {
2481 		RETURN_THROWS();
2482 	}
2483 
2484 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2485 
2486 	php_flock_common(intern->u.file.stream, operation, 1, wouldblock, return_value);
2487 }
2488 /* }}} */
2489 
2490 /* {{{ Flush the file */
PHP_METHOD(SplFileObject,fflush)2491 PHP_METHOD(SplFileObject, fflush)
2492 {
2493 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2494 
2495 	if (zend_parse_parameters_none() == FAILURE) {
2496 		RETURN_THROWS();
2497 	}
2498 
2499 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2500 
2501 	RETURN_BOOL(!php_stream_flush(intern->u.file.stream));
2502 } /* }}} */
2503 
2504 /* {{{ Return current file position */
PHP_METHOD(SplFileObject,ftell)2505 PHP_METHOD(SplFileObject, ftell)
2506 {
2507 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2508 	zend_long ret;
2509 
2510 	if (zend_parse_parameters_none() == FAILURE) {
2511 		RETURN_THROWS();
2512 	}
2513 
2514 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2515 
2516 	ret = php_stream_tell(intern->u.file.stream);
2517 
2518 	if (ret == -1) {
2519 		RETURN_FALSE;
2520 	} else {
2521 		RETURN_LONG(ret);
2522 	}
2523 } /* }}} */
2524 
2525 /* {{{ Seek to a position */
PHP_METHOD(SplFileObject,fseek)2526 PHP_METHOD(SplFileObject, fseek)
2527 {
2528 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2529 	zend_long pos, whence = SEEK_SET;
2530 
2531 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &pos, &whence) == FAILURE) {
2532 		RETURN_THROWS();
2533 	}
2534 
2535 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2536 
2537 	spl_filesystem_file_free_line(intern);
2538 	RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, (int)whence));
2539 } /* }}} */
2540 
2541 /* {{{ Get a character from the file */
PHP_METHOD(SplFileObject,fgetc)2542 PHP_METHOD(SplFileObject, fgetc)
2543 {
2544 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2545 	char buf[2];
2546 	int result;
2547 
2548 	if (zend_parse_parameters_none() == FAILURE) {
2549 		RETURN_THROWS();
2550 	}
2551 
2552 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2553 
2554 	spl_filesystem_file_free_line(intern);
2555 
2556 	result = php_stream_getc(intern->u.file.stream);
2557 
2558 	if (result == EOF) {
2559 		RETURN_FALSE;
2560 	}
2561 	if (result == '\n') {
2562 		intern->u.file.current_line_num++;
2563 	}
2564 	buf[0] = result;
2565 	buf[1] = '\0';
2566 
2567 	RETURN_STRINGL(buf, 1);
2568 } /* }}} */
2569 
2570 /* {{{ Output all remaining data from a file pointer */
PHP_METHOD(SplFileObject,fpassthru)2571 PHP_METHOD(SplFileObject, fpassthru)
2572 {
2573 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2574 
2575 	if (zend_parse_parameters_none() == FAILURE) {
2576 		RETURN_THROWS();
2577 	}
2578 
2579 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2580 
2581 	RETURN_LONG(php_stream_passthru(intern->u.file.stream));
2582 } /* }}} */
2583 
2584 /* {{{ Implements a mostly ANSI compatible fscanf() */
PHP_METHOD(SplFileObject,fscanf)2585 PHP_METHOD(SplFileObject, fscanf)
2586 {
2587 	int result, num_varargs = 0;
2588 	zend_string *format_str;
2589 	zval *varargs= NULL;
2590 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2591 
2592 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S*", &format_str, &varargs, &num_varargs) == FAILURE) {
2593 		RETURN_THROWS();
2594 	}
2595 
2596 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2597 
2598 	/* Get next line */
2599 	if (spl_filesystem_file_read(intern, /* silent */ false, /* csv */ false) == FAILURE) {
2600 		RETURN_THROWS();
2601 	}
2602 
2603 	result = php_sscanf_internal(intern->u.file.current_line, ZSTR_VAL(format_str), num_varargs, varargs, 0, return_value);
2604 
2605 	if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
2606 		WRONG_PARAM_COUNT;
2607 	}
2608 }
2609 /* }}} */
2610 
2611 /* {{{ Binary-safe file write */
PHP_METHOD(SplFileObject,fwrite)2612 PHP_METHOD(SplFileObject, fwrite)
2613 {
2614 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2615 	char *str;
2616 	size_t str_len;
2617 	zend_long length = 0;
2618 	ssize_t written;
2619 
2620 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &length) == FAILURE) {
2621 		RETURN_THROWS();
2622 	}
2623 
2624 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2625 
2626 	if (ZEND_NUM_ARGS() > 1) {
2627 		if (length >= 0) {
2628 			str_len = MIN((size_t)length, str_len);
2629 		} else {
2630 			/* Negative length given, nothing to write */
2631 			str_len = 0;
2632 		}
2633 	}
2634 	if (!str_len) {
2635 		RETURN_LONG(0);
2636 	}
2637 
2638 	written = php_stream_write(intern->u.file.stream, str, str_len);
2639 	if (written < 0) {
2640 		RETURN_FALSE;
2641 	}
2642 	RETURN_LONG(written);
2643 } /* }}} */
2644 
PHP_METHOD(SplFileObject,fread)2645 PHP_METHOD(SplFileObject, fread)
2646 {
2647 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2648 	zend_long length = 0;
2649 	zend_string *str;
2650 
2651 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &length) == FAILURE) {
2652 		RETURN_THROWS();
2653 	}
2654 
2655 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2656 
2657 	if (length <= 0) {
2658 		zend_argument_value_error(1, "must be greater than 0");
2659 		RETURN_THROWS();
2660 	}
2661 
2662 	str = php_stream_read_to_str(intern->u.file.stream, length);
2663 	if (!str) {
2664 		RETURN_FALSE;
2665 	}
2666 	RETURN_STR(str);
2667 }
2668 
2669 /* {{{ Stat() on a filehandle */
PHP_METHOD(SplFileObject,fstat)2670 PHP_METHOD(SplFileObject, fstat)
2671 {
2672 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2673 
2674 	if (zend_parse_parameters_none() == FAILURE) {
2675 		RETURN_THROWS();
2676 	}
2677 
2678 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2679 
2680 	php_fstat(intern->u.file.stream, return_value);
2681 }
2682 /* }}} */
2683 
2684 /* {{{ Truncate file to 'size' length */
PHP_METHOD(SplFileObject,ftruncate)2685 PHP_METHOD(SplFileObject, ftruncate)
2686 {
2687 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2688 	zend_long size;
2689 
2690 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &size) == FAILURE) {
2691 		RETURN_THROWS();
2692 	}
2693 
2694 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2695 
2696 	if (!php_stream_truncate_supported(intern->u.file.stream)) {
2697 		zend_throw_exception_ex(spl_ce_LogicException, 0, "Can't truncate file %s", ZSTR_VAL(intern->file_name));
2698 		RETURN_THROWS();
2699 	}
2700 
2701 	RETURN_BOOL(0 == php_stream_truncate_set_size(intern->u.file.stream, size));
2702 } /* }}} */
2703 
2704 /* {{{ Seek to specified line */
PHP_METHOD(SplFileObject,seek)2705 PHP_METHOD(SplFileObject, seek)
2706 {
2707 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2708 	zend_long line_pos, i;
2709 
2710 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &line_pos) == FAILURE) {
2711 		RETURN_THROWS();
2712 	}
2713 
2714 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2715 
2716 	if (line_pos < 0) {
2717 		zend_argument_value_error(1, "must be greater than or equal to 0");
2718 		RETURN_THROWS();
2719 	}
2720 
2721 	spl_filesystem_file_rewind(ZEND_THIS, intern);
2722 
2723 	for (i = 0; i < line_pos; i++) {
2724 		if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) {
2725 			return;
2726 		}
2727 	}
2728 	if (line_pos > 0 && !SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2729 		intern->u.file.current_line_num++;
2730 		spl_filesystem_file_free_line(intern);
2731 	}
2732 } /* }}} */
2733 
PHP_METHOD(SplFileObject,__toString)2734 PHP_METHOD(SplFileObject, __toString)
2735 {
2736 	if (zend_parse_parameters_none() == FAILURE) {
2737 		RETURN_THROWS();
2738 	}
2739 
2740 	spl_filesystem_object *intern = spl_filesystem_from_obj(Z_OBJ_P(ZEND_THIS));
2741 
2742 	CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern);
2743 
2744 	if (!intern->u.file.current_line) {
2745 		ZEND_ASSERT(Z_ISUNDEF(intern->u.file.current_zval));
2746 		zend_result result = spl_filesystem_file_read_line(ZEND_THIS, intern, false);
2747 		if (UNEXPECTED(result != SUCCESS)) {
2748 			RETURN_THROWS();
2749 		}
2750 	}
2751 
2752 	RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len);
2753 }
2754 
2755 /* {{{ PHP_MINIT_FUNCTION(spl_directory) */
PHP_MINIT_FUNCTION(spl_directory)2756 PHP_MINIT_FUNCTION(spl_directory)
2757 {
2758 	spl_ce_SplFileInfo = register_class_SplFileInfo(zend_ce_stringable);
2759 	spl_ce_SplFileInfo->create_object = spl_filesystem_object_new;
2760 	spl_ce_SplFileInfo->default_object_handlers = &spl_filesystem_object_handlers;
2761 
2762 	memcpy(&spl_filesystem_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2763 	spl_filesystem_object_handlers.offset = XtOffsetOf(spl_filesystem_object, std);
2764 	spl_filesystem_object_handlers.clone_obj = spl_filesystem_object_clone;
2765 	spl_filesystem_object_handlers.dtor_obj = spl_filesystem_object_destroy_object;
2766 	spl_filesystem_object_handlers.free_obj = spl_filesystem_object_free_storage;
2767 
2768 	spl_ce_DirectoryIterator = register_class_DirectoryIterator(spl_ce_SplFileInfo, spl_ce_SeekableIterator);
2769 	spl_ce_DirectoryIterator->create_object = spl_filesystem_object_new;
2770 	spl_ce_DirectoryIterator->get_iterator = spl_filesystem_dir_get_iterator;
2771 
2772 	spl_ce_FilesystemIterator = register_class_FilesystemIterator(spl_ce_DirectoryIterator);
2773 	spl_ce_FilesystemIterator->create_object = spl_filesystem_object_new;
2774 	spl_ce_FilesystemIterator->get_iterator = spl_filesystem_tree_get_iterator;
2775 
2776 	spl_ce_RecursiveDirectoryIterator = register_class_RecursiveDirectoryIterator(spl_ce_FilesystemIterator, spl_ce_RecursiveIterator);
2777 	spl_ce_RecursiveDirectoryIterator->create_object = spl_filesystem_object_new;
2778 
2779 	memcpy(&spl_filesystem_object_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers));
2780 	spl_filesystem_object_check_handlers.clone_obj = NULL;
2781 	spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check;
2782 
2783 #ifdef HAVE_GLOB
2784 	spl_ce_GlobIterator = register_class_GlobIterator(spl_ce_FilesystemIterator, zend_ce_countable);
2785 	spl_ce_GlobIterator->create_object = spl_filesystem_object_new;
2786 	spl_ce_GlobIterator->default_object_handlers = &spl_filesystem_object_check_handlers;
2787 #endif
2788 
2789 	spl_ce_SplFileObject = register_class_SplFileObject(spl_ce_SplFileInfo, spl_ce_RecursiveIterator, spl_ce_SeekableIterator);
2790 	spl_ce_SplFileObject->default_object_handlers = &spl_filesystem_object_check_handlers;
2791 	spl_ce_SplFileObject->create_object = spl_filesystem_object_new;
2792 
2793 	spl_ce_SplTempFileObject = register_class_SplTempFileObject(spl_ce_SplFileObject);
2794 	spl_ce_SplTempFileObject->create_object = spl_filesystem_object_new;
2795 
2796 	return SUCCESS;
2797 }
2798 /* }}} */
2799