pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


Prototype nfs://-URL support
Posted by Anonymous on Wed 24th Jan 2024 13:04
raw | new post

  1. diff --git a/build.vc19/nfs_mount/nfs_mount.vcxproj b/build.vc19/nfs_mount/nfs_mount.vcxproj
  2. index 7ab83e0..2f91ab2 100644
  3. --- a/build.vc19/nfs_mount/nfs_mount.vcxproj
  4. +++ b/build.vc19/nfs_mount/nfs_mount.vcxproj
  5. @@ -161,9 +161,11 @@
  6.      <ClCompile Include="..\..\mount\enum.c" />
  7.      <ClCompile Include="..\..\mount\mount.c" />
  8.      <ClCompile Include="..\..\mount\options.c" />
  9. +    <ClCompile Include="..\..\mount\urlparser1.c" />
  10.    </ItemGroup>
  11.    <ItemGroup>
  12.      <ClInclude Include="..\..\mount\options.h" />
  13. +    <ClInclude Include="..\..\mount\urlparser1.h" />
  14.    </ItemGroup>
  15.    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  16.    <ImportGroup Label="ExtensionTargets">
  17. diff --git a/build.vc19/nfs_mount/nfs_mount.vcxproj.filters b/build.vc19/nfs_mount/nfs_mount.vcxproj.filters
  18. index de8db60..623fa7d 100644
  19. --- a/build.vc19/nfs_mount/nfs_mount.vcxproj.filters
  20. +++ b/build.vc19/nfs_mount/nfs_mount.vcxproj.filters
  21. @@ -24,10 +24,16 @@
  22.      <ClCompile Include="..\..\mount\options.c">
  23.        <Filter>Source Files</Filter>
  24.      </ClCompile>
  25. +    <ClCompile Include="..\..\mount\urlparser1.c">
  26. +      <Filter>Source Files</Filter>
  27. +    </ClCompile>
  28.    </ItemGroup>
  29.    <ItemGroup>
  30.      <ClInclude Include="..\..\mount\options.h">
  31.        <Filter>Header Files</Filter>
  32.      </ClInclude>
  33. +    <ClInclude Include="..\..\mount\urlparser1.h">
  34. +      <Filter>Header Files</Filter>
  35. +    </ClInclude>
  36.    </ItemGroup>
  37.  </Project>
  38. \ No newline at end of file
  39. diff --git a/mount/mount.c b/mount/mount.c
  40. index 2e229ca..07ff357 100644
  41. --- a/mount/mount.c
  42. +++ b/mount/mount.c
  43. @@ -34,6 +34,7 @@
  44.  
  45.  #include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */
  46.  #include "options.h"
  47. +#include "urlparser1.h"
  48.  
  49.  #define MOUNT_CONFIG_NFS_PORT_DEFAULT   2049
  50.  
  51. @@ -282,58 +283,87 @@ static DWORD ParseRemoteName(
  52.      wchar_t remotename[NFS41_SYS_MAX_PATH_LEN];
  53.      wchar_t *premotename = remotename;
  54.      wchar_t srvname[NFS41_SYS_MAX_PATH_LEN+1+32]; /* sizeof(hostname+'@'+integer) */
  55. +    url_parser_context *uctx = NULL;
  56.  
  57.      result = StringCchCopy(premotename, NFS41_SYS_MAX_PATH_LEN, pRemoteName);
  58.  
  59.      /*
  60. -     * gisburn: Fixme: Implement nfs://-URLS per RFC 2224 ("NFS URL
  61. +     * Support nfs://-URLS per RFC 2224 ("NFS URL
  62.       * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  63.       * including port support (nfs://hostname@port/path/...)
  64.       */
  65.      if (!wcsncmp(premotename, TEXT("nfs://"), 6)) {
  66. -        _ftprintf(stderr, TEXT("nfs://-URLs not supported yet.\n"));
  67. -        result = ERROR_NOT_SUPPORTED;
  68. -        goto out;
  69. -    }
  70. +        uctx = url_parser_create_context(premotename, 0);
  71. +        if (!uctx) {
  72. +            result = ERROR_NOT_ENOUGH_MEMORY;
  73. +            goto out;
  74. +        }
  75.  
  76. -    ConvertUnixSlashes(premotename);
  77. +        if (url_parser_parse(uctx) < 0) {
  78. +            result = ERROR_BAD_ARGUMENTS;
  79. +            (void)_ftprintf(stderr, TEXT("Error parsing nfs://-URL.\n"));
  80. +            goto out;
  81. +        }
  82.  
  83. -    /*
  84. -     * Remote hostname should not contain a '@' since we use this
  85. -     * to communicate the NFSv4 port number below
  86. -     * Use $ nfs_mount.exe -o port=portnumber ... # instead
  87. -     */
  88. -    if (_tcsrchr(premotename, TEXT('@'))) {
  89. -        _ftprintf(stderr, TEXT("Remote path should not contain '@', ")
  90. -           TEXT("use -o port=tcpportnum.\n"));
  91. -        result = ERROR_BAD_ARGUMENTS;
  92. -        goto out;
  93. -    }
  94. +        if (uctx->login.username || uctx->login.passwd) {
  95. +            result = ERROR_BAD_ARGUMENTS;
  96. +            (void)_ftprintf(stderr, TEXT("Username/Password are not defined for nfs://-URL.\n"));
  97. +            goto out;
  98. +        }
  99. +
  100. +        (void)wcscpy_s(premotename, NFS41_SYS_MAX_PATH_LEN,
  101. +            uctx->hostport.hostname);
  102.  
  103. -    if (FindOptionByName(TEXT("port"), pOptions, &port_option_val)) {
  104. -        wchar_t *port_value_wstr = (PTCH)(port_option_val->EaName + port_option_val->EaNameLength + sizeof(TCHAR));
  105. +        if (uctx->hostport.port != -1)
  106. +            port = uctx->hostport.port;
  107. +        else
  108. +            port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
  109.  
  110. -       port = _wtoi(port_value_wstr);
  111. -       if ((port < 1) || (port > 65535)) {
  112. -            result = ERROR_BAD_ARGUMENTS;
  113. -            goto out;
  114. -       }
  115. +        ConvertUnixSlashes(premotename);
  116. +        pEnd = uctx->path;
  117. +        ConvertUnixSlashes(pEnd);
  118.      }
  119.      else
  120.      {
  121. -        port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
  122. -    }
  123. +        ConvertUnixSlashes(premotename);
  124.  
  125. -    /* fail if the server name doesn't end with :\ */
  126. -    pEnd = _tcsrchr(premotename, TEXT(':'));
  127. -    if (pEnd == NULL || pEnd[1] != TEXT('\\')) {
  128. -        _ftprintf(stderr, TEXT("Failed to parse the remote path. ")
  129. -            TEXT("Expected 'hostname:\\path'.\n"));
  130. -        result = ERROR_BAD_ARGUMENTS;
  131. -        goto out;
  132. +        /*
  133. +         * Remote hostname should not contain a '@' since we use this
  134. +         * to communicate the NFSv4 port number below
  135. +         * Use $ nfs_mount.exe -o port=portnumber ... # instead
  136. +         */
  137. +        if (_tcsrchr(premotename, TEXT('@'))) {
  138. +            (void)_ftprintf(stderr, TEXT("Remote path should not contain '@', ")
  139. +                TEXT("use -o port=tcpportnum.\n"));
  140. +            result = ERROR_BAD_ARGUMENTS;
  141. +            goto out;
  142. +        }
  143. +
  144. +        if (FindOptionByName(TEXT("port"), pOptions, &port_option_val)) {
  145. +            wchar_t *port_value_wstr =
  146. +                (PTCH)(port_option_val->EaName + port_option_val->EaNameLength + sizeof(TCHAR));
  147. +
  148. +            port = _wtoi(port_value_wstr);
  149. +            if ((port < 1) || (port > 65535)) {
  150. +                result = ERROR_BAD_ARGUMENTS;
  151. +                goto out;
  152. +            }
  153. +        }
  154. +        else {
  155. +            port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
  156. +        }
  157. +
  158. +        /* fail if the server name doesn't end with :\ */
  159. +        pEnd = _tcsrchr(premotename, TEXT(':'));
  160. +        if (pEnd == NULL || pEnd[1] != TEXT('\\')) {
  161. +            (void)_ftprintf(stderr, TEXT("Failed to parse the remote path. ")
  162. +                TEXT("Expected 'hostname:\\path'.\n"));
  163. +            result = ERROR_BAD_ARGUMENTS;
  164. +            goto out;
  165. +        }
  166. +        *pEnd = TEXT('\0');
  167. +        ++pEnd;
  168.      }
  169. -    *pEnd = TEXT('\0');
  170. -    ++pEnd;
  171.  
  172.      /*
  173.       * Make sure that we do not pass raw IPv6 addresses to the kernel.
  174. @@ -415,6 +445,12 @@ static DWORD ParseRemoteName(
  175.          goto out;
  176.      }
  177.  
  178. +#if 0
  179. +        _ftprintf(stderr,
  180. +           TEXT("srvname='%s', mntpt='%s'\n"), srvname, pEnd);
  181. +        exit(0);
  182. +#endif
  183. +
  184.      if (!InsertOption(TEXT("srvname"), srvname, pOptions) ||
  185.          !InsertOption(TEXT("mntpt"), *pEnd ? pEnd : TEXT("\\"), pOptions)) {
  186.          result = ERROR_BAD_ARGUMENTS;
  187. @@ -447,6 +483,9 @@ static DWORD ParseRemoteName(
  188.      result = StringCchCopy(pParsedRemoteName, cchConnectionLen, srvname);
  189.  
  190.  out:
  191. +    if (uctx) {
  192. +        url_parser_free_context(uctx);
  193. +    }
  194.      return result;
  195.  }
  196.  
  197. diff --git a/mount/urlparser1.c b/mount/urlparser1.c
  198. new file mode 100644
  199. index 0000000..43af33b
  200. --- /dev/null
  201. +++ b/mount/urlparser1.c
  202. @@ -0,0 +1,193 @@
  203. +/* NFSv4.1 client for Windows
  204. + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
  205. + *
  206. + * This library is free software; you can redistribute it and/or modify it
  207. + * under the terms of the GNU Lesser General Public License as published by
  208. + * the Free Software Foundation; either version 2.1 of the License, or (at
  209. + * your option) any later version.
  210. + *
  211. + * This library is distributed in the hope that it will be useful, but
  212. + * without any warranty; without even the implied warranty of merchantability
  213. + * or fitness for a particular purpose.  See the GNU Lesser General Public
  214. + * License for more details.
  215. + *
  216. + * You should have received a copy of the GNU Lesser General Public License
  217. + * along with this library; if not, write to the Free Software Foundation,
  218. + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  219. + */
  220. +
  221. +
  222. +/* urlparser1.c - simple URL parser */
  223. +
  224. +#if ((__STDC_VERSION__-0) < 201710L)
  225. +#error Code requires ISO C17
  226. +#endif
  227. +
  228. +
  229. +#include <crtdbg.h>
  230. +#include <Windows.h>
  231. +#include <stdlib.h>
  232. +
  233. +#include "urlparser1.h"
  234. +
  235. +/*
  236. + * Disable "warning C4996: 'wcscpy': This function or variable may be
  237. + * unsafe." because in this case the buffers are properly sized,
  238. + * making this function safe
  239. + */
  240. +#pragma warning (disable : 4996)
  241. +
  242. +/*
  243. + * Original extended regular expression:
  244. + *
  245. + * "^"
  246. + * "(.+?)"                      // scheme
  247. + * "://"                        // '://'
  248. + * "("                          // login
  249. + *      "(?:"
  250. + *              "(.+?)"         // user (optional)
  251. + *              "(?::(.+))?"    // password (optional)
  252. + *              "@"
  253. + *      ")?"
  254. + *      "("                     // hostport
  255. + *              "(.+?)"         // host
  256. + *              "(?::([[:digit:]]+))?" // port (optional)
  257. + *      ")"
  258. + * ")"
  259. + * "(?:/(.*?))?"                // path (optional)
  260. + * "$"
  261. + */
  262. +
  263. +#define DBGNULLSTR(s) (((s)!=NULL)?(s):TEXT("<NULL>"))
  264. +#if 0
  265. +#define D(x) x
  266. +#else
  267. +#define D(x)
  268. +#endif
  269. +
  270. +url_parser_context *url_parser_create_context(const TCHAR *in_url, unsigned int flags)
  271. +{
  272. +       url_parser_context *uctx;
  273. +       TCHAR *s;
  274. +       size_t in_url_len;
  275. +       size_t context_len;
  276. +
  277. +       if (!in_url)
  278. +               return NULL;
  279. +
  280. +       in_url_len = _tcsclen(in_url);
  281. +
  282. +       context_len = sizeof(url_parser_context) +
  283. +               (((in_url_len+1)*5L*sizeof(TCHAR)));
  284. +       uctx = malloc(context_len);
  285. +       if (!uctx)
  286. +               return NULL;
  287. +
  288. +       s = (void *)(uctx+1);
  289. +       uctx->in_url = s;               s+= in_url_len+1;
  290. +       (void)_tcscpy(uctx->in_url, in_url);
  291. +       uctx->scheme = s;               s+= in_url_len+1;
  292. +       uctx->login.username = s;       s+= in_url_len+1;
  293. +       uctx->hostport.hostname = s;    s+= in_url_len+1;
  294. +       uctx->path = s;                 s+= in_url_len+1;
  295. +       uctx->hostport.port = -1;
  296. +
  297. +       return uctx;
  298. +}
  299. +
  300. +int url_parser_parse(url_parser_context *uctx)
  301. +{
  302. +       D((void)_tprintf(TEXT("## parser in_url='%s'\n"), uctx->in_url));
  303. +
  304. +       TCHAR *s;
  305. +       const TCHAR *urlstr = uctx->in_url;
  306. +       size_t slen;
  307. +
  308. +       s = _tcsstr(urlstr, TEXT("://"));
  309. +       if (!s) {
  310. +               D((void)_tprintf(TEXT("url_parser: Not an URL\n")));
  311. +               return -1;
  312. +       }
  313. +
  314. +       slen = s-urlstr;
  315. +       (void)memcpy(uctx->scheme, urlstr, slen*sizeof(TCHAR));
  316. +       uctx->scheme[slen] = TEXT('\0');
  317. +       urlstr += slen + 3;
  318. +
  319. +       D((void)_tprintf(TEXT("scheme='%s', rest='%s'\n"), uctx->scheme, urlstr));
  320. +
  321. +       s = _tcsstr(urlstr, TEXT("@"));
  322. +       if (s) {
  323. +               /* URL has user/password */
  324. +               slen = s-urlstr;
  325. +               (void)memcpy(uctx->login.username, urlstr, slen*sizeof(TCHAR));
  326. +               uctx->login.username[slen] = TEXT('\0');
  327. +               urlstr += slen + 1;
  328. +
  329. +               s = _tcsstr(uctx->login.username, TEXT(":"));
  330. +               if (s) {
  331. +                       /* found passwd */
  332. +                       uctx->login.passwd = s+1;
  333. +                       *s = TEXT('\0');
  334. +               }
  335. +               else
  336. +               {
  337. +                       uctx->login.passwd = NULL;
  338. +               }
  339. +
  340. +               /* catch password-only URLs */
  341. +               if (uctx->login.username[0] == TEXT('\0'))
  342. +                       uctx->login.username = NULL;
  343. +       }
  344. +       else
  345. +       {
  346. +               uctx->login.username = NULL;
  347. +               uctx->login.passwd = NULL;
  348. +       }
  349. +
  350. +       D((void)_tprintf(TEXT("login='%s', passwd='%s', rest='%s'\n"),
  351. +               DBGNULLSTR(uctx->login.username),
  352. +               DBGNULLSTR(uctx->login.passwd),
  353. +               DBGNULLSTR(urlstr)));
  354. +
  355. +       s = _tcsstr(urlstr, TEXT("/"));
  356. +       if (s) {
  357. +               /* URL has hostport */
  358. +               slen = s-urlstr;
  359. +               (void)memcpy(uctx->hostport.hostname, urlstr, slen*sizeof(TCHAR));
  360. +               uctx->hostport.hostname[slen] = TEXT('\0');
  361. +               urlstr += slen + 1;
  362. +
  363. +               s = _tcsstr(uctx->hostport.hostname, TEXT(":"));
  364. +               if (s) {
  365. +                       /* found port number */
  366. +                       uctx->hostport.port = _tstoi(s+1);
  367. +                       *s = TEXT('\0');
  368. +               }
  369. +       }
  370. +       else
  371. +       {
  372. +               (void)_tcscpy(uctx->hostport.hostname, urlstr);
  373. +               uctx->path = NULL;
  374. +               urlstr = NULL;
  375. +       }
  376. +
  377. +       D((void)_tprintf(TEXT("hostport='%s', port=%d, rest='%s'\n"),
  378. +               DBGNULLSTR(uctx->hostport.hostname),
  379. +               uctx->hostport.port,
  380. +               DBGNULLSTR(urlstr)));
  381. +
  382. +       if (!urlstr) {
  383. +               return 0;
  384. +       }
  385. +
  386. +       (void)_tcscpy(uctx->path, urlstr);
  387. +       D((void)_tprintf(TEXT("path='%s'\n"), uctx->path));
  388. +
  389. +       return 0;
  390. +}
  391. +
  392. +void url_parser_free_context(url_parser_context *c)
  393. +{
  394. +       free(c);
  395. +}
  396. diff --git a/mount/urlparser1.h b/mount/urlparser1.h
  397. new file mode 100644
  398. index 0000000..ea715d2
  399. --- /dev/null
  400. +++ b/mount/urlparser1.h
  401. @@ -0,0 +1,46 @@
  402. +/* NFSv4.1 client for Windows
  403. + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
  404. + *
  405. + * This library is free software; you can redistribute it and/or modify it
  406. + * under the terms of the GNU Lesser General Public License as published by
  407. + * the Free Software Foundation; either version 2.1 of the License, or (at
  408. + * your option) any later version.
  409. + *
  410. + * This library is distributed in the hope that it will be useful, but
  411. + * without any warranty; without even the implied warranty of merchantability
  412. + * or fitness for a particular purpose.  See the GNU Lesser General Public
  413. + * License for more details.
  414. + *
  415. + * You should have received a copy of the GNU Lesser General Public License
  416. + * along with this library; if not, write to the Free Software Foundation,
  417. + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  418. + */
  419. +
  420. +#ifndef __URLPARSER1_H__
  421. +#define __URLPARSER1_H__
  422. +
  423. +#include <tchar.h>
  424. +
  425. +typedef
  426. +struct _url_parser_context {
  427. +       TCHAR *in_url;
  428. +
  429. +       TCHAR *scheme;
  430. +       struct {
  431. +               TCHAR *username;
  432. +               TCHAR *passwd;
  433. +       } login;
  434. +       struct {
  435. +               TCHAR *hostname;
  436. +               signed int port;
  437. +       } hostport;
  438. +       TCHAR *path;
  439. +} url_parser_context;
  440. +
  441. +
  442. +/* Prototypes */
  443. +url_parser_context *url_parser_create_context(const TCHAR *in_url, unsigned int flags);
  444. +int url_parser_parse(url_parser_context *uctx);
  445. +void url_parser_free_context(url_parser_context *c);
  446. +
  447. +#endif /* !__URLPARSER1_H__ */

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