Beispiel #1
0
/** @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;
}
Beispiel #2
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));
}