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