Skip to content

Commit

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

Ref: nodejs/node#33024
  • Loading branch information
bzoz committed Apr 24, 2020
1 parent 3e5d261 commit 5acd053
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/win/error.c
Original file line number Diff line number Diff line change
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
33 changes: 33 additions & 0 deletions src/win/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
WCHAR* w_target;
DWORD w_target_len;
DWORD bytes;
size_t i, len;

if (!DeviceIoControl(handle,
FSCTL_GET_REPARSE_POINT,
Expand Down Expand Up @@ -405,6 +406,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
4 changes: 4 additions & 0 deletions src/win/winapi.h
Original file line number Diff line number Diff line change
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
43 changes: 43 additions & 0 deletions test/test-fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2453,6 +2453,49 @@ 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, stat_req;
uv_dirent_t dirent;

loop = uv_default_loop();
ASSERT(loop != NULL);
len = MAX_PATH;
r = uv_os_getenv("LOCALAPPDATA", localappdata, &len);
if (r == UV_ENOENT) {
return TEST_SKIP;
}
ASSERT(r == 0);
r = sprintf_s(windowsapps_path,
MAX_PATH,
"%s\\Microsoft\\WindowsApps",
localappdata);
ASSERT(r > 0);
if (uv_fs_opendir(loop, &req, windowsapps_path, NULL) != 0) {
/* If we cannot read the directory, skip the test. */
return TEST_SKIP;
}
if (uv_fs_scandir(loop, &req, windowsapps_path, 0, NULL) <= 0) {
return TEST_SKIP;
}
while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) {
if (dirent.type != UV_DIRENT_LINK) {
continue;
}
if (sprintf_s(file_path, MAX_PATH, "%s\\%s", windowsapps_path, dirent.name) < 0) {
continue;
}

ASSERT(uv_fs_lstat(loop, &stat_req, file_path, NULL) == 0);
}
return 0;
}
#endif


Expand Down
2 changes: 2 additions & 0 deletions test/test-list.h
Original file line number Diff line number Diff line change
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 @@ -978,6 +979,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 5acd053

Please sign in to comment.