/* * correct_ents * * Correct the entries in the restore list by appending the appropriate * path to them */ static int correct_ents(ndmpd_module_params_t *params, int n, char *bkpath) { char *cp, *pathname; int i, len, rv; ndmp_name *ent; if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) { MOD_LOG(params, "Error: insufficient memory.\n"); return (-1); } rv = 0; /* Append the backup path to all the "ent[].name"s. */ for (i = 0; i < n; i++) { ent = (ndmp_name *)MOD_GETNAME(params, i); NDMP_LOG(LOG_DEBUG, "Old: ent[%d].name: \"%s\"", i, ent->name); NDMP_LOG(LOG_DEBUG, "Old: ent[%d].dest: \"%s\"", i, ent->dest); /* remove trailing slash */ len = strlen(ent->name); if (ent->name[len - 1] == '/') ent->name[len - 1] = '\0'; if (!tlm_cat_path(pathname, bkpath, ent->name)) { MOD_LOG(params, "Error: path too long.\n"); rv = -1; break; } /* Make a copy of the new string and save it in ent->name. */ cp = strdup(pathname); if (cp == NULL) { MOD_LOG(params, "Error: insufficient memory.\n"); rv = -1; break; } free(ent->name); ent->name = cp; NDMP_LOG(LOG_DEBUG, "New: ent[%d].name: \"%s\"", i, ent->name); } free(pathname); return (rv); }
/* * tlm_new_dir_info * * Create a new structure, set fh field to what is specified and the path * to the concatenation of directory and the component */ struct full_dir_info * tlm_new_dir_info(struct fs_fhandle *fhp, char *dir, char *nm) { struct full_dir_info *fdip; if (!(fdip = ndmp_malloc(sizeof (struct full_dir_info)))) return (NULL); (void) memcpy(&fdip->fd_dir_fh, fhp, sizeof (fs_fhandle_t)); if (!tlm_cat_path(fdip->fd_dir_name, dir, nm)) { free(fdip); NDMP_LOG(LOG_DEBUG, "TAPE BACKUP Find> path too long [%s][%s]", dir, nm); return (NULL); } return (fdip); }
/* * see if we should exclude this file. */ boolean_t tlm_is_excluded(char *dir, char *name, char **excl_files) { int i; char full_name[TLM_MAX_PATH_NAME]; if (!dir || !name || !excl_files) return (FALSE); if (!tlm_cat_path(full_name, dir, name)) { NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name); return (FALSE); } for (i = 0; excl_files[i] != 0; i++) { if (match(excl_files[i], full_name)) { return (TRUE); } } return (FALSE); }
/* * tlm_output_file * * Put this file into the output buffers. */ longlong_t tlm_output_file(char *dir, char *name, char *chkdir, tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q) { char *fullname; /* directory + name */ char *snapname; /* snapshot name */ char *linkname; /* where this file points */ int section = 0; /* section of a huge file */ int fd; longlong_t real_size; /* the origional file size */ longlong_t file_size; /* real size of this file */ longlong_t seek_spot = 0; /* location in the file */ /* for Multi Volume record */ u_longlong_t pos; char *fnamep; /* Indicate whether a file with the same inode has been backed up. */ int hardlink_done = 0; /* * If a file with the same inode has been backed up, hardlink_pos holds * the tape offset of the data record. */ u_longlong_t hardlink_pos = 0; if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) { syslog(LOG_ERR, "Path too long [%s][%s]", dir, name); return (-TLM_NO_SCRATCH_SPACE); } fullname = ndmp_malloc(TLM_MAX_PATH_NAME); linkname = ndmp_malloc(TLM_MAX_PATH_NAME); snapname = ndmp_malloc(TLM_MAX_PATH_NAME); if (fullname == NULL || linkname == NULL || snapname == NULL) { real_size = -TLM_NO_SCRATCH_SPACE; goto err_out; } if (!tlm_cat_path(fullname, dir, name) || !tlm_cat_path(snapname, chkdir, name)) { syslog(LOG_ERR, "Path too long."); real_size = -TLM_NO_SCRATCH_SPACE; goto err_out; } pos = tlm_get_data_offset(local_commands); if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) { if (S_ISLNK(tlm_acls->acl_attr.st_mode)) { file_size = tlm_readlink(fullname, snapname, linkname, TLM_MAX_PATH_NAME-1); if (file_size < 0) { real_size = -ENOENT; goto err_out; } } /* * Since soft links can not be read(2), we should only * backup the file header. */ (void) output_file_header(fullname, linkname, tlm_acls, section, local_commands); (void) tlm_log_fhnode(job_stats, dir, name, &tlm_acls->acl_attr, pos); (void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr, pos); free(fullname); free(linkname); free(snapname); return (0); } fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname; /* * For hardlink, only read the data if no other link * belonging to the same inode has been backed up. */ if (tlm_acls->acl_attr.st_nlink > 1) { hardlink_done = !hardlink_q_get(hardlink_q, tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL); } if (!hardlink_done) { /* * Open the file for reading. */ fd = open(fnamep, O_RDONLY); if (fd == -1) { syslog(LOG_ERR, "BACKUP> Can't open file [%s][%s] err(%d)", fullname, fnamep, errno); real_size = -TLM_NO_SOURCE_FILE; goto err_out; } } else { syslog(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ", tlm_acls->acl_attr.st_ino, hardlink_pos); fd = -1; } linkname[0] = 0; real_size = tlm_acls->acl_attr.st_size; (void) output_acl_header(&tlm_acls->acl_info, local_commands); /* * section = 0: file is small enough for TAR * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks * and the file name gets munged */ file_size = real_size; if (file_size > TLM_MAX_TAR_IMAGE) { if (output_humongus_header(fullname, file_size, local_commands) < 0) { (void) close(fd); real_size = -TLM_NO_SCRATCH_SPACE; goto err_out; } section = 1; } else { section = 0; } /* * For hardlink, if other link belonging to the same inode * has been backed up, only backup an empty record. */ if (hardlink_done) file_size = 0; /* * work */ if (file_size == 0) { (void) output_file_header(fullname, linkname, tlm_acls, section, local_commands); /* * this can fall right through since zero size files * will be skipped by the WHILE loop anyway */ } while (file_size > 0) { int section_size = llmin(file_size, (longlong_t)TLM_MAX_TAR_IMAGE); tlm_acls->acl_attr.st_size = (longlong_t)section_size; (void) output_file_header(fullname, linkname, tlm_acls, section, local_commands); while (section_size > 0) { char *buf; long actual_size; int read_size; /* * check for Abort commands */ if (commands->tcs_reader != TLM_BACKUP_RUN) { local_commands->tc_writer = TLM_ABORT; goto tear_down; } local_commands->tc_buffers->tbs_buffer[ local_commands->tc_buffers->tbs_buffer_in]. tb_file_size = section_size; local_commands->tc_buffers->tbs_buffer[ local_commands->tc_buffers->tbs_buffer_in]. tb_seek_spot = seek_spot; buf = get_write_buffer(section_size, &actual_size, FALSE, local_commands); if (!buf) goto tear_down; /* * check for Abort commands */ if (commands->tcs_reader != TLM_BACKUP_RUN) { local_commands->tc_writer = TLM_ABORT; goto tear_down; } read_size = min(section_size, actual_size); actual_size = read(fd, buf, read_size); NS_ADD(rdisk, actual_size); NS_INC(rfile); if (actual_size == 0) break; if (actual_size == -1) { syslog(LOG_ERR, "problem(%d) reading file [%s][%s]", errno, fullname, snapname); goto tear_down; } seek_spot += actual_size; file_size -= actual_size; section_size -= actual_size; } section++; } /* * If data belonging to this hardlink has been backed up, add the link * to hardlink queue. */ if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) { (void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino, pos, NULL, 0); syslog(LOG_DEBUG, "backed up hardlink file %s, inode = %llu, pos = %llu ", fullname, tlm_acls->acl_attr.st_ino, pos); } /* * For hardlink, if other link belonging to the same inode has been * backed up, no add_node entry should be sent for this link. */ if (hardlink_done) { syslog(LOG_DEBUG, "backed up hardlink link %s, inode = %llu, pos = %llu ", fullname, tlm_acls->acl_attr.st_ino, hardlink_pos); } else { (void) tlm_log_fhnode(job_stats, dir, name, &tlm_acls->acl_attr, pos); } (void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr, pos); tear_down: local_commands->tc_buffers->tbs_buffer[ local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0; (void) close(fd); err_out: free(fullname); free(linkname); free(snapname); return (real_size); }
/*ARGSUSED*/ longlong_t tlm_output_xattr(char *dir, char *name, char *chkdir, tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats) { char *fullname; /* directory + name */ char *snapname; /* snapshot name */ int section; /* section of a huge file */ int fd; int afd = 0; longlong_t seek_spot = 0; /* location in the file */ /* for Multi Volume record */ DIR *dp; struct dirent *dtp; char *attrname; char *fnamep; int rv = 0; if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) { return (TLM_NO_SOURCE_FILE); } fullname = ndmp_malloc(TLM_MAX_PATH_NAME); if (fullname == NULL) { free(fullname); return (-TLM_NO_SCRATCH_SPACE); } if (!tlm_cat_path(fullname, dir, name)) { syslog(LOG_ERR, "Path too long."); free(fullname); return (-TLM_NO_SCRATCH_SPACE); } if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 && sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) { free(fullname); return (0); } attrname = ndmp_malloc(TLM_MAX_PATH_NAME); snapname = ndmp_malloc(TLM_MAX_PATH_NAME); if (attrname == NULL || snapname == NULL) { rv = -TLM_NO_SCRATCH_SPACE; goto err_out; } if (!tlm_cat_path(snapname, chkdir, name)) { syslog(LOG_ERR, "Path too long."); rv = -TLM_NO_SCRATCH_SPACE; goto err_out; } fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname; /* * Open the file for reading. */ fd = attropen(fnamep, ".", O_RDONLY); if (fd == -1) { syslog(LOG_ERR, "BACKUP> Can't open file [%s][%s]", fullname, fnamep); rv = TLM_NO_SOURCE_FILE; goto err_out; } section = 0; dp = (DIR *)fdopendir(fd); if (dp == NULL) { syslog(LOG_ERR, "BACKUP> Can't open file [%s]", fullname); (void) close(fd); rv = TLM_NO_SOURCE_FILE; goto err_out; } while ((dtp = readdir(dp)) != NULL) { int section_size; if (*dtp->d_name == '.') continue; if (sysattr_rdonly(dtp->d_name)) continue; afd = attropen(fnamep, dtp->d_name, O_RDONLY); if (afd == -1) { syslog(LOG_ERR, "problem(%d) opening xattr file [%s][%s]", errno, fullname, fnamep); goto tear_down; } (void) output_xattr_header(fullname, dtp->d_name, afd, tlm_acls, section, local_commands); (void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s", dtp->d_name); (void) output_file_header(attrname, "", tlm_acls, 0, local_commands); section_size = (long)llmin(tlm_acls->acl_attr.st_size, (longlong_t)TLM_MAX_TAR_IMAGE); /* We only can read upto one section extended attribute */ while (section_size > 0) { char *buf; long actual_size; int read_size; int sysattr_read = 0; char *rec; int size; /* * check for Abort commands */ if (commands->tcs_reader != TLM_BACKUP_RUN) { local_commands->tc_writer = TLM_ABORT; goto tear_down; } local_commands->tc_buffers->tbs_buffer[ local_commands->tc_buffers->tbs_buffer_in]. tb_file_size = section_size; local_commands->tc_buffers->tbs_buffer[ local_commands->tc_buffers->tbs_buffer_in]. tb_seek_spot = seek_spot; buf = get_write_buffer(section_size, &actual_size, FALSE, local_commands); if (!buf) goto tear_down; if ((actual_size < section_size) && sysattr_rw(dtp->d_name)) { rec = buf; buf = ndmp_malloc(section_size); if (!buf) goto tear_down; size = actual_size; actual_size = section_size; sysattr_read = 1; } /* * check for Abort commands */ if (commands->tcs_reader != TLM_BACKUP_RUN) { local_commands->tc_writer = TLM_ABORT; goto tear_down; } read_size = min(section_size, actual_size); if ((actual_size = read(afd, buf, read_size)) < 0) break; if (sysattr_read) { if (get_write_one_buf(buf, rec, read_size, size, local_commands) == 0) { free(buf); goto tear_down; } free(buf); } NS_ADD(rdisk, actual_size); NS_INC(rfile); if (actual_size == -1) { syslog(LOG_ERR, "problem(%d) reading file [%s][%s]", errno, fullname, snapname); goto tear_down; } seek_spot += actual_size; section_size -= actual_size; } (void) close(afd); afd = -1; } tear_down: local_commands->tc_buffers->tbs_buffer[ local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0; if (afd > 0) (void) close(afd); /* closedir closes fd too */ (void) closedir(dp); err_out: free(fullname); free(attrname); free(snapname); return (rv); }