1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 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 */ |
55 | PHP_FUNCTION(readlink) |
56 | { |
57 | char *link; |
58 | int link_len; |
59 | char buff[MAXPATHLEN]; |
60 | int ret; |
61 | |
62 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p" , &link, &link_len) == FAILURE) { |
63 | return; |
64 | } |
65 | |
66 | if (php_check_open_basedir(link TSRMLS_CC)) { |
67 | RETURN_FALSE; |
68 | } |
69 | |
70 | ret = php_sys_readlink(link, buff, MAXPATHLEN-1); |
71 | |
72 | if (ret == -1) { |
73 | php_error_docref(NULL TSRMLS_CC, 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, 1); |
80 | } |
81 | /* }}} */ |
82 | |
83 | /* {{{ proto int linkinfo(string filename) |
84 | Returns the st_dev field of the UNIX C stat structure describing the link */ |
85 | PHP_FUNCTION(linkinfo) |
86 | { |
87 | char *link; |
88 | char *dirname; |
89 | int link_len, dir_len; |
90 | struct stat sb; |
91 | int ret; |
92 | |
93 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p" , &link, &link_len) == FAILURE) { |
94 | return; |
95 | } |
96 | |
97 | dirname = estrndup(link, link_len); |
98 | dir_len = php_dirname(dirname, link_len); |
99 | |
100 | if (php_check_open_basedir(dirname TSRMLS_CC)) { |
101 | efree(dirname); |
102 | RETURN_FALSE; |
103 | } |
104 | |
105 | ret = VCWD_LSTAT(link, &sb); |
106 | if (ret == -1) { |
107 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
108 | efree(dirname); |
109 | RETURN_LONG(-1L); |
110 | } |
111 | |
112 | efree(dirname); |
113 | RETURN_LONG((long) sb.st_dev); |
114 | } |
115 | /* }}} */ |
116 | |
117 | /* {{{ proto int symlink(string target, string link) |
118 | Create a symbolic link */ |
119 | PHP_FUNCTION(symlink) |
120 | { |
121 | char *topath, *frompath; |
122 | int 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 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pp" , &topath, &topath_len, &frompath, &frompath_len) == FAILURE) { |
130 | return; |
131 | } |
132 | |
133 | if (!expand_filepath(frompath, source_p TSRMLS_CC)) { |
134 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory" ); |
135 | RETURN_FALSE; |
136 | } |
137 | |
138 | memcpy(dirname, source_p, sizeof(source_p)); |
139 | len = php_dirname(dirname, strlen(dirname)); |
140 | |
141 | if (!expand_filepath_ex(topath, dest_p, dirname, len TSRMLS_CC)) { |
142 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory" ); |
143 | RETURN_FALSE; |
144 | } |
145 | |
146 | if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) || |
147 | php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ) |
148 | { |
149 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to symlink to a URL" ); |
150 | RETURN_FALSE; |
151 | } |
152 | |
153 | if (php_check_open_basedir(dest_p TSRMLS_CC)) { |
154 | RETURN_FALSE; |
155 | } |
156 | |
157 | if (php_check_open_basedir(source_p TSRMLS_CC)) { |
158 | RETURN_FALSE; |
159 | } |
160 | |
161 | /* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD). |
162 | * For the target the exact string given by the user must be used, relative or not, existing or not. |
163 | * The target is relative to the link itself, not to the CWD. */ |
164 | ret = symlink(topath, source_p); |
165 | |
166 | if (ret == -1) { |
167 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s" , strerror(errno)); |
168 | RETURN_FALSE; |
169 | } |
170 | |
171 | RETURN_TRUE; |
172 | } |
173 | /* }}} */ |
174 | |
175 | /* {{{ proto int link(string target, string link) |
176 | Create a hard link */ |
177 | PHP_FUNCTION(link) |
178 | { |
179 | char *topath, *frompath; |
180 | int topath_len, frompath_len; |
181 | int ret; |
182 | char source_p[MAXPATHLEN]; |
183 | char dest_p[MAXPATHLEN]; |
184 | |
185 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "pp" , &topath, &topath_len, &frompath, &frompath_len) == FAILURE) { |
186 | return; |
187 | } |
188 | |
189 | if (!expand_filepath(frompath, source_p TSRMLS_CC) || !expand_filepath(topath, dest_p TSRMLS_CC)) { |
190 | php_error_docref(NULL TSRMLS_CC, 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 TSRMLS_CC) || |
195 | php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ) |
196 | { |
197 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to link to a URL" ); |
198 | RETURN_FALSE; |
199 | } |
200 | |
201 | if (php_check_open_basedir(dest_p TSRMLS_CC)) { |
202 | RETURN_FALSE; |
203 | } |
204 | |
205 | if (php_check_open_basedir(source_p TSRMLS_CC)) { |
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 TSRMLS_CC, 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 | |