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