summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2017-12-07 23:05:19 +0100
committerAnatol Belski <ab@php.net>2017-12-08 19:23:18 +0100
commit2fbdaec03cdbda901cbd1b69898a3e3f265536bc (patch)
treee947682707edfe5701a7fb1b9eb823e506e0e367
parent17d621e7d3bc0a97d1ddddeb3e7fbdea25548637 (diff)
downloadphp-git-2fbdaec03cdbda901cbd1b69898a3e3f265536bc.tar.gz
Revamp unlink() implementation and improve error handling
-rw-r--r--ext/standard/tests/file/unlink_error-win32-mb.phpt2
-rw-r--r--ext/standard/tests/file/unlink_error-win32.phpt2
-rw-r--r--win32/ioutil.c62
-rw-r--r--win32/ioutil.h11
-rw-r--r--win32/winutil.c1
5 files changed, 67 insertions, 11 deletions
diff --git a/ext/standard/tests/file/unlink_error-win32-mb.phpt b/ext/standard/tests/file/unlink_error-win32-mb.phpt
index 5111f34b76..4ce4ca796a 100644
--- a/ext/standard/tests/file/unlink_error-win32-mb.phpt
+++ b/ext/standard/tests/file/unlink_error-win32-mb.phpt
@@ -108,6 +108,6 @@ bool(false)
-- Testing unlink() on directory --
-Warning: unlink(%s/unlink_error): Permission denied in %s on line %d
+Warning: unlink(%s/unlink_error): Is a directory in %s on line %d
bool(false)
Done
diff --git a/ext/standard/tests/file/unlink_error-win32.phpt b/ext/standard/tests/file/unlink_error-win32.phpt
index e55f6ed5cd..f7a123919f 100644
--- a/ext/standard/tests/file/unlink_error-win32.phpt
+++ b/ext/standard/tests/file/unlink_error-win32.phpt
@@ -105,6 +105,6 @@ bool(false)
-- Testing unlink() on directory --
-Warning: unlink(%s/unlink_error): Permission denied in %s on line %d
+Warning: unlink(%s/unlink_error): Is a directory in %s on line %d
bool(false)
Done
diff --git a/win32/ioutil.c b/win32/ioutil.c
index 68346a19bb..7f1f758456 100644
--- a/win32/ioutil.c
+++ b/win32/ioutil.c
@@ -359,16 +359,72 @@ PW32IO int php_win32_ioutil_unlink_w(const wchar_t *path)
{/*{{{*/
int ret = 0;
DWORD err = 0;
+ HANDLE h;
+ BY_HANDLE_FILE_INFORMATION info;
+ FILE_DISPOSITION_INFO disposition;
+ BOOL status;
PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1, 0)
- if (!DeleteFileW(path)) {
+ h = CreateFileW(path,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
+ PHP_WIN32_IOUTIL_DEFAULT_SHARE_MODE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (INVALID_HANDLE_VALUE == h) {
err = GetLastError();
- ret = -1;
SET_ERRNO_FROM_WIN32_CODE(err);
+ return -1;
}
- return ret;
+ if (!GetFileInformationByHandle(h, &info)) {
+ err = GetLastError();
+ CloseHandle(h);
+ SET_ERRNO_FROM_WIN32_CODE(err);
+ return -1;
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ /* TODO Handle possible reparse point. */
+ CloseHandle(h);
+ SET_ERRNO_FROM_WIN32_CODE(ERROR_DIRECTORY_NOT_SUPPORTED);
+ return -1;
+ }
+
+#if 0
+ /* XXX BC breach! */
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ /* Remove read-only attribute */
+ FILE_BASIC_INFO basic = { 0 };
+
+ basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY);
+
+ status = SetFileInformationByHandle(h, FileBasicInfo, &basic, sizeof basic);
+ if (!status) {
+ err = GetLastError();
+ SET_ERRNO_FROM_WIN32_CODE(err);
+ CloseHandle(h);
+ return -1;
+ }
+ }
+#endif
+
+ /* Try to set the delete flag. */
+ disposition.DeleteFile = TRUE;
+ status = SetFileInformationByHandle(h, FileDispositionInfo, &disposition, sizeof disposition);
+ if (!status) {
+ err = GetLastError();
+ CloseHandle(h);
+ SET_ERRNO_FROM_WIN32_CODE(err);
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ return 0;
}/*}}}*/
PW32IO int php_win32_ioutil_rmdir_w(const wchar_t *path)
diff --git a/win32/ioutil.h b/win32/ioutil.h
index 71737f697b..5d06fd1940 100644
--- a/win32/ioutil.h
+++ b/win32/ioutil.h
@@ -241,6 +241,7 @@ PW32IO int php_win32_ioutil_open_w(const wchar_t *path, int flags, ...);
PW32IO int php_win32_ioutil_chdir_w(const wchar_t *path);
PW32IO int php_win32_ioutil_rename_w(const wchar_t *oldname, const wchar_t *newname);
PW32IO wchar_t *php_win32_ioutil_getcwd_w(wchar_t *buf, size_t len);
+PW32IO int php_win32_ioutil_unlink_w(const wchar_t *path);
#if 0
PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode);
@@ -314,19 +315,17 @@ __forceinline static int php_win32_ioutil_open(const char *path, int flags, ...)
__forceinline static int php_win32_ioutil_unlink(const char *path)
{/*{{{*/
PHP_WIN32_IOUTIL_INIT_W(path)
- int ret = 0;
- DWORD err = 0;
+ int ret = -1;
+ DWORD err;
if (!pathw) {
SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);
return -1;
}
- PHP_WIN32_IOUTIL_CHECK_PATH_W(pathw, -1, 1)
-
- if (!DeleteFileW(pathw)) {
+ ret = php_win32_ioutil_unlink_w(pathw);
+ if (0 > ret) {
err = GetLastError();
- ret = -1;
}
PHP_WIN32_IOUTIL_CLEANUP_W()
diff --git a/win32/winutil.c b/win32/winutil.c
index 34dda95498..e1f819ac5e 100644
--- a/win32/winutil.c
+++ b/win32/winutil.c
@@ -371,6 +371,7 @@ PHP_WINUTIL_API int php_win32_code_to_errno(unsigned long w32Err)
/* 258 */ , { WAIT_TIMEOUT, ETIME}
/* 267 */ , { ERROR_DIRECTORY , ENOTDIR }
+ /* 336 */ , { ERROR_DIRECTORY_NOT_SUPPORTED , EISDIR }
/* 996 */ , { ERROR_IO_INCOMPLETE , EAGAIN }
/* 997 */ , { ERROR_IO_PENDING , EAGAIN }