diff options
Diffstat (limited to 'ext/standard/link.c')
-rw-r--r-- | ext/standard/link.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/ext/standard/link.c b/ext/standard/link.c new file mode 100644 index 0000000..8da6395 --- /dev/null +++ b/ext/standard/link.c @@ -0,0 +1,232 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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: | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#include "php.h" +#include "php_filestat.h" +#include "php_globals.h" + +#ifdef HAVE_SYMLINK + +#include <stdlib.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/stat.h> +#include <string.h> +#if HAVE_PWD_H +#ifdef PHP_WIN32 +#include "win32/pwd.h" +#else +#include <pwd.h> +#endif +#endif +#if HAVE_GRP_H +#ifdef PHP_WIN32 +#include "win32/grp.h" +#else +#include <grp.h> +#endif +#endif +#include <errno.h> +#include <ctype.h> + +#include "php_link.h" +#include "php_string.h" + +/* {{{ proto string readlink(string filename) + Return the target of a symbolic link */ +PHP_FUNCTION(readlink) +{ + char *link; + int link_len; + char buff[MAXPATHLEN]; + int ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &link, &link_len) == FAILURE) { + return; + } + + if (php_check_open_basedir(link TSRMLS_CC)) { + RETURN_FALSE; + } + + ret = php_sys_readlink(link, buff, MAXPATHLEN-1); + + if (ret == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + RETURN_FALSE; + } + /* Append NULL to the end of the string */ + buff[ret] = '\0'; + + RETURN_STRING(buff, 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; + char *dirname; + int link_len, dir_len; + struct stat sb; + int ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &link, &link_len) == FAILURE) { + return; + } + + dirname = estrndup(link, link_len); + dir_len = php_dirname(dirname, link_len); + + if (php_check_open_basedir(dirname TSRMLS_CC)) { + efree(dirname); + RETURN_FALSE; + } + + ret = VCWD_LSTAT(link, &sb); + if (ret == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + efree(dirname); + RETURN_LONG(-1L); + } + + efree(dirname); + 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; + int ret; + char source_p[MAXPATHLEN]; + char dest_p[MAXPATHLEN]; + char dirname[MAXPATHLEN]; + size_t len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pp", &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 (php_check_open_basedir(dest_p TSRMLS_CC)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(source_p TSRMLS_CC)) { + 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 = symlink(topath, source_p); + + if (ret == -1) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno)); + 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, "pp", &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 (php_check_open_basedir(dest_p TSRMLS_CC)) { + RETURN_FALSE; + } + + if (php_check_open_basedir(source_p TSRMLS_CC)) { + RETURN_FALSE; + } + +#ifndef ZTS + ret = link(topath, frompath); +#else + ret = link(dest_p, source_p); +#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 + */ |