Extract tiger.[ch] and utils.[ch] as common code.
[doldaconnect.git] / config / 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     int c, fd, outfd;
64     int len, len2;
65     int filter, output;
66     struct tigertreehash tth;
67     char *dec, *enc;
68     char res[24];
69     char *statefile;
70     FILE *state;
71     int progress, bytes;
72     struct stat sb;
73     
74     filter = 0;
75     output = 4;
76     outfd = 3;
77     progress = 0;
78     statefile = NULL;
79     while((c = getopt(argc, argv, "phf456F:s:")) != -1) {
80         switch(c) {
81         case '4':
82         case '5':
83         case '6':
84             output = c - '0';
85             break;
86         case 'p':
87             progress = 1;
88             break;
89         case 'f':
90             filter = 1;
91             break;
92         case 'F':
93             outfd = atoi(optarg);
94             break;
95         case 's':
96             statefile = optarg;
97             break;
98         case 'h':
99         case ':':
100         case '?':
101         default:
102             fprintf(stderr, "usage: tigersum [-h456] FILE...\n");
103             fprintf(stderr, "       tigersum [-h456] [-F OUTFD] [-s STATEFILE] -f\n");
104             exit((c == 'h')?0:1);
105         }
106     }
107     if(filter) {
108         inittigertree(&tth);
109         if(statefile != NULL)
110         {
111             if(((state = fopen(statefile, "r")) == NULL) && (errno != ENOENT)) {
112                 fprintf(stderr, "tigersum: %s: %s\n", statefile, strerror(errno));
113                 exit(1);
114             }
115             if(state != NULL) {
116                 if(fgets(buf, sizeof(buf), state) == NULL) {
117                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
118                     exit(1);
119                 }
120                 tth.blocks = atoi(buf);
121                 if(fgets(buf, sizeof(buf), state) == NULL) {
122                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
123                     exit(1);
124                 }
125                 tth.depth = atoi(buf);
126                 for(i = 0; i < tth.depth; i++) {
127                     if(fgets(buf, sizeof(buf), state) == NULL) {
128                         fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
129                         exit(1);
130                     }
131                     dec = base64dec2(buf, &ret);
132                     if(ret != 24) {
133                         fprintf(stderr, "tigersum: %s: illegal state\n", statefile);
134                         exit(1);
135                     }
136                     memcpy(tth.stack[i], dec, 24);
137                 }
138                 if(fgets(buf, sizeof(buf), state) == NULL) {
139                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
140                     exit(1);
141                 }
142                 tth.offset = atoi(buf);
143                 if(fgets(buf, sizeof(buf), state) == NULL) {
144                     fprintf(stderr, "tigersum: %s: could not read entire state\n", statefile);
145                     exit(1);
146                 }
147                 dec = base64dec2(buf, &ret);
148                 if(ret != tth.offset) {
149                     fprintf(stderr, "tigersum: %s: illegal state\n", statefile);
150                     exit(1);
151                 }
152                 memcpy(&tth.block, dec, tth.offset);
153                 fclose(state);
154                 unlink(statefile);
155             }
156         }
157         while(1) {
158             ret = read(0, buf, sizeof(buf));
159             if(ret < 0) {
160                 perror("tigersum: read");
161                 exit(1);
162             }
163             if(ret == 0)
164                 break;
165             len = ret;
166             for(len2 = 0; len2 < len; len2 += ret) {
167                 if((ret = write(1, buf, ret)) < 0) {
168                     perror("tigersum: write");
169                     exit(1);
170                 }
171             }
172             dotigertree(&tth, buf, len);
173         }
174         if(statefile != NULL) {
175             if((state = fopen(statefile, "w")) == NULL) {
176                 fprintf(stderr, "tigersum: %s: %s\n", statefile, strerror(errno));
177                 exit(1);
178             }
179             fprintf(state, "%i\n", tth.blocks);
180             fprintf(state, "%i\n", tth.depth);
181             for(i = 0; i < tth.depth; i++) {
182                 enc = base64enc2(tth.stack[i], 24);
183                 fprintf(state, "%s\n", enc);
184             }
185             fprintf(state, "%i\n", tth.offset);
186             enc = base64enc2(tth.block, tth.offset);
187             fputs(enc, state);
188             fputc('\n', state);
189             fclose(state);
190         }
191         synctigertree(&tth);
192         restigertree(&tth, res);
193         if(output == 4)
194             enc = hexencode(res, 24);
195         else if(output == 5)
196             enc = base32encode(res, 24);
197         else if(output == 6)
198             enc = base64encode(res, 24);
199         for(len = 0; len < strlen(enc); len += ret) {
200             if((ret = write(outfd, enc + len, strlen(enc) - len)) < 0) {
201                 perror("tigersum: output");
202                 exit(1);
203             }
204         }
205         free(enc);
206         write(outfd, "\n", 1);
207     } else {
208         for(i = optind; i < argc; i++) {
209             if(!strcmp(argv[i], "-")) {
210                 fd = 0;
211             } else {
212                 if((fd = open(argv[i], O_RDONLY)) < 0) {
213                     fprintf(stderr, "tigersum: %s: %s\n", argv[i], strerror(errno));
214                     exit(1);
215                 }
216             }
217             if(progress) {
218                 fstat(fd, &sb);
219                 if(!S_ISREG(sb.st_mode))
220                     sb.st_size = -1;
221                 bytes = 0;
222             }
223             inittigertree(&tth);
224             while(1) {
225                 ret = read(fd, buf, sizeof(buf));
226                 if(ret < 0) {
227                     perror("tigersum: read");
228                     exit(1);
229                 }
230                 if(progress) {
231                     if((bytes == 0) || ((bytes & ~0xFFFFF) != ((bytes + ret) & ~0xFFFFF))) {
232                         bytes += ret;
233                         fprintf(stderr, "\033[1G");
234                         if(argc - optind > 1)
235                             fprintf(stderr, "%s: ", argv[i]);
236                         if(sb.st_size < 0) {
237                             fprintf(stderr, "%i", bytes);
238                         } else {
239                             fprintf(stderr, "%i%%", (int)(((float)bytes / (float)sb.st_size) * 100.0));
240                         }
241                         fprintf(stderr, "\033[K");
242                         fflush(stderr);
243                     } else {
244                         bytes += ret;
245                     }
246                 }
247                 if(ret == 0)
248                     break;
249                 dotigertree(&tth, buf, ret);
250             }
251             if(progress)
252                 fprintf(stderr, "\n");
253             synctigertree(&tth);
254             restigertree(&tth, res);
255             if(output == 4)
256                 enc = hexencode(res, 24);
257             else if(output == 5)
258                 enc = base32encode(res, 24);
259             else if(output == 6)
260                 enc = base64encode(res, 24);
261             if(argc - optind > 1)
262                 printf("%s %s\n", enc, argv[i]);
263             else
264                 printf("%s\n", enc);
265             free(enc);
266             fflush(stdout);
267             close(fd);
268         }
269     }
270     return(0);
271 }