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