xref: /PHP-7.3/ext/standard/link.c (revision 8d3f8ca1)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author:                                                              |
16    +----------------------------------------------------------------------+
17  */
18 
19 #include "php.h"
20 #include "php_filestat.h"
21 #include "php_globals.h"
22 
23 #ifdef HAVE_SYMLINK
24 
25 #include <stdlib.h>
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #include <sys/stat.h>
30 #include <string.h>
31 #if HAVE_PWD_H
32 #ifdef PHP_WIN32
33 #include "win32/pwd.h"
34 #else
35 #include <pwd.h>
36 #endif
37 #endif
38 #if HAVE_GRP_H
39 #ifdef PHP_WIN32
40 #include "win32/grp.h"
41 #else
42 #include <grp.h>
43 #endif
44 #endif
45 #include <errno.h>
46 #include <ctype.h>
47 
48 #include "php_link.h"
49 #include "php_string.h"
50 
51 /* {{{ proto string readlink(string filename)
52    Return the target of a symbolic link */
PHP_FUNCTION(readlink)53 PHP_FUNCTION(readlink)
54 {
55 	char *link;
56 	size_t link_len;
57 	char buff[MAXPATHLEN];
58 	ssize_t ret;
59 
60 	ZEND_PARSE_PARAMETERS_START(1, 1)
61 		Z_PARAM_PATH(link, link_len)
62 	ZEND_PARSE_PARAMETERS_END();
63 
64 	if (php_check_open_basedir(link)) {
65 		RETURN_FALSE;
66 	}
67 
68 	ret = php_sys_readlink(link, buff, MAXPATHLEN-1);
69 
70 	if (ret == -1) {
71 		php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
72 		RETURN_FALSE;
73 	}
74 	/* Append NULL to the end of the string */
75 	buff[ret] = '\0';
76 
77 	RETURN_STRINGL(buff, ret);
78 }
79 /* }}} */
80 
81 /* {{{ proto int linkinfo(string filename)
82    Returns the st_dev field of the UNIX C stat structure describing the link */
PHP_FUNCTION(linkinfo)83 PHP_FUNCTION(linkinfo)
84 {
85 	char *link;
86 	char *dirname;
87 	size_t link_len;
88 	zend_stat_t sb;
89 	int ret;
90 
91 	ZEND_PARSE_PARAMETERS_START(1, 1)
92 		Z_PARAM_PATH(link, link_len)
93 	ZEND_PARSE_PARAMETERS_END();
94 
95 	dirname = estrndup(link, link_len);
96 	php_dirname(dirname, link_len);
97 
98 	if (php_check_open_basedir(dirname)) {
99 		efree(dirname);
100 		RETURN_FALSE;
101 	}
102 
103 	ret = VCWD_LSTAT(link, &sb);
104 	if (ret == -1) {
105 		php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
106 		efree(dirname);
107 		RETURN_LONG(-1L);
108 	}
109 
110 	efree(dirname);
111 	RETURN_LONG((zend_long) sb.st_dev);
112 }
113 /* }}} */
114 
115 /* {{{ proto int symlink(string target, string link)
116    Create a symbolic link */
PHP_FUNCTION(symlink)117 PHP_FUNCTION(symlink)
118 {
119 	char *topath, *frompath;
120 	size_t topath_len, frompath_len;
121 	int ret;
122 	char source_p[MAXPATHLEN];
123 	char dest_p[MAXPATHLEN];
124 	char dirname[MAXPATHLEN];
125 	size_t len;
126 
127 	ZEND_PARSE_PARAMETERS_START(2, 2)
128 		Z_PARAM_PATH(topath, topath_len)
129 		Z_PARAM_PATH(frompath, frompath_len)
130 	ZEND_PARSE_PARAMETERS_END();
131 
132 	if (!expand_filepath(frompath, source_p)) {
133 		php_error_docref(NULL, E_WARNING, "No such file or directory");
134 		RETURN_FALSE;
135 	}
136 
137 	memcpy(dirname, source_p, sizeof(source_p));
138 	len = php_dirname(dirname, strlen(dirname));
139 
140 	if (!expand_filepath_ex(topath, dest_p, dirname, len)) {
141 		php_error_docref(NULL, E_WARNING, "No such file or directory");
142 		RETURN_FALSE;
143 	}
144 
145 	if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) ||
146 		php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) )
147 	{
148 		php_error_docref(NULL, E_WARNING, "Unable to symlink to a URL");
149 		RETURN_FALSE;
150 	}
151 
152 	if (php_check_open_basedir(dest_p)) {
153 		RETURN_FALSE;
154 	}
155 
156 	if (php_check_open_basedir(source_p)) {
157 		RETURN_FALSE;
158 	}
159 
160 	/* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD).
161 	 * For the target the exact string given by the user must be used, relative or not, existing or not.
162 	 * The target is relative to the link itself, not to the CWD. */
163 	ret = symlink(topath, source_p);
164 
165 	if (ret == -1) {
166 		php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
167 		RETURN_FALSE;
168 	}
169 
170 	RETURN_TRUE;
171 }
172 /* }}} */
173 
174 /* {{{ proto int link(string target, string link)
175    Create a hard link */
PHP_FUNCTION(link)176 PHP_FUNCTION(link)
177 {
178 	char *topath, *frompath;
179 	size_t topath_len, frompath_len;
180 	int ret;
181 	char source_p[MAXPATHLEN];
182 	char dest_p[MAXPATHLEN];
183 
184 	ZEND_PARSE_PARAMETERS_START(2, 2)
185 		Z_PARAM_PATH(topath, topath_len)
186 		Z_PARAM_PATH(frompath, frompath_len)
187 	ZEND_PARSE_PARAMETERS_END();
188 
189 	if (!expand_filepath(frompath, source_p) || !expand_filepath(topath, dest_p)) {
190 		php_error_docref(NULL, E_WARNING, "No such file or directory");
191 		RETURN_FALSE;
192 	}
193 
194 	if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) ||
195 		php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) )
196 	{
197 		php_error_docref(NULL, E_WARNING, "Unable to link to a URL");
198 		RETURN_FALSE;
199 	}
200 
201 	if (php_check_open_basedir(dest_p)) {
202 		RETURN_FALSE;
203 	}
204 
205 	if (php_check_open_basedir(source_p)) {
206 		RETURN_FALSE;
207 	}
208 
209 #ifndef ZTS
210 	ret = link(topath, frompath);
211 #else
212 	ret = link(dest_p, source_p);
213 #endif
214 	if (ret == -1) {
215 		php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
216 		RETURN_FALSE;
217 	}
218 
219 	RETURN_TRUE;
220 }
221 /* }}} */
222 
223 #endif
224 
225 /*
226  * Local variables:
227  * tab-width: 4
228  * c-basic-offset: 4
229  * End:
230  * vim600: noet sw=4 ts=4 fdm=marker
231  * vim<600: noet sw=4 ts=4
232  */
233