progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / progs / cc-enc.c
CommitLineData
5c3f75ec 1/* -*-c-*-
2 *
5c3f75ec 3 * Catcrypt data encoding
4 *
5 * (c) 2004 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
5c3f75ec 9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
45c0fd36 16 *
5c3f75ec 17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
45c0fd36 21 *
5c3f75ec 22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28/*----- Header files ------------------------------------------------------*/
29
cd6eca43
MW
30#define _FILE_OFFSET_BITS 64
31
fa54fe1e 32#include <errno.h>
5c3f75ec 33#include <stdio.h>
34
35#include <mLib/alloc.h>
36#include <mLib/base64.h>
37#include <mLib/dstr.h>
141c1284 38#include <mLib/macros.h>
fa54fe1e 39#include <mLib/mdwopt.h>
5c3f75ec 40#include <mLib/report.h>
41#include <mLib/sub.h>
42
43#include "cc.h"
44
fa54fe1e 45typedef int encbdryp(const char *, void *);
46
5c3f75ec 47/*----- Main code ---------------------------------------------------------*/
48
49/* --- Binary --- */
50
fa54fe1e 51static enc *bin_encinit(FILE *fp, const char *msg)
52 { enc *e = CREATE(enc); return (e); }
53static enc *bin_decinit(FILE *fp, encbdryp *func, void *p)
5c3f75ec 54 { enc *e = CREATE(enc); return (e); }
55
56static int bin_read(enc *e, void *p, size_t sz)
57{
58 size_t n;
45c0fd36 59
5c3f75ec 60 if (!sz) return (0);
61 n = fread(p, 1, sz, e->fp);
62 if (!n || ferror(e->fp)) return (-1);
63 return (n);
64}
65
66static int bin_write(enc *e, const void *p, size_t sz)
67 { if (sz && fwrite(p, 1, sz, e->fp) < sz) return (-1); return (0); }
68
69static int bin_done(enc *e) { return (0); }
70
71static void bin_destroy(enc *e) { DESTROY(e); }
72
73/* --- PEM --- */
74
75typedef struct pem_encctx {
76 enc e;
77 char *msg;
78 unsigned f;
79 base64_ctx b;
80 dstr d;
81 size_t n;
82#define PEMF_NL 1u
83#define PEMF_EOF 2u
84} pem_encctx;
85
86static enc *pem_encinit(FILE *fp, const char *msg)
87{
88 pem_encctx *pe = CREATE(pem_encctx);
89 base64_init(&pe->b);
90 fprintf(fp, "-----BEGIN %s-----\n", msg);
91 pe->msg = xstrdup(msg);
92 dstr_create(&pe->d);
93 pe->n = 0;
94 pe->f = 0;
95 return (&pe->e);
96}
97
141c1284 98int checkbdry(const char *b, void *p) { return (!p || STRCMP(b, ==, p)); }
fa54fe1e 99
100static enc *pem_decinit(FILE *fp, encbdryp *func, void *p)
5c3f75ec 101{
102 char buf[128];
103 int i, d;
104 pem_encctx *pe;
105 int ch;
106
107 /* --- Go until I find a newline and `-----' --- */
108
109top:
110 d = 0;
111 for (;;) {
112 if ((ch = getc(fp)) == EOF) goto fail;
113 switch (ch) {
114 case '\n': d = 0; break;
115 case '-': if (d >= 0) { d++; if (d == 5) goto banner; }; break;
116 default: d = -1; break;
117 }
118 }
119
120 /* --- See what the banner looks like --- */
121
122banner:
123 i = d = 0;
124 for (;;) {
125 if ((ch = getc(fp)) == EOF) goto fail;
126 if (ch == '-') { d++; continue; }
127 if (ch == '\n') break;
128 if (i + d + 1 >= sizeof(buf)) goto top;
129 while (d) { buf[i++] = '-'; d--; }
130 buf[i++] = ch;
131 }
132 buf[i] = 0;
133
134 /* --- Check we have the right framing --- */
135
136 if (d != 5) goto top;
141c1284 137 if (STRNCMP(buf, !=, "BEGIN ", 6) || (func && !func(buf + 6, p)))
5c3f75ec 138 goto top;
139
140 /* --- Ready --- */
141
142 pe = CREATE(pem_encctx);
143 base64_init(&pe->b);
144 pe->msg = xstrdup(buf + 6);
145 dstr_create(&pe->d);
146 pe->n = 0;
147 pe->f = PEMF_NL;
148 return (&pe->e);
149
150 /* --- Failed --- */
151
152fail:
153 die(EXIT_FAILURE, "initial encapsulation boundary not found");
154 return (0);
155}
156
157#define PEM_CHUNKSZ 4096
158
159static int pem_read(enc *e, void *p, size_t sz)
160{
161 pem_encctx *pe = (pem_encctx *)e;
162 char buf[PEM_CHUNKSZ];
163 char *pp = p;
164 int ch;
165 size_t n;
166 int rc = 0;
167
168 for (;;) {
169 n = pe->d.len - pe->n;
170 if (n > sz) n = sz;
171 memcpy(pp, pe->d.buf + pe->n, n);
172 pe->n += n;
173 pp += n;
174 rc += n;
175 sz -= n;
176 if (!sz) break;
177 if (pe->f & PEMF_EOF) return (rc ? rc : -1);
178 dstr_reset(&pe->d);
179 n = 0;
180 for (;;) {
181 if ((ch = getc(pe->e.fp)) == EOF) return (-1);
182 if ((pe->f & PEMF_NL) && ch == '-') {
183 ungetc(ch, pe->e.fp);
184 pe->f |= PEMF_EOF;
185 break;
186 }
187 if (ch == '\n') { pe->f |= PEMF_NL; continue; }
188 pe->f &= ~PEMF_NL;
189 buf[n++] = ch;
190 if (n >= PEM_CHUNKSZ) break;
191 }
192 if (n)
193 base64_decode(&pe->b, buf, n, &pe->d);
194 if (pe->f & PEMF_EOF)
195 base64_decode(&pe->b, 0, 0, &pe->d);
196 pe->n = 0;
197 }
198 return (rc);
199}
200
201static int pem_write(enc *e, const void *p, size_t sz)
202{
203 pem_encctx *pe = (pem_encctx *)e;
204 const char *pp = p;
205 size_t n;
206
207 while (sz) {
208 n = PEM_CHUNKSZ;
209 if (n > sz) n = sz;
210 dstr_reset(&pe->d);
211 base64_encode(&pe->b, pp, n, &pe->d);
212 if (fwrite(pe->d.buf, 1, pe->d.len, pe->e.fp) < pe->d.len)
213 return (-1);
214 pp += n;
215 sz -= n;
216 }
217 return (0);
218}
219
220static int pem_encdone(enc *e)
221{
222 pem_encctx *pe = (pem_encctx *)e;
223 dstr_reset(&pe->d);
224 base64_encode(&pe->b, 0, 0, &pe->d);
225 if (fwrite(pe->d.buf, 1, pe->d.len, pe->e.fp) < pe->d.len)
226 return (-1);
227 if (pe->b.lnlen) fputc('\n', pe->e.fp);
228 fprintf(pe->e.fp, "-----END %s-----\n", pe->msg);
229 return (0);
230}
231
232static int pem_decdone(enc *e)
233{
234 pem_encctx *pe = (pem_encctx *)e;
235 char buf[128];
236 int i, d;
237 int ch;
238
239 for (d = 0; d < 5; d++)
240 if ((ch = getc(pe->e.fp)) != '-') goto fail;
241 i = d = 0;
242 for (;;) {
243 if ((ch = getc(pe->e.fp)) == EOF) goto fail;
244 if (ch == '-') { d++; continue; }
245 if (ch == '\n') break;
246 if (i + d + 1 >= sizeof(buf)) goto fail;
247 while (d) { buf[i++] = '-'; d--; }
248 buf[i++] = ch;
249 }
250 if (d != 5) goto fail;
251 buf[i] = 0;
141c1284 252 if (STRNCMP(buf, !=, "END ", 4) || STRCMP(buf + 4, !=, pe->msg))
5c3f75ec 253 goto fail;
254 return (0);
255
256fail:
257 die(EXIT_FAILURE, "final encapsulation boundary not found");
258 return (-1);
259}
260
261static void pem_destroy(enc *e)
262{
263 pem_encctx *pe = (pem_encctx *)e;
264 dstr_destroy(&pe->d);
265 xfree(pe->msg);
266 DESTROY(pe);
267}
268
269/* --- Encoder table --- */
270
c65df279 271const encops enctab[] = {
cd6eca43 272 { "binary", "rb", "wb", 1, 1,
fa54fe1e 273 bin_encinit, bin_decinit,
5c3f75ec 274 bin_read, bin_write,
275 bin_done, bin_done,
276 bin_destroy },
cd6eca43 277 { "pem", "r", "w", 3, 4,
5c3f75ec 278 pem_encinit, pem_decinit,
279 pem_read, pem_write,
280 pem_encdone, pem_decdone,
281 pem_destroy },
282 { 0 }
45c0fd36 283};
5c3f75ec 284
285/* --- @getenc@ --- *
286 *
287 * Arguments: @const char *enc@ = name of wanted encoding
288 *
289 * Returns: Pointer to encoder operations.
290 *
291 * Use: Finds a named encoder or decoder.
292 */
293
294const encops *getenc(const char *enc)
295{
296 const encops *eo;
297
298 for (eo = enctab; eo->name; eo++) {
141c1284 299 if (STRCMP(eo->name, ==, enc))
5c3f75ec 300 goto e_found;
301 }
302 die(EXIT_FAILURE, "couldn't find encoding `%s'", enc);
303e_found:
304 return (eo);
305}
306
307/* --- @initenc@ --- *
308 *
309 * Arguments: @const encops *eo@ = operations (from @getenc@)
310 * @FILE *fp@ = file handle to attach
311 * @const char *msg@ = banner message
5c3f75ec 312 *
313 * Returns: The encoder object.
314 *
315 * Use: Initializes an encoder.
316 */
317
fa54fe1e 318enc *initenc(const encops *eo, FILE *fp, const char *msg)
5c3f75ec 319{
fa54fe1e 320 enc *e = eo->initenc(fp, msg);
5c3f75ec 321 e->ops = eo;
322 e->fp = fp;
45c0fd36 323 return (e);
5c3f75ec 324}
325
fa54fe1e 326/* --- @initdec@ --- *
327 *
328 * Arguments: @const encops *eo@ = operations (from @getenc@)
329 * @FILE *fp@ = file handle to attach
330 * @int (*func)(const char *, void *)@ = banner check function
331 * @void *p@ = argument for @func@
332 *
333 * Returns: The encoder object.
334 *
335 * Use: Initializes an encoder.
336 */
337
338enc *initdec(const encops *eo, FILE *fp,
339 int (*func)(const char *, void *), void *p)
340{
341 enc *e = eo->initdec(fp, func, p);
342 e->ops = eo;
343 e->fp = fp;
344 return (e);
345}
346
5c3f75ec 347/* --- @freeenc@ --- *
348 *
349 * Arguments: @enc *e@ = encoder object
350 *
351 * Returns: ---
352 *
353 * Use: Frees an encoder object.
354 */
355
356void freeenc(enc *e) { e->ops->destroy(e); }
357
fa54fe1e 358/*----- Encoding and decoding commands ------------------------------------*/
359
360int cmd_encode(int argc, char *argv[])
361{
cd6eca43 362 const char *fn, *of = 0;
fa54fe1e 363 FILE *ofp = 0;
364 FILE *fp = 0;
365 const char *ef = "binary";
366 const char *bd = "MESSAGE";
cd6eca43 367 fprogress ff;
fa54fe1e 368 int i;
369 size_t n;
370 char buf[4096];
371 unsigned f = 0;
372 const encops *eo;
373 enc *e;
374
375#define f_bogus 1u
cd6eca43 376#define f_progress 2u
fa54fe1e 377
378 for (;;) {
379 static const struct option opt[] = {
45c0fd36
MW
380 { "format", OPTF_ARGREQ, 0, 'f' },
381 { "boundary", OPTF_ARGREQ, 0, 'b' },
382 { "output", OPTF_ARGREQ, 0, 'o' },
cd6eca43 383 { "progress", 0, 0, 'p' },
fa54fe1e 384 { 0, 0, 0, 0 }
385 };
cd6eca43 386 i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0);
fa54fe1e 387 if (i < 0) break;
388 switch (i) {
389 case 'f': ef = optarg; break;
390 case 'b': bd = optarg; break;
391 case 'o': of = optarg; break;
cd6eca43 392 case 'p': f |= f_progress; break;
fa54fe1e 393 default: f |= f_bogus; break;
394 }
395 }
396 if (argc - optind > 1 || (f & f_bogus))
397 die(EXIT_FAILURE, "Usage: encode [-OPTIONS] [FILE]");
398
399 if ((eo = getenc(ef)) == 0)
400 die(EXIT_FAILURE, "encoding `%s' not found", ef);
401
cd6eca43 402 fn = optind < argc ? argv[optind++] : "-";
141c1284 403 if (STRCMP(fn, ==, "-"))
fa54fe1e 404 fp = stdin;
cd6eca43 405 else if ((fp = fopen(fn, "rb")) == 0) {
fa54fe1e 406 die(EXIT_FAILURE, "couldn't open file `%s': %s",
cd6eca43
MW
407 fn, strerror(errno));
408 }
fa54fe1e 409
141c1284 410 if (!of || STRCMP(of, ==, "-"))
fa54fe1e 411 ofp = stdout;
412 else if ((ofp = fopen(of, eo->wmode)) == 0) {
413 die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
9b1663a5 414 of, strerror(errno));
fa54fe1e 415 }
416
417 e = initenc(eo, ofp, bd);
418
cd6eca43
MW
419 if (f & f_progress) {
420 if (fprogress_init(&ff, fn, fp)) {
421 die(EXIT_FAILURE, "failed to initialize progress display: %s",
422 strerror(errno));
423 }
424 }
425
fa54fe1e 426 do {
427 n = fread(buf, 1, sizeof(buf), fp);
cd6eca43
MW
428 if (f & f_progress) fprogress_update(&ff, n);
429 if (e->ops->write(e, buf, n)) {
430 if (f & f_progress) fprogress_done(&ff);
fa54fe1e 431 die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
cd6eca43 432 }
fa54fe1e 433 } while (n == sizeof(buf));
cd6eca43 434 if (f & f_progress) fprogress_done(&ff);
fa54fe1e 435 e->ops->encdone(e);
436 freeenc(e);
437 return (0);
438
439#undef f_bogus
cd6eca43 440#undef f_progress
fa54fe1e 441}
442
443int cmd_decode(int argc, char *argv[])
444{
cd6eca43 445 const char *fn, *of = 0;
fa54fe1e 446 FILE *ofp = 0;
447 FILE *fp = 0;
448 const char *ef = "binary";
449 const char *bd = 0;
cd6eca43 450 fprogress ff;
fa54fe1e 451 int i;
452 char buf[4096];
453 unsigned f = 0;
454 const encops *eo;
455 enc *e;
456
457#define f_bogus 1u
cd6eca43 458#define f_progress 2u
fa54fe1e 459
460 for (;;) {
461 static const struct option opt[] = {
45c0fd36
MW
462 { "format", OPTF_ARGREQ, 0, 'f' },
463 { "boundary", OPTF_ARGREQ, 0, 'b' },
464 { "output", OPTF_ARGREQ, 0, 'o' },
cd6eca43 465 { "progress", 0, 0, 'p' },
fa54fe1e 466 { 0, 0, 0, 0 }
467 };
cd6eca43 468 i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0);
fa54fe1e 469 if (i < 0) break;
470 switch (i) {
471 case 'f': ef = optarg; break;
472 case 'b': bd = optarg; break;
473 case 'o': of = optarg; break;
cd6eca43 474 case 'p': f |= f_progress; break;
fa54fe1e 475 default: f |= f_bogus; break;
476 }
477 }
478 if (argc - optind > 1 || (f & f_bogus))
479 die(EXIT_FAILURE, "Usage: decode [-OPTIONS] [FILE]");
480
481 if ((eo = getenc(ef)) == 0)
482 die(EXIT_FAILURE, "encoding `%s' not found", ef);
483
cd6eca43 484 fn = optind < argc ? argv[optind++] : "-";
141c1284 485 if (STRCMP(fn, ==, "-"))
fa54fe1e 486 fp = stdin;
cd6eca43 487 else if ((fp = fopen(fn, eo->rmode)) == 0) {
fa54fe1e 488 die(EXIT_FAILURE, "couldn't open file `%s': %s",
cd6eca43
MW
489 fn, strerror(errno));
490 }
fa54fe1e 491
141c1284 492 if (!of || STRCMP(of, ==, "-"))
fa54fe1e 493 ofp = stdout;
494 else if ((ofp = fopen(of, "wb")) == 0) {
495 die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
9b1663a5 496 of, strerror(errno));
fa54fe1e 497 }
498
499 e = initdec(eo, fp, checkbdry, (/*unconst*/ void *)bd);
500
cd6eca43
MW
501 if (f & f_progress) {
502 if (fprogress_init(&ff, fn, fp)) {
503 die(EXIT_FAILURE, "failed to initialize progress display: %s",
504 strerror(errno));
505 }
506 }
507
fa54fe1e 508 do {
cd6eca43
MW
509 if ((i = e->ops->read(e, buf, sizeof(buf))) < 0) {
510 if (f & f_progress) fprogress_done(&ff);
fa54fe1e 511 die(EXIT_FAILURE, "error reading input: %s", strerror(errno));
cd6eca43
MW
512 }
513 if (f & f_progress)
514 fprogress_update(&ff, i*e->ops->ncook/e->ops->nraw);
515 if (fwrite(buf, 1, i, ofp) < i) {
516 if (f & f_progress) fprogress_done(&ff);
fa54fe1e 517 die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
cd6eca43 518 }
fa54fe1e 519 } while (i == sizeof(buf));
520 e->ops->decdone(e);
cd6eca43 521 if (f & f_progress) fprogress_done(&ff);
fa54fe1e 522 freeenc(e);
523 return (0);
524
525#undef f_bogus
cd6eca43 526#undef f_progress
fa54fe1e 527}
528
5c3f75ec 529/*----- That's all, folks -------------------------------------------------*/