- From 816e47a15aa13c2c5b53048cbd974e17fd0f97c5 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Mon, 15 Sep 2025 18:30:12 +0200
- Subject: [PATCH 01/10] daemon,include,nfs41_build_features.h,sys: Add hack to
- override case_preserving+case_insensitive options for testing
- Add hack to override case_preserving+case_insensitive options for
- testing, which provides two mount options "forcecasepreserving=0/1"
- and "forcecaseinsensitive=0/1" to override the
- |FATTR4_WORD0_CASE_INSENSITIVE| and/or |FATTR4_WORD0_CASE_PRESERVING|
- attributes obtained from the NFS server.
- This is only a HACK to circumvent a Linux nfsd bug which always returns
- |FATTR4_WORD0_CASE_INSENSITIVE==0|&&|FATTR4_WORD0_CASE_PRESERVING==1|,
- even for FAT.
- Since Windows file accesses via UNC path make mount options basically
- per-server mounts from a single server can only have one set of
- "forcecasepreserving=0/1" and "forcecaseinsensitive=0/1" options.
- As workaround you can use use the same hostname but a different port
- number (as for ms-nfs41-client the port number of part of the UNC path),
- e.g. ssh on the NFS server itself to forward port 2050 to 2049 to
- pretent it is a different server:
- $ ssh -L '*:2050:localhost:2049' root@localhost 'printf "# forwarding...\n" ; sleep $((60*60*24*366*99))' #
- and then connect the NFS client to port 2050 on the NFS server.
- This build option should be removed as soon as the Linux nfsd bug has
- been fixed.
- THIS OPTION MUST NOT BE USED ON PRODUCTION SYSTEMS!!
- Reported-by: Cedric Blancher <cedric.blancher@gmail.com>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/mount.c | 24 +++++++++++
- daemon/namespace.c | 32 +++++++++++++--
- daemon/nfs41.h | 15 +++++++
- daemon/nfs41_client.c | 22 +++++++++++
- daemon/nfs41_superblock.c | 38 ++++++++++++------
- daemon/upcall.h | 4 ++
- include/nfs41_driver.h | 6 +++
- nfs41_build_features.h | 26 ++++++++++++
- sys/nfs41sys_driver.h | 12 ++++++
- sys/nfs41sys_mount.c | 83 ++++++++++++++++++++++++++++++++++-----
- 10 files changed, 238 insertions(+), 24 deletions(-)
- diff --git a/daemon/mount.c b/daemon/mount.c
- index 89f555c..db3327d 100644
- --- a/daemon/mount.c
- +++ b/daemon/mount.c
- @@ -55,13 +55,33 @@ static int parse_mount(unsigned char *buffer, uint32_t length, nfs41_upcall *upc
- if (status) goto out;
- status = safe_read(&buffer, &length, &args->nfsvers, sizeof(DWORD));
- if (status) goto out;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + status = safe_read(&buffer, &length, &args->force_case_preserving,
- + sizeof(tristate_bool));
- + if (status) goto out;
- + status = safe_read(&buffer, &length, &args->force_case_insensitive,
- + sizeof(tristate_bool));
- + if (status) goto out;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + DPRINTF(1, ("parsing NFS41_SYSOP_MOUNT: hostport='%s' root='%s' "
- + "sec_flavor='%s' rsize=%d wsize=%d use_nfspubfh=%d "
- + "nfsvers=%d force_case_preserving=%d force_case_insensitive=%d\n",
- + args->hostport, args->path, secflavorop2name(args->sec_flavor),
- + args->rsize, args->wsize, args->use_nfspubfh,
- + args->nfsvers,
- + (int)args->force_case_preserving,
- + (int)args->force_case_insensitive));
- +#else
- DPRINTF(1, ("parsing NFS41_SYSOP_MOUNT: hostport='%s' root='%s' "
- "sec_flavor='%s' rsize=%d wsize=%d use_nfspubfh=%d "
- "nfsvers=%d\n",
- args->hostport, args->path, secflavorop2name(args->sec_flavor),
- args->rsize, args->wsize, args->use_nfspubfh,
- args->nfsvers));
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- +
- return status;
- out:
- DPRINTF(1, ("parsing NFS41_SYSOP_MOUNT: failed %d\n", status));
- @@ -183,6 +203,10 @@ static int handle_mount(void *daemon_context, nfs41_upcall *upcall)
- // create root
- status = nfs41_root_create(hostname, port,
- args->use_nfspubfh?true:false,
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + args->force_case_preserving,
- + args->force_case_insensitive,
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- args->nfsvers,
- args->sec_flavor,
- args->wsize + WRITE_OVERHEAD, args->rsize + READ_OVERHEAD, &root);
- diff --git a/daemon/namespace.c b/daemon/namespace.c
- index 89a0e0b..7ff6ee9 100644
- --- a/daemon/namespace.c
- +++ b/daemon/namespace.c
- @@ -43,6 +43,10 @@ int nfs41_root_create(
- IN const char *name,
- IN uint32_t port,
- IN bool use_nfspubfh,
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + IN tristate_bool force_case_preserving,
- + IN tristate_bool force_case_insensitive,
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- IN DWORD nfsvers,
- IN uint32_t sec_flavor,
- IN uint32_t wsize,
- @@ -52,10 +56,23 @@ int nfs41_root_create(
- int status = NO_ERROR;
- nfs41_root *root;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- DPRINTF(NSLVL,
- ("--> nfs41_root_create(name='%s', port=%d, "
- - "use_nfspubfh=%d, nfsvers=%d)\n",
- - name, port, (int)use_nfspubfh, (int)nfsvers));
- + "use_nfspubfh=%d, "
- + "force_case_preserving=%d force_case_insensitive=%d"
- + "nfsvers=%d)\n",
- + name, port, (int)use_nfspubfh,
- + (int)force_case_preserving, (int)force_case_insensitive,
- + (int)nfsvers));
- +#else
- + DPRINTF(NSLVL,
- + ("--> nfs41_root_create(name='%s', port=%d, "
- + "use_nfspubfh=%d, "
- + "nfsvers=%d)\n",
- + name, port, (int)use_nfspubfh,
- + (int)nfsvers));
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- root = calloc(1, sizeof(nfs41_root));
- if (root == NULL) {
- @@ -65,6 +82,11 @@ int nfs41_root_create(
- list_init(&root->clients);
- root->use_nfspubfh = use_nfspubfh;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + root->force_case_preserving = force_case_preserving;
- + root->force_case_insensitive = force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- +
- /*
- * nfs41_root_mount_addrs() will enable NFSv4.2 features (like
- * |OP_READ_PLUS|) after NFSv4.x minor version autonegitiation
- @@ -98,7 +120,11 @@ int nfs41_root_create(
- /* generate a unique client_owner */
- status = nfs41_client_owner(name, port, root->nfsminorvers,
- - use_nfspubfh, sec_flavor, &root->client_owner);
- + use_nfspubfh,
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + root->force_case_preserving, root->force_case_insensitive,
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- + sec_flavor, &root->client_owner);
- if (status) {
- eprintf("nfs41_client_owner() failed with %d\n", status);
- free(root);
- diff --git a/daemon/nfs41.h b/daemon/nfs41.h
- index 670ce9c..bdebbd9 100644
- --- a/daemon/nfs41.h
- +++ b/daemon/nfs41.h
- @@ -25,8 +25,10 @@
- #define __NFS41__ 1
- #include <stdbool.h>
- +#include "nfs41_build_features.h"
- #include "util.h"
- #include "list.h"
- +#include "nfs41_driver.h" /* needed for |tristate_bool| */
- struct __nfs41_session;
- @@ -320,6 +322,10 @@ typedef struct __nfs41_root {
- uint32_t uid;
- uint32_t gid;
- DWORD sec_flavor;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + tristate_bool force_case_preserving;
- + tristate_bool force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- } nfs41_root;
- @@ -328,12 +334,17 @@ int nfs41_root_create(
- IN const char *name,
- IN uint32_t port,
- IN bool use_nfspubfh,
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + IN tristate_bool force_case_preserving,
- + IN tristate_bool force_case_insensitive,
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- IN DWORD nfsvers,
- IN uint32_t sec_flavor,
- IN uint32_t wsize,
- IN uint32_t rsize,
- OUT nfs41_root **root_out);
- +
- void nfs41_root_ref(
- IN nfs41_root *root);
- @@ -449,6 +460,10 @@ int nfs41_client_owner(
- IN uint32_t port,
- IN int nfsminorvers,
- IN bool use_nfspubfh,
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + IN tristate_bool force_case_preserving,
- + IN tristate_bool force_case_insensitive,
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- IN uint32_t sec_flavor,
- OUT client_owner4 *owner);
- diff --git a/daemon/nfs41_client.c b/daemon/nfs41_client.c
- index 7510f05..f585ee9 100644
- --- a/daemon/nfs41_client.c
- +++ b/daemon/nfs41_client.c
- @@ -371,6 +371,10 @@ int nfs41_client_owner(
- IN uint32_t port,
- IN int nfsminorvers,
- IN bool use_nfspubfh,
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + IN tristate_bool force_case_preserving,
- + IN tristate_bool force_case_insensitive,
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- IN uint32_t sec_flavor,
- OUT client_owner4 *owner)
- {
- @@ -443,6 +447,24 @@ int nfs41_client_owner(
- goto out_hash;
- }
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + if (!CryptHashData(hash,
- + (const BYTE*)&force_case_preserving,
- + (DWORD)sizeof(force_case_preserving), 0)) {
- + status = GetLastError();
- + eprintf("CryptHashData() failed with %d\n", status);
- + goto out_hash;
- + }
- +
- + if (!CryptHashData(hash,
- + (const BYTE*)&force_case_insensitive,
- + (DWORD)sizeof(force_case_insensitive), 0)) {
- + status = GetLastError();
- + eprintf("CryptHashData() failed with %d\n", status);
- + goto out_hash;
- + }
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- +
- if (!CryptHashData(hash, (const BYTE*)&sec_flavor, (DWORD)sizeof(sec_flavor), 0)) {
- status = GetLastError();
- eprintf("CryptHashData() failed with %d\n", status);
- diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
- index 23b4024..626ef04 100644
- --- a/daemon/nfs41_superblock.c
- +++ b/daemon/nfs41_superblock.c
- @@ -81,6 +81,7 @@ static int get_superblock_attrs(
- IN nfs41_superblock *superblock,
- IN nfs41_path_fh *file)
- {
- + nfs41_root *root = session->client->root;
- bool_t supports_named_attrs;
- int status;
- bitmap4 attr_request;
- @@ -125,22 +126,35 @@ static int get_superblock_attrs(
- superblock->link_support = info.link_support;
- superblock->symlink_support = info.symlink_support;
- superblock->ea_support = supports_named_attrs;
- -//#define TEST_LINUX_FORCE_FAT32 1
- -#ifdef TEST_LINUX_FORCE_FAT32
- - /*
- - * Testing-ONLY: Force FAT32 behaviour, because Linux nfsd returns
- - * |info.case_insensitive==0| even on FAT32
- - * Windows Server 2019 nfsd and OpenText nfsd do this correctly
- - */
- - DPRINTF(0, ("get_superblock_attrs: TEST_LINUX_FORCE_FAT32 enabled!\n"));
- - superblock->case_preserving = 0/*info.case_preserving*/;
- - superblock->case_insensitive = 1/*info.case_insensitive*/;
- +
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + if (root->force_case_preserving == TRISTATE_BOOL_NOT_SET) {
- + superblock->case_preserving = info.case_preserving;
- + }
- + else {
- + superblock->case_preserving =
- + root->force_case_preserving?1:0;
- + DPRINTF(0,
- + ("get_superblock_attrs: OVERRIDING case_preserving to %d\n",
- + (int)superblock->case_preserving));
- + }
- + if (root->force_case_insensitive == TRISTATE_BOOL_NOT_SET) {
- + superblock->case_insensitive = info.case_insensitive;
- + }
- + else {
- + superblock->case_insensitive =
- + root->force_case_insensitive?1:0;
- + DPRINTF(0,
- + ("get_superblock_attrs: OVERRIDING case_insensitive to %d\n",
- + (int)superblock->case_insensitive));
- + }
- #else
- superblock->case_preserving = info.case_preserving;
- superblock->case_insensitive = info.case_insensitive;
- -#endif /* TEST_FS_FORCE_FAT32 */
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- +
- superblock->sparse_file_support = 1; /* always ON for now */
- - if (session->client->root->nfsminorvers >= 2) {
- + if (root->nfsminorvers >= 2) {
- superblock->block_clone_support = 1;
- }
- else {
- diff --git a/daemon/upcall.h b/daemon/upcall.h
- index 2d829ae..8e099bc 100644
- --- a/daemon/upcall.h
- +++ b/daemon/upcall.h
- @@ -40,6 +40,10 @@ typedef struct __mount_upcall_args {
- DWORD wsize;
- DWORD use_nfspubfh;
- DWORD nfsvers;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + tristate_bool force_case_preserving;
- + tristate_bool force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- DWORD lease_time;
- NFS41_FILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
- } mount_upcall_args;
- diff --git a/include/nfs41_driver.h b/include/nfs41_driver.h
- index 7a4ddfc..310eeee 100644
- --- a/include/nfs41_driver.h
- +++ b/include/nfs41_driver.h
- @@ -156,4 +156,10 @@ typedef enum _nfs41_start_driver_state {
- #define ERROR_NFS_VERSION_MISMATCH ERROR_REMOTE_FILE_VERSION_MISMATCH
- #define STATUS_NFS_VERSION_MISMATCH STATUS_REMOTE_FILE_VERSION_MISMATCH
- +/* Boolean with three states to cover "not set" */
- +typedef signed char tristate_bool;
- +#define TRISTATE_BOOL_NOT_SET (-1)
- +#define TRISTATE_BOOL_FALSE (0)
- +#define TRISTATE_BOOL_TRUE (1)
- +
- #endif /* !_NFS41_DRIVER_ */
- diff --git a/nfs41_build_features.h b/nfs41_build_features.h
- index 38f6372..c2963f4 100644
- --- a/nfs41_build_features.h
- +++ b/nfs41_build_features.h
- @@ -236,4 +236,30 @@
- */
- #define NFS41_DRIVER_HACK_LOCKING_STORAGE32_RANGELOCK_PROBING 1
- +/*
- + * |NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS| - provide mount
- + * options "forcecasepreserving=0/1" and "forcecaseinsensitive=0/1"
- + * to override |FATTR4_WORD0_CASE_INSENSITIVE|/|FATTR4_WORD0_CASE_PRESERVING|
- + * obtained by the NFS server.
- + *
- + * This is only a HACK to circumvent a Linux nfsd bug which always returns
- + * |FATTR4_WORD0_CASE_INSENSITIVE==0|&&|FATTR4_WORD0_CASE_PRESERVING==1|,
- + * even for FAT.
- + * Since Windows file accesses via UNC path make mount options basically
- + * per-server mounts from a single server can only have one set of
- + * "forcecasepreserving=0/1" and "forcecaseinsensitive=0/1" options.
- + *
- + * As workaround you can use use the same hostname but a different port
- + * number (as for ms-nfs41-client the port number of part of the UNC path),
- + * e.g. ssh on the NFS server itself to forward port 2050 to 2049 to
- + * pretent it is a different server:
- + * $ ssh -L '*:2050:localhost:2049' root@localhost 'printf "# forwarding...\n" ; sleep $((60*60*24*366*99))' #
- + * and then connect the NFS client to port 2050 on the NFS server.
- + *
- + * This build option should be removed as soon as the Linux nfsd has been
- + * fixed.
- + * THIS OPTION MUST NOT BE USED ON PRODUCTION SYSTEMS!!
- + */
- +#define NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS 1
- +
- #endif /* !_NFS41_DRIVER_BUILDFEATURES_ */
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index c96244c..df26e64 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -201,6 +201,10 @@ typedef struct _updowncall_entry {
- DWORD lease_time;
- DWORD use_nfspubfh;
- DWORD nfsvers;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + tristate_bool force_case_preserving;
- + tristate_bool force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- } Mount;
- struct {
- PMDL MdlAddress;
- @@ -339,6 +343,10 @@ typedef struct _NFS41_MOUNT_CONFIG {
- DWORD timeout;
- NFS41_MOUNT_CREATEMODE dir_createmode;
- NFS41_MOUNT_CREATEMODE file_createmode;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + tristate_bool force_case_preserving;
- + tristate_bool force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- } NFS41_MOUNT_CONFIG, *PNFS41_MOUNT_CONFIG;
- typedef struct _nfs41_mount_entry {
- @@ -434,6 +442,10 @@ typedef struct _NFS41_V_NET_ROOT_EXTENSION {
- BOOLEAN write_thru;
- BOOLEAN nocache;
- BOOLEAN timebasedcoherency;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + tristate_bool force_case_preserving;
- + tristate_bool force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- } NFS41_V_NET_ROOT_EXTENSION, *PNFS41_V_NET_ROOT_EXTENSION;
- #define NFS41GetVNetRootExtension(pVNetRoot) \
- (((pVNetRoot) == NULL) ? NULL : \
- diff --git a/sys/nfs41sys_mount.c b/sys/nfs41sys_mount.c
- index 6d652b6..6903b62 100644
- --- a/sys/nfs41sys_mount.c
- +++ b/sys/nfs41sys_mount.c
- @@ -108,7 +108,11 @@ NTSTATUS marshal_nfs41_mount(
- else tmp += *len;
- header_len = *len + length_as_utf8(entry->u.Mount.srv_name) +
- - length_as_utf8(entry->u.Mount.root) + 5 * sizeof(DWORD);
- + length_as_utf8(entry->u.Mount.root) + 5 * sizeof(DWORD)
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + + 2 * sizeof(tristate_bool)
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- + ;
- if (header_len > buf_len) {
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto out;
- @@ -126,18 +130,36 @@ NTSTATUS marshal_nfs41_mount(
- RtlCopyMemory(tmp, &entry->u.Mount.use_nfspubfh, sizeof(DWORD));
- tmp += sizeof(DWORD);
- RtlCopyMemory(tmp, &entry->u.Mount.nfsvers, sizeof(DWORD));
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + tmp += sizeof(DWORD);
- + RtlCopyMemory(tmp, &entry->u.Mount.force_case_preserving,
- + sizeof(tristate_bool));
- + tmp += sizeof(tristate_bool);
- + RtlCopyMemory(tmp, &entry->u.Mount.force_case_insensitive,
- + sizeof(tristate_bool));
- + /* tmp += sizeof(tristate_bool); */
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- *len = header_len;
- #ifdef DEBUG_MARSHAL_DETAIL
- DbgP("marshal_nfs41_mount: server name='%wZ' mount point='%wZ' "
- - "sec_flavor='%s' rsize=%d wsize=%d use_nfspubfh=%d "
- - "nfsvers=%d\n",
- - entry->u.Mount.srv_name, entry->u.Mount.root,
- - secflavorop2name(entry->u.Mount.sec_flavor),
- - (int)entry->u.Mount.rsize, (int)entry->u.Mount.wsize,
- - (int)entry->u.Mount.use_nfspubfh,
- - (int)entry->u.Mount.nfsvers);
- + "sec_flavor='%s' rsize=%d wsize=%d use_nfspubfh=%d "
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + "nfsvers=%d force_case_preserving=%d force_case_insensitive=%d\n"
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- + ,
- + entry->u.Mount.srv_name, entry->u.Mount.root,
- + secflavorop2name(entry->u.Mount.sec_flavor),
- + (int)entry->u.Mount.rsize, (int)entry->u.Mount.wsize,
- + (int)entry->u.Mount.use_nfspubfh,
- + (int)entry->u.Mount.nfsvers
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + ,
- + (int)entry->u.Mount.force_case_preserving,
- + (int)entry->u.Mount.force_case_insensitive
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- + );
- #endif
- out:
- return status;
- @@ -262,6 +284,10 @@ NTSTATUS nfs41_mount(
- entry->u.Mount.wsize = config->WriteSize;
- entry->u.Mount.use_nfspubfh = config->use_nfspubfh;
- entry->u.Mount.nfsvers = config->nfsvers;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + entry->u.Mount.force_case_preserving = config->force_case_preserving;
- + entry->u.Mount.force_case_insensitive = config->force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- entry->u.Mount.sec_flavor = sec_flavor;
- entry->u.Mount.FsAttrs = FsAttrs;
- @@ -320,6 +346,10 @@ void nfs41_MountConfig_InitDefaults(
- Config->file_createmode.use_nfsv3attrsea_mode = TRUE;
- Config->file_createmode.mode =
- NFS41_DRIVER_DEFAULT_FILE_CREATE_MODE;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + Config->force_case_preserving = TRISTATE_BOOL_NOT_SET;
- + Config->force_case_insensitive = TRISTATE_BOOL_NOT_SET;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- }
- static
- @@ -647,6 +677,22 @@ NTSTATUS nfs41_MountConfig_ParseOptions(
- (int)Config->file_createmode.use_nfsv3attrsea_mode,
- (int)Config->file_createmode.mode);
- }
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + else if (wcsncmp(L"forcecasepreserving", Name, NameLen) == 0) {
- + BOOLEAN val;
- + status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
- + FALSE, &val);
- + Config->force_case_preserving =
- + val?TRISTATE_BOOL_TRUE:TRISTATE_BOOL_FALSE;
- + }
- + else if (wcsncmp(L"forcecaseinsensitive", Name, NameLen) == 0) {
- + BOOLEAN val;
- + status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
- + FALSE, &val);
- + Config->force_case_insensitive =
- + val?TRISTATE_BOOL_TRUE:TRISTATE_BOOL_FALSE;
- + }
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- else {
- status = STATUS_INVALID_PARAMETER;
- print_error("Unrecognized option '%ls' -> '%wZ'\n",
- @@ -1068,6 +1114,10 @@ NTSTATUS nfs41_CreateVNetRoot(
- "timeout=%d "
- "dir_cmode=(usenfsv3attrs=%d mode=0%o) "
- "file_cmode=(usenfsv3attrs=%d mode=0%o) "
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + "force_case_preserving=%d "
- + "force_case_insensitive=%d "
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- "}\n",
- &Config->MntPt,
- &Config->SrvName,
- @@ -1081,7 +1131,13 @@ NTSTATUS nfs41_CreateVNetRoot(
- Config->dir_createmode.use_nfsv3attrsea_mode?1:0,
- Config->dir_createmode.mode,
- Config->file_createmode.use_nfsv3attrsea_mode?1:0,
- - Config->file_createmode.mode);
- + Config->file_createmode.mode
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + ,
- + (int)Config->force_case_preserving,
- + (int)Config->force_case_insensitive
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- + );
- pVNetRootContext->MntPt.Buffer = pVNetRootContext->mntpt_buffer;
- pVNetRootContext->MntPt.Length = Config->MntPt.Length;
- @@ -1096,6 +1152,15 @@ NTSTATUS nfs41_CreateVNetRoot(
- Config->file_createmode.use_nfsv3attrsea_mode;
- pVNetRootContext->file_createmode.mode =
- Config->file_createmode.mode;
- +#ifdef NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS
- + /*
- + * FIXME: NO-OP for now, as no one reads
- + * |pVNetRootContext->force_case_preserving| and
- + * |pVNetRootContext->force_case_insensitive| (yet)
- + */
- + pVNetRootContext->force_case_preserving = Config->force_case_preserving;
- + pVNetRootContext->force_case_insensitive = Config->force_case_insensitive;
- +#endif /* NFS41_DRIVER_HACK_FORCE_FILENAME_CASE_MOUNTOPTIONS */
- status = map_sec_flavor(&Config->SecFlavor, &pVNetRootContext->sec_flavor);
- if (status != STATUS_SUCCESS) {
- --
- 2.51.0
- From d26f9e97e72e32e55b74e8a6c849d7a24297014f Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Mon, 15 Sep 2025 18:48:20 +0200
- Subject: [PATCH 02/10] daemon: Remove |GetACP()| debug code
- Remove |GetACP()| debug code
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/nfs41_daemon.c | 4 ----
- 1 file changed, 4 deletions(-)
- diff --git a/daemon/nfs41_daemon.c b/daemon/nfs41_daemon.c
- index fb919c5..074c291 100644
- --- a/daemon/nfs41_daemon.c
- +++ b/daemon/nfs41_daemon.c
- @@ -805,10 +805,6 @@ VOID ServiceStart(DWORD argc, LPTSTR *argv)
- DPRINTF(0, ("SID cache disabled\n"));
- #endif /* NFS41_DRIVER_SID_CACHE */
- -#if 1
- - DPRINTF(0, ("wmain: GetACP()=%d\n", (int)GetACP()));
- -#endif
- -
- #ifdef _DEBUG
- logprintf("NFS client daemon (DEBUG build) %s starting...\n",
- GIT_COMMIT_ID);
- --
- 2.51.0
- From e66af0732c0c7cf6994258475859e3234746c6cf Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Mon, 15 Sep 2025 18:52:44 +0200
- Subject: [PATCH 03/10] tests: Document how to (easily) test custom NFS TCP
- ports via local ssh port forwaring on the NFS server
- Document how to (easily) test custom NFS TCP ports via local ssh port
- forwaring on the NFS server.
- Reported-by: Lionel Cons <Lionelcons1972@gmail.com>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/manual_testing.txt | 9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
- diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
- index d9e00ca..5659ed5 100644
- --- a/tests/manual_testing.txt
- +++ b/tests/manual_testing.txt
- @@ -1,5 +1,5 @@
- #
- -# ms-nfs41-client manual testing sequence, 2025-09-04
- +# ms-nfs41-client manual testing sequence, 2025-09-15
- #
- # Draft version, needs to be turned into automated tests
- # if possible
- @@ -158,7 +158,12 @@
- # 4. Disable verifier:
- # $ verifier /reset
- #
- -
- +# - Testing NFSv4.* with non-standard TCP ports:
- +# 1. Run this on the NFS server itself to forward accesses to TCP/2050
- +# to TCP/2049 on the same server machine:
- +# $ ssh -L '*:2050:localhost:2049' root@localhost 'printf "# forwarding...\n" ; sleep $((60*60*24*366))'
- +# 2. Connect to the NFS server via nfs://servername1:2050//path/to/nfsexport
- +#
- #
- # "cthon04" test suite:
- --
- 2.51.0
- From 8ff8c9e1b1d226e9e05f31ebf7c9687c338c852b Mon Sep 17 00:00:00 2001
- From: Cedric Blancher <cedric.blancher@gmail.com>
- Date: Sat, 13 Sep 2025 13:17:38 +0200
- Subject: [PATCH 04/10] daemon: Update+comment |FATTR_|+|OP_| for new RFCs
- Update+comment |FATTR_|+|OP_| for new RFCs.
- Signed-off-by: Roland Mainz <roland.mainz@nrubsig.org>
- ---
- daemon/nfs41_const.h | 10 +++++++++-
- daemon/nfs41_ops.h | 10 +++++++++-
- 2 files changed, 18 insertions(+), 2 deletions(-)
- diff --git a/daemon/nfs41_const.h b/daemon/nfs41_const.h
- index 74ad31d..04adcc4 100644
- --- a/daemon/nfs41_const.h
- +++ b/daemon/nfs41_const.h
- @@ -369,7 +369,15 @@ enum nfsstat4 {
- #define FATTR4_WORD2_MODE_SET_MASKED MAKE_WORD2(74)
- #define FATTR4_WORD2_FS_CHARSET_CAP MAKE_WORD2(76)
- #define FATTR4_WORD2_CLONE_BLKSIZE MAKE_WORD2(77)
- -
- +#define FATTR4_WORD2_SPACE_FREED MAKE_WORD2(78)
- +#define FATTR4_WORD2_CHANGE_ATTR_TYPE MAKE_WORD2(79)
- +#define FATTR4_WORD2_SECURITY_LABEL MAKE_WORD2(80)
- +#define FATTR4_WORD2_MODE_UMASK MAKE_WORD2(81) /* RFC 8275 */
- +#define FATTR4_WORD2_XATTR_SUPPORT MAKE_WORD2(82) /* RFC 8726+Linux XATTR is incompatible with Win32 EA */
- +#define FATTR4_WORD2_OFFLINE MAKE_WORD2(83) /* RFC 9754 */
- +#define FATTR4_WORD2_TIME_DELEG_ACCESS MAKE_WORD2(84)
- +#define FATTR4_WORD2_TIME_DELEG_MODIFY MAKE_WORD2(85)
- +#define FATTR4_WORD2_OPEN_ARGUMENTS MAKE_WORD2(86)
- /*
- * File types
- diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h
- index bd93fbf..8f2b022 100644
- --- a/daemon/nfs41_ops.h
- +++ b/daemon/nfs41_ops.h
- @@ -104,7 +104,15 @@ enum nfs_opnum4 {
- OP_WRITE_SAME = 70,
- OP_CLONE = 71,
- - /* xattr support (RFC8726) */
- + /*
- + * xattr support (RFC8726)
- + * Note that RFC8726 XATTRS represent Linux XATTRs and are
- + * semantically incompatible to Windows EA (extended attributes).
- + * Windows EAs can only properly (i.e. pass the Windows HCL
- + * filesystem tests) be implemented via NFSv4 "named attributes"
- + * (OP_OPENATTR)&co, so these will remain no-ops for Windows NFS
- + * clients conformaing to the Win32 specs.
- + */
- OP_GETXATTR = 72,
- OP_SETXATTR = 73,
- OP_LISTXATTRS = 74,
- --
- 2.51.0
- From 088f99b5d8e8745e62a805e8f77f9b701ed80738 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Mon, 15 Sep 2025 18:59:43 +0200
- Subject: [PATCH 05/10] daemon: Implement Win32 |FILE_ATTRIBUTE_OFFLINE| via
- |FATTR4_OFFLINE|
- Implement Win32 |FILE_ATTRIBUTE_OFFLINE| via RFC9754 |FATTR4_OFFLINE|
- (see https://datatracker.ietf.org/doc/rfc9754/).
- Reported-by: Lionel Cons <Lionelcons1972@gmail.com>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/daemon_debug.c | 3 +++
- daemon/fileinfoutil.c | 5 ++++
- daemon/lookup.c | 3 ++-
- daemon/name_cache.c | 48 +++++++++++++++++++++++----------------
- daemon/nfs41_superblock.c | 2 +-
- daemon/nfs41_types.h | 2 ++
- daemon/nfs41_xdr.c | 4 ++++
- daemon/open.c | 1 +
- 8 files changed, 47 insertions(+), 21 deletions(-)
- diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
- index 02a0aec..19d9e6e 100644
- --- a/daemon/daemon_debug.c
- +++ b/daemon/daemon_debug.c
- @@ -1147,6 +1147,9 @@ void print_nfs41_file_info(
- (long)info->clone_blksize);
- }
- + if (info->attrmask.arr[2] & FATTR4_WORD2_OFFLINE)
- + PRNFS41FI_FMT("offline=%d, ", (int)info->offline);
- +
- p += snprintf(p, (sizeof(buf)-(p-buf)), "} ");
- }
- diff --git a/daemon/fileinfoutil.c b/daemon/fileinfoutil.c
- index 2556c87..3466cfd 100644
- --- a/daemon/fileinfoutil.c
- +++ b/daemon/fileinfoutil.c
- @@ -84,6 +84,8 @@ ULONG nfs_file_info_to_attributes(
- attrs |= FILE_ATTRIBUTE_SYSTEM;
- if (info->archive)
- attrs |= FILE_ATTRIBUTE_ARCHIVE;
- + if (info->offline)
- + attrs |= FILE_ATTRIBUTE_OFFLINE;
- /*
- * |FILE_ATTRIBUTE_NORMAL| attribute is only set if no other
- @@ -637,6 +639,9 @@ void nfs41_file_info_cpy(
- if (attrmask->arr[2] & FATTR4_WORD2_CLONE_BLKSIZE) {
- dest->clone_blksize = src->clone_blksize;
- }
- + if (attrmask->arr[2] & FATTR4_WORD2_OFFLINE) {
- + dest->offline = src->offline;
- + }
- }
- if (flags & NFS41FILEINFOCPY_COPY_SYMLINK_DIR) {
- diff --git a/daemon/lookup.c b/daemon/lookup.c
- index 4eb6808..d56307d 100644
- --- a/daemon/lookup.c
- +++ b/daemon/lookup.c
- @@ -96,7 +96,7 @@ static void init_component_args(
- {
- uint32_t i;
- - args->attr_request.count = 2;
- + args->attr_request.count = 3;
- args->attr_request.arr[0] = FATTR4_WORD0_TYPE
- | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE
- | FATTR4_WORD0_FSID | FATTR4_WORD0_FILEID
- @@ -107,6 +107,7 @@ static void init_component_args(
- | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_CREATE
- | FATTR4_WORD1_TIME_MODIFY
- | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP;
- + args->attr_request.arr[2] = FATTR4_WORD2_OFFLINE;
- args->getrootattr.attr_request = &args->attr_request;
- res->root.path = path;
- diff --git a/daemon/name_cache.c b/daemon/name_cache.c
- index f025983..1ef1a47 100644
- --- a/daemon/name_cache.c
- +++ b/daemon/name_cache.c
- @@ -77,22 +77,23 @@ static __inline bool_t is_delegation(
- return type == OPEN_DELEGATE_READ || type == OPEN_DELEGATE_WRITE;
- }
- -#define NC_ATTR_TYPE (1 << 0)
- -#define NC_ATTR_CHANGE (1 << 1)
- -#define NC_ATTR_FSID (1 << 2)
- -#define NC_ATTR_SIZE (1 << 3)
- -#define NC_ATTR_SPACE_USED (1 << 4)
- -#define NC_ATTR_HIDDEN (1 << 5)
- -#define NC_ATTR_ARCHIVE (1 << 6)
- -#define NC_ATTR_MODE (1 << 7)
- -#define NC_ATTR_NUMLINKS (1 << 8)
- -#define NC_ATTR_OWNER (1 << 9)
- -#define NC_ATTR_OWNER_GROUP (1 << 10)
- -#define NC_ATTR_TIME_ACCESS (1 << 11)
- -#define NC_ATTR_TIME_CREATE (1 << 12)
- -#define NC_ATTR_TIME_MODIFY (1 << 13)
- -#define NC_ATTR_SYSTEM (1 << 14)
- -#define NC_ATTR_CLONE_BLKSIZE (1 << 15)
- +#define NC_ATTR_TYPE (1 << 0)
- +#define NC_ATTR_CHANGE (1 << 1)
- +#define NC_ATTR_FSID (1 << 2)
- +#define NC_ATTR_SIZE (1 << 3)
- +#define NC_ATTR_SPACE_USED (1 << 4)
- +#define NC_ATTR_HIDDEN (1 << 5)
- +#define NC_ATTR_ARCHIVE (1 << 6)
- +#define NC_ATTR_SYSTEM (1 << 7)
- +#define NC_ATTR_OFFLINE (1 << 8)
- +#define NC_ATTR_MODE (1 << 9)
- +#define NC_ATTR_NUMLINKS (1 << 10)
- +#define NC_ATTR_OWNER (1 << 11)
- +#define NC_ATTR_OWNER_GROUP (1 << 12)
- +#define NC_ATTR_TIME_ACCESS (1 << 13)
- +#define NC_ATTR_TIME_CREATE (1 << 14)
- +#define NC_ATTR_TIME_MODIFY (1 << 15)
- +#define NC_ATTR_CLONE_BLKSIZE (1 << 16)
- /* attribute cache */
- struct attr_cache_entry {
- @@ -114,14 +115,15 @@ struct attr_cache_entry {
- uint32_t numlinks;
- unsigned mode : 30;
- unsigned hidden : 1;
- - unsigned system : 1;
- unsigned archive : 1;
- - uint32_t clone_blksize;
- - util_reltimestamp expiration;
- + unsigned system : 1;
- + unsigned offline : 1;
- unsigned ref_count : 26;
- unsigned type : 4;
- unsigned invalidated : 1;
- unsigned delegated : 1;
- + uint32_t clone_blksize;
- + util_reltimestamp expiration;
- char owner[NFS4_FATTR4_OWNER_LIMIT+1];
- char owner_group[NFS4_FATTR4_OWNER_LIMIT+1];
- };
- @@ -394,6 +396,10 @@ static void attr_cache_update(
- entry->nc_attrs |= NC_ATTR_CLONE_BLKSIZE;
- entry->clone_blksize = info->clone_blksize;
- }
- + if (info->attrmask.arr[2] & FATTR4_WORD2_OFFLINE) {
- + entry->nc_attrs |= NC_ATTR_OFFLINE;
- + entry->offline = info->offline;
- + }
- }
- if (is_delegation(delegation))
- @@ -489,6 +495,10 @@ static void copy_attrs(
- dst->attrmask.arr[2] |= FATTR4_WORD2_CLONE_BLKSIZE;
- dst->clone_blksize = src->clone_blksize;
- }
- + if (src->nc_attrs & NC_ATTR_OFFLINE) {
- + dst->attrmask.arr[2] |= FATTR4_WORD2_OFFLINE;
- + dst->offline = src->offline;
- + }
- if (dst->attrmask.arr[2] != 0) {
- dst->attrmask.count = 3;
- diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
- index 626ef04..84d06db 100644
- --- a/daemon/nfs41_superblock.c
- +++ b/daemon/nfs41_superblock.c
- @@ -185,7 +185,7 @@ static int get_superblock_attrs(
- | FATTR4_WORD1_SYSTEM
- | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_CREATE
- | FATTR4_WORD1_TIME_MODIFY;
- - superblock->default_getattr.arr[2] = 0;
- + superblock->default_getattr.arr[2] = FATTR4_WORD2_OFFLINE;
- nfs41_superblock_supported_attrs(superblock, &superblock->default_getattr);
- diff --git a/daemon/nfs41_types.h b/daemon/nfs41_types.h
- index b0dca52..bded8db 100644
- --- a/daemon/nfs41_types.h
- +++ b/daemon/nfs41_types.h
- @@ -4,6 +4,7 @@
- *
- * Olga Kornievskaia <aglo@umich.edu>
- * Casey Bodley <cbodley@umich.edu>
- + * Roland Mainz <roland.mainz@nrubsig.org>
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- @@ -221,6 +222,7 @@ typedef struct __nfs41_file_info {
- bool_t hidden;
- bool_t system;
- bool_t archive;
- + bool_t offline;
- uint32_t clone_blksize;
- bool_t case_insensitive;
- bool_t case_preserving;
- diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c
- index c1e22e5..1736ade 100644
- --- a/daemon/nfs41_xdr.c
- +++ b/daemon/nfs41_xdr.c
- @@ -1927,6 +1927,10 @@ static bool_t decode_file_attrs(
- if (!xdr_uint32_t(xdr, &info->clone_blksize))
- return FALSE;
- }
- + if (attrs->attrmask.arr[2] & FATTR4_WORD2_OFFLINE) {
- + if (!xdr_bool(xdr, &info->offline))
- + return FALSE;
- + }
- }
- return TRUE;
- }
- diff --git a/daemon/open.c b/daemon/open.c
- index dd10c38..43f753c 100644
- --- a/daemon/open.c
- +++ b/daemon/open.c
- @@ -1021,6 +1021,7 @@ static int handle_open(void *daemon_context, nfs41_upcall *upcall)
- createattrs.hidden = args->file_attrs & FILE_ATTRIBUTE_HIDDEN ? 1 : 0;
- createattrs.system = args->file_attrs & FILE_ATTRIBUTE_SYSTEM ? 1 : 0;
- createattrs.archive = args->file_attrs & FILE_ATTRIBUTE_ARCHIVE ? 1 : 0;
- + /* FIXME: What about |FILE_ATTRIBUTE_OFFLINE| ? */
- map_access_2_allowdeny(args->access_mask, args->access_mode,
- args->disposition, &state->share_access, &state->share_deny);
- --
- 2.51.0
- From b6584909d927abd24154dd090c006ddd5e1593ae Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 17 Sep 2025 15:19:17 +0200
- Subject: [PATCH 06/10] daemon,sys: Make case-insensitive name matching
- per-superblock
- Make case-insensitive name matching per-superblock instead of per-server,
- to allow that a single server can export both case-sensitive and
- case-insensitive filesystems.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/lookup.c | 15 ++--
- daemon/mount.c | 7 +-
- daemon/name_cache.c | 139 ++++++++++++++++++++++++--------------
- daemon/name_cache.h | 10 +--
- daemon/nfs41_compound.c | 5 +-
- daemon/nfs41_ops.c | 9 ++-
- daemon/nfs41_ops.h | 1 +
- daemon/nfs41_superblock.c | 19 ++----
- daemon/open.c | 29 +++++++-
- daemon/readdir.c | 9 ++-
- daemon/setattr.c | 4 ++
- daemon/symlink.c | 5 +-
- daemon/upcall.h | 1 +
- daemon/util.h | 6 ++
- sys/nfs41sys_driver.h | 1 +
- sys/nfs41sys_openclose.c | 17 +++++
- 16 files changed, 198 insertions(+), 79 deletions(-)
- diff --git a/daemon/lookup.c b/daemon/lookup.c
- index d56307d..dfff849 100644
- --- a/daemon/lookup.c
- +++ b/daemon/lookup.c
- @@ -231,7 +231,9 @@ static int server_lookup(
- /* add the file handle and attributes to the name cache */
- bitmap4_cpy(&res->getrootattr.info->attrmask,
- &res->getrootattr.obj_attributes.attrmask);
- - nfs41_name_cache_insert(session_name_cache(session), path, &name,
- + nfs41_name_cache_insert(session_name_cache(session),
- + BIT2BOOL(dir->fh.superblock->case_insensitive),
- + path, &name,
- &dir->fh, res->getrootattr.info, NULL, OPEN_DELEGATE_NONE);
- }
- file = dir;
- @@ -254,7 +256,9 @@ static int server_lookup(
- if (parent_out) *parent_out = file;
- } else if (res->lookup[i].status == NFS4ERR_NOENT) {
- /* insert a negative lookup entry */
- - nfs41_name_cache_insert(session_name_cache(session), path,
- + nfs41_name_cache_insert(session_name_cache(session),
- + BIT2BOOL(dir->fh.superblock->case_insensitive),
- + path,
- args->lookup[i].name, NULL, NULL, NULL, OPEN_DELEGATE_NONE);
- }
- status = res->lookup[i].status; if (status) break;
- @@ -282,6 +286,7 @@ static int server_lookup(
- bitmap4_cpy(&res->getattr[i].info->attrmask,
- &res->getattr[i].obj_attributes.attrmask);
- nfs41_name_cache_insert(session_name_cache(session),
- + BIT2BOOL(parent->fh.superblock->case_insensitive),
- path, args->lookup[i].name, &res->file[i].fh,
- res->getattr[i].info, NULL, OPEN_DELEGATE_NONE);
- @@ -463,6 +468,7 @@ out:
- int nfs41_lookup(
- IN nfs41_root *root,
- IN nfs41_session *session,
- + IN bool casesensitive,
- IN OUT nfs41_abs_path *path_inout,
- OUT OPTIONAL nfs41_path_fh *parent_out,
- OUT OPTIONAL nfs41_path_fh *target_out,
- @@ -496,7 +502,7 @@ int nfs41_lookup(
- if (target_out == NULL) target_out = ⌖
- parent_out->fh.len = target_out->fh.len = 0;
- - status = nfs41_name_cache_lookup(cache, path_pos, path_end, &path_pos,
- + status = nfs41_name_cache_lookup(cache, casesensitive, path_pos, path_end, &path_pos,
- &parent_out->fh, &target_out->fh, info_out, &negative);
- if (status == NO_ERROR || negative)
- goto out;
- @@ -538,7 +544,8 @@ int nfs41_lookup(
- if (session_out) *session_out = new_session;
- /* look up the new path */
- - status = nfs41_lookup(root, new_session, path_inout,
- + status = nfs41_lookup(root, new_session,
- + casesensitive, path_inout,
- parent_out, target_out, info_out, session_out);
- }
- out:
- diff --git a/daemon/mount.c b/daemon/mount.c
- index db3327d..d1f2e9e 100644
- --- a/daemon/mount.c
- +++ b/daemon/mount.c
- @@ -234,8 +234,13 @@ static int handle_mount(void *daemon_context, nfs41_upcall *upcall)
- }
- path.len = (unsigned short)strlen(path.path);
- - // look up the mount path, and fail if it doesn't exist
- + /*
- + * look up the mount path, and fail if it doesn't exist
- + * (The lookup is done case-sensitive, but will work correctly
- + * with case mixing if the exported filesystem is case-insensitive)
- + */
- status = nfs41_lookup(root, client->session,
- + false,
- &path, NULL, &file, NULL, NULL);
- if (status) {
- eprintf("nfs41_lookup('%s') failed with %d\n", path.path, status);
- diff --git a/daemon/name_cache.c b/daemon/name_cache.c
- index 1ef1a47..1351a58 100644
- --- a/daemon/name_cache.c
- +++ b/daemon/name_cache.c
- @@ -530,7 +530,13 @@ struct name_cache_entry {
- };
- #define NAME_ENTRY_SIZE sizeof(struct name_cache_entry)
- -static int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs);
- +/*
- + * FIXME: We use a thread-local variable |name_cmp| here because we do not know
- + * an (easy) way to do a |RB_GENERATE()| with two diffrent name comparisation
- + * functions (|name_cmp_case_sensitive()| and |name_cmp_case_insensitive()|)
- + */
- +__declspec(thread) static
- +int (*name_cmp)(struct name_cache_entry *, struct name_cache_entry *) = NULL;
- RB_GENERATE(name_tree, name_cache_entry, rbnode, name_cmp)
- @@ -545,7 +551,6 @@ struct nfs41_name_cache {
- uint32_t delegations;
- uint32_t max_delegations;
- SRWLOCK lock;
- - bool casesensitivesearch;
- UCollator *icu_coll;
- };
- @@ -579,7 +584,8 @@ int icu_strcmpcoll(UCollator *coll, const char *str1, const char *str2, int32_t
- }
- static
- -int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs)
- +int name_cmp_case_sensitive(
- + struct name_cache_entry *lhs, struct name_cache_entry *rhs)
- {
- const int diff = rhs->component_len - lhs->component_len;
- int res;
- @@ -589,43 +595,65 @@ int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs)
- unsigned short clen = lhs->component_len;
- - if (lhs->name_cache->casesensitivesearch) {
- - /* FIXME: Can we use |memcmp()| here ? */
- - res = strncmp(lhs->component, rhs->component, clen);
- - }
- - else {
- - res = icu_strcmpcoll(lhs->name_cache->icu_coll,
- - lhs->component, rhs->component, (int32_t)clen);
- + /* FIXME: Can we use |memcmp()| here ? */
- + res = strncmp(lhs->component, rhs->component, clen);
- +
- + return res;
- +}
- +
- +static
- +int name_cmp_case_insensitive(
- + struct name_cache_entry *lhs, struct name_cache_entry *rhs)
- +{
- + const int diff = rhs->component_len - lhs->component_len;
- + int res;
- +
- + if (diff != 0)
- + return diff;
- +
- + unsigned short clen = lhs->component_len;
- +
- + res = icu_strcmpcoll(lhs->name_cache->icu_coll,
- + lhs->component, rhs->component, (int32_t)clen);
- //#define DEBUG_CASEINSENSITIVE_NAMECMP 1
- #ifdef DEBUG_CASEINSENSITIVE_NAMECMP
- - int casesensitive_res;
- -
- - /* FIXME: Can we use |memcmp()| here ? */
- - casesensitive_res = strncmp(lhs->component, rhs->component,
- - clen);
- -
- - if (res != casesensitive_res) {
- - /*
- - * Explicitly call |clen| "byte_clen" in the output to make sure
- - * people do not get confused, e.g. if |<Ae><ae>| has the same
- - * terminal character width as "dir1
- - */
- - DPRINTF(0,
- - ("name_cmp: "
- - "(lhs='%.*s',rhs='%.*s',byte_clen=%d), "
- - "res(=%d) != casesensitive_res(=%d)\n",
- - (int)clen, lhs->component,
- - (int)clen, rhs->component,
- - (int)clen,
- - res, casesensitive_res));
- - }
- -#endif /* DEBUG_CASEINSENSITIVE_NAMECMP */
- + int casesensitive_res;
- +
- + /* FIXME: Can we use |memcmp()| here ? */
- + casesensitive_res = strncmp(lhs->component, rhs->component,
- + clen);
- +
- + if (res != casesensitive_res) {
- + /*
- + * Explicitly call |clen| "byte_clen" in the output to make sure
- + * people do not get confused, e.g. if |<Ae><ae>| has the same
- + * terminal character width as "dir1
- + */
- + DPRINTF(0,
- + ("name_cmp: "
- + "(lhs='%.*s',rhs='%.*s',byte_clen=%d), "
- + "res(=%d) != casesensitive_res(=%d)\n",
- + (int)clen, lhs->component,
- + (int)clen, rhs->component,
- + (int)clen,
- + res, casesensitive_res));
- }
- +#endif /* DEBUG_CASEINSENSITIVE_NAMECMP */
- return res;
- }
- +#define NC_SET_NAMECMP(ciss) \
- + { name_cmp = (ciss)?name_cmp_case_insensitive:name_cmp_case_sensitive; }
- +#define NC_CLEAR_NAMECMP() \
- + { \
- + name_cmp = \
- + (int (*)(struct name_cache_entry *, struct name_cache_entry *))NULL; \
- + }
- +
- +
- +
- /* internal name cache functions used by the public name cache interface;
- * these functions expect the caller to hold a lock on the cache */
- @@ -1004,13 +1032,6 @@ int nfs41_name_cache_create(
- goto out;
- }
- - /*
- - * We need to set this to the real value later, once we have the value
- - * of the |FATTR4_WORD0_CASE_INSENSITIVE| attribute...
- - * FIXME: This is suboptimal...
- - */
- - cache->casesensitivesearch = false;
- -
- UErrorCode xstatus = U_ZERO_ERROR;
- cache->icu_coll = ucol_open("en_US", &xstatus);
- if (U_FAILURE(xstatus)) {
- @@ -1086,16 +1107,6 @@ int nfs41_name_cache_free(
- return status;
- }
- -void nfs41_name_cache_set_casesensitivesearch(
- - IN struct nfs41_name_cache *cache,
- - IN bool casesensitivesearch)
- -{
- - cache->casesensitivesearch = casesensitivesearch;
- - DPRINTF(1,
- - ("nfs41_name_cache_set_casesensitivesearch: casesensitivesearch=%d\n",
- - (int)casesensitivesearch));
- -}
- -
- static __inline void copy_fh(
- OUT nfs41_fh *dst,
- IN OPTIONAL const struct name_cache_entry *src)
- @@ -1108,6 +1119,7 @@ static __inline void copy_fh(
- int nfs41_name_cache_lookup(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *path,
- IN const char *path_end,
- OUT OPTIONAL const char **remaining_path_out,
- @@ -1120,6 +1132,8 @@ int nfs41_name_cache_lookup(
- const char *path_pos = path;
- int status;
- + NC_SET_NAMECMP(caseinsensitivesearch);
- +
- AcquireSRWLockShared(&cache->lock);
- if (!name_cache_enabled(cache)) {
- @@ -1137,6 +1151,7 @@ int nfs41_name_cache_lookup(
- out_unlock:
- ReleaseSRWLockShared(&cache->lock);
- + NC_CLEAR_NAMECMP();
- if (remaining_path_out) *remaining_path_out = path_pos;
- return status;
- }
- @@ -1151,6 +1166,9 @@ int nfs41_attr_cache_lookup(
- DPRINTF(NCLVL1, ("--> nfs41_attr_cache_lookup(%llu)\n", fileid));
- + /* No name argument, so no lookups by name */
- + NC_CLEAR_NAMECMP();
- +
- AcquireSRWLockShared(&cache->lock);
- if (!name_cache_enabled(cache)) {
- @@ -1183,6 +1201,9 @@ int nfs41_attr_cache_update(
- DPRINTF(NCLVL1, ("--> nfs41_attr_cache_update(%llu)\n", fileid));
- + /* No name argument, so no lookups by name */
- + NC_CLEAR_NAMECMP();
- +
- AcquireSRWLockExclusive(&cache->lock);
- if (!name_cache_enabled(cache)) {
- @@ -1207,6 +1228,7 @@ out_unlock:
- int nfs41_name_cache_insert(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *path,
- IN const nfs41_component *name,
- IN OPTIONAL const nfs41_fh *fh,
- @@ -1220,6 +1242,8 @@ int nfs41_name_cache_insert(
- DPRINTF(NCLVL1, ("--> nfs41_name_cache_insert('%.*s')\n",
- name->name + name->len - path, path));
- + NC_SET_NAMECMP(caseinsensitivesearch);
- +
- AcquireSRWLockExclusive(&cache->lock);
- if (!name_cache_enabled(cache)) {
- @@ -1268,6 +1292,7 @@ int nfs41_name_cache_insert(
- out_unlock:
- ReleaseSRWLockExclusive(&cache->lock);
- + NC_CLEAR_NAMECMP();
- DPRINTF(NCLVL1, ("<-- nfs41_name_cache_insert() returning %d\n",
- status));
- @@ -1296,6 +1321,7 @@ out_err_deleg:
- int nfs41_name_cache_delegreturn(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN uint64_t fileid,
- IN const char *path,
- IN const nfs41_component *name)
- @@ -1307,6 +1333,8 @@ int nfs41_name_cache_delegreturn(
- DPRINTF(NCLVL1, ("--> nfs41_name_cache_delegreturn(%llu, '%s')\n",
- fileid, path));
- + NC_SET_NAMECMP(caseinsensitivesearch);
- +
- AcquireSRWLockExclusive(&cache->lock);
- if (!name_cache_enabled(cache)) {
- @@ -1343,6 +1371,7 @@ int nfs41_name_cache_delegreturn(
- out_unlock:
- ReleaseSRWLockExclusive(&cache->lock);
- + NC_CLEAR_NAMECMP();
- DPRINTF(NCLVL1, ("<-- nfs41_name_cache_delegreturn() returning %d\n", status));
- return status;
- @@ -1350,6 +1379,7 @@ out_unlock:
- int nfs41_name_cache_remove(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *path,
- IN const nfs41_component *name,
- IN uint64_t fileid,
- @@ -1361,6 +1391,8 @@ int nfs41_name_cache_remove(
- DPRINTF(NCLVL1, ("--> nfs41_name_cache_remove('%s')\n", path));
- + NC_SET_NAMECMP(caseinsensitivesearch);
- +
- AcquireSRWLockExclusive(&cache->lock);
- if (!name_cache_enabled(cache)) {
- @@ -1390,6 +1422,7 @@ int nfs41_name_cache_remove(
- out_unlock:
- ReleaseSRWLockExclusive(&cache->lock);
- + NC_CLEAR_NAMECMP();
- DPRINTF(NCLVL1, ("<-- nfs41_name_cache_remove() returning %d\n", status));
- return status;
- @@ -1406,6 +1439,7 @@ out_attributes:
- int nfs41_name_cache_rename(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *src_path,
- IN const nfs41_component *src_name,
- IN const change_info4 *src_cinfo,
- @@ -1420,6 +1454,8 @@ int nfs41_name_cache_rename(
- DPRINTF(NCLVL1, ("--> nfs41_name_cache_rename('%s' to '%s')\n",
- src_path, dst_path));
- + NC_SET_NAMECMP(caseinsensitivesearch);
- +
- AcquireSRWLockExclusive(&cache->lock);
- if (!name_cache_enabled(cache)) {
- @@ -1506,6 +1542,7 @@ int nfs41_name_cache_rename(
- out_unlock:
- ReleaseSRWLockExclusive(&cache->lock);
- + NC_CLEAR_NAMECMP();
- DPRINTF(NCLVL1, ("<-- nfs41_name_cache_rename() returning %d\n", status));
- return status;
- @@ -1659,6 +1696,7 @@ static __inline uint32_t max_putfh_components(
- int nfs41_name_cache_remove_stale(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN nfs41_session *session,
- IN nfs41_abs_path *path)
- {
- @@ -1669,6 +1707,8 @@ int nfs41_name_cache_remove_stale(
- uint32_t count, index;
- int status = NO_ERROR;
- + NC_SET_NAMECMP(caseinsensitivesearch);
- +
- AcquireSRWLockShared(&cache->lock);
- /* if there's no cache, don't check any components */
- @@ -1695,6 +1735,7 @@ int nfs41_name_cache_remove_stale(
- }
- ReleaseSRWLockShared(&path->lock);
- + NC_CLEAR_NAMECMP();
- return status;
- }
- \ No newline at end of file
- diff --git a/daemon/name_cache.h b/daemon/name_cache.h
- index 8bc5b78..3950983 100644
- --- a/daemon/name_cache.h
- +++ b/daemon/name_cache.h
- @@ -56,15 +56,12 @@ int nfs41_attr_cache_update(
- int nfs41_name_cache_create(
- OUT struct nfs41_name_cache **cache_out);
- -void nfs41_name_cache_set_casesensitivesearch(
- - IN struct nfs41_name_cache *cache,
- - IN bool casesensitivesearch);
- -
- int nfs41_name_cache_free(
- IN OUT struct nfs41_name_cache **cache_out);
- int nfs41_name_cache_lookup(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *path,
- IN const char *path_end,
- OUT OPTIONAL const char **remaining_path_out,
- @@ -75,6 +72,7 @@ int nfs41_name_cache_lookup(
- int nfs41_name_cache_insert(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *path,
- IN const nfs41_component *name,
- IN OPTIONAL const nfs41_fh *fh,
- @@ -84,12 +82,14 @@ int nfs41_name_cache_insert(
- int nfs41_name_cache_delegreturn(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN uint64_t fileid,
- IN const char *path,
- IN const nfs41_component *name);
- int nfs41_name_cache_remove(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *path,
- IN const nfs41_component *name,
- IN uint64_t fileid,
- @@ -97,6 +97,7 @@ int nfs41_name_cache_remove(
- int nfs41_name_cache_rename(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN const char *src_path,
- IN const nfs41_component *src_name,
- IN const change_info4 *src_cinfo,
- @@ -106,6 +107,7 @@ int nfs41_name_cache_rename(
- int nfs41_name_cache_remove_stale(
- IN struct nfs41_name_cache *cache,
- + IN bool caseinsensitivesearch,
- IN nfs41_session *session,
- IN nfs41_abs_path *path);
- diff --git a/daemon/nfs41_compound.c b/daemon/nfs41_compound.c
- index 25d2449..4d3b49e 100644
- --- a/daemon/nfs41_compound.c
- +++ b/daemon/nfs41_compound.c
- @@ -371,9 +371,12 @@ retry:
- if (argarray[i].op == OP_PUTFH) {
- putfh = (nfs41_putfh_args*)argarray[i].arg;
- - if (!putfh->in_recovery && putfh->file->path)
- + if (!putfh->in_recovery && putfh->file->path) {
- nfs41_name_cache_remove_stale(name_cache,
- + BIT2BOOL(
- + putfh->file->fh.superblock->case_insensitive),
- session, putfh->file->path);
- + }
- }
- }
- }
- diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c
- index 7c017b2..9012db4 100644
- --- a/daemon/nfs41_ops.c
- +++ b/daemon/nfs41_ops.c
- @@ -412,7 +412,9 @@ static void open_update_cache(
- bitmap4_cpy(&file_attrs->info->attrmask, &file_attrs->obj_attributes.attrmask);
- retry_cache_insert:
- AcquireSRWLockShared(&file->path->lock);
- - status = nfs41_name_cache_insert(cache, file->path->path, &file->name,
- + status = nfs41_name_cache_insert(cache,
- + BIT2BOOL(parent->fh.superblock->case_insensitive),
- + file->path->path, &file->name,
- &file->fh, file_attrs->info, changeinfo,
- already_delegated ? OPEN_DELEGATE_NONE : delegation->type);
- ReleaseSRWLockShared(&file->path->lock);
- @@ -688,6 +690,7 @@ int nfs41_create(
- bitmap4_cpy(&info->attrmask, &getattr_res.obj_attributes.attrmask);
- AcquireSRWLockShared(&file->path->lock);
- nfs41_name_cache_insert(session_name_cache(session),
- + BIT2BOOL(parent->fh.superblock->case_insensitive),
- file->path->path, &file->name, &file->fh,
- info, &create_res.cinfo, OPEN_DELEGATE_NONE);
- ReleaseSRWLockShared(&file->path->lock);
- @@ -1331,6 +1334,7 @@ int nfs41_remove(
- /* remove the target file from the cache */
- AcquireSRWLockShared(&parent->path->lock);
- nfs41_name_cache_remove(session_name_cache(session),
- + BIT2BOOL(parent->fh.superblock->case_insensitive),
- parent->path->path, target, fileid, &remove_res.cinfo);
- ReleaseSRWLockShared(&parent->path->lock);
- @@ -1429,6 +1433,7 @@ int nfs41_rename(
- /* move/rename the target file's name cache entry */
- nfs41_name_cache_rename(session_name_cache(session),
- + BIT2BOOL(src_dir->fh.superblock->case_insensitive),
- src_dir->path->path, src_name, &rename_res.source_cinfo,
- dst_dir->path->path, dst_name, &rename_res.target_cinfo);
- @@ -1623,6 +1628,7 @@ int nfs41_link(
- bitmap4_cpy(&cinfo->attrmask, &getattr_res[1].obj_attributes.attrmask);
- AcquireSRWLockShared(&dst_dir->path->lock);
- nfs41_name_cache_insert(session_name_cache(session),
- + BIT2BOOL(dst_dir->fh.superblock->case_insensitive),
- dst_dir->path->path, target, &file.fh,
- cinfo, &link_res.cinfo, OPEN_DELEGATE_NONE);
- ReleaseSRWLockShared(&dst_dir->path->lock);
- @@ -1858,6 +1864,7 @@ int nfs41_delegreturn(
- AcquireSRWLockShared(&file->path->lock);
- nfs41_name_cache_delegreturn(session_name_cache(session),
- + BIT2BOOL(file->fh.superblock->case_insensitive),
- file->fh.fileid, file->path->path, &file->name);
- ReleaseSRWLockShared(&file->path->lock);
- out:
- diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h
- index 8f2b022..b3b70fb 100644
- --- a/daemon/nfs41_ops.h
- +++ b/daemon/nfs41_ops.h
- @@ -1222,6 +1222,7 @@ enum nfsstat4 nfs41_reclaim_complete(
- int nfs41_lookup(
- IN nfs41_root *root,
- IN nfs41_session *session,
- + IN bool casesensitive,
- IN OUT nfs41_abs_path *path,
- OUT OPTIONAL nfs41_path_fh *parent_out,
- OUT OPTIONAL nfs41_path_fh *target_out,
- diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
- index 84d06db..c0141f0 100644
- --- a/daemon/nfs41_superblock.c
- +++ b/daemon/nfs41_superblock.c
- @@ -132,8 +132,7 @@ static int get_superblock_attrs(
- superblock->case_preserving = info.case_preserving;
- }
- else {
- - superblock->case_preserving =
- - root->force_case_preserving?1:0;
- + superblock->case_preserving = BOOL2BIT(root->force_case_preserving);
- DPRINTF(0,
- ("get_superblock_attrs: OVERRIDING case_preserving to %d\n",
- (int)superblock->case_preserving));
- @@ -142,8 +141,7 @@ static int get_superblock_attrs(
- superblock->case_insensitive = info.case_insensitive;
- }
- else {
- - superblock->case_insensitive =
- - root->force_case_insensitive?1:0;
- + superblock->case_insensitive = BOOL2BIT(root->force_case_insensitive);
- DPRINTF(0,
- ("get_superblock_attrs: OVERRIDING case_insensitive to %d\n",
- (int)superblock->case_insensitive));
- @@ -161,10 +159,6 @@ static int get_superblock_attrs(
- superblock->block_clone_support = 0;
- }
- - nfs41_name_cache_set_casesensitivesearch(
- - session->client->server->name_cache,
- - superblock->case_insensitive?false:true);
- -
- if (bitmap_isset(&info.attrmask, 0, FATTR4_WORD0_CANSETTIME))
- superblock->cansettime = info.cansettime;
- else /* cansettime is not supported, try setting them anyway */
- @@ -257,8 +251,9 @@ static int get_superblock_attrs(
- superblock->layout_types, superblock->cansettime,
- superblock->time_delta.seconds, superblock->time_delta.nseconds,
- superblock->aclsupport, superblock->link_support,
- - superblock->symlink_support, superblock->case_preserving,
- - superblock->case_insensitive,
- + superblock->symlink_support,
- + (int)superblock->case_preserving,
- + (int)superblock->case_insensitive,
- superblock->sparse_file_support,
- superblock->block_clone_support));
- out:
- @@ -327,8 +322,8 @@ void nfs41_superblock_fs_attributes(
- superblock->link_support,
- superblock->symlink_support,
- superblock->ea_support,
- - superblock->case_preserving,
- - superblock->case_insensitive,
- + (int)superblock->case_preserving,
- + (int)superblock->case_insensitive,
- superblock->aclsupport,
- (unsigned int)FsAttrs->MaximumComponentNameLength,
- (unsigned long)FsAttrs->FileSystemAttributes));
- diff --git a/daemon/open.c b/daemon/open.c
- index 43f753c..593452c 100644
- --- a/daemon/open.c
- +++ b/daemon/open.c
- @@ -317,6 +317,10 @@ static int parse_open(unsigned char *buffer, uint32_t length, nfs41_upcall *upca
- status = get_name(&buffer, &length, &args->path);
- if (status) goto out;
- +
- + status = safe_read(&buffer, &length, &args->is_caseinsensitive_volume,
- + sizeof(tristate_bool));
- + if (status) goto out;
- status = safe_read(&buffer, &length, &args->isvolumemntpt, sizeof(BOOLEAN));
- if (status) goto out;
- status = safe_read(&buffer, &length, &args->access_mask, sizeof(ULONG));
- @@ -737,6 +741,25 @@ static int handle_open(void *daemon_context, nfs41_upcall *upcall)
- open_upcall_args *args = &upcall->args.open;
- nfs41_open_state *state;
- nfs41_file_info info = { 0 };
- + bool is_caseinsensitive_volume;
- +
- + switch (args->is_caseinsensitive_volume) {
- + case TRISTATE_BOOL_FALSE:
- + is_caseinsensitive_volume = false;
- + break;
- + case TRISTATE_BOOL_TRUE:
- + is_caseinsensitive_volume = true;
- + break;
- + default:
- + eprintf("handle_open(args->path='%s'): "
- + "Invalid args->is_caseinsensitive_volume=%d value\n",
- + args->path, (int)args->is_caseinsensitive_volume);
- + /* fall-through */
- + case TRISTATE_BOOL_NOT_SET:
- + /* We default to case-sensitive mode */
- + is_caseinsensitive_volume = false;
- + break;
- + }
- EASSERT_MSG(!(args->create_opts & FILE_COMPLETE_IF_OPLOCKED),
- ("handle_open: file='%s': "
- @@ -776,7 +799,8 @@ static int handle_open(void *daemon_context, nfs41_upcall *upcall)
- // always do a lookup
- status = nfs41_lookup(upcall->root_ref, nfs41_root_session(upcall->root_ref),
- - &state->path, &state->parent, &state->file, &info, &state->session);
- + is_caseinsensitive_volume, &state->path,
- + &state->parent, &state->file, &info, &state->session);
- if (status == ERROR_REPARSE) {
- uint32_t depth = 0;
- @@ -802,7 +826,8 @@ static int handle_open(void *daemon_context, nfs41_upcall *upcall)
- /* redo the lookup until it doesn't return REPARSE */
- status = nfs41_lookup(upcall->root_ref, state->session,
- - &state->path, &state->parent, NULL, NULL, &state->session);
- + is_caseinsensitive_volume, &state->path,
- + &state->parent, NULL, NULL, &state->session);
- } while (status == ERROR_REPARSE);
- if (status == NO_ERROR || status == ERROR_FILE_NOT_FOUND) {
- diff --git a/daemon/readdir.c b/daemon/readdir.c
- index f809c9d..0e35421 100644
- --- a/daemon/readdir.c
- +++ b/daemon/readdir.c
- @@ -499,8 +499,9 @@ static int lookup_entry(
- status = format_abs_path(parent->path, &name, &path);
- if (status) goto out;
- - status = nfs41_lookup(root, session, &path,
- - NULL, NULL, &entry->attr_info, NULL);
- + status = nfs41_lookup(root, session,
- + BIT2BOOL(parent->fh.superblock->case_insensitive),
- + &path, NULL, NULL, &entry->attr_info, NULL);
- if (status) goto out;
- out:
- return status;
- @@ -522,7 +523,9 @@ static int lookup_symlink(
- if (status) goto out;
- file.path = &path;
- - status = nfs41_lookup(root, session, &path, NULL, &file, &info, &session);
- + status = nfs41_lookup(root, session,
- + BIT2BOOL(parent->fh.superblock->case_insensitive),
- + &path, NULL, &file, &info, &session);
- if (status) goto out;
- last_component(path.path, path.path + path.len, &file.name);
- diff --git a/daemon/setattr.c b/daemon/setattr.c
- index a47918e..db45478 100644
- --- a/daemon/setattr.c
- +++ b/daemon/setattr.c
- @@ -413,6 +413,7 @@ static int handle_nfs41_rename(void *daemon_context, setattr_upcall_args *args)
- /* the destination path is absolute, so start from the root session */
- status = nfs41_lookup(args->root, nfs41_root_session(args->root),
- + BIT2BOOL(state->file.fh.superblock->case_insensitive),
- &dst_path, &dst_dir, &dst, NULL, &dst_session);
- while (status == ERROR_REPARSE) {
- @@ -431,6 +432,7 @@ static int handle_nfs41_rename(void *daemon_context, setattr_upcall_args *args)
- /* redo the lookup until it doesn't return REPARSE */
- status = nfs41_lookup(args->root, dst_session,
- + BIT2BOOL(state->file.fh.superblock->case_insensitive),
- &dst_path, &dst_dir, NULL, NULL, &dst_session);
- }
- @@ -591,6 +593,7 @@ static int handle_nfs41_link(void *daemon_context, setattr_upcall_args *args)
- /* the destination path is absolute, so start from the root session */
- status = nfs41_lookup(args->root, nfs41_root_session(args->root),
- + BIT2BOOL(state->file.fh.superblock->case_insensitive),
- &dst_path, &dst_dir, &dst, NULL, &dst_session);
- while (status == ERROR_REPARSE) {
- @@ -609,6 +612,7 @@ static int handle_nfs41_link(void *daemon_context, setattr_upcall_args *args)
- /* redo the lookup until it doesn't return REPARSE */
- status = nfs41_lookup(args->root, dst_session,
- + BIT2BOOL(state->file.fh.superblock->case_insensitive),
- &dst_path, &dst_dir, &dst, NULL, &dst_session);
- }
- diff --git a/daemon/symlink.c b/daemon/symlink.c
- index 09cb07d..0537380 100644
- --- a/daemon/symlink.c
- +++ b/daemon/symlink.c
- @@ -222,8 +222,9 @@ int nfs41_symlink_follow(
- last_component(path.path, path.path + path.len, &file.name);
- /* get attributes for the target */
- - status = nfs41_lookup(root, session, &path,
- - NULL, &file, info, &session);
- + status = nfs41_lookup(root, session,
- + BIT2BOOL(symlink->fh.superblock->case_insensitive),
- + &path, NULL, &file, info, &session);
- if (status) goto out;
- symlink = &file;
- diff --git a/daemon/upcall.h b/daemon/upcall.h
- index 8e099bc..b16719b 100644
- --- a/daemon/upcall.h
- +++ b/daemon/upcall.h
- @@ -55,6 +55,7 @@ typedef struct __open_upcall_args {
- ULONGLONG fileid;
- ULONGLONG fsid_major, fsid_minor;
- const char *path;
- + tristate_bool is_caseinsensitive_volume;
- BOOLEAN isvolumemntpt;
- ULONG access_mask;
- ULONG access_mode;
- diff --git a/daemon/util.h b/daemon/util.h
- index b936ac4..6a7f458 100644
- --- a/daemon/util.h
- +++ b/daemon/util.h
- @@ -39,6 +39,12 @@ typedef struct __nfs41_file_info nfs41_file_info;
- typedef struct __nfs41_superblock nfs41_superblock;
- enum stable_how4;
- +/*
- + * Turn |unsigned int foo:1| from/to |bool|
- + */
- +#define BIT2BOOL(bit) ((bit)?true:false)
- +#define BOOL2BIT(b) ((b)?1U:0U)
- +
- /*
- * UTIL_GETRELTIME - Get a relative time stamp
- * |GetTickCount64()| is almost twice as fast as |time()|, and
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index df26e64..95f4c8c 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -227,6 +227,7 @@ typedef struct _updowncall_entry {
- ULONGLONG fileid;
- ULONGLONG fsid_major, fsid_minor;
- UNICODE_STRING symlink;
- + tristate_bool is_caseinsensitive_volume;
- BOOLEAN isvolumemntpt;
- ULONG access_mask;
- ULONG access_mode;
- diff --git a/sys/nfs41sys_openclose.c b/sys/nfs41sys_openclose.c
- index 2833d1f..86bc604 100644
- --- a/sys/nfs41sys_openclose.c
- +++ b/sys/nfs41sys_openclose.c
- @@ -119,6 +119,7 @@ NTSTATUS marshal_nfs41_open(
- else tmp += *len;
- header_len = *len + length_as_utf8(entry->filename) +
- + 1 * sizeof(tristate_bool) +
- 7 * sizeof(ULONG) +
- 1 * sizeof(BOOLEAN) +
- 2 * sizeof(HANDLE) +
- @@ -129,6 +130,9 @@ NTSTATUS marshal_nfs41_open(
- }
- status = marshall_unicode_as_utf8(&tmp, entry->filename);
- if (status) goto out;
- + RtlCopyMemory(tmp, &entry->u.Open.is_caseinsensitive_volume,
- + sizeof(entry->u.Open.is_caseinsensitive_volume));
- + tmp += sizeof(entry->u.Open.is_caseinsensitive_volume);
- RtlCopyMemory(tmp, &entry->u.Open.isvolumemntpt,
- sizeof(entry->u.Open.isvolumemntpt));
- tmp += sizeof(entry->u.Open.isvolumemntpt);
- @@ -632,6 +636,19 @@ NTSTATUS nfs41_Create(
- SrvOpen->pAlreadyPrefixedName, &entry);
- if (status) goto out;
- + entry->u.Open.is_caseinsensitive_volume = TRISTATE_BOOL_NOT_SET;
- + ULONG fsattrs = pVNetRootContext->FsAttrs.FileSystemAttributes;
- + /*
- + * Only set |entry->u.Open.is_caseinsensitive_volume| to |TRUE|/|FALSE|
- + * if we got any attributes from the superblock yet...
- + */
- + if (fsattrs) {
- + if (fsattrs & FILE_CASE_SENSITIVE_SEARCH)
- + entry->u.Open.is_caseinsensitive_volume = TRISTATE_BOOL_FALSE;
- + else
- + entry->u.Open.is_caseinsensitive_volume = TRISTATE_BOOL_TRUE;
- + }
- +
- /* Check whether this is the mount point for this volume */
- entry->u.Open.isvolumemntpt =
- isFileNameTheVolumeMountPoint(SrvOpen->pAlreadyPrefixedName,
- --
- 2.51.0
- From a783b3d654b8b1c8ca9dec40da458953166786cc Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 17 Sep 2025 15:32:09 +0200
- Subject: [PATCH 07/10] daemon: Name cache should use C99 |bool|, not |bool_t|
- Name cache should use C99 |bool|, not |bool_t|, so that the
- compilers+linters can recognise this as boolean.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/lookup.c | 6 +++---
- daemon/name_cache.c | 16 ++++++++--------
- daemon/name_cache.h | 2 +-
- 3 files changed, 12 insertions(+), 12 deletions(-)
- diff --git a/daemon/lookup.c b/daemon/lookup.c
- index dfff849..27f8383 100644
- --- a/daemon/lookup.c
- +++ b/daemon/lookup.c
- @@ -177,7 +177,7 @@ out:
- return status;
- }
- -static int map_lookup_error(int status, bool_t last_component)
- +static int map_lookup_error(int status, bool last_component)
- {
- switch (status) {
- case NFS4ERR_NOENT:
- @@ -302,7 +302,7 @@ static int server_lookup(
- }
- }
- out:
- - return map_lookup_error(status, i == count-1);
- + return map_lookup_error(status, ((i == count-1)?true:false));
- }
- static uint32_t max_lookup_components(
- @@ -480,7 +480,7 @@ int nfs41_lookup(
- nfs41_path_fh parent = { 0 }, target = { 0 }, *server_start;
- const char *path_pos, *path_end;
- struct lookup_referral referral = { 0 };
- - bool_t negative = 0;
- + bool negative = false;
- int status;
- if (session_out) *session_out = session;
- diff --git a/daemon/name_cache.c b/daemon/name_cache.c
- index 1351a58..32851a9 100644
- --- a/daemon/name_cache.c
- +++ b/daemon/name_cache.c
- @@ -71,7 +71,7 @@ enum {
- * ERROR_TOO_MANY_OPEN_FILES, chosen arbitrarily for this case, instructs the
- * caller to return an outstanding delegation before caching a new one.
- */
- -static __inline bool_t is_delegation(
- +static __inline bool is_delegation(
- IN enum open_delegation_type4 type)
- {
- return type == OPEN_DELEGATE_READ || type == OPEN_DELEGATE_WRITE;
- @@ -659,7 +659,7 @@ int name_cmp_case_insensitive(
- #define name_entry(pos) list_container(pos, struct name_cache_entry, exp_entry)
- -static __inline bool_t name_cache_enabled(
- +static __inline bool name_cache_enabled(
- IN struct nfs41_name_cache *cache)
- {
- return cache->expiration > 0;
- @@ -890,7 +890,7 @@ static struct name_cache_entry* name_cache_search(
- static int entry_invis(
- IN struct name_cache_entry *entry,
- - OUT OPTIONAL bool_t *is_negative)
- + OUT OPTIONAL bool *is_negative)
- {
- /* name entry timer expired? */
- if (!list_empty(&entry->exp_entry) && (UTIL_GETRELTIME() > entry->expiration)) {
- @@ -899,7 +899,7 @@ static int entry_invis(
- }
- /* negative lookup entry? */
- if (entry->attributes == NULL) {
- - if (is_negative) *is_negative = 1;
- + if (is_negative) *is_negative = true;
- DPRINTF(NCLVL2, ("name_entry_negative('%s')\n", entry->component));
- return 1;
- }
- @@ -914,13 +914,13 @@ static int entry_invis(
- static int name_cache_lookup(
- IN struct nfs41_name_cache *cache,
- - IN bool_t skip_invis,
- + IN bool skip_invis,
- IN const char *path,
- IN const char *path_end,
- OUT OPTIONAL const char **remaining_path_out,
- OUT OPTIONAL struct name_cache_entry **parent_out,
- OUT OPTIONAL struct name_cache_entry **target_out,
- - OUT OPTIONAL bool_t *is_negative)
- + OUT OPTIONAL bool *is_negative)
- {
- struct name_cache_entry *parent, *target;
- nfs41_component component;
- @@ -1126,7 +1126,7 @@ int nfs41_name_cache_lookup(
- OUT OPTIONAL nfs41_fh *parent_out,
- OUT OPTIONAL nfs41_fh *target_out,
- OUT OPTIONAL nfs41_file_info *info_out,
- - OUT OPTIONAL bool_t *is_negative)
- + OUT OPTIONAL bool *is_negative)
- {
- struct name_cache_entry *parent, *target;
- const char *path_pos = path;
- @@ -1567,7 +1567,7 @@ out_unlock:
- */
- #define MAX_PUTFH_PER_COMPOUND 64
- -static bool_t get_path_fhs(
- +static bool get_path_fhs(
- IN struct nfs41_name_cache *cache,
- IN nfs41_abs_path *path,
- IN OUT const char **path_pos,
- diff --git a/daemon/name_cache.h b/daemon/name_cache.h
- index 3950983..3d79137 100644
- --- a/daemon/name_cache.h
- +++ b/daemon/name_cache.h
- @@ -68,7 +68,7 @@ int nfs41_name_cache_lookup(
- OUT OPTIONAL nfs41_fh *parent_out,
- OUT OPTIONAL nfs41_fh *target_out,
- OUT OPTIONAL nfs41_file_info *info_out,
- - OUT OPTIONAL bool_t *is_negative);
- + OUT OPTIONAL bool *is_negative);
- int nfs41_name_cache_insert(
- IN struct nfs41_name_cache *cache,
- --
- 2.51.0
- From 97675e5c3d869f9f9133aafa4210a6fdd28bae7f Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 17 Sep 2025 16:07:07 +0200
- Subject: [PATCH 08/10] daemon: superblock+mount admin info logging should
- include the NFS fsid
- superblock+mount admin info logging should include the NFS fsid.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/mount.c | 14 +++++++++-----
- daemon/nfs41_superblock.c | 14 ++++++++++----
- 2 files changed, 19 insertions(+), 9 deletions(-)
- diff --git a/daemon/mount.c b/daemon/mount.c
- index d1f2e9e..3864b4a 100644
- --- a/daemon/mount.c
- +++ b/daemon/mount.c
- @@ -99,7 +99,7 @@ static int handle_mount(void *daemon_context, nfs41_upcall *upcall)
- multi_addr4 addrs = { 0 };
- nfs41_root *root = NULL;
- nfs41_client *client;
- - nfs41_path_fh file;
- + nfs41_path_fh file = { 0 };
- #ifdef NFS41_DRIVER_USE_AUTHENTICATIONID_FOR_MOUNT_NAMESPACE
- LUID authenticationid = { .LowPart = 0, .HighPart = 0L };
- #endif /* NFS41_DRIVER_USE_AUTHENTICATIONID_FOR_MOUNT_NAMESPACE */
- @@ -258,7 +258,8 @@ out:
- if (status == 0) {
- #ifdef NFS41_DRIVER_USE_AUTHENTICATIONID_FOR_MOUNT_NAMESPACE
- logprintf("mount(hostport='%s', use_nfspubfh=%d, %s='%s', "
- - "authid=(0x%lx.0x%lx)) success, root=0x%p, NFS version=4.%d\n",
- + "authid=(0x%lx.0x%lx)) success, root=0x%p, "
- + "NFS version=4.%d, NFS fsid=(%llu,%llu)\n",
- args->hostport?args->hostport:"<NULL>",
- (int)args->use_nfspubfh,
- (args->use_nfspubfh?"relative_path":"path"),
- @@ -266,16 +267,19 @@ out:
- (long)authenticationid.HighPart,
- (long)authenticationid.LowPart,
- root,
- - (int)root->nfsminorvers);
- + (int)root->nfsminorvers,
- + file.fh.superblock->fsid.major, file.fh.superblock->fsid.minor);
- #else
- logprintf("mount(hostport='%s', use_nfspubfh=%d, %s='%s') success, "
- - "root=0x%p, NFS version=4.%d\n",
- + "root=0x%p, "
- + "NFS version=4.%d, NFS fsid=(%llu,%llu)\n",
- args->hostport?args->hostport:"<NULL>",
- (int)args->use_nfspubfh,
- (args->use_nfspubfh?"relative_path":"path"),
- args->path?args->path:"<NULL>",
- root,
- - (int)root->nfsminorvers);
- + (int)root->nfsminorvers,
- + file.fh.superblock->fsid.major, file.fh.superblock->fsid.minor);
- #endif /* NFS41_DRIVER_USE_AUTHENTICATIONID_FOR_MOUNT_NAMESPACE */
- }
- else {
- diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
- index c0141f0..8777feb 100644
- --- a/daemon/nfs41_superblock.c
- +++ b/daemon/nfs41_superblock.c
- @@ -207,11 +207,15 @@ static int get_superblock_attrs(
- is = stpcpy(is, "SACL");
- }
- - logprintf("get_superblock_attrs: Supported ACL types: { %s }\n",
- + logprintf("get_superblock_attrs(fsid=(%llu,%llu)): "
- + "Supported ACL types: { %s }\n",
- + superblock->fsid.major, superblock->fsid.minor,
- infobuff);
- }
- else {
- - logprintf("get_superblock_attrs: No ACL support\n");
- + logprintf("get_superblock_attrs(fsid=(%llu,%llu)): "
- + "No ACL support\n",
- + superblock->fsid.major, superblock->fsid.minor);
- }
- /* Windows/DOS attributes */
- @@ -230,13 +234,15 @@ static int get_superblock_attrs(
- *is++ = ',';
- is = stpcpy(is, "SYSTEM");
- }
- - logprintf("get_superblock_attrs: "
- + logprintf("get_superblock_attrs(fsid=(%llu,%llu)): "
- "Supported Windows/DOS attributes: { %s }\n",
- + superblock->fsid.major, superblock->fsid.minor,
- infobuff);
- /* Filename case handling */
- - logprintf("get_superblock_attrs: "
- + logprintf("get_superblock_attrs(fsid=(%llu,%llu)): "
- "Case handling: case_insensitive=%d, case_preserving=%d\n",
- + superblock->fsid.major, superblock->fsid.minor,
- (int)superblock->case_insensitive,
- (int)superblock->case_preserving);
- --
- 2.51.0
- From ca4a15ba1a4f6bb2d41d9492e5828e2c0eab1ea5 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 17 Sep 2025 16:23:01 +0200
- Subject: [PATCH 09/10] README.md,docs: Document case-insensitive filesystem
- support
- Document case-insensitive filesystem support.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- README.md | 6 ++++++
- docs/README.xml | 9 +++++++++
- 2 files changed, 15 insertions(+)
- diff --git a/README.md b/README.md
- index 519f1f0..13098fe 100644
- --- a/README.md
- +++ b/README.md
- @@ -139,6 +139,12 @@ NFSv4.2/NFSv4.1 filesystem driver for Windows 10/11 & Windows Server
- sparse files. Requires on Win11 \>= 22H2 because it relies on
- `|CopyFile2()|` flag `|COPY_FILE_ENABLE_SPARSE_COPY|`.
- +- Case-insensitive filesystem support
- +
- + - Requires NFSv4.1 server which supports the
- + `|FATTR4_WORD0_CASE_INSENSITIVE|` attribute set to `TRUE` (currently
- + Windows Server NFSv4.1 server exporting NTFS).
- +
- - Data copy offload (server-side copy)
- - Implemented via Win32 `|FSCTL_OFFLOAD_READ|`+`|FSCTL_OFFLOAD_WRITE|`
- diff --git a/docs/README.xml b/docs/README.xml
- index 4f290a3..f64fcee 100644
- --- a/docs/README.xml
- +++ b/docs/README.xml
- @@ -141,6 +141,15 @@
- </itemizedlist>
- </para>
- </listitem>
- + <listitem>
- + <para>Case-insensitive filesystem support
- + <itemizedlist>
- + <listitem>
- + <para>Requires NFSv4.1 server which supports the <literal>|FATTR4_WORD0_CASE_INSENSITIVE|</literal> attribute set to <literal>TRUE</literal> (currently Windows Server NFSv4.1 server exporting NTFS).</para>
- + </listitem>
- + </itemizedlist>
- + </para>
- + </listitem>
- <listitem>
- <para>Data copy offload (server-side copy)
- <itemizedlist>
- --
- 2.51.0
- From 990065fe93b86f56cf9067a2bb0995b67c53b507 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 17 Sep 2025 16:42:17 +0200
- Subject: [PATCH 10/10] tests: Add notes about software compatibility
- Add notes about software compatibility.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/tests_software_compat.txt | 65 +++++++++++++++++++++++++++++++++
- 1 file changed, 65 insertions(+)
- create mode 100644 tests/tests_software_compat.txt
- diff --git a/tests/tests_software_compat.txt b/tests/tests_software_compat.txt
- new file mode 100644
- index 0000000..c9aa29a
- --- /dev/null
- +++ b/tests/tests_software_compat.txt
- @@ -0,0 +1,65 @@
- +#
- +# ms-nfs41-client software compatibility notes
- +#
- +
- +# Name: FireFox
- +# Version: FireFox 143.0b9
- +# Download URL: https://download-installer.cdn.mozilla.net/pub/firefox/releases/143.0b9/win64/de/Firefox%20Setup%20143.0b9.exe
- +# Can use NFS for data storage: yes
- +# Software can be installed on NFS: Yes, requires global-mount, requires case-insensitive filesystem
- +# Notes:
- +# - Requires case-insensitive filesystem for installation on NFS because DLL
- +# are stored with a different case than they are loaded
- +# - Requires global-mount, because installer uses different, evelated logon than the caller
- +# - The *.msi installer does not provide an option to install to a non-standard location, so the *.exe installer is needed
- +#
- +
- +# Name: Seamonkey
- +# Version:
- +# Download URL: https://archive.seamonkey-project.org/releases/2.53.21/win64/de/seamonkey-2.53.21.de.win64.installer.exe
- +# Can use NFS for data storage: yes
- +# Software can be installed on NFS: Yes, requires global-mount, requires case-insensitive filesystem
- +# Notes:
- +# - Requires case-insensitive filesystem for installation on NFS because DLL
- +# are stored with a different case than they are loaded
- +# - Requires global-mount, because installer uses different, evelated logon than the caller
- +#
- +
- +# Name: VMware Workstation
- +# Version: VMware-workstation-full-17.5.0-22583795
- +# Installer: VMware-workstation-full-17.5.0-22583795.exe
- +# Download URL: XXX
- +# Can use NFS for data storage: yes
- +# Software can be installed on NFS: Yes, requires global-mount, requires case-insensitive filesystem
- +# Notes:
- +# - Requires case-insensitive filesystem for installation on NFS because DLL
- +# are stored with a different case than they are loaded
- +# - Requires global-mount, because installer uses different, evelated logon than the caller
- +#
- +
- +# Name: Wireshark
- +# Version: Wireshark-4.4.3-x64
- +# Installer: Wireshark-4.4.3-x64.exe
- +# Download URL:
- +# Can use NFS for data storage: yes
- +# Software can be installed on NFS: Yes, requires global-mount, requires case-insensitive filesystem
- +# Notes:
- +# - Requires case-insensitive filesystem for installation on NFS because DLL
- +# are stored with a different case than they are loaded
- +# - Requires global-mount, because installer uses different, evelated logon than the caller
- +#
- +
- +# Name: JAVA SDK
- +# Version: jdk-23_windows-x64
- +# Installer: jdk-23_windows-x64_bin.msi
- +# Download URL:
- +# Can use NFS for data storage: yes
- +# Software can be installed on NFS: No, MSI installer fails to unpack the files
- +# Notes:
- +# - MSI installer fails to unpack the files
- +# - running java software via *.class or *.jar works fine, even on case-sensive filesystems
- +#
- +
- +
- +
- +# EOF.
- --
- 2.51.0
msnfs41client: Patches for case-insenstive support, fattr4_offline, softwarecompat-notes, tests+misc, 2025-09-17
Posted by Anonymous on Wed 17th Sep 2025 15:51
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.
rovema.kpaste.net RSS