link.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 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. #include "php.h"
  19. #include "php_filestat.h"
  20. #include "php_globals.h"
  21. #ifdef HAVE_SYMLINK
  22. #include <stdlib.h>
  23. #if HAVE_UNISTD_H
  24. #include <unistd.h>
  25. #endif
  26. #include <sys/stat.h>
  27. #include <string.h>
  28. #if HAVE_PWD_H
  29. #ifdef PHP_WIN32
  30. #include "win32/pwd.h"
  31. #else
  32. #include <pwd.h>
  33. #endif
  34. #endif
  35. #if HAVE_GRP_H
  36. #ifdef PHP_WIN32
  37. #include "win32/grp.h"
  38. #else
  39. #include <grp.h>
  40. #endif
  41. #endif
  42. #include <errno.h>
  43. #include <ctype.h>
  44. #include "php_link.h"
  45. #include "php_string.h"
  46. /* {{{ proto string readlink(string filename)
  47. Return the target of a symbolic link */
  48. PHP_FUNCTION(readlink)
  49. {
  50. char *link;
  51. size_t link_len;
  52. char buff[MAXPATHLEN];
  53. ssize_t ret;
  54. ZEND_PARSE_PARAMETERS_START(1, 1)
  55. Z_PARAM_PATH(link, link_len)
  56. ZEND_PARSE_PARAMETERS_END();
  57. if (php_check_open_basedir(link)) {
  58. RETURN_FALSE;
  59. }
  60. ret = php_sys_readlink(link, buff, MAXPATHLEN-1);
  61. if (ret == -1) {
  62. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  63. RETURN_FALSE;
  64. }
  65. /* Append NULL to the end of the string */
  66. buff[ret] = '\0';
  67. RETURN_STRINGL(buff, ret);
  68. }
  69. /* }}} */
  70. /* {{{ proto int linkinfo(string filename)
  71. Returns the st_dev field of the UNIX C stat structure describing the link */
  72. PHP_FUNCTION(linkinfo)
  73. {
  74. char *link;
  75. char *dirname;
  76. size_t link_len;
  77. zend_stat_t sb;
  78. int ret;
  79. ZEND_PARSE_PARAMETERS_START(1, 1)
  80. Z_PARAM_PATH(link, link_len)
  81. ZEND_PARSE_PARAMETERS_END();
  82. dirname = estrndup(link, link_len);
  83. php_dirname(dirname, link_len);
  84. if (php_check_open_basedir(dirname)) {
  85. efree(dirname);
  86. RETURN_FALSE;
  87. }
  88. ret = VCWD_LSTAT(link, &sb);
  89. if (ret == -1) {
  90. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  91. efree(dirname);
  92. RETURN_LONG(-1L);
  93. }
  94. efree(dirname);
  95. RETURN_LONG((zend_long) sb.st_dev);
  96. }
  97. /* }}} */
  98. /* {{{ proto int symlink(string target, string link)
  99. Create a symbolic link */
  100. PHP_FUNCTION(symlink)
  101. {
  102. char *topath, *frompath;
  103. size_t topath_len, frompath_len;
  104. int ret;
  105. char source_p[MAXPATHLEN];
  106. char dest_p[MAXPATHLEN];
  107. char dirname[MAXPATHLEN];
  108. size_t len;
  109. ZEND_PARSE_PARAMETERS_START(2, 2)
  110. Z_PARAM_PATH(topath, topath_len)
  111. Z_PARAM_PATH(frompath, frompath_len)
  112. ZEND_PARSE_PARAMETERS_END();
  113. if (!expand_filepath(frompath, source_p)) {
  114. php_error_docref(NULL, E_WARNING, "No such file or directory");
  115. RETURN_FALSE;
  116. }
  117. memcpy(dirname, source_p, sizeof(source_p));
  118. len = php_dirname(dirname, strlen(dirname));
  119. if (!expand_filepath_ex(topath, dest_p, dirname, len)) {
  120. php_error_docref(NULL, E_WARNING, "No such file or directory");
  121. RETURN_FALSE;
  122. }
  123. if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) ||
  124. php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) )
  125. {
  126. php_error_docref(NULL, E_WARNING, "Unable to symlink to a URL");
  127. RETURN_FALSE;
  128. }
  129. if (php_check_open_basedir(dest_p)) {
  130. RETURN_FALSE;
  131. }
  132. if (php_check_open_basedir(source_p)) {
  133. RETURN_FALSE;
  134. }
  135. /* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD).
  136. * For the target the exact string given by the user must be used, relative or not, existing or not.
  137. * The target is relative to the link itself, not to the CWD. */
  138. ret = symlink(topath, source_p);
  139. if (ret == -1) {
  140. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  141. RETURN_FALSE;
  142. }
  143. RETURN_TRUE;
  144. }
  145. /* }}} */
  146. /* {{{ proto int link(string target, string link)
  147. Create a hard link */
  148. PHP_FUNCTION(link)
  149. {
  150. char *topath, *frompath;
  151. size_t topath_len, frompath_len;
  152. int ret;
  153. char source_p[MAXPATHLEN];
  154. char dest_p[MAXPATHLEN];
  155. ZEND_PARSE_PARAMETERS_START(2, 2)
  156. Z_PARAM_PATH(topath, topath_len)
  157. Z_PARAM_PATH(frompath, frompath_len)
  158. ZEND_PARSE_PARAMETERS_END();
  159. if (!expand_filepath(frompath, source_p) || !expand_filepath(topath, dest_p)) {
  160. php_error_docref(NULL, E_WARNING, "No such file or directory");
  161. RETURN_FALSE;
  162. }
  163. if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) ||
  164. php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) )
  165. {
  166. php_error_docref(NULL, E_WARNING, "Unable to link to a URL");
  167. RETURN_FALSE;
  168. }
  169. if (php_check_open_basedir(dest_p)) {
  170. RETURN_FALSE;
  171. }
  172. if (php_check_open_basedir(source_p)) {
  173. RETURN_FALSE;
  174. }
  175. #ifndef ZTS
  176. ret = link(topath, frompath);
  177. #else
  178. ret = link(dest_p, source_p);
  179. #endif
  180. if (ret == -1) {
  181. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  182. RETURN_FALSE;
  183. }
  184. RETURN_TRUE;
  185. }
  186. /* }}} */
  187. #endif
  188. /*
  189. * Local variables:
  190. * tab-width: 4
  191. * c-basic-offset: 4
  192. * End:
  193. * vim600: noet sw=4 ts=4 fdm=marker
  194. * vim<600: noet sw=4 ts=4
  195. */