Skip to content

Commit

Permalink
common/gossip_store: handle short reads.
Browse files Browse the repository at this point in the history
This happened on Travis, and the gossip_store was a suspicious 4096
bytes long.  This implies they're using some non-atomic filesystem
(gossipd always does atomic writes to gossip_store), but if they are,
others surely are too.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jun 21, 2019
1 parent f1b5706 commit adcb664
Showing 1 changed file with 29 additions and 9 deletions.
38 changes: 29 additions & 9 deletions common/gossip_store.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ static bool timestamp_filter(const struct per_peer_state *pps, u32 timestamp)
&& timestamp <= pps->gs->timestamp_max;
}

static void undo_read(int fd, int len, size_t wanted)
{
if (len < 0) {
/* Grab errno before lseek overrides it */
const char *err = strerror(errno);
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: failed read @%"PRIu64": %s",
(u64)lseek(fd, 0, SEEK_CUR), err);
}

/* Shouldn't happen, but some filesystems are not as atomic as
* they should be! */
status_unusual("gossip_store: short read %i of %zu @%"PRIu64,
len, wanted, (u64)lseek(fd, 0, SEEK_CUR) - len);
lseek(fd, -len, SEEK_CUR);
}

u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps)
{
u8 *msg = NULL;
Expand All @@ -66,9 +83,13 @@ u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps)
while (!msg) {
struct gossip_hdr hdr;
u32 msglen, checksum, timestamp;
int type;
int type, r;

if (read(pps->gossip_store_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
r = read(pps->gossip_store_fd, &hdr, sizeof(hdr));
if (r != sizeof(hdr)) {
/* We expect a 0 read here at EOF */
if (r != 0)
undo_read(pps->gossip_store_fd, r, sizeof(hdr));
per_peer_state_reset_gossip_timer(pps);
return NULL;
}
Expand All @@ -86,13 +107,12 @@ u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps)
checksum = be32_to_cpu(hdr.crc);
timestamp = be32_to_cpu(hdr.timestamp);
msg = tal_arr(ctx, u8, msglen);
if (read(pps->gossip_store_fd, msg, msglen) != msglen)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: can't read len %u"
" ~offset %"PRIi64,
msglen,
(s64)lseek(pps->gossip_store_fd,
0, SEEK_CUR));
r = read(pps->gossip_store_fd, msg, msglen);
if (r != msglen) {
undo_read(pps->gossip_store_fd, r, msglen);
per_peer_state_reset_gossip_timer(pps);
return NULL;
}

if (checksum != crc32c(be32_to_cpu(hdr.timestamp), msg, msglen))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
Expand Down

0 comments on commit adcb664

Please sign in to comment.