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