Merge branch 'master' of pc18:/srv/git/r/doldaconnect
[doldaconnect.git] / config / cmd / tthsum.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
4  *  
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *  
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *  
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 /* This frankenfile is built from bits and pieces of the daemon. The
21  * copying and pasting is very ugly, but it doesn't *really*
22  * matter. */
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <sys/stat.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 #include <tiger.h>
36 #include <utils.h>
37
38 char buf[32768];
39
40 static char *base64enc2(char *data, size_t datalen)
41 {
42     static char *res = NULL;
43     
44     if(res != NULL)
45         free(res);
46     res = base64encode(data, datalen);
47     return(res);
48 }
49
50 static char *base64dec2(char *data, size_t *datalen)
51 {
52     static char *res = NULL;
53     
54     if(res != NULL)
55         free(res);
56     res = base64decode(data, datalen);
57     return(res);
58 }
59
60 int main(int argc, char **argv)
61 {
62     int i, ret;
63     size_t size;
64     int c, fd, outfd;
65     int len, len2;
66     int filter, output;
67     struct tigertreehash tth;
68     char *dec, *enc;
69     char res[24];
70     char *statefile;
71     FILE *state;
72     int progress, bytes;
73     struct stat sb;
74     
75     filter = 0;
76     output = 4;
77     outfd = 3;
78     progress = 0;
79     statefile = NULL;
80     while((c = getopt(argc, argv, "phf456F:s:")) != -1) {
81         switch(c) {
82         case '4':
83         case '5':
84         case '6':
85             output = c - '0';
86             break;
87         case 'p':
88             progress = 1;
89             break;
90         case 'f':
91             filter = 1;
92             break;
93         case 'F':
94             outfd = atoi(optarg);
95             break;
96         case 's':
97             statefile = optarg;
98             break;
99         case 'h':
100         case ':':
101         case '?':
102         default:
103             fprintf(stderr, "usage: tigersum [-h456] FILE...\n");
104             fprintf(stderr, "       tigersum [-h456] [-F OUTFD] [-s STATEFILE] -f\n");
105             exit((c == 'h')?0:1);
106         }
107     }
108     if(filter) {
109         inittigertree(&tth);
110         if(statefile != NULL)
111         {
112             if(((state = fopen(statefile, "r")) == NULL) && (errno != ENOENT)) {
113                 fprintf(stderr, "tigersum: %s: %s\n", statefile, strerror(errno));
114                 exit(1);
115             }
116             if(state != NULL) {
117                 if(fgets(buf, sizeof(buf), state) == NULL) {
118                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
119                     exit(1);
120                 }
121                 tth.blocks = atoi(buf);
122                 if(fgets(buf, sizeof(buf), state) == NULL) {
123                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
124                     exit(1);
125                 }
126                 tth.depth = atoi(buf);
127                 for(i = 0; i < tth.depth; i++) {
128                     if(fgets(buf, sizeof(buf), state) == NULL) {
129                         fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
130                         exit(1);
131                     }
132                     dec = base64dec2(buf, &size);
133                     if(size != 24) {
134                         fprintf(stderr, "tigersum: %s: illegal state\n", statefile);
135                         exit(1);
136                     }
137                     memcpy(tth.stack[i], dec, 24);
138                 }
139                 if(fgets(buf, sizeof(buf), state) == NULL) {
140                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
141                     exit(1);
142                 }
143                 tth.offset = atoi(buf);
144                 if(fgets(buf, sizeof(buf), state) == NULL) {
145                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
146                     exit(1);
147                 }
148                 dec = base64dec2(buf, &size);
149                 if(size != tth.offset) {
150                     fprintf(stderr, "tigersum: %s: illegal state\n", statefile);
151                     exit(1);
152                 }
153                 memcpy(&tth.block, dec, tth.offset);
154                 fclose(state);
155                 unlink(statefile);
156             }
157         }
158         while(1) {
159             ret = read(0, buf, sizeof(buf));
160             if(ret < 0) {
161                 perror("tigersum: read");
162                 exit(1);
163             }
164             if(ret == 0)
165                 break;
166             len = ret;
167             for(len2 = 0; len2 < len; len2 += ret) {
168                 if((ret = write(1, buf, ret)) < 0) {
169                     perror("tigersum: write");
170                     exit(1);
171                 }
172             }
173             dotigertree(&tth, buf, len);
174         }
175         if(statefile != NULL) {
176             if((state = fopen(statefile, "w")) == NULL) {
177                 fprintf(stderr, "tigersum: %s: %s\n", statefile, strerror(errno));
178                 exit(1);
179             }
180             fprintf(state, "%i\n", tth.blocks);
181             fprintf(state, "%i\n", tth.depth);
182             for(i = 0; i < tth.depth; i++) {
183                 enc = base64enc2(tth.stack[i], 24);
184                 fprintf(state, "%s\n", enc);
185             }
186             fprintf(state, "%i\n", tth.offset);
187             enc = base64enc2(tth.block, tth.offset);
188             fputs(enc, state);
189             fputc('\n', state);
190             fclose(state);
191         }
192         synctigertree(&tth);
193         restigertree(&tth, res);
194         if(output == 4)
195             enc = hexencode(res, 24);
196         else if(output == 5)
197             enc = base32encode(res, 24);
198         else if(output == 6)
199             enc = base64encode(res, 24);
200         for(len = 0; len < strlen(enc); len += ret) {
201             if((ret = write(outfd, enc + len, strlen(enc) - len)) < 0) {
202                 perror("tigersum: output");
203                 exit(1);
204             }
205         }
206         free(enc);
207         write(outfd, "\n", 1);
208     } else {
209         for(i = optind; i < argc; i++) {
210             if(!strcmp(argv[i], "-")) {
211                 fd = 0;
212             } else {
213                 if((fd = open(argv[i], O_RDONLY)) < 0) {
214                     fprintf(stderr, "tigersum: %s: %s\n", argv[i], strerror(errno));
215                     exit(1);
216                 }
217             }
218             if(progress) {
219                 fstat(fd, &sb);
220                 if(!S_ISREG(sb.st_mode))
221                     sb.st_size = -1;
222                 bytes = 0;
223             }
224             inittigertree(&tth);
225             while(1) {
226                 ret = read(fd, buf, sizeof(buf));
227                 if(ret < 0) {
228                     perror("tigersum: read");
229                     exit(1);
230                 }
231                 if(progress) {
232                     if((bytes == 0) || ((bytes & ~0xFFFFF) != ((bytes + ret) & ~0xFFFFF))) {
233                         bytes += ret;
234                         fprintf(stderr, "\033[1G");
235                         if(argc - optind > 1)
236                             fprintf(stderr, "%s: ", argv[i]);
237                         if(sb.st_size < 0) {
238                             fprintf(stderr, "%i", bytes);
239                         } else {
240                             fprintf(stderr, "%i%%", (int)(((float)bytes / (float)sb.st_size) * 100.0));
241                         }
242                         fprintf(stderr, "\033[K");
243                         fflush(stderr);
244                     } else {
245                         bytes += ret;
246                     }
247                 }
248                 if(ret == 0)
249                     break;
250                 dotigertree(&tth, buf, ret);
251             }
252             if(progress)
253                 fprintf(stderr, "\n");
254             synctigertree(&tth);
255             restigertree(&tth, res);
256             if(output == 4)
257                 enc = hexencode(res, 24);
258             else if(output == 5)
259                 enc = base32encode(res, 24);
260             else if(output == 6)
261                 enc = base64encode(res, 24);
262             if(argc - optind > 1)
263                 printf("%s %s\n", enc, argv[i]);
264             else
265                 printf("%s\n", enc);
266             free(enc);
267             fflush(stdout);
268             close(fd);
269         }
270     }
271     return(0);
272 }