chiark / gitweb /
02254dca7a2ed5ee4661d5c4f7dcc5b7bc3fa6f7
[chiark-utils.git] / backup / writebuffer.c
1 /*
2  * writebuffer.c
3  *
4  * Copyright (C) 1997,1998 Ian Jackson <ian@chiark.greenend.org.uk>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2,
9  * or (at your option) any later version.
10  *
11  * This is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this file; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <unistd.h>
28
29 #define BUFFER 16*1024*1024
30 #define WAITFILL ((BUFFER*3)/4)
31
32 static inline int min(int a, int b) { return a<=b ? a : b; }
33
34 static void nonblock(int fd) {
35   int r;
36   r= fcntl(fd,F_GETFL,0); if (r == -1) { perror("fcntl getfl"); exit(1); }
37   r |= O_NDELAY;
38   if (fcntl(fd,F_SETFL,r) == -1) { perror("fcntl setfl"); exit(1); }
39 }
40
41 int main(int argc, const char *const *argv) {
42   static unsigned char buf[BUFFER];
43   
44   if (argv[1]) {
45     fputs("readbuffer: no arguments allowed\n", stderr);
46     exit(-1);
47   }
48
49   unsigned char *wp, *rp;
50   int used,r,writing,seeneof;
51   fd_set readfds;
52   fd_set writefds;
53
54   used=0; wp=rp=buf; writing=0; seeneof=0;
55   nonblock(0); nonblock(1);
56   while (!seeneof || used) {
57     FD_ZERO(&readfds); if (!seeneof && used+1<BUFFER) FD_SET(0,&readfds);
58     FD_ZERO(&writefds); if (writing) FD_SET(1,&writefds);
59 /*fprintf(stderr,"used %6d writing %d seeneof %d wp %8lx rp %8lx read %d write %d\n",
60         used,writing,seeneof,(unsigned long)(wp-buf),(unsigned long)(rp-buf),
61         FD_ISSET(0,&readfds),FD_ISSET(1,&writefds));*/
62     r= select(2,&readfds,&writefds,0,0);
63 /*fprintf(stderr,"\t readable %d writeable %d\n",
64         FD_ISSET(0,&readfds),FD_ISSET(1,&writefds));*/
65     if (r == -1) {
66       if (errno == EINTR) continue;
67       perror("select"); exit(1);
68     }
69     if (FD_ISSET(1,&writefds) && !FD_ISSET(0,&readfds) && !used) {
70       writing= 0;
71       FD_CLR(1,&writefds);
72 /*fprintf(stderr,"\t buffers empty - stopping\n");*/
73     }
74     if (FD_ISSET(0,&readfds)) {
75       r= read(0,rp,min(BUFFER-1-used,buf+BUFFER-rp));
76       if (!r) {
77 /*fprintf(stderr,"\t eof detected\n");*/
78         seeneof=1; writing=1;
79       } else if (r<0) {
80         if (!(errno == EAGAIN || errno == EINTR)) { perror("read"); exit(1); }
81 fprintf(stderr,"\t read transient error\n");
82       } else {
83 /*fprintf(stderr,"\t read %d\n",r);*/
84         used+= r;
85         rp+= r;
86         if (rp == buf+BUFFER) rp=buf;
87 /*fprintf(stderr,"\t starting writes\n");*/
88       }
89       if (used > WAITFILL) writing=1;
90     }
91     if (FD_ISSET(1,&writefds) && used) {
92       r= write(1,wp,min(used,buf+BUFFER-wp));
93       if (r<=0) {
94         if (!(errno == EAGAIN || errno == EINTR)) { perror("write"); exit(1); }
95 /*fprintf(stderr,"\t write transient error\n");*/
96       } else {
97 /*fprintf(stderr,"\t wrote %d\n",r);*/
98         used-= r;
99         wp+= r;
100         if (wp == buf+BUFFER) wp=buf;
101       }
102     }
103   }
104   exit(0);
105 }