17917SReza.Sabdar@Sun.COM /*
2*13120SReza.Sabdar@Sun.COM * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
37917SReza.Sabdar@Sun.COM */
47917SReza.Sabdar@Sun.COM
57917SReza.Sabdar@Sun.COM /*
67917SReza.Sabdar@Sun.COM * BSD 3 Clause License
77917SReza.Sabdar@Sun.COM *
87917SReza.Sabdar@Sun.COM * Copyright (c) 2007, The Storage Networking Industry Association.
97917SReza.Sabdar@Sun.COM *
107917SReza.Sabdar@Sun.COM * Redistribution and use in source and binary forms, with or without
117917SReza.Sabdar@Sun.COM * modification, are permitted provided that the following conditions
127917SReza.Sabdar@Sun.COM * are met:
137917SReza.Sabdar@Sun.COM * - Redistributions of source code must retain the above copyright
147917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer.
157917SReza.Sabdar@Sun.COM *
167917SReza.Sabdar@Sun.COM * - Redistributions in binary form must reproduce the above copyright
177917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer in
187917SReza.Sabdar@Sun.COM * the documentation and/or other materials provided with the
197917SReza.Sabdar@Sun.COM * distribution.
207917SReza.Sabdar@Sun.COM *
217917SReza.Sabdar@Sun.COM * - Neither the name of The Storage Networking Industry Association (SNIA)
227917SReza.Sabdar@Sun.COM * nor the names of its contributors may be used to endorse or promote
237917SReza.Sabdar@Sun.COM * products derived from this software without specific prior written
247917SReza.Sabdar@Sun.COM * permission.
257917SReza.Sabdar@Sun.COM *
267917SReza.Sabdar@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
277917SReza.Sabdar@Sun.COM * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287917SReza.Sabdar@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
297917SReza.Sabdar@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
307917SReza.Sabdar@Sun.COM * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
317917SReza.Sabdar@Sun.COM * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
327917SReza.Sabdar@Sun.COM * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
337917SReza.Sabdar@Sun.COM * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
347917SReza.Sabdar@Sun.COM * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
357917SReza.Sabdar@Sun.COM * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
367917SReza.Sabdar@Sun.COM * POSSIBILITY OF SUCH DAMAGE.
377917SReza.Sabdar@Sun.COM */
387917SReza.Sabdar@Sun.COM /*
397917SReza.Sabdar@Sun.COM * This file implemets the post-order, pre-order and level-order
407917SReza.Sabdar@Sun.COM * traversing of the file system. The related macros and constants
417917SReza.Sabdar@Sun.COM * are defined in traverse.h.
427917SReza.Sabdar@Sun.COM */
437917SReza.Sabdar@Sun.COM
447917SReza.Sabdar@Sun.COM #include <sys/stat.h>
457917SReza.Sabdar@Sun.COM #include <sys/types.h>
467917SReza.Sabdar@Sun.COM #include <sys/param.h>
477917SReza.Sabdar@Sun.COM #include <assert.h>
487917SReza.Sabdar@Sun.COM #include <cstack.h>
497917SReza.Sabdar@Sun.COM #include <dirent.h>
507917SReza.Sabdar@Sun.COM #include <errno.h>
517917SReza.Sabdar@Sun.COM #include <traverse.h>
527917SReza.Sabdar@Sun.COM #include <limits.h>
537917SReza.Sabdar@Sun.COM #include <stdarg.h>
547917SReza.Sabdar@Sun.COM #include <stdio.h>
557917SReza.Sabdar@Sun.COM #include <stdlib.h>
567917SReza.Sabdar@Sun.COM #include <string.h>
577917SReza.Sabdar@Sun.COM #include <syslog.h>
587917SReza.Sabdar@Sun.COM #include <fcntl.h>
597917SReza.Sabdar@Sun.COM #include <unistd.h>
607917SReza.Sabdar@Sun.COM #include <tlm.h>
617917SReza.Sabdar@Sun.COM #include "tlm_proto.h"
627917SReza.Sabdar@Sun.COM
637917SReza.Sabdar@Sun.COM /*
647917SReza.Sabdar@Sun.COM * Check if it's "." or ".."
657917SReza.Sabdar@Sun.COM */
667917SReza.Sabdar@Sun.COM boolean_t
rootfs_dot_or_dotdot(char * name)677917SReza.Sabdar@Sun.COM rootfs_dot_or_dotdot(char *name)
687917SReza.Sabdar@Sun.COM {
697917SReza.Sabdar@Sun.COM if (*name != '.')
707917SReza.Sabdar@Sun.COM return (FALSE);
717917SReza.Sabdar@Sun.COM
727917SReza.Sabdar@Sun.COM if ((name[1] == 0) || (name[1] == '.' && name[2] == 0))
737917SReza.Sabdar@Sun.COM return (TRUE);
747917SReza.Sabdar@Sun.COM
757917SReza.Sabdar@Sun.COM return (FALSE);
767917SReza.Sabdar@Sun.COM }
777917SReza.Sabdar@Sun.COM
787917SReza.Sabdar@Sun.COM /*
797917SReza.Sabdar@Sun.COM * Macros on fs_traverse flags.
807917SReza.Sabdar@Sun.COM */
817917SReza.Sabdar@Sun.COM #define STOP_ONERR(f) ((f)->ft_flags & FST_STOP_ONERR)
827917SReza.Sabdar@Sun.COM #define STOP_ONLONG(f) ((f)->ft_flags & FST_STOP_ONLONG)
837917SReza.Sabdar@Sun.COM #define VERBOSE(f) ((f)->ft_flags & FST_VERBOSE)
847917SReza.Sabdar@Sun.COM
857917SReza.Sabdar@Sun.COM #define CALLBACK(pp, ep) \
867917SReza.Sabdar@Sun.COM (*(ftp)->ft_callbk)((ftp)->ft_arg, pp, ep)
877917SReza.Sabdar@Sun.COM
887917SReza.Sabdar@Sun.COM #define NEGATE(rv) ((rv) = -(rv))
897917SReza.Sabdar@Sun.COM
907917SReza.Sabdar@Sun.COM /*
917917SReza.Sabdar@Sun.COM * The traversing state that is pushed onto the stack.
927917SReza.Sabdar@Sun.COM * This include:
937917SReza.Sabdar@Sun.COM * - The end of the path of the current directory.
947917SReza.Sabdar@Sun.COM * - The position of the last component on it.
957917SReza.Sabdar@Sun.COM * - The read position in the directory.
967917SReza.Sabdar@Sun.COM * - The file handle of the directory.
977917SReza.Sabdar@Sun.COM * - The stat of the directory.
987917SReza.Sabdar@Sun.COM */
997917SReza.Sabdar@Sun.COM typedef struct traverse_state {
1007917SReza.Sabdar@Sun.COM char *ts_end;
1017917SReza.Sabdar@Sun.COM char *ts_ent;
1027917SReza.Sabdar@Sun.COM long ts_dpos; /* position in the directory when reading its entries */
1037917SReza.Sabdar@Sun.COM fs_fhandle_t ts_fh;
1047917SReza.Sabdar@Sun.COM struct stat64 ts_st;
1057917SReza.Sabdar@Sun.COM } traverse_state_t;
1067917SReza.Sabdar@Sun.COM
1077917SReza.Sabdar@Sun.COM /*
1087917SReza.Sabdar@Sun.COM * Statistics gathering structure.
1097917SReza.Sabdar@Sun.COM */
1107917SReza.Sabdar@Sun.COM typedef struct traverse_statistics {
1117917SReza.Sabdar@Sun.COM ulong_t fss_newdirs;
1127917SReza.Sabdar@Sun.COM ulong_t fss_readdir_err;
1137917SReza.Sabdar@Sun.COM ulong_t fss_longpath_err;
1147917SReza.Sabdar@Sun.COM ulong_t fss_lookup_err;
1157917SReza.Sabdar@Sun.COM ulong_t fss_nondir_calls;
1167917SReza.Sabdar@Sun.COM ulong_t fss_dir_calls;
1177917SReza.Sabdar@Sun.COM ulong_t fss_nondir_skipped;
1187917SReza.Sabdar@Sun.COM ulong_t fss_dir_skipped;
1197917SReza.Sabdar@Sun.COM ulong_t fss_pushes;
1207917SReza.Sabdar@Sun.COM ulong_t fss_pops;
1217917SReza.Sabdar@Sun.COM ulong_t fss_stack_residue;
1227917SReza.Sabdar@Sun.COM } traverse_statistics_t;
1237917SReza.Sabdar@Sun.COM
1247917SReza.Sabdar@Sun.COM /*
1257917SReza.Sabdar@Sun.COM * Global instance of statistics variable.
1267917SReza.Sabdar@Sun.COM */
1277917SReza.Sabdar@Sun.COM traverse_statistics_t traverse_stats;
1287917SReza.Sabdar@Sun.COM
1297917SReza.Sabdar@Sun.COM #define MAX_DENT_BUF_SIZE (8 * 1024)
1307917SReza.Sabdar@Sun.COM
1317917SReza.Sabdar@Sun.COM typedef struct {
1327917SReza.Sabdar@Sun.COM struct stat64 fd_attr;
1337917SReza.Sabdar@Sun.COM fs_fhandle_t fd_fh;
1347917SReza.Sabdar@Sun.COM short fd_len;
1357917SReza.Sabdar@Sun.COM char fd_name[1];
1367917SReza.Sabdar@Sun.COM } fs_dent_info_t;
1377917SReza.Sabdar@Sun.COM
1387917SReza.Sabdar@Sun.COM typedef struct dent_arg {
1397917SReza.Sabdar@Sun.COM char *da_buf;
1407917SReza.Sabdar@Sun.COM int da_end;
1417917SReza.Sabdar@Sun.COM int da_size;
1427917SReza.Sabdar@Sun.COM } dent_arg_t;
1437917SReza.Sabdar@Sun.COM
1447917SReza.Sabdar@Sun.COM static int traverse_level_nondir(struct fs_traverse *ftp,
1457917SReza.Sabdar@Sun.COM traverse_state_t *tsp, struct fst_node *pnp,
1467917SReza.Sabdar@Sun.COM dent_arg_t *darg);
1477917SReza.Sabdar@Sun.COM
1487917SReza.Sabdar@Sun.COM /*
1497917SReza.Sabdar@Sun.COM * Gather some directory entry information and return them
1507917SReza.Sabdar@Sun.COM */
1517917SReza.Sabdar@Sun.COM static int
fs_populate_dents(void * arg,int namelen,char * name,long * countp,struct stat64 * attr,fs_fhandle_t * fh)1527917SReza.Sabdar@Sun.COM fs_populate_dents(void *arg, int namelen,
1537917SReza.Sabdar@Sun.COM char *name, long *countp, struct stat64 *attr,
1547917SReza.Sabdar@Sun.COM fs_fhandle_t *fh)
1557917SReza.Sabdar@Sun.COM {
1567917SReza.Sabdar@Sun.COM dent_arg_t *darg = (dent_arg_t *)arg;
1577917SReza.Sabdar@Sun.COM int reclen = sizeof (fs_dent_info_t) + namelen;
1587917SReza.Sabdar@Sun.COM fs_dent_info_t *dent;
1597917SReza.Sabdar@Sun.COM
1607917SReza.Sabdar@Sun.COM if ((darg->da_end + reclen) > darg->da_size)
1617917SReza.Sabdar@Sun.COM return (-1);
1627917SReza.Sabdar@Sun.COM
1637917SReza.Sabdar@Sun.COM /* LINTED improper alignment */
1647917SReza.Sabdar@Sun.COM dent = (fs_dent_info_t *)(darg->da_buf + darg->da_end);
1657917SReza.Sabdar@Sun.COM
1667917SReza.Sabdar@Sun.COM dent->fd_attr = *attr;
1677917SReza.Sabdar@Sun.COM dent->fd_fh = *fh;
1687917SReza.Sabdar@Sun.COM (void) strcpy(dent->fd_name, name);
1697917SReza.Sabdar@Sun.COM
1707917SReza.Sabdar@Sun.COM dent->fd_len = reclen;
1717917SReza.Sabdar@Sun.COM darg->da_end += reclen;
1727917SReza.Sabdar@Sun.COM
1737917SReza.Sabdar@Sun.COM if (countp)
1747917SReza.Sabdar@Sun.COM (*countp)++;
1757917SReza.Sabdar@Sun.COM
1767917SReza.Sabdar@Sun.COM return (0);
1777917SReza.Sabdar@Sun.COM }
1787917SReza.Sabdar@Sun.COM
1797917SReza.Sabdar@Sun.COM /*
1807917SReza.Sabdar@Sun.COM * Creates a new traversing state based on the path passed to it.
1817917SReza.Sabdar@Sun.COM */
1827917SReza.Sabdar@Sun.COM static traverse_state_t *
new_tsp(char * path)1837917SReza.Sabdar@Sun.COM new_tsp(char *path)
1847917SReza.Sabdar@Sun.COM {
1857917SReza.Sabdar@Sun.COM traverse_state_t *tsp;
1867917SReza.Sabdar@Sun.COM tsp = ndmp_malloc(sizeof (traverse_state_t));
1877917SReza.Sabdar@Sun.COM if (!tsp)
1887917SReza.Sabdar@Sun.COM return (NULL);
1897917SReza.Sabdar@Sun.COM
1907917SReza.Sabdar@Sun.COM tsp->ts_end = strchr(path, '\0');
1917917SReza.Sabdar@Sun.COM if (*(tsp->ts_end-1) == '/')
1927917SReza.Sabdar@Sun.COM *--tsp->ts_end = '\0';
1937917SReza.Sabdar@Sun.COM tsp->ts_ent = NULL;
1947917SReza.Sabdar@Sun.COM tsp->ts_dpos = 0;
1957917SReza.Sabdar@Sun.COM
1967917SReza.Sabdar@Sun.COM return (tsp);
1977917SReza.Sabdar@Sun.COM }
1987917SReza.Sabdar@Sun.COM
1997917SReza.Sabdar@Sun.COM /*
2007917SReza.Sabdar@Sun.COM * Create a file handle and get stats for the given path
2017917SReza.Sabdar@Sun.COM */
2027917SReza.Sabdar@Sun.COM int
fs_getstat(char * path,fs_fhandle_t * fh,struct stat64 * st)2039714SReza.Sabdar@Sun.COM fs_getstat(char *path, fs_fhandle_t *fh, struct stat64 *st)
2047917SReza.Sabdar@Sun.COM {
2057917SReza.Sabdar@Sun.COM if (lstat64(path, st) == -1)
2067917SReza.Sabdar@Sun.COM return (errno);
2077917SReza.Sabdar@Sun.COM
2087917SReza.Sabdar@Sun.COM fh->fh_fid = st->st_ino;
2099012SReza.Sabdar@Sun.COM
2109714SReza.Sabdar@Sun.COM if (!S_ISDIR(st->st_mode))
2119012SReza.Sabdar@Sun.COM fh->fh_fpath = NULL;
2127917SReza.Sabdar@Sun.COM else
2137917SReza.Sabdar@Sun.COM fh->fh_fpath = strdup(path);
2147917SReza.Sabdar@Sun.COM return (0);
2157917SReza.Sabdar@Sun.COM }
2167917SReza.Sabdar@Sun.COM
2177917SReza.Sabdar@Sun.COM /*
2187917SReza.Sabdar@Sun.COM * Get directory entries info and return in the buffer. Cookie
2197917SReza.Sabdar@Sun.COM * will keep the state of each call
2207917SReza.Sabdar@Sun.COM */
2217917SReza.Sabdar@Sun.COM 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)2227917SReza.Sabdar@Sun.COM fs_getdents(int fildes, struct dirent *buf, size_t *nbyte,
2237917SReza.Sabdar@Sun.COM char *pn_path, long *dpos, longlong_t *cookie,
2249714SReza.Sabdar@Sun.COM long *n_entries, dent_arg_t *darg)
2257917SReza.Sabdar@Sun.COM {
2267917SReza.Sabdar@Sun.COM struct dirent *ptr;
2277917SReza.Sabdar@Sun.COM char file_path[PATH_MAX + 1];
2287917SReza.Sabdar@Sun.COM fs_fhandle_t fh;
2297917SReza.Sabdar@Sun.COM struct stat64 st;
2307917SReza.Sabdar@Sun.COM char *p;
2317917SReza.Sabdar@Sun.COM int len;
2327917SReza.Sabdar@Sun.COM int rv;
2337917SReza.Sabdar@Sun.COM
2347917SReza.Sabdar@Sun.COM if (*nbyte == 0) {
2357917SReza.Sabdar@Sun.COM (void) memset((char *)buf, 0, MAX_DENT_BUF_SIZE);
2367917SReza.Sabdar@Sun.COM *nbyte = rv = getdents(fildes, buf, darg->da_size);
2377917SReza.Sabdar@Sun.COM *cookie = 0LL;
2387917SReza.Sabdar@Sun.COM
2397917SReza.Sabdar@Sun.COM if (rv <= 0)
2407917SReza.Sabdar@Sun.COM return (rv);
2417917SReza.Sabdar@Sun.COM }
2427917SReza.Sabdar@Sun.COM
2437917SReza.Sabdar@Sun.COM p = (char *)buf + *cookie;
2447917SReza.Sabdar@Sun.COM len = *nbyte;
2457917SReza.Sabdar@Sun.COM do {
2467917SReza.Sabdar@Sun.COM /* LINTED improper alignment */
2477917SReza.Sabdar@Sun.COM ptr = (struct dirent *)p;
2487917SReza.Sabdar@Sun.COM *dpos = ptr->d_off;
2499714SReza.Sabdar@Sun.COM
2509714SReza.Sabdar@Sun.COM if (rootfs_dot_or_dotdot(ptr->d_name))
2519714SReza.Sabdar@Sun.COM goto skip_entry;
2529714SReza.Sabdar@Sun.COM
2537917SReza.Sabdar@Sun.COM (void) snprintf(file_path, PATH_MAX, "%s/", pn_path);
254*13120SReza.Sabdar@Sun.COM (void) strlcat(file_path, ptr->d_name, PATH_MAX + 1);
2557917SReza.Sabdar@Sun.COM (void) memset(&fh, 0, sizeof (fs_fhandle_t));
2567917SReza.Sabdar@Sun.COM
25710874SReza.Sabdar@Sun.COM if (lstat64(file_path, &st) != 0) {
25810874SReza.Sabdar@Sun.COM rv = -1;
2597917SReza.Sabdar@Sun.COM break;
26010874SReza.Sabdar@Sun.COM }
2617917SReza.Sabdar@Sun.COM
2629714SReza.Sabdar@Sun.COM fh.fh_fid = st.st_ino;
2639714SReza.Sabdar@Sun.COM
2649714SReza.Sabdar@Sun.COM if (S_ISDIR(st.st_mode))
2659714SReza.Sabdar@Sun.COM goto skip_entry;
2669714SReza.Sabdar@Sun.COM
26710874SReza.Sabdar@Sun.COM if (fs_populate_dents(darg, strlen(ptr->d_name),
26810874SReza.Sabdar@Sun.COM (char *)ptr->d_name, n_entries, &st, &fh) != 0)
2697917SReza.Sabdar@Sun.COM break;
2707917SReza.Sabdar@Sun.COM
2719714SReza.Sabdar@Sun.COM skip_entry:
2727917SReza.Sabdar@Sun.COM p = p + ptr->d_reclen;
2737917SReza.Sabdar@Sun.COM len -= ptr->d_reclen;
2747917SReza.Sabdar@Sun.COM } while (len);
2757917SReza.Sabdar@Sun.COM
2767917SReza.Sabdar@Sun.COM *cookie = (longlong_t)(p - (char *)buf);
2777917SReza.Sabdar@Sun.COM *nbyte = len;
2787917SReza.Sabdar@Sun.COM return (rv);
2797917SReza.Sabdar@Sun.COM }
2807917SReza.Sabdar@Sun.COM
2817917SReza.Sabdar@Sun.COM /*
2827917SReza.Sabdar@Sun.COM * Read the directory entries and return the information about
2837917SReza.Sabdar@Sun.COM * each entry
2847917SReza.Sabdar@Sun.COM */
2857917SReza.Sabdar@Sun.COM int
fs_readdir(fs_fhandle_t * ts_fh,char * path,long * dpos,char * nm,int * el,fs_fhandle_t * efh,struct stat64 * est)2867917SReza.Sabdar@Sun.COM fs_readdir(fs_fhandle_t *ts_fh, char *path, long *dpos,
2879714SReza.Sabdar@Sun.COM char *nm, int *el, fs_fhandle_t *efh, struct stat64 *est)
2887917SReza.Sabdar@Sun.COM {
2897917SReza.Sabdar@Sun.COM struct dirent *dp;
2907917SReza.Sabdar@Sun.COM char file_path[PATH_MAX + 1];
2917917SReza.Sabdar@Sun.COM DIR *dirp;
2927917SReza.Sabdar@Sun.COM int rv;
2937917SReza.Sabdar@Sun.COM
2947917SReza.Sabdar@Sun.COM if ((dirp = opendir(ts_fh->fh_fpath)) == NULL)
2957917SReza.Sabdar@Sun.COM return (errno);
2967917SReza.Sabdar@Sun.COM
2977917SReza.Sabdar@Sun.COM seekdir(dirp, *dpos);
2987917SReza.Sabdar@Sun.COM if ((dp = readdir(dirp)) == NULL) {
2997917SReza.Sabdar@Sun.COM rv = 0; /* skip this dir */
3007917SReza.Sabdar@Sun.COM *el = 0;
3017917SReza.Sabdar@Sun.COM } else {
3027917SReza.Sabdar@Sun.COM (void) snprintf(file_path, PATH_MAX, "%s/", path);
303*13120SReza.Sabdar@Sun.COM (void) strlcat(file_path, dp->d_name, PATH_MAX + 1);
3047917SReza.Sabdar@Sun.COM
3059714SReza.Sabdar@Sun.COM rv = fs_getstat(file_path, efh, est);
3067917SReza.Sabdar@Sun.COM if (rv == 0) {
3077917SReza.Sabdar@Sun.COM *dpos = telldir(dirp);
308*13120SReza.Sabdar@Sun.COM (void) strlcpy(nm, dp->d_name, NAME_MAX + 1);
3097917SReza.Sabdar@Sun.COM *el = strlen(dp->d_name);
3107917SReza.Sabdar@Sun.COM } else {
3117917SReza.Sabdar@Sun.COM *el = 0;
3127917SReza.Sabdar@Sun.COM }
3137917SReza.Sabdar@Sun.COM }
3147917SReza.Sabdar@Sun.COM (void) closedir(dirp);
3157917SReza.Sabdar@Sun.COM return (rv);
3167917SReza.Sabdar@Sun.COM }
3177917SReza.Sabdar@Sun.COM
3187917SReza.Sabdar@Sun.COM /*
3197917SReza.Sabdar@Sun.COM * Traverse the file system in the post-order way. The description
3207917SReza.Sabdar@Sun.COM * and example is in the header file.
3217917SReza.Sabdar@Sun.COM *
3227917SReza.Sabdar@Sun.COM * The callback function should return 0, on success and non-zero on
3237917SReza.Sabdar@Sun.COM * failure. If the callback function returns non-zero return value,
3247917SReza.Sabdar@Sun.COM * the traversing stops.
3257917SReza.Sabdar@Sun.COM */
3267917SReza.Sabdar@Sun.COM int
traverse_post(struct fs_traverse * ftp)3277917SReza.Sabdar@Sun.COM traverse_post(struct fs_traverse *ftp)
3287917SReza.Sabdar@Sun.COM {
3297917SReza.Sabdar@Sun.COM char path[PATH_MAX + 1]; /* full path name of the current dir */
3307917SReza.Sabdar@Sun.COM char nm[NAME_MAX + 1]; /* directory entry name */
3317917SReza.Sabdar@Sun.COM char *lp; /* last position on the path */
3327917SReza.Sabdar@Sun.COM int next_dir, rv;
3337917SReza.Sabdar@Sun.COM int pl, el; /* path and directory entry length */
3347917SReza.Sabdar@Sun.COM cstack_t *sp;
3357917SReza.Sabdar@Sun.COM fs_fhandle_t pfh, efh;
3367917SReza.Sabdar@Sun.COM struct stat64 pst, est;
3377917SReza.Sabdar@Sun.COM traverse_state_t *tsp;
3387917SReza.Sabdar@Sun.COM struct fst_node pn, en; /* parent and entry nodes */
3397917SReza.Sabdar@Sun.COM
3407917SReza.Sabdar@Sun.COM if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
3417917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument");
3427917SReza.Sabdar@Sun.COM errno = EINVAL;
3437917SReza.Sabdar@Sun.COM return (-1);
3447917SReza.Sabdar@Sun.COM }
3457917SReza.Sabdar@Sun.COM
3467917SReza.Sabdar@Sun.COM /* set the default log function if it's not already set */
3477917SReza.Sabdar@Sun.COM if (!ftp->ft_logfp) {
3487917SReza.Sabdar@Sun.COM ftp->ft_logfp = (ft_log_t)syslog;
3497917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
3507917SReza.Sabdar@Sun.COM }
3517917SReza.Sabdar@Sun.COM
3527917SReza.Sabdar@Sun.COM /* set the logical path to physical path if it's not already set */
3537917SReza.Sabdar@Sun.COM if (!ftp->ft_lpath) {
3547917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
3557917SReza.Sabdar@Sun.COM "report the same paths: \"%s\"", ftp->ft_path);
3567917SReza.Sabdar@Sun.COM ftp->ft_lpath = ftp->ft_path;
3577917SReza.Sabdar@Sun.COM }
3587917SReza.Sabdar@Sun.COM
3597917SReza.Sabdar@Sun.COM pl = strlen(ftp->ft_lpath);
3607917SReza.Sabdar@Sun.COM if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
3617917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
3627917SReza.Sabdar@Sun.COM errno = ENAMETOOLONG;
3637917SReza.Sabdar@Sun.COM return (-1);
3647917SReza.Sabdar@Sun.COM }
3657917SReza.Sabdar@Sun.COM (void) strcpy(path, ftp->ft_lpath);
3667917SReza.Sabdar@Sun.COM (void) memset(&pfh, 0, sizeof (pfh));
3679714SReza.Sabdar@Sun.COM rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
3687917SReza.Sabdar@Sun.COM
3697917SReza.Sabdar@Sun.COM if (rv != 0) {
3707917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
3717917SReza.Sabdar@Sun.COM "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
3727917SReza.Sabdar@Sun.COM return (rv);
3737917SReza.Sabdar@Sun.COM }
3747917SReza.Sabdar@Sun.COM
3757917SReza.Sabdar@Sun.COM if (!S_ISDIR(pst.st_mode)) {
3767917SReza.Sabdar@Sun.COM pn.tn_path = ftp->ft_lpath;
3777917SReza.Sabdar@Sun.COM pn.tn_fh = &pfh;
3787917SReza.Sabdar@Sun.COM pn.tn_st = &pst;
3797917SReza.Sabdar@Sun.COM en.tn_path = NULL;
3807917SReza.Sabdar@Sun.COM en.tn_fh = NULL;
3817917SReza.Sabdar@Sun.COM en.tn_st = NULL;
3827917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en);
3837917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
3847917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
3857917SReza.Sabdar@Sun.COM free(pfh.fh_fpath);
3867917SReza.Sabdar@Sun.COM return (rv);
3877917SReza.Sabdar@Sun.COM }
3887917SReza.Sabdar@Sun.COM
3897917SReza.Sabdar@Sun.COM sp = cstack_new();
3907917SReza.Sabdar@Sun.COM if (!sp) {
3917917SReza.Sabdar@Sun.COM errno = ENOMEM;
3927917SReza.Sabdar@Sun.COM free(pfh.fh_fpath);
3937917SReza.Sabdar@Sun.COM return (-1);
3947917SReza.Sabdar@Sun.COM }
3957917SReza.Sabdar@Sun.COM tsp = new_tsp(path);
3967917SReza.Sabdar@Sun.COM if (!tsp) {
3977917SReza.Sabdar@Sun.COM cstack_delete(sp);
3987917SReza.Sabdar@Sun.COM errno = ENOMEM;
3997917SReza.Sabdar@Sun.COM free(pfh.fh_fpath);
4007917SReza.Sabdar@Sun.COM return (-1);
4017917SReza.Sabdar@Sun.COM }
4027917SReza.Sabdar@Sun.COM tsp->ts_ent = tsp->ts_end;
4037917SReza.Sabdar@Sun.COM tsp->ts_fh = pfh;
4047917SReza.Sabdar@Sun.COM tsp->ts_st = pst;
4057917SReza.Sabdar@Sun.COM pn.tn_path = path;
4067917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh;
4077917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st;
4087917SReza.Sabdar@Sun.COM
4097917SReza.Sabdar@Sun.COM rv = 0;
4107917SReza.Sabdar@Sun.COM next_dir = 1;
4117917SReza.Sabdar@Sun.COM do {
4127917SReza.Sabdar@Sun.COM if (next_dir) {
4137917SReza.Sabdar@Sun.COM traverse_stats.fss_newdirs++;
4147917SReza.Sabdar@Sun.COM
4157917SReza.Sabdar@Sun.COM *tsp->ts_end = '\0';
4167917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
4177917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
4187917SReza.Sabdar@Sun.COM }
4197917SReza.Sabdar@Sun.COM
4207917SReza.Sabdar@Sun.COM next_dir = 0;
4217917SReza.Sabdar@Sun.COM do {
4227917SReza.Sabdar@Sun.COM el = NAME_MAX;
4237917SReza.Sabdar@Sun.COM rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
4247917SReza.Sabdar@Sun.COM &tsp->ts_dpos, nm, &el,
4259714SReza.Sabdar@Sun.COM &efh, &est);
4267917SReza.Sabdar@Sun.COM
4277917SReza.Sabdar@Sun.COM if (rv != 0) {
4289714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
4297917SReza.Sabdar@Sun.COM traverse_stats.fss_readdir_err++;
4307917SReza.Sabdar@Sun.COM
4317917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
4327917SReza.Sabdar@Sun.COM "Error %d on readdir(%s) pos %d",
4337917SReza.Sabdar@Sun.COM rv, path, tsp->ts_dpos);
4347917SReza.Sabdar@Sun.COM if (STOP_ONERR(ftp))
4357917SReza.Sabdar@Sun.COM break;
4367917SReza.Sabdar@Sun.COM rv = SKIP_ENTRY;
4377917SReza.Sabdar@Sun.COM
4387917SReza.Sabdar@Sun.COM continue;
4397917SReza.Sabdar@Sun.COM }
4407917SReza.Sabdar@Sun.COM
4417917SReza.Sabdar@Sun.COM /* done with this directory */
4427917SReza.Sabdar@Sun.COM if (el == 0) {
4437917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
4447917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
4457917SReza.Sabdar@Sun.COM "Done(%s)", pn.tn_path);
4467917SReza.Sabdar@Sun.COM break;
4477917SReza.Sabdar@Sun.COM }
4487917SReza.Sabdar@Sun.COM nm[el] = '\0';
4497917SReza.Sabdar@Sun.COM
4507917SReza.Sabdar@Sun.COM if (rootfs_dot_or_dotdot(nm)) {
4519714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
4527917SReza.Sabdar@Sun.COM continue;
4537917SReza.Sabdar@Sun.COM }
4547917SReza.Sabdar@Sun.COM
4557917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
4567917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
4577917SReza.Sabdar@Sun.COM tsp->ts_dpos, nm);
4587917SReza.Sabdar@Sun.COM
4597917SReza.Sabdar@Sun.COM if (pl + 1 + el > PATH_MAX) {
4607917SReza.Sabdar@Sun.COM traverse_stats.fss_longpath_err++;
4617917SReza.Sabdar@Sun.COM
4627917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
4637917SReza.Sabdar@Sun.COM path, nm);
4647917SReza.Sabdar@Sun.COM if (STOP_ONLONG(ftp))
4657917SReza.Sabdar@Sun.COM rv = ENAMETOOLONG;
4669714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
4677917SReza.Sabdar@Sun.COM continue;
4687917SReza.Sabdar@Sun.COM }
4697917SReza.Sabdar@Sun.COM
4707917SReza.Sabdar@Sun.COM /*
4717917SReza.Sabdar@Sun.COM * Push the current directory on to the stack and
4727917SReza.Sabdar@Sun.COM * dive into the entry found.
4737917SReza.Sabdar@Sun.COM */
4747917SReza.Sabdar@Sun.COM if (S_ISDIR(est.st_mode)) {
4757917SReza.Sabdar@Sun.COM
4767917SReza.Sabdar@Sun.COM assert(tsp != NULL);
4777917SReza.Sabdar@Sun.COM if (cstack_push(sp, tsp, 0)) {
4787917SReza.Sabdar@Sun.COM rv = ENOMEM;
4799714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
4807917SReza.Sabdar@Sun.COM break;
4817917SReza.Sabdar@Sun.COM }
4827917SReza.Sabdar@Sun.COM traverse_stats.fss_pushes++;
4837917SReza.Sabdar@Sun.COM
4847917SReza.Sabdar@Sun.COM /*
4857917SReza.Sabdar@Sun.COM * Concatenate the current entry with the
4867917SReza.Sabdar@Sun.COM * current path. This will be the path of
4877917SReza.Sabdar@Sun.COM * the new directory to be scanned.
4887917SReza.Sabdar@Sun.COM *
4897917SReza.Sabdar@Sun.COM * Note:
4907917SReza.Sabdar@Sun.COM * sprintf(tsp->ts_end, "/%s", de->d_name);
4917917SReza.Sabdar@Sun.COM * could be used here, but concatenating
4927917SReza.Sabdar@Sun.COM * strings like this might be faster.
4937917SReza.Sabdar@Sun.COM * The length of the new path has been
4947917SReza.Sabdar@Sun.COM * checked above. So strcpy() can be
4957917SReza.Sabdar@Sun.COM * safe and should not lead to a buffer
4967917SReza.Sabdar@Sun.COM * over-run.
4977917SReza.Sabdar@Sun.COM */
4987917SReza.Sabdar@Sun.COM lp = tsp->ts_end;
4997917SReza.Sabdar@Sun.COM *tsp->ts_end = '/';
5007917SReza.Sabdar@Sun.COM (void) strcpy(tsp->ts_end + 1, nm);
5017917SReza.Sabdar@Sun.COM
5027917SReza.Sabdar@Sun.COM tsp = new_tsp(path);
5037917SReza.Sabdar@Sun.COM if (!tsp) {
5049714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
5057917SReza.Sabdar@Sun.COM rv = ENOMEM;
5067917SReza.Sabdar@Sun.COM } else {
5077917SReza.Sabdar@Sun.COM next_dir = 1;
5087917SReza.Sabdar@Sun.COM pl += el;
5097917SReza.Sabdar@Sun.COM tsp->ts_fh = efh;
5107917SReza.Sabdar@Sun.COM tsp->ts_st = est;
5117917SReza.Sabdar@Sun.COM tsp->ts_ent = lp;
5127917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh;
5137917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st;
5147917SReza.Sabdar@Sun.COM }
5157917SReza.Sabdar@Sun.COM break;
5167917SReza.Sabdar@Sun.COM } else {
5177917SReza.Sabdar@Sun.COM /*
5187917SReza.Sabdar@Sun.COM * The entry is not a directory so the
5197917SReza.Sabdar@Sun.COM * callback function must be called.
5207917SReza.Sabdar@Sun.COM */
5217917SReza.Sabdar@Sun.COM traverse_stats.fss_nondir_calls++;
5227917SReza.Sabdar@Sun.COM
5237917SReza.Sabdar@Sun.COM en.tn_path = nm;
5247917SReza.Sabdar@Sun.COM en.tn_fh = &efh;
5257917SReza.Sabdar@Sun.COM en.tn_st = &est;
5267917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en);
5279714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
5287917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
5297917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
5307917SReza.Sabdar@Sun.COM "CALLBACK(%s/%s): %d",
5317917SReza.Sabdar@Sun.COM pn.tn_path, en.tn_path, rv);
5327917SReza.Sabdar@Sun.COM
5337917SReza.Sabdar@Sun.COM if (rv != 0)
5347917SReza.Sabdar@Sun.COM break;
5357917SReza.Sabdar@Sun.COM }
5367917SReza.Sabdar@Sun.COM } while (rv == 0);
5377917SReza.Sabdar@Sun.COM
5387917SReza.Sabdar@Sun.COM /*
5397917SReza.Sabdar@Sun.COM * A new directory must be processed, go to the start of
5407917SReza.Sabdar@Sun.COM * the loop, open it and process it.
5417917SReza.Sabdar@Sun.COM */
5427917SReza.Sabdar@Sun.COM if (next_dir)
5437917SReza.Sabdar@Sun.COM continue;
5447917SReza.Sabdar@Sun.COM
5457917SReza.Sabdar@Sun.COM if (rv == SKIP_ENTRY)
5467917SReza.Sabdar@Sun.COM rv = 0; /* We should skip the current directory */
5477917SReza.Sabdar@Sun.COM
5487917SReza.Sabdar@Sun.COM if (rv == 0) {
5497917SReza.Sabdar@Sun.COM /*
5507917SReza.Sabdar@Sun.COM * Remove the ent from the end of path and send it
5517917SReza.Sabdar@Sun.COM * as an entry of the path.
5527917SReza.Sabdar@Sun.COM */
5537917SReza.Sabdar@Sun.COM lp = tsp->ts_ent;
5547917SReza.Sabdar@Sun.COM *lp = '\0';
5557917SReza.Sabdar@Sun.COM efh = tsp->ts_fh;
5567917SReza.Sabdar@Sun.COM est = tsp->ts_st;
5577917SReza.Sabdar@Sun.COM free(tsp);
5587917SReza.Sabdar@Sun.COM if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
5597917SReza.Sabdar@Sun.COM break;
5607917SReza.Sabdar@Sun.COM
5617917SReza.Sabdar@Sun.COM assert(tsp != NULL);
5627917SReza.Sabdar@Sun.COM pl = tsp->ts_end - path;
5637917SReza.Sabdar@Sun.COM
5647917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
5657917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "poped pl %d 0x%p \"%s\"",
5667917SReza.Sabdar@Sun.COM pl, tsp, path);
5677917SReza.Sabdar@Sun.COM
5687917SReza.Sabdar@Sun.COM traverse_stats.fss_pops++;
5697917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++;
5707917SReza.Sabdar@Sun.COM
5717917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh;
5727917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st;
5737917SReza.Sabdar@Sun.COM en.tn_path = lp + 1;
5747917SReza.Sabdar@Sun.COM en.tn_fh = &efh;
5757917SReza.Sabdar@Sun.COM en.tn_st = &est;
5767917SReza.Sabdar@Sun.COM
5777917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en);
5789714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
5797917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
5807917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s/%s): %d",
5817917SReza.Sabdar@Sun.COM pn.tn_path, en.tn_path, rv);
5827917SReza.Sabdar@Sun.COM /*
5837917SReza.Sabdar@Sun.COM * Does not need to free tsp here. It will be released
5847917SReza.Sabdar@Sun.COM * later.
5857917SReza.Sabdar@Sun.COM */
5867917SReza.Sabdar@Sun.COM }
5877917SReza.Sabdar@Sun.COM
5889714SReza.Sabdar@Sun.COM if (rv != 0 && tsp) {
5899714SReza.Sabdar@Sun.COM free(tsp->ts_fh.fh_fpath);
5907917SReza.Sabdar@Sun.COM free(tsp);
5919714SReza.Sabdar@Sun.COM }
5927917SReza.Sabdar@Sun.COM
5937917SReza.Sabdar@Sun.COM } while (rv == 0);
5947917SReza.Sabdar@Sun.COM
5957917SReza.Sabdar@Sun.COM /*
5967917SReza.Sabdar@Sun.COM * For the 'ftp->ft_path' directory itself.
5977917SReza.Sabdar@Sun.COM */
5987917SReza.Sabdar@Sun.COM if (rv == 0) {
5997917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++;
6007917SReza.Sabdar@Sun.COM
6017917SReza.Sabdar@Sun.COM pn.tn_fh = &efh;
6027917SReza.Sabdar@Sun.COM pn.tn_st = &est;
6037917SReza.Sabdar@Sun.COM en.tn_path = NULL;
6047917SReza.Sabdar@Sun.COM en.tn_fh = NULL;
6057917SReza.Sabdar@Sun.COM en.tn_st = NULL;
6067917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en);
6077917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
6087917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
6097917SReza.Sabdar@Sun.COM }
6107917SReza.Sabdar@Sun.COM
6117917SReza.Sabdar@Sun.COM /*
6127917SReza.Sabdar@Sun.COM * Pop and free all the remaining entries on the stack.
6137917SReza.Sabdar@Sun.COM */
6147917SReza.Sabdar@Sun.COM while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
6157917SReza.Sabdar@Sun.COM traverse_stats.fss_stack_residue++;
6167917SReza.Sabdar@Sun.COM
6179714SReza.Sabdar@Sun.COM free(tsp->ts_fh.fh_fpath);
6187917SReza.Sabdar@Sun.COM free(tsp);
6197917SReza.Sabdar@Sun.COM }
6207917SReza.Sabdar@Sun.COM
6217917SReza.Sabdar@Sun.COM cstack_delete(sp);
6227917SReza.Sabdar@Sun.COM return (rv);
6237917SReza.Sabdar@Sun.COM }
6247917SReza.Sabdar@Sun.COM
6257917SReza.Sabdar@Sun.COM /*
6267917SReza.Sabdar@Sun.COM * In one pass, read all the directory entries of the specified
6277917SReza.Sabdar@Sun.COM * directory and call the callback function for non-directory
6287917SReza.Sabdar@Sun.COM * entries.
6297917SReza.Sabdar@Sun.COM *
6307917SReza.Sabdar@Sun.COM * On return:
6317917SReza.Sabdar@Sun.COM * 0: Lets the directory to be scanned for directory entries.
6327917SReza.Sabdar@Sun.COM * < 0: Completely stops traversing.
6337917SReza.Sabdar@Sun.COM * FST_SKIP: stops further scanning of the directory. Traversing
6347917SReza.Sabdar@Sun.COM * will continue with the next directory in the hierarchy.
6357917SReza.Sabdar@Sun.COM * SKIP_ENTRY: Failed to get the directory entries, so the caller
6367917SReza.Sabdar@Sun.COM * should skip this entry.
6377917SReza.Sabdar@Sun.COM */
6387917SReza.Sabdar@Sun.COM static int
traverse_level_nondir(struct fs_traverse * ftp,traverse_state_t * tsp,struct fst_node * pnp,dent_arg_t * darg)6397917SReza.Sabdar@Sun.COM traverse_level_nondir(struct fs_traverse *ftp,
6407917SReza.Sabdar@Sun.COM traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
6417917SReza.Sabdar@Sun.COM {
6429714SReza.Sabdar@Sun.COM int pl; /* path length */
6437917SReza.Sabdar@Sun.COM int rv;
6447917SReza.Sabdar@Sun.COM struct fst_node en; /* entry node */
6457917SReza.Sabdar@Sun.COM longlong_t cookie_verf;
6467917SReza.Sabdar@Sun.COM fs_dent_info_t *dent;
6477917SReza.Sabdar@Sun.COM struct dirent *buf;
6487917SReza.Sabdar@Sun.COM size_t len = 0;
6497917SReza.Sabdar@Sun.COM int fd;
6507917SReza.Sabdar@Sun.COM
6517917SReza.Sabdar@Sun.COM rv = 0;
6527917SReza.Sabdar@Sun.COM pl = strlen(pnp->tn_path);
6537917SReza.Sabdar@Sun.COM
6547917SReza.Sabdar@Sun.COM buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
6557917SReza.Sabdar@Sun.COM if (buf == NULL)
6567917SReza.Sabdar@Sun.COM return (errno);
6577917SReza.Sabdar@Sun.COM
6587917SReza.Sabdar@Sun.COM fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
6597917SReza.Sabdar@Sun.COM if (fd == -1) {
6607917SReza.Sabdar@Sun.COM free(buf);
6617917SReza.Sabdar@Sun.COM return (errno);
6627917SReza.Sabdar@Sun.COM }
6637917SReza.Sabdar@Sun.COM
6647917SReza.Sabdar@Sun.COM while (rv == 0) {
6657917SReza.Sabdar@Sun.COM long i, n_entries;
6667917SReza.Sabdar@Sun.COM
6677917SReza.Sabdar@Sun.COM darg->da_end = 0;
6687917SReza.Sabdar@Sun.COM n_entries = 0;
6697917SReza.Sabdar@Sun.COM rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
6709714SReza.Sabdar@Sun.COM &cookie_verf, &n_entries, darg);
67110874SReza.Sabdar@Sun.COM if (rv < 0) {
6727917SReza.Sabdar@Sun.COM traverse_stats.fss_readdir_err++;
6737917SReza.Sabdar@Sun.COM
6747917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
6757917SReza.Sabdar@Sun.COM rv, pnp->tn_path, tsp->ts_dpos);
676*13120SReza.Sabdar@Sun.COM if (STOP_ONERR(ftp))
6777917SReza.Sabdar@Sun.COM break;
6787917SReza.Sabdar@Sun.COM /*
6797917SReza.Sabdar@Sun.COM * We cannot read the directory entry, we should
6807917SReza.Sabdar@Sun.COM * skip to the next directory.
6817917SReza.Sabdar@Sun.COM */
6827917SReza.Sabdar@Sun.COM rv = SKIP_ENTRY;
6837917SReza.Sabdar@Sun.COM continue;
68410874SReza.Sabdar@Sun.COM } else {
68510874SReza.Sabdar@Sun.COM /* Break at the end of directory */
68610874SReza.Sabdar@Sun.COM if (rv > 0)
68710874SReza.Sabdar@Sun.COM rv = 0;
68810874SReza.Sabdar@Sun.COM else
68910874SReza.Sabdar@Sun.COM break;
6907917SReza.Sabdar@Sun.COM }
6917917SReza.Sabdar@Sun.COM
6927917SReza.Sabdar@Sun.COM /* LINTED imporper alignment */
6937917SReza.Sabdar@Sun.COM dent = (fs_dent_info_t *)darg->da_buf;
6947917SReza.Sabdar@Sun.COM /* LINTED imporper alignment */
6957917SReza.Sabdar@Sun.COM for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
6967917SReza.Sabdar@Sun.COM ((char *)dent + dent->fd_len)) {
6977917SReza.Sabdar@Sun.COM
6987917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
6997917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
7007917SReza.Sabdar@Sun.COM dent->fd_fh.fh_fid, dent->fd_name);
7017917SReza.Sabdar@Sun.COM
7027917SReza.Sabdar@Sun.COM if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
7037917SReza.Sabdar@Sun.COM traverse_stats.fss_longpath_err++;
7047917SReza.Sabdar@Sun.COM
7057917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
7067917SReza.Sabdar@Sun.COM pnp->tn_path, dent->fd_name);
7077917SReza.Sabdar@Sun.COM if (STOP_ONLONG(ftp))
7087917SReza.Sabdar@Sun.COM rv = -ENAMETOOLONG;
7099714SReza.Sabdar@Sun.COM free(dent->fd_fh.fh_fpath);
7107917SReza.Sabdar@Sun.COM continue;
7117917SReza.Sabdar@Sun.COM }
7127917SReza.Sabdar@Sun.COM
7137917SReza.Sabdar@Sun.COM /*
7147917SReza.Sabdar@Sun.COM * The entry is not a directory so the callback
7157917SReza.Sabdar@Sun.COM * function must be called.
7167917SReza.Sabdar@Sun.COM */
7177917SReza.Sabdar@Sun.COM if (!S_ISDIR(dent->fd_attr.st_mode)) {
7187917SReza.Sabdar@Sun.COM traverse_stats.fss_nondir_calls++;
7197917SReza.Sabdar@Sun.COM
7207917SReza.Sabdar@Sun.COM en.tn_path = dent->fd_name;
7217917SReza.Sabdar@Sun.COM en.tn_fh = &dent->fd_fh;
7227917SReza.Sabdar@Sun.COM en.tn_st = &dent->fd_attr;
7237917SReza.Sabdar@Sun.COM rv = CALLBACK(pnp, &en);
7247917SReza.Sabdar@Sun.COM dent->fd_fh.fh_fpath = NULL;
7257917SReza.Sabdar@Sun.COM if (rv < 0)
7267917SReza.Sabdar@Sun.COM break;
7277917SReza.Sabdar@Sun.COM if (rv == FST_SKIP) {
7287917SReza.Sabdar@Sun.COM traverse_stats.fss_nondir_skipped++;
7297917SReza.Sabdar@Sun.COM break;
7307917SReza.Sabdar@Sun.COM }
7317917SReza.Sabdar@Sun.COM }
7327917SReza.Sabdar@Sun.COM }
7337917SReza.Sabdar@Sun.COM }
7347917SReza.Sabdar@Sun.COM
7357917SReza.Sabdar@Sun.COM free(buf);
7367917SReza.Sabdar@Sun.COM (void) close(fd);
7377917SReza.Sabdar@Sun.COM return (rv);
7387917SReza.Sabdar@Sun.COM }
7397917SReza.Sabdar@Sun.COM
7407917SReza.Sabdar@Sun.COM /*
7417917SReza.Sabdar@Sun.COM * Traverse the file system in the level-order way. The description
7427917SReza.Sabdar@Sun.COM * and example is in the header file.
7437917SReza.Sabdar@Sun.COM */
7447917SReza.Sabdar@Sun.COM int
traverse_level(struct fs_traverse * ftp)7457917SReza.Sabdar@Sun.COM traverse_level(struct fs_traverse *ftp)
7467917SReza.Sabdar@Sun.COM {
7477917SReza.Sabdar@Sun.COM char path[PATH_MAX + 1]; /* full path name of the current dir */
7487917SReza.Sabdar@Sun.COM char nm[NAME_MAX + 1]; /* directory entry name */
7497917SReza.Sabdar@Sun.COM char *lp; /* last position on the path */
7507917SReza.Sabdar@Sun.COM int next_dir, rv;
7517917SReza.Sabdar@Sun.COM int pl, el; /* path and directory entry length */
7527917SReza.Sabdar@Sun.COM
7537917SReza.Sabdar@Sun.COM cstack_t *sp;
7547917SReza.Sabdar@Sun.COM fs_fhandle_t pfh, efh;
7557917SReza.Sabdar@Sun.COM struct stat64 pst, est;
7567917SReza.Sabdar@Sun.COM traverse_state_t *tsp;
7577917SReza.Sabdar@Sun.COM struct fst_node pn, en; /* parent and entry nodes */
7587917SReza.Sabdar@Sun.COM dent_arg_t darg;
7597917SReza.Sabdar@Sun.COM
7607917SReza.Sabdar@Sun.COM if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
7617917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument");
7627917SReza.Sabdar@Sun.COM errno = EINVAL;
7637917SReza.Sabdar@Sun.COM return (-1);
7647917SReza.Sabdar@Sun.COM }
7657917SReza.Sabdar@Sun.COM /* set the default log function if it's not already set */
7667917SReza.Sabdar@Sun.COM if (!ftp->ft_logfp) {
7677917SReza.Sabdar@Sun.COM ftp->ft_logfp = (ft_log_t)syslog;
7687917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
7697917SReza.Sabdar@Sun.COM }
7707917SReza.Sabdar@Sun.COM if (!ftp->ft_lpath) {
7717917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
7727917SReza.Sabdar@Sun.COM "report the same paths \"%s\"", ftp->ft_path);
7737917SReza.Sabdar@Sun.COM ftp->ft_lpath = ftp->ft_path;
7747917SReza.Sabdar@Sun.COM }
7757917SReza.Sabdar@Sun.COM
7767917SReza.Sabdar@Sun.COM pl = strlen(ftp->ft_lpath);
7777917SReza.Sabdar@Sun.COM if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
7787917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
7797917SReza.Sabdar@Sun.COM errno = ENAMETOOLONG;
7807917SReza.Sabdar@Sun.COM return (-1);
7817917SReza.Sabdar@Sun.COM }
7827917SReza.Sabdar@Sun.COM (void) strcpy(path, ftp->ft_lpath);
7837917SReza.Sabdar@Sun.COM (void) memset(&pfh, 0, sizeof (pfh));
7849714SReza.Sabdar@Sun.COM rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
7857917SReza.Sabdar@Sun.COM if (rv != 0) {
7867917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
7877917SReza.Sabdar@Sun.COM "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
7887917SReza.Sabdar@Sun.COM return (-1);
7897917SReza.Sabdar@Sun.COM }
7907917SReza.Sabdar@Sun.COM
7917917SReza.Sabdar@Sun.COM en.tn_path = NULL;
7927917SReza.Sabdar@Sun.COM en.tn_fh = NULL;
7937917SReza.Sabdar@Sun.COM en.tn_st = NULL;
7947917SReza.Sabdar@Sun.COM if (!S_ISDIR(pst.st_mode)) {
7957917SReza.Sabdar@Sun.COM pn.tn_path = ftp->ft_lpath;
7967917SReza.Sabdar@Sun.COM pn.tn_fh = &pfh;
7977917SReza.Sabdar@Sun.COM pn.tn_st = &pst;
7987917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en);
7997917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
8007917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
8017917SReza.Sabdar@Sun.COM
8027917SReza.Sabdar@Sun.COM free(pfh.fh_fpath);
8037917SReza.Sabdar@Sun.COM return (rv);
8047917SReza.Sabdar@Sun.COM }
8057917SReza.Sabdar@Sun.COM
8067917SReza.Sabdar@Sun.COM sp = cstack_new();
8077917SReza.Sabdar@Sun.COM if (!sp) {
8087917SReza.Sabdar@Sun.COM free(pfh.fh_fpath);
8097917SReza.Sabdar@Sun.COM errno = ENOMEM;
8107917SReza.Sabdar@Sun.COM return (-1);
8117917SReza.Sabdar@Sun.COM }
8127917SReza.Sabdar@Sun.COM tsp = new_tsp(path);
8137917SReza.Sabdar@Sun.COM if (!tsp) {
8147917SReza.Sabdar@Sun.COM cstack_delete(sp);
8157917SReza.Sabdar@Sun.COM free(pfh.fh_fpath);
8167917SReza.Sabdar@Sun.COM errno = ENOMEM;
8177917SReza.Sabdar@Sun.COM return (-1);
8187917SReza.Sabdar@Sun.COM }
8197917SReza.Sabdar@Sun.COM
8207917SReza.Sabdar@Sun.COM darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
8217917SReza.Sabdar@Sun.COM if (!darg.da_buf) {
8227917SReza.Sabdar@Sun.COM cstack_delete(sp);
8237917SReza.Sabdar@Sun.COM free(pfh.fh_fpath);
8247917SReza.Sabdar@Sun.COM free(tsp);
8257917SReza.Sabdar@Sun.COM errno = ENOMEM;
8267917SReza.Sabdar@Sun.COM return (-1);
8277917SReza.Sabdar@Sun.COM }
8287917SReza.Sabdar@Sun.COM darg.da_size = MAX_DENT_BUF_SIZE;
8297917SReza.Sabdar@Sun.COM
8307917SReza.Sabdar@Sun.COM tsp->ts_ent = tsp->ts_end;
8317917SReza.Sabdar@Sun.COM tsp->ts_fh = pfh;
8327917SReza.Sabdar@Sun.COM tsp->ts_st = pst;
8337917SReza.Sabdar@Sun.COM pn.tn_path = path;
8347917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh;
8357917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st;
8367917SReza.Sabdar@Sun.COM
8377917SReza.Sabdar@Sun.COM /* call the callback function on the path itself */
8387917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++;
8397917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en);
8407917SReza.Sabdar@Sun.COM if (rv < 0) {
8417917SReza.Sabdar@Sun.COM free(tsp);
8427917SReza.Sabdar@Sun.COM goto end;
8437917SReza.Sabdar@Sun.COM }
8447917SReza.Sabdar@Sun.COM if (rv == FST_SKIP) {
8457917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_skipped++;
8467917SReza.Sabdar@Sun.COM free(tsp);
8477917SReza.Sabdar@Sun.COM rv = 0;
8487917SReza.Sabdar@Sun.COM goto end;
8497917SReza.Sabdar@Sun.COM }
8507917SReza.Sabdar@Sun.COM
8517917SReza.Sabdar@Sun.COM rv = 0;
8527917SReza.Sabdar@Sun.COM next_dir = 1;
8537917SReza.Sabdar@Sun.COM do {
8547917SReza.Sabdar@Sun.COM if (next_dir) {
8557917SReza.Sabdar@Sun.COM traverse_stats.fss_newdirs++;
8567917SReza.Sabdar@Sun.COM
8577917SReza.Sabdar@Sun.COM *tsp->ts_end = '\0';
8587917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
8597917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
8607917SReza.Sabdar@Sun.COM
8617917SReza.Sabdar@Sun.COM rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
8627917SReza.Sabdar@Sun.COM if (rv < 0) {
8637917SReza.Sabdar@Sun.COM NEGATE(rv);
8649714SReza.Sabdar@Sun.COM free(tsp->ts_fh.fh_fpath);
8657917SReza.Sabdar@Sun.COM free(tsp);
8667917SReza.Sabdar@Sun.COM break;
8677917SReza.Sabdar@Sun.COM }
8687917SReza.Sabdar@Sun.COM /*
8697917SReza.Sabdar@Sun.COM * If skipped by the callback function or
8707917SReza.Sabdar@Sun.COM * error happened reading the information
8717917SReza.Sabdar@Sun.COM */
8727917SReza.Sabdar@Sun.COM if (rv == FST_SKIP || rv == SKIP_ENTRY) {
8737917SReza.Sabdar@Sun.COM /*
8747917SReza.Sabdar@Sun.COM * N.B. next_dir should be set to 0 as
8757917SReza.Sabdar@Sun.COM * well. This prevents the infinite loop.
8767917SReza.Sabdar@Sun.COM * If it's not set the same directory will
8777917SReza.Sabdar@Sun.COM * be poped from the stack and will be
8787917SReza.Sabdar@Sun.COM * scanned again.
8797917SReza.Sabdar@Sun.COM */
8807917SReza.Sabdar@Sun.COM next_dir = 0;
8817917SReza.Sabdar@Sun.COM rv = 0;
8827917SReza.Sabdar@Sun.COM goto skip_dir;
8837917SReza.Sabdar@Sun.COM }
8847917SReza.Sabdar@Sun.COM
8857917SReza.Sabdar@Sun.COM /* re-start reading entries of the directory */
8867917SReza.Sabdar@Sun.COM tsp->ts_dpos = 0;
8877917SReza.Sabdar@Sun.COM }
8887917SReza.Sabdar@Sun.COM
8897917SReza.Sabdar@Sun.COM next_dir = 0;
8907917SReza.Sabdar@Sun.COM do {
8917917SReza.Sabdar@Sun.COM el = NAME_MAX;
8927917SReza.Sabdar@Sun.COM rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
8937917SReza.Sabdar@Sun.COM &tsp->ts_dpos, nm, &el, &efh,
8949714SReza.Sabdar@Sun.COM &est);
8957917SReza.Sabdar@Sun.COM if (rv != 0) {
8967917SReza.Sabdar@Sun.COM traverse_stats.fss_readdir_err++;
8977917SReza.Sabdar@Sun.COM
8987917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
8997917SReza.Sabdar@Sun.COM "Error %d on readdir(%s) pos %d",
9007917SReza.Sabdar@Sun.COM rv, path, tsp->ts_dpos);
9017917SReza.Sabdar@Sun.COM if (STOP_ONERR(ftp))
9027917SReza.Sabdar@Sun.COM break;
9037917SReza.Sabdar@Sun.COM rv = SKIP_ENTRY;
9047917SReza.Sabdar@Sun.COM continue;
9057917SReza.Sabdar@Sun.COM }
9067917SReza.Sabdar@Sun.COM
9077917SReza.Sabdar@Sun.COM /* done with this directory */
9087917SReza.Sabdar@Sun.COM if (el == 0)
9097917SReza.Sabdar@Sun.COM break;
9107917SReza.Sabdar@Sun.COM
9117917SReza.Sabdar@Sun.COM nm[el] = '\0';
9127917SReza.Sabdar@Sun.COM
9137917SReza.Sabdar@Sun.COM if (rootfs_dot_or_dotdot(nm)) {
9149714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
9157917SReza.Sabdar@Sun.COM continue;
9167917SReza.Sabdar@Sun.COM }
9177917SReza.Sabdar@Sun.COM
9187917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
9197917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
9207917SReza.Sabdar@Sun.COM tsp->ts_dpos, nm);
9217917SReza.Sabdar@Sun.COM
9227917SReza.Sabdar@Sun.COM if (pl + 1 + el > PATH_MAX) {
9237917SReza.Sabdar@Sun.COM /*
9247917SReza.Sabdar@Sun.COM * The long paths were already encountered
9257917SReza.Sabdar@Sun.COM * when processing non-dir entries in.
9267917SReza.Sabdar@Sun.COM * traverse_level_nondir.
9277917SReza.Sabdar@Sun.COM * We don't increase fss_longpath_err
9287917SReza.Sabdar@Sun.COM * counter for them again here.
9297917SReza.Sabdar@Sun.COM */
9307917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
9317917SReza.Sabdar@Sun.COM path, nm);
9327917SReza.Sabdar@Sun.COM if (STOP_ONLONG(ftp))
9337917SReza.Sabdar@Sun.COM rv = ENAMETOOLONG;
9349714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
9357917SReza.Sabdar@Sun.COM continue;
9367917SReza.Sabdar@Sun.COM }
9377917SReza.Sabdar@Sun.COM
9389714SReza.Sabdar@Sun.COM if (!S_ISDIR(est.st_mode))
9397917SReza.Sabdar@Sun.COM continue;
9407917SReza.Sabdar@Sun.COM
9417917SReza.Sabdar@Sun.COM /*
9427917SReza.Sabdar@Sun.COM * Call the callback function for the new
9437917SReza.Sabdar@Sun.COM * directory found, then push the current
9447917SReza.Sabdar@Sun.COM * directory on to the stack. Then dive
9457917SReza.Sabdar@Sun.COM * into the entry found.
9467917SReza.Sabdar@Sun.COM */
9477917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++;
9487917SReza.Sabdar@Sun.COM en.tn_path = nm;
9497917SReza.Sabdar@Sun.COM en.tn_fh = &efh;
9507917SReza.Sabdar@Sun.COM en.tn_st = &est;
9517917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en);
9527917SReza.Sabdar@Sun.COM
9537917SReza.Sabdar@Sun.COM if (rv < 0) {
9547917SReza.Sabdar@Sun.COM NEGATE(rv);
9559714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
9567917SReza.Sabdar@Sun.COM break;
9577917SReza.Sabdar@Sun.COM }
9587917SReza.Sabdar@Sun.COM if (rv == FST_SKIP) {
9597917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_skipped++;
9609714SReza.Sabdar@Sun.COM free(efh.fh_fpath);
9617917SReza.Sabdar@Sun.COM rv = 0;
9627917SReza.Sabdar@Sun.COM continue;
9637917SReza.Sabdar@Sun.COM }
9647917SReza.Sabdar@Sun.COM
9657917SReza.Sabdar@Sun.COM /*
9667917SReza.Sabdar@Sun.COM * Push the current directory on to the stack and
9677917SReza.Sabdar@Sun.COM * dive into the entry found.
9687917SReza.Sabdar@Sun.COM */
9699714SReza.Sabdar@Sun.COM if (cstack_push(sp, tsp, 0)) {
9707917SReza.Sabdar@Sun.COM rv = ENOMEM;
9719714SReza.Sabdar@Sun.COM } else {
9727917SReza.Sabdar@Sun.COM traverse_stats.fss_pushes++;
9737917SReza.Sabdar@Sun.COM
9747917SReza.Sabdar@Sun.COM lp = tsp->ts_end;
9757917SReza.Sabdar@Sun.COM *tsp->ts_end = '/';
9767917SReza.Sabdar@Sun.COM (void) strcpy(tsp->ts_end + 1, nm);
9777917SReza.Sabdar@Sun.COM
9787917SReza.Sabdar@Sun.COM tsp = new_tsp(path);
9797917SReza.Sabdar@Sun.COM if (!tsp)
9807917SReza.Sabdar@Sun.COM rv = ENOMEM;
9817917SReza.Sabdar@Sun.COM else {
9827917SReza.Sabdar@Sun.COM next_dir = 1;
9837917SReza.Sabdar@Sun.COM pl += el + 1;
9847917SReza.Sabdar@Sun.COM tsp->ts_fh = efh;
9857917SReza.Sabdar@Sun.COM tsp->ts_st = est;
9867917SReza.Sabdar@Sun.COM tsp->ts_ent = lp;
9877917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh;
9887917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st;
9897917SReza.Sabdar@Sun.COM }
9907917SReza.Sabdar@Sun.COM }
9917917SReza.Sabdar@Sun.COM break;
9927917SReza.Sabdar@Sun.COM
9937917SReza.Sabdar@Sun.COM } while (rv == 0);
9947917SReza.Sabdar@Sun.COM
9957917SReza.Sabdar@Sun.COM /*
9967917SReza.Sabdar@Sun.COM * A new directory must be processed, go to the start of
9977917SReza.Sabdar@Sun.COM * the loop, open it and process it.
9987917SReza.Sabdar@Sun.COM */
9997917SReza.Sabdar@Sun.COM if (next_dir)
10007917SReza.Sabdar@Sun.COM continue;
10017917SReza.Sabdar@Sun.COM skip_dir:
10029714SReza.Sabdar@Sun.COM if (tsp) {
10039714SReza.Sabdar@Sun.COM free(tsp->ts_fh.fh_fpath);
10047917SReza.Sabdar@Sun.COM free(tsp);
10059714SReza.Sabdar@Sun.COM }
10067917SReza.Sabdar@Sun.COM
10077917SReza.Sabdar@Sun.COM if (rv == SKIP_ENTRY)
10087917SReza.Sabdar@Sun.COM rv = 0;
10097917SReza.Sabdar@Sun.COM
10107917SReza.Sabdar@Sun.COM if (rv == 0) {
10117917SReza.Sabdar@Sun.COM if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
10127917SReza.Sabdar@Sun.COM break;
10137917SReza.Sabdar@Sun.COM
10147917SReza.Sabdar@Sun.COM traverse_stats.fss_pops++;
10157917SReza.Sabdar@Sun.COM
10167917SReza.Sabdar@Sun.COM if (VERBOSE(ftp))
10177917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG,
10187917SReza.Sabdar@Sun.COM "Poped pl %d \"%s\"", pl, path);
10197917SReza.Sabdar@Sun.COM
10207917SReza.Sabdar@Sun.COM *tsp->ts_end = '\0';
10217917SReza.Sabdar@Sun.COM pl = tsp->ts_end - path;
10227917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh;
10237917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st;
10247917SReza.Sabdar@Sun.COM }
10257917SReza.Sabdar@Sun.COM } while (rv == 0);
10267917SReza.Sabdar@Sun.COM
10277917SReza.Sabdar@Sun.COM /*
10287917SReza.Sabdar@Sun.COM * Pop and free all the remaining entries on the stack.
10297917SReza.Sabdar@Sun.COM */
10307917SReza.Sabdar@Sun.COM while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
10317917SReza.Sabdar@Sun.COM traverse_stats.fss_stack_residue++;
10327917SReza.Sabdar@Sun.COM
10339714SReza.Sabdar@Sun.COM free(tsp->ts_fh.fh_fpath);
10347917SReza.Sabdar@Sun.COM free(tsp);
10357917SReza.Sabdar@Sun.COM }
10367917SReza.Sabdar@Sun.COM end:
10377917SReza.Sabdar@Sun.COM free(darg.da_buf);
10387917SReza.Sabdar@Sun.COM cstack_delete(sp);
10397917SReza.Sabdar@Sun.COM return (rv);
10407917SReza.Sabdar@Sun.COM }
10417917SReza.Sabdar@Sun.COM
10427917SReza.Sabdar@Sun.COM /*
10437917SReza.Sabdar@Sun.COM * filecopy - Copy a file
10447917SReza.Sabdar@Sun.COM *
10457917SReza.Sabdar@Sun.COM * Parameters:
10467917SReza.Sabdar@Sun.COM * char *dest - Destination path
10477917SReza.Sabdar@Sun.COM * char *src - Source path
10487917SReza.Sabdar@Sun.COM *
10497917SReza.Sabdar@Sun.COM * Returns:
10507917SReza.Sabdar@Sun.COM * 0 - No errors
10517917SReza.Sabdar@Sun.COM * #0 - Error occured
10527917SReza.Sabdar@Sun.COM * -4 - read/write error
10537917SReza.Sabdar@Sun.COM * -5 - source modified during copy
10547917SReza.Sabdar@Sun.COM *
10557917SReza.Sabdar@Sun.COM * Simplified version for Solaris
10567917SReza.Sabdar@Sun.COM */
10577917SReza.Sabdar@Sun.COM #define BUFSIZE 32768
10587917SReza.Sabdar@Sun.COM int
filecopy(char * dest,char * src)10597917SReza.Sabdar@Sun.COM filecopy(char *dest, char *src)
10607917SReza.Sabdar@Sun.COM {
10617917SReza.Sabdar@Sun.COM FILE *src_fh = 0;
10627917SReza.Sabdar@Sun.COM FILE *dst_fh = 0;
10637917SReza.Sabdar@Sun.COM struct stat64 src_attr;
10647917SReza.Sabdar@Sun.COM struct stat64 dst_attr;
10657917SReza.Sabdar@Sun.COM char *buf = 0;
10667917SReza.Sabdar@Sun.COM u_longlong_t bytes_to_copy;
10677917SReza.Sabdar@Sun.COM size_t nbytes;
10687917SReza.Sabdar@Sun.COM int file_copied = 0;
10697917SReza.Sabdar@Sun.COM
10707917SReza.Sabdar@Sun.COM buf = ndmp_malloc(BUFSIZE);
10717917SReza.Sabdar@Sun.COM if (!buf)
10727917SReza.Sabdar@Sun.COM return (-1);
10737917SReza.Sabdar@Sun.COM
10747917SReza.Sabdar@Sun.COM src_fh = fopen(src, "r");
10757917SReza.Sabdar@Sun.COM if (src_fh == 0) {
10767917SReza.Sabdar@Sun.COM free(buf);
10777917SReza.Sabdar@Sun.COM return (-2);
10787917SReza.Sabdar@Sun.COM }
10797917SReza.Sabdar@Sun.COM
10807917SReza.Sabdar@Sun.COM dst_fh = fopen(dest, "w");
10817917SReza.Sabdar@Sun.COM if (dst_fh == NULL) {
10827917SReza.Sabdar@Sun.COM free(buf);
10837917SReza.Sabdar@Sun.COM (void) fclose(src_fh);
10847917SReza.Sabdar@Sun.COM return (-3);
10857917SReza.Sabdar@Sun.COM }
10867917SReza.Sabdar@Sun.COM
10877917SReza.Sabdar@Sun.COM if (stat64(src, &src_attr) < 0) {
10887917SReza.Sabdar@Sun.COM free(buf);
10897917SReza.Sabdar@Sun.COM (void) fclose(src_fh);
10907917SReza.Sabdar@Sun.COM (void) fclose(dst_fh);
10917917SReza.Sabdar@Sun.COM return (-2);
10927917SReza.Sabdar@Sun.COM }
10937917SReza.Sabdar@Sun.COM
10947917SReza.Sabdar@Sun.COM bytes_to_copy = src_attr.st_size;
10957917SReza.Sabdar@Sun.COM while (bytes_to_copy) {
10967917SReza.Sabdar@Sun.COM if (bytes_to_copy > BUFSIZE)
10977917SReza.Sabdar@Sun.COM nbytes = BUFSIZE;
10987917SReza.Sabdar@Sun.COM else
10997917SReza.Sabdar@Sun.COM nbytes = bytes_to_copy;
11007917SReza.Sabdar@Sun.COM
11017917SReza.Sabdar@Sun.COM if ((fread(buf, nbytes, 1, src_fh) != 1) ||
11027917SReza.Sabdar@Sun.COM (fwrite(buf, nbytes, 1, dst_fh) != 1))
11037917SReza.Sabdar@Sun.COM break;
11047917SReza.Sabdar@Sun.COM bytes_to_copy -= nbytes;
11057917SReza.Sabdar@Sun.COM }
11067917SReza.Sabdar@Sun.COM
11077917SReza.Sabdar@Sun.COM (void) fclose(src_fh);
11087917SReza.Sabdar@Sun.COM (void) fclose(dst_fh);
11097917SReza.Sabdar@Sun.COM
11107917SReza.Sabdar@Sun.COM if (bytes_to_copy > 0) {
11117917SReza.Sabdar@Sun.COM free(buf);
11127917SReza.Sabdar@Sun.COM /* short read/write, remove the partial file */
11137917SReza.Sabdar@Sun.COM return (-4);
11147917SReza.Sabdar@Sun.COM }
11157917SReza.Sabdar@Sun.COM
11167917SReza.Sabdar@Sun.COM if (stat64(src, &dst_attr) < 0) {
11177917SReza.Sabdar@Sun.COM free(buf);
11187917SReza.Sabdar@Sun.COM return (-2);
11197917SReza.Sabdar@Sun.COM }
11207917SReza.Sabdar@Sun.COM
11217917SReza.Sabdar@Sun.COM free(buf);
11227917SReza.Sabdar@Sun.COM
11237917SReza.Sabdar@Sun.COM if (!file_copied)
11247917SReza.Sabdar@Sun.COM return (-5); /* source modified during copy */
11257917SReza.Sabdar@Sun.COM else
11267917SReza.Sabdar@Sun.COM return (0);
11277917SReza.Sabdar@Sun.COM }
1128