Skip to content

Commit

Permalink
Fix reading special files that lie about their size
Browse files Browse the repository at this point in the history
  • Loading branch information
graebm committed Oct 12, 2023
1 parent d09b75e commit 7e11465
Showing 1 changed file with 37 additions and 19 deletions.
56 changes: 37 additions & 19 deletions source/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,43 @@ int aws_byte_buf_init_from_file(struct aws_byte_buf *out_buf, struct aws_allocat
goto error;
}

size_t allocation_size = (size_t)len64 + 1;
aws_byte_buf_init(out_buf, alloc, allocation_size);

/* Ensure compatibility with null-terminated APIs, but don't consider
* the null terminator part of the length of the payload */
out_buf->len = out_buf->capacity - 1;
out_buf->buffer[out_buf->len] = 0;

size_t read = fread(out_buf->buffer, 1, out_buf->len, fp);
if (read < out_buf->len) {
int errno_value = ferror(fp) ? errno : 0; /* Always cache errno before potential side-effect */
aws_translate_and_raise_io_error_or(errno_value, AWS_ERROR_FILE_READ_FAILURE);
AWS_LOGF_ERROR(
AWS_LS_COMMON_IO,
"static: Failed reading file:'%s' errno:%d aws-error:%s",
filename,
errno_value,
aws_error_name(aws_last_error()));
goto error;
/* For "special" files, size may be a lie. For example, on Amazon Linux 2:
* /proc/net/tcp: says 0, but it's larger if you read it.
* /sys/devices/virtual/dmi/id/product_name: says 4096, but it's smaller if you read it.
*
* So we'll use file-size as a hint, but read() in a loop until we hit EOF,
* resizing the buffer if necessary as we go.
*
* If file-size == 0, add a bit of capacity to start.
* If file-size != 0, add 1 more to capacity, in case we need to do a 2nd read to learn it's EOF. */
size_t initial_capacity = len64 == 0 ? 128 : (size_t)len64 + 1;
aws_byte_buf_init(out_buf, alloc, initial_capacity);
while (true) {
/* Add more capacity if necessary */
if (out_buf->len == out_buf->capacity) {
size_t additional_capacity = aws_min_size(4096, aws_mul_size_saturating(out_buf->capacity, 2));
aws_byte_buf_reserve_relative(out_buf, additional_capacity);
}

size_t space_available = out_buf->capacity - out_buf->len;
size_t read = fread(out_buf->buffer + out_buf->len, 1, space_available, fp);
out_buf->len += read;

if (feof(fp)) {
break;
}

if (read == 0) {
int errno_value = ferror(fp) ? errno : 0; /* Always cache errno before potential side-effect */
aws_translate_and_raise_io_error_or(errno_value, AWS_ERROR_FILE_READ_FAILURE);
AWS_LOGF_ERROR(
AWS_LS_COMMON_IO,
"static: Failed reading file:'%s' errno:%d aws-error:%s",
filename,
errno_value,
aws_error_name(aws_last_error()));
goto error;
}
}

fclose(fp);
Expand Down

0 comments on commit 7e11465

Please sign in to comment.