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
ndmpd_api_file_history_path_v2(void * cookie,char * name,struct stat64 * file_stat,u_longlong_t fh_info)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
ndmpd_api_file_history_dir_v2(void * cookie,char * name,ulong_t node,ulong_t parent)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
ndmpd_api_file_history_node_v2(void * cookie,ulong_t node,struct stat64 * file_stat,u_longlong_t fh_info)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
ndmpd_api_file_history_file_v3(void * cookie,char * name,struct stat64 * file_stat,u_longlong_t fh_info)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
ndmpd_api_file_history_dir_v3(void * cookie,char * name,ulong_t node,ulong_t parent)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
ndmpd_api_file_history_node_v3(void * cookie,ulong_t node,struct stat64 * file_stat,u_longlong_t fh_info)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
ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t * cbp,char * path,struct stat64 * stp,u_longlong_t off)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
ndmpd_fhdir_v3_cb(lbr_fhlog_call_backs_t * cbp,char * dir,struct stat64 * stp)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
ndmpd_fhnode_v3_cb(lbr_fhlog_call_backs_t * cbp,char * dir,char * file,struct stat64 * stp,u_longlong_t off)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
ndmp_send_recovery_stat_v3(ndmpd_module_params_t * params,ndmp_lbr_params_t * nlp,int idx,int stat)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
ndmpd_path_restored_v3(lbr_fhlog_call_backs_t * cbp,char * name,struct stat64 * st,u_longlong_t ll_idx)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
ndmpd_file_history_init(ndmpd_session_t * session)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
ndmpd_file_history_cleanup_v2(ndmpd_session_t * session,boolean_t send_flag)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
ndmpd_file_history_cleanup_v3(ndmpd_session_t * session,boolean_t send_flag)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
ndmpd_file_history_cleanup(ndmpd_session_t * session,boolean_t send_flag)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 *
get_params(void * cookie)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
fh_requested(void * cookie)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
ndmpd_file_history_path(lbr_fhlog_call_backs_t * cbp,char * path,struct stat64 * stp,u_longlong_t off)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
ndmpd_file_history_dir(lbr_fhlog_call_backs_t * cbp,char * dir,struct stat64 * stp)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
ndmpd_file_history_node(lbr_fhlog_call_backs_t * cbp,char * dir,char * file,struct stat64 * stp,u_longlong_t off)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
ndmpd_path_restored(lbr_fhlog_call_backs_t * cbp,char * name,struct stat64 * stp,u_longlong_t ll_pos)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
dp_readdir(DIR * dirp,unsigned long * cookiep,char * name,int * n_namep,unsigned long * fileidp)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