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