- diff --git a/daemon/readdir.c b/daemon/readdir.c
- index 14325bf..5b40e18 100644
- --- a/daemon/readdir.c
- +++ b/daemon/readdir.c
- @@ -25,6 +25,7 @@
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- +#include "nfs41_build_features.h"
- #include "nfs41_driver.h" /* for |FILE_INFO_TIME_NOT_SET| */
- #include "from_kernel.h"
- #include "nfs41_ops.h"
- @@ -403,8 +404,23 @@ static void readdir_copy_full_dir_info(
- * the 'dir' command to show files as <SYMLINK>, and triggers a
- * FSCTL_GET_REPARSE_POINT to query the symlink target
- */
- +#ifdef NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT
- + if (entry->attr_info.type == NF4LNK) {
- + /* BUG: |entry->name| is wrong, we have to get the VALUE of the symlink instead */
- + if (!strncmp(entry->name, "/cygdrive/")) {
- + info->fifdi.EaSize = IO_REPARSE_TAG_MOUNT_POINT;
- + }
- + else {
- + info->fifdi.EaSize = IO_REPARSE_TAG_SYMLINK;
- + }
- + }
- + else {
- + info->fifdi.EaSize = 0;
- + }
- +#else
- info->fifdi.EaSize = entry->attr_info.type == NF4LNK ?
- IO_REPARSE_TAG_SYMLINK : 0;
- +#endif /* NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT */
- }
- static void readdir_copy_both_dir_info(
- diff --git a/nfs41_build_features.h b/nfs41_build_features.h
- index a127e40..af7d643 100644
- --- a/nfs41_build_features.h
- +++ b/nfs41_build_features.h
- @@ -181,4 +181,12 @@
- */
- #define NFS41_DRIVER_DEFAULT_NFS4MINORVERSION 2
- +/*
- + * NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT - use
- + * Win32 Junctions to represent absolute symlinks
- + * Example:
- + * $ powershell -Command 'New-Item -Path junc_builds -ItemType Junction -Value L:\builds'
- + */
- +#define NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT 1
- +
- #endif /* !_NFS41_DRIVER_BUILDFEATURES_ */
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index f14beb5..7a3500a 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -776,6 +776,10 @@ void unmarshal_nfs41_symlink(
- unsigned char **buf);
- NTSTATUS nfs41_SetSymlinkReparsePoint(
- IN OUT PRX_CONTEXT RxContext);
- +#ifdef NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT
- +NTSTATUS nfs41_SetJunctionReparsePoint(
- + IN OUT PRX_CONTEXT RxContext);
- +#endif /* NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT */
- NTSTATUS nfs41_GetSymlinkReparsePoint(
- IN OUT PRX_CONTEXT RxContext);
- diff --git a/sys/nfs41sys_reparse.c b/sys/nfs41sys_reparse.c
- index 0b1e726..5e62a33 100644
- --- a/sys/nfs41sys_reparse.c
- +++ b/sys/nfs41sys_reparse.c
- @@ -89,6 +89,11 @@ NTSTATUS nfs41_SetReparsePoint(
- case IO_REPARSE_TAG_SYMLINK:
- status = nfs41_SetSymlinkReparsePoint(RxContext);
- break;
- +#ifdef NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT
- + case IO_REPARSE_TAG_MOUNT_POINT:
- + status = nfs41_SetJunctionReparsePoint(RxContext);
- + break;
- +#endif /* NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT */
- default:
- status = STATUS_NOT_IMPLEMENTED;
- DbgP("nfs41_SetReparsePoint: "
- diff --git a/sys/nfs41sys_symlink.c b/sys/nfs41sys_symlink.c
- index 6e04074..ef2abab 100644
- --- a/sys/nfs41sys_symlink.c
- +++ b/sys/nfs41sys_symlink.c
- @@ -135,6 +135,8 @@ NTSTATUS map_symlink_errors(
- {
- switch (status) {
- case NO_ERROR: return STATUS_SUCCESS;
- + case ERROR_FILE_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND;
- + case ERROR_PATH_NOT_FOUND: return STATUS_OBJECT_PATH_NOT_FOUND;
- case ERROR_INVALID_REPARSE_DATA: return STATUS_IO_REPARSE_DATA_INVALID;
- case ERROR_NOT_A_REPARSE_POINT: return STATUS_NOT_A_REPARSE_POINT;
- case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
- @@ -161,19 +163,20 @@ static void print_reparse_buffer(
- PREPARSE_DATA_BUFFER Reparse)
- {
- UNICODE_STRING name;
- - DbgP("ReparseTag: %08X\n", Reparse->ReparseTag);
- + DbgP("ReparseTag: 0x%lx\n", (long)Reparse->ReparseTag);
- DbgP("ReparseDataLength: %8u\n", Reparse->ReparseDataLength);
- DbgP("Reserved: %8u\n", Reparse->Reserved);
- - DbgP("SubstituteNameOffset: %8u\n",
- + if (Reparse->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
- + DbgP("SubstituteNameOffset: %u\n",
- Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset);
- - DbgP("SubstituteNameLength: %8u\n",
- + DbgP("SubstituteNameLength: %u\n",
- Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength);
- - DbgP("PrintNameOffset: %8u\n",
- + DbgP("PrintNameOffset: %u\n",
- Reparse->SymbolicLinkReparseBuffer.PrintNameOffset);
- - DbgP("PrintNameLength: %8u\n",
- + DbgP("PrintNameLength: %u\n",
- Reparse->SymbolicLinkReparseBuffer.PrintNameLength);
- - DbgP("Flags: %08X\n",
- - Reparse->SymbolicLinkReparseBuffer.Flags);
- + DbgP("Flags: 0x%lx\n",
- + (long)Reparse->SymbolicLinkReparseBuffer.Flags);
- name.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
- Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
- @@ -187,6 +190,29 @@ static void print_reparse_buffer(
- Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
- DbgP("PrintName: '%wZ'\n", &name);
- }
- + else if (Reparse->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
- + DbgP("SubstituteNameOffset: %u\n",
- + Reparse->MountPointReparseBuffer.SubstituteNameOffset);
- + DbgP("SubstituteNameLength: %u\n",
- + Reparse->MountPointReparseBuffer.SubstituteNameLength);
- + DbgP("PrintNameOffset: %u\n",
- + Reparse->MountPointReparseBuffer.PrintNameOffset);
- + DbgP("PrintNameLength: %u\n",
- + Reparse->MountPointReparseBuffer.PrintNameLength);
- +
- + name.Buffer = &Reparse->MountPointReparseBuffer.PathBuffer[
- + Reparse->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
- + name.MaximumLength = name.Length =
- + Reparse->MountPointReparseBuffer.SubstituteNameLength;
- + DbgP("SubstituteName: '%wZ'\n", &name);
- +
- + name.Buffer = &Reparse->MountPointReparseBuffer.PathBuffer[
- + Reparse->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
- + name.MaximumLength = name.Length =
- + Reparse->MountPointReparseBuffer.PrintNameLength;
- + DbgP("PrintName: '%wZ'\n", &name);
- + }
- +}
- static
- NTSTATUS check_nfs41_setsymlinkreparse_args(
- @@ -247,12 +273,6 @@ NTSTATUS check_nfs41_setsymlinkreparse_args(
- "IsReparseTagValid() failed\n");
- goto out;
- }
- - if (Reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
- - status = STATUS_IO_REPARSE_TAG_MISMATCH;
- - DbgP("check_nfs41_setsymlinkreparse_args: "
- - "Reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK\n");
- - goto out;
- - }
- out:
- return status;
- }
- @@ -291,6 +311,13 @@ NTSTATUS nfs41_SetSymlinkReparsePoint(
- goto out;
- }
- + if (Reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
- + status = STATUS_IO_REPARSE_TAG_MISMATCH;
- + DbgP("nfs41_SetSymlinkReparsePoint: "
- + "Reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK\n");
- + goto out;
- + }
- +
- TargetName.MaximumLength = TargetName.Length =
- Reparse->SymbolicLinkReparseBuffer.PrintNameLength;
- TargetName.Buffer = &Reparse->SymbolicLinkReparseBuffer.PathBuffer[
- @@ -316,6 +343,131 @@ out:
- return status;
- }
- +#ifdef NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT
- +NTSTATUS nfs41_SetJunctionReparsePoint(
- + IN OUT PRX_CONTEXT RxContext)
- +{
- + NTSTATUS status;
- + UNICODE_STRING TargetName;
- + __notnull XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
- + __notnull PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)FsCtl->pInputBuffer;
- + __notnull PNFS41_FOBX Fobx = NFS41GetFobxExtension(RxContext->pFobx);
- + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
- + __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
- + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
- + __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
- + NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
- + nfs41_updowncall_entry *entry;
- + PWSTR prefixed_targetname = NULL;
- +
- +#ifdef DEBUG_SYMLINK
- + DbgEn();
- + print_debug_header(RxContext);
- + print_reparse_buffer(Reparse);
- +#endif
- +
- + DbgP("nfs41_SetJunctionReparsePoint: ReparseTag: '%s'/0x%04lx\n",
- + reparsetag2string(Reparse->ReparseTag),
- + (long)Reparse->ReparseTag);
- +
- + status = check_nfs41_setsymlinkreparse_args(RxContext);
- + if (status) {
- + DbgP("nfs41_SetJunctionReparsePoint: "
- + "check_nfs41_setsymlinkreparse_args() failed, "
- + "status=0xlx\n",
- + (long)status);
- + goto out;
- + }
- +
- + if (Reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
- + status = STATUS_IO_REPARSE_TAG_MISMATCH;
- + DbgP("nfs41_SetJunctionReparsePoint: "
- + "Reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT\n");
- + goto out;
- + }
- +
- + TargetName.MaximumLength = TargetName.Length =
- + Reparse->MountPointReparseBuffer.SubstituteNameLength;
- + TargetName.Buffer = &Reparse->MountPointReparseBuffer.PathBuffer[
- + Reparse->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
- +
- + if (!memcmp(&TargetName.Buffer[0], L"\\??\\",
- + (4*sizeof(wchar_t)))) {
- + TargetName.Buffer += 4;
- + TargetName.MaximumLength = TargetName.Length =
- + TargetName.Length-(4*sizeof(wchar_t));
- + }
- +
- + DbgP("nfs41_SetJunctionReparsePoint: TargetName='%wZ'\n",
- + &TargetName);
- +
- + wchar_t devletter;
- + if ((TargetName.Buffer[1] != L':') || TargetName.Buffer[2] != L'\\') {
- + status = STATUS_INVALID_PARAMETER;
- + DbgP("nfs41_SetJunctionReparsePoint: "
- + "non-drive letter path '%wZ' not supported\n", &TargetName);
- + goto out;
- + }
- +
- + /* Skip "L:\" "*/
- + devletter = towlower(TargetName.Buffer[0]);
- + TargetName.Buffer += 3;
- + TargetName.MaximumLength = TargetName.Length =
- + TargetName.Length-(3*sizeof(wchar_t));
- +
- + DbgP("nfs41_SetJunctionReparsePoint: dosletter='%C' path='%wZ'\n",
- + devletter,
- + &TargetName);
- +
- + size_t prefixed_targetname_len = 4096*sizeof(wchar_t);
- +
- + prefixed_targetname = RxAllocatePoolWithTag(NonPagedPoolNx,
- + prefixed_targetname_len, NFS41_MM_POOLTAG);
- + if (prefixed_targetname == NULL) {
- + status = STATUS_INSUFFICIENT_RESOURCES;
- + goto out;
- + }
- +
- + /*
- + * Stuff Cygwin /cygdrive/<dosletter>/ prefix in front of path,
- + * userland daemon will convert the backslashes to slashes
- + */
- + (void)_snwprintf(prefixed_targetname,
- + prefixed_targetname_len, L"\\cygdrive\\%C\\%wZ",
- + devletter,
- + &TargetName);
- +
- + /* Put new buffer into target name */
- + TargetName.MaximumLength = TargetName.Length =
- + (USHORT)(wcslen(prefixed_targetname)*sizeof(wchar_t));
- + TargetName.Buffer = prefixed_targetname;
- +
- + DbgP("nfs41_SetJunctionReparsePoint: new TargetName='%wZ'\n",
- + &TargetName);
- +
- + status = nfs41_UpcallCreate(NFS41_SYSOP_SYMLINK, &Fobx->sec_ctx,
- + VNetRootContext->session, Fobx->nfs41_open_state,
- + pNetRootContext->nfs41d_version, SrvOpen->pAlreadyPrefixedName, &entry);
- + if (status) goto out;
- +
- + entry->u.Symlink.target = &TargetName;
- + entry->u.Symlink.set = TRUE;
- +
- + status = nfs41_UpcallWaitForReply(entry, VNetRootContext->timeout);
- + if (status) goto out;
- +
- + status = map_symlink_errors(entry->status);
- + nfs41_UpcallDestroy(entry);
- +out:
- + RxFreePool(prefixed_targetname);
- +
- +#ifdef DEBUG_SYMLINK
- + DbgEx();
- +#endif
- + return status;
- +}
- +#endif /* NFS41_DRIVER_EXPERIMENTAL_JUNCTION_ABSOLUTESYMLINK_SUPPORT */
- +
- static
- NTSTATUS check_nfs41_getsymlinkreparse_args(
- PRX_CONTEXT RxContext)
- @@ -376,8 +528,7 @@ NTSTATUS nfs41_GetSymlinkReparsePoint(
- __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
- NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
- nfs41_updowncall_entry *entry;
- - const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
- - SymbolicLinkReparseBuffer.PathBuffer);
- + PWSTR targetname_buffer = NULL;
- #ifdef DEBUG_SYMLINK
- DbgEn();
- @@ -391,9 +542,16 @@ NTSTATUS nfs41_GetSymlinkReparsePoint(
- goto out;
- }
- - TargetName.Buffer = (PWCH)((PBYTE)FsCtl->pOutputBuffer + HeaderLen);
- - TargetName.MaximumLength = (USHORT)min(FsCtl->OutputBufferLength -
- - HeaderLen, 0xFFFF);
- + size_t targetname_buffer_len = 4096*sizeof(wchar_t);
- + targetname_buffer = RxAllocatePoolWithTag(NonPagedPoolNx,
- + targetname_buffer_len, NFS41_MM_POOLTAG);
- + if (targetname_buffer == NULL) {
- + status = STATUS_INSUFFICIENT_RESOURCES;
- + goto out;
- + }
- +
- + TargetName.Buffer = targetname_buffer;
- + TargetName.MaximumLength = (USHORT)targetname_buffer_len;
- status = nfs41_UpcallCreate(NFS41_SYSOP_SYMLINK, &Fobx->sec_ctx,
- VNetRootContext->session, Fobx->nfs41_open_state,
- @@ -411,27 +569,115 @@ NTSTATUS nfs41_GetSymlinkReparsePoint(
- /* fill in the output buffer */
- PREPARSE_DATA_BUFFER Reparse = (PREPARSE_DATA_BUFFER)
- FsCtl->pOutputBuffer;
- +
- + DbgP("nfs41_GetSymlinkReparsePoint: TargetName='%wZ'\n",
- + &TargetName);
- +
- + /* "/cygdrive/l/" == 12 characters */
- + if ((TargetName.Length >= (12*sizeof(wchar_t))) &&
- + (!memcmp(&TargetName.Buffer[0], L"/cygdrive/",
- + (10*sizeof(wchar_t))))) {
- + const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
- + MountPointReparseBuffer.PathBuffer);
- +
- + DbgP("nfs41_GetSymlinkReparsePoint: Junction codepath\n");
- +
- + wchar_t dosletter;
- + dosletter = towupper(TargetName.Buffer[10]);
- + TargetName.Buffer += 9;
- + TargetName.MaximumLength = TargetName.Length =
- + TargetName.Length-(9*sizeof(wchar_t));
- + TargetName.Buffer[0] = dosletter;
- + TargetName.Buffer[1] = L':';
- + TargetName.Buffer[2] = L'/';
- +
- + /* POSIX slash to Win32 backslash */
- + size_t i;
- + for (i=0 ; i < TargetName.Length ; i++) {
- + if (TargetName.Buffer[i] == L'/')
- + TargetName.Buffer[i] = L'\\';
- + }
- +
- + DbgP("nfs41_GetSymlinkReparsePoint: new TargetName='%wZ'\n",
- + &TargetName);
- +
- + /* Copy data into FsCtl buffer */
- + (void)memcpy(((PBYTE)FsCtl->pOutputBuffer + HeaderLen),
- + TargetName.Buffer, TargetName.Length);
- + TargetName.Buffer =
- + (PWCH)((PBYTE)FsCtl->pOutputBuffer + HeaderLen);
- +
- + DbgP("nfs41_GetSymlinkReparsePoint: new TargetName='%wZ'\n",
- + &TargetName);
- +
- + Reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
- + Reparse->ReparseDataLength = HeaderLen + TargetName.Length -
- + REPARSE_DATA_BUFFER_HEADER_SIZE;
- + Reparse->Reserved = 0;
- + /* PrintName and SubstituteName point to the same string */
- + Reparse->MountPointReparseBuffer.SubstituteNameOffset = 0;
- + Reparse->MountPointReparseBuffer.SubstituteNameLength =
- + TargetName.Length;
- + Reparse->MountPointReparseBuffer.PrintNameOffset = 0;
- + Reparse->MountPointReparseBuffer.PrintNameLength =
- + TargetName.Length;
- +
- + print_reparse_buffer(Reparse);
- +
- + RxContext->IoStatusBlock.Information =
- + (ULONG_PTR)HeaderLen + TargetName.Length;
- + }
- + else {
- + const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
- + SymbolicLinkReparseBuffer.PathBuffer);
- +
- + DbgP("nfs41_GetSymlinkReparsePoint: Symlink codepath\n");
- +
- + /* Copy data into FsCtl buffer */
- + (void)memcpy(((PBYTE)FsCtl->pOutputBuffer + HeaderLen),
- + TargetName.Buffer, TargetName.Length);
- + TargetName.Buffer =
- + (PWCH)((PBYTE)FsCtl->pOutputBuffer + HeaderLen);
- +
- Reparse->ReparseTag = IO_REPARSE_TAG_SYMLINK;
- Reparse->ReparseDataLength = HeaderLen + TargetName.Length -
- REPARSE_DATA_BUFFER_HEADER_SIZE;
- Reparse->Reserved = 0;
- - Reparse->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
- + Reparse->SymbolicLinkReparseBuffer.Flags =
- + SYMLINK_FLAG_RELATIVE;
- /* PrintName and SubstituteName point to the same string */
- Reparse->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
- Reparse->SymbolicLinkReparseBuffer.SubstituteNameLength =
- TargetName.Length;
- Reparse->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
- - Reparse->SymbolicLinkReparseBuffer.PrintNameLength = TargetName.Length;
- + Reparse->SymbolicLinkReparseBuffer.PrintNameLength =
- + TargetName.Length;
- +
- print_reparse_buffer(Reparse);
- RxContext->IoStatusBlock.Information =
- (ULONG_PTR)HeaderLen + TargetName.Length;
- + }
- } else if (status == STATUS_BUFFER_TOO_SMALL) {
- + const size_t sym_hdr_len =
- + FIELD_OFFSET(REPARSE_DATA_BUFFER,
- + MountPointReparseBuffer.PathBuffer);
- + const size_t mnt_hdr_len =
- + FIELD_OFFSET(REPARSE_DATA_BUFFER,
- + SymbolicLinkReparseBuffer.PathBuffer);
- + /*
- + * We don't know whether we have to return
- + * |IO_REPARSE_TAG_MOUNT_POINT| or |IO_REPARSE_TAG_SYMLINK|,
- + * so we return a size which can fit both
- + */
- +#define MAX(a, b) (((a) > (b)) ? (a) : (b))
- RxContext->InformationToReturn =
- - (ULONG_PTR)HeaderLen + TargetName.Length;
- + MAX(sym_hdr_len, mnt_hdr_len) + TargetName.Length;
- }
- nfs41_UpcallDestroy(entry);
- out:
- + RxFreePool(targetname_buffer);
- +
- #ifdef DEBUG_SYMLINK
- DbgEx();
- #endif
mount reparse prototype, 2025-02-05
Posted by Anonymous on Wed 5th Feb 2025 09:06
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.