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
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 }
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];
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;
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);
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);
628 int
629 ndmpd_api_file_history_node_v3(void *cookie, ulong_t node,
630 struct stat64 *file_stat, u_longlong_t fh_info)
631 {
632 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
633 ndmp_node_v3 *node_entry;
634 ndmp_file_stat_v3 *file_stat_entry;
635 ndmp_fh_add_node_request_v3 request;
636
637 if (file_stat == NULL && session->ns_fh_v3.fh_node_index == 0)
638 return (0);
639
640 /*
641 * If the buffer does not have space
642 * for the current entry, send the buffered data to the client.
643 * A 0 file_stat pointer indicates that any buffered data should
644 * be sent.
645 */
646 if (file_stat == NULL ||
647 session->ns_fh_v3.fh_node_index == N_NODE_ENTRIES) {
648 NDMP_LOG(LOG_DEBUG, "sending %ld entries",
649 session->ns_fh_v3.fh_node_index);
650
651 /*
652 * Need to send Dir entry as well. Since Dir entry is more
653 * than a Node entry, we may send a Node entry that hasn't
654 * had its Dir entry sent. Therefore, we need to flush Dir
655 * entry as well every time the Dir entry is sent.
656 */
657 (void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);
658
659 request.nodes.nodes_len = session->ns_fh_v3.fh_node_index;
660 request.nodes.nodes_val = session->ns_fh_v3.fh_nodes;
661
662 if (ndmp_send_request_lock(session->ns_connection,
663 NDMP_FH_ADD_NODE,
664 NDMP_NO_ERR, (void *) &request, 0) < 0) {
665 NDMP_LOG(LOG_DEBUG,
666 "Sending ndmp_fh_add_node request");
667 return (-1);
668 }
669
670 session->ns_fh_v3.fh_node_index = 0;
671 }
672
673 if (file_stat == NULL)
674 return (0);
675
676 if (session->ns_fh_v3.fh_nodes == 0) {
677 session->ns_fh_v3.fh_nodes =
678 ndmp_malloc(sizeof (ndmp_node_v3) * N_NODE_ENTRIES);
679 if (session->ns_fh_v3.fh_nodes == 0)
680 return (-1);
681 }
682
683 if (session->ns_fh_v3.fh_node_stats == 0) {
684 session->ns_fh_v3.fh_node_stats =
685 ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_NODE_ENTRIES);
686 if (session->ns_fh_v3.fh_node_stats == 0)
722 * NDMP V4 HANDLERS
723 * ************************************************************************
724 */
725
726
727 /*
728 * ndmpd_fhpath_v3_cb
729 *
730 * Callback function for file history path information
731 */
732 int
733 ndmpd_fhpath_v3_cb(lbr_fhlog_call_backs_t *cbp, char *path, struct stat64 *stp,
734 u_longlong_t off)
735 {
736 int err;
737 ndmp_lbr_params_t *nlp;
738 ndmpd_module_params_t *params;
739
740 if (!cbp) {
741 err = -1;
742 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
743 } else if (!cbp->fh_cookie) {
744 err = -1;
745 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
746 } else if (!path) {
747 err = -1;
748 NDMP_LOG(LOG_DEBUG, "path is NULL");
749 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
750 err = -1;
751 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
752 } else
753 err = 0;
754
755 if (err != 0)
756 return (0);
757
758 NDMP_LOG(LOG_DEBUG, "pname(%s)", path);
759
760 err = 0;
761 if (NLP_ISSET(nlp, NLPF_FH)) {
762 if (!NLP_ISSET(nlp, NLPF_DIRECT)) {
763 NDMP_LOG(LOG_DEBUG, "DAR NOT SET!");
764 off = 0LL;
765 }
766
767 params = get_params(cbp->fh_cookie);
768 if (!params || !params->mp_file_history_path_func) {
769 err = -1;
770 } else {
771 char *p =
772 ndmp_get_relative_path(get_backup_path_v3(params),
773 path);
774 if ((err = ndmpd_api_file_history_file_v3(cbp->
775 fh_cookie, p, stp, off)) < 0)
776 NDMP_LOG(LOG_DEBUG, "\"%s\" %d", path, err);
777 }
778 }
779
780 return (err);
781 }
782
783
784 /*
785 * ndmpd_fhdir_v3_cb
786 *
787 * Callback function for file history dir information
788 */
789 int
790 ndmpd_fhdir_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, struct stat64 *stp)
791 {
792 char nm[PATH_MAX+1];
793 int nml;
794 int err;
795 ulong_t ino, pino;
796 ulong_t pos;
797 ndmp_lbr_params_t *nlp;
798 ndmpd_module_params_t *params;
799 DIR *dirp;
800 char dirpath[PATH_MAX];
801
802 if (!cbp) {
803 err = -1;
804 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
805 } else if (!cbp->fh_cookie) {
806 err = -1;
807 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
808 } else if (!dir) {
809 err = -1;
810 NDMP_LOG(LOG_DEBUG, "dir is NULL");
811 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
812 err = -1;
813 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
814 } else
815 err = 0;
816
817 if (err != 0)
818 return (0);
819
820 NDMP_LOG(LOG_DEBUG, "d(%s)", dir);
821
822 if (!NLP_ISSET(nlp, NLPF_FH))
823 return (0);
824
825 /*
826 * Veritas net_backup accepts only 2 as the inode number of the backup
827 * root directory. The other way compares the path against the
828 * backup path which is slower.
829 */
830 if (stp->st_ino == nlp->nlp_bkdirino)
831 pino = ROOT_INODE;
832 else
833 pino = stp->st_ino;
834
835 /*
836 * There is nothing below this directory to be backed up.
837 * If there was, the bit for this directory would have
838 * been set. Backup root directory is exception. We
839 * always send the dir file history records of it.
840 */
841 if (pino != ROOT_INODE &&
842 !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
843 NDMP_LOG(LOG_DEBUG, "nothing below here");
844 return (0);
845 }
846
847 params = nlp->nlp_params;
848 if (!params || !params->mp_file_history_dir_func)
849 return (-1);
850
851 pos = 0;
852 err = 0;
853
854 dirp = opendir(dir);
855 if (dirp == NULL)
856 return (0);
857
858 do {
859 nml = PATH_MAX;
860 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
861 if (err != 0) {
862 NDMP_LOG(LOG_DEBUG,
863 "%d reading pos %u dir \"%s\"", err, pos, dir);
864 break;
865 }
866 if (nml == 0)
867 break;
868 nm[nml] = '\0';
869
870 if (pino == ROOT_INODE) {
871 if (rootfs_dot_or_dotdot(nm))
872 ino = ROOT_INODE;
873 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {
874 NDMP_LOG(LOG_DEBUG, "nm(%s): %lu", nm, ino);
875 ino = ROOT_INODE;
876 }
877
878 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
879 continue;
880
881 /*
882 * If the entry is on exclusion list dont send the info
883 */
884 if (tlm_is_excluded(dir, nm, ndmp_excl_list)) {
885 NDMP_LOG(LOG_DEBUG,
886 "name \"%s\" skipped", nm == 0 ? "nil" : nm);
887 continue;
888 }
889
890 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
891 ino, pino);
892 if (err < 0) {
893 NDMP_LOG(LOG_DEBUG, "\"%s\": %d", dir, err);
894 break;
895 }
896
897 /*
898 * This is a requirement by some DMA's (net_vault) that during
899 * the incremental backup, the node info should also be sent
900 * along with the dir info for all directories leading to a
901 * backed up file.
902 */
903 if (ndmp_fhinode) {
904 struct stat64 ret_attr;
905
906 (void) strlcpy(dirpath, dir, PATH_MAX);
907 (void) strlcat(dirpath, "/", PATH_MAX);
908 (void) strlcat(dirpath, nm, PATH_MAX);
909 err = stat64(dirpath, &ret_attr);
910 if (err != 0) {
911 NDMP_LOG(LOG_DEBUG,
912 "Error looking up %s", nm);
913 break;
914 }
915
916 if (S_ISDIR(ret_attr.st_mode)) {
917 err = (*params->mp_file_history_node_func)(cbp->
918 fh_cookie, ino, &ret_attr, 0);
919 if (err < 0) {
920 NDMP_LOG(LOG_DEBUG, "\"%s/\": %d",
921 dir, err);
922 break;
923 }
924 }
925 }
926 } while (err == 0);
927
928 (void) closedir(dirp);
929 return (err);
930 }
931
932
933 /*
934 * ndmpd_fhnode_v3_cb
935 *
936 * Callback function for file history node information
937 */
938 int
939 ndmpd_fhnode_v3_cb(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
940 struct stat64 *stp, u_longlong_t off)
941 {
942 int err;
943 ulong_t ino;
944 ndmp_lbr_params_t *nlp;
945 ndmpd_module_params_t *params;
946
947 if (!cbp) {
948 err = -1;
949 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
950 } else if (!cbp->fh_cookie) {
951 err = -1;
952 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
953 } else if (!dir) {
954 err = -1;
955 NDMP_LOG(LOG_DEBUG, "dir is NULL");
956 } else if (!file) {
957 err = -1;
958 NDMP_LOG(LOG_DEBUG, "file is NULL");
959 } else if (!stp) {
960 err = -1;
961 NDMP_LOG(LOG_DEBUG, "stp is NULL");
962 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
963 err = -1;
964 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
965 } else {
966 err = 0;
967 }
968
969 if (err != 0)
970 return (0);
971
972 NDMP_LOG(LOG_DEBUG, "d(%s), f(%s)", dir, file);
973
974 err = 0;
975 if (NLP_ISSET(nlp, NLPF_FH)) {
976 if (!NLP_ISSET(nlp, NLPF_DIRECT))
977 off = 0LL;
978 if (stp->st_ino == nlp->nlp_bkdirino) {
979 ino = ROOT_INODE;
980 NDMP_LOG(LOG_DEBUG,
981 "bkroot %d -> %d", stp->st_ino, ROOT_INODE);
982 } else
983 ino = stp->st_ino;
984
985 params = nlp->nlp_params;
986 if (!params || !params->mp_file_history_node_func)
987 err = -1;
988 else if ((err = (*params->mp_file_history_node_func)(cbp->
989 fh_cookie, ino, stp, off)) < 0)
990 NDMP_LOG(LOG_DEBUG, "\"%s/%s\" %d", dir, file, err);
991 }
992
993 return (err);
994 }
995
996
997 /*
998 * ndmp_send_recovery_stat_v3
999 *
1000 * Send the recovery status to the DMA
1001 */
1002 int
1003 ndmp_send_recovery_stat_v3(ndmpd_module_params_t *params,
1004 ndmp_lbr_params_t *nlp, int idx, int stat)
1005 {
1006 int rv;
1007 mem_ndmp_name_v3_t *ep;
1008
1009 rv = -1;
1010 if (!params) {
1011 NDMP_LOG(LOG_DEBUG, "params == NULL");
1012 } else if (!params->mp_file_recovered_func) {
1013 NDMP_LOG(LOG_DEBUG, "paramsfile_recovered_func == NULL");
1014 } else if (!nlp) {
1015 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1016 } else if (idx < 0) {
1017 NDMP_LOG(LOG_DEBUG, "idx(%d) < 0", idx);
1018 } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, idx))) {
1019 NDMP_LOG(LOG_DEBUG, "nlist[%d] == NULL", idx);
1020 } else if (!ep->nm3_opath) {
1021 NDMP_LOG(LOG_DEBUG, "nlist[%d].nm3_opath == NULL", idx);
1022 } else {
1023 NDMP_LOG(LOG_DEBUG,
1024 "ep[%d].nm3_opath \"%s\"", idx, ep->nm3_opath);
1025 rv = MOD_FILERECOVERD(params, ep->nm3_opath, stat);
1026 }
1027
1028 return (rv);
1029 }
1030
1031
1032 /*
1033 * ndmpd_path_restored_v3
1034 *
1035 * Send the recovery status and the information for the restored
1036 * path.
1037 */
1038 /*ARGSUSED*/
1039 int
1040 ndmpd_path_restored_v3(lbr_fhlog_call_backs_t *cbp, char *name,
1041 struct stat64 *st, u_longlong_t ll_idx)
1042 {
1043 int rv;
1044 ndmp_lbr_params_t *nlp;
1045 ndmpd_module_params_t *params;
1046 int idx = (int)ll_idx;
1047
1048 if (!cbp) {
1049 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1050 return (-1);
1051 }
1052 if (!name) {
1053 NDMP_LOG(LOG_DEBUG, "name is NULL");
1054 return (-1);
1055 }
1056
1057 NDMP_LOG(LOG_DEBUG, "name: \"%s\", idx: %d", name, idx);
1058
1059 nlp = ndmp_get_nlp(cbp->fh_cookie);
1060 if (!nlp) {
1061 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1062 return (-1);
1063 }
1064 if (idx < 0 || idx >= nlp->nlp_nfiles) {
1065 NDMP_LOG(LOG_DEBUG, "Invalid idx: %d", idx);
1066 return (-1);
1067 }
1068 params = nlp->nlp_params;
1069 if (!params || !params->mp_file_recovered_func)
1070 return (-1);
1071
1072 if (nlp->nlp_lastidx == -1)
1073 nlp->nlp_lastidx = idx;
1074
1075 rv = 0;
1076 (void) bm_setone(nlp->nlp_rsbm, (u_longlong_t)idx);
1077 /*
1078 * Note: We should set the nm3_err here.
1079 */
1080 if (nlp->nlp_lastidx != idx) {
1081 rv = ndmp_send_recovery_stat_v3(params, nlp, nlp->nlp_lastidx,
1082 0);
1083 nlp->nlp_lastidx = idx;
1084 }
1085
1257
1258
1259 /*
1260 * ndmpd_file_history_cleanup
1261 *
1262 * Send any pending posts and clean up
1263 */
1264 void
1265 ndmpd_file_history_cleanup(ndmpd_session_t *session, boolean_t send_flag)
1266 {
1267 switch (session->ns_protocol_version) {
1268 case 1:
1269 case 2:
1270 ndmpd_file_history_cleanup_v2(session, send_flag);
1271 break;
1272 case 3:
1273 case 4:
1274 ndmpd_file_history_cleanup_v3(session, send_flag);
1275 break;
1276 default:
1277 NDMP_LOG(LOG_DEBUG, "Unknown version %d",
1278 session->ns_protocol_version);
1279 }
1280 }
1281
1282 /*
1283 * get_params
1284 *
1285 * Callbacks from LBR.
1286 */
1287 static ndmpd_module_params_t *
1288 get_params(void *cookie)
1289 {
1290 ndmp_lbr_params_t *nlp;
1291
1292 if ((nlp = ndmp_get_nlp(cookie)) == NULL)
1293 return (NULL);
1294
1295 return (nlp->nlp_params);
1296 }
1297
1298
1299 /*
1300 * fh_requested
1301 *
1302 * Check in LB parameters if file history is requested
1303 */
1304 static boolean_t
1305 fh_requested(void *cookie)
1306 {
1307 ndmp_lbr_params_t *nlp;
1308
1309 if ((nlp = ndmp_get_nlp(cookie)) == NULL) {
1310 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1311 return (FALSE);
1312 }
1313
1314 NDMP_LOG(LOG_DEBUG, "nlp_fh %c", NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
1315
1316 return (NLP_ISSET(nlp, NLPF_FH));
1317 }
1318
1319
1320 /*
1321 * ndmpd_file_history_path
1322 *
1323 * Generates file history path information posts
1324 *
1325 * Note:
1326 * Action must be determined when the 'dir' and/or 'file'
1327 * arguments of ndmpd_file_history_path(), ndmpd_file_history_dir(), and
1328 * ndmpd_file_history_node() are NULL.
1329 */
1330 /*ARGSUSED*/
1331 int
1332 ndmpd_file_history_path(lbr_fhlog_call_backs_t *cbp, char *path,
1333 struct stat64 *stp, u_longlong_t off)
1334 {
1335 int err;
1336 ndmpd_module_params_t *params;
1337
1338 if (!cbp) {
1339 err = -1;
1340 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1341 } else if (!cbp->fh_cookie) {
1342 err = -1;
1343 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
1344 } else if (!path) {
1345 err = -1;
1346 NDMP_LOG(LOG_DEBUG, "path is NULL");
1347 } else if (!stp) {
1348 err = -1;
1349 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1350 } else
1351 err = 0;
1352
1353 if (err != 0)
1354 return (0);
1355
1356 NDMP_LOG(LOG_DEBUG, "path: \"%s\"", path);
1357
1358 err = 0;
1359 if (fh_requested(cbp->fh_cookie)) {
1360 params = get_params(cbp->fh_cookie);
1361 if (params == NULL || params->mp_file_history_path_func == NULL)
1362 err = -1;
1363 else if ((err = (*params->mp_file_history_path_func)(cbp->
1364 fh_cookie, path, stp, 0)) < 0)
1365 NDMP_LOG(LOG_DEBUG, "\"%s\": %d", path, err);
1366 }
1367
1368 return (err);
1369 }
1370
1371
1372 /*
1373 * ndmpd_file_history_dir
1374 *
1375 * Generate file history directory information posts
1376 */
1377 int
1378 ndmpd_file_history_dir(lbr_fhlog_call_backs_t *cbp, char *dir,
1379 struct stat64 *stp)
1380 {
1381 char nm[PATH_MAX+1];
1382 int nml;
1383 int err;
1384 ulong_t ino, pino;
1385 ulong_t pos;
1386 ndmp_lbr_params_t *nlp;
1387 ndmpd_module_params_t *params;
1388 DIR *dirp;
1389 char dirpath[PATH_MAX];
1390
1391 if (!cbp) {
1392 err = -1;
1393 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1394 } else if (!cbp->fh_cookie) {
1395 err = -1;
1396 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
1397 } else if (!dir) {
1398 err = -1;
1399 NDMP_LOG(LOG_DEBUG, "dir is NULL");
1400 } else if (!stp) {
1401 err = -1;
1402 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1403 } if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1404 err = -1;
1405 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1406 } else
1407 err = 0;
1408
1409 if (err != 0)
1410 return (0);
1411
1412 NDMP_LOG(LOG_DEBUG, "dir: \"%s\"", dir);
1413
1414 if (!fh_requested(cbp->fh_cookie))
1415 return (0);
1416
1417 /*
1418 * Veritas net_backup accepts only 2 as the inode number of the backup
1419 * root directory. The other way compares the path against the
1420 * backup path which is slower.
1421 */
1422 if (stp->st_ino == nlp->nlp_bkdirino)
1423 pino = ROOT_INODE;
1424 else
1425 pino = stp->st_ino;
1426
1427 /*
1428 * There is nothing below this directory to be backed up.
1429 * If there was, the bit for this directory would have
1430 * been set. Backup root directory is exception. We
1431 * always send the dir file history records of it.
1432 */
1433 if (pino != ROOT_INODE &&
1434 !dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino)) {
1435 NDMP_LOG(LOG_DEBUG, "nothing below here");
1436 return (0);
1437 }
1438
1439 params = get_params(cbp->fh_cookie);
1440 if (params == NULL || params->mp_file_history_dir_func == NULL) {
1441 return (0);
1442 }
1443
1444 pos = 0;
1445 err = 0;
1446
1447 dirp = opendir(dir);
1448 if (dirp == NULL)
1449 return (0);
1450
1451 do {
1452 nml = PATH_MAX;
1453 err = dp_readdir(dirp, &pos, nm, &nml, &ino);
1454 if (err != 0) {
1455 NDMP_LOG(LOG_DEBUG,
1456 "%d reading pos %u dir \"%s\"", err, pos, dir);
1457 break;
1458 }
1459 if (nml == 0)
1460 break;
1461 nm[nml] = '\0';
1462
1463 if (pino == ROOT_INODE) {
1464 if (rootfs_dot_or_dotdot(nm))
1465 ino = ROOT_INODE;
1466 } else if (ino == nlp->nlp_bkdirino && IS_DOTDOT(nm)) {
1467 NDMP_LOG(LOG_DEBUG, "nm(%s): %lu", nm, ino);
1468 ino = ROOT_INODE;
1469 }
1470
1471 if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)ino))
1472 continue;
1473
1474 err = (*params->mp_file_history_dir_func)(cbp->fh_cookie, nm,
1475 ino, pino);
1476 if (err < 0) {
1477 NDMP_LOG(LOG_DEBUG, "\"%s/%s\": %d", dir, nm, err);
1478 break;
1479 }
1480
1481 /*
1482 * This is a requirement by some DMA's (net_vault) that during
1483 * the incremental backup, the node info should also be sent
1484 * along with the dir info for all directories leading to a
1485 * backed up file.
1486 */
1487 if (ndmp_fhinode) {
1488 struct stat64 ret_attr;
1489
1490 (void) strlcpy(dirpath, dir, PATH_MAX);
1491 (void) strlcat(dirpath, "/", PATH_MAX);
1492 (void) strlcat(dirpath, nm, PATH_MAX);
1493 err = stat64(dirpath, &ret_attr);
1494 if (err != 0) {
1495 NDMP_LOG(LOG_DEBUG,
1496 "Error looking up %s", nm);
1497 break;
1498 }
1499
1500 if (S_ISDIR(ret_attr.st_mode)) {
1501 err = (*params->mp_file_history_node_func)(cbp->
1502 fh_cookie, ino, &ret_attr, 0);
1503 if (err < 0) {
1504 NDMP_LOG(LOG_DEBUG, "\"%s/\": %d",
1505 dir, err);
1506 break;
1507 }
1508 }
1509 }
1510 } while (err == 0);
1511
1512 (void) closedir(dirp);
1513 return (err);
1514 }
1515
1516
1517 /*
1518 * ndmpd_file_history_node
1519 *
1520 * Generate file history node information posts
1521 */
1522 /*ARGSUSED*/
1523 int
1524 ndmpd_file_history_node(lbr_fhlog_call_backs_t *cbp, char *dir, char *file,
1525 struct stat64 *stp, u_longlong_t off)
1526 {
1527 int err;
1528 ulong_t ino;
1529 ndmp_lbr_params_t *nlp;
1530 ndmpd_module_params_t *params;
1531
1532 if (!cbp) {
1533 err = -1;
1534 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1535 } else if (!cbp->fh_cookie) {
1536 err = -1;
1537 NDMP_LOG(LOG_DEBUG, "cookie is NULL");
1538 } else if (!dir) {
1539 err = -1;
1540 NDMP_LOG(LOG_DEBUG, "dir is NULL");
1541 } else if (!file) {
1542 err = -1;
1543 NDMP_LOG(LOG_DEBUG, "file is NULL");
1544 } else if (!stp) {
1545 err = -1;
1546 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1547 } else if (!(nlp = ndmp_get_nlp(cbp->fh_cookie))) {
1548 err = -1;
1549 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1550 } else
1551 err = 0;
1552
1553 if (err != 0)
1554 return (0);
1555
1556 NDMP_LOG(LOG_DEBUG, "d(%s), f(%s)", dir, file);
1557
1558 err = 0;
1559 if (fh_requested(cbp->fh_cookie) == TRUE) {
1560 if (stp->st_ino == nlp->nlp_bkdirino) {
1561 ino = ROOT_INODE;
1562 NDMP_LOG(LOG_DEBUG,
1563 "bkroot %d -> %d", stp->st_ino, ROOT_INODE);
1564 } else {
1565 ino = stp->st_ino;
1566 }
1567
1568 params = get_params(cbp->fh_cookie);
1569 if (params == NULL || params->mp_file_history_node_func == NULL)
1570 err = -1;
1571 else if ((err = (*params->mp_file_history_node_func)(cbp->
1572 fh_cookie, ino, stp, 0)) < 0)
1573 NDMP_LOG(LOG_DEBUG, "\"%s/\": %d", dir, file, err);
1574
1575 }
1576
1577 return (err);
1578 }
1579
1580
1581 /*
1582 * ndmpd_path_restored
1583 *
1584 * Mark the specified path as a restored path
1585 */
1586 /*ARGSUSED*/
1587 int
1588 ndmpd_path_restored(lbr_fhlog_call_backs_t *cbp, char *name, struct stat64 *stp,
1589 u_longlong_t ll_pos)
1590 {
1591 int rv;
1592 ndmp_name *entp;
1593 ndmp_lbr_params_t *nlp;
1594 ndmpd_module_params_t *params;
1595 int pos = (int)ll_pos;
1596
1597 if (cbp == NULL) {
1598 NDMP_LOG(LOG_DEBUG, "cbp is NULL");
1599 return (-1);
1600 }
1601 if (name == NULL) {
1602 NDMP_LOG(LOG_DEBUG, "name is NULL");
1603 return (-1);
1604 }
1605
1606 NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d",
1607 name, pos);
1608
1609 if ((nlp = ndmp_get_nlp(cbp->fh_cookie)) == NULL) {
1610 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1611 return (-1);
1612 }
1613 if (pos < 0 || pos >= nlp->nlp_nfiles) {
1614 NDMP_LOG(LOG_DEBUG, "Invalid pos: %d", pos);
1615 return (-1);
1616 }
1617 params = get_params(cbp->fh_cookie);
1618 if (params == NULL || params->mp_file_recovered_func == NULL)
1619 return (-1);
1620
1621 rv = 0;
1622 if (!nlp->nlp_restored[pos]) {
1623 entp = (ndmp_name *)MOD_GETNAME(params, pos);
1624 if (entp && entp->name)
1625 name = entp->name;
1626
1627 if ((rv = MOD_FILERECOVERD(params, name, 0)) >= 0)
1628 nlp->nlp_restored[pos] = TRUE;
1629 }
1630
1631 return (rv);
1632 }
1633
1634
|
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
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 }
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];
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;
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);
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);
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)
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
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
|