- diff --git a/build.vc19/nfs_mount/nfs_mount.vcxproj b/build.vc19/nfs_mount/nfs_mount.vcxproj
- index 7ab83e0..2f91ab2 100644
- --- a/build.vc19/nfs_mount/nfs_mount.vcxproj
- +++ b/build.vc19/nfs_mount/nfs_mount.vcxproj
- @@ -161,9 +161,11 @@
- <ClCompile Include="..\..\mount\enum.c" />
- <ClCompile Include="..\..\mount\mount.c" />
- <ClCompile Include="..\..\mount\options.c" />
- + <ClCompile Include="..\..\mount\urlparser1.c" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="..\..\mount\options.h" />
- + <ClInclude Include="..\..\mount\urlparser1.h" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- diff --git a/build.vc19/nfs_mount/nfs_mount.vcxproj.filters b/build.vc19/nfs_mount/nfs_mount.vcxproj.filters
- index de8db60..623fa7d 100644
- --- a/build.vc19/nfs_mount/nfs_mount.vcxproj.filters
- +++ b/build.vc19/nfs_mount/nfs_mount.vcxproj.filters
- @@ -24,10 +24,16 @@
- <ClCompile Include="..\..\mount\options.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- + <ClCompile Include="..\..\mount\urlparser1.c">
- + <Filter>Source Files</Filter>
- + </ClCompile>
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="..\..\mount\options.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- + <ClInclude Include="..\..\mount\urlparser1.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- </ItemGroup>
- </Project>
- \ No newline at end of file
- diff --git a/mount/mount.c b/mount/mount.c
- index 2e229ca..07ff357 100644
- --- a/mount/mount.c
- +++ b/mount/mount.c
- @@ -34,6 +34,7 @@
- #include "nfs41_driver.h" /* NFS41_PROVIDER_NAME_A */
- #include "options.h"
- +#include "urlparser1.h"
- #define MOUNT_CONFIG_NFS_PORT_DEFAULT 2049
- @@ -282,58 +283,87 @@ static DWORD ParseRemoteName(
- wchar_t remotename[NFS41_SYS_MAX_PATH_LEN];
- wchar_t *premotename = remotename;
- wchar_t srvname[NFS41_SYS_MAX_PATH_LEN+1+32]; /* sizeof(hostname+'@'+integer) */
- + url_parser_context *uctx = NULL;
- result = StringCchCopy(premotename, NFS41_SYS_MAX_PATH_LEN, pRemoteName);
- /*
- - * gisburn: Fixme: Implement nfs://-URLS per RFC 2224 ("NFS URL
- + * Support nfs://-URLS per RFC 2224 ("NFS URL
- * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- * including port support (nfs://hostname@port/path/...)
- */
- if (!wcsncmp(premotename, TEXT("nfs://"), 6)) {
- - _ftprintf(stderr, TEXT("nfs://-URLs not supported yet.\n"));
- - result = ERROR_NOT_SUPPORTED;
- - goto out;
- - }
- + uctx = url_parser_create_context(premotename, 0);
- + if (!uctx) {
- + result = ERROR_NOT_ENOUGH_MEMORY;
- + goto out;
- + }
- - ConvertUnixSlashes(premotename);
- + if (url_parser_parse(uctx) < 0) {
- + result = ERROR_BAD_ARGUMENTS;
- + (void)_ftprintf(stderr, TEXT("Error parsing nfs://-URL.\n"));
- + goto out;
- + }
- - /*
- - * Remote hostname should not contain a '@' since we use this
- - * to communicate the NFSv4 port number below
- - * Use $ nfs_mount.exe -o port=portnumber ... # instead
- - */
- - if (_tcsrchr(premotename, TEXT('@'))) {
- - _ftprintf(stderr, TEXT("Remote path should not contain '@', ")
- - TEXT("use -o port=tcpportnum.\n"));
- - result = ERROR_BAD_ARGUMENTS;
- - goto out;
- - }
- + if (uctx->login.username || uctx->login.passwd) {
- + result = ERROR_BAD_ARGUMENTS;
- + (void)_ftprintf(stderr, TEXT("Username/Password are not defined for nfs://-URL.\n"));
- + goto out;
- + }
- +
- + (void)wcscpy_s(premotename, NFS41_SYS_MAX_PATH_LEN,
- + uctx->hostport.hostname);
- - if (FindOptionByName(TEXT("port"), pOptions, &port_option_val)) {
- - wchar_t *port_value_wstr = (PTCH)(port_option_val->EaName + port_option_val->EaNameLength + sizeof(TCHAR));
- + if (uctx->hostport.port != -1)
- + port = uctx->hostport.port;
- + else
- + port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
- - port = _wtoi(port_value_wstr);
- - if ((port < 1) || (port > 65535)) {
- - result = ERROR_BAD_ARGUMENTS;
- - goto out;
- - }
- + ConvertUnixSlashes(premotename);
- + pEnd = uctx->path;
- + ConvertUnixSlashes(pEnd);
- }
- else
- {
- - port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
- - }
- + ConvertUnixSlashes(premotename);
- - /* fail if the server name doesn't end with :\ */
- - pEnd = _tcsrchr(premotename, TEXT(':'));
- - if (pEnd == NULL || pEnd[1] != TEXT('\\')) {
- - _ftprintf(stderr, TEXT("Failed to parse the remote path. ")
- - TEXT("Expected 'hostname:\\path'.\n"));
- - result = ERROR_BAD_ARGUMENTS;
- - goto out;
- + /*
- + * Remote hostname should not contain a '@' since we use this
- + * to communicate the NFSv4 port number below
- + * Use $ nfs_mount.exe -o port=portnumber ... # instead
- + */
- + if (_tcsrchr(premotename, TEXT('@'))) {
- + (void)_ftprintf(stderr, TEXT("Remote path should not contain '@', ")
- + TEXT("use -o port=tcpportnum.\n"));
- + result = ERROR_BAD_ARGUMENTS;
- + goto out;
- + }
- +
- + if (FindOptionByName(TEXT("port"), pOptions, &port_option_val)) {
- + wchar_t *port_value_wstr =
- + (PTCH)(port_option_val->EaName + port_option_val->EaNameLength + sizeof(TCHAR));
- +
- + port = _wtoi(port_value_wstr);
- + if ((port < 1) || (port > 65535)) {
- + result = ERROR_BAD_ARGUMENTS;
- + goto out;
- + }
- + }
- + else {
- + port = MOUNT_CONFIG_NFS_PORT_DEFAULT;
- + }
- +
- + /* fail if the server name doesn't end with :\ */
- + pEnd = _tcsrchr(premotename, TEXT(':'));
- + if (pEnd == NULL || pEnd[1] != TEXT('\\')) {
- + (void)_ftprintf(stderr, TEXT("Failed to parse the remote path. ")
- + TEXT("Expected 'hostname:\\path'.\n"));
- + result = ERROR_BAD_ARGUMENTS;
- + goto out;
- + }
- + *pEnd = TEXT('\0');
- + ++pEnd;
- }
- - *pEnd = TEXT('\0');
- - ++pEnd;
- /*
- * Make sure that we do not pass raw IPv6 addresses to the kernel.
- @@ -415,6 +445,12 @@ static DWORD ParseRemoteName(
- goto out;
- }
- +#if 0
- + _ftprintf(stderr,
- + TEXT("srvname='%s', mntpt='%s'\n"), srvname, pEnd);
- + exit(0);
- +#endif
- +
- if (!InsertOption(TEXT("srvname"), srvname, pOptions) ||
- !InsertOption(TEXT("mntpt"), *pEnd ? pEnd : TEXT("\\"), pOptions)) {
- result = ERROR_BAD_ARGUMENTS;
- @@ -447,6 +483,9 @@ static DWORD ParseRemoteName(
- result = StringCchCopy(pParsedRemoteName, cchConnectionLen, srvname);
- out:
- + if (uctx) {
- + url_parser_free_context(uctx);
- + }
- return result;
- }
- diff --git a/mount/urlparser1.c b/mount/urlparser1.c
- new file mode 100644
- index 0000000..43af33b
- --- /dev/null
- +++ b/mount/urlparser1.c
- @@ -0,0 +1,193 @@
- +/* NFSv4.1 client for Windows
- + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * This library is free software; you can redistribute it and/or modify it
- + * under the terms of the GNU Lesser General Public License as published by
- + * the Free Software Foundation; either version 2.1 of the License, or (at
- + * your option) any later version.
- + *
- + * This library is distributed in the hope that it will be useful, but
- + * without any warranty; without even the implied warranty of merchantability
- + * or fitness for a particular purpose. See the GNU Lesser General Public
- + * License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public License
- + * along with this library; if not, write to the Free Software Foundation,
- + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- + */
- +
- +
- +/* urlparser1.c - simple URL parser */
- +
- +#if ((__STDC_VERSION__-0) < 201710L)
- +#error Code requires ISO C17
- +#endif
- +
- +
- +#include <crtdbg.h>
- +#include <Windows.h>
- +#include <stdlib.h>
- +
- +#include "urlparser1.h"
- +
- +/*
- + * Disable "warning C4996: 'wcscpy': This function or variable may be
- + * unsafe." because in this case the buffers are properly sized,
- + * making this function safe
- + */
- +#pragma warning (disable : 4996)
- +
- +/*
- + * Original extended regular expression:
- + *
- + * "^"
- + * "(.+?)" // scheme
- + * "://" // '://'
- + * "(" // login
- + * "(?:"
- + * "(.+?)" // user (optional)
- + * "(?::(.+))?" // password (optional)
- + * "@"
- + * ")?"
- + * "(" // hostport
- + * "(.+?)" // host
- + * "(?::([[:digit:]]+))?" // port (optional)
- + * ")"
- + * ")"
- + * "(?:/(.*?))?" // path (optional)
- + * "$"
- + */
- +
- +#define DBGNULLSTR(s) (((s)!=NULL)?(s):TEXT("<NULL>"))
- +#if 0
- +#define D(x) x
- +#else
- +#define D(x)
- +#endif
- +
- +url_parser_context *url_parser_create_context(const TCHAR *in_url, unsigned int flags)
- +{
- + url_parser_context *uctx;
- + TCHAR *s;
- + size_t in_url_len;
- + size_t context_len;
- +
- + if (!in_url)
- + return NULL;
- +
- + in_url_len = _tcsclen(in_url);
- +
- + context_len = sizeof(url_parser_context) +
- + (((in_url_len+1)*5L*sizeof(TCHAR)));
- + uctx = malloc(context_len);
- + if (!uctx)
- + return NULL;
- +
- + s = (void *)(uctx+1);
- + uctx->in_url = s; s+= in_url_len+1;
- + (void)_tcscpy(uctx->in_url, in_url);
- + uctx->scheme = s; s+= in_url_len+1;
- + uctx->login.username = s; s+= in_url_len+1;
- + uctx->hostport.hostname = s; s+= in_url_len+1;
- + uctx->path = s; s+= in_url_len+1;
- + uctx->hostport.port = -1;
- +
- + return uctx;
- +}
- +
- +int url_parser_parse(url_parser_context *uctx)
- +{
- + D((void)_tprintf(TEXT("## parser in_url='%s'\n"), uctx->in_url));
- +
- + TCHAR *s;
- + const TCHAR *urlstr = uctx->in_url;
- + size_t slen;
- +
- + s = _tcsstr(urlstr, TEXT("://"));
- + if (!s) {
- + D((void)_tprintf(TEXT("url_parser: Not an URL\n")));
- + return -1;
- + }
- +
- + slen = s-urlstr;
- + (void)memcpy(uctx->scheme, urlstr, slen*sizeof(TCHAR));
- + uctx->scheme[slen] = TEXT('\0');
- + urlstr += slen + 3;
- +
- + D((void)_tprintf(TEXT("scheme='%s', rest='%s'\n"), uctx->scheme, urlstr));
- +
- + s = _tcsstr(urlstr, TEXT("@"));
- + if (s) {
- + /* URL has user/password */
- + slen = s-urlstr;
- + (void)memcpy(uctx->login.username, urlstr, slen*sizeof(TCHAR));
- + uctx->login.username[slen] = TEXT('\0');
- + urlstr += slen + 1;
- +
- + s = _tcsstr(uctx->login.username, TEXT(":"));
- + if (s) {
- + /* found passwd */
- + uctx->login.passwd = s+1;
- + *s = TEXT('\0');
- + }
- + else
- + {
- + uctx->login.passwd = NULL;
- + }
- +
- + /* catch password-only URLs */
- + if (uctx->login.username[0] == TEXT('\0'))
- + uctx->login.username = NULL;
- + }
- + else
- + {
- + uctx->login.username = NULL;
- + uctx->login.passwd = NULL;
- + }
- +
- + D((void)_tprintf(TEXT("login='%s', passwd='%s', rest='%s'\n"),
- + DBGNULLSTR(uctx->login.username),
- + DBGNULLSTR(uctx->login.passwd),
- + DBGNULLSTR(urlstr)));
- +
- + s = _tcsstr(urlstr, TEXT("/"));
- + if (s) {
- + /* URL has hostport */
- + slen = s-urlstr;
- + (void)memcpy(uctx->hostport.hostname, urlstr, slen*sizeof(TCHAR));
- + uctx->hostport.hostname[slen] = TEXT('\0');
- + urlstr += slen + 1;
- +
- + s = _tcsstr(uctx->hostport.hostname, TEXT(":"));
- + if (s) {
- + /* found port number */
- + uctx->hostport.port = _tstoi(s+1);
- + *s = TEXT('\0');
- + }
- + }
- + else
- + {
- + (void)_tcscpy(uctx->hostport.hostname, urlstr);
- + uctx->path = NULL;
- + urlstr = NULL;
- + }
- +
- + D((void)_tprintf(TEXT("hostport='%s', port=%d, rest='%s'\n"),
- + DBGNULLSTR(uctx->hostport.hostname),
- + uctx->hostport.port,
- + DBGNULLSTR(urlstr)));
- +
- + if (!urlstr) {
- + return 0;
- + }
- +
- + (void)_tcscpy(uctx->path, urlstr);
- + D((void)_tprintf(TEXT("path='%s'\n"), uctx->path));
- +
- + return 0;
- +}
- +
- +void url_parser_free_context(url_parser_context *c)
- +{
- + free(c);
- +}
- diff --git a/mount/urlparser1.h b/mount/urlparser1.h
- new file mode 100644
- index 0000000..ea715d2
- --- /dev/null
- +++ b/mount/urlparser1.h
- @@ -0,0 +1,46 @@
- +/* NFSv4.1 client for Windows
- + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * This library is free software; you can redistribute it and/or modify it
- + * under the terms of the GNU Lesser General Public License as published by
- + * the Free Software Foundation; either version 2.1 of the License, or (at
- + * your option) any later version.
- + *
- + * This library is distributed in the hope that it will be useful, but
- + * without any warranty; without even the implied warranty of merchantability
- + * or fitness for a particular purpose. See the GNU Lesser General Public
- + * License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public License
- + * along with this library; if not, write to the Free Software Foundation,
- + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- + */
- +
- +#ifndef __URLPARSER1_H__
- +#define __URLPARSER1_H__
- +
- +#include <tchar.h>
- +
- +typedef
- +struct _url_parser_context {
- + TCHAR *in_url;
- +
- + TCHAR *scheme;
- + struct {
- + TCHAR *username;
- + TCHAR *passwd;
- + } login;
- + struct {
- + TCHAR *hostname;
- + signed int port;
- + } hostport;
- + TCHAR *path;
- +} url_parser_context;
- +
- +
- +/* Prototypes */
- +url_parser_context *url_parser_create_context(const TCHAR *in_url, unsigned int flags);
- +int url_parser_parse(url_parser_context *uctx);
- +void url_parser_free_context(url_parser_context *c);
- +
- +#endif /* !__URLPARSER1_H__ */
Prototype nfs://-URL support
Posted by Anonymous on Wed 24th Jan 2024 13:04
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.