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