/* * Read the system attribute file in a single buffer to write * it as a single write. A partial write to system attribute would * cause an EINVAL on write. */ static char * get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size, tlm_cmd_t *lc) { int len; long write_size; if (rec_size > buf_size) return (rec); len = rec_size; (void) memcpy(rec, buf, len); buf += len; while (rec_size < buf_size) { rec = get_write_buffer(buf_size - rec_size, &write_size, FALSE, lc); if (!rec) return (0); len = min(buf_size - rec_size, write_size); (void) memcpy(rec, buf, len); rec_size += len; buf += len; } return (rec); }
void panda_writer_unref( PandaWriter writer) { size_t count; if (writer == NULL) return; #ifdef HAVE_PTHREAD flush_buffer(writer, get_write_buffer(writer)); pthread_mutex_lock(&writer->mutex); #endif count = --(writer->refcnt); #ifdef HAVE_PTHREAD pthread_mutex_unlock(&writer->mutex); #endif if (count == 0) { #ifdef HAVE_PTHREAD struct write_buffer *data; pthread_key_delete(writer->buffers); pthread_mutex_destroy(&writer->mutex); data = writer->buffer_list; while (data != NULL) { struct write_buffer *temp = data->next; writer->write(data->committed, data->committed_length, data->owner->write_data); writer->write(data->uncommitted, data->uncommitted_length, data->owner->write_data); free(data); data = temp; } if (writer->commit_slave != NULL) panda_writer_unref(writer->commit_slave); #endif DESTROY_MEMBER(writer, write); free(writer); } }
void panda_writer_flush( PandaWriter writer) { #ifdef HAVE_PTHREAD flush_buffer(writer, get_write_buffer(writer)); #else (void) writer; #endif }
void panda_writer_append_c( PandaWriter writer, char c) { #ifdef HAVE_PTHREAD struct write_buffer *data = get_write_buffer(writer); if (data->uncommitted_length < sizeof(data->uncommitted)) { data->uncommitted[data->uncommitted_length] = c; data->uncommitted_length++; } #else writer->write(&c, 1, writer->write_data); #endif }
PandaWriter panda_writer_ref( PandaWriter writer) { if (writer == NULL) return NULL; #ifdef HAVE_PTHREAD flush_buffer(writer, get_write_buffer(writer)); pthread_mutex_lock(&writer->mutex); #endif writer->refcnt++; #ifdef HAVE_PTHREAD pthread_mutex_unlock(&writer->mutex); #endif return writer; }
void panda_writer_append_v( PandaWriter writer, const char *format, va_list va) { #ifdef HAVE_PTHREAD struct write_buffer *data = get_write_buffer(writer); data->uncommitted_length += vsnprintf(data->uncommitted + data->uncommitted_length, sizeof(data->uncommitted) - data->uncommitted_length, format, va); #else char buffer[2048]; size_t buffer_length; buffer_length = vsnprintf(buffer, sizeof(buffer), format, va); writer->write(buffer, buffer_length, writer->write_data); #endif }
/* * write_tar_eof * * This function is initially written for NDMP support. It appends * two tar headers to the tar file, and also N more empty buffers * to make sure that the two tar headers will be read as a part of * a mover record and don't get locked because of EOM on the mover * side. */ void write_tar_eof(tlm_cmd_t *local_commands) { int i; long actual_size; tlm_buffers_t *bufs; /* * output 2 zero filled records, * TAR wants this. */ (void) get_write_buffer(sizeof (tlm_tar_hdr_t), &actual_size, TRUE, local_commands); (void) get_write_buffer(sizeof (tlm_tar_hdr_t), &actual_size, TRUE, local_commands); /* * NDMP: Clear the rest of the buffer and write two more buffers * to the tape. */ bufs = local_commands->tc_buffers; (void) get_write_buffer(bufs->tbs_data_transfer_size, &actual_size, TRUE, local_commands); for (i = 0; i < NDMP_MORE_RECORDS && local_commands->tc_reader == TLM_BACKUP_RUN; i++) { /* * We don't need the return value of get_write_buffer(), * since it's already zeroed out if the buffer is returned. */ (void) get_write_buffer(bufs->tbs_data_transfer_size, &actual_size, TRUE, local_commands); } bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE; tlm_buffer_release_in_buf(bufs); }
void update() { int todo = get_todo(); int16_t* buffer = get_write_buffer(); int samples = rb.data_left(); const int to_write = MIN(todo, samples); for (int i=0; i<to_write; i++) { uint16_t sample = uint16_t(rb.read() * 32767); buffer[i] = sample; }; write(to_write/channels); total_wrote += to_write; };
/* * output_mem * * Gets a IO write buffer and copies memory to the that. */ static void output_mem(tlm_cmd_t *local_commands, char *mem, int len) { long actual_size, rec_size; char *rec; while (len > 0) { rec = get_write_buffer(len, &actual_size, FALSE, local_commands); rec_size = min(actual_size, len); (void) memcpy(rec, mem, rec_size); mem += rec_size; len -= rec_size; } }
void test_fill_drain() { int i; int* pointer; buffer_init(1); for (i = 0; i < 1023; ++i) { pointer = (int*)get_write_buffer(); *pointer = i; g_assert(buffer_push(sizeof(int))); } for (i = 0; i < 1023; ++i) { pointer = (int*)get_read_buffer(0); g_assert_cmpint(*pointer, ==, i); g_assert(buffer_pop(sizeof(int), 0)); } buffer_free(); }
void update() { _THREAD_SAFE_METHOD_; int todo = get_todo(); int16_t* buffer = get_write_buffer(); int frames = rb.data_left()/channels; const int to_write = MIN(todo, frames); for (int i=0; i<to_write*channels; i++) { int v = rb.read() * 32767; int16_t sample = CLAMP(v,-32768,32767); buffer[i] = sample; }; write(to_write); total_wrote += to_write; };
void test_read_write_one_at_a_time() { int i; int* pointer; buffer_init(1); for (i = 0; i < 9000; ++i) { g_assert_cmpint(get_available_to_write(), >=, sizeof(int)); pointer = (int*)get_write_buffer(); *pointer = i; g_assert(buffer_push(sizeof(int))); g_assert_cmpint(get_available_to_read(0), >=, sizeof(int)); pointer = (int*)get_read_buffer(0); g_assert_cmpint(*pointer, ==, i); g_assert(buffer_pop(sizeof(int), 0)); } buffer_free(); }
void panda_writer_commit( PandaWriter writer) { #ifdef HAVE_PTHREAD struct write_buffer *data = get_write_buffer(writer); if (sizeof(data->committed) - data->committed_length < data->uncommitted_length) { flush_buffer(writer, data); } else { memcpy(data->committed + data->committed_length, data->uncommitted, data->uncommitted_length); data->committed_length += data->uncommitted_length; data->uncommitted_length = 0; } if (writer->commit_slave != NULL) { panda_writer_commit(writer->commit_slave); } #else (void) writer; #endif }
void AudioStreamMPC::update() { if (!active || paused) return; int todo=get_todo(); while(todo>MPC_DECODER_BUFFER_LENGTH/si.channels) { mpc_frame_info frame; frame.buffer=sample_buffer; mpc_status err = mpc_demux_decode(demux, &frame); if (frame.bits!=-1) { int16_t *dst_buff = get_write_buffer(); #ifdef MPC_FIXED_POINT for( int i = 0; i < frame.samples * si.channels; i++) { int tmp = sample_buffer[i] >> MPC_FIXED_POINT_FRACTPART; if (tmp > ((1 << 15) - 1)) tmp = ((1 << 15) - 1); if (tmp < -(1 << 15)) tmp = -(1 << 15); dst_buff[i] = tmp; } #else for( int i = 0; i < frame.samples * si.channels; i++) { int tmp = Math::fast_ftoi(sample_buffer[i]*32767.0); if (tmp > ((1 << 15) - 1)) tmp = ((1 << 15) - 1); if (tmp < -(1 << 15)) tmp = -(1 << 15); dst_buff[i] = tmp; } #endif int frames = frame.samples; write(frames); todo-=frames; } else { if (err != MPC_STATUS_OK) {
/* Reporting of error via struct errorlog */ struct errorlog *opal_elog_create(struct opal_err_info *e_info) { struct errorlog *buf; buf = get_write_buffer(e_info->sev); if (buf) { buf->error_event_type = e_info->err_type; buf->component_id = e_info->cmp_id; buf->subsystem_id = e_info->subsystem; buf->event_severity = e_info->sev; buf->event_subtype = e_info->event_subtype; buf->reason_code = e_info->reason_code; buf->elog_origin = ORG_SAPPHIRE; lock(&elog_lock); buf->plid = ++sapphire_elog_id; unlock(&elog_lock); } return buf; }
static void *thread_client(void *pdata) { buffer_cblk_t *pcblk = (buffer_cblk_t *)pdata; uint32_t frames_avail; uint32_t frames_req; void *ptr1; uint32_t size1; void *ptr2; uint32_t size2; while (g_client_runnig) { pthread_mutex_lock(&pcblk->lock); frames_avail = frames_write_available(pcblk); if (frames_avail == 0) { printf("[c]wait server\n"); pthread_cond_wait(&pcblk->cond, &pcblk->lock); if (g_client_runnig == 0) { break; } frames_avail = frames_write_available(pcblk); } pthread_mutex_unlock(&pcblk->lock); frames_req = BUF_FRAME_REQ; if (frames_req > frames_avail) { frames_req = frames_avail; } frames_req = get_write_buffer(pcblk, frames_req, &ptr1, &size1, &ptr2, &size2); if (frames_req > 0) { printf("[c]frames_req = 0x%x\n", frames_req); printf("[c]buf1 = 0x%x, size1 = 0x%x, buf2 = 0x%x, size2 = 0x%x\n", (unsigned int)ptr1, size1, (unsigned int)ptr2, size2); advance_write_index(pcblk, frames_req); } usleep(DELAY_C*1000); } return NULL; }
/* * output_acl_header * * output the ACL header record and data */ static int output_acl_header(sec_attr_t *acl_info, tlm_cmd_t *local_commands) { long actual_size; tlm_tar_hdr_t *tar_hdr; long acl_size; if ((acl_info == NULL) || (*acl_info->attr_info == '\0')) return (0); tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, &actual_size, TRUE, local_commands); if (!tar_hdr) return (0); tar_hdr->th_linkflag = LF_ACL; acl_info->attr_type = UFSD_ACL; (void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len), "%06o", strlen(acl_info->attr_info)); acl_size = sizeof (*acl_info); (void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE); (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", acl_size); (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", 0444); (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0); (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0); (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ", 0); (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, sizeof (tar_hdr->th_magic)); tlm_build_header_checksum(tar_hdr); (void) output_mem(local_commands, (void *)acl_info, acl_size); return (0); }
/* * output_humongus_header * * output a special header record for HUGE files * output is: 1) a TAR "HUGE" header redord * 2) a "file" of size, name */ static int output_humongus_header(char *fullname, longlong_t file_size, tlm_cmd_t *local_commands) { char *buf; int len; long actual_size; tlm_tar_hdr_t *tar_hdr; /* * buf will contain: "%llu %s": * - 20 is the maximum length of 'ulong_tlong' decimal notation. * - The first '1' is for the ' ' between the "%llu" and the fullname. * - The last '1' is for the null-terminator of fullname. */ len = 20 + 1 + strlen(fullname) + 1; if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL) return (-1); tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, &actual_size, TRUE, local_commands); if (!tar_hdr) { free(buf); return (0); } tar_hdr->th_linkflag = LF_HUMONGUS; (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", len); tlm_build_header_checksum(tar_hdr); (void) snprintf(buf, len, "%lld %s", file_size, fullname); (void) output_mem(local_commands, buf, len); free(buf); return (0); }
/* * Notifies ndmpd that the metadata associated with the given ZFS dataset * should be backed up. */ int ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset) { tlm_commands_t *cmds; ndmp_metadata_handle_t mhd; ndmp_metadata_header_ext_t *mhp; ndmp_metadata_property_ext_t *mpp; zfs_handle_t *zhp; tlm_cmd_t *lcmd; long actual_size; nvlist_t *uprops, *ulist; const char *pname; nvpair_t *elp; char *sval, *ssrc; char *wbuf, *pp, *tp; long size, lsize, sz; int align = RECORDSIZE - 1; int pcount; if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL) return (-1); if ((lcmd = cmds->tcs_command) == NULL || lcmd->tc_buffers == NULL) return (-1); (void) mutex_lock(&zlib_mtx); if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) { (void) mutex_unlock(&zlib_mtx); return (-1); } pcount = zfs_get_prop_counts(zhp); size = sizeof (ndmp_metadata_header_ext_t) + pcount * sizeof (ndmp_metadata_property_ext_t); size += align; size &= ~align; if ((mhp = malloc(size)) == NULL) { zfs_close(zhp); (void) mutex_unlock(&zlib_mtx); return (-1); } (void) memset(mhp, 0, size); mhd.ml_handle = zhp; mhd.ml_xhdr = mhp; mhp->nh_total_bytes = size; mhp->nh_major = META_HDR_MAJOR_VERSION; mhp->nh_minor = META_HDR_MINOR_VERSION; mhp->nh_plversion = nctx->nc_plversion; (void) strlcpy(mhp->nh_plname, nctx->nc_plname, sizeof (mhp->nh_plname)); (void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT, sizeof (mhp->nh_magic)); (void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset)); /* Get all the ZFS properties */ (void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE, ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET); /* Get user properties */ uprops = zfs_get_user_props(mhd.ml_handle); elp = nvlist_next_nvpair(uprops, NULL); while (elp != NULL) { mpp = &mhp->nh_property[mhp->nh_count]; if (nvpair_value_nvlist(elp, &ulist) != 0 || nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 || nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) { zfs_close(mhd.ml_handle); (void) mutex_unlock(&zlib_mtx); free(mhp); return (-1); } if ((pname = nvpair_name(elp)) != NULL) (void) strlcpy(mpp->mp_name, pname, ZFS_MAXNAMELEN); (void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN); (void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN); mhp->nh_count++; elp = nvlist_next_nvpair(uprops, elp); } mhd.ml_quota_prop = ZFS_PROP_USERQUOTA; (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA, zfs_put_quota_cb, &mhd); mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA; (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA, zfs_put_quota_cb, &mhd); mhp->nh_count = pcount; zfs_close(mhd.ml_handle); (void) mutex_unlock(&zlib_mtx); if ((wbuf = get_write_buffer(size, &actual_size, TRUE, lcmd)) != NULL) { pp = (char *)mhp; (void) memcpy(wbuf, pp, (actual_size < size) ? actual_size : size); pp += (actual_size < size) ? actual_size : size; sz = actual_size; while (sz < size && ((tp = get_write_buffer(size - sz, &lsize, TRUE, lcmd))) != NULL) { (void) memcpy(tp, pp, lsize); sz += lsize; pp += lsize; } if (sz > size) { tlm_unget_write_buffer(lcmd->tc_buffers, sz - size); } } free(mhp); return (0); }
/* * output_xattr_header * * output the TAR header record for extended attributes */ static int output_xattr_header(char *fname, char *aname, int fd, tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands) { struct stat64 *attr = &tlm_acls->acl_attr; struct xattr_hdr *xhdr; struct xattr_buf *xbuf; tlm_tar_hdr_t *tar_hdr; long actual_size; char *section_name = ndmp_malloc(TLM_MAX_PATH_NAME); int hsize; int comlen; int namesz; if (section_name == NULL) return (-TLM_NO_SCRATCH_SPACE); if (fstat64(fd, attr) == -1) { syslog(LOG_ERR, "output_file_header stat failed."); free(section_name); return (-TLM_OPEN_ERR); } /* * if the file has to go out in sections, * we must mung the name. */ if (section == 0) { (void) snprintf(section_name, TLM_MAX_PATH_NAME, "/dev/null/%s.hdr", aname); } else { (void) snprintf(section_name, TLM_MAX_PATH_NAME, "%s.%03d", aname, section); } namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */ hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf); comlen = namesz + sizeof (struct xattr_buf); tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, &actual_size, TRUE, local_commands); if (!tar_hdr) { free(section_name); return (0); } (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE); tar_hdr->th_linkflag = LF_XATTR; (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", hsize); (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", attr->st_mode & 07777); (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", attr->st_uid); (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", attr->st_gid); (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ", attr->st_mtime); (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, sizeof (tar_hdr->th_magic)); tlm_build_header_checksum(tar_hdr); xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE, &actual_size, TRUE, local_commands); if (!xhdr) { free(section_name); return (0); } (void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s", XATTR_ARCH_VERS); (void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d", sizeof (xhdr->h_size) - 1, hsize); (void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len), "%0*d", sizeof (xhdr->h_component_len) - 1, comlen); (void) snprintf(xhdr->h_link_component_len, sizeof (xhdr->h_link_component_len), "%0*d", sizeof (xhdr->h_link_component_len) - 1, 0); xbuf = (struct xattr_buf *)(((caddr_t)xhdr) + sizeof (struct xattr_hdr)); (void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d", sizeof (xbuf->h_namesz) - 1, namesz); /* No support for links in extended attributes */ xbuf->h_typeflag = LF_NORMAL; (void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE); (void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname, TLM_NAME_SIZE); free(section_name); return (0); }
void VideoStreamTheora::update() { if (!playing) { //printf("not playing\n"); return; }; double ctime =AudioServer::get_singleton()->get_mix_time(); if (last_update_time) { double delta = (ctime-last_update_time); time+=delta; //print_line("delta: "+rtos(delta)); } last_update_time=ctime; int audio_todo = get_todo(); ogg_packet op; int audio_pending = 0; while (vorbis_p && audio_todo) { int ret; float **pcm; /* if there's pending, decoded audio, grab it */ if ((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0) { audio_pending = ret; int16_t* out = get_write_buffer(); int count = 0; int to_read = MIN(ret, audio_todo); for (int i=0; i<to_read; i++) { for(int j=0;j<vi.channels;j++){ int val=Math::fast_ftoi(pcm[j][i]*32767.f); if(val>32767)val=32767; if(val<-32768)val=-32768; out[count++] = val; }; }; int tr = vorbis_synthesis_read(&vd, to_read); audio_todo -= to_read; audio_frames_wrote += to_read; write(to_read); audio_pending -= to_read; if (audio_todo==0) buffering=false; } else { /* no pending audio; is there a pending packet to decode? */ if (ogg_stream_packetout(&vo,&op)>0){ if(vorbis_synthesis(&vb,&op)==0) { /* test for success! */ vorbis_synthesis_blockin(&vd,&vb); } } else { /* we need more data; break out to suck in another page */ //printf("need moar data\n"); break; }; } } while(theora_p && !videobuf_ready){ /* theora is one in, one out... */ if(ogg_stream_packetout(&to,&op)>0){ if(pp_inc){ pp_level+=pp_inc; th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level, sizeof(pp_level)); pp_inc=0; } /*HACK: This should be set after a seek or a gap, but we might not have a granulepos for the first packet (we only have them for the last packet on a page), so we just set it as often as we get it. To do this right, we should back-track from the last packet on the page and compute the correct granulepos for the first packet after a seek or a gap.*/ if(op.granulepos>=0){ th_decode_ctl(td,TH_DECCTL_SET_GRANPOS,&op.granulepos, sizeof(op.granulepos)); } ogg_int64_t videobuf_granulepos; if(th_decode_packetin(td,&op,&videobuf_granulepos)==0){ videobuf_time=th_granule_time(td,videobuf_granulepos); //printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready); /* is it already too old to be useful? This is only actually useful cosmetically after a SIGSTOP. Note that we have to decode the frame even if we don't show it (for now) due to keyframing. Soon enough libtheora will be able to deal with non-keyframe seeks. */ if(videobuf_time>=get_time()) videobuf_ready=1; else{ /*If we are too slow, reduce the pp level.*/ pp_inc=pp_level>0?-1:0; } } } else break; } if (/*!videobuf_ready && */ audio_pending == 0 && file->eof_reached()) { printf("video done, stopping\n"); stop(); return; }; if (!videobuf_ready || audio_todo > 0){ /* no data yet for somebody. Grab another page */ buffer_data(); while(ogg_sync_pageout(&oy,&og)>0){ queue_page(&og); } } /* If playback has begun, top audio buffer off immediately. */ //if(stateflag) audio_write_nonblocking(); /* are we at or past time for this video frame? */ if(videobuf_ready && videobuf_time<=get_time()){ video_write(); videobuf_ready=0; } else { //printf("frame at %f not ready (time %f), ready %i\n", (float)videobuf_time, get_time(), videobuf_ready); } float tdiff=videobuf_time-get_time(); /*If we have lots of extra time, increase the post-processing level.*/ if(tdiff>ti.fps_denominator*0.25/ti.fps_numerator){ pp_inc=pp_level<pp_level_max?1:0; } else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){ pp_inc=pp_level>0?-1:0; } };
/* * output_file_header * * output the TAR header record */ static int output_file_header(char *name, char *link, tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands) { static longlong_t file_count = 0; struct stat64 *attr = &tlm_acls->acl_attr; tlm_tar_hdr_t *tar_hdr; long actual_size; boolean_t long_name = FALSE; boolean_t long_link = FALSE; char *section_name = ndmp_malloc(TLM_MAX_PATH_NAME); int nmlen, lnklen; uid_t uid; gid_t gid; char *uname = ""; char *gname = ""; struct passwd *pwd; struct group *grp; if (section_name == NULL) return (-TLM_NO_SCRATCH_SPACE); /* * if the file has to go out in sections, * we must mung the name. */ if (section == 0) { (void) strlcpy(section_name, name, TLM_MAX_PATH_NAME); } else { (void) snprintf(section_name, TLM_MAX_PATH_NAME, "%s.%03d", name, section); } if ((pwd = getpwuid(attr->st_uid)) != NULL) uname = pwd->pw_name; if ((grp = getgrgid(attr->st_gid)) != NULL) gname = grp->gr_name; if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR) uid = UID_NOBODY; if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR) gid = GID_NOBODY; nmlen = strlen(section_name); if (nmlen >= NAMSIZ) { /* * file name is too big, it must go out * in its own data file */ tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, &actual_size, TRUE, local_commands); if (!tar_hdr) { free(section_name); return (0); } (void) snprintf(tar_hdr->th_name, sizeof (tar_hdr->th_name), "%s%08qd.fil", LONGNAME_PREFIX, file_count++); tar_hdr->th_linkflag = LF_LONGNAME; (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", nmlen); (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", attr->st_mode & 07777); (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", uid); (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", gid); (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s", uname); (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s", gname); (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ", attr->st_mtime); (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, sizeof (tar_hdr->th_magic)); tlm_build_header_checksum(tar_hdr); (void) output_mem(local_commands, (void *)section_name, nmlen); long_name = TRUE; } lnklen = strlen(link); if (lnklen >= NAMSIZ) { /* * link name is too big, it must go out * in its own data file */ tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, &actual_size, TRUE, local_commands); if (!tar_hdr) { free(section_name); return (0); } (void) snprintf(tar_hdr->th_linkname, sizeof (tar_hdr->th_name), "%s%08qd.slk", LONGNAME_PREFIX, file_count++); tar_hdr->th_linkflag = LF_LONGLINK; (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", lnklen); (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", attr->st_mode & 07777); (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", uid); (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", gid); (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s", uname); (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s", gname); (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ", attr->st_mtime); (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, sizeof (tar_hdr->th_magic)); tlm_build_header_checksum(tar_hdr); (void) output_mem(local_commands, (void *)link, lnklen); long_link = TRUE; } tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, &actual_size, TRUE, local_commands); if (!tar_hdr) { free(section_name); return (0); } if (long_name) { (void) snprintf(tar_hdr->th_name, sizeof (tar_hdr->th_name), "%s%08qd.fil", LONGNAME_PREFIX, file_count++); } else { (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE); } if (long_link) { (void) snprintf(tar_hdr->th_linkname, sizeof (tar_hdr->th_name), "%s%08qd.slk", LONGNAME_PREFIX, file_count++); } else { (void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE); } switch (attr->st_mode & S_IFMT) { case S_IFDIR: tar_hdr->th_linkflag = LF_DIR; break; case S_IFIFO: tar_hdr->th_linkflag = LF_FIFO; break; case S_IFBLK: case S_IFCHR: if (S_ISBLK(attr->st_mode)) tar_hdr->th_linkflag = LF_BLK; else tar_hdr->th_linkflag = LF_CHR; (void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor, sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ", major(attr->st_rdev)); (void) snprintf(tar_hdr->th_shared.th_dev.th_devminor, sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ", minor(attr->st_rdev)); break; default: if (attr->st_nlink > 1) { /* mark file with hardlink LF_LINK */ tar_hdr->th_linkflag = LF_LINK; (void) snprintf(tar_hdr->th_shared.th_hlink_ino, sizeof (tar_hdr->th_shared.th_hlink_ino), "%011llo ", attr->st_ino); } else { tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL : LF_SYMLINK; } } (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", (long)attr->st_size); (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", attr->st_mode & 07777); (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", uid); (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", gid); (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s", uname); (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s", gname); (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ", attr->st_mtime); (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, sizeof (tar_hdr->th_magic)); tlm_build_header_checksum(tar_hdr); if (long_name || long_link) { if (file_count > 99999990) { file_count = 0; } } free(section_name); 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); }