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 } 1663