From 613e8d7210d6208b50edf0a5daa44c65f562e9d9 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 28 Mar 2024 21:05:50 +0000 Subject: [PATCH] ext/posix: adding posix_mkfifoat/posix_mknodat. The additional directory file descriptor argument allows to operate from a relative path perspective but those new calls can still work with absolute paths. --- ext/posix/config.m4 | 2 +- ext/posix/posix.c | 98 +++++++++++++++++++++ ext/posix/posix.stub.php | 10 +++ ext/posix/posix_arginfo.h | 32 ++++++- ext/posix/tests/posix_mknodat_mkfifoat.phpt | 44 +++++++++ 5 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 ext/posix/tests/posix_mknodat_mkfifoat.phpt diff --git a/ext/posix/config.m4 b/ext/posix/config.m4 index 9f1091a3c4521..5f3f28dd1f0b9 100644 --- a/ext/posix/config.m4 +++ b/ext/posix/config.m4 @@ -8,7 +8,7 @@ if test "$PHP_POSIX" = "yes"; then AC_DEFINE(HAVE_POSIX, 1, [whether to include POSIX-like functions]) PHP_NEW_EXTENSION(posix, posix.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) - AC_CHECK_FUNCS(seteuid setegid setsid getsid getpgid ctermid mkfifo mknod setrlimit getrlimit getgroups initgroups getgrgid_r eaccess) + AC_CHECK_FUNCS(seteuid setegid setsid getsid getpgid ctermid mkfifo mknod setrlimit getrlimit getgroups initgroups getgrgid_r eaccess mkfifoat mknodat) dnl Check for makedev. If it's defined as a macro, AC_CHECK_FUNCS won't work. dnl Required headers are included by the AC_HEADER_MAJOR logic. diff --git a/ext/posix/posix.c b/ext/posix/posix.c index 787b18ae28126..e0523e0fca5fd 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -1305,3 +1305,101 @@ PHP_FUNCTION(posix_fpathconf) RETURN_LONG(ret); } #endif + +#ifdef HAVE_MKFIFOAT +PHP_FUNCTION(posix_mkfifoat) +{ + zend_string *path; + zend_long mode, fd = 0; + zval *z_fd; + int result; + + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_ZVAL(z_fd) + Z_PARAM_PATH_STR(path) + Z_PARAM_LONG(mode) + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(z_fd) == IS_RESOURCE) { + if (!php_posix_stream_get_fd(z_fd, &fd)) { + RETURN_FALSE; + } + } else { + if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) { + zend_argument_type_error(1, "must be of type int|resource, %s given", + zend_zval_value_name(z_fd)); + RETURN_THROWS(); + } + } + + if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) { + RETURN_FALSE; + } + + result = mkfifoat(fd, ZSTR_VAL(path), mode); + if (result < 0) { + POSIX_G(last_error) = errno; + RETURN_FALSE; + } + + RETURN_TRUE; +} +#endif + +#ifdef HAVE_MKNODAT +PHP_FUNCTION(posix_mknodat) +{ + zend_string *path; + zend_long mode, fd = 0; + zend_long major = 0, minor = 0; + zval *z_fd; + int result; + dev_t php_dev = 0; + + ZEND_PARSE_PARAMETERS_START(3, 5) + Z_PARAM_ZVAL(z_fd) + Z_PARAM_PATH_STR(path) + Z_PARAM_LONG(mode) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(major) + Z_PARAM_LONG(minor) + ZEND_PARSE_PARAMETERS_END(); + + if (Z_TYPE_P(z_fd) == IS_RESOURCE) { + if (!php_posix_stream_get_fd(z_fd, &fd)) { + RETURN_FALSE; + } + } else { + if (!zend_parse_arg_long(z_fd, &fd, /* is_null */ NULL, /* check_null */ false, /* arg_num */ 1)) { + zend_argument_type_error(1, "must be of type int|resource, %s given", + zend_zval_value_name(z_fd)); + RETURN_THROWS(); + } + } + + if (php_check_open_basedir_ex(ZSTR_VAL(path), 0)) { + RETURN_FALSE; + } + + if ((mode & S_IFCHR) || (mode & S_IFBLK)) { + if (major == 0) { + zend_argument_value_error(4, "cannot be 0 for the POSIX_S_IFCHR and POSIX_S_IFBLK modes"); + RETURN_THROWS(); + } else { +#ifdef HAVE_MAKEDEV + php_dev = makedev(major, minor); +#else + php_error_docref(NULL, E_WARNING, "Cannot create a block or character device, creating a normal file instead"); +#endif + } + } + + result = mknodat(fd, ZSTR_VAL(path), mode, php_dev); + if (result < 0) { + POSIX_G(last_error) = errno; + RETURN_FALSE; + } + + RETURN_TRUE; +} +#endif diff --git a/ext/posix/posix.stub.php b/ext/posix/posix.stub.php index d34415107a07f..84ec5d38c96fe 100644 --- a/ext/posix/posix.stub.php +++ b/ext/posix/posix.stub.php @@ -454,3 +454,13 @@ function posix_pathconf(string $path, int $name): int|false {} /** @param resource|int $file_descriptor */ function posix_fpathconf($file_descriptor, int $name): int|false {} #endif + +#ifdef HAVE_MKFIFOAT +/** @param resource|int $file_descriptor */ +function posix_mkfifoat($file_descriptor, string $path, int $permissions): bool {} +#endif + +#ifdef HAVE_MKNODAT +/** @param resource|int $file_descriptor */ +function posix_mknodat($file_descriptor, string $path, int $flags, int $major = 0, int $minor = 0): bool {} +#endif diff --git a/ext/posix/posix_arginfo.h b/ext/posix/posix_arginfo.h index 664d822db9eda..92227d2a90838 100644 --- a/ext/posix/posix_arginfo.h +++ b/ext/posix/posix_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 82caf527a8ec686bc450e5d782bb79275d5a13e3 */ + * Stub hash: 6152cd1c60c3136d137106736789161eb402a991 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_posix_kill, 0, 2, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, process_id, IS_LONG, 0) @@ -185,6 +185,24 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_posix_fpathconf, 0, 2, MAY_BE_LO ZEND_END_ARG_INFO() #endif +#if defined(HAVE_MKFIFOAT) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_posix_mkfifoat, 0, 3, _IS_BOOL, 0) + ZEND_ARG_INFO(0, file_descriptor) + ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, permissions, IS_LONG, 0) +ZEND_END_ARG_INFO() +#endif + +#if defined(HAVE_MKNODAT) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_posix_mknodat, 0, 3, _IS_BOOL, 0) + ZEND_ARG_INFO(0, file_descriptor) + ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, major, IS_LONG, 0, "0") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, minor, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() +#endif + ZEND_FUNCTION(posix_kill); ZEND_FUNCTION(posix_getpid); ZEND_FUNCTION(posix_getppid); @@ -257,6 +275,12 @@ ZEND_FUNCTION(posix_pathconf); #if defined(HAVE_FPATHCONF) ZEND_FUNCTION(posix_fpathconf); #endif +#if defined(HAVE_MKFIFOAT) +ZEND_FUNCTION(posix_mkfifoat); +#endif +#if defined(HAVE_MKNODAT) +ZEND_FUNCTION(posix_mknodat); +#endif static const zend_function_entry ext_functions[] = { ZEND_FE(posix_kill, arginfo_posix_kill) @@ -331,6 +355,12 @@ static const zend_function_entry ext_functions[] = { #endif #if defined(HAVE_FPATHCONF) ZEND_FE(posix_fpathconf, arginfo_posix_fpathconf) +#endif +#if defined(HAVE_MKFIFOAT) + ZEND_FE(posix_mkfifoat, arginfo_posix_mkfifoat) +#endif +#if defined(HAVE_MKNODAT) + ZEND_FE(posix_mknodat, arginfo_posix_mknodat) #endif ZEND_FE_END }; diff --git a/ext/posix/tests/posix_mknodat_mkfifoat.phpt b/ext/posix/tests/posix_mknodat_mkfifoat.phpt new file mode 100644 index 0000000000000..3e5ba0314656c --- /dev/null +++ b/ext/posix/tests/posix_mknodat_mkfifoat.phpt @@ -0,0 +1,44 @@ +--TEST-- +posix_mknodat/posix_mkfifoat support +--EXTENSIONS-- +posix +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} +var_dump(posix_mkfifoat($fd, '', POSIX_S_IFBLK | 0777)); +var_dump(posix_mkfifoat($fd, __DIR__ . '', POSIX_S_IFBLK | 0777)); +try { + posix_mkfifoat(new stdClass(), '/dev/', POSIX_S_IFBLK | 0777); +} catch (TypeError $e) { + echo $e->getMessage() . PHP_EOL; +} +@unlink(__DIR__ . '/dev'); +var_dump(posix_mkfifoat($fd, 'dev', POSIX_S_IFIFO | 0666)); +fclose($fd); +@unlink(__DIR__ . '/dev'); +?> +--EXPECT-- +bool(true) +bool(false) +bool(false) +posix_mknodat(): Argument #4 ($major) cannot be 0 for the POSIX_S_IFCHR and POSIX_S_IFBLK modes +bool(false) +bool(false) +posix_mkfifoat(): Argument #1 ($file_descriptor) must be of type int|resource, stdClass given +bool(true) +