/* * The buf is already using BUF for an output buffer, and probably * contains some buffered output now. Write this out to F, and reset * the buffer cursor. */ rs_result rs_outfilebuf_drain(rs_job_t *job, rs_buffers_t *buf, void *opaque) { rs_filebuf_t *fb = (rs_filebuf_t *) opaque; FILE *fp = fb->fp; gzFile zp = fb->zp; int fd = fb->fd; size_t wlen; //logp("in rs_outfilebuf_drain\n"); /* This is only allowed if either the buf has no output buffer * yet, or that buffer could possibly be BUF. */ if(!buf->next_out) { assert(buf->avail_out == 0); buf->next_out = fb->buf; buf->avail_out = fb->buf_len; return RS_DONE; } assert(buf->avail_out <= fb->buf_len); assert(buf->next_out >= fb->buf); assert(buf->next_out <= fb->buf + fb->buf_len); if((wlen=buf->next_out-fb->buf)>0) { //logp("wlen: %d\n", wlen); if(fd>0) { size_t w=wlen; if(async_append_all_to_write_buffer(CMD_APPEND, fb->buf, &wlen)) { // stop the rsync stuff from reading more. // buf->next_out = fb->buf; // buf->avail_out = 0; // logp("out return BLOCKED\n"); return RS_BLOCKED; } fb->bytes+=w; } else { size_t result=0; if(fp) result=fwrite(fb->buf, 1, wlen, fp); else if(zp) result=gzwrite(zp, fb->buf, wlen); if(wlen!=result) { logp("error draining buf to file: %s", strerror(errno)); return RS_IO_ERROR; } } } buf->next_out = fb->buf; buf->avail_out = fb->buf_len; return RS_DONE; }
int async_rw(char *rcmd, char **rdst, size_t *rlen, char wcmd, const char *wsrc, size_t *wlen) { int mfd=-1; fd_set fsr; fd_set fsw; fd_set fse; int doread=0; int dowrite=0; struct timeval tval; static int read_blocked_on_write=0; static int write_blocked_on_read=0; //printf("in async_rw\n"); if(doing_estimate) return 0; if(fd<0) { logp("fd not ready in async rw: %d\n", fd); return -1; } if(rdst) doread++; // Given a pointer to allocate and read into. if(*wlen) { // More stuff to append to the write buffer. async_append_all_to_write_buffer(wcmd, wsrc, wlen); } if(writebuflen && !write_blocked_on_read) dowrite++; // The write buffer is not yet empty. if(doread) { if(parse_readbuf(rcmd, rdst, rlen)) { logp("error in parse_readbuf\n"); return -1; } if(*rcmd && *rdst) return 0; if(read_blocked_on_write) doread=0; } if(doread || dowrite) { //printf("async_rw loop read %d write %d wbuflen: %d\n", doread, dowrite, writebuflen); mfd=-1; if(doread) FD_ZERO(&fsr); if(dowrite) FD_ZERO(&fsw); FD_ZERO(&fse); add_fd_to_sets(fd, doread?&fsr:NULL, dowrite?&fsw:NULL, &fse, &mfd); tval.tv_sec=setsec; tval.tv_usec=setusec; if(select(mfd+1, doread?&fsr:NULL, dowrite?&fsw:NULL, &fse, &tval)<0) { if(errno!=EAGAIN && errno!=EINTR) { logp("select error: %s\n", strerror(errno)); return -1; } } if(!FD_ISSET(fd, &fse) && (!doread || !FD_ISSET(fd, &fsr)) && (!dowrite || !FD_ISSET(fd, &fsw))) { //logp("SELECT HIT TIMEOUT - doread: %d, dowrite: %d\n", // doread, dowrite); // Be careful to avoid 'read quick' mode. if((setsec || setusec) && max_network_timeout>0 && network_timeout--<=0) { logp("No activity on network for %d seconds.\n", max_network_timeout); return -1; } return 0; } network_timeout=max_network_timeout; if(FD_ISSET(fd, &fse)) { logp("error on socket\n"); return -1; } if(doread && FD_ISSET(fd, &fsr)) // able to read { int r; read_blocked_on_write=0; if(do_read(&read_blocked_on_write)) return -1; if((r=parse_readbuf(rcmd, rdst, rlen))) logp("error in second parse_readbuf\n"); return r; } if(dowrite && FD_ISSET(fd, &fsw)) // able to write { int r=0; write_blocked_on_read=0; if((r=do_write(&write_blocked_on_read))) logp("error in do_write\n"); return r; } } return 0; }
// Return 1 if there is still stuff needing to be sent. static int do_stuff_to_send(struct sbuf *p1b, char **last_requested) { //size_t junk=0; if(p1b->senddatapth) { size_t l=strlen(p1b->datapth); if(async_append_all_to_write_buffer(CMD_DATAPTH, p1b->datapth, &l)) return 1; p1b->senddatapth=0; //if(async_rw(NULL, NULL, NULL, NULL, NULL, &junk)) return -1; } if(p1b->sendstat) { size_t l=p1b->slen; if(async_append_all_to_write_buffer(CMD_STAT, p1b->statbuf, &l)) return 1; p1b->sendstat=0; //if(async_rw(NULL, NULL, NULL, NULL, NULL, &junk)) return -1; } if(p1b->sendpath) { size_t l=p1b->plen; if(async_append_all_to_write_buffer(p1b->cmd, p1b->path, &l)) return 1; p1b->sendpath=0; if(*last_requested) free(*last_requested); *last_requested=strdup(p1b->path); //if(async_rw(NULL, NULL, NULL, NULL, NULL, &junk)) return -1; } if(p1b->sigjob && !p1b->sendendofsig) { rs_result sigresult; sigresult=rs_async(p1b->sigjob, &(p1b->rsbuf), p1b->infb, p1b->outfb); //logp("after rs_async: %d %c %s\n", sigresult, p1b->cmd, p1b->path); if(sigresult==RS_DONE) { p1b->sendendofsig++; //if(async_rw(NULL, NULL, NULL, NULL, NULL, &junk)) // return -1; } else if(sigresult==RS_BLOCKED || sigresult==RS_RUNNING) { // keep going round the loop. //if(async_rw(NULL, NULL, NULL, NULL, NULL, &junk)) // return -1; return 1; } else { logp("error in rs_async: %d\n", sigresult); return -1; } } if(p1b->sendendofsig) { size_t l; const char *endfile="endfile"; l=strlen(endfile); if(async_append_all_to_write_buffer(CMD_END_FILE, endfile, &l)) return 1; //if(async_rw(NULL, NULL, NULL, NULL, NULL, &junk)) return -1; p1b->sendendofsig=0; } return 0; }