/* * tlm_output_dir * * Put the directory information into the output buffers. */ int tlm_output_dir(char *name, tlm_acls_t *tlm_acls, tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats) { u_longlong_t pos; /* * Send the node or path history of the directory itself. */ pos = tlm_get_data_offset(local_commands); (void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos); (void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos); /* fhdir_cb is handled in ndmpd_tar3.c */ (void) output_acl_header(&tlm_acls->acl_info, local_commands); (void) output_file_header(name, "", tlm_acls, 0, local_commands); return (0); }
int write_file (struct wnn_file *wf, char *n) { FILE *fp; int mode = 3; struct wnn_file_head fh; #ifdef WRITE_CHECK char *tmp = NULL, *backup = NULL; check_backup (n); #endif if ((fp = fopen (n, "r")) != NULL) { /* Old File Exist */ if (input_file_header (fp, &fh) == -1) { wnn_errorno = WNN_NOT_A_FILE; fclose (fp); return (-1); } mode = must_write_file (wf, &(fh.file_uniq)); fclose (fp); if (mode == -1) return -1; } if (mode == 0) { return (0); /* Need Not Write */ } else if (mode == 1 || mode == 3) { /* 3 when the file is not the one to be read. */ #ifdef WRITE_CHECK backup = make_backup_file (n); if ((tmp = make_tmp_file (n, 0, &fp)) == NULL) { delete_tmp_file (backup); #else /* WRITE_CHECK */ if ((fp = fopen (n, "w+")) == NULL) { #endif /* WRITE_CHECK */ wnn_errorno = WNN_FILE_WRITE_ERROR; return (-1); } } else if (mode == 2) { #ifdef WRITE_CHECK backup = make_backup_file (n); if ((tmp = make_tmp_file (n, 1, &fp)) == NULL) { delete_tmp_file (backup); #else /* WRITE_CHECK */ if ((fp = fopen (n, "r+")) == NULL) { /* New File */ #endif /* WRITE_CHECK */ wnn_errorno = WNN_FILE_WRITE_ERROR; return (-1); } } if (write_file_real (wf, fp, mode) == -1) { fclose (fp); #ifdef WRITE_CHECK delete_tmp_file (tmp); delete_tmp_file (backup); #endif /* WRITE_CHECK */ return -1; } fclose (fp); #ifdef WRITE_CHECK move_tmp_to_org (tmp, n, 1); delete_tmp_file (backup); #endif /* WRITE_CHECK */ if ((mode == 1) || (mode == 2)) { clear_dirty_bit (wf); } return (0); } static int write_file_real (struct wnn_file *wf, FILE *fp, int mode /* 1 For All, 2 For only hindo */ ) { struct wnn_file_head fh; if (fp) rewind (fp); bcopy ((char *) &wf->f_uniq, (char *) &(fh.file_uniq), WNN_F_UNIQ_LEN); bcopy ((char *) &wf->f_uniq_org, (char *) &(fh.file_uniq_org), WNN_F_UNIQ_LEN); bcopy (wf->passwd, fh.file_passwd, WNN_PASSWD_LEN); fh.file_type = wf->file_type; if (output_file_header (fp, &fh) == -1) { wnn_errorno = WNN_FILE_WRITE_ERROR; goto ERROR_RET; } switch (fh.file_type) { case WNN_FT_DICT_FILE: { struct JT *jt2; struct JT *jt = (struct JT *) wf->area; if (little_endian () && jt->dirty) { if ((jt2 = copy_dict ((struct JT *) wf->area)) == NULL) goto ERROR_RET; revdic (jt2, 1); if (writedict (jt2, fp) == -1) goto ERROR_RET; jt2 = free_dict (jt2); } else { /* if(writedict(wf->area, fp) == -1)goto ERROR_RET; */ if (mode == 2) { if (write_hindo_of_dict (wf->area, fp) == -1) goto ERROR_RET; } else { if (writedict (wf->area, fp) == -1) goto ERROR_RET; } } } break; case WNN_FT_HINDO_FILE: if (writehindo (wf->area, fp) == -1) goto ERROR_RET; break; case WNN_FT_FUZOKUGO_FILE: wnn_errorno = NOT_SUPPORTED_OPERATION; goto ERROR_RET; } return (0); ERROR_RET: return (-1); } static int writedict (struct JT *jt1, FILE *fp) { if (output_header_jt (fp, jt1) == -1) return (-1); #ifdef WRITE_CHECK if ((vfwrite (jt1->comment, 2, jt1->maxcomment, fp) == -1) || (vfwrite (jt1->hinsi_list, 2, jt1->maxhinsi_list, fp) == -1) || (vfwrite (jt1->hindo, 1, jt1->maxserial, fp) == -1) || (vfwrite (jt1->hinsi, 2, jt1->maxserial, fp) == -1)) return (-1); #ifdef CONVERT_with_SiSheng if (jt1->syurui == CWNN_REV_DICT) /* for Chinese PinYin dic only */ if (vfwrite (jt1->sisheng, 2, jt1->maxserial, fp) == -1) return (-1); #endif /* CONVERT_with_SiSheng */ if ((vfwrite (jt1->kanji, 1, jt1->maxkanji, fp) == -1) || (vfwrite (jt1->table, sizeof (struct uind1), jt1->maxtable, fp) == -1) || (vfwrite (jt1->ri1[D_YOMI], sizeof (struct rind1), jt1->maxri1[D_YOMI], fp) == -1) || (vfwrite (jt1->ri1[D_KANJI], sizeof (struct rind1), jt1->maxri1[D_KANJI], fp) == -1) || (vfwrite (jt1->hontai, 1, jt1->maxhontai, fp) == -1) || (vfwrite (jt1->ri2, sizeof (struct rind2), jt1->maxri2, fp) == -1)) return (-1); #else /* WRITE_CHECK */ vfwrite (jt1->comment, 2, jt1->maxcomment, fp); vfwrite (jt1->hinsi_list, 2, jt1->maxhinsi_list, fp); vfwrite (jt1->hindo, 1, jt1->maxserial, fp); vfwrite (jt1->hinsi, 2, jt1->maxserial, fp); #ifdef CONVERT_with_SiSheng if (jt1->syurui == CWNN_REV_DICT) /* for Chinese PinYin dic only */ vfwrite (jt1->sisheng, 2, jt1->maxserial, fp); #endif /* CONVERT_with_SiSheng */ vfwrite (jt1->kanji, 1, jt1->maxkanji, fp); vfwrite (jt1->table, sizeof (struct uind1), jt1->maxtable, fp); vfwrite (jt1->ri1[D_YOMI], sizeof (struct rind1), jt1->maxri1[D_YOMI], fp); vfwrite (jt1->ri1[D_KANJI], sizeof (struct rind1), jt1->maxri1[D_KANJI], fp); vfwrite (jt1->hontai, 1, jt1->maxhontai, fp); vfwrite (jt1->ri2, sizeof (struct rind2), jt1->maxri2, fp); #endif /* WRITE_CHECK */ return (0); } static int write_hindo_of_dict (struct JT *jt1, FILE *fp) { if (output_header_jt (fp, jt1) == -1) return (-1); #ifdef WRITE_CHECK if ((vfwrite (jt1->comment, 2, jt1->maxcomment, fp) == -1) || (vfwrite (jt1->hindo, 1, jt1->maxserial, fp) == -1)) return (-1); #else /* WRITE_CHECK */ vfwrite (jt1->comment, 2, jt1->maxcomment, fp); vfwrite (jt1->hindo, 1, jt1->maxserial, fp); #endif /* WRITE_CHECK */ return (0); } int discardfile (struct wnn_file *wf) { #ifdef nodef FILE *fp; if (wf->localf == LOCAL) { if ((fp = fopen (wf->name, "r")) == NULL) { log_err ("discardfile:No file %s.", wf->name); return (-1); } fclose (fp); } #endif switch (wf->file_type) { case WNN_FT_DICT_FILE: wf->area = free_dict (wf->area); break; case WNN_FT_HINDO_FILE: wf->area = free_hindo (wf->area); break; case WNN_FT_FUZOKUGO_FILE: /* fzk_discard(wf->area); */ break; } return (0); }
/* * 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); }