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