1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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 "safe_mode.h"
51 #include "php_link.h"
52 #include "php_string.h"
53
54 /* {{{ proto string readlink(string filename)
55 Return the target of a symbolic link */
PHP_FUNCTION(readlink)56 PHP_FUNCTION(readlink)
57 {
58 char *link;
59 int link_len;
60 char buff[MAXPATHLEN];
61 int ret;
62
63 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &link, &link_len) == FAILURE) {
64 return;
65 }
66
67 if (strlen(link) != link_len) {
68 RETURN_FALSE;
69 }
70
71 if (PG(safe_mode) && !php_checkuid(link, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
72 RETURN_FALSE;
73 }
74
75 if (php_check_open_basedir(link TSRMLS_CC)) {
76 RETURN_FALSE;
77 }
78
79 ret = php_sys_readlink(link, buff, MAXPATHLEN-1);
80
81 if (ret == -1) {
82 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
83 RETURN_FALSE;
84 }
85 /* Append NULL to the end of the string */
86 buff[ret] = '\0';
87
88 RETURN_STRING(buff, 1);
89 }
90 /* }}} */
91
92 /* {{{ proto int linkinfo(string filename)
93 Returns the st_dev field of the UNIX C stat structure describing the link */
PHP_FUNCTION(linkinfo)94 PHP_FUNCTION(linkinfo)
95 {
96 char *link;
97 char *dirname;
98 int link_len, dir_len;
99 struct stat sb;
100 int ret;
101
102 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &link, &link_len) == FAILURE) {
103 return;
104 }
105
106 dirname = estrndup(link, link_len);
107 dir_len = php_dirname(dirname, link_len);
108
109 if (php_check_open_basedir(dirname TSRMLS_CC)) {
110 efree(dirname);
111 RETURN_FALSE;
112 }
113
114 ret = VCWD_LSTAT(link, &sb);
115 if (ret == -1) {
116 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
117 efree(dirname);
118 RETURN_LONG(-1L);
119 }
120
121 efree(dirname);
122 RETURN_LONG((long) sb.st_dev);
123 }
124 /* }}} */
125
126 /* {{{ proto int symlink(string target, string link)
127 Create a symbolic link */
PHP_FUNCTION(symlink)128 PHP_FUNCTION(symlink)
129 {
130 char *topath, *frompath;
131 int topath_len, frompath_len;
132 int ret;
133 char source_p[MAXPATHLEN];
134 char dest_p[MAXPATHLEN];
135 char dirname[MAXPATHLEN];
136 size_t len;
137
138 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &topath, &topath_len, &frompath, &frompath_len) == FAILURE) {
139 return;
140 }
141
142 if (strlen(topath) != topath_len) {
143 RETURN_FALSE;
144 }
145
146 if (strlen(frompath) != frompath_len) {
147 RETURN_FALSE;
148 }
149
150 if (!expand_filepath(frompath, source_p TSRMLS_CC)) {
151 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory");
152 RETURN_FALSE;
153 }
154
155 memcpy(dirname, source_p, sizeof(source_p));
156 len = php_dirname(dirname, strlen(dirname));
157
158 if (!expand_filepath_ex(topath, dest_p, dirname, len TSRMLS_CC)) {
159 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory");
160 RETURN_FALSE;
161 }
162
163 if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ||
164 php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) )
165 {
166 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to symlink to a URL");
167 RETURN_FALSE;
168 }
169
170 if (PG(safe_mode) && !php_checkuid(dest_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
171 RETURN_FALSE;
172 }
173
174 if (PG(safe_mode) && !php_checkuid(source_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
175 RETURN_FALSE;
176 }
177
178 if (php_check_open_basedir(dest_p TSRMLS_CC)) {
179 RETURN_FALSE;
180 }
181
182 if (php_check_open_basedir(source_p TSRMLS_CC)) {
183 RETURN_FALSE;
184 }
185
186 /* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD).
187 * For the target the exact string given by the user must be used, relative or not, existing or not.
188 * The target is relative to the link itself, not to the CWD. */
189 ret = symlink(topath, source_p);
190
191 if (ret == -1) {
192 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
193 RETURN_FALSE;
194 }
195
196 RETURN_TRUE;
197 }
198 /* }}} */
199
200 /* {{{ proto int link(string target, string link)
201 Create a hard link */
PHP_FUNCTION(link)202 PHP_FUNCTION(link)
203 {
204 char *topath, *frompath;
205 int topath_len, frompath_len;
206 int ret;
207 char source_p[MAXPATHLEN];
208 char dest_p[MAXPATHLEN];
209
210 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &topath, &topath_len, &frompath, &frompath_len) == FAILURE) {
211 return;
212 }
213
214 if (strlen(topath) != topath_len) {
215 RETURN_FALSE;
216 }
217
218 if (strlen(frompath) != frompath_len) {
219 RETURN_FALSE;
220 }
221
222 if (!expand_filepath(frompath, source_p TSRMLS_CC) || !expand_filepath(topath, dest_p TSRMLS_CC)) {
223 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory");
224 RETURN_FALSE;
225 }
226
227 if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ||
228 php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) )
229 {
230 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to link to a URL");
231 RETURN_FALSE;
232 }
233
234 if (PG(safe_mode) && !php_checkuid(dest_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
235 RETURN_FALSE;
236 }
237
238 if (PG(safe_mode) && !php_checkuid(source_p, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
239 RETURN_FALSE;
240 }
241
242 if (php_check_open_basedir(dest_p TSRMLS_CC)) {
243 RETURN_FALSE;
244 }
245
246 if (php_check_open_basedir(source_p TSRMLS_CC)) {
247 RETURN_FALSE;
248 }
249
250 #ifndef ZTS
251 ret = link(topath, frompath);
252 #else
253 ret = link(dest_p, source_p);
254 #endif
255 if (ret == -1) {
256 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
257 RETURN_FALSE;
258 }
259
260 RETURN_TRUE;
261 }
262 /* }}} */
263
264 #endif
265
266 /*
267 * Local variables:
268 * tab-width: 4
269 * c-basic-offset: 4
270 * End:
271 * vim600: noet sw=4 ts=4 fdm=marker
272 * vim<600: noet sw=4 ts=4
273 */
274