--- old/usr/src/cmd/ndmpd/tlm/tlm_traverse.c	Mon Aug  5 17:15:21 2019
+++ new/usr/src/cmd/ndmpd/tlm/tlm_traverse.c	Mon Aug  5 17:15:21 2019
@@ -35,6 +35,8 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+/* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
+
 /*
  * This file implemets the post-order, pre-order and level-order
  * traversing of the file system.  The related macros and constants
@@ -80,7 +82,6 @@
  */
 #define	STOP_ONERR(f)	((f)->ft_flags & FST_STOP_ONERR)
 #define	STOP_ONLONG(f)	((f)->ft_flags & FST_STOP_ONLONG)
-#define	VERBOSE(f)	((f)->ft_flags & FST_VERBOSE)
 
 #define	CALLBACK(pp, ep)	\
 	(*(ftp)->ft_callbk)((ftp)->ft_arg, pp, ep)
@@ -104,30 +105,6 @@
 	struct stat64 ts_st;
 } traverse_state_t;
 
-/*
- * Statistics gathering structure.
- */
-typedef struct traverse_statistics {
-	ulong_t fss_newdirs;
-	ulong_t fss_readdir_err;
-	ulong_t fss_longpath_err;
-	ulong_t fss_lookup_err;
-	ulong_t fss_nondir_calls;
-	ulong_t fss_dir_calls;
-	ulong_t fss_nondir_skipped;
-	ulong_t fss_dir_skipped;
-	ulong_t fss_pushes;
-	ulong_t fss_pops;
-	ulong_t fss_stack_residue;
-} traverse_statistics_t;
-
-/*
- * Global instance of statistics variable.
- */
-traverse_statistics_t traverse_stats;
-
-#define	MAX_DENT_BUF_SIZE	(8 * 1024)
-
 typedef struct {
 	struct stat64 fd_attr;
 	fs_fhandle_t fd_fh;
@@ -142,41 +119,9 @@
 } dent_arg_t;
 
 static int traverse_level_nondir(struct fs_traverse *ftp,
-    traverse_state_t *tsp, struct fst_node *pnp,
-    dent_arg_t *darg);
+    traverse_state_t *tsp, struct fst_node *pnp);
 
 /*
- * Gather some directory entry information and return them
- */
-static int
-fs_populate_dents(void *arg, int namelen,
-    char *name, long *countp, struct stat64 *attr,
-    fs_fhandle_t *fh)
-{
-	dent_arg_t *darg = (dent_arg_t *)arg;
-	int reclen = sizeof (fs_dent_info_t) + namelen;
-	fs_dent_info_t *dent;
-
-	if ((darg->da_end + reclen) > darg->da_size)
-		return (-1);
-
-	/* LINTED improper alignment */
-	dent = (fs_dent_info_t *)(darg->da_buf + darg->da_end);
-
-	dent->fd_attr = *attr;
-	dent->fd_fh = *fh;
-	(void) strcpy(dent->fd_name, name);
-
-	dent->fd_len = reclen;
-	darg->da_end += reclen;
-
-	if (countp)
-		(*countp)++;
-
-	return (0);
-}
-
-/*
  * Creates a new traversing state based on the path passed to it.
  */
 static traverse_state_t *
@@ -202,8 +147,11 @@
 int
 fs_getstat(char *path, fs_fhandle_t *fh, struct stat64 *st)
 {
-	if (lstat64(path, st) == -1)
+	if (lstat64(path, st) == -1) {
+		syslog(LOG_INFO,
+		    "lstat64() says [%s] not found errno=(%d)", path, errno);
 		return (errno);
+	}
 
 	fh->fh_fid = st->st_ino;
 
@@ -215,70 +163,6 @@
 }
 
 /*
- * Get directory entries info and return in the buffer. Cookie
- * will keep the state of each call
- */
-static int
-fs_getdents(int fildes, struct dirent *buf, size_t *nbyte,
-    char *pn_path, long *dpos, longlong_t *cookie,
-    long *n_entries, dent_arg_t *darg)
-{
-	struct dirent *ptr;
-	char file_path[PATH_MAX + 1];
-	fs_fhandle_t fh;
-	struct stat64 st;
-	char *p;
-	int len;
-	int rv;
-
-	if (*nbyte == 0) {
-		(void) memset((char *)buf, 0, MAX_DENT_BUF_SIZE);
-		*nbyte = rv = getdents(fildes, buf, darg->da_size);
-		*cookie = 0LL;
-
-		if (rv <= 0)
-			return (rv);
-	}
-
-	p = (char *)buf + *cookie;
-	len = *nbyte;
-	do {
-		/* LINTED improper alignment */
-		ptr = (struct dirent *)p;
-		*dpos =  ptr->d_off;
-
-		if (rootfs_dot_or_dotdot(ptr->d_name))
-			goto skip_entry;
-
-		(void) snprintf(file_path, PATH_MAX, "%s/", pn_path);
-		(void) strlcat(file_path, ptr->d_name, PATH_MAX + 1);
-		(void) memset(&fh, 0, sizeof (fs_fhandle_t));
-
-		if (lstat64(file_path, &st) != 0) {
-			rv = -1;
-			break;
-		}
-
-		fh.fh_fid = st.st_ino;
-
-		if (S_ISDIR(st.st_mode))
-			goto skip_entry;
-
-		if (fs_populate_dents(darg, strlen(ptr->d_name),
-		    (char *)ptr->d_name, n_entries, &st, &fh) != 0)
-			break;
-
-skip_entry:
-		p = p + ptr->d_reclen;
-		len -= ptr->d_reclen;
-	} while (len);
-
-	*cookie = (longlong_t)(p - (char *)buf);
-	*nbyte = len;
-	return (rv);
-}
-
-/*
  * Read the directory entries and return the information about
  * each entry
  */
@@ -338,7 +222,6 @@
 	struct fst_node pn, en; /* parent and entry nodes */
 
 	if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
-		NDMP_LOG(LOG_DEBUG, "Invalid argument");
 		errno = EINVAL;
 		return (-1);
 	}
@@ -346,12 +229,12 @@
 	/* set the default log function if it's not already set */
 	if (!ftp->ft_logfp) {
 		ftp->ft_logfp = (ft_log_t)syslog;
-		NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
+		syslog(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
 	}
 
 	/* set the logical path to physical path if it's not already set */
 	if (!ftp->ft_lpath) {
-		NDMP_LOG(LOG_DEBUG,
+		syslog(LOG_DEBUG,
 		    "report the same paths: \"%s\"", ftp->ft_path);
 		ftp->ft_lpath = ftp->ft_path;
 	}
@@ -358,7 +241,7 @@
 
 	pl = strlen(ftp->ft_lpath);
 	if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
-		NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
+		syslog(LOG_ERR, "lpath too long \"%s\"", ftp->ft_path);
 		errno = ENAMETOOLONG;
 		return (-1);
 	}
@@ -367,7 +250,7 @@
 	rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
 
 	if (rv != 0) {
-		NDMP_LOG(LOG_DEBUG,
+		syslog(LOG_ERR,
 		    "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
 		return (rv);
 	}
@@ -380,8 +263,6 @@
 		en.tn_fh = NULL;
 		en.tn_st = NULL;
 		rv = CALLBACK(&pn, &en);
-		if (VERBOSE(ftp))
-			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
 		free(pfh.fh_fpath);
 		return (rv);
 	}
@@ -410,11 +291,7 @@
 	next_dir = 1;
 	do {
 		if (next_dir) {
-			traverse_stats.fss_newdirs++;
-
 			*tsp->ts_end = '\0';
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
 		}
 
 		next_dir = 0;
@@ -425,10 +302,7 @@
 			    &efh, &est);
 
 			if (rv != 0) {
-				free(efh.fh_fpath);
-				traverse_stats.fss_readdir_err++;
-
-				NDMP_LOG(LOG_DEBUG,
+				syslog(LOG_ERR,
 				    "Error %d on readdir(%s) pos %d",
 				    rv, path, tsp->ts_dpos);
 				if (STOP_ONERR(ftp))
@@ -440,9 +314,6 @@
 
 			/* done with this directory */
 			if (el == 0) {
-				if (VERBOSE(ftp))
-					NDMP_LOG(LOG_DEBUG,
-					    "Done(%s)", pn.tn_path);
 				break;
 			}
 			nm[el] = '\0';
@@ -452,14 +323,8 @@
 				continue;
 			}
 
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
-				    tsp->ts_dpos, nm);
-
 			if (pl + 1 + el > PATH_MAX) {
-				traverse_stats.fss_longpath_err++;
-
-				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
+				syslog(LOG_ERR, "Path %s/%s is too long.",
 				    path, nm);
 				if (STOP_ONLONG(ftp))
 					rv = ENAMETOOLONG;
@@ -479,7 +344,6 @@
 					free(efh.fh_fpath);
 					break;
 				}
-				traverse_stats.fss_pushes++;
 
 				/*
 				 * Concatenate the current entry with the
@@ -518,18 +382,11 @@
 				 * The entry is not a directory so the
 				 * callback function must be called.
 				 */
-				traverse_stats.fss_nondir_calls++;
-
 				en.tn_path = nm;
 				en.tn_fh = &efh;
 				en.tn_st = &est;
 				rv = CALLBACK(&pn, &en);
 				free(efh.fh_fpath);
-				if (VERBOSE(ftp))
-					NDMP_LOG(LOG_DEBUG,
-					    "CALLBACK(%s/%s): %d",
-					    pn.tn_path, en.tn_path, rv);
-
 				if (rv != 0)
 					break;
 			}
@@ -561,13 +418,6 @@
 			assert(tsp != NULL);
 			pl = tsp->ts_end - path;
 
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG, "poped pl %d 0x%p \"%s\"",
-				    pl, tsp, path);
-
-			traverse_stats.fss_pops++;
-			traverse_stats.fss_dir_calls++;
-
 			pn.tn_fh = &tsp->ts_fh;
 			pn.tn_st = &tsp->ts_st;
 			en.tn_path = lp + 1;
@@ -576,9 +426,6 @@
 
 			rv = CALLBACK(&pn, &en);
 			free(efh.fh_fpath);
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG, "CALLBACK(%s/%s): %d",
-				    pn.tn_path, en.tn_path, rv);
 			/*
 			 * Does not need to free tsp here.  It will be released
 			 * later.
@@ -596,8 +443,6 @@
 	 * For the 'ftp->ft_path' directory itself.
 	 */
 	if (rv == 0) {
-		traverse_stats.fss_dir_calls++;
-
 		pn.tn_fh = &efh;
 		pn.tn_st = &est;
 		en.tn_path = NULL;
@@ -604,8 +449,6 @@
 		en.tn_fh = NULL;
 		en.tn_st = NULL;
 		rv = CALLBACK(&pn, &en);
-		if (VERBOSE(ftp))
-			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
 	}
 
 	/*
@@ -612,8 +455,6 @@
 	 * Pop and free all the remaining entries on the stack.
 	 */
 	while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
-		traverse_stats.fss_stack_residue++;
-
 		free(tsp->ts_fh.fh_fpath);
 		free(tsp);
 	}
@@ -637,103 +478,67 @@
  */
 static int
 traverse_level_nondir(struct fs_traverse *ftp,
-    traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
+    traverse_state_t *tsp, struct fst_node *pnp)
 {
-	int pl; /* path length */
-	int rv;
+	struct stat64 st;
+	fs_fhandle_t fh;
+	DIR *dp;
+	struct dirent *dirp;
 	struct fst_node en; /* entry node */
-	longlong_t cookie_verf;
-	fs_dent_info_t *dent;
-	struct dirent *buf;
-	size_t len = 0;
-	int fd;
+	char path[MAXPATHLEN+MAXNAMELEN+2];
+	int rv = 0;
 
-	rv = 0;
-	pl = strlen(pnp->tn_path);
-
-	buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
-	if (buf == NULL)
+	if ((dp = opendir(tsp->ts_fh.fh_fpath)) == NULL) {
+		syslog(LOG_ERR,
+		    "traverse_level_nondir: open directory "
+		    "%s failed: %m", tsp->ts_fh.fh_fpath);
 		return (errno);
-
-	fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
-	if (fd == -1) {
-		free(buf);
-		return (errno);
 	}
 
-	while (rv == 0) {
-		long i, n_entries;
+	while ((dirp = readdir(dp)) != NULL) {
+		if ((strcmp(dirp->d_name, ".") == 0) ||
+		    (strcmp(dirp->d_name, "..") == 0)) {
+			continue;
+		}
 
-		darg->da_end = 0;
-		n_entries = 0;
-		rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
-		    &cookie_verf, &n_entries, darg);
-		if (rv < 0) {
-			traverse_stats.fss_readdir_err++;
+		if (!tlm_cat_path(path, tsp->ts_fh.fh_fpath,
+		    dirp->d_name)) {
+			continue;
+		}
 
-			NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
-			    rv, pnp->tn_path, tsp->ts_dpos);
-			if (STOP_ONERR(ftp))
-				break;
-			/*
-			 * We cannot read the directory entry, we should
-			 * skip to the next directory.
-			 */
-			rv = SKIP_ENTRY;
+		if (lstat64(path, &st) != 0) {
+			syslog(LOG_ERR,
+			    "traverse_level_nondir: failed to get file"
+			    " status for %s skipping: %m", tsp->ts_fh.fh_fpath);
 			continue;
-		} else {
-			/* Break at the end of directory */
-			if (rv > 0)
-				rv = 0;
-			else
-				break;
 		}
+		fh.fh_fid = st.st_ino;
 
-		/* LINTED imporper alignment */
-		dent = (fs_dent_info_t *)darg->da_buf;
-		/* LINTED imporper alignment */
-		for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
-		    ((char *)dent + dent->fd_len)) {
-
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
-				    dent->fd_fh.fh_fid, dent->fd_name);
-
-			if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
-				traverse_stats.fss_longpath_err++;
-
-				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
-				    pnp->tn_path, dent->fd_name);
-				if (STOP_ONLONG(ftp))
-					rv = -ENAMETOOLONG;
-				free(dent->fd_fh.fh_fpath);
-				continue;
+		/*
+		 * The entry is not a directory so the callback
+		 * function must be called.
+		 */
+		if (!S_ISDIR(st.st_mode)) {
+			en.tn_path = dirp->d_name;
+			en.tn_fh = &fh;
+			en.tn_st = &st;
+			rv = CALLBACK(pnp, &en);
+			if (rv < 0) {
+				syslog(LOG_DEBUG,
+				    "traverse_level_nondir: result is %d "
+				    "with %s", rv, path);
+				break;
 			}
-
-			/*
-			 * The entry is not a directory so the callback
-			 * function must be called.
-			 */
-			if (!S_ISDIR(dent->fd_attr.st_mode)) {
-				traverse_stats.fss_nondir_calls++;
-
-				en.tn_path = dent->fd_name;
-				en.tn_fh = &dent->fd_fh;
-				en.tn_st = &dent->fd_attr;
-				rv = CALLBACK(pnp, &en);
-				dent->fd_fh.fh_fpath = NULL;
-				if (rv < 0)
-					break;
-				if (rv == FST_SKIP) {
-					traverse_stats.fss_nondir_skipped++;
-					break;
-				}
+			if (rv == FST_SKIP) {
+				syslog(LOG_DEBUG,
+				    "traverse_level_nondir: skipping "
+				    "%s", path);
+				break;
 			}
 		}
 	}
 
-	free(buf);
-	(void) close(fd);
+	(void) closedir(dp);
 	return (rv);
 }
 
@@ -755,10 +560,8 @@
 	struct stat64 pst, est;
 	traverse_state_t *tsp;
 	struct fst_node pn, en;  /* parent and entry nodes */
-	dent_arg_t darg;
 
 	if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
-		NDMP_LOG(LOG_DEBUG, "Invalid argument");
 		errno = EINVAL;
 		return (-1);
 	}
@@ -765,10 +568,10 @@
 	/* set the default log function if it's not already set */
 	if (!ftp->ft_logfp) {
 		ftp->ft_logfp = (ft_log_t)syslog;
-		NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
+		syslog(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
 	}
 	if (!ftp->ft_lpath) {
-		NDMP_LOG(LOG_DEBUG,
+		syslog(LOG_DEBUG,
 		    "report the same paths \"%s\"", ftp->ft_path);
 		ftp->ft_lpath = ftp->ft_path;
 	}
@@ -775,7 +578,7 @@
 
 	pl = strlen(ftp->ft_lpath);
 	if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
-		NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
+		syslog(LOG_ERR, "lpath too long \"%s\"", ftp->ft_path);
 		errno = ENAMETOOLONG;
 		return (-1);
 	}
@@ -783,8 +586,8 @@
 	(void) memset(&pfh, 0, sizeof (pfh));
 	rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
 	if (rv != 0) {
-		NDMP_LOG(LOG_DEBUG,
-		    "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
+		syslog(LOG_DEBUG,
+		    "Error %d on fs_getstat(%s)", rv, ftp->ft_lpath);
 		return (-1);
 	}
 
@@ -796,9 +599,6 @@
 		pn.tn_fh = &pfh;
 		pn.tn_st = &pst;
 		rv = CALLBACK(&pn, &en);
-		if (VERBOSE(ftp))
-			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
-
 		free(pfh.fh_fpath);
 		return (rv);
 	}
@@ -817,16 +617,6 @@
 		return (-1);
 	}
 
-	darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
-	if (!darg.da_buf) {
-		cstack_delete(sp);
-		free(pfh.fh_fpath);
-		free(tsp);
-		errno = ENOMEM;
-		return (-1);
-	}
-	darg.da_size = MAX_DENT_BUF_SIZE;
-
 	tsp->ts_ent = tsp->ts_end;
 	tsp->ts_fh = pfh;
 	tsp->ts_st = pst;
@@ -835,7 +625,6 @@
 	pn.tn_st = &tsp->ts_st;
 
 	/* call the callback function on the path itself */
-	traverse_stats.fss_dir_calls++;
 	rv = CALLBACK(&pn, &en);
 	if (rv < 0) {
 		free(tsp);
@@ -842,7 +631,6 @@
 		goto end;
 	}
 	if (rv == FST_SKIP) {
-		traverse_stats.fss_dir_skipped++;
 		free(tsp);
 		rv = 0;
 		goto end;
@@ -852,13 +640,8 @@
 	next_dir = 1;
 	do {
 		if (next_dir) {
-			traverse_stats.fss_newdirs++;
-
 			*tsp->ts_end = '\0';
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
-
-			rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
+			rv = traverse_level_nondir(ftp, tsp, &pn);
 			if (rv < 0) {
 				NEGATE(rv);
 				free(tsp->ts_fh.fh_fpath);
@@ -893,9 +676,7 @@
 			    &tsp->ts_dpos, nm, &el, &efh,
 			    &est);
 			if (rv != 0) {
-				traverse_stats.fss_readdir_err++;
-
-				NDMP_LOG(LOG_DEBUG,
+				syslog(LOG_DEBUG,
 				    "Error %d on readdir(%s) pos %d",
 				    rv, path, tsp->ts_dpos);
 				if (STOP_ONERR(ftp))
@@ -915,10 +696,6 @@
 				continue;
 			}
 
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
-				    tsp->ts_dpos, nm);
-
 			if (pl + 1 + el > PATH_MAX) {
 				/*
 				 * The long paths were already encountered
@@ -927,7 +704,7 @@
 				 * We don't increase fss_longpath_err
 				 * counter for them again here.
 				 */
-				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
+				syslog(LOG_ERR, "Path %s/%s is too long.",
 				    path, nm);
 				if (STOP_ONLONG(ftp))
 					rv = ENAMETOOLONG;
@@ -944,7 +721,6 @@
 			 * directory on to the stack.  Then dive
 			 * into the entry found.
 			 */
-			traverse_stats.fss_dir_calls++;
 			en.tn_path = nm;
 			en.tn_fh = &efh;
 			en.tn_st = &est;
@@ -956,7 +732,6 @@
 				break;
 			}
 			if (rv == FST_SKIP) {
-				traverse_stats.fss_dir_skipped++;
 				free(efh.fh_fpath);
 				rv = 0;
 				continue;
@@ -969,8 +744,6 @@
 			if (cstack_push(sp, tsp, 0)) {
 				rv = ENOMEM;
 			} else {
-				traverse_stats.fss_pushes++;
-
 				lp = tsp->ts_end;
 				*tsp->ts_end = '/';
 				(void) strcpy(tsp->ts_end + 1, nm);
@@ -1011,12 +784,6 @@
 			if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
 				break;
 
-			traverse_stats.fss_pops++;
-
-			if (VERBOSE(ftp))
-				NDMP_LOG(LOG_DEBUG,
-				    "Poped pl %d \"%s\"", pl, path);
-
 			*tsp->ts_end = '\0';
 			pl = tsp->ts_end - path;
 			pn.tn_fh = &tsp->ts_fh;
@@ -1028,13 +795,10 @@
 	 * Pop and free all the remaining entries on the stack.
 	 */
 	while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
-		traverse_stats.fss_stack_residue++;
-
 		free(tsp->ts_fh.fh_fpath);
 		free(tsp);
 	}
 end:
-	free(darg.da_buf);
 	cstack_delete(sp);
 	return (rv);
 }
