- From 471cc11006af7aa9a56f142906733df2078919c2 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Thu, 20 Mar 2025 11:21:47 +0100
- Subject: [PATCH 1/5] tests: Setup instructions for Illumos NFS server should
- default to NFSv4.2
- Illumos NFS server supports NFSv4.2, so setup instructions should
- default to NFSv4.2
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/nfs_server_setup.txt | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
- diff --git a/tests/nfs_server_setup.txt b/tests/nfs_server_setup.txt
- index e8340c9..6d0ffcc 100644
- --- a/tests/nfs_server_setup.txt
- +++ b/tests/nfs_server_setup.txt
- @@ -82,7 +82,7 @@ See https://docs.oracle.com/en/operating-systems/solaris/oracle-solaris/11.4/man
- #
- -# Illumos NFSv4.1 server setup
- +# Illumos NFSv4.2 server setup
- # (similar to Solaris 11.4)
- #
- @@ -97,7 +97,7 @@ svcadm enable network/nfs/mapid
- svcadm enable network/nfs/server
- sharectl set -p nfsmapid_domain=global.loc nfs
- sharectl set -p server_delegation=on nfs
- -sharectl set -p server_versmax=4.1 nfs
- +sharectl set -p server_versmax=4.2 nfs
- # prepare test share
- mkdir /nfsdata
- --
- 2.45.1
- From b7b5f96158726c4fa0c393c79b3512de45d922b7 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Thu, 20 Mar 2025 15:13:17 +0100
- Subject: [PATCH 2/5] daemon: Add a NFSv4 XATTR filename prefix for Windows
- Extended Attributes
- Add a NFSv4 XATTR (extended attributes) filename prefix for Windows
- Extended Attributes (EA)
- We need such a prefix to avoid colliding with other users in the
- NFSv4 XATTR namespace - for example SUN Microsystrems (Solaris,
- Illumos, ...) uses "SUNWattr_" as prefix, and setting such attributes
- can cause data corruption (or in case of "SUNWattr_ro" will fail, because
- the attribute file is read-only).
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/ea.c | 128 +++++++++++++++++++++++++++++++++++++++++-----------
- 1 file changed, 102 insertions(+), 26 deletions(-)
- diff --git a/daemon/ea.c b/daemon/ea.c
- index 00211a9..1a9a24c 100644
- --- a/daemon/ea.c
- +++ b/daemon/ea.c
- @@ -1,5 +1,6 @@
- /* NFSv4.1 client for Windows
- - * Copyright (C) 2012 The Regents of the University of Michigan
- + * Copyright (C) 2012 The Regents of the University of Michigan
- + * Copyright (C) 2024-2025 Roland Mainz <roland.mainz@nrubsig.org>
- *
- * Olga Kornievskaia <aglo@umich.edu>
- * Casey Bodley <cbodley@umich.edu>
- @@ -31,6 +32,20 @@
- #include "daemon_debug.h"
- #include "nfs_ea.h"
- +/*
- + * |WIN_NFS4_EA_NAME_PREFIX| - Prefix for Windows EA in NFSv4
- + * XATTR (extended attributes) namespace
- + *
- + * We need such a prefix to avoid colliding with other users
- + * in the NFSv4 XATTR namespace - for example SUN Microsystrems
- + * (Solaris, Illumos, ...) uses "SUNWattr_" as prefix, and setting
- + * such attributes can cause data corruption (or in case of
- + * "SUNWattr_ro" will fail, because the attribute file is
- + * read-only).
- + */
- +#define WIN_NFS4_EA_NAME_PREFIX "win32.ea."
- +#define WIN_NFS4_EA_NAME_PREFIX_LEN (9)
- +
- #define EALVL 2 /* dprintf level for extended attribute logging */
- @@ -49,6 +64,19 @@ static int set_ea_value(
- nfs41_write_verf verf;
- uint32_t bytes_written;
- int status;
- + char prefixed_name[256];
- +
- + DPRINTF(EALVL,
- + ("set_ea_value: "
- + "ea->(EaName='%.*s' EaNameLength=%d)\n",
- + (int)ea->EaNameLength,
- + ea->EaName,
- + (int)ea->EaNameLength));
- +
- + (void)snprintf(prefixed_name, sizeof(prefixed_name), "%s%.*s",
- + WIN_NFS4_EA_NAME_PREFIX,
- + (int)ea->EaNameLength,
- + ea->EaName);
- /* don't allow values larger than NFS4_EASIZE */
- if (ea->EaValueLength > NFS4_EASIZE) {
- @@ -61,8 +89,8 @@ static int set_ea_value(
- /* remove the file on empty value */
- if (ea->EaValueLength == 0) {
- nfs41_component name;
- - name.name = ea->EaName;
- - name.len = ea->EaNameLength;
- + name.name = prefixed_name;
- + name.len = (USHORT)strlen(prefixed_name);
- nfs41_remove(session, parent, &name, 0);
- status = NFS4_OK;
- goto out;
- @@ -70,8 +98,8 @@ static int set_ea_value(
- claim.claim = CLAIM_NULL;
- claim.u.null.filename = &file.name;
- - file.name.name = ea->EaName;
- - file.name.len = ea->EaNameLength;
- + file.name.name = prefixed_name;
- + file.name.len = (USHORT)strlen(prefixed_name);
- createattrs.attrmask.count = 2;
- createattrs.attrmask.arr[0] = FATTR4_WORD0_SIZE;
- @@ -85,9 +113,8 @@ static int set_ea_value(
- &createattrs, TRUE, &stateid.stateid, &delegation, NULL);
- if (status) {
- eprintf("set_ea_value: "
- - "nfs41_open(ea_name='%.*s') failed with '%s'\n",
- - (int)ea->EaNameLength,
- - ea->EaName,
- + "nfs41_open(ea_name='%s') failed with '%s'\n",
- + prefixed_name,
- nfs_error_string(status));
- goto out;
- }
- @@ -98,9 +125,8 @@ static int set_ea_value(
- &verf, NULL);
- if (status) {
- eprintf("set_ea_value: "
- - "nfs41_write(ea_name='%.*s') failed with '%s'\n",
- - (int)ea->EaNameLength,
- - ea->EaName,
- + "nfs41_write(ea_name='%s') failed with '%s'\n",
- + prefixed_name,
- nfs_error_string(status));
- goto out_close;
- }
- @@ -343,7 +369,13 @@ static uint32_t calculate_ea_list_length(
- while (remaining) {
- entry = (const nfs41_readdir_entry*)position;
- - length += ALIGNED_EASIZE(entry->name_len);
- +
- + if ((entry->name_len > WIN_NFS4_EA_NAME_PREFIX_LEN) &&
- + (memcmp(entry->name,
- + WIN_NFS4_EA_NAME_PREFIX, WIN_NFS4_EA_NAME_PREFIX_LEN) == 0)) {
- + length +=
- + ALIGNED_EASIZE(entry->name_len-WIN_NFS4_EA_NAME_PREFIX_LEN);
- + }
- if (!entry->next_entry_offset)
- break;
- @@ -359,21 +391,52 @@ static void populate_ea_list(
- OUT PFILE_GET_EA_INFORMATION ea_list)
- {
- const nfs41_readdir_entry *entry;
- - PFILE_GET_EA_INFORMATION ea = ea_list, prev = NULL;
- + PFILE_GET_EA_INFORMATION ea = ea_list;
- + PFILE_GET_EA_INFORMATION last_win_ea = NULL;
- + bool is_win_ea;
- for (;;) {
- entry = (const nfs41_readdir_entry*)position;
- - StringCchCopyA(ea->EaName, entry->name_len, entry->name);
- - ea->EaNameLength = (UCHAR)entry->name_len - 1;
- +
- + if ((entry->name_len > WIN_NFS4_EA_NAME_PREFIX_LEN) &&
- + (memcmp(entry->name,
- + WIN_NFS4_EA_NAME_PREFIX, WIN_NFS4_EA_NAME_PREFIX_LEN) == 0)) {
- + is_win_ea = true;
- + }
- + else {
- + is_win_ea = false;
- + }
- +
- + if (is_win_ea) {
- + ea->EaNameLength =
- + (UCHAR)(entry->name_len - WIN_NFS4_EA_NAME_PREFIX_LEN);
- + (void)memcpy(ea->EaName,
- + entry->name+WIN_NFS4_EA_NAME_PREFIX_LEN,
- + ea->EaNameLength);
- +
- + DPRINTF(EALVL,
- + ("populate_ea_list: adding ea "
- + "entry->(name='%.*s' name_len=%d) "
- + "ea->(EaName='%.*s' EaNameLength=%d)\n",
- + (int)entry->name_len,
- + entry->name,
- + (int)entry->name_len,
- + (int)ea->EaNameLength,
- + ea->EaName,
- + (int)ea->EaNameLength));
- + last_win_ea = ea;
- + }
- if (!entry->next_entry_offset) {
- - ea->NextEntryOffset = 0;
- + (last_win_ea?last_win_ea:ea)->NextEntryOffset = 0;
- break;
- }
- - prev = ea;
- - ea->NextEntryOffset = ALIGNED_EASIZE(ea->EaNameLength);
- - ea = (PFILE_GET_EA_INFORMATION)NEXT_ENTRY(ea);
- + if (is_win_ea) {
- + ea->NextEntryOffset = ALIGNED_EASIZE(ea->EaNameLength);
- + ea = (PFILE_GET_EA_INFORMATION)NEXT_ENTRY(ea);
- + }
- +
- position += entry->next_entry_offset;
- }
- }
- @@ -442,14 +505,27 @@ static int get_ea_value(
- uint32_t diff, bytes_read;
- bool_t eof;
- int status;
- + char prefixed_name[256];
- if (parent->fh.len == 0) /* no named attribute directory */
- goto out_empty;
- + DPRINTF(EALVL,
- + ("get_ea_value: "
- + "ea->(EaName='%.*s' EaNameLength=%d)\n",
- + (int)ea->EaNameLength,
- + ea->EaName,
- + (int)ea->EaNameLength));
- +
- + (void)snprintf(prefixed_name, sizeof(prefixed_name), "%s%.*s",
- + WIN_NFS4_EA_NAME_PREFIX,
- + (int)ea->EaNameLength,
- + ea->EaName);
- +
- claim.claim = CLAIM_NULL;
- claim.u.null.filename = &file.name;
- - file.name.name = ea->EaName;
- - file.name.len = ea->EaNameLength;
- + file.name.name = prefixed_name;
- + file.name.len = (USHORT)strlen(prefixed_name);
- status = nfs41_open(session, parent, &file, owner, &claim,
- OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WANT_NO_DELEG,
- @@ -457,9 +533,8 @@ static int get_ea_value(
- &stateid.stateid, &delegation, &info);
- if (status) {
- eprintf("get_ea_value: "
- - "nfs41_open(ea_name='%.*s') failed with '%s'\n",
- - (int)ea->EaNameLength,
- - ea->EaName,
- + "nfs41_open(ea_name='%s') failed with '%s'\n",
- + prefixed_name,
- nfs_error_string(status));
- if (status == NFS4ERR_NOENT)
- goto out_empty;
- @@ -470,7 +545,8 @@ static int get_ea_value(
- status = NFS4ERR_FBIG;
- eprintf("get_ea_value: "
- "EA value for '%s' longer than maximum %u "
- - "(%llu bytes), returning %s\n", ea->EaName, NFS4_EASIZE,
- + "(%llu bytes), returning '%s'\n",
- + prefixed_name, NFS4_EASIZE,
- info.size, nfs_error_string(status));
- goto out_close;
- }
- @@ -627,7 +703,7 @@ static int handle_getexattr(void *daemon_context, nfs41_upcall *upcall)
- }
- ea->EaNameLength = query->EaNameLength;
- - StringCchCopyA(ea->EaName, (size_t)ea->EaNameLength + 1, query->EaName);
- + (void)memcpy(ea->EaName, query->EaName, ea->EaNameLength);
- ea->Flags = 0;
- /* read the value from file */
- --
- 2.45.1
- From 39dd639aba76685976bdf8b42cbb9b1fd445046d Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Thu, 20 Mar 2025 16:23:39 +0100
- Subject: [PATCH 3/5] tests: Add tests for Windows EAs+NFSv4 XATTRs
- Add tests for Windows (Extended Attributes) EAs and NFSv4 XATTRs
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/manual_testing.txt | 60 +++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 59 insertions(+), 1 deletion(-)
- diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
- index 09ef4a6..4740a5d 100644
- --- a/tests/manual_testing.txt
- +++ b/tests/manual_testing.txt
- @@ -1,5 +1,5 @@
- #
- -# ms-nfs41-client manual testing sequence, 2025-02-24
- +# ms-nfs41-client manual testing sequence, 2025-03-20
- #
- # Draft version, needs to be turned into automated tests
- # if possible
- @@ -19,6 +19,7 @@
- # make
- # bmake
- # netpbm
- +# attr
- # git
- # subversion
- # cygport
- @@ -373,6 +374,63 @@ icacls mytestfile1.txt | grep --colour -E 'cygwingrp2.+GR'
- #
- +#
- +# Tests for Windows EAs (Extended Attributes)
- +# Windows EAs are represented as NFSv4 extended attributes (XATTR)
- +# files, with the Windows EaName prefixed with "win32.ea." to
- +# avoid namespace collision with other users of NFSv4 XATTR files
- +# (e.g. SUN Microsystems/Solaris/Illumos/ZFS etc. use "SUNWattr_"
- +# as predix
- +#
- +
- +1. One-liner:
- +---- snip ----
- +$ ksh93 -c 'set -o xtrace -o errexit ; rm -f x1 ; touch x1 ; attr -q -s "fish5" -V "hello lake world" x1 ; [[ "$(attr -q -l x1)" == *fish5* ]] || echo FAIL ; [[ "$(attr -q -g "fish5" x1)" == "hello lake world" ]] || echo "FAIL" ; attr -q -r "fish5" x1 ; echo "# Test OK"'
- +---- snip ----
- +
- +2. Detailed test:
- +---- snip ----
- +# create parent file
- +$ rm -f myattrfile ; touch myattrfile
- +
- +# list attributes for new file (should be no EAs)
- +$ attr -l myattrfile
- +
- +# create EA attribute "chicken3"
- +$ attr -s "chicken3" -V "hello world" myattrfile
- +Attribute "chicken3" set to a 11 byte value for myattrfile:
- +hello world
- +
- +# create EA attribute "fish5"
- +$ attr -s "fish5" -V "hello lake world" myattrfile
- +Attribute "fish5" set to a 16 byte value for myattrfile:
- +hello lake world
- +
- +# list attributes (should be "fish5" and "chicken3"
- +$ attr -l myattrfile
- +Attribute "fish5" has a 16 byte value for myattrfile
- +Attribute "chicken3" has a 11 byte value for myattrfile
- +
- +# get value of "chicken3" (should be "hello world")
- +$ attr -g chicken3 myattrfile
- +Attribute "chicken3" had a 11 byte value for myattrfile:
- +hello world
- +
- +# remove attribute "chicken3", try to get it (should fail)
- +$ attr -r chicken3 myattrfile
- +$ attr -g chicken3 myattrfile
- +attr_get: No data available
- +Could not get "chicken3" for myattrfile
- +---- snip ----
- +
- +3. Notes:
- +On the NFS server side you can observe XATTR attributes like this:
- +- Using runat:
- +$ runat "x1" "ls -la"
- +- Using bash cd(1) -@:
- +$ bash -c 'cd -@ "x1" && ls -la'
- +
- +
- #
- # ksh93 (ast-ksh)
- #
- --
- 2.45.1
- From a555eaf921fe861cb5d8f9d36c06a990bcfbe80c Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Thu, 20 Mar 2025 17:01:55 +0100
- Subject: [PATCH 4/5] daemon: Cleanup EA macros
- Cleanup EA macros and put one copy in "daemon/util.h".
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/daemon_debug.c | 4 ----
- daemon/ea.c | 13 ++++++-------
- daemon/util.h | 4 ++++
- 3 files changed, 10 insertions(+), 11 deletions(-)
- diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
- index 493d221..083fe2f 100644
- --- a/daemon/daemon_debug.c
- +++ b/daemon/daemon_debug.c
- @@ -1464,10 +1464,6 @@ void debug_print_ea(PFILE_FULL_EA_INFORMATION ea)
- if (ea == NULL)
- goto out;
- -#define EA_NEXT_ENTRY(ea) ((PBYTE)(ea) + (ea)->NextEntryOffset)
- -#define EA_VALUE(ea) \
- - ((void *)((unsigned char*)(ea)->EaName + (ea)->EaNameLength + 1))
- -
- while (1) {
- const char *ea_name = print_ea->EaName;
- size_t ea_name_len = print_ea->EaNameLength;
- diff --git a/daemon/ea.c b/daemon/ea.c
- index 1a9a24c..8f829c6 100644
- --- a/daemon/ea.c
- +++ b/daemon/ea.c
- @@ -120,7 +120,7 @@ static int set_ea_value(
- }
- status = nfs41_write(session, &file, &stateid,
- - (unsigned char*)ea->EaName + ea->EaNameLength + 1,
- + EA_VALUE(ea),
- ea->EaValueLength, 0, FILE_SYNC4, &bytes_written,
- &verf, NULL);
- if (status) {
- @@ -149,7 +149,6 @@ static bool is_nfs_ea(
- (!strncmp(EA_NFSSYMLINKTARGETNAME, ea->EaName, ea->EaNameLength))));
- }
- -#define NEXT_ENTRY(ea) ((PBYTE)(ea) + (ea)->NextEntryOffset)
- int nfs41_ea_set(
- IN nfs41_open_state *state,
- @@ -172,7 +171,7 @@ int nfs41_ea_set(
- if (ea->NextEntryOffset == 0)
- break;
- - ea = (PFILE_FULL_EA_INFORMATION)NEXT_ENTRY(ea);
- + ea = (PFILE_FULL_EA_INFORMATION)EA_NEXT_ENTRY(ea);
- }
- out:
- return status;
- @@ -434,7 +433,7 @@ static void populate_ea_list(
- if (is_win_ea) {
- ea->NextEntryOffset = ALIGNED_EASIZE(ea->EaNameLength);
- - ea = (PFILE_GET_EA_INFORMATION)NEXT_ENTRY(ea);
- + ea = (PFILE_GET_EA_INFORMATION)EA_NEXT_ENTRY(ea);
- }
- position += entry->next_entry_offset;
- @@ -677,7 +676,7 @@ static int handle_getexattr(void *daemon_context, nfs41_upcall *upcall)
- status = ERROR_NO_MORE_FILES; /* STATUS_NO_MORE_EAS */
- goto out;
- }
- - query = (PFILE_GET_EA_INFORMATION)NEXT_ENTRY(query);
- + query = (PFILE_GET_EA_INFORMATION)EA_NEXT_ENTRY(query);
- }
- }
- @@ -735,8 +734,8 @@ static int handle_getexattr(void *daemon_context, nfs41_upcall *upcall)
- prev = ea;
- ea->NextEntryOffset = needed;
- - ea = (PFILE_FULL_EA_INFORMATION)NEXT_ENTRY(ea);
- - query = (PFILE_GET_EA_INFORMATION)NEXT_ENTRY(query);
- + ea = (PFILE_FULL_EA_INFORMATION)EA_NEXT_ENTRY(ea);
- + query = (PFILE_GET_EA_INFORMATION)EA_NEXT_ENTRY(query);
- }
- ea->NextEntryOffset = 0;
- diff --git a/daemon/util.h b/daemon/util.h
- index 242dfb9..65a1eee 100644
- --- a/daemon/util.h
- +++ b/daemon/util.h
- @@ -55,6 +55,10 @@ typedef ULONGLONG util_reltimestamp;
- #define PTR2PTRDIFF_T(p) ((ptrdiff_t)((char *)((void *)(p)) - ((char *)0)))
- #define PTRDIFF_T2PTR(d) ((void *)(((char *)0) + (d)))
- +#define EA_NEXT_ENTRY(ea) ((PBYTE)(ea) + (ea)->NextEntryOffset)
- +#define EA_VALUE(ea) \
- + ((void *)((unsigned char *)(ea)->EaName + (ea)->EaNameLength + 1))
- +
- char *stpcpy(char *restrict s1, const char *restrict s2);
- static __inline
- --
- 2.45.1
- From 5d5925b346a4c52a37f2e23507d6ae4fcae1aad8 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Thu, 20 Mar 2025 17:15:20 +0100
- Subject: [PATCH 5/5] daemon: Replace |strncmp()| with |memcmp()| when
- comparing EA names if len is identical
- Replace |strncmp()| with |memcmp()| when comparing EA names if
- the string length is identical.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/ea.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
- diff --git a/daemon/ea.c b/daemon/ea.c
- index 8f829c6..955ae66 100644
- --- a/daemon/ea.c
- +++ b/daemon/ea.c
- @@ -142,11 +142,11 @@ static bool is_nfs_ea(
- PFILE_FULL_EA_INFORMATION ea)
- {
- return (((ea->EaNameLength == EA_NFSV3ATTRIBUTES_LEN) &&
- - (!strncmp(EA_NFSV3ATTRIBUTES, ea->EaName, ea->EaNameLength)))
- + (!memcmp(EA_NFSV3ATTRIBUTES, ea->EaName, ea->EaNameLength)))
- || ((ea->EaNameLength == EA_NFSACTONLINK_LEN) &&
- - (!strncmp(EA_NFSACTONLINK, ea->EaName, ea->EaNameLength)))
- + (!memcmp(EA_NFSACTONLINK, ea->EaName, ea->EaNameLength)))
- || ((ea->EaNameLength == EA_NFSSYMLINKTARGETNAME_LEN) &&
- - (!strncmp(EA_NFSSYMLINKTARGETNAME, ea->EaName, ea->EaNameLength))));
- + (!memcmp(EA_NFSSYMLINKTARGETNAME, ea->EaName, ea->EaNameLength))));
- }
- @@ -210,7 +210,7 @@ static int handle_setexattr(void *daemon_context, nfs41_upcall *upcall)
- OPEN_DELEGATE_READ, FALSE);
- if ((ea->EaNameLength == EA_NFSV3ATTRIBUTES_LEN) &&
- - (!strncmp(EA_NFSV3ATTRIBUTES, ea->EaName, ea->EaNameLength))) {
- + (!memcmp(EA_NFSV3ATTRIBUTES, ea->EaName, ea->EaNameLength))) {
- nfs41_file_info info;
- stateid_arg stateid;
- --
- 2.45.1
msnfs41client: Patches for using a NFSv4 XATTR prefix for Win32 EAs, Win32 EA fixes+misc, 2025-03-20
Posted by Anonymous on Thu 20th Mar 2025 16:37
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.