Print this page
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-2911 NDMP logging should use syslog and is too chatty


  20  *
  21  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  22  *        nor the names of its contributors may be used to endorse or promote
  23  *        products derived from this software without specific prior written
  24  *        permission.
  25  *
  26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36  * POSSIBILITY OF SUCH DAMAGE.
  37  */
  38 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  39 /* Copyright (c) 2007, The Storage Networking Industry Association. */

  40 
  41 /*
  42  * File history callback functions called by backup modules. NDMP file history
  43  * supports 2 file history models: path based and inode/directory based.
  44  * Backup/recover modules similar to unix dump/restore utilize the
  45  * inode/directory based model. During the filesystem scan pass,
  46  * ndmpd_file_history_dir() is called. During the file backup pass,
  47  * ndmpd_file_history_node() is called. This model is appropriate for
  48  * modules whose code is structured such that file name and file attribute
  49  * data is not available at the same time. Backup/recover modules similar
  50  * to tar or cpio utilize the path based model. The simple dump/restore module
  51  * included with the SDK uses the path based model.
  52  */
  53 
  54 #include <sys/stat.h>
  55 #include <sys/types.h>

  56 #include <dirent.h>
  57 #include <errno.h>
  58 #include <stdlib.h>
  59 #include <string.h>
  60 #include "ndmpd.h"
  61 #include <dirent.h>
  62 #include <bitmap.h>
  63 
  64 
  65 #define N_PATH_ENTRIES  1000
  66 #define N_FILE_ENTRIES  N_PATH_ENTRIES
  67 #define N_DIR_ENTRIES   1000
  68 #define N_NODE_ENTRIES  1000
  69 
  70 /* Figure an average of 32 bytes per path name */
  71 #define PATH_NAMEBUF_SIZE       (N_PATH_ENTRIES * 32)
  72 
  73 /* Figure an average of 16 bytes per file name */
  74 #define DIR_NAMEBUF_SIZE        (N_PATH_ENTRIES * 16)
  75 


 117     struct stat64 *file_stat, u_longlong_t fh_info)
 118 {
 119         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 120         ndmp_fh_unix_path *entry;
 121 
 122         if (name == NULL && session->ns_fh.fh_path_index == 0)
 123                 return (0);
 124 
 125         /*
 126          * If the buffer does not have space
 127          * for the current entry, send the buffered data to the client.
 128          * A NULL name indicates that any buffered data should be sent.
 129          */
 130         if (name == NULL ||
 131             (ndmp_syncfh && session->ns_fh.fh_path_index != 0) ||
 132             session->ns_fh.fh_path_index == N_PATH_ENTRIES ||
 133             session->ns_fh.fh_path_name_buf_index + strlen(name) + 1 >
 134             PATH_NAMEBUF_SIZE) {
 135                 ndmp_fh_add_unix_path_request request;
 136 
 137                 NDMP_LOG(LOG_DEBUG,
 138                     "sending %ld entries", session->ns_fh.fh_path_index);
 139 
 140                 request.paths.paths_val = session->ns_fh.fh_path_entries;
 141                 request.paths.paths_len = session->ns_fh.fh_path_index;
 142 
 143                 if (ndmp_send_request_lock(session->ns_connection,
 144                     NDMP_FH_ADD_UNIX_PATH, NDMP_NO_ERR, (void *) &request,
 145                     0) < 0) {
 146                         NDMP_LOG(LOG_DEBUG, "Sending file history data");
 147                         return (-1);
 148                 }
 149                 session->ns_fh.fh_path_index = 0;
 150                 session->ns_fh.fh_path_name_buf_index = 0;
 151         }
 152         if (name == NULL)
 153                 return (0);
 154 
 155         if (session->ns_fh.fh_path_entries == 0) {
 156                 session->ns_fh.fh_path_entries = ndmp_malloc(N_PATH_ENTRIES *
 157                     sizeof (ndmp_fh_unix_path));
 158                 if (session->ns_fh.fh_path_entries == 0)
 159                         return (-1);
 160         }
 161         if (session->ns_fh.fh_path_name_buf == 0) {
 162                 session->ns_fh.fh_path_name_buf =
 163                     ndmp_malloc(PATH_NAMEBUF_SIZE);
 164                 if (session->ns_fh.fh_path_name_buf == 0)
 165                         return (-1);
 166         }


 209     ulong_t parent)
 210 {
 211         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 212         ndmp_fh_unix_dir *entry;
 213 
 214         if (name == NULL && session->ns_fh.fh_dir_index == 0)
 215                 return (0);
 216 
 217         /*
 218          * If the buffer does not have space for the current entry,
 219          * send the buffered data to the client. A NULL name indicates
 220          * that any buffered data should be sent.
 221          */
 222         if (name == NULL ||
 223             (ndmp_syncfh && session->ns_fh.fh_dir_index != 0) ||
 224             session->ns_fh.fh_dir_index == N_DIR_ENTRIES ||
 225             session->ns_fh.fh_dir_name_buf_index + strlen(name) + 1 >
 226             DIR_NAMEBUF_SIZE) {
 227                 ndmp_fh_add_unix_dir_request request;
 228 
 229                 NDMP_LOG(LOG_DEBUG,
 230                     "sending %ld entries", session->ns_fh.fh_dir_index);
 231 
 232                 request.dirs.dirs_val = session->ns_fh.fh_dir_entries;
 233                 request.dirs.dirs_len = session->ns_fh.fh_dir_index;
 234                 if (ndmp_send_request_lock(session->ns_connection,
 235                     NDMP_FH_ADD_UNIX_DIR, NDMP_NO_ERR, (void *) &request,
 236                     0) < 0) {
 237                         NDMP_LOG(LOG_DEBUG, "Sending file history data");
 238                         return (-1);
 239                 }
 240                 session->ns_fh.fh_dir_index = 0;
 241                 session->ns_fh.fh_dir_name_buf_index = 0;
 242         }
 243         if (name == NULL)
 244                 return (0);
 245 
 246         if (session->ns_fh.fh_dir_entries == 0) {
 247                 session->ns_fh.fh_dir_entries = ndmp_malloc(N_DIR_ENTRIES
 248                     * sizeof (ndmp_fh_unix_dir));
 249                 if (session->ns_fh.fh_dir_entries == 0)
 250                         return (-1);
 251         }
 252         if (session->ns_fh.fh_dir_name_buf == 0) {
 253                 session->ns_fh.fh_dir_name_buf = ndmp_malloc(DIR_NAMEBUF_SIZE);
 254                 if (session->ns_fh.fh_dir_name_buf == 0)
 255                         return (-1);
 256         }
 257         entry = &session->ns_fh.fh_dir_entries[session->ns_fh.fh_dir_index];


 296 ndmpd_api_file_history_node_v2(void *cookie, ulong_t node,
 297     struct stat64 *file_stat, u_longlong_t fh_info)
 298 {
 299         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 300         ndmp_fh_unix_node *entry;
 301 
 302         if (file_stat == NULL && session->ns_fh.fh_node_index == 0)
 303                 return (-1);
 304 
 305         /*
 306          * If the buffer does not have space
 307          * for the current entry, send the buffered data to the client.
 308          * A 0 file_stat pointer indicates that any buffered data should
 309          * be sent.
 310          */
 311         if (file_stat == NULL ||
 312             (ndmp_syncfh && session->ns_fh.fh_node_index != 0) ||
 313             session->ns_fh.fh_node_index == N_NODE_ENTRIES) {
 314                 ndmp_fh_add_unix_node_request request;
 315 
 316                 NDMP_LOG(LOG_DEBUG,
 317                     "sending %ld entries", session->ns_fh.fh_node_index);
 318 
 319                 request.nodes.nodes_val = session->ns_fh.fh_node_entries;
 320                 request.nodes.nodes_len = session->ns_fh.fh_node_index;
 321                 /*
 322                  * Need to send Dir entry as well. Since Dir entry is more than
 323                  * Node entry, we may send a Node entry that hasn't have
 324                  * its dir entry sent. Therefore, we need to flush Dir entry
 325                  * as well everytime the Dir entry is send.
 326                  */
 327                 (void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0);
 328 
 329                 if (ndmp_send_request_lock(session->ns_connection,
 330                     NDMP_FH_ADD_UNIX_NODE, NDMP_NO_ERR, (void *) &request,
 331                     0) < 0) {
 332                         NDMP_LOG(LOG_DEBUG, "Sending file history data");
 333                         return (-1);
 334                 }
 335                 session->ns_fh.fh_node_index = 0;
 336         }
 337         if (file_stat == NULL)
 338                 return (0);
 339 
 340         if (session->ns_fh.fh_node_entries == 0) {
 341                 session->ns_fh.fh_node_entries = ndmp_malloc(N_NODE_ENTRIES
 342                     * sizeof (ndmp_fh_unix_node));
 343                 if (session->ns_fh.fh_node_entries == 0)
 344                         return (-1);
 345         }
 346         entry = &session->ns_fh.fh_node_entries[session->ns_fh.fh_node_index];
 347         ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype);
 348 
 349         entry->node = node;
 350         entry->fstat.mtime = (ulong_t)file_stat->st_mtime;
 351         entry->fstat.atime = (ulong_t)file_stat->st_atime;
 352         entry->fstat.ctime = (ulong_t)file_stat->st_ctime;


 392 {
 393         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 394         ndmp_file_v3 *file_entry;
 395         ndmp_file_name_v3 *file_name_entry;
 396         ndmp_file_stat_v3 *file_stat_entry;
 397         ndmp_fh_add_file_request_v3 request;
 398 
 399         if (name == NULL && session->ns_fh_v3.fh_file_index == 0)
 400                 return (0);
 401 
 402         /*
 403          * If the buffer does not have space
 404          * for the current entry, send the buffered data to the client.
 405          * A NULL name indicates that any buffered data should be sent.
 406          */
 407         if (name == NULL ||
 408             session->ns_fh_v3.fh_file_index == N_FILE_ENTRIES ||
 409             session->ns_fh_v3.fh_file_name_buf_index + strlen(name) + 1 >
 410             PATH_NAMEBUF_SIZE) {
 411 
 412                 NDMP_LOG(LOG_DEBUG, "sending %ld entries",
 413                     session->ns_fh_v3.fh_file_index);
 414 
 415                 request.files.files_len = session->ns_fh_v3.fh_file_index;
 416                 request.files.files_val = session->ns_fh_v3.fh_files;
 417 
 418                 if (ndmp_send_request_lock(session->ns_connection,
 419                     NDMP_FH_ADD_FILE, NDMP_NO_ERR, (void *) &request, 0) < 0) {
 420                         NDMP_LOG(LOG_DEBUG,
 421                             "Sending ndmp_fh_add_file request");
 422                         return (-1);
 423                 }
 424 
 425                 session->ns_fh_v3.fh_file_index = 0;
 426                 session->ns_fh_v3.fh_file_name_buf_index = 0;
 427         }
 428 
 429         if (name == NULL)
 430                 return (0);
 431 
 432         if (session->ns_fh_v3.fh_files == 0) {
 433                 session->ns_fh_v3.fh_files = ndmp_malloc(sizeof (ndmp_file_v3) *
 434                     N_FILE_ENTRIES);
 435                 if (session->ns_fh_v3.fh_files == 0)
 436                         return (-1);
 437         }
 438 
 439         if (session->ns_fh_v3.fh_file_names == 0) {
 440                 session->ns_fh_v3.fh_file_names =
 441                     ndmp_malloc(sizeof (ndmp_file_name_v3) * N_FILE_ENTRIES);


 522     ulong_t parent)
 523 {
 524         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 525         ndmp_dir_v3 *dir_entry;
 526         ndmp_file_name_v3 *dir_name_entry;
 527         ndmp_fh_add_dir_request_v3 request;
 528 
 529         if (name == NULL && session->ns_fh_v3.fh_dir_index == 0)
 530                 return (0);
 531 
 532         /*
 533          * If the buffer does not have space
 534          * for the current entry, send the buffered data to the client.
 535          * A NULL name indicates that any buffered data should be sent.
 536          */
 537         if (name == NULL ||
 538             session->ns_fh_v3.fh_dir_index == N_DIR_ENTRIES ||
 539             session->ns_fh_v3.fh_dir_name_buf_index + strlen(name) + 1 >
 540             DIR_NAMEBUF_SIZE) {
 541 
 542                 NDMP_LOG(LOG_DEBUG, "sending %ld entries",
 543                     session->ns_fh_v3.fh_dir_index);
 544 
 545                 request.dirs.dirs_val = session->ns_fh_v3.fh_dirs;
 546                 request.dirs.dirs_len = session->ns_fh_v3.fh_dir_index;
 547 
 548                 if (ndmp_send_request_lock(session->ns_connection,
 549                     NDMP_FH_ADD_DIR, NDMP_NO_ERR, (void *) &request, 0) < 0) {
 550                         NDMP_LOG(LOG_DEBUG,
 551                             "Sending ndmp_fh_add_dir request");
 552                         return (-1);
 553                 }
 554 
 555                 session->ns_fh_v3.fh_dir_index = 0;
 556                 session->ns_fh_v3.fh_dir_name_buf_index = 0;
 557         }
 558 
 559         if (name == NULL)
 560                 return (0);
 561 
 562         if (session->ns_fh_v3.fh_dirs == 0) {
 563                 session->ns_fh_v3.fh_dirs =
 564                     ndmp_malloc(sizeof (ndmp_dir_v3) * N_DIR_ENTRIES);
 565                 if (session->ns_fh_v3.fh_dirs == 0)
 566                         return (-1);
 567         }
 568 
 569         if (session->ns_fh_v3.fh_dir_names == 0) {
 570                 session->ns_fh_v3.fh_dir_names =
 571                     ndmp_malloc(sizeof (ndmp_file_name_v3) * N_DIR_ENTRIES);


 628 int
 629 ndmpd_api_file_history_node_v3(void *cookie, ulong_t node,
 630     struct stat64 *file_stat, u_longlong_t fh_info)
 631 {
 632         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 633         ndmp_node_v3 *node_entry;
 634         ndmp_file_stat_v3 *file_stat_entry;
 635         ndmp_fh_add_node_request_v3 request;
 636 
 637         if (file_stat == NULL && session->ns_fh_v3.fh_node_index == 0)
 638                 return (0);
 639 
 640         /*
 641          * If the buffer does not have space
 642          * for the current entry, send the buffered data to the client.
 643          * A 0 file_stat pointer indicates that any buffered data should
 644          * be sent.
 645          */
 646         if (file_stat == NULL ||
 647             session->ns_fh_v3.fh_node_index == N_NODE_ENTRIES) {
 648                 NDMP_LOG(LOG_DEBUG, "sending %ld entries",
 649                     session->ns_fh_v3.fh_node_index);
 650 
 651                 /*
 652                  * Need to send Dir entry as well. Since Dir entry is more
 653                  * than a Node entry, we may send a Node entry that hasn't
 654                  * had its Dir entry sent. Therefore, we need to flush Dir
 655                  * entry as well every time the Dir entry is sent.
 656                  */
 657                 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);
 658 
 659                 request.nodes.nodes_len = session->ns_fh_v3.fh_node_index;
 660                 request.nodes.nodes_val = session->ns_fh_v3.fh_nodes;
 661 
 662                 if (ndmp_send_request_lock(session->ns_connection,
 663                     NDMP_FH_ADD_NODE,
 664                     NDMP_NO_ERR, (void *) &request, 0) < 0) {
 665                         NDMP_LOG(LOG_DEBUG,
 666                             "Sending ndmp_fh_add_node request");
 667                         return (-1);
 668                 }
 669 
 670                 session->ns_fh_v3.fh_node_index = 0;
 671         }
 672 
 673         if (file_stat == NULL)
 674                 return (0);
 675 
 676         if (session->ns_fh_v3.fh_nodes == 0) {
 677                 session->ns_fh_v3.fh_nodes =
 678                     ndmp_malloc(sizeof (ndmp_node_v3) * N_NODE_ENTRIES);
 679                 if (session->ns_fh_v3.fh_nodes == 0)
 680                         return (-1);
 681         }
 682 
 683         if (session->ns_fh_v3.fh_node_stats == 0) {
 684                 session->ns_fh_v3.fh_node_stats =
 685                     ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_NODE_ENTRIES);
 686                 if (session->ns_fh_v3.fh_node_stats == 0)


 722  * NDMP V4 HANDLERS
 723  * ************************************************************************
 724  */
 725 
 726 
 727 /*
 728  * ndmpd_fhpath_v3_cb
 729  *
 730  * Callback function for file history path information
 731  */
 732 int
 733 ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t *cbp, char *path, struct stat64 *stp,
 734     u_longlong_t off)
 735 {
 736         int err;
 737         ndmp_lbr_params_t *nlp;
 738         ndmpd_module_params_t *params;
 739 
 740         if (!cbp) {
 741                 err = -1;
 742                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
 743         } else if (!cbp->fh_cookie) {
 744                 err = -1;
 745                 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
 746         } else if (!path) {
 747                 err = -1;
 748                 NDMP_LOG(LOG_DEBUG, "path is NULL");
 749         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
 750                 err = -1;
 751                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
 752         } else
 753                 err = 0;
 754 
 755         if (err != 0)
 756                 return (0);
 757 
 758         NDMP_LOG(LOG_DEBUG, "pname(%s)", path);
 759 
 760         err = 0;
 761         if (NLP_ISSET(nlp, NLPF_FH)) {
 762                 if (!NLP_ISSET(nlp, NLPF_DIRECT)) {
 763                         NDMP_LOG(LOG_DEBUG, "DAR NOT SET!");
 764                         off = 0LL;
 765                 }
 766 
 767                 params = get_params(cbp->fh_cookie);
 768                 if (!params || !params->mp_file_history_path_func) {
 769                         err = -1;
 770                 } else {
 771                         char *p =
 772                             ndmp_get_relative_path(get_backup_path_v3(params),
 773                             path);
 774                         if ((err = ndmpd_api_file_history_file_v3(cbp->
 775                             fh_cookie, p, stp, off)) < 0)
 776                                 NDMP_LOG(LOG_DEBUG, "\"%s\" %d", path, err);
 777                 }
 778         }
 779 
 780         return (err);
 781 }
 782 
 783 
 784 /*
 785  * ndmpd_fhdir_v3_cb
 786  *
 787  * Callback function for file history dir information
 788  */
 789 int
 790 ndmpd_fhdir_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, struct stat64 *stp)
 791 {
 792         char nm[PATH_MAX+1];
 793         int nml;
 794         int err;
 795         ulong_t ino, pino;
 796         ulong_t pos;
 797         ndmp_lbr_params_t *nlp;
 798         ndmpd_module_params_t *params;
 799         DIR *dirp;
 800         char dirpath[PATH_MAX];
 801 
 802         if (!cbp) {
 803                 err = -1;
 804                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
 805         } else if (!cbp->fh_cookie) {
 806                 err = -1;
 807                 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
 808         } else if (!dir) {
 809                 err = -1;
 810                 NDMP_LOG(LOG_DEBUG, "dir is NULL");
 811         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
 812                 err = -1;
 813                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
 814         } else
 815                 err = 0;
 816 
 817         if (err != 0)
 818                 return (0);
 819 
 820         NDMP_LOG(LOG_DEBUG, "d(%s)", dir);
 821 
 822         if (!NLP_ISSET(nlp, NLPF_FH))
 823                 return (0);
 824 
 825         /*
 826          * Veritas net_backup accepts only 2 as the inode number of the backup
 827          * root directory.  The other way compares the path against the
 828          * backup path which is slower.
 829          */
 830         if (stp->st_ino == nlp->nlp_bkdirino)
 831                 pino = ROOT_INODE;
 832         else
 833                 pino = stp->st_ino;
 834 
 835         /*
 836          * There is nothing below this directory to be backed up.
 837          * If there was, the bit for this directory would have
 838          * been set.  Backup root directory is exception.  We
 839          * always send the dir file history records of it.
 840          */
 841         if (pino != ROOT_INODE &&
 842             !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
 843                 NDMP_LOG(LOG_DEBUG, "nothing below here");
 844                 return (0);
 845         }
 846 
 847         params = nlp->nlp_params;
 848         if (!params || !params->mp_file_history_dir_func)
 849                 return (-1);
 850 
 851         pos = 0;
 852         err = 0;
 853 
 854         dirp = opendir(dir);
 855         if (dirp == NULL)
 856                 return (0);
 857 
 858         do {
 859                 nml = PATH_MAX;
 860                 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
 861                 if (err != 0) {
 862                         NDMP_LOG(LOG_DEBUG,
 863                             "%d reading pos %u dir \"%s\"", err, pos, dir);
 864                         break;
 865                 }
 866                 if (nml == 0)
 867                         break;
 868                 nm[nml] = '\0';
 869 
 870                 if (pino == ROOT_INODE) {
 871                         if (rootfs_dot_or_dotdot(nm))
 872                                 ino = ROOT_INODE;
 873                 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {
 874                         NDMP_LOG(LOG_DEBUG, "nm(%s): %lu", nm, ino);
 875                         ino = ROOT_INODE;
 876                 }
 877 
 878                 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
 879                         continue;
 880 
 881                 /*
 882                  * If the entry is on exclusion list dont send the info
 883                  */
 884                 if (tlm_is_excluded(dir, nm, ndmp_excl_list)) {
 885                         NDMP_LOG(LOG_DEBUG,
 886                             "name \"%s\" skipped", nm == 0 ? "nil" : nm);
 887                         continue;
 888                 }
 889 
 890                 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
 891                     ino, pino);
 892                 if (err < 0) {
 893                         NDMP_LOG(LOG_DEBUG, "\"%s\": %d", dir, err);
 894                         break;
 895                 }
 896 
 897                 /*
 898                  * This is a requirement by some DMA's (net_vault) that during
 899                  * the incremental backup, the node info should also be sent
 900                  * along with the dir info for all directories leading to a
 901                  * backed up file.
 902                  */
 903                 if (ndmp_fhinode) {
 904                         struct stat64 ret_attr;
 905 
 906                         (void) strlcpy(dirpath, dir, PATH_MAX);
 907                         (void) strlcat(dirpath, "/", PATH_MAX);
 908                         (void) strlcat(dirpath, nm, PATH_MAX);
 909                         err = stat64(dirpath, &ret_attr);
 910                         if (err != 0) {
 911                                 NDMP_LOG(LOG_DEBUG,
 912                                     "Error looking up %s", nm);
 913                                 break;
 914                         }
 915 
 916                         if (S_ISDIR(ret_attr.st_mode)) {
 917                                 err = (*params->mp_file_history_node_func)(cbp->
 918                                     fh_cookie, ino, &ret_attr, 0);
 919                                 if (err < 0) {
 920                                         NDMP_LOG(LOG_DEBUG, "\"%s/\": %d",
 921                                             dir, err);
 922                                         break;
 923                                 }
 924                         }
 925                 }
 926         } while (err == 0);
 927 
 928         (void) closedir(dirp);
 929         return (err);
 930 }
 931 
 932 
 933 /*
 934  * ndmpd_fhnode_v3_cb
 935  *
 936  * Callback function for file history node information
 937  */
 938 int
 939 ndmpd_fhnode_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
 940     struct stat64 *stp, u_longlong_t off)
 941 {
 942         int err;
 943         ulong_t ino;
 944         ndmp_lbr_params_t *nlp;
 945         ndmpd_module_params_t *params;
 946 
 947         if (!cbp) {
 948                 err = -1;
 949                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
 950         } else if (!cbp->fh_cookie) {
 951                 err = -1;
 952                 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
 953         } else if (!dir) {
 954                 err = -1;
 955                 NDMP_LOG(LOG_DEBUG, "dir is NULL");
 956         } else if (!file) {
 957                 err = -1;
 958                 NDMP_LOG(LOG_DEBUG, "file is NULL");
 959         } else if (!stp) {
 960                 err = -1;
 961                 NDMP_LOG(LOG_DEBUG, "stp is NULL");
 962         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
 963                 err = -1;
 964                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
 965         } else {
 966                 err = 0;
 967         }
 968 
 969         if (err != 0)
 970                 return (0);
 971 
 972         NDMP_LOG(LOG_DEBUG, "d(%s), f(%s)", dir, file);
 973 
 974         err = 0;
 975         if (NLP_ISSET(nlp, NLPF_FH)) {
 976                 if (!NLP_ISSET(nlp, NLPF_DIRECT))
 977                         off = 0LL;
 978                 if (stp->st_ino == nlp->nlp_bkdirino) {
 979                         ino = ROOT_INODE;
 980                         NDMP_LOG(LOG_DEBUG,
 981                             "bkroot %d -> %d", stp->st_ino, ROOT_INODE);
 982                 } else
 983                         ino = stp->st_ino;
 984 
 985                 params = nlp->nlp_params;
 986                 if (!params || !params->mp_file_history_node_func)
 987                         err = -1;
 988                 else if ((err = (*params->mp_file_history_node_func)(cbp->
 989                     fh_cookie, ino, stp, off)) < 0)
 990                         NDMP_LOG(LOG_DEBUG, "\"%s/%s\" %d", dir, file, err);
 991         }
 992 
 993         return (err);
 994 }
 995 
 996 
 997 /*
 998  * ndmp_send_recovery_stat_v3
 999  *
1000  * Send the recovery status to the DMA
1001  */
1002 int
1003 ndmp_send_recovery_stat_v3(ndmpd_module_params_t *params,
1004     ndmp_lbr_params_t *nlp, int idx, int stat)
1005 {
1006         int rv;
1007         mem_ndmp_name_v3_t *ep;
1008 
1009         rv = -1;
1010         if (!params) {
1011                 NDMP_LOG(LOG_DEBUG, "params == NULL");
1012         } else if (!params->mp_file_recovered_func) {
1013                 NDMP_LOG(LOG_DEBUG, "paramsfile_recovered_func == NULL");
1014         } else if (!nlp) {
1015                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1016         } else if (idx < 0) {
1017                 NDMP_LOG(LOG_DEBUG, "idx(%d) < 0", idx);
1018         } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, idx))) {
1019                 NDMP_LOG(LOG_DEBUG, "nlist[%d] == NULL", idx);
1020         } else if (!ep->nm3_opath) {
1021                 NDMP_LOG(LOG_DEBUG, "nlist[%d].nm3_opath == NULL", idx);
1022         } else {
1023                 NDMP_LOG(LOG_DEBUG,
1024                     "ep[%d].nm3_opath \"%s\"", idx, ep->nm3_opath);
1025                 rv = MOD_FILERECOVERD(params, ep->nm3_opath, stat);
1026         }
1027 
1028         return (rv);
1029 }
1030 
1031 
1032 /*
1033  * ndmpd_path_restored_v3
1034  *
1035  * Send the recovery status and the information for the restored
1036  * path.
1037  */
1038 /*ARGSUSED*/
1039 int
1040 ndmpd_path_restored_v3(lbr_fhlog_call_backs_t *cbp, char *name,
1041     struct stat64 *st, u_longlong_t ll_idx)
1042 {
1043         int rv;
1044         ndmp_lbr_params_t *nlp;
1045         ndmpd_module_params_t *params;
1046         int idx = (int)ll_idx;
1047 
1048         if (!cbp) {
1049                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1050                 return (-1);
1051         }
1052         if (!name) {
1053                 NDMP_LOG(LOG_DEBUG, "name is NULL");
1054                 return (-1);
1055         }
1056 
1057         NDMP_LOG(LOG_DEBUG, "name: \"%s\", idx: %d", name, idx);
1058 
1059         nlp = ndmp_get_nlp(cbp->fh_cookie);
1060         if (!nlp) {
1061                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1062                 return (-1);
1063         }
1064         if (idx < 0 || idx >= nlp->nlp_nfiles) {
1065                 NDMP_LOG(LOG_DEBUG, "Invalid idx: %d", idx);
1066                 return (-1);
1067         }
1068         params = nlp->nlp_params;
1069         if (!params || !params->mp_file_recovered_func)
1070                 return (-1);
1071 
1072         if (nlp->nlp_lastidx == -1)
1073                 nlp->nlp_lastidx = idx;
1074 
1075         rv = 0;
1076         (void) bm_setone(nlp->nlp_rsbm, (u_longlong_t)idx);
1077         /*
1078          * Note: We should set the nm3_err here.
1079          */
1080         if (nlp->nlp_lastidx != idx) {
1081                 rv = ndmp_send_recovery_stat_v3(params, nlp, nlp->nlp_lastidx,
1082                     0);
1083                 nlp->nlp_lastidx = idx;
1084         }
1085 


1257 
1258 
1259 /*
1260  * ndmpd_file_history_cleanup
1261  *
1262  * Send any pending posts and clean up
1263  */
1264 void
1265 ndmpd_file_history_cleanup(ndmpd_session_t *session, boolean_t send_flag)
1266 {
1267         switch (session->ns_protocol_version) {
1268         case 1:
1269         case 2:
1270                 ndmpd_file_history_cleanup_v2(session, send_flag);
1271                 break;
1272         case 3:
1273         case 4:
1274                 ndmpd_file_history_cleanup_v3(session, send_flag);
1275                 break;
1276         default:
1277                 NDMP_LOG(LOG_DEBUG, "Unknown version %d",
1278                     session->ns_protocol_version);
1279         }
1280 }
1281 
1282 /*
1283  * get_params
1284  *
1285  * Callbacks from LBR.
1286  */
1287 static ndmpd_module_params_t *
1288 get_params(void *cookie)
1289 {
1290         ndmp_lbr_params_t *nlp;
1291 
1292         if ((nlp = ndmp_get_nlp(cookie)) == NULL)
1293                 return (NULL);
1294 
1295         return (nlp->nlp_params);
1296 }
1297 
1298 
1299 /*
1300  * fh_requested
1301  *
1302  * Check in LB parameters if file history is requested
1303  */
1304 static boolean_t
1305 fh_requested(void *cookie)
1306 {
1307         ndmp_lbr_params_t *nlp;
1308 
1309         if ((nlp = ndmp_get_nlp(cookie)) == NULL) {
1310                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1311                 return (FALSE);
1312         }
1313 
1314         NDMP_LOG(LOG_DEBUG, "nlp_fh %c", NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
1315 
1316         return (NLP_ISSET(nlp, NLPF_FH));
1317 }
1318 
1319 
1320 /*
1321  * ndmpd_file_history_path
1322  *
1323  * Generates file history path information posts
1324  *
1325  * Note:
1326  *   Action must be determined when the 'dir' and/or 'file'
1327  *   arguments of ndmpd_file_history_path(), ndmpd_file_history_dir(), and
1328  *   ndmpd_file_history_node() are NULL.
1329  */
1330 /*ARGSUSED*/
1331 int
1332 ndmpd_file_history_path(lbr_fhlog_call_backs_t *cbp, char *path,
1333     struct stat64 *stp, u_longlong_t off)
1334 {
1335         int err;
1336         ndmpd_module_params_t *params;
1337 
1338         if (!cbp) {
1339                 err = -1;
1340                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1341         } else if (!cbp->fh_cookie) {
1342                 err = -1;
1343                 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
1344         } else if (!path) {
1345                 err = -1;
1346                 NDMP_LOG(LOG_DEBUG, "path is NULL");
1347         } else if (!stp) {
1348                 err = -1;
1349                 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1350         } else
1351                 err = 0;
1352 
1353         if (err != 0)
1354                 return (0);
1355 
1356         NDMP_LOG(LOG_DEBUG, "path: \"%s\"", path);
1357 
1358         err = 0;
1359         if (fh_requested(cbp->fh_cookie)) {
1360                 params = get_params(cbp->fh_cookie);
1361                 if (params == NULL || params->mp_file_history_path_func == NULL)
1362                         err = -1;
1363                 else if ((err = (*params->mp_file_history_path_func)(cbp->
1364                     fh_cookie, path, stp, 0)) < 0)
1365                         NDMP_LOG(LOG_DEBUG, "\"%s\": %d", path, err);
1366         }
1367 
1368         return (err);
1369 }
1370 
1371 
1372 /*
1373  * ndmpd_file_history_dir
1374  *
1375  * Generate file history directory information posts
1376  */
1377 int
1378 ndmpd_file_history_dir(lbr_fhlog_call_backs_t *cbp, char *dir,
1379     struct stat64 *stp)
1380 {
1381         char nm[PATH_MAX+1];
1382         int nml;
1383         int err;
1384         ulong_t ino, pino;
1385         ulong_t pos;
1386         ndmp_lbr_params_t *nlp;
1387         ndmpd_module_params_t *params;
1388         DIR *dirp;
1389         char dirpath[PATH_MAX];
1390 
1391         if (!cbp) {
1392                 err = -1;
1393                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1394         } else if (!cbp->fh_cookie) {
1395                 err = -1;
1396                 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
1397         } else if (!dir) {
1398                 err = -1;
1399                 NDMP_LOG(LOG_DEBUG, "dir is NULL");
1400         } else if (!stp) {
1401                 err = -1;
1402                 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1403         } if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1404                 err = -1;
1405                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1406         } else
1407                 err = 0;
1408 
1409         if (err != 0)
1410                 return (0);
1411 
1412         NDMP_LOG(LOG_DEBUG, "dir: \"%s\"", dir);
1413 
1414         if (!fh_requested(cbp->fh_cookie))
1415                 return (0);
1416 
1417         /*
1418          * Veritas net_backup accepts only 2 as the inode number of the backup
1419          * root directory.  The other way compares the path against the
1420          * backup path which is slower.
1421          */
1422         if (stp->st_ino == nlp->nlp_bkdirino)
1423                 pino = ROOT_INODE;
1424         else
1425                 pino = stp->st_ino;
1426 
1427         /*
1428          * There is nothing below this directory to be backed up.
1429          * If there was, the bit for this directory would have
1430          * been set.  Backup root directory is exception.  We
1431          * always send the dir file history records of it.
1432          */
1433         if (pino != ROOT_INODE &&
1434             !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
1435                 NDMP_LOG(LOG_DEBUG, "nothing below here");
1436                 return (0);
1437         }
1438 
1439         params = get_params(cbp->fh_cookie);
1440         if (params == NULL || params->mp_file_history_dir_func == NULL) {
1441                 return (0);
1442         }
1443 
1444         pos = 0;
1445         err = 0;
1446 
1447         dirp = opendir(dir);
1448         if (dirp == NULL)
1449                 return (0);
1450 
1451         do {
1452                 nml = PATH_MAX;
1453                 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
1454                 if (err != 0) {
1455                         NDMP_LOG(LOG_DEBUG,
1456                             "%d reading pos %u dir \"%s\"", err, pos, dir);
1457                         break;
1458                 }
1459                 if (nml == 0)
1460                         break;
1461                 nm[nml] = '\0';
1462 
1463                 if (pino == ROOT_INODE) {
1464                         if (rootfs_dot_or_dotdot(nm))
1465                                 ino = ROOT_INODE;
1466                 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {
1467                         NDMP_LOG(LOG_DEBUG, "nm(%s): %lu", nm, ino);
1468                         ino = ROOT_INODE;
1469                 }
1470 
1471                 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
1472                         continue;
1473 
1474                 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
1475                     ino, pino);
1476                 if (err < 0) {
1477                         NDMP_LOG(LOG_DEBUG, "\"%s/%s\": %d", dir, nm, err);
1478                         break;
1479                 }
1480 
1481                 /*
1482                  * This is a requirement by some DMA's (net_vault) that during
1483                  * the incremental backup, the node info should also be sent
1484                  * along with the dir info for all directories leading to a
1485                  * backed up file.
1486                  */
1487                 if (ndmp_fhinode) {
1488                         struct stat64 ret_attr;
1489 
1490                         (void) strlcpy(dirpath, dir, PATH_MAX);
1491                         (void) strlcat(dirpath, "/", PATH_MAX);
1492                         (void) strlcat(dirpath, nm, PATH_MAX);
1493                         err = stat64(dirpath, &ret_attr);
1494                         if (err != 0) {
1495                                 NDMP_LOG(LOG_DEBUG,
1496                                     "Error looking up %s", nm);
1497                                 break;
1498                         }
1499 
1500                         if (S_ISDIR(ret_attr.st_mode)) {
1501                                 err = (*params->mp_file_history_node_func)(cbp->
1502                                     fh_cookie, ino, &ret_attr, 0);
1503                                 if (err < 0) {
1504                                         NDMP_LOG(LOG_DEBUG, "\"%s/\": %d",
1505                                             dir, err);
1506                                         break;
1507                                 }
1508                         }
1509                 }
1510         } while (err == 0);
1511 
1512         (void) closedir(dirp);
1513         return (err);
1514 }
1515 
1516 
1517 /*
1518  * ndmpd_file_history_node
1519  *
1520  * Generate file history node information posts
1521  */
1522 /*ARGSUSED*/
1523 int
1524 ndmpd_file_history_node(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
1525     struct stat64 *stp, u_longlong_t off)
1526 {
1527         int err;
1528         ulong_t ino;
1529         ndmp_lbr_params_t *nlp;
1530         ndmpd_module_params_t *params;
1531 
1532         if (!cbp) {
1533                 err = -1;
1534                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1535         } else if (!cbp->fh_cookie) {
1536                 err = -1;
1537                 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
1538         } else if (!dir) {
1539                 err = -1;
1540                 NDMP_LOG(LOG_DEBUG, "dir is NULL");
1541         } else if (!file) {
1542                 err = -1;
1543                 NDMP_LOG(LOG_DEBUG, "file is NULL");
1544         } else if (!stp) {
1545                 err = -1;
1546                 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1547         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1548                 err = -1;
1549                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1550         } else
1551                 err = 0;
1552 
1553         if (err != 0)
1554                 return (0);
1555 
1556         NDMP_LOG(LOG_DEBUG, "d(%s), f(%s)", dir, file);
1557 
1558         err = 0;
1559         if (fh_requested(cbp->fh_cookie) == TRUE) {
1560                 if (stp->st_ino == nlp->nlp_bkdirino) {
1561                         ino = ROOT_INODE;
1562                         NDMP_LOG(LOG_DEBUG,
1563                             "bkroot %d -> %d", stp->st_ino, ROOT_INODE);
1564                 } else {
1565                         ino = stp->st_ino;
1566                 }
1567 
1568                 params = get_params(cbp->fh_cookie);
1569                 if (params == NULL || params->mp_file_history_node_func == NULL)
1570                         err = -1;
1571                 else if ((err = (*params->mp_file_history_node_func)(cbp->
1572                     fh_cookie, ino, stp, 0)) < 0)
1573                         NDMP_LOG(LOG_DEBUG, "\"%s/\": %d", dir, file, err);
1574 
1575         }
1576 
1577         return (err);
1578 }
1579 
1580 
1581 /*
1582  * ndmpd_path_restored
1583  *
1584  * Mark the specified path as a restored path
1585  */
1586 /*ARGSUSED*/
1587 int
1588 ndmpd_path_restored(lbr_fhlog_call_backs_t *cbp, char *name, struct stat64 *stp,
1589     u_longlong_t ll_pos)
1590 {
1591         int rv;
1592         ndmp_name *entp;
1593         ndmp_lbr_params_t *nlp;
1594         ndmpd_module_params_t *params;
1595         int pos =  (int)ll_pos;
1596 
1597         if (cbp == NULL) {
1598                 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1599                 return (-1);
1600         }
1601         if (name == NULL) {
1602                 NDMP_LOG(LOG_DEBUG, "name is NULL");
1603                 return (-1);
1604         }
1605 
1606         NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d",
1607             name, pos);
1608 
1609         if ((nlp = ndmp_get_nlp(cbp->fh_cookie)) == NULL) {
1610                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1611                 return (-1);
1612         }
1613         if (pos < 0 || pos >= nlp->nlp_nfiles) {
1614                 NDMP_LOG(LOG_DEBUG, "Invalid pos: %d", pos);
1615                 return (-1);
1616         }
1617         params = get_params(cbp->fh_cookie);
1618         if (params == NULL || params->mp_file_recovered_func == NULL)
1619                 return (-1);
1620 
1621         rv = 0;
1622         if (!nlp->nlp_restored[pos]) {
1623                 entp = (ndmp_name *)MOD_GETNAME(params, pos);
1624                 if (entp && entp->name)
1625                         name = entp->name;
1626 
1627                 if ((rv = MOD_FILERECOVERD(params, name, 0)) >= 0)
1628                         nlp->nlp_restored[pos] = TRUE;
1629         }
1630 
1631         return (rv);
1632 }
1633 
1634 




  20  *
  21  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  22  *        nor the names of its contributors may be used to endorse or promote
  23  *        products derived from this software without specific prior written
  24  *        permission.
  25  *
  26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36  * POSSIBILITY OF SUCH DAMAGE.
  37  */
  38 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  40 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
  41 
  42 /*
  43  * File history callback functions called by backup modules. NDMP file history
  44  * supports 2 file history models: path based and inode/directory based.
  45  * Backup/recover modules similar to unix dump/restore utilize the
  46  * inode/directory based model. During the filesystem scan pass,
  47  * ndmpd_file_history_dir() is called. During the file backup pass,
  48  * ndmpd_file_history_node() is called. This model is appropriate for
  49  * modules whose code is structured such that file name and file attribute
  50  * data is not available at the same time. Backup/recover modules similar
  51  * to tar or cpio utilize the path based model. The simple dump/restore module
  52  * included with the SDK uses the path based model.
  53  */
  54 
  55 #include <sys/stat.h>
  56 #include <sys/types.h>
  57 #include <syslog.h>
  58 #include <dirent.h>
  59 #include <errno.h>
  60 #include <stdlib.h>
  61 #include <string.h>
  62 #include "ndmpd.h"
  63 #include <dirent.h>
  64 #include <bitmap.h>
  65 
  66 
  67 #define N_PATH_ENTRIES  1000
  68 #define N_FILE_ENTRIES  N_PATH_ENTRIES
  69 #define N_DIR_ENTRIES   1000
  70 #define N_NODE_ENTRIES  1000
  71 
  72 /* Figure an average of 32 bytes per path name */
  73 #define PATH_NAMEBUF_SIZE       (N_PATH_ENTRIES * 32)
  74 
  75 /* Figure an average of 16 bytes per file name */
  76 #define DIR_NAMEBUF_SIZE        (N_PATH_ENTRIES * 16)
  77 


 119     struct stat64 *file_stat, u_longlong_t fh_info)
 120 {
 121         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 122         ndmp_fh_unix_path *entry;
 123 
 124         if (name == NULL && session->ns_fh.fh_path_index == 0)
 125                 return (0);
 126 
 127         /*
 128          * If the buffer does not have space
 129          * for the current entry, send the buffered data to the client.
 130          * A NULL name indicates that any buffered data should be sent.
 131          */
 132         if (name == NULL ||
 133             (ndmp_syncfh && session->ns_fh.fh_path_index != 0) ||
 134             session->ns_fh.fh_path_index == N_PATH_ENTRIES ||
 135             session->ns_fh.fh_path_name_buf_index + strlen(name) + 1 >
 136             PATH_NAMEBUF_SIZE) {
 137                 ndmp_fh_add_unix_path_request request;
 138 


 139 
 140                 request.paths.paths_val = session->ns_fh.fh_path_entries;
 141                 request.paths.paths_len = session->ns_fh.fh_path_index;
 142 
 143                 if (ndmp_send_request_lock(session->ns_connection,
 144                     NDMP_FH_ADD_UNIX_PATH, NDMP_NO_ERR, (void *) &request,
 145                     0) < 0) {
 146                         syslog(LOG_ERR, "Sending file history data failed");
 147                         return (-1);
 148                 }
 149                 session->ns_fh.fh_path_index = 0;
 150                 session->ns_fh.fh_path_name_buf_index = 0;
 151         }
 152         if (name == NULL)
 153                 return (0);
 154 
 155         if (session->ns_fh.fh_path_entries == 0) {
 156                 session->ns_fh.fh_path_entries = ndmp_malloc(N_PATH_ENTRIES *
 157                     sizeof (ndmp_fh_unix_path));
 158                 if (session->ns_fh.fh_path_entries == 0)
 159                         return (-1);
 160         }
 161         if (session->ns_fh.fh_path_name_buf == 0) {
 162                 session->ns_fh.fh_path_name_buf =
 163                     ndmp_malloc(PATH_NAMEBUF_SIZE);
 164                 if (session->ns_fh.fh_path_name_buf == 0)
 165                         return (-1);
 166         }


 209     ulong_t parent)
 210 {
 211         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 212         ndmp_fh_unix_dir *entry;
 213 
 214         if (name == NULL && session->ns_fh.fh_dir_index == 0)
 215                 return (0);
 216 
 217         /*
 218          * If the buffer does not have space for the current entry,
 219          * send the buffered data to the client. A NULL name indicates
 220          * that any buffered data should be sent.
 221          */
 222         if (name == NULL ||
 223             (ndmp_syncfh && session->ns_fh.fh_dir_index != 0) ||
 224             session->ns_fh.fh_dir_index == N_DIR_ENTRIES ||
 225             session->ns_fh.fh_dir_name_buf_index + strlen(name) + 1 >
 226             DIR_NAMEBUF_SIZE) {
 227                 ndmp_fh_add_unix_dir_request request;
 228 



 229                 request.dirs.dirs_val = session->ns_fh.fh_dir_entries;
 230                 request.dirs.dirs_len = session->ns_fh.fh_dir_index;
 231                 if (ndmp_send_request_lock(session->ns_connection,
 232                     NDMP_FH_ADD_UNIX_DIR, NDMP_NO_ERR, (void *) &request,
 233                     0) < 0) {
 234                         syslog(LOG_DEBUG, "Sending file history data");
 235                         return (-1);
 236                 }
 237                 session->ns_fh.fh_dir_index = 0;
 238                 session->ns_fh.fh_dir_name_buf_index = 0;
 239         }
 240         if (name == NULL)
 241                 return (0);
 242 
 243         if (session->ns_fh.fh_dir_entries == 0) {
 244                 session->ns_fh.fh_dir_entries = ndmp_malloc(N_DIR_ENTRIES
 245                     * sizeof (ndmp_fh_unix_dir));
 246                 if (session->ns_fh.fh_dir_entries == 0)
 247                         return (-1);
 248         }
 249         if (session->ns_fh.fh_dir_name_buf == 0) {
 250                 session->ns_fh.fh_dir_name_buf = ndmp_malloc(DIR_NAMEBUF_SIZE);
 251                 if (session->ns_fh.fh_dir_name_buf == 0)
 252                         return (-1);
 253         }
 254         entry = &session->ns_fh.fh_dir_entries[session->ns_fh.fh_dir_index];


 293 ndmpd_api_file_history_node_v2(void *cookie, ulong_t node,
 294     struct stat64 *file_stat, u_longlong_t fh_info)
 295 {
 296         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 297         ndmp_fh_unix_node *entry;
 298 
 299         if (file_stat == NULL && session->ns_fh.fh_node_index == 0)
 300                 return (-1);
 301 
 302         /*
 303          * If the buffer does not have space
 304          * for the current entry, send the buffered data to the client.
 305          * A 0 file_stat pointer indicates that any buffered data should
 306          * be sent.
 307          */
 308         if (file_stat == NULL ||
 309             (ndmp_syncfh && session->ns_fh.fh_node_index != 0) ||
 310             session->ns_fh.fh_node_index == N_NODE_ENTRIES) {
 311                 ndmp_fh_add_unix_node_request request;
 312 



 313                 request.nodes.nodes_val = session->ns_fh.fh_node_entries;
 314                 request.nodes.nodes_len = session->ns_fh.fh_node_index;
 315                 /*
 316                  * Need to send Dir entry as well. Since Dir entry is more than
 317                  * Node entry, we may send a Node entry that hasn't have
 318                  * its dir entry sent. Therefore, we need to flush Dir entry
 319                  * as well everytime the Dir entry is send.
 320                  */
 321                 (void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0);
 322 
 323                 if (ndmp_send_request_lock(session->ns_connection,
 324                     NDMP_FH_ADD_UNIX_NODE, NDMP_NO_ERR, (void *) &request,
 325                     0) < 0) {
 326                         syslog(LOG_ERR, "Sending file history data failed");
 327                         return (-1);
 328                 }
 329                 session->ns_fh.fh_node_index = 0;
 330         }
 331         if (file_stat == NULL)
 332                 return (0);
 333 
 334         if (session->ns_fh.fh_node_entries == 0) {
 335                 session->ns_fh.fh_node_entries = ndmp_malloc(N_NODE_ENTRIES
 336                     * sizeof (ndmp_fh_unix_node));
 337                 if (session->ns_fh.fh_node_entries == 0)
 338                         return (-1);
 339         }
 340         entry = &session->ns_fh.fh_node_entries[session->ns_fh.fh_node_index];
 341         ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype);
 342 
 343         entry->node = node;
 344         entry->fstat.mtime = (ulong_t)file_stat->st_mtime;
 345         entry->fstat.atime = (ulong_t)file_stat->st_atime;
 346         entry->fstat.ctime = (ulong_t)file_stat->st_ctime;


 386 {
 387         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 388         ndmp_file_v3 *file_entry;
 389         ndmp_file_name_v3 *file_name_entry;
 390         ndmp_file_stat_v3 *file_stat_entry;
 391         ndmp_fh_add_file_request_v3 request;
 392 
 393         if (name == NULL && session->ns_fh_v3.fh_file_index == 0)
 394                 return (0);
 395 
 396         /*
 397          * If the buffer does not have space
 398          * for the current entry, send the buffered data to the client.
 399          * A NULL name indicates that any buffered data should be sent.
 400          */
 401         if (name == NULL ||
 402             session->ns_fh_v3.fh_file_index == N_FILE_ENTRIES ||
 403             session->ns_fh_v3.fh_file_name_buf_index + strlen(name) + 1 >
 404             PATH_NAMEBUF_SIZE) {
 405 



 406                 request.files.files_len = session->ns_fh_v3.fh_file_index;
 407                 request.files.files_val = session->ns_fh_v3.fh_files;
 408 
 409                 if (ndmp_send_request_lock(session->ns_connection,
 410                     NDMP_FH_ADD_FILE, NDMP_NO_ERR, (void *) &request, 0) < 0) {
 411                         syslog(LOG_ERR,
 412                             "Sending ndmp_fh_add_file request failed");
 413                         return (-1);
 414                 }
 415 
 416                 session->ns_fh_v3.fh_file_index = 0;
 417                 session->ns_fh_v3.fh_file_name_buf_index = 0;
 418         }
 419 
 420         if (name == NULL)
 421                 return (0);
 422 
 423         if (session->ns_fh_v3.fh_files == 0) {
 424                 session->ns_fh_v3.fh_files = ndmp_malloc(sizeof (ndmp_file_v3) *
 425                     N_FILE_ENTRIES);
 426                 if (session->ns_fh_v3.fh_files == 0)
 427                         return (-1);
 428         }
 429 
 430         if (session->ns_fh_v3.fh_file_names == 0) {
 431                 session->ns_fh_v3.fh_file_names =
 432                     ndmp_malloc(sizeof (ndmp_file_name_v3) * N_FILE_ENTRIES);


 513     ulong_t parent)
 514 {
 515         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 516         ndmp_dir_v3 *dir_entry;
 517         ndmp_file_name_v3 *dir_name_entry;
 518         ndmp_fh_add_dir_request_v3 request;
 519 
 520         if (name == NULL && session->ns_fh_v3.fh_dir_index == 0)
 521                 return (0);
 522 
 523         /*
 524          * If the buffer does not have space
 525          * for the current entry, send the buffered data to the client.
 526          * A NULL name indicates that any buffered data should be sent.
 527          */
 528         if (name == NULL ||
 529             session->ns_fh_v3.fh_dir_index == N_DIR_ENTRIES ||
 530             session->ns_fh_v3.fh_dir_name_buf_index + strlen(name) + 1 >
 531             DIR_NAMEBUF_SIZE) {
 532 



 533                 request.dirs.dirs_val = session->ns_fh_v3.fh_dirs;
 534                 request.dirs.dirs_len = session->ns_fh_v3.fh_dir_index;
 535 
 536                 if (ndmp_send_request_lock(session->ns_connection,
 537                     NDMP_FH_ADD_DIR, NDMP_NO_ERR, (void *) &request, 0) < 0) {
 538                         syslog(LOG_ERR,
 539                             "Sending ndmp_fh_add_dir request failed");
 540                         return (-1);
 541                 }
 542 
 543                 session->ns_fh_v3.fh_dir_index = 0;
 544                 session->ns_fh_v3.fh_dir_name_buf_index = 0;
 545         }
 546 
 547         if (name == NULL)
 548                 return (0);
 549 
 550         if (session->ns_fh_v3.fh_dirs == 0) {
 551                 session->ns_fh_v3.fh_dirs =
 552                     ndmp_malloc(sizeof (ndmp_dir_v3) * N_DIR_ENTRIES);
 553                 if (session->ns_fh_v3.fh_dirs == 0)
 554                         return (-1);
 555         }
 556 
 557         if (session->ns_fh_v3.fh_dir_names == 0) {
 558                 session->ns_fh_v3.fh_dir_names =
 559                     ndmp_malloc(sizeof (ndmp_file_name_v3) * N_DIR_ENTRIES);


 616 int
 617 ndmpd_api_file_history_node_v3(void *cookie, ulong_t node,
 618     struct stat64 *file_stat, u_longlong_t fh_info)
 619 {
 620         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 621         ndmp_node_v3 *node_entry;
 622         ndmp_file_stat_v3 *file_stat_entry;
 623         ndmp_fh_add_node_request_v3 request;
 624 
 625         if (file_stat == NULL && session->ns_fh_v3.fh_node_index == 0)
 626                 return (0);
 627 
 628         /*
 629          * If the buffer does not have space
 630          * for the current entry, send the buffered data to the client.
 631          * A 0 file_stat pointer indicates that any buffered data should
 632          * be sent.
 633          */
 634         if (file_stat == NULL ||
 635             session->ns_fh_v3.fh_node_index == N_NODE_ENTRIES) {


 636 
 637                 /*
 638                  * Need to send Dir entry as well. Since Dir entry is more
 639                  * than a Node entry, we may send a Node entry that hasn't
 640                  * had its Dir entry sent. Therefore, we need to flush Dir
 641                  * entry as well every time the Dir entry is sent.
 642                  */
 643                 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);
 644 
 645                 request.nodes.nodes_len = session->ns_fh_v3.fh_node_index;
 646                 request.nodes.nodes_val = session->ns_fh_v3.fh_nodes;
 647 
 648                 if (ndmp_send_request_lock(session->ns_connection,
 649                     NDMP_FH_ADD_NODE,
 650                     NDMP_NO_ERR, (void *) &request, 0) < 0) {
 651                         syslog(LOG_ERR,
 652                             "Sending ndmp_fh_add_node request failed");
 653                         return (-1);
 654                 }
 655 
 656                 session->ns_fh_v3.fh_node_index = 0;
 657         }
 658 
 659         if (file_stat == NULL)
 660                 return (0);
 661 
 662         if (session->ns_fh_v3.fh_nodes == 0) {
 663                 session->ns_fh_v3.fh_nodes =
 664                     ndmp_malloc(sizeof (ndmp_node_v3) * N_NODE_ENTRIES);
 665                 if (session->ns_fh_v3.fh_nodes == 0)
 666                         return (-1);
 667         }
 668 
 669         if (session->ns_fh_v3.fh_node_stats == 0) {
 670                 session->ns_fh_v3.fh_node_stats =
 671                     ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_NODE_ENTRIES);
 672                 if (session->ns_fh_v3.fh_node_stats == 0)


 708  * NDMP V4 HANDLERS
 709  * ************************************************************************
 710  */
 711 
 712 
 713 /*
 714  * ndmpd_fhpath_v3_cb
 715  *
 716  * Callback function for file history path information
 717  */
 718 int
 719 ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t *cbp, char *path, struct stat64 *stp,
 720     u_longlong_t off)
 721 {
 722         int err;
 723         ndmp_lbr_params_t *nlp;
 724         ndmpd_module_params_t *params;
 725 
 726         if (!cbp) {
 727                 err = -1;
 728                 syslog(LOG_DEBUG, "cbp is NULL");
 729         } else if (!cbp->fh_cookie) {
 730                 err = -1;
 731                 syslog(LOG_DEBUG, "cookie is NULL");
 732         } else if (!path) {
 733                 err = -1;
 734                 syslog(LOG_DEBUG, "path is NULL");
 735         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
 736                 err = -1;
 737                 syslog(LOG_DEBUG, "nlp is NULL");
 738         } else
 739                 err = 0;
 740 
 741         if (err != 0)
 742                 return (0);
 743 


 744         err = 0;
 745         if (NLP_ISSET(nlp, NLPF_FH)) {
 746                 if (!NLP_ISSET(nlp, NLPF_DIRECT)) {
 747                         syslog(LOG_DEBUG, "DAR NOT SET!");
 748                         off = 0LL;
 749                 }
 750 
 751                 params = get_params(cbp->fh_cookie);
 752                 if (!params || !params->mp_file_history_path_func) {
 753                         err = -1;
 754                 } else {
 755                         char *p =
 756                             ndmp_get_relative_path(get_backup_path_v3(params),
 757                             path);
 758                         if ((err = ndmpd_api_file_history_file_v3(cbp->
 759                             fh_cookie, p, stp, off)) < 0)
 760                                 syslog(LOG_DEBUG, "\"%s\" %d", path, err);
 761                 }
 762         }
 763 
 764         return (err);
 765 }
 766 
 767 
 768 /*
 769  * ndmpd_fhdir_v3_cb
 770  *
 771  * Callback function for file history dir information
 772  */
 773 int
 774 ndmpd_fhdir_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, struct stat64 *stp)
 775 {
 776         char nm[PATH_MAX+1];
 777         int nml;
 778         int err;
 779         ulong_t ino, pino;
 780         ulong_t pos;
 781         ndmp_lbr_params_t *nlp;
 782         ndmpd_module_params_t *params;
 783         DIR *dirp;
 784         char dirpath[PATH_MAX];
 785 
 786         if (!cbp) {
 787                 err = -1;
 788                 syslog(LOG_DEBUG, "cbp is NULL");
 789         } else if (!cbp->fh_cookie) {
 790                 err = -1;
 791                 syslog(LOG_DEBUG, "cookie is NULL");
 792         } else if (!dir) {
 793                 err = -1;
 794                 syslog(LOG_DEBUG, "dir is NULL");
 795         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
 796                 err = -1;
 797                 syslog(LOG_DEBUG, "nlp is NULL");
 798         } else
 799                 err = 0;
 800 
 801         if (err != 0)
 802                 return (0);
 803 


 804         if (!NLP_ISSET(nlp, NLPF_FH))
 805                 return (0);
 806 
 807         /*
 808          * Veritas net_backup accepts only 2 as the inode number of the backup
 809          * root directory.  The other way compares the path against the
 810          * backup path which is slower.
 811          */
 812         if (stp->st_ino == nlp->nlp_bkdirino)
 813                 pino = ROOT_INODE;
 814         else
 815                 pino = stp->st_ino;
 816 
 817         /*
 818          * There is nothing below this directory to be backed up.
 819          * If there was, the bit for this directory would have
 820          * been set.  Backup root directory is exception.  We
 821          * always send the dir file history records of it.
 822          */
 823         if (pino != ROOT_INODE &&
 824             !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
 825                 syslog(LOG_DEBUG, "nothing below here");
 826                 return (0);
 827         }
 828 
 829         params = nlp->nlp_params;
 830         if (!params || !params->mp_file_history_dir_func)
 831                 return (-1);
 832 
 833         pos = 0;
 834         err = 0;
 835 
 836         dirp = opendir(dir);
 837         if (dirp == NULL)
 838                 return (0);
 839 
 840         do {
 841                 nml = PATH_MAX;
 842                 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
 843                 if (err != 0) {
 844                         syslog(LOG_DEBUG,
 845                             "%d reading pos %u dir \"%s\"", err, pos, dir);
 846                         break;
 847                 }
 848                 if (nml == 0)
 849                         break;
 850                 nm[nml] = '\0';
 851 
 852                 if (pino == ROOT_INODE) {
 853                         if (rootfs_dot_or_dotdot(nm))
 854                                 ino = ROOT_INODE;
 855                 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {

 856                         ino = ROOT_INODE;
 857                 }
 858 
 859                 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
 860                         continue;
 861 
 862                 /*
 863                  * If the entry is on exclusion list dont send the info
 864                  */
 865                 if (tlm_is_excluded(dir, nm, ndmp_excl_list)) {
 866                         syslog(LOG_DEBUG,
 867                             "name \"%s\" skipped", *nm == '\0' ? "nil" : nm);
 868                         continue;
 869                 }
 870 
 871                 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
 872                     ino, pino);
 873                 if (err < 0) {
 874                         syslog(LOG_ERR, "\"%s\": %d", dir, err);
 875                         break;
 876                 }
 877 
 878                 /*
 879                  * This is a requirement by some DMA's (net_vault) that during
 880                  * the incremental backup, the node info should also be sent
 881                  * along with the dir info for all directories leading to a
 882                  * backed up file.
 883                  */
 884                 if (ndmp_fhinode) {
 885                         struct stat64 ret_attr;
 886 
 887                         (void) strlcpy(dirpath, dir, PATH_MAX);
 888                         (void) strlcat(dirpath, "/", PATH_MAX);
 889                         (void) strlcat(dirpath, nm, PATH_MAX);
 890                         err = stat64(dirpath, &ret_attr);
 891                         if (err != 0) {
 892                                 syslog(LOG_ERR,
 893                                     "Error looking up %s", nm);
 894                                 break;
 895                         }
 896 
 897                         if (S_ISDIR(ret_attr.st_mode)) {
 898                                 err = (*params->mp_file_history_node_func)(cbp->
 899                                     fh_cookie, ino, &ret_attr, 0);
 900                                 if (err < 0) {
 901                                         syslog(LOG_ERR, "\"%s/\": %d",
 902                                             dir, err);
 903                                         break;
 904                                 }
 905                         }
 906                 }
 907         } while (err == 0);
 908 
 909         (void) closedir(dirp);
 910         return (err);
 911 }
 912 
 913 
 914 /*
 915  * ndmpd_fhnode_v3_cb
 916  *
 917  * Callback function for file history node information
 918  */
 919 int
 920 ndmpd_fhnode_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
 921     struct stat64 *stp, u_longlong_t off)
 922 {
 923         int err;
 924         ulong_t ino;
 925         ndmp_lbr_params_t *nlp;
 926         ndmpd_module_params_t *params;
 927 
 928         if (!cbp) {
 929                 err = -1;
 930                 syslog(LOG_DEBUG, "cbp is NULL");
 931         } else if (!cbp->fh_cookie) {
 932                 err = -1;
 933                 syslog(LOG_DEBUG, "cookie is NULL");
 934         } else if (!dir) {
 935                 err = -1;
 936                 syslog(LOG_DEBUG, "dir is NULL");
 937         } else if (!file) {
 938                 err = -1;
 939                 syslog(LOG_DEBUG, "file is NULL");
 940         } else if (!stp) {
 941                 err = -1;
 942                 syslog(LOG_DEBUG, "stp is NULL");
 943         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
 944                 err = -1;
 945                 syslog(LOG_DEBUG, "nlp is NULL");
 946         } else {
 947                 err = 0;
 948         }
 949 
 950         if (err != 0)
 951                 return (0);
 952 

 953 
 954         err = 0;
 955         if (NLP_ISSET(nlp, NLPF_FH)) {
 956                 if (!NLP_ISSET(nlp, NLPF_DIRECT))
 957                         off = 0LL;
 958                 if (stp->st_ino == nlp->nlp_bkdirino) {
 959                         ino = ROOT_INODE;


 960                 } else
 961                         ino = stp->st_ino;
 962 
 963                 params = nlp->nlp_params;
 964                 if (!params || !params->mp_file_history_node_func)
 965                         err = -1;
 966                 else if ((err = (*params->mp_file_history_node_func)(cbp->
 967                     fh_cookie, ino, stp, off)) < 0)
 968                         syslog(LOG_ERR, "\"%s/%s\" %d", dir, file, err);
 969         }
 970 
 971         return (err);
 972 }
 973 
 974 
 975 /*
 976  * ndmp_send_recovery_stat_v3
 977  *
 978  * Send the recovery status to the DMA
 979  */
 980 int
 981 ndmp_send_recovery_stat_v3(ndmpd_module_params_t *params,
 982     ndmp_lbr_params_t *nlp, int idx, int stat)
 983 {
 984         int rv;
 985         mem_ndmp_name_v3_t *ep;
 986 
 987         rv = -1;
 988         if (!params) {
 989                 syslog(LOG_DEBUG, "params == NULL");
 990         } else if (!params->mp_file_recovered_func) {
 991                 syslog(LOG_DEBUG, "paramsfile_recovered_func == NULL");
 992         } else if (!nlp) {
 993                 syslog(LOG_DEBUG, "nlp == NULL");
 994         } else if (idx < 0) {
 995                 syslog(LOG_DEBUG, "idx(%d) < 0", idx);
 996         } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, idx))) {
 997                 syslog(LOG_DEBUG, "nlist[%d] == NULL", idx);
 998         } else if (!ep->nm3_opath) {
 999                 syslog(LOG_DEBUG, "nlist[%d].nm3_opath == NULL", idx);
1000         } else {
1001                 syslog(LOG_DEBUG,
1002                     "ep[%d].nm3_opath \"%s\"", idx, ep->nm3_opath);
1003                 rv = MOD_FILERECOVERD(params, ep->nm3_opath, stat);
1004         }
1005 
1006         return (rv);
1007 }
1008 
1009 
1010 /*
1011  * ndmpd_path_restored_v3
1012  *
1013  * Send the recovery status and the information for the restored
1014  * path.
1015  */
1016 /*ARGSUSED*/
1017 int
1018 ndmpd_path_restored_v3(lbr_fhlog_call_backs_t *cbp, char *name,
1019     struct stat64 *st, u_longlong_t ll_idx)
1020 {
1021         int rv;
1022         ndmp_lbr_params_t *nlp;
1023         ndmpd_module_params_t *params;
1024         int idx = (int)ll_idx;
1025 
1026         if (!cbp) {
1027                 syslog(LOG_DEBUG, "cbp is NULL");
1028                 return (-1);
1029         }
1030         if (!name) {
1031                 syslog(LOG_DEBUG, "name is NULL");
1032                 return (-1);
1033         }
1034 


1035         nlp = ndmp_get_nlp(cbp->fh_cookie);
1036         if (!nlp) {
1037                 syslog(LOG_DEBUG, "nlp is NULL");
1038                 return (-1);
1039         }
1040         if (idx < 0 || idx >= nlp->nlp_nfiles) {
1041                 syslog(LOG_DEBUG, "Invalid idx: %d", idx);
1042                 return (-1);
1043         }
1044         params = nlp->nlp_params;
1045         if (!params || !params->mp_file_recovered_func)
1046                 return (-1);
1047 
1048         if (nlp->nlp_lastidx == -1)
1049                 nlp->nlp_lastidx = idx;
1050 
1051         rv = 0;
1052         (void) bm_setone(nlp->nlp_rsbm, (u_longlong_t)idx);
1053         /*
1054          * Note: We should set the nm3_err here.
1055          */
1056         if (nlp->nlp_lastidx != idx) {
1057                 rv = ndmp_send_recovery_stat_v3(params, nlp, nlp->nlp_lastidx,
1058                     0);
1059                 nlp->nlp_lastidx = idx;
1060         }
1061 


1233 
1234 
1235 /*
1236  * ndmpd_file_history_cleanup
1237  *
1238  * Send any pending posts and clean up
1239  */
1240 void
1241 ndmpd_file_history_cleanup(ndmpd_session_t *session, boolean_t send_flag)
1242 {
1243         switch (session->ns_protocol_version) {
1244         case 1:
1245         case 2:
1246                 ndmpd_file_history_cleanup_v2(session, send_flag);
1247                 break;
1248         case 3:
1249         case 4:
1250                 ndmpd_file_history_cleanup_v3(session, send_flag);
1251                 break;
1252         default:
1253                 syslog(LOG_ERR, "Unknown version %d",
1254                     session->ns_protocol_version);
1255         }
1256 }
1257 
1258 /*
1259  * get_params
1260  *
1261  * Callbacks from LBR.
1262  */
1263 static ndmpd_module_params_t *
1264 get_params(void *cookie)
1265 {
1266         ndmp_lbr_params_t *nlp;
1267 
1268         if ((nlp = ndmp_get_nlp(cookie)) == NULL)
1269                 return (NULL);
1270 
1271         return (nlp->nlp_params);
1272 }
1273 
1274 
1275 /*
1276  * fh_requested
1277  *
1278  * Check in LB parameters if file history is requested
1279  */
1280 static boolean_t
1281 fh_requested(void *cookie)
1282 {
1283         ndmp_lbr_params_t *nlp;
1284 
1285         if ((nlp = ndmp_get_nlp(cookie)) == NULL) {
1286                 syslog(LOG_DEBUG, "nlp is NULL");
1287                 return (FALSE);
1288         }
1289 
1290         syslog(LOG_DEBUG, "nlp_fh %c", NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
1291 
1292         return (NLP_ISSET(nlp, NLPF_FH));
1293 }
1294 
1295 
1296 /*
1297  * ndmpd_file_history_path
1298  *
1299  * Generates file history path information posts
1300  *
1301  * Note:
1302  *   Action must be determined when the 'dir' and/or 'file'
1303  *   arguments of ndmpd_file_history_path(), ndmpd_file_history_dir(), and
1304  *   ndmpd_file_history_node() are NULL.
1305  */
1306 /*ARGSUSED*/
1307 int
1308 ndmpd_file_history_path(lbr_fhlog_call_backs_t *cbp, char *path,
1309     struct stat64 *stp, u_longlong_t off)
1310 {
1311         int err;
1312         ndmpd_module_params_t *params;
1313 
1314         if (!cbp) {
1315                 err = -1;
1316                 syslog(LOG_DEBUG, "cbp is NULL");
1317         } else if (!cbp->fh_cookie) {
1318                 err = -1;
1319                 syslog(LOG_DEBUG, "cookie is NULL");
1320         } else if (!path) {
1321                 err = -1;
1322                 syslog(LOG_DEBUG, "path is NULL");
1323         } else if (!stp) {
1324                 err = -1;
1325                 syslog(LOG_DEBUG, "stp is NULL");
1326         } else
1327                 err = 0;
1328 
1329         if (err != 0)
1330                 return (0);
1331 
1332         syslog(LOG_DEBUG, "path: \"%s\"", path);
1333 
1334         err = 0;
1335         if (fh_requested(cbp->fh_cookie)) {
1336                 params = get_params(cbp->fh_cookie);
1337                 if (params == NULL || params->mp_file_history_path_func == NULL)
1338                         err = -1;
1339                 else if ((err = (*params->mp_file_history_path_func)(cbp->
1340                     fh_cookie, path, stp, 0)) < 0)
1341                         syslog(LOG_DEBUG, "\"%s\": %d", path, err);
1342         }
1343 
1344         return (err);
1345 }
1346 
1347 
1348 /*
1349  * ndmpd_file_history_dir
1350  *
1351  * Generate file history directory information posts
1352  */
1353 int
1354 ndmpd_file_history_dir(lbr_fhlog_call_backs_t *cbp, char *dir,
1355     struct stat64 *stp)
1356 {
1357         char nm[PATH_MAX+1];
1358         int nml;
1359         int err;
1360         ulong_t ino, pino;
1361         ulong_t pos;
1362         ndmp_lbr_params_t *nlp;
1363         ndmpd_module_params_t *params;
1364         DIR *dirp;
1365         char dirpath[PATH_MAX];
1366 
1367         if (!cbp) {
1368                 err = -1;
1369                 syslog(LOG_DEBUG, "cbp is NULL");
1370         } else if (!cbp->fh_cookie) {
1371                 err = -1;
1372                 syslog(LOG_DEBUG, "cookie is NULL");
1373         } else if (!dir) {
1374                 err = -1;
1375                 syslog(LOG_DEBUG, "dir is NULL");
1376         } else if (!stp) {
1377                 err = -1;
1378                 syslog(LOG_DEBUG, "stp is NULL");
1379         } if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1380                 err = -1;
1381                 syslog(LOG_DEBUG, "nlp is NULL");
1382         } else
1383                 err = 0;
1384 
1385         if (err != 0)
1386                 return (0);
1387 
1388         syslog(LOG_DEBUG, "dir: \"%s\"", dir);
1389 
1390         if (!fh_requested(cbp->fh_cookie))
1391                 return (0);
1392 
1393         /*
1394          * Veritas net_backup accepts only 2 as the inode number of the backup
1395          * root directory.  The other way compares the path against the
1396          * backup path which is slower.
1397          */
1398         if (stp->st_ino == nlp->nlp_bkdirino)
1399                 pino = ROOT_INODE;
1400         else
1401                 pino = stp->st_ino;
1402 
1403         /*
1404          * There is nothing below this directory to be backed up.
1405          * If there was, the bit for this directory would have
1406          * been set.  Backup root directory is exception.  We
1407          * always send the dir file history records of it.
1408          */
1409         if (pino != ROOT_INODE &&
1410             !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
1411                 syslog(LOG_DEBUG, "nothing below here");
1412                 return (0);
1413         }
1414 
1415         params = get_params(cbp->fh_cookie);
1416         if (params == NULL || params->mp_file_history_dir_func == NULL) {
1417                 return (0);
1418         }
1419 
1420         pos = 0;
1421         err = 0;
1422 
1423         dirp = opendir(dir);
1424         if (dirp == NULL)
1425                 return (0);
1426 
1427         do {
1428                 nml = PATH_MAX;
1429                 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
1430                 if (err != 0) {
1431                         syslog(LOG_DEBUG,
1432                             "%d reading pos %u dir \"%s\"", err, pos, dir);
1433                         break;
1434                 }
1435                 if (nml == 0)
1436                         break;
1437                 nm[nml] = '\0';
1438 
1439                 if (pino == ROOT_INODE) {
1440                         if (rootfs_dot_or_dotdot(nm))
1441                                 ino = ROOT_INODE;
1442                 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {
1443                         syslog(LOG_DEBUG, "nm(%s): %lu", nm, ino);
1444                         ino = ROOT_INODE;
1445                 }
1446 
1447                 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
1448                         continue;
1449 
1450                 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
1451                     ino, pino);
1452                 if (err < 0) {
1453                         syslog(LOG_ERR, "\"%s/%s\": %d", dir, nm, err);
1454                         break;
1455                 }
1456 
1457                 /*
1458                  * This is a requirement by some DMA's (net_vault) that during
1459                  * the incremental backup, the node info should also be sent
1460                  * along with the dir info for all directories leading to a
1461                  * backed up file.
1462                  */
1463                 if (ndmp_fhinode) {
1464                         struct stat64 ret_attr;
1465 
1466                         (void) strlcpy(dirpath, dir, PATH_MAX);
1467                         (void) strlcat(dirpath, "/", PATH_MAX);
1468                         (void) strlcat(dirpath, nm, PATH_MAX);
1469                         err = stat64(dirpath, &ret_attr);
1470                         if (err != 0) {
1471                                 syslog(LOG_ERR,
1472                                     "Error looking up %s failed", nm);
1473                                 break;
1474                         }
1475 
1476                         if (S_ISDIR(ret_attr.st_mode)) {
1477                                 err = (*params->mp_file_history_node_func)(cbp->
1478                                     fh_cookie, ino, &ret_attr, 0);
1479                                 if (err < 0) {
1480                                         syslog(LOG_DEBUG, "\"%s/\": %d",
1481                                             dir, err);
1482                                         break;
1483                                 }
1484                         }
1485                 }
1486         } while (err == 0);
1487 
1488         (void) closedir(dirp);
1489         return (err);
1490 }
1491 
1492 
1493 /*
1494  * ndmpd_file_history_node
1495  *
1496  * Generate file history node information posts
1497  */
1498 /*ARGSUSED*/
1499 int
1500 ndmpd_file_history_node(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
1501     struct stat64 *stp, u_longlong_t off)
1502 {
1503         int err;
1504         ulong_t ino;
1505         ndmp_lbr_params_t *nlp;
1506         ndmpd_module_params_t *params;
1507 
1508         if (!cbp) {
1509                 err = -1;
1510                 syslog(LOG_DEBUG, "cbp is NULL");
1511         } else if (!cbp->fh_cookie) {
1512                 err = -1;
1513                 syslog(LOG_DEBUG, "cookie is NULL");
1514         } else if (!dir) {
1515                 err = -1;
1516                 syslog(LOG_DEBUG, "dir is NULL");
1517         } else if (!file) {
1518                 err = -1;
1519                 syslog(LOG_DEBUG, "file is NULL");
1520         } else if (!stp) {
1521                 err = -1;
1522                 syslog(LOG_DEBUG, "stp is NULL");
1523         } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1524                 err = -1;
1525                 syslog(LOG_DEBUG, "nlp is NULL");
1526         } else
1527                 err = 0;
1528 
1529         if (err != 0)
1530                 return (0);
1531 


1532         err = 0;
1533         if (fh_requested(cbp->fh_cookie) == TRUE) {
1534                 if (stp->st_ino == nlp->nlp_bkdirino) {
1535                         ino = ROOT_INODE;


1536                 } else {
1537                         ino = stp->st_ino;
1538                 }
1539 
1540                 params = get_params(cbp->fh_cookie);
1541                 if (params == NULL || params->mp_file_history_node_func == NULL)
1542                         err = -1;
1543                 else if ((err = (*params->mp_file_history_node_func)(cbp->
1544                     fh_cookie, ino, stp, 0)) < 0)
1545                         syslog(LOG_DEBUG, "\"%s/\": %d", dir, file, err);
1546 
1547         }
1548 
1549         return (err);
1550 }
1551 
1552 
1553 /*
1554  * ndmpd_path_restored
1555  *
1556  * Mark the specified path as a restored path
1557  */
1558 /*ARGSUSED*/
1559 int
1560 ndmpd_path_restored(lbr_fhlog_call_backs_t *cbp, char *name, struct stat64 *stp,
1561     u_longlong_t ll_pos)
1562 {
1563         int rv;
1564         ndmp_name *entp;
1565         ndmp_lbr_params_t *nlp;
1566         ndmpd_module_params_t *params;
1567         int pos =  (int)ll_pos;
1568 
1569         if (cbp == NULL) {
1570                 syslog(LOG_DEBUG, "cbp is NULL");
1571                 return (-1);
1572         }
1573         if (name == NULL) {
1574                 syslog(LOG_DEBUG, "name is NULL");
1575                 return (-1);
1576         }
1577 



1578         if ((nlp = ndmp_get_nlp(cbp->fh_cookie)) == NULL) {
1579                 syslog(LOG_DEBUG, "nlp is NULL");
1580                 return (-1);
1581         }
1582         if (pos < 0 || pos >= nlp->nlp_nfiles) {
1583                 syslog(LOG_DEBUG, "Invalid pos: %d", pos);
1584                 return (-1);
1585         }
1586         params = get_params(cbp->fh_cookie);
1587         if (params == NULL || params->mp_file_recovered_func == NULL)
1588                 return (-1);
1589 
1590         rv = 0;
1591         if (!nlp->nlp_restored[pos]) {
1592                 entp = (ndmp_name *)MOD_GETNAME(params, pos);
1593                 if (entp && entp->name)
1594                         name = entp->name;
1595 
1596                 if ((rv = MOD_FILERECOVERD(params, name, 0)) >= 0)
1597                         nlp->nlp_restored[pos] = TRUE;
1598         }
1599 
1600         return (rv);
1601 }
1602 
1603