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