LDADD = libcatcrypt.a libcatacomb.la
define(`LIBCAT_SRC', `cc.h getdate.h dnl
- cc-sig.c cc-subcmd.c cc-enc.c cc-kem.c cc-list.c')
+ cc-sig.c cc-subcmd.c cc-enc.c cc-kem.c cc-list.c cc-progress.c')
libcatcrypt_a_SOURCES = LIBCAT_SRC getdate.y
patsubst(MP_BASE MP_SOURCES, `\.c\>', `.lo') dsig.o keyutil.o rspit.o \
.RI [ item ...]
.br
.B encrypt
-.RB [ \-aC ]
+.RB [ \-apC ]
.RB [ \-k
.IR tag ]
.RB [ \-f
.RI [ file ]
.br
.B decrypt
-.RB [ \-aqvC ]
+.RB [ \-apqvC ]
.RB [ \-f
.IR format ]
.RB [ \-o
.RI [ file ]
.br
.B encode
+.RB [ \-p ]
.RB [ \-f
.IR format ]
.RB [ \-b
.RI [ file ]
.br
.B decode
+.RB [ \-p ]
.RB [ \-f
.IR format ]
.RB [ \-b
in the current keyring; the default key is
.BR ccrypt .
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.BI "\-s, \-\-sign-key " tag
Use the signature key named
.I tag
Read input encoded according to
.IR format .
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.B "\-v, \-\-verbose"
Produce more verbose messages. See below for the messages produced
during decryption. The default verbosity level is 1. (Currently this
given on the command line, or from standard input if none is specified.
Options provided are:
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.BI "\-f, \-\-format " format
Produce output in
.IR format .
will start reading at the first plausible boundary string, and continue
processing until it reaches the matching end boundary.
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.BI "\-o, \-\-output " file
Write output to
.I file
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include "config.h"
#include <errno.h>
static int encrypt(int argc, char *argv[])
{
- const char *of = 0, *kn = "ccrypt", *skn = 0;
+ const char *fn, *of = 0, *kn = "ccrypt", *skn = 0;
FILE *ofp = 0;
FILE *fp = 0;
const char *ef = "binary";
+ fprogress ff;
const char *err;
int i;
int en;
#define f_bogus 1u
#define f_nocheck 2u
+#define f_progress 4u
for (;;) {
static const struct option opt[] = {
{ "armor", 0, 0, 'a' },
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "output", OPTF_ARGREQ, 0, 'o' },
+ { "progress", 0, 0, 'p' },
{ "nocheck", 0, 0, 'C' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "k:s:af:o:C", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "k:s:af:o:pC", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'k': kn = optarg; break;
case 'a': ef = "pem"; break;
case 'f': ef = optarg; break;
case 'o': of = optarg; break;
+ case 'p': f |= f_progress; break;
case 'C': f |= f_nocheck; break;
default: f |= f_bogus; break;
}
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
- if (optind == argc)
- fp = stdin;
- else if (strcmp(argv[optind], "-") == 0) {
+ fn = optind < argc ? argv[optind++] : "-";
+ if (strcmp(fn, "-") == 0)
fp = stdin;
- optind++;
- } else if ((fp = fopen(argv[optind], "rb")) == 0) {
+ else if ((fp = fopen(fn, "rb")) == 0) {
die(EXIT_FAILURE, "couldn't open file `%s': %s",
- argv[optind], strerror(errno));
- } else
- optind++;
+ fn, strerror(errno));
+ }
if (!of || strcmp(of, "-") == 0)
ofp = stdout;
/* --- Now do the main crypto --- */
+ if (f & f_progress) {
+ if (fprogress_init(&ff, fn, fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress display: %s",
+ strerror(errno));
+ }
+ }
+
assert(GC_CLASS(c)->blksz <= sizeof(bb));
dstr_ensure(&d, sizeof(bb) + GM_CLASS(m)->hashsz);
seq = 0;
}
n = fread(bb, 1, chsz, fp);
if (!n) break;
+ if (f & f_progress) fprogress_update(&ff, n);
buf_init(&b, d.buf, d.sz);
tag = buf_get(&b, GM_CLASS(m)->hashsz);
ct = buf_get(&b, n);
/* --- All done --- */
+ if (f & f_progress) fprogress_done(&ff);
e->ops->encdone(e);
GM_DESTROY(m);
GC_DESTROY(c);
#undef f_bogus
#undef f_nocheck
+#undef f_progress
}
/*---- Decryption ---------------------------------------------------------*/
static int decrypt(int argc, char *argv[])
{
- const char *of = 0;
+ const char *fn, *of = 0;
FILE *ofp = 0, *rfp = 0;
FILE *fp = 0;
const char *ef = "binary";
+ fprogress ff;
int i;
size_t n;
dstr d = DSTR_INIT;
#define f_bogus 1u
#define f_buffer 2u
#define f_nocheck 4u
+#define f_progress 8u
for (;;) {
static const struct option opt[] = {
{ "nocheck", 0, 0, 'C' },
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "output", OPTF_ARGREQ, 0, 'o' },
+ { "progress", 0, 0, 'p' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "abf:o:qvC", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "abf:o:pqvC", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'a': ef = "pem"; break;
case 'C': f |= f_nocheck; break;
case 'f': ef = optarg; break;
case 'o': of = optarg; break;
+ case 'p': f |= f_progress; break;
default: f |= f_bogus; break;
}
}
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
- if (optind == argc)
- fp = stdin;
- else if (strcmp(argv[optind], "-") == 0) {
+ fn = optind < argc ? argv[optind++] : "-";
+ if (strcmp(fn, "-") == 0)
fp = stdin;
- optind++;
- } else if ((fp = fopen(argv[optind], eo->rmode)) == 0) {
+ else if ((fp = fopen(fn, eo->rmode)) == 0) {
die(EXIT_FAILURE, "couldn't open file `%s': %s",
- argv[optind], strerror(errno));
- } else
- optind++;
+ fn, strerror(errno));
+ }
if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0))
die(EXIT_FAILURE, "can't open keyring `%s'", keyring);
e = initdec(eo, fp, checkbdry, "CATCRYPT ENCRYPTED MESSAGE");
+ if (f & f_progress) {
+ if (fprogress_init(&ff, fn, fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress display: %s",
+ strerror(errno));
+ }
+ }
+
/* --- Read the header chunk --- */
chunk_read(e, &d, &b);
+ if (f & f_progress)
+ fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
if (buf_getu32(&b, &id)) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL malformed header: missing keyid\n");
exit(EXIT_FAILURE);
}
if ((k = key_byid(&kf, id)) == 0) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
exit(EXIT_FAILURE);
}
if (BLEFT(&b)) {
if (buf_getu32(&b, &id)) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL malformed header: missing signature keyid\n");
exit(EXIT_FAILURE);
}
if ((sk = key_byid(&kf, id)) == 0) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL key id %08lx not found\n", (unsigned long)id);
exit(EXIT_FAILURE);
}
}
if (BLEFT(&b)) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL malformed header: junk at end\n");
exit(EXIT_FAILURE);
}
/* --- Read the KEM chunk --- */
chunk_read(e, &d, &b);
+ if (f & f_progress)
+ fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
if (setupkem(km, &d, &cx, &c, &m)) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL failed to decapsulate key\n");
exit(EXIT_FAILURE);
}
GC_ENCRYPT(cx, 0, d.buf, 1024);
GH_HASH(s->h, d.buf, 1024);
chunk_read(e, &d, &b);
+ if (f & f_progress)
+ fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
if (s->ops->doit(s, &d)) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL signature verification failed\n");
exit(EXIT_FAILURE);
}
if (verb) {
dstr_reset(&d);
key_fulltag(sk, &d);
+ if (f & f_progress) fprogress_clear(&ff);
printf("INFO good-signature %s\n", d.buf);
}
freesig(s);
- } else if (verb)
+ } else if (verb) {
+ if (f & f_progress) fprogress_clear(&ff);
printf("INFO no-signature\n");
+ }
/* --- Now decrypt the main body --- */
}
if (!(f & f_buffer)) {
if ((ofp = fopen(of, "wb")) == 0) {
+ if (f & f_progress) fprogress_done(&ff);
die(EXIT_FAILURE, "couldn't open file `%s' for output: %s",
ofp, strerror(errno));
}
rfp = ofp;
- } else if ((rfp = tmpfile()) == 0)
+ } else if ((rfp = tmpfile()) == 0) {
+ if (f & f_progress) fprogress_done(&ff);
die(EXIT_FAILURE, "couldn't create temporary file: %s", strerror(errno));
+ }
seq = 0;
dstr_ensure(&d, GC_CLASS(c)->blksz);
GH_HASHU32(h, seq);
seq++;
chunk_read(e, &d, &b);
+ if (f & f_progress)
+ fprogress_update(&ff, BLEFT(&b)*e->ops->ncook/e->ops->nraw);
if ((tag = buf_get(&b, GM_CLASS(m)->hashsz)) == 0) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL bad ciphertext chunk: no tag\n");
exit(EXIT_FAILURE);
}
GH_HASH(h, BCUR(&b), BLEFT(&b));
if (memcmp(tag, GH_DONE(h, 0), GM_CLASS(m)->hashsz) != 0) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb)
printf("FAIL bad ciphertext chunk: authentication failure\n");
exit(EXIT_FAILURE);
break;
GC_DECRYPT(c, BCUR(&b), BCUR(&b), BLEFT(&b));
if (fwrite(BCUR(&b), 1, BLEFT(&b), rfp) != BLEFT(&b)) {
+ if (f & f_progress) fprogress_done(&ff);
if (verb) printf("FAIL error writing output: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
+ if (f & f_progress) fprogress_done(&ff);
if (fflush(rfp) || ferror(rfp)) {
if (verb) printf("FAIL error writing output: %s\n", strerror(errno));
exit(EXIT_FAILURE);
of, strerror(errno));
}
rewind(rfp);
+ if (f & f_progress) fprogress_init(&ff, "copying buffer", rfp);
dstr_reset(&d);
dstr_ensure(&d, 65536);
if (verb && ofp == stdout) printf("DATA\n");
for (;;) {
n = fread(d.buf, 1, d.sz, rfp);
if (!n) break;
- if (fwrite(d.buf, 1, n, ofp) < n)
+ if (f & f_progress) fprogress_update(&ff, n);
+ if (fwrite(d.buf, 1, n, ofp) < n) {
+ if (f & f_progress) fprogress_done(&ff);
die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+ }
}
+ if (f & f_progress) fprogress_done(&ff);
if (ferror(rfp) || fclose(rfp))
die(EXIT_FAILURE, "error unbuffering output: %s", strerror(errno));
}
#undef f_bogus
#undef f_buffer
#undef f_nocheck
+#undef f_progress
}
/*----- Main code ---------------------------------------------------------*/
CMD_ENCODE,
CMD_DECODE,
{ "encrypt", encrypt,
- "encrypt [-aC] [-k TAG] [-s TAG] [-f FORMAT]\n\t\
+ "encrypt [-apC] [-k TAG] [-s TAG] [-f FORMAT]\n\t\
[-o OUTPUT] [FILE]", "\
Options:\n\
\n\
-k, --key=TAG Use public encryption key named by TAG.\n\
-s, --sign-key=TAG Use private signature key named by TAG.\n\
-o, --output=FILE Write output to FILE.\n\
+-p, --progress Show progress on large files.\n\
-C, --nocheck Don't check the public key.\n\
" },
{ "decrypt", decrypt,
- "decrypt [-abqvC] [-f FORMAT] [-o OUTPUT] [FILE]", "\
+ "decrypt [-abpqvC] [-f FORMAT] [-o OUTPUT] [FILE]", "\
Options:\n\
\n\
-a, --armour Same as `-f pem'.\n\
-b, --buffer Buffer output until we're sure we have it all.\n\
-f, --format=FORMAT Decode as FORMAT.\n\
-o, --output=FILE Write output to FILE.\n\
+-p, --progress Show progress on large files.\n\
-q, --quiet Produce fewer messages.\n\
-v, --verbose Produce more verbose messages.\n\
-C, --nocheck Don't check the private key.\n\
-" }, /* ' emacs is confused */
+" },
{ 0, 0, 0 }
};
.RI [ item ...]
.br
.B sign
-.RB [ \-adtC ]
+.RB [ \-adptC ]
.RB [ \-k
.IR tag ]
.RB [ \-f
.RI [ file ]
.br
.B verify
-.RB [ \-aquvC ]
+.RB [ \-apquvC ]
.RB [ \-k
.IR tag ]
.RB [ \-f
.RI [ file ]
.br
.B format
-.RB [ \-auABDET ]
+.RB [ \-apuABDET ]
.RB [ \-f
.IR format ]
.RB [ \-F
.RI [ message ]]
.br
.B encode
+.RB [ \-p ]
.RB [ \-f
.IR format ]
.RB [ \-b
.RI [ file ]
.br
.B decode
+.RB [ \-p ]
.RB [ \-f
.IR format ]
.RB [ \-b
.I file
rather than to standard output.
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.B "\-t, \-\-text"
Read and sign the input as text. This is the default.
.TP
during decryption. The default verbosity level is 1. (Currently this
is the most verbose setting. This might not be the case always.)
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.B "\-q, \-\-quiet"
Produce fewer messages.
.TP
Read input encoded according to
.IR format .
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.B "\-u, \-\-utc"
Show the datestamp in the signature in UTC rather than (your) local
time. The synonym
.B "\-\-armor"
is also accepted.
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.BI "\-A, \-\-armour-out"
Produce ASCII-armoured output. This is equivalent to specifying
.BR "\-F pem" .
is
.BR MESSAGE .
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.BI "\-o, \-\-output " file
Write output to
.I file
will start reading at the first plausible boundary string, and continue
processing until it reaches the matching end boundary.
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.BI "\-o, \-\-output " file
Write output to
.I file
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include "config.h"
#include <ctype.h>
#define F_BUFFER 256u
#define F_UTC 512u
#define F_NOCHECK 1024u
+#define F_PROGRESS 2048u
/*----- Chunk I/O ---------------------------------------------------------*/
unsigned f;
FILE *fp;
enc *e;
+ fprogress ff;
size_t (*read)(struct msgcanon *, void *);
void (*write)(struct msgcanon *, const void *, size_t);
void (*close)(struct msgcanon *);
ungetc(ch, m->fp);
done:
m->f = f;
+ if (m->f & F_PROGRESS) fprogress_update(&m->ff, n);
return (n);
}
}
static size_t binreadembed(msgcanon *m, void *bp)
- { return (chunk_read(m->e, bp)); }
+{
+ size_t n = chunk_read(m->e, bp);
+ if (m->f & F_PROGRESS) fprogress_update(&m->ff, n);
+ return (n);
+}
+
static size_t binreaddetach(msgcanon *m, void *bp)
- { return (fread(bp, 1, MSGBUFSZ - 1, m->fp)); }
+{
+ size_t n = fread(bp, 1, MSGBUFSZ - 1, m->fp);
+ if (m->f & F_PROGRESS) fprogress_update(&m->ff, n);
+ return (n);
+}
static void binwriteembed(msgcanon *m, const void *bp, size_t n)
{ chunk_write(m->e, bp, n); }
static void mcsetup_readfile(msgcanon *m, unsigned f, const char *fn)
{
- m->f = F_DETACH | (f & F_BINARY);
+ m->f = F_DETACH | (f & (F_BINARY | F_PROGRESS));
if (!fn || strcmp(fn, "-") == 0) {
m->fp = stdin;
m->f |= F_NOCLOSE;
} else if ((m->fp = fopen(fn, (f & F_BINARY) ? "rb" : "r")) == 0)
die(EXIT_FAILURE, "couldn't open file `%s': %s", fn, strerror(errno));
+ if (m->f & F_PROGRESS) {
+ if (fprogress_init(&m->ff, fn, m->fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+ strerror(errno));
+ }
+ }
m->read = (f & F_BINARY) ? binreaddetach : textread;
}
static void mcsetup_writenull(msgcanon *m) { m->write = nullwrite; }
-static void mcsetup_read(msgcanon *m, unsigned f, enc **ee, const char *dfn)
+static void mcsetup_read(msgcanon *m, unsigned f, enc **ee,
+ const char *fn, const char *dfn)
{
enc *e = *ee;
*ee = 0;
m->fp = e->fp;
m->read = binreadembed;
+ if (m->f & F_PROGRESS) {
+ if (fprogress_init(&m->ff, fn, m->fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+ strerror(errno));
+ }
+ }
} else {
m->read = binreaddetach;
if (!dfn || strcmp(dfn, "-") == 0)
die(EXIT_FAILURE, "can't open `%s': %s", dfn, strerror(errno));
else
m->f &= ~F_NOCLOSE;
+ if (m->f & F_PROGRESS) {
+ if (fprogress_init(&m->ff, dfn, m->fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+ strerror(errno));
+ }
+ }
}
} else {
m->read = textread;
m->fp = e->fp;
e->ops->destroy(e);
*ee = 0;
- } else if (!dfn || strcmp(dfn, "-") == 0)
- m->fp = stdin;
- else if ((m->fp = fopen(dfn, "r")) == 0)
- die(EXIT_FAILURE, "can't read file `%s': %s", dfn, strerror(errno));
- else
- m->f &= ~F_NOCLOSE;
+ if (m->f & F_PROGRESS) {
+ if (fprogress_init(&m->ff, fn, m->fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+ strerror(errno));
+ }
+ }
+ } else {
+ if (!dfn || strcmp(dfn, "-") == 0)
+ m->fp = stdin;
+ else if ((m->fp = fopen(dfn, "r")) == 0)
+ die(EXIT_FAILURE, "can't read file `%s': %s", dfn, strerror(errno));
+ else
+ m->f &= ~F_NOCLOSE;
+ if (m->f & F_PROGRESS) {
+ if (fprogress_init(&m->ff, dfn, m->fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress indicator: %s",
+ strerror(errno));
+ }
+ }
+ }
}
}
if (ferror(m->fp) || fclose(m->fp))
die(EXIT_FAILURE, "error closing message file: %s", strerror(errno));
}
+ if (m->f & F_PROGRESS) fprogress_done(&m->ff);
}
static void mc_endwrite(msgcanon *m, const encops *eops, enc **ee)
{ "key", OPTF_ARGREQ, 0, 'k' },
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "output", OPTF_ARGREQ, 0, 'o' },
+ { "progress", 0, 0, 'p' },
{ "text", 0, 0, 't' },
{ "nocheck", 0, 0, 'C' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "k:f:o:abdtC", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "k:f:o:abdptC", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'k': kn = optarg; break;
case 'b': f |= F_BINARY; break;
case 'd': f |= F_DETACH; break;
case 'C': f |= F_NOCHECK; break;
+ case 'p': f |= F_PROGRESS; break;
default: f |= F_BOGUS; break;
}
}
static int verify(int argc, char *argv[])
{
- const char *ef = "binary", *of = 0, *dfn = 0, *kn = 0, *err;
+ const char *ef = "binary", *of = 0, *fn, *dfn = 0, *kn = 0, *err;
vrfctx v = { 0, 0, 1 };
key_file kf;
key *k, *kk = 0;
sigmsg s;
FILE *fp, *ofp = 0, *rfp = 0;
+ fprogress ff;
struct tm *tm;
int i;
char bb[MSGBUFSZ];
{ "key", OPTF_ARGREQ, 0, 'k' },
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "output", OPTF_ARGREQ, 0, 'o' },
+ { "progress", 0, 0, 'p' },
{ "quiet", 0, 0, 'q' },
{ "utc", 0, 0, 'u' },
{ "fresh-time", 0, 0, 't' },
{ "nocheck", 0, 0, 'C' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "k:f:o:abqt:uvC", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "k:f:o:abpqt:uvC", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'a': ef = "pem"; break;
break;
case 'q': if (v.verb > 0) v.verb--; break;
case 'v': if (v.verb < 10) v.verb++; break;
+ case 'p': v.f |= F_PROGRESS; break;
default: v.f |= F_BOGUS; break;
}
}
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
- if (optind >= argc)
- fp = stdin;
- else if (strcmp(argv[optind], "-") == 0) {
+ fn = optind < argc ? argv[optind++] : "-";
+ if (strcmp(fn, "-") == 0)
fp = stdin;
- optind++;
- } else if ((fp = fopen(argv[optind], eo->rmode)) == 0) {
+ else if ((fp = fopen(fn, eo->rmode)) == 0) {
die(EXIT_FAILURE, "couldn't open file `%s': %s",
- argv[optind], strerror(errno));
- } else
- optind++;
+ fn, strerror(errno));
+ }
if (key_open(&kf, keyring, KOPEN_READ, key_moan, 0))
die(EXIT_FAILURE, "can't open keyring `%s'", keyring);
sig_readsig(e, &s);
if (optind < argc)
dfn = argv[optind++];
- mcsetup_read(&mc_in, v.f, &e, dfn);
+ mcsetup_read(&mc_in, v.f, &e, fn, dfn);
if (!of && (v.f & F_DETACH)) {
rfp = ofp = 0;
of, strerror(errno));
}
rewind(rfp);
+ if (v.f & F_PROGRESS) fprogress_init(&ff, "copying buffer", rfp);
if (v.verb && ofp == stdout) printf("DATA\n");
for (;;) {
n = fread(bb, 1, sizeof(bb), rfp);
if (!n) break;
- if (fwrite(bb, 1, n, ofp) < n)
+ if (v.f & F_PROGRESS) fprogress_update(&ff, n);
+ if (fwrite(bb, 1, n, ofp) < n) {
+ if (v.f & F_PROGRESS) fprogress_done(&ff);
die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+ }
}
+ if (v.f & F_PROGRESS) fprogress_done(&ff);
if (ferror(rfp) || fclose(rfp))
die(EXIT_FAILURE, "error unbuffering output: %s", strerror(errno));
}
static int format(int argc, char *argv[])
{
const char *ief = "binary", *oef = "binary";
- const char *dfn = 0, *of = 0, *mf = 0;
+ const char *fn, *dfn = 0, *of = 0, *mf = 0;
sigmsg s;
FILE *fp, *ofp = 0, *mfp = 0;
int i;
{ "format-out", OPTF_ARGREQ, 0, 'F' },
{ "message", OPTF_ARGREQ, 0, 'm' },
{ "output", OPTF_ARGREQ, 0, 'o' },
+ { "progress", 0, 0, 'p' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "f:F:m:o:aADE", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "f:F:m:o:apADE", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'a': ief = "pem"; break;
case 'E': f &= ~F_DETACH; fm |= F_DETACH; break;
case 'm': mf = optarg; break;
case 'o': of = optarg; break;
+ case 'p': f |= F_PROGRESS; break;
default: f |= F_BOGUS; break;
}
}
if ((oeo = getenc(oef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", oef);
- if (optind >= argc)
- fp = stdin;
- else if (strcmp(argv[optind], "-") == 0) {
+ fn = optind < argc ? argv[optind++] : "-";
+ if (strcmp(fn, "-") == 0)
fp = stdin;
- optind++;
- } else if ((fp = fopen(argv[optind], ieo->rmode)) == 0) {
+ else if ((fp = fopen(fn, ieo->rmode)) == 0) {
die(EXIT_FAILURE, "couldn't open file `%s': %s",
- argv[optind], strerror(errno));
- } else
- optind++;
+ fn, strerror(errno));
+ }
if (optind < argc)
dfn = argv[optind++];
if (((s.f ^ v.f) & v.m) != 0)
moan("boundary string inconsistent with contents (ignoring)");
- mcsetup_read(&mc_in, s.f, &ie, dfn);
+ mcsetup_read(&mc_in, s.f, &ie, fn, dfn);
/* --- Prepare the output stuff --- */
CMD_ENCODE,
CMD_DECODE,
{ "sign", sign,
- "sign [-adtC] [-k TAG] [-f FORMAT] [-o OUTPUT] [FILE]", "\
+ "sign [-adptC] [-k TAG] [-f FORMAT] [-o OUTPUT] [FILE]", "\
Options:\n\
\n\
-a, --armour Same as `-f pem'.\n\
-f, --format=FORMAT Encode as FORMAT.\n\
-k, --key=TAG Use public encryption key named by TAG.\n\
-o, --output=FILE Write output to FILE.\n\
+-p, --progress Show progress on large files.\n\
-t, --text Canonify input message as a text file.\n\
-C, --nocheck Don't check the private key.\n\
" },
{ "verify", verify,
- "verify [-abquvC] [-f FORMAT] [-k TAG] [-o OUTPUT]\n\t\
+ "verify [-abpquvC] [-f FORMAT] [-k TAG] [-o OUTPUT]\n\t\
[FILE [MESSAGE]]", "\
Options:\n\
\n\
-f, --format=FORMAT Decode as FORMAT.\n\
-k, --key=TAG Require that the message be signed by key TAG.\n\
-o, --output=FILE Write message to FILE.\n\
+-p, --progress Show progress on large files.\n\
-q, --quiet Produce fewer messages.\n\
-t, --freshtime=TIME Only accept signatures made after this time.\n\
-u, --utc Show dates in UTC rather than local time.\n\
-u, --utc Show dates in UTC rather than local time.\n\
"},
{ "format", format,
- "format [-auADE] [-f FORMAT] [-F format] [-m FILE] [-o FILE]\n\t\
+ "format [-apuADE] [-f FORMAT] [-F format] [-m FILE] [-o FILE]\n\t\
[FILE [MESSAGE]]", "\
Options:\n\
\n\
-F, --format-out=FORMAT Encode output as FORMAT.\n\
-m, --message=FILE Write message to FILE.\n\
-o, --output=FILE Write new signature to FILE.\n\
+-p, --progress Show progress on large files.\n\
"},
{ 0, 0, 0 }
}; /* " Emacs seems confused. */
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include <errno.h>
#include <stdio.h>
/* --- Encoder table --- */
const encops enctab[] = {
- { "binary", "rb", "wb",
+ { "binary", "rb", "wb", 1, 1,
bin_encinit, bin_decinit,
bin_read, bin_write,
bin_done, bin_done,
bin_destroy },
- { "pem", "r", "w",
+ { "pem", "r", "w", 3, 4,
pem_encinit, pem_decinit,
pem_read, pem_write,
pem_encdone, pem_decdone,
int cmd_encode(int argc, char *argv[])
{
- const char *of = 0;
+ const char *fn, *of = 0;
FILE *ofp = 0;
FILE *fp = 0;
const char *ef = "binary";
const char *bd = "MESSAGE";
+ fprogress ff;
int i;
size_t n;
char buf[4096];
enc *e;
#define f_bogus 1u
+#define f_progress 2u
for (;;) {
static const struct option opt[] = {
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "boundary", OPTF_ARGREQ, 0, 'b' },
{ "output", OPTF_ARGREQ, 0, 'o' },
+ { "progress", 0, 0, 'p' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "f:b:o:", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'f': ef = optarg; break;
case 'b': bd = optarg; break;
case 'o': of = optarg; break;
+ case 'p': f |= f_progress; break;
default: f |= f_bogus; break;
}
}
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
- if (optind == argc)
- fp = stdin;
- else if (strcmp(argv[optind], "-") == 0) {
+ fn = optind < argc ? argv[optind++] : "-";
+ if (strcmp(fn, "-") == 0)
fp = stdin;
- optind++;
- } else if ((fp = fopen(argv[optind], "rb")) == 0) {
+ else if ((fp = fopen(fn, "rb")) == 0) {
die(EXIT_FAILURE, "couldn't open file `%s': %s",
- argv[optind], strerror(errno));
- } else
- optind++;
+ fn, strerror(errno));
+ }
if (!of || strcmp(of, "-") == 0)
ofp = stdout;
e = initenc(eo, ofp, bd);
+ if (f & f_progress) {
+ if (fprogress_init(&ff, fn, fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress display: %s",
+ strerror(errno));
+ }
+ }
+
do {
n = fread(buf, 1, sizeof(buf), fp);
- if (e->ops->write(e, buf, n))
+ if (f & f_progress) fprogress_update(&ff, n);
+ if (e->ops->write(e, buf, n)) {
+ if (f & f_progress) fprogress_done(&ff);
die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+ }
} while (n == sizeof(buf));
+ if (f & f_progress) fprogress_done(&ff);
e->ops->encdone(e);
freeenc(e);
return (0);
#undef f_bogus
+#undef f_progress
}
int cmd_decode(int argc, char *argv[])
{
- const char *of = 0;
+ const char *fn, *of = 0;
FILE *ofp = 0;
FILE *fp = 0;
const char *ef = "binary";
const char *bd = 0;
+ fprogress ff;
int i;
char buf[4096];
unsigned f = 0;
enc *e;
#define f_bogus 1u
+#define f_progress 2u
for (;;) {
static const struct option opt[] = {
{ "format", OPTF_ARGREQ, 0, 'f' },
{ "boundary", OPTF_ARGREQ, 0, 'b' },
{ "output", OPTF_ARGREQ, 0, 'o' },
+ { "progress", 0, 0, 'p' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "f:b:o:", opt, 0, 0, 0);
+ i = mdwopt(argc, argv, "f:b:o:p", opt, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'f': ef = optarg; break;
case 'b': bd = optarg; break;
case 'o': of = optarg; break;
+ case 'p': f |= f_progress; break;
default: f |= f_bogus; break;
}
}
if ((eo = getenc(ef)) == 0)
die(EXIT_FAILURE, "encoding `%s' not found", ef);
- if (optind == argc)
+ fn = optind < argc ? argv[optind++] : "-";
+ if (strcmp(fn, "-") == 0)
fp = stdin;
- else if (strcmp(argv[optind], "-") == 0) {
- fp = stdin;
- optind++;
- } else if ((fp = fopen(argv[optind], eo->rmode)) == 0) {
+ else if ((fp = fopen(fn, eo->rmode)) == 0) {
die(EXIT_FAILURE, "couldn't open file `%s': %s",
- argv[optind], strerror(errno));
- } else
- optind++;
+ fn, strerror(errno));
+ }
if (!of || strcmp(of, "-") == 0)
ofp = stdout;
e = initdec(eo, fp, checkbdry, (/*unconst*/ void *)bd);
+ if (f & f_progress) {
+ if (fprogress_init(&ff, fn, fp)) {
+ die(EXIT_FAILURE, "failed to initialize progress display: %s",
+ strerror(errno));
+ }
+ }
+
do {
- if ((i = e->ops->read(e, buf, sizeof(buf))) < 0)
+ if ((i = e->ops->read(e, buf, sizeof(buf))) < 0) {
+ if (f & f_progress) fprogress_done(&ff);
die(EXIT_FAILURE, "error reading input: %s", strerror(errno));
- if (fwrite(buf, 1, i, ofp) < i)
+ }
+ if (f & f_progress)
+ fprogress_update(&ff, i*e->ops->ncook/e->ops->nraw);
+ if (fwrite(buf, 1, i, ofp) < i) {
+ if (f & f_progress) fprogress_done(&ff);
die(EXIT_FAILURE, "error writing output: %s", strerror(errno));
+ }
} while (i == sizeof(buf));
e->ops->decdone(e);
+ if (f & f_progress) fprogress_done(&ff);
freeenc(e);
return (0);
#undef f_bogus
+#undef f_progress
}
/*----- That's all, folks -------------------------------------------------*/
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include <stdlib.h>
#include <mLib/alloc.h>
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include <mLib/report.h>
#include "cc.h"
--- /dev/null
+/* -*-c-*-
+ *
+ * Progress indicators for command-line tools
+ *
+ * (c) 2011 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#define _FILE_OFFSET_BITS 64
+
+#include "config.h"
+
+#include "cc.h"
+
+#ifndef PATHSEP
+# if defined(__riscos)
+# define PATHSEP '.'
+# elif defined(__unix) || defined(unix)
+# define PATHSEP '/'
+# else
+# define PATHSEP '\\'
+# endif
+#endif
+
+/*----- Static data -------------------------------------------------------*/
+
+static const char baton[] = "-\\|/";
+
+/*----- Human-friendly unit printing --------------------------------------*/
+
+struct unit {
+ const char *name;
+ int m;
+};
+
+/* --- @prhuman_time@ --- *
+ *
+ * Arguments: @FILE *fp@ = stream to print on
+ * @unsigned long n@ = time in seconds to print
+ *
+ * Returns: ---
+ *
+ * Use: Prints a time in some reasonable format. The time takes up
+ * PRHUMAN_TIMEWD character spaces.
+ */
+
+#define PRHUMAN_TIMEWD 7
+
+static void prhuman_time(FILE *fp, unsigned long n)
+{
+ const static struct unit utime[] = {
+ { "s", 60 }, { "m", 60 }, { "h", 24 }, { "d", 0 }
+ };
+
+ unsigned long m = 0;
+ const struct unit *u = utime;
+
+ while (u[1].m && n > u[0].m*u[1].m) { n /= u->m; u++; }
+ m = n / u[1].m; n %= u[0].m;
+ if (m) fprintf(fp, "%3lu%s%02lu%s", m, u[1].name, n, u[0].name);
+ else fprintf(fp, " %2lu%s", n, u[0].name);
+}
+
+/* --- @prhuman_data@ --- *
+ *
+ * Arguments: @FILE *fp@ = file to print on
+ * @off_t n@ = size to be printed
+ *
+ * Returns: ---
+ *
+ * Use: Prints a data size in some reasonable format. The data size
+ * takes up PRHUMAN_DATAWD character spaces.
+ */
+
+#define PRHUMAN_DATAWD 7
+
+static void prhuman_data(FILE *fp, off_t n)
+{
+ const static struct unit udata[] = {
+ { " ", 1024 }, { "k", 1024 }, { "M", 1024 }, { "G", 1024 },
+ { "T", 1024 }, { "P", 1024 }, { "E", 1024 }, { "Z", 1024 },
+ { "Y", 0 }
+ };
+
+ double x = n;
+ const struct unit *u = udata;
+
+ while (u->m && x >= u->m) { x /= u->m; u++; }
+ fprintf(fp, "%6.1f%s", x, u->name);
+}
+
+/*----- Main code ---------------------------------------------------------*/
+
+#define BARWD 16
+
+/* --- @fprogress_init@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context to be initialized
+ * @const char *name@ = file name string to show
+ * @FILE *fp@ = file we're reading from
+ *
+ * Returns: Zero on success, nonzero if the file's state is now broken.
+ *
+ * Use: Initializes a progress context. Nothing is actually
+ * displayed yet.
+ */
+
+int fprogress_init(fprogress *f, const char *name, FILE *fp)
+{
+ const char *p;
+ off_t o, sz = -1;
+ size_t n;
+
+ /* --- Set up the offset --- */
+
+ if ((o = ftello(fp)) >= 0 &&
+ fseeko(fp, 0, SEEK_END) >= 0 &&
+ (sz = ftello(fp),
+ fseeko(fp, o, SEEK_SET) < 0))
+ return (-1);
+ if (o != -1 && sz != -1) sz -= o;
+ f->o = f->olast = 0; f->sz = sz;
+
+ /* --- Set up the file name --- */
+
+ n = strlen(name);
+ if (n < sizeof(f->name))
+ strcpy(f->name, name);
+ else if ((p = strchr(name + n - sizeof(f->name) + 4, PATHSEP)) != 0)
+ sprintf(f->name, "...%s", p);
+ else {
+ p = strrchr(name, PATHSEP);
+ if (!p) sprintf(f->name, "%.*s...", (int)sizeof(f->name) - 4, name);
+ else sprintf(f->name, "...%.*s...", (int)sizeof(f->name) - 7, p);
+ }
+
+ /* --- Set up some other stuff --- */
+
+ f->start = f->last = time(0);
+ f->bp = baton;
+
+ /* --- Done --- */
+
+ return (0);
+}
+
+/* --- @fprogress_clear@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context
+ *
+ * Returns: ---
+ *
+ * Use: Clears the progress display from the screen.
+ */
+
+void fprogress_clear(fprogress *f)
+{
+ fprintf(stderr, "\r%*s\r",
+ sizeof(f->name) + 2*PRHUMAN_DATAWD + PRHUMAN_TIMEWD + BARWD + 16,
+ "");
+}
+
+/* --- @fprogress_update@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context
+ * @size_t n@ = how much progress has been made
+ *
+ * Returns: ---
+ *
+ * Use: Maybe updates the display to show that some progress has been
+ * made.
+ */
+
+void fprogress_update(fprogress *f, size_t sz)
+{
+ time_t now = time(0);
+ int i, n;
+
+ /* --- See if there's anything to do --- */
+
+ f->o += sz;
+ if (difftime(now, f->last) < 1) return;
+ f->last = now;
+
+ /* --- See if we're going to lose the ETA and percentage indicators --- */
+
+ if (f->olast < f->sz && f->o > f->sz) fprogress_clear(f);
+ f->olast = f->o;
+
+ /* --- Do the initial display --- */
+
+ fprintf(stderr, "\r%-*s%c ",
+ (int)sizeof(f->name), f->name,
+ *f->bp++);
+ if (!*f->bp) f->bp = baton;
+ prhuman_data(stderr, f->o);
+
+ /* --- More complicated display if we have a set size --- */
+
+ if (f->sz > f->o) {
+ fputc('/', stderr);
+ prhuman_data(stderr, f->sz);
+ fputs(" [", stderr);
+ n = (f->o*BARWD + f->sz/2)/f->sz;
+ for (i = 0; i < n; i++) fputc('.', stderr);
+ fprintf(stderr, "%*s] %3d%% ETA ", BARWD - n, "",
+ (int)((f->o*100 + 50)/f->sz));
+ prhuman_time(stderr, difftime(now, f->start)*(f->sz - f->o)/f->o);
+ }
+}
+
+/* --- @fprogress_done@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context
+ *
+ * Returns: ---
+ *
+ * Use: Clear up the progress context and removes any display.
+ */
+
+void fprogress_done(fprogress *f) { fprogress_clear(f); }
+
+/*----- That's all, folks -------------------------------------------------*/
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include <stdlib.h>
#include <mLib/report.h>
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include <mLib/quis.h>
#include <mLib/report.h>
/*----- Header files ------------------------------------------------------*/
+#if _FILE_OFFSET_BITS != 64
+# error "Must set _FILE_OFFSET_BITS to 64."
+#endif
+
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include <mLib/dstr.h>
/*----- Data structures ---------------------------------------------------*/
+/* --- Progress indicators --- */
+
+typedef struct fprogress {
+ const char *bp;
+ off_t o, sz, olast;
+ time_t start, last;
+ char name[24];
+} fprogress;
+
/* --- Key encapsulation --- */
typedef struct kem {
typedef struct encops {
const char *name;
const char *rmode, *wmode;
+ int nraw, ncook;
enc *(*initenc)(FILE */*fp*/, const char */*msg*/);
enc *(*initdec)(FILE */*fp*/,
int (*/*func*/)(const char *, void *), void */*p*/);
#define CMD_ENCODE { \
"encode", cmd_encode, \
- "encode [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]", \
+ "encode [-p] [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]", \
"\
Options:\n\
\n\
-f, --format=FORMAT Encode to FORMAT.\n\
-b, --boundary=LABEL PEM boundary is LABEL.\n\
-o, --output=FILE Write output to FILE.\n\
+-p, --progress Show progress on large files.\n\
" }
#define CMD_DECODE { \
"decode", cmd_decode, \
- "decode [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]", \
+ "decode [-p] [-f FORMAT] [-b LABEL] [-o OUTPUT] [FILE]", \
"\
Options:\n\
\n\
-f, --format=FORMAT Decode from FORMAT.\n\
-b, --boundary=LABEL PEM boundary is LABEL.\n\
-o, --output=FILE Write output to FILE.\n\
+-p, --progress Show progress on large files.\n\
" }
extern int cmd_encode(int /*argc*/, char */*argv*/[]);
extern void sc_help(const cmd */*cmds*/, FILE */*fp*/,
char *const */*argv*/);
+/*----- Progress indicators -----------------------------------------------*/
+
+/* --- @fprogress_init@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context to be initialized
+ * @const char *name@ = file name string to show
+ * @FILE *fp@ = file we're reading from
+ *
+ * Returns: Zero on success, nonzero if the file's state is now broken.
+ *
+ * Use: Initializes a progress context. Nothing is actually
+ * displayed yet.
+ */
+
+extern int fprogress_init(fprogress */*f*/,
+ const char */*name*/, FILE */*fp*/);
+
+/* --- @fprogress_update@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context
+ * @size_t n@ = how much progress has been made
+ *
+ * Returns: ---
+ *
+ * Use: Maybe updates the display to show that some progress has been
+ * made.
+ */
+
+extern void fprogress_update(fprogress */*f*/, size_t /*n*/);
+
+/* --- @fprogress_clear@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context
+ *
+ * Returns: ---
+ *
+ * Use: Clears the progress display from the screen.
+ */
+
+extern void fprogress_clear(fprogress */*f*/);
+
+/* --- @fprogress_done@ --- *
+ *
+ * Arguments: @fprogress *f@ = progress context
+ *
+ * Returns: ---
+ *
+ * Use: Clear up the progress context and removes any display.
+ */
+
+extern void fprogress_done(fprogress */*f*/);
+
/*----- That's all, folks -------------------------------------------------*/
#ifdef __cplusplus
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include "config.h"
#include <errno.h>
.RI [ item ...]
.br
.B sign
-.RB [ \-0bqvC ]
+.RB [ \-0bpqvC ]
.RB [ \-c
.IR comment ]
.RB [ \-k
.IR output ]
.br
.B verify
-.RB [ \-qvC ]
+.RB [ \-pqvC ]
.RI [ file ]
.SH DESCRIPTION
The
as a comment in the output file. The comment's integrity is protected
by the signature.
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.BI "\-f, \-\-file " name
Read filenames from
.I name
.B "\-q, \-\-quiet"
Produce less information output.
.TP
+.BI "\-p, \-\-progress"
+Write a progress meter to standard error while processing large files.
+.TP
.B "\-C, \-\-nocheck"
Don't check the public key for validity. This makes verification go
much faster, but at the risk of using a duff key, and potentially
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include "config.h"
#include <ctype.h>
/* --- @fhash@ --- *
*
* Arguments: @const gchash *c@ = pointer to hash class
+ * @unsigned f@ = flags
* @const char *file@ = file to hash
* @void *b@ = pointer to output buffer
*
* Use: Hashes a file.
*/
-static int fhash(const gchash *c, const char *file, void *b)
+#define FHF_PROGRESS 256u
+
+static int fhash(const gchash *c, unsigned f, const char *file, void *b)
{
FILE *fp = fopen(file, "rb");
+ fprogress ff;
ghash *h = GH_INIT(c);
char buf[4096];
size_t sz;
if (!fp)
return (-1);
- while ((sz = fread(buf, 1, sizeof(buf), fp)) > 0)
+ if (f & FHF_PROGRESS) {
+ if (fprogress_init(&ff, file, fp)) return (-1);
+ }
+ while ((sz = fread(buf, 1, sizeof(buf), fp)) > 0) {
GH_HASH(h, buf, sz);
+ if (f & FHF_PROGRESS) fprogress_update(&ff, sz);
+ }
if (ferror(fp))
rc = -1;
+ if (f & FHF_PROGRESS) fprogress_done(&ff);
GH_DONE(h, b);
GH_DESTROY(h);
fclose(fp);
{ "null", 0, 0, '0' },
{ "binary", 0, 0, 'b' },
{ "verbose", 0, 0, 'v' },
+ { "progress", 0, 0, 'p' },
{ "quiet", 0, 0, 'q' },
{ "comment", OPTF_ARGREQ, 0, 'c' },
{ "file", OPTF_ARGREQ, 0, 'f' },
{ "nocheck", OPTF_ARGREQ, 0, 'C' },
{ 0, 0, 0, 0 }
};
- int i = mdwopt(argc, argv, "+0vqbC" "c:" "f:o:" "k:e:", opts, 0, 0, 0);
+ int i = mdwopt(argc, argv, "+0vpqbC" "c:" "f:o:" "k:e:", opts, 0, 0, 0);
if (i < 0)
break;
switch (i) {
case 'v':
verb++;
break;
+ case 'p':
+ f |= FHF_PROGRESS;
+ break;
case 'q':
if (verb > 0)
verb--;
break;
b.tag = T_FILE;
DENSURE(&b.b, GH_CLASS(s->h)->hashsz);
- if (fhash(GH_CLASS(s->h), b.d.buf, b.b.buf)) {
+ if (fhash(GH_CLASS(s->h), f, b.d.buf, b.b.buf)) {
moan("Error reading `%s': %s", b.d.buf, strerror(errno));
f |= f_bogus;
} else {
for (;;) {
static struct option opts[] = {
{ "verbose", 0, 0, 'v' },
+ { "progress", 0, 0, 'p' },
{ "quiet", 0, 0, 'q' },
{ "nocheck", 0, 0, 'C' },
{ 0, 0, 0, 0 }
};
- int i = mdwopt(argc, argv, "+vqC", opts, 0, 0, 0);
+ int i = mdwopt(argc, argv, "+vpqC", opts, 0, 0, 0);
if (i < 0)
break;
switch (i) {
case 'v':
verb++;
break;
+ case 'p':
+ f |= FHF_PROGRESS;
+ break;
case 'q':
if (verb)
verb--;
case T_FILE:
DRESET(&d);
DENSURE(&d, GH_CLASS(s->h)->hashsz);
- if (fhash(GH_CLASS(s->h), b.d.buf, d.buf)) {
+ if (fhash(GH_CLASS(s->h), f, b.d.buf, d.buf)) {
if (verb > 1) {
printf("BAD error reading file `%s': %s\n",
b.d.buf, strerror(errno));
{ "help", cmd_help, "help [COMMAND...]" },
{ "show", cmd_show, "show [ITEM...]" },
{ "sign", sign,
- "sign [-0bqvC] [-c COMMENT] [-k TAG] [-e EXPIRE]\n\t\
+ "sign [-0bpqvC] [-c COMMENT] [-k TAG] [-e EXPIRE]\n\t\
[-f FILE] [-o OUTPUT]",
"\
Options:\n\
-b, --binary Produce a binary output file.\n\
-q, --quiet Produce fewer messages while working.\n\
-v, --verbose Produce more messages while working.\n\
+-p, --progress Show progress on large files.\n\
-C, --nocheck Don't check the private key.\n\
-c, --comment=COMMENT Include COMMENT in the output file.\n\
-f, --file=FILE Read filenames to hash from FILE.\n\
-e, --expire=TIME The signature should expire after TIME.\n\
" },
{ "verify", verify,
- "verify [-qvC] [FILE]", "\
+ "verify [-pqvC] [FILE]", "\
Options:\n\
\n\
-q, --quiet Produce fewer messages while working.\n\
-v, --verbose Produce more messages while working.\n\
+-p, --progress Show progress on large files.\n\
-C, --nocheck Don't check the public key.\n\
" },
{ 0, 0, 0 }
#include "ghash.h"
#include "cc.h"
-#ifndef PATHSEP
-# if defined(__riscos)
-# define PATHSEP '.'
-# elif defined(__unix) || defined(unix)
-# define PATHSEP '/'
-# else
-# define PATHSEP '\\'
-# endif
-#endif
-
/*----- Static variables --------------------------------------------------*/
#define f_binary 1u
* Use: Hashes a file.
*/
-struct unit {
- const char *name;
- int m;
-};
-
-static void prhuman_time(FILE *fp, unsigned long n)
-{
- const static struct unit utime[] = {
- { "s", 60 }, { "m", 60 }, { "h", 24 }, { "d", 0 }
- };
-
- unsigned long m = 0;
- const struct unit *u = utime;
-
- while (u[1].m && n > u[0].m*u[1].m) { n /= u->m; u++; }
- m = n / u[1].m; n %= u[0].m;
- if (m) fprintf(fp, "%3lu%s%02lu%s", m, u[1].name, n, u[0].name);
- else fprintf(fp, " %2lu%s", n, u[0].name);
-}
-
-static void prhuman_data(FILE *fp, off_t n)
-{
- const static struct unit udata[] = {
- { " ", 1024 }, { "k", 1024 }, { "M", 1024 }, { "G", 1024 },
- { "T", 1024 }, { "P", 1024 }, { "E", 1024 }, { "Z", 1024 },
- { "Y", 0 }
- };
-
- double x = n;
- const struct unit *u = udata;
-
- while (u->m && x >= u->m) { x /= u->m; u++; }
- fprintf(fp, "%6.1f%s", x, u->name);
-}
-
static int fhash(const char *file, unsigned f, const gchash *gch, void *buf)
{
FILE *fp;
size_t sz;
ghash *h;
int e;
- off_t fsz = -1, fo;
- const char *p;
- dstr d = DSTR_INIT;
- static char baton[] = "-\\|/";
- char *bp = baton;
- time_t now, last, start;
- int i, pc;
+ fprogress ff;
if (!file || strcmp(file, "-") == 0)
fp = stdin;
return (-1);
if (f & f_progress) {
- if ((fo = ftello(fp)) >= 0 &&
- fseeko(fp, 0, SEEK_END) >= 0 &&
- (fsz = ftello(fp),
- fseeko(fp, fo, SEEK_SET) < 0))
- return (-1);
- if (fo != -1 && fsz != -1) fsz -= fo;
- fo = 0;
- sz = strlen(file);
- if (sz < 24)
- dstr_puts(&d, file);
- else if ((p = strchr(file + sz - 20, PATHSEP)) != 0) {
- dstr_puts(&d, "..."); dstr_puts(&d, p);
- } else {
- p = strrchr(file, PATHSEP);
- if (!p) dstr_putf(&d, "%.20s...", file);
- else dstr_putf(&d, "...%.17s...", p);
- }
- start = last = time(0);
+ if (fprogress_init(&ff, file, fp)) return (-1);
}
h = GH_INIT(gch);
while ((sz = fread(fbuf, 1, sizeof(fbuf), fp)) > 0) {
GH_HASH(h, fbuf, sz);
- if (f & f_progress) {
- fo += sz;
- now = time(0);
- if (difftime(now, last) < 1) continue;
- last = now;
- fprintf(stderr, "\r%-24s", d.buf);
- fprintf(stderr, "%c ", *bp++); if (!*bp) bp = baton;
- prhuman_data(stderr, fo);
- if (fsz >= fo) {
- fputc('/', stderr);
- prhuman_data(stderr, fsz);
- fputs(" [", stderr);
- pc = (fo*16 + fsz/2)/fsz;
- for (i = 0; i < pc; i++) fputc('.', stderr);
- for (; i < 16; i++) fputc(' ', stderr);
- fprintf(stderr, "] %3d%%", (int)((fo*100 + 50)/fsz));
- fprintf(stderr, " ETA ");
- prhuman_time(stderr, difftime(now, start)*(fsz - fo)/fo);
- }
- }
+ if (f & f_progress) fprogress_update(&ff, sz);
}
GH_DONE(h, buf);
GH_DESTROY(h);
- if (f & f_progress) fprintf(stderr, "\r%78s\r", "");
+ if (f & f_progress) fprogress_done(&ff);
e = ferror(fp);
if (file)
fclose(fp);
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include "config.h"
#include <ctype.h>
/*----- Header files ------------------------------------------------------*/
+#define _FILE_OFFSET_BITS 64
+
#include "config.h"
#include <errno.h>