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