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 */
48static zend_object_handlers spl_filesystem_object_handlers;
49/* includes handler to validate object state when retrieving methods */
50static zend_object_handlers spl_filesystem_object_check_handlers;
51
52/* decalre the class entry */
53PHPAPI zend_class_entry *spl_ce_SplFileInfo;
54PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
55PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
56PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
57PHPAPI zend_class_entry *spl_ce_GlobIterator;
58PHPAPI zend_class_entry *spl_ce_SplFileObject;
59PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
60
61static 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
73static 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
107static 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 */
154static 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 */
173static 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 */
180static 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
188PHPAPI 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
203static 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
234static 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
247static 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 */
255static 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
285static 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 */
349static 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
401void 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
435static 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
478static 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
578static 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
584static 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
602static 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
680zend_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
699void 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. */
761SPL_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 */
769SPL_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 */
787SPL_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) */
805SPL_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 */
817SPL_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 */
839SPL_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 */
869SPL_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 */
883SPL_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 */
900SPL_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 */
921SPL_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 */
935SPL_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 */
976SPL_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 */
1003SPL_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 */
1030SPL_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 */
1049SPL_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 */
1069SPL_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 */
1088SPL_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  '..' */
1112SPL_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 */
1129SPL_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) \
1149SPL_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 */
1166FileInfoFunction(getPerms, FS_PERMS)
1167/* }}} */
1168
1169/* {{{ proto int SplFileInfo::getInode()
1170   Get file inode */
1171FileInfoFunction(getInode, FS_INODE)
1172/* }}} */
1173
1174/* {{{ proto int SplFileInfo::getSize()
1175   Get file size */
1176FileInfoFunction(getSize, FS_SIZE)
1177/* }}} */
1178
1179/* {{{ proto int SplFileInfo::getOwner()
1180   Get file owner */
1181FileInfoFunction(getOwner, FS_OWNER)
1182/* }}} */
1183
1184/* {{{ proto int SplFileInfo::getGroup()
1185   Get file group */
1186FileInfoFunction(getGroup, FS_GROUP)
1187/* }}} */
1188
1189/* {{{ proto int SplFileInfo::getATime()
1190   Get last access time of file */
1191FileInfoFunction(getATime, FS_ATIME)
1192/* }}} */
1193
1194/* {{{ proto int SplFileInfo::getMTime()
1195   Get last modification time of file */
1196FileInfoFunction(getMTime, FS_MTIME)
1197/* }}} */
1198
1199/* {{{ proto int SplFileInfo::getCTime()
1200   Get inode modification time of file */
1201FileInfoFunction(getCTime, FS_CTIME)
1202/* }}} */
1203
1204/* {{{ proto string SplFileInfo::getType()
1205   Get file type */
1206FileInfoFunction(getType, FS_TYPE)
1207/* }}} */
1208
1209/* {{{ proto bool SplFileInfo::isWritable()
1210   Returns true if file can be written */
1211FileInfoFunction(isWritable, FS_IS_W)
1212/* }}} */
1213
1214/* {{{ proto bool SplFileInfo::isReadable()
1215   Returns true if file can be read */
1216FileInfoFunction(isReadable, FS_IS_R)
1217/* }}} */
1218
1219/* {{{ proto bool SplFileInfo::isExecutable()
1220   Returns true if file is executable */
1221FileInfoFunction(isExecutable, FS_IS_X)
1222/* }}} */
1223
1224/* {{{ proto bool SplFileInfo::isFile()
1225   Returns true if file is a regular file */
1226FileInfoFunction(isFile, FS_IS_FILE)
1227/* }}} */
1228
1229/* {{{ proto bool SplFileInfo::isDir()
1230   Returns true if file is directory */
1231FileInfoFunction(isDir, FS_IS_DIR)
1232/* }}} */
1233
1234/* {{{ proto bool SplFileInfo::isLink()
1235   Returns true if file is symbolic link */
1236FileInfoFunction(isLink, FS_IS_LINK)
1237/* }}} */
1238
1239/* {{{ proto string SplFileInfo::getLinkTarget()
1240   Return the target of a symbolic link */
1241SPL_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 */
1292SPL_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 */
1334SPL_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() */
1344SPL_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() */
1362SPL_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 */
1380SPL_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 */
1398SPL_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) */
1422SPL_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. */
1432SPL_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 */
1440SPL_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 */
1461SPL_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 */
1474SPL_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 '..' */
1489SPL_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 */
1514SPL_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 */
1549SPL_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 */
1567SPL_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. */
1586SPL_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). */
1595SPL_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 */
1603SPL_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 */
1622static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter);
1623static int spl_filesystem_dir_it_valid(zend_object_iterator *iter);
1624static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter);
1625static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key);
1626static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter);
1627static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter);
1628
1629/* iterator handler table */
1630static 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 */
1642zend_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 */
1664static 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 */
1680static 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 */
1689static 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 */
1698static 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 */
1707static 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 */
1721static 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 */
1734static 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 */
1751static 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 */
1775static 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 */
1789static 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 */
1810static 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 */
1830static 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 */
1842zend_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 */
1862static 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 */
1891ZEND_BEGIN_ARG_INFO(arginfo_info___construct, 0)
1892	ZEND_ARG_INFO(0, file_name)
1893ZEND_END_ARG_INFO()
1894
1895ZEND_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)
1899ZEND_END_ARG_INFO()
1900
1901ZEND_BEGIN_ARG_INFO_EX(arginfo_info_optinalFileClass, 0, 0, 0)
1902	ZEND_ARG_INFO(0, class_name)
1903ZEND_END_ARG_INFO()
1904
1905ZEND_BEGIN_ARG_INFO_EX(arginfo_optinalSuffix, 0, 0, 0)
1906	ZEND_ARG_INFO(0, suffix)
1907ZEND_END_ARG_INFO()
1908
1909ZEND_BEGIN_ARG_INFO(arginfo_splfileinfo_void, 0)
1910ZEND_END_ARG_INFO()
1911
1912/* the method table */
1913/* each method can have its own parameters and visibility */
1914static 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
1950ZEND_BEGIN_ARG_INFO(arginfo_dir___construct, 0)
1951	ZEND_ARG_INFO(0, path)
1952ZEND_END_ARG_INFO()
1953
1954ZEND_BEGIN_ARG_INFO(arginfo_dir_it_seek, 0)
1955	ZEND_ARG_INFO(0, position)
1956ZEND_END_ARG_INFO();
1957
1958/* the method table */
1959/* each method can have its own parameters and visibility */
1960static 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
1976ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir___construct, 0, 0, 1)
1977	ZEND_ARG_INFO(0, path)
1978	ZEND_ARG_INFO(0, flags)
1979ZEND_END_ARG_INFO()
1980
1981ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_hasChildren, 0, 0, 0)
1982	ZEND_ARG_INFO(0, allow_links)
1983ZEND_END_ARG_INFO()
1984
1985ZEND_BEGIN_ARG_INFO_EX(arginfo_r_dir_setFlags, 0, 0, 0)
1986	ZEND_ARG_INFO(0, flags)
1987ZEND_END_ARG_INFO()
1988
1989static 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
2000static 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
2010static 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
2018static 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
2062static 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
2124static 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
2153static 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
2194static 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
2226static 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
2239static 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 */
2258SPL_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 */
2318SPL_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 */
2352SPL_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 */
2365SPL_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() */
2383SPL_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 */
2403SPL_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 */
2424SPL_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 */
2453SPL_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 */
2470SPL_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 */
2487SPL_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 */
2498SPL_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 */
2511SPL_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 */
2531SPL_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 */
2544SPL_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 */
2555SPL_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) \
2565SPL_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 */
2574SPL_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 */
2621SPL_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 */
2666SPL_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 */
2709SPL_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 */
2731FileFunction(flock)
2732/* }}} */
2733
2734/* {{{ proto bool SplFileObject::fflush()
2735   Flush the file */
2736SPL_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 */
2750SPL_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 */
2771SPL_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 */
2791SPL_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 */
2821SPL_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 */
2845SPL_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() */
2859SPL_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 */
2877SPL_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
2908SPL_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 */
2936FileFunction(fstat)
2937/* }}} */
2938
2939/* {{{ proto bool SplFileObject::ftruncate(int size)
2940   Truncate file to 'size' length */
2941SPL_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 */
2965SPL_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 */
2993ZEND_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)
2998ZEND_END_ARG_INFO()
2999
3000ZEND_BEGIN_ARG_INFO(arginfo_file_object_setFlags, 0)
3001	ZEND_ARG_INFO(0, flags)
3002ZEND_END_ARG_INFO()
3003
3004ZEND_BEGIN_ARG_INFO(arginfo_file_object_setMaxLineLen, 0)
3005	ZEND_ARG_INFO(0, max_len)
3006ZEND_END_ARG_INFO()
3007
3008ZEND_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)
3012ZEND_END_ARG_INFO()
3013
3014ZEND_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)
3019ZEND_END_ARG_INFO()
3020
3021ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_flock, 0, 0, 1)
3022	ZEND_ARG_INFO(0, operation)
3023	ZEND_ARG_INFO(1, wouldblock)
3024ZEND_END_ARG_INFO()
3025
3026ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fseek, 0, 0, 1)
3027	ZEND_ARG_INFO(0, pos)
3028	ZEND_ARG_INFO(0, whence)
3029ZEND_END_ARG_INFO()
3030
3031ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetss, 0, 0, 0)
3032	ZEND_ARG_INFO(0, allowable_tags)
3033ZEND_END_ARG_INFO()
3034
3035ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fscanf, 0, 0, 1)
3036	ZEND_ARG_INFO(0, format)
3037	ZEND_ARG_VARIADIC_INFO(1, vars)
3038ZEND_END_ARG_INFO()
3039
3040ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fwrite, 0, 0, 1)
3041	ZEND_ARG_INFO(0, str)
3042	ZEND_ARG_INFO(0, length)
3043ZEND_END_ARG_INFO()
3044
3045ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fread, 0, 0, 1)
3046	ZEND_ARG_INFO(0, length)
3047ZEND_END_ARG_INFO()
3048
3049ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_ftruncate, 0, 0, 1)
3050	ZEND_ARG_INFO(0, size)
3051ZEND_END_ARG_INFO()
3052
3053ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_seek, 0, 0, 1)
3054	ZEND_ARG_INFO(0, line_pos)
3055ZEND_END_ARG_INFO()
3056
3057static 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
3095ZEND_BEGIN_ARG_INFO_EX(arginfo_temp_file_object___construct, 0, 0, 0)
3096	ZEND_ARG_INFO(0, max_memory)
3097ZEND_END_ARG_INFO()
3098
3099static 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 */
3107PHP_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