summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Högberg <john@erlang.org>2018-05-04 09:46:34 +0200
committerJohn Högberg <john@erlang.org>2018-05-04 09:46:34 +0200
commita7ab99c17a583fdba1dd90e28a8ef3df19e87de9 (patch)
tree699b7d32e2ddae120c30e2c53987dae7256dba5b
parentf770320ddc583c1059d33ff756ad986b53848517 (diff)
parent2c0e76fa55ecb8c6fa6e7b82ce02e0f33a81391e (diff)
downloaderlang-a7ab99c17a583fdba1dd90e28a8ef3df19e87de9.tar.gz
Merge branch 'john/erts/fix-windows-symlinks/OTP-15062/ERL-615'
* john/erts/fix-windows-symlinks/OTP-15062/ERL-615: Stop assuming that all NTFS reparse points are links
-rw-r--r--erts/emulator/nifs/win32/win_prim_file.c50
1 files changed, 48 insertions, 2 deletions
diff --git a/erts/emulator/nifs/win32/win_prim_file.c b/erts/emulator/nifs/win32/win_prim_file.c
index 8058350b25..044bee62cf 100644
--- a/erts/emulator/nifs/win32/win_prim_file.c
+++ b/erts/emulator/nifs/win32/win_prim_file.c
@@ -24,6 +24,7 @@
#include "prim_file_nif.h"
+#include <winioctl.h>
#include <windows.h>
#include <strsafe.h>
#include <wchar.h>
@@ -671,11 +672,48 @@ static int is_executable_file(const efile_path_t *path) {
return 0;
}
+/* Returns whether the path refers to a link-like object, e.g. a junction
+ * point, symbolic link, or mounted folder. */
+static int is_name_surrogate(const efile_path_t *path) {
+ HANDLE handle;
+ int result;
+
+ handle = CreateFileW((const WCHAR*)path->data, GENERIC_READ,
+ FILE_SHARE_FLAGS, NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT |
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ result = 0;
+
+ if(handle != INVALID_HANDLE_VALUE) {
+ REPARSE_GUID_DATA_BUFFER reparse_buffer;
+ LPDWORD unused_length;
+ BOOL success;
+
+ success = DeviceIoControl(handle,
+ FSCTL_GET_REPARSE_POINT, NULL, 0,
+ &reparse_buffer, sizeof(reparse_buffer),
+ &unused_length, NULL);
+
+ /* ERROR_MORE_DATA is tolerated since we're guaranteed to have filled
+ * the field we want. */
+ if(success || GetLastError() == ERROR_MORE_DATA) {
+ result = IsReparseTagNameSurrogate(reparse_buffer.ReparseTag);
+ }
+
+ CloseHandle(handle);
+ }
+
+ return result;
+}
+
posix_errno_t efile_read_info(const efile_path_t *path, int follow_links, efile_fileinfo_t *result) {
BY_HANDLE_FILE_INFORMATION native_file_info;
DWORD attributes;
+ int is_link;
sys_memset(&native_file_info, 0, sizeof(native_file_info));
+ is_link = 0;
attributes = GetFileAttributesW((WCHAR*)path->data);
@@ -696,7 +734,11 @@ posix_errno_t efile_read_info(const efile_path_t *path, int follow_links, efile_
} else {
HANDLE handle;
- if(follow_links && (attributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ if(attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ is_link = is_name_surrogate(path);
+ }
+
+ if(follow_links && is_link) {
posix_errno_t posix_errno;
efile_path_t resolved_path;
@@ -737,7 +779,7 @@ posix_errno_t efile_read_info(const efile_path_t *path, int follow_links, efile_
}
}
- if(attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ if(is_link) {
result->type = EFILE_FILETYPE_SYMLINK;
/* This should be _S_IFLNK, but the old driver always set
* non-directories to _S_IFREG. */
@@ -917,6 +959,10 @@ posix_errno_t efile_read_link(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_
return EINVAL;
}
+ if(!is_name_surrogate(path)) {
+ return EINVAL;
+ }
+
posix_errno = internal_read_link(path, &result_bin);
if(posix_errno == 0) {