Print this page
NEX-1348 It takes 23 hours and 37 minutes to run NDMP backup 43.9 GB with10000000 3KB files
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-13094 Netbackup 8.0 failed to back up files in NDMP certification test
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-9532 NDMP: readdir errors when file/directory has special characters
Reviewed by: Peer Dampmann <peer.dampmann@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2947 Volumes with more than a small fixed about don't traverse properly
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-2692 ndmpd intermittently dumps core due to SIGABRT in umem
SUP-898 nscd is extremely slow when a local file is missing
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
NEX-2500 Conflict between NDMP backup job and 'zfs send' leads to NDMP job abort.

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/ndmpd/tlm/tlm_traverse.c
          +++ new/usr/src/cmd/ndmpd/tlm/tlm_traverse.c
↓ open down ↓ 27 lines elided ↑ open up ↑
  28   28   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29   29   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30   30   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31   31   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32   32   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33   33   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34   34   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35   35   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36   36   * POSSIBILITY OF SUCH DAMAGE.
  37   37   */
       38 +/* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
       39 +
  38   40  /*
  39   41   * This file implemets the post-order, pre-order and level-order
  40   42   * traversing of the file system.  The related macros and constants
  41   43   * are defined in traverse.h.
  42   44   */
  43   45  
  44   46  #include <sys/stat.h>
  45   47  #include <sys/types.h>
  46   48  #include <sys/param.h>
  47   49  #include <assert.h>
↓ open down ↓ 25 lines elided ↑ open up ↑
  73   75                  return (TRUE);
  74   76  
  75   77          return (FALSE);
  76   78  }
  77   79  
  78   80  /*
  79   81   * Macros on fs_traverse flags.
  80   82   */
  81   83  #define STOP_ONERR(f)   ((f)->ft_flags & FST_STOP_ONERR)
  82   84  #define STOP_ONLONG(f)  ((f)->ft_flags & FST_STOP_ONLONG)
  83      -#define VERBOSE(f)      ((f)->ft_flags & FST_VERBOSE)
  84   85  
  85   86  #define CALLBACK(pp, ep)        \
  86   87          (*(ftp)->ft_callbk)((ftp)->ft_arg, pp, ep)
  87   88  
  88   89  #define NEGATE(rv)      ((rv) = -(rv))
  89   90  
  90   91  /*
  91   92   * The traversing state that is pushed onto the stack.
  92   93   * This include:
  93   94   *      - The end of the path of the current directory.
↓ open down ↓ 3 lines elided ↑ open up ↑
  97   98   *      - The stat of the directory.
  98   99   */
  99  100  typedef struct traverse_state {
 100  101          char *ts_end;
 101  102          char *ts_ent;
 102  103          long ts_dpos; /* position in the directory when reading its entries */
 103  104          fs_fhandle_t ts_fh;
 104  105          struct stat64 ts_st;
 105  106  } traverse_state_t;
 106  107  
 107      -/*
 108      - * Statistics gathering structure.
 109      - */
 110      -typedef struct traverse_statistics {
 111      -        ulong_t fss_newdirs;
 112      -        ulong_t fss_readdir_err;
 113      -        ulong_t fss_longpath_err;
 114      -        ulong_t fss_lookup_err;
 115      -        ulong_t fss_nondir_calls;
 116      -        ulong_t fss_dir_calls;
 117      -        ulong_t fss_nondir_skipped;
 118      -        ulong_t fss_dir_skipped;
 119      -        ulong_t fss_pushes;
 120      -        ulong_t fss_pops;
 121      -        ulong_t fss_stack_residue;
 122      -} traverse_statistics_t;
 123      -
 124      -/*
 125      - * Global instance of statistics variable.
 126      - */
 127      -traverse_statistics_t traverse_stats;
 128      -
 129      -#define MAX_DENT_BUF_SIZE       (8 * 1024)
 130      -
 131  108  typedef struct {
 132  109          struct stat64 fd_attr;
 133  110          fs_fhandle_t fd_fh;
 134  111          short fd_len;
 135  112          char fd_name[1];
 136  113  } fs_dent_info_t;
 137  114  
 138  115  typedef struct dent_arg {
 139  116          char *da_buf;
 140  117          int da_end;
 141  118          int da_size;
 142  119  } dent_arg_t;
 143  120  
 144  121  static int traverse_level_nondir(struct fs_traverse *ftp,
 145      -    traverse_state_t *tsp, struct fst_node *pnp,
 146      -    dent_arg_t *darg);
      122 +    traverse_state_t *tsp, struct fst_node *pnp);
 147  123  
 148  124  /*
 149      - * Gather some directory entry information and return them
 150      - */
 151      -static int
 152      -fs_populate_dents(void *arg, int namelen,
 153      -    char *name, long *countp, struct stat64 *attr,
 154      -    fs_fhandle_t *fh)
 155      -{
 156      -        dent_arg_t *darg = (dent_arg_t *)arg;
 157      -        int reclen = sizeof (fs_dent_info_t) + namelen;
 158      -        fs_dent_info_t *dent;
 159      -
 160      -        if ((darg->da_end + reclen) > darg->da_size)
 161      -                return (-1);
 162      -
 163      -        /* LINTED improper alignment */
 164      -        dent = (fs_dent_info_t *)(darg->da_buf + darg->da_end);
 165      -
 166      -        dent->fd_attr = *attr;
 167      -        dent->fd_fh = *fh;
 168      -        (void) strcpy(dent->fd_name, name);
 169      -
 170      -        dent->fd_len = reclen;
 171      -        darg->da_end += reclen;
 172      -
 173      -        if (countp)
 174      -                (*countp)++;
 175      -
 176      -        return (0);
 177      -}
 178      -
 179      -/*
 180  125   * Creates a new traversing state based on the path passed to it.
 181  126   */
 182  127  static traverse_state_t *
 183  128  new_tsp(char *path)
 184  129  {
 185  130          traverse_state_t *tsp;
 186  131          tsp = ndmp_malloc(sizeof (traverse_state_t));
 187  132          if (!tsp)
 188  133                  return (NULL);
 189  134  
↓ open down ↓ 5 lines elided ↑ open up ↑
 195  140  
 196  141          return (tsp);
 197  142  }
 198  143  
 199  144  /*
 200  145   * Create a file handle and get stats for the given path
 201  146   */
 202  147  int
 203  148  fs_getstat(char *path, fs_fhandle_t *fh, struct stat64 *st)
 204  149  {
 205      -        if (lstat64(path, st) == -1)
      150 +        if (lstat64(path, st) == -1) {
      151 +                syslog(LOG_INFO,
      152 +                    "lstat64() says [%s] not found errno=(%d)", path, errno);
 206  153                  return (errno);
      154 +        }
 207  155  
 208  156          fh->fh_fid = st->st_ino;
 209  157  
 210  158          if (!S_ISDIR(st->st_mode))
 211  159                  fh->fh_fpath = NULL;
 212  160          else
 213  161                  fh->fh_fpath = strdup(path);
 214  162          return (0);
 215  163  }
 216  164  
 217  165  /*
 218      - * Get directory entries info and return in the buffer. Cookie
 219      - * will keep the state of each call
 220      - */
 221      -static int
 222      -fs_getdents(int fildes, struct dirent *buf, size_t *nbyte,
 223      -    char *pn_path, long *dpos, longlong_t *cookie,
 224      -    long *n_entries, dent_arg_t *darg)
 225      -{
 226      -        struct dirent *ptr;
 227      -        char file_path[PATH_MAX + 1];
 228      -        fs_fhandle_t fh;
 229      -        struct stat64 st;
 230      -        char *p;
 231      -        int len;
 232      -        int rv;
 233      -
 234      -        if (*nbyte == 0) {
 235      -                (void) memset((char *)buf, 0, MAX_DENT_BUF_SIZE);
 236      -                *nbyte = rv = getdents(fildes, buf, darg->da_size);
 237      -                *cookie = 0LL;
 238      -
 239      -                if (rv <= 0)
 240      -                        return (rv);
 241      -        }
 242      -
 243      -        p = (char *)buf + *cookie;
 244      -        len = *nbyte;
 245      -        do {
 246      -                /* LINTED improper alignment */
 247      -                ptr = (struct dirent *)p;
 248      -                *dpos =  ptr->d_off;
 249      -
 250      -                if (rootfs_dot_or_dotdot(ptr->d_name))
 251      -                        goto skip_entry;
 252      -
 253      -                (void) snprintf(file_path, PATH_MAX, "%s/", pn_path);
 254      -                (void) strlcat(file_path, ptr->d_name, PATH_MAX + 1);
 255      -                (void) memset(&fh, 0, sizeof (fs_fhandle_t));
 256      -
 257      -                if (lstat64(file_path, &st) != 0) {
 258      -                        rv = -1;
 259      -                        break;
 260      -                }
 261      -
 262      -                fh.fh_fid = st.st_ino;
 263      -
 264      -                if (S_ISDIR(st.st_mode))
 265      -                        goto skip_entry;
 266      -
 267      -                if (fs_populate_dents(darg, strlen(ptr->d_name),
 268      -                    (char *)ptr->d_name, n_entries, &st, &fh) != 0)
 269      -                        break;
 270      -
 271      -skip_entry:
 272      -                p = p + ptr->d_reclen;
 273      -                len -= ptr->d_reclen;
 274      -        } while (len);
 275      -
 276      -        *cookie = (longlong_t)(p - (char *)buf);
 277      -        *nbyte = len;
 278      -        return (rv);
 279      -}
 280      -
 281      -/*
 282  166   * Read the directory entries and return the information about
 283  167   * each entry
 284  168   */
 285  169  int
 286  170  fs_readdir(fs_fhandle_t *ts_fh, char *path, long *dpos,
 287  171      char *nm, int *el, fs_fhandle_t *efh, struct stat64 *est)
 288  172  {
 289  173          struct dirent *dp;
 290  174          char  file_path[PATH_MAX + 1];
 291  175          DIR *dirp;
↓ open down ↓ 39 lines elided ↑ open up ↑
 331  215          char *lp; /* last position on the path */
 332  216          int next_dir, rv;
 333  217          int pl, el; /* path and directory entry length */
 334  218          cstack_t *sp;
 335  219          fs_fhandle_t pfh, efh;
 336  220          struct stat64 pst, est;
 337  221          traverse_state_t *tsp;
 338  222          struct fst_node pn, en; /* parent and entry nodes */
 339  223  
 340  224          if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
 341      -                NDMP_LOG(LOG_DEBUG, "Invalid argument");
 342  225                  errno = EINVAL;
 343  226                  return (-1);
 344  227          }
 345  228  
 346  229          /* set the default log function if it's not already set */
 347  230          if (!ftp->ft_logfp) {
 348  231                  ftp->ft_logfp = (ft_log_t)syslog;
 349      -                NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
      232 +                syslog(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
 350  233          }
 351  234  
 352  235          /* set the logical path to physical path if it's not already set */
 353  236          if (!ftp->ft_lpath) {
 354      -                NDMP_LOG(LOG_DEBUG,
      237 +                syslog(LOG_DEBUG,
 355  238                      "report the same paths: \"%s\"", ftp->ft_path);
 356  239                  ftp->ft_lpath = ftp->ft_path;
 357  240          }
 358  241  
 359  242          pl = strlen(ftp->ft_lpath);
 360  243          if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
 361      -                NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
      244 +                syslog(LOG_ERR, "lpath too long \"%s\"", ftp->ft_path);
 362  245                  errno = ENAMETOOLONG;
 363  246                  return (-1);
 364  247          }
 365  248          (void) strcpy(path, ftp->ft_lpath);
 366  249          (void) memset(&pfh, 0, sizeof (pfh));
 367  250          rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
 368  251  
 369  252          if (rv != 0) {
 370      -                NDMP_LOG(LOG_DEBUG,
      253 +                syslog(LOG_ERR,
 371  254                      "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
 372  255                  return (rv);
 373  256          }
 374  257  
 375  258          if (!S_ISDIR(pst.st_mode)) {
 376  259                  pn.tn_path = ftp->ft_lpath;
 377  260                  pn.tn_fh = &pfh;
 378  261                  pn.tn_st = &pst;
 379  262                  en.tn_path = NULL;
 380  263                  en.tn_fh = NULL;
 381  264                  en.tn_st = NULL;
 382  265                  rv = CALLBACK(&pn, &en);
 383      -                if (VERBOSE(ftp))
 384      -                        NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
 385  266                  free(pfh.fh_fpath);
 386  267                  return (rv);
 387  268          }
 388  269  
 389  270          sp = cstack_new();
 390  271          if (!sp) {
 391  272                  errno = ENOMEM;
 392  273                  free(pfh.fh_fpath);
 393  274                  return (-1);
 394  275          }
↓ open down ↓ 8 lines elided ↑ open up ↑
 403  284          tsp->ts_fh = pfh;
 404  285          tsp->ts_st = pst;
 405  286          pn.tn_path = path;
 406  287          pn.tn_fh = &tsp->ts_fh;
 407  288          pn.tn_st = &tsp->ts_st;
 408  289  
 409  290          rv = 0;
 410  291          next_dir = 1;
 411  292          do {
 412  293                  if (next_dir) {
 413      -                        traverse_stats.fss_newdirs++;
 414      -
 415  294                          *tsp->ts_end = '\0';
 416      -                        if (VERBOSE(ftp))
 417      -                                NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
 418  295                  }
 419  296  
 420  297                  next_dir = 0;
 421  298                  do {
 422  299                          el = NAME_MAX;
 423  300                          rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
 424  301                              &tsp->ts_dpos, nm, &el,
 425  302                              &efh, &est);
 426  303  
 427  304                          if (rv != 0) {
 428      -                                free(efh.fh_fpath);
 429      -                                traverse_stats.fss_readdir_err++;
 430      -
 431      -                                NDMP_LOG(LOG_DEBUG,
      305 +                                syslog(LOG_ERR,
 432  306                                      "Error %d on readdir(%s) pos %d",
 433  307                                      rv, path, tsp->ts_dpos);
 434  308                                  if (STOP_ONERR(ftp))
 435  309                                          break;
 436  310                                  rv = SKIP_ENTRY;
 437  311  
 438  312                                  continue;
 439  313                          }
 440  314  
 441  315                          /* done with this directory */
 442  316                          if (el == 0) {
 443      -                                if (VERBOSE(ftp))
 444      -                                        NDMP_LOG(LOG_DEBUG,
 445      -                                            "Done(%s)", pn.tn_path);
 446  317                                  break;
 447  318                          }
 448  319                          nm[el] = '\0';
 449  320  
 450  321                          if (rootfs_dot_or_dotdot(nm)) {
 451  322                                  free(efh.fh_fpath);
 452  323                                  continue;
 453  324                          }
 454  325  
 455      -                        if (VERBOSE(ftp))
 456      -                                NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
 457      -                                    tsp->ts_dpos, nm);
 458      -
 459  326                          if (pl + 1 + el > PATH_MAX) {
 460      -                                traverse_stats.fss_longpath_err++;
 461      -
 462      -                                NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
      327 +                                syslog(LOG_ERR, "Path %s/%s is too long.",
 463  328                                      path, nm);
 464  329                                  if (STOP_ONLONG(ftp))
 465  330                                          rv = ENAMETOOLONG;
 466  331                                  free(efh.fh_fpath);
 467  332                                  continue;
 468  333                          }
 469  334  
 470  335                          /*
 471  336                           * Push the current directory on to the stack and
 472  337                           * dive into the entry found.
 473  338                           */
 474  339                          if (S_ISDIR(est.st_mode)) {
 475  340  
 476  341                                  assert(tsp != NULL);
 477  342                                  if (cstack_push(sp, tsp, 0)) {
 478  343                                          rv = ENOMEM;
 479  344                                          free(efh.fh_fpath);
 480  345                                          break;
 481  346                                  }
 482      -                                traverse_stats.fss_pushes++;
 483  347  
 484  348                                  /*
 485  349                                   * Concatenate the current entry with the
 486  350                                   * current path.  This will be the path of
 487  351                                   * the new directory to be scanned.
 488  352                                   *
 489  353                                   * Note:
 490  354                                   * sprintf(tsp->ts_end, "/%s", de->d_name);
 491  355                                   * could be used here, but concatenating
 492  356                                   * strings like this might be faster.
↓ open down ↓ 18 lines elided ↑ open up ↑
 511  375                                          tsp->ts_ent = lp;
 512  376                                          pn.tn_fh = &tsp->ts_fh;
 513  377                                          pn.tn_st = &tsp->ts_st;
 514  378                                  }
 515  379                                  break;
 516  380                          } else {
 517  381                                  /*
 518  382                                   * The entry is not a directory so the
 519  383                                   * callback function must be called.
 520  384                                   */
 521      -                                traverse_stats.fss_nondir_calls++;
 522      -
 523  385                                  en.tn_path = nm;
 524  386                                  en.tn_fh = &efh;
 525  387                                  en.tn_st = &est;
 526  388                                  rv = CALLBACK(&pn, &en);
 527  389                                  free(efh.fh_fpath);
 528      -                                if (VERBOSE(ftp))
 529      -                                        NDMP_LOG(LOG_DEBUG,
 530      -                                            "CALLBACK(%s/%s): %d",
 531      -                                            pn.tn_path, en.tn_path, rv);
 532      -
 533  390                                  if (rv != 0)
 534  391                                          break;
 535  392                          }
 536  393                  } while (rv == 0);
 537  394  
 538  395                  /*
 539  396                   * A new directory must be processed, go to the start of
 540  397                   * the loop, open it and process it.
 541  398                   */
 542  399                  if (next_dir)
↓ open down ↓ 11 lines elided ↑ open up ↑
 554  411                          *lp = '\0';
 555  412                          efh = tsp->ts_fh;
 556  413                          est = tsp->ts_st;
 557  414                          free(tsp);
 558  415                          if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
 559  416                                  break;
 560  417  
 561  418                          assert(tsp != NULL);
 562  419                          pl = tsp->ts_end - path;
 563  420  
 564      -                        if (VERBOSE(ftp))
 565      -                                NDMP_LOG(LOG_DEBUG, "poped pl %d 0x%p \"%s\"",
 566      -                                    pl, tsp, path);
 567      -
 568      -                        traverse_stats.fss_pops++;
 569      -                        traverse_stats.fss_dir_calls++;
 570      -
 571  421                          pn.tn_fh = &tsp->ts_fh;
 572  422                          pn.tn_st = &tsp->ts_st;
 573  423                          en.tn_path = lp + 1;
 574  424                          en.tn_fh = &efh;
 575  425                          en.tn_st = &est;
 576  426  
 577  427                          rv = CALLBACK(&pn, &en);
 578  428                          free(efh.fh_fpath);
 579      -                        if (VERBOSE(ftp))
 580      -                                NDMP_LOG(LOG_DEBUG, "CALLBACK(%s/%s): %d",
 581      -                                    pn.tn_path, en.tn_path, rv);
 582  429                          /*
 583  430                           * Does not need to free tsp here.  It will be released
 584  431                           * later.
 585  432                           */
 586  433                  }
 587  434  
 588  435                  if (rv != 0 && tsp) {
 589  436                          free(tsp->ts_fh.fh_fpath);
 590  437                          free(tsp);
 591  438                  }
 592  439  
 593  440          } while (rv == 0);
 594  441  
 595  442          /*
 596  443           * For the 'ftp->ft_path' directory itself.
 597  444           */
 598  445          if (rv == 0) {
 599      -                traverse_stats.fss_dir_calls++;
 600      -
 601  446                  pn.tn_fh = &efh;
 602  447                  pn.tn_st = &est;
 603  448                  en.tn_path = NULL;
 604  449                  en.tn_fh = NULL;
 605  450                  en.tn_st = NULL;
 606  451                  rv = CALLBACK(&pn, &en);
 607      -                if (VERBOSE(ftp))
 608      -                        NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
 609  452          }
 610  453  
 611  454          /*
 612  455           * Pop and free all the remaining entries on the stack.
 613  456           */
 614  457          while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
 615      -                traverse_stats.fss_stack_residue++;
 616      -
 617  458                  free(tsp->ts_fh.fh_fpath);
 618  459                  free(tsp);
 619  460          }
 620  461  
 621  462          cstack_delete(sp);
 622  463          return (rv);
 623  464  }
 624  465  
 625  466  /*
 626  467   * In one pass, read all the directory entries of the specified
↓ open down ↓ 3 lines elided ↑ open up ↑
 630  471   * On return:
 631  472   *    0: Lets the directory to be scanned for directory entries.
 632  473   *    < 0: Completely stops traversing.
 633  474   *    FST_SKIP: stops further scanning of the directory.  Traversing
 634  475   *        will continue with the next directory in the hierarchy.
 635  476   *    SKIP_ENTRY: Failed to get the directory entries, so the caller
 636  477   *        should skip this entry.
 637  478   */
 638  479  static int
 639  480  traverse_level_nondir(struct fs_traverse *ftp,
 640      -    traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
      481 +    traverse_state_t *tsp, struct fst_node *pnp)
 641  482  {
 642      -        int pl; /* path length */
 643      -        int rv;
      483 +        struct stat64 st;
      484 +        fs_fhandle_t fh;
      485 +        DIR *dp;
      486 +        struct dirent *dirp;
 644  487          struct fst_node en; /* entry node */
 645      -        longlong_t cookie_verf;
 646      -        fs_dent_info_t *dent;
 647      -        struct dirent *buf;
 648      -        size_t len = 0;
 649      -        int fd;
      488 +        char path[MAXPATHLEN+MAXNAMELEN+2];
      489 +        int rv = 0;
 650  490  
 651      -        rv = 0;
 652      -        pl = strlen(pnp->tn_path);
 653      -
 654      -        buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
 655      -        if (buf == NULL)
      491 +        if ((dp = opendir(tsp->ts_fh.fh_fpath)) == NULL) {
      492 +                syslog(LOG_ERR,
      493 +                    "traverse_level_nondir: open directory "
      494 +                    "%s failed: %m", tsp->ts_fh.fh_fpath);
 656  495                  return (errno);
 657      -
 658      -        fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
 659      -        if (fd == -1) {
 660      -                free(buf);
 661      -                return (errno);
 662  496          }
 663  497  
 664      -        while (rv == 0) {
 665      -                long i, n_entries;
      498 +        while ((dirp = readdir(dp)) != NULL) {
      499 +                if ((strcmp(dirp->d_name, ".") == 0) ||
      500 +                    (strcmp(dirp->d_name, "..") == 0)) {
      501 +                        continue;
      502 +                }
 666  503  
 667      -                darg->da_end = 0;
 668      -                n_entries = 0;
 669      -                rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
 670      -                    &cookie_verf, &n_entries, darg);
 671      -                if (rv < 0) {
 672      -                        traverse_stats.fss_readdir_err++;
      504 +                if (!tlm_cat_path(path, tsp->ts_fh.fh_fpath,
      505 +                    dirp->d_name)) {
      506 +                        continue;
      507 +                }
 673  508  
 674      -                        NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
 675      -                            rv, pnp->tn_path, tsp->ts_dpos);
 676      -                        if (STOP_ONERR(ftp))
 677      -                                break;
 678      -                        /*
 679      -                         * We cannot read the directory entry, we should
 680      -                         * skip to the next directory.
 681      -                         */
 682      -                        rv = SKIP_ENTRY;
      509 +                if (lstat64(path, &st) != 0) {
      510 +                        syslog(LOG_ERR,
      511 +                            "traverse_level_nondir: failed to get file"
      512 +                            " status for %s skipping: %m", tsp->ts_fh.fh_fpath);
 683  513                          continue;
 684      -                } else {
 685      -                        /* Break at the end of directory */
 686      -                        if (rv > 0)
 687      -                                rv = 0;
 688      -                        else
 689      -                                break;
 690  514                  }
      515 +                fh.fh_fid = st.st_ino;
 691  516  
 692      -                /* LINTED imporper alignment */
 693      -                dent = (fs_dent_info_t *)darg->da_buf;
 694      -                /* LINTED imporper alignment */
 695      -                for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
 696      -                    ((char *)dent + dent->fd_len)) {
 697      -
 698      -                        if (VERBOSE(ftp))
 699      -                                NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
 700      -                                    dent->fd_fh.fh_fid, dent->fd_name);
 701      -
 702      -                        if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
 703      -                                traverse_stats.fss_longpath_err++;
 704      -
 705      -                                NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
 706      -                                    pnp->tn_path, dent->fd_name);
 707      -                                if (STOP_ONLONG(ftp))
 708      -                                        rv = -ENAMETOOLONG;
 709      -                                free(dent->fd_fh.fh_fpath);
 710      -                                continue;
      517 +                /*
      518 +                 * The entry is not a directory so the callback
      519 +                 * function must be called.
      520 +                 */
      521 +                if (!S_ISDIR(st.st_mode)) {
      522 +                        en.tn_path = dirp->d_name;
      523 +                        en.tn_fh = &fh;
      524 +                        en.tn_st = &st;
      525 +                        rv = CALLBACK(pnp, &en);
      526 +                        if (rv < 0) {
      527 +                                syslog(LOG_DEBUG,
      528 +                                    "traverse_level_nondir: result is %d "
      529 +                                    "with %s", rv, path);
      530 +                                break;
 711  531                          }
 712      -
 713      -                        /*
 714      -                         * The entry is not a directory so the callback
 715      -                         * function must be called.
 716      -                         */
 717      -                        if (!S_ISDIR(dent->fd_attr.st_mode)) {
 718      -                                traverse_stats.fss_nondir_calls++;
 719      -
 720      -                                en.tn_path = dent->fd_name;
 721      -                                en.tn_fh = &dent->fd_fh;
 722      -                                en.tn_st = &dent->fd_attr;
 723      -                                rv = CALLBACK(pnp, &en);
 724      -                                dent->fd_fh.fh_fpath = NULL;
 725      -                                if (rv < 0)
 726      -                                        break;
 727      -                                if (rv == FST_SKIP) {
 728      -                                        traverse_stats.fss_nondir_skipped++;
 729      -                                        break;
 730      -                                }
      532 +                        if (rv == FST_SKIP) {
      533 +                                syslog(LOG_DEBUG,
      534 +                                    "traverse_level_nondir: skipping "
      535 +                                    "%s", path);
      536 +                                break;
 731  537                          }
 732  538                  }
 733  539          }
 734  540  
 735      -        free(buf);
 736      -        (void) close(fd);
      541 +        (void) closedir(dp);
 737  542          return (rv);
 738  543  }
 739  544  
 740  545  /*
 741  546   * Traverse the file system in the level-order way.  The description
 742  547   * and example is in the header file.
 743  548   */
 744  549  int
 745  550  traverse_level(struct fs_traverse *ftp)
 746  551  {
↓ open down ↓ 1 lines elided ↑ open up ↑
 748  553          char nm[NAME_MAX + 1];  /* directory entry name */
 749  554          char *lp;               /* last position on the path */
 750  555          int next_dir, rv;
 751  556          int pl, el;             /* path and directory entry length */
 752  557  
 753  558          cstack_t *sp;
 754  559          fs_fhandle_t pfh, efh;
 755  560          struct stat64 pst, est;
 756  561          traverse_state_t *tsp;
 757  562          struct fst_node pn, en;  /* parent and entry nodes */
 758      -        dent_arg_t darg;
 759  563  
 760  564          if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
 761      -                NDMP_LOG(LOG_DEBUG, "Invalid argument");
 762  565                  errno = EINVAL;
 763  566                  return (-1);
 764  567          }
 765  568          /* set the default log function if it's not already set */
 766  569          if (!ftp->ft_logfp) {
 767  570                  ftp->ft_logfp = (ft_log_t)syslog;
 768      -                NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
      571 +                syslog(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
 769  572          }
 770  573          if (!ftp->ft_lpath) {
 771      -                NDMP_LOG(LOG_DEBUG,
      574 +                syslog(LOG_DEBUG,
 772  575                      "report the same paths \"%s\"", ftp->ft_path);
 773  576                  ftp->ft_lpath = ftp->ft_path;
 774  577          }
 775  578  
 776  579          pl = strlen(ftp->ft_lpath);
 777  580          if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
 778      -                NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
      581 +                syslog(LOG_ERR, "lpath too long \"%s\"", ftp->ft_path);
 779  582                  errno = ENAMETOOLONG;
 780  583                  return (-1);
 781  584          }
 782  585          (void) strcpy(path, ftp->ft_lpath);
 783  586          (void) memset(&pfh, 0, sizeof (pfh));
 784  587          rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
 785  588          if (rv != 0) {
 786      -                NDMP_LOG(LOG_DEBUG,
 787      -                    "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
      589 +                syslog(LOG_DEBUG,
      590 +                    "Error %d on fs_getstat(%s)", rv, ftp->ft_lpath);
 788  591                  return (-1);
 789  592          }
 790  593  
 791  594          en.tn_path = NULL;
 792  595          en.tn_fh = NULL;
 793  596          en.tn_st = NULL;
 794  597          if (!S_ISDIR(pst.st_mode)) {
 795  598                  pn.tn_path = ftp->ft_lpath;
 796  599                  pn.tn_fh = &pfh;
 797  600                  pn.tn_st = &pst;
 798  601                  rv = CALLBACK(&pn, &en);
 799      -                if (VERBOSE(ftp))
 800      -                        NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
 801      -
 802  602                  free(pfh.fh_fpath);
 803  603                  return (rv);
 804  604          }
 805  605  
 806  606          sp = cstack_new();
 807  607          if (!sp) {
 808  608                  free(pfh.fh_fpath);
 809  609                  errno = ENOMEM;
 810  610                  return (-1);
 811  611          }
 812  612          tsp = new_tsp(path);
 813  613          if (!tsp) {
 814  614                  cstack_delete(sp);
 815  615                  free(pfh.fh_fpath);
 816  616                  errno = ENOMEM;
 817  617                  return (-1);
 818  618          }
 819  619  
 820      -        darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
 821      -        if (!darg.da_buf) {
 822      -                cstack_delete(sp);
 823      -                free(pfh.fh_fpath);
 824      -                free(tsp);
 825      -                errno = ENOMEM;
 826      -                return (-1);
 827      -        }
 828      -        darg.da_size = MAX_DENT_BUF_SIZE;
 829      -
 830  620          tsp->ts_ent = tsp->ts_end;
 831  621          tsp->ts_fh = pfh;
 832  622          tsp->ts_st = pst;
 833  623          pn.tn_path = path;
 834  624          pn.tn_fh = &tsp->ts_fh;
 835  625          pn.tn_st = &tsp->ts_st;
 836  626  
 837  627          /* call the callback function on the path itself */
 838      -        traverse_stats.fss_dir_calls++;
 839  628          rv = CALLBACK(&pn, &en);
 840  629          if (rv < 0) {
 841  630                  free(tsp);
 842  631                  goto end;
 843  632          }
 844  633          if (rv == FST_SKIP) {
 845      -                traverse_stats.fss_dir_skipped++;
 846  634                  free(tsp);
 847  635                  rv = 0;
 848  636                  goto end;
 849  637          }
 850  638  
 851  639          rv = 0;
 852  640          next_dir = 1;
 853  641          do {
 854  642                  if (next_dir) {
 855      -                        traverse_stats.fss_newdirs++;
 856      -
 857  643                          *tsp->ts_end = '\0';
 858      -                        if (VERBOSE(ftp))
 859      -                                NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
 860      -
 861      -                        rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
      644 +                        rv = traverse_level_nondir(ftp, tsp, &pn);
 862  645                          if (rv < 0) {
 863  646                                  NEGATE(rv);
 864  647                                  free(tsp->ts_fh.fh_fpath);
 865  648                                  free(tsp);
 866  649                                  break;
 867  650                          }
 868  651                          /*
 869  652                           * If skipped by the callback function or
 870  653                           * error happened reading the information
 871  654                           */
↓ open down ↓ 14 lines elided ↑ open up ↑
 886  669                          tsp->ts_dpos = 0;
 887  670                  }
 888  671  
 889  672                  next_dir = 0;
 890  673                  do {
 891  674                          el = NAME_MAX;
 892  675                          rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
 893  676                              &tsp->ts_dpos, nm, &el, &efh,
 894  677                              &est);
 895  678                          if (rv != 0) {
 896      -                                traverse_stats.fss_readdir_err++;
 897      -
 898      -                                NDMP_LOG(LOG_DEBUG,
      679 +                                syslog(LOG_DEBUG,
 899  680                                      "Error %d on readdir(%s) pos %d",
 900  681                                      rv, path, tsp->ts_dpos);
 901  682                                  if (STOP_ONERR(ftp))
 902  683                                          break;
 903  684                                  rv = SKIP_ENTRY;
 904  685                                  continue;
 905  686                          }
 906  687  
 907  688                          /* done with this directory */
 908  689                          if (el == 0)
 909  690                                  break;
 910  691  
 911  692                          nm[el] = '\0';
 912  693  
 913  694                          if (rootfs_dot_or_dotdot(nm)) {
 914  695                                  free(efh.fh_fpath);
 915  696                                  continue;
 916  697                          }
 917  698  
 918      -                        if (VERBOSE(ftp))
 919      -                                NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
 920      -                                    tsp->ts_dpos, nm);
 921      -
 922  699                          if (pl + 1 + el > PATH_MAX) {
 923  700                                  /*
 924  701                                   * The long paths were already encountered
 925  702                                   * when processing non-dir entries in.
 926  703                                   * traverse_level_nondir.
 927  704                                   * We don't increase fss_longpath_err
 928  705                                   * counter for them again here.
 929  706                                   */
 930      -                                NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
      707 +                                syslog(LOG_ERR, "Path %s/%s is too long.",
 931  708                                      path, nm);
 932  709                                  if (STOP_ONLONG(ftp))
 933  710                                          rv = ENAMETOOLONG;
 934  711                                  free(efh.fh_fpath);
 935  712                                  continue;
 936  713                          }
 937  714  
 938  715                          if (!S_ISDIR(est.st_mode))
 939  716                                  continue;
 940  717  
 941  718                          /*
 942  719                           * Call the callback function for the new
 943  720                           * directory found, then push the current
 944  721                           * directory on to the stack.  Then dive
 945  722                           * into the entry found.
 946  723                           */
 947      -                        traverse_stats.fss_dir_calls++;
 948  724                          en.tn_path = nm;
 949  725                          en.tn_fh = &efh;
 950  726                          en.tn_st = &est;
 951  727                          rv = CALLBACK(&pn, &en);
 952  728  
 953  729                          if (rv < 0) {
 954  730                                  NEGATE(rv);
 955  731                                  free(efh.fh_fpath);
 956  732                                  break;
 957  733                          }
 958  734                          if (rv == FST_SKIP) {
 959      -                                traverse_stats.fss_dir_skipped++;
 960  735                                  free(efh.fh_fpath);
 961  736                                  rv = 0;
 962  737                                  continue;
 963  738                          }
 964  739  
 965  740                          /*
 966  741                           * Push the current directory on to the stack and
 967  742                           * dive into the entry found.
 968  743                           */
 969  744                          if (cstack_push(sp, tsp, 0)) {
 970  745                                  rv = ENOMEM;
 971  746                          } else {
 972      -                                traverse_stats.fss_pushes++;
 973      -
 974  747                                  lp = tsp->ts_end;
 975  748                                  *tsp->ts_end = '/';
 976  749                                  (void) strcpy(tsp->ts_end + 1, nm);
 977  750  
 978  751                                  tsp = new_tsp(path);
 979  752                                  if (!tsp)
 980  753                                          rv = ENOMEM;
 981  754                                  else {
 982  755                                          next_dir = 1;
 983  756                                          pl += el + 1;
↓ open down ↓ 20 lines elided ↑ open up ↑
1004  777                          free(tsp);
1005  778                  }
1006  779  
1007  780                  if (rv == SKIP_ENTRY)
1008  781                          rv = 0;
1009  782  
1010  783                  if (rv == 0) {
1011  784                          if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
1012  785                                  break;
1013  786  
1014      -                        traverse_stats.fss_pops++;
1015      -
1016      -                        if (VERBOSE(ftp))
1017      -                                NDMP_LOG(LOG_DEBUG,
1018      -                                    "Poped pl %d \"%s\"", pl, path);
1019      -
1020  787                          *tsp->ts_end = '\0';
1021  788                          pl = tsp->ts_end - path;
1022  789                          pn.tn_fh = &tsp->ts_fh;
1023  790                          pn.tn_st = &tsp->ts_st;
1024  791                  }
1025  792          } while (rv == 0);
1026  793  
1027  794          /*
1028  795           * Pop and free all the remaining entries on the stack.
1029  796           */
1030  797          while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
1031      -                traverse_stats.fss_stack_residue++;
1032      -
1033  798                  free(tsp->ts_fh.fh_fpath);
1034  799                  free(tsp);
1035  800          }
1036  801  end:
1037      -        free(darg.da_buf);
1038  802          cstack_delete(sp);
1039  803          return (rv);
1040  804  }
1041  805  
1042  806  /*
1043  807   * filecopy - Copy a file
1044  808   *
1045  809   * Parameters:
1046  810   *  char *dest  - Destination path
1047  811   *  char *src   - Source path
↓ open down ↓ 80 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX