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