17917SReza.Sabdar@Sun.COM /* 2*9012SReza.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 * Initialize a list for path names 2027917SReza.Sabdar@Sun.COM */ 2037917SReza.Sabdar@Sun.COM path_list_t * 2047917SReza.Sabdar@Sun.COM fs_init_pathlist() 2057917SReza.Sabdar@Sun.COM { 2067917SReza.Sabdar@Sun.COM path_list_t *pl_head; 2077917SReza.Sabdar@Sun.COM 2087917SReza.Sabdar@Sun.COM pl_head = ndmp_malloc(sizeof (path_list_t)); 2097917SReza.Sabdar@Sun.COM return (pl_head); 2107917SReza.Sabdar@Sun.COM } 2117917SReza.Sabdar@Sun.COM 2127917SReza.Sabdar@Sun.COM /* 2137917SReza.Sabdar@Sun.COM * Free the list of path names 2147917SReza.Sabdar@Sun.COM */ 2157917SReza.Sabdar@Sun.COM void 2167917SReza.Sabdar@Sun.COM fs_free_pathlist(path_list_t *pl_head) 2177917SReza.Sabdar@Sun.COM { 2187917SReza.Sabdar@Sun.COM path_list_t *p = pl_head; 2197917SReza.Sabdar@Sun.COM 2207917SReza.Sabdar@Sun.COM while (p) { 2217917SReza.Sabdar@Sun.COM p = pl_head->pl_next; 2227917SReza.Sabdar@Sun.COM free(pl_head->pl_path); 2237917SReza.Sabdar@Sun.COM free(pl_head); 2247917SReza.Sabdar@Sun.COM pl_head = p; 2257917SReza.Sabdar@Sun.COM } 2267917SReza.Sabdar@Sun.COM } 2277917SReza.Sabdar@Sun.COM 2287917SReza.Sabdar@Sun.COM /* 2297917SReza.Sabdar@Sun.COM * Add a path in the list of path names 2307917SReza.Sabdar@Sun.COM */ 2317917SReza.Sabdar@Sun.COM char * 2327917SReza.Sabdar@Sun.COM fs_add_pathlist(char *path, path_list_t **pp) 2337917SReza.Sabdar@Sun.COM { 2347917SReza.Sabdar@Sun.COM char *tpath; 2357917SReza.Sabdar@Sun.COM 2367917SReza.Sabdar@Sun.COM if (*pp) { 2377917SReza.Sabdar@Sun.COM (*pp)->pl_path = strdup(path); 2387917SReza.Sabdar@Sun.COM if ((*pp)->pl_path == NULL) 2397917SReza.Sabdar@Sun.COM return (NULL); 2407917SReza.Sabdar@Sun.COM tpath = (*pp)->pl_path; 2417917SReza.Sabdar@Sun.COM (*pp)->pl_next = ndmp_malloc(sizeof (path_list_t)); 2427917SReza.Sabdar@Sun.COM if ((*pp)->pl_next == NULL) 2437917SReza.Sabdar@Sun.COM return (NULL); 2447917SReza.Sabdar@Sun.COM *pp = (*pp)->pl_next; 2457917SReza.Sabdar@Sun.COM (*pp)->pl_path = NULL; 2467917SReza.Sabdar@Sun.COM (*pp)->pl_next = NULL; 2477917SReza.Sabdar@Sun.COM return (tpath); 2487917SReza.Sabdar@Sun.COM } 2497917SReza.Sabdar@Sun.COM return (NULL); 2507917SReza.Sabdar@Sun.COM } 2517917SReza.Sabdar@Sun.COM 2527917SReza.Sabdar@Sun.COM /* 2537917SReza.Sabdar@Sun.COM * Create a file handle and get stats for the given path 2547917SReza.Sabdar@Sun.COM */ 2557917SReza.Sabdar@Sun.COM int 2567917SReza.Sabdar@Sun.COM fs_getstat(char *path, fs_fhandle_t *fh, struct stat64 *st, path_list_t **pl) 2577917SReza.Sabdar@Sun.COM { 2587917SReza.Sabdar@Sun.COM if (lstat64(path, st) == -1) 2597917SReza.Sabdar@Sun.COM return (errno); 2607917SReza.Sabdar@Sun.COM 2617917SReza.Sabdar@Sun.COM fh->fh_fid = st->st_ino; 262*9012SReza.Sabdar@Sun.COM 263*9012SReza.Sabdar@Sun.COM if (!S_ISDIR(st->st_mode)) { 264*9012SReza.Sabdar@Sun.COM fh->fh_fpath = NULL; 265*9012SReza.Sabdar@Sun.COM return (0); 266*9012SReza.Sabdar@Sun.COM } 267*9012SReza.Sabdar@Sun.COM 2687917SReza.Sabdar@Sun.COM if (pl) 2697917SReza.Sabdar@Sun.COM fh->fh_fpath = fs_add_pathlist(path, pl); 2707917SReza.Sabdar@Sun.COM else 2717917SReza.Sabdar@Sun.COM fh->fh_fpath = strdup(path); 2727917SReza.Sabdar@Sun.COM return (0); 2737917SReza.Sabdar@Sun.COM } 2747917SReza.Sabdar@Sun.COM 2757917SReza.Sabdar@Sun.COM /* 2767917SReza.Sabdar@Sun.COM * Get directory entries info and return in the buffer. Cookie 2777917SReza.Sabdar@Sun.COM * will keep the state of each call 2787917SReza.Sabdar@Sun.COM */ 2797917SReza.Sabdar@Sun.COM static int 2807917SReza.Sabdar@Sun.COM fs_getdents(int fildes, struct dirent *buf, size_t *nbyte, 2817917SReza.Sabdar@Sun.COM char *pn_path, long *dpos, longlong_t *cookie, 2827917SReza.Sabdar@Sun.COM long *n_entries, dent_arg_t *darg, path_list_t **pl) 2837917SReza.Sabdar@Sun.COM { 2847917SReza.Sabdar@Sun.COM struct dirent *ptr; 2857917SReza.Sabdar@Sun.COM char file_path[PATH_MAX + 1]; 2867917SReza.Sabdar@Sun.COM fs_fhandle_t fh; 2877917SReza.Sabdar@Sun.COM struct stat64 st; 2887917SReza.Sabdar@Sun.COM char *p; 2897917SReza.Sabdar@Sun.COM int len; 2907917SReza.Sabdar@Sun.COM int rv; 2917917SReza.Sabdar@Sun.COM 2927917SReza.Sabdar@Sun.COM if (*nbyte == 0) { 2937917SReza.Sabdar@Sun.COM (void) memset((char *)buf, 0, MAX_DENT_BUF_SIZE); 2947917SReza.Sabdar@Sun.COM *nbyte = rv = getdents(fildes, buf, darg->da_size); 2957917SReza.Sabdar@Sun.COM *cookie = 0LL; 2967917SReza.Sabdar@Sun.COM 2977917SReza.Sabdar@Sun.COM if (rv <= 0) 2987917SReza.Sabdar@Sun.COM return (rv); 2997917SReza.Sabdar@Sun.COM } 3007917SReza.Sabdar@Sun.COM 3017917SReza.Sabdar@Sun.COM p = (char *)buf + *cookie; 3027917SReza.Sabdar@Sun.COM len = *nbyte; 3037917SReza.Sabdar@Sun.COM do { 3047917SReza.Sabdar@Sun.COM /* LINTED improper alignment */ 3057917SReza.Sabdar@Sun.COM ptr = (struct dirent *)p; 3067917SReza.Sabdar@Sun.COM *dpos = ptr->d_off; 3077917SReza.Sabdar@Sun.COM (void) snprintf(file_path, PATH_MAX, "%s/", pn_path); 3087917SReza.Sabdar@Sun.COM (void) strlcat(file_path, ptr->d_name, PATH_MAX); 3097917SReza.Sabdar@Sun.COM (void) memset(&fh, 0, sizeof (fs_fhandle_t)); 3107917SReza.Sabdar@Sun.COM 3117917SReza.Sabdar@Sun.COM rv = fs_getstat(file_path, &fh, &st, pl); 3127917SReza.Sabdar@Sun.COM if (rv != 0) 3137917SReza.Sabdar@Sun.COM break; 3147917SReza.Sabdar@Sun.COM 3157917SReza.Sabdar@Sun.COM rv = fs_populate_dents(darg, strlen(ptr->d_name), 3167917SReza.Sabdar@Sun.COM (char *)ptr->d_name, n_entries, &st, &fh); 3177917SReza.Sabdar@Sun.COM 3187917SReza.Sabdar@Sun.COM if (rv != 0) { 3197917SReza.Sabdar@Sun.COM rv = 0; 3207917SReza.Sabdar@Sun.COM break; 3217917SReza.Sabdar@Sun.COM } 3227917SReza.Sabdar@Sun.COM 3237917SReza.Sabdar@Sun.COM p = p + ptr->d_reclen; 3247917SReza.Sabdar@Sun.COM len -= ptr->d_reclen; 3257917SReza.Sabdar@Sun.COM } while (len); 3267917SReza.Sabdar@Sun.COM 3277917SReza.Sabdar@Sun.COM *cookie = (longlong_t)(p - (char *)buf); 3287917SReza.Sabdar@Sun.COM *nbyte = len; 3297917SReza.Sabdar@Sun.COM return (rv); 3307917SReza.Sabdar@Sun.COM } 3317917SReza.Sabdar@Sun.COM 3327917SReza.Sabdar@Sun.COM /* 3337917SReza.Sabdar@Sun.COM * Read the directory entries and return the information about 3347917SReza.Sabdar@Sun.COM * each entry 3357917SReza.Sabdar@Sun.COM */ 3367917SReza.Sabdar@Sun.COM int 3377917SReza.Sabdar@Sun.COM fs_readdir(fs_fhandle_t *ts_fh, char *path, long *dpos, 3387917SReza.Sabdar@Sun.COM char *nm, int *el, fs_fhandle_t *efh, struct stat64 *est, 3397917SReza.Sabdar@Sun.COM path_list_t **pl) 3407917SReza.Sabdar@Sun.COM { 3417917SReza.Sabdar@Sun.COM struct dirent *dp; 3427917SReza.Sabdar@Sun.COM char file_path[PATH_MAX + 1]; 3437917SReza.Sabdar@Sun.COM DIR *dirp; 3447917SReza.Sabdar@Sun.COM int rv; 3457917SReza.Sabdar@Sun.COM 3467917SReza.Sabdar@Sun.COM if ((dirp = opendir(ts_fh->fh_fpath)) == NULL) 3477917SReza.Sabdar@Sun.COM return (errno); 3487917SReza.Sabdar@Sun.COM 3497917SReza.Sabdar@Sun.COM seekdir(dirp, *dpos); 3507917SReza.Sabdar@Sun.COM if ((dp = readdir(dirp)) == NULL) { 3517917SReza.Sabdar@Sun.COM rv = 0; /* skip this dir */ 3527917SReza.Sabdar@Sun.COM *el = 0; 3537917SReza.Sabdar@Sun.COM } else { 3547917SReza.Sabdar@Sun.COM (void) snprintf(file_path, PATH_MAX, "%s/", path); 3557917SReza.Sabdar@Sun.COM (void) strlcat(file_path, dp->d_name, PATH_MAX); 3567917SReza.Sabdar@Sun.COM 3577917SReza.Sabdar@Sun.COM rv = fs_getstat(file_path, efh, est, pl); 3587917SReza.Sabdar@Sun.COM if (rv == 0) { 3597917SReza.Sabdar@Sun.COM *dpos = telldir(dirp); 3607917SReza.Sabdar@Sun.COM (void) strlcpy(nm, dp->d_name, NAME_MAX); 3617917SReza.Sabdar@Sun.COM *el = strlen(dp->d_name); 3627917SReza.Sabdar@Sun.COM } else { 3637917SReza.Sabdar@Sun.COM *el = 0; 3647917SReza.Sabdar@Sun.COM } 3657917SReza.Sabdar@Sun.COM } 3667917SReza.Sabdar@Sun.COM (void) closedir(dirp); 3677917SReza.Sabdar@Sun.COM return (rv); 3687917SReza.Sabdar@Sun.COM } 3697917SReza.Sabdar@Sun.COM 3707917SReza.Sabdar@Sun.COM /* 3717917SReza.Sabdar@Sun.COM * Traverse the file system in the post-order way. The description 3727917SReza.Sabdar@Sun.COM * and example is in the header file. 3737917SReza.Sabdar@Sun.COM * 3747917SReza.Sabdar@Sun.COM * The callback function should return 0, on success and non-zero on 3757917SReza.Sabdar@Sun.COM * failure. If the callback function returns non-zero return value, 3767917SReza.Sabdar@Sun.COM * the traversing stops. 3777917SReza.Sabdar@Sun.COM */ 3787917SReza.Sabdar@Sun.COM int 3797917SReza.Sabdar@Sun.COM traverse_post(struct fs_traverse *ftp) 3807917SReza.Sabdar@Sun.COM { 3817917SReza.Sabdar@Sun.COM char path[PATH_MAX + 1]; /* full path name of the current dir */ 3827917SReza.Sabdar@Sun.COM char nm[NAME_MAX + 1]; /* directory entry name */ 3837917SReza.Sabdar@Sun.COM char *lp; /* last position on the path */ 3847917SReza.Sabdar@Sun.COM int next_dir, rv; 3857917SReza.Sabdar@Sun.COM int pl, el; /* path and directory entry length */ 3867917SReza.Sabdar@Sun.COM cstack_t *sp; 3877917SReza.Sabdar@Sun.COM fs_fhandle_t pfh, efh; 3887917SReza.Sabdar@Sun.COM struct stat64 pst, est; 3897917SReza.Sabdar@Sun.COM traverse_state_t *tsp; 3907917SReza.Sabdar@Sun.COM struct fst_node pn, en; /* parent and entry nodes */ 3917917SReza.Sabdar@Sun.COM path_list_t *plhead, *plist; 3927917SReza.Sabdar@Sun.COM 3937917SReza.Sabdar@Sun.COM if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) { 3947917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument"); 3957917SReza.Sabdar@Sun.COM errno = EINVAL; 3967917SReza.Sabdar@Sun.COM return (-1); 3977917SReza.Sabdar@Sun.COM } 3987917SReza.Sabdar@Sun.COM 3997917SReza.Sabdar@Sun.COM /* set the default log function if it's not already set */ 4007917SReza.Sabdar@Sun.COM if (!ftp->ft_logfp) { 4017917SReza.Sabdar@Sun.COM ftp->ft_logfp = (ft_log_t)syslog; 4027917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path); 4037917SReza.Sabdar@Sun.COM } 4047917SReza.Sabdar@Sun.COM 4057917SReza.Sabdar@Sun.COM /* set the logical path to physical path if it's not already set */ 4067917SReza.Sabdar@Sun.COM if (!ftp->ft_lpath) { 4077917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 4087917SReza.Sabdar@Sun.COM "report the same paths: \"%s\"", ftp->ft_path); 4097917SReza.Sabdar@Sun.COM ftp->ft_lpath = ftp->ft_path; 4107917SReza.Sabdar@Sun.COM } 4117917SReza.Sabdar@Sun.COM 4127917SReza.Sabdar@Sun.COM pl = strlen(ftp->ft_lpath); 4137917SReza.Sabdar@Sun.COM if (pl + 1 > PATH_MAX) { /* +1 for the '/' */ 4147917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path); 4157917SReza.Sabdar@Sun.COM errno = ENAMETOOLONG; 4167917SReza.Sabdar@Sun.COM return (-1); 4177917SReza.Sabdar@Sun.COM } 4187917SReza.Sabdar@Sun.COM (void) strcpy(path, ftp->ft_lpath); 4197917SReza.Sabdar@Sun.COM (void) memset(&pfh, 0, sizeof (pfh)); 4207917SReza.Sabdar@Sun.COM rv = fs_getstat(ftp->ft_lpath, &pfh, &pst, NULL); 4217917SReza.Sabdar@Sun.COM 4227917SReza.Sabdar@Sun.COM if (rv != 0) { 4237917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 4247917SReza.Sabdar@Sun.COM "Error %d on fs_getstat(%s)", rv, ftp->ft_path); 4257917SReza.Sabdar@Sun.COM return (rv); 4267917SReza.Sabdar@Sun.COM } 4277917SReza.Sabdar@Sun.COM 4287917SReza.Sabdar@Sun.COM if (!S_ISDIR(pst.st_mode)) { 4297917SReza.Sabdar@Sun.COM pn.tn_path = ftp->ft_lpath; 4307917SReza.Sabdar@Sun.COM pn.tn_fh = &pfh; 4317917SReza.Sabdar@Sun.COM pn.tn_st = &pst; 4327917SReza.Sabdar@Sun.COM en.tn_path = NULL; 4337917SReza.Sabdar@Sun.COM en.tn_fh = NULL; 4347917SReza.Sabdar@Sun.COM en.tn_st = NULL; 4357917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en); 4367917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 4377917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv); 4387917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 4397917SReza.Sabdar@Sun.COM return (rv); 4407917SReza.Sabdar@Sun.COM } 4417917SReza.Sabdar@Sun.COM 4427917SReza.Sabdar@Sun.COM sp = cstack_new(); 4437917SReza.Sabdar@Sun.COM if (!sp) { 4447917SReza.Sabdar@Sun.COM errno = ENOMEM; 4457917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 4467917SReza.Sabdar@Sun.COM return (-1); 4477917SReza.Sabdar@Sun.COM } 4487917SReza.Sabdar@Sun.COM tsp = new_tsp(path); 4497917SReza.Sabdar@Sun.COM if (!tsp) { 4507917SReza.Sabdar@Sun.COM cstack_delete(sp); 4517917SReza.Sabdar@Sun.COM errno = ENOMEM; 4527917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 4537917SReza.Sabdar@Sun.COM return (-1); 4547917SReza.Sabdar@Sun.COM } 4557917SReza.Sabdar@Sun.COM tsp->ts_ent = tsp->ts_end; 4567917SReza.Sabdar@Sun.COM tsp->ts_fh = pfh; 4577917SReza.Sabdar@Sun.COM tsp->ts_st = pst; 4587917SReza.Sabdar@Sun.COM pn.tn_path = path; 4597917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh; 4607917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st; 4617917SReza.Sabdar@Sun.COM 4627917SReza.Sabdar@Sun.COM if ((plist = fs_init_pathlist()) == NULL) { 4637917SReza.Sabdar@Sun.COM errno = ENOMEM; 4647917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 4657917SReza.Sabdar@Sun.COM return (-1); 4667917SReza.Sabdar@Sun.COM } 4677917SReza.Sabdar@Sun.COM plhead = plist; 4687917SReza.Sabdar@Sun.COM 4697917SReza.Sabdar@Sun.COM rv = 0; 4707917SReza.Sabdar@Sun.COM next_dir = 1; 4717917SReza.Sabdar@Sun.COM do { 4727917SReza.Sabdar@Sun.COM if (next_dir) { 4737917SReza.Sabdar@Sun.COM traverse_stats.fss_newdirs++; 4747917SReza.Sabdar@Sun.COM 4757917SReza.Sabdar@Sun.COM *tsp->ts_end = '\0'; 4767917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 4777917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path); 4787917SReza.Sabdar@Sun.COM } 4797917SReza.Sabdar@Sun.COM 4807917SReza.Sabdar@Sun.COM next_dir = 0; 4817917SReza.Sabdar@Sun.COM do { 4827917SReza.Sabdar@Sun.COM el = NAME_MAX; 4837917SReza.Sabdar@Sun.COM rv = fs_readdir(&tsp->ts_fh, pn.tn_path, 4847917SReza.Sabdar@Sun.COM &tsp->ts_dpos, nm, &el, 4857917SReza.Sabdar@Sun.COM &efh, &est, &plist); 4867917SReza.Sabdar@Sun.COM 4877917SReza.Sabdar@Sun.COM if (rv != 0) { 4887917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 4897917SReza.Sabdar@Sun.COM traverse_stats.fss_readdir_err++; 4907917SReza.Sabdar@Sun.COM 4917917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 4927917SReza.Sabdar@Sun.COM "Error %d on readdir(%s) pos %d", 4937917SReza.Sabdar@Sun.COM rv, path, tsp->ts_dpos); 4947917SReza.Sabdar@Sun.COM if (STOP_ONERR(ftp)) 4957917SReza.Sabdar@Sun.COM break; 4967917SReza.Sabdar@Sun.COM rv = SKIP_ENTRY; 4977917SReza.Sabdar@Sun.COM 4987917SReza.Sabdar@Sun.COM continue; 4997917SReza.Sabdar@Sun.COM } 5007917SReza.Sabdar@Sun.COM 5017917SReza.Sabdar@Sun.COM /* done with this directory */ 5027917SReza.Sabdar@Sun.COM if (el == 0) { 5037917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 5047917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 5057917SReza.Sabdar@Sun.COM "Done(%s)", pn.tn_path); 5067917SReza.Sabdar@Sun.COM break; 5077917SReza.Sabdar@Sun.COM } 5087917SReza.Sabdar@Sun.COM nm[el] = '\0'; 5097917SReza.Sabdar@Sun.COM 5107917SReza.Sabdar@Sun.COM if (rootfs_dot_or_dotdot(nm)) { 5117917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 5127917SReza.Sabdar@Sun.COM continue; 5137917SReza.Sabdar@Sun.COM } 5147917SReza.Sabdar@Sun.COM 5157917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 5167917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"", 5177917SReza.Sabdar@Sun.COM tsp->ts_dpos, nm); 5187917SReza.Sabdar@Sun.COM 5197917SReza.Sabdar@Sun.COM if (pl + 1 + el > PATH_MAX) { 5207917SReza.Sabdar@Sun.COM traverse_stats.fss_longpath_err++; 5217917SReza.Sabdar@Sun.COM 5227917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Path %s/%s is too long.", 5237917SReza.Sabdar@Sun.COM path, nm); 5247917SReza.Sabdar@Sun.COM if (STOP_ONLONG(ftp)) 5257917SReza.Sabdar@Sun.COM rv = ENAMETOOLONG; 5267917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 5277917SReza.Sabdar@Sun.COM continue; 5287917SReza.Sabdar@Sun.COM } 5297917SReza.Sabdar@Sun.COM 5307917SReza.Sabdar@Sun.COM /* 5317917SReza.Sabdar@Sun.COM * Push the current directory on to the stack and 5327917SReza.Sabdar@Sun.COM * dive into the entry found. 5337917SReza.Sabdar@Sun.COM */ 5347917SReza.Sabdar@Sun.COM if (S_ISDIR(est.st_mode)) { 5357917SReza.Sabdar@Sun.COM 5367917SReza.Sabdar@Sun.COM assert(tsp != NULL); 5377917SReza.Sabdar@Sun.COM if (cstack_push(sp, tsp, 0)) { 5387917SReza.Sabdar@Sun.COM rv = ENOMEM; 5397917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 5407917SReza.Sabdar@Sun.COM break; 5417917SReza.Sabdar@Sun.COM } 5427917SReza.Sabdar@Sun.COM traverse_stats.fss_pushes++; 5437917SReza.Sabdar@Sun.COM 5447917SReza.Sabdar@Sun.COM /* 5457917SReza.Sabdar@Sun.COM * Concatenate the current entry with the 5467917SReza.Sabdar@Sun.COM * current path. This will be the path of 5477917SReza.Sabdar@Sun.COM * the new directory to be scanned. 5487917SReza.Sabdar@Sun.COM * 5497917SReza.Sabdar@Sun.COM * Note: 5507917SReza.Sabdar@Sun.COM * sprintf(tsp->ts_end, "/%s", de->d_name); 5517917SReza.Sabdar@Sun.COM * could be used here, but concatenating 5527917SReza.Sabdar@Sun.COM * strings like this might be faster. 5537917SReza.Sabdar@Sun.COM * The length of the new path has been 5547917SReza.Sabdar@Sun.COM * checked above. So strcpy() can be 5557917SReza.Sabdar@Sun.COM * safe and should not lead to a buffer 5567917SReza.Sabdar@Sun.COM * over-run. 5577917SReza.Sabdar@Sun.COM */ 5587917SReza.Sabdar@Sun.COM lp = tsp->ts_end; 5597917SReza.Sabdar@Sun.COM *tsp->ts_end = '/'; 5607917SReza.Sabdar@Sun.COM (void) strcpy(tsp->ts_end + 1, nm); 5617917SReza.Sabdar@Sun.COM 5627917SReza.Sabdar@Sun.COM tsp = new_tsp(path); 5637917SReza.Sabdar@Sun.COM if (!tsp) { 5647917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 5657917SReza.Sabdar@Sun.COM rv = ENOMEM; 5667917SReza.Sabdar@Sun.COM } else { 5677917SReza.Sabdar@Sun.COM next_dir = 1; 5687917SReza.Sabdar@Sun.COM pl += el; 5697917SReza.Sabdar@Sun.COM tsp->ts_fh = efh; 5707917SReza.Sabdar@Sun.COM tsp->ts_st = est; 5717917SReza.Sabdar@Sun.COM tsp->ts_ent = lp; 5727917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh; 5737917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st; 5747917SReza.Sabdar@Sun.COM } 5757917SReza.Sabdar@Sun.COM break; 5767917SReza.Sabdar@Sun.COM } else { 5777917SReza.Sabdar@Sun.COM /* 5787917SReza.Sabdar@Sun.COM * The entry is not a directory so the 5797917SReza.Sabdar@Sun.COM * callback function must be called. 5807917SReza.Sabdar@Sun.COM */ 5817917SReza.Sabdar@Sun.COM traverse_stats.fss_nondir_calls++; 5827917SReza.Sabdar@Sun.COM 5837917SReza.Sabdar@Sun.COM en.tn_path = nm; 5847917SReza.Sabdar@Sun.COM en.tn_fh = &efh; 5857917SReza.Sabdar@Sun.COM en.tn_st = &est; 5867917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en); 5877917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 5887917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 5897917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 5907917SReza.Sabdar@Sun.COM "CALLBACK(%s/%s): %d", 5917917SReza.Sabdar@Sun.COM pn.tn_path, en.tn_path, rv); 5927917SReza.Sabdar@Sun.COM 5937917SReza.Sabdar@Sun.COM if (rv != 0) 5947917SReza.Sabdar@Sun.COM break; 5957917SReza.Sabdar@Sun.COM } 5967917SReza.Sabdar@Sun.COM } while (rv == 0); 5977917SReza.Sabdar@Sun.COM 5987917SReza.Sabdar@Sun.COM /* 5997917SReza.Sabdar@Sun.COM * A new directory must be processed, go to the start of 6007917SReza.Sabdar@Sun.COM * the loop, open it and process it. 6017917SReza.Sabdar@Sun.COM */ 6027917SReza.Sabdar@Sun.COM if (next_dir) 6037917SReza.Sabdar@Sun.COM continue; 6047917SReza.Sabdar@Sun.COM 6057917SReza.Sabdar@Sun.COM if (rv == SKIP_ENTRY) 6067917SReza.Sabdar@Sun.COM rv = 0; /* We should skip the current directory */ 6077917SReza.Sabdar@Sun.COM 6087917SReza.Sabdar@Sun.COM if (rv == 0) { 6097917SReza.Sabdar@Sun.COM /* 6107917SReza.Sabdar@Sun.COM * Remove the ent from the end of path and send it 6117917SReza.Sabdar@Sun.COM * as an entry of the path. 6127917SReza.Sabdar@Sun.COM */ 6137917SReza.Sabdar@Sun.COM lp = tsp->ts_ent; 6147917SReza.Sabdar@Sun.COM *lp = '\0'; 6157917SReza.Sabdar@Sun.COM efh = tsp->ts_fh; 6167917SReza.Sabdar@Sun.COM est = tsp->ts_st; 6177917SReza.Sabdar@Sun.COM free(tsp); 6187917SReza.Sabdar@Sun.COM if (cstack_pop(sp, (void **)&tsp, (int *)NULL)) 6197917SReza.Sabdar@Sun.COM break; 6207917SReza.Sabdar@Sun.COM 6217917SReza.Sabdar@Sun.COM assert(tsp != NULL); 6227917SReza.Sabdar@Sun.COM pl = tsp->ts_end - path; 6237917SReza.Sabdar@Sun.COM 6247917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 6257917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "poped pl %d 0x%p \"%s\"", 6267917SReza.Sabdar@Sun.COM pl, tsp, path); 6277917SReza.Sabdar@Sun.COM 6287917SReza.Sabdar@Sun.COM traverse_stats.fss_pops++; 6297917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++; 6307917SReza.Sabdar@Sun.COM 6317917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh; 6327917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st; 6337917SReza.Sabdar@Sun.COM en.tn_path = lp + 1; 6347917SReza.Sabdar@Sun.COM en.tn_fh = &efh; 6357917SReza.Sabdar@Sun.COM en.tn_st = &est; 6367917SReza.Sabdar@Sun.COM 6377917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en); 6387917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 6397917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 6407917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s/%s): %d", 6417917SReza.Sabdar@Sun.COM pn.tn_path, en.tn_path, rv); 6427917SReza.Sabdar@Sun.COM /* 6437917SReza.Sabdar@Sun.COM * Does not need to free tsp here. It will be released 6447917SReza.Sabdar@Sun.COM * later. 6457917SReza.Sabdar@Sun.COM */ 6467917SReza.Sabdar@Sun.COM } 6477917SReza.Sabdar@Sun.COM 6487917SReza.Sabdar@Sun.COM if (rv != 0 && tsp) 6497917SReza.Sabdar@Sun.COM free(tsp); 6507917SReza.Sabdar@Sun.COM 6517917SReza.Sabdar@Sun.COM } while (rv == 0); 6527917SReza.Sabdar@Sun.COM 6537917SReza.Sabdar@Sun.COM /* 6547917SReza.Sabdar@Sun.COM * For the 'ftp->ft_path' directory itself. 6557917SReza.Sabdar@Sun.COM */ 6567917SReza.Sabdar@Sun.COM if (rv == 0) { 6577917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++; 6587917SReza.Sabdar@Sun.COM 6597917SReza.Sabdar@Sun.COM pn.tn_fh = &efh; 6607917SReza.Sabdar@Sun.COM pn.tn_st = &est; 6617917SReza.Sabdar@Sun.COM en.tn_path = NULL; 6627917SReza.Sabdar@Sun.COM en.tn_fh = NULL; 6637917SReza.Sabdar@Sun.COM en.tn_st = NULL; 6647917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en); 6657917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 6667917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv); 6677917SReza.Sabdar@Sun.COM } 6687917SReza.Sabdar@Sun.COM 6697917SReza.Sabdar@Sun.COM /* 6707917SReza.Sabdar@Sun.COM * Pop and free all the remaining entries on the stack. 6717917SReza.Sabdar@Sun.COM */ 6727917SReza.Sabdar@Sun.COM while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) { 6737917SReza.Sabdar@Sun.COM traverse_stats.fss_stack_residue++; 6747917SReza.Sabdar@Sun.COM 6757917SReza.Sabdar@Sun.COM free(tsp); 6767917SReza.Sabdar@Sun.COM } 6777917SReza.Sabdar@Sun.COM 6787917SReza.Sabdar@Sun.COM fs_free_pathlist(plhead); 6797917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 6807917SReza.Sabdar@Sun.COM cstack_delete(sp); 6817917SReza.Sabdar@Sun.COM return (rv); 6827917SReza.Sabdar@Sun.COM } 6837917SReza.Sabdar@Sun.COM 6847917SReza.Sabdar@Sun.COM /* 6857917SReza.Sabdar@Sun.COM * In one pass, read all the directory entries of the specified 6867917SReza.Sabdar@Sun.COM * directory and call the callback function for non-directory 6877917SReza.Sabdar@Sun.COM * entries. 6887917SReza.Sabdar@Sun.COM * 6897917SReza.Sabdar@Sun.COM * On return: 6907917SReza.Sabdar@Sun.COM * 0: Lets the directory to be scanned for directory entries. 6917917SReza.Sabdar@Sun.COM * < 0: Completely stops traversing. 6927917SReza.Sabdar@Sun.COM * FST_SKIP: stops further scanning of the directory. Traversing 6937917SReza.Sabdar@Sun.COM * will continue with the next directory in the hierarchy. 6947917SReza.Sabdar@Sun.COM * SKIP_ENTRY: Failed to get the directory entries, so the caller 6957917SReza.Sabdar@Sun.COM * should skip this entry. 6967917SReza.Sabdar@Sun.COM */ 6977917SReza.Sabdar@Sun.COM static int 6987917SReza.Sabdar@Sun.COM traverse_level_nondir(struct fs_traverse *ftp, 6997917SReza.Sabdar@Sun.COM traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg) 7007917SReza.Sabdar@Sun.COM { 7017917SReza.Sabdar@Sun.COM int pl; /* patth length */ 7027917SReza.Sabdar@Sun.COM int rv; 7037917SReza.Sabdar@Sun.COM struct fst_node en; /* entry node */ 7047917SReza.Sabdar@Sun.COM longlong_t cookie_verf; 7057917SReza.Sabdar@Sun.COM fs_dent_info_t *dent; 7067917SReza.Sabdar@Sun.COM struct dirent *buf; 7077917SReza.Sabdar@Sun.COM size_t len = 0; 7087917SReza.Sabdar@Sun.COM path_list_t *plhead, *plist; 7097917SReza.Sabdar@Sun.COM int fd; 7107917SReza.Sabdar@Sun.COM 7117917SReza.Sabdar@Sun.COM rv = 0; 7127917SReza.Sabdar@Sun.COM pl = strlen(pnp->tn_path); 7137917SReza.Sabdar@Sun.COM 7147917SReza.Sabdar@Sun.COM buf = ndmp_malloc(MAX_DENT_BUF_SIZE); 7157917SReza.Sabdar@Sun.COM if (buf == NULL) 7167917SReza.Sabdar@Sun.COM return (errno); 7177917SReza.Sabdar@Sun.COM 7187917SReza.Sabdar@Sun.COM fd = open(tsp->ts_fh.fh_fpath, O_RDONLY); 7197917SReza.Sabdar@Sun.COM if (fd == -1) { 7207917SReza.Sabdar@Sun.COM free(buf); 7217917SReza.Sabdar@Sun.COM return (errno); 7227917SReza.Sabdar@Sun.COM } 7237917SReza.Sabdar@Sun.COM if ((plist = fs_init_pathlist()) == NULL) { 7247917SReza.Sabdar@Sun.COM free(buf); 7257917SReza.Sabdar@Sun.COM (void) close(fd); 7267917SReza.Sabdar@Sun.COM return (errno); 7277917SReza.Sabdar@Sun.COM } 7287917SReza.Sabdar@Sun.COM plhead = plist; 7297917SReza.Sabdar@Sun.COM 7307917SReza.Sabdar@Sun.COM while (rv == 0) { 7317917SReza.Sabdar@Sun.COM long i, n_entries; 7327917SReza.Sabdar@Sun.COM 7337917SReza.Sabdar@Sun.COM darg->da_end = 0; 7347917SReza.Sabdar@Sun.COM n_entries = 0; 7357917SReza.Sabdar@Sun.COM rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos, 7367917SReza.Sabdar@Sun.COM &cookie_verf, &n_entries, darg, &plist); 7377917SReza.Sabdar@Sun.COM if (n_entries == 0) 7387917SReza.Sabdar@Sun.COM break; 7397917SReza.Sabdar@Sun.COM if (rv != 0) { 7407917SReza.Sabdar@Sun.COM traverse_stats.fss_readdir_err++; 7417917SReza.Sabdar@Sun.COM 7427917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d", 7437917SReza.Sabdar@Sun.COM rv, pnp->tn_path, tsp->ts_dpos); 7447917SReza.Sabdar@Sun.COM if (STOP_ONERR(ftp)) { 7457917SReza.Sabdar@Sun.COM NEGATE(rv); 7467917SReza.Sabdar@Sun.COM break; 7477917SReza.Sabdar@Sun.COM } 7487917SReza.Sabdar@Sun.COM /* 7497917SReza.Sabdar@Sun.COM * We cannot read the directory entry, we should 7507917SReza.Sabdar@Sun.COM * skip to the next directory. 7517917SReza.Sabdar@Sun.COM */ 7527917SReza.Sabdar@Sun.COM rv = SKIP_ENTRY; 7537917SReza.Sabdar@Sun.COM continue; 7547917SReza.Sabdar@Sun.COM } 7557917SReza.Sabdar@Sun.COM 7567917SReza.Sabdar@Sun.COM /* LINTED imporper alignment */ 7577917SReza.Sabdar@Sun.COM dent = (fs_dent_info_t *)darg->da_buf; 7587917SReza.Sabdar@Sun.COM /* LINTED imporper alignment */ 7597917SReza.Sabdar@Sun.COM for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *) 7607917SReza.Sabdar@Sun.COM ((char *)dent + dent->fd_len)) { 7617917SReza.Sabdar@Sun.COM 7627917SReza.Sabdar@Sun.COM if (rootfs_dot_or_dotdot(dent->fd_name)) { 7637917SReza.Sabdar@Sun.COM dent->fd_fh.fh_fpath = NULL; 7647917SReza.Sabdar@Sun.COM continue; 7657917SReza.Sabdar@Sun.COM } 7667917SReza.Sabdar@Sun.COM 7677917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 7687917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"", 7697917SReza.Sabdar@Sun.COM dent->fd_fh.fh_fid, dent->fd_name); 7707917SReza.Sabdar@Sun.COM 7717917SReza.Sabdar@Sun.COM if ((pl + strlen(dent->fd_name)) > PATH_MAX) { 7727917SReza.Sabdar@Sun.COM traverse_stats.fss_longpath_err++; 7737917SReza.Sabdar@Sun.COM 7747917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Path %s/%s is too long.", 7757917SReza.Sabdar@Sun.COM pnp->tn_path, dent->fd_name); 7767917SReza.Sabdar@Sun.COM if (STOP_ONLONG(ftp)) 7777917SReza.Sabdar@Sun.COM rv = -ENAMETOOLONG; 7787917SReza.Sabdar@Sun.COM continue; 7797917SReza.Sabdar@Sun.COM } 7807917SReza.Sabdar@Sun.COM 7817917SReza.Sabdar@Sun.COM /* 7827917SReza.Sabdar@Sun.COM * The entry is not a directory so the callback 7837917SReza.Sabdar@Sun.COM * function must be called. 7847917SReza.Sabdar@Sun.COM */ 7857917SReza.Sabdar@Sun.COM if (!S_ISDIR(dent->fd_attr.st_mode)) { 7867917SReza.Sabdar@Sun.COM traverse_stats.fss_nondir_calls++; 7877917SReza.Sabdar@Sun.COM 7887917SReza.Sabdar@Sun.COM en.tn_path = dent->fd_name; 7897917SReza.Sabdar@Sun.COM en.tn_fh = &dent->fd_fh; 7907917SReza.Sabdar@Sun.COM en.tn_st = &dent->fd_attr; 7917917SReza.Sabdar@Sun.COM rv = CALLBACK(pnp, &en); 7927917SReza.Sabdar@Sun.COM dent->fd_fh.fh_fpath = NULL; 7937917SReza.Sabdar@Sun.COM if (rv < 0) 7947917SReza.Sabdar@Sun.COM break; 7957917SReza.Sabdar@Sun.COM if (rv == FST_SKIP) { 7967917SReza.Sabdar@Sun.COM traverse_stats.fss_nondir_skipped++; 7977917SReza.Sabdar@Sun.COM break; 7987917SReza.Sabdar@Sun.COM } 7997917SReza.Sabdar@Sun.COM } else { 8007917SReza.Sabdar@Sun.COM dent->fd_fh.fh_fpath = NULL; 8017917SReza.Sabdar@Sun.COM } 8027917SReza.Sabdar@Sun.COM } 8037917SReza.Sabdar@Sun.COM } 8047917SReza.Sabdar@Sun.COM 8057917SReza.Sabdar@Sun.COM fs_free_pathlist(plhead); 8067917SReza.Sabdar@Sun.COM free(buf); 8077917SReza.Sabdar@Sun.COM (void) close(fd); 8087917SReza.Sabdar@Sun.COM return (rv); 8097917SReza.Sabdar@Sun.COM } 8107917SReza.Sabdar@Sun.COM 8117917SReza.Sabdar@Sun.COM /* 8127917SReza.Sabdar@Sun.COM * Traverse the file system in the level-order way. The description 8137917SReza.Sabdar@Sun.COM * and example is in the header file. 8147917SReza.Sabdar@Sun.COM */ 8157917SReza.Sabdar@Sun.COM int 8167917SReza.Sabdar@Sun.COM traverse_level(struct fs_traverse *ftp) 8177917SReza.Sabdar@Sun.COM { 8187917SReza.Sabdar@Sun.COM char path[PATH_MAX + 1]; /* full path name of the current dir */ 8197917SReza.Sabdar@Sun.COM char nm[NAME_MAX + 1]; /* directory entry name */ 8207917SReza.Sabdar@Sun.COM char *lp; /* last position on the path */ 8217917SReza.Sabdar@Sun.COM int next_dir, rv; 8227917SReza.Sabdar@Sun.COM int pl, el; /* path and directory entry length */ 8237917SReza.Sabdar@Sun.COM 8247917SReza.Sabdar@Sun.COM cstack_t *sp; 8257917SReza.Sabdar@Sun.COM fs_fhandle_t pfh, efh; 8267917SReza.Sabdar@Sun.COM struct stat64 pst, est; 8277917SReza.Sabdar@Sun.COM traverse_state_t *tsp; 8287917SReza.Sabdar@Sun.COM struct fst_node pn, en; /* parent and entry nodes */ 8297917SReza.Sabdar@Sun.COM dent_arg_t darg; 8307917SReza.Sabdar@Sun.COM path_list_t *plhead, *plist; 8317917SReza.Sabdar@Sun.COM 8327917SReza.Sabdar@Sun.COM if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) { 8337917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Invalid argument"); 8347917SReza.Sabdar@Sun.COM errno = EINVAL; 8357917SReza.Sabdar@Sun.COM return (-1); 8367917SReza.Sabdar@Sun.COM } 8377917SReza.Sabdar@Sun.COM /* set the default log function if it's not already set */ 8387917SReza.Sabdar@Sun.COM if (!ftp->ft_logfp) { 8397917SReza.Sabdar@Sun.COM ftp->ft_logfp = (ft_log_t)syslog; 8407917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path); 8417917SReza.Sabdar@Sun.COM } 8427917SReza.Sabdar@Sun.COM if (!ftp->ft_lpath) { 8437917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 8447917SReza.Sabdar@Sun.COM "report the same paths \"%s\"", ftp->ft_path); 8457917SReza.Sabdar@Sun.COM ftp->ft_lpath = ftp->ft_path; 8467917SReza.Sabdar@Sun.COM } 8477917SReza.Sabdar@Sun.COM 8487917SReza.Sabdar@Sun.COM pl = strlen(ftp->ft_lpath); 8497917SReza.Sabdar@Sun.COM if (pl + 1 > PATH_MAX) { /* +1 for the '/' */ 8507917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path); 8517917SReza.Sabdar@Sun.COM errno = ENAMETOOLONG; 8527917SReza.Sabdar@Sun.COM return (-1); 8537917SReza.Sabdar@Sun.COM } 8547917SReza.Sabdar@Sun.COM (void) strcpy(path, ftp->ft_lpath); 8557917SReza.Sabdar@Sun.COM (void) memset(&pfh, 0, sizeof (pfh)); 8567917SReza.Sabdar@Sun.COM rv = fs_getstat(ftp->ft_lpath, &pfh, &pst, NULL); 8577917SReza.Sabdar@Sun.COM if (rv != 0) { 8587917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 8597917SReza.Sabdar@Sun.COM "Error %d on fs_getstat(%s)", rv, ftp->ft_path); 8607917SReza.Sabdar@Sun.COM return (-1); 8617917SReza.Sabdar@Sun.COM } 8627917SReza.Sabdar@Sun.COM 8637917SReza.Sabdar@Sun.COM en.tn_path = NULL; 8647917SReza.Sabdar@Sun.COM en.tn_fh = NULL; 8657917SReza.Sabdar@Sun.COM en.tn_st = NULL; 8667917SReza.Sabdar@Sun.COM if (!S_ISDIR(pst.st_mode)) { 8677917SReza.Sabdar@Sun.COM pn.tn_path = ftp->ft_lpath; 8687917SReza.Sabdar@Sun.COM pn.tn_fh = &pfh; 8697917SReza.Sabdar@Sun.COM pn.tn_st = &pst; 8707917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en); 8717917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 8727917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv); 8737917SReza.Sabdar@Sun.COM 8747917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 8757917SReza.Sabdar@Sun.COM return (rv); 8767917SReza.Sabdar@Sun.COM } 8777917SReza.Sabdar@Sun.COM 8787917SReza.Sabdar@Sun.COM sp = cstack_new(); 8797917SReza.Sabdar@Sun.COM if (!sp) { 8807917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 8817917SReza.Sabdar@Sun.COM errno = ENOMEM; 8827917SReza.Sabdar@Sun.COM return (-1); 8837917SReza.Sabdar@Sun.COM } 8847917SReza.Sabdar@Sun.COM tsp = new_tsp(path); 8857917SReza.Sabdar@Sun.COM if (!tsp) { 8867917SReza.Sabdar@Sun.COM cstack_delete(sp); 8877917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 8887917SReza.Sabdar@Sun.COM errno = ENOMEM; 8897917SReza.Sabdar@Sun.COM return (-1); 8907917SReza.Sabdar@Sun.COM } 8917917SReza.Sabdar@Sun.COM 8927917SReza.Sabdar@Sun.COM darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE); 8937917SReza.Sabdar@Sun.COM if (!darg.da_buf) { 8947917SReza.Sabdar@Sun.COM cstack_delete(sp); 8957917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 8967917SReza.Sabdar@Sun.COM free(tsp); 8977917SReza.Sabdar@Sun.COM errno = ENOMEM; 8987917SReza.Sabdar@Sun.COM return (-1); 8997917SReza.Sabdar@Sun.COM } 9007917SReza.Sabdar@Sun.COM darg.da_size = MAX_DENT_BUF_SIZE; 9017917SReza.Sabdar@Sun.COM 9027917SReza.Sabdar@Sun.COM tsp->ts_ent = tsp->ts_end; 9037917SReza.Sabdar@Sun.COM tsp->ts_fh = pfh; 9047917SReza.Sabdar@Sun.COM tsp->ts_st = pst; 9057917SReza.Sabdar@Sun.COM pn.tn_path = path; 9067917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh; 9077917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st; 9087917SReza.Sabdar@Sun.COM 9097917SReza.Sabdar@Sun.COM if ((plist = fs_init_pathlist()) == NULL) { 9107917SReza.Sabdar@Sun.COM cstack_delete(sp); 9117917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 9127917SReza.Sabdar@Sun.COM free(tsp); 9137917SReza.Sabdar@Sun.COM errno = ENOMEM; 9147917SReza.Sabdar@Sun.COM return (-1); 9157917SReza.Sabdar@Sun.COM } 9167917SReza.Sabdar@Sun.COM plhead = plist; 9177917SReza.Sabdar@Sun.COM 9187917SReza.Sabdar@Sun.COM /* call the callback function on the path itself */ 9197917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++; 9207917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en); 9217917SReza.Sabdar@Sun.COM if (rv < 0) { 9227917SReza.Sabdar@Sun.COM free(tsp); 9237917SReza.Sabdar@Sun.COM goto end; 9247917SReza.Sabdar@Sun.COM } 9257917SReza.Sabdar@Sun.COM if (rv == FST_SKIP) { 9267917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_skipped++; 9277917SReza.Sabdar@Sun.COM free(tsp); 9287917SReza.Sabdar@Sun.COM rv = 0; 9297917SReza.Sabdar@Sun.COM goto end; 9307917SReza.Sabdar@Sun.COM } 9317917SReza.Sabdar@Sun.COM 9327917SReza.Sabdar@Sun.COM rv = 0; 9337917SReza.Sabdar@Sun.COM next_dir = 1; 9347917SReza.Sabdar@Sun.COM do { 9357917SReza.Sabdar@Sun.COM if (next_dir) { 9367917SReza.Sabdar@Sun.COM traverse_stats.fss_newdirs++; 9377917SReza.Sabdar@Sun.COM 9387917SReza.Sabdar@Sun.COM *tsp->ts_end = '\0'; 9397917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 9407917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path); 9417917SReza.Sabdar@Sun.COM 9427917SReza.Sabdar@Sun.COM rv = traverse_level_nondir(ftp, tsp, &pn, &darg); 9437917SReza.Sabdar@Sun.COM if (rv < 0) { 9447917SReza.Sabdar@Sun.COM NEGATE(rv); 9457917SReza.Sabdar@Sun.COM free(tsp); 9467917SReza.Sabdar@Sun.COM break; 9477917SReza.Sabdar@Sun.COM } 9487917SReza.Sabdar@Sun.COM /* 9497917SReza.Sabdar@Sun.COM * If skipped by the callback function or 9507917SReza.Sabdar@Sun.COM * error happened reading the information 9517917SReza.Sabdar@Sun.COM */ 9527917SReza.Sabdar@Sun.COM if (rv == FST_SKIP || rv == SKIP_ENTRY) { 9537917SReza.Sabdar@Sun.COM /* 9547917SReza.Sabdar@Sun.COM * N.B. next_dir should be set to 0 as 9557917SReza.Sabdar@Sun.COM * well. This prevents the infinite loop. 9567917SReza.Sabdar@Sun.COM * If it's not set the same directory will 9577917SReza.Sabdar@Sun.COM * be poped from the stack and will be 9587917SReza.Sabdar@Sun.COM * scanned again. 9597917SReza.Sabdar@Sun.COM */ 9607917SReza.Sabdar@Sun.COM next_dir = 0; 9617917SReza.Sabdar@Sun.COM rv = 0; 9627917SReza.Sabdar@Sun.COM goto skip_dir; 9637917SReza.Sabdar@Sun.COM } 9647917SReza.Sabdar@Sun.COM 9657917SReza.Sabdar@Sun.COM /* re-start reading entries of the directory */ 9667917SReza.Sabdar@Sun.COM tsp->ts_dpos = 0; 9677917SReza.Sabdar@Sun.COM } 9687917SReza.Sabdar@Sun.COM 9697917SReza.Sabdar@Sun.COM next_dir = 0; 9707917SReza.Sabdar@Sun.COM do { 9717917SReza.Sabdar@Sun.COM el = NAME_MAX; 9727917SReza.Sabdar@Sun.COM rv = fs_readdir(&tsp->ts_fh, pn.tn_path, 9737917SReza.Sabdar@Sun.COM &tsp->ts_dpos, nm, &el, &efh, 9747917SReza.Sabdar@Sun.COM &est, &plist); 9757917SReza.Sabdar@Sun.COM if (rv != 0) { 9767917SReza.Sabdar@Sun.COM traverse_stats.fss_readdir_err++; 9777917SReza.Sabdar@Sun.COM 9787917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 9797917SReza.Sabdar@Sun.COM "Error %d on readdir(%s) pos %d", 9807917SReza.Sabdar@Sun.COM rv, path, tsp->ts_dpos); 9817917SReza.Sabdar@Sun.COM if (STOP_ONERR(ftp)) 9827917SReza.Sabdar@Sun.COM break; 9837917SReza.Sabdar@Sun.COM rv = SKIP_ENTRY; 9847917SReza.Sabdar@Sun.COM continue; 9857917SReza.Sabdar@Sun.COM } 9867917SReza.Sabdar@Sun.COM 9877917SReza.Sabdar@Sun.COM /* done with this directory */ 9887917SReza.Sabdar@Sun.COM if (el == 0) 9897917SReza.Sabdar@Sun.COM break; 9907917SReza.Sabdar@Sun.COM 9917917SReza.Sabdar@Sun.COM nm[el] = '\0'; 9927917SReza.Sabdar@Sun.COM 9937917SReza.Sabdar@Sun.COM if (rootfs_dot_or_dotdot(nm)) { 9947917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 9957917SReza.Sabdar@Sun.COM continue; 9967917SReza.Sabdar@Sun.COM } 9977917SReza.Sabdar@Sun.COM 9987917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 9997917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"", 10007917SReza.Sabdar@Sun.COM tsp->ts_dpos, nm); 10017917SReza.Sabdar@Sun.COM 10027917SReza.Sabdar@Sun.COM if (pl + 1 + el > PATH_MAX) { 10037917SReza.Sabdar@Sun.COM /* 10047917SReza.Sabdar@Sun.COM * The long paths were already encountered 10057917SReza.Sabdar@Sun.COM * when processing non-dir entries in. 10067917SReza.Sabdar@Sun.COM * traverse_level_nondir. 10077917SReza.Sabdar@Sun.COM * We don't increase fss_longpath_err 10087917SReza.Sabdar@Sun.COM * counter for them again here. 10097917SReza.Sabdar@Sun.COM */ 10107917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Path %s/%s is too long.", 10117917SReza.Sabdar@Sun.COM path, nm); 10127917SReza.Sabdar@Sun.COM if (STOP_ONLONG(ftp)) 10137917SReza.Sabdar@Sun.COM rv = ENAMETOOLONG; 10147917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 10157917SReza.Sabdar@Sun.COM continue; 10167917SReza.Sabdar@Sun.COM } 10177917SReza.Sabdar@Sun.COM 10187917SReza.Sabdar@Sun.COM if (!S_ISDIR(est.st_mode)) { 10197917SReza.Sabdar@Sun.COM efh.fh_fpath = NULL; 10207917SReza.Sabdar@Sun.COM continue; 10217917SReza.Sabdar@Sun.COM } 10227917SReza.Sabdar@Sun.COM 10237917SReza.Sabdar@Sun.COM /* 10247917SReza.Sabdar@Sun.COM * Call the callback function for the new 10257917SReza.Sabdar@Sun.COM * directory found, then push the current 10267917SReza.Sabdar@Sun.COM * directory on to the stack. Then dive 10277917SReza.Sabdar@Sun.COM * into the entry found. 10287917SReza.Sabdar@Sun.COM */ 10297917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_calls++; 10307917SReza.Sabdar@Sun.COM en.tn_path = nm; 10317917SReza.Sabdar@Sun.COM en.tn_fh = &efh; 10327917SReza.Sabdar@Sun.COM en.tn_st = &est; 10337917SReza.Sabdar@Sun.COM rv = CALLBACK(&pn, &en); 10347917SReza.Sabdar@Sun.COM 10357917SReza.Sabdar@Sun.COM if (rv < 0) { 10367917SReza.Sabdar@Sun.COM NEGATE(rv); 10377917SReza.Sabdar@Sun.COM break; 10387917SReza.Sabdar@Sun.COM } 10397917SReza.Sabdar@Sun.COM if (rv == FST_SKIP) { 10407917SReza.Sabdar@Sun.COM traverse_stats.fss_dir_skipped++; 10417917SReza.Sabdar@Sun.COM rv = 0; 10427917SReza.Sabdar@Sun.COM continue; 10437917SReza.Sabdar@Sun.COM } 10447917SReza.Sabdar@Sun.COM 10457917SReza.Sabdar@Sun.COM /* 10467917SReza.Sabdar@Sun.COM * Push the current directory on to the stack and 10477917SReza.Sabdar@Sun.COM * dive into the entry found. 10487917SReza.Sabdar@Sun.COM */ 10497917SReza.Sabdar@Sun.COM if (cstack_push(sp, tsp, 0)) 10507917SReza.Sabdar@Sun.COM rv = ENOMEM; 10517917SReza.Sabdar@Sun.COM else { 10527917SReza.Sabdar@Sun.COM traverse_stats.fss_pushes++; 10537917SReza.Sabdar@Sun.COM 10547917SReza.Sabdar@Sun.COM lp = tsp->ts_end; 10557917SReza.Sabdar@Sun.COM *tsp->ts_end = '/'; 10567917SReza.Sabdar@Sun.COM (void) strcpy(tsp->ts_end + 1, nm); 10577917SReza.Sabdar@Sun.COM 10587917SReza.Sabdar@Sun.COM tsp = new_tsp(path); 10597917SReza.Sabdar@Sun.COM if (!tsp) 10607917SReza.Sabdar@Sun.COM rv = ENOMEM; 10617917SReza.Sabdar@Sun.COM else { 10627917SReza.Sabdar@Sun.COM next_dir = 1; 10637917SReza.Sabdar@Sun.COM pl += el + 1; 10647917SReza.Sabdar@Sun.COM tsp->ts_fh = efh; 10657917SReza.Sabdar@Sun.COM tsp->ts_st = est; 10667917SReza.Sabdar@Sun.COM tsp->ts_ent = lp; 10677917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh; 10687917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st; 10697917SReza.Sabdar@Sun.COM } 10707917SReza.Sabdar@Sun.COM } 10717917SReza.Sabdar@Sun.COM break; 10727917SReza.Sabdar@Sun.COM 10737917SReza.Sabdar@Sun.COM } while (rv == 0); 10747917SReza.Sabdar@Sun.COM 10757917SReza.Sabdar@Sun.COM /* 10767917SReza.Sabdar@Sun.COM * A new directory must be processed, go to the start of 10777917SReza.Sabdar@Sun.COM * the loop, open it and process it. 10787917SReza.Sabdar@Sun.COM */ 10797917SReza.Sabdar@Sun.COM if (next_dir) 10807917SReza.Sabdar@Sun.COM continue; 10817917SReza.Sabdar@Sun.COM skip_dir: 10827917SReza.Sabdar@Sun.COM if (tsp) 10837917SReza.Sabdar@Sun.COM free(tsp); 10847917SReza.Sabdar@Sun.COM 10857917SReza.Sabdar@Sun.COM if (rv == SKIP_ENTRY) 10867917SReza.Sabdar@Sun.COM rv = 0; 10877917SReza.Sabdar@Sun.COM 10887917SReza.Sabdar@Sun.COM if (rv == 0) { 10897917SReza.Sabdar@Sun.COM if (cstack_pop(sp, (void **)&tsp, (int *)NULL)) 10907917SReza.Sabdar@Sun.COM break; 10917917SReza.Sabdar@Sun.COM 10927917SReza.Sabdar@Sun.COM traverse_stats.fss_pops++; 10937917SReza.Sabdar@Sun.COM 10947917SReza.Sabdar@Sun.COM if (VERBOSE(ftp)) 10957917SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 10967917SReza.Sabdar@Sun.COM "Poped pl %d \"%s\"", pl, path); 10977917SReza.Sabdar@Sun.COM 10987917SReza.Sabdar@Sun.COM *tsp->ts_end = '\0'; 10997917SReza.Sabdar@Sun.COM pl = tsp->ts_end - path; 11007917SReza.Sabdar@Sun.COM pn.tn_fh = &tsp->ts_fh; 11017917SReza.Sabdar@Sun.COM pn.tn_st = &tsp->ts_st; 11027917SReza.Sabdar@Sun.COM } 11037917SReza.Sabdar@Sun.COM } while (rv == 0); 11047917SReza.Sabdar@Sun.COM 11057917SReza.Sabdar@Sun.COM /* 11067917SReza.Sabdar@Sun.COM * Pop and free all the remaining entries on the stack. 11077917SReza.Sabdar@Sun.COM */ 11087917SReza.Sabdar@Sun.COM while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) { 11097917SReza.Sabdar@Sun.COM traverse_stats.fss_stack_residue++; 11107917SReza.Sabdar@Sun.COM 11117917SReza.Sabdar@Sun.COM free(tsp); 11127917SReza.Sabdar@Sun.COM } 11137917SReza.Sabdar@Sun.COM end: 11147917SReza.Sabdar@Sun.COM free(darg.da_buf); 11157917SReza.Sabdar@Sun.COM free(pfh.fh_fpath); 11167917SReza.Sabdar@Sun.COM fs_free_pathlist(plhead); 11177917SReza.Sabdar@Sun.COM cstack_delete(sp); 11187917SReza.Sabdar@Sun.COM return (rv); 11197917SReza.Sabdar@Sun.COM } 11207917SReza.Sabdar@Sun.COM 11217917SReza.Sabdar@Sun.COM /* 11227917SReza.Sabdar@Sun.COM * filecopy - Copy a file 11237917SReza.Sabdar@Sun.COM * 11247917SReza.Sabdar@Sun.COM * Parameters: 11257917SReza.Sabdar@Sun.COM * char *dest - Destination path 11267917SReza.Sabdar@Sun.COM * char *src - Source path 11277917SReza.Sabdar@Sun.COM * 11287917SReza.Sabdar@Sun.COM * Returns: 11297917SReza.Sabdar@Sun.COM * 0 - No errors 11307917SReza.Sabdar@Sun.COM * #0 - Error occured 11317917SReza.Sabdar@Sun.COM * -4 - read/write error 11327917SReza.Sabdar@Sun.COM * -5 - source modified during copy 11337917SReza.Sabdar@Sun.COM * 11347917SReza.Sabdar@Sun.COM * Simplified version for Solaris 11357917SReza.Sabdar@Sun.COM */ 11367917SReza.Sabdar@Sun.COM #define BUFSIZE 32768 11377917SReza.Sabdar@Sun.COM int 11387917SReza.Sabdar@Sun.COM filecopy(char *dest, char *src) 11397917SReza.Sabdar@Sun.COM { 11407917SReza.Sabdar@Sun.COM FILE *src_fh = 0; 11417917SReza.Sabdar@Sun.COM FILE *dst_fh = 0; 11427917SReza.Sabdar@Sun.COM struct stat64 src_attr; 11437917SReza.Sabdar@Sun.COM struct stat64 dst_attr; 11447917SReza.Sabdar@Sun.COM char *buf = 0; 11457917SReza.Sabdar@Sun.COM u_longlong_t bytes_to_copy; 11467917SReza.Sabdar@Sun.COM size_t nbytes; 11477917SReza.Sabdar@Sun.COM int file_copied = 0; 11487917SReza.Sabdar@Sun.COM 11497917SReza.Sabdar@Sun.COM buf = ndmp_malloc(BUFSIZE); 11507917SReza.Sabdar@Sun.COM if (!buf) 11517917SReza.Sabdar@Sun.COM return (-1); 11527917SReza.Sabdar@Sun.COM 11537917SReza.Sabdar@Sun.COM src_fh = fopen(src, "r"); 11547917SReza.Sabdar@Sun.COM if (src_fh == 0) { 11557917SReza.Sabdar@Sun.COM free(buf); 11567917SReza.Sabdar@Sun.COM return (-2); 11577917SReza.Sabdar@Sun.COM } 11587917SReza.Sabdar@Sun.COM 11597917SReza.Sabdar@Sun.COM dst_fh = fopen(dest, "w"); 11607917SReza.Sabdar@Sun.COM if (dst_fh == NULL) { 11617917SReza.Sabdar@Sun.COM free(buf); 11627917SReza.Sabdar@Sun.COM (void) fclose(src_fh); 11637917SReza.Sabdar@Sun.COM return (-3); 11647917SReza.Sabdar@Sun.COM } 11657917SReza.Sabdar@Sun.COM 11667917SReza.Sabdar@Sun.COM if (stat64(src, &src_attr) < 0) { 11677917SReza.Sabdar@Sun.COM free(buf); 11687917SReza.Sabdar@Sun.COM (void) fclose(src_fh); 11697917SReza.Sabdar@Sun.COM (void) fclose(dst_fh); 11707917SReza.Sabdar@Sun.COM return (-2); 11717917SReza.Sabdar@Sun.COM } 11727917SReza.Sabdar@Sun.COM 11737917SReza.Sabdar@Sun.COM bytes_to_copy = src_attr.st_size; 11747917SReza.Sabdar@Sun.COM while (bytes_to_copy) { 11757917SReza.Sabdar@Sun.COM if (bytes_to_copy > BUFSIZE) 11767917SReza.Sabdar@Sun.COM nbytes = BUFSIZE; 11777917SReza.Sabdar@Sun.COM else 11787917SReza.Sabdar@Sun.COM nbytes = bytes_to_copy; 11797917SReza.Sabdar@Sun.COM 11807917SReza.Sabdar@Sun.COM if ((fread(buf, nbytes, 1, src_fh) != 1) || 11817917SReza.Sabdar@Sun.COM (fwrite(buf, nbytes, 1, dst_fh) != 1)) 11827917SReza.Sabdar@Sun.COM break; 11837917SReza.Sabdar@Sun.COM bytes_to_copy -= nbytes; 11847917SReza.Sabdar@Sun.COM } 11857917SReza.Sabdar@Sun.COM 11867917SReza.Sabdar@Sun.COM (void) fclose(src_fh); 11877917SReza.Sabdar@Sun.COM (void) fclose(dst_fh); 11887917SReza.Sabdar@Sun.COM 11897917SReza.Sabdar@Sun.COM if (bytes_to_copy > 0) { 11907917SReza.Sabdar@Sun.COM free(buf); 11917917SReza.Sabdar@Sun.COM /* short read/write, remove the partial file */ 11927917SReza.Sabdar@Sun.COM return (-4); 11937917SReza.Sabdar@Sun.COM } 11947917SReza.Sabdar@Sun.COM 11957917SReza.Sabdar@Sun.COM if (stat64(src, &dst_attr) < 0) { 11967917SReza.Sabdar@Sun.COM free(buf); 11977917SReza.Sabdar@Sun.COM return (-2); 11987917SReza.Sabdar@Sun.COM } 11997917SReza.Sabdar@Sun.COM 12007917SReza.Sabdar@Sun.COM free(buf); 12017917SReza.Sabdar@Sun.COM 12027917SReza.Sabdar@Sun.COM if (!file_copied) 12037917SReza.Sabdar@Sun.COM return (-5); /* source modified during copy */ 12047917SReza.Sabdar@Sun.COM else 12057917SReza.Sabdar@Sun.COM return (0); 12067917SReza.Sabdar@Sun.COM } 1207