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: Pierre A. Joye <pierre@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20 #ifdef PHP_WIN32
21
22 #include "php.h"
23 #include "php_filestat.h"
24 #include "php_globals.h"
25
26 #include <WinBase.h>
27
28 #include <stdlib.h>
29
30 #include <string.h>
31 #if HAVE_PWD_H
32 #include "win32/pwd.h"
33 #endif
34
35 #if HAVE_GRP_H
36 #include "win32/grp.h"
37 #endif
38
39 #include <errno.h>
40 #include <ctype.h>
41
42 #include "safe_mode.h"
43 #include "php_link.h"
44 #include "php_string.h"
45
46 /*
47 TODO:
48 - Create php_readlink (done), php_link and php_symlink in win32/link.c
49 - Expose them (PHPAPI) so extensions developers can use them
50 - define link/readlink/symlink to their php_ equivalent and use them in ext/standart/link.c
51 - this file is then useless and we have a portable link API
52 */
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 target[MAXPATHLEN];
61
62 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &link, &link_len) == FAILURE) {
63 return;
64 }
65
66 if (OPENBASEDIR_CHECKPATH(link)) {
67 RETURN_FALSE;
68 }
69
70 if (php_sys_readlink(link, target, MAXPATHLEN) == -1) {
71 php_error_docref(NULL TSRMLS_CC, E_WARNING, "readlink failed to read the symbolic link (%s), error %d)", link, GetLastError());
72 RETURN_FALSE;
73 }
74 RETURN_STRING(target, 1);
75 }
76 /* }}} */
77
78 /* {{{ proto int linkinfo(string filename)
79 Returns the st_dev field of the UNIX C stat structure describing the link */
PHP_FUNCTION(linkinfo)80 PHP_FUNCTION(linkinfo)
81 {
82 char *link;
83 int link_len;
84 struct stat sb;
85 int ret;
86
87 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &link, &link_len) == FAILURE) {
88 return;
89 }
90
91 ret = VCWD_STAT(link, &sb);
92 if (ret == -1) {
93 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
94 RETURN_LONG(-1L);
95 }
96
97 RETURN_LONG((long) sb.st_dev);
98 }
99 /* }}} */
100
101 /* {{{ proto int symlink(string target, string link)
102 Create a symbolic link */
PHP_FUNCTION(symlink)103 PHP_FUNCTION(symlink)
104 {
105 char *topath, *frompath;
106 int topath_len, frompath_len;
107 BOOLEAN ret;
108 char source_p[MAXPATHLEN];
109 char dest_p[MAXPATHLEN];
110 char dirname[MAXPATHLEN];
111 size_t len;
112 DWORD attr;
113 HINSTANCE kernel32;
114 typedef BOOLEAN (WINAPI *csla_func)(LPCSTR, LPCSTR, DWORD);
115 csla_func pCreateSymbolicLinkA;
116
117 kernel32 = LoadLibrary("kernel32.dll");
118
119 if (kernel32) {
120 pCreateSymbolicLinkA = (csla_func)GetProcAddress(kernel32, "CreateSymbolicLinkA");
121 if (pCreateSymbolicLinkA == NULL) {
122 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't call CreateSymbolicLinkA");
123 RETURN_FALSE;
124 }
125 } else {
126 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't call get a handle on kernel32.dll");
127 RETURN_FALSE;
128 }
129
130 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &topath, &topath_len, &frompath, &frompath_len) == FAILURE) {
131 return;
132 }
133
134 if (!expand_filepath(frompath, source_p TSRMLS_CC)) {
135 php_error_docref(NULL TSRMLS_CC, 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 TSRMLS_CC)) {
143 php_error_docref(NULL TSRMLS_CC, 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 TSRMLS_CC) ||
148 php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) )
149 {
150 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to symlink to a URL");
151 RETURN_FALSE;
152 }
153
154 if (OPENBASEDIR_CHECKPATH(dest_p)) {
155 RETURN_FALSE;
156 }
157
158 if (OPENBASEDIR_CHECKPATH(source_p)) {
159 RETURN_FALSE;
160 }
161
162 if ((attr = GetFileAttributes(topath)) == INVALID_FILE_ATTRIBUTES) {
163 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not fetch file information(error %d)", GetLastError());
164 RETURN_FALSE;
165 }
166
167 /* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD).
168 * For the target the exact string given by the user must be used, relative or not, existing or not.
169 * The target is relative to the link itself, not to the CWD. */
170 ret = pCreateSymbolicLinkA(source_p, topath, (attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0));
171
172 if (!ret) {
173 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create symlink, error code(%d)", GetLastError());
174 RETURN_FALSE;
175 }
176
177 RETURN_TRUE;
178 }
179 /* }}} */
180
181 /* {{{ proto int link(string target, string link)
182 Create a hard link */
PHP_FUNCTION(link)183 PHP_FUNCTION(link)
184 {
185 char *topath, *frompath;
186 int topath_len, frompath_len;
187 int ret;
188 char source_p[MAXPATHLEN];
189 char dest_p[MAXPATHLEN];
190
191 /*First argument to link function is the target and hence should go to frompath
192 Second argument to link function is the link itself and hence should go to topath */
193 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &frompath, &frompath_len, &topath, &topath_len) == FAILURE) {
194 return;
195 }
196
197 if (!expand_filepath(frompath, source_p TSRMLS_CC) || !expand_filepath(topath, dest_p TSRMLS_CC)) {
198 php_error_docref(NULL TSRMLS_CC, E_WARNING, "No such file or directory");
199 RETURN_FALSE;
200 }
201
202 if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ||
203 php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) )
204 {
205 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to link to a URL");
206 RETURN_FALSE;
207 }
208
209 if (OPENBASEDIR_CHECKPATH(source_p)) {
210 RETURN_FALSE;
211 }
212
213 if (OPENBASEDIR_CHECKPATH(dest_p)) {
214 RETURN_FALSE;
215 }
216
217 #ifndef ZTS
218 ret = CreateHardLinkA(topath, frompath, NULL);
219 #else
220 ret = CreateHardLinkA(dest_p, source_p, NULL);
221 #endif
222
223 if (ret == 0) {
224 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
225 RETURN_FALSE;
226 }
227
228 RETURN_TRUE;
229 }
230 /* }}} */
231
232 #endif
233
234 /*
235 * Local variables:
236 * tab-width: 4
237 * c-basic-offset: 4
238 * End:
239 * vim600: noet sw=4 ts=4 fdm=marker
240 * vim<600: noet sw=4 ts=4
241 */
242