Coverage Report

Created: 2026-09-14 06:25

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