win: readlink support for IO_REPARSE_TAG_LX_SYMLINK (#4994)
This adds support for "Linux"-style Windows symbolic links, reparse tag 0xA000001D (IO_REPARSE_TAG_LX_SYMLINK).
This commit is contained in:
parent
3908e54252
commit
588ea9b913
26
src/win/fs.c
26
src/win/fs.c
@ -247,6 +247,32 @@ static int fs__readlink_handle(HANDLE handle,
|
||||
}
|
||||
}
|
||||
|
||||
} else if (reparse_data->ReparseTag == IO_REPARSE_TAG_LX_SYMLINK) {
|
||||
/* Real (Linux) symlink */
|
||||
char* buffer;
|
||||
char* target;
|
||||
size_t target_len;
|
||||
|
||||
target_len = (reparse_data->ReparseDataLength -
|
||||
sizeof(ULONG)); /* Version field */
|
||||
buffer = (char*) reparse_data->LinuxSymbolicLinkReparseBuffer.PathBuffer;
|
||||
|
||||
if (target_len_ptr != NULL) {
|
||||
*target_len_ptr = target_len;
|
||||
}
|
||||
|
||||
if (target_ptr != NULL) {
|
||||
assert(*target_ptr == NULL);
|
||||
target = uv__malloc(target_len + 1);
|
||||
if (target == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
memcpy(target, buffer, target_len);
|
||||
target[target_len] = '\0';
|
||||
*target_ptr = target;
|
||||
}
|
||||
return 0;
|
||||
|
||||
} else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
|
||||
/* Junction. */
|
||||
w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
|
||||
|
||||
@ -4163,6 +4163,10 @@ typedef struct _REPARSE_DATA_BUFFER {
|
||||
ULONG Flags;
|
||||
WCHAR PathBuffer[1];
|
||||
} SymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
ULONG Version;
|
||||
UCHAR PathBuffer[1];
|
||||
} LinuxSymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
USHORT SubstituteNameOffset;
|
||||
USHORT SubstituteNameLength;
|
||||
@ -4582,6 +4586,9 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||
#ifndef IO_REPARSE_TAG_SYMLINK
|
||||
# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_LX_SYMLINK
|
||||
# define IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL)
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_APPEXECLINK
|
||||
# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL)
|
||||
#endif
|
||||
|
||||
100
test/test-fs.c
100
test/test-fs.c
@ -23,6 +23,7 @@
|
||||
#include "task.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h> /* offsetof */
|
||||
#include <string.h> /* memset */
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
@ -37,6 +38,13 @@
|
||||
# ifndef ERROR_SYMLINK_NOT_SUPPORTED
|
||||
# define ERROR_SYMLINK_NOT_SUPPORTED 1464
|
||||
# endif
|
||||
# ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
|
||||
# define REPARSE_DATA_BUFFER_HEADER_SIZE \
|
||||
offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer)
|
||||
# endif
|
||||
# ifndef IO_REPARSE_TAG_LX_SYMLINK
|
||||
# define IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL)
|
||||
# endif
|
||||
# ifndef S_IFIFO
|
||||
# define S_IFIFO _S_IFIFO
|
||||
# endif
|
||||
@ -77,6 +85,24 @@ typedef struct {
|
||||
double mtime;
|
||||
} utime_check_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef REPARSE_DATA_BUFFER
|
||||
typedef struct _REPARSE_DATA_BUFFER {
|
||||
ULONG ReparseTag;
|
||||
USHORT ReparseDataLength;
|
||||
USHORT Reserved;
|
||||
union {
|
||||
struct {
|
||||
ULONG Version;
|
||||
UCHAR PathBuffer[1];
|
||||
} LinuxSymbolicLinkReparseBuffer;
|
||||
struct {
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
} DUMMYUNIONNAME;
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int dummy_cb_count;
|
||||
static int close_cb_count;
|
||||
@ -2694,6 +2720,80 @@ TEST_FS_IMPL(fs_non_symlink_reparse_point) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_FS_IMPL(fs_readlink_lx_symlink) {
|
||||
uv_fs_t req;
|
||||
int r;
|
||||
HANDLE file_handle;
|
||||
REPARSE_DATA_BUFFER* reparse_buffer;
|
||||
DWORD bytes_returned;
|
||||
const char* target_path = "target_file";
|
||||
size_t target_len = strlen(target_path);
|
||||
size_t buffer_size;
|
||||
|
||||
/* set-up */
|
||||
unlink("test_dir/lx_symlink");
|
||||
rmdir("test_dir");
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
file_handle = CreateFile("test_dir/lx_symlink",
|
||||
GENERIC_WRITE | FILE_WRITE_ATTRIBUTES,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT |
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE);
|
||||
|
||||
/* Allocate buffer for reparse data */
|
||||
buffer_size = REPARSE_DATA_BUFFER_HEADER_SIZE +
|
||||
sizeof(ULONG) + /* Version field */
|
||||
target_len;
|
||||
reparse_buffer = malloc(buffer_size);
|
||||
ASSERT_NOT_NULL(reparse_buffer);
|
||||
|
||||
/* Set up Linux symlink reparse buffer */
|
||||
memset(reparse_buffer, 0, buffer_size);
|
||||
reparse_buffer->ReparseTag = IO_REPARSE_TAG_LX_SYMLINK;
|
||||
reparse_buffer->ReparseDataLength = sizeof(ULONG) + target_len;
|
||||
reparse_buffer->Reserved = 0;
|
||||
reparse_buffer->LinuxSymbolicLinkReparseBuffer.Version = 2;
|
||||
memcpy(reparse_buffer->LinuxSymbolicLinkReparseBuffer.PathBuffer,
|
||||
target_path,
|
||||
target_len);
|
||||
|
||||
r = DeviceIoControl(file_handle,
|
||||
FSCTL_SET_REPARSE_POINT,
|
||||
reparse_buffer,
|
||||
buffer_size,
|
||||
NULL,
|
||||
0,
|
||||
&bytes_returned,
|
||||
NULL);
|
||||
ASSERT(r);
|
||||
|
||||
CloseHandle(file_handle);
|
||||
|
||||
/* Test that readlink works on the Linux symlink */
|
||||
r = uv_fs_readlink(NULL, &req, "test_dir/lx_symlink", NULL);
|
||||
ASSERT_OK(r);
|
||||
ASSERT_NOT_NULL(req.ptr);
|
||||
ASSERT_OK(strcmp(req.ptr, target_path));
|
||||
uv_fs_req_cleanup(&req);
|
||||
|
||||
/* clean-up */
|
||||
free(reparse_buffer);
|
||||
unlink("test_dir/lx_symlink");
|
||||
rmdir("test_dir");
|
||||
|
||||
MAKE_VALGRIND_HAPPY(loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST_FS_IMPL(fs_lstat_windows_store_apps) {
|
||||
uv_loop_t* loop;
|
||||
char localappdata[MAX_PATH];
|
||||
|
||||
@ -385,6 +385,7 @@ TEST_FS_DECLARE (fs_symlink_dir)
|
||||
#ifdef _WIN32
|
||||
TEST_FS_DECLARE (fs_symlink_junction)
|
||||
TEST_FS_DECLARE (fs_non_symlink_reparse_point)
|
||||
TEST_FS_DECLARE (fs_readlink_lx_symlink)
|
||||
TEST_FS_DECLARE (fs_lstat_windows_store_apps)
|
||||
TEST_FS_DECLARE (fs_open_flags)
|
||||
#endif
|
||||
@ -1113,6 +1114,7 @@ TASK_LIST_START
|
||||
#ifdef _WIN32
|
||||
TEST_FS_ENTRY (fs_symlink_junction)
|
||||
TEST_FS_ENTRY (fs_non_symlink_reparse_point)
|
||||
TEST_FS_ENTRY (fs_readlink_lx_symlink)
|
||||
TEST_FS_ENTRY (fs_lstat_windows_store_apps)
|
||||
TEST_FS_ENTRY (fs_open_flags)
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user