From c9861bd7a974ef1555395b879c1035a0bbc12ef1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 2 Aug 2018 14:08:30 +0200 Subject: [PATCH] Create and expose php_sys_symlink() and php_sys_link() These macros are supposed to behave like POSIX's symlink() and link(), respectively, on POSIX compliant systems and on Windows. Future scope: merge link.c and link_win32.c --- UPGRADING.INTERNALS | 5 ++ Zend/zend_virtual_cwd.h | 4 ++ ext/standard/link.c | 6 +- ext/standard/link_win32.c | 64 +++---------------- .../tests/file/rename_variation7-win32.phpt | 2 +- win32/ioutil.c | 32 ++++++++++ win32/ioutil.h | 53 +++++++++++++++ 7 files changed, 106 insertions(+), 60 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 32f043b55f..b949e78803 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -1,6 +1,7 @@ PHP 7.4 INTERNALS UPGRADE NOTES 1. Internal API changes + a. php_sys_symlink() and php_sys_link() 2. Build system changes a. Unix build system changes @@ -12,6 +13,10 @@ PHP 7.4 INTERNALS UPGRADE NOTES 1. Internal API changes ======================== + a. php_sys_symlink() and php_sys_link() portability macros have been + added, which behave like POSIX's symlink() and link(), respectively, on + POSIX compliant systems and on Windows. + ======================== 2. Build system changes ======================== diff --git a/Zend/zend_virtual_cwd.h b/Zend/zend_virtual_cwd.h index 43d3965adb..feee04a745 100644 --- a/Zend/zend_virtual_cwd.h +++ b/Zend/zend_virtual_cwd.h @@ -120,11 +120,15 @@ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat); # define php_sys_stat(path, buf) php_sys_stat_ex(path, buf, 0) # define php_sys_lstat(path, buf) php_sys_stat_ex(path, buf, 1) CWD_API ssize_t php_sys_readlink(const char *link, char *target, size_t target_len); +# define php_sys_symlink php_win32_ioutil_symlink +# define php_sys_link php_win32_ioutil_link #else # define php_sys_stat stat # define php_sys_lstat lstat # ifdef HAVE_SYMLINK # define php_sys_readlink(link, target, target_len) readlink(link, target, target_len) +# define php_sys_symlink symlink +# define php_sys_link link # endif #endif diff --git a/ext/standard/link.c b/ext/standard/link.c index 5ca8b2c49c..c95c75d136 100644 --- a/ext/standard/link.c +++ b/ext/standard/link.c @@ -160,7 +160,7 @@ PHP_FUNCTION(symlink) /* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD). * For the target the exact string given by the user must be used, relative or not, existing or not. * The target is relative to the link itself, not to the CWD. */ - ret = symlink(topath, source_p); + ret = php_sys_symlink(topath, source_p); if (ret == -1) { php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); @@ -207,9 +207,9 @@ PHP_FUNCTION(link) } #ifndef ZTS - ret = link(topath, frompath); + ret = php_sys_link(topath, frompath); #else - ret = link(dest_p, source_p); + ret = php_sys_link(dest_p, source_p); #endif if (ret == -1) { php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); diff --git a/ext/standard/link_win32.c b/ext/standard/link_win32.c index ae6cdd11f2..bc9931359d 100644 --- a/ext/standard/link_win32.c +++ b/ext/standard/link_win32.c @@ -43,7 +43,7 @@ /* TODO: -- Create php_readlink (done), php_link and php_symlink in win32/link.c +- Create php_readlink (done), php_link (done) and php_symlink (done) in win32/link.c - Expose them (PHPAPI) so extensions developers can use them - define link/readlink/symlink to their php_ equivalent and use them in ext/standart/link.c - this file is then useless and we have a portable link API @@ -122,13 +122,11 @@ PHP_FUNCTION(symlink) { char *topath, *frompath; size_t topath_len, frompath_len; - BOOLEAN ret; + int ret; char source_p[MAXPATHLEN]; char dest_p[MAXPATHLEN]; char dirname[MAXPATHLEN]; size_t len; - DWORD attr; - wchar_t *dstw, *srcw; if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &topath, &topath_len, &frompath, &frompath_len) == FAILURE) { return; @@ -162,38 +160,16 @@ PHP_FUNCTION(symlink) RETURN_FALSE; } - dstw = php_win32_ioutil_any_to_w(topath); - if (!dstw) { - php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError()); - RETURN_FALSE; - } - if ((attr = GetFileAttributesW(dstw)) == INVALID_FILE_ATTRIBUTES) { - free(dstw); - php_error_docref(NULL, E_WARNING, "Could not fetch file information(error %d)", GetLastError()); - RETURN_FALSE; - } - - srcw = php_win32_ioutil_any_to_w(source_p); - if (!srcw) { - free(dstw); - php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError()); - RETURN_FALSE; - } /* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD). * For the target the exact string given by the user must be used, relative or not, existing or not. * The target is relative to the link itself, not to the CWD. */ - ret = CreateSymbolicLinkW(srcw, dstw, (attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0)); + ret = php_sys_symlink(topath, source_p); - if (!ret) { - free(dstw); - free(srcw); - php_error_docref(NULL, E_WARNING, "Cannot create symlink, error code(%d)", GetLastError()); + if (ret == -1) { + php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); RETURN_FALSE; } - free(dstw); - free(srcw); - RETURN_TRUE; } /* }}} */ @@ -207,7 +183,6 @@ PHP_FUNCTION(link) int ret; char source_p[MAXPATHLEN]; char dest_p[MAXPATHLEN]; - wchar_t *dstw, *srcw; /*First argument to link function is the target and hence should go to frompath Second argument to link function is the link itself and hence should go to topath */ @@ -236,38 +211,15 @@ PHP_FUNCTION(link) } #ifndef ZTS -# define _TO_PATH topath -# define _FROM_PATH frompath + ret = php_sys_link(topath, frompath); #else -# define _TO_PATH dest_p -# define _FROM_PATH source_p + ret = php_sys_link(dest_p, source_p); #endif - dstw = php_win32_ioutil_any_to_w(_TO_PATH); - if (!dstw) { - php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError()); - RETURN_FALSE; - } - srcw = php_win32_ioutil_any_to_w(_FROM_PATH); - if (!srcw) { - free(dstw); - php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError()); - RETURN_FALSE; - } -#undef _TO_PATH -#undef _FROM_PATH - - ret = CreateHardLinkW(dstw, srcw, NULL); - - if (ret == 0) { - free(dstw); - free(srcw); + if (ret == -1) { php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); RETURN_FALSE; } - free(dstw); - free(srcw); - RETURN_TRUE; } /* }}} */ diff --git a/ext/standard/tests/file/rename_variation7-win32.phpt b/ext/standard/tests/file/rename_variation7-win32.phpt index 369e8c2d43..b1a04b38c6 100644 --- a/ext/standard/tests/file/rename_variation7-win32.phpt +++ b/ext/standard/tests/file/rename_variation7-win32.phpt @@ -26,7 +26,7 @@ var_dump(readlink($tmp_link2)); echo "Done\n"; ?> --EXPECTF-- -Warning: symlink(): Could not fetch file information(error 2) in %srename_variation7-win32.php on line %d +Warning: symlink(): No such file or directory in %srename_variation7-win32.php on line %d Warning: readlink(): readlink failed to read the symbolic link (%srename_variation7-win32.php.tmp.link), error 2) in %srename_variation7-win32.php on line %d bool(false) diff --git a/win32/ioutil.c b/win32/ioutil.c index 2ff62e3b6c..d3fb2bdb59 100644 --- a/win32/ioutil.c +++ b/win32/ioutil.c @@ -785,6 +785,38 @@ PW32IO char *realpath(const char *path, char *resolved) return php_win32_ioutil_realpath(path, resolved); }/*}}}*/ +PW32IO int php_win32_ioutil_symlink_w(const wchar_t *target, const wchar_t *link) +{/*{{{*/ + DWORD attr; + BOOLEAN res; + + if ((attr = GetFileAttributesW(target)) == INVALID_FILE_ATTRIBUTES) { + SET_ERRNO_FROM_WIN32_CODE(GetLastError()); + return -1; + } + + res = CreateSymbolicLinkW(link, target, (attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0)); + if (!res) { + SET_ERRNO_FROM_WIN32_CODE(GetLastError()); + return -1; + } + + return 0; +}/*}}}*/ + +PW32IO int php_win32_ioutil_link_w(const wchar_t *target, const wchar_t *link) +{/*{{{*/ + BOOL res; + + res = CreateHardLinkW(target, link, NULL); + if (!res) { + SET_ERRNO_FROM_WIN32_CODE(GetLastError()); + return -1; + } + + return 0; +}/*}}}*/ + /* * Local variables: * tab-width: 4 diff --git a/win32/ioutil.h b/win32/ioutil.h index 2a396f67b6..8c0275cad6 100644 --- a/win32/ioutil.h +++ b/win32/ioutil.h @@ -261,6 +261,8 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode); PW32IO FILE *php_win32_ioutil_fopen_w(const wchar_t *path, const wchar_t *mode); PW32IO wchar_t *php_win32_ioutil_realpath_w(const wchar_t *path, wchar_t *resolved); PW32IO wchar_t *php_win32_ioutil_realpath_w_ex0(const wchar_t *path, wchar_t *resolved, PBY_HANDLE_FILE_INFORMATION info); +PW32IO int php_win32_ioutil_symlink_w(const wchar_t *target, const wchar_t *link); +PW32IO int php_win32_ioutil_link_w(const wchar_t *target, const wchar_t *link); __forceinline static int php_win32_ioutil_access(const char *path, mode_t mode) {/*{{{*/ @@ -571,6 +573,57 @@ __forceinline static int php_win32_ioutil_mkdir(const char *path, mode_t mode) return ret; }/*}}}*/ +__forceinline static int php_win32_ioutil_symlink(const char *target, const char *link) +{/*{{{*/ + wchar_t *targetw, *linkw; + int ret; + + targetw = php_win32_ioutil_any_to_w(target); + if (!targetw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + linkw = php_win32_ioutil_any_to_w(link); + if (!linkw) { + free(targetw); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + ret = php_win32_ioutil_symlink_w(targetw, linkw); + + free(targetw); + free(linkw); + + return ret; +}/*}}}*/ + +__forceinline static int php_win32_ioutil_link(const char *target, const char *link) +{/*{{{*/ + wchar_t *targetw, *linkw; + int ret; + + targetw = php_win32_ioutil_any_to_w(target); + if (!targetw) { + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + linkw = php_win32_ioutil_any_to_w(link); + if (!linkw) { + free(targetw); + SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); + return -1; + } + + ret = php_win32_ioutil_link_w(targetw, linkw); + + free(targetw); + free(linkw); + + return ret; +}/*}}}*/ + #define HAVE_REALPATH 1 PW32IO char *realpath(const char *path, char *resolved); -- 2.40.0