Coverage Report

Created: 2025-09-27 06:26

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