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