fixed ps_eof(): consider cache. fixed ps_read_cached() which didn't work under certain circumstances (blocksize < readbytes and such)

This commit is contained in:
git@daemon.de
2014-02-26 15:32:46 +01:00
parent deace4109c
commit c11ce76d21
3 changed files with 116 additions and 41 deletions

3
TODO
View File

@@ -46,9 +46,6 @@ Check is_utf8 license.
Vault checksum with global vault Vault checksum with global vault
Pcpstream armored write: fails if blocksize is smaller than chunk to
write. It even coredumps in ps_write (overlap calculation gets negative)
need to check
Python binding, e.g.: Python binding, e.g.:
py % cdll.LoadLibrary("libsodium.so.8") py % cdll.LoadLibrary("libsodium.so.8")

View File

@@ -8,6 +8,7 @@ extern "C" {
#include "pcp/config.h" #include "pcp/config.h"
#include "pcp/base85.h" #include "pcp/base85.h"
#include "pcp/buffer.h" #include "pcp/buffer.h"
#include "pcp/config.h"
#include "pcp/crypto.h" #include "pcp/crypto.h"
#include "pcp/defines.h" #include "pcp/defines.h"
#include "pcp/digital_crc32.h" #include "pcp/digital_crc32.h"

View File

@@ -108,35 +108,63 @@ size_t ps_read_raw(Pcpstream *stream, void *buf, size_t readbytes) {
fetch (and decode) the next chunk, append it to cache and return from fetch (and decode) the next chunk, append it to cache and return from
that */ that */
size_t ps_read_cached(Pcpstream *stream, void *buf, size_t readbytes) { size_t ps_read_cached(Pcpstream *stream, void *buf, size_t readbytes) {
if(buffer_left(stream->cache) <= readbytes && buffer_left(stream->cache) > 0) { if(buffer_left(stream->cache) <= readbytes && buffer_left(stream->cache) > 0 && readbytes <= stream->blocksize) {
/* enough left in current cache */ /* enough left in current cache */
return buffer_get_chunk(stream->cache, buf, readbytes); return buffer_get_chunk(stream->cache, buf, readbytes);
} }
else { else {
/* not enough, fetch the next chunk */ /* request for chunk larger than what we've got in the cache */
ps_read_next(stream); Buffer *tmp = buffer_new(stream->blocksize, "Pcpreadover");
if( buffer_left(stream->cache) > 0) {
/* put the remaining cache into dest */
buffer_get_chunk_tobuf(stream->cache, tmp, buffer_size(stream->cache));
}
/* how much left to fetch */
long int left = readbytes - buffer_size(tmp);
/* fetch and decode data until tmp is filled */
while (left > 0) {
/* not enough cached, fetch the next chunk */
if(ps_read_next(stream) == 0)
break;
/* need to fetch more? */
left = readbytes - (buffer_size(tmp) + buffer_size(stream->next));
if(left < 0) {
/* no more to fetch, in fact there's more than we need */
/* determine overlapping bytes */ /* determine overlapping bytes */
size_t overlap = readbytes - buffer_left(stream->cache); size_t overlap = readbytes - buffer_size(tmp);
/* fetch the rest from the cache */ /* avoid overflow */
size_t fromcache = buffer_get_chunk(stream->cache, buf, buffer_left(stream->cache)); if(overlap > buffer_size(stream->next))
overlap = buffer_size(stream->next);
/* fetch the overlap from next, append to buf */ /* add the overlap from next to tmp */
if(overlap > buffer_left(stream->next)) buffer_get_chunk_tobuf(stream->next, tmp, overlap);
overlap = buffer_left(stream->next);
buffer_get_chunk(stream->next, buf+overlap, overlap);
/* move the rest of stream->next into cache */ /* move the rest of stream->next into cache */
buffer_clear(stream->cache); buffer_clear(stream->cache);
void *rest = buffer_get_remainder(stream->next); buffer_get_chunk_tobuf(stream->next, stream->cache, buffer_left(stream->next));
buffer_add(stream->cache, rest, buffer_left(stream->next));
free(rest);
/* reset next */
buffer_clear(stream->next); buffer_clear(stream->next);
}
else {
/* we've got precisely what we need, no need to calculate any overlap
OR there's more to fetch, we don't have enough stuff yet,
put next into tmp, reset next and loop again - same behavior */
buffer_add_buf(tmp, stream->next);
buffer_clear(stream->next);
}
}
return fromcache + overlap; /* return to the caller */
left = buffer_size(tmp);
buffer_get_chunk(tmp, buf, left);
buffer_free(tmp);
return left;
} }
} }
@@ -192,7 +220,13 @@ void ps_determine(Pcpstream *stream) {
if(_buffer_is_binary(buf, got) == 0) { if(_buffer_is_binary(buf, got) == 0) {
/* no, it's armored */ /* no, it's armored */
stream->armor = 1; stream->armor = 1;
/* decode the first chunk */
ps_read_decode(stream, buf, got); ps_read_decode(stream, buf, got);
/* put it into the cache */
buffer_add_buf(stream->cache, stream->next);
buffer_clear(stream->next);
} }
else { else {
/* just put the raw stuff into the cache */ /* just put the raw stuff into the cache */
@@ -226,23 +260,25 @@ size_t ps_read_decode(Pcpstream *stream, void *buf, size_t bufsize) {
} }
} }
/* finally, decode it and put into cache */ /* finally, decode it and put into next */
size_t binlen, outlen; size_t binlen, outlen;
byte *bin = pcp_z85_decode(buffer_get_str(z), &binlen); byte *bin = pcp_z85_decode(buffer_get_str(z), &binlen);
if(bin == NULL) { if(bin == NULL) {
/* it's not z85 encoded, so threat it as binary */ /* it's not z85 encoded, so threat it as binary */
stream->armor = 1; stream->armor = 0;
buffer_add_buf(stream->cache, z); buffer_add_buf(stream->next, z);
outlen = buffer_size(stream->cache); outlen = buffer_size(stream->next);
} }
else { else {
/* yes, successfully decoded it, put into cache */ /* yes, successfully decoded it, put into cache */
buffer_add(stream->cache, bin, binlen); buffer_add(stream->next, bin, binlen);
outlen = binlen; outlen = binlen;
} }
buffer_free(z); buffer_free(z);
return outlen; return outlen;
} }
@@ -254,6 +290,30 @@ size_t ps_write(Pcpstream *stream, void *buf, size_t writebytes) {
/* just put it into the cache and done with it */ /* just put it into the cache and done with it */
buffer_add(stream->cache, buf, writebytes); buffer_add(stream->cache, buf, writebytes);
} }
else if(buffer_size(stream->cache) + writebytes > stream->blocksize) {
/* buf is too large to fit into blocksize, put out the blocks we've got so far */
buffer_add(stream->cache, buf, writebytes);
/* encode blockwise and write directly until there's a rest */
Buffer *tmp = buffer_new(stream->blocksize, "Pcpcopybuf");
/* copy current cache to tmp for iteration */
buffer_add_buf(tmp, stream->cache);
while (buffer_left(tmp) > stream->blocksize) {
/* iterate over tmp blockwise, encode each block, write it out until there's a rest */
buffer_clear(stream->cache);
buffer_get_chunk_tobuf(tmp, stream->cache, stream->blocksize);
ps_write_encode(stream, z);
}
/* now, z contains a couple of z85 encoded blocks, tmp contains the
remainder of the write buffer, store the rest in the cache and
go on as nothing did happen */
buffer_clear(stream->cache);
buffer_add(stream->cache, buffer_get_remainder(tmp), buffer_left(tmp));
buffer_free(tmp);
}
else { else {
/* z85 encode cache+buf */ /* z85 encode cache+buf */
@@ -277,7 +337,7 @@ size_t ps_write(Pcpstream *stream, void *buf, size_t writebytes) {
buffer_clear(stream->cache); buffer_clear(stream->cache);
if(aside != NULL) { if(aside != NULL) {
/* there is an overlapping rest, put it into the cache /* there is an overlapping rest, put it into the cache
FIXME: write it on calling ps_close() or ad some ps_finish() function */ the caller needs to call ps_finish() to put it out */
buffer_add(stream->cache, aside, overlap); buffer_add(stream->cache, aside, overlap);
} }
} }
@@ -286,12 +346,18 @@ size_t ps_write(Pcpstream *stream, void *buf, size_t writebytes) {
buffer_add(z, buf, writebytes); buffer_add(z, buf, writebytes);
} }
if(buffer_size(z) > 0) {
/* actually put it out */
size_t outsize = ps_write_buf(stream, z); size_t outsize = ps_write_buf(stream, z);
buffer_free(z); buffer_free(z);
return outsize; return outsize;
} }
else {
/* buf has been put into the cache only, no writing required */
buffer_free(z);
return writebytes;
}
}
void ps_write_encode(Pcpstream *stream, Buffer *dst) { void ps_write_encode(Pcpstream *stream, Buffer *dst) {
size_t zlen, i, pos; size_t zlen, i, pos;
@@ -299,8 +365,10 @@ void ps_write_encode(Pcpstream *stream, Buffer *dst) {
/* do z85 0 padding, manually */ /* do z85 0 padding, manually */
if(buffer_size(stream->cache) % 4 != 0) { if(buffer_size(stream->cache) % 4 != 0) {
size_t outlen = buffer_size(stream->cache); size_t outlen = buffer_size(stream->cache);
while (outlen % 4 != 0) while (outlen % 4 != 0) {
buffer_add8(stream->cache, 0); buffer_add8(stream->cache, 0);
outlen = buffer_size(stream->cache);
}
} }
/* z85 encode */ /* z85 encode */
@@ -346,12 +414,15 @@ size_t ps_write_buf(Pcpstream *stream, Buffer *z) {
size_t ps_finish(Pcpstream *stream) { size_t ps_finish(Pcpstream *stream) {
size_t outsize = 0; size_t outsize = 0;
if(stream->cache != NULL) {
if(buffer_left(stream->cache) > 0) { if(buffer_left(stream->cache) > 0) {
Buffer *z = buffer_new(32, "Pcpwritetemp"); Buffer *z = buffer_new(32, "Pcpwritetemp");
ps_write_encode(stream, z); ps_write_encode(stream, z);
outsize = ps_write_buf(stream, z); outsize = ps_write_buf(stream, z);
buffer_clear(stream->cache);
buffer_free(z); buffer_free(z);
} }
}
return outsize; return outsize;
} }
@@ -373,8 +444,10 @@ size_t ps_print(Pcpstream *stream, const char * fmt, ...) {
} }
void ps_close(Pcpstream *stream) { void ps_close(Pcpstream *stream) {
if(stream->cache != NULL) if(stream->cache != NULL) {
assert(buffer_left(stream->cache) == 0); /* there's something left in the cache, call ps_finish() */
buffer_free(stream->cache); buffer_free(stream->cache);
}
if(stream->next != NULL) if(stream->next != NULL)
buffer_free(stream->next); buffer_free(stream->next);
@@ -392,6 +465,10 @@ void ps_close(Pcpstream *stream) {
} }
int ps_end(Pcpstream *stream) { int ps_end(Pcpstream *stream) {
/* simulate open file if there's still something in the cache */
if(stream->cache != NULL)
if(buffer_left(stream->cache) > 0)
return 0;
return stream->eof; return stream->eof;
} }