We're about to introduce support for encoding NFSv4 pathnames in an NFS URI. Add helpers for handling the details.
Note that this commit adds a new build dependency: liburiparser. Not all current distributions have liburiparser. RHEL / OL 6 do not have it, for example. Signed-off-by: Chuck Lever <[email protected]> --- configure.ac | 5 + src/fedfsd/Makefile.am | 1 src/include/nsdb.h | 7 + src/libnsdb/path.c | 229 ++++++++++++++++++++++++++++++++++++++++++++ src/nfsref/Makefile.am | 1 src/nsdbc/Makefile.am | 1 src/nsdbparams/Makefile.am | 1 7 files changed, 245 insertions(+), 0 deletions(-) diff --git a/configure.ac b/configure.ac index 9a848c5..31634cb 100644 --- a/configure.ac +++ b/configure.ac @@ -123,6 +123,11 @@ AC_CHECK_LIB([xml2], [xmlParseFile], AC_DEFINE([HAVE_LIBXML2], [1], [Define if you have libxml2])], [AC_MSG_ERROR([libxml2 not found.])]) +AC_CHECK_LIB([uriparser], [uriParseUriA], + [AC_SUBST([LIBURIPARSER], ["-luriparser"]) + AC_DEFINE([HAVE_LIBURIPARSER], [1], + [Define if you have liburiparser])], + [AC_MSG_ERROR([liburiparser not found.])]) # Checks for header files. AC_CHECK_HEADERS([fcntl.h langinfo.h locale.h memory.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h syslog.h termios.h unistd.h wchar.h]) diff --git a/src/fedfsd/Makefile.am b/src/fedfsd/Makefile.am index 47ee106..29050c2 100644 --- a/src/fedfsd/Makefile.am +++ b/src/fedfsd/Makefile.am @@ -29,6 +29,7 @@ sbin_PROGRAMS = fedfsd fedfsd_SOURCES = listen.c main.c privilege.c svc.c fedfsd_LDADD = $(LIBTIRPC) $(LIBLDAP) $(LIBLBER) $(LIBXML2) \ $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) $(LIBCAP) \ + $(LIBURIPARSER) \ $(top_builddir)/src/libadmin/libadmin.la \ $(top_builddir)/src/libnsdb/libnsdb.la \ $(top_builddir)/src/libjunction/libjunction.la \ diff --git a/src/include/nsdb.h b/src/include/nsdb.h index a115fae..d6c6841 100644 --- a/src/include/nsdb.h +++ b/src/include/nsdb.h @@ -28,6 +28,7 @@ #include <netdb.h> #include <ldap.h> +#include <uriparser/Uri.h> #include "fedfs_admin.h" #include "fedfs.h" @@ -414,5 +415,11 @@ FedFsStatus nsdb_path_array_to_fedfspathname(char * const *path_array, FedFsPathName *fpath); FedFsStatus nsdb_fedfspathname_to_path_array(FedFsPathName fpath, char ***path_array); +void nsdb_assign_textrange(UriTextRangeA *text, + const char *string); +FedFsStatus nsdb_path_array_to_uri_pathname(char * const *path_array, + UriUriA *uri); +FedFsStatus nsdb_uri_pathname_to_path_array(const UriUriA *uri, + char ***path_array); #endif /* !_FEDFS_NSDB_H_ */ diff --git a/src/libnsdb/path.c b/src/libnsdb/path.c index e5506ea..6894ee2 100644 --- a/src/libnsdb/path.c +++ b/src/libnsdb/path.c @@ -38,6 +38,7 @@ #include <ldap.h> #include <netinet/in.h> +#include <uriparser/Uri.h> #include "nsdb.h" #include "junction.h" @@ -723,3 +724,231 @@ nsdb_fedfspathname_to_path_array(FedFsPathName fpath, char ***path_array) *path_array = result; return FEDFS_OK; } + +/** + * Assign the value of "string" to a UriTextRangeA field + * + * @param text UriTextRangeA field to assign + * @param string NUL-terminated C string + * + * Note: "string" must not be freed until the text range + * is no longer used. + * + * Note: string is assumed to contain only single-width + * characters. + */ +void +nsdb_assign_textrange(UriTextRangeA *text, const char *string) +{ + text->first = string; + text->afterLast = string + strlen(string); +} + +/** + * Allocate a UriPathSegmentA + * + * @param name NUL-terminated C string containing path segment + * @return freshly allocated UriPathSegmentA object + */ +static UriPathSegmentA * +nsdb_new_uri_path_segment(const char *name) +{ + UriPathSegmentA *new; + + new = (UriPathSegmentA *)calloc(1, sizeof(*new)); + if (new != NULL) + nsdb_assign_textrange(&new->text, name); + return new; +} + +/** + * Release a list of UriPathSegmentA objects + * + * @param pos head of UriPathSegmentA list + */ +static void +nsdb_free_path_segments(UriPathSegmentA *pos) +{ + UriPathSegmentA *next; + + while (pos != NULL) { + next = pos->next; + free(pos); + pos = next; + } +} + +/** + * Marshal the pathname component of an NFS URI + * + * @param path_array array of pointers to NUL-terminated C strings + * @param uri OUT: a filled-in UriUriA structure + * @return a FedFsStatus code + * + * Caller must free the members of the UriUriA object with + * uriFreeUriMembersA(). + * + * @todo Proper i18n of pathname segments + */ +FedFsStatus +nsdb_path_array_to_uri_pathname(char * const *path_array, UriUriA *uri) +{ + UriPathSegmentA *pos, *result; + size_t length, len; + char *component; + unsigned int i; + + pos = nsdb_new_uri_path_segment(""); + if (pos == NULL) + return FEDFS_ERR_SVRFAULT; + result = pos; + + length = 0; + for (i = 0; path_array[i] != NULL; i++) { + component = path_array[i]; + len = strlen(component); + + if (len == 0) { + xlog(D_GENERAL, "%s: Zero-length component", __func__); + return FEDFS_ERR_BADNAME; + } + if (len > NAME_MAX) { + xlog(D_GENERAL, "%s: Component length too long", __func__); + return FEDFS_ERR_NAMETOOLONG; + } + if (strchr(component, '/') != NULL) { + xlog(D_GENERAL, "%s: Local separator character " + "found in component", __func__); + return FEDFS_ERR_BADNAME; + } + if (!nsdb_pathname_is_utf8(component)) { + xlog(D_GENERAL, "%s: Bad character in component", + __func__); + return FEDFS_ERR_BADCHAR; + } + + length += STRLEN_SLASH + len; + + if (length > PATH_MAX) { + xlog(D_GENERAL, "%s: Pathname too long", __func__); + return FEDFS_ERR_NAMETOOLONG; + } + + pos->next = nsdb_new_uri_path_segment(component); + if (pos->next == NULL) { + nsdb_free_path_segments(result); + return FEDFS_ERR_SVRFAULT; + } + pos = pos->next; + } + + uri->pathHead = result; + return FEDFS_OK; +} + +/** + * Return length in bytes of a URI pathname segment + * + * @param segment URI pathname segment + * @return count of bytes in segment + * + * XXX: Isn't there a uriparser API that does this? + */ +static size_t +nsdb_uri_pathname_segment_size(const UriPathSegmentA *segment) +{ + if (segment->text.first == NULL) + return 0; + return segment->text.afterLast - segment->text.first; +} + +/** + * Return number of segments in a URI pathname + * + * @param uri filled-in URI + * @return count of segments + * + * XXX: Isn't there a uriparser API that does this? + */ +static unsigned int +nsdb_uri_pathname_segment_count(const UriUriA *uri) +{ + UriPathSegmentA *pos; + unsigned int result; + + if (uri->pathHead->text.first == NULL) + return 0; + + result = 1; + for (pos = uri->pathHead; pos != uri->pathTail; pos = pos->next) + result++; + return result; +} + +/** + * Unmarshal the pathname component of an NFS URI + * + * @param uri a filled-in UriUriA structure + * @param path_array OUT: array of pointers to NUL-terminated C strings + * @return a FedFsStatus code + * + * Caller must free "path_array" with nsdb_free_string_array(). + * + * @todo Proper i18n of pathname segments + * @todo Handling too many slashes in various places + */ +FedFsStatus +nsdb_uri_pathname_to_path_array(const UriUriA *uri, char ***path_array) +{ + unsigned int i, count; + UriPathSegmentA *pos; + char **result = NULL; + + if (uri->pathHead == NULL) { + xlog(D_GENERAL, "%s: NFS URI has no pathname component", __func__); + return FEDFS_ERR_BADNAME; + } + + count = nsdb_uri_pathname_segment_count(uri); + if (count < 2) { + xlog(D_GENERAL, "%s: NFS URI has short pathname component", __func__); + return FEDFS_ERR_BADNAME; + } + + pos = uri->pathHead->next; + if (count == 2 && nsdb_uri_pathname_segment_size(pos) == 0) + return nsdb_alloc_zero_component_pathname(path_array); + + result = (char **)calloc(count + 1, sizeof(char *)); + if (result == NULL) { + xlog(L_ERROR, "%s: Failed to allocate array", + __func__); + return FEDFS_ERR_SVRFAULT; + } + + for (i = 0; pos != NULL; pos = pos->next) { + size_t len; + + len = nsdb_uri_pathname_segment_size(pos); + if (len > NAME_MAX) { + nsdb_free_string_array(result); + xlog(D_GENERAL, "%s: Component length too long", + __func__); + return FEDFS_ERR_NAMETOOLONG; + } + if (len == 0) + continue; + + result[i] = strndup((char *)pos->text.first, len); + if (result[i] == NULL) { + nsdb_free_string_array(result); + xlog(L_ERROR, "%s: Failed to allocate component string", + __func__); + return FEDFS_ERR_SVRFAULT; + } + i++; + } + + *path_array = result; + return FEDFS_OK; +} diff --git a/src/nfsref/Makefile.am b/src/nfsref/Makefile.am index 284d4b4..c8ef8c9 100644 --- a/src/nfsref/Makefile.am +++ b/src/nfsref/Makefile.am @@ -28,6 +28,7 @@ sbin_PROGRAMS = nfsref nfsref_SOURCES = add.c lookup.c nfsref.c remove.c LDADD = $(LIBLDAP) $(LIBLBER) $(LIBXML2) \ $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) \ + $(LIBURIPARSER) \ $(top_builddir)/src/libnsdb/libnsdb.la \ $(top_builddir)/src/libxlog/libxlog.la \ $(top_builddir)/src/libjunction/libjunction.la diff --git a/src/nsdbc/Makefile.am b/src/nsdbc/Makefile.am index bf0e057..e64d259 100644 --- a/src/nsdbc/Makefile.am +++ b/src/nsdbc/Makefile.am @@ -30,6 +30,7 @@ sbin_PROGRAMS = nsdb-annotate nsdb-describe nsdb-list \ nsdb-create-fsl nsdb-delete-fsl nsdb-update-fsl LDADD = $(LIBLDAP) $(LIBLBER) $(LIBXML2) \ $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) \ + $(LIBURIPARSER) \ $(top_builddir)/src/libnsdb/libnsdb.la \ $(top_builddir)/src/libxlog/libxlog.la \ $(top_builddir)/src/libjunction/libjunction.la diff --git a/src/nsdbparams/Makefile.am b/src/nsdbparams/Makefile.am index 7b7911a..9deb9ea 100644 --- a/src/nsdbparams/Makefile.am +++ b/src/nsdbparams/Makefile.am @@ -28,6 +28,7 @@ sbin_PROGRAMS = nsdbparams nsdbparams_SOURCES = delete.c list.c main.c show.c update.c LDADD = $(LIBLDAP) $(LIBLBER) $(LIBXML2) \ $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) $(LIBCAP) \ + $(LIBURIPARSER) \ $(top_builddir)/src/libnsdb/libnsdb.la \ $(top_builddir)/src/libjunction/libjunction.la \ $(top_builddir)/src/libxlog/libxlog.la _______________________________________________ fedfs-utils-devel mailing list [email protected] https://oss.oracle.com/mailman/listinfo/fedfs-utils-devel
