link.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "php.h"
  17. #include "php_filestat.h"
  18. #include "php_globals.h"
  19. #if defined(HAVE_SYMLINK) || defined(PHP_WIN32)
  20. #ifdef PHP_WIN32
  21. #include <WinBase.h>
  22. #endif
  23. #include <stdlib.h>
  24. #if HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27. #ifndef PHP_WIN32
  28. #include <sys/stat.h>
  29. #endif
  30. #include <string.h>
  31. #if HAVE_PWD_H
  32. #ifdef PHP_WIN32
  33. #include "win32/pwd.h"
  34. #else
  35. #include <pwd.h>
  36. #endif
  37. #endif
  38. #if HAVE_GRP_H
  39. # include <grp.h>
  40. #endif
  41. #include <errno.h>
  42. #include <ctype.h>
  43. #include "php_string.h"
  44. #ifndef VOLUME_NAME_NT
  45. #define VOLUME_NAME_NT 0x2
  46. #endif
  47. #ifndef VOLUME_NAME_DOS
  48. #define VOLUME_NAME_DOS 0x0
  49. #endif
  50. /* {{{ Return the target of a symbolic link */
  51. PHP_FUNCTION(readlink)
  52. {
  53. char *link;
  54. size_t link_len;
  55. char buff[MAXPATHLEN];
  56. ssize_t ret;
  57. ZEND_PARSE_PARAMETERS_START(1, 1)
  58. Z_PARAM_PATH(link, link_len)
  59. ZEND_PARSE_PARAMETERS_END();
  60. if (php_check_open_basedir(link)) {
  61. RETURN_FALSE;
  62. }
  63. ret = php_sys_readlink(link, buff, MAXPATHLEN-1);
  64. if (ret == -1) {
  65. #ifdef PHP_WIN32
  66. php_error_docref(NULL, E_WARNING, "readlink failed to read the symbolic link (%s), error %d)", link, GetLastError());
  67. #else
  68. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  69. #endif
  70. RETURN_FALSE;
  71. }
  72. /* Append NULL to the end of the string */
  73. buff[ret] = '\0';
  74. RETURN_STRINGL(buff, ret);
  75. }
  76. /* }}} */
  77. /* {{{ Returns the st_dev field of the UNIX C stat structure describing the link */
  78. PHP_FUNCTION(linkinfo)
  79. {
  80. char *link;
  81. char *dirname;
  82. size_t link_len;
  83. zend_stat_t sb;
  84. int ret;
  85. ZEND_PARSE_PARAMETERS_START(1, 1)
  86. Z_PARAM_PATH(link, link_len)
  87. ZEND_PARSE_PARAMETERS_END();
  88. dirname = estrndup(link, link_len);
  89. php_dirname(dirname, link_len);
  90. if (php_check_open_basedir(dirname)) {
  91. efree(dirname);
  92. RETURN_FALSE;
  93. }
  94. ret = VCWD_LSTAT(link, &sb);
  95. if (ret == -1) {
  96. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  97. efree(dirname);
  98. RETURN_LONG(Z_L(-1));
  99. }
  100. efree(dirname);
  101. RETURN_LONG((zend_long) sb.st_dev);
  102. }
  103. /* }}} */
  104. /* {{{ Create a symbolic link */
  105. PHP_FUNCTION(symlink)
  106. {
  107. char *topath, *frompath;
  108. size_t topath_len, frompath_len;
  109. int ret;
  110. char source_p[MAXPATHLEN];
  111. char dest_p[MAXPATHLEN];
  112. char dirname[MAXPATHLEN];
  113. size_t len;
  114. ZEND_PARSE_PARAMETERS_START(2, 2)
  115. Z_PARAM_PATH(topath, topath_len)
  116. Z_PARAM_PATH(frompath, frompath_len)
  117. ZEND_PARSE_PARAMETERS_END();
  118. if (!expand_filepath(frompath, source_p)) {
  119. php_error_docref(NULL, E_WARNING, "No such file or directory");
  120. RETURN_FALSE;
  121. }
  122. memcpy(dirname, source_p, sizeof(source_p));
  123. len = php_dirname(dirname, strlen(dirname));
  124. if (!expand_filepath_ex(topath, dest_p, dirname, len)) {
  125. php_error_docref(NULL, E_WARNING, "No such file or directory");
  126. RETURN_FALSE;
  127. }
  128. if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) ||
  129. php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) )
  130. {
  131. php_error_docref(NULL, E_WARNING, "Unable to symlink to a URL");
  132. RETURN_FALSE;
  133. }
  134. if (php_check_open_basedir(dest_p)) {
  135. RETURN_FALSE;
  136. }
  137. if (php_check_open_basedir(source_p)) {
  138. RETURN_FALSE;
  139. }
  140. /* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD).
  141. * For the target the exact string given by the user must be used, relative or not, existing or not.
  142. * The target is relative to the link itself, not to the CWD. */
  143. ret = php_sys_symlink(topath, source_p);
  144. if (ret == -1) {
  145. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  146. RETURN_FALSE;
  147. }
  148. RETURN_TRUE;
  149. }
  150. /* }}} */
  151. /* {{{ Create a hard link */
  152. PHP_FUNCTION(link)
  153. {
  154. char *topath, *frompath;
  155. size_t topath_len, frompath_len;
  156. int ret;
  157. char source_p[MAXPATHLEN];
  158. char dest_p[MAXPATHLEN];
  159. ZEND_PARSE_PARAMETERS_START(2, 2)
  160. Z_PARAM_PATH(topath, topath_len)
  161. Z_PARAM_PATH(frompath, frompath_len)
  162. ZEND_PARSE_PARAMETERS_END();
  163. if (!expand_filepath(frompath, source_p) || !expand_filepath(topath, dest_p)) {
  164. php_error_docref(NULL, E_WARNING, "No such file or directory");
  165. RETURN_FALSE;
  166. }
  167. if (php_stream_locate_url_wrapper(source_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) ||
  168. php_stream_locate_url_wrapper(dest_p, NULL, STREAM_LOCATE_WRAPPERS_ONLY) )
  169. {
  170. php_error_docref(NULL, E_WARNING, "Unable to link to a URL");
  171. RETURN_FALSE;
  172. }
  173. if (php_check_open_basedir(dest_p)) {
  174. RETURN_FALSE;
  175. }
  176. if (php_check_open_basedir(source_p)) {
  177. RETURN_FALSE;
  178. }
  179. #ifndef ZTS
  180. ret = php_sys_link(topath, frompath);
  181. #else
  182. ret = php_sys_link(dest_p, source_p);
  183. #endif
  184. if (ret == -1) {
  185. php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
  186. RETURN_FALSE;
  187. }
  188. RETURN_TRUE;
  189. }
  190. /* }}} */
  191. #endif