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 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 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 * 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 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 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 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 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 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 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 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