1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /*
   6  * BSD 3 Clause License
   7  *
   8  * Copyright (c) 2007, The Storage Networking Industry Association.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  *      - Redistributions of source code must retain the above copyright
  14  *        notice, this list of conditions and the following disclaimer.
  15  *
  16  *      - Redistributions in binary form must reproduce the above copyright
  17  *        notice, this list of conditions and the following disclaimer in
  18  *        the documentation and/or other materials provided with the
  19  *        distribution.
  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 
  78 static boolean_t fh_requested(void *cookie);
  79 static void ndmpd_file_history_cleanup_v2(ndmpd_session_t *session,
  80     boolean_t send_flag);
  81 static void ndmpd_file_history_cleanup_v3(ndmpd_session_t *session,
  82     boolean_t send_flag);
  83 static ndmpd_module_params_t *get_params(void *cookie);
  84 
  85 
  86 /*
  87  * Each file history as a separate message to the client.
  88  */
  89 static int ndmp_syncfh = 0;
  90 
  91 
  92 /*
  93  * ************************************************************************
  94  * NDMP V2 HANDLERS
  95  * ************************************************************************
  96  */
  97 
  98 /*
  99  * ndmpd_api_file_history_path_v2
 100  *
 101  * Add a file history path entry to the buffer.
 102  * History data is buffered until the buffer is filled.
 103  * Full buffers are then sent to the client.
 104  *
 105  * Parameters:
 106  *   cookie   (input) - session pointer.
 107  *   name     (input) - file name.
 108  *                    NULL forces buffered data to be sent.
 109  *   file_stat (input) - file status pointer.
 110  *   fh_info  (input) - data stream position of file data used during
 111  *                    fast restore.
 112  *
 113  * Returns:
 114  *   0 - success
 115  *  -1 - error
 116  */
 117 int
 118 ndmpd_api_file_history_path_v2(void *cookie, char *name,
 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         }
 167         entry = &session->ns_fh.fh_path_entries[session->ns_fh.fh_path_index];
 168         ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype);
 169 
 170         entry->name = &session->
 171             ns_fh.fh_path_name_buf[session->ns_fh.fh_path_name_buf_index];
 172         (void) strlcpy(entry->name, name, PATH_NAMEBUF_SIZE);
 173         session->ns_fh.fh_path_name_buf_index += strlen(name) + 1;
 174         entry->fstat.mtime = (ulong_t)file_stat->st_mtime;
 175         entry->fstat.atime = (ulong_t)file_stat->st_atime;
 176         entry->fstat.ctime = (ulong_t)file_stat->st_ctime;
 177         entry->fstat.uid = file_stat->st_uid;
 178         entry->fstat.gid = file_stat->st_gid;
 179         entry->fstat.mode = (file_stat->st_mode) & 0x0fff;
 180         entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size);
 181         entry->fstat.fh_info = long_long_to_quad((u_longlong_t)fh_info);
 182         session->ns_fh.fh_path_index++;
 183         return (0);
 184 }
 185 
 186 
 187 /*
 188  * ndmpd_api_file_history_dir_v2
 189  *
 190  * Add a file history dir entry to the buffer.
 191  * History data is buffered until the buffer is filled.
 192  * Full buffers are then sent to the client.
 193  *
 194  * Parameters:
 195  *   cookie (input) - session pointer.
 196  *   name   (input) - file name.
 197  *                  NULL forces buffered data to be sent.
 198  *   node   (input) - file inode.
 199  *   parent (input) - file parent inode.
 200  *                  Should equal node if the file is the root of
 201  *                  the filesystem and has no parent.
 202  *
 203  * Returns:
 204  *   0 - success
 205  *  -1 - error
 206  */
 207 int
 208 ndmpd_api_file_history_dir_v2(void *cookie, char *name, ulong_t node,
 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];
 255 
 256         entry->name = &session->
 257             ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index];
 258         (void) strlcpy(&session->
 259             ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index],
 260             name, PATH_NAMEBUF_SIZE);
 261         session->ns_fh.fh_dir_name_buf_index += strlen(name) + 1;
 262 
 263         entry->node = node;
 264         entry->parent = parent;
 265 
 266         session->ns_fh.fh_dir_index++;
 267         return (0);
 268 }
 269 
 270 
 271 /*
 272  * ndmpd_api_file_history_node_v2
 273  *
 274  * Add a file history node entry to the buffer.
 275  * History data is buffered until the buffer is filled.
 276  * Full buffers are then sent to the client.
 277  *
 278  * Parameters:
 279  *   cookie   (input) - session pointer.
 280  *   node     (input) - file inode.
 281  *            must match a node from a prior ndmpd_api_file_history_dir()
 282  *                    call.
 283  *   file_stat (input) - file status pointer.
 284  *                    0 forces buffered data to be sent.
 285  *   fh_info  (input) - data stream position of file data used during
 286  *                    fast restore.
 287  *
 288  * Returns:
 289  *   0 - success
 290  *  -1 - error.
 291  */
 292 int
 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;
 347         entry->fstat.uid = file_stat->st_uid;
 348         entry->fstat.gid = file_stat->st_gid;
 349         entry->fstat.mode = (file_stat->st_mode) & 0x0fff;
 350         entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size);
 351         entry->fstat.fh_info = long_long_to_quad(fh_info);
 352 
 353         session->ns_fh.fh_node_index++;
 354         return (0);
 355 }
 356 
 357 
 358 /*
 359  * ************************************************************************
 360  * NDMP V3 HANDLERS
 361  * ************************************************************************
 362  */
 363 
 364 /*
 365  * ndmpd_api_file_history_file_v3
 366  *
 367  * Add a file history file entry to the buffer.
 368  * History data is buffered until the buffer is filled.
 369  * Full buffers are then sent to the client.
 370  *
 371  * Parameters:
 372  *   cookie   (input) - session pointer.
 373  *   name     (input) - file name.
 374  *                    NULL forces buffered data to be sent.
 375  *   file_stat (input) - file status pointer.
 376  *   fh_info  (input) - data stream position of file data used during
 377  *                    fast restore.
 378  *
 379  * Returns:
 380  *   0 - success
 381  *  -1 - error
 382  */
 383 int
 384 ndmpd_api_file_history_file_v3(void *cookie, char *name,
 385     struct stat64 *file_stat, u_longlong_t fh_info)
 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);
 433                 if (session->ns_fh_v3.fh_file_names == 0)
 434                         return (-1);
 435         }
 436 
 437         if (session->ns_fh_v3.fh_file_name_buf == 0) {
 438                 session->ns_fh_v3.fh_file_name_buf =
 439                     ndmp_malloc(sizeof (char) * PATH_NAMEBUF_SIZE);
 440                 if (session->ns_fh_v3.fh_file_name_buf == 0)
 441                         return (-1);
 442         }
 443 
 444         if (session->ns_fh_v3.fh_file_stats == 0) {
 445                 session->ns_fh_v3.fh_file_stats =
 446                     ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_FILE_ENTRIES);
 447                 if (session->ns_fh_v3.fh_file_stats == 0)
 448                         return (-1);
 449         }
 450 
 451         file_entry =
 452             &session->ns_fh_v3.fh_files[session->ns_fh_v3.fh_file_index];
 453         file_name_entry =
 454             &session->ns_fh_v3.fh_file_names[session->ns_fh_v3.fh_file_index];
 455         file_stat_entry =
 456             &session->ns_fh_v3.fh_file_stats[session->ns_fh_v3.fh_file_index];
 457         file_entry->names.names_len = 1;
 458         file_entry->names.names_val = file_name_entry;
 459         file_entry->stats.stats_len = 1;
 460         file_entry->stats.stats_val = file_stat_entry;
 461         file_entry->node = long_long_to_quad(file_stat->st_ino);
 462         file_entry->fh_info = long_long_to_quad(fh_info);
 463 
 464         file_name_entry->fs_type = NDMP_FS_UNIX;
 465         file_name_entry->ndmp_file_name_v3_u.unix_name =
 466             &session->ns_fh_v3.fh_file_name_buf[session->
 467             ns_fh_v3.fh_file_name_buf_index];
 468         (void) strlcpy(&session->ns_fh_v3.fh_file_name_buf[session->
 469             ns_fh_v3.fh_file_name_buf_index], name, PATH_NAMEBUF_SIZE);
 470         session->ns_fh_v3.fh_file_name_buf_index += strlen(name) + 1;
 471         ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);
 472 
 473         file_stat_entry->invalid = 0;
 474         file_stat_entry->fs_type = NDMP_FS_UNIX;
 475         file_stat_entry->mtime = file_stat->st_mtime;
 476         file_stat_entry->atime = file_stat->st_atime;
 477         file_stat_entry->ctime = file_stat->st_ctime;
 478         file_stat_entry->owner = file_stat->st_uid;
 479         file_stat_entry->group = file_stat->st_gid;
 480         file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
 481         file_stat_entry->size =
 482             long_long_to_quad((u_longlong_t)file_stat->st_size);
 483         file_stat_entry->links = file_stat->st_nlink;
 484 
 485         session->ns_fh_v3.fh_file_index++;
 486 
 487         return (0);
 488 }
 489 
 490 
 491 /*
 492  * ndmpd_api_file_history_dir_v3
 493  *
 494  * Add a file history dir entry to the buffer.
 495  * History data is buffered until the buffer is filled.
 496  * Full buffers are then sent to the client.
 497  *
 498  * Parameters:
 499  *   cookie (input) - session pointer.
 500  *   name   (input) - file name.
 501  *                  NULL forces buffered data to be sent.
 502  *   node   (input) - file inode.
 503  *   parent (input) - file parent inode.
 504  *                  Should equal node if the file is the root of
 505  *                  the filesystem and has no parent.
 506  *
 507  * Returns:
 508  *   0 - success
 509  *  -1 - error
 510  */
 511 int
 512 ndmpd_api_file_history_dir_v3(void *cookie, char *name, ulong_t node,
 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);
 560                 if (session->ns_fh_v3.fh_dir_names == 0)
 561                         return (-1);
 562         }
 563 
 564         if (session->ns_fh_v3.fh_dir_name_buf == 0) {
 565                 session->ns_fh_v3.fh_dir_name_buf =
 566                     ndmp_malloc(sizeof (char) * DIR_NAMEBUF_SIZE);
 567                 if (session->ns_fh_v3.fh_dir_name_buf == 0)
 568                         return (-1);
 569         }
 570 
 571         dir_entry = &session->ns_fh_v3.fh_dirs[session->ns_fh_v3.fh_dir_index];
 572         dir_name_entry =
 573             &session->ns_fh_v3.fh_dir_names[session->ns_fh_v3.fh_dir_index];
 574 
 575         dir_name_entry->fs_type = NDMP_FS_UNIX;
 576         dir_name_entry->ndmp_file_name_v3_u.unix_name =
 577             &session->ns_fh_v3.fh_dir_name_buf[session->
 578             ns_fh_v3.fh_dir_name_buf_index];
 579 
 580         (void) strlcpy(&session->ns_fh_v3.fh_dir_name_buf[session->
 581             ns_fh_v3.fh_dir_name_buf_index], name, PATH_NAMEBUF_SIZE);
 582         session->ns_fh_v3.fh_dir_name_buf_index += strlen(name) + 1;
 583 
 584         dir_entry->names.names_len = 1;
 585         dir_entry->names.names_val = dir_name_entry;
 586         dir_entry->node = long_long_to_quad(node);
 587         dir_entry->parent = long_long_to_quad(parent);
 588 
 589         session->ns_fh_v3.fh_dir_index++;
 590 
 591         return (0);
 592 }
 593 
 594 
 595 /*
 596  * ndmpd_api_file_history_node_v3
 597  *
 598  * Add a file history node entry to the buffer.
 599  * History data is buffered until the buffer is filled.
 600  * Full buffers are then sent to the client.
 601  *
 602  * Parameters:
 603  *   cookie   (input) - session pointer.
 604  *   node     (input) - file inode.
 605  *              must match a node from a prior ndmpd_api_file_history_dir()
 606  *                    call.
 607  *   file_stat (input) - file status pointer.
 608  *                    0 forces buffered data to be sent.
 609  *   fh_info  (input) - data stream position of file data used during
 610  *                    fast restore.
 611  *
 612  * Returns:
 613  *   0 - success
 614  *  -1 - error.
 615  */
 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)
 673                         return (-1);
 674         }
 675 
 676         node_entry =
 677             &session->ns_fh_v3.fh_nodes[session->ns_fh_v3.fh_node_index];
 678 
 679         file_stat_entry =
 680             &session->ns_fh_v3.fh_node_stats[session->ns_fh_v3.fh_node_index];
 681         ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);
 682 
 683         file_stat_entry->invalid = 0;
 684         file_stat_entry->fs_type = NDMP_FS_UNIX;
 685         file_stat_entry->mtime = file_stat->st_mtime;
 686         file_stat_entry->atime = file_stat->st_atime;
 687         file_stat_entry->ctime = file_stat->st_ctime;
 688         file_stat_entry->owner = file_stat->st_uid;
 689         file_stat_entry->group = file_stat->st_gid;
 690         file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
 691         file_stat_entry->size =
 692             long_long_to_quad((u_longlong_t)file_stat->st_size);
 693         file_stat_entry->links = file_stat->st_nlink;
 694 
 695         node_entry->stats.stats_len = 1;
 696         node_entry->stats.stats_val = file_stat_entry;
 697         node_entry->node = long_long_to_quad((u_longlong_t)node);
 698         node_entry->fh_info = long_long_to_quad(fh_info);
 699 
 700         session->ns_fh_v3.fh_node_index++;
 701 
 702         return (0);
 703 }
 704 
 705 
 706 /*
 707  * ************************************************************************
 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 
1062         return (rv);
1063 }
1064 
1065 
1066 
1067 /*
1068  * ndmpd_file_history_init
1069  *
1070  * Initialize file history variables.
1071  * Note that the entry and name buffers are not allocated here.
1072  * Since it is not know if the backup module will be sending file history
1073  * data or what kind of data (path or dir/node), the entry and name
1074  * buffers are not allocated until the first call to one of the file history
1075  * entry functions is made. This way resources are only allocated as
1076  * needed.
1077  *
1078  * Parameters:
1079  *   session (input) - session pointer.
1080  *
1081  * Returns:
1082  *   void
1083  */
1084 void
1085 ndmpd_file_history_init(ndmpd_session_t *session)
1086 {
1087         session->ns_fh.fh_path_entries = 0;
1088         session->ns_fh.fh_dir_entries = 0;
1089         session->ns_fh.fh_node_entries = 0;
1090         session->ns_fh.fh_path_name_buf = 0;
1091         session->ns_fh.fh_dir_name_buf = 0;
1092         session->ns_fh.fh_path_index = 0;
1093         session->ns_fh.fh_dir_index = 0;
1094         session->ns_fh.fh_node_index = 0;
1095         session->ns_fh.fh_path_name_buf_index = 0;
1096         session->ns_fh.fh_dir_name_buf_index = 0;
1097 
1098         /*
1099          * V3.
1100          */
1101         session->ns_fh_v3.fh_files = 0;
1102         session->ns_fh_v3.fh_dirs = 0;
1103         session->ns_fh_v3.fh_nodes = 0;
1104         session->ns_fh_v3.fh_file_names = 0;
1105         session->ns_fh_v3.fh_dir_names = 0;
1106         session->ns_fh_v3.fh_file_stats = 0;
1107         session->ns_fh_v3.fh_node_stats = 0;
1108         session->ns_fh_v3.fh_file_name_buf = 0;
1109         session->ns_fh_v3.fh_dir_name_buf = 0;
1110         session->ns_fh_v3.fh_file_index = 0;
1111         session->ns_fh_v3.fh_dir_index = 0;
1112         session->ns_fh_v3.fh_node_index = 0;
1113         session->ns_fh_v3.fh_file_name_buf_index = 0;
1114         session->ns_fh_v3.fh_dir_name_buf_index = 0;
1115 }
1116 
1117 
1118 /*
1119  * ndmpd_file_history_cleanup_v2
1120  *
1121  * Send (or discard) any buffered file history entries.
1122  *
1123  * Parameters:
1124  *   session  (input) - session pointer.
1125  *   send_flag (input) - if TRUE  buffered entries are sent.
1126  *                    if FALSE buffered entries are discarded.
1127  *
1128  * Returns:
1129  *   void
1130  */
1131 static void
1132 ndmpd_file_history_cleanup_v2(ndmpd_session_t *session, boolean_t send_flag)
1133 {
1134         if (send_flag == TRUE) {
1135                 (void) ndmpd_api_file_history_path_v2(session, 0, 0, 0);
1136                 (void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0);
1137                 (void) ndmpd_api_file_history_node_v2(session, 0, 0, 0);
1138         }
1139 
1140         if (session->ns_fh.fh_path_entries != 0) {
1141                 free(session->ns_fh.fh_path_entries);
1142                 session->ns_fh.fh_path_entries = 0;
1143         }
1144         if (session->ns_fh.fh_dir_entries != 0) {
1145                 free(session->ns_fh.fh_dir_entries);
1146                 session->ns_fh.fh_dir_entries = 0;
1147         }
1148         if (session->ns_fh.fh_node_entries != 0) {
1149                 free(session->ns_fh.fh_node_entries);
1150                 session->ns_fh.fh_node_entries = 0;
1151         }
1152         if (session->ns_fh.fh_path_name_buf != 0) {
1153                 free(session->ns_fh.fh_path_name_buf);
1154                 session->ns_fh.fh_path_name_buf = 0;
1155         }
1156         if (session->ns_fh.fh_dir_name_buf != 0) {
1157                 free(session->ns_fh.fh_dir_name_buf);
1158                 session->ns_fh.fh_dir_name_buf = 0;
1159         }
1160         session->ns_fh.fh_path_index = 0;
1161         session->ns_fh.fh_dir_index = 0;
1162         session->ns_fh.fh_node_index = 0;
1163         session->ns_fh.fh_path_name_buf_index = 0;
1164         session->ns_fh.fh_dir_name_buf_index = 0;
1165 }
1166 
1167 
1168 /*
1169  * ndmpd_file_history_cleanup_v3
1170  *
1171  * Send (or discard) any buffered file history entries.
1172  *
1173  * Parameters:
1174  *   session  (input) - session pointer.
1175  *   send_flag (input) - if TRUE  buffered entries are sent.
1176  *                    if FALSE buffered entries are discarded.
1177  *
1178  * Returns:
1179  *   void
1180  */
1181 static void
1182 ndmpd_file_history_cleanup_v3(ndmpd_session_t *session, boolean_t send_flag)
1183 {
1184         if (send_flag == TRUE) {
1185                 (void) ndmpd_api_file_history_file_v3(session, 0, 0, 0);
1186                 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);
1187                 (void) ndmpd_api_file_history_node_v3(session, 0, 0, 0);
1188         }
1189 
1190         if (session->ns_fh_v3.fh_files != 0) {
1191                 free(session->ns_fh_v3.fh_files);
1192                 session->ns_fh_v3.fh_files = 0;
1193         }
1194         if (session->ns_fh_v3.fh_dirs != 0) {
1195                 free(session->ns_fh_v3.fh_dirs);
1196                 session->ns_fh_v3.fh_dirs = 0;
1197         }
1198         if (session->ns_fh_v3.fh_nodes != 0) {
1199                 free(session->ns_fh_v3.fh_nodes);
1200                 session->ns_fh_v3.fh_nodes = 0;
1201         }
1202         if (session->ns_fh_v3.fh_file_names != 0) {
1203                 free(session->ns_fh_v3.fh_file_names);
1204                 session->ns_fh_v3.fh_file_names = 0;
1205         }
1206         if (session->ns_fh_v3.fh_dir_names != 0) {
1207                 free(session->ns_fh_v3.fh_dir_names);
1208                 session->ns_fh_v3.fh_dir_names = 0;
1209         }
1210         if (session->ns_fh_v3.fh_file_stats != 0) {
1211                 free(session->ns_fh_v3.fh_file_stats);
1212                 session->ns_fh_v3.fh_file_stats = 0;
1213         }
1214         if (session->ns_fh_v3.fh_node_stats != 0) {
1215                 free(session->ns_fh_v3.fh_node_stats);
1216                 session->ns_fh_v3.fh_node_stats = 0;
1217         }
1218         if (session->ns_fh_v3.fh_file_name_buf != 0) {
1219                 free(session->ns_fh_v3.fh_file_name_buf);
1220                 session->ns_fh_v3.fh_file_name_buf = 0;
1221         }
1222         if (session->ns_fh_v3.fh_dir_name_buf != 0) {
1223                 free(session->ns_fh_v3.fh_dir_name_buf);
1224                 session->ns_fh_v3.fh_dir_name_buf = 0;
1225         }
1226 
1227         session->ns_fh_v3.fh_file_index = 0;
1228         session->ns_fh_v3.fh_dir_index = 0;
1229         session->ns_fh_v3.fh_node_index = 0;
1230         session->ns_fh_v3.fh_file_name_buf_index = 0;
1231         session->ns_fh_v3.fh_dir_name_buf_index = 0;
1232 }
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 
1604 /*
1605  * dp_readdir
1606  *
1607  * Reads the entry of the directory and provides other information
1608  * such as i-number, name, length and saves the dir entry position
1609  * in a cookie for future calls.
1610  */
1611 int
1612 dp_readdir(DIR *dirp, unsigned long *cookiep, char *name, int *n_namep,
1613     unsigned long *fileidp)
1614 {
1615         struct dirent *entp;
1616         int err = errno;
1617 
1618         if ((entp = readdir(dirp)) == 0) {
1619                 if (err == errno) {
1620                         *n_namep = 0;
1621                         return (0);
1622                 }
1623                 return (errno);
1624         }
1625 
1626         *fileidp = entp->d_ino;
1627         (void) strlcpy(name, entp->d_name, *n_namep);
1628         *n_namep = entp->d_reclen + 1;
1629         *cookiep = telldir(dirp);
1630         return (0);
1631 }