/* * mark_commonv3 * * Create the inode bitmap. If last date of the the * backup is epoch, then all the objects should be backed * up; there is no need to traverse the backup hierarchy * and mark the inodes. All the bits should be marked. * * Otherwise, the backup hierarchy should be traversed and * the objects should be marked. * * Parameters: * session (input) - pointer to the session * nlp (input) - pointer to the nlp structure * * Returns: * 0: on success. * != 0: on error. */ int mark_commonv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp) { char buf[TLM_MAX_PATH_NAME], *chkpath; int rv; if (NLP_ISCHKPNTED(nlp)) chkpath = nlp->nlp_backup_path; else chkpath = tlm_build_snapshot_name(nlp->nlp_backup_path, buf, nlp->nlp_jstat->js_job_name); if (NLP_ISSET(nlp, NLPF_TOKENBK)) rv = mark_tokv3(session, nlp, chkpath); else if (NLP_ISSET(nlp, NLPF_LBRBK)) rv = mark_lbrv3(session, nlp, chkpath); else if (NLP_ISSET(nlp, NLPF_LEVELBK)) { rv = mark_levelv3(session, nlp, chkpath); } else { rv = -1; syslog(LOG_ERR, "Unknown backup type for \"%s\"", nlp->nlp_backup_path); } return (rv); }
/* * mark_common_v2 * * Create the inode bitmap. If last date of the the * backup is epoch, then all the objects should be backed * up; there is no need to traverse the backup hierarchy * and mark the inodes. All the bits should be marked. * * Otherwise, the backup hierarchy should be traversed and * the objects should be marked. * * Parameters: * session (input) - pointer to the session * nlp (input) - pointer to the nlp structure * * Returns: * 0: on success. * != 0: on error. */ static int mark_common_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp) { char buf[TLM_MAX_PATH_NAME], *chkpath; int rv; /* * Everything is needed for full backup. */ if (nlp->nlp_ldate == (time_t)0) return (create_allset_bitmap(nlp)); rv = 0; nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0); syslog(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap); if (nlp->nlp_bkmap < 0) { syslog(LOG_ERR, "Failed to allocate bitmap in mark_common_v2"); rv = -1; } else { if (fs_is_chkpntvol(nlp->nlp_backup_path)) chkpath = nlp->nlp_backup_path; else chkpath = tlm_build_snapshot_name( nlp->nlp_backup_path, buf, nlp->nlp_jstat->js_job_name); rv = mark_inodes_v2(session, nlp, chkpath); (void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE); } return (rv); }
/* * backup_work * * Start the NDMP backup (V2 only). */ int backup_work(char *bk_path, tlm_job_stats_t *job_stats, ndmp_run_args_t *np, tlm_commands_t *commands, ndmp_lbr_params_t *nlp) { struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */ struct full_dir_info *t_dir_info, *p_dir_info; struct stat64 ret_attr; /* attributes of current file name */ fs_fhandle_t ret_fh; char *first_name; /* where the first name is located */ char *dname; int erc; int retval; cstack_t *stk; unsigned long fileid; tlm_acls_t tlm_acls; int dname_size; longlong_t fsize; bk_selector_t bks; tlm_cmd_t *local_commands; long dpos; NDMP_LOG(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"", NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path); /* Get every name in this directory */ dname = ndmp_malloc(TLM_MAX_PATH_NAME); if (dname == NULL) return (-ENOMEM); local_commands = commands->tcs_command; retval = 0; (void) memset(&bks, 0, sizeof (bks)); bks.bs_cookie = (void *)nlp; bks.bs_level = nlp->nlp_clevel; bks.bs_ldate = nlp->nlp_ldate; bks.bs_fn = timecmp; /* * should we skip the whole thing? */ if (tlm_is_excluded("", bk_path, np->nr_excls)) { NDMP_LOG(LOG_DEBUG, "%s excluded", bk_path); free(dname); return (0); } /* * Search for the top-level file-directory */ if (NLP_ISCHKPNTED(nlp)) { first_name = np->nr_chkp_nm; (void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME); } else { first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm, nlp->nlp_jstat->js_job_name); } (void) memset(&ret_fh, 0, sizeof (ret_fh)); erc = fs_getstat(first_name, &ret_fh, &ret_attr); if (erc != 0) { NDMP_LOG(LOG_ERR, "Path %s not found.", first_name); free(dname); return (-EINVAL); } if ((stk = cstack_new()) == NULL) { free(dname); NDMP_LOG(LOG_DEBUG, "cstack_new failed"); return (-ENOMEM); } (void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME); (void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t)); p_dir_info = dup_dir_info(&dir_info); /* * Push the first name onto the stack so that we can pop it back * off as part of the normal cycle */ if (cstack_push(stk, p_dir_info, 0)) { free(dname); free(p_dir_info); cstack_delete(stk); NDMP_LOG(LOG_DEBUG, "cstack_push failed"); return (-ENOMEM); } (void) memset(&tlm_acls, 0, sizeof (tlm_acls)); /* * Did NDMP create a checkpoint? */ if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) { tlm_acls.acl_checkpointed = FALSE; } else { /* Use the checkpoint created by NDMP */ tlm_acls.acl_checkpointed = TRUE; } /* * This is level-backup. It never resets the archive bit. */ tlm_acls.acl_clear_archive = FALSE; NDMP_LOG(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c", NDMP_YORN(tlm_acls.acl_checkpointed), NDMP_YORN(tlm_acls.acl_clear_archive)); while (commands->tcs_reader == TLM_BACKUP_RUN && local_commands->tc_reader == TLM_BACKUP_RUN && cstack_pop(stk, (void **)&p_dir_info, 0) == 0) { if (NLP_ISCHKPNTED(nlp)) (void) strlcpy(np->nr_unchkp_nm, p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME); else (void) tlm_remove_checkpoint(p_dir_info->fd_dir_name, np->nr_unchkp_nm); (void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands, job_stats, &bks); while (commands->tcs_reader == TLM_BACKUP_RUN && local_commands->tc_reader == TLM_BACKUP_RUN) { dname_size = TLM_MAX_PATH_NAME - 1; NDMP_LOG(LOG_DEBUG, "dir_name: %s", p_dir_info->fd_dir_name); (void) memset(&ret_fh, 0, sizeof (ret_fh)); erc = fs_readdir(&p_dir_info->fd_dir_fh, p_dir_info->fd_dir_name, &dpos, dname, &dname_size, &ret_fh, &ret_attr); if (erc == 0) { fileid = ret_fh.fh_fid; } else { NDMP_LOG(LOG_DEBUG, "Filesystem readdir in [%s]", p_dir_info->fd_dir_name); retval = -ENOENT; break; } /* an empty name size marks the end of the list */ if (dname_size == 0) break; dname[dname_size] = '\0'; NDMP_LOG(LOG_DEBUG, "dname: \"%s\"", dname); /* * If name refers to a directory, push its file * handle onto the stack (skip "." and ".."). */ if (rootfs_dot_or_dotdot(dname)) { fileid = 0; continue; } /* * Skip the: * non-dir entries which should not be backed up * Or * dir-type entries which have have nothing under * their hierarchy to be backed up. */ if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) { NDMP_LOG(LOG_DEBUG, "Skipping %s/%s", p_dir_info->fd_dir_name, dname); fileid = 0; continue; } if (tlm_is_excluded(np->nr_unchkp_nm, dname, np->nr_excls)) { fileid = 0; continue; } if (S_ISDIR(ret_attr.st_mode)) { /* * only directories get pushed onto this stack, * so we do not have to test for regular files. */ t_dir_info = tlm_new_dir_info(&ret_fh, p_dir_info->fd_dir_name, dname); if (t_dir_info == NULL) { NDMP_LOG(LOG_DEBUG, "While backing up [%s][%s]", p_dir_info->fd_dir_name, dname); } else if (cstack_push(stk, t_dir_info, 0) != 0) { NDMP_LOG(LOG_DEBUG, "No enough memory stack_push"); retval = -ENOMEM; break; } } else if (S_ISREG(ret_attr.st_mode) || S_ISLNK(ret_attr.st_mode)) { fsize = backup_file(np->nr_unchkp_nm, dname, &tlm_acls, commands, local_commands, job_stats, &bks); if (fsize >= 0) { job_stats->js_files_so_far++; job_stats->js_bytes_total += fsize; } else job_stats->js_errors++; fileid = 0; } } fileid = 0; free(p_dir_info); if (retval != 0) break; } free(dname); while (cstack_pop(stk, (void **)&p_dir_info, 0) == 0) { free(p_dir_info); } cstack_delete(stk); return (retval); }
/* * get_dir_acl_info * * load up all ACL and attr info about a directory */ static int get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js) { int erc; char *checkpointed_dir; char root_dir[TLM_VOLNAME_MAX_LENGTH]; char *spot; char *fil; acl_t *aclp = NULL; char *acltp; checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME); if (checkpointed_dir == NULL) return (-1); if (tlm_acls->acl_checkpointed) fil = tlm_build_snapshot_name(dir, checkpointed_dir, js->js_job_name); else fil = dir; erc = lstat64(fil, &tlm_acls->acl_attr); if (erc != 0) { NDMP_LOG(LOG_ERR, "Could not find directory %s.", dir); free(checkpointed_dir); return (-1); } spot = strchr(&fil[1], '/'); if (spot == NULL) { (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH); } else { *spot = 0; (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH); *spot = '/'; } if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) { struct stat64 attr; erc = lstat64(root_dir, &attr); if (erc != 0) { NDMP_LOG(LOG_ERR, "Cannot find root directory %s.", root_dir); free(checkpointed_dir); return (-1); } (void) strlcpy(tlm_acls->acl_root_dir, root_dir, TLM_VOLNAME_MAX_LENGTH); } erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp); if (erc != 0) { NDMP_LOG(LOG_DEBUG, "Could not read metadata for directory [%s]", dir); free(checkpointed_dir); return (-1); } if (aclp && (acltp = acl_totext(aclp, ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { (void) strlcpy(tlm_acls->acl_info.attr_info, acltp, TLM_MAX_ACL_TXT); acl_free(aclp); free(acltp); } free(checkpointed_dir); return (0); }