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