/** @brief Reads an entire file into \c result, stopping after \c size bytes or * EOF. It will read until EOF if size is 0. */ static posix_errno_t read_file(efile_data_t *d, size_t size, ErlNifBinary *result) { size_t initial_buffer_size; ssize_t bytes_read; if(size == 0) { initial_buffer_size = 16 << 10; } else { initial_buffer_size = size; } if(!enif_alloc_binary(initial_buffer_size, result)) { return ENOMEM; } bytes_read = 0; for(;;) { ssize_t block_bytes_read; SysIOVec read_vec[1]; read_vec[0].iov_base = result->data + bytes_read; read_vec[0].iov_len = result->size - bytes_read; block_bytes_read = efile_readv(d, read_vec, 1); if(block_bytes_read < 0) { enif_release_binary(result); return d->posix_errno; } bytes_read += block_bytes_read; if(block_bytes_read < (result->size - bytes_read)) { /* EOF */ break; } else if(bytes_read == size) { break; } if(!enif_realloc_binary(result, bytes_read * 2)) { enif_release_binary(result); return ENOMEM; } } /* The file may have shrunk since we queried its size, so we have to do * this even when the size is known. */ if(bytes_read < result->size && !enif_realloc_binary(result, bytes_read)) { ERTS_INTERNAL_ERROR("Failed to shrink read_file result."); } return 0; }
static ERL_NIF_TERM read_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { Sint64 bytes_read, block_size; SysIOVec read_vec[1]; ErlNifBinary result; ASSERT(argc == 1); if(!enif_is_number(env, argv[0])) { return enif_make_badarg(env); } if(!enif_get_int64(env, argv[0], &block_size) || block_size < 0) { return posix_error_to_tuple(env, EINVAL); } if(!enif_alloc_binary(block_size, &result)) { return posix_error_to_tuple(env, ENOMEM); } read_vec[0].iov_base = result.data; read_vec[0].iov_len = result.size; bytes_read = efile_readv(d, read_vec, 1); ASSERT(bytes_read <= block_size); if(bytes_read < 0) { enif_release_binary(&result); return posix_error_to_tuple(env, d->posix_errno); } else if(bytes_read == 0) { enif_release_binary(&result); return am_eof; } if(bytes_read < block_size && !enif_realloc_binary(&result, bytes_read)) { ERTS_INTERNAL_ERROR("Failed to shrink read result."); } return enif_make_tuple2(env, am_ok, enif_make_binary(env, &result)); }