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 
  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 
  76 static boolean_t fh_requested(void *cookie);
  77 static void ndmpd_file_history_cleanup_v2(ndmpd_session_t *session,
  78     boolean_t send_flag);
  79 static void ndmpd_file_history_cleanup_v3(ndmpd_session_t *session,
  80     boolean_t send_flag);
  81 static ndmpd_module_params_t *get_params(void *cookie);
  82 
  83 
  84 /*
  85  * Each file history as a separate message to the client.
  86  */
  87 static int ndmp_syncfh = 0;
  88 
  89 
  90 /*
  91  * ************************************************************************
  92  * NDMP V2 HANDLERS
  93  * ************************************************************************
  94  */
  95 
  96 /*
  97  * ndmpd_api_file_history_path_v2
  98  *
  99  * Add a file history path entry to the buffer.
 100  * History data is buffered until the buffer is filled.
 101  * Full buffers are then sent to the client.
 102  *
 103  * Parameters:
 104  *   cookie   (input) - session pointer.
 105  *   name     (input) - file name.
 106  *                    NULL forces buffered data to be sent.
 107  *   file_stat (input) - file status pointer.
 108  *   fh_info  (input) - data stream position of file data used during
 109  *                    fast restore.
 110  *
 111  * Returns:
 112  *   0 - success
 113  *  -1 - error
 114  */
 115 int
 116 ndmpd_api_file_history_path_v2(void *cookie, char *name,
 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         }
 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                 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];
 258 
 259         entry->name = &session->
 260             ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index];
 261         (void) strlcpy(&session->
 262             ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index],
 263             name, PATH_NAMEBUF_SIZE);
 264         session->ns_fh.fh_dir_name_buf_index += strlen(name) + 1;
 265 
 266         entry->node = node;
 267         entry->parent = parent;
 268 
 269         session->ns_fh.fh_dir_index++;
 270         return (0);
 271 }
 272 
 273 
 274 /*
 275  * ndmpd_api_file_history_node_v2
 276  *
 277  * Add a file history node entry to the buffer.
 278  * History data is buffered until the buffer is filled.
 279  * Full buffers are then sent to the client.
 280  *
 281  * Parameters:
 282  *   cookie   (input) - session pointer.
 283  *   node     (input) - file inode.
 284  *            must match a node from a prior ndmpd_api_file_history_dir()
 285  *                    call.
 286  *   file_stat (input) - file status pointer.
 287  *                    0 forces buffered data to be sent.
 288  *   fh_info  (input) - data stream position of file data used during
 289  *                    fast restore.
 290  *
 291  * Returns:
 292  *   0 - success
 293  *  -1 - error.
 294  */
 295 int
 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;
 353         entry->fstat.uid = file_stat->st_uid;
 354         entry->fstat.gid = file_stat->st_gid;
 355         entry->fstat.mode = (file_stat->st_mode) & 0x0fff;
 356         entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size);
 357         entry->fstat.fh_info = long_long_to_quad(fh_info);
 358 
 359         session->ns_fh.fh_node_index++;
 360         return (0);
 361 }
 362 
 363 
 364 /*
 365  * ************************************************************************
 366  * NDMP V3 HANDLERS
 367  * ************************************************************************
 368  */
 369 
 370 /*
 371  * ndmpd_api_file_history_file_v3
 372  *
 373  * Add a file history file entry to the buffer.
 374  * History data is buffered until the buffer is filled.
 375  * Full buffers are then sent to the client.
 376  *
 377  * Parameters:
 378  *   cookie   (input) - session pointer.
 379  *   name     (input) - file name.
 380  *                    NULL forces buffered data to be sent.
 381  *   file_stat (input) - file status pointer.
 382  *   fh_info  (input) - data stream position of file data used during
 383  *                    fast restore.
 384  *
 385  * Returns:
 386  *   0 - success
 387  *  -1 - error
 388  */
 389 int
 390 ndmpd_api_file_history_file_v3(void *cookie, char *name,
 391     struct stat64 *file_stat, u_longlong_t fh_info)
 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);
 442                 if (session->ns_fh_v3.fh_file_names == 0)
 443                         return (-1);
 444         }
 445 
 446         if (session->ns_fh_v3.fh_file_name_buf == 0) {
 447                 session->ns_fh_v3.fh_file_name_buf =
 448                     ndmp_malloc(sizeof (char) * PATH_NAMEBUF_SIZE);
 449                 if (session->ns_fh_v3.fh_file_name_buf == 0)
 450                         return (-1);
 451         }
 452 
 453         if (session->ns_fh_v3.fh_file_stats == 0) {
 454                 session->ns_fh_v3.fh_file_stats =
 455                     ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_FILE_ENTRIES);
 456                 if (session->ns_fh_v3.fh_file_stats == 0)
 457                         return (-1);
 458         }
 459 
 460         file_entry =
 461             &session->ns_fh_v3.fh_files[session->ns_fh_v3.fh_file_index];
 462         file_name_entry =
 463             &session->ns_fh_v3.fh_file_names[session->ns_fh_v3.fh_file_index];
 464         file_stat_entry =
 465             &session->ns_fh_v3.fh_file_stats[session->ns_fh_v3.fh_file_index];
 466         file_entry->names.names_len = 1;
 467         file_entry->names.names_val = file_name_entry;
 468         file_entry->stats.stats_len = 1;
 469         file_entry->stats.stats_val = file_stat_entry;
 470         file_entry->node = long_long_to_quad(file_stat->st_ino);
 471         file_entry->fh_info = long_long_to_quad(fh_info);
 472 
 473         file_name_entry->fs_type = NDMP_FS_UNIX;
 474         file_name_entry->ndmp_file_name_v3_u.unix_name =
 475             &session->ns_fh_v3.fh_file_name_buf[session->
 476             ns_fh_v3.fh_file_name_buf_index];
 477         (void) strlcpy(&session->ns_fh_v3.fh_file_name_buf[session->
 478             ns_fh_v3.fh_file_name_buf_index], name, PATH_NAMEBUF_SIZE);
 479         session->ns_fh_v3.fh_file_name_buf_index += strlen(name) + 1;
 480         ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);
 481 
 482         file_stat_entry->invalid = 0;
 483         file_stat_entry->fs_type = NDMP_FS_UNIX;
 484         file_stat_entry->mtime = file_stat->st_mtime;
 485         file_stat_entry->atime = file_stat->st_atime;
 486         file_stat_entry->ctime = file_stat->st_ctime;
 487         file_stat_entry->owner = file_stat->st_uid;
 488         file_stat_entry->group = file_stat->st_gid;
 489         file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
 490         file_stat_entry->size =
 491             long_long_to_quad((u_longlong_t)file_stat->st_size);
 492         file_stat_entry->links = file_stat->st_nlink;
 493 
 494         session->ns_fh_v3.fh_file_index++;
 495 
 496         return (0);
 497 }
 498 
 499 
 500 /*
 501  * ndmpd_api_file_history_dir_v3
 502  *
 503  * Add a file history dir entry to the buffer.
 504  * History data is buffered until the buffer is filled.
 505  * Full buffers are then sent to the client.
 506  *
 507  * Parameters:
 508  *   cookie (input) - session pointer.
 509  *   name   (input) - file name.
 510  *                  NULL forces buffered data to be sent.
 511  *   node   (input) - file inode.
 512  *   parent (input) - file parent inode.
 513  *                  Should equal node if the file is the root of
 514  *                  the filesystem and has no parent.
 515  *
 516  * Returns:
 517  *   0 - success
 518  *  -1 - error
 519  */
 520 int
 521 ndmpd_api_file_history_dir_v3(void *cookie, char *name, ulong_t node,
 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);
 572                 if (session->ns_fh_v3.fh_dir_names == 0)
 573                         return (-1);
 574         }
 575 
 576         if (session->ns_fh_v3.fh_dir_name_buf == 0) {
 577                 session->ns_fh_v3.fh_dir_name_buf =
 578                     ndmp_malloc(sizeof (char) * DIR_NAMEBUF_SIZE);
 579                 if (session->ns_fh_v3.fh_dir_name_buf == 0)
 580                         return (-1);
 581         }
 582 
 583         dir_entry = &session->ns_fh_v3.fh_dirs[session->ns_fh_v3.fh_dir_index];
 584         dir_name_entry =
 585             &session->ns_fh_v3.fh_dir_names[session->ns_fh_v3.fh_dir_index];
 586 
 587         dir_name_entry->fs_type = NDMP_FS_UNIX;
 588         dir_name_entry->ndmp_file_name_v3_u.unix_name =
 589             &session->ns_fh_v3.fh_dir_name_buf[session->
 590             ns_fh_v3.fh_dir_name_buf_index];
 591 
 592         (void) strlcpy(&session->ns_fh_v3.fh_dir_name_buf[session->
 593             ns_fh_v3.fh_dir_name_buf_index], name, PATH_NAMEBUF_SIZE);
 594         session->ns_fh_v3.fh_dir_name_buf_index += strlen(name) + 1;
 595 
 596         dir_entry->names.names_len = 1;
 597         dir_entry->names.names_val = dir_name_entry;
 598         dir_entry->node = long_long_to_quad(node);
 599         dir_entry->parent = long_long_to_quad(parent);
 600 
 601         session->ns_fh_v3.fh_dir_index++;
 602 
 603         return (0);
 604 }
 605 
 606 
 607 /*
 608  * ndmpd_api_file_history_node_v3
 609  *
 610  * Add a file history node entry to the buffer.
 611  * History data is buffered until the buffer is filled.
 612  * Full buffers are then sent to the client.
 613  *
 614  * Parameters:
 615  *   cookie   (input) - session pointer.
 616  *   node     (input) - file inode.
 617  *              must match a node from a prior ndmpd_api_file_history_dir()
 618  *                    call.
 619  *   file_stat (input) - file status pointer.
 620  *                    0 forces buffered data to be sent.
 621  *   fh_info  (input) - data stream position of file data used during
 622  *                    fast restore.
 623  *
 624  * Returns:
 625  *   0 - success
 626  *  -1 - error.
 627  */
 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)
 687                         return (-1);
 688         }
 689 
 690         node_entry =
 691             &session->ns_fh_v3.fh_nodes[session->ns_fh_v3.fh_node_index];
 692 
 693         file_stat_entry =
 694             &session->ns_fh_v3.fh_node_stats[session->ns_fh_v3.fh_node_index];
 695         ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);
 696 
 697         file_stat_entry->invalid = 0;
 698         file_stat_entry->fs_type = NDMP_FS_UNIX;
 699         file_stat_entry->mtime = file_stat->st_mtime;
 700         file_stat_entry->atime = file_stat->st_atime;
 701         file_stat_entry->ctime = file_stat->st_ctime;
 702         file_stat_entry->owner = file_stat->st_uid;
 703         file_stat_entry->group = file_stat->st_gid;
 704         file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
 705         file_stat_entry->size =
 706             long_long_to_quad((u_longlong_t)file_stat->st_size);
 707         file_stat_entry->links = file_stat->st_nlink;
 708 
 709         node_entry->stats.stats_len = 1;
 710         node_entry->stats.stats_val = file_stat_entry;
 711         node_entry->node = long_long_to_quad((u_longlong_t)node);
 712         node_entry->fh_info = long_long_to_quad(fh_info);
 713 
 714         session->ns_fh_v3.fh_node_index++;
 715 
 716         return (0);
 717 }
 718 
 719 
 720 /*
 721  * ************************************************************************
 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 
1086         return (rv);
1087 }
1088 
1089 
1090 
1091 /*
1092  * ndmpd_file_history_init
1093  *
1094  * Initialize file history variables.
1095  * Note that the entry and name buffers are not allocated here.
1096  * Since it is not know if the backup module will be sending file history
1097  * data or what kind of data (path or dir/node), the entry and name
1098  * buffers are not allocated until the first call to one of the file history
1099  * entry functions is made. This way resources are only allocated as
1100  * needed.
1101  *
1102  * Parameters:
1103  *   session (input) - session pointer.
1104  *
1105  * Returns:
1106  *   void
1107  */
1108 void
1109 ndmpd_file_history_init(ndmpd_session_t *session)
1110 {
1111         session->ns_fh.fh_path_entries = 0;
1112         session->ns_fh.fh_dir_entries = 0;
1113         session->ns_fh.fh_node_entries = 0;
1114         session->ns_fh.fh_path_name_buf = 0;
1115         session->ns_fh.fh_dir_name_buf = 0;
1116         session->ns_fh.fh_path_index = 0;
1117         session->ns_fh.fh_dir_index = 0;
1118         session->ns_fh.fh_node_index = 0;
1119         session->ns_fh.fh_path_name_buf_index = 0;
1120         session->ns_fh.fh_dir_name_buf_index = 0;
1121 
1122         /*
1123          * V3.
1124          */
1125         session->ns_fh_v3.fh_files = 0;
1126         session->ns_fh_v3.fh_dirs = 0;
1127         session->ns_fh_v3.fh_nodes = 0;
1128         session->ns_fh_v3.fh_file_names = 0;
1129         session->ns_fh_v3.fh_dir_names = 0;
1130         session->ns_fh_v3.fh_file_stats = 0;
1131         session->ns_fh_v3.fh_node_stats = 0;
1132         session->ns_fh_v3.fh_file_name_buf = 0;
1133         session->ns_fh_v3.fh_dir_name_buf = 0;
1134         session->ns_fh_v3.fh_file_index = 0;
1135         session->ns_fh_v3.fh_dir_index = 0;
1136         session->ns_fh_v3.fh_node_index = 0;
1137         session->ns_fh_v3.fh_file_name_buf_index = 0;
1138         session->ns_fh_v3.fh_dir_name_buf_index = 0;
1139 }
1140 
1141 
1142 /*
1143  * ndmpd_file_history_cleanup_v2
1144  *
1145  * Send (or discard) any buffered file history entries.
1146  *
1147  * Parameters:
1148  *   session  (input) - session pointer.
1149  *   send_flag (input) - if TRUE  buffered entries are sent.
1150  *                    if FALSE buffered entries are discarded.
1151  *
1152  * Returns:
1153  *   void
1154  */
1155 static void
1156 ndmpd_file_history_cleanup_v2(ndmpd_session_t *session, boolean_t send_flag)
1157 {
1158         if (send_flag == TRUE) {
1159                 (void) ndmpd_api_file_history_path_v2(session, 0, 0, 0);
1160                 (void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0);
1161                 (void) ndmpd_api_file_history_node_v2(session, 0, 0, 0);
1162         }
1163 
1164         if (session->ns_fh.fh_path_entries != 0) {
1165                 free(session->ns_fh.fh_path_entries);
1166                 session->ns_fh.fh_path_entries = 0;
1167         }
1168         if (session->ns_fh.fh_dir_entries != 0) {
1169                 free(session->ns_fh.fh_dir_entries);
1170                 session->ns_fh.fh_dir_entries = 0;
1171         }
1172         if (session->ns_fh.fh_node_entries != 0) {
1173                 free(session->ns_fh.fh_node_entries);
1174                 session->ns_fh.fh_node_entries = 0;
1175         }
1176         if (session->ns_fh.fh_path_name_buf != 0) {
1177                 free(session->ns_fh.fh_path_name_buf);
1178                 session->ns_fh.fh_path_name_buf = 0;
1179         }
1180         if (session->ns_fh.fh_dir_name_buf != 0) {
1181                 free(session->ns_fh.fh_dir_name_buf);
1182                 session->ns_fh.fh_dir_name_buf = 0;
1183         }
1184         session->ns_fh.fh_path_index = 0;
1185         session->ns_fh.fh_dir_index = 0;
1186         session->ns_fh.fh_node_index = 0;
1187         session->ns_fh.fh_path_name_buf_index = 0;
1188         session->ns_fh.fh_dir_name_buf_index = 0;
1189 }
1190 
1191 
1192 /*
1193  * ndmpd_file_history_cleanup_v3
1194  *
1195  * Send (or discard) any buffered file history entries.
1196  *
1197  * Parameters:
1198  *   session  (input) - session pointer.
1199  *   send_flag (input) - if TRUE  buffered entries are sent.
1200  *                    if FALSE buffered entries are discarded.
1201  *
1202  * Returns:
1203  *   void
1204  */
1205 static void
1206 ndmpd_file_history_cleanup_v3(ndmpd_session_t *session, boolean_t send_flag)
1207 {
1208         if (send_flag == TRUE) {
1209                 (void) ndmpd_api_file_history_file_v3(session, 0, 0, 0);
1210                 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);
1211                 (void) ndmpd_api_file_history_node_v3(session, 0, 0, 0);
1212         }
1213 
1214         if (session->ns_fh_v3.fh_files != 0) {
1215                 free(session->ns_fh_v3.fh_files);
1216                 session->ns_fh_v3.fh_files = 0;
1217         }
1218         if (session->ns_fh_v3.fh_dirs != 0) {
1219                 free(session->ns_fh_v3.fh_dirs);
1220                 session->ns_fh_v3.fh_dirs = 0;
1221         }
1222         if (session->ns_fh_v3.fh_nodes != 0) {
1223                 free(session->ns_fh_v3.fh_nodes);
1224                 session->ns_fh_v3.fh_nodes = 0;
1225         }
1226         if (session->ns_fh_v3.fh_file_names != 0) {
1227                 free(session->ns_fh_v3.fh_file_names);
1228                 session->ns_fh_v3.fh_file_names = 0;
1229         }
1230         if (session->ns_fh_v3.fh_dir_names != 0) {
1231                 free(session->ns_fh_v3.fh_dir_names);
1232                 session->ns_fh_v3.fh_dir_names = 0;
1233         }
1234         if (session->ns_fh_v3.fh_file_stats != 0) {
1235                 free(session->ns_fh_v3.fh_file_stats);
1236                 session->ns_fh_v3.fh_file_stats = 0;
1237         }
1238         if (session->ns_fh_v3.fh_node_stats != 0) {
1239                 free(session->ns_fh_v3.fh_node_stats);
1240                 session->ns_fh_v3.fh_node_stats = 0;
1241         }
1242         if (session->ns_fh_v3.fh_file_name_buf != 0) {
1243                 free(session->ns_fh_v3.fh_file_name_buf);
1244                 session->ns_fh_v3.fh_file_name_buf = 0;
1245         }
1246         if (session->ns_fh_v3.fh_dir_name_buf != 0) {
1247                 free(session->ns_fh_v3.fh_dir_name_buf);
1248                 session->ns_fh_v3.fh_dir_name_buf = 0;
1249         }
1250 
1251         session->ns_fh_v3.fh_file_index = 0;
1252         session->ns_fh_v3.fh_dir_index = 0;
1253         session->ns_fh_v3.fh_node_index = 0;
1254         session->ns_fh_v3.fh_file_name_buf_index = 0;
1255         session->ns_fh_v3.fh_dir_name_buf_index = 0;
1256 }
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 
1635 /*
1636  * dp_readdir
1637  *
1638  * Reads the entry of the directory and provides other information
1639  * such as i-number, name, length and saves the dir entry position
1640  * in a cookie for future calls.
1641  */
1642 int
1643 dp_readdir(DIR *dirp, unsigned long *cookiep, char *name, int *n_namep,
1644     unsigned long *fileidp)
1645 {
1646         struct dirent *entp;
1647         int err = errno;
1648 
1649         if ((entp = readdir(dirp)) == 0) {
1650                 if (err == errno) {
1651                         *n_namep = 0;
1652                         return (0);
1653                 }
1654                 return (errno);
1655         }
1656 
1657         *fileidp = entp->d_ino;
1658         (void) strlcpy(name, entp->d_name, *n_namep);
1659         *n_namep = entp->d_reclen + 1;
1660         *cookiep = telldir(dirp);
1661         return (0);
1662 }