📄 pgpprsbin.c
字号:
/* How many merged bytes are available? */
static size_t
inputMerged(struct Input const *input)
{
return (size_t)(input->bufend - input->bufptr);
}
/* Pointer to the merged bytes */
static unsigned char const *
inputMergedPtr(struct Input const *input)
{
return input->bufptr;
}
/*
* Return a buffer and length corresponding to the next batch of
* raw (unparsed) characters in the current packet.
* The bytes might come from one of three places:
* - The FIFO where they have been copied by inputMerge()
* - The input buffer
* - the passed-in external buffer
* In the latter case, this parses ahead in the input buffer as many
* subpackets as possible to give the largest block of data possible.
*
* Returns NULL with a length of 0 if there are no more bytes in the current
* packet. Returns "buf" with a length of 0 if size is 0.
* That may or may not be NULL, depending on the caller.
*/
static byte const *
inputRawPeek(struct Input const *input, byte const *buf, size_t size,
size_t *len)
{
byte const *p;
size_t s;
size_t size0;
unsigned ulen;
struct Header head;
pgpAssert(buf || !size);
/* Try the byte FIFO */
p = pgpFifoPeek (&pgpByteFifoDesc, input->fifo, &ulen);
if (p) {
*len = (size_t)ulen;
return p;
}
/* Then the buffered data */
if (input->passptr != input->bufend) {
*len = input->bufend - input->passptr;
return input->passptr;
}
/* Finally, the external buffer */
size0 = size;
p = buf;
head = input->head;
while (size && !inputFinished(&head)) {
s = inputHeadSeek(&head, p, size);
size -= s;
if (!size)
break;
p += s;
if (size <= head.pktlen) {
size = 0;
break;
}
size -= head.pktlen;
p += head.pktlen;
head.pktlen = 0;
}
*len = size0 - size;
return buf;
}
/*
* Skip forward over a given number of bytes of raw input data.
* The number of bytes must be <= the number returned from
* inputRawPeek().
*
* The FIFO and buffered data are simple. If those are empty,
* parse forward in the external buffer until the desired number of
* bytes have been skipped, then store the parsing state.
*/
static size_t
inputRawSeek(struct Input *input, byte const *buf, size_t size, unsigned len)
{
size_t s;
pgpAssert(buf || !size);
/* If there's data in the FIFO, skip that... */
if (pgpFifoSize (&pgpByteFifoDesc, input->fifo)) {
pgpFifoSeek (&pgpByteFifoDesc, input->fifo, len);
return 0;
}
/* Otherwise the buffered data */
if (input->passptr != input->bufend) {
pgpAssert(len <= (size_t)(input->bufend - input->passptr));
input->passptr += len;
if (input->bufptr < input->passptr)
input->bufptr = input->passptr;
return 0;
}
/* Finally, the external buffer */
pgpAssert(len <= size);
size = len;
while (size) {
s = inputHeadSeek(&input->head, buf, size);
size -= s;
if (!len)
break;
buf += s;
if (size <= input->head.pktlen) {
input->head.pktlen -= size;
break;
}
size -= input->head.pktlen;
buf += input->head.pktlen;
input->head.pktlen = 0;
}
return len;
}
/* Get rid of the header we've processed from the system. */
static void
inputPurge(struct Input *input)
{
pgpFifoFlush (&pgpByteFifoDesc, input->fifo);
input->passptr = input->bufptr = input->bufend = input->buffer;
}
/*
* Write all the already-buffered bytes from the current packet.
* Return an error, if any is encountered.
*/
static int
DoRawFlush (struct Context *ctx, struct PgpPipeline *tail)
{
int error = 0;
size_t len;
byte const *p;
do {
p = inputRawPeek(&ctx->input, NULL, 0, &len);
if (!p)
break;
len = tail->write (tail, p, len, &error);
(void)inputRawSeek(&ctx->input, NULL, 0, len);
} while (!error);
return error;
}
static size_t
DoSkip (struct PgpPipeline *myself, byte const *buf, size_t size, int *error)
{
struct Context *ctx;
size_t size0 = size;
byte const *p;
size_t len;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (struct Context *)myself->priv;
pgpAssert (ctx);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
*error = 0;
inputPurge (&ctx->input);
for (;;) {
p = inputPeek(&ctx->input, buf, size, &len);
if (!p) {
if (inputFinished(&ctx->input.head)) {
/* End of input */
myself->write = nextScope;
size -= nextScope (myself, buf, size, error);
}
break;
}
if (!len && !size)
break;
len = inputSeek(&ctx->input, buf, size, len);
size -= len;
buf += len;
}
return size0-size;
}
/*
* Write out the as-yet-unread body of this packet to the tail of this module.
* At the end of the packet (inputFinished), set the state back to
* nextScope.
*/
static size_t
DoWrite (struct PgpPipeline *myself, byte const *buf, size_t size, int *error)
{
struct Context *ctx;
size_t len;
size_t size0 = size;
byte const *p;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (struct Context *)myself->priv;
pgpAssert (ctx);
pgpAssert (ctx->tail);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
*error = 0;
do {
p = inputPeek(&ctx->input, buf, size, &len);
if (!p) {
if (inputFinished(&ctx->input.head)) {
/* End of input */
myself->write = nextScope;
size -= nextScope (myself, buf, size, error);
}
break;
}
if (!len && !size)
break;
len = ctx->tail->write (ctx->tail, p, len, error);
len = inputSeek(&ctx->input, buf, size, len);
size -= len;
buf += len;
} while (!*error);
return size0-size;
}
/*
* Write out a series of packets to the tail of this module, keeping
* track of packet boundaries, and counting pairs of signature headers
* and footers. When come to an unpaired footer, exit to process it.
*/
static size_t
DoWriteSignedPackets(struct PgpPipeline *myself, byte const *buf, size_t size,
int *error)
{
struct Context *ctx;
size_t len;
size_t size0 = size;
byte const *p;
byte b;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (struct Context *)myself->priv;
pgpAssert (ctx);
pgpAssert (ctx->tail);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
*error = 0;
switch (ctx->state) {
case 0:
/* Here at the start of a packet */
inputReset(&ctx->input);
if (!size)
return 0; /* I need a packet header! */
/*
* Track signature nesting.
* sig1nest holds the excess 1pass sig hdrs we've seen
* We distinguish old-style sig packets from new style by
* whether the packet type byte is old or new style.
*/
if (IS_NEW_PKTBYTE(buf[0])) {
byte bt = PKTBYTE_TYPE(buf[0]);
if (bt==PKTBYTE_SIG && ctx->sig1nest==0) {
/* This footer is what we are looking for */
myself->write = nextScope;
size -= nextScope (myself, buf, size, error);
break;
} else if (bt==PKTBYTE_1PASSSIG) { /* sig header */
++ctx->sig1nest;
} else if (bt==PKTBYTE_SIG) { /* sig footer */
--ctx->sig1nest;
}
}
/* Else read and pass on this packet */
b = *(buf++);
size--;
if (inputStart(&ctx->input, b) < 0) {
pgpAssert (0); /* what to do here? */
}
ctx->state++;
/* FALLTHROUGH */
case 1:
while (!inputFinished(&ctx->input.head)) {
p = inputRawPeek(&ctx->input, buf, size, &len);
if (!len)
return size0-size;
len = ctx->tail->write(ctx->tail, p, len, error);
len = inputRawSeek(&ctx->input, buf, size, len);
size -= len;
buf += len;
if (*error)
return size0-size;
}
/* Here at end of packet */
ctx->state = 0;
break;
}
return size0-size;
}
/*
* This function flushes the raw header bytes from the beginning of
* the parser's buffer "over" the following module on to the following
* parser, then falls through to writing the payload bytes to the following
* module and the header bytes "over" it.
*/
static size_t
DoWriteNext (struct PgpPipeline *myself, byte const *buf, size_t size,
int *error)
{
struct Context *ctx;
byte const *p;
size_t size0 = size;
size_t len;
struct PgpPipeline *tail, *next;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (struct Context *)myself->priv;
pgpAssert (ctx);
pgpAssert (ctx->tail);
pgpAssert (ctx->nextparser);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
next = ctx->nextparser;
*error = 0;
for (;;) {
p = inputRawPeek(&ctx->input, NULL, 0, &len);
if (!len)
break;
len = next->write (next, p, len, error);
(void)inputRawSeek(&ctx->input, NULL, 0, len);
if (*error)
return 0;
}
tail = ctx->tail;
do {
p = inputHeadPeek(&ctx->input.head, buf, size, &len);
if (len) {
len = next->write(next, p, len, error);
(void)inputHeadSeek(&ctx->input.head, buf, len);
buf += len;
size -= len;
} else {
p = inputPeek(&ctx->input, buf, size, &len);
if (len) {
len = tail->write(tail, p, len, error);
/* Note double "len" to prevent header skip */
len = inputSeek(&ctx->input, buf, len, len);
buf += len;
size -= len;
} else
break;
}
if (*error)
return size0-size;
} while (size);
/* If that's the end of this packet, continue with the next. */
if (inputFinished(&ctx->input.head)) {
/* End of input */
myself->write = nextScope;
size -= nextScope (myself, buf, size, error);
}
return size0-size;
}
/*
* This function is called when we are checking the signature on a literal
* packet. The reason it is needed is that signatures are only on the BODY
* of the literal packet, not the headers. OOPS. So find the size of
* the literal packet header and pass it (external header and internal
* header) "over" the hash module to the ctx->nextparser using
* DoWriteNext.
*
* This does NOT report errors on a short or truncated literal packet, since
* we're pretending not to be parsing it - the downstream parser will
* notice it and do any necessary complaining. It DOES, however, try
* to write out such packets to the downstream parser so it can do the
* reporting.
*/
static size_t
parseSignedLiteralMagic (struct PgpPipeline *myself,
byte const *buf, size_t size, int *error)
{
struct Context *ctx;
size_t len;
byte const *p;
size_t size0 = size;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
ctx = (struct Context *)myself->priv;
pgpAssert (ctx);
pgpAssert (ctx->tail);
pgpAssert (error);
pgpAssert (!size || !ctx->eof);
/* Make sure nothing confusing can happen here! */
pgpAssert(!ctx->needcallback);
/* Do NOT complain on truncation. */
ctx->input.silent_trunc = 1;
/* No error until told otherwise */
*error = 0;
switch (ctx->state) {
case 0: /* Get packet header byte */
if (!size)
return 0;
/* We know it's a literal packet, so no worries. */
(void)inputStart(&ctx->input, *buf);
buf++;
size--;
ctx->state++;
/* FALLTHROUGH */
case 1: /* Get internal header */
len = inputMerge(&ctx->input, buf, size, 2, error);
buf += len;
size -= len;
if (*error)
break;
p = inputPeek(&ctx->input, NULL, 0, &len);
if (len < 2) {
if (!inputFinished(&ctx->input.head))
break;
} else {
len = inputMerge(&ctx->input, buf, size, 6+p[1],
error);
buf += len;
size -= len;
if (*error)
break;
if (inputMerged(&ctx->input) < (size_t)6+p[1]) {
if (!inputFinished(&ctx->input.head))
break;
}
}
/* We've got as much as we need */
ctx->state++;
myself->write = DoWriteNext;
size -= DoWriteNext (myself, buf, size, error);
break;
default:
pgpAssert(0);
}
return size0-size;
}
/*
* This function just does a little bit of trivial initialization,
* including setting the state to 0, and then falls through to
* parseSignedLiteralMagic. The Do functions can be called from a
* variety of states, due to the way they are set up from callbacks
* that may be called from a variety of states, so they can't depend on
* the ctx->state. Thus, the need for this little wrapper function.
*/
static size_t
DoSignedLiteralMagic (struct PgpPipeline *myself, byte const *buf, size_t size,
int *error)
{
struct Context *ctx;
pgpAssert (myself);
pgpAssert (myself->magic == PARSERMAGIC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -