pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: Patch for UNC path support, 2023-11-30
Posted by Anonymous on Thu 30th Nov 2023 16:26
raw | new post

  1. From e612e88abedbe9439ce6cfd6146d0883df87ad9c Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Thu, 30 Nov 2023 16:15:01 +0100
  4. Subject: [PATCH] sys/nfs41_driver,mount: Add support for UNC+Cygwin UNC paths
  5.  
  6. Add support for UNC paths (e.g. \\server@port\nfs4\path).
  7.  
  8. This requires that the matching share has been mounted with
  9. nfs_mount.exe first, so the mount attributes are available for the
  10. NFSv4 filesystem.
  11.  
  12. Example usage for Cygwin:
  13. ---- snip ----
  14. $ nfs_mount -p -o rw,sec=sys T derfwnb4966_ipv6:/net_tmpfs2
  15. ...
  16.  
  17. $ ls -l //derfwnb4966_ipv6@2049/nfs4/net_tmpfs2/test1
  18. total 1386
  19. drwxr-xr-x 14 Unix_User+768 Unix_Group+7121 3860 Nov 30 13:43 bash
  20. drwxr-xr-x  4 Unix_User+768 Unix_Group+7121   80 Nov 17 11:16 chtontest
  21. drwxr-xr-x  4 Unix_User+768 Unix_Group+7121  100 Nov 10 12:00 ksh
  22. drwxr-xr-x  3 Unix_User+768 Unix_Group+7121   60 Nov 13 16:16 msnfs41clientbuild
  23.  
  24. $ cd '//derfwnb4966_ipv6@2049/nfs4/net_tmpfs2/test1'
  25. $ ls -l
  26. total 1386
  27. drwxr-xr-x 14 Unix_User+768 Unix_Group+7121 3860 Nov 30 13:43 bash
  28. drwxr-xr-x  4 Unix_User+768 Unix_Group+7121   80 Nov 17 11:16 chtontest
  29. drwxr-xr-x  4 Unix_User+768 Unix_Group+7121  100 Nov 10 12:00 ksh
  30. drwxr-xr-x  3 Unix_User+768 Unix_Group+7121   60 Nov 13 16:16 msnfs41clientbuild
  31.  
  32. $ fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1
  33. $ cmd /c 'mklink /d c:\mnt \\derfwnb4966_ipv6@2049\nfs4\net_tmpfs2\'
  34. $ ls -l /cygdrive/c/mnt
  35. lrwxrwxrwx 1 rmainz Kein 40 Nov 30 12:15 /cygdrive/c/mnt -> //derfwnb4966_ipv6@2049/nfs4/net_tmpfs2/
  36.  
  37. $ nfs_mount
  38. Listing 'NFS41 Network' mounts:
  39.  
  40. Volume  Remote path                                Cygwin UNC path
  41. (null)  \\derfwpc5131_ipv6@2049\export\home\rmainz //derfwpc5131_ipv6@2049/nfs4/export/home/rmainz
  42. (null)  \\derfwnb4966_ipv6@2049\net_tmpfs2         //derfwnb4966_ipv6@2049/nfs4/net_tmpfs2
  43. (null)  \\derfwnb4966_ipv6@2049\net_tmpfs2\test2   //derfwnb4966_ipv6@2049/nfs4/net_tmpfs2/test2
  44. ---- snip ----
  45.  
  46. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  47. ---
  48. cygwin/devel/msnfs41client.bash |   5 +
  49.  mount/enum.c                    |  30 +++++-
  50.  sys/nfs41_driver.c              | 169 ++++++++++++++++++++++++--------
  51.  3 files changed, 161 insertions(+), 43 deletions(-)
  52.  
  53. diff --git a/cygwin/devel/msnfs41client.bash b/cygwin/devel/msnfs41client.bash
  54. index 478f7f6..cafd82e 100644
  55. --- a/cygwin/devel/msnfs41client.bash
  56. +++ b/cygwin/devel/msnfs41client.bash
  57. @@ -78,6 +78,11 @@ function nfsclient_install
  58.         cp etc_netconfig /cygdrive/c/etc/netconfig
  59.         cp ms-nfs41-idmap.conf /cygdrive/c/etc/.
  60.  
  61. +       # enable symlink lookup
  62. +       # and then print the status
  63. +       fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1
  64. +       fsutil behavior query SymlinkEvaluation
  65. +
  66.         # make sure we can load the kernel driver
  67.         # (does not work with SecureBoot)
  68.         bcdedit /set testsigning on
  69. diff --git a/mount/enum.c b/mount/enum.c
  70. index c0de2bb..e6c2281 100644
  71. --- a/mount/enum.c
  72. +++ b/mount/enum.c
  73. @@ -22,6 +22,7 @@
  74.  #include <Windows.h>
  75.  #include <tchar.h>
  76.  #include <stdio.h>
  77. +#include <malloc.h>
  78.  
  79.  #include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */
  80.  
  81. @@ -34,7 +35,29 @@ void PrintMountLine(
  82.      LPCTSTR local,
  83.      LPCTSTR remote)
  84.  {
  85. -    _tprintf(TEXT("%-11s %s\n"), local, remote);
  86. +    TCHAR *cygwin_unc_buffer = alloca((_tcslen(remote)+32)*sizeof(TCHAR));
  87. +    TCHAR *b = cygwin_unc_buffer;
  88. +    LPCTSTR s = remote;
  89. +    TCHAR sc;
  90. +    unsigned int backslash_counter = 0;
  91. +
  92. +    while((sc = *s++) != TEXT('\0')) {
  93. +        switch(sc) {
  94. +            case TEXT('\\'):
  95. +                *b++ = TEXT('/');
  96. +                if (backslash_counter++ == 2) {
  97. +                    (void)wcscpy_s(b, 6, TEXT("nfs4/"));
  98. +                    b+=5;
  99. +                }
  100. +                break;
  101. +            default:
  102. +                *b++ = sc;
  103. +                break;
  104. +        }
  105. +    }
  106. +    *b = TEXT('\0');
  107. +
  108. +    _tprintf(TEXT("%-8s\t%-40s\t%s\n"), local, remote, cygwin_unc_buffer);
  109.  }
  110.  
  111.  /* ENUM_RESOURCE_BUFFER_SIZE
  112. @@ -66,8 +89,9 @@ DWORD EnumMounts(
  113.      if (result)
  114.          goto out_free;
  115.  
  116. -    _tprintf(TEXT("Listing %s mounts:\n\n"), TEXT(NFS41_PROVIDER_NAME_A));
  117. -    PrintMountLine(TEXT("Volume"), TEXT("Remote path"));
  118. +    _tprintf(TEXT("Listing '%s' mounts:\n\n"), TEXT(NFS41_PROVIDER_NAME_A));
  119. +    _tprintf(TEXT("%-8s\t%-40s\t%s\n"), TEXT("Volume"), TEXT("Remote path"), TEXT("Cygwin UNC path"));
  120. +
  121.      do
  122.      {
  123.          dwCount = (DWORD)-1;
  124. diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c
  125. index 526b064..16e1957 100644
  126. --- a/sys/nfs41_driver.c
  127. +++ b/sys/nfs41_driver.c
  128. @@ -260,6 +260,40 @@ typedef struct _updowncall_list {
  129.  } nfs41_updowncall_list;
  130.  nfs41_updowncall_list upcall, downcall;
  131.  
  132. +
  133. +
  134. +/* In order to cooperate with other network providers,
  135. + * we only claim paths of the format '\\server\nfs4\path' */
  136. +DECLARE_CONST_UNICODE_STRING(NfsPrefix, L"\\nfs4");
  137. +DECLARE_CONST_UNICODE_STRING(AUTH_SYS_NAME, L"sys");
  138. +DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5_NAME, L"krb5");
  139. +DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5I_NAME, L"krb5i");
  140. +DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5P_NAME, L"krb5p");
  141. +DECLARE_CONST_UNICODE_STRING(SLASH, L"\\");
  142. +DECLARE_CONST_UNICODE_STRING(EMPTY_STRING, L"");
  143. +
  144. +#define SERVER_NAME_BUFFER_SIZE         1024
  145. +#define MOUNT_CONFIG_RW_SIZE_MIN        1024
  146. +#define MOUNT_CONFIG_RW_SIZE_DEFAULT    1048576
  147. +#define MOUNT_CONFIG_RW_SIZE_MAX        1048576
  148. +#define MAX_SEC_FLAVOR_LEN              12
  149. +#define UPCALL_TIMEOUT_DEFAULT          50  /* in seconds */
  150. +
  151. +typedef struct _NFS41_MOUNT_CONFIG {
  152. +    DWORD ReadSize;
  153. +    DWORD WriteSize;
  154. +    BOOLEAN ReadOnly;
  155. +    BOOLEAN write_thru;
  156. +    BOOLEAN nocache;
  157. +    WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE];
  158. +    UNICODE_STRING SrvName; /* hostname, or hostname@port */
  159. +    WCHAR mntpt_buffer[MAX_PATH];
  160. +    UNICODE_STRING MntPt;
  161. +    WCHAR sec_flavor[MAX_SEC_FLAVOR_LEN];
  162. +    UNICODE_STRING SecFlavor;
  163. +    DWORD timeout;
  164. +} NFS41_MOUNT_CONFIG, *PNFS41_MOUNT_CONFIG;
  165. +
  166.  typedef struct _nfs41_mount_entry {
  167.      LIST_ENTRY next;
  168.      LUID login_id;
  169. @@ -267,6 +301,7 @@ typedef struct _nfs41_mount_entry {
  170.      HANDLE gss_session;
  171.      HANDLE gssi_session;
  172.      HANDLE gssp_session;
  173. +    NFS41_MOUNT_CONFIG Config;
  174.  } nfs41_mount_entry;
  175.  
  176.  typedef struct _nfs41_mount_list {
  177. @@ -310,37 +345,6 @@ typedef struct _nfs41_mount_list {
  178.                                    next)));                  \
  179.              ExReleaseFastMutex(&lock);
  180.  
  181. -/* In order to cooperate with other network providers,
  182. - * we only claim paths of the format '\\server\nfs4\path' */
  183. -DECLARE_CONST_UNICODE_STRING(NfsPrefix, L"\\nfs4");
  184. -DECLARE_CONST_UNICODE_STRING(AUTH_SYS_NAME, L"sys");
  185. -DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5_NAME, L"krb5");
  186. -DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5I_NAME, L"krb5i");
  187. -DECLARE_CONST_UNICODE_STRING(AUTHGSS_KRB5P_NAME, L"krb5p");
  188. -DECLARE_CONST_UNICODE_STRING(SLASH, L"\\");
  189. -DECLARE_CONST_UNICODE_STRING(EMPTY_STRING, L"");
  190. -
  191. -#define SERVER_NAME_BUFFER_SIZE         1024
  192. -#define MOUNT_CONFIG_RW_SIZE_MIN        1024
  193. -#define MOUNT_CONFIG_RW_SIZE_DEFAULT    1048576
  194. -#define MOUNT_CONFIG_RW_SIZE_MAX        1048576
  195. -#define MAX_SEC_FLAVOR_LEN              12
  196. -#define UPCALL_TIMEOUT_DEFAULT          50  /* in seconds */
  197. -
  198. -typedef struct _NFS41_MOUNT_CONFIG {
  199. -    DWORD ReadSize;
  200. -    DWORD WriteSize;
  201. -    BOOLEAN ReadOnly;
  202. -    BOOLEAN write_thru;
  203. -    BOOLEAN nocache;
  204. -    WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE];
  205. -    UNICODE_STRING SrvName; /* hostname, or hostname@port */
  206. -    WCHAR mntpt_buffer[MAX_PATH];
  207. -    UNICODE_STRING MntPt;
  208. -    WCHAR sec_flavor[MAX_SEC_FLAVOR_LEN];
  209. -    UNICODE_STRING SecFlavor;
  210. -    DWORD timeout;
  211. -} NFS41_MOUNT_CONFIG, *PNFS41_MOUNT_CONFIG;
  212.  
  213.  typedef struct _NFS41_NETROOT_EXTENSION {
  214.      NODE_TYPE_CODE          NodeTypeCode;
  215. @@ -475,6 +479,14 @@ nfs41_start_driver_state nfs41_start_state = NFS41_START_DRIVER_STARTABLE;
  216.  
  217.  NTSTATUS map_readwrite_errors(DWORD status);
  218.  
  219. +
  220. +void copy_nfs41_mount_config(NFS41_MOUNT_CONFIG *dest, NFS41_MOUNT_CONFIG *src)
  221. +{
  222. +    RtlCopyMemory(dest, src, sizeof(NFS41_MOUNT_CONFIG));
  223. +    dest->SrvName.Buffer = dest->srv_buffer;
  224. +    dest->MntPt.Buffer = dest->mntpt_buffer;
  225. +}
  226. +
  227.  void print_debug_header(
  228.      PRX_CONTEXT RxContext)
  229.  {
  230. @@ -2739,6 +2751,9 @@ NTSTATUS nfs41_MountConfig_ParseOptions(
  231.      IN ULONG EaLength,
  232.      IN OUT PNFS41_MOUNT_CONFIG Config)
  233.  {
  234. +    DbgP("--> nfs41_MountConfig_ParseOptions(EaBuffer=%p,EaLength=%ld)\n",
  235. +        (void *)EaBuffer,
  236. +        (long)EaLength);
  237.      NTSTATUS  status = STATUS_SUCCESS;
  238.      PFILE_FULL_EA_INFORMATION Option;
  239.      LPWSTR Name;
  240. @@ -2746,13 +2761,20 @@ NTSTATUS nfs41_MountConfig_ParseOptions(
  241.      UNICODE_STRING  usValue;
  242.      Option = EaBuffer;
  243.      while (status == STATUS_SUCCESS) {
  244. +        DbgP("Option=%p\n", (void *)Option);
  245.          Name = (LPWSTR)Option->EaName;
  246.          NameLen = Option->EaNameLength/sizeof(WCHAR);
  247.  
  248. +        DbgP("nfs41_MountConfig_ParseOptions: Name='%*S'/NameLen=%d\n",
  249. +            (int)NameLen, Name, (int)NameLen);
  250. +
  251.          usValue.Length = usValue.MaximumLength = Option->EaValueLength;
  252.          usValue.Buffer = (PWCH)(Option->EaName +
  253.              Option->EaNameLength + sizeof(WCHAR));
  254.  
  255. +        DbgP("nfs41_MountConfig_ParseOptions: option/usValue='%wZ'/%ld\n",
  256. +            &usValue, (long)usValue.Length);
  257. +
  258.          if (wcsncmp(L"ro", Name, NameLen) == 0) {
  259.              status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
  260.                  FALSE, &Config->ReadOnly);
  261. @@ -2834,6 +2856,7 @@ NTSTATUS nfs41_MountConfig_ParseOptions(
  262.              ((PBYTE)Option + Option->NextEntryOffset);
  263.      }
  264.  
  265. +    DbgP("<-- nfs41_MountConfig_ParseOptions, status=%ld\n", (long)status);
  266.      return status;
  267.  }
  268.  
  269. @@ -2996,27 +3019,88 @@ NTSTATUS nfs41_CreateVNetRoot(
  270.  
  271.      if (pCreateNetRootContext->RxContext->Create.EaLength) {
  272.          /* Codepath for nfs_mount.exe */
  273. +        DbgP("Codepath for nfs_mount.exe, Create->{ EaBuffer=%p, EaLength=%ld }\n",
  274. +            pCreateNetRootContext->RxContext->Create.EaBuffer,
  275. +            (long)pCreateNetRootContext->RxContext->Create.EaLength);
  276.  
  277.          /* parse the extended attributes for mount options */
  278.          status = nfs41_MountConfig_ParseOptions(
  279.              pCreateNetRootContext->RxContext->Create.EaBuffer,
  280.              pCreateNetRootContext->RxContext->Create.EaLength,
  281.              Config);
  282. -        if (status != STATUS_SUCCESS)
  283. +        if (status != STATUS_SUCCESS) {
  284. +            DbgP("nfs41_MountConfig_ParseOptions() failed\n");
  285.              goto out_free;
  286. +        }
  287.          pVNetRootContext->read_only = Config->ReadOnly;
  288.          pVNetRootContext->write_thru = Config->write_thru;
  289.          pVNetRootContext->nocache = Config->nocache;        
  290.      } else {
  291. -        /* Codepath for \\server:port\nfs4\path */
  292. -
  293. -        /* use the SRV_CALL name (without leading \) as the hostname */
  294. -        Config->SrvName.Buffer = pSrvCall->pSrvCallName->Buffer + 1;
  295. -        Config->SrvName.Length =
  296. -            pSrvCall->pSrvCallName->Length - sizeof(WCHAR);
  297. -        Config->SrvName.MaximumLength =
  298. -            pSrvCall->pSrvCallName->MaximumLength - sizeof(WCHAR);
  299. +        /* Codepath for \\server@port\nfs4\path */
  300. +        DbgP("Codepath for \\\\server@port\\nfs4\\path\n");
  301. +
  302. +        /*
  303. +         * gisburn: Fixme: Originally the code was using the
  304. +         * SRV_CALL name (without leading \) as the hostname
  305. +         * like this:
  306. +         * ---- snip ----
  307. +         * Config->SrvName.Buffer = pSrvCall->pSrvCallName->Buffer+1;
  308. +         * Config->SrvName.Length =
  309. +         *     pSrvCall->pSrvCallName->Length - sizeof(WCHAR);
  310. +         * Config->SrvName.MaximumLength =
  311. +         *     pSrvCall->pSrvCallName->MaximumLength - sizeof(WCHAR);
  312. +         * ---- snip ----
  313. +         * IMHO we should validate that the hostname in
  314. +         * |existing_mount->Config| below matches
  315. +         * |pSrvCall->pSrvCallName->Buffer|
  316. +         */
  317. +
  318. +        status = nfs41_GetLUID(&luid);
  319. +        if (status)
  320. +            goto out_free;
  321. +
  322. +        PLIST_ENTRY pEntry;
  323. +
  324. +        status = STATUS_OBJECT_NAME_NOT_FOUND;
  325. +
  326. +        ExAcquireFastMutex(&pNetRootContext->mountLock);
  327. +        pEntry = &pNetRootContext->mounts.head;
  328. +        pEntry = pEntry->Flink;
  329. +        while (pEntry != NULL) {
  330. +            existing_mount = (nfs41_mount_entry *)CONTAINING_RECORD(pEntry,
  331. +                    nfs41_mount_entry, next);
  332. +
  333. +            if (RtlEqualLuid(&luid, &existing_mount->login_id)) {
  334. +                /* found existing mount */
  335. +                copy_nfs41_mount_config(Config, &existing_mount->Config);
  336. +                DbgP("Found existing mount: Entry Config->MntPt='%wZ'\n",
  337. +                    &Config->MntPt);
  338. +                status = STATUS_SUCCESS;
  339. +                break;
  340. +            }
  341. +            if (pEntry->Flink == &pNetRootContext->mounts.head)
  342. +                break;
  343. +            pEntry = pEntry->Flink;
  344. +        }
  345. +        ExReleaseFastMutex(&pNetRootContext->mountLock);
  346. +
  347. +        if (status != STATUS_SUCCESS) {
  348. +            DbgP("No existing mount found\n");
  349. +            goto out_free;
  350. +        }
  351. +
  352. +        pVNetRootContext->read_only = Config->ReadOnly;
  353. +        pVNetRootContext->write_thru = Config->write_thru;
  354. +        pVNetRootContext->nocache = Config->nocache;
  355.      }
  356. +
  357. +    DbgP("Config->{ MntPt='%wZ', SrvName='%wZ', ReadOnly=%d, write_thru=%d, nocache=%d }\n",
  358. +        &Config->MntPt,
  359. +        &Config->SrvName,
  360. +        Config->ReadOnly?1:0,
  361. +        Config->write_thru?1:0,
  362. +        Config->nocache?1:0);
  363. +
  364.      pVNetRootContext->MountPathLen = Config->MntPt.Length;
  365.      pVNetRootContext->timeout = Config->timeout;
  366.  
  367. @@ -3127,6 +3211,11 @@ NTSTATUS nfs41_CreateVNetRoot(
  368.              entry->gssp_session = pVNetRootContext->session; break;
  369.          }
  370.          RtlCopyLuid(&entry->login_id, &luid);
  371. +        /*
  372. +         * Save mount config so we can use it for
  373. +         * \\server@port\nfs4\path mounts later
  374. +         */
  375. +        copy_nfs41_mount_config(&entry->Config, Config);
  376.          nfs41_AddEntry(pNetRootContext->mountLock,
  377.              pNetRootContext->mounts, entry);
  378.      } else if (!found_matching_flavor) {
  379. --
  380. 2.42.1

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