Files
raven/testdata/native_loader/junction_client.c
T
Raymond Bennett c7f74916cd feat: make, read and remove reparse points through DeviceIoControl
uv makes directory junctions with FSCTL_SET_REPARSE_POINT for its Python
version links, and lsd asks every file for its reparse data with
FSCTL_GET_REPARSE_POINT; both got ERROR_INVALID_FUNCTION.

Reparse points are the host's symbolic links: FSCTL_SET_REPARSE_POINT makes
an empty directory a mount point, or an empty file or directory a symbolic
link, to the target its REPARSE_DATA_BUFFER names; FSCTL_GET_REPARSE_POINT
describes a link (as a mount point when it holds an absolute path to a
directory); FSCTL_DELETE_REPARSE_POINT leaves an empty directory or file.
A file that is no reparse point answers ERROR_NOT_A_REPARSE_POINT. A test
makes a junction, reads a file through it, reads it back and removes it.

Assisted-by: Claude Code:claude-opus-5-5
AI-Scope: the control codes and the test
2026-10-29 00:11:51 -07:00

110 lines
4.1 KiB
C

#include <windows.h>
#include <winioctl.h>
// Reparse points through DeviceIoControl: an empty directory becomes a mount point (a junction) to another directory, whose file is
// then reached through it; FSCTL_GET_REPARSE_POINT reads the junction back, FSCTL_DELETE_REPARSE_POINT leaves an empty directory, and
// a plain file is not a reparse point. Returns 0, or the number of the check that failed.
static void append(WCHAR *to, const WCHAR *text)
{
while (*to)
++to;
while ((*to++ = *text++))
;
}
static int ends_with(const WCHAR *text, unsigned length, const WCHAR *tail)
{
unsigned count = 0;
while (tail[count])
++count;
if (length < count)
return 0;
for (unsigned index = 0; index < count; ++index)
if (text[length - count + index] != tail[index])
return 0;
return 1;
}
int raven_entry(void)
{
static WCHAR root[MAX_PATH], target[MAX_PATH + 32], link[MAX_PATH + 32], inside[MAX_PATH + 64], file[MAX_PATH + 64];
static __attribute__((aligned(8))) BYTE buffer[1024];
if (!GetTempPathW(MAX_PATH, root))
return 1;
append(target, root);
append(target, L"raven-junction-target");
append(link, root);
append(link, L"raven-junction-link");
append(file, target);
append(file, L"\\inside.txt");
CreateDirectoryW(target, NULL);
RemoveDirectoryW(link);
if (!CreateDirectoryW(link, NULL))
return 2;
HANDLE created = CreateFileW(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
DWORD written;
if (created == INVALID_HANDLE_VALUE || !WriteFile(created, "hi", 2, &written, NULL))
return 3;
CloseHandle(created);
// REPARSE_DATA_BUFFER for a mount point: the substitute name \??\<target>, then an empty print name.
static WCHAR substitute[MAX_PATH + 40];
append(substitute, L"\\??\\");
append(substitute, target);
USHORT length = 0;
while (substitute[length])
++length;
DWORD *tag = (DWORD *)buffer;
USHORT *words = (USHORT *)(buffer + 4);
tag[0] = IO_REPARSE_TAG_MOUNT_POINT;
words[0] = (USHORT)(8 + (length + 2) * 2);
words[1] = 0;
words[2] = 0;
words[3] = (USHORT)(length * 2);
words[4] = (USHORT)((length + 1) * 2);
words[5] = 0;
WCHAR *names = (WCHAR *)(buffer + 16);
for (USHORT index = 0; index < length; ++index)
names[index] = substitute[index];
names[length] = names[length + 1] = 0;
HANDLE directory = CreateFileW(link, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (directory == INVALID_HANDLE_VALUE)
return 4;
DWORD returned = 0;
if (!DeviceIoControl(directory, FSCTL_SET_REPARSE_POINT, buffer, 8 + words[0], NULL, 0, &returned, NULL))
return 5;
CloseHandle(directory);
if (!(GetFileAttributesW(link) & FILE_ATTRIBUTE_REPARSE_POINT))
return 6;
append(inside, link);
append(inside, L"\\inside.txt");
HANDLE through = CreateFileW(inside, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
char read[4] = {0};
if (through == INVALID_HANDLE_VALUE || !ReadFile(through, read, sizeof read, &returned, NULL) || returned != 2 || read[0] != 'h')
return 7;
CloseHandle(through);
directory = CreateFileW(link, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (directory == INVALID_HANDLE_VALUE)
return 8;
if (!DeviceIoControl(directory, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof buffer, &returned, NULL) || tag[0] != IO_REPARSE_TAG_MOUNT_POINT)
return 9;
if (!ends_with((WCHAR *)(buffer + 16 + words[2]), words[3] / 2, L"raven-junction-target"))
return 10;
tag[0] = IO_REPARSE_TAG_MOUNT_POINT;
words[0] = 0;
if (!DeviceIoControl(directory, FSCTL_DELETE_REPARSE_POINT, buffer, 8, NULL, 0, &returned, NULL))
return 11;
CloseHandle(directory);
if (GetFileAttributesW(link) & FILE_ATTRIBUTE_REPARSE_POINT)
return 12;
HANDLE plain = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (plain == INVALID_HANDLE_VALUE)
return 13;
if (DeviceIoControl(plain, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof buffer, &returned, NULL) || GetLastError() != ERROR_NOT_A_REPARSE_POINT)
return 14;
CloseHandle(plain);
DeleteFileW(file);
RemoveDirectoryW(link);
RemoveDirectoryW(target);
return 0;
}