diff options
-rw-r--r-- | ext/standard/config.w32 | 2 | ||||
-rw-r--r-- | ext/standard/link_win32.c | 297 | ||||
-rw-r--r-- | ext/standard/php_link.h | 2 |
3 files changed, 299 insertions, 2 deletions
diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index bf92e9b1c4..5744d9399c 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -16,7 +16,7 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \ crypt_freesec.c crypt_blowfish.c php_crypt_r.c \ cyr_convert.c datetime.c dir.c dl.c dns.c dns_win32.c exec.c \ file.c filestat.c formatted_print.c fsock.c head.c html.c image.c \ - info.c iptc.c lcg.c link.c mail.c math.c md5.c metaphone.c microtime.c \ + info.c iptc.c lcg.c link_win32.c mail.c math.c md5.c metaphone.c microtime.c \ pack.c pageinfo.c quot_print.c rand.c soundex.c \ string.c scanf.c syslog.c type.c uniqid.c url.c url_scanner.c var.c \ versioning.c assert.c strnatcmp.c levenshtein.c incomplete_class.c \ diff --git a/ext/standard/link_win32.c b/ext/standard/link_win32.c new file mode 100644 index 0000000000..493bc866c9 --- /dev/null +++ b/ext/standard/link_win32.c @@ -0,0 +1,297 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2009 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Pierre A. Joye <pierre@php.net> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ +#ifdef PHP_WIN32 + +#include "php.h" +#include "php_filestat.h" +#include "php_globals.h" + +#include <WinBase.h> + +#include <stdlib.h> + +#include <string.h> +#if HAVE_PWD_H +#include "win32/pwd.h" +#endif + +#if HAVE_GRP_H +#include "win32/grp.h" +#endif + +#include <errno.h> +#include <ctype.h> + +#include "safe_mode.h" +#include "php_link.h" +#include "php_string.h" + +/* +TODO: +- Create php_readlink, php_link and php_symlink 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 +*/ + +/* {{{ proto string readlink(string filename) + Return the target of a symbolic link */ +PHP_FUNCTION(readlink) +{ + HINSTANCE kernel32; + char *link; + int link_len; + TCHAR Path[MAXPATHLEN]; + HANDLE hFile; + DWORD dwRet; + + typedef BOOL (WINAPI *gfpnh_func)(HANDLE, LPTSTR, DWORD, DWORD); + gfpnh_func pGetFinalPathNameByHandle; + + kernel32 = LoadLibrary("kernel32.dll"); + + if (kernel32) { + pGetFinalPathNameByHandle = (gfpnh_func)GetProcAddress(kernel32, "GetFinalPathNameByHandleA"); + if (pGetFinalPathNameByHandle == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't call GetFinalPathNameByHandleA"); + RETURN_FALSE; + } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't call get a handle on kernel32.dll"); + RETURN_FALSE; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &link, &link_len) == FAILURE) { + return; + } + + if (PG(safe_mode) && !php_checkuid(link, NULL, CHECKUID_CHECK_FILE_AND_DIR)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(link TSRMLS_CC)) { + RETURN_FALSE; + } + + hFile = CreateFile(link, // file to open + GENERIC_READ, // open for reading + FILE_SHARE_READ, // share for reading + NULL, // default security + OPEN_EXISTING, // existing file only + FILE_FLAG_BACKUP_SEMANTICS, // normal file + NULL); // no attr. template + + if( hFile == INVALID_HANDLE_VALUE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not open file (error %d)", GetLastError()); + RETURN_FALSE; + } + + dwRet = pGetFinalPathNameByHandle(hFile, Path, MAXPATHLEN, VOLUME_NAME_NT); + if(dwRet >= MAXPATHLEN) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't resolve the full path, the path exceeds the MAX_PATH_LEN (%d) limit", MAXPATHLEN); + RETURN_FALSE; + } + + CloseHandle(hFile); + + /* Append NULL to the end of the string */ + Path[dwRet] = '\0'; + + RETURN_STRING(Path, 1); +} +/* }}} */ + +/* {{{ proto int linkinfo(string filename) + Returns the st_dev field of the UNIX C stat structure describing the link */ +PHP_FUNCTION(linkinfo) +{ + char *link; + int link_len; + struct stat sb; + int ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &link, &link_len) == FAILURE) { + return; + } + + ret = VCWD_STAT(link, &sb); + if (ret == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_LONG(-1L); + } + + RETURN_LONG((long) sb.st_dev); +} +/* }}} */ + +/* {{{ proto int symlink(string target, string link) + Create a symbolic link */ +PHP_FUNCTION(symlink) +{ + char *topath, *frompath; + int topath_len, frompath_len; + BOOLEAN ret; + char source_p[MAXPATHLEN]; + char dest_p[MAXPATHLEN]; + char dirname[MAXPATHLEN]; + size_t len; + DWORD attr; + HINSTANCE kernel32; + typedef BOOLEAN (WINAPI *csla_func)( __in LPCSTR, __in LPCSTR, __in DWORD); + csla_func pCreateSymbolicLinkA; + + kernel32 = LoadLibrary("kernel32.dll"); + + if (kernel32) { + pCreateSymbolicLinkA = (csla_func)GetProcAddress(kernel32, "CreateSymbolicLinkA"); + if (pCreateSymbolicLinkA == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't call CreateSymbolicLinkA"); + RETURN_FALSE; + } + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't call get a handle on kernel32.dll"); + RETURN_FALSE; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &topath, &topath_len, &frompath, &frompath_len) == FAILURE) { + return; + } + + if (!expand_filepath(frompath, source_p TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory"); + RETURN_FALSE; + } + + memcpy(dirname, source_p, sizeof(source_p)); + len = php_dirname(dirname, strlen(dirname)); + + if (!expand_filepath_ex(topath, dest_p, dirname, len TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory"); + RETURN_FALSE; + } + + if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) || + php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ) + { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to symlink to a URL"); + RETURN_FALSE; + } + + if (PG(safe_mode) && !php_checkuid(dest_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) { + RETURN_FALSE; + } + + if (PG(safe_mode) && !php_checkuid(source_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(dest_p TSRMLS_CC)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(source_p TSRMLS_CC)) { + RETURN_FALSE; + } + + if ((attr = GetFileAttributes(topath)) == INVALID_FILE_ATTRIBUTES) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch file information(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 = pCreateSymbolicLinkA(source_p, topath, (attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0)); + + if (!ret) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create symlink, error code(%d)", GetLastError()); + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int link(string target, string link) + Create a hard link */ +PHP_FUNCTION(link) +{ + char *topath, *frompath; + int topath_len, frompath_len; + int ret; + char source_p[MAXPATHLEN]; + char dest_p[MAXPATHLEN]; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &topath, &topath_len, &frompath, &frompath_len) == FAILURE) { + return; + } + + if (!expand_filepath(frompath, source_p TSRMLS_CC) || !expand_filepath(topath, dest_p TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory"); + RETURN_FALSE; + } + + if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) || + php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ) + { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to link to a URL"); + RETURN_FALSE; + } + + if (PG(safe_mode) && !php_checkuid(dest_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) { + RETURN_FALSE; + } + + if (PG(safe_mode) && !php_checkuid(source_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(dest_p TSRMLS_CC)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(source_p TSRMLS_CC)) { + RETURN_FALSE; + } + +#ifndef ZTS + ret = CreateHardLinkA(topath, frompath, NULL); +#else + ret = CreateHardLinkA(dest_p, source_p, NULL); +#endif + if (ret == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ + +#endif + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/standard/php_link.h b/ext/standard/php_link.h index 64e97ef4eb..58669457cb 100644 --- a/ext/standard/php_link.h +++ b/ext/standard/php_link.h @@ -21,7 +21,7 @@ #ifndef PHP_LINK_H #define PHP_LINK_H -#ifdef HAVE_SYMLINK +#if defined(HAVE_SYMLINK) || defined(PHP_WIN32) PHP_FUNCTION(link); PHP_FUNCTION(readlink); |