Coverage Report

Created: 2025-06-13 06:43

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