xref: /PHP-7.3/ext/spl/spl_directory.c (revision 32f377b0)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Marcus Boerger <helly@php.net>                               |
16    +----------------------------------------------------------------------+
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 
23 #include "php.h"
24 #include "php_ini.h"
25 #include "ext/standard/info.h"
26 #include "ext/standard/file.h"
27 #include "ext/standard/php_string.h"
28 #include "zend_compile.h"
29 #include "zend_exceptions.h"
30 #include "zend_interfaces.h"
31 
32 #include "php_spl.h"
33 #include "spl_functions.h"
34 #include "spl_engine.h"
35 #include "spl_iterators.h"
36 #include "spl_directory.h"
37 #include "spl_exceptions.h"
38 
39 #include "php.h"
40 #include "fopen_wrappers.h"
41 
42 #include "ext/standard/basic_functions.h"
43 #include "ext/standard/php_filestat.h"
44 
45 #define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0)
46 
47 /* declare the class handlers */
48 static zend_object_handlers spl_filesystem_object_handlers;
49 /* includes handler to validate object state when retrieving methods */
50 static zend_object_handlers spl_filesystem_object_check_handlers;
51 
52 /* decalre the class entry */
53 PHPAPI zend_class_entry *spl_ce_SplFileInfo;
54 PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
55 PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
56 PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
57 PHPAPI zend_class_entry *spl_ce_GlobIterator;
58 PHPAPI zend_class_entry *spl_ce_SplFileObject;
59 PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
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, 0, 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 void 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 				php_error_docref(NULL, E_ERROR, "Object not initialized");
212 			}
213 			break;
214 		case SPL_FS_DIR:
215 			{
216 				size_t path_len = 0;
217 				char *path = spl_filesystem_object_get_path(intern, &path_len);
218 				if (intern->file_name) {
219 					efree(intern->file_name);
220 				}
221 				/* if there is parent path, ammend it, otherwise just use the given path as is */
222 				if (path_len == 0) {
223 					intern->file_name_len = spprintf(
224 						&intern->file_name, 0, "%s", intern->u.dir.entry.d_name);
225 				} else {
226 					intern->file_name_len = spprintf(
227 						&intern->file_name, 0, "%s%c%s", path, slash, intern->u.dir.entry.d_name);
228 				}
229 			}
230 			break;
231 	}
232 } /* }}} */
233 
spl_filesystem_dir_read(spl_filesystem_object * intern)234 static int spl_filesystem_dir_read(spl_filesystem_object *intern) /* {{{ */
235 {
236 	if (!intern->u.dir.dirp || !php_stream_readdir(intern->u.dir.dirp, &intern->u.dir.entry)) {
237 		intern->u.dir.entry.d_name[0] = '\0';
238 		return 0;
239 	} else {
240 		return 1;
241 	}
242 }
243 /* }}} */
244 
245 #define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos]))
246 
spl_filesystem_is_dot(const char * d_name)247 static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */
248 {
249 	return !strcmp(d_name, ".") || !strcmp(d_name, "..");
250 }
251 /* }}} */
252 
253 /* {{{ spl_filesystem_dir_open */
254 /* open a directory resource */
spl_filesystem_dir_open(spl_filesystem_object * intern,char * path)255 static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path)
256 {
257 	int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
258 
259 	intern->type = SPL_FS_DIR;
260 	intern->_path_len = strlen(path);
261 	intern->u.dir.dirp = php_stream_opendir(path, REPORT_ERRORS, FG(default_context));
262 
263 	if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) {
264 		intern->_path = estrndup(path, --intern->_path_len);
265 	} else {
266 		intern->_path = estrndup(path, intern->_path_len);
267 	}
268 	intern->u.dir.index = 0;
269 
270 	if (EG(exception) || intern->u.dir.dirp == NULL) {
271 		intern->u.dir.entry.d_name[0] = '\0';
272 		if (!EG(exception)) {
273 			/* open failed w/out notice (turned to exception due to EH_THROW) */
274 			zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
275 				"Failed to open directory \"%s\"", path);
276 		}
277 	} else {
278 		do {
279 			spl_filesystem_dir_read(intern);
280 		} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
281 	}
282 }
283 /* }}} */
284 
spl_filesystem_file_open(spl_filesystem_object * intern,int use_include_path,int silent)285 static int spl_filesystem_file_open(spl_filesystem_object *intern, int use_include_path, int silent) /* {{{ */
286 {
287 	zval tmp;
288 
289 	intern->type = SPL_FS_FILE;
290 
291 	php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, &tmp);
292 	if (Z_TYPE(tmp) == IS_TRUE) {
293 		intern->u.file.open_mode = NULL;
294 		intern->file_name = NULL;
295 		zend_throw_exception_ex(spl_ce_LogicException, 0, "Cannot use SplFileObject with directories");
296 		return FAILURE;
297 	}
298 
299 	intern->u.file.context = php_stream_context_from_zval(intern->u.file.zcontext, 0);
300 	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);
301 
302 	if (!intern->file_name_len || !intern->u.file.stream) {
303 		if (!EG(exception)) {
304 			zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot open file '%s'", intern->file_name_len ? intern->file_name : "");
305 		}
306 		intern->file_name = NULL; /* until here it is not a copy */
307 		intern->u.file.open_mode = NULL;
308 		return FAILURE;
309 	}
310 
311 	/*
312 	if (intern->u.file.zcontext) {
313 		//zend_list_addref(Z_RES_VAL(intern->u.file.zcontext));
314 		Z_ADDREF_P(intern->u.file.zcontext);
315 	}
316 	*/
317 
318 	if (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) {
319 		intern->file_name_len--;
320 	}
321 
322 	intern->orig_path = estrndup(intern->u.file.stream->orig_path, strlen(intern->u.file.stream->orig_path));
323 
324 	intern->file_name = estrndup(intern->file_name, intern->file_name_len);
325 	intern->u.file.open_mode = estrndup(intern->u.file.open_mode, intern->u.file.open_mode_len);
326 
327 	/* avoid reference counting in debug mode, thus do it manually */
328 	ZVAL_RES(&intern->u.file.zresource, intern->u.file.stream->res);
329 	/*!!! TODO: maybe bug?
330 	Z_SET_REFCOUNT(intern->u.file.zresource, 1);
331 	*/
332 
333 	intern->u.file.delimiter = ',';
334 	intern->u.file.enclosure = '"';
335 	intern->u.file.escape = '\\';
336 
337 	intern->u.file.func_getCurr = zend_hash_str_find_ptr(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline") - 1);
338 
339 	return SUCCESS;
340 } /* }}} */
341 
342 /* {{{ spl_filesystem_object_clone */
343 /* Local zend_object creation (on stack)
344    Load the 'other' object
345    Create a new empty object (See spl_filesystem_object_new_ex)
346    Open the directory
347    Clone other members (properties)
348  */
spl_filesystem_object_clone(zval * zobject)349 static zend_object *spl_filesystem_object_clone(zval *zobject)
350 {
351 	zend_object *old_object;
352 	zend_object *new_object;
353 	spl_filesystem_object *intern;
354 	spl_filesystem_object *source;
355 	int index, skip_dots;
356 
357 	old_object = Z_OBJ_P(zobject);
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_ASSERT(0);
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 #if defined(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 #if defined(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 	ZVAL_OBJ(return_value, &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(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 ht,spl_filesystem_object * source,int type,zend_class_entry * ce,zval * return_value)478 static spl_filesystem_object *spl_filesystem_object_create_type(int ht, 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 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
486 
487 	switch (source->type) {
488 		case SPL_FS_INFO:
489 		case SPL_FS_FILE:
490 			break;
491 		case SPL_FS_DIR:
492 			if (!source->u.dir.entry.d_name[0]) {
493 				zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Could not open file");
494 				zend_restore_error_handling(&error_handling);
495 				return NULL;
496 			}
497 	}
498 
499 	switch (type) {
500 		case SPL_FS_INFO:
501 			ce = ce ? ce : source->info_class;
502 
503 			if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
504 				break;
505 			}
506 
507 			intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
508 			ZVAL_OBJ(return_value, &intern->std);
509 
510 			spl_filesystem_object_get_file_name(source);
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(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 			ce = ce ? ce : source->file_class;
524 
525 			if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
526 				break;
527 			}
528 
529 			intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
530 
531 			ZVAL_OBJ(return_value, &intern->std);
532 
533 			spl_filesystem_object_get_file_name(source);
534 
535 			if (ce->constructor->common.scope != spl_ce_SplFileObject) {
536 				ZVAL_STRINGL(&arg1, source->file_name, source->file_name_len);
537 				ZVAL_STRINGL(&arg2, "r", 1);
538 				zend_call_method_with_2_params(return_value, ce, &ce->constructor, "__construct", NULL, &arg1, &arg2);
539 				zval_ptr_dtor(&arg1);
540 				zval_ptr_dtor(&arg2);
541 			} else {
542 				intern->file_name = source->file_name;
543 				intern->file_name_len = source->file_name_len;
544 				intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len);
545 				intern->_path = estrndup(intern->_path, intern->_path_len);
546 
547 				intern->u.file.open_mode = "r";
548 				intern->u.file.open_mode_len = 1;
549 
550 				if (ht && zend_parse_parameters(ht, "|sbr",
551 							&intern->u.file.open_mode, &intern->u.file.open_mode_len,
552 							&use_include_path, &intern->u.file.zcontext) == FAILURE) {
553 					zend_restore_error_handling(&error_handling);
554 					intern->u.file.open_mode = NULL;
555 					intern->file_name = NULL;
556 					zval_ptr_dtor(return_value);
557 					ZVAL_NULL(return_value);
558 					return NULL;
559 				}
560 
561 				if (spl_filesystem_file_open(intern, use_include_path, 0) == FAILURE) {
562 					zend_restore_error_handling(&error_handling);
563 					zval_ptr_dtor(return_value);
564 					ZVAL_NULL(return_value);
565 					return NULL;
566 				}
567 			}
568 			break;
569 		case SPL_FS_DIR:
570 			zend_restore_error_handling(&error_handling);
571 			zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Operation not supported");
572 			return NULL;
573 	}
574 	zend_restore_error_handling(&error_handling);
575 	return NULL;
576 } /* }}} */
577 
spl_filesystem_is_invalid_or_dot(const char * d_name)578 static int spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */
579 {
580 	return d_name[0] == '\0' || spl_filesystem_is_dot(d_name);
581 }
582 /* }}} */
583 
spl_filesystem_object_get_pathname(spl_filesystem_object * intern,size_t * len)584 static char *spl_filesystem_object_get_pathname(spl_filesystem_object *intern, size_t *len) { /* {{{ */
585 	switch (intern->type) {
586 		case SPL_FS_INFO:
587 		case SPL_FS_FILE:
588 			*len = intern->file_name_len;
589 			return intern->file_name;
590 		case SPL_FS_DIR:
591 			if (intern->u.dir.entry.d_name[0]) {
592 				spl_filesystem_object_get_file_name(intern);
593 				*len = intern->file_name_len;
594 				return intern->file_name;
595 			}
596 	}
597 	*len = 0;
598 	return NULL;
599 }
600 /* }}} */
601 
spl_filesystem_object_get_debug_info(zval * object,int * is_temp)602 static HashTable *spl_filesystem_object_get_debug_info(zval *object, int *is_temp) /* {{{ */
603 {
604 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(object);
605 	zval tmp;
606 	HashTable *rv;
607 	zend_string *pnstr;
608 	char *path;
609 	size_t  path_len;
610 	char stmp[2];
611 
612 	*is_temp = 1;
613 
614 	if (!intern->std.properties) {
615 		rebuild_object_properties(&intern->std);
616 	}
617 
618 	rv = zend_array_dup(intern->std.properties);
619 
620 	pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1);
621 	path = spl_filesystem_object_get_pathname(intern, &path_len);
622 	ZVAL_STRINGL(&tmp, path, path_len);
623 	zend_symtable_update(rv, pnstr, &tmp);
624 	zend_string_release_ex(pnstr, 0);
625 
626 	if (intern->file_name) {
627 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1);
628 		spl_filesystem_object_get_path(intern, &path_len);
629 
630 		if (path_len && path_len < intern->file_name_len) {
631 			ZVAL_STRINGL(&tmp, intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1));
632 		} else {
633 			ZVAL_STRINGL(&tmp, intern->file_name, intern->file_name_len);
634 		}
635 		zend_symtable_update(rv, pnstr, &tmp);
636 		zend_string_release_ex(pnstr, 0);
637 	}
638 	if (intern->type == SPL_FS_DIR) {
639 #ifdef HAVE_GLOB
640 		pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1);
641 		if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
642 			ZVAL_STRINGL(&tmp, intern->_path, intern->_path_len);
643 		} else {
644 			ZVAL_FALSE(&tmp);
645 		}
646 		zend_symtable_update(rv, pnstr, &tmp);
647 		zend_string_release_ex(pnstr, 0);
648 #endif
649 		pnstr = spl_gen_private_prop_name(spl_ce_RecursiveDirectoryIterator, "subPathName", sizeof("subPathName")-1);
650 		if (intern->u.dir.sub_path) {
651 			ZVAL_STRINGL(&tmp, intern->u.dir.sub_path, intern->u.dir.sub_path_len);
652 		} else {
653 			ZVAL_EMPTY_STRING(&tmp);
654 		}
655 		zend_symtable_update(rv, pnstr, &tmp);
656 		zend_string_release_ex(pnstr, 0);
657 	}
658 	if (intern->type == SPL_FS_FILE) {
659 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "openMode", sizeof("openMode")-1);
660 		ZVAL_STRINGL(&tmp, intern->u.file.open_mode, intern->u.file.open_mode_len);
661 		zend_symtable_update(rv, pnstr, &tmp);
662 		zend_string_release_ex(pnstr, 0);
663 		stmp[1] = '\0';
664 		stmp[0] = intern->u.file.delimiter;
665 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "delimiter", sizeof("delimiter")-1);
666 		ZVAL_STRINGL(&tmp, stmp, 1);
667 		zend_symtable_update(rv, pnstr, &tmp);
668 		zend_string_release_ex(pnstr, 0);
669 		stmp[0] = intern->u.file.enclosure;
670 		pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "enclosure", sizeof("enclosure")-1);
671 		ZVAL_STRINGL(&tmp, stmp, 1);
672 		zend_symtable_update(rv, pnstr, &tmp);
673 		zend_string_release_ex(pnstr, 0);
674 	}
675 
676 	return rv;
677 }
678 /* }}} */
679 
spl_filesystem_object_get_method_check(zend_object ** object,zend_string * method,const zval * key)680 zend_function *spl_filesystem_object_get_method_check(zend_object **object, zend_string *method, const zval *key) /* {{{ */
681 {
682 	spl_filesystem_object *fsobj = spl_filesystem_from_obj(*object);
683 
684 	if (fsobj->u.dir.dirp == NULL && fsobj->orig_path == NULL) {
685 		zend_function *func;
686 		zend_string *tmp = zend_string_init("_bad_state_ex", sizeof("_bad_state_ex") - 1, 0);
687 		func = zend_std_get_method(object, tmp, NULL);
688 		zend_string_release_ex(tmp, 0);
689 		return func;
690 	}
691 
692 	return zend_std_get_method(object, method, key);
693 }
694 /* }}} */
695 
696 #define DIT_CTOR_FLAGS  0x00000001
697 #define DIT_CTOR_GLOB   0x00000002
698 
spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS,zend_long ctor_flags)699 void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_long ctor_flags) /* {{{ */
700 {
701 	spl_filesystem_object *intern;
702 	char *path;
703 	int parsed;
704 	size_t len;
705 	zend_long flags;
706 	zend_error_handling error_handling;
707 
708 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
709 
710 	if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) {
711 		flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO;
712 		parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &path, &len, &flags);
713 	} else {
714 		flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF;
715 		parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "p", &path, &len);
716 	}
717 	if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_SKIPDOTS)) {
718 		flags |= SPL_FILE_DIR_SKIPDOTS;
719 	}
720 	if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_UNIXPATHS)) {
721 		flags |= SPL_FILE_DIR_UNIXPATHS;
722 	}
723 	if (parsed == FAILURE) {
724 		zend_restore_error_handling(&error_handling);
725 		return;
726 	}
727 	if (!len) {
728 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Directory name must not be empty.");
729 		zend_restore_error_handling(&error_handling);
730 		return;
731 	}
732 
733 	intern = Z_SPLFILESYSTEM_P(getThis());
734 	if (intern->_path) {
735 		/* object is alreay initialized */
736 		zend_restore_error_handling(&error_handling);
737 		php_error_docref(NULL, E_WARNING, "Directory object is already initialized");
738 		return;
739 	}
740 	intern->flags = flags;
741 #ifdef HAVE_GLOB
742 	if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && strstr(path, "glob://") != path) {
743 		spprintf(&path, 0, "glob://%s", path);
744 		spl_filesystem_dir_open(intern, path);
745 		efree(path);
746 	} else
747 #endif
748 	{
749 		spl_filesystem_dir_open(intern, path);
750 
751 	}
752 
753 	intern->u.dir.is_recursive = instanceof_function(intern->std.ce, spl_ce_RecursiveDirectoryIterator) ? 1 : 0;
754 
755 	zend_restore_error_handling(&error_handling);
756 }
757 /* }}} */
758 
759 /* {{{ proto DirectoryIterator::__construct(string path)
760  Cronstructs a new dir iterator from a path. */
SPL_METHOD(DirectoryIterator,__construct)761 SPL_METHOD(DirectoryIterator, __construct)
762 {
763 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
764 }
765 /* }}} */
766 
767 /* {{{ proto void DirectoryIterator::rewind()
768    Rewind dir back to the start */
SPL_METHOD(DirectoryIterator,rewind)769 SPL_METHOD(DirectoryIterator, rewind)
770 {
771 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
772 
773 	if (zend_parse_parameters_none() == FAILURE) {
774 		return;
775 	}
776 
777 	intern->u.dir.index = 0;
778 	if (intern->u.dir.dirp) {
779 		php_stream_rewinddir(intern->u.dir.dirp);
780 	}
781 	spl_filesystem_dir_read(intern);
782 }
783 /* }}} */
784 
785 /* {{{ proto string DirectoryIterator::key()
786    Return current dir entry */
SPL_METHOD(DirectoryIterator,key)787 SPL_METHOD(DirectoryIterator, key)
788 {
789 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
790 
791 	if (zend_parse_parameters_none() == FAILURE) {
792 		return;
793 	}
794 
795 	if (intern->u.dir.dirp) {
796 		RETURN_LONG(intern->u.dir.index);
797 	} else {
798 		RETURN_FALSE;
799 	}
800 }
801 /* }}} */
802 
803 /* {{{ proto DirectoryIterator DirectoryIterator::current()
804    Return this (needed for Iterator interface) */
SPL_METHOD(DirectoryIterator,current)805 SPL_METHOD(DirectoryIterator, current)
806 {
807 	if (zend_parse_parameters_none() == FAILURE) {
808 		return;
809 	}
810 	ZVAL_OBJ(return_value, Z_OBJ_P(getThis()));
811 	Z_ADDREF_P(return_value);
812 }
813 /* }}} */
814 
815 /* {{{ proto void DirectoryIterator::next()
816    Move to next entry */
SPL_METHOD(DirectoryIterator,next)817 SPL_METHOD(DirectoryIterator, next)
818 {
819 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
820 	int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
821 
822 	if (zend_parse_parameters_none() == FAILURE) {
823 		return;
824 	}
825 
826 	intern->u.dir.index++;
827 	do {
828 		spl_filesystem_dir_read(intern);
829 	} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
830 	if (intern->file_name) {
831 		efree(intern->file_name);
832 		intern->file_name = NULL;
833 	}
834 }
835 /* }}} */
836 
837 /* {{{ proto void DirectoryIterator::seek(int position)
838    Seek to the given position */
SPL_METHOD(DirectoryIterator,seek)839 SPL_METHOD(DirectoryIterator, seek)
840 {
841 	spl_filesystem_object *intern    = Z_SPLFILESYSTEM_P(getThis());
842 	zval retval;
843 	zend_long pos;
844 
845 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &pos) == FAILURE) {
846 		return;
847 	}
848 
849 	if (intern->u.dir.index > pos) {
850 		/* we first rewind */
851 		zend_call_method_with_0_params(&EX(This), Z_OBJCE(EX(This)), &intern->u.dir.func_rewind, "rewind", NULL);
852 	}
853 
854 	while (intern->u.dir.index < pos) {
855 		int valid = 0;
856 		zend_call_method_with_0_params(&EX(This), Z_OBJCE(EX(This)), &intern->u.dir.func_valid, "valid", &retval);
857 		valid = zend_is_true(&retval);
858 		zval_ptr_dtor(&retval);
859 		if (!valid) {
860 			zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", pos);
861 			return;
862 		}
863 		zend_call_method_with_0_params(&EX(This), Z_OBJCE(EX(This)), &intern->u.dir.func_next, "next", NULL);
864 	}
865 } /* }}} */
866 
867 /* {{{ proto string DirectoryIterator::valid()
868    Check whether dir contains more entries */
SPL_METHOD(DirectoryIterator,valid)869 SPL_METHOD(DirectoryIterator, valid)
870 {
871 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
872 
873 	if (zend_parse_parameters_none() == FAILURE) {
874 		return;
875 	}
876 
877 	RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0');
878 }
879 /* }}} */
880 
881 /* {{{ proto string SplFileInfo::getPath()
882    Return the path */
SPL_METHOD(SplFileInfo,getPath)883 SPL_METHOD(SplFileInfo, getPath)
884 {
885 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
886 	char *path;
887 	size_t path_len;
888 
889 	if (zend_parse_parameters_none() == FAILURE) {
890 		return;
891 	}
892 
893   	path = spl_filesystem_object_get_path(intern, &path_len);
894 	RETURN_STRINGL(path, path_len);
895 }
896 /* }}} */
897 
898 /* {{{ proto string SplFileInfo::getFilename()
899    Return filename only */
SPL_METHOD(SplFileInfo,getFilename)900 SPL_METHOD(SplFileInfo, getFilename)
901 {
902 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
903 	size_t path_len;
904 
905 	if (zend_parse_parameters_none() == FAILURE) {
906 		return;
907 	}
908 
909 	spl_filesystem_object_get_path(intern, &path_len);
910 
911 	if (path_len && path_len < intern->file_name_len) {
912 		RETURN_STRINGL(intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1));
913 	} else {
914 		RETURN_STRINGL(intern->file_name, intern->file_name_len);
915 	}
916 }
917 /* }}} */
918 
919 /* {{{ proto string DirectoryIterator::getFilename()
920    Return filename of current dir entry */
SPL_METHOD(DirectoryIterator,getFilename)921 SPL_METHOD(DirectoryIterator, getFilename)
922 {
923 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
924 
925 	if (zend_parse_parameters_none() == FAILURE) {
926 		return;
927 	}
928 
929 	RETURN_STRING(intern->u.dir.entry.d_name);
930 }
931 /* }}} */
932 
933 /* {{{ proto string SplFileInfo::getExtension()
934    Returns file extension component of path */
SPL_METHOD(SplFileInfo,getExtension)935 SPL_METHOD(SplFileInfo, getExtension)
936 {
937 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
938 	char *fname = NULL;
939 	const char *p;
940 	size_t flen;
941 	size_t path_len;
942 	size_t idx;
943 	zend_string *ret;
944 
945 	if (zend_parse_parameters_none() == FAILURE) {
946 		return;
947 	}
948 
949 	spl_filesystem_object_get_path(intern, &path_len);
950 
951 	if (path_len && path_len < intern->file_name_len) {
952 		fname = intern->file_name + path_len + 1;
953 		flen = intern->file_name_len - (path_len + 1);
954 	} else {
955 		fname = intern->file_name;
956 		flen = intern->file_name_len;
957 	}
958 
959 	ret = php_basename(fname, flen, NULL, 0);
960 
961 	p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
962 	if (p) {
963 		idx = p - ZSTR_VAL(ret);
964 		RETVAL_STRINGL(ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
965 		zend_string_release_ex(ret, 0);
966 		return;
967 	} else {
968 		zend_string_release_ex(ret, 0);
969 		RETURN_EMPTY_STRING();
970 	}
971 }
972 /* }}}*/
973 
974 /* {{{ proto string DirectoryIterator::getExtension()
975    Returns the file extension component of path */
SPL_METHOD(DirectoryIterator,getExtension)976 SPL_METHOD(DirectoryIterator, getExtension)
977 {
978 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
979 	const char *p;
980 	size_t idx;
981 	zend_string *fname;
982 
983 	if (zend_parse_parameters_none() == FAILURE) {
984 		return;
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 /* {{{ proto string SplFileInfo::getBasename([string $suffix])
1002    Returns filename component of path */
SPL_METHOD(SplFileInfo,getBasename)1003 SPL_METHOD(SplFileInfo, getBasename)
1004 {
1005 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1006 	char *fname, *suffix = 0;
1007 	size_t flen;
1008 	size_t slen = 0, path_len;
1009 
1010 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
1011 		return;
1012 	}
1013 
1014 	spl_filesystem_object_get_path(intern, &path_len);
1015 
1016 	if (path_len && path_len < intern->file_name_len) {
1017 		fname = intern->file_name + path_len + 1;
1018 		flen = intern->file_name_len - (path_len + 1);
1019 	} else {
1020 		fname = intern->file_name;
1021 		flen = intern->file_name_len;
1022 	}
1023 
1024 	RETURN_STR(php_basename(fname, flen, suffix, slen));
1025 }
1026 /* }}}*/
1027 
1028 /* {{{ proto string DirectoryIterator::getBasename([string $suffix])
1029    Returns filename component of current dir entry */
SPL_METHOD(DirectoryIterator,getBasename)1030 SPL_METHOD(DirectoryIterator, getBasename)
1031 {
1032 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1033 	char *suffix = 0;
1034 	size_t slen = 0;
1035 	zend_string *fname;
1036 
1037 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
1038 		return;
1039 	}
1040 
1041 	fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), suffix, slen);
1042 
1043 	RETVAL_STR(fname);
1044 }
1045 /* }}} */
1046 
1047 /* {{{ proto string SplFileInfo::getPathname()
1048    Return path and filename */
SPL_METHOD(SplFileInfo,getPathname)1049 SPL_METHOD(SplFileInfo, getPathname)
1050 {
1051 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1052 	char *path;
1053 	size_t path_len;
1054 
1055 	if (zend_parse_parameters_none() == FAILURE) {
1056 		return;
1057 	}
1058 	path = spl_filesystem_object_get_pathname(intern, &path_len);
1059 	if (path != NULL) {
1060 		RETURN_STRINGL(path, path_len);
1061 	} else {
1062 		RETURN_FALSE;
1063 	}
1064 }
1065 /* }}} */
1066 
1067 /* {{{ proto string FilesystemIterator::key()
1068    Return getPathname() or getFilename() depending on flags */
SPL_METHOD(FilesystemIterator,key)1069 SPL_METHOD(FilesystemIterator, key)
1070 {
1071 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1072 
1073 	if (zend_parse_parameters_none() == FAILURE) {
1074 		return;
1075 	}
1076 
1077 	if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) {
1078 		RETURN_STRING(intern->u.dir.entry.d_name);
1079 	} else {
1080 		spl_filesystem_object_get_file_name(intern);
1081 		RETURN_STRINGL(intern->file_name, intern->file_name_len);
1082 	}
1083 }
1084 /* }}} */
1085 
1086 /* {{{ proto string FilesystemIterator::current()
1087    Return getFilename(), getFileInfo() or $this depending on flags */
SPL_METHOD(FilesystemIterator,current)1088 SPL_METHOD(FilesystemIterator, current)
1089 {
1090 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1091 
1092 	if (zend_parse_parameters_none() == FAILURE) {
1093 		return;
1094 	}
1095 
1096 	if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
1097 		spl_filesystem_object_get_file_name(intern);
1098 		RETURN_STRINGL(intern->file_name, intern->file_name_len);
1099 	} else if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
1100 		spl_filesystem_object_get_file_name(intern);
1101 		spl_filesystem_object_create_type(0, intern, SPL_FS_INFO, NULL, return_value);
1102 	} else {
1103 		ZVAL_OBJ(return_value, Z_OBJ_P(getThis()));
1104 		Z_ADDREF_P(return_value);
1105 		/*RETURN_STRING(intern->u.dir.entry.d_name, 1);*/
1106 	}
1107 }
1108 /* }}} */
1109 
1110 /* {{{ proto bool DirectoryIterator::isDot()
1111    Returns true if current entry is '.' or  '..' */
SPL_METHOD(DirectoryIterator,isDot)1112 SPL_METHOD(DirectoryIterator, isDot)
1113 {
1114 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1115 
1116 	if (zend_parse_parameters_none() == FAILURE) {
1117 		return;
1118 	}
1119 
1120 	RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name));
1121 }
1122 /* }}} */
1123 
1124 /* {{{ proto SplFileInfo::__construct(string file_name)
1125  Cronstructs a new SplFileInfo from a path. */
1126 /* When the constructor gets called the object is already created
1127    by the engine, so we must only call 'additional' initializations.
1128  */
SPL_METHOD(SplFileInfo,__construct)1129 SPL_METHOD(SplFileInfo, __construct)
1130 {
1131 	spl_filesystem_object *intern;
1132 	char *path;
1133 	size_t len;
1134 
1135 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "p", &path, &len) == FAILURE) {
1136 		return;
1137 	}
1138 
1139 	intern = Z_SPLFILESYSTEM_P(getThis());
1140 
1141 	spl_filesystem_info_set_filename(intern, path, len, 1);
1142 
1143 	/* intern->type = SPL_FS_INFO; already set */
1144 }
1145 /* }}} */
1146 
1147 /* {{{ FileInfoFunction */
1148 #define FileInfoFunction(func_name, func_num) \
1149 SPL_METHOD(SplFileInfo, func_name) \
1150 { \
1151 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis()); \
1152 	zend_error_handling error_handling; \
1153 	if (zend_parse_parameters_none() == FAILURE) { \
1154 		return; \
1155 	} \
1156  \
1157 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);\
1158 	spl_filesystem_object_get_file_name(intern); \
1159 	php_stat(intern->file_name, intern->file_name_len, func_num, return_value); \
1160 	zend_restore_error_handling(&error_handling); \
1161 }
1162 /* }}} */
1163 
1164 /* {{{ proto int SplFileInfo::getPerms()
1165    Get file permissions */
FileInfoFunction(getPerms,FS_PERMS)1166 FileInfoFunction(getPerms, FS_PERMS)
1167 /* }}} */
1168 
1169 /* {{{ proto int SplFileInfo::getInode()
1170    Get file inode */
1171 FileInfoFunction(getInode, FS_INODE)
1172 /* }}} */
1173 
1174 /* {{{ proto int SplFileInfo::getSize()
1175    Get file size */
1176 FileInfoFunction(getSize, FS_SIZE)
1177 /* }}} */
1178 
1179 /* {{{ proto int SplFileInfo::getOwner()
1180    Get file owner */
1181 FileInfoFunction(getOwner, FS_OWNER)
1182 /* }}} */
1183 
1184 /* {{{ proto int SplFileInfo::getGroup()
1185    Get file group */
1186 FileInfoFunction(getGroup, FS_GROUP)
1187 /* }}} */
1188 
1189 /* {{{ proto int SplFileInfo::getATime()
1190    Get last access time of file */
1191 FileInfoFunction(getATime, FS_ATIME)
1192 /* }}} */
1193 
1194 /* {{{ proto int SplFileInfo::getMTime()
1195    Get last modification time of file */
1196 FileInfoFunction(getMTime, FS_MTIME)
1197 /* }}} */
1198 
1199 /* {{{ proto int SplFileInfo::getCTime()
1200    Get inode modification time of file */
1201 FileInfoFunction(getCTime, FS_CTIME)
1202 /* }}} */
1203 
1204 /* {{{ proto string SplFileInfo::getType()
1205    Get file type */
1206 FileInfoFunction(getType, FS_TYPE)
1207 /* }}} */
1208 
1209 /* {{{ proto bool SplFileInfo::isWritable()
1210    Returns true if file can be written */
1211 FileInfoFunction(isWritable, FS_IS_W)
1212 /* }}} */
1213 
1214 /* {{{ proto bool SplFileInfo::isReadable()
1215    Returns true if file can be read */
1216 FileInfoFunction(isReadable, FS_IS_R)
1217 /* }}} */
1218 
1219 /* {{{ proto bool SplFileInfo::isExecutable()
1220    Returns true if file is executable */
1221 FileInfoFunction(isExecutable, FS_IS_X)
1222 /* }}} */
1223 
1224 /* {{{ proto bool SplFileInfo::isFile()
1225    Returns true if file is a regular file */
1226 FileInfoFunction(isFile, FS_IS_FILE)
1227 /* }}} */
1228 
1229 /* {{{ proto bool SplFileInfo::isDir()
1230    Returns true if file is directory */
1231 FileInfoFunction(isDir, FS_IS_DIR)
1232 /* }}} */
1233 
1234 /* {{{ proto bool SplFileInfo::isLink()
1235    Returns true if file is symbolic link */
1236 FileInfoFunction(isLink, FS_IS_LINK)
1237 /* }}} */
1238 
1239 /* {{{ proto string SplFileInfo::getLinkTarget()
1240    Return the target of a symbolic link */
1241 SPL_METHOD(SplFileInfo, getLinkTarget)
1242 {
1243 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1244 	ssize_t ret;
1245 	char buff[MAXPATHLEN];
1246 	zend_error_handling error_handling;
1247 
1248 	if (zend_parse_parameters_none() == FAILURE) {
1249 		return;
1250 	}
1251 
1252 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
1253 
1254 	if (intern->file_name == NULL) {
1255 		spl_filesystem_object_get_file_name(intern);
1256 	}
1257 #if defined(PHP_WIN32) || HAVE_SYMLINK
1258 	if (intern->file_name == NULL) {
1259 		php_error_docref(NULL, E_WARNING, "Empty filename");
1260 		RETURN_FALSE;
1261 	} else if (!IS_ABSOLUTE_PATH(intern->file_name, intern->file_name_len)) {
1262 		char expanded_path[MAXPATHLEN];
1263 		if (!expand_filepath_with_mode(intern->file_name, expanded_path, NULL, 0, CWD_EXPAND )) {
1264 			php_error_docref(NULL, E_WARNING, "No such file or directory");
1265 			RETURN_FALSE;
1266 		}
1267 		ret = php_sys_readlink(expanded_path, buff, MAXPATHLEN - 1);
1268 	} else {
1269 		ret = php_sys_readlink(intern->file_name, buff,  MAXPATHLEN-1);
1270 	}
1271 #else
1272 	ret = -1; /* always fail if not implemented */
1273 #endif
1274 
1275 	if (ret == -1) {
1276 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to read link %s, error: %s", intern->file_name, strerror(errno));
1277 		RETVAL_FALSE;
1278 	} else {
1279 		/* Append NULL to the end of the string */
1280 		buff[ret] = '\0';
1281 
1282 		RETVAL_STRINGL(buff, ret);
1283 	}
1284 
1285 	zend_restore_error_handling(&error_handling);
1286 }
1287 /* }}} */
1288 
1289 #if HAVE_REALPATH || defined(ZTS)
1290 /* {{{ proto string SplFileInfo::getRealPath()
1291    Return the resolved path */
SPL_METHOD(SplFileInfo,getRealPath)1292 SPL_METHOD(SplFileInfo, getRealPath)
1293 {
1294 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1295 	char buff[MAXPATHLEN];
1296 	char *filename;
1297 	zend_error_handling error_handling;
1298 
1299 	if (zend_parse_parameters_none() == FAILURE) {
1300 		return;
1301 	}
1302 
1303 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
1304 
1305 	if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) {
1306 		spl_filesystem_object_get_file_name(intern);
1307 	}
1308 
1309 	if (intern->orig_path) {
1310 		filename = intern->orig_path;
1311 	} else {
1312 		filename = intern->file_name;
1313 	}
1314 
1315 
1316 	if (filename && VCWD_REALPATH(filename, buff)) {
1317 #ifdef ZTS
1318 		if (VCWD_ACCESS(buff, F_OK)) {
1319 			RETVAL_FALSE;
1320 		} else
1321 #endif
1322 		RETVAL_STRING(buff);
1323 	} else {
1324 		RETVAL_FALSE;
1325 	}
1326 
1327 	zend_restore_error_handling(&error_handling);
1328 }
1329 /* }}} */
1330 #endif
1331 
1332 /* {{{ proto SplFileObject SplFileInfo::openFile([string mode = 'r' [, bool use_include_path  [, resource context]]])
1333    Open the current file */
SPL_METHOD(SplFileInfo,openFile)1334 SPL_METHOD(SplFileInfo, openFile)
1335 {
1336 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1337 
1338 	spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_FILE, NULL, return_value);
1339 }
1340 /* }}} */
1341 
1342 /* {{{ proto void SplFileInfo::setFileClass([string class_name])
1343    Class to use in openFile() */
SPL_METHOD(SplFileInfo,setFileClass)1344 SPL_METHOD(SplFileInfo, setFileClass)
1345 {
1346 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1347 	zend_class_entry *ce = spl_ce_SplFileObject;
1348 	zend_error_handling error_handling;
1349 
1350 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
1351 
1352 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == SUCCESS) {
1353 		intern->file_class = ce;
1354 	}
1355 
1356 	zend_restore_error_handling(&error_handling);
1357 }
1358 /* }}} */
1359 
1360 /* {{{ proto void SplFileInfo::setInfoClass([string class_name])
1361    Class to use in getFileInfo(), getPathInfo() */
SPL_METHOD(SplFileInfo,setInfoClass)1362 SPL_METHOD(SplFileInfo, setInfoClass)
1363 {
1364 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1365 	zend_class_entry *ce = spl_ce_SplFileInfo;
1366 	zend_error_handling error_handling;
1367 
1368 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling );
1369 
1370 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == SUCCESS) {
1371 		intern->info_class = ce;
1372 	}
1373 
1374 	zend_restore_error_handling(&error_handling);
1375 }
1376 /* }}} */
1377 
1378 /* {{{ proto SplFileInfo SplFileInfo::getFileInfo([string $class_name])
1379    Get/copy file info */
SPL_METHOD(SplFileInfo,getFileInfo)1380 SPL_METHOD(SplFileInfo, getFileInfo)
1381 {
1382 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1383 	zend_class_entry *ce = intern->info_class;
1384 	zend_error_handling error_handling;
1385 
1386 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
1387 
1388 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == SUCCESS) {
1389 		spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_INFO, ce, return_value);
1390 	}
1391 
1392 	zend_restore_error_handling(&error_handling);
1393 }
1394 /* }}} */
1395 
1396 /* {{{ proto SplFileInfo SplFileInfo::getPathInfo([string $class_name])
1397    Get/copy file info */
SPL_METHOD(SplFileInfo,getPathInfo)1398 SPL_METHOD(SplFileInfo, getPathInfo)
1399 {
1400 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1401 	zend_class_entry *ce = intern->info_class;
1402 	zend_error_handling error_handling;
1403 
1404 	zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
1405 
1406 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == SUCCESS) {
1407 		size_t path_len;
1408 		char *path = spl_filesystem_object_get_pathname(intern, &path_len);
1409 		if (path) {
1410 			char *dpath = estrndup(path, path_len);
1411 			path_len = php_dirname(dpath, path_len);
1412 			spl_filesystem_object_create_info(intern, dpath, path_len, 1, ce, return_value);
1413 			efree(dpath);
1414 		}
1415 	}
1416 
1417 	zend_restore_error_handling(&error_handling);
1418 }
1419 /* }}} */
1420 
1421 /* {{{  proto SplFileInfo::_bad_state_ex(void) */
SPL_METHOD(SplFileInfo,_bad_state_ex)1422 SPL_METHOD(SplFileInfo, _bad_state_ex)
1423 {
1424 	zend_throw_exception_ex(spl_ce_LogicException, 0,
1425 		"The parent constructor was not called: the object is in an "
1426 		"invalid state ");
1427 }
1428 /* }}} */
1429 
1430 /* {{{ proto FilesystemIterator::__construct(string path [, int flags])
1431  Cronstructs a new dir iterator from a path. */
SPL_METHOD(FilesystemIterator,__construct)1432 SPL_METHOD(FilesystemIterator, __construct)
1433 {
1434 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS);
1435 }
1436 /* }}} */
1437 
1438 /* {{{ proto void FilesystemIterator::rewind()
1439    Rewind dir back to the start */
SPL_METHOD(FilesystemIterator,rewind)1440 SPL_METHOD(FilesystemIterator, rewind)
1441 {
1442 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1443 	int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
1444 
1445 	if (zend_parse_parameters_none() == FAILURE) {
1446 		return;
1447 	}
1448 
1449 	intern->u.dir.index = 0;
1450 	if (intern->u.dir.dirp) {
1451 		php_stream_rewinddir(intern->u.dir.dirp);
1452 	}
1453 	do {
1454 		spl_filesystem_dir_read(intern);
1455 	} while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
1456 }
1457 /* }}} */
1458 
1459 /* {{{ proto int FilesystemIterator::getFlags()
1460    Get handling flags */
SPL_METHOD(FilesystemIterator,getFlags)1461 SPL_METHOD(FilesystemIterator, getFlags)
1462 {
1463 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1464 
1465 	if (zend_parse_parameters_none() == FAILURE) {
1466 		return;
1467 	}
1468 
1469 	RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK));
1470 } /* }}} */
1471 
1472 /* {{{ proto void FilesystemIterator::setFlags(long $flags)
1473    Set handling flags */
SPL_METHOD(FilesystemIterator,setFlags)1474 SPL_METHOD(FilesystemIterator, setFlags)
1475 {
1476 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1477 	zend_long flags;
1478 
1479 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
1480 		return;
1481 	}
1482 
1483 	intern->flags &= ~(SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK);
1484 	intern->flags |= ((SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK) & flags);
1485 } /* }}} */
1486 
1487 /* {{{ proto bool RecursiveDirectoryIterator::hasChildren([bool $allow_links = false])
1488    Returns whether current entry is a directory and not '.' or '..' */
SPL_METHOD(RecursiveDirectoryIterator,hasChildren)1489 SPL_METHOD(RecursiveDirectoryIterator, hasChildren)
1490 {
1491 	zend_bool allow_links = 0;
1492 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1493 
1494 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &allow_links) == FAILURE) {
1495 		return;
1496 	}
1497 	if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
1498 		RETURN_FALSE;
1499 	} else {
1500 		spl_filesystem_object_get_file_name(intern);
1501 		if (!allow_links && !(intern->flags & SPL_FILE_DIR_FOLLOW_SYMLINKS)) {
1502 			php_stat(intern->file_name, intern->file_name_len, FS_IS_LINK, return_value);
1503 			if (zend_is_true(return_value)) {
1504 				RETURN_FALSE;
1505 			}
1506 		}
1507 		php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, return_value);
1508     }
1509 }
1510 /* }}} */
1511 
1512 /* {{{ proto RecursiveDirectoryIterator DirectoryIterator::getChildren()
1513    Returns an iterator for the current entry if it is a directory */
SPL_METHOD(RecursiveDirectoryIterator,getChildren)1514 SPL_METHOD(RecursiveDirectoryIterator, getChildren)
1515 {
1516 	zval zpath, zflags;
1517 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1518 	spl_filesystem_object *subdir;
1519 	char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
1520 
1521 	if (zend_parse_parameters_none() == FAILURE) {
1522 		return;
1523 	}
1524 
1525 	spl_filesystem_object_get_file_name(intern);
1526 
1527 	ZVAL_LONG(&zflags, intern->flags);
1528 	ZVAL_STRINGL(&zpath, intern->file_name, intern->file_name_len);
1529 	spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), return_value, &zpath, &zflags);
1530 	zval_ptr_dtor(&zpath);
1531 
1532 	subdir = Z_SPLFILESYSTEM_P(return_value);
1533 	if (subdir) {
1534 		if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
1535 			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);
1536 		} else {
1537 			subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
1538 			subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
1539 		}
1540 		subdir->info_class = intern->info_class;
1541 		subdir->file_class = intern->file_class;
1542 		subdir->oth = intern->oth;
1543 	}
1544 }
1545 /* }}} */
1546 
1547 /* {{{ proto void RecursiveDirectoryIterator::getSubPath()
1548    Get sub path */
SPL_METHOD(RecursiveDirectoryIterator,getSubPath)1549 SPL_METHOD(RecursiveDirectoryIterator, getSubPath)
1550 {
1551 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1552 
1553 	if (zend_parse_parameters_none() == FAILURE) {
1554 		return;
1555 	}
1556 
1557 	if (intern->u.dir.sub_path) {
1558 		RETURN_STRINGL(intern->u.dir.sub_path, intern->u.dir.sub_path_len);
1559 	} else {
1560 		RETURN_EMPTY_STRING();
1561 	}
1562 }
1563 /* }}} */
1564 
1565 /* {{{ proto void RecursiveDirectoryIterator::getSubPathname()
1566    Get sub path and file name */
SPL_METHOD(RecursiveDirectoryIterator,getSubPathname)1567 SPL_METHOD(RecursiveDirectoryIterator, getSubPathname)
1568 {
1569 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1570 	char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
1571 
1572 	if (zend_parse_parameters_none() == FAILURE) {
1573 		return;
1574 	}
1575 
1576 	if (intern->u.dir.sub_path) {
1577 		RETURN_NEW_STR(strpprintf(0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name));
1578 	} else {
1579 		RETURN_STRING(intern->u.dir.entry.d_name);
1580 	}
1581 }
1582 /* }}} */
1583 
1584 /* {{{ proto RecursiveDirectoryIterator::__construct(string path [, int flags])
1585  Cronstructs a new dir iterator from a path. */
SPL_METHOD(RecursiveDirectoryIterator,__construct)1586 SPL_METHOD(RecursiveDirectoryIterator, __construct)
1587 {
1588 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS);
1589 }
1590 /* }}} */
1591 
1592 #ifdef HAVE_GLOB
1593 /* {{{ proto GlobIterator::__construct(string path [, int flags])
1594  Cronstructs a new dir iterator from a glob expression (no glob:// needed). */
SPL_METHOD(GlobIterator,__construct)1595 SPL_METHOD(GlobIterator, __construct)
1596 {
1597 	spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS|DIT_CTOR_GLOB);
1598 }
1599 /* }}} */
1600 
1601 /* {{{ proto int GlobIterator::cont()
1602    Return the number of directories and files found by globbing */
SPL_METHOD(GlobIterator,count)1603 SPL_METHOD(GlobIterator, count)
1604 {
1605 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
1606 
1607 	if (zend_parse_parameters_none() == FAILURE) {
1608 		return;
1609 	}
1610 
1611 	if (intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
1612 		RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL));
1613 	} else {
1614 		/* should not happen */
1615 		php_error_docref(NULL, E_ERROR, "GlobIterator lost glob state");
1616 	}
1617 }
1618 /* }}} */
1619 #endif /* HAVE_GLOB */
1620 
1621 /* {{{ forward declarations to the iterator handlers */
1622 static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter);
1623 static int spl_filesystem_dir_it_valid(zend_object_iterator *iter);
1624 static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter);
1625 static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key);
1626 static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter);
1627 static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter);
1628 
1629 /* iterator handler table */
1630 static const zend_object_iterator_funcs spl_filesystem_dir_it_funcs = {
1631 	spl_filesystem_dir_it_dtor,
1632 	spl_filesystem_dir_it_valid,
1633 	spl_filesystem_dir_it_current_data,
1634 	spl_filesystem_dir_it_current_key,
1635 	spl_filesystem_dir_it_move_forward,
1636 	spl_filesystem_dir_it_rewind,
1637 	NULL
1638 };
1639 /* }}} */
1640 
1641 /* {{{ spl_ce_dir_get_iterator */
spl_filesystem_dir_get_iterator(zend_class_entry * ce,zval * object,int by_ref)1642 zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
1643 {
1644 	spl_filesystem_iterator *iterator;
1645 	spl_filesystem_object *dir_object;
1646 
1647 	if (by_ref) {
1648 		zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0);
1649 		return NULL;
1650 	}
1651 	dir_object = Z_SPLFILESYSTEM_P(object);
1652 	iterator = spl_filesystem_object_to_iterator(dir_object);
1653 	ZVAL_COPY(&iterator->intern.data, object);
1654 	iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
1655 	/* ->current must be initialized; rewind doesn't set it and valid
1656 	 * doesn't check whether it's set */
1657 	iterator->current = *object;
1658 
1659 	return &iterator->intern;
1660 }
1661 /* }}} */
1662 
1663 /* {{{ spl_filesystem_dir_it_dtor */
spl_filesystem_dir_it_dtor(zend_object_iterator * iter)1664 static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter)
1665 {
1666 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1667 
1668 	if (!Z_ISUNDEF(iterator->intern.data)) {
1669 		zval *object = &iterator->intern.data;
1670 		zval_ptr_dtor(object);
1671 	}
1672 	/* Otherwise we were called from the owning object free storage handler as
1673 	 * it sets iterator->intern.data to IS_UNDEF.
1674 	 * We don't even need to destroy iterator->current as we didn't add a
1675 	 * reference to it in move_forward or get_iterator */
1676 }
1677 /* }}} */
1678 
1679 /* {{{ spl_filesystem_dir_it_valid */
spl_filesystem_dir_it_valid(zend_object_iterator * iter)1680 static int spl_filesystem_dir_it_valid(zend_object_iterator *iter)
1681 {
1682 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1683 
1684 	return object->u.dir.entry.d_name[0] != '\0' ? SUCCESS : FAILURE;
1685 }
1686 /* }}} */
1687 
1688 /* {{{ spl_filesystem_dir_it_current_data */
spl_filesystem_dir_it_current_data(zend_object_iterator * iter)1689 static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter)
1690 {
1691 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1692 
1693 	return &iterator->current;
1694 }
1695 /* }}} */
1696 
1697 /* {{{ spl_filesystem_dir_it_current_key */
spl_filesystem_dir_it_current_key(zend_object_iterator * iter,zval * key)1698 static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key)
1699 {
1700 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1701 
1702 	ZVAL_LONG(key, object->u.dir.index);
1703 }
1704 /* }}} */
1705 
1706 /* {{{ spl_filesystem_dir_it_move_forward */
spl_filesystem_dir_it_move_forward(zend_object_iterator * iter)1707 static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter)
1708 {
1709 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1710 
1711 	object->u.dir.index++;
1712 	spl_filesystem_dir_read(object);
1713 	if (object->file_name) {
1714 		efree(object->file_name);
1715 		object->file_name = NULL;
1716 	}
1717 }
1718 /* }}} */
1719 
1720 /* {{{ spl_filesystem_dir_it_rewind */
spl_filesystem_dir_it_rewind(zend_object_iterator * iter)1721 static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter)
1722 {
1723 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1724 
1725 	object->u.dir.index = 0;
1726 	if (object->u.dir.dirp) {
1727 		php_stream_rewinddir(object->u.dir.dirp);
1728 	}
1729 	spl_filesystem_dir_read(object);
1730 }
1731 /* }}} */
1732 
1733 /* {{{ spl_filesystem_tree_it_dtor */
spl_filesystem_tree_it_dtor(zend_object_iterator * iter)1734 static void spl_filesystem_tree_it_dtor(zend_object_iterator *iter)
1735 {
1736 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1737 
1738 	if (!Z_ISUNDEF(iterator->intern.data)) {
1739 		zval *object = &iterator->intern.data;
1740 		zval_ptr_dtor(object);
1741 	} else {
1742 		if (!Z_ISUNDEF(iterator->current)) {
1743 			zval_ptr_dtor(&iterator->current);
1744 			ZVAL_UNDEF(&iterator->current);
1745 		}
1746 	}
1747 }
1748 /* }}} */
1749 
1750 /* {{{ spl_filesystem_tree_it_current_data */
spl_filesystem_tree_it_current_data(zend_object_iterator * iter)1751 static zval *spl_filesystem_tree_it_current_data(zend_object_iterator *iter)
1752 {
1753 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1754 	spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
1755 
1756 	if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
1757 		if (Z_ISUNDEF(iterator->current)) {
1758 			spl_filesystem_object_get_file_name(object);
1759 			ZVAL_STRINGL(&iterator->current, object->file_name, object->file_name_len);
1760 		}
1761 		return &iterator->current;
1762 	} else if (SPL_FILE_DIR_CURRENT(object, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
1763 		if (Z_ISUNDEF(iterator->current)) {
1764 			spl_filesystem_object_get_file_name(object);
1765 			spl_filesystem_object_create_type(0, object, SPL_FS_INFO, NULL, &iterator->current);
1766 		}
1767 		return &iterator->current;
1768 	} else {
1769 		return &iterator->intern.data;
1770 	}
1771 }
1772 /* }}} */
1773 
1774 /* {{{ spl_filesystem_tree_it_current_key */
spl_filesystem_tree_it_current_key(zend_object_iterator * iter,zval * key)1775 static void spl_filesystem_tree_it_current_key(zend_object_iterator *iter, zval *key)
1776 {
1777 	spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
1778 
1779 	if (SPL_FILE_DIR_KEY(object, SPL_FILE_DIR_KEY_AS_FILENAME)) {
1780 		ZVAL_STRING(key, object->u.dir.entry.d_name);
1781 	} else {
1782 		spl_filesystem_object_get_file_name(object);
1783 		ZVAL_STRINGL(key, object->file_name, object->file_name_len);
1784 	}
1785 }
1786 /* }}} */
1787 
1788 /* {{{ spl_filesystem_tree_it_move_forward */
spl_filesystem_tree_it_move_forward(zend_object_iterator * iter)1789 static void spl_filesystem_tree_it_move_forward(zend_object_iterator *iter)
1790 {
1791 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1792 	spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
1793 
1794 	object->u.dir.index++;
1795 	do {
1796 		spl_filesystem_dir_read(object);
1797 	} while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
1798 	if (object->file_name) {
1799 		efree(object->file_name);
1800 		object->file_name = NULL;
1801 	}
1802 	if (!Z_ISUNDEF(iterator->current)) {
1803 		zval_ptr_dtor(&iterator->current);
1804 		ZVAL_UNDEF(&iterator->current);
1805 	}
1806 }
1807 /* }}} */
1808 
1809 /* {{{ spl_filesystem_tree_it_rewind */
spl_filesystem_tree_it_rewind(zend_object_iterator * iter)1810 static void spl_filesystem_tree_it_rewind(zend_object_iterator *iter)
1811 {
1812 	spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
1813 	spl_filesystem_object   *object   = spl_filesystem_iterator_to_object(iterator);
1814 
1815 	object->u.dir.index = 0;
1816 	if (object->u.dir.dirp) {
1817 		php_stream_rewinddir(object->u.dir.dirp);
1818 	}
1819 	do {
1820 		spl_filesystem_dir_read(object);
1821 	} while (spl_filesystem_is_dot(object->u.dir.entry.d_name));
1822 	if (!Z_ISUNDEF(iterator->current)) {
1823 		zval_ptr_dtor(&iterator->current);
1824 		ZVAL_UNDEF(&iterator->current);
1825 	}
1826 }
1827 /* }}} */
1828 
1829 /* {{{ iterator handler table */
1830 static const zend_object_iterator_funcs spl_filesystem_tree_it_funcs = {
1831 	spl_filesystem_tree_it_dtor,
1832 	spl_filesystem_dir_it_valid,
1833 	spl_filesystem_tree_it_current_data,
1834 	spl_filesystem_tree_it_current_key,
1835 	spl_filesystem_tree_it_move_forward,
1836 	spl_filesystem_tree_it_rewind,
1837 	NULL
1838 };
1839 /* }}} */
1840 
1841 /* {{{ spl_ce_dir_get_iterator */
spl_filesystem_tree_get_iterator(zend_class_entry * ce,zval * object,int by_ref)1842 zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
1843 {
1844 	spl_filesystem_iterator *iterator;
1845 	spl_filesystem_object *dir_object;
1846 
1847 	if (by_ref) {
1848 		zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0);
1849 		return NULL;
1850 	}
1851 	dir_object = Z_SPLFILESYSTEM_P(object);
1852 	iterator = spl_filesystem_object_to_iterator(dir_object);
1853 
1854 	ZVAL_COPY(&iterator->intern.data, object);
1855 	iterator->intern.funcs = &spl_filesystem_tree_it_funcs;
1856 
1857 	return &iterator->intern;
1858 }
1859 /* }}} */
1860 
1861 /* {{{ spl_filesystem_object_cast */
spl_filesystem_object_cast(zval * readobj,zval * writeobj,int type)1862 static int spl_filesystem_object_cast(zval *readobj, zval *writeobj, int type)
1863 {
1864 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(readobj);
1865 
1866 	if (type == IS_STRING) {
1867 		if (Z_OBJCE_P(readobj)->__tostring) {
1868 			return zend_std_cast_object_tostring(readobj, writeobj, type);
1869 		}
1870 
1871 		switch (intern->type) {
1872 		case SPL_FS_INFO:
1873 		case SPL_FS_FILE:
1874 			ZVAL_STRINGL(writeobj, intern->file_name, intern->file_name_len);
1875 			return SUCCESS;
1876 		case SPL_FS_DIR:
1877 			ZVAL_STRING(writeobj, intern->u.dir.entry.d_name);
1878 			return SUCCESS;
1879 		}
1880 	} else if (type == _IS_BOOL) {
1881 		ZVAL_TRUE(writeobj);
1882 		return SUCCESS;
1883 	}
1884 	ZVAL_NULL(writeobj);
1885 	return FAILURE;
1886 }
1887 /* }}} */
1888 
1889 /* {{{ declare method parameters */
1890 /* supply a name and default to call by parameter */
1891 ZEND_BEGIN_ARG_INFO(arginfo_info___construct, 0)
1892 	ZEND_ARG_INFO(0, file_name)
1893 ZEND_END_ARG_INFO()
1894 
1895 ZEND_BEGIN_ARG_INFO_EX(arginfo_info_openFile, 0, 0, 0)
1896 	ZEND_ARG_INFO(0, open_mode)
1897 	ZEND_ARG_INFO(0, use_include_path)
1898 	ZEND_ARG_INFO(0, context)
1899 ZEND_END_ARG_INFO()
1900 
1901 ZEND_BEGIN_ARG_INFO_EX(arginfo_info_optinalFileClass, 0, 0, 0)
1902 	ZEND_ARG_INFO(0, class_name)
1903 ZEND_END_ARG_INFO()
1904 
1905 ZEND_BEGIN_ARG_INFO_EX(arginfo_optinalSuffix, 0, 0, 0)
1906 	ZEND_ARG_INFO(0, suffix)
1907 ZEND_END_ARG_INFO()
1908 
1909 ZEND_BEGIN_ARG_INFO(arginfo_splfileinfo_void, 0)
1910 ZEND_END_ARG_INFO()
1911 
1912 /* the method table */
1913 /* each method can have its own parameters and visibility */
1914 static const zend_function_entry spl_SplFileInfo_functions[] = {
1915 	SPL_ME(SplFileInfo,       __construct,   arginfo_info___construct, ZEND_ACC_PUBLIC)
1916 	SPL_ME(SplFileInfo,       getPath,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1917 	SPL_ME(SplFileInfo,       getFilename,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1918 	SPL_ME(SplFileInfo,       getExtension,  arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1919 	SPL_ME(SplFileInfo,       getBasename,   arginfo_optinalSuffix, ZEND_ACC_PUBLIC)
1920 	SPL_ME(SplFileInfo,       getPathname,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1921 	SPL_ME(SplFileInfo,       getPerms,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1922 	SPL_ME(SplFileInfo,       getInode,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1923 	SPL_ME(SplFileInfo,       getSize,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1924 	SPL_ME(SplFileInfo,       getOwner,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1925 	SPL_ME(SplFileInfo,       getGroup,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1926 	SPL_ME(SplFileInfo,       getATime,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1927 	SPL_ME(SplFileInfo,       getMTime,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1928 	SPL_ME(SplFileInfo,       getCTime,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1929 	SPL_ME(SplFileInfo,       getType,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1930 	SPL_ME(SplFileInfo,       isWritable,    arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1931 	SPL_ME(SplFileInfo,       isReadable,    arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1932 	SPL_ME(SplFileInfo,       isExecutable,  arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1933 	SPL_ME(SplFileInfo,       isFile,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1934 	SPL_ME(SplFileInfo,       isDir,         arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1935 	SPL_ME(SplFileInfo,       isLink,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1936 	SPL_ME(SplFileInfo,       getLinkTarget, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1937 #if HAVE_REALPATH || defined(ZTS)
1938 	SPL_ME(SplFileInfo,       getRealPath,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1939 #endif
1940 	SPL_ME(SplFileInfo,       getFileInfo,   arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
1941 	SPL_ME(SplFileInfo,       getPathInfo,   arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
1942 	SPL_ME(SplFileInfo,       openFile,      arginfo_info_openFile,         ZEND_ACC_PUBLIC)
1943 	SPL_ME(SplFileInfo,       setFileClass,  arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
1944 	SPL_ME(SplFileInfo,       setInfoClass,  arginfo_info_optinalFileClass, ZEND_ACC_PUBLIC)
1945 	SPL_ME(SplFileInfo,       _bad_state_ex, NULL,							ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1946 	SPL_MA(SplFileInfo,       __toString, SplFileInfo, getPathname, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1947 	PHP_FE_END
1948 };
1949 
1950 ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0)
1951 	ZEND_ARG_INFO(0, path)
1952 ZEND_END_ARG_INFO()
1953 
1954 ZEND_BEGIN_ARG_INFO(arginfo_dir_it_seek, 0)
1955 	ZEND_ARG_INFO(0, position)
1956 ZEND_END_ARG_INFO();
1957 
1958 /* the method table */
1959 /* each method can have its own parameters and visibility */
1960 static const zend_function_entry spl_DirectoryIterator_functions[] = {
1961 	SPL_ME(DirectoryIterator, __construct,   arginfo_dir___construct, ZEND_ACC_PUBLIC)
1962 	SPL_ME(DirectoryIterator, getFilename,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1963 	SPL_ME(DirectoryIterator, getExtension,  arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1964 	SPL_ME(DirectoryIterator, getBasename,   arginfo_optinalSuffix, ZEND_ACC_PUBLIC)
1965 	SPL_ME(DirectoryIterator, isDot,         arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1966 	SPL_ME(DirectoryIterator, rewind,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1967 	SPL_ME(DirectoryIterator, valid,         arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1968 	SPL_ME(DirectoryIterator, key,           arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1969 	SPL_ME(DirectoryIterator, current,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1970 	SPL_ME(DirectoryIterator, next,          arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1971 	SPL_ME(DirectoryIterator, seek,          arginfo_dir_it_seek, ZEND_ACC_PUBLIC)
1972 	SPL_MA(DirectoryIterator, __toString, DirectoryIterator, getFilename, arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1973 	PHP_FE_END
1974 };
1975 
1976 ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir___construct, 0, 0, 1)
1977 	ZEND_ARG_INFO(0, path)
1978 	ZEND_ARG_INFO(0, flags)
1979 ZEND_END_ARG_INFO()
1980 
1981 ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_hasChildren, 0, 0, 0)
1982 	ZEND_ARG_INFO(0, allow_links)
1983 ZEND_END_ARG_INFO()
1984 
1985 ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_setFlags, 0, 0, 0)
1986 	ZEND_ARG_INFO(0, flags)
1987 ZEND_END_ARG_INFO()
1988 
1989 static const zend_function_entry spl_FilesystemIterator_functions[] = {
1990 	SPL_ME(FilesystemIterator, __construct,   arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
1991 	SPL_ME(FilesystemIterator, rewind,        arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1992 	SPL_ME(DirectoryIterator,  next,          arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1993 	SPL_ME(FilesystemIterator, key,           arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1994 	SPL_ME(FilesystemIterator, current,       arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1995 	SPL_ME(FilesystemIterator, getFlags,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
1996 	SPL_ME(FilesystemIterator, setFlags,      arginfo_r_dir_setFlags, ZEND_ACC_PUBLIC)
1997 	PHP_FE_END
1998 };
1999 
2000 static const zend_function_entry spl_RecursiveDirectoryIterator_functions[] = {
2001 	SPL_ME(RecursiveDirectoryIterator, __construct,   arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
2002 	SPL_ME(RecursiveDirectoryIterator, hasChildren,   arginfo_r_dir_hasChildren, ZEND_ACC_PUBLIC)
2003 	SPL_ME(RecursiveDirectoryIterator, getChildren,   arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
2004 	SPL_ME(RecursiveDirectoryIterator, getSubPath,    arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
2005 	SPL_ME(RecursiveDirectoryIterator, getSubPathname,arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
2006 	PHP_FE_END
2007 };
2008 
2009 #ifdef HAVE_GLOB
2010 static const zend_function_entry spl_GlobIterator_functions[] = {
2011 	SPL_ME(GlobIterator, __construct,   arginfo_r_dir___construct, ZEND_ACC_PUBLIC)
2012 	SPL_ME(GlobIterator, count,         arginfo_splfileinfo_void,  ZEND_ACC_PUBLIC)
2013 	PHP_FE_END
2014 };
2015 #endif
2016 /* }}} */
2017 
spl_filesystem_file_read(spl_filesystem_object * intern,int silent)2018 static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent) /* {{{ */
2019 {
2020 	char *buf;
2021 	size_t line_len = 0;
2022 	zend_long line_add = (intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval)) ? 1 : 0;
2023 
2024 	spl_filesystem_file_free_line(intern);
2025 
2026 	if (php_stream_eof(intern->u.file.stream)) {
2027 		if (!silent) {
2028 			zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", intern->file_name);
2029 		}
2030 		return FAILURE;
2031 	}
2032 
2033 	if (intern->u.file.max_line_len > 0) {
2034 		buf = safe_emalloc((intern->u.file.max_line_len + 1), sizeof(char), 0);
2035 		if (php_stream_get_line(intern->u.file.stream, buf, intern->u.file.max_line_len + 1, &line_len) == NULL) {
2036 			efree(buf);
2037 			buf = NULL;
2038 		} else {
2039 			buf[line_len] = '\0';
2040 		}
2041 	} else {
2042 		buf = php_stream_get_line(intern->u.file.stream, NULL, 0, &line_len);
2043 	}
2044 
2045 	if (!buf) {
2046 		intern->u.file.current_line = estrdup("");
2047 		intern->u.file.current_line_len = 0;
2048 	} else {
2049 		if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_DROP_NEW_LINE)) {
2050 			line_len = strcspn(buf, "\r\n");
2051 			buf[line_len] = '\0';
2052 		}
2053 
2054 		intern->u.file.current_line = buf;
2055 		intern->u.file.current_line_len = line_len;
2056 	}
2057 	intern->u.file.current_line_num += line_add;
2058 
2059 	return SUCCESS;
2060 } /* }}} */
2061 
spl_filesystem_file_call(spl_filesystem_object * intern,zend_function * func_ptr,int pass_num_args,zval * return_value,zval * arg2)2062 static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function *func_ptr, int pass_num_args, zval *return_value, zval *arg2) /* {{{ */
2063 {
2064 	zend_fcall_info fci;
2065 	zend_fcall_info_cache fcic;
2066 	zval *zresource_ptr = &intern->u.file.zresource, *params, retval;
2067 	int result;
2068 	int num_args = pass_num_args + (arg2 ? 2 : 1);
2069 
2070 	if (Z_ISUNDEF_P(zresource_ptr)) {
2071 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2072 		return FAILURE;
2073 	}
2074 
2075 	params = (zval*)safe_emalloc(num_args, sizeof(zval), 0);
2076 	params[0] = *zresource_ptr;
2077 
2078 	if (arg2) {
2079 		params[1] = *arg2;
2080 	}
2081 
2082 	if (zend_get_parameters_array_ex(pass_num_args, params + (arg2 ? 2 : 1)) != SUCCESS) {
2083 		efree(params);
2084 		WRONG_PARAM_COUNT_WITH_RETVAL(FAILURE);
2085 	}
2086 
2087 	ZVAL_UNDEF(&retval);
2088 
2089 	fci.size = sizeof(fci);
2090 	fci.object = NULL;
2091 	fci.retval = &retval;
2092 	fci.param_count = num_args;
2093 	fci.params = params;
2094 	fci.no_separation = 1;
2095 	ZVAL_STR(&fci.function_name, func_ptr->common.function_name);
2096 
2097 	fcic.function_handler = func_ptr;
2098 	fcic.called_scope = NULL;
2099 	fcic.object = NULL;
2100 
2101 	result = zend_call_function(&fci, &fcic);
2102 
2103 	if (result == FAILURE || Z_ISUNDEF(retval)) {
2104 		RETVAL_FALSE;
2105 	} else {
2106 		ZVAL_ZVAL(return_value, &retval, 0, 0);
2107 	}
2108 
2109 	efree(params);
2110 	return result;
2111 } /* }}} */
2112 
2113 #define FileFunctionCall(func_name, pass_num_args, arg2) /* {{{ */ \
2114 { \
2115 	zend_function *func_ptr; \
2116 	func_ptr = (zend_function *)zend_hash_str_find_ptr(EG(function_table), #func_name, sizeof(#func_name) - 1); \
2117 	if (func_ptr == NULL) { \
2118 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Internal error, function '%s' not found. Please report", #func_name); \
2119 		return; \
2120 	} \
2121 	spl_filesystem_file_call(intern, func_ptr, pass_num_args, return_value, arg2); \
2122 } /* }}} */
2123 
spl_filesystem_file_read_csv(spl_filesystem_object * intern,char delimiter,char enclosure,char escape,zval * return_value)2124 static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, char escape, zval *return_value) /* {{{ */
2125 {
2126 	int ret = SUCCESS;
2127 	zval *value;
2128 
2129 	do {
2130 		ret = spl_filesystem_file_read(intern, 1);
2131 	} while (ret == SUCCESS && !intern->u.file.current_line_len && SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY));
2132 
2133 	if (ret == SUCCESS) {
2134 		size_t buf_len = intern->u.file.current_line_len;
2135 		char *buf = estrndup(intern->u.file.current_line, buf_len);
2136 
2137 		if (!Z_ISUNDEF(intern->u.file.current_zval)) {
2138 			zval_ptr_dtor(&intern->u.file.current_zval);
2139 			ZVAL_UNDEF(&intern->u.file.current_zval);
2140 		}
2141 
2142 		php_fgetcsv(intern->u.file.stream, delimiter, enclosure, escape, buf_len, buf, &intern->u.file.current_zval);
2143 		if (return_value) {
2144 			zval_ptr_dtor(return_value);
2145 			value = &intern->u.file.current_zval;
2146 			ZVAL_COPY_DEREF(return_value, value);
2147 		}
2148 	}
2149 	return ret;
2150 }
2151 /* }}} */
2152 
spl_filesystem_file_read_line_ex(zval * this_ptr,spl_filesystem_object * intern,int silent)2153 static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, int silent) /* {{{ */
2154 {
2155 	zval retval;
2156 
2157 	/* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */
2158 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) {
2159 		if (php_stream_eof(intern->u.file.stream)) {
2160 			if (!silent) {
2161 				zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", intern->file_name);
2162 			}
2163 			return FAILURE;
2164 		}
2165 		if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) {
2166 			return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL);
2167 		} else {
2168 			zend_execute_data *execute_data = EG(current_execute_data);
2169 			zend_call_method_with_0_params(this_ptr, Z_OBJCE(EX(This)), &intern->u.file.func_getCurr, "getCurrentLine", &retval);
2170 		}
2171 		if (!Z_ISUNDEF(retval)) {
2172 			if (intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval)) {
2173 				intern->u.file.current_line_num++;
2174 			}
2175 			spl_filesystem_file_free_line(intern);
2176 			if (Z_TYPE(retval) == IS_STRING) {
2177 				intern->u.file.current_line = estrndup(Z_STRVAL(retval), Z_STRLEN(retval));
2178 				intern->u.file.current_line_len = Z_STRLEN(retval);
2179 			} else {
2180 				zval *value = &retval;
2181 
2182 				ZVAL_COPY_DEREF(&intern->u.file.current_zval, value);
2183 			}
2184 			zval_ptr_dtor(&retval);
2185 			return SUCCESS;
2186 		} else {
2187 			return FAILURE;
2188 		}
2189 	} else {
2190 		return spl_filesystem_file_read(intern, silent);
2191 	}
2192 } /* }}} */
2193 
spl_filesystem_file_is_empty_line(spl_filesystem_object * intern)2194 static int spl_filesystem_file_is_empty_line(spl_filesystem_object *intern) /* {{{ */
2195 {
2196 	if (intern->u.file.current_line) {
2197 		return intern->u.file.current_line_len == 0;
2198 	} else if (!Z_ISUNDEF(intern->u.file.current_zval)) {
2199 		switch(Z_TYPE(intern->u.file.current_zval)) {
2200 			case IS_STRING:
2201 				return Z_STRLEN(intern->u.file.current_zval) == 0;
2202 			case IS_ARRAY:
2203 				if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)
2204 						&& zend_hash_num_elements(Z_ARRVAL(intern->u.file.current_zval)) == 1) {
2205 					uint32_t idx = 0;
2206 					zval *first;
2207 
2208 					while (Z_ISUNDEF(Z_ARRVAL(intern->u.file.current_zval)->arData[idx].val)) {
2209 						idx++;
2210 					}
2211 					first = &Z_ARRVAL(intern->u.file.current_zval)->arData[idx].val;
2212 					return Z_TYPE_P(first) == IS_STRING && Z_STRLEN_P(first) == 0;
2213 				}
2214 				return zend_hash_num_elements(Z_ARRVAL(intern->u.file.current_zval)) == 0;
2215 			case IS_NULL:
2216 				return 1;
2217 			default:
2218 				return 0;
2219 		}
2220 	} else {
2221 		return 1;
2222 	}
2223 }
2224 /* }}} */
2225 
spl_filesystem_file_read_line(zval * this_ptr,spl_filesystem_object * intern,int silent)2226 static int spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, int silent) /* {{{ */
2227 {
2228 	int ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent);
2229 
2230 	while (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && spl_filesystem_file_is_empty_line(intern)) {
2231 		spl_filesystem_file_free_line(intern);
2232 		ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent);
2233 	}
2234 
2235 	return ret;
2236 }
2237 /* }}} */
2238 
spl_filesystem_file_rewind(zval * this_ptr,spl_filesystem_object * intern)2239 static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *intern) /* {{{ */
2240 {
2241 	if(!intern->u.file.stream) {
2242 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2243 		return;
2244 	}
2245 	if (-1 == php_stream_rewind(intern->u.file.stream)) {
2246 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot rewind file %s", intern->file_name);
2247 	} else {
2248 		spl_filesystem_file_free_line(intern);
2249 		intern->u.file.current_line_num = 0;
2250 	}
2251 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2252 		spl_filesystem_file_read_line(this_ptr, intern, 1);
2253 	}
2254 } /* }}} */
2255 
2256 /* {{{ proto SplFileObject::__construct(string filename [, string mode = 'r' [, bool use_include_path  [, resource context]]]])
2257    Construct a new file object */
SPL_METHOD(SplFileObject,__construct)2258 SPL_METHOD(SplFileObject, __construct)
2259 {
2260 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2261 	zend_bool use_include_path = 0;
2262 	char *p1, *p2;
2263 	char *tmp_path;
2264 	size_t   tmp_path_len;
2265 	zend_error_handling error_handling;
2266 
2267 	intern->u.file.open_mode = NULL;
2268 	intern->u.file.open_mode_len = 0;
2269 
2270 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "p|sbr!",
2271 			&intern->file_name, &intern->file_name_len,
2272 			&intern->u.file.open_mode, &intern->u.file.open_mode_len,
2273 			&use_include_path, &intern->u.file.zcontext) == FAILURE) {
2274 		intern->u.file.open_mode = NULL;
2275 		intern->file_name = NULL;
2276 		return;
2277 	}
2278 
2279 	if (intern->u.file.open_mode == NULL) {
2280 		intern->u.file.open_mode = "r";
2281 		intern->u.file.open_mode_len = 1;
2282 	}
2283 
2284 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
2285 
2286 	if (spl_filesystem_file_open(intern, use_include_path, 0) == SUCCESS) {
2287 		tmp_path_len = strlen(intern->u.file.stream->orig_path);
2288 
2289 		if (tmp_path_len > 1 && IS_SLASH_AT(intern->u.file.stream->orig_path, tmp_path_len-1)) {
2290 			tmp_path_len--;
2291 		}
2292 
2293 		tmp_path = estrndup(intern->u.file.stream->orig_path, tmp_path_len);
2294 
2295 		p1 = strrchr(tmp_path, '/');
2296 #if defined(PHP_WIN32)
2297 		p2 = strrchr(tmp_path, '\\');
2298 #else
2299 		p2 = 0;
2300 #endif
2301 		if (p1 || p2) {
2302 			intern->_path_len = ((p1 > p2 ? p1 : p2) - tmp_path);
2303 		} else {
2304 			intern->_path_len = 0;
2305 		}
2306 
2307 		efree(tmp_path);
2308 
2309 		intern->_path = estrndup(intern->u.file.stream->orig_path, intern->_path_len);
2310 	}
2311 
2312 	zend_restore_error_handling(&error_handling);
2313 
2314 } /* }}} */
2315 
2316 /* {{{ proto SplTempFileObject::__construct([int max_memory])
2317    Construct a new temp file object */
SPL_METHOD(SplTempFileObject,__construct)2318 SPL_METHOD(SplTempFileObject, __construct)
2319 {
2320 	zend_long max_memory = PHP_STREAM_MAX_MEM;
2321 	char tmp_fname[48];
2322 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2323 	zend_error_handling error_handling;
2324 
2325 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "|l", &max_memory) == FAILURE) {
2326 		return;
2327 	}
2328 
2329 	if (max_memory < 0) {
2330 		intern->file_name = "php://memory";
2331 		intern->file_name_len = 12;
2332 	} else if (ZEND_NUM_ARGS()) {
2333 		intern->file_name_len = slprintf(tmp_fname, sizeof(tmp_fname), "php://temp/maxmemory:" ZEND_LONG_FMT, max_memory);
2334 		intern->file_name = tmp_fname;
2335 	} else {
2336 		intern->file_name = "php://temp";
2337 		intern->file_name_len = 10;
2338 	}
2339 	intern->u.file.open_mode = "wb";
2340 	intern->u.file.open_mode_len = 1;
2341 
2342 	zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
2343 	if (spl_filesystem_file_open(intern, 0, 0) == SUCCESS) {
2344 		intern->_path_len = 0;
2345 		intern->_path = estrndup("", 0);
2346 	}
2347 	zend_restore_error_handling(&error_handling);
2348 } /* }}} */
2349 
2350 /* {{{ proto void SplFileObject::rewind()
2351    Rewind the file and read the first line */
SPL_METHOD(SplFileObject,rewind)2352 SPL_METHOD(SplFileObject, rewind)
2353 {
2354 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2355 
2356 	if (zend_parse_parameters_none() == FAILURE) {
2357 		return;
2358 	}
2359 
2360 	spl_filesystem_file_rewind(getThis(), intern);
2361 } /* }}} */
2362 
2363 /* {{{ proto void SplFileObject::eof()
2364    Return whether end of file is reached */
SPL_METHOD(SplFileObject,eof)2365 SPL_METHOD(SplFileObject, eof)
2366 {
2367 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2368 
2369 	if (zend_parse_parameters_none() == FAILURE) {
2370 		return;
2371 	}
2372 
2373 	if(!intern->u.file.stream) {
2374 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2375 		return;
2376 	}
2377 
2378 	RETURN_BOOL(php_stream_eof(intern->u.file.stream));
2379 } /* }}} */
2380 
2381 /* {{{ proto void SplFileObject::valid()
2382    Return !eof() */
SPL_METHOD(SplFileObject,valid)2383 SPL_METHOD(SplFileObject, valid)
2384 {
2385 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2386 
2387 	if (zend_parse_parameters_none() == FAILURE) {
2388 		return;
2389 	}
2390 
2391 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2392 		RETURN_BOOL(intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval));
2393 	} else {
2394 		if(!intern->u.file.stream) {
2395 			RETURN_FALSE;
2396 		}
2397 		RETVAL_BOOL(!php_stream_eof(intern->u.file.stream));
2398 	}
2399 } /* }}} */
2400 
2401 /* {{{ proto string SplFileObject::fgets()
2402    Rturn next line from file */
SPL_METHOD(SplFileObject,fgets)2403 SPL_METHOD(SplFileObject, fgets)
2404 {
2405 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2406 
2407 	if (zend_parse_parameters_none() == FAILURE) {
2408 		return;
2409 	}
2410 
2411 	if(!intern->u.file.stream) {
2412 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2413 		return;
2414 	}
2415 
2416 	if (spl_filesystem_file_read(intern, 0) == FAILURE) {
2417 		RETURN_FALSE;
2418 	}
2419 	RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len);
2420 } /* }}} */
2421 
2422 /* {{{ proto string SplFileObject::current()
2423    Return current line from file */
SPL_METHOD(SplFileObject,current)2424 SPL_METHOD(SplFileObject, current)
2425 {
2426 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2427 
2428 	if (zend_parse_parameters_none() == FAILURE) {
2429 		return;
2430 	}
2431 
2432 	if(!intern->u.file.stream) {
2433 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2434 		return;
2435 	}
2436 
2437 	if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) {
2438 		spl_filesystem_file_read_line(getThis(), intern, 1);
2439 	}
2440 	if (intern->u.file.current_line && (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || Z_ISUNDEF(intern->u.file.current_zval))) {
2441 		RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len);
2442 	} else if (!Z_ISUNDEF(intern->u.file.current_zval)) {
2443 		zval *value = &intern->u.file.current_zval;
2444 
2445 		ZVAL_COPY_DEREF(return_value, value);
2446 		return;
2447 	}
2448 	RETURN_FALSE;
2449 } /* }}} */
2450 
2451 /* {{{ proto int SplFileObject::key()
2452    Return line number */
SPL_METHOD(SplFileObject,key)2453 SPL_METHOD(SplFileObject, key)
2454 {
2455 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2456 
2457 	if (zend_parse_parameters_none() == FAILURE) {
2458 		return;
2459 	}
2460 
2461 /*	Do not read the next line to support correct counting with fgetc()
2462 	if (!intern->current_line) {
2463 		spl_filesystem_file_read_line(getThis(), intern, 1);
2464 	} */
2465 	RETURN_LONG(intern->u.file.current_line_num);
2466 } /* }}} */
2467 
2468 /* {{{ proto void SplFileObject::next()
2469    Read next line */
SPL_METHOD(SplFileObject,next)2470 SPL_METHOD(SplFileObject, next)
2471 {
2472 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2473 
2474 	if (zend_parse_parameters_none() == FAILURE) {
2475 		return;
2476 	}
2477 
2478 	spl_filesystem_file_free_line(intern);
2479 	if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) {
2480 		spl_filesystem_file_read_line(getThis(), intern, 1);
2481 	}
2482 	intern->u.file.current_line_num++;
2483 } /* }}} */
2484 
2485 /* {{{ proto void SplFileObject::setFlags(int flags)
2486    Set file handling flags */
SPL_METHOD(SplFileObject,setFlags)2487 SPL_METHOD(SplFileObject, setFlags)
2488 {
2489 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2490 
2491 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &intern->flags) == FAILURE) {
2492 		return;
2493 	}
2494 } /* }}} */
2495 
2496 /* {{{ proto int SplFileObject::getFlags()
2497    Get file handling flags */
SPL_METHOD(SplFileObject,getFlags)2498 SPL_METHOD(SplFileObject, getFlags)
2499 {
2500 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2501 
2502 	if (zend_parse_parameters_none() == FAILURE) {
2503 		return;
2504 	}
2505 
2506 	RETURN_LONG(intern->flags & SPL_FILE_OBJECT_MASK);
2507 } /* }}} */
2508 
2509 /* {{{ proto void SplFileObject::setMaxLineLen(int max_len)
2510    Set maximum line length */
SPL_METHOD(SplFileObject,setMaxLineLen)2511 SPL_METHOD(SplFileObject, setMaxLineLen)
2512 {
2513 	zend_long max_len;
2514 
2515 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2516 
2517 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &max_len) == FAILURE) {
2518 		return;
2519 	}
2520 
2521 	if (max_len < 0) {
2522 		zend_throw_exception_ex(spl_ce_DomainException, 0, "Maximum line length must be greater than or equal zero");
2523 		return;
2524 	}
2525 
2526 	intern->u.file.max_line_len = max_len;
2527 } /* }}} */
2528 
2529 /* {{{ proto int SplFileObject::getMaxLineLen()
2530    Get maximum line length */
SPL_METHOD(SplFileObject,getMaxLineLen)2531 SPL_METHOD(SplFileObject, getMaxLineLen)
2532 {
2533 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2534 
2535 	if (zend_parse_parameters_none() == FAILURE) {
2536 		return;
2537 	}
2538 
2539 	RETURN_LONG((zend_long)intern->u.file.max_line_len);
2540 } /* }}} */
2541 
2542 /* {{{ proto bool SplFileObject::hasChildren()
2543    Return false */
SPL_METHOD(SplFileObject,hasChildren)2544 SPL_METHOD(SplFileObject, hasChildren)
2545 {
2546 	if (zend_parse_parameters_none() == FAILURE) {
2547 		return;
2548 	}
2549 
2550 	RETURN_FALSE;
2551 } /* }}} */
2552 
2553 /* {{{ proto bool SplFileObject::getChildren()
2554    Read NULL */
SPL_METHOD(SplFileObject,getChildren)2555 SPL_METHOD(SplFileObject, getChildren)
2556 {
2557 	if (zend_parse_parameters_none() == FAILURE) {
2558 		return;
2559 	}
2560 	/* return NULL */
2561 } /* }}} */
2562 
2563 /* {{{ FileFunction */
2564 #define FileFunction(func_name) \
2565 SPL_METHOD(SplFileObject, func_name) \
2566 { \
2567 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis()); \
2568 	FileFunctionCall(func_name, ZEND_NUM_ARGS(), NULL); \
2569 }
2570 /* }}} */
2571 
2572 /* {{{ proto array SplFileObject::fgetcsv([string delimiter [, string enclosure [, escape = '\\']]])
2573    Return current line as csv */
SPL_METHOD(SplFileObject,fgetcsv)2574 SPL_METHOD(SplFileObject, fgetcsv)
2575 {
2576 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2577 	char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape;
2578 	char *delim = NULL, *enclo = NULL, *esc = NULL;
2579 	size_t d_len = 0, e_len = 0, esc_len = 0;
2580 
2581 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
2582 
2583 		if(!intern->u.file.stream) {
2584 			zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2585 			return;
2586 		}
2587 
2588 		switch(ZEND_NUM_ARGS())
2589 		{
2590 		case 3:
2591 			if (esc_len != 1) {
2592 				php_error_docref(NULL, E_WARNING, "escape must be a character");
2593 				RETURN_FALSE;
2594 			}
2595 			escape = esc[0];
2596 			/* no break */
2597 		case 2:
2598 			if (e_len != 1) {
2599 				php_error_docref(NULL, E_WARNING, "enclosure must be a character");
2600 				RETURN_FALSE;
2601 			}
2602 			enclosure = enclo[0];
2603 			/* no break */
2604 		case 1:
2605 			if (d_len != 1) {
2606 				php_error_docref(NULL, E_WARNING, "delimiter must be a character");
2607 				RETURN_FALSE;
2608 			}
2609 			delimiter = delim[0];
2610 			/* no break */
2611 		case 0:
2612 			break;
2613 		}
2614 		spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value);
2615 	}
2616 }
2617 /* }}} */
2618 
2619 /* {{{ proto int SplFileObject::fputcsv(array fields, [string delimiter [, string enclosure [, string escape]]])
2620    Output a field array as a CSV line */
SPL_METHOD(SplFileObject,fputcsv)2621 SPL_METHOD(SplFileObject, fputcsv)
2622 {
2623 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2624 	char delimiter = intern->u.file.delimiter, enclosure = intern->u.file.enclosure, escape = intern->u.file.escape;
2625 	char *delim = NULL, *enclo = NULL, *esc = NULL;
2626 	size_t d_len = 0, e_len = 0, esc_len = 0;
2627 	zend_long ret;
2628 	zval *fields = NULL;
2629 
2630 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|sss", &fields, &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
2631 		switch(ZEND_NUM_ARGS())
2632 		{
2633 		case 4:
2634 			if (esc_len != 1) {
2635 				php_error_docref(NULL, E_WARNING, "escape must be a character");
2636 				RETURN_FALSE;
2637 			}
2638 			escape = esc[0];
2639 			/* no break */
2640 		case 3:
2641 			if (e_len != 1) {
2642 				php_error_docref(NULL, E_WARNING, "enclosure must be a character");
2643 				RETURN_FALSE;
2644 			}
2645 			enclosure = enclo[0];
2646 			/* no break */
2647 		case 2:
2648 			if (d_len != 1) {
2649 				php_error_docref(NULL, E_WARNING, "delimiter must be a character");
2650 				RETURN_FALSE;
2651 			}
2652 			delimiter = delim[0];
2653 			/* no break */
2654 		case 1:
2655 		case 0:
2656 			break;
2657 		}
2658 		ret = php_fputcsv(intern->u.file.stream, fields, delimiter, enclosure, escape);
2659 		RETURN_LONG(ret);
2660 	}
2661 }
2662 /* }}} */
2663 
2664 /* {{{ proto void SplFileObject::setCsvControl([string delimiter [, string enclosure [, string escape ]]])
2665    Set the delimiter, enclosure and escape character used in fgetcsv */
SPL_METHOD(SplFileObject,setCsvControl)2666 SPL_METHOD(SplFileObject, setCsvControl)
2667 {
2668 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2669 	char delimiter = ',', enclosure = '"', escape='\\';
2670 	char *delim = NULL, *enclo = NULL, *esc = NULL;
2671 	size_t d_len = 0, e_len = 0, esc_len = 0;
2672 
2673 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sss", &delim, &d_len, &enclo, &e_len, &esc, &esc_len) == SUCCESS) {
2674 		switch(ZEND_NUM_ARGS())
2675 		{
2676 		case 3:
2677 			if (esc_len != 1) {
2678 				php_error_docref(NULL, E_WARNING, "escape must be a character");
2679 				RETURN_FALSE;
2680 			}
2681 			escape = esc[0];
2682 			/* no break */
2683 		case 2:
2684 			if (e_len != 1) {
2685 				php_error_docref(NULL, E_WARNING, "enclosure must be a character");
2686 				RETURN_FALSE;
2687 			}
2688 			enclosure = enclo[0];
2689 			/* no break */
2690 		case 1:
2691 			if (d_len != 1) {
2692 				php_error_docref(NULL, E_WARNING, "delimiter must be a character");
2693 				RETURN_FALSE;
2694 			}
2695 			delimiter = delim[0];
2696 			/* no break */
2697 		case 0:
2698 			break;
2699 		}
2700 		intern->u.file.delimiter = delimiter;
2701 		intern->u.file.enclosure = enclosure;
2702 		intern->u.file.escape    = escape;
2703 	}
2704 }
2705 /* }}} */
2706 
2707 /* {{{ proto array SplFileObject::getCsvControl()
2708    Get the delimiter, enclosure and escape character used in fgetcsv */
SPL_METHOD(SplFileObject,getCsvControl)2709 SPL_METHOD(SplFileObject, getCsvControl)
2710 {
2711 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2712 	char delimiter[2], enclosure[2], escape[2];
2713 
2714 	array_init(return_value);
2715 
2716 	delimiter[0] = intern->u.file.delimiter;
2717 	delimiter[1] = '\0';
2718 	enclosure[0] = intern->u.file.enclosure;
2719 	enclosure[1] = '\0';
2720 	escape[0] = intern->u.file.escape;
2721 	escape[1] = '\0';
2722 
2723 	add_next_index_string(return_value, delimiter);
2724 	add_next_index_string(return_value, enclosure);
2725 	add_next_index_string(return_value, escape);
2726 }
2727 /* }}} */
2728 
2729 /* {{{ proto bool SplFileObject::flock(int operation [, int &wouldblock])
2730    Portable file locking */
2731 FileFunction(flock)
2732 /* }}} */
2733 
2734 /* {{{ proto bool SplFileObject::fflush()
2735    Flush the file */
SPL_METHOD(SplFileObject,fflush)2736 SPL_METHOD(SplFileObject, fflush)
2737 {
2738 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2739 
2740 	if(!intern->u.file.stream) {
2741 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2742 		return;
2743 	}
2744 
2745 	RETURN_BOOL(!php_stream_flush(intern->u.file.stream));
2746 } /* }}} */
2747 
2748 /* {{{ proto int SplFileObject::ftell()
2749    Return current file position */
SPL_METHOD(SplFileObject,ftell)2750 SPL_METHOD(SplFileObject, ftell)
2751 {
2752 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2753 	zend_long ret;
2754 
2755 	if(!intern->u.file.stream) {
2756 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2757 		return;
2758 	}
2759 
2760 	ret = php_stream_tell(intern->u.file.stream);
2761 
2762 	if (ret == -1) {
2763 		RETURN_FALSE;
2764 	} else {
2765 		RETURN_LONG(ret);
2766 	}
2767 } /* }}} */
2768 
2769 /* {{{ proto int SplFileObject::fseek(int pos [, int whence = SEEK_SET])
2770    Return current file position */
SPL_METHOD(SplFileObject,fseek)2771 SPL_METHOD(SplFileObject, fseek)
2772 {
2773 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2774 	zend_long pos, whence = SEEK_SET;
2775 
2776 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &pos, &whence) == FAILURE) {
2777 		return;
2778 	}
2779 
2780 	if(!intern->u.file.stream) {
2781 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2782 		return;
2783 	}
2784 
2785 	spl_filesystem_file_free_line(intern);
2786 	RETURN_LONG(php_stream_seek(intern->u.file.stream, pos, (int)whence));
2787 } /* }}} */
2788 
2789 /* {{{ proto int SplFileObject::fgetc()
2790    Get a character form the file */
SPL_METHOD(SplFileObject,fgetc)2791 SPL_METHOD(SplFileObject, fgetc)
2792 {
2793 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2794 	char buf[2];
2795 	int result;
2796 
2797 	if(!intern->u.file.stream) {
2798 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2799 		return;
2800 	}
2801 
2802 	spl_filesystem_file_free_line(intern);
2803 
2804 	result = php_stream_getc(intern->u.file.stream);
2805 
2806 	if (result == EOF) {
2807 		RETVAL_FALSE;
2808 	} else {
2809 		if (result == '\n') {
2810 			intern->u.file.current_line_num++;
2811 		}
2812 		buf[0] = result;
2813 		buf[1] = '\0';
2814 
2815 		RETURN_STRINGL(buf, 1);
2816 	}
2817 } /* }}} */
2818 
2819 /* {{{ proto string SplFileObject::fgetss([string allowable_tags])
2820    Get a line from file pointer and strip HTML tags */
SPL_METHOD(SplFileObject,fgetss)2821 SPL_METHOD(SplFileObject, fgetss)
2822 {
2823 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2824 	zval arg2;
2825 
2826 	if(!intern->u.file.stream) {
2827 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2828 		return;
2829 	}
2830 
2831 	if (intern->u.file.max_line_len > 0) {
2832 		ZVAL_LONG(&arg2, intern->u.file.max_line_len);
2833 	} else {
2834 		ZVAL_LONG(&arg2, 1024);
2835 	}
2836 
2837 	spl_filesystem_file_free_line(intern);
2838 	intern->u.file.current_line_num++;
2839 
2840 	FileFunctionCall(fgetss, ZEND_NUM_ARGS(), &arg2);
2841 } /* }}} */
2842 
2843 /* {{{ proto int SplFileObject::fpassthru()
2844    Output all remaining data from a file pointer */
SPL_METHOD(SplFileObject,fpassthru)2845 SPL_METHOD(SplFileObject, fpassthru)
2846 {
2847 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2848 
2849 	if(!intern->u.file.stream) {
2850 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2851 		return;
2852 	}
2853 
2854 	RETURN_LONG(php_stream_passthru(intern->u.file.stream));
2855 } /* }}} */
2856 
2857 /* {{{ proto bool SplFileObject::fscanf(string format [, string ...])
2858    Implements a mostly ANSI compatible fscanf() */
SPL_METHOD(SplFileObject,fscanf)2859 SPL_METHOD(SplFileObject, fscanf)
2860 {
2861 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2862 
2863 	if(!intern->u.file.stream) {
2864 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2865 		return;
2866 	}
2867 
2868 	spl_filesystem_file_free_line(intern);
2869 	intern->u.file.current_line_num++;
2870 
2871 	FileFunctionCall(fscanf, ZEND_NUM_ARGS(), NULL);
2872 }
2873 /* }}} */
2874 
2875 /* {{{ proto mixed SplFileObject::fwrite(string str [, int length])
2876    Binary-safe file write */
SPL_METHOD(SplFileObject,fwrite)2877 SPL_METHOD(SplFileObject, fwrite)
2878 {
2879 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2880 	char *str;
2881 	size_t str_len;
2882 	zend_long length = 0;
2883 
2884 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &length) == FAILURE) {
2885 		return;
2886 	}
2887 
2888 	if(!intern->u.file.stream) {
2889 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2890 		return;
2891 	}
2892 
2893 	if (ZEND_NUM_ARGS() > 1) {
2894 		if (length >= 0) {
2895 			str_len = MIN((size_t)length, str_len);
2896 		} else {
2897 			/* Negative length given, nothing to write */
2898 			str_len = 0;
2899 		}
2900 	}
2901 	if (!str_len) {
2902 		RETURN_LONG(0);
2903 	}
2904 
2905 	RETURN_LONG(php_stream_write(intern->u.file.stream, str, str_len));
2906 } /* }}} */
2907 
SPL_METHOD(SplFileObject,fread)2908 SPL_METHOD(SplFileObject, fread)
2909 {
2910 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2911 	zend_long length = 0;
2912 
2913 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &length) == FAILURE) {
2914 		return;
2915 	}
2916 
2917 	if(!intern->u.file.stream) {
2918 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2919 		return;
2920 	}
2921 
2922 	if (length <= 0) {
2923 		php_error_docref(NULL, E_WARNING, "Length parameter must be greater than 0");
2924 		RETURN_FALSE;
2925 	}
2926 
2927 	ZVAL_NEW_STR(return_value, zend_string_alloc(length, 0));
2928 	Z_STRLEN_P(return_value) = php_stream_read(intern->u.file.stream, Z_STRVAL_P(return_value), length);
2929 
2930 	/* needed because recv/read/gzread doesn't put a null at the end*/
2931 	Z_STRVAL_P(return_value)[Z_STRLEN_P(return_value)] = 0;
2932 }
2933 
2934 /* {{{ proto bool SplFileObject::fstat()
2935    Stat() on a filehandle */
2936 FileFunction(fstat)
2937 /* }}} */
2938 
2939 /* {{{ proto bool SplFileObject::ftruncate(int size)
2940    Truncate file to 'size' length */
SPL_METHOD(SplFileObject,ftruncate)2941 SPL_METHOD(SplFileObject, ftruncate)
2942 {
2943 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2944 	zend_long size;
2945 
2946 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &size) == FAILURE) {
2947 		return;
2948 	}
2949 
2950 	if(!intern->u.file.stream) {
2951 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2952 		return;
2953 	}
2954 
2955 	if (!php_stream_truncate_supported(intern->u.file.stream)) {
2956 		zend_throw_exception_ex(spl_ce_LogicException, 0, "Can't truncate file %s", intern->file_name);
2957 		RETURN_FALSE;
2958 	}
2959 
2960 	RETURN_BOOL(0 == php_stream_truncate_set_size(intern->u.file.stream, size));
2961 } /* }}} */
2962 
2963 /* {{{ proto void SplFileObject::seek(int line_pos)
2964    Seek to specified line */
SPL_METHOD(SplFileObject,seek)2965 SPL_METHOD(SplFileObject, seek)
2966 {
2967 	spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(getThis());
2968 	zend_long line_pos;
2969 
2970 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &line_pos) == FAILURE) {
2971 		return;
2972 	}
2973 	if(!intern->u.file.stream) {
2974 		zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
2975 		return;
2976 	}
2977 
2978 	if (line_pos < 0) {
2979 		zend_throw_exception_ex(spl_ce_LogicException, 0, "Can't seek file %s to negative line " ZEND_LONG_FMT, intern->file_name, line_pos);
2980 		RETURN_FALSE;
2981 	}
2982 
2983 	spl_filesystem_file_rewind(getThis(), intern);
2984 
2985 	while(intern->u.file.current_line_num < line_pos) {
2986 		if (spl_filesystem_file_read_line(getThis(), intern, 1) == FAILURE) {
2987 			break;
2988 		}
2989 	}
2990 } /* }}} */
2991 
2992 /* {{{ Function/Class/Method definitions */
2993 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object___construct, 0, 0, 1)
2994 	ZEND_ARG_INFO(0, file_name)
2995 	ZEND_ARG_INFO(0, open_mode)
2996 	ZEND_ARG_INFO(0, use_include_path)
2997 	ZEND_ARG_INFO(0, context)
2998 ZEND_END_ARG_INFO()
2999 
3000 ZEND_BEGIN_ARG_INFO(arginfo_file_object_setFlags, 0)
3001 	ZEND_ARG_INFO(0, flags)
3002 ZEND_END_ARG_INFO()
3003 
3004 ZEND_BEGIN_ARG_INFO(arginfo_file_object_setMaxLineLen, 0)
3005 	ZEND_ARG_INFO(0, max_len)
3006 ZEND_END_ARG_INFO()
3007 
3008 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetcsv, 0, 0, 0)
3009 	ZEND_ARG_INFO(0, delimiter)
3010 	ZEND_ARG_INFO(0, enclosure)
3011 	ZEND_ARG_INFO(0, escape)
3012 ZEND_END_ARG_INFO()
3013 
3014 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fputcsv, 0, 0, 1)
3015 	ZEND_ARG_INFO(0, fields)
3016 	ZEND_ARG_INFO(0, delimiter)
3017 	ZEND_ARG_INFO(0, enclosure)
3018 	ZEND_ARG_INFO(0, escape)
3019 ZEND_END_ARG_INFO()
3020 
3021 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_flock, 0, 0, 1)
3022 	ZEND_ARG_INFO(0, operation)
3023 	ZEND_ARG_INFO(1, wouldblock)
3024 ZEND_END_ARG_INFO()
3025 
3026 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fseek, 0, 0, 1)
3027 	ZEND_ARG_INFO(0, pos)
3028 	ZEND_ARG_INFO(0, whence)
3029 ZEND_END_ARG_INFO()
3030 
3031 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetss, 0, 0, 0)
3032 	ZEND_ARG_INFO(0, allowable_tags)
3033 ZEND_END_ARG_INFO()
3034 
3035 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fscanf, 0, 0, 1)
3036 	ZEND_ARG_INFO(0, format)
3037 	ZEND_ARG_VARIADIC_INFO(1, vars)
3038 ZEND_END_ARG_INFO()
3039 
3040 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fwrite, 0, 0, 1)
3041 	ZEND_ARG_INFO(0, str)
3042 	ZEND_ARG_INFO(0, length)
3043 ZEND_END_ARG_INFO()
3044 
3045 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fread, 0, 0, 1)
3046 	ZEND_ARG_INFO(0, length)
3047 ZEND_END_ARG_INFO()
3048 
3049 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_ftruncate, 0, 0, 1)
3050 	ZEND_ARG_INFO(0, size)
3051 ZEND_END_ARG_INFO()
3052 
3053 ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_seek, 0, 0, 1)
3054 	ZEND_ARG_INFO(0, line_pos)
3055 ZEND_END_ARG_INFO()
3056 
3057 static const zend_function_entry spl_SplFileObject_functions[] = {
3058 	SPL_ME(SplFileObject, __construct,    arginfo_file_object___construct,   ZEND_ACC_PUBLIC)
3059 	SPL_ME(SplFileObject, rewind,         arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3060 	SPL_ME(SplFileObject, eof,            arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3061 	SPL_ME(SplFileObject, valid,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3062 	SPL_ME(SplFileObject, fgets,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3063 	SPL_ME(SplFileObject, fgetcsv,        arginfo_file_object_fgetcsv,       ZEND_ACC_PUBLIC)
3064 	SPL_ME(SplFileObject, fputcsv,        arginfo_file_object_fputcsv,       ZEND_ACC_PUBLIC)
3065 	SPL_ME(SplFileObject, setCsvControl,  arginfo_file_object_fgetcsv,       ZEND_ACC_PUBLIC)
3066 	SPL_ME(SplFileObject, getCsvControl,  arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3067 	SPL_ME(SplFileObject, flock,          arginfo_file_object_flock,         ZEND_ACC_PUBLIC)
3068 	SPL_ME(SplFileObject, fflush,         arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3069 	SPL_ME(SplFileObject, ftell,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3070 	SPL_ME(SplFileObject, fseek,          arginfo_file_object_fseek,         ZEND_ACC_PUBLIC)
3071 	SPL_ME(SplFileObject, fgetc,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3072 	SPL_ME(SplFileObject, fpassthru,      arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3073 	SPL_ME(SplFileObject, fgetss,         arginfo_file_object_fgetss,        ZEND_ACC_PUBLIC)
3074 	SPL_ME(SplFileObject, fscanf,         arginfo_file_object_fscanf,        ZEND_ACC_PUBLIC)
3075 	SPL_ME(SplFileObject, fwrite,         arginfo_file_object_fwrite,        ZEND_ACC_PUBLIC)
3076 	SPL_ME(SplFileObject, fread,          arginfo_file_object_fread,         ZEND_ACC_PUBLIC)
3077 	SPL_ME(SplFileObject, fstat,          arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3078 	SPL_ME(SplFileObject, ftruncate,      arginfo_file_object_ftruncate,     ZEND_ACC_PUBLIC)
3079 	SPL_ME(SplFileObject, current,        arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3080 	SPL_ME(SplFileObject, key,            arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3081 	SPL_ME(SplFileObject, next,           arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3082 	SPL_ME(SplFileObject, setFlags,       arginfo_file_object_setFlags,      ZEND_ACC_PUBLIC)
3083 	SPL_ME(SplFileObject, getFlags,       arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3084 	SPL_ME(SplFileObject, setMaxLineLen,  arginfo_file_object_setMaxLineLen, ZEND_ACC_PUBLIC)
3085 	SPL_ME(SplFileObject, getMaxLineLen,  arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3086 	SPL_ME(SplFileObject, hasChildren,    arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3087 	SPL_ME(SplFileObject, getChildren,    arginfo_splfileinfo_void,          ZEND_ACC_PUBLIC)
3088 	SPL_ME(SplFileObject, seek,           arginfo_file_object_seek,          ZEND_ACC_PUBLIC)
3089 	/* mappings */
3090 	SPL_MA(SplFileObject, getCurrentLine, SplFileObject, fgets,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
3091 	SPL_MA(SplFileObject, __toString,     SplFileObject, fgets,      arginfo_splfileinfo_void, ZEND_ACC_PUBLIC)
3092 	PHP_FE_END
3093 };
3094 
3095 ZEND_BEGIN_ARG_INFO_EX(arginfo_temp_file_object___construct, 0, 0, 0)
3096 	ZEND_ARG_INFO(0, max_memory)
3097 ZEND_END_ARG_INFO()
3098 
3099 static const zend_function_entry spl_SplTempFileObject_functions[] = {
3100 	SPL_ME(SplTempFileObject, __construct, arginfo_temp_file_object___construct,  ZEND_ACC_PUBLIC)
3101 	PHP_FE_END
3102 };
3103 /* }}} */
3104 
3105 /* {{{ PHP_MINIT_FUNCTION(spl_directory)
3106  */
PHP_MINIT_FUNCTION(spl_directory)3107 PHP_MINIT_FUNCTION(spl_directory)
3108 {
3109 	REGISTER_SPL_STD_CLASS_EX(SplFileInfo, spl_filesystem_object_new, spl_SplFileInfo_functions);
3110 	memcpy(&spl_filesystem_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
3111 	spl_filesystem_object_handlers.offset = XtOffsetOf(spl_filesystem_object, std);
3112 	spl_filesystem_object_handlers.clone_obj = spl_filesystem_object_clone;
3113 	spl_filesystem_object_handlers.cast_object = spl_filesystem_object_cast;
3114 	spl_filesystem_object_handlers.get_debug_info  = spl_filesystem_object_get_debug_info;
3115 	spl_filesystem_object_handlers.dtor_obj = spl_filesystem_object_destroy_object;
3116 	spl_filesystem_object_handlers.free_obj = spl_filesystem_object_free_storage;
3117 	spl_ce_SplFileInfo->serialize = zend_class_serialize_deny;
3118 	spl_ce_SplFileInfo->unserialize = zend_class_unserialize_deny;
3119 
3120 
3121 	REGISTER_SPL_SUB_CLASS_EX(DirectoryIterator, SplFileInfo, spl_filesystem_object_new, spl_DirectoryIterator_functions);
3122 	zend_class_implements(spl_ce_DirectoryIterator, 1, zend_ce_iterator);
3123 	REGISTER_SPL_IMPLEMENTS(DirectoryIterator, SeekableIterator);
3124 
3125 	spl_ce_DirectoryIterator->get_iterator = spl_filesystem_dir_get_iterator;
3126 
3127 	REGISTER_SPL_SUB_CLASS_EX(FilesystemIterator, DirectoryIterator, spl_filesystem_object_new, spl_FilesystemIterator_functions);
3128 
3129 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_MODE_MASK",   SPL_FILE_DIR_CURRENT_MODE_MASK);
3130 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_PATHNAME", SPL_FILE_DIR_CURRENT_AS_PATHNAME);
3131 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_FILEINFO", SPL_FILE_DIR_CURRENT_AS_FILEINFO);
3132 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "CURRENT_AS_SELF",     SPL_FILE_DIR_CURRENT_AS_SELF);
3133 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_MODE_MASK",       SPL_FILE_DIR_KEY_MODE_MASK);
3134 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_PATHNAME",     SPL_FILE_DIR_KEY_AS_PATHNAME);
3135 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "FOLLOW_SYMLINKS",     SPL_FILE_DIR_FOLLOW_SYMLINKS);
3136 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "KEY_AS_FILENAME",     SPL_FILE_DIR_KEY_AS_FILENAME);
3137 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "NEW_CURRENT_AND_KEY", SPL_FILE_DIR_KEY_AS_FILENAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO);
3138 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "OTHER_MODE_MASK",     SPL_FILE_DIR_OTHERS_MASK);
3139 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "SKIP_DOTS",           SPL_FILE_DIR_SKIPDOTS);
3140 	REGISTER_SPL_CLASS_CONST_LONG(FilesystemIterator, "UNIX_PATHS",          SPL_FILE_DIR_UNIXPATHS);
3141 
3142 	spl_ce_FilesystemIterator->get_iterator = spl_filesystem_tree_get_iterator;
3143 
3144 	REGISTER_SPL_SUB_CLASS_EX(RecursiveDirectoryIterator, FilesystemIterator, spl_filesystem_object_new, spl_RecursiveDirectoryIterator_functions);
3145 	REGISTER_SPL_IMPLEMENTS(RecursiveDirectoryIterator, RecursiveIterator);
3146 
3147 	memcpy(&spl_filesystem_object_check_handlers, &spl_filesystem_object_handlers, sizeof(zend_object_handlers));
3148 	spl_filesystem_object_check_handlers.clone_obj = NULL;
3149 	spl_filesystem_object_check_handlers.get_method = spl_filesystem_object_get_method_check;
3150 
3151 #ifdef HAVE_GLOB
3152 	REGISTER_SPL_SUB_CLASS_EX(GlobIterator, FilesystemIterator, spl_filesystem_object_new_check, spl_GlobIterator_functions);
3153 	REGISTER_SPL_IMPLEMENTS(GlobIterator, Countable);
3154 #endif
3155 
3156 	REGISTER_SPL_SUB_CLASS_EX(SplFileObject, SplFileInfo, spl_filesystem_object_new_check, spl_SplFileObject_functions);
3157 	REGISTER_SPL_IMPLEMENTS(SplFileObject, RecursiveIterator);
3158 	REGISTER_SPL_IMPLEMENTS(SplFileObject, SeekableIterator);
3159 
3160 	REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "DROP_NEW_LINE", SPL_FILE_OBJECT_DROP_NEW_LINE);
3161 	REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_AHEAD",    SPL_FILE_OBJECT_READ_AHEAD);
3162 	REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "SKIP_EMPTY",    SPL_FILE_OBJECT_SKIP_EMPTY);
3163 	REGISTER_SPL_CLASS_CONST_LONG(SplFileObject, "READ_CSV",      SPL_FILE_OBJECT_READ_CSV);
3164 
3165 	REGISTER_SPL_SUB_CLASS_EX(SplTempFileObject, SplFileObject, spl_filesystem_object_new_check, spl_SplTempFileObject_functions);
3166 	return SUCCESS;
3167 }
3168 /* }}} */
3169 
3170 /*
3171  * Local variables:
3172  * tab-width: 4
3173  * c-basic-offset: 4
3174  * End:
3175  * vim600: noet sw=4 ts=4 fdm=marker
3176  * vim<600: noet sw=4 ts=4
3177  */
3178