xref: /PHP-5.3/ext/standard/link_win32.c (revision a2045ff3)
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