1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * BSD 3 Clause License 8 * 9 * Copyright (c) 2007, The Storage Networking Industry Association. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * - Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * - Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * - Neither the name of The Storage Networking Industry Association (SNIA) 23 * nor the names of its contributors may be used to endorse or promote 24 * products derived from this software without specific prior written 25 * permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ 40 /* Copyright (c) 2007, The Storage Networking Industry Association. */ 41 42 /* 43 * File history callback functions called by backup modules. NDMP file history 44 * supports 2 file history models: path based and inode/directory based. 45 * Backup/recover modules similar to unix dump/restore utilize the 46 * inode/directory based model. During the filesystem scan pass, 47 * ndmpd_file_history_dir() is called. During the file backup pass, 48 * ndmpd_file_history_node() is called. This model is appropriate for 49 * modules whose code is structured such that file name and file attribute 50 * data is not available at the same time. Backup/recover modules similar 51 * to tar or cpio utilize the path based model. The simple dump/restore module 52 * included with the SDK uses the path based model. 53 */ 54 55 #include <sys/stat.h> 56 #include <sys/types.h> 57 #include <dirent.h> 58 #include <errno.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include "ndmpd.h" 62 #include <dirent.h> 63 #include <bitmap.h> 64 65 66 #define N_PATH_ENTRIES 1000 67 #define N_FILE_ENTRIES N_PATH_ENTRIES 68 #define N_DIR_ENTRIES 1000 69 #define N_NODE_ENTRIES 1000 70 71 /* Figure an average of 32 bytes per path name */ 72 #define PATH_NAMEBUF_SIZE (N_PATH_ENTRIES * 32) 73 74 /* Figure an average of 16 bytes per file name */ 75 #define DIR_NAMEBUF_SIZE (N_PATH_ENTRIES * 16) 76 77 static boolean_t fh_requested(void *cookie); 78 static void ndmpd_file_history_cleanup_v2(ndmpd_session_t *session, 79 boolean_t send_flag); 80 static void ndmpd_file_history_cleanup_v3(ndmpd_session_t *session, 81 boolean_t send_flag); 82 static ndmpd_module_params_t *get_params(void *cookie); 83 84 85 /* 86 * Each file history as a separate message to the client. 87 */ 88 static int ndmp_syncfh = 0; 89 90 91 /* 92 * ************************************************************************ 93 * NDMP V2 HANDLERS 94 * ************************************************************************ 95 */ 96 97 /* 98 * ndmpd_api_file_history_path_v2 99 * 100 * Add a file history path entry to the buffer. 101 * History data is buffered until the buffer is filled. 102 * Full buffers are then sent to the client. 103 * 104 * Parameters: 105 * cookie (input) - session pointer. 106 * name (input) - file name. 107 * NULL forces buffered data to be sent. 108 * file_stat (input) - file status pointer. 109 * fh_info (input) - data stream position of file data used during 110 * fast restore. 111 * 112 * Returns: 113 * 0 - success 114 * -1 - error 115 */ 116 int 117 ndmpd_api_file_history_path_v2(void *cookie, char *name, 118 struct stat64 *file_stat, u_longlong_t fh_info) 119 { 120 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 121 ndmp_fh_unix_path *entry; 122 123 if (name == NULL && session->ns_fh.fh_path_index == 0) 124 return (0); 125 126 /* 127 * If the buffer does not have space 128 * for the current entry, send the buffered data to the client. 129 * A NULL name indicates that any buffered data should be sent. 130 */ 131 if (name == NULL || 132 (ndmp_syncfh && session->ns_fh.fh_path_index != 0) || 133 session->ns_fh.fh_path_index == N_PATH_ENTRIES || 134 session->ns_fh.fh_path_name_buf_index + strlen(name) + 1 > 135 PATH_NAMEBUF_SIZE) { 136 ndmp_fh_add_unix_path_request request; 137 138 NDMP_LOG(LOG_DEBUG, 139 "sending %ld entries", session->ns_fh.fh_path_index); 140 141 request.paths.paths_val = session->ns_fh.fh_path_entries; 142 request.paths.paths_len = session->ns_fh.fh_path_index; 143 144 if (ndmp_send_request_lock(session->ns_connection, 145 NDMP_FH_ADD_UNIX_PATH, NDMP_NO_ERR, (void *) &request, 146 0) < 0) { 147 NDMP_LOG(LOG_DEBUG, "Sending file history data"); 148 return (-1); 149 } 150 session->ns_fh.fh_path_index = 0; 151 session->ns_fh.fh_path_name_buf_index = 0; 152 } 153 if (name == NULL) 154 return (0); 155 156 if (session->ns_fh.fh_path_entries == 0) { 157 session->ns_fh.fh_path_entries = ndmp_malloc(N_PATH_ENTRIES * 158 sizeof (ndmp_fh_unix_path)); 159 if (session->ns_fh.fh_path_entries == 0) 160 return (-1); 161 } 162 if (session->ns_fh.fh_path_name_buf == 0) { 163 session->ns_fh.fh_path_name_buf = 164 ndmp_malloc(PATH_NAMEBUF_SIZE); 165 if (session->ns_fh.fh_path_name_buf == 0) 166 return (-1); 167 } 168 entry = &session->ns_fh.fh_path_entries[session->ns_fh.fh_path_index]; 169 ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype); 170 171 entry->name = &session-> 172 ns_fh.fh_path_name_buf[session->ns_fh.fh_path_name_buf_index]; 173 (void) strlcpy(entry->name, name, PATH_NAMEBUF_SIZE); 174 session->ns_fh.fh_path_name_buf_index += strlen(name) + 1; 175 entry->fstat.mtime = (ulong_t)file_stat->st_mtime; 176 entry->fstat.atime = (ulong_t)file_stat->st_atime; 177 entry->fstat.ctime = (ulong_t)file_stat->st_ctime; 178 entry->fstat.uid = file_stat->st_uid; 179 entry->fstat.gid = file_stat->st_gid; 180 entry->fstat.mode = (file_stat->st_mode) & 0x0fff; 181 entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size); 182 entry->fstat.fh_info = long_long_to_quad((u_longlong_t)fh_info); 183 session->ns_fh.fh_path_index++; 184 return (0); 185 } 186 187 188 /* 189 * ndmpd_api_file_history_dir_v2 190 * 191 * Add a file history dir entry to the buffer. 192 * History data is buffered until the buffer is filled. 193 * Full buffers are then sent to the client. 194 * 195 * Parameters: 196 * cookie (input) - session pointer. 197 * name (input) - file name. 198 * NULL forces buffered data to be sent. 199 * node (input) - file inode. 200 * parent (input) - file parent inode. 201 * Should equal node if the file is the root of 202 * the filesystem and has no parent. 203 * 204 * Returns: 205 * 0 - success 206 * -1 - error 207 */ 208 int 209 ndmpd_api_file_history_dir_v2(void *cookie, char *name, ulong_t node, 210 ulong_t parent) 211 { 212 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 213 ndmp_fh_unix_dir *entry; 214 215 if (name == NULL && session->ns_fh.fh_dir_index == 0) 216 return (0); 217 218 /* 219 * If the buffer does not have space for the current entry, 220 * send the buffered data to the client. A NULL name indicates 221 * that any buffered data should be sent. 222 */ 223 if (name == NULL || 224 (ndmp_syncfh && session->ns_fh.fh_dir_index != 0) || 225 session->ns_fh.fh_dir_index == N_DIR_ENTRIES || 226 session->ns_fh.fh_dir_name_buf_index + strlen(name) + 1 > 227 DIR_NAMEBUF_SIZE) { 228 ndmp_fh_add_unix_dir_request request; 229 230 NDMP_LOG(LOG_DEBUG, 231 "sending %ld entries", session->ns_fh.fh_dir_index); 232 233 request.dirs.dirs_val = session->ns_fh.fh_dir_entries; 234 request.dirs.dirs_len = session->ns_fh.fh_dir_index; 235 if (ndmp_send_request_lock(session->ns_connection, 236 NDMP_FH_ADD_UNIX_DIR, NDMP_NO_ERR, (void *) &request, 237 0) < 0) { 238 NDMP_LOG(LOG_DEBUG, "Sending file history data"); 239 return (-1); 240 } 241 session->ns_fh.fh_dir_index = 0; 242 session->ns_fh.fh_dir_name_buf_index = 0; 243 } 244 if (name == NULL) 245 return (0); 246 247 if (session->ns_fh.fh_dir_entries == 0) { 248 session->ns_fh.fh_dir_entries = ndmp_malloc(N_DIR_ENTRIES 249 * sizeof (ndmp_fh_unix_dir)); 250 if (session->ns_fh.fh_dir_entries == 0) 251 return (-1); 252 } 253 if (session->ns_fh.fh_dir_name_buf == 0) { 254 session->ns_fh.fh_dir_name_buf = ndmp_malloc(DIR_NAMEBUF_SIZE); 255 if (session->ns_fh.fh_dir_name_buf == 0) 256 return (-1); 257 } 258 entry = &session->ns_fh.fh_dir_entries[session->ns_fh.fh_dir_index]; 259 260 entry->name = &session-> 261 ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index]; 262 (void) strlcpy(&session-> 263 ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index], 264 name, PATH_NAMEBUF_SIZE); 265 session->ns_fh.fh_dir_name_buf_index += strlen(name) + 1; 266 267 entry->node = node; 268 entry->parent = parent; 269 270 session->ns_fh.fh_dir_index++; 271 return (0); 272 } 273 274 275 /* 276 * ndmpd_api_file_history_node_v2 277 * 278 * Add a file history node entry to the buffer. 279 * History data is buffered until the buffer is filled. 280 * Full buffers are then sent to the client. 281 * 282 * Parameters: 283 * cookie (input) - session pointer. 284 * node (input) - file inode. 285 * must match a node from a prior ndmpd_api_file_history_dir() 286 * call. 287 * file_stat (input) - file status pointer. 288 * 0 forces buffered data to be sent. 289 * fh_info (input) - data stream position of file data used during 290 * fast restore. 291 * 292 * Returns: 293 * 0 - success 294 * -1 - error. 295 */ 296 int 297 ndmpd_api_file_history_node_v2(void *cookie, ulong_t node, 298 struct stat64 *file_stat, u_longlong_t fh_info) 299 { 300 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 301 ndmp_fh_unix_node *entry; 302 303 if (file_stat == NULL && session->ns_fh.fh_node_index == 0) 304 return (-1); 305 306 /* 307 * If the buffer does not have space 308 * for the current entry, send the buffered data to the client. 309 * A 0 file_stat pointer indicates that any buffered data should 310 * be sent. 311 */ 312 if (file_stat == NULL || 313 (ndmp_syncfh && session->ns_fh.fh_node_index != 0) || 314 session->ns_fh.fh_node_index == N_NODE_ENTRIES) { 315 ndmp_fh_add_unix_node_request request; 316 317 NDMP_LOG(LOG_DEBUG, 318 "sending %ld entries", session->ns_fh.fh_node_index); 319 320 request.nodes.nodes_val = session->ns_fh.fh_node_entries; 321 request.nodes.nodes_len = session->ns_fh.fh_node_index; 322 /* 323 * Need to send Dir entry as well. Since Dir entry is more than 324 * Node entry, we may send a Node entry that hasn't have 325 * its dir entry sent. Therefore, we need to flush Dir entry 326 * as well everytime the Dir entry is send. 327 */ 328 (void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0); 329 330 if (ndmp_send_request_lock(session->ns_connection, 331 NDMP_FH_ADD_UNIX_NODE, NDMP_NO_ERR, (void *) &request, 332 0) < 0) { 333 NDMP_LOG(LOG_DEBUG, "Sending file history data"); 334 return (-1); 335 } 336 session->ns_fh.fh_node_index = 0; 337 } 338 if (file_stat == NULL) 339 return (0); 340 341 if (session->ns_fh.fh_node_entries == 0) { 342 session->ns_fh.fh_node_entries = ndmp_malloc(N_NODE_ENTRIES 343 * sizeof (ndmp_fh_unix_node)); 344 if (session->ns_fh.fh_node_entries == 0) 345 return (-1); 346 } 347 entry = &session->ns_fh.fh_node_entries[session->ns_fh.fh_node_index]; 348 ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype); 349 350 entry->node = node; 351 entry->fstat.mtime = (ulong_t)file_stat->st_mtime; 352 entry->fstat.atime = (ulong_t)file_stat->st_atime; 353 entry->fstat.ctime = (ulong_t)file_stat->st_ctime; 354 entry->fstat.uid = file_stat->st_uid; 355 entry->fstat.gid = file_stat->st_gid; 356 entry->fstat.mode = (file_stat->st_mode) & 0x0fff; 357 entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size); 358 entry->fstat.fh_info = long_long_to_quad(fh_info); 359 360 session->ns_fh.fh_node_index++; 361 return (0); 362 } 363 364 365 /* 366 * ************************************************************************ 367 * NDMP V3 HANDLERS 368 * ************************************************************************ 369 */ 370 371 /* 372 * ndmpd_api_file_history_file_v3 373 * 374 * Add a file history file entry to the buffer. 375 * History data is buffered until the buffer is filled. 376 * Full buffers are then sent to the client. 377 * 378 * Parameters: 379 * cookie (input) - session pointer. 380 * name (input) - file name. 381 * NULL forces buffered data to be sent. 382 * file_stat (input) - file status pointer. 383 * fh_info (input) - data stream position of file data used during 384 * fast restore. 385 * 386 * Returns: 387 * 0 - success 388 * -1 - error 389 */ 390 int 391 ndmpd_api_file_history_file_v3(void *cookie, char *name, 392 struct stat64 *file_stat, u_longlong_t fh_info) 393 { 394 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 395 ndmp_file_v3 *file_entry; 396 ndmp_file_name_v3 *file_name_entry; 397 ndmp_file_stat_v3 *file_stat_entry; 398 ndmp_fh_add_file_request_v3 request; 399 400 if (name == NULL && session->ns_fh_v3.fh_file_index == 0) 401 return (0); 402 403 /* 404 * If the buffer does not have space 405 * for the current entry, send the buffered data to the client. 406 * A NULL name indicates that any buffered data should be sent. 407 */ 408 if (name == NULL || 409 session->ns_fh_v3.fh_file_index == N_FILE_ENTRIES || 410 session->ns_fh_v3.fh_file_name_buf_index + strlen(name) + 1 > 411 PATH_NAMEBUF_SIZE) { 412 413 NDMP_LOG(LOG_DEBUG, "sending %ld entries", 414 session->ns_fh_v3.fh_file_index); 415 416 request.files.files_len = session->ns_fh_v3.fh_file_index; 417 request.files.files_val = session->ns_fh_v3.fh_files; 418 419 if (ndmp_send_request_lock(session->ns_connection, 420 NDMP_FH_ADD_FILE, NDMP_NO_ERR, (void *) &request, 0) < 0) { 421 NDMP_LOG(LOG_DEBUG, 422 "Sending ndmp_fh_add_file request"); 423 return (-1); 424 } 425 426 session->ns_fh_v3.fh_file_index = 0; 427 session->ns_fh_v3.fh_file_name_buf_index = 0; 428 } 429 430 if (name == NULL) 431 return (0); 432 433 if (session->ns_fh_v3.fh_files == 0) { 434 session->ns_fh_v3.fh_files = ndmp_malloc(sizeof (ndmp_file_v3) * 435 N_FILE_ENTRIES); 436 if (session->ns_fh_v3.fh_files == 0) 437 return (-1); 438 } 439 440 if (session->ns_fh_v3.fh_file_names == 0) { 441 session->ns_fh_v3.fh_file_names = 442 ndmp_malloc(sizeof (ndmp_file_name_v3) * N_FILE_ENTRIES); 443 if (session->ns_fh_v3.fh_file_names == 0) 444 return (-1); 445 } 446 447 if (session->ns_fh_v3.fh_file_name_buf == 0) { 448 session->ns_fh_v3.fh_file_name_buf = 449 ndmp_malloc(sizeof (char) * PATH_NAMEBUF_SIZE); 450 if (session->ns_fh_v3.fh_file_name_buf == 0) 451 return (-1); 452 } 453 454 if (session->ns_fh_v3.fh_file_stats == 0) { 455 session->ns_fh_v3.fh_file_stats = 456 ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_FILE_ENTRIES); 457 if (session->ns_fh_v3.fh_file_stats == 0) 458 return (-1); 459 } 460 461 file_entry = 462 &session->ns_fh_v3.fh_files[session->ns_fh_v3.fh_file_index]; 463 file_name_entry = 464 &session->ns_fh_v3.fh_file_names[session->ns_fh_v3.fh_file_index]; 465 file_stat_entry = 466 &session->ns_fh_v3.fh_file_stats[session->ns_fh_v3.fh_file_index]; 467 file_entry->names.names_len = 1; 468 file_entry->names.names_val = file_name_entry; 469 file_entry->stats.stats_len = 1; 470 file_entry->stats.stats_val = file_stat_entry; 471 file_entry->node = long_long_to_quad(file_stat->st_ino); 472 file_entry->fh_info = long_long_to_quad(fh_info); 473 474 file_name_entry->fs_type = NDMP_FS_UNIX; 475 file_name_entry->ndmp_file_name_v3_u.unix_name = 476 &session->ns_fh_v3.fh_file_name_buf[session-> 477 ns_fh_v3.fh_file_name_buf_index]; 478 (void) strlcpy(&session->ns_fh_v3.fh_file_name_buf[session-> 479 ns_fh_v3.fh_file_name_buf_index], name, PATH_NAMEBUF_SIZE); 480 session->ns_fh_v3.fh_file_name_buf_index += strlen(name) + 1; 481 ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype); 482 483 file_stat_entry->invalid = 0; 484 file_stat_entry->fs_type = NDMP_FS_UNIX; 485 file_stat_entry->mtime = file_stat->st_mtime; 486 file_stat_entry->atime = file_stat->st_atime; 487 file_stat_entry->ctime = file_stat->st_ctime; 488 file_stat_entry->owner = file_stat->st_uid; 489 file_stat_entry->group = file_stat->st_gid; 490 file_stat_entry->fattr = file_stat->st_mode & 0x0fff; 491 file_stat_entry->size = 492 long_long_to_quad((u_longlong_t)file_stat->st_size); 493 file_stat_entry->links = file_stat->st_nlink; 494 495 session->ns_fh_v3.fh_file_index++; 496 497 return (0); 498 } 499 500 501 /* 502 * ndmpd_api_file_history_dir_v3 503 * 504 * Add a file history dir entry to the buffer. 505 * History data is buffered until the buffer is filled. 506 * Full buffers are then sent to the client. 507 * 508 * Parameters: 509 * cookie (input) - session pointer. 510 * name (input) - file name. 511 * NULL forces buffered data to be sent. 512 * node (input) - file inode. 513 * parent (input) - file parent inode. 514 * Should equal node if the file is the root of 515 * the filesystem and has no parent. 516 * 517 * Returns: 518 * 0 - success 519 * -1 - error 520 */ 521 int 522 ndmpd_api_file_history_dir_v3(void *cookie, char *name, ulong_t node, 523 ulong_t parent) 524 { 525 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 526 ndmp_dir_v3 *dir_entry; 527 ndmp_file_name_v3 *dir_name_entry; 528 ndmp_fh_add_dir_request_v3 request; 529 530 if (name == NULL && session->ns_fh_v3.fh_dir_index == 0) 531 return (0); 532 533 /* 534 * If the buffer does not have space 535 * for the current entry, send the buffered data to the client. 536 * A NULL name indicates that any buffered data should be sent. 537 */ 538 if (name == NULL || 539 session->ns_fh_v3.fh_dir_index == N_DIR_ENTRIES || 540 session->ns_fh_v3.fh_dir_name_buf_index + strlen(name) + 1 > 541 DIR_NAMEBUF_SIZE) { 542 543 NDMP_LOG(LOG_DEBUG, "sending %ld entries", 544 session->ns_fh_v3.fh_dir_index); 545 546 request.dirs.dirs_val = session->ns_fh_v3.fh_dirs; 547 request.dirs.dirs_len = session->ns_fh_v3.fh_dir_index; 548 549 if (ndmp_send_request_lock(session->ns_connection, 550 NDMP_FH_ADD_DIR, NDMP_NO_ERR, (void *) &request, 0) < 0) { 551 NDMP_LOG(LOG_DEBUG, 552 "Sending ndmp_fh_add_dir request"); 553 return (-1); 554 } 555 556 session->ns_fh_v3.fh_dir_index = 0; 557 session->ns_fh_v3.fh_dir_name_buf_index = 0; 558 } 559 560 if (name == NULL) 561 return (0); 562 563 if (session->ns_fh_v3.fh_dirs == 0) { 564 session->ns_fh_v3.fh_dirs = 565 ndmp_malloc(sizeof (ndmp_dir_v3) * N_DIR_ENTRIES); 566 if (session->ns_fh_v3.fh_dirs == 0) 567 return (-1); 568 } 569 570 if (session->ns_fh_v3.fh_dir_names == 0) { 571 session->ns_fh_v3.fh_dir_names = 572 ndmp_malloc(sizeof (ndmp_file_name_v3) * N_DIR_ENTRIES); 573 if (session->ns_fh_v3.fh_dir_names == 0) 574 return (-1); 575 } 576 577 if (session->ns_fh_v3.fh_dir_name_buf == 0) { 578 session->ns_fh_v3.fh_dir_name_buf = 579 ndmp_malloc(sizeof (char) * DIR_NAMEBUF_SIZE); 580 if (session->ns_fh_v3.fh_dir_name_buf == 0) 581 return (-1); 582 } 583 584 dir_entry = &session->ns_fh_v3.fh_dirs[session->ns_fh_v3.fh_dir_index]; 585 dir_name_entry = 586 &session->ns_fh_v3.fh_dir_names[session->ns_fh_v3.fh_dir_index]; 587 588 dir_name_entry->fs_type = NDMP_FS_UNIX; 589 dir_name_entry->ndmp_file_name_v3_u.unix_name = 590 &session->ns_fh_v3.fh_dir_name_buf[session-> 591 ns_fh_v3.fh_dir_name_buf_index]; 592 593 (void) strlcpy(&session->ns_fh_v3.fh_dir_name_buf[session-> 594 ns_fh_v3.fh_dir_name_buf_index], name, PATH_NAMEBUF_SIZE); 595 session->ns_fh_v3.fh_dir_name_buf_index += strlen(name) + 1; 596 597 dir_entry->names.names_len = 1; 598 dir_entry->names.names_val = dir_name_entry; 599 dir_entry->node = long_long_to_quad(node); 600 dir_entry->parent = long_long_to_quad(parent); 601 602 session->ns_fh_v3.fh_dir_index++; 603 604 return (0); 605 } 606 607 608 /* 609 * ndmpd_api_file_history_node_v3 610 * 611 * Add a file history node entry to the buffer. 612 * History data is buffered until the buffer is filled. 613 * Full buffers are then sent to the client. 614 * 615 * Parameters: 616 * cookie (input) - session pointer. 617 * node (input) - file inode. 618 * must match a node from a prior ndmpd_api_file_history_dir() 619 * call. 620 * file_stat (input) - file status pointer. 621 * 0 forces buffered data to be sent. 622 * fh_info (input) - data stream position of file data used during 623 * fast restore. 624 * 625 * Returns: 626 * 0 - success 627 * -1 - error. 628 */ 629 int 630 ndmpd_api_file_history_node_v3(void *cookie, ulong_t node, 631 struct stat64 *file_stat, u_longlong_t fh_info) 632 { 633 ndmpd_session_t *session = (ndmpd_session_t *)cookie; 634 ndmp_node_v3 *node_entry; 635 ndmp_file_stat_v3 *file_stat_entry; 636 ndmp_fh_add_node_request_v3 request; 637 638 if (file_stat == NULL && session->ns_fh_v3.fh_node_index == 0) 639 return (0); 640 641 /* 642 * If the buffer does not have space 643 * for the current entry, send the buffered data to the client. 644 * A 0 file_stat pointer indicates that any buffered data should 645 * be sent. 646 */ 647 if (file_stat == NULL || 648 session->ns_fh_v3.fh_node_index == N_NODE_ENTRIES) { 649 NDMP_LOG(LOG_DEBUG, "sending %ld entries", 650 session->ns_fh_v3.fh_node_index); 651 652 /* 653 * Need to send Dir entry as well. Since Dir entry is more 654 * than a Node entry, we may send a Node entry that hasn't 655 * had its Dir entry sent. Therefore, we need to flush Dir 656 * entry as well every time the Dir entry is sent. 657 */ 658 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0); 659 660 request.nodes.nodes_len = session->ns_fh_v3.fh_node_index; 661 request.nodes.nodes_val = session->ns_fh_v3.fh_nodes; 662 663 if (ndmp_send_request_lock(session->ns_connection, 664 NDMP_FH_ADD_NODE, 665 NDMP_NO_ERR, (void *) &request, 0) < 0) { 666 NDMP_LOG(LOG_DEBUG, 667 "Sending ndmp_fh_add_node request"); 668 return (-1); 669 } 670 671 session->ns_fh_v3.fh_node_index = 0; 672 } 673 674 if (file_stat == NULL) 675 return (0); 676 677 if (session->ns_fh_v3.fh_nodes == 0) { 678 session->ns_fh_v3.fh_nodes = 679 ndmp_malloc(sizeof (ndmp_node_v3) * N_NODE_ENTRIES); 680 if (session->ns_fh_v3.fh_nodes == 0) 681 return (-1); 682 } 683 684 if (session->ns_fh_v3.fh_node_stats == 0) { 685 session->ns_fh_v3.fh_node_stats = 686 ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_NODE_ENTRIES); 687 if (session->ns_fh_v3.fh_node_stats == 0) 688 return (-1); 689 } 690 691 node_entry = 692 &session->ns_fh_v3.fh_nodes[session->ns_fh_v3.fh_node_index]; 693 694 file_stat_entry = 695 &session->ns_fh_v3.fh_node_stats[session->ns_fh_v3.fh_node_index]; 696 ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype); 697 698 file_stat_entry->invalid = 0; 699 file_stat_entry->fs_type = NDMP_FS_UNIX; 700 file_stat_entry->mtime = file_stat->st_mtime; 701 file_stat_entry->atime = file_stat->st_atime; 702 file_stat_entry->ctime = file_stat->st_ctime; 703 file_stat_entry->owner = file_stat->st_uid; 704 file_stat_entry->group = file_stat->st_gid; 705 file_stat_entry->fattr = file_stat->st_mode & 0x0fff; 706 file_stat_entry->size = 707 long_long_to_quad((u_longlong_t)file_stat->st_size); 708 file_stat_entry->links = file_stat->st_nlink; 709 710 node_entry->stats.stats_len = 1; 711 node_entry->stats.stats_val = file_stat_entry; 712 node_entry->node = long_long_to_quad((u_longlong_t)node); 713 node_entry->fh_info = long_long_to_quad(fh_info); 714 715 session->ns_fh_v3.fh_node_index++; 716 717 return (0); 718 } 719 720 721 /* 722 * ************************************************************************ 723 * NDMP V4 HANDLERS 724 * ************************************************************************ 725 */ 726 727 728 /* 729 * ndmpd_fhpath_v3_cb 730 * 731 * Callback function for file history path information 732 */ 733 int 734 ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t *cbp, char *path, struct stat64 *stp, 735 u_longlong_t off) 736 { 737 int err; 738 ndmp_lbr_params_t *nlp; 739 ndmpd_module_params_t *params; 740 741 if (!cbp) { 742 err = -1; 743 NDMP_LOG(LOG_DEBUG, "cbp is NULL"); 744 } else if (!cbp->fh_cookie) { 745 err = -1; 746 NDMP_LOG(LOG_DEBUG, "cookie is NULL"); 747 } else if (!path) { 748 err = -1; 749 NDMP_LOG(LOG_DEBUG, "path is NULL"); 750 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) { 751 err = -1; 752 NDMP_LOG(LOG_DEBUG, "nlp is NULL"); 753 } else 754 err = 0; 755 756 if (err != 0) 757 return (0); 758 759 NDMP_LOG(LOG_DEBUG, "pname(%s)", path); 760 761 err = 0; 762 if (NLP_ISSET(nlp, NLPF_FH)) { 763 if (!NLP_ISSET(nlp, NLPF_DIRECT)) { 764 NDMP_LOG(LOG_DEBUG, "DAR NOT SET!"); 765 off = 0LL; 766 } 767 768 params = get_params(cbp->fh_cookie); 769 if (!params || !params->mp_file_history_path_func) { 770 err = -1; 771 } else { 772 char *p = ndmp_get_relative_path(get_bk_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