Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
win, fs: add IO_REPARSE_TAG_APPEXECLINK support
Adds support for IO_REPARSE_TAG_APPEXECLINK reparse points, used by
Windows Store.

Ref: nodejs/node#33024

PR-URL: #2812
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
  • Loading branch information
bzoz committed Apr 29, 2020
1 parent 4572858 commit e7ebae2
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/win/error.c
Expand Up @@ -72,6 +72,7 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
Expand Down
34 changes: 34 additions & 0 deletions src/win/fs.c
Expand Up @@ -322,6 +322,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
WCHAR* w_target;
DWORD w_target_len;
DWORD bytes;
size_t i;
size_t len;

if (!DeviceIoControl(handle,
FSCTL_GET_REPARSE_POINT,
Expand Down Expand Up @@ -406,6 +408,38 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
w_target += 4;
w_target_len -= 4;

} else if (reparse_data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) {
/* String #3 in the list has the target filename. */
if (reparse_data->AppExecLinkReparseBuffer.StringCount < 3) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
w_target = reparse_data->AppExecLinkReparseBuffer.StringList;
/* The StringList buffer contains a list of strings separated by "\0", */
/* with "\0\0" terminating the list. Move to the 3rd string in the list: */
for (i = 0; i < 2; ++i) {
len = wcslen(w_target);
if (len == 0) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
w_target += len + 1;
}
w_target_len = wcslen(w_target);
if (w_target_len == 0) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}
/* Make sure it is an absolute path. */
if (!(w_target_len >= 3 &&
((w_target[0] >= L'a' && w_target[0] <= L'z') ||
(w_target[0] >= L'A' && w_target[0] <= L'Z')) &&
w_target[1] == L':' &&
w_target[2] == L'\\')) {
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
return -1;
}

} else {
/* Reparse tag does not indicate a symlink. */
SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
Expand Down
7 changes: 7 additions & 0 deletions src/win/winapi.h
Expand Up @@ -4152,6 +4152,10 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
struct {
ULONG StringCount;
WCHAR StringList[1];
} AppExecLinkReparseBuffer;
};
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
#endif
Expand Down Expand Up @@ -4517,6 +4521,9 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
#ifndef IO_REPARSE_TAG_SYMLINK
# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
#endif
#ifndef IO_REPARSE_TAG_APPEXECLINK
# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL)
#endif

typedef VOID (NTAPI *PIO_APC_ROUTINE)
(PVOID ApcContext,
Expand Down
51 changes: 51 additions & 0 deletions test/test-fs.c
Expand Up @@ -2453,6 +2453,57 @@ TEST_IMPL(fs_non_symlink_reparse_point) {
MAKE_VALGRIND_HAPPY();
return 0;
}

TEST_IMPL(fs_lstat_windows_store_apps) {
uv_loop_t* loop;
char localappdata[MAX_PATH];
char windowsapps_path[MAX_PATH];
char file_path[MAX_PATH];
size_t len;
int r;
uv_fs_t req;
uv_fs_t stat_req;
uv_dirent_t dirent;

loop = uv_default_loop();
ASSERT_NOT_NULL(loop);
len = sizeof(localappdata);
r = uv_os_getenv("LOCALAPPDATA", localappdata, &len);
if (r == UV_ENOENT) {
MAKE_VALGRIND_HAPPY();
return TEST_SKIP;
}
ASSERT_EQ(r, 0);
r = snprintf(windowsapps_path,
sizeof(localappdata),
"%s\\Microsoft\\WindowsApps",
localappdata);
ASSERT_GT(r, 0);
if (uv_fs_opendir(loop, &req, windowsapps_path, NULL) != 0) {
/* If we cannot read the directory, skip the test. */
MAKE_VALGRIND_HAPPY();
return TEST_SKIP;
}
if (uv_fs_scandir(loop, &req, windowsapps_path, 0, NULL) <= 0) {
MAKE_VALGRIND_HAPPY();
return TEST_SKIP;
}
while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) {
if (dirent.type != UV_DIRENT_LINK) {
continue;
}
if (snprintf(file_path,
sizeof(file_path),
"%s\\%s",
windowsapps_path,
dirent.name) < 0) {
continue;
}
ASSERT_EQ(uv_fs_lstat(loop, &stat_req, file_path, NULL), 0);
}
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif


Expand Down
2 changes: 2 additions & 0 deletions test/test-list.h
Expand Up @@ -346,6 +346,7 @@ TEST_DECLARE (fs_symlink_dir)
#ifdef _WIN32
TEST_DECLARE (fs_symlink_junction)
TEST_DECLARE (fs_non_symlink_reparse_point)
TEST_DECLARE (fs_lstat_windows_store_apps)
TEST_DECLARE (fs_open_flags)
#endif
#if defined(_WIN32) && !defined(USING_UV_SHARED)
Expand Down Expand Up @@ -979,6 +980,7 @@ TASK_LIST_START
#ifdef _WIN32
TEST_ENTRY (fs_symlink_junction)
TEST_ENTRY (fs_non_symlink_reparse_point)
TEST_ENTRY (fs_lstat_windows_store_apps)
TEST_ENTRY (fs_open_flags)
#endif
#if defined(_WIN32) && !defined(USING_UV_SHARED)
Expand Down

0 comments on commit e7ebae2

Please sign in to comment.