pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patches for ARM64 support, global mount issues, case-insensitive filesystem support+misc, 2025-09-11
Posted by Anonymous on Thu 11th Sep 2025 19:40
raw | new post

  1. From 9e91e7fa39fb97a07b11b8078a9050b71c570337 Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Sat, 6 Sep 2025 17:11:33 +0200
  4. Subject: [PATCH 01/12] cygwin: Add codepath to copy&register kernel module and
  5.  network provider dll manually
  6.  
  7. Add codepath to copy&register kernel module and network provider dll
  8. manually. We need this for testing the Windows 11/ARM64 port, because
  9. right now
  10. $ rundll32 setupapi.dll,InstallHinfSection DefaultInstall 132 ./nfs41rdr.inf #
  11. does not work on Windows 11/ARM64.
  12.  
  13. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  14. ---
  15. cygwin/devel/msnfs41client.bash | 79 ++++++++++++++++++++++++++++++---
  16.  1 file changed, 73 insertions(+), 6 deletions(-)
  17.  
  18. diff --git a/cygwin/devel/msnfs41client.bash b/cygwin/devel/msnfs41client.bash
  19. index cc104a6..1c495d0 100755
  20. --- a/cygwin/devel/msnfs41client.bash
  21. +++ b/cygwin/devel/msnfs41client.bash
  22. @@ -381,8 +381,12 @@ function nfsclient_disable_autostartservices
  23.         sc config 'ms-nfs41-client-globalmountall-service' start=disabled
  24.  }
  25.  
  26. +typeset -r use_nfs41rdrinf=true
  27. +
  28.  function nfsclient_adddriver
  29.  {
  30. +       typeset -i res
  31. +
  32.         set -o nounset
  33.         set -o xtrace
  34.         set -o errexit
  35. @@ -404,7 +408,37 @@ function nfsclient_adddriver
  36.         nfs_install -D
  37.         printf 'after nfs_install:  ProviderOrder="%s"\n' "$( strings -a '/proc/registry/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/NetworkProvider/Order/ProviderOrder')"
  38.  
  39. -       rundll32 setupapi.dll,InstallHinfSection DefaultInstall 132 ./nfs41rdr.inf
  40. +       if ${use_nfs41rdrinf} ; then
  41. +               rundll32 setupapi.dll,InstallHinfSection DefaultInstall 132 ./nfs41rdr.inf
  42. +       else
  43. +               #
  44. +               # Install kernel driver and network provider DLL "manually"
  45. +               # (this is the same functionality which the nfs41rdr.inf should do)
  46. +               #
  47. +               rm -f '/cygdrive/c/Windows/System32/drivers/nfs41_driver.sys'
  48. +               cp 'nfs41_driver.sys' '/cygdrive/c/Windows/System32/drivers/nfs41_driver.sys'
  49. +               rm -f '/cygdrive/c/Windows/System32/nfs41_np.dll'
  50. +               cp 'nfs41_np.dll' '/cygdrive/c/Windows/System32/nfs41_np.dll'
  51. +
  52. +               #
  53. +               # create nfs41_driver service if it does not exists
  54. +               # (ERROR_SERVICE_DOES_NOT_EXIST==1060, 1060-1024==36)
  55. +               #
  56. +               set +o errexit
  57. +               sc query nfs41_driver >'/dev/null' 2>&1
  58. +               (( res=$? ))
  59. +               set -o errexit
  60. +
  61. +               if (( res == 36 )) ; then
  62. +                       sc create nfs41_driver binPath='C:\Windows\System32\drivers\nfs41_driver.sys' type=filesys group=network start=system tag=8
  63. +               fi
  64. +
  65. +               regtool add '/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/nfs41_driver'
  66. +               regtool add '/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/nfs41_driver/NetworkProvider'
  67. +               regtool -s set '/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/nfs41_driver/NetworkProvider/DeviceName' '\Device\nfs41_driver'
  68. +               regtool -s set '/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/nfs41_driver/NetworkProvider/Name' 'NFS41 Network'
  69. +               regtool -s set '/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/nfs41_driver/NetworkProvider/ProviderPath' 'System32\nfs41_np.dll'
  70. +       fi
  71.  
  72.         #
  73.         # Hack: Manually Add 32bit provider DLL to a 64bit system, so
  74. @@ -413,7 +447,8 @@ function nfsclient_adddriver
  75.         #
  76.         if is_windows_64bit ; then
  77.                 # copy from the 32bit install dir
  78. -               cp './i686/nfs41_np.dll' '/cygdrive/c/Windows/SysWOW64/'
  79. +               rm -f '/cygdrive/c/Windows/SysWOW64/nfs41_np.dll'
  80. +               cp './i686/nfs41_np.dll' '/cygdrive/c/Windows/SysWOW64/nfs41_np.dll'
  81.         fi
  82.  
  83.         return 0
  84. @@ -436,12 +471,44 @@ function nfsclient_removedriver
  85.         fi
  86.  
  87.         nfs_install.exe 0
  88. -       rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 ./nfs41rdr.inf
  89. -       rm /cygdrive/c/Windows/System32/nfs41_np.dll || true
  90. +
  91. +       if ${use_nfs41rdrinf} ; then
  92. +               rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 ./nfs41rdr.inf
  93. +
  94. +               # nfs41rdr.inf should do this, but we do this here for testing
  95. +               if [[ -f '/cygdrive/c/Windows/System32/drivers/nfs41_driver.sys' ]] ; then
  96. +                       printf '# %q leftover from INF uninstall, removing...\n' \
  97. +                               '/cygdrive/c/Windows/System32/drivers/nfs41_driver.sys'
  98. +                       rm -f '/cygdrive/c/Windows/System32/drivers/nfs41_driver.sys' || true
  99. +               fi
  100. +               if [[ -f '/cygdrive/c/Windows/System32/nfs41_np.dll' ]] ; then
  101. +                       printf '# %q leftover from INF uninstall, removing...\n' \
  102. +                               '/cygdrive/c/Windows/System32/nfs41_np.dll'
  103. +                       rm -f '/cygdrive/c/Windows/System32/nfs41_np.dll' || true
  104. +               fi
  105. +       else
  106. +               #
  107. +               # Remove kernel driver and network provider DLL "manually"
  108. +               # (this is the same functionality which the nfs41rdr.inf should do)
  109. +               #
  110. +
  111. +               #sc stop nfs41_driver
  112. +               #sc delete nfs41_driver
  113. +
  114. +               # regtool fails with an error if we try to delete the nfs41_driver dir
  115. +               reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nfs41_driver" /f || true
  116. +
  117. +               rm -f '/cygdrive/c/Windows/System32/drivers/nfs41_driver.sys' || true
  118. +               rm -f '/cygdrive/c/Windows/System32/nfs41_np.dll' || true
  119. +       fi
  120. +
  121. +       #
  122. +       # Hack: Manually remove 32bit provider DLL on a 64bit system,
  123. +       # (see comment in "nfsclient_adddriver")
  124. +       #
  125.         if is_windows_64bit ; then
  126. -               rm '/cygdrive/c/Windows/SysWOW64/nfs41_np.dll' || true
  127. +               rm -f '/cygdrive/c/Windows/SysWOW64/nfs41_np.dll' || true
  128.         fi
  129. -       rm /cygdrive/c/Windows/System32/drivers/nfs41_driver.sys || true
  130.  
  131.         sync
  132.  
  133. --
  134. 2.51.0
  135.  
  136. From a0b77cbe3111c807ac6758838898363947ee96bb Mon Sep 17 00:00:00 2001
  137. From: Aurelien Couderc <aurelien.couderc2002@gmail.com>
  138. Date: Mon, 8 Sep 2025 22:06:00 +0200
  139. Subject: [PATCH 02/12] cygwin,nfs41rdr.inf: Provide a catalog file for
  140.  nfs41rdr.inf
  141.  
  142. Provide a catalog file for nfs41rdr.inf.
  143.  
  144. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  145. ---
  146. cygwin/Makefile.install | 2 ++
  147.  nfs41rdr.inf            | 2 +-
  148.  2 files changed, 3 insertions(+), 1 deletion(-)
  149.  
  150. diff --git a/cygwin/Makefile.install b/cygwin/Makefile.install
  151. index e9f68df..6d2aaaa 100644
  152. --- a/cygwin/Makefile.install
  153. +++ b/cygwin/Makefile.install
  154. @@ -72,7 +72,9 @@ installdest:
  155.         # workaround for coreutils 9.5-1 /bin/cp bug stuck in an endless loop with compressed files
  156.         chattr -V -c $(VS_BUILD_DIR)/nfs41_driver.*
  157.         cp $(VS_BUILD_DIR)/nfs41_driver.*       $(DESTDIR)/$(CYGWIN_BASEPATH)/lib/msnfs41client/.
  158. +       # Copy kernel driver INF file and generate signature catalog
  159.         cp $(PROJECT_BASEDIR_DIR)/nfs41rdr.inf  $(DESTDIR)/$(CYGWIN_BASEPATH)/lib/msnfs41client/.
  160. +       (cd "$(DESTDIR)/$(CYGWIN_BASEPATH)/lib/msnfs41client/" && '/cygdrive/c/Program Files (x86)/Windows Kits/10/bin/x86/Inf2Cat.exe' /driver:. /os:10_X86,10_X64,10_VB_ARM64)
  161.         cp $(PROJECT_BASEDIR_DIR)/etc_netconfig $(DESTDIR)/$(CYGWIN_BASEPATH)/lib/msnfs41client/.
  162.         cp $(PROJECT_BASEDIR_DIR)/ms-nfs41-idmap.conf           $(DESTDIR)/$(CYGWIN_BASEPATH)/lib/msnfs41client/.
  163.         cp $(CYGWIN_MAKEFILE_DIR)/devel/msnfs41client.bash      $(DESTDIR)/$(CYGWIN_BASEPATH)/lib/msnfs41client/msnfs41client
  164. diff --git a/nfs41rdr.inf b/nfs41rdr.inf
  165. index 4274370..03339bb 100644
  166. --- a/nfs41rdr.inf
  167. +++ b/nfs41rdr.inf
  168. @@ -3,7 +3,7 @@ Signature="$CHICAGO$"
  169.  DriverVer=06/12/2024,1.0.0.0
  170.  Class=NetService
  171.  ClassGUID={4d36e974-e325-11ce-bfc1-08002be10318}
  172. -CatalogFile=catalogfile.cat
  173. +CatalogFile=nfs41rdr.cat
  174.  Provider=%ProviderName%
  175.  
  176.  [SourceDisksNames]
  177. --
  178. 2.51.0
  179.  
  180. From c194bd9eab4c51517f144d1fbc2f09dfb220b2cd Mon Sep 17 00:00:00 2001
  181. From: Aurelien Couderc <aurelien.couderc2002@gmail.com>
  182. Date: Mon, 8 Sep 2025 22:08:11 +0200
  183. Subject: [PATCH 03/12] cygwin: /sbin/msnfs41client run_service+sys_run_service
  184.  should start nfs41_driver
  185.  
  186. /sbin/msnfs41client run_service+sys_run_service should start nfs41_driver,
  187. otherwise a reboot is always neccesary even for a new install.
  188.  
  189. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  190. ---
  191. cygwin/devel/msnfs41client.bash | 12 ++++++++++++
  192.  1 file changed, 12 insertions(+)
  193.  
  194. diff --git a/cygwin/devel/msnfs41client.bash b/cygwin/devel/msnfs41client.bash
  195. index 1c495d0..0dfc94a 100755
  196. --- a/cygwin/devel/msnfs41client.bash
  197. +++ b/cygwin/devel/msnfs41client.bash
  198. @@ -567,6 +567,12 @@ function nfsclient_rundeamon
  199.  
  200.         set -o xtrace
  201.  
  202. +       #
  203. +       # start kernel driver if it is not running yet
  204. +       # (can happen directly after installation if no reboot was made)
  205. +       #
  206. +       sc start nfs41_driver || true
  207. +
  208.         # switch to UTF-8 codepage so debug output with non-ASCII characters
  209.         # gets printed correctly on a terminal
  210.         chcp.com 65001
  211. @@ -687,6 +693,12 @@ function nfsclient_system_rundeamon
  212.  
  213.         set -o xtrace
  214.  
  215. +       #
  216. +       # start kernel driver if it is not running yet
  217. +       # (can happen directly after installation if no reboot was made)
  218. +       #
  219. +       sc start nfs41_driver || true
  220. +
  221.         # switch to UTF-8 codepage so debug output with non-ASCII characters
  222.         # gets printed correctly on a terminal
  223.         chcp.com 65001
  224. --
  225. 2.51.0
  226.  
  227. From 4b5e06bb9f11dab575c02c9b560f732bc76367e6 Mon Sep 17 00:00:00 2001
  228. From: Roland Mainz <roland.mainz@nrubsig.org>
  229. Date: Tue, 9 Sep 2025 12:58:32 +0200
  230. Subject: [PATCH 04/12] cygwin,tests: Reimplement nfs_globalmount.ksh as
  231.  nfs_globalmount.exe
  232.  
  233. Reimplement nfs_globalmount.ksh as nfs_globalmount.exe, so it can be
  234. easily called from cmd.exe, powershell.exe, and be whitelisted in MS Defender.
  235.  
  236. Fixes: https://sourceforge.net/p/ms-nfs41-client/mailman/message/59230996/
  237. Reported-by: Mark Liam Brown <brownmarkliam@gmail.com>
  238. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  239. ---
  240. cygwin/Makefile.install                       |  11 +-
  241.  .../utils/nfs_globalmount/nfs_globalmount.ksh |  30 ------
  242.  tests/winrunassystem/Makefile                 |  38 ++++++-
  243.  tests/winrunassystem/winrunassystem.c         | 100 ++++++++++++++----
  244.  4 files changed, 123 insertions(+), 56 deletions(-)
  245.  delete mode 100644 cygwin/utils/nfs_globalmount/nfs_globalmount.ksh
  246.  
  247. diff --git a/cygwin/Makefile.install b/cygwin/Makefile.install
  248. index 6d2aaaa..ea3dc0f 100644
  249. --- a/cygwin/Makefile.install
  250. +++ b/cygwin/Makefile.install
  251. @@ -88,10 +88,6 @@ installdest:
  252.         git diff -w     >"$(DESTDIR)/$(CYGWIN_BASEPATH)/usr/src/msnfs41client/msnfs41client_diff_w.diff"
  253.         git diff        >"$(DESTDIR)/$(CYGWIN_BASEPATH)/usr/src/msnfs41client/msnfs41client_diff.diff"
  254.         @ printf "# Package utilties\n"
  255. -       cp $(CYGWIN_MAKEFILE_DIR)/utils/nfs_globalmount/nfs_globalmount.ksh $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/nfs_globalmount
  256. -       chmod a+x $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/nfs_globalmount
  257. -       PATH+=":$(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/" \
  258. -               /usr/bin/ksh93 $(CYGWIN_MAKEFILE_DIR)/utils/nfs_globalmount/nfs_globalmount.ksh --nroff 2>"$(DESTDIR)/$(CYGWIN_BASEPATH)/usr/share/man/man1/nfs_globalmount.1" || true
  259.         cp $(CYGWIN_MAKEFILE_DIR)/utils/mountall_msnfs41client/mountall_msnfs41client.ksh $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/mountall_msnfs41client
  260.         chmod a+x $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/mountall_msnfs41client
  261.         PATH+=":$(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/" \
  262. @@ -139,6 +135,13 @@ installdest:
  263.         else \
  264.                 (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/ && $(LINKEXE) winrunassystem.i686.exe winrunassystem.exe) \
  265.         fi
  266. +       cp "$(PROJECT_BASEDIR_DIR)/tests/winrunassystem/nfs_globalmount.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/nfs_globalmount.x86_64.exe
  267. +       cp "$(PROJECT_BASEDIR_DIR)/tests/winrunassystem/nfs_globalmount.i686.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/nfs_globalmount.i686.exe
  268. +       if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
  269. +               (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/ && $(LINKEXE) nfs_globalmount.x86_64.exe nfs_globalmount.exe) \
  270. +       else \
  271. +               (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/sbin/ && $(LINKEXE) nfs_globalmount.i686.exe nfs_globalmount.exe) \
  272. +       fi
  273.         cp "$(PROJECT_BASEDIR_DIR)/tests/lssparse/lssparse.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/lssparse.x86_64.exe
  274.         if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
  275.                 (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && $(LINKEXE) lssparse.x86_64.exe lssparse.exe) \
  276. diff --git a/cygwin/utils/nfs_globalmount/nfs_globalmount.ksh b/cygwin/utils/nfs_globalmount/nfs_globalmount.ksh
  277. deleted file mode 100644
  278. index c4edd41..0000000
  279. --- a/cygwin/utils/nfs_globalmount/nfs_globalmount.ksh
  280. +++ /dev/null
  281. @@ -1,30 +0,0 @@
  282. -#!/bin/ksh93
  283. -
  284. -# ksh93 scripts using AST getopts(1) support --nroff,
  285. -# but we do not do that yet
  286. -[[ "$1" == '--nroff' ]] && exit 1
  287. -
  288. -function is_windows_admin_account
  289. -{
  290. -       #
  291. -       # Test whether we have the Windows permissions to install DLLs
  292. -       # and the kernel module
  293. -       #
  294. -       # Usually Windows Adminstrator rights are indicated by the
  295. -       # membership in group "544(Administratoren)" (Cygwin maps
  296. -       # "SID S-1-5-32-544" to GID 544)
  297. -       #
  298. -       if [[ "$(/bin/id -G)" =~ (^|[[:space:]]+)544([[:space:]]+|$) ]] ; then
  299. -               return 0
  300. -       fi
  301. -       return 1
  302. -}
  303. -
  304. -if ! is_windows_admin_account ; then
  305. -       printf $"%s: Requires Windows Adminstator permissions.\n" "$0"
  306. -       exit 1
  307. -fi
  308. -
  309. -/sbin/winrunassystem "$(cygpath -w '/sbin/nfs_mount.exe')" "$@"
  310. -exit $?
  311. -# EOF.
  312. diff --git a/tests/winrunassystem/Makefile b/tests/winrunassystem/Makefile
  313. index 69ce1ab..881396d 100644
  314. --- a/tests/winrunassystem/Makefile
  315. +++ b/tests/winrunassystem/Makefile
  316. @@ -5,22 +5,52 @@
  317.  # POSIX Makefile
  318.  SIGNTOOL="/cygdrive/c/Program Files (x86)/Microsoft SDKs/ClickOnce/SignTool/signtool.exe"
  319.  
  320. -all: winrunassystem.i686.exe winrunassystem.x86_64.exe winrunassystem.exe
  321. +all: \
  322. +       winrunassystem.i686.exe \
  323. +       winrunassystem.x86_64.exe \
  324. +       winrunassystem.exe \
  325. +       nfs_globalmount.i686.exe \
  326. +       nfs_globalmount.x86_64.exe \
  327. +       nfs_globalmount.exe
  328.  
  329. +#
  330. +# winrunassystem.exe
  331. +#
  332.  winrunassystem.i686.exe: winrunassystem.c
  333. -       clang -target i686-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o $@
  334. +       clang -target i686-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DBUILD_WINRUNASSYSTEM=1 -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o $@
  335.         bash -x -c '$(SIGNTOOL) sign /ph /fd "sha256" /sha1 "$${CERTIFICATE_THUMBPRINT%$$(printf "\r")}" $@'
  336.  
  337.  winrunassystem.x86_64.exe: winrunassystem.c
  338. -       clang -target x86_64-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o $@
  339. +       clang -target x86_64-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DBUILD_WINRUNASSYSTEM=1 -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o $@
  340.         bash -x -c '$(SIGNTOOL) sign /ph /fd "sha256" /sha1 "$${CERTIFICATE_THUMBPRINT%$$(printf "\r")}" $@'
  341.  
  342.  winrunassystem.exe: winrunassystem.x86_64.exe
  343.         ln -s winrunassystem.x86_64.exe $@
  344.  
  345. +
  346. +#
  347. +# nfs_globalmount.exe
  348. +#
  349. +# (implemented *.exe instead of a script,so it can be easily called from
  350. +# cmd.exe, powershell.exe, and be whitelisted in MS Defender)
  351. +#
  352. +nfs_globalmount.i686.exe: winrunassystem.c
  353. +       clang -target i686-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DBUILD_NFS_GLOBALMOUNT=1 -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o $@
  354. +       bash -x -c '$(SIGNTOOL) sign /ph /fd "sha256" /sha1 "$${CERTIFICATE_THUMBPRINT%$$(printf "\r")}" $@'
  355. +
  356. +nfs_globalmount.x86_64.exe: winrunassystem.c
  357. +       clang -target x86_64-pc-windows-gnu -std=gnu17 -municode -Wall -Wextra -DBUILD_NFS_GLOBALMOUNT=1 -DUNICODE=1 -D_UNICODE=1 -g winrunassystem.c -lWtsapi32 -o $@
  358. +       bash -x -c '$(SIGNTOOL) sign /ph /fd "sha256" /sha1 "$${CERTIFICATE_THUMBPRINT%$$(printf "\r")}" $@'
  359. +
  360. +nfs_globalmount.exe: nfs_globalmount.x86_64.exe
  361. +       ln -s nfs_globalmount.x86_64.exe $@
  362. +
  363.  clean:
  364.         rm -fv \
  365.                 winrunassystem.i686.exe \
  366.                 winrunassystem.x86_64.exe \
  367. -               winrunassystem.exe
  368. +               winrunassystem.exe \
  369. +               nfs_globalmount.i686.exe \
  370. +               nfs_globalmount.x86_64.exe \
  371. +               nfs_globalmount.exe
  372.  # EOF.
  373. diff --git a/tests/winrunassystem/winrunassystem.c b/tests/winrunassystem/winrunassystem.c
  374. index 07b166d..c37ebfd 100644
  375. --- a/tests/winrunassystem/winrunassystem.c
  376. +++ b/tests/winrunassystem/winrunassystem.c
  377. @@ -80,7 +80,6 @@ static void LaunchInteractiveProcess(void);
  378.  static void WINAPI ServiceCtrlHandler(DWORD CtrlCode);
  379.  static void WINAPI ServiceMain(DWORD argc, LPWSTR* argv);
  380.  
  381. -
  382.  // #define DBG 1
  383.  
  384.  #ifdef DBG
  385. @@ -573,26 +572,10 @@ done:
  386.  }
  387.  
  388.  static
  389. -void usage(const wchar_t *av0)
  390. -{
  391. -    (void)fwprintf(stderr,
  392. -        L"%ls: Run command as user SYSTEM\n",
  393. -        av0);
  394. -}
  395. -
  396. -int wmain(int argc, wchar_t *argv[])
  397. +int winrunassystem_main(int argc, wchar_t *argv[])
  398.  {
  399.      int retval = EXIT_FAILURE;
  400.  
  401. -    if ((argc == 1) ||
  402. -        ((argc == 2) &&
  403. -            ((wcscmp(argv[1], L"--help") == 0) ||
  404. -            (wcscmp(argv[1], L"-h") == 0) ||
  405. -            (wcscmp(argv[1], L"/?") == 0)))) {
  406. -        usage(argv[0]);
  407. -        return EXIT_USAGE;
  408. -    }
  409. -
  410.      /*
  411.       * If started with "--service", run as a service
  412.       */
  413. @@ -663,3 +646,84 @@ int wmain(int argc, wchar_t *argv[])
  414.  
  415.      return retval;
  416.  }
  417. +
  418. +#ifdef BUILD_WINRUNASSYSTEM
  419. +static
  420. +void usage(const wchar_t *av0)
  421. +{
  422. +    (void)fwprintf(stderr,
  423. +        L"%ls: Run command as user SYSTEM\n",
  424. +        av0);
  425. +}
  426. +
  427. +int wmain(int argc, wchar_t *argv[])
  428. +{
  429. +    if ((argc == 1) ||
  430. +        ((argc == 2) &&
  431. +            ((wcscmp(argv[1], L"--help") == 0) ||
  432. +            (wcscmp(argv[1], L"-h") == 0) ||
  433. +            (wcscmp(argv[1], L"/?") == 0)))) {
  434. +        usage(argv[0]);
  435. +        return EXIT_USAGE;
  436. +    }
  437. +
  438. +    return winrunassystem_main(argc, argv);
  439. +}
  440. +#elif BUILD_NFS_GLOBALMOUNT
  441. +
  442. +/*
  443. + * Implement /sbin/nfs_globalmount.exe as EXE instead of a script,
  444. + * so it can be easily called from cmd.exe, powershell.exe, and
  445. + * be whitelisted in MS Defender
  446. + */
  447. +
  448. +/* Paths to nfs_mount*.exe */
  449. +#ifdef _WIN64
  450. +#define NFS_MOUNT_PATH L"C:\\cygwin64\\sbin\\nfs_mount.exe"
  451. +#define NFS_MOUNT_PATH_X86 L"C:\\cygwin64\\sbin\\nfs_mount.i686.exe"
  452. +#define NFS_MOUNT_PATH_AMD64 L"C:\\cygwin64\\sbin\\nfs_mount.x86_64.exe"
  453. +#else
  454. +#define NFS_MOUNT_PATH L"C:\\cygwin\\sbin\\nfs_mount.exe"
  455. +#define NFS_MOUNT_PATH_X86 L"C:\\cygwin\\sbin\\nfs_mount.i686.exe"
  456. +#define NFS_MOUNT_PATH_AMD64 L"C:\\cygwin\\sbin\\nfs_mount.x86_64.exe"
  457. +#endif /* _WIN64 */
  458. +/* FIXME: What about ARM64 ? */
  459. +
  460. +int wmain(int argc, wchar_t *argv[])
  461. +{
  462. +    int i;
  463. +    const wchar_t *nfs_mount_path;
  464. +
  465. +    /*
  466. +     * Select nfs_mount.exe binary based on our argv[0] name, e.g.
  467. +     * "nfs_globalmount.i686.exe" ---> "/sbin/nfs_mount.i686.exe",
  468. +     * "nfs_globalmount.x86_64.exe" ---> "/sbin/nfs_mount.x86_64.exe",
  469. +     * etc
  470. +     *
  471. +     * FIXME: What about ARM64 ?
  472. +     */
  473. +    if (wcsstr(argv[0], L".i686") != NULL) {
  474. +        nfs_mount_path = NFS_MOUNT_PATH_X86;
  475. +    }
  476. +    else if (wcsstr(argv[0], L".x86_64") != NULL) {
  477. +        nfs_mount_path = NFS_MOUNT_PATH_AMD64;
  478. +    }
  479. +    else {
  480. +        nfs_mount_path = NFS_MOUNT_PATH;
  481. +    }
  482. +
  483. +    if ((argc > 2) && (wcscmp(argv[1], L"--service") == 0)) {
  484. +        return winrunassystem_main(argc, argv);
  485. +    }
  486. +    else {
  487. +        wchar_t **new_argv = (wchar_t **)alloca(sizeof(wchar_t *)*(argc+3));
  488. +        new_argv[0] = argv[0];
  489. +        new_argv[1] = (wchar_t *)nfs_mount_path;
  490. +        for (i=1 ; i < argc ; i++)
  491. +            new_argv[i+1] = argv[i];
  492. +        return winrunassystem_main(argc+1, new_argv);
  493. +    }
  494. +}
  495. +#else
  496. +#error Unknown target, BUILD_WINRUNASSYSTEM+BUILD_NFS_GLOBALMOUNT not set
  497. +#endif
  498. --
  499. 2.51.0
  500.  
  501. From d526e0efecdd298a7d6f0f3e8b2cbdaa49366498 Mon Sep 17 00:00:00 2001
  502. From: Roland Mainz <roland.mainz@nrubsig.org>
  503. Date: Tue, 9 Sep 2025 13:10:09 +0200
  504. Subject: [PATCH 05/12] tests: winrunassystem should not hang if it cannot
  505.  create the child process
  506.  
  507. winrunassystem should not hang if it cannot create the child process.
  508.  
  509. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  510. ---
  511. tests/winrunassystem/winrunassystem.c | 14 ++++++++++++--
  512.  1 file changed, 12 insertions(+), 2 deletions(-)
  513.  
  514. diff --git a/tests/winrunassystem/winrunassystem.c b/tests/winrunassystem/winrunassystem.c
  515. index c37ebfd..c0e415c 100644
  516. --- a/tests/winrunassystem/winrunassystem.c
  517. +++ b/tests/winrunassystem/winrunassystem.c
  518. @@ -249,8 +249,18 @@ void LaunchInteractiveProcess(void)
  519.          NULL,
  520.          &si,
  521.          &pi)) {
  522. -        (void)printf("CreateProcess failed (%d).\n", (int)GetLastError());
  523. -        return;
  524. +        char errbuff[16384];
  525. +        DWORD lasterr = GetLastError();
  526. +
  527. +        (void)snprintf(errbuff, sizeof(errbuff),
  528. +            "Cannot create process for '%s', lasterr=%d\n",
  529. +            buffer, (int)lasterr);
  530. +        (void)WriteFile(hFile_stderr,
  531. +            errbuff, strlen(errbuff), NULL, NULL);
  532. +
  533. +        child_retval = 127;
  534. +
  535. +        goto done;
  536.      }
  537.  
  538.      (void)WaitForSingleObject(pi.hProcess, INFINITE);
  539. --
  540. 2.51.0
  541.  
  542. From 700c738ec1444e7bcedec131d3277b2d692fe9b2 Mon Sep 17 00:00:00 2001
  543. From: Roland Mainz <roland.mainz@nrubsig.org>
  544. Date: Tue, 9 Sep 2025 13:35:14 +0200
  545. Subject: [PATCH 06/12] tests: winrunassystem should print an error message if
  546.  called from non-admin user
  547.  
  548. winrunassystem should print an error message if called from non-admin user.
  549.  
  550. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  551. ---
  552. tests/winrunassystem/winrunassystem.c | 26 +++++++++++++++++++++++++-
  553.  1 file changed, 25 insertions(+), 1 deletion(-)
  554.  
  555. diff --git a/tests/winrunassystem/winrunassystem.c b/tests/winrunassystem/winrunassystem.c
  556. index c0e415c..68b2e30 100644
  557. --- a/tests/winrunassystem/winrunassystem.c
  558. +++ b/tests/winrunassystem/winrunassystem.c
  559. @@ -127,6 +127,22 @@ ULONG _cdecl RASDbgPrint(__in LPWSTR fmt, ...)
  560.  }
  561.  #endif /* DBG */
  562.  
  563. +static
  564. +bool isprocesselevated(void)
  565. +{
  566. +    bool isElevated = false;
  567. +    HANDLE hToken = GetCurrentProcessToken();
  568. +    TOKEN_ELEVATION elevation;
  569. +    DWORD cbSize = sizeof(elevation);
  570. +
  571. +    if (GetTokenInformation(hToken, TokenElevation,
  572. +        &elevation, cbSize, &cbSize)) {
  573. +        isElevated = elevation.TokenIsElevated?true:false;
  574. +    }
  575. +
  576. +    return isElevated;
  577. +}
  578. +
  579.  static
  580.  void ReportError(const char* context)
  581.  {
  582. @@ -605,9 +621,17 @@ int winrunassystem_main(int argc, wchar_t *argv[])
  583.          return 0;
  584.      }
  585.  
  586. -    /* Otherwise, run as the client to manage the service */
  587. +    /*
  588. +     * Otherwise, run as the client to manage the service
  589. +     */
  590.      D((void)wprintf(L"Running as client to install and start the service...\n"));
  591.  
  592. +    if (!isprocesselevated()) {
  593. +        (void)fwprintf(stderr,
  594. +            L"%ls: Requires Windows Adminstator permissions.\n", argv[0]);
  595. +        return EXIT_FAILURE;
  596. +    }
  597. +
  598.      SetupTemporaryServiceName();
  599.  
  600.      /* Remove old status file */
  601. --
  602. 2.51.0
  603.  
  604. From ffd290e5393b094acd89fea8761fa24c4bbd0118 Mon Sep 17 00:00:00 2001
  605. From: Roland Mainz <roland.mainz@nrubsig.org>
  606. Date: Thu, 11 Sep 2025 12:10:17 +0200
  607. Subject: [PATCH 07/12] build.vc19: Name cache should handle case-insensitive
  608.  filesystems
  609.  
  610. Name cache should handle case-insensitive filesystems.
  611. This implements case-insensitive UTF-8 file name comparisations via
  612. ICU.
  613.  
  614. Notes:
  615. - This still has issues related to the different Unicode versions
  616. and Unicode implementations on Windows, Windows libicu, NFS server
  617. and the exported filesystem on the NFS server side.
  618. - NTFS is only case-insensitive, but compares details like
  619. Frnech accents 1:1 as is, so we use |ucol_setStrength(cache->icu_coll,
  620. UCOL_SECONDARY)| for the Unicode collator to be compatible with NTFS.
  621. We might want to make this a mount option to choose between
  622. |UCOL_SECONDARY| and |UCOL_PRIMARY|.
  623.  
  624. Reported-by: Cedric Blancher <cedric.blancher@gmail.com>
  625. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  626. ---
  627. build.vc19/nfsd/nfsd.vcxproj |  12 +--
  628.  daemon/name_cache.c          | 138 +++++++++++++++++++++++++++++++++--
  629.  daemon/name_cache.h          |   8 +-
  630.  daemon/nfs41_superblock.c    |  17 +++++
  631.  4 files changed, 163 insertions(+), 12 deletions(-)
  632.  
  633. diff --git a/build.vc19/nfsd/nfsd.vcxproj b/build.vc19/nfsd/nfsd.vcxproj
  634. index 22e4f8b..7cfa57a 100644
  635. --- a/build.vc19/nfsd/nfsd.vcxproj
  636. +++ b/build.vc19/nfsd/nfsd.vcxproj
  637. @@ -148,7 +148,7 @@
  638.      <Link>
  639.        <SubSystem>Console</SubSystem>
  640.        <GenerateDebugInformation>true</GenerateDebugInformation>
  641. -      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;ntdll.lib;..\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  642. +      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;icu.lib;ntdll.lib;..\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  643.      </Link>
  644.    </ItemDefinitionGroup>
  645.    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
  646. @@ -174,7 +174,7 @@
  647.      <Link>
  648.        <SubSystem>Console</SubSystem>
  649.        <GenerateDebugInformation>true</GenerateDebugInformation>
  650. -      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  651. +      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;icu.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  652.      </Link>
  653.    </ItemDefinitionGroup>
  654.    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
  655. @@ -199,7 +199,7 @@
  656.      <Link>
  657.        <SubSystem>Console</SubSystem>
  658.        <GenerateDebugInformation>true</GenerateDebugInformation>
  659. -      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  660. +      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;icu.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  661.      </Link>
  662.    </ItemDefinitionGroup>
  663.    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
  664. @@ -226,7 +226,7 @@
  665.        <GenerateDebugInformation>true</GenerateDebugInformation>
  666.        <EnableCOMDATFolding>true</EnableCOMDATFolding>
  667.        <OptimizeReferences>true</OptimizeReferences>
  668. -      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;ntdll.lib;..\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  669. +      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;icu.lib;ntdll.lib;..\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  670.        <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
  671.      </Link>
  672.    </ItemDefinitionGroup>
  673. @@ -255,7 +255,7 @@
  674.        <GenerateDebugInformation>true</GenerateDebugInformation>
  675.        <EnableCOMDATFolding>true</EnableCOMDATFolding>
  676.        <OptimizeReferences>true</OptimizeReferences>
  677. -      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  678. +      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;icu.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  679.        <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
  680.      </Link>
  681.    </ItemDefinitionGroup>
  682. @@ -282,7 +282,7 @@
  683.        <GenerateDebugInformation>true</GenerateDebugInformation>
  684.        <EnableCOMDATFolding>true</EnableCOMDATFolding>
  685.        <OptimizeReferences>true</OptimizeReferences>
  686. -      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  687. +      <AdditionalDependencies>iphlpapi.lib;ws2_32.lib;wldap32.lib;icu.lib;ntdll.lib;..\$(Platform)\$(Configuration)\libtirpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
  688.        <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
  689.      </Link>
  690.    </ItemDefinitionGroup>
  691. diff --git a/daemon/name_cache.c b/daemon/name_cache.c
  692. index 202e466..f025983 100644
  693. --- a/daemon/name_cache.c
  694. +++ b/daemon/name_cache.c
  695. @@ -23,6 +23,7 @@
  696.  
  697.  #include <Windows.h>
  698.  #include <strsafe.h>
  699. +#include <icu.h>
  700.  #include <time.h>
  701.  
  702.  #include "nfs41_ops.h"
  703. @@ -502,6 +503,8 @@ static void copy_attrs(
  704.  
  705.  
  706.  /* name cache */
  707. +struct nfs41_name_cache;
  708. +
  709.  RB_HEAD(name_tree, name_cache_entry);
  710.  struct name_cache_entry {
  711.      char                    component[NFS41_MAX_COMPONENT_LEN+1];
  712. @@ -512,15 +515,13 @@ struct name_cache_entry {
  713.      struct name_cache_entry *parent;
  714.      struct list_entry       exp_entry;
  715.      util_reltimestamp         expiration;
  716. +    struct nfs41_name_cache *name_cache;
  717.      unsigned short          component_len;
  718.  };
  719.  #define NAME_ENTRY_SIZE sizeof(struct name_cache_entry)
  720.  
  721. -static int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs)
  722. -{
  723. -    const int diff = rhs->component_len - lhs->component_len;
  724. -    return diff ? diff : strncmp(lhs->component, rhs->component, lhs->component_len);
  725. -}
  726. +static int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs);
  727. +
  728.  RB_GENERATE(name_tree, name_cache_entry, rbnode, name_cmp)
  729.  
  730.  struct nfs41_name_cache {
  731. @@ -534,8 +535,86 @@ struct nfs41_name_cache {
  732.      uint32_t                delegations;
  733.      uint32_t                max_delegations;
  734.      SRWLOCK                 lock;
  735. +    bool                    casesensitivesearch;
  736. +    UCollator               *icu_coll;
  737.  };
  738.  
  739. +static
  740. +int icu_strcmpcoll(UCollator *coll, const char *str1, const char *str2, int32_t len)
  741. +{
  742. +    UErrorCode status = U_ZERO_ERROR;
  743. +    UCollationResult result;
  744. +
  745. +    result = ucol_strcollUTF8(coll, str1, len, str2, len, &status);
  746. +    if (U_FAILURE(status)) {
  747. +        eprintf("icu_strcmpcoll: "
  748. +            "ucol_strcollUTF8(str1='%s',str2='%s') returned status='%s'\n",
  749. +            u_errorName(status));
  750. +        return -1;
  751. +    }
  752. +
  753. +    switch (result) {
  754. +        case UCOL_LESS:
  755. +            return -1;
  756. +        case UCOL_EQUAL:
  757. +            return 0;
  758. +        case UCOL_GREATER:
  759. +            return 1;
  760. +    }
  761. +
  762. +    eprintf("icu_strcmpcoll: "
  763. +        "ucol_strcollUTF8(str1='%s',str2='%s') returned unexpected result=0x%lx\n",
  764. +        (long)result);
  765. +    return -1;
  766. +}
  767. +
  768. +static
  769. +int name_cmp(struct name_cache_entry *lhs, struct name_cache_entry *rhs)
  770. +{
  771. +    const int diff = rhs->component_len - lhs->component_len;
  772. +    int res;
  773. +
  774. +    if (diff != 0)
  775. +        return diff;
  776. +
  777. +    unsigned short clen = lhs->component_len;
  778. +
  779. +    if (lhs->name_cache->casesensitivesearch) {
  780. +        /* FIXME: Can we use |memcmp()| here ? */
  781. +        res = strncmp(lhs->component, rhs->component, clen);
  782. +    }
  783. +    else {
  784. +        res = icu_strcmpcoll(lhs->name_cache->icu_coll,
  785. +            lhs->component, rhs->component, (int32_t)clen);
  786. +
  787. +//#define DEBUG_CASEINSENSITIVE_NAMECMP 1
  788. +#ifdef DEBUG_CASEINSENSITIVE_NAMECMP
  789. +        int casesensitive_res;
  790. +
  791. +        /* FIXME: Can we use |memcmp()| here ? */
  792. +        casesensitive_res = strncmp(lhs->component, rhs->component,
  793. +            clen);
  794. +
  795. +        if (res != casesensitive_res) {
  796. +            /*
  797. +             * Explicitly call |clen| "byte_clen" in the output to make sure
  798. +             * people do not get confused, e.g. if |<Ae><ae>| has the same
  799. +             * terminal character width as "dir1
  800. +             */
  801. +            DPRINTF(0,
  802. +                ("name_cmp: "
  803. +                    "(lhs='%.*s',rhs='%.*s',byte_clen=%d), "
  804. +                    "res(=%d) != casesensitive_res(=%d)\n",
  805. +                    (int)clen, lhs->component,
  806. +                    (int)clen, rhs->component,
  807. +                    (int)clen,
  808. +                    res, casesensitive_res));
  809. +        }
  810. +#endif /* DEBUG_CASEINSENSITIVE_NAMECMP */
  811. +    }
  812. +
  813. +    return res;
  814. +}
  815.  
  816.  /* internal name cache functions used by the public name cache interface;
  817.   * these functions expect the caller to hold a lock on the cache */
  818. @@ -626,6 +705,9 @@ static int name_cache_entry_create(
  819.          list_add_tail(&cache->exp_entries, &entry->exp_entry);
  820.      }
  821.  
  822. +    /* Add back pointer to entry */
  823. +    entry->name_cache = cache;
  824. +
  825.      name_cache_entry_rename(entry, component);
  826.  
  827.      *entry_out = entry;
  828. @@ -755,6 +837,7 @@ static struct name_cache_entry* name_cache_search(
  829.      StringCchCopyNA(tmp.component, NFS41_MAX_COMPONENT_LEN+1,
  830.          component->name, component->len);
  831.      tmp.component_len = component->len;
  832. +    tmp.name_cache = cache;
  833.  
  834.      entry = RB_FIND(name_tree, &parent->rbchildren, &tmp);
  835.      if (entry) {
  836. @@ -911,6 +994,33 @@ int nfs41_name_cache_create(
  837.          goto out;
  838.      }
  839.  
  840. +    /*
  841. +     * We need to set this to the real value later, once we have the value
  842. +     * of the |FATTR4_WORD0_CASE_INSENSITIVE| attribute...
  843. +     * FIXME: This is suboptimal...
  844. +     */
  845. +    cache->casesensitivesearch = false;
  846. +
  847. +    UErrorCode xstatus = U_ZERO_ERROR;
  848. +    cache->icu_coll = ucol_open("en_US", &xstatus);
  849. +    if (U_FAILURE(xstatus)) {
  850. +        eprintf("nfs41_name_cache_create: "
  851. +            "ucol_open() failued with icu_error='%s'\n",
  852. +            u_errorName(xstatus));
  853. +        goto out_err_cache;
  854. +    }
  855. +
  856. +
  857. +    /*
  858. +     * FIXME: Which strength should be use ?
  859. +     * - |UCOL_SECONDARY| --> ignore case, keep accents
  860. +     * - |UCOL_PRIMARY|   --> ignore case AND accents
  861. +     *
  862. +     * NTFS is case-insensitive by default but compares accents 1:1,
  863. +     * so we stick with |UCOL_SECONDARY|
  864. +     */
  865. +    ucol_setStrength(cache->icu_coll, UCOL_SECONDARY);
  866. +
  867.      list_init(&cache->exp_entries);
  868.      cache->expiration = NAME_CACHE_EXPIRATION;
  869.      cache->max_entries = NAME_CACHE_MAX_ENTRIES;
  870. @@ -936,6 +1046,9 @@ out:
  871.  out_err_pool:
  872.      free(cache->pool);
  873.  out_err_cache:
  874. +    if (cache->icu_coll) {
  875. +        ucol_close(cache->icu_coll);
  876. +    }
  877.      free(cache);
  878.      goto out;
  879.  }
  880. @@ -951,6 +1064,11 @@ int nfs41_name_cache_free(
  881.      /* free the attribute cache */
  882.      attr_cache_free(&cache->attributes);
  883.  
  884. +    /* free the ICU object */
  885. +    if (cache->icu_coll) {
  886. +        ucol_close(cache->icu_coll);
  887. +    }
  888. +
  889.      /* free the name entry pool */
  890.      free(cache->pool);
  891.      free(cache);
  892. @@ -958,6 +1076,16 @@ int nfs41_name_cache_free(
  893.      return status;
  894.  }
  895.  
  896. +void nfs41_name_cache_set_casesensitivesearch(
  897. +    IN struct nfs41_name_cache *cache,
  898. +    IN bool casesensitivesearch)
  899. +{
  900. +    cache->casesensitivesearch = casesensitivesearch;
  901. +    DPRINTF(1,
  902. +        ("nfs41_name_cache_set_casesensitivesearch: casesensitivesearch=%d\n",
  903. +        (int)casesensitivesearch));
  904. +}
  905. +
  906.  static __inline void copy_fh(
  907.      OUT nfs41_fh *dst,
  908.      IN OPTIONAL const struct name_cache_entry *src)
  909. diff --git a/daemon/name_cache.h b/daemon/name_cache.h
  910. index f7399e1..ff7fb00 100644
  911. --- a/daemon/name_cache.h
  912. +++ b/daemon/name_cache.h
  913. @@ -1,8 +1,10 @@
  914.  /* NFSv4.1 client for Windows
  915. - * Copyright (C) 2012 The Regents of the University of Michigan
  916. + * Copyright (C) 2012 The Regents of the University of Michigan
  917. + * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
  918.   *
  919.   * Olga Kornievskaia <aglo@umich.edu>
  920.   * Casey Bodley <cbodley@umich.edu>
  921. + * Roland Mainz <roland.mainz@nrubsig.org>
  922.   *
  923.   * This library is free software; you can redistribute it and/or modify it
  924.   * under the terms of the GNU Lesser General Public License as published by
  925. @@ -54,6 +56,10 @@ int nfs41_attr_cache_update(
  926.  int nfs41_name_cache_create(
  927.      OUT struct nfs41_name_cache **cache_out);
  928.  
  929. +void nfs41_name_cache_set_casesensitivesearch(
  930. +    IN struct nfs41_name_cache *cache,
  931. +    IN bool casesensitivesearch);
  932. +
  933.  int nfs41_name_cache_free(
  934.      IN OUT struct nfs41_name_cache **cache_out);
  935.  
  936. diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
  937. index eb8a938..3689fe5 100644
  938. --- a/daemon/nfs41_superblock.c
  939. +++ b/daemon/nfs41_superblock.c
  940. @@ -28,6 +28,7 @@
  941.  #include "daemon_debug.h"
  942.  #include "nfs41.h"
  943.  #include "nfs41_ops.h"
  944. +#include "name_cache.h"
  945.  #include "from_kernel.h"
  946.  #include "nfs41_driver.h"
  947.  #include "util.h"
  948. @@ -124,8 +125,20 @@ static int get_superblock_attrs(
  949.      superblock->link_support = info.link_support;
  950.      superblock->symlink_support = info.symlink_support;
  951.      superblock->ea_support = supports_named_attrs;
  952. +//#define TEST_LINUX_FORCE_FAT32 1
  953. +#ifdef TEST_LINUX_FORCE_FAT32
  954. +    /*
  955. +     * Testing-ONLY: Force FAT32 behaviour, because Linux nfsd returns
  956. +     * |info.case_insensitive==0| even on FAT32
  957. +     * Windows Server 2019 nfsd and OpenText nfsd do this correctly
  958. +     */
  959. +    DPRINTF(0, ("get_superblock_attrs: TEST_LINUX_FORCE_FAT32 enabled!\n"));
  960. +    superblock->case_preserving = 0/*info.case_preserving*/;
  961. +    superblock->case_insensitive = 1/*info.case_insensitive*/;
  962. +#else
  963.      superblock->case_preserving = info.case_preserving;
  964.      superblock->case_insensitive = info.case_insensitive;
  965. +#endif /* TEST_FS_FORCE_FAT32 */
  966.      superblock->sparse_file_support = 1; /* always ON for now */
  967.      if (session->client->root->nfsminorvers >= 2) {
  968.          superblock->block_clone_support = 1;
  969. @@ -134,6 +147,10 @@ static int get_superblock_attrs(
  970.          superblock->block_clone_support = 0;
  971.      }
  972.  
  973. +    nfs41_name_cache_set_casesensitivesearch(
  974. +        session->client->server->name_cache,
  975. +        superblock->case_insensitive?false:true);
  976. +
  977.      if (bitmap_isset(&info.attrmask, 0, FATTR4_WORD0_CANSETTIME))
  978.          superblock->cansettime = info.cansettime;
  979.      else /* cansettime is not supported, try setting them anyway */
  980. --
  981. 2.51.0
  982.  
  983. From dd0e776517cc1229451d8493c5456edff9b23459 Mon Sep 17 00:00:00 2001
  984. From: Cedric Blancher <cedric.blancher@gmail.com>
  985. Date: Thu, 11 Sep 2025 12:24:01 +0200
  986. Subject: [PATCH 08/12] tests: nfs_server_setup: FAT test filesystem setup: Add
  987.  ",fmask=0000,dmask=0000" mount options
  988.  
  989. nfs_server_setup: FAT test filesystem setup: Add ",fmask=0000,dmask=0000"
  990. mount options - FAT does not have uid/gid support, so all users/groups
  991. should get the same r/w flags.
  992.  
  993. Signed-off-by: Roland Mainz <roland.mainz@nrubsig.org>
  994. ---
  995. tests/nfs_server_setup.txt | 4 ++--
  996.  1 file changed, 2 insertions(+), 2 deletions(-)
  997.  
  998. diff --git a/tests/nfs_server_setup.txt b/tests/nfs_server_setup.txt
  999. index 2a5e7af..825bffa 100644
  1000. --- a/tests/nfs_server_setup.txt
  1001. +++ b/tests/nfs_server_setup.txt
  1002. @@ -47,8 +47,8 @@ mkfs.fat -F 32 '/bigdisk/fat32_image.img'
  1003.  mkdir /fat32_mount
  1004.  chmod -R a+rwx /fat32_mount
  1005.  chown 65534:65534 /fat32_mount
  1006. -#mount -o loop,uid=65534,gid=65534 /bigdisk/fat32_image.img /fat32_mount
  1007. -echo '/bigdisk/fat32_image.img /fat32_mount fat loop,uid=65534,gid=65534 0 0' >>'/etc/fstab'
  1008. +#mount -o loop,uid=65534,gid=65534,fmask=0000,dmask=0000 /bigdisk/fat32_image.img /fat32_mount
  1009. +echo '/bigdisk/fat32_image.img /fat32_mount fat loop,uid=65534,gid=65534,fmask=0000,dmask=0000 0 0' >>'/etc/fstab'
  1010.  mount /fat32_mount
  1011.  echo '/fat32_mount *(sec=sys,rw,async,insecure,all_squash,anonuid=65534,anongid=65534,fsid=5272429)' >>'/etc/exports'
  1012.  service nfs-server restart
  1013. --
  1014. 2.51.0
  1015.  
  1016. From 994bcbd482f2402e1b9e5b3fce526f5bd40f2c75 Mon Sep 17 00:00:00 2001
  1017. From: Cedric Blancher <cedric.blancher@gmail.com>
  1018. Date: Thu, 11 Sep 2025 12:26:19 +0200
  1019. Subject: [PATCH 09/12] tests: nfs_server_setup: Use "vfat" and not "fat" in
  1020.  /etc/fstab
  1021.  
  1022. Use "vfat" and not "fat" in /etc/fstab. Not all Linux versions
  1023. support the "fat" alias for "vfat".
  1024.  
  1025. Signed-off-by: Roland Mainz <roland.mainz@nrubsig.org>
  1026. ---
  1027. tests/nfs_server_setup.txt | 2 +-
  1028.  1 file changed, 1 insertion(+), 1 deletion(-)
  1029.  
  1030. diff --git a/tests/nfs_server_setup.txt b/tests/nfs_server_setup.txt
  1031. index 825bffa..ba86526 100644
  1032. --- a/tests/nfs_server_setup.txt
  1033. +++ b/tests/nfs_server_setup.txt
  1034. @@ -48,7 +48,7 @@ mkdir /fat32_mount
  1035.  chmod -R a+rwx /fat32_mount
  1036.  chown 65534:65534 /fat32_mount
  1037.  #mount -o loop,uid=65534,gid=65534,fmask=0000,dmask=0000 /bigdisk/fat32_image.img /fat32_mount
  1038. -echo '/bigdisk/fat32_image.img /fat32_mount fat loop,uid=65534,gid=65534,fmask=0000,dmask=0000 0 0' >>'/etc/fstab'
  1039. +echo '/bigdisk/fat32_image.img /fat32_mount vfat loop,uid=65534,gid=65534,fmask=0000,dmask=0000 0 0' >>'/etc/fstab'
  1040.  mount /fat32_mount
  1041.  echo '/fat32_mount *(sec=sys,rw,async,insecure,all_squash,anonuid=65534,anongid=65534,fsid=5272429)' >>'/etc/exports'
  1042.  service nfs-server restart
  1043. --
  1044. 2.51.0
  1045.  
  1046. From 7f1f4ca468d07f5c43c0e6c531a410882b5efac4 Mon Sep 17 00:00:00 2001
  1047. From: Roland Mainz <roland.mainz@nrubsig.org>
  1048. Date: Thu, 11 Sep 2025 18:09:43 +0200
  1049. Subject: [PATCH 10/12] daemon: |nfs41_superblock.aclsupport| should be able to
  1050.  store all |ACL4_SUPPORT_*| flags
  1051.  
  1052. |nfs41_superblock.aclsupport| should be able to store all |ACL4_SUPPORT_*|
  1053. flags. Just three bits is not enough.
  1054.  
  1055. Reported-by: Lionel Cons <Lionelcons1972@gmail.com>
  1056. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  1057. ---
  1058. daemon/nfs41.h | 2 +-
  1059.  1 file changed, 1 insertion(+), 1 deletion(-)
  1060.  
  1061. diff --git a/daemon/nfs41.h b/daemon/nfs41.h
  1062. index 242417e..670ce9c 100644
  1063. --- a/daemon/nfs41.h
  1064. +++ b/daemon/nfs41.h
  1065. @@ -50,8 +50,8 @@ typedef struct __nfs41_superblock {
  1066.      uint64_t maxwrite;
  1067.  
  1068.      /* constant filesystem attributes */
  1069. +    uint32_t aclsupport; /* |ACL4_SUPPORT_*| */
  1070.      unsigned int layout_types : 3;
  1071. -    unsigned int aclsupport : 3;
  1072.      unsigned int cansettime : 1;
  1073.      unsigned int link_support : 1;
  1074.      unsigned int symlink_support : 1;
  1075. --
  1076. 2.51.0
  1077.  
  1078. From 21640bb60b25f4563b8995dbc7623e03ff2b2e0d Mon Sep 17 00:00:00 2001
  1079. From: Roland Mainz <roland.mainz@nrubsig.org>
  1080. Date: Thu, 11 Sep 2025 19:22:37 +0200
  1081. Subject: [PATCH 11/12] daemon: Log superblock info about supported filesystem
  1082.  features
  1083.  
  1084. Log superblock info about supported filesystem features.
  1085.  
  1086. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  1087. ---
  1088. daemon/nfs41_superblock.c | 57 +++++++++++++++++++++++++++++++++++++++
  1089.  1 file changed, 57 insertions(+)
  1090.  
  1091. diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c
  1092. index 3689fe5..23b4024 100644
  1093. --- a/daemon/nfs41_superblock.c
  1094. +++ b/daemon/nfs41_superblock.c
  1095. @@ -175,6 +175,63 @@ static int get_superblock_attrs(
  1096.  
  1097.      nfs41_superblock_supported_attrs(superblock, &superblock->default_getattr);
  1098.  
  1099. +    /*
  1100. +     * Print infos for admins
  1101. +     */
  1102. +    char infobuff[256];
  1103. +    char *is;
  1104. +
  1105. +    /* ACL info */
  1106. +    if (superblock->aclsupport) {
  1107. +        is = infobuff;
  1108. +        *is = '\0';
  1109. +        if (bitmap_isset(&superblock->supported_attrs, 0, FATTR4_WORD0_ACL)) {
  1110. +            is = stpcpy(is, "ACL");
  1111. +        }
  1112. +        if (bitmap_isset(&superblock->supported_attrs, 1, FATTR4_WORD1_DACL)) {
  1113. +            if (is != infobuff)
  1114. +                *is++ = ',';
  1115. +            is = stpcpy(is, "DACL");
  1116. +        }
  1117. +        if (bitmap_isset(&superblock->supported_attrs, 1, FATTR4_WORD1_SACL)) {
  1118. +            if (is != infobuff)
  1119. +                *is++ = ',';
  1120. +            is = stpcpy(is, "SACL");
  1121. +        }
  1122. +
  1123. +        logprintf("get_superblock_attrs: Supported ACL types: { %s }\n",
  1124. +            infobuff);
  1125. +    }
  1126. +    else {
  1127. +        logprintf("get_superblock_attrs: No ACL support\n");
  1128. +    }
  1129. +
  1130. +    /* Windows/DOS attributes */
  1131. +    is = infobuff;
  1132. +    *is = '\0';
  1133. +    if (bitmap_isset(&superblock->supported_attrs, 0, FATTR4_WORD0_HIDDEN)) {
  1134. +        is = stpcpy(is, "HIDDEN");
  1135. +    }
  1136. +    if (bitmap_isset(&superblock->supported_attrs, 0, FATTR4_WORD0_ARCHIVE)) {
  1137. +        if (is != infobuff)
  1138. +            *is++ = ',';
  1139. +        is = stpcpy(is, "ARCHIVE");
  1140. +    }
  1141. +    if (bitmap_isset(&superblock->supported_attrs, 1, FATTR4_WORD1_SYSTEM)) {
  1142. +        if (is != infobuff)
  1143. +            *is++ = ',';
  1144. +        is = stpcpy(is, "SYSTEM");
  1145. +    }
  1146. +    logprintf("get_superblock_attrs: "
  1147. +        "Supported Windows/DOS attributes: { %s }\n",
  1148. +        infobuff);
  1149. +
  1150. +    /* Filename case handling */
  1151. +    logprintf("get_superblock_attrs: "
  1152. +        "Case handling: case_insensitive=%d, case_preserving=%d\n",
  1153. +        (int)superblock->case_insensitive,
  1154. +        (int)superblock->case_preserving);
  1155. +
  1156.      DPRINTF(SBLVL, ("attributes for fsid(%llu,%llu): "
  1157.          "maxread=%llu, maxwrite=%llu, layout_types: 0x%X, "
  1158.          "cansettime=%u, time_delta={%llu,%u}, aclsupport=%u, "
  1159. --
  1160. 2.51.0
  1161.  
  1162. From de4e8fb4c4790a295c8547643403e07d92956d9d Mon Sep 17 00:00:00 2001
  1163. From: Cedric Blancher <cedric.blancher@gmail.com>
  1164. Date: Thu, 11 Sep 2025 20:00:40 +0200
  1165. Subject: [PATCH 12/12] tests: nfs_server_setup: Add instructions how to set up
  1166.  a case-insensitive ext4 share
  1167.  
  1168. nfs_server_setup: Add instructions how to set up a case-insensitive ext4
  1169. share with Linux nfsd.
  1170.  
  1171. Signed-off-by: Roland Mainz <roland.mainz@nrubsig.org>
  1172. ---
  1173. tests/nfs_server_setup.txt | 22 ++++++++++++++++++++++
  1174.  1 file changed, 22 insertions(+)
  1175.  
  1176. diff --git a/tests/nfs_server_setup.txt b/tests/nfs_server_setup.txt
  1177. index ba86526..00f802d 100644
  1178. --- a/tests/nfs_server_setup.txt
  1179. +++ b/tests/nfs_server_setup.txt
  1180. @@ -55,6 +55,28 @@ service nfs-server restart
  1181.  ---- snip ----
  1182.  
  1183.  
  1184. +##### 4. Setup a 32GB EXT4 filesystem in case-INSENSITIVE mode for testing:
  1185. +# * Notes:
  1186. +# - requires CONFIG_UNICODE in the kernel, otherwise mount will FAIL
  1187. +# - Linux nfsd has a bug which will report FATTR4_WORD0_CASE_INSENSITIVE==0 even
  1188. +# if the filesystem is case-insensitive (FATTR4_WORD0_CASE_INSENSITIVE and
  1189. +# FATTR4_WORD0_CASE_PRESERVING are currently hardcoded in Linux nfsd)
  1190. +---- snip ----
  1191. +dd if='/dev/zero' of='/bigdisk/ext4_caseinsensitive_image.img' bs=$((1024*1024)) count=$((32*1024))
  1192. +mkfs.ext4 -O casefold -E encoding=utf8 /bigdisk/ext4_caseinsensitive_image.img
  1193. +mkdir /ext4caseinsensitive
  1194. +chmod -R a+rwx /ext4caseinsensitive
  1195. +echo '/bigdisk/ext4_caseinsensitive_image.img /ext4caseinsensitive ext4 loop 0 0' >>'/etc/fstab'
  1196. +mount /ext4caseinsensitive
  1197. +mkdir /ext4caseinsensitive/nfsexport
  1198. +# chattr +F is inherited by subdirs (of /ext4caseinsensitive/nfsexport) automatically
  1199. +chattr +F /ext4caseinsensitive/nfsexport
  1200. +chmod a+rwxt /ext4caseinsensitive/nfsexport
  1201. +echo '/ext4caseinsensitive/nfsexport *(sec=sys,rw,async,insecure,no_root_squash,fsid=3272524)' >>'/etc/exports'
  1202. +service nfs-server restart
  1203. +---- snip ----
  1204. +
  1205. +
  1206.  #
  1207.  # Windows Server 2019 NFSv4.1 server setup
  1208.  #
  1209. --
  1210. 2.51.0

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.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at