12654012fSReza Sabdar /*
2*65451a03SReza Sabdar * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
32654012fSReza Sabdar */
42654012fSReza Sabdar
52654012fSReza Sabdar /*
62654012fSReza Sabdar * BSD 3 Clause License
72654012fSReza Sabdar *
82654012fSReza Sabdar * Copyright (c) 2007, The Storage Networking Industry Association.
92654012fSReza Sabdar *
102654012fSReza Sabdar * Redistribution and use in source and binary forms, with or without
112654012fSReza Sabdar * modification, are permitted provided that the following conditions
122654012fSReza Sabdar * are met:
132654012fSReza Sabdar * - Redistributions of source code must retain the above copyright
142654012fSReza Sabdar * notice, this list of conditions and the following disclaimer.
152654012fSReza Sabdar *
162654012fSReza Sabdar * - Redistributions in binary form must reproduce the above copyright
172654012fSReza Sabdar * notice, this list of conditions and the following disclaimer in
182654012fSReza Sabdar * the documentation and/or other materials provided with the
192654012fSReza Sabdar * distribution.
202654012fSReza Sabdar *
212654012fSReza Sabdar * - Neither the name of The Storage Networking Industry Association (SNIA)
222654012fSReza Sabdar * nor the names of its contributors may be used to endorse or promote
232654012fSReza Sabdar * products derived from this software without specific prior written
242654012fSReza Sabdar * permission.
252654012fSReza Sabdar *
262654012fSReza Sabdar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
272654012fSReza Sabdar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
282654012fSReza Sabdar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
292654012fSReza Sabdar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
302654012fSReza Sabdar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
312654012fSReza Sabdar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
322654012fSReza Sabdar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
332654012fSReza Sabdar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
342654012fSReza Sabdar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
352654012fSReza Sabdar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
362654012fSReza Sabdar * POSSIBILITY OF SUCH DAMAGE.
372654012fSReza Sabdar */
382654012fSReza Sabdar /*
392654012fSReza Sabdar * This file implemets the post-order, pre-order and level-order
402654012fSReza Sabdar * traversing of the file system. The related macros and constants
412654012fSReza Sabdar * are defined in traverse.h.
422654012fSReza Sabdar */
432654012fSReza Sabdar
442654012fSReza Sabdar #include <sys/stat.h>
452654012fSReza Sabdar #include <sys/types.h>
462654012fSReza Sabdar #include <sys/param.h>
472654012fSReza Sabdar #include <assert.h>
482654012fSReza Sabdar #include <cstack.h>
492654012fSReza Sabdar #include <dirent.h>
502654012fSReza Sabdar #include <errno.h>
512654012fSReza Sabdar #include <traverse.h>
522654012fSReza Sabdar #include <limits.h>
532654012fSReza Sabdar #include <stdarg.h>
542654012fSReza Sabdar #include <stdio.h>
552654012fSReza Sabdar #include <stdlib.h>
562654012fSReza Sabdar #include <string.h>
572654012fSReza Sabdar #include <syslog.h>
582654012fSReza Sabdar #include <fcntl.h>
592654012fSReza Sabdar #include <unistd.h>
602654012fSReza Sabdar #include <tlm.h>
612654012fSReza Sabdar #include "tlm_proto.h"
622654012fSReza Sabdar
632654012fSReza Sabdar /*
642654012fSReza Sabdar * Check if it's "." or ".."
652654012fSReza Sabdar */
662654012fSReza Sabdar boolean_t
rootfs_dot_or_dotdot(char * name)672654012fSReza Sabdar rootfs_dot_or_dotdot(char *name)
682654012fSReza Sabdar {
692654012fSReza Sabdar if (*name != '.')
702654012fSReza Sabdar return (FALSE);
712654012fSReza Sabdar
722654012fSReza Sabdar if ((name[1] == 0) || (name[1] == '.' && name[2] == 0))
732654012fSReza Sabdar return (TRUE);
742654012fSReza Sabdar
752654012fSReza Sabdar return (FALSE);
762654012fSReza Sabdar }
772654012fSReza Sabdar
782654012fSReza Sabdar /*
792654012fSReza Sabdar * Macros on fs_traverse flags.
802654012fSReza Sabdar */
812654012fSReza Sabdar #define STOP_ONERR(f) ((f)->ft_flags & FST_STOP_ONERR)
822654012fSReza Sabdar #define STOP_ONLONG(f) ((f)->ft_flags & FST_STOP_ONLONG)
832654012fSReza Sabdar #define VERBOSE(f) ((f)->ft_flags & FST_VERBOSE)
842654012fSReza Sabdar
852654012fSReza Sabdar #define CALLBACK(pp, ep) \
862654012fSReza Sabdar (*(ftp)->ft_callbk)((ftp)->ft_arg, pp, ep)
872654012fSReza Sabdar
882654012fSReza Sabdar #define NEGATE(rv) ((rv) = -(rv))
892654012fSReza Sabdar
902654012fSReza Sabdar /*
912654012fSReza Sabdar * The traversing state that is pushed onto the stack.
922654012fSReza Sabdar * This include:
932654012fSReza Sabdar * - The end of the path of the current directory.
942654012fSReza Sabdar * - The position of the last component on it.
952654012fSReza Sabdar * - The read position in the directory.
962654012fSReza Sabdar * - The file handle of the directory.
972654012fSReza Sabdar * - The stat of the directory.
982654012fSReza Sabdar */
992654012fSReza Sabdar typedef struct traverse_state {
1002654012fSReza Sabdar char *ts_end;
1012654012fSReza Sabdar char *ts_ent;
1022654012fSReza Sabdar long ts_dpos; /* position in the directory when reading its entries */
1032654012fSReza Sabdar fs_fhandle_t ts_fh;
1042654012fSReza Sabdar struct stat64 ts_st;
1052654012fSReza Sabdar } traverse_state_t;
1062654012fSReza Sabdar
1072654012fSReza Sabdar /*
1082654012fSReza Sabdar * Statistics gathering structure.
1092654012fSReza Sabdar */
1102654012fSReza Sabdar typedef struct traverse_statistics {
1112654012fSReza Sabdar ulong_t fss_newdirs;
1122654012fSReza Sabdar ulong_t fss_readdir_err;
1132654012fSReza Sabdar ulong_t fss_longpath_err;
1142654012fSReza Sabdar ulong_t fss_lookup_err;
1152654012fSReza Sabdar ulong_t fss_nondir_calls;
1162654012fSReza Sabdar ulong_t fss_dir_calls;
1172654012fSReza Sabdar ulong_t fss_nondir_skipped;
1182654012fSReza Sabdar ulong_t fss_dir_skipped;
1192654012fSReza Sabdar ulong_t fss_pushes;
1202654012fSReza Sabdar ulong_t fss_pops;
1212654012fSReza Sabdar ulong_t fss_stack_residue;
1222654012fSReza Sabdar } traverse_statistics_t;
1232654012fSReza Sabdar
1242654012fSReza Sabdar /*
1252654012fSReza Sabdar * Global instance of statistics variable.
1262654012fSReza Sabdar */
1272654012fSReza Sabdar traverse_statistics_t traverse_stats;
1282654012fSReza Sabdar
1292654012fSReza Sabdar #define MAX_DENT_BUF_SIZE (8 * 1024)
1302654012fSReza Sabdar
1312654012fSReza Sabdar typedef struct {
1322654012fSReza Sabdar struct stat64 fd_attr;
1332654012fSReza Sabdar fs_fhandle_t fd_fh;
1342654012fSReza Sabdar short fd_len;
1352654012fSReza Sabdar char fd_name[1];
1362654012fSReza Sabdar } fs_dent_info_t;
1372654012fSReza Sabdar
1382654012fSReza Sabdar typedef struct dent_arg {
1392654012fSReza Sabdar char *da_buf;
1402654012fSReza Sabdar int da_end;
1412654012fSReza Sabdar int da_size;
1422654012fSReza Sabdar } dent_arg_t;
1432654012fSReza Sabdar
1442654012fSReza Sabdar static int traverse_level_nondir(struct fs_traverse *ftp,
1452654012fSReza Sabdar traverse_state_t *tsp, struct fst_node *pnp,
1462654012fSReza Sabdar dent_arg_t *darg);
1472654012fSReza Sabdar
1482654012fSReza Sabdar /*
1492654012fSReza Sabdar * Gather some directory entry information and return them
1502654012fSReza Sabdar */
1512654012fSReza Sabdar static int
fs_populate_dents(void * arg,int namelen,char * name,long * countp,struct stat64 * attr,fs_fhandle_t * fh)1522654012fSReza Sabdar fs_populate_dents(void *arg, int namelen,
1532654012fSReza Sabdar char *name, long *countp, struct stat64 *attr,
1542654012fSReza Sabdar fs_fhandle_t *fh)
1552654012fSReza Sabdar {
1562654012fSReza Sabdar dent_arg_t *darg = (dent_arg_t *)arg;
1572654012fSReza Sabdar int reclen = sizeof (fs_dent_info_t) + namelen;
1582654012fSReza Sabdar fs_dent_info_t *dent;
1592654012fSReza Sabdar
1602654012fSReza Sabdar if ((darg->da_end + reclen) > darg->da_size)
1612654012fSReza Sabdar return (-1);
1622654012fSReza Sabdar
1632654012fSReza Sabdar /* LINTED improper alignment */
1642654012fSReza Sabdar dent = (fs_dent_info_t *)(darg->da_buf + darg->da_end);
1652654012fSReza Sabdar
1662654012fSReza Sabdar dent->fd_attr = *attr;
1672654012fSReza Sabdar dent->fd_fh = *fh;
1682654012fSReza Sabdar (void) strcpy(dent->fd_name, name);
1692654012fSReza Sabdar
1702654012fSReza Sabdar dent->fd_len = reclen;
1712654012fSReza Sabdar darg->da_end += reclen;
1722654012fSReza Sabdar
1732654012fSReza Sabdar if (countp)
1742654012fSReza Sabdar (*countp)++;
1752654012fSReza Sabdar
1762654012fSReza Sabdar return (0);
1772654012fSReza Sabdar }
1782654012fSReza Sabdar
1792654012fSReza Sabdar /*
1802654012fSReza Sabdar * Creates a new traversing state based on the path passed to it.
1812654012fSReza Sabdar */
1822654012fSReza Sabdar static traverse_state_t *
new_tsp(char * path)1832654012fSReza Sabdar new_tsp(char *path)
1842654012fSReza Sabdar {
1852654012fSReza Sabdar traverse_state_t *tsp;
1862654012fSReza Sabdar tsp = ndmp_malloc(sizeof (traverse_state_t));
1872654012fSReza Sabdar if (!tsp)
1882654012fSReza Sabdar return (NULL);
1892654012fSReza Sabdar
1902654012fSReza Sabdar tsp->ts_end = strchr(path, '\0');
1912654012fSReza Sabdar if (*(tsp->ts_end-1) == '/')
1922654012fSReza Sabdar *--tsp->ts_end = '\0';
1932654012fSReza Sabdar tsp->ts_ent = NULL;
1942654012fSReza Sabdar tsp->ts_dpos = 0;
1952654012fSReza Sabdar
1962654012fSReza Sabdar return (tsp);
1972654012fSReza Sabdar }
1982654012fSReza Sabdar
1992654012fSReza Sabdar /*
2002654012fSReza Sabdar * Create a file handle and get stats for the given path
2012654012fSReza Sabdar */
2022654012fSReza Sabdar int
fs_getstat(char * path,fs_fhandle_t * fh,struct stat64 * st)20384bf06e9SReza Sabdar fs_getstat(char *path, fs_fhandle_t *fh, struct stat64 *st)
2042654012fSReza Sabdar {
2052654012fSReza Sabdar if (lstat64(path, st) == -1)
2062654012fSReza Sabdar return (errno);
2072654012fSReza Sabdar
2082654012fSReza Sabdar fh->fh_fid = st->st_ino;
209c211fc47SReza Sabdar
21084bf06e9SReza Sabdar if (!S_ISDIR(st->st_mode))
211c211fc47SReza Sabdar fh->fh_fpath = NULL;
2122654012fSReza Sabdar else
2132654012fSReza Sabdar fh->fh_fpath = strdup(path);
2142654012fSReza Sabdar return (0);
2152654012fSReza Sabdar }
2162654012fSReza Sabdar
2172654012fSReza Sabdar /*
2182654012fSReza Sabdar * Get directory entries info and return in the buffer. Cookie
2192654012fSReza Sabdar * will keep the state of each call
2202654012fSReza Sabdar */
2212654012fSReza Sabdar 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)2222654012fSReza Sabdar fs_getdents(int fildes, struct dirent *buf, size_t *nbyte,
2232654012fSReza Sabdar char *pn_path, long *dpos, longlong_t *cookie,
22484bf06e9SReza Sabdar long *n_entries, dent_arg_t *darg)
2252654012fSReza Sabdar {
2262654012fSReza Sabdar struct dirent *ptr;
2272654012fSReza Sabdar char file_path[PATH_MAX + 1];
2282654012fSReza Sabdar fs_fhandle_t fh;
2292654012fSReza Sabdar struct stat64 st;
2302654012fSReza Sabdar char *p;
2312654012fSReza Sabdar int len;
2322654012fSReza Sabdar int rv;
2332654012fSReza Sabdar
2342654012fSReza Sabdar if (*nbyte == 0) {
2352654012fSReza Sabdar (void) memset((char *)buf, 0, MAX_DENT_BUF_SIZE);
2362654012fSReza Sabdar *nbyte = rv = getdents(fildes, buf, darg->da_size);
2372654012fSReza Sabdar *cookie = 0LL;
2382654012fSReza Sabdar
2392654012fSReza Sabdar if (rv <= 0)
2402654012fSReza Sabdar return (rv);
2412654012fSReza Sabdar }
2422654012fSReza Sabdar
2432654012fSReza Sabdar p = (char *)buf + *cookie;
2442654012fSReza Sabdar len = *nbyte;
2452654012fSReza Sabdar do {
2462654012fSReza Sabdar /* LINTED improper alignment */
2472654012fSReza Sabdar ptr = (struct dirent *)p;
2482654012fSReza Sabdar *dpos = ptr->d_off;
24984bf06e9SReza Sabdar
25084bf06e9SReza Sabdar if (rootfs_dot_or_dotdot(ptr->d_name))
25184bf06e9SReza Sabdar goto skip_entry;
25284bf06e9SReza Sabdar
2532654012fSReza Sabdar (void) snprintf(file_path, PATH_MAX, "%s/", pn_path);
254*65451a03SReza Sabdar (void) strlcat(file_path, ptr->d_name, PATH_MAX + 1);
2552654012fSReza Sabdar (void) memset(&fh, 0, sizeof (fs_fhandle_t));
2562654012fSReza Sabdar
2575a3c8170SReza Sabdar if (lstat64(file_path, &st) != 0) {
2585a3c8170SReza Sabdar rv = -1;
2592654012fSReza Sabdar break;
2605a3c8170SReza Sabdar }
2612654012fSReza Sabdar
26284bf06e9SReza Sabdar fh.fh_fid = st.st_ino;
26384bf06e9SReza Sabdar
26484bf06e9SReza Sabdar if (S_ISDIR(st.st_mode))
26584bf06e9SReza Sabdar goto skip_entry;
26684bf06e9SReza Sabdar
2675a3c8170SReza Sabdar if (fs_populate_dents(darg, strlen(ptr->d_name),
2685a3c8170SReza Sabdar (char *)ptr->d_name, n_entries, &st, &fh) != 0)
2692654012fSReza Sabdar break;
2702654012fSReza Sabdar
27184bf06e9SReza Sabdar skip_entry:
2722654012fSReza Sabdar p = p + ptr->d_reclen;
2732654012fSReza Sabdar len -= ptr->d_reclen;
2742654012fSReza Sabdar } while (len);
2752654012fSReza Sabdar
2762654012fSReza Sabdar *cookie = (longlong_t)(p - (char *)buf);
2772654012fSReza Sabdar *nbyte = len;
2782654012fSReza Sabdar return (rv);
2792654012fSReza Sabdar }
2802654012fSReza Sabdar
2812654012fSReza Sabdar /*
2822654012fSReza Sabdar * Read the directory entries and return the information about
2832654012fSReza Sabdar * each entry
2842654012fSReza Sabdar */
2852654012fSReza Sabdar int
fs_readdir(fs_fhandle_t * ts_fh,char * path,long * dpos,char * nm,int * el,fs_fhandle_t * efh,struct stat64 * est)2862654012fSReza Sabdar fs_readdir(fs_fhandle_t *ts_fh, char *path, long *dpos,
28784bf06e9SReza Sabdar char *nm, int *el, fs_fhandle_t *efh, struct stat64 *est)
2882654012fSReza Sabdar {
2892654012fSReza Sabdar struct dirent *dp;
2902654012fSReza Sabdar char file_path[PATH_MAX + 1];
2912654012fSReza Sabdar DIR *dirp;
2922654012fSReza Sabdar int rv;
2932654012fSReza Sabdar
2942654012fSReza Sabdar if ((dirp = opendir(ts_fh->fh_fpath)) == NULL)
2952654012fSReza Sabdar return (errno);
2962654012fSReza Sabdar
2972654012fSReza Sabdar seekdir(dirp, *dpos);
2982654012fSReza Sabdar if ((dp = readdir(dirp)) == NULL) {
2992654012fSReza Sabdar rv = 0; /* skip this dir */
3002654012fSReza Sabdar *el = 0;
3012654012fSReza Sabdar } else {
3022654012fSReza Sabdar (void) snprintf(file_path, PATH_MAX, "%s/", path);
303*65451a03SReza Sabdar (void) strlcat(file_path, dp->d_name, PATH_MAX + 1);
3042654012fSReza Sabdar
30584bf06e9SReza Sabdar rv = fs_getstat(file_path, efh, est);
3062654012fSReza Sabdar if (rv == 0) {
3072654012fSReza Sabdar *dpos = telldir(dirp);
308*65451a03SReza Sabdar (void) strlcpy(nm, dp->d_name, NAME_MAX + 1);
3092654012fSReza Sabdar *el = strlen(dp->d_name);
3102654012fSReza Sabdar } else {
3112654012fSReza Sabdar *el = 0;
3122654012fSReza Sabdar }
3132654012fSReza Sabdar }
3142654012fSReza Sabdar (void) closedir(dirp);
3152654012fSReza Sabdar return (rv);
3162654012fSReza Sabdar }
3172654012fSReza Sabdar
3182654012fSReza Sabdar /*
3192654012fSReza Sabdar * Traverse the file system in the post-order way. The description
3202654012fSReza Sabdar * and example is in the header file.
3212654012fSReza Sabdar *
3222654012fSReza Sabdar * The callback function should return 0, on success and non-zero on
3232654012fSReza Sabdar * failure. If the callback function returns non-zero return value,
3242654012fSReza Sabdar * the traversing stops.
3252654012fSReza Sabdar */
3262654012fSReza Sabdar int
traverse_post(struct fs_traverse * ftp)3272654012fSReza Sabdar traverse_post(struct fs_traverse *ftp)
3282654012fSReza Sabdar {
3292654012fSReza Sabdar char path[PATH_MAX + 1]; /* full path name of the current dir */
3302654012fSReza Sabdar char nm[NAME_MAX + 1]; /* directory entry name */
3312654012fSReza Sabdar char *lp; /* last position on the path */
3322654012fSReza Sabdar int next_dir, rv;
3332654012fSReza Sabdar int pl, el; /* path and directory entry length */
3342654012fSReza Sabdar cstack_t *sp;
3352654012fSReza Sabdar fs_fhandle_t pfh, efh;
3362654012fSReza Sabdar struct stat64 pst, est;
3372654012fSReza Sabdar traverse_state_t *tsp;
3382654012fSReza Sabdar struct fst_node pn, en; /* parent and entry nodes */
3392654012fSReza Sabdar
3402654012fSReza Sabdar if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
3412654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Invalid argument");
3422654012fSReza Sabdar errno = EINVAL;
3432654012fSReza Sabdar return (-1);
3442654012fSReza Sabdar }
3452654012fSReza Sabdar
3462654012fSReza Sabdar /* set the default log function if it's not already set */
3472654012fSReza Sabdar if (!ftp->ft_logfp) {
3482654012fSReza Sabdar ftp->ft_logfp = (ft_log_t)syslog;
3492654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
3502654012fSReza Sabdar }
3512654012fSReza Sabdar
3522654012fSReza Sabdar /* set the logical path to physical path if it's not already set */
3532654012fSReza Sabdar if (!ftp->ft_lpath) {
3542654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
3552654012fSReza Sabdar "report the same paths: \"%s\"", ftp->ft_path);
3562654012fSReza Sabdar ftp->ft_lpath = ftp->ft_path;
3572654012fSReza Sabdar }
3582654012fSReza Sabdar
3592654012fSReza Sabdar pl = strlen(ftp->ft_lpath);
3602654012fSReza Sabdar if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
3612654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
3622654012fSReza Sabdar errno = ENAMETOOLONG;
3632654012fSReza Sabdar return (-1);
3642654012fSReza Sabdar }
3652654012fSReza Sabdar (void) strcpy(path, ftp->ft_lpath);
3662654012fSReza Sabdar (void) memset(&pfh, 0, sizeof (pfh));
36784bf06e9SReza Sabdar rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
3682654012fSReza Sabdar
3692654012fSReza Sabdar if (rv != 0) {
3702654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
3712654012fSReza Sabdar "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
3722654012fSReza Sabdar return (rv);
3732654012fSReza Sabdar }
3742654012fSReza Sabdar
3752654012fSReza Sabdar if (!S_ISDIR(pst.st_mode)) {
3762654012fSReza Sabdar pn.tn_path = ftp->ft_lpath;
3772654012fSReza Sabdar pn.tn_fh = &pfh;
3782654012fSReza Sabdar pn.tn_st = &pst;
3792654012fSReza Sabdar en.tn_path = NULL;
3802654012fSReza Sabdar en.tn_fh = NULL;
3812654012fSReza Sabdar en.tn_st = NULL;
3822654012fSReza Sabdar rv = CALLBACK(&pn, &en);
3832654012fSReza Sabdar if (VERBOSE(ftp))
3842654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
3852654012fSReza Sabdar free(pfh.fh_fpath);
3862654012fSReza Sabdar return (rv);
3872654012fSReza Sabdar }
3882654012fSReza Sabdar
3892654012fSReza Sabdar sp = cstack_new();
3902654012fSReza Sabdar if (!sp) {
3912654012fSReza Sabdar errno = ENOMEM;
3922654012fSReza Sabdar free(pfh.fh_fpath);
3932654012fSReza Sabdar return (-1);
3942654012fSReza Sabdar }
3952654012fSReza Sabdar tsp = new_tsp(path);
3962654012fSReza Sabdar if (!tsp) {
3972654012fSReza Sabdar cstack_delete(sp);
3982654012fSReza Sabdar errno = ENOMEM;
3992654012fSReza Sabdar free(pfh.fh_fpath);
4002654012fSReza Sabdar return (-1);
4012654012fSReza Sabdar }
4022654012fSReza Sabdar tsp->ts_ent = tsp->ts_end;
4032654012fSReza Sabdar tsp->ts_fh = pfh;
4042654012fSReza Sabdar tsp->ts_st = pst;
4052654012fSReza Sabdar pn.tn_path = path;
4062654012fSReza Sabdar pn.tn_fh = &tsp->ts_fh;
4072654012fSReza Sabdar pn.tn_st = &tsp->ts_st;
4082654012fSReza Sabdar
4092654012fSReza Sabdar rv = 0;
4102654012fSReza Sabdar next_dir = 1;
4112654012fSReza Sabdar do {
4122654012fSReza Sabdar if (next_dir) {
4132654012fSReza Sabdar traverse_stats.fss_newdirs++;
4142654012fSReza Sabdar
4152654012fSReza Sabdar *tsp->ts_end = '\0';
4162654012fSReza Sabdar if (VERBOSE(ftp))
4172654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
4182654012fSReza Sabdar }
4192654012fSReza Sabdar
4202654012fSReza Sabdar next_dir = 0;
4212654012fSReza Sabdar do {
4222654012fSReza Sabdar el = NAME_MAX;
4232654012fSReza Sabdar rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
4242654012fSReza Sabdar &tsp->ts_dpos, nm, &el,
42584bf06e9SReza Sabdar &efh, &est);
4262654012fSReza Sabdar
4272654012fSReza Sabdar if (rv != 0) {
42884bf06e9SReza Sabdar free(efh.fh_fpath);
4292654012fSReza Sabdar traverse_stats.fss_readdir_err++;
4302654012fSReza Sabdar
4312654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
4322654012fSReza Sabdar "Error %d on readdir(%s) pos %d",
4332654012fSReza Sabdar rv, path, tsp->ts_dpos);
4342654012fSReza Sabdar if (STOP_ONERR(ftp))
4352654012fSReza Sabdar break;
4362654012fSReza Sabdar rv = SKIP_ENTRY;
4372654012fSReza Sabdar
4382654012fSReza Sabdar continue;
4392654012fSReza Sabdar }
4402654012fSReza Sabdar
4412654012fSReza Sabdar /* done with this directory */
4422654012fSReza Sabdar if (el == 0) {
4432654012fSReza Sabdar if (VERBOSE(ftp))
4442654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
4452654012fSReza Sabdar "Done(%s)", pn.tn_path);
4462654012fSReza Sabdar break;
4472654012fSReza Sabdar }
4482654012fSReza Sabdar nm[el] = '\0';
4492654012fSReza Sabdar
4502654012fSReza Sabdar if (rootfs_dot_or_dotdot(nm)) {
45184bf06e9SReza Sabdar free(efh.fh_fpath);
4522654012fSReza Sabdar continue;
4532654012fSReza Sabdar }
4542654012fSReza Sabdar
4552654012fSReza Sabdar if (VERBOSE(ftp))
4562654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
4572654012fSReza Sabdar tsp->ts_dpos, nm);
4582654012fSReza Sabdar
4592654012fSReza Sabdar if (pl + 1 + el > PATH_MAX) {
4602654012fSReza Sabdar traverse_stats.fss_longpath_err++;
4612654012fSReza Sabdar
4622654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
4632654012fSReza Sabdar path, nm);
4642654012fSReza Sabdar if (STOP_ONLONG(ftp))
4652654012fSReza Sabdar rv = ENAMETOOLONG;
46684bf06e9SReza Sabdar free(efh.fh_fpath);
4672654012fSReza Sabdar continue;
4682654012fSReza Sabdar }
4692654012fSReza Sabdar
4702654012fSReza Sabdar /*
4712654012fSReza Sabdar * Push the current directory on to the stack and
4722654012fSReza Sabdar * dive into the entry found.
4732654012fSReza Sabdar */
4742654012fSReza Sabdar if (S_ISDIR(est.st_mode)) {
4752654012fSReza Sabdar
4762654012fSReza Sabdar assert(tsp != NULL);
4772654012fSReza Sabdar if (cstack_push(sp, tsp, 0)) {
4782654012fSReza Sabdar rv = ENOMEM;
47984bf06e9SReza Sabdar free(efh.fh_fpath);
4802654012fSReza Sabdar break;
4812654012fSReza Sabdar }
4822654012fSReza Sabdar traverse_stats.fss_pushes++;
4832654012fSReza Sabdar
4842654012fSReza Sabdar /*
4852654012fSReza Sabdar * Concatenate the current entry with the
4862654012fSReza Sabdar * current path. This will be the path of
4872654012fSReza Sabdar * the new directory to be scanned.
4882654012fSReza Sabdar *
4892654012fSReza Sabdar * Note:
4902654012fSReza Sabdar * sprintf(tsp->ts_end, "/%s", de->d_name);
4912654012fSReza Sabdar * could be used here, but concatenating
4922654012fSReza Sabdar * strings like this might be faster.
4932654012fSReza Sabdar * The length of the new path has been
4942654012fSReza Sabdar * checked above. So strcpy() can be
4952654012fSReza Sabdar * safe and should not lead to a buffer
4962654012fSReza Sabdar * over-run.
4972654012fSReza Sabdar */
4982654012fSReza Sabdar lp = tsp->ts_end;
4992654012fSReza Sabdar *tsp->ts_end = '/';
5002654012fSReza Sabdar (void) strcpy(tsp->ts_end + 1, nm);
5012654012fSReza Sabdar
5022654012fSReza Sabdar tsp = new_tsp(path);
5032654012fSReza Sabdar if (!tsp) {
50484bf06e9SReza Sabdar free(efh.fh_fpath);
5052654012fSReza Sabdar rv = ENOMEM;
5062654012fSReza Sabdar } else {
5072654012fSReza Sabdar next_dir = 1;
5082654012fSReza Sabdar pl += el;
5092654012fSReza Sabdar tsp->ts_fh = efh;
5102654012fSReza Sabdar tsp->ts_st = est;
5112654012fSReza Sabdar tsp->ts_ent = lp;
5122654012fSReza Sabdar pn.tn_fh = &tsp->ts_fh;
5132654012fSReza Sabdar pn.tn_st = &tsp->ts_st;
5142654012fSReza Sabdar }
5152654012fSReza Sabdar break;
5162654012fSReza Sabdar } else {
5172654012fSReza Sabdar /*
5182654012fSReza Sabdar * The entry is not a directory so the
5192654012fSReza Sabdar * callback function must be called.
5202654012fSReza Sabdar */
5212654012fSReza Sabdar traverse_stats.fss_nondir_calls++;
5222654012fSReza Sabdar
5232654012fSReza Sabdar en.tn_path = nm;
5242654012fSReza Sabdar en.tn_fh = &efh;
5252654012fSReza Sabdar en.tn_st = &est;
5262654012fSReza Sabdar rv = CALLBACK(&pn, &en);
52784bf06e9SReza Sabdar free(efh.fh_fpath);
5282654012fSReza Sabdar if (VERBOSE(ftp))
5292654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
5302654012fSReza Sabdar "CALLBACK(%s/%s): %d",
5312654012fSReza Sabdar pn.tn_path, en.tn_path, rv);
5322654012fSReza Sabdar
5332654012fSReza Sabdar if (rv != 0)
5342654012fSReza Sabdar break;
5352654012fSReza Sabdar }
5362654012fSReza Sabdar } while (rv == 0);
5372654012fSReza Sabdar
5382654012fSReza Sabdar /*
5392654012fSReza Sabdar * A new directory must be processed, go to the start of
5402654012fSReza Sabdar * the loop, open it and process it.
5412654012fSReza Sabdar */
5422654012fSReza Sabdar if (next_dir)
5432654012fSReza Sabdar continue;
5442654012fSReza Sabdar
5452654012fSReza Sabdar if (rv == SKIP_ENTRY)
5462654012fSReza Sabdar rv = 0; /* We should skip the current directory */
5472654012fSReza Sabdar
5482654012fSReza Sabdar if (rv == 0) {
5492654012fSReza Sabdar /*
5502654012fSReza Sabdar * Remove the ent from the end of path and send it
5512654012fSReza Sabdar * as an entry of the path.
5522654012fSReza Sabdar */
5532654012fSReza Sabdar lp = tsp->ts_ent;
5542654012fSReza Sabdar *lp = '\0';
5552654012fSReza Sabdar efh = tsp->ts_fh;
5562654012fSReza Sabdar est = tsp->ts_st;
5572654012fSReza Sabdar free(tsp);
5582654012fSReza Sabdar if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
5592654012fSReza Sabdar break;
5602654012fSReza Sabdar
5612654012fSReza Sabdar assert(tsp != NULL);
5622654012fSReza Sabdar pl = tsp->ts_end - path;
5632654012fSReza Sabdar
5642654012fSReza Sabdar if (VERBOSE(ftp))
5652654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "poped pl %d 0x%p \"%s\"",
5662654012fSReza Sabdar pl, tsp, path);
5672654012fSReza Sabdar
5682654012fSReza Sabdar traverse_stats.fss_pops++;
5692654012fSReza Sabdar traverse_stats.fss_dir_calls++;
5702654012fSReza Sabdar
5712654012fSReza Sabdar pn.tn_fh = &tsp->ts_fh;
5722654012fSReza Sabdar pn.tn_st = &tsp->ts_st;
5732654012fSReza Sabdar en.tn_path = lp + 1;
5742654012fSReza Sabdar en.tn_fh = &efh;
5752654012fSReza Sabdar en.tn_st = &est;
5762654012fSReza Sabdar
5772654012fSReza Sabdar rv = CALLBACK(&pn, &en);
57884bf06e9SReza Sabdar free(efh.fh_fpath);
5792654012fSReza Sabdar if (VERBOSE(ftp))
5802654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "CALLBACK(%s/%s): %d",
5812654012fSReza Sabdar pn.tn_path, en.tn_path, rv);
5822654012fSReza Sabdar /*
5832654012fSReza Sabdar * Does not need to free tsp here. It will be released
5842654012fSReza Sabdar * later.
5852654012fSReza Sabdar */
5862654012fSReza Sabdar }
5872654012fSReza Sabdar
58884bf06e9SReza Sabdar if (rv != 0 && tsp) {
58984bf06e9SReza Sabdar free(tsp->ts_fh.fh_fpath);
5902654012fSReza Sabdar free(tsp);
59184bf06e9SReza Sabdar }
5922654012fSReza Sabdar
5932654012fSReza Sabdar } while (rv == 0);
5942654012fSReza Sabdar
5952654012fSReza Sabdar /*
5962654012fSReza Sabdar * For the 'ftp->ft_path' directory itself.
5972654012fSReza Sabdar */
5982654012fSReza Sabdar if (rv == 0) {
5992654012fSReza Sabdar traverse_stats.fss_dir_calls++;
6002654012fSReza Sabdar
6012654012fSReza Sabdar pn.tn_fh = &efh;
6022654012fSReza Sabdar pn.tn_st = &est;
6032654012fSReza Sabdar en.tn_path = NULL;
6042654012fSReza Sabdar en.tn_fh = NULL;
6052654012fSReza Sabdar en.tn_st = NULL;
6062654012fSReza Sabdar rv = CALLBACK(&pn, &en);
6072654012fSReza Sabdar if (VERBOSE(ftp))
6082654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
6092654012fSReza Sabdar }
6102654012fSReza Sabdar
6112654012fSReza Sabdar /*
6122654012fSReza Sabdar * Pop and free all the remaining entries on the stack.
6132654012fSReza Sabdar */
6142654012fSReza Sabdar while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
6152654012fSReza Sabdar traverse_stats.fss_stack_residue++;
6162654012fSReza Sabdar
61784bf06e9SReza Sabdar free(tsp->ts_fh.fh_fpath);
6182654012fSReza Sabdar free(tsp);
6192654012fSReza Sabdar }
6202654012fSReza Sabdar
6212654012fSReza Sabdar cstack_delete(sp);
6222654012fSReza Sabdar return (rv);
6232654012fSReza Sabdar }
6242654012fSReza Sabdar
6252654012fSReza Sabdar /*
6262654012fSReza Sabdar * In one pass, read all the directory entries of the specified
6272654012fSReza Sabdar * directory and call the callback function for non-directory
6282654012fSReza Sabdar * entries.
6292654012fSReza Sabdar *
6302654012fSReza Sabdar * On return:
6312654012fSReza Sabdar * 0: Lets the directory to be scanned for directory entries.
6322654012fSReza Sabdar * < 0: Completely stops traversing.
6332654012fSReza Sabdar * FST_SKIP: stops further scanning of the directory. Traversing
6342654012fSReza Sabdar * will continue with the next directory in the hierarchy.
6352654012fSReza Sabdar * SKIP_ENTRY: Failed to get the directory entries, so the caller
6362654012fSReza Sabdar * should skip this entry.
6372654012fSReza Sabdar */
6382654012fSReza Sabdar static int
traverse_level_nondir(struct fs_traverse * ftp,traverse_state_t * tsp,struct fst_node * pnp,dent_arg_t * darg)6392654012fSReza Sabdar traverse_level_nondir(struct fs_traverse *ftp,
6402654012fSReza Sabdar traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
6412654012fSReza Sabdar {
64284bf06e9SReza Sabdar int pl; /* path length */
6432654012fSReza Sabdar int rv;
6442654012fSReza Sabdar struct fst_node en; /* entry node */
6452654012fSReza Sabdar longlong_t cookie_verf;
6462654012fSReza Sabdar fs_dent_info_t *dent;
6472654012fSReza Sabdar struct dirent *buf;
6482654012fSReza Sabdar size_t len = 0;
6492654012fSReza Sabdar int fd;
6502654012fSReza Sabdar
6512654012fSReza Sabdar rv = 0;
6522654012fSReza Sabdar pl = strlen(pnp->tn_path);
6532654012fSReza Sabdar
6542654012fSReza Sabdar buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
6552654012fSReza Sabdar if (buf == NULL)
6562654012fSReza Sabdar return (errno);
6572654012fSReza Sabdar
6582654012fSReza Sabdar fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
6592654012fSReza Sabdar if (fd == -1) {
6602654012fSReza Sabdar free(buf);
6612654012fSReza Sabdar return (errno);
6622654012fSReza Sabdar }
6632654012fSReza Sabdar
6642654012fSReza Sabdar while (rv == 0) {
6652654012fSReza Sabdar long i, n_entries;
6662654012fSReza Sabdar
6672654012fSReza Sabdar darg->da_end = 0;
6682654012fSReza Sabdar n_entries = 0;
6692654012fSReza Sabdar rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
67084bf06e9SReza Sabdar &cookie_verf, &n_entries, darg);
6715a3c8170SReza Sabdar if (rv < 0) {
6722654012fSReza Sabdar traverse_stats.fss_readdir_err++;
6732654012fSReza Sabdar
6742654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
6752654012fSReza Sabdar rv, pnp->tn_path, tsp->ts_dpos);
676*65451a03SReza Sabdar if (STOP_ONERR(ftp))
6772654012fSReza Sabdar break;
6782654012fSReza Sabdar /*
6792654012fSReza Sabdar * We cannot read the directory entry, we should
6802654012fSReza Sabdar * skip to the next directory.
6812654012fSReza Sabdar */
6822654012fSReza Sabdar rv = SKIP_ENTRY;
6832654012fSReza Sabdar continue;
6845a3c8170SReza Sabdar } else {
6855a3c8170SReza Sabdar /* Break at the end of directory */
6865a3c8170SReza Sabdar if (rv > 0)
6875a3c8170SReza Sabdar rv = 0;
6885a3c8170SReza Sabdar else
6895a3c8170SReza Sabdar break;
6902654012fSReza Sabdar }
6912654012fSReza Sabdar
6922654012fSReza Sabdar /* LINTED imporper alignment */
6932654012fSReza Sabdar dent = (fs_dent_info_t *)darg->da_buf;
6942654012fSReza Sabdar /* LINTED imporper alignment */
6952654012fSReza Sabdar for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
6962654012fSReza Sabdar ((char *)dent + dent->fd_len)) {
6972654012fSReza Sabdar
6982654012fSReza Sabdar if (VERBOSE(ftp))
6992654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
7002654012fSReza Sabdar dent->fd_fh.fh_fid, dent->fd_name);
7012654012fSReza Sabdar
7022654012fSReza Sabdar if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
7032654012fSReza Sabdar traverse_stats.fss_longpath_err++;
7042654012fSReza Sabdar
7052654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
7062654012fSReza Sabdar pnp->tn_path, dent->fd_name);
7072654012fSReza Sabdar if (STOP_ONLONG(ftp))
7082654012fSReza Sabdar rv = -ENAMETOOLONG;
70984bf06e9SReza Sabdar free(dent->fd_fh.fh_fpath);
7102654012fSReza Sabdar continue;
7112654012fSReza Sabdar }
7122654012fSReza Sabdar
7132654012fSReza Sabdar /*
7142654012fSReza Sabdar * The entry is not a directory so the callback
7152654012fSReza Sabdar * function must be called.
7162654012fSReza Sabdar */
7172654012fSReza Sabdar if (!S_ISDIR(dent->fd_attr.st_mode)) {
7182654012fSReza Sabdar traverse_stats.fss_nondir_calls++;
7192654012fSReza Sabdar
7202654012fSReza Sabdar en.tn_path = dent->fd_name;
7212654012fSReza Sabdar en.tn_fh = &dent->fd_fh;
7222654012fSReza Sabdar en.tn_st = &dent->fd_attr;
7232654012fSReza Sabdar rv = CALLBACK(pnp, &en);
7242654012fSReza Sabdar dent->fd_fh.fh_fpath = NULL;
7252654012fSReza Sabdar if (rv < 0)
7262654012fSReza Sabdar break;
7272654012fSReza Sabdar if (rv == FST_SKIP) {
7282654012fSReza Sabdar traverse_stats.fss_nondir_skipped++;
7292654012fSReza Sabdar break;
7302654012fSReza Sabdar }
7312654012fSReza Sabdar }
7322654012fSReza Sabdar }
7332654012fSReza Sabdar }
7342654012fSReza Sabdar
7352654012fSReza Sabdar free(buf);
7362654012fSReza Sabdar (void) close(fd);
7372654012fSReza Sabdar return (rv);
7382654012fSReza Sabdar }
7392654012fSReza Sabdar
7402654012fSReza Sabdar /*
7412654012fSReza Sabdar * Traverse the file system in the level-order way. The description
7422654012fSReza Sabdar * and example is in the header file.
7432654012fSReza Sabdar */
7442654012fSReza Sabdar int
traverse_level(struct fs_traverse * ftp)7452654012fSReza Sabdar traverse_level(struct fs_traverse *ftp)
7462654012fSReza Sabdar {
7472654012fSReza Sabdar char path[PATH_MAX + 1]; /* full path name of the current dir */
7482654012fSReza Sabdar char nm[NAME_MAX + 1]; /* directory entry name */
7492654012fSReza Sabdar char *lp; /* last position on the path */
7502654012fSReza Sabdar int next_dir, rv;
7512654012fSReza Sabdar int pl, el; /* path and directory entry length */
7522654012fSReza Sabdar
7532654012fSReza Sabdar cstack_t *sp;
7542654012fSReza Sabdar fs_fhandle_t pfh, efh;
7552654012fSReza Sabdar struct stat64 pst, est;
7562654012fSReza Sabdar traverse_state_t *tsp;
7572654012fSReza Sabdar struct fst_node pn, en; /* parent and entry nodes */
7582654012fSReza Sabdar dent_arg_t darg;
7592654012fSReza Sabdar
7602654012fSReza Sabdar if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
7612654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Invalid argument");
7622654012fSReza Sabdar errno = EINVAL;
7632654012fSReza Sabdar return (-1);
7642654012fSReza Sabdar }
7652654012fSReza Sabdar /* set the default log function if it's not already set */
7662654012fSReza Sabdar if (!ftp->ft_logfp) {
7672654012fSReza Sabdar ftp->ft_logfp = (ft_log_t)syslog;
7682654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
7692654012fSReza Sabdar }
7702654012fSReza Sabdar if (!ftp->ft_lpath) {
7712654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
7722654012fSReza Sabdar "report the same paths \"%s\"", ftp->ft_path);
7732654012fSReza Sabdar ftp->ft_lpath = ftp->ft_path;
7742654012fSReza Sabdar }
7752654012fSReza Sabdar
7762654012fSReza Sabdar pl = strlen(ftp->ft_lpath);
7772654012fSReza Sabdar if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
7782654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
7792654012fSReza Sabdar errno = ENAMETOOLONG;
7802654012fSReza Sabdar return (-1);
7812654012fSReza Sabdar }
7822654012fSReza Sabdar (void) strcpy(path, ftp->ft_lpath);
7832654012fSReza Sabdar (void) memset(&pfh, 0, sizeof (pfh));
78484bf06e9SReza Sabdar rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
7852654012fSReza Sabdar if (rv != 0) {
7862654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
7872654012fSReza Sabdar "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
7882654012fSReza Sabdar return (-1);
7892654012fSReza Sabdar }
7902654012fSReza Sabdar
7912654012fSReza Sabdar en.tn_path = NULL;
7922654012fSReza Sabdar en.tn_fh = NULL;
7932654012fSReza Sabdar en.tn_st = NULL;
7942654012fSReza Sabdar if (!S_ISDIR(pst.st_mode)) {
7952654012fSReza Sabdar pn.tn_path = ftp->ft_lpath;
7962654012fSReza Sabdar pn.tn_fh = &pfh;
7972654012fSReza Sabdar pn.tn_st = &pst;
7982654012fSReza Sabdar rv = CALLBACK(&pn, &en);
7992654012fSReza Sabdar if (VERBOSE(ftp))
8002654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
8012654012fSReza Sabdar
8022654012fSReza Sabdar free(pfh.fh_fpath);
8032654012fSReza Sabdar return (rv);
8042654012fSReza Sabdar }
8052654012fSReza Sabdar
8062654012fSReza Sabdar sp = cstack_new();
8072654012fSReza Sabdar if (!sp) {
8082654012fSReza Sabdar free(pfh.fh_fpath);
8092654012fSReza Sabdar errno = ENOMEM;
8102654012fSReza Sabdar return (-1);
8112654012fSReza Sabdar }
8122654012fSReza Sabdar tsp = new_tsp(path);
8132654012fSReza Sabdar if (!tsp) {
8142654012fSReza Sabdar cstack_delete(sp);
8152654012fSReza Sabdar free(pfh.fh_fpath);
8162654012fSReza Sabdar errno = ENOMEM;
8172654012fSReza Sabdar return (-1);
8182654012fSReza Sabdar }
8192654012fSReza Sabdar
8202654012fSReza Sabdar darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
8212654012fSReza Sabdar if (!darg.da_buf) {
8222654012fSReza Sabdar cstack_delete(sp);
8232654012fSReza Sabdar free(pfh.fh_fpath);
8242654012fSReza Sabdar free(tsp);
8252654012fSReza Sabdar errno = ENOMEM;
8262654012fSReza Sabdar return (-1);
8272654012fSReza Sabdar }
8282654012fSReza Sabdar darg.da_size = MAX_DENT_BUF_SIZE;
8292654012fSReza Sabdar
8302654012fSReza Sabdar tsp->ts_ent = tsp->ts_end;
8312654012fSReza Sabdar tsp->ts_fh = pfh;
8322654012fSReza Sabdar tsp->ts_st = pst;
8332654012fSReza Sabdar pn.tn_path = path;
8342654012fSReza Sabdar pn.tn_fh = &tsp->ts_fh;
8352654012fSReza Sabdar pn.tn_st = &tsp->ts_st;
8362654012fSReza Sabdar
8372654012fSReza Sabdar /* call the callback function on the path itself */
8382654012fSReza Sabdar traverse_stats.fss_dir_calls++;
8392654012fSReza Sabdar rv = CALLBACK(&pn, &en);
8402654012fSReza Sabdar if (rv < 0) {
8412654012fSReza Sabdar free(tsp);
8422654012fSReza Sabdar goto end;
8432654012fSReza Sabdar }
8442654012fSReza Sabdar if (rv == FST_SKIP) {
8452654012fSReza Sabdar traverse_stats.fss_dir_skipped++;
8462654012fSReza Sabdar free(tsp);
8472654012fSReza Sabdar rv = 0;
8482654012fSReza Sabdar goto end;
8492654012fSReza Sabdar }
8502654012fSReza Sabdar
8512654012fSReza Sabdar rv = 0;
8522654012fSReza Sabdar next_dir = 1;
8532654012fSReza Sabdar do {
8542654012fSReza Sabdar if (next_dir) {
8552654012fSReza Sabdar traverse_stats.fss_newdirs++;
8562654012fSReza Sabdar
8572654012fSReza Sabdar *tsp->ts_end = '\0';
8582654012fSReza Sabdar if (VERBOSE(ftp))
8592654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
8602654012fSReza Sabdar
8612654012fSReza Sabdar rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
8622654012fSReza Sabdar if (rv < 0) {
8632654012fSReza Sabdar NEGATE(rv);
86484bf06e9SReza Sabdar free(tsp->ts_fh.fh_fpath);
8652654012fSReza Sabdar free(tsp);
8662654012fSReza Sabdar break;
8672654012fSReza Sabdar }
8682654012fSReza Sabdar /*
8692654012fSReza Sabdar * If skipped by the callback function or
8702654012fSReza Sabdar * error happened reading the information
8712654012fSReza Sabdar */
8722654012fSReza Sabdar if (rv == FST_SKIP || rv == SKIP_ENTRY) {
8732654012fSReza Sabdar /*
8742654012fSReza Sabdar * N.B. next_dir should be set to 0 as
8752654012fSReza Sabdar * well. This prevents the infinite loop.
8762654012fSReza Sabdar * If it's not set the same directory will
8772654012fSReza Sabdar * be poped from the stack and will be
8782654012fSReza Sabdar * scanned again.
8792654012fSReza Sabdar */
8802654012fSReza Sabdar next_dir = 0;
8812654012fSReza Sabdar rv = 0;
8822654012fSReza Sabdar goto skip_dir;
8832654012fSReza Sabdar }
8842654012fSReza Sabdar
8852654012fSReza Sabdar /* re-start reading entries of the directory */
8862654012fSReza Sabdar tsp->ts_dpos = 0;
8872654012fSReza Sabdar }
8882654012fSReza Sabdar
8892654012fSReza Sabdar next_dir = 0;
8902654012fSReza Sabdar do {
8912654012fSReza Sabdar el = NAME_MAX;
8922654012fSReza Sabdar rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
8932654012fSReza Sabdar &tsp->ts_dpos, nm, &el, &efh,
89484bf06e9SReza Sabdar &est);
8952654012fSReza Sabdar if (rv != 0) {
8962654012fSReza Sabdar traverse_stats.fss_readdir_err++;
8972654012fSReza Sabdar
8982654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
8992654012fSReza Sabdar "Error %d on readdir(%s) pos %d",
9002654012fSReza Sabdar rv, path, tsp->ts_dpos);
9012654012fSReza Sabdar if (STOP_ONERR(ftp))
9022654012fSReza Sabdar break;
9032654012fSReza Sabdar rv = SKIP_ENTRY;
9042654012fSReza Sabdar continue;
9052654012fSReza Sabdar }
9062654012fSReza Sabdar
9072654012fSReza Sabdar /* done with this directory */
9082654012fSReza Sabdar if (el == 0)
9092654012fSReza Sabdar break;
9102654012fSReza Sabdar
9112654012fSReza Sabdar nm[el] = '\0';
9122654012fSReza Sabdar
9132654012fSReza Sabdar if (rootfs_dot_or_dotdot(nm)) {
91484bf06e9SReza Sabdar free(efh.fh_fpath);
9152654012fSReza Sabdar continue;
9162654012fSReza Sabdar }
9172654012fSReza Sabdar
9182654012fSReza Sabdar if (VERBOSE(ftp))
9192654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
9202654012fSReza Sabdar tsp->ts_dpos, nm);
9212654012fSReza Sabdar
9222654012fSReza Sabdar if (pl + 1 + el > PATH_MAX) {
9232654012fSReza Sabdar /*
9242654012fSReza Sabdar * The long paths were already encountered
9252654012fSReza Sabdar * when processing non-dir entries in.
9262654012fSReza Sabdar * traverse_level_nondir.
9272654012fSReza Sabdar * We don't increase fss_longpath_err
9282654012fSReza Sabdar * counter for them again here.
9292654012fSReza Sabdar */
9302654012fSReza Sabdar NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
9312654012fSReza Sabdar path, nm);
9322654012fSReza Sabdar if (STOP_ONLONG(ftp))
9332654012fSReza Sabdar rv = ENAMETOOLONG;
93484bf06e9SReza Sabdar free(efh.fh_fpath);
9352654012fSReza Sabdar continue;
9362654012fSReza Sabdar }
9372654012fSReza Sabdar
93884bf06e9SReza Sabdar if (!S_ISDIR(est.st_mode))
9392654012fSReza Sabdar continue;
9402654012fSReza Sabdar
9412654012fSReza Sabdar /*
9422654012fSReza Sabdar * Call the callback function for the new
9432654012fSReza Sabdar * directory found, then push the current
9442654012fSReza Sabdar * directory on to the stack. Then dive
9452654012fSReza Sabdar * into the entry found.
9462654012fSReza Sabdar */
9472654012fSReza Sabdar traverse_stats.fss_dir_calls++;
9482654012fSReza Sabdar en.tn_path = nm;
9492654012fSReza Sabdar en.tn_fh = &efh;
9502654012fSReza Sabdar en.tn_st = &est;
9512654012fSReza Sabdar rv = CALLBACK(&pn, &en);
9522654012fSReza Sabdar
9532654012fSReza Sabdar if (rv < 0) {
9542654012fSReza Sabdar NEGATE(rv);
95584bf06e9SReza Sabdar free(efh.fh_fpath);
9562654012fSReza Sabdar break;
9572654012fSReza Sabdar }
9582654012fSReza Sabdar if (rv == FST_SKIP) {
9592654012fSReza Sabdar traverse_stats.fss_dir_skipped++;
96084bf06e9SReza Sabdar free(efh.fh_fpath);
9612654012fSReza Sabdar rv = 0;
9622654012fSReza Sabdar continue;
9632654012fSReza Sabdar }
9642654012fSReza Sabdar
9652654012fSReza Sabdar /*
9662654012fSReza Sabdar * Push the current directory on to the stack and
9672654012fSReza Sabdar * dive into the entry found.
9682654012fSReza Sabdar */
96984bf06e9SReza Sabdar if (cstack_push(sp, tsp, 0)) {
9702654012fSReza Sabdar rv = ENOMEM;
97184bf06e9SReza Sabdar } else {
9722654012fSReza Sabdar traverse_stats.fss_pushes++;
9732654012fSReza Sabdar
9742654012fSReza Sabdar lp = tsp->ts_end;
9752654012fSReza Sabdar *tsp->ts_end = '/';
9762654012fSReza Sabdar (void) strcpy(tsp->ts_end + 1, nm);
9772654012fSReza Sabdar
9782654012fSReza Sabdar tsp = new_tsp(path);
9792654012fSReza Sabdar if (!tsp)
9802654012fSReza Sabdar rv = ENOMEM;
9812654012fSReza Sabdar else {
9822654012fSReza Sabdar next_dir = 1;
9832654012fSReza Sabdar pl += el + 1;
9842654012fSReza Sabdar tsp->ts_fh = efh;
9852654012fSReza Sabdar tsp->ts_st = est;
9862654012fSReza Sabdar tsp->ts_ent = lp;
9872654012fSReza Sabdar pn.tn_fh = &tsp->ts_fh;
9882654012fSReza Sabdar pn.tn_st = &tsp->ts_st;
9892654012fSReza Sabdar }
9902654012fSReza Sabdar }
9912654012fSReza Sabdar break;
9922654012fSReza Sabdar
9932654012fSReza Sabdar } while (rv == 0);
9942654012fSReza Sabdar
9952654012fSReza Sabdar /*
9962654012fSReza Sabdar * A new directory must be processed, go to the start of
9972654012fSReza Sabdar * the loop, open it and process it.
9982654012fSReza Sabdar */
9992654012fSReza Sabdar if (next_dir)
10002654012fSReza Sabdar continue;
10012654012fSReza Sabdar skip_dir:
100284bf06e9SReza Sabdar if (tsp) {
100384bf06e9SReza Sabdar free(tsp->ts_fh.fh_fpath);
10042654012fSReza Sabdar free(tsp);
100584bf06e9SReza Sabdar }
10062654012fSReza Sabdar
10072654012fSReza Sabdar if (rv == SKIP_ENTRY)
10082654012fSReza Sabdar rv = 0;
10092654012fSReza Sabdar
10102654012fSReza Sabdar if (rv == 0) {
10112654012fSReza Sabdar if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
10122654012fSReza Sabdar break;
10132654012fSReza Sabdar
10142654012fSReza Sabdar traverse_stats.fss_pops++;
10152654012fSReza Sabdar
10162654012fSReza Sabdar if (VERBOSE(ftp))
10172654012fSReza Sabdar NDMP_LOG(LOG_DEBUG,
10182654012fSReza Sabdar "Poped pl %d \"%s\"", pl, path);
10192654012fSReza Sabdar
10202654012fSReza Sabdar *tsp->ts_end = '\0';
10212654012fSReza Sabdar pl = tsp->ts_end - path;
10222654012fSReza Sabdar pn.tn_fh = &tsp->ts_fh;
10232654012fSReza Sabdar pn.tn_st = &tsp->ts_st;
10242654012fSReza Sabdar }
10252654012fSReza Sabdar } while (rv == 0);
10262654012fSReza Sabdar
10272654012fSReza Sabdar /*
10282654012fSReza Sabdar * Pop and free all the remaining entries on the stack.
10292654012fSReza Sabdar */
10302654012fSReza Sabdar while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
10312654012fSReza Sabdar traverse_stats.fss_stack_residue++;
10322654012fSReza Sabdar
103384bf06e9SReza Sabdar free(tsp->ts_fh.fh_fpath);
10342654012fSReza Sabdar free(tsp);
10352654012fSReza Sabdar }
10362654012fSReza Sabdar end:
10372654012fSReza Sabdar free(darg.da_buf);
10382654012fSReza Sabdar cstack_delete(sp);
10392654012fSReza Sabdar return (rv);
10402654012fSReza Sabdar }
10412654012fSReza Sabdar
10422654012fSReza Sabdar /*
10432654012fSReza Sabdar * filecopy - Copy a file
10442654012fSReza Sabdar *
10452654012fSReza Sabdar * Parameters:
10462654012fSReza Sabdar * char *dest - Destination path
10472654012fSReza Sabdar * char *src - Source path
10482654012fSReza Sabdar *
10492654012fSReza Sabdar * Returns:
10502654012fSReza Sabdar * 0 - No errors
10512654012fSReza Sabdar * #0 - Error occured
10522654012fSReza Sabdar * -4 - read/write error
10532654012fSReza Sabdar * -5 - source modified during copy
10542654012fSReza Sabdar *
10552654012fSReza Sabdar * Simplified version for Solaris
10562654012fSReza Sabdar */
10572654012fSReza Sabdar #define BUFSIZE 32768
10582654012fSReza Sabdar int
filecopy(char * dest,char * src)10592654012fSReza Sabdar filecopy(char *dest, char *src)
10602654012fSReza Sabdar {
10612654012fSReza Sabdar FILE *src_fh = 0;
10622654012fSReza Sabdar FILE *dst_fh = 0;
10632654012fSReza Sabdar struct stat64 src_attr;
10642654012fSReza Sabdar struct stat64 dst_attr;
10652654012fSReza Sabdar char *buf = 0;
10662654012fSReza Sabdar u_longlong_t bytes_to_copy;
10672654012fSReza Sabdar size_t nbytes;
10682654012fSReza Sabdar int file_copied = 0;
10692654012fSReza Sabdar
10702654012fSReza Sabdar buf = ndmp_malloc(BUFSIZE);
10712654012fSReza Sabdar if (!buf)
10722654012fSReza Sabdar return (-1);
10732654012fSReza Sabdar
10742654012fSReza Sabdar src_fh = fopen(src, "r");
10752654012fSReza Sabdar if (src_fh == 0) {
10762654012fSReza Sabdar free(buf);
10772654012fSReza Sabdar return (-2);
10782654012fSReza Sabdar }
10792654012fSReza Sabdar
10802654012fSReza Sabdar dst_fh = fopen(dest, "w");
10812654012fSReza Sabdar if (dst_fh == NULL) {
10822654012fSReza Sabdar free(buf);
10832654012fSReza Sabdar (void) fclose(src_fh);
10842654012fSReza Sabdar return (-3);
10852654012fSReza Sabdar }
10862654012fSReza Sabdar
10872654012fSReza Sabdar if (stat64(src, &src_attr) < 0) {
10882654012fSReza Sabdar free(buf);
10892654012fSReza Sabdar (void) fclose(src_fh);
10902654012fSReza Sabdar (void) fclose(dst_fh);
10912654012fSReza Sabdar return (-2);
10922654012fSReza Sabdar }
10932654012fSReza Sabdar
10942654012fSReza Sabdar bytes_to_copy = src_attr.st_size;
10952654012fSReza Sabdar while (bytes_to_copy) {
10962654012fSReza Sabdar if (bytes_to_copy > BUFSIZE)
10972654012fSReza Sabdar nbytes = BUFSIZE;
10982654012fSReza Sabdar else
10992654012fSReza Sabdar nbytes = bytes_to_copy;
11002654012fSReza Sabdar
11012654012fSReza Sabdar if ((fread(buf, nbytes, 1, src_fh) != 1) ||
11022654012fSReza Sabdar (fwrite(buf, nbytes, 1, dst_fh) != 1))
11032654012fSReza Sabdar break;
11042654012fSReza Sabdar bytes_to_copy -= nbytes;
11052654012fSReza Sabdar }
11062654012fSReza Sabdar
11072654012fSReza Sabdar (void) fclose(src_fh);
11082654012fSReza Sabdar (void) fclose(dst_fh);
11092654012fSReza Sabdar
11102654012fSReza Sabdar if (bytes_to_copy > 0) {
11112654012fSReza Sabdar free(buf);
11122654012fSReza Sabdar /* short read/write, remove the partial file */
11132654012fSReza Sabdar return (-4);
11142654012fSReza Sabdar }
11152654012fSReza Sabdar
11162654012fSReza Sabdar if (stat64(src, &dst_attr) < 0) {
11172654012fSReza Sabdar free(buf);
11182654012fSReza Sabdar return (-2);
11192654012fSReza Sabdar }
11202654012fSReza Sabdar
11212654012fSReza Sabdar free(buf);
11222654012fSReza Sabdar
11232654012fSReza Sabdar if (!file_copied)
11242654012fSReza Sabdar return (-5); /* source modified during copy */
11252654012fSReza Sabdar else
11262654012fSReza Sabdar return (0);
11272654012fSReza Sabdar }
1128