php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
filestat.c
Go to the documentation of this file.
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: Jim Winstead <jimw@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17#include "php.h"
18#include "fopen_wrappers.h"
19#include "php_globals.h"
20
21#include <stdlib.h>
22#include <sys/stat.h>
23#include <string.h>
24#include <errno.h>
25#include <ctype.h>
26#include <time.h>
27
28#ifdef HAVE_UNISTD_H
29# include <unistd.h>
30#endif
31
32#ifdef HAVE_SYS_PARAM_H
33# include <sys/param.h>
34#endif
35
36#ifdef HAVE_SYS_VFS_H
37# include <sys/vfs.h>
38#endif
39
40#if defined(__APPLE__)
41 /*
42 Apple statvfs has an interger overflow in libc copying to statvfs.
43 cvt_statfs_to_statvfs(struct statfs *from, struct statvfs *to) {
44 to->f_blocks = (fsblkcnt_t)from->f_blocks;
45 */
46# undef HAVE_SYS_STATVFS_H
47# undef HAVE_STATVFS
48#endif
49
50#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
51# include <sys/statvfs.h>
52#elif defined(HAVE_SYS_STATFS_H) && defined(HAVE_STATFS)
53# include <sys/statfs.h>
54#elif defined(HAVE_SYS_MOUNT_H) && defined(HAVE_STATFS)
55# include <sys/mount.h>
56#endif
57
58#ifdef HAVE_PWD_H
59# ifdef PHP_WIN32
60# include "win32/pwd.h"
61# else
62# include <pwd.h>
63# endif
64#endif
65
66#ifdef HAVE_GRP_H
67# include <grp.h>
68#endif
69
70#ifdef HAVE_UTIME
71# ifdef PHP_WIN32
72# include <sys/utime.h>
73# else
74# include <utime.h>
75# endif
76#endif
77
78#ifdef PHP_WIN32
79#include "win32/winutil.h"
80#endif
81
82#include "basic_functions.h"
83#include "php_filestat.h"
84
86{
87 BG(CurrentStatFile)=NULL;
88 BG(CurrentLStatFile)=NULL;
89 return SUCCESS;
90}
91/* }}} */
92
94{
95 if (BG(CurrentStatFile)) {
96 zend_string_release(BG(CurrentStatFile));
97 BG(CurrentStatFile) = NULL;
98 }
99 if (BG(CurrentLStatFile)) {
100 zend_string_release(BG(CurrentLStatFile));
101 BG(CurrentLStatFile) = NULL;
102 }
103 return SUCCESS;
104}
105/* }}} */
106
107static zend_result php_disk_total_space(char *path, double *space) /* {{{ */
108#if defined(PHP_WIN32) /* {{{ */
109{
110 ULARGE_INTEGER FreeBytesAvailableToCaller;
111 ULARGE_INTEGER TotalNumberOfBytes;
112 ULARGE_INTEGER TotalNumberOfFreeBytes;
114
115 if (GetDiskFreeSpaceExW(pathw, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) == 0) {
116 char *err = php_win_err();
121 }
122
123 /* i know - this is ugly, but i works <thies@thieso.net> */
124 *space = TotalNumberOfBytes.HighPart * (double) (((zend_ulong)1) << 31) * 2.0 + TotalNumberOfBytes.LowPart;
125
127
129}
130/* }}} */
131#else /* {{{ if !defined(PHP_WIN32) */
132{
133 double bytestotal = 0;
134#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
135 struct statvfs buf;
136#elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS)
137 struct statfs buf;
138#endif
139
140#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
141 if (statvfs(path, &buf)) {
142 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
143 return FAILURE;
144 }
145 if (buf.f_frsize) {
146 bytestotal = (((double)buf.f_blocks) * ((double)buf.f_frsize));
147 } else {
148 bytestotal = (((double)buf.f_blocks) * ((double)buf.f_bsize));
149 }
150
151#elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS)
152 if (statfs(path, &buf)) {
153 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
154 return FAILURE;
155 }
156 bytestotal = (((double)buf.f_bsize) * ((double)buf.f_blocks));
157#endif
158
159 *space = bytestotal;
160 return SUCCESS;
161}
162#endif
163/* }}} */
164/* }}} */
165
166/* {{{ Get total disk space for filesystem that path is on */
168{
169 double bytestotal;
170 char *path, fullpath[MAXPATHLEN];
171 size_t path_len;
172
174 Z_PARAM_PATH(path, path_len)
176
177 if (!expand_filepath(path, fullpath)) {
179 }
180
181 if (php_check_open_basedir(fullpath)) {
183 }
184
185 if (php_disk_total_space(fullpath, &bytestotal) == SUCCESS) {
186 RETURN_DOUBLE(bytestotal);
187 }
189}
190/* }}} */
191
192static zend_result php_disk_free_space(char *path, double *space) /* {{{ */
193#if defined(PHP_WIN32) /* {{{ */
194{
195 ULARGE_INTEGER FreeBytesAvailableToCaller;
196 ULARGE_INTEGER TotalNumberOfBytes;
197 ULARGE_INTEGER TotalNumberOfFreeBytes;
199
200 if (GetDiskFreeSpaceExW(pathw, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, &TotalNumberOfFreeBytes) == 0) {
201 char *err = php_win_err();
206 }
207
208 *space = FreeBytesAvailableToCaller.HighPart * (double) (1ULL << 32) + FreeBytesAvailableToCaller.LowPart;
209
211
213}
214#else /* {{{ if !defined(PHP_WIN32) */
215{
216 double bytesfree = 0;
217#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
218 struct statvfs buf;
219#elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS)
220 struct statfs buf;
221#endif
222
223#if defined(HAVE_SYS_STATVFS_H) && defined(HAVE_STATVFS)
224 if (statvfs(path, &buf)) {
225 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
226 return FAILURE;
227 }
228 if (buf.f_frsize) {
229 bytesfree = (((double)buf.f_bavail) * ((double)buf.f_frsize));
230 } else {
231 bytesfree = (((double)buf.f_bavail) * ((double)buf.f_bsize));
232 }
233#elif (defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_MOUNT_H)) && defined(HAVE_STATFS)
234 if (statfs(path, &buf)) {
235 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
236 return FAILURE;
237 }
238 bytesfree = (((double)buf.f_bsize) * ((double)buf.f_bavail));
239#endif
240
241 *space = bytesfree;
242 return SUCCESS;
243}
244#endif
245/* }}} */
246/* }}} */
247
248/* {{{ Get free disk space for filesystem that path is on */
250{
251 double bytesfree;
252 char *path, fullpath[MAXPATHLEN];
253 size_t path_len;
254
256 Z_PARAM_PATH(path, path_len)
258
259 if (!expand_filepath(path, fullpath)) {
261 }
262
263 if (php_check_open_basedir(fullpath)) {
265 }
266
267 if (php_disk_free_space(fullpath, &bytesfree) == SUCCESS) {
268 RETURN_DOUBLE(bytesfree);
269 }
271}
272/* }}} */
273
274#ifndef PHP_WIN32
276{
277#if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
278 struct group gr;
279 struct group *retgrptr;
280 long grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
281 char *grbuf;
282 int err;
283
284 if (grbuflen < 1) {
285 grbuflen = 1024;
286 }
287# if ZEND_DEBUG
288 /* Test retry logic */
289 grbuflen = 1;
290# endif
291 grbuf = emalloc(grbuflen);
292
293try_again:
294 err = getgrnam_r(name, &gr, grbuf, grbuflen, &retgrptr);
295 if (err != 0 || retgrptr == NULL) {
296 if (err == ERANGE) {
297 grbuflen *= 2;
298 grbuf = erealloc(grbuf, grbuflen);
299 goto try_again;
300 }
301 efree(grbuf);
302 return FAILURE;
303 }
304 efree(grbuf);
305 *gid = gr.gr_gid;
306#else
307 struct group *gr = getgrnam(name);
308
309 if (!gr) {
310 return FAILURE;
311 }
312 *gid = gr->gr_gid;
313#endif
314 return SUCCESS;
315}
316#endif
317
318static void php_do_chgrp(INTERNAL_FUNCTION_PARAMETERS, int do_lchgrp) /* {{{ */
319{
320 char *filename;
321 size_t filename_len;
322 zend_string *group_str;
323 zend_long group_long;
324#if !defined(PHP_WIN32)
325 gid_t gid;
326 int ret;
327#endif
328 php_stream_wrapper *wrapper;
329
331 Z_PARAM_PATH(filename, filename_len)
332 Z_PARAM_STR_OR_LONG(group_str, group_long)
334
335 wrapper = php_stream_locate_url_wrapper(filename, NULL, 0);
336 if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
337 if(wrapper && wrapper->wops->stream_metadata) {
338 int option;
339 void *value;
340 if (group_str) {
341 option = PHP_STREAM_META_GROUP_NAME;
342 value = ZSTR_VAL(group_str);
343 } else {
344 option = PHP_STREAM_META_GROUP;
345 value = &group_long;
346 }
347
348 if(wrapper->wops->stream_metadata(wrapper, filename, option, value, NULL)) {
349 RETURN_TRUE;
350 } else {
351 RETURN_FALSE;
352 }
353 } else {
354#ifndef PHP_WIN32
355/* On Windows, we expect regular chgrp to fail silently by default */
356 php_error_docref(NULL, E_WARNING, "Cannot call chgrp() for a non-standard stream");
357#endif
359 }
360 }
361
362#ifdef PHP_WIN32
363 /* We have no native chgrp on Windows, nothing left to do if stream doesn't have own implementation */
365#else
366 if (group_str) {
367 if (php_get_gid_by_name(ZSTR_VAL(group_str), &gid) != SUCCESS) {
368 php_error_docref(NULL, E_WARNING, "Unable to find gid for %s", ZSTR_VAL(group_str));
370 }
371 } else {
372 gid = (gid_t) group_long;
373 }
374
375 /* Check the basedir */
376 if (php_check_open_basedir(filename)) {
378 }
379
380 if (do_lchgrp) {
381#ifdef HAVE_LCHOWN
382 ret = VCWD_LCHOWN(filename, -1, gid);
383#endif
384 } else {
385 ret = VCWD_CHOWN(filename, -1, gid);
386 }
387 if (ret == -1) {
388 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
390 }
391
393
395#endif
396}
397/* }}} */
398
399/* {{{ Change file group */
401{
402 php_do_chgrp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
403}
404/* }}} */
405
406/* {{{ Change symlink group */
407#ifdef HAVE_LCHOWN
409{
410 php_do_chgrp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
411}
412#endif
413/* }}} */
414
415#ifndef PHP_WIN32
417{
418#if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
419 struct passwd pw;
420 struct passwd *retpwptr = NULL;
421 long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
422 char *pwbuf;
423 int err;
424
425 if (pwbuflen < 1) {
426 pwbuflen = 1024;
427 }
428# if ZEND_DEBUG
429 /* Test retry logic */
430 pwbuflen = 1;
431# endif
432 pwbuf = emalloc(pwbuflen);
433
434try_again:
435 err = getpwnam_r(name, &pw, pwbuf, pwbuflen, &retpwptr);
436 if (err != 0 || retpwptr == NULL) {
437 if (err == EAGAIN) {
438 pwbuflen *= 2;
439 pwbuf = erealloc(pwbuf, pwbuflen);
440 goto try_again;
441 }
442 efree(pwbuf);
443 return FAILURE;
444 }
445 efree(pwbuf);
446 *uid = pw.pw_uid;
447#else
448 struct passwd *pw = getpwnam(name);
449
450 if (!pw) {
451 return FAILURE;
452 }
453 *uid = pw->pw_uid;
454#endif
455 return SUCCESS;
456}
457#endif
458
459static void php_do_chown(INTERNAL_FUNCTION_PARAMETERS, int do_lchown) /* {{{ */
460{
461 char *filename;
462 size_t filename_len;
463 zend_string *user_str;
464 zend_long user_long;
465#if !defined(PHP_WIN32)
466 uid_t uid;
467 int ret;
468#endif
469 php_stream_wrapper *wrapper;
470
472 Z_PARAM_PATH(filename, filename_len)
473 Z_PARAM_STR_OR_LONG(user_str, user_long)
475
476 wrapper = php_stream_locate_url_wrapper(filename, NULL, 0);
477 if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
478 if(wrapper && wrapper->wops->stream_metadata) {
479 int option;
480 void *value;
481 if (user_str) {
482 option = PHP_STREAM_META_OWNER_NAME;
483 value = ZSTR_VAL(user_str);
484 } else {
485 option = PHP_STREAM_META_OWNER;
486 value = &user_long;
487 }
488
489 if(wrapper->wops->stream_metadata(wrapper, filename, option, value, NULL)) {
490 RETURN_TRUE;
491 } else {
492 RETURN_FALSE;
493 }
494 } else {
495#ifndef PHP_WIN32
496/* On Windows, we expect regular chown to fail silently by default */
497 php_error_docref(NULL, E_WARNING, "Cannot call chown() for a non-standard stream");
498#endif
500 }
501 }
502
503#ifdef PHP_WIN32
504 /* We have no native chown on Windows, nothing left to do if stream doesn't have own implementation */
506#else
507
508 if (user_str) {
509 if (php_get_uid_by_name(ZSTR_VAL(user_str), &uid) != SUCCESS) {
510 php_error_docref(NULL, E_WARNING, "Unable to find uid for %s", ZSTR_VAL(user_str));
512 }
513 } else {
514 uid = (uid_t) user_long;
515 }
516
517 /* Check the basedir */
518 if (php_check_open_basedir(filename)) {
520 }
521
522 if (do_lchown) {
523#ifdef HAVE_LCHOWN
524 ret = VCWD_LCHOWN(filename, uid, -1);
525#endif
526 } else {
527 ret = VCWD_CHOWN(filename, uid, -1);
528 }
529 if (ret == -1) {
530 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
532 }
533
535
537#endif
538}
539/* }}} */
540
541
542/* {{{ Change file owner */
544{
545 php_do_chown(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
546}
547/* }}} */
548
549/* {{{ Change file owner */
550#ifdef HAVE_LCHOWN
552{
554 php_do_chown(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
555}
556#endif
557/* }}} */
558
559/* {{{ Change file mode */
561{
562 char *filename;
563 size_t filename_len;
565 int ret;
566 mode_t imode;
567 php_stream_wrapper *wrapper;
568
570 Z_PARAM_PATH(filename, filename_len)
573
574 wrapper = php_stream_locate_url_wrapper(filename, NULL, 0);
575 if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
576 if(wrapper && wrapper->wops->stream_metadata) {
577 if(wrapper->wops->stream_metadata(wrapper, filename, PHP_STREAM_META_ACCESS, &mode, NULL)) {
579 } else {
581 }
582 } else {
583 php_error_docref(NULL, E_WARNING, "Cannot call chmod() for a non-standard stream");
585 }
586 }
587
588 /* Check the basedir */
589 if (php_check_open_basedir(filename)) {
591 }
592
593 imode = (mode_t) mode;
594
595 ret = VCWD_CHMOD(filename, imode);
596 if (ret == -1) {
597 php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
599 }
600
602
604}
605/* }}} */
606
607#ifdef HAVE_UTIME
608/* {{{ Set modification time of file */
610{
611 char *filename;
612 size_t filename_len;
613 zend_long filetime = 0, fileatime = 0;
614 bool filetime_is_null = 1, fileatime_is_null = 1;
615 int ret;
616 FILE *file;
617 struct utimbuf newtimebuf;
618 struct utimbuf *newtime = &newtimebuf;
619 php_stream_wrapper *wrapper;
620
622 Z_PARAM_PATH(filename, filename_len)
624 Z_PARAM_LONG_OR_NULL(filetime, filetime_is_null)
625 Z_PARAM_LONG_OR_NULL(fileatime, fileatime_is_null)
627
628 if (!filename_len) {
630 }
631
632 if (filetime_is_null && fileatime_is_null) {
633 newtime = NULL;
634 } else if (!filetime_is_null && fileatime_is_null) {
635 newtime->modtime = newtime->actime = filetime;
636 } else if (filetime_is_null && !fileatime_is_null) {
637 zend_argument_value_error(2, "cannot be null when argument #3 ($atime) is an integer");
639 } else {
640 newtime->modtime = filetime;
641 newtime->actime = fileatime;
642 }
643
644 wrapper = php_stream_locate_url_wrapper(filename, NULL, 0);
645 if(wrapper != &php_plain_files_wrapper || strncasecmp("file://", filename, 7) == 0) {
646 if(wrapper && wrapper->wops->stream_metadata) {
647 if(wrapper->wops->stream_metadata(wrapper, filename, PHP_STREAM_META_TOUCH, newtime, NULL)) {
649 } else {
651 }
652 } else {
653 php_stream *stream;
654 if(!filetime_is_null || !fileatime_is_null) {
655 php_error_docref(NULL, E_WARNING, "Cannot call touch() for a non-standard stream");
657 }
658 stream = php_stream_open_wrapper_ex(filename, "c", REPORT_ERRORS, NULL, NULL);
659 if(stream != NULL) {
660 php_stream_close(stream);
662 } else {
664 }
665 }
666 }
667
668 /* Check the basedir */
669 if (php_check_open_basedir(filename)) {
671 }
672
673 /* create the file if it doesn't exist already */
674 if (VCWD_ACCESS(filename, F_OK) != 0) {
675 file = VCWD_FOPEN(filename, "w");
676 if (file == NULL) {
677 php_error_docref(NULL, E_WARNING, "Unable to create file %s because %s", filename, strerror(errno));
679 }
680 fclose(file);
681 }
682
683 ret = VCWD_UTIME(filename, newtime);
684 if (ret == -1) {
685 php_error_docref(NULL, E_WARNING, "Utime failed: %s", strerror(errno));
687 }
688
690
692}
693/* }}} */
694#endif
695
696/* {{{ php_clear_stat_cache() */
697PHPAPI void php_clear_stat_cache(bool clear_realpath_cache, const char *filename, size_t filename_len)
698{
699 /* always clear CurrentStatFile and CurrentLStatFile even if filename is not NULL
700 * as it may contain outdated data (e.g. "nlink" for a directory when deleting a file
701 * in this directory, as shown by lstat_stat_variation9.phpt) */
702 if (BG(CurrentStatFile)) {
703 zend_string_release(BG(CurrentStatFile));
704 BG(CurrentStatFile) = NULL;
705 }
706 if (BG(CurrentLStatFile)) {
707 zend_string_release(BG(CurrentLStatFile));
708 BG(CurrentLStatFile) = NULL;
709 }
710 if (clear_realpath_cache) {
711 if (filename != NULL) {
713 } else {
715 }
716 }
717}
718/* }}} */
719
720/* {{{ Clear file stat cache */
722{
723 bool clear_realpath_cache = 0;
724 char *filename = NULL;
725 size_t filename_len = 0;
726
729 Z_PARAM_BOOL(clear_realpath_cache)
730 Z_PARAM_PATH(filename, filename_len)
732
733 php_clear_stat_cache(clear_realpath_cache, filename, filename_len);
734}
735/* }}} */
736
737#define IS_LINK_OPERATION(__t) ((__t) == FS_TYPE || (__t) == FS_IS_LINK || (__t) == FS_LSTAT || (__t) == FS_LPERMS)
738#define IS_EXISTS_CHECK(__t) ((__t) == FS_EXISTS || (__t) == FS_IS_W || (__t) == FS_IS_R || (__t) == FS_IS_X || (__t) == FS_IS_FILE || (__t) == FS_IS_DIR || (__t) == FS_IS_LINK || (__t) == FS_LPERMS)
739#define IS_ABLE_CHECK(__t) ((__t) == FS_IS_R || (__t) == FS_IS_W || (__t) == FS_IS_X)
740#define IS_ACCESS_CHECK(__t) (IS_ABLE_CHECK(type) || (__t) == FS_EXISTS)
741
742/* {{{ php_stat */
744{
745 php_stream_statbuf ssb = {0};
746 zend_stat_t *stat_sb = &ssb.sb;
747 int flags = 0, rmask=S_IROTH, wmask=S_IWOTH, xmask=S_IXOTH; /* access rights defaults to other */
748 const char *local = NULL;
749 php_stream_wrapper *wrapper = NULL;
750
751 if (IS_ACCESS_CHECK(type)) {
752 if (!ZSTR_LEN(filename) || CHECK_NULL_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename))) {
753 if (ZSTR_LEN(filename) && !IS_EXISTS_CHECK(type)) {
754 php_error_docref(NULL, E_WARNING, "Filename contains null byte");
755 }
757 }
758
759 if ((wrapper = php_stream_locate_url_wrapper(ZSTR_VAL(filename), &local, 0)) == &php_plain_files_wrapper
760 && php_check_open_basedir(local)) {
762 }
763
764 if (wrapper == &php_plain_files_wrapper) {
765 char realpath[MAXPATHLEN];
766 const char *file_path_to_check;
767 /* if the wrapper is not found, we need to expand path to match open behavior */
768 if (EXPECTED(!php_is_stream_path(local) || expand_filepath(local, realpath) == NULL)) {
769 file_path_to_check = local;
770 } else {
771 file_path_to_check = realpath;
772 }
773 switch (type) {
774#ifdef F_OK
775 case FS_EXISTS:
776 RETURN_BOOL(VCWD_ACCESS(file_path_to_check, F_OK) == 0);
777 break;
778#endif
779#ifdef W_OK
780 case FS_IS_W:
781 RETURN_BOOL(VCWD_ACCESS(file_path_to_check, W_OK) == 0);
782 break;
783#endif
784#ifdef R_OK
785 case FS_IS_R:
786 RETURN_BOOL(VCWD_ACCESS(file_path_to_check, R_OK) == 0);
787 break;
788#endif
789#ifdef X_OK
790 case FS_IS_X:
791 RETURN_BOOL(VCWD_ACCESS(file_path_to_check, X_OK) == 0);
792 break;
793#endif
794 }
795 }
796 }
797
798 if (IS_LINK_OPERATION(type)) {
800 }
801 if (IS_EXISTS_CHECK(type)) {
803 }
804
805 do {
806 /* Try to hit the cache first */
808 if (filename == BG(CurrentLStatFile)
809 || (BG(CurrentLStatFile)
810 && zend_string_equal_content(filename, BG(CurrentLStatFile)))) {
811 stat_sb = &BG(lssb).sb;
812 break;
813 }
814 } else {
815 if (filename == BG(CurrentStatFile)
816 || (BG(CurrentStatFile)
817 && zend_string_equal_content(filename, BG(CurrentStatFile)))) {
818 stat_sb = &BG(ssb).sb;
819 break;
820 }
821 }
822
823 if (!wrapper) {
824 if (!ZSTR_LEN(filename) || CHECK_NULL_PATH(ZSTR_VAL(filename), ZSTR_LEN(filename))) {
825 if (ZSTR_LEN(filename) && !IS_EXISTS_CHECK(type)) {
826 php_error_docref(NULL, E_WARNING, "Filename contains null byte");
827 }
829 }
830
831 if ((wrapper = php_stream_locate_url_wrapper(ZSTR_VAL(filename), &local, 0)) == &php_plain_files_wrapper
832 && php_check_open_basedir(local)) {
834 }
835 }
836
837 if (!wrapper
838 || !wrapper->wops->url_stat
839 || wrapper->wops->url_stat(wrapper, local, flags | PHP_STREAM_URL_STAT_IGNORE_OPEN_BASEDIR, &ssb, NULL)) {
840 /* Error Occurred */
841 if (!IS_EXISTS_CHECK(type)) {
842 php_error_docref(NULL, E_WARNING, "%sstat failed for %s", IS_LINK_OPERATION(type) ? "L" : "", ZSTR_VAL(filename));
843 }
845 }
846
847 /* Drop into cache */
849 if (BG(CurrentLStatFile)) {
850 zend_string_release(BG(CurrentLStatFile));
851 }
852 BG(CurrentLStatFile) = zend_string_copy(filename);
853 memcpy(&BG(lssb), &ssb, sizeof(php_stream_statbuf));
854 }
856 || !S_ISLNK(ssb.sb.st_mode)) {
857 if (BG(CurrentStatFile)) {
858 zend_string_release(BG(CurrentStatFile));
859 }
860 BG(CurrentStatFile) = zend_string_copy(filename);
861 memcpy(&BG(ssb), &ssb, sizeof(php_stream_statbuf));
862 }
863 } while (0);
864
865 if (type >= FS_IS_W && type <= FS_IS_X) {
866 if(stat_sb->st_uid==getuid()) {
867 rmask=S_IRUSR;
868 wmask=S_IWUSR;
869 xmask=S_IXUSR;
870 } else if(stat_sb->st_gid==getgid()) {
871 rmask=S_IRGRP;
872 wmask=S_IWGRP;
873 xmask=S_IXGRP;
874 } else {
875 int groups, n, i;
876 gid_t *gids;
877
878 groups = getgroups(0, NULL);
879 if(groups > 0) {
880 gids=(gid_t *)safe_emalloc(groups, sizeof(gid_t), 0);
881 n=getgroups(groups, gids);
882 for(i=0;i<n;i++){
883 if(stat_sb->st_gid==gids[i]) {
884 rmask=S_IRGRP;
885 wmask=S_IWGRP;
886 xmask=S_IXGRP;
887 break;
888 }
889 }
890 efree(gids);
891 }
892 }
893 }
894
895 if (IS_ABLE_CHECK(type) && getuid() == 0) {
896 /* root has special perms on plain_wrapper */
897 if (wrapper == &php_plain_files_wrapper) {
898 if (type == FS_IS_X) {
899 xmask = S_IXROOT;
900 } else {
902 }
903 }
904 }
905
906 switch (type) {
907 case FS_PERMS:
908 case FS_LPERMS:
909 RETURN_LONG((zend_long)stat_sb->st_mode);
910 case FS_INODE:
911 RETURN_LONG((zend_long)stat_sb->st_ino);
912 case FS_SIZE:
913 RETURN_LONG((zend_long)stat_sb->st_size);
914 case FS_OWNER:
915 RETURN_LONG((zend_long)stat_sb->st_uid);
916 case FS_GROUP:
917 RETURN_LONG((zend_long)stat_sb->st_gid);
918 case FS_ATIME:
919 RETURN_LONG((zend_long)stat_sb->st_atime);
920 case FS_MTIME:
921 RETURN_LONG((zend_long)stat_sb->st_mtime);
922 case FS_CTIME:
923 RETURN_LONG((zend_long)stat_sb->st_ctime);
924 case FS_TYPE:
925 if (S_ISLNK(stat_sb->st_mode)) {
926 RETURN_STRING("link");
927 }
928 switch(stat_sb->st_mode & S_IFMT) {
929 case S_IFIFO: RETURN_STRING("fifo");
930 case S_IFCHR: RETURN_STRING("char");
931 case S_IFDIR: RETURN_STRING("dir");
932 case S_IFBLK: RETURN_STRING("block");
933 case S_IFREG: RETURN_STR(ZSTR_KNOWN(ZEND_STR_FILE)); /* "file" */
934#if defined(S_IFSOCK) && !defined(PHP_WIN32)
935 case S_IFSOCK: RETURN_STRING("socket");
936#endif
937 }
938 php_error_docref(NULL, E_NOTICE, "Unknown file type (%d)", stat_sb->st_mode&S_IFMT);
939 RETURN_STRING("unknown");
940 case FS_IS_W:
941 RETURN_BOOL((stat_sb->st_mode & wmask) != 0);
942 case FS_IS_R:
943 RETURN_BOOL((stat_sb->st_mode & rmask) != 0);
944 case FS_IS_X:
945 RETURN_BOOL((stat_sb->st_mode & xmask) != 0);
946 case FS_IS_FILE:
947 RETURN_BOOL(S_ISREG(stat_sb->st_mode));
948 case FS_IS_DIR:
949 RETURN_BOOL(S_ISDIR(stat_sb->st_mode));
950 case FS_IS_LINK:
951 RETURN_BOOL(S_ISLNK(stat_sb->st_mode));
952 case FS_EXISTS:
953 RETURN_TRUE; /* the false case was done earlier */
954 case FS_LSTAT:
955 /* FALLTHROUGH */
956 case FS_STAT: {
957 char *stat_sb_names[] = {
958 "dev", "ino", "mode", "nlink", "uid", "gid", "rdev",
959 "size", "atime", "mtime", "ctime", "blksize", "blocks"
960 };
961 zval stat_dev, stat_ino, stat_mode, stat_nlink, stat_uid, stat_gid, stat_rdev,
962 stat_size, stat_atime, stat_mtime, stat_ctime, stat_blksize, stat_blocks;
963 zval *stat_sb_addresses[] = {
964 &stat_dev, &stat_ino, &stat_mode, &stat_nlink, &stat_uid, &stat_gid, &stat_rdev,
965 &stat_size, &stat_atime, &stat_mtime, &stat_ctime, &stat_blksize, &stat_blocks
966 };
967 size_t i, size_stat_sb = sizeof(stat_sb_addresses) / sizeof(*stat_sb_addresses);
968
970
971 ZVAL_LONG(&stat_dev, stat_sb->st_dev);
972 ZVAL_LONG(&stat_ino, stat_sb->st_ino);
973 ZVAL_LONG(&stat_mode, stat_sb->st_mode);
974 ZVAL_LONG(&stat_nlink, stat_sb->st_nlink);
975 ZVAL_LONG(&stat_uid, stat_sb->st_uid);
976 ZVAL_LONG(&stat_gid, stat_sb->st_gid);
977#ifdef HAVE_STRUCT_STAT_ST_RDEV
978 ZVAL_LONG(&stat_rdev, stat_sb->st_rdev);
979#else
980 ZVAL_LONG(&stat_rdev, -1);
981#endif
982 ZVAL_LONG(&stat_size, stat_sb->st_size);
983 ZVAL_LONG(&stat_atime, stat_sb->st_atime);
984 ZVAL_LONG(&stat_mtime, stat_sb->st_mtime);
985 ZVAL_LONG(&stat_ctime, stat_sb->st_ctime);
986#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
987 ZVAL_LONG(&stat_blksize, stat_sb->st_blksize);
988#else
989 ZVAL_LONG(&stat_blksize,-1);
990#endif
991#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
992 ZVAL_LONG(&stat_blocks, stat_sb->st_blocks);
993#else
994 ZVAL_LONG(&stat_blocks,-1);
995#endif
996 for (i = 0; i < size_stat_sb; i++) {
997 /* Store numeric indexes in proper order */
999 }
1000
1001 for (i = 0; i < size_stat_sb; i++) {
1002 /* Store string indexes referencing the same zval */
1003 zend_hash_str_add_new(Z_ARRVAL_P(return_value), stat_sb_names[i], strlen(stat_sb_names[i]), stat_sb_addresses[i]);
1004 }
1005
1006 return;
1007 }
1008 }
1009 php_error_docref(NULL, E_WARNING, "Didn't understand stat call");
1011}
1012/* }}} */
1013
1014/* another quickie macro to make defining similar functions easier */
1015/* {{{ FileFunction(name, funcnum) */
1016#define FileFunction(name, funcnum) \
1017ZEND_NAMED_FUNCTION(name) { \
1018 zend_string *filename; \
1019 \
1020 ZEND_PARSE_PARAMETERS_START(1, 1) \
1021 Z_PARAM_STR(filename) \
1022 ZEND_PARSE_PARAMETERS_END(); \
1023 \
1024 php_stat(filename, funcnum, return_value); \
1025}
1026/* }}} */
1027
1028/* {{{ Get file permissions */
1030/* }}} */
1031
1032/* {{{ Get file inode */
1034/* }}} */
1035
1036/* {{{ Get file size */
1038/* }}} */
1039
1040/* {{{ Get file owner */
1042/* }}} */
1043
1044/* {{{ Get file group */
1046/* }}} */
1047
1048/* {{{ Get last access time of file */
1050/* }}} */
1051
1052/* {{{ Get last modification time of file */
1054/* }}} */
1055
1056/* {{{ Get inode modification time of file */
1058/* }}} */
1059
1060/* {{{ Get file type */
1062/* }}} */
1063
1064/* {{{ Returns true if file can be written */
1066/* }}} */
1067
1068/* {{{ Returns true if file can be read */
1070/* }}} */
1071
1072/* {{{ Returns true if file is executable */
1074/* }}} */
1075
1076/* {{{ Returns true if file is a regular file */
1078/* }}} */
1079
1080/* {{{ Returns true if file is directory */
1082/* }}} */
1083
1084/* {{{ Returns true if file is symbolic link */
1086/* }}} */
1087
1088/* {{{ Returns true if filename exists */
1090/* }}} */
1091
1092/* {{{ Give information about a file or symbolic link */
1094/* }}} */
1095
1096/* {{{ Give information about a file */
1098/* }}} */
1099
1100/* {{{ Get current size of realpath cache */
1102{
1104
1106}
1107
1108/* {{{ Get current size of realpath cache */
1110{
1112
1114
1116 while(buckets < end) {
1117 realpath_cache_bucket *bucket = *buckets;
1118 while(bucket) {
1119 zval entry;
1120
1121 array_init(&entry);
1122
1123 /* bucket->key is unsigned long */
1124 if (ZEND_LONG_MAX >= bucket->key) {
1125 add_assoc_long_ex(&entry, "key", sizeof("key") - 1, bucket->key);
1126 } else {
1127 add_assoc_double_ex(&entry, "key", sizeof("key") - 1, (double)bucket->key);
1128 }
1129 add_assoc_bool_ex(&entry, "is_dir", sizeof("is_dir") - 1, bucket->is_dir);
1130 add_assoc_stringl_ex(&entry, "realpath", sizeof("realpath") - 1, bucket->realpath, bucket->realpath_len);
1131 add_assoc_long_ex(&entry, "expires", sizeof("expires") - 1, bucket->expires);
1132#ifdef PHP_WIN32
1133 add_assoc_bool_ex(&entry, "is_rvalid", sizeof("is_rvalid") - 1, bucket->is_rvalid);
1134 add_assoc_bool_ex(&entry, "is_wvalid", sizeof("is_wvalid") - 1, bucket->is_wvalid);
1135 add_assoc_bool_ex(&entry, "is_readable", sizeof("is_readable") - 1, bucket->is_readable);
1136 add_assoc_bool_ex(&entry, "is_writable", sizeof("is_writable") - 1, bucket->is_writable);
1137#endif
1138 zend_hash_str_update(Z_ARRVAL_P(return_value), bucket->path, bucket->path_len, &entry);
1139 bucket = bucket->next;
1140 }
1141 buckets++;
1142 }
1143}
PHP_RINIT filestat(INIT_FUNC_ARGS_PASSTHRU)
#define BG(v)
is_executable(string $filename)
filegroup(string $filename)
fileowner(string $filename)
filemtime(string $filename)
is_link(string $filename)
is_dir(string $filename)
file_exists(string $filename)
file(string $filename, int $flags=0, $context=null)
chown(string $filename, string|int $user)
chgrp(string $filename, string|int $group)
is_readable(string $filename)
fileatime(string $filename)
clearstatcache(bool $clear_realpath_cache=false, string $filename="")
is_writable(string $filename)
is_file(string $filename)
touch(string $filename, ?int $mtime=null, ?int $atime=null)
fclose($stream)
fileperms(string $filename)
chmod(string $filename, int $permissions)
disk_total_space(string $directory)
filectime(string $filename)
fileinode(string $filename)
filetype(string $filename)
lchgrp(string $filename, string|int $group)
stat(string $filename)
disk_free_space(string $directory)
filesize(string $filename)
lstat(string $filename)
realpath(string $path)
lchown(string $filename, string|int $user)
zend_ffi_type * type
Definition ffi.c:3812
zend_long n
Definition ffi.c:4979
memcpy(ptr1, ptr2, size)
char * err
Definition ffi.c:3029
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define FileFunction(name, funcnum)
Definition filestat.c:1016
PHPAPI void php_stat(zend_string *filename, int type, zval *return_value)
Definition filestat.c:743
#define IS_ACCESS_CHECK(__t)
Definition filestat.c:740
#define IS_LINK_OPERATION(__t)
Definition filestat.c:737
#define IS_ABLE_CHECK(__t)
Definition filestat.c:739
PHPAPI void php_clear_stat_cache(bool clear_realpath_cache, const char *filename, size_t filename_len)
Definition filestat.c:697
#define IS_EXISTS_CHECK(__t)
Definition filestat.c:738
PHPAPI zend_result php_get_uid_by_name(const char *name, uid_t *uid)
Definition filestat.c:416
PHPAPI zend_result php_get_gid_by_name(const char *name, gid_t *gid)
Definition filestat.c:275
PHPAPI int php_check_open_basedir(const char *path)
PHPAPI char * expand_filepath(const char *filepath, char *real_path)
char * mode
size_t filename_len
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
#define R_OK
Definition ioutil.h:80
unsigned short mode_t
Definition ioutil.h:72
#define X_OK
Definition ioutil.h:83
#define PHP_WIN32_IOUTIL_INIT_W(path)
Definition ioutil.h:143
#define PHP_WIN32_IOUTIL_CLEANUP_W()
Definition ioutil.h:146
#define W_OK
Definition ioutil.h:77
#define F_OK
Definition ioutil.h:86
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define PHP_FUNCTION
Definition php.h:364
#define PHP_RINIT_FUNCTION
Definition php.h:402
#define PHP_FN
Definition php.h:361
#define PHP_RSHUTDOWN_FUNCTION
Definition php.h:403
#define PHPAPI
Definition php.h:71
unsigned const char * end
Definition php_ffi.h:51
#define FS_EXISTS
#define FS_IS_W
#define FS_SIZE
#define FS_GROUP
#define FS_IS_X
#define FS_TYPE
#define FS_INODE
#define FS_IS_DIR
#define FS_IS_R
#define FS_MTIME
#define FS_OWNER
#define FS_PERMS
#define FS_LPERMS
#define FS_IS_FILE
#define FS_LSTAT
#define FS_ATIME
#define FS_CTIME
#define FS_IS_LINK
#define FS_STAT
PHPAPI php_stream_wrapper php_plain_files_wrapper
struct _php_stream php_stream
Definition php_streams.h:96
#define REPORT_ERRORS
#define PHP_STREAM_URL_STAT_IGNORE_OPEN_BASEDIR
#define php_stream_open_wrapper_ex(path, mode, options, opened, context)
#define php_stream_close(stream)
#define PHP_STREAM_URL_STAT_LINK
#define PHP_STREAM_META_TOUCH
struct _php_stream_wrapper php_stream_wrapper
Definition php_streams.h:97
PHPAPI php_stream_wrapper * php_stream_locate_url_wrapper(const char *path, const char **path_for_open, int options)
Definition streams.c:1964
#define PHP_STREAM_URL_STAT_QUIET
struct _php_stream_statbuf php_stream_statbuf
#define PHP_STREAM_META_ACCESS
int(* url_stat)(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context)
int(* stream_metadata)(php_stream_wrapper *wrapper, const char *url, int options, void *value, php_stream_context *context)
const php_stream_wrapper_ops * wops
struct _realpath_cache_bucket * next
#define errno
#define EAGAIN
#define php_win_err()
Definition winutil.h:29
#define php_win_err_free(err)
Definition winutil.h:30
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
Definition zend.h:50
ZEND_API void add_assoc_bool_ex(zval *arg, const char *key, size_t key_len, bool b)
Definition zend_API.c:1946
ZEND_API void add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double d)
Definition zend_API.c:1964
ZEND_API void add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length)
Definition zend_API.c:1991
ZEND_API void add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n)
Definition zend_API.c:1928
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
#define CHECK_NULL_PATH(p, l)
Definition zend_API.h:950
#define RETURN_STRING(s)
Definition zend_API.h:1043
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define RETURN_DOUBLE(d)
Definition zend_API.h:1038
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define RETURN_THROWS()
Definition zend_API.h:1060
#define RETVAL_TRUE
Definition zend_API.h:1033
#define RETURN_STR(s)
Definition zend_API.h:1039
#define Z_PARAM_LONG_OR_NULL(dest, is_null)
Definition zend_API.h:1899
#define Z_PARAM_STR_OR_LONG(dest_str, dest_long)
Definition zend_API.h:2165
#define Z_PARAM_BOOL(dest)
Definition zend_API.h:1726
#define Z_PARAM_PATH(dest, dest_len)
Definition zend_API.h:2026
#define RETURN_TRUE
Definition zend_API.h:1059
#define array_init(arg)
Definition zend_API.h:537
#define efree(ptr)
Definition zend_alloc.h:155
#define erealloc(ptr, size)
Definition zend_alloc.h:159
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
#define strncasecmp(s1, s2, n)
#define E_NOTICE
Definition zend_errors.h:26
#define E_WARNING
Definition zend_errors.h:24
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
Definition zend_hash.c:1224
ZEND_API zval *ZEND_FASTCALL zend_hash_str_update(HashTable *ht, const char *str, size_t len, zval *pData)
Definition zend_hash.c:1031
ZEND_API zval *ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *str, size_t len, zval *pData)
Definition zend_hash.c:1052
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_MAX
Definition zend_long.h:45
struct _zend_string zend_string
#define EXPECTED(condition)
struct stat zend_stat_t
Definition zend_stream.h:94
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_KNOWN(idx)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_LONG(z, l)
@ FAILURE
Definition zend_types.h:61
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
CWD_API void realpath_cache_del(const char *path, size_t path_len)
CWD_API zend_long realpath_cache_max_buckets(void)
CWD_API realpath_cache_bucket ** realpath_cache_get_buckets(void)
CWD_API void realpath_cache_clean(void)
CWD_API zend_long realpath_cache_size(void)
struct _realpath_cache_bucket realpath_cache_bucket
#define S_IXROOT
#define VCWD_FOPEN(path, mode)
#define VCWD_CHOWN(path, owner, group)
#define S_ISDIR(mode)
#define S_IFIFO
#define S_IFBLK
#define S_ISLNK(mode)
#define S_ISREG(mode)
#define VCWD_CHMOD(path, mode)
#define MAXPATHLEN
#define VCWD_ACCESS(pathname, mode)
zval * return_value
zend_string * name
zval * ret
value