Skip to content

Commit c9861bd

Browse files
committed
Create and expose php_sys_symlink() and php_sys_link()
These macros are supposed to behave like POSIX's symlink() and link(), respectively, on POSIX compliant systems and on Windows. Future scope: merge link.c and link_win32.c
1 parent 1fe5981 commit c9861bd

File tree

7 files changed

+106
-60
lines changed

7 files changed

+106
-60
lines changed

UPGRADING.INTERNALS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
PHP 7.4 INTERNALS UPGRADE NOTES
22

33
1. Internal API changes
4+
a. php_sys_symlink() and php_sys_link()
45

56
2. Build system changes
67
a. Unix build system changes
@@ -12,6 +13,10 @@ PHP 7.4 INTERNALS UPGRADE NOTES
1213
1. Internal API changes
1314
========================
1415

16+
a. php_sys_symlink() and php_sys_link() portability macros have been
17+
added, which behave like POSIX's symlink() and link(), respectively, on
18+
POSIX compliant systems and on Windows.
19+
1520
========================
1621
2. Build system changes
1722
========================

Zend/zend_virtual_cwd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,15 @@ CWD_API int php_sys_stat_ex(const char *path, zend_stat_t *buf, int lstat);
120120
# define php_sys_stat(path, buf) php_sys_stat_ex(path, buf, 0)
121121
# define php_sys_lstat(path, buf) php_sys_stat_ex(path, buf, 1)
122122
CWD_API ssize_t php_sys_readlink(const char *link, char *target, size_t target_len);
123+
# define php_sys_symlink php_win32_ioutil_symlink
124+
# define php_sys_link php_win32_ioutil_link
123125
#else
124126
# define php_sys_stat stat
125127
# define php_sys_lstat lstat
126128
# ifdef HAVE_SYMLINK
127129
# define php_sys_readlink(link, target, target_len) readlink(link, target, target_len)
130+
# define php_sys_symlink symlink
131+
# define php_sys_link link
128132
# endif
129133
#endif
130134

ext/standard/link.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ PHP_FUNCTION(symlink)
160160
/* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD).
161161
* For the target the exact string given by the user must be used, relative or not, existing or not.
162162
* The target is relative to the link itself, not to the CWD. */
163-
ret = symlink(topath, source_p);
163+
ret = php_sys_symlink(topath, source_p);
164164

165165
if (ret == -1) {
166166
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
@@ -207,9 +207,9 @@ PHP_FUNCTION(link)
207207
}
208208

209209
#ifndef ZTS
210-
ret = link(topath, frompath);
210+
ret = php_sys_link(topath, frompath);
211211
#else
212-
ret = link(dest_p, source_p);
212+
ret = php_sys_link(dest_p, source_p);
213213
#endif
214214
if (ret == -1) {
215215
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));

ext/standard/link_win32.c

Lines changed: 8 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
/*
4545
TODO:
46-
- Create php_readlink (done), php_link and php_symlink in win32/link.c
46+
- Create php_readlink (done), php_link (done) and php_symlink (done) in win32/link.c
4747
- Expose them (PHPAPI) so extensions developers can use them
4848
- define link/readlink/symlink to their php_ equivalent and use them in ext/standart/link.c
4949
- this file is then useless and we have a portable link API
@@ -122,13 +122,11 @@ PHP_FUNCTION(symlink)
122122
{
123123
char *topath, *frompath;
124124
size_t topath_len, frompath_len;
125-
BOOLEAN ret;
125+
int ret;
126126
char source_p[MAXPATHLEN];
127127
char dest_p[MAXPATHLEN];
128128
char dirname[MAXPATHLEN];
129129
size_t len;
130-
DWORD attr;
131-
wchar_t *dstw, *srcw;
132130

133131
if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &topath, &topath_len, &frompath, &frompath_len) == FAILURE) {
134132
return;
@@ -162,38 +160,16 @@ PHP_FUNCTION(symlink)
162160
RETURN_FALSE;
163161
}
164162

165-
dstw = php_win32_ioutil_any_to_w(topath);
166-
if (!dstw) {
167-
php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError());
168-
RETURN_FALSE;
169-
}
170-
if ((attr = GetFileAttributesW(dstw)) == INVALID_FILE_ATTRIBUTES) {
171-
free(dstw);
172-
php_error_docref(NULL, E_WARNING, "Could not fetch file information(error %d)", GetLastError());
173-
RETURN_FALSE;
174-
}
175-
176-
srcw = php_win32_ioutil_any_to_w(source_p);
177-
if (!srcw) {
178-
free(dstw);
179-
php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError());
180-
RETURN_FALSE;
181-
}
182163
/* For the source, an expanded path must be used (in ZTS an other thread could have changed the CWD).
183164
* For the target the exact string given by the user must be used, relative or not, existing or not.
184165
* The target is relative to the link itself, not to the CWD. */
185-
ret = CreateSymbolicLinkW(srcw, dstw, (attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0));
166+
ret = php_sys_symlink(topath, source_p);
186167

187-
if (!ret) {
188-
free(dstw);
189-
free(srcw);
190-
php_error_docref(NULL, E_WARNING, "Cannot create symlink, error code(%d)", GetLastError());
168+
if (ret == -1) {
169+
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
191170
RETURN_FALSE;
192171
}
193172

194-
free(dstw);
195-
free(srcw);
196-
197173
RETURN_TRUE;
198174
}
199175
/* }}} */
@@ -207,7 +183,6 @@ PHP_FUNCTION(link)
207183
int ret;
208184
char source_p[MAXPATHLEN];
209185
char dest_p[MAXPATHLEN];
210-
wchar_t *dstw, *srcw;
211186

212187
/*First argument to link function is the target and hence should go to frompath
213188
Second argument to link function is the link itself and hence should go to topath */
@@ -236,38 +211,15 @@ PHP_FUNCTION(link)
236211
}
237212

238213
#ifndef ZTS
239-
# define _TO_PATH topath
240-
# define _FROM_PATH frompath
214+
ret = php_sys_link(topath, frompath);
241215
#else
242-
# define _TO_PATH dest_p
243-
# define _FROM_PATH source_p
216+
ret = php_sys_link(dest_p, source_p);
244217
#endif
245-
dstw = php_win32_ioutil_any_to_w(_TO_PATH);
246-
if (!dstw) {
247-
php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError());
248-
RETURN_FALSE;
249-
}
250-
srcw = php_win32_ioutil_any_to_w(_FROM_PATH);
251-
if (!srcw) {
252-
free(dstw);
253-
php_error_docref(NULL, E_WARNING, "UTF-16 conversion failed (error %d)", GetLastError());
254-
RETURN_FALSE;
255-
}
256-
#undef _TO_PATH
257-
#undef _FROM_PATH
258-
259-
ret = CreateHardLinkW(dstw, srcw, NULL);
260-
261-
if (ret == 0) {
262-
free(dstw);
263-
free(srcw);
218+
if (ret == -1) {
264219
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
265220
RETURN_FALSE;
266221
}
267222

268-
free(dstw);
269-
free(srcw);
270-
271223
RETURN_TRUE;
272224
}
273225
/* }}} */

ext/standard/tests/file/rename_variation7-win32.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ var_dump(readlink($tmp_link2));
2626
echo "Done\n";
2727
?>
2828
--EXPECTF--
29-
Warning: symlink(): Could not fetch file information(error 2) in %srename_variation7-win32.php on line %d
29+
Warning: symlink(): No such file or directory in %srename_variation7-win32.php on line %d
3030

3131
Warning: readlink(): readlink failed to read the symbolic link (%srename_variation7-win32.php.tmp.link), error 2) in %srename_variation7-win32.php on line %d
3232
bool(false)

win32/ioutil.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,38 @@ PW32IO char *realpath(const char *path, char *resolved)
785785
return php_win32_ioutil_realpath(path, resolved);
786786
}/*}}}*/
787787

788+
PW32IO int php_win32_ioutil_symlink_w(const wchar_t *target, const wchar_t *link)
789+
{/*{{{*/
790+
DWORD attr;
791+
BOOLEAN res;
792+
793+
if ((attr = GetFileAttributesW(target)) == INVALID_FILE_ATTRIBUTES) {
794+
SET_ERRNO_FROM_WIN32_CODE(GetLastError());
795+
return -1;
796+
}
797+
798+
res = CreateSymbolicLinkW(link, target, (attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0));
799+
if (!res) {
800+
SET_ERRNO_FROM_WIN32_CODE(GetLastError());
801+
return -1;
802+
}
803+
804+
return 0;
805+
}/*}}}*/
806+
807+
PW32IO int php_win32_ioutil_link_w(const wchar_t *target, const wchar_t *link)
808+
{/*{{{*/
809+
BOOL res;
810+
811+
res = CreateHardLinkW(target, link, NULL);
812+
if (!res) {
813+
SET_ERRNO_FROM_WIN32_CODE(GetLastError());
814+
return -1;
815+
}
816+
817+
return 0;
818+
}/*}}}*/
819+
788820
/*
789821
* Local variables:
790822
* tab-width: 4

win32/ioutil.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode);
261261
PW32IO FILE *php_win32_ioutil_fopen_w(const wchar_t *path, const wchar_t *mode);
262262
PW32IO wchar_t *php_win32_ioutil_realpath_w(const wchar_t *path, wchar_t *resolved);
263263
PW32IO wchar_t *php_win32_ioutil_realpath_w_ex0(const wchar_t *path, wchar_t *resolved, PBY_HANDLE_FILE_INFORMATION info);
264+
PW32IO int php_win32_ioutil_symlink_w(const wchar_t *target, const wchar_t *link);
265+
PW32IO int php_win32_ioutil_link_w(const wchar_t *target, const wchar_t *link);
264266

265267
__forceinline static int php_win32_ioutil_access(const char *path, mode_t mode)
266268
{/*{{{*/
@@ -571,6 +573,57 @@ __forceinline static int php_win32_ioutil_mkdir(const char *path, mode_t mode)
571573
return ret;
572574
}/*}}}*/
573575

576+
__forceinline static int php_win32_ioutil_symlink(const char *target, const char *link)
577+
{/*{{{*/
578+
wchar_t *targetw, *linkw;
579+
int ret;
580+
581+
targetw = php_win32_ioutil_any_to_w(target);
582+
if (!targetw) {
583+
SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
584+
return -1;
585+
}
586+
587+
linkw = php_win32_ioutil_any_to_w(link);
588+
if (!linkw) {
589+
free(targetw);
590+
SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
591+
return -1;
592+
}
593+
594+
ret = php_win32_ioutil_symlink_w(targetw, linkw);
595+
596+
free(targetw);
597+
free(linkw);
598+
599+
return ret;
600+
}/*}}}*/
601+
602+
__forceinline static int php_win32_ioutil_link(const char *target, const char *link)
603+
{/*{{{*/
604+
wchar_t *targetw, *linkw;
605+
int ret;
606+
607+
targetw = php_win32_ioutil_any_to_w(target);
608+
if (!targetw) {
609+
SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
610+
return -1;
611+
}
612+
linkw = php_win32_ioutil_any_to_w(link);
613+
if (!linkw) {
614+
free(targetw);
615+
SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
616+
return -1;
617+
}
618+
619+
ret = php_win32_ioutil_link_w(targetw, linkw);
620+
621+
free(targetw);
622+
free(linkw);
623+
624+
return ret;
625+
}/*}}}*/
626+
574627
#define HAVE_REALPATH 1
575628
PW32IO char *realpath(const char *path, char *resolved);
576629

0 commit comments

Comments
 (0)