diff --git a/configure.ac b/configure.ac
index 2a2052f..5d1eca0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,7 +162,6 @@ AC_CONFIG_FILES([Makefile
                  src/libjunction/Makefile
                  src/libnsdb/Makefile
                  src/libparser/Makefile
-                 src/libpath/Makefile
                  src/libsi/Makefile
                  src/libxlog/Makefile
                  src/mount/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 2b03192..f4ba864 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,7 @@
 ##
 
 SUBDIRS			= include libxlog libadmin libnsdb libjunction \
-			  libparser libpath libsi \
+			  libparser libsi \
 			  fedfsc fedfsd nsdbc nsdbparams resolve-junction \
 			  mount
 
diff --git a/src/fedfsc/Makefile.am b/src/fedfsc/Makefile.am
index c91a102..2fd4d4d 100644
--- a/src/fedfsc/Makefile.am
+++ b/src/fedfsc/Makefile.am
@@ -35,7 +35,6 @@ LDADD			= $(LIBTIRPC) $(LIBLDAP) $(LIBLBER) \
 			  $(top_builddir)/src/libadmin/libadmin.a \
 			  $(top_builddir)/src/libjunction/libjunction.a \
 			  $(top_builddir)/src/libnsdb/libnsdb.a \
-			  $(top_builddir)/src/libpath/libpath.a \
 			  $(top_builddir)/src/libxlog/libxlog.a
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
diff --git a/src/fedfsc/fedfs-create-junction.c b/src/fedfsc/fedfs-create-junction.c
index a303041..77815fc 100644
--- a/src/fedfsc/fedfs-create-junction.c
+++ b/src/fedfsc/fedfs-create-junction.c
@@ -43,7 +43,6 @@
 #include "fedfs_admin.h"
 #include "nsdb.h"
 #include "junction.h"
-#include "path.h"
 #include "xlog.h"
 #include "gpl-boiler.h"
 
diff --git a/src/fedfsc/fedfs-create-replication.c b/src/fedfsc/fedfs-create-replication.c
index 4aaea98..8048da7 100644
--- a/src/fedfsc/fedfs-create-replication.c
+++ b/src/fedfsc/fedfs-create-replication.c
@@ -40,7 +40,6 @@
 #include "fedfs_admin.h"
 #include "nsdb.h"
 #include "junction.h"
-#include "path.h"
 #include "xlog.h"
 #include "gpl-boiler.h"
 
diff --git a/src/fedfsc/fedfs-delete-junction.c b/src/fedfsc/fedfs-delete-junction.c
index 28f2f77..f7e53f3 100644
--- a/src/fedfsc/fedfs-delete-junction.c
+++ b/src/fedfsc/fedfs-delete-junction.c
@@ -39,7 +39,6 @@
 #include "fedfs_admin.h"
 #include "nsdb.h"
 #include "junction.h"
-#include "path.h"
 #include "xlog.h"
 #include "gpl-boiler.h"
 
diff --git a/src/fedfsc/fedfs-delete-replication.c b/src/fedfsc/fedfs-delete-replication.c
index 052ca45..e3c5cca 100644
--- a/src/fedfsc/fedfs-delete-replication.c
+++ b/src/fedfsc/fedfs-delete-replication.c
@@ -39,7 +39,6 @@
 #include "fedfs_admin.h"
 #include "nsdb.h"
 #include "junction.h"
-#include "path.h"
 #include "xlog.h"
 #include "gpl-boiler.h"
 
diff --git a/src/fedfsc/fedfs-lookup-junction.c b/src/fedfsc/fedfs-lookup-junction.c
index 224e684..fa0248e 100644
--- a/src/fedfsc/fedfs-lookup-junction.c
+++ b/src/fedfsc/fedfs-lookup-junction.c
@@ -41,7 +41,6 @@
 #include "fedfs_admin.h"
 #include "nsdb.h"
 #include "junction.h"
-#include "path.h"
 #include "xlog.h"
 #include "gpl-boiler.h"
 
diff --git a/src/fedfsc/fedfs-lookup-replication.c b/src/fedfsc/fedfs-lookup-replication.c
index 19a6b09..ed0a5c7 100644
--- a/src/fedfsc/fedfs-lookup-replication.c
+++ b/src/fedfsc/fedfs-lookup-replication.c
@@ -41,7 +41,6 @@
 #include "fedfs_admin.h"
 #include "nsdb.h"
 #include "junction.h"
-#include "path.h"
 #include "xlog.h"
 #include "gpl-boiler.h"
 
diff --git a/src/fedfsd/Makefile.am b/src/fedfsd/Makefile.am
index 78bfc90..c8332dc 100644
--- a/src/fedfsd/Makefile.am
+++ b/src/fedfsd/Makefile.am
@@ -32,7 +32,6 @@ fedfsd_LDADD		= $(LIBTIRPC) $(LIBLDAP) $(LIBLBER) \
 			  $(top_builddir)/src/libadmin/libadmin.a \
 			  $(top_builddir)/src/libnsdb/libnsdb.a \
 			  $(top_builddir)/src/libjunction/libjunction.a \
-			  $(top_builddir)/src/libpath/libpath.a \
 			  $(top_builddir)/src/libxlog/libxlog.a
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
diff --git a/src/fedfsd/svc.c b/src/fedfsd/svc.c
index 291afdf..9772df7 100644
--- a/src/fedfsd/svc.c
+++ b/src/fedfsd/svc.c
@@ -49,7 +49,6 @@
 #include "nsdb.h"
 #include "fedfsd.h"
 #include "junction.h"
-#include "path.h"
 #include "xlog.h"
 
 /**
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 6244670..5f779b3 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -24,7 +24,7 @@
 ##
 
 noinst_HEADERS		= fedfs_admin.h fedfs.h getsrvinfo.h gpl-boiler.h \
-			  junction.h list.h nsdb.h parse_opt.h path.h \
+			  junction.h list.h nsdb.h parse_opt.h \
 			  token.h xlog.h
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
diff --git a/src/include/nsdb.h b/src/include/nsdb.h
index ae9fc14..296c3e1 100644
--- a/src/include/nsdb.h
+++ b/src/include/nsdb.h
@@ -377,4 +377,22 @@ FedFsStatus	 nsdb_construct_annotation(const char *keyword,
 FedFsStatus	 nsdb_parse_annotation(const char *annotation, size_t len,
 				char **keyword, char **value);
 
+/**
+ ** Pathname parsing utilities
+ **/
+__attribute_malloc__
+char		*nsdb_normalize_path(const char *pathname);
+_Bool		 nsdb_pathname_is_utf8(const char *pathname);
+
+FedFsStatus	 nsdb_fedfspathname_to_posix(const FedFsPathName fpath,
+				char **pathname);
+FedFsStatus	 nsdb_posix_to_fedfspathname(const char *pathname,
+				FedFsPathName *fpath);
+void		 nsdb_free_fedfspathname(FedFsPathName *fpath);
+
+FedFsStatus	 nsdb_posix_path_to_xdr(const char *pathname,
+				struct berval *xdr_path);
+FedFsStatus	 nsdb_xdr_to_posix_path(struct berval *xdr_path,
+				char **pathname);
+
 #endif	/* !_FEDFS_NSDB_H_ */
diff --git a/src/include/path.h b/src/include/path.h
deleted file mode 100644
index 6d4fda3..0000000
--- a/src/include/path.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * @file src/include/path.h
- * @brief Declarations for libpath.a
- */
-
-/*
- * Copyright 2010 Oracle.  All rights reserved.
- *
- * This file is part of fedfs-utils.
- *
- * fedfs-utils is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2.0 as
- * published by the Free Software Foundation.
- *
- * fedfs-utils 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 General Public License version 2.0 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2.0 along with fedfs-utils.  If not, see:
- *
- *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
- */
-
-#ifndef _FEDFS_PATH_H_
-#define _FEDFS_PATH_H_
-
-#include <sys/cdefs.h>
-
-#include "nsdb.h"
-
-__attribute_malloc__
-char		*nsdb_normalize_path(const char *pathname);
-_Bool		 nsdb_pathname_is_utf8(const char *pathname);
-
-FedFsStatus	 nsdb_fedfspathname_to_posix(const FedFsPathName fpath,
-				char **pathname);
-FedFsStatus	 nsdb_posix_to_fedfspathname(const char *pathname,
-				FedFsPathName *fpath);
-void		 nsdb_free_fedfspathname(FedFsPathName *fpath);
-
-FedFsStatus	 nsdb_posix_path_to_xdr(const char *pathname,
-				struct berval *xdr_path);
-FedFsStatus	 nsdb_xdr_to_posix_path(struct berval *xdr_path,
-				char **pathname);
-
-#endif	/* !_FEDFS_PATH_H_ */
diff --git a/src/libnsdb/Makefile.am b/src/libnsdb/Makefile.am
index ddf770d..f0a4dd6 100644
--- a/src/libnsdb/Makefile.am
+++ b/src/libnsdb/Makefile.am
@@ -26,7 +26,7 @@
 noinst_HEADERS		= nsdb-internal.h
 noinst_LIBRARIES	= libnsdb.a
 libnsdb_a_SOURCES	= administrator.c annotation.c display.c fileserver.c \
-			  ldap.c nsdb.c sqlite.c
+			  ldap.c nsdb.c path.c sqlite.c
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
 DISTCLEANFILES		= Makefile.in
diff --git a/src/libnsdb/administrator.c b/src/libnsdb/administrator.c
index 15db8ac..117b0ba 100644
--- a/src/libnsdb/administrator.c
+++ b/src/libnsdb/administrator.c
@@ -43,7 +43,6 @@
 
 #include "nsdb.h"
 #include "junction.h"
-#include "path.h"
 #include "nsdb-internal.h"
 #include "xlog.h"
 
diff --git a/src/libnsdb/ldap.c b/src/libnsdb/ldap.c
index d972ef8..5bff920 100644
--- a/src/libnsdb/ldap.c
+++ b/src/libnsdb/ldap.c
@@ -41,7 +41,6 @@
 #include "nsdb.h"
 #include "junction.h"
 #include "nsdb-internal.h"
-#include "path.h"
 #include "xlog.h"
 
 /**
diff --git a/src/libnsdb/path.c b/src/libnsdb/path.c
new file mode 100644
index 0000000..fd0fec8
--- /dev/null
+++ b/src/libnsdb/path.c
@@ -0,0 +1,534 @@
+/**
+ * @file src/libnsdb/path.c
+ * @brief Encode and decode FedFS pathnames
+ */
+
+/*
+ * Copyright 2010 Oracle.  All rights reserved.
+ *
+ * This file is part of fedfs-utils.
+ *
+ * fedfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0 as
+ * published by the Free Software Foundation.
+ *
+ * fedfs-utils 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 General Public License version 2.0 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2.0 along with fedfs-utils.  If not, see:
+ *
+ *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ldap.h>
+
+#include <netinet/in.h>
+
+#include "nsdb.h"
+#include "junction.h"
+#include "xlog.h"
+
+#define STRLEN_SLASH	((size_t)1)	/* strlen("/") */
+#define STRLEN_NUL	((size_t)1)	/* strlen("") */
+
+#define XDR_UINT_BYTES	(4)
+
+/**
+ * Compute count of XDR 4-octet units from byte count
+ *
+ * @param bytes number of bytes to convert
+ * @return equivalent number of XDR 4-octet units
+ */
+static inline unsigned int
+nsdb_quadlen(const unsigned int bytes)
+{
+	return (bytes + 3) >> 2;
+}
+
+/**
+ * Sanitize an incoming POSIX path
+ *
+ * @param pathname NUL-terminated C string containing a POSIX pathname
+ * @return NUL-terminated C string containing sanitized path
+ *
+ * Caller must free the returned pathname with free(3).
+ *
+ * Remove multiple sequential slashes and any trailing slashes,
+ * but leave "/" by itself alone.
+ */
+__attribute_malloc__ char *
+nsdb_normalize_path(const char *pathname)
+{
+	size_t i, j, len;
+	char *result;
+
+	len = strlen(pathname);
+	if (len == 0) {
+		xlog(D_CALL, "%s: NULL pathname", __func__);
+		return NULL;
+	}
+
+	result = malloc(len + 1);
+	if (result == NULL) {
+		xlog(L_ERROR, "%s: Failed to allocate pathname buffer",
+			__func__);
+		return NULL;
+	}
+
+	for (i = 0, j = 0; i < len; i++) {
+		if (pathname[i] == '/' && pathname[i + 1] == '/')
+			continue;
+		result[j++] = pathname[i];
+	}
+	result[j] = '\0';
+
+	if (j > 1 && result[j - 1] == '/')
+		result[j - 1] = '\0';
+
+	xlog(D_CALL, "%s: result = '%s'", __func__, result);
+	return result;
+}
+
+/**
+ * Count the number of components in a POSIX pathname
+ *
+ * @param pathname NUL-terminated C string containing a POSIX pathname
+ * @param len OUT: number of bytes the encoded XDR stream will consume
+ * @param cnt OUT: component count
+ * @return true when successful
+ */
+static _Bool
+nsdb_count_components(const char *pathname, size_t *len,
+		unsigned int *cnt)
+{
+	char *start, *component;
+	unsigned int count;
+	size_t length;
+
+	/* strtok(3) will tromp on the string */
+	start = strdup(pathname);
+	if (start == NULL) {
+		xlog(L_ERROR, "%s: Failed to duplicate pathname",
+			__func__);
+		return false;
+	}
+
+	length = XDR_UINT_BYTES;
+	count = 0;
+	component = start;
+	for ( ;; ) {
+		char *next;
+
+		if (*component == '/')
+			component++;
+		if (*component == '\0')
+			break;
+		next = strchrnul(component, '/');
+		length += XDR_UINT_BYTES + (nsdb_quadlen(next - component) << 2);
+		count++;
+
+		if (*next == '\0')
+			break;
+		component = next;
+	}
+
+	free(start);
+
+	xlog(D_CALL, "%s: length = %zu, count = %u, path = '%s'",
+		__func__, length, count, pathname);
+	*len = length;
+	*cnt = count;
+	return true;
+}
+
+/**
+ * Predicate: is input character set for a POSIX pathname valid UTF-8?
+ *
+ * @param pathname NUL-terminated C string containing a POSIX path
+ * @return true if the string is valid UTF-8
+ *
+ * XXX: implement this
+ */
+_Bool
+nsdb_pathname_is_utf8(__attribute__((unused)) const char *pathname)
+{
+	return true;
+}
+
+/**
+ * XDR encode a POSIX path name
+ *
+ * @param pathname NUL-terminated C string containing a POSIX path
+ * @param xdr_path OUT: pointer to XDR-encoded path in a berval
+ * @return a FedFsStatus code
+ *
+ * Caller must free xdr_path->bv_val with free(3)
+ *
+ * The XDR encoded result is described by the NSDB protocol draft as
+ * "an XDR encoded variable length array of variable length opaque
+ * data."  The result of this encoding is a byte stream.
+ */
+FedFsStatus
+nsdb_posix_path_to_xdr(const char *pathname, struct berval *xdr_path)
+{
+	char *component, *normalized;
+	unsigned int i, count;
+	uint32_t *xdrbuf;
+	size_t length;
+
+	if (pathname == NULL || xdr_path == NULL) {
+		xlog(L_ERROR, "%s: Invalid argument", __func__);
+		return FEDFS_ERR_INVAL;
+	}
+
+	if (!nsdb_pathname_is_utf8(pathname)) {
+		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
+		return FEDFS_ERR_BADCHAR;
+	}
+
+	normalized = nsdb_normalize_path(pathname);
+	if (normalized == NULL)
+		return FEDFS_ERR_SVRFAULT;
+
+	/*
+	 * Calculate the number of path components and the
+	 * number of bytes in the encoded result so that a
+	 * buffer for the result can be allocated.
+	 */
+	if (!nsdb_count_components(normalized, &length, &count))
+		return FEDFS_ERR_BADNAME;
+
+	/*
+	 * Flatten the POSIX path into an encoded XDR stream
+	 * stored in the allocated buffer
+	 */
+	xdrbuf = malloc(length);
+	if (xdrbuf == NULL) {
+		xlog(L_ERROR, "%s: Failed to allocate XDR buffer",
+			__func__);
+		free(normalized);
+		return FEDFS_ERR_SVRFAULT;
+	}
+	memset(xdrbuf, 0, length);
+
+	i = 1;
+	xdrbuf[i] = htonl(count);
+	component = normalized;
+	for ( ;; ) {
+		char *next;
+
+		if (*component == '/')
+			component++;
+		if (*component == '\0')
+			break;
+		next = strchrnul(component, '/');
+		length = next - component;
+
+		xdrbuf[i++] = htonl(length);
+		memcpy(&xdrbuf[i], component, length);
+		i += nsdb_quadlen(length);
+
+		if (*next == '\0')
+			break;
+		component = next;
+	}
+
+	xdr_path->bv_val = (char *)xdrbuf;
+	xdr_path->bv_len = (ber_len_t)(i << 2);
+
+	free(normalized);
+	return FEDFS_OK;
+}
+
+/**
+ * XDR decode an XDR byte stream into a POSIX path name
+ *
+ * @param xdr_path berval containing XDR-encoded path
+ * @param pathname OUT: pointer to NUL-terminated UTF-8 C string containing a POSIX path name
+ * @return a FedFsStatus code
+ *
+ * Caller must free "pathname" with free(3)
+ *
+ * Note that the count of array items is ignored.  It's not needed to
+ * decode the XDR byte stream correctly.  The only important thing is
+ * to avoid reading outside the passed-in XDR byte stream.  That can
+ * result in incorrect results or even segfaults.
+ */
+FedFsStatus
+nsdb_xdr_to_posix_path(struct berval *xdr_path, char **pathname)
+{
+	const unsigned int buflen = nsdb_quadlen((unsigned int)xdr_path->bv_len);
+	uint32_t *buf = (uint32_t *)xdr_path->bv_val;
+	unsigned int i;
+	uint32_t size;
+	size_t length;
+	char *result;
+
+	if (xdr_path == NULL || pathname == NULL) {
+		xlog(L_ERROR, "%s: Invalid argument", __func__);
+		return FEDFS_ERR_INVAL;
+	}
+
+	i = 1;		/* skip the count of array elements */
+	length = STRLEN_NUL;
+	for ( ;; ) {
+		length += STRLEN_SLASH;
+		if (i >= buflen)
+			break;
+
+		size = ntohl(buf[i++]);
+		i += nsdb_quadlen(size);
+		if (i == buflen)
+			break;
+		if (i > buflen) {
+			xlog(D_GENERAL, "%s: XDR decoding error", __func__);
+			return FEDFS_ERR_BADXDR;
+		}
+
+		length += size;
+	}
+
+	result = malloc(length);
+	if (result == NULL) {
+		xlog(L_ERROR, "%s: Failed to allocate pathname buffer",
+			__func__);
+		return FEDFS_ERR_SVRFAULT;
+	}
+	result[0] = '\0';
+
+	i = 1;		/* skip the count of elements */
+	for ( ;; ) {
+		strcat(result, "/");
+		if (i == buflen)
+			break;
+
+		size = ntohl(buf[i++]);
+		strncat(result, (char *)&buf[i], size);
+		i += nsdb_quadlen(size);
+		if (i == buflen)
+			break;
+	}
+
+	if (!nsdb_pathname_is_utf8(result)) {
+		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
+		free(result);
+		return FEDFS_ERR_BADCHAR;
+	}
+
+	*pathname = result;
+	return FEDFS_OK;
+}
+
+/**
+ * Free a FedFsPathComponent allocated by nsdb_new_component
+ *
+ * @param fcomp pointer to FedFsPathComponent to free
+ */
+static void
+nsdb_free_component(FedFsPathComponent *fcomp)
+{
+	free(fcomp->utf8string_val);
+	fcomp->utf8string_val = NULL;
+	fcomp->utf8string_len = 0;
+}
+
+/**
+ * Allocate a FedFsPathComponent
+ *
+ * @param component UTF-8 C string containing one path component
+ * @param length count of bytes in "component"
+ * @param fcomp OUT: newly allocated FedFsPathComponent; caller must free with nsdb_free_component
+ * @return true if successful, otherwise false
+ */
+static _Bool
+nsdb_new_component(const char *component, size_t length,
+		FedFsPathComponent *fcomp)
+{
+	fcomp->utf8string_val = strndup(component, length);
+	if (fcomp->utf8string_val == NULL)
+		return false;
+	fcomp->utf8string_len = length;
+	return true;
+}
+
+/**
+ * Free resources associated with a FedFsPathName
+ *
+ * @param fpath pointer to FedFsPathName
+ */
+void
+nsdb_free_fedfspathname(FedFsPathName *fpath)
+{
+	unsigned int i;
+
+	for (i = 0; i < fpath->FedFsPathName_len; i++)
+		nsdb_free_component(&fpath->FedFsPathName_val[i]);
+	free(fpath->FedFsPathName_val);
+}
+
+/**
+ * Construct a FedFsPathName from a C string
+ *
+ * @param pathname NUL-terminated C string containing a POSIX pathname
+ * @param fpath OUT: pointer to FedFsPathName in which to construct path
+ * @return a FedFsStatus code
+ */
+FedFsStatus
+nsdb_posix_to_fedfspathname(const char *pathname, FedFsPathName *fpath)
+{
+	char *normalized, *component;
+	unsigned int i, count;
+	size_t length;
+
+	if (!nsdb_pathname_is_utf8(pathname)) {
+		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
+		return FEDFS_ERR_BADCHAR;
+	}
+
+	normalized = nsdb_normalize_path(pathname);
+	if (normalized == NULL)
+		return FEDFS_ERR_SVRFAULT;
+
+	if (!nsdb_count_components(normalized, &length, &count))
+		return FEDFS_ERR_BADNAME;
+
+	/* The path "/" MUST be encoded as an array with zero components. */
+	if (count == 0) {
+		fpath->FedFsPathName_val = NULL;
+		fpath->FedFsPathName_len = 0;
+		return FEDFS_OK;
+	}
+
+	fpath->FedFsPathName_val = calloc(count, sizeof(FedFsPathComponent));
+	if (fpath->FedFsPathName_val == NULL)
+		return FEDFS_ERR_SVRFAULT;
+	fpath->FedFsPathName_len = count;
+
+	i = 0;
+	component = normalized;
+	for (i = 0; ; i++) {
+		char *next;
+
+		if (*component == '/')
+			component++;
+		if (*component == '\0')
+			break;
+		next = strchrnul(component, '/');
+		length = next - component;
+
+		if (!nsdb_new_component(component,
+				length, &fpath->FedFsPathName_val[i]))
+			goto out_err;
+
+		if (*next == '\0')
+			break;
+		component = next;
+	}
+
+	return FEDFS_OK;
+
+out_err:
+	xlog(D_GENERAL, "%s: Failed to allocate new pathname component",
+		__func__);
+	nsdb_free_fedfspathname(fpath);
+	return FEDFS_ERR_SVRFAULT;
+}
+
+/**
+ * Construct a local Posix-style path from a FedFsPathName 
+ *
+ * @param fpath FedFsPathName from which to construct path
+ * @param pathname OUT: pointer to NUL-terminated UTF-8 C string containing a Posix-style path
+ * @return a FedFsStatus code
+ *
+ * Caller must free the returned pathname with free(3).
+ *
+ * NB: The use of fixed constants for NAME_MAX and PATH_MAX are required
+ *     here because, on the client side, the pathname likely does not
+ *     exist, so pathconf(3) cannot be used.
+ */
+FedFsStatus
+nsdb_fedfspathname_to_posix(const FedFsPathName fpath, char **pathname)
+{
+	unsigned int i;
+	char *result;
+
+	result = malloc(PATH_MAX);
+	if (result == NULL) {
+		xlog(D_GENERAL, "%s: Failed to allocate buffer for result",
+			__func__);
+		return FEDFS_ERR_SVRFAULT;
+	}
+	result[0] = '\0';
+
+	if (fpath.FedFsPathName_len == 0) {
+		xlog(D_GENERAL, "%s: Zero-component pathname", __func__);
+		strcat(result, "/");
+		*pathname = result;
+		return FEDFS_OK;
+	}
+
+	for (i = 0; i < fpath.FedFsPathName_len; i++) {
+		FedFsPathComponent fcomp = fpath.FedFsPathName_val[i];
+		unsigned int len = fcomp.utf8string_len;
+		char *component = fcomp.utf8string_val;
+
+		if (len == 0) {
+			xlog(D_GENERAL, "%s: Zero-length component", __func__);
+			free(result);
+			return FEDFS_ERR_BADNAME;
+		}
+
+		if (len > NAME_MAX) {
+			xlog(D_GENERAL, "%s: Component length too long",
+				__func__);
+			free(result);
+			return FEDFS_ERR_NAMETOOLONG;
+		}
+
+		if (strchr(component, '/') != NULL) {
+			xlog(D_GENERAL, "%s: Local separator "
+				"character found in component",
+				__func__);
+			free(result);
+			return FEDFS_ERR_BADNAME;
+		}
+
+		if (strlen(result) + STRLEN_SLASH + len >= PATH_MAX) {
+			xlog(D_GENERAL, "%s: FedFsPathName "
+				"too long", __func__);
+			free(result);
+			return FEDFS_ERR_NAMETOOLONG;
+		}
+
+		strcat(result, "/");
+		strcat(result, component);
+	}
+
+	if (!nsdb_pathname_is_utf8(result)) {
+		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
+		free(result);
+		return FEDFS_ERR_BADCHAR;
+	}
+
+	*pathname = nsdb_normalize_path(result);
+	free(result);
+	if (*pathname == NULL)
+		return FEDFS_ERR_SVRFAULT;
+	return FEDFS_OK;
+}
diff --git a/src/libpath/Makefile.am b/src/libpath/Makefile.am
deleted file mode 100644
index 3b13423..0000000
--- a/src/libpath/Makefile.am
+++ /dev/null
@@ -1,35 +0,0 @@
-##
-## @file src/libpath/Makefile.am
-## @brief Process this file with automake to produce src/libpath/Makefile.in
-##
-
-##
-## Copyright 2010 Oracle.  All rights reserved.
-##
-## This file is part of fedfs-utils.
-##
-## fedfs-utils is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License version 2.0 as
-## published by the Free Software Foundation.
-##
-## fedfs-utils 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 General Public License version 2.0 for more details.
-##
-## You should have received a copy of the GNU General Public License
-## version 2.0 along with fedfs-utils.  If not, see:
-##
-##	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
-##
-
-noinst_LIBRARIES	= libpath.a
-libpath_a_SOURCES	= path.c
-
-CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
-DISTCLEANFILES		= Makefile.in
-
-AM_CFLAGS		= -ggdb -fstrict-aliasing -fpie -Wall -Wextra \
-			  -pedantic -Wformat=2 -Wstrict-aliasing=2 \
-			  -Wp,-D_FORTIFY_SOURCE=2
-AM_CPPFLAGS		= -I. -I$(top_srcdir)/src/include
diff --git a/src/libpath/path.c b/src/libpath/path.c
deleted file mode 100644
index 91c648c..0000000
--- a/src/libpath/path.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/**
- * @file src/libpath/path.c
- * @brief Encode and decode FedFS pathnames
- */
-
-/*
- * Copyright 2010 Oracle.  All rights reserved.
- *
- * This file is part of fedfs-utils.
- *
- * fedfs-utils is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2.0 as
- * published by the Free Software Foundation.
- *
- * fedfs-utils 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 General Public License version 2.0 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2.0 along with fedfs-utils.  If not, see:
- *
- *	http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <stdbool.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <ldap.h>
-
-#include <netinet/in.h>
-
-#include "junction.h"
-#include "path.h"
-#include "xlog.h"
-
-#define STRLEN_SLASH	((size_t)1)	/* strlen("/") */
-#define STRLEN_NUL	((size_t)1)	/* strlen("") */
-
-#define XDR_UINT_BYTES	(4)
-
-/**
- * Compute count of XDR 4-octet units from byte count
- *
- * @param bytes number of bytes to convert
- * @return equivalent number of XDR 4-octet units
- */
-static inline unsigned int
-nsdb_quadlen(const unsigned int bytes)
-{
-	return (bytes + 3) >> 2;
-}
-
-/**
- * Sanitize an incoming POSIX path
- *
- * @param pathname NUL-terminated C string containing a POSIX pathname
- * @return NUL-terminated C string containing sanitized path
- *
- * Caller must free the returned pathname with free(3).
- *
- * Remove multiple sequential slashes and any trailing slashes,
- * but leave "/" by itself alone.
- */
-__attribute_malloc__ char *
-nsdb_normalize_path(const char *pathname)
-{
-	size_t i, j, len;
-	char *result;
-
-	len = strlen(pathname);
-	if (len == 0) {
-		xlog(D_CALL, "%s: NULL pathname", __func__);
-		return NULL;
-	}
-
-	result = malloc(len + 1);
-	if (result == NULL) {
-		xlog(L_ERROR, "%s: Failed to allocate pathname buffer",
-			__func__);
-		return NULL;
-	}
-
-	for (i = 0, j = 0; i < len; i++) {
-		if (pathname[i] == '/' && pathname[i + 1] == '/')
-			continue;
-		result[j++] = pathname[i];
-	}
-	result[j] = '\0';
-
-	if (j > 1 && result[j - 1] == '/')
-		result[j - 1] = '\0';
-
-	xlog(D_CALL, "%s: result = '%s'", __func__, result);
-	return result;
-}
-
-/**
- * Count the number of components in a POSIX pathname
- *
- * @param pathname NUL-terminated C string containing a POSIX pathname
- * @param len OUT: number of bytes the encoded XDR stream will consume
- * @param cnt OUT: component count
- * @return true when successful
- */
-static _Bool
-nsdb_count_components(const char *pathname, size_t *len,
-		unsigned int *cnt)
-{
-	char *start, *component;
-	unsigned int count;
-	size_t length;
-
-	/* strtok(3) will tromp on the string */
-	start = strdup(pathname);
-	if (start == NULL) {
-		xlog(L_ERROR, "%s: Failed to duplicate pathname",
-			__func__);
-		return false;
-	}
-
-	length = XDR_UINT_BYTES;
-	count = 0;
-	component = start;
-	for ( ;; ) {
-		char *next;
-
-		if (*component == '/')
-			component++;
-		if (*component == '\0')
-			break;
-		next = strchrnul(component, '/');
-		length += XDR_UINT_BYTES + (nsdb_quadlen(next - component) << 2);
-		count++;
-
-		if (*next == '\0')
-			break;
-		component = next;
-	}
-
-	free(start);
-
-	xlog(D_CALL, "%s: length = %zu, count = %u, path = '%s'",
-		__func__, length, count, pathname);
-	*len = length;
-	*cnt = count;
-	return true;
-}
-
-/**
- * Predicate: is input character set for a POSIX pathname valid UTF-8?
- *
- * @param pathname NUL-terminated C string containing a POSIX path
- * @return true if the string is valid UTF-8
- *
- * XXX: implement this
- */
-_Bool
-nsdb_pathname_is_utf8(__attribute__((unused)) const char *pathname)
-{
-	return true;
-}
-
-/**
- * XDR encode a POSIX path name
- *
- * @param pathname NUL-terminated C string containing a POSIX path
- * @param xdr_path OUT: pointer to XDR-encoded path in a berval
- * @return a FedFsStatus code
- *
- * Caller must free xdr_path->bv_val with free(3)
- *
- * The XDR encoded result is described by the NSDB protocol draft as
- * "an XDR encoded variable length array of variable length opaque
- * data."  The result of this encoding is a byte stream.
- */
-FedFsStatus
-nsdb_posix_path_to_xdr(const char *pathname, struct berval *xdr_path)
-{
-	char *component, *normalized;
-	unsigned int i, count;
-	uint32_t *xdrbuf;
-	size_t length;
-
-	if (pathname == NULL || xdr_path == NULL) {
-		xlog(L_ERROR, "%s: Invalid argument", __func__);
-		return FEDFS_ERR_INVAL;
-	}
-
-	if (!nsdb_pathname_is_utf8(pathname)) {
-		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
-		return FEDFS_ERR_BADCHAR;
-	}
-
-	normalized = nsdb_normalize_path(pathname);
-	if (normalized == NULL)
-		return FEDFS_ERR_SVRFAULT;
-
-	/*
-	 * Calculate the number of path components and the
-	 * number of bytes in the encoded result so that a
-	 * buffer for the result can be allocated.
-	 */
-	if (!nsdb_count_components(normalized, &length, &count))
-		return FEDFS_ERR_BADNAME;
-
-	/*
-	 * Flatten the POSIX path into an encoded XDR stream
-	 * stored in the allocated buffer
-	 */
-	xdrbuf = malloc(length);
-	if (xdrbuf == NULL) {
-		xlog(L_ERROR, "%s: Failed to allocate XDR buffer",
-			__func__);
-		free(normalized);
-		return FEDFS_ERR_SVRFAULT;
-	}
-	memset(xdrbuf, 0, length);
-
-	i = 1;
-	xdrbuf[i] = htonl(count);
-	component = normalized;
-	for ( ;; ) {
-		char *next;
-
-		if (*component == '/')
-			component++;
-		if (*component == '\0')
-			break;
-		next = strchrnul(component, '/');
-		length = next - component;
-
-		xdrbuf[i++] = htonl(length);
-		memcpy(&xdrbuf[i], component, length);
-		i += nsdb_quadlen(length);
-
-		if (*next == '\0')
-			break;
-		component = next;
-	}
-
-	xdr_path->bv_val = (char *)xdrbuf;
-	xdr_path->bv_len = (ber_len_t)(i << 2);
-
-	free(normalized);
-	return FEDFS_OK;
-}
-
-/**
- * XDR decode an XDR byte stream into a POSIX path name
- *
- * @param xdr_path berval containing XDR-encoded path
- * @param pathname OUT: pointer to NUL-terminated UTF-8 C string containing a POSIX path name
- * @return a FedFsStatus code
- *
- * Caller must free "pathname" with free(3)
- *
- * Note that the count of array items is ignored.  It's not needed to
- * decode the XDR byte stream correctly.  The only important thing is
- * to avoid reading outside the passed-in XDR byte stream.  That can
- * result in incorrect results or even segfaults.
- */
-FedFsStatus
-nsdb_xdr_to_posix_path(struct berval *xdr_path, char **pathname)
-{
-	const unsigned int buflen = nsdb_quadlen((unsigned int)xdr_path->bv_len);
-	uint32_t *buf = (uint32_t *)xdr_path->bv_val;
-	unsigned int i;
-	uint32_t size;
-	size_t length;
-	char *result;
-
-	if (xdr_path == NULL || pathname == NULL) {
-		xlog(L_ERROR, "%s: Invalid argument", __func__);
-		return FEDFS_ERR_INVAL;
-	}
-
-	i = 1;		/* skip the count of array elements */
-	length = STRLEN_NUL;
-	for ( ;; ) {
-		length += STRLEN_SLASH;
-		if (i >= buflen)
-			break;
-
-		size = ntohl(buf[i++]);
-		i += nsdb_quadlen(size);
-		if (i == buflen)
-			break;
-		if (i > buflen) {
-			xlog(D_GENERAL, "%s: XDR decoding error", __func__);
-			return FEDFS_ERR_BADXDR;
-		}
-
-		length += size;
-	}
-
-	result = malloc(length);
-	if (result == NULL) {
-		xlog(L_ERROR, "%s: Failed to allocate pathname buffer",
-			__func__);
-		return FEDFS_ERR_SVRFAULT;
-	}
-	result[0] = '\0';
-
-	i = 1;		/* skip the count of elements */
-	for ( ;; ) {
-		strcat(result, "/");
-		if (i == buflen)
-			break;
-
-		size = ntohl(buf[i++]);
-		strncat(result, (char *)&buf[i], size);
-		i += nsdb_quadlen(size);
-		if (i == buflen)
-			break;
-	}
-
-	if (!nsdb_pathname_is_utf8(result)) {
-		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
-		free(result);
-		return FEDFS_ERR_BADCHAR;
-	}
-
-	*pathname = result;
-	return FEDFS_OK;
-}
-
-/**
- * Free a FedFsPathComponent allocated by nsdb_new_component
- *
- * @param fcomp pointer to FedFsPathComponent to free
- */
-static void
-nsdb_free_component(FedFsPathComponent *fcomp)
-{
-	free(fcomp->utf8string_val);
-	fcomp->utf8string_val = NULL;
-	fcomp->utf8string_len = 0;
-}
-
-/**
- * Allocate a FedFsPathComponent
- *
- * @param component UTF-8 C string containing one path component
- * @param length count of bytes in "component"
- * @param fcomp OUT: newly allocated FedFsPathComponent; caller must free with nsdb_free_component
- * @return true if successful, otherwise false
- */
-static _Bool
-nsdb_new_component(const char *component, size_t length,
-		FedFsPathComponent *fcomp)
-{
-	fcomp->utf8string_val = strndup(component, length);
-	if (fcomp->utf8string_val == NULL)
-		return false;
-	fcomp->utf8string_len = length;
-	return true;
-}
-
-/**
- * Free resources associated with a FedFsPathName
- *
- * @param fpath pointer to FedFsPathName
- */
-void
-nsdb_free_fedfspathname(FedFsPathName *fpath)
-{
-	unsigned int i;
-
-	for (i = 0; i < fpath->FedFsPathName_len; i++)
-		nsdb_free_component(&fpath->FedFsPathName_val[i]);
-	free(fpath->FedFsPathName_val);
-}
-
-/**
- * Construct a FedFsPathName from a C string
- *
- * @param pathname NUL-terminated C string containing a POSIX pathname
- * @param fpath OUT: pointer to FedFsPathName in which to construct path
- * @return a FedFsStatus code
- */
-FedFsStatus
-nsdb_posix_to_fedfspathname(const char *pathname, FedFsPathName *fpath)
-{
-	char *normalized, *component;
-	unsigned int i, count;
-	size_t length;
-
-	if (!nsdb_pathname_is_utf8(pathname)) {
-		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
-		return FEDFS_ERR_BADCHAR;
-	}
-
-	normalized = nsdb_normalize_path(pathname);
-	if (normalized == NULL)
-		return FEDFS_ERR_SVRFAULT;
-
-	if (!nsdb_count_components(normalized, &length, &count))
-		return FEDFS_ERR_BADNAME;
-
-	/* The path "/" MUST be encoded as an array with zero components. */
-	if (count == 0) {
-		fpath->FedFsPathName_val = NULL;
-		fpath->FedFsPathName_len = 0;
-		return FEDFS_OK;
-	}
-
-	fpath->FedFsPathName_val = calloc(count, sizeof(FedFsPathComponent));
-	if (fpath->FedFsPathName_val == NULL)
-		return FEDFS_ERR_SVRFAULT;
-	fpath->FedFsPathName_len = count;
-
-	i = 0;
-	component = normalized;
-	for (i = 0; ; i++) {
-		char *next;
-
-		if (*component == '/')
-			component++;
-		if (*component == '\0')
-			break;
-		next = strchrnul(component, '/');
-		length = next - component;
-
-		if (!nsdb_new_component(component,
-				length, &fpath->FedFsPathName_val[i]))
-			goto out_err;
-
-		if (*next == '\0')
-			break;
-		component = next;
-	}
-
-	return FEDFS_OK;
-
-out_err:
-	xlog(D_GENERAL, "%s: Failed to allocate new pathname component",
-		__func__);
-	nsdb_free_fedfspathname(fpath);
-	return FEDFS_ERR_SVRFAULT;
-}
-
-/**
- * Construct a local Posix-style path from a FedFsPathName 
- *
- * @param fpath FedFsPathName from which to construct path
- * @param pathname OUT: pointer to NUL-terminated UTF-8 C string containing a Posix-style path
- * @return a FedFsStatus code
- *
- * Caller must free the returned pathname with free(3).
- *
- * NB: The use of fixed constants for NAME_MAX and PATH_MAX are required
- *     here because, on the client side, the pathname likely does not
- *     exist, so pathconf(3) cannot be used.
- */
-FedFsStatus
-nsdb_fedfspathname_to_posix(const FedFsPathName fpath, char **pathname)
-{
-	unsigned int i;
-	char *result;
-
-	result = malloc(PATH_MAX);
-	if (result == NULL) {
-		xlog(D_GENERAL, "%s: Failed to allocate buffer for result",
-			__func__);
-		return FEDFS_ERR_SVRFAULT;
-	}
-	result[0] = '\0';
-
-	if (fpath.FedFsPathName_len == 0) {
-		xlog(D_GENERAL, "%s: Zero-component pathname", __func__);
-		strcat(result, "/");
-		*pathname = result;
-		return FEDFS_OK;
-	}
-
-	for (i = 0; i < fpath.FedFsPathName_len; i++) {
-		FedFsPathComponent fcomp = fpath.FedFsPathName_val[i];
-		unsigned int len = fcomp.utf8string_len;
-		char *component = fcomp.utf8string_val;
-
-		if (len == 0) {
-			xlog(D_GENERAL, "%s: Zero-length component", __func__);
-			free(result);
-			return FEDFS_ERR_BADNAME;
-		}
-
-		if (len > NAME_MAX) {
-			xlog(D_GENERAL, "%s: Component length too long",
-				__func__);
-			free(result);
-			return FEDFS_ERR_NAMETOOLONG;
-		}
-
-		if (strchr(component, '/') != NULL) {
-			xlog(D_GENERAL, "%s: Local separator "
-				"character found in component",
-				__func__);
-			free(result);
-			return FEDFS_ERR_BADNAME;
-		}
-
-		if (strlen(result) + STRLEN_SLASH + len >= PATH_MAX) {
-			xlog(D_GENERAL, "%s: FedFsPathName "
-				"too long", __func__);
-			free(result);
-			return FEDFS_ERR_NAMETOOLONG;
-		}
-
-		strcat(result, "/");
-		strcat(result, component);
-	}
-
-	if (!nsdb_pathname_is_utf8(result)) {
-		xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
-		free(result);
-		return FEDFS_ERR_BADCHAR;
-	}
-
-	*pathname = nsdb_normalize_path(result);
-	free(result);
-	if (*pathname == NULL)
-		return FEDFS_ERR_SVRFAULT;
-	return FEDFS_OK;
-}
diff --git a/src/nsdbc/Makefile.am b/src/nsdbc/Makefile.am
index 1f8b79f..9dfb642 100644
--- a/src/nsdbc/Makefile.am
+++ b/src/nsdbc/Makefile.am
@@ -32,8 +32,7 @@ LDADD			= $(LIBLDAP) $(LIBLBER) \
 			  $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) \
 			  $(top_builddir)/src/libnsdb/libnsdb.a \
 			  $(top_builddir)/src/libxlog/libxlog.a \
-			  $(top_builddir)/src/libjunction/libjunction.a \
-			  $(top_builddir)/src/libpath/libpath.a
+			  $(top_builddir)/src/libjunction/libjunction.a
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
 DISTCLEANFILES		= Makefile.in
diff --git a/src/nsdbparams/Makefile.am b/src/nsdbparams/Makefile.am
index 6205e32..2109c87 100644
--- a/src/nsdbparams/Makefile.am
+++ b/src/nsdbparams/Makefile.am
@@ -30,7 +30,6 @@ LDADD			= $(LIBLDAP) $(LIBLBER) \
 			  $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) $(LIBCAP) \
 			  $(top_builddir)/src/libnsdb/libnsdb.a \
 			  $(top_builddir)/src/libjunction/libjunction.a \
-			  $(top_builddir)/src/libpath/libpath.a \
 			  $(top_builddir)/src/libxlog/libxlog.a
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
diff --git a/src/resolve-junction/Makefile.am b/src/resolve-junction/Makefile.am
index 9149042..ec5f5a7 100644
--- a/src/resolve-junction/Makefile.am
+++ b/src/resolve-junction/Makefile.am
@@ -32,7 +32,6 @@ LDADD			= $(LIBLDAP) $(LIBLBER) \
 			  $(top_builddir)/src/libadmin/libadmin.a \
 			  $(top_builddir)/src/libnsdb/libnsdb.a \
 			  $(top_builddir)/src/libjunction/libjunction.a \
-			  $(top_builddir)/src/libpath/libpath.a \
 			  $(top_builddir)/src/libxlog/libxlog.a
 
 CLEANFILES		= cscope.in.out cscope.out cscope.po.out *~
