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 */
55PHP_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 */
85PHP_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 */
119PHP_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 */
177PHP_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