1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4
5 /*
6 * BSD 3 Clause License
7 *
8 * Copyright (c) 2007, The Storage Networking Industry Association.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * - Neither the name of The Storage Networking Industry Association (SNIA)
22 * nor the names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
41
42 /*
43 * File history callback functions called by backup modules. NDMP file history
44 * supports 2 file history models: path based and inode/directory based.
45 * Backup/recover modules similar to unix dump/restore utilize the
46 * inode/directory based model. During the filesystem scan pass,
47 * ndmpd_file_history_dir() is called. During the file backup pass,
48 * ndmpd_file_history_node() is called. This model is appropriate for
49 * modules whose code is structured such that file name and file attribute
50 * data is not available at the same time. Backup/recover modules similar
51 * to tar or cpio utilize the path based model. The simple dump/restore module
52 * included with the SDK uses the path based model.
53 */
54
55 #include <sys/stat.h>
56 #include <sys/types.h>
57 #include <syslog.h>
58 #include <dirent.h>
59 #include <errno.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include "ndmpd.h"
63 #include <dirent.h>
64 #include <bitmap.h>
65
66
67 #define N_PATH_ENTRIES 1000
68 #define N_FILE_ENTRIES N_PATH_ENTRIES
69 #define N_DIR_ENTRIES 1000
70 #define N_NODE_ENTRIES 1000
71
72 /* Figure an average of 32 bytes per path name */
73 #define PATH_NAMEBUF_SIZE (N_PATH_ENTRIES * 32)
74
75 /* Figure an average of 16 bytes per file name */
76 #define DIR_NAMEBUF_SIZE (N_PATH_ENTRIES * 16)
77
78 static boolean_t fh_requested(void *cookie);
79 static void ndmpd_file_history_cleanup_v2(ndmpd_session_t *session,
80 boolean_t send_flag);
81 static void ndmpd_file_history_cleanup_v3(ndmpd_session_t *session,
82 boolean_t send_flag);
83 static ndmpd_module_params_t *get_params(void *cookie);
84
85
86 /*
87 * Each file history as a separate message to the client.
88 */
89 static int ndmp_syncfh = 0;
90
91
92 /*
93 * ************************************************************************
94 * NDMP V2 HANDLERS
95 * ************************************************************************
96 */
97
98 /*
99 * ndmpd_api_file_history_path_v2
100 *
101 * Add a file history path entry to the buffer.
102 * History data is buffered until the buffer is filled.
103 * Full buffers are then sent to the client.
104 *
105 * Parameters:
106 * cookie (input) - session pointer.
107 * name (input) - file name.
108 * NULL forces buffered data to be sent.
109 * file_stat (input) - file status pointer.
110 * fh_info (input) - data stream position of file data used during
111 * fast restore.
112 *
113 * Returns:
114 * 0 - success
115 * -1 - error
116 */
117 int
118 ndmpd_api_file_history_path_v2(void *cookie, char *name,
119 struct stat64 *file_stat, u_longlong_t fh_info)
120 {
121 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
122 ndmp_fh_unix_path *entry;
123
124 if (name == NULL && session->ns_fh.fh_path_index == 0)
125 return (0);
126
127 /*
128 * If the buffer does not have space
129 * for the current entry, send the buffered data to the client.
130 * A NULL name indicates that any buffered data should be sent.
131 */
132 if (name == NULL ||
133 (ndmp_syncfh && session->ns_fh.fh_path_index != 0) ||
134 session->ns_fh.fh_path_index == N_PATH_ENTRIES ||
135 session->ns_fh.fh_path_name_buf_index + strlen(name) + 1 >
136 PATH_NAMEBUF_SIZE) {
137 ndmp_fh_add_unix_path_request request;
138
139
140 request.paths.paths_val = session->ns_fh.fh_path_entries;
141 request.paths.paths_len = session->ns_fh.fh_path_index;
142
143 if (ndmp_send_request_lock(session->ns_connection,
144 NDMP_FH_ADD_UNIX_PATH, NDMP_NO_ERR, (void *) &request,
145 0) < 0) {
146 syslog(LOG_ERR, "Sending file history data failed");
147 return (-1);
148 }
149 session->ns_fh.fh_path_index = 0;
150 session->ns_fh.fh_path_name_buf_index = 0;
151 }
152 if (name == NULL)
153 return (0);
154
155 if (session->ns_fh.fh_path_entries == 0) {
156 session->ns_fh.fh_path_entries = ndmp_malloc(N_PATH_ENTRIES *
157 sizeof (ndmp_fh_unix_path));
158 if (session->ns_fh.fh_path_entries == 0)
159 return (-1);
160 }
161 if (session->ns_fh.fh_path_name_buf == 0) {
162 session->ns_fh.fh_path_name_buf =
163 ndmp_malloc(PATH_NAMEBUF_SIZE);
164 if (session->ns_fh.fh_path_name_buf == 0)
165 return (-1);
166 }
167 entry = &session->ns_fh.fh_path_entries[session->ns_fh.fh_path_index];
168 ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype);
169
170 entry->name = &session->
171 ns_fh.fh_path_name_buf[session->ns_fh.fh_path_name_buf_index];
172 (void) strlcpy(entry->name, name, PATH_NAMEBUF_SIZE);
173 session->ns_fh.fh_path_name_buf_index += strlen(name) + 1;
174 entry->fstat.mtime = (ulong_t)file_stat->st_mtime;
175 entry->fstat.atime = (ulong_t)file_stat->st_atime;
176 entry->fstat.ctime = (ulong_t)file_stat->st_ctime;
177 entry->fstat.uid = file_stat->st_uid;
178 entry->fstat.gid = file_stat->st_gid;
179 entry->fstat.mode = (file_stat->st_mode) & 0x0fff;
180 entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size);
181 entry->fstat.fh_info = long_long_to_quad((u_longlong_t)fh_info);
182 session->ns_fh.fh_path_index++;
183 return (0);
184 }
185
186
187 /*
188 * ndmpd_api_file_history_dir_v2
189 *
190 * Add a file history dir entry to the buffer.
191 * History data is buffered until the buffer is filled.
192 * Full buffers are then sent to the client.
193 *
194 * Parameters:
195 * cookie (input) - session pointer.
196 * name (input) - file name.
197 * NULL forces buffered data to be sent.
198 * node (input) - file inode.
199 * parent (input) - file parent inode.
200 * Should equal node if the file is the root of
201 * the filesystem and has no parent.
202 *
203 * Returns:
204 * 0 - success
205 * -1 - error
206 */
207 int
208 ndmpd_api_file_history_dir_v2(void *cookie, char *name, ulong_t node,
209 ulong_t parent)
210 {
211 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
212 ndmp_fh_unix_dir *entry;
213
214 if (name == NULL && session->ns_fh.fh_dir_index == 0)
215 return (0);
216
217 /*
218 * If the buffer does not have space for the current entry,
219 * send the buffered data to the client. A NULL name indicates
220 * that any buffered data should be sent.
221 */
222 if (name == NULL ||
223 (ndmp_syncfh && session->ns_fh.fh_dir_index != 0) ||
224 session->ns_fh.fh_dir_index == N_DIR_ENTRIES ||
225 session->ns_fh.fh_dir_name_buf_index + strlen(name) + 1 >
226 DIR_NAMEBUF_SIZE) {
227 ndmp_fh_add_unix_dir_request request;
228
229 request.dirs.dirs_val = session->ns_fh.fh_dir_entries;
230 request.dirs.dirs_len = session->ns_fh.fh_dir_index;
231 if (ndmp_send_request_lock(session->ns_connection,
232 NDMP_FH_ADD_UNIX_DIR, NDMP_NO_ERR, (void *) &request,
233 0) < 0) {
234 syslog(LOG_DEBUG, "Sending file history data");
235 return (-1);
236 }
237 session->ns_fh.fh_dir_index = 0;
238 session->ns_fh.fh_dir_name_buf_index = 0;
239 }
240 if (name == NULL)
241 return (0);
242
243 if (session->ns_fh.fh_dir_entries == 0) {
244 session->ns_fh.fh_dir_entries = ndmp_malloc(N_DIR_ENTRIES
245 * sizeof (ndmp_fh_unix_dir));
246 if (session->ns_fh.fh_dir_entries == 0)
247 return (-1);
248 }
249 if (session->ns_fh.fh_dir_name_buf == 0) {
250 session->ns_fh.fh_dir_name_buf = ndmp_malloc(DIR_NAMEBUF_SIZE);
251 if (session->ns_fh.fh_dir_name_buf == 0)
252 return (-1);
253 }
254 entry = &session->ns_fh.fh_dir_entries[session->ns_fh.fh_dir_index];
255
256 entry->name = &session->
257 ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index];
258 (void) strlcpy(&session->
259 ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index],
260 name, PATH_NAMEBUF_SIZE);
261 session->ns_fh.fh_dir_name_buf_index += strlen(name) + 1;
262
263 entry->node = node;
264 entry->parent = parent;
265
266 session->ns_fh.fh_dir_index++;
267 return (0);
268 }
269
270
271 /*
272 * ndmpd_api_file_history_node_v2
273 *
274 * Add a file history node entry to the buffer.
275 * History data is buffered until the buffer is filled.
276 * Full buffers are then sent to the client.
277 *
278 * Parameters:
279 * cookie (input) - session pointer.
280 * node (input) - file inode.
281 * must match a node from a prior ndmpd_api_file_history_dir()
282 * call.
283 * file_stat (input) - file status pointer.
284 * 0 forces buffered data to be sent.
285 * fh_info (input) - data stream position of file data used during
286 * fast restore.
287 *
288 * Returns:
289 * 0 - success
290 * -1 - error.
291 */
292 int
293 ndmpd_api_file_history_node_v2(void *cookie, ulong_t node,
294 struct stat64 *file_stat, u_longlong_t fh_info)
295 {
296 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
297 ndmp_fh_unix_node *entry;
298
299 if (file_stat == NULL && session->ns_fh.fh_node_index == 0)
300 return (-1);
301
302 /*
303 * If the buffer does not have space
304 * for the current entry, send the buffered data to the client.
305 * A 0 file_stat pointer indicates that any buffered data should
306 * be sent.
307 */
308 if (file_stat == NULL ||
309 (ndmp_syncfh && session->ns_fh.fh_node_index != 0) ||
310 session->ns_fh.fh_node_index == N_NODE_ENTRIES) {
311 ndmp_fh_add_unix_node_request request;
312
313 request.nodes.nodes_val = session->ns_fh.fh_node_entries;
314 request.nodes.nodes_len = session->ns_fh.fh_node_index;
315 /*
316 * Need to send Dir entry as well. Since Dir entry is more than
317 * Node entry, we may send a Node entry that hasn't have
318 * its dir entry sent. Therefore, we need to flush Dir entry
319 * as well everytime the Dir entry is send.
320 */
321 (void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0);
322
323 if (ndmp_send_request_lock(session->ns_connection,
324 NDMP_FH_ADD_UNIX_NODE, NDMP_NO_ERR, (void *) &request,
325 0) < 0) {
326 syslog(LOG_ERR, "Sending file history data failed");
327 return (-1);
328 }
329 session->ns_fh.fh_node_index = 0;
330 }
331 if (file_stat == NULL)
332 return (0);
333
334 if (session->ns_fh.fh_node_entries == 0) {
335 session->ns_fh.fh_node_entries = ndmp_malloc(N_NODE_ENTRIES
336 * sizeof (ndmp_fh_unix_node));
337 if (session->ns_fh.fh_node_entries == 0)
338 return (-1);
339 }
340 entry = &session->ns_fh.fh_node_entries[session->ns_fh.fh_node_index];
341 ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype);
342
343 entry->node = node;
344 entry->fstat.mtime = (ulong_t)file_stat->st_mtime;
345 entry->fstat.atime = (ulong_t)file_stat->st_atime;
346 entry->fstat.ctime = (ulong_t)file_stat->st_ctime;
347 entry->fstat.uid = file_stat->st_uid;
348 entry->fstat.gid = file_stat->st_gid;
349 entry->fstat.mode = (file_stat->st_mode) & 0x0fff;
350 entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size);
351 entry->fstat.fh_info = long_long_to_quad(fh_info);
352
353 session->ns_fh.fh_node_index++;
354 return (0);
355 }
356
357
358 /*
359 * ************************************************************************
360 * NDMP V3 HANDLERS
361 * ************************************************************************
362 */
363
364 /*
365 * ndmpd_api_file_history_file_v3
366 *
367 * Add a file history file entry to the buffer.
368 * History data is buffered until the buffer is filled.
369 * Full buffers are then sent to the client.
370 *
371 * Parameters:
372 * cookie (input) - session pointer.
373 * name (input) - file name.
374 * NULL forces buffered data to be sent.
375 * file_stat (input) - file status pointer.
376 * fh_info (input) - data stream position of file data used during
377 * fast restore.
378 *
379 * Returns:
380 * 0 - success
381 * -1 - error
382 */
383 int
384 ndmpd_api_file_history_file_v3(void *cookie, char *name,
385 struct stat64 *file_stat, u_longlong_t fh_info)
386 {
387 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
388 ndmp_file_v3 *file_entry;
389 ndmp_file_name_v3 *file_name_entry;
390 ndmp_file_stat_v3 *file_stat_entry;
391 ndmp_fh_add_file_request_v3 request;
392
393 if (name == NULL && session->ns_fh_v3.fh_file_index == 0)
394 return (0);
395
396 /*
397 * If the buffer does not have space
398 * for the current entry, send the buffered data to the client.
399 * A NULL name indicates that any buffered data should be sent.
400 */
401 if (name == NULL ||
402 session->ns_fh_v3.fh_file_index == N_FILE_ENTRIES ||
403 session->ns_fh_v3.fh_file_name_buf_index + strlen(name) + 1 >
404 PATH_NAMEBUF_SIZE) {
405
406 request.files.files_len = session->ns_fh_v3.fh_file_index;
407 request.files.files_val = session->ns_fh_v3.fh_files;
408
409 if (ndmp_send_request_lock(session->ns_connection,
410 NDMP_FH_ADD_FILE, NDMP_NO_ERR, (void *) &request, 0) < 0) {
411 syslog(LOG_ERR,
412 "Sending ndmp_fh_add_file request failed");
413 return (-1);
414 }
415
416 session->ns_fh_v3.fh_file_index = 0;
417 session->ns_fh_v3.fh_file_name_buf_index = 0;
418 }
419
420 if (name == NULL)
421 return (0);
422
423 if (session->ns_fh_v3.fh_files == 0) {
424 session->ns_fh_v3.fh_files = ndmp_malloc(sizeof (ndmp_file_v3) *
425 N_FILE_ENTRIES);
426 if (session->ns_fh_v3.fh_files == 0)
427 return (-1);
428 }
429
430 if (session->ns_fh_v3.fh_file_names == 0) {
431 session->ns_fh_v3.fh_file_names =
432 ndmp_malloc(sizeof (ndmp_file_name_v3) * N_FILE_ENTRIES);
433 if (session->ns_fh_v3.fh_file_names == 0)
434 return (-1);
435 }
436
437 if (session->ns_fh_v3.fh_file_name_buf == 0) {
438 session->ns_fh_v3.fh_file_name_buf =
439 ndmp_malloc(sizeof (char) * PATH_NAMEBUF_SIZE);
440 if (session->ns_fh_v3.fh_file_name_buf == 0)
441 return (-1);
442 }
443
444 if (session->ns_fh_v3.fh_file_stats == 0) {
445 session->ns_fh_v3.fh_file_stats =
446 ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_FILE_ENTRIES);
447 if (session->ns_fh_v3.fh_file_stats == 0)
448 return (-1);
449 }
450
451 file_entry =
452 &session->ns_fh_v3.fh_files[session->ns_fh_v3.fh_file_index];
453 file_name_entry =
454 &session->ns_fh_v3.fh_file_names[session->ns_fh_v3.fh_file_index];
455 file_stat_entry =
456 &session->ns_fh_v3.fh_file_stats[session->ns_fh_v3.fh_file_index];
457 file_entry->names.names_len = 1;
458 file_entry->names.names_val = file_name_entry;
459 file_entry->stats.stats_len = 1;
460 file_entry->stats.stats_val = file_stat_entry;
461 file_entry->node = long_long_to_quad(file_stat->st_ino);
462 file_entry->fh_info = long_long_to_quad(fh_info);
463
464 file_name_entry->fs_type = NDMP_FS_UNIX;
465 file_name_entry->ndmp_file_name_v3_u.unix_name =
466 &session->ns_fh_v3.fh_file_name_buf[session->
467 ns_fh_v3.fh_file_name_buf_index];
468 (void) strlcpy(&session->ns_fh_v3.fh_file_name_buf[session->
469 ns_fh_v3.fh_file_name_buf_index], name, PATH_NAMEBUF_SIZE);
470 session->ns_fh_v3.fh_file_name_buf_index += strlen(name) + 1;
471 ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);
472
473 file_stat_entry->invalid = 0;
474 file_stat_entry->fs_type = NDMP_FS_UNIX;
475 file_stat_entry->mtime = file_stat->st_mtime;
476 file_stat_entry->atime = file_stat->st_atime;
477 file_stat_entry->ctime = file_stat->st_ctime;
478 file_stat_entry->owner = file_stat->st_uid;
479 file_stat_entry->group = file_stat->st_gid;
480 file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
481 file_stat_entry->size =
482 long_long_to_quad((u_longlong_t)file_stat->st_size);
483 file_stat_entry->links = file_stat->st_nlink;
484
485 session->ns_fh_v3.fh_file_index++;
486
487 return (0);
488 }
489
490
491 /*
492 * ndmpd_api_file_history_dir_v3
493 *
494 * Add a file history dir entry to the buffer.
495 * History data is buffered until the buffer is filled.
496 * Full buffers are then sent to the client.
497 *
498 * Parameters:
499 * cookie (input) - session pointer.
500 * name (input) - file name.
501 * NULL forces buffered data to be sent.
502 * node (input) - file inode.
503 * parent (input) - file parent inode.
504 * Should equal node if the file is the root of
505 * the filesystem and has no parent.
506 *
507 * Returns:
508 * 0 - success
509 * -1 - error
510 */
511 int
512 ndmpd_api_file_history_dir_v3(void *cookie, char *name, ulong_t node,
513 ulong_t parent)
514 {
515 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
516 ndmp_dir_v3 *dir_entry;
517 ndmp_file_name_v3 *dir_name_entry;
518 ndmp_fh_add_dir_request_v3 request;
519
520 if (name == NULL && session->ns_fh_v3.fh_dir_index == 0)
521 return (0);
522
523 /*
524 * If the buffer does not have space
525 * for the current entry, send the buffered data to the client.
526 * A NULL name indicates that any buffered data should be sent.
527 */
528 if (name == NULL ||
529 session->ns_fh_v3.fh_dir_index == N_DIR_ENTRIES ||
530 session->ns_fh_v3.fh_dir_name_buf_index + strlen(name) + 1 >
531 DIR_NAMEBUF_SIZE) {
532
533 request.dirs.dirs_val = session->ns_fh_v3.fh_dirs;
534 request.dirs.dirs_len = session->ns_fh_v3.fh_dir_index;
535
536 if (ndmp_send_request_lock(session->ns_connection,
537 NDMP_FH_ADD_DIR, NDMP_NO_ERR, (void *) &request, 0) < 0) {
538 syslog(LOG_ERR,
539 "Sending ndmp_fh_add_dir request failed");
540 return (-1);
541 }
542
543 session->ns_fh_v3.fh_dir_index = 0;
544 session->ns_fh_v3.fh_dir_name_buf_index = 0;
545 }
546
547 if (name == NULL)
548 return (0);
549
550 if (session->ns_fh_v3.fh_dirs == 0) {
551 session->ns_fh_v3.fh_dirs =
552 ndmp_malloc(sizeof (ndmp_dir_v3) * N_DIR_ENTRIES);
553 if (session->ns_fh_v3.fh_dirs == 0)
554 return (-1);
555 }
556
557 if (session->ns_fh_v3.fh_dir_names == 0) {
558 session->ns_fh_v3.fh_dir_names =
559 ndmp_malloc(sizeof (ndmp_file_name_v3) * N_DIR_ENTRIES);
560 if (session->ns_fh_v3.fh_dir_names == 0)
561 return (-1);
562 }
563
564 if (session->ns_fh_v3.fh_dir_name_buf == 0) {
565 session->ns_fh_v3.fh_dir_name_buf =
566 ndmp_malloc(sizeof (char) * DIR_NAMEBUF_SIZE);
567 if (session->ns_fh_v3.fh_dir_name_buf == 0)
568 return (-1);
569 }
570
571 dir_entry = &session->ns_fh_v3.fh_dirs[session->ns_fh_v3.fh_dir_index];
572 dir_name_entry =
573 &session->ns_fh_v3.fh_dir_names[session->ns_fh_v3.fh_dir_index];
574
575 dir_name_entry->fs_type = NDMP_FS_UNIX;
576 dir_name_entry->ndmp_file_name_v3_u.unix_name =
577 &session->ns_fh_v3.fh_dir_name_buf[session->
578 ns_fh_v3.fh_dir_name_buf_index];
579
580 (void) strlcpy(&session->ns_fh_v3.fh_dir_name_buf[session->
581 ns_fh_v3.fh_dir_name_buf_index], name, PATH_NAMEBUF_SIZE);
582 session->ns_fh_v3.fh_dir_name_buf_index += strlen(name) + 1;
583
584 dir_entry->names.names_len = 1;
585 dir_entry->names.names_val = dir_name_entry;
586 dir_entry->node = long_long_to_quad(node);
587 dir_entry->parent = long_long_to_quad(parent);
588
589 session->ns_fh_v3.fh_dir_index++;
590
591 return (0);
592 }
593
594
595 /*
596 * ndmpd_api_file_history_node_v3
597 *
598 * Add a file history node entry to the buffer.
599 * History data is buffered until the buffer is filled.
600 * Full buffers are then sent to the client.
601 *
602 * Parameters:
603 * cookie (input) - session pointer.
604 * node (input) - file inode.
605 * must match a node from a prior ndmpd_api_file_history_dir()
606 * call.
607 * file_stat (input) - file status pointer.
608 * 0 forces buffered data to be sent.
609 * fh_info (input) - data stream position of file data used during
610 * fast restore.
611 *
612 * Returns:
613 * 0 - success
614 * -1 - error.
615 */
616 int
617 ndmpd_api_file_history_node_v3(void *cookie, ulong_t node,
618 struct stat64 *file_stat, u_longlong_t fh_info)
619 {
620 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
621 ndmp_node_v3 *node_entry;
622 ndmp_file_stat_v3 *file_stat_entry;
623 ndmp_fh_add_node_request_v3 request;
624
625 if (file_stat == NULL && session->ns_fh_v3.fh_node_index == 0)
626 return (0);
627
628 /*
629 * If the buffer does not have space
630 * for the current entry, send the buffered data to the client.
631 * A 0 file_stat pointer indicates that any buffered data should
632 * be sent.
633 */
634 if (file_stat == NULL ||
635 session->ns_fh_v3.fh_node_index == N_NODE_ENTRIES) {
636
637 /*
638 * Need to send Dir entry as well. Since Dir entry is more
639 * than a Node entry, we may send a Node entry that hasn't
640 * had its Dir entry sent. Therefore, we need to flush Dir
641 * entry as well every time the Dir entry is sent.
642 */
643 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);
644
645 request.nodes.nodes_len = session->ns_fh_v3.fh_node_index;
646 request.nodes.nodes_val = session->ns_fh_v3.fh_nodes;
647
648 if (ndmp_send_request_lock(session->ns_connection,
649 NDMP_FH_ADD_NODE,
650 NDMP_NO_ERR, (void *) &request, 0) < 0) {
651 syslog(LOG_ERR,
652 "Sending ndmp_fh_add_node request failed");
653 return (-1);
654 }
655
656 session->ns_fh_v3.fh_node_index = 0;
657 }
658
659 if (file_stat == NULL)
660 return (0);
661
662 if (session->ns_fh_v3.fh_nodes == 0) {
663 session->ns_fh_v3.fh_nodes =
664 ndmp_malloc(sizeof (ndmp_node_v3) * N_NODE_ENTRIES);
665 if (session->ns_fh_v3.fh_nodes == 0)
666 return (-1);
667 }
668
669 if (session->ns_fh_v3.fh_node_stats == 0) {
670 session->ns_fh_v3.fh_node_stats =
671 ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_NODE_ENTRIES);
672 if (session->ns_fh_v3.fh_node_stats == 0)
673 return (-1);
674 }
675
676 node_entry =
677 &session->ns_fh_v3.fh_nodes[session->ns_fh_v3.fh_node_index];
678
679 file_stat_entry =
680 &session->ns_fh_v3.fh_node_stats[session->ns_fh_v3.fh_node_index];
681 ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);
682
683 file_stat_entry->invalid = 0;
684 file_stat_entry->fs_type = NDMP_FS_UNIX;
685 file_stat_entry->mtime = file_stat->st_mtime;
686 file_stat_entry->atime = file_stat->st_atime;
687 file_stat_entry->ctime = file_stat->st_ctime;
688 file_stat_entry->owner = file_stat->st_uid;
689 file_stat_entry->group = file_stat->st_gid;
690 file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
691 file_stat_entry->size =
692 long_long_to_quad((u_longlong_t)file_stat->st_size);
693 file_stat_entry->links = file_stat->st_nlink;
694
695 node_entry->stats.stats_len = 1;
696 node_entry->stats.stats_val = file_stat_entry;
697 node_entry->node = long_long_to_quad((u_longlong_t)node);
698 node_entry->fh_info = long_long_to_quad(fh_info);
699
700 session->ns_fh_v3.fh_node_index++;
701
702 return (0);
703 }
704
705
706 /*
707 * ************************************************************************
708 * NDMP V4 HANDLERS
709 * ************************************************************************
710 */
711
712
713 /*
714 * ndmpd_fhpath_v3_cb
715 *
716 * Callback function for file history path information
717 */
718 int
719 ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t *cbp, char *path, struct stat64 *stp,
720 u_longlong_t off)
721 {
722 int err;
723 ndmp_lbr_params_t *nlp;
724 ndmpd_module_params_t *params;
725
726 if (!cbp) {
727 err = -1;
728 syslog(LOG_DEBUG, "cbp is NULL");
729 } else if (!cbp->fh_cookie) {
730 err = -1;
731 syslog(LOG_DEBUG, "cookie is NULL");
732 } else if (!path) {
733 err = -1;
734 syslog(LOG_DEBUG, "path is NULL");
735 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
736 err = -1;
737 syslog(LOG_DEBUG, "nlp is NULL");
738 } else
739 err = 0;
740
741 if (err != 0)
742 return (0);
743
744 err = 0;
745 if (NLP_ISSET(nlp, NLPF_FH)) {
746 if (!NLP_ISSET(nlp, NLPF_DIRECT)) {
747 syslog(LOG_DEBUG, "DAR NOT SET!");
748 off = 0LL;
749 }
750
751 params = get_params(cbp->fh_cookie);
752 if (!params || !params->mp_file_history_path_func) {
753 err = -1;
754 } else {
755 char *p =
756 ndmp_get_relative_path(get_backup_path_v3(params),
757 path);
758 if ((err = ndmpd_api_file_history_file_v3(cbp->
759 fh_cookie, p, stp, off)) < 0)
760 syslog(LOG_DEBUG, "\"%s\" %d", path, err);
761 }
762 }
763
764 return (err);
765 }
766
767
768 /*
769 * ndmpd_fhdir_v3_cb
770 *
771 * Callback function for file history dir information
772 */
773 int
774 ndmpd_fhdir_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, struct stat64 *stp)
775 {
776 char nm[PATH_MAX+1];
777 int nml;
778 int err;
779 ulong_t ino, pino;
780 ulong_t pos;
781 ndmp_lbr_params_t *nlp;
782 ndmpd_module_params_t *params;
783 DIR *dirp;
784 char dirpath[PATH_MAX];
785
786 if (!cbp) {
787 err = -1;
788 syslog(LOG_DEBUG, "cbp is NULL");
789 } else if (!cbp->fh_cookie) {
790 err = -1;
791 syslog(LOG_DEBUG, "cookie is NULL");
792 } else if (!dir) {
793 err = -1;
794 syslog(LOG_DEBUG, "dir is NULL");
795 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
796 err = -1;
797 syslog(LOG_DEBUG, "nlp is NULL");
798 } else
799 err = 0;
800
801 if (err != 0)
802 return (0);
803
804 if (!NLP_ISSET(nlp, NLPF_FH))
805 return (0);
806
807 /*
808 * Veritas net_backup accepts only 2 as the inode number of the backup
809 * root directory. The other way compares the path against the
810 * backup path which is slower.
811 */
812 if (stp->st_ino == nlp->nlp_bkdirino)
813 pino = ROOT_INODE;
814 else
815 pino = stp->st_ino;
816
817 /*
818 * There is nothing below this directory to be backed up.
819 * If there was, the bit for this directory would have
820 * been set. Backup root directory is exception. We
821 * always send the dir file history records of it.
822 */
823 if (pino != ROOT_INODE &&
824 !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
825 syslog(LOG_DEBUG, "nothing below here");
826 return (0);
827 }
828
829 params = nlp->nlp_params;
830 if (!params || !params->mp_file_history_dir_func)
831 return (-1);
832
833 pos = 0;
834 err = 0;
835
836 dirp = opendir(dir);
837 if (dirp == NULL)
838 return (0);
839
840 do {
841 nml = PATH_MAX;
842 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
843 if (err != 0) {
844 syslog(LOG_DEBUG,
845 "%d reading pos %u dir \"%s\"", err, pos, dir);
846 break;
847 }
848 if (nml == 0)
849 break;
850 nm[nml] = '\0';
851
852 if (pino == ROOT_INODE) {
853 if (rootfs_dot_or_dotdot(nm))
854 ino = ROOT_INODE;
855 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {
856 ino = ROOT_INODE;
857 }
858
859 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
860 continue;
861
862 /*
863 * If the entry is on exclusion list dont send the info
864 */
865 if (tlm_is_excluded(dir, nm, ndmp_excl_list)) {
866 syslog(LOG_DEBUG,
867 "name \"%s\" skipped", *nm == '\0' ? "nil" : nm);
868 continue;
869 }
870
871 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
872 ino, pino);
873 if (err < 0) {
874 syslog(LOG_ERR, "\"%s\": %d", dir, err);
875 break;
876 }
877
878 /*
879 * This is a requirement by some DMA's (net_vault) that during
880 * the incremental backup, the node info should also be sent
881 * along with the dir info for all directories leading to a
882 * backed up file.
883 */
884 if (ndmp_fhinode) {
885 struct stat64 ret_attr;
886
887 (void) strlcpy(dirpath, dir, PATH_MAX);
888 (void) strlcat(dirpath, "/", PATH_MAX);
889 (void) strlcat(dirpath, nm, PATH_MAX);
890 err = stat64(dirpath, &ret_attr);
891 if (err != 0) {
892 syslog(LOG_ERR,
893 "Error looking up %s", nm);
894 break;
895 }
896
897 if (S_ISDIR(ret_attr.st_mode)) {
898 err = (*params->mp_file_history_node_func)(cbp->
899 fh_cookie, ino, &ret_attr, 0);
900 if (err < 0) {
901 syslog(LOG_ERR, "\"%s/\": %d",
902 dir, err);
903 break;
904 }
905 }
906 }
907 } while (err == 0);
908
909 (void) closedir(dirp);
910 return (err);
911 }
912
913
914 /*
915 * ndmpd_fhnode_v3_cb
916 *
917 * Callback function for file history node information
918 */
919 int
920 ndmpd_fhnode_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
921 struct stat64 *stp, u_longlong_t off)
922 {
923 int err;
924 ulong_t ino;
925 ndmp_lbr_params_t *nlp;
926 ndmpd_module_params_t *params;
927
928 if (!cbp) {
929 err = -1;
930 syslog(LOG_DEBUG, "cbp is NULL");
931 } else if (!cbp->fh_cookie) {
932 err = -1;
933 syslog(LOG_DEBUG, "cookie is NULL");
934 } else if (!dir) {
935 err = -1;
936 syslog(LOG_DEBUG, "dir is NULL");
937 } else if (!file) {
938 err = -1;
939 syslog(LOG_DEBUG, "file is NULL");
940 } else if (!stp) {
941 err = -1;
942 syslog(LOG_DEBUG, "stp is NULL");
943 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
944 err = -1;
945 syslog(LOG_DEBUG, "nlp is NULL");
946 } else {
947 err = 0;
948 }
949
950 if (err != 0)
951 return (0);
952
953
954 err = 0;
955 if (NLP_ISSET(nlp, NLPF_FH)) {
956 if (!NLP_ISSET(nlp, NLPF_DIRECT))
957 off = 0LL;
958 if (stp->st_ino == nlp->nlp_bkdirino) {
959 ino = ROOT_INODE;
960 } else
961 ino = stp->st_ino;
962
963 params = nlp->nlp_params;
964 if (!params || !params->mp_file_history_node_func)
965 err = -1;
966 else if ((err = (*params->mp_file_history_node_func)(cbp->
967 fh_cookie, ino, stp, off)) < 0)
968 syslog(LOG_ERR, "\"%s/%s\" %d", dir, file, err);
969 }
970
971 return (err);
972 }
973
974
975 /*
976 * ndmp_send_recovery_stat_v3
977 *
978 * Send the recovery status to the DMA
979 */
980 int
981 ndmp_send_recovery_stat_v3(ndmpd_module_params_t *params,
982 ndmp_lbr_params_t *nlp, int idx, int stat)
983 {
984 int rv;
985 mem_ndmp_name_v3_t *ep;
986
987 rv = -1;
988 if (!params) {
989 syslog(LOG_DEBUG, "params == NULL");
990 } else if (!params->mp_file_recovered_func) {
991 syslog(LOG_DEBUG, "paramsfile_recovered_func == NULL");
992 } else if (!nlp) {
993 syslog(LOG_DEBUG, "nlp == NULL");
994 } else if (idx < 0) {
995 syslog(LOG_DEBUG, "idx(%d) < 0", idx);
996 } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, idx))) {
997 syslog(LOG_DEBUG, "nlist[%d] == NULL", idx);
998 } else if (!ep->nm3_opath) {
999 syslog(LOG_DEBUG, "nlist[%d].nm3_opath == NULL", idx);
1000 } else {
1001 syslog(LOG_DEBUG,
1002 "ep[%d].nm3_opath \"%s\"", idx, ep->nm3_opath);
1003 rv = MOD_FILERECOVERD(params, ep->nm3_opath, stat);
1004 }
1005
1006 return (rv);
1007 }
1008
1009
1010 /*
1011 * ndmpd_path_restored_v3
1012 *
1013 * Send the recovery status and the information for the restored
1014 * path.
1015 */
1016 /*ARGSUSED*/
1017 int
1018 ndmpd_path_restored_v3(lbr_fhlog_call_backs_t *cbp, char *name,
1019 struct stat64 *st, u_longlong_t ll_idx)
1020 {
1021 int rv;
1022 ndmp_lbr_params_t *nlp;
1023 ndmpd_module_params_t *params;
1024 int idx = (int)ll_idx;
1025
1026 if (!cbp) {
1027 syslog(LOG_DEBUG, "cbp is NULL");
1028 return (-1);
1029 }
1030 if (!name) {
1031 syslog(LOG_DEBUG, "name is NULL");
1032 return (-1);
1033 }
1034
1035 nlp = ndmp_get_nlp(cbp->fh_cookie);
1036 if (!nlp) {
1037 syslog(LOG_DEBUG, "nlp is NULL");
1038 return (-1);
1039 }
1040 if (idx < 0 || idx >= nlp->nlp_nfiles) {
1041 syslog(LOG_DEBUG, "Invalid idx: %d", idx);
1042 return (-1);
1043 }
1044 params = nlp->nlp_params;
1045 if (!params || !params->mp_file_recovered_func)
1046 return (-1);
1047
1048 if (nlp->nlp_lastidx == -1)
1049 nlp->nlp_lastidx = idx;
1050
1051 rv = 0;
1052 (void) bm_setone(nlp->nlp_rsbm, (u_longlong_t)idx);
1053 /*
1054 * Note: We should set the nm3_err here.
1055 */
1056 if (nlp->nlp_lastidx != idx) {
1057 rv = ndmp_send_recovery_stat_v3(params, nlp, nlp->nlp_lastidx,
1058 0);
1059 nlp->nlp_lastidx = idx;
1060 }
1061
1062 return (rv);
1063 }
1064
1065
1066
1067 /*
1068 * ndmpd_file_history_init
1069 *
1070 * Initialize file history variables.
1071 * Note that the entry and name buffers are not allocated here.
1072 * Since it is not know if the backup module will be sending file history
1073 * data or what kind of data (path or dir/node), the entry and name
1074 * buffers are not allocated until the first call to one of the file history
1075 * entry functions is made. This way resources are only allocated as
1076 * needed.
1077 *
1078 * Parameters:
1079 * session (input) - session pointer.
1080 *
1081 * Returns:
1082 * void
1083 */
1084 void
1085 ndmpd_file_history_init(ndmpd_session_t *session)
1086 {
1087 session->ns_fh.fh_path_entries = 0;
1088 session->ns_fh.fh_dir_entries = 0;
1089 session->ns_fh.fh_node_entries = 0;
1090 session->ns_fh.fh_path_name_buf = 0;
1091 session->ns_fh.fh_dir_name_buf = 0;
1092 session->ns_fh.fh_path_index = 0;
1093 session->ns_fh.fh_dir_index = 0;
1094 session->ns_fh.fh_node_index = 0;
1095 session->ns_fh.fh_path_name_buf_index = 0;
1096 session->ns_fh.fh_dir_name_buf_index = 0;
1097
1098 /*
1099 * V3.
1100 */
1101 session->ns_fh_v3.fh_files = 0;
1102 session->ns_fh_v3.fh_dirs = 0;
1103 session->ns_fh_v3.fh_nodes = 0;
1104 session->ns_fh_v3.fh_file_names = 0;
1105 session->ns_fh_v3.fh_dir_names = 0;
1106 session->ns_fh_v3.fh_file_stats = 0;
1107 session->ns_fh_v3.fh_node_stats = 0;
1108 session->ns_fh_v3.fh_file_name_buf = 0;
1109 session->ns_fh_v3.fh_dir_name_buf = 0;
1110 session->ns_fh_v3.fh_file_index = 0;
1111 session->ns_fh_v3.fh_dir_index = 0;
1112 session->ns_fh_v3.fh_node_index = 0;
1113 session->ns_fh_v3.fh_file_name_buf_index = 0;
1114 session->ns_fh_v3.fh_dir_name_buf_index = 0;
1115 }
1116
1117
1118 /*
1119 * ndmpd_file_history_cleanup_v2
1120 *
1121 * Send (or discard) any buffered file history entries.
1122 *
1123 * Parameters:
1124 * session (input) - session pointer.
1125 * send_flag (input) - if TRUE buffered entries are sent.
1126 * if FALSE buffered entries are discarded.
1127 *
1128 * Returns:
1129 * void
1130 */
1131 static void
1132 ndmpd_file_history_cleanup_v2(ndmpd_session_t *session, boolean_t send_flag)
1133 {
1134 if (send_flag == TRUE) {
1135 (void) ndmpd_api_file_history_path_v2(session, 0, 0, 0);
1136 (void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0);
1137 (void) ndmpd_api_file_history_node_v2(session, 0, 0, 0);
1138 }
1139
1140 if (session->ns_fh.fh_path_entries != 0) {
1141 free(session->ns_fh.fh_path_entries);
1142 session->ns_fh.fh_path_entries = 0;
1143 }
1144 if (session->ns_fh.fh_dir_entries != 0) {
1145 free(session->ns_fh.fh_dir_entries);
1146 session->ns_fh.fh_dir_entries = 0;
1147 }
1148 if (session->ns_fh.fh_node_entries != 0) {
1149 free(session->ns_fh.fh_node_entries);
1150 session->ns_fh.fh_node_entries = 0;
1151 }
1152 if (session->ns_fh.fh_path_name_buf != 0) {
1153 free(session->ns_fh.fh_path_name_buf);
1154 session->ns_fh.fh_path_name_buf = 0;
1155 }
1156 if (session->ns_fh.fh_dir_name_buf != 0) {
1157 free(session->ns_fh.fh_dir_name_buf);
1158 session->ns_fh.fh_dir_name_buf = 0;
1159 }
1160 session->ns_fh.fh_path_index = 0;
1161 session->ns_fh.fh_dir_index = 0;
1162 session->ns_fh.fh_node_index = 0;
1163 session->ns_fh.fh_path_name_buf_index = 0;
1164 session->ns_fh.fh_dir_name_buf_index = 0;
1165 }
1166
1167
1168 /*
1169 * ndmpd_file_history_cleanup_v3
1170 *
1171 * Send (or discard) any buffered file history entries.
1172 *
1173 * Parameters:
1174 * session (input) - session pointer.
1175 * send_flag (input) - if TRUE buffered entries are sent.
1176 * if FALSE buffered entries are discarded.
1177 *
1178 * Returns:
1179 * void
1180 */
1181 static void
1182 ndmpd_file_history_cleanup_v3(ndmpd_session_t *session, boolean_t send_flag)
1183 {
1184 if (send_flag == TRUE) {
1185 (void) ndmpd_api_file_history_file_v3(session, 0, 0, 0);
1186 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);
1187 (void) ndmpd_api_file_history_node_v3(session, 0, 0, 0);
1188 }
1189
1190 if (session->ns_fh_v3.fh_files != 0) {
1191 free(session->ns_fh_v3.fh_files);
1192 session->ns_fh_v3.fh_files = 0;
1193 }
1194 if (session->ns_fh_v3.fh_dirs != 0) {
1195 free(session->ns_fh_v3.fh_dirs);
1196 session->ns_fh_v3.fh_dirs = 0;
1197 }
1198 if (session->ns_fh_v3.fh_nodes != 0) {
1199 free(session->ns_fh_v3.fh_nodes);
1200 session->ns_fh_v3.fh_nodes = 0;
1201 }
1202 if (session->ns_fh_v3.fh_file_names != 0) {
1203 free(session->ns_fh_v3.fh_file_names);
1204 session->ns_fh_v3.fh_file_names = 0;
1205 }
1206 if (session->ns_fh_v3.fh_dir_names != 0) {
1207 free(session->ns_fh_v3.fh_dir_names);
1208 session->ns_fh_v3.fh_dir_names = 0;
1209 }
1210 if (session->ns_fh_v3.fh_file_stats != 0) {
1211 free(session->ns_fh_v3.fh_file_stats);
1212 session->ns_fh_v3.fh_file_stats = 0;
1213 }
1214 if (session->ns_fh_v3.fh_node_stats != 0) {
1215 free(session->ns_fh_v3.fh_node_stats);
1216 session->ns_fh_v3.fh_node_stats = 0;
1217 }
1218 if (session->ns_fh_v3.fh_file_name_buf != 0) {
1219 free(session->ns_fh_v3.fh_file_name_buf);
1220 session->ns_fh_v3.fh_file_name_buf = 0;
1221 }
1222 if (session->ns_fh_v3.fh_dir_name_buf != 0) {
1223 free(session->ns_fh_v3.fh_dir_name_buf);
1224 session->ns_fh_v3.fh_dir_name_buf = 0;
1225 }
1226
1227 session->ns_fh_v3.fh_file_index = 0;
1228 session->ns_fh_v3.fh_dir_index = 0;
1229 session->ns_fh_v3.fh_node_index = 0;
1230 session->ns_fh_v3.fh_file_name_buf_index = 0;
1231 session->ns_fh_v3.fh_dir_name_buf_index = 0;
1232 }
1233
1234
1235 /*
1236 * ndmpd_file_history_cleanup
1237 *
1238 * Send any pending posts and clean up
1239 */
1240 void
1241 ndmpd_file_history_cleanup(ndmpd_session_t *session, boolean_t send_flag)
1242 {
1243 switch (session->ns_protocol_version) {
1244 case 1:
1245 case 2:
1246 ndmpd_file_history_cleanup_v2(session, send_flag);
1247 break;
1248 case 3:
1249 case 4:
1250 ndmpd_file_history_cleanup_v3(session, send_flag);
1251 break;
1252 default:
1253 syslog(LOG_ERR, "Unknown version %d",
1254 session->ns_protocol_version);
1255 }
1256 }
1257
1258 /*
1259 * get_params
1260 *
1261 * Callbacks from LBR.
1262 */
1263 static ndmpd_module_params_t *
1264 get_params(void *cookie)
1265 {
1266 ndmp_lbr_params_t *nlp;
1267
1268 if ((nlp = ndmp_get_nlp(cookie)) == NULL)
1269 return (NULL);
1270
1271 return (nlp->nlp_params);
1272 }
1273
1274
1275 /*
1276 * fh_requested
1277 *
1278 * Check in LB parameters if file history is requested
1279 */
1280 static boolean_t
1281 fh_requested(void *cookie)
1282 {
1283 ndmp_lbr_params_t *nlp;
1284
1285 if ((nlp = ndmp_get_nlp(cookie)) == NULL) {
1286 syslog(LOG_DEBUG, "nlp is NULL");
1287 return (FALSE);
1288 }
1289
1290 syslog(LOG_DEBUG, "nlp_fh %c", NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
1291
1292 return (NLP_ISSET(nlp, NLPF_FH));
1293 }
1294
1295
1296 /*
1297 * ndmpd_file_history_path
1298 *
1299 * Generates file history path information posts
1300 *
1301 * Note:
1302 * Action must be determined when the 'dir' and/or 'file'
1303 * arguments of ndmpd_file_history_path(), ndmpd_file_history_dir(), and
1304 * ndmpd_file_history_node() are NULL.
1305 */
1306 /*ARGSUSED*/
1307 int
1308 ndmpd_file_history_path(lbr_fhlog_call_backs_t *cbp, char *path,
1309 struct stat64 *stp, u_longlong_t off)
1310 {
1311 int err;
1312 ndmpd_module_params_t *params;
1313
1314 if (!cbp) {
1315 err = -1;
1316 syslog(LOG_DEBUG, "cbp is NULL");
1317 } else if (!cbp->fh_cookie) {
1318 err = -1;
1319 syslog(LOG_DEBUG, "cookie is NULL");
1320 } else if (!path) {
1321 err = -1;
1322 syslog(LOG_DEBUG, "path is NULL");
1323 } else if (!stp) {
1324 err = -1;
1325 syslog(LOG_DEBUG, "stp is NULL");
1326 } else
1327 err = 0;
1328
1329 if (err != 0)
1330 return (0);
1331
1332 syslog(LOG_DEBUG, "path: \"%s\"", path);
1333
1334 err = 0;
1335 if (fh_requested(cbp->fh_cookie)) {
1336 params = get_params(cbp->fh_cookie);
1337 if (params == NULL || params->mp_file_history_path_func == NULL)
1338 err = -1;
1339 else if ((err = (*params->mp_file_history_path_func)(cbp->
1340 fh_cookie, path, stp, 0)) < 0)
1341 syslog(LOG_DEBUG, "\"%s\": %d", path, err);
1342 }
1343
1344 return (err);
1345 }
1346
1347
1348 /*
1349 * ndmpd_file_history_dir
1350 *
1351 * Generate file history directory information posts
1352 */
1353 int
1354 ndmpd_file_history_dir(lbr_fhlog_call_backs_t *cbp, char *dir,
1355 struct stat64 *stp)
1356 {
1357 char nm[PATH_MAX+1];
1358 int nml;
1359 int err;
1360 ulong_t ino, pino;
1361 ulong_t pos;
1362 ndmp_lbr_params_t *nlp;
1363 ndmpd_module_params_t *params;
1364 DIR *dirp;
1365 char dirpath[PATH_MAX];
1366
1367 if (!cbp) {
1368 err = -1;
1369 syslog(LOG_DEBUG, "cbp is NULL");
1370 } else if (!cbp->fh_cookie) {
1371 err = -1;
1372 syslog(LOG_DEBUG, "cookie is NULL");
1373 } else if (!dir) {
1374 err = -1;
1375 syslog(LOG_DEBUG, "dir is NULL");
1376 } else if (!stp) {
1377 err = -1;
1378 syslog(LOG_DEBUG, "stp is NULL");
1379 } if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1380 err = -1;
1381 syslog(LOG_DEBUG, "nlp is NULL");
1382 } else
1383 err = 0;
1384
1385 if (err != 0)
1386 return (0);
1387
1388 syslog(LOG_DEBUG, "dir: \"%s\"", dir);
1389
1390 if (!fh_requested(cbp->fh_cookie))
1391 return (0);
1392
1393 /*
1394 * Veritas net_backup accepts only 2 as the inode number of the backup
1395 * root directory. The other way compares the path against the
1396 * backup path which is slower.
1397 */
1398 if (stp->st_ino == nlp->nlp_bkdirino)
1399 pino = ROOT_INODE;
1400 else
1401 pino = stp->st_ino;
1402
1403 /*
1404 * There is nothing below this directory to be backed up.
1405 * If there was, the bit for this directory would have
1406 * been set. Backup root directory is exception. We
1407 * always send the dir file history records of it.
1408 */
1409 if (pino != ROOT_INODE &&
1410 !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
1411 syslog(LOG_DEBUG, "nothing below here");
1412 return (0);
1413 }
1414
1415 params = get_params(cbp->fh_cookie);
1416 if (params == NULL || params->mp_file_history_dir_func == NULL) {
1417 return (0);
1418 }
1419
1420 pos = 0;
1421 err = 0;
1422
1423 dirp = opendir(dir);
1424 if (dirp == NULL)
1425 return (0);
1426
1427 do {
1428 nml = PATH_MAX;
1429 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
1430 if (err != 0) {
1431 syslog(LOG_DEBUG,
1432 "%d reading pos %u dir \"%s\"", err, pos, dir);
1433 break;
1434 }
1435 if (nml == 0)
1436 break;
1437 nm[nml] = '\0';
1438
1439 if (pino == ROOT_INODE) {
1440 if (rootfs_dot_or_dotdot(nm))
1441 ino = ROOT_INODE;
1442 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {
1443 syslog(LOG_DEBUG, "nm(%s): %lu", nm, ino);
1444 ino = ROOT_INODE;
1445 }
1446
1447 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
1448 continue;
1449
1450 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
1451 ino, pino);
1452 if (err < 0) {
1453 syslog(LOG_ERR, "\"%s/%s\": %d", dir, nm, err);
1454 break;
1455 }
1456
1457 /*
1458 * This is a requirement by some DMA's (net_vault) that during
1459 * the incremental backup, the node info should also be sent
1460 * along with the dir info for all directories leading to a
1461 * backed up file.
1462 */
1463 if (ndmp_fhinode) {
1464 struct stat64 ret_attr;
1465
1466 (void) strlcpy(dirpath, dir, PATH_MAX);
1467 (void) strlcat(dirpath, "/", PATH_MAX);
1468 (void) strlcat(dirpath, nm, PATH_MAX);
1469 err = stat64(dirpath, &ret_attr);
1470 if (err != 0) {
1471 syslog(LOG_ERR,
1472 "Error looking up %s failed", nm);
1473 break;
1474 }
1475
1476 if (S_ISDIR(ret_attr.st_mode)) {
1477 err = (*params->mp_file_history_node_func)(cbp->
1478 fh_cookie, ino, &ret_attr, 0);
1479 if (err < 0) {
1480 syslog(LOG_DEBUG, "\"%s/\": %d",
1481 dir, err);
1482 break;
1483 }
1484 }
1485 }
1486 } while (err == 0);
1487
1488 (void) closedir(dirp);
1489 return (err);
1490 }
1491
1492
1493 /*
1494 * ndmpd_file_history_node
1495 *
1496 * Generate file history node information posts
1497 */
1498 /*ARGSUSED*/
1499 int
1500 ndmpd_file_history_node(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
1501 struct stat64 *stp, u_longlong_t off)
1502 {
1503 int err;
1504 ulong_t ino;
1505 ndmp_lbr_params_t *nlp;
1506 ndmpd_module_params_t *params;
1507
1508 if (!cbp) {
1509 err = -1;
1510 syslog(LOG_DEBUG, "cbp is NULL");
1511 } else if (!cbp->fh_cookie) {
1512 err = -1;
1513 syslog(LOG_DEBUG, "cookie is NULL");
1514 } else if (!dir) {
1515 err = -1;
1516 syslog(LOG_DEBUG, "dir is NULL");
1517 } else if (!file) {
1518 err = -1;
1519 syslog(LOG_DEBUG, "file is NULL");
1520 } else if (!stp) {
1521 err = -1;
1522 syslog(LOG_DEBUG, "stp is NULL");
1523 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1524 err = -1;
1525 syslog(LOG_DEBUG, "nlp is NULL");
1526 } else
1527 err = 0;
1528
1529 if (err != 0)
1530 return (0);
1531
1532 err = 0;
1533 if (fh_requested(cbp->fh_cookie) == TRUE) {
1534 if (stp->st_ino == nlp->nlp_bkdirino) {
1535 ino = ROOT_INODE;
1536 } else {
1537 ino = stp->st_ino;
1538 }
1539
1540 params = get_params(cbp->fh_cookie);
1541 if (params == NULL || params->mp_file_history_node_func == NULL)
1542 err = -1;
1543 else if ((err = (*params->mp_file_history_node_func)(cbp->
1544 fh_cookie, ino, stp, 0)) < 0)
1545 syslog(LOG_DEBUG, "\"%s/\": %d", dir, file, err);
1546
1547 }
1548
1549 return (err);
1550 }
1551
1552
1553 /*
1554 * ndmpd_path_restored
1555 *
1556 * Mark the specified path as a restored path
1557 */
1558 /*ARGSUSED*/
1559 int
1560 ndmpd_path_restored(lbr_fhlog_call_backs_t *cbp, char *name, struct stat64 *stp,
1561 u_longlong_t ll_pos)
1562 {
1563 int rv;
1564 ndmp_name *entp;
1565 ndmp_lbr_params_t *nlp;
1566 ndmpd_module_params_t *params;
1567 int pos = (int)ll_pos;
1568
1569 if (cbp == NULL) {
1570 syslog(LOG_DEBUG, "cbp is NULL");
1571 return (-1);
1572 }
1573 if (name == NULL) {
1574 syslog(LOG_DEBUG, "name is NULL");
1575 return (-1);
1576 }
1577
1578 if ((nlp = ndmp_get_nlp(cbp->fh_cookie)) == NULL) {
1579 syslog(LOG_DEBUG, "nlp is NULL");
1580 return (-1);
1581 }
1582 if (pos < 0 || pos >= nlp->nlp_nfiles) {
1583 syslog(LOG_DEBUG, "Invalid pos: %d", pos);
1584 return (-1);
1585 }
1586 params = get_params(cbp->fh_cookie);
1587 if (params == NULL || params->mp_file_recovered_func == NULL)
1588 return (-1);
1589
1590 rv = 0;
1591 if (!nlp->nlp_restored[pos]) {
1592 entp = (ndmp_name *)MOD_GETNAME(params, pos);
1593 if (entp && entp->name)
1594 name = entp->name;
1595
1596 if ((rv = MOD_FILERECOVERD(params, name, 0)) >= 0)
1597 nlp->nlp_restored[pos] = TRUE;
1598 }
1599
1600 return (rv);
1601 }
1602
1603
1604 /*
1605 * dp_readdir
1606 *
1607 * Reads the entry of the directory and provides other information
1608 * such as i-number, name, length and saves the dir entry position
1609 * in a cookie for future calls.
1610 */
1611 int
1612 dp_readdir(DIR *dirp, unsigned long *cookiep, char *name, int *n_namep,
1613 unsigned long *fileidp)
1614 {
1615 struct dirent *entp;
1616 int err = errno;
1617
1618 if ((entp = readdir(dirp)) == 0) {
1619 if (err == errno) {
1620 *n_namep = 0;
1621 return (0);
1622 }
1623 return (errno);
1624 }
1625
1626 *fileidp = entp->d_ino;
1627 (void) strlcpy(name, entp->d_name, *n_namep);
1628 *n_namep = entp->d_reclen + 1;
1629 *cookiep = telldir(dirp);
1630 return (0);
1631 }